ae55fb6e82e5bd3a857b37d4410e41806d510ddf
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / drivers / net / wireless / bcmdhd4361 / wl_android.c
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 of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: wl_android.c 796872 2018-12-27 08:23:42Z $
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 <wlc_types.h>
40 #include <wlioctl.h>
41 #include <wlioctl_utils.h>
42 #include <bcmutils.h>
43 #include <linux_osl.h>
44 #include <dhd_dbg.h>
45 #include <dngl_stats.h>
46 #include <dhd.h>
47 #include <bcmip.h>
48 #ifdef PNO_SUPPORT
49 #include <dhd_pno.h>
50 #endif // endif
51 #ifdef BCMSDIO
52 #include <bcmsdbus.h>
53 #endif // endif
54 #ifdef WL_CFG80211
55 #include <wl_cfg80211.h>
56 #endif // endif
57 #ifdef WL_NAN
58 #include <wl_cfgnan.h>
59 #endif /* WL_NAN */
60 #ifdef DHDTCPACK_SUPPRESS
61 #include <dhd_ip.h>
62 #endif /* DHDTCPACK_SUPPRESS */
63 #include <bcmwifi_rspec.h>
64 #include <dhd_linux.h>
65 #include <bcmiov.h>
66 #ifdef DHD_PKT_LOGGING
67 #include <dhd_pktlog.h>
68 #endif /* DHD_PKT_LOGGING */
69
70 #ifdef WL_STATIC_IF
71 #define WL_BSSIDX_MAX 16
72 #endif /* WL_STATIC_IF */
73
74 /*
75 * Android private command strings, PLEASE define new private commands here
76 * so they can be updated easily in the future (if needed)
77 */
78
79 #define CMD_START "START"
80 #define CMD_STOP "STOP"
81 #define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
82 #define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
83 #define CMD_RSSI "RSSI"
84 #define CMD_LINKSPEED "LINKSPEED"
85 #define CMD_RXFILTER_START "RXFILTER-START"
86 #define CMD_RXFILTER_STOP "RXFILTER-STOP"
87 #define CMD_RXFILTER_ADD "RXFILTER-ADD"
88 #define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
89 #define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
90 #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
91 #define CMD_BTCOEXMODE "BTCOEXMODE"
92 #define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
93 #define CMD_SETSUSPENDMODE "SETSUSPENDMODE"
94 #define CMD_SETDTIM_IN_SUSPEND "SET_DTIM_IN_SUSPEND"
95 #define CMD_MAXDTIM_IN_SUSPEND "MAX_DTIM_IN_SUSPEND"
96 #define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
97 #define CMD_SETFWPATH "SETFWPATH"
98 #define CMD_SETBAND "SETBAND"
99 #define CMD_GETBAND "GETBAND"
100 #define CMD_COUNTRY "COUNTRY"
101 #define CMD_P2P_SET_NOA "P2P_SET_NOA"
102 #if !defined WL_ENABLE_P2P_IF
103 #define CMD_P2P_GET_NOA "P2P_GET_NOA"
104 #endif /* WL_ENABLE_P2P_IF */
105 #define CMD_P2P_SD_OFFLOAD "P2P_SD_"
106 #define CMD_P2P_LISTEN_OFFLOAD "P2P_LO_"
107 #define CMD_P2P_SET_PS "P2P_SET_PS"
108 #define CMD_P2P_ECSA "P2P_ECSA"
109 #define CMD_P2P_INC_BW "P2P_INCREASE_BW"
110 #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
111 #define CMD_SETROAMMODE "SETROAMMODE"
112 #define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA"
113 #define CMD_MIRACAST "MIRACAST"
114 #ifdef WL_NAN
115 #define CMD_NAN "NAN_"
116 #endif /* WL_NAN */
117 #define CMD_COUNTRY_DELIMITER "/"
118
119 #if defined(WL_SUPPORT_AUTO_CHANNEL)
120 #define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS"
121 #endif /* WL_SUPPORT_AUTO_CHANNEL */
122
123 #define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */
124 #define CMD_CHANSPEC "CHANSPEC"
125 #define CMD_DATARATE "DATARATE"
126 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
127 #define CMD_SET_CSA "SETCSA"
128 #ifdef WL_SUPPORT_AUTO_CHANNEL
129 #define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL"
130 #endif /* WL_SUPPORT_AUTO_CHANNEL */
131 #ifdef CUSTOMER_HW4_PRIVATE_CMD
132 #ifdef SUPPORT_HIDDEN_AP
133 /* Hostapd private command */
134 #define CMD_SET_HAPD_MAX_NUM_STA "HAPD_MAX_NUM_STA"
135 #define CMD_SET_HAPD_SSID "HAPD_SSID"
136 #define CMD_SET_HAPD_HIDE_SSID "HAPD_HIDE_SSID"
137 #endif /* SUPPORT_HIDDEN_AP */
138 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
139 #define CMD_HAPD_STA_DISASSOC "HAPD_STA_DISASSOC"
140 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
141 #ifdef SUPPORT_SET_LPC
142 #define CMD_HAPD_LPC_ENABLED "HAPD_LPC_ENABLED"
143 #endif /* SUPPORT_SET_LPC */
144 #ifdef SUPPORT_TRIGGER_HANG_EVENT
145 #define CMD_TEST_FORCE_HANG "TEST_FORCE_HANG"
146 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
147 #ifdef SUPPORT_LTECX
148 #define CMD_LTECX_SET "LTECOEX"
149 #endif /* SUPPORT_LTECX */
150 #ifdef TEST_TX_POWER_CONTROL
151 #define CMD_TEST_SET_TX_POWER "TEST_SET_TX_POWER"
152 #define CMD_TEST_GET_TX_POWER "TEST_GET_TX_POWER"
153 #endif /* TEST_TX_POWER_CONTROL */
154 #define CMD_SARLIMIT_TX_CONTROL "SET_TX_POWER_CALLING"
155 #ifdef SUPPORT_SET_TID
156 #define CMD_SET_TID "SET_TID"
157 #define CMD_GET_TID "GET_TID"
158 #endif /* SUPPORT_SET_TID */
159 #ifdef APSTA_RESTRICTED_CHANNEL
160 #define CMD_SET_INDOOR_CHANNELS "SET_INDOOR_CHANNELS"
161 #define CMD_GET_INDOOR_CHANNELS "GET_INDOOR_CHANNELS"
162 #endif /* APSTA_RESTRICTED_CHANNEL */
163 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
164 #define CMD_KEEP_ALIVE "KEEPALIVE"
165
166 #ifdef BCMCCX
167 /* CCX Private Commands */
168 #define CMD_GETCCKM_RN "get cckm_rn"
169 #define CMD_SETCCKM_KRK "set cckm_krk"
170 #define CMD_GET_ASSOC_RES_IES "get assoc_res_ies"
171
172 #define CCKM_KRK_LEN 16
173 #define CCKM_BTK_LEN 32
174 #endif // endif
175
176 #ifdef PNO_SUPPORT
177 #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR"
178 #define CMD_PNOSETUP_SET "PNOSETUP "
179 #define CMD_PNOENABLE_SET "PNOFORCE"
180 #define CMD_PNODEBUG_SET "PNODEBUG"
181 #define CMD_WLS_BATCHING "WLS_BATCHING"
182 #endif /* PNO_SUPPORT */
183
184 #define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER"
185
186 #ifdef CUSTOMER_HW4_PRIVATE_CMD
187
188 #ifdef ROAM_API
189 #define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER"
190 #define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER"
191 #define CMD_ROAMDELTA_SET "SETROAMDELTA"
192 #define CMD_ROAMDELTA_GET "GETROAMDELTA"
193 #define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD"
194 #define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD"
195 #define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD"
196 #define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD"
197 #define CMD_COUNTRYREV_SET "SETCOUNTRYREV"
198 #define CMD_COUNTRYREV_GET "GETCOUNTRYREV"
199 #endif /* ROAM_API */
200
201 #if defined(SUPPORT_RANDOM_MAC_SCAN)
202 #define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC"
203 #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC"
204 #endif /* SUPPORT_RANDOM_MAC_SCAN */
205
206 #ifdef WES_SUPPORT
207 #define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
208 #define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
209 #define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
210 #define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
211
212 #define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
213 #define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
214 #define CMD_GETSCANUNASSOCTIME "GETSCANUNASSOCTIME"
215 #define CMD_SETSCANUNASSOCTIME "SETSCANUNASSOCTIME"
216 #define CMD_GETSCANPASSIVETIME "GETSCANPASSIVETIME"
217 #define CMD_SETSCANPASSIVETIME "SETSCANPASSIVETIME"
218 #define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
219 #define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
220 #define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
221 #define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
222 #define CMD_GETSCANNPROBES "GETSCANNPROBES"
223 #define CMD_SETSCANNPROBES "SETSCANNPROBES"
224 #define CMD_GETDFSSCANMODE "GETDFSSCANMODE"
225 #define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
226 #define CMD_SETJOINPREFER "SETJOINPREFER"
227
228 #define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
229 #define CMD_REASSOC "REASSOC"
230
231 #define CMD_GETWESMODE "GETWESMODE"
232 #define CMD_SETWESMODE "SETWESMODE"
233
234 #define CMD_GETOKCMODE "GETOKCMODE"
235 #define CMD_SETOKCMODE "SETOKCMODE"
236
237 #define CMD_OKC_SET_PMK "SET_PMK"
238 #define CMD_OKC_ENABLE "OKC_ENABLE"
239
240 typedef struct android_wifi_reassoc_params {
241 unsigned char bssid[18];
242 int channel;
243 } android_wifi_reassoc_params_t;
244
245 #define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params)
246
247 #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
248
249 typedef struct android_wifi_af_params {
250 unsigned char bssid[18];
251 int channel;
252 int dwell_time;
253 int len;
254 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
255 } android_wifi_af_params_t;
256
257 #define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params)
258 #endif /* WES_SUPPORT */
259 #ifdef SUPPORT_AMPDU_MPDU_CMD
260 #define CMD_AMPDU_MPDU "AMPDU_MPDU"
261 #endif /* SUPPORT_AMPDU_MPDU_CMD */
262
263 #define CMD_CHANGE_RL "CHANGE_RL"
264 #define CMD_RESTORE_RL "RESTORE_RL"
265
266 #define CMD_SET_RMC_ENABLE "SETRMCENABLE"
267 #define CMD_SET_RMC_TXRATE "SETRMCTXRATE"
268 #define CMD_SET_RMC_ACTPERIOD "SETRMCACTIONPERIOD"
269 #define CMD_SET_RMC_IDLEPERIOD "SETRMCIDLEPERIOD"
270 #define CMD_SET_RMC_LEADER "SETRMCLEADER"
271 #define CMD_SET_RMC_EVENT "SETRMCEVENT"
272
273 #define CMD_SET_SCSCAN "SETSINGLEANT"
274 #define CMD_GET_SCSCAN "GETSINGLEANT"
275 #ifdef WLTDLS
276 #define CMD_TDLS_RESET "TDLS_RESET"
277 #endif /* WLTDLS */
278
279 #ifdef FCC_PWR_LIMIT_2G
280 #define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL"
281 #define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL"
282 /* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */
283 #define CUSTOMER_HW4_ENABLE 0
284 #define CUSTOMER_HW4_DISABLE -1
285 #define CUSTOMER_HW4_EN_CONVERT(i) (i += 1)
286 #endif /* FCC_PWR_LIMIT_2G */
287
288 #ifdef APSTA_RESTRICTED_CHANNEL
289 #define CMD_SET_INDOOR_CHANNELS "SET_INDOOR_CHANNELS"
290 #define CMD_GET_INDOOR_CHANNELS "GET_INDOOR_CHANNELS"
291 #endif /* APSTA_RESTRICTED_CHANNEL */
292
293 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
294
295 #ifdef WLFBT
296 #define CMD_GET_FTKEY "GET_FTKEY"
297 #endif // endif
298
299 #ifdef WLAIBSS
300 #define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT"
301 #define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO"
302 #define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL"
303 #define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE"
304 #define CMD_SETIBSSAMPDU "SETIBSSAMPDU"
305 #define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE"
306 #endif /* WLAIBSS */
307
308 #define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
309 #define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
310 #define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
311 #define CMD_GET_LINK_STATUS "GETLINKSTATUS"
312
313 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
314 #define CMD_GET_BSS_INFO "GETBSSINFO"
315 #define CMD_GET_ASSOC_REJECT_INFO "GETASSOCREJECTINFO"
316 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
317 #define CMD_GET_STA_INFO "GETSTAINFO"
318
319 /* related with CMD_GET_LINK_STATUS */
320 #define WL_ANDROID_LINK_VHT 0x01
321 #define WL_ANDROID_LINK_MIMO 0x02
322 #define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04
323 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08
324
325 #ifdef P2PRESP_WFDIE_SRC
326 #define CMD_P2P_SET_WFDIE_RESP "P2P_SET_WFDIE_RESP"
327 #define CMD_P2P_GET_WFDIE_RESP "P2P_GET_WFDIE_RESP"
328 #endif /* P2PRESP_WFDIE_SRC */
329
330 #define CMD_DFS_AP_MOVE "DFS_AP_MOVE"
331 #define CMD_WBTEXT_ENABLE "WBTEXT_ENABLE"
332 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
333 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
334 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
335 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
336 #define CMD_WBTEXT_BTM_TIMER_THRESHOLD "WBTEXT_BTM_TIMER_THRESHOLD"
337 #define CMD_WBTEXT_BTM_DELTA "WBTEXT_BTM_DELTA"
338
339 #ifdef WLWFDS
340 #define CMD_ADD_WFDS_HASH "ADD_WFDS_HASH"
341 #define CMD_DEL_WFDS_HASH "DEL_WFDS_HASH"
342 #endif /* WLWFDS */
343
344 #ifdef SET_RPS_CPUS
345 #define CMD_RPSMODE "RPSMODE"
346 #endif /* SET_RPS_CPUS */
347
348 #ifdef BT_WIFI_HANDOVER
349 #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
350 #endif /* BT_WIFI_HANDOVER */
351
352 #ifdef DYNAMIC_MUMIMO_CONTROL
353 #define CMD_GET_MURX_BFE_CAP "GET_MURX_BFE_CAP"
354 #define CMD_SET_MURX_BFE_CAP "SET_MURX_BFE_CAP"
355 #define CMD_GET_BSS_SUPPORT_MUMIMO "GET_BSS_SUPPORT_MUMIMO"
356 #endif /* DYNAMIC_MUMIMO_CONTROL */
357
358 #ifdef SUPPORT_RSSI_SUM_REPORT
359 #define CMD_SET_RSSI_LOGGING "SET_RSSI_LOGGING"
360 #define CMD_GET_RSSI_LOGGING "GET_RSSI_LOGGING"
361 #define CMD_GET_RSSI_PER_ANT "GET_RSSI_PER_ANT"
362 #endif /* SUPPORT_RSSI_SUM_REPORT */
363
364 #define CMD_GET_SNR "GET_SNR"
365
366 #ifdef SUPPORT_SET_CAC
367 #define CMD_ENABLE_CAC "ENABLE_CAC"
368 #endif /* SUPPORT_SET_CAC */
369
370 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
371 #define CMD_SET_AP_BEACONRATE "SET_AP_BEACONRATE"
372 #define CMD_GET_AP_BASICRATE "GET_AP_BASICRATE"
373 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
374
375 #ifdef SUPPORT_AP_RADIO_PWRSAVE
376 #define CMD_SET_AP_RPS "SET_AP_RPS"
377 #define CMD_GET_AP_RPS "GET_AP_RPS"
378 #define CMD_SET_AP_RPS_PARAMS "SET_AP_RPS_PARAMS"
379 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
380
381 /* miracast related definition */
382 #define MIRACAST_MODE_OFF 0
383 #define MIRACAST_MODE_SOURCE 1
384 #define MIRACAST_MODE_SINK 2
385
386 #ifdef CONNECTION_STATISTICS
387 #define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS"
388
389 struct connection_stats {
390 u32 txframe;
391 u32 txbyte;
392 u32 txerror;
393 u32 rxframe;
394 u32 rxbyte;
395 u32 txfail;
396 u32 txretry;
397 u32 txretrie;
398 u32 txrts;
399 u32 txnocts;
400 u32 txexptime;
401 u32 txrate;
402 u8 chan_idle;
403 };
404 #endif /* CONNECTION_STATISTICS */
405
406 #ifdef SUPPORT_LQCM
407 #define CMD_SET_LQCM_ENABLE "SET_LQCM_ENABLE"
408 #define CMD_GET_LQCM_REPORT "GET_LQCM_REPORT"
409 #endif // endif
410
411 static LIST_HEAD(miracast_resume_list);
412 static u8 miracast_cur_mode;
413
414 #ifdef DHD_LOG_DUMP
415 #define CMD_NEW_DEBUG_PRINT_DUMP "DEBUG_DUMP"
416 #define SUBCMD_UNWANTED "UNWANTED"
417 #define SUBCMD_DISCONNECTED "DISCONNECTED"
418 void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
419 #endif /* DHD_LOG_DUMP */
420
421 #ifdef DHD_HANG_SEND_UP_TEST
422 #define CMD_MAKE_HANG "MAKE_HANG"
423 #endif /* CMD_DHD_HANG_SEND_UP_TEST */
424 #ifdef DHD_DEBUG_UART
425 extern bool dhd_debug_uart_is_running(struct net_device *dev);
426 #endif /* DHD_DEBUG_UART */
427
428 struct io_cfg {
429 s8 *iovar;
430 s32 param;
431 u32 ioctl;
432 void *arg;
433 u32 len;
434 struct list_head list;
435 };
436
437 #if defined(BCMFW_ROAM_ENABLE)
438 #define CMD_SET_ROAMPREF "SET_ROAMPREF"
439
440 #define MAX_NUM_SUITES 10
441 #define WIDTH_AKM_SUITE 8
442 #define JOIN_PREF_RSSI_LEN 0x02
443 #define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */
444 #define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */
445 #define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */
446 #define JOIN_PREF_MAX_WPA_TUPLES 16
447 #define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \
448 (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
449 #endif /* BCMFW_ROAM_ENABLE */
450
451 #define CMD_DEBUG_VERBOSE "DEBUG_VERBOSE"
452 #ifdef WL_NATOE
453
454 #define CMD_NATOE "NATOE"
455
456 #define NATOE_MAX_PORT_NUM 65535
457
458 /* natoe command info structure */
459 typedef struct wl_natoe_cmd_info {
460 uint8 *command; /* pointer to the actual command */
461 uint16 tot_len; /* total length of the command */
462 uint16 bytes_written; /* Bytes written for get response */
463 } wl_natoe_cmd_info_t;
464
465 typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
466 typedef int (natoe_cmd_handler_t)(struct net_device *dev,
467 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
468
469 struct wl_natoe_sub_cmd {
470 char *name;
471 uint8 version; /* cmd version */
472 uint16 id; /* id for the dongle f/w switch/case */
473 uint16 type; /* base type of argument */
474 natoe_cmd_handler_t *handler; /* cmd handler */
475 };
476
477 #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix
478 static int wl_android_process_natoe_cmd(struct net_device *dev,
479 char *command, int total_len);
480 static int wl_android_natoe_subcmd_enable(struct net_device *dev,
481 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
482 static int wl_android_natoe_subcmd_config_ips(struct net_device *dev,
483 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
484 static int wl_android_natoe_subcmd_config_ports(struct net_device *dev,
485 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
486 static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev,
487 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
488 static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
489 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
490
491 static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
492 /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
493 {"enable", 0x01, WL_NATOE_CMD_ENABLE,
494 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable)
495 },
496 {"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS,
497 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips)
498 },
499 {"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS,
500 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports)
501 },
502 {"stats", 0x01, WL_NATOE_CMD_DBG_STATS,
503 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats)
504 },
505 {"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT,
506 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt)
507 },
508 {NULL, 0, 0, 0, NULL}
509 };
510
511 #endif /* WL_NATOE */
512
513 #ifdef SET_PCIE_IRQ_CPU_CORE
514 #define CMD_PCIE_IRQ_CORE "PCIE_IRQ_CORE"
515 #endif /* SET_PCIE_IRQ_CPU_CORE */
516
517 #ifdef WLADPS_PRIVATE_CMD
518 #define CMD_SET_ADPS "SET_ADPS"
519 #define CMD_GET_ADPS "GET_ADPS"
520 #endif /* WLADPS_PRIVATE_CMD */
521
522 #ifdef DHD_PKT_LOGGING
523 #define CMD_PKTLOG_FILTER_ENABLE "PKTLOG_FILTER_ENABLE"
524 #define CMD_PKTLOG_FILTER_DISABLE "PKTLOG_FILTER_DISABLE"
525 #define CMD_PKTLOG_FILTER_PATTERN_ENABLE "PKTLOG_FILTER_PATTERN_ENABLE"
526 #define CMD_PKTLOG_FILTER_PATTERN_DISABLE "PKTLOG_FILTER_PATTERN_DISABLE"
527 #define CMD_PKTLOG_FILTER_ADD "PKTLOG_FILTER_ADD"
528 #define CMD_PKTLOG_FILTER_INFO "PKTLOG_FILTER_INFO"
529 #define CMD_PKTLOG_START "PKTLOG_START"
530 #define CMD_PKTLOG_STOP "PKTLOG_STOP"
531 #define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST"
532 #define CMD_PKTLOG_MINMIZE_ENABLE "PKTLOG_MINMIZE_ENABLE"
533 #define CMD_PKTLOG_MINMIZE_DISABLE "PKTLOG_MINMIZE_DISABLE"
534 #define CMD_PKTLOG_CHANGE_SIZE "PKTLOG_CHANGE_SIZE"
535 #endif /* DHD_PKT_LOGGING */
536
537 #ifdef DHD_EVENT_LOG_FILTER
538 #define CMD_EWP_FILTER "EWP_FILTER"
539 #endif /* DHD_EVENT_LOG_FILTER */
540
541 #ifdef WL_GENL
542 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
543 static int wl_genl_init(void);
544 static int wl_genl_deinit(void);
545
546 extern struct net init_net;
547 /* attribute policy: defines which attribute has which type (e.g int, char * etc)
548 * possible values defined in net/netlink.h
549 */
550 static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
551 [BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
552 [BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
553 };
554
555 #define WL_GENL_VER 1
556 /* family definition */
557 static struct genl_family wl_genl_family = {
558 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
559 .hdrsize = 0,
560 .name = "bcm-genl", /* Netlink I/F for Android */
561 .version = WL_GENL_VER, /* Version Number */
562 .maxattr = BCM_GENL_ATTR_MAX,
563 };
564
565 /* commands: mapping between the command enumeration and the actual function */
566 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
567 struct genl_ops wl_genl_ops[] = {
568 {
569 .cmd = BCM_GENL_CMD_MSG,
570 .flags = 0,
571 .policy = wl_genl_policy,
572 .doit = wl_genl_handle_msg,
573 .dumpit = NULL,
574 },
575 };
576 #else
577 struct genl_ops wl_genl_ops = {
578 .cmd = BCM_GENL_CMD_MSG,
579 .flags = 0,
580 .policy = wl_genl_policy,
581 .doit = wl_genl_handle_msg,
582 .dumpit = NULL,
583
584 };
585 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
586
587 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
588 static struct genl_multicast_group wl_genl_mcast[] = {
589 { .name = "bcm-genl-mcast", },
590 };
591 #else
592 static struct genl_multicast_group wl_genl_mcast = {
593 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
594 .name = "bcm-genl-mcast",
595 };
596 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
597 #endif /* WL_GENL */
598
599 #ifdef SUPPORT_LQCM
600 #define LQCM_ENAB_MASK 0x000000FF /* LQCM enable flag mask */
601 #define LQCM_TX_INDEX_MASK 0x0000FF00 /* LQCM tx index mask */
602 #define LQCM_RX_INDEX_MASK 0x00FF0000 /* LQCM rx index mask */
603
604 #define LQCM_TX_INDEX_SHIFT 8 /* LQCM tx index shift */
605 #define LQCM_RX_INDEX_SHIFT 16 /* LQCM rx index shift */
606 #endif /* SUPPORT_LQCM */
607
608 /**
609 * Extern function declarations (TODO: move them to dhd_linux.h)
610 */
611 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
612 int dhd_dev_init_ioctl(struct net_device *dev);
613 #ifdef WL_CFG80211
614 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
615 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
616 #ifdef WES_SUPPORT
617 int wl_cfg80211_set_wes_mode(int mode);
618 int wl_cfg80211_get_wes_mode(void);
619 #endif /* WES_SUPPORT */
620 #else
621 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
622 { return 0; }
623 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
624 { return 0; }
625 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
626 { return 0; }
627 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
628 { return 0; }
629 int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
630 { return 0; }
631 int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
632 { return 0; }
633 #endif /* WK_CFG80211 */
634 #ifdef WBTEXT
635 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len);
636 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
637 char *command, int total_len);
638 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
639 char *command, int total_len);
640 #endif /* WBTEXT */
641 #ifdef WES_SUPPORT
642 /* wl_roam.c */
643 extern int get_roamscan_mode(struct net_device *dev, int *mode);
644 extern int set_roamscan_mode(struct net_device *dev, int mode);
645 extern int get_roamscan_channel_list(struct net_device *dev,
646 unsigned char channels[], int n_channels);
647 extern int set_roamscan_channel_list(struct net_device *dev, unsigned char n,
648 unsigned char channels[], int ioctl_ver);
649 #endif /* WES_SUPPORT */
650 #ifdef ROAM_CHANNEL_CACHE
651 extern void wl_update_roamscan_cache_by_band(struct net_device *dev, int band);
652 #endif /* ROAM_CHANNEL_CACHE */
653
654 #ifdef ENABLE_4335BT_WAR
655 extern int bcm_bt_lock(int cookie);
656 extern void bcm_bt_unlock(int cookie);
657 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
658 #endif /* ENABLE_4335BT_WAR */
659
660 extern bool ap_fw_loaded;
661 extern char iface_name[IFNAMSIZ];
662 #ifdef DHD_PM_CONTROL_FROM_FILE
663 extern bool g_pm_control;
664 #endif /* DHD_PM_CONTROL_FROM_FILE */
665
666 /**
667 * Local (static) functions and variables
668 */
669
670 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
671 * time (only) in dhd_open, subsequential wifi on will be handled by
672 * wl_android_wifi_on
673 */
674 static int g_wifi_on = TRUE;
675
676 /**
677 * Local (static) function definitions
678 */
679
680 #ifdef WLWFDS
681 static int wl_android_set_wfds_hash(
682 struct net_device *dev, char *command, bool enable)
683 {
684 int error = 0;
685 wl_p2p_wfds_hash_t *wfds_hash = NULL;
686 char *smbuf = NULL;
687 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
688
689 smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
690 if (smbuf == NULL) {
691 DHD_ERROR(("%s: failed to allocated memory %d bytes\n",
692 __FUNCTION__, WLC_IOCTL_MAXLEN));
693 return -ENOMEM;
694 }
695
696 if (enable) {
697 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
698 error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
699 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
700 }
701 else {
702 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
703 error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
704 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
705 }
706
707 if (error) {
708 DHD_ERROR(("%s: failed to %s, error=%d\n", __FUNCTION__, command, error));
709 }
710
711 if (smbuf) {
712 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
713 }
714 return error;
715 }
716 #endif /* WLWFDS */
717
718 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
719 {
720 int link_speed;
721 int bytes_written;
722 int error;
723
724 error = wldev_get_link_speed(net, &link_speed);
725 if (error) {
726 DHD_ERROR(("Get linkspeed failed \n"));
727 return -1;
728 }
729
730 /* Convert Kbps to Android Mbps */
731 link_speed = link_speed / 1000;
732 bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
733 DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command));
734 return bytes_written;
735 }
736
737 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
738 {
739 wlc_ssid_t ssid = {0, {0}};
740 int bytes_written = 0;
741 int error = 0;
742 scb_val_t scbval;
743 char *delim = NULL;
744 struct net_device *target_ndev = net;
745 #ifdef WL_VIRTUAL_APSTA
746 char *pos = NULL;
747 struct bcm_cfg80211 *cfg;
748 #endif /* WL_VIRTUAL_APSTA */
749
750 delim = strchr(command, ' ');
751 /* For Ap mode rssi command would be
752 * driver rssi <sta_mac_addr>
753 * for STA/GC mode
754 * driver rssi
755 */
756 if (delim) {
757 /* Ap/GO mode
758 * driver rssi <sta_mac_addr>
759 */
760 DHD_TRACE(("%s: cmd:%s\n", __FUNCTION__, delim));
761 /* skip space from delim after finding char */
762 delim++;
763 if (!(bcm_ether_atoe((delim), &scbval.ea))) {
764 DHD_ERROR(("%s:address err\n", __FUNCTION__));
765 return -1;
766 }
767 scbval.val = htod32(0);
768 DHD_TRACE(("%s: address:"MACDBG, __FUNCTION__, MAC2STRDBG(scbval.ea.octet)));
769 #ifdef WL_VIRTUAL_APSTA
770 /* RSDB AP may have another virtual interface
771 * In this case, format of private command is as following,
772 * DRIVER rssi <sta_mac_addr> <AP interface name>
773 */
774
775 /* Current position is start of MAC address string */
776 pos = delim;
777 delim = strchr(pos, ' ');
778 if (delim) {
779 /* skip space from delim after finding char */
780 delim++;
781 if (strnlen(delim, IFNAMSIZ)) {
782 cfg = wl_get_cfg(net);
783 target_ndev = wl_get_ap_netdev(cfg, delim);
784 if (target_ndev == NULL)
785 target_ndev = net;
786 }
787 }
788 #endif /* WL_VIRTUAL_APSTA */
789 }
790 else {
791 /* STA/GC mode */
792 memset(&scbval, 0, sizeof(scb_val_t));
793 }
794
795 error = wldev_get_rssi(target_ndev, &scbval);
796 if (error)
797 return -1;
798
799 error = wldev_get_ssid(target_ndev, &ssid);
800 if (error)
801 return -1;
802 if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
803 DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
804 } else if (total_len <= ssid.SSID_len) {
805 return -ENOMEM;
806 } else {
807 memcpy(command, ssid.SSID, ssid.SSID_len);
808 bytes_written = ssid.SSID_len;
809 }
810 if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1))
811 return -ENOMEM;
812
813 bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written,
814 " rssi %d", scbval.val);
815 command[bytes_written] = '\0';
816
817 DHD_TRACE(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
818 return bytes_written;
819 }
820
821 static int wl_android_set_suspendopt(struct net_device *dev, char *command)
822 {
823 int suspend_flag;
824 int ret_now;
825 int ret = 0;
826
827 suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
828
829 if (suspend_flag != 0) {
830 suspend_flag = 1;
831 }
832 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
833
834 if (ret_now != suspend_flag) {
835 if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
836 DHD_INFO(("%s: Suspend Flag %d -> %d\n",
837 __FUNCTION__, ret_now, suspend_flag));
838 } else {
839 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
840 }
841 }
842
843 return ret;
844 }
845
846 static int wl_android_set_suspendmode(struct net_device *dev, char *command)
847 {
848 int ret = 0;
849
850 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
851 int suspend_flag;
852
853 suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
854 if (suspend_flag != 0)
855 suspend_flag = 1;
856
857 if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
858 DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag));
859 else
860 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
861 #endif // endif
862
863 return ret;
864 }
865
866 int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
867 {
868 uint8 mode[5];
869 int error = 0;
870 int bytes_written = 0;
871
872 error = wldev_get_mode(dev, mode, sizeof(mode));
873 if (error)
874 return -1;
875
876 DHD_INFO(("%s: mode:%s\n", __FUNCTION__, mode));
877 bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
878 DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command));
879 return bytes_written;
880
881 }
882
883 extern chanspec_t
884 wl_chspec_driver_to_host(chanspec_t chanspec);
885 int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len)
886 {
887 int error = 0;
888 int bytes_written = 0;
889 int chsp = {0};
890 uint16 band = 0;
891 uint16 bw = 0;
892 uint16 channel = 0;
893 u32 sb = 0;
894 chanspec_t chanspec;
895
896 /* command is
897 * driver chanspec
898 */
899 error = wldev_iovar_getint(dev, "chanspec", &chsp);
900 if (error)
901 return -1;
902
903 chanspec = wl_chspec_driver_to_host(chsp);
904 DHD_INFO(("%s:return value of chanspec:%x\n", __FUNCTION__, chanspec));
905
906 channel = chanspec & WL_CHANSPEC_CHAN_MASK;
907 band = chanspec & WL_CHANSPEC_BAND_MASK;
908 bw = chanspec & WL_CHANSPEC_BW_MASK;
909
910 DHD_INFO(("%s:channel:%d band:%d bandwidth:%d\n", __FUNCTION__, channel, band, bw));
911
912 if (bw == WL_CHANSPEC_BW_80)
913 bw = WL_CH_BANDWIDTH_80MHZ;
914 else if (bw == WL_CHANSPEC_BW_40)
915 bw = WL_CH_BANDWIDTH_40MHZ;
916 else if (bw == WL_CHANSPEC_BW_20)
917 bw = WL_CH_BANDWIDTH_20MHZ;
918 else
919 bw = WL_CH_BANDWIDTH_20MHZ;
920
921 if (bw == WL_CH_BANDWIDTH_40MHZ) {
922 if (CHSPEC_SB_UPPER(chanspec)) {
923 channel += CH_10MHZ_APART;
924 } else {
925 channel -= CH_10MHZ_APART;
926 }
927 }
928 else if (bw == WL_CH_BANDWIDTH_80MHZ) {
929 sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
930 if (sb == WL_CHANSPEC_CTL_SB_LL) {
931 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
932 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
933 channel -= CH_10MHZ_APART;
934 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
935 channel += CH_10MHZ_APART;
936 } else {
937 /* WL_CHANSPEC_CTL_SB_UU */
938 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
939 }
940 }
941 bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC,
942 channel, band == WL_CHANSPEC_BAND_5G ? "5G":"2G", bw);
943
944 DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command));
945 return bytes_written;
946
947 }
948
949 /* returns current datarate datarate returned from firmware are in 500kbps */
950 int wl_android_get_datarate(struct net_device *dev, char *command, int total_len)
951 {
952 int error = 0;
953 int datarate = 0;
954 int bytes_written = 0;
955
956 error = wldev_get_datarate(dev, &datarate);
957 if (error)
958 return -1;
959
960 DHD_INFO(("%s:datarate:%d\n", __FUNCTION__, datarate));
961
962 bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2));
963 return bytes_written;
964 }
965 int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len)
966 {
967 int error = 0;
968 int bytes_written = 0;
969 uint i;
970 int len = 0;
971 char mac_buf[MAX_NUM_OF_ASSOCLIST *
972 sizeof(struct ether_addr) + sizeof(uint)] = {0};
973 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
974
975 DHD_TRACE(("%s: ENTER\n", __FUNCTION__));
976
977 assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
978
979 error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
980 if (error)
981 return -1;
982
983 assoc_maclist->count = dtoh32(assoc_maclist->count);
984 bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:",
985 CMD_ASSOC_CLIENTS, assoc_maclist->count);
986
987 for (i = 0; i < assoc_maclist->count; i++) {
988 len = snprintf(command + bytes_written, total_len - bytes_written, " " MACDBG,
989 MAC2STRDBG(assoc_maclist->ea[i].octet));
990 /* A return value of '(total_len - bytes_written)' or more means that the
991 * output was truncated
992 */
993 if ((len > 0) && (len < (total_len - bytes_written))) {
994 bytes_written += len;
995 } else {
996 DHD_ERROR(("%s: Insufficient buffer %d, bytes_written %d\n",
997 __FUNCTION__, total_len, bytes_written));
998 bytes_written = -1;
999 break;
1000 }
1001 }
1002 return bytes_written;
1003 }
1004 extern chanspec_t
1005 wl_chspec_host_to_driver(chanspec_t chanspec);
1006 static int wl_android_set_csa(struct net_device *dev, char *command)
1007 {
1008 int error = 0;
1009 char smbuf[WLC_IOCTL_SMLEN];
1010 wl_chan_switch_t csa_arg;
1011 u32 chnsp = 0;
1012 int err = 0;
1013
1014 DHD_INFO(("%s: command:%s\n", __FUNCTION__, command));
1015
1016 command = (command + strlen(CMD_SET_CSA));
1017 /* Order is mode, count channel */
1018 if (!*++command) {
1019 DHD_ERROR(("%s:error missing arguments\n", __FUNCTION__));
1020 return -1;
1021 }
1022 csa_arg.mode = bcm_atoi(command);
1023
1024 if (csa_arg.mode != 0 && csa_arg.mode != 1) {
1025 DHD_ERROR(("Invalid mode\n"));
1026 return -1;
1027 }
1028
1029 if (!*++command) {
1030 DHD_ERROR(("%s:error missing count\n", __FUNCTION__));
1031 return -1;
1032 }
1033 command++;
1034 csa_arg.count = bcm_atoi(command);
1035
1036 csa_arg.reg = 0;
1037 csa_arg.chspec = 0;
1038 command += 2;
1039 if (!*command) {
1040 DHD_ERROR(("%s:error missing channel\n", __FUNCTION__));
1041 return -1;
1042 }
1043
1044 chnsp = wf_chspec_aton(command);
1045 if (chnsp == 0) {
1046 DHD_ERROR(("%s:chsp is not correct\n", __FUNCTION__));
1047 return -1;
1048 }
1049 chnsp = wl_chspec_host_to_driver(chnsp);
1050 csa_arg.chspec = chnsp;
1051
1052 if (chnsp & WL_CHANSPEC_BAND_5G) {
1053 u32 chanspec = chnsp;
1054 err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
1055 if (!err) {
1056 if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
1057 DHD_ERROR(("Channel is radar sensitive\n"));
1058 return -1;
1059 }
1060 if (chanspec == 0) {
1061 DHD_ERROR(("Invalid hw channel\n"));
1062 return -1;
1063 }
1064 } else {
1065 DHD_ERROR(("does not support per_chan_info\n"));
1066 return -1;
1067 }
1068 DHD_INFO(("non radar sensitivity\n"));
1069 }
1070 error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
1071 smbuf, sizeof(smbuf), NULL);
1072 if (error) {
1073 DHD_ERROR(("%s:set csa failed:%d\n", __FUNCTION__, error));
1074 return -1;
1075 }
1076 return 0;
1077 }
1078
1079 static int
1080 wl_android_set_bcn_li_dtim(struct net_device *dev, char *command)
1081 {
1082 int ret = 0;
1083 int dtim;
1084
1085 dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0';
1086
1087 if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) {
1088 DHD_ERROR(("%s: failed, invalid dtim %d\n",
1089 __FUNCTION__, dtim));
1090 return BCME_ERROR;
1091 }
1092
1093 if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) {
1094 DHD_TRACE(("%s: SET bcn_li_dtim in suspend %d\n",
1095 __FUNCTION__, dtim));
1096 } else {
1097 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1098 }
1099
1100 return ret;
1101 }
1102
1103 static int
1104 wl_android_set_max_dtim(struct net_device *dev, char *command)
1105 {
1106 int ret = 0;
1107 int dtim_flag;
1108
1109 dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
1110
1111 if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
1112 DHD_TRACE(("%s: use Max bcn_li_dtim in suspend %s\n",
1113 __FUNCTION__, (dtim_flag ? "Enable" : "Disable")));
1114 } else {
1115 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1116 }
1117
1118 return ret;
1119 }
1120
1121 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
1122 {
1123 uint band;
1124 int bytes_written;
1125 int error;
1126
1127 error = wldev_get_band(dev, &band);
1128 if (error)
1129 return -1;
1130 bytes_written = snprintf(command, total_len, "Band %d", band);
1131 return bytes_written;
1132 }
1133
1134 #ifdef CUSTOMER_HW4_PRIVATE_CMD
1135 #ifdef ROAM_API
1136 static bool wl_android_check_wbtext(struct net_device *dev)
1137 {
1138 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1139 return dhdp->wbtext_support;
1140 }
1141
1142 static int wl_android_set_roam_trigger(
1143 struct net_device *dev, char* command)
1144 {
1145 int roam_trigger[2] = {0, 0};
1146 int error;
1147
1148 #ifdef WBTEXT
1149 if (wl_android_check_wbtext(dev)) {
1150 WL_ERR(("blocked to set roam trigger. try with setting roam profile\n"));
1151 return BCME_ERROR;
1152 }
1153 #endif /* WBTEXT */
1154
1155 sscanf(command, "%*s %10d", &roam_trigger[0]);
1156 if (roam_trigger[0] >= 0) {
1157 WL_ERR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1158 return BCME_ERROR;
1159 }
1160
1161 roam_trigger[1] = WLC_BAND_ALL;
1162 error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1163 sizeof(roam_trigger));
1164 if (error != BCME_OK) {
1165 WL_ERR(("failed to set roam trigger (%d)\n", error));
1166 return BCME_ERROR;
1167 }
1168
1169 return BCME_OK;
1170 }
1171
1172 static int wl_android_get_roam_trigger(
1173 struct net_device *dev, char *command, int total_len)
1174 {
1175 int bytes_written, error;
1176 int roam_trigger[2] = {0, 0};
1177 uint16 band = 0;
1178 int chsp = {0};
1179 chanspec_t chanspec;
1180 int i;
1181 struct wl_roam_prof_band_v2 rp;
1182 char smbuf[WLC_IOCTL_SMLEN];
1183
1184 error = wldev_iovar_getint(dev, "chanspec", &chsp);
1185 if (error != BCME_OK) {
1186 WL_ERR(("failed to get chanspec (%d)\n", error));
1187 return BCME_ERROR;
1188 }
1189
1190 chanspec = wl_chspec_driver_to_host(chsp);
1191 band = chanspec & WL_CHANSPEC_BAND_MASK;
1192 if (band == WL_CHANSPEC_BAND_5G)
1193 band = WLC_BAND_5G;
1194 else
1195 band = WLC_BAND_2G;
1196
1197 if (wl_android_check_wbtext(dev)) {
1198 rp.ver = WL_MAX_ROAM_PROF_VER;
1199 rp.len = 0;
1200 rp.band = band;
1201 error = wldev_iovar_getbuf(dev, "roam_prof", &rp, sizeof(rp),
1202 smbuf, sizeof(smbuf), NULL);
1203 if (error != BCME_OK) {
1204 WL_ERR(("failed to get roam profile (%d)\n", error));
1205 return BCME_ERROR;
1206 }
1207 memcpy(&rp, smbuf, sizeof(struct wl_roam_prof_band_v2));
1208 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1209 if (rp.roam_prof[i].channel_usage == 0) {
1210 roam_trigger[0] = rp.roam_prof[i].roam_trigger;
1211 break;
1212 }
1213 }
1214 if (roam_trigger[0] == 0) {
1215 WL_ERR(("roam trigger was not set properly\n"));
1216 return BCME_ERROR;
1217 }
1218 } else {
1219 roam_trigger[1] = band;
1220 error = wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
1221 sizeof(roam_trigger));
1222 if (error != BCME_OK) {
1223 WL_ERR(("failed to get roam trigger (%d)\n", error));
1224 return BCME_ERROR;
1225 }
1226 }
1227
1228 bytes_written = snprintf(command, total_len, "%s %d",
1229 CMD_ROAMTRIGGER_GET, roam_trigger[0]);
1230
1231 return bytes_written;
1232 }
1233
1234 int wl_android_set_roam_delta(
1235 struct net_device *dev, char* command)
1236 {
1237 int roam_delta[2];
1238
1239 sscanf(command, "%*s %10d", &roam_delta[0]);
1240 roam_delta[1] = WLC_BAND_ALL;
1241
1242 return wldev_ioctl_set(dev, WLC_SET_ROAM_DELTA, roam_delta,
1243 sizeof(roam_delta));
1244 }
1245
1246 static int wl_android_get_roam_delta(
1247 struct net_device *dev, char *command, int total_len)
1248 {
1249 int bytes_written;
1250 int roam_delta[2] = {0, 0};
1251
1252 roam_delta[1] = WLC_BAND_2G;
1253 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1254 sizeof(roam_delta))) {
1255 roam_delta[1] = WLC_BAND_5G;
1256 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1257 sizeof(roam_delta)))
1258 return -1;
1259 }
1260
1261 bytes_written = snprintf(command, total_len, "%s %d",
1262 CMD_ROAMDELTA_GET, roam_delta[0]);
1263
1264 return bytes_written;
1265 }
1266
1267 int wl_android_set_roam_scan_period(
1268 struct net_device *dev, char* command)
1269 {
1270 int roam_scan_period = 0;
1271
1272 sscanf(command, "%*s %10d", &roam_scan_period);
1273 return wldev_ioctl_set(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period,
1274 sizeof(roam_scan_period));
1275 }
1276
1277 static int wl_android_get_roam_scan_period(
1278 struct net_device *dev, char *command, int total_len)
1279 {
1280 int bytes_written;
1281 int roam_scan_period = 0;
1282
1283 if (wldev_ioctl_get(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period,
1284 sizeof(roam_scan_period)))
1285 return -1;
1286
1287 bytes_written = snprintf(command, total_len, "%s %d",
1288 CMD_ROAMSCANPERIOD_GET, roam_scan_period);
1289
1290 return bytes_written;
1291 }
1292
1293 int wl_android_set_full_roam_scan_period(
1294 struct net_device *dev, char* command, int total_len)
1295 {
1296 int error = 0;
1297 int full_roam_scan_period = 0;
1298 char smbuf[WLC_IOCTL_SMLEN];
1299
1300 sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period);
1301 WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period));
1302
1303 error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period,
1304 sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL);
1305 if (error) {
1306 DHD_ERROR(("Failed to set full roam scan period, error = %d\n", error));
1307 }
1308
1309 return error;
1310 }
1311
1312 static int wl_android_get_full_roam_scan_period(
1313 struct net_device *dev, char *command, int total_len)
1314 {
1315 int error;
1316 int bytes_written;
1317 int full_roam_scan_period = 0;
1318
1319 error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period);
1320
1321 if (error) {
1322 DHD_ERROR(("%s: get full roam scan period failed code %d\n",
1323 __func__, error));
1324 return -1;
1325 } else {
1326 DHD_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period));
1327 }
1328
1329 bytes_written = snprintf(command, total_len, "%s %d",
1330 CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period);
1331
1332 return bytes_written;
1333 }
1334
1335 int wl_android_set_country_rev(
1336 struct net_device *dev, char* command)
1337 {
1338 int error = 0;
1339 wl_country_t cspec = {{0}, 0, {0} };
1340 char country_code[WLC_CNTRY_BUF_SZ];
1341 char smbuf[WLC_IOCTL_SMLEN];
1342 int rev = 0;
1343
1344 memset(country_code, 0, sizeof(country_code));
1345 sscanf(command+sizeof("SETCOUNTRYREV"), "%3s %10d", country_code, &rev);
1346 WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev));
1347
1348 memcpy(cspec.country_abbrev, country_code, sizeof(country_code));
1349 memcpy(cspec.ccode, country_code, sizeof(country_code));
1350 cspec.rev = rev;
1351
1352 error = wldev_iovar_setbuf(dev, "country", (char *)&cspec,
1353 sizeof(cspec), smbuf, sizeof(smbuf), NULL);
1354
1355 if (error) {
1356 DHD_ERROR(("%s: set country '%s/%d' failed code %d\n",
1357 __FUNCTION__, cspec.ccode, cspec.rev, error));
1358 } else {
1359 dhd_bus_country_set(dev, &cspec, true);
1360 DHD_INFO(("%s: set country '%s/%d'\n",
1361 __FUNCTION__, cspec.ccode, cspec.rev));
1362 }
1363
1364 return error;
1365 }
1366
1367 static int wl_android_get_country_rev(
1368 struct net_device *dev, char *command, int total_len)
1369 {
1370 int error;
1371 int bytes_written;
1372 char smbuf[WLC_IOCTL_SMLEN];
1373 wl_country_t cspec;
1374
1375 error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf,
1376 sizeof(smbuf), NULL);
1377
1378 if (error) {
1379 DHD_ERROR(("%s: get country failed code %d\n",
1380 __FUNCTION__, error));
1381 return -1;
1382 } else {
1383 memcpy(&cspec, smbuf, sizeof(cspec));
1384 DHD_INFO(("%s: get country '%c%c %d'\n",
1385 __FUNCTION__, cspec.ccode[0], cspec.ccode[1], cspec.rev));
1386 }
1387
1388 bytes_written = snprintf(command, total_len, "%s %c%c %d",
1389 CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev);
1390
1391 return bytes_written;
1392 }
1393 #endif /* ROAM_API */
1394
1395 #ifdef WES_SUPPORT
1396 int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len)
1397 {
1398 int error = 0;
1399 int bytes_written = 0;
1400 int mode = 0;
1401
1402 error = get_roamscan_mode(dev, &mode);
1403 if (error) {
1404 DHD_ERROR(("%s: Failed to get Scan Control, error = %d\n", __FUNCTION__, error));
1405 return -1;
1406 }
1407
1408 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode);
1409
1410 return bytes_written;
1411 }
1412
1413 int wl_android_set_roam_scan_control(struct net_device *dev, char *command)
1414 {
1415 int error = 0;
1416 int mode = 0;
1417
1418 if (sscanf(command, "%*s %d", &mode) != 1) {
1419 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1420 return -1;
1421 }
1422
1423 error = set_roamscan_mode(dev, mode);
1424 if (error) {
1425 DHD_ERROR(("%s: Failed to set Scan Control %d, error = %d\n",
1426 __FUNCTION__, mode, error));
1427 return -1;
1428 }
1429
1430 return 0;
1431 }
1432
1433 int wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len)
1434 {
1435 int bytes_written = 0;
1436 unsigned char channels[MAX_ROAM_CHANNEL] = {0};
1437 int channel_cnt = 0;
1438 int i = 0;
1439 int buf_avail, len;
1440
1441 channel_cnt = get_roamscan_channel_list(dev, channels, MAX_ROAM_CHANNEL);
1442 bytes_written = snprintf(command, total_len, "%s %d",
1443 CMD_GETROAMSCANCHANNELS, channel_cnt);
1444 buf_avail = total_len - bytes_written;
1445 for (i = 0; i < channel_cnt; i++) {
1446 /* A return value of 'buf_avail' or more means that the output was truncated */
1447 len = snprintf(command + bytes_written, buf_avail, " %d", channels[i]);
1448 if (len >= buf_avail) {
1449 WL_ERR(("%s: Insufficient memory, %d bytes\n", __FUNCTION__, total_len));
1450 bytes_written = -1;
1451 break;
1452 }
1453 /* 'buf_avail' decremented by number of bytes written */
1454 buf_avail -= len;
1455 bytes_written += len;
1456 }
1457 WL_INFORM(("%s: %s\n", __FUNCTION__, command));
1458 return bytes_written;
1459 }
1460
1461 int wl_android_set_roam_scan_channels(struct net_device *dev, char *command)
1462 {
1463 int error = 0;
1464 unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1);
1465 int get_ioctl_version = wl_cfg80211_get_ioctl_version();
1466 error = set_roamscan_channel_list(dev, p[0], &p[1], get_ioctl_version);
1467 if (error) {
1468 DHD_ERROR(("%s: Failed to set Scan Channels %d, error = %d\n",
1469 __FUNCTION__, p[0], error));
1470 return -1;
1471 }
1472
1473 return 0;
1474 }
1475
1476 int wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len)
1477 {
1478 int error = 0;
1479 int bytes_written = 0;
1480 int time = 0;
1481
1482 error = wldev_ioctl_get(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time));
1483 if (error) {
1484 DHD_ERROR(("%s: Failed to get Scan Channel Time, error = %d\n",
1485 __FUNCTION__, error));
1486 return -1;
1487 }
1488
1489 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time);
1490
1491 return bytes_written;
1492 }
1493
1494 int wl_android_set_scan_channel_time(struct net_device *dev, char *command)
1495 {
1496 int error = 0;
1497 int time = 0;
1498
1499 if (sscanf(command, "%*s %d", &time) != 1) {
1500 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1501 return -1;
1502 }
1503 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1504 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_CHANNEL_TIME, time);
1505 error = wldev_ioctl_set(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time));
1506 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1507 if (error) {
1508 DHD_ERROR(("%s: Failed to set Scan Channel Time %d, error = %d\n",
1509 __FUNCTION__, time, error));
1510 return -1;
1511 }
1512
1513 return 0;
1514 }
1515
1516 int
1517 wl_android_get_scan_unassoc_time(struct net_device *dev, char *command, int total_len)
1518 {
1519 int error = 0;
1520 int bytes_written = 0;
1521 int time = 0;
1522
1523 error = wldev_ioctl_get(dev, WLC_GET_SCAN_UNASSOC_TIME, &time, sizeof(time));
1524 if (error) {
1525 DHD_ERROR(("%s: Failed to get Scan Unassoc Time, error = %d\n",
1526 __FUNCTION__, error));
1527 return -1;
1528 }
1529
1530 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANUNASSOCTIME, time);
1531
1532 return bytes_written;
1533 }
1534
1535 int
1536 wl_android_set_scan_unassoc_time(struct net_device *dev, char *command)
1537 {
1538 int error = 0;
1539 int time = 0;
1540
1541 if (sscanf(command, "%*s %d", &time) != 1) {
1542 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1543 return -1;
1544 }
1545 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1546 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_UNASSOC_TIME, time);
1547 error = wldev_ioctl_set(dev, WLC_SET_SCAN_UNASSOC_TIME, &time, sizeof(time));
1548 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1549 if (error) {
1550 DHD_ERROR(("%s: Failed to set Scan Unassoc Time %d, error = %d\n",
1551 __FUNCTION__, time, error));
1552 return -1;
1553 }
1554
1555 return 0;
1556 }
1557
1558 int
1559 wl_android_get_scan_passive_time(struct net_device *dev, char *command, int total_len)
1560 {
1561 int error = 0;
1562 int bytes_written = 0;
1563 int time = 0;
1564
1565 error = wldev_ioctl_get(dev, WLC_GET_SCAN_PASSIVE_TIME, &time, sizeof(time));
1566 if (error) {
1567 DHD_ERROR(("%s: Failed to get Scan Passive Time, error = %d\n",
1568 __FUNCTION__, error));
1569 return -1;
1570 }
1571
1572 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANPASSIVETIME, time);
1573
1574 return bytes_written;
1575 }
1576
1577 int
1578 wl_android_set_scan_passive_time(struct net_device *dev, char *command)
1579 {
1580 int error = 0;
1581 int time = 0;
1582
1583 if (sscanf(command, "%*s %d", &time) != 1) {
1584 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1585 return -1;
1586 }
1587 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1588 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_PASSIVE_TIME, time);
1589 error = wldev_ioctl_set(dev, WLC_SET_SCAN_PASSIVE_TIME, &time, sizeof(time));
1590 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1591 if (error) {
1592 DHD_ERROR(("%s: Failed to set Scan Passive Time %d, error = %d\n",
1593 __FUNCTION__, time, error));
1594 return -1;
1595 }
1596
1597 return 0;
1598 }
1599
1600 int wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len)
1601 {
1602 int error = 0;
1603 int bytes_written = 0;
1604 int time = 0;
1605
1606 error = wldev_ioctl_get(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time));
1607 if (error) {
1608 DHD_ERROR(("Failed to get Scan Home Time, error = %d\n", error));
1609 return -1;
1610 }
1611
1612 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time);
1613
1614 return bytes_written;
1615 }
1616
1617 int wl_android_set_scan_home_time(struct net_device *dev, char *command)
1618 {
1619 int error = 0;
1620 int time = 0;
1621
1622 if (sscanf(command, "%*s %d", &time) != 1) {
1623 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1624 return -1;
1625 }
1626 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1627 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_TIME, time);
1628 error = wldev_ioctl_set(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time));
1629 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1630 if (error) {
1631 DHD_ERROR(("%s: Failed to set Scan Home Time %d, error = %d\n",
1632 __FUNCTION__, time, error));
1633 return -1;
1634 }
1635
1636 return 0;
1637 }
1638
1639 int wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len)
1640 {
1641 int error = 0;
1642 int bytes_written = 0;
1643 int time = 0;
1644
1645 error = wldev_iovar_getint(dev, "scan_home_away_time", &time);
1646 if (error) {
1647 DHD_ERROR(("%s: Failed to get Scan Home Away Time, error = %d\n",
1648 __FUNCTION__, error));
1649 return -1;
1650 }
1651
1652 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time);
1653
1654 return bytes_written;
1655 }
1656
1657 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command)
1658 {
1659 int error = 0;
1660 int time = 0;
1661
1662 if (sscanf(command, "%*s %d", &time) != 1) {
1663 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1664 return -1;
1665 }
1666 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
1667 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_AWAY_TIME, time);
1668 error = wldev_iovar_setint(dev, "scan_home_away_time", time);
1669 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
1670 if (error) {
1671 DHD_ERROR(("%s: Failed to set Scan Home Away Time %d, error = %d\n",
1672 __FUNCTION__, time, error));
1673 return -1;
1674 }
1675
1676 return 0;
1677 }
1678
1679 int wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len)
1680 {
1681 int error = 0;
1682 int bytes_written = 0;
1683 int num = 0;
1684
1685 error = wldev_ioctl_get(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num));
1686 if (error) {
1687 DHD_ERROR(("%s: Failed to get Scan NProbes, error = %d\n", __FUNCTION__, error));
1688 return -1;
1689 }
1690
1691 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num);
1692
1693 return bytes_written;
1694 }
1695
1696 int wl_android_set_scan_nprobes(struct net_device *dev, char *command)
1697 {
1698 int error = 0;
1699 int num = 0;
1700
1701 if (sscanf(command, "%*s %d", &num) != 1) {
1702 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1703 return -1;
1704 }
1705
1706 error = wldev_ioctl_set(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num));
1707 if (error) {
1708 DHD_ERROR(("%s: Failed to set Scan NProbes %d, error = %d\n",
1709 __FUNCTION__, num, error));
1710 return -1;
1711 }
1712
1713 return 0;
1714 }
1715
1716 int wl_android_get_scan_dfs_channel_mode(struct net_device *dev, char *command, int total_len)
1717 {
1718 int error = 0;
1719 int bytes_written = 0;
1720 int mode = 0;
1721 int scan_passive_time = 0;
1722
1723 error = wldev_iovar_getint(dev, "scan_passive_time", &scan_passive_time);
1724 if (error) {
1725 DHD_ERROR(("%s: Failed to get Passive Time, error = %d\n", __FUNCTION__, error));
1726 return -1;
1727 }
1728
1729 if (scan_passive_time == 0) {
1730 mode = 0;
1731 } else {
1732 mode = 1;
1733 }
1734
1735 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETDFSSCANMODE, mode);
1736
1737 return bytes_written;
1738 }
1739
1740 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command)
1741 {
1742 int error = 0;
1743 int mode = 0;
1744 int scan_passive_time = 0;
1745
1746 if (sscanf(command, "%*s %d", &mode) != 1) {
1747 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1748 return -1;
1749 }
1750
1751 if (mode == 1) {
1752 scan_passive_time = DHD_SCAN_PASSIVE_TIME;
1753 } else if (mode == 0) {
1754 scan_passive_time = 0;
1755 } else {
1756 DHD_ERROR(("%s: Failed to set Scan DFS channel mode %d, error = %d\n",
1757 __FUNCTION__, mode, error));
1758 return -1;
1759 }
1760 error = wldev_iovar_setint(dev, "scan_passive_time", scan_passive_time);
1761 if (error) {
1762 DHD_ERROR(("%s: Failed to set Scan Passive Time %d, error = %d\n",
1763 __FUNCTION__, scan_passive_time, error));
1764 return -1;
1765 }
1766
1767 return 0;
1768 }
1769
1770 #define JOINPREFFER_BUF_SIZE 12
1771
1772 static int
1773 wl_android_set_join_prefer(struct net_device *dev, char *command)
1774 {
1775 int error = BCME_OK;
1776 char smbuf[WLC_IOCTL_SMLEN];
1777 uint8 buf[JOINPREFFER_BUF_SIZE];
1778 char *pcmd;
1779 int total_len_left;
1780 int i;
1781 char hex[] = "XX";
1782 #ifdef WBTEXT
1783 char commandp[WLC_IOCTL_SMLEN];
1784 char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
1785 #endif /* WBTEXT */
1786
1787 pcmd = command + strlen(CMD_SETJOINPREFER) + 1;
1788 total_len_left = strlen(pcmd);
1789
1790 memset(buf, 0, sizeof(buf));
1791
1792 if (total_len_left != JOINPREFFER_BUF_SIZE << 1) {
1793 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1794 return BCME_ERROR;
1795 }
1796
1797 /* Store the MSB first, as required by join_pref */
1798 for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) {
1799 hex[0] = *pcmd++;
1800 hex[1] = *pcmd++;
1801 buf[i] = (uint8)simple_strtoul(hex, NULL, 16);
1802 }
1803
1804 #ifdef WBTEXT
1805 /* No coexistance between 11kv and join pref */
1806 if (wl_android_check_wbtext(dev)) {
1807 memset(commandp, 0, sizeof(commandp));
1808 if (memcmp(buf, clear, sizeof(buf)) == 0) {
1809 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 1");
1810 } else {
1811 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 0");
1812 }
1813 if ((error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN)) != BCME_OK) {
1814 DHD_ERROR(("Failed to set WBTEXT = %d\n", error));
1815 return error;
1816 }
1817 }
1818 #endif /* WBTEXT */
1819
1820 prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE);
1821 error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE,
1822 smbuf, sizeof(smbuf), NULL);
1823 if (error) {
1824 DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
1825 }
1826
1827 return error;
1828 }
1829
1830 int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len)
1831 {
1832 int error = -1;
1833 android_wifi_af_params_t *params = NULL;
1834 wl_action_frame_t *action_frame = NULL;
1835 wl_af_params_t *af_params = NULL;
1836 char *smbuf = NULL;
1837 struct ether_addr tmp_bssid;
1838 int tmp_channel = 0;
1839 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1840
1841 if (total_len <
1842 (strlen(CMD_SENDACTIONFRAME) + 1 + sizeof(android_wifi_af_params_t))) {
1843 DHD_ERROR(("%s: Invalid parameters \n", __FUNCTION__));
1844 goto send_action_frame_out;
1845 }
1846
1847 params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1);
1848
1849 if ((uint16)params->len > ANDROID_WIFI_ACTION_FRAME_SIZE) {
1850 DHD_ERROR(("%s: Requested action frame len was out of range(%d)\n",
1851 __FUNCTION__, params->len));
1852 goto send_action_frame_out;
1853 }
1854
1855 smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
1856 if (smbuf == NULL) {
1857 DHD_ERROR(("%s: failed to allocated memory %d bytes\n",
1858 __FUNCTION__, WLC_IOCTL_MAXLEN));
1859 goto send_action_frame_out;
1860 }
1861
1862 af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
1863 if (af_params == NULL) {
1864 DHD_ERROR(("%s: unable to allocate frame\n", __FUNCTION__));
1865 goto send_action_frame_out;
1866 }
1867
1868 memset(&tmp_bssid, 0, ETHER_ADDR_LEN);
1869 if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) {
1870 memset(&tmp_bssid, 0, ETHER_ADDR_LEN);
1871
1872 error = wldev_ioctl_get(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN);
1873 if (error) {
1874 memset(&tmp_bssid, 0, ETHER_ADDR_LEN);
1875 DHD_ERROR(("%s: failed to get bssid, error=%d\n", __FUNCTION__, error));
1876 goto send_action_frame_out;
1877 }
1878 }
1879
1880 if (params->channel < 0) {
1881 struct channel_info ci;
1882 memset(&ci, 0, sizeof(ci));
1883 error = wldev_ioctl_get(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
1884 if (error) {
1885 DHD_ERROR(("%s: failed to get channel, error=%d\n", __FUNCTION__, error));
1886 goto send_action_frame_out;
1887 }
1888
1889 tmp_channel = ci.hw_channel;
1890 }
1891 else {
1892 tmp_channel = params->channel;
1893 }
1894
1895 af_params->channel = tmp_channel;
1896 af_params->dwell_time = params->dwell_time;
1897 memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN);
1898 action_frame = &af_params->action_frame;
1899
1900 action_frame->packetId = 0;
1901 memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN);
1902 action_frame->len = (uint16)params->len;
1903 memcpy(action_frame->data, params->data, action_frame->len);
1904
1905 error = wldev_iovar_setbuf(dev, "actframe", af_params,
1906 sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1907 if (error) {
1908 DHD_ERROR(("%s: failed to set action frame, error=%d\n", __FUNCTION__, error));
1909 }
1910
1911 send_action_frame_out:
1912 if (af_params) {
1913 MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
1914 }
1915
1916 if (smbuf) {
1917 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
1918 }
1919
1920 if (error)
1921 return -1;
1922 else
1923 return 0;
1924 }
1925
1926 int wl_android_reassoc(struct net_device *dev, char *command, int total_len)
1927 {
1928 int error = 0;
1929 android_wifi_reassoc_params_t *params = NULL;
1930 uint band;
1931 chanspec_t channel;
1932 u32 params_size;
1933 wl_reassoc_params_t reassoc_params;
1934
1935 if (total_len <
1936 (strlen(CMD_REASSOC) + 1 + sizeof(android_wifi_reassoc_params_t))) {
1937 DHD_ERROR(("%s: Invalid parameters \n", __FUNCTION__));
1938 return -1;
1939 }
1940 params = (android_wifi_reassoc_params_t *)(command + strlen(CMD_REASSOC) + 1);
1941
1942 memset(&reassoc_params, 0, WL_REASSOC_PARAMS_FIXED_SIZE);
1943
1944 if (bcm_ether_atoe((const char *)params->bssid,
1945 (struct ether_addr *)&reassoc_params.bssid) == 0) {
1946 DHD_ERROR(("%s: Invalid bssid \n", __FUNCTION__));
1947 return -1;
1948 }
1949
1950 if (params->channel < 0) {
1951 DHD_ERROR(("%s: Invalid Channel \n", __FUNCTION__));
1952 return -1;
1953 }
1954
1955 reassoc_params.chanspec_num = 1;
1956
1957 channel = params->channel;
1958 #ifdef D11AC_IOTYPES
1959 if (wl_cfg80211_get_ioctl_version() == 1) {
1960 band = ((channel <= CH_MAX_2G_CHANNEL) ?
1961 WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G);
1962 reassoc_params.chanspec_list[0] = channel |
1963 band | WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
1964 }
1965 else {
1966 band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
1967 reassoc_params.chanspec_list[0] = channel | band | WL_CHANSPEC_BW_20;
1968 }
1969 #else
1970 band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
1971 reassoc_params.chanspec_list[0] = channel |
1972 band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
1973 #endif /* D11AC_IOTYPES */
1974 params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t);
1975
1976 error = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, params_size);
1977 if (error) {
1978 DHD_ERROR(("%s: failed to reassoc, error=%d\n", __FUNCTION__, error));
1979 return -1;
1980 }
1981 return 0;
1982 }
1983
1984 int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len)
1985 {
1986 int bytes_written = 0;
1987 int mode = 0;
1988
1989 mode = wl_cfg80211_get_wes_mode();
1990
1991 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode);
1992
1993 return bytes_written;
1994 }
1995
1996 int wl_android_set_wes_mode(struct net_device *dev, char *command)
1997 {
1998 int error = 0;
1999 int mode = 0;
2000 #ifdef WBTEXT
2001 char commandp[WLC_IOCTL_SMLEN];
2002 #endif /* WBTEXT */
2003
2004 if (sscanf(command, "%*s %d", &mode) != 1) {
2005 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
2006 return -1;
2007 }
2008
2009 error = wl_cfg80211_set_wes_mode(mode);
2010 if (error) {
2011 DHD_ERROR(("%s: Failed to set WES Mode %d, error = %d\n",
2012 __FUNCTION__, mode, error));
2013 return -1;
2014 }
2015
2016 #ifdef WBTEXT
2017 /* No coexistance between 11kv and FMC */
2018 if (wl_android_check_wbtext(dev)) {
2019 memset(commandp, 0, sizeof(commandp));
2020 if (!mode) {
2021 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 1");
2022 } else {
2023 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 0");
2024 }
2025 if ((error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN)) != BCME_OK) {
2026 DHD_ERROR(("Failed to set WBTEXT = %d\n", error));
2027 return error;
2028 }
2029 }
2030 #endif /* WBTEXT */
2031
2032 return 0;
2033 }
2034
2035 int wl_android_get_okc_mode(struct net_device *dev, char *command, int total_len)
2036 {
2037 int error = 0;
2038 int bytes_written = 0;
2039 int mode = 0;
2040
2041 error = wldev_iovar_getint(dev, "okc_enable", &mode);
2042 if (error) {
2043 DHD_ERROR(("%s: Failed to get OKC Mode, error = %d\n", __FUNCTION__, error));
2044 return -1;
2045 }
2046
2047 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETOKCMODE, mode);
2048
2049 return bytes_written;
2050 }
2051
2052 int wl_android_set_okc_mode(struct net_device *dev, char *command)
2053 {
2054 int error = 0;
2055 int mode = 0;
2056
2057 if (sscanf(command, "%*s %d", &mode) != 1) {
2058 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
2059 return -1;
2060 }
2061
2062 error = wldev_iovar_setint(dev, "okc_enable", mode);
2063 if (error) {
2064 DHD_ERROR(("%s: Failed to set OKC Mode %d, error = %d\n",
2065 __FUNCTION__, mode, error));
2066 return -1;
2067 }
2068
2069 return error;
2070 }
2071 static int
2072 wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
2073 {
2074 uchar pmk[33];
2075 int error = 0;
2076 char smbuf[WLC_IOCTL_SMLEN];
2077 #ifdef OKC_DEBUG
2078 int i = 0;
2079 #endif // endif
2080
2081 if (total_len < (strlen("SET_PMK ") + 32)) {
2082 DHD_ERROR(("%s: Invalid argument\n", __FUNCTION__));
2083 return -1;
2084 }
2085 bzero(pmk, sizeof(pmk));
2086 memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
2087 error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
2088 if (error) {
2089 DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
2090 }
2091 #ifdef OKC_DEBUG
2092 DHD_ERROR(("PMK is "));
2093 for (i = 0; i < 32; i++)
2094 DHD_ERROR(("%02X ", pmk[i]));
2095
2096 DHD_ERROR(("\n"));
2097 #endif // endif
2098 return error;
2099 }
2100
2101 static int
2102 wl_android_okc_enable(struct net_device *dev, char *command)
2103 {
2104 int error = 0;
2105 char okc_enable = 0;
2106
2107 okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
2108 error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
2109 if (error) {
2110 DHD_ERROR(("Failed to %s OKC, error = %d\n",
2111 okc_enable ? "enable" : "disable", error));
2112 }
2113
2114 return error;
2115 }
2116 #endif /* WES_SUPPORT */
2117 #ifdef WLTDLS
2118 int wl_android_tdls_reset(struct net_device *dev)
2119 {
2120 int ret = 0;
2121 ret = dhd_tdls_enable(dev, false, false, NULL);
2122 if (ret < 0) {
2123 DHD_ERROR(("Disable tdls failed. %d\n", ret));
2124 return ret;
2125 }
2126 ret = dhd_tdls_enable(dev, true, true, NULL);
2127 if (ret < 0) {
2128 DHD_ERROR(("enable tdls failed. %d\n", ret));
2129 return ret;
2130 }
2131 return 0;
2132 }
2133 #endif /* WLTDLS */
2134 #ifdef FCC_PWR_LIMIT_2G
2135 int
2136 wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command)
2137 {
2138 int error = 0;
2139 int enable = 0;
2140
2141 sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable);
2142
2143 if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) {
2144 DHD_ERROR(("%s: Invalid data\n", __FUNCTION__));
2145 return BCME_ERROR;
2146 }
2147
2148 CUSTOMER_HW4_EN_CONVERT(enable);
2149
2150 DHD_ERROR(("%s: fccpwrlimit2g set (%d)\n", __FUNCTION__, enable));
2151 error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
2152 if (error) {
2153 DHD_ERROR(("%s: fccpwrlimit2g set returned (%d)\n", __FUNCTION__, error));
2154 return BCME_ERROR;
2155 }
2156
2157 return error;
2158 }
2159
2160 int
2161 wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
2162 {
2163 int error = 0;
2164 int enable = 0;
2165 int bytes_written = 0;
2166
2167 error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable);
2168 if (error) {
2169 DHD_ERROR(("%s: fccpwrlimit2g get error (%d)\n", __FUNCTION__, error));
2170 return BCME_ERROR;
2171 }
2172 DHD_ERROR(("%s: fccpwrlimit2g get (%d)\n", __FUNCTION__, enable));
2173
2174 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable);
2175
2176 return bytes_written;
2177 }
2178 #endif /* FCC_PWR_LIMIT_2G */
2179
2180 s32
2181 wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
2182 {
2183 int bytes_written = -1, ret = 0;
2184 char *pcmd = command;
2185 char *str;
2186 sta_info_v4_t *sta = NULL;
2187 const wl_cnt_wlc_t* wlc_cnt = NULL;
2188 struct ether_addr mac;
2189 char *iovar_buf;
2190 /* Client information */
2191 uint16 cap = 0;
2192 uint32 rxrtry = 0;
2193 uint32 rxmulti = 0;
2194 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2195
2196 #ifdef BIGDATA_SOFTAP
2197 void *data = NULL;
2198 int get_bigdata_softap = FALSE;
2199 wl_ap_sta_data_t *sta_data = NULL;
2200 struct bcm_cfg80211 *bcm_cfg = wl_get_cfg(dev);
2201 #endif /* BIGDATA_SOFTAP */
2202
2203 WL_DBG(("%s\n", command));
2204
2205 iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
2206 if (iovar_buf == NULL) {
2207 DHD_ERROR(("%s: failed to allocated memory %d bytes\n",
2208 __FUNCTION__, WLC_IOCTL_MAXLEN));
2209 goto error;
2210 }
2211
2212 str = bcmstrtok(&pcmd, " ", NULL);
2213 if (str) {
2214 str = bcmstrtok(&pcmd, " ", NULL);
2215 /* If GETSTAINFO subcmd name is not provided, return error */
2216 if (str == NULL) {
2217 WL_ERR(("GETSTAINFO subcmd not provided %s\n", __FUNCTION__));
2218 goto error;
2219 }
2220
2221 memset(&mac, 0, ETHER_ADDR_LEN);
2222 if ((bcm_ether_atoe((str), &mac))) {
2223 /* get the sta info */
2224 ret = wldev_iovar_getbuf(dev, "sta_info",
2225 (struct ether_addr *)mac.octet,
2226 ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
2227 #ifdef BIGDATA_SOFTAP
2228 get_bigdata_softap = TRUE;
2229 #endif /* BIGDATA_SOFTAP */
2230 if (ret < 0) {
2231 WL_ERR(("Get sta_info ERR %d\n", ret));
2232 #ifndef BIGDATA_SOFTAP
2233 goto error;
2234 #else
2235 goto get_bigdata;
2236 #endif /* BIGDATA_SOFTAP */
2237 }
2238
2239 sta = (sta_info_v4_t *)iovar_buf;
2240 if (dtoh16(sta->ver) != WL_STA_VER_4) {
2241 WL_ERR(("sta_info struct version mismatch, "
2242 "host ver : %d, fw ver : %d\n", WL_STA_VER_4,
2243 dtoh16(sta->ver)));
2244 goto error;
2245 }
2246 cap = dtoh16(sta->cap);
2247 rxrtry = dtoh32(sta->rx_pkts_retried);
2248 rxmulti = dtoh32(sta->rx_mcast_pkts);
2249 } else if ((!strncmp(str, "all", 3)) || (!strncmp(str, "ALL", 3))) {
2250 /* get counters info */
2251 ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
2252 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2253 if (unlikely(ret)) {
2254 WL_ERR(("counters error (%d) - size = %zu\n",
2255 ret, sizeof(wl_cnt_wlc_t)));
2256 goto error;
2257 }
2258 ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
2259 if (ret != BCME_OK) {
2260 WL_ERR(("wl_cntbuf_to_xtlv_format ERR %d\n", ret));
2261 goto error;
2262 }
2263 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
2264 WL_ERR(("wlc_cnt NULL!\n"));
2265 goto error;
2266 }
2267
2268 rxrtry = dtoh32(wlc_cnt->rxrtry);
2269 rxmulti = dtoh32(wlc_cnt->rxmulti);
2270 } else {
2271 WL_ERR(("Get address fail\n"));
2272 goto error;
2273 }
2274 } else {
2275 WL_ERR(("Command ERR\n"));
2276 goto error;
2277 }
2278
2279 #ifdef BIGDATA_SOFTAP
2280 get_bigdata:
2281 if (get_bigdata_softap) {
2282 WL_ERR(("mac " MACDBG" \n", MAC2STRDBG((char*)&mac)));
2283 if (wl_get_ap_stadata(bcm_cfg, &mac, &data) == BCME_OK) {
2284 sta_data = (wl_ap_sta_data_t *)data;
2285 bytes_written = snprintf(command, total_len,
2286 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
2287 "CAP=%04x "MACOUI" %d %s %d %d %d %d %d %d\n",
2288 CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap,
2289 MACOUI2STR((char*)&sta_data->mac),
2290 sta_data->channel,
2291 wf_chspec_to_bw_str(sta_data->chanspec),
2292 sta_data->rssi, sta_data->rate,
2293 sta_data->mode_80211, sta_data->nss, sta_data->mimo,
2294 sta_data->reason_code);
2295 WL_ERR_KERN(("command %s\n", command));
2296 goto error;
2297 }
2298 }
2299 #endif /* BIGDATA_SOFTAP */
2300 bytes_written = snprintf(command, total_len,
2301 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x\n",
2302 CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap);
2303
2304 WL_DBG(("%s", command));
2305
2306 error:
2307 if (iovar_buf) {
2308 MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MAXLEN);
2309
2310 }
2311 return bytes_written;
2312 }
2313 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
2314
2315 #ifdef WBTEXT
2316 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
2317 {
2318 int error = BCME_OK, argc = 0;
2319 int data, bytes_written;
2320 int roam_trigger[2];
2321 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
2322
2323 argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
2324 if (!argc) {
2325 error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
2326 if (error) {
2327 DHD_ERROR(("%s: Failed to set wbtext error = %d\n",
2328 __FUNCTION__, error));
2329 return error;
2330 }
2331 bytes_written = snprintf(command, total_len, "WBTEXT %s\n",
2332 (data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)?
2333 "ENABLED" : "DISABLED");
2334 return bytes_written;
2335 } else {
2336 if (data) {
2337 data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT;
2338 }
2339
2340 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
2341 DHD_ERROR(("%s: Failed to set wbtext error = %d\n",
2342 __FUNCTION__, error));
2343 return error;
2344 }
2345
2346 if (data) {
2347 /* reset roam_prof when wbtext is on */
2348 if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) {
2349 return error;
2350 }
2351 dhdp->wbtext_support = TRUE;
2352 } else {
2353 /* reset legacy roam trigger when wbtext is off */
2354 roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE;
2355 roam_trigger[1] = WLC_BAND_ALL;
2356 if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
2357 sizeof(roam_trigger))) != BCME_OK) {
2358 DHD_ERROR(("%s: Failed to reset roam trigger = %d\n",
2359 __FUNCTION__, error));
2360 return error;
2361 }
2362 dhdp->wbtext_support = FALSE;
2363 }
2364 }
2365 return error;
2366 }
2367
2368 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
2369 char *command, int total_len)
2370 {
2371 int error = BCME_OK, argc = 0;
2372 int data, bytes_written;
2373
2374 argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data);
2375 if (!argc) {
2376 error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data);
2377 if (error) {
2378 WL_ERR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error));
2379 return error;
2380 }
2381 bytes_written = snprintf(command, total_len, "%d\n", data);
2382 return bytes_written;
2383 } else {
2384 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold",
2385 data)) != BCME_OK) {
2386 WL_ERR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error));
2387 return error;
2388 }
2389 }
2390 return error;
2391 }
2392
2393 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
2394 char *command, int total_len)
2395 {
2396 int error = BCME_OK, argc = 0;
2397 int data = 0, bytes_written;
2398
2399 argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data);
2400 if (!argc) {
2401 error = wldev_iovar_getint(dev, "wnm_btmdelta", &data);
2402 if (error) {
2403 WL_ERR(("Failed to get wnm_btmdelta (%d)\n", error));
2404 return error;
2405 }
2406 bytes_written = snprintf(command, total_len, "%d\n", data);
2407 return bytes_written;
2408 } else {
2409 if ((error = wldev_iovar_setint(dev, "wnm_btmdelta",
2410 data)) != BCME_OK) {
2411 WL_ERR(("Failed to set wnm_btmdelta (%d)\n", error));
2412 return error;
2413 }
2414 }
2415 return error;
2416 }
2417
2418 #endif /* WBTEXT */
2419
2420 #ifdef PNO_SUPPORT
2421 #define PNO_PARAM_SIZE 50
2422 #define VALUE_SIZE 50
2423 #define LIMIT_STR_FMT ("%50s %50s")
2424 static int
2425 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
2426 {
2427 int err = BCME_OK;
2428 uint i, tokens, len_remain;
2429 char *pos, *pos2, *token, *token2, *delim;
2430 char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
2431 struct dhd_pno_batch_params batch_params;
2432
2433 DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
2434 len_remain = total_len;
2435 if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) {
2436 pos = command + strlen(CMD_WLS_BATCHING) + 1;
2437 len_remain -= strlen(CMD_WLS_BATCHING) + 1;
2438 } else {
2439 WL_ERR(("%s: No arguments, total_len %d\n", __FUNCTION__, total_len));
2440 err = BCME_ERROR;
2441 goto exit;
2442 }
2443 memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params));
2444 if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
2445 if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) {
2446 pos += strlen(PNO_BATCHING_SET) + 1;
2447 } else {
2448 WL_ERR(("%s: %s missing arguments, total_len %d\n",
2449 __FUNCTION__, PNO_BATCHING_SET, total_len));
2450 err = BCME_ERROR;
2451 goto exit;
2452 }
2453 while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
2454 memset(param, 0, sizeof(param));
2455 memset(value, 0, sizeof(value));
2456 if (token == NULL || !*token)
2457 break;
2458 if (*token == '\0')
2459 continue;
2460 delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
2461 if (delim != NULL)
2462 *delim = ' ';
2463
2464 tokens = sscanf(token, LIMIT_STR_FMT, param, value);
2465 if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
2466 batch_params.scan_fr = simple_strtol(value, NULL, 0);
2467 DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr));
2468 } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
2469 batch_params.bestn = simple_strtol(value, NULL, 0);
2470 DHD_PNO(("bestn : %d\n", batch_params.bestn));
2471 } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
2472 batch_params.mscan = simple_strtol(value, NULL, 0);
2473 DHD_PNO(("mscan : %d\n", batch_params.mscan));
2474 } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
2475 i = 0;
2476 pos2 = value;
2477 tokens = sscanf(value, "<%s>", value);
2478 if (tokens != 1) {
2479 err = BCME_ERROR;
2480 DHD_ERROR(("%s : invalid format for channel"
2481 " <> params\n", __FUNCTION__));
2482 goto exit;
2483 }
2484 while ((token2 = strsep(&pos2,
2485 PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
2486 if (token2 == NULL || !*token2)
2487 break;
2488 if (*token2 == '\0')
2489 continue;
2490 if (*token2 == 'A' || *token2 == 'B') {
2491 batch_params.band = (*token2 == 'A')?
2492 WLC_BAND_5G : WLC_BAND_2G;
2493 DHD_PNO(("band : %s\n",
2494 (*token2 == 'A')? "A" : "B"));
2495 } else {
2496 if ((batch_params.nchan >= WL_NUMCHANNELS) ||
2497 (i >= WL_NUMCHANNELS)) {
2498 DHD_ERROR(("Too many nchan %d\n",
2499 batch_params.nchan));
2500 err = BCME_BUFTOOSHORT;
2501 goto exit;
2502 }
2503 batch_params.chan_list[i++] =
2504 simple_strtol(token2, NULL, 0);
2505 batch_params.nchan++;
2506 DHD_PNO(("channel :%d\n",
2507 batch_params.chan_list[i-1]));
2508 }
2509 }
2510 } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
2511 batch_params.rtt = simple_strtol(value, NULL, 0);
2512 DHD_PNO(("rtt : %d\n", batch_params.rtt));
2513 } else {
2514 DHD_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param));
2515 err = BCME_ERROR;
2516 goto exit;
2517 }
2518 }
2519 err = dhd_dev_pno_set_for_batch(dev, &batch_params);
2520 if (err < 0) {
2521 DHD_ERROR(("failed to configure batch scan\n"));
2522 } else {
2523 memset(command, 0, total_len);
2524 err = snprintf(command, total_len, "%d", err);
2525 }
2526 } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
2527 err = dhd_dev_pno_get_for_batch(dev, command, total_len);
2528 if (err < 0) {
2529 DHD_ERROR(("failed to getting batching results\n"));
2530 } else {
2531 err = strlen(command);
2532 }
2533 } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
2534 err = dhd_dev_pno_stop_for_batch(dev);
2535 if (err < 0) {
2536 DHD_ERROR(("failed to stop batching scan\n"));
2537 } else {
2538 memset(command, 0, total_len);
2539 err = snprintf(command, total_len, "OK");
2540 }
2541 } else {
2542 DHD_ERROR(("%s : unknown command\n", __FUNCTION__));
2543 err = BCME_ERROR;
2544 goto exit;
2545 }
2546 exit:
2547 return err;
2548 }
2549 #ifndef WL_SCHED_SCAN
2550 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
2551 {
2552 wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
2553 int res = -1;
2554 int nssid = 0;
2555 cmd_tlv_t *cmd_tlv_temp;
2556 char *str_ptr;
2557 int tlv_size_left;
2558 int pno_time = 0;
2559 int pno_repeat = 0;
2560 int pno_freq_expo_max = 0;
2561
2562 #ifdef PNO_SET_DEBUG
2563 int i;
2564 char pno_in_example[] = {
2565 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
2566 'S', '1', '2', '0',
2567 'S',
2568 0x05,
2569 'd', 'l', 'i', 'n', 'k',
2570 'S',
2571 0x04,
2572 'G', 'O', 'O', 'G',
2573 'T',
2574 '0', 'B',
2575 'R',
2576 '2',
2577 'M',
2578 '2',
2579 0x00
2580 };
2581 #endif /* PNO_SET_DEBUG */
2582 DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
2583
2584 if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
2585 DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
2586 goto exit_proc;
2587 }
2588 #ifdef PNO_SET_DEBUG
2589 memcpy(command, pno_in_example, sizeof(pno_in_example));
2590 total_len = sizeof(pno_in_example);
2591 #endif // endif
2592 str_ptr = command + strlen(CMD_PNOSETUP_SET);
2593 tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
2594
2595 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
2596 memset(ssids_local, 0, sizeof(ssids_local));
2597
2598 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
2599 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
2600 (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
2601
2602 str_ptr += sizeof(cmd_tlv_t);
2603 tlv_size_left -= sizeof(cmd_tlv_t);
2604
2605 if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
2606 MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
2607 DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
2608 goto exit_proc;
2609 } else {
2610 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
2611 DHD_ERROR(("%s scan duration corrupted field size %d\n",
2612 __FUNCTION__, tlv_size_left));
2613 goto exit_proc;
2614 }
2615 str_ptr++;
2616 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
2617 DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
2618
2619 if (str_ptr[0] != 0) {
2620 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
2621 DHD_ERROR(("%s pno repeat : corrupted field\n",
2622 __FUNCTION__));
2623 goto exit_proc;
2624 }
2625 str_ptr++;
2626 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
2627 DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
2628 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
2629 DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
2630 __FUNCTION__));
2631 goto exit_proc;
2632 }
2633 str_ptr++;
2634 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
2635 DHD_PNO(("%s: pno_freq_expo_max=%d\n",
2636 __FUNCTION__, pno_freq_expo_max));
2637 }
2638 }
2639 } else {
2640 DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
2641 goto exit_proc;
2642 }
2643
2644 res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
2645 pno_freq_expo_max, NULL, 0);
2646 exit_proc:
2647 return res;
2648 }
2649 #endif /* !WL_SCHED_SCAN */
2650 #endif /* PNO_SUPPORT */
2651
2652 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
2653 {
2654 int ret;
2655 struct ether_addr p2pdev_addr;
2656
2657 #define MAC_ADDR_STR_LEN 18
2658 if (total_len < MAC_ADDR_STR_LEN) {
2659 DHD_ERROR(("%s: buflen %d is less than p2p dev addr\n",
2660 __FUNCTION__, total_len));
2661 return -1;
2662 }
2663
2664 ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr);
2665 if (ret) {
2666 DHD_ERROR(("%s Failed to get p2p dev addr\n", __FUNCTION__));
2667 return -1;
2668 }
2669 return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr)));
2670 }
2671
2672 #ifdef BCMCCX
2673 static int wl_android_get_cckm_rn(struct net_device *dev, char *command)
2674 {
2675 int error, rn;
2676
2677 WL_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name));
2678
2679 error = wldev_iovar_getint(dev, "cckm_rn", &rn);
2680 if (unlikely(error)) {
2681 WL_ERR(("wl_android_get_cckm_rn error (%d)\n", error));
2682 return -1;
2683 }
2684 memcpy(command, &rn, sizeof(int));
2685
2686 return sizeof(int);
2687 }
2688
2689 static int
2690 wl_android_set_cckm_krk(struct net_device *dev, char *command, int total_len)
2691 {
2692 int error, key_len, skip_len;
2693 unsigned char key[CCKM_KRK_LEN + CCKM_BTK_LEN];
2694 char iovar_buf[WLC_IOCTL_SMLEN];
2695
2696 WL_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name));
2697
2698 skip_len = strlen("set cckm_krk")+1;
2699
2700 if (total_len < (skip_len + CCKM_KRK_LEN)) {
2701 return BCME_BADLEN;
2702 }
2703
2704 if (total_len >= skip_len + CCKM_KRK_LEN + CCKM_BTK_LEN) {
2705 key_len = CCKM_KRK_LEN + CCKM_BTK_LEN;
2706 } else {
2707 key_len = CCKM_KRK_LEN;
2708 }
2709
2710 memset(iovar_buf, 0, sizeof(iovar_buf));
2711 memcpy(key, command+skip_len, key_len);
2712
2713 WL_DBG(("CCKM KRK-BTK (%d/%d) :\n", key_len, total_len));
2714 if (wl_dbg_level & WL_DBG_DBG) {
2715 prhex(NULL, key, key_len);
2716 }
2717
2718 error = wldev_iovar_setbuf(dev, "cckm_krk", key, key_len,
2719 iovar_buf, WLC_IOCTL_SMLEN, NULL);
2720 if (unlikely(error)) {
2721 WL_ERR((" cckm_krk set error (%d)\n", error));
2722 return -1;
2723 }
2724 return 0;
2725 }
2726
2727 static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command, int total_len)
2728 {
2729 int error;
2730 u8 buf[WL_ASSOC_INFO_MAX];
2731 wl_assoc_info_t assoc_info;
2732 u32 resp_ies_len = 0;
2733 int bytes_written = 0;
2734
2735 WL_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name));
2736
2737 error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf, WL_ASSOC_INFO_MAX, NULL);
2738 if (unlikely(error)) {
2739 WL_ERR(("could not get assoc info (%d)\n", error));
2740 return -1;
2741 }
2742
2743 memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t));
2744 assoc_info.req_len = htod32(assoc_info.req_len);
2745 assoc_info.resp_len = htod32(assoc_info.resp_len);
2746 assoc_info.flags = htod32(assoc_info.flags);
2747
2748 if (assoc_info.resp_len) {
2749 resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp);
2750 }
2751
2752 if (total_len < (sizeof(u32) + resp_ies_len)) {
2753 WL_ERR(("%s: Insufficient memory, %d bytes\n",
2754 __FUNCTION__, total_len));
2755 return -1;
2756 }
2757 /* first 4 bytes are ie len */
2758 memcpy(command, &resp_ies_len, sizeof(u32));
2759 bytes_written = sizeof(u32);
2760
2761 /* get the association resp IE's if there are any */
2762 if (resp_ies_len) {
2763 error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0,
2764 buf, WL_ASSOC_INFO_MAX, NULL);
2765 if (unlikely(error)) {
2766 WL_ERR(("could not get assoc resp_ies (%d)\n", error));
2767 return -1;
2768 }
2769
2770 memcpy(command+sizeof(u32), buf, resp_ies_len);
2771 bytes_written += resp_ies_len;
2772 }
2773 return bytes_written;
2774 }
2775
2776 #endif /* BCMCCX */
2777
2778 int
2779 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
2780 {
2781 int i, j, match;
2782 int ret = 0;
2783 char mac_buf[MAX_NUM_OF_ASSOCLIST *
2784 sizeof(struct ether_addr) + sizeof(uint)] = {0};
2785 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
2786
2787 /* set filtering mode */
2788 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) {
2789 DHD_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret));
2790 return ret;
2791 }
2792 if (macmode != MACLIST_MODE_DISABLED) {
2793 /* set the MAC filter list */
2794 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
2795 sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
2796 DHD_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret));
2797 return ret;
2798 }
2799 /* get the current list of associated STAs */
2800 assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
2801 if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
2802 sizeof(mac_buf))) != 0) {
2803 DHD_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret));
2804 return ret;
2805 }
2806 /* do we have any STA associated? */
2807 if (assoc_maclist->count) {
2808 /* iterate each associated STA */
2809 for (i = 0; i < assoc_maclist->count; i++) {
2810 match = 0;
2811 /* compare with each entry */
2812 for (j = 0; j < maclist->count; j++) {
2813 DHD_INFO(("%s : associated="MACDBG " list="MACDBG "\n",
2814 __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet),
2815 MAC2STRDBG(maclist->ea[j].octet)));
2816 if (memcmp(assoc_maclist->ea[i].octet,
2817 maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
2818 match = 1;
2819 break;
2820 }
2821 }
2822 /* do conditional deauth */
2823 /* "if not in the allow list" or "if in the deny list" */
2824 if ((macmode == MACLIST_MODE_ALLOW && !match) ||
2825 (macmode == MACLIST_MODE_DENY && match)) {
2826 scb_val_t scbval;
2827
2828 scbval.val = htod32(1);
2829 memcpy(&scbval.ea, &assoc_maclist->ea[i],
2830 ETHER_ADDR_LEN);
2831 if ((ret = wldev_ioctl_set(dev,
2832 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
2833 &scbval, sizeof(scb_val_t))) != 0)
2834 DHD_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n",
2835 __FUNCTION__, ret));
2836 }
2837 }
2838 }
2839 }
2840 return ret;
2841 }
2842
2843 /*
2844 * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
2845 *
2846 */
2847 static int
2848 wl_android_set_mac_address_filter(struct net_device *dev, char* str)
2849 {
2850 int i;
2851 int ret = 0;
2852 int macnum = 0;
2853 int macmode = MACLIST_MODE_DISABLED;
2854 struct maclist *list;
2855 char eabuf[ETHER_ADDR_STR_LEN];
2856 const char *token;
2857 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2858
2859 /* string should look like below (macmode/macnum/maclist) */
2860 /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */
2861
2862 /* get the MAC filter mode */
2863 token = strsep((char**)&str, " ");
2864 if (!token) {
2865 return -1;
2866 }
2867 macmode = bcm_atoi(token);
2868
2869 if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
2870 DHD_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode));
2871 return -1;
2872 }
2873
2874 token = strsep((char**)&str, " ");
2875 if (!token) {
2876 return -1;
2877 }
2878 macnum = bcm_atoi(token);
2879 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
2880 DHD_ERROR(("%s : invalid number of MAC address entries %d\n",
2881 __FUNCTION__, macnum));
2882 return -1;
2883 }
2884 /* allocate memory for the MAC list */
2885 list = (struct maclist*) MALLOCZ(cfg->osh, sizeof(int) +
2886 sizeof(struct ether_addr) * macnum);
2887 if (!list) {
2888 DHD_ERROR(("%s : failed to allocate memory\n", __FUNCTION__));
2889 return -1;
2890 }
2891 /* prepare the MAC list */
2892 list->count = htod32(macnum);
2893 bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
2894 for (i = 0; i < list->count; i++) {
2895 token = strsep((char**)&str, " ");
2896 if (token == NULL) {
2897 DHD_ERROR(("%s : No mac address present\n", __FUNCTION__));
2898 ret = -EINVAL;
2899 goto exit;
2900 }
2901 strncpy(eabuf, token, ETHER_ADDR_STR_LEN - 1);
2902 if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
2903 DHD_ERROR(("%s : mac parsing err index=%d, addr=%s\n",
2904 __FUNCTION__, i, eabuf));
2905 list->count = i;
2906 break;
2907 }
2908 DHD_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf));
2909 }
2910 if (i == 0)
2911 goto exit;
2912
2913 /* set the list */
2914 if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
2915 DHD_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
2916
2917 exit:
2918 MFREE(cfg->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
2919
2920 return ret;
2921 }
2922
2923 /**
2924 * Global function definitions (declared in wl_android.h)
2925 */
2926
2927 int wl_android_wifi_on(struct net_device *dev)
2928 {
2929 int ret = 0;
2930 int retry = POWERUP_MAX_RETRY;
2931
2932 DHD_ERROR(("%s in\n", __FUNCTION__));
2933 if (!dev) {
2934 DHD_ERROR(("%s: dev is null\n", __FUNCTION__));
2935 return -EINVAL;
2936 }
2937
2938 dhd_net_if_lock(dev);
2939 if (!g_wifi_on) {
2940 do {
2941 dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
2942 #ifdef BCMSDIO
2943 ret = dhd_net_bus_resume(dev, 0);
2944 #endif /* BCMSDIO */
2945 #ifdef BCMPCIE
2946 ret = dhd_net_bus_devreset(dev, FALSE);
2947 #endif /* BCMPCIE */
2948 if (ret == 0) {
2949 break;
2950 }
2951 DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
2952 retry));
2953 #ifdef BCMPCIE
2954 dhd_net_bus_devreset(dev, TRUE);
2955 #endif /* BCMPCIE */
2956 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
2957 } while (retry-- > 0);
2958 if (ret != 0) {
2959 DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
2960 goto exit;
2961 }
2962 #ifdef BCMSDIO
2963 ret = dhd_net_bus_devreset(dev, FALSE);
2964 dhd_net_bus_resume(dev, 1);
2965 #endif /* BCMSDIO */
2966
2967 #ifndef BCMPCIE
2968 if (!ret) {
2969 if (dhd_dev_init_ioctl(dev) < 0) {
2970 ret = -EFAULT;
2971 }
2972 }
2973 #endif /* !BCMPCIE */
2974 g_wifi_on = TRUE;
2975 }
2976
2977 exit:
2978 dhd_net_if_unlock(dev);
2979
2980 return ret;
2981 }
2982
2983 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
2984 {
2985 int ret = 0;
2986
2987 DHD_ERROR(("%s in\n", __FUNCTION__));
2988 if (!dev) {
2989 DHD_TRACE(("%s: dev is null\n", __FUNCTION__));
2990 return -EINVAL;
2991 }
2992
2993 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
2994 ret = dhd_debug_uart_is_running(dev);
2995 if (ret) {
2996 DHD_ERROR(("%s - Debug UART App is running\n", __FUNCTION__));
2997 return -EBUSY;
2998 }
2999 #endif /* BCMPCIE && DHD_DEBUG_UART */
3000 dhd_net_if_lock(dev);
3001 if (g_wifi_on || on_failure) {
3002 #if defined(BCMSDIO) || defined(BCMPCIE)
3003 ret = dhd_net_bus_devreset(dev, TRUE);
3004 #ifdef BCMSDIO
3005 dhd_net_bus_suspend(dev);
3006 #endif /* BCMSDIO */
3007 #endif /* BCMSDIO || BCMPCIE */
3008 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
3009 g_wifi_on = FALSE;
3010 }
3011 dhd_net_if_unlock(dev);
3012
3013 return ret;
3014 }
3015
3016 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
3017 {
3018 if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
3019 return -1;
3020 return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
3021 }
3022
3023 #ifdef CONNECTION_STATISTICS
3024 static int
3025 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
3026 {
3027 int err;
3028 wl_chanim_stats_t *list;
3029 /* Parameter _and_ returned buffer of chanim_stats. */
3030 wl_chanim_stats_t param;
3031 u8 result[WLC_IOCTL_SMLEN];
3032 chanim_stats_t *stats;
3033
3034 memset(&param, 0, sizeof(param));
3035
3036 param.buflen = htod32(sizeof(wl_chanim_stats_t));
3037 param.count = htod32(WL_CHANIM_COUNT_ONE);
3038
3039 if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
3040 (char*)result, sizeof(result), 0)) < 0) {
3041 WL_ERR(("Failed to get chanim results %d \n", err));
3042 return err;
3043 }
3044
3045 list = (wl_chanim_stats_t*)result;
3046
3047 list->buflen = dtoh32(list->buflen);
3048 list->version = dtoh32(list->version);
3049 list->count = dtoh32(list->count);
3050
3051 if (list->buflen == 0) {
3052 list->version = 0;
3053 list->count = 0;
3054 } else if (list->version != WL_CHANIM_STATS_VERSION) {
3055 WL_ERR(("Sorry, firmware has wl_chanim_stats version %d "
3056 "but driver supports only version %d.\n",
3057 list->version, WL_CHANIM_STATS_VERSION));
3058 list->buflen = 0;
3059 list->count = 0;
3060 }
3061
3062 stats = list->stats;
3063 stats->glitchcnt = dtoh32(stats->glitchcnt);
3064 stats->badplcp = dtoh32(stats->badplcp);
3065 stats->chanspec = dtoh16(stats->chanspec);
3066 stats->timestamp = dtoh32(stats->timestamp);
3067 stats->chan_idle = dtoh32(stats->chan_idle);
3068
3069 WL_INFORM(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
3070 stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
3071 stats->timestamp));
3072
3073 *chan_idle = stats->chan_idle;
3074
3075 return (err);
3076 }
3077
3078 static int
3079 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
3080 {
3081 static char iovar_buf[WLC_IOCTL_MAXLEN];
3082 const wl_cnt_wlc_t* wlc_cnt = NULL;
3083 #ifndef DISABLE_IF_COUNTERS
3084 wl_if_stats_t* if_stats = NULL;
3085 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3086 #endif /* DISABLE_IF_COUNTERS */
3087
3088 int link_speed = 0;
3089 struct connection_stats *output;
3090 unsigned int bufsize = 0;
3091 int bytes_written = -1;
3092 int ret = 0;
3093
3094 WL_INFORM(("%s: enter Get Connection Stats\n", __FUNCTION__));
3095
3096 if (total_len <= 0) {
3097 WL_ERR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len));
3098 goto error;
3099 }
3100
3101 bufsize = total_len;
3102 if (bufsize < sizeof(struct connection_stats)) {
3103 WL_ERR(("%s: not enough buffer size, provided=%u, requires=%zu\n",
3104 __FUNCTION__, bufsize,
3105 sizeof(struct connection_stats)));
3106 goto error;
3107 }
3108
3109 output = (struct connection_stats *)command;
3110
3111 #ifndef DISABLE_IF_COUNTERS
3112 if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
3113 if (if_stats == NULL) {
3114 WL_ERR(("%s(%d): MALLOCZ failed\n", __FUNCTION__, __LINE__));
3115 goto error;
3116 }
3117 memset(if_stats, 0, sizeof(*if_stats));
3118
3119 if (FW_SUPPORTED(dhdp, ifst)) {
3120 ret = wl_cfg80211_ifstats_counters(dev, if_stats);
3121 } else {
3122 ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
3123 (char *)if_stats, sizeof(*if_stats), NULL);
3124 }
3125
3126 if (ret) {
3127 WL_ERR(("%s: if_counters not supported ret=%d\n",
3128 __FUNCTION__, ret));
3129
3130 /* In case if_stats IOVAR is not supported, get information from counters. */
3131 #endif /* DISABLE_IF_COUNTERS */
3132 ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
3133 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
3134 if (unlikely(ret)) {
3135 WL_ERR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
3136 goto error;
3137 }
3138 ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
3139 if (ret != BCME_OK) {
3140 WL_ERR(("%s wl_cntbuf_to_xtlv_format ERR %d\n",
3141 __FUNCTION__, ret));
3142 goto error;
3143 }
3144
3145 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
3146 WL_ERR(("%s wlc_cnt NULL!\n", __FUNCTION__));
3147 goto error;
3148 }
3149
3150 output->txframe = dtoh32(wlc_cnt->txframe);
3151 output->txbyte = dtoh32(wlc_cnt->txbyte);
3152 output->txerror = dtoh32(wlc_cnt->txerror);
3153 output->rxframe = dtoh32(wlc_cnt->rxframe);
3154 output->rxbyte = dtoh32(wlc_cnt->rxbyte);
3155 output->txfail = dtoh32(wlc_cnt->txfail);
3156 output->txretry = dtoh32(wlc_cnt->txretry);
3157 output->txretrie = dtoh32(wlc_cnt->txretrie);
3158 output->txrts = dtoh32(wlc_cnt->txrts);
3159 output->txnocts = dtoh32(wlc_cnt->txnocts);
3160 output->txexptime = dtoh32(wlc_cnt->txexptime);
3161 #ifndef DISABLE_IF_COUNTERS
3162 } else {
3163 /* Populate from if_stats. */
3164 if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
3165 WL_ERR(("%s: incorrect version of wl_if_stats_t, expected=%u got=%u\n",
3166 __FUNCTION__, WL_IF_STATS_T_VERSION, if_stats->version));
3167 goto error;
3168 }
3169
3170 output->txframe = (uint32)dtoh64(if_stats->txframe);
3171 output->txbyte = (uint32)dtoh64(if_stats->txbyte);
3172 output->txerror = (uint32)dtoh64(if_stats->txerror);
3173 output->rxframe = (uint32)dtoh64(if_stats->rxframe);
3174 output->rxbyte = (uint32)dtoh64(if_stats->rxbyte);
3175 output->txfail = (uint32)dtoh64(if_stats->txfail);
3176 output->txretry = (uint32)dtoh64(if_stats->txretry);
3177 output->txretrie = (uint32)dtoh64(if_stats->txretrie);
3178 if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
3179 output->txexptime = (uint32)dtoh64(if_stats->txexptime);
3180 output->txrts = (uint32)dtoh64(if_stats->txrts);
3181 output->txnocts = (uint32)dtoh64(if_stats->txnocts);
3182 } else {
3183 output->txexptime = 0;
3184 output->txrts = 0;
3185 output->txnocts = 0;
3186 }
3187 }
3188 #endif /* DISABLE_IF_COUNTERS */
3189
3190 /* link_speed is in kbps */
3191 ret = wldev_get_link_speed(dev, &link_speed);
3192 if (ret || link_speed < 0) {
3193 WL_ERR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n",
3194 __FUNCTION__, ret, link_speed));
3195 goto error;
3196 }
3197
3198 output->txrate = link_speed;
3199
3200 /* Channel idle ratio. */
3201 if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
3202 output->chan_idle = 0;
3203 };
3204
3205 bytes_written = sizeof(struct connection_stats);
3206
3207 error:
3208 #ifndef DISABLE_IF_COUNTERS
3209 if (if_stats) {
3210 MFREE(cfg->osh, if_stats, sizeof(*if_stats));
3211 }
3212 #endif /* DISABLE_IF_COUNTERS */
3213
3214 return bytes_written;
3215 }
3216 #endif /* CONNECTION_STATISTICS */
3217
3218 #ifdef WL_NATOE
3219 static int
3220 wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
3221 {
3222 int ret = BCME_ERROR;
3223 char *pcmd = command;
3224 char *str = NULL;
3225 wl_natoe_cmd_info_t cmd_info;
3226 const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
3227
3228 /* skip to cmd name after "natoe" */
3229 str = bcmstrtok(&pcmd, " ", NULL);
3230
3231 /* If natoe subcmd name is not provided, return error */
3232 if (*pcmd == '\0') {
3233 WL_ERR(("natoe subcmd not provided %s\n", __FUNCTION__));
3234 ret = -EINVAL;
3235 return ret;
3236 }
3237
3238 /* get the natoe command name to str */
3239 str = bcmstrtok(&pcmd, " ", NULL);
3240
3241 while (natoe_cmd->name != NULL) {
3242 if (strcmp(natoe_cmd->name, str) == 0) {
3243 /* dispacth cmd to appropriate handler */
3244 if (natoe_cmd->handler) {
3245 cmd_info.command = command;
3246 cmd_info.tot_len = total_len;
3247 ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
3248 }
3249 return ret;
3250 }
3251 natoe_cmd++;
3252 }
3253 return ret;
3254 }
3255
3256 static int
3257 wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
3258 {
3259 int res = BCME_OK;
3260 wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
3261 uint8 *command = cmd_info->command;
3262 uint16 total_len = cmd_info->tot_len;
3263 uint16 bytes_written = 0;
3264
3265 UNUSED_PARAMETER(len);
3266
3267 switch (type) {
3268
3269 case WL_NATOE_XTLV_ENABLE:
3270 {
3271 bytes_written = snprintf(command, total_len, "natoe: %s\n",
3272 *data?"enabled":"disabled");
3273 cmd_info->bytes_written = bytes_written;
3274 break;
3275 }
3276
3277 case WL_NATOE_XTLV_CONFIG_IPS:
3278 {
3279 wl_natoe_config_ips_t *config_ips;
3280 uint8 buf[16];
3281
3282 config_ips = (wl_natoe_config_ips_t *)data;
3283 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
3284 bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
3285 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
3286 bytes_written += snprintf(command + bytes_written, total_len,
3287 "sta netmask: %s\n", buf);
3288 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
3289 bytes_written += snprintf(command + bytes_written, total_len,
3290 "sta router ip: %s\n", buf);
3291 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
3292 bytes_written += snprintf(command + bytes_written, total_len,
3293 "sta dns ip: %s\n", buf);
3294 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
3295 bytes_written += snprintf(command + bytes_written, total_len,
3296 "ap ip: %s\n", buf);
3297 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
3298 bytes_written += snprintf(command + bytes_written, total_len,
3299 "ap netmask: %s\n", buf);
3300 cmd_info->bytes_written = bytes_written;
3301 break;
3302 }
3303
3304 case WL_NATOE_XTLV_CONFIG_PORTS:
3305 {
3306 wl_natoe_ports_config_t *ports_config;
3307
3308 ports_config = (wl_natoe_ports_config_t *)data;
3309 bytes_written = snprintf(command, total_len, "starting port num: %d\n",
3310 dtoh16(ports_config->start_port_num));
3311 bytes_written += snprintf(command + bytes_written, total_len,
3312 "number of ports: %d\n", dtoh16(ports_config->no_of_ports));
3313 cmd_info->bytes_written = bytes_written;
3314 break;
3315 }
3316
3317 case WL_NATOE_XTLV_DBG_STATS:
3318 {
3319 char *stats_dump = (char *)data;
3320
3321 bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
3322 cmd_info->bytes_written = bytes_written;
3323 break;
3324 }
3325
3326 case WL_NATOE_XTLV_TBL_CNT:
3327 {
3328 bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
3329 dtoh32(*(uint32 *)data));
3330 cmd_info->bytes_written = bytes_written;
3331 break;
3332 }
3333
3334 default:
3335 /* ignore */
3336 break;
3337 }
3338
3339 return res;
3340 }
3341
3342 /*
3343 * --- common for all natoe get commands ----
3344 */
3345 static int
3346 wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
3347 uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
3348 {
3349 /* for gets we only need to pass ioc header */
3350 wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
3351 int res;
3352
3353 /* send getbuf natoe iovar */
3354 res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
3355 buflen, NULL);
3356
3357 /* check the response buff */
3358 if ((res == BCME_OK)) {
3359 /* scans ioctl tlvbuf f& invokes the cbfn for processing */
3360 res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
3361 BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
3362
3363 if (res == BCME_OK) {
3364 res = cmd_info->bytes_written;
3365 }
3366 }
3367 else
3368 {
3369 DHD_ERROR(("%s: get command failed code %d\n", __FUNCTION__, res));
3370 res = BCME_ERROR;
3371 }
3372
3373 return res;
3374 }
3375
3376 static int
3377 wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
3378 char *command, wl_natoe_cmd_info_t *cmd_info)
3379 {
3380 int ret = BCME_OK;
3381 wl_natoe_ioc_t *natoe_ioc;
3382 char *pcmd = command;
3383 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
3384 uint16 buflen = WL_NATOE_IOC_BUFSZ;
3385 bcm_xtlv_t *pxtlv = NULL;
3386 char *ioctl_buf = NULL;
3387 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3388
3389 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
3390 if (!ioctl_buf) {
3391 WL_ERR(("ioctl memory alloc failed\n"));
3392 return -ENOMEM;
3393 }
3394
3395 /* alloc mem for ioctl headr + tlv data */
3396 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3397 if (!natoe_ioc) {
3398 WL_ERR(("ioctl header memory alloc failed\n"));
3399 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3400 return -ENOMEM;
3401 }
3402
3403 /* make up natoe cmd ioctl header */
3404 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3405 natoe_ioc->id = htod16(cmd->id);
3406 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
3407 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3408
3409 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3410 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3411 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
3412 WLC_IOCTL_MEDLEN, cmd_info);
3413 if (ret != BCME_OK) {
3414 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
3415 ret = -EINVAL;
3416 }
3417 } else { /* set */
3418 uint8 val = bcm_atoi(pcmd);
3419
3420 /* buflen is max tlv data we can write, it will be decremented as we pack */
3421 /* save buflen at start */
3422 uint16 buflen_at_start = buflen;
3423
3424 /* we'll adjust final ioc size at the end */
3425 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
3426 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
3427
3428 if (ret != BCME_OK) {
3429 ret = -EINVAL;
3430 goto exit;
3431 }
3432
3433 /* adjust iocsz to the end of last data record */
3434 natoe_ioc->len = (buflen_at_start - buflen);
3435 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
3436
3437 ret = wldev_iovar_setbuf(dev, "natoe",
3438 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3439 if (ret != BCME_OK) {
3440 WL_ERR(("Fail to set iovar %d\n", ret));
3441 ret = -EINVAL;
3442 }
3443 }
3444
3445 exit:
3446 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3447 MFREE(cfg->osh, natoe_ioc, iocsz);
3448
3449 return ret;
3450 }
3451
3452 static int
3453 wl_android_natoe_subcmd_config_ips(struct net_device *dev,
3454 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
3455 {
3456 int ret = BCME_OK;
3457 wl_natoe_config_ips_t config_ips;
3458 wl_natoe_ioc_t *natoe_ioc;
3459 char *pcmd = command;
3460 char *str;
3461 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
3462 uint16 buflen = WL_NATOE_IOC_BUFSZ;
3463 bcm_xtlv_t *pxtlv = NULL;
3464 char *ioctl_buf = NULL;
3465 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3466
3467 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
3468 if (!ioctl_buf) {
3469 WL_ERR(("ioctl memory alloc failed\n"));
3470 return -ENOMEM;
3471 }
3472
3473 /* alloc mem for ioctl headr + tlv data */
3474 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3475 if (!natoe_ioc) {
3476 WL_ERR(("ioctl header memory alloc failed\n"));
3477 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3478 return -ENOMEM;
3479 }
3480
3481 /* make up natoe cmd ioctl header */
3482 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3483 natoe_ioc->id = htod16(cmd->id);
3484 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
3485 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3486
3487 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3488 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3489 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
3490 WLC_IOCTL_MEDLEN, cmd_info);
3491 if (ret != BCME_OK) {
3492 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
3493 ret = -EINVAL;
3494 }
3495 } else { /* set */
3496 /* buflen is max tlv data we can write, it will be decremented as we pack */
3497 /* save buflen at start */
3498 uint16 buflen_at_start = buflen;
3499
3500 memset(&config_ips, 0, sizeof(config_ips));
3501
3502 str = bcmstrtok(&pcmd, " ", NULL);
3503 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
3504 WL_ERR(("Invalid STA IP addr %s\n", str));
3505 ret = -EINVAL;
3506 goto exit;
3507 }
3508
3509 str = bcmstrtok(&pcmd, " ", NULL);
3510 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
3511 WL_ERR(("Invalid STA netmask %s\n", str));
3512 ret = -EINVAL;
3513 goto exit;
3514 }
3515
3516 str = bcmstrtok(&pcmd, " ", NULL);
3517 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
3518 WL_ERR(("Invalid STA router IP addr %s\n", str));
3519 ret = -EINVAL;
3520 goto exit;
3521 }
3522
3523 str = bcmstrtok(&pcmd, " ", NULL);
3524 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
3525 WL_ERR(("Invalid STA DNS IP addr %s\n", str));
3526 ret = -EINVAL;
3527 goto exit;
3528 }
3529
3530 str = bcmstrtok(&pcmd, " ", NULL);
3531 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
3532 WL_ERR(("Invalid AP IP addr %s\n", str));
3533 ret = -EINVAL;
3534 goto exit;
3535 }
3536
3537 str = bcmstrtok(&pcmd, " ", NULL);
3538 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
3539 WL_ERR(("Invalid AP netmask %s\n", str));
3540 ret = -EINVAL;
3541 goto exit;
3542 }
3543
3544 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
3545 &buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
3546 &config_ips, BCM_XTLV_OPTION_ALIGN32);
3547
3548 if (ret != BCME_OK) {
3549 ret = -EINVAL;
3550 goto exit;
3551 }
3552
3553 /* adjust iocsz to the end of last data record */
3554 natoe_ioc->len = (buflen_at_start - buflen);
3555 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
3556
3557 ret = wldev_iovar_setbuf(dev, "natoe",
3558 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3559 if (ret != BCME_OK) {
3560 WL_ERR(("Fail to set iovar %d\n", ret));
3561 ret = -EINVAL;
3562 }
3563 }
3564
3565 exit:
3566 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3567 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
3568
3569 return ret;
3570 }
3571
3572 static int
3573 wl_android_natoe_subcmd_config_ports(struct net_device *dev,
3574 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
3575 {
3576 int ret = BCME_OK;
3577 wl_natoe_ports_config_t ports_config;
3578 wl_natoe_ioc_t *natoe_ioc;
3579 char *pcmd = command;
3580 char *str;
3581 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
3582 uint16 buflen = WL_NATOE_IOC_BUFSZ;
3583 bcm_xtlv_t *pxtlv = NULL;
3584 char *ioctl_buf = NULL;
3585 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3586
3587 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
3588 if (!ioctl_buf) {
3589 WL_ERR(("ioctl memory alloc failed\n"));
3590 return -ENOMEM;
3591 }
3592
3593 /* alloc mem for ioctl headr + tlv data */
3594 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3595 if (!natoe_ioc) {
3596 WL_ERR(("ioctl header memory alloc failed\n"));
3597 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3598 return -ENOMEM;
3599 }
3600
3601 /* make up natoe cmd ioctl header */
3602 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3603 natoe_ioc->id = htod16(cmd->id);
3604 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
3605 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3606
3607 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3608 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3609 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
3610 WLC_IOCTL_MEDLEN, cmd_info);
3611 if (ret != BCME_OK) {
3612 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
3613 ret = -EINVAL;
3614 }
3615 } else { /* set */
3616 /* buflen is max tlv data we can write, it will be decremented as we pack */
3617 /* save buflen at start */
3618 uint16 buflen_at_start = buflen;
3619
3620 memset(&ports_config, 0, sizeof(ports_config));
3621
3622 str = bcmstrtok(&pcmd, " ", NULL);
3623 if (!str) {
3624 WL_ERR(("Invalid port string %s\n", str));
3625 ret = -EINVAL;
3626 goto exit;
3627 }
3628 ports_config.start_port_num = htod16(bcm_atoi(str));
3629
3630 str = bcmstrtok(&pcmd, " ", NULL);
3631 if (!str) {
3632 WL_ERR(("Invalid port string %s\n", str));
3633 ret = -EINVAL;
3634 goto exit;
3635 }
3636 ports_config.no_of_ports = htod16(bcm_atoi(str));
3637
3638 if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
3639 NATOE_MAX_PORT_NUM) {
3640 WL_ERR(("Invalid port configuration\n"));
3641 ret = -EINVAL;
3642 goto exit;
3643 }
3644 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
3645 &buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
3646 &ports_config, BCM_XTLV_OPTION_ALIGN32);
3647
3648 if (ret != BCME_OK) {
3649 ret = -EINVAL;
3650 goto exit;
3651 }
3652
3653 /* adjust iocsz to the end of last data record */
3654 natoe_ioc->len = (buflen_at_start - buflen);
3655 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
3656
3657 ret = wldev_iovar_setbuf(dev, "natoe",
3658 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3659 if (ret != BCME_OK) {
3660 WL_ERR(("Fail to set iovar %d\n", ret));
3661 ret = -EINVAL;
3662 }
3663 }
3664
3665 exit:
3666 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3667 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
3668
3669 return ret;
3670 }
3671
3672 static int
3673 wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
3674 char *command, wl_natoe_cmd_info_t *cmd_info)
3675 {
3676 int ret = BCME_OK;
3677 wl_natoe_ioc_t *natoe_ioc;
3678 char *pcmd = command;
3679 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
3680 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
3681 uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
3682 bcm_xtlv_t *pxtlv = NULL;
3683 char *ioctl_buf = NULL;
3684 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3685
3686 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
3687 if (!ioctl_buf) {
3688 WL_ERR(("ioctl memory alloc failed\n"));
3689 return -ENOMEM;
3690 }
3691
3692 /* alloc mem for ioctl headr + tlv data */
3693 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3694 if (!natoe_ioc) {
3695 WL_ERR(("ioctl header memory alloc failed\n"));
3696 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
3697 return -ENOMEM;
3698 }
3699
3700 /* make up natoe cmd ioctl header */
3701 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3702 natoe_ioc->id = htod16(cmd->id);
3703 natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
3704 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3705
3706 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3707 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3708 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
3709 WLC_IOCTL_MAXLEN, cmd_info);
3710 if (ret != BCME_OK) {
3711 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
3712 ret = -EINVAL;
3713 }
3714 } else { /* set */
3715 uint8 val = bcm_atoi(pcmd);
3716
3717 /* buflen is max tlv data we can write, it will be decremented as we pack */
3718 /* save buflen at start */
3719 uint16 buflen_at_start = buflen;
3720
3721 /* we'll adjust final ioc size at the end */
3722 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
3723 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
3724
3725 if (ret != BCME_OK) {
3726 ret = -EINVAL;
3727 goto exit;
3728 }
3729
3730 /* adjust iocsz to the end of last data record */
3731 natoe_ioc->len = (buflen_at_start - buflen);
3732 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
3733
3734 ret = wldev_iovar_setbuf(dev, "natoe",
3735 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
3736 if (ret != BCME_OK) {
3737 WL_ERR(("Fail to set iovar %d\n", ret));
3738 ret = -EINVAL;
3739 }
3740 }
3741
3742 exit:
3743 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
3744 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
3745
3746 return ret;
3747 }
3748
3749 static int
3750 wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
3751 char *command, wl_natoe_cmd_info_t *cmd_info)
3752 {
3753 int ret = BCME_OK;
3754 wl_natoe_ioc_t *natoe_ioc;
3755 char *pcmd = command;
3756 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
3757 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
3758 uint16 buflen = WL_NATOE_IOC_BUFSZ;
3759 bcm_xtlv_t *pxtlv = NULL;
3760 char *ioctl_buf = NULL;
3761 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3762
3763 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
3764 if (!ioctl_buf) {
3765 WL_ERR(("ioctl memory alloc failed\n"));
3766 return -ENOMEM;
3767 }
3768
3769 /* alloc mem for ioctl headr + tlv data */
3770 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
3771 if (!natoe_ioc) {
3772 WL_ERR(("ioctl header memory alloc failed\n"));
3773 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3774 return -ENOMEM;
3775 }
3776
3777 /* make up natoe cmd ioctl header */
3778 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
3779 natoe_ioc->id = htod16(cmd->id);
3780 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
3781 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
3782
3783 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
3784 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
3785 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
3786 WLC_IOCTL_MEDLEN, cmd_info);
3787 if (ret != BCME_OK) {
3788 WL_ERR(("Fail to get iovar %s\n", __FUNCTION__));
3789 ret = -EINVAL;
3790 }
3791 } else { /* set */
3792 uint32 val = bcm_atoi(pcmd);
3793
3794 /* buflen is max tlv data we can write, it will be decremented as we pack */
3795 /* save buflen at start */
3796 uint16 buflen_at_start = buflen;
3797
3798 /* we'll adjust final ioc size at the end */
3799 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
3800 sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
3801
3802 if (ret != BCME_OK) {
3803 ret = -EINVAL;
3804 goto exit;
3805 }
3806
3807 /* adjust iocsz to the end of last data record */
3808 natoe_ioc->len = (buflen_at_start - buflen);
3809 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
3810
3811 ret = wldev_iovar_setbuf(dev, "natoe",
3812 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3813 if (ret != BCME_OK) {
3814 WL_ERR(("Fail to set iovar %d\n", ret));
3815 ret = -EINVAL;
3816 }
3817 }
3818
3819 exit:
3820 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3821 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
3822
3823 return ret;
3824 }
3825
3826 #endif /* WL_NATOE */
3827
3828 #ifdef CUSTOMER_HW4_PRIVATE_CMD
3829 #ifdef SUPPORT_AMPDU_MPDU_CMD
3830 /* CMD_AMPDU_MPDU */
3831 static int
3832 wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
3833 {
3834 int err = 0;
3835 int ampdu_mpdu;
3836
3837 ampdu_mpdu = bcm_atoi(string_num);
3838
3839 if (ampdu_mpdu > 32) {
3840 DHD_ERROR(("%s : ampdu_mpdu MAX value is 32.\n", __FUNCTION__));
3841 return -1;
3842 }
3843
3844 DHD_ERROR(("%s : ampdu_mpdu = %d\n", __FUNCTION__, ampdu_mpdu));
3845 err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
3846 if (err < 0) {
3847 DHD_ERROR(("%s : ampdu_mpdu set error. %d\n", __FUNCTION__, err));
3848 return -1;
3849 }
3850
3851 return 0;
3852 }
3853 #endif /* SUPPORT_AMPDU_MPDU_CMD */
3854 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
3855
3856 #if defined(WL_SUPPORT_AUTO_CHANNEL)
3857 /* SoftAP feature */
3858 #define APCS_BAND_2G_LEGACY1 20
3859 #define APCS_BAND_2G_LEGACY2 0
3860 #define APCS_BAND_AUTO "band=auto"
3861 #define APCS_BAND_2G "band=2g"
3862 #define APCS_BAND_5G "band=5g"
3863 #define APCS_MAX_2G_CHANNELS 11
3864 #define APCS_MAX_RETRY 10
3865 #define APCS_DEFAULT_2G_CH 1
3866 #define APCS_DEFAULT_5G_CH 149
3867 static int
3868 wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
3869 char* command, int total_len)
3870 {
3871 int channel = 0;
3872 int chosen = 0;
3873 int retry = 0;
3874 int ret = 0;
3875 int spect = 0;
3876 u8 *reqbuf = NULL;
3877 uint32 band = WLC_BAND_2G;
3878 uint32 buf_size;
3879 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3880
3881 if (cmd_str) {
3882 WL_INFORM(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
3883 if (strncmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
3884 band = WLC_BAND_AUTO;
3885 } else if (strncmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
3886 band = WLC_BAND_5G;
3887 } else if (strncmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
3888 band = WLC_BAND_2G;
3889 } else {
3890 /*
3891 * For backward compatibility: Some platforms used to issue argument 20 or 0
3892 * to enforce the 2G channel selection
3893 */
3894 channel = bcm_atoi(cmd_str);
3895 if ((channel == APCS_BAND_2G_LEGACY1) ||
3896 (channel == APCS_BAND_2G_LEGACY2)) {
3897 band = WLC_BAND_2G;
3898 } else {
3899 WL_ERR(("Invalid argument\n"));
3900 return -EINVAL;
3901 }
3902 }
3903 } else {
3904 /* If no argument is provided, default to 2G */
3905 WL_ERR(("No argument given default to 2.4G scan\n"));
3906 band = WLC_BAND_2G;
3907 }
3908 WL_INFORM(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
3909
3910 /* If STA is connected, return is STA channel, else ACS can be issued,
3911 * set spect to 0 and proceed with ACS
3912 */
3913 channel = wl_cfg80211_get_sta_channel(cfg);
3914 if (channel) {
3915 channel = (channel <= CH_MAX_2G_CHANNEL) ?
3916 channel : APCS_DEFAULT_2G_CH;
3917 goto done2;
3918 }
3919
3920 ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
3921 if (ret) {
3922 WL_ERR(("ACS: error getting the spect, ret=%d\n", ret));
3923 goto done;
3924 }
3925
3926 if (spect > 0) {
3927 ret = wl_cfg80211_set_spect(dev, 0);
3928 if (ret < 0) {
3929 WL_ERR(("ACS: error while setting spect, ret=%d\n", ret));
3930 goto done;
3931 }
3932 }
3933
3934 reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
3935 if (reqbuf == NULL) {
3936 WL_ERR(("failed to allocate chanspec buffer\n"));
3937 return -ENOMEM;
3938 }
3939
3940 if (band == WLC_BAND_AUTO) {
3941 WL_DBG(("ACS full channel scan \n"));
3942 reqbuf[0] = htod32(0);
3943 } else if (band == WLC_BAND_5G) {
3944 WL_DBG(("ACS 5G band scan \n"));
3945 if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
3946 WL_ERR(("ACS 5g chanspec retreival failed! \n"));
3947 goto done;
3948 }
3949 } else if (band == WLC_BAND_2G) {
3950 /*
3951 * If channel argument is not provided/ argument 20 is provided,
3952 * Restrict channel to 2GHz, 20MHz BW, No SB
3953 */
3954 WL_DBG(("ACS 2G band scan \n"));
3955 if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
3956 WL_ERR(("ACS 2g chanspec retreival failed! \n"));
3957 goto done;
3958 }
3959 } else {
3960 WL_ERR(("ACS: No band chosen\n"));
3961 goto done2;
3962 }
3963
3964 buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
3965 ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
3966 buf_size);
3967 if (ret < 0) {
3968 WL_ERR(("can't start auto channel scan, err = %d\n", ret));
3969 channel = 0;
3970 goto done;
3971 }
3972
3973 /* Wait for auto channel selection, max 3000 ms */
3974 if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) {
3975 OSL_SLEEP(500);
3976 } else {
3977 /*
3978 * Full channel scan at the minimum takes 1.2secs
3979 * even with parallel scan. max wait time: 3500ms
3980 */
3981 OSL_SLEEP(1000);
3982 }
3983
3984 retry = APCS_MAX_RETRY;
3985 while (retry--) {
3986 ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
3987 sizeof(chosen));
3988 if (ret < 0) {
3989 chosen = 0;
3990 } else {
3991 chosen = dtoh32(chosen);
3992 }
3993
3994 if (chosen) {
3995 int chosen_band;
3996 int apcs_band;
3997 #ifdef D11AC_IOTYPES
3998 if (wl_cfg80211_get_ioctl_version() == 1) {
3999 channel = LCHSPEC_CHANNEL((chanspec_t)chosen);
4000 } else {
4001 channel = CHSPEC_CHANNEL((chanspec_t)chosen);
4002 }
4003 #else
4004 channel = CHSPEC_CHANNEL((chanspec_t)chosen);
4005 #endif /* D11AC_IOTYPES */
4006 apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band;
4007 chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G;
4008 if (apcs_band == chosen_band) {
4009 WL_ERR(("selected channel = %d\n", channel));
4010 break;
4011 }
4012 }
4013 WL_DBG(("%d tried, ret = %d, chosen = 0x%x\n",
4014 (APCS_MAX_RETRY - retry), ret, chosen));
4015 OSL_SLEEP(250);
4016 }
4017
4018 done:
4019 if ((retry == 0) || (ret < 0)) {
4020 /* On failure, fallback to a default channel */
4021 if ((band == WLC_BAND_5G)) {
4022 channel = APCS_DEFAULT_5G_CH;
4023 } else {
4024 channel = APCS_DEFAULT_2G_CH;
4025 }
4026 WL_ERR(("ACS failed. Fall back to default channel (%d) \n", channel));
4027 }
4028 done2:
4029 if (spect > 0) {
4030 if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) {
4031 WL_ERR(("ACS: error while setting spect\n"));
4032 }
4033 }
4034
4035 if (reqbuf) {
4036 MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
4037 }
4038
4039 if (channel) {
4040 ret = snprintf(command, total_len, "%d", channel);
4041 WL_INFORM(("command result is %s \n", command));
4042 }
4043
4044 return ret;
4045 }
4046 #endif /* WL_SUPPORT_AUTO_CHANNEL */
4047
4048 #ifdef CUSTOMER_HW4_PRIVATE_CMD
4049 #ifdef SUPPORT_HIDDEN_AP
4050 static int
4051 wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
4052 {
4053 int max_assoc;
4054
4055 max_assoc = bcm_atoi(string_num);
4056 WL_INFORM(("HAPD_MAX_NUM_STA = %d\n", max_assoc));
4057 wldev_iovar_setint(dev, "maxassoc", max_assoc);
4058 WL_INFORM(("Conigured maxassoc = %d\n", max_assoc));
4059 return 1;
4060 }
4061
4062 static int
4063 wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
4064 {
4065 wlc_ssid_t ssid;
4066 s32 ret;
4067
4068 ssid.SSID_len = strlen(hapd_ssid);
4069 if (ssid.SSID_len == 0) {
4070 WL_ERR(("%s : No SSID\n", __FUNCTION__));
4071 return -1;
4072 }
4073 if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
4074 ssid.SSID_len = DOT11_MAX_SSID_LEN;
4075 WL_ERR(("%s : Too long SSID Length %zu\n", __FUNCTION__, strlen(hapd_ssid)));
4076 }
4077 bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
4078 DHD_INFO(("%s: HAPD_SSID = %s\n", __FUNCTION__, ssid.SSID));
4079 ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
4080 if (ret < 0) {
4081 WL_ERR(("%s : WLC_SET_SSID Error:%d\n", __FUNCTION__, ret));
4082 }
4083 return 1;
4084
4085 }
4086
4087 static int
4088 wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
4089 {
4090 int hide_ssid;
4091 int enable = 0;
4092
4093 hide_ssid = bcm_atoi(string_num);
4094 DHD_INFO(("%s: HAPD_HIDE_SSID = %d\n", __FUNCTION__, hide_ssid));
4095 if (hide_ssid)
4096 enable = 1;
4097 wldev_iovar_setint(dev, "closednet", enable);
4098 return 1;
4099 }
4100 #endif /* SUPPORT_HIDDEN_AP */
4101
4102 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
4103 static int
4104 wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
4105 {
4106 scb_val_t scbval;
4107 int error = 0;
4108
4109 DHD_INFO(("%s: deauth STA %s\n", __FUNCTION__, straddr));
4110
4111 /* Unspecified reason */
4112 scbval.val = htod32(1);
4113
4114 if (bcm_ether_atoe(straddr, &scbval.ea) == 0) {
4115 DHD_ERROR(("%s: Invalid station MAC Address!!!\n", __FUNCTION__));
4116 return -1;
4117 }
4118
4119 DHD_ERROR(("%s: deauth STA: "MACDBG " scb_val.val %d\n", __FUNCTION__,
4120 MAC2STRDBG(scbval.ea.octet), scbval.val));
4121
4122 error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
4123 sizeof(scb_val_t));
4124 if (error) {
4125 DHD_ERROR(("Fail to DEAUTH station, error = %d\n", error));
4126 }
4127
4128 return 1;
4129 }
4130 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
4131
4132 #ifdef SUPPORT_SET_LPC
4133 static int
4134 wl_android_set_lpc(struct net_device *dev, const char* string_num)
4135 {
4136 int lpc_enabled, ret;
4137 s32 val = 1;
4138
4139 lpc_enabled = bcm_atoi(string_num);
4140 DHD_INFO(("%s : HAPD_LPC_ENABLED = %d\n", __FUNCTION__, lpc_enabled));
4141
4142 ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
4143 if (ret < 0)
4144 DHD_ERROR(("WLC_DOWN error %d\n", ret));
4145
4146 wldev_iovar_setint(dev, "lpc", lpc_enabled);
4147
4148 ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
4149 if (ret < 0)
4150 DHD_ERROR(("WLC_UP error %d\n", ret));
4151
4152 return 1;
4153 }
4154 #endif /* SUPPORT_SET_LPC */
4155
4156 static int
4157 wl_android_ch_res_rl(struct net_device *dev, bool change)
4158 {
4159 int error = 0;
4160 s32 srl = 7;
4161 s32 lrl = 4;
4162 printk("%s enter\n", __FUNCTION__);
4163 if (change) {
4164 srl = 4;
4165 lrl = 2;
4166 }
4167
4168 BCM_REFERENCE(lrl);
4169
4170 error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
4171 if (error) {
4172 DHD_ERROR(("Failed to set SRL, error = %d\n", error));
4173 }
4174 #ifndef CUSTOM_LONG_RETRY_LIMIT
4175 error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
4176 if (error) {
4177 DHD_ERROR(("Failed to set LRL, error = %d\n", error));
4178 }
4179 #endif /* CUSTOM_LONG_RETRY_LIMIT */
4180 return error;
4181 }
4182
4183 #ifdef SUPPORT_LTECX
4184 #define DEFAULT_WLANRX_PROT 1
4185 #define DEFAULT_LTERX_PROT 0
4186 #define DEFAULT_LTETX_ADV 1200
4187
4188 static int
4189 wl_android_set_ltecx(struct net_device *dev, const char* string_num)
4190 {
4191 uint16 chan_bitmap;
4192 int ret;
4193
4194 chan_bitmap = bcm_strtoul(string_num, NULL, 16);
4195
4196 DHD_INFO(("%s : LTECOEX 0x%x\n", __FUNCTION__, chan_bitmap));
4197
4198 if (chan_bitmap) {
4199 ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
4200 if (ret < 0) {
4201 DHD_ERROR(("mws_coex_bitmap error %d\n", ret));
4202 }
4203
4204 ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT);
4205 if (ret < 0) {
4206 DHD_ERROR(("mws_wlanrx_prot error %d\n", ret));
4207 }
4208
4209 ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT);
4210 if (ret < 0) {
4211 DHD_ERROR(("mws_lterx_prot error %d\n", ret));
4212 }
4213
4214 ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV);
4215 if (ret < 0) {
4216 DHD_ERROR(("mws_ltetx_adv error %d\n", ret));
4217 }
4218 } else {
4219 ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
4220 if (ret < 0) {
4221 if (ret == BCME_UNSUPPORTED) {
4222 DHD_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n"));
4223 } else {
4224 DHD_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret));
4225 }
4226 }
4227 }
4228 return 1;
4229 }
4230 #endif /* SUPPORT_LTECX */
4231
4232 #ifdef WL_RELMCAST
4233 static int
4234 wl_android_rmc_enable(struct net_device *net, int rmc_enable)
4235 {
4236 int err;
4237
4238 err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
4239 if (err != BCME_OK) {
4240 DHD_ERROR(("%s: rmc_ackreq, error = %d\n", __FUNCTION__, err));
4241 }
4242 return err;
4243 }
4244
4245 static int
4246 wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
4247 {
4248 int error = BCME_OK;
4249 char smbuf[WLC_IOCTL_SMLEN];
4250 wl_rmc_entry_t rmc_entry;
4251 DHD_INFO(("%s: Set new RMC leader %s\n", __FUNCTION__, straddr));
4252
4253 memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t));
4254 if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
4255 if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
4256 DHD_INFO(("%s: Set auto leader selection mode\n", __FUNCTION__));
4257 memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t));
4258 } else {
4259 DHD_ERROR(("%s: No valid mac address provided\n",
4260 __FUNCTION__));
4261 return BCME_ERROR;
4262 }
4263 }
4264
4265 error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
4266 smbuf, sizeof(smbuf), NULL);
4267
4268 if (error != BCME_OK) {
4269 DHD_ERROR(("%s: Unable to set RMC leader, error = %d\n",
4270 __FUNCTION__, error));
4271 }
4272
4273 return error;
4274 }
4275
4276 static int wl_android_set_rmc_event(struct net_device *dev, char *command)
4277 {
4278 int err = 0;
4279 int pid = 0;
4280
4281 if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
4282 WL_ERR(("Failed to get Parameter from : %s\n", command));
4283 return -1;
4284 }
4285
4286 /* set pid, and if the event was happened, let's send a notification through netlink */
4287 wl_cfg80211_set_rmc_pid(dev, pid);
4288
4289 WL_DBG(("RMC pid=%d\n", pid));
4290
4291 return err;
4292 }
4293 #endif /* WL_RELMCAST */
4294
4295 int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
4296 {
4297 int error = 0;
4298 int bytes_written = 0;
4299 int mode = 0;
4300
4301 error = wldev_iovar_getint(dev, "scan_ps", &mode);
4302 if (error) {
4303 DHD_ERROR(("%s: Failed to get single core scan Mode, error = %d\n",
4304 __FUNCTION__, error));
4305 return -1;
4306 }
4307
4308 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
4309
4310 return bytes_written;
4311 }
4312
4313 int wl_android_set_singlecore_scan(struct net_device *dev, char *command)
4314 {
4315 int error = 0;
4316 int mode = 0;
4317
4318 if (sscanf(command, "%*s %d", &mode) != 1) {
4319 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
4320 return -1;
4321 }
4322
4323 error = wldev_iovar_setint(dev, "scan_ps", mode);
4324 if (error) {
4325 DHD_ERROR(("%s[1]: Failed to set Mode %d, error = %d\n",
4326 __FUNCTION__, mode, error));
4327 return -1;
4328 }
4329
4330 return error;
4331 }
4332 #ifdef TEST_TX_POWER_CONTROL
4333 static int
4334 wl_android_set_tx_power(struct net_device *dev, const char* string_num)
4335 {
4336 int err = 0;
4337 s32 dbm;
4338 enum nl80211_tx_power_setting type;
4339
4340 dbm = bcm_atoi(string_num);
4341
4342 if (dbm < -1) {
4343 DHD_ERROR(("%s: dbm is negative...\n", __FUNCTION__));
4344 return -EINVAL;
4345 }
4346
4347 if (dbm == -1)
4348 type = NL80211_TX_POWER_AUTOMATIC;
4349 else
4350 type = NL80211_TX_POWER_FIXED;
4351
4352 err = wl_set_tx_power(dev, type, dbm);
4353 if (unlikely(err)) {
4354 DHD_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
4355 return err;
4356 }
4357
4358 return 1;
4359 }
4360
4361 static int
4362 wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
4363 {
4364 int err;
4365 int bytes_written;
4366 s32 dbm = 0;
4367
4368 err = wl_get_tx_power(dev, &dbm);
4369 if (unlikely(err)) {
4370 DHD_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
4371 return err;
4372 }
4373
4374 bytes_written = snprintf(command, total_len, "%s %d",
4375 CMD_TEST_GET_TX_POWER, dbm);
4376
4377 DHD_ERROR(("%s: GET_TX_POWER: dBm=%d\n", __FUNCTION__, dbm));
4378
4379 return bytes_written;
4380 }
4381 #endif /* TEST_TX_POWER_CONTROL */
4382
4383 static int
4384 wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
4385 {
4386 int err = 0;
4387 int setval = 0;
4388 s32 mode = bcm_atoi(string_num);
4389
4390 /* As Samsung specific and their requirement, '0' means activate sarlimit
4391 * and '-1' means back to normal state (deactivate sarlimit)
4392 */
4393 if (mode >= 0 && mode < 3) {
4394 DHD_INFO(("%s: SAR limit control activated mode = %d\n", __FUNCTION__, mode));
4395 setval = mode + 1;
4396 } else if (mode == -1) {
4397 DHD_INFO(("%s: SAR limit control deactivated\n", __FUNCTION__));
4398 setval = 0;
4399 } else {
4400 return -EINVAL;
4401 }
4402
4403 err = wldev_iovar_setint(dev, "sar_enable", setval);
4404 if (unlikely(err)) {
4405 DHD_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
4406 return err;
4407 }
4408 return 1;
4409 }
4410
4411 #ifdef SUPPORT_SET_TID
4412 static int
4413 wl_android_set_tid(struct net_device *dev, char* command)
4414 {
4415 int err = BCME_ERROR;
4416 char *pos = command;
4417 char *token = NULL;
4418 uint8 mode = 0;
4419 uint32 uid = 0;
4420 uint8 prio = 0;
4421 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4422
4423 if (!dhdp) {
4424 WL_ERR(("dhd is NULL\n"));
4425 return err;
4426 }
4427
4428 WL_DBG(("%s: command[%s]\n", __FUNCTION__, command));
4429
4430 /* drop command */
4431 token = bcmstrtok(&pos, " ", NULL);
4432
4433 token = bcmstrtok(&pos, " ", NULL);
4434 if (!token) {
4435 WL_ERR(("Invalid arguments\n"));
4436 return err;
4437 }
4438
4439 mode = bcm_atoi(token);
4440
4441 if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) {
4442 WL_ERR(("Invalid arguments, mode %d\n", mode));
4443 return err;
4444 }
4445
4446 if (mode) {
4447 token = bcmstrtok(&pos, " ", NULL);
4448 if (!token) {
4449 WL_ERR(("Invalid arguments for target uid\n"));
4450 return err;
4451 }
4452
4453 uid = bcm_atoi(token);
4454
4455 token = bcmstrtok(&pos, " ", NULL);
4456 if (!token) {
4457 WL_ERR(("Invalid arguments for target tid\n"));
4458 return err;
4459 }
4460
4461 prio = bcm_atoi(token);
4462 if (prio >= 0 && prio <= MAXPRIO) {
4463 dhdp->tid_mode = mode;
4464 dhdp->target_uid = uid;
4465 dhdp->target_tid = prio;
4466 } else {
4467 WL_ERR(("Invalid arguments, prio %d\n", prio));
4468 return err;
4469 }
4470 } else {
4471 dhdp->tid_mode = SET_TID_OFF;
4472 dhdp->target_uid = 0;
4473 dhdp->target_tid = 0;
4474 }
4475
4476 WL_DBG(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__,
4477 dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid));
4478
4479 err = BCME_OK;
4480 return err;
4481 }
4482
4483 static int
4484 wl_android_get_tid(struct net_device *dev, char* command, int total_len)
4485 {
4486 int bytes_written = BCME_ERROR;
4487 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4488
4489 if (!dhdp) {
4490 WL_ERR(("dhd is NULL\n"));
4491 return bytes_written;
4492 }
4493
4494 bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d",
4495 dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid);
4496
4497 WL_DBG(("%s: command results %s\n", __FUNCTION__, command));
4498
4499 return bytes_written;
4500 }
4501 #endif /* SUPPORT_SET_TID */
4502 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
4503
4504 int wl_android_set_roam_mode(struct net_device *dev, char *command)
4505 {
4506 int error = 0;
4507 int mode = 0;
4508
4509 if (sscanf(command, "%*s %d", &mode) != 1) {
4510 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
4511 return -1;
4512 }
4513
4514 error = wldev_iovar_setint(dev, "roam_off", mode);
4515 if (error) {
4516 DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
4517 __FUNCTION__, mode, error));
4518 return -1;
4519 }
4520 else
4521 DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
4522 __FUNCTION__, mode, error));
4523 return 0;
4524 }
4525
4526 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
4527 {
4528 char ie_buf[VNDR_IE_MAX_LEN];
4529 char *ioctl_buf = NULL;
4530 char hex[] = "XX";
4531 char *pcmd = NULL;
4532 int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
4533 vndr_ie_setbuf_t *vndr_ie = NULL;
4534 s32 iecount;
4535 uint32 pktflag;
4536 s32 err = BCME_OK, bssidx;
4537 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4538
4539 /* Check the VSIE (Vendor Specific IE) which was added.
4540 * If exist then send IOVAR to delete it
4541 */
4542 if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
4543 return -EINVAL;
4544 }
4545
4546 if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
4547 WL_ERR(("error. total_len:%d\n", total_len));
4548 return -EINVAL;
4549 }
4550
4551 pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
4552 for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
4553 if (*pcmd == '\0') {
4554 WL_ERR(("error while parsing OUI.\n"));
4555 return -EINVAL;
4556 }
4557 hex[0] = *pcmd++;
4558 hex[1] = *pcmd++;
4559 ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16);
4560 }
4561 pcmd++;
4562 while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
4563 hex[0] = *pcmd++;
4564 hex[1] = *pcmd++;
4565 ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16);
4566 datalen++;
4567 }
4568
4569 if (datalen <= 0) {
4570 WL_ERR(("error. vndr ie len:%d\n", datalen));
4571 return -EINVAL;
4572 }
4573
4574 tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
4575 vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
4576 if (!vndr_ie) {
4577 WL_ERR(("IE memory alloc failed\n"));
4578 return -ENOMEM;
4579 }
4580 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
4581 strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1);
4582 vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
4583
4584 /* Set the IE count - the buffer contains only 1 IE */
4585 iecount = htod32(1);
4586 memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
4587
4588 /* Set packet flag to indicate that BEACON's will contain this IE */
4589 pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
4590 memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
4591 sizeof(u32));
4592 /* Set the IE ID */
4593 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
4594
4595 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
4596 DOT11_OUI_LEN);
4597 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
4598 &ie_buf[DOT11_OUI_LEN], datalen);
4599
4600 ielen = DOT11_OUI_LEN + datalen;
4601 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
4602
4603 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
4604 if (!ioctl_buf) {
4605 WL_ERR(("ioctl memory alloc failed\n"));
4606 if (vndr_ie) {
4607 MFREE(cfg->osh, vndr_ie, tot_len);
4608 }
4609 return -ENOMEM;
4610 }
4611 memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
4612 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4613 WL_ERR(("Find index failed\n"));
4614 err = BCME_ERROR;
4615 goto end;
4616 }
4617 err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
4618 WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
4619 end:
4620 if (err != BCME_OK) {
4621 err = -EINVAL;
4622 if (vndr_ie) {
4623 MFREE(cfg->osh, vndr_ie, tot_len);
4624 }
4625 }
4626 else {
4627 /* do NOT free 'vndr_ie' for the next process */
4628 wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
4629 }
4630
4631 if (ioctl_buf) {
4632 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4633 }
4634
4635 return err;
4636 }
4637
4638 #if defined(BCMFW_ROAM_ENABLE)
4639 static int
4640 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
4641 {
4642 int error = 0;
4643 char smbuf[WLC_IOCTL_SMLEN];
4644 uint8 buf[MAX_BUF_SIZE];
4645 uint8 *pref = buf;
4646 char *pcmd;
4647 int num_ucipher_suites = 0;
4648 int num_akm_suites = 0;
4649 wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
4650 wpa_suite_t akm_suites[MAX_NUM_SUITES];
4651 int num_tuples = 0;
4652 int total_bytes = 0;
4653 int total_len_left;
4654 int i, j;
4655 char hex[] = "XX";
4656
4657 pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
4658 total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
4659
4660 num_akm_suites = simple_strtoul(pcmd, NULL, 16);
4661 if (num_akm_suites > MAX_NUM_SUITES) {
4662 DHD_ERROR(("too many AKM suites = %d\n", num_akm_suites));
4663 return -1;
4664 }
4665
4666 /* Increment for number of AKM suites field + space */
4667 pcmd += 3;
4668 total_len_left -= 3;
4669
4670 /* check to make sure pcmd does not overrun */
4671 if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
4672 return -1;
4673
4674 memset(buf, 0, sizeof(buf));
4675 memset(akm_suites, 0, sizeof(akm_suites));
4676 memset(ucipher_suites, 0, sizeof(ucipher_suites));
4677
4678 /* Save the AKM suites passed in the command */
4679 for (i = 0; i < num_akm_suites; i++) {
4680 /* Store the MSB first, as required by join_pref */
4681 for (j = 0; j < 4; j++) {
4682 hex[0] = *pcmd++;
4683 hex[1] = *pcmd++;
4684 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
4685 }
4686 memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
4687 }
4688
4689 total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
4690 num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
4691 /* Increment for number of cipher suites field + space */
4692 pcmd += 3;
4693 total_len_left -= 3;
4694
4695 if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
4696 return -1;
4697
4698 /* Save the cipher suites passed in the command */
4699 for (i = 0; i < num_ucipher_suites; i++) {
4700 /* Store the MSB first, as required by join_pref */
4701 for (j = 0; j < 4; j++) {
4702 hex[0] = *pcmd++;
4703 hex[1] = *pcmd++;
4704 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
4705 }
4706 memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
4707 }
4708
4709 /* Join preference for RSSI
4710 * Type : 1 byte (0x01)
4711 * Length : 1 byte (0x02)
4712 * Value : 2 bytes (reserved)
4713 */
4714 *pref++ = WL_JOIN_PREF_RSSI;
4715 *pref++ = JOIN_PREF_RSSI_LEN;
4716 *pref++ = 0;
4717 *pref++ = 0;
4718
4719 /* Join preference for WPA
4720 * Type : 1 byte (0x02)
4721 * Length : 1 byte (not used)
4722 * Value : (variable length)
4723 * reserved: 1 byte
4724 * count : 1 byte (no of tuples)
4725 * Tuple1 : 12 bytes
4726 * akm[4]
4727 * ucipher[4]
4728 * mcipher[4]
4729 * Tuple2 : 12 bytes
4730 * Tuplen : 12 bytes
4731 */
4732 num_tuples = num_akm_suites * num_ucipher_suites;
4733 if (num_tuples != 0) {
4734 if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
4735 *pref++ = WL_JOIN_PREF_WPA;
4736 *pref++ = 0;
4737 *pref++ = 0;
4738 *pref++ = (uint8)num_tuples;
4739 total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
4740 (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
4741 } else {
4742 DHD_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
4743 return -1;
4744 }
4745 } else {
4746 /* No WPA config, configure only RSSI preference */
4747 total_bytes = JOIN_PREF_RSSI_SIZE;
4748 }
4749
4750 /* akm-ucipher-mcipher tuples in the format required for join_pref */
4751 for (i = 0; i < num_ucipher_suites; i++) {
4752 for (j = 0; j < num_akm_suites; j++) {
4753 memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
4754 pref += WPA_SUITE_LEN;
4755 memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
4756 pref += WPA_SUITE_LEN;
4757 /* Set to 0 to match any available multicast cipher */
4758 memset(pref, 0, WPA_SUITE_LEN);
4759 pref += WPA_SUITE_LEN;
4760 }
4761 }
4762
4763 prhex("join pref", (uint8 *)buf, total_bytes);
4764 error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
4765 if (error) {
4766 DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
4767 }
4768 return error;
4769 }
4770 #endif /* defined(BCMFW_ROAM_ENABLE */
4771
4772 static int
4773 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
4774 {
4775 struct io_cfg *resume_cfg;
4776 s32 ret;
4777 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4778
4779 resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
4780 if (!resume_cfg)
4781 return -ENOMEM;
4782
4783 if (config->iovar) {
4784 ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
4785 if (ret) {
4786 DHD_ERROR(("%s: Failed to get current %s value\n",
4787 __FUNCTION__, config->iovar));
4788 goto error;
4789 }
4790
4791 ret = wldev_iovar_setint(dev, config->iovar, config->param);
4792 if (ret) {
4793 DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
4794 config->iovar, config->param));
4795 goto error;
4796 }
4797
4798 resume_cfg->iovar = config->iovar;
4799 } else {
4800 resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
4801 if (!resume_cfg->arg) {
4802 ret = -ENOMEM;
4803 goto error;
4804 }
4805 ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
4806 if (ret) {
4807 DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
4808 config->ioctl));
4809 goto error;
4810 }
4811 ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
4812 if (ret) {
4813 DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
4814 config->iovar, config->param));
4815 goto error;
4816 }
4817 if (config->ioctl + 1 == WLC_SET_PM)
4818 wl_cfg80211_update_power_mode(dev);
4819 resume_cfg->ioctl = config->ioctl;
4820 resume_cfg->len = config->len;
4821 }
4822
4823 list_add(&resume_cfg->list, head);
4824
4825 return 0;
4826 error:
4827 MFREE(cfg->osh, resume_cfg->arg, config->len);
4828 MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
4829 return ret;
4830 }
4831
4832 static void
4833 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
4834 {
4835 struct io_cfg *config;
4836 struct list_head *cur, *q;
4837 s32 ret = 0;
4838 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4839
4840 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
4841 #pragma GCC diagnostic push
4842 #pragma GCC diagnostic ignored "-Wcast-qual"
4843 #endif // endif
4844 list_for_each_safe(cur, q, head) {
4845 config = list_entry(cur, struct io_cfg, list);
4846 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
4847 #pragma GCC diagnostic pop
4848 #endif // endif
4849 if (config->iovar) {
4850 if (!ret)
4851 ret = wldev_iovar_setint(dev, config->iovar,
4852 config->param);
4853 } else {
4854 if (!ret)
4855 ret = wldev_ioctl_set(dev, config->ioctl + 1,
4856 config->arg, config->len);
4857 if (config->ioctl + 1 == WLC_SET_PM)
4858 wl_cfg80211_update_power_mode(dev);
4859 MFREE(cfg->osh, config->arg, config->len);
4860 }
4861 list_del(cur);
4862 MFREE(cfg->osh, config, sizeof(struct io_cfg));
4863 }
4864 }
4865 static int
4866 wl_android_set_miracast(struct net_device *dev, char *command)
4867 {
4868 int mode, val = 0;
4869 int ret = 0;
4870 struct io_cfg config;
4871
4872 if (sscanf(command, "%*s %d", &mode) != 1) {
4873 DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
4874 return -1;
4875 }
4876
4877 DHD_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
4878
4879 if (miracast_cur_mode == mode) {
4880 return 0;
4881 }
4882
4883 wl_android_iolist_resume(dev, &miracast_resume_list);
4884 miracast_cur_mode = MIRACAST_MODE_OFF;
4885 memset((void *)&config, 0, sizeof(config));
4886 switch (mode) {
4887 case MIRACAST_MODE_SOURCE:
4888 #ifdef MIRACAST_MCHAN_ALGO
4889 /* setting mchan_algo to platform specific value */
4890 config.iovar = "mchan_algo";
4891
4892 ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
4893 if (!ret && val > 100) {
4894 config.param = 0;
4895 DHD_ERROR(("%s: Connected station's beacon interval: "
4896 "%d and set mchan_algo to %d \n",
4897 __FUNCTION__, val, config.param));
4898 } else {
4899 config.param = MIRACAST_MCHAN_ALGO;
4900 }
4901 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
4902 if (ret) {
4903 goto resume;
4904 }
4905 #endif /* MIRACAST_MCHAN_ALGO */
4906
4907 #ifdef MIRACAST_MCHAN_BW
4908 /* setting mchan_bw to platform specific value */
4909 config.iovar = "mchan_bw";
4910 config.param = MIRACAST_MCHAN_BW;
4911 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
4912 if (ret) {
4913 goto resume;
4914 }
4915 #endif /* MIRACAST_MCHAN_BW */
4916
4917 #ifdef MIRACAST_AMPDU_SIZE
4918 /* setting apmdu to platform specific value */
4919 config.iovar = "ampdu_mpdu";
4920 config.param = MIRACAST_AMPDU_SIZE;
4921 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
4922 if (ret) {
4923 goto resume;
4924 }
4925 #endif /* MIRACAST_AMPDU_SIZE */
4926 /* FALLTROUGH */
4927 /* Source mode shares most configurations with sink mode.
4928 * Fall through here to avoid code duplication
4929 */
4930 case MIRACAST_MODE_SINK:
4931 /* disable internal roaming */
4932 config.iovar = "roam_off";
4933 config.param = 1;
4934 config.arg = NULL;
4935 config.len = 0;
4936 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
4937 if (ret) {
4938 goto resume;
4939 }
4940
4941 /* tunr off pm */
4942 ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
4943 if (ret) {
4944 goto resume;
4945 }
4946
4947 if (val != PM_OFF) {
4948 val = PM_OFF;
4949 config.iovar = NULL;
4950 config.ioctl = WLC_GET_PM;
4951 config.arg = &val;
4952 config.len = sizeof(int);
4953 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
4954 if (ret) {
4955 goto resume;
4956 }
4957 }
4958 break;
4959 case MIRACAST_MODE_OFF:
4960 default:
4961 break;
4962 }
4963 miracast_cur_mode = mode;
4964
4965 return 0;
4966
4967 resume:
4968 DHD_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
4969 wl_android_iolist_resume(dev, &miracast_resume_list);
4970 return ret;
4971 }
4972
4973 #define NETLINK_OXYGEN 30
4974 #define AIBSS_BEACON_TIMEOUT 10
4975
4976 static struct sock *nl_sk = NULL;
4977
4978 static void wl_netlink_recv(struct sk_buff *skb)
4979 {
4980 WL_ERR(("netlink_recv called\n"));
4981 }
4982
4983 static int wl_netlink_init(void)
4984 {
4985 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
4986 struct netlink_kernel_cfg cfg = {
4987 .input = wl_netlink_recv,
4988 };
4989 #endif // endif
4990
4991 if (nl_sk != NULL) {
4992 WL_ERR(("nl_sk already exist\n"));
4993 return BCME_ERROR;
4994 }
4995
4996 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
4997 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
4998 0, wl_netlink_recv, NULL, THIS_MODULE);
4999 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
5000 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
5001 #else
5002 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
5003 #endif // endif
5004
5005 if (nl_sk == NULL) {
5006 WL_ERR(("nl_sk is not ready\n"));
5007 return BCME_ERROR;
5008 }
5009
5010 return BCME_OK;
5011 }
5012
5013 static void wl_netlink_deinit(void)
5014 {
5015 if (nl_sk) {
5016 netlink_kernel_release(nl_sk);
5017 nl_sk = NULL;
5018 }
5019 }
5020
5021 s32
5022 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
5023 {
5024 struct sk_buff *skb = NULL;
5025 struct nlmsghdr *nlh = NULL;
5026 int ret = -1;
5027
5028 if (nl_sk == NULL) {
5029 WL_ERR(("nl_sk was not initialized\n"));
5030 goto nlmsg_failure;
5031 }
5032
5033 skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
5034 if (skb == NULL) {
5035 WL_ERR(("failed to allocate memory\n"));
5036 goto nlmsg_failure;
5037 }
5038
5039 nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
5040 if (nlh == NULL) {
5041 WL_ERR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
5042 skb_tailroom(skb), nlmsg_total_size(size)));
5043 dev_kfree_skb(skb);
5044 goto nlmsg_failure;
5045 }
5046
5047 memcpy(nlmsg_data(nlh), data, size);
5048 nlh->nlmsg_seq = seq;
5049 nlh->nlmsg_type = type;
5050
5051 /* netlink_unicast() takes ownership of the skb and frees it itself. */
5052 ret = netlink_unicast(nl_sk, skb, pid, 0);
5053 WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
5054
5055 nlmsg_failure:
5056 return ret;
5057 }
5058
5059 #ifdef WLAIBSS
5060 static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
5061 {
5062 int err = 0;
5063 int retry = 0;
5064 int pid = 0;
5065 aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0};
5066 char smbuf[WLC_IOCTL_SMLEN];
5067
5068 if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
5069 WL_ERR(("Failed to get Parameter from : %s\n", command));
5070 return -1;
5071 }
5072
5073 /* set pid, and if the event was happened, let's send a notification through netlink */
5074 wl_cfg80211_set_txfail_pid(dev, pid);
5075
5076 #ifdef WL_RELMCAST
5077 /* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */
5078 wl_cfg80211_set_rmc_pid(dev, pid);
5079 #endif /* WL_RELMCAST */
5080
5081 /* If retry value is 0, it disables the functionality for TX Fail. */
5082 if (retry > 0) {
5083 txfail_config.max_tx_retry = retry;
5084 txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */
5085 }
5086 txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
5087 txfail_config.len = sizeof(txfail_config);
5088
5089 err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
5090 sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
5091 WL_DBG(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
5092
5093 return ((err == 0)?total_len:err);
5094 }
5095
5096 static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
5097 int total_len, bool bAll)
5098 {
5099 int error;
5100 int bytes_written = 0;
5101 void *buf = NULL;
5102 bss_peer_list_info_t peer_list_info;
5103 bss_peer_info_t *peer_info;
5104 int i;
5105 bool found = false;
5106 struct ether_addr mac_ea;
5107 char *str = command;
5108 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5109
5110 WL_DBG(("get ibss peer info(%s)\n", bAll?"true":"false"));
5111
5112 if (!bAll) {
5113 if (bcmstrtok(&str, " ", NULL) == NULL) {
5114 WL_ERR(("invalid command\n"));
5115 return -1;
5116 }
5117
5118 if (!str || !bcm_ether_atoe(str, &mac_ea)) {
5119 WL_ERR(("invalid MAC address\n"));
5120 return -1;
5121 }
5122 }
5123
5124 buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
5125 if (buf == NULL) {
5126 WL_ERR(("MALLOC failed\n"));
5127 return -1;
5128 }
5129
5130 error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
5131 if (unlikely(error)) {
5132 WL_ERR(("could not get ibss peer info (%d)\n", error));
5133 MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
5134 return -1;
5135 }
5136
5137 memcpy(&peer_list_info, buf, sizeof(peer_list_info));
5138 peer_list_info.version = htod16(peer_list_info.version);
5139 peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
5140 peer_list_info.count = htod32(peer_list_info.count);
5141
5142 WL_DBG(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
5143 peer_list_info.bss_peer_info_len, peer_list_info.count));
5144
5145 if (peer_list_info.count > 0) {
5146 if (bAll)
5147 bytes_written += snprintf(&command[bytes_written], total_len, "%u ",
5148 peer_list_info.count);
5149
5150 peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
5151
5152 for (i = 0; i < peer_list_info.count; i++) {
5153
5154 WL_DBG(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
5155 peer_info->tx_rate, peer_info->rx_rate));
5156
5157 if (!bAll &&
5158 memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
5159 found = true;
5160 }
5161
5162 if (bAll || found) {
5163 bytes_written += snprintf(&command[bytes_written],
5164 total_len - bytes_written,
5165 MACF" %u %d ", ETHER_TO_MACF(peer_info->ea),
5166 peer_info->tx_rate/1000, peer_info->rssi);
5167 if (bytes_written >= total_len) {
5168 WL_ERR(("%s: Insufficient memory, %d bytes\n",
5169 __FUNCTION__, total_len));
5170 bytes_written = -1;
5171 break;
5172 }
5173 }
5174
5175 if (found)
5176 break;
5177
5178 peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t));
5179 }
5180 }
5181 else {
5182 WL_ERR(("could not get ibss peer info : no item\n"));
5183 }
5184 WL_DBG(("command(%u):%s\n", total_len, command));
5185 WL_DBG(("bytes_written:%d\n", bytes_written));
5186
5187 MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
5188 return bytes_written;
5189 }
5190
5191 int wl_android_set_ibss_routetable(struct net_device *dev, char *command)
5192 {
5193
5194 char *pcmd = command;
5195 char *str = NULL;
5196 ibss_route_tbl_t *route_tbl = NULL;
5197 char *ioctl_buf = NULL;
5198 s32 err = BCME_OK;
5199 uint32 route_tbl_len;
5200 uint32 entries;
5201 char *endptr;
5202 uint32 i = 0;
5203 struct ipv4_addr dipaddr;
5204 struct ether_addr ea;
5205 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5206
5207 route_tbl_len = sizeof(ibss_route_tbl_t) +
5208 (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
5209 route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len);
5210 if (!route_tbl) {
5211 WL_ERR(("Route TBL alloc failed\n"));
5212 return -ENOMEM;
5213 }
5214 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5215 if (!ioctl_buf) {
5216 WL_ERR(("ioctl memory alloc failed\n"));
5217 if (route_tbl) {
5218 MFREE(cfg->osh, route_tbl, route_tbl_len);
5219 }
5220 return -ENOMEM;
5221 }
5222 memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN);
5223
5224 /* drop command */
5225 str = bcmstrtok(&pcmd, " ", NULL);
5226
5227 /* get count */
5228 str = bcmstrtok(&pcmd, " ", NULL);
5229 if (!str) {
5230 WL_ERR(("Invalid number parameter %s\n", str));
5231 err = -EINVAL;
5232 goto exit;
5233 }
5234 entries = bcm_strtoul(str, &endptr, 0);
5235 if (*endptr != '\0') {
5236 WL_ERR(("Invalid number parameter %s\n", str));
5237 err = -EINVAL;
5238 goto exit;
5239 }
5240 if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) {
5241 WL_ERR(("Invalid entries number %u\n", entries));
5242 err = -EINVAL;
5243 goto exit;
5244 }
5245
5246 WL_INFORM(("Routing table count:%u\n", entries));
5247 route_tbl->num_entry = entries;
5248
5249 for (i = 0; i < entries; i++) {
5250 str = bcmstrtok(&pcmd, " ", NULL);
5251 if (!str || !bcm_atoipv4(str, &dipaddr)) {
5252 WL_ERR(("Invalid ip string %s\n", str));
5253 err = -EINVAL;
5254 goto exit;
5255 }
5256
5257 str = bcmstrtok(&pcmd, " ", NULL);
5258 if (!str || !bcm_ether_atoe(str, &ea)) {
5259 WL_ERR(("Invalid ethernet string %s\n", str));
5260 err = -EINVAL;
5261 goto exit;
5262 }
5263 bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
5264 bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
5265 }
5266
5267 route_tbl_len = sizeof(ibss_route_tbl_t) +
5268 ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
5269 err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
5270 route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5271 if (err != BCME_OK) {
5272 WL_ERR(("Fail to set iovar %d\n", err));
5273 err = -EINVAL;
5274 }
5275
5276 exit:
5277 if (route_tbl) {
5278 MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) +
5279 (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t));
5280 }
5281 if (ioctl_buf) {
5282 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5283 }
5284 return err;
5285
5286 }
5287
5288 int
5289 wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
5290 {
5291 char *pcmd = command;
5292 char *str = NULL, *endptr = NULL;
5293 struct ampdu_aggr aggr;
5294 char smbuf[WLC_IOCTL_SMLEN];
5295 int idx;
5296 int err = 0;
5297 int wme_AC2PRIO[AC_COUNT][2] = {
5298 {PRIO_8021D_VO, PRIO_8021D_NC}, /* AC_VO - 3 */
5299 {PRIO_8021D_CL, PRIO_8021D_VI}, /* AC_VI - 2 */
5300 {PRIO_8021D_BK, PRIO_8021D_NONE}, /* AC_BK - 1 */
5301 {PRIO_8021D_BE, PRIO_8021D_EE}}; /* AC_BE - 0 */
5302
5303 WL_DBG(("set ibss ampdu:%s\n", command));
5304
5305 memset(&aggr, 0, sizeof(aggr));
5306 /* Cofigure all priorities */
5307 aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
5308
5309 /* acquire parameters */
5310 /* drop command */
5311 str = bcmstrtok(&pcmd, " ", NULL);
5312
5313 for (idx = 0; idx < AC_COUNT; idx++) {
5314 bool on;
5315 str = bcmstrtok(&pcmd, " ", NULL);
5316 if (!str) {
5317 WL_ERR(("Invalid parameter : %s\n", pcmd));
5318 return -EINVAL;
5319 }
5320 on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
5321 if (*endptr != '\0') {
5322 WL_ERR(("Invalid number format %s\n", str));
5323 return -EINVAL;
5324 }
5325 if (on) {
5326 setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
5327 setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
5328 }
5329 }
5330
5331 err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
5332 sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
5333
5334 return ((err == 0) ? total_len : err);
5335 }
5336
5337 int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
5338 {
5339 char *pcmd = command;
5340 char *str = NULL;
5341 int txchain, rxchain;
5342 int err = 0;
5343
5344 WL_DBG(("set ibss antenna:%s\n", command));
5345
5346 /* acquire parameters */
5347 /* drop command */
5348 str = bcmstrtok(&pcmd, " ", NULL);
5349
5350 /* TX chain */
5351 str = bcmstrtok(&pcmd, " ", NULL);
5352 if (!str) {
5353 WL_ERR(("Invalid parameter : %s\n", pcmd));
5354 return -EINVAL;
5355 }
5356 txchain = bcm_atoi(str);
5357
5358 /* RX chain */
5359 str = bcmstrtok(&pcmd, " ", NULL);
5360 if (!str) {
5361 WL_ERR(("Invalid parameter : %s\n", pcmd));
5362 return -EINVAL;
5363 }
5364 rxchain = bcm_atoi(str);
5365
5366 err = wldev_iovar_setint(dev, "txchain", txchain);
5367 if (err != 0)
5368 return err;
5369 err = wldev_iovar_setint(dev, "rxchain", rxchain);
5370 return ((err == 0)?total_len:err);
5371 }
5372 #endif /* WLAIBSS */
5373
5374 int wl_keep_alive_set(struct net_device *dev, char* extra)
5375 {
5376 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
5377 int ret;
5378 uint period_msec = 0;
5379 char *buf;
5380 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5381
5382 if (extra == NULL) {
5383 DHD_ERROR(("%s: extra is NULL\n", __FUNCTION__));
5384 return -1;
5385 }
5386 if (sscanf(extra, "%d", &period_msec) != 1) {
5387 DHD_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
5388 return -EINVAL;
5389 }
5390 DHD_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
5391
5392 memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
5393
5394 mkeep_alive_pkt.period_msec = period_msec;
5395 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
5396 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
5397
5398 /* Setup keep alive zero for null packet generation */
5399 mkeep_alive_pkt.keep_alive_id = 0;
5400 mkeep_alive_pkt.len_bytes = 0;
5401
5402 buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_SMLEN);
5403 if (!buf) {
5404 DHD_ERROR(("%s: buffer alloc failed\n", __FUNCTION__));
5405 return BCME_NOMEM;
5406 }
5407 ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
5408 WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
5409 if (ret < 0)
5410 DHD_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret));
5411 else
5412 DHD_TRACE(("%s:keep_alive set ok\n", __FUNCTION__));
5413 MFREE(cfg->osh, buf, WLC_IOCTL_SMLEN);
5414 return ret;
5415 }
5416 #ifdef P2PRESP_WFDIE_SRC
5417 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
5418 {
5419 int error = 0;
5420 int bytes_written = 0;
5421 int only_resp_wfdsrc = 0;
5422
5423 error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
5424 if (error) {
5425 DHD_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
5426 __FUNCTION__, error));
5427 return -1;
5428 }
5429
5430 bytes_written = snprintf(command, total_len, "%s %d",
5431 CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
5432
5433 return bytes_written;
5434 }
5435
5436 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
5437 {
5438 int error = 0;
5439
5440 error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
5441 if (error) {
5442 DHD_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
5443 __FUNCTION__, only_resp_wfdsrc, error));
5444 return -1;
5445 }
5446
5447 return 0;
5448 }
5449 #endif /* P2PRESP_WFDIE_SRC */
5450
5451 #ifdef BT_WIFI_HANDOVER
5452 static int
5453 wl_tbow_teardown(struct net_device *dev)
5454 {
5455 int err = BCME_OK;
5456 char buf[WLC_IOCTL_SMLEN];
5457 tbow_setup_netinfo_t netinfo;
5458 memset(&netinfo, 0, sizeof(netinfo));
5459 netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
5460
5461 err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
5462 sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
5463 if (err < 0) {
5464 WL_ERR(("tbow_doho iovar error %d\n", err));
5465 return err;
5466 }
5467 return err;
5468 }
5469 #endif /* BT_WIFI_HANOVER */
5470
5471 #ifdef SET_RPS_CPUS
5472 static int
5473 wl_android_set_rps_cpus(struct net_device *dev, char *command)
5474 {
5475 int error, enable;
5476
5477 enable = command[strlen(CMD_RPSMODE) + 1] - '0';
5478 error = dhd_rps_cpus_enable(dev, enable);
5479
5480 #if defined(DHDTCPACK_SUPPRESS) && defined(BCMPCIE) && defined(WL_CFG80211)
5481 if (!error) {
5482 void *dhdp = wl_cfg80211_get_dhdp(net);
5483 if (enable) {
5484 DHD_TRACE(("%s : set ack suppress. TCPACK_SUP_HOLD.\n", __FUNCTION__));
5485 dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_HOLD);
5486 } else {
5487 DHD_TRACE(("%s : clear ack suppress.\n", __FUNCTION__));
5488 dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
5489 }
5490 }
5491 #endif /* DHDTCPACK_SUPPRESS && BCMPCIE && WL_CFG80211 */
5492
5493 return error;
5494 }
5495 #endif /* SET_RPS_CPUS */
5496
5497 static int wl_android_get_link_status(struct net_device *dev, char *command,
5498 int total_len)
5499 {
5500 int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
5501 uint32 rspec;
5502 uint encode, txexp;
5503 wl_bss_info_t *bi;
5504 int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
5505 char buf[datalen];
5506
5507 memset(buf, 0, datalen);
5508 /* get BSS information */
5509 *(u32 *) buf = htod32(datalen);
5510 error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
5511 if (unlikely(error)) {
5512 WL_ERR(("Could not get bss info %d\n", error));
5513 return -1;
5514 }
5515
5516 bi = (wl_bss_info_t*) (buf + sizeof(uint32));
5517
5518 for (i = 0; i < ETHER_ADDR_LEN; i++) {
5519 if (bi->BSSID.octet[i] > 0) {
5520 break;
5521 }
5522 }
5523
5524 if (i == ETHER_ADDR_LEN) {
5525 WL_DBG(("No BSSID\n"));
5526 return -1;
5527 }
5528
5529 /* check VHT capability at beacon */
5530 if (bi->vht_cap) {
5531 if (CHSPEC_IS5G(bi->chanspec)) {
5532 result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
5533 }
5534 }
5535
5536 /* get a rspec (radio spectrum) rate */
5537 error = wldev_iovar_getint(dev, "nrate", &rspec);
5538 if (unlikely(error) || rspec == 0) {
5539 WL_ERR(("get link status error (%d)\n", error));
5540 return -1;
5541 }
5542
5543 encode = (rspec & WL_RSPEC_ENCODING_MASK);
5544 txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
5545
5546 switch (encode) {
5547 case WL_RSPEC_ENCODE_HT:
5548 /* check Rx MCS Map for HT */
5549 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
5550 int8 bitmap = 0xFF;
5551 if (i == MAX_STREAMS_SUPPORTED-1) {
5552 bitmap = 0x7F;
5553 }
5554 if (bi->basic_mcs[i] & bitmap) {
5555 nss++;
5556 }
5557 }
5558 break;
5559 case WL_RSPEC_ENCODE_VHT:
5560 /* check Rx MCS Map for VHT */
5561 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
5562 mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
5563 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
5564 nss++;
5565 }
5566 }
5567 break;
5568 }
5569
5570 /* check MIMO capability with nss in beacon */
5571 if (nss > 1) {
5572 result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
5573 }
5574
5575 single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
5576 ((encode == WL_RSPEC_ENCODE_HT) && (rspec & WL_RSPEC_HT_MCS_MASK) < 8) ||
5577 ((encode == WL_RSPEC_ENCODE_VHT) &&
5578 ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
5579
5580 if (txexp == 0) {
5581 if ((rspec & WL_RSPEC_STBC) && single_stream) {
5582 stf = OLD_NRATE_STF_STBC;
5583 } else {
5584 stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
5585 }
5586 } else if (txexp == 1 && single_stream) {
5587 stf = OLD_NRATE_STF_CDD;
5588 }
5589
5590 /* check 11ac (VHT) */
5591 if (encode == WL_RSPEC_ENCODE_VHT) {
5592 if (CHSPEC_IS5G(bi->chanspec)) {
5593 result |= WL_ANDROID_LINK_VHT;
5594 }
5595 }
5596
5597 /* check MIMO */
5598 if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
5599 switch (stf) {
5600 case OLD_NRATE_STF_SISO:
5601 break;
5602 case OLD_NRATE_STF_CDD:
5603 case OLD_NRATE_STF_STBC:
5604 result |= WL_ANDROID_LINK_MIMO;
5605 break;
5606 case OLD_NRATE_STF_SDM:
5607 if (!single_stream) {
5608 result |= WL_ANDROID_LINK_MIMO;
5609 }
5610 break;
5611 }
5612 }
5613
5614 WL_DBG(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
5615 __FUNCTION__, result, stf, single_stream, nss));
5616
5617 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
5618
5619 return bytes_written;
5620 }
5621
5622 #ifdef P2P_LISTEN_OFFLOADING
5623
5624 s32
5625 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
5626 {
5627 s32 bssidx;
5628 int ret = 0;
5629 int p2plo_pause = 0;
5630 dhd_pub_t *dhd = NULL;
5631 if (!cfg || !cfg->p2p) {
5632 WL_ERR(("Wl %p or cfg->p2p %p is null\n",
5633 cfg, cfg ? cfg->p2p : 0));
5634 return 0;
5635 }
5636
5637 dhd = (dhd_pub_t *)(cfg->pub);
5638 if (!dhd->up) {
5639 WL_ERR(("bus is already down\n"));
5640 return ret;
5641 }
5642
5643 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
5644 ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
5645 "p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
5646 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
5647 if (ret < 0) {
5648 WL_ERR(("p2po_stop Failed :%d\n", ret));
5649 }
5650
5651 return ret;
5652 }
5653 s32
5654 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
5655 {
5656 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5657 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
5658 wl_p2plo_listen_t p2plo_listen;
5659 int ret = -EAGAIN;
5660 int channel = 0;
5661 int period = 0;
5662 int interval = 0;
5663 int count = 0;
5664 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
5665 WL_ERR(("Sending Action Frames. Try it again.\n"));
5666 goto exit;
5667 }
5668
5669 if (wl_get_drv_status_all(cfg, SCANNING)) {
5670 WL_ERR(("Scanning already\n"));
5671 goto exit;
5672 }
5673
5674 if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
5675 WL_ERR(("Scanning being aborted\n"));
5676 goto exit;
5677 }
5678
5679 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
5680 WL_ERR(("p2p listen offloading already running\n"));
5681 goto exit;
5682 }
5683
5684 /* Just in case if it is not enabled */
5685 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
5686 WL_ERR(("cfgp2p_enable discovery failed"));
5687 goto exit;
5688 }
5689
5690 bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
5691
5692 if (len) {
5693 sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
5694 if ((channel == 0) || (period == 0) ||
5695 (interval == 0) || (count == 0)) {
5696 WL_ERR(("Wrong argument %d/%d/%d/%d \n",
5697 channel, period, interval, count));
5698 ret = -EAGAIN;
5699 goto exit;
5700 }
5701 p2plo_listen.period = period;
5702 p2plo_listen.interval = interval;
5703 p2plo_listen.count = count;
5704
5705 WL_ERR(("channel:%d period:%d, interval:%d count:%d\n",
5706 channel, period, interval, count));
5707 } else {
5708 WL_ERR(("Argument len is wrong.\n"));
5709 ret = -EAGAIN;
5710 goto exit;
5711 }
5712
5713 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
5714 sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
5715 bssidx, &cfg->ioctl_buf_sync)) < 0) {
5716 WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
5717 goto exit;
5718 }
5719
5720 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
5721 sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
5722 bssidx, &cfg->ioctl_buf_sync)) < 0) {
5723 WL_ERR(("p2po_listen Failed :%d\n", ret));
5724 goto exit;
5725 }
5726
5727 wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
5728 exit :
5729 return ret;
5730 }
5731 s32
5732 wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
5733 {
5734 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5735 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
5736 int ret = -EAGAIN;
5737
5738 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
5739 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
5740 bssidx, &cfg->ioctl_buf_sync)) < 0) {
5741 WL_ERR(("p2po_stop Failed :%d\n", ret));
5742 goto exit;
5743 }
5744
5745 exit:
5746 return ret;
5747 }
5748
5749 s32
5750 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
5751 {
5752 int ret = 0;
5753
5754 WL_ERR(("Entry cmd:%s arg_len:%d \n", cmd, len));
5755
5756 if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
5757 ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
5758 } else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
5759 ret = wl_cfg80211_p2plo_listen_stop(dev);
5760 } else {
5761 WL_ERR(("Request for Unsupported CMD:%s \n", buf));
5762 ret = -EINVAL;
5763 }
5764 return ret;
5765 }
5766 #endif /* P2P_LISTEN_OFFLOADING */
5767
5768 #ifdef DYNAMIC_MUMIMO_CONTROL
5769 int
5770 wl_android_get_murx_bfe_cap(struct net_device *dev, char *command, int total_len)
5771 {
5772 int err = 0;
5773 int cap = 0;
5774 int bytes_written = 0;
5775
5776 /* Now there is only single interface */
5777 err = wl_get_murx_bfe_cap(dev, &cap);
5778 if (unlikely(err)) {
5779 WL_ERR(("Failed to get murx_bfe_cap, error = %d\n", err));
5780 return err;
5781 }
5782
5783 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_MURX_BFE_CAP, cap);
5784
5785 return bytes_written;
5786 }
5787
5788 int
5789 wl_android_set_murx_bfe_cap(struct net_device *dev, int val)
5790 {
5791 int err = BCME_OK;
5792
5793 err = wl_set_murx_bfe_cap(dev, val, TRUE);
5794 if (unlikely(err)) {
5795 WL_ERR(("Failed to set murx_bfe_cap to %d, error = %d\n", val, err));
5796 }
5797
5798 return err;
5799 }
5800
5801 int
5802 wl_android_get_bss_support_mumimo(struct net_device *dev, char *command, int total_len)
5803 {
5804 int val = 0;
5805 int bytes_written = 0;
5806
5807 val = wl_check_bss_support_mumimo(dev);
5808 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_BSS_SUPPORT_MUMIMO, val);
5809
5810 return bytes_written;
5811 }
5812 #endif /* DYNAMIC_MUMIMO_CONTROL */
5813
5814 #ifdef SUPPORT_RSSI_SUM_REPORT
5815 int
5816 wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
5817 {
5818 wl_rssi_ant_mimo_t rssi_ant_mimo;
5819 char *ifname = NULL;
5820 char *peer_mac = NULL;
5821 char *mimo_cmd = "mimo";
5822 char *pos, *token;
5823 int err = BCME_OK;
5824 int bytes_written = 0;
5825 bool mimo_rssi = FALSE;
5826
5827 memset(&rssi_ant_mimo, 0, sizeof(wl_rssi_ant_mimo_t));
5828 /*
5829 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
5830 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
5831 */
5832 pos = command;
5833
5834 /* drop command */
5835 token = bcmstrtok(&pos, " ", NULL);
5836
5837 /* get the interface name */
5838 token = bcmstrtok(&pos, " ", NULL);
5839 if (!token) {
5840 WL_ERR(("Invalid arguments\n"));
5841 return -EINVAL;
5842 }
5843 ifname = token;
5844
5845 /* Optional: Check the MIMO RSSI mode or peer MAC address */
5846 token = bcmstrtok(&pos, " ", NULL);
5847 if (token) {
5848 /* Check the MIMO RSSI mode */
5849 if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
5850 mimo_rssi = TRUE;
5851 } else {
5852 peer_mac = token;
5853 }
5854 }
5855
5856 /* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
5857 token = bcmstrtok(&pos, " ", NULL);
5858 if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
5859 mimo_rssi = TRUE;
5860 }
5861
5862 err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
5863 if (unlikely(err)) {
5864 WL_ERR(("Failed to get RSSI info, err=%d\n", err));
5865 return err;
5866 }
5867
5868 /* Parse the results */
5869 WL_DBG(("ifname %s, version %d, count %d, mimo rssi %d\n",
5870 ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
5871 if (mimo_rssi) {
5872 WL_DBG(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
5873 bytes_written = snprintf(command, total_len, "%s MIMO %d",
5874 CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
5875 } else {
5876 int cnt;
5877 bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
5878 for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
5879 WL_DBG(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
5880 bytes_written = snprintf(command, total_len, "%d ",
5881 rssi_ant_mimo.rssi_ant[cnt]);
5882 }
5883 }
5884
5885 return bytes_written;
5886 }
5887
5888 int
5889 wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
5890 {
5891 rssilog_set_param_t set_param;
5892 char *pos, *token;
5893 int err = BCME_OK;
5894
5895 memset(&set_param, 0, sizeof(rssilog_set_param_t));
5896 /*
5897 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
5898 */
5899 pos = command;
5900
5901 /* drop command */
5902 token = bcmstrtok(&pos, " ", NULL);
5903
5904 /* enable/disable */
5905 token = bcmstrtok(&pos, " ", NULL);
5906 if (!token) {
5907 WL_ERR(("Invalid arguments\n"));
5908 return -EINVAL;
5909 }
5910 set_param.enable = bcm_atoi(token);
5911
5912 /* RSSI Threshold */
5913 token = bcmstrtok(&pos, " ", NULL);
5914 if (!token) {
5915 WL_ERR(("Invalid arguments\n"));
5916 return -EINVAL;
5917 }
5918 set_param.rssi_threshold = bcm_atoi(token);
5919
5920 /* Time Threshold */
5921 token = bcmstrtok(&pos, " ", NULL);
5922 if (!token) {
5923 WL_ERR(("Invalid arguments\n"));
5924 return -EINVAL;
5925 }
5926 set_param.time_threshold = bcm_atoi(token);
5927
5928 WL_DBG(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
5929 set_param.rssi_threshold, set_param.time_threshold));
5930
5931 err = wl_set_rssi_logging(dev, (void *)&set_param);
5932 if (unlikely(err)) {
5933 WL_ERR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
5934 " Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
5935 set_param.time_threshold));
5936 }
5937
5938 return err;
5939 }
5940
5941 int
5942 wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
5943 {
5944 rssilog_get_param_t get_param;
5945 int err = BCME_OK;
5946 int bytes_written = 0;
5947
5948 err = wl_get_rssi_logging(dev, (void *)&get_param);
5949 if (unlikely(err)) {
5950 WL_ERR(("Failed to get RSSI logging info\n"));
5951 return BCME_ERROR;
5952 }
5953
5954 WL_DBG(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
5955 get_param.report_count, get_param.enable, get_param.rssi_threshold,
5956 get_param.time_threshold));
5957
5958 /* Parse the parameter */
5959 if (!get_param.enable) {
5960 WL_DBG(("RSSI LOGGING: Feature is disables\n"));
5961 bytes_written = snprintf(command, total_len,
5962 "%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
5963 } else if (get_param.enable &
5964 (RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
5965 if (!get_param.report_count) {
5966 WL_DBG(("[PASS] RSSI difference across antennas is within"
5967 " threshold limits\n"));
5968 bytes_written = snprintf(command, total_len, "%s PASS\n",
5969 CMD_GET_RSSI_LOGGING);
5970 } else {
5971 WL_DBG(("[FAIL] RSSI difference across antennas found "
5972 "to be greater than %3d dB\n", get_param.rssi_threshold));
5973 WL_DBG(("[FAIL] RSSI difference check have failed for "
5974 "%d out of %d times\n", get_param.report_count,
5975 get_param.time_threshold));
5976 WL_DBG(("[FAIL] RSSI difference is being monitored once "
5977 "per second, for a %d secs window\n", get_param.time_threshold));
5978 bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
5979 "%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
5980 get_param.rssi_threshold, get_param.report_count,
5981 get_param.time_threshold);
5982 }
5983 } else {
5984 WL_DBG(("[BUSY] Reprot is not ready\n"));
5985 bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
5986 CMD_GET_RSSI_LOGGING);
5987 }
5988
5989 return bytes_written;
5990 }
5991 #endif /* SUPPORT_RSSI_SUM_REPORT */
5992
5993 #ifdef SET_PCIE_IRQ_CPU_CORE
5994 void
5995 wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
5996 {
5997 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
5998 if (!dhdp) {
5999 WL_ERR(("dhd is NULL\n"));
6000 return;
6001 }
6002
6003 if (affinity_cmd < PCIE_IRQ_AFFINITY_OFF || affinity_cmd > PCIE_IRQ_AFFINITY_LAST) {
6004 WL_ERR(("Wrong Affinity cmds:%d, %s\n", affinity_cmd, __FUNCTION__));
6005 return;
6006 }
6007
6008 dhd_set_irq_cpucore(dhdp, affinity_cmd);
6009 }
6010 #endif /* SET_PCIE_IRQ_CPU_CORE */
6011
6012 #ifdef SUPPORT_LQCM
6013 static int
6014 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
6015 {
6016 int err = 0;
6017
6018 err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
6019 if (err != BCME_OK) {
6020 WL_ERR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
6021 return -EIO;
6022 }
6023 return err;
6024 }
6025
6026 static int
6027 wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len)
6028 {
6029 int bytes_written, err = 0;
6030 uint32 lqcm_report = 0;
6031 uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
6032
6033 err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
6034 if (err != BCME_OK) {
6035 WL_ERR(("failed to get lqcm report, error = %d\n", err));
6036 return -EIO;
6037 }
6038 lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
6039 tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
6040 rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
6041
6042 WL_ERR(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
6043
6044 bytes_written = snprintf(command, total_len, "%s %d",
6045 CMD_GET_LQCM_REPORT, lqcm_report);
6046
6047 return bytes_written;
6048 }
6049 #endif /* SUPPORT_LQCM */
6050
6051 int
6052 wl_android_get_snr(struct net_device *dev, char *command, int total_len)
6053 {
6054 int bytes_written, error = 0;
6055 s32 snr = 0;
6056
6057 error = wldev_iovar_getint(dev, "snr", &snr);
6058 if (error) {
6059 DHD_ERROR(("%s: Failed to get SNR %d, error = %d\n",
6060 __FUNCTION__, snr, error));
6061 return -EIO;
6062 }
6063
6064 bytes_written = snprintf(command, total_len, "snr %d", snr);
6065 DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command));
6066 return bytes_written;
6067 }
6068
6069 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
6070 int
6071 wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
6072 {
6073 int rate = 0;
6074 char *pos, *token;
6075 char *ifname = NULL;
6076 int err = BCME_OK;
6077
6078 /*
6079 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
6080 */
6081 pos = command;
6082
6083 /* drop command */
6084 token = bcmstrtok(&pos, " ", NULL);
6085
6086 /* Rate */
6087 token = bcmstrtok(&pos, " ", NULL);
6088 if (!token)
6089 return -EINVAL;
6090 rate = bcm_atoi(token);
6091
6092 /* get the interface name */
6093 token = bcmstrtok(&pos, " ", NULL);
6094 if (!token)
6095 return -EINVAL;
6096 ifname = token;
6097
6098 WL_DBG(("rate %d, ifacename %s\n", rate, ifname));
6099
6100 err = wl_set_ap_beacon_rate(dev, rate, ifname);
6101 if (unlikely(err)) {
6102 WL_ERR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
6103 }
6104
6105 return err;
6106 }
6107
6108 int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
6109 {
6110 char *pos, *token;
6111 char *ifname = NULL;
6112 int bytes_written = 0;
6113 /*
6114 * DRIVER GET_AP_BASICRATE <ifname>
6115 */
6116 pos = command;
6117
6118 /* drop command */
6119 token = bcmstrtok(&pos, " ", NULL);
6120
6121 /* get the interface name */
6122 token = bcmstrtok(&pos, " ", NULL);
6123 if (!token)
6124 return -EINVAL;
6125 ifname = token;
6126
6127 WL_DBG(("ifacename %s\n", ifname));
6128
6129 bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
6130 if (bytes_written < 1) {
6131 WL_ERR(("Failed to get ap basic rate, error = %d\n", bytes_written));
6132 return -EPROTO;
6133 }
6134
6135 return bytes_written;
6136 }
6137 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
6138
6139 #ifdef SUPPORT_AP_RADIO_PWRSAVE
6140 int
6141 wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
6142 {
6143 char *pos, *token;
6144 char *ifname = NULL;
6145 int bytes_written = 0;
6146 char name[IFNAMSIZ];
6147 /*
6148 * DRIVER GET_AP_RPS <ifname>
6149 */
6150 pos = command;
6151
6152 /* drop command */
6153 token = bcmstrtok(&pos, " ", NULL);
6154
6155 /* get the interface name */
6156 token = bcmstrtok(&pos, " ", NULL);
6157 if (!token)
6158 return -EINVAL;
6159 ifname = token;
6160
6161 strncpy(name, ifname, IFNAMSIZ);
6162 name[IFNAMSIZ-1] = '\0';
6163 WL_DBG(("ifacename %s\n", name));
6164
6165 bytes_written = wl_get_ap_rps(dev, command, name, total_len);
6166 if (bytes_written < 1) {
6167 WL_ERR(("Failed to get rps, error = %d\n", bytes_written));
6168 return -EPROTO;
6169 }
6170
6171 return bytes_written;
6172
6173 }
6174
6175 int
6176 wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
6177 {
6178 int enable = 0;
6179 char *pos, *token;
6180 char *ifname = NULL;
6181 int err = BCME_OK;
6182 char name[IFNAMSIZ];
6183
6184 /*
6185 * DRIVER SET_AP_RPS <0/1> <ifname>
6186 */
6187 pos = command;
6188
6189 /* drop command */
6190 token = bcmstrtok(&pos, " ", NULL);
6191
6192 /* Enable */
6193 token = bcmstrtok(&pos, " ", NULL);
6194 if (!token)
6195 return -EINVAL;
6196 enable = bcm_atoi(token);
6197
6198 /* get the interface name */
6199 token = bcmstrtok(&pos, " ", NULL);
6200 if (!token)
6201 return -EINVAL;
6202 ifname = token;
6203
6204 strncpy(name, ifname, IFNAMSIZ);
6205 name[IFNAMSIZ-1] = '\0';
6206 WL_DBG(("enable %d, ifacename %s\n", enable, name));
6207
6208 err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name);
6209 if (unlikely(err)) {
6210 WL_ERR(("Failed to set rps, enable %d, error = %d\n", enable, err));
6211 }
6212
6213 return err;
6214 }
6215
6216 int
6217 wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
6218 {
6219 ap_rps_info_t rps;
6220 char *pos, *token;
6221 char *ifname = NULL;
6222 int err = BCME_OK;
6223 char name[IFNAMSIZ];
6224
6225 memset(&rps, 0, sizeof(rps));
6226 /*
6227 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
6228 */
6229 pos = command;
6230
6231 /* drop command */
6232 token = bcmstrtok(&pos, " ", NULL);
6233
6234 /* pps */
6235 token = bcmstrtok(&pos, " ", NULL);
6236 if (!token)
6237 return -EINVAL;
6238 rps.pps = bcm_atoi(token);
6239
6240 /* level */
6241 token = bcmstrtok(&pos, " ", NULL);
6242 if (!token)
6243 return -EINVAL;
6244 rps.level = bcm_atoi(token);
6245
6246 /* quiettime */
6247 token = bcmstrtok(&pos, " ", NULL);
6248 if (!token)
6249 return -EINVAL;
6250 rps.quiet_time = bcm_atoi(token);
6251
6252 /* sta assoc check */
6253 token = bcmstrtok(&pos, " ", NULL);
6254 if (!token)
6255 return -EINVAL;
6256 rps.sta_assoc_check = bcm_atoi(token);
6257
6258 /* get the interface name */
6259 token = bcmstrtok(&pos, " ", NULL);
6260 if (!token)
6261 return -EINVAL;
6262 ifname = token;
6263 strncpy(name, ifname, IFNAMSIZ);
6264 name[IFNAMSIZ-1] = '\0';
6265
6266 WL_DBG(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
6267 "ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
6268 rps.sta_assoc_check, name));
6269
6270 err = wl_update_ap_rps_params(dev, &rps, name);
6271 if (unlikely(err)) {
6272 WL_ERR(("Failed to update rps, pps %d, level %d, quiettime %d, "
6273 "sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
6274 rps.sta_assoc_check, err));
6275 }
6276
6277 return err;
6278 }
6279 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
6280
6281 #if defined(DHD_HANG_SEND_UP_TEST)
6282 void
6283 wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
6284 {
6285 dhd_make_hang_with_reason(dev, string_num);
6286 }
6287 #endif /* DHD_HANG_SEND_UP_TEST */
6288
6289 #ifdef DHD_PKT_LOGGING
6290 static int
6291 wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
6292 {
6293 int bytes_written = 0;
6294 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6295 dhd_pktlog_filter_t *filter;
6296 int err = BCME_OK;
6297
6298 if (!dhdp || !dhdp->pktlog) {
6299 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6300 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6301 return -EINVAL;
6302 }
6303
6304 filter = dhdp->pktlog->pktlog_filter;
6305
6306 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
6307 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
6308 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
6309
6310 if (err == BCME_OK) {
6311 bytes_written = snprintf(command, total_len, "OK");
6312 DHD_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
6313 } else {
6314 DHD_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
6315 return BCME_ERROR;
6316 }
6317
6318 return bytes_written;
6319 }
6320
6321 static int
6322 wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
6323 {
6324 int bytes_written = 0;
6325 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6326 dhd_pktlog_filter_t *filter;
6327 int err = BCME_OK;
6328
6329 if (!dhdp || !dhdp->pktlog) {
6330 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6331 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6332 return -EINVAL;
6333 }
6334
6335 filter = dhdp->pktlog->pktlog_filter;
6336
6337 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
6338 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
6339 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
6340
6341 if (err == BCME_OK) {
6342 bytes_written = snprintf(command, total_len, "OK");
6343 DHD_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
6344 } else {
6345 DHD_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
6346 return BCME_ERROR;
6347 }
6348
6349 return bytes_written;
6350 }
6351
6352 static int
6353 wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
6354 {
6355 int bytes_written = 0;
6356 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6357 dhd_pktlog_filter_t *filter;
6358 int err = BCME_OK;
6359
6360 if (!dhdp || !dhdp->pktlog) {
6361 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6362 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6363 return -EINVAL;
6364 }
6365
6366 filter = dhdp->pktlog->pktlog_filter;
6367
6368 if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
6369 return BCME_ERROR;
6370 }
6371
6372 err = dhd_pktlog_filter_pattern_enable(filter,
6373 command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
6374
6375 if (err == BCME_OK) {
6376 bytes_written = snprintf(command, total_len, "OK");
6377 DHD_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
6378 } else {
6379 DHD_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
6380 return BCME_ERROR;
6381 }
6382
6383 return bytes_written;
6384 }
6385
6386 static int
6387 wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
6388 {
6389 int bytes_written = 0;
6390 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6391 dhd_pktlog_filter_t *filter;
6392 int err = BCME_OK;
6393
6394 if (!dhdp || !dhdp->pktlog) {
6395 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6396 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6397 return -EINVAL;
6398 }
6399
6400 filter = dhdp->pktlog->pktlog_filter;
6401
6402 if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
6403 return BCME_ERROR;
6404 }
6405
6406 err = dhd_pktlog_filter_pattern_enable(filter,
6407 command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
6408
6409 if (err == BCME_OK) {
6410 bytes_written = snprintf(command, total_len, "OK");
6411 DHD_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
6412 } else {
6413 DHD_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
6414 return BCME_ERROR;
6415 }
6416
6417 return bytes_written;
6418 }
6419
6420 static int
6421 wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
6422 {
6423 int bytes_written = 0;
6424 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6425 dhd_pktlog_filter_t *filter;
6426 int err = BCME_OK;
6427
6428 if (!dhdp || !dhdp->pktlog) {
6429 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6430 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6431 return -EINVAL;
6432 }
6433
6434 filter = dhdp->pktlog->pktlog_filter;
6435
6436 if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
6437 return BCME_ERROR;
6438 }
6439
6440 err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
6441
6442 if (err == BCME_OK) {
6443 bytes_written = snprintf(command, total_len, "OK");
6444 DHD_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
6445 } else {
6446 DHD_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
6447 return BCME_ERROR;
6448 }
6449
6450 return bytes_written;
6451 }
6452
6453 static int
6454 wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
6455 {
6456 int bytes_written = 0;
6457 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6458 dhd_pktlog_filter_t *filter;
6459 int err = BCME_OK;
6460
6461 if (!dhdp || !dhdp->pktlog) {
6462 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6463 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6464 return -EINVAL;
6465 }
6466
6467 filter = dhdp->pktlog->pktlog_filter;
6468
6469 err = dhd_pktlog_filter_info(filter);
6470
6471 if (err == BCME_OK) {
6472 bytes_written = snprintf(command, total_len, "OK");
6473 DHD_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
6474 } else {
6475 DHD_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
6476 return BCME_ERROR;
6477 }
6478
6479 return bytes_written;
6480 }
6481
6482 static int
6483 wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
6484 {
6485 int bytes_written = 0;
6486 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6487
6488 if (!dhdp || !dhdp->pktlog) {
6489 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6490 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6491 return -EINVAL;
6492 }
6493
6494 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
6495 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
6496 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
6497 return -EINVAL;
6498 }
6499
6500 dhdp->pktlog->tx_pktlog_ring->start = TRUE;
6501 dhdp->pktlog->rx_pktlog_ring->start = TRUE;
6502
6503 bytes_written = snprintf(command, total_len, "OK");
6504
6505 DHD_ERROR(("%s: pktlog start success\n", __FUNCTION__));
6506
6507 return bytes_written;
6508 }
6509
6510 static int
6511 wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
6512 {
6513 int bytes_written = 0;
6514 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6515
6516 if (!dhdp || !dhdp->pktlog) {
6517 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6518 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6519 return -EINVAL;
6520 }
6521
6522 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
6523 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
6524 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
6525 return -EINVAL;
6526 }
6527
6528 dhdp->pktlog->tx_pktlog_ring->start = FALSE;
6529 dhdp->pktlog->rx_pktlog_ring->start = FALSE;
6530
6531 bytes_written = snprintf(command, total_len, "OK");
6532
6533 DHD_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
6534
6535 return bytes_written;
6536 }
6537
6538 static int
6539 wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
6540 {
6541 int bytes_written = 0;
6542 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6543 dhd_pktlog_filter_t *filter;
6544 uint32 id;
6545 bool exist = FALSE;
6546
6547 if (!dhdp || !dhdp->pktlog) {
6548 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6549 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6550 return -EINVAL;
6551 }
6552
6553 filter = dhdp->pktlog->pktlog_filter;
6554
6555 if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
6556 return BCME_ERROR;
6557 }
6558
6559 exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
6560 &id);
6561
6562 if (exist) {
6563 bytes_written = snprintf(command, total_len, "TRUE");
6564 DHD_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
6565 } else {
6566 bytes_written = snprintf(command, total_len, "FALSE");
6567 DHD_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
6568 }
6569
6570 return bytes_written;
6571 }
6572
6573 static int
6574 wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int total_len)
6575 {
6576 int bytes_written = 0;
6577 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6578
6579 if (!dhdp || !dhdp->pktlog) {
6580 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6581 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6582 return -EINVAL;
6583 }
6584
6585 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
6586 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
6587 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
6588 return -EINVAL;
6589 }
6590
6591 dhdp->pktlog->tx_pktlog_ring->pktlog_minmize = TRUE;
6592 dhdp->pktlog->rx_pktlog_ring->pktlog_minmize = TRUE;
6593
6594 bytes_written = snprintf(command, total_len, "OK");
6595
6596 DHD_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__));
6597
6598 return bytes_written;
6599 }
6600
6601 static int
6602 wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int total_len)
6603 {
6604 int bytes_written = 0;
6605 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6606
6607 if (!dhdp || !dhdp->pktlog) {
6608 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6609 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6610 return -EINVAL;
6611 }
6612
6613 if (!dhdp->pktlog->tx_pktlog_ring || !dhdp->pktlog->rx_pktlog_ring) {
6614 DHD_PKT_LOG(("%s(): tx_pktlog_ring=%p rx_pktlog_ring=%p\n",
6615 __FUNCTION__, dhdp->pktlog->tx_pktlog_ring, dhdp->pktlog->rx_pktlog_ring));
6616 return -EINVAL;
6617 }
6618
6619 dhdp->pktlog->tx_pktlog_ring->pktlog_minmize = FALSE;
6620 dhdp->pktlog->rx_pktlog_ring->pktlog_minmize = FALSE;
6621
6622 bytes_written = snprintf(command, total_len, "OK");
6623
6624 DHD_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__));
6625
6626 return bytes_written;
6627 }
6628
6629 static int
6630 wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_len)
6631 {
6632 int bytes_written = 0;
6633 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6634 int err = BCME_OK;
6635 int size;
6636
6637 if (!dhdp || !dhdp->pktlog) {
6638 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
6639 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
6640 return -EINVAL;
6641 }
6642
6643 if (strlen(CMD_PKTLOG_CHANGE_SIZE) + 1 > total_len) {
6644 return BCME_ERROR;
6645 }
6646
6647 size = bcm_strtoul(command + strlen(CMD_PKTLOG_CHANGE_SIZE) + 1, NULL, 0);
6648
6649 dhdp->pktlog->tx_pktlog_ring =
6650 dhd_pktlog_ring_change_size(dhdp->pktlog->tx_pktlog_ring, size);
6651 if (!dhdp->pktlog->tx_pktlog_ring) {
6652 err = BCME_ERROR;
6653 }
6654
6655 dhdp->pktlog->rx_pktlog_ring =
6656 dhd_pktlog_ring_change_size(dhdp->pktlog->rx_pktlog_ring, size);
6657 if (!dhdp->pktlog->tx_pktlog_ring) {
6658 err = BCME_ERROR;
6659 }
6660
6661 if (err == BCME_OK) {
6662 bytes_written = snprintf(command, total_len, "OK");
6663 DHD_ERROR(("%s: pktlog change size success\n", __FUNCTION__));
6664 } else {
6665 DHD_ERROR(("%s: pktlog change size fail\n", __FUNCTION__));
6666 return BCME_ERROR;
6667 }
6668
6669 return bytes_written;
6670 }
6671 #endif /* DHD_PKT_LOGGING */
6672
6673 #ifdef DHD_EVENT_LOG_FILTER
6674 uint32 dhd_event_log_filter_serialize(dhd_pub_t *dhdp, char *buf, uint32 tot_len, int type);
6675 static int
6676 wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len)
6677 {
6678 uint32 bytes_written = 0;
6679 int type = 0;
6680 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6681
6682 if (!dhdp || !command) {
6683 DHD_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp));
6684 return -EINVAL;
6685 }
6686
6687 /* NEED TO GET TYPE if EXIST */
6688 type = 0;
6689
6690 bytes_written += dhd_event_log_filter_serialize(dhdp,
6691 &command[bytes_written], tot_len - bytes_written, type);
6692
6693 return (int)bytes_written;
6694 }
6695 #endif /* DHD_EVENT_LOG_FILTER */
6696
6697 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
6698 {
6699 #define PRIVATE_COMMAND_MAX_LEN 8192
6700 #define PRIVATE_COMMAND_DEF_LEN 4096
6701 int ret = 0;
6702 char *command = NULL;
6703 int bytes_written = 0;
6704 android_wifi_priv_cmd priv_cmd;
6705 int buf_size = 0;
6706 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
6707
6708 net_os_wake_lock(net);
6709
6710 if (!capable(CAP_NET_ADMIN)) {
6711 ret = -EPERM;
6712 goto exit;
6713 }
6714
6715 if (!ifr->ifr_data) {
6716 ret = -EINVAL;
6717 goto exit;
6718 }
6719
6720 #ifdef CONFIG_COMPAT
6721 if (is_compat_task()) {
6722 compat_android_wifi_priv_cmd compat_priv_cmd;
6723 if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
6724 sizeof(compat_android_wifi_priv_cmd))) {
6725 ret = -EFAULT;
6726 goto exit;
6727
6728 }
6729 priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
6730 priv_cmd.used_len = compat_priv_cmd.used_len;
6731 priv_cmd.total_len = compat_priv_cmd.total_len;
6732 } else
6733 #endif /* CONFIG_COMPAT */
6734 {
6735 if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
6736 ret = -EFAULT;
6737 goto exit;
6738 }
6739 }
6740 if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
6741 DHD_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__,
6742 priv_cmd.total_len));
6743 ret = -EINVAL;
6744 goto exit;
6745 }
6746
6747 buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
6748 command = (char *)MALLOC(cfg->osh, (buf_size + 1));
6749 if (!command) {
6750 DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
6751 ret = -ENOMEM;
6752 goto exit;
6753 }
6754 if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
6755 ret = -EFAULT;
6756 goto exit;
6757 }
6758 command[priv_cmd.total_len] = '\0';
6759
6760 DHD_ERROR(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
6761
6762 bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
6763 if (bytes_written >= 0) {
6764 if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
6765 command[0] = '\0';
6766 }
6767 if (bytes_written >= priv_cmd.total_len) {
6768 DHD_ERROR(("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n",
6769 __FUNCTION__, bytes_written, priv_cmd.total_len, buf_size));
6770
6771 ret = BCME_BUFTOOSHORT;
6772 goto exit;
6773 }
6774 bytes_written++;
6775 priv_cmd.used_len = bytes_written;
6776 if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
6777 DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
6778 ret = -EFAULT;
6779 }
6780 }
6781 else {
6782 /* Propagate the error */
6783 ret = bytes_written;
6784 }
6785
6786 exit:
6787 net_os_wake_unlock(net);
6788 MFREE(cfg->osh, command, (buf_size + 1));
6789 return ret;
6790 }
6791 #ifdef WLADPS_PRIVATE_CMD
6792 static int
6793 wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
6794 {
6795 int err = 0, adps_mode;
6796 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6797 #ifdef DHD_PM_CONTROL_FROM_FILE
6798 if (g_pm_control) {
6799 return -EPERM;
6800 }
6801 #endif /* DHD_PM_CONTROL_FROM_FILE */
6802
6803 adps_mode = bcm_atoi(string_num);
6804 WL_ERR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode));
6805
6806 if ((adps_mode < 0) && (1 < adps_mode)) {
6807 WL_ERR(("%s: Invalid value %d.\n", __FUNCTION__, adps_mode));
6808 return -EINVAL;
6809 }
6810
6811 err = dhd_enable_adps(dhdp, adps_mode);
6812 if (err != BCME_OK) {
6813 WL_ERR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
6814 return -EIO;
6815 }
6816 return err;
6817 }
6818 static int
6819 wl_android_get_adps_mode(
6820 struct net_device *dev, char *command, int total_len)
6821 {
6822 int bytes_written, err = 0;
6823 int len;
6824 char buf[WLC_IOCTL_SMLEN];
6825
6826 bcm_iov_buf_t iov_buf;
6827 bcm_iov_buf_t *ptr = NULL;
6828 wl_adps_params_v1_t *data = NULL;
6829
6830 uint8 *pdata = NULL;
6831 uint8 band, mode = 0;
6832
6833 memset(&iov_buf, 0, sizeof(iov_buf));
6834
6835 len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
6836
6837 iov_buf.version = WL_ADPS_IOV_VER;
6838 iov_buf.len = sizeof(band);
6839 iov_buf.id = WL_ADPS_IOV_MODE;
6840
6841 pdata = (uint8 *)&iov_buf.data;
6842
6843 for (band = 1; band <= MAX_BANDS; band++) {
6844 pdata[0] = band;
6845 err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
6846 buf, WLC_IOCTL_SMLEN, NULL);
6847 if (err != BCME_OK) {
6848 WL_ERR(("%s fail to get adps band %d(%d).\n",
6849 __FUNCTION__, band, err));
6850 return -EIO;
6851 }
6852 ptr = (bcm_iov_buf_t *) buf;
6853 data = (wl_adps_params_v1_t *) ptr->data;
6854 mode = data->mode;
6855 if (mode != OFF) {
6856 break;
6857 }
6858 }
6859
6860 bytes_written = snprintf(command, total_len, "%s %d",
6861 CMD_GET_ADPS, mode);
6862 return bytes_written;
6863 }
6864 #endif /* WLADPS_PRIVATE_CMD */
6865
6866 int
6867 wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
6868 {
6869 int bytes_written = 0;
6870 android_wifi_priv_cmd priv_cmd;
6871
6872 bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
6873 priv_cmd.total_len = cmd_len;
6874
6875 if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
6876 DHD_INFO(("%s, Received regular START command\n", __FUNCTION__));
6877 #ifdef SUPPORT_DEEP_SLEEP
6878 trigger_deep_sleep = 1;
6879 #else
6880 #ifdef BT_OVER_SDIO
6881 bytes_written = dhd_net_bus_get(net);
6882 #else
6883 bytes_written = wl_android_wifi_on(net);
6884 #endif /* BT_OVER_SDIO */
6885 #endif /* SUPPORT_DEEP_SLEEP */
6886 }
6887 else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
6888 bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
6889 }
6890
6891 if (!g_wifi_on) {
6892 DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
6893 __FUNCTION__, command));
6894 return 0;
6895 }
6896
6897 if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
6898 #ifdef SUPPORT_DEEP_SLEEP
6899 trigger_deep_sleep = 1;
6900 #else
6901 #ifdef BT_OVER_SDIO
6902 bytes_written = dhd_net_bus_put(net);
6903 #else
6904 bytes_written = wl_android_wifi_off(net, FALSE);
6905 #endif /* BT_OVER_SDIO */
6906 #endif /* SUPPORT_DEEP_SLEEP */
6907 }
6908 else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
6909 wl_cfg80211_set_passive_scan(net, command);
6910 }
6911 else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
6912 wl_cfg80211_set_passive_scan(net, command);
6913 }
6914 else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
6915 bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
6916 }
6917 else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
6918 bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
6919 }
6920 #ifdef PKT_FILTER_SUPPORT
6921 else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
6922 bytes_written = net_os_enable_packet_filter(net, 1);
6923 }
6924 else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
6925 bytes_written = net_os_enable_packet_filter(net, 0);
6926 }
6927 else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
6928 int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
6929 bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
6930 }
6931 else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
6932 int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
6933 bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
6934 }
6935 #endif /* PKT_FILTER_SUPPORT */
6936 else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
6937 /* TBD: BTCOEXSCAN-START */
6938 }
6939 else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
6940 /* TBD: BTCOEXSCAN-STOP */
6941 }
6942 else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
6943 #ifdef WL_CFG80211
6944 void *dhdp = wl_cfg80211_get_dhdp(net);
6945 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
6946 #else
6947 #ifdef PKT_FILTER_SUPPORT
6948 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
6949
6950 if (mode == 1)
6951 net_os_enable_packet_filter(net, 0); /* DHCP starts */
6952 else
6953 net_os_enable_packet_filter(net, 1); /* DHCP ends */
6954 #endif /* PKT_FILTER_SUPPORT */
6955 #endif /* WL_CFG80211 */
6956 }
6957 else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
6958 bytes_written = wl_android_set_suspendopt(net, command);
6959 }
6960 else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
6961 bytes_written = wl_android_set_suspendmode(net, command);
6962 }
6963 else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND, strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
6964 bytes_written = wl_android_set_bcn_li_dtim(net, command);
6965 }
6966 else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
6967 bytes_written = wl_android_set_max_dtim(net, command);
6968 }
6969 else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
6970 uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
6971 #ifdef WL_HOST_BAND_MGMT
6972 s32 ret = 0;
6973 if ((ret = wl_cfg80211_set_band(net, band)) < 0) {
6974 if (ret == BCME_UNSUPPORTED) {
6975 /* If roam_var is unsupported, fallback to the original method */
6976 WL_ERR(("WL_HOST_BAND_MGMT defined, "
6977 "but roam_band iovar unsupported in the firmware\n"));
6978 } else {
6979 bytes_written = -1;
6980 }
6981 }
6982 if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) {
6983 /* Apply if roam_band iovar is not supported or band setting is AUTO */
6984 bytes_written = wldev_set_band(net, band);
6985 }
6986 #else
6987 bytes_written = wl_cfg80211_set_if_band(net, band);
6988 #endif /* WL_HOST_BAND_MGMT */
6989 #ifdef ROAM_CHANNEL_CACHE
6990 wl_update_roamscan_cache_by_band(net, band);
6991 #endif /* ROAM_CHANNEL_CACHE */
6992 }
6993 else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
6994 bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
6995 }
6996 #ifdef WL_CFG80211
6997 #ifndef CUSTOMER_SET_COUNTRY
6998 /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
6999 else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
7000 /*
7001 * Usage examples:
7002 * DRIVER COUNTRY US
7003 * DRIVER COUNTRY US/7
7004 */
7005 char *country_code = command + strlen(CMD_COUNTRY) + 1;
7006 char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
7007 int revinfo = -1;
7008 struct wireless_dev *wdev = ndev_to_wdev(net);
7009 struct wiphy *wiphy = wdev->wiphy;
7010 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
7011
7012 BCM_REFERENCE(dhdp);
7013 if (CHECK_IS_BLOB(dhdp) && !CHECK_IS_MULT_REGREV(dhdp)) {
7014 revinfo = 0;
7015 } else if ((rev_info_delim) &&
7016 (strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
7017 strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
7018 (rev_info_delim + 1)) {
7019 revinfo = bcm_atoi(rev_info_delim + 1);
7020 }
7021
7022 if (wl_check_dongle_idle(wiphy) != TRUE) {
7023 DHD_ERROR(("FW is busy to check dongle idle\n"));
7024 return 0;
7025 }
7026
7027 bytes_written = wldev_set_country(net, country_code, true, true, revinfo);
7028 #ifdef CUSTOMER_HW4_PRIVATE_CMD
7029 #ifdef FCC_PWR_LIMIT_2G
7030 if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
7031 DHD_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
7032 } else {
7033 DHD_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
7034 }
7035 #endif /* FCC_PWR_LIMIT_2G */
7036 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7037 }
7038 #endif /* CUSTOMER_SET_COUNTRY */
7039 #endif /* WL_CFG80211 */
7040 else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
7041 bytes_written = wl_android_set_csa(net, command);
7042 } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
7043 bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
7044 } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
7045 bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
7046 } else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
7047 bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
7048 } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) {
7049 bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
7050 }
7051
7052 #ifdef CUSTOMER_HW4_PRIVATE_CMD
7053 #ifdef ROAM_API
7054 else if (strnicmp(command, CMD_ROAMTRIGGER_SET,
7055 strlen(CMD_ROAMTRIGGER_SET)) == 0) {
7056 bytes_written = wl_android_set_roam_trigger(net, command);
7057 } else if (strnicmp(command, CMD_ROAMTRIGGER_GET,
7058 strlen(CMD_ROAMTRIGGER_GET)) == 0) {
7059 bytes_written = wl_android_get_roam_trigger(net, command,
7060 priv_cmd.total_len);
7061 } else if (strnicmp(command, CMD_ROAMDELTA_SET,
7062 strlen(CMD_ROAMDELTA_SET)) == 0) {
7063 bytes_written = wl_android_set_roam_delta(net, command);
7064 } else if (strnicmp(command, CMD_ROAMDELTA_GET,
7065 strlen(CMD_ROAMDELTA_GET)) == 0) {
7066 bytes_written = wl_android_get_roam_delta(net, command,
7067 priv_cmd.total_len);
7068 } else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET,
7069 strlen(CMD_ROAMSCANPERIOD_SET)) == 0) {
7070 bytes_written = wl_android_set_roam_scan_period(net, command);
7071 } else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET,
7072 strlen(CMD_ROAMSCANPERIOD_GET)) == 0) {
7073 bytes_written = wl_android_get_roam_scan_period(net, command,
7074 priv_cmd.total_len);
7075 } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET,
7076 strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) {
7077 bytes_written = wl_android_set_full_roam_scan_period(net, command,
7078 priv_cmd.total_len);
7079 } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET,
7080 strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) {
7081 bytes_written = wl_android_get_full_roam_scan_period(net, command,
7082 priv_cmd.total_len);
7083 } else if (strnicmp(command, CMD_COUNTRYREV_SET,
7084 strlen(CMD_COUNTRYREV_SET)) == 0) {
7085 bytes_written = wl_android_set_country_rev(net, command);
7086 #ifdef FCC_PWR_LIMIT_2G
7087 if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
7088 DHD_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
7089 } else {
7090 DHD_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
7091 }
7092 #endif /* FCC_PWR_LIMIT_2G */
7093 } else if (strnicmp(command, CMD_COUNTRYREV_GET,
7094 strlen(CMD_COUNTRYREV_GET)) == 0) {
7095 bytes_written = wl_android_get_country_rev(net, command,
7096 priv_cmd.total_len);
7097 }
7098 #endif /* ROAM_API */
7099 #ifdef WES_SUPPORT
7100 else if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) {
7101 bytes_written = wl_android_get_roam_scan_control(net, command, priv_cmd.total_len);
7102 }
7103 else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) {
7104 bytes_written = wl_android_set_roam_scan_control(net, command);
7105 }
7106 else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) {
7107 bytes_written = wl_android_get_roam_scan_channels(net, command, priv_cmd.total_len);
7108 }
7109 else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) {
7110 bytes_written = wl_android_set_roam_scan_channels(net, command);
7111 }
7112 else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) {
7113 bytes_written = wl_android_send_action_frame(net, command, priv_cmd.total_len);
7114 }
7115 else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) {
7116 bytes_written = wl_android_reassoc(net, command, priv_cmd.total_len);
7117 }
7118 else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) {
7119 bytes_written = wl_android_get_scan_channel_time(net, command, priv_cmd.total_len);
7120 }
7121 else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) {
7122 bytes_written = wl_android_set_scan_channel_time(net, command);
7123 }
7124 else if (strnicmp(command, CMD_GETSCANUNASSOCTIME, strlen(CMD_GETSCANUNASSOCTIME)) == 0) {
7125 bytes_written = wl_android_get_scan_unassoc_time(net, command, priv_cmd.total_len);
7126 }
7127 else if (strnicmp(command, CMD_SETSCANUNASSOCTIME, strlen(CMD_SETSCANUNASSOCTIME)) == 0) {
7128 bytes_written = wl_android_set_scan_unassoc_time(net, command);
7129 }
7130 else if (strnicmp(command, CMD_GETSCANPASSIVETIME, strlen(CMD_GETSCANPASSIVETIME)) == 0) {
7131 bytes_written = wl_android_get_scan_passive_time(net, command, priv_cmd.total_len);
7132 }
7133 else if (strnicmp(command, CMD_SETSCANPASSIVETIME, strlen(CMD_SETSCANPASSIVETIME)) == 0) {
7134 bytes_written = wl_android_set_scan_passive_time(net, command);
7135 }
7136 else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) {
7137 bytes_written = wl_android_get_scan_home_time(net, command, priv_cmd.total_len);
7138 }
7139 else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) {
7140 bytes_written = wl_android_set_scan_home_time(net, command);
7141 }
7142 else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) {
7143 bytes_written = wl_android_get_scan_home_away_time(net, command,
7144 priv_cmd.total_len);
7145 }
7146 else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) {
7147 bytes_written = wl_android_set_scan_home_away_time(net, command);
7148 }
7149 else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) {
7150 bytes_written = wl_android_get_scan_nprobes(net, command, priv_cmd.total_len);
7151 }
7152 else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) {
7153 bytes_written = wl_android_set_scan_nprobes(net, command);
7154 }
7155 else if (strnicmp(command, CMD_GETDFSSCANMODE, strlen(CMD_GETDFSSCANMODE)) == 0) {
7156 bytes_written = wl_android_get_scan_dfs_channel_mode(net, command,
7157 priv_cmd.total_len);
7158 }
7159 else if (strnicmp(command, CMD_SETDFSSCANMODE, strlen(CMD_SETDFSSCANMODE)) == 0) {
7160 bytes_written = wl_android_set_scan_dfs_channel_mode(net, command);
7161 }
7162 else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) {
7163 bytes_written = wl_android_set_join_prefer(net, command);
7164 }
7165 else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) {
7166 bytes_written = wl_android_get_wes_mode(net, command, priv_cmd.total_len);
7167 }
7168 else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) {
7169 bytes_written = wl_android_set_wes_mode(net, command);
7170 }
7171 else if (strnicmp(command, CMD_GETOKCMODE, strlen(CMD_GETOKCMODE)) == 0) {
7172 bytes_written = wl_android_get_okc_mode(net, command, priv_cmd.total_len);
7173 }
7174 else if (strnicmp(command, CMD_SETOKCMODE, strlen(CMD_SETOKCMODE)) == 0) {
7175 bytes_written = wl_android_set_okc_mode(net, command);
7176 }
7177 else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) {
7178 bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
7179 }
7180 else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) {
7181 bytes_written = wl_android_okc_enable(net, command);
7182 }
7183 #endif /* WES_SUPPORT */
7184 #ifdef WLTDLS
7185 else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
7186 bytes_written = wl_android_tdls_reset(net);
7187 }
7188 #endif /* WLTDLS */
7189 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7190
7191 #ifdef PNO_SUPPORT
7192 else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
7193 #if defined(SUPPORT_RANDOM_MAC_SCAN)
7194 wl_cfg80211_set_random_mac(net, FALSE);
7195 #endif /* SUPPORT_RANDOM_MAC_SCAN */
7196 bytes_written = dhd_dev_pno_stop_for_ssid(net);
7197 }
7198 #ifndef WL_SCHED_SCAN
7199 else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
7200 #if defined(SUPPORT_RANDOM_MAC_SCAN)
7201 int res = BCME_ERROR;
7202 res = wl_cfg80211_set_random_mac(net, TRUE);
7203 if (res < 0 && res != BCME_UNSUPPORTED) {
7204 DHD_ERROR(("%s : failed to set random mac for PNO scan, %d\n",
7205 __FUNCTION__, res));
7206 }
7207 #endif /* SUPPORT_RANDOM_MAC_SCAN */
7208 bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
7209 }
7210 #endif /* !WL_SCHED_SCAN */
7211 else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
7212 int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
7213 bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
7214 }
7215 else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
7216 bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
7217 }
7218 #endif /* PNO_SUPPORT */
7219 else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
7220 bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
7221 }
7222 else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
7223 int skip = strlen(CMD_P2P_SET_NOA) + 1;
7224 bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
7225 priv_cmd.total_len - skip);
7226 }
7227 #ifdef P2P_LISTEN_OFFLOADING
7228 else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
7229 u8 *sub_command = strchr(command, ' ');
7230 bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
7231 sub_command ? strlen(sub_command) : 0);
7232 }
7233 #endif /* P2P_LISTEN_OFFLOADING */
7234 #if !defined WL_ENABLE_P2P_IF
7235 else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
7236 bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
7237 }
7238 #endif /* WL_ENABLE_P2P_IF */
7239 else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
7240 int skip = strlen(CMD_P2P_SET_PS) + 1;
7241 bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
7242 priv_cmd.total_len - skip);
7243 }
7244 else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
7245 int skip = strlen(CMD_P2P_ECSA) + 1;
7246 bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
7247 priv_cmd.total_len - skip);
7248 }
7249 else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
7250 int skip = strlen(CMD_P2P_INC_BW) + 1;
7251 bytes_written = wl_cfg80211_increase_p2p_bw(net,
7252 command + skip, priv_cmd.total_len - skip);
7253 }
7254 #ifdef WL_CFG80211
7255 else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
7256 strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
7257 int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
7258 bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
7259 priv_cmd.total_len - skip, *(command + skip - 2) - '0');
7260 }
7261 #ifdef WLFBT
7262 else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
7263 bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
7264 }
7265 #endif /* WLFBT */
7266 #endif /* WL_CFG80211 */
7267 #ifdef BCMCCX
7268 else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) {
7269 bytes_written = wl_android_get_cckm_rn(net, command);
7270 }
7271 else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) {
7272 bytes_written = wl_android_set_cckm_krk(net, command, priv_cmd.total_len);
7273 }
7274 else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) {
7275 bytes_written = wl_android_get_assoc_res_ies(net, command, priv_cmd.total_len);
7276 }
7277 #endif /* BCMCCX */
7278 #if defined(WL_SUPPORT_AUTO_CHANNEL)
7279 else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
7280 strlen(CMD_GET_BEST_CHANNELS)) == 0) {
7281 bytes_written = wl_cfg80211_get_best_channels(net, command,
7282 priv_cmd.total_len);
7283 }
7284 #endif /* WL_SUPPORT_AUTO_CHANNEL */
7285 #if defined(WL_SUPPORT_AUTO_CHANNEL)
7286 else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
7287 strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
7288 int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
7289 bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
7290 priv_cmd.total_len);
7291 }
7292 #endif /* WL_SUPPORT_AUTO_CHANNEL */
7293 #ifdef CUSTOMER_HW4_PRIVATE_CMD
7294 #ifdef SUPPORT_AMPDU_MPDU_CMD
7295 /* CMD_AMPDU_MPDU */
7296 else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
7297 int skip = strlen(CMD_AMPDU_MPDU) + 1;
7298 bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
7299 }
7300 #endif /* SUPPORT_AMPDU_MPDU_CMD */
7301 #if defined(SUPPORT_HIDDEN_AP)
7302 else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
7303 strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
7304 int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
7305 wl_android_set_max_num_sta(net, (const char*)command+skip);
7306 }
7307 else if (strnicmp(command, CMD_SET_HAPD_SSID,
7308 strlen(CMD_SET_HAPD_SSID)) == 0) {
7309 int skip = strlen(CMD_SET_HAPD_SSID) + 3;
7310 wl_android_set_ssid(net, (const char*)command+skip);
7311 }
7312 else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
7313 strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
7314 int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3;
7315 wl_android_set_hide_ssid(net, (const char*)command+skip);
7316 }
7317 #endif /* SUPPORT_HIDDEN_AP */
7318 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
7319 else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
7320 strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
7321 int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
7322 wl_android_sta_diassoc(net, (const char*)command+skip);
7323 }
7324 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
7325 #ifdef SUPPORT_SET_LPC
7326 else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
7327 strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
7328 int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
7329 wl_android_set_lpc(net, (const char*)command+skip);
7330 }
7331 #endif /* SUPPORT_SET_LPC */
7332 #ifdef SUPPORT_TRIGGER_HANG_EVENT
7333 else if (strnicmp(command, CMD_TEST_FORCE_HANG,
7334 strlen(CMD_TEST_FORCE_HANG)) == 0) {
7335 int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
7336 net_os_send_hang_message_reason(net, (const char*)command+skip);
7337 }
7338 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
7339 else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
7340 bytes_written = wl_android_ch_res_rl(net, true);
7341 else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
7342 bytes_written = wl_android_ch_res_rl(net, false);
7343 #ifdef SUPPORT_LTECX
7344 else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) {
7345 int skip = strlen(CMD_LTECX_SET) + 1;
7346 bytes_written = wl_android_set_ltecx(net, (const char*)command+skip);
7347 }
7348 #endif /* SUPPORT_LTECX */
7349 #ifdef WL_RELMCAST
7350 else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
7351 int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
7352 bytes_written = wl_android_rmc_enable(net, rmc_enable);
7353 }
7354 else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
7355 int rmc_txrate;
7356 sscanf(command, "%*s %10d", &rmc_txrate);
7357 bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
7358 }
7359 else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
7360 int actperiod;
7361 sscanf(command, "%*s %10d", &actperiod);
7362 bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
7363 }
7364 else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
7365 int acktimeout;
7366 sscanf(command, "%*s %10d", &acktimeout);
7367 acktimeout *= 1000;
7368 bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
7369 }
7370 else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
7371 int skip = strlen(CMD_SET_RMC_LEADER) + 1;
7372 bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
7373 }
7374 else if (strnicmp(command, CMD_SET_RMC_EVENT,
7375 strlen(CMD_SET_RMC_EVENT)) == 0) {
7376 bytes_written = wl_android_set_rmc_event(net, command);
7377 }
7378 #endif /* WL_RELMCAST */
7379 else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
7380 bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
7381 }
7382 else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
7383 bytes_written = wl_android_set_singlecore_scan(net, command);
7384 }
7385 #ifdef TEST_TX_POWER_CONTROL
7386 else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
7387 strlen(CMD_TEST_SET_TX_POWER)) == 0) {
7388 int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
7389 wl_android_set_tx_power(net, (const char*)command+skip);
7390 }
7391 else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
7392 strlen(CMD_TEST_GET_TX_POWER)) == 0) {
7393 wl_android_get_tx_power(net, command, priv_cmd.total_len);
7394 }
7395 #endif /* TEST_TX_POWER_CONTROL */
7396 else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
7397 strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
7398 int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
7399 wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
7400 }
7401 #ifdef SUPPORT_SET_TID
7402 else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) {
7403 bytes_written = wl_android_set_tid(net, command);
7404 }
7405 else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) {
7406 bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len);
7407 }
7408 #endif /* SUPPORT_SET_TID */
7409 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7410 else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
7411 int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
7412 wl_android_set_mac_address_filter(net, command+skip);
7413 }
7414 else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
7415 bytes_written = wl_android_set_roam_mode(net, command);
7416 #if defined(BCMFW_ROAM_ENABLE)
7417 else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
7418 bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
7419 }
7420 #endif /* BCMFW_ROAM_ENABLE */
7421 else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
7422 bytes_written = wl_android_set_miracast(net, command);
7423 else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
7424 bytes_written = wl_android_set_ibss_beacon_ouidata(net,
7425 command, priv_cmd.total_len);
7426 #ifdef WLAIBSS
7427 else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
7428 strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
7429 bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
7430 else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
7431 strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
7432 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
7433 TRUE);
7434 else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
7435 strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
7436 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
7437 FALSE);
7438 else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
7439 strlen(CMD_SETIBSSROUTETABLE)) == 0)
7440 bytes_written = wl_android_set_ibss_routetable(net, command);
7441 else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
7442 bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
7443 else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
7444 bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
7445 #endif /* WLAIBSS */
7446 else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
7447 int skip = strlen(CMD_KEEP_ALIVE) + 1;
7448 bytes_written = wl_keep_alive_set(net, command + skip);
7449 }
7450 else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
7451 int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
7452 bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
7453 }
7454 else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
7455 char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
7456 WL_INFORM(("Creating %s interface\n", name));
7457 if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA,
7458 name, NULL) == NULL) {
7459 bytes_written = -ENODEV;
7460 } else {
7461 /* Return success */
7462 bytes_written = 0;
7463 }
7464 }
7465 else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
7466 char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
7467 WL_INFORM(("Deleteing %s interface\n", name));
7468 bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
7469 }
7470 else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
7471 bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
7472 }
7473 #ifdef P2PRESP_WFDIE_SRC
7474 else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
7475 strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
7476 int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
7477 bytes_written = wl_android_set_wfdie_resp(net, mode);
7478 } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
7479 strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
7480 bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
7481 }
7482 #endif /* P2PRESP_WFDIE_SRC */
7483 else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
7484 char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
7485 bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
7486 }
7487 #ifdef WBTEXT
7488 else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
7489 bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
7490 }
7491 else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
7492 strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
7493 char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
7494 bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
7495 }
7496 else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
7497 strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
7498 char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
7499 bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
7500 command, priv_cmd.total_len);
7501 }
7502 else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
7503 strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
7504 char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
7505 bytes_written = wl_cfg80211_wbtext_table_config(net, data,
7506 command, priv_cmd.total_len);
7507 }
7508 else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
7509 strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
7510 char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
7511 bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
7512 command, priv_cmd.total_len);
7513 }
7514 else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
7515 strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
7516 bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
7517 priv_cmd.total_len);
7518 }
7519 else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
7520 strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
7521 bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
7522 priv_cmd.total_len);
7523 }
7524 #endif /* WBTEXT */
7525 #ifdef SET_RPS_CPUS
7526 else if (strnicmp(command, CMD_RPSMODE, strlen(CMD_RPSMODE)) == 0) {
7527 bytes_written = wl_android_set_rps_cpus(net, command);
7528 }
7529 #endif /* SET_RPS_CPUS */
7530 #ifdef WLWFDS
7531 else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
7532 bytes_written = wl_android_set_wfds_hash(net, command, 1);
7533 }
7534 else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
7535 bytes_written = wl_android_set_wfds_hash(net, command, 0);
7536 }
7537 #endif /* WLWFDS */
7538 #ifdef BT_WIFI_HANDOVER
7539 else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
7540 bytes_written = wl_tbow_teardown(net);
7541 }
7542 #endif /* BT_WIFI_HANDOVER */
7543 #ifdef CUSTOMER_HW4_PRIVATE_CMD
7544 #ifdef FCC_PWR_LIMIT_2G
7545 else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
7546 strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
7547 bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
7548 }
7549 else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
7550 strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
7551 bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command);
7552 }
7553 #endif /* FCC_PWR_LIMIT_2G */
7554 else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
7555 bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
7556 }
7557 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7558 #ifdef DYNAMIC_MUMIMO_CONTROL
7559 else if (strnicmp(command, CMD_GET_MURX_BFE_CAP,
7560 strlen(CMD_GET_MURX_BFE_CAP)) == 0) {
7561 bytes_written = wl_android_get_murx_bfe_cap(net, command, priv_cmd.total_len);
7562 }
7563 else if (strnicmp(command, CMD_SET_MURX_BFE_CAP,
7564 strlen(CMD_SET_MURX_BFE_CAP)) == 0) {
7565 uint val = *(command + strlen(CMD_SET_MURX_BFE_CAP) + 1) - '0';
7566 bytes_written = wl_android_set_murx_bfe_cap(net, val);
7567 }
7568 else if (strnicmp(command, CMD_GET_BSS_SUPPORT_MUMIMO,
7569 strlen(CMD_GET_BSS_SUPPORT_MUMIMO)) == 0) {
7570 bytes_written = wl_android_get_bss_support_mumimo(net, command, priv_cmd.total_len);
7571 }
7572 #endif /* DYNAMIC_MUMIMO_CONTROL */
7573 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
7574 else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
7575 bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
7576 }
7577 else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
7578 bytes_written = wl_android_set_ap_beaconrate(net, command);
7579 }
7580 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
7581 #ifdef SUPPORT_AP_RADIO_PWRSAVE
7582 else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
7583 bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
7584 }
7585 else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
7586 bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
7587 }
7588 else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
7589 bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
7590 }
7591 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
7592 #ifdef SUPPORT_RSSI_SUM_REPORT
7593 else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
7594 bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
7595 }
7596 else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
7597 bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
7598 }
7599 else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
7600 bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
7601 }
7602 #endif /* SUPPORT_RSSI_SUM_REPORT */
7603 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
7604 else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
7605 bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
7606 }
7607 else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
7608 == 0) {
7609 bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
7610 priv_cmd.total_len);
7611 }
7612 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
7613 #if defined(SUPPORT_RANDOM_MAC_SCAN)
7614 else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
7615 bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
7616 } else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
7617 bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
7618 }
7619 #endif /* SUPPORT_RANDOM_MAC_SCAN */
7620 #ifdef WL_NATOE
7621 else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
7622 bytes_written = wl_android_process_natoe_cmd(net, command,
7623 priv_cmd.total_len);
7624 }
7625 #endif /* WL_NATOE */
7626 #ifdef CONNECTION_STATISTICS
7627 else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
7628 strlen(CMD_GET_CONNECTION_STATS)) == 0) {
7629 bytes_written = wl_android_get_connection_stats(net, command,
7630 priv_cmd.total_len);
7631 }
7632 #endif // endif
7633 #ifdef DHD_LOG_DUMP
7634 else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
7635 strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
7636 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
7637 /* check whether it has more command */
7638 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
7639 /* compare unwanted/disconnected command */
7640 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
7641 SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
7642 dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
7643 } else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
7644 SUBCMD_DISCONNECTED, strlen(SUBCMD_DISCONNECTED)) == 0) {
7645 dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
7646 } else {
7647 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
7648 }
7649 } else {
7650 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
7651 }
7652 }
7653 #endif /* DHD_LOG_DUMP */
7654 #ifdef SET_PCIE_IRQ_CPU_CORE
7655 else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
7656 int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
7657 wl_android_set_irq_cpucore(net, affinity_cmd);
7658 }
7659 #endif /* SET_PCIE_IRQ_CPU_CORE */
7660 #if defined(DHD_HANG_SEND_UP_TEST)
7661 else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
7662 int skip = strlen(CMD_MAKE_HANG) + 1;
7663 wl_android_make_hang_with_reason(net, (const char*)command+skip);
7664 }
7665 #endif /* DHD_HANG_SEND_UP_TEST */
7666 #ifdef SUPPORT_LQCM
7667 else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
7668 int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
7669 bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
7670 }
7671 else if (strnicmp(command, CMD_GET_LQCM_REPORT,
7672 strlen(CMD_GET_LQCM_REPORT)) == 0) {
7673 bytes_written = wl_android_get_lqcm_report(net, command,
7674 priv_cmd.total_len);
7675 }
7676 #endif // endif
7677 else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
7678 bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
7679 }
7680 #ifdef WLADPS_PRIVATE_CMD
7681 else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
7682 int skip = strlen(CMD_SET_ADPS) + 1;
7683 bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
7684 }
7685 else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
7686 bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
7687 }
7688 #endif /* WLADPS_PRIVATE_CMD */
7689 #ifdef DHD_PKT_LOGGING
7690 else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
7691 strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
7692 bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
7693 }
7694 else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
7695 strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
7696 bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
7697 }
7698 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
7699 strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
7700 bytes_written =
7701 wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
7702 }
7703 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
7704 strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
7705 bytes_written =
7706 wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
7707 }
7708 else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
7709 bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
7710 }
7711 else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
7712 bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
7713 }
7714 else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
7715 bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
7716 }
7717 else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
7718 bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
7719 }
7720 else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
7721 bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
7722 }
7723 else if (strnicmp(command, CMD_PKTLOG_MINMIZE_ENABLE,
7724 strlen(CMD_PKTLOG_MINMIZE_ENABLE)) == 0) {
7725 bytes_written = wl_android_pktlog_minmize_enable(net, command, priv_cmd.total_len);
7726 }
7727 else if (strnicmp(command, CMD_PKTLOG_MINMIZE_DISABLE,
7728 strlen(CMD_PKTLOG_MINMIZE_DISABLE)) == 0) {
7729 bytes_written = wl_android_pktlog_minmize_disable(net, command, priv_cmd.total_len);
7730 }
7731 else if (strnicmp(command, CMD_PKTLOG_CHANGE_SIZE,
7732 strlen(CMD_PKTLOG_CHANGE_SIZE)) == 0) {
7733 bytes_written = wl_android_pktlog_change_size(net, command, priv_cmd.total_len);
7734 }
7735 #endif /* DHD_PKT_LOGGING */
7736 else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) {
7737 int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
7738 bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
7739 }
7740 #ifdef DHD_EVENT_LOG_FILTER
7741 else if (strnicmp(command, CMD_EWP_FILTER,
7742 strlen(CMD_EWP_FILTER)) == 0) {
7743 bytes_written = wl_android_ewp_filter(net, command, priv_cmd.total_len);
7744 }
7745 #endif /* DHD_EVENT_LOG_FILTER */
7746 #ifdef APSTA_RESTRICTED_CHANNEL
7747 else if (strnicmp(command, CMD_GET_INDOOR_CHANNELS,
7748 strlen(CMD_GET_INDOOR_CHANNELS)) == 0) {
7749 bytes_written = wl_cfg80211_get_indoor_channels(net, command, priv_cmd.total_len);
7750 DHD_INFO(("Selected Indoor Channels - %s\n", command));
7751 }
7752 else if (strnicmp(command, CMD_SET_INDOOR_CHANNELS,
7753 strlen(CMD_SET_INDOOR_CHANNELS)) == 0) {
7754 bytes_written = wl_cfg80211_set_indoor_channels(net, command, priv_cmd.total_len);
7755 }
7756 #endif /* APSTA_RESTRICTED_CHANNEL */
7757 #ifdef SUPPORT_SET_CAC
7758 else if (strnicmp(command, CMD_ENABLE_CAC, strlen(CMD_ENABLE_CAC)) == 0) {
7759 int enable = *(command + strlen(CMD_ENABLE_CAC) + 1) - '0';
7760 bytes_written = wl_cfg80211_enable_cac(net, enable);
7761 }
7762 #endif /* SUPPORT_SET_CAC */
7763 else {
7764 DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
7765 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
7766 }
7767
7768 return bytes_written;
7769 }
7770
7771 int wl_android_init(void)
7772 {
7773 int ret = 0;
7774
7775 #ifdef ENABLE_INSMOD_NO_FW_LOAD
7776 dhd_download_fw_on_driverload = FALSE;
7777 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
7778 if (!iface_name[0]) {
7779 memset(iface_name, 0, IFNAMSIZ);
7780 bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
7781 }
7782
7783 #ifdef CUSTOMER_HW4_DEBUG
7784 g_assert_type = 1;
7785 #endif /* CUSTOMER_HW4_DEBUG */
7786
7787 #ifdef WL_GENL
7788 wl_genl_init();
7789 #endif // endif
7790 wl_netlink_init();
7791
7792 return ret;
7793 }
7794
7795 int wl_android_exit(void)
7796 {
7797 int ret = 0;
7798 struct io_cfg *cur, *q;
7799
7800 #ifdef WL_GENL
7801 wl_genl_deinit();
7802 #endif /* WL_GENL */
7803 wl_netlink_deinit();
7804
7805 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
7806 #pragma GCC diagnostic push
7807 #pragma GCC diagnostic ignored "-Wcast-qual"
7808 #endif // endif
7809 list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
7810 list_del(&cur->list);
7811 kfree(cur);
7812 }
7813 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
7814 #pragma GCC diagnostic pop
7815 #endif // endif
7816
7817 return ret;
7818 }
7819
7820 void wl_android_post_init(void)
7821 {
7822
7823 #ifdef ENABLE_4335BT_WAR
7824 bcm_bt_unlock(lock_cookie_wifi);
7825 printk("%s: btlock released\n", __FUNCTION__);
7826 #endif /* ENABLE_4335BT_WAR */
7827
7828 if (!dhd_download_fw_on_driverload)
7829 g_wifi_on = FALSE;
7830 }
7831
7832 #ifdef WL_GENL
7833 /* Generic Netlink Initializaiton */
7834 static int wl_genl_init(void)
7835 {
7836 int ret;
7837
7838 WL_DBG(("GEN Netlink Init\n\n"));
7839
7840 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
7841 /* register new family */
7842 ret = genl_register_family(&wl_genl_family);
7843 if (ret != 0)
7844 goto failure;
7845
7846 /* register functions (commands) of the new family */
7847 ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
7848 if (ret != 0) {
7849 WL_ERR(("register ops failed: %i\n", ret));
7850 genl_unregister_family(&wl_genl_family);
7851 goto failure;
7852 }
7853
7854 ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
7855 #else
7856 ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
7857 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
7858 if (ret != 0) {
7859 WL_ERR(("register mc_group failed: %i\n", ret));
7860 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
7861 genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
7862 #endif // endif
7863 genl_unregister_family(&wl_genl_family);
7864 goto failure;
7865 }
7866
7867 return 0;
7868
7869 failure:
7870 WL_ERR(("Registering Netlink failed!!\n"));
7871 return -1;
7872 }
7873
7874 /* Generic netlink deinit */
7875 static int wl_genl_deinit(void)
7876 {
7877
7878 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
7879 if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
7880 WL_ERR(("Unregister wl_genl_ops failed\n"));
7881 #endif // endif
7882 if (genl_unregister_family(&wl_genl_family) < 0)
7883 WL_ERR(("Unregister wl_genl_ops failed\n"));
7884
7885 return 0;
7886 }
7887
7888 s32 wl_event_to_bcm_event(u16 event_type)
7889 {
7890 u16 event = -1;
7891
7892 switch (event_type) {
7893 case WLC_E_SERVICE_FOUND:
7894 event = BCM_E_SVC_FOUND;
7895 break;
7896 case WLC_E_P2PO_ADD_DEVICE:
7897 event = BCM_E_DEV_FOUND;
7898 break;
7899 case WLC_E_P2PO_DEL_DEVICE:
7900 event = BCM_E_DEV_LOST;
7901 break;
7902 /* Above events are supported from BCM Supp ver 47 Onwards */
7903 #ifdef BT_WIFI_HANDOVER
7904 case WLC_E_BT_WIFI_HANDOVER_REQ:
7905 event = BCM_E_DEV_BT_WIFI_HO_REQ;
7906 break;
7907 #endif /* BT_WIFI_HANDOVER */
7908
7909 default:
7910 WL_ERR(("Event not supported\n"));
7911 }
7912
7913 return event;
7914 }
7915
7916 s32
7917 wl_genl_send_msg(
7918 struct net_device *ndev,
7919 u32 event_type,
7920 const u8 *buf,
7921 u16 len,
7922 u8 *subhdr,
7923 u16 subhdr_len)
7924 {
7925 int ret = 0;
7926 struct sk_buff *skb;
7927 void *msg;
7928 u32 attr_type = 0;
7929 bcm_event_hdr_t *hdr = NULL;
7930 int mcast = 1; /* By default sent as mutlicast type */
7931 int pid = 0;
7932 u8 *ptr = NULL, *p = NULL;
7933 u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
7934 u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
7935 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
7936
7937 WL_DBG(("Enter \n"));
7938
7939 /* Decide between STRING event and Data event */
7940 if (event_type == 0)
7941 attr_type = BCM_GENL_ATTR_STRING;
7942 else
7943 attr_type = BCM_GENL_ATTR_MSG;
7944
7945 skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
7946 if (skb == NULL) {
7947 ret = -ENOMEM;
7948 goto out;
7949 }
7950
7951 msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
7952 if (msg == NULL) {
7953 ret = -ENOMEM;
7954 goto out;
7955 }
7956
7957 if (attr_type == BCM_GENL_ATTR_STRING) {
7958 /* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
7959 * make sure it is null terminated
7960 */
7961 if (subhdr || subhdr_len) {
7962 WL_ERR(("No sub hdr support for the ATTR STRING type \n"));
7963 ret = -EINVAL;
7964 goto out;
7965 }
7966
7967 ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
7968 if (ret != 0) {
7969 WL_ERR(("nla_put_string failed\n"));
7970 goto out;
7971 }
7972 } else {
7973 /* ATTR_MSG */
7974
7975 /* Create a single buffer for all */
7976 p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
7977 if (!ptr) {
7978 ret = -ENOMEM;
7979 WL_ERR(("ENOMEM!!\n"));
7980 goto out;
7981 }
7982
7983 /* Include the bcm event header */
7984 hdr = (bcm_event_hdr_t *)ptr;
7985 hdr->event_type = wl_event_to_bcm_event(event_type);
7986 hdr->len = len + subhdr_len;
7987 ptr += sizeof(bcm_event_hdr_t);
7988
7989 /* Copy subhdr (if any) */
7990 if (subhdr && subhdr_len) {
7991 memcpy(ptr, subhdr, subhdr_len);
7992 ptr += subhdr_len;
7993 }
7994
7995 /* Copy the data */
7996 if (buf && len) {
7997 memcpy(ptr, buf, len);
7998 }
7999
8000 ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
8001 if (ret != 0) {
8002 WL_ERR(("nla_put_string failed\n"));
8003 goto out;
8004 }
8005 }
8006
8007 if (mcast) {
8008 int err = 0;
8009 /* finalize the message */
8010 genlmsg_end(skb, msg);
8011 /* NETLINK_CB(skb).dst_group = 1; */
8012
8013 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
8014 if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
8015 #else
8016 if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
8017 #endif // endif
8018 WL_ERR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
8019 attr_type, err));
8020 else
8021 WL_DBG(("Multicast msg sent successfully. attr_type:%d len:%d \n",
8022 attr_type, tot_len));
8023 } else {
8024 NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
8025
8026 /* finalize the message */
8027 genlmsg_end(skb, msg);
8028
8029 /* send the message back */
8030 if (genlmsg_unicast(&init_net, skb, pid) < 0)
8031 WL_ERR(("genlmsg_unicast failed\n"));
8032 }
8033
8034 out:
8035 if (p) {
8036 MFREE(cfg->osh, p, tot_len);
8037 }
8038 if (ret)
8039 nlmsg_free(skb);
8040
8041 return ret;
8042 }
8043
8044 static s32
8045 wl_genl_handle_msg(
8046 struct sk_buff *skb,
8047 struct genl_info *info)
8048 {
8049 struct nlattr *na;
8050 u8 *data = NULL;
8051
8052 WL_DBG(("Enter \n"));
8053
8054 if (info == NULL) {
8055 return -EINVAL;
8056 }
8057
8058 na = info->attrs[BCM_GENL_ATTR_MSG];
8059 if (!na) {
8060 WL_ERR(("nlattribute NULL\n"));
8061 return -EINVAL;
8062 }
8063
8064 data = (char *)nla_data(na);
8065 if (!data) {
8066 WL_ERR(("Invalid data\n"));
8067 return -EINVAL;
8068 } else {
8069 /* Handle the data */
8070 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || defined(WL_COMPAT_WIRELESS)
8071 WL_DBG(("%s: Data received from pid (%d) \n", __func__,
8072 info->snd_pid));
8073 #else
8074 WL_DBG(("%s: Data received from pid (%d) \n", __func__,
8075 info->snd_portid));
8076 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
8077 }
8078
8079 return 0;
8080 }
8081 #endif /* WL_GENL */
8082
8083 int wl_fatal_error(void * wl, int rc)
8084 {
8085 return FALSE;
8086 }
8087
8088 #if defined(BT_OVER_SDIO)
8089 void
8090 wl_android_set_wifi_on_flag(bool enable)
8091 {
8092 g_wifi_on = enable;
8093 }
8094 #endif /* BT_OVER_SDIO */
8095
8096 #ifdef WL_STATIC_IF
8097 struct net_device *
8098 wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname)
8099 {
8100 struct net_device *ndev;
8101 struct wireless_dev *wdev = NULL;
8102 int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */
8103 u8 mac_addr[ETH_ALEN];
8104 struct net_device *primary_ndev;
8105
8106 WL_INFORM_MEM(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype));
8107
8108 if (!cfg) {
8109 WL_ERR(("cfg null\n"));
8110 return NULL;
8111 }
8112
8113 /* Use primary mac with locally admin bit set */
8114 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
8115 memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
8116 mac_addr[0] |= 0x02;
8117
8118 ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr,
8119 WL_BSSIDX_MAX, NULL);
8120 if (unlikely(!ndev)) {
8121 WL_ERR(("Failed to allocate static_if\n"));
8122 goto fail;
8123 }
8124 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
8125 if (unlikely(!wdev)) {
8126 WL_ERR(("Failed to allocate wdev for static_if\n"));
8127 goto fail;
8128 }
8129
8130 wdev->wiphy = cfg->wdev->wiphy;
8131 wdev->iftype = iftype;
8132
8133 ndev->ieee80211_ptr = wdev;
8134 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
8135 wdev->netdev = ndev;
8136
8137 if (wl_cfg80211_register_if(cfg, ifidx,
8138 ndev, TRUE) != BCME_OK) {
8139 WL_ERR(("ndev registration failed!\n"));
8140 goto fail;
8141 }
8142
8143 cfg->static_ndev = ndev;
8144 cfg->static_ndev_state = NDEV_STATE_OS_IF_CREATED;
8145 wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
8146 ifname, NDEV_STATE_OS_IF_CREATED);
8147 WL_INFORM_MEM(("Static I/F (%s) Registered\n", ndev->name));
8148 return ndev;
8149
8150 fail:
8151 wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
8152 return NULL;
8153 }
8154
8155 void
8156 wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
8157 {
8158 WL_INFORM_MEM(("[STATIC_IF] Enter\n"));
8159 if (!cfg || !cfg->static_ndev) {
8160 WL_ERR(("invalid input\n"));
8161 return;
8162 }
8163
8164 /* wdev free will happen from notifier context */
8165 /* free_netdev(cfg->static_ndev);
8166 */
8167 unregister_netdev(cfg->static_ndev);
8168 }
8169
8170 s32
8171 wl_cfg80211_static_if_open(struct net_device *net)
8172 {
8173 struct wireless_dev *wdev = NULL;
8174 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
8175 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
8176 u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
8177 u16 wl_iftype, wl_mode;
8178
8179 WL_INFORM_MEM(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr));
8180 ASSERT(cfg->static_ndev == net);
8181
8182 if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) < 0) {
8183 return BCME_ERROR;
8184 }
8185 if (cfg->static_ndev_state != NDEV_STATE_FW_IF_CREATED) {
8186 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, NULL);
8187 ASSERT(wdev == net->ieee80211_ptr);
8188 } else {
8189 WL_INFORM_MEM(("Fw IF for static netdev already created\n"));
8190 }
8191
8192 return BCME_OK;
8193 }
8194
8195 s32
8196 wl_cfg80211_static_if_close(struct net_device *net)
8197 {
8198 int ret = BCME_OK;
8199 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
8200 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
8201
8202 if (cfg->static_ndev_state == NDEV_STATE_FW_IF_CREATED) {
8203 ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
8204 if (unlikely(ret)) {
8205 WL_ERR(("Del iface failed for static_if %d\n", ret));
8206 }
8207 }
8208
8209 return ret;
8210 }
8211 struct net_device *
8212 wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
8213 wl_if_event_info *event, u8 *addr, s32 iface_type)
8214 {
8215 struct net_device *new_ndev = NULL;
8216 struct wireless_dev *wdev = NULL;
8217
8218 WL_INFORM_MEM(("Updating static iface after Fw IF create \n"));
8219 new_ndev = cfg->static_ndev;
8220
8221 if (new_ndev) {
8222 wdev = new_ndev->ieee80211_ptr;
8223 ASSERT(wdev);
8224 wdev->iftype = iface_type;
8225 memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
8226 }
8227
8228 cfg->static_ndev_state = NDEV_STATE_FW_IF_CREATED;
8229 wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx,
8230 event->name, NDEV_STATE_FW_IF_CREATED);
8231 return new_ndev;
8232 }
8233 s32
8234 wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev)
8235 {
8236 cfg->static_ndev_state = NDEV_STATE_FW_IF_DELETED;
8237 wl_cfg80211_update_iflist_info(cfg, ndev, WL_STATIC_IFIDX, NULL,
8238 WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED);
8239 wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
8240 wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
8241 return BCME_OK;
8242 }
8243 #endif /* WL_STATIC_IF */