1 /*
2 * Linux cfg80211 driver - Android related functions
3 *
4 * Copyright (C) 1999-2019, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions
16 * of the license of that module. An independent module is a module which is
17 * not 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 825470 2019-06-14 09:08:11Z $
28 */
29
30 #include <linux/module.h>
31 #include <linux/netdevice.h>
32 #include <net/netlink.h>
33 #ifdef CONFIG_COMPAT
34 #include <linux/compat.h>
35 #endif // endif
36
37 #include <wl_android.h>
38 #include <wldev_common.h>
39 #include <wlioctl.h>
40 #include <wlioctl_utils.h>
41 #include <bcmutils.h>
42 #include <bcmstdlib_s.h>
43 #include <linux_osl.h>
44 #include <dhd_dbg.h>
45 #include <dngl_stats.h>
46 #include <dhd.h>
47 #include <dhd_config.h>
48 #include <bcmip.h>
49 #ifdef PNO_SUPPORT
50 #include <dhd_pno.h>
51 #endif // endif
52 #ifdef BCMSDIO
53 #include <bcmsdbus.h>
54 #endif // endif
55 #ifdef WL_CFG80211
56 #include <wl_cfg80211.h>
57 #include <wl_cfgscan.h>
58 #endif // endif
59 #ifdef WL_NAN
60 #include <wl_cfgnan.h>
61 #endif /* WL_NAN */
62 #ifdef DHDTCPACK_SUPPRESS
63 #include <dhd_ip.h>
64 #endif /* DHDTCPACK_SUPPRESS */
65 #include <bcmwifi_rspec.h>
66 #include <dhd_linux.h>
67 #include <bcmiov.h>
68 #ifdef WL_BCNRECV
69 #include <wl_cfgvendor.h>
70 #include <brcm_nl80211.h>
71 #endif /* WL_BCNRECV */
72 #ifdef WL_MBO
73 #include <mbo.h>
74 #endif /* WL_MBO */
75 #ifdef RTT_SUPPORT
76 #include <dhd_rtt.h>
77 #endif /* RTT_SUPPORT */
78 #ifdef WL_ESCAN
79 #include <wl_escan.h>
80 #endif
81
82 #ifdef WL_STATIC_IF
83 #define WL_BSSIDX_MAX 16
84 #endif /* WL_STATIC_IF */
85
86 #ifdef CONFIG_AP6XXX_WIFI6_HDF
87 #include "net_device.h"
88
89 extern int g_event_ifidx;
90 struct NetDevice *get_hdf_netdev(int ifidx);
91 #endif
92
93 uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL;
94
95 #define ANDROID_ERROR_MSG(x, args...) \
96 do { \
97 if (android_msg_level & ANDROID_ERROR_LEVEL) { \
98 printk(KERN_ERR DHD_LOG_PREFIXS "ANDROID-ERROR) " x, ##args); \
99 } \
100 } while (0)
101 #define ANDROID_TRACE_MSG(x, args...) \
102 do { \
103 if (android_msg_level & ANDROID_TRACE_LEVEL) { \
104 printk(KERN_INFO DHD_LOG_PREFIXS "ANDROID-TRACE) " x, ##args); \
105 } \
106 } while (0)
107 #define ANDROID_INFO_MSG(x, args...) \
108 do { \
109 if (android_msg_level & ANDROID_INFO_LEVEL) { \
110 printk(KERN_INFO DHD_LOG_PREFIXS "ANDROID-INFO) " x, ##args); \
111 } \
112 } while (0)
113 #define ANDROID_ERROR(x) ANDROID_ERROR_MSG x
114 #define ANDROID_TRACE(x) ANDROID_TRACE_MSG x
115 #define ANDROID_INFO(x) ANDROID_INFO_MSG x
116
117 /*
118 * Android private command strings, PLEASE define new private commands here
119 * so they can be updated easily in the future (if needed)
120 */
121
122 #define CMD_START "START"
123 #define CMD_STOP "STOP"
124 #define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
125 #define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
126 #define CMD_RSSI "RSSI"
127 #define CMD_LINKSPEED "LINKSPEED"
128 #define CMD_RXFILTER_START "RXFILTER-START"
129 #define CMD_RXFILTER_STOP "RXFILTER-STOP"
130 #define CMD_RXFILTER_ADD "RXFILTER-ADD"
131 #define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
132 #define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
133 #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
134 #define CMD_BTCOEXMODE "BTCOEXMODE"
135 #define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
136 #define CMD_SETSUSPENDMODE "SETSUSPENDMODE"
137 #define CMD_SETDTIM_IN_SUSPEND "SET_DTIM_IN_SUSPEND"
138 #define CMD_MAXDTIM_IN_SUSPEND "MAX_DTIM_IN_SUSPEND"
139 #define CMD_DISDTIM_IN_SUSPEND "DISABLE_DTIM_IN_SUSPEND"
140 #define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
141 #define CMD_SETFWPATH "SETFWPATH"
142 #define CMD_SETBAND "SETBAND"
143 #define CMD_GETBAND "GETBAND"
144 #define CMD_COUNTRY "COUNTRY"
145 #define CMD_P2P_SET_NOA "P2P_SET_NOA"
146 #define CMD_P2P_GET_NOA "P2P_GET_NOA"
147 #define CMD_P2P_SD_OFFLOAD "P2P_SD_"
148 #define CMD_P2P_LISTEN_OFFLOAD "P2P_LO_"
149 #define CMD_P2P_SET_PS "P2P_SET_PS"
150 #define CMD_P2P_ECSA "P2P_ECSA"
151 #define CMD_P2P_INC_BW "P2P_INCREASE_BW"
152 #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
153 #define CMD_SETROAMMODE "SETROAMMODE"
154 #define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA"
155 #define CMD_MIRACAST "MIRACAST"
156 #ifdef WL_NAN
157 #define CMD_NAN "NAN_"
158 #endif /* WL_NAN */
159 #define CMD_COUNTRY_DELIMITER "/"
160
161 #if defined(WL_SUPPORT_AUTO_CHANNEL)
162 #define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS"
163 #endif /* WL_SUPPORT_AUTO_CHANNEL */
164
165 #define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */
166 #define CMD_CHANSPEC "CHANSPEC"
167 #define CMD_DATARATE "DATARATE"
168 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
169 #define CMD_SET_CSA "SETCSA"
170 #ifdef WL_SUPPORT_AUTO_CHANNEL
171 #define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL"
172 #endif /* WL_SUPPORT_AUTO_CHANNEL */
173 #define CMD_KEEP_ALIVE "KEEPALIVE"
174
175 #ifdef PNO_SUPPORT
176 #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR"
177 #define CMD_PNOSETUP_SET "PNOSETUP "
178 #define CMD_PNOENABLE_SET "PNOFORCE"
179 #define CMD_PNODEBUG_SET "PNODEBUG"
180 #define CMD_WLS_BATCHING "WLS_BATCHING"
181 #endif /* PNO_SUPPORT */
182
183 #define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER"
184
185 #ifdef WLFBT
186 #define CMD_GET_FTKEY "GET_FTKEY"
187 #endif // endif
188
189 #define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
190 #define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
191 #define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
192 #define CMD_GET_LINK_STATUS "GETLINKSTATUS"
193
194 #define CMD_GET_STA_INFO "GETSTAINFO"
195
196 /* related with CMD_GET_LINK_STATUS */
197 #define WL_ANDROID_LINK_VHT 0x01
198 #define WL_ANDROID_LINK_MIMO 0x02
199 #define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04
200 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08
201
202 #ifdef P2PRESP_WFDIE_SRC
203 #define CMD_P2P_SET_WFDIE_RESP "P2P_SET_WFDIE_RESP"
204 #define CMD_P2P_GET_WFDIE_RESP "P2P_GET_WFDIE_RESP"
205 #endif /* P2PRESP_WFDIE_SRC */
206
207 #define CMD_DFS_AP_MOVE "DFS_AP_MOVE"
208 #define CMD_WBTEXT_ENABLE "WBTEXT_ENABLE"
209 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
210 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
211 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
212 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
213 #define CMD_WBTEXT_BTM_TIMER_THRESHOLD "WBTEXT_BTM_TIMER_THRESHOLD"
214 #define CMD_WBTEXT_BTM_DELTA "WBTEXT_BTM_DELTA"
215 #define CMD_WBTEXT_ESTM_ENABLE "WBTEXT_ESTM_ENABLE"
216
217 #define BUFSZ 8
218 #define BUFSZN BUFSZ + 1
219
220 #define _S(x) #x
221 #define S(x) _S(x)
222
223 #define MAXBANDS 2 /**< Maximum #of bands */
224 #define BAND_2G_INDEX 0
225 #define BAND_5G_INDEX 0
226
227 typedef union {
228 wl_roam_prof_band_v1_t v1;
229 wl_roam_prof_band_v2_t v2;
230 wl_roam_prof_band_v3_t v3;
231 } wl_roamprof_band_t;
232
233 #ifdef WLWFDS
234 #define CMD_ADD_WFDS_HASH "ADD_WFDS_HASH"
235 #define CMD_DEL_WFDS_HASH "DEL_WFDS_HASH"
236 #endif /* WLWFDS */
237
238 #ifdef SET_RPS_CPUS
239 #define CMD_RPSMODE "RPSMODE"
240 #endif /* SET_RPS_CPUS */
241
242 #ifdef BT_WIFI_HANDOVER
243 #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
244 #endif /* BT_WIFI_HANDOVER */
245
246 #define CMD_MURX_BFE_CAP "MURX_BFE_CAP"
247
248 #ifdef SUPPORT_RSSI_SUM_REPORT
249 #define CMD_SET_RSSI_LOGGING "SET_RSSI_LOGGING"
250 #define CMD_GET_RSSI_LOGGING "GET_RSSI_LOGGING"
251 #define CMD_GET_RSSI_PER_ANT "GET_RSSI_PER_ANT"
252 #endif /* SUPPORT_RSSI_SUM_REPORT */
253
254 #define CMD_GET_SNR "GET_SNR"
255
256 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
257 #define CMD_SET_AP_BEACONRATE "SET_AP_BEACONRATE"
258 #define CMD_GET_AP_BASICRATE "GET_AP_BASICRATE"
259 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
260
261 #ifdef SUPPORT_AP_RADIO_PWRSAVE
262 #define CMD_SET_AP_RPS "SET_AP_RPS"
263 #define CMD_GET_AP_RPS "GET_AP_RPS"
264 #define CMD_SET_AP_RPS_PARAMS "SET_AP_RPS_PARAMS"
265 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
266
267 #ifdef SUPPORT_AP_SUSPEND
268 #define CMD_SET_AP_SUSPEND "SET_AP_SUSPEND"
269 #endif /* SUPPORT_AP_SUSPEND */
270
271 #ifdef SUPPORT_AP_BWCTRL
272 #define CMD_SET_AP_BW "SET_AP_BW"
273 #define CMD_GET_AP_BW "GET_AP_BW"
274 #endif /* SUPPORT_AP_BWCTRL */
275
276 /* miracast related definition */
277 #define MIRACAST_MODE_OFF 0
278 #define MIRACAST_MODE_SOURCE 1
279 #define MIRACAST_MODE_SINK 2
280
281 #ifdef CONNECTION_STATISTICS
282 #define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS"
283
284 struct connection_stats {
285 u32 txframe;
286 u32 txbyte;
287 u32 txerror;
288 u32 rxframe;
289 u32 rxbyte;
290 u32 txfail;
291 u32 txretry;
292 u32 txretrie;
293 u32 txrts;
294 u32 txnocts;
295 u32 txexptime;
296 u32 txrate;
297 u8 chan_idle;
298 };
299 #endif /* CONNECTION_STATISTICS */
300
301 #ifdef SUPPORT_LQCM
302 #define CMD_SET_LQCM_ENABLE "SET_LQCM_ENABLE"
303 #define CMD_GET_LQCM_REPORT "GET_LQCM_REPORT"
304 #endif // endif
305
306 static LIST_HEAD(miracast_resume_list);
307 #ifdef WL_CFG80211
308 static u8 miracast_cur_mode;
309 #endif /* WL_CFG80211 */
310
311 #ifdef DHD_LOG_DUMP
312 #define CMD_NEW_DEBUG_PRINT_DUMP "DEBUG_DUMP"
313 #define SUBCMD_UNWANTED "UNWANTED"
314 #define SUBCMD_DISCONNECTED "DISCONNECTED"
315 void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
316 #endif /* DHD_LOG_DUMP */
317
318 #ifdef DHD_STATUS_LOGGING
319 #define CMD_DUMP_STATUS_LOG "DUMP_STAT_LOG"
320 #define CMD_QUERY_STATUS_LOG "QUERY_STAT_LOG"
321 #endif /* DHD_STATUS_LOGGING */
322
323 #ifdef DHD_DEBUG_UART
324 extern bool dhd_debug_uart_is_running(struct net_device *dev);
325 #endif /* DHD_DEBUG_UART */
326
327 #ifdef RTT_GEOFENCE_INTERVAL
328 #if defined(RTT_SUPPORT) && defined(WL_NAN)
329 #define CMD_GEOFENCE_INTERVAL "GEOFENCE_INT"
330 #endif /* RTT_SUPPORT && WL_NAN */
331 #endif /* RTT_GEOFENCE_INTERVAL */
332
333 struct io_cfg {
334 s8 *iovar;
335 s32 param;
336 u32 ioctl;
337 void *arg;
338 u32 len;
339 struct list_head list;
340 };
341
342 typedef enum {
343 HEAD_SAR_BACKOFF_DISABLE = -1,
344 HEAD_SAR_BACKOFF_ENABLE = 0,
345 GRIP_SAR_BACKOFF_DISABLE,
346 GRIP_SAR_BACKOFF_ENABLE,
347 NR_mmWave_SAR_BACKOFF_DISABLE,
348 NR_mmWave_SAR_BACKOFF_ENABLE,
349 NR_Sub6_SAR_BACKOFF_DISABLE,
350 NR_Sub6_SAR_BACKOFF_ENABLE,
351 SAR_BACKOFF_DISABLE_ALL
352 } sar_modes;
353
354 #if defined(BCMFW_ROAM_ENABLE)
355 #define CMD_SET_ROAMPREF "SET_ROAMPREF"
356
357 #define MAX_NUM_SUITES 10
358 #define WIDTH_AKM_SUITE 8
359 #define JOIN_PREF_RSSI_LEN 0x02
360 #define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */
361 #define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */
362 #define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */
363 #define JOIN_PREF_MAX_WPA_TUPLES 16
364 #define MAX_BUF_SIZE \
365 (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \
366 (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
367 #endif /* BCMFW_ROAM_ENABLE */
368
369 #define CMD_DEBUG_VERBOSE "DEBUG_VERBOSE"
370 #ifdef WL_NATOE
371
372 #define CMD_NATOE "NATOE"
373
374 #define NATOE_MAX_PORT_NUM 65535
375
376 /* natoe command info structure */
377 typedef struct wl_natoe_cmd_info {
378 uint8 *command; /* pointer to the actual command */
379 uint16 tot_len; /* total length of the command */
380 uint16 bytes_written; /* Bytes written for get response */
381 } wl_natoe_cmd_info_t;
382
383 typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
384 typedef int(natoe_cmd_handler_t)(struct net_device *dev,
385 const wl_natoe_sub_cmd_t *cmd, char *command,
386 wl_natoe_cmd_info_t *cmd_info);
387
388 struct wl_natoe_sub_cmd {
389 char *name;
390 uint8 version; /* cmd version */
391 uint16 id; /* id for the dongle f/w switch/case */
392 uint16 type; /* base type of argument */
393 natoe_cmd_handler_t *handler; /* cmd handler */
394 };
395
396 #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_##suffix
397 static int wl_android_process_natoe_cmd(struct net_device *dev, char *command,
398 int total_len);
399 static int wl_android_natoe_subcmd_enable(struct net_device *dev,
400 const wl_natoe_sub_cmd_t *cmd,
401 char *command,
402 wl_natoe_cmd_info_t *cmd_info);
403 static int wl_android_natoe_subcmd_config_ips(struct net_device *dev,
404 const wl_natoe_sub_cmd_t *cmd,
405 char *command,
406 wl_natoe_cmd_info_t *cmd_info);
407 static int wl_android_natoe_subcmd_config_ports(struct net_device *dev,
408 const wl_natoe_sub_cmd_t *cmd,
409 char *command,
410 wl_natoe_cmd_info_t *cmd_info);
411 static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev,
412 const wl_natoe_sub_cmd_t *cmd,
413 char *command,
414 wl_natoe_cmd_info_t *cmd_info);
415 static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
416 const wl_natoe_sub_cmd_t *cmd,
417 char *command,
418 wl_natoe_cmd_info_t *cmd_info);
419
420 static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
421 /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
422 {"enable", 0x01, WL_NATOE_CMD_ENABLE, IOVT_BUFFER,
423 WL_ANDROID_NATOE_FUNC(enable)},
424 {"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS, IOVT_BUFFER,
425 WL_ANDROID_NATOE_FUNC(config_ips)},
426 {"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS, IOVT_BUFFER,
427 WL_ANDROID_NATOE_FUNC(config_ports)},
428 {"stats", 0x01, WL_NATOE_CMD_DBG_STATS, IOVT_BUFFER,
429 WL_ANDROID_NATOE_FUNC(dbg_stats)},
430 {"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT, IOVT_BUFFER,
431 WL_ANDROID_NATOE_FUNC(tbl_cnt)},
432 {NULL, 0, 0, 0, NULL}};
433
434 #endif /* WL_NATOE */
435
436 #ifdef SET_PCIE_IRQ_CPU_CORE
437 #define CMD_PCIE_IRQ_CORE "PCIE_IRQ_CORE"
438 #endif /* SET_PCIE_IRQ_CPU_CORE */
439
440 #ifdef WL_BCNRECV
441 #define CMD_BEACON_RECV "BEACON_RECV"
442 #endif /* WL_BCNRECV */
443 #ifdef WL_CAC_TS
444 #define CMD_CAC_TSPEC "CAC_TSPEC"
445 #endif /* WL_CAC_TS */
446 #ifdef WL_CHAN_UTIL
447 #define CMD_GET_CHAN_UTIL "GET_CU"
448 #endif /* WL_CHAN_UTIL */
449
450 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
451 #define CMD_SET_SOFTAP_ELNA_BYPASS "SET_SOFTAP_ELNA_BYPASS"
452 #define CMD_GET_SOFTAP_ELNA_BYPASS "GET_SOFTAP_ELNA_BYPASS"
453 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
454
455 #ifdef WL_NAN
456 #define CMD_GET_NAN_STATUS "GET_NAN_STATUS"
457 #endif /* WL_NAN */
458
459 /* drv command info structure */
460 typedef struct wl_drv_cmd_info {
461 uint8 *command; /* pointer to the actual command */
462 uint16 tot_len; /* total length of the command */
463 uint16 bytes_written; /* Bytes written for get response */
464 } wl_drv_cmd_info_t;
465
466 typedef struct wl_drv_sub_cmd wl_drv_sub_cmd_t;
467 typedef int(drv_cmd_handler_t)(struct net_device *dev,
468 const wl_drv_sub_cmd_t *cmd, char *command,
469 wl_drv_cmd_info_t *cmd_info);
470
471 struct wl_drv_sub_cmd {
472 char *name;
473 uint8 version; /* cmd version */
474 uint16 id; /* id for the dongle f/w switch/case */
475 uint16 type; /* base type of argument */
476 drv_cmd_handler_t *handler; /* cmd handler */
477 };
478
479 #ifdef WL_MBO
480
481 #define CMD_MBO "MBO"
482 enum { WL_MBO_CMD_NON_CHAN_PREF = 1, WL_MBO_CMD_CELL_DATA_CAP = 2 };
483 #define WL_ANDROID_MBO_FUNC(suffix) wl_android_mbo_subcmd_##suffix
484
485 static int wl_android_process_mbo_cmd(struct net_device *dev, char *command,
486 int total_len);
487 static int wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev,
488 const wl_drv_sub_cmd_t *cmd,
489 char *command,
490 wl_drv_cmd_info_t *cmd_info);
491 static int wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
492 const wl_drv_sub_cmd_t *cmd,
493 char *command,
494 wl_drv_cmd_info_t *cmd_info);
495
496 static const wl_drv_sub_cmd_t mbo_cmd_list[] = {
497 {"non_pref_chan", 0x01, WL_MBO_CMD_NON_CHAN_PREF, IOVT_BUFFER,
498 WL_ANDROID_MBO_FUNC(non_pref_chan)},
499 {"cell_data_cap", 0x01, WL_MBO_CMD_CELL_DATA_CAP, IOVT_BUFFER,
500 WL_ANDROID_MBO_FUNC(cell_data_cap)},
501 {NULL, 0, 0, 0, NULL}};
502
503 #endif /* WL_MBO */
504
505 #ifdef WL_GENL
506 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
507 static int wl_genl_init(void);
508 static int wl_genl_deinit(void);
509
510 extern struct net init_net;
511 /* attribute policy: defines which attribute has which type (e.g int, char *
512 * etc) possible values defined in net/netlink.h
513 */
514 static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
515 [BCM_GENL_ATTR_STRING] = {.type = NLA_NUL_STRING},
516 [BCM_GENL_ATTR_MSG] = {.type = NLA_BINARY},
517 };
518
519 #define WL_GENL_VER 1
520 /* family definition */
521 static struct genl_family wl_genl_family = {
522 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
523 .hdrsize = 0,
524 .name = "bcm-genl", /* Netlink I/F for Android */
525 .version = WL_GENL_VER, /* Version Number */
526 .maxattr = BCM_GENL_ATTR_MAX,
527 };
528
529 /* commands: mapping between the command enumeration and the actual function */
530 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
531 struct genl_ops wl_genl_ops[] = {
532 {
533 .cmd = BCM_GENL_CMD_MSG,
534 .flags = 0,
535 .policy = wl_genl_policy,
536 .doit = wl_genl_handle_msg,
537 .dumpit = NULL,
538 },
539 };
540 #else
541 struct genl_ops wl_genl_ops = {
542 .cmd = BCM_GENL_CMD_MSG,
543 .flags = 0,
544 .policy = wl_genl_policy,
545 .doit = wl_genl_handle_msg,
546 .dumpit = NULL,
547
548 };
549 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
550
551 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
552 static struct genl_multicast_group wl_genl_mcast[] = {
553 {
554 .name = "bcm-genl-mcast",
555 },
556 };
557 #else
558 static struct genl_multicast_group wl_genl_mcast = {
559 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
560 .name = "bcm-genl-mcast",
561 };
562 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
563 #endif /* WL_GENL */
564
565 #ifdef SUPPORT_LQCM
566 #define LQCM_ENAB_MASK 0x000000FF /* LQCM enable flag mask */
567 #define LQCM_TX_INDEX_MASK 0x0000FF00 /* LQCM tx index mask */
568 #define LQCM_RX_INDEX_MASK 0x00FF0000 /* LQCM rx index mask */
569
570 #define LQCM_TX_INDEX_SHIFT 8 /* LQCM tx index shift */
571 #define LQCM_RX_INDEX_SHIFT 16 /* LQCM rx index shift */
572 #endif /* SUPPORT_LQCM */
573
574 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
575 #define NUMBER_SEQUENTIAL_PRIVCMD_ERRORS 7
576 static int priv_cmd_errors = 0;
577 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
578
579 /**
580 * Extern function declarations (move them to dhd_linux.h)
581 */
582 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
583 int dhd_dev_init_ioctl(struct net_device *dev);
584 #ifdef WL_CFG80211
585 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net,
586 struct ether_addr *p2pdev_addr);
587 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd,
588 char *command);
589 #else
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)590 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net,
591 struct ether_addr *p2pdev_addr)
592 {
593 return 0;
594 }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)595 int wl_cfg80211_set_p2p_noa(struct net_device *net, char *buf, int len)
596 {
597 return 0;
598 }
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)599 int wl_cfg80211_get_p2p_noa(struct net_device *net, char *buf, int len)
600 {
601 return 0;
602 }
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)603 int wl_cfg80211_set_p2p_ps(struct net_device *net, char *buf, int len)
604 {
605 return 0;
606 }
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)607 int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char *buf, int len)
608 {
609 return 0;
610 }
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)611 int wl_cfg80211_increase_p2p_bw(struct net_device *net, char *buf, int len)
612 {
613 return 0;
614 }
615 #endif /* WL_CFG80211 */
616 #ifdef ROAM_CHANNEL_CACHE
617 extern void wl_update_roamscan_cache_by_band(struct net_device *dev, int band);
618 #endif /* ROAM_CHANNEL_CACHE */
619
620 #ifdef ENABLE_4335BT_WAR
621 extern int bcm_bt_lock(int cookie);
622 extern void bcm_bt_unlock(int cookie);
623 static int lock_cookie_wifi =
624 'W' | 'i' << 8 | 'F' << 16 | 'i' << 24; /* cookie is "WiFi" */
625 #endif /* ENABLE_4335BT_WAR */
626
627 extern bool ap_fw_loaded;
628 extern char iface_name[IFNAMSIZ];
629 #ifdef DHD_PM_CONTROL_FROM_FILE
630 extern bool g_pm_control;
631 #endif /* DHD_PM_CONTROL_FROM_FILE */
632
633 /* private command support for restoring roam/scan parameters */
634 #ifdef SUPPORT_RESTORE_SCAN_PARAMS
635 #define CMD_RESTORE_SCAN_PARAMS "RESTORE_SCAN_PARAMS"
636
637 typedef int (*PRIV_CMD_HANDLER)(struct net_device *dev, char *command);
638 typedef int (*PRIV_CMD_HANDLER_WITH_LEN)(struct net_device *dev, char *command,
639 int total_len);
640
641 enum {
642 RESTORE_TYPE_UNSPECIFIED = 0,
643 RESTORE_TYPE_PRIV_CMD = 1,
644 RESTORE_TYPE_PRIV_CMD_WITH_LEN = 2
645 };
646
647 typedef struct android_restore_scan_params {
648 char command[64];
649 int parameter;
650 int cmd_type;
651 union {
652 PRIV_CMD_HANDLER cmd_handler;
653 PRIV_CMD_HANDLER_WITH_LEN cmd_handler_w_len;
654 };
655 } android_restore_scan_params_t;
656
657 /* function prototypes of private command handler */
658 static int wl_android_set_roam_trigger(struct net_device *dev, char *command);
659 int wl_android_set_roam_delta(struct net_device *dev, char *command);
660 int wl_android_set_roam_scan_period(struct net_device *dev, char *command);
661 int wl_android_set_full_roam_scan_period(struct net_device *dev, char *command,
662 int total_len);
663 int wl_android_set_roam_scan_control(struct net_device *dev, char *command);
664 int wl_android_set_scan_channel_time(struct net_device *dev, char *command);
665 int wl_android_set_scan_home_time(struct net_device *dev, char *command);
666 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command);
667 int wl_android_set_scan_nprobes(struct net_device *dev, char *command);
668 static int wl_android_set_band(struct net_device *dev, char *command);
669 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command);
670 int wl_android_set_wes_mode(struct net_device *dev, char *command);
671 int wl_android_set_okc_mode(struct net_device *dev, char *command);
672
673 /* default values */
674 #ifdef ROAM_API
675 #define DEFAULT_ROAM_TIRGGER -75
676 #define DEFAULT_ROAM_DELTA 10
677 #define DEFAULT_ROAMSCANPERIOD 10
678 #define DEFAULT_FULLROAMSCANPERIOD_SET 120
679 #endif /* ROAM_API */
680 #define DEFAULT_BAND 0
681
682 /* restoring parameter list, please don't change order */
683 static android_restore_scan_params_t restore_params[] = {
684 /* wbtext need to be disabled while updating roam/scan parameters */
685 #ifdef ROAM_API
686 {CMD_ROAMTRIGGER_SET, DEFAULT_ROAM_TIRGGER, RESTORE_TYPE_PRIV_CMD,
687 .cmd_handler = wl_android_set_roam_trigger},
688 {CMD_ROAMDELTA_SET, DEFAULT_ROAM_DELTA, RESTORE_TYPE_PRIV_CMD,
689 .cmd_handler = wl_android_set_roam_delta},
690 {CMD_ROAMSCANPERIOD_SET, DEFAULT_ROAMSCANPERIOD, RESTORE_TYPE_PRIV_CMD,
691 .cmd_handler = wl_android_set_roam_scan_period},
692 {CMD_FULLROAMSCANPERIOD_SET, DEFAULT_FULLROAMSCANPERIOD_SET,
693 RESTORE_TYPE_PRIV_CMD_WITH_LEN,
694 .cmd_handler_w_len = wl_android_set_full_roam_scan_period},
695 #endif /* ROAM_API */
696 {CMD_SETBAND, DEFAULT_BAND, RESTORE_TYPE_PRIV_CMD,
697 .cmd_handler = wl_android_set_band},
698 {"\0", 0, RESTORE_TYPE_UNSPECIFIED, .cmd_handler = NULL}};
699 #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
700
701 /**
702 * Local (static) functions and variables
703 */
704
705 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
706 * time (only) in dhd_open, subsequential wifi on will be handled by
707 * wl_android_wifi_on
708 */
709 int g_wifi_on = TRUE;
710
711 /**
712 * Local (static) function definitions
713 */
714
715 #ifdef WLWFDS
wl_android_set_wfds_hash(struct net_device * dev,char * command,bool enable)716 static int wl_android_set_wfds_hash(struct net_device *dev, char *command,
717 bool enable)
718 {
719 int error = 0;
720 wl_p2p_wfds_hash_t *wfds_hash = NULL;
721 char *smbuf = NULL;
722 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
723
724 smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
725 if (smbuf == NULL) {
726 ANDROID_ERROR(
727 ("wl_android_set_wfds_hash: failed to allocated memory %d bytes\n",
728 WLC_IOCTL_MAXLEN));
729 return -ENOMEM;
730 }
731
732 if (enable) {
733 wfds_hash =
734 (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
735 error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
736 sizeof(wl_p2p_wfds_hash_t), smbuf,
737 WLC_IOCTL_MAXLEN, NULL);
738 } else {
739 wfds_hash =
740 (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
741 error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
742 sizeof(wl_p2p_wfds_hash_t), smbuf,
743 WLC_IOCTL_MAXLEN, NULL);
744 }
745
746 if (error) {
747 ANDROID_ERROR(("wl_android_set_wfds_hash: failed to %s, error=%d\n",
748 command, error));
749 }
750
751 if (smbuf) {
752 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
753 }
754 return error;
755 }
756 #endif /* WLWFDS */
757
wl_android_get_link_speed(struct net_device * net,char * command,int total_len)758 static int wl_android_get_link_speed(struct net_device *net, char *command,
759 int total_len)
760 {
761 int link_speed;
762 int bytes_written;
763 int error;
764
765 error = wldev_get_link_speed(net, &link_speed);
766 if (error) {
767 ANDROID_ERROR(("Get linkspeed failed \n"));
768 return -1;
769 }
770
771 /* Convert Kbps to Android Mbps */
772 link_speed = link_speed / 0x3E8;
773 bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
774 ANDROID_INFO(
775 ("wl_android_get_link_speed: command result is %s\n", command));
776 return bytes_written;
777 }
778
wl_android_get_rssi(struct net_device * net,char * command,int total_len)779 static int wl_android_get_rssi(struct net_device *net, char *command,
780 int total_len)
781 {
782 wlc_ssid_t ssid = {0, {0}};
783 int bytes_written = 0;
784 int error = 0;
785 scb_val_t scbval;
786 char *delim = NULL;
787 struct net_device *target_ndev = net;
788 #ifdef WL_VIRTUAL_APSTA
789 char *pos = NULL;
790 struct bcm_cfg80211 *cfg;
791 #endif /* WL_VIRTUAL_APSTA */
792
793 delim = strchr(command, ' ');
794 /* For Ap mode rssi command would be
795 * driver rssi <sta_mac_addr>
796 * for STA/GC mode
797 * driver rssi
798 */
799 if (delim) {
800 /* Ap/GO mode
801 * driver rssi <sta_mac_addr>
802 */
803 ANDROID_TRACE(("wl_android_get_rssi: cmd:%s\n", delim));
804 /* skip space from delim after finding char */
805 delim++;
806 if (!(bcm_ether_atoe((delim), &scbval.ea))) {
807 ANDROID_ERROR(("wl_android_get_rssi: address err\n"));
808 return -1;
809 }
810 scbval.val = htod32(0);
811 ANDROID_TRACE(("wl_android_get_rssi: address:" MACDBG,
812 MAC2STRDBG(scbval.ea.octet)));
813 #ifdef WL_VIRTUAL_APSTA
814 /* RSDB AP may have another virtual interface
815 * In this case, format of private command is as following,
816 * DRIVER rssi <sta_mac_addr> <AP interface name>
817 */
818
819 /* Current position is start of MAC address string */
820 pos = delim;
821 delim = strchr(pos, ' ');
822 if (delim) {
823 /* skip space from delim after finding char */
824 delim++;
825 if (strnlen(delim, IFNAMSIZ)) {
826 cfg = wl_get_cfg(net);
827 target_ndev = wl_get_ap_netdev(cfg, delim);
828 if (target_ndev == NULL) {
829 target_ndev = net;
830 }
831 }
832 }
833 #endif /* WL_VIRTUAL_APSTA */
834 } else {
835 /* STA/GC mode */
836 bzero(&scbval, sizeof(scb_val_t));
837 }
838
839 error = wldev_get_rssi(target_ndev, &scbval);
840 if (error) {
841 return -1;
842 }
843 #if defined(RSSIOFFSET)
844 scbval.val = wl_update_rssi_offset(net, scbval.val);
845 #endif
846
847 error = wldev_get_ssid(target_ndev, &ssid);
848 if (error) {
849 return -1;
850 }
851 if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
852 ANDROID_ERROR(("wl_android_get_rssi: wldev_get_ssid failed\n"));
853 } else if (total_len <= ssid.SSID_len) {
854 return -ENOMEM;
855 } else {
856 memcpy(command, ssid.SSID, ssid.SSID_len);
857 bytes_written = ssid.SSID_len;
858 }
859 if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1)) {
860 return -ENOMEM;
861 }
862
863 bytes_written +=
864 scnprintf(&command[bytes_written], total_len - bytes_written,
865 " rssi %d", scbval.val);
866 command[bytes_written] = '\0';
867
868 ANDROID_TRACE(("wl_android_get_rssi: command result is %s (%d)\n", command,
869 bytes_written));
870 return bytes_written;
871 }
872
wl_android_set_suspendopt(struct net_device * dev,char * command)873 static int wl_android_set_suspendopt(struct net_device *dev, char *command)
874 {
875 int suspend_flag;
876 int ret_now;
877 int ret = 0;
878
879 suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
880 if (suspend_flag != 0) {
881 suspend_flag = 1;
882 }
883 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
884 if (ret_now != suspend_flag) {
885 if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
886 ANDROID_INFO(("wl_android_set_suspendopt: Suspend Flag %d -> %d\n",
887 ret_now, suspend_flag));
888 } else {
889 ANDROID_ERROR(("wl_android_set_suspendopt: failed %d\n", ret));
890 }
891 }
892
893 return ret;
894 }
895
wl_android_set_suspendmode(struct net_device * dev,char * command)896 static int wl_android_set_suspendmode(struct net_device *dev, char *command)
897 {
898 int ret = 0;
899
900 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
901 int suspend_flag;
902
903 suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
904 if (suspend_flag != 0) {
905 suspend_flag = 1;
906 }
907
908 if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) {
909 ANDROID_INFO(
910 ("wl_android_set_suspendmode: Suspend Mode %d\n", suspend_flag));
911 } else {
912 ANDROID_ERROR(("wl_android_set_suspendmode: failed %d\n", ret));
913 }
914 #endif // endif
915
916 return ret;
917 }
918
919 #ifdef WL_CFG80211
wl_android_get_80211_mode(struct net_device * dev,char * command,int total_len)920 int wl_android_get_80211_mode(struct net_device *dev, char *command,
921 int total_len)
922 {
923 uint8 mode[0x5];
924 int error = 0;
925 int bytes_written = 0;
926
927 error = wldev_get_mode(dev, mode, sizeof(mode));
928 if (error) {
929 return -1;
930 }
931
932 ANDROID_INFO(("wl_android_get_80211_mode: mode:%s\n", mode));
933 bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
934 ANDROID_INFO(("wl_android_get_80211_mode: command:%s EXIT\n", command));
935 return bytes_written;
936 }
937
938 extern chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
wl_android_get_chanspec(struct net_device * dev,char * command,int total_len)939 int wl_android_get_chanspec(struct net_device *dev, char *command,
940 int total_len)
941 {
942 int error = 0;
943 int bytes_written = 0;
944 int chsp = {0};
945 uint16 band = 0;
946 uint16 bw = 0;
947 uint16 channel = 0;
948 u32 sb = 0;
949 chanspec_t chanspec;
950
951 /* command is
952 * driver chanspec
953 */
954 error = wldev_iovar_getint(dev, "chanspec", &chsp);
955 if (error) {
956 return -1;
957 }
958
959 chanspec = wl_chspec_driver_to_host(chsp);
960 ANDROID_INFO(
961 ("wl_android_get_80211_mode: return value of chanspec:%x\n", chanspec));
962
963 channel = chanspec & WL_CHANSPEC_CHAN_MASK;
964 band = chanspec & WL_CHANSPEC_BAND_MASK;
965 bw = chanspec & WL_CHANSPEC_BW_MASK;
966
967 ANDROID_INFO(
968 ("wl_android_get_80211_mode: channel:%d band:%d bandwidth:%d\n",
969 channel, band, bw));
970
971 if (bw == WL_CHANSPEC_BW_80) {
972 bw = WL_CH_BANDWIDTH_80MHZ;
973 } else if (bw == WL_CHANSPEC_BW_40) {
974 bw = WL_CH_BANDWIDTH_40MHZ;
975 } else if (bw == WL_CHANSPEC_BW_20) {
976 bw = WL_CH_BANDWIDTH_20MHZ;
977 } else {
978 bw = WL_CH_BANDWIDTH_20MHZ;
979 }
980
981 if (bw == WL_CH_BANDWIDTH_40MHZ) {
982 if (CHSPEC_SB_UPPER(chanspec)) {
983 channel += CH_10MHZ_APART;
984 } else {
985 channel -= CH_10MHZ_APART;
986 }
987 } else if (bw == WL_CH_BANDWIDTH_80MHZ) {
988 sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
989 if (sb == WL_CHANSPEC_CTL_SB_LL) {
990 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
991 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
992 channel -= CH_10MHZ_APART;
993 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
994 channel += CH_10MHZ_APART;
995 } else {
996 /* WL_CHANSPEC_CTL_SB_UU */
997 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
998 }
999 }
1000 bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d",
1001 CMD_CHANSPEC, channel,
1002 band == WL_CHANSPEC_BAND_5G ? "5G" : "2G", bw);
1003
1004 ANDROID_INFO(("wl_android_get_chanspec: command:%s EXIT\n", command));
1005 return bytes_written;
1006 }
1007 #endif /* WL_CFG80211 */
1008
1009 /* returns current datarate datarate returned from firmware are in 500kbps */
wl_android_get_datarate(struct net_device * dev,char * command,int total_len)1010 int wl_android_get_datarate(struct net_device *dev, char *command,
1011 int total_len)
1012 {
1013 int error = 0;
1014 int datarate = 0;
1015 int bytes_written = 0;
1016
1017 error = wldev_get_datarate(dev, &datarate);
1018 if (error) {
1019 return -1;
1020 }
1021
1022 ANDROID_INFO(("wl_android_get_datarate: datarate:%d\n", datarate));
1023
1024 bytes_written =
1025 snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate / 0x2));
1026 return bytes_written;
1027 }
wl_android_get_assoclist(struct net_device * dev,char * command,int total_len)1028 int wl_android_get_assoclist(struct net_device *dev, char *command,
1029 int total_len)
1030 {
1031 int error = 0;
1032 int bytes_written = 0;
1033 uint i;
1034 int len = 0;
1035 char mac_buf[MAX_NUM_OF_ASSOCLIST * sizeof(struct ether_addr) +
1036 sizeof(uint)] = {0};
1037 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
1038
1039 ANDROID_TRACE(("wl_android_get_assoclist: ENTER\n"));
1040
1041 assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
1042
1043 error =
1044 wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
1045 if (error) {
1046 return -1;
1047 }
1048
1049 assoc_maclist->count = dtoh32(assoc_maclist->count);
1050 bytes_written = snprintf(command, total_len,
1051 "%s listcount: %d Stations:", CMD_ASSOC_CLIENTS,
1052 assoc_maclist->count);
1053
1054 for (i = 0; i < assoc_maclist->count; i++) {
1055 len = snprintf(command + bytes_written, total_len - bytes_written,
1056 " " MACDBG, MAC2STRDBG(assoc_maclist->ea[i].octet));
1057 /* A return value of '(total_len - bytes_written)' or more means that
1058 * the output was truncated
1059 */
1060 if ((len > 0) && (len < (total_len - bytes_written))) {
1061 bytes_written += len;
1062 } else {
1063 ANDROID_ERROR(("wl_android_get_assoclist: Insufficient buffer %d,"
1064 " bytes_written %d\n",
1065 total_len, bytes_written));
1066 bytes_written = -1;
1067 break;
1068 }
1069 }
1070 return bytes_written;
1071 }
1072
1073 #ifdef WL_CFG80211
1074 extern chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
wl_android_set_csa(struct net_device * dev,char * command)1075 static int wl_android_set_csa(struct net_device *dev, char *command)
1076 {
1077 int error = 0;
1078 char smbuf[WLC_IOCTL_SMLEN];
1079 wl_chan_switch_t csa_arg;
1080 u32 chnsp = 0;
1081 int err = 0;
1082
1083 ANDROID_INFO(("wl_android_set_csa: command:%s\n", command));
1084
1085 command = (command + strlen(CMD_SET_CSA));
1086 /* Order is mode, count channel */
1087 if (!*++command) {
1088 ANDROID_ERROR(("wl_android_set_csa:error missing arguments\n"));
1089 return -1;
1090 }
1091 csa_arg.mode = bcm_atoi(command);
1092
1093 if (csa_arg.mode != 0 && csa_arg.mode != 1) {
1094 ANDROID_ERROR(("Invalid mode\n"));
1095 return -1;
1096 }
1097
1098 if (!*++command) {
1099 ANDROID_ERROR(("wl_android_set_csa: error missing count\n"));
1100 return -1;
1101 }
1102 command++;
1103 csa_arg.count = bcm_atoi(command);
1104
1105 csa_arg.reg = 0;
1106 csa_arg.chspec = 0;
1107 command += 0x2;
1108 if (!*command) {
1109 ANDROID_ERROR(("wl_android_set_csa: error missing channel\n"));
1110 return -1;
1111 }
1112
1113 chnsp = wf_chspec_aton(command);
1114 if (chnsp == 0) {
1115 ANDROID_ERROR(("wl_android_set_csa:chsp is not correct\n"));
1116 return -1;
1117 }
1118 chnsp = wl_chspec_host_to_driver(chnsp);
1119 csa_arg.chspec = chnsp;
1120
1121 if (chnsp & WL_CHANSPEC_BAND_5G) {
1122 u32 chanspec = chnsp;
1123 err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
1124 if (!err) {
1125 if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
1126 ANDROID_ERROR(("Channel is radar sensitive\n"));
1127 return -1;
1128 }
1129 if (chanspec == 0) {
1130 ANDROID_ERROR(("Invalid hw channel\n"));
1131 return -1;
1132 }
1133 } else {
1134 ANDROID_ERROR(("does not support per_chan_info\n"));
1135 return -1;
1136 }
1137 ANDROID_INFO(("non radar sensitivity\n"));
1138 }
1139 error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg), smbuf,
1140 sizeof(smbuf), NULL);
1141 if (error) {
1142 ANDROID_ERROR(("wl_android_set_csa:set csa failed:%d\n", error));
1143 return -1;
1144 }
1145 return 0;
1146 }
1147 #endif /* WL_CFG80211 */
1148
wl_android_set_bcn_li_dtim(struct net_device * dev,char * command)1149 static int wl_android_set_bcn_li_dtim(struct net_device *dev, char *command)
1150 {
1151 int ret = 0;
1152 int dtim;
1153
1154 dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0';
1155 if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) {
1156 ANDROID_ERROR(("%s: failed, invalid dtim %d\n", __FUNCTION__, dtim));
1157 return BCME_ERROR;
1158 }
1159
1160 if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) {
1161 ANDROID_TRACE(
1162 ("%s: SET bcn_li_dtim in suspend %d\n", __FUNCTION__, dtim));
1163 } else {
1164 ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1165 }
1166
1167 return ret;
1168 }
1169
wl_android_set_max_dtim(struct net_device * dev,char * command)1170 static int wl_android_set_max_dtim(struct net_device *dev, char *command)
1171 {
1172 int ret = 0;
1173 int dtim_flag;
1174
1175 dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
1176 if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
1177 ANDROID_TRACE(
1178 ("wl_android_set_max_dtim: use Max bcn_li_dtim in suspend %s\n",
1179 (dtim_flag ? "Enable" : "Disable")));
1180 } else {
1181 ANDROID_ERROR(("wl_android_set_max_dtim: failed %d\n", ret));
1182 }
1183
1184 return ret;
1185 }
1186
1187 #ifdef DISABLE_DTIM_IN_SUSPEND
wl_android_set_disable_dtim_in_suspend(struct net_device * dev,char * command)1188 static int wl_android_set_disable_dtim_in_suspend(struct net_device *dev,
1189 char *command)
1190 {
1191 int ret = 0;
1192 int dtim_flag;
1193
1194 dtim_flag = *(command + strlen(CMD_DISDTIM_IN_SUSPEND) + 1) - '0';
1195 if (!(ret = net_os_set_disable_dtim_in_suspend(dev, dtim_flag))) {
1196 ANDROID_TRACE(("wl_android_set_disable_dtim_in_suspend: "
1197 "use Disable bcn_li_dtim in suspend %s\n",
1198 (dtim_flag ? "Enable" : "Disable")));
1199 } else {
1200 ANDROID_ERROR(
1201 ("wl_android_set_disable_dtim_in_suspend: failed %d\n", ret));
1202 }
1203
1204 return ret;
1205 }
1206 #endif /* DISABLE_DTIM_IN_SUSPEND */
1207
wl_android_get_band(struct net_device * dev,char * command,int total_len)1208 static int wl_android_get_band(struct net_device *dev, char *command,
1209 int total_len)
1210 {
1211 uint band;
1212 int bytes_written;
1213 int error;
1214
1215 error = wldev_get_band(dev, &band);
1216 if (error) {
1217 return -1;
1218 }
1219 bytes_written = snprintf(command, total_len, "Band %d", band);
1220 return bytes_written;
1221 }
1222
1223 #ifdef WL_CFG80211
wl_android_set_band(struct net_device * dev,char * command)1224 static int wl_android_set_band(struct net_device *dev, char *command)
1225 {
1226 int error = 0;
1227 uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
1228 #ifdef WL_HOST_BAND_MGMT
1229 int ret = 0;
1230 if ((ret = wl_cfg80211_set_band(dev, band)) < 0) {
1231 if (ret == BCME_UNSUPPORTED) {
1232 /* If roam_var is unsupported, fallback to the original method */
1233 ANDROID_ERROR(
1234 ("WL_HOST_BAND_MGMT defined, "
1235 "but roam_band iovar unsupported in the firmware\n"));
1236 } else {
1237 error = -1;
1238 }
1239 }
1240 if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) {
1241 /* Apply if roam_band iovar is not supported or band setting is AUTO */
1242 error = wldev_set_band(dev, band);
1243 }
1244 #else
1245 error = wl_cfg80211_set_if_band(dev, band);
1246 #endif /* WL_HOST_BAND_MGMT */
1247 #ifdef ROAM_CHANNEL_CACHE
1248 wl_update_roamscan_cache_by_band(dev, band);
1249 #endif /* ROAM_CHANNEL_CACHE */
1250 return error;
1251 }
1252 #endif /* WL_CFG80211 */
1253
1254 #ifdef PNO_SUPPORT
1255 #define PNO_PARAM_SIZE 50
1256 #define VALUE_SIZE 50
1257 #define LIMIT_STR_FMT ("%50s %50s")
1258
wls_parse_batching_cmd(struct net_device * dev,char * command,int total_len)1259 static int wls_parse_batching_cmd(struct net_device *dev, char *command,
1260 int total_len)
1261 {
1262 int err = BCME_OK;
1263 uint i, tokens, len_remain;
1264 char *pos, *pos2, *token, *token2, *delim;
1265 char param[PNO_PARAM_SIZE + 1], value[VALUE_SIZE + 1];
1266 struct dhd_pno_batch_params batch_params;
1267
1268 ANDROID_INFO(
1269 ("wls_parse_batching_cmd: command=%s, len=%d\n", command, total_len));
1270 len_remain = total_len;
1271 if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) {
1272 pos = command + strlen(CMD_WLS_BATCHING) + 1;
1273 len_remain -= strlen(CMD_WLS_BATCHING) + 1;
1274 } else {
1275 ANDROID_ERROR(("wls_parse_batching_cmd: No arguments, total_len %d\n",
1276 total_len));
1277 err = BCME_ERROR;
1278 goto exit;
1279 }
1280 bzero(&batch_params, sizeof(struct dhd_pno_batch_params));
1281 if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
1282 if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) {
1283 pos += strlen(PNO_BATCHING_SET) + 1;
1284 } else {
1285 ANDROID_ERROR(
1286 ("wls_parse_batching_cmd: %s missing arguments, total_len %d\n",
1287 PNO_BATCHING_SET, total_len));
1288 err = BCME_ERROR;
1289 goto exit;
1290 }
1291 while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
1292 bzero(param, sizeof(param));
1293 bzero(value, sizeof(value));
1294 if (token == NULL || !*token) {
1295 break;
1296 }
1297 if (*token == '\0') {
1298 continue;
1299 }
1300 delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
1301 if (delim != NULL) {
1302 *delim = ' ';
1303 }
1304
1305 tokens = sscanf(token, LIMIT_STR_FMT, param, value);
1306 if (!strncmp(param, PNO_PARAM_SCANFREQ,
1307 strlen(PNO_PARAM_SCANFREQ))) {
1308 batch_params.scan_fr = simple_strtol(value, NULL, 0);
1309 ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr));
1310 } else if (!strncmp(param, PNO_PARAM_BESTN,
1311 strlen(PNO_PARAM_BESTN))) {
1312 batch_params.bestn = simple_strtol(value, NULL, 0);
1313 ANDROID_INFO(("bestn : %d\n", batch_params.bestn));
1314 } else if (!strncmp(param, PNO_PARAM_MSCAN,
1315 strlen(PNO_PARAM_MSCAN))) {
1316 batch_params.mscan = simple_strtol(value, NULL, 0);
1317 ANDROID_INFO(("mscan : %d\n", batch_params.mscan));
1318 } else if (!strncmp(param, PNO_PARAM_CHANNEL,
1319 strlen(PNO_PARAM_CHANNEL))) {
1320 i = 0;
1321 pos2 = value;
1322 tokens = sscanf(value, "<%s>", value);
1323 if (tokens != 1) {
1324 err = BCME_ERROR;
1325 ANDROID_ERROR(("wls_parse_batching_cmd: invalid format"
1326 " for channel"
1327 " <> params\n"));
1328 goto exit;
1329 }
1330 while ((token2 = strsep(&pos2, PNO_PARAM_CHANNEL_DELIMETER)) !=
1331 NULL) {
1332 if (token2 == NULL || !*token2) {
1333 break;
1334 }
1335 if (*token2 == '\0') {
1336 continue;
1337 }
1338 if (*token2 == 'A' || *token2 == 'B') {
1339 batch_params.band =
1340 (*token2 == 'A') ? WLC_BAND_5G : WLC_BAND_2G;
1341 ANDROID_INFO(
1342 ("band : %s\n", (*token2 == 'A') ? "A" : "B"));
1343 } else {
1344 if ((batch_params.nchan >= WL_NUMCHANNELS) ||
1345 (i >= WL_NUMCHANNELS)) {
1346 ANDROID_ERROR(
1347 ("Too many nchan %d\n", batch_params.nchan));
1348 err = BCME_BUFTOOSHORT;
1349 goto exit;
1350 }
1351 batch_params.chan_list[i++] =
1352 simple_strtol(token2, NULL, 0);
1353 batch_params.nchan++;
1354 ANDROID_INFO(
1355 ("channel :%d\n", batch_params.chan_list[i - 1]));
1356 }
1357 }
1358 } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
1359 batch_params.rtt = simple_strtol(value, NULL, 0);
1360 ANDROID_INFO(("rtt : %d\n", batch_params.rtt));
1361 } else {
1362 ANDROID_ERROR(
1363 ("wls_parse_batching_cmd : unknown param: %s\n", param));
1364 err = BCME_ERROR;
1365 goto exit;
1366 }
1367 }
1368 err = dhd_dev_pno_set_for_batch(dev, &batch_params);
1369 if (err < 0) {
1370 ANDROID_ERROR(("failed to configure batch scan\n"));
1371 } else {
1372 bzero(command, total_len);
1373 err = snprintf(command, total_len, "%d", err);
1374 }
1375 } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
1376 err = dhd_dev_pno_get_for_batch(dev, command, total_len);
1377 if (err < 0) {
1378 ANDROID_ERROR(("failed to getting batching results\n"));
1379 } else {
1380 err = strlen(command);
1381 }
1382 } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
1383 err = dhd_dev_pno_stop_for_batch(dev);
1384 if (err < 0) {
1385 ANDROID_ERROR(("failed to stop batching scan\n"));
1386 } else {
1387 bzero(command, total_len);
1388 err = snprintf(command, total_len, "OK");
1389 }
1390 } else {
1391 ANDROID_ERROR(("wls_parse_batching_cmd : unknown command\n"));
1392 err = BCME_ERROR;
1393 goto exit;
1394 }
1395 exit:
1396 return err;
1397 }
1398
1399 #ifndef WL_SCHED_SCAN
wl_android_set_pno_setup(struct net_device * dev,char * command,int total_len)1400 static int wl_android_set_pno_setup(struct net_device *dev, char *command,
1401 int total_len)
1402 {
1403 wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
1404 int res = -1;
1405 int nssid = 0;
1406 cmd_tlv_t *cmd_tlv_temp;
1407 char *str_ptr;
1408 int tlv_size_left;
1409 int pno_time = 0;
1410 int pno_repeat = 0;
1411 int pno_freq_expo_max = 0;
1412
1413 #ifdef PNO_SET_DEBUG
1414 int i;
1415 char pno_in_example[] = {'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
1416 'S', '1', '2', '0', 'S', 0x05, 'd', 'l', 'i',
1417 'n', 'k', 'S', 0x04, 'G', 'O', 'O', 'G', 'T',
1418 '0', 'B', 'R', '2', 'M', '2', 0x00};
1419 #endif /* PNO_SET_DEBUG */
1420 ANDROID_INFO(
1421 ("wl_android_set_pno_setup: command=%s, len=%d\n", command, total_len));
1422
1423 if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
1424 ANDROID_ERROR(("wl_android_set_pno_setup: argument=%d less min size\n",
1425 total_len));
1426 goto exit_proc;
1427 }
1428 #ifdef PNO_SET_DEBUG
1429 memcpy(command, pno_in_example, sizeof(pno_in_example));
1430 total_len = sizeof(pno_in_example);
1431 #endif // endif
1432 str_ptr = command + strlen(CMD_PNOSETUP_SET);
1433 tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
1434
1435 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
1436 bzero(ssids_local, sizeof(ssids_local));
1437
1438 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
1439 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
1440 (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
1441 str_ptr += sizeof(cmd_tlv_t);
1442 tlv_size_left -= sizeof(cmd_tlv_t);
1443 if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
1444 MAX_PFN_LIST_COUNT,
1445 &tlv_size_left)) <= 0) {
1446 ANDROID_ERROR(
1447 ("SSID is not presented or corrupted ret=%d\n", nssid));
1448 goto exit_proc;
1449 } else {
1450 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
1451 ANDROID_ERROR(
1452 ("wl_android_set_pno_setup: scan duration corrupted"
1453 " field size %d\n",
1454 tlv_size_left));
1455 goto exit_proc;
1456 }
1457 str_ptr++;
1458 pno_time = simple_strtoul(str_ptr, &str_ptr, 0x10);
1459 ANDROID_INFO(("wl_android_set_pno_setup: pno_time=%d\n", pno_time));
1460
1461 if (str_ptr[0] != 0) {
1462 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
1463 ANDROID_ERROR(("wl_android_set_pno_setup: pno repeat:"
1464 " corrupted field\n"));
1465 goto exit_proc;
1466 }
1467 str_ptr++;
1468 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 0x10);
1469 ANDROID_INFO(("wl_android_set_pno_setup: got pno_repeat=%d\n",
1470 pno_repeat));
1471 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
1472 ANDROID_ERROR(("wl_android_set_pno_setup: FREQ_EXPO_MAX"
1473 " corrupted field size\n"));
1474 goto exit_proc;
1475 }
1476 str_ptr++;
1477 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 0x10);
1478 ANDROID_INFO(
1479 ("wl_android_set_pno_setup: pno_freq_expo_max=%d\n",
1480 pno_freq_expo_max));
1481 }
1482 }
1483 } else {
1484 ANDROID_ERROR(("wl_android_set_pno_setup: get wrong TLV command\n"));
1485 goto exit_proc;
1486 }
1487
1488 res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time,
1489 pno_repeat, pno_freq_expo_max, NULL, 0);
1490 exit_proc:
1491 return res;
1492 }
1493 #endif /* !WL_SCHED_SCAN */
1494 #endif /* PNO_SUPPORT */
1495
wl_android_get_p2p_dev_addr(struct net_device * ndev,char * command,int total_len)1496 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command,
1497 int total_len)
1498 {
1499 int ret;
1500 struct ether_addr p2pdev_addr;
1501
1502 #define MAC_ADDR_STR_LEN 18
1503 if (total_len < MAC_ADDR_STR_LEN) {
1504 ANDROID_ERROR(("wl_android_get_p2p_dev_addr: buflen %d is less than "
1505 "p2p dev addr\n",
1506 total_len));
1507 return -1;
1508 }
1509
1510 ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr);
1511 if (ret) {
1512 ANDROID_ERROR(
1513 ("wl_android_get_p2p_dev_addr: Failed to get p2p dev addr\n"));
1514 return -1;
1515 }
1516 return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr)));
1517 }
1518
wl_android_set_ap_mac_list(struct net_device * dev,int macmode,struct maclist * maclist)1519 int wl_android_set_ap_mac_list(struct net_device *dev, int macmode,
1520 struct maclist *maclist)
1521 {
1522 int i, j, match;
1523 int ret = 0;
1524 char mac_buf[MAX_NUM_OF_ASSOCLIST * sizeof(struct ether_addr) +
1525 sizeof(uint)] = {0};
1526 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
1527
1528 /* set filtering mode */
1529 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode,
1530 sizeof(macmode)) != 0)) {
1531 ANDROID_ERROR(
1532 ("wl_android_set_ap_mac_list : WLC_SET_MACMODE error=%d\n", ret));
1533 return ret;
1534 }
1535 if (macmode != MACLIST_MODE_DISABLED) {
1536 /* set the MAC filter list */
1537 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
1538 sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
1539 ANDROID_ERROR(
1540 ("wl_android_set_ap_mac_list : WLC_SET_MACLIST error=%d\n",
1541 ret));
1542 return ret;
1543 }
1544 /* get the current list of associated STAs */
1545 assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
1546 if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
1547 sizeof(mac_buf))) != 0) {
1548 ANDROID_ERROR(
1549 ("wl_android_set_ap_mac_list: WLC_GET_ASSOCLIST error=%d\n",
1550 ret));
1551 return ret;
1552 }
1553 /* do we have any STA associated? */
1554 if (assoc_maclist->count) {
1555 /* iterate each associated STA */
1556 for (i = 0; i < assoc_maclist->count; i++) {
1557 match = 0;
1558 /* compare with each entry */
1559 for (j = 0; j < maclist->count; j++) {
1560 ANDROID_INFO(
1561 ("wl_android_set_ap_mac_list: associated=" MACDBG
1562 "list = " MACDBG "\n",
1563 MAC2STRDBG(assoc_maclist->ea[i].octet),
1564 MAC2STRDBG(maclist->ea[j].octet)));
1565 if (memcmp(assoc_maclist->ea[i].octet, maclist->ea[j].octet,
1566 ETHER_ADDR_LEN) == 0) {
1567 match = 1;
1568 break;
1569 }
1570 }
1571 /* do conditional deauth */
1572 /* "if not in the allow list" or "if in the deny list" */
1573 if ((macmode == MACLIST_MODE_ALLOW && !match) ||
1574 (macmode == MACLIST_MODE_DENY && match)) {
1575 scb_val_t scbval;
1576
1577 scbval.val = htod32(1);
1578 memcpy(&scbval.ea, &assoc_maclist->ea[i], ETHER_ADDR_LEN);
1579 if ((ret = wldev_ioctl_set(
1580 dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
1581 sizeof(scb_val_t))) != 0) {
1582 ANDROID_ERROR(("wl_android_set_ap_mac_list:"
1583 " WLC_SCB_DEAUTHENTICATE"
1584 " error=%d\n",
1585 ret));
1586 }
1587 }
1588 }
1589 }
1590 }
1591 return ret;
1592 }
1593
1594 /*
1595 * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
1596 *
1597 */
wl_android_set_mac_address_filter(struct net_device * dev,char * str)1598 static int wl_android_set_mac_address_filter(struct net_device *dev, char *str)
1599 {
1600 int i;
1601 int ret = 0;
1602 int macnum = 0;
1603 int macmode = MACLIST_MODE_DISABLED;
1604 struct maclist *list;
1605 char eabuf[ETHER_ADDR_STR_LEN];
1606 const char *token;
1607 dhd_pub_t *dhd = dhd_get_pub(dev);
1608
1609 /* string should look like below (macmode/macnum/maclist) */
1610 /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */
1611
1612 /* get the MAC filter mode */
1613 token = strsep((char **)&str, " ");
1614 if (!token) {
1615 return -1;
1616 }
1617 macmode = bcm_atoi(token);
1618 if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
1619 ANDROID_ERROR(
1620 ("wl_android_set_mac_address_filter: invalid macmode %d\n",
1621 macmode));
1622 return -1;
1623 }
1624
1625 token = strsep((char **)&str, " ");
1626 if (!token) {
1627 return -1;
1628 }
1629 macnum = bcm_atoi(token);
1630 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
1631 ANDROID_ERROR(
1632 ("wl_android_set_mac_address_filter: invalid number of MAC"
1633 " address entries %d\n",
1634 macnum));
1635 return -1;
1636 }
1637 /* allocate memory for the MAC list */
1638 list = (struct maclist *)MALLOCZ(
1639 dhd->osh, sizeof(int) + sizeof(struct ether_addr) * macnum);
1640 if (!list) {
1641 ANDROID_ERROR((
1642 "wl_android_set_mac_address_filter : failed to allocate memory\n"));
1643 return -1;
1644 }
1645 /* prepare the MAC list */
1646 list->count = htod32(macnum);
1647 bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
1648 for (i = 0; i < list->count; i++) {
1649 token = strsep((char **)&str, " ");
1650 if (token == NULL) {
1651 ANDROID_ERROR(("wl_android_set_mac_address_filter : No mac address "
1652 "present\n"));
1653 ret = -EINVAL;
1654 goto exit;
1655 }
1656 strlcpy(eabuf, token, sizeof(eabuf));
1657 if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
1658 ANDROID_ERROR(
1659 ("wl_android_set_mac_address_filter : mac parsing err index=%d,"
1660 " addr=%s\n",
1661 i, eabuf));
1662 list->count = i;
1663 break;
1664 }
1665 ANDROID_INFO(("wl_android_set_mac_address_filter : %d/%d MACADDR=%s", i,
1666 list->count, eabuf));
1667 }
1668 if (i == 0) {
1669 goto exit;
1670 }
1671
1672 /* set the list */
1673 if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0) {
1674 ANDROID_ERROR(("wl_android_set_mac_address_filter: Setting MAC list "
1675 "failed error=%d\n",
1676 ret));
1677 }
1678
1679 exit:
1680 MFREE(dhd->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
1681
1682 return ret;
1683 }
1684
1685 /**
1686 * Global function definitions (declared in wl_android.h)
1687 */
1688
wl_android_wifi_on(struct net_device * dev)1689 int wl_android_wifi_on(struct net_device *dev)
1690 {
1691 int ret = 0;
1692 int retry = POWERUP_MAX_RETRY;
1693
1694 if (!dev) {
1695 ANDROID_ERROR(("wl_android_wifi_on: dev is null\n"));
1696 return -EINVAL;
1697 }
1698
1699 dhd_net_if_lock(dev);
1700 WL_MSG(dev->name, "in g_wifi_on=%d\n", g_wifi_on);
1701 if (!g_wifi_on) {
1702 do {
1703 dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
1704 #ifdef BCMSDIO
1705 ret = dhd_net_bus_resume(dev, 0);
1706 #endif /* BCMSDIO */
1707 #ifdef BCMPCIE
1708 ret = dhd_net_bus_devreset(dev, FALSE);
1709 #endif /* BCMPCIE */
1710 if (ret == 0) {
1711 break;
1712 }
1713 ANDROID_ERROR(
1714 ("failed to power up wifi chip, retry again (%d left) **\n\n",
1715 retry));
1716 #ifdef BCMPCIE
1717 dhd_net_bus_devreset(dev, TRUE);
1718 #endif /* BCMPCIE */
1719 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
1720 } while (retry-- > 0);
1721 if (ret != 0) {
1722 ANDROID_ERROR(
1723 ("failed to power up wifi chip, max retry reached **\n\n"));
1724 #ifdef BCM_DETECT_TURN_ON_FAILURE
1725 BUG_ON(1);
1726 #endif /* BCM_DETECT_TURN_ON_FAILURE */
1727 goto exit;
1728 }
1729 #if defined(BCMSDIO) || defined(BCMDBUS)
1730 ret = dhd_net_bus_devreset(dev, FALSE);
1731 if (ret) {
1732 goto err;
1733 }
1734 #ifdef BCMSDIO
1735 dhd_net_bus_resume(dev, 1);
1736 #endif /* BCMSDIO */
1737 #endif /* BCMSDIO || BCMDBUS */
1738 #if defined(BCMSDIO) || defined(BCMDBUS)
1739 if (!ret) {
1740 if (dhd_dev_init_ioctl(dev) < 0) {
1741 ret = -EFAULT;
1742 goto err;
1743 }
1744 }
1745 #endif /* BCMSDIO || BCMDBUS */
1746 g_wifi_on = TRUE;
1747 }
1748
1749 exit:
1750 WL_MSG(dev->name, "Success\n");
1751 dhd_net_if_unlock(dev);
1752 return ret;
1753
1754 #if defined(BCMSDIO) || defined(BCMDBUS)
1755 err:
1756 dhd_net_bus_devreset(dev, TRUE);
1757 #ifdef BCMSDIO
1758 dhd_net_bus_suspend(dev);
1759 #endif /* BCMSDIO */
1760 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
1761 WL_MSG(dev->name, "Failed\n");
1762 dhd_net_if_unlock(dev);
1763 return ret;
1764 #endif /* BCMSDIO || BCMDBUS */
1765 }
1766
wl_android_wifi_off(struct net_device * dev,bool on_failure)1767 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
1768 {
1769 int ret = 0;
1770
1771 if (!dev) {
1772 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
1773 return -EINVAL;
1774 }
1775
1776 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
1777 ret = dhd_debug_uart_is_running(dev);
1778 if (ret) {
1779 ANDROID_ERROR(("wl_android_wifi_off: - Debug UART App is running\n"));
1780 return -EBUSY;
1781 }
1782 #endif /* BCMPCIE && DHD_DEBUG_UART */
1783 dhd_net_if_lock(dev);
1784 WL_MSG(dev->name, "in g_wifi_on=%d, on_failure=%d\n", g_wifi_on,
1785 on_failure);
1786 if (g_wifi_on || on_failure) {
1787 #if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
1788 ret = dhd_net_bus_devreset(dev, TRUE);
1789 #ifdef BCMSDIO
1790 dhd_net_bus_suspend(dev);
1791 #endif /* BCMSDIO */
1792 #endif /* BCMSDIO || BCMPCIE || BCMDBUS */
1793 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
1794 g_wifi_on = FALSE;
1795 }
1796 WL_MSG(dev->name, "out\n");
1797 dhd_net_if_unlock(dev);
1798
1799 return ret;
1800 }
1801
wl_android_set_fwpath(struct net_device * net,char * command,int total_len)1802 static int wl_android_set_fwpath(struct net_device *net, char *command,
1803 int total_len)
1804 {
1805 if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN) {
1806 return -1;
1807 }
1808 return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
1809 }
1810
1811 #ifdef CONNECTION_STATISTICS
wl_chanim_stats(struct net_device * dev,u8 * chan_idle)1812 static int wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
1813 {
1814 int err;
1815 wl_chanim_stats_t *list;
1816 /* Parameter _and_ returned buffer of chanim_stats. */
1817 wl_chanim_stats_t param;
1818 u8 result[WLC_IOCTL_SMLEN];
1819 chanim_stats_t *stats;
1820
1821 bzero(¶m, sizeof(param));
1822
1823 param.buflen = htod32(sizeof(wl_chanim_stats_t));
1824 param.count = htod32(WL_CHANIM_COUNT_ONE);
1825
1826 if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char *)¶m,
1827 sizeof(wl_chanim_stats_t), (char *)result,
1828 sizeof(result), 0)) < 0) {
1829 ANDROID_ERROR(("Failed to get chanim results %d \n", err));
1830 return err;
1831 }
1832
1833 list = (wl_chanim_stats_t *)result;
1834
1835 list->buflen = dtoh32(list->buflen);
1836 list->version = dtoh32(list->version);
1837 list->count = dtoh32(list->count);
1838
1839 if (list->buflen == 0) {
1840 list->version = 0;
1841 list->count = 0;
1842 } else if (list->version != WL_CHANIM_STATS_VERSION) {
1843 ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d "
1844 "but driver supports only version %d.\n",
1845 list->version, WL_CHANIM_STATS_VERSION));
1846 list->buflen = 0;
1847 list->count = 0;
1848 }
1849
1850 stats = list->stats;
1851 stats->glitchcnt = dtoh32(stats->glitchcnt);
1852 stats->badplcp = dtoh32(stats->badplcp);
1853 stats->chanspec = dtoh16(stats->chanspec);
1854 stats->timestamp = dtoh32(stats->timestamp);
1855 stats->chan_idle = dtoh32(stats->chan_idle);
1856
1857 ANDROID_INFO(
1858 ("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
1859 stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
1860 stats->timestamp));
1861
1862 *chan_idle = stats->chan_idle;
1863
1864 return (err);
1865 }
1866
wl_android_get_connection_stats(struct net_device * dev,char * command,int total_len)1867 static int wl_android_get_connection_stats(struct net_device *dev,
1868 char *command, int total_len)
1869 {
1870 static char iovar_buf[WLC_IOCTL_MAXLEN];
1871 const wl_cnt_wlc_t *wlc_cnt = NULL;
1872 #ifndef DISABLE_IF_COUNTERS
1873 wl_if_stats_t *if_stats = NULL;
1874 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1875 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1876 #endif /* DISABLE_IF_COUNTERS */
1877
1878 int link_speed = 0;
1879 struct connection_stats *output;
1880 unsigned int bufsize = 0;
1881 int bytes_written = -1;
1882 int ret = 0;
1883
1884 ANDROID_INFO(
1885 ("wl_android_get_connection_stats: enter Get Connection Stats\n"));
1886
1887 if (total_len <= 0) {
1888 ANDROID_ERROR(
1889 ("wl_android_get_connection_stats: invalid buffer size %d\n",
1890 total_len));
1891 goto error;
1892 }
1893
1894 bufsize = total_len;
1895 if (bufsize < sizeof(struct connection_stats)) {
1896 ANDROID_ERROR(("wl_android_get_connection_stats: not enough buffer "
1897 "size, provided=%u,"
1898 " requires=%zu\n",
1899 bufsize, sizeof(struct connection_stats)));
1900 goto error;
1901 }
1902
1903 output = (struct connection_stats *)command;
1904
1905 #ifndef DISABLE_IF_COUNTERS
1906 if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
1907 if (if_stats == NULL) {
1908 ANDROID_ERROR(("wl_android_get_connection_stats: MALLOCZ failed\n"));
1909 goto error;
1910 }
1911 bzero(if_stats, sizeof(*if_stats));
1912
1913 if (FW_SUPPORTED(dhdp, ifst)) {
1914 ret = wl_cfg80211_ifstats_counters(dev, if_stats);
1915 } else {
1916 ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0, (char *)if_stats,
1917 sizeof(*if_stats), NULL);
1918 }
1919
1920 ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0, (char *)if_stats,
1921 sizeof(*if_stats), NULL);
1922 if (ret) {
1923 ANDROID_ERROR(("wl_android_get_connection_stats: if_counters not "
1924 "supported ret=%d\n",
1925 ret));
1926
1927 /* In case if_stats IOVAR is not supported, get information from
1928 * counters. */
1929 #endif /* DISABLE_IF_COUNTERS */
1930 ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, iovar_buf,
1931 WLC_IOCTL_MAXLEN, NULL);
1932 if (unlikely(ret)) {
1933 ANDROID_ERROR(("counters error (%d) - size = %zu\n", ret,
1934 sizeof(wl_cnt_wlc_t)));
1935 goto error;
1936 }
1937 ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
1938 if (ret != BCME_OK) {
1939 ANDROID_ERROR(("wl_android_get_connection_stats:"
1940 " wl_cntbuf_to_xtlv_format ERR %d\n",
1941 ret));
1942 goto error;
1943 }
1944
1945 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
1946 ANDROID_ERROR(("wl_android_get_connection_stats: wlc_cnt NULL!\n"));
1947 goto error;
1948 }
1949
1950 output->txframe = dtoh32(wlc_cnt->txframe);
1951 output->txbyte = dtoh32(wlc_cnt->txbyte);
1952 output->txerror = dtoh32(wlc_cnt->txerror);
1953 output->rxframe = dtoh32(wlc_cnt->rxframe);
1954 output->rxbyte = dtoh32(wlc_cnt->rxbyte);
1955 output->txfail = dtoh32(wlc_cnt->txfail);
1956 output->txretry = dtoh32(wlc_cnt->txretry);
1957 output->txretrie = dtoh32(wlc_cnt->txretrie);
1958 output->txrts = dtoh32(wlc_cnt->txrts);
1959 output->txnocts = dtoh32(wlc_cnt->txnocts);
1960 output->txexptime = dtoh32(wlc_cnt->txexptime);
1961 #ifndef DISABLE_IF_COUNTERS
1962 } else {
1963 /* Populate from if_stats. */
1964 if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
1965 ANDROID_ERROR(
1966 ("wl_android_get_connection_stats: incorrect version of"
1967 " wl_if_stats_t,"
1968 " expected=%u got=%u\n",
1969 WL_IF_STATS_T_VERSION, if_stats->version));
1970 goto error;
1971 }
1972
1973 output->txframe = (uint32)dtoh64(if_stats->txframe);
1974 output->txbyte = (uint32)dtoh64(if_stats->txbyte);
1975 output->txerror = (uint32)dtoh64(if_stats->txerror);
1976 output->rxframe = (uint32)dtoh64(if_stats->rxframe);
1977 output->rxbyte = (uint32)dtoh64(if_stats->rxbyte);
1978 output->txfail = (uint32)dtoh64(if_stats->txfail);
1979 output->txretry = (uint32)dtoh64(if_stats->txretry);
1980 output->txretrie = (uint32)dtoh64(if_stats->txretrie);
1981 if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
1982 output->txexptime = (uint32)dtoh64(if_stats->txexptime);
1983 output->txrts = (uint32)dtoh64(if_stats->txrts);
1984 output->txnocts = (uint32)dtoh64(if_stats->txnocts);
1985 } else {
1986 output->txexptime = 0;
1987 output->txrts = 0;
1988 output->txnocts = 0;
1989 }
1990 }
1991 #endif /* DISABLE_IF_COUNTERS */
1992
1993 /* link_speed is in kbps */
1994 ret = wldev_get_link_speed(dev, &link_speed);
1995 if (ret || link_speed < 0) {
1996 ANDROID_ERROR(("wl_android_get_connection_stats: wldev_get_link_speed()"
1997 " failed, ret=%d, speed=%d\n",
1998 ret, link_speed));
1999 goto error;
2000 }
2001
2002 output->txrate = link_speed;
2003
2004 /* Channel idle ratio. */
2005 if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
2006 output->chan_idle = 0;
2007 };
2008
2009 bytes_written = sizeof(struct connection_stats);
2010
2011 error:
2012 #ifndef DISABLE_IF_COUNTERS
2013 if (if_stats) {
2014 MFREE(cfg->osh, if_stats, sizeof(*if_stats));
2015 }
2016 #endif /* DISABLE_IF_COUNTERS */
2017
2018 return bytes_written;
2019 }
2020 #endif /* CONNECTION_STATISTICS */
2021
2022 #ifdef WL_NATOE
wl_android_process_natoe_cmd(struct net_device * dev,char * command,int total_len)2023 static int wl_android_process_natoe_cmd(struct net_device *dev, char *command,
2024 int total_len)
2025 {
2026 int ret = BCME_ERROR;
2027 char *pcmd = command;
2028 char *str = NULL;
2029 wl_natoe_cmd_info_t cmd_info;
2030 const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
2031
2032 /* skip to cmd name after "natoe" */
2033 str = bcmstrtok(&pcmd, " ", NULL);
2034
2035 /* If natoe subcmd name is not provided, return error */
2036 if (*pcmd == '\0') {
2037 ANDROID_ERROR(
2038 ("natoe subcmd not provided wl_android_process_natoe_cmd\n"));
2039 ret = -EINVAL;
2040 return ret;
2041 }
2042
2043 /* get the natoe command name to str */
2044 str = bcmstrtok(&pcmd, " ", NULL);
2045
2046 while (natoe_cmd->name != NULL) {
2047 if (strcmp(natoe_cmd->name, str) == 0) {
2048 /* dispacth cmd to appropriate handler */
2049 if (natoe_cmd->handler) {
2050 cmd_info.command = command;
2051 cmd_info.tot_len = total_len;
2052 ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
2053 }
2054 return ret;
2055 }
2056 natoe_cmd++;
2057 }
2058 return ret;
2059 }
2060
wlu_natoe_set_vars_cbfn(void * ctx,uint8 * data,uint16 type,uint16 len)2061 static int wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type,
2062 uint16 len)
2063 {
2064 int res = BCME_OK;
2065 wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
2066 uint8 *command = cmd_info->command;
2067 uint16 total_len = cmd_info->tot_len;
2068 uint16 bytes_written = 0;
2069
2070 UNUSED_PARAMETER(len);
2071
2072 switch (type) {
2073 case WL_NATOE_XTLV_ENABLE: {
2074 bytes_written = snprintf(command, total_len, "natoe: %s\n",
2075 *data ? "enabled" : "disabled");
2076 cmd_info->bytes_written = bytes_written;
2077 break;
2078 }
2079
2080 case WL_NATOE_XTLV_CONFIG_IPS: {
2081 wl_natoe_config_ips_t *config_ips;
2082 uint8 buf[0x10];
2083
2084 config_ips = (wl_natoe_config_ips_t *)data;
2085 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
2086 bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
2087 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
2088 bytes_written += snprintf(command + bytes_written, total_len,
2089 "sta netmask: %s\n", buf);
2090 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
2091 bytes_written += snprintf(command + bytes_written, total_len,
2092 "sta router ip: %s\n", buf);
2093 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
2094 bytes_written += snprintf(command + bytes_written, total_len,
2095 "sta dns ip: %s\n", buf);
2096 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
2097 bytes_written += snprintf(command + bytes_written, total_len,
2098 "ap ip: %s\n", buf);
2099 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
2100 bytes_written += snprintf(command + bytes_written, total_len,
2101 "ap netmask: %s\n", buf);
2102 cmd_info->bytes_written = bytes_written;
2103 break;
2104 }
2105
2106 case WL_NATOE_XTLV_CONFIG_PORTS: {
2107 wl_natoe_ports_config_t *ports_config;
2108
2109 ports_config = (wl_natoe_ports_config_t *)data;
2110 bytes_written =
2111 snprintf(command, total_len, "starting port num: %d\n",
2112 dtoh16(ports_config->start_port_num));
2113 bytes_written += snprintf(command + bytes_written, total_len,
2114 "number of ports: %d\n",
2115 dtoh16(ports_config->no_of_ports));
2116 cmd_info->bytes_written = bytes_written;
2117 break;
2118 }
2119
2120 case WL_NATOE_XTLV_DBG_STATS: {
2121 char *stats_dump = (char *)data;
2122
2123 bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
2124 cmd_info->bytes_written = bytes_written;
2125 break;
2126 }
2127
2128 case WL_NATOE_XTLV_TBL_CNT: {
2129 bytes_written =
2130 snprintf(command, total_len, "natoe max tbl entries: %d\n",
2131 dtoh32(*(uint32 *)data));
2132 cmd_info->bytes_written = bytes_written;
2133 break;
2134 }
2135
2136 default:
2137 /* ignore */
2138 break;
2139 }
2140
2141 return res;
2142 }
2143
2144 /*
2145 * --- common for all natoe get commands ----
2146 */
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)2147 static int wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
2148 uint16 iocsz, uint8 *buf, uint16 buflen,
2149 wl_natoe_cmd_info_t *cmd_info)
2150 {
2151 /* for gets we only need to pass ioc header */
2152 wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
2153 int res;
2154
2155 /* send getbuf natoe iovar */
2156 res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf, buflen, NULL);
2157 /* check the response buff */
2158 if ((res == BCME_OK)) {
2159 /* scans ioctl tlvbuf f& invokes the cbfn for processing */
2160 res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
2161 BCM_XTLV_OPTION_ALIGN32,
2162 wlu_natoe_set_vars_cbfn);
2163 if (res == BCME_OK) {
2164 res = cmd_info->bytes_written;
2165 }
2166 } else {
2167 ANDROID_ERROR(
2168 ("wl_natoe_get_ioctl: get command failed code %d\n", res));
2169 res = BCME_ERROR;
2170 }
2171 return res;
2172 }
2173
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)2174 static int wl_android_natoe_subcmd_enable(struct net_device *dev,
2175 const wl_natoe_sub_cmd_t *cmd,
2176 char *command,
2177 wl_natoe_cmd_info_t *cmd_info)
2178 {
2179 int ret = BCME_OK;
2180 wl_natoe_ioc_t *natoe_ioc;
2181 char *pcmd = command;
2182 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
2183 uint16 buflen = WL_NATOE_IOC_BUFSZ;
2184 bcm_xtlv_t *pxtlv = NULL;
2185 char *ioctl_buf = NULL;
2186 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2187
2188 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
2189 if (!ioctl_buf) {
2190 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2191 return -ENOMEM;
2192 }
2193
2194 /* alloc mem for ioctl headr + tlv data */
2195 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
2196 if (!natoe_ioc) {
2197 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2198 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2199 return -ENOMEM;
2200 }
2201
2202 /* make up natoe cmd ioctl header */
2203 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2204 natoe_ioc->id = htod16(cmd->id);
2205 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
2206 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2207
2208 if (*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2209 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2210 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2211 WLC_IOCTL_MEDLEN, cmd_info);
2212 if (ret != BCME_OK) {
2213 ANDROID_ERROR(
2214 ("Fail to get iovar wl_android_natoe_subcmd_enable\n"));
2215 ret = -EINVAL;
2216 }
2217 } else { /* set */
2218 uint8 val = bcm_atoi(pcmd);
2219
2220 /* buflen is max tlv data we can write, it will be decremented as we
2221 * pack */
2222 /* save buflen at start */
2223 uint16 buflen_at_start = buflen;
2224
2225 /* we'll adjust final ioc size at the end */
2226 ret =
2227 bcm_pack_xtlv_entry((uint8 **)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
2228 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
2229 if (ret != BCME_OK) {
2230 ret = -EINVAL;
2231 goto exit;
2232 }
2233
2234 /* adjust iocsz to the end of last data record */
2235 natoe_ioc->len = (buflen_at_start - buflen);
2236 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2237 ret = wldev_iovar_setbuf(dev, "natoe", natoe_ioc, iocsz, ioctl_buf,
2238 WLC_IOCTL_MEDLEN, NULL);
2239 if (ret != BCME_OK) {
2240 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2241 ret = -EINVAL;
2242 }
2243 }
2244
2245 exit:
2246 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2247 MFREE(cfg->osh, natoe_ioc, iocsz);
2248
2249 return ret;
2250 }
2251
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)2252 static int wl_android_natoe_subcmd_config_ips(struct net_device *dev,
2253 const wl_natoe_sub_cmd_t *cmd,
2254 char *command,
2255 wl_natoe_cmd_info_t *cmd_info)
2256 {
2257 int ret = BCME_OK;
2258 wl_natoe_config_ips_t config_ips;
2259 wl_natoe_ioc_t *natoe_ioc;
2260 char *pcmd = command;
2261 char *str;
2262 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
2263 uint16 buflen = WL_NATOE_IOC_BUFSZ;
2264 bcm_xtlv_t *pxtlv = NULL;
2265 char *ioctl_buf = NULL;
2266 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2267
2268 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
2269 if (!ioctl_buf) {
2270 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2271 return -ENOMEM;
2272 }
2273
2274 /* alloc mem for ioctl headr + tlv data */
2275 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
2276 if (!natoe_ioc) {
2277 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2278 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2279 return -ENOMEM;
2280 }
2281
2282 /* make up natoe cmd ioctl header */
2283 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2284 natoe_ioc->id = htod16(cmd->id);
2285 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
2286 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2287
2288 if (*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2289 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2290 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2291 WLC_IOCTL_MEDLEN, cmd_info);
2292 if (ret != BCME_OK) {
2293 ANDROID_ERROR(
2294 ("Fail to get iovar wl_android_natoe_subcmd_config_ips\n"));
2295 ret = -EINVAL;
2296 }
2297 } else { /* set */
2298 /* buflen is max tlv data we can write, it will be decremented as we
2299 * pack */
2300 /* save buflen at start */
2301 uint16 buflen_at_start = buflen;
2302
2303 bzero(&config_ips, sizeof(config_ips));
2304
2305 str = bcmstrtok(&pcmd, " ", NULL);
2306 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
2307 ANDROID_ERROR(("Invalid STA IP addr %s\n", str));
2308 ret = -EINVAL;
2309 goto exit;
2310 }
2311
2312 str = bcmstrtok(&pcmd, " ", NULL);
2313 if (!str ||
2314 !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
2315 ANDROID_ERROR(("Invalid STA netmask %s\n", str));
2316 ret = -EINVAL;
2317 goto exit;
2318 }
2319
2320 str = bcmstrtok(&pcmd, " ", NULL);
2321 if (!str ||
2322 !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
2323 ANDROID_ERROR(("Invalid STA router IP addr %s\n", str));
2324 ret = -EINVAL;
2325 goto exit;
2326 }
2327
2328 str = bcmstrtok(&pcmd, " ", NULL);
2329 if (!str ||
2330 !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
2331 ANDROID_ERROR(("Invalid STA DNS IP addr %s\n", str));
2332 ret = -EINVAL;
2333 goto exit;
2334 }
2335
2336 str = bcmstrtok(&pcmd, " ", NULL);
2337 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
2338 ANDROID_ERROR(("Invalid AP IP addr %s\n", str));
2339 ret = -EINVAL;
2340 goto exit;
2341 }
2342
2343 str = bcmstrtok(&pcmd, " ", NULL);
2344 if (!str ||
2345 !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
2346 ANDROID_ERROR(("Invalid AP netmask %s\n", str));
2347 ret = -EINVAL;
2348 goto exit;
2349 }
2350
2351 ret = bcm_pack_xtlv_entry((uint8 **)&pxtlv, &buflen,
2352 WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
2353 &config_ips, BCM_XTLV_OPTION_ALIGN32);
2354 if (ret != BCME_OK) {
2355 ret = -EINVAL;
2356 goto exit;
2357 }
2358
2359 /* adjust iocsz to the end of last data record */
2360 natoe_ioc->len = (buflen_at_start - buflen);
2361 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2362 ret = wldev_iovar_setbuf(dev, "natoe", natoe_ioc, iocsz, ioctl_buf,
2363 WLC_IOCTL_MEDLEN, NULL);
2364 if (ret != BCME_OK) {
2365 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2366 ret = -EINVAL;
2367 }
2368 }
2369
2370 exit:
2371 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2372 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
2373
2374 return ret;
2375 }
2376
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)2377 static int wl_android_natoe_subcmd_config_ports(struct net_device *dev,
2378 const wl_natoe_sub_cmd_t *cmd,
2379 char *command,
2380 wl_natoe_cmd_info_t *cmd_info)
2381 {
2382 int ret = BCME_OK;
2383 wl_natoe_ports_config_t ports_config;
2384 wl_natoe_ioc_t *natoe_ioc;
2385 char *pcmd = command;
2386 char *str;
2387 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
2388 uint16 buflen = WL_NATOE_IOC_BUFSZ;
2389 bcm_xtlv_t *pxtlv = NULL;
2390 char *ioctl_buf = NULL;
2391 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2392
2393 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
2394 if (!ioctl_buf) {
2395 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2396 return -ENOMEM;
2397 }
2398
2399 /* alloc mem for ioctl headr + tlv data */
2400 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
2401 if (!natoe_ioc) {
2402 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2403 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2404 return -ENOMEM;
2405 }
2406
2407 /* make up natoe cmd ioctl header */
2408 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2409 natoe_ioc->id = htod16(cmd->id);
2410 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
2411 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2412
2413 if (*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2414 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2415 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2416 WLC_IOCTL_MEDLEN, cmd_info);
2417 if (ret != BCME_OK) {
2418 ANDROID_ERROR(
2419 ("Fail to get iovar wl_android_natoe_subcmd_config_ports\n"));
2420 ret = -EINVAL;
2421 }
2422 } else { /* set */
2423 /* buflen is max tlv data we can write, it will be decremented as we
2424 * pack */
2425 /* save buflen at start */
2426 uint16 buflen_at_start = buflen;
2427
2428 bzero(&ports_config, sizeof(ports_config));
2429
2430 str = bcmstrtok(&pcmd, " ", NULL);
2431 if (!str) {
2432 ANDROID_ERROR(("Invalid port string %s\n", str));
2433 ret = -EINVAL;
2434 goto exit;
2435 }
2436 ports_config.start_port_num = htod16(bcm_atoi(str));
2437
2438 str = bcmstrtok(&pcmd, " ", NULL);
2439 if (!str) {
2440 ANDROID_ERROR(("Invalid port string %s\n", str));
2441 ret = -EINVAL;
2442 goto exit;
2443 }
2444 ports_config.no_of_ports = htod16(bcm_atoi(str));
2445
2446 if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
2447 NATOE_MAX_PORT_NUM) {
2448 ANDROID_ERROR(("Invalid port configuration\n"));
2449 ret = -EINVAL;
2450 goto exit;
2451 }
2452 ret = bcm_pack_xtlv_entry(
2453 (uint8 **)&pxtlv, &buflen, WL_NATOE_XTLV_CONFIG_PORTS,
2454 sizeof(ports_config), &ports_config, BCM_XTLV_OPTION_ALIGN32);
2455 if (ret != BCME_OK) {
2456 ret = -EINVAL;
2457 goto exit;
2458 }
2459
2460 /* adjust iocsz to the end of last data record */
2461 natoe_ioc->len = (buflen_at_start - buflen);
2462 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2463 ret = wldev_iovar_setbuf(dev, "natoe", natoe_ioc, iocsz, ioctl_buf,
2464 WLC_IOCTL_MEDLEN, NULL);
2465 if (ret != BCME_OK) {
2466 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2467 ret = -EINVAL;
2468 }
2469 }
2470
2471 exit:
2472 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2473 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
2474
2475 return ret;
2476 }
2477
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)2478 static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev,
2479 const wl_natoe_sub_cmd_t *cmd,
2480 char *command,
2481 wl_natoe_cmd_info_t *cmd_info)
2482 {
2483 int ret = BCME_OK;
2484 wl_natoe_ioc_t *natoe_ioc;
2485 char *pcmd = command;
2486 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2487 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
2488 uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
2489 bcm_xtlv_t *pxtlv = NULL;
2490 char *ioctl_buf = NULL;
2491 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2492
2493 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
2494 if (!ioctl_buf) {
2495 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2496 return -ENOMEM;
2497 }
2498
2499 /* alloc mem for ioctl headr + tlv data */
2500 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
2501 if (!natoe_ioc) {
2502 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2503 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
2504 return -ENOMEM;
2505 }
2506
2507 /* make up natoe cmd ioctl header */
2508 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2509 natoe_ioc->id = htod16(cmd->id);
2510 natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
2511 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2512
2513 if (*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2514 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2515 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2516 WLC_IOCTL_MAXLEN, cmd_info);
2517 if (ret != BCME_OK) {
2518 ANDROID_ERROR(
2519 ("Fail to get iovar wl_android_natoe_subcmd_dbg_stats\n"));
2520 ret = -EINVAL;
2521 }
2522 } else { /* set */
2523 uint8 val = bcm_atoi(pcmd);
2524
2525 /* buflen is max tlv data we can write, it will be decremented as we
2526 * pack */
2527 /* save buflen at start */
2528 uint16 buflen_at_start = buflen;
2529
2530 /* we'll adjust final ioc size at the end */
2531 ret =
2532 bcm_pack_xtlv_entry((uint8 **)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
2533 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
2534 if (ret != BCME_OK) {
2535 ret = -EINVAL;
2536 goto exit;
2537 }
2538
2539 /* adjust iocsz to the end of last data record */
2540 natoe_ioc->len = (buflen_at_start - buflen);
2541 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2542 ret = wldev_iovar_setbuf(dev, "natoe", natoe_ioc, iocsz, ioctl_buf,
2543 WLC_IOCTL_MAXLEN, NULL);
2544 if (ret != BCME_OK) {
2545 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2546 ret = -EINVAL;
2547 }
2548 }
2549
2550 exit:
2551 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
2552 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
2553
2554 return ret;
2555 }
2556
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)2557 static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
2558 const wl_natoe_sub_cmd_t *cmd,
2559 char *command,
2560 wl_natoe_cmd_info_t *cmd_info)
2561 {
2562 int ret = BCME_OK;
2563 wl_natoe_ioc_t *natoe_ioc;
2564 char *pcmd = command;
2565 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2566 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
2567 uint16 buflen = WL_NATOE_IOC_BUFSZ;
2568 bcm_xtlv_t *pxtlv = NULL;
2569 char *ioctl_buf = NULL;
2570 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2571
2572 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
2573 if (!ioctl_buf) {
2574 ANDROID_ERROR(("ioctl memory alloc failed\n"));
2575 return -ENOMEM;
2576 }
2577
2578 /* alloc mem for ioctl headr + tlv data */
2579 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
2580 if (!natoe_ioc) {
2581 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
2582 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2583 return -ENOMEM;
2584 }
2585
2586 /* make up natoe cmd ioctl header */
2587 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
2588 natoe_ioc->id = htod16(cmd->id);
2589 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
2590 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
2591
2592 if (*pcmd == WL_IOCTL_ACTION_GET) { /* get */
2593 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
2594 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
2595 WLC_IOCTL_MEDLEN, cmd_info);
2596 if (ret != BCME_OK) {
2597 ANDROID_ERROR(
2598 ("Fail to get iovar wl_android_natoe_subcmd_tbl_cnt\n"));
2599 ret = -EINVAL;
2600 }
2601 } else { /* set */
2602 uint32 val = bcm_atoi(pcmd);
2603
2604 /* buflen is max tlv data we can write, it will be decremented as we
2605 * pack */
2606 /* save buflen at start */
2607 uint16 buflen_at_start = buflen;
2608
2609 /* we'll adjust final ioc size at the end */
2610 ret = bcm_pack_xtlv_entry((uint8 **)&pxtlv, &buflen,
2611 WL_NATOE_XTLV_TBL_CNT, sizeof(uint32), &val,
2612 BCM_XTLV_OPTION_ALIGN32);
2613 if (ret != BCME_OK) {
2614 ret = -EINVAL;
2615 goto exit;
2616 }
2617 /* adjust iocsz to the end of last data record */
2618 natoe_ioc->len = (buflen_at_start - buflen);
2619 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
2620 ret = wldev_iovar_setbuf(dev, "natoe", natoe_ioc, iocsz, ioctl_buf,
2621 WLC_IOCTL_MEDLEN, NULL);
2622 if (ret != BCME_OK) {
2623 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2624 ret = -EINVAL;
2625 }
2626 }
2627
2628 exit:
2629 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2630 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
2631
2632 return ret;
2633 }
2634
2635 #endif /* WL_NATOE */
2636
2637 #ifdef WL_MBO
wl_android_process_mbo_cmd(struct net_device * dev,char * command,int total_len)2638 static int wl_android_process_mbo_cmd(struct net_device *dev, char *command,
2639 int total_len)
2640 {
2641 int ret = BCME_ERROR;
2642 char *pcmd = command;
2643 char *str = NULL;
2644 wl_drv_cmd_info_t cmd_info;
2645 const wl_drv_sub_cmd_t *mbo_cmd = &mbo_cmd_list[0];
2646
2647 /* skip to cmd name after "mbo" */
2648 str = bcmstrtok(&pcmd, " ", NULL);
2649
2650 /* If mbo subcmd name is not provided, return error */
2651 if (*pcmd == '\0') {
2652 ANDROID_ERROR(("mbo subcmd not provided %s\n", __FUNCTION__));
2653 ret = -EINVAL;
2654 return ret;
2655 }
2656
2657 /* get the mbo command name to str */
2658 str = bcmstrtok(&pcmd, " ", NULL);
2659
2660 while (mbo_cmd->name != NULL) {
2661 if (strnicmp(mbo_cmd->name, str, strlen(mbo_cmd->name)) == 0) {
2662 /* dispatch cmd to appropriate handler */
2663 if (mbo_cmd->handler) {
2664 cmd_info.command = command;
2665 cmd_info.tot_len = total_len;
2666 ret = mbo_cmd->handler(dev, mbo_cmd, pcmd, &cmd_info);
2667 }
2668 return ret;
2669 }
2670 mbo_cmd++;
2671 }
2672 return ret;
2673 }
2674
wl_android_send_wnm_notif(struct net_device * dev,bcm_iov_buf_t * iov_buf,uint16 iov_buf_len,uint8 * iov_resp,uint16 iov_resp_len,uint8 sub_elem_type)2675 static int wl_android_send_wnm_notif(struct net_device *dev,
2676 bcm_iov_buf_t *iov_buf, uint16 iov_buf_len,
2677 uint8 *iov_resp, uint16 iov_resp_len,
2678 uint8 sub_elem_type)
2679 {
2680 int ret = BCME_OK;
2681 uint8 *pxtlv = NULL;
2682 uint16 iovlen = 0;
2683 uint16 buflen = 0, buflen_start = 0;
2684
2685 memset_s(iov_buf, iov_buf_len, 0, iov_buf_len);
2686 iov_buf->version = WL_MBO_IOV_VERSION;
2687 iov_buf->id = WL_MBO_CMD_SEND_NOTIF;
2688 buflen = buflen_start = iov_buf_len - sizeof(bcm_iov_buf_t);
2689 pxtlv = (uint8 *)&iov_buf->data[0];
2690 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_SUB_ELEM_TYPE,
2691 sizeof(sub_elem_type), &sub_elem_type,
2692 BCM_XTLV_OPTION_ALIGN32);
2693 if (ret != BCME_OK) {
2694 return ret;
2695 }
2696 iov_buf->len = buflen_start - buflen;
2697 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
2698 ret = wldev_iovar_setbuf(dev, "mbo", iov_buf, iovlen, iov_resp,
2699 WLC_IOCTL_MAXLEN, NULL);
2700 if (ret != BCME_OK) {
2701 ANDROID_ERROR(("Fail to sent wnm notif %d\n", ret));
2702 }
2703 return ret;
2704 }
2705
wl_android_mbo_resp_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)2706 static int wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data,
2707 uint16 type, uint16 len)
2708 {
2709 wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
2710 uint8 *command = cmd_info->command;
2711 uint16 total_len = cmd_info->tot_len;
2712 uint16 bytes_written = 0;
2713
2714 UNUSED_PARAMETER(len);
2715 /* validate data value */
2716 if (data == NULL) {
2717 ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
2718 return -EINVAL;
2719 }
2720 switch (type) {
2721 case WL_MBO_XTLV_CELL_DATA_CAP: {
2722 bytes_written =
2723 snprintf(command, total_len, "cell_data_cap: %u\n", *data);
2724 cmd_info->bytes_written = bytes_written;
2725 break;
2726 }
2727 default:
2728 ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
2729 }
2730 return BCME_OK;
2731 }
2732
wl_android_mbo_subcmd_cell_data_cap(struct net_device * dev,const wl_drv_sub_cmd_t * cmd,char * command,wl_drv_cmd_info_t * cmd_info)2733 static int wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev,
2734 const wl_drv_sub_cmd_t *cmd,
2735 char *command,
2736 wl_drv_cmd_info_t *cmd_info)
2737 {
2738 int ret = BCME_OK;
2739 uint8 *pxtlv = NULL;
2740 uint16 buflen = 0, buflen_start = 0;
2741 uint16 iovlen = 0;
2742 char *pcmd = command;
2743 bcm_iov_buf_t *iov_buf = NULL;
2744 bcm_iov_buf_t *p_resp = NULL;
2745 uint8 *iov_resp = NULL;
2746 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2747 uint16 version;
2748
2749 /* first get the configured value */
2750 iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
2751 if (iov_buf == NULL) {
2752 ret = -ENOMEM;
2753 ANDROID_ERROR(("iov buf memory alloc exited\n"));
2754 goto exit;
2755 }
2756 iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
2757 if (iov_resp == NULL) {
2758 ret = -ENOMEM;
2759 ANDROID_ERROR(("iov resp memory alloc exited\n"));
2760 goto exit;
2761 }
2762
2763 /* fill header */
2764 iov_buf->version = WL_MBO_IOV_VERSION;
2765 iov_buf->id = WL_MBO_CMD_CELLULAR_DATA_CAP;
2766
2767 ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
2768 WLC_IOCTL_MAXLEN, NULL);
2769 if (ret != BCME_OK) {
2770 goto exit;
2771 }
2772 p_resp = (bcm_iov_buf_t *)iov_resp;
2773
2774 /* get */
2775 if (*pcmd == WL_IOCTL_ACTION_GET) {
2776 /* Check for version */
2777 version = dtoh16(*(uint16 *)iov_resp);
2778 if (version != WL_MBO_IOV_VERSION) {
2779 ret = -EINVAL;
2780 }
2781 if (p_resp->id == WL_MBO_CMD_CELLULAR_DATA_CAP) {
2782 ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
2783 p_resp->len, BCM_XTLV_OPTION_ALIGN32,
2784 wl_android_mbo_resp_parse_cbfn);
2785 if (ret == BCME_OK) {
2786 ret = cmd_info->bytes_written;
2787 }
2788 } else {
2789 ret = -EINVAL;
2790 ANDROID_ERROR(
2791 ("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
2792 goto exit;
2793 }
2794 } else {
2795 uint8 cell_cap = bcm_atoi(pcmd);
2796 const uint8 *old_cell_cap = NULL;
2797 uint16 len = 0;
2798
2799 old_cell_cap = bcm_get_data_from_xtlv_buf(
2800 (uint8 *)p_resp->data, p_resp->len, WL_MBO_XTLV_CELL_DATA_CAP, &len,
2801 BCM_XTLV_OPTION_ALIGN32);
2802 if (old_cell_cap && *old_cell_cap == cell_cap) {
2803 ANDROID_ERROR(("No change is cellular data capability\n"));
2804 /* No change in value */
2805 goto exit;
2806 }
2807
2808 buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
2809
2810 if (cell_cap < MBO_CELL_DATA_CONN_AVAILABLE ||
2811 cell_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) {
2812 ANDROID_ERROR(("wrong value %u\n", cell_cap));
2813 ret = -EINVAL;
2814 goto exit;
2815 }
2816 pxtlv = (uint8 *)&iov_buf->data[0];
2817 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CELL_DATA_CAP,
2818 sizeof(cell_cap), &cell_cap,
2819 BCM_XTLV_OPTION_ALIGN32);
2820 if (ret != BCME_OK) {
2821 goto exit;
2822 }
2823 iov_buf->len = buflen_start - buflen;
2824 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
2825 ret = wldev_iovar_setbuf(dev, "mbo", iov_buf, iovlen, iov_resp,
2826 WLC_IOCTL_MAXLEN, NULL);
2827 if (ret != BCME_OK) {
2828 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2829 ret = -EINVAL;
2830 goto exit;
2831 }
2832 /* Skip for CUSTOMER_HW4 - WNM notification
2833 * for cellular data capability is handled by host
2834 */
2835 /* send a WNM notification request to associated AP */
2836 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
2837 ANDROID_INFO(("Sending WNM Notif\n"));
2838 ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
2839 iov_resp, WLC_IOCTL_MAXLEN,
2840 MBO_ATTR_CELL_DATA_CAP);
2841 if (ret != BCME_OK) {
2842 ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
2843 ret = -EINVAL;
2844 }
2845 }
2846 }
2847 exit:
2848 if (iov_buf) {
2849 MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
2850 }
2851 if (iov_resp) {
2852 MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
2853 }
2854 return ret;
2855 }
2856
wl_android_mbo_non_pref_chan_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)2857 static int wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data,
2858 uint16 type, uint16 len)
2859 {
2860 wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
2861 uint8 *command = cmd_info->command + cmd_info->bytes_written;
2862 uint16 total_len = cmd_info->tot_len;
2863 uint16 bytes_written = 0;
2864
2865 ANDROID_INFO(
2866 ("Total bytes written at begining %u\n", cmd_info->bytes_written));
2867 UNUSED_PARAMETER(len);
2868 if (data == NULL) {
2869 ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
2870 return -EINVAL;
2871 }
2872 switch (type) {
2873 case WL_MBO_XTLV_OPCLASS: {
2874 bytes_written = snprintf(command, total_len, "%u:", *data);
2875 ANDROID_ERROR(("wr %u %u\n", bytes_written, *data));
2876 command += bytes_written;
2877 cmd_info->bytes_written += bytes_written;
2878 break;
2879 }
2880 case WL_MBO_XTLV_CHAN: {
2881 bytes_written = snprintf(command, total_len, "%u:", *data);
2882 ANDROID_ERROR(("wr %u\n", bytes_written));
2883 command += bytes_written;
2884 cmd_info->bytes_written += bytes_written;
2885 break;
2886 }
2887 case WL_MBO_XTLV_PREFERENCE: {
2888 bytes_written = snprintf(command, total_len, "%u:", *data);
2889 ANDROID_ERROR(("wr %u\n", bytes_written));
2890 command += bytes_written;
2891 cmd_info->bytes_written += bytes_written;
2892 break;
2893 }
2894 case WL_MBO_XTLV_REASON_CODE: {
2895 bytes_written = snprintf(command, total_len, "%u ", *data);
2896 ANDROID_ERROR(("wr %u\n", bytes_written));
2897 command += bytes_written;
2898 cmd_info->bytes_written += bytes_written;
2899 break;
2900 }
2901 default:
2902 ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
2903 }
2904 ANDROID_INFO(("Total bytes written %u\n", cmd_info->bytes_written));
2905 return BCME_OK;
2906 }
2907
wl_android_mbo_subcmd_non_pref_chan(struct net_device * dev,const wl_drv_sub_cmd_t * cmd,char * command,wl_drv_cmd_info_t * cmd_info)2908 static int wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
2909 const wl_drv_sub_cmd_t *cmd,
2910 char *command,
2911 wl_drv_cmd_info_t *cmd_info)
2912 {
2913 int ret = BCME_OK;
2914 uint8 *pxtlv = NULL;
2915 uint16 buflen = 0, buflen_start = 0;
2916 uint16 iovlen = 0;
2917 char *pcmd = command;
2918 bcm_iov_buf_t *iov_buf = NULL;
2919 bcm_iov_buf_t *p_resp = NULL;
2920 uint8 *iov_resp = NULL;
2921 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2922 uint16 version;
2923
2924 ANDROID_ERROR(("%s:%d\n", __FUNCTION__, __LINE__));
2925 iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
2926 if (iov_buf == NULL) {
2927 ret = -ENOMEM;
2928 ANDROID_ERROR(("iov buf memory alloc exited\n"));
2929 goto exit;
2930 }
2931 iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
2932 if (iov_resp == NULL) {
2933 ret = -ENOMEM;
2934 ANDROID_ERROR(("iov resp memory alloc exited\n"));
2935 goto exit;
2936 }
2937 /* get */
2938 if (*pcmd == WL_IOCTL_ACTION_GET) {
2939 /* fill header */
2940 iov_buf->version = WL_MBO_IOV_VERSION;
2941 iov_buf->id = WL_MBO_CMD_LIST_CHAN_PREF;
2942
2943 ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN,
2944 iov_resp, WLC_IOCTL_MAXLEN, NULL);
2945 if (ret != BCME_OK) {
2946 goto exit;
2947 }
2948 p_resp = (bcm_iov_buf_t *)iov_resp;
2949 /* Check for version */
2950 version = dtoh16(*(uint16 *)iov_resp);
2951 if (version != WL_MBO_IOV_VERSION) {
2952 ANDROID_ERROR(("Version mismatch. returned ver %u expected %u\n",
2953 version, WL_MBO_IOV_VERSION));
2954 ret = -EINVAL;
2955 }
2956 if (p_resp->id == WL_MBO_CMD_LIST_CHAN_PREF) {
2957 ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
2958 p_resp->len, BCM_XTLV_OPTION_ALIGN32,
2959 wl_android_mbo_non_pref_chan_parse_cbfn);
2960 if (ret == BCME_OK) {
2961 ret = cmd_info->bytes_written;
2962 }
2963 } else {
2964 ret = -EINVAL;
2965 ANDROID_ERROR(
2966 ("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
2967 goto exit;
2968 }
2969 } else {
2970 char *str = pcmd;
2971 uint opcl = 0, ch = 0, pref = 0, rc = 0;
2972
2973 str = bcmstrtok(&pcmd, " ", NULL);
2974 if (!(strnicmp(str, "set", 0x3)) || (!strnicmp(str, "clear", 0x5))) {
2975 /* delete all configurations */
2976 iov_buf->version = WL_MBO_IOV_VERSION;
2977 iov_buf->id = WL_MBO_CMD_DEL_CHAN_PREF;
2978 iov_buf->len = 0;
2979 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
2980 ret = wldev_iovar_setbuf(dev, "mbo", iov_buf, iovlen, iov_resp,
2981 WLC_IOCTL_MAXLEN, NULL);
2982 if (ret != BCME_OK) {
2983 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
2984 ret = -EINVAL;
2985 goto exit;
2986 }
2987 } else {
2988 ANDROID_ERROR(("Unknown command %s\n", str));
2989 goto exit;
2990 }
2991 /* parse non pref channel list */
2992 if (strnicmp(str, "set", 0x3) == 0) {
2993 uint8 cnt = 0;
2994 str = bcmstrtok(&pcmd, " ", NULL);
2995 while (str != NULL) {
2996 ret = sscanf(str, "%u:%u:%u:%u", &opcl, &ch, &pref, &rc);
2997 ANDROID_ERROR(("buflen %u op %u, ch %u, pref %u rc %u\n",
2998 buflen, opcl, ch, pref, rc));
2999 if (ret != 0x4) {
3000 ANDROID_ERROR(("Not all parameter presents\n"));
3001 ret = -EINVAL;
3002 }
3003 /* add a validation check here */
3004 memset_s(iov_buf, WLC_IOCTL_MEDLEN, 0, WLC_IOCTL_MEDLEN);
3005 buflen = buflen_start = WLC_IOCTL_MEDLEN;
3006 pxtlv = (uint8 *)&iov_buf->data[0];
3007 /* opclass */
3008 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
3009 sizeof(uint8), (uint8 *)&opcl,
3010 BCM_XTLV_OPTION_ALIGN32);
3011 if (ret != BCME_OK) {
3012 goto exit;
3013 }
3014 /* channel */
3015 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
3016 sizeof(uint8), (uint8 *)&ch,
3017 BCM_XTLV_OPTION_ALIGN32);
3018 if (ret != BCME_OK) {
3019 goto exit;
3020 }
3021 /* preference */
3022 ret = bcm_pack_xtlv_entry(
3023 &pxtlv, &buflen, WL_MBO_XTLV_PREFERENCE, sizeof(uint8),
3024 (uint8 *)&pref, BCM_XTLV_OPTION_ALIGN32);
3025 if (ret != BCME_OK) {
3026 goto exit;
3027 }
3028 /* reason */
3029 ret = bcm_pack_xtlv_entry(
3030 &pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE, sizeof(uint8),
3031 (uint8 *)&rc, BCM_XTLV_OPTION_ALIGN32);
3032 if (ret != BCME_OK) {
3033 goto exit;
3034 }
3035 ANDROID_ERROR(("len %u\n", (buflen_start - buflen)));
3036 /* Now set the new non pref channels */
3037 iov_buf->version = WL_MBO_IOV_VERSION;
3038 iov_buf->id = WL_MBO_CMD_ADD_CHAN_PREF;
3039 iov_buf->len = buflen_start - buflen;
3040 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
3041 ret = wldev_iovar_setbuf(dev, "mbo", iov_buf, iovlen, iov_resp,
3042 WLC_IOCTL_MEDLEN, NULL);
3043 if (ret != BCME_OK) {
3044 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
3045 ret = -EINVAL;
3046 goto exit;
3047 }
3048 cnt++;
3049 if (cnt >= MBO_MAX_CHAN_PREF_ENTRIES) {
3050 break;
3051 }
3052 ANDROID_ERROR(("%d cnt %u\n", __LINE__, cnt));
3053 str = bcmstrtok(&pcmd, " ", NULL);
3054 }
3055 }
3056 /* send a WNM notification request to associated AP */
3057 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
3058 ANDROID_INFO(("Sending WNM Notif\n"));
3059 ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
3060 iov_resp, WLC_IOCTL_MAXLEN,
3061 MBO_ATTR_NON_PREF_CHAN_REPORT);
3062 if (ret != BCME_OK) {
3063 ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
3064 ret = -EINVAL;
3065 }
3066 }
3067 }
3068 exit:
3069 if (iov_buf) {
3070 MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
3071 }
3072 if (iov_resp) {
3073 MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
3074 }
3075 return ret;
3076 }
3077 #endif /* WL_MBO */
3078
3079 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
3080 extern int wl_cfg80211_send_msg_to_ril(void);
3081 extern void wl_cfg80211_register_dev_ril_bridge_event_notifier(void);
3082 extern void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void);
3083 extern int g_mhs_chan_for_cpcoex;
3084 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
3085
3086 #if defined(WL_SUPPORT_AUTO_CHANNEL)
3087 /* SoftAP feature */
3088 #define APCS_BAND_2G_LEGACY1 20
3089 #define APCS_BAND_2G_LEGACY2 0
3090 #define APCS_BAND_AUTO "band=auto"
3091 #define APCS_BAND_2G "band=2g"
3092 #define APCS_BAND_5G "band=5g"
3093 #define APCS_MAX_2G_CHANNELS 11
3094 #define APCS_MAX_RETRY 10
3095 #define APCS_DEFAULT_2G_CH 1
3096 #define APCS_DEFAULT_5G_CH 149
3097
wl_android_set_auto_channel(struct net_device * dev,const char * cmd_str,char * command,int total_len)3098 static int wl_android_set_auto_channel(struct net_device *dev,
3099 const char *cmd_str, char *command,
3100 int total_len)
3101 {
3102 int channel = 0;
3103 int chosen = 0;
3104 int retry = 0;
3105 int ret = 0;
3106 int spect = 0;
3107 u8 *reqbuf = NULL;
3108 uint32 band = WLC_BAND_2G, sta_band = WLC_BAND_2G;
3109 uint32 buf_size;
3110 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3111
3112 if (cmd_str) {
3113 ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
3114 if (strnicmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
3115 band = WLC_BAND_AUTO;
3116 } else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
3117 band = WLC_BAND_5G;
3118 } else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
3119 band = WLC_BAND_2G;
3120 } else {
3121 /*
3122 * For backward compatibility: Some platforms used to issue argument
3123 * 20 or 0 to enforce the 2G channel selection
3124 */
3125 channel = bcm_atoi(cmd_str);
3126 if ((channel == APCS_BAND_2G_LEGACY1) ||
3127 (channel == APCS_BAND_2G_LEGACY2)) {
3128 band = WLC_BAND_2G;
3129 } else {
3130 ANDROID_ERROR(("Invalid argument\n"));
3131 return -EINVAL;
3132 }
3133 }
3134 } else {
3135 /* If no argument is provided, default to 2G */
3136 ANDROID_ERROR(("No argument given default to 2.4G scan\n"));
3137 band = WLC_BAND_2G;
3138 }
3139 ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
3140
3141 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
3142 wl_cfg80211_register_dev_ril_bridge_event_notifier();
3143 if (band == WLC_BAND_2G) {
3144 wl_cfg80211_send_msg_to_ril();
3145
3146 if (g_mhs_chan_for_cpcoex) {
3147 channel = g_mhs_chan_for_cpcoex;
3148 g_mhs_chan_for_cpcoex = 0;
3149 goto done2;
3150 }
3151 }
3152 wl_cfg80211_unregister_dev_ril_bridge_event_notifier();
3153 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
3154
3155 /* If STA is connected, return is STA channel, else ACS can be issued,
3156 * set spect to 0 and proceed with ACS
3157 */
3158 channel = wl_cfg80211_get_sta_channel(cfg);
3159 if (channel) {
3160 sta_band = WL_GET_BAND(channel);
3161 switch (sta_band) {
3162 case (WL_CHANSPEC_BAND_5G): {
3163 if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) {
3164 channel = APCS_DEFAULT_2G_CH;
3165 }
3166 break;
3167 }
3168 case (WL_CHANSPEC_BAND_2G): {
3169 if (band == WLC_BAND_5G) {
3170 channel = APCS_DEFAULT_5G_CH;
3171 }
3172 break;
3173 }
3174 default:
3175 /* Intentional fall through to use same sta channel for softap
3176 */
3177 break;
3178 }
3179 WL_MSG(dev->name, "band=%d, sta_band=%d, channel=%d\n", band, sta_band,
3180 channel);
3181 goto done2;
3182 }
3183
3184 channel = wl_ext_autochannel(dev, ACS_FW_BIT | ACS_DRV_BIT, band);
3185 if (channel) {
3186 goto done2;
3187 } else {
3188 goto done;
3189 }
3190
3191 ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
3192 if (ret) {
3193 ANDROID_ERROR(("ACS: error getting the spect, ret=%d\n", ret));
3194 goto done;
3195 }
3196
3197 if (spect > 0) {
3198 ret = wl_cfg80211_set_spect(dev, 0);
3199 if (ret < 0) {
3200 ANDROID_ERROR(("ACS: error while setting spect, ret=%d\n", ret));
3201 goto done;
3202 }
3203 }
3204
3205 reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
3206 if (reqbuf == NULL) {
3207 ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
3208 return -ENOMEM;
3209 }
3210
3211 if (band == WLC_BAND_AUTO) {
3212 ANDROID_INFO(("ACS full channel scan \n"));
3213 reqbuf[0] = htod32(0);
3214 } else if (band == WLC_BAND_5G) {
3215 ANDROID_INFO(("ACS 5G band scan \n"));
3216 if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf,
3217 CHANSPEC_BUF_SIZE)) < 0) {
3218 ANDROID_ERROR(("ACS 5g chanspec retreival failed! \n"));
3219 goto done;
3220 }
3221 } else if (band == WLC_BAND_2G) {
3222 /*
3223 * If channel argument is not provided/ argument 20 is provided,
3224 * Restrict channel to 2GHz, 20MHz BW, No SB
3225 */
3226 ANDROID_INFO(("ACS 2G band scan \n"));
3227 if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf,
3228 CHANSPEC_BUF_SIZE)) < 0) {
3229 ANDROID_ERROR(("ACS 2g chanspec retreival failed! \n"));
3230 goto done;
3231 }
3232 } else {
3233 ANDROID_ERROR(("ACS: No band chosen\n"));
3234 goto done2;
3235 }
3236
3237 buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
3238 ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf, buf_size);
3239 if (ret < 0) {
3240 ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret));
3241 channel = 0;
3242 goto done;
3243 }
3244
3245 /* Wait for auto channel selection, max 3000 ms */
3246 if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) {
3247 OSL_SLEEP(0x1F4);
3248 } else {
3249 /*
3250 * Full channel scan at the minimum takes 1.2secs
3251 * even with parallel scan. max wait time: 3500ms
3252 */
3253 OSL_SLEEP(0x3E8);
3254 }
3255
3256 retry = APCS_MAX_RETRY;
3257 while (retry--) {
3258 ret =
3259 wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
3260 if (ret < 0) {
3261 chosen = 0;
3262 } else {
3263 chosen = dtoh32(chosen);
3264 }
3265
3266 if (chosen) {
3267 int chosen_band;
3268 int apcs_band;
3269 #ifdef D11AC_IOTYPES
3270 if (wl_cfg80211_get_ioctl_version() == 1) {
3271 channel = LCHSPEC_CHANNEL((chanspec_t)chosen);
3272 } else {
3273 channel = CHSPEC_CHANNEL((chanspec_t)chosen);
3274 }
3275 #else
3276 channel = CHSPEC_CHANNEL((chanspec_t)chosen);
3277 #endif /* D11AC_IOTYPES */
3278 apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band;
3279 chosen_band =
3280 (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G;
3281 if (apcs_band == chosen_band) {
3282 WL_MSG(dev->name, "selected channel = %d\n", channel);
3283 break;
3284 }
3285 }
3286 ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x\n",
3287 (APCS_MAX_RETRY - retry), ret, chosen));
3288 OSL_SLEEP(0xFA);
3289 }
3290
3291 done:
3292 if ((retry == 0) || (ret < 0)) {
3293 /* On failure, fallback to a default channel */
3294 if (band == WLC_BAND_5G) {
3295 channel = APCS_DEFAULT_5G_CH;
3296 } else {
3297 channel = APCS_DEFAULT_2G_CH;
3298 }
3299 ANDROID_ERROR(
3300 ("ACS failed. Fall back to default channel (%d) \n", channel));
3301 }
3302 done2:
3303 if (spect > 0) {
3304 if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) {
3305 ANDROID_ERROR(("ACS: error while setting spect\n"));
3306 }
3307 }
3308
3309 if (reqbuf) {
3310 MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
3311 }
3312
3313 if (channel) {
3314 ret = snprintf(command, total_len, "%d", channel);
3315 ANDROID_INFO(("command result is %s \n", command));
3316 }
3317
3318 return ret;
3319 }
3320 #endif /* WL_SUPPORT_AUTO_CHANNEL */
3321
wl_android_set_roam_mode(struct net_device * dev,char * command)3322 int wl_android_set_roam_mode(struct net_device *dev, char *command)
3323 {
3324 int error = 0;
3325 int mode = 0;
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 error = wldev_iovar_setint(dev, "roam_off", mode);
3333 if (error) {
3334 ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
3335 __FUNCTION__, mode, error));
3336 return -1;
3337 } else {
3338 ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
3339 __FUNCTION__, mode, error));
3340 }
3341 return 0;
3342 }
3343
3344 #ifdef WL_CFG80211
wl_android_set_ibss_beacon_ouidata(struct net_device * dev,char * command,int total_len)3345 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command,
3346 int total_len)
3347 {
3348 char ie_buf[VNDR_IE_MAX_LEN];
3349 char *ioctl_buf = NULL;
3350 char hex[] = "XX";
3351 char *pcmd = NULL;
3352 int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
3353 vndr_ie_setbuf_t *vndr_ie = NULL;
3354 s32 iecount;
3355 uint32 pktflag;
3356 s32 err = BCME_OK, bssidx;
3357 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3358
3359 /* Check the VSIE (Vendor Specific IE) which was added.
3360 * If exist then send IOVAR to delete it
3361 */
3362 if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
3363 return -EINVAL;
3364 }
3365
3366 if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
3367 ANDROID_ERROR(("error. total_len:%d\n", total_len));
3368 return -EINVAL;
3369 }
3370
3371 pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
3372 for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
3373 if (*pcmd == '\0') {
3374 ANDROID_ERROR(("error while parsing OUI.\n"));
3375 return -EINVAL;
3376 }
3377 hex[0] = *pcmd++;
3378 hex[1] = *pcmd++;
3379 ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 0x10);
3380 }
3381 pcmd++;
3382 while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
3383 hex[0] = *pcmd++;
3384 hex[1] = *pcmd++;
3385 ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 0x10);
3386 datalen++;
3387 }
3388
3389 if (datalen <= 0) {
3390 ANDROID_ERROR(("error. vndr ie len:%d\n", datalen));
3391 return -EINVAL;
3392 }
3393
3394 tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
3395 vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
3396 if (!vndr_ie) {
3397 ANDROID_ERROR(("IE memory alloc failed\n"));
3398 return -ENOMEM;
3399 }
3400 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
3401 strlcpy(vndr_ie->cmd, "add", sizeof(vndr_ie->cmd));
3402
3403 /* Set the IE count - the buffer contains only 1 IE */
3404 iecount = htod32(1);
3405 memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
3406
3407 /* Set packet flag to indicate that BEACON's will contain this IE */
3408 pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
3409 memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
3410 sizeof(u32));
3411 /* Set the IE ID */
3412 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id =
3413 (uchar)DOT11_MNG_PROPR_ID;
3414
3415 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
3416 DOT11_OUI_LEN);
3417 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
3418 &ie_buf[DOT11_OUI_LEN], datalen);
3419
3420 ielen = DOT11_OUI_LEN + datalen;
3421 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar)ielen;
3422
3423 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
3424 if (!ioctl_buf) {
3425 ANDROID_ERROR(("ioctl memory alloc failed\n"));
3426 if (vndr_ie) {
3427 MFREE(cfg->osh, vndr_ie, tot_len);
3428 }
3429 return -ENOMEM;
3430 }
3431 bzero(ioctl_buf, WLC_IOCTL_MEDLEN); /* init the buffer */
3432 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3433 ANDROID_ERROR(("Find index failed\n"));
3434 err = BCME_ERROR;
3435 goto end;
3436 }
3437 err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
3438 WLC_IOCTL_MEDLEN, bssidx,
3439 &cfg->ioctl_buf_sync);
3440 end:
3441 if (err != BCME_OK) {
3442 err = -EINVAL;
3443 if (vndr_ie) {
3444 MFREE(cfg->osh, vndr_ie, tot_len);
3445 }
3446 } else {
3447 /* do NOT free 'vndr_ie' for the next process */
3448 wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
3449 }
3450
3451 if (ioctl_buf) {
3452 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3453 }
3454
3455 return err;
3456 }
3457 #endif /* WL_CFG80211 */
3458
3459 #if defined(BCMFW_ROAM_ENABLE)
wl_android_set_roampref(struct net_device * dev,char * command,int total_len)3460 static int wl_android_set_roampref(struct net_device *dev, char *command,
3461 int total_len)
3462 {
3463 int error = 0;
3464 char smbuf[WLC_IOCTL_SMLEN];
3465 uint8 buf[MAX_BUF_SIZE];
3466 uint8 *pref = buf;
3467 char *pcmd;
3468 int num_ucipher_suites = 0;
3469 int num_akm_suites = 0;
3470 wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
3471 wpa_suite_t akm_suites[MAX_NUM_SUITES];
3472 int num_tuples = 0;
3473 int total_bytes = 0;
3474 int total_len_left;
3475 int i, j;
3476 char hex[] = "XX";
3477
3478 pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
3479 total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
3480
3481 num_akm_suites = simple_strtoul(pcmd, NULL, 0x10);
3482 if (num_akm_suites > MAX_NUM_SUITES) {
3483 ANDROID_ERROR(("too many AKM suites = %d\n", num_akm_suites));
3484 return -1;
3485 }
3486
3487 /* Increment for number of AKM suites field + space */
3488 pcmd += 0x3;
3489 total_len_left -= 0x3;
3490
3491 /* check to make sure pcmd does not overrun */
3492 if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE)) {
3493 return -1;
3494 }
3495
3496 bzero(buf, sizeof(buf));
3497 bzero(akm_suites, sizeof(akm_suites));
3498 bzero(ucipher_suites, sizeof(ucipher_suites));
3499
3500 /* Save the AKM suites passed in the command */
3501 for (i = 0; i < num_akm_suites; i++) {
3502 /* Store the MSB first, as required by join_pref */
3503 for (j = 0; j < 0x4; j++) {
3504 hex[0] = *pcmd++;
3505 hex[1] = *pcmd++;
3506 buf[j] = (uint8)simple_strtoul(hex, NULL, 0x10);
3507 }
3508 memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
3509 }
3510
3511 total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
3512 num_ucipher_suites = simple_strtoul(pcmd, NULL, 0x10);
3513 /* Increment for number of cipher suites field + space */
3514 pcmd += 0x3;
3515 total_len_left -= 0x3;
3516
3517 if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE)) {
3518 return -1;
3519 }
3520
3521 /* Save the cipher suites passed in the command */
3522 for (i = 0; i < num_ucipher_suites; i++) {
3523 /* Store the MSB first, as required by join_pref */
3524 for (j = 0; j < 0x4; j++) {
3525 hex[0] = *pcmd++;
3526 hex[1] = *pcmd++;
3527 buf[j] = (uint8)simple_strtoul(hex, NULL, 0x10);
3528 }
3529 memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
3530 }
3531
3532 /* Join preference for RSSI
3533 * Type : 1 byte (0x01)
3534 * Length : 1 byte (0x02)
3535 * Value : 2 bytes (reserved)
3536 */
3537 *pref++ = WL_JOIN_PREF_RSSI;
3538 *pref++ = JOIN_PREF_RSSI_LEN;
3539 *pref++ = 0;
3540 *pref++ = 0;
3541
3542 /* Join preference for WPA
3543 * Type : 1 byte (0x02)
3544 * Length : 1 byte (not used)
3545 * Value : (variable length)
3546 * reserved: 1 byte
3547 * count : 1 byte (no of tuples)
3548 * Tuple1 : 12 bytes
3549 * akm[4]
3550 * ucipher[4]
3551 * mcipher[4]
3552 * Tuple2 : 12 bytes
3553 * Tuplen : 12 bytes
3554 */
3555 num_tuples = num_akm_suites * num_ucipher_suites;
3556 if (num_tuples != 0) {
3557 if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
3558 *pref++ = WL_JOIN_PREF_WPA;
3559 *pref++ = 0;
3560 *pref++ = 0;
3561 *pref++ = (uint8)num_tuples;
3562 total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
3563 (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
3564 } else {
3565 ANDROID_ERROR(
3566 ("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
3567 return -1;
3568 }
3569 } else {
3570 /* No WPA config, configure only RSSI preference */
3571 total_bytes = JOIN_PREF_RSSI_SIZE;
3572 }
3573
3574 /* akm-ucipher-mcipher tuples in the format required for join_pref */
3575 for (i = 0; i < num_ucipher_suites; i++) {
3576 for (j = 0; j < num_akm_suites; j++) {
3577 memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
3578 pref += WPA_SUITE_LEN;
3579 memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
3580 pref += WPA_SUITE_LEN;
3581 /* Set to 0 to match any available multicast cipher */
3582 bzero(pref, WPA_SUITE_LEN);
3583 pref += WPA_SUITE_LEN;
3584 }
3585 }
3586
3587 prhex("join pref", (uint8 *)buf, total_bytes);
3588 error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf,
3589 sizeof(smbuf), NULL);
3590 if (error) {
3591 ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
3592 }
3593 return error;
3594 }
3595 #endif /* defined(BCMFW_ROAM_ENABLE */
3596
3597 #ifdef WL_CFG80211
wl_android_iolist_add(struct net_device * dev,struct list_head * head,struct io_cfg * config)3598 static int wl_android_iolist_add(struct net_device *dev, struct list_head *head,
3599 struct io_cfg *config)
3600 {
3601 struct io_cfg *resume_cfg;
3602 s32 ret;
3603 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3604
3605 resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
3606 if (!resume_cfg) {
3607 return -ENOMEM;
3608 }
3609
3610 if (config->iovar) {
3611 ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
3612 if (ret) {
3613 ANDROID_ERROR(("%s: Failed to get current %s value\n", __FUNCTION__,
3614 config->iovar));
3615 goto error;
3616 }
3617
3618 ret = wldev_iovar_setint(dev, config->iovar, config->param);
3619 if (ret) {
3620 ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
3621 config->iovar, config->param));
3622 goto error;
3623 }
3624
3625 resume_cfg->iovar = config->iovar;
3626 } else {
3627 resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
3628 if (!resume_cfg->arg) {
3629 ret = -ENOMEM;
3630 goto error;
3631 }
3632 ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
3633 if (ret) {
3634 ANDROID_ERROR(
3635 ("%s: Failed to get ioctl %d\n", __FUNCTION__, config->ioctl));
3636 goto error;
3637 }
3638 ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
3639 if (ret) {
3640 ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
3641 config->iovar, config->param));
3642 goto error;
3643 }
3644 if (config->ioctl + 1 == WLC_SET_PM) {
3645 wl_cfg80211_update_power_mode(dev);
3646 }
3647 resume_cfg->ioctl = config->ioctl;
3648 resume_cfg->len = config->len;
3649 }
3650
3651 list_add(&resume_cfg->list, head);
3652
3653 return 0;
3654 error:
3655 MFREE(cfg->osh, resume_cfg->arg, config->len);
3656 MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
3657 return ret;
3658 }
3659
wl_android_iolist_resume(struct net_device * dev,struct list_head * head)3660 static void wl_android_iolist_resume(struct net_device *dev,
3661 struct list_head *head)
3662 {
3663 struct io_cfg *config;
3664 struct list_head *cur, *q;
3665 s32 ret = 0;
3666 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3667 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3668 list_for_each_safe(cur, q, head)
3669 {
3670 config = list_entry(cur, struct io_cfg, list);
3671 GCC_DIAGNOSTIC_POP();
3672 if (config->iovar) {
3673 if (!ret) {
3674 ret = wldev_iovar_setint(dev, config->iovar, config->param);
3675 }
3676 } else {
3677 if (!ret) {
3678 ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg,
3679 config->len);
3680 }
3681 if (config->ioctl + 1 == WLC_SET_PM) {
3682 wl_cfg80211_update_power_mode(dev);
3683 }
3684 MFREE(cfg->osh, config->arg, config->len);
3685 }
3686 list_del(cur);
3687 MFREE(cfg->osh, config, sizeof(struct io_cfg));
3688 }
3689 }
3690
wl_android_set_miracast(struct net_device * dev,char * command)3691 static int wl_android_set_miracast(struct net_device *dev, char *command)
3692 {
3693 int mode, val = 0;
3694 int ret = 0;
3695 struct io_cfg config;
3696
3697 if (sscanf(command, "%*s %d", &mode) != 1) {
3698 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
3699 return -1;
3700 }
3701
3702 ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
3703
3704 if (miracast_cur_mode == mode) {
3705 return 0;
3706 }
3707
3708 wl_android_iolist_resume(dev, &miracast_resume_list);
3709 miracast_cur_mode = MIRACAST_MODE_OFF;
3710
3711 bzero((void *)&config, sizeof(config));
3712 switch (mode) {
3713 case MIRACAST_MODE_SOURCE:
3714 #ifdef MIRACAST_MCHAN_ALGO
3715 /* setting mchan_algo to platform specific value */
3716 config.iovar = "mchan_algo";
3717
3718 ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
3719 if (!ret && val > 0x64) {
3720 config.param = 0;
3721 ANDROID_ERROR(("%s: Connected station's beacon interval: "
3722 "%d and set mchan_algo to %d \n",
3723 __FUNCTION__, val, config.param));
3724 } else {
3725 config.param = MIRACAST_MCHAN_ALGO;
3726 }
3727 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
3728 if (ret) {
3729 goto resume;
3730 }
3731 #endif /* MIRACAST_MCHAN_ALGO */
3732
3733 #ifdef MIRACAST_MCHAN_BW
3734 /* setting mchan_bw to platform specific value */
3735 config.iovar = "mchan_bw";
3736 config.param = MIRACAST_MCHAN_BW;
3737 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
3738 if (ret) {
3739 goto resume;
3740 }
3741 #endif /* MIRACAST_MCHAN_BW */
3742
3743 #ifdef MIRACAST_AMPDU_SIZE
3744 /* setting apmdu to platform specific value */
3745 config.iovar = "ampdu_mpdu";
3746 config.param = MIRACAST_AMPDU_SIZE;
3747 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
3748 if (ret) {
3749 goto resume;
3750 }
3751 #endif /* MIRACAST_AMPDU_SIZE */
3752 /* FALLTROUGH */
3753 /* Source mode shares most configurations with sink mode.
3754 * Fall through here to avoid code duplication
3755 */
3756 case MIRACAST_MODE_SINK:
3757 /* disable internal roaming */
3758 config.iovar = "roam_off";
3759 config.param = 1;
3760 config.arg = NULL;
3761 config.len = 0;
3762 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
3763 if (ret) {
3764 goto resume;
3765 }
3766
3767 /* tunr off pm */
3768 ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
3769 if (ret) {
3770 goto resume;
3771 }
3772
3773 if (val != PM_OFF) {
3774 val = PM_OFF;
3775 config.iovar = NULL;
3776 config.ioctl = WLC_GET_PM;
3777 config.arg = &val;
3778 config.len = sizeof(int);
3779 ret =
3780 wl_android_iolist_add(dev, &miracast_resume_list, &config);
3781 if (ret) {
3782 goto resume;
3783 }
3784 }
3785 break;
3786 case MIRACAST_MODE_OFF:
3787 default:
3788 break;
3789 }
3790 miracast_cur_mode = mode;
3791
3792 return 0;
3793
3794 resume:
3795 ANDROID_ERROR(
3796 ("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
3797 wl_android_iolist_resume(dev, &miracast_resume_list);
3798 return ret;
3799 }
3800 #endif /* WL_CFG80211 */
3801
3802 #ifdef WL_RELMCAST
3803 #define NETLINK_OXYGEN 30
3804 #define AIBSS_BEACON_TIMEOUT 10
3805
3806 static struct sock *nl_sk = NULL;
3807
wl_netlink_recv(struct sk_buff * skb)3808 static void wl_netlink_recv(struct sk_buff *skb)
3809 {
3810 ANDROID_ERROR(("netlink_recv called\n"));
3811 }
3812
wl_netlink_init(void)3813 static int wl_netlink_init(void)
3814 {
3815 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
3816 struct netlink_kernel_cfg cfg = {
3817 .input = wl_netlink_recv,
3818 };
3819 #endif // endif
3820
3821 if (nl_sk != NULL) {
3822 ANDROID_ERROR(("nl_sk already exist\n"));
3823 return BCME_ERROR;
3824 }
3825
3826 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
3827 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, 0, wl_netlink_recv,
3828 NULL, THIS_MODULE);
3829 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
3830 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
3831 #else
3832 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
3833 #endif // endif
3834 if (nl_sk == NULL) {
3835 ANDROID_ERROR(("nl_sk is not ready\n"));
3836 return BCME_ERROR;
3837 }
3838 return BCME_OK;
3839 }
3840
wl_netlink_deinit(void)3841 static void wl_netlink_deinit(void)
3842 {
3843 if (nl_sk) {
3844 netlink_kernel_release(nl_sk);
3845 nl_sk = NULL;
3846 }
3847 }
3848
wl_netlink_send_msg(int pid,int type,int seq,const void * data,size_t size)3849 s32 wl_netlink_send_msg(int pid, int type, int seq, const void *data,
3850 size_t size)
3851 {
3852 struct sk_buff *skb = NULL;
3853 struct nlmsghdr *nlh = NULL;
3854 int ret = -1;
3855
3856 if (nl_sk == NULL) {
3857 ANDROID_ERROR(("nl_sk was not initialized\n"));
3858 goto nlmsg_failure;
3859 }
3860
3861 skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
3862 if (skb == NULL) {
3863 ANDROID_ERROR(("failed to allocate memory\n"));
3864 goto nlmsg_failure;
3865 }
3866
3867 nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
3868 if (nlh == NULL) {
3869 ANDROID_ERROR(
3870 ("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
3871 skb_tailroom(skb), nlmsg_total_size(size)));
3872 dev_kfree_skb(skb);
3873 goto nlmsg_failure;
3874 }
3875
3876 memcpy(nlmsg_data(nlh), data, size);
3877 nlh->nlmsg_seq = seq;
3878 nlh->nlmsg_type = type;
3879
3880 /* netlink_unicast() takes ownership of the skb and frees it itself. */
3881 ret = netlink_unicast(nl_sk, skb, pid, 0);
3882 ANDROID_INFO(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
3883
3884 nlmsg_failure:
3885 return ret;
3886 }
3887 #endif /* WL_RELMCAST */
3888
wl_keep_alive_set(struct net_device * dev,char * extra)3889 int wl_keep_alive_set(struct net_device *dev, char *extra)
3890 {
3891 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
3892 int ret;
3893 uint period_msec = 0;
3894 char *buf;
3895 dhd_pub_t *dhd = dhd_get_pub(dev);
3896
3897 if (extra == NULL) {
3898 ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__));
3899 return -1;
3900 }
3901 if (sscanf(extra, "%d", &period_msec) != 1) {
3902 ANDROID_ERROR(
3903 ("%s: sscanf error. check period_msec value\n", __FUNCTION__));
3904 return -EINVAL;
3905 }
3906 ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
3907
3908 bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
3909
3910 mkeep_alive_pkt.period_msec = period_msec;
3911 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
3912 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
3913
3914 /* Setup keep alive zero for null packet generation */
3915 mkeep_alive_pkt.keep_alive_id = 0;
3916 mkeep_alive_pkt.len_bytes = 0;
3917
3918 buf = (char *)MALLOC(dhd->osh, WLC_IOCTL_SMLEN);
3919 if (!buf) {
3920 ANDROID_ERROR(("%s: buffer alloc failed\n", __FUNCTION__));
3921 return BCME_NOMEM;
3922 }
3923 ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
3924 WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN,
3925 NULL);
3926 if (ret < 0) {
3927 ANDROID_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret));
3928 } else {
3929 ANDROID_TRACE(("%s:keep_alive set ok\n", __FUNCTION__));
3930 }
3931 MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN);
3932 return ret;
3933 }
3934
3935 #ifdef P2PRESP_WFDIE_SRC
wl_android_get_wfdie_resp(struct net_device * dev,char * command,int total_len)3936 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command,
3937 int total_len)
3938 {
3939 int error = 0;
3940 int bytes_written = 0;
3941 int only_resp_wfdsrc = 0;
3942
3943 error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
3944 if (error) {
3945 ANDROID_ERROR(
3946 ("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
3947 __FUNCTION__, error));
3948 return -1;
3949 }
3950
3951 bytes_written = snprintf(command, total_len, "%s %d",
3952 CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
3953
3954 return bytes_written;
3955 }
3956
wl_android_set_wfdie_resp(struct net_device * dev,int only_resp_wfdsrc)3957 static int wl_android_set_wfdie_resp(struct net_device *dev,
3958 int only_resp_wfdsrc)
3959 {
3960 int error = 0;
3961
3962 error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
3963 if (error) {
3964 ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
3965 __FUNCTION__, only_resp_wfdsrc, error));
3966 return -1;
3967 }
3968
3969 return 0;
3970 }
3971 #endif /* P2PRESP_WFDIE_SRC */
3972
3973 #ifdef BT_WIFI_HANDOVER
wl_tbow_teardown(struct net_device * dev)3974 static int wl_tbow_teardown(struct net_device *dev)
3975 {
3976 int err = BCME_OK;
3977 char buf[WLC_IOCTL_SMLEN];
3978 tbow_setup_netinfo_t netinfo;
3979 bzero(&netinfo, sizeof(netinfo));
3980 netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
3981
3982 err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
3983 sizeof(tbow_setup_netinfo_t), buf,
3984 WLC_IOCTL_SMLEN, 0, NULL);
3985 if (err < 0) {
3986 ANDROID_ERROR(("tbow_doho iovar error %d\n", err));
3987 return err;
3988 }
3989 return err;
3990 }
3991 #endif /* BT_WIFI_HANOVER */
3992
3993 #ifdef SET_RPS_CPUS
wl_android_set_rps_cpus(struct net_device * dev,char * command)3994 static int wl_android_set_rps_cpus(struct net_device *dev, char *command)
3995 {
3996 int error, enable;
3997 enable = command[strlen(CMD_RPSMODE) + 1] - '0';
3998 error = dhd_rps_cpus_enable(dev, enable);
3999 #if defined(DHDTCPACK_SUPPRESS) && defined(BCMPCIE) && defined(WL_CFG80211) && \
4000 !defined(DHD_TPUT_PATCH)
4001 if (!error) {
4002 void *dhdp = wl_cfg80211_get_dhdp(net);
4003 if (enable) {
4004 ANDROID_TRACE(
4005 ("%s : set ack suppress. TCPACK_SUP_HOLD.\n", __FUNCTION__));
4006 dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_HOLD);
4007 } else {
4008 ANDROID_TRACE(("%s : clear ack suppress.\n", __FUNCTION__));
4009 dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
4010 }
4011 }
4012 #endif /* DHDTCPACK_SUPPRESS && BCMPCIE && WL_CFG80211 */
4013 return error;
4014 }
4015 #endif /* SET_RPS_CPUS */
4016
wl_android_get_link_status(struct net_device * dev,char * command,int total_len)4017 static int wl_android_get_link_status(struct net_device *dev, char *command,
4018 int total_len)
4019 {
4020 int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0,
4021 mcs_map;
4022 uint32 rspec;
4023 uint encode, txexp;
4024 wl_bss_info_t *bi;
4025 int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
4026 char buf[WLC_IOCTL_SMLEN];
4027
4028 if (datalen > WLC_IOCTL_SMLEN) {
4029 ANDROID_ERROR(("data too big\n"));
4030 return -1;
4031 }
4032
4033 bzero(buf, datalen);
4034 /* get BSS information */
4035 *(u32 *)buf = htod32(datalen);
4036 error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
4037 if (unlikely(error)) {
4038 ANDROID_ERROR(("Could not get bss info %d\n", error));
4039 return -1;
4040 }
4041
4042 bi = (wl_bss_info_t *)(buf + sizeof(uint32));
4043
4044 for (i = 0; i < ETHER_ADDR_LEN; i++) {
4045 if (bi->BSSID.octet[i] > 0) {
4046 break;
4047 }
4048 }
4049
4050 if (i == ETHER_ADDR_LEN) {
4051 ANDROID_INFO(("No BSSID\n"));
4052 return -1;
4053 }
4054
4055 /* check VHT capability at beacon */
4056 if (bi->vht_cap) {
4057 if (CHSPEC_IS5G(bi->chanspec)) {
4058 result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
4059 }
4060 }
4061
4062 /* get a rspec (radio spectrum) rate */
4063 error = wldev_iovar_getint(dev, "nrate", &rspec);
4064 if (unlikely(error) || rspec == 0) {
4065 ANDROID_ERROR(("get link status error (%d)\n", error));
4066 return -1;
4067 }
4068
4069 encode = (rspec & WL_RSPEC_ENCODING_MASK);
4070 txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
4071
4072 switch (encode) {
4073 case WL_RSPEC_ENCODE_HT:
4074 /* check Rx MCS Map for HT */
4075 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
4076 int8 bitmap = 0xFF;
4077 if (i == MAX_STREAMS_SUPPORTED - 1) {
4078 bitmap = 0x7F;
4079 }
4080 if (bi->basic_mcs[i] & bitmap) {
4081 nss++;
4082 }
4083 }
4084 break;
4085 case WL_RSPEC_ENCODE_VHT:
4086 /* check Rx MCS Map for VHT */
4087 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
4088 mcs_map =
4089 VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
4090 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
4091 nss++;
4092 }
4093 }
4094 break;
4095 default:
4096 break;
4097 }
4098
4099 /* check MIMO capability with nss in beacon */
4100 if (nss > 1) {
4101 result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
4102 }
4103
4104 single_stream =
4105 (encode == WL_RSPEC_ENCODE_RATE) ||
4106 ((encode == WL_RSPEC_ENCODE_HT) &&
4107 (rspec & WL_RSPEC_HT_MCS_MASK) < 0x8) ||
4108 ((encode == WL_RSPEC_ENCODE_VHT) &&
4109 ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
4110
4111 if (txexp == 0) {
4112 if ((rspec & WL_RSPEC_STBC) && single_stream) {
4113 stf = OLD_NRATE_STF_STBC;
4114 } else {
4115 stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
4116 }
4117 } else if (txexp == 1 && single_stream) {
4118 stf = OLD_NRATE_STF_CDD;
4119 }
4120
4121 /* check 11ac (VHT) */
4122 if (encode == WL_RSPEC_ENCODE_VHT) {
4123 if (CHSPEC_IS5G(bi->chanspec)) {
4124 result |= WL_ANDROID_LINK_VHT;
4125 }
4126 }
4127
4128 /* check MIMO */
4129 if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
4130 switch (stf) {
4131 case OLD_NRATE_STF_SISO:
4132 break;
4133 case OLD_NRATE_STF_CDD:
4134 case OLD_NRATE_STF_STBC:
4135 result |= WL_ANDROID_LINK_MIMO;
4136 break;
4137 case OLD_NRATE_STF_SDM:
4138 if (!single_stream) {
4139 result |= WL_ANDROID_LINK_MIMO;
4140 }
4141 break;
4142 default:
4143 break;
4144 }
4145 }
4146
4147 ANDROID_INFO(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
4148 __FUNCTION__, result, stf, single_stream, nss));
4149
4150 bytes_written =
4151 snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
4152
4153 return bytes_written;
4154 }
4155
4156 #ifdef P2P_LISTEN_OFFLOADING
4157
wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 * cfg)4158 s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
4159 {
4160 s32 bssidx;
4161 int ret = 0;
4162 int p2plo_pause = 0;
4163 dhd_pub_t *dhd = NULL;
4164 if (!cfg || !cfg->p2p) {
4165 ANDROID_ERROR(
4166 ("Wl %p or cfg->p2p %p is null\n", cfg, cfg ? cfg->p2p : 0));
4167 return 0;
4168 }
4169
4170 dhd = (dhd_pub_t *)(cfg->pub);
4171 if (!dhd->up) {
4172 ANDROID_ERROR(("bus is already down\n"));
4173 return ret;
4174 }
4175
4176 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
4177 ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "p2po_stop",
4178 (void *)&p2plo_pause, sizeof(p2plo_pause),
4179 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx,
4180 &cfg->ioctl_buf_sync);
4181 if (ret < 0) {
4182 ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
4183 }
4184
4185 return ret;
4186 }
wl_cfg80211_p2plo_listen_start(struct net_device * dev,u8 * buf,int len)4187 s32 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
4188 {
4189 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4190 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
4191 wl_p2plo_listen_t p2plo_listen;
4192 int ret = -EAGAIN;
4193 int channel = 0;
4194 int period = 0;
4195 int interval = 0;
4196 int count = 0;
4197 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
4198 ANDROID_ERROR(("Sending Action Frames. Try it again.\n"));
4199 goto exit;
4200 }
4201
4202 if (wl_get_drv_status_all(cfg, SCANNING)) {
4203 ANDROID_ERROR(("Scanning already\n"));
4204 goto exit;
4205 }
4206
4207 if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
4208 ANDROID_ERROR(("Scanning being aborted\n"));
4209 goto exit;
4210 }
4211
4212 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
4213 ANDROID_ERROR(("p2p listen offloading already running\n"));
4214 goto exit;
4215 }
4216
4217 /* Just in case if it is not enabled */
4218 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
4219 ANDROID_ERROR(("cfgp2p_enable discovery failed"));
4220 goto exit;
4221 }
4222
4223 bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
4224
4225 if (len) {
4226 sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval,
4227 &count);
4228 if ((channel == 0) || (period == 0) || (interval == 0) ||
4229 (count == 0)) {
4230 ANDROID_ERROR(("Wrong argument %d/%d/%d/%d \n", channel, period,
4231 interval, count));
4232 ret = -EAGAIN;
4233 goto exit;
4234 }
4235 p2plo_listen.period = period;
4236 p2plo_listen.interval = interval;
4237 p2plo_listen.count = count;
4238
4239 ANDROID_ERROR(("channel:%d period:%d, interval:%d count:%d\n", channel,
4240 period, interval, count));
4241 } else {
4242 ANDROID_ERROR(("Argument len is wrong.\n"));
4243 ret = -EAGAIN;
4244 goto exit;
4245 }
4246
4247 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel",
4248 (void *)&channel, sizeof(channel),
4249 cfg->ioctl_buf, WLC_IOCTL_SMLEN,
4250 bssidx, &cfg->ioctl_buf_sync)) < 0) {
4251 ANDROID_ERROR(("p2po_listen_channel Failed :%d\n", ret));
4252 goto exit;
4253 }
4254
4255 if ((ret = wldev_iovar_setbuf_bsscfg(
4256 dev, "p2po_listen", (void *)&p2plo_listen,
4257 sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx,
4258 &cfg->ioctl_buf_sync)) < 0) {
4259 ANDROID_ERROR(("p2po_listen Failed :%d\n", ret));
4260 goto exit;
4261 }
4262
4263 wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
4264 exit:
4265 return ret;
4266 }
wl_cfg80211_p2plo_listen_stop(struct net_device * dev)4267 s32 wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
4268 {
4269 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4270 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
4271 int ret = -EAGAIN;
4272
4273 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL, 0,
4274 cfg->ioctl_buf, WLC_IOCTL_SMLEN,
4275 bssidx, &cfg->ioctl_buf_sync)) < 0) {
4276 ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
4277 goto exit;
4278 }
4279
4280 exit:
4281 return ret;
4282 }
4283
wl_cfg80211_p2plo_offload(struct net_device * dev,char * cmd,char * buf,int len)4284 s32 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char *buf,
4285 int len)
4286 {
4287 int ret = 0;
4288
4289 ANDROID_ERROR(("Entry cmd:%s arg_len:%d \n", cmd, len));
4290
4291 if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
4292 ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
4293 } else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
4294 ret = wl_cfg80211_p2plo_listen_stop(dev);
4295 } else {
4296 ANDROID_ERROR(("Request for Unsupported CMD:%s \n", buf));
4297 ret = -EINVAL;
4298 }
4299 return ret;
4300 }
wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 * cfg)4301 void wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg)
4302 {
4303 struct wireless_dev *wdev;
4304 if (!cfg) {
4305 return;
4306 }
4307
4308 wdev = bcmcfg_to_p2p_wdev(cfg);
4309
4310 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
4311 WL_INFORM_MEM(("P2P_FIND: Discovery offload is already in progress."
4312 "it aborted\n"));
4313 wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
4314 if (wdev != NULL) {
4315 #if defined(WL_CFG80211_P2P_DEV_IF)
4316 cfg80211_remain_on_channel_expired(
4317 wdev, cfg->last_roc_id, &cfg->remain_on_chan, GFP_KERNEL);
4318 #else
4319 cfg80211_remain_on_channel_expired(
4320 wdev, cfg->last_roc_id, &cfg->remain_on_chan,
4321 cfg->remain_on_chan_type, GFP_KERNEL);
4322 #endif /* WL_CFG80211_P2P_DEV_IF */
4323
4324 #ifdef CONFIG_AP6XXX_WIFI6_HDF
4325 int32 ret = 0;
4326 ret = HdfWifiEventCancelRemainOnChannel(
4327 get_hdf_netdev(g_event_ifidx), cfg->remain_on_chan.center_freq);
4328 WL_ERR(("HdfWifiEventCancelRemainOnChannel ret=%d\n", ret));
4329 #endif
4330 }
4331 wl_cfg80211_p2plo_deinit(cfg);
4332 }
4333 }
4334 #endif /* P2P_LISTEN_OFFLOADING */
4335
4336 #ifdef WL_MURX
wl_android_murx_bfe_cap(struct net_device * dev,int val)4337 int wl_android_murx_bfe_cap(struct net_device *dev, int val)
4338 {
4339 int err = BCME_OK;
4340 int iface_count = wl_cfg80211_iface_count(dev);
4341 struct ether_addr bssid;
4342 wl_reassoc_params_t params;
4343
4344 if (iface_count > 1) {
4345 ANDROID_ERROR(("murx_bfe_cap change is not allowed when "
4346 "there are multiple interfaces\n"));
4347 return -EINVAL;
4348 }
4349 /* Now there is only single interface */
4350 err = wldev_iovar_setint(dev, "murx_bfe_cap", val);
4351 if (unlikely(err)) {
4352 ANDROID_ERROR(("Failed to set murx_bfe_cap IOVAR to %d,"
4353 "error %d\n",
4354 val, err));
4355 return err;
4356 }
4357
4358 /* If successful intiate a reassoc */
4359 bzero(&bssid, ETHER_ADDR_LEN);
4360 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) <
4361 0) {
4362 ANDROID_ERROR(("Failed to get bssid, error=%d\n", err));
4363 return err;
4364 }
4365
4366 bzero(¶ms, sizeof(wl_reassoc_params_t));
4367 memcpy(¶ms.bssid, &bssid, ETHER_ADDR_LEN);
4368
4369 if ((err = wldev_ioctl_set(dev, WLC_REASSOC, ¶ms,
4370 sizeof(wl_reassoc_params_t))) < 0) {
4371 ANDROID_ERROR(("reassoc failed err:%d \n", err));
4372 } else {
4373 ANDROID_INFO(("reassoc issued successfully\n"));
4374 }
4375
4376 return err;
4377 }
4378 #endif /* WL_MURX */
4379
4380 #ifdef SUPPORT_RSSI_SUM_REPORT
wl_android_get_rssi_per_ant(struct net_device * dev,char * command,int total_len)4381 int wl_android_get_rssi_per_ant(struct net_device *dev, char *command,
4382 int total_len)
4383 {
4384 wl_rssi_ant_mimo_t rssi_ant_mimo;
4385 char *ifname = NULL;
4386 char *peer_mac = NULL;
4387 char *mimo_cmd = "mimo";
4388 char *pos, *token;
4389 int err = BCME_OK;
4390 int bytes_written = 0;
4391 bool mimo_rssi = FALSE;
4392
4393 bzero(&rssi_ant_mimo, sizeof(wl_rssi_ant_mimo_t));
4394 /*
4395 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
4396 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
4397 */
4398 pos = command;
4399
4400 /* drop command */
4401 token = bcmstrtok(&pos, " ", NULL);
4402
4403 /* get the interface name */
4404 token = bcmstrtok(&pos, " ", NULL);
4405 if (!token) {
4406 ANDROID_ERROR(("Invalid arguments\n"));
4407 return -EINVAL;
4408 }
4409 ifname = token;
4410
4411 /* Optional: Check the MIMO RSSI mode or peer MAC address */
4412 token = bcmstrtok(&pos, " ", NULL);
4413 if (token) {
4414 /* Check the MIMO RSSI mode */
4415 if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
4416 mimo_rssi = TRUE;
4417 } else {
4418 peer_mac = token;
4419 }
4420 }
4421
4422 /* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
4423 token = bcmstrtok(&pos, " ", NULL);
4424 if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
4425 mimo_rssi = TRUE;
4426 }
4427
4428 err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
4429 if (unlikely(err)) {
4430 ANDROID_ERROR(("Failed to get RSSI info, err=%d\n", err));
4431 return err;
4432 }
4433
4434 /* Parse the results */
4435 ANDROID_INFO(("ifname %s, version %d, count %d, mimo rssi %d\n", ifname,
4436 rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
4437 if (mimo_rssi) {
4438 ANDROID_INFO(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
4439 bytes_written = snprintf(command, total_len, "%s MIMO %d",
4440 CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
4441 } else {
4442 int cnt;
4443 bytes_written =
4444 snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
4445 for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
4446 ANDROID_INFO(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
4447 bytes_written = snprintf(command, total_len, "%d ",
4448 rssi_ant_mimo.rssi_ant[cnt]);
4449 }
4450 }
4451
4452 return bytes_written;
4453 }
4454
wl_android_set_rssi_logging(struct net_device * dev,char * command,int total_len)4455 int wl_android_set_rssi_logging(struct net_device *dev, char *command,
4456 int total_len)
4457 {
4458 rssilog_set_param_t set_param;
4459 char *pos, *token;
4460 int err = BCME_OK;
4461
4462 bzero(&set_param, sizeof(rssilog_set_param_t));
4463 /*
4464 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time
4465 * Threshold>
4466 */
4467 pos = command;
4468
4469 /* drop command */
4470 token = bcmstrtok(&pos, " ", NULL);
4471
4472 /* enable/disable */
4473 token = bcmstrtok(&pos, " ", NULL);
4474 if (!token) {
4475 ANDROID_ERROR(("Invalid arguments\n"));
4476 return -EINVAL;
4477 }
4478 set_param.enable = bcm_atoi(token);
4479
4480 /* RSSI Threshold */
4481 token = bcmstrtok(&pos, " ", NULL);
4482 if (!token) {
4483 ANDROID_ERROR(("Invalid arguments\n"));
4484 return -EINVAL;
4485 }
4486 set_param.rssi_threshold = bcm_atoi(token);
4487
4488 /* Time Threshold */
4489 token = bcmstrtok(&pos, " ", NULL);
4490 if (!token) {
4491 ANDROID_ERROR(("Invalid arguments\n"));
4492 return -EINVAL;
4493 }
4494 set_param.time_threshold = bcm_atoi(token);
4495
4496 ANDROID_INFO(("enable %d, RSSI threshold %d, Time threshold %d\n",
4497 set_param.enable, set_param.rssi_threshold,
4498 set_param.time_threshold));
4499
4500 err = wl_set_rssi_logging(dev, (void *)&set_param);
4501 if (unlikely(err)) {
4502 ANDROID_ERROR(
4503 ("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
4504 " Time Threshold %d\n",
4505 set_param.enable, set_param.rssi_threshold,
4506 set_param.time_threshold));
4507 }
4508
4509 return err;
4510 }
4511
wl_android_get_rssi_logging(struct net_device * dev,char * command,int total_len)4512 int wl_android_get_rssi_logging(struct net_device *dev, char *command,
4513 int total_len)
4514 {
4515 rssilog_get_param_t get_param;
4516 int err = BCME_OK;
4517 int bytes_written = 0;
4518
4519 err = wl_get_rssi_logging(dev, (void *)&get_param);
4520 if (unlikely(err)) {
4521 ANDROID_ERROR(("Failed to get RSSI logging info\n"));
4522 return BCME_ERROR;
4523 }
4524
4525 ANDROID_INFO(
4526 ("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
4527 get_param.report_count, get_param.enable, get_param.rssi_threshold,
4528 get_param.time_threshold));
4529
4530 /* Parse the parameter */
4531 if (!get_param.enable) {
4532 ANDROID_INFO(("RSSI LOGGING: Feature is disables\n"));
4533 bytes_written = snprintf(command, total_len, "%s FEATURE DISABLED\n",
4534 CMD_GET_RSSI_LOGGING);
4535 } else if (get_param.enable &
4536 (RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
4537 if (!get_param.report_count) {
4538 ANDROID_INFO(("[PASS] RSSI difference across antennas is within"
4539 " threshold limits\n"));
4540 bytes_written =
4541 snprintf(command, total_len, "%s PASS\n", CMD_GET_RSSI_LOGGING);
4542 } else {
4543 ANDROID_INFO(("[FAIL] RSSI difference across antennas found "
4544 "to be greater than %3d dB\n",
4545 get_param.rssi_threshold));
4546 ANDROID_INFO(("[FAIL] RSSI difference check have failed for "
4547 "%d out of %d times\n",
4548 get_param.report_count, get_param.time_threshold));
4549 ANDROID_INFO(("[FAIL] RSSI difference is being monitored once "
4550 "per second, for a %d secs window\n",
4551 get_param.time_threshold));
4552 bytes_written =
4553 snprintf(command, total_len,
4554 "%s FAIL - RSSI Threshold "
4555 "%d dBm for %d out of %d times\n",
4556 CMD_GET_RSSI_LOGGING, get_param.rssi_threshold,
4557 get_param.report_count, get_param.time_threshold);
4558 }
4559 } else {
4560 ANDROID_INFO(("[BUSY] Reprot is not ready\n"));
4561 bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
4562 CMD_GET_RSSI_LOGGING);
4563 }
4564
4565 return bytes_written;
4566 }
4567 #endif /* SUPPORT_RSSI_SUM_REPORT */
4568
4569 #ifdef SET_PCIE_IRQ_CPU_CORE
wl_android_set_irq_cpucore(struct net_device * net,int affinity_cmd)4570 void wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
4571 {
4572 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
4573 if (!dhdp) {
4574 ANDROID_ERROR(("dhd is NULL\n"));
4575 return;
4576 }
4577
4578 if (affinity_cmd < PCIE_IRQ_AFFINITY_OFF ||
4579 affinity_cmd > PCIE_IRQ_AFFINITY_LAST) {
4580 ANDROID_ERROR(
4581 ("Wrong Affinity cmds:%d, %s\n", affinity_cmd, __FUNCTION__));
4582 return;
4583 }
4584
4585 dhd_set_irq_cpucore(dhdp, affinity_cmd);
4586 }
4587 #endif /* SET_PCIE_IRQ_CPU_CORE */
4588
4589 #ifdef SUPPORT_LQCM
wl_android_lqcm_enable(struct net_device * net,int lqcm_enable)4590 static int wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
4591 {
4592 int err = 0;
4593
4594 err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
4595 if (err != BCME_OK) {
4596 ANDROID_ERROR(
4597 ("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
4598 return -EIO;
4599 }
4600 return err;
4601 }
4602
wl_android_get_lqcm_report(struct net_device * dev,char * command,int total_len)4603 static int wl_android_get_lqcm_report(struct net_device *dev, char *command,
4604 int total_len)
4605 {
4606 int bytes_written, err = 0;
4607 uint32 lqcm_report = 0;
4608 uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
4609
4610 err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
4611 if (err != BCME_OK) {
4612 ANDROID_ERROR(("failed to get lqcm report, error = %d\n", err));
4613 return -EIO;
4614 }
4615 lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
4616 tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
4617 rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
4618
4619 ANDROID_INFO(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx,
4620 rx_lqcm_idx));
4621
4622 bytes_written =
4623 snprintf(command, total_len, "%s %d", CMD_GET_LQCM_REPORT, lqcm_report);
4624
4625 return bytes_written;
4626 }
4627 #endif /* SUPPORT_LQCM */
4628
wl_android_get_snr(struct net_device * dev,char * command,int total_len)4629 int wl_android_get_snr(struct net_device *dev, char *command, int total_len)
4630 {
4631 int bytes_written, error = 0;
4632 s32 snr = 0;
4633
4634 error = wldev_iovar_getint(dev, "snr", &snr);
4635 if (error) {
4636 ANDROID_ERROR(("%s: Failed to get SNR %d, error = %d\n", __FUNCTION__,
4637 snr, error));
4638 return -EIO;
4639 }
4640
4641 bytes_written = snprintf(command, total_len, "snr %d", snr);
4642 ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command));
4643 return bytes_written;
4644 }
4645
4646 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
wl_android_set_ap_beaconrate(struct net_device * dev,char * command)4647 int wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
4648 {
4649 int rate = 0;
4650 char *pos, *token;
4651 char *ifname = NULL;
4652 int err = BCME_OK;
4653
4654 /*
4655 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
4656 */
4657 pos = command;
4658
4659 /* drop command */
4660 token = bcmstrtok(&pos, " ", NULL);
4661
4662 /* Rate */
4663 token = bcmstrtok(&pos, " ", NULL);
4664 if (!token) {
4665 return -EINVAL;
4666 }
4667 rate = bcm_atoi(token);
4668
4669 /* get the interface name */
4670 token = bcmstrtok(&pos, " ", NULL);
4671 if (!token) {
4672 return -EINVAL;
4673 }
4674 ifname = token;
4675
4676 ANDROID_INFO(("rate %d, ifacename %s\n", rate, ifname));
4677
4678 err = wl_set_ap_beacon_rate(dev, rate, ifname);
4679 if (unlikely(err)) {
4680 ANDROID_ERROR(
4681 ("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
4682 }
4683
4684 return err;
4685 }
4686
wl_android_get_ap_basicrate(struct net_device * dev,char * command,int total_len)4687 int wl_android_get_ap_basicrate(struct net_device *dev, char *command,
4688 int total_len)
4689 {
4690 char *pos, *token;
4691 char *ifname = NULL;
4692 int bytes_written = 0;
4693 /*
4694 * DRIVER GET_AP_BASICRATE <ifname>
4695 */
4696 pos = command;
4697
4698 /* drop command */
4699 token = bcmstrtok(&pos, " ", NULL);
4700
4701 /* get the interface name */
4702 token = bcmstrtok(&pos, " ", NULL);
4703 if (!token) {
4704 return -EINVAL;
4705 }
4706 ifname = token;
4707
4708 ANDROID_INFO(("ifacename %s\n", ifname));
4709
4710 bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
4711 if (bytes_written < 1) {
4712 ANDROID_ERROR(
4713 ("Failed to get ap basic rate, error = %d\n", bytes_written));
4714 return -EPROTO;
4715 }
4716
4717 return bytes_written;
4718 }
4719 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
4720
4721 #ifdef SUPPORT_AP_RADIO_PWRSAVE
wl_android_get_ap_rps(struct net_device * dev,char * command,int total_len)4722 int wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
4723 {
4724 char *pos, *token;
4725 char *ifname = NULL;
4726 int bytes_written = 0;
4727 char name[IFNAMSIZ];
4728 /*
4729 * DRIVER GET_AP_RPS <ifname>
4730 */
4731 pos = command;
4732
4733 /* drop command */
4734 token = bcmstrtok(&pos, " ", NULL);
4735
4736 /* get the interface name */
4737 token = bcmstrtok(&pos, " ", NULL);
4738 if (!token) {
4739 return -EINVAL;
4740 }
4741 ifname = token;
4742
4743 strlcpy(name, ifname, sizeof(name));
4744 ANDROID_INFO(("ifacename %s\n", name));
4745
4746 bytes_written = wl_get_ap_rps(dev, command, name, total_len);
4747 if (bytes_written < 1) {
4748 ANDROID_ERROR(("Failed to get rps, error = %d\n", bytes_written));
4749 return -EPROTO;
4750 }
4751
4752 return bytes_written;
4753 }
4754
wl_android_set_ap_rps(struct net_device * dev,char * command,int total_len)4755 int wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
4756 {
4757 int enable = 0;
4758 char *pos, *token;
4759 char *ifname = NULL;
4760 int err = BCME_OK;
4761 char name[IFNAMSIZ];
4762
4763 /*
4764 * DRIVER SET_AP_RPS <0/1> <ifname>
4765 */
4766 pos = command;
4767
4768 /* drop command */
4769 token = bcmstrtok(&pos, " ", NULL);
4770
4771 /* Enable */
4772 token = bcmstrtok(&pos, " ", NULL);
4773 if (!token) {
4774 return -EINVAL;
4775 }
4776 enable = bcm_atoi(token);
4777
4778 /* get the interface name */
4779 token = bcmstrtok(&pos, " ", NULL);
4780 if (!token) {
4781 return -EINVAL;
4782 }
4783 ifname = token;
4784
4785 strlcpy(name, ifname, sizeof(name));
4786 ANDROID_INFO(("enable %d, ifacename %s\n", enable, name));
4787
4788 err = wl_set_ap_rps(dev, enable ? TRUE : FALSE, name);
4789 if (unlikely(err)) {
4790 ANDROID_ERROR(
4791 ("Failed to set rps, enable %d, error = %d\n", enable, err));
4792 }
4793
4794 return err;
4795 }
4796
wl_android_set_ap_rps_params(struct net_device * dev,char * command,int total_len)4797 int wl_android_set_ap_rps_params(struct net_device *dev, char *command,
4798 int total_len)
4799 {
4800 ap_rps_info_t rps;
4801 char *pos, *token;
4802 char *ifname = NULL;
4803 int err = BCME_OK;
4804 char name[IFNAMSIZ];
4805
4806 bzero(&rps, sizeof(rps));
4807 /*
4808 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
4809 */
4810 pos = command;
4811
4812 /* drop command */
4813 token = bcmstrtok(&pos, " ", NULL);
4814
4815 /* pps */
4816 token = bcmstrtok(&pos, " ", NULL);
4817 if (!token) {
4818 return -EINVAL;
4819 }
4820 rps.pps = bcm_atoi(token);
4821
4822 /* level */
4823 token = bcmstrtok(&pos, " ", NULL);
4824 if (!token) {
4825 return -EINVAL;
4826 }
4827 rps.level = bcm_atoi(token);
4828
4829 /* quiettime */
4830 token = bcmstrtok(&pos, " ", NULL);
4831 if (!token) {
4832 return -EINVAL;
4833 }
4834 rps.quiet_time = bcm_atoi(token);
4835
4836 /* sta assoc check */
4837 token = bcmstrtok(&pos, " ", NULL);
4838 if (!token) {
4839 return -EINVAL;
4840 }
4841 rps.sta_assoc_check = bcm_atoi(token);
4842
4843 /* get the interface name */
4844 token = bcmstrtok(&pos, " ", NULL);
4845 if (!token) {
4846 return -EINVAL;
4847 }
4848 ifname = token;
4849 strlcpy(name, ifname, sizeof(name));
4850
4851 ANDROID_INFO(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
4852 "ifacename %s\n",
4853 rps.pps, rps.level, rps.quiet_time, rps.sta_assoc_check,
4854 name));
4855
4856 err = wl_update_ap_rps_params(dev, &rps, name);
4857 if (unlikely(err)) {
4858 ANDROID_ERROR(("Failed to update rps, pps %d, level %d, quiettime %d, "
4859 "sta_assoc_check %d, err = %d\n",
4860 rps.pps, rps.level, rps.quiet_time, rps.sta_assoc_check,
4861 err));
4862 }
4863
4864 return err;
4865 }
4866 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
4867
4868 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
wl_android_check_priv_cmd_errors(struct net_device * dev)4869 static void wl_android_check_priv_cmd_errors(struct net_device *dev)
4870 {
4871 dhd_pub_t *dhdp;
4872 int memdump_mode;
4873
4874 if (!dev) {
4875 ANDROID_ERROR(("dev is NULL\n"));
4876 return;
4877 }
4878
4879 dhdp = wl_cfg80211_get_dhdp(dev);
4880 if (!dhdp) {
4881 ANDROID_ERROR(("dhdp is NULL\n"));
4882 return;
4883 }
4884
4885 #ifdef DHD_FW_COREDUMP
4886 memdump_mode = dhdp->memdump_enabled;
4887 #else
4888 /* Default enable if DHD doesn't support SOCRAM dump */
4889 memdump_mode = 1;
4890 #endif /* DHD_FW_COREDUMP */
4891
4892 if (report_hang_privcmd_err) {
4893 priv_cmd_errors++;
4894 } else {
4895 priv_cmd_errors = 0;
4896 }
4897
4898 /* Trigger HANG event only if memdump mode is enabled
4899 * due to customer's request
4900 */
4901 if (memdump_mode == DUMP_MEMFILE_BUGON &&
4902 (priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) {
4903 ANDROID_ERROR(
4904 ("Send HANG event due to sequential private cmd errors\n"));
4905 priv_cmd_errors = 0;
4906 #ifdef DHD_FW_COREDUMP
4907 /* Take a SOCRAM dump */
4908 dhdp->memdump_type = DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR;
4909 dhd_common_socram_dump(dhdp);
4910 #endif /* DHD_FW_COREDUMP */
4911 /* Send the HANG event to upper layer */
4912 dhdp->hang_reason = HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR;
4913 dhd_os_check_hang(dhdp, 0, -EREMOTEIO);
4914 }
4915 }
4916 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
4917
4918 #ifdef SUPPORT_AP_SUSPEND
wl_android_set_ap_suspend(struct net_device * dev,char * command,int total_len)4919 int wl_android_set_ap_suspend(struct net_device *dev, char *command,
4920 int total_len)
4921 {
4922 int suspend = 0;
4923 char *pos, *token;
4924 char *ifname = NULL;
4925 int err = BCME_OK;
4926 char name[IFNAMSIZ];
4927
4928 /*
4929 * DRIVER SET_AP_SUSPEND <0/1> <ifname>
4930 */
4931 pos = command;
4932
4933 /* drop command */
4934 token = bcmstrtok(&pos, " ", NULL);
4935
4936 /* Enable */
4937 token = bcmstrtok(&pos, " ", NULL);
4938 if (!token) {
4939 return -EINVAL;
4940 }
4941 suspend = bcm_atoi(token);
4942
4943 /* get the interface name */
4944 token = bcmstrtok(&pos, " ", NULL);
4945 if (!token) {
4946 return -EINVAL;
4947 }
4948 ifname = token;
4949
4950 strlcpy(name, ifname, sizeof(name));
4951 ANDROID_INFO(("suspend %d, ifacename %s\n", suspend, name));
4952
4953 err = wl_set_ap_suspend(dev, suspend ? TRUE : FALSE, name);
4954 if (unlikely(err)) {
4955 ANDROID_ERROR(
4956 ("Failed to set suspend, suspend %d, error = %d\n", suspend, err));
4957 }
4958
4959 return err;
4960 }
4961 #endif /* SUPPORT_AP_SUSPEND */
4962
4963 #ifdef SUPPORT_AP_BWCTRL
wl_android_set_ap_bw(struct net_device * dev,char * command,int total_len)4964 int wl_android_set_ap_bw(struct net_device *dev, char *command, int total_len)
4965 {
4966 int bw = DOT11_OPER_MODE_20MHZ;
4967 char *pos, *token;
4968 char *ifname = NULL;
4969 int err = BCME_OK;
4970 char name[IFNAMSIZ];
4971
4972 /*
4973 * DRIVER SET_AP_BW <0/1/2> <ifname>
4974 * 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
4975 * This is from operating mode field
4976 * in 8.4.1.50 of 802.11ac-2013
4977 */
4978 pos = command;
4979
4980 /* drop command */
4981 token = bcmstrtok(&pos, " ", NULL);
4982
4983 /* BW */
4984 token = bcmstrtok(&pos, " ", NULL);
4985 if (!token) {
4986 return -EINVAL;
4987 }
4988 bw = bcm_atoi(token);
4989
4990 /* get the interface name */
4991 token = bcmstrtok(&pos, " ", NULL);
4992 if (!token) {
4993 return -EINVAL;
4994 }
4995 ifname = token;
4996
4997 strlcpy(name, ifname, sizeof(name));
4998 ANDROID_INFO(("bw %d, ifacename %s\n", bw, name));
4999
5000 err = wl_set_ap_bw(dev, bw, name);
5001 if (unlikely(err)) {
5002 ANDROID_ERROR(("Failed to set bw, bw %d, error = %d\n", bw, err));
5003 }
5004
5005 return err;
5006 }
5007
wl_android_get_ap_bw(struct net_device * dev,char * command,int total_len)5008 int wl_android_get_ap_bw(struct net_device *dev, char *command, int total_len)
5009 {
5010 char *pos, *token;
5011 char *ifname = NULL;
5012 int bytes_written = 0;
5013 char name[IFNAMSIZ];
5014
5015 /*
5016 * DRIVER GET_AP_BW <ifname>
5017 * returns 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
5018 * This is from operating mode field
5019 * in 8.4.1.50 of 802.11ac-2013
5020 */
5021 pos = command;
5022
5023 /* drop command */
5024 token = bcmstrtok(&pos, " ", NULL);
5025
5026 /* get the interface name */
5027 token = bcmstrtok(&pos, " ", NULL);
5028 if (!token) {
5029 return -EINVAL;
5030 }
5031 ifname = token;
5032
5033 strlcpy(name, ifname, sizeof(name));
5034 ANDROID_INFO(("ifacename %s\n", name));
5035
5036 bytes_written = wl_get_ap_bw(dev, command, name, total_len);
5037 if (bytes_written < 1) {
5038 ANDROID_ERROR(("Failed to get bw, error = %d\n", bytes_written));
5039 return -EPROTO;
5040 }
5041
5042 return bytes_written;
5043 }
5044 #endif /* SUPPORT_AP_BWCTRL */
5045
wl_android_priv_cmd(struct net_device * net,struct ifreq * ifr)5046 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
5047 {
5048 #define PRIVATE_COMMAND_MAX_LEN 8192
5049 #define PRIVATE_COMMAND_DEF_LEN 4096
5050 int ret = 0;
5051 char *command = NULL;
5052 int bytes_written = 0;
5053 android_wifi_priv_cmd priv_cmd;
5054 int buf_size = 0;
5055 dhd_pub_t *dhd = dhd_get_pub(net);
5056
5057 net_os_wake_lock(net);
5058
5059 if (!capable(CAP_NET_ADMIN)) {
5060 ret = -EPERM;
5061 goto exit;
5062 }
5063
5064 if (!ifr->ifr_data) {
5065 ret = -EINVAL;
5066 goto exit;
5067 }
5068
5069 #ifdef CONFIG_COMPAT
5070 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
5071 if (in_compat_syscall())
5072 #else
5073 if (is_compat_task())
5074 #endif
5075 {
5076 compat_android_wifi_priv_cmd compat_priv_cmd;
5077 if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
5078 sizeof(compat_android_wifi_priv_cmd))) {
5079 ret = -EFAULT;
5080 goto exit;
5081 }
5082 priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
5083 priv_cmd.used_len = compat_priv_cmd.used_len;
5084 priv_cmd.total_len = compat_priv_cmd.total_len;
5085 } else
5086 #endif /* CONFIG_COMPAT */
5087 {
5088 if (copy_from_user(&priv_cmd, ifr->ifr_data,
5089 sizeof(android_wifi_priv_cmd))) {
5090 ret = -EFAULT;
5091 goto exit;
5092 }
5093 }
5094 if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) ||
5095 (priv_cmd.total_len < 0)) {
5096 ANDROID_ERROR(
5097 ("%s: buf length invalid:%d\n", __FUNCTION__, priv_cmd.total_len));
5098 ret = -EINVAL;
5099 goto exit;
5100 }
5101
5102 buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
5103 command = (char *)MALLOC(dhd->osh, (buf_size + 1));
5104 if (!command) {
5105 ANDROID_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
5106 ret = -ENOMEM;
5107 goto exit;
5108 }
5109 if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
5110 ret = -EFAULT;
5111 goto exit;
5112 }
5113 command[priv_cmd.total_len] = '\0';
5114
5115 ANDROID_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__,
5116 command, ifr->ifr_name));
5117
5118 bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
5119 if (bytes_written >= 0) {
5120 if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
5121 command[0] = '\0';
5122 }
5123 if (bytes_written >= priv_cmd.total_len) {
5124 ANDROID_ERROR(
5125 ("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n",
5126 __FUNCTION__, bytes_written, priv_cmd.total_len, buf_size));
5127
5128 ret = BCME_BUFTOOSHORT;
5129 goto exit;
5130 }
5131 bytes_written++;
5132 priv_cmd.used_len = bytes_written;
5133 if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
5134 ANDROID_ERROR(
5135 ("%s: failed to copy data to user buffer\n", __FUNCTION__));
5136 ret = -EFAULT;
5137 }
5138 } else {
5139 /* Propagate the error */
5140 ret = bytes_written;
5141 }
5142
5143 exit:
5144 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
5145 if (ret) {
5146 /* Avoid incrementing priv_cmd_errors in case of unsupported feature */
5147 if (ret != BCME_UNSUPPORTED) {
5148 wl_android_check_priv_cmd_errors(net);
5149 }
5150 } else {
5151 priv_cmd_errors = 0;
5152 }
5153 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
5154 net_os_wake_unlock(net);
5155 MFREE(dhd->osh, command, (buf_size + 1));
5156 return ret;
5157 }
5158
5159 #ifdef WL_BCNRECV
5160 #define BCNRECV_ATTR_HDR_LEN 30
wl_android_bcnrecv_event(struct net_device * ndev,uint attr_type,uint status,uint reason,uint8 * data,uint data_len)5161 int wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type,
5162 uint status, uint reason, uint8 *data,
5163 uint data_len)
5164 {
5165 s32 err = BCME_OK;
5166 struct sk_buff *skb;
5167 gfp_t kflags;
5168 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
5169 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
5170 uint len;
5171
5172 len = BCNRECV_ATTR_HDR_LEN + data_len;
5173
5174 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5175 skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len,
5176 BRCM_VENDOR_EVENT_BEACON_RECV, kflags);
5177 if (!skb) {
5178 ANDROID_ERROR(("skb alloc failed"));
5179 return -ENOMEM;
5180 }
5181 if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) {
5182 /* send bcn info to upper layer */
5183 nla_put(skb, BCNRECV_ATTR_BCNINFO, data_len, data);
5184 } else if (attr_type == BCNRECV_ATTR_STATUS) {
5185 nla_put_u32(skb, BCNRECV_ATTR_STATUS, status);
5186 if (reason) {
5187 nla_put_u32(skb, BCNRECV_ATTR_REASON, reason);
5188 }
5189 } else {
5190 ANDROID_ERROR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type));
5191 kfree_skb(skb);
5192 return -EINVAL;
5193 }
5194 cfg80211_vendor_event(skb, kflags);
5195 return err;
5196 }
5197
_wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool user_trigger)5198 static int _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg,
5199 struct net_device *ndev, bool user_trigger)
5200 {
5201 s32 err = BCME_OK;
5202
5203 /* check any scan is in progress before beacon recv scan trigger IOVAR */
5204 if (wl_get_drv_status_all(cfg, SCANNING)) {
5205 err = BCME_UNSUPPORTED;
5206 ANDROID_ERROR(("Scan in progress, Aborting beacon recv start, "
5207 "error:%d\n",
5208 err));
5209 goto exit;
5210 }
5211
5212 if (wl_get_p2p_status(cfg, SCANNING)) {
5213 err = BCME_UNSUPPORTED;
5214 ANDROID_ERROR(("P2P Scan in progress, Aborting beacon recv start, "
5215 "error:%d\n",
5216 err));
5217 goto exit;
5218 }
5219
5220 if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) {
5221 err = BCME_UNSUPPORTED;
5222 ANDROID_ERROR(("P2P remain on channel, Aborting beacon recv start, "
5223 "error:%d\n",
5224 err));
5225 goto exit;
5226 }
5227
5228 /* check STA is in connected state, Beacon recv required connected state
5229 * else exit from beacon recv scan
5230 */
5231 if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
5232 err = BCME_UNSUPPORTED;
5233 ANDROID_ERROR(("STA is in not associated state error:%d\n", err));
5234 goto exit;
5235 }
5236
5237 #ifdef WL_NAN
5238 /* Check NAN is enabled, if enabled exit else continue */
5239 if (wl_cfgnan_check_state(cfg)) {
5240 err = BCME_UNSUPPORTED;
5241 ANDROID_ERROR(
5242 ("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n"));
5243 goto exit;
5244 }
5245 #endif /* WL_NAN */
5246
5247 /* Triggering an sendup_bcn iovar */
5248 err = wldev_iovar_setint(ndev, "sendup_bcn", 1);
5249 if (unlikely(err)) {
5250 ANDROID_ERROR(("sendup_bcn failed to set, error:%d\n", err));
5251 } else {
5252 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED;
5253 WL_INFORM_MEM(("bcnrecv started. user_trigger:%d\n", user_trigger));
5254 if (user_trigger) {
5255 if ((err = wl_android_bcnrecv_event(ndev, BCNRECV_ATTR_STATUS,
5256 WL_BCNRECV_STARTED, 0, NULL,
5257 0)) != BCME_OK) {
5258 ANDROID_ERROR(
5259 ("failed to send bcnrecv event, error:%d\n", err));
5260 }
5261 }
5262 }
5263 exit:
5264 /*
5265 * BCNRECV start request can be rejected from dongle
5266 * in various conditions.
5267 * Error code need to be overridden to BCME_UNSUPPORTED
5268 * to avoid hang event from continous private
5269 * command error
5270 */
5271 if (err) {
5272 err = BCME_UNSUPPORTED;
5273 }
5274 return err;
5275 }
5276
_wl_android_bcnrecv_stop(struct bcm_cfg80211 * cfg,struct net_device * ndev,uint reason)5277 int _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev,
5278 uint reason)
5279 {
5280 s32 err = BCME_OK;
5281 u32 status;
5282
5283 /* Send sendup_bcn iovar for all cases except W_BCNRECV_ROAMABORT reason -
5284 * fw generates roam abort event after aborting the bcnrecv.
5285 */
5286 if (reason != WL_BCNRECV_ROAMABORT) {
5287 /* Triggering an sendup_bcn iovar */
5288 err = wldev_iovar_setint(ndev, "sendup_bcn", 0);
5289 if (unlikely(err)) {
5290 ANDROID_ERROR(("sendup_bcn failed to set error:%d\n", err));
5291 goto exit;
5292 }
5293 }
5294
5295 /* Send notification for all cases */
5296 if (reason == WL_BCNRECV_SUSPEND) {
5297 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED;
5298 status = WL_BCNRECV_SUSPENDED;
5299 } else {
5300 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED;
5301 WL_INFORM_MEM(("bcnrecv stopped\n"));
5302 if (reason == WL_BCNRECV_USER_TRIGGER) {
5303 status = WL_BCNRECV_STOPPED;
5304 } else {
5305 status = WL_BCNRECV_ABORTED;
5306 }
5307 }
5308 if ((err = wl_android_bcnrecv_event(ndev, BCNRECV_ATTR_STATUS, status,
5309 reason, NULL, 0)) != BCME_OK) {
5310 ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
5311 }
5312 exit:
5313 return err;
5314 }
5315
wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev)5316 static int wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg,
5317 struct net_device *ndev)
5318 {
5319 s32 err = BCME_OK;
5320
5321 /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn
5322 * recv */
5323 mutex_lock(&cfg->scan_sync);
5324 mutex_lock(&cfg->bcn_sync);
5325 err = _wl_android_bcnrecv_start(cfg, ndev, true);
5326 mutex_unlock(&cfg->bcn_sync);
5327 mutex_unlock(&cfg->scan_sync);
5328 return err;
5329 }
5330
wl_android_bcnrecv_stop(struct net_device * ndev,uint reason)5331 int wl_android_bcnrecv_stop(struct net_device *ndev, uint reason)
5332 {
5333 s32 err = BCME_OK;
5334 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
5335
5336 mutex_lock(&cfg->bcn_sync);
5337 if ((cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) ||
5338 (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED)) {
5339 err = _wl_android_bcnrecv_stop(cfg, ndev, reason);
5340 }
5341 mutex_unlock(&cfg->bcn_sync);
5342 return err;
5343 }
5344
wl_android_bcnrecv_suspend(struct net_device * ndev)5345 int wl_android_bcnrecv_suspend(struct net_device *ndev)
5346 {
5347 s32 ret = BCME_OK;
5348 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
5349
5350 mutex_lock(&cfg->bcn_sync);
5351 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
5352 WL_INFORM_MEM(("bcnrecv suspend\n"));
5353 ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND);
5354 }
5355 mutex_unlock(&cfg->bcn_sync);
5356 return ret;
5357 }
5358
wl_android_bcnrecv_resume(struct net_device * ndev)5359 int wl_android_bcnrecv_resume(struct net_device *ndev)
5360 {
5361 s32 ret = BCME_OK;
5362 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
5363
5364 /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn
5365 * recv */
5366 mutex_lock(&cfg->scan_sync);
5367 mutex_lock(&cfg->bcn_sync);
5368 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) {
5369 WL_INFORM_MEM(("bcnrecv resume\n"));
5370 ret = _wl_android_bcnrecv_start(cfg, ndev, false);
5371 }
5372 mutex_unlock(&cfg->bcn_sync);
5373 mutex_unlock(&cfg->scan_sync);
5374 return ret;
5375 }
5376
5377 /* Beacon recv functionality code implementation */
wl_android_bcnrecv_config(struct net_device * ndev,char * cmd_argv,int total_len)5378 int wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv,
5379 int total_len)
5380 {
5381 struct bcm_cfg80211 *cfg = NULL;
5382 uint err = BCME_OK;
5383
5384 if (!ndev) {
5385 ANDROID_ERROR(("ndev is NULL\n"));
5386 return -EINVAL;
5387 }
5388
5389 cfg = wl_get_cfg(ndev);
5390 if (!cfg) {
5391 ANDROID_ERROR(("cfg is NULL\n"));
5392 return -EINVAL;
5393 }
5394
5395 /* sync commands from user space */
5396 mutex_lock(&cfg->usr_sync);
5397 if (strncmp(cmd_argv, "start", strlen("start")) == 0) {
5398 ANDROID_INFO(("BCNRECV start\n"));
5399 err = wl_android_bcnrecv_start(cfg, ndev);
5400 if (err != BCME_OK) {
5401 ANDROID_ERROR(
5402 ("Failed to process the start command, error:%d\n", err));
5403 goto exit;
5404 }
5405 } else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) {
5406 ANDROID_INFO(("BCNRECV stop\n"));
5407 err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER);
5408 if (err != BCME_OK) {
5409 ANDROID_ERROR(("Failed to stop the bcn recv, error:%d\n", err));
5410 goto exit;
5411 }
5412 } else {
5413 err = BCME_ERROR;
5414 }
5415 exit:
5416 mutex_unlock(&cfg->usr_sync);
5417 return err;
5418 }
5419 #endif /* WL_BCNRECV */
5420
5421 #ifdef WL_CAC_TS
5422 /* CAC TSPEC functionality code implementation */
wl_android_update_tsinfo(uint8 access_category,tspec_arg_t * tspec_arg)5423 static void wl_android_update_tsinfo(uint8 access_category,
5424 tspec_arg_t *tspec_arg)
5425 {
5426 uint8 tspec_id;
5427 /* Using direction as bidirectional by default */
5428 uint8 direction = TSPEC_BI_DIRECTION;
5429 /* Using U-APSD as the default power save mode */
5430 uint8 user_psb = TSPEC_UAPSD_PSB;
5431 uint8 ADDTS_AC2PRIO[0x4] = {PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_VI,
5432 PRIO_8021D_VO};
5433
5434 /* Map tspec_id from access category */
5435 tspec_id = ADDTS_AC2PRIO[access_category];
5436
5437 /* Update the tsinfo */
5438 tspec_arg->tsinfo.octets[0] = (uint8)(TSPEC_EDCA_ACCESS | direction |
5439 (tspec_id << TSPEC_TSINFO_TID_SHIFT));
5440 tspec_arg->tsinfo.octets[1] =
5441 (uint8)((tspec_id << TSPEC_TSINFO_PRIO_SHIFT) | user_psb);
5442 tspec_arg->tsinfo.octets[0x2] = 0x00;
5443 }
5444
wl_android_handle_cac_action(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * argv)5445 static s32 wl_android_handle_cac_action(struct bcm_cfg80211 *cfg,
5446 struct net_device *ndev, char *argv)
5447 {
5448 tspec_arg_t tspec_arg;
5449 s32 err = BCME_ERROR;
5450 u8 ts_cmd[12] = "cac_addts";
5451 uint8 access_category;
5452 s32 bssidx;
5453
5454 /* Following handling is done only for the primary interface */
5455 memset_s(&tspec_arg, sizeof(tspec_arg), 0, sizeof(tspec_arg));
5456 if (strncmp(argv, "addts", strlen("addts")) == 0) {
5457 tspec_arg.version = TSPEC_ARG_VERSION;
5458 tspec_arg.length = sizeof(tspec_arg_t) - (0x2 * sizeof(uint16));
5459 /* Read the params passed */
5460 sscanf(argv, "%*s %hhu %hu %hu", &access_category,
5461 &tspec_arg.nom_msdu_size, &tspec_arg.surplus_bw);
5462 if ((access_category > TSPEC_MAX_ACCESS_CATEGORY) ||
5463 ((tspec_arg.surplus_bw < TSPEC_MIN_SURPLUS_BW) ||
5464 (tspec_arg.surplus_bw > TSPEC_MAX_SURPLUS_BW)) ||
5465 (tspec_arg.nom_msdu_size > TSPEC_MAX_MSDU_SIZE)) {
5466 ANDROID_ERROR(
5467 ("Invalid params access_category %hhu nom_msdu_size %hu"
5468 " surplus BW %hu\n",
5469 access_category, tspec_arg.nom_msdu_size,
5470 tspec_arg.surplus_bw));
5471 return BCME_USAGE_ERROR;
5472 }
5473
5474 /* Update tsinfo */
5475 wl_android_update_tsinfo(access_category, &tspec_arg);
5476 /* Update other tspec parameters */
5477 tspec_arg.dialog_token = TSPEC_DEF_DIALOG_TOKEN;
5478 tspec_arg.mean_data_rate = TSPEC_DEF_MEAN_DATA_RATE;
5479 tspec_arg.min_phy_rate = TSPEC_DEF_MIN_PHY_RATE;
5480 } else if (strncmp(argv, "delts", strlen("delts")) == 0) {
5481 snprintf(ts_cmd, sizeof(ts_cmd), "cac_delts");
5482 tspec_arg.length = sizeof(tspec_arg_t) - (0x2 * sizeof(uint16));
5483 tspec_arg.version = TSPEC_ARG_VERSION;
5484 /* Read the params passed */
5485 sscanf(argv, "%*s %hhu", &access_category);
5486
5487 if (access_category > TSPEC_MAX_ACCESS_CATEGORY) {
5488 WL_INFORM_MEM(
5489 ("Invalide param, access_category %hhu\n", access_category));
5490 return BCME_USAGE_ERROR;
5491 }
5492 /* Update tsinfo */
5493 wl_android_update_tsinfo(access_category, &tspec_arg);
5494 }
5495
5496 if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
5497 ANDROID_ERROR(("Find index failed\n"));
5498 err = BCME_ERROR;
5499 return err;
5500 }
5501 err = wldev_iovar_setbuf_bsscfg(ndev, ts_cmd, &tspec_arg, sizeof(tspec_arg),
5502 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx,
5503 &cfg->ioctl_buf_sync);
5504 if (unlikely(err)) {
5505 ANDROID_ERROR(("%s error (%d)\n", ts_cmd, err));
5506 }
5507
5508 return err;
5509 }
5510
wl_android_cac_ts_config(struct net_device * ndev,char * cmd_argv,int total_len)5511 static s32 wl_android_cac_ts_config(struct net_device *ndev, char *cmd_argv,
5512 int total_len)
5513 {
5514 struct bcm_cfg80211 *cfg = NULL;
5515 s32 err = BCME_OK;
5516
5517 if (!ndev) {
5518 ANDROID_ERROR(("ndev is NULL\n"));
5519 return -EINVAL;
5520 }
5521
5522 cfg = wl_get_cfg(ndev);
5523 if (!cfg) {
5524 ANDROID_ERROR(("cfg is NULL\n"));
5525 return -EINVAL;
5526 }
5527
5528 /* Request supported only for primary interface */
5529 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
5530 ANDROID_ERROR(("Request on non-primary interface\n"));
5531 return -1;
5532 }
5533
5534 /* sync commands from user space */
5535 mutex_lock(&cfg->usr_sync);
5536 err = wl_android_handle_cac_action(cfg, ndev, cmd_argv);
5537 mutex_unlock(&cfg->usr_sync);
5538
5539 return err;
5540 }
5541 #endif /* WL_CAC_TS */
5542
5543 #ifdef WL_GET_CU
5544 /* Implementation to get channel usage from framework */
wl_android_get_channel_util(struct net_device * ndev,char * command,int total_len)5545 static s32 wl_android_get_channel_util(struct net_device *ndev, char *command,
5546 int total_len)
5547 {
5548 s32 bytes_written, err = 0;
5549 wl_bssload_t bssload;
5550 u8 smbuf[WLC_IOCTL_SMLEN];
5551 u8 chan_use_percentage = 0;
5552
5553 if ((err = wldev_iovar_getbuf(ndev, "bssload_report", NULL, 0, smbuf,
5554 WLC_IOCTL_SMLEN, NULL))) {
5555 ANDROID_ERROR(("Getting bssload report failed with err=%d \n", err));
5556 return err;
5557 }
5558
5559 (void)memcpy_s(&bssload, sizeof(wl_bssload_t), smbuf, sizeof(wl_bssload_t));
5560 /* Convert channel usage to percentage value */
5561 chan_use_percentage = (bssload.chan_util * 0x64) / 0xFF;
5562
5563 bytes_written =
5564 snprintf(command, total_len, "CU %hhu", chan_use_percentage);
5565 ANDROID_INFO(("Channel Utilization %u %u\n", bssload.chan_util,
5566 chan_use_percentage));
5567
5568 return bytes_written;
5569 }
5570 #endif /* WL_GET_CU */
5571
5572 #ifdef RTT_GEOFENCE_INTERVAL
5573 #if defined(RTT_SUPPORT) && defined(WL_NAN)
wl_android_set_rtt_geofence_interval(struct net_device * ndev,char * command)5574 static void wl_android_set_rtt_geofence_interval(struct net_device *ndev,
5575 char *command)
5576 {
5577 int rtt_interval = 0;
5578 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
5579 char *rtt_intp = command + strlen(CMD_GEOFENCE_INTERVAL) + 1;
5580
5581 rtt_interval = bcm_atoi(rtt_intp);
5582 dhd_rtt_set_geofence_rtt_interval(dhdp, rtt_interval);
5583 }
5584 #endif /* RTT_SUPPORT && WL_NAN */
5585 #endif /* RTT_GEOFENCE_INTERVAL */
5586
5587 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
wl_android_set_softap_elna_bypass(struct net_device * dev,char * command,int total_len)5588 int wl_android_set_softap_elna_bypass(struct net_device *dev, char *command,
5589 int total_len)
5590 {
5591 char *ifname = NULL;
5592 char *pos, *token;
5593 int err = BCME_OK;
5594 int enable = FALSE;
5595
5596 /*
5597 * STA/AP/GO I/F: DRIVER SET_SOFTAP_ELNA_BYPASS <ifname> <enable/disable>
5598 * the enable/disable format follows Samsung specific rules as following
5599 * Enable : 0
5600 * Disable :-1
5601 */
5602 pos = command;
5603
5604 /* drop command */
5605 token = bcmstrtok(&pos, " ", NULL);
5606
5607 /* get the interface name */
5608 token = bcmstrtok(&pos, " ", NULL);
5609 if (!token) {
5610 ANDROID_ERROR(
5611 ("%s: Invalid arguments about interface name\n", __FUNCTION__));
5612 return -EINVAL;
5613 }
5614 ifname = token;
5615
5616 /* get enable/disable flag */
5617 token = bcmstrtok(&pos, " ", NULL);
5618 if (!token) {
5619 ANDROID_ERROR(
5620 ("%s: Invalid arguments about Enable/Disable\n", __FUNCTION__));
5621 return -EINVAL;
5622 }
5623 enable = bcm_atoi(token);
5624
5625 CUSTOMER_HW4_EN_CONVERT(enable);
5626 err = wl_set_softap_elna_bypass(dev, ifname, enable);
5627 if (unlikely(err)) {
5628 ANDROID_ERROR(("%s: Failed to set ELNA Bypass of SoftAP mode, err=%d\n",
5629 __FUNCTION__, err));
5630 return err;
5631 }
5632
5633 return err;
5634 }
5635
wl_android_get_softap_elna_bypass(struct net_device * dev,char * command,int total_len)5636 int wl_android_get_softap_elna_bypass(struct net_device *dev, char *command,
5637 int total_len)
5638 {
5639 char *ifname = NULL;
5640 char *pos, *token;
5641 int err = BCME_OK;
5642 int bytes_written = 0;
5643 int softap_elnabypass = 0;
5644
5645 /*
5646 * STA/AP/GO I/F: DRIVER GET_SOFTAP_ELNA_BYPASS <ifname>
5647 */
5648 pos = command;
5649
5650 /* drop command */
5651 token = bcmstrtok(&pos, " ", NULL);
5652
5653 /* get the interface name */
5654 token = bcmstrtok(&pos, " ", NULL);
5655 if (!token) {
5656 ANDROID_ERROR(
5657 ("%s: Invalid arguments about interface name\n", __FUNCTION__));
5658 return -EINVAL;
5659 }
5660 ifname = token;
5661
5662 err = wl_get_softap_elna_bypass(dev, ifname, &softap_elnabypass);
5663 if (unlikely(err)) {
5664 ANDROID_ERROR(("%s: Failed to get ELNA Bypass of SoftAP mode, err=%d\n",
5665 __FUNCTION__, err));
5666 return err;
5667 } else {
5668 softap_elnabypass--; // Convert format to Customer HW4
5669 ANDROID_INFO(("%s: eLNA Bypass feature enable status is %d\n",
5670 __FUNCTION__, softap_elnabypass));
5671 bytes_written = snprintf(command, total_len, "%s %d",
5672 CMD_GET_SOFTAP_ELNA_BYPASS, softap_elnabypass);
5673 }
5674
5675 return bytes_written;
5676 }
5677 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
5678
5679 #ifdef WL_NAN
wl_android_get_nan_status(struct net_device * dev,char * command,int total_len)5680 int wl_android_get_nan_status(struct net_device *dev, char *command,
5681 int total_len)
5682 {
5683 int bytes_written = 0;
5684 int error = BCME_OK;
5685 wl_nan_conf_status_t nstatus;
5686
5687 error = wl_cfgnan_get_status(dev, &nstatus);
5688 if (error) {
5689 ANDROID_ERROR(("Failed to get nan status (%d)\n", error));
5690 return error;
5691 }
5692
5693 bytes_written = snprintf(
5694 command, total_len,
5695 "EN:%d Role:%d EM:%d CID:" MACF " NMI:" MACF " SC(2G):%d SC(5G):%d "
5696 "MR:" NMRSTR " AMR:" NMRSTR " IMR:" NMRSTR
5697 "HC:%d AMBTT:%04x TSF[%04x:%04x]\n",
5698 nstatus.enabled, nstatus.role, nstatus.election_mode,
5699 ETHERP_TO_MACF(&(nstatus.cid)), ETHERP_TO_MACF(&(nstatus.nmi)),
5700 nstatus.social_chans[0], nstatus.social_chans[1], NMR2STR(nstatus.mr),
5701 NMR2STR(nstatus.amr), NMR2STR(nstatus.imr), nstatus.hop_count,
5702 nstatus.ambtt, nstatus.cluster_tsf_h, nstatus.cluster_tsf_l);
5703 return bytes_written;
5704 }
5705 #endif /* WL_NAN */
5706
5707 #ifdef SUPPORT_NAN_RANGING_TEST_BW
5708 enum { NAN_RANGING_5G_BW20 = 1, NAN_RANGING_5G_BW40, NAN_RANGING_5G_BW80 };
5709
wl_nan_ranging_bw(struct net_device * net,int bw,char * command)5710 int wl_nan_ranging_bw(struct net_device *net, int bw, char *command)
5711 {
5712 int bytes_written, err = BCME_OK;
5713 u8 ioctl_buf[WLC_IOCTL_SMLEN];
5714 s32 val = 1;
5715 struct {
5716 u32 band;
5717 u32 bw_cap;
5718 } param = {0, 0};
5719
5720 if (bw < NAN_RANGING_5G_BW20 || bw > NAN_RANGING_5G_BW80) {
5721 ANDROID_ERROR(("Wrong BW cmd:%d, %s\n", bw, __FUNCTION__));
5722 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
5723 return bytes_written;
5724 }
5725
5726 switch (bw) {
5727 case NAN_RANGING_5G_BW20:
5728 ANDROID_ERROR(("NAN_RANGING 5G/BW20\n"));
5729 param.band = WLC_BAND_5G;
5730 param.bw_cap = 0x1;
5731 break;
5732 case NAN_RANGING_5G_BW40:
5733 ANDROID_ERROR(("NAN_RANGING 5G/BW40\n"));
5734 param.band = WLC_BAND_5G;
5735 param.bw_cap = 0x3;
5736 break;
5737 case NAN_RANGING_5G_BW80:
5738 ANDROID_ERROR(("NAN_RANGING 5G/BW80\n"));
5739 param.band = WLC_BAND_5G;
5740 param.bw_cap = 0x7;
5741 break;
5742 }
5743
5744 err = wldev_ioctl_set(net, WLC_DOWN, &val, sizeof(s32));
5745 if (err) {
5746 ANDROID_ERROR(("WLC_DOWN error %d\n", err));
5747 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
5748 } else {
5749 err = wldev_iovar_setbuf(net, "bw_cap", ¶m, sizeof(param),
5750 ioctl_buf, sizeof(ioctl_buf), NULL);
5751 if (err) {
5752 ANDROID_ERROR(("BW set failed\n"));
5753 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
5754 } else {
5755 ANDROID_ERROR(("BW set done\n"));
5756 bytes_written = scnprintf(command, sizeof("OK"), "OK");
5757 }
5758
5759 err = wldev_ioctl_set(net, WLC_UP, &val, sizeof(s32));
5760 if (err < 0) {
5761 ANDROID_ERROR(("WLC_UP error %d\n", err));
5762 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
5763 }
5764 }
5765 return bytes_written;
5766 }
5767 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
5768
wl_handle_private_cmd(struct net_device * net,char * command,u32 cmd_len)5769 int wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
5770 {
5771 int bytes_written = 0;
5772 android_wifi_priv_cmd priv_cmd;
5773
5774 bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
5775 priv_cmd.total_len = cmd_len;
5776
5777 if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
5778 ANDROID_INFO(("%s, Received regular START command\n", __FUNCTION__));
5779 #ifdef SUPPORT_DEEP_SLEEP
5780 trigger_deep_sleep = 1;
5781 #else
5782 #ifdef BT_OVER_SDIO
5783 bytes_written = dhd_net_bus_get(net);
5784 #else
5785 bytes_written = wl_android_wifi_on(net);
5786 #endif /* BT_OVER_SDIO */
5787 #endif /* SUPPORT_DEEP_SLEEP */
5788 } else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
5789 bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
5790 }
5791
5792 if (!g_wifi_on) {
5793 ANDROID_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
5794 __FUNCTION__, command));
5795 return 0;
5796 }
5797
5798 if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
5799 #ifdef SUPPORT_DEEP_SLEEP
5800 trigger_deep_sleep = 1;
5801 #else
5802 #ifdef BT_OVER_SDIO
5803 bytes_written = dhd_net_bus_put(net);
5804 #else
5805 bytes_written = wl_android_wifi_off(net, FALSE);
5806 #endif /* BT_OVER_SDIO */
5807 #endif /* SUPPORT_DEEP_SLEEP */
5808 }
5809 #ifdef WL_CFG80211
5810 else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
5811 wl_cfg80211_set_passive_scan(net, command);
5812 } else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) ==
5813 0) {
5814 wl_cfg80211_set_passive_scan(net, command);
5815 }
5816 #endif /* WL_CFG80211 */
5817 else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
5818 bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
5819 } else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
5820 bytes_written =
5821 wl_android_get_link_speed(net, command, priv_cmd.total_len);
5822 }
5823 #ifdef PKT_FILTER_SUPPORT
5824 else if (strnicmp(command, CMD_RXFILTER_START,
5825 strlen(CMD_RXFILTER_START)) == 0) {
5826 bytes_written = net_os_enable_packet_filter(net, 1);
5827 } else if (strnicmp(command, CMD_RXFILTER_STOP,
5828 strlen(CMD_RXFILTER_STOP)) == 0) {
5829 bytes_written = net_os_enable_packet_filter(net, 0);
5830 } else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) ==
5831 0) {
5832 int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
5833 bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
5834 } else if (strnicmp(command, CMD_RXFILTER_REMOVE,
5835 strlen(CMD_RXFILTER_REMOVE)) == 0) {
5836 int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
5837 bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
5838 }
5839 #endif /* PKT_FILTER_SUPPORT */
5840 else if (strnicmp(command, CMD_BTCOEXSCAN_START,
5841 strlen(CMD_BTCOEXSCAN_START)) == 0) {
5842 /* BTCOEXSCAN-START */
5843 } else if (strnicmp(command, CMD_BTCOEXSCAN_STOP,
5844 strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
5845 /* BTCOEXSCAN-STOP */
5846 } else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
5847 #ifdef WL_CFG80211
5848 void *dhdp = wl_cfg80211_get_dhdp(net);
5849 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
5850 #else
5851 #ifdef PKT_FILTER_SUPPORT
5852 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
5853 if (mode == 1) {
5854 net_os_enable_packet_filter(net, 0); /* DHCP starts */
5855 } else {
5856 net_os_enable_packet_filter(net, 1); /* DHCP ends */
5857 }
5858 #endif /* PKT_FILTER_SUPPORT */
5859 #endif /* WL_CFG80211 */
5860 } else if (strnicmp(command, CMD_SETSUSPENDOPT,
5861 strlen(CMD_SETSUSPENDOPT)) == 0) {
5862 bytes_written = wl_android_set_suspendopt(net, command);
5863 } else if (strnicmp(command, CMD_SETSUSPENDMODE,
5864 strlen(CMD_SETSUSPENDMODE)) == 0) {
5865 bytes_written = wl_android_set_suspendmode(net, command);
5866 } else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND,
5867 strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
5868 bytes_written = wl_android_set_bcn_li_dtim(net, command);
5869 } else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND,
5870 strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
5871 bytes_written = wl_android_set_max_dtim(net, command);
5872 }
5873 #ifdef DISABLE_DTIM_IN_SUSPEND
5874 else if (strnicmp(command, CMD_DISDTIM_IN_SUSPEND,
5875 strlen(CMD_DISDTIM_IN_SUSPEND)) == 0) {
5876 bytes_written = wl_android_set_disable_dtim_in_suspend(net, command);
5877 }
5878 #endif /* DISABLE_DTIM_IN_SUSPEND */
5879 #ifdef WL_CFG80211
5880 else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
5881 bytes_written = wl_android_set_band(net, command);
5882 }
5883 #endif /* WL_CFG80211 */
5884 else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
5885 bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
5886 }
5887 #ifdef WL_CFG80211
5888 else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
5889 bytes_written = wl_android_set_csa(net, command);
5890 } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
5891 bytes_written =
5892 wl_android_get_80211_mode(net, command, priv_cmd.total_len);
5893 } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
5894 bytes_written =
5895 wl_android_get_chanspec(net, command, priv_cmd.total_len);
5896 }
5897 #endif /* WL_CFG80211 */
5898 #ifndef CUSTOMER_SET_COUNTRY
5899 /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
5900 else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
5901 /*
5902 * Usage examples:
5903 * DRIVER COUNTRY US
5904 * DRIVER COUNTRY US/7
5905 */
5906 char *country_code = command + strlen(CMD_COUNTRY) + 1;
5907 char *rev_info_delim = country_code + 0x2; /* 2 bytes of country code */
5908 int revinfo = -1;
5909 #if defined(DHD_BLOB_EXISTENCE_CHECK)
5910 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
5911
5912 if (dhdp->is_blob) {
5913 revinfo = 0;
5914 } else
5915 #endif /* DHD_BLOB_EXISTENCE_CHECK */
5916 if ((rev_info_delim) &&
5917 (strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
5918 strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
5919 (rev_info_delim + 1)) {
5920 revinfo = bcm_atoi(rev_info_delim + 1);
5921 }
5922 #ifdef WL_CFG80211
5923 bytes_written = wl_cfg80211_set_country_code(net, country_code, true,
5924 true, revinfo);
5925 #else
5926 bytes_written =
5927 wldev_set_country(net, country_code, true, true, revinfo);
5928 #endif /* WL_CFG80211 */
5929 }
5930 #endif /* CUSTOMER_SET_COUNTRY */
5931 else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
5932 bytes_written =
5933 wl_android_get_datarate(net, command, priv_cmd.total_len);
5934 } else if (strnicmp(command, CMD_ASSOC_CLIENTS,
5935 strlen(CMD_ASSOC_CLIENTS)) == 0) {
5936 bytes_written =
5937 wl_android_get_assoclist(net, command, priv_cmd.total_len);
5938 }
5939
5940 #ifdef PNO_SUPPORT
5941 else if (strnicmp(command, CMD_PNOSSIDCLR_SET,
5942 strlen(CMD_PNOSSIDCLR_SET)) == 0) {
5943 bytes_written = dhd_dev_pno_stop_for_ssid(net);
5944 }
5945 #ifndef WL_SCHED_SCAN
5946 else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) ==
5947 0) {
5948 bytes_written =
5949 wl_android_set_pno_setup(net, command, priv_cmd.total_len);
5950 }
5951 #endif /* !WL_SCHED_SCAN */
5952 else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) ==
5953 0) {
5954 int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
5955 bytes_written = (enable) ? 0 : dhd_dev_pno_stop_for_ssid(net);
5956 } else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) ==
5957 0) {
5958 bytes_written =
5959 wls_parse_batching_cmd(net, command, priv_cmd.total_len);
5960 }
5961 #endif /* PNO_SUPPORT */
5962 else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) ==
5963 0) {
5964 bytes_written =
5965 wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
5966 } else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) ==
5967 0) {
5968 int skip = strlen(CMD_P2P_SET_NOA) + 1;
5969 bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
5970 priv_cmd.total_len - skip);
5971 }
5972 #ifdef P2P_LISTEN_OFFLOADING
5973 else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD,
5974 strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
5975 u8 *sub_command = strchr(command, ' ');
5976 bytes_written = wl_cfg80211_p2plo_offload(
5977 net, command, sub_command, sub_command ? strlen(sub_command) : 0);
5978 }
5979 #endif /* P2P_LISTEN_OFFLOADING */
5980 #if !defined WL_ENABLE_P2P_IF
5981 else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
5982 bytes_written =
5983 wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
5984 }
5985 #endif /* WL_ENABLE_P2P_IF */
5986 else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
5987 int skip = strlen(CMD_P2P_SET_PS) + 1;
5988 bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
5989 priv_cmd.total_len - skip);
5990 } else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
5991 int skip = strlen(CMD_P2P_ECSA) + 1;
5992 bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
5993 priv_cmd.total_len - skip);
5994 } else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
5995 int skip = strlen(CMD_P2P_INC_BW) + 1;
5996 bytes_written = wl_cfg80211_increase_p2p_bw(net, command + skip,
5997 priv_cmd.total_len - skip);
5998 }
5999 #ifdef WL_CFG80211
6000 else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
6001 strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
6002 int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
6003 bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
6004 priv_cmd.total_len - skip,
6005 *(command + skip - 0x2) - '0');
6006 }
6007 #ifdef WLFBT
6008 else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
6009 bytes_written =
6010 wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
6011 }
6012 #endif /* WLFBT */
6013 #endif /* WL_CFG80211 */
6014 #if defined(WL_SUPPORT_AUTO_CHANNEL)
6015 else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
6016 strlen(CMD_GET_BEST_CHANNELS)) == 0) {
6017 bytes_written =
6018 wl_cfg80211_get_best_channels(net, command, priv_cmd.total_len);
6019 }
6020 #endif /* WL_SUPPORT_AUTO_CHANNEL */
6021 #if defined(WL_SUPPORT_AUTO_CHANNEL)
6022 else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
6023 strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
6024 int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
6025 bytes_written = wl_android_set_auto_channel(
6026 net, (const char *)command + skip, command, priv_cmd.total_len);
6027 }
6028 #endif /* WL_SUPPORT_AUTO_CHANNEL */
6029 else if (strnicmp(command, CMD_HAPD_MAC_FILTER,
6030 strlen(CMD_HAPD_MAC_FILTER)) == 0) {
6031 int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
6032 wl_android_set_mac_address_filter(net, command + skip);
6033 } else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) ==
6034 0) {
6035 bytes_written = wl_android_set_roam_mode(net, command);
6036 }
6037 #if defined(BCMFW_ROAM_ENABLE)
6038 else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) ==
6039 0) {
6040 bytes_written =
6041 wl_android_set_roampref(net, command, priv_cmd.total_len);
6042 }
6043 #endif /* BCMFW_ROAM_ENABLE */
6044 #ifdef WL_CFG80211
6045 else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
6046 bytes_written = wl_android_set_miracast(net, command);
6047 else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA,
6048 strlen(CMD_SETIBSSBEACONOUIDATA)) == 0) {
6049 bytes_written = wl_android_set_ibss_beacon_ouidata(net, command,
6050 priv_cmd.total_len);
6051 }
6052 #endif /* WL_CFG80211 */
6053 else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
6054 int skip = strlen(CMD_KEEP_ALIVE) + 1;
6055 bytes_written = wl_keep_alive_set(net, command + skip);
6056 }
6057 #ifdef WL_CFG80211
6058 else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) ==
6059 0) {
6060 int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
6061 bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
6062 } else if (strnicmp(command, CMD_INTERFACE_CREATE,
6063 strlen(CMD_INTERFACE_CREATE)) == 0) {
6064 char *name = (command + strlen(CMD_INTERFACE_CREATE) + 1);
6065 ANDROID_INFO(("Creating %s interface\n", name));
6066 if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA, name,
6067 NULL) == NULL) {
6068 bytes_written = -ENODEV;
6069 } else {
6070 /* Return success */
6071 bytes_written = 0;
6072 }
6073 } else if (strnicmp(command, CMD_INTERFACE_DELETE,
6074 strlen(CMD_INTERFACE_DELETE)) == 0) {
6075 char *name = (command + strlen(CMD_INTERFACE_DELETE) + 1);
6076 ANDROID_INFO(("Deleteing %s interface\n", name));
6077 bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
6078 }
6079 #endif /* WL_CFG80211 */
6080 else if (strnicmp(command, CMD_GET_LINK_STATUS,
6081 strlen(CMD_GET_LINK_STATUS)) == 0) {
6082 bytes_written =
6083 wl_android_get_link_status(net, command, priv_cmd.total_len);
6084 }
6085 #ifdef P2PRESP_WFDIE_SRC
6086 else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
6087 strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
6088 int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
6089 bytes_written = wl_android_set_wfdie_resp(net, mode);
6090 } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
6091 strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
6092 bytes_written =
6093 wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
6094 }
6095 #endif /* P2PRESP_WFDIE_SRC */
6096 #ifdef WL_CFG80211
6097 else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
6098 char *data = (command + strlen(CMD_DFS_AP_MOVE) + 1);
6099 bytes_written =
6100 wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
6101 }
6102 #endif /* WL_CFG80211 */
6103 #ifdef SET_RPS_CPUS
6104 else if (strnicmp(command, CMD_RPSMODE, strlen(CMD_RPSMODE)) == 0) {
6105 bytes_written = wl_android_set_rps_cpus(net, command);
6106 }
6107 #endif /* SET_RPS_CPUS */
6108 #ifdef WLWFDS
6109 else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) ==
6110 0) {
6111 bytes_written = wl_android_set_wfds_hash(net, command, 1);
6112 } else if (strnicmp(command, CMD_DEL_WFDS_HASH,
6113 strlen(CMD_DEL_WFDS_HASH)) == 0) {
6114 bytes_written = wl_android_set_wfds_hash(net, command, 0);
6115 }
6116 #endif /* WLWFDS */
6117 #ifdef BT_WIFI_HANDOVER
6118 else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) ==
6119 0) {
6120 bytes_written = wl_tbow_teardown(net);
6121 }
6122 #endif /* BT_WIFI_HANDOVER */
6123 else if (strnicmp(command, CMD_MURX_BFE_CAP, strlen(CMD_MURX_BFE_CAP)) ==
6124 0) {
6125 #if defined(WL_MURX) && defined(WL_CFG80211)
6126 uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
6127 bytes_written = wl_android_murx_bfe_cap(net, val);
6128 #else
6129 return BCME_UNSUPPORTED;
6130 #endif /* WL_MURX */
6131 }
6132 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
6133 else if (strnicmp(command, CMD_GET_AP_BASICRATE,
6134 strlen(CMD_GET_AP_BASICRATE)) == 0) {
6135 bytes_written =
6136 wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
6137 } else if (strnicmp(command, CMD_SET_AP_BEACONRATE,
6138 strlen(CMD_SET_AP_BEACONRATE)) == 0) {
6139 bytes_written = wl_android_set_ap_beaconrate(net, command);
6140 }
6141 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
6142 #ifdef SUPPORT_AP_RADIO_PWRSAVE
6143 else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS,
6144 strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
6145 bytes_written =
6146 wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
6147 } else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
6148 bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
6149 } else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
6150 bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
6151 }
6152 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
6153 #ifdef SUPPORT_AP_SUSPEND
6154 else if (strnicmp(command, CMD_SET_AP_SUSPEND,
6155 strlen(CMD_SET_AP_SUSPEND)) == 0) {
6156 bytes_written =
6157 wl_android_set_ap_suspend(net, command, priv_cmd.total_len);
6158 }
6159 #endif /* SUPPORT_AP_SUSPEND */
6160 #ifdef SUPPORT_AP_BWCTRL
6161 else if (strnicmp(command, CMD_SET_AP_BW, strlen(CMD_SET_AP_BW)) == 0) {
6162 bytes_written = wl_android_set_ap_bw(net, command, priv_cmd.total_len);
6163 } else if (strnicmp(command, CMD_GET_AP_BW, strlen(CMD_GET_AP_BW)) == 0) {
6164 bytes_written = wl_android_get_ap_bw(net, command, priv_cmd.total_len);
6165 }
6166 #endif /* SUPPORT_AP_BWCTRL */
6167 #ifdef SUPPORT_RSSI_SUM_REPORT
6168 else if (strnicmp(command, CMD_SET_RSSI_LOGGING,
6169 strlen(CMD_SET_RSSI_LOGGING)) == 0) {
6170 bytes_written =
6171 wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
6172 } else if (strnicmp(command, CMD_GET_RSSI_LOGGING,
6173 strlen(CMD_GET_RSSI_LOGGING)) == 0) {
6174 bytes_written =
6175 wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
6176 } else if (strnicmp(command, CMD_GET_RSSI_PER_ANT,
6177 strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
6178 bytes_written =
6179 wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
6180 }
6181 #endif /* SUPPORT_RSSI_SUM_REPORT */
6182 #ifdef WL_NATOE
6183 else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
6184 bytes_written =
6185 wl_android_process_natoe_cmd(net, command, priv_cmd.total_len);
6186 }
6187 #endif /* WL_NATOE */
6188 #ifdef CONNECTION_STATISTICS
6189 else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
6190 strlen(CMD_GET_CONNECTION_STATS)) == 0) {
6191 bytes_written =
6192 wl_android_get_connection_stats(net, command, priv_cmd.total_len);
6193 }
6194 #endif // endif
6195 #ifdef DHD_LOG_DUMP
6196 else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
6197 strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
6198 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
6199 /* check whether it has more command */
6200 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
6201 /* compare unwanted/disconnected command */
6202 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
6203 SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
6204 dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
6205 } else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
6206 SUBCMD_DISCONNECTED,
6207 strlen(SUBCMD_DISCONNECTED)) == 0) {
6208 dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
6209 } else {
6210 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
6211 }
6212 } else {
6213 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
6214 }
6215 }
6216 #endif /* DHD_LOG_DUMP */
6217 #ifdef DHD_STATUS_LOGGING
6218 else if (strnicmp(command, CMD_DUMP_STATUS_LOG,
6219 strlen(CMD_DUMP_STATUS_LOG)) == 0) {
6220 dhd_statlog_dump_scr(wl_cfg80211_get_dhdp(net));
6221 } else if (strnicmp(command, CMD_QUERY_STATUS_LOG,
6222 strlen(CMD_QUERY_STATUS_LOG)) == 0) {
6223 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
6224 bytes_written = dhd_statlog_query(dhdp, command, priv_cmd.total_len);
6225 }
6226 #endif /* DHD_STATUS_LOGGING */
6227 #ifdef SET_PCIE_IRQ_CPU_CORE
6228 else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) ==
6229 0) {
6230 int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
6231 wl_android_set_irq_cpucore(net, affinity_cmd);
6232 }
6233 #endif /* SET_PCIE_IRQ_CPU_CORE */
6234 #ifdef SUPPORT_LQCM
6235 else if (strnicmp(command, CMD_SET_LQCM_ENABLE,
6236 strlen(CMD_SET_LQCM_ENABLE)) == 0) {
6237 int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
6238 bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
6239 } else if (strnicmp(command, CMD_GET_LQCM_REPORT,
6240 strlen(CMD_GET_LQCM_REPORT)) == 0) {
6241 bytes_written =
6242 wl_android_get_lqcm_report(net, command, priv_cmd.total_len);
6243 }
6244 #endif // endif
6245 else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
6246 bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
6247 }
6248 #ifdef WL_CFG80211
6249 else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) ==
6250 0) {
6251 int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
6252 bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
6253 }
6254 #endif /* WL_CFG80211 */
6255 #ifdef WL_BCNRECV
6256 else if (strnicmp(command, CMD_BEACON_RECV, strlen(CMD_BEACON_RECV)) == 0) {
6257 char *data = (command + strlen(CMD_BEACON_RECV) + 1);
6258 bytes_written =
6259 wl_android_bcnrecv_config(net, data, priv_cmd.total_len);
6260 }
6261 #endif /* WL_BCNRECV */
6262 #ifdef WL_MBO
6263 else if (strnicmp(command, CMD_MBO, strlen(CMD_MBO)) == 0) {
6264 bytes_written =
6265 wl_android_process_mbo_cmd(net, command, priv_cmd.total_len);
6266 }
6267 #endif /* WL_MBO */
6268 #ifdef WL_CAC_TS
6269 else if (strnicmp(command, CMD_CAC_TSPEC, strlen(CMD_CAC_TSPEC)) == 0) {
6270 char *data = (command + strlen(CMD_CAC_TSPEC) + 1);
6271 bytes_written = wl_android_cac_ts_config(net, data, priv_cmd.total_len);
6272 }
6273 #endif /* WL_CAC_TS */
6274 #ifdef WL_GET_CU
6275 else if (strnicmp(command, CMD_GET_CHAN_UTIL, strlen(CMD_GET_CHAN_UTIL)) ==
6276 0) {
6277 bytes_written =
6278 wl_android_get_channel_util(net, command, priv_cmd.total_len);
6279 }
6280 #endif /* WL_GET_CU */
6281 #ifdef RTT_GEOFENCE_INTERVAL
6282 #if defined(RTT_SUPPORT) && defined(WL_NAN)
6283 else if (strnicmp(command, CMD_GEOFENCE_INTERVAL,
6284 strlen(CMD_GEOFENCE_INTERVAL)) == 0) {
6285 (void)wl_android_set_rtt_geofence_interval(net, command);
6286 }
6287 #endif /* RTT_SUPPORT && WL_NAN */
6288 #endif /* RTT_GEOFENCE_INTERVAL */
6289 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
6290 else if (strnicmp(command, CMD_SET_SOFTAP_ELNA_BYPASS,
6291 strlen(CMD_SET_SOFTAP_ELNA_BYPASS)) == 0) {
6292 bytes_written =
6293 wl_android_set_softap_elna_bypass(net, command, priv_cmd.total_len);
6294 } else if (strnicmp(command, CMD_GET_SOFTAP_ELNA_BYPASS,
6295 strlen(CMD_GET_SOFTAP_ELNA_BYPASS)) == 0) {
6296 bytes_written =
6297 wl_android_get_softap_elna_bypass(net, command, priv_cmd.total_len);
6298 }
6299 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
6300 #ifdef WL_NAN
6301 else if (strnicmp(command, CMD_GET_NAN_STATUS,
6302 strlen(CMD_GET_NAN_STATUS)) == 0) {
6303 bytes_written =
6304 wl_android_get_nan_status(net, command, priv_cmd.total_len);
6305 }
6306 #endif /* WL_NAN */
6307 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
6308 else if (strnicmp(command, CMD_NAN_RANGING_SET_BW,
6309 strlen(CMD_NAN_RANGING_SET_BW)) == 0) {
6310 int bw_cmd = *(command + strlen(CMD_NAN_RANGING_SET_BW) + 1) - '0';
6311 bytes_written = wl_nan_ranging_bw(net, bw_cmd, command);
6312 }
6313 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
6314 else if (wl_android_ext_priv_cmd(net, command, priv_cmd.total_len,
6315 &bytes_written) == 0) {
6316 } else {
6317 ANDROID_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
6318 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
6319 }
6320
6321 return bytes_written;
6322 }
6323
6324 /*
6325 * ENABLE_INSMOD_NO_FW_LOAD X O O O
6326 * ENABLE_INSMOD_NO_POWER_OFF X X O O
6327 * NO_POWER_OFF_AFTER_OPEN X X X O
6328 * after insmod H L H H
6329 * wlan0 down H L L H
6330 * fw trap trigger wlan0 down H L L L
6331 */
6332
wl_android_init(void)6333 int wl_android_init(void)
6334 {
6335 int ret = 0;
6336
6337 #ifdef ENABLE_INSMOD_NO_POWER_OFF
6338 dhd_download_fw_on_driverload = TRUE;
6339 #elif defined(ENABLE_INSMOD_NO_FW_LOAD) || defined(BUS_POWER_RESTORE)
6340 dhd_download_fw_on_driverload = FALSE;
6341 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
6342 if (!iface_name[0]) {
6343 bzero(iface_name, IFNAMSIZ);
6344 bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
6345 }
6346
6347 #ifdef WL_GENL
6348 wl_genl_init();
6349 #endif // endif
6350 #ifdef WL_RELMCAST
6351 wl_netlink_init();
6352 #endif /* WL_RELMCAST */
6353
6354 return ret;
6355 }
6356
wl_android_exit(void)6357 int wl_android_exit(void)
6358 {
6359 int ret = 0;
6360 struct io_cfg *cur, *q;
6361
6362 #ifdef WL_GENL
6363 wl_genl_deinit();
6364 #endif /* WL_GENL */
6365 #ifdef WL_RELMCAST
6366 wl_netlink_deinit();
6367 #endif /* WL_RELMCAST */
6368
6369 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
6370 list_for_each_entry_safe(cur, q, &miracast_resume_list, list)
6371 {
6372 GCC_DIAGNOSTIC_POP();
6373 list_del(&cur->list);
6374 kfree(cur);
6375 }
6376
6377 return ret;
6378 }
6379
wl_android_post_init(void)6380 void wl_android_post_init(void)
6381 {
6382 #ifdef ENABLE_4335BT_WAR
6383 bcm_bt_unlock(lock_cookie_wifi);
6384 printk("%s: btlock released\n", __FUNCTION__);
6385 #endif /* ENABLE_4335BT_WAR */
6386
6387 if (!dhd_download_fw_on_driverload) {
6388 g_wifi_on = FALSE;
6389 }
6390 }
6391
6392 #ifdef WL_GENL
6393 /* Generic Netlink Initializaiton */
wl_genl_init(void)6394 static int wl_genl_init(void)
6395 {
6396 int ret;
6397
6398 ANDROID_INFO(("GEN Netlink Init\n\n"));
6399
6400 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
6401 /* register new family */
6402 ret = genl_register_family(&wl_genl_family);
6403 if (ret != 0) {
6404 goto failure;
6405 }
6406
6407 /* register functions (commands) of the new family */
6408 ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
6409 if (ret != 0) {
6410 ANDROID_ERROR(("register ops failed: %i\n", ret));
6411 genl_unregister_family(&wl_genl_family);
6412 goto failure;
6413 }
6414
6415 ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
6416 #else
6417 ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops,
6418 wl_genl_mcast);
6419 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
6420 if (ret != 0) {
6421 ANDROID_ERROR(("register mc_group failed: %i\n", ret));
6422 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
6423 genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
6424 #endif // endif
6425 genl_unregister_family(&wl_genl_family);
6426 goto failure;
6427 }
6428
6429 return 0;
6430
6431 failure:
6432 ANDROID_ERROR(("Registering Netlink failed!!\n"));
6433 return -1;
6434 }
6435
6436 /* Generic netlink deinit */
wl_genl_deinit(void)6437 static int wl_genl_deinit(void)
6438 {
6439 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
6440 if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0) {
6441 ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
6442 }
6443 #endif // endif
6444 if (genl_unregister_family(&wl_genl_family) < 0) {
6445 ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
6446 }
6447
6448 return 0;
6449 }
6450
wl_event_to_bcm_event(u16 event_type)6451 s32 wl_event_to_bcm_event(u16 event_type)
6452 {
6453 u16 event = -1;
6454
6455 switch (event_type) {
6456 case WLC_E_SERVICE_FOUND:
6457 event = BCM_E_SVC_FOUND;
6458 break;
6459 case WLC_E_P2PO_ADD_DEVICE:
6460 event = BCM_E_DEV_FOUND;
6461 break;
6462 case WLC_E_P2PO_DEL_DEVICE:
6463 event = BCM_E_DEV_LOST;
6464 break;
6465 /* Above events are supported from BCM Supp ver 47 Onwards */
6466 #ifdef BT_WIFI_HANDOVER
6467 case WLC_E_BT_WIFI_HANDOVER_REQ:
6468 event = BCM_E_DEV_BT_WIFI_HO_REQ;
6469 break;
6470 #endif /* BT_WIFI_HANDOVER */
6471
6472 default:
6473 ANDROID_ERROR(("Event not supported\n"));
6474 }
6475
6476 return event;
6477 }
6478
wl_genl_send_msg(struct net_device * ndev,u32 event_type,const u8 * buf,u16 len,u8 * subhdr,u16 subhdr_len)6479 s32 wl_genl_send_msg(struct net_device *ndev, u32 event_type, const u8 *buf,
6480 u16 len, u8 *subhdr, u16 subhdr_len)
6481 {
6482 int ret = 0;
6483 struct sk_buff *skb;
6484 void *msg;
6485 u32 attr_type = 0;
6486 bcm_event_hdr_t *hdr = NULL;
6487 int mcast = 1; /* By default sent as mutlicast type */
6488 int pid = 0;
6489 u8 *ptr = NULL, *p = NULL;
6490 u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
6491 u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
6492 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6493
6494 ANDROID_INFO(("Enter \n"));
6495
6496 /* Decide between STRING event and Data event */
6497 if (event_type == 0) {
6498 attr_type = BCM_GENL_ATTR_STRING;
6499 } else {
6500 attr_type = BCM_GENL_ATTR_MSG;
6501 }
6502
6503 skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
6504 if (skb == NULL) {
6505 ret = -ENOMEM;
6506 goto out;
6507 }
6508
6509 msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
6510 if (msg == NULL) {
6511 ret = -ENOMEM;
6512 goto out;
6513 }
6514
6515 if (attr_type == BCM_GENL_ATTR_STRING) {
6516 /* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
6517 * make sure it is null terminated
6518 */
6519 if (subhdr || subhdr_len) {
6520 ANDROID_ERROR(("No sub hdr support for the ATTR STRING type \n"));
6521 ret = -EINVAL;
6522 goto out;
6523 }
6524
6525 ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
6526 if (ret != 0) {
6527 ANDROID_ERROR(("nla_put_string failed\n"));
6528 goto out;
6529 }
6530 } else {
6531 /* ATTR_MSG */
6532
6533 /* Create a single buffer for all */
6534 p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
6535 if (!ptr) {
6536 ret = -ENOMEM;
6537 ANDROID_ERROR(("ENOMEM!!\n"));
6538 goto out;
6539 }
6540
6541 /* Include the bcm event header */
6542 hdr = (bcm_event_hdr_t *)ptr;
6543 hdr->event_type = wl_event_to_bcm_event(event_type);
6544 hdr->len = len + subhdr_len;
6545 ptr += sizeof(bcm_event_hdr_t);
6546
6547 /* Copy subhdr (if any) */
6548 if (subhdr && subhdr_len) {
6549 memcpy(ptr, subhdr, subhdr_len);
6550 ptr += subhdr_len;
6551 }
6552
6553 /* Copy the data */
6554 if (buf && len) {
6555 memcpy(ptr, buf, len);
6556 }
6557
6558 ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
6559 if (ret != 0) {
6560 ANDROID_ERROR(("nla_put_string failed\n"));
6561 goto out;
6562 }
6563 }
6564
6565 if (mcast) {
6566 int err = 0;
6567 /* finalize the message */
6568 genlmsg_end(skb, msg);
6569
6570 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
6571 if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
6572 #else
6573 if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) <
6574 0)
6575 #endif // endif
6576 ANDROID_ERROR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
6577 attr_type, err));
6578 else {
6579 ANDROID_INFO(
6580 ("Multicast msg sent successfully. attr_type:%d len:%d \n",
6581 attr_type, tot_len));
6582 }
6583 } else {
6584 NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
6585
6586 /* finalize the message */
6587 genlmsg_end(skb, msg);
6588
6589 /* send the message back */
6590 if (genlmsg_unicast(&init_net, skb, pid) < 0) {
6591 ANDROID_ERROR(("genlmsg_unicast failed\n"));
6592 }
6593 }
6594
6595 out:
6596 if (p) {
6597 MFREE(cfg->osh, p, tot_len);
6598 }
6599 if (ret) {
6600 nlmsg_free(skb);
6601 }
6602
6603 return ret;
6604 }
6605
wl_genl_handle_msg(struct sk_buff * skb,struct genl_info * info)6606 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info)
6607 {
6608 struct nlattr *na;
6609 u8 *data = NULL;
6610
6611 ANDROID_INFO(("Enter \n"));
6612
6613 if (info == NULL) {
6614 return -EINVAL;
6615 }
6616
6617 na = info->attrs[BCM_GENL_ATTR_MSG];
6618 if (!na) {
6619 ANDROID_ERROR(("nlattribute NULL\n"));
6620 return -EINVAL;
6621 }
6622
6623 data = (char *)nla_data(na);
6624 if (!data) {
6625 ANDROID_ERROR(("Invalid data\n"));
6626 return -EINVAL;
6627 } else {
6628 /* Handle the data */
6629 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || \
6630 defined(WL_COMPAT_WIRELESS)
6631 ANDROID_INFO(
6632 ("%s: Data received from pid (%d) \n", __func__, info->snd_pid));
6633 #else
6634 ANDROID_INFO(
6635 ("%s: Data received from pid (%d) \n", __func__, info->snd_portid));
6636 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
6637 }
6638
6639 return 0;
6640 }
6641 #endif /* WL_GENL */
6642
wl_fatal_error(void * wl,int rc)6643 int wl_fatal_error(void *wl, int rc)
6644 {
6645 return FALSE;
6646 }
6647
6648 #if defined(BT_OVER_SDIO)
wl_android_set_wifi_on_flag(bool enable)6649 void wl_android_set_wifi_on_flag(bool enable)
6650 {
6651 g_wifi_on = enable;
6652 }
6653 #endif /* BT_OVER_SDIO */
6654
6655 #ifdef WL_STATIC_IF
6656 #include <dhd_linux_priv.h>
wl_cfg80211_register_static_if(struct bcm_cfg80211 * cfg,u16 iftype,char * ifname,int static_ifidx)6657 struct net_device *wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg,
6658 u16 iftype, char *ifname,
6659 int static_ifidx)
6660 {
6661 #if defined(CUSTOM_MULTI_MAC) || defined(WL_EXT_IAPSTA)
6662 dhd_pub_t *dhd = cfg->pub;
6663 #endif
6664 struct net_device *ndev;
6665 struct wireless_dev *wdev = NULL;
6666 int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */
6667 u8 mac_addr[ETH_ALEN];
6668 struct net_device *primary_ndev;
6669 #ifdef DHD_USE_RANDMAC
6670 struct ether_addr ea_addr;
6671 #endif /* DHD_USE_RANDMAC */
6672 #ifdef CUSTOM_MULTI_MAC
6673 char hw_ether[62];
6674 #endif
6675
6676 WL_INFORM_MEM(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype));
6677
6678 if (!cfg) {
6679 ANDROID_ERROR(("cfg null\n"));
6680 return NULL;
6681 }
6682 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
6683
6684 ifidx += static_ifidx;
6685 #ifdef DHD_USE_RANDMAC
6686 dhd_generate_mac_addr(&ea_addr);
6687 (void)memcpy_s(mac_addr, ETH_ALEN, ea_addr.octet, ETH_ALEN);
6688 #else
6689 #if defined(CUSTOM_MULTI_MAC)
6690 if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether,
6691 static_ifidx + 1)) {
6692 (void)memcpy_s(mac_addr, ETH_ALEN, hw_ether, ETH_ALEN);
6693 } else
6694 #endif
6695 {
6696 /* Use primary mac with locally admin bit set */
6697 (void)memcpy_s(mac_addr, ETH_ALEN, primary_ndev->dev_addr, ETH_ALEN);
6698 mac_addr[0] |= 0x02;
6699 #ifdef WL_EXT_IAPSTA
6700 wl_ext_iapsta_get_vif_macaddr(dhd, static_ifidx + 1, mac_addr);
6701 #endif
6702 }
6703 #endif /* DHD_USE_RANDMAC */
6704
6705 ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr, WL_BSSIDX_MAX,
6706 NULL);
6707 if (unlikely(!ndev)) {
6708 ANDROID_ERROR(("Failed to allocate static_if\n"));
6709 goto fail;
6710 }
6711 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
6712 if (unlikely(!wdev)) {
6713 ANDROID_ERROR(("Failed to allocate wdev for static_if\n"));
6714 goto fail;
6715 }
6716
6717 wdev->wiphy = cfg->wdev->wiphy;
6718 wdev->iftype = iftype;
6719
6720 ndev->ieee80211_ptr = wdev;
6721 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
6722 wdev->netdev = ndev;
6723
6724 if (wl_cfg80211_register_if(cfg, ifidx, ndev, TRUE) != BCME_OK) {
6725 ANDROID_ERROR(("ndev registration failed!\n"));
6726 goto fail;
6727 }
6728
6729 cfg->static_ndev[static_ifidx] = ndev;
6730 cfg->static_ndev_state[static_ifidx] = NDEV_STATE_OS_IF_CREATED;
6731 wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
6732 ifname, NDEV_STATE_OS_IF_CREATED);
6733 WL_INFORM_MEM(("Static I/F (%s) Registered\n", ndev->name));
6734 return ndev;
6735
6736 fail:
6737 wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
6738 return NULL;
6739 }
6740
wl_cfg80211_unregister_static_if(struct bcm_cfg80211 * cfg)6741 void wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
6742 {
6743 int i;
6744
6745 WL_INFORM_MEM(("[STATIC_IF] Enter\n"));
6746 if (!cfg) {
6747 ANDROID_ERROR(("invalid input\n"));
6748 return;
6749 }
6750
6751 for (i = 0; i < DHD_MAX_STATIC_IFS; i++) {
6752 if (cfg->static_ndev[i]) {
6753 unregister_netdev(cfg->static_ndev[i]);
6754 }
6755 }
6756 }
6757
wl_cfg80211_static_if_open(struct net_device * net)6758 s32 wl_cfg80211_static_if_open(struct net_device *net)
6759 {
6760 struct wireless_dev *wdev = NULL;
6761 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
6762 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
6763 u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
6764 u16 wl_iftype, wl_mode;
6765 #ifdef CUSTOM_MULTI_MAC
6766 dhd_pub_t *dhd = dhd_get_pub(net);
6767 char hw_ether[62];
6768 #endif
6769 int static_ifidx;
6770
6771 WL_INFORM_MEM(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net,
6772 net->ieee80211_ptr));
6773 static_ifidx = wl_cfg80211_static_ifidx(cfg, net);
6774 ASSERT(static_ifidx >= 0);
6775
6776 if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) < 0) {
6777 return BCME_ERROR;
6778 }
6779 if (cfg->static_ndev_state[static_ifidx] != NDEV_STATE_FW_IF_CREATED) {
6780 #ifdef CUSTOM_MULTI_MAC
6781 if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether,
6782 static_ifidx + 1)) {
6783 memcpy(net->dev_addr, hw_ether, ETHER_ADDR_LEN);
6784 }
6785 #endif
6786 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name,
6787 net->dev_addr);
6788 if (!wdev) {
6789 ANDROID_ERROR(("[STATIC_IF] wdev is NULL, can't proceed\n"));
6790 return BCME_ERROR;
6791 }
6792 } else {
6793 WL_INFORM_MEM(("Fw IF for static netdev already created\n"));
6794 }
6795
6796 return BCME_OK;
6797 }
6798
wl_cfg80211_static_if_close(struct net_device * net)6799 s32 wl_cfg80211_static_if_close(struct net_device *net)
6800 {
6801 int ret = BCME_OK;
6802 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
6803 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
6804 int static_ifidx;
6805
6806 static_ifidx = wl_cfg80211_static_ifidx(cfg, net);
6807 if (cfg->static_ndev_state[static_ifidx] == NDEV_STATE_FW_IF_CREATED) {
6808 if (mutex_is_locked(&cfg->if_sync) == TRUE) {
6809 ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr,
6810 net->name);
6811 } else {
6812 ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr,
6813 net->name);
6814 }
6815
6816 if (unlikely(ret)) {
6817 ANDROID_ERROR(("Del iface failed for static_if %d\n", ret));
6818 }
6819 }
6820
6821 return ret;
6822 }
wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 * cfg,wl_if_event_info * event,u8 * addr,s32 iface_type,int static_ifidx)6823 struct net_device *wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
6824 wl_if_event_info *event,
6825 u8 *addr, s32 iface_type,
6826 int static_ifidx)
6827 {
6828 struct net_device *new_ndev = NULL;
6829 struct wireless_dev *wdev = NULL;
6830
6831 WL_INFORM_MEM(("Updating static iface after Fw IF create \n"));
6832 new_ndev = cfg->static_ndev[static_ifidx];
6833
6834 if (new_ndev) {
6835 wdev = new_ndev->ieee80211_ptr;
6836 ASSERT(wdev);
6837 wdev->iftype = iface_type;
6838 (void)memcpy_s(new_ndev->dev_addr, ETH_ALEN, addr, ETH_ALEN);
6839 }
6840
6841 cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_CREATED;
6842 wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr,
6843 event->bssidx, event->name,
6844 NDEV_STATE_FW_IF_CREATED);
6845 return new_ndev;
6846 }
wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 * cfg,struct net_device * ndev)6847 s32 wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg,
6848 struct net_device *ndev)
6849 {
6850 int static_ifidx;
6851 int ifidx = WL_STATIC_IFIDX;
6852
6853 static_ifidx = wl_cfg80211_static_ifidx(cfg, ndev);
6854 ifidx += static_ifidx;
6855 cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_DELETED;
6856 wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX, NULL,
6857 NDEV_STATE_FW_IF_DELETED);
6858 wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
6859 wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
6860 return BCME_OK;
6861 }
6862 #endif /* WL_STATIC_IF */
6863