1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * Linux cfg80211 driver - Android related functions
4 *
5 * Copyright (C) 1999-2017, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 *
26 * <<Broadcom-WL-IPTag/Open:>>
27 *
28 * $Id: wl_android.c 710862 2017-07-14 07:43:59Z $
29 */
30
31 #include <linux/module.h>
32 #include <linux/netdevice.h>
33 #include <net/netlink.h>
34 #ifdef CONFIG_COMPAT
35 #include <linux/compat.h>
36 #endif
37
38 #include <wl_android.h>
39 #include <wldev_common.h>
40 #include <wlc_types.h>
41 #include <wlioctl.h>
42 #include <wlioctl_utils.h>
43 #include <bcmutils.h>
44 #include <linux_osl.h>
45 #include <dhd_dbg.h>
46 #include <dngl_stats.h>
47 #include <dhd.h>
48 #include <dhd_config.h>
49 #include <bcmip.h>
50 #ifdef PNO_SUPPORT
51 #include <dhd_pno.h>
52 #endif
53 #ifdef BCMSDIO
54 #include <bcmsdbus.h>
55 #endif
56 #ifdef WL_CFG80211
57 #include <wl_cfg80211.h>
58 #endif
59 #ifdef DHDTCPACK_SUPPRESS
60 #include <dhd_ip.h>
61 #endif /* DHDTCPACK_SUPPRESS */
62 #include <dhd_linux.h>
63 #ifdef DHD_PKT_LOGGING
64 #include <dhd_pktlog.h>
65 #endif /* DHD_PKT_LOGGING */
66
67 #if defined(STAT_REPORT)
68 #include <wl_statreport.h>
69 #endif /* STAT_REPORT */
70 #ifdef WL_ESCAN
71 #include <wl_escan.h>
72 #endif
73
74 #ifndef WL_CFG80211
75 #define htod32(i) i
76 #define htod16(i) i
77 #define dtoh32(i) i
78 #define dtoh16(i) i
79 #define htodchanspec(i) i
80 #define dtohchanspec(i) i
81 #endif
82
83 uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL;
84
85 #define ANDROID_ERROR_MSG(x, args...) \
86 do { \
87 if (android_msg_level & ANDROID_ERROR_LEVEL) { \
88 printk(KERN_ERR "[dhd] ANDROID-ERROR) " x, ## args); \
89 } \
90 } while (0)
91 #define ANDROID_TRACE_MSG(x, args...) \
92 do { \
93 if (android_msg_level & ANDROID_TRACE_LEVEL) { \
94 printk(KERN_INFO "[dhd] ANDROID-TRACE) " x, ## args); \
95 } \
96 } while (0)
97 #define ANDROID_INFO_MSG(x, args...) \
98 do { \
99 if (android_msg_level & ANDROID_INFO_LEVEL) { \
100 printk(KERN_INFO "[dhd] ANDROID-INFO) " x, ## args); \
101 } \
102 } while (0)
103 #define ANDROID_ERROR(x) ANDROID_ERROR_MSG x
104 #define ANDROID_TRACE(x) ANDROID_TRACE_MSG x
105 #define ANDROID_INFO(x) ANDROID_INFO_MSG x
106
107 /*
108 * Android private command strings, PLEASE define new private commands here
109 * so they can be updated easily in the future (if needed)
110 */
111
112 #define CMD_START "START"
113 #define CMD_STOP "STOP"
114 #define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
115 #define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
116 #define CMD_RSSI "RSSI"
117 #define CMD_LINKSPEED "LINKSPEED"
118 #define CMD_RXFILTER_START "RXFILTER-START"
119 #define CMD_RXFILTER_STOP "RXFILTER-STOP"
120 #define CMD_RXFILTER_ADD "RXFILTER-ADD"
121 #define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
122 #define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
123 #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
124 #define CMD_BTCOEXMODE "BTCOEXMODE"
125 #define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
126 #define CMD_MAXDTIM_IN_SUSPEND "MAX_DTIM_IN_SUSPEND"
127 #define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
128 #define CMD_SETFWPATH "SETFWPATH"
129 #define CMD_SETBAND "SETBAND"
130 #define CMD_GETBAND "GETBAND"
131 #define CMD_COUNTRY "COUNTRY"
132 #ifdef WLMESH_CFG80211
133 #define CMD_SAE_SET_PASSWORD "SAE_SET_PASSWORD"
134 #define CMD_SET_RSDB_MODE "RSDB_MODE"
135 #endif
136 #define CMD_P2P_SET_NOA "P2P_SET_NOA"
137 #if !defined WL_ENABLE_P2P_IF
138 #define CMD_P2P_GET_NOA "P2P_GET_NOA"
139 #endif /* WL_ENABLE_P2P_IF */
140 #define CMD_P2P_SD_OFFLOAD "P2P_SD_"
141 #define CMD_P2P_LISTEN_OFFLOAD "P2P_LO_"
142 #define CMD_P2P_SET_PS "P2P_SET_PS"
143 #define CMD_P2P_ECSA "P2P_ECSA"
144 #define CMD_P2P_INC_BW "P2P_INCREASE_BW"
145 #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
146 #define CMD_SETROAMMODE "SETROAMMODE"
147 #define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA"
148 #define CMD_MIRACAST "MIRACAST"
149 #define CMD_COUNTRY_DELIMITER "/"
150 #ifdef WL11ULB
151 #define CMD_ULB_MODE "ULB_MODE"
152 #define CMD_ULB_BW "ULB_BW"
153 #endif /* WL11ULB */
154 #ifdef WLFBT
155 #define CMD_GET_FTKEY "GET_FTKEY"
156 #endif
157
158 #if defined(WL_SUPPORT_AUTO_CHANNEL)
159 #define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS"
160 #endif /* WL_SUPPORT_AUTO_CHANNEL */
161
162 #define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */
163 #define CMD_CHANSPEC "CHANSPEC"
164 #define CMD_DATARATE "DATARATE"
165 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
166 #define CMD_SET_CSA "SETCSA"
167 #ifdef WL_SUPPORT_AUTO_CHANNEL
168 #define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL"
169 #endif /* WL_SUPPORT_AUTO_CHANNEL */
170 #ifdef CUSTOMER_HW4_PRIVATE_CMD
171 #ifdef SUPPORT_SET_LPC
172 #define CMD_HAPD_LPC_ENABLED "HAPD_LPC_ENABLED"
173 #endif /* SUPPORT_SET_LPC */
174 #ifdef SUPPORT_TRIGGER_HANG_EVENT
175 #define CMD_TEST_FORCE_HANG "TEST_FORCE_HANG"
176 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
177 #ifdef TEST_TX_POWER_CONTROL
178 #define CMD_TEST_SET_TX_POWER "TEST_SET_TX_POWER"
179 #define CMD_TEST_GET_TX_POWER "TEST_GET_TX_POWER"
180 #endif /* TEST_TX_POWER_CONTROL */
181 #define CMD_SARLIMIT_TX_CONTROL "SET_TX_POWER_CALLING"
182 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
183 #define CMD_KEEP_ALIVE "KEEPALIVE"
184
185
186 #ifdef PNO_SUPPORT
187 #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR"
188 #define CMD_PNOSETUP_SET "PNOSETUP "
189 #define CMD_PNOENABLE_SET "PNOFORCE"
190 #define CMD_PNODEBUG_SET "PNODEBUG"
191 #define CMD_WLS_BATCHING "WLS_BATCHING"
192 #endif /* PNO_SUPPORT */
193
194 #define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER"
195
196 #ifdef CUSTOMER_HW4_PRIVATE_CMD
197
198
199 #if defined(SUPPORT_RANDOM_MAC_SCAN)
200 #define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC"
201 #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC"
202 #endif /* SUPPORT_RANDOM_MAC_SCAN */
203
204
205 #define CMD_CHANGE_RL "CHANGE_RL"
206 #define CMD_RESTORE_RL "RESTORE_RL"
207
208 #define CMD_SET_RMC_ENABLE "SETRMCENABLE"
209 #define CMD_SET_RMC_TXRATE "SETRMCTXRATE"
210 #define CMD_SET_RMC_ACTPERIOD "SETRMCACTIONPERIOD"
211 #define CMD_SET_RMC_IDLEPERIOD "SETRMCIDLEPERIOD"
212 #define CMD_SET_RMC_LEADER "SETRMCLEADER"
213 #define CMD_SET_RMC_EVENT "SETRMCEVENT"
214
215 #define CMD_SET_SCSCAN "SETSINGLEANT"
216 #define CMD_GET_SCSCAN "GETSINGLEANT"
217 #ifdef WLTDLS
218 #define CMD_TDLS_RESET "TDLS_RESET"
219 #endif /* WLTDLS */
220
221 #ifdef FCC_PWR_LIMIT_2G
222 #define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL"
223 #define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL"
224 /* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */
225 #define CUSTOMER_HW4_ENABLE 0
226 #define CUSTOMER_HW4_DISABLE -1
227 #define CUSTOMER_HW4_EN_CONVERT(i) (i += 1)
228 #endif /* FCC_PWR_LIMIT_2G */
229
230 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
231
232
233
234 #define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
235 #define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
236 #define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
237 #define CMD_GET_LINK_STATUS "GETLINKSTATUS"
238
239 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
240 #define CMD_GET_BSS_INFO "GETBSSINFO"
241 #define CMD_GET_ASSOC_REJECT_INFO "GETASSOCREJECTINFO"
242 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
243 #define CMD_GET_STA_INFO "GETSTAINFO"
244
245 /* related with CMD_GET_LINK_STATUS */
246 #define WL_ANDROID_LINK_VHT 0x01
247 #define WL_ANDROID_LINK_MIMO 0x02
248 #define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04
249 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08
250
251 #ifdef P2PRESP_WFDIE_SRC
252 #define CMD_P2P_SET_WFDIE_RESP "P2P_SET_WFDIE_RESP"
253 #define CMD_P2P_GET_WFDIE_RESP "P2P_GET_WFDIE_RESP"
254 #endif /* P2PRESP_WFDIE_SRC */
255
256 #define CMD_DFS_AP_MOVE "DFS_AP_MOVE"
257 #define CMD_WBTEXT_ENABLE "WBTEXT_ENABLE"
258 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
259 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
260 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
261 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
262 #define CMD_WBTEXT_BTM_TIMER_THRESHOLD "WBTEXT_BTM_TIMER_THRESHOLD"
263 #define CMD_WBTEXT_BTM_DELTA "WBTEXT_BTM_DELTA"
264
265 #ifdef WLWFDS
266 #define CMD_ADD_WFDS_HASH "ADD_WFDS_HASH"
267 #define CMD_DEL_WFDS_HASH "DEL_WFDS_HASH"
268 #endif /* WLWFDS */
269
270 #ifdef SET_RPS_CPUS
271 #define CMD_RPSMODE "RPSMODE"
272 #endif /* SET_RPS_CPUS */
273
274 #ifdef BT_WIFI_HANDOVER
275 #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
276 #endif /* BT_WIFI_HANDOVER */
277
278 #define CMD_MURX_BFE_CAP "MURX_BFE_CAP"
279
280 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
281 #define CMD_SET_AP_BEACONRATE "SET_AP_BEACONRATE"
282 #define CMD_GET_AP_BASICRATE "GET_AP_BASICRATE"
283 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
284
285 #ifdef SUPPORT_AP_RADIO_PWRSAVE
286 #define CMD_SET_AP_RPS "SET_AP_RPS"
287 #define CMD_GET_AP_RPS "GET_AP_RPS"
288 #define CMD_SET_AP_RPS_PARAMS "SET_AP_RPS_PARAMS"
289 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
290
291 #ifdef SUPPORT_RSSI_LOGGING
292 #define CMD_SET_RSSI_LOGGING "SET_RSSI_LOGGING"
293 #define CMD_GET_RSSI_LOGGING "GET_RSSI_LOGGING"
294 #define CMD_GET_RSSI_PER_ANT "GET_RSSI_PER_ANT"
295 #endif /* SUPPORT_RSSI_LOGGING */
296
297 #define CMD_GET_SNR "GET_SNR"
298
299 /* miracast related definition */
300 #define MIRACAST_MODE_OFF 0
301 #define MIRACAST_MODE_SOURCE 1
302 #define MIRACAST_MODE_SINK 2
303
304 #ifndef MIRACAST_AMPDU_SIZE
305 #define MIRACAST_AMPDU_SIZE 8
306 #endif
307
308 #ifndef MIRACAST_MCHAN_ALGO
309 #define MIRACAST_MCHAN_ALGO 1
310 #endif
311
312 #ifndef MIRACAST_MCHAN_BW
313 #define MIRACAST_MCHAN_BW 25
314 #endif
315
316 #ifdef CONNECTION_STATISTICS
317 #define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS"
318
319 struct connection_stats {
320 u32 txframe;
321 u32 txbyte;
322 u32 txerror;
323 u32 rxframe;
324 u32 rxbyte;
325 u32 txfail;
326 u32 txretry;
327 u32 txretrie;
328 u32 txrts;
329 u32 txnocts;
330 u32 txexptime;
331 u32 txrate;
332 u8 chan_idle;
333 };
334 #endif /* CONNECTION_STATISTICS */
335
336 #ifdef SUPPORT_LQCM
337 #define CMD_SET_LQCM_ENABLE "SET_LQCM_ENABLE"
338 #define CMD_GET_LQCM_REPORT "GET_LQCM_REPORT"
339 #endif
340
341 static LIST_HEAD(miracast_resume_list);
342 #ifdef WL_CFG80211
343 static u8 miracast_cur_mode;
344 #endif
345
346 #ifdef DHD_LOG_DUMP
347 #define CMD_NEW_DEBUG_PRINT_DUMP "DEBUG_DUMP"
348 extern void dhd_schedule_log_dump(dhd_pub_t *dhdp);
349 extern int dhd_bus_mem_dump(dhd_pub_t *dhd);
350 #endif /* DHD_LOG_DUMP */
351
352 #ifdef DHD_HANG_SEND_UP_TEST
353 #define CMD_MAKE_HANG "MAKE_HANG"
354 #endif /* CMD_DHD_HANG_SEND_UP_TEST */
355 #ifdef DHD_DEBUG_UART
356 extern bool dhd_debug_uart_is_running(struct net_device *dev);
357 #endif /* DHD_DEBUG_UART */
358
359 struct io_cfg {
360 s8 *iovar;
361 s32 param;
362 u32 ioctl;
363 void *arg;
364 u32 len;
365 struct list_head list;
366 };
367
368 #if defined(BCMFW_ROAM_ENABLE)
369 #define CMD_SET_ROAMPREF "SET_ROAMPREF"
370
371 #define MAX_NUM_SUITES 10
372 #define WIDTH_AKM_SUITE 8
373 #define JOIN_PREF_RSSI_LEN 0x02
374 #define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */
375 #define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */
376 #define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */
377 #define JOIN_PREF_MAX_WPA_TUPLES 16
378 #define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \
379 (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
380 #endif /* BCMFW_ROAM_ENABLE */
381
382 #ifdef WL_NATOE
383
384 #define CMD_NATOE "NATOE"
385
386 #define NATOE_MAX_PORT_NUM 65535
387
388 /* natoe command info structure */
389 typedef struct wl_natoe_cmd_info {
390 uint8 *command; /* pointer to the actual command */
391 uint16 tot_len; /* total length of the command */
392 uint16 bytes_written; /* Bytes written for get response */
393 } wl_natoe_cmd_info_t;
394
395 typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
396 typedef int (natoe_cmd_handler_t)(struct net_device *dev,
397 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
398
399 struct wl_natoe_sub_cmd {
400 char *name;
401 uint8 version; /* cmd version */
402 uint16 id; /* id for the dongle f/w switch/case */
403 uint16 type; /* base type of argument */
404 natoe_cmd_handler_t *handler; /* cmd handler */
405 };
406
407 #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix
408 static int wl_android_process_natoe_cmd(struct net_device *dev,
409 char *command, int total_len);
410 static int wl_android_natoe_subcmd_enable(struct net_device *dev,
411 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
412 static int wl_android_natoe_subcmd_config_ips(struct net_device *dev,
413 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
414 static int wl_android_natoe_subcmd_config_ports(struct net_device *dev,
415 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
416 static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev,
417 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
418 static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
419 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
420
421 static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
422 /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
423 {"enable", 0x01, WL_NATOE_CMD_ENABLE,
424 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable)
425 },
426 {"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS,
427 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips)
428 },
429 {"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS,
430 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports)
431 },
432 {"stats", 0x01, WL_NATOE_CMD_DBG_STATS,
433 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats)
434 },
435 {"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT,
436 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt)
437 },
438 {NULL, 0, 0, 0, NULL}
439 };
440
441 #endif /* WL_NATOE */
442
443 #ifdef SET_PCIE_IRQ_CPU_CORE
444 #define CMD_PCIE_IRQ_CORE "PCIE_IRQ_CORE"
445 #endif /* SET_PCIE_IRQ_CPU_CORE */
446
447 #ifdef WLADPS_PRIVATE_CMD
448 #define CMD_SET_ADPS "SET_ADPS"
449 #define CMD_GET_ADPS "GET_ADPS"
450 #endif /* WLADPS_PRIVATE_CMD */
451
452 #ifdef DHD_PKT_LOGGING
453 #define CMD_PKTLOG_FILTER_ENABLE "PKTLOG_FILTER_ENABLE"
454 #define CMD_PKTLOG_FILTER_DISABLE "PKTLOG_FILTER_DISABLE"
455 #define CMD_PKTLOG_FILTER_PATTERN_ENABLE "PKTLOG_FILTER_PATTERN_ENABLE"
456 #define CMD_PKTLOG_FILTER_PATTERN_DISABLE "PKTLOG_FILTER_PATTERN_DISABLE"
457 #define CMD_PKTLOG_FILTER_ADD "PKTLOG_FILTER_ADD"
458 #define CMD_PKTLOG_FILTER_INFO "PKTLOG_FILTER_INFO"
459 #define CMD_PKTLOG_START "PKTLOG_START"
460 #define CMD_PKTLOG_STOP "PKTLOG_STOP"
461 #define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST"
462 #endif /* DHD_PKT_LOGGING */
463
464 #if defined(STAT_REPORT)
465 #define CMD_STAT_REPORT_GET_START "STAT_REPORT_GET_START"
466 #define CMD_STAT_REPORT_GET_NEXT "STAT_REPORT_GET_NEXT"
467 #endif /* STAT_REPORT */
468
469
470 #ifdef SUPPORT_LQCM
471 #define LQCM_ENAB_MASK 0x000000FF /* LQCM enable flag mask */
472 #define LQCM_TX_INDEX_MASK 0x0000FF00 /* LQCM tx index mask */
473 #define LQCM_RX_INDEX_MASK 0x00FF0000 /* LQCM rx index mask */
474
475 #define LQCM_TX_INDEX_SHIFT 8 /* LQCM tx index shift */
476 #define LQCM_RX_INDEX_SHIFT 16 /* LQCM rx index shift */
477 #endif /* SUPPORT_LQCM */
478
479 /**
480 * Extern function declarations (TODO: move them to dhd_linux.h)
481 */
482 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
483 int dhd_dev_init_ioctl(struct net_device *dev);
484 #ifdef WL_CFG80211
485 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
486 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
487 #else
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)488 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
489 { return 0; }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)490 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
491 { return 0; }
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)492 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
493 { return 0; }
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)494 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
495 { return 0; }
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)496 int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
497 { return 0; }
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)498 int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
499 { return 0; }
500 #endif /* WL_CFG80211 */
501 #ifdef WBTEXT
502 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len);
503 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
504 char *command, int total_len);
505 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
506 char *command, int total_len);
507 #endif /* WBTEXT */
508
509 #ifdef ENABLE_4335BT_WAR
510 extern int bcm_bt_lock(int cookie);
511 extern void bcm_bt_unlock(int cookie);
512 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
513 #endif /* ENABLE_4335BT_WAR */
514
515 extern bool ap_fw_loaded;
516 extern char iface_name[IFNAMSIZ];
517
518 /**
519 * Local (static) functions and variables
520 */
521
522 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
523 * time (only) in dhd_open, subsequential wifi on will be handled by
524 * wl_android_wifi_on
525 */
526 int g_wifi_on = TRUE;
527
528 /**
529 * Local (static) function definitions
530 */
531
532 #ifdef WLWFDS
wl_android_set_wfds_hash(struct net_device * dev,char * command,int total_len,bool enable)533 static int wl_android_set_wfds_hash(
534 struct net_device *dev, char *command, int total_len, bool enable)
535 {
536 int error = 0;
537 wl_p2p_wfds_hash_t *wfds_hash = NULL;
538 char *smbuf = NULL;
539 smbuf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
540
541 if (smbuf == NULL) {
542 ANDROID_ERROR(("%s: failed to allocated memory %d bytes\n",
543 __FUNCTION__, WLC_IOCTL_MAXLEN));
544 return -ENOMEM;
545 }
546
547 if (enable) {
548 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
549 error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
550 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
551 }
552 else {
553 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
554 error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
555 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
556 }
557
558 if (error) {
559 ANDROID_ERROR(("%s: failed to %s, error=%d\n", __FUNCTION__, command, error));
560 }
561
562 if (smbuf)
563 kfree(smbuf);
564 return error;
565 }
566 #endif /* WLWFDS */
567
wl_android_get_link_speed(struct net_device * net,char * command,int total_len)568 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
569 {
570 int link_speed;
571 int bytes_written;
572 int error;
573
574 error = wldev_get_link_speed(net, &link_speed);
575 if (error) {
576 ANDROID_ERROR(("Get linkspeed failed \n"));
577 return -1;
578 }
579
580 /* Convert Kbps to Android Mbps */
581 link_speed = link_speed / 1000;
582 bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
583 ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command));
584 return bytes_written;
585 }
586
wl_android_get_rssi(struct net_device * net,char * command,int total_len)587 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
588 {
589 wlc_ssid_t ssid = {0, {0}};
590 int bytes_written = 0;
591 int error = 0;
592 scb_val_t scbval;
593 char *delim = NULL;
594 struct net_device *target_ndev = net;
595 #ifdef WL_VIRTUAL_APSTA
596 char *pos = NULL;
597 struct bcm_cfg80211 *cfg;
598 #endif /* WL_VIRTUAL_APSTA */
599
600 delim = strchr(command, ' ');
601 /* For Ap mode rssi command would be
602 * driver rssi <sta_mac_addr>
603 * for STA/GC mode
604 * driver rssi
605 */
606 if (delim) {
607 /* Ap/GO mode
608 * driver rssi <sta_mac_addr>
609 */
610 ANDROID_TRACE(("%s: cmd:%s\n", __FUNCTION__, delim));
611 /* skip space from delim after finding char */
612 delim++;
613 if (!(bcm_ether_atoe((delim), &scbval.ea)))
614 {
615 ANDROID_ERROR(("%s:address err\n", __FUNCTION__));
616 return -1;
617 }
618 scbval.val = htod32(0);
619 ANDROID_TRACE(("%s: address:"MACDBG, __FUNCTION__, MAC2STRDBG(scbval.ea.octet)));
620 #ifdef WL_VIRTUAL_APSTA
621 /* RSDB AP may have another virtual interface
622 * In this case, format of private command is as following,
623 * DRIVER rssi <sta_mac_addr> <AP interface name>
624 */
625
626 /* Current position is start of MAC address string */
627 pos = delim;
628 delim = strchr(pos, ' ');
629 if (delim) {
630 /* skip space from delim after finding char */
631 delim++;
632 if (strnlen(delim, IFNAMSIZ)) {
633 cfg = wl_get_cfg(net);
634 target_ndev = wl_get_ap_netdev(cfg, delim);
635 if (target_ndev == NULL)
636 target_ndev = net;
637 }
638 }
639 #endif /* WL_VIRTUAL_APSTA */
640 }
641 else {
642 /* STA/GC mode */
643 memset(&scbval, 0, sizeof(scb_val_t));
644 }
645
646 error = wldev_get_rssi(target_ndev, &scbval);
647 if (error)
648 return -1;
649 #if defined(RSSIOFFSET)
650 scbval.val = wl_update_rssi_offset(net, scbval.val);
651 #endif
652
653 error = wldev_get_ssid(target_ndev, &ssid);
654 if (error)
655 return -1;
656 if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
657 ANDROID_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
658 } else if (total_len <= ssid.SSID_len) {
659 return -ENOMEM;
660 } else {
661 memcpy(command, ssid.SSID, ssid.SSID_len);
662 bytes_written = ssid.SSID_len;
663 }
664 if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1))
665 return -ENOMEM;
666
667 bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written,
668 " rssi %d", scbval.val);
669 command[bytes_written] = '\0';
670
671 ANDROID_TRACE(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
672 return bytes_written;
673 }
674
wl_android_set_suspendopt(struct net_device * dev,char * command,int total_len)675 static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len)
676 {
677 int suspend_flag;
678 int ret_now;
679 int ret = 0;
680
681 suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
682
683 if (suspend_flag != 0) {
684 suspend_flag = 1;
685 }
686 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
687
688 if (ret_now != suspend_flag) {
689 if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
690 ANDROID_INFO(("%s: Suspend Flag %d -> %d\n",
691 __FUNCTION__, ret_now, suspend_flag));
692 } else {
693 ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
694 }
695 }
696
697 return ret;
698 }
699
700 #ifdef WL_CFG80211
wl_android_get_80211_mode(struct net_device * dev,char * command,int total_len)701 int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
702 {
703 uint8 mode[5];
704 int error = 0;
705 int bytes_written = 0;
706
707 error = wldev_get_mode(dev, mode, sizeof(mode));
708 if (error)
709 return -1;
710
711 ANDROID_INFO(("%s: mode:%s\n", __FUNCTION__, mode));
712 bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
713 ANDROID_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command));
714 return bytes_written;
715
716 }
717
718 extern chanspec_t
719 wl_chspec_driver_to_host(chanspec_t chanspec);
wl_android_get_chanspec(struct net_device * dev,char * command,int total_len)720 int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len)
721 {
722 int error = 0;
723 int bytes_written = 0;
724 int chsp = {0};
725 uint16 band = 0;
726 uint16 bw = 0;
727 uint16 channel = 0;
728 u32 sb = 0;
729 chanspec_t chanspec;
730
731 /* command is
732 * driver chanspec
733 */
734 error = wldev_iovar_getint(dev, "chanspec", &chsp);
735 if (error)
736 return -1;
737
738 chanspec = wl_chspec_driver_to_host(chsp);
739 ANDROID_INFO(("%s:return value of chanspec:%x\n", __FUNCTION__, chanspec));
740
741 channel = chanspec & WL_CHANSPEC_CHAN_MASK;
742 band = chanspec & WL_CHANSPEC_BAND_MASK;
743 bw = chanspec & WL_CHANSPEC_BW_MASK;
744
745 ANDROID_INFO(("%s:channel:%d band:%d bandwidth:%d\n", __FUNCTION__, channel, band, bw));
746
747 if (bw == WL_CHANSPEC_BW_80)
748 bw = WL_CH_BANDWIDTH_80MHZ;
749 else if (bw == WL_CHANSPEC_BW_40)
750 bw = WL_CH_BANDWIDTH_40MHZ;
751 else if (bw == WL_CHANSPEC_BW_20)
752 bw = WL_CH_BANDWIDTH_20MHZ;
753 else
754 bw = WL_CH_BANDWIDTH_20MHZ;
755
756 if (bw == WL_CH_BANDWIDTH_40MHZ) {
757 if (CHSPEC_SB_UPPER(chanspec)) {
758 channel += CH_10MHZ_APART;
759 } else {
760 channel -= CH_10MHZ_APART;
761 }
762 }
763 else if (bw == WL_CH_BANDWIDTH_80MHZ) {
764 sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
765 if (sb == WL_CHANSPEC_CTL_SB_LL) {
766 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
767 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
768 channel -= CH_10MHZ_APART;
769 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
770 channel += CH_10MHZ_APART;
771 } else {
772 /* WL_CHANSPEC_CTL_SB_UU */
773 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
774 }
775 }
776 bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC,
777 channel, band == WL_CHANSPEC_BAND_5G ? "5G":"2G", bw);
778
779 ANDROID_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command));
780 return bytes_written;
781
782 }
783 #endif
784
785 /* returns current datarate datarate returned from firmware are in 500kbps */
wl_android_get_datarate(struct net_device * dev,char * command,int total_len)786 int wl_android_get_datarate(struct net_device *dev, char *command, int total_len)
787 {
788 int error = 0;
789 int datarate = 0;
790 int bytes_written = 0;
791
792 error = wldev_get_datarate(dev, &datarate);
793 if (error)
794 return -1;
795
796 ANDROID_INFO(("%s:datarate:%d\n", __FUNCTION__, datarate));
797
798 bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2));
799 return bytes_written;
800 }
wl_android_get_assoclist(struct net_device * dev,char * command,int total_len)801 int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len)
802 {
803 int error = 0;
804 int bytes_written = 0;
805 uint i;
806 char mac_buf[MAX_NUM_OF_ASSOCLIST *
807 sizeof(struct ether_addr) + sizeof(uint)] = {0};
808 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
809
810 ANDROID_TRACE(("%s: ENTER\n", __FUNCTION__));
811
812 assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
813
814 error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
815 if (error)
816 return -1;
817
818 assoc_maclist->count = dtoh32(assoc_maclist->count);
819 bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:",
820 CMD_ASSOC_CLIENTS, assoc_maclist->count);
821
822 for (i = 0; i < assoc_maclist->count; i++) {
823 bytes_written += snprintf(command + bytes_written, total_len, " " MACDBG,
824 MAC2STRDBG(assoc_maclist->ea[i].octet));
825 }
826 return bytes_written;
827
828 }
829
830 #ifdef WL_CFG80211
831 extern chanspec_t
832 wl_chspec_host_to_driver(chanspec_t chanspec);
wl_android_set_csa(struct net_device * dev,char * command,int total_len)833 static int wl_android_set_csa(struct net_device *dev, char *command, int total_len)
834 {
835 int error = 0;
836 char smbuf[WLC_IOCTL_SMLEN];
837 wl_chan_switch_t csa_arg;
838 u32 chnsp = 0;
839 int err = 0;
840
841 ANDROID_INFO(("%s: command:%s\n", __FUNCTION__, command));
842
843 command = (command + strlen(CMD_SET_CSA));
844 /* Order is mode, count channel */
845 if (!*++command) {
846 ANDROID_ERROR(("%s:error missing arguments\n", __FUNCTION__));
847 return -1;
848 }
849 csa_arg.mode = bcm_atoi(command);
850
851 if (csa_arg.mode != 0 && csa_arg.mode != 1) {
852 ANDROID_ERROR(("Invalid mode\n"));
853 return -1;
854 }
855
856 if (!*++command) {
857 ANDROID_ERROR(("%s:error missing count\n", __FUNCTION__));
858 return -1;
859 }
860 command++;
861 csa_arg.count = bcm_atoi(command);
862
863 csa_arg.reg = 0;
864 csa_arg.chspec = 0;
865 command += 2;
866 if (!*command) {
867 ANDROID_ERROR(("%s:error missing channel\n", __FUNCTION__));
868 return -1;
869 }
870
871 chnsp = wf_chspec_aton(command);
872 if (chnsp == 0) {
873 ANDROID_ERROR(("%s:chsp is not correct\n", __FUNCTION__));
874 return -1;
875 }
876 chnsp = wl_chspec_host_to_driver(chnsp);
877 csa_arg.chspec = chnsp;
878
879 if (chnsp & WL_CHANSPEC_BAND_5G) {
880 u32 chanspec = chnsp;
881 err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
882 if (!err) {
883 if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
884 ANDROID_ERROR(("Channel is radar sensitive\n"));
885 return -1;
886 }
887 if (chanspec == 0) {
888 ANDROID_ERROR(("Invalid hw channel\n"));
889 return -1;
890 }
891 } else {
892 ANDROID_ERROR(("does not support per_chan_info\n"));
893 return -1;
894 }
895 ANDROID_INFO(("non radar sensitivity\n"));
896 }
897 error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
898 smbuf, sizeof(smbuf), NULL);
899 if (error) {
900 ANDROID_ERROR(("%s:set csa failed:%d\n", __FUNCTION__, error));
901 return -1;
902 }
903 return 0;
904 }
905 #endif
906
907 static int
wl_android_set_max_dtim(struct net_device * dev,char * command,int total_len)908 wl_android_set_max_dtim(struct net_device *dev, char *command, int total_len)
909 {
910 int ret = 0;
911 int dtim_flag;
912
913 dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
914
915 if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
916 ANDROID_TRACE(("%s: use Max bcn_li_dtim in suspend %s\n",
917 __FUNCTION__, (dtim_flag ? "Enable" : "Disable")));
918 } else {
919 ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
920 }
921
922 return ret;
923 }
924
wl_android_get_band(struct net_device * dev,char * command,int total_len)925 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
926 {
927 uint band;
928 int bytes_written;
929 int error;
930
931 error = wldev_get_band(dev, &band);
932 if (error)
933 return -1;
934 bytes_written = snprintf(command, total_len, "Band %d", band);
935 return bytes_written;
936 }
937
938 #ifdef CUSTOMER_HW4_PRIVATE_CMD
939
940 #ifdef WLTDLS
wl_android_tdls_reset(struct net_device * dev)941 int wl_android_tdls_reset(struct net_device *dev)
942 {
943 int ret = 0;
944 ret = dhd_tdls_enable(dev, false, false, NULL);
945 if (ret < 0) {
946 ANDROID_ERROR(("Disable tdls failed. %d\n", ret));
947 return ret;
948 }
949 ret = dhd_tdls_enable(dev, true, true, NULL);
950 if (ret < 0) {
951 ANDROID_ERROR(("enable tdls failed. %d\n", ret));
952 return ret;
953 }
954 return 0;
955 }
956 #endif /* WLTDLS */
957 #ifdef FCC_PWR_LIMIT_2G
958 int
wl_android_set_fcc_pwr_limit_2g(struct net_device * dev,char * command,int total_len)959 wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
960 {
961 int error = 0;
962 int enable = 0;
963
964 sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable);
965
966 if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) {
967 ANDROID_ERROR(("%s: Invalid data\n", __FUNCTION__));
968 return BCME_ERROR;
969 }
970
971 CUSTOMER_HW4_EN_CONVERT(enable);
972
973 ANDROID_ERROR(("%s: fccpwrlimit2g set (%d)\n", __FUNCTION__, enable));
974 error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
975 if (error) {
976 ANDROID_ERROR(("%s: fccpwrlimit2g set returned (%d)\n", __FUNCTION__, error));
977 return BCME_ERROR;
978 }
979
980 return error;
981 }
982
983 int
wl_android_get_fcc_pwr_limit_2g(struct net_device * dev,char * command,int total_len)984 wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
985 {
986 int error = 0;
987 int enable = 0;
988 int bytes_written = 0;
989
990 error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable);
991 if (error) {
992 ANDROID_ERROR(("%s: fccpwrlimit2g get error (%d)\n", __FUNCTION__, error));
993 return BCME_ERROR;
994 }
995 ANDROID_ERROR(("%s: fccpwrlimit2g get (%d)\n", __FUNCTION__, enable));
996
997 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable);
998
999 return bytes_written;
1000 }
1001 #endif /* FCC_PWR_LIMIT_2G */
1002
1003 s32
wl_cfg80211_get_sta_info(struct net_device * dev,char * command,int total_len)1004 wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
1005 {
1006 static char iovar_buf[WLC_IOCTL_MAXLEN];
1007 int bytes_written = -1, ret = 0;
1008 char *pcmd = command;
1009 char *str;
1010 sta_info_t *sta = NULL;
1011 wl_cnt_wlc_t* wlc_cnt = NULL;
1012 struct ether_addr mac;
1013
1014 /* Client information */
1015 uint16 cap = 0;
1016 uint32 rxrtry = 0;
1017 uint32 rxmulti = 0;
1018
1019 ANDROID_TRACE(("%s\n", command));
1020 str = bcmstrtok(&pcmd, " ", NULL);
1021 if (str) {
1022 str = bcmstrtok(&pcmd, " ", NULL);
1023 /* If GETSTAINFO subcmd name is not provided, return error */
1024 if (str == NULL) {
1025 ANDROID_ERROR(("GETSTAINFO subcmd not provided %s\n", __FUNCTION__));
1026 goto error;
1027 }
1028
1029 memset(&mac, 0, ETHER_ADDR_LEN);
1030 if ((bcm_ether_atoe((str), &mac))) {
1031 /* get the sta info */
1032 ret = wldev_iovar_getbuf(dev, "sta_info",
1033 (struct ether_addr *)mac.octet,
1034 ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
1035 if (ret < 0) {
1036 ANDROID_ERROR(("Get sta_info ERR %d\n", ret));
1037 goto error;
1038 }
1039
1040 sta = (sta_info_t *)iovar_buf;
1041 cap = dtoh16(sta->cap);
1042 rxrtry = dtoh32(sta->rx_pkts_retried);
1043 rxmulti = dtoh32(sta->rx_mcast_pkts);
1044 } else if ((!strncmp(str, "all", 3)) || (!strncmp(str, "ALL", 3))) {
1045 /* get counters info */
1046 ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
1047 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
1048 if (unlikely(ret)) {
1049 ANDROID_ERROR(("counters error (%d) - size = %zu\n",
1050 ret, sizeof(wl_cnt_wlc_t)));
1051 goto error;
1052 }
1053 ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
1054 if (ret != BCME_OK) {
1055 ANDROID_ERROR(("wl_cntbuf_to_xtlv_format ERR %d\n", ret));
1056 goto error;
1057 }
1058 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
1059 ANDROID_ERROR(("wlc_cnt NULL!\n"));
1060 goto error;
1061 }
1062
1063 rxrtry = dtoh32(wlc_cnt->rxrtry);
1064 rxmulti = dtoh32(wlc_cnt->rxmulti);
1065 } else {
1066 ANDROID_ERROR(("Get address fail\n"));
1067 goto error;
1068 }
1069 } else {
1070 ANDROID_ERROR(("Command ERR\n"));
1071 goto error;
1072 }
1073
1074 bytes_written = snprintf(command, total_len,
1075 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x\n",
1076 CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap);
1077
1078 ANDROID_TRACE(("%s", command));
1079
1080 error:
1081 return bytes_written;
1082 }
1083 #endif
1084
1085 #ifdef WBTEXT
wl_android_wbtext(struct net_device * dev,char * command,int total_len)1086 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
1087 {
1088 int error = BCME_OK, argc = 0;
1089 int data, bytes_written;
1090 int roam_trigger[2];
1091 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1092
1093 argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
1094 if (!argc) {
1095 error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
1096 if (error) {
1097 ANDROID_ERROR(("%s: Failed to set wbtext error = %d\n",
1098 __FUNCTION__, error));
1099 return error;
1100 }
1101 bytes_written = snprintf(command, total_len, "WBTEXT %s\n",
1102 (data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)?
1103 "ENABLED" : "DISABLED");
1104 return bytes_written;
1105 } else {
1106 if (data) {
1107 data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT;
1108 }
1109
1110 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
1111 ANDROID_ERROR(("%s: Failed to set wbtext error = %d\n",
1112 __FUNCTION__, error));
1113 return error;
1114 }
1115
1116 if (data) {
1117 /* reset roam_prof when wbtext is on */
1118 if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) {
1119 return error;
1120 }
1121 dhdp->wbtext_support = TRUE;
1122 } else {
1123 /* reset legacy roam trigger when wbtext is off */
1124 roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE;
1125 roam_trigger[1] = WLC_BAND_ALL;
1126 if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1127 sizeof(roam_trigger))) != BCME_OK) {
1128 ANDROID_ERROR(("%s: Failed to reset roam trigger = %d\n",
1129 __FUNCTION__, error));
1130 return error;
1131 }
1132 dhdp->wbtext_support = FALSE;
1133 }
1134 }
1135 return error;
1136 }
1137
wl_cfg80211_wbtext_btm_timer_threshold(struct net_device * dev,char * command,int total_len)1138 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
1139 char *command, int total_len)
1140 {
1141 int error = BCME_OK, argc = 0;
1142 int data, bytes_written;
1143
1144 argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data);
1145 if (!argc) {
1146 error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data);
1147 if (error) {
1148 ANDROID_ERROR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error));
1149 return error;
1150 }
1151 bytes_written = snprintf(command, total_len, "%d\n", data);
1152 return bytes_written;
1153 } else {
1154 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold",
1155 data)) != BCME_OK) {
1156 ANDROID_ERROR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error));
1157 return error;
1158 }
1159 }
1160 return error;
1161 }
1162
wl_cfg80211_wbtext_btm_delta(struct net_device * dev,char * command,int total_len)1163 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
1164 char *command, int total_len)
1165 {
1166 int error = BCME_OK, argc = 0;
1167 int data = 0, bytes_written;
1168
1169 argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data);
1170 if (!argc) {
1171 error = wldev_iovar_getint(dev, "wnm_btmdelta", &data);
1172 if (error) {
1173 ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error));
1174 return error;
1175 }
1176 bytes_written = snprintf(command, total_len, "%d\n", data);
1177 return bytes_written;
1178 } else {
1179 if ((error = wldev_iovar_setint(dev, "wnm_btmdelta",
1180 data)) != BCME_OK) {
1181 ANDROID_ERROR(("Failed to set wnm_btmdelta (%d)\n", error));
1182 return error;
1183 }
1184 }
1185 return error;
1186 }
1187
1188 #endif /* WBTEXT */
1189
1190 #ifdef PNO_SUPPORT
1191 #define PNO_PARAM_SIZE 50
1192 #define VALUE_SIZE 50
1193 #define LIMIT_STR_FMT ("%50s %50s")
1194
1195 static int
wls_parse_batching_cmd(struct net_device * dev,char * command,int total_len)1196 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
1197 {
1198 int err = BCME_OK;
1199 uint i, tokens;
1200 char *pos, *pos2, *token, *token2, *delim;
1201 char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
1202 struct dhd_pno_batch_params batch_params;
1203
1204 ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
1205 if (total_len < strlen(CMD_WLS_BATCHING)) {
1206 ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
1207 err = BCME_ERROR;
1208 goto exit;
1209 }
1210 pos = command + strlen(CMD_WLS_BATCHING) + 1;
1211 memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params));
1212
1213 if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
1214 pos += strlen(PNO_BATCHING_SET) + 1;
1215 while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
1216 memset(param, 0, sizeof(param));
1217 memset(value, 0, sizeof(value));
1218 if (token == NULL || !*token)
1219 break;
1220 if (*token == '\0')
1221 continue;
1222 delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
1223 if (delim != NULL)
1224 *delim = ' ';
1225
1226 tokens = sscanf(token, LIMIT_STR_FMT, param, value);
1227 if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
1228 batch_params.scan_fr = simple_strtol(value, NULL, 0);
1229 ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr));
1230 } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
1231 batch_params.bestn = simple_strtol(value, NULL, 0);
1232 ANDROID_INFO(("bestn : %d\n", batch_params.bestn));
1233 } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
1234 batch_params.mscan = simple_strtol(value, NULL, 0);
1235 ANDROID_INFO(("mscan : %d\n", batch_params.mscan));
1236 } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
1237 i = 0;
1238 pos2 = value;
1239 tokens = sscanf(value, "<%s>", value);
1240 if (tokens != 1) {
1241 err = BCME_ERROR;
1242 ANDROID_ERROR(("%s : invalid format for channel"
1243 " <> params\n", __FUNCTION__));
1244 goto exit;
1245 }
1246 while ((token2 = strsep(&pos2,
1247 PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
1248 if (token2 == NULL || !*token2)
1249 break;
1250 if (*token2 == '\0')
1251 continue;
1252 if (*token2 == 'A' || *token2 == 'B') {
1253 batch_params.band = (*token2 == 'A')?
1254 WLC_BAND_5G : WLC_BAND_2G;
1255 ANDROID_INFO(("band : %s\n",
1256 (*token2 == 'A')? "A" : "B"));
1257 } else {
1258 if ((batch_params.nchan >= WL_NUMCHANNELS) ||
1259 (i >= WL_NUMCHANNELS)) {
1260 ANDROID_ERROR(("Too many nchan %d\n",
1261 batch_params.nchan));
1262 err = BCME_BUFTOOSHORT;
1263 goto exit;
1264 }
1265 batch_params.chan_list[i++] =
1266 simple_strtol(token2, NULL, 0);
1267 batch_params.nchan++;
1268 ANDROID_INFO(("channel :%d\n",
1269 batch_params.chan_list[i-1]));
1270 }
1271 }
1272 } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
1273 batch_params.rtt = simple_strtol(value, NULL, 0);
1274 ANDROID_INFO(("rtt : %d\n", batch_params.rtt));
1275 } else {
1276 ANDROID_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param));
1277 err = BCME_ERROR;
1278 goto exit;
1279 }
1280 }
1281 err = dhd_dev_pno_set_for_batch(dev, &batch_params);
1282 if (err < 0) {
1283 ANDROID_ERROR(("failed to configure batch scan\n"));
1284 } else {
1285 memset(command, 0, total_len);
1286 err = snprintf(command, total_len, "%d", err);
1287 }
1288 } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
1289 err = dhd_dev_pno_get_for_batch(dev, command, total_len);
1290 if (err < 0) {
1291 ANDROID_ERROR(("failed to getting batching results\n"));
1292 } else {
1293 err = strlen(command);
1294 }
1295 } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
1296 err = dhd_dev_pno_stop_for_batch(dev);
1297 if (err < 0) {
1298 ANDROID_ERROR(("failed to stop batching scan\n"));
1299 } else {
1300 memset(command, 0, total_len);
1301 err = snprintf(command, total_len, "OK");
1302 }
1303 } else {
1304 ANDROID_ERROR(("%s : unknown command\n", __FUNCTION__));
1305 err = BCME_ERROR;
1306 goto exit;
1307 }
1308 exit:
1309 return err;
1310 }
1311
1312 #ifndef WL_SCHED_SCAN
wl_android_set_pno_setup(struct net_device * dev,char * command,int total_len)1313 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
1314 {
1315 wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
1316 int res = -1;
1317 int nssid = 0;
1318 cmd_tlv_t *cmd_tlv_temp;
1319 char *str_ptr;
1320 int tlv_size_left;
1321 int pno_time = 0;
1322 int pno_repeat = 0;
1323 int pno_freq_expo_max = 0;
1324
1325 #ifdef PNO_SET_DEBUG
1326 int i;
1327 char pno_in_example[] = {
1328 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
1329 'S', '1', '2', '0',
1330 'S',
1331 0x05,
1332 'd', 'l', 'i', 'n', 'k',
1333 'S',
1334 0x04,
1335 'G', 'O', 'O', 'G',
1336 'T',
1337 '0', 'B',
1338 'R',
1339 '2',
1340 'M',
1341 '2',
1342 0x00
1343 };
1344 #endif /* PNO_SET_DEBUG */
1345 ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
1346
1347 if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
1348 ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
1349 goto exit_proc;
1350 }
1351 #ifdef PNO_SET_DEBUG
1352 memcpy(command, pno_in_example, sizeof(pno_in_example));
1353 total_len = sizeof(pno_in_example);
1354 #endif
1355 str_ptr = command + strlen(CMD_PNOSETUP_SET);
1356 tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
1357
1358 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
1359 memset(ssids_local, 0, sizeof(ssids_local));
1360
1361 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
1362 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
1363 (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
1364
1365 str_ptr += sizeof(cmd_tlv_t);
1366 tlv_size_left -= sizeof(cmd_tlv_t);
1367
1368 if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
1369 MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
1370 ANDROID_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
1371 goto exit_proc;
1372 } else {
1373 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
1374 ANDROID_ERROR(("%s scan duration corrupted field size %d\n",
1375 __FUNCTION__, tlv_size_left));
1376 goto exit_proc;
1377 }
1378 str_ptr++;
1379 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
1380 ANDROID_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
1381
1382 if (str_ptr[0] != 0) {
1383 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
1384 ANDROID_ERROR(("%s pno repeat : corrupted field\n",
1385 __FUNCTION__));
1386 goto exit_proc;
1387 }
1388 str_ptr++;
1389 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
1390 ANDROID_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
1391 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
1392 ANDROID_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
1393 __FUNCTION__));
1394 goto exit_proc;
1395 }
1396 str_ptr++;
1397 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
1398 ANDROID_INFO(("%s: pno_freq_expo_max=%d\n",
1399 __FUNCTION__, pno_freq_expo_max));
1400 }
1401 }
1402 } else {
1403 ANDROID_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
1404 goto exit_proc;
1405 }
1406
1407 res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
1408 pno_freq_expo_max, NULL, 0);
1409 exit_proc:
1410 return res;
1411 }
1412 #endif /* !WL_SCHED_SCAN */
1413 #endif /* PNO_SUPPORT */
1414
wl_android_get_p2p_dev_addr(struct net_device * ndev,char * command,int total_len)1415 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
1416 {
1417 int ret;
1418 int bytes_written = 0;
1419
1420 ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command);
1421 if (ret)
1422 return 0;
1423 bytes_written = sizeof(struct ether_addr);
1424 return bytes_written;
1425 }
1426
1427
1428 int
wl_android_set_ap_mac_list(struct net_device * dev,int macmode,struct maclist * maclist)1429 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
1430 {
1431 int i, j, match;
1432 int ret = 0;
1433 char mac_buf[MAX_NUM_OF_ASSOCLIST *
1434 sizeof(struct ether_addr) + sizeof(uint)] = {0};
1435 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
1436
1437 /* set filtering mode */
1438 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) {
1439 ANDROID_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret));
1440 return ret;
1441 }
1442 if (macmode != MACLIST_MODE_DISABLED) {
1443 /* set the MAC filter list */
1444 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
1445 sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
1446 ANDROID_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret));
1447 return ret;
1448 }
1449 /* get the current list of associated STAs */
1450 assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
1451 if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
1452 sizeof(mac_buf))) != 0) {
1453 ANDROID_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret));
1454 return ret;
1455 }
1456 /* do we have any STA associated? */
1457 if (assoc_maclist->count) {
1458 /* iterate each associated STA */
1459 for (i = 0; i < assoc_maclist->count; i++) {
1460 match = 0;
1461 /* compare with each entry */
1462 for (j = 0; j < maclist->count; j++) {
1463 ANDROID_INFO(("%s : associated="MACDBG " list="MACDBG "\n",
1464 __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet),
1465 MAC2STRDBG(maclist->ea[j].octet)));
1466 if (memcmp(assoc_maclist->ea[i].octet,
1467 maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
1468 match = 1;
1469 break;
1470 }
1471 }
1472 /* do conditional deauth */
1473 /* "if not in the allow list" or "if in the deny list" */
1474 if ((macmode == MACLIST_MODE_ALLOW && !match) ||
1475 (macmode == MACLIST_MODE_DENY && match)) {
1476 scb_val_t scbval;
1477
1478 scbval.val = htod32(1);
1479 memcpy(&scbval.ea, &assoc_maclist->ea[i],
1480 ETHER_ADDR_LEN);
1481 if ((ret = wldev_ioctl_set(dev,
1482 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
1483 &scbval, sizeof(scb_val_t))) != 0)
1484 ANDROID_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n",
1485 __FUNCTION__, ret));
1486 }
1487 }
1488 }
1489 }
1490 return ret;
1491 }
1492
1493 /*
1494 * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
1495 *
1496 */
1497 static int
wl_android_set_mac_address_filter(struct net_device * dev,char * str)1498 wl_android_set_mac_address_filter(struct net_device *dev, char* str)
1499 {
1500 int i;
1501 int ret = 0;
1502 int macnum = 0;
1503 int macmode = MACLIST_MODE_DISABLED;
1504 struct maclist *list;
1505 char eabuf[ETHER_ADDR_STR_LEN];
1506 const char *token;
1507
1508 /* string should look like below (macmode/macnum/maclist) */
1509 /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */
1510
1511 /* get the MAC filter mode */
1512 token = strsep((char**)&str, " ");
1513 if (!token) {
1514 return -1;
1515 }
1516 macmode = bcm_atoi(token);
1517
1518 if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
1519 ANDROID_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode));
1520 return -1;
1521 }
1522
1523 token = strsep((char**)&str, " ");
1524 if (!token) {
1525 return -1;
1526 }
1527 macnum = bcm_atoi(token);
1528 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
1529 ANDROID_ERROR(("%s : invalid number of MAC address entries %d\n",
1530 __FUNCTION__, macnum));
1531 return -1;
1532 }
1533 /* allocate memory for the MAC list */
1534 list = (struct maclist*)kmalloc(sizeof(int) +
1535 sizeof(struct ether_addr) * macnum, GFP_KERNEL);
1536 if (!list) {
1537 ANDROID_ERROR(("%s : failed to allocate memory\n", __FUNCTION__));
1538 return -1;
1539 }
1540 /* prepare the MAC list */
1541 list->count = htod32(macnum);
1542 bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
1543 for (i = 0; i < list->count; i++) {
1544 strncpy(eabuf, strsep((char**)&str, " "), ETHER_ADDR_STR_LEN - 1);
1545 if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
1546 ANDROID_ERROR(("%s : mac parsing err index=%d, addr=%s\n",
1547 __FUNCTION__, i, eabuf));
1548 list->count--;
1549 break;
1550 }
1551 ANDROID_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf));
1552 }
1553 /* set the list */
1554 if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
1555 ANDROID_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
1556
1557 kfree(list);
1558
1559 return 0;
1560 }
1561
1562 /**
1563 * Global function definitions (declared in wl_android.h)
1564 */
1565
wl_android_wifi_on(struct net_device * dev)1566 int wl_android_wifi_on(struct net_device *dev)
1567 {
1568 int ret = 0;
1569 int retry = POWERUP_MAX_RETRY;
1570
1571 if (!dev) {
1572 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
1573 return -EINVAL;
1574 }
1575
1576 dhd_net_if_lock(dev);
1577 WL_MSG(dev->name, "in g_wifi_on=%d\n", g_wifi_on);
1578 if (!g_wifi_on) {
1579 do {
1580 if (!dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY)) {
1581 #ifdef BCMSDIO
1582 ret = dhd_net_bus_resume(dev, 0);
1583 #endif /* BCMSDIO */
1584 }
1585 #ifdef BCMPCIE
1586 ret = dhd_net_bus_devreset(dev, FALSE);
1587 #endif /* BCMPCIE */
1588 if (ret == 0) {
1589 break;
1590 }
1591 ANDROID_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
1592 retry));
1593 #ifdef BCMPCIE
1594 dhd_net_bus_devreset(dev, TRUE);
1595 #endif /* BCMPCIE */
1596 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
1597 } while (retry-- > 0);
1598 if (ret != 0) {
1599 ANDROID_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
1600 goto exit;
1601 }
1602 #if defined(BCMSDIO) || defined(BCMDBUS)
1603 ret = dhd_net_bus_devreset(dev, FALSE);
1604 if (ret)
1605 goto err;
1606 #ifdef BCMSDIO
1607 dhd_net_bus_resume(dev, 1);
1608 #endif /* BCMSDIO */
1609 #endif /* BCMSDIO || BCMDBUS */
1610 #if defined(BCMSDIO) || defined(BCMDBUS)
1611 if (!ret) {
1612 if (dhd_dev_init_ioctl(dev) < 0) {
1613 ret = -EFAULT;
1614 goto err;
1615 }
1616 }
1617 #endif /* BCMSDIO || BCMDBUS */
1618 g_wifi_on = TRUE;
1619 }
1620
1621 exit:
1622 WL_MSG(dev->name, "Success\n");
1623 dhd_net_if_unlock(dev);
1624 return ret;
1625
1626 #if defined(BCMSDIO) || defined(BCMDBUS)
1627 err:
1628 dhd_net_bus_devreset(dev, TRUE);
1629 #ifdef BCMSDIO
1630 dhd_net_bus_suspend(dev);
1631 #endif /* BCMSDIO */
1632 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
1633 WL_MSG(dev->name, "Failed\n");
1634 dhd_net_if_unlock(dev);
1635 return ret;
1636 #endif /* BCMSDIO || BCMDBUS */
1637 }
1638
wl_android_wifi_off(struct net_device * dev,bool on_failure)1639 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
1640 {
1641 int ret = 0;
1642
1643 if (!dev) {
1644 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
1645 return -EINVAL;
1646 }
1647
1648 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
1649 ret = dhd_debug_uart_is_running(dev);
1650 if (ret) {
1651 ANDROID_ERROR(("%s - Debug UART App is running\n", __FUNCTION__));
1652 return -EBUSY;
1653 }
1654 #endif /* BCMPCIE && DHD_DEBUG_UART */
1655 dhd_net_if_lock(dev);
1656 WL_MSG(dev->name, "in g_wifi_on=%d, on_failure=%d\n", g_wifi_on, on_failure);
1657 if (g_wifi_on || on_failure) {
1658 #if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
1659 ret = dhd_net_bus_devreset(dev, TRUE);
1660 #if defined(BCMSDIO)
1661 dhd_net_bus_suspend(dev);
1662 #endif /* BCMSDIO */
1663 #endif /* BCMSDIO || BCMPCIE || BCMDBUS */
1664 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
1665 g_wifi_on = FALSE;
1666 #ifdef DHD_LOAD_CHIPALIVE
1667 dhd_chip_alive = FALSE;
1668 #endif
1669 }
1670 WL_MSG(dev->name, "out\n");
1671 dhd_net_if_unlock(dev);
1672
1673 return ret;
1674 }
1675
wl_android_set_fwpath(struct net_device * net,char * command,int total_len)1676 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
1677 {
1678 if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
1679 return -1;
1680 return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
1681 }
1682
1683 #ifdef CONNECTION_STATISTICS
1684 static int
wl_chanim_stats(struct net_device * dev,u8 * chan_idle)1685 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
1686 {
1687 int err;
1688 wl_chanim_stats_t *list;
1689 /* Parameter _and_ returned buffer of chanim_stats. */
1690 wl_chanim_stats_t param;
1691 u8 result[WLC_IOCTL_SMLEN];
1692 chanim_stats_t *stats;
1693
1694 memset(¶m, 0, sizeof(param));
1695
1696 param.buflen = htod32(sizeof(wl_chanim_stats_t));
1697 param.count = htod32(WL_CHANIM_COUNT_ONE);
1698
1699 if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)¶m, sizeof(wl_chanim_stats_t),
1700 (char*)result, sizeof(result), 0)) < 0) {
1701 ANDROID_ERROR(("Failed to get chanim results %d \n", err));
1702 return err;
1703 }
1704
1705 list = (wl_chanim_stats_t*)result;
1706
1707 list->buflen = dtoh32(list->buflen);
1708 list->version = dtoh32(list->version);
1709 list->count = dtoh32(list->count);
1710
1711 if (list->buflen == 0) {
1712 list->version = 0;
1713 list->count = 0;
1714 } else if (list->version != WL_CHANIM_STATS_VERSION) {
1715 ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d "
1716 "but driver supports only version %d.\n",
1717 list->version, WL_CHANIM_STATS_VERSION));
1718 list->buflen = 0;
1719 list->count = 0;
1720 }
1721
1722 stats = list->stats;
1723 stats->glitchcnt = dtoh32(stats->glitchcnt);
1724 stats->badplcp = dtoh32(stats->badplcp);
1725 stats->chanspec = dtoh16(stats->chanspec);
1726 stats->timestamp = dtoh32(stats->timestamp);
1727 stats->chan_idle = dtoh32(stats->chan_idle);
1728
1729 ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
1730 stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
1731 stats->timestamp));
1732
1733 *chan_idle = stats->chan_idle;
1734
1735 return (err);
1736 }
1737
1738 static int
wl_android_get_connection_stats(struct net_device * dev,char * command,int total_len)1739 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
1740 {
1741 static char iovar_buf[WLC_IOCTL_MAXLEN];
1742 wl_cnt_wlc_t* wlc_cnt = NULL;
1743 #ifndef DISABLE_IF_COUNTERS
1744 wl_if_stats_t* if_stats = NULL;
1745 #endif /* DISABLE_IF_COUNTERS */
1746
1747 int link_speed = 0;
1748 struct connection_stats *output;
1749 unsigned int bufsize = 0;
1750 int bytes_written = -1;
1751 int ret = 0;
1752
1753 ANDROID_INFO(("%s: enter Get Connection Stats\n", __FUNCTION__));
1754
1755 if (total_len <= 0) {
1756 ANDROID_ERROR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len));
1757 goto error;
1758 }
1759
1760 bufsize = total_len;
1761 if (bufsize < sizeof(struct connection_stats)) {
1762 ANDROID_ERROR(("%s: not enough buffer size, provided=%u, requires=%zu\n",
1763 __FUNCTION__, bufsize,
1764 sizeof(struct connection_stats)));
1765 goto error;
1766 }
1767
1768 output = (struct connection_stats *)command;
1769
1770 #ifndef DISABLE_IF_COUNTERS
1771 if ((if_stats = kmalloc(sizeof(*if_stats), GFP_KERNEL)) == NULL) {
1772 ANDROID_ERROR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__));
1773 goto error;
1774 }
1775 memset(if_stats, 0, sizeof(*if_stats));
1776
1777 ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
1778 (char *)if_stats, sizeof(*if_stats), NULL);
1779 if (ret) {
1780 ANDROID_ERROR(("%s: if_counters not supported ret=%d\n",
1781 __FUNCTION__, ret));
1782
1783 /* In case if_stats IOVAR is not supported, get information from counters. */
1784 #endif /* DISABLE_IF_COUNTERS */
1785 ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
1786 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
1787 if (unlikely(ret)) {
1788 ANDROID_ERROR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
1789 goto error;
1790 }
1791 ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
1792 if (ret != BCME_OK) {
1793 ANDROID_ERROR(("%s wl_cntbuf_to_xtlv_format ERR %d\n",
1794 __FUNCTION__, ret));
1795 goto error;
1796 }
1797
1798 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
1799 ANDROID_ERROR(("%s wlc_cnt NULL!\n", __FUNCTION__));
1800 goto error;
1801 }
1802
1803 output->txframe = dtoh32(wlc_cnt->txframe);
1804 output->txbyte = dtoh32(wlc_cnt->txbyte);
1805 output->txerror = dtoh32(wlc_cnt->txerror);
1806 output->rxframe = dtoh32(wlc_cnt->rxframe);
1807 output->rxbyte = dtoh32(wlc_cnt->rxbyte);
1808 output->txfail = dtoh32(wlc_cnt->txfail);
1809 output->txretry = dtoh32(wlc_cnt->txretry);
1810 output->txretrie = dtoh32(wlc_cnt->txretrie);
1811 output->txrts = dtoh32(wlc_cnt->txrts);
1812 output->txnocts = dtoh32(wlc_cnt->txnocts);
1813 output->txexptime = dtoh32(wlc_cnt->txexptime);
1814 #ifndef DISABLE_IF_COUNTERS
1815 } else {
1816 /* Populate from if_stats. */
1817 if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
1818 ANDROID_ERROR(("%s: incorrect version of wl_if_stats_t, expected=%u got=%u\n",
1819 __FUNCTION__, WL_IF_STATS_T_VERSION, if_stats->version));
1820 goto error;
1821 }
1822
1823 output->txframe = (uint32)dtoh64(if_stats->txframe);
1824 output->txbyte = (uint32)dtoh64(if_stats->txbyte);
1825 output->txerror = (uint32)dtoh64(if_stats->txerror);
1826 output->rxframe = (uint32)dtoh64(if_stats->rxframe);
1827 output->rxbyte = (uint32)dtoh64(if_stats->rxbyte);
1828 output->txfail = (uint32)dtoh64(if_stats->txfail);
1829 output->txretry = (uint32)dtoh64(if_stats->txretry);
1830 output->txretrie = (uint32)dtoh64(if_stats->txretrie);
1831 if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
1832 output->txexptime = (uint32)dtoh64(if_stats->txexptime);
1833 output->txrts = (uint32)dtoh64(if_stats->txrts);
1834 output->txnocts = (uint32)dtoh64(if_stats->txnocts);
1835 } else {
1836 output->txexptime = 0;
1837 output->txrts = 0;
1838 output->txnocts = 0;
1839 }
1840 }
1841 #endif /* DISABLE_IF_COUNTERS */
1842
1843 /* link_speed is in kbps */
1844 ret = wldev_get_link_speed(dev, &link_speed);
1845 if (ret || link_speed < 0) {
1846 ANDROID_ERROR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n",
1847 __FUNCTION__, ret, link_speed));
1848 goto error;
1849 }
1850
1851 output->txrate = link_speed;
1852
1853 /* Channel idle ratio. */
1854 if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
1855 output->chan_idle = 0;
1856 };
1857
1858 bytes_written = sizeof(struct connection_stats);
1859
1860 error:
1861 #ifndef DISABLE_IF_COUNTERS
1862 if (if_stats) {
1863 kfree(if_stats);
1864 }
1865 #endif /* DISABLE_IF_COUNTERS */
1866
1867 return bytes_written;
1868 }
1869 #endif /* CONNECTION_STATISTICS */
1870
1871 #ifdef WL_NATOE
1872 static int
wl_android_process_natoe_cmd(struct net_device * dev,char * command,int total_len)1873 wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
1874 {
1875 int ret = BCME_ERROR;
1876 char *pcmd = command;
1877 char *str = NULL;
1878 wl_natoe_cmd_info_t cmd_info;
1879 const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
1880
1881 /* skip to cmd name after "natoe" */
1882 str = bcmstrtok(&pcmd, " ", NULL);
1883
1884 /* If natoe subcmd name is not provided, return error */
1885 if (*pcmd == '\0') {
1886 ANDROID_ERROR(("natoe subcmd not provided %s\n", __FUNCTION__));
1887 ret = -EINVAL;
1888 return ret;
1889 }
1890
1891 /* get the natoe command name to str */
1892 str = bcmstrtok(&pcmd, " ", NULL);
1893
1894 while (natoe_cmd->name != NULL) {
1895 if (strcmp(natoe_cmd->name, str) == 0) {
1896 /* dispacth cmd to appropriate handler */
1897 if (natoe_cmd->handler) {
1898 cmd_info.command = command;
1899 cmd_info.tot_len = total_len;
1900 ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
1901 }
1902 return ret;
1903 }
1904 natoe_cmd++;
1905 }
1906 return ret;
1907 }
1908
1909 static int
wlu_natoe_set_vars_cbfn(void * ctx,uint8 * data,uint16 type,uint16 len)1910 wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
1911 {
1912 int res = BCME_OK;
1913 wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
1914 uint8 *command = cmd_info->command;
1915 uint16 total_len = cmd_info->tot_len;
1916 uint16 bytes_written = 0;
1917
1918 UNUSED_PARAMETER(len);
1919
1920 switch (type) {
1921
1922 case WL_NATOE_XTLV_ENABLE:
1923 {
1924 bytes_written = snprintf(command, total_len, "natoe: %s\n",
1925 *data?"enabled":"disabled");
1926 cmd_info->bytes_written = bytes_written;
1927 break;
1928 }
1929
1930 case WL_NATOE_XTLV_CONFIG_IPS:
1931 {
1932 wl_natoe_config_ips_t *config_ips;
1933 uint8 buf[16];
1934
1935 config_ips = (wl_natoe_config_ips_t *)data;
1936 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
1937 bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
1938 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
1939 bytes_written += snprintf(command + bytes_written, total_len,
1940 "sta netmask: %s\n", buf);
1941 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
1942 bytes_written += snprintf(command + bytes_written, total_len,
1943 "sta router ip: %s\n", buf);
1944 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
1945 bytes_written += snprintf(command + bytes_written, total_len,
1946 "sta dns ip: %s\n", buf);
1947 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
1948 bytes_written += snprintf(command + bytes_written, total_len,
1949 "ap ip: %s\n", buf);
1950 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
1951 bytes_written += snprintf(command + bytes_written, total_len,
1952 "ap netmask: %s\n", buf);
1953 cmd_info->bytes_written = bytes_written;
1954 break;
1955 }
1956
1957 case WL_NATOE_XTLV_CONFIG_PORTS:
1958 {
1959 wl_natoe_ports_config_t *ports_config;
1960
1961 ports_config = (wl_natoe_ports_config_t *)data;
1962 bytes_written = snprintf(command, total_len, "starting port num: %d\n",
1963 dtoh16(ports_config->start_port_num));
1964 bytes_written += snprintf(command + bytes_written, total_len,
1965 "number of ports: %d\n", dtoh16(ports_config->no_of_ports));
1966 cmd_info->bytes_written = bytes_written;
1967 break;
1968 }
1969
1970 case WL_NATOE_XTLV_DBG_STATS:
1971 {
1972 char *stats_dump = (char *)data;
1973
1974 bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
1975 cmd_info->bytes_written = bytes_written;
1976 break;
1977 }
1978
1979 case WL_NATOE_XTLV_TBL_CNT:
1980 {
1981 bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
1982 dtoh32(*(uint32 *)data));
1983 cmd_info->bytes_written = bytes_written;
1984 break;
1985 }
1986
1987 default:
1988 /* ignore */
1989 break;
1990 }
1991
1992 return res;
1993 }
1994
1995 /*
1996 * --- common for all natoe get commands ----
1997 */
1998 static int
wl_natoe_get_ioctl(struct net_device * dev,wl_natoe_ioc_t * natoe_ioc,uint16 iocsz,uint8 * buf,uint16 buflen,wl_natoe_cmd_info_t * cmd_info)1999 wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
2000 uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
2001 {
2002 /* for gets we only need to pass ioc header */
2003 wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
2004 int res;
2005
2006 /* send getbuf natoe iovar */
2007 res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
2008 buflen, NULL);
2009
2010 /* check the response buff */
2011 if ((res == BCME_OK)) {
2012 /* scans ioctl tlvbuf f& invokes the cbfn for processing */
2013 res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
2014 BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
2015
2016 if (res == BCME_OK) {
2017 res = cmd_info->bytes_written;
2018 }
2019 }
2020 else
2021 {
2022 ANDROID_ERROR(("%s: get command failed code %d\n", __FUNCTION__, res));
2023 res = BCME_ERROR;
2024 }
2025
2026 return res;
2027 }
2028
2029 static int
wl_android_natoe_subcmd_enable(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)2030 wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
2031 char *command, wl_natoe_cmd_info_t *cmd_info)
2032 {
2033 int ret = BCME_OK;
2034 wl_natoe_ioc_t *natoe_ioc;
2035 char *pcmd = command;
2036 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2037 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
2038 uint16 buflen = WL_NATOE_IOC_BUFSZ;
2039 bcm_xtlv_t *pxtlv = NULL;
2040 char *ioctl_buf = NULL;
2041
2042 ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, kflags);
2043 if (!ioctl_buf) {
2044 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2045 return -ENOMEM;
2046 }
2047
2048 /* alloc mem for ioctl headr + tlv data */
2049 natoe_ioc = kzalloc(iocsz, kflags);
2050 if (!natoe_ioc) {
2051 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2052 kfree(ioctl_buf);
2053 return -ENOMEM;
2054 }
2055
2056 /* make up natoe cmd ioctl header */
2057 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2058 natoe_ioc->id = htod16(cmd->id);
2059 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
2060 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2061
2062 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2063 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2064 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2065 WLC_IOCTL_MEDLEN, cmd_info);
2066 if (ret != BCME_OK) {
2067 ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__));
2068 ret = -EINVAL;
2069 }
2070 } else { /* set */
2071 uint8 val = bcm_atoi(pcmd);
2072
2073 /* buflen is max tlv data we can write, it will be decremented as we pack */
2074 /* save buflen at start */
2075 uint16 buflen_at_start = buflen;
2076
2077 /* we'll adjust final ioc size at the end */
2078 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
2079 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
2080
2081 if (ret != BCME_OK) {
2082 ret = -EINVAL;
2083 goto exit;
2084 }
2085
2086 /* adjust iocsz to the end of last data record */
2087 natoe_ioc->len = (buflen_at_start - buflen);
2088 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2089
2090 ret = wldev_iovar_setbuf(dev, "natoe",
2091 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
2092 if (ret != BCME_OK) {
2093 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2094 ret = -EINVAL;
2095 }
2096 }
2097
2098 exit:
2099 kfree(ioctl_buf);
2100 kfree(natoe_ioc);
2101
2102 return ret;
2103 }
2104
2105 static int
wl_android_natoe_subcmd_config_ips(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)2106 wl_android_natoe_subcmd_config_ips(struct net_device *dev,
2107 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
2108 {
2109 int ret = BCME_OK;
2110 wl_natoe_config_ips_t config_ips;
2111 wl_natoe_ioc_t *natoe_ioc;
2112 char *pcmd = command;
2113 char *str;
2114 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2115 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
2116 uint16 buflen = WL_NATOE_IOC_BUFSZ;
2117 bcm_xtlv_t *pxtlv = NULL;
2118 char *ioctl_buf = NULL;
2119
2120 ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, kflags);
2121 if (!ioctl_buf) {
2122 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2123 return -ENOMEM;
2124 }
2125
2126 /* alloc mem for ioctl headr + tlv data */
2127 natoe_ioc = kzalloc(iocsz, kflags);
2128 if (!natoe_ioc) {
2129 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2130 kfree(ioctl_buf);
2131 return -ENOMEM;
2132 }
2133
2134 /* make up natoe cmd ioctl header */
2135 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2136 natoe_ioc->id = htod16(cmd->id);
2137 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
2138 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2139
2140 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2141 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2142 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2143 WLC_IOCTL_MEDLEN, cmd_info);
2144 if (ret != BCME_OK) {
2145 ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__));
2146 ret = -EINVAL;
2147 }
2148 } else { /* set */
2149 /* buflen is max tlv data we can write, it will be decremented as we pack */
2150 /* save buflen at start */
2151 uint16 buflen_at_start = buflen;
2152
2153 memset(&config_ips, 0, sizeof(config_ips));
2154
2155 str = bcmstrtok(&pcmd, " ", NULL);
2156 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
2157 ANDROID_ERROR(("Invalid STA IP addr %s\n", str));
2158 ret = -EINVAL;
2159 goto exit;
2160 }
2161
2162 str = bcmstrtok(&pcmd, " ", NULL);
2163 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
2164 ANDROID_ERROR(("Invalid STA netmask %s\n", str));
2165 ret = -EINVAL;
2166 goto exit;
2167 }
2168
2169 str = bcmstrtok(&pcmd, " ", NULL);
2170 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
2171 ANDROID_ERROR(("Invalid STA router IP addr %s\n", str));
2172 ret = -EINVAL;
2173 goto exit;
2174 }
2175
2176 str = bcmstrtok(&pcmd, " ", NULL);
2177 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
2178 ANDROID_ERROR(("Invalid STA DNS IP addr %s\n", str));
2179 ret = -EINVAL;
2180 goto exit;
2181 }
2182
2183 str = bcmstrtok(&pcmd, " ", NULL);
2184 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
2185 ANDROID_ERROR(("Invalid AP IP addr %s\n", str));
2186 ret = -EINVAL;
2187 goto exit;
2188 }
2189
2190 str = bcmstrtok(&pcmd, " ", NULL);
2191 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
2192 ANDROID_ERROR(("Invalid AP netmask %s\n", str));
2193 ret = -EINVAL;
2194 goto exit;
2195 }
2196
2197 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
2198 &buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
2199 &config_ips, BCM_XTLV_OPTION_ALIGN32);
2200
2201 if (ret != BCME_OK) {
2202 ret = -EINVAL;
2203 goto exit;
2204 }
2205
2206 /* adjust iocsz to the end of last data record */
2207 natoe_ioc->len = (buflen_at_start - buflen);
2208 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2209
2210 ret = wldev_iovar_setbuf(dev, "natoe",
2211 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
2212 if (ret != BCME_OK) {
2213 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2214 ret = -EINVAL;
2215 }
2216 }
2217
2218 exit:
2219 kfree(ioctl_buf);
2220 kfree(natoe_ioc);
2221
2222 return ret;
2223 }
2224
2225 static int
wl_android_natoe_subcmd_config_ports(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)2226 wl_android_natoe_subcmd_config_ports(struct net_device *dev,
2227 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
2228 {
2229 int ret = BCME_OK;
2230 wl_natoe_ports_config_t ports_config;
2231 wl_natoe_ioc_t *natoe_ioc;
2232 char *pcmd = command;
2233 char *str;
2234 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2235 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
2236 uint16 buflen = WL_NATOE_IOC_BUFSZ;
2237 bcm_xtlv_t *pxtlv = NULL;
2238 char *ioctl_buf = NULL;
2239
2240 ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, kflags);
2241 if (!ioctl_buf) {
2242 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2243 return -ENOMEM;
2244 }
2245
2246 /* alloc mem for ioctl headr + tlv data */
2247 natoe_ioc = kzalloc(iocsz, kflags);
2248 if (!natoe_ioc) {
2249 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2250 kfree(ioctl_buf);
2251 return -ENOMEM;
2252 }
2253
2254 /* make up natoe cmd ioctl header */
2255 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2256 natoe_ioc->id = htod16(cmd->id);
2257 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
2258 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2259
2260 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2261 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2262 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2263 WLC_IOCTL_MEDLEN, cmd_info);
2264 if (ret != BCME_OK) {
2265 ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__));
2266 ret = -EINVAL;
2267 }
2268 } else { /* set */
2269 /* buflen is max tlv data we can write, it will be decremented as we pack */
2270 /* save buflen at start */
2271 uint16 buflen_at_start = buflen;
2272
2273 memset(&ports_config, 0, sizeof(ports_config));
2274
2275 str = bcmstrtok(&pcmd, " ", NULL);
2276 if (!str) {
2277 ANDROID_ERROR(("Invalid port string %s\n", str));
2278 ret = -EINVAL;
2279 goto exit;
2280 }
2281 ports_config.start_port_num = htod16(bcm_atoi(str));
2282
2283 str = bcmstrtok(&pcmd, " ", NULL);
2284 if (!str) {
2285 ANDROID_ERROR(("Invalid port string %s\n", str));
2286 ret = -EINVAL;
2287 goto exit;
2288 }
2289 ports_config.no_of_ports = htod16(bcm_atoi(str));
2290
2291 if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
2292 NATOE_MAX_PORT_NUM) {
2293 ANDROID_ERROR(("Invalid port configuration\n"));
2294 ret = -EINVAL;
2295 goto exit;
2296 }
2297 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
2298 &buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
2299 &ports_config, BCM_XTLV_OPTION_ALIGN32);
2300
2301 if (ret != BCME_OK) {
2302 ret = -EINVAL;
2303 goto exit;
2304 }
2305
2306 /* adjust iocsz to the end of last data record */
2307 natoe_ioc->len = (buflen_at_start - buflen);
2308 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2309
2310 ret = wldev_iovar_setbuf(dev, "natoe",
2311 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
2312 if (ret != BCME_OK) {
2313 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2314 ret = -EINVAL;
2315 }
2316 }
2317
2318 exit:
2319 kfree(ioctl_buf);
2320 kfree(natoe_ioc);
2321
2322 return ret;
2323 }
2324
2325 static int
wl_android_natoe_subcmd_dbg_stats(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)2326 wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
2327 char *command, wl_natoe_cmd_info_t *cmd_info)
2328 {
2329 int ret = BCME_OK;
2330 wl_natoe_ioc_t *natoe_ioc;
2331 char *pcmd = command;
2332 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2333 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
2334 uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
2335 bcm_xtlv_t *pxtlv = NULL;
2336 char *ioctl_buf = NULL;
2337
2338 ioctl_buf = kzalloc(WLC_IOCTL_MAXLEN, kflags);
2339 if (!ioctl_buf) {
2340 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2341 return -ENOMEM;
2342 }
2343
2344 /* alloc mem for ioctl headr + tlv data */
2345 natoe_ioc = kzalloc(iocsz, kflags);
2346 if (!natoe_ioc) {
2347 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2348 kfree(ioctl_buf);
2349 return -ENOMEM;
2350 }
2351
2352 /* make up natoe cmd ioctl header */
2353 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2354 natoe_ioc->id = htod16(cmd->id);
2355 natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
2356 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2357
2358 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2359 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2360 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2361 WLC_IOCTL_MAXLEN, cmd_info);
2362 if (ret != BCME_OK) {
2363 ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__));
2364 ret = -EINVAL;
2365 }
2366 } else { /* set */
2367 uint8 val = bcm_atoi(pcmd);
2368
2369 /* buflen is max tlv data we can write, it will be decremented as we pack */
2370 /* save buflen at start */
2371 uint16 buflen_at_start = buflen;
2372
2373 /* we'll adjust final ioc size at the end */
2374 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
2375 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
2376
2377 if (ret != BCME_OK) {
2378 ret = -EINVAL;
2379 goto exit;
2380 }
2381
2382 /* adjust iocsz to the end of last data record */
2383 natoe_ioc->len = (buflen_at_start - buflen);
2384 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2385
2386 ret = wldev_iovar_setbuf(dev, "natoe",
2387 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
2388 if (ret != BCME_OK) {
2389 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2390 ret = -EINVAL;
2391 }
2392 }
2393
2394 exit:
2395 kfree(ioctl_buf);
2396 kfree(natoe_ioc);
2397
2398 return ret;
2399 }
2400
2401 static int
wl_android_natoe_subcmd_tbl_cnt(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)2402 wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
2403 char *command, wl_natoe_cmd_info_t *cmd_info)
2404 {
2405 int ret = BCME_OK;
2406 wl_natoe_ioc_t *natoe_ioc;
2407 char *pcmd = command;
2408 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2409 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
2410 uint16 buflen = WL_NATOE_IOC_BUFSZ;
2411 bcm_xtlv_t *pxtlv = NULL;
2412 char *ioctl_buf = NULL;
2413
2414 ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, kflags);
2415 if (!ioctl_buf) {
2416 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2417 return -ENOMEM;
2418 }
2419
2420 /* alloc mem for ioctl headr + tlv data */
2421 natoe_ioc = kzalloc(iocsz, kflags);
2422 if (!natoe_ioc) {
2423 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2424 kfree(ioctl_buf);
2425 return -ENOMEM;
2426 }
2427
2428 /* make up natoe cmd ioctl header */
2429 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2430 natoe_ioc->id = htod16(cmd->id);
2431 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
2432 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2433
2434 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2435 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2436 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2437 WLC_IOCTL_MEDLEN, cmd_info);
2438 if (ret != BCME_OK) {
2439 ANDROID_ERROR(("Fail to get iovar %s\n", __FUNCTION__));
2440 ret = -EINVAL;
2441 }
2442 } else { /* set */
2443 uint32 val = bcm_atoi(pcmd);
2444
2445 /* buflen is max tlv data we can write, it will be decremented as we pack */
2446 /* save buflen at start */
2447 uint16 buflen_at_start = buflen;
2448
2449 /* we'll adjust final ioc size at the end */
2450 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
2451 sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
2452
2453 if (ret != BCME_OK) {
2454 ret = -EINVAL;
2455 goto exit;
2456 }
2457
2458 /* adjust iocsz to the end of last data record */
2459 natoe_ioc->len = (buflen_at_start - buflen);
2460 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2461
2462 ret = wldev_iovar_setbuf(dev, "natoe",
2463 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
2464 if (ret != BCME_OK) {
2465 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2466 ret = -EINVAL;
2467 }
2468 }
2469
2470 exit:
2471 kfree(ioctl_buf);
2472 kfree(natoe_ioc);
2473
2474 return ret;
2475 }
2476
2477 #endif /* WL_NATOE */
2478
2479 #ifdef CUSTOMER_HW4_PRIVATE_CMD
2480 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
2481
2482 #if defined(WL_SUPPORT_AUTO_CHANNEL)
2483 /* SoftAP feature */
2484 #define APCS_BAND_2G_LEGACY1 20
2485 #define APCS_BAND_2G_LEGACY2 0
2486 #define APCS_BAND_AUTO "band=auto"
2487 #define APCS_BAND_2G "band=2g"
2488 #define APCS_BAND_5G "band=5g"
2489 #define APCS_MAX_2G_CHANNELS 11
2490 #define APCS_MAX_RETRY 10
2491 #define APCS_DEFAULT_2G_CH 1
2492 #define APCS_DEFAULT_5G_CH 149
2493
2494 static int
wl_android_set_auto_channel(struct net_device * dev,const char * cmd_str,char * command,int total_len)2495 wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
2496 char* command, int total_len)
2497 {
2498 int channel = 0;
2499 int chosen = 0;
2500 int retry = 0;
2501 int ret = 0;
2502 int spect = 0;
2503 u8 *reqbuf = NULL;
2504 uint32 band = WLC_BAND_2G, sta_band = WLC_BAND_2G;
2505 uint32 buf_size;
2506
2507 if (cmd_str) {
2508 ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
2509 if (strnicmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
2510 band = WLC_BAND_AUTO;
2511 } else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
2512 band = WLC_BAND_5G;
2513 } else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
2514 band = WLC_BAND_2G;
2515 } else {
2516 /*
2517 * For backward compatibility: Some platforms used to issue argument 20 or 0
2518 * to enforce the 2G channel selection
2519 */
2520 channel = bcm_atoi(cmd_str);
2521 if ((channel == APCS_BAND_2G_LEGACY1) ||
2522 (channel == APCS_BAND_2G_LEGACY2)) {
2523 band = WLC_BAND_2G;
2524 } else {
2525 ANDROID_ERROR(("Invalid argument\n"));
2526 return -EINVAL;
2527 }
2528 }
2529 } else {
2530 /* If no argument is provided, default to 2G */
2531 ANDROID_ERROR(("No argument given default to 2.4G scan\n"));
2532 band = WLC_BAND_2G;
2533 }
2534 ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
2535
2536 /* If STA is connected, return is STA channel, else ACS can be issued,
2537 * set spect to 0 and proceed with ACS
2538 */
2539 channel = wl_cfg80211_get_sta_channel(dev);
2540 if (channel) {
2541 sta_band = WL_GET_BAND(channel);
2542 switch (sta_band) {
2543 case (WL_CHANSPEC_BAND_5G): {
2544 if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) {
2545 channel = APCS_DEFAULT_2G_CH;
2546 }
2547 break;
2548 }
2549 case (WL_CHANSPEC_BAND_2G): {
2550 if (band == WLC_BAND_5G) {
2551 channel = APCS_DEFAULT_5G_CH;
2552 }
2553 break;
2554 }
2555 default:
2556 /* Intentional fall through to use same sta channel for softap */
2557 break;
2558 }
2559 WL_MSG(dev->name, "band=%d, sta_band=%d, channel=%d\n", band, sta_band, channel);
2560 goto done2;
2561 }
2562
2563 channel = wl_ext_autochannel(dev, ACS_FW_BIT|ACS_DRV_BIT, band);
2564 if (channel)
2565 goto done2;
2566 else
2567 goto done;
2568
2569 if ((ret =
2570 wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect))) < 0) {
2571 ANDROID_ERROR(("ACS: error getting the spect\n"));
2572 goto done;
2573 }
2574
2575 if (spect > 0) {
2576 /* If STA is connected, return is STA channel, else ACS can be issued,
2577 * set spect to 0 and proceed with ACS
2578 */
2579 channel = wl_cfg80211_get_sta_channel(dev);
2580 if (channel) {
2581 channel = (channel <= CH_MAX_2G_CHANNEL) ? channel : APCS_DEFAULT_2G_CH;
2582 goto done2;
2583 }
2584
2585 if ((ret = wl_cfg80211_set_spect(dev, 0) < 0)) {
2586 ANDROID_ERROR(("ACS: error while setting spect\n"));
2587 goto done;
2588 }
2589 }
2590
2591 reqbuf = kzalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL);
2592 if (reqbuf == NULL) {
2593 ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
2594 return -ENOMEM;
2595 }
2596
2597 if (band == WLC_BAND_AUTO) {
2598 ANDROID_INFO(("ACS full channel scan \n"));
2599 reqbuf[0] = htod32(0);
2600 } else if (band == WLC_BAND_5G) {
2601 ANDROID_INFO(("ACS 5G band scan \n"));
2602 if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
2603 ANDROID_ERROR(("ACS 5g chanspec retreival failed! \n"));
2604 goto done;
2605 }
2606 } else if (band == WLC_BAND_2G) {
2607 /*
2608 * If channel argument is not provided/ argument 20 is provided,
2609 * Restrict channel to 2GHz, 20MHz BW, No SB
2610 */
2611 ANDROID_INFO(("ACS 2G band scan \n"));
2612 if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
2613 ANDROID_ERROR(("ACS 2g chanspec retreival failed! \n"));
2614 goto done;
2615 }
2616 } else {
2617 ANDROID_ERROR(("ACS: No band chosen\n"));
2618 goto done2;
2619 }
2620
2621 buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
2622 ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
2623 buf_size);
2624 if (ret < 0) {
2625 ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret));
2626 channel = 0;
2627 goto done;
2628 }
2629
2630 /* Wait for auto channel selection, max 3000 ms */
2631 if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) {
2632 OSL_SLEEP(500);
2633 } else {
2634 /*
2635 * Full channel scan at the minimum takes 1.2secs
2636 * even with parallel scan. max wait time: 3500ms
2637 */
2638 OSL_SLEEP(1000);
2639 }
2640
2641 retry = APCS_MAX_RETRY;
2642 while (retry--) {
2643 ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
2644 sizeof(chosen));
2645 if (ret < 0) {
2646 chosen = 0;
2647 } else {
2648 chosen = dtoh32(chosen);
2649 }
2650
2651 if (chosen) {
2652 int chosen_band;
2653 int apcs_band;
2654 #ifdef D11AC_IOTYPES
2655 if (wl_cfg80211_get_ioctl_version() == 1) {
2656 channel = LCHSPEC_CHANNEL((chanspec_t)chosen);
2657 } else {
2658 channel = CHSPEC_CHANNEL((chanspec_t)chosen);
2659 }
2660 #else
2661 channel = CHSPEC_CHANNEL((chanspec_t)chosen);
2662 #endif /* D11AC_IOTYPES */
2663 apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band;
2664 chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G;
2665 if (apcs_band == chosen_band) {
2666 WL_MSG(dev->name, "selected channel = %d\n", channel);
2667 break;
2668 }
2669 }
2670 ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x\n",
2671 (APCS_MAX_RETRY - retry), ret, chosen));
2672 OSL_SLEEP(250);
2673 }
2674
2675 done:
2676 if ((retry == 0) || (ret < 0)) {
2677 /* On failure, fallback to a default channel */
2678 if ((band == WLC_BAND_5G)) {
2679 channel = APCS_DEFAULT_5G_CH;
2680 } else {
2681 channel = APCS_DEFAULT_2G_CH;
2682 }
2683 ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel));
2684 }
2685 done2:
2686 if (spect > 0) {
2687 if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) {
2688 ANDROID_ERROR(("ACS: error while setting spect\n"));
2689 }
2690 }
2691
2692 if (reqbuf) {
2693 kfree(reqbuf);
2694 }
2695
2696 if (channel) {
2697 snprintf(command, 4, "%d", channel);
2698 ANDROID_INFO(("command result is %s \n", command));
2699 return strlen(command);
2700 } else {
2701 return ret;
2702 }
2703 }
2704 #endif /* WL_SUPPORT_AUTO_CHANNEL */
2705
2706 #ifdef CUSTOMER_HW4_PRIVATE_CMD
2707
2708
2709 #ifdef SUPPORT_SET_LPC
2710 static int
wl_android_set_lpc(struct net_device * dev,const char * string_num)2711 wl_android_set_lpc(struct net_device *dev, const char* string_num)
2712 {
2713 int lpc_enabled, ret;
2714 s32 val = 1;
2715
2716 lpc_enabled = bcm_atoi(string_num);
2717 ANDROID_INFO(("%s : HAPD_LPC_ENABLED = %d\n", __FUNCTION__, lpc_enabled));
2718
2719 ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
2720 if (ret < 0)
2721 ANDROID_ERROR(("WLC_DOWN error %d\n", ret));
2722
2723 wldev_iovar_setint(dev, "lpc", lpc_enabled);
2724
2725 ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
2726 if (ret < 0)
2727 ANDROID_ERROR(("WLC_UP error %d\n", ret));
2728
2729 return 1;
2730 }
2731 #endif /* SUPPORT_SET_LPC */
2732
2733 static int
wl_android_ch_res_rl(struct net_device * dev,bool change)2734 wl_android_ch_res_rl(struct net_device *dev, bool change)
2735 {
2736 int error = 0;
2737 s32 srl = 7;
2738 s32 lrl = 4;
2739 printk("%s enter\n", __FUNCTION__);
2740 if (change) {
2741 srl = 4;
2742 lrl = 2;
2743 }
2744 error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
2745 if (error) {
2746 ANDROID_ERROR(("Failed to set SRL, error = %d\n", error));
2747 }
2748 error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
2749 if (error) {
2750 ANDROID_ERROR(("Failed to set LRL, error = %d\n", error));
2751 }
2752 return error;
2753 }
2754
2755
2756 #ifdef WL_RELMCAST
2757 static int
wl_android_rmc_enable(struct net_device * net,int rmc_enable)2758 wl_android_rmc_enable(struct net_device *net, int rmc_enable)
2759 {
2760 int err;
2761
2762 err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
2763 return err;
2764 }
2765
2766 static int
wl_android_rmc_set_leader(struct net_device * dev,const char * straddr)2767 wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
2768 {
2769 int error = BCME_OK;
2770 char smbuf[WLC_IOCTL_SMLEN];
2771 wl_rmc_entry_t rmc_entry;
2772 ANDROID_INFO(("%s: Set new RMC leader %s\n", __FUNCTION__, straddr));
2773
2774 memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t));
2775 if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
2776 if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
2777 ANDROID_INFO(("%s: Set auto leader selection mode\n", __FUNCTION__));
2778 memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t));
2779 } else {
2780 ANDROID_ERROR(("%s: No valid mac address provided\n",
2781 __FUNCTION__));
2782 return BCME_ERROR;
2783 }
2784 }
2785
2786 error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
2787 smbuf, sizeof(smbuf), NULL);
2788
2789 if (error != BCME_OK) {
2790 ANDROID_ERROR(("%s: Unable to set RMC leader, error = %d\n",
2791 __FUNCTION__, error));
2792 }
2793
2794 return error;
2795 }
2796
wl_android_set_rmc_event(struct net_device * dev,char * command,int total_len)2797 static int wl_android_set_rmc_event(struct net_device *dev, char *command, int total_len)
2798 {
2799 int err = 0;
2800 int pid = 0;
2801
2802 if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
2803 ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
2804 return -1;
2805 }
2806
2807 /* set pid, and if the event was happened, let's send a notification through netlink */
2808 wl_cfg80211_set_rmc_pid(dev, pid);
2809
2810 ANDROID_TRACE(("RMC pid=%d\n", pid));
2811
2812 return err;
2813 }
2814 #endif /* WL_RELMCAST */
2815
wl_android_get_singlecore_scan(struct net_device * dev,char * command,int total_len)2816 int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
2817 {
2818 int error = 0;
2819 int bytes_written = 0;
2820 int mode = 0;
2821
2822 error = wldev_iovar_getint(dev, "scan_ps", &mode);
2823 if (error) {
2824 ANDROID_ERROR(("%s: Failed to get single core scan Mode, error = %d\n",
2825 __FUNCTION__, error));
2826 return -1;
2827 }
2828
2829 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
2830
2831 return bytes_written;
2832 }
2833
wl_android_set_singlecore_scan(struct net_device * dev,char * command,int total_len)2834 int wl_android_set_singlecore_scan(struct net_device *dev, char *command, int total_len)
2835 {
2836 int error = 0;
2837 int mode = 0;
2838
2839 if (sscanf(command, "%*s %d", &mode) != 1) {
2840 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
2841 return -1;
2842 }
2843
2844 error = wldev_iovar_setint(dev, "scan_ps", mode);
2845 if (error) {
2846 ANDROID_ERROR(("%s[1]: Failed to set Mode %d, error = %d\n",
2847 __FUNCTION__, mode, error));
2848 return -1;
2849 }
2850
2851 return error;
2852 }
2853 #ifdef TEST_TX_POWER_CONTROL
2854 static int
wl_android_set_tx_power(struct net_device * dev,const char * string_num)2855 wl_android_set_tx_power(struct net_device *dev, const char* string_num)
2856 {
2857 int err = 0;
2858 s32 dbm;
2859 enum nl80211_tx_power_setting type;
2860
2861 dbm = bcm_atoi(string_num);
2862
2863 if (dbm < -1) {
2864 ANDROID_ERROR(("%s: dbm is negative...\n", __FUNCTION__));
2865 return -EINVAL;
2866 }
2867
2868 if (dbm == -1)
2869 type = NL80211_TX_POWER_AUTOMATIC;
2870 else
2871 type = NL80211_TX_POWER_FIXED;
2872
2873 err = wl_set_tx_power(dev, type, dbm);
2874 if (unlikely(err)) {
2875 ANDROID_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
2876 return err;
2877 }
2878
2879 return 1;
2880 }
2881
2882 static int
wl_android_get_tx_power(struct net_device * dev,char * command,int total_len)2883 wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
2884 {
2885 int err;
2886 int bytes_written;
2887 s32 dbm = 0;
2888
2889 err = wl_get_tx_power(dev, &dbm);
2890 if (unlikely(err)) {
2891 ANDROID_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
2892 return err;
2893 }
2894
2895 bytes_written = snprintf(command, total_len, "%s %d",
2896 CMD_TEST_GET_TX_POWER, dbm);
2897
2898 ANDROID_ERROR(("%s: GET_TX_POWER: dBm=%d\n", __FUNCTION__, dbm));
2899
2900 return bytes_written;
2901 }
2902 #endif /* TEST_TX_POWER_CONTROL */
2903
2904 static int
wl_android_set_sarlimit_txctrl(struct net_device * dev,const char * string_num)2905 wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
2906 {
2907 int err = 0;
2908 int setval = 0;
2909 s32 mode = bcm_atoi(string_num);
2910
2911 /* '0' means activate sarlimit
2912 * and '-1' means back to normal state (deactivate sarlimit)
2913 */
2914 if (mode == 0) {
2915 ANDROID_INFO(("%s: SAR limit control activated\n", __FUNCTION__));
2916 setval = 1;
2917 } else if (mode == -1) {
2918 ANDROID_INFO(("%s: SAR limit control deactivated\n", __FUNCTION__));
2919 setval = 0;
2920 } else {
2921 return -EINVAL;
2922 }
2923
2924 err = wldev_iovar_setint(dev, "sar_enable", setval);
2925 if (unlikely(err)) {
2926 ANDROID_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
2927 return err;
2928 }
2929 return 1;
2930 }
2931 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
2932
wl_android_set_roam_mode(struct net_device * dev,char * command,int total_len)2933 int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len)
2934 {
2935 int error = 0;
2936 int mode = 0;
2937
2938 if (sscanf(command, "%*s %d", &mode) != 1) {
2939 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
2940 return -1;
2941 }
2942
2943 error = wldev_iovar_setint(dev, "roam_off", mode);
2944 if (error) {
2945 ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
2946 __FUNCTION__, mode, error));
2947 return -1;
2948 }
2949 else
2950 ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
2951 __FUNCTION__, mode, error));
2952 return 0;
2953 }
2954
2955 #ifdef WL_CFG80211
wl_android_set_ibss_beacon_ouidata(struct net_device * dev,char * command,int total_len)2956 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
2957 {
2958 char ie_buf[VNDR_IE_MAX_LEN];
2959 char *ioctl_buf = NULL;
2960 char hex[] = "XX";
2961 char *pcmd = NULL;
2962 int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
2963 vndr_ie_setbuf_t *vndr_ie = NULL;
2964 s32 iecount;
2965 uint32 pktflag;
2966 u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2967 s32 err = BCME_OK, bssidx;
2968 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2969
2970 /* Check the VSIE (Vendor Specific IE) which was added.
2971 * If exist then send IOVAR to delete it
2972 */
2973 if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
2974 return -EINVAL;
2975 }
2976
2977 if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
2978 ANDROID_ERROR(("error. total_len:%d\n", total_len));
2979 return -EINVAL;
2980 }
2981
2982 pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
2983 for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
2984 if (*pcmd == '\0') {
2985 ANDROID_ERROR(("error while parsing OUI.\n"));
2986 return -EINVAL;
2987 }
2988 hex[0] = *pcmd++;
2989 hex[1] = *pcmd++;
2990 ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16);
2991 }
2992 pcmd++;
2993 while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
2994 hex[0] = *pcmd++;
2995 hex[1] = *pcmd++;
2996 ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16);
2997 datalen++;
2998 }
2999
3000 if (datalen <= 0) {
3001 ANDROID_ERROR(("error. vndr ie len:%d\n", datalen));
3002 return -EINVAL;
3003 }
3004
3005 tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
3006 vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
3007 if (!vndr_ie) {
3008 ANDROID_ERROR(("IE memory alloc failed\n"));
3009 return -ENOMEM;
3010 }
3011 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
3012 strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1);
3013 vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
3014
3015 /* Set the IE count - the buffer contains only 1 IE */
3016 iecount = htod32(1);
3017 memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
3018
3019 /* Set packet flag to indicate that BEACON's will contain this IE */
3020 pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
3021 memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
3022 sizeof(u32));
3023 /* Set the IE ID */
3024 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
3025
3026 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
3027 DOT11_OUI_LEN);
3028 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
3029 &ie_buf[DOT11_OUI_LEN], datalen);
3030
3031 ielen = DOT11_OUI_LEN + datalen;
3032 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
3033
3034 ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
3035 if (!ioctl_buf) {
3036 ANDROID_ERROR(("ioctl memory alloc failed\n"));
3037 if (vndr_ie) {
3038 kfree(vndr_ie);
3039 }
3040 return -ENOMEM;
3041 }
3042 memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
3043 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3044 ANDROID_ERROR(("Find index failed\n"));
3045 err = BCME_ERROR;
3046 goto end;
3047 }
3048 err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
3049 WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
3050
3051 end:
3052 if (err != BCME_OK) {
3053 err = -EINVAL;
3054 if (vndr_ie) {
3055 kfree(vndr_ie);
3056 }
3057 }
3058 else {
3059 /* do NOT free 'vndr_ie' for the next process */
3060 wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
3061 }
3062
3063 if (ioctl_buf) {
3064 kfree(ioctl_buf);
3065 }
3066
3067 return err;
3068 }
3069 #endif
3070
3071 #if defined(BCMFW_ROAM_ENABLE)
3072 static int
wl_android_set_roampref(struct net_device * dev,char * command,int total_len)3073 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
3074 {
3075 int error = 0;
3076 char smbuf[WLC_IOCTL_SMLEN];
3077 uint8 buf[MAX_BUF_SIZE];
3078 uint8 *pref = buf;
3079 char *pcmd;
3080 int num_ucipher_suites = 0;
3081 int num_akm_suites = 0;
3082 wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
3083 wpa_suite_t akm_suites[MAX_NUM_SUITES];
3084 int num_tuples = 0;
3085 int total_bytes = 0;
3086 int total_len_left;
3087 int i, j;
3088 char hex[] = "XX";
3089
3090 pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
3091 total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
3092
3093 num_akm_suites = simple_strtoul(pcmd, NULL, 16);
3094 if (num_akm_suites > MAX_NUM_SUITES) {
3095 ANDROID_ERROR(("too many AKM suites = %d\n", num_akm_suites));
3096 return -1;
3097 }
3098
3099 /* Increment for number of AKM suites field + space */
3100 pcmd += 3;
3101 total_len_left -= 3;
3102
3103 /* check to make sure pcmd does not overrun */
3104 if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
3105 return -1;
3106
3107 memset(buf, 0, sizeof(buf));
3108 memset(akm_suites, 0, sizeof(akm_suites));
3109 memset(ucipher_suites, 0, sizeof(ucipher_suites));
3110
3111 /* Save the AKM suites passed in the command */
3112 for (i = 0; i < num_akm_suites; i++) {
3113 /* Store the MSB first, as required by join_pref */
3114 for (j = 0; j < 4; j++) {
3115 hex[0] = *pcmd++;
3116 hex[1] = *pcmd++;
3117 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
3118 }
3119 memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
3120 }
3121
3122 total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
3123 num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
3124 /* Increment for number of cipher suites field + space */
3125 pcmd += 3;
3126 total_len_left -= 3;
3127
3128 if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
3129 return -1;
3130
3131 /* Save the cipher suites passed in the command */
3132 for (i = 0; i < num_ucipher_suites; i++) {
3133 /* Store the MSB first, as required by join_pref */
3134 for (j = 0; j < 4; j++) {
3135 hex[0] = *pcmd++;
3136 hex[1] = *pcmd++;
3137 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
3138 }
3139 memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
3140 }
3141
3142 /* Join preference for RSSI
3143 * Type : 1 byte (0x01)
3144 * Length : 1 byte (0x02)
3145 * Value : 2 bytes (reserved)
3146 */
3147 *pref++ = WL_JOIN_PREF_RSSI;
3148 *pref++ = JOIN_PREF_RSSI_LEN;
3149 *pref++ = 0;
3150 *pref++ = 0;
3151
3152 /* Join preference for WPA
3153 * Type : 1 byte (0x02)
3154 * Length : 1 byte (not used)
3155 * Value : (variable length)
3156 * reserved: 1 byte
3157 * count : 1 byte (no of tuples)
3158 * Tuple1 : 12 bytes
3159 * akm[4]
3160 * ucipher[4]
3161 * mcipher[4]
3162 * Tuple2 : 12 bytes
3163 * Tuplen : 12 bytes
3164 */
3165 num_tuples = num_akm_suites * num_ucipher_suites;
3166 if (num_tuples != 0) {
3167 if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
3168 *pref++ = WL_JOIN_PREF_WPA;
3169 *pref++ = 0;
3170 *pref++ = 0;
3171 *pref++ = (uint8)num_tuples;
3172 total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
3173 (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
3174 } else {
3175 ANDROID_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
3176 return -1;
3177 }
3178 } else {
3179 /* No WPA config, configure only RSSI preference */
3180 total_bytes = JOIN_PREF_RSSI_SIZE;
3181 }
3182
3183 /* akm-ucipher-mcipher tuples in the format required for join_pref */
3184 for (i = 0; i < num_ucipher_suites; i++) {
3185 for (j = 0; j < num_akm_suites; j++) {
3186 memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
3187 pref += WPA_SUITE_LEN;
3188 memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
3189 pref += WPA_SUITE_LEN;
3190 /* Set to 0 to match any available multicast cipher */
3191 memset(pref, 0, WPA_SUITE_LEN);
3192 pref += WPA_SUITE_LEN;
3193 }
3194 }
3195
3196 prhex("join pref", (uint8 *)buf, total_bytes);
3197 error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
3198 if (error) {
3199 ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
3200 }
3201 return error;
3202 }
3203 #endif /* defined(BCMFW_ROAM_ENABLE */
3204
3205 #ifdef WL_CFG80211
3206 static int
wl_android_iolist_add(struct net_device * dev,struct list_head * head,struct io_cfg * config)3207 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
3208 {
3209 struct io_cfg *resume_cfg;
3210 s32 ret;
3211
3212 resume_cfg = kzalloc(sizeof(struct io_cfg), GFP_KERNEL);
3213 if (!resume_cfg)
3214 return -ENOMEM;
3215
3216 if (config->iovar) {
3217 ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
3218 if (ret) {
3219 ANDROID_ERROR(("%s: Failed to get current %s value\n",
3220 __FUNCTION__, config->iovar));
3221 goto error;
3222 }
3223
3224 ret = wldev_iovar_setint(dev, config->iovar, config->param);
3225 if (ret) {
3226 ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
3227 config->iovar, config->param));
3228 goto error;
3229 }
3230
3231 resume_cfg->iovar = config->iovar;
3232 } else {
3233 resume_cfg->arg = kzalloc(config->len, GFP_KERNEL);
3234 if (!resume_cfg->arg) {
3235 ret = -ENOMEM;
3236 goto error;
3237 }
3238 ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
3239 if (ret) {
3240 ANDROID_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
3241 config->ioctl));
3242 goto error;
3243 }
3244 ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
3245 if (ret) {
3246 ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
3247 config->iovar, config->param));
3248 goto error;
3249 }
3250 if (config->ioctl + 1 == WLC_SET_PM)
3251 wl_cfg80211_update_power_mode(dev);
3252 resume_cfg->ioctl = config->ioctl;
3253 resume_cfg->len = config->len;
3254 }
3255
3256 list_add(&resume_cfg->list, head);
3257
3258 return 0;
3259 error:
3260 kfree(resume_cfg->arg);
3261 kfree(resume_cfg);
3262 return ret;
3263 }
3264
3265 static void
wl_android_iolist_resume(struct net_device * dev,struct list_head * head)3266 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
3267 {
3268 struct io_cfg *config;
3269 struct list_head *cur, *q;
3270 s32 ret = 0;
3271
3272 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
3273 #pragma GCC diagnostic push
3274 #pragma GCC diagnostic ignored "-Wcast-qual"
3275 #endif
3276 list_for_each_safe(cur, q, head) {
3277 config = list_entry(cur, struct io_cfg, list);
3278 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
3279 #pragma GCC diagnostic pop
3280 #endif
3281 if (config->iovar) {
3282 if (!ret)
3283 ret = wldev_iovar_setint(dev, config->iovar,
3284 config->param);
3285 } else {
3286 if (!ret)
3287 ret = wldev_ioctl_set(dev, config->ioctl + 1,
3288 config->arg, config->len);
3289 if (config->ioctl + 1 == WLC_SET_PM)
3290 wl_cfg80211_update_power_mode(dev);
3291 kfree(config->arg);
3292 }
3293 list_del(cur);
3294 kfree(config);
3295 }
3296 }
3297 #ifdef WL11ULB
3298 static int
wl_android_set_ulb_mode(struct net_device * dev,char * command,int total_len)3299 wl_android_set_ulb_mode(struct net_device *dev, char *command, int total_len)
3300 {
3301 int mode = 0;
3302
3303 ANDROID_INFO(("set ulb mode (%s) \n", command));
3304 if (sscanf(command, "%*s %d", &mode) != 1) {
3305 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
3306 return -1;
3307 }
3308 return wl_cfg80211_set_ulb_mode(dev, mode);
3309 }
3310 static int
wl_android_set_ulb_bw(struct net_device * dev,char * command,int total_len)3311 wl_android_set_ulb_bw(struct net_device *dev, char *command, int total_len)
3312 {
3313 int bw = 0;
3314 u8 *pos;
3315 char *ifname = NULL;
3316 ANDROID_INFO(("set ulb bw (%s) \n", command));
3317
3318 /*
3319 * For sta/ap: IFNAME=<ifname> DRIVER ULB_BW <bw> ifname
3320 * For p2p: IFNAME=wlan0 DRIVER ULB_BW <bw> p2p-dev-wlan0
3321 */
3322 if (total_len < strlen(CMD_ULB_BW) + 2)
3323 return -EINVAL;
3324
3325 pos = command + strlen(CMD_ULB_BW) + 1;
3326 bw = bcm_atoi(pos);
3327
3328 if ((strlen(pos) >= 5)) {
3329 ifname = pos + 2;
3330 }
3331
3332 ANDROID_INFO(("[ULB] ifname:%s ulb_bw:%d \n", ifname, bw));
3333 return wl_cfg80211_set_ulb_bw(dev, bw, ifname);
3334 }
3335 #endif /* WL11ULB */
3336
3337 static int
wl_android_set_miracast(struct net_device * dev,char * command,int total_len)3338 wl_android_set_miracast(struct net_device *dev, char *command, int total_len)
3339 {
3340 int mode, val;
3341 int ret = 0;
3342 struct io_cfg config;
3343
3344 if (sscanf(command, "%*s %d", &mode) != 1) {
3345 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
3346 return -1;
3347 }
3348
3349 ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
3350
3351 if (miracast_cur_mode == mode) {
3352 return 0;
3353 }
3354
3355 wl_android_iolist_resume(dev, &miracast_resume_list);
3356 miracast_cur_mode = MIRACAST_MODE_OFF;
3357
3358 switch (mode) {
3359 case MIRACAST_MODE_SOURCE:
3360 /* setting mchan_algo to platform specific value */
3361 config.iovar = "mchan_algo";
3362
3363 ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
3364 if (!ret && val > 100) {
3365 config.param = 0;
3366 ANDROID_ERROR(("%s: Connected station's beacon interval: "
3367 "%d and set mchan_algo to %d \n",
3368 __FUNCTION__, val, config.param));
3369 } else {
3370 config.param = MIRACAST_MCHAN_ALGO;
3371 }
3372 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
3373 if (ret) {
3374 goto resume;
3375 }
3376
3377 /* setting mchan_bw to platform specific value */
3378 config.iovar = "mchan_bw";
3379 config.param = MIRACAST_MCHAN_BW;
3380 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
3381 if (ret) {
3382 goto resume;
3383 }
3384
3385 /* setting apmdu to platform specific value */
3386 config.iovar = "ampdu_mpdu";
3387 config.param = MIRACAST_AMPDU_SIZE;
3388 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
3389 if (ret) {
3390 goto resume;
3391 }
3392 /* FALLTROUGH */
3393 /* Source mode shares most configurations with sink mode.
3394 * Fall through here to avoid code duplication
3395 */
3396 case MIRACAST_MODE_SINK:
3397 /* disable internal roaming */
3398 config.iovar = "roam_off";
3399 config.param = 1;
3400 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
3401 if (ret) {
3402 goto resume;
3403 }
3404
3405 /* tunr off pm */
3406 ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
3407 if (ret) {
3408 goto resume;
3409 }
3410
3411 if (val != PM_OFF) {
3412 val = PM_OFF;
3413 config.iovar = NULL;
3414 config.ioctl = WLC_GET_PM;
3415 config.arg = &val;
3416 config.len = sizeof(int);
3417 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
3418 if (ret) {
3419 goto resume;
3420 }
3421 }
3422 break;
3423 case MIRACAST_MODE_OFF:
3424 default:
3425 break;
3426 }
3427 miracast_cur_mode = mode;
3428
3429 return 0;
3430
3431 resume:
3432 ANDROID_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
3433 wl_android_iolist_resume(dev, &miracast_resume_list);
3434 return ret;
3435 }
3436 #endif
3437
3438 #ifdef WL_RELMCAST
3439 #define NETLINK_OXYGEN 30
3440 #define AIBSS_BEACON_TIMEOUT 10
3441
3442 static struct sock *nl_sk = NULL;
3443
wl_netlink_recv(struct sk_buff * skb)3444 static void wl_netlink_recv(struct sk_buff *skb)
3445 {
3446 ANDROID_ERROR(("netlink_recv called\n"));
3447 }
3448
wl_netlink_init(void)3449 static int wl_netlink_init(void)
3450 {
3451 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
3452 struct netlink_kernel_cfg cfg = {
3453 .input = wl_netlink_recv,
3454 };
3455 #endif
3456
3457 if (nl_sk != NULL) {
3458 ANDROID_ERROR(("nl_sk already exist\n"));
3459 return BCME_ERROR;
3460 }
3461
3462 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
3463 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
3464 0, wl_netlink_recv, NULL, THIS_MODULE);
3465 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
3466 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
3467 #else
3468 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
3469 #endif
3470
3471 if (nl_sk == NULL) {
3472 ANDROID_ERROR(("nl_sk is not ready\n"));
3473 return BCME_ERROR;
3474 }
3475
3476 return BCME_OK;
3477 }
3478
wl_netlink_deinit(void)3479 static void wl_netlink_deinit(void)
3480 {
3481 if (nl_sk) {
3482 netlink_kernel_release(nl_sk);
3483 nl_sk = NULL;
3484 }
3485 }
3486
3487 s32
wl_netlink_send_msg(int pid,int type,int seq,const void * data,size_t size)3488 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
3489 {
3490 struct sk_buff *skb = NULL;
3491 struct nlmsghdr *nlh = NULL;
3492 int ret = -1;
3493
3494 if (nl_sk == NULL) {
3495 ANDROID_ERROR(("nl_sk was not initialized\n"));
3496 goto nlmsg_failure;
3497 }
3498
3499 skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
3500 if (skb == NULL) {
3501 ANDROID_ERROR(("failed to allocate memory\n"));
3502 goto nlmsg_failure;
3503 }
3504
3505 nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
3506 if (nlh == NULL) {
3507 ANDROID_ERROR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
3508 skb_tailroom(skb), nlmsg_total_size(size)));
3509 dev_kfree_skb(skb);
3510 goto nlmsg_failure;
3511 }
3512
3513 memcpy(nlmsg_data(nlh), data, size);
3514 nlh->nlmsg_seq = seq;
3515 nlh->nlmsg_type = type;
3516
3517 /* netlink_unicast() takes ownership of the skb and frees it itself. */
3518 ret = netlink_unicast(nl_sk, skb, pid, 0);
3519 ANDROID_TRACE(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
3520
3521 nlmsg_failure:
3522 return ret;
3523 }
3524 #endif /* WL_RELMCAST */
3525
wl_keep_alive_set(struct net_device * dev,char * extra,int total_len)3526 int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len)
3527 {
3528 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
3529 int ret;
3530 uint period_msec = 0;
3531 char *buf;
3532
3533 if (extra == NULL) {
3534 ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__));
3535 return -1;
3536 }
3537 if (sscanf(extra, "%d", &period_msec) != 1) {
3538 ANDROID_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
3539 return -EINVAL;
3540 }
3541 ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
3542
3543 memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
3544
3545 mkeep_alive_pkt.period_msec = period_msec;
3546 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
3547 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
3548
3549 /* Setup keep alive zero for null packet generation */
3550 mkeep_alive_pkt.keep_alive_id = 0;
3551 mkeep_alive_pkt.len_bytes = 0;
3552
3553 buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
3554 if (!buf) {
3555 ANDROID_ERROR(("%s: buffer alloc failed\n", __FUNCTION__));
3556 return BCME_NOMEM;
3557 }
3558 ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
3559 WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
3560 if (ret < 0)
3561 ANDROID_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret));
3562 else
3563 ANDROID_TRACE(("%s:keep_alive set ok\n", __FUNCTION__));
3564 kfree(buf);
3565 return ret;
3566 }
3567
3568 #ifdef P2PRESP_WFDIE_SRC
wl_android_get_wfdie_resp(struct net_device * dev,char * command,int total_len)3569 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
3570 {
3571 int error = 0;
3572 int bytes_written = 0;
3573 int only_resp_wfdsrc = 0;
3574
3575 error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
3576 if (error) {
3577 ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
3578 __FUNCTION__, error));
3579 return -1;
3580 }
3581
3582 bytes_written = snprintf(command, total_len, "%s %d",
3583 CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
3584
3585 return bytes_written;
3586 }
3587
wl_android_set_wfdie_resp(struct net_device * dev,int only_resp_wfdsrc)3588 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
3589 {
3590 int error = 0;
3591
3592 error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
3593 if (error) {
3594 ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
3595 __FUNCTION__, only_resp_wfdsrc, error));
3596 return -1;
3597 }
3598
3599 return 0;
3600 }
3601 #endif /* P2PRESP_WFDIE_SRC */
3602
3603 #ifdef BT_WIFI_HANDOVER
3604 static int
wl_tbow_teardown(struct net_device * dev,char * command,int total_len)3605 wl_tbow_teardown(struct net_device *dev, char *command, int total_len)
3606 {
3607 int err = BCME_OK;
3608 char buf[WLC_IOCTL_SMLEN];
3609 tbow_setup_netinfo_t netinfo;
3610 memset(&netinfo, 0, sizeof(netinfo));
3611 netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
3612
3613 err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
3614 sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
3615 if (err < 0) {
3616 ANDROID_ERROR(("tbow_doho iovar error %d\n", err));
3617 return err;
3618 }
3619 return err;
3620 }
3621 #endif /* BT_WIFI_HANOVER */
3622
3623 #ifdef SET_RPS_CPUS
3624 static int
wl_android_set_rps_cpus(struct net_device * dev,char * command,int total_len)3625 wl_android_set_rps_cpus(struct net_device *dev, char *command, int total_len)
3626 {
3627 int error, enable;
3628
3629 enable = command[strlen(CMD_RPSMODE) + 1] - '0';
3630 error = dhd_rps_cpus_enable(dev, enable);
3631
3632 #if defined(DHDTCPACK_SUPPRESS) && defined(BCMPCIE) && defined(WL_CFG80211)
3633 if (!error) {
3634 void *dhdp = wl_cfg80211_get_dhdp(net);
3635 if (enable) {
3636 ANDROID_TRACE(("%s : set ack suppress. TCPACK_SUP_HOLD.\n", __FUNCTION__));
3637 dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_HOLD);
3638 } else {
3639 ANDROID_TRACE(("%s : clear ack suppress.\n", __FUNCTION__));
3640 dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
3641 }
3642 }
3643 #endif /* DHDTCPACK_SUPPRESS && BCMPCIE && WL_CFG80211 */
3644
3645 return error;
3646 }
3647 #endif /* SET_RPS_CPUS */
3648
wl_android_get_link_status(struct net_device * dev,char * command,int total_len)3649 static int wl_android_get_link_status(struct net_device *dev, char *command,
3650 int total_len)
3651 {
3652 int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
3653 uint32 rspec;
3654 uint encode, rate, txexp;
3655 struct wl_bss_info *bi;
3656 int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
3657 char buf[datalen];
3658
3659 /* get BSS information */
3660 *(u32 *) buf = htod32(datalen);
3661 error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
3662 if (unlikely(error)) {
3663 ANDROID_ERROR(("Could not get bss info %d\n", error));
3664 return -1;
3665 }
3666
3667 bi = (struct wl_bss_info *) (buf + sizeof(uint32));
3668
3669 for (i = 0; i < ETHER_ADDR_LEN; i++) {
3670 if (bi->BSSID.octet[i] > 0) {
3671 break;
3672 }
3673 }
3674
3675 if (i == ETHER_ADDR_LEN) {
3676 ANDROID_TRACE(("No BSSID\n"));
3677 return -1;
3678 }
3679
3680 /* check VHT capability at beacon */
3681 if (bi->vht_cap) {
3682 if (CHSPEC_IS5G(bi->chanspec)) {
3683 result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
3684 }
3685 }
3686
3687 /* get a rspec (radio spectrum) rate */
3688 error = wldev_iovar_getint(dev, "nrate", &rspec);
3689 if (unlikely(error) || rspec == 0) {
3690 ANDROID_ERROR(("get link status error (%d)\n", error));
3691 return -1;
3692 }
3693
3694 encode = (rspec & WL_RSPEC_ENCODING_MASK);
3695 rate = (rspec & WL_RSPEC_RATE_MASK);
3696 txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
3697
3698 switch (encode) {
3699 case WL_RSPEC_ENCODE_HT:
3700 /* check Rx MCS Map for HT */
3701 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
3702 int8 bitmap = 0xFF;
3703 if (i == MAX_STREAMS_SUPPORTED-1) {
3704 bitmap = 0x7F;
3705 }
3706 if (bi->basic_mcs[i] & bitmap) {
3707 nss++;
3708 }
3709 }
3710 break;
3711 case WL_RSPEC_ENCODE_VHT:
3712 /* check Rx MCS Map for VHT */
3713 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
3714 mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
3715 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
3716 nss++;
3717 }
3718 }
3719 break;
3720 }
3721
3722 /* check MIMO capability with nss in beacon */
3723 if (nss > 1) {
3724 result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
3725 }
3726
3727 single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
3728 ((encode == WL_RSPEC_ENCODE_HT) && rate < 8) ||
3729 ((encode == WL_RSPEC_ENCODE_VHT) &&
3730 ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
3731
3732 if (txexp == 0) {
3733 if ((rspec & WL_RSPEC_STBC) && single_stream) {
3734 stf = OLD_NRATE_STF_STBC;
3735 } else {
3736 stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
3737 }
3738 } else if (txexp == 1 && single_stream) {
3739 stf = OLD_NRATE_STF_CDD;
3740 }
3741
3742 /* check 11ac (VHT) */
3743 if (encode == WL_RSPEC_ENCODE_VHT) {
3744 if (CHSPEC_IS5G(bi->chanspec)) {
3745 result |= WL_ANDROID_LINK_VHT;
3746 }
3747 }
3748
3749 /* check MIMO */
3750 if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
3751 switch (stf) {
3752 case OLD_NRATE_STF_SISO:
3753 break;
3754 case OLD_NRATE_STF_CDD:
3755 case OLD_NRATE_STF_STBC:
3756 result |= WL_ANDROID_LINK_MIMO;
3757 break;
3758 case OLD_NRATE_STF_SDM:
3759 if (!single_stream) {
3760 result |= WL_ANDROID_LINK_MIMO;
3761 }
3762 break;
3763 }
3764 }
3765
3766 ANDROID_TRACE(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
3767 __FUNCTION__, result, stf, single_stream, nss));
3768
3769 bytes_written = sprintf(command, "%s %d", CMD_GET_LINK_STATUS, result);
3770
3771 return bytes_written;
3772 }
3773
3774 #ifdef P2P_LISTEN_OFFLOADING
3775 s32
wl_cfg80211_p2plo_offload(struct net_device * dev,char * cmd,char * buf,int len)3776 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
3777 {
3778 int ret = 0;
3779
3780 ANDROID_ERROR(("Entry cmd:%s arg_len:%d \n", cmd, len));
3781
3782 if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
3783 ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
3784 } else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
3785 ret = wl_cfg80211_p2plo_listen_stop(dev);
3786 } else {
3787 ANDROID_ERROR(("Request for Unsupported CMD:%s \n", buf));
3788 ret = -EINVAL;
3789 }
3790 return ret;
3791 }
3792 #endif /* P2P_LISTEN_OFFLOADING */
3793
3794 #if defined(BCM4359_CHIP) && defined(WL_CFG80211)
3795 int
wl_android_murx_bfe_cap(struct net_device * dev,int val)3796 wl_android_murx_bfe_cap(struct net_device *dev, int val)
3797 {
3798 int err = BCME_OK;
3799 int iface_count = wl_cfg80211_iface_count(dev);
3800 struct ether_addr bssid;
3801 wl_reassoc_params_t params;
3802
3803 if (iface_count > 1) {
3804 ANDROID_ERROR(("murx_bfe_cap change is not allowed when "
3805 "there are multiple interfaces\n"));
3806 return -EINVAL;
3807 }
3808 /* Now there is only single interface */
3809 err = wldev_iovar_setint(dev, "murx_bfe_cap", val);
3810 if (unlikely(err)) {
3811 ANDROID_ERROR(("Failed to set murx_bfe_cap IOVAR to %d,"
3812 "error %d\n", val, err));
3813 return err;
3814 }
3815
3816 /* If successful intiate a reassoc */
3817 memset(&bssid, 0, ETHER_ADDR_LEN);
3818 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) {
3819 ANDROID_ERROR(("Failed to get bssid, error=%d\n", err));
3820 return err;
3821 }
3822
3823 bzero(¶ms, sizeof(wl_reassoc_params_t));
3824 memcpy(¶ms.bssid, &bssid, ETHER_ADDR_LEN);
3825
3826 if ((err = wldev_ioctl_set(dev, WLC_REASSOC, ¶ms,
3827 sizeof(wl_reassoc_params_t))) < 0) {
3828 ANDROID_ERROR(("reassoc failed err:%d \n", err));
3829 } else {
3830 ANDROID_TRACE(("reassoc issued successfully\n"));
3831 }
3832
3833 return err;
3834 }
3835 #endif /* BCM4359_CHIP */
3836
3837 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
3838 int
wl_android_set_ap_beaconrate(struct net_device * dev,char * command)3839 wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
3840 {
3841 int rate = 0;
3842 char *pos, *token;
3843 char *ifname = NULL;
3844 int err = BCME_OK;
3845
3846 /*
3847 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
3848 */
3849 pos = command;
3850
3851 /* drop command */
3852 token = bcmstrtok(&pos, " ", NULL);
3853
3854 /* Rate */
3855 token = bcmstrtok(&pos, " ", NULL);
3856 if (!token)
3857 return -EINVAL;
3858 rate = bcm_atoi(token);
3859
3860 /* get the interface name */
3861 token = bcmstrtok(&pos, " ", NULL);
3862 if (!token)
3863 return -EINVAL;
3864 ifname = token;
3865
3866 ANDROID_TRACE(("rate %d, ifacename %s\n", rate, ifname));
3867
3868 err = wl_set_ap_beacon_rate(dev, rate, ifname);
3869 if (unlikely(err)) {
3870 ANDROID_ERROR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
3871 }
3872
3873 return err;
3874 }
3875
wl_android_get_ap_basicrate(struct net_device * dev,char * command,int total_len)3876 int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
3877 {
3878 char *pos, *token;
3879 char *ifname = NULL;
3880 int bytes_written = 0;
3881 /*
3882 * DRIVER GET_AP_BASICRATE <ifname>
3883 */
3884 pos = command;
3885
3886 /* drop command */
3887 token = bcmstrtok(&pos, " ", NULL);
3888
3889 /* get the interface name */
3890 token = bcmstrtok(&pos, " ", NULL);
3891 if (!token)
3892 return -EINVAL;
3893 ifname = token;
3894
3895 ANDROID_TRACE(("ifacename %s\n", ifname));
3896
3897 bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
3898 if (bytes_written < 1) {
3899 ANDROID_ERROR(("Failed to get ap basic rate, error = %d\n", bytes_written));
3900 return -EPROTO;
3901 }
3902
3903 return bytes_written;
3904
3905 }
3906 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
3907
3908 #ifdef SUPPORT_AP_RADIO_PWRSAVE
3909 int
wl_android_get_ap_rps(struct net_device * dev,char * command,int total_len)3910 wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
3911 {
3912 char *pos, *token;
3913 char *ifname = NULL;
3914 int bytes_written = 0;
3915 /*
3916 * DRIVER GET_AP_RPS <ifname>
3917 */
3918 pos = command;
3919
3920 /* drop command */
3921 token = bcmstrtok(&pos, " ", NULL);
3922
3923 /* get the interface name */
3924 token = bcmstrtok(&pos, " ", NULL);
3925 if (!token)
3926 return -EINVAL;
3927 ifname = token;
3928
3929 ANDROID_TRACE(("ifacename %s\n", ifname));
3930
3931 bytes_written = wl_get_ap_rps(dev, command, ifname, total_len);
3932 if (bytes_written < 1) {
3933 ANDROID_ERROR(("Failed to get rps, error = %d\n", bytes_written));
3934 return -EPROTO;
3935 }
3936
3937 return bytes_written;
3938
3939 }
3940
3941 int
wl_android_set_ap_rps(struct net_device * dev,char * command,int total_len)3942 wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
3943 {
3944 int enable = 0;
3945 char *pos, *token;
3946 char *ifname = NULL;
3947 int err = BCME_OK;
3948
3949 /*
3950 * DRIVER SET_AP_RPS <0/1> <ifname>
3951 */
3952 pos = command;
3953
3954 /* drop command */
3955 token = bcmstrtok(&pos, " ", NULL);
3956
3957 /* Enable */
3958 token = bcmstrtok(&pos, " ", NULL);
3959 if (!token)
3960 return -EINVAL;
3961 enable = bcm_atoi(token);
3962
3963 /* get the interface name */
3964 token = bcmstrtok(&pos, " ", NULL);
3965 if (!token)
3966 return -EINVAL;
3967 ifname = token;
3968
3969 ANDROID_TRACE(("enable %d, ifacename %s\n", enable, ifname));
3970
3971 err = wl_set_ap_rps(dev, enable? TRUE: FALSE, ifname);
3972 if (unlikely(err)) {
3973 ANDROID_ERROR(("Failed to set rps, enable %d, error = %d\n", enable, err));
3974 }
3975
3976 return err;
3977 }
3978
3979 int
wl_android_set_ap_rps_params(struct net_device * dev,char * command,int total_len)3980 wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
3981 {
3982 ap_rps_info_t rps;
3983 char *pos, *token;
3984 char *ifname = NULL;
3985 int err = BCME_OK;
3986
3987 memset(&rps, 0, sizeof(rps));
3988 /*
3989 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
3990 */
3991 pos = command;
3992
3993 /* drop command */
3994 token = bcmstrtok(&pos, " ", NULL);
3995
3996 /* pps */
3997 token = bcmstrtok(&pos, " ", NULL);
3998 if (!token)
3999 return -EINVAL;
4000 rps.pps = bcm_atoi(token);
4001
4002 /* level */
4003 token = bcmstrtok(&pos, " ", NULL);
4004 if (!token)
4005 return -EINVAL;
4006 rps.level = bcm_atoi(token);
4007
4008 /* quiettime */
4009 token = bcmstrtok(&pos, " ", NULL);
4010 if (!token)
4011 return -EINVAL;
4012 rps.quiet_time = bcm_atoi(token);
4013
4014 /* sta assoc check */
4015 token = bcmstrtok(&pos, " ", NULL);
4016 if (!token)
4017 return -EINVAL;
4018 rps.sta_assoc_check = bcm_atoi(token);
4019
4020 /* get the interface name */
4021 token = bcmstrtok(&pos, " ", NULL);
4022 if (!token)
4023 return -EINVAL;
4024 ifname = token;
4025
4026 ANDROID_TRACE(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
4027 "ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
4028 rps.sta_assoc_check, ifname));
4029
4030 err = wl_update_ap_rps_params(dev, &rps, ifname);
4031 if (unlikely(err)) {
4032 ANDROID_ERROR(("Failed to update rps, pps %d, level %d, quiettime %d, "
4033 "sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
4034 rps.sta_assoc_check, err));
4035 }
4036
4037 return err;
4038 }
4039 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
4040
4041 #ifdef SUPPORT_RSSI_LOGGING
4042 int
wl_android_get_rssi_per_ant(struct net_device * dev,char * command,int total_len)4043 wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
4044 {
4045 wl_rssi_ant_mimo_t rssi_ant_mimo;
4046 char *ifname = NULL;
4047 char *peer_mac = NULL;
4048 char *mimo_cmd = "mimo";
4049 char *pos, *token;
4050 int err = BCME_OK;
4051 int bytes_written = 0;
4052 bool mimo_rssi = FALSE;
4053
4054 memset(&rssi_ant_mimo, 0, sizeof(wl_rssi_ant_mimo_t));
4055 /*
4056 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
4057 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
4058 */
4059 pos = command;
4060
4061 /* drop command */
4062 token = bcmstrtok(&pos, " ", NULL);
4063
4064 /* get the interface name */
4065 token = bcmstrtok(&pos, " ", NULL);
4066 if (!token) {
4067 ANDROID_ERROR(("Invalid arguments\n"));
4068 return -EINVAL;
4069 }
4070 ifname = token;
4071
4072 /* Optional: Check the MIMO RSSI mode or peer MAC address */
4073 token = bcmstrtok(&pos, " ", NULL);
4074 if (token) {
4075 /* Check the MIMO RSSI mode */
4076 if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
4077 mimo_rssi = TRUE;
4078 } else {
4079 peer_mac = token;
4080 }
4081 }
4082
4083 /* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
4084 token = bcmstrtok(&pos, " ", NULL);
4085 if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
4086 mimo_rssi = TRUE;
4087 }
4088
4089 err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
4090 if (unlikely(err)) {
4091 ANDROID_ERROR(("Failed to get RSSI info, err=%d\n", err));
4092 return err;
4093 }
4094
4095 /* Parse the results */
4096 ANDROID_TRACE(("ifname %s, version %d, count %d, mimo rssi %d\n",
4097 ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
4098 if (mimo_rssi) {
4099 ANDROID_TRACE(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
4100 bytes_written = snprintf(command, total_len, "%s MIMO %d",
4101 CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
4102 } else {
4103 int cnt;
4104 bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
4105 for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
4106 ANDROID_TRACE(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
4107 bytes_written = snprintf(command, total_len, "%d ",
4108 rssi_ant_mimo.rssi_ant[cnt]);
4109 }
4110 }
4111
4112 return bytes_written;
4113 }
4114
4115 int
wl_android_set_rssi_logging(struct net_device * dev,char * command,int total_len)4116 wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
4117 {
4118 rssilog_set_param_t set_param;
4119 char *pos, *token;
4120 int err = BCME_OK;
4121
4122 memset(&set_param, 0, sizeof(rssilog_set_param_t));
4123 /*
4124 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
4125 */
4126 pos = command;
4127
4128 /* drop command */
4129 token = bcmstrtok(&pos, " ", NULL);
4130
4131 /* enable/disable */
4132 token = bcmstrtok(&pos, " ", NULL);
4133 if (!token) {
4134 ANDROID_ERROR(("Invalid arguments\n"));
4135 return -EINVAL;
4136 }
4137 set_param.enable = bcm_atoi(token);
4138
4139 /* RSSI Threshold */
4140 token = bcmstrtok(&pos, " ", NULL);
4141 if (!token) {
4142 ANDROID_ERROR(("Invalid arguments\n"));
4143 return -EINVAL;
4144 }
4145 set_param.rssi_threshold = bcm_atoi(token);
4146
4147 /* Time Threshold */
4148 token = bcmstrtok(&pos, " ", NULL);
4149 if (!token) {
4150 ANDROID_ERROR(("Invalid arguments\n"));
4151 return -EINVAL;
4152 }
4153 set_param.time_threshold = bcm_atoi(token);
4154
4155 ANDROID_TRACE(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
4156 set_param.rssi_threshold, set_param.time_threshold));
4157
4158 err = wl_set_rssi_logging(dev, (void *)&set_param);
4159 if (unlikely(err)) {
4160 ANDROID_ERROR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
4161 " Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
4162 set_param.time_threshold));
4163 }
4164
4165 return err;
4166 }
4167
4168 int
wl_android_get_rssi_logging(struct net_device * dev,char * command,int total_len)4169 wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
4170 {
4171 rssilog_get_param_t get_param;
4172 int err = BCME_OK;
4173 int bytes_written = 0;
4174
4175 err = wl_get_rssi_logging(dev, (void *)&get_param);
4176 if (unlikely(err)) {
4177 ANDROID_ERROR(("Failed to get RSSI logging info\n"));
4178 return BCME_ERROR;
4179 }
4180
4181 ANDROID_TRACE(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
4182 get_param.report_count, get_param.enable, get_param.rssi_threshold,
4183 get_param.time_threshold));
4184
4185 /* Parse the parameter */
4186 if (!get_param.enable) {
4187 ANDROID_TRACE(("RSSI LOGGING: Feature is disables\n"));
4188 bytes_written = snprintf(command, total_len,
4189 "%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
4190 } else if (get_param.enable &
4191 (RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
4192 if (!get_param.report_count) {
4193 ANDROID_TRACE(("[PASS] RSSI difference across antennas is within"
4194 " threshold limits\n"));
4195 bytes_written = snprintf(command, total_len, "%s PASS\n",
4196 CMD_GET_RSSI_LOGGING);
4197 } else {
4198 ANDROID_TRACE(("[FAIL] RSSI difference across antennas found "
4199 "to be greater than %3d dB\n", get_param.rssi_threshold));
4200 ANDROID_TRACE(("[FAIL] RSSI difference check have failed for "
4201 "%d out of %d times\n", get_param.report_count,
4202 get_param.time_threshold));
4203 ANDROID_TRACE(("[FAIL] RSSI difference is being monitored once "
4204 "per second, for a %d secs window\n", get_param.time_threshold));
4205 bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
4206 "%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
4207 get_param.rssi_threshold, get_param.report_count,
4208 get_param.time_threshold);
4209 }
4210 } else {
4211 ANDROID_TRACE(("[BUSY] Reprot is not ready\n"));
4212 bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
4213 CMD_GET_RSSI_LOGGING);
4214 }
4215
4216 return bytes_written;
4217 }
4218 #endif /* SUPPORT_RSSI_LOGGING */
4219
4220 #ifdef SET_PCIE_IRQ_CPU_CORE
4221 void
wl_android_set_irq_cpucore(struct net_device * net,int set)4222 wl_android_set_irq_cpucore(struct net_device *net, int set)
4223 {
4224 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
4225 if (!dhdp) {
4226 ANDROID_ERROR(("dhd is NULL\n"));
4227 return;
4228 }
4229 dhd_set_irq_cpucore(dhdp, set);
4230 }
4231 #endif /* SET_PCIE_IRQ_CPU_CORE */
4232
4233 #if defined(DHD_HANG_SEND_UP_TEST)
4234 void
wl_android_make_hang_with_reason(struct net_device * dev,const char * string_num)4235 wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
4236 {
4237 dhd_make_hang_with_reason(dev, string_num);
4238 }
4239 #endif /* DHD_HANG_SEND_UP_TEST */
4240
4241 #ifdef WL_CFG80211
4242 #ifdef WLMESH_CFG80211
4243 static int
wl_android_set_rsdb_mode(struct net_device * dev,char * command,int total_len)4244 wl_android_set_rsdb_mode(struct net_device *dev, char *command, int total_len)
4245 {
4246 int ret;
4247 wl_config_t rsdb_mode_cfg = {-1, 0};
4248 char smbuf[WLC_IOCTL_SMLEN];
4249 s32 val = 1;
4250
4251 if (sscanf(command, "%*s %d", &rsdb_mode_cfg.config) != 1) {
4252 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
4253 return -1;
4254 }
4255 DHD_INFO(("%s : RSDB_MODE = %d\n", __FUNCTION__, rsdb_mode_cfg.config));
4256
4257 ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
4258 if (ret < 0)
4259 DHD_ERROR(("WLC_DOWN error %d\n", ret));
4260
4261 ret = wldev_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg, sizeof(rsdb_mode_cfg),
4262 smbuf, sizeof(smbuf), NULL);
4263 if (ret < 0)
4264 DHD_ERROR(("%s : set rsdb_mode error=%d\n", __FUNCTION__, ret));
4265
4266 ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
4267 if (ret < 0)
4268 DHD_ERROR(("WLC_UP error %d\n", ret));
4269
4270 return ret;
4271 }
4272 #endif /* WLMESH */
4273 #endif /* WL_CFG80211 */
4274
4275 #ifdef SUPPORT_LQCM
4276 static int
wl_android_lqcm_enable(struct net_device * net,int lqcm_enable)4277 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
4278 {
4279 int err = 0;
4280
4281 err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
4282 if (err != BCME_OK) {
4283 ANDROID_ERROR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
4284 return -EIO;
4285 }
4286 return err;
4287 }
4288
wl_android_get_lqcm_report(struct net_device * dev,char * command,int total_len)4289 static int wl_android_get_lqcm_report(
4290 struct net_device *dev, char *command, int total_len)
4291 {
4292 int bytes_written, err = 0;
4293 uint32 lqcm_report = 0;
4294 uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
4295
4296 err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
4297 if (err != BCME_OK) {
4298 ANDROID_ERROR(("failed to get lqcm report, error = %d\n", err));
4299 return -EIO;
4300 }
4301 lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
4302 tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
4303 rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
4304
4305 ANDROID_ERROR(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
4306
4307 bytes_written = snprintf(command, total_len, "%s %d",
4308 CMD_GET_LQCM_REPORT, lqcm_report);
4309
4310 return bytes_written;
4311 }
4312 #endif /* SUPPORT_LQCM */
4313
4314 int
wl_android_get_snr(struct net_device * dev,char * command,int total_len)4315 wl_android_get_snr(struct net_device *dev, char *command, int total_len)
4316 {
4317 int bytes_written, error = 0;
4318 s32 snr = 0;
4319
4320 error = wldev_iovar_getint(dev, "snr", &snr);
4321 if (error) {
4322 ANDROID_ERROR(("%s: Failed to get SNR %d, error = %d\n",
4323 __FUNCTION__, snr, error));
4324 return -EIO;
4325 }
4326
4327 bytes_written = snprintf(command, total_len, "snr %d", snr);
4328 ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command));
4329 return bytes_written;
4330 }
4331 #ifdef WLADPS_PRIVATE_CMD
4332 static int
wl_android_set_adps_mode(struct net_device * dev,const char * string_num)4333 wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
4334 {
4335 int err = 0, adps_mode;
4336 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4337
4338 adps_mode = bcm_atoi(string_num);
4339
4340 if ((adps_mode < 0) && (1 < adps_mode)) {
4341 ANDROID_ERROR(("%s: Invalid value %d.\n", __FUNCTION__, adps_mode));
4342 return -EINVAL;
4343 }
4344
4345 err = dhd_enable_adps(dhdp, adps_mode);
4346 if (err != BCME_OK) {
4347 ANDROID_ERROR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
4348 return -EIO;
4349 }
4350 return err;
4351 }
4352 static int
wl_android_get_adps_mode(struct net_device * dev,char * command,int total_len)4353 wl_android_get_adps_mode(
4354 struct net_device *dev, char *command, int total_len)
4355 {
4356 int bytes_written, err = 0;
4357 int len;
4358 char buf[WLC_IOCTL_SMLEN];
4359
4360 bcm_iov_buf_t iov_buf;
4361 bcm_iov_buf_t *ptr = NULL;
4362 wl_adps_params_v1_t *data = NULL;
4363
4364 uint8 *pdata = NULL;
4365 uint8 band, mode = 0;
4366
4367 memset(&iov_buf, 0, sizeof(iov_buf));
4368
4369 len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(*data);
4370
4371 iov_buf.version = WL_ADPS_IOV_VER;
4372 iov_buf.len = sizeof(band);
4373 iov_buf.id = WL_ADPS_IOV_MODE;
4374
4375 pdata = (uint8 *)&iov_buf.data;
4376
4377 for (band = 1; band <= MAX_BANDS; band++) {
4378 pdata[0] = band;
4379 err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
4380 buf, WLC_IOCTL_SMLEN, NULL);
4381 if (err != BCME_OK) {
4382 ANDROID_ERROR(("%s fail to get adps band %d(%d).\n",
4383 __FUNCTION__, band, err));
4384 return -EIO;
4385 }
4386 ptr = (bcm_iov_buf_t *) buf;
4387 data = (wl_adps_params_v1_t *) ptr->data;
4388 mode = data->mode;
4389 if (mode != OFF) {
4390 break;
4391 }
4392 }
4393
4394 bytes_written = snprintf(command, total_len, "%s %d",
4395 CMD_GET_ADPS, mode);
4396 return bytes_written;
4397 }
4398 #endif /* WLADPS_PRIVATE_CMD */
4399
4400 #ifdef DHD_PKT_LOGGING
4401 static int
wl_android_pktlog_filter_enable(struct net_device * dev,char * command,int total_len)4402 wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
4403 {
4404 int bytes_written = 0;
4405 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4406 dhd_pktlog_filter_t *filter;
4407 int err = BCME_OK;
4408
4409 if (!dhdp || !dhdp->pktlog) {
4410 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
4411 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
4412 return -EINVAL;
4413 }
4414
4415 filter = dhdp->pktlog->pktlog_filter;
4416
4417 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
4418 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
4419 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
4420
4421 if (err == BCME_OK) {
4422 bytes_written = snprintf(command, total_len, "OK");
4423 ANDROID_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
4424 } else {
4425 ANDROID_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
4426 return BCME_ERROR;
4427 }
4428
4429 return bytes_written;
4430 }
4431
4432 static int
wl_android_pktlog_filter_disable(struct net_device * dev,char * command,int total_len)4433 wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
4434 {
4435 int bytes_written = 0;
4436 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4437 dhd_pktlog_filter_t *filter;
4438 int err = BCME_OK;
4439
4440 if (!dhdp || !dhdp->pktlog) {
4441 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
4442 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
4443 return -EINVAL;
4444 }
4445
4446 filter = dhdp->pktlog->pktlog_filter;
4447
4448 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
4449 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
4450 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
4451
4452 if (err == BCME_OK) {
4453 bytes_written = snprintf(command, total_len, "OK");
4454 ANDROID_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
4455 } else {
4456 ANDROID_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
4457 return BCME_ERROR;
4458 }
4459
4460 return bytes_written;
4461 }
4462
4463 static int
wl_android_pktlog_filter_pattern_enable(struct net_device * dev,char * command,int total_len)4464 wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
4465 {
4466 int bytes_written = 0;
4467 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4468 dhd_pktlog_filter_t *filter;
4469 int err = BCME_OK;
4470
4471 if (!dhdp || !dhdp->pktlog) {
4472 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
4473 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
4474 return -EINVAL;
4475 }
4476
4477 filter = dhdp->pktlog->pktlog_filter;
4478
4479 if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
4480 return BCME_ERROR;
4481 }
4482
4483 err = dhd_pktlog_filter_pattern_enable(filter,
4484 command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
4485
4486 if (err == BCME_OK) {
4487 bytes_written = snprintf(command, total_len, "OK");
4488 ANDROID_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
4489 } else {
4490 ANDROID_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
4491 return BCME_ERROR;
4492 }
4493
4494 return bytes_written;
4495 }
4496
4497 static int
wl_android_pktlog_filter_pattern_disable(struct net_device * dev,char * command,int total_len)4498 wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
4499 {
4500 int bytes_written = 0;
4501 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4502 dhd_pktlog_filter_t *filter;
4503 int err = BCME_OK;
4504
4505 if (!dhdp || !dhdp->pktlog) {
4506 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
4507 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
4508 return -EINVAL;
4509 }
4510
4511 filter = dhdp->pktlog->pktlog_filter;
4512
4513 if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
4514 return BCME_ERROR;
4515 }
4516
4517 err = dhd_pktlog_filter_pattern_enable(filter,
4518 command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
4519
4520 if (err == BCME_OK) {
4521 bytes_written = snprintf(command, total_len, "OK");
4522 ANDROID_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
4523 } else {
4524 ANDROID_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
4525 return BCME_ERROR;
4526 }
4527
4528 return bytes_written;
4529 }
4530
4531 static int
wl_android_pktlog_filter_add(struct net_device * dev,char * command,int total_len)4532 wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
4533 {
4534 int bytes_written = 0;
4535 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4536 dhd_pktlog_filter_t *filter;
4537 int err = BCME_OK;
4538
4539 if (!dhdp || !dhdp->pktlog) {
4540 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
4541 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
4542 return -EINVAL;
4543 }
4544
4545 filter = dhdp->pktlog->pktlog_filter;
4546
4547 if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
4548 return BCME_ERROR;
4549 }
4550
4551 err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
4552
4553 if (err == BCME_OK) {
4554 bytes_written = snprintf(command, total_len, "OK");
4555 ANDROID_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
4556 } else {
4557 ANDROID_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
4558 return BCME_ERROR;
4559 }
4560
4561 return bytes_written;
4562 }
4563
4564 static int
wl_android_pktlog_filter_info(struct net_device * dev,char * command,int total_len)4565 wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
4566 {
4567 int bytes_written = 0;
4568 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4569 dhd_pktlog_filter_t *filter;
4570 int err = BCME_OK;
4571
4572 if (!dhdp || !dhdp->pktlog) {
4573 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
4574 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
4575 return -EINVAL;
4576 }
4577
4578 filter = dhdp->pktlog->pktlog_filter;
4579
4580 err = dhd_pktlog_filter_info(filter);
4581
4582 if (err == BCME_OK) {
4583 bytes_written = snprintf(command, total_len, "OK");
4584 ANDROID_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
4585 } else {
4586 ANDROID_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
4587 return BCME_ERROR;
4588 }
4589
4590 return bytes_written;
4591 }
4592
4593 static int
wl_android_pktlog_start(struct net_device * dev,char * command,int total_len)4594 wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
4595 {
4596 int bytes_written = 0;
4597 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4598
4599 if (!dhdp || !dhdp->pktlog) {
4600 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
4601 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
4602 return -EINVAL;
4603 }
4604
4605 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
4606 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
4607 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
4608 return -EINVAL;
4609 }
4610
4611 dhdp->pktlog->tx_pktlog_ring->start = TRUE;
4612 dhdp->pktlog->rx_pktlog_ring->start = TRUE;
4613
4614 bytes_written = snprintf(command, total_len, "OK");
4615
4616 ANDROID_ERROR(("%s: pktlog start success\n", __FUNCTION__));
4617
4618 return bytes_written;
4619 }
4620
4621 static int
wl_android_pktlog_stop(struct net_device * dev,char * command,int total_len)4622 wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
4623 {
4624 int bytes_written = 0;
4625 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4626
4627 if (!dhdp || !dhdp->pktlog) {
4628 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
4629 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
4630 return -EINVAL;
4631 }
4632
4633 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
4634 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
4635 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
4636 return -EINVAL;
4637 }
4638
4639 dhdp->pktlog->tx_pktlog_ring->start = FALSE;
4640 dhdp->pktlog->rx_pktlog_ring->start = FALSE;
4641
4642 bytes_written = snprintf(command, total_len, "OK");
4643
4644 ANDROID_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
4645
4646 return bytes_written;
4647 }
4648
4649 static int
wl_android_pktlog_filter_exist(struct net_device * dev,char * command,int total_len)4650 wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
4651 {
4652 int bytes_written = 0;
4653 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4654 dhd_pktlog_filter_t *filter;
4655 uint32 id;
4656 bool exist = FALSE;
4657
4658 if (!dhdp || !dhdp->pktlog) {
4659 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
4660 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
4661 return -EINVAL;
4662 }
4663
4664 filter = dhdp->pktlog->pktlog_filter;
4665
4666 if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
4667 return BCME_ERROR;
4668 }
4669
4670 exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
4671 &id);
4672
4673 if (exist) {
4674 bytes_written = snprintf(command, total_len, "TRUE");
4675 ANDROID_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
4676 } else {
4677 bytes_written = snprintf(command, total_len, "FALSE");
4678 ANDROID_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
4679 }
4680
4681 return bytes_written;
4682 }
4683 #endif /* DHD_PKT_LOGGING */
4684
wl_android_priv_cmd(struct net_device * net,struct ifreq * ifr,int cmd)4685 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
4686 {
4687 #define PRIVATE_COMMAND_MAX_LEN 8192
4688 #define PRIVATE_COMMAND_DEF_LEN 4096
4689 int ret = 0;
4690 char *command = NULL;
4691 int bytes_written = 0;
4692 android_wifi_priv_cmd priv_cmd;
4693 int buf_size = 0;
4694
4695 net_os_wake_lock(net);
4696
4697 if (!capable(CAP_NET_ADMIN)) {
4698 ret = -EPERM;
4699 goto exit;
4700 }
4701
4702 if (!ifr->ifr_data) {
4703 ret = -EINVAL;
4704 goto exit;
4705 }
4706
4707 #ifdef CONFIG_COMPAT
4708 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
4709 if (in_compat_syscall())
4710 #else
4711 if (is_compat_task())
4712 #endif
4713 {
4714 compat_android_wifi_priv_cmd compat_priv_cmd;
4715 if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
4716 sizeof(compat_android_wifi_priv_cmd))) {
4717 ret = -EFAULT;
4718 goto exit;
4719
4720 }
4721 priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
4722 priv_cmd.used_len = compat_priv_cmd.used_len;
4723 priv_cmd.total_len = compat_priv_cmd.total_len;
4724 } else
4725 #endif /* CONFIG_COMPAT */
4726 {
4727 if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
4728 ret = -EFAULT;
4729 goto exit;
4730 }
4731 }
4732 if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
4733 ANDROID_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__,
4734 priv_cmd.total_len));
4735 ret = -EINVAL;
4736 goto exit;
4737 }
4738
4739 buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
4740 command = kmalloc((buf_size + 1), GFP_KERNEL);
4741
4742 if (!command)
4743 {
4744 ANDROID_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
4745 ret = -ENOMEM;
4746 goto exit;
4747 }
4748 if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
4749 ret = -EFAULT;
4750 goto exit;
4751 }
4752 command[priv_cmd.total_len] = '\0';
4753
4754 ANDROID_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
4755
4756 bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
4757 if (bytes_written >= 0) {
4758 if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
4759 command[0] = '\0';
4760 }
4761 if (bytes_written >= priv_cmd.total_len) {
4762 ANDROID_ERROR(("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n",
4763 __FUNCTION__, bytes_written, priv_cmd.total_len, buf_size));
4764 ret = BCME_BUFTOOSHORT;
4765 goto exit;
4766 }
4767 bytes_written++;
4768 priv_cmd.used_len = bytes_written;
4769 if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
4770 ANDROID_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
4771 ret = -EFAULT;
4772 }
4773 }
4774 else {
4775 /* Propagate the error */
4776 ret = bytes_written;
4777 }
4778
4779 exit:
4780 net_os_wake_unlock(net);
4781 kfree(command);
4782 return ret;
4783 }
4784
4785 int
wl_handle_private_cmd(struct net_device * net,char * command,u32 cmd_len)4786 wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
4787 {
4788 int bytes_written = 0;
4789 android_wifi_priv_cmd priv_cmd;
4790
4791 bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
4792 priv_cmd.total_len = cmd_len;
4793
4794 if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
4795 ANDROID_INFO(("%s, Received regular START command\n", __FUNCTION__));
4796 #ifdef BT_OVER_SDIO
4797 bytes_written = dhd_net_bus_get(net);
4798 #else
4799 bytes_written = wl_android_wifi_on(net);
4800 #endif /* BT_OVER_SDIO */
4801 }
4802 else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
4803 bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
4804 }
4805
4806 if (!g_wifi_on) {
4807 ANDROID_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
4808 __FUNCTION__, command));
4809 return 0;
4810 }
4811
4812 if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
4813 #ifdef BT_OVER_SDIO
4814 bytes_written = dhd_net_bus_put(net);
4815 #else
4816 bytes_written = wl_android_wifi_off(net, FALSE);
4817 #endif /* BT_OVER_SDIO */
4818 }
4819 #ifdef WL_CFG80211
4820 else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
4821 wl_cfg80211_set_passive_scan(net, command);
4822 }
4823 else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
4824 wl_cfg80211_set_passive_scan(net, command);
4825 }
4826 #endif
4827 else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
4828 bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
4829 }
4830 else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
4831 bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
4832 }
4833 #ifdef PKT_FILTER_SUPPORT
4834 else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
4835 bytes_written = net_os_enable_packet_filter(net, 1);
4836 }
4837 else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
4838 bytes_written = net_os_enable_packet_filter(net, 0);
4839 }
4840 else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
4841 int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
4842 bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
4843 }
4844 else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
4845 int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
4846 bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
4847 }
4848 #endif /* PKT_FILTER_SUPPORT */
4849 else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
4850 /* TBD: BTCOEXSCAN-START */
4851 }
4852 else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
4853 /* TBD: BTCOEXSCAN-STOP */
4854 }
4855 else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
4856 #ifdef WL_CFG80211
4857 void *dhdp = wl_cfg80211_get_dhdp(net);
4858 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
4859 #else
4860 #ifdef PKT_FILTER_SUPPORT
4861 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
4862
4863 if (mode == 1)
4864 net_os_enable_packet_filter(net, 0); /* DHCP starts */
4865 else
4866 net_os_enable_packet_filter(net, 1); /* DHCP ends */
4867 #endif /* PKT_FILTER_SUPPORT */
4868 #endif /* WL_CFG80211 */
4869 }
4870 else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
4871 bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
4872 }
4873 else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
4874 bytes_written = wl_android_set_max_dtim(net, command, priv_cmd.total_len);
4875 }
4876 #ifdef WL_CFG80211
4877 else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
4878 #ifdef DISABLE_SETBAND
4879 bytes_written = BCME_DISABLED;
4880 #else /* DISABLE_SETBAND */
4881 uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
4882 if (dhd_conf_get_band(dhd_get_pub(net)) >= WLC_BAND_AUTO) {
4883 printf("%s: Band is fixed in config.txt\n", __FUNCTION__);
4884 } else
4885 bytes_written = wl_cfg80211_set_if_band(net, band);
4886 #endif /* DISABLE_SETBAND */
4887 }
4888 #endif
4889 else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
4890 bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
4891 }
4892 #ifdef WL_CFG80211
4893 else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
4894 bytes_written = wl_android_set_csa(net, command, priv_cmd.total_len);
4895 } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
4896 bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
4897 } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
4898 bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
4899 }
4900 #endif /* WL_CFG80211 */
4901 /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
4902 else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
4903 /*
4904 * Usage examples:
4905 * DRIVER COUNTRY US
4906 * DRIVER COUNTRY US/7
4907 */
4908 char *country_code = command + strlen(CMD_COUNTRY) + 1;
4909 char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
4910 int revinfo = -1;
4911 #if defined(DHD_BLOB_EXISTENCE_CHECK)
4912 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
4913
4914 if (dhdp->is_blob) {
4915 revinfo = 0;
4916 } else
4917 #endif /* DHD_BLOB_EXISTENCE_CHECK */
4918 if ((rev_info_delim) &&
4919 (strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
4920 strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
4921 (rev_info_delim + 1)) {
4922 revinfo = bcm_atoi(rev_info_delim + 1);
4923 }
4924 bytes_written = wldev_set_country(net, country_code, true, true, revinfo);
4925 #ifdef CUSTOMER_HW4_PRIVATE_CMD
4926 #ifdef FCC_PWR_LIMIT_2G
4927 if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
4928 ANDROID_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
4929 } else {
4930 ANDROID_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
4931 }
4932 #endif /* FCC_PWR_LIMIT_2G */
4933 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
4934 }
4935 else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
4936 bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
4937 } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) {
4938 bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
4939 }
4940
4941 #ifdef CUSTOMER_HW4_PRIVATE_CMD
4942 #ifdef WLTDLS
4943 else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
4944 bytes_written = wl_android_tdls_reset(net);
4945 }
4946 #endif /* WLTDLS */
4947 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
4948
4949 #ifdef PNO_SUPPORT
4950 else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
4951 bytes_written = dhd_dev_pno_stop_for_ssid(net);
4952 }
4953 #ifndef WL_SCHED_SCAN
4954 else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
4955 bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
4956 }
4957 #endif /* !WL_SCHED_SCAN */
4958 else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
4959 int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
4960 bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
4961 }
4962 else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
4963 bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
4964 }
4965 #endif /* PNO_SUPPORT */
4966 else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
4967 bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
4968 }
4969 #ifdef WL_CFG80211
4970 #ifdef WLMESH_CFG80211
4971 else if (strnicmp(command, CMD_SAE_SET_PASSWORD, strlen(CMD_SAE_SET_PASSWORD)) == 0) {
4972 int skip = strlen(CMD_SAE_SET_PASSWORD) + 1;
4973 bytes_written = wl_cfg80211_set_sae_password(net, command + skip,
4974 priv_cmd.total_len - skip);
4975 }
4976 else if (strnicmp(command, CMD_SET_RSDB_MODE, strlen(CMD_SET_RSDB_MODE)) == 0) {
4977 bytes_written = wl_android_set_rsdb_mode(net, command, priv_cmd.total_len);
4978 }
4979 #endif
4980 #endif /* WL_CFG80211 */
4981 else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
4982 int skip = strlen(CMD_P2P_SET_NOA) + 1;
4983 bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
4984 priv_cmd.total_len - skip);
4985 }
4986 #ifdef P2P_LISTEN_OFFLOADING
4987 else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
4988 u8 *sub_command = strchr(command, ' ');
4989 bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
4990 sub_command ? strlen(sub_command) : 0);
4991 }
4992 #endif /* P2P_LISTEN_OFFLOADING */
4993 #if !defined WL_ENABLE_P2P_IF
4994 else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
4995 bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
4996 }
4997 #endif /* WL_ENABLE_P2P_IF */
4998 else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
4999 int skip = strlen(CMD_P2P_SET_PS) + 1;
5000 bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
5001 priv_cmd.total_len - skip);
5002 }
5003 else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
5004 int skip = strlen(CMD_P2P_ECSA) + 1;
5005 bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
5006 priv_cmd.total_len - skip);
5007 }
5008 else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
5009 int skip = strlen(CMD_P2P_INC_BW) + 1;
5010 bytes_written = wl_cfg80211_increase_p2p_bw(net,
5011 command + skip, priv_cmd.total_len - skip);
5012 }
5013 #ifdef WL_CFG80211
5014 else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
5015 strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
5016 int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
5017 bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
5018 priv_cmd.total_len - skip, *(command + skip - 2) - '0');
5019 }
5020 #ifdef WLFBT
5021 else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
5022 bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
5023 }
5024 #endif /* WLFBT */
5025 #endif /* WL_CFG80211 */
5026 #if defined(WL_SUPPORT_AUTO_CHANNEL)
5027 else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
5028 strlen(CMD_GET_BEST_CHANNELS)) == 0) {
5029 bytes_written = wl_cfg80211_get_best_channels(net, command,
5030 priv_cmd.total_len);
5031 }
5032 #endif /* WL_SUPPORT_AUTO_CHANNEL */
5033 #if defined(WL_SUPPORT_AUTO_CHANNEL)
5034 else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
5035 strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
5036 int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
5037 bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
5038 priv_cmd.total_len);
5039 }
5040 #endif /* WL_SUPPORT_AUTO_CHANNEL */
5041 #ifdef CUSTOMER_HW4_PRIVATE_CMD
5042 #ifdef SUPPORT_SET_LPC
5043 else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
5044 strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
5045 int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
5046 wl_android_set_lpc(net, (const char*)command+skip);
5047 }
5048 #endif /* SUPPORT_SET_LPC */
5049 #ifdef SUPPORT_TRIGGER_HANG_EVENT
5050 else if (strnicmp(command, CMD_TEST_FORCE_HANG,
5051 strlen(CMD_TEST_FORCE_HANG)) == 0) {
5052 int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
5053 net_os_send_hang_message_reason(net, (const char*)command+skip);
5054 }
5055 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
5056 else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
5057 bytes_written = wl_android_ch_res_rl(net, true);
5058 else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
5059 bytes_written = wl_android_ch_res_rl(net, false);
5060 #ifdef WL_RELMCAST
5061 else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
5062 int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
5063 bytes_written = wl_android_rmc_enable(net, rmc_enable);
5064 }
5065 else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
5066 int rmc_txrate;
5067 sscanf(command, "%*s %10d", &rmc_txrate);
5068 bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
5069 }
5070 else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
5071 int actperiod;
5072 sscanf(command, "%*s %10d", &actperiod);
5073 bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
5074 }
5075 else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
5076 int acktimeout;
5077 sscanf(command, "%*s %10d", &acktimeout);
5078 acktimeout *= 1000;
5079 bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
5080 }
5081 else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
5082 int skip = strlen(CMD_SET_RMC_LEADER) + 1;
5083 bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
5084 }
5085 else if (strnicmp(command, CMD_SET_RMC_EVENT,
5086 strlen(CMD_SET_RMC_EVENT)) == 0) {
5087 bytes_written = wl_android_set_rmc_event(net, command, priv_cmd.total_len);
5088 }
5089 #endif /* WL_RELMCAST */
5090 else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
5091 bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
5092 }
5093 else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
5094 bytes_written = wl_android_set_singlecore_scan(net, command, priv_cmd.total_len);
5095 }
5096 #ifdef TEST_TX_POWER_CONTROL
5097 else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
5098 strlen(CMD_TEST_SET_TX_POWER)) == 0) {
5099 int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
5100 wl_android_set_tx_power(net, (const char*)command+skip);
5101 }
5102 else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
5103 strlen(CMD_TEST_GET_TX_POWER)) == 0) {
5104 wl_android_get_tx_power(net, command, priv_cmd.total_len);
5105 }
5106 #endif /* TEST_TX_POWER_CONTROL */
5107 else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
5108 strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
5109 int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
5110 wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
5111 }
5112 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
5113 else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
5114 int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
5115 wl_android_set_mac_address_filter(net, command+skip);
5116 }
5117 else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
5118 bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len);
5119 #if defined(BCMFW_ROAM_ENABLE)
5120 else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
5121 bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
5122 }
5123 #endif /* BCMFW_ROAM_ENABLE */
5124 #ifdef WL_CFG80211
5125 else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
5126 bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len);
5127 #ifdef WL11ULB
5128 else if (strnicmp(command, CMD_ULB_MODE, strlen(CMD_ULB_MODE)) == 0)
5129 bytes_written = wl_android_set_ulb_mode(net, command, priv_cmd.total_len);
5130 else if (strnicmp(command, CMD_ULB_BW, strlen(CMD_ULB_BW)) == 0)
5131 bytes_written = wl_android_set_ulb_bw(net, command, priv_cmd.total_len);
5132 #endif /* WL11ULB */
5133 else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
5134 bytes_written = wl_android_set_ibss_beacon_ouidata(net,
5135 command, priv_cmd.total_len);
5136 #endif
5137 else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
5138 int skip = strlen(CMD_KEEP_ALIVE) + 1;
5139 bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip);
5140 }
5141 #ifdef WL_CFG80211
5142 else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
5143 int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
5144 bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
5145 }
5146 #endif
5147 #if defined(WL_VIRTUAL_APSTA)
5148 else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
5149 char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
5150 ANDROID_INFO(("Creating %s interface\n", name));
5151 bytes_written = wl_cfg80211_interface_create(net, name);
5152 }
5153 else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
5154 char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
5155 ANDROID_INFO(("Deleteing %s interface\n", name));
5156 bytes_written = wl_cfg80211_interface_delete(net, name);
5157 }
5158 #endif /* defined (WL_VIRTUAL_APSTA) */
5159 else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
5160 bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
5161 }
5162 #ifdef P2PRESP_WFDIE_SRC
5163 else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
5164 strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
5165 int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
5166 bytes_written = wl_android_set_wfdie_resp(net, mode);
5167 } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
5168 strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
5169 bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
5170 }
5171 #endif /* P2PRESP_WFDIE_SRC */
5172 #ifdef WL_CFG80211
5173 else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
5174 char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
5175 bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
5176 }
5177 #endif
5178 #ifdef WBTEXT
5179 else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
5180 bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
5181 }
5182 #ifdef WL_CFG80211
5183 else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
5184 strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
5185 char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
5186 bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
5187 }
5188 else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
5189 strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
5190 char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
5191 bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
5192 command, priv_cmd.total_len);
5193 }
5194 else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
5195 strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
5196 char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
5197 bytes_written = wl_cfg80211_wbtext_table_config(net, data,
5198 command, priv_cmd.total_len);
5199 }
5200 else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
5201 strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
5202 char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
5203 bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
5204 command, priv_cmd.total_len);
5205 }
5206 #endif
5207 else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
5208 strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
5209 bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
5210 priv_cmd.total_len);
5211 }
5212 else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
5213 strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
5214 bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
5215 priv_cmd.total_len);
5216 }
5217 #endif /* WBTEXT */
5218 #ifdef SET_RPS_CPUS
5219 else if (strnicmp(command, CMD_RPSMODE, strlen(CMD_RPSMODE)) == 0) {
5220 bytes_written = wl_android_set_rps_cpus(net, command, priv_cmd.total_len);
5221 }
5222 #endif /* SET_RPS_CPUS */
5223 #ifdef WLWFDS
5224 else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
5225 bytes_written = wl_android_set_wfds_hash(net, command, priv_cmd.total_len, 1);
5226 }
5227 else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
5228 bytes_written = wl_android_set_wfds_hash(net, command, priv_cmd.total_len, 0);
5229 }
5230 #endif /* WLWFDS */
5231 #ifdef BT_WIFI_HANDOVER
5232 else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
5233 bytes_written = wl_tbow_teardown(net, command, priv_cmd.total_len);
5234 }
5235 #endif /* BT_WIFI_HANDOVER */
5236 #ifdef CUSTOMER_HW4_PRIVATE_CMD
5237 #ifdef FCC_PWR_LIMIT_2G
5238 else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
5239 strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
5240 bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
5241 }
5242 else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
5243 strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
5244 bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
5245 }
5246 #endif /* FCC_PWR_LIMIT_2G */
5247 else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
5248 bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
5249 }
5250 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
5251 else if (strnicmp(command, CMD_MURX_BFE_CAP,
5252 strlen(CMD_MURX_BFE_CAP)) == 0) {
5253 #if defined(BCM4359_CHIP) && defined(WL_CFG80211)
5254 uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
5255 bytes_written = wl_android_murx_bfe_cap(net, val);
5256 #else
5257 return BCME_UNSUPPORTED;
5258 #endif /* BCM4359_CHIP */
5259 }
5260 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
5261 else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
5262 bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
5263 }
5264 else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
5265 bytes_written = wl_android_set_ap_beaconrate(net, command);
5266 }
5267 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
5268 #ifdef SUPPORT_AP_RADIO_PWRSAVE
5269 else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
5270 bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
5271 }
5272 else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
5273 bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
5274 }
5275 else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
5276 bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
5277 }
5278 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
5279 #ifdef SUPPORT_RSSI_LOGGING
5280 else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
5281 bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
5282 }
5283 else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
5284 bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
5285 }
5286 else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
5287 bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
5288 }
5289 #endif /* SUPPORT_RSSI_LOGGING */
5290 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
5291 else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
5292 bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
5293 }
5294 else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
5295 == 0) {
5296 bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
5297 priv_cmd.total_len);
5298 }
5299 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
5300 #if defined(SUPPORT_RANDOM_MAC_SCAN)
5301 else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
5302 bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
5303 } else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
5304 bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
5305 }
5306 #endif /* SUPPORT_RANDOM_MAC_SCAN */
5307 #ifdef WL_NATOE
5308 else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
5309 bytes_written = wl_android_process_natoe_cmd(net, command,
5310 priv_cmd.total_len);
5311 }
5312 #endif /* WL_NATOE */
5313 #ifdef CONNECTION_STATISTICS
5314 else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
5315 strlen(CMD_GET_CONNECTION_STATS)) == 0) {
5316 bytes_written = wl_android_get_connection_stats(net, command,
5317 priv_cmd.total_len);
5318 }
5319 #endif
5320 #ifdef DHD_LOG_DUMP
5321 else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
5322 strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
5323 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
5324 dhd_schedule_log_dump(dhdp);
5325 #if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
5326 dhdp->memdump_type = DUMP_TYPE_BY_SYSDUMP;
5327 dhd_bus_mem_dump(dhdp);
5328 #endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
5329 #ifdef DHD_PKT_LOGGING
5330 dhd_schedule_pktlog_dump(dhdp);
5331 #endif /* DHD_PKT_LOGGING */
5332 }
5333 #endif /* DHD_LOG_DUMP */
5334 #ifdef SET_PCIE_IRQ_CPU_CORE
5335 else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
5336 int set = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
5337 wl_android_set_irq_cpucore(net, set);
5338 }
5339 #endif /* SET_PCIE_IRQ_CPU_CORE */
5340 #if defined(DHD_HANG_SEND_UP_TEST)
5341 else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
5342 int skip = strlen(CMD_MAKE_HANG) + 1;
5343 wl_android_make_hang_with_reason(net, (const char*)command+skip);
5344 }
5345 #endif /* DHD_HANG_SEND_UP_TEST */
5346 #ifdef SUPPORT_LQCM
5347 else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
5348 int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
5349 bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
5350 }
5351 else if (strnicmp(command, CMD_GET_LQCM_REPORT,
5352 strlen(CMD_GET_LQCM_REPORT)) == 0) {
5353 bytes_written = wl_android_get_lqcm_report(net, command,
5354 priv_cmd.total_len);
5355 }
5356 #endif
5357 else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
5358 bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
5359 }
5360 #ifdef WLADPS_PRIVATE_CMD
5361 else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
5362 int skip = strlen(CMD_SET_ADPS) + 1;
5363 bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
5364 }
5365 else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
5366 bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
5367 }
5368 #endif /* WLADPS_PRIVATE_CMD */
5369 #ifdef DHD_PKT_LOGGING
5370 else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
5371 strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
5372 bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
5373 }
5374 else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
5375 strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
5376 bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
5377 }
5378 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
5379 strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
5380 bytes_written =
5381 wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
5382 }
5383 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
5384 strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
5385 bytes_written =
5386 wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
5387 }
5388 else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
5389 bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
5390 }
5391 else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
5392 bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
5393 }
5394 else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
5395 bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
5396 }
5397 else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
5398 bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
5399 }
5400 else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
5401 bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
5402 }
5403 #endif /* DHD_PKT_LOGGING */
5404 #if defined(STAT_REPORT)
5405 else if (strnicmp(command, CMD_STAT_REPORT_GET_START,
5406 strlen(CMD_STAT_REPORT_GET_START)) == 0) {
5407 bytes_written = wl_android_stat_report_get_start(net, command, priv_cmd.total_len);
5408 } else if (strnicmp(command, CMD_STAT_REPORT_GET_NEXT,
5409 strlen(CMD_STAT_REPORT_GET_NEXT)) == 0) {
5410 bytes_written = wl_android_stat_report_get_next(net, command, priv_cmd.total_len);
5411 }
5412 #endif /* STAT_REPORT */
5413 else if (wl_android_ext_priv_cmd(net, command, priv_cmd.total_len, &bytes_written) == 0) {
5414 }
5415 else {
5416 ANDROID_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
5417 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
5418 }
5419
5420 return bytes_written;
5421 }
5422
wl_android_init(void)5423 int wl_android_init(void)
5424 {
5425 int ret = 0;
5426
5427 #if defined(ENABLE_INSMOD_NO_FW_LOAD) || defined(BUS_POWER_RESTORE)
5428 dhd_download_fw_on_driverload = FALSE;
5429 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
5430 if (!iface_name[0]) {
5431 memset(iface_name, 0, IFNAMSIZ);
5432 bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
5433 }
5434
5435 #ifdef WL_RELMCAST
5436 wl_netlink_init();
5437 #endif /* WL_RELMCAST */
5438
5439 return ret;
5440 }
5441
wl_android_exit(void)5442 int wl_android_exit(void)
5443 {
5444 int ret = 0;
5445 struct io_cfg *cur, *q;
5446
5447 #ifdef WL_RELMCAST
5448 wl_netlink_deinit();
5449 #endif
5450
5451 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5452 #pragma GCC diagnostic push
5453 #pragma GCC diagnostic ignored "-Wcast-qual"
5454 #endif
5455 list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
5456 list_del(&cur->list);
5457 kfree(cur);
5458 }
5459 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5460 #pragma GCC diagnostic pop
5461 #endif
5462
5463 return ret;
5464 }
5465
wl_android_post_init(void)5466 void wl_android_post_init(void)
5467 {
5468
5469 #ifdef ENABLE_4335BT_WAR
5470 bcm_bt_unlock(lock_cookie_wifi);
5471 printk("%s: btlock released\n", __FUNCTION__);
5472 #endif /* ENABLE_4335BT_WAR */
5473
5474 if (!dhd_download_fw_on_driverload)
5475 g_wifi_on = FALSE;
5476 }
5477
5478
5479
wl_fatal_error(void * wl,int rc)5480 int wl_fatal_error(void * wl, int rc)
5481 {
5482 return FALSE;
5483 }
5484
5485 #if defined(BT_OVER_SDIO)
5486 void
wl_android_set_wifi_on_flag(bool enable)5487 wl_android_set_wifi_on_flag(bool enable)
5488 {
5489 g_wifi_on = enable;
5490 }
5491 #endif /* BT_OVER_SDIO */
5492