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