• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&param, 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*)&param, 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(&params, sizeof(wl_reassoc_params_t));
4245 	memcpy(&params.bssid, &bssid, ETHER_ADDR_LEN);
4246 
4247 	if ((err = wldev_ioctl_set(dev, WLC_REASSOC, &params,
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", &param, 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