source: G950FXXS5DSI1
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / drivers / net / wireless / bcmdhd4361 / wl_android.c
1 /*
2 * Linux cfg80211 driver - Android related functions
3 *
4 * Copyright (C) 1999-2019, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: wl_android.c 818247 2019-05-07 04:15:13Z $
28 */
29
30 #include <linux/module.h>
31 #include <linux/netdevice.h>
32 #include <net/netlink.h>
33 #ifdef CONFIG_COMPAT
34 #include <linux/compat.h>
35 #endif // endif
36
37 #include <wl_android.h>
38 #include <wldev_common.h>
39 #include <wlc_types.h>
40 #include <wlioctl.h>
41 #include <wlioctl_utils.h>
42 #include <bcmutils.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 #endif // endif
57 #ifdef WL_NAN
58 #include <wl_cfgnan.h>
59 #endif /* WL_NAN */
60 #ifdef DHDTCPACK_SUPPRESS
61 #include <dhd_ip.h>
62 #endif /* DHDTCPACK_SUPPRESS */
63 #include <bcmwifi_rspec.h>
64 #include <dhd_linux.h>
65 #include <bcmiov.h>
66 #ifdef DHD_PKT_LOGGING
67 #include <dhd_pktlog.h>
68 #endif /* DHD_PKT_LOGGING */
69
70 #ifdef WL_STATIC_IF
71 #define WL_BSSIDX_MAX 16
72 #endif /* WL_STATIC_IF */
73 #ifdef WL_BCNRECV
74 #include <wl_cfgvendor.h>
75 #include <brcm_nl80211.h>
76 #endif /* WL_BCNRECV */
77 /*
78 * Android private command strings, PLEASE define new private commands here
79 * so they can be updated easily in the future (if needed)
80 */
81
82 #define CMD_START "START"
83 #define CMD_STOP "STOP"
84 #define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
85 #define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
86 #define CMD_RSSI "RSSI"
87 #define CMD_LINKSPEED "LINKSPEED"
88 #define CMD_RXFILTER_START "RXFILTER-START"
89 #define CMD_RXFILTER_STOP "RXFILTER-STOP"
90 #define CMD_RXFILTER_ADD "RXFILTER-ADD"
91 #define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
92 #define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
93 #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
94 #define CMD_BTCOEXMODE "BTCOEXMODE"
95 #define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
96 #define CMD_SETSUSPENDMODE "SETSUSPENDMODE"
97 #define CMD_SETDTIM_IN_SUSPEND "SET_DTIM_IN_SUSPEND"
98 #define CMD_MAXDTIM_IN_SUSPEND "MAX_DTIM_IN_SUSPEND"
99 #define CMD_DISDTIM_IN_SUSPEND "DISABLE_DTIM_IN_SUSPEND"
100 #define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
101 #define CMD_SETFWPATH "SETFWPATH"
102 #define CMD_SETBAND "SETBAND"
103 #define CMD_GETBAND "GETBAND"
104 #define CMD_COUNTRY "COUNTRY"
105 #define CMD_P2P_SET_NOA "P2P_SET_NOA"
106 #if !defined WL_ENABLE_P2P_IF
107 #define CMD_P2P_GET_NOA "P2P_GET_NOA"
108 #endif /* WL_ENABLE_P2P_IF */
109 #define CMD_P2P_SD_OFFLOAD "P2P_SD_"
110 #define CMD_P2P_LISTEN_OFFLOAD "P2P_LO_"
111 #define CMD_P2P_SET_PS "P2P_SET_PS"
112 #define CMD_P2P_ECSA "P2P_ECSA"
113 #define CMD_P2P_INC_BW "P2P_INCREASE_BW"
114 #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
115 #define CMD_SETROAMMODE "SETROAMMODE"
116 #define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA"
117 #define CMD_MIRACAST "MIRACAST"
118 #ifdef WL_NAN
119 #define CMD_NAN "NAN_"
120 #endif /* WL_NAN */
121 #define CMD_COUNTRY_DELIMITER "/"
122
123 #if defined(WL_SUPPORT_AUTO_CHANNEL)
124 #define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS"
125 #endif /* WL_SUPPORT_AUTO_CHANNEL */
126
127 #define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */
128 #define CMD_CHANSPEC "CHANSPEC"
129 #define CMD_DATARATE "DATARATE"
130 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
131 #define CMD_SET_CSA "SETCSA"
132 #ifdef WL_SUPPORT_AUTO_CHANNEL
133 #define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL"
134 #endif /* WL_SUPPORT_AUTO_CHANNEL */
135 #ifdef CUSTOMER_HW4_PRIVATE_CMD
136 #ifdef SUPPORT_HIDDEN_AP
137 /* Hostapd private command */
138 #define CMD_SET_HAPD_MAX_NUM_STA "HAPD_MAX_NUM_STA"
139 #define CMD_SET_HAPD_SSID "HAPD_SSID"
140 #define CMD_SET_HAPD_HIDE_SSID "HAPD_HIDE_SSID"
141 #endif /* SUPPORT_HIDDEN_AP */
142 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
143 #define CMD_HAPD_STA_DISASSOC "HAPD_STA_DISASSOC"
144 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
145 #ifdef SUPPORT_SET_LPC
146 #define CMD_HAPD_LPC_ENABLED "HAPD_LPC_ENABLED"
147 #endif /* SUPPORT_SET_LPC */
148 #ifdef SUPPORT_TRIGGER_HANG_EVENT
149 #define CMD_TEST_FORCE_HANG "TEST_FORCE_HANG"
150 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
151 #ifdef SUPPORT_LTECX
152 #define CMD_LTECX_SET "LTECOEX"
153 #endif /* SUPPORT_LTECX */
154 #ifdef TEST_TX_POWER_CONTROL
155 #define CMD_TEST_SET_TX_POWER "TEST_SET_TX_POWER"
156 #define CMD_TEST_GET_TX_POWER "TEST_GET_TX_POWER"
157 #endif /* TEST_TX_POWER_CONTROL */
158 #define CMD_SARLIMIT_TX_CONTROL "SET_TX_POWER_CALLING"
159 #ifdef SUPPORT_SET_TID
160 #define CMD_SET_TID "SET_TID"
161 #define CMD_GET_TID "GET_TID"
162 #endif /* SUPPORT_SET_TID */
163 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
164 #define CMD_KEEP_ALIVE "KEEPALIVE"
165
166 #ifdef BCMCCX
167 /* CCX Private Commands */
168 #define CMD_GETCCKM_RN "get cckm_rn"
169 #define CMD_SETCCKM_KRK "set cckm_krk"
170 #define CMD_GET_ASSOC_RES_IES "get assoc_res_ies"
171
172 #define CCKM_KRK_LEN 16
173 #define CCKM_BTK_LEN 32
174 #endif // endif
175
176 #ifdef PNO_SUPPORT
177 #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR"
178 #define CMD_PNOSETUP_SET "PNOSETUP "
179 #define CMD_PNOENABLE_SET "PNOFORCE"
180 #define CMD_PNODEBUG_SET "PNODEBUG"
181 #define CMD_WLS_BATCHING "WLS_BATCHING"
182 #endif /* PNO_SUPPORT */
183
184 #define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER"
185
186 #ifdef CUSTOMER_HW4_PRIVATE_CMD
187
188 #ifdef ROAM_API
189 #define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER"
190 #define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER"
191 #define CMD_ROAMDELTA_SET "SETROAMDELTA"
192 #define CMD_ROAMDELTA_GET "GETROAMDELTA"
193 #define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD"
194 #define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD"
195 #define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD"
196 #define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD"
197 #define CMD_COUNTRYREV_SET "SETCOUNTRYREV"
198 #define CMD_COUNTRYREV_GET "GETCOUNTRYREV"
199 #endif /* ROAM_API */
200
201 #if defined(SUPPORT_RANDOM_MAC_SCAN)
202 #define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC"
203 #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC"
204 #endif /* SUPPORT_RANDOM_MAC_SCAN */
205
206 #ifdef WES_SUPPORT
207 #define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
208 #define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
209 #define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
210 #define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
211
212 #define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
213 #define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
214 #define CMD_GETSCANUNASSOCTIME "GETSCANUNASSOCTIME"
215 #define CMD_SETSCANUNASSOCTIME "SETSCANUNASSOCTIME"
216 #define CMD_GETSCANPASSIVETIME "GETSCANPASSIVETIME"
217 #define CMD_SETSCANPASSIVETIME "SETSCANPASSIVETIME"
218 #define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
219 #define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
220 #define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
221 #define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
222 #define CMD_GETSCANNPROBES "GETSCANNPROBES"
223 #define CMD_SETSCANNPROBES "SETSCANNPROBES"
224 #define CMD_GETDFSSCANMODE "GETDFSSCANMODE"
225 #define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
226 #define CMD_SETJOINPREFER "SETJOINPREFER"
227
228 #define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
229 #define CMD_REASSOC "REASSOC"
230
231 #define CMD_GETWESMODE "GETWESMODE"
232 #define CMD_SETWESMODE "SETWESMODE"
233
234 #define CMD_GETOKCMODE "GETOKCMODE"
235 #define CMD_SETOKCMODE "SETOKCMODE"
236
237 #define CMD_OKC_SET_PMK "SET_PMK"
238 #define CMD_OKC_ENABLE "OKC_ENABLE"
239
240 typedef struct android_wifi_reassoc_params {
241 unsigned char bssid[18];
242 int channel;
243 } android_wifi_reassoc_params_t;
244
245 #define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params)
246
247 #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
248
249 typedef struct android_wifi_af_params {
250 unsigned char bssid[18];
251 int channel;
252 int dwell_time;
253 int len;
254 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
255 } android_wifi_af_params_t;
256
257 #define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params)
258 #endif /* WES_SUPPORT */
259 #ifdef SUPPORT_AMPDU_MPDU_CMD
260 #define CMD_AMPDU_MPDU "AMPDU_MPDU"
261 #endif /* SUPPORT_AMPDU_MPDU_CMD */
262
263 #define CMD_CHANGE_RL "CHANGE_RL"
264 #define CMD_RESTORE_RL "RESTORE_RL"
265
266 #define CMD_SET_RMC_ENABLE "SETRMCENABLE"
267 #define CMD_SET_RMC_TXRATE "SETRMCTXRATE"
268 #define CMD_SET_RMC_ACTPERIOD "SETRMCACTIONPERIOD"
269 #define CMD_SET_RMC_IDLEPERIOD "SETRMCIDLEPERIOD"
270 #define CMD_SET_RMC_LEADER "SETRMCLEADER"
271 #define CMD_SET_RMC_EVENT "SETRMCEVENT"
272
273 #define CMD_SET_SCSCAN "SETSINGLEANT"
274 #define CMD_GET_SCSCAN "GETSINGLEANT"
275 #ifdef WLTDLS
276 #define CMD_TDLS_RESET "TDLS_RESET"
277 #endif /* WLTDLS */
278
279 #ifdef FCC_PWR_LIMIT_2G
280 #define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL"
281 #define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL"
282 /* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */
283 #define CUSTOMER_HW4_ENABLE 0
284 #define CUSTOMER_HW4_DISABLE -1
285 #define CUSTOMER_HW4_EN_CONVERT(i) (i += 1)
286 #endif /* FCC_PWR_LIMIT_2G */
287 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
288
289 #ifdef WLFBT
290 #define CMD_GET_FTKEY "GET_FTKEY"
291 #endif // endif
292
293 #ifdef WLAIBSS
294 #define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT"
295 #define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO"
296 #define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL"
297 #define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE"
298 #define CMD_SETIBSSAMPDU "SETIBSSAMPDU"
299 #define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE"
300 #endif /* WLAIBSS */
301
302 #define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
303 #define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
304 #define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
305 #define CMD_GET_LINK_STATUS "GETLINKSTATUS"
306
307 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
308 #define CMD_GET_BSS_INFO "GETBSSINFO"
309 #define CMD_GET_ASSOC_REJECT_INFO "GETASSOCREJECTINFO"
310 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
311 #define CMD_GET_STA_INFO "GETSTAINFO"
312
313 /* related with CMD_GET_LINK_STATUS */
314 #define WL_ANDROID_LINK_VHT 0x01
315 #define WL_ANDROID_LINK_MIMO 0x02
316 #define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04
317 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08
318
319 #ifdef P2PRESP_WFDIE_SRC
320 #define CMD_P2P_SET_WFDIE_RESP "P2P_SET_WFDIE_RESP"
321 #define CMD_P2P_GET_WFDIE_RESP "P2P_GET_WFDIE_RESP"
322 #endif /* P2PRESP_WFDIE_SRC */
323
324 #define CMD_DFS_AP_MOVE "DFS_AP_MOVE"
325 #define CMD_WBTEXT_ENABLE "WBTEXT_ENABLE"
326 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
327 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
328 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
329 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
330 #define CMD_WBTEXT_BTM_TIMER_THRESHOLD "WBTEXT_BTM_TIMER_THRESHOLD"
331 #define CMD_WBTEXT_BTM_DELTA "WBTEXT_BTM_DELTA"
332
333 #ifdef WLWFDS
334 #define CMD_ADD_WFDS_HASH "ADD_WFDS_HASH"
335 #define CMD_DEL_WFDS_HASH "DEL_WFDS_HASH"
336 #endif /* WLWFDS */
337
338 #ifdef SET_RPS_CPUS
339 #define CMD_RPSMODE "RPSMODE"
340 #endif /* SET_RPS_CPUS */
341
342 #ifdef BT_WIFI_HANDOVER
343 #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
344 #endif /* BT_WIFI_HANDOVER */
345
346 #ifdef DYNAMIC_MUMIMO_CONTROL
347 #define CMD_GET_MURX_BFE_CAP "GET_MURX_BFE_CAP"
348 #define CMD_SET_MURX_BFE_CAP "SET_MURX_BFE_CAP"
349 #define CMD_GET_BSS_SUPPORT_MUMIMO "GET_BSS_SUPPORT_MUMIMO"
350 #endif /* DYNAMIC_MUMIMO_CONTROL */
351
352 #ifdef SUPPORT_RSSI_SUM_REPORT
353 #define CMD_SET_RSSI_LOGGING "SET_RSSI_LOGGING"
354 #define CMD_GET_RSSI_LOGGING "GET_RSSI_LOGGING"
355 #define CMD_GET_RSSI_PER_ANT "GET_RSSI_PER_ANT"
356 #endif /* SUPPORT_RSSI_SUM_REPORT */
357
358 #ifdef APSTA_RESTRICTED_CHANNEL
359 #define CMD_SET_INDOOR_CHANNELS "SET_INDOOR_CHANNELS"
360 #define CMD_GET_INDOOR_CHANNELS "GET_INDOOR_CHANNELS"
361 #endif /* APSTA_RESTRICTED_CHANNEL */
362
363 #define CMD_GET_SNR "GET_SNR"
364
365 #ifdef SUPPORT_SET_CAC
366 #define CMD_ENABLE_CAC "ENABLE_CAC"
367 #endif /* SUPPORT_SET_CAC */
368
369 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
370 #define CMD_SET_AP_BEACONRATE "SET_AP_BEACONRATE"
371 #define CMD_GET_AP_BASICRATE "GET_AP_BASICRATE"
372 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
373
374 #ifdef SUPPORT_AP_RADIO_PWRSAVE
375 #define CMD_SET_AP_RPS "SET_AP_RPS"
376 #define CMD_GET_AP_RPS "GET_AP_RPS"
377 #define CMD_SET_AP_RPS_PARAMS "SET_AP_RPS_PARAMS"
378 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
379
380 /* miracast related definition */
381 #define MIRACAST_MODE_OFF 0
382 #define MIRACAST_MODE_SOURCE 1
383 #define MIRACAST_MODE_SINK 2
384
385 #ifdef CONNECTION_STATISTICS
386 #define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS"
387
388 struct connection_stats {
389 u32 txframe;
390 u32 txbyte;
391 u32 txerror;
392 u32 rxframe;
393 u32 rxbyte;
394 u32 txfail;
395 u32 txretry;
396 u32 txretrie;
397 u32 txrts;
398 u32 txnocts;
399 u32 txexptime;
400 u32 txrate;
401 u8 chan_idle;
402 };
403 #endif /* CONNECTION_STATISTICS */
404
405 #ifdef SUPPORT_LQCM
406 #define CMD_SET_LQCM_ENABLE "SET_LQCM_ENABLE"
407 #define CMD_GET_LQCM_REPORT "GET_LQCM_REPORT"
408 #endif // endif
409
410 static LIST_HEAD(miracast_resume_list);
411 static u8 miracast_cur_mode;
412
413 #ifdef DHD_LOG_DUMP
414 #define CMD_NEW_DEBUG_PRINT_DUMP "DEBUG_DUMP"
415 #define SUBCMD_UNWANTED "UNWANTED"
416 #define SUBCMD_DISCONNECTED "DISCONNECTED"
417 void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
418 #endif /* DHD_LOG_DUMP */
419
420 #ifdef DHD_HANG_SEND_UP_TEST
421 #define CMD_MAKE_HANG "MAKE_HANG"
422 #endif /* CMD_DHD_HANG_SEND_UP_TEST */
423 #ifdef DHD_DEBUG_UART
424 extern bool dhd_debug_uart_is_running(struct net_device *dev);
425 #endif /* DHD_DEBUG_UART */
426
427 struct io_cfg {
428 s8 *iovar;
429 s32 param;
430 u32 ioctl;
431 void *arg;
432 u32 len;
433 struct list_head list;
434 };
435
436 #if defined(BCMFW_ROAM_ENABLE)
437 #define CMD_SET_ROAMPREF "SET_ROAMPREF"
438
439 #define MAX_NUM_SUITES 10
440 #define WIDTH_AKM_SUITE 8
441 #define JOIN_PREF_RSSI_LEN 0x02
442 #define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */
443 #define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */
444 #define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */
445 #define JOIN_PREF_MAX_WPA_TUPLES 16
446 #define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \
447 (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
448 #endif /* BCMFW_ROAM_ENABLE */
449
450 #define CMD_DEBUG_VERBOSE "DEBUG_VERBOSE"
451 #ifdef WL_NATOE
452
453 #define CMD_NATOE "NATOE"
454
455 #define NATOE_MAX_PORT_NUM 65535
456
457 /* natoe command info structure */
458 typedef struct wl_natoe_cmd_info {
459 uint8 *command; /* pointer to the actual command */
460 uint16 tot_len; /* total length of the command */
461 uint16 bytes_written; /* Bytes written for get response */
462 } wl_natoe_cmd_info_t;
463
464 typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
465 typedef int (natoe_cmd_handler_t)(struct net_device *dev,
466 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
467
468 struct wl_natoe_sub_cmd {
469 char *name;
470 uint8 version; /* cmd version */
471 uint16 id; /* id for the dongle f/w switch/case */
472 uint16 type; /* base type of argument */
473 natoe_cmd_handler_t *handler; /* cmd handler */
474 };
475
476 #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix
477 static int wl_android_process_natoe_cmd(struct net_device *dev,
478 char *command, int total_len);
479 static int wl_android_natoe_subcmd_enable(struct net_device *dev,
480 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
481 static int wl_android_natoe_subcmd_config_ips(struct net_device *dev,
482 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
483 static int wl_android_natoe_subcmd_config_ports(struct net_device *dev,
484 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
485 static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev,
486 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
487 static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
488 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
489
490 static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
491 /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
492 {"enable", 0x01, WL_NATOE_CMD_ENABLE,
493 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable)
494 },
495 {"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS,
496 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips)
497 },
498 {"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS,
499 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports)
500 },
501 {"stats", 0x01, WL_NATOE_CMD_DBG_STATS,
502 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats)
503 },
504 {"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT,
505 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt)
506 },
507 {NULL, 0, 0, 0, NULL}
508 };
509
510 #endif /* WL_NATOE */
511
512 #ifdef SET_PCIE_IRQ_CPU_CORE
513 #define CMD_PCIE_IRQ_CORE "PCIE_IRQ_CORE"
514 #endif /* SET_PCIE_IRQ_CPU_CORE */
515
516 #ifdef WLADPS_PRIVATE_CMD
517 #define CMD_SET_ADPS "SET_ADPS"
518 #define CMD_GET_ADPS "GET_ADPS"
519 #endif /* WLADPS_PRIVATE_CMD */
520
521 #ifdef DHD_PKT_LOGGING
522 #define CMD_PKTLOG_FILTER_ENABLE "PKTLOG_FILTER_ENABLE"
523 #define CMD_PKTLOG_FILTER_DISABLE "PKTLOG_FILTER_DISABLE"
524 #define CMD_PKTLOG_FILTER_PATTERN_ENABLE "PKTLOG_FILTER_PATTERN_ENABLE"
525 #define CMD_PKTLOG_FILTER_PATTERN_DISABLE "PKTLOG_FILTER_PATTERN_DISABLE"
526 #define CMD_PKTLOG_FILTER_ADD "PKTLOG_FILTER_ADD"
527 #define CMD_PKTLOG_FILTER_INFO "PKTLOG_FILTER_INFO"
528 #define CMD_PKTLOG_START "PKTLOG_START"
529 #define CMD_PKTLOG_STOP "PKTLOG_STOP"
530 #define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST"
531 #define CMD_PKTLOG_MINMIZE_ENABLE "PKTLOG_MINMIZE_ENABLE"
532 #define CMD_PKTLOG_MINMIZE_DISABLE "PKTLOG_MINMIZE_DISABLE"
533 #define CMD_PKTLOG_CHANGE_SIZE "PKTLOG_CHANGE_SIZE"
534 #endif /* DHD_PKT_LOGGING */
535
536 #ifdef DHD_EVENT_LOG_FILTER
537 #define CMD_EWP_FILTER "EWP_FILTER"
538 #endif /* DHD_EVENT_LOG_FILTER */
539
540 #ifdef WL_BCNRECV
541 #define CMD_BEACON_RECV "BEACON_RECV"
542 #endif /* WL_BCNRECV */
543
544 #ifdef WL_GENL
545 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
546 static int wl_genl_init(void);
547 static int wl_genl_deinit(void);
548
549 extern struct net init_net;
550 /* attribute policy: defines which attribute has which type (e.g int, char * etc)
551 * possible values defined in net/netlink.h
552 */
553 static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
554 [BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
555 [BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
556 };
557
558 #define WL_GENL_VER 1
559 /* family definition */
560 static struct genl_family wl_genl_family = {
561 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
562 .hdrsize = 0,
563 .name = "bcm-genl", /* Netlink I/F for Android */
564 .version = WL_GENL_VER, /* Version Number */
565 .maxattr = BCM_GENL_ATTR_MAX,
566 };
567
568 /* commands: mapping between the command enumeration and the actual function */
569 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
570 struct genl_ops wl_genl_ops[] = {
571 {
572 .cmd = BCM_GENL_CMD_MSG,
573 .flags = 0,
574 .policy = wl_genl_policy,
575 .doit = wl_genl_handle_msg,
576 .dumpit = NULL,
577 },
578 };
579 #else
580 struct genl_ops wl_genl_ops = {
581 .cmd = BCM_GENL_CMD_MSG,
582 .flags = 0,
583 .policy = wl_genl_policy,
584 .doit = wl_genl_handle_msg,
585 .dumpit = NULL,
586
587 };
588 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
589
590 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
591 static struct genl_multicast_group wl_genl_mcast[] = {
592 { .name = "bcm-genl-mcast", },
593 };
594 #else
595 static struct genl_multicast_group wl_genl_mcast = {
596 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
597 .name = "bcm-genl-mcast",
598 };
599 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
600 #endif /* WL_GENL */
601
602 #ifdef SUPPORT_LQCM
603 #define LQCM_ENAB_MASK 0x000000FF /* LQCM enable flag mask */
604 #define LQCM_TX_INDEX_MASK 0x0000FF00 /* LQCM tx index mask */
605 #define LQCM_RX_INDEX_MASK 0x00FF0000 /* LQCM rx index mask */
606
607 #define LQCM_TX_INDEX_SHIFT 8 /* LQCM tx index shift */
608 #define LQCM_RX_INDEX_SHIFT 16 /* LQCM rx index shift */
609 #endif /* SUPPORT_LQCM */
610
611 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
612 #define NUMBER_SEQUENTIAL_PRIVCMD_ERRORS 7
613 static int priv_cmd_errors = 0;
614 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
615
616 /**
617 * Extern function declarations (TODO: move them to dhd_linux.h)
618 */
619 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
620 int dhd_dev_init_ioctl(struct net_device *dev);
621 #ifdef WL_CFG80211
622 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
623 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
624 #ifdef WES_SUPPORT
625 int wl_cfg80211_set_wes_mode(int mode);
626 int wl_cfg80211_get_wes_mode(void);
627 #endif /* WES_SUPPORT */
628 #else
629 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
630 { return 0; }
631 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
632 { return 0; }
633 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
634 { return 0; }
635 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
636 { return 0; }
637 int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
638 { return 0; }
639 int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
640 { return 0; }
641 #endif /* WK_CFG80211 */
642 #ifdef WBTEXT
643 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len);
644 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
645 char *command, int total_len);
646 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
647 char *command, int total_len);
648 #endif /* WBTEXT */
649 #ifdef WES_SUPPORT
650 /* wl_roam.c */
651 extern int get_roamscan_mode(struct net_device *dev, int *mode);
652 extern int set_roamscan_mode(struct net_device *dev, int mode);
653 extern int get_roamscan_channel_list(struct net_device *dev,
654 unsigned char channels[], int n_channels);
655 extern int set_roamscan_channel_list(struct net_device *dev, unsigned char n,
656 unsigned char channels[], int ioctl_ver);
657 #endif /* WES_SUPPORT */
658 #ifdef ROAM_CHANNEL_CACHE
659 extern void wl_update_roamscan_cache_by_band(struct net_device *dev, int band);
660 #endif /* ROAM_CHANNEL_CACHE */
661
662 #ifdef ENABLE_4335BT_WAR
663 extern int bcm_bt_lock(int cookie);
664 extern void bcm_bt_unlock(int cookie);
665 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
666 #endif /* ENABLE_4335BT_WAR */
667
668 extern bool ap_fw_loaded;
669 extern char iface_name[IFNAMSIZ];
670 #ifdef DHD_PM_CONTROL_FROM_FILE
671 extern bool g_pm_control;
672 #endif /* DHD_PM_CONTROL_FROM_FILE */
673
674 /* private command support for restoring roam/scan parameters */
675 #ifdef SUPPORT_RESTORE_SCAN_PARAMS
676 #define CMD_RESTORE_SCAN_PARAMS "RESTORE_SCAN_PARAMS"
677
678 typedef int (*PRIV_CMD_HANDLER) (struct net_device *dev, char *command);
679 typedef int (*PRIV_CMD_HANDLER_WITH_LEN) (struct net_device *dev, char *command, int total_len);
680
681 enum {
682 RESTORE_TYPE_UNSPECIFIED = 0,
683 RESTORE_TYPE_PRIV_CMD = 1,
684 RESTORE_TYPE_PRIV_CMD_WITH_LEN = 2
685 };
686
687 typedef struct android_restore_scan_params {
688 char command[64];
689 int parameter;
690 int cmd_type;
691 union {
692 PRIV_CMD_HANDLER cmd_handler;
693 PRIV_CMD_HANDLER_WITH_LEN cmd_handler_w_len;
694 };
695 } android_restore_scan_params_t;
696
697 /* function prototypes of private command handler */
698 static int wl_android_set_roam_trigger(struct net_device *dev, char* command);
699 int wl_android_set_roam_delta(struct net_device *dev, char* command);
700 int wl_android_set_roam_scan_period(struct net_device *dev, char* command);
701 int wl_android_set_full_roam_scan_period(struct net_device *dev, char* command, int total_len);
702 int wl_android_set_roam_scan_control(struct net_device *dev, char *command);
703 int wl_android_set_scan_channel_time(struct net_device *dev, char *command);
704 int wl_android_set_scan_home_time(struct net_device *dev, char *command);
705 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command);
706 int wl_android_set_scan_nprobes(struct net_device *dev, char *command);
707 static int wl_android_set_band(struct net_device *dev, char *command);
708 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command);
709 int wl_android_set_wes_mode(struct net_device *dev, char *command);
710 int wl_android_set_okc_mode(struct net_device *dev, char *command);
711
712 /* default values */
713 #ifdef ROAM_API
714 #define DEFAULT_ROAM_TIRGGER -75
715 #define DEFAULT_ROAM_DELTA 10
716 #define DEFAULT_ROAMSCANPERIOD 10
717 #define DEFAULT_FULLROAMSCANPERIOD_SET 120
718 #endif /* ROAM_API */
719 #ifdef WES_SUPPORT
720 #define DEFAULT_ROAMSCANCONTROL 0
721 #define DEFAULT_SCANCHANNELTIME 40
722 #ifdef BCM4361_CHIP
723 #define DEFAULT_SCANHOMETIME 60
724 #else
725 #define DEFAULT_SCANHOMETIME 45
726 #endif /* BCM4361_CHIP */
727 #define DEFAULT_SCANHOMEAWAYTIME 100
728 #define DEFAULT_SCANPROBES 2
729 #define DEFAULT_DFSSCANMODE 1
730 #define DEFAULT_WESMODE 0
731 #define DEFAULT_OKCMODE 1
732 #endif /* WES_SUPPORT */
733 #define DEFAULT_BAND 0
734 #ifdef WBTEXT
735 #define DEFAULT_WBTEXT_ENABLE 1
736 #endif /* WBTEXT */
737
738 /* restoring parameter list, please don't change order */
739 static android_restore_scan_params_t restore_params[] =
740 {
741 /* wbtext need to be disabled while updating roam/scan parameters */
742 #ifdef WBTEXT
743 { CMD_WBTEXT_ENABLE, 0, RESTORE_TYPE_PRIV_CMD_WITH_LEN,
744 .cmd_handler_w_len = wl_android_wbtext},
745 #endif /* WBTEXT */
746 #ifdef ROAM_API
747 { CMD_ROAMTRIGGER_SET, DEFAULT_ROAM_TIRGGER,
748 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_trigger},
749 { CMD_ROAMDELTA_SET, DEFAULT_ROAM_DELTA,
750 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_delta},
751 { CMD_ROAMSCANPERIOD_SET, DEFAULT_ROAMSCANPERIOD,
752 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_period},
753 { CMD_FULLROAMSCANPERIOD_SET, DEFAULT_FULLROAMSCANPERIOD_SET,
754 RESTORE_TYPE_PRIV_CMD_WITH_LEN,
755 .cmd_handler_w_len = wl_android_set_full_roam_scan_period},
756 #endif /* ROAM_API */
757 #ifdef WES_SUPPORT
758 { CMD_SETROAMSCANCONTROL, DEFAULT_ROAMSCANCONTROL,
759 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_control},
760 { CMD_SETSCANCHANNELTIME, DEFAULT_SCANCHANNELTIME,
761 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_channel_time},
762 { CMD_SETSCANHOMETIME, DEFAULT_SCANHOMETIME,
763 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_time},
764 { CMD_GETSCANHOMEAWAYTIME, DEFAULT_SCANHOMEAWAYTIME,
765 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_away_time},
766 { CMD_SETSCANNPROBES, DEFAULT_SCANPROBES,
767 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_nprobes},
768 { CMD_SETDFSSCANMODE, DEFAULT_DFSSCANMODE,
769 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_dfs_channel_mode},
770 { CMD_SETWESMODE, DEFAULT_WESMODE,
771 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_wes_mode},
772 { CMD_SETOKCMODE, DEFAULT_OKCMODE,
773 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_okc_mode},
774 #endif /* WES_SUPPORT */
775 { CMD_SETBAND, DEFAULT_BAND,
776 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_band},
777 #ifdef WBTEXT
778 { CMD_WBTEXT_ENABLE, DEFAULT_WBTEXT_ENABLE,
779 RESTORE_TYPE_PRIV_CMD_WITH_LEN, .cmd_handler_w_len = wl_android_wbtext},
780 #endif /* WBTEXT */
781 { "\0", 0, RESTORE_TYPE_UNSPECIFIED, .cmd_handler = NULL}
782 };
783 #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
784
785 /**
786 * Local (static) functions and variables
787 */
788
789 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
790 * time (only) in dhd_open, subsequential wifi on will be handled by
791 * wl_android_wifi_on
792 */
793 static int g_wifi_on = TRUE;
794
795 /**
796 * Local (static) function definitions
797 */
798
799 #ifdef WLWFDS
800 static int wl_android_set_wfds_hash(
801 struct net_device *dev, char *command, bool enable)
802 {
803 int error = 0;
804 wl_p2p_wfds_hash_t *wfds_hash = NULL;
805 char *smbuf = NULL;
806 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
807
808 smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
809 if (smbuf == NULL) {
810 DHD_ERROR(("%s: failed to allocated memory %d bytes\n",
811 __FUNCTION__, WLC_IOCTL_MAXLEN));
812 return -ENOMEM;
813 }
814
815 if (enable) {
816 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
817 error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
818 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
819 }
820 else {
821 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
822 error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
823 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
824 }
825
826 if (error) {
827 DHD_ERROR(("%s: failed to %s, error=%d\n", __FUNCTION__, command, error));
828 }
829
830 if (smbuf) {
831 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
832 }
833 return error;
834 }
835 #endif /* WLWFDS */
836
837 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
838 {
839 int link_speed;
840 int bytes_written;
841 int error;
842
843 error = wldev_get_link_speed(net, &link_speed);
844 if (error) {
845 DHD_ERROR(("Get linkspeed failed \n"));
846 return -1;
847 }
848
849 /* Convert Kbps to Android Mbps */
850 link_speed = link_speed / 1000;
851 bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
852 DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command));
853 return bytes_written;
854 }
855
856 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
857 {
858 wlc_ssid_t ssid = {0, {0}};
859 int bytes_written = 0;
860 int error = 0;
861 scb_val_t scbval;
862 char *delim = NULL;
863 struct net_device *target_ndev = net;
864 #ifdef WL_VIRTUAL_APSTA
865 char *pos = NULL;
866 struct bcm_cfg80211 *cfg;
867 #endif /* WL_VIRTUAL_APSTA */
868
869 delim = strchr(command, ' ');
870 /* For Ap mode rssi command would be
871 * driver rssi <sta_mac_addr>
872 * for STA/GC mode
873 * driver rssi
874 */
875 if (delim) {
876 /* Ap/GO mode
877 * driver rssi <sta_mac_addr>
878 */
879 DHD_TRACE(("%s: cmd:%s\n", __FUNCTION__, delim));
880 /* skip space from delim after finding char */
881 delim++;
882 if (!(bcm_ether_atoe((delim), &scbval.ea))) {
883 DHD_ERROR(("%s:address err\n", __FUNCTION__));
884 return -1;
885 }
886 scbval.val = htod32(0);
887 DHD_TRACE(("%s: address:"MACDBG, __FUNCTION__, MAC2STRDBG(scbval.ea.octet)));
888 #ifdef WL_VIRTUAL_APSTA
889 /* RSDB AP may have another virtual interface
890 * In this case, format of private command is as following,
891 * DRIVER rssi <sta_mac_addr> <AP interface name>
892 */
893
894 /* Current position is start of MAC address string */
895 pos = delim;
896 delim = strchr(pos, ' ');
897 if (delim) {
898 /* skip space from delim after finding char */
899 delim++;
900 if (strnlen(delim, IFNAMSIZ)) {
901 cfg = wl_get_cfg(net);
902 target_ndev = wl_get_ap_netdev(cfg, delim);
903 if (target_ndev == NULL)
904 target_ndev = net;
905 }
906 }
907 #endif /* WL_VIRTUAL_APSTA */
908 }
909 else {
910 /* STA/GC mode */
911 memset(&scbval, 0, sizeof(scb_val_t));
912 }
913
914 error = wldev_get_rssi(target_ndev, &scbval);
915 if (error)
916 return -1;
917
918 error = wldev_get_ssid(target_ndev, &ssid);
919 if (error)
920 return -1;
921 if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
922 DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
923 } else if (total_len <= ssid.SSID_len) {
924 return -ENOMEM;
925 } else {
926 memcpy(command, ssid.SSID, ssid.SSID_len);
927 bytes_written = ssid.SSID_len;
928 }
929 if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1))
930 return -ENOMEM;
931
932 bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written,
933 " rssi %d", scbval.val);
934 command[bytes_written] = '\0';
935
936 DHD_TRACE(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
937 return bytes_written;
938 }
939
940 static int wl_android_set_suspendopt(struct net_device *dev, char *command)
941 {
942 int suspend_flag;
943 int ret_now;
944 int ret = 0;
945
946 suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
947
948 if (suspend_flag != 0) {
949 suspend_flag = 1;
950 }
951 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
952
953 if (ret_now != suspend_flag) {
954 if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
955 DHD_INFO(("%s: Suspend Flag %d -> %d\n",
956 __FUNCTION__, ret_now, suspend_flag));
957 } else {
958 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
959 }
960 }
961
962 return ret;
963 }
964
965 static int wl_android_set_suspendmode(struct net_device *dev, char *command)
966 {
967 int ret = 0;
968
969 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
970 int suspend_flag;
971
972 suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
973 if (suspend_flag != 0)
974 suspend_flag = 1;
975
976 if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
977 DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag));
978 else
979 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
980 #endif // endif
981
982 return ret;
983 }
984
985 int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
986 {
987 uint8 mode[5];
988 int error = 0;
989 int bytes_written = 0;
990
991 error = wldev_get_mode(dev, mode, sizeof(mode));
992 if (error)
993 return -1;
994
995 DHD_INFO(("%s: mode:%s\n", __FUNCTION__, mode));
996 bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
997 DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command));
998 return bytes_written;
999
1000 }
1001
1002 extern chanspec_t
1003 wl_chspec_driver_to_host(chanspec_t chanspec);
1004 int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len)
1005 {
1006 int error = 0;
1007 int bytes_written = 0;
1008 int chsp = {0};
1009 uint16 band = 0;
1010 uint16 bw = 0;
1011 uint16 channel = 0;
1012 u32 sb = 0;
1013 chanspec_t chanspec;
1014
1015 /* command is
1016 * driver chanspec
1017 */
1018 error = wldev_iovar_getint(dev, "chanspec", &chsp);
1019 if (error)
1020 return -1;
1021
1022 chanspec = wl_chspec_driver_to_host(chsp);
1023 DHD_INFO(("%s:return value of chanspec:%x\n", __FUNCTION__, chanspec));
1024
1025 channel = chanspec & WL_CHANSPEC_CHAN_MASK;
1026 band = chanspec & WL_CHANSPEC_BAND_MASK;
1027 bw = chanspec & WL_CHANSPEC_BW_MASK;
1028
1029 DHD_INFO(("%s:channel:%d band:%d bandwidth:%d\n", __FUNCTION__, channel, band, bw));
1030
1031 if (bw == WL_CHANSPEC_BW_80)
1032 bw = WL_CH_BANDWIDTH_80MHZ;
1033 else if (bw == WL_CHANSPEC_BW_40)
1034 bw = WL_CH_BANDWIDTH_40MHZ;
1035 else if (bw == WL_CHANSPEC_BW_20)
1036 bw = WL_CH_BANDWIDTH_20MHZ;
1037 else
1038 bw = WL_CH_BANDWIDTH_20MHZ;
1039
1040 if (bw == WL_CH_BANDWIDTH_40MHZ) {
1041 if (CHSPEC_SB_UPPER(chanspec)) {
1042 channel += CH_10MHZ_APART;
1043 } else {
1044 channel -= CH_10MHZ_APART;
1045 }
1046 }
1047 else if (bw == WL_CH_BANDWIDTH_80MHZ) {
1048 sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
1049 if (sb == WL_CHANSPEC_CTL_SB_LL) {
1050 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
1051 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
1052 channel -= CH_10MHZ_APART;
1053 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
1054 channel += CH_10MHZ_APART;
1055 } else {
1056 /* WL_CHANSPEC_CTL_SB_UU */
1057 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
1058 }
1059 }
1060 bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC,
1061 channel, band == WL_CHANSPEC_BAND_5G ? "5G":"2G", bw);
1062
1063 DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command));
1064 return bytes_written;
1065
1066 }
1067
1068 /* returns current datarate datarate returned from firmware are in 500kbps */
1069 int wl_android_get_datarate(struct net_device *dev, char *command, int total_len)
1070 {
1071 int error = 0;
1072 int datarate = 0;
1073 int bytes_written = 0;
1074
1075 error = wldev_get_datarate(dev, &datarate);
1076 if (error)
1077 return -1;
1078
1079 DHD_INFO(("%s:datarate:%d\n", __FUNCTION__, datarate));
1080
1081 bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2));
1082 return bytes_written;
1083 }
1084 int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len)
1085 {
1086 int error = 0;
1087 int bytes_written = 0;
1088 uint i;
1089 int len = 0;
1090 char mac_buf[MAX_NUM_OF_ASSOCLIST *
1091 sizeof(struct ether_addr) + sizeof(uint)] = {0};
1092 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
1093
1094 DHD_TRACE(("%s: ENTER\n", __FUNCTION__));
1095
1096 assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
1097
1098 error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
1099 if (error)
1100 return -1;
1101
1102 assoc_maclist->count = dtoh32(assoc_maclist->count);
1103 bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:",
1104 CMD_ASSOC_CLIENTS, assoc_maclist->count);
1105
1106 for (i = 0; i < assoc_maclist->count; i++) {
1107 len = snprintf(command + bytes_written, total_len - bytes_written, " " MACDBG,
1108 MAC2STRDBG(assoc_maclist->ea[i].octet));
1109 /* A return value of '(total_len - bytes_written)' or more means that the
1110 * output was truncated
1111 */
1112 if ((len > 0) && (len < (total_len - bytes_written))) {
1113 bytes_written += len;
1114 } else {
1115 DHD_ERROR(("%s: Insufficient buffer %d, bytes_written %d\n",
1116 __FUNCTION__, total_len, bytes_written));
1117 bytes_written = -1;
1118 break;
1119 }
1120 }
1121 return bytes_written;
1122 }
1123 extern chanspec_t
1124 wl_chspec_host_to_driver(chanspec_t chanspec);
1125 static int wl_android_set_csa(struct net_device *dev, char *command)
1126 {
1127 int error = 0;
1128 char smbuf[WLC_IOCTL_SMLEN];
1129 wl_chan_switch_t csa_arg;
1130 u32 chnsp = 0;
1131 int err = 0;
1132
1133 DHD_INFO(("%s: command:%s\n", __FUNCTION__, command));
1134
1135 command = (command + strlen(CMD_SET_CSA));
1136 /* Order is mode, count channel */
1137 if (!*++command) {
1138 DHD_ERROR(("%s:error missing arguments\n", __FUNCTION__));
1139 return -1;
1140 }
1141 csa_arg.mode = bcm_atoi(command);
1142
1143 if (csa_arg.mode != 0 && csa_arg.mode != 1) {
1144 DHD_ERROR(("Invalid mode\n"));
1145 return -1;
1146 }
1147
1148 if (!*++command) {
1149 DHD_ERROR(("%s:error missing count\n", __FUNCTION__));
1150 return -1;
1151 }
1152 command++;
1153 csa_arg.count = bcm_atoi(command);
1154
1155 csa_arg.reg = 0;
1156 csa_arg.chspec = 0;
1157 command += 2;
1158 if (!*command) {
1159 DHD_ERROR(("%s:error missing channel\n", __FUNCTION__));
1160 return -1;
1161 }
1162
1163 chnsp = wf_chspec_aton(command);
1164 if (chnsp == 0) {
1165 DHD_ERROR(("%s:chsp is not correct\n", __FUNCTION__));
1166 return -1;
1167 }
1168 chnsp = wl_chspec_host_to_driver(chnsp);
1169 csa_arg.chspec = chnsp;
1170
1171 if (chnsp & WL_CHANSPEC_BAND_5G) {
1172 u32 chanspec = chnsp;
1173 err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
1174 if (!err) {
1175 if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
1176 DHD_ERROR(("Channel is radar sensitive\n"));
1177 return -1;
1178 }
1179 if (chanspec == 0) {
1180 DHD_ERROR(("Invalid hw channel\n"));
1181 return -1;
1182 }
1183 } else {
1184 DHD_ERROR(("does not support per_chan_info\n"));
1185 return -1;
1186 }
1187 DHD_INFO(("non radar sensitivity\n"));
1188 }
1189 error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
1190 smbuf, sizeof(smbuf), NULL);
1191 if (error) {
1192 DHD_ERROR(("%s:set csa failed:%d\n", __FUNCTION__, error));
1193 return -1;
1194 }
1195 return 0;
1196 }
1197
1198 static int
1199 wl_android_set_bcn_li_dtim(struct net_device *dev, char *command)
1200 {
1201 int ret = 0;
1202 int dtim;
1203
1204 dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0';
1205
1206 if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) {
1207 DHD_ERROR(("%s: failed, invalid dtim %d\n",
1208 __FUNCTION__, dtim));
1209 return BCME_ERROR;
1210 }
1211
1212 if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) {
1213 DHD_TRACE(("%s: SET bcn_li_dtim in suspend %d\n",
1214 __FUNCTION__, dtim));
1215 } else {
1216 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1217 }
1218
1219 return ret;
1220 }
1221
1222 static int
1223 wl_android_set_max_dtim(struct net_device *dev, char *command)
1224 {
1225 int ret = 0;
1226 int dtim_flag;
1227
1228 dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
1229
1230 if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
1231 DHD_TRACE(("%s: use Max bcn_li_dtim in suspend %s\n",
1232 __FUNCTION__, (dtim_flag ? "Enable" : "Disable")));
1233 } else {
1234 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1235 }
1236
1237 return ret;
1238 }
1239
1240 static int
1241 wl_android_set_disable_dtim_in_suspend(struct net_device *dev, char *command)
1242 {
1243 int ret = 0;
1244 int dtim_flag;
1245
1246 dtim_flag = *(command + strlen(CMD_DISDTIM_IN_SUSPEND) + 1) - '0';
1247
1248 if (!(ret = net_os_set_disable_dtim_in_suspend(dev, dtim_flag))) {
1249 DHD_TRACE(("%s: use Disable bcn_li_dtim in suspend %s\n",
1250 __FUNCTION__, (dtim_flag ? "Enable" : "Disable")));
1251 } else {
1252 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1253 }
1254
1255 return ret;
1256 }
1257
1258 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
1259 {
1260 uint band;
1261 int bytes_written;
1262 int error;
1263
1264 error = wldev_get_band(dev, &band);
1265 if (error)
1266 return -1;
1267 bytes_written = snprintf(command, total_len, "Band %d", band);
1268 return bytes_written;
1269 }
1270
1271 static int
1272 wl_android_set_band(struct net_device *dev, char *command)
1273 {
1274 int error = 0;
1275 uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
1276 #ifdef WL_HOST_BAND_MGMT
1277 int ret = 0;
1278 if ((ret = wl_cfg80211_set_band(dev, band)) < 0) {
1279 if (ret == BCME_UNSUPPORTED) {
1280 /* If roam_var is unsupported, fallback to the original method */
1281 WL_ERR(("WL_HOST_BAND_MGMT defined, "
1282 "but roam_band iovar unsupported in the firmware\n"));
1283 } else {
1284 error = -1;
1285 }
1286 }
1287 if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) {
1288 /* Apply if roam_band iovar is not supported or band setting is AUTO */
1289 error = wldev_set_band(dev, band);
1290 }
1291 #else
1292 error = wl_cfg80211_set_if_band(dev, band);
1293 #endif /* WL_HOST_BAND_MGMT */
1294 #ifdef ROAM_CHANNEL_CACHE
1295 wl_update_roamscan_cache_by_band(dev, band);
1296 #endif /* ROAM_CHANNEL_CACHE */
1297 return error;
1298 }
1299
1300 #ifdef CUSTOMER_HW4_PRIVATE_CMD
1301 #ifdef ROAM_API
1302 static bool wl_android_check_wbtext(struct net_device *dev)
1303 {
1304 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1305 return dhdp->wbtext_support;
1306 }
1307
1308 static int wl_android_set_roam_trigger(
1309 struct net_device *dev, char* command)
1310 {
1311 int roam_trigger[2] = {0, 0};
1312 int error;
1313
1314 #ifdef WBTEXT
1315 if (wl_android_check_wbtext(dev)) {
1316 WL_ERR(("blocked to set roam trigger. try with setting roam profile\n"));
1317 return BCME_ERROR;
1318 }
1319 #endif /* WBTEXT */
1320
1321 sscanf(command, "%*s %10d", &roam_trigger[0]);
1322 if (roam_trigger[0] >= 0) {
1323 WL_ERR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1324 return BCME_ERROR;
1325 }
1326
1327 roam_trigger[1] = WLC_BAND_ALL;
1328 error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1329 sizeof(roam_trigger));
1330 if (error != BCME_OK) {
1331 WL_ERR(("failed to set roam trigger (%d)\n", error));
1332 return BCME_ERROR;
1333 }
1334
1335 return BCME_OK;
1336 }
1337
1338 static int wl_android_get_roam_trigger(
1339 struct net_device *dev, char *command, int total_len)
1340 {
1341 int bytes_written, error;
1342 int roam_trigger[2] = {0, 0};
1343 uint16 band = 0;
1344 int chsp = {0};
1345 chanspec_t chanspec;
1346 int i;
1347 struct wl_roam_prof_band_v2 rp;
1348 char smbuf[WLC_IOCTL_SMLEN];
1349
1350 error = wldev_iovar_getint(dev, "chanspec", &chsp);
1351 if (error != BCME_OK) {
1352 WL_ERR(("failed to get chanspec (%d)\n", error));
1353 return BCME_ERROR;
1354 }
1355
1356 chanspec = wl_chspec_driver_to_host(chsp);
1357 band = chanspec & WL_CHANSPEC_BAND_MASK;
1358 if (band == WL_CHANSPEC_BAND_5G)
1359 band = WLC_BAND_5G;
1360 else
1361 band = WLC_BAND_2G;
1362
1363 if (wl_android_check_wbtext(dev)) {
1364 rp.ver = WL_MAX_ROAM_PROF_VER;
1365 rp.len = 0;
1366 rp.band = band;
1367 error = wldev_iovar_getbuf(dev, "roam_prof", &rp, sizeof(rp),
1368 smbuf, sizeof(smbuf), NULL);
1369 if (error != BCME_OK) {
1370 WL_ERR(("failed to get roam profile (%d)\n", error));
1371 return BCME_ERROR;
1372 }
1373 memcpy(&rp, smbuf, sizeof(struct wl_roam_prof_band_v2));
1374 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1375 if (rp.roam_prof[i].channel_usage == 0) {
1376 roam_trigger[0] = rp.roam_prof[i].roam_trigger;
1377 break;
1378 }
1379 }
1380 if (roam_trigger[0] == 0) {
1381 WL_ERR(("roam trigger was not set properly\n"));
1382 return BCME_ERROR;
1383 }
1384 } else {
1385 roam_trigger[1] = band;
1386 error = wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
1387 sizeof(roam_trigger));
1388 if (error != BCME_OK) {
1389 WL_ERR(("failed to get roam trigger (%d)\n", error));
1390 return BCME_ERROR;
1391 }
1392 }
1393
1394 bytes_written = snprintf(command, total_len, "%s %d",
1395 CMD_ROAMTRIGGER_GET, roam_trigger[0]);
1396
1397 return bytes_written;
1398 }
1399
1400 int wl_android_set_roam_delta(
1401 struct net_device *dev, char* command)
1402 {
1403 int roam_delta[2];
1404
1405 sscanf(command, "%*s %10d", &roam_delta[0]);
1406 roam_delta[1] = WLC_BAND_ALL;
1407
1408 return wldev_ioctl_set(dev, WLC_SET_ROAM_DELTA, roam_delta,
1409 sizeof(roam_delta));
1410 }
1411
1412 static int wl_android_get_roam_delta(
1413 struct net_device *dev, char *command, int total_len)
1414 {
1415 int bytes_written;
1416 int roam_delta[2] = {0, 0};
1417
1418 roam_delta[1] = WLC_BAND_2G;
1419 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1420 sizeof(roam_delta))) {
1421 roam_delta[1] = WLC_BAND_5G;
1422 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1423 sizeof(roam_delta)))
1424 return -1;
1425 }
1426
1427 bytes_written = snprintf(command, total_len, "%s %d",
1428 CMD_ROAMDELTA_GET, roam_delta[0]);
1429
1430 return bytes_written;
1431 }
1432
1433 int wl_android_set_roam_scan_period(
1434 struct net_device *dev, char* command)
1435 {
1436 int roam_scan_period = 0;
1437
1438 sscanf(command, "%*s %10d", &roam_scan_period);
1439 return wldev_ioctl_set(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period,
1440 sizeof(roam_scan_period));
1441 }
1442
1443 static int wl_android_get_roam_scan_period(
1444 struct net_device *dev, char *command, int total_len)
1445 {
1446 int bytes_written;
1447 int roam_scan_period = 0;
1448
1449 if (wldev_ioctl_get(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period,
1450 sizeof(roam_scan_period)))
1451 return -1;
1452
1453 bytes_written = snprintf(command, total_len, "%s %d",
1454 CMD_ROAMSCANPERIOD_GET, roam_scan_period);
1455
1456 return bytes_written;
1457 }
1458
1459 int wl_android_set_full_roam_scan_period(
1460 struct net_device *dev, char* command, int total_len)
1461 {
1462 int error = 0;
1463 int full_roam_scan_period = 0;
1464 char smbuf[WLC_IOCTL_SMLEN];
1465
1466 sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period);
1467 WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period));
1468
1469 error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period,
1470 sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL);
1471 if (error) {
1472 DHD_ERROR(("Failed to set full roam scan period, error = %d\n", error));
1473 }
1474
1475 return error;
1476 }
1477
1478 static int wl_android_get_full_roam_scan_period(
1479 struct net_device *dev, char *command, int total_len)
1480 {
1481 int error;
1482 int bytes_written;
1483 int full_roam_scan_period = 0;
1484
1485 error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period);
1486
1487 if (error) {
1488 DHD_ERROR(("%s: get full roam scan period failed code %d\n",
1489 __func__, error));
1490 return -1;
1491 } else {
1492 DHD_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period));
1493 }
1494
1495 bytes_written = snprintf(command, total_len, "%s %d",
1496 CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period);
1497
1498 return bytes_written;
1499 }
1500
1501 int wl_android_set_country_rev(
1502 struct net_device *dev, char* command)
1503 {
1504 int error = 0;
1505 wl_country_t cspec = {{0}, 0, {0} };
1506 char country_code[WLC_CNTRY_BUF_SZ];
1507 char smbuf[WLC_IOCTL_SMLEN];
1508 int rev = 0;
1509
1510 memset(country_code, 0, sizeof(country_code));
1511 sscanf(command+sizeof("SETCOUNTRYREV"), "%3s %10d", country_code, &rev);
1512 WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev));
1513
1514 memcpy(cspec.country_abbrev, country_code, sizeof(country_code));
1515 memcpy(cspec.ccode, country_code, sizeof(country_code));
1516 cspec.rev = rev;
1517
1518 error = wldev_iovar_setbuf(dev, "country", (char *)&cspec,
1519 sizeof(cspec), smbuf, sizeof(smbuf), NULL);
1520
1521 if (error) {
1522 DHD_ERROR(("%s: set country '%s/%d' failed code %d\n",
1523 __FUNCTION__, cspec.ccode, cspec.rev, error));
1524 } else {
1525 dhd_bus_country_set(dev, &cspec, true);
1526 DHD_INFO(("%s: set country '%s/%d'\n",
1527 __FUNCTION__, cspec.ccode, cspec.rev));
1528 }
1529
1530 return error;
1531 }
1532
1533 static int wl_android_get_country_rev(
1534 struct net_device *dev, char *command, int total_len)
1535 {
1536 int error;
1537 int bytes_written;
1538 char smbuf[WLC_IOCTL_SMLEN];
1539 wl_country_t cspec;
1540
1541 error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf,
1542 sizeof(smbuf), NULL);
1543
1544 if (error) {
1545 DHD_ERROR(("%s: get country failed code %d\n",
1546 __FUNCTION__, error));
1547 return -1;
1548 } else {
1549 memcpy(&cspec, smbuf, sizeof(cspec));
1550 DHD_INFO(("%s: get country '%c%c %d'\n",
1551 __FUNCTION__, cspec.ccode[0], cspec.ccode[1], cspec.rev));
1552 }
1553
1554 bytes_written = snprintf(command, total_len, "%s %c%c %d",
1555 CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev);
1556
1557 return bytes_written;
1558 }
1559 #endif /* ROAM_API */
1560
1561 #ifdef WES_SUPPORT
1562 int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len)
1563 {
1564 int error = 0;
1565 int bytes_written = 0;
1566 int mode = 0;
1567
1568 error = get_roamscan_mode(dev, &mode);
1569 if (error) {
1570 DHD_ERROR(("%s: Failed to get Scan Control, error = %d\n", __FUNCTION__, error));
1571 return -1;
1572 }
1573
1574 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode);
1575
1576 return bytes_written;
1577 }
1578
1579 int wl_android_set_roam_scan_control(struct net_device *dev, char *command)
1580 {
1581 int error = 0;
1582 int mode = 0;
1583
1584 if (sscanf(command, "%*s %d", &mode) != 1) {
1585 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1586 return -1;
1587 }
1588
1589 error = set_roamscan_mode(dev, mode);
1590 if (error) {
1591 DHD_ERROR(("%s: Failed to set Scan Control %d, error = %d\n",
1592 __FUNCTION__, mode, error));
1593 return -1;
1594 }
1595
1596 return 0;
1597 }
1598
1599 int wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len)
1600 {
1601 int bytes_written = 0;
1602 unsigned char channels[MAX_ROAM_CHANNEL] = {0};
1603 int channel_cnt = 0;
1604 int i = 0;
1605 int buf_avail, len;
1606
1607 channel_cnt = get_roamscan_channel_list(dev, channels, MAX_ROAM_CHANNEL);
1608 bytes_written = snprintf(command, total_len, "%s %d",
1609 CMD_GETROAMSCANCHANNELS, channel_cnt);
1610 buf_avail = total_len - bytes_written;
1611 for (i = 0; i < channel_cnt; i++) {
1612 /* A return value of 'buf_avail' or more means that the output was truncated */
1613 len = snprintf(command + bytes_written, buf_avail, " %d", channels[i]);
1614 if (len >= buf_avail) {
1615 WL_ERR(("%s: Insufficient memory, %d bytes\n", __FUNCTION__, total_len));
1616 bytes_written = -1;
1617 break;
1618 }
1619 /* 'buf_avail' decremented by number of bytes written */
1620 buf_avail -= len;
1621 bytes_written += len;
1622 }
1623 WL_INFORM(("%s: %s\n", __FUNCTION__, command));
1624 return bytes_written;
1625 }
1626
1627 int wl_android_set_roam_scan_channels(struct net_device *dev, char *command)
1628 {
1629 int error = 0;
1630 unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1);
1631 int get_ioctl_version = wl_cfg80211_get_ioctl_version();
1632 error = set_roamscan_channel_list(dev, p[0], &p[1], get_ioctl_version);
1633 if (error) {
1634 DHD_ERROR(("%s: Failed to set Scan Channels %d, error = %d\n",
1635 __FUNCTION__, p[0], error));
1636 return -1;
1637 }
1638
1639 return 0;
1640 }
1641
1642 int wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len)
1643 {
1644 int error = 0;
1645 int bytes_written = 0;
1646 int time = 0;
1647
1648 error = wldev_ioctl_get(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time));
1649 if (error) {
1650 DHD_ERROR(("%s: Failed to get Scan Channel Time, error = %d\n",
1651 __FUNCTION__, error));
1652 return -1;
1653 }
1654
1655 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time);
1656
1657 return bytes_written;
1658 }
1659
1660 int wl_android_set_scan_channel_time(struct net_device *dev, char *command)
1661 {
1662 int error = 0;
1663 int time = 0;
1664
1665 if (sscanf(command, "%*s %d", &time) != 1) {
1666 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1667 return -1;
1668 }
1669 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1670 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_CHANNEL_TIME, time);
1671 error = wldev_ioctl_set(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time));
1672 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1673 if (error) {
1674 DHD_ERROR(("%s: Failed to set Scan Channel Time %d, error = %d\n",
1675 __FUNCTION__, time, error));
1676 return -1;
1677 }
1678
1679 return 0;
1680 }
1681
1682 int
1683 wl_android_get_scan_unassoc_time(struct net_device *dev, char *command, int total_len)
1684 {
1685 int error = 0;
1686 int bytes_written = 0;
1687 int time = 0;
1688
1689 error = wldev_ioctl_get(dev, WLC_GET_SCAN_UNASSOC_TIME, &time, sizeof(time));
1690 if (error) {
1691 DHD_ERROR(("%s: Failed to get Scan Unassoc Time, error = %d\n",
1692 __FUNCTION__, error));
1693 return -1;
1694 }
1695
1696 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANUNASSOCTIME, time);
1697
1698 return bytes_written;
1699 }
1700
1701 int
1702 wl_android_set_scan_unassoc_time(struct net_device *dev, char *command)
1703 {
1704 int error = 0;
1705 int time = 0;
1706
1707 if (sscanf(command, "%*s %d", &time) != 1) {
1708 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1709 return -1;
1710 }
1711 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1712 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_UNASSOC_TIME, time);
1713 error = wldev_ioctl_set(dev, WLC_SET_SCAN_UNASSOC_TIME, &time, sizeof(time));
1714 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1715 if (error) {
1716 DHD_ERROR(("%s: Failed to set Scan Unassoc Time %d, error = %d\n",
1717 __FUNCTION__, time, error));
1718 return -1;
1719 }
1720
1721 return 0;
1722 }
1723
1724 int
1725 wl_android_get_scan_passive_time(struct net_device *dev, char *command, int total_len)
1726 {
1727 int error = 0;
1728 int bytes_written = 0;
1729 int time = 0;
1730
1731 error = wldev_ioctl_get(dev, WLC_GET_SCAN_PASSIVE_TIME, &time, sizeof(time));
1732 if (error) {
1733 DHD_ERROR(("%s: Failed to get Scan Passive Time, error = %d\n",
1734 __FUNCTION__, error));
1735 return -1;
1736 }
1737
1738 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANPASSIVETIME, time);
1739
1740 return bytes_written;
1741 }
1742
1743 int
1744 wl_android_set_scan_passive_time(struct net_device *dev, char *command)
1745 {
1746 int error = 0;
1747 int time = 0;
1748
1749 if (sscanf(command, "%*s %d", &time) != 1) {
1750 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1751 return -1;
1752 }
1753 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1754 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_PASSIVE_TIME, time);
1755 error = wldev_ioctl_set(dev, WLC_SET_SCAN_PASSIVE_TIME, &time, sizeof(time));
1756 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1757 if (error) {
1758 DHD_ERROR(("%s: Failed to set Scan Passive Time %d, error = %d\n",
1759 __FUNCTION__, time, error));
1760 return -1;
1761 }
1762
1763 return 0;
1764 }
1765
1766 int wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len)
1767 {
1768 int error = 0;
1769 int bytes_written = 0;
1770 int time = 0;
1771
1772 error = wldev_ioctl_get(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time));
1773 if (error) {
1774 DHD_ERROR(("Failed to get Scan Home Time, error = %d\n", error));
1775 return -1;
1776 }
1777
1778 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time);
1779
1780 return bytes_written;
1781 }
1782
1783 int wl_android_set_scan_home_time(struct net_device *dev, char *command)
1784 {
1785 int error = 0;
1786 int time = 0;
1787
1788 if (sscanf(command, "%*s %d", &time) != 1) {
1789 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1790 return -1;
1791 }
1792 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1793 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_TIME, time);
1794 error = wldev_ioctl_set(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time));
1795 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1796 if (error) {
1797 DHD_ERROR(("%s: Failed to set Scan Home Time %d, error = %d\n",
1798 __FUNCTION__, time, error));
1799 return -1;
1800 }
1801
1802 return 0;
1803 }
1804
1805 int wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len)
1806 {
1807 int error = 0;
1808 int bytes_written = 0;
1809 int time = 0;
1810
1811 error = wldev_iovar_getint(dev, "scan_home_away_time", &time);
1812 if (error) {
1813 DHD_ERROR(("%s: Failed to get Scan Home Away Time, error = %d\n",
1814 __FUNCTION__, error));
1815 return -1;
1816 }
1817
1818 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time);
1819
1820 return bytes_written;
1821 }
1822
1823 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command)
1824 {
1825 int error = 0;
1826 int time = 0;
1827
1828 if (sscanf(command, "%*s %d", &time) != 1) {
1829 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1830 return -1;
1831 }
1832 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1833 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_AWAY_TIME, time);
1834 error = wldev_iovar_setint(dev, "scan_home_away_time", time);
1835 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1836 if (error) {
1837 DHD_ERROR(("%s: Failed to set Scan Home Away Time %d, error = %d\n",
1838 __FUNCTION__, time, error));
1839 return -1;
1840 }
1841
1842 return 0;
1843 }
1844
1845 int wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len)
1846 {
1847 int error = 0;
1848 int bytes_written = 0;
1849 int num = 0;
1850
1851 error = wldev_ioctl_get(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num));
1852 if (error) {
1853 DHD_ERROR(("%s: Failed to get Scan NProbes, error = %d\n", __FUNCTION__, error));
1854 return -1;
1855 }
1856
1857 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num);
1858
1859 return bytes_written;
1860 }
1861
1862 int wl_android_set_scan_nprobes(struct net_device *dev, char *command)
1863 {
1864 int error = 0;
1865 int num = 0;
1866
1867 if (sscanf(command, "%*s %d", &num) != 1) {
1868 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1869 return -1;
1870 }
1871
1872 error = wldev_ioctl_set(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num));
1873 if (error) {
1874 DHD_ERROR(("%s: Failed to set Scan NProbes %d, error = %d\n",
1875 __FUNCTION__, num, error));
1876 return -1;
1877 }
1878
1879 return 0;
1880 }
1881
1882 int wl_android_get_scan_dfs_channel_mode(struct net_device *dev, char *command, int total_len)
1883 {
1884 int error = 0;
1885 int bytes_written = 0;
1886 int mode = 0;
1887 int scan_passive_time = 0;
1888
1889 error = wldev_iovar_getint(dev, "scan_passive_time", &scan_passive_time);
1890 if (error) {
1891 DHD_ERROR(("%s: Failed to get Passive Time, error = %d\n", __FUNCTION__, error));
1892 return -1;
1893 }
1894
1895 if (scan_passive_time == 0) {
1896 mode = 0;
1897 } else {
1898 mode = 1;
1899 }
1900
1901 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETDFSSCANMODE, mode);
1902
1903 return bytes_written;
1904 }
1905
1906 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command)
1907 {
1908 int error = 0;
1909 int mode = 0;
1910 int scan_passive_time = 0;
1911
1912 if (sscanf(command, "%*s %d", &mode) != 1) {
1913 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1914 return -1;
1915 }
1916
1917 if (mode == 1) {
1918 scan_passive_time = DHD_SCAN_PASSIVE_TIME;
1919 } else if (mode == 0) {
1920 scan_passive_time = 0;
1921 } else {
1922 DHD_ERROR(("%s: Failed to set Scan DFS channel mode %d, error = %d\n",
1923 __FUNCTION__, mode, error));
1924 return -1;
1925 }
1926 error = wldev_iovar_setint(dev, "scan_passive_time", scan_passive_time);
1927 if (error) {
1928 DHD_ERROR(("%s: Failed to set Scan Passive Time %d, error = %d\n",
1929 __FUNCTION__, scan_passive_time, error));
1930 return -1;
1931 }
1932
1933 return 0;
1934 }
1935
1936 #define JOINPREFFER_BUF_SIZE 12
1937
1938 static int
1939 wl_android_set_join_prefer(struct net_device *dev, char *command)
1940 {
1941 int error = BCME_OK;
1942 char smbuf[WLC_IOCTL_SMLEN];
1943 uint8 buf[JOINPREFFER_BUF_SIZE];
1944 char *pcmd;
1945 int total_len_left;
1946 int i;
1947 char hex[] = "XX";
1948 #ifdef WBTEXT
1949 char commandp[WLC_IOCTL_SMLEN];
1950 char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
1951 #endif /* WBTEXT */
1952
1953 pcmd = command + strlen(CMD_SETJOINPREFER) + 1;
1954 total_len_left = strlen(pcmd);
1955
1956 memset(buf, 0, sizeof(buf));
1957
1958 if (total_len_left != JOINPREFFER_BUF_SIZE << 1) {
1959 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1960 return BCME_ERROR;
1961 }
1962
1963 /* Store the MSB first, as required by join_pref */
1964 for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) {
1965 hex[0] = *pcmd++;
1966 hex[1] = *pcmd++;
1967 buf[i] = (uint8)simple_strtoul(hex, NULL, 16);
1968 }
1969
1970 #ifdef WBTEXT
1971 /* No coexistance between 11kv and join pref */
1972 if (wl_android_check_wbtext(dev)) {
1973 memset(commandp, 0, sizeof(commandp));
1974 if (memcmp(buf, clear, sizeof(buf)) == 0) {
1975 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 1");
1976 } else {
1977 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 0");
1978 }
1979 if ((error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN)) != BCME_OK) {
1980 DHD_ERROR(("Failed to set WBTEXT = %d\n", error));
1981 return error;
1982 }
1983 }
1984 #endif /* WBTEXT */
1985
1986 prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE);
1987 error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE,
1988 smbuf, sizeof(smbuf), NULL);
1989 if (error) {
1990 DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
1991 }
1992
1993 return error;
1994 }
1995
1996 int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len)
1997 {
1998 int error = -1;
1999 android_wifi_af_params_t *params = NULL;
2000 wl_action_frame_t *action_frame = NULL;
2001 wl_af_params_t *af_params = NULL;
2002 char *smbuf = NULL;
2003 struct ether_addr tmp_bssid;
2004 int tmp_channel = 0;
2005 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2006
2007 if (total_len <
2008 (strlen(CMD_SENDACTIONFRAME) + 1 + sizeof(android_wifi_af_params_t))) {
2009 DHD_ERROR(("%s: Invalid parameters \n", __FUNCTION__));
2010 goto send_action_frame_out;
2011 }
2012
2013 params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1);
2014
2015 if ((uint16)params->len > ANDROID_WIFI_ACTION_FRAME_SIZE) {
2016 DHD_ERROR(("%s: Requested action frame len was out of range(%d)\n",
2017 __FUNCTION__, params->len));
2018 goto send_action_frame_out;
2019 }
2020
2021 smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
2022 if (smbuf == NULL) {
2023 DHD_ERROR(("%s: failed to allocated memory %d bytes\n",
2024 __FUNCTION__, WLC_IOCTL_MAXLEN));
2025 goto send_action_frame_out;
2026 }
2027
2028 af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
2029 if (af_params == NULL) {
2030 DHD_ERROR(("%s: unable to allocate frame\n", __FUNCTION__));
2031 goto send_action_frame_out;
2032 }
2033
2034 memset(&tmp_bssid, 0, ETHER_ADDR_LEN);
2035 if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) {
2036 memset(&tmp_bssid, 0, ETHER_ADDR_LEN);
2037
2038 error = wldev_ioctl_get(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2039 if (error) {
2040 memset(&tmp_bssid, 0, ETHER_ADDR_LEN);
2041 DHD_ERROR(("%s: failed to get bssid, error=%d\n", __FUNCTION__, error));
2042 goto send_action_frame_out;
2043 }
2044 }
2045
2046 if (params->channel < 0) {
2047 struct channel_info ci;
2048 memset(&ci, 0, sizeof(ci));
2049 error = wldev_ioctl_get(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
2050 if (error) {
2051 DHD_ERROR(("%s: failed to get channel, error=%d\n", __FUNCTION__, error));
2052 goto send_action_frame_out;
2053 }
2054
2055 tmp_channel = ci.hw_channel;
2056 }
2057 else {
2058 tmp_channel = params->channel;
2059 }
2060
2061 af_params->channel = tmp_channel;
2062 af_params->dwell_time = params->dwell_time;
2063 memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2064 action_frame = &af_params->action_frame;
2065
2066 action_frame->packetId = 0;
2067 memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN);
2068 action_frame->len = (uint16)params->len;
2069 memcpy(action_frame->data, params->data, action_frame->len);
2070
2071 error = wldev_iovar_setbuf(dev, "actframe", af_params,
2072 sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
2073 if (error) {
2074 DHD_ERROR(("%s: failed to set action frame, error=%d\n", __FUNCTION__, error));
2075 }
2076
2077 send_action_frame_out:
2078 if (af_params) {
2079 MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
2080 }
2081
2082 if (smbuf) {
2083 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
2084 }
2085
2086 if (error)
2087 return -1;
2088 else
2089 return 0;
2090 }
2091
2092 int wl_android_reassoc(struct net_device *dev, char *command, int total_len)
2093 {
2094 int error = 0;
2095 android_wifi_reassoc_params_t *params = NULL;
2096 uint band;
2097 chanspec_t channel;
2098 u32 params_size;
2099 wl_reassoc_params_t reassoc_params;
2100
2101 if (total_len <
2102 (strlen(CMD_REASSOC) + 1 + sizeof(android_wifi_reassoc_params_t))) {
2103 DHD_ERROR(("%s: Invalid parameters \n", __FUNCTION__));
2104 return -1;
2105 }
2106 params = (android_wifi_reassoc_params_t *)(command + strlen(CMD_REASSOC) + 1);
2107
2108 memset(&reassoc_params, 0, WL_REASSOC_PARAMS_FIXED_SIZE);
2109
2110 if (bcm_ether_atoe((const char *)params->bssid,
2111 (struct ether_addr *)&reassoc_params.bssid) == 0) {
2112 DHD_ERROR(("%s: Invalid bssid \n", __FUNCTION__));
2113 return -1;
2114 }
2115
2116 if (params->channel < 0) {
2117 DHD_ERROR(("%s: Invalid Channel \n", __FUNCTION__));
2118 return -1;
2119 }
2120
2121 reassoc_params.chanspec_num = 1;
2122
2123 channel = params->channel;
2124 #ifdef D11AC_IOTYPES
2125 if (wl_cfg80211_get_ioctl_version() == 1) {
2126 band = ((channel <= CH_MAX_2G_CHANNEL) ?
2127 WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G);
2128 reassoc_params.chanspec_list[0] = channel |
2129 band | WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
2130 }
2131 else {
2132 band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
2133 reassoc_params.chanspec_list[0] = channel | band | WL_CHANSPEC_BW_20;
2134 }
2135 #else
2136 band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
2137 reassoc_params.chanspec_list[0] = channel |
2138 band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
2139 #endif /* D11AC_IOTYPES */
2140 params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t);
2141
2142 error = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, params_size);
2143 if (error) {
2144 DHD_ERROR(("%s: failed to reassoc, error=%d\n", __FUNCTION__, error));
2145 return -1;
2146 }
2147 return 0;
2148 }
2149
2150 int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len)
2151 {
2152 int bytes_written = 0;
2153 int mode = 0;
2154
2155 mode = wl_cfg80211_get_wes_mode();
2156
2157 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode);
2158
2159 return bytes_written;
2160 }
2161
2162 int wl_android_set_wes_mode(struct net_device *dev, char *command)
2163 {
2164 int error = 0;
2165 int mode = 0;
2166 #ifdef WBTEXT
2167 char commandp[WLC_IOCTL_SMLEN];
2168 #endif /* WBTEXT */
2169
2170 if (sscanf(command, "%*s %d", &mode) != 1) {
2171 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
2172 return -1;
2173 }
2174
2175 error = wl_cfg80211_set_wes_mode(mode);
2176 if (error) {
2177 DHD_ERROR(("%s: Failed to set WES Mode %d, error = %d\n",
2178 __FUNCTION__, mode, error));
2179 return -1;
2180 }
2181
2182 #ifdef WBTEXT
2183 /* No coexistance between 11kv and FMC */
2184 if (wl_android_check_wbtext(dev)) {
2185 memset(commandp, 0, sizeof(commandp));
2186 if (!mode) {
2187 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 1");
2188 } else {
2189 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 0");
2190 }
2191 if ((error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN)) != BCME_OK) {
2192 DHD_ERROR(("Failed to set WBTEXT = %d\n", error));
2193 return error;
2194 }
2195 }
2196 #endif /* WBTEXT */
2197
2198 return 0;
2199 }
2200
2201 int wl_android_get_okc_mode(struct net_device *dev, char *command, int total_len)
2202 {
2203 int error = 0;
2204 int bytes_written = 0;
2205 int mode = 0;
2206
2207 error = wldev_iovar_getint(dev, "okc_enable", &mode);
2208 if (error) {
2209 DHD_ERROR(("%s: Failed to get OKC Mode, error = %d\n", __FUNCTION__, error));
2210 return -1;
2211 }
2212
2213 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETOKCMODE, mode);
2214
2215 return bytes_written;
2216 }
2217
2218 int wl_android_set_okc_mode(struct net_device *dev, char *command)
2219 {
2220 int error = 0;
2221 int mode = 0;
2222
2223 if (sscanf(command, "%*s %d", &mode) != 1) {
2224 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
2225 return -1;
2226 }
2227
2228 error = wldev_iovar_setint(dev, "okc_enable", mode);
2229 if (error) {
2230 DHD_ERROR(("%s: Failed to set OKC Mode %d, error = %d\n",
2231 __FUNCTION__, mode, error));
2232 return -1;
2233 }
2234
2235 return error;
2236 }
2237 static int
2238 wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
2239 {
2240 uchar pmk[33];
2241 int error = 0;
2242 char smbuf[WLC_IOCTL_SMLEN];
2243 #ifdef OKC_DEBUG
2244 int i = 0;
2245 #endif // endif
2246
2247 if (total_len < (strlen("SET_PMK ") + 32)) {
2248 DHD_ERROR(("%s: Invalid argument\n", __FUNCTION__));
2249 return -1;
2250 }
2251 bzero(pmk, sizeof(pmk));
2252 memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
2253 error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
2254 if (error) {
2255 DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
2256 }
2257 #ifdef OKC_DEBUG
2258 DHD_ERROR(("PMK is "));
2259 for (i = 0; i < 32; i++)
2260 DHD_ERROR(("%02X ", pmk[i]));
2261
2262 DHD_ERROR(("\n"));
2263 #endif // endif
2264 return error;
2265 }
2266
2267 static int
2268 wl_android_okc_enable(struct net_device *dev, char *command)
2269 {
2270 int error = 0;
2271 char okc_enable = 0;
2272
2273 okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
2274 error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
2275 if (error) {
2276 DHD_ERROR(("Failed to %s OKC, error = %d\n",
2277 okc_enable ? "enable" : "disable", error));
2278 }
2279
2280 return error;
2281 }
2282 #endif /* WES_SUPPORT */
2283
2284 #ifdef SUPPORT_RESTORE_SCAN_PARAMS
2285 static int
2286 wl_android_restore_scan_params(struct net_device *dev, char *command, int total_len)
2287 {
2288 int error = 0;
2289 uint error_cnt = 0;
2290 int cnt = 0;
2291 char restore_command[WLC_IOCTL_SMLEN];
2292
2293 while (strlen(restore_params[cnt].command) > 0 && restore_params[cnt].cmd_handler) {
2294 sprintf(restore_command, "%s %d", restore_params[cnt].command,
2295 restore_params[cnt].parameter);
2296 printk("CNT : %d\n", cnt);
2297 printk("COMMAND : %s\n", restore_command);
2298 if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD) {
2299 error = restore_params[cnt].cmd_handler(dev, restore_command);
2300 } else if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD_WITH_LEN) {
2301 error = restore_params[cnt].cmd_handler_w_len(dev,
2302 restore_command, total_len);
2303 } else {
2304 DHD_ERROR(("Unknown restore command handler\n"));
2305 error = -1;
2306 }
2307 if (error) {
2308 DHD_ERROR(("Failed to restore scan parameters %s, error : %d\n",
2309 restore_command, error));
2310 error_cnt++;
2311 }
2312 cnt++;
2313 }
2314 if (error_cnt > 0) {
2315 DHD_ERROR(("Got %d error(s) while restoring scan parameters\n",
2316 error_cnt));
2317 error = -1;
2318 }
2319 return error;
2320 }
2321 #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
2322
2323 #ifdef WLTDLS
2324 int wl_android_tdls_reset(struct net_device *dev)
2325 {
2326 int ret = 0;
2327 ret = dhd_tdls_enable(dev, false, false, NULL);
2328 if (ret < 0) {
2329 DHD_ERROR(("Disable tdls failed. %d\n", ret));
2330 return ret;
2331 }
2332 ret = dhd_tdls_enable(dev, true, true, NULL);
2333 if (ret < 0) {
2334 DHD_ERROR(("enable tdls failed. %d\n", ret));
2335 return ret;
2336 }
2337 return 0;
2338 }
2339 #endif /* WLTDLS */
2340 #ifdef FCC_PWR_LIMIT_2G
2341 int
2342 wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command)
2343 {
2344 int error = 0;
2345 int enable = 0;
2346
2347 sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable);
2348
2349 if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) {
2350 DHD_ERROR(("%s: Invalid data\n", __FUNCTION__));
2351 return BCME_ERROR;
2352 }
2353
2354 CUSTOMER_HW4_EN_CONVERT(enable);
2355
2356 DHD_ERROR(("%s: fccpwrlimit2g set (%d)\n", __FUNCTION__, enable));
2357 error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
2358 if (error) {
2359 DHD_ERROR(("%s: fccpwrlimit2g set returned (%d)\n", __FUNCTION__, error));
2360 return BCME_ERROR;
2361 }
2362
2363 return error;
2364 }
2365
2366 int
2367 wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
2368 {
2369 int error = 0;
2370 int enable = 0;
2371 int bytes_written = 0;
2372
2373 error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable);
2374 if (error) {
2375 DHD_ERROR(("%s: fccpwrlimit2g get error (%d)\n", __FUNCTION__, error));
2376 return BCME_ERROR;
2377 }
2378 DHD_ERROR(("%s: fccpwrlimit2g get (%d)\n", __FUNCTION__, enable));
2379
2380 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable);
2381
2382 return bytes_written;
2383 }
2384 #endif /* FCC_PWR_LIMIT_2G */
2385
2386 s32
2387 wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
2388 {
2389 int bytes_written = -1, ret = 0;
2390 char *pcmd = command;
2391 char *str;
2392 sta_info_v4_t *sta = NULL;
2393 const wl_cnt_wlc_t* wlc_cnt = NULL;
2394 struct ether_addr mac;
2395 char *iovar_buf;
2396 /* Client information */
2397 uint16 cap = 0;
2398 uint32 rxrtry = 0;
2399 uint32 rxmulti = 0;
2400 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2401
2402 #ifdef BIGDATA_SOFTAP
2403 void *data = NULL;
2404 int get_bigdata_softap = FALSE;
2405 wl_ap_sta_data_t *sta_data = NULL;
2406 struct bcm_cfg80211 *bcm_cfg = wl_get_cfg(dev);
2407 #endif /* BIGDATA_SOFTAP */
2408
2409 WL_DBG(("%s\n", command));
2410
2411 iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
2412 if (iovar_buf == NULL) {
2413 DHD_ERROR(("%s: failed to allocated memory %d bytes\n",
2414 __FUNCTION__, WLC_IOCTL_MAXLEN));
2415 goto error;
2416 }
2417
2418 str = bcmstrtok(&pcmd, " ", NULL);
2419 if (str) {
2420 str = bcmstrtok(&pcmd, " ", NULL);
2421 /* If GETSTAINFO subcmd name is not provided, return error */
2422 if (str == NULL) {
2423 WL_ERR(("GETSTAINFO subcmd not provided %s\n", __FUNCTION__));
2424 goto error;
2425 }
2426
2427 memset(&mac, 0, ETHER_ADDR_LEN);
2428 if ((bcm_ether_atoe((str), &mac))) {
2429 /* get the sta info */
2430 ret = wldev_iovar_getbuf(dev, "sta_info",
2431 (struct ether_addr *)mac.octet,
2432 ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
2433 #ifdef BIGDATA_SOFTAP
2434 get_bigdata_softap = TRUE;
2435 #endif /* BIGDATA_SOFTAP */
2436 if (ret < 0) {
2437 WL_ERR(("Get sta_info ERR %d\n", ret));
2438 #ifdef BIGDATA_SOFTAP
2439 goto get_bigdata;
2440 #else
2441 /* In case framework assumes the BIGDATA_SOFTAP
2442 * is enabled in DHD, the return value causes
2443 * triggering HANG event.
2444 */
2445 bytes_written = BCME_UNSUPPORTED;
2446 goto error;
2447 #endif /* BIGDATA_SOFTAP */
2448 }
2449
2450 sta = (sta_info_v4_t *)iovar_buf;
2451 if (dtoh16(sta->ver) != WL_STA_VER_4) {
2452 WL_ERR(("sta_info struct version mismatch, "
2453 "host ver : %d, fw ver : %d\n", WL_STA_VER_4,
2454 dtoh16(sta->ver)));
2455 goto error;
2456 }
2457 cap = dtoh16(sta->cap);
2458 rxrtry = dtoh32(sta->rx_pkts_retried);
2459 rxmulti = dtoh32(sta->rx_mcast_pkts);
2460 } else if ((!strncmp(str, "all", 3)) || (!strncmp(str, "ALL", 3))) {
2461 /* get counters info */
2462 ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
2463 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2464 if (unlikely(ret)) {
2465 WL_ERR(("counters error (%d) - size = %zu\n",
2466 ret, sizeof(wl_cnt_wlc_t)));
2467 goto error;
2468 }
2469 ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
2470 if (ret != BCME_OK) {
2471 WL_ERR(("wl_cntbuf_to_xtlv_format ERR %d\n", ret));
2472 goto error;
2473 }
2474 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
2475 WL_ERR(("wlc_cnt NULL!\n"));
2476 goto error;
2477 }
2478
2479 rxrtry = dtoh32(wlc_cnt->rxrtry);
2480 rxmulti = dtoh32(wlc_cnt->rxmulti);
2481 } else {
2482 WL_ERR(("Get address fail\n"));
2483 goto error;
2484 }
2485 } else {
2486 WL_ERR(("Command ERR\n"));
2487 goto error;
2488 }
2489
2490 #ifdef BIGDATA_SOFTAP
2491 get_bigdata:
2492 if (get_bigdata_softap) {
2493 WL_ERR(("mac " MACDBG" \n", MAC2STRDBG((char*)&mac)));
2494 if (wl_get_ap_stadata(bcm_cfg, &mac, &data) == BCME_OK) {
2495 sta_data = (wl_ap_sta_data_t *)data;
2496 bytes_written = snprintf(command, total_len,
2497 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
2498 "CAP=%04x "MACOUI" %d %s %d %d %d %d %d %d\n",
2499 CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap,
2500 MACOUI2STR((char*)&sta_data->mac),
2501 sta_data->channel,
2502 wf_chspec_to_bw_str(sta_data->chanspec),
2503 sta_data->rssi, sta_data->rate,
2504 sta_data->mode_80211, sta_data->nss, sta_data->mimo,
2505 sta_data->reason_code);
2506 WL_ERR_KERN(("command %s\n", command));
2507 goto error;
2508 }
2509 }
2510 #endif /* BIGDATA_SOFTAP */
2511 bytes_written = snprintf(command, total_len,
2512 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x\n",
2513 CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap);
2514
2515 WL_DBG(("%s", command));
2516
2517 error:
2518 if (iovar_buf) {
2519 MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MAXLEN);
2520
2521 }
2522 return bytes_written;
2523 }
2524 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
2525
2526 #ifdef WBTEXT
2527 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
2528 {
2529 int error = BCME_OK, argc = 0;
2530 int data, bytes_written;
2531 int roam_trigger[2];
2532 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
2533
2534 argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
2535 if (!argc) {
2536 error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
2537 if (error) {
2538 DHD_ERROR(("%s: Failed to set wbtext error = %d\n",
2539 __FUNCTION__, error));
2540 return error;
2541 }
2542 bytes_written = snprintf(command, total_len, "WBTEXT %s\n",
2543 (data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)?
2544 "ENABLED" : "DISABLED");
2545 return bytes_written;
2546 } else {
2547 if (data) {
2548 data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT;
2549 }
2550
2551 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
2552 DHD_ERROR(("%s: Failed to set wbtext error = %d\n",
2553 __FUNCTION__, error));
2554 return error;
2555 }
2556
2557 if (data) {
2558 /* reset roam_prof when wbtext is on */
2559 if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) {
2560 return error;
2561 }
2562 dhdp->wbtext_support = TRUE;
2563 } else {
2564 /* reset legacy roam trigger when wbtext is off */
2565 roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE;
2566 roam_trigger[1] = WLC_BAND_ALL;
2567 if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
2568 sizeof(roam_trigger))) != BCME_OK) {
2569 DHD_ERROR(("%s: Failed to reset roam trigger = %d\n",
2570 __FUNCTION__, error));
2571 return error;
2572 }
2573 dhdp->wbtext_support = FALSE;
2574 }
2575 }
2576 return error;
2577 }
2578
2579 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
2580 char *command, int total_len)
2581 {
2582 int error = BCME_OK, argc = 0;
2583 int data, bytes_written;
2584
2585 argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data);
2586 if (!argc) {
2587 error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data);
2588 if (error) {
2589 WL_ERR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error));
2590 return error;
2591 }
2592 bytes_written = snprintf(command, total_len, "%d\n", data);
2593 return bytes_written;
2594 } else {
2595 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold",
2596 data)) != BCME_OK) {
2597 WL_ERR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error));
2598 return error;
2599 }
2600 }
2601 return error;
2602 }
2603
2604 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
2605 char *command, int total_len)
2606 {
2607 int error = BCME_OK, argc = 0;
2608 int data = 0, bytes_written;
2609
2610 argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data);
2611 if (!argc) {
2612 error = wldev_iovar_getint(dev, "wnm_btmdelta", &data);
2613 if (error) {
2614 WL_ERR(("Failed to get wnm_btmdelta (%d)\n", error));
2615 return error;
2616 }
2617 bytes_written = snprintf(command, total_len, "%d\n", data);
2618 return bytes_written;
2619 } else {
2620 if ((error = wldev_iovar_setint(dev, "wnm_btmdelta",
2621 data)) != BCME_OK) {
2622 WL_ERR(("Failed to set wnm_btmdelta (%d)\n", error));
2623 return error;
2624 }
2625 }
2626 return error;
2627 }
2628
2629 #endif /* WBTEXT */
2630
2631 #ifdef PNO_SUPPORT
2632 #define PNO_PARAM_SIZE 50
2633 #define VALUE_SIZE 50
2634 #define LIMIT_STR_FMT ("%50s %50s")
2635 static int
2636 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
2637 {
2638 int err = BCME_OK;
2639 uint i, tokens, len_remain;
2640 char *pos, *pos2, *token, *token2, *delim;
2641 char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
2642 struct dhd_pno_batch_params batch_params;
2643
2644 DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
2645 len_remain = total_len;
2646 if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) {
2647 pos = command + strlen(CMD_WLS_BATCHING) + 1;
2648 len_remain -= strlen(CMD_WLS_BATCHING) + 1;
2649 } else {
2650 WL_ERR(("%s: No arguments, total_len %d\n", __FUNCTION__, total_len));
2651 err = BCME_ERROR;
2652 goto exit;
2653 }
2654 memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params));
2655 if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
2656 if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) {
2657 pos += strlen(PNO_BATCHING_SET) + 1;
2658 } else {
2659 WL_ERR(("%s: %s missing arguments, total_len %d\n",
2660 __FUNCTION__, PNO_BATCHING_SET, total_len));
2661 err = BCME_ERROR;
2662 goto exit;
2663 }
2664 while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
2665 memset(param, 0, sizeof(param));
2666 memset(value, 0, sizeof(value));
2667 if (token == NULL || !*token)
2668 break;
2669 if (*token == '\0')
2670 continue;
2671 delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
2672 if (delim != NULL)
2673 *delim = ' ';
2674
2675 tokens = sscanf(token, LIMIT_STR_FMT, param, value);
2676 if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
2677 batch_params.scan_fr = simple_strtol(value, NULL, 0);
2678 DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr));
2679 } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
2680 batch_params.bestn = simple_strtol(value, NULL, 0);
2681 DHD_PNO(("bestn : %d\n", batch_params.bestn));
2682 } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
2683 batch_params.mscan = simple_strtol(value, NULL, 0);
2684 DHD_PNO(("mscan : %d\n", batch_params.mscan));
2685 } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
2686 i = 0;
2687 pos2 = value;
2688 tokens = sscanf(value, "<%s>", value);
2689 if (tokens != 1) {
2690 err = BCME_ERROR;
2691 DHD_ERROR(("%s : invalid format for channel"
2692 " <> params\n", __FUNCTION__));
2693 goto exit;
2694 }
2695 while ((token2 = strsep(&pos2,
2696 PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
2697 if (token2 == NULL || !*token2)
2698 break;
2699 if (*token2 == '\0')
2700 continue;
2701 if (*token2 == 'A' || *token2 == 'B') {
2702 batch_params.band = (*token2 == 'A')?
2703 WLC_BAND_5G : WLC_BAND_2G;
2704 DHD_PNO(("band : %s\n",
2705 (*token2 == 'A')? "A" : "B"));
2706 } else {
2707 if ((batch_params.nchan >= WL_NUMCHANNELS) ||
2708 (i >= WL_NUMCHANNELS)) {
2709 DHD_ERROR(("Too many nchan %d\n",
2710 batch_params.nchan));
2711 err = BCME_BUFTOOSHORT;
2712 goto exit;
2713 }
2714 batch_params.chan_list[i++] =
2715 simple_strtol(token2, NULL, 0);
2716 batch_params.nchan++;
2717 DHD_PNO(("channel :%d\n",
2718 batch_params.chan_list[i-1]));
2719 }
2720 }
2721 } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
2722 batch_params.rtt = simple_strtol(value, NULL, 0);
2723 DHD_PNO(("rtt : %d\n", batch_params.rtt));
2724 } else {
2725 DHD_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param));
2726 err = BCME_ERROR;
2727 goto exit;
2728 }
2729 }
2730 err = dhd_dev_pno_set_for_batch(dev, &batch_params);
2731 if (err < 0) {
2732 DHD_ERROR(("failed to configure batch scan\n"));
2733 } else {
2734 memset(command, 0, total_len);
2735 err = snprintf(command, total_len, "%d", err);
2736 }
2737 } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
2738 err = dhd_dev_pno_get_for_batch(dev, command, total_len);
2739 if (err < 0) {
2740 DHD_ERROR(("failed to getting batching results\n"));
2741 } else {
2742 err = strlen(command);
2743 }
2744 } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
2745 err = dhd_dev_pno_stop_for_batch(dev);
2746 if (err < 0) {
2747 DHD_ERROR(("failed to stop batching scan\n"));
2748 } else {
2749 memset(command, 0, total_len);
2750 err = snprintf(command, total_len, "OK");
2751 }
2752 } else {
2753 DHD_ERROR(("%s : unknown command\n", __FUNCTION__));
2754 err = BCME_ERROR;
2755 goto exit;
2756 }
2757 exit:
2758 return err;
2759 }
2760 #ifndef WL_SCHED_SCAN
2761 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
2762 {
2763 wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
2764 int res = -1;
2765 int nssid = 0;
2766 cmd_tlv_t *cmd_tlv_temp;
2767 char *str_ptr;
2768 int tlv_size_left;
2769 int pno_time = 0;
2770 int pno_repeat = 0;
2771 int pno_freq_expo_max = 0;
2772
2773 #ifdef PNO_SET_DEBUG
2774 int i;
2775 char pno_in_example[] = {
2776 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
2777 'S', '1', '2', '0',
2778 'S',
2779 0x05,
2780 'd', 'l', 'i', 'n', 'k',
2781 'S',
2782 0x04,
2783 'G', 'O', 'O', 'G',
2784 'T',
2785 '0', 'B',
2786 'R',
2787 '2',
2788 'M',
2789 '2',
2790 0x00
2791 };
2792 #endif /* PNO_SET_DEBUG */
2793 DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
2794
2795 if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
2796 DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
2797 goto exit_proc;
2798 }
2799 #ifdef PNO_SET_DEBUG
2800 memcpy(command, pno_in_example, sizeof(pno_in_example));
2801 total_len = sizeof(pno_in_example);
2802 #endif // endif
2803 str_ptr = command + strlen(CMD_PNOSETUP_SET);
2804 tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
2805
2806 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
2807 memset(ssids_local, 0, sizeof(ssids_local));
2808
2809 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
2810 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
2811 (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
2812
2813 str_ptr += sizeof(cmd_tlv_t);
2814 tlv_size_left -= sizeof(cmd_tlv_t);
2815
2816 if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
2817 MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
2818 DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
2819 goto exit_proc;
2820 } else {
2821 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
2822 DHD_ERROR(("%s scan duration corrupted field size %d\n",
2823 __FUNCTION__, tlv_size_left));
2824 goto exit_proc;
2825 }
2826 str_ptr++;
2827 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
2828 DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
2829
2830 if (str_ptr[0] != 0) {
2831 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
2832 DHD_ERROR(("%s pno repeat : corrupted field\n",
2833 __FUNCTION__));
2834 goto exit_proc;
2835 }
2836 str_ptr++;
2837 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
2838 DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
2839 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
2840 DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
2841 __FUNCTION__));
2842 goto exit_proc;
2843 }
2844 str_ptr++;
2845 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
2846 DHD_PNO(("%s: pno_freq_expo_max=%d\n",
2847 __FUNCTION__, pno_freq_expo_max));
2848 }
2849 }
2850 } else {
2851 DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
2852 goto exit_proc;
2853 }
2854
2855 res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
2856 pno_freq_expo_max, NULL, 0);
2857 exit_proc:
2858 return res;
2859 }
2860 #endif /* !WL_SCHED_SCAN */
2861 #endif /* PNO_SUPPORT */
2862
2863 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
2864 {
2865 int ret;
2866 struct ether_addr p2pdev_addr;
2867
2868 #define MAC_ADDR_STR_LEN 18
2869 if (total_len < MAC_ADDR_STR_LEN) {
2870 DHD_ERROR(("%s: buflen %d is less than p2p dev addr\n",
2871 __FUNCTION__, total_len));
2872 return -1;
2873 }
2874
2875 ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr);
2876 if (ret) {
2877 DHD_ERROR(("%s Failed to get p2p dev addr\n", __FUNCTION__));
2878 return -1;
2879 }
2880 return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr)));
2881 }
2882
2883 #ifdef BCMCCX
2884 static int wl_android_get_cckm_rn(struct net_device *dev, char *command)
2885 {
2886 int error, rn;
2887
2888 WL_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name));
2889
2890 error = wldev_iovar_getint(dev, "cckm_rn", &rn);
2891 if (unlikely(error)) {
2892 WL_ERR(("wl_android_get_cckm_rn error (%d)\n", error));
2893 return -1;
2894 }
2895 memcpy(command, &rn, sizeof(int));
2896
2897 return sizeof(int);
2898 }
2899
2900 static int
2901 wl_android_set_cckm_krk(struct net_device *dev, char *command, int total_len)
2902 {
2903 int error, key_len, skip_len;
2904 unsigned char key[CCKM_KRK_LEN + CCKM_BTK_LEN];
2905 char iovar_buf[WLC_IOCTL_SMLEN];
2906
2907 WL_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name));
2908
2909 skip_len = strlen("set cckm_krk")+1;
2910
2911 if (total_len < (skip_len + CCKM_KRK_LEN)) {
2912 return BCME_BADLEN;
2913 }
2914
2915 if (total_len >= skip_len + CCKM_KRK_LEN + CCKM_BTK_LEN) {
2916 key_len = CCKM_KRK_LEN + CCKM_BTK_LEN;
2917 } else {
2918 key_len = CCKM_KRK_LEN;
2919 }
2920
2921 memset(iovar_buf, 0, sizeof(iovar_buf));
2922 memcpy(key, command+skip_len, key_len);
2923
2924 WL_DBG(("CCKM KRK-BTK (%d/%d) :\n", key_len, total_len));
2925 if (wl_dbg_level & WL_DBG_DBG) {
2926 prhex(NULL, key, key_len);
2927 }
2928
2929 error = wldev_iovar_setbuf(dev, "cckm_krk", key, key_len,
2930 iovar_buf, WLC_IOCTL_SMLEN, NULL);
2931 if (unlikely(error)) {
2932 WL_ERR((" cckm_krk set error (%d)\n", error));
2933 return -1;
2934 }
2935 return 0;
2936 }
2937
2938 static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command, int total_len)
2939 {
2940 int error;
2941 u8 buf[WL_ASSOC_INFO_MAX];
2942 wl_assoc_info_t assoc_info;
2943 u32 resp_ies_len = 0;
2944 int bytes_written = 0;
2945
2946 WL_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name));
2947
2948 error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf, WL_ASSOC_INFO_MAX, NULL);
2949 if (unlikely(error)) {
2950 WL_ERR(("could not get assoc info (%d)\n", error));
2951 return -1;
2952 }
2953
2954 memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t));
2955 assoc_info.req_len = htod32(assoc_info.req_len);
2956 assoc_info.resp_len = htod32(assoc_info.resp_len);
2957 assoc_info.flags = htod32(assoc_info.flags);
2958
2959 if (assoc_info.resp_len) {
2960 resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp);
2961 }
2962
2963 if (total_len < (sizeof(u32) + resp_ies_len)) {
2964 WL_ERR(("%s: Insufficient memory, %d bytes\n",
2965 __FUNCTION__, total_len));
2966 return -1;
2967 }
2968 /* first 4 bytes are ie len */
2969 memcpy(command, &resp_ies_len, sizeof(u32));
2970 bytes_written = sizeof(u32);
2971
2972 /* get the association resp IE's if there are any */
2973 if (resp_ies_len) {
2974 error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0,
2975 buf, WL_ASSOC_INFO_MAX, NULL);
2976 if (unlikely(error)) {
2977 WL_ERR(("could not get assoc resp_ies (%d)\n", error));
2978 return -1;
2979 }
2980
2981 memcpy(command+sizeof(u32), buf, resp_ies_len);
2982 bytes_written += resp_ies_len;
2983 }
2984 return bytes_written;
2985 }
2986
2987 #endif /* BCMCCX */
2988
2989 int
2990 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
2991 {
2992 int i, j, match;
2993 int ret = 0;
2994 char mac_buf[MAX_NUM_OF_ASSOCLIST *
2995 sizeof(struct ether_addr) + sizeof(uint)] = {0};
2996 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
2997
2998 /* set filtering mode */
2999 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) {
3000 DHD_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret));
3001 return ret;
3002 }
3003 if (macmode != MACLIST_MODE_DISABLED) {
3004 /* set the MAC filter list */
3005 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
3006 sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
3007 DHD_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret));
3008 return ret;
3009 }
3010 /* get the current list of associated STAs */
3011 assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
3012 if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
3013 sizeof(mac_buf))) != 0) {
3014 DHD_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret));
3015 return ret;
3016 }
3017 /* do we have any STA associated? */
3018 if (assoc_maclist->count) {
3019 /* iterate each associated STA */
3020 for (i = 0; i < assoc_maclist->count; i++) {
3021 match = 0;
3022 /* compare with each entry */
3023 for (j = 0; j < maclist->count; j++) {
3024 DHD_INFO(("%s : associated="MACDBG " list="MACDBG "\n",
3025 __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet),
3026 MAC2STRDBG(maclist->ea[j].octet)));
3027 if (memcmp(assoc_maclist->ea[i].octet,
3028 maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
3029 match = 1;
3030 break;
3031 }
3032 }
3033 /* do conditional deauth */
3034 /* "if not in the allow list" or "if in the deny list" */
3035 if ((macmode == MACLIST_MODE_ALLOW && !match) ||
3036 (macmode == MACLIST_MODE_DENY && match)) {
3037 scb_val_t scbval;
3038
3039 scbval.val = htod32(1);
3040 memcpy(&scbval.ea, &assoc_maclist->ea[i],
3041 ETHER_ADDR_LEN);
3042 if ((ret = wldev_ioctl_set(dev,
3043 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
3044 &scbval, sizeof(scb_val_t))) != 0)
3045 DHD_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n",
3046 __FUNCTION__, ret));
3047 }
3048 }
3049 }
3050 }
3051 return ret;
3052 }
3053
3054 /*
3055 * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
3056 *
3057 */
3058 static int
3059 wl_android_set_mac_address_filter(struct net_device *dev, char* str)
3060 {
3061 int i;
3062 int ret = 0;
3063 int macnum = 0;
3064 int macmode = MACLIST_MODE_DISABLED;
3065 struct maclist *list;
3066 char eabuf[ETHER_ADDR_STR_LEN];
3067 const char *token;
3068 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3069
3070 /* string should look like below (macmode/macnum/maclist) */
3071 /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */
3072
3073 /* get the MAC filter mode */
3074 token = strsep((char**)&str, " ");
3075 if (!token) {
3076 return -1;
3077 }
3078 macmode = bcm_atoi(token);
3079
3080 if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
3081 DHD_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode));
3082 return -1;
3083 }
3084
3085 token = strsep((char**)&str, " ");
3086 if (!token) {
3087 return -1;
3088 }
3089 macnum = bcm_atoi(token);
3090 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
3091 DHD_ERROR(("%s : invalid number of MAC address entries %d\n",
3092 __FUNCTION__, macnum));
3093 return -1;
3094 }
3095 /* allocate memory for the MAC list */
3096 list = (struct maclist*) MALLOCZ(cfg->osh, sizeof(int) +
3097 sizeof(struct ether_addr) * macnum);
3098 if (!list) {
3099 DHD_ERROR(("%s : failed to allocate memory\n", __FUNCTION__));
3100 return -1;
3101 }
3102 /* prepare the MAC list */
3103 list->count = htod32(macnum);
3104 bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
3105 for (i = 0; i < list->count; i++) {
3106 token = strsep((char**)&str, " ");
3107 if (token == NULL) {
3108 DHD_ERROR(("%s : No mac address present\n", __FUNCTION__));
3109 ret = -EINVAL;
3110 goto exit;
3111 }
3112 strncpy(eabuf, token, ETHER_ADDR_STR_LEN - 1);
3113 if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
3114 DHD_ERROR(("%s : mac parsing err index=%d, addr=%s\n",
3115 __FUNCTION__, i, eabuf));
3116 list->count = i;
3117 break;
3118 }
3119 DHD_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf));
3120 }
3121 if (i == 0)
3122 goto exit;
3123
3124 /* set the list */
3125 if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
3126 DHD_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
3127
3128 exit:
3129 MFREE(cfg->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
3130
3131 return ret;
3132 }
3133
3134 /**
3135 * Global function definitions (declared in wl_android.h)
3136 */
3137
3138 int wl_android_wifi_on(struct net_device *dev)
3139 {
3140 int ret = 0;
3141 int retry = POWERUP_MAX_RETRY;
3142
3143 DHD_ERROR(("%s in\n", __FUNCTION__));
3144 if (!dev) {
3145 DHD_ERROR(("%s: dev is null\n", __FUNCTION__));
3146 return -EINVAL;
3147 }
3148
3149 dhd_net_if_lock(dev);
3150 if (!g_wifi_on) {
3151 do {
3152 dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
3153 #ifdef BCMSDIO
3154 ret = dhd_net_bus_resume(dev, 0);
3155 #endif /* BCMSDIO */
3156 #ifdef BCMPCIE
3157 ret = dhd_net_bus_devreset(dev, FALSE);
3158 #endif /* BCMPCIE */
3159 if (ret == 0) {
3160 break;
3161 }
3162 DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
3163 retry));
3164 #ifdef BCMPCIE
3165 dhd_net_bus_devreset(dev, TRUE);
3166 #endif /* BCMPCIE */
3167 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
3168 } while (retry-- > 0);
3169 if (ret != 0) {
3170 DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
3171 #ifdef BCM_DETECT_TURN_ON_FAILURE
3172 BUG_ON(1);
3173 #endif /* BCM_DETECT_TURN_ON_FAILURE */
3174 goto exit;
3175 }
3176 #ifdef BCMSDIO
3177 ret = dhd_net_bus_devreset(dev, FALSE);
3178 dhd_net_bus_resume(dev, 1);
3179 #endif /* BCMSDIO */
3180
3181 #ifndef BCMPCIE
3182 if (!ret) {
3183 if (dhd_dev_init_ioctl(dev) < 0) {
3184 ret = -EFAULT;
3185 }
3186 }
3187 #endif /* !BCMPCIE */
3188 g_wifi_on = TRUE;
3189 }
3190
3191 exit:
3192 dhd_net_if_unlock(dev);
3193
3194 return ret;
3195 }
3196
3197 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
3198 {
3199 int ret = 0;
3200
3201 DHD_ERROR(("%s in\n", __FUNCTION__));
3202 if (!dev) {
3203 DHD_TRACE(("%s: dev is null\n", __FUNCTION__));
3204 return -EINVAL;
3205 }
3206
3207 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
3208 ret = dhd_debug_uart_is_running(dev);
3209 if (ret) {
3210 DHD_ERROR(("%s - Debug UART App is running\n", __FUNCTION__));
3211 return -EBUSY;
3212 }
3213 #endif /* BCMPCIE && DHD_DEBUG_UART */
3214 dhd_net_if_lock(dev);
3215 if (g_wifi_on || on_failure) {
3216 #if defined(BCMSDIO) || defined(BCMPCIE)
3217 ret = dhd_net_bus_devreset(dev, TRUE);
3218 #ifdef BCMSDIO
3219 dhd_net_bus_suspend(dev);
3220 #endif /* BCMSDIO */
3221 #endif /* BCMSDIO || BCMPCIE */
3222 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
3223 g_wifi_on = FALSE;
3224 }
3225 dhd_net_if_unlock(dev);
3226
3227 return ret;
3228 }
3229
3230 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
3231 {
3232 if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
3233 return -1;
3234 return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
3235 }
3236
3237 #ifdef CONNECTION_STATISTICS
3238 static int
3239 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
3240 {
3241 int err;
3242 wl_chanim_stats_t *list;
3243 /* Parameter _and_ returned buffer of chanim_stats. */
3244 wl_chanim_stats_t param;
3245 u8 result[WLC_IOCTL_SMLEN];
3246 chanim_stats_t *stats;
3247
3248 memset(&param, 0, sizeof(param));
3249
3250 param.buflen = htod32(sizeof(wl_chanim_stats_t));
3251 param.count = htod32(WL_CHANIM_COUNT_ONE);
3252
3253 if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
3254 (char*)result, sizeof(result), 0)) < 0) {
3255 WL_ERR(("Failed to get chanim results %d \n", err));
3256 return err;
3257 }
3258
3259 list = (wl_chanim_stats_t*)result;
3260
3261 list->buflen = dtoh32(list->buflen);
3262 list->version = dtoh32(list->version);
3263 list->count = dtoh32(list->count);
3264
3265 if (list->buflen == 0) {
3266 list->version = 0;
3267 list->count = 0;
3268 } else if (list->version != WL_CHANIM_STATS_VERSION) {
3269 WL_ERR(("Sorry, firmware has wl_chanim_stats version %d "
3270 "but driver supports only version %d.\n",
3271 list->version, WL_CHANIM_STATS_VERSION));
3272 list->buflen = 0;
3273 list->count = 0;
3274 }
3275
3276 stats = list->stats;
3277 stats->glitchcnt = dtoh32(stats->glitchcnt);
3278 stats->badplcp = dtoh32(stats->badplcp);
3279 stats->chanspec = dtoh16(stats->chanspec);
3280 stats->timestamp = dtoh32(stats->timestamp);
3281 stats->chan_idle = dtoh32(stats->chan_idle);
3282
3283 WL_INFORM(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
3284 stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
3285 stats->timestamp));
3286
3287 *chan_idle = stats->chan_idle;
3288
3289 return (err);
3290 }
3291
3292 static int
3293 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
3294 {
3295 static char iovar_buf[WLC_IOCTL_MAXLEN];
3296 const wl_cnt_wlc_t* wlc_cnt = NULL;
3297 #ifndef DISABLE_IF_COUNTERS
3298 wl_if_stats_t* if_stats = NULL;
3299 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3300 #endif /* DISABLE_IF_COUNTERS */
3301
3302 int link_speed = 0;
3303 struct connection_stats *output;
3304 unsigned int bufsize = 0;
3305 int bytes_written = -1;
3306 int ret = 0;
3307
3308 WL_INFORM(("%s: enter Get Connection Stats\n", __FUNCTION__));
3309
3310 if (total_len <= 0) {
3311 WL_ERR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len));
3312 goto error;
3313 }
3314
3315 bufsize = total_len;
3316 if (bufsize < sizeof(struct connection_stats)) {
3317 WL_ERR(("%s: not enough buffer size, provided=%u, requires=%zu\n",
3318 __FUNCTION__, bufsize,
3319 sizeof(struct connection_stats)));
3320 goto error;
3321 }
3322
3323 output = (struct connection_stats *)command;
3324
3325 #ifndef DISABLE_IF_COUNTERS
3326 if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
3327 if (if_stats == NULL) {
3328 WL_ERR(("%s(%d): MALLOCZ failed\n", __FUNCTION__, __LINE__));
3329 goto error;
3330 }
3331 memset(if_stats, 0, sizeof(*if_stats));
3332
3333 if (FW_SUPPORTED(dhdp, ifst)) {
3334 ret = wl_cfg80211_ifstats_counters(dev, if_stats);
3335 } else {
3336 ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
3337 (char *)if_stats, sizeof(*if_stats), NULL);
3338 }
3339
3340 if (ret) {
3341 WL_ERR(("%s: if_counters not supported ret=%d\n",
3342 __FUNCTION__, ret));
3343
3344 /* In case if_stats IOVAR is not supported, get information from counters. */
3345 #endif /* DISABLE_IF_COUNTERS */
3346 ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
3347 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
3348 if (unlikely(ret)) {
3349 WL_ERR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
3350 goto error;
3351 }
3352 ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
3353 if (ret != BCME_OK) {
3354 WL_ERR(("%s wl_cntbuf_to_xtlv_format ERR %d\n",
3355 __FUNCTION__, ret));
3356 goto error;
3357 }
3358
3359 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
3360 WL_ERR(("%s wlc_cnt NULL!\n", __FUNCTION__));
3361 goto error;
3362 }
3363
3364 output->txframe = dtoh32(wlc_cnt->txframe);
3365 output->txbyte = dtoh32(wlc_cnt->txbyte);
3366 output->txerror = dtoh32(wlc_cnt->txerror);
3367 output->rxframe = dtoh32(wlc_cnt->rxframe);
3368 output->rxbyte = dtoh32(wlc_cnt->rxbyte);
3369 output->txfail = dtoh32(wlc_cnt->txfail);
3370 output->txretry = dtoh32(wlc_cnt->txretry);
3371 output->txretrie = dtoh32(wlc_cnt->txretrie);
3372 output->txrts = dtoh32(wlc_cnt->txrts);
3373 output->txnocts = dtoh32(wlc_cnt->txnocts);
3374 output->txexptime = dtoh32(wlc_cnt->txexptime);
3375 #ifndef DISABLE_IF_COUNTERS
3376 } else {
3377 /* Populate from if_stats. */
3378 if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
3379 WL_ERR(("%s: incorrect version of wl_if_stats_t, expected=%u got=%u\n",
3380 __FUNCTION__, WL_IF_STATS_T_VERSION, if_stats->version));
3381 goto error;
3382 }
3383
3384 output->txframe = (uint32)dtoh64(if_stats->txframe);
3385 output->txbyte = (uint32)dtoh64(if_stats->txbyte);
3386 output->txerror = (uint32)dtoh64(if_stats->txerror);
3387 output->rxframe = (uint32)dtoh64(if_stats->rxframe);
3388 output->rxbyte = (uint32)dtoh64(if_stats->rxbyte);
3389 output->txfail = (uint32)dtoh64(if_stats->txfail);
3390 output->txretry = (uint32)dtoh64(if_stats->txretry);
3391 output->txretrie = (uint32)dtoh64(if_stats->txretrie);
3392 if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
3393 output->txexptime = (uint32)dtoh64(if_stats->txexptime);
3394 output->txrts = (uint32)dtoh64(if_stats->txrts);
3395 output->txnocts = (uint32)dtoh64(if_stats->txnocts);
3396 } else {
3397 output->txexptime = 0;
3398 output->txrts = 0;
3399 output->txnocts = 0;
3400 }
3401 }
3402 #endif /* DISABLE_IF_COUNTERS */
3403
3404 /* link_speed is in kbps */
3405 ret = wldev_get_link_speed(dev, &link_speed);
3406 if (ret || link_speed < 0) {
3407 WL_ERR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n",
3408 __FUNCTION__, ret, link_speed));
3409 goto error;
3410 }
3411
3412 output->txrate = link_speed;
3413
3414 /* Channel idle ratio. */
3415 if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
3416 output->chan_idle = 0;
3417 };
3418
3419 bytes_written = sizeof(struct connection_stats);
3420
3421 error:
3422 #ifndef DISABLE_IF_COUNTERS
3423 if (if_stats) {
3424 MFREE(cfg->osh, if_stats, sizeof(*if_stats));
3425 }
3426 #endif /* DISABLE_IF_COUNTERS */
3427
3428 return bytes_written;
3429 }
3430 #endif /* CONNECTION_STATISTICS */
3431
3432 #ifdef WL_NATOE
3433 static int
3434 wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
3435 {
3436 int ret = BCME_ERROR;
3437 char *pcmd = command;
3438 char *str = NULL;
3439 wl_natoe_cmd_info_t cmd_info;
3440 const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
3441
3442 /* skip to cmd name after "natoe" */
3443 str = bcmstrtok(&pcmd, " ", NULL);
3444
3445 /* If natoe subcmd name is not provided, return error */
3446 if (*pcmd == '\0') {
3447 WL_ERR(("natoe subcmd not provided %s\n", __FUNCTION__));
3448 ret = -EINVAL;
3449 return ret;
3450 }
3451
3452 /* get the natoe command name to str */
3453 str = bcmstrtok(&pcmd, " ", NULL);
3454
3455 while (natoe_cmd->name != NULL) {
3456 if (strcmp(natoe_cmd->name, str) == 0) {
3457 /* dispacth cmd to appropriate handler */
3458 if (natoe_cmd->handler) {
3459 cmd_info.command = command;
3460 cmd_info.tot_len = total_len;
3461 ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
3462 }
3463 return ret;
3464 }
3465 natoe_cmd++;
3466 }
3467 return ret;
3468 }
3469
3470 static int
3471 wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
3472 {
3473 int res = BCME_OK;
3474 wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
3475 uint8 *command = cmd_info->command;
3476 uint16 total_len = cmd_info->tot_len;
3477 uint16 bytes_written = 0;
3478
3479 UNUSED_PARAMETER(len);
3480
3481 switch (type) {
3482
3483 case WL_NATOE_XTLV_ENABLE:
3484 {
3485 bytes_written = snprintf(command, total_len, "natoe: %s\n",
3486 *data?"enabled":"disabled");
3487 cmd_info->bytes_written = bytes_written;
3488 break;
3489 }
3490
3491 case WL_NATOE_XTLV_CONFIG_IPS:
3492 {
3493 wl_natoe_config_ips_t *config_ips;
3494 uint8 buf[16];
3495
3496 config_ips = (wl_natoe_config_ips_t *)data;
3497 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
3498 bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
3499 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
3500 bytes_written += snprintf(command + bytes_written, total_len,
3501 "sta netmask: %s\n", buf);
3502 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
3503 bytes_written += snprintf(command + bytes_written, total_len,
3504 "sta router ip: %s\n", buf);
3505 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
3506 bytes_written += snprintf(command + bytes_written, total_len,
3507 "sta dns ip: %s\n", buf);
3508 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
3509 bytes_written += snprintf(command + bytes_written, total_len,
3510 "ap ip: %s\n", buf);
3511 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
3512 bytes_written += snprintf(command + bytes_written, total_len,
3513 "ap netmask: %s\n", buf);
3514 cmd_info->bytes_written = bytes_written;
3515 break;
3516 }
3517
3518 case WL_NATOE_XTLV_CONFIG_PORTS:
3519 {
3520 wl_natoe_ports_config_t *ports_config;
3521
3522 ports_config = (wl_natoe_ports_config_t *)data;
3523 bytes_written = snprintf(command, total_len, "starting port num: %d\n",
3524 dtoh16(ports_config->start_port_num));
3525 bytes_written += snprintf(command + bytes_written, total_len,
3526 "number of ports: %d\n", dtoh16(ports_config->no_of_ports));
3527 cmd_info->bytes_written = bytes_written;
3528 break;
3529 }
3530
3531 case WL_NATOE_XTLV_DBG_STATS:
3532 {
3533 char *stats_dump = (char *)data;
3534
3535 bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
3536 cmd_info->bytes_written = bytes_written;
3537 break;
3538 }
3539
3540 case WL_NATOE_XTLV_TBL_CNT:
3541 {
3542 bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
3543 dtoh32(*(uint32 *)data));
3544 cmd_info->bytes_written = bytes_written;
3545 break;
3546 }
3547
3548 default:
3549 /* ignore */
3550 break;
3551 }
3552
3553 return res;
3554 }
3555
3556 /*
3557 * --- common for all natoe get commands ----
3558 */
3559 static int
3560 wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
3561 uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
3562 {
3563 /* for gets we only need to pass ioc header */
3564 wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
3565 int res;
3566
3567 /* send getbuf natoe iovar */
3568 res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
3569 buflen, NULL);
3570
3571 /* check the response buff */
3572 if ((res == BCME_OK)) {
3573 /* scans ioctl tlvbuf f& invokes the cbfn for processing */
3574 res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
3575 BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
3576
3577 if (res == BCME_OK) {
3578 res = cmd_info->bytes_written;
3579 }
3580 }
3581 else
3582 {
3583 DHD_ERROR(("%s: get command failed code %d\n", __FUNCTION__, res));
3584 res = BCME_ERROR;
3585 }
3586
3587 return res;
3588 }
3589
3590 static int
3591 wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
3592 char *command, wl_natoe_cmd_info_t *cmd_info)
3593 {
3594 int ret = BCME_OK;
3595 wl_natoe_ioc_t *natoe_ioc;
3596 char *pcmd = command;
3597 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
3598 uint16 buflen = WL_NATOE_IOC_BUFSZ;
3599 bcm_xtlv_t *pxtlv = NULL;
3600 char *ioctl_buf = NULL;
3601 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3602
3603 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
3604 if (!ioctl_buf) {
3605 WL_ERR(("ioctl memory alloc failed\n"));
3606 return -ENOMEM;
3607 }
3608
3609 /* alloc mem for ioctl headr + tlv data */
3610 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3611 if (!natoe_ioc) {
3612 WL_ERR(("ioctl header memory alloc failed\n"));
3613 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3614 return -ENOMEM;
3615 }
3616
3617 /* make up natoe cmd ioctl header */
3618 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3619 natoe_ioc->id = htod16(cmd->id);
3620 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
3621 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3622
3623 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3624 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3625 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
3626 WLC_IOCTL_MEDLEN, cmd_info);
3627 if (ret != BCME_OK) {
3628 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
3629 ret = -EINVAL;
3630 }
3631 } else { /* set */
3632 uint8 val = bcm_atoi(pcmd);
3633
3634 /* buflen is max tlv data we can write, it will be decremented as we pack */
3635 /* save buflen at start */
3636 uint16 buflen_at_start = buflen;
3637
3638 /* we'll adjust final ioc size at the end */
3639 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
3640 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
3641
3642 if (ret != BCME_OK) {
3643 ret = -EINVAL;
3644 goto exit;
3645 }
3646
3647 /* adjust iocsz to the end of last data record */
3648 natoe_ioc->len = (buflen_at_start - buflen);
3649 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
3650
3651 ret = wldev_iovar_setbuf(dev, "natoe",
3652 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3653 if (ret != BCME_OK) {
3654 WL_ERR(("Fail to set iovar %d\n", ret));
3655 ret = -EINVAL;
3656 }
3657 }
3658
3659 exit:
3660 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3661 MFREE(cfg->osh, natoe_ioc, iocsz);
3662
3663 return ret;
3664 }
3665
3666 static int
3667 wl_android_natoe_subcmd_config_ips(struct net_device *dev,
3668 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
3669 {
3670 int ret = BCME_OK;
3671 wl_natoe_config_ips_t config_ips;
3672 wl_natoe_ioc_t *natoe_ioc;
3673 char *pcmd = command;
3674 char *str;
3675 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
3676 uint16 buflen = WL_NATOE_IOC_BUFSZ;
3677 bcm_xtlv_t *pxtlv = NULL;
3678 char *ioctl_buf = NULL;
3679 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3680
3681 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
3682 if (!ioctl_buf) {
3683 WL_ERR(("ioctl memory alloc failed\n"));
3684 return -ENOMEM;
3685 }
3686
3687 /* alloc mem for ioctl headr + tlv data */
3688 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3689 if (!natoe_ioc) {
3690 WL_ERR(("ioctl header memory alloc failed\n"));
3691 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3692 return -ENOMEM;
3693 }
3694
3695 /* make up natoe cmd ioctl header */
3696 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3697 natoe_ioc->id = htod16(cmd->id);
3698 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
3699 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3700
3701 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3702 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3703 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
3704 WLC_IOCTL_MEDLEN, cmd_info);
3705 if (ret != BCME_OK) {
3706 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
3707 ret = -EINVAL;
3708 }
3709 } else { /* set */
3710 /* buflen is max tlv data we can write, it will be decremented as we pack */
3711 /* save buflen at start */
3712 uint16 buflen_at_start = buflen;
3713
3714 memset(&config_ips, 0, sizeof(config_ips));
3715
3716 str = bcmstrtok(&pcmd, " ", NULL);
3717 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
3718 WL_ERR(("Invalid STA IP addr %s\n", str));
3719 ret = -EINVAL;
3720 goto exit;
3721 }
3722
3723 str = bcmstrtok(&pcmd, " ", NULL);
3724 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
3725 WL_ERR(("Invalid STA netmask %s\n", str));
3726 ret = -EINVAL;
3727 goto exit;
3728 }
3729
3730 str = bcmstrtok(&pcmd, " ", NULL);
3731 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
3732 WL_ERR(("Invalid STA router IP addr %s\n", str));
3733 ret = -EINVAL;
3734 goto exit;
3735 }
3736
3737 str = bcmstrtok(&pcmd, " ", NULL);
3738 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
3739 WL_ERR(("Invalid STA DNS IP addr %s\n", str));
3740 ret = -EINVAL;
3741 goto exit;
3742 }
3743
3744 str = bcmstrtok(&pcmd, " ", NULL);
3745 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
3746 WL_ERR(("Invalid AP IP addr %s\n", str));
3747 ret = -EINVAL;
3748 goto exit;
3749 }
3750
3751 str = bcmstrtok(&pcmd, " ", NULL);
3752 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
3753 WL_ERR(("Invalid AP netmask %s\n", str));
3754 ret = -EINVAL;
3755 goto exit;
3756 }
3757
3758 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
3759 &buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
3760 &config_ips, BCM_XTLV_OPTION_ALIGN32);
3761
3762 if (ret != BCME_OK) {
3763 ret = -EINVAL;
3764 goto exit;
3765 }
3766
3767 /* adjust iocsz to the end of last data record */
3768 natoe_ioc->len = (buflen_at_start - buflen);
3769 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
3770
3771 ret = wldev_iovar_setbuf(dev, "natoe",
3772 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3773 if (ret != BCME_OK) {
3774 WL_ERR(("Fail to set iovar %d\n", ret));
3775 ret = -EINVAL;
3776 }
3777 }
3778
3779 exit:
3780 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3781 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
3782
3783 return ret;
3784 }
3785
3786 static int
3787 wl_android_natoe_subcmd_config_ports(struct net_device *dev,
3788 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
3789 {
3790 int ret = BCME_OK;
3791 wl_natoe_ports_config_t ports_config;
3792 wl_natoe_ioc_t *natoe_ioc;
3793 char *pcmd = command;
3794 char *str;
3795 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
3796 uint16 buflen = WL_NATOE_IOC_BUFSZ;
3797 bcm_xtlv_t *pxtlv = NULL;
3798 char *ioctl_buf = NULL;
3799 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3800
3801 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
3802 if (!ioctl_buf) {
3803 WL_ERR(("ioctl memory alloc failed\n"));
3804 return -ENOMEM;
3805 }
3806
3807 /* alloc mem for ioctl headr + tlv data */
3808 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3809 if (!natoe_ioc) {
3810 WL_ERR(("ioctl header memory alloc failed\n"));
3811 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3812 return -ENOMEM;
3813 }
3814
3815 /* make up natoe cmd ioctl header */
3816 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3817 natoe_ioc->id = htod16(cmd->id);
3818 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
3819 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3820
3821 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3822 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3823 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
3824 WLC_IOCTL_MEDLEN, cmd_info);
3825 if (ret != BCME_OK) {
3826 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
3827 ret = -EINVAL;
3828 }
3829 } else { /* set */
3830 /* buflen is max tlv data we can write, it will be decremented as we pack */
3831 /* save buflen at start */
3832 uint16 buflen_at_start = buflen;
3833
3834 memset(&ports_config, 0, sizeof(ports_config));
3835
3836 str = bcmstrtok(&pcmd, " ", NULL);
3837 if (!str) {
3838 WL_ERR(("Invalid port string %s\n", str));
3839 ret = -EINVAL;
3840 goto exit;
3841 }
3842 ports_config.start_port_num = htod16(bcm_atoi(str));
3843
3844 str = bcmstrtok(&pcmd, " ", NULL);
3845 if (!str) {
3846 WL_ERR(("Invalid port string %s\n", str));
3847 ret = -EINVAL;
3848 goto exit;
3849 }
3850 ports_config.no_of_ports = htod16(bcm_atoi(str));
3851
3852 if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
3853 NATOE_MAX_PORT_NUM) {
3854 WL_ERR(("Invalid port configuration\n"));
3855 ret = -EINVAL;
3856 goto exit;
3857 }
3858 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
3859 &buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
3860 &ports_config, BCM_XTLV_OPTION_ALIGN32);
3861
3862 if (ret != BCME_OK) {
3863 ret = -EINVAL;
3864 goto exit;
3865 }
3866
3867 /* adjust iocsz to the end of last data record */
3868 natoe_ioc->len = (buflen_at_start - buflen);
3869 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
3870
3871 ret = wldev_iovar_setbuf(dev, "natoe",
3872 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3873 if (ret != BCME_OK) {
3874 WL_ERR(("Fail to set iovar %d\n", ret));
3875 ret = -EINVAL;
3876 }
3877 }
3878
3879 exit:
3880 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3881 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
3882
3883 return ret;
3884 }
3885
3886 static int
3887 wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
3888 char *command, wl_natoe_cmd_info_t *cmd_info)
3889 {
3890 int ret = BCME_OK;
3891 wl_natoe_ioc_t *natoe_ioc;
3892 char *pcmd = command;
3893 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
3894 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
3895 uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
3896 bcm_xtlv_t *pxtlv = NULL;
3897 char *ioctl_buf = NULL;
3898 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3899
3900 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
3901 if (!ioctl_buf) {
3902 WL_ERR(("ioctl memory alloc failed\n"));
3903 return -ENOMEM;
3904 }
3905
3906 /* alloc mem for ioctl headr + tlv data */
3907 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3908 if (!natoe_ioc) {
3909 WL_ERR(("ioctl header memory alloc failed\n"));
3910 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
3911 return -ENOMEM;
3912 }
3913
3914 /* make up natoe cmd ioctl header */
3915 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3916 natoe_ioc->id = htod16(cmd->id);
3917 natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
3918 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3919
3920 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3921 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3922 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
3923 WLC_IOCTL_MAXLEN, cmd_info);
3924 if (ret != BCME_OK) {
3925 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
3926 ret = -EINVAL;
3927 }
3928 } else { /* set */
3929 uint8 val = bcm_atoi(pcmd);
3930
3931 /* buflen is max tlv data we can write, it will be decremented as we pack */
3932 /* save buflen at start */
3933 uint16 buflen_at_start = buflen;
3934
3935 /* we'll adjust final ioc size at the end */
3936 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
3937 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
3938
3939 if (ret != BCME_OK) {
3940 ret = -EINVAL;
3941 goto exit;
3942 }
3943
3944 /* adjust iocsz to the end of last data record */
3945 natoe_ioc->len = (buflen_at_start - buflen);
3946 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
3947
3948 ret = wldev_iovar_setbuf(dev, "natoe",
3949 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
3950 if (ret != BCME_OK) {
3951 WL_ERR(("Fail to set iovar %d\n", ret));
3952 ret = -EINVAL;
3953 }
3954 }
3955
3956 exit:
3957 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
3958 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
3959
3960 return ret;
3961 }
3962
3963 static int
3964 wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
3965 char *command, wl_natoe_cmd_info_t *cmd_info)
3966 {
3967 int ret = BCME_OK;
3968 wl_natoe_ioc_t *natoe_ioc;
3969 char *pcmd = command;
3970 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
3971 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
3972 uint16 buflen = WL_NATOE_IOC_BUFSZ;
3973 bcm_xtlv_t *pxtlv = NULL;
3974 char *ioctl_buf = NULL;
3975 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3976
3977 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
3978 if (!ioctl_buf) {
3979 WL_ERR(("ioctl memory alloc failed\n"));
3980 return -ENOMEM;
3981 }
3982
3983 /* alloc mem for ioctl headr + tlv data */
3984 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3985 if (!natoe_ioc) {
3986 WL_ERR(("ioctl header memory alloc failed\n"));
3987 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3988 return -ENOMEM;
3989 }
3990
3991 /* make up natoe cmd ioctl header */
3992 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3993 natoe_ioc->id = htod16(cmd->id);
3994 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
3995 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3996
3997 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3998 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3999 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
4000 WLC_IOCTL_MEDLEN, cmd_info);
4001 if (ret != BCME_OK) {
4002 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
4003 ret = -EINVAL;
4004 }
4005 } else { /* set */
4006 uint32 val = bcm_atoi(pcmd);
4007
4008 /* buflen is max tlv data we can write, it will be decremented as we pack */
4009 /* save buflen at start */
4010 uint16 buflen_at_start = buflen;
4011
4012 /* we'll adjust final ioc size at the end */
4013 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
4014 sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
4015
4016 if (ret != BCME_OK) {
4017 ret = -EINVAL;
4018 goto exit;
4019 }
4020
4021 /* adjust iocsz to the end of last data record */
4022 natoe_ioc->len = (buflen_at_start - buflen);
4023 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
4024
4025 ret = wldev_iovar_setbuf(dev, "natoe",
4026 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
4027 if (ret != BCME_OK) {
4028 WL_ERR(("Fail to set iovar %d\n", ret));
4029 ret = -EINVAL;
4030 }
4031 }
4032
4033 exit:
4034 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4035 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
4036
4037 return ret;
4038 }
4039
4040 #endif /* WL_NATOE */
4041
4042 #ifdef CUSTOMER_HW4_PRIVATE_CMD
4043 #ifdef SUPPORT_AMPDU_MPDU_CMD
4044 /* CMD_AMPDU_MPDU */
4045 static int
4046 wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
4047 {
4048 int err = 0;
4049 int ampdu_mpdu;
4050
4051 ampdu_mpdu = bcm_atoi(string_num);
4052
4053 if (ampdu_mpdu > 32) {
4054 DHD_ERROR(("%s : ampdu_mpdu MAX value is 32.\n", __FUNCTION__));
4055 return -1;
4056 }
4057
4058 DHD_ERROR(("%s : ampdu_mpdu = %d\n", __FUNCTION__, ampdu_mpdu));
4059 err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
4060 if (err < 0) {
4061 DHD_ERROR(("%s : ampdu_mpdu set error. %d\n", __FUNCTION__, err));
4062 return -1;
4063 }
4064
4065 return 0;
4066 }
4067 #endif /* SUPPORT_AMPDU_MPDU_CMD */
4068 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
4069
4070 #if defined(WL_SUPPORT_AUTO_CHANNEL)
4071 /* SoftAP feature */
4072 #define APCS_BAND_2G_LEGACY1 20
4073 #define APCS_BAND_2G_LEGACY2 0
4074 #define APCS_BAND_AUTO "band=auto"
4075 #define APCS_BAND_2G "band=2g"
4076 #define APCS_BAND_5G "band=5g"
4077 #define APCS_MAX_2G_CHANNELS 11
4078 #define APCS_MAX_RETRY 10
4079 #define APCS_DEFAULT_2G_CH 1
4080 #define APCS_DEFAULT_5G_CH 149
4081 static int
4082 wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
4083 char* command, int total_len)
4084 {
4085 int channel = 0;
4086 int chosen = 0;
4087 int retry = 0;
4088 int ret = 0;
4089 int spect = 0;
4090 u8 *reqbuf = NULL;
4091 uint32 band = WLC_BAND_2G;
4092 uint32 buf_size;
4093 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4094
4095 if (cmd_str) {
4096 WL_INFORM(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
4097 if (strncmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
4098 band = WLC_BAND_AUTO;
4099 } else if (strncmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
4100 band = WLC_BAND_5G;
4101 } else if (strncmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
4102 band = WLC_BAND_2G;
4103 } else {
4104 /*
4105 * For backward compatibility: Some platforms used to issue argument 20 or 0
4106 * to enforce the 2G channel selection
4107 */
4108 channel = bcm_atoi(cmd_str);
4109 if ((channel == APCS_BAND_2G_LEGACY1) ||
4110 (channel == APCS_BAND_2G_LEGACY2)) {
4111 band = WLC_BAND_2G;
4112 } else {
4113 WL_ERR(("Invalid argument\n"));
4114 return -EINVAL;
4115 }
4116 }
4117 } else {
4118 /* If no argument is provided, default to 2G */
4119 WL_ERR(("No argument given default to 2.4G scan\n"));
4120 band = WLC_BAND_2G;
4121 }
4122 WL_INFORM(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
4123
4124 /* If STA is connected, return is STA channel, else ACS can be issued,
4125 * set spect to 0 and proceed with ACS
4126 */
4127 channel = wl_cfg80211_get_sta_channel(cfg);
4128 if (channel) {
4129 channel = (channel <= CH_MAX_2G_CHANNEL) ?
4130 channel : APCS_DEFAULT_2G_CH;
4131 goto done2;
4132 }
4133
4134 ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
4135 if (ret) {
4136 WL_ERR(("ACS: error getting the spect, ret=%d\n", ret));
4137 goto done;
4138 }
4139
4140 if (spect > 0) {
4141 ret = wl_cfg80211_set_spect(dev, 0);
4142 if (ret < 0) {
4143 WL_ERR(("ACS: error while setting spect, ret=%d\n", ret));
4144 goto done;
4145 }
4146 }
4147
4148 reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
4149 if (reqbuf == NULL) {
4150 WL_ERR(("failed to allocate chanspec buffer\n"));
4151 return -ENOMEM;
4152 }
4153
4154 if (band == WLC_BAND_AUTO) {
4155 WL_DBG(("ACS full channel scan \n"));
4156 reqbuf[0] = htod32(0);
4157 } else if (band == WLC_BAND_5G) {
4158 WL_DBG(("ACS 5G band scan \n"));
4159 if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
4160 WL_ERR(("ACS 5g chanspec retreival failed! \n"));
4161 goto done;
4162 }
4163 } else if (band == WLC_BAND_2G) {
4164 /*
4165 * If channel argument is not provided/ argument 20 is provided,
4166 * Restrict channel to 2GHz, 20MHz BW, No SB
4167 */
4168 WL_DBG(("ACS 2G band scan \n"));
4169 if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
4170 WL_ERR(("ACS 2g chanspec retreival failed! \n"));
4171 goto done;
4172 }
4173 } else {
4174 WL_ERR(("ACS: No band chosen\n"));
4175 goto done2;
4176 }
4177
4178 buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
4179 ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
4180 buf_size);
4181 if (ret < 0) {
4182 WL_ERR(("can't start auto channel scan, err = %d\n", ret));
4183 channel = 0;
4184 goto done;
4185 }
4186
4187 /* Wait for auto channel selection, max 3000 ms */
4188 if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) {
4189 OSL_SLEEP(500);
4190 } else {
4191 /*
4192 * Full channel scan at the minimum takes 1.2secs
4193 * even with parallel scan. max wait time: 3500ms
4194 */
4195 OSL_SLEEP(1000);
4196 }
4197
4198 retry = APCS_MAX_RETRY;
4199 while (retry--) {
4200 ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
4201 sizeof(chosen));
4202 if (ret < 0) {
4203 chosen = 0;
4204 } else {
4205 chosen = dtoh32(chosen);
4206 }
4207
4208 if (chosen) {
4209 int chosen_band;
4210 int apcs_band;
4211 #ifdef D11AC_IOTYPES
4212 if (wl_cfg80211_get_ioctl_version() == 1) {
4213 channel = LCHSPEC_CHANNEL((chanspec_t)chosen);
4214 } else {
4215 channel = CHSPEC_CHANNEL((chanspec_t)chosen);
4216 }
4217 #else
4218 channel = CHSPEC_CHANNEL((chanspec_t)chosen);
4219 #endif /* D11AC_IOTYPES */
4220 apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band;
4221 chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G;
4222 if (apcs_band == chosen_band) {
4223 WL_ERR(("selected channel = %d\n", channel));
4224 break;
4225 }
4226 }
4227 WL_DBG(("%d tried, ret = %d, chosen = 0x%x\n",
4228 (APCS_MAX_RETRY - retry), ret, chosen));
4229 OSL_SLEEP(250);
4230 }
4231
4232 done:
4233 if ((retry == 0) || (ret < 0)) {
4234 /* On failure, fallback to a default channel */
4235 if (band == WLC_BAND_5G) {
4236 channel = APCS_DEFAULT_5G_CH;
4237 } else {
4238 channel = APCS_DEFAULT_2G_CH;
4239 }
4240 WL_ERR(("ACS failed. Fall back to default channel (%d) \n", channel));
4241 }
4242 done2:
4243 if (spect > 0) {
4244 if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) {
4245 WL_ERR(("ACS: error while setting spect\n"));
4246 }
4247 }
4248
4249 if (reqbuf) {
4250 MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
4251 }
4252
4253 if (channel) {
4254 ret = snprintf(command, total_len, "%d", channel);
4255 WL_INFORM(("command result is %s \n", command));
4256 }
4257
4258 return ret;
4259 }
4260 #endif /* WL_SUPPORT_AUTO_CHANNEL */
4261
4262 #ifdef CUSTOMER_HW4_PRIVATE_CMD
4263 #ifdef SUPPORT_HIDDEN_AP
4264 static int
4265 wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
4266 {
4267 int max_assoc;
4268
4269 max_assoc = bcm_atoi(string_num);
4270 WL_INFORM(("HAPD_MAX_NUM_STA = %d\n", max_assoc));
4271 wldev_iovar_setint(dev, "maxassoc", max_assoc);
4272 WL_INFORM(("Conigured maxassoc = %d\n", max_assoc));
4273 return 1;
4274 }
4275
4276 static int
4277 wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
4278 {
4279 wlc_ssid_t ssid;
4280 s32 ret;
4281
4282 ssid.SSID_len = strlen(hapd_ssid);
4283 if (ssid.SSID_len == 0) {
4284 WL_ERR(("%s : No SSID\n", __FUNCTION__));
4285 return -1;
4286 }
4287 if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
4288 ssid.SSID_len = DOT11_MAX_SSID_LEN;
4289 WL_ERR(("%s : Too long SSID Length %zu\n", __FUNCTION__, strlen(hapd_ssid)));
4290 }
4291 bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
4292 DHD_INFO(("%s: HAPD_SSID = %s\n", __FUNCTION__, ssid.SSID));
4293 ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
4294 if (ret < 0) {
4295 WL_ERR(("%s : WLC_SET_SSID Error:%d\n", __FUNCTION__, ret));
4296 }
4297 return 1;
4298
4299 }
4300
4301 static int
4302 wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
4303 {
4304 int hide_ssid;
4305 int enable = 0;
4306
4307 hide_ssid = bcm_atoi(string_num);
4308 DHD_INFO(("%s: HAPD_HIDE_SSID = %d\n", __FUNCTION__, hide_ssid));
4309 if (hide_ssid)
4310 enable = 1;
4311 wldev_iovar_setint(dev, "closednet", enable);
4312 return 1;
4313 }
4314 #endif /* SUPPORT_HIDDEN_AP */
4315
4316 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
4317 static int
4318 wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
4319 {
4320 scb_val_t scbval;
4321 int error = 0;
4322
4323 DHD_INFO(("%s: deauth STA %s\n", __FUNCTION__, straddr));
4324
4325 /* Unspecified reason */
4326 scbval.val = htod32(1);
4327
4328 if (bcm_ether_atoe(straddr, &scbval.ea) == 0) {
4329 DHD_ERROR(("%s: Invalid station MAC Address!!!\n", __FUNCTION__));
4330 return -1;
4331 }
4332
4333 DHD_ERROR(("%s: deauth STA: "MACDBG " scb_val.val %d\n", __FUNCTION__,
4334 MAC2STRDBG(scbval.ea.octet), scbval.val));
4335
4336 error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
4337 sizeof(scb_val_t));
4338 if (error) {
4339 DHD_ERROR(("Fail to DEAUTH station, error = %d\n", error));
4340 }
4341
4342 return 1;
4343 }
4344 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
4345
4346 #ifdef SUPPORT_SET_LPC
4347 static int
4348 wl_android_set_lpc(struct net_device *dev, const char* string_num)
4349 {
4350 int lpc_enabled, ret;
4351 s32 val = 1;
4352
4353 lpc_enabled = bcm_atoi(string_num);
4354 DHD_INFO(("%s : HAPD_LPC_ENABLED = %d\n", __FUNCTION__, lpc_enabled));
4355
4356 ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
4357 if (ret < 0)
4358 DHD_ERROR(("WLC_DOWN error %d\n", ret));
4359
4360 wldev_iovar_setint(dev, "lpc", lpc_enabled);
4361
4362 ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
4363 if (ret < 0)
4364 DHD_ERROR(("WLC_UP error %d\n", ret));
4365
4366 return 1;
4367 }
4368 #endif /* SUPPORT_SET_LPC */
4369
4370 static int
4371 wl_android_ch_res_rl(struct net_device *dev, bool change)
4372 {
4373 int error = 0;
4374 s32 srl = 7;
4375 s32 lrl = 4;
4376 printk("%s enter\n", __FUNCTION__);
4377 if (change) {
4378 srl = 4;
4379 lrl = 2;
4380 }
4381
4382 BCM_REFERENCE(lrl);
4383
4384 error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
4385 if (error) {
4386 DHD_ERROR(("Failed to set SRL, error = %d\n", error));
4387 }
4388 #ifndef CUSTOM_LONG_RETRY_LIMIT
4389 error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
4390 if (error) {
4391 DHD_ERROR(("Failed to set LRL, error = %d\n", error));
4392 }
4393 #endif /* CUSTOM_LONG_RETRY_LIMIT */
4394 return error;
4395 }
4396
4397 #ifdef SUPPORT_LTECX
4398 #define DEFAULT_WLANRX_PROT 1
4399 #define DEFAULT_LTERX_PROT 0
4400 #define DEFAULT_LTETX_ADV 1200
4401
4402 static int
4403 wl_android_set_ltecx(struct net_device *dev, const char* string_num)
4404 {
4405 uint16 chan_bitmap;
4406 int ret;
4407
4408 chan_bitmap = bcm_strtoul(string_num, NULL, 16);
4409
4410 DHD_INFO(("%s : LTECOEX 0x%x\n", __FUNCTION__, chan_bitmap));
4411
4412 if (chan_bitmap) {
4413 ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
4414 if (ret < 0) {
4415 DHD_ERROR(("mws_coex_bitmap error %d\n", ret));
4416 }
4417
4418 ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT);
4419 if (ret < 0) {
4420 DHD_ERROR(("mws_wlanrx_prot error %d\n", ret));
4421 }
4422
4423 ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT);
4424 if (ret < 0) {
4425 DHD_ERROR(("mws_lterx_prot error %d\n", ret));
4426 }
4427
4428 ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV);
4429 if (ret < 0) {
4430 DHD_ERROR(("mws_ltetx_adv error %d\n", ret));
4431 }
4432 } else {
4433 ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
4434 if (ret < 0) {
4435 if (ret == BCME_UNSUPPORTED) {
4436 DHD_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n"));
4437 } else {
4438 DHD_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret));
4439 }
4440 }
4441 }
4442 return 1;
4443 }
4444 #endif /* SUPPORT_LTECX */
4445
4446 #ifdef WL_RELMCAST
4447 static int
4448 wl_android_rmc_enable(struct net_device *net, int rmc_enable)
4449 {
4450 int err;
4451
4452 err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
4453 if (err != BCME_OK) {
4454 DHD_ERROR(("%s: rmc_ackreq, error = %d\n", __FUNCTION__, err));
4455 }
4456 return err;
4457 }
4458
4459 static int
4460 wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
4461 {
4462 int error = BCME_OK;
4463 char smbuf[WLC_IOCTL_SMLEN];
4464 wl_rmc_entry_t rmc_entry;
4465 DHD_INFO(("%s: Set new RMC leader %s\n", __FUNCTION__, straddr));
4466
4467 memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t));
4468 if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
4469 if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
4470 DHD_INFO(("%s: Set auto leader selection mode\n", __FUNCTION__));
4471 memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t));
4472 } else {
4473 DHD_ERROR(("%s: No valid mac address provided\n",
4474 __FUNCTION__));
4475 return BCME_ERROR;
4476 }
4477 }
4478
4479 error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
4480 smbuf, sizeof(smbuf), NULL);
4481
4482 if (error != BCME_OK) {
4483 DHD_ERROR(("%s: Unable to set RMC leader, error = %d\n",
4484 __FUNCTION__, error));
4485 }
4486
4487 return error;
4488 }
4489
4490 static int wl_android_set_rmc_event(struct net_device *dev, char *command)
4491 {
4492 int err = 0;
4493 int pid = 0;
4494
4495 if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
4496 WL_ERR(("Failed to get Parameter from : %s\n", command));
4497 return -1;
4498 }
4499
4500 /* set pid, and if the event was happened, let's send a notification through netlink */
4501 wl_cfg80211_set_rmc_pid(dev, pid);
4502
4503 WL_DBG(("RMC pid=%d\n", pid));
4504
4505 return err;
4506 }
4507 #endif /* WL_RELMCAST */
4508
4509 int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
4510 {
4511 int error = 0;
4512 int bytes_written = 0;
4513 int mode = 0;
4514
4515 error = wldev_iovar_getint(dev, "scan_ps", &mode);
4516 if (error) {
4517 DHD_ERROR(("%s: Failed to get single core scan Mode, error = %d\n",
4518 __FUNCTION__, error));
4519 return -1;
4520 }
4521
4522 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
4523
4524 return bytes_written;
4525 }
4526
4527 int wl_android_set_singlecore_scan(struct net_device *dev, char *command)
4528 {
4529 int error = 0;
4530 int mode = 0;
4531
4532 if (sscanf(command, "%*s %d", &mode) != 1) {
4533 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
4534 return -1;
4535 }
4536
4537 error = wldev_iovar_setint(dev, "scan_ps", mode);
4538 if (error) {
4539 DHD_ERROR(("%s[1]: Failed to set Mode %d, error = %d\n",
4540 __FUNCTION__, mode, error));
4541 return -1;
4542 }
4543
4544 return error;
4545 }
4546 #ifdef TEST_TX_POWER_CONTROL
4547 static int
4548 wl_android_set_tx_power(struct net_device *dev, const char* string_num)
4549 {
4550 int err = 0;
4551 s32 dbm;
4552 enum nl80211_tx_power_setting type;
4553
4554 dbm = bcm_atoi(string_num);
4555
4556 if (dbm < -1) {
4557 DHD_ERROR(("%s: dbm is negative...\n", __FUNCTION__));
4558 return -EINVAL;
4559 }
4560
4561 if (dbm == -1)
4562 type = NL80211_TX_POWER_AUTOMATIC;
4563 else
4564 type = NL80211_TX_POWER_FIXED;
4565
4566 err = wl_set_tx_power(dev, type, dbm);
4567 if (unlikely(err)) {
4568 DHD_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
4569 return err;
4570 }
4571
4572 return 1;
4573 }
4574
4575 static int
4576 wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
4577 {
4578 int err;
4579 int bytes_written;
4580 s32 dbm = 0;
4581
4582 err = wl_get_tx_power(dev, &dbm);
4583 if (unlikely(err)) {
4584 DHD_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
4585 return err;
4586 }
4587
4588 bytes_written = snprintf(command, total_len, "%s %d",
4589 CMD_TEST_GET_TX_POWER, dbm);
4590
4591 DHD_ERROR(("%s: GET_TX_POWER: dBm=%d\n", __FUNCTION__, dbm));
4592
4593 return bytes_written;
4594 }
4595 #endif /* TEST_TX_POWER_CONTROL */
4596
4597 static int
4598 wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
4599 {
4600 int err = 0;
4601 int setval = 0;
4602 s32 mode = bcm_atoi(string_num);
4603
4604 /* As Samsung specific and their requirement, '0' means activate sarlimit
4605 * and '-1' means back to normal state (deactivate sarlimit)
4606 */
4607 if (mode >= 0 && mode < 3) {
4608 DHD_INFO(("%s: SAR limit control activated mode = %d\n", __FUNCTION__, mode));
4609 setval = mode + 1;
4610 } else if (mode == -1) {
4611 DHD_INFO(("%s: SAR limit control deactivated\n", __FUNCTION__));
4612 setval = 0;
4613 } else {
4614 return -EINVAL;
4615 }
4616
4617 err = wldev_iovar_setint(dev, "sar_enable", setval);
4618 if (unlikely(err)) {
4619 DHD_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
4620 return err;
4621 }
4622 return 1;
4623 }
4624
4625 #ifdef SUPPORT_SET_TID
4626 static int
4627 wl_android_set_tid(struct net_device *dev, char* command)
4628 {
4629 int err = BCME_ERROR;
4630 char *pos = command;
4631 char *token = NULL;
4632 uint8 mode = 0;
4633 uint32 uid = 0;
4634 uint8 prio = 0;
4635 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4636
4637 if (!dhdp) {
4638 WL_ERR(("dhd is NULL\n"));
4639 return err;
4640 }
4641
4642 WL_DBG(("%s: command[%s]\n", __FUNCTION__, command));
4643
4644 /* drop command */
4645 token = bcmstrtok(&pos, " ", NULL);
4646
4647 token = bcmstrtok(&pos, " ", NULL);
4648 if (!token) {
4649 WL_ERR(("Invalid arguments\n"));
4650 return err;
4651 }
4652
4653 mode = bcm_atoi(token);
4654
4655 if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) {
4656 WL_ERR(("Invalid arguments, mode %d\n", mode));
4657 return err;
4658 }
4659
4660 if (mode) {
4661 token = bcmstrtok(&pos, " ", NULL);
4662 if (!token) {
4663 WL_ERR(("Invalid arguments for target uid\n"));
4664 return err;
4665 }
4666
4667 uid = bcm_atoi(token);
4668
4669 token = bcmstrtok(&pos, " ", NULL);
4670 if (!token) {
4671 WL_ERR(("Invalid arguments for target tid\n"));
4672 return err;
4673 }
4674
4675 prio = bcm_atoi(token);
4676 if (prio >= 0 && prio <= MAXPRIO) {
4677 dhdp->tid_mode = mode;
4678 dhdp->target_uid = uid;
4679 dhdp->target_tid = prio;
4680 } else {
4681 WL_ERR(("Invalid arguments, prio %d\n", prio));
4682 return err;
4683 }
4684 } else {
4685 dhdp->tid_mode = SET_TID_OFF;
4686 dhdp->target_uid = 0;
4687 dhdp->target_tid = 0;
4688 }
4689
4690 WL_DBG(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__,
4691 dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid));
4692
4693 err = BCME_OK;
4694 return err;
4695 }
4696
4697 static int
4698 wl_android_get_tid(struct net_device *dev, char* command, int total_len)
4699 {
4700 int bytes_written = BCME_ERROR;
4701 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4702
4703 if (!dhdp) {
4704 WL_ERR(("dhd is NULL\n"));
4705 return bytes_written;
4706 }
4707
4708 bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d",
4709 dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid);
4710
4711 WL_DBG(("%s: command results %s\n", __FUNCTION__, command));
4712
4713 return bytes_written;
4714 }
4715 #endif /* SUPPORT_SET_TID */
4716 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
4717
4718 int wl_android_set_roam_mode(struct net_device *dev, char *command)
4719 {
4720 int error = 0;
4721 int mode = 0;
4722
4723 if (sscanf(command, "%*s %d", &mode) != 1) {
4724 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
4725 return -1;
4726 }
4727
4728 error = wldev_iovar_setint(dev, "roam_off", mode);
4729 if (error) {
4730 DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
4731 __FUNCTION__, mode, error));
4732 return -1;
4733 }
4734 else
4735 DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
4736 __FUNCTION__, mode, error));
4737 return 0;
4738 }
4739
4740 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
4741 {
4742 char ie_buf[VNDR_IE_MAX_LEN];
4743 char *ioctl_buf = NULL;
4744 char hex[] = "XX";
4745 char *pcmd = NULL;
4746 int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
4747 vndr_ie_setbuf_t *vndr_ie = NULL;
4748 s32 iecount;
4749 uint32 pktflag;
4750 s32 err = BCME_OK, bssidx;
4751 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4752
4753 /* Check the VSIE (Vendor Specific IE) which was added.
4754 * If exist then send IOVAR to delete it
4755 */
4756 if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
4757 return -EINVAL;
4758 }
4759
4760 if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
4761 WL_ERR(("error. total_len:%d\n", total_len));
4762 return -EINVAL;
4763 }
4764
4765 pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
4766 for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
4767 if (*pcmd == '\0') {
4768 WL_ERR(("error while parsing OUI.\n"));
4769 return -EINVAL;
4770 }
4771 hex[0] = *pcmd++;
4772 hex[1] = *pcmd++;
4773 ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16);
4774 }
4775 pcmd++;
4776 while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
4777 hex[0] = *pcmd++;
4778 hex[1] = *pcmd++;
4779 ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16);
4780 datalen++;
4781 }
4782
4783 if (datalen <= 0) {
4784 WL_ERR(("error. vndr ie len:%d\n", datalen));
4785 return -EINVAL;
4786 }
4787
4788 tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
4789 vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
4790 if (!vndr_ie) {
4791 WL_ERR(("IE memory alloc failed\n"));
4792 return -ENOMEM;
4793 }
4794 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
4795 strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1);
4796 vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
4797
4798 /* Set the IE count - the buffer contains only 1 IE */
4799 iecount = htod32(1);
4800 memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
4801
4802 /* Set packet flag to indicate that BEACON's will contain this IE */
4803 pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
4804 memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
4805 sizeof(u32));
4806 /* Set the IE ID */
4807 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
4808
4809 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
4810 DOT11_OUI_LEN);
4811 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
4812 &ie_buf[DOT11_OUI_LEN], datalen);
4813
4814 ielen = DOT11_OUI_LEN + datalen;
4815 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
4816
4817 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
4818 if (!ioctl_buf) {
4819 WL_ERR(("ioctl memory alloc failed\n"));
4820 if (vndr_ie) {
4821 MFREE(cfg->osh, vndr_ie, tot_len);
4822 }
4823 return -ENOMEM;
4824 }
4825 memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
4826 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4827 WL_ERR(("Find index failed\n"));
4828 err = BCME_ERROR;
4829 goto end;
4830 }
4831 err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
4832 WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
4833 end:
4834 if (err != BCME_OK) {
4835 err = -EINVAL;
4836 if (vndr_ie) {
4837 MFREE(cfg->osh, vndr_ie, tot_len);
4838 }
4839 }
4840 else {
4841 /* do NOT free 'vndr_ie' for the next process */
4842 wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
4843 }
4844
4845 if (ioctl_buf) {
4846 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4847 }
4848
4849 return err;
4850 }
4851
4852 #if defined(BCMFW_ROAM_ENABLE)
4853 static int
4854 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
4855 {
4856 int error = 0;
4857 char smbuf[WLC_IOCTL_SMLEN];
4858 uint8 buf[MAX_BUF_SIZE];
4859 uint8 *pref = buf;
4860 char *pcmd;
4861 int num_ucipher_suites = 0;
4862 int num_akm_suites = 0;
4863 wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
4864 wpa_suite_t akm_suites[MAX_NUM_SUITES];
4865 int num_tuples = 0;
4866 int total_bytes = 0;
4867 int total_len_left;
4868 int i, j;
4869 char hex[] = "XX";
4870
4871 pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
4872 total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
4873
4874 num_akm_suites = simple_strtoul(pcmd, NULL, 16);
4875 if (num_akm_suites > MAX_NUM_SUITES) {
4876 DHD_ERROR(("too many AKM suites = %d\n", num_akm_suites));
4877 return -1;
4878 }
4879
4880 /* Increment for number of AKM suites field + space */
4881 pcmd += 3;
4882 total_len_left -= 3;
4883
4884 /* check to make sure pcmd does not overrun */
4885 if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
4886 return -1;
4887
4888 memset(buf, 0, sizeof(buf));
4889 memset(akm_suites, 0, sizeof(akm_suites));
4890 memset(ucipher_suites, 0, sizeof(ucipher_suites));
4891
4892 /* Save the AKM suites passed in the command */
4893 for (i = 0; i < num_akm_suites; i++) {
4894 /* Store the MSB first, as required by join_pref */
4895 for (j = 0; j < 4; j++) {
4896 hex[0] = *pcmd++;
4897 hex[1] = *pcmd++;
4898 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
4899 }
4900 memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
4901 }
4902
4903 total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
4904 num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
4905 /* Increment for number of cipher suites field + space */
4906 pcmd += 3;
4907 total_len_left -= 3;
4908
4909 if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
4910 return -1;
4911
4912 /* Save the cipher suites passed in the command */
4913 for (i = 0; i < num_ucipher_suites; i++) {
4914 /* Store the MSB first, as required by join_pref */
4915 for (j = 0; j < 4; j++) {
4916 hex[0] = *pcmd++;
4917 hex[1] = *pcmd++;
4918 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
4919 }
4920 memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
4921 }
4922
4923 /* Join preference for RSSI
4924 * Type : 1 byte (0x01)
4925 * Length : 1 byte (0x02)
4926 * Value : 2 bytes (reserved)
4927 */
4928 *pref++ = WL_JOIN_PREF_RSSI;
4929 *pref++ = JOIN_PREF_RSSI_LEN;
4930 *pref++ = 0;
4931 *pref++ = 0;
4932
4933 /* Join preference for WPA
4934 * Type : 1 byte (0x02)
4935 * Length : 1 byte (not used)
4936 * Value : (variable length)
4937 * reserved: 1 byte
4938 * count : 1 byte (no of tuples)
4939 * Tuple1 : 12 bytes
4940 * akm[4]
4941 * ucipher[4]
4942 * mcipher[4]
4943 * Tuple2 : 12 bytes
4944 * Tuplen : 12 bytes
4945 */
4946 num_tuples = num_akm_suites * num_ucipher_suites;
4947 if (num_tuples != 0) {
4948 if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
4949 *pref++ = WL_JOIN_PREF_WPA;
4950 *pref++ = 0;
4951 *pref++ = 0;
4952 *pref++ = (uint8)num_tuples;
4953 total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
4954 (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
4955 } else {
4956 DHD_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
4957 return -1;
4958 }
4959 } else {
4960 /* No WPA config, configure only RSSI preference */
4961 total_bytes = JOIN_PREF_RSSI_SIZE;
4962 }
4963
4964 /* akm-ucipher-mcipher tuples in the format required for join_pref */
4965 for (i = 0; i < num_ucipher_suites; i++) {
4966 for (j = 0; j < num_akm_suites; j++) {
4967 memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
4968 pref += WPA_SUITE_LEN;
4969 memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
4970 pref += WPA_SUITE_LEN;
4971 /* Set to 0 to match any available multicast cipher */
4972 memset(pref, 0, WPA_SUITE_LEN);
4973 pref += WPA_SUITE_LEN;
4974 }
4975 }
4976
4977 prhex("join pref", (uint8 *)buf, total_bytes);
4978 error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
4979 if (error) {
4980 DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
4981 }
4982 return error;
4983 }
4984 #endif /* defined(BCMFW_ROAM_ENABLE */
4985
4986 static int
4987 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
4988 {
4989 struct io_cfg *resume_cfg;
4990 s32 ret;
4991 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4992
4993 resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
4994 if (!resume_cfg)
4995 return -ENOMEM;
4996
4997 if (config->iovar) {
4998 ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
4999 if (ret) {
5000 DHD_ERROR(("%s: Failed to get current %s value\n",
5001 __FUNCTION__, config->iovar));
5002 goto error;
5003 }
5004
5005 ret = wldev_iovar_setint(dev, config->iovar, config->param);
5006 if (ret) {
5007 DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
5008 config->iovar, config->param));
5009 goto error;
5010 }
5011
5012 resume_cfg->iovar = config->iovar;
5013 } else {
5014 resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
5015 if (!resume_cfg->arg) {
5016 ret = -ENOMEM;
5017 goto error;
5018 }
5019 ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
5020 if (ret) {
5021 DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
5022 config->ioctl));
5023 goto error;
5024 }
5025 ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
5026 if (ret) {
5027 DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
5028 config->iovar, config->param));
5029 goto error;
5030 }
5031 if (config->ioctl + 1 == WLC_SET_PM)
5032 wl_cfg80211_update_power_mode(dev);
5033 resume_cfg->ioctl = config->ioctl;
5034 resume_cfg->len = config->len;
5035 }
5036
5037 list_add(&resume_cfg->list, head);
5038
5039 return 0;
5040 error:
5041 MFREE(cfg->osh, resume_cfg->arg, config->len);
5042 MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
5043 return ret;
5044 }
5045
5046 static void
5047 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
5048 {
5049 struct io_cfg *config;
5050 struct list_head *cur, *q;
5051 s32 ret = 0;
5052 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5053
5054 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5055 #pragma GCC diagnostic push
5056 #pragma GCC diagnostic ignored "-Wcast-qual"
5057 #endif // endif
5058 list_for_each_safe(cur, q, head) {
5059 config = list_entry(cur, struct io_cfg, list);
5060 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5061 #pragma GCC diagnostic pop
5062 #endif // endif
5063 if (config->iovar) {
5064 if (!ret)
5065 ret = wldev_iovar_setint(dev, config->iovar,
5066 config->param);
5067 } else {
5068 if (!ret)
5069 ret = wldev_ioctl_set(dev, config->ioctl + 1,
5070 config->arg, config->len);
5071 if (config->ioctl + 1 == WLC_SET_PM)
5072 wl_cfg80211_update_power_mode(dev);
5073 MFREE(cfg->osh, config->arg, config->len);
5074 }
5075 list_del(cur);
5076 MFREE(cfg->osh, config, sizeof(struct io_cfg));
5077 }
5078 }
5079 static int
5080 wl_android_set_miracast(struct net_device *dev, char *command)
5081 {
5082 int mode, val = 0;
5083 int ret = 0;
5084 struct io_cfg config;
5085
5086 if (sscanf(command, "%*s %d", &mode) != 1) {
5087 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
5088 return -1;
5089 }
5090
5091 DHD_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
5092
5093 if (miracast_cur_mode == mode) {
5094 return 0;
5095 }
5096
5097 wl_android_iolist_resume(dev, &miracast_resume_list);
5098 miracast_cur_mode = MIRACAST_MODE_OFF;
5099 memset((void *)&config, 0, sizeof(config));
5100 switch (mode) {
5101 case MIRACAST_MODE_SOURCE:
5102 #ifdef MIRACAST_MCHAN_ALGO
5103 /* setting mchan_algo to platform specific value */
5104 config.iovar = "mchan_algo";
5105
5106 ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
5107 if (!ret && val > 100) {
5108 config.param = 0;
5109 DHD_ERROR(("%s: Connected station's beacon interval: "
5110 "%d and set mchan_algo to %d \n",
5111 __FUNCTION__, val, config.param));
5112 } else {
5113 config.param = MIRACAST_MCHAN_ALGO;
5114 }
5115 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
5116 if (ret) {
5117 goto resume;
5118 }
5119 #endif /* MIRACAST_MCHAN_ALGO */
5120
5121 #ifdef MIRACAST_MCHAN_BW
5122 /* setting mchan_bw to platform specific value */
5123 config.iovar = "mchan_bw";
5124 config.param = MIRACAST_MCHAN_BW;
5125 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
5126 if (ret) {
5127 goto resume;
5128 }
5129 #endif /* MIRACAST_MCHAN_BW */
5130
5131 #ifdef MIRACAST_AMPDU_SIZE
5132 /* setting apmdu to platform specific value */
5133 config.iovar = "ampdu_mpdu";
5134 config.param = MIRACAST_AMPDU_SIZE;
5135 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
5136 if (ret) {
5137 goto resume;
5138 }
5139 #endif /* MIRACAST_AMPDU_SIZE */
5140 /* FALLTROUGH */
5141 /* Source mode shares most configurations with sink mode.
5142 * Fall through here to avoid code duplication
5143 */
5144 case MIRACAST_MODE_SINK:
5145 /* disable internal roaming */
5146 config.iovar = "roam_off";
5147 config.param = 1;
5148 config.arg = NULL;
5149 config.len = 0;
5150 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
5151 if (ret) {
5152 goto resume;
5153 }
5154
5155 /* tunr off pm */
5156 ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
5157 if (ret) {
5158 goto resume;
5159 }
5160
5161 if (val != PM_OFF) {
5162 val = PM_OFF;
5163 config.iovar = NULL;
5164 config.ioctl = WLC_GET_PM;
5165 config.arg = &val;
5166 config.len = sizeof(int);
5167 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
5168 if (ret) {
5169 goto resume;
5170 }
5171 }
5172 break;
5173 case MIRACAST_MODE_OFF:
5174 default:
5175 break;
5176 }
5177 miracast_cur_mode = mode;
5178
5179 return 0;
5180
5181 resume:
5182 DHD_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
5183 wl_android_iolist_resume(dev, &miracast_resume_list);
5184 return ret;
5185 }
5186
5187 #define NETLINK_OXYGEN 30
5188 #define AIBSS_BEACON_TIMEOUT 10
5189
5190 static struct sock *nl_sk = NULL;
5191
5192 static void wl_netlink_recv(struct sk_buff *skb)
5193 {
5194 WL_ERR(("netlink_recv called\n"));
5195 }
5196
5197 static int wl_netlink_init(void)
5198 {
5199 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
5200 struct netlink_kernel_cfg cfg = {
5201 .input = wl_netlink_recv,
5202 };
5203 #endif // endif
5204
5205 if (nl_sk != NULL) {
5206 WL_ERR(("nl_sk already exist\n"));
5207 return BCME_ERROR;
5208 }
5209
5210 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
5211 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
5212 0, wl_netlink_recv, NULL, THIS_MODULE);
5213 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
5214 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
5215 #else
5216 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
5217 #endif // endif
5218
5219 if (nl_sk == NULL) {
5220 WL_ERR(("nl_sk is not ready\n"));
5221 return BCME_ERROR;
5222 }
5223
5224 return BCME_OK;
5225 }
5226
5227 static void wl_netlink_deinit(void)
5228 {
5229 if (nl_sk) {
5230 netlink_kernel_release(nl_sk);
5231 nl_sk = NULL;
5232 }
5233 }
5234
5235 s32
5236 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
5237 {
5238 struct sk_buff *skb = NULL;
5239 struct nlmsghdr *nlh = NULL;
5240 int ret = -1;
5241
5242 if (nl_sk == NULL) {
5243 WL_ERR(("nl_sk was not initialized\n"));
5244 goto nlmsg_failure;
5245 }
5246
5247 skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
5248 if (skb == NULL) {
5249 WL_ERR(("failed to allocate memory\n"));
5250 goto nlmsg_failure;
5251 }
5252
5253 nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
5254 if (nlh == NULL) {
5255 WL_ERR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
5256 skb_tailroom(skb), nlmsg_total_size(size)));
5257 dev_kfree_skb(skb);
5258 goto nlmsg_failure;
5259 }
5260
5261 memcpy(nlmsg_data(nlh), data, size);
5262 nlh->nlmsg_seq = seq;
5263 nlh->nlmsg_type = type;
5264
5265 /* netlink_unicast() takes ownership of the skb and frees it itself. */
5266 ret = netlink_unicast(nl_sk, skb, pid, 0);
5267 WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
5268
5269 nlmsg_failure:
5270 return ret;
5271 }
5272
5273 #ifdef WLAIBSS
5274 static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
5275 {
5276 int err = 0;
5277 int retry = 0;
5278 int pid = 0;
5279 aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0};
5280 char smbuf[WLC_IOCTL_SMLEN];
5281
5282 if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
5283 WL_ERR(("Failed to get Parameter from : %s\n", command));
5284 return -1;
5285 }
5286
5287 /* set pid, and if the event was happened, let's send a notification through netlink */
5288 wl_cfg80211_set_txfail_pid(dev, pid);
5289
5290 #ifdef WL_RELMCAST
5291 /* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */
5292 wl_cfg80211_set_rmc_pid(dev, pid);
5293 #endif /* WL_RELMCAST */
5294
5295 /* If retry value is 0, it disables the functionality for TX Fail. */
5296 if (retry > 0) {
5297 txfail_config.max_tx_retry = retry;
5298 txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */
5299 }
5300 txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
5301 txfail_config.len = sizeof(txfail_config);
5302
5303 err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
5304 sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
5305 WL_DBG(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
5306
5307 return ((err == 0)?total_len:err);
5308 }
5309
5310 static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
5311 int total_len, bool bAll)
5312 {
5313 int error;
5314 int bytes_written = 0;
5315 void *buf = NULL;
5316 bss_peer_list_info_t peer_list_info;
5317 bss_peer_info_t *peer_info;
5318 int i;
5319 bool found = false;
5320 struct ether_addr mac_ea;
5321 char *str = command;
5322 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5323
5324 WL_DBG(("get ibss peer info(%s)\n", bAll?"true":"false"));
5325
5326 if (!bAll) {
5327 if (bcmstrtok(&str, " ", NULL) == NULL) {
5328 WL_ERR(("invalid command\n"));
5329 return -1;
5330 }
5331
5332 if (!str || !bcm_ether_atoe(str, &mac_ea)) {
5333 WL_ERR(("invalid MAC address\n"));
5334 return -1;
5335 }
5336 }
5337
5338 buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
5339 if (buf == NULL) {
5340 WL_ERR(("MALLOC failed\n"));
5341 return -1;
5342 }
5343
5344 error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
5345 if (unlikely(error)) {
5346 WL_ERR(("could not get ibss peer info (%d)\n", error));
5347 MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
5348 return -1;
5349 }
5350
5351 memcpy(&peer_list_info, buf, sizeof(peer_list_info));
5352 peer_list_info.version = htod16(peer_list_info.version);
5353 peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
5354 peer_list_info.count = htod32(peer_list_info.count);
5355
5356 WL_DBG(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
5357 peer_list_info.bss_peer_info_len, peer_list_info.count));
5358
5359 if (peer_list_info.count > 0) {
5360 if (bAll)
5361 bytes_written += snprintf(&command[bytes_written], total_len, "%u ",
5362 peer_list_info.count);
5363
5364 peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
5365
5366 for (i = 0; i < peer_list_info.count; i++) {
5367
5368 WL_DBG(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
5369 peer_info->tx_rate, peer_info->rx_rate));
5370
5371 if (!bAll &&
5372 memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
5373 found = true;
5374 }
5375
5376 if (bAll || found) {
5377 bytes_written += snprintf(&command[bytes_written],
5378 total_len - bytes_written,
5379 MACF" %u %d ", ETHER_TO_MACF(peer_info->ea),
5380 peer_info->tx_rate/1000, peer_info->rssi);
5381 if (bytes_written >= total_len) {
5382 WL_ERR(("%s: Insufficient memory, %d bytes\n",
5383 __FUNCTION__, total_len));
5384 bytes_written = -1;
5385 break;
5386 }
5387 }
5388
5389 if (found)
5390 break;
5391
5392 peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t));
5393 }
5394 }
5395 else {
5396 WL_ERR(("could not get ibss peer info : no item\n"));
5397 }
5398 WL_DBG(("command(%u):%s\n", total_len, command));
5399 WL_DBG(("bytes_written:%d\n", bytes_written));
5400
5401 MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
5402 return bytes_written;
5403 }
5404
5405 int wl_android_set_ibss_routetable(struct net_device *dev, char *command)
5406 {
5407
5408 char *pcmd = command;
5409 char *str = NULL;
5410 ibss_route_tbl_t *route_tbl = NULL;
5411 char *ioctl_buf = NULL;
5412 s32 err = BCME_OK;
5413 uint32 route_tbl_len;
5414 uint32 entries;
5415 char *endptr;
5416 uint32 i = 0;
5417 struct ipv4_addr dipaddr;
5418 struct ether_addr ea;
5419 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5420
5421 route_tbl_len = sizeof(ibss_route_tbl_t) +
5422 (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
5423 route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len);
5424 if (!route_tbl) {
5425 WL_ERR(("Route TBL alloc failed\n"));
5426 return -ENOMEM;
5427 }
5428 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5429 if (!ioctl_buf) {
5430 WL_ERR(("ioctl memory alloc failed\n"));
5431 if (route_tbl) {
5432 MFREE(cfg->osh, route_tbl, route_tbl_len);
5433 }
5434 return -ENOMEM;
5435 }
5436 memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN);
5437
5438 /* drop command */
5439 str = bcmstrtok(&pcmd, " ", NULL);
5440
5441 /* get count */
5442 str = bcmstrtok(&pcmd, " ", NULL);
5443 if (!str) {
5444 WL_ERR(("Invalid number parameter %s\n", str));
5445 err = -EINVAL;
5446 goto exit;
5447 }
5448 entries = bcm_strtoul(str, &endptr, 0);
5449 if (*endptr != '\0') {
5450 WL_ERR(("Invalid number parameter %s\n", str));
5451 err = -EINVAL;
5452 goto exit;
5453 }
5454 if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) {
5455 WL_ERR(("Invalid entries number %u\n", entries));
5456 err = -EINVAL;
5457 goto exit;
5458 }
5459
5460 WL_INFORM(("Routing table count:%u\n", entries));
5461 route_tbl->num_entry = entries;
5462
5463 for (i = 0; i < entries; i++) {
5464 str = bcmstrtok(&pcmd, " ", NULL);
5465 if (!str || !bcm_atoipv4(str, &dipaddr)) {
5466 WL_ERR(("Invalid ip string %s\n", str));
5467 err = -EINVAL;
5468 goto exit;
5469 }
5470
5471 str = bcmstrtok(&pcmd, " ", NULL);
5472 if (!str || !bcm_ether_atoe(str, &ea)) {
5473 WL_ERR(("Invalid ethernet string %s\n", str));
5474 err = -EINVAL;
5475 goto exit;
5476 }
5477 bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
5478 bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
5479 }
5480
5481 route_tbl_len = sizeof(ibss_route_tbl_t) +
5482 ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
5483 err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
5484 route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5485 if (err != BCME_OK) {
5486 WL_ERR(("Fail to set iovar %d\n", err));
5487 err = -EINVAL;
5488 }
5489
5490 exit:
5491 if (route_tbl) {
5492 MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) +
5493 (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t));
5494 }
5495 if (ioctl_buf) {
5496 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5497 }
5498 return err;
5499
5500 }
5501
5502 int
5503 wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
5504 {
5505 char *pcmd = command;
5506 char *str = NULL, *endptr = NULL;
5507 struct ampdu_aggr aggr;
5508 char smbuf[WLC_IOCTL_SMLEN];
5509 int idx;
5510 int err = 0;
5511 int wme_AC2PRIO[AC_COUNT][2] = {
5512 {PRIO_8021D_VO, PRIO_8021D_NC}, /* AC_VO - 3 */
5513 {PRIO_8021D_CL, PRIO_8021D_VI}, /* AC_VI - 2 */
5514 {PRIO_8021D_BK, PRIO_8021D_NONE}, /* AC_BK - 1 */
5515 {PRIO_8021D_BE, PRIO_8021D_EE}}; /* AC_BE - 0 */
5516
5517 WL_DBG(("set ibss ampdu:%s\n", command));
5518
5519 memset(&aggr, 0, sizeof(aggr));
5520 /* Cofigure all priorities */
5521 aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
5522
5523 /* acquire parameters */
5524 /* drop command */
5525 str = bcmstrtok(&pcmd, " ", NULL);
5526
5527 for (idx = 0; idx < AC_COUNT; idx++) {
5528 bool on;
5529 str = bcmstrtok(&pcmd, " ", NULL);
5530 if (!str) {
5531 WL_ERR(("Invalid parameter : %s\n", pcmd));
5532 return -EINVAL;
5533 }
5534 on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
5535 if (*endptr != '\0') {
5536 WL_ERR(("Invalid number format %s\n", str));
5537 return -EINVAL;
5538 }
5539 if (on) {
5540 setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
5541 setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
5542 }
5543 }
5544
5545 err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
5546 sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
5547
5548 return ((err == 0) ? total_len : err);
5549 }
5550
5551 int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
5552 {
5553 char *pcmd = command;
5554 char *str = NULL;
5555 int txchain, rxchain;
5556 int err = 0;
5557
5558 WL_DBG(("set ibss antenna:%s\n", command));
5559
5560 /* acquire parameters */
5561 /* drop command */
5562 str = bcmstrtok(&pcmd, " ", NULL);
5563
5564 /* TX chain */
5565 str = bcmstrtok(&pcmd, " ", NULL);
5566 if (!str) {
5567 WL_ERR(("Invalid parameter : %s\n", pcmd));
5568 return -EINVAL;
5569 }
5570 txchain = bcm_atoi(str);
5571
5572 /* RX chain */
5573 str = bcmstrtok(&pcmd, " ", NULL);
5574 if (!str) {
5575 WL_ERR(("Invalid parameter : %s\n", pcmd));
5576 return -EINVAL;
5577 }
5578 rxchain = bcm_atoi(str);
5579
5580 err = wldev_iovar_setint(dev, "txchain", txchain);
5581 if (err != 0)
5582 return err;
5583 err = wldev_iovar_setint(dev, "rxchain", rxchain);
5584 return ((err == 0)?total_len:err);
5585 }
5586 #endif /* WLAIBSS */
5587
5588 int wl_keep_alive_set(struct net_device *dev, char* extra)
5589 {
5590 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
5591 int ret;
5592 uint period_msec = 0;
5593 char *buf;
5594 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5595
5596 if (extra == NULL) {
5597 DHD_ERROR(("%s: extra is NULL\n", __FUNCTION__));
5598 return -1;
5599 }
5600 if (sscanf(extra, "%d", &period_msec) != 1) {
5601 DHD_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
5602 return -EINVAL;
5603 }
5604 DHD_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
5605
5606 memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
5607
5608 mkeep_alive_pkt.period_msec = period_msec;
5609 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
5610 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
5611
5612 /* Setup keep alive zero for null packet generation */
5613 mkeep_alive_pkt.keep_alive_id = 0;
5614 mkeep_alive_pkt.len_bytes = 0;
5615
5616 buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_SMLEN);
5617 if (!buf) {
5618 DHD_ERROR(("%s: buffer alloc failed\n", __FUNCTION__));
5619 return BCME_NOMEM;
5620 }
5621 ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
5622 WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
5623 if (ret < 0)
5624 DHD_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret));
5625 else
5626 DHD_TRACE(("%s:keep_alive set ok\n", __FUNCTION__));
5627 MFREE(cfg->osh, buf, WLC_IOCTL_SMLEN);
5628 return ret;
5629 }
5630 #ifdef P2PRESP_WFDIE_SRC
5631 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
5632 {
5633 int error = 0;
5634 int bytes_written = 0;
5635 int only_resp_wfdsrc = 0;
5636
5637 error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
5638 if (error) {
5639 DHD_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
5640 __FUNCTION__, error));
5641 return -1;
5642 }
5643
5644 bytes_written = snprintf(command, total_len, "%s %d",
5645 CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
5646
5647 return bytes_written;
5648 }
5649
5650 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
5651 {
5652 int error = 0;
5653
5654 error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
5655 if (error) {
5656 DHD_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
5657 __FUNCTION__, only_resp_wfdsrc, error));
5658 return -1;
5659 }
5660
5661 return 0;
5662 }
5663 #endif /* P2PRESP_WFDIE_SRC */
5664
5665 #ifdef BT_WIFI_HANDOVER
5666 static int
5667 wl_tbow_teardown(struct net_device *dev)
5668 {
5669 int err = BCME_OK;
5670 char buf[WLC_IOCTL_SMLEN];
5671 tbow_setup_netinfo_t netinfo;
5672 memset(&netinfo, 0, sizeof(netinfo));
5673 netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
5674
5675 err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
5676 sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
5677 if (err < 0) {
5678 WL_ERR(("tbow_doho iovar error %d\n", err));
5679 return err;
5680 }
5681 return err;
5682 }
5683 #endif /* BT_WIFI_HANOVER */
5684
5685 #ifdef SET_RPS_CPUS
5686 static int
5687 wl_android_set_rps_cpus(struct net_device *dev, char *command)
5688 {
5689 int error, enable;
5690
5691 enable = command[strlen(CMD_RPSMODE) + 1] - '0';
5692 error = dhd_rps_cpus_enable(dev, enable);
5693
5694 #if defined(DHDTCPACK_SUPPRESS) && defined(BCMPCIE) && defined(WL_CFG80211)
5695 if (!error) {
5696 void *dhdp = wl_cfg80211_get_dhdp(net);
5697 if (enable) {
5698 DHD_TRACE(("%s : set ack suppress. TCPACK_SUP_HOLD.\n", __FUNCTION__));
5699 dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_HOLD);
5700 } else {
5701 DHD_TRACE(("%s : clear ack suppress.\n", __FUNCTION__));
5702 dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
5703 }
5704 }
5705 #endif /* DHDTCPACK_SUPPRESS && BCMPCIE && WL_CFG80211 */
5706
5707 return error;
5708 }
5709 #endif /* SET_RPS_CPUS */
5710
5711 static int wl_android_get_link_status(struct net_device *dev, char *command,
5712 int total_len)
5713 {
5714 int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
5715 uint32 rspec;
5716 uint encode, txexp;
5717 wl_bss_info_t *bi;
5718 int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
5719 char buf[datalen];
5720
5721 memset(buf, 0, datalen);
5722 /* get BSS information */
5723 *(u32 *) buf = htod32(datalen);
5724 error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
5725 if (unlikely(error)) {
5726 WL_ERR(("Could not get bss info %d\n", error));
5727 return -1;
5728 }
5729
5730 bi = (wl_bss_info_t*) (buf + sizeof(uint32));
5731
5732 for (i = 0; i < ETHER_ADDR_LEN; i++) {
5733 if (bi->BSSID.octet[i] > 0) {
5734 break;
5735 }
5736 }
5737
5738 if (i == ETHER_ADDR_LEN) {
5739 WL_DBG(("No BSSID\n"));
5740 return -1;
5741 }
5742
5743 /* check VHT capability at beacon */
5744 if (bi->vht_cap) {
5745 if (CHSPEC_IS5G(bi->chanspec)) {
5746 result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
5747 }
5748 }
5749
5750 /* get a rspec (radio spectrum) rate */
5751 error = wldev_iovar_getint(dev, "nrate", &rspec);
5752 if (unlikely(error) || rspec == 0) {
5753 WL_ERR(("get link status error (%d)\n", error));
5754 return -1;
5755 }
5756
5757 encode = (rspec & WL_RSPEC_ENCODING_MASK);
5758 txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
5759
5760 switch (encode) {
5761 case WL_RSPEC_ENCODE_HT:
5762 /* check Rx MCS Map for HT */
5763 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
5764 int8 bitmap = 0xFF;
5765 if (i == MAX_STREAMS_SUPPORTED-1) {
5766 bitmap = 0x7F;
5767 }
5768 if (bi->basic_mcs[i] & bitmap) {
5769 nss++;
5770 }
5771 }
5772 break;
5773 case WL_RSPEC_ENCODE_VHT:
5774 /* check Rx MCS Map for VHT */
5775 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
5776 mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
5777 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
5778 nss++;
5779 }
5780 }
5781 break;
5782 }
5783
5784 /* check MIMO capability with nss in beacon */
5785 if (nss > 1) {
5786 result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
5787 }
5788
5789 single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
5790 ((encode == WL_RSPEC_ENCODE_HT) && (rspec & WL_RSPEC_HT_MCS_MASK) < 8) ||
5791 ((encode == WL_RSPEC_ENCODE_VHT) &&
5792 ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
5793
5794 if (txexp == 0) {
5795 if ((rspec & WL_RSPEC_STBC) && single_stream) {
5796 stf = OLD_NRATE_STF_STBC;
5797 } else {
5798 stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
5799 }
5800 } else if (txexp == 1 && single_stream) {
5801 stf = OLD_NRATE_STF_CDD;
5802 }
5803
5804 /* check 11ac (VHT) */
5805 if (encode == WL_RSPEC_ENCODE_VHT) {
5806 if (CHSPEC_IS5G(bi->chanspec)) {
5807 result |= WL_ANDROID_LINK_VHT;
5808 }
5809 }
5810
5811 /* check MIMO */
5812 if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
5813 switch (stf) {
5814 case OLD_NRATE_STF_SISO:
5815 break;
5816 case OLD_NRATE_STF_CDD:
5817 case OLD_NRATE_STF_STBC:
5818 result |= WL_ANDROID_LINK_MIMO;
5819 break;
5820 case OLD_NRATE_STF_SDM:
5821 if (!single_stream) {
5822 result |= WL_ANDROID_LINK_MIMO;
5823 }
5824 break;
5825 }
5826 }
5827
5828 WL_DBG(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
5829 __FUNCTION__, result, stf, single_stream, nss));
5830
5831 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
5832
5833 return bytes_written;
5834 }
5835
5836 #ifdef P2P_LISTEN_OFFLOADING
5837
5838 s32
5839 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
5840 {
5841 s32 bssidx;
5842 int ret = 0;
5843 dhd_pub_t *dhd = NULL;
5844 if (!cfg || !cfg->p2p) {
5845 WL_ERR(("Wl %p or cfg->p2p %p is null\n",
5846 cfg, cfg ? cfg->p2p : 0));
5847 return 0;
5848 }
5849
5850 dhd = (dhd_pub_t *)(cfg->pub);
5851 if (!dhd->up) {
5852 WL_ERR(("bus is already down\n"));
5853 return ret;
5854 }
5855
5856 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
5857 ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
5858 "p2po_stop", NULL, 0,
5859 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
5860 if (ret < 0) {
5861 WL_ERR(("p2po_stop Failed :%d\n", ret));
5862 }
5863
5864 return ret;
5865 }
5866 s32
5867 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
5868 {
5869 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5870 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
5871 wl_p2plo_listen_t p2plo_listen;
5872 int ret = -EAGAIN;
5873 int channel = 0;
5874 int period = 0;
5875 int interval = 0;
5876 int count = 0;
5877 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
5878 WL_ERR(("Sending Action Frames. Try it again.\n"));
5879 goto exit;
5880 }
5881
5882 if (wl_get_drv_status_all(cfg, SCANNING)) {
5883 WL_ERR(("Scanning already\n"));
5884 goto exit;
5885 }
5886
5887 if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
5888 WL_ERR(("Scanning being aborted\n"));
5889 goto exit;
5890 }
5891
5892 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
5893 WL_ERR(("p2p listen offloading already running\n"));
5894 goto exit;
5895 }
5896
5897 /* Just in case if it is not enabled */
5898 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
5899 WL_ERR(("cfgp2p_enable discovery failed"));
5900 goto exit;
5901 }
5902
5903 bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
5904
5905 if (len) {
5906 sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
5907 if ((channel == 0) || (period == 0) ||
5908 (interval == 0) || (count == 0)) {
5909 WL_ERR(("Wrong argument %d/%d/%d/%d \n",
5910 channel, period, interval, count));
5911 ret = -EAGAIN;
5912 goto exit;
5913 }
5914 p2plo_listen.period = period;
5915 p2plo_listen.interval = interval;
5916 p2plo_listen.count = count;
5917
5918 WL_ERR(("channel:%d period:%d, interval:%d count:%d\n",
5919 channel, period, interval, count));
5920 } else {
5921 WL_ERR(("Argument len is wrong.\n"));
5922 ret = -EAGAIN;
5923 goto exit;
5924 }
5925
5926 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
5927 sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
5928 bssidx, &cfg->ioctl_buf_sync)) < 0) {
5929 WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
5930 goto exit;
5931 }
5932
5933 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
5934 sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
5935 bssidx, &cfg->ioctl_buf_sync)) < 0) {
5936 WL_ERR(("p2po_listen Failed :%d\n", ret));
5937 goto exit;
5938 }
5939
5940 wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
5941 exit :
5942 return ret;
5943 }
5944 s32
5945 wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
5946 {
5947 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5948 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
5949 int ret = -EAGAIN;
5950
5951 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
5952 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
5953 bssidx, &cfg->ioctl_buf_sync)) < 0) {
5954 WL_ERR(("p2po_stop Failed :%d\n", ret));
5955 goto exit;
5956 }
5957
5958 exit:
5959 return ret;
5960 }
5961
5962 s32
5963 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
5964 {
5965 int ret = 0;
5966
5967 WL_ERR(("Entry cmd:%s arg_len:%d \n", cmd, len));
5968
5969 if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
5970 ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
5971 } else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
5972 ret = wl_cfg80211_p2plo_listen_stop(dev);
5973 } else {
5974 WL_ERR(("Request for Unsupported CMD:%s \n", buf));
5975 ret = -EINVAL;
5976 }
5977 return ret;
5978 }
5979 void
5980 wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg)
5981 {
5982 struct wireless_dev *wdev;
5983 if (!cfg) {
5984 return;
5985 }
5986
5987 wdev = bcmcfg_to_p2p_wdev(cfg);
5988
5989 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
5990 WL_INFORM_MEM(("P2P_FIND: Discovery offload is already in progress."
5991 "it aborted\n"));
5992 wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
5993 if (wdev != NULL) {
5994 #if defined(WL_CFG80211_P2P_DEV_IF)
5995 cfg80211_remain_on_channel_expired(wdev,
5996 cfg->last_roc_id,
5997 &cfg->remain_on_chan, GFP_KERNEL);
5998 #else
5999 cfg80211_remain_on_channel_expired(wdev,
6000 cfg->last_roc_id,
6001 &cfg->remain_on_chan,
6002 cfg->remain_on_chan_type, GFP_KERNEL);
6003 #endif /* WL_CFG80211_P2P_DEV_IF */
6004 }
6005 wl_cfg80211_p2plo_deinit(cfg);
6006 }
6007 }
6008 #endif /* P2P_LISTEN_OFFLOADING */
6009
6010 #ifdef DYNAMIC_MUMIMO_CONTROL
6011 int
6012 wl_android_get_murx_bfe_cap(struct net_device *dev, char *command, int total_len)
6013 {
6014 int err = 0;
6015 int cap = 0;
6016 int bytes_written = 0;
6017
6018 /* Now there is only single interface */
6019 err = wl_get_murx_bfe_cap(dev, &cap);
6020 if (unlikely(err)) {
6021 WL_ERR(("Failed to get murx_bfe_cap, error = %d\n", err));
6022 return err;
6023 }
6024
6025 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_MURX_BFE_CAP, cap);
6026
6027 return bytes_written;
6028 }
6029
6030 int
6031 wl_android_set_murx_bfe_cap(struct net_device *dev, int val)
6032 {
6033 int err = BCME_OK;
6034
6035 err = wl_set_murx_bfe_cap(dev, val, TRUE);
6036 if (unlikely(err)) {
6037 WL_ERR(("Failed to set murx_bfe_cap to %d, error = %d\n", val, err));
6038 }
6039
6040 return err;
6041 }
6042
6043 int
6044 wl_android_get_bss_support_mumimo(struct net_device *dev, char *command, int total_len)
6045 {
6046 int val = 0;
6047 int bytes_written = 0;
6048
6049 val = wl_check_bss_support_mumimo(dev);
6050 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_BSS_SUPPORT_MUMIMO, val);
6051
6052 return bytes_written;
6053 }
6054 #endif /* DYNAMIC_MUMIMO_CONTROL */
6055
6056 #ifdef SUPPORT_RSSI_SUM_REPORT
6057 int
6058 wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
6059 {
6060 wl_rssi_ant_mimo_t rssi_ant_mimo;
6061 char *ifname = NULL;
6062 char *peer_mac = NULL;
6063 char *mimo_cmd = "mimo";
6064 char *pos, *token;
6065 int err = BCME_OK;
6066 int bytes_written = 0;
6067 bool mimo_rssi = FALSE;
6068
6069 memset(&rssi_ant_mimo, 0, sizeof(wl_rssi_ant_mimo_t));
6070 /*
6071 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
6072 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
6073 */
6074 pos = command;
6075
6076 /* drop command */
6077 token = bcmstrtok(&pos, " ", NULL);
6078
6079 /* get the interface name */
6080 token = bcmstrtok(&pos, " ", NULL);
6081 if (!token) {
6082 WL_ERR(("Invalid arguments\n"));
6083 return -EINVAL;
6084 }
6085 ifname = token;
6086
6087 /* Optional: Check the MIMO RSSI mode or peer MAC address */
6088 token = bcmstrtok(&pos, " ", NULL);
6089 if (token) {
6090 /* Check the MIMO RSSI mode */
6091 if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
6092 mimo_rssi = TRUE;
6093 } else {
6094 peer_mac = token;
6095 }
6096 }
6097
6098 /* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
6099 token = bcmstrtok(&pos, " ", NULL);
6100 if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
6101 mimo_rssi = TRUE;
6102 }
6103
6104 err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
6105 if (unlikely(err)) {
6106 WL_ERR(("Failed to get RSSI info, err=%d\n", err));
6107 return err;
6108 }
6109
6110 /* Parse the results */
6111 WL_DBG(("ifname %s, version %d, count %d, mimo rssi %d\n",
6112 ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
6113 if (mimo_rssi) {
6114 WL_DBG(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
6115 bytes_written = snprintf(command, total_len, "%s MIMO %d",
6116 CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
6117 } else {
6118 int cnt;
6119 bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
6120 for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
6121 WL_DBG(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
6122 bytes_written = snprintf(command, total_len, "%d ",
6123 rssi_ant_mimo.rssi_ant[cnt]);
6124 }
6125 }
6126
6127 return bytes_written;
6128 }
6129
6130 int
6131 wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
6132 {
6133 rssilog_set_param_t set_param;
6134 char *pos, *token;
6135 int err = BCME_OK;
6136
6137 memset(&set_param, 0, sizeof(rssilog_set_param_t));
6138 /*
6139 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
6140 */
6141 pos = command;
6142
6143 /* drop command */
6144 token = bcmstrtok(&pos, " ", NULL);
6145
6146 /* enable/disable */
6147 token = bcmstrtok(&pos, " ", NULL);
6148 if (!token) {
6149 WL_ERR(("Invalid arguments\n"));
6150 return -EINVAL;
6151 }
6152 set_param.enable = bcm_atoi(token);
6153
6154 /* RSSI Threshold */
6155 token = bcmstrtok(&pos, " ", NULL);
6156 if (!token) {
6157 WL_ERR(("Invalid arguments\n"));
6158 return -EINVAL;
6159 }
6160 set_param.rssi_threshold = bcm_atoi(token);
6161
6162 /* Time Threshold */
6163 token = bcmstrtok(&pos, " ", NULL);
6164 if (!token) {
6165 WL_ERR(("Invalid arguments\n"));
6166 return -EINVAL;
6167 }
6168 set_param.time_threshold = bcm_atoi(token);
6169
6170 WL_DBG(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
6171 set_param.rssi_threshold, set_param.time_threshold));
6172
6173 err = wl_set_rssi_logging(dev, (void *)&set_param);
6174 if (unlikely(err)) {
6175 WL_ERR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
6176 " Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
6177 set_param.time_threshold));
6178 }
6179
6180 return err;
6181 }
6182
6183 int
6184 wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
6185 {
6186 rssilog_get_param_t get_param;
6187 int err = BCME_OK;
6188 int bytes_written = 0;
6189
6190 err = wl_get_rssi_logging(dev, (void *)&get_param);
6191 if (unlikely(err)) {
6192 WL_ERR(("Failed to get RSSI logging info\n"));
6193 return BCME_ERROR;
6194 }
6195
6196 WL_DBG(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
6197 get_param.report_count, get_param.enable, get_param.rssi_threshold,
6198 get_param.time_threshold));
6199
6200 /* Parse the parameter */
6201 if (!get_param.enable) {
6202 WL_DBG(("RSSI LOGGING: Feature is disables\n"));
6203 bytes_written = snprintf(command, total_len,
6204 "%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
6205 } else if (get_param.enable &
6206 (RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
6207 if (!get_param.report_count) {
6208 WL_DBG(("[PASS] RSSI difference across antennas is within"
6209 " threshold limits\n"));
6210 bytes_written = snprintf(command, total_len, "%s PASS\n",
6211 CMD_GET_RSSI_LOGGING);
6212 } else {
6213 WL_DBG(("[FAIL] RSSI difference across antennas found "
6214 "to be greater than %3d dB\n", get_param.rssi_threshold));
6215 WL_DBG(("[FAIL] RSSI difference check have failed for "
6216 "%d out of %d times\n", get_param.report_count,
6217 get_param.time_threshold));
6218 WL_DBG(("[FAIL] RSSI difference is being monitored once "
6219 "per second, for a %d secs window\n", get_param.time_threshold));
6220 bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
6221 "%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
6222 get_param.rssi_threshold, get_param.report_count,
6223 get_param.time_threshold);
6224 }
6225 } else {
6226 WL_DBG(("[BUSY] Reprot is not ready\n"));
6227 bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
6228 CMD_GET_RSSI_LOGGING);
6229 }
6230
6231 return bytes_written;
6232 }
6233 #endif /* SUPPORT_RSSI_SUM_REPORT */
6234
6235 #ifdef SET_PCIE_IRQ_CPU_CORE
6236 void
6237 wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
6238 {
6239 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
6240 if (!dhdp) {
6241 WL_ERR(("dhd is NULL\n"));
6242 return;
6243 }
6244
6245 if (affinity_cmd < PCIE_IRQ_AFFINITY_OFF || affinity_cmd > PCIE_IRQ_AFFINITY_LAST) {
6246 WL_ERR(("Wrong Affinity cmds:%d, %s\n", affinity_cmd, __FUNCTION__));
6247 return;
6248 }
6249
6250 dhd_set_irq_cpucore(dhdp, affinity_cmd);
6251 }
6252 #endif /* SET_PCIE_IRQ_CPU_CORE */
6253
6254 #ifdef SUPPORT_LQCM
6255 static int
6256 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
6257 {
6258 int err = 0;
6259
6260 err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
6261 if (err != BCME_OK) {
6262 WL_ERR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
6263 return -EIO;
6264 }
6265 return err;
6266 }
6267
6268 static int
6269 wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len)
6270 {
6271 int bytes_written, err = 0;
6272 uint32 lqcm_report = 0;
6273 uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
6274
6275 err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
6276 if (err != BCME_OK) {
6277 WL_ERR(("failed to get lqcm report, error = %d\n", err));
6278 return -EIO;
6279 }
6280 lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
6281 tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
6282 rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
6283
6284 WL_DBG(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
6285
6286 bytes_written = snprintf(command, total_len, "%s %d",
6287 CMD_GET_LQCM_REPORT, lqcm_report);
6288
6289 return bytes_written;
6290 }
6291 #endif /* SUPPORT_LQCM */
6292
6293 int
6294 wl_android_get_snr(struct net_device *dev, char *command, int total_len)
6295 {
6296 int bytes_written, error = 0;
6297 s32 snr = 0;
6298
6299 error = wldev_iovar_getint(dev, "snr", &snr);
6300 if (error) {
6301 DHD_ERROR(("%s: Failed to get SNR %d, error = %d\n",
6302 __FUNCTION__, snr, error));
6303 return -EIO;
6304 }
6305
6306 bytes_written = snprintf(command, total_len, "snr %d", snr);
6307 DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command));
6308 return bytes_written;
6309 }
6310
6311 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
6312 int
6313 wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
6314 {
6315 int rate = 0;
6316 char *pos, *token;
6317 char *ifname = NULL;
6318 int err = BCME_OK;
6319
6320 /*
6321 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
6322 */
6323 pos = command;
6324
6325 /* drop command */
6326 token = bcmstrtok(&pos, " ", NULL);
6327
6328 /* Rate */
6329 token = bcmstrtok(&pos, " ", NULL);
6330 if (!token)
6331 return -EINVAL;
6332 rate = bcm_atoi(token);
6333
6334 /* get the interface name */
6335 token = bcmstrtok(&pos, " ", NULL);
6336 if (!token)
6337 return -EINVAL;
6338 ifname = token;
6339
6340 WL_DBG(("rate %d, ifacename %s\n", rate, ifname));
6341
6342 err = wl_set_ap_beacon_rate(dev, rate, ifname);
6343 if (unlikely(err)) {
6344 WL_ERR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
6345 }
6346
6347 return err;
6348 }
6349
6350 int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
6351 {
6352 char *pos, *token;
6353 char *ifname = NULL;
6354 int bytes_written = 0;
6355 /*
6356 * DRIVER GET_AP_BASICRATE <ifname>
6357 */
6358 pos = command;
6359
6360 /* drop command */
6361 token = bcmstrtok(&pos, " ", NULL);
6362
6363 /* get the interface name */
6364 token = bcmstrtok(&pos, " ", NULL);
6365 if (!token)
6366 return -EINVAL;
6367 ifname = token;
6368
6369 WL_DBG(("ifacename %s\n", ifname));
6370
6371 bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
6372 if (bytes_written < 1) {
6373 WL_ERR(("Failed to get ap basic rate, error = %d\n", bytes_written));
6374 return -EPROTO;
6375 }
6376
6377 return bytes_written;
6378 }
6379 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
6380
6381 #ifdef SUPPORT_AP_RADIO_PWRSAVE
6382 int
6383 wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
6384 {
6385 char *pos, *token;
6386 char *ifname = NULL;
6387 int bytes_written = 0;
6388 char name[IFNAMSIZ];
6389 /*
6390 * DRIVER GET_AP_RPS <ifname>
6391 */
6392 pos = command;
6393
6394 /* drop command */
6395 token = bcmstrtok(&pos, " ", NULL);
6396
6397 /* get the interface name */
6398 token = bcmstrtok(&pos, " ", NULL);
6399 if (!token)
6400 return -EINVAL;
6401 ifname = token;
6402
6403 strncpy(name, ifname, IFNAMSIZ);
6404 name[IFNAMSIZ-1] = '\0';
6405 WL_DBG(("ifacename %s\n", name));
6406
6407 bytes_written = wl_get_ap_rps(dev, command, name, total_len);
6408 if (bytes_written < 1) {
6409 WL_ERR(("Failed to get rps, error = %d\n", bytes_written));
6410 return -EPROTO;
6411 }
6412
6413 return bytes_written;
6414
6415 }
6416
6417 int
6418 wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
6419 {
6420 int enable = 0;
6421 char *pos, *token;
6422 char *ifname = NULL;
6423 int err = BCME_OK;
6424 char name[IFNAMSIZ];
6425
6426 /*
6427 * DRIVER SET_AP_RPS <0/1> <ifname>
6428 */
6429 pos = command;
6430
6431 /* drop command */
6432 token = bcmstrtok(&pos, " ", NULL);
6433
6434 /* Enable */
6435 token = bcmstrtok(&pos, " ", NULL);
6436 if (!token)
6437 return -EINVAL;
6438 enable = bcm_atoi(token);
6439
6440 /* get the interface name */
6441 token = bcmstrtok(&pos, " ", NULL);
6442 if (!token)
6443 return -EINVAL;
6444 ifname = token;
6445
6446 strncpy(name, ifname, IFNAMSIZ);
6447 name[IFNAMSIZ-1] = '\0';
6448 WL_DBG(("enable %d, ifacename %s\n", enable, name));
6449
6450 err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name);
6451 if (unlikely(err)) {
6452 WL_ERR(("Failed to set rps, enable %d, error = %d\n", enable, err));
6453 }
6454
6455 return err;
6456 }
6457
6458 int
6459 wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
6460 {
6461 ap_rps_info_t rps;
6462 char *pos, *token;
6463 char *ifname = NULL;
6464 int err = BCME_OK;
6465 char name[IFNAMSIZ];
6466
6467 memset(&rps, 0, sizeof(rps));
6468 /*
6469 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
6470 */
6471 pos = command;
6472
6473 /* drop command */
6474 token = bcmstrtok(&pos, " ", NULL);
6475
6476 /* pps */
6477 token = bcmstrtok(&pos, " ", NULL);
6478 if (!token)
6479 return -EINVAL;
6480 rps.pps = bcm_atoi(token);
6481
6482 /* level */
6483 token = bcmstrtok(&pos, " ", NULL);
6484 if (!token)
6485 return -EINVAL;
6486 rps.level = bcm_atoi(token);
6487
6488 /* quiettime */
6489 token = bcmstrtok(&pos, " ", NULL);
6490 if (!token)
6491 return -EINVAL;
6492 rps.quiet_time = bcm_atoi(token);
6493
6494 /* sta assoc check */
6495 token = bcmstrtok(&pos, " ", NULL);
6496 if (!token)
6497 return -EINVAL;
6498 rps.sta_assoc_check = bcm_atoi(token);
6499
6500 /* get the interface name */
6501 token = bcmstrtok(&pos, " ", NULL);
6502 if (!token)
6503 return -EINVAL;
6504 ifname = token;
6505 strncpy(name, ifname, IFNAMSIZ);
6506 name[IFNAMSIZ-1] = '\0';
6507
6508 WL_DBG(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
6509 "ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
6510 rps.sta_assoc_check, name));
6511
6512 err = wl_update_ap_rps_params(dev, &rps, name);
6513 if (unlikely(err)) {
6514 WL_ERR(("Failed to update rps, pps %d, level %d, quiettime %d, "
6515 "sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
6516 rps.sta_assoc_check, err));
6517 }
6518
6519 return err;
6520 }
6521 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
6522
6523 #if defined(DHD_HANG_SEND_UP_TEST)
6524 void
6525 wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
6526 {
6527 dhd_make_hang_with_reason(dev, string_num);
6528 }
6529 #endif /* DHD_HANG_SEND_UP_TEST */
6530
6531 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
6532 static void
6533 wl_android_check_priv_cmd_errors(struct net_device *dev)
6534 {
6535 dhd_pub_t *dhdp;
6536 int memdump_mode;
6537
6538 if (!dev) {
6539 WL_ERR(("dev is NULL\n"));
6540 return;
6541 }
6542
6543 dhdp = wl_cfg80211_get_dhdp(dev);
6544 if (!dhdp) {
6545 WL_ERR(("dhdp is NULL\n"));
6546 return;
6547 }
6548
6549 #ifdef DHD_FW_COREDUMP
6550 memdump_mode = dhdp->memdump_enabled;
6551 #else
6552 /* Default enable if DHD doesn't support SOCRAM dump */
6553 memdump_mode = 1;
6554 #endif /* DHD_FW_COREDUMP */
6555
6556 if (report_hang_privcmd_err) {
6557 priv_cmd_errors++;
6558 } else {
6559 priv_cmd_errors = 0;
6560 }
6561
6562 /* Trigger HANG event only if memdump mode is enabled
6563 * due to customer's request
6564 */
6565 if (memdump_mode && (priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) {
6566 WL_ERR(("Send HANG event due to sequential private cmd errors\n"));
6567 priv_cmd_errors = 0;
6568 #ifdef DHD_FW_COREDUMP
6569 /* Take a SOCRAM dump */
6570 dhdp->memdump_type = DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR;
6571 dhd_common_socram_dump(dhdp);
6572 #endif /* DHD_FW_COREDUMP */
6573 /* Send the HANG event to upper layer */
6574 dhdp->hang_reason = HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR;
6575 dhd_os_check_hang(dhdp, 0, -EREMOTEIO);
6576 }
6577 }
6578 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
6579
6580 #ifdef DHD_PKT_LOGGING
6581 static int
6582 wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
6583 {
6584 int bytes_written = 0;
6585 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6586 dhd_pktlog_filter_t *filter;
6587 int err = BCME_OK;
6588
6589 if (!dhdp || !dhdp->pktlog) {
6590 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6591 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6592 return -EINVAL;
6593 }
6594
6595 filter = dhdp->pktlog->pktlog_filter;
6596
6597 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
6598 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
6599 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
6600
6601 if (err == BCME_OK) {
6602 bytes_written = snprintf(command, total_len, "OK");
6603 DHD_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
6604 } else {
6605 DHD_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
6606 return BCME_ERROR;
6607 }
6608
6609 return bytes_written;
6610 }
6611
6612 static int
6613 wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
6614 {
6615 int bytes_written = 0;
6616 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6617 dhd_pktlog_filter_t *filter;
6618 int err = BCME_OK;
6619
6620 if (!dhdp || !dhdp->pktlog) {
6621 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6622 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6623 return -EINVAL;
6624 }
6625
6626 filter = dhdp->pktlog->pktlog_filter;
6627
6628 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
6629 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
6630 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
6631
6632 if (err == BCME_OK) {
6633 bytes_written = snprintf(command, total_len, "OK");
6634 DHD_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
6635 } else {
6636 DHD_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
6637 return BCME_ERROR;
6638 }
6639
6640 return bytes_written;
6641 }
6642
6643 static int
6644 wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
6645 {
6646 int bytes_written = 0;
6647 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6648 dhd_pktlog_filter_t *filter;
6649 int err = BCME_OK;
6650
6651 if (!dhdp || !dhdp->pktlog) {
6652 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6653 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6654 return -EINVAL;
6655 }
6656
6657 filter = dhdp->pktlog->pktlog_filter;
6658
6659 if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
6660 return BCME_ERROR;
6661 }
6662
6663 err = dhd_pktlog_filter_pattern_enable(filter,
6664 command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
6665
6666 if (err == BCME_OK) {
6667 bytes_written = snprintf(command, total_len, "OK");
6668 DHD_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
6669 } else {
6670 DHD_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
6671 return BCME_ERROR;
6672 }
6673
6674 return bytes_written;
6675 }
6676
6677 static int
6678 wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
6679 {
6680 int bytes_written = 0;
6681 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6682 dhd_pktlog_filter_t *filter;
6683 int err = BCME_OK;
6684
6685 if (!dhdp || !dhdp->pktlog) {
6686 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6687 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6688 return -EINVAL;
6689 }
6690
6691 filter = dhdp->pktlog->pktlog_filter;
6692
6693 if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
6694 return BCME_ERROR;
6695 }
6696
6697 err = dhd_pktlog_filter_pattern_enable(filter,
6698 command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
6699
6700 if (err == BCME_OK) {
6701 bytes_written = snprintf(command, total_len, "OK");
6702 DHD_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
6703 } else {
6704 DHD_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
6705 return BCME_ERROR;
6706 }
6707
6708 return bytes_written;
6709 }
6710
6711 static int
6712 wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
6713 {
6714 int bytes_written = 0;
6715 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6716 dhd_pktlog_filter_t *filter;
6717 int err = BCME_OK;
6718
6719 if (!dhdp || !dhdp->pktlog) {
6720 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6721 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6722 return -EINVAL;
6723 }
6724
6725 filter = dhdp->pktlog->pktlog_filter;
6726
6727 if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
6728 return BCME_ERROR;
6729 }
6730
6731 err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
6732
6733 if (err == BCME_OK) {
6734 bytes_written = snprintf(command, total_len, "OK");
6735 DHD_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
6736 } else {
6737 DHD_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
6738 return BCME_ERROR;
6739 }
6740
6741 return bytes_written;
6742 }
6743
6744 static int
6745 wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
6746 {
6747 int bytes_written = 0;
6748 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6749 dhd_pktlog_filter_t *filter;
6750 int err = BCME_OK;
6751
6752 if (!dhdp || !dhdp->pktlog) {
6753 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6754 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6755 return -EINVAL;
6756 }
6757
6758 filter = dhdp->pktlog->pktlog_filter;
6759
6760 err = dhd_pktlog_filter_info(filter);
6761
6762 if (err == BCME_OK) {
6763 bytes_written = snprintf(command, total_len, "OK");
6764 DHD_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
6765 } else {
6766 DHD_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
6767 return BCME_ERROR;
6768 }
6769
6770 return bytes_written;
6771 }
6772
6773 static int
6774 wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
6775 {
6776 int bytes_written = 0;
6777 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6778
6779 if (!dhdp || !dhdp->pktlog) {
6780 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6781 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6782 return -EINVAL;
6783 }
6784
6785 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
6786 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
6787 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
6788 return -EINVAL;
6789 }
6790
6791 dhdp->pktlog->tx_pktlog_ring->start = TRUE;
6792 dhdp->pktlog->rx_pktlog_ring->start = TRUE;
6793
6794 bytes_written = snprintf(command, total_len, "OK");
6795
6796 DHD_ERROR(("%s: pktlog start success\n", __FUNCTION__));
6797
6798 return bytes_written;
6799 }
6800
6801 static int
6802 wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
6803 {
6804 int bytes_written = 0;
6805 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6806
6807 if (!dhdp || !dhdp->pktlog) {
6808 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6809 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6810 return -EINVAL;
6811 }
6812
6813 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
6814 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
6815 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
6816 return -EINVAL;
6817 }
6818
6819 dhdp->pktlog->tx_pktlog_ring->start = FALSE;
6820 dhdp->pktlog->rx_pktlog_ring->start = FALSE;
6821
6822 bytes_written = snprintf(command, total_len, "OK");
6823
6824 DHD_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
6825
6826 return bytes_written;
6827 }
6828
6829 static int
6830 wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
6831 {
6832 int bytes_written = 0;
6833 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6834 dhd_pktlog_filter_t *filter;
6835 uint32 id;
6836 bool exist = FALSE;
6837
6838 if (!dhdp || !dhdp->pktlog) {
6839 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6840 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6841 return -EINVAL;
6842 }
6843
6844 filter = dhdp->pktlog->pktlog_filter;
6845
6846 if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
6847 return BCME_ERROR;
6848 }
6849
6850 exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
6851 &id);
6852
6853 if (exist) {
6854 bytes_written = snprintf(command, total_len, "TRUE");
6855 DHD_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
6856 } else {
6857 bytes_written = snprintf(command, total_len, "FALSE");
6858 DHD_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
6859 }
6860
6861 return bytes_written;
6862 }
6863
6864 static int
6865 wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int total_len)
6866 {
6867 int bytes_written = 0;
6868 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6869
6870 if (!dhdp || !dhdp->pktlog) {
6871 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6872 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6873 return -EINVAL;
6874 }
6875
6876 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
6877 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
6878 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
6879 return -EINVAL;
6880 }
6881
6882 dhdp->pktlog->tx_pktlog_ring->pktlog_minmize = TRUE;
6883 dhdp->pktlog->rx_pktlog_ring->pktlog_minmize = TRUE;
6884
6885 bytes_written = snprintf(command, total_len, "OK");
6886
6887 DHD_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__));
6888
6889 return bytes_written;
6890 }
6891
6892 static int
6893 wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int total_len)
6894 {
6895 int bytes_written = 0;
6896 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6897
6898 if (!dhdp || !dhdp->pktlog) {
6899 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6900 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6901 return -EINVAL;
6902 }
6903
6904 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
6905 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
6906 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
6907 return -EINVAL;
6908 }
6909
6910 dhdp->pktlog->tx_pktlog_ring->pktlog_minmize = FALSE;
6911 dhdp->pktlog->rx_pktlog_ring->pktlog_minmize = FALSE;
6912
6913 bytes_written = snprintf(command, total_len, "OK");
6914
6915 DHD_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__));
6916
6917 return bytes_written;
6918 }
6919
6920 static int
6921 wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_len)
6922 {
6923 int bytes_written = 0;
6924 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6925 int err = BCME_OK;
6926 int size;
6927
6928 if (!dhdp || !dhdp->pktlog) {
6929 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6930 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6931 return -EINVAL;
6932 }
6933
6934 if (strlen(CMD_PKTLOG_CHANGE_SIZE) + 1 > total_len) {
6935 return BCME_ERROR;
6936 }
6937
6938 size = bcm_strtoul(command + strlen(CMD_PKTLOG_CHANGE_SIZE) + 1, NULL, 0);
6939
6940 dhdp->pktlog->tx_pktlog_ring =
6941 dhd_pktlog_ring_change_size(dhdp->pktlog->tx_pktlog_ring, size);
6942 if (!dhdp->pktlog->tx_pktlog_ring) {
6943 err = BCME_ERROR;
6944 }
6945
6946 dhdp->pktlog->rx_pktlog_ring =
6947 dhd_pktlog_ring_change_size(dhdp->pktlog->rx_pktlog_ring, size);
6948 if (!dhdp->pktlog->tx_pktlog_ring) {
6949 err = BCME_ERROR;
6950 }
6951
6952 if (err == BCME_OK) {
6953 bytes_written = snprintf(command, total_len, "OK");
6954 DHD_ERROR(("%s: pktlog change size success\n", __FUNCTION__));
6955 } else {
6956 DHD_ERROR(("%s: pktlog change size fail\n", __FUNCTION__));
6957 return BCME_ERROR;
6958 }
6959
6960 return bytes_written;
6961 }
6962 #endif /* DHD_PKT_LOGGING */
6963
6964 #ifdef DHD_EVENT_LOG_FILTER
6965 uint32 dhd_event_log_filter_serialize(dhd_pub_t *dhdp, char *buf, uint32 tot_len, int type);
6966 static int
6967 wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len)
6968 {
6969 uint32 bytes_written = 0;
6970 int type = 0;
6971 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6972
6973 if (!dhdp || !command) {
6974 DHD_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp));
6975 return -EINVAL;
6976 }
6977
6978 /* NEED TO GET TYPE if EXIST */
6979 type = 0;
6980
6981 bytes_written += dhd_event_log_filter_serialize(dhdp,
6982 &command[bytes_written], tot_len - bytes_written, type);
6983
6984 return (int)bytes_written;
6985 }
6986 #endif /* DHD_EVENT_LOG_FILTER */
6987
6988 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
6989 {
6990 #define PRIVATE_COMMAND_MAX_LEN 8192
6991 #define PRIVATE_COMMAND_DEF_LEN 4096
6992 int ret = 0;
6993 char *command = NULL;
6994 int bytes_written = 0;
6995 android_wifi_priv_cmd priv_cmd;
6996 int buf_size = 0;
6997 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
6998
6999 net_os_wake_lock(net);
7000
7001 if (!capable(CAP_NET_ADMIN)) {
7002 ret = -EPERM;
7003 goto exit;
7004 }
7005
7006 if (!ifr->ifr_data) {
7007 ret = -EINVAL;
7008 goto exit;
7009 }
7010
7011 #ifdef CONFIG_COMPAT
7012 if (is_compat_task()) {
7013 compat_android_wifi_priv_cmd compat_priv_cmd;
7014 if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
7015 sizeof(compat_android_wifi_priv_cmd))) {
7016 ret = -EFAULT;
7017 goto exit;
7018
7019 }
7020 priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
7021 priv_cmd.used_len = compat_priv_cmd.used_len;
7022 priv_cmd.total_len = compat_priv_cmd.total_len;
7023 } else
7024 #endif /* CONFIG_COMPAT */
7025 {
7026 if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
7027 ret = -EFAULT;
7028 goto exit;
7029 }
7030 }
7031 if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
7032 DHD_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__,
7033 priv_cmd.total_len));
7034 ret = -EINVAL;
7035 goto exit;
7036 }
7037
7038 buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
7039 command = (char *)MALLOC(cfg->osh, (buf_size + 1));
7040 if (!command) {
7041 DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
7042 ret = -ENOMEM;
7043 goto exit;
7044 }
7045 if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
7046 ret = -EFAULT;
7047 goto exit;
7048 }
7049 command[priv_cmd.total_len] = '\0';
7050
7051 DHD_ERROR(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
7052
7053 bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
7054 if (bytes_written >= 0) {
7055 if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
7056 command[0] = '\0';
7057 }
7058 if (bytes_written >= priv_cmd.total_len) {
7059 DHD_ERROR(("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n",
7060 __FUNCTION__, bytes_written, priv_cmd.total_len, buf_size));
7061
7062 ret = BCME_BUFTOOSHORT;
7063 goto exit;
7064 }
7065 bytes_written++;
7066 priv_cmd.used_len = bytes_written;
7067 if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
7068 DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
7069 ret = -EFAULT;
7070 }
7071 }
7072 else {
7073 /* Propagate the error */
7074 ret = bytes_written;
7075 }
7076
7077 exit:
7078 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
7079 if (ret) {
7080 /* Avoid incrementing priv_cmd_errors in case of unsupported feature */
7081 if (ret != BCME_UNSUPPORTED) {
7082 wl_android_check_priv_cmd_errors(net);
7083 }
7084 } else {
7085 priv_cmd_errors = 0;
7086 }
7087 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
7088 net_os_wake_unlock(net);
7089 MFREE(cfg->osh, command, (buf_size + 1));
7090 return ret;
7091 }
7092 #ifdef WLADPS_PRIVATE_CMD
7093 static int
7094 wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
7095 {
7096 int err = 0, adps_mode;
7097 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7098 #ifdef DHD_PM_CONTROL_FROM_FILE
7099 if (g_pm_control) {
7100 return -EPERM;
7101 }
7102 #endif /* DHD_PM_CONTROL_FROM_FILE */
7103
7104 adps_mode = bcm_atoi(string_num);
7105 WL_ERR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode));
7106
7107 if ((adps_mode < 0) && (1 < adps_mode)) {
7108 WL_ERR(("%s: Invalid value %d.\n", __FUNCTION__, adps_mode));
7109 return -EINVAL;
7110 }
7111
7112 err = dhd_enable_adps(dhdp, adps_mode);
7113 if (err != BCME_OK) {
7114 WL_ERR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
7115 return -EIO;
7116 }
7117 return err;
7118 }
7119 static int
7120 wl_android_get_adps_mode(
7121 struct net_device *dev, char *command, int total_len)
7122 {
7123 int bytes_written, err = 0;
7124 int len;
7125 char buf[WLC_IOCTL_SMLEN];
7126
7127 bcm_iov_buf_t iov_buf;
7128 bcm_iov_buf_t *ptr = NULL;
7129 wl_adps_params_v1_t *data = NULL;
7130
7131 uint8 *pdata = NULL;
7132 uint8 band, mode = 0;
7133
7134 memset(&iov_buf, 0, sizeof(iov_buf));
7135
7136 len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
7137
7138 iov_buf.version = WL_ADPS_IOV_VER;
7139 iov_buf.len = sizeof(band);
7140 iov_buf.id = WL_ADPS_IOV_MODE;
7141
7142 pdata = (uint8 *)&iov_buf.data;
7143
7144 for (band = 1; band <= MAX_BANDS; band++) {
7145 pdata[0] = band;
7146 err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
7147 buf, WLC_IOCTL_SMLEN, NULL);
7148 if (err != BCME_OK) {
7149 WL_ERR(("%s fail to get adps band %d(%d).\n",
7150 __FUNCTION__, band, err));
7151 return -EIO;
7152 }
7153 ptr = (bcm_iov_buf_t *) buf;
7154 data = (wl_adps_params_v1_t *) ptr->data;
7155 mode = data->mode;
7156 if (mode != OFF) {
7157 break;
7158 }
7159 }
7160
7161 bytes_written = snprintf(command, total_len, "%s %d",
7162 CMD_GET_ADPS, mode);
7163 return bytes_written;
7164 }
7165 #endif /* WLADPS_PRIVATE_CMD */
7166
7167 #ifdef WL_BCNRECV
7168 #define BCNRECV_ATTR_HDR_LEN 30
7169 int
7170 wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type,
7171 uint status, uint reason, uint8 *data, uint data_len)
7172 {
7173 s32 err = BCME_OK;
7174 struct sk_buff *skb;
7175 gfp_t kflags;
7176 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
7177 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
7178 uint len;
7179
7180 len = BCNRECV_ATTR_HDR_LEN + data_len;
7181
7182 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
7183 skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len,
7184 BRCM_VENDOR_EVENT_BEACON_RECV, kflags);
7185 if (!skb) {
7186 WL_ERR(("skb alloc failed"));
7187 return -ENOMEM;
7188 }
7189 if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) {
7190 /* send bcn info to upper layer */
7191 nla_put(skb, BCNRECV_ATTR_BCNINFO, data_len, data);
7192 } else if (attr_type == BCNRECV_ATTR_STATUS) {
7193 nla_put_u32(skb, BCNRECV_ATTR_STATUS, status);
7194 if (reason) {
7195 nla_put_u32(skb, BCNRECV_ATTR_REASON, reason);
7196 }
7197 } else {
7198 WL_ERR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type));
7199 kfree_skb(skb);
7200 return -EINVAL;
7201 }
7202 cfg80211_vendor_event(skb, kflags);
7203 return err;
7204 }
7205
7206 static int
7207 _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool user_trigger)
7208 {
7209 s32 err = BCME_OK;
7210
7211 /* check any scan is in progress before beacon recv scan trigger IOVAR */
7212 if (wl_get_drv_status_all(cfg, SCANNING)) {
7213 err = BCME_UNSUPPORTED;
7214 WL_ERR(("Scan in progress, Aborting beacon recv start, "
7215 "error:%d\n", err));
7216 goto exit;
7217 }
7218
7219 if (wl_get_p2p_status(cfg, SCANNING)) {
7220 err = BCME_UNSUPPORTED;
7221 WL_ERR(("P2P Scan in progress, Aborting beacon recv start, "
7222 "error:%d\n", err));
7223 goto exit;
7224 }
7225
7226 if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) {
7227 err = BCME_UNSUPPORTED;
7228 WL_ERR(("P2P remain on channel, Aborting beacon recv start, "
7229 "error:%d\n", err));
7230 goto exit;
7231 }
7232
7233 /* check STA is in connected state, Beacon recv required connected state
7234 * else exit from beacon recv scan
7235 */
7236 if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
7237 err = BCME_UNSUPPORTED;
7238 WL_ERR(("STA is in not associated state error:%d\n", err));
7239 goto exit;
7240 }
7241
7242 #ifdef WL_NAN
7243 /* Check NAN is enabled, if enabled exit else continue */
7244 if (wl_cfgnan_check_state(cfg)) {
7245 err = BCME_UNSUPPORTED;
7246 WL_ERR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n"));
7247 goto exit;
7248 }
7249 #endif /* WL_NAN */
7250
7251 /* Triggering an sendup_bcn iovar */
7252 err = wldev_iovar_setint(ndev, "sendup_bcn", 1);
7253 if (unlikely(err)) {
7254 WL_ERR(("sendup_bcn failed to set, error:%d\n", err));
7255 } else {
7256 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED;
7257 WL_INFORM_MEM(("bcnrecv started\n"));
7258 if (user_trigger) {
7259 WL_INFORM_MEM(("BCN-RECV-STARTED"));
7260 if ((err = wl_android_bcnrecv_event(ndev, BCNRECV_ATTR_STATUS,
7261 WL_BCNRECV_STARTED, 0, NULL, 0)) != BCME_OK) {
7262 WL_ERR(("failed to send bcnrecv event, error:%d\n", err));
7263 }
7264 }
7265 }
7266 exit:
7267 /*
7268 * BCNRECV start request can be rejected from dongle
7269 * in various conditions.
7270 * Error code need to be overridden to BCME_UNSUPPORTED
7271 * to avoid hang event from continous private
7272 * command error
7273 */
7274 if (err) {
7275 err = BCME_UNSUPPORTED;
7276 }
7277 return err;
7278 }
7279
7280 int
7281 _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint reason)
7282 {
7283 s32 err = BCME_OK;
7284 u32 status;
7285
7286 /* Send sendup_bcn iovar for all cases except W_BCNRECV_ROAMABORT reason -
7287 * fw generates roam abort event after aborting the bcnrecv.
7288 */
7289 if (reason != WL_BCNRECV_ROAMABORT) {
7290 /* Triggering an sendup_bcn iovar */
7291 err = wldev_iovar_setint(ndev, "sendup_bcn", 0);
7292 if (unlikely(err)) {
7293 WL_ERR(("sendup_bcn failed to set error:%d\n", err));
7294 goto exit;
7295 }
7296 }
7297
7298 /* Send notification for all cases */
7299 if (reason == WL_BCNRECV_SUSPEND) {
7300 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED;
7301 status = WL_BCNRECV_SUSPENDED;
7302 } else {
7303 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED;
7304 WL_INFORM_MEM(("bcnrecv stopped\n"));
7305 if (reason == WL_BCNRECV_USER_TRIGGER) {
7306 status = WL_BCNRECV_STOPPED;
7307 } else {
7308 status = WL_BCNRECV_ABORTED;
7309 }
7310 }
7311 if ((err = wl_android_bcnrecv_event(ndev, BCNRECV_ATTR_STATUS, status,
7312 reason, NULL, 0)) != BCME_OK) {
7313 WL_ERR(("failed to send bcnrecv event, error:%d\n", err));
7314 }
7315 exit:
7316 return err;
7317 }
7318
7319 static int
7320 wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev)
7321 {
7322 s32 err = BCME_OK;
7323
7324 /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
7325 mutex_lock(&cfg->scan_sync);
7326 mutex_lock(&cfg->bcn_sync);
7327 err = _wl_android_bcnrecv_start(cfg, ndev, true);
7328 mutex_unlock(&cfg->bcn_sync);
7329 mutex_unlock(&cfg->scan_sync);
7330 return err;
7331 }
7332
7333 int
7334 wl_android_bcnrecv_stop(struct net_device *ndev, uint reason)
7335 {
7336 s32 err = BCME_OK;
7337 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
7338
7339 mutex_lock(&cfg->bcn_sync);
7340 if ((cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) ||
7341 (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED)) {
7342 err = _wl_android_bcnrecv_stop(cfg, ndev, reason);
7343 }
7344 mutex_unlock(&cfg->bcn_sync);
7345 return err;
7346 }
7347
7348 int
7349 wl_android_bcnrecv_suspend(struct net_device *ndev)
7350 {
7351 s32 ret = BCME_OK;
7352 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
7353
7354 mutex_lock(&cfg->bcn_sync);
7355 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
7356 WL_INFORM_MEM(("bcnrecv suspend\n"));
7357 ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND);
7358 }
7359 mutex_unlock(&cfg->bcn_sync);
7360 return ret;
7361 }
7362
7363 int
7364 wl_android_bcnrecv_resume(struct net_device *ndev)
7365 {
7366 s32 ret = BCME_OK;
7367 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
7368
7369 /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
7370 mutex_lock(&cfg->scan_sync);
7371 mutex_lock(&cfg->bcn_sync);
7372 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) {
7373 WL_INFORM_MEM(("bcnrecv resume\n"));
7374 ret = _wl_android_bcnrecv_start(cfg, ndev, false);
7375 }
7376 mutex_unlock(&cfg->bcn_sync);
7377 mutex_unlock(&cfg->scan_sync);
7378 return ret;
7379 }
7380
7381 /* Beacon recv functionality code implementation */
7382 int
7383 wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv, int total_len)
7384 {
7385 struct bcm_cfg80211 *cfg = NULL;
7386 uint err = BCME_OK;
7387
7388 if (!ndev) {
7389 WL_ERR(("ndev is NULL\n"));
7390 return -EINVAL;
7391 }
7392
7393 cfg = wl_get_cfg(ndev);
7394 if (!cfg) {
7395 WL_ERR(("cfg is NULL\n"));
7396 return -EINVAL;
7397 }
7398
7399 /* sync commands from user space */
7400 mutex_lock(&cfg->usr_sync);
7401 if (strncmp(cmd_argv, "start", strlen("start")) == 0) {
7402 WL_INFORM(("BCNRECV start\n"));
7403 err = wl_android_bcnrecv_start(cfg, ndev);
7404 if (err != BCME_OK) {
7405 WL_ERR(("Failed to process the start command, error:%d\n", err));
7406 goto exit;
7407 }
7408 } else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) {
7409 WL_INFORM(("BCNRECV stop\n"));
7410 err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER);
7411 if (err != BCME_OK) {
7412 WL_ERR(("Failed to stop the bcn recv, error:%d\n", err));
7413 goto exit;
7414 }
7415 } else {
7416 err = BCME_ERROR;
7417 }
7418 exit:
7419 mutex_unlock(&cfg->usr_sync);
7420 return err;
7421 }
7422 #endif /* WL_BCNRECV */
7423
7424 int
7425 wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
7426 {
7427 int bytes_written = 0;
7428 android_wifi_priv_cmd priv_cmd;
7429
7430 bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
7431 priv_cmd.total_len = cmd_len;
7432
7433 if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
7434 DHD_INFO(("%s, Received regular START command\n", __FUNCTION__));
7435 #ifdef SUPPORT_DEEP_SLEEP
7436 trigger_deep_sleep = 1;
7437 #else
7438 #ifdef BT_OVER_SDIO
7439 bytes_written = dhd_net_bus_get(net);
7440 #else
7441 bytes_written = wl_android_wifi_on(net);
7442 #endif /* BT_OVER_SDIO */
7443 #endif /* SUPPORT_DEEP_SLEEP */
7444 }
7445 else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
7446 bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
7447 }
7448
7449 if (!g_wifi_on) {
7450 DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
7451 __FUNCTION__, command));
7452 return 0;
7453 }
7454
7455 if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
7456 #ifdef SUPPORT_DEEP_SLEEP
7457 trigger_deep_sleep = 1;
7458 #else
7459 #ifdef BT_OVER_SDIO
7460 bytes_written = dhd_net_bus_put(net);
7461 #else
7462 bytes_written = wl_android_wifi_off(net, FALSE);
7463 #endif /* BT_OVER_SDIO */
7464 #endif /* SUPPORT_DEEP_SLEEP */
7465 }
7466 else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
7467 wl_cfg80211_set_passive_scan(net, command);
7468 }
7469 else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
7470 wl_cfg80211_set_passive_scan(net, command);
7471 }
7472 else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
7473 bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
7474 }
7475 else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
7476 bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
7477 }
7478 #ifdef PKT_FILTER_SUPPORT
7479 else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
7480 bytes_written = net_os_enable_packet_filter(net, 1);
7481 }
7482 else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
7483 bytes_written = net_os_enable_packet_filter(net, 0);
7484 }
7485 else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
7486 int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
7487 bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
7488 }
7489 else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
7490 int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
7491 bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
7492 }
7493 #endif /* PKT_FILTER_SUPPORT */
7494 else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
7495 /* TBD: BTCOEXSCAN-START */
7496 }
7497 else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
7498 /* TBD: BTCOEXSCAN-STOP */
7499 }
7500 else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
7501 #ifdef WL_CFG80211
7502 void *dhdp = wl_cfg80211_get_dhdp(net);
7503 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
7504 #else
7505 #ifdef PKT_FILTER_SUPPORT
7506 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
7507
7508 if (mode == 1)
7509 net_os_enable_packet_filter(net, 0); /* DHCP starts */
7510 else
7511 net_os_enable_packet_filter(net, 1); /* DHCP ends */
7512 #endif /* PKT_FILTER_SUPPORT */
7513 #endif /* WL_CFG80211 */
7514 }
7515 else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
7516 bytes_written = wl_android_set_suspendopt(net, command);
7517 }
7518 else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
7519 bytes_written = wl_android_set_suspendmode(net, command);
7520 }
7521 else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND, strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
7522 bytes_written = wl_android_set_bcn_li_dtim(net, command);
7523 }
7524 else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
7525 bytes_written = wl_android_set_max_dtim(net, command);
7526 }
7527 else if (strnicmp(command, CMD_DISDTIM_IN_SUSPEND, strlen(CMD_DISDTIM_IN_SUSPEND)) == 0) {
7528 bytes_written = wl_android_set_disable_dtim_in_suspend(net, command);
7529 }
7530 else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
7531 bytes_written = wl_android_set_band(net, command);
7532 }
7533 else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
7534 bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
7535 }
7536 #ifdef WL_CFG80211
7537 #ifndef CUSTOMER_SET_COUNTRY
7538 /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
7539 else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
7540 /*
7541 * Usage examples:
7542 * DRIVER COUNTRY US
7543 * DRIVER COUNTRY US/7
7544 */
7545 char *country_code = command + strlen(CMD_COUNTRY) + 1;
7546 char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
7547 int revinfo = -1;
7548 struct wireless_dev *wdev = ndev_to_wdev(net);
7549 struct wiphy *wiphy = wdev->wiphy;
7550 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
7551
7552 BCM_REFERENCE(dhdp);
7553 if (CHECK_IS_BLOB(dhdp) && !CHECK_IS_MULT_REGREV(dhdp)) {
7554 revinfo = 0;
7555 } else if ((rev_info_delim) &&
7556 (strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
7557 strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
7558 (rev_info_delim + 1)) {
7559 revinfo = bcm_atoi(rev_info_delim + 1);
7560 }
7561
7562 if (wl_check_dongle_idle(wiphy) != TRUE) {
7563 DHD_ERROR(("FW is busy to check dongle idle\n"));
7564 return 0;
7565 }
7566
7567 bytes_written = wldev_set_country(net, country_code, true, true, revinfo);
7568 #ifdef CUSTOMER_HW4_PRIVATE_CMD
7569 #ifdef FCC_PWR_LIMIT_2G
7570 if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
7571 DHD_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
7572 } else {
7573 DHD_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
7574 }
7575 #endif /* FCC_PWR_LIMIT_2G */
7576 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7577 }
7578 #endif /* CUSTOMER_SET_COUNTRY */
7579 #endif /* WL_CFG80211 */
7580 else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
7581 bytes_written = wl_android_set_csa(net, command);
7582 } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
7583 bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
7584 } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
7585 bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
7586 } else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
7587 bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
7588 } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) {
7589 bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
7590 }
7591
7592 #ifdef CUSTOMER_HW4_PRIVATE_CMD
7593 #ifdef ROAM_API
7594 else if (strnicmp(command, CMD_ROAMTRIGGER_SET,
7595 strlen(CMD_ROAMTRIGGER_SET)) == 0) {
7596 bytes_written = wl_android_set_roam_trigger(net, command);
7597 } else if (strnicmp(command, CMD_ROAMTRIGGER_GET,
7598 strlen(CMD_ROAMTRIGGER_GET)) == 0) {
7599 bytes_written = wl_android_get_roam_trigger(net, command,
7600 priv_cmd.total_len);
7601 } else if (strnicmp(command, CMD_ROAMDELTA_SET,
7602 strlen(CMD_ROAMDELTA_SET)) == 0) {
7603 bytes_written = wl_android_set_roam_delta(net, command);
7604 } else if (strnicmp(command, CMD_ROAMDELTA_GET,
7605 strlen(CMD_ROAMDELTA_GET)) == 0) {
7606 bytes_written = wl_android_get_roam_delta(net, command,
7607 priv_cmd.total_len);
7608 } else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET,
7609 strlen(CMD_ROAMSCANPERIOD_SET)) == 0) {
7610 bytes_written = wl_android_set_roam_scan_period(net, command);
7611 } else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET,
7612 strlen(CMD_ROAMSCANPERIOD_GET)) == 0) {
7613 bytes_written = wl_android_get_roam_scan_period(net, command,
7614 priv_cmd.total_len);
7615 } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET,
7616 strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) {
7617 bytes_written = wl_android_set_full_roam_scan_period(net, command,
7618 priv_cmd.total_len);
7619 } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET,
7620 strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) {
7621 bytes_written = wl_android_get_full_roam_scan_period(net, command,
7622 priv_cmd.total_len);
7623 } else if (strnicmp(command, CMD_COUNTRYREV_SET,
7624 strlen(CMD_COUNTRYREV_SET)) == 0) {
7625 bytes_written = wl_android_set_country_rev(net, command);
7626 #ifdef FCC_PWR_LIMIT_2G
7627 if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
7628 DHD_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
7629 } else {
7630 DHD_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
7631 }
7632 #endif /* FCC_PWR_LIMIT_2G */
7633 } else if (strnicmp(command, CMD_COUNTRYREV_GET,
7634 strlen(CMD_COUNTRYREV_GET)) == 0) {
7635 bytes_written = wl_android_get_country_rev(net, command,
7636 priv_cmd.total_len);
7637 }
7638 #endif /* ROAM_API */
7639 #ifdef WES_SUPPORT
7640 else if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) {
7641 bytes_written = wl_android_get_roam_scan_control(net, command, priv_cmd.total_len);
7642 }
7643 else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) {
7644 bytes_written = wl_android_set_roam_scan_control(net, command);
7645 }
7646 else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) {
7647 bytes_written = wl_android_get_roam_scan_channels(net, command, priv_cmd.total_len);
7648 }
7649 else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) {
7650 bytes_written = wl_android_set_roam_scan_channels(net, command);
7651 }
7652 else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) {
7653 bytes_written = wl_android_send_action_frame(net, command, priv_cmd.total_len);
7654 }
7655 else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) {
7656 bytes_written = wl_android_reassoc(net, command, priv_cmd.total_len);
7657 }
7658 else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) {
7659 bytes_written = wl_android_get_scan_channel_time(net, command, priv_cmd.total_len);
7660 }
7661 else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) {
7662 bytes_written = wl_android_set_scan_channel_time(net, command);
7663 }
7664 else if (strnicmp(command, CMD_GETSCANUNASSOCTIME, strlen(CMD_GETSCANUNASSOCTIME)) == 0) {
7665 bytes_written = wl_android_get_scan_unassoc_time(net, command, priv_cmd.total_len);
7666 }
7667 else if (strnicmp(command, CMD_SETSCANUNASSOCTIME, strlen(CMD_SETSCANUNASSOCTIME)) == 0) {
7668 bytes_written = wl_android_set_scan_unassoc_time(net, command);
7669 }
7670 else if (strnicmp(command, CMD_GETSCANPASSIVETIME, strlen(CMD_GETSCANPASSIVETIME)) == 0) {
7671 bytes_written = wl_android_get_scan_passive_time(net, command, priv_cmd.total_len);
7672 }
7673 else if (strnicmp(command, CMD_SETSCANPASSIVETIME, strlen(CMD_SETSCANPASSIVETIME)) == 0) {
7674 bytes_written = wl_android_set_scan_passive_time(net, command);
7675 }
7676 else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) {
7677 bytes_written = wl_android_get_scan_home_time(net, command, priv_cmd.total_len);
7678 }
7679 else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) {
7680 bytes_written = wl_android_set_scan_home_time(net, command);
7681 }
7682 else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) {
7683 bytes_written = wl_android_get_scan_home_away_time(net, command,
7684 priv_cmd.total_len);
7685 }
7686 else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) {
7687 bytes_written = wl_android_set_scan_home_away_time(net, command);
7688 }
7689 else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) {
7690 bytes_written = wl_android_get_scan_nprobes(net, command, priv_cmd.total_len);
7691 }
7692 else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) {
7693 bytes_written = wl_android_set_scan_nprobes(net, command);
7694 }
7695 else if (strnicmp(command, CMD_GETDFSSCANMODE, strlen(CMD_GETDFSSCANMODE)) == 0) {
7696 bytes_written = wl_android_get_scan_dfs_channel_mode(net, command,
7697 priv_cmd.total_len);
7698 }
7699 else if (strnicmp(command, CMD_SETDFSSCANMODE, strlen(CMD_SETDFSSCANMODE)) == 0) {
7700 bytes_written = wl_android_set_scan_dfs_channel_mode(net, command);
7701 }
7702 else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) {
7703 bytes_written = wl_android_set_join_prefer(net, command);
7704 }
7705 else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) {
7706 bytes_written = wl_android_get_wes_mode(net, command, priv_cmd.total_len);
7707 }
7708 else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) {
7709 bytes_written = wl_android_set_wes_mode(net, command);
7710 }
7711 else if (strnicmp(command, CMD_GETOKCMODE, strlen(CMD_GETOKCMODE)) == 0) {
7712 bytes_written = wl_android_get_okc_mode(net, command, priv_cmd.total_len);
7713 }
7714 else if (strnicmp(command, CMD_SETOKCMODE, strlen(CMD_SETOKCMODE)) == 0) {
7715 bytes_written = wl_android_set_okc_mode(net, command);
7716 }
7717 else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) {
7718 bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
7719 }
7720 else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) {
7721 bytes_written = wl_android_okc_enable(net, command);
7722 }
7723 #endif /* WES_SUPPORT */
7724 #ifdef SUPPORT_RESTORE_SCAN_PARAMS
7725 else if (strnicmp(command, CMD_RESTORE_SCAN_PARAMS, strlen(CMD_RESTORE_SCAN_PARAMS)) == 0) {
7726 bytes_written = wl_android_restore_scan_params(net, command, priv_cmd.total_len);
7727 }
7728 #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
7729 #ifdef WLTDLS
7730 else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
7731 bytes_written = wl_android_tdls_reset(net);
7732 }
7733 #endif /* WLTDLS */
7734 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7735
7736 #ifdef PNO_SUPPORT
7737 else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
7738 #if defined(SUPPORT_RANDOM_MAC_SCAN)
7739 wl_cfg80211_set_random_mac(net, FALSE);
7740 #endif /* SUPPORT_RANDOM_MAC_SCAN */
7741 bytes_written = dhd_dev_pno_stop_for_ssid(net);
7742 }
7743 #ifndef WL_SCHED_SCAN
7744 else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
7745 #if defined(SUPPORT_RANDOM_MAC_SCAN)
7746 int res = BCME_ERROR;
7747 res = wl_cfg80211_set_random_mac(net, TRUE);
7748 if (res < 0 && res != BCME_UNSUPPORTED) {
7749 DHD_ERROR(("%s : failed to set random mac for PNO scan, %d\n",
7750 __FUNCTION__, res));
7751 }
7752 #endif /* SUPPORT_RANDOM_MAC_SCAN */
7753 bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
7754 }
7755 #endif /* !WL_SCHED_SCAN */
7756 else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
7757 int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
7758 bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
7759 }
7760 else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
7761 bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
7762 }
7763 #endif /* PNO_SUPPORT */
7764 else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
7765 bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
7766 }
7767 else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
7768 int skip = strlen(CMD_P2P_SET_NOA) + 1;
7769 bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
7770 priv_cmd.total_len - skip);
7771 }
7772 #ifdef P2P_LISTEN_OFFLOADING
7773 else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
7774 u8 *sub_command = strchr(command, ' ');
7775 bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
7776 sub_command ? strlen(sub_command) : 0);
7777 }
7778 #endif /* P2P_LISTEN_OFFLOADING */
7779 #if !defined WL_ENABLE_P2P_IF
7780 else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
7781 bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
7782 }
7783 #endif /* WL_ENABLE_P2P_IF */
7784 else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
7785 int skip = strlen(CMD_P2P_SET_PS) + 1;
7786 bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
7787 priv_cmd.total_len - skip);
7788 }
7789 else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
7790 int skip = strlen(CMD_P2P_ECSA) + 1;
7791 bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
7792 priv_cmd.total_len - skip);
7793 }
7794 else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
7795 int skip = strlen(CMD_P2P_INC_BW) + 1;
7796 bytes_written = wl_cfg80211_increase_p2p_bw(net,
7797 command + skip, priv_cmd.total_len - skip);
7798 }
7799 #ifdef WL_CFG80211
7800 else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
7801 strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
7802 int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
7803 bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
7804 priv_cmd.total_len - skip, *(command + skip - 2) - '0');
7805 }
7806 #ifdef WLFBT
7807 else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
7808 bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
7809 }
7810 #endif /* WLFBT */
7811 #endif /* WL_CFG80211 */
7812 #ifdef BCMCCX
7813 else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) {
7814 bytes_written = wl_android_get_cckm_rn(net, command);
7815 }
7816 else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) {
7817 bytes_written = wl_android_set_cckm_krk(net, command, priv_cmd.total_len);
7818 }
7819 else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) {
7820 bytes_written = wl_android_get_assoc_res_ies(net, command, priv_cmd.total_len);
7821 }
7822 #endif /* BCMCCX */
7823 #if defined(WL_SUPPORT_AUTO_CHANNEL)
7824 else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
7825 strlen(CMD_GET_BEST_CHANNELS)) == 0) {
7826 bytes_written = wl_cfg80211_get_best_channels(net, command,
7827 priv_cmd.total_len);
7828 }
7829 #endif /* WL_SUPPORT_AUTO_CHANNEL */
7830 #if defined(WL_SUPPORT_AUTO_CHANNEL)
7831 else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
7832 strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
7833 int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
7834 bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
7835 priv_cmd.total_len);
7836 }
7837 #endif /* WL_SUPPORT_AUTO_CHANNEL */
7838 #ifdef CUSTOMER_HW4_PRIVATE_CMD
7839 #ifdef SUPPORT_AMPDU_MPDU_CMD
7840 /* CMD_AMPDU_MPDU */
7841 else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
7842 int skip = strlen(CMD_AMPDU_MPDU) + 1;
7843 bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
7844 }
7845 #endif /* SUPPORT_AMPDU_MPDU_CMD */
7846 #if defined(SUPPORT_HIDDEN_AP)
7847 else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
7848 strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
7849 int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
7850 wl_android_set_max_num_sta(net, (const char*)command+skip);
7851 }
7852 else if (strnicmp(command, CMD_SET_HAPD_SSID,
7853 strlen(CMD_SET_HAPD_SSID)) == 0) {
7854 int skip = strlen(CMD_SET_HAPD_SSID) + 3;
7855 wl_android_set_ssid(net, (const char*)command+skip);
7856 }
7857 else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
7858 strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
7859 int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3;
7860 wl_android_set_hide_ssid(net, (const char*)command+skip);
7861 }
7862 #endif /* SUPPORT_HIDDEN_AP */
7863 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
7864 else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
7865 strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
7866 int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
7867 wl_android_sta_diassoc(net, (const char*)command+skip);
7868 }
7869 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
7870 #ifdef SUPPORT_SET_LPC
7871 else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
7872 strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
7873 int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
7874 wl_android_set_lpc(net, (const char*)command+skip);
7875 }
7876 #endif /* SUPPORT_SET_LPC */
7877 #ifdef SUPPORT_TRIGGER_HANG_EVENT
7878 else if (strnicmp(command, CMD_TEST_FORCE_HANG,
7879 strlen(CMD_TEST_FORCE_HANG)) == 0) {
7880 int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
7881 net_os_send_hang_message_reason(net, (const char*)command+skip);
7882 }
7883 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
7884 else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
7885 bytes_written = wl_android_ch_res_rl(net, true);
7886 else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
7887 bytes_written = wl_android_ch_res_rl(net, false);
7888 #ifdef SUPPORT_LTECX
7889 else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) {
7890 int skip = strlen(CMD_LTECX_SET) + 1;
7891 bytes_written = wl_android_set_ltecx(net, (const char*)command+skip);
7892 }
7893 #endif /* SUPPORT_LTECX */
7894 #ifdef WL_RELMCAST
7895 else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
7896 int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
7897 bytes_written = wl_android_rmc_enable(net, rmc_enable);
7898 }
7899 else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
7900 int rmc_txrate;
7901 sscanf(command, "%*s %10d", &rmc_txrate);
7902 bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
7903 }
7904 else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
7905 int actperiod;
7906 sscanf(command, "%*s %10d", &actperiod);
7907 bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
7908 }
7909 else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
7910 int acktimeout;
7911 sscanf(command, "%*s %10d", &acktimeout);
7912 acktimeout *= 1000;
7913 bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
7914 }
7915 else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
7916 int skip = strlen(CMD_SET_RMC_LEADER) + 1;
7917 bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
7918 }
7919 else if (strnicmp(command, CMD_SET_RMC_EVENT,
7920 strlen(CMD_SET_RMC_EVENT)) == 0) {
7921 bytes_written = wl_android_set_rmc_event(net, command);
7922 }
7923 #endif /* WL_RELMCAST */
7924 else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
7925 bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
7926 }
7927 else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
7928 bytes_written = wl_android_set_singlecore_scan(net, command);
7929 }
7930 #ifdef TEST_TX_POWER_CONTROL
7931 else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
7932 strlen(CMD_TEST_SET_TX_POWER)) == 0) {
7933 int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
7934 wl_android_set_tx_power(net, (const char*)command+skip);
7935 }
7936 else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
7937 strlen(CMD_TEST_GET_TX_POWER)) == 0) {
7938 wl_android_get_tx_power(net, command, priv_cmd.total_len);
7939 }
7940 #endif /* TEST_TX_POWER_CONTROL */
7941 else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
7942 strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
7943 int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
7944 wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
7945 }
7946 #ifdef SUPPORT_SET_TID
7947 else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) {
7948 bytes_written = wl_android_set_tid(net, command);
7949 }
7950 else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) {
7951 bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len);
7952 }
7953 #endif /* SUPPORT_SET_TID */
7954 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7955 else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
7956 int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
7957 wl_android_set_mac_address_filter(net, command+skip);
7958 }
7959 else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
7960 bytes_written = wl_android_set_roam_mode(net, command);
7961 #if defined(BCMFW_ROAM_ENABLE)
7962 else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
7963 bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
7964 }
7965 #endif /* BCMFW_ROAM_ENABLE */
7966 else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
7967 bytes_written = wl_android_set_miracast(net, command);
7968 else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
7969 bytes_written = wl_android_set_ibss_beacon_ouidata(net,
7970 command, priv_cmd.total_len);
7971 #ifdef WLAIBSS
7972 else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
7973 strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
7974 bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
7975 else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
7976 strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
7977 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
7978 TRUE);
7979 else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
7980 strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
7981 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
7982 FALSE);
7983 else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
7984 strlen(CMD_SETIBSSROUTETABLE)) == 0)
7985 bytes_written = wl_android_set_ibss_routetable(net, command);
7986 else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
7987 bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
7988 else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
7989 bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
7990 #endif /* WLAIBSS */
7991 else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
7992 int skip = strlen(CMD_KEEP_ALIVE) + 1;
7993 bytes_written = wl_keep_alive_set(net, command + skip);
7994 }
7995 else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
7996 int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
7997 bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
7998 }
7999 else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
8000 char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
8001 WL_INFORM(("Creating %s interface\n", name));
8002 if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA,
8003 name, NULL) == NULL) {
8004 bytes_written = -ENODEV;
8005 } else {
8006 /* Return success */
8007 bytes_written = 0;
8008 }
8009 }
8010 else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
8011 char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
8012 WL_INFORM(("Deleteing %s interface\n", name));
8013 bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
8014 }
8015 else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
8016 bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
8017 }
8018 #ifdef P2PRESP_WFDIE_SRC
8019 else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
8020 strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
8021 int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
8022 bytes_written = wl_android_set_wfdie_resp(net, mode);
8023 } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
8024 strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
8025 bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
8026 }
8027 #endif /* P2PRESP_WFDIE_SRC */
8028 else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
8029 char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
8030 bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
8031 }
8032 #ifdef WBTEXT
8033 else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
8034 bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
8035 }
8036 else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
8037 strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
8038 char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
8039 bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
8040 }
8041 else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
8042 strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
8043 char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
8044 bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
8045 command, priv_cmd.total_len);
8046 }
8047 else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
8048 strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
8049 char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
8050 bytes_written = wl_cfg80211_wbtext_table_config(net, data,
8051 command, priv_cmd.total_len);
8052 }
8053 else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
8054 strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
8055 char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
8056 bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
8057 command, priv_cmd.total_len);
8058 }
8059 else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
8060 strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
8061 bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
8062 priv_cmd.total_len);
8063 }
8064 else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
8065 strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
8066 bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
8067 priv_cmd.total_len);
8068 }
8069 #endif /* WBTEXT */
8070 #ifdef SET_RPS_CPUS
8071 else if (strnicmp(command, CMD_RPSMODE, strlen(CMD_RPSMODE)) == 0) {
8072 bytes_written = wl_android_set_rps_cpus(net, command);
8073 }
8074 #endif /* SET_RPS_CPUS */
8075 #ifdef WLWFDS
8076 else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
8077 bytes_written = wl_android_set_wfds_hash(net, command, 1);
8078 }
8079 else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
8080 bytes_written = wl_android_set_wfds_hash(net, command, 0);
8081 }
8082 #endif /* WLWFDS */
8083 #ifdef BT_WIFI_HANDOVER
8084 else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
8085 bytes_written = wl_tbow_teardown(net);
8086 }
8087 #endif /* BT_WIFI_HANDOVER */
8088 #ifdef CUSTOMER_HW4_PRIVATE_CMD
8089 #ifdef FCC_PWR_LIMIT_2G
8090 else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
8091 strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
8092 bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
8093 }
8094 else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
8095 strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
8096 bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command);
8097 }
8098 #endif /* FCC_PWR_LIMIT_2G */
8099 else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
8100 bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
8101 }
8102 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
8103 #ifdef DYNAMIC_MUMIMO_CONTROL
8104 else if (strnicmp(command, CMD_GET_MURX_BFE_CAP,
8105 strlen(CMD_GET_MURX_BFE_CAP)) == 0) {
8106 bytes_written = wl_android_get_murx_bfe_cap(net, command, priv_cmd.total_len);
8107 }
8108 else if (strnicmp(command, CMD_SET_MURX_BFE_CAP,
8109 strlen(CMD_SET_MURX_BFE_CAP)) == 0) {
8110 uint val = *(command + strlen(CMD_SET_MURX_BFE_CAP) + 1) - '0';
8111 bytes_written = wl_android_set_murx_bfe_cap(net, val);
8112 }
8113 else if (strnicmp(command, CMD_GET_BSS_SUPPORT_MUMIMO,
8114 strlen(CMD_GET_BSS_SUPPORT_MUMIMO)) == 0) {
8115 bytes_written = wl_android_get_bss_support_mumimo(net, command, priv_cmd.total_len);
8116 }
8117 #endif /* DYNAMIC_MUMIMO_CONTROL */
8118 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
8119 else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
8120 bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
8121 }
8122 else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
8123 bytes_written = wl_android_set_ap_beaconrate(net, command);
8124 }
8125 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
8126 #ifdef SUPPORT_AP_RADIO_PWRSAVE
8127 else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
8128 bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
8129 }
8130 else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
8131 bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
8132 }
8133 else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
8134 bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
8135 }
8136 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
8137 #ifdef SUPPORT_RSSI_SUM_REPORT
8138 else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
8139 bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
8140 }
8141 else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
8142 bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
8143 }
8144 else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
8145 bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
8146 }
8147 #endif /* SUPPORT_RSSI_SUM_REPORT */
8148 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
8149 else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
8150 bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
8151 }
8152 else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
8153 == 0) {
8154 bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
8155 priv_cmd.total_len);
8156 }
8157 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
8158 #if defined(SUPPORT_RANDOM_MAC_SCAN)
8159 else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
8160 bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
8161 } else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
8162 bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
8163 }
8164 #endif /* SUPPORT_RANDOM_MAC_SCAN */
8165 #ifdef WL_NATOE
8166 else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
8167 bytes_written = wl_android_process_natoe_cmd(net, command,
8168 priv_cmd.total_len);
8169 }
8170 #endif /* WL_NATOE */
8171 #ifdef CONNECTION_STATISTICS
8172 else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
8173 strlen(CMD_GET_CONNECTION_STATS)) == 0) {
8174 bytes_written = wl_android_get_connection_stats(net, command,
8175 priv_cmd.total_len);
8176 }
8177 #endif // endif
8178 #ifdef DHD_LOG_DUMP
8179 else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
8180 strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
8181 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
8182 /* check whether it has more command */
8183 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
8184 /* compare unwanted/disconnected command */
8185 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
8186 SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
8187 dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
8188 } else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
8189 SUBCMD_DISCONNECTED, strlen(SUBCMD_DISCONNECTED)) == 0) {
8190 dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
8191 } else {
8192 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
8193 }
8194 } else {
8195 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
8196 }
8197 }
8198 #endif /* DHD_LOG_DUMP */
8199 #ifdef SET_PCIE_IRQ_CPU_CORE
8200 else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
8201 int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
8202 wl_android_set_irq_cpucore(net, affinity_cmd);
8203 }
8204 #endif /* SET_PCIE_IRQ_CPU_CORE */
8205 #if defined(DHD_HANG_SEND_UP_TEST)
8206 else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
8207 int skip = strlen(CMD_MAKE_HANG) + 1;
8208 wl_android_make_hang_with_reason(net, (const char*)command+skip);
8209 }
8210 #endif /* DHD_HANG_SEND_UP_TEST */
8211 #ifdef SUPPORT_LQCM
8212 else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
8213 int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
8214 bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
8215 }
8216 else if (strnicmp(command, CMD_GET_LQCM_REPORT,
8217 strlen(CMD_GET_LQCM_REPORT)) == 0) {
8218 bytes_written = wl_android_get_lqcm_report(net, command,
8219 priv_cmd.total_len);
8220 }
8221 #endif // endif
8222 else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
8223 bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
8224 }
8225 #ifdef WLADPS_PRIVATE_CMD
8226 else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
8227 int skip = strlen(CMD_SET_ADPS) + 1;
8228 bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
8229 }
8230 else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
8231 bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
8232 }
8233 #endif /* WLADPS_PRIVATE_CMD */
8234 #ifdef DHD_PKT_LOGGING
8235 else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
8236 strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
8237 bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
8238 }
8239 else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
8240 strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
8241 bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
8242 }
8243 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
8244 strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
8245 bytes_written =
8246 wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
8247 }
8248 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
8249 strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
8250 bytes_written =
8251 wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
8252 }
8253 else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
8254 bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
8255 }
8256 else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
8257 bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
8258 }
8259 else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
8260 bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
8261 }
8262 else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
8263 bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
8264 }
8265 else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
8266 bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
8267 }
8268 else if (strnicmp(command, CMD_PKTLOG_MINMIZE_ENABLE,
8269 strlen(CMD_PKTLOG_MINMIZE_ENABLE)) == 0) {
8270 bytes_written = wl_android_pktlog_minmize_enable(net, command, priv_cmd.total_len);
8271 }
8272 else if (strnicmp(command, CMD_PKTLOG_MINMIZE_DISABLE,
8273 strlen(CMD_PKTLOG_MINMIZE_DISABLE)) == 0) {
8274 bytes_written = wl_android_pktlog_minmize_disable(net, command, priv_cmd.total_len);
8275 }
8276 else if (strnicmp(command, CMD_PKTLOG_CHANGE_SIZE,
8277 strlen(CMD_PKTLOG_CHANGE_SIZE)) == 0) {
8278 bytes_written = wl_android_pktlog_change_size(net, command, priv_cmd.total_len);
8279 }
8280 #endif /* DHD_PKT_LOGGING */
8281 else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) {
8282 int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
8283 bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
8284 }
8285 #ifdef DHD_EVENT_LOG_FILTER
8286 else if (strnicmp(command, CMD_EWP_FILTER,
8287 strlen(CMD_EWP_FILTER)) == 0) {
8288 bytes_written = wl_android_ewp_filter(net, command, priv_cmd.total_len);
8289 }
8290 #endif /* DHD_EVENT_LOG_FILTER */
8291 #ifdef APSTA_RESTRICTED_CHANNEL
8292 else if (strnicmp(command, CMD_GET_INDOOR_CHANNELS,
8293 strlen(CMD_GET_INDOOR_CHANNELS)) == 0) {
8294 bytes_written = wl_cfg80211_get_indoor_channels(net, command, priv_cmd.total_len);
8295 DHD_INFO(("Selected Indoor Channels - %s\n", command));
8296 }
8297 else if (strnicmp(command, CMD_SET_INDOOR_CHANNELS,
8298 strlen(CMD_SET_INDOOR_CHANNELS)) == 0) {
8299 bytes_written = wl_cfg80211_set_indoor_channels(net, command, priv_cmd.total_len);
8300 }
8301 #endif /* APSTA_RESTRICTED_CHANNEL */
8302 #ifdef SUPPORT_SET_CAC
8303 else if (strnicmp(command, CMD_ENABLE_CAC, strlen(CMD_ENABLE_CAC)) == 0) {
8304 int enable = *(command + strlen(CMD_ENABLE_CAC) + 1) - '0';
8305 bytes_written = wl_cfg80211_enable_cac(net, enable);
8306 }
8307 #endif /* SUPPORT_SET_CAC */
8308 #ifdef WL_BCNRECV
8309 else if (strnicmp(command, CMD_BEACON_RECV,
8310 strlen(CMD_BEACON_RECV)) == 0) {
8311 char *data = (command + strlen(CMD_BEACON_RECV) + 1);
8312 bytes_written = wl_android_bcnrecv_config(net,
8313 data, priv_cmd.total_len);
8314 }
8315 #endif /* WL_BCNRECV */
8316 else {
8317 DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
8318 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
8319 }
8320
8321 return bytes_written;
8322 }
8323
8324 int wl_android_init(void)
8325 {
8326 int ret = 0;
8327
8328 #ifdef ENABLE_INSMOD_NO_FW_LOAD
8329 dhd_download_fw_on_driverload = FALSE;
8330 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
8331 if (!iface_name[0]) {
8332 memset(iface_name, 0, IFNAMSIZ);
8333 bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
8334 }
8335
8336 #ifdef CUSTOMER_HW4_DEBUG
8337 g_assert_type = 1;
8338 #endif /* CUSTOMER_HW4_DEBUG */
8339
8340 #ifdef WL_GENL
8341 wl_genl_init();
8342 #endif // endif
8343 wl_netlink_init();
8344
8345 return ret;
8346 }
8347
8348 int wl_android_exit(void)
8349 {
8350 int ret = 0;
8351 struct io_cfg *cur, *q;
8352
8353 #ifdef WL_GENL
8354 wl_genl_deinit();
8355 #endif /* WL_GENL */
8356 wl_netlink_deinit();
8357
8358 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
8359 #pragma GCC diagnostic push
8360 #pragma GCC diagnostic ignored "-Wcast-qual"
8361 #endif // endif
8362 list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
8363 list_del(&cur->list);
8364 kfree(cur);
8365 }
8366 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
8367 #pragma GCC diagnostic pop
8368 #endif // endif
8369
8370 return ret;
8371 }
8372
8373 void wl_android_post_init(void)
8374 {
8375
8376 #ifdef ENABLE_4335BT_WAR
8377 bcm_bt_unlock(lock_cookie_wifi);
8378 printk("%s: btlock released\n", __FUNCTION__);
8379 #endif /* ENABLE_4335BT_WAR */
8380
8381 if (!dhd_download_fw_on_driverload)
8382 g_wifi_on = FALSE;
8383 }
8384
8385 #ifdef WL_GENL
8386 /* Generic Netlink Initializaiton */
8387 static int wl_genl_init(void)
8388 {
8389 int ret;
8390
8391 WL_DBG(("GEN Netlink Init\n\n"));
8392
8393 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
8394 /* register new family */
8395 ret = genl_register_family(&wl_genl_family);
8396 if (ret != 0)
8397 goto failure;
8398
8399 /* register functions (commands) of the new family */
8400 ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
8401 if (ret != 0) {
8402 WL_ERR(("register ops failed: %i\n", ret));
8403 genl_unregister_family(&wl_genl_family);
8404 goto failure;
8405 }
8406
8407 ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
8408 #else
8409 ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
8410 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
8411 if (ret != 0) {
8412 WL_ERR(("register mc_group failed: %i\n", ret));
8413 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
8414 genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
8415 #endif // endif
8416 genl_unregister_family(&wl_genl_family);
8417 goto failure;
8418 }
8419
8420 return 0;
8421
8422 failure:
8423 WL_ERR(("Registering Netlink failed!!\n"));
8424 return -1;
8425 }
8426
8427 /* Generic netlink deinit */
8428 static int wl_genl_deinit(void)
8429 {
8430
8431 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
8432 if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
8433 WL_ERR(("Unregister wl_genl_ops failed\n"));
8434 #endif // endif
8435 if (genl_unregister_family(&wl_genl_family) < 0)
8436 WL_ERR(("Unregister wl_genl_ops failed\n"));
8437
8438 return 0;
8439 }
8440
8441 s32 wl_event_to_bcm_event(u16 event_type)
8442 {
8443 u16 event = -1;
8444
8445 switch (event_type) {
8446 case WLC_E_SERVICE_FOUND:
8447 event = BCM_E_SVC_FOUND;
8448 break;
8449 case WLC_E_P2PO_ADD_DEVICE:
8450 event = BCM_E_DEV_FOUND;
8451 break;
8452 case WLC_E_P2PO_DEL_DEVICE:
8453 event = BCM_E_DEV_LOST;
8454 break;
8455 /* Above events are supported from BCM Supp ver 47 Onwards */
8456 #ifdef BT_WIFI_HANDOVER
8457 case WLC_E_BT_WIFI_HANDOVER_REQ:
8458 event = BCM_E_DEV_BT_WIFI_HO_REQ;
8459 break;
8460 #endif /* BT_WIFI_HANDOVER */
8461
8462 default:
8463 WL_ERR(("Event not supported\n"));
8464 }
8465
8466 return event;
8467 }
8468
8469 s32
8470 wl_genl_send_msg(
8471 struct net_device *ndev,
8472 u32 event_type,
8473 const u8 *buf,
8474 u16 len,
8475 u8 *subhdr,
8476 u16 subhdr_len)
8477 {
8478 int ret = 0;
8479 struct sk_buff *skb;
8480 void *msg;
8481 u32 attr_type = 0;
8482 bcm_event_hdr_t *hdr = NULL;
8483 int mcast = 1; /* By default sent as mutlicast type */
8484 int pid = 0;
8485 u8 *ptr = NULL, *p = NULL;
8486 u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
8487 gfp_t kflags;
8488 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
8489
8490 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
8491
8492 WL_DBG(("Enter \n"));
8493
8494 /* Decide between STRING event and Data event */
8495 if (event_type == 0)
8496 attr_type = BCM_GENL_ATTR_STRING;
8497 else
8498 attr_type = BCM_GENL_ATTR_MSG;
8499
8500 skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
8501 if (skb == NULL) {
8502 ret = -ENOMEM;
8503 goto out;
8504 }
8505
8506 msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
8507 if (msg == NULL) {
8508 ret = -ENOMEM;
8509 goto out;
8510 }
8511
8512 if (attr_type == BCM_GENL_ATTR_STRING) {
8513 /* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
8514 * make sure it is null terminated
8515 */
8516 if (subhdr || subhdr_len) {
8517 WL_ERR(("No sub hdr support for the ATTR STRING type \n"));
8518 ret = -EINVAL;
8519 goto out;
8520 }
8521
8522 ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
8523 if (ret != 0) {
8524 WL_ERR(("nla_put_string failed\n"));
8525 goto out;
8526 }
8527 } else {
8528 /* ATTR_MSG */
8529
8530 /* Create a single buffer for all */
8531 p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
8532 if (!ptr) {
8533 ret = -ENOMEM;
8534 WL_ERR(("ENOMEM!!\n"));
8535 goto out;
8536 }
8537
8538 /* Include the bcm event header */
8539 hdr = (bcm_event_hdr_t *)ptr;
8540 hdr->event_type = wl_event_to_bcm_event(event_type);
8541 hdr->len = len + subhdr_len;
8542 ptr += sizeof(bcm_event_hdr_t);
8543
8544 /* Copy subhdr (if any) */
8545 if (subhdr && subhdr_len) {
8546 memcpy(ptr, subhdr, subhdr_len);
8547 ptr += subhdr_len;
8548 }
8549
8550 /* Copy the data */
8551 if (buf && len) {
8552 memcpy(ptr, buf, len);
8553 }
8554
8555 ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
8556 if (ret != 0) {
8557 WL_ERR(("nla_put_string failed\n"));
8558 goto out;
8559 }
8560 }
8561
8562 if (mcast) {
8563 int err = 0;
8564 /* finalize the message */
8565 genlmsg_end(skb, msg);
8566 /* NETLINK_CB(skb).dst_group = 1; */
8567
8568 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
8569 if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
8570 #else
8571 if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
8572 #endif // endif
8573 WL_ERR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
8574 attr_type, err));
8575 else
8576 WL_DBG(("Multicast msg sent successfully. attr_type:%d len:%d \n",
8577 attr_type, tot_len));
8578 } else {
8579 NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
8580
8581 /* finalize the message */
8582 genlmsg_end(skb, msg);
8583
8584 /* send the message back */
8585 if (genlmsg_unicast(&init_net, skb, pid) < 0)
8586 WL_ERR(("genlmsg_unicast failed\n"));
8587 }
8588
8589 out:
8590 if (p) {
8591 MFREE(cfg->osh, p, tot_len);
8592 }
8593 if (ret)
8594 nlmsg_free(skb);
8595
8596 return ret;
8597 }
8598
8599 static s32
8600 wl_genl_handle_msg(
8601 struct sk_buff *skb,
8602 struct genl_info *info)
8603 {
8604 struct nlattr *na;
8605 u8 *data = NULL;
8606
8607 WL_DBG(("Enter \n"));
8608
8609 if (info == NULL) {
8610 return -EINVAL;
8611 }
8612
8613 na = info->attrs[BCM_GENL_ATTR_MSG];
8614 if (!na) {
8615 WL_ERR(("nlattribute NULL\n"));
8616 return -EINVAL;
8617 }
8618
8619 data = (char *)nla_data(na);
8620 if (!data) {
8621 WL_ERR(("Invalid data\n"));
8622 return -EINVAL;
8623 } else {
8624 /* Handle the data */
8625 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || defined(WL_COMPAT_WIRELESS)
8626 WL_DBG(("%s: Data received from pid (%d) \n", __func__,
8627 info->snd_pid));
8628 #else
8629 WL_DBG(("%s: Data received from pid (%d) \n", __func__,
8630 info->snd_portid));
8631 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
8632 }
8633
8634 return 0;
8635 }
8636 #endif /* WL_GENL */
8637
8638 int wl_fatal_error(void * wl, int rc)
8639 {
8640 return FALSE;
8641 }
8642
8643 #if defined(BT_OVER_SDIO)
8644 void
8645 wl_android_set_wifi_on_flag(bool enable)
8646 {
8647 g_wifi_on = enable;
8648 }
8649 #endif /* BT_OVER_SDIO */
8650
8651 #ifdef WL_STATIC_IF
8652 struct net_device *
8653 wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname)
8654 {
8655 struct net_device *ndev;
8656 struct wireless_dev *wdev = NULL;
8657 int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */
8658 u8 mac_addr[ETH_ALEN];
8659 struct net_device *primary_ndev;
8660
8661 WL_INFORM_MEM(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype));
8662
8663 if (!cfg) {
8664 WL_ERR(("cfg null\n"));
8665 return NULL;
8666 }
8667
8668 /* Use primary mac with locally admin bit set */
8669 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
8670 memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
8671 mac_addr[0] |= 0x02;
8672
8673 ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr,
8674 WL_BSSIDX_MAX, NULL);
8675 if (unlikely(!ndev)) {
8676 WL_ERR(("Failed to allocate static_if\n"));
8677 goto fail;
8678 }
8679 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
8680 if (unlikely(!wdev)) {
8681 WL_ERR(("Failed to allocate wdev for static_if\n"));
8682 goto fail;
8683 }
8684
8685 wdev->wiphy = cfg->wdev->wiphy;
8686 wdev->iftype = iftype;
8687
8688 ndev->ieee80211_ptr = wdev;
8689 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
8690 wdev->netdev = ndev;
8691
8692 if (wl_cfg80211_register_if(cfg, ifidx,
8693 ndev, TRUE) != BCME_OK) {
8694 WL_ERR(("ndev registration failed!\n"));
8695 goto fail;
8696 }
8697
8698 cfg->static_ndev = ndev;
8699 cfg->static_ndev_state = NDEV_STATE_OS_IF_CREATED;
8700 wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
8701 ifname, NDEV_STATE_OS_IF_CREATED);
8702 WL_INFORM_MEM(("Static I/F (%s) Registered\n", ndev->name));
8703 return ndev;
8704
8705 fail:
8706 wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
8707 return NULL;
8708 }
8709
8710 void
8711 wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
8712 {
8713 WL_INFORM_MEM(("[STATIC_IF] Enter\n"));
8714 if (!cfg || !cfg->static_ndev) {
8715 WL_ERR(("invalid input\n"));
8716 return;
8717 }
8718
8719 /* wdev free will happen from notifier context */
8720 /* free_netdev(cfg->static_ndev);
8721 */
8722 unregister_netdev(cfg->static_ndev);
8723 }
8724
8725 s32
8726 wl_cfg80211_static_if_open(struct net_device *net)
8727 {
8728 struct wireless_dev *wdev = NULL;
8729 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
8730 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
8731 u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
8732 u16 wl_iftype, wl_mode;
8733
8734 WL_INFORM_MEM(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr));
8735 ASSERT(cfg->static_ndev == net);
8736
8737 if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) < 0) {
8738 return BCME_ERROR;
8739 }
8740 if (cfg->static_ndev_state != NDEV_STATE_FW_IF_CREATED) {
8741 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, NULL);
8742 ASSERT(wdev == net->ieee80211_ptr);
8743 } else {
8744 WL_INFORM_MEM(("Fw IF for static netdev already created\n"));
8745 }
8746
8747 return BCME_OK;
8748 }
8749
8750 s32
8751 wl_cfg80211_static_if_close(struct net_device *net)
8752 {
8753 int ret = BCME_OK;
8754 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
8755 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
8756
8757 if (cfg->static_ndev_state == NDEV_STATE_FW_IF_CREATED) {
8758 ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
8759 if (unlikely(ret)) {
8760 WL_ERR(("Del iface failed for static_if %d\n", ret));
8761 }
8762 }
8763
8764 return ret;
8765 }
8766 struct net_device *
8767 wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
8768 wl_if_event_info *event, u8 *addr, s32 iface_type)
8769 {
8770 struct net_device *new_ndev = NULL;
8771 struct wireless_dev *wdev = NULL;
8772
8773 WL_INFORM_MEM(("Updating static iface after Fw IF create \n"));
8774 new_ndev = cfg->static_ndev;
8775
8776 if (new_ndev) {
8777 wdev = new_ndev->ieee80211_ptr;
8778 ASSERT(wdev);
8779 wdev->iftype = iface_type;
8780 memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
8781 }
8782
8783 cfg->static_ndev_state = NDEV_STATE_FW_IF_CREATED;
8784 wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx,
8785 event->name, NDEV_STATE_FW_IF_CREATED);
8786 return new_ndev;
8787 }
8788 s32
8789 wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev)
8790 {
8791 cfg->static_ndev_state = NDEV_STATE_FW_IF_DELETED;
8792 wl_cfg80211_update_iflist_info(cfg, ndev, WL_STATIC_IFIDX, NULL,
8793 WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED);
8794 wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
8795 wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
8796 return BCME_OK;
8797 }
8798 #endif /* WL_STATIC_IF */