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