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