wifi: fix wifi close issue and ap62x8 open fail issue
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.1.579.77.41.1.cn / wl_cfg80211.c
CommitLineData
010c3a89
RC
1/*
2 * Linux cfg80211 driver
3 *
4 * Copyright (C) 1999-2017, Broadcom Corporation
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_cfg80211.c 711110 2017-07-17 04:38:25Z $
28 */
29/* */
30#include <typedefs.h>
31#include <linuxver.h>
32#include <osl.h>
33#include <linux/kernel.h>
34
35#include <wlc_types.h>
36#include <bcmutils.h>
37#include <bcmwifi_channels.h>
38#include <bcmendian.h>
39#include <ethernet.h>
40#include <802.11.h>
41#include <linux/if_arp.h>
42#include <asm/uaccess.h>
43
44#include <ethernet.h>
45#include <linux/kernel.h>
46#include <linux/kthread.h>
47#include <linux/netdevice.h>
48#include <linux/sched.h>
49#include <linux/etherdevice.h>
50#include <linux/wireless.h>
51#include <linux/ieee80211.h>
52#include <linux/wait.h>
53#include <net/cfg80211.h>
54#include <net/rtnetlink.h>
55
56#include <wlioctl.h>
57#include <wldev_common.h>
58#include <wl_cfg80211.h>
59#include <wl_cfgp2p.h>
60#include <bcmdevs.h>
61#include <wl_android.h>
62#include <dngl_stats.h>
63#include <dhd.h>
64#include <dhd_linux.h>
65#include <dhd_debug.h>
66#include <dhdioctl.h>
67#include <wlioctl.h>
68#include <dhd_cfg80211.h>
69#include <dhd_bus.h>
70#ifdef PNO_SUPPORT
71#include <dhd_pno.h>
72#endif /* PNO_SUPPORT */
73#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
74#include <wl_cfgvendor.h>
75#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
76
dfb0f3ae
RC
77#if !defined(WL_VENDOR_EXT_SUPPORT)
78#undef GSCAN_SUPPORT
79#endif
80
010c3a89
RC
81#if defined(STAT_REPORT)
82#include <wl_statreport.h>
83#endif /* STAT_REPORT */
84#include <dhd_config.h>
85
86
87#ifdef PROP_TXSTATUS
88#include <dhd_wlfc.h>
89#endif
90
91#ifdef BCMPCIE
92#include <dhd_flowring.h>
93#endif
94#ifdef RTT_SUPPORT
95#include <dhd_rtt.h>
96#endif /* RTT_SUPPORT */
97#ifdef WL11U
98#endif /* WL11U */
99
100#ifndef DHD_UNSUPPORT_IF_CNTS
101#define DHD_SUPPORT_IF_CNTS
102#endif /* !DHD_UN_SUPPORT_IF_CNTS */
103
104
105#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
106
107static struct device *cfg80211_parent_dev = NULL;
108#ifdef CUSTOMER_HW4_DEBUG
109u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_P2P_ACTION;
110#else
111u32 wl_dbg_level = WL_DBG_ERR;
112#endif /* CUSTOMER_HW4_DEBUG */
113
114#define MAX_WAIT_TIME 1500
115#ifdef WLAIBSS_MCHAN
116#define IBSS_IF_NAME "ibss%d"
117#endif /* WLAIBSS_MCHAN */
118
119#ifdef VSDB
120/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
121#define DEFAULT_SLEEP_TIME_VSDB 120
122#define OFF_CHAN_TIME_THRESHOLD_MS 200
123#define AF_RETRY_DELAY_TIME 40
124
125/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
126#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
127 do { \
128 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
129 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
130 OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
131 } \
132 } while (0)
133#else /* VSDB */
134/* if not VSDB, do nothing */
135#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
136#endif /* VSDB */
137
138#ifdef WL_CFG80211_SYNC_GON
139#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) \
140 (wl_get_drv_status_all(cfg, SENDING_ACT_FRM) || \
141 wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN))
142#else
143#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) wl_get_drv_status_all(cfg, SENDING_ACT_FRM)
144#endif /* WL_CFG80211_SYNC_GON */
145
146#define DNGL_FUNC(func, parameters) func parameters
147#define COEX_DHCP
148
149#define WLAN_EID_SSID 0
150#define CH_MIN_5G_CHANNEL 34
151#define CH_MIN_2G_CHANNEL 1
152#define ACTIVE_SCAN 1
153#define PASSIVE_SCAN 0
154
155#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
156 4 && __GNUC_MINOR__ >= 6))
157#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
158_Pragma("GCC diagnostic push") \
159_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
160(entry) = list_first_entry((ptr), type, member); \
161_Pragma("GCC diagnostic pop") \
162
163#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
164_Pragma("GCC diagnostic push") \
165_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
166entry = container_of((ptr), type, member); \
167_Pragma("GCC diagnostic pop") \
168
169#else
170#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
171(entry) = list_first_entry((ptr), type, member); \
172
173#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
174entry = container_of((ptr), type, member); \
175
176#endif /* STRICT_GCC_WARNINGS */
177
178#ifdef WL_RELMCAST
179enum rmc_event_type {
180 RMC_EVENT_NONE,
181 RMC_EVENT_LEADER_CHECK_FAIL
182};
183#endif /* WL_RELMCAST */
184
185#ifdef WL_LASTEVT
186typedef struct wl_last_event {
187 uint32 current_time; /* current tyime */
188 uint32 timestamp; /* event timestamp */
189 wl_event_msg_t event; /* Encapsulated event */
190} wl_last_event_t;
191#endif /* WL_LASTEVT */
192
193/* This is to override regulatory domains defined in cfg80211 module (reg.c)
194 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
195 * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
196 * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
197 * All the chnages in world regulatory domain are to be done here.
198 *
199 * this definition reuires disabling missing-field-initializer warning
200 * as the ieee80211_regdomain definition differs in plain linux and in Android
201 */
202#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
203 4 && __GNUC_MINOR__ >= 6))
204_Pragma("GCC diagnostic push")
205_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
206#endif
207static const struct ieee80211_regdomain brcm_regdom = {
208 .n_reg_rules = 4,
209 .alpha2 = "99",
210 .reg_rules = {
211 /* IEEE 802.11b/g, channels 1..11 */
212 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
213 /* If any */
214 /* IEEE 802.11 channel 14 - Only JP enables
215 * this and for 802.11b only
216 */
217 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
218 /* IEEE 802.11a, channel 36..64 */
219 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
220 /* IEEE 802.11a, channel 100..165 */
221 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
222};
223#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
224 4 && __GNUC_MINOR__ >= 6))
225_Pragma("GCC diagnostic pop")
226#endif
227
228
229#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
230 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
231static const struct ieee80211_iface_limit common_if_limits[] = {
232 {
233 /*
234 * Driver can support up to 2 AP's
235 */
236 .max = 2,
237 .types = BIT(NL80211_IFTYPE_AP),
238 },
239 {
240 /*
241 * During P2P-GO removal, P2P-GO is first changed to STA and later only
242 * removed. So setting maximum possible number of STA interfaces according
243 * to kernel version.
244 *
245 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
246 * linux-3.8 and above - max:2 (wlan0 + group removal of p2p-wlan0-x)
247 */
248#ifdef WL_ENABLE_P2P_IF
249 .max = 3,
250#else
251 .max = 2,
252#endif /* WL_ENABLE_P2P_IF */
253 .types = BIT(NL80211_IFTYPE_STATION),
254 },
255 {
256 .max = 2,
257 .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
258 },
259#if defined(WL_CFG80211_P2P_DEV_IF)
260 {
261 .max = 1,
262 .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
263 },
264#endif /* WL_CFG80211_P2P_DEV_IF */
265 {
266 .max = 1,
267 .types = BIT(NL80211_IFTYPE_ADHOC),
268 },
269};
270#ifdef BCM4330_CHIP
271#define NUM_DIFF_CHANNELS 1
272#else
273#define NUM_DIFF_CHANNELS 2
274#endif
d964ce36 275static const struct ieee80211_iface_combination
010c3a89
RC
276common_iface_combinations[] = {
277 {
278 .num_different_channels = NUM_DIFF_CHANNELS,
279 /*
280 * max_interfaces = 4
281 * The max no of interfaces will be used in dual p2p case.
282 * {STA, P2P Device, P2P Group 1, P2P Group 2}. Though we
283 * will not be using the STA functionality in this case, it
284 * will remain registered as it is the primary interface.
285 */
286 .max_interfaces = 4,
287 .limits = common_if_limits,
288 .n_limits = ARRAY_SIZE(common_if_limits),
289 },
290};
291#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
292
293/* Data Element Definitions */
294#define WPS_ID_CONFIG_METHODS 0x1008
295#define WPS_ID_REQ_TYPE 0x103A
296#define WPS_ID_DEVICE_NAME 0x1011
297#define WPS_ID_VERSION 0x104A
298#define WPS_ID_DEVICE_PWD_ID 0x1012
299#define WPS_ID_REQ_DEV_TYPE 0x106A
300#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
301#define WPS_ID_PRIM_DEV_TYPE 0x1054
302
303/* Device Password ID */
304#define DEV_PW_DEFAULT 0x0000
305#define DEV_PW_USER_SPECIFIED 0x0001,
306#define DEV_PW_MACHINE_SPECIFIED 0x0002
307#define DEV_PW_REKEY 0x0003
308#define DEV_PW_PUSHBUTTON 0x0004
309#define DEV_PW_REGISTRAR_SPECIFIED 0x0005
310
311/* Config Methods */
312#define WPS_CONFIG_USBA 0x0001
313#define WPS_CONFIG_ETHERNET 0x0002
314#define WPS_CONFIG_LABEL 0x0004
315#define WPS_CONFIG_DISPLAY 0x0008
316#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
317#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
318#define WPS_CONFIG_NFC_INTERFACE 0x0040
319#define WPS_CONFIG_PUSHBUTTON 0x0080
320#define WPS_CONFIG_KEYPAD 0x0100
321#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
322#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
323#define WPS_CONFIG_VIRT_DISPLAY 0x2008
324#define WPS_CONFIG_PHY_DISPLAY 0x4008
325
326#define PM_BLOCK 1
327#define PM_ENABLE 0
328
329
330#define WL_AKM_SUITE_SHA256_1X 0x000FAC05
331#define WL_AKM_SUITE_SHA256_PSK 0x000FAC06
332
333#ifndef IBSS_COALESCE_ALLOWED
334#define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT
335#endif
336
337#ifndef IBSS_INITIAL_SCAN_ALLOWED
338#define IBSS_INITIAL_SCAN_ALLOWED IBSS_INITIAL_SCAN_ALLOWED_DEFAULT
339#endif
340
341#define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
342#define LONG_LISTEN_TIME 2000
343
344#ifdef WBTEXT
345#define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
346#define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
347#define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
348#define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
349#define DEFAULT_WBTEXT_PROFILE_A "a -70 -75 70 10 -75 -128 0 10"
350#define DEFAULT_WBTEXT_PROFILE_B "b -60 -75 70 10 -75 -128 0 10"
351#define DEFAULT_WBTEXT_WEIGHT_RSSI_A "RSSI a 65"
352#define DEFAULT_WBTEXT_WEIGHT_RSSI_B "RSSI b 65"
353#define DEFAULT_WBTEXT_WEIGHT_CU_A "CU a 35"
354#define DEFAULT_WBTEXT_WEIGHT_CU_B "CU b 35"
355#define DEFAULT_WBTEXT_TABLE_RSSI_A "RSSI a 0 55 100 55 60 90 \
35660 65 70 65 70 50 70 128 20"
357#define DEFAULT_WBTEXT_TABLE_RSSI_B "RSSI b 0 55 100 55 60 90 \
35860 65 70 65 70 50 70 128 20"
359#define DEFAULT_WBTEXT_TABLE_CU_A "CU a 0 30 100 30 50 90 \
36050 60 70 60 80 50 80 100 20"
361#define DEFAULT_WBTEXT_TABLE_CU_B "CU b 0 10 100 10 25 90 \
36225 40 70 40 70 50 70 100 20"
363
364typedef struct wl_wbtext_bssid {
365 struct ether_addr ea;
366 struct list_head list;
367} wl_wbtext_bssid_t;
368
369static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev);
370static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
371static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
372static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg);
373static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
374 struct wl_profile *profile);
375static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
376 struct wl_profile *profile);
377static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev);
378static int wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, int body_len);
379#endif /* WBTEXT */
380
381#ifdef SUPPORT_AP_RADIO_PWRSAVE
382#define RADIO_PWRSAVE_PPS 10
383#define RADIO_PWRSAVE_QUIET_TIME 10
384#define RADIO_PWRSAVE_LEVEL 3
385#define RADIO_PWRSAVE_STAS_ASSOC_CHECK 0
386
387#define RADIO_PWRSAVE_LEVEL_MIN 1
388#define RADIO_PWRSAVE_LEVEL_MAX 5
389#define RADIO_PWRSAVE_PPS_MIN 1
390#define RADIO_PWRSAVE_QUIETTIME_MIN 1
391#define RADIO_PWRSAVE_ASSOCCHECK_MIN 0
392#define RADIO_PWRSAVE_ASSOCCHECK_MAX 1
393
394#define RADIO_PWRSAVE_MAJOR_VER 1
395#define RADIO_PWRSAVE_MINOR_VER 0
396#define RADIO_PWRSAVE_MAJOR_VER_SHIFT 8
397#define RADIO_PWRSAVE_VERSION \
398 ((RADIO_PWRSAVE_MAJOR_VER << RADIO_PWRSAVE_MAJOR_VER_SHIFT)| RADIO_PWRSAVE_MINOR_VER)
399#endif /* SUPPORT_AP_RADIO_PWRSAVE */
400
401#ifdef WLADPS_SEAK_AP_WAR
402#define ATHEROS_OUI "\x00\x03\x7F"
403#define CAMEO_MAC_PREFIX "\x00\x18\xE7"
404#define MAC_PREFIX_LEN 3
405static bool
406wl_find_vndr_ies_specific_vender(struct bcm_cfg80211 *cfg,
407 struct net_device *ndev, const u8 *vndr_oui);
408static s32 wl_set_adps_mode(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint8 enable_mode);
409#endif /* WLADPS_SEAK_AP_WAR */
410
411#define MAX_VNDR_OUI_STR_LEN 256
412#define VNDR_OUI_STR_LEN 10
413static const uchar *exclude_vndr_oui_list[] = {
414 "\x00\x50\xf2", /* Microsoft */
415 "\x00\x00\xf0", /* Samsung Elec */
416 WFA_OUI, /* WFA */
417 NULL
418};
419
420typedef struct wl_vndr_oui_entry {
421 uchar oui[DOT11_OUI_LEN];
422 struct list_head list;
423} wl_vndr_oui_entry_t;
424
425static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
426 struct net_device *ndev, char *vndr_oui, u32 vndr_oui_len);
427static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg);
428
429/*
430 * cfg80211_ops api/callback list
431 */
432static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
433 const struct ether_addr *sa, const struct ether_addr *bssid,
434 u8 **pheader, u32 *body_len, u8 *pbody);
435static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
436 struct cfg80211_scan_request *request,
437 struct cfg80211_ssid *this_ssid);
438#if defined(WL_CFG80211_P2P_DEV_IF)
439static s32
440wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request);
441#else
442static s32
443wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
444 struct cfg80211_scan_request *request);
445#endif /* WL_CFG80211_P2P_DEV_IF */
446static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
447#ifdef WLAIBSS_MCHAN
448static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name);
449static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
450#endif /* WLAIBSS_MCHAN */
451static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
452 struct cfg80211_ibss_params *params);
453static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
454 struct net_device *dev);
455#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
456static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
457 struct net_device *dev, const u8 *mac,
458 struct station_info *sinfo);
459#else
460static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
461 struct net_device *dev, u8 *mac,
462 struct station_info *sinfo);
463#endif
464static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
465 struct net_device *dev, bool enabled,
466 s32 timeout);
467static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
468 struct cfg80211_connect_params *sme);
469static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
470 u16 reason_code);
471#if defined(WL_CFG80211_P2P_DEV_IF)
472static s32
473wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
474 enum nl80211_tx_power_setting type, s32 mbm);
475#else
476static s32
477wl_cfg80211_set_tx_power(struct wiphy *wiphy,
478 enum nl80211_tx_power_setting type, s32 dbm);
479#endif /* WL_CFG80211_P2P_DEV_IF */
480#if defined(WL_CFG80211_P2P_DEV_IF)
481static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
482 struct wireless_dev *wdev, s32 *dbm);
483#else
484static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
485#endif /* WL_CFG80211_P2P_DEV_IF */
486static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
487 struct net_device *dev,
488 u8 key_idx, bool unicast, bool multicast);
489static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
490 u8 key_idx, bool pairwise, const u8 *mac_addr,
491 struct key_params *params);
492static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
493 u8 key_idx, bool pairwise, const u8 *mac_addr);
494static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
495 u8 key_idx, bool pairwise, const u8 *mac_addr,
496 void *cookie, void (*callback) (void *cookie,
497 struct key_params *params));
498static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
499 struct net_device *dev, u8 key_idx);
500static s32 wl_cfg80211_resume(struct wiphy *wiphy);
501#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
502 2, 0))
503static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
504 bcm_struct_cfgdev *cfgdev, u64 cookie);
505#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
506static s32 wl_cfg80211_del_station(
507 struct wiphy *wiphy, struct net_device *ndev,
508 struct station_del_parameters *params);
509#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
510static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
511 struct net_device *ndev, const u8* mac_addr);
512#else
513static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
514 struct net_device *ndev, u8* mac_addr);
515#endif
dfb0f3ae
RC
516#ifdef WLMESH
517static s32 wl_cfg80211_join_mesh(
518 struct wiphy *wiphy, struct net_device *dev,
519 const struct mesh_config *conf,
520 const struct mesh_setup *setup);
521static s32 wl_cfg80211_leave_mesh(struct wiphy *wiphy,
522 struct net_device *dev);
523#endif /* WLMESH */
010c3a89
RC
524#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
525static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
526 struct net_device *dev, const u8 *mac, struct station_parameters *params);
527#else
528static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
529 struct net_device *dev, u8 *mac, struct station_parameters *params);
530#endif
531#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
532#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
533static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
534#else
535static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
536#endif
537static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
538 struct cfg80211_pmksa *pmksa);
539static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
540 struct cfg80211_pmksa *pmksa);
541static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
542 struct net_device *dev);
543void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
544static void wl_cfg80211_cancel_scan(struct bcm_cfg80211 *cfg);
545static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
546 struct net_device *ndev, bool aborted, bool fw_abort);
547#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
548#if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
549 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
550static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
551 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
552 u32 peer_capability, const u8 *buf, size_t len);
553#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
554 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
555static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
556 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
557 u32 peer_capability, const u8 *buf, size_t len);
558#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
559static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
560 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
561 u32 peer_capability, bool initiator, const u8 *buf, size_t len);
562#else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
563static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
564 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
565 const u8 *buf, size_t len);
566#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
567#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
568static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
569 const u8 *peer, enum nl80211_tdls_operation oper);
570#else
571static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
572 u8 *peer, enum nl80211_tdls_operation oper);
573#endif
574#endif
575#ifdef WL_SCHED_SCAN
dfb0f3ae
RC
576static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
577#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
578 , u64 reqid
579#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
580);
010c3a89
RC
581#endif
582static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg, struct net_device *dev);
583#if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF)
584bcm_struct_cfgdev*
585wl_cfg80211_create_iface(struct wiphy *wiphy, enum nl80211_iftype
586 iface_type, u8 *mac_addr, const char *name);
587s32
588wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
589#endif /* defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) */
590
591s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
592 struct net_device *ndev, s32 bsscfg_idx,
593 enum nl80211_iftype iface_type, s32 del, u8 *addr);
594s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
595 struct net_device *ndev, s32 bsscfg_idx,
596 enum nl80211_iftype iface_type, s32 del, u8 *addr);
597#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
598static s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev);
599#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */
600#ifdef GTK_OFFLOAD_SUPPORT
601#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
602static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
603 struct cfg80211_gtk_rekey_data *data);
604#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
605#endif /* GTK_OFFLOAD_SUPPORT */
606chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
607chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
608#ifdef WL11ULB
609static s32 wl_cfg80211_get_ulb_bw(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev);
610static chanspec_t wl_cfg80211_ulb_get_min_bw_chspec(struct bcm_cfg80211 *cfg,
611 struct wireless_dev *wdev, s32 bssidx);
612static s32 wl_cfg80211_ulbbw_to_ulbchspec(u32 ulb_bw);
613#else
614static inline chanspec_t wl_cfg80211_ulb_get_min_bw_chspec(
615 struct bcm_cfg80211 *cfg, struct wireless_dev *wdev, s32 bssidx)
616{
617 return WL_CHANSPEC_BW_20;
618}
619#endif /* WL11ULB */
620static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev);
621
622/*
623 * event & event Q handlers for cfg80211 interfaces
624 */
625static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
626static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
627static void wl_event_handler(struct work_struct *work_data);
628static void wl_init_eq(struct bcm_cfg80211 *cfg);
629static void wl_flush_eq(struct bcm_cfg80211 *cfg);
630static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
631static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
632static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
633static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
634static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
635static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
636 const wl_event_msg_t *msg, void *data);
637static void wl_put_event(struct wl_event_q *e);
638static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
639 const wl_event_msg_t *e, void *data);
640static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
641 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
642static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
643 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
644static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
645 const wl_event_msg_t *e, void *data);
646static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
647 const wl_event_msg_t *e, void *data, bool completed);
648static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
649 const wl_event_msg_t *e, void *data);
650static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
651 const wl_event_msg_t *e, void *data);
652#ifdef BT_WIFI_HANDOVER
653static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
654 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
655#endif /* BT_WIFI_HANDOVER */
656#ifdef WL_SCHED_SCAN
657static s32
658wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
659 const wl_event_msg_t *e, void *data);
660#endif /* WL_SCHED_SCAN */
661#ifdef PNO_SUPPORT
662static s32 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
663 const wl_event_msg_t *e, void *data);
664#endif /* PNO_SUPPORT */
665#ifdef GSCAN_SUPPORT
666static s32 wl_notify_gscan_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
667 const wl_event_msg_t *e, void *data);
668static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
669 const wl_event_msg_t *e, void *data);
670#endif /* GSCAN_SUPPORT */
671#ifdef RSSI_MONITOR_SUPPORT
672static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
673 const wl_event_msg_t *e, void *data);
674#endif /* RSSI_MONITOR_SUPPORT */
675static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
676 enum wl_status state, bool set);
677#ifdef CUSTOM_EVENT_PM_WAKE
678static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
679 const wl_event_msg_t *e, void *data);
680#endif /* CUSTOM_EVENT_PM_WAKE */
681#ifdef ENABLE_TEMP_THROTTLING
682static s32 wl_check_rx_throttle_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
683 const wl_event_msg_t *e, void *data);
684#endif /* ENABLE_TEMP_THROTTLING */
685#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
686static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
687 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
688#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
689#ifdef DHD_LOSSLESS_ROAMING
690static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
691#endif /* DHD_LOSSLESS_ROAMING */
692
693#ifdef WLTDLS
694static s32 wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg,
695 enum wl_tdls_config state, bool tdls_mode);
696static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
697 const wl_event_msg_t *e, void *data);
698#endif /* WLTDLS */
699/*
700 * register/deregister parent device
701 */
702static void wl_cfg80211_clear_parent_dev(void);
703/*
704 * ioctl utilites
705 */
706
707/*
708 * cfg80211 set_wiphy_params utilities
709 */
710static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
711static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
712static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
713
714/*
715 * cfg profile utilities
716 */
717static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
718 const wl_event_msg_t *e, const void *data, s32 item);
719static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item);
720static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
721
722/*
723 * cfg80211 connect utilites
724 */
725static s32 wl_set_wpa_version(struct net_device *dev,
726 struct cfg80211_connect_params *sme);
727static s32 wl_set_auth_type(struct net_device *dev,
728 struct cfg80211_connect_params *sme);
729static s32 wl_set_set_cipher(struct net_device *dev,
730 struct cfg80211_connect_params *sme);
731static s32 wl_set_key_mgmt(struct net_device *dev,
732 struct cfg80211_connect_params *sme);
733static s32 wl_set_set_sharedkey(struct net_device *dev,
734 struct cfg80211_connect_params *sme);
735static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
736static s32 wl_ch_to_chanspec(struct net_device *dev, int ch,
737 struct wl_join_params *join_params, size_t *join_params_size);
738void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
739
740/*
741 * information element utilities
742 */
743static void wl_rst_ie(struct bcm_cfg80211 *cfg);
744static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
745static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, const u8 *ie_stream, u32 *ie_size,
746 bool roam);
747static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size);
748static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size);
749static u32 wl_get_ielen(struct bcm_cfg80211 *cfg);
750#ifdef MFP
751static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8** rsn_cap);
752#endif
753
754#ifdef WL11U
755static bcm_tlv_t *
756wl_cfg80211_find_interworking_ie(const u8 *parse, u32 len);
757static s32
758wl_cfg80211_clear_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx);
759static s32
760wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
761 uint8 ie_id, uint8 *data, uint8 data_len);
762#endif /* WL11U */
763
764static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, dhd_pub_t *data);
765static void wl_free_wdev(struct bcm_cfg80211 *cfg);
766#ifdef CONFIG_CFG80211_INTERNAL_REGDB
767#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
768static int
769#else
770static void
771#endif /* kernel version < 3.10.11 */
772wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
773#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
774
775static s32 wl_inform_bss(struct bcm_cfg80211 *cfg);
776static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam);
777static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam);
778static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
779s32 wl_cfg80211_channel_to_freq(u32 channel);
780
781
782static void wl_cfg80211_work_handler(struct work_struct *work);
783static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
784 u8 key_idx, const u8 *mac_addr,
785 struct key_params *params);
786/*
787 * key indianess swap utilities
788 */
789static void swap_key_from_BE(struct wl_wsec_key *key);
790static void swap_key_to_BE(struct wl_wsec_key *key);
791
792/*
793 * bcm_cfg80211 memory init/deinit utilities
794 */
795static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
796static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
797
798static void wl_delay(u32 ms);
799
800/*
801 * ibss mode utilities
802 */
803static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev);
804static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
805
806/*
807 * link up/down , default configuration utilities
808 */
809static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
810static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
811
812#ifdef WL_LASTEVT
813static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, void *data);
814#define WL_IS_LINKDOWN(cfg, e, data) wl_is_linkdown(cfg, e, data)
815#else
816static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
817#define WL_IS_LINKDOWN(cfg, e, data) wl_is_linkdown(cfg, e)
818#endif /* WL_LASTEVT */
819
820static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
821 struct net_device *ndev);
822static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
823static void wl_link_up(struct bcm_cfg80211 *cfg);
824static void wl_link_down(struct bcm_cfg80211 *cfg);
825static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype);
826static void wl_init_conf(struct wl_conf *conf);
827static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info,
828 struct net_device* ndev);
829int wl_cfg80211_get_ioctl_version(void);
830
831/*
832 * find most significant bit set
833 */
834static __used u32 wl_find_msb(u16 bit16);
835
836/*
837 * rfkill support
838 */
839static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
840static int wl_rfkill_set(void *data, bool blocked);
841#ifdef DEBUGFS_CFG80211
842static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg);
843static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg);
844#endif
845static wl_scan_params_t *wl_cfg80211_scan_alloc_params(struct bcm_cfg80211 *cfg,
846 int channel, int nprobes, int *out_params_size);
847static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
848
849#ifdef WL_CFG80211_ACL
850/* ACL */
851static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
852 const struct cfg80211_acl_data *acl);
853#endif /* WL_CFG80211_ACL */
854
855/*
856 * Some external functions, TODO: move them to dhd_linux.h
857 */
858int dhd_add_monitor(const char *name, struct net_device **new_ndev);
859int dhd_del_monitor(struct net_device *ndev);
860int dhd_monitor_init(void *dhd_pub);
861int dhd_monitor_uninit(void);
862int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
863
864
865#ifdef P2P_LISTEN_OFFLOADING
866s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
867#endif /* P2P_LISTEN_OFFLOADING */
868
869#ifdef PKT_FILTER_SUPPORT
870extern uint dhd_pkt_filter_enable;
871extern uint dhd_master_mode;
872extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
873#endif /* PKT_FILTER_SUPPORT */
874
875#ifdef SUPPORT_SET_CAC
876static void wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable);
877#endif /* SUPPORT_SET_CAC */
878
879static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
880 const struct ether_addr *bssid);
881static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
882
883static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ,
884 WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ };
885
886#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || (defined(CONFIG_ARCH_MSM) && \
887 defined(CFG80211_DISCONNECTED_V2))
888#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
889 cfg80211_disconnected(dev, reason, ie, len, loc_gen, gfp);
890#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0))
891#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
892 cfg80211_disconnected(dev, reason, ie, len, gfp);
893#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) */
894
895#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || (defined(CONFIG_ARCH_MSM) && \
896 defined(CFG80211_DISCONNECTED_V2))
897#define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
898 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
899 IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
900#else
901#define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
902 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
903 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
904#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
905
906#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
907 (akm) == RSN_AKM_UNSPECIFIED || \
908 (akm) == RSN_AKM_PSK)
909
910
911extern int dhd_wait_pend8021x(struct net_device *dev);
912#ifdef PROP_TXSTATUS_VSDB
913extern int disable_proptx;
914#endif /* PROP_TXSTATUS_VSDB */
32c27b7a
RC
915static int wl_cfg80211_check_in4way(struct bcm_cfg80211 *cfg,
916 struct net_device *dev, uint action, enum wl_ext_status status, void *context);
010c3a89
RC
917
918
919extern int passive_channel_skip;
920
921static s32
922wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
923 const wl_event_msg_t *e, void *data);
924static s32
925wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
926 const wl_event_msg_t *e, void *data);
927#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \
928 0)))
929struct chan_info {
930 int freq;
931 int chan_type;
932};
933#endif
934
935#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
936#define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(wiphy, bss);
937#else
938#define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(bss);
939#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
940
010c3a89
RC
941#define CHAN2G(_channel, _freq, _flags) { \
942 .band = IEEE80211_BAND_2GHZ, \
943 .center_freq = (_freq), \
944 .hw_value = (_channel), \
945 .flags = (_flags), \
946 .max_antenna_gain = 0, \
947 .max_power = 30, \
948}
949
950#define CHAN5G(_channel, _flags) { \
951 .band = IEEE80211_BAND_5GHZ, \
952 .center_freq = 5000 + (5 * (_channel)), \
953 .hw_value = (_channel), \
954 .flags = (_flags), \
955 .max_antenna_gain = 0, \
956 .max_power = 30, \
957}
958
959#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
960#define RATETAB_ENT(_rateid, _flags) \
961 { \
962 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
963 .hw_value = (_rateid), \
964 .flags = (_flags), \
965 }
966
967static struct ieee80211_rate __wl_rates[] = {
968 RATETAB_ENT(DOT11_RATE_1M, 0),
969 RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
970 RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
971 RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
972 RATETAB_ENT(DOT11_RATE_6M, 0),
973 RATETAB_ENT(DOT11_RATE_9M, 0),
974 RATETAB_ENT(DOT11_RATE_12M, 0),
975 RATETAB_ENT(DOT11_RATE_18M, 0),
976 RATETAB_ENT(DOT11_RATE_24M, 0),
977 RATETAB_ENT(DOT11_RATE_36M, 0),
978 RATETAB_ENT(DOT11_RATE_48M, 0),
979 RATETAB_ENT(DOT11_RATE_54M, 0)
980};
981
982#define wl_a_rates (__wl_rates + 4)
983#define wl_a_rates_size 8
984#define wl_g_rates (__wl_rates + 0)
985#define wl_g_rates_size 12
986
987static struct ieee80211_channel __wl_2ghz_channels[] = {
988 CHAN2G(1, 2412, 0),
989 CHAN2G(2, 2417, 0),
990 CHAN2G(3, 2422, 0),
991 CHAN2G(4, 2427, 0),
992 CHAN2G(5, 2432, 0),
993 CHAN2G(6, 2437, 0),
994 CHAN2G(7, 2442, 0),
995 CHAN2G(8, 2447, 0),
996 CHAN2G(9, 2452, 0),
997 CHAN2G(10, 2457, 0),
998 CHAN2G(11, 2462, 0),
999 CHAN2G(12, 2467, 0),
1000 CHAN2G(13, 2472, 0),
1001 CHAN2G(14, 2484, 0)
1002};
1003
1004static struct ieee80211_channel __wl_5ghz_a_channels[] = {
1005 CHAN5G(34, 0), CHAN5G(36, 0),
1006 CHAN5G(38, 0), CHAN5G(40, 0),
1007 CHAN5G(42, 0), CHAN5G(44, 0),
1008 CHAN5G(46, 0), CHAN5G(48, 0),
1009 CHAN5G(52, 0), CHAN5G(56, 0),
1010 CHAN5G(60, 0), CHAN5G(64, 0),
1011 CHAN5G(100, 0), CHAN5G(104, 0),
1012 CHAN5G(108, 0), CHAN5G(112, 0),
1013 CHAN5G(116, 0), CHAN5G(120, 0),
1014 CHAN5G(124, 0), CHAN5G(128, 0),
1015 CHAN5G(132, 0), CHAN5G(136, 0),
1016 CHAN5G(140, 0), CHAN5G(144, 0),
1017 CHAN5G(149, 0), CHAN5G(153, 0),
1018 CHAN5G(157, 0), CHAN5G(161, 0),
1019 CHAN5G(165, 0)
1020};
1021
1022static struct ieee80211_supported_band __wl_band_2ghz = {
1023 .band = IEEE80211_BAND_2GHZ,
1024 .channels = __wl_2ghz_channels,
1025 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
1026 .bitrates = wl_g_rates,
1027 .n_bitrates = wl_g_rates_size
1028};
1029
1030static struct ieee80211_supported_band __wl_band_5ghz_a = {
1031 .band = IEEE80211_BAND_5GHZ,
1032 .channels = __wl_5ghz_a_channels,
1033 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
1034 .bitrates = wl_a_rates,
1035 .n_bitrates = wl_a_rates_size
1036};
1037
1038static const u32 __wl_cipher_suites[] = {
1039 WLAN_CIPHER_SUITE_WEP40,
1040 WLAN_CIPHER_SUITE_WEP104,
1041 WLAN_CIPHER_SUITE_TKIP,
1042 WLAN_CIPHER_SUITE_CCMP,
1043#ifdef MFP
1044 /*
1045 * Advertising AES_CMAC cipher suite to userspace would imply that we
1046 * are supporting MFP. So advertise only when MFP support is enabled.
1047 */
1048 WLAN_CIPHER_SUITE_AES_CMAC,
1049#endif /* MFP */
1050};
1051
1052#ifdef WL_SUPPORT_ACS
1053/*
1054 * The firmware code required for this feature to work is currently under
1055 * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1056 * required firmware code out of the BCMINTERNAL flag.
1057 */
1058struct wl_dump_survey {
1059 u32 obss;
1060 u32 ibss;
1061 u32 no_ctg;
1062 u32 no_pckt;
1063 u32 tx;
1064 u32 idle;
1065};
1066#endif /* WL_SUPPORT_ACS */
1067
1068
1069#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1070static int maxrxpktglom = 0;
1071#endif
1072
1073/* IOCtl version read from targeted driver */
1074int ioctl_version;
1075#ifdef DEBUGFS_CFG80211
1076#define S_SUBLOGLEVEL 20
1077static const struct {
1078 u32 log_level;
1079 char *sublogname;
1080} sublogname_map[] = {
1081 {WL_DBG_ERR, "ERR"},
1082 {WL_DBG_INFO, "INFO"},
1083 {WL_DBG_DBG, "DBG"},
1084 {WL_DBG_SCAN, "SCAN"},
1085 {WL_DBG_TRACE, "TRACE"},
1086 {WL_DBG_P2P_ACTION, "P2PACTION"}
1087};
1088#endif
1089
1090#ifdef CUSTOMER_HW4_DEBUG
1091uint prev_dhd_console_ms = 0;
1092u32 prev_wl_dbg_level = 0;
1093bool wl_scan_timeout_dbg_enabled = 0;
1094static void wl_scan_timeout_dbg_set(void);
1095static void wl_scan_timeout_dbg_clear(void);
1096
1097static void wl_scan_timeout_dbg_set(void)
1098{
1099 WL_ERR(("Enter \n"));
1100 prev_dhd_console_ms = dhd_console_ms;
1101 prev_wl_dbg_level = wl_dbg_level;
1102
1103 dhd_console_ms = 1;
1104 wl_dbg_level |= (WL_DBG_ERR | WL_DBG_P2P_ACTION | WL_DBG_SCAN);
1105
1106 wl_scan_timeout_dbg_enabled = 1;
1107}
1108static void wl_scan_timeout_dbg_clear(void)
1109{
1110 WL_ERR(("Enter \n"));
1111 dhd_console_ms = prev_dhd_console_ms;
1112 wl_dbg_level = prev_wl_dbg_level;
1113
1114 wl_scan_timeout_dbg_enabled = 0;
1115}
1116#endif /* CUSTOMER_HW4_DEBUG */
1117
1118/* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1119uint32 fw_assoc_watchdog_ms = 0;
1120bool fw_assoc_watchdog_started = 0;
1121#define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1122
1123static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg,
1124 enum wl_pm_workq_act_type type)
1125{
1126 u16 wq_duration = 0;
1127 dhd_pub_t *dhd = NULL;
1128
1129 if (cfg == NULL)
1130 return;
1131
1132 dhd = (dhd_pub_t *)(cfg->pub);
1133
1134 mutex_lock(&cfg->pm_sync);
1135 /*
1136 * Make cancel and schedule work part mutually exclusive
1137 * so that while cancelling, we are sure that there is no
1138 * work getting scheduled.
1139 */
1140 if (delayed_work_pending(&cfg->pm_enable_work)) {
1141 cancel_delayed_work_sync(&cfg->pm_enable_work);
1142 DHD_PM_WAKE_UNLOCK(cfg->pub);
1143 }
1144
1145 if (type == WL_PM_WORKQ_SHORT) {
1146 wq_duration = WL_PM_ENABLE_TIMEOUT;
1147 } else if (type == WL_PM_WORKQ_LONG) {
1148 wq_duration = (WL_PM_ENABLE_TIMEOUT*2);
1149 }
1150
1151 /* It should schedule work item only if driver is up */
1152 if (wq_duration && dhd->up) {
1153 if (schedule_delayed_work(&cfg->pm_enable_work,
1154 msecs_to_jiffies((const unsigned int)wq_duration))) {
1155 DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub, wq_duration);
1156 } else {
1157 WL_ERR(("Can't schedule pm work handler\n"));
1158 }
1159 }
1160 mutex_unlock(&cfg->pm_sync);
1161}
1162
1163/* Return a new chanspec given a legacy chanspec
1164 * Returns INVCHANSPEC on error
1165 */
1166chanspec_t
1167wl_chspec_from_legacy(chanspec_t legacy_chspec)
1168{
1169 chanspec_t chspec;
1170
1171 /* get the channel number */
1172 chspec = LCHSPEC_CHANNEL(legacy_chspec);
1173
1174 /* convert the band */
1175 if (LCHSPEC_IS2G(legacy_chspec)) {
1176 chspec |= WL_CHANSPEC_BAND_2G;
1177 } else {
1178 chspec |= WL_CHANSPEC_BAND_5G;
1179 }
1180
1181 /* convert the bw and sideband */
1182 if (LCHSPEC_IS20(legacy_chspec)) {
1183 chspec |= WL_CHANSPEC_BW_20;
1184 } else {
1185 chspec |= WL_CHANSPEC_BW_40;
1186 if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
1187 chspec |= WL_CHANSPEC_CTL_SB_L;
1188 } else {
1189 chspec |= WL_CHANSPEC_CTL_SB_U;
1190 }
1191 }
ccd15baf 1192
010c3a89
RC
1193 if (wf_chspec_malformed(chspec)) {
1194 WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1195 chspec));
1196 return INVCHANSPEC;
1197 }
ccd15baf 1198
010c3a89
RC
1199 return chspec;
1200}
1201
1202/* Return a legacy chanspec given a new chanspec
1203 * Returns INVCHANSPEC on error
1204 */
1205static chanspec_t
1206wl_chspec_to_legacy(chanspec_t chspec)
1207{
1208 chanspec_t lchspec;
1209
1210 if (wf_chspec_malformed(chspec)) {
1211 WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1212 chspec));
1213 return INVCHANSPEC;
1214 }
1215
1216 /* get the channel number */
1217 lchspec = CHSPEC_CHANNEL(chspec);
1218
1219 /* convert the band */
1220 if (CHSPEC_IS2G(chspec)) {
1221 lchspec |= WL_LCHANSPEC_BAND_2G;
1222 } else {
1223 lchspec |= WL_LCHANSPEC_BAND_5G;
1224 }
1225
1226 /* convert the bw and sideband */
1227 if (CHSPEC_IS20(chspec)) {
1228 lchspec |= WL_LCHANSPEC_BW_20;
1229 lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
1230 } else if (CHSPEC_IS40(chspec)) {
1231 lchspec |= WL_LCHANSPEC_BW_40;
1232 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
1233 lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
1234 } else {
1235 lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
1236 }
1237 } else {
1238 /* cannot express the bandwidth */
1239 char chanbuf[CHANSPEC_STR_LEN];
1240 WL_ERR((
1241 "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1242 "to pre-11ac format\n",
1243 wf_chspec_ntoa(chspec, chanbuf), chspec));
1244 return INVCHANSPEC;
1245 }
1246
1247 return lchspec;
1248}
1249
1250/* given a chanspec value, do the endian and chanspec version conversion to
1251 * a chanspec_t value
1252 * Returns INVCHANSPEC on error
1253 */
1254chanspec_t
1255wl_chspec_host_to_driver(chanspec_t chanspec)
1256{
1257 if (ioctl_version == 1) {
1258 chanspec = wl_chspec_to_legacy(chanspec);
1259 if (chanspec == INVCHANSPEC) {
1260 return chanspec;
1261 }
1262 }
1263 chanspec = htodchanspec(chanspec);
1264
1265 return chanspec;
1266}
1267
1268/* given a channel value, do the endian and chanspec version conversion to
1269 * a chanspec_t value
1270 * Returns INVCHANSPEC on error
1271 */
1272chanspec_t
1273wl_ch_host_to_driver(struct bcm_cfg80211 *cfg, s32 bssidx, u16 channel)
1274{
1275 chanspec_t chanspec;
1276
1277 chanspec = channel & WL_CHANSPEC_CHAN_MASK;
1278
1279 if (channel <= CH_MAX_2G_CHANNEL)
1280 chanspec |= WL_CHANSPEC_BAND_2G;
1281 else
1282 chanspec |= WL_CHANSPEC_BAND_5G;
1283
1284 chanspec |= wl_cfg80211_ulb_get_min_bw_chspec(cfg, NULL, bssidx);
1285
1286 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
1287
1288 return wl_chspec_host_to_driver(chanspec);
1289}
1290
1291/* given a chanspec value from the driver, do the endian and chanspec version conversion to
1292 * a chanspec_t value
1293 * Returns INVCHANSPEC on error
1294 */
1295chanspec_t
1296wl_chspec_driver_to_host(chanspec_t chanspec)
1297{
1298 chanspec = dtohchanspec(chanspec);
1299 if (ioctl_version == 1) {
1300 chanspec = wl_chspec_from_legacy(chanspec);
1301 }
ccd15baf 1302
010c3a89
RC
1303 return chanspec;
1304}
1305
1306/*
1307 * convert ASCII string to MAC address (colon-delimited format)
1308 * eg: 00:11:22:33:44:55
1309 */
1310int
1311wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
1312{
1313 char *c = NULL;
1314 int count = 0;
1315
1316 memset(n, 0, ETHER_ADDR_LEN);
1317 for (;;) {
1318 n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
1319 if (!*c++ || count == ETHER_ADDR_LEN)
1320 break;
1321 a = c;
1322 }
1323 return (count == ETHER_ADDR_LEN);
1324}
1325
1326/* There isn't a lot of sense in it, but you can transmit anything you like */
1327static const struct ieee80211_txrx_stypes
1328wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
dfb0f3ae
RC
1329#ifdef WLMESH
1330 [NL80211_IFTYPE_MESH_POINT] = {
1331 .tx = 0xffff,
1332 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1333 BIT(IEEE80211_STYPE_AUTH >> 4)
1334 },
1335#endif /* WLMESH */
010c3a89
RC
1336 [NL80211_IFTYPE_ADHOC] = {
1337 .tx = 0xffff,
1338 .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
1339 },
1340 [NL80211_IFTYPE_STATION] = {
1341 .tx = 0xffff,
1342 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1343 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1344 },
1345 [NL80211_IFTYPE_AP] = {
1346 .tx = 0xffff,
1347 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1348 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1349 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1350 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1351 BIT(IEEE80211_STYPE_AUTH >> 4) |
1352 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1353 BIT(IEEE80211_STYPE_ACTION >> 4)
1354 },
1355 [NL80211_IFTYPE_AP_VLAN] = {
1356 /* copy AP */
1357 .tx = 0xffff,
1358 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1359 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1360 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1361 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1362 BIT(IEEE80211_STYPE_AUTH >> 4) |
1363 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1364 BIT(IEEE80211_STYPE_ACTION >> 4)
1365 },
1366 [NL80211_IFTYPE_P2P_CLIENT] = {
1367 .tx = 0xffff,
1368 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1369 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1370 },
1371 [NL80211_IFTYPE_P2P_GO] = {
1372 .tx = 0xffff,
1373 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1374 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1375 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1376 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1377 BIT(IEEE80211_STYPE_AUTH >> 4) |
1378 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1379 BIT(IEEE80211_STYPE_ACTION >> 4)
1380 },
1381#if defined(WL_CFG80211_P2P_DEV_IF)
1382 [NL80211_IFTYPE_P2P_DEVICE] = {
1383 .tx = 0xffff,
1384 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1385 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1386 },
1387#endif /* WL_CFG80211_P2P_DEV_IF */
1388};
1389
1390static void swap_key_from_BE(struct wl_wsec_key *key)
1391{
1392 key->index = htod32(key->index);
1393 key->len = htod32(key->len);
1394 key->algo = htod32(key->algo);
1395 key->flags = htod32(key->flags);
1396 key->rxiv.hi = htod32(key->rxiv.hi);
1397 key->rxiv.lo = htod16(key->rxiv.lo);
1398 key->iv_initialized = htod32(key->iv_initialized);
1399}
1400
1401static void swap_key_to_BE(struct wl_wsec_key *key)
1402{
1403 key->index = dtoh32(key->index);
1404 key->len = dtoh32(key->len);
1405 key->algo = dtoh32(key->algo);
1406 key->flags = dtoh32(key->flags);
1407 key->rxiv.hi = dtoh32(key->rxiv.hi);
1408 key->rxiv.lo = dtoh16(key->rxiv.lo);
1409 key->iv_initialized = dtoh32(key->iv_initialized);
1410}
1411
1412/* Dump the contents of the encoded wps ie buffer and get pbc value */
1413static void
1414wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc)
1415{
1416 #define WPS_IE_FIXED_LEN 6
1417 s16 len;
1418 u8 *subel = NULL;
1419 u16 subelt_id;
1420 u16 subelt_len;
1421 u16 val;
1422 u8 *valptr = (uint8*) &val;
1423 if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
1424 WL_ERR(("invalid argument : NULL\n"));
1425 return;
1426 }
1427 len = (s16)wps_ie[TLV_LEN_OFF];
1428
1429 if (len > wps_ie_len) {
1430 WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
1431 return;
1432 }
1433 WL_DBG(("wps_ie len=%d\n", len));
1434 len -= 4; /* for the WPS IE's OUI, oui_type fields */
1435 subel = wps_ie + WPS_IE_FIXED_LEN;
1436 while (len >= 4) { /* must have attr id, attr len fields */
1437 valptr[0] = *subel++;
1438 valptr[1] = *subel++;
1439 subelt_id = HTON16(val);
1440
1441 valptr[0] = *subel++;
1442 valptr[1] = *subel++;
1443 subelt_len = HTON16(val);
1444
1445 len -= 4; /* for the attr id, attr len fields */
1446 len -= (s16)subelt_len; /* for the remaining fields in this attribute */
1447 if (len < 0) {
1448 break;
1449 }
1450 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
1451 subel, subelt_id, subelt_len));
1452
1453 if (subelt_id == WPS_ID_VERSION) {
1454 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
1455 } else if (subelt_id == WPS_ID_REQ_TYPE) {
1456 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
1457 } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
1458 valptr[0] = *subel;
1459 valptr[1] = *(subel + 1);
1460 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
1461 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
1462 char devname[100];
1463 int namelen = MIN(subelt_len, (sizeof(devname) - 1));
1464
1465 if (namelen) {
1466 memcpy(devname, subel, namelen);
1467 devname[namelen] = '\0';
1468 /* Printing len as rx'ed in the IE */
1469 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1470 devname, subelt_len));
1471 }
1472 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
1473 valptr[0] = *subel;
1474 valptr[1] = *(subel + 1);
1475 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
1476 *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
1477 } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
1478 valptr[0] = *subel;
1479 valptr[1] = *(subel + 1);
1480 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
1481 valptr[0] = *(subel + 6);
1482 valptr[1] = *(subel + 7);
1483 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
1484 } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
1485 valptr[0] = *subel;
1486 valptr[1] = *(subel + 1);
1487 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
1488 valptr[0] = *(subel + 6);
1489 valptr[1] = *(subel + 7);
1490 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
1491 } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
1492 valptr[0] = *subel;
1493 valptr[1] = *(subel + 1);
1494 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1495 ": cat=%u\n", HTON16(val)));
1496 } else {
1497 WL_DBG((" unknown attr 0x%x\n", subelt_id));
1498 }
1499
1500 subel += subelt_len;
1501 }
1502}
1503
1504s32 wl_set_tx_power(struct net_device *dev,
1505 enum nl80211_tx_power_setting type, s32 dbm)
1506{
1507 s32 err = 0;
1508 s32 disable = 0;
1509 s32 txpwrqdbm;
1510 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1511
1512 /* Make sure radio is off or on as far as software is concerned */
1513 disable = WL_RADIO_SW_DISABLE << 16;
1514 disable = htod32(disable);
1515 err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable));
1516 if (unlikely(err)) {
1517 WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
1518 return err;
1519 }
1520
1521 if (dbm > 0xffff)
1522 dbm = 0xffff;
1523 txpwrqdbm = dbm * 4;
1524 err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
1525 sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
1526 &cfg->ioctl_buf_sync);
1527 if (unlikely(err))
1528 WL_ERR(("qtxpower error (%d)\n", err));
1529 else
1530 WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
1531
1532 return err;
1533}
1534
1535s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
1536{
1537 s32 err = 0;
1538 s32 txpwrdbm;
1539 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1540
1541 err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
1542 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
1543 if (unlikely(err)) {
1544 WL_ERR(("error (%d)\n", err));
1545 return err;
1546 }
1547
1548 memcpy(&txpwrdbm, cfg->ioctl_buf, sizeof(txpwrdbm));
1549 txpwrdbm = dtoh32(txpwrdbm);
1550 *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
1551
1552 WL_INFORM(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
1553
1554 return err;
1555}
1556
1557static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
1558{
1559 chanspec_t chspec;
1560 int cur_band, err = 0;
1561 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1562 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
1563 struct ether_addr bssid;
1564 struct wl_bss_info *bss = NULL;
1565 s32 bssidx = 0; /* Explicitly set to primary bssidx */
1566 char *buf;
1567
1568 memset(&bssid, 0, sizeof(bssid));
1569 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) {
1570 /* STA interface is not associated. So start the new interface on a temp
1571 * channel . Later proper channel will be applied by the above framework
1572 * via set_channel (cfg80211 API).
1573 */
1574 WL_DBG(("Not associated. Return a temp channel. \n"));
1575 cur_band = 0;
1576 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(int));
1577 if (unlikely(err)) {
1578 WL_ERR(("Get band failed\n"));
1579 return wl_ch_host_to_driver(cfg, bssidx, WL_P2P_TEMP_CHAN);
1580 }
1581 if (cur_band == WLC_BAND_5G)
1582 return wl_ch_host_to_driver(cfg, bssidx, WL_P2P_TEMP_CHAN_5G);
1583 else
1584 return wl_ch_host_to_driver(cfg, bssidx, WL_P2P_TEMP_CHAN);
1585 }
1586
1587 buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
1588 if (!buf) {
1589 WL_ERR(("buf alloc failed. use temp channel\n"));
1590 return wl_ch_host_to_driver(cfg, bssidx, WL_P2P_TEMP_CHAN);
1591 }
1592
1593 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1594 if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf,
1595 WL_EXTRA_BUF_MAX))) {
1596 WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1597 chspec = wl_ch_host_to_driver(cfg, bssidx, WL_P2P_TEMP_CHAN);
1598 }
1599 else {
1600 bss = (struct wl_bss_info *) (buf + 4);
1601 chspec = bss->chanspec;
1602
1603 WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
1604 }
1605
1606 kfree(buf);
1607 return chspec;
1608}
1609
1610static bcm_struct_cfgdev *
1611wl_cfg80211_add_monitor_if(const char *name)
1612{
1613#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
1614 WL_INFORM(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
1615 return ERR_PTR(-EOPNOTSUPP);
1616#else
1617 struct net_device* ndev = NULL;
1618
1619 dhd_add_monitor(name, &ndev);
1620 WL_INFORM(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
1621 return ndev_to_cfgdev(ndev);
1622#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */
1623}
1624
1625static bcm_struct_cfgdev *
1626wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
1627#if defined(WL_CFG80211_P2P_DEV_IF)
1628 const char *name,
1629#else
1630 char *name,
1631#endif /* WL_CFG80211_P2P_DEV_IF */
1632#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
1633 unsigned char name_assign_type,
1634#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
dfb0f3ae
RC
1635 enum nl80211_iftype type,
1636#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
1637 u32 *flags,
1638#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) */
010c3a89
RC
1639 struct vif_params *params)
1640{
1641 s32 err = -ENODEV;
1642 s32 timeout = -1;
1643 s32 wlif_type = -1;
1644 s32 mode = 0;
1645 s32 val = 0;
1646 s32 cfg_type;
1647 s32 dhd_mode = 0;
1648 chanspec_t chspec;
1649 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1650 struct net_device *primary_ndev;
1651 struct net_device *new_ndev;
1652 struct ether_addr primary_mac;
1653 bcm_struct_cfgdev *new_cfgdev;
1654#ifdef PROP_TXSTATUS_VSDB
dfb0f3ae 1655#if defined(BCMSDIO) || defined(BCMDBUS)
010c3a89
RC
1656 s32 up = 1;
1657 bool enabled;
dfb0f3ae 1658#endif /* BCMSDIO || BCMDBUS */
010c3a89
RC
1659#endif /* PROP_TXSTATUS_VSDB */
1660 dhd_pub_t *dhd;
1661 bool hang_required = false;
1662
1663 if (!cfg)
1664 return ERR_PTR(-EINVAL);
1665
1666 dhd = (dhd_pub_t *)(cfg->pub);
1667
1668 /* Use primary I/F for sending cmds down to firmware */
1669 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1670
1671 if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
1672 WL_ERR(("device is not ready\n"));
1673 return ERR_PTR(-ENODEV);
1674 }
1675
1676 if (!name) {
1677 WL_ERR(("Interface name not provided \n"));
1678 return ERR_PTR(-EINVAL);
1679 }
1680
1681#ifdef WLTDLS
1682 /* disable TDLS if number of connected interfaces is >= 1 */
1683 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_CREATE, false);
1684#endif /* WLTDLS */
1685
1686 mutex_lock(&cfg->if_sync);
1687 WL_DBG(("if name: %s, type: %d\n", name, type));
1688 switch (type) {
1689 case NL80211_IFTYPE_ADHOC:
1690#ifdef WLAIBSS_MCHAN
1691 new_cfgdev = bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
1692 mutex_unlock(&cfg->if_sync);
1693 return new_cfgdev;
1694#endif /* WLAIBSS_MCHAN */
1695 case NL80211_IFTYPE_AP_VLAN:
1696 case NL80211_IFTYPE_WDS:
1697 case NL80211_IFTYPE_MESH_POINT:
1698 WL_ERR(("Unsupported interface type\n"));
1699 mode = WL_MODE_IBSS;
1700 err = -EINVAL;
1701 goto fail;
1702 case NL80211_IFTYPE_MONITOR:
1703 new_cfgdev = wl_cfg80211_add_monitor_if(name);
1704 mutex_unlock(&cfg->if_sync);
1705 return new_cfgdev;
1706#if defined(WL_CFG80211_P2P_DEV_IF)
1707 case NL80211_IFTYPE_P2P_DEVICE:
1708 cfg->down_disc_if = FALSE;
1709 new_cfgdev = wl_cfgp2p_add_p2p_disc_if(cfg);
1710 mutex_unlock(&cfg->if_sync);
1711 return new_cfgdev;
1712#endif /* WL_CFG80211_P2P_DEV_IF */
1713 case NL80211_IFTYPE_STATION:
1714#ifdef WL_VIRTUAL_APSTA
1715#ifdef WLAIBSS_MCHAN
1716 if (cfg->ibss_cfgdev) {
1717 WL_ERR(("AIBSS is already operational. "
1718 " AIBSS & DUALSTA can't be used together \n"));
1719 err = -ENOMEM;
1720 goto fail;
1721 }
1722#endif /* WLAIBSS_MCHAN */
1723
1724 if (wl_cfgp2p_vif_created(cfg)) {
1725 WL_ERR(("Could not create new iface."
1726 "Already one p2p interface is running"));
1727 err = -ENOMEM;
1728 goto fail;
1729 }
1730 new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
1731 NL80211_IFTYPE_STATION, NULL, name);
1732 if (!new_cfgdev) {
1733 err = -ENOMEM;
1734 goto fail;
1735 } else {
1736 mutex_unlock(&cfg->if_sync);
1737 return new_cfgdev;
1738 }
1739#endif /* WL_VIRTUAL_APSTA */
1740 case NL80211_IFTYPE_P2P_CLIENT:
1741 wlif_type = WL_P2P_IF_CLIENT;
1742 mode = WL_MODE_BSS;
1743 break;
1744 case NL80211_IFTYPE_P2P_GO:
1745 wlif_type = WL_P2P_IF_GO;
1746 mode = WL_MODE_AP;
1747 break;
1748#ifdef WL_VIRTUAL_APSTA
1749 case NL80211_IFTYPE_AP:
1750 dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
1751 new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
1752 NL80211_IFTYPE_AP, NULL, name);
1753 if (!new_cfgdev) {
1754 err = -ENOMEM;
1755 goto fail;
1756 } else {
1757 mutex_unlock(&cfg->if_sync);
1758 return new_cfgdev;
1759 }
1760#endif /* WL_VIRTUAL_APSTA */
1761 default:
1762 WL_ERR(("Unsupported interface type\n"));
1763 err = -EINVAL;
1764 goto fail;
1765 }
1766
1767 if (cfg->p2p_supported && (wlif_type != -1)) {
1768 ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */
1769
1770#ifdef PROP_TXSTATUS_VSDB
1771#if defined(BCMSDIO)
1772 if (!dhd) {
1773 err = -EINVAL;
1774 goto fail;
1775 }
1776#endif
1777#endif /* PROP_TXSTATUS_VSDB */
1778
1779 if (!cfg->p2p) {
1780 WL_ERR(("Failed to start p2p"));
1781 err = -ENODEV;
1782 goto fail;
1783 }
1784
1785 if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
1786 p2p_on(cfg) = true;
1787 wl_cfgp2p_set_firm_p2p(cfg);
1788 wl_cfgp2p_init_discovery(cfg);
1789 get_primary_mac(cfg, &primary_mac);
1790 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
1791 }
1792
1793 strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1);
1794 cfg->p2p->vir_ifname[IFNAMSIZ - 1] = '\0';
1795
1796 wl_cfg80211_scan_abort(cfg);
1797#ifdef PROP_TXSTATUS_VSDB
dfb0f3ae 1798#if defined(BCMSDIO) || defined(BCMDBUS)
010c3a89
RC
1799 if (!cfg->wlfc_on && !disable_proptx) {
1800 dhd_wlfc_get_enable(dhd, &enabled);
1801 if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1802 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1803 dhd_wlfc_init(dhd);
1804 err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32));
1805 if (err < 0)
1806 WL_ERR(("WLC_UP return err:%d\n", err));
1807 }
1808 cfg->wlfc_on = true;
1809 }
dfb0f3ae 1810#endif /* BCMSDIO || BCMDBUS */
010c3a89
RC
1811#endif /* PROP_TXSTATUS_VSDB */
1812
1813 /* Dual p2p doesn't support multiple P2PGO interfaces,
1814 * p2p_go_count is the counter for GO creation
1815 * requests.
1816 */
1817 if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
d964ce36 1818 WL_ERR(("Fw does not support multiple Go\n"));
010c3a89
RC
1819 err = -ENOTSUPP;
1820 goto fail;
1821 }
1822 /* In concurrency case, STA may be already associated in a particular channel.
1823 * so retrieve the current channel of primary interface and then start the virtual
1824 * interface on that.
1825 */
1826 chspec = wl_cfg80211_get_shared_freq(wiphy);
1827
1828 /* For P2P mode, use P2P-specific driver features to create the
1829 * bss: "cfg p2p_ifadd"
1830 */
1831 wl_set_p2p_status(cfg, IF_ADDING);
1832 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
1833 cfg_type = wl_cfgp2p_get_conn_idx(cfg);
1834 if (cfg_type == BCME_ERROR) {
1835 wl_clr_p2p_status(cfg, IF_ADDING);
d964ce36 1836 WL_ERR(("Failed to get connection idx for p2p interface\n"));
010c3a89
RC
1837 err = -ENOTSUPP;
1838 goto fail;
1839 }
1840 err = wl_cfgp2p_ifadd(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type),
1841 htod32(wlif_type), chspec);
1842 if (unlikely(err)) {
1843 wl_clr_p2p_status(cfg, IF_ADDING);
1844 WL_ERR((" virtual iface add failed (%d) \n", err));
1845 err = -ENOMEM;
1846 goto fail;
1847 }
1848
1849 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1850 ((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
1851 (cfg->if_event_info.valid)),
1852 msecs_to_jiffies(MAX_WAIT_TIME));
1853
1854 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
1855 struct wireless_dev *vwdev;
1856 int pm_mode = PM_ENABLE;
1857 wl_if_event_info *event = &cfg->if_event_info;
1858 /* IF_ADD event has come back, we can proceed to to register
1859 * the new interface now, use the interface name provided by caller (thus
1860 * ignore the one from wlc)
1861 */
1862 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname,
1863 event->mac, event->bssidx, event->name);
1864 if (new_ndev == NULL) {
1865 err = -ENODEV;
1866 goto fail;
1867 }
1868
1869 wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
1870 wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
1871 vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
1872 if (unlikely(!vwdev)) {
1873 WL_ERR(("Could not allocate wireless device\n"));
1874 err = -ENOMEM;
1875 goto fail;
1876 }
1877 vwdev->wiphy = cfg->wdev->wiphy;
1878 WL_INFORM(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname));
1879 if (type == NL80211_IFTYPE_P2P_GO) {
1880 cfg->p2p->p2p_go_count++;
1881 }
1882 vwdev->iftype = type;
1883 vwdev->netdev = new_ndev;
1884 new_ndev->ieee80211_ptr = vwdev;
1885 SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy));
1886 wl_set_drv_status(cfg, READY, new_ndev);
1887 if (wl_config_ifmode(cfg, new_ndev, type) < 0) {
1888 WL_ERR(("conf ifmode failed\n"));
1889 kfree(vwdev);
1890 err = -ENOTSUPP;
1891 goto fail;
1892 }
1893
1894 if (wl_cfg80211_register_if(cfg,
1895 event->ifidx, new_ndev, FALSE) != BCME_OK) {
1896 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
1897 err = -ENODEV;
1898 goto fail;
1899 }
1900 err = wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode, event->bssidx);
1901 if (unlikely(err != 0)) {
1902 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
1903 WL_ERR(("Allocation of netinfo failed (%d) \n", err));
1904 goto fail;
1905 }
1906 val = 1;
1907 /* Disable firmware roaming for P2P interface */
1908 wldev_iovar_setint(new_ndev, "roam_off", val);
1909 wldev_iovar_setint(new_ndev, "bcn_timeout", dhd->conf->bcn_timeout);
1910#ifdef WL11ULB
1911 if (cfg->p2p_wdev && is_p2p_group_iface(new_ndev->ieee80211_ptr)) {
1912 u32 ulb_bw = wl_cfg80211_get_ulb_bw(cfg, cfg->p2p_wdev);
1913 if (ulb_bw) {
1914 /* Apply ULB BW settings on the newly spawned interface */
1915 WL_DBG(("[ULB] Applying ULB BW for the newly"
1916 "created P2P interface \n"));
1917 if (wl_cfg80211_set_ulb_bw(new_ndev,
1918 ulb_bw, new_ndev->name) < 0) {
1919 /*
1920 * If ulb_bw set failed, fail the iface creation.
1921 * wl_dealloc_netinfo_by_wdev will be called by the
1922 * unregister notifier.
1923 */
1924 wl_cfg80211_remove_if(cfg,
1925 event->ifidx, new_ndev, FALSE);
1926 err = -EINVAL;
1927 goto fail;
1928 }
1929 }
1930 }
1931#endif /* WL11ULB */
1932
1933 if (mode != WL_MODE_AP)
1934 wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1);
1935
1936 WL_ERR((" virtual interface(%s) is "
1937 "created net attach done\n", cfg->p2p->vir_ifname));
1938 if (mode == WL_MODE_AP)
1939 wl_set_drv_status(cfg, CONNECTED, new_ndev);
1940#ifdef SUPPORT_AP_POWERSAVE
1941 if (mode == WL_MODE_AP) {
1942 dhd_set_ap_powersave(dhd, 0, TRUE);
1943 }
1944#endif /* SUPPORT_AP_POWERSAVE */
1945 if (type == NL80211_IFTYPE_P2P_CLIENT)
1946 dhd_mode = DHD_FLAG_P2P_GC_MODE;
1947 else if (type == NL80211_IFTYPE_P2P_GO)
1948 dhd_mode = DHD_FLAG_P2P_GO_MODE;
1949 DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
1950 /* reinitialize completion to clear previous count */
1951#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1952 INIT_COMPLETION(cfg->iface_disable);
1953#else
1954 init_completion(&cfg->iface_disable);
1955#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
1956#ifdef SUPPORT_SET_CAC
1957 wl_cfg80211_set_cac(cfg, 0);
1958#endif /* SUPPORT_SET_CAC */
1959 mutex_unlock(&cfg->if_sync);
1960 return ndev_to_cfgdev(new_ndev);
1961 } else {
1962 wl_clr_p2p_status(cfg, IF_ADDING);
1963 WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname));
1964
1965 WL_ERR(("left timeout : %d\n", timeout));
1966 WL_ERR(("IF_ADDING status : %d\n", wl_get_p2p_status(cfg, IF_ADDING)));
1967 WL_ERR(("event valid : %d\n", cfg->if_event_info.valid));
1968
1969 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
1970 wl_set_p2p_status(cfg, IF_DELETING);
1971
1972 hang_required = true;
1973 if ((err = wl_cfgp2p_ifdel(cfg,
1974 wl_to_p2p_bss_macaddr(cfg,
1975 cfg_type))) == BCME_OK) {
1976 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1977 ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
1978 (cfg->if_event_info.valid)),
1979 msecs_to_jiffies(MAX_WAIT_TIME));
1980 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
1981 cfg->if_event_info.valid) {
1982 hang_required = false;
1983 WL_ERR(("IFDEL operation done\n"));
1984 } else {
1985 WL_ERR(("IFDEL didn't complete properly\n"));
1986 }
1987 err = -ENODEV;
1988#ifdef SUPPORT_SET_CAC
1989 wl_cfg80211_set_cac(cfg, 1);
1990#endif /* SUPPORT_SET_CAC */
1991 } else {
1992 WL_ERR(("IFDEL operation failed, error code = %d\n", err));
1993 }
1994
1995 memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
1996 wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
1997#ifdef PROP_TXSTATUS_VSDB
dfb0f3ae 1998#if defined(BCMSDIO) || defined(BCMDBUS)
010c3a89
RC
1999 dhd_wlfc_get_enable(dhd, &enabled);
2000 if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
2001 dhd->op_mode != DHD_FLAG_IBSS_MODE && dhd->conf->disable_proptx!=0) {
2002 dhd_wlfc_deinit(dhd);
2003 cfg->wlfc_on = false;
2004 }
dfb0f3ae 2005#endif /* BCMSDIO || BCMDBUS */
010c3a89
RC
2006#endif /* PROP_TXSTATUS_VSDB */
2007 }
2008 }
2009
2010fail:
2011 mutex_unlock(&cfg->if_sync);
2012 if (err) {
2013#ifdef WLTDLS
2014 /* Enable back TDLS on failure */
2015 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2016#endif /* WLTDLS */
2017 if (err != -ENOTSUPP) {
2018#if defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
2019 if (dhd->memdump_enabled) {
2020 /* Load the dongle side dump to host
2021 * memory and then BUG_ON()
2022 */
2023 dhd->memdump_type = DUMP_TYPE_HANG_ON_IFACE_OP_FAIL;
2024 dhd_bus_mem_dump(dhd);
2025 }
2026#endif /* BCMPCIE && DHD_FW_COREDUMP */
2027 if (hang_required) {
2028 /* Notify the user space to recover */
2029 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2030 WL_ERR(("if add failed, error %d, sent HANG event to %s\n",
2031 err, ndev->name));
2032 dhd->hang_reason = HANG_REASON_IFACE_OP_FAILURE;
2033 net_os_send_hang_message(ndev);
2034 }
2035 }
2036 }
2037 return ERR_PTR(err);
2038}
2039
2040static s32
2041wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
2042{
2043 struct net_device *dev = NULL;
2044 struct ether_addr p2p_mac;
2045 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2046 s32 timeout = -1;
2047 s32 ret = 0;
2048 s32 index = -1;
2049 s32 type = -1;
2050#if defined(CUSTOM_SET_CPUCORE) || defined(DHD_HANG_SEND_UP_TEST)
2051 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2052#endif /* CUSTOM_SET_CPUCORE || DHD_HANG_SEND_UP_TEST */
2053 WL_DBG(("Enter\n"));
2054
2055 memset(&p2p_mac, 0, sizeof(struct ether_addr));
2056#ifdef CUSTOM_SET_CPUCORE
2057 dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
2058 if (!(dhd->chan_isvht80))
2059 dhd_set_cpucore(dhd, FALSE);
2060#endif /* CUSTOM_SET_CPUCORE */
2061 mutex_lock(&cfg->if_sync);
2062#ifdef WL_CFG80211_P2P_DEV_IF
2063 if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2064 if (dhd_download_fw_on_driverload) {
2065 ret = wl_cfgp2p_del_p2p_disc_if(cfgdev, cfg);
2066 } else {
2067 cfg->down_disc_if = TRUE;
2068 ret = 0;
2069 }
2070 mutex_unlock(&cfg->if_sync);
2071 return ret;
2072 }
2073#endif /* WL_CFG80211_P2P_DEV_IF */
2074 dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
2075
2076#ifdef WLAIBSS_MCHAN
2077 if (cfgdev == cfg->ibss_cfgdev) {
2078 ret = bcm_cfg80211_del_ibss_if(wiphy, cfgdev);
2079 goto done;
2080 }
2081#endif /* WLAIBSS_MCHAN */
2082
2083 if ((index = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
2084 WL_ERR(("Find p2p index from wdev failed\n"));
2085 ret = -ENODEV;
2086 goto done;
2087 }
2088 if ((cfg->p2p_supported) && index && (wl_cfgp2p_find_type(cfg, index, &type) == BCME_OK)) {
2089 /* Handle P2P Interace del */
2090 memcpy(p2p_mac.octet, wl_to_p2p_bss_macaddr(cfg, type).octet, ETHER_ADDR_LEN);
2091
2092 /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases
2093 */
2094 WL_DBG(("P2P: GO_NEG_PHASE status cleared "));
2095 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2096 if (wl_cfgp2p_vif_created(cfg)) {
2097 if (wl_get_drv_status(cfg, SCANNING, dev)) {
2098 wl_notify_escan_complete(cfg, dev, true, true);
2099 }
2100 /* Delete pm_enable_work */
2101 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
2102
2103 /* for GC */
2104 if (wl_get_drv_status(cfg, DISCONNECTING, dev) &&
2105 (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)) {
2106 WL_ERR(("Wait for Link Down event for GC !\n"));
2107 wait_for_completion_timeout
2108 (&cfg->iface_disable, msecs_to_jiffies(500));
2109 }
2110
2111 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
2112 wl_set_p2p_status(cfg, IF_DELETING);
2113 DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
2114
2115 /* for GO */
2116 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
2117 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
2118 cfg->p2p->p2p_go_count--;
2119 /* disable interface before bsscfg free */
2120 ret = wl_cfgp2p_ifdisable(cfg, &p2p_mac);
2121 /* if fw doesn't support "ifdis",
2122 do not wait for link down of ap mode
2123 */
2124 if (ret == 0) {
2125 WL_ERR(("Wait for Link Down event for GO !!!\n"));
2126 wait_for_completion_timeout(&cfg->iface_disable,
2127 msecs_to_jiffies(500));
2128 } else if (ret != BCME_UNSUPPORTED) {
2129 msleep(300);
2130 }
2131 }
2132 wl_cfg80211_clear_per_bss_ies(cfg, index);
2133
2134 if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)
2135 wldev_iovar_setint(dev, "buf_key_b4_m4", 0);
2136 memcpy(p2p_mac.octet, wl_to_p2p_bss_macaddr(cfg, type).octet,
2137 ETHER_ADDR_LEN);
2138 CFGP2P_INFO(("primary idx %d : cfg p2p_ifdis "MACDBG"\n",
2139 dev->ifindex, MAC2STRDBG(p2p_mac.octet)));
2140
2141 /* delete interface after link down */
2142 ret = wl_cfgp2p_ifdel(cfg, &p2p_mac);
2143#if defined(DHD_HANG_SEND_UP_TEST)
2144 if (ret != BCME_OK ||
2145 dhd->req_hang_type == HANG_REASON_IFACE_OP_FAILURE)
2146#else /* DHD_HANG_SEND_UP_TEST */
2147 if (ret != BCME_OK)
2148#endif /* DHD_HANG_SEND_UP_TEST */
2149 {
2150 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2151 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2152
2153 WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n",
2154 ret, ndev->name));
2155#if defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
2156 if (dhd->memdump_enabled) {
2157 /* Load the dongle side dump to host
2158 * memory and then BUG_ON()
2159 */
2160 dhd->memdump_type = DUMP_TYPE_HANG_ON_IFACE_OP_FAIL;
2161 dhd_bus_mem_dump(dhd);
2162 }
2163#endif /* BCMPCIE && DHD_FW_COREDUMP */
2164 dhd->hang_reason = HANG_REASON_IFACE_OP_FAILURE;
2165 net_os_send_hang_message(ndev);
2166 } else {
2167 /* Wait for IF_DEL operation to be finished */
2168 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2169 ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
2170 (cfg->if_event_info.valid)),
2171 msecs_to_jiffies(MAX_WAIT_TIME));
2172 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
2173 cfg->if_event_info.valid) {
2174
2175 WL_DBG(("IFDEL operation done\n"));
2176 wl_cfg80211_handle_ifdel(cfg, &cfg->if_event_info, dev);
2177 } else {
2178 WL_ERR(("IFDEL didn't complete properly\n"));
2179 }
2180#ifdef SUPPORT_SET_CAC
2181 wl_cfg80211_set_cac(cfg, 1);
2182#endif /* SUPPORT_SET_CAC */
2183 }
2184
2185 ret = dhd_del_monitor(dev);
2186 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
2187 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL((dhd_pub_t *)(cfg->pub));
2188 }
2189 }
2190 } else if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) ||
2191 (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) {
2192#ifdef WL_VIRTUAL_APSTA
2193 ret = wl_cfg80211_del_iface(wiphy, cfgdev);
2194#else
2195 WL_ERR(("Virtual APSTA not supported!\n"));
2196#endif /* WL_VIRTUAL_APSTA */
2197 }
2198
2199done:
2200 mutex_unlock(&cfg->if_sync);
2201#ifdef WLTDLS
2202 if (ret == BCME_OK) {
2203 /* If interface del is success, try enabling back TDLS */
2204 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2205 }
2206#endif /* WLTDLS */
2207 return ret;
2208}
2209
2210static s32
2211wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
dfb0f3ae
RC
2212 enum nl80211_iftype type,
2213#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
2214 u32 *flags,
2215#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) */
010c3a89
RC
2216 struct vif_params *params)
2217{
2218 s32 ap = 0;
2219 s32 infra_ibss = 1;
2220 s32 wlif_type;
2221 s32 mode = 0;
2222 s32 err = BCME_OK;
2223 s32 index;
2224 s32 conn_idx = -1;
2225 chanspec_t chspec;
2226 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2227 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2228
2229 mutex_lock(&cfg->if_sync);
2230 WL_DBG(("Enter type %d\n", type));
2231 switch (type) {
2232 case NL80211_IFTYPE_MONITOR:
2233 case NL80211_IFTYPE_WDS:
dfb0f3ae 2234#ifndef WLMESH
010c3a89 2235 case NL80211_IFTYPE_MESH_POINT:
dfb0f3ae 2236#endif /* WLMESH */
010c3a89
RC
2237 ap = 1;
2238 WL_ERR(("type (%d) : currently we do not support this type\n",
2239 type));
2240 break;
dfb0f3ae
RC
2241#ifdef WLMESH
2242 case NL80211_IFTYPE_MESH_POINT:
2243 infra_ibss = WL_BSSTYPE_MESH;
2244 break;
2245#endif /* WLMESH */
010c3a89
RC
2246 case NL80211_IFTYPE_ADHOC:
2247 mode = WL_MODE_IBSS;
2248 infra_ibss = 0;
2249 break;
2250 case NL80211_IFTYPE_STATION:
2251 case NL80211_IFTYPE_P2P_CLIENT:
2252 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
2253 s32 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
2254 if (bssidx < 0) {
2255 /* validate bssidx */
2256 WL_ERR(("Wrong bssidx! \n"));
2257 err = -EINVAL;
2258 goto error;
2259 }
2260 WL_DBG(("del interface. bssidx:%d", bssidx));
2261 /* Downgrade role from AP to STA */
2262 if ((err = wl_cfg80211_add_del_bss(cfg, ndev,
2263 bssidx, NL80211_IFTYPE_STATION, 0, NULL)) < 0) {
2264 WL_ERR(("AP-STA Downgrade failed \n"));
2265 err = -EINVAL;
2266 goto error;
2267 }
2268 }
2269 mode = WL_MODE_BSS;
2270 break;
2271 case NL80211_IFTYPE_AP:
2272 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
2273 /* intentional fall through */
2274 case NL80211_IFTYPE_AP_VLAN:
2275 case NL80211_IFTYPE_P2P_GO:
2276 mode = WL_MODE_AP;
2277 ap = 1;
2278 break;
2279 default:
2280 err = -EINVAL;
2281 goto error;
2282 }
2283
2284 if (!dhd) {
2285 err = -EINVAL;
2286 goto error;
2287 }
2288 if (ap) {
2289 wl_set_mode_by_netdev(cfg, ndev, mode);
2290 if (is_p2p_group_iface(ndev->ieee80211_ptr) &&
2291 cfg->p2p && wl_cfgp2p_vif_created(cfg)) {
2292 WL_DBG(("p2p_vif_created p2p_on (%d)\n", p2p_on(cfg)));
2293 wl_notify_escan_complete(cfg, ndev, true, true);
2294
2295 /* Dual p2p doesn't support multiple P2PGO interfaces,
2296 * p2p_go_count is the counter for GO creation
2297 * requests.
2298 */
2299 if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
2300 wl_set_mode_by_netdev(cfg, ndev, WL_MODE_BSS);
d964ce36 2301 WL_ERR(("Fw does not support multiple GO\n"));
010c3a89
RC
2302 err = BCME_ERROR;
2303 goto error;
2304 }
2305 /* In concurrency case, STA may be already associated in a particular
2306 * channel. so retrieve the current channel of primary interface and
2307 * then start the virtual interface on that.
2308 */
2309 chspec = wl_cfg80211_get_shared_freq(wiphy);
2310 index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
2311 if (index < 0) {
2312 WL_ERR(("Find p2p index from ndev(%p) failed\n", ndev));
2313 err = BCME_ERROR;
2314 goto error;
2315 }
2316 if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK) {
2317 err = BCME_ERROR;
2318 goto error;
2319 }
2320
2321 wlif_type = WL_P2P_IF_GO;
2322 printf("%s: %s ap (%d), infra_ibss (%d), iftype (%d) conn_idx (%d)\n",
2323 __FUNCTION__, ndev->name, ap, infra_ibss, type, conn_idx);
2324 wl_set_p2p_status(cfg, IF_CHANGING);
2325 wl_clr_p2p_status(cfg, IF_CHANGED);
2326 wl_cfgp2p_ifchange(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx),
2327 htod32(wlif_type), chspec, conn_idx);
2328 wait_event_interruptible_timeout(cfg->netif_change_event,
2329 (wl_get_p2p_status(cfg, IF_CHANGED) == true),
2330 msecs_to_jiffies(MAX_WAIT_TIME));
2331 wl_set_mode_by_netdev(cfg, ndev, mode);
2332 dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
2333 dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
2334 wl_clr_p2p_status(cfg, IF_CHANGING);
2335 wl_clr_p2p_status(cfg, IF_CHANGED);
2336 if (mode == WL_MODE_AP)
2337 wl_set_drv_status(cfg, CONNECTED, ndev);
2338#ifdef SUPPORT_AP_POWERSAVE
2339 dhd_set_ap_powersave(dhd, 0, TRUE);
2340#endif /* SUPPORT_AP_POWERSAVE */
2341 } else if ((type == NL80211_IFTYPE_AP) &&
2342 !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
2343#if 0
2344 err = wl_cfg80211_set_ap_role(cfg, ndev);
2345 if (unlikely(err)) {
2346 WL_ERR(("set ap role failed!\n"));
2347 goto error;
2348 }
2349#else
2350 wl_set_drv_status(cfg, AP_CREATING, ndev);
2351#endif
2352 } else {
2353 WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
2354 err = -EINVAL;
2355 goto error;
2356 }
2357 } else {
2358 /* P2P GO interface deletion is handled on the basis of role type (AP).
2359 * So avoid changing role for p2p type.
2360 */
2361 if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2362 wl_set_mode_by_netdev(cfg, ndev, mode);
2363 WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA\n"));
2364#ifdef SUPPORT_AP_POWERSAVE
2365 dhd_set_ap_powersave(dhd, 0, FALSE);
2366#endif /* SUPPORT_AP_POWERSAVE */
2367 }
2368
2369 if (!infra_ibss) {
2370 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra_ibss, sizeof(s32));
2371 if (err < 0) {
2372 WL_ERR(("SET INFRA/IBSS error %d\n", err));
2373 err = -EINVAL;
2374 goto error;
2375 }
2376 }
2377
2378 WL_DBG(("Setting iftype to %d \n", type));
2379 ndev->ieee80211_ptr->iftype = type;
2380error:
2381 mutex_unlock(&cfg->if_sync);
2382 return err;
2383}
2384
2385s32
2386wl_cfg80211_notify_ifadd(struct net_device *dev, int ifidx, char *name, uint8 *mac, uint8 bssidx)
2387{
2388 bool ifadd_expected = FALSE;
2389 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2390
2391 /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
2392 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
2393 */
2394 if (wl_get_p2p_status(cfg, IF_CHANGING))
2395 return wl_cfg80211_notify_ifchange(dev, ifidx, name, mac, bssidx);
2396
2397 /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
2398 if (wl_get_p2p_status(cfg, IF_ADDING)) {
2399 ifadd_expected = TRUE;
2400 wl_clr_p2p_status(cfg, IF_ADDING);
2401 } else if (cfg->bss_pending_op) {
2402 ifadd_expected = TRUE;
2403 cfg->bss_pending_op = FALSE;
2404 }
2405
2406 if (ifadd_expected) {
2407 wl_if_event_info *if_event_info = &cfg->if_event_info;
2408
2409 if_event_info->valid = TRUE;
2410 if_event_info->ifidx = ifidx;
2411 if_event_info->bssidx = bssidx;
2412 strncpy(if_event_info->name, name, IFNAMSIZ);
2413 if_event_info->name[IFNAMSIZ] = '\0';
2414 if (mac)
2415 memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
2416 wake_up_interruptible(&cfg->netif_change_event);
2417 return BCME_OK;
2418 }
2419
2420 return BCME_ERROR;
2421}
2422
2423s32
2424wl_cfg80211_notify_ifdel(struct net_device *dev, int ifidx, char *name, uint8 *mac, uint8 bssidx)
2425{
2426 bool ifdel_expected = FALSE;
2427 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2428 wl_if_event_info *if_event_info = &cfg->if_event_info;
2429
2430 if (wl_get_p2p_status(cfg, IF_DELETING)) {
2431 ifdel_expected = TRUE;
2432 wl_clr_p2p_status(cfg, IF_DELETING);
2433 } else if (cfg->bss_pending_op) {
2434 ifdel_expected = TRUE;
2435 cfg->bss_pending_op = FALSE;
2436 }
2437
2438 if (ifdel_expected) {
2439 if_event_info->valid = TRUE;
2440 if_event_info->ifidx = ifidx;
2441 if_event_info->bssidx = bssidx;
2442 wake_up_interruptible(&cfg->netif_change_event);
2443 return BCME_OK;
2444 }
2445
2446 return BCME_ERROR;
2447}
2448
2449s32
2450wl_cfg80211_notify_ifchange(struct net_device * dev, int ifidx, char *name, uint8 *mac,
2451 uint8 bssidx)
2452{
2453 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2454
2455 if (wl_get_p2p_status(cfg, IF_CHANGING)) {
2456 wl_set_p2p_status(cfg, IF_CHANGED);
2457 wake_up_interruptible(&cfg->netif_change_event);
2458 return BCME_OK;
2459 }
2460
2461 return BCME_ERROR;
2462}
2463
2464static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info,
2465 struct net_device* ndev)
2466{
2467 s32 type = -1;
2468 s32 bssidx = -1;
2469#ifdef PROP_TXSTATUS_VSDB
dfb0f3ae 2470#if defined(BCMSDIO) || defined(BCMDBUS)
010c3a89
RC
2471 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2472 bool enabled;
dfb0f3ae 2473#endif /* BCMSDIO || BCMDBUS */
010c3a89
RC
2474#endif /* PROP_TXSTATUS_VSDB */
2475
2476 bssidx = if_event_info->bssidx;
2477 if (bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION1) &&
2478 bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION2)) {
2479 WL_ERR(("got IF_DEL for if %d, not owned by cfg driver\n", bssidx));
2480 return BCME_ERROR;
2481 }
2482
2483 if (p2p_is_on(cfg) && wl_cfgp2p_vif_created(cfg)) {
2484 if (cfg->scan_request && (cfg->escan_info.ndev == ndev)) {
2485 /* Abort any pending scan requests */
2486 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2487 WL_DBG(("ESCAN COMPLETED\n"));
2488 wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, false);
2489 }
2490
2491 memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
2492 if (wl_cfgp2p_find_type(cfg, bssidx, &type) == BCME_OK) {
2493 /* Update P2P data */
2494 wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, type));
2495 wl_to_p2p_bss_ndev(cfg, type) = NULL;
2496 wl_to_p2p_bss_bssidx(cfg, type) = -1;
2497 } else if (wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr) < 0) {
2498 WL_ERR(("bssidx not known for the given ndev as per net_info data \n"));
2499 return BCME_ERROR;
2500 }
2501
2502#ifdef PROP_TXSTATUS_VSDB
dfb0f3ae 2503#if defined(BCMSDIO) || defined(BCMDBUS)
010c3a89
RC
2504 dhd_wlfc_get_enable(dhd, &enabled);
2505 if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
2506 dhd->op_mode != DHD_FLAG_IBSS_MODE && dhd->conf->disable_proptx!=0) {
2507 dhd_wlfc_deinit(dhd);
2508 cfg->wlfc_on = false;
2509 }
dfb0f3ae 2510#endif /* BCMSDIO || BCMDBUS */
010c3a89
RC
2511#endif /* PROP_TXSTATUS_VSDB */
2512 }
2513
2514 dhd_net_if_lock(ndev);
2515 wl_cfg80211_remove_if(cfg, if_event_info->ifidx, ndev, FALSE);
2516 dhd_net_if_unlock(ndev);
2517
2518 return BCME_OK;
2519}
2520
2521/* Find listen channel */
2522static s32 wl_find_listen_channel(struct bcm_cfg80211 *cfg,
2523 const u8 *ie, u32 ie_len)
2524{
2525 wifi_p2p_ie_t *p2p_ie;
2526 u8 *end, *pos;
2527 s32 listen_channel;
2528
2529/* unfortunately const cast required here - function is
2530 * a callback so its signature must not be changed
2531 * and cascade of changing wl_cfgp2p_find_p2pie
2532 * causes need for const cast in other places
2533 */
2534#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
2535 4 && __GNUC_MINOR__ >= 6))
2536_Pragma("GCC diagnostic push")
2537_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
2538#endif
2539 pos = (u8 *)ie;
2540#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
2541 4 && __GNUC_MINOR__ >= 6))
2542_Pragma("GCC diagnostic pop")
2543#endif
2544 p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len);
2545
2546 if (p2p_ie == NULL)
2547 return 0;
2548
2549 pos = p2p_ie->subelts;
2550 end = p2p_ie->subelts + (p2p_ie->len - 4);
2551
2552 CFGP2P_DBG((" found p2p ie ! lenth %d \n",
2553 p2p_ie->len));
2554
2555 while (pos < end) {
2556 uint16 attr_len;
2557 if (pos + 2 >= end) {
2558 CFGP2P_DBG((" -- Invalid P2P attribute"));
2559 return 0;
2560 }
2561 attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0]));
2562
2563 if (pos + 3 + attr_len > end) {
2564 CFGP2P_DBG(("P2P: Attribute underflow "
2565 "(len=%u left=%d)",
2566 attr_len, (int) (end - pos - 3)));
2567 return 0;
2568 }
2569
2570 /* if Listen Channel att id is 6 and the vailue is valid,
2571 * return the listen channel
2572 */
2573 if (pos[0] == 6) {
2574 /* listen channel subel length format
2575 * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num)
2576 */
2577 listen_channel = pos[1 + 2 + 3 + 1];
2578
2579 if (listen_channel == SOCIAL_CHAN_1 ||
2580 listen_channel == SOCIAL_CHAN_2 ||
2581 listen_channel == SOCIAL_CHAN_3) {
2582 CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel));
2583 return listen_channel;
2584 }
2585 }
2586 pos += 3 + attr_len;
2587 }
2588 return 0;
2589}
2590
2591static void wl_scan_prep(struct bcm_cfg80211 *cfg, struct wl_scan_params *params,
2592 struct cfg80211_scan_request *request)
2593{
2594 u32 n_ssids;
2595 u32 n_channels;
2596 u16 channel;
2597 chanspec_t chanspec;
2598 s32 i = 0, j = 0, offset;
2599 char *ptr;
2600 wlc_ssid_t ssid;
2601 struct wireless_dev *wdev;
2602
2603 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
2604 params->bss_type = DOT11_BSSTYPE_ANY;
2605 params->scan_type = 0;
2606 params->nprobes = -1;
2607 params->active_time = -1;
2608 params->passive_time = -1;
2609 params->home_time = -1;
2610 params->channel_num = 0;
2611 memset(&params->ssid, 0, sizeof(wlc_ssid_t));
2612
2613 WL_SCAN(("Preparing Scan request\n"));
2614 WL_SCAN(("nprobes=%d\n", params->nprobes));
2615 WL_SCAN(("active_time=%d\n", params->active_time));
2616 WL_SCAN(("passive_time=%d\n", params->passive_time));
2617 WL_SCAN(("home_time=%d\n", params->home_time));
2618 WL_SCAN(("scan_type=%d\n", params->scan_type));
2619
2620 params->nprobes = htod32(params->nprobes);
2621 params->active_time = htod32(params->active_time);
2622 params->passive_time = htod32(params->passive_time);
2623 params->home_time = htod32(params->home_time);
2624
2625 /* if request is null just exit so it will be all channel broadcast scan */
2626 if (!request)
2627 return;
2628
2629 n_ssids = request->n_ssids;
2630 n_channels = request->n_channels;
2631
2632 /* Copy channel array if applicable */
2633 WL_SCAN(("### List of channelspecs to scan ###\n"));
2634 if (n_channels > 0) {
2635 for (i = 0; i < n_channels; i++) {
2636 channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq);
2637 /* SKIP DFS channels for Secondary interface */
2638 if ((cfg->escan_info.ndev != bcmcfg_to_prmry_ndev(cfg)) &&
2639 (request->channels[i]->flags &
2640#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
2641 (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN)))
2642#else
2643 (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)))
2644#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */
2645 continue;
2646 if (!dhd_conf_match_channel(cfg->pub, channel))
2647 continue;
2648
2649#if defined(WL_CFG80211_P2P_DEV_IF)
2650 wdev = request->wdev;
2651#else
2652 wdev = request->dev->ieee80211_ptr;
2653#endif /* WL_CFG80211_P2P_DEV_IF */
2654 chanspec = wl_cfg80211_ulb_get_min_bw_chspec(cfg, wdev, -1);
2655 if (chanspec == INVCHANSPEC) {
2656 WL_ERR(("Invalid chanspec! Skipping channel\n"));
2657 continue;
2658 }
2659
2660 if (request->channels[i]->band == IEEE80211_BAND_2GHZ) {
2661 chanspec |= WL_CHANSPEC_BAND_2G;
2662 } else {
2663 chanspec |= WL_CHANSPEC_BAND_5G;
2664 }
2665 params->channel_list[j] = channel;
2666 params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK;
2667 params->channel_list[j] |= chanspec;
2668 WL_SCAN(("Chan : %d, Channel spec: %x \n",
2669 channel, params->channel_list[j]));
2670 params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]);
2671 j++;
2672 }
2673 } else {
2674 WL_SCAN(("Scanning all channels\n"));
2675 }
2676 n_channels = j;
2677 /* Copy ssid array if applicable */
2678 WL_SCAN(("### List of SSIDs to scan ###\n"));
2679 if (n_ssids > 0) {
2680 offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16);
2681 offset = roundup(offset, sizeof(u32));
2682 ptr = (char*)params + offset;
2683 for (i = 0; i < n_ssids; i++) {
2684 memset(&ssid, 0, sizeof(wlc_ssid_t));
2685 ssid.SSID_len = MIN(request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN);
2686 memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
2687 if (!ssid.SSID_len)
2688 WL_SCAN(("%d: Broadcast scan\n", i));
2689 else
2690 WL_SCAN(("%d: scan for %s size =%d\n", i,
2691 ssid.SSID, ssid.SSID_len));
2692 memcpy(ptr, &ssid, sizeof(wlc_ssid_t));
2693 ptr += sizeof(wlc_ssid_t);
2694 }
2695 } else {
2696 WL_SCAN(("Broadcast scan\n"));
2697 }
2698 /* Adding mask to channel numbers */
2699 params->channel_num =
2700 htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
2701 (n_channels & WL_SCAN_PARAMS_COUNT_MASK));
2702
2703 if (n_channels == 1) {
2704 params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS);
2705 params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS);
2706 }
2707}
2708
2709static s32
2710wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size)
2711{
2712 wl_uint32_list_t *list;
2713 s32 err = BCME_OK;
2714 if (valid_chan_list == NULL || size <= 0)
2715 return -ENOMEM;
2716
2717 memset(valid_chan_list, 0, size);
2718 list = (wl_uint32_list_t *)(void *) valid_chan_list;
2719 list->count = htod32(WL_NUMCHANNELS);
2720 err = wldev_ioctl_get(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size);
2721 if (err != 0) {
2722 WL_ERR(("get channels failed with %d\n", err));
2723 }
2724
2725 return err;
2726}
2727
2728#if defined(USE_INITIAL_SHORT_DWELL_TIME)
2729#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40
2730bool g_first_broadcast_scan = TRUE;
2731#endif
2732
2733static s32
2734wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev,
2735 struct cfg80211_scan_request *request, uint16 action)
2736{
2737 s32 err = BCME_OK;
2738 u32 n_channels;
2739 u32 n_ssids;
2740 s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
2741 wl_escan_params_t *params = NULL;
2742 u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
2743 u32 num_chans = 0;
2744 s32 channel;
2745 u32 n_valid_chan;
2746 s32 search_state = WL_P2P_DISC_ST_SCAN;
2747 u32 i, j, n_nodfs = 0;
2748 u16 *default_chan_list = NULL;
2749 wl_uint32_list_t *list;
2750 s32 bssidx = -1;
2751 struct net_device *dev = NULL;
2752#if defined(USE_INITIAL_SHORT_DWELL_TIME)
2753 bool is_first_init_2g_scan = false;
2754#endif
2755 p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN;
2756 scb_val_t scbval;
2757 static int cnt = 0;
2758
2759 WL_DBG(("Enter \n"));
2760
2761 /* scan request can come with empty request : perform all default scan */
2762 if (!cfg) {
2763 err = -EINVAL;
2764 goto exit;
2765 }
2766 if (!cfg->p2p_supported || !p2p_scan(cfg)) {
2767 /* LEGACY SCAN TRIGGER */
2768 WL_SCAN((" LEGACY E-SCAN START\n"));
2769
2770#if defined(USE_INITIAL_SHORT_DWELL_TIME)
2771 if (!request) {
2772 err = -EINVAL;
2773 goto exit;
2774 }
2775 if (ndev == bcmcfg_to_prmry_ndev(cfg) && g_first_broadcast_scan == true) {
2776 is_first_init_2g_scan = true;
2777 g_first_broadcast_scan = false;
2778 }
2779#endif
2780
2781 /* if scan request is not empty parse scan request paramters */
2782 if (request != NULL) {
2783 n_channels = request->n_channels;
2784 n_ssids = request->n_ssids;
2785 if (n_channels % 2)
2786 /* If n_channels is odd, add a padd of u16 */
2787 params_size += sizeof(u16) * (n_channels + 1);
2788 else
2789 params_size += sizeof(u16) * n_channels;
2790
2791 /* Allocate space for populating ssids in wl_escan_params_t struct */
2792 params_size += sizeof(struct wlc_ssid) * n_ssids;
2793 }
2794 params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
2795 if (params == NULL) {
2796 err = -ENOMEM;
2797 goto exit;
2798 }
2799 wl_scan_prep(cfg, &params->params, request);
2800
2801#if defined(USE_INITIAL_SHORT_DWELL_TIME)
2802 /* Override active_time to reduce scan time if it's first bradcast scan. */
2803 if (is_first_init_2g_scan)
2804 params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS;
2805#endif
2806
2807 params->version = htod32(ESCAN_REQ_VERSION);
2808 params->action = htod16(action);
2809 wl_escan_set_sync_id(params->sync_id, cfg);
2810 wl_escan_set_type(cfg, WL_SCANTYPE_LEGACY);
2811 if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
2812 WL_ERR(("ioctl buffer length not sufficient\n"));
2813 kfree(params);
2814 err = -ENOMEM;
2815 goto exit;
2816 }
2817 if (cfg->active_scan == PASSIVE_SCAN) {
2818 params->params.scan_type = DOT11_SCANTYPE_PASSIVE;
2819 WL_DBG(("Passive scan_type %d \n", params->params.scan_type));
2820 }
2821
2822 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
2823
2824 err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
2825 cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
2826 printf("%s: LEGACY_SCAN sync ID: %d, bssidx: %d\n", __FUNCTION__, params->sync_id, bssidx);
2827 if (unlikely(err)) {
2828 if (err == BCME_EPERM)
2829 /* Scan Not permitted at this point of time */
2830 WL_DBG((" Escan not permitted at this time (%d)\n", err));
2831 else
2832 WL_ERR((" Escan set error (%d)\n", err));
2833 } else {
2834 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_REQUESTED);
2835 }
2836 kfree(params);
2837 }
2838 else if (p2p_is_on(cfg) && p2p_scan(cfg)) {
2839 /* P2P SCAN TRIGGER */
2840 s32 _freq = 0;
2841 n_nodfs = 0;
2842 if (request && request->n_channels) {
2843 num_chans = request->n_channels;
2844 WL_SCAN((" chann number : %d\n", num_chans));
2845 default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list),
2846 GFP_KERNEL);
2847 if (default_chan_list == NULL) {
2848 WL_ERR(("channel list allocation failed \n"));
2849 err = -ENOMEM;
2850 goto exit;
2851 }
2852 if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) {
2853#ifdef P2P_SKIP_DFS
2854 int is_printed = false;
2855#endif /* P2P_SKIP_DFS */
2856 list = (wl_uint32_list_t *) chan_buf;
2857 n_valid_chan = dtoh32(list->count);
2858 if (n_valid_chan > WL_NUMCHANNELS) {
2859 WL_ERR(("wrong n_valid_chan:%d\n", n_valid_chan));
2860 kfree(default_chan_list);
2861 err = -EINVAL;
2862 goto exit;
2863 }
2864
2865 for (i = 0; i < num_chans; i++)
2866 {
2867 _freq = request->channels[i]->center_freq;
2868 channel = ieee80211_frequency_to_channel(_freq);
2869
2870 /* ignore DFS channels */
2871 if (request->channels[i]->flags &
2872#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
2873 (IEEE80211_CHAN_NO_IR
2874 | IEEE80211_CHAN_RADAR))
2875#else
2876 (IEEE80211_CHAN_RADAR
2877 | IEEE80211_CHAN_PASSIVE_SCAN))
2878#endif
2879 continue;
2880#ifdef P2P_SKIP_DFS
2881 if (channel >= 52 && channel <= 144) {
2882 if (is_printed == false) {
2883 WL_ERR(("SKIP DFS CHANs(52~144)\n"));
2884 is_printed = true;
2885 }
2886 continue;
2887 }
2888#endif /* P2P_SKIP_DFS */
2889
2890 for (j = 0; j < n_valid_chan; j++) {
2891 /* allows only supported channel on
2892 * current reguatory
2893 */
2894 if (n_nodfs >= num_chans) {
2895 break;
2896 }
2897 if (channel == (dtoh32(list->element[j]))) {
2898 default_chan_list[n_nodfs++] =
2899 channel;
2900 }
2901 }
2902
2903 }
2904 }
2905 if (num_chans == SOCIAL_CHAN_CNT && (
2906 (default_chan_list[0] == SOCIAL_CHAN_1) &&
2907 (default_chan_list[1] == SOCIAL_CHAN_2) &&
2908 (default_chan_list[2] == SOCIAL_CHAN_3))) {
2909 /* SOCIAL CHANNELS 1, 6, 11 */
2910 search_state = WL_P2P_DISC_ST_SEARCH;
2911 p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
2912 WL_INFORM(("P2P SEARCH PHASE START \n"));
2913 } else if (((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1)) &&
2914 (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) ||
2915 ((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION2)) &&
2916 (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP))) {
2917 /* If you are already a GO, then do SEARCH only */
2918 WL_INFORM(("Already a GO. Do SEARCH Only"));
2919 search_state = WL_P2P_DISC_ST_SEARCH;
2920 num_chans = n_nodfs;
2921 p2p_scan_purpose = P2P_SCAN_NORMAL;
2922
2923 } else if (num_chans == 1) {
2924 p2p_scan_purpose = P2P_SCAN_CONNECT_TRY;
2925 } else if (num_chans == SOCIAL_CHAN_CNT + 1) {
2926 /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by
2927 * the supplicant
2928 */
2929 p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
2930 } else {
2931 WL_INFORM(("P2P SCAN STATE START \n"));
2932 num_chans = n_nodfs;
2933 p2p_scan_purpose = P2P_SCAN_NORMAL;
2934 }
2935 } else {
2936 err = -EINVAL;
2937 goto exit;
2938 }
2939 err = wl_cfgp2p_escan(cfg, ndev, ACTIVE_SCAN, num_chans, default_chan_list,
2940 search_state, action,
2941 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE), NULL,
2942 p2p_scan_purpose);
2943
2944 if (!err)
2945 cfg->p2p->search_state = search_state;
2946
2947 kfree(default_chan_list);
2948 }
2949exit:
2950 if (unlikely(err)) {
2951 /* Don't print Error incase of Scan suppress */
2952 if ((err == BCME_EPERM) && cfg->scan_suppressed)
2953 WL_DBG(("Escan failed: Scan Suppressed \n"));
2954 else {
2955 cnt++;
2956 WL_ERR(("error (%d), cnt=%d\n", err, cnt));
2957 // terence 20140111: send disassoc to firmware
2958 if (cnt >= 4) {
2959 dev = bcmcfg_to_prmry_ndev(cfg);
2960 memset(&scbval, 0, sizeof(scb_val_t));
2961 wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true);
2962 WL_ERR(("Send disassoc to break the busy dev=%p\n", dev));
2963 cnt = 0;
2964 }
2965 }
2966 } else {
2967 cnt = 0;
2968 }
2969 return err;
2970}
2971
2972
2973static s32
2974wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *ndev,
2975 struct cfg80211_scan_request *request)
2976{
2977 s32 err = BCME_OK;
2978 s32 passive_scan = 0;
2979 s32 passive_scan_time = 0;
2980 s32 passive_scan_time_org = 0;
2981 wl_scan_results_t *results;
2982 WL_SCAN(("Enter \n"));
2983
2984 results = wl_escan_get_buf(cfg, FALSE);
2985 results->version = 0;
2986 results->count = 0;
2987 results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
2988
2989 cfg->escan_info.ndev = ndev;
2990 cfg->escan_info.wiphy = wiphy;
2991 cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
2992 passive_scan = cfg->active_scan ? 0 : 1;
2993 err = wldev_ioctl_set(ndev, WLC_SET_PASSIVE_SCAN,
2994 &passive_scan, sizeof(passive_scan));
2995 if (unlikely(err)) {
2996 WL_ERR(("error (%d)\n", err));
2997 goto exit;
2998 }
2999
3000 if (passive_channel_skip) {
3001
3002 err = wldev_ioctl_get(ndev, WLC_GET_SCAN_PASSIVE_TIME,
3003 &passive_scan_time_org, sizeof(passive_scan_time_org));
3004 if (unlikely(err)) {
3005 WL_ERR(("== error (%d)\n", err));
3006 goto exit;
3007 }
3008
3009 WL_SCAN(("PASSIVE SCAN time : %d \n", passive_scan_time_org));
3010
3011 passive_scan_time = 0;
3012 err = wldev_ioctl_set(ndev, WLC_SET_SCAN_PASSIVE_TIME,
3013 &passive_scan_time, sizeof(passive_scan_time));
3014 if (unlikely(err)) {
3015 WL_ERR(("== error (%d)\n", err));
3016 goto exit;
3017 }
3018
3019 WL_SCAN(("PASSIVE SCAN SKIPED!! (passive_channel_skip:%d) \n",
3020 passive_channel_skip));
3021 }
3022
3023 err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START);
3024
3025 if (passive_channel_skip) {
3026 err = wldev_ioctl_set(ndev, WLC_SET_SCAN_PASSIVE_TIME,
3027 &passive_scan_time_org, sizeof(passive_scan_time_org));
3028 if (unlikely(err)) {
3029 WL_ERR(("== error (%d)\n", err));
3030 goto exit;
3031 }
3032
3033 WL_SCAN(("PASSIVE SCAN RECOVERED!! (passive_scan_time_org:%d) \n",
3034 passive_scan_time_org));
3035 }
3036
3037exit:
3038 return err;
3039}
3040
3041static s32
3042__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
3043 struct cfg80211_scan_request *request,
3044 struct cfg80211_ssid *this_ssid)
3045{
3046 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3047 struct cfg80211_ssid *ssids;
3048 struct ether_addr primary_mac;
3049 bool p2p_ssid;
3050#ifdef WL11U
3051 bcm_tlv_t *interworking_ie;
3052#endif
3053 s32 err = 0;
3054 s32 bssidx = -1;
3055 s32 i;
3056
3057 unsigned long flags;
3058 static s32 busy_count = 0;
3059#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
3060 struct net_device *remain_on_channel_ndev = NULL;
3061#endif
3062 uint scan_timer_interval_ms = WL_SCAN_TIMER_INTERVAL_MS;
3063
3064 /*
3065 * Hostapd triggers scan before starting automatic channel selection
3066 * to collect channel characteristics. However firmware scan engine
3067 * doesn't support any channel characteristics collection along with
3068 * scan. Hence return scan success.
3069 */
3070 if (request && (scan_req_iftype(request) == NL80211_IFTYPE_AP)) {
3071 WL_INFORM(("Scan Command on SoftAP Interface. Ignoring...\n"));
3072// terence 20161023: let it scan in SoftAP mode
3073// return 0;
3074 }
3075
3076 ndev = ndev_to_wlc_ndev(ndev, cfg);
3077
3078 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
3079 WL_ERR(("Sending Action Frames. Try it again.\n"));
3080 return -EAGAIN;
3081 }
3082
3083 WL_DBG(("Enter wiphy (%p)\n", wiphy));
3084 if (wl_get_drv_status_all(cfg, SCANNING)) {
3085 if (cfg->scan_request == NULL) {
3086 wl_clr_drv_status_all(cfg, SCANNING);
3087 WL_DBG(("<<<<<<<<<<<Force Clear Scanning Status>>>>>>>>>>>\n"));
3088 } else {
3089 WL_ERR(("Scanning already\n"));
3090 return -EAGAIN;
3091 }
3092 }
3093 if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) {
3094 WL_ERR(("Scanning being aborted\n"));
3095 return -EAGAIN;
3096 }
3097 if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
3098 WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
3099 return -EOPNOTSUPP;
3100 }
3101
3102#ifdef P2P_LISTEN_OFFLOADING
3103 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
3104 WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
3105 return -EAGAIN;
3106 }
3107#endif /* P2P_LISTEN_OFFLOADING */
3108
3109#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
3110 remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg);
3111 if (remain_on_channel_ndev) {
3112 WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n"));
3113 wl_notify_escan_complete(cfg, remain_on_channel_ndev, true, true);
3114 }
3115#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
3116
3117
3118 /* Arm scan timeout timer */
3119 mod_timer(&cfg->scan_timeout, jiffies + msecs_to_jiffies(scan_timer_interval_ms));
3120 if (request) { /* scan bss */
3121 ssids = request->ssids;
3122 p2p_ssid = false;
3123 for (i = 0; i < request->n_ssids; i++) {
3124 if (ssids[i].ssid_len &&
3125 IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) {
3126 p2p_ssid = true;
3127 break;
3128 }
3129 }
3130 if (p2p_ssid) {
3131 if (cfg->p2p_supported) {
3132 /* p2p scan trigger */
3133 if (p2p_on(cfg) == false) {
3134 /* p2p on at the first time */
3135 p2p_on(cfg) = true;
3136 wl_cfgp2p_set_firm_p2p(cfg);
3137 get_primary_mac(cfg, &primary_mac);
3138 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
3139#if defined(P2P_IE_MISSING_FIX)
3140 cfg->p2p_prb_noti = false;
3141#endif
3142 }
3143 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
3144 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
3145 p2p_scan(cfg) = true;
3146 }
3147 } else {
3148 /* legacy scan trigger
3149 * So, we have to disable p2p discovery if p2p discovery is on
3150 */
3151 if (cfg->p2p_supported) {
3152 p2p_scan(cfg) = false;
3153 /* If Netdevice is not equals to primary and p2p is on
3154 * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
3155 */
3156
3157 if (p2p_scan(cfg) == false) {
3158 if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
3159 err = wl_cfgp2p_discover_enable_search(cfg,
3160 false);
3161 if (unlikely(err)) {
3162 goto scan_out;
3163 }
3164
3165 }
3166 }
3167 }
3168 if (!cfg->p2p_supported || !p2p_scan(cfg)) {
3169 if ((bssidx = wl_get_bssidx_by_wdev(cfg,
3170 ndev->ieee80211_ptr)) < 0) {
3171 WL_ERR(("Find p2p index from ndev(%p) failed\n",
3172 ndev));
3173 err = BCME_ERROR;
3174 goto scan_out;
3175 }
3176#ifdef WL11U
3177 if (request && (interworking_ie =
3178 wl_cfg80211_find_interworking_ie(
3179 request->ie, request->ie_len)) != NULL) {
3180 if ((err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx,
3181 VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
3182 interworking_ie->data,
3183 interworking_ie->len)) != BCME_OK) {
3184 WL_ERR(("Failed to add interworking IE"));
3185 }
3186 } else if (cfg->wl11u) {
3187 /* we have to clear IW IE and disable gratuitous APR */
3188 wl_cfg80211_clear_iw_ie(cfg, ndev, bssidx);
3189 err = wldev_iovar_setint_bsscfg(ndev, "grat_arp",
3190 0, bssidx);
3191 /* we don't care about error here
3192 * because the only failure case is unsupported,
3193 * which is fine
3194 */
3195 if (unlikely(err)) {
3196 WL_ERR(("Set grat_arp failed:(%d) Ignore!\n", err));
3197 }
3198 cfg->wl11u = FALSE;
3199 }
3200#endif /* WL11U */
3201 if (request) {
3202 err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
3203 ndev_to_cfgdev(ndev),
3204 bssidx, VNDR_IE_PRBREQ_FLAG, request->ie,
3205 request->ie_len);
3206 }
3207
3208 if (unlikely(err)) {
3209// terence 20161023: let it scan in SoftAP mode
3210// goto scan_out;
3211 }
3212
3213 }
3214 }
3215 } else { /* scan in ibss */
3216 ssids = this_ssid;
3217 }
3218
3219 if (request && cfg->p2p_supported) {
3220 WL_TRACE_HW4(("START SCAN\n"));
3221 DHD_OS_SCAN_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub),
3222 SCAN_WAKE_LOCK_TIMEOUT);
3223 DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)(cfg->pub));
3224 }
3225
3226 if (cfg->p2p_supported) {
3227 if (request && p2p_on(cfg) && p2p_scan(cfg)) {
3228
3229 /* find my listen channel */
3230 cfg->afx_hdl->my_listen_chan =
3231 wl_find_listen_channel(cfg, request->ie,
3232 request->ie_len);
3233 err = wl_cfgp2p_enable_discovery(cfg, ndev,
3234 request->ie, request->ie_len);
3235
3236 if (unlikely(err)) {
3237 goto scan_out;
3238 }
3239 }
3240 }
3241 err = wl_do_escan(cfg, wiphy, ndev, request);
3242 if (likely(!err))
3243 goto scan_success;
3244 else
3245 goto scan_out;
3246
3247scan_success:
3248 busy_count = 0;
3249 cfg->scan_request = request;
3250 wl_set_drv_status(cfg, SCANNING, ndev);
3251
3252 return 0;
3253
3254scan_out:
3255 if (err == BCME_BUSY || err == BCME_NOTREADY) {
3256 WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY));
3257 err = -EBUSY;
3258 } else if ((err == BCME_EPERM) && cfg->scan_suppressed) {
3259 WL_ERR(("Scan not permitted due to scan suppress\n"));
3260 err = -EPERM;
3261 } else {
3262 /* For all other fw errors, use a generic error code as return
3263 * value to cfg80211 stack
3264 */
3265 err = -EAGAIN;
3266 }
3267
3268#define SCAN_EBUSY_RETRY_LIMIT 20
3269 if (err == -EBUSY) {
3270 if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) {
3271 struct ether_addr bssid;
3272 s32 ret = 0;
3273#if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
3274 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
3275#endif /* DHD_DEBUG && DHD_FW_COREDUMP */
3276 busy_count = 0;
3277 WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n",
3278 wl_get_drv_status(cfg, SCANNING, ndev),
3279 wl_get_drv_status(cfg, SCAN_ABORTING, ndev),
3280 wl_get_drv_status(cfg, CONNECTING, ndev),
3281 wl_get_drv_status(cfg, CONNECTED, ndev),
3282 wl_get_drv_status(cfg, DISCONNECTING, ndev),
3283 wl_get_drv_status(cfg, AP_CREATING, ndev),
3284 wl_get_drv_status(cfg, AP_CREATED, ndev),
3285 wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev),
3286 wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev)));
3287
3288#if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
3289 if (dhdp->memdump_enabled) {
3290 dhdp->memdump_type = DUMP_TYPE_SCAN_BUSY;
3291 dhd_bus_mem_dump(dhdp);
3292 }
3293#endif /* DHD_DEBUG && DHD_FW_COREDUMP */
3294
3295 bzero(&bssid, sizeof(bssid));
3296 if ((ret = wldev_ioctl_get(ndev, WLC_GET_BSSID,
3297 &bssid, ETHER_ADDR_LEN)) == 0)
3298 WL_ERR(("FW is connected with " MACDBG "/n",
3299 MAC2STRDBG(bssid.octet)));
3300 else
3301 WL_ERR(("GET BSSID failed with %d\n", ret));
3302
3303 wl_cfg80211_scan_abort(cfg);
3304
3305 } else {
3306 /* Hold the context for 400msec, so that 10 subsequent scans
3307 * can give a buffer of 4sec which is enough to
3308 * cover any on-going scan in the firmware
3309 */
3310 WL_DBG(("Enforcing delay for EBUSY case \n"));
3311 msleep(400);
3312 }
3313 } else {
3314 busy_count = 0;
3315 }
3316
3317 wl_clr_drv_status(cfg, SCANNING, ndev);
3318 if (timer_pending(&cfg->scan_timeout))
3319 del_timer_sync(&cfg->scan_timeout);
3320 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
3321 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
3322 cfg->scan_request = NULL;
3323 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
3324
3325 return err;
3326}
3327
3328static s32
3329#if defined(WL_CFG80211_P2P_DEV_IF)
3330wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
3331#else
3332wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
3333 struct cfg80211_scan_request *request)
3334#endif /* WL_CFG80211_P2P_DEV_IF */
3335{
3336 s32 err = 0;
3337 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3338#if defined(WL_CFG80211_P2P_DEV_IF)
3339 struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg);
3340#endif /* WL_CFG80211_P2P_DEV_IF */
3341
3342 WL_DBG(("Enter\n"));
3343 RETURN_EIO_IF_NOT_UP(cfg);
3344
3345#ifdef DHD_IFDEBUG
3346#ifdef WL_CFG80211_P2P_DEV_IF
3347 PRINT_WDEV_INFO(request->wdev);
3348#else
3349 PRINT_WDEV_INFO(ndev);
3350#endif /* WL_CFG80211_P2P_DEV_IF */
3351#endif /* DHD_IFDEBUG */
3352
3353 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
3354 if (wl_cfg_multip2p_operational(cfg)) {
3355 WL_ERR(("wlan0 scan failed, p2p devices are operational"));
3356 return -ENODEV;
3357 }
3358 }
32c27b7a
RC
3359 err = wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
3360 WL_EXT_STATUS_SCAN, NULL);
d964ce36 3361 if (err)
3362 return err;
010c3a89
RC
3363
3364 mutex_lock(&cfg->usr_sync);
3365 err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
3366 if (unlikely(err)) {
3367 WL_ERR(("scan error (%d)\n", err));
3368 }
3369 mutex_unlock(&cfg->usr_sync);
3370#ifdef WL_DRV_AVOID_SCANCACHE
3371 /* Reset roam cache after successful scan request */
3372#endif /* WL_DRV_AVOID_SCANCACHE */
3373 return err;
3374}
3375
3376static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
3377{
3378 s32 err = 0;
3379
3380 err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
3381 if (unlikely(err)) {
3382 WL_ERR(("Error (%d)\n", err));
3383 return err;
3384 }
3385 return err;
3386}
3387
3388static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
3389{
3390 s32 err = 0;
3391
3392 err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
3393 if (unlikely(err)) {
3394 WL_ERR(("Error (%d)\n", err));
3395 return err;
3396 }
3397 return err;
3398}
3399
3400static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
3401{
3402 s32 err = 0;
3403 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
3404
3405 retry = htod32(retry);
3406 err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry));
3407 if (unlikely(err)) {
3408 WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
3409 return err;
3410 }
3411 return err;
3412}
3413
3414static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
3415{
3416 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
3417 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
3418 s32 err = 0;
3419
3420 RETURN_EIO_IF_NOT_UP(cfg);
3421 WL_DBG(("Enter\n"));
3422 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
3423 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
3424 cfg->conf->rts_threshold = wiphy->rts_threshold;
3425 err = wl_set_rts(ndev, cfg->conf->rts_threshold);
3426 if (err != BCME_OK)
3427 return err;
3428 }
3429 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
3430 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
3431 cfg->conf->frag_threshold = wiphy->frag_threshold;
3432 err = wl_set_frag(ndev, cfg->conf->frag_threshold);
3433 if (err != BCME_OK)
3434 return err;
3435 }
3436 if (changed & WIPHY_PARAM_RETRY_LONG &&
3437 (cfg->conf->retry_long != wiphy->retry_long)) {
3438 cfg->conf->retry_long = wiphy->retry_long;
3439 err = wl_set_retry(ndev, cfg->conf->retry_long, true);
3440 if (err != BCME_OK)
3441 return err;
3442 }
3443 if (changed & WIPHY_PARAM_RETRY_SHORT &&
3444 (cfg->conf->retry_short != wiphy->retry_short)) {
3445 cfg->conf->retry_short = wiphy->retry_short;
3446 err = wl_set_retry(ndev, cfg->conf->retry_short, false);
3447 if (err != BCME_OK) {
3448 return err;
3449 }
3450 }
3451
3452 return err;
3453}
3454static chanspec_t
3455channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap)
3456{
3457 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3458 u8 *buf = NULL;
3459 wl_uint32_list_t *list;
3460 int err = BCME_OK;
3461 chanspec_t c = 0, ret_c = 0;
3462 int bw = 0, tmp_bw = 0;
3463 int i;
3464 u32 tmp_c;
3465 u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
3466#define LOCAL_BUF_SIZE 1024
3467 buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags);
3468 if (!buf) {
3469 WL_ERR(("buf memory alloc failed\n"));
3470 goto exit;
3471 }
3472
3473 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
3474 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync);
3475 if (err != BCME_OK) {
3476 WL_ERR(("get chanspecs failed with %d\n", err));
3477 goto exit;
3478 }
3479
3480 list = (wl_uint32_list_t *)(void *)buf;
3481 for (i = 0; i < dtoh32(list->count); i++) {
3482 c = dtoh32(list->element[i]);
3483 if (channel <= CH_MAX_2G_CHANNEL) {
3484 if (!CHSPEC_IS20(c))
3485 continue;
3486 if (channel == CHSPEC_CHANNEL(c)) {
3487 ret_c = c;
3488 bw = 20;
3489 goto exit;
3490 }
3491 }
3492 tmp_c = wf_chspec_ctlchan(c);
3493 tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT];
3494 if (tmp_c != channel)
3495 continue;
3496
3497 if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) {
3498 bw = tmp_bw;
3499 ret_c = c;
3500 if (bw == bw_cap)
3501 goto exit;
3502 }
3503 }
3504exit:
3505 if (buf)
3506 kfree(buf);
3507#undef LOCAL_BUF_SIZE
3508 WL_INFORM(("return chanspec %x %d\n", ret_c, bw));
3509 return ret_c;
3510}
3511
3512void
3513wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev, vndr_ie_setbuf_t *ibss_vsie,
3514 int ibss_vsie_len)
3515{
3516 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3517
3518 if (cfg != NULL && ibss_vsie != NULL) {
3519 if (cfg->ibss_vsie != NULL) {
3520 kfree(cfg->ibss_vsie);
3521 }
3522 cfg->ibss_vsie = ibss_vsie;
3523 cfg->ibss_vsie_len = ibss_vsie_len;
3524 }
3525}
3526
3527static void
3528wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
3529{
3530 /* free & initiralize VSIE (Vendor Specific IE) */
3531 if (cfg->ibss_vsie != NULL) {
3532 kfree(cfg->ibss_vsie);
3533 cfg->ibss_vsie = NULL;
3534 cfg->ibss_vsie_len = 0;
3535 }
3536}
3537
3538s32
3539wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
3540{
3541 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3542 char *ioctl_buf = NULL;
3543 s32 ret = BCME_OK, bssidx;
3544
3545 if (cfg != NULL && cfg->ibss_vsie != NULL) {
3546 ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
3547 if (!ioctl_buf) {
3548 WL_ERR(("ioctl memory alloc failed\n"));
3549 return -ENOMEM;
3550 }
3551
3552 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3553 WL_ERR(("Find index failed\n"));
3554 ret = BCME_ERROR;
3555 goto end;
3556 }
3557 /* change the command from "add" to "del" */
3558 strncpy(cfg->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1);
3559 cfg->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
3560
3561 ret = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie",
3562 cfg->ibss_vsie, cfg->ibss_vsie_len,
3563 ioctl_buf, WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
3564 WL_ERR(("ret=%d\n", ret));
3565
3566 if (ret == BCME_OK) {
3567 /* free & initiralize VSIE */
3568 kfree(cfg->ibss_vsie);
3569 cfg->ibss_vsie = NULL;
3570 cfg->ibss_vsie_len = 0;
3571 }
3572end:
3573 if (ioctl_buf) {
3574 kfree(ioctl_buf);
3575 }
3576 }
3577
3578 return ret;
3579}
3580
3581#ifdef WLAIBSS_MCHAN
3582static bcm_struct_cfgdev*
3583bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name)
3584{
3585 int err = 0;
3586 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3587 struct wireless_dev* wdev = NULL;
3588 struct net_device *new_ndev = NULL;
3589 struct net_device *primary_ndev = NULL;
3590 s32 timeout;
3591 wl_aibss_if_t aibss_if;
3592 wl_if_event_info *event = NULL;
3593
3594 if (cfg->ibss_cfgdev != NULL) {
3595 WL_ERR(("IBSS interface %s already exists\n", name));
3596 return NULL;
3597 }
3598
3599 WL_ERR(("Try to create IBSS interface %s\n", name));
3600 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3601 /* generate a new MAC address for the IBSS interface */
3602 get_primary_mac(cfg, &cfg->ibss_if_addr);
3603 cfg->ibss_if_addr.octet[4] ^= 0x40;
3604 memset(&aibss_if, sizeof(aibss_if), 0);
3605 memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
3606 aibss_if.chspec = 0;
3607 aibss_if.len = sizeof(aibss_if);
3608
3609 cfg->bss_pending_op = TRUE;
3610 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
3611 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
3612 sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3613 if (err) {
3614 WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
3615 goto fail;
3616 }
3617 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3618 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
3619 if (timeout <= 0 || cfg->bss_pending_op)
3620 goto fail;
3621
3622 event = &cfg->if_event_info;
3623 /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
3624 * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
3625 * and will be freed by dhd_detach unless it gets unregistered before that. The
3626 * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
3627 * be freed by wl_dealloc_netinfo
3628 */
3629 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name,
3630 event->mac, event->bssidx, event->name);
3631 if (new_ndev == NULL)
3632 goto fail;
3633 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
3634 if (wdev == NULL)
3635 goto fail;
3636 wdev->wiphy = wiphy;
3637 wdev->iftype = NL80211_IFTYPE_ADHOC;
3638 wdev->netdev = new_ndev;
3639 new_ndev->ieee80211_ptr = wdev;
3640 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
3641
3642 /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
3643 * needs to be modified to take one parameter (bool need_rtnl_lock)
3644 */
3645 ASSERT_RTNL();
3646 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, FALSE) != BCME_OK)
3647 goto fail;
3648
3649 wl_alloc_netinfo(cfg, new_ndev, wdev, WL_MODE_IBSS, PM_ENABLE, event->bssidx);
3650 cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
3651 WL_ERR(("IBSS interface %s created\n", new_ndev->name));
3652 return cfg->ibss_cfgdev;
3653
3654fail:
3655 WL_ERR(("failed to create IBSS interface %s \n", name));
3656 cfg->bss_pending_op = FALSE;
3657 if (new_ndev)
3658 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
3659 if (wdev)
3660 kfree(wdev);
3661 return NULL;
3662}
3663
3664static s32
3665bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
3666{
3667 int err = 0;
3668 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3669 struct net_device *ndev = NULL;
3670 struct net_device *primary_ndev = NULL;
3671 s32 timeout;
3672
3673 if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet))
3674 return -EINVAL;
3675 ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev);
3676 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3677
3678 cfg->bss_pending_op = TRUE;
3679 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
3680 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
3681 sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3682 if (err) {
3683 WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
3684 goto fail;
3685 }
3686 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3687 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
3688 if (timeout <= 0 || cfg->bss_pending_op) {
3689 WL_ERR(("timeout in waiting IF_DEL event\n"));
3690 goto fail;
3691 }
3692
3693 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
3694 cfg->ibss_cfgdev = NULL;
3695 return 0;
3696
3697fail:
3698 cfg->bss_pending_op = FALSE;
3699 return -1;
3700}
3701#endif /* WLAIBSS_MCHAN */
3702
dfb0f3ae
RC
3703#ifdef WLMESH
3704s32
3705wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
3706 struct net_device *ndev, s32 bsscfg_idx,
3707 enum nl80211_iftype iface_type, s32 del, u8 *addr)
3708{
3709 wl_interface_create_t iface;
3710 s32 ret;
3711 wl_interface_info_t *info;
3712
3713 bzero(&iface, sizeof(wl_interface_create_t));
3714
3715 iface.ver = WL_INTERFACE_CREATE_VER;
3716
3717 if (iface_type == NL80211_IFTYPE_AP)
3718 iface.flags = WL_INTERFACE_CREATE_AP;
3719 else
3720 iface.flags = WL_INTERFACE_CREATE_STA;
3721
3722 if (del) {
3723 ret = wldev_iovar_setbuf(ndev, "interface_remove",
3724 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3725 } else {
3726 if (addr) {
3727 memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
3728 iface.flags |= WL_INTERFACE_MAC_USE;
3729 }
3730 ret = wldev_iovar_getbuf(ndev, "interface_create",
3731 &iface, sizeof(wl_interface_create_t),
3732 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3733 if (ret == 0) {
3734 /* success */
3735 info = (wl_interface_info_t *)cfg->ioctl_buf;
3736 WL_DBG(("wl interface create success!! bssidx:%d \n",
3737 info->bsscfgidx));
3738 }
3739 }
3740
3741 if (ret < 0)
3742 WL_ERR(("Interface %s failed!! ret %d\n",
3743 del ? "remove" : "create", ret));
3744
3745 return ret;
3746}
3747#else
010c3a89
RC
3748s32
3749wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
3750 struct net_device *ndev, s32 bsscfg_idx,
3751 enum nl80211_iftype iface_type, s32 del, u8 *addr)
3752{
3753 s32 ret;
3754 struct wl_interface_create_v2 iface;
3755 wl_interface_create_v3_t iface_v3;
3756 struct wl_interface_info_v1 *info;
3757 wl_interface_info_v2_t *info_v2;
3758 enum wl_interface_type iftype;
3759 uint32 ifflags;
3760 bool use_iface_info_v2 = false;
3761 u8 ioctl_buf[WLC_IOCTL_SMLEN];
3762
3763 if (del) {
3764 ret = wldev_iovar_setbuf(ndev, "interface_remove",
3765 NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL);
3766 if (unlikely(ret))
3767 WL_ERR(("Interface remove failed!! ret %d\n", ret));
3768 return ret;
3769 }
3770
3771 /* Interface create */
3772 bzero(&iface, sizeof(iface));
3773 /*
3774 * flags field is still used along with iftype inorder to support the old version of the
3775 * FW work with the latest app changes.
3776 */
3777 if (iface_type == NL80211_IFTYPE_AP) {
3778 iftype = WL_INTERFACE_TYPE_AP;
3779 ifflags = WL_INTERFACE_CREATE_AP;
3780 } else {
3781 iftype = WL_INTERFACE_TYPE_STA;
3782 ifflags = WL_INTERFACE_CREATE_STA;
3783 }
3784 if (addr) {
3785 ifflags |= WL_INTERFACE_MAC_USE;
3786 }
3787
3788 /* Pass ver = 0 for fetching the interface_create iovar version */
3789 ret = wldev_iovar_getbuf(ndev, "interface_create",
3790 &iface, sizeof(struct wl_interface_create_v2),
3791 ioctl_buf, sizeof(ioctl_buf), NULL);
3792 if (ret == BCME_UNSUPPORTED) {
3793 WL_ERR(("interface_create iovar not supported\n"));
3794 return ret;
3795 } else if ((ret == 0) && *((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3) {
3796 WL_DBG(("interface_create version 3\n"));
3797 use_iface_info_v2 = true;
3798 bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
3799 iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
3800 iface_v3.iftype = iftype;
3801 iface_v3.flags = ifflags;
3802 if (addr) {
3803 memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
3804 }
3805 ret = wldev_iovar_getbuf(ndev, "interface_create",
3806 &iface_v3, sizeof(wl_interface_create_v3_t),
3807 ioctl_buf, sizeof(ioctl_buf), NULL);
3808 } else {
ccd15baf 3809#if 0
010c3a89
RC
3810 /* On any other error, attempt with iovar version 2 */
3811 WL_DBG(("interface_create version 2. get_ver:%d\n", ret));
3812 iface.ver = WL_INTERFACE_CREATE_VER_2;
3813 iface.iftype = iftype;
3814 iface.flags = ifflags;
3815 if (addr) {
3816 memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
3817 }
3818 ret = wldev_iovar_getbuf(ndev, "interface_create",
3819 &iface, sizeof(struct wl_interface_create_v2),
3820 ioctl_buf, sizeof(ioctl_buf), NULL);
ccd15baf 3821#endif
010c3a89
RC
3822 }
3823
3824 if (unlikely(ret)) {
3825 WL_ERR(("Interface create failed!! ret %d\n", ret));
3826 return ret;
3827 }
3828
3829 /* success case */
3830 if (use_iface_info_v2 == true) {
3831 info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
3832 ret = info_v2->bsscfgidx;
3833 } else {
3834 /* Use v1 struct */
3835 info = (struct wl_interface_info_v1 *)ioctl_buf;
3836 ret = info->bsscfgidx;
3837 }
3838
3839 WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
3840 return ret;
3841}
dfb0f3ae 3842#endif
010c3a89
RC
3843
3844bool
3845wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg,
3846 struct net_device *ndev)
3847{
3848 u32 chipnum;
3849 wlc_rev_info_t revinfo;
3850 int ret;
3851
3852 /* Get the device rev info */
3853 memset(&revinfo, 0, sizeof(revinfo));
3854 ret = wldev_ioctl_get(ndev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
3855 if (ret < 0) {
3856 WL_ERR(("%s: GET revinfo FAILED. ret:%d\n", __FUNCTION__, ret));
3857 ASSERT(0);
3858 return false;
3859 }
3860
3861 WL_DBG(("%s: GET_REVINFO device 0x%x, vendor 0x%x, chipnum 0x%x\n", __FUNCTION__,
3862 dtoh32(revinfo.deviceid), dtoh32(revinfo.vendorid), dtoh32(revinfo.chipnum)));
3863 chipnum = revinfo.chipnum;
3864 if ((chipnum == BCM4350_CHIP_ID) || (chipnum == BCM4355_CHIP_ID) ||
d964ce36 3865 (chipnum == BCM4345_CHIP_ID) || (chipnum == BCM43430_CHIP_ID) ||
3866 (chipnum == BCM43362_CHIP_ID)) {
010c3a89
RC
3867 /* WAR required */
3868 return true;
3869 }
3870
3871 return false;
3872}
3873
3874void
3875wl_bss_iovar_war(struct bcm_cfg80211 *cfg,
3876 struct net_device *ndev, s32 *val)
3877{
d964ce36 3878 u32 chipnum;
3879 wlc_rev_info_t revinfo;
3880 int ret;
3881 bool need_war = false;
3882
3883 /* Get the device rev info */
3884 memset(&revinfo, 0, sizeof(revinfo));
3885 ret = wldev_ioctl_get(ndev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
3886 if (ret < 0) {
3887 WL_ERR(("%s: GET revinfo FAILED. ret:%d\n", __FUNCTION__, ret));
3888 } else {
3889 WL_DBG(("%s: GET_REVINFO device 0x%x, vendor 0x%x, chipnum 0x%x\n", __FUNCTION__,
3890 dtoh32(revinfo.deviceid), dtoh32(revinfo.vendorid), dtoh32(revinfo.chipnum)));
3891 chipnum = revinfo.chipnum;
3892 if ((chipnum == BCM4359_CHIP_ID) || (chipnum == BCM43596_CHIP_ID)) {
3893 /* WAR required */
3894 need_war = true;
3895 }
3896 }
3897
3898 if (wl_customer6_legacy_chip_check(cfg, ndev) || need_war) {
010c3a89
RC
3899 /* Few firmware branches have issues in bss iovar handling and
3900 * that can't be changed since they are in production.
3901 */
3902 if (*val == WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE) {
3903 *val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
3904 } else if (*val == WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE) {
3905 *val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
3906 } else {
3907 /* Ignore for other bss enums */
3908 return;
3909 }
3910 WL_ERR(("wl bss %d\n", *val));
3911 }
3912}
3913
3914s32
3915wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
3916 struct net_device *ndev, s32 bsscfg_idx,
3917 enum nl80211_iftype iface_type, s32 del, u8 *addr)
3918{
3919 s32 ret = BCME_OK;
3920 s32 val = 0;
3921
3922 struct {
3923 s32 cfg;
3924 s32 val;
3925 struct ether_addr ea;
3926 } bss_setbuf;
3927
3928 WL_INFORM(("iface_type:%d del:%d \n", iface_type, del));
3929
3930 bzero(&bss_setbuf, sizeof(bss_setbuf));
3931
3932 /* AP=2, STA=3, up=1, down=0, val=-1 */
3933 if (del) {
3934 val = WLC_AP_IOV_OP_DELETE;
3935 } else if (iface_type == NL80211_IFTYPE_AP) {
3936 /* Add/role change to AP Interface */
3937 WL_DBG(("Adding AP Interface \n"));
3938 val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
3939 } else if (iface_type == NL80211_IFTYPE_STATION) {
3940 /* Add/role change to STA Interface */
3941 WL_DBG(("Adding STA Interface \n"));
3942 val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
3943 } else {
3944 WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", iface_type));
3945 return -EINVAL;
3946 }
3947
3948 if (!del) {
3949 wl_bss_iovar_war(cfg, ndev, &val);
3950 }
3951
3952 bss_setbuf.cfg = htod32(bsscfg_idx);
3953 bss_setbuf.val = htod32(val);
3954
3955 if (addr) {
3956 memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
3957 }
3958
3959 WL_DBG(("wl bss %d bssidx:%d iface:%s \n", val, bsscfg_idx, ndev->name));
3960 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3961 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3962 if (ret != 0)
3963 WL_ERR(("'bss %d' failed with %d\n", val, ret));
3964
3965 return ret;
3966}
3967
3968s32
3969wl_cfg80211_bss_up(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 bss_up)
3970{
3971 s32 ret = BCME_OK;
3972 s32 val = bss_up ? 1 : 0;
3973
3974 struct {
3975 s32 cfg;
3976 s32 val;
3977 } bss_setbuf;
3978
3979 bss_setbuf.cfg = htod32(bsscfg_idx);
3980 bss_setbuf.val = htod32(val);
3981
3982 WL_DBG(("wl bss -C %d %s\n", bsscfg_idx, bss_up ? "up" : "down"));
3983 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3984 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3985
3986 if (ret != 0) {
3987 WL_ERR(("'bss %d' failed with %d\n", bss_up, ret));
3988 }
3989
3990 return ret;
3991}
3992
3993bool
3994wl_cfg80211_bss_isup(struct net_device *ndev, int bsscfg_idx)
3995{
3996 s32 result, val;
3997 bool isup = false;
3998 s8 getbuf[64];
3999
4000 /* Check if the BSS is up */
4001 *(int*)getbuf = -1;
4002 result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
4003 sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
4004 if (result != 0) {
4005 WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
4006 WL_ERR(("NOTE: this ioctl error is normal "
4007 "when the BSS has not been created yet.\n"));
4008 } else {
4009 val = *(int*)getbuf;
4010 val = dtoh32(val);
4011 WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx, val));
4012 isup = (val ? TRUE : FALSE);
4013 }
4014 return isup;
4015}
4016
4017static s32
4018cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode)
4019{
4020 switch (type) {
4021 case NL80211_IFTYPE_STATION:
4022 *role = WLC_E_IF_ROLE_STA;
4023 *mode = WL_MODE_BSS;
4024 break;
4025 case NL80211_IFTYPE_AP:
4026 *role = WLC_E_IF_ROLE_AP;
4027 *mode = WL_MODE_AP;
4028 break;
4029 case NL80211_IFTYPE_P2P_GO:
4030 *role = WLC_E_IF_ROLE_P2P_GO;
4031 *mode = WL_MODE_AP;
4032 break;
4033 case NL80211_IFTYPE_P2P_CLIENT:
4034 *role = WLC_E_IF_ROLE_P2P_CLIENT;
4035 *mode = WL_MODE_BSS;
4036 break;
4037 case NL80211_IFTYPE_MONITOR:
4038 WL_ERR(("Unsupported mode \n"));
4039 return BCME_UNSUPPORTED;
4040 case NL80211_IFTYPE_ADHOC:
4041 *role = WLC_E_IF_ROLE_IBSS;
4042 *mode = WL_MODE_IBSS;
4043 break;
4044 default:
4045 WL_ERR(("Unknown interface type:0x%x\n", type));
4046 return BCME_ERROR;
4047 }
4048 return BCME_OK;
4049}
4050
4051static s32
4052wl_if_to_cfg80211_type(uint16 role)
4053{
4054 switch (role) {
4055 case WLC_E_IF_ROLE_STA:
4056 return NL80211_IFTYPE_STATION;
4057 case WLC_E_IF_ROLE_AP:
4058 return NL80211_IFTYPE_AP;
4059 case WLC_E_IF_ROLE_P2P_GO:
4060 return NL80211_IFTYPE_P2P_GO;
4061 case WLC_E_IF_ROLE_P2P_CLIENT:
4062 return NL80211_IFTYPE_P2P_CLIENT;
4063 case WLC_E_IF_ROLE_IBSS:
4064 return NL80211_IFTYPE_ADHOC;
4065 default:
4066 WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role));
4067 return BCME_ERROR;
4068 }
4069}
4070
4071struct net_device *
4072wl_cfg80211_post_ifcreate(struct net_device *ndev,
4073 wl_if_event_info *event, u8 *addr,
4074 const char *name, bool rtnl_lock_reqd)
4075{
4076 struct bcm_cfg80211 *cfg;
4077 struct net_device *primary_ndev;
4078 struct net_device *new_ndev = NULL;
4079 struct wireless_dev *wdev = NULL;
4080 s32 iface_type;
4081 s32 ret;
4082 u16 mode;
4083 u16 role;
4084 u8 mac_addr[ETH_ALEN];
4085
4086 if (!ndev || !event) {
4087 WL_ERR(("Wrong arg\n"));
4088 return NULL;
4089 }
4090
4091 cfg = wl_get_cfg(ndev);
4092 if (!cfg) {
4093 WL_ERR(("cfg null\n"));
4094 return NULL;
4095 }
4096
4097 WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
4098 event->role, event->ifidx, event->bssidx));
4099 if (!event->ifidx || !event->bssidx) {
4100 /* Fw returned primary idx (0) for virtual interface */
4101 WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
4102 event->ifidx, event->bssidx));
4103 return NULL;
4104 }
4105
4106 iface_type = wl_if_to_cfg80211_type(event->role);
4107 if (iface_type < 0) {
4108 /* Unknown iface type */
4109 WL_ERR(("Wrong iface type \n"));
4110 return NULL;
4111 }
4112
4113 if (cfg80211_to_wl_iftype(iface_type, &role, &mode) < 0) {
4114 /* Unsupported operating mode */
4115 WL_ERR(("Unsupported operating mode \n"));
4116 return NULL;
4117 }
4118
4119 WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG "\n",
4120 addr, name, event->role, iface_type, MAC2STRDBG(event->mac)));
4121 if (!name) {
4122 /* If iface name is not provided, use dongle ifname */
4123 name = event->name;
4124 }
4125
4126 if (!addr) {
4127 /* If mac address is not set, use primary mac with locally administered
4128 * bit set.
4129 */
4130 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4131 memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
4132#ifndef CUSTOMER_HW6
4133 /* For customer6 builds, use primary mac address for virtual interface */
4134 mac_addr[0] |= 0x02;
4135#endif /* CUSTOMER_HW6 */
4136 addr = mac_addr;
4137 }
4138
4139 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
4140 name, addr, event->bssidx, event->name);
4141 if (!new_ndev) {
4142 WL_ERR(("I/F allocation failed! \n"));
4143 goto fail;
4144 } else {
4145 WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
4146 event->ifidx, event->bssidx));
4147 }
4148
4149 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
4150 if (!wdev) {
4151 WL_ERR(("wireless_dev alloc failed! \n"));
4152 goto fail;
4153 }
4154
4155 wdev->wiphy = bcmcfg_to_wiphy(cfg);
4156 wdev->iftype = iface_type;
4157 new_ndev->ieee80211_ptr = wdev;
4158 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4159
4160 /* Check whether mac addr is in sync with fw. If not,
4161 * apply it using cur_etheraddr.
4162 */
4163 if (memcmp(addr, event->mac, ETH_ALEN) != 0) {
4164 ret = wldev_iovar_setbuf_bsscfg(new_ndev, "cur_etheraddr",
4165 addr, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
4166 event->bssidx, &cfg->ioctl_buf_sync);
4167 if (unlikely(ret)) {
d964ce36 4168 WL_ERR(("set cur_etheraddr Error (%d)\n", ret));
4169 goto fail;
010c3a89
RC
4170 }
4171 memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
4172 WL_ERR(("Applying updated mac address to firmware\n"));
4173 }
4174
4175 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd) != BCME_OK) {
4176 WL_ERR(("IFACE register failed \n"));
4177 goto fail;
4178 }
4179
4180 /* Initialize with the station mode params */
4181 ret = wl_alloc_netinfo(cfg, new_ndev, wdev, mode,
4182 PM_ENABLE, event->bssidx);
4183 if (unlikely(ret)) {
4184 WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret));
4185 goto fail;
4186 }
4187
4188 /* Apply the mode & infra setting based on iftype */
4189 if ((ret = wl_config_ifmode(cfg, new_ndev, iface_type)) < 0) {
4190 WL_ERR(("config ifmode failure (%d)\n", ret));
4191 goto fail;
4192 }
4193
4194 if (mode == WL_MODE_AP) {
4195 wl_set_drv_status(cfg, AP_CREATING, new_ndev);
4196 }
4197
4198 WL_INFORM(("Host Network Interface (%s) for Secondary I/F created."
4199 " cfg_iftype:%d wl_role:%d\n", new_ndev->name, iface_type, event->role));
4200
4201 return new_ndev;
4202
4203fail:
4204 if (wdev)
4205 kfree(wdev);
4206 if (new_ndev)
4207 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4208
4209 return NULL;
4210}
4211
4212void
4213wl_cfg80211_cleanup_virtual_ifaces(struct net_device *dev, bool rtnl_lock_reqd)
4214{
4215 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4216 struct net_info *iter, *next;
4217 struct net_device *primary_ndev;
4218
4219 /* Note: This function will clean up only the network interface and host
4220 * data structures. The firmware interface clean up will happen in the
4221 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4222 * context for the module case).
4223 */
4224 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4225#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
4226#pragma GCC diagnostic push
4227#pragma GCC diagnostic ignored "-Wcast-qual"
4228#endif
4229 for_each_ndev(cfg, iter, next) {
4230 if (iter->ndev && (iter->ndev != primary_ndev)) {
4231 WL_DBG(("Cleaning up iface:%s \n", iter->ndev->name));
4232 wl_cfg80211_post_ifdel(iter->ndev, rtnl_lock_reqd);
4233 }
4234 }
4235#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
4236#pragma GCC diagnostic pop
4237#endif
4238}
4239
4240s32
4241wl_cfg80211_post_ifdel(struct net_device *ndev, bool rtnl_lock_reqd)
4242{
4243 int ifidx = -1;
4244 struct bcm_cfg80211 *cfg;
4245
4246 if (!ndev || !ndev->ieee80211_ptr) {
4247 /* No wireless dev done for this interface */
4248 return -EINVAL;
4249 }
4250
4251 cfg = wl_get_cfg(ndev);
4252 if (!cfg) {
4253 WL_ERR(("cfg null\n"));
4254 return BCME_ERROR;
4255 }
4256 ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
4257 BCM_REFERENCE(ifidx);
4258 if (ifidx <= 0) {
4259 WL_ERR(("Invalid IF idx for iface:%s\n", ndev->name));
4260 ASSERT(0);
4261 return BCME_ERROR;
4262 }
4263 WL_DBG(("cfg80211_remove for iface:%s \n", ndev->name));
4264 wl_cfg80211_remove_if(cfg, ifidx, ndev, rtnl_lock_reqd);
4265 cfg->bss_pending_op = FALSE;
4266
4267 return BCME_OK;
4268}
4269
4270#if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF)
4271/* Create a Generic Network Interface and initialize it depending up on
4272 * the interface type
4273 */
4274bcm_struct_cfgdev*
4275wl_cfg80211_create_iface(struct wiphy *wiphy,
4276 enum nl80211_iftype iface_type,
4277 u8 *mac_addr, const char *name)
4278{
4279 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4280 struct net_device *new_ndev = NULL;
4281 struct net_device *primary_ndev = NULL;
4282 s32 ret = BCME_OK;
4283 s32 bsscfg_idx = 0;
4284 u32 timeout;
4285 wl_if_event_info *event = NULL;
4286 u8 addr[ETH_ALEN];
4287 struct net_info *iter, *next;
dfb0f3ae
RC
4288#ifdef WLMESH
4289 u16 role = 0, mode = 0;
4290#endif
010c3a89
RC
4291
4292 WL_DBG(("Enter\n"));
4293 if (!name) {
4294 WL_ERR(("Interface name not provided\n"));
4295 return NULL;
4296 }
4297 else {
4298#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
4299#pragma GCC diagnostic push
4300#pragma GCC diagnostic ignored "-Wcast-qual"
4301#endif
4302 for_each_ndev(cfg, iter, next) {
4303 if (iter->ndev) {
4304 if (strcmp(iter->ndev->name, name) == 0) {
4305 WL_ERR(("Interface name, %s exists !\n", iter->ndev->name));
4306 return NULL;
4307 }
4308 }
4309 }
4310#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
4311#pragma GCC diagnostic pop
4312#endif
4313 }
4314 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4315
4316 if (likely(!mac_addr)) {
4317 /* Use primary MAC with the locally administered bit for the
4318 * Secondary STA I/F
4319 */
4320 memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
4321 addr[0] |= 0x02;
4322 } else {
4323 /* Use the application provided mac address (if any) */
4324 memcpy(addr, mac_addr, ETH_ALEN);
4325 }
4326
4327 if ((iface_type != NL80211_IFTYPE_STATION) && (iface_type != NL80211_IFTYPE_AP)) {
4328 WL_ERR(("IFACE type:%d not supported. STA "
4329 "or AP IFACE is only supported\n", iface_type));
4330 return NULL;
4331 }
4332
4333 cfg->bss_pending_op = TRUE;
4334 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4335
4336 /* De-initialize the p2p discovery interface, if operational */
4337 if (p2p_is_on(cfg)) {
4338 WL_DBG(("Disabling P2P Discovery Interface \n"));
4339#ifdef WL_CFG80211_P2P_DEV_IF
4340 ret = wl_cfg80211_scan_stop(cfg, bcmcfg_to_p2p_wdev(cfg));
4341#else
4342 ret = wl_cfg80211_scan_stop(cfg, cfg->p2p_net);
4343#endif
4344 if (unlikely(ret < 0)) {
4345 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
4346 }
4347
4348 wl_cfgp2p_disable_discovery(cfg);
4349 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
4350 p2p_on(cfg) = false;
4351 }
4352
4353 /*
4354 * Intialize the firmware I/F.
4355 */
4356 if (wl_customer6_legacy_chip_check(cfg, primary_ndev)) {
4357 /* Use bss iovar instead of interface_create iovar */
4358 ret = BCME_UNSUPPORTED;
4359 } else {
4360 ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
4361 iface_type, 0, addr);
4362 }
4363 if (ret == BCME_UNSUPPORTED) {
4364 /* Use bssidx 1 by default */
4365 bsscfg_idx = 1;
4366 if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
4367 bsscfg_idx, iface_type, 0, addr)) < 0) {
4368 goto exit;
4369 }
4370 } else if (ret < 0) {
4371 WL_ERR(("Interface create failed!! ret:%d \n", ret));
4372 goto exit;
4373 } else {
4374 /* Success */
4375 bsscfg_idx = ret;
4376 }
4377
4378 WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
4379
4380 /*
4381 * Wait till the firmware send a confirmation event back.
4382 */
4383 WL_DBG(("Wait for the FW I/F Event\n"));
4384 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4385 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4386 if (timeout <= 0 || cfg->bss_pending_op) {
4387 WL_ERR(("ADD_IF event, didn't come. Return \n"));
4388 goto exit;
4389 }
4390
4391 event = &cfg->if_event_info;
dfb0f3ae
RC
4392#ifdef WLMESH
4393 cfg80211_to_wl_iftype(iface_type, &role, &mode);
4394 event->role = role;
4395#endif
4396
010c3a89
RC
4397 /*
4398 * Since FW operation is successful,we can go ahead with the
4399 * the host interface creation.
4400 */
4401 if ((new_ndev = wl_cfg80211_post_ifcreate(primary_ndev,
4402 event, mac_addr, name, false))) {
4403 /* Iface post ops successful. Return ndev/wdev ptr */
4404 return ndev_to_cfgdev(new_ndev);
4405 }
4406
4407exit:
4408 cfg->bss_pending_op = FALSE;
4409 return NULL;
4410}
4411
4412s32
4413wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
4414{
4415 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4416 struct net_device *ndev = NULL;
4417 s32 ret = BCME_OK;
4418 s32 bsscfg_idx = 1;
4419 u32 timeout;
4420 enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION;
4421
4422 WL_DBG(("Enter\n"));
4423
4424 /* If any scan is going on, abort it */
4425 if (wl_get_drv_status_all(cfg, SCANNING)) {
4426 WL_DBG(("Scan in progress. Aborting the scan!\n"));
4427 wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
4428 }
4429
4430 ndev = (struct net_device *)cfgdev_to_ndev(cfgdev);
4431 cfg->bss_pending_op = TRUE;
4432 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4433
4434 /* Delete the firmware interface. "interface_remove" command
4435 * should go on the interface to be deleted
4436 */
4437 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
4438 if (bsscfg_idx <= 0) {
4439 /* validate bsscfgidx */
4440 WL_ERR(("Wrong bssidx! \n"));
4441 return -EINVAL;
4442 }
4443 WL_DBG(("del interface. bssidx:%d", bsscfg_idx));
4444 ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx,
4445 NL80211_IFTYPE_STATION, 1, NULL);
4446 if (ret == BCME_UNSUPPORTED) {
4447 if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
4448 bsscfg_idx, iface_type, true, NULL)) < 0) {
4449 WL_ERR(("DEL bss failed ret:%d \n", ret));
4450 goto exit;
4451 }
4452 } else if (ret < 0) {
4453 WL_ERR(("Interface DEL failed ret:%d \n", ret));
4454 goto exit;
4455 }
4456
4457 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4458 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4459 if (timeout <= 0 || cfg->bss_pending_op) {
4460 WL_ERR(("timeout in waiting IF_DEL event\n"));
4461 }
4462
4463exit:
4464 ret = wl_cfg80211_post_ifdel(ndev, false);
4465 if (unlikely(ret)) {
4466 WL_ERR(("post_ifdel failed\n"));
4467 }
4468
4469 return ret;
4470}
4471#endif /* defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) */
4472
dfb0f3ae
RC
4473#ifdef WLMESH
4474s32 wl_cfg80211_set_sae_password(struct net_device *dev, char* buf, int len)
4475{
4476 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4477
4478 sscanf(buf, "%s %d", cfg->sae_password, &cfg->sae_password_len);
4479 return 0;
4480}
4481
4482static s32 wl_cfg80211_join_mesh(
4483 struct wiphy *wiphy, struct net_device *dev,
4484 const struct mesh_config *conf,
4485 const struct mesh_setup *setup)
4486{
4487 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4488#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
4489 struct ieee80211_channel *chan = setup->chandef.chan;
4490#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 6, 0))
4491 struct ieee80211_channel *chan = setup->channel;
4492#endif
4493 u32 param[2] = {0, 0};
4494 s32 err = 0;
4495 u32 bw_cap = 0;
4496 u32 beacon_interval = setup->beacon_interval;
4497 u32 dtim_period = setup->dtim_period;
4498 size_t join_params_size;
4499 struct wl_join_params join_params;
4500 chanspec_t chanspec = 0;
4501
4502 cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
4503
4504 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
4505 struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
4506 u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
4507 u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
4508 if ((memcmp(setup->mesh_id, lssid->SSID, lssid->SSID_len) == 0) &&
4509 (*channel == cfg->channel)) {
4510 WL_ERR(("MESH connection already existed to " MACDBG "\n",
4511 MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
4512 return -EISCONN;
4513 }
4514 WL_ERR(("Previous connecton existed, please disconnect mesh %s (" MACDBG ") first\n",
4515 lssid->SSID, MAC2STRDBG(bssid)));
4516 return -EISCONN;
4517 }
4518
4519 if (chan) {
4520 if (chan->band == IEEE80211_BAND_5GHZ)
4521 param[0] = WLC_BAND_5G;
4522 else if (chan->band == IEEE80211_BAND_2GHZ)
4523 param[0] = WLC_BAND_2G;
4524 err = wldev_iovar_getint(dev, "bw_cap", param);
4525 if (unlikely(err)) {
4526 WL_ERR(("Get bw_cap Failed (%d)\n", err));
4527 return err;
4528 }
4529 bw_cap = param[0];
4530 chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap);
4531 }
4532
4533 memset(&join_params, 0, sizeof(join_params));
4534 memcpy((void *)join_params.ssid.SSID, (void *)setup->mesh_id,
4535 setup->mesh_id_len);
4536
4537 join_params.ssid.SSID_len = htod32(setup->mesh_id_len);
4538 join_params.params.chanspec_list[0] = chanspec;
4539 join_params.params.chanspec_num = 1;
4540 wldev_iovar_setint(dev, "chanspec", chanspec);
4541 join_params_size = sizeof(join_params);
4542
4543 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
4544 wldev_iovar_setint(dev, "wsec", 0);
4545
4546 if (cfg->sae_password_len > 0) {
4547 wldev_iovar_setint(dev, "mesh_auth_proto", 1);
4548 wldev_iovar_setint(dev, "wpa_auth", WPA2_AUTH_PSK);
4549 wldev_iovar_setint(dev, "wsec", AES_ENABLED);
4550 wldev_iovar_setint(dev, "mfp", WL_MFP_REQUIRED);
4551 printf("%s: password=%s, len=%d\n", __FUNCTION__,
4552 cfg->sae_password, cfg->sae_password_len);
4553 wldev_iovar_setbuf(dev, "sae_password", cfg->sae_password, cfg->sae_password_len,
4554 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
4555 } else {
4556 wldev_iovar_setint(dev, "mesh_auth_proto", 0);
4557 wldev_iovar_setint(dev, "mfp", WL_MFP_NONE);
4558 }
4559
4560 if (beacon_interval) {
4561 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
4562 &beacon_interval, sizeof(s32))) < 0) {
4563 WL_ERR(("Beacon Interval Set Error, %d\n", err));
4564 return err;
4565 }
4566 }
4567
4568 if (dtim_period) {
4569 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
4570 &dtim_period, sizeof(s32))) < 0) {
4571 WL_ERR(("DTIM Interval Set Error, %d\n", err));
4572 return err;
4573 }
4574 }
4575 wldev_iovar_setint(dev, "mpc", 0);
4576
4577 WL_ERR(("JOIN %s on channel %d with chanspec 0x%4x\n",
4578 join_params.ssid.SSID, cfg->channel, chanspec));
4579
4580 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
4581 join_params_size);
4582
4583 if (unlikely(err)) {
4584 WL_ERR(("Error (%d)\n", err));
4585 return err;
4586 }
4587
4588 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
4589 wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
4590 return err;
4591}
4592
4593
4594static s32 wl_cfg80211_leave_mesh(
4595 struct wiphy *wiphy, struct net_device *dev)
4596{
4597 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4598 s32 err = 0;
4599 scb_val_t scbval;
4600 u8 *curbssid;
4601
4602 RETURN_EIO_IF_NOT_UP(cfg);
4603 wl_link_down(cfg);
4604
4605 WL_ERR(("Leave MESH\n"));
4606 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
4607 wl_set_drv_status(cfg, DISCONNECTING, dev);
4608 scbval.val = 0;
4609 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
4610 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
4611 sizeof(scb_val_t));
4612 if (unlikely(err)) {
4613 wl_clr_drv_status(cfg, DISCONNECTING, dev);
4614 WL_ERR(("error(%d)\n", err));
4615 return err;
4616 }
4617 memset(cfg->sae_password, 0, SAE_MAX_PASSWD_LEN);
4618 cfg->sae_password_len = 0;
4619
4620 return err;
4621}
4622#endif /* WLMESH */
4623
010c3a89
RC
4624static s32
4625wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
4626 struct cfg80211_ibss_params *params)
4627{
4628 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4629 struct cfg80211_bss *bss;
4630 struct ieee80211_channel *chan;
4631 struct wl_join_params join_params;
4632 int scan_suppress;
4633 struct cfg80211_ssid ssid;
4634 s32 scan_retry = 0;
4635 s32 err = 0;
4636 size_t join_params_size;
4637 chanspec_t chanspec = 0;
4638 u32 param[2] = {0, 0};
4639 u32 bw_cap = 0;
4640
4641 WL_TRACE(("In\n"));
4642 RETURN_EIO_IF_NOT_UP(cfg);
4643 WL_INFORM(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
4644 if (!params->ssid || params->ssid_len <= 0 ||
4645 params->ssid_len > DOT11_MAX_SSID_LEN) {
4646 WL_ERR(("Invalid parameter\n"));
4647 return -EINVAL;
4648 }
4649#if defined(WL_CFG80211_P2P_DEV_IF)
4650 chan = params->chandef.chan;
4651#else
4652 chan = params->channel;
4653#endif /* WL_CFG80211_P2P_DEV_IF */
4654 if (chan)
4655 cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
4656 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
4657 struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
4658 u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
4659 u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
4660 if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
4661 (memcmp(params->ssid, lssid->SSID, lssid->SSID_len) == 0) &&
4662 (*channel == cfg->channel))) {
4663 WL_ERR(("Connection already existed to " MACDBG "\n",
4664 MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
4665 return -EISCONN;
4666 }
4667 WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n",
4668 lssid->SSID, MAC2STRDBG(bssid)));
4669 }
4670
4671 /* remove the VSIE */
4672 wl_cfg80211_ibss_vsie_delete(dev);
4673
4674 bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
4675 if (!bss) {
4676 if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
4677 memcpy(ssid.ssid, params->ssid, params->ssid_len);
4678 ssid.ssid_len = params->ssid_len;
4679 do {
4680 if (unlikely
4681 (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
4682 -EBUSY)) {
4683 wl_delay(150);
4684 } else {
4685 break;
4686 }
4687 } while (++scan_retry < WL_SCAN_RETRY_MAX);
4688
4689 /* rtnl lock code is removed here. don't see why rtnl lock
4690 * needs to be released.
4691 */
4692
4693 /* wait 4 secons till scan done.... */
4694 schedule_timeout_interruptible(msecs_to_jiffies(4000));
4695
4696 bss = cfg80211_get_ibss(wiphy, NULL,
4697 params->ssid, params->ssid_len);
4698 }
4699 }
4700 if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
4701 ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
4702 !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
4703 cfg->ibss_starter = false;
4704 WL_DBG(("Found IBSS\n"));
4705 } else {
4706 cfg->ibss_starter = true;
4707 }
4708
4709 if (bss) {
4710 CFG80211_PUT_BSS(wiphy, bss);
4711 }
4712
4713 if (chan) {
4714 if (chan->band == IEEE80211_BAND_5GHZ)
4715 param[0] = WLC_BAND_5G;
4716 else if (chan->band == IEEE80211_BAND_2GHZ)
4717 param[0] = WLC_BAND_2G;
4718 err = wldev_iovar_getint(dev, "bw_cap", param);
4719 if (unlikely(err)) {
4720 WL_ERR(("Get bw_cap Failed (%d)\n", err));
4721 return err;
4722 }
4723 bw_cap = param[0];
4724 chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap);
4725 }
4726 /*
4727 * Join with specific BSSID and cached SSID
4728 * If SSID is zero join based on BSSID only
4729 */
4730 memset(&join_params, 0, sizeof(join_params));
4731 memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
4732 params->ssid_len);
4733 join_params.ssid.SSID_len = htod32(params->ssid_len);
4734 if (params->bssid) {
4735 memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
4736 err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
4737 ETHER_ADDR_LEN);
4738 if (unlikely(err)) {
4739 WL_ERR(("Error (%d)\n", err));
4740 return err;
4741 }
4742 } else
4743 memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
4744
4745 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
4746 scan_suppress = TRUE;
4747 /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
4748 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
4749 &scan_suppress, sizeof(int));
4750 if (unlikely(err)) {
4751 WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
4752 return err;
4753 }
4754 }
4755
4756 join_params.params.chanspec_list[0] = chanspec;
4757 join_params.params.chanspec_num = 1;
4758 wldev_iovar_setint(dev, "chanspec", chanspec);
4759 join_params_size = sizeof(join_params);
4760
4761 /* Disable Authentication, IBSS will add key if it required */
4762 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
4763 wldev_iovar_setint(dev, "wsec", 0);
4764
4765 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
4766 join_params_size);
4767 if (unlikely(err)) {
4768 WL_ERR(("Error (%d)\n", err));
4769 return err;
4770 }
4771
4772 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
4773 scan_suppress = FALSE;
4774 /* Reset the SCAN SUPPRESS Flag */
4775 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
4776 &scan_suppress, sizeof(int));
4777 if (unlikely(err)) {
4778 WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
4779 return err;
4780 }
4781 }
4782 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
4783 wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
4784#ifdef WL_RELMCAST
4785 cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
4786#endif /* WL_RELMCAST */
4787 return err;
4788}
4789
4790static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
4791{
4792 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4793 s32 err = 0;
4794 scb_val_t scbval;
4795 u8 *curbssid;
4796
4797 RETURN_EIO_IF_NOT_UP(cfg);
4798 wl_link_down(cfg);
4799
4800 WL_ERR(("Leave IBSS\n"));
4801 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
4802 wl_set_drv_status(cfg, DISCONNECTING, dev);
4803 scbval.val = 0;
4804 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
4805 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
4806 sizeof(scb_val_t));
4807 if (unlikely(err)) {
4808 wl_clr_drv_status(cfg, DISCONNECTING, dev);
4809 WL_ERR(("error(%d)\n", err));
4810 return err;
4811 }
4812
4813 /* remove the VSIE */
4814 wl_cfg80211_ibss_vsie_delete(dev);
4815
4816 return err;
4817}
4818
4819#ifdef MFP
4820static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8** rsn_cap)
4821{
4822 u16 suite_count;
4823 wpa_suite_mcast_t *mcast;
4824 wpa_suite_ucast_t *ucast;
4825 u16 len;
4826 wpa_suite_auth_key_mgmt_t *mgmt;
4827
4828 if (!wpa2ie)
4829 return -1;
4830
4831 len = wpa2ie->len;
4832 mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
4833 if ((len -= WPA_SUITE_LEN) <= 0)
4834 return BCME_BADLEN;
4835 ucast = (wpa_suite_ucast_t *)&mcast[1];
4836 suite_count = ltoh16_ua(&ucast->count);
4837 if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
4838 (len -= (WPA_IE_SUITE_COUNT_LEN +
4839 (WPA_SUITE_LEN * suite_count))) <= 0)
4840 return BCME_BADLEN;
4841
4842 mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
4843 suite_count = ltoh16_ua(&mgmt->count);
4844
4845 if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
4846 (len -= (WPA_IE_SUITE_COUNT_LEN +
4847 (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
4848 rsn_cap[0] = (u8 *)&mgmt->list[suite_count];
4849 } else
4850 return BCME_BADLEN;
4851
4852 return 0;
4853}
4854#endif /* MFP */
4855
4856static s32
4857wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
4858{
4859 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4860 struct wl_security *sec;
4861 s32 val = 0;
4862 s32 err = 0;
4863 s32 bssidx;
4864
4865 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4866 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4867 return BCME_ERROR;
4868 }
4869
4870 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
4871 val = WPA_AUTH_PSK |
4872 WPA_AUTH_UNSPECIFIED;
4873 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
4874 val = WPA2_AUTH_PSK|
4875 WPA2_AUTH_UNSPECIFIED;
4876 else
4877 val = WPA_AUTH_DISABLED;
4878
4879 if (is_wps_conn(sme))
4880 val = WPA_AUTH_DISABLED;
4881
4882 WL_DBG(("setting wpa_auth to 0x%0x\n", val));
4883 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
4884 if (unlikely(err)) {
4885 WL_ERR(("set wpa_auth failed (%d)\n", err));
4886 return err;
4887 }
4888 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4889 sec->wpa_versions = sme->crypto.wpa_versions;
4890 return err;
4891}
4892
4893
4894static s32
4895wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
4896{
4897 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4898 struct wl_security *sec;
4899 s32 val = 0;
4900 s32 err = 0;
4901 s32 bssidx;
4902
4903 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4904 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4905 return BCME_ERROR;
4906 }
4907
4908 switch (sme->auth_type) {
4909 case NL80211_AUTHTYPE_OPEN_SYSTEM:
4910 val = WL_AUTH_OPEN_SYSTEM;
4911 WL_DBG(("open system\n"));
4912 break;
4913 case NL80211_AUTHTYPE_SHARED_KEY:
4914 val = WL_AUTH_SHARED_KEY;
4915 WL_DBG(("shared key\n"));
4916 break;
4917 case NL80211_AUTHTYPE_AUTOMATIC:
4918 val = WL_AUTH_OPEN_SHARED;
4919 WL_DBG(("automatic\n"));
4920 break;
4921 default:
4922 val = 2;
4923 WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
4924 break;
4925 }
4926
4927 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
4928 if (unlikely(err)) {
4929 WL_ERR(("set auth failed (%d)\n", err));
4930 return err;
4931 }
4932 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4933 sec->auth_type = sme->auth_type;
4934 return err;
4935}
4936
4937static s32
4938wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
4939{
4940 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4941 struct wl_security *sec;
4942 s32 pval = 0;
4943 s32 gval = 0;
4944 s32 err = 0;
4945 s32 wsec_val = 0;
4946 s32 bssidx;
4947
4948 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4949 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4950 return BCME_ERROR;
4951 }
4952
4953 if (sme->crypto.n_ciphers_pairwise) {
4954 switch (sme->crypto.ciphers_pairwise[0]) {
4955 case WLAN_CIPHER_SUITE_WEP40:
4956 case WLAN_CIPHER_SUITE_WEP104:
4957 pval = WEP_ENABLED;
4958 break;
4959 case WLAN_CIPHER_SUITE_TKIP:
4960 pval = TKIP_ENABLED;
4961 break;
4962 case WLAN_CIPHER_SUITE_CCMP:
4963 case WLAN_CIPHER_SUITE_AES_CMAC:
4964 pval = AES_ENABLED;
4965 break;
4966 default:
4967 WL_ERR(("invalid cipher pairwise (%d)\n",
4968 sme->crypto.ciphers_pairwise[0]));
4969 return -EINVAL;
4970 }
4971 }
4972 if (sme->crypto.cipher_group) {
4973 switch (sme->crypto.cipher_group) {
4974 case WLAN_CIPHER_SUITE_WEP40:
4975 case WLAN_CIPHER_SUITE_WEP104:
4976 gval = WEP_ENABLED;
4977 break;
4978 case WLAN_CIPHER_SUITE_TKIP:
4979 gval = TKIP_ENABLED;
4980 break;
4981 case WLAN_CIPHER_SUITE_CCMP:
4982 gval = AES_ENABLED;
4983 break;
4984 case WLAN_CIPHER_SUITE_AES_CMAC:
4985 gval = AES_ENABLED;
4986 break;
4987 default:
4988 WL_ERR(("invalid cipher group (%d)\n",
4989 sme->crypto.cipher_group));
4990 return -EINVAL;
4991 }
4992 }
4993
4994 WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
4995
4996 if (is_wps_conn(sme)) {
4997 if (sme->privacy)
4998 err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
4999 else
5000 /* WPS-2.0 allows no security */
5001 err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx);
5002 } else {
5003 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
5004 wsec_val = pval | gval;
5005
5006 WL_DBG((" Set WSEC to fW 0x%x \n", wsec_val));
5007 err = wldev_iovar_setint_bsscfg(dev, "wsec",
5008 wsec_val, bssidx);
5009 }
5010 if (unlikely(err)) {
5011 WL_ERR(("error (%d)\n", err));
5012 return err;
5013 }
5014
5015 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5016 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
5017 sec->cipher_group = sme->crypto.cipher_group;
5018
5019 return err;
5020}
5021
5022#ifdef MFP
5023static s32
5024wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
5025 struct net_device *dev,
5026 struct cfg80211_connect_params *sme)
5027{
5028 s32 mfp = WL_MFP_NONE;
5029 s32 current_mfp = WL_MFP_NONE;
5030 bcm_tlv_t *wpa2_ie;
5031 u8* rsn_cap = NULL;
5032 bool fw_support = false;
5033 int err, count = 0;
5034 u8 *eptr = NULL, *ptr = NULL;
5035 u8* group_mgmt_cs = NULL;
5036 wpa_pmkid_list_t* pmkid = NULL;
5037
5038 if (!sme) {
5039 /* No connection params from userspace, Do nothing. */
5040 return 0;
5041 }
5042
5043 /* Check fw support and retreive current mfp val */
5044 err = wldev_iovar_getint(dev, "mfp", &current_mfp);
5045 if (!err) {
5046 fw_support = true;
5047 }
5048
5049 /* Parse the wpa2ie to decode the MFP capablity */
5050 if (((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len,
5051 DOT11_MNG_RSN_ID)) != NULL) &&
5052 (wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0)) {
5053 /* Check for MFP cap in the RSN capability field */
5054 if (rsn_cap[0] & RSN_CAP_MFPR) {
5055 mfp = WL_MFP_REQUIRED;
5056 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
5057 mfp = WL_MFP_CAPABLE;
5058 }
5059
5060 /*
5061 * eptr --> end/last byte addr of wpa2_ie
5062 * ptr --> to keep track of current/required byte addr
5063 */
5064 eptr = (u8*)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN);
5065 /* pointing ptr to the next byte after rns_cap */
5066 ptr = (u8*)rsn_cap + RSN_CAP_LEN;
5067 if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) {
5068 /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
5069 pmkid = (wpa_pmkid_list_t*)ptr;
5070 count = pmkid->count.low | (pmkid->count.high << 8);
5071 /* ptr now to point to last byte addr of pmkid */
5072 ptr = (u8*)pmkid + (count * WPA2_PMKID_LEN
5073 + WPA2_PMKID_COUNT_LEN);
5074 if ((eptr - ptr) >= WPA_SUITE_LEN) {
5075 /* group_mgmt_cs now to point to first byte addr of bip */
5076 group_mgmt_cs = ptr;
5077 }
5078 }
5079 }
5080
5081 WL_DBG((" mfp:%d wpa2_ie ptr:%p rsn_cap 0x%x%x fw mfp support:%d\n",
5082 mfp, wpa2_ie, rsn_cap[0], rsn_cap[1], fw_support));
5083
5084 if (fw_support == false) {
dfb0f3ae 5085 if (mfp == WL_MFP_REQUIRED) {
010c3a89
RC
5086 /* if mfp > 0, mfp capability set in wpa ie, but
5087 * FW indicated error for mfp. Propagate the error up.
5088 */
dfb0f3ae 5089 WL_ERR(("mfp capability found in wpaie. But fw doesn't "
010c3a89
RC
5090 "seem to support MFP\n"));
5091 return -EINVAL;
5092 } else {
5093 /* Firmware doesn't support mfp. But since connection request
5094 * is for non-mfp case, don't bother.
5095 */
5096 return 0;
5097 }
5098 } else if (mfp != current_mfp) {
5099 err = wldev_iovar_setint(dev, "mfp", mfp);
5100 if (unlikely(err)) {
5101 WL_ERR(("mfp (%d) set failed ret:%d \n", mfp, err));
5102 return err;
5103 }
5104 WL_DBG(("mfp set to 0x%x \n", mfp));
5105 }
5106
5107 if (group_mgmt_cs && bcmp((const uint8 *)WPA2_OUI,
5108 group_mgmt_cs, (WPA_SUITE_LEN - 1)) == 0) {
5109 WL_DBG(("BIP is found\n"));
5110 err = wldev_iovar_setbuf(dev, "bip",
5111 group_mgmt_cs, WPA_SUITE_LEN, cfg->ioctl_buf,
5112 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5113 /*
5114 * Dont return failure for unsupported cases
5115 * of bip iovar for backward compatibility
5116 */
5117 if (err != BCME_UNSUPPORTED && err < 0) {
5118 WL_ERR(("bip set error (%d)\n", err));
5119 return err;
5120 }
5121 }
5122
5123 return 0;
5124}
5125#endif /* MFP */
5126
5127static s32
5128wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
5129{
5130 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5131 struct wl_security *sec;
5132 s32 val = 0;
5133 s32 err = 0;
5134 s32 bssidx;
5135
5136 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5137 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5138 return BCME_ERROR;
5139 }
5140
5141 if (sme->crypto.n_akm_suites) {
5142 err = wldev_iovar_getint(dev, "wpa_auth", &val);
5143 if (unlikely(err)) {
5144 WL_ERR(("could not get wpa_auth (%d)\n", err));
5145 return err;
5146 }
5147 if (val & (WPA_AUTH_PSK |
5148 WPA_AUTH_UNSPECIFIED)) {
5149 switch (sme->crypto.akm_suites[0]) {
5150 case WLAN_AKM_SUITE_8021X:
5151 val = WPA_AUTH_UNSPECIFIED;
5152 break;
5153 case WLAN_AKM_SUITE_PSK:
5154 val = WPA_AUTH_PSK;
5155 break;
5156 default:
5157 WL_ERR(("invalid akm suite (0x%x)\n",
5158 sme->crypto.akm_suites[0]));
5159 return -EINVAL;
5160 }
5161 } else if (val & (WPA2_AUTH_PSK |
5162 WPA2_AUTH_UNSPECIFIED)) {
5163 switch (sme->crypto.akm_suites[0]) {
5164 case WLAN_AKM_SUITE_8021X:
5165 val = WPA2_AUTH_UNSPECIFIED;
5166 break;
5167#ifdef MFP
5168#ifdef CUSTOMER_HW6
5169 case WL_AKM_SUITE_SHA256_1X:
5170 if (wl_customer6_legacy_chip_check(cfg, dev)) {
5171 val = WPA2_AUTH_UNSPECIFIED;
5172 } else {
5173 val = WPA2_AUTH_1X_SHA256;
5174 }
5175 break;
5176 case WL_AKM_SUITE_SHA256_PSK:
5177 if (wl_customer6_legacy_chip_check(cfg, dev)) {
5178 val = WPA2_AUTH_PSK;
5179 } else {
5180 val = WPA2_AUTH_PSK_SHA256;
5181 }
5182 break;
5183#else
5184 case WL_AKM_SUITE_SHA256_1X:
5185 val = WPA2_AUTH_1X_SHA256;
5186 break;
5187 case WL_AKM_SUITE_SHA256_PSK:
5188 val = WPA2_AUTH_PSK_SHA256;
5189 break;
5190#endif /* CUSTOMER_HW6 */
5191#endif /* MFP */
5192 case WLAN_AKM_SUITE_PSK:
5193 val = WPA2_AUTH_PSK;
5194 break;
5195 default:
5196 WL_ERR(("invalid akm suite (0x%x)\n",
5197 sme->crypto.akm_suites[0]));
5198 return -EINVAL;
5199 }
5200 }
5201
5202#ifdef MFP
5203 if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) {
5204 WL_ERR(("MFP set failed err:%d\n", err));
5205 return -EINVAL;
5206 }
5207#endif /* MFP */
5208
5209 WL_DBG(("setting wpa_auth to 0x%x\n", val));
5210 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
5211 if (unlikely(err)) {
5212 WL_ERR(("could not set wpa_auth (0x%x)\n", err));
5213 return err;
5214 }
5215 }
5216 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5217 sec->wpa_auth = sme->crypto.akm_suites[0];
5218
5219 return err;
5220}
5221
5222static s32
5223wl_set_set_sharedkey(struct net_device *dev,
5224 struct cfg80211_connect_params *sme)
5225{
5226 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5227 struct wl_security *sec;
5228 struct wl_wsec_key key;
5229 s32 val;
5230 s32 err = 0;
5231 s32 bssidx;
5232
5233 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5234 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5235 return BCME_ERROR;
5236 }
5237
5238 WL_DBG(("key len (%d)\n", sme->key_len));
5239 if (sme->key_len) {
5240 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5241 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
5242 sec->wpa_versions, sec->cipher_pairwise));
5243 if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
5244 NL80211_WPA_VERSION_2)) &&
5245 (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
5246 WLAN_CIPHER_SUITE_WEP104)))
5247 {
5248 memset(&key, 0, sizeof(key));
5249 key.len = (u32) sme->key_len;
5250 key.index = (u32) sme->key_idx;
5251 if (unlikely(key.len > sizeof(key.data))) {
5252 WL_ERR(("Too long key length (%u)\n", key.len));
5253 return -EINVAL;
5254 }
5255 memcpy(key.data, sme->key, key.len);
5256 key.flags = WL_PRIMARY_KEY;
5257 switch (sec->cipher_pairwise) {
5258 case WLAN_CIPHER_SUITE_WEP40:
5259 key.algo = CRYPTO_ALGO_WEP1;
5260 break;
5261 case WLAN_CIPHER_SUITE_WEP104:
5262 key.algo = CRYPTO_ALGO_WEP128;
5263 break;
5264 default:
5265 WL_ERR(("Invalid algorithm (%d)\n",
5266 sme->crypto.ciphers_pairwise[0]));
5267 return -EINVAL;
5268 }
5269 /* Set the new key/index */
5270 WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
5271 key.len, key.index, key.algo));
5272 WL_DBG(("key \"%s\"\n", key.data));
5273 swap_key_from_BE(&key);
5274 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
5275 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5276 if (unlikely(err)) {
5277 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
5278 return err;
5279 }
5280 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
5281 WL_DBG(("set auth_type to shared key\n"));
5282 val = WL_AUTH_SHARED_KEY; /* shared key */
5283 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
5284 if (unlikely(err)) {
5285 WL_ERR(("set auth failed (%d)\n", err));
5286 return err;
5287 }
5288 }
5289 }
5290 }
5291 return err;
5292}
5293
5294#if defined(ESCAN_RESULT_PATCH)
5295static u8 connect_req_bssid[6];
5296static u8 broad_bssid[6];
5297#endif /* ESCAN_RESULT_PATCH */
5298
5299
5300
5301#if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
5302static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
5303{
5304 u32 chanspec = 0;
5305 bool isvht80 = 0;
5306
5307 if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK)
5308 chanspec = wl_chspec_driver_to_host(chanspec);
5309
5310 isvht80 = chanspec & WL_CHANSPEC_BW_80;
5311 WL_INFORM(("%s: chanspec(%x:%d)\n", __FUNCTION__, chanspec, isvht80));
5312
5313 return isvht80;
5314}
5315#endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
5316
5317int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80211 *cfg,
5318 bool disassociate)
5319{
5320 scb_val_t scbval;
5321 int err = TRUE;
5322 int wait_cnt;
5323
5324 if (disassociate) {
5325 WL_ERR(("Disassociate previous connection!\n"));
5326 wl_set_drv_status(cfg, DISCONNECTING, dev);
5327 scbval.val = DOT11_RC_DISASSOC_LEAVING;
5328 scbval.val = htod32(scbval.val);
5329
5330 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
5331 sizeof(scb_val_t));
5332 if (unlikely(err)) {
5333 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5334 WL_ERR(("error (%d)\n", err));
5335 return err;
5336 }
5337 wait_cnt = 500/10;
5338 } else {
5339 wait_cnt = 200/10;
5340 WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
5341 if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
5342 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5343 }
5344 }
5345
5346 while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
5347 WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
5348 wait_cnt));
5349 wait_cnt--;
5350 OSL_SLEEP(10);
5351 }
5352
5353 if (wait_cnt == 0) {
5354 WL_ERR(("DISCONNECING clean up failed!\n"));
5355 return BCME_NOTREADY;
5356 }
5357 return BCME_OK;
5358}
5359
5360#define MAX_SCAN_ABORT_WAIT_CNT 20
5361#define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
5362
5363static s32
5364wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
5365 struct cfg80211_connect_params *sme)
5366{
5367 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5368 struct ieee80211_channel *chan = sme->channel;
5369 wl_extjoin_params_t *ext_join_params;
5370 struct wl_join_params join_params;
5371 size_t join_params_size;
5372 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
5373 s32 err = 0;
5374 wpa_ie_fixed_t *wpa_ie;
5375 bcm_tlv_t *wpa2_ie;
5376 u8* wpaie = 0;
5377 u32 wpaie_len = 0;
5378 u32 chan_cnt = 0;
5379 struct ether_addr bssid;
5380 s32 bssidx = -1;
5381#if (defined(BCM4359_CHIP) || !defined(ESCAN_RESULT_PATCH))
5382 int wait_cnt;
5383#endif
5384
5385 WL_DBG(("In\n"));
5386 BCM_REFERENCE(dhdp);
5387
dfb0f3ae
RC
5388#ifdef WLMESH
5389 wl_config_ifmode(cfg, dev, dev->ieee80211_ptr->iftype);
5390#endif
010c3a89
RC
5391#if defined(SUPPORT_RANDOM_MAC_SCAN)
5392 wl_cfg80211_set_random_mac(dev, FALSE);
5393#endif /* SUPPORT_RANDOM_MAC_SCAN */
5394
5395#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
5396 if (sme->channel_hint) {
5397 chan = sme->channel_hint;
5398 WL_DBG(("channel_hint (%d), channel_hint center_freq (%d)\n",
5399 ieee80211_frequency_to_channel(sme->channel_hint->center_freq),
5400 sme->channel_hint->center_freq));
5401 }
5402 if (sme->bssid_hint) {
5403 sme->bssid = sme->bssid_hint;
5404 WL_DBG(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
5405 }
5406#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
5407
5408 if (unlikely(!sme->ssid)) {
5409 WL_ERR(("Invalid ssid\n"));
5410 return -EOPNOTSUPP;
5411 }
5412
5413 if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) {
5414 WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n",
5415 sme->ssid, sme->ssid_len));
5416 return -EINVAL;
5417 }
5418
5419 WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
5420 if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
5421 prhex(NULL, (uchar *)sme->ie, sme->ie_len);
5422 }
5423
5424 RETURN_EIO_IF_NOT_UP(cfg);
5425
5426 /*
5427 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
5428 */
5429#if (defined(BCM4359_CHIP) || !defined(ESCAN_RESULT_PATCH))
5430 if (cfg->scan_request) {
5431 WL_TRACE_HW4(("Aborting the scan! \n"));
5432 wl_cfg80211_scan_abort(cfg);
5433 wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
5434 while (wl_get_drv_status(cfg, SCANNING, dev) && wait_cnt) {
5435 WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
5436 wait_cnt--;
5437 OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
5438 }
5439 if (wl_get_drv_status(cfg, SCANNING, dev)) {
5440 wl_notify_escan_complete(cfg, dev, true, true);
5441 }
5442 }
5443#endif
5444#ifdef WL_SCHED_SCAN
5445 /* Locks are taken in wl_cfg80211_sched_scan_stop()
5446 * A start scan occuring during connect is unlikely
5447 */
5448 if (cfg->sched_scan_req) {
dfb0f3ae
RC
5449#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
5450 wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg), 0);
5451#else
010c3a89 5452 wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg));
dfb0f3ae 5453#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
010c3a89
RC
5454 }
5455#endif
5456#if defined(ESCAN_RESULT_PATCH)
5457 if (sme->bssid)
5458 memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN);
5459 else
5460 bzero(connect_req_bssid, ETHER_ADDR_LEN);
5461 bzero(broad_bssid, ETHER_ADDR_LEN);
5462#endif
5463#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
5464 maxrxpktglom = 0;
5465#endif
5466 if (wl_get_drv_status(cfg, CONNECTING, dev) || wl_get_drv_status(cfg, CONNECTED, dev)) {
5467 /* set nested connect bit to identify the context */
5468 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
5469 /* DHD prev status is CONNECTING/CONNECTED */
5470 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
5471 } else if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
5472 /* DHD prev status is DISCONNECTING */
5473 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, FALSE);
5474 } else if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
5475 /* DHD previous status is not connected and FW connected */
5476 if (wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) == 0) {
5477 /* set nested connect bit to identify the context */
5478 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
5479 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
5480 }
5481 }
5482
5483 /* 'connect' request received */
5484 wl_set_drv_status(cfg, CONNECTING, dev);
5485 /* clear nested connect bit on proceeding for connection */
5486 wl_clr_drv_status(cfg, NESTED_CONNECT, dev);
5487
5488 /* Clean BSSID */
5489 bzero(&bssid, sizeof(bssid));
5490 if (!wl_get_drv_status(cfg, DISCONNECTING, dev))
5491 wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
5492
5493 if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) {
5494 /* we only allow to connect using virtual interface in case of P2P */
5495 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5496 WL_ERR(("Find p2p index from wdev(%p) failed\n",
5497 dev->ieee80211_ptr));
5498 err = BCME_ERROR;
5499 goto exit;
5500 }
5501 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
5502 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
5503 } else if (dev == bcmcfg_to_prmry_ndev(cfg)) {
5504 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5505 WL_ERR(("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr));
5506 err = BCME_ERROR;
5507 goto exit;
5508 }
5509
5510 /* find the RSN_IE */
5511 if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len,
5512 DOT11_MNG_RSN_ID)) != NULL) {
5513 WL_DBG((" WPA2 IE is found\n"));
5514 }
5515 /* find the WPA_IE */
5516 if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie,
5517 sme->ie_len)) != NULL) {
5518 WL_DBG((" WPA IE is found\n"));
5519 }
5520 if (wpa_ie != NULL || wpa2_ie != NULL) {
5521 wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie;
5522 wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
5523 wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
5524 err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
5525 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
5526 if (unlikely(err)) {
5527 WL_ERR(("wpaie set error (%d)\n", err));
5528 goto exit;
5529 }
5530 } else {
5531 err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
5532 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
5533 if (unlikely(err)) {
5534 WL_ERR(("wpaie set error (%d)\n", err));
5535 goto exit;
5536 }
5537 }
5538 err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
5539 VNDR_IE_ASSOCREQ_FLAG, (const u8 *)sme->ie, sme->ie_len);
5540 if (unlikely(err)) {
5541 goto exit;
5542 }
5543 }
5544
5545 if (chan) {
5546 cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
5547 chan_cnt = 1;
5548 WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel,
5549 chan->center_freq, chan_cnt));
5550 } else {
5551 WL_DBG(("No channel info from user space\n"));
5552 cfg->channel = 0;
5553 }
5554
5555
5556 WL_DBG(("3. set wpa version \n"));
5557
5558 err = wl_set_wpa_version(dev, sme);
5559 if (unlikely(err)) {
5560 WL_ERR(("Invalid wpa_version\n"));
5561 goto exit;
5562 }
5563 err = wl_set_auth_type(dev, sme);
5564 if (unlikely(err)) {
5565 WL_ERR(("Invalid auth type\n"));
5566 goto exit;
5567 }
5568
5569 err = wl_set_set_cipher(dev, sme);
5570 if (unlikely(err)) {
5571 WL_ERR(("Invalid ciper\n"));
5572 goto exit;
5573 }
5574
5575 err = wl_set_key_mgmt(dev, sme);
5576 if (unlikely(err)) {
5577 WL_ERR(("Invalid key mgmt\n"));
5578 goto exit;
5579 }
5580
5581 err = wl_set_set_sharedkey(dev, sme);
5582 if (unlikely(err)) {
5583 WL_ERR(("Invalid shared key\n"));
5584 goto exit;
5585 }
5586
5587 /*
5588 * Join with specific BSSID and cached SSID
5589 * If SSID is zero join based on BSSID only
5590 */
5591 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
5592 chan_cnt * sizeof(chanspec_t);
5593 ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
5594 if (ext_join_params == NULL) {
5595 err = -ENOMEM;
5596 wl_clr_drv_status(cfg, CONNECTING, dev);
5597 goto exit;
5598 }
5599 ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
5600 memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
5601 wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
5602 ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
5603 /* increate dwell time to receive probe response or detect Beacon
5604 * from target AP at a noisy air only during connect command
5605 */
5606 ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
5607 ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
5608 /* Set up join scan parameters */
5609 ext_join_params->scan.scan_type = -1;
5610 ext_join_params->scan.nprobes = chan_cnt ?
5611 (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
5612 ext_join_params->scan.home_time = -1;
5613
5614 if (sme->bssid)
5615 memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
5616 else
5617 memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
5618 ext_join_params->assoc.chanspec_num = chan_cnt;
5619 if (chan_cnt) {
5620 if (cfg->channel) {
5621 /*
5622 * Use the channel provided by userspace
5623 */
5624 u16 channel, band, bw, ctl_sb;
5625 chanspec_t chspec;
5626 channel = cfg->channel;
5627 band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
5628 : WL_CHANSPEC_BAND_5G;
5629
5630 /* Get min_bw set for the interface */
5631 bw = wl_cfg80211_ulb_get_min_bw_chspec(cfg, dev->ieee80211_ptr, bssidx);
5632 if (bw == INVCHANSPEC) {
5633 WL_ERR(("Invalid chanspec \n"));
5634 kfree(ext_join_params);
5635 err = BCME_ERROR;
5636 goto exit;
5637 }
5638
5639 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
5640 chspec = (channel | band | bw | ctl_sb);
5641 ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
5642 ext_join_params->assoc.chanspec_list[0] |= chspec;
5643 ext_join_params->assoc.chanspec_list[0] =
5644 wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]);
5645 }
5646 }
5647 ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
5648 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
5649 WL_INFORM(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
5650 ext_join_params->ssid.SSID_len));
5651 }
5652
5653 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5654 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5655 kfree(ext_join_params);
5656 err = BCME_ERROR;
5657 goto exit;
5658 }
5659#if defined(CUSTOMER_HW2)
5660 DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
5661#endif /* BCMDONGLEHOST && CUSTOMER_HW2 */
5662#ifdef WL_EXT_IAPSTA
d964ce36 5663 wl_ext_iapsta_update_channel(dev, cfg->channel);
010c3a89
RC
5664#endif
5665 err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
5666 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5667
5668 if (cfg->rcc_enabled) {
5669 printf("Connecting with " MACDBG " ssid \"%s\", len (%d) with rcc channels \n\n",
5670 MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
5671 ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len);
5672 } else {
5673 printf("Connecting with " MACDBG " ssid \"%s\", len (%d) channel=%d\n\n",
5674 MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
5675 ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, cfg->channel);
5676 }
5677
5678 kfree(ext_join_params);
5679 if (err) {
5680 wl_clr_drv_status(cfg, CONNECTING, dev);
5681 if (err == BCME_UNSUPPORTED) {
5682 WL_DBG(("join iovar is not supported\n"));
5683 goto set_ssid;
5684 } else {
5685 WL_ERR(("error (%d)\n", err));
5686 goto exit;
5687 }
5688 } else
5689 goto exit;
5690
5691set_ssid:
5692 memset(&join_params, 0, sizeof(join_params));
5693 join_params_size = sizeof(join_params.ssid);
5694
5695 join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
5696 memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
5697 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
5698 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
5699 if (sme->bssid)
5700 memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
5701 else
5702 memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
5703
5704 if (wl_ch_to_chanspec(dev, cfg->channel, &join_params, &join_params_size) < 0) {
5705 WL_ERR(("Invalid chanspec\n"));
5706 return -EINVAL;
5707 }
5708
5709 WL_DBG(("join_param_size %zu\n", join_params_size));
5710
5711 if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
5712 WL_INFORM(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
5713 join_params.ssid.SSID_len));
5714 }
5715 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, join_params_size);
5716exit:
5717 if (err) {
5718 WL_ERR(("error (%d)\n", err));
5719 wl_clr_drv_status(cfg, CONNECTING, dev);
5720 }
d964ce36 5721 if (!err)
32c27b7a
RC
5722 wl_cfg80211_check_in4way(cfg, dev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
5723 WL_EXT_STATUS_CONNECTING, NULL);
010c3a89
RC
5724
5725#ifdef WLTDLS
5726 /* disable TDLS if number of connected interfaces is >= 1 */
5727 wl_cfg80211_tdls_config(cfg, TDLS_STATE_CONNECT, false);
5728#endif /* WLTDLS */
5729
5730#ifdef DBG_PKT_MON
5731 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && !err) {
5732 DHD_DBG_PKT_MON_START(dhdp);
5733 }
5734#endif /* DBG_PKT_MON */
5735 return err;
5736}
5737
5738#define WAIT_FOR_DISCONNECT_MAX 10
5739static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev)
5740{
5741 uint8 wait_cnt;
5742
5743 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
5744 while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
5745 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
5746 wait_cnt--;
5747 OSL_SLEEP(50);
5748 }
5749
5750 return;
5751}
5752
5753static s32
5754wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
5755 u16 reason_code)
5756{
5757 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5758 scb_val_t scbval;
5759 bool act = false;
5760 s32 err = 0;
5761 u8 *curbssid;
5762 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
5763 WL_ERR(("Reason %d\n", reason_code));
5764 RETURN_EIO_IF_NOT_UP(cfg);
5765 act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
5766 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
5767
5768 BCM_REFERENCE(dhdp);
5769
5770#ifdef ESCAN_RESULT_PATCH
5771 if (wl_get_drv_status(cfg, CONNECTING, dev) && curbssid &&
5772 (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0)) {
5773 WL_ERR(("Disconnecting from connecting device: " MACDBG "\n",
5774 MAC2STRDBG(curbssid)));
5775 act = true;
5776 }
5777#endif /* ESCAN_RESULT_PATCH */
5778
5779 if (act) {
5780#ifdef DBG_PKT_MON
5781 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
5782 DHD_DBG_PKT_MON_STOP(dhdp);
5783 }
5784#endif /* DBG_PKT_MON */
5785 /*
5786 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
5787 */
5788#if !defined(ESCAN_RESULT_PATCH)
5789 /* Let scan aborted by F/W */
5790 if (cfg->scan_request) {
5791 WL_TRACE_HW4(("Aborting the scan! \n"));
5792 wl_notify_escan_complete(cfg, dev, true, true);
5793 }
5794#endif /* ESCAN_RESULT_PATCH */
5795 if (wl_get_drv_status(cfg, CONNECTING, dev) ||
5796 wl_get_drv_status(cfg, CONNECTED, dev)) {
5797 wl_set_drv_status(cfg, DISCONNECTING, dev);
5798 scbval.val = reason_code;
5799 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
5800 scbval.val = htod32(scbval.val);
5801 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
5802 sizeof(scb_val_t));
5803 if (unlikely(err)) {
5804 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5805 WL_ERR(("error (%d)\n", err));
5806 return err;
5807 }
5808 wl_cfg80211_wait_for_disconnection(cfg, dev);
5809 }
5810 }
5811#ifdef CUSTOM_SET_CPUCORE
5812 /* set default cpucore */
5813 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
5814 dhdp->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
5815 if (!(dhdp->chan_isvht80))
5816 dhd_set_cpucore(dhdp, FALSE);
5817 }
5818#endif /* CUSTOM_SET_CPUCORE */
5819
5820 return err;
5821}
5822
5823static s32
5824#if defined(WL_CFG80211_P2P_DEV_IF)
5825wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
5826 enum nl80211_tx_power_setting type, s32 mbm)
5827#else
5828wl_cfg80211_set_tx_power(struct wiphy *wiphy,
5829 enum nl80211_tx_power_setting type, s32 dbm)
5830#endif /* WL_CFG80211_P2P_DEV_IF */
5831{
5832
5833 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5834 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
5835 s32 err = 0;
5836#if defined(WL_CFG80211_P2P_DEV_IF)
5837 s32 dbm = MBM_TO_DBM(mbm);
5838#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
5839 defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
5840 dbm = MBM_TO_DBM(dbm);
5841#endif /* WL_CFG80211_P2P_DEV_IF */
5842
5843 RETURN_EIO_IF_NOT_UP(cfg);
5844 switch (type) {
5845 case NL80211_TX_POWER_AUTOMATIC:
5846 break;
5847 case NL80211_TX_POWER_LIMITED:
5848 if (dbm < 0) {
5849 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
5850 return -EINVAL;
5851 }
5852 break;
5853 case NL80211_TX_POWER_FIXED:
5854 if (dbm < 0) {
5855 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
5856 return -EINVAL;
5857 }
5858 break;
5859 }
5860
5861 err = wl_set_tx_power(ndev, type, dbm);
5862 if (unlikely(err)) {
5863 WL_ERR(("error (%d)\n", err));
5864 return err;
5865 }
5866
5867 cfg->conf->tx_power = dbm;
5868
5869 return err;
5870}
5871
5872static s32
5873#if defined(WL_CFG80211_P2P_DEV_IF)
5874wl_cfg80211_get_tx_power(struct wiphy *wiphy,
5875 struct wireless_dev *wdev, s32 *dbm)
5876#else
5877wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
5878#endif /* WL_CFG80211_P2P_DEV_IF */
5879{
5880 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5881 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
5882 s32 err = 0;
5883
5884 RETURN_EIO_IF_NOT_UP(cfg);
5885 err = wl_get_tx_power(ndev, dbm);
5886 if (unlikely(err))
5887 WL_ERR(("error (%d)\n", err));
5888
5889 return err;
5890}
5891
5892static s32
5893wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
5894 u8 key_idx, bool unicast, bool multicast)
5895{
5896 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5897 u32 index;
5898 s32 wsec;
5899 s32 err = 0;
5900 s32 bssidx;
5901
5902 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5903 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
5904 return BCME_ERROR;
5905 }
5906
5907 WL_DBG(("key index (%d)\n", key_idx));
5908 RETURN_EIO_IF_NOT_UP(cfg);
5909 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
5910 if (unlikely(err)) {
5911 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
5912 return err;
5913 }
5914 if (wsec == WEP_ENABLED) {
5915 /* Just select a new current key */
5916 index = (u32) key_idx;
5917 index = htod32(index);
5918 err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index,
5919 sizeof(index));
5920 if (unlikely(err)) {
5921 WL_ERR(("error (%d)\n", err));
5922 }
5923 }
5924 return err;
5925}
5926
5927static s32
5928wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
5929 u8 key_idx, const u8 *mac_addr, struct key_params *params)
5930{
5931 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5932 struct wl_wsec_key key;
5933 s32 err = 0;
5934 s32 bssidx;
5935 s32 mode = wl_get_mode_by_netdev(cfg, dev);
5936
5937 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5938 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5939 return BCME_ERROR;
5940 }
5941 memset(&key, 0, sizeof(key));
5942 key.index = (u32) key_idx;
5943
5944 if (!ETHER_ISMULTI(mac_addr))
5945 memcpy((char *)&key.ea, (const void *)mac_addr, ETHER_ADDR_LEN);
5946 key.len = (u32) params->key_len;
5947
5948 /* check for key index change */
5949 if (key.len == 0) {
5950 /* key delete */
5951 swap_key_from_BE(&key);
5952 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
5953 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5954 if (unlikely(err)) {
5955 WL_ERR(("key delete error (%d)\n", err));
5956 return err;
5957 }
5958 } else {
5959 if (key.len > sizeof(key.data)) {
5960 WL_ERR(("Invalid key length (%d)\n", key.len));
5961 return -EINVAL;
5962 }
5963 WL_DBG(("Setting the key index %d\n", key.index));
5964 memcpy(key.data, params->key, key.len);
5965
5966 if ((mode == WL_MODE_BSS) &&
5967 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
5968 u8 keybuf[8];
5969 memcpy(keybuf, &key.data[24], sizeof(keybuf));
5970 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
5971 memcpy(&key.data[16], keybuf, sizeof(keybuf));
5972 }
5973
5974 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
5975 if (params->seq && params->seq_len == 6) {
5976 /* rx iv */
5977 u8 *ivptr;
5978 ivptr = (u8 *) params->seq;
5979 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
5980 (ivptr[3] << 8) | ivptr[2];
5981 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
5982 key.iv_initialized = true;
5983 }
5984
5985 switch (params->cipher) {
5986 case WLAN_CIPHER_SUITE_WEP40:
5987 key.algo = CRYPTO_ALGO_WEP1;
5988 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
5989 break;
5990 case WLAN_CIPHER_SUITE_WEP104:
5991 key.algo = CRYPTO_ALGO_WEP128;
5992 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
5993 break;
5994 case WLAN_CIPHER_SUITE_TKIP:
5995 key.algo = CRYPTO_ALGO_TKIP;
5996 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
5997 break;
5998 case WLAN_CIPHER_SUITE_AES_CMAC:
5999 key.algo = CRYPTO_ALGO_AES_CCM;
6000 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
6001 break;
6002 case WLAN_CIPHER_SUITE_CCMP:
6003 key.algo = CRYPTO_ALGO_AES_CCM;
6004 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
6005 break;
6006 default:
6007 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
6008 return -EINVAL;
6009 }
6010 swap_key_from_BE(&key);
6011 /* need to guarantee EAPOL 4/4 send out before set key */
6012 dhd_wait_pend8021x(dev);
6013 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6014 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6015 if (unlikely(err)) {
6016 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6017 return err;
6018 }
6019 }
6020 return err;
6021}
6022
6023int
6024wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
6025{
6026 int err;
6027 wl_eventmsg_buf_t ev_buf;
6028 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6029
6030 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
6031 /* roam offload is only for the primary device */
6032 return -1;
6033 }
6034 err = wldev_iovar_setint(dev, "roam_offload", enable);
6035 if (err)
6036 return err;
6037
6038 bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
6039 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
6040 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
6041 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
6042 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
6043 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
6044 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
6045 err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
6046 if (!err) {
6047 cfg->roam_offload = enable;
6048 }
6049 return err;
6050}
6051
6052#if defined(WL_VIRTUAL_APSTA)
6053int
6054wl_cfg80211_interface_create(struct net_device *dev, char *name)
6055{
6056 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6057 bcm_struct_cfgdev *new_cfgdev;
dfb0f3ae
RC
6058 char ifname[IFNAMSIZ];
6059 char iftype[IFNAMSIZ];
6060 enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION;
6061
6062 sscanf(name, "%s %s", ifname, iftype);
6063
6064 if (strnicmp(iftype, "AP", strlen("AP")) == 0) {
6065 iface_type = NL80211_IFTYPE_AP;
6066 }
010c3a89
RC
6067
6068 new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
dfb0f3ae 6069 iface_type, NULL, ifname);
010c3a89
RC
6070 if (!new_cfgdev) {
6071 return BCME_ERROR;
6072 }
6073 else {
6074 WL_DBG(("Iface %s created successfuly\n", name));
6075 return BCME_OK;
6076 }
6077}
6078
6079int
6080wl_cfg80211_interface_delete(struct net_device *dev, char *name)
6081{
6082 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6083 struct net_info *iter, *next;
6084 int err = BCME_ERROR;
6085
6086 if (name == NULL) {
6087 return BCME_ERROR;
6088 }
6089
6090#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
6091#pragma GCC diagnostic push
6092#pragma GCC diagnostic ignored "-Wcast-qual"
6093#endif
6094 for_each_ndev(cfg, iter, next) {
6095 if (iter->ndev) {
6096 if (strcmp(iter->ndev->name, name) == 0) {
6097 err = wl_cfg80211_del_iface(cfg->wdev->wiphy,
6098 ndev_to_cfgdev(iter->ndev));
6099 break;
6100 }
6101 }
6102 }
6103#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
6104#pragma GCC diagnostic pop
6105#endif
6106 if (!err) {
6107 WL_DBG(("Iface %s deleted successfuly", name));
6108 }
6109 return err;
6110}
6111
6112#if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
6113void
6114wl_cfg80211_block_arp(struct net_device *dev, int enable)
6115{
6116 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6117 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6118
6119 if (!dhd_pkt_filter_enable) {
6120 WL_INFORM(("Packet filter isn't enabled\n"));
6121 return;
6122 }
6123
6124 /* Block/Unblock ARP frames only if STA is connected to
6125 * the upstream AP in case of STA+SoftAP Concurrenct mode
6126 */
6127 if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6128 WL_INFORM(("STA doesn't connected to upstream AP\n"));
6129 return;
6130 }
6131
6132 if (enable) {
6133 WL_DBG(("Enable ARP Filter\n"));
6134 /* Add ARP filter */
6135 dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
6136
6137 /* Enable ARP packet filter - blacklist */
6138 dhd_master_mode = FALSE;
6139 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
6140 TRUE, dhd_master_mode);
6141 } else {
6142 WL_DBG(("Disable ARP Filter\n"));
6143 /* Disable ARP packet filter */
6144 dhd_master_mode = TRUE;
6145 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
6146 FALSE, dhd_master_mode);
6147
6148 /* Delete ARP filter */
6149 dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
6150 }
6151}
6152#endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
6153#endif /* defined (WL_VIRTUAL_APSTA) */
6154
6155static s32
6156wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
6157 u8 key_idx, bool pairwise, const u8 *mac_addr,
6158 struct key_params *params)
6159{
6160 struct wl_wsec_key key;
6161 s32 val = 0;
6162 s32 wsec = 0;
6163 s32 err = 0;
6164 u8 keybuf[8];
6165 s32 bssidx = 0;
6166 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6167 s32 mode = wl_get_mode_by_netdev(cfg, dev);
d964ce36 6168
010c3a89
RC
6169 WL_DBG(("key index (%d)\n", key_idx));
6170 RETURN_EIO_IF_NOT_UP(cfg);
6171
6172 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6173 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
6174 return BCME_ERROR;
6175 }
32c27b7a
RC
6176 wl_cfg80211_check_in4way(cfg, dev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
6177 WL_EXT_STATUS_4WAY_DONE, NULL);
010c3a89
RC
6178
6179 if (mac_addr &&
6180 ((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
6181 (params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
6182 wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
6183 goto exit;
6184 }
6185 memset(&key, 0, sizeof(key));
6186 /* Clear any buffered wep key */
6187 memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
6188
6189 key.len = (u32) params->key_len;
6190 key.index = (u32) key_idx;
6191
6192 if (unlikely(key.len > sizeof(key.data))) {
6193 WL_ERR(("Too long key length (%u)\n", key.len));
6194 return -EINVAL;
6195 }
6196 memcpy(key.data, params->key, key.len);
6197
6198 key.flags = WL_PRIMARY_KEY;
6199 switch (params->cipher) {
6200 case WLAN_CIPHER_SUITE_WEP40:
6201 key.algo = CRYPTO_ALGO_WEP1;
6202 val = WEP_ENABLED;
6203 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
6204 break;
6205 case WLAN_CIPHER_SUITE_WEP104:
6206 key.algo = CRYPTO_ALGO_WEP128;
6207 val = WEP_ENABLED;
6208 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
6209 break;
6210 case WLAN_CIPHER_SUITE_TKIP:
6211 key.algo = CRYPTO_ALGO_TKIP;
6212 val = TKIP_ENABLED;
6213 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
6214 if (mode == WL_MODE_BSS) {
6215 bcopy(&key.data[24], keybuf, sizeof(keybuf));
6216 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
6217 bcopy(keybuf, &key.data[16], sizeof(keybuf));
6218 }
6219 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
6220 break;
6221 case WLAN_CIPHER_SUITE_AES_CMAC:
6222 key.algo = CRYPTO_ALGO_AES_CCM;
6223 val = AES_ENABLED;
6224 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
6225 break;
6226 case WLAN_CIPHER_SUITE_CCMP:
6227 key.algo = CRYPTO_ALGO_AES_CCM;
6228 val = AES_ENABLED;
6229 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
6230 break;
6231 default:
6232 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
6233 return -EINVAL;
6234 }
6235
6236 /* Set the new key/index */
6237 if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
6238 WL_ERR(("IBSS KEY setted\n"));
6239 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
6240 }
6241 swap_key_from_BE(&key);
6242 if ((params->cipher == WLAN_CIPHER_SUITE_WEP40) ||
6243 (params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
6244 /*
6245 * For AP role, since we are doing a wl down before bringing up AP,
6246 * the plumbed keys will be lost. So for AP once we bring up AP, we
6247 * need to plumb keys again. So buffer the keys for future use. This
6248 * is more like a WAR. If firmware later has the capability to do
6249 * interface upgrade without doing a "wl down" and "wl apsta 0", then
6250 * this will not be required.
6251 */
6252 WL_DBG(("Buffering WEP Keys \n"));
6253 memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key));
6254 }
6255 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
6256 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6257 if (unlikely(err)) {
6258 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6259 return err;
6260 }
6261
6262exit:
6263 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
6264 if (unlikely(err)) {
6265 WL_ERR(("get wsec error (%d)\n", err));
6266 return err;
6267 }
6268
6269 wsec |= val;
6270 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
6271 if (unlikely(err)) {
6272 WL_ERR(("set wsec error (%d)\n", err));
6273 return err;
6274 }
6275
6276 return err;
6277}
6278
6279static s32
6280wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
6281 u8 key_idx, bool pairwise, const u8 *mac_addr)
6282{
6283 struct wl_wsec_key key;
6284 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6285 s32 err = 0;
6286 s32 bssidx;
6287
6288 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6289 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6290 return BCME_ERROR;
6291 }
6292 WL_DBG(("Enter\n"));
6293
6294#ifndef MFP
6295 if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
6296 return -EINVAL;
6297#endif
6298
6299 RETURN_EIO_IF_NOT_UP(cfg);
6300 memset(&key, 0, sizeof(key));
6301
6302 key.flags = WL_PRIMARY_KEY;
6303 key.algo = CRYPTO_ALGO_OFF;
6304 key.index = (u32) key_idx;
6305
6306 WL_DBG(("key index (%d)\n", key_idx));
6307 /* Set the new key/index */
6308 swap_key_from_BE(&key);
6309 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
6310 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6311 if (unlikely(err)) {
6312 if (err == -EINVAL) {
6313 if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
6314 /* we ignore this key index in this case */
6315 WL_DBG(("invalid key index (%d)\n", key_idx));
6316 }
6317 } else {
6318 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6319 }
6320 return err;
6321 }
6322 return err;
6323}
6324
6325static s32
6326wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
6327 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
6328 void (*callback) (void *cookie, struct key_params * params))
6329{
6330 struct key_params params;
6331 struct wl_wsec_key key;
6332 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6333 struct wl_security *sec;
6334 s32 wsec;
6335 s32 err = 0;
6336 s32 bssidx;
6337
6338 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6339 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6340 return BCME_ERROR;
6341 }
6342 WL_DBG(("key index (%d)\n", key_idx));
6343 RETURN_EIO_IF_NOT_UP(cfg);
6344 memset(&key, 0, sizeof(key));
6345 key.index = key_idx;
6346 swap_key_to_BE(&key);
6347 memset(&params, 0, sizeof(params));
6348 params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
6349 memcpy((void *)params.key, key.data, params.key_len);
6350
6351 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
6352 if (unlikely(err)) {
6353 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
6354 return err;
6355 }
6356 switch (WSEC_ENABLED(wsec)) {
6357 case WEP_ENABLED:
6358 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6359 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
6360 params.cipher = WLAN_CIPHER_SUITE_WEP40;
6361 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
6362 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
6363 params.cipher = WLAN_CIPHER_SUITE_WEP104;
6364 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
6365 }
6366 break;
6367 case TKIP_ENABLED:
6368 params.cipher = WLAN_CIPHER_SUITE_TKIP;
6369 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
6370 break;
6371 case AES_ENABLED:
6372 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
6373 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
6374 break;
6375#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
6376 /* to connect to mixed mode AP */
6377 case (AES_ENABLED | TKIP_ENABLED): /* TKIP CCMP */
6378 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
6379 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
6380 break;
6381#endif
6382 default:
6383 WL_ERR(("Invalid algo (0x%x)\n", wsec));
6384 return -EINVAL;
6385 }
6386
6387 callback(cookie, &params);
6388 return err;
6389}
6390
6391static s32
6392wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
6393 struct net_device *dev, u8 key_idx)
6394{
6395#ifdef MFP
6396 return 0;
6397#else
6398 WL_INFORM(("Not supported\n"));
6399 return -EOPNOTSUPP;
6400#endif /* MFP */
6401}
6402
010c3a89
RC
6403static s32
6404#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
6405wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
6406 const u8 *mac, struct station_info *sinfo)
6407#else
6408wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
6409 u8 *mac, struct station_info *sinfo)
6410#endif
6411{
6412 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6413 scb_val_t scb_val;
6414 s32 rssi;
6415 s32 rate;
6416 s32 err = 0;
6417 sta_info_t *sta;
6418#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
6419 s8 eabuf[ETHER_ADDR_STR_LEN];
6420#endif
6421 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
6422 bool fw_assoc_state = FALSE;
6423 u32 dhd_assoc_state = 0;
6424 static int err_cnt = 0;
6425
6426 RETURN_EIO_IF_NOT_UP(cfg);
6427 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
6428 err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
6429 ETHER_ADDR_LEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
6430 if (err < 0) {
6431 WL_ERR(("GET STA INFO failed, %d\n", err));
6432 return err;
6433 }
6434 sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
6435 sta = (sta_info_t *)cfg->ioctl_buf;
6436 sta->len = dtoh16(sta->len);
6437 sta->cap = dtoh16(sta->cap);
6438 sta->flags = dtoh32(sta->flags);
6439 sta->idle = dtoh32(sta->idle);
6440 sta->in = dtoh32(sta->in);
6441 sinfo->inactive_time = sta->idle * 1000;
6442#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
6443 if (sta->flags & WL_STA_ASSOC) {
6444 sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
6445 sinfo->connected_time = sta->in;
6446 }
6447 WL_INFORM(("STA %s : idle time : %d sec, connected time :%d ms\n",
6448 bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
6449 sta->idle * 1000));
6450#endif
6451 } else if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS ||
6452 wl_get_mode_by_netdev(cfg, dev) == WL_MODE_IBSS) {
6453 get_pktcnt_t pktcnt;
6454#ifdef DHD_SUPPORT_IF_CNTS
6455 wl_if_stats_t *if_stats = NULL;
6456#endif /* DHD_SUPPORT_IF_CNTS */
6457 u8 *curmacp;
6458
6459 if (cfg->roam_offload) {
6460 struct ether_addr bssid;
6461 memset(&bssid, 0, sizeof(bssid));
6462 err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
6463 if (err) {
6464 WL_ERR(("Failed to get current BSSID\n"));
6465 } else {
6466 if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
6467 /* roaming is detected */
6468 err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
6469 if (err)
6470 WL_ERR(("Failed to handle the delayed roam, "
6471 "err=%d", err));
6472 mac = (u8 *)bssid.octet;
6473 }
6474 }
6475 }
6476 dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
6477 DHD_OS_WAKE_LOCK(dhd);
6478 fw_assoc_state = dhd_is_associated(dhd, 0, &err);
6479 DHD_OS_WAKE_UNLOCK(dhd);
6480 if (!dhd_assoc_state || !fw_assoc_state) {
6481 WL_ERR(("NOT assoc\n"));
6482 if (err == -ENODATA)
6483 return err;
6484 if (!dhd_assoc_state) {
6485 WL_TRACE_HW4(("drv state is not connected \n"));
6486 }
6487 if (!fw_assoc_state) {
6488 WL_TRACE_HW4(("fw state is not associated \n"));
6489 }
6490 /* Disconnect due to fw is not associated for FW_ASSOC_WATCHDOG_TIME ms.
6491 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
6492 * means that BSSID is null.
6493 */
6494 if (dhd_assoc_state && !fw_assoc_state && !err) {
6495 if (!fw_assoc_watchdog_started) {
6496 fw_assoc_watchdog_ms = OSL_SYSUPTIME();
6497 fw_assoc_watchdog_started = TRUE;
6498 WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
6499 } else {
6500 if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
6501 FW_ASSOC_WATCHDOG_TIME) {
6502 fw_assoc_watchdog_started = FALSE;
6503 err = -ENODEV;
6504 WL_TRACE_HW4(("fw is not associated for %d ms \n",
6505 (OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
6506 goto get_station_err;
6507 }
6508 }
6509 }
6510 err = -ENODEV;
6511 return err;
6512 }
6513 fw_assoc_watchdog_started = FALSE;
6514 curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
6515 if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
6516 WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
6517 MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
6518 }
6519
6520 /* Report the current tx rate */
6521 rate = 0;
6522 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
6523 if (err) {
6524 WL_ERR(("Could not get rate (%d)\n", err));
6525 } else {
6526#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
6527 int rxpktglom;
6528#endif
6529 rate = dtoh32(rate);
6530 sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
6531 sinfo->txrate.legacy = rate * 5;
6532 WL_DBG(("Rate %d Mbps\n", (rate / 2)));
6533#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
6534 rxpktglom = ((rate/2) > 150) ? 20 : 10;
6535
6536 if (maxrxpktglom != rxpktglom) {
6537 maxrxpktglom = rxpktglom;
6538 WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2),
6539 maxrxpktglom));
6540 err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
6541 (char*)&maxrxpktglom, 4, cfg->ioctl_buf,
6542 WLC_IOCTL_MAXLEN, NULL);
6543 if (err < 0) {
6544 WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
6545 }
6546 }
6547#endif
6548 }
6549
6550 memset(&scb_val, 0, sizeof(scb_val));
6551 scb_val.val = 0;
6552 err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val,
6553 sizeof(scb_val_t));
6554 if (err) {
6555 WL_ERR(("Could not get rssi (%d)\n", err));
6556 goto get_station_err;
6557 }
6558 rssi = dtoh32(scb_val.val);
6559#if defined(RSSIAVG)
d964ce36 6560 err = wl_update_connected_rssi_cache(dev, &cfg->g_connected_rssi_cache_ctrl, &rssi);
010c3a89
RC
6561 if (err) {
6562 WL_ERR(("Could not get rssi (%d)\n", err));
6563 goto get_station_err;
6564 }
d964ce36 6565 wl_delete_dirty_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
6566 wl_reset_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
010c3a89
RC
6567#endif
6568#if defined(RSSIOFFSET)
6569 rssi = wl_update_rssi_offset(dev, rssi);
6570#endif
6571#if !defined(RSSIAVG) && !defined(RSSIOFFSET)
6572 // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
6573 rssi = MIN(rssi, RSSI_MAXVAL);
6574#endif
6575 sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
6576 sinfo->signal = rssi;
6577 WL_DBG(("RSSI %d dBm\n", rssi));
6578
6579#ifdef DHD_SUPPORT_IF_CNTS
6580 if ((if_stats = kmalloc(sizeof(*if_stats), GFP_KERNEL)) == NULL) {
6581 WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__));
6582 goto error;
6583 }
6584 memset(if_stats, 0, sizeof(*if_stats));
6585
6586 err = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
6587 (char *)if_stats, sizeof(*if_stats), NULL);
6588 if (!err) {
6589 sinfo->rx_packets = (uint32)dtoh64(if_stats->rxframe);
6590 sinfo->rx_dropped_misc = 0;
6591 sinfo->tx_packets = (uint32)dtoh64(if_stats->txfrmsnt);
6592 sinfo->tx_failed = (uint32)dtoh64(if_stats->txnobuf) +
6593 (uint32)dtoh64(if_stats->txrunt) +
6594 (uint32)dtoh64(if_stats->txfail);
6595 } else {
57ab87eb
RC
6596 // WL_ERR(("%s: if_counters not supported ret=%d\n",
6597 // __FUNCTION__, err));
010c3a89
RC
6598#endif /* DHD_SUPPORT_IF_CNTS */
6599
6600 err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt,
6601 sizeof(pktcnt));
6602 if (err) {
6603 WL_ERR(("Could not get WLC_GET_PKTCNTS (%d)\n", err));
6604 goto get_station_err;
6605 }
6606 sinfo->rx_packets = pktcnt.rx_good_pkt;
6607 sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
6608 sinfo->tx_packets = pktcnt.tx_good_pkt;
6609 sinfo->tx_failed = pktcnt.tx_bad_pkt;
6610#ifdef DHD_SUPPORT_IF_CNTS
6611 }
6612#endif /* DHD_SUPPORT_IF_CNTS */
6613
6614 sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
6615 STA_INFO_BIT(INFO_RX_DROP_MISC) |
6616 STA_INFO_BIT(INFO_TX_PACKETS) |
6617 STA_INFO_BIT(INFO_TX_FAILED));
6618
6619get_station_err:
6620 if (err)
6621 err_cnt++;
6622 else
6623 err_cnt = 0;
6624 if (err_cnt >= 3 && (err != -ENODATA)) {
6625 /* Disconnect due to zero BSSID or error to get RSSI */
6626 scb_val_t scbval;
6627 scbval.val = htod32(DOT11_RC_DISASSOC_LEAVING);
6628 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
6629 if (unlikely(err)) {
6630 WL_ERR(("disassoc error (%d)\n", err));
6631 }
6632
6633 WL_ERR(("force cfg80211_disconnected: %d\n", err));
6634 wl_clr_drv_status(cfg, CONNECTED, dev);
6635 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
6636 wl_link_down(cfg);
6637 }
6638#ifdef DHD_SUPPORT_IF_CNTS
6639error:
6640 if (if_stats) {
6641 kfree(if_stats);
6642 }
6643#endif /* DHD_SUPPORT_IF_CNTS */
6644 }
6645 else {
6646 WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
6647 }
6648
6649 return err;
6650}
6651
6652static s32
6653wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
6654 bool enabled, s32 timeout)
6655{
6656 s32 pm;
6657 s32 err = 0;
6658 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6659 struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
6660#ifdef RTT_SUPPORT
6661 rtt_status_info_t *rtt_status;
6662#endif /* RTT_SUPPORT */
6663 dhd_pub_t *dhd = cfg->pub;
6664
6665 RETURN_EIO_IF_NOT_UP(cfg);
6666 WL_DBG(("Enter\n"));
6667 if (cfg->p2p_net == dev || _net_info == NULL ||
6668 !wl_get_drv_status(cfg, CONNECTED, dev) ||
6669 (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_BSS &&
6670 wl_get_mode_by_netdev(cfg, dev) != WL_MODE_IBSS)) {
6671 return err;
6672 }
6673
6674 /* Enlarge pm_enable_work */
6675 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
6676
6677 pm = enabled ? PM_FAST : PM_OFF;
6678 if (_net_info->pm_block) {
6679 WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
6680 dev->name, _net_info->pm_block));
6681 pm = PM_OFF;
6682 }
6683 if (enabled && dhd_conf_get_pm(dhd) >= 0)
6684 pm = dhd_conf_get_pm(dhd);
6685 pm = htod32(pm);
6686 WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
6687#ifdef RTT_SUPPORT
6688 rtt_status = GET_RTTSTATE(dhd);
6689 if (rtt_status->status != RTT_ENABLED) {
6690#endif /* RTT_SUPPORT */
6691 err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
6692 if (unlikely(err)) {
6693 if (err == -ENODEV)
6694 WL_DBG(("net_device is not ready yet\n"));
6695 else
6696 WL_ERR(("error (%d)\n", err));
6697 return err;
6698 }
6699#ifdef RTT_SUPPORT
6700 }
6701#endif /* RTT_SUPPORT */
6702 wl_cfg80211_update_power_mode(dev);
6703 return err;
6704}
6705
6706void wl_cfg80211_update_power_mode(struct net_device *dev)
6707{
6708 int err, pm = -1;
6709
6710 err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
6711 if (err)
6712 WL_ERR(("%s:error (%d)\n", __FUNCTION__, err));
6713 else if (pm != -1 && dev->ieee80211_ptr)
6714 dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
6715}
6716
6717void wl_cfg80211_set_passive_scan(struct net_device *dev, char *command)
6718{
6719 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6720
6721 if (strcmp(command, "SCAN-ACTIVE") == 0) {
6722 cfg->active_scan = 1;
6723 } else if (strcmp(command, "SCAN-PASSIVE") == 0) {
6724 cfg->active_scan = 0;
6725 } else
6726 WL_ERR(("Unknown command \n"));
6727}
6728
6729static __used u32 wl_find_msb(u16 bit16)
6730{
6731 u32 ret = 0;
6732
6733 if (bit16 & 0xff00) {
6734 ret += 8;
6735 bit16 >>= 8;
6736 }
6737
6738 if (bit16 & 0xf0) {
6739 ret += 4;
6740 bit16 >>= 4;
6741 }
6742
6743 if (bit16 & 0xc) {
6744 ret += 2;
6745 bit16 >>= 2;
6746 }
6747
6748 if (bit16 & 2)
6749 ret += bit16 & 2;
6750 else if (bit16)
6751 ret += bit16;
6752
6753 return ret;
6754}
6755
6756static s32 wl_cfg80211_resume(struct wiphy *wiphy)
6757{
6758 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6759 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6760 s32 err = BCME_OK;
6761
6762 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
6763 WL_INFORM(("device is not ready\n"));
6764 return err;
6765 }
6766
6767
6768 return err;
6769}
6770
6771
6772static s32
6773#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
6774wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
6775#else
6776wl_cfg80211_suspend(struct wiphy *wiphy)
6777#endif /* KERNEL_VERSION(2, 6, 39) || WL_COMPAT_WIRELES */
6778{
6779 s32 err = BCME_OK;
6780#ifdef DHD_CLEAR_ON_SUSPEND
6781 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6782 struct net_info *iter, *next;
6783 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6784 unsigned long flags;
6785#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
6786 struct cfg80211_scan_info info;
6787#endif
6788
6789 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
6790 WL_INFORM(("device is not ready : status (%d)\n",
6791 (int)cfg->status));
6792 return err;
6793 }
6794 for_each_ndev(cfg, iter, next) {
6795 /* p2p discovery iface doesn't have a ndev associated with it (for kernel > 3.8) */
6796 if (iter->ndev)
6797 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
6798 }
6799 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
6800 if (cfg->scan_request) {
6801#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
6802 info.aborted = true;
6803 cfg80211_scan_done(cfg->scan_request, &info);
6804#else
6805 cfg80211_scan_done(cfg->scan_request, true);
6806#endif
6807 cfg->scan_request = NULL;
6808 }
6809 for_each_ndev(cfg, iter, next) {
6810 if (iter->ndev) {
6811 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
6812 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
6813 }
6814 }
6815 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
6816 for_each_ndev(cfg, iter, next) {
6817 if (iter->ndev) {
6818 if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
6819 wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false);
6820 }
6821 }
6822 }
6823#endif /* DHD_CLEAR_ON_SUSPEND */
6824
6825
6826 return err;
6827}
6828
6829static s32
6830wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
6831 s32 err)
6832{
6833 int i, j;
6834 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6835 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
6836
6837 if (!pmk_list) {
6838 printf("pmk_list is NULL\n");
6839 return -EINVAL;
6840 }
6841 /* pmk list is supported only for STA interface i.e. primary interface
6842 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
6843 */
6844 if (primary_dev != dev) {
6845 WL_INFORM(("Not supporting Flushing pmklist on virtual"
6846 " interfaces than primary interface\n"));
6847 return err;
6848 }
6849
6850 WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
6851 for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
6852 WL_DBG(("PMKID[%d]: %pM =\n", i,
6853 &pmk_list->pmkids.pmkid[i].BSSID));
6854 for (j = 0; j < WPA2_PMKID_LEN; j++) {
6855 WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]));
6856 }
6857 }
6858 if (likely(!err)) {
6859 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
6860 sizeof(*pmk_list), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6861 }
6862
6863 return err;
6864}
6865
6866static s32
6867wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
6868 struct cfg80211_pmksa *pmksa)
6869{
6870 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6871 s32 err = 0;
6872 int i;
6873
6874 RETURN_EIO_IF_NOT_UP(cfg);
6875 for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
6876 if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
6877 ETHER_ADDR_LEN))
6878 break;
6879 if (i < WL_NUM_PMKIDS_MAX) {
6880 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid,
6881 ETHER_ADDR_LEN);
6882 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid,
6883 WPA2_PMKID_LEN);
6884 if (i == cfg->pmk_list->pmkids.npmkid)
6885 cfg->pmk_list->pmkids.npmkid++;
6886 } else {
6887 err = -EINVAL;
6888 }
6889 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
6890 &cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].BSSID));
6891 for (i = 0; i < WPA2_PMKID_LEN; i++) {
6892 WL_DBG(("%02x\n",
6893 cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].
6894 PMKID[i]));
6895 }
6896
6897 err = wl_update_pmklist(dev, cfg->pmk_list, err);
6898
6899 return err;
6900}
6901
6902static s32
6903wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
6904 struct cfg80211_pmksa *pmksa)
6905{
6906 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6907
6908 struct _pmkid_list pmkid = {.npmkid = 0};
6909 s32 err = 0;
6910 int i;
6911
6912 RETURN_EIO_IF_NOT_UP(cfg);
6913 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
6914 memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
6915
6916 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
6917 &pmkid.pmkid[0].BSSID));
6918 for (i = 0; i < WPA2_PMKID_LEN; i++) {
6919 WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i]));
6920 }
6921
6922 for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
6923 if (!memcmp
6924 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
6925 ETHER_ADDR_LEN))
6926 break;
6927
6928 if ((cfg->pmk_list->pmkids.npmkid > 0) &&
6929 (i < cfg->pmk_list->pmkids.npmkid)) {
6930 memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t));
6931 for (; i < (cfg->pmk_list->pmkids.npmkid - 1); i++) {
6932 memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
6933 &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
6934 ETHER_ADDR_LEN);
6935 memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
6936 &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
6937 WPA2_PMKID_LEN);
6938 }
6939 cfg->pmk_list->pmkids.npmkid--;
6940 } else {
6941 err = -EINVAL;
6942 }
6943
6944 err = wl_update_pmklist(dev, cfg->pmk_list, err);
6945
6946 return err;
6947
6948}
6949
6950static s32
6951wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
6952{
6953 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6954 s32 err = 0;
6955 RETURN_EIO_IF_NOT_UP(cfg);
6956 memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
6957 err = wl_update_pmklist(dev, cfg->pmk_list, err);
6958 return err;
6959}
6960
6961static wl_scan_params_t *
6962wl_cfg80211_scan_alloc_params(struct bcm_cfg80211 *cfg, int channel, int nprobes,
6963 int *out_params_size)
6964{
6965 wl_scan_params_t *params;
6966 int params_size;
6967 int num_chans;
6968 int bssidx = 0;
6969
6970 *out_params_size = 0;
6971
6972 /* Our scan params only need space for 1 channel and 0 ssids */
6973 params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16);
6974 params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL);
6975 if (params == NULL) {
6976 WL_ERR(("mem alloc failed (%d bytes)\n", params_size));
6977 return params;
6978 }
6979 memset(params, 0, params_size);
6980 params->nprobes = nprobes;
6981
6982 num_chans = (channel == 0) ? 0 : 1;
6983
6984 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
6985 params->bss_type = DOT11_BSSTYPE_ANY;
6986 params->scan_type = DOT11_SCANTYPE_ACTIVE;
6987 params->nprobes = htod32(1);
6988 params->active_time = htod32(-1);
6989 params->passive_time = htod32(-1);
6990 params->home_time = htod32(10);
6991 if (channel == -1)
6992 params->channel_list[0] = htodchanspec(channel);
6993 else
6994 params->channel_list[0] = wl_ch_host_to_driver(cfg, bssidx, channel);
6995
6996 /* Our scan params have 1 channel and 0 ssids */
6997 params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
6998 (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
6999
7000 *out_params_size = params_size; /* rtn size to the caller */
7001 return params;
7002}
7003
7004static s32
7005#if defined(WL_CFG80211_P2P_DEV_IF)
7006wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
7007 struct ieee80211_channel *channel, unsigned int duration, u64 *cookie)
7008#else
7009wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
7010 struct ieee80211_channel * channel,
7011 enum nl80211_channel_type channel_type,
7012 unsigned int duration, u64 *cookie)
7013#endif /* WL_CFG80211_P2P_DEV_IF */
7014{
7015 s32 target_channel;
7016 u32 id;
7017 s32 err = BCME_OK;
7018 struct ether_addr primary_mac;
7019 struct net_device *ndev = NULL;
7020 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7021
7022#ifdef DHD_IFDEBUG
7023 PRINT_WDEV_INFO(cfgdev);
7024#endif /* DHD_IFDEBUG */
7025
7026 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
7027
7028 WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
7029 ieee80211_frequency_to_channel(channel->center_freq),
7030 duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO"));
7031
7032 if (!cfg->p2p) {
7033 WL_ERR(("cfg->p2p is not initialized\n"));
7034 err = BCME_ERROR;
7035 goto exit;
7036 }
7037
7038#ifdef P2P_LISTEN_OFFLOADING
7039 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
7040 WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
7041 return -EAGAIN;
7042 }
7043#endif /* P2P_LISTEN_OFFLOADING */
7044
7045#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
7046 if (wl_get_drv_status_all(cfg, SCANNING)) {
7047 wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
7048 }
7049#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
7050
7051 target_channel = ieee80211_frequency_to_channel(channel->center_freq);
7052 memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel));
7053#if defined(WL_ENABLE_P2P_IF)
7054 cfg->remain_on_chan_type = channel_type;
7055#endif /* WL_ENABLE_P2P_IF */
7056 id = ++cfg->last_roc_id;
7057 if (id == 0)
7058 id = ++cfg->last_roc_id;
7059 *cookie = id;
7060
7061#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
7062 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
7063 struct timer_list *_timer;
7064 WL_DBG(("scan is running. go to fake listen state\n"));
7065
7066 if (duration > LONG_LISTEN_TIME) {
7067 wl_cfg80211_scan_abort(cfg);
7068 } else {
7069 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
7070
7071 if (timer_pending(&cfg->p2p->listen_timer)) {
7072 WL_DBG(("cancel current listen timer \n"));
7073 del_timer_sync(&cfg->p2p->listen_timer);
7074 }
7075
7076 _timer = &cfg->p2p->listen_timer;
7077 wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
7078
7079 INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0);
7080
7081 err = BCME_OK;
7082 goto exit;
7083 }
7084 }
7085#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
7086
7087#ifdef WL_CFG80211_SYNC_GON
7088 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
7089 /* do not enter listen mode again if we are in listen mode already for next af.
7090 * remain on channel completion will be returned by waiting next af completion.
7091 */
7092#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
7093 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
7094#else
7095 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
7096#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
7097 goto exit;
7098 }
7099#endif /* WL_CFG80211_SYNC_GON */
7100 if (cfg->p2p && !cfg->p2p->on) {
7101 /* In case of p2p_listen command, supplicant send remain_on_channel
7102 * without turning on P2P
7103 */
7104 get_primary_mac(cfg, &primary_mac);
7105 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
7106 p2p_on(cfg) = true;
7107 }
7108
7109 if (p2p_is_on(cfg)) {
7110 err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
7111 if (unlikely(err)) {
7112 goto exit;
7113 }
7114#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
7115 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
7116#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
7117 err = wl_cfgp2p_discover_listen(cfg, target_channel, duration);
7118
7119#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
7120 if (err == BCME_OK) {
7121 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
7122 } else {
7123 /* if failed, firmware may be internal scanning state.
7124 * so other scan request shall not abort it
7125 */
7126 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
7127 }
7128#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
7129 /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant
7130 * and expire timer will send a completion to the upper layer
7131 */
7132 err = BCME_OK;
7133 }
7134
7135exit:
7136 if (err == BCME_OK) {
7137 WL_INFORM(("Success\n"));
7138#if defined(WL_CFG80211_P2P_DEV_IF)
7139 cfg80211_ready_on_channel(cfgdev, *cookie, channel,
7140 duration, GFP_KERNEL);
7141#else
7142 cfg80211_ready_on_channel(cfgdev, *cookie, channel,
7143 channel_type, duration, GFP_KERNEL);
7144#endif /* WL_CFG80211_P2P_DEV_IF */
7145 } else {
7146 WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie));
7147 }
7148 return err;
7149}
7150
7151static s32
7152wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
7153 bcm_struct_cfgdev *cfgdev, u64 cookie)
7154{
7155 s32 err = 0;
7156
7157 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7158
7159#ifdef P2PLISTEN_AP_SAMECHN
7160 struct net_device *dev;
7161#endif /* P2PLISTEN_AP_SAMECHN */
7162
7163 RETURN_EIO_IF_NOT_UP(cfg);
7164
7165#ifdef DHD_IFDEBUG
7166 PRINT_WDEV_INFO(cfgdev);
7167#endif /* DHD_IFDEBUG */
7168
7169#if defined(WL_CFG80211_P2P_DEV_IF)
7170 if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
7171 WL_DBG((" enter ) on P2P dedicated discover interface\n"));
7172 }
7173#else
7174 WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex));
7175#endif /* WL_CFG80211_P2P_DEV_IF */
7176
7177#ifdef P2PLISTEN_AP_SAMECHN
7178 if (cfg && cfg->p2p_resp_apchn_status) {
7179 dev = bcmcfg_to_prmry_ndev(cfg);
7180 wl_cfg80211_set_p2p_resp_ap_chn(dev, 0);
7181 cfg->p2p_resp_apchn_status = false;
7182 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
7183 }
7184#endif /* P2PLISTEN_AP_SAMECHN */
7185
7186 if (cfg->last_roc_id == cookie) {
7187 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
7188 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
7189 } else {
7190 WL_ERR(("%s : ignore, request cookie(%llu) is not matched. (cur : %llu)\n",
7191 __FUNCTION__, cookie, cfg->last_roc_id));
7192 }
7193
7194 return err;
7195}
7196
7197static void
7198wl_cfg80211_afx_handler(struct work_struct *work)
7199{
7200 struct afx_hdl *afx_instance;
7201 struct bcm_cfg80211 *cfg;
7202 s32 ret = BCME_OK;
7203
7204 BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
7205 if (!afx_instance) {
7206 WL_ERR(("afx_instance is NULL\n"));
7207 return;
7208 }
7209 cfg = wl_get_cfg(afx_instance->dev);
7210 if (afx_instance) {
7211 if (cfg->afx_hdl->is_active) {
7212 if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
7213 ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
7214 (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
7215 } else {
7216 ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
7217 cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
7218 NULL);
7219 }
7220 if (unlikely(ret != BCME_OK)) {
7221 WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
7222 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
7223 complete(&cfg->act_frm_scan);
7224 }
7225 }
7226 }
7227}
7228
7229static s32
7230wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
7231{
7232 u32 max_retry = WL_CHANNEL_SYNC_RETRY;
7233 bool is_p2p_gas = false;
7234
7235 if (dev == NULL)
7236 return -1;
7237
7238 WL_DBG((" enter ) \n"));
7239
7240 wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
7241 cfg->afx_hdl->is_active = TRUE;
7242
7243 if (cfg->afx_hdl->pending_tx_act_frm) {
7244 wl_action_frame_t *action_frame;
7245 action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
7246 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len))
7247 is_p2p_gas = true;
7248 }
7249
7250 /* Loop to wait until we find a peer's channel or the
7251 * pending action frame tx is cancelled.
7252 */
7253 while ((cfg->afx_hdl->retry < max_retry) &&
7254 (cfg->afx_hdl->peer_chan == WL_INVALID)) {
7255 cfg->afx_hdl->is_listen = FALSE;
7256 wl_set_drv_status(cfg, SCANNING, dev);
7257 WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
7258 cfg->afx_hdl->retry));
7259 /* search peer on peer's listen channel */
7260 schedule_work(&cfg->afx_hdl->work);
7261 wait_for_completion_timeout(&cfg->act_frm_scan,
7262 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
7263
7264 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
7265 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
7266 break;
7267
7268 if (is_p2p_gas)
7269 break;
7270
7271 if (cfg->afx_hdl->my_listen_chan) {
7272 WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
7273 cfg->afx_hdl->my_listen_chan));
7274 /* listen on my listen channel */
7275 cfg->afx_hdl->is_listen = TRUE;
7276 schedule_work(&cfg->afx_hdl->work);
7277 wait_for_completion_timeout(&cfg->act_frm_scan,
7278 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
7279 }
7280 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
7281 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
7282 break;
7283
7284 cfg->afx_hdl->retry++;
7285
7286 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
7287 }
7288
7289 cfg->afx_hdl->is_active = FALSE;
7290
7291 wl_clr_drv_status(cfg, SCANNING, dev);
7292 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
7293
7294 return (cfg->afx_hdl->peer_chan);
7295}
7296
7297struct p2p_config_af_params {
7298 s32 max_tx_retry; /* max tx retry count if tx no ack */
7299#ifdef WL_CFG80211_SYNC_GON
7300 bool extra_listen;
7301#endif
7302 bool search_channel; /* 1: search peer's channel to send af */
7303};
7304
7305static s32
7306wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
7307 wl_action_frame_t *action_frame, wl_af_params_t *af_params,
7308 struct p2p_config_af_params *config_af_params)
7309{
7310 s32 err = BCME_OK;
7311 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7312 wifi_p2p_pub_act_frame_t *act_frm =
7313 (wifi_p2p_pub_act_frame_t *) (action_frame->data);
7314
7315 /* initialize default value */
7316#ifdef WL_CFG80211_SYNC_GON
7317 config_af_params->extra_listen = true;
7318#endif
7319 config_af_params->search_channel = false;
7320 config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
7321 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
7322
7323 switch (act_frm->subtype) {
7324 case P2P_PAF_GON_REQ: {
7325 WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
7326 wl_set_p2p_status(cfg, GO_NEG_PHASE);
7327
7328 config_af_params->search_channel = true;
7329 cfg->next_af_subtype = act_frm->subtype + 1;
7330
7331 /* increase dwell time to wait for RESP frame */
7332 af_params->dwell_time = WL_MED_DWELL_TIME;
7333
7334 break;
7335 }
7336 case P2P_PAF_GON_RSP: {
7337 cfg->next_af_subtype = act_frm->subtype + 1;
7338 /* increase dwell time to wait for CONF frame */
7339 af_params->dwell_time = WL_MED_DWELL_TIME + 100;
7340 break;
7341 }
7342 case P2P_PAF_GON_CONF: {
7343 /* If we reached till GO Neg confirmation reset the filter */
7344 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
7345 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
7346
7347 /* minimize dwell time */
7348 af_params->dwell_time = WL_MIN_DWELL_TIME;
7349
7350#ifdef WL_CFG80211_SYNC_GON
7351 config_af_params->extra_listen = false;
7352#endif /* WL_CFG80211_SYNC_GON */
7353 break;
7354 }
7355 case P2P_PAF_INVITE_REQ: {
7356 config_af_params->search_channel = true;
7357 cfg->next_af_subtype = act_frm->subtype + 1;
7358
7359 /* increase dwell time */
7360 af_params->dwell_time = WL_MED_DWELL_TIME;
7361 break;
7362 }
7363 case P2P_PAF_INVITE_RSP:
7364 /* minimize dwell time */
7365 af_params->dwell_time = WL_MIN_DWELL_TIME;
7366#ifdef WL_CFG80211_SYNC_GON
7367 config_af_params->extra_listen = false;
7368#endif /* WL_CFG80211_SYNC_GON */
7369 break;
7370 case P2P_PAF_DEVDIS_REQ: {
7371 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
7372 action_frame->len)) {
7373 config_af_params->search_channel = true;
7374 }
7375
7376 cfg->next_af_subtype = act_frm->subtype + 1;
7377 /* maximize dwell time to wait for RESP frame */
7378 af_params->dwell_time = WL_LONG_DWELL_TIME;
7379 break;
7380 }
7381 case P2P_PAF_DEVDIS_RSP:
7382 /* minimize dwell time */
7383 af_params->dwell_time = WL_MIN_DWELL_TIME;
7384#ifdef WL_CFG80211_SYNC_GON
7385 config_af_params->extra_listen = false;
7386#endif /* WL_CFG80211_SYNC_GON */
7387 break;
7388 case P2P_PAF_PROVDIS_REQ: {
7389 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
7390 action_frame->len)) {
7391 config_af_params->search_channel = true;
7392 }
7393
7394 cfg->next_af_subtype = act_frm->subtype + 1;
7395 /* increase dwell time to wait for RESP frame */
7396 af_params->dwell_time = WL_MED_DWELL_TIME;
7397 break;
7398 }
7399 case P2P_PAF_PROVDIS_RSP: {
7400 cfg->next_af_subtype = P2P_PAF_GON_REQ;
7401 af_params->dwell_time = WL_MED_DWELL_TIME;
7402#ifdef WL_CFG80211_SYNC_GON
7403 config_af_params->extra_listen = false;
7404#endif /* WL_CFG80211_SYNC_GON */
7405 break;
7406 }
7407 default:
7408 WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
7409 act_frm->subtype));
7410 err = BCME_BADARG;
7411 }
7412 return err;
7413}
7414
7415#ifdef WL11U
7416static bool
7417wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params,
7418 void *frame, u16 frame_len)
7419{
7420 struct wl_scan_results *bss_list;
7421 struct wl_bss_info *bi = NULL;
7422 bool result = false;
7423 s32 i;
7424 chanspec_t chanspec;
7425
7426 /* If DFS channel is 52~148, check to block it or not */
7427 if (af_params &&
7428 (af_params->channel >= 52 && af_params->channel <= 148)) {
7429 if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
7430 bss_list = cfg->bss_list;
7431 bi = next_bss(bss_list, bi);
7432 for_each_bss(bss_list, bi, i) {
7433 chanspec = wl_chspec_driver_to_host(bi->chanspec);
7434 if (CHSPEC_IS5G(chanspec) &&
7435 ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec))
7436 == af_params->channel)) {
7437 result = true; /* do not block the action frame */
7438 break;
7439 }
7440 }
7441 }
7442 }
7443 else {
7444 result = true;
7445 }
7446
7447 WL_DBG(("result=%s", result?"true":"false"));
7448 return result;
7449}
7450#endif /* WL11U */
7451static bool
7452wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies)
7453{
7454 if ((requested_dwell & CUSTOM_RETRY_MASK) &&
7455 (jiffies_to_msecs(jiffies - dwell_jiffies) >
7456 (requested_dwell & ~CUSTOM_RETRY_MASK))) {
7457 WL_ERR(("Action frame TX retry time over dwell time!\n"));
7458 return true;
7459 }
7460 return false;
7461}
7462
7463static bool
7464wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
7465 bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
7466 wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
7467{
7468#ifdef WL11U
7469 struct net_device *ndev = NULL;
7470#endif /* WL11U */
7471 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7472 bool ack = false;
7473 u8 category, action;
7474 s32 tx_retry;
7475 struct p2p_config_af_params config_af_params;
7476 struct net_info *netinfo;
7477#ifdef VSDB
7478 ulong off_chan_started_jiffies = 0;
7479#endif
7480 ulong dwell_jiffies = 0;
7481 bool dwell_overflow = false;
7482 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
7483 bool miss_gon_cfm = false;
7484
7485 int32 requested_dwell = af_params->dwell_time;
7486
7487 /* Add the default dwell time
7488 * Dwell time to stay off-channel to wait for a response action frame
7489 * after transmitting an GO Negotiation action frame
7490 */
7491 af_params->dwell_time = WL_DWELL_TIME;
7492
7493#ifdef WL11U
7494#if defined(WL_CFG80211_P2P_DEV_IF)
7495 ndev = dev;
7496#else
7497 ndev = ndev_to_cfgdev(cfgdev);
7498#endif /* WL_CFG80211_P2P_DEV_IF */
7499#endif /* WL11U */
7500
7501 category = action_frame->data[DOT11_ACTION_CAT_OFF];
7502 action = action_frame->data[DOT11_ACTION_ACT_OFF];
7503
7504 /* initialize variables */
7505 tx_retry = 0;
7506 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
7507 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
7508 config_af_params.search_channel = false;
7509#ifdef WL_CFG80211_SYNC_GON
7510 config_af_params.extra_listen = false;
7511#endif
7512
7513 /* config parameters */
7514 /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
7515 if (category == DOT11_ACTION_CAT_PUBLIC) {
7516 if ((action == P2P_PUB_AF_ACTION) &&
7517 (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
7518 /* p2p public action frame process */
7519 if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy,
7520 action_frame, af_params, &config_af_params)) {
7521 WL_DBG(("Unknown subtype.\n"));
7522 }
7523
7524 } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
7525 /* service discovery process */
7526 if (action == P2PSD_ACTION_ID_GAS_IREQ ||
7527 action == P2PSD_ACTION_ID_GAS_CREQ) {
7528 /* configure service discovery query frame */
7529
7530 config_af_params.search_channel = true;
7531
7532 /* save next af suptype to cancel remained dwell time */
7533 cfg->next_af_subtype = action + 1;
7534
7535 af_params->dwell_time = WL_MED_DWELL_TIME;
7536 if (requested_dwell & CUSTOM_RETRY_MASK) {
7537 config_af_params.max_tx_retry =
7538 (requested_dwell & CUSTOM_RETRY_MASK) >> 24;
7539 af_params->dwell_time =
7540 (requested_dwell & ~CUSTOM_RETRY_MASK);
7541 WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
7542 config_af_params.max_tx_retry,
7543 af_params->dwell_time));
7544 }
7545 } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
7546 action == P2PSD_ACTION_ID_GAS_CRESP) {
7547 /* configure service discovery response frame */
7548 af_params->dwell_time = WL_MIN_DWELL_TIME;
7549 } else {
7550 WL_DBG(("Unknown action type: %d\n", action));
7551 }
7552 } else {
7553 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
7554 category, action, action_frame_len));
7555 }
7556 } else if (category == P2P_AF_CATEGORY) {
7557 /* do not configure anything. it will be sent with a default configuration */
7558 } else {
7559 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
7560 category, action));
7561 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
7562 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
7563 return false;
7564 }
7565 }
7566 netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
7567 /* validate channel and p2p ies */
7568 if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) &&
7569 netinfo && netinfo->bss.ies.probe_req_ie_len) {
7570 config_af_params.search_channel = true;
7571 } else {
7572 config_af_params.search_channel = false;
7573 }
7574#ifdef WL11U
7575 if (ndev == bcmcfg_to_prmry_ndev(cfg))
7576 config_af_params.search_channel = false;
7577#endif /* WL11U */
7578
7579#ifdef VSDB
7580 /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
7581 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
7582 OSL_SLEEP(50);
7583 }
7584#endif
7585
7586 /* if scan is ongoing, abort current scan. */
7587 if (wl_get_drv_status_all(cfg, SCANNING)) {
7588 wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
7589 }
7590
7591 /* Abort P2P listen */
7592 if (discover_cfgdev(cfgdev, cfg)) {
7593 if (cfg->p2p_supported && cfg->p2p) {
7594 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
7595 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
7596 }
7597 }
7598
7599#ifdef WL11U
7600 /* handling DFS channel exceptions */
7601 if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) {
7602 return false; /* the action frame was blocked */
7603 }
7604#endif /* WL11U */
7605
7606 /* set status and destination address before sending af */
7607 if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
7608 /* set this status to cancel the remained dwell time in rx process */
7609 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
7610 }
7611 wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
7612 memcpy(cfg->afx_hdl->tx_dst_addr.octet,
7613 af_params->action_frame.da.octet,
7614 sizeof(cfg->afx_hdl->tx_dst_addr.octet));
7615
7616 /* save af_params for rx process */
7617 cfg->afx_hdl->pending_tx_act_frm = af_params;
7618
7619 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
7620 WL_DBG(("Set GAS action frame config.\n"));
7621 config_af_params.search_channel = false;
7622 config_af_params.max_tx_retry = 1;
7623 }
7624
7625 /* search peer's channel */
7626 if (config_af_params.search_channel) {
7627 /* initialize afx_hdl */
7628 if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7629 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7630 goto exit;
7631 }
7632 cfg->afx_hdl->dev = dev;
7633 cfg->afx_hdl->retry = 0;
7634 cfg->afx_hdl->peer_chan = WL_INVALID;
7635
7636 if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
7637 WL_ERR(("couldn't find peer's channel.\n"));
7638 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
7639 af_params->channel);
7640 /* Even if we couldn't find peer channel, try to send the frame
7641 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
7642 * respond to probe request (Ideally it has to be in listen and
7643 * responsd to probe request). However if we send Go neg req, the
7644 * peer is sending GO-neg resp. So instead of giving up here, just
7645 * proceed and attempt sending out the action frame.
7646 */
7647 }
7648
7649 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
7650 /*
7651 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
7652 * but after the check of piggyback algorithm.
7653 * To take care of current piggback algo, lets abort the scan here itself.
7654 */
7655 wl_notify_escan_complete(cfg, dev, true, true);
7656 /* Suspend P2P discovery's search-listen to prevent it from
7657 * starting a scan or changing the channel.
7658 */
7659 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
7660 WL_ERR(("Can not disable discovery mode\n"));
7661 goto exit;
7662 }
7663
7664 /* update channel */
7665 if (cfg->afx_hdl->peer_chan != WL_INVALID) {
7666 af_params->channel = cfg->afx_hdl->peer_chan;
7667 WL_ERR(("Attempt tx on peer listen channel:%d ",
7668 cfg->afx_hdl->peer_chan));
7669 } else {
7670 WL_ERR(("Attempt tx with the channel provided by userspace."
7671 "Channel: %d\n", af_params->channel));
7672 }
7673 }
7674
7675#ifdef VSDB
7676 off_chan_started_jiffies = jiffies;
7677#endif /* VSDB */
7678
7679 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel);
7680
7681 wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
7682
7683 dwell_jiffies = jiffies;
7684 /* Now send a tx action frame */
7685 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
7686 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
7687
7688 if (ack && (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM))) {
7689 wifi_p2p_pub_act_frame_t *pact_frm;
7690 pact_frm = (wifi_p2p_pub_act_frame_t *)(action_frame->data);
7691 if (pact_frm->subtype == P2P_PAF_GON_RSP) {
7692 WL_ERR(("Miss GO Nego cfm after P2P_PAF_GON_RSP\n"));
7693 miss_gon_cfm = true;
7694 }
7695 }
7696
7697 /* if failed, retry it. tx_retry_max value is configure by .... */
7698 while ((miss_gon_cfm || (ack == false)) && (tx_retry++ < config_af_params.max_tx_retry) &&
7699 !dwell_overflow) {
7700#ifdef VSDB
7701 if (af_params->channel) {
7702 if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
7703 OFF_CHAN_TIME_THRESHOLD_MS) {
7704 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
7705 off_chan_started_jiffies = jiffies;
7706 } else
7707 OSL_SLEEP(AF_RETRY_DELAY_TIME);
7708 }
7709#endif /* VSDB */
7710 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
7711 false : true;
7712 if (miss_gon_cfm && !wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
7713 WL_ERR(("Received GO Nego cfm after P2P_PAF_GON_RSP\n"));
7714 miss_gon_cfm = false;
7715 }
7716 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
7717 }
7718
7719 if (ack == false) {
7720 WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
7721 }
7722 WL_DBG(("Complete to send action frame\n"));
7723exit:
7724 /* Clear SENDING_ACT_FRM after all sending af is done */
7725 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
7726
7727#ifdef WL_CFG80211_SYNC_GON
7728 /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
7729 * if we coundn't get the next action response frame and dongle does not keep
7730 * the dwell time, go to listen state again to get next action response frame.
7731 */
7732 if (ack && config_af_params.extra_listen &&
7733 wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
7734 cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
7735 s32 extar_listen_time;
7736
7737 extar_listen_time = af_params->dwell_time -
7738 jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
7739
7740 if (extar_listen_time > 50) {
7741 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
7742 WL_DBG(("Wait more time! actual af time:%d,"
7743 "calculated extar listen:%d\n",
7744 af_params->dwell_time, extar_listen_time));
7745 if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
7746 extar_listen_time + 100) == BCME_OK) {
7747 wait_for_completion_timeout(&cfg->wait_next_af,
7748 msecs_to_jiffies(extar_listen_time + 100 + 300));
7749 }
7750 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
7751 }
7752 }
7753#endif /* WL_CFG80211_SYNC_GON */
7754 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
7755 cfg->afx_hdl->pending_tx_act_frm = NULL;
7756
7757 WL_INFORM(("-- sending Action Frame is %s, listen chan: %d\n",
7758 (ack) ? "Succeeded!!":"Failed!!", cfg->afx_hdl->my_listen_chan));
7759
7760 return ack;
7761}
7762
7763#define MAX_NUM_OF_ASSOCIATED_DEV 64
7764static s32
7765#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
7766wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
7767 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
7768#else
7769wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
7770 struct ieee80211_channel *channel, bool offchan,
7771#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
7772 enum nl80211_channel_type channel_type,
7773 bool channel_type_valid,
7774#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
7775 unsigned int wait, const u8* buf, size_t len,
7776#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
7777 bool no_cck,
7778#endif
7779#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
7780 bool dont_wait_for_ack,
7781#endif
7782 u64 *cookie)
7783#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
7784{
7785 wl_action_frame_t *action_frame;
7786 wl_af_params_t *af_params;
7787 scb_val_t scb_val;
7788#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
7789 struct ieee80211_channel *channel = params->chan;
7790 const u8 *buf = params->buf;
7791 size_t len = params->len;
7792#endif
7793 const struct ieee80211_mgmt *mgmt;
7794 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7795 struct net_device *dev = NULL;
7796 s32 err = BCME_OK;
7797 s32 bssidx = 0;
7798 u32 id;
7799 bool ack = false;
7800 s8 eabuf[ETHER_ADDR_STR_LEN];
7801
7802 WL_DBG(("Enter \n"));
7803
7804 if (len > ACTION_FRAME_SIZE) {
7805 WL_ERR(("bad length:%zu\n", len));
7806 return BCME_BADLEN;
7807 }
7808#ifdef DHD_IFDEBUG
7809 PRINT_WDEV_INFO(cfgdev);
7810#endif /* DHD_IFDEBUG */
7811
7812 dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
7813
7814 if (!dev) {
7815 WL_ERR(("dev is NULL\n"));
7816 return -EINVAL;
7817 }
7818
7819 /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
7820 if (discover_cfgdev(cfgdev, cfg)) {
7821 if (!cfg->p2p_supported || !cfg->p2p) {
7822 WL_ERR(("P2P doesn't setup completed yet\n"));
7823 return -EINVAL;
7824 }
7825 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
7826 }
7827 else {
7828 if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
7829 WL_ERR(("Find p2p index failed\n"));
7830 return BCME_ERROR;
7831 }
7832 }
7833
7834 WL_DBG(("TX target bssidx=%d\n", bssidx));
7835
7836 if (p2p_is_on(cfg)) {
7837 /* Suspend P2P discovery search-listen to prevent it from changing the
7838 * channel.
7839 */
7840 if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
7841 WL_ERR(("Can not disable discovery mode\n"));
7842 return -EFAULT;
7843 }
7844 }
7845 *cookie = 0;
7846 id = cfg->send_action_id++;
7847 if (id == 0)
7848 id = cfg->send_action_id++;
7849 *cookie = id;
7850 mgmt = (const struct ieee80211_mgmt *)buf;
7851 if (ieee80211_is_mgmt(mgmt->frame_control)) {
7852 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
7853 s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
7854 s32 ie_len = len - ie_offset;
7855 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
7856 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
7857 }
7858 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
7859 VNDR_IE_PRBRSP_FLAG, (const u8 *)(buf + ie_offset), ie_len);
7860 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
7861#if defined(P2P_IE_MISSING_FIX)
7862 if (!cfg->p2p_prb_noti) {
7863 cfg->p2p_prb_noti = true;
7864 WL_DBG(("%s: TX 802_1X Probe Response first time.\n",
7865 __FUNCTION__));
7866 }
7867#endif
7868 goto exit;
7869 } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
7870 ieee80211_is_deauth(mgmt->frame_control)) {
7871 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
7872 sizeof(struct ether_addr) + sizeof(uint)] = {0};
7873 int num_associated = 0;
7874 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
7875 if (!bcmp((const uint8 *)BSSID_BROADCAST,
7876 (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
7877 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
7878 err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST,
7879 assoc_maclist, sizeof(mac_buf));
7880 if (err < 0)
7881 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
7882 else
7883 num_associated = assoc_maclist->count;
7884 }
7885 memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
7886 scb_val.val = mgmt->u.disassoc.reason_code;
7887 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
7888 sizeof(scb_val_t));
7889 if (err < 0)
7890 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
7891 WL_ERR(("Disconnect STA : %s scb_val.val %d\n",
7892 bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
7893 scb_val.val));
7894
7895 if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
7896 wl_delay(400);
7897
7898 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
7899 goto exit;
7900
7901 } else if (ieee80211_is_action(mgmt->frame_control)) {
7902 /* Abort the dwell time of any previous off-channel
7903 * action frame that may be still in effect. Sending
7904 * off-channel action frames relies on the driver's
7905 * scan engine. If a previous off-channel action frame
7906 * tx is still in progress (including the dwell time),
7907 * then this new action frame will not be sent out.
7908 */
7909/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
7910 * And previous off-channel action frame must be ended before new af tx.
7911 */
7912#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
7913 wl_notify_escan_complete(cfg, dev, true, true);
7914#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
7915 }
7916
7917 } else {
7918 WL_ERR(("Driver only allows MGMT packet type\n"));
7919 goto exit;
7920 }
7921
7922 af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
7923
7924 if (af_params == NULL)
7925 {
7926 WL_ERR(("unable to allocate frame\n"));
7927 return -ENOMEM;
7928 }
7929
7930 action_frame = &af_params->action_frame;
7931
7932 /* Add the packet Id */
7933 action_frame->packetId = *cookie;
7934 WL_DBG(("action frame %d\n", action_frame->packetId));
7935 /* Add BSSID */
7936 memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
7937 memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
7938
7939 /* Add the length exepted for 802.11 header */
7940 action_frame->len = len - DOT11_MGMT_HDR_LEN;
7941 WL_DBG(("action_frame->len: %d\n", action_frame->len));
7942
7943 /* Add the channel */
7944 af_params->channel =
7945 ieee80211_frequency_to_channel(channel->center_freq);
7946 /* Save listen_chan for searching common channel */
7947 cfg->afx_hdl->peer_listen_chan = af_params->channel;
7948 WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
7949
7950#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
7951 af_params->dwell_time = params->wait;
7952#else
7953 af_params->dwell_time = wait;
7954#endif
7955
7956 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
7957
7958 ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params,
7959 action_frame, action_frame->len, bssidx);
7960 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
7961
7962 kfree(af_params);
7963exit:
7964 return err;
7965}
7966
7967
7968static void
7969wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
7970 u16 frame, bool reg)
7971{
7972
7973 WL_DBG(("frame_type: %x, reg: %d\n", frame, reg));
7974
7975 if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
7976 return;
7977
7978 return;
7979}
7980
7981
7982static s32
7983wl_cfg80211_change_bss(struct wiphy *wiphy,
7984 struct net_device *dev,
7985 struct bss_parameters *params)
7986{
7987 s32 err = 0;
7988 s32 ap_isolate = 0;
7989#ifdef PCIE_FULL_DONGLE
7990 s32 ifidx = DHD_BAD_IF;
7991#endif
7992#if defined(PCIE_FULL_DONGLE)
7993 dhd_pub_t *dhd;
7994 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7995 dhd = (dhd_pub_t *)(cfg->pub);
7996#if defined(WL_ENABLE_P2P_IF)
7997 if (cfg->p2p_net == dev)
7998 dev = bcmcfg_to_prmry_ndev(cfg);
7999#endif
8000#endif
8001
8002 if (params->use_cts_prot >= 0) {
8003 }
8004
8005 if (params->use_short_preamble >= 0) {
8006 }
8007
8008 if (params->use_short_slot_time >= 0) {
8009 }
8010
8011 if (params->basic_rates) {
8012 }
8013
8014 if (params->ap_isolate >= 0) {
8015 ap_isolate = params->ap_isolate;
8016#ifdef PCIE_FULL_DONGLE
8017 ifidx = dhd_net2idx(dhd->info, dev);
8018
8019 if (ifidx != DHD_BAD_IF) {
8020 err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate);
8021 } else {
8022 WL_ERR(("Failed to set ap_isolate\n"));
8023 }
8024#else
8025 err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
8026 if (unlikely(err))
8027 {
8028 WL_ERR(("set ap_isolate Error (%d)\n", err));
8029 }
8030#endif /* PCIE_FULL_DONGLE */
8031 }
8032
8033 if (params->ht_opmode >= 0) {
8034 }
8035
8036
8037 return err;
8038}
8039
8040static s32
8041wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
8042 struct ieee80211_channel *chan,
8043 enum nl80211_channel_type channel_type)
8044{
8045 s32 _chan;
8046 chanspec_t chspec = 0;
8047 chanspec_t fw_chspec = 0;
8048 u32 bw = WL_CHANSPEC_BW_20;
8049#ifdef WL11ULB
8050 u32 ulb_bw = wl_cfg80211_get_ulb_bw(wl_get_cfg(dev), dev->ieee80211_ptr);
8051#endif /* WL11ULB */
8052
8053 s32 err = BCME_OK;
8054 s32 bw_cap = 0;
8055 struct {
8056 u32 band;
8057 u32 bw_cap;
8058 } param = {0, 0};
8059 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8060#if defined(CUSTOM_SET_CPUCORE) || (defined(WL_VIRTUAL_APSTA) && \
8061 defined(APSTA_RESTRICTED_CHANNEL))
8062 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
8063#endif /* CUSTOM_SET_CPUCORE || (WL_VIRTUAL_APSTA && APSTA_RESTRICTED_CHANNEL) */
8064
8065 dev = ndev_to_wlc_ndev(dev, cfg);
8066 _chan = ieee80211_frequency_to_channel(chan->center_freq);
d964ce36 8067#ifdef WL_EXT_IAPSTA
8068 _chan = wl_ext_iapsta_update_channel(dev, _chan);
8069#endif
010c3a89
RC
8070 printf("%s: netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
8071 __FUNCTION__, dev->ifindex, channel_type, _chan);
8072
8073
8074#if defined(WL_VIRTUAL_APSTA) && defined(APSTA_RESTRICTED_CHANNEL)
8075#define DEFAULT_2G_SOFTAP_CHANNEL 1
8076#define DEFAULT_5G_SOFTAP_CHANNEL 149
8077 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
8078 (dhd->op_mode & DHD_FLAG_CONCURR_STA_HOSTAP_MODE) ==
8079 DHD_FLAG_CONCURR_STA_HOSTAP_MODE &&
8080 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
8081 u32 *sta_chan = (u32 *)wl_read_prof(cfg,
8082 bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN);
8083 u32 sta_band = (*sta_chan > CH_MAX_2G_CHANNEL) ?
8084 IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
8085 if (chan->band == sta_band) {
8086 /* Do not try SCC in 5GHz if channel is not CH149 */
8087 _chan = (sta_band == IEEE80211_BAND_5GHZ &&
8088 *sta_chan != DEFAULT_5G_SOFTAP_CHANNEL) ?
8089 DEFAULT_2G_SOFTAP_CHANNEL : *sta_chan;
8090 WL_ERR(("target channel will be changed to %d\n", _chan));
8091 if (_chan <= CH_MAX_2G_CHANNEL) {
8092 bw = WL_CHANSPEC_BW_20;
8093 goto set_channel;
8094 }
8095 }
8096 }
8097#undef DEFAULT_2G_SOFTAP_CHANNEL
8098#undef DEFAULT_5G_SOFTAP_CHANNEL
8099#endif /* WL_VIRTUAL_APSTA && APSTA_RESTRICTED_CHANNEL */
8100
8101#ifdef WL11ULB
8102 if (ulb_bw) {
8103 WL_DBG(("[ULB] setting AP/GO BW to ulb_bw 0x%x \n", ulb_bw));
8104 bw = wl_cfg80211_ulbbw_to_ulbchspec(ulb_bw);
8105 goto set_channel;
8106 }
8107#endif /* WL11ULB */
8108 if (chan->band == IEEE80211_BAND_5GHZ) {
8109 param.band = WLC_BAND_5G;
8110 err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
8111 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
8112 if (err) {
8113 if (err != BCME_UNSUPPORTED) {
8114 WL_ERR(("bw_cap failed, %d\n", err));
8115 return err;
8116 } else {
8117 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
8118 if (err) {
8119 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
8120 }
8121 if (bw_cap != WLC_N_BW_20ALL)
8122 bw = WL_CHANSPEC_BW_40;
8123 }
8124 } else {
8125 if (WL_BW_CAP_80MHZ(cfg->ioctl_buf[0]))
8126 bw = WL_CHANSPEC_BW_80;
8127 else if (WL_BW_CAP_40MHZ(cfg->ioctl_buf[0]))
8128 bw = WL_CHANSPEC_BW_40;
8129 else
8130 bw = WL_CHANSPEC_BW_20;
8131
8132 }
8133
8134 } else if (chan->band == IEEE80211_BAND_2GHZ)
8135 bw = WL_CHANSPEC_BW_20;
8136set_channel:
8137 chspec = wf_channel2chspec(_chan, bw);
8138 if (wf_chspec_valid(chspec)) {
8139 fw_chspec = wl_chspec_host_to_driver(chspec);
8140 if (fw_chspec != INVCHANSPEC) {
8141 if ((err = wldev_iovar_setint(dev, "chanspec",
8142 fw_chspec)) == BCME_BADCHAN) {
8143 if (bw == WL_CHANSPEC_BW_80)
8144 goto change_bw;
8145 err = wldev_ioctl_set(dev, WLC_SET_CHANNEL,
8146 &_chan, sizeof(_chan));
8147 if (err < 0) {
8148 WL_ERR(("WLC_SET_CHANNEL error %d"
8149 "chip may not be supporting this channel\n", err));
8150 }
8151 } else if (err) {
8152 WL_ERR(("failed to set chanspec error %d\n", err));
8153 }
8154 } else {
8155 WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
8156 err = BCME_ERROR;
8157 }
8158 } else {
8159change_bw:
8160 if (bw == WL_CHANSPEC_BW_80)
8161 bw = WL_CHANSPEC_BW_40;
8162 else if (bw == WL_CHANSPEC_BW_40)
8163 bw = WL_CHANSPEC_BW_20;
8164 else
8165 bw = 0;
8166 if (bw)
8167 goto set_channel;
8168 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
8169 err = BCME_ERROR;
8170 }
8171#ifdef CUSTOM_SET_CPUCORE
8172 if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
8173 WL_DBG(("SoftAP mode do not need to set cpucore\n"));
8174 } else if (chspec & WL_CHANSPEC_BW_80) {
8175 /* SoftAp only mode do not need to set cpucore */
8176 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
8177 dev != bcmcfg_to_prmry_ndev(cfg)) {
8178 /* Soft AP on virtual Iface (AP+STA case) */
8179 dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
8180 dhd_set_cpucore(dhd, TRUE);
8181 } else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
8182 /* If P2P IF is vht80 */
8183 dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
8184 dhd_set_cpucore(dhd, TRUE);
8185 }
8186 }
8187#endif /* CUSTOM_SET_CPUCORE */
8188 if (!err && (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
8189 /* Update AP/GO operating channel */
8190 cfg->ap_oper_channel = ieee80211_frequency_to_channel(chan->center_freq);
8191 }
8192 return err;
8193}
8194
8195#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8196struct net_device *
8197wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
8198{
8199 struct net_info *_net_info, *next;
8200#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
8201#pragma GCC diagnostic push
8202#pragma GCC diagnostic ignored "-Wcast-qual"
8203#endif
8204 list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
8205 if (_net_info->ndev &&
8206 test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
8207 return _net_info->ndev;
8208 }
8209#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
8210#pragma GCC diagnostic pop
8211#endif
8212 return NULL;
8213}
8214#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8215
8216static s32
8217wl_validate_opensecurity(struct net_device *dev, s32 bssidx, bool privacy)
8218{
8219 s32 err = BCME_OK;
8220 u32 wpa_val;
8221 s32 wsec = 0;
8222
8223 /* set auth */
8224 err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
8225 if (err < 0) {
8226 WL_ERR(("auth error %d\n", err));
8227 return BCME_ERROR;
8228 }
8229
8230 if (privacy) {
8231 /* If privacy bit is set in open mode, then WEP would be enabled */
8232 wsec = WEP_ENABLED;
8233 WL_DBG(("Setting wsec to %d for WEP \n", wsec));
8234 }
8235
8236 /* set wsec */
8237 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
8238 if (err < 0) {
8239 WL_ERR(("wsec error %d\n", err));
8240 return BCME_ERROR;
8241 }
8242
8243 /* set upper-layer auth */
8244 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC)
8245 wpa_val = WPA_AUTH_NONE;
8246 else
8247 wpa_val = WPA_AUTH_DISABLED;
8248 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_val, bssidx);
8249 if (err < 0) {
8250 WL_ERR(("wpa_auth error %d\n", err));
8251 return BCME_ERROR;
8252 }
8253
8254 return 0;
8255}
8256
8257static s32
8258wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
8259{
8260 s32 len = 0;
8261 s32 err = BCME_OK;
8262 u16 auth = 0; /* d11 open authentication */
8263 u32 wsec;
8264 u32 pval = 0;
8265 u32 gval = 0;
8266 u32 wpa_auth = 0;
8267 wpa_suite_mcast_t *mcast;
8268 wpa_suite_ucast_t *ucast;
8269 wpa_suite_auth_key_mgmt_t *mgmt;
8270 wpa_pmkid_list_t *pmkid;
8271 int cnt = 0;
8272#ifdef MFP
8273 int mfp = 0;
8274 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8275#endif /* MFP */
8276
8277 u16 suite_count;
8278 u8 rsn_cap[2];
8279 u32 wme_bss_disable;
8280
8281 if (wpa2ie == NULL)
8282 goto exit;
8283
8284 WL_DBG(("Enter \n"));
8285 len = wpa2ie->len - WPA2_VERSION_LEN;
8286 /* check the mcast cipher */
8287 mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
8288 switch (mcast->type) {
8289 case WPA_CIPHER_NONE:
8290 gval = 0;
8291 break;
8292 case WPA_CIPHER_WEP_40:
8293 case WPA_CIPHER_WEP_104:
8294 gval = WEP_ENABLED;
8295 break;
8296 case WPA_CIPHER_TKIP:
8297 gval = TKIP_ENABLED;
8298 break;
8299 case WPA_CIPHER_AES_CCM:
8300 gval = AES_ENABLED;
8301 break;
8302 default:
8303 WL_ERR(("No Security Info\n"));
8304 break;
8305 }
8306 if ((len -= WPA_SUITE_LEN) <= 0)
8307 return BCME_BADLEN;
8308
8309 /* check the unicast cipher */
8310 ucast = (wpa_suite_ucast_t *)&mcast[1];
8311 suite_count = ltoh16_ua(&ucast->count);
8312 switch (ucast->list[0].type) {
8313 case WPA_CIPHER_NONE:
8314 pval = 0;
8315 break;
8316 case WPA_CIPHER_WEP_40:
8317 case WPA_CIPHER_WEP_104:
8318 pval = WEP_ENABLED;
8319 break;
8320 case WPA_CIPHER_TKIP:
8321 pval = TKIP_ENABLED;
8322 break;
8323 case WPA_CIPHER_AES_CCM:
8324 pval = AES_ENABLED;
8325 break;
8326 default:
8327 WL_ERR(("No Security Info\n"));
8328 }
8329 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
8330 return BCME_BADLEN;
8331
8332 /* FOR WPS , set SEC_OW_ENABLED */
8333 wsec = (pval | gval | SES_OW_ENABLED);
8334 /* check the AKM */
8335 mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
8336 suite_count = cnt = ltoh16_ua(&mgmt->count);
8337 while (cnt--) {
8338 switch (mgmt->list[cnt].type) {
8339 case RSN_AKM_NONE:
8340 wpa_auth |= WPA_AUTH_NONE;
8341 break;
8342 case RSN_AKM_UNSPECIFIED:
8343 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
8344 break;
8345 case RSN_AKM_PSK:
8346 wpa_auth |= WPA2_AUTH_PSK;
8347 break;
8348#ifdef MFP
8349 case RSN_AKM_MFP_PSK:
8350 wpa_auth |= WPA2_AUTH_PSK_SHA256;
8351 break;
8352 case RSN_AKM_MFP_1X:
8353 wpa_auth |= WPA2_AUTH_1X_SHA256;
8354 break;
8355#endif /* MFP */
8356 default:
8357 WL_ERR(("No Key Mgmt Info\n"));
8358 }
8359 }
8360
8361 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
8362 rsn_cap[0] = *(u8 *)&mgmt->list[suite_count];
8363 rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1);
8364
8365 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
8366 wme_bss_disable = 0;
8367 } else {
8368 wme_bss_disable = 1;
8369 }
8370
8371#ifdef MFP
8372 if (rsn_cap[0] & RSN_CAP_MFPR) {
8373 WL_DBG(("MFP Required \n"));
8374 mfp = WL_MFP_REQUIRED;
8375 /* Our firmware has requirement that WPA2_AUTH_PSK/WPA2_AUTH_UNSPECIFIED
8376 * be set, if SHA256 OUI is to be included in the rsn ie.
8377 */
8378 if (wpa_auth & WPA2_AUTH_PSK_SHA256) {
8379 wpa_auth |= WPA2_AUTH_PSK;
8380 } else if (wpa_auth & WPA2_AUTH_1X_SHA256) {
8381 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
8382 }
8383 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
8384 WL_DBG(("MFP Capable \n"));
8385 mfp = WL_MFP_CAPABLE;
8386 }
8387#endif /* MFP */
8388
8389 /* set wme_bss_disable to sync RSN Capabilities */
8390 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
8391 if (err < 0) {
8392 WL_ERR(("wme_bss_disable error %d\n", err));
8393 return BCME_ERROR;
8394 }
8395 } else {
8396 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
8397 }
8398
8399 len -= RSN_CAP_LEN;
8400 if (len >= WPA2_PMKID_COUNT_LEN) {
8401 pmkid = (wpa_pmkid_list_t *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
8402 cnt = ltoh16_ua(&pmkid->count);
8403 if (cnt != 0) {
8404 WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
8405 return BCME_ERROR;
8406 }
8407 /* since PMKID cnt is known to be 0 for AP, */
8408 /* so don't bother to send down this info to firmware */
8409 }
8410
8411#ifdef MFP
8412 len -= WPA2_PMKID_COUNT_LEN;
8413 if (len >= WPA_SUITE_LEN) {
8414 cfg->bip_pos = (u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN;
8415 } else {
8416 cfg->bip_pos = NULL;
8417 }
8418#endif
8419
8420 /* set auth */
8421 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
8422 if (err < 0) {
8423 WL_ERR(("auth error %d\n", err));
8424 return BCME_ERROR;
8425 }
8426
8427 /* set wsec */
8428 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
8429 if (err < 0) {
8430 WL_ERR(("wsec error %d\n", err));
8431 return BCME_ERROR;
8432 }
8433
8434#ifdef MFP
8435 cfg->mfp_mode = mfp;
8436#endif /* MFP */
8437
8438 /* set upper-layer auth */
8439 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
8440 if (err < 0) {
8441 WL_ERR(("wpa_auth error %d\n", err));
8442 return BCME_ERROR;
8443 }
8444exit:
8445 return 0;
8446}
8447
8448static s32
8449wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
8450{
8451 wpa_suite_mcast_t *mcast;
8452 wpa_suite_ucast_t *ucast;
8453 wpa_suite_auth_key_mgmt_t *mgmt;
8454 u16 auth = 0; /* d11 open authentication */
8455 u16 count;
8456 s32 err = BCME_OK;
8457 s32 len = 0;
8458 u32 i;
8459 u32 wsec;
8460 u32 pval = 0;
8461 u32 gval = 0;
8462 u32 wpa_auth = 0;
8463 u32 tmp = 0;
8464
8465 if (wpaie == NULL)
8466 goto exit;
8467 WL_DBG(("Enter \n"));
8468 len = wpaie->length; /* value length */
8469 len -= WPA_IE_TAG_FIXED_LEN;
8470 /* check for multicast cipher suite */
8471 if (len < WPA_SUITE_LEN) {
8472 WL_INFORM(("no multicast cipher suite\n"));
8473 goto exit;
8474 }
8475
8476 /* pick up multicast cipher */
8477 mcast = (wpa_suite_mcast_t *)&wpaie[1];
8478 len -= WPA_SUITE_LEN;
8479 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
8480 if (IS_WPA_CIPHER(mcast->type)) {
8481 tmp = 0;
8482 switch (mcast->type) {
8483 case WPA_CIPHER_NONE:
8484 tmp = 0;
8485 break;
8486 case WPA_CIPHER_WEP_40:
8487 case WPA_CIPHER_WEP_104:
8488 tmp = WEP_ENABLED;
8489 break;
8490 case WPA_CIPHER_TKIP:
8491 tmp = TKIP_ENABLED;
8492 break;
8493 case WPA_CIPHER_AES_CCM:
8494 tmp = AES_ENABLED;
8495 break;
8496 default:
8497 WL_ERR(("No Security Info\n"));
8498 }
8499 gval |= tmp;
8500 }
8501 }
8502 /* Check for unicast suite(s) */
8503 if (len < WPA_IE_SUITE_COUNT_LEN) {
8504 WL_INFORM(("no unicast suite\n"));
8505 goto exit;
8506 }
8507 /* walk thru unicast cipher list and pick up what we recognize */
8508 ucast = (wpa_suite_ucast_t *)&mcast[1];
8509 count = ltoh16_ua(&ucast->count);
8510 len -= WPA_IE_SUITE_COUNT_LEN;
8511 for (i = 0; i < count && len >= WPA_SUITE_LEN;
8512 i++, len -= WPA_SUITE_LEN) {
8513 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
8514 if (IS_WPA_CIPHER(ucast->list[i].type)) {
8515 tmp = 0;
8516 switch (ucast->list[i].type) {
8517 case WPA_CIPHER_NONE:
8518 tmp = 0;
8519 break;
8520 case WPA_CIPHER_WEP_40:
8521 case WPA_CIPHER_WEP_104:
8522 tmp = WEP_ENABLED;
8523 break;
8524 case WPA_CIPHER_TKIP:
8525 tmp = TKIP_ENABLED;
8526 break;
8527 case WPA_CIPHER_AES_CCM:
8528 tmp = AES_ENABLED;
8529 break;
8530 default:
8531 WL_ERR(("No Security Info\n"));
8532 }
8533 pval |= tmp;
8534 }
8535 }
8536 }
8537 len -= (count - i) * WPA_SUITE_LEN;
8538 /* Check for auth key management suite(s) */
8539 if (len < WPA_IE_SUITE_COUNT_LEN) {
8540 WL_INFORM((" no auth key mgmt suite\n"));
8541 goto exit;
8542 }
8543 /* walk thru auth management suite list and pick up what we recognize */
8544 mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
8545 count = ltoh16_ua(&mgmt->count);
8546 len -= WPA_IE_SUITE_COUNT_LEN;
8547 for (i = 0; i < count && len >= WPA_SUITE_LEN;
8548 i++, len -= WPA_SUITE_LEN) {
8549 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
8550 if (IS_WPA_AKM(mgmt->list[i].type)) {
8551 tmp = 0;
8552 switch (mgmt->list[i].type) {
8553 case RSN_AKM_NONE:
8554 tmp = WPA_AUTH_NONE;
8555 break;
8556 case RSN_AKM_UNSPECIFIED:
8557 tmp = WPA_AUTH_UNSPECIFIED;
8558 break;
8559 case RSN_AKM_PSK:
8560 tmp = WPA_AUTH_PSK;
8561 break;
8562 default:
8563 WL_ERR(("No Key Mgmt Info\n"));
8564 }
8565 wpa_auth |= tmp;
8566 }
8567 }
8568
8569 }
8570 /* FOR WPS , set SEC_OW_ENABLED */
8571 wsec = (pval | gval | SES_OW_ENABLED);
8572 /* set auth */
8573 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
8574 if (err < 0) {
8575 WL_ERR(("auth error %d\n", err));
8576 return BCME_ERROR;
8577 }
8578 /* set wsec */
8579 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
8580 if (err < 0) {
8581 WL_ERR(("wsec error %d\n", err));
8582 return BCME_ERROR;
8583 }
8584 /* set upper-layer auth */
8585 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
8586 if (err < 0) {
8587 WL_ERR(("wpa_auth error %d\n", err));
8588 return BCME_ERROR;
8589 }
8590exit:
8591 return 0;
8592}
8593
8594#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
8595static u32 wl_get_cipher_type(uint8 type)
8596{
8597 u32 ret = 0;
8598 switch (type) {
8599 case WPA_CIPHER_NONE:
8600 ret = 0;
8601 break;
8602 case WPA_CIPHER_WEP_40:
8603 case WPA_CIPHER_WEP_104:
8604 ret = WEP_ENABLED;
8605 break;
8606 case WPA_CIPHER_TKIP:
8607 ret = TKIP_ENABLED;
8608 break;
8609 case WPA_CIPHER_AES_CCM:
8610 ret = AES_ENABLED;
8611 break;
8612#ifdef BCMWAPI_WPI
8613 case WAPI_CIPHER_SMS4:
8614 ret = SMS4_ENABLED;
8615 break;
8616#endif
8617 default:
8618 WL_ERR(("No Security Info\n"));
8619 }
8620 return ret;
8621}
8622
8623static u32 wl_get_suite_auth_key_mgmt_type(uint8 type)
8624{
8625 u32 ret = 0;
8626 switch (type) {
8627 case RSN_AKM_NONE:
8628 ret = WPA_AUTH_NONE;
8629 break;
8630 case RSN_AKM_UNSPECIFIED:
8631 ret = WPA_AUTH_UNSPECIFIED;
8632 break;
8633 case RSN_AKM_PSK:
8634 ret = WPA_AUTH_PSK;
8635 break;
8636 default:
8637 WL_ERR(("No Key Mgmt Info\n"));
8638 }
8639 return ret;
8640}
8641
8642static u32 wl_get_suite_auth2_key_mgmt_type(uint8 type)
8643{
8644 u32 ret = 0;
8645 switch (type) {
8646 case RSN_AKM_NONE:
8647 ret = WPA_AUTH_NONE;
8648 break;
8649 case RSN_AKM_UNSPECIFIED:
8650 ret = WPA2_AUTH_UNSPECIFIED;
8651 break;
8652 case RSN_AKM_PSK:
8653 ret = WPA2_AUTH_PSK;
8654 break;
8655 default:
8656 WL_ERR(("No Key Mgmt Info\n"));
8657 }
8658 return ret;
8659}
8660
8661static s32
8662wl_validate_wpaie_wpa2ie(struct net_device *dev, wpa_ie_fixed_t *wpaie,
8663 bcm_tlv_t *wpa2ie, s32 bssidx)
8664{
8665 wpa_suite_mcast_t *mcast;
8666 wpa_suite_ucast_t *ucast;
8667 wpa_suite_auth_key_mgmt_t *mgmt;
8668 u16 auth = 0; /* d11 open authentication */
8669 u16 count;
8670 s32 err = BCME_OK;
8671 u32 wme_bss_disable;
8672 u16 suite_count;
8673 u8 rsn_cap[2];
8674 s32 len = 0;
8675 u32 i;
8676 u32 wsec1, wsec2, wsec;
8677 u32 pval = 0;
8678 u32 gval = 0;
8679 u32 wpa_auth = 0;
8680 u32 wpa_auth1 = 0;
8681 u32 wpa_auth2 = 0;
8682 u8* ptmp;
8683
8684 if (wpaie == NULL || wpa2ie == NULL)
8685 goto exit;
8686
8687 WL_DBG(("Enter \n"));
8688 len = wpaie->length; /* value length */
8689 len -= WPA_IE_TAG_FIXED_LEN;
8690 /* check for multicast cipher suite */
8691 if (len < WPA_SUITE_LEN) {
8692 WL_INFORM(("no multicast cipher suite\n"));
8693 goto exit;
8694 }
8695
8696 /* pick up multicast cipher */
8697 mcast = (wpa_suite_mcast_t *)&wpaie[1];
8698 len -= WPA_SUITE_LEN;
8699 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
8700 if (IS_WPA_CIPHER(mcast->type)) {
8701 gval |= wl_get_cipher_type(mcast->type);
8702 }
8703 }
8704 WL_ERR(("\nwpa ie validate\n"));
8705 WL_ERR(("wpa ie mcast cipher = 0x%X\n", gval));
8706
8707 /* Check for unicast suite(s) */
8708 if (len < WPA_IE_SUITE_COUNT_LEN) {
8709 WL_INFORM(("no unicast suite\n"));
8710 goto exit;
8711 }
8712
8713 /* walk thru unicast cipher list and pick up what we recognize */
8714 ucast = (wpa_suite_ucast_t *)&mcast[1];
8715 count = ltoh16_ua(&ucast->count);
8716 len -= WPA_IE_SUITE_COUNT_LEN;
8717 for (i = 0; i < count && len >= WPA_SUITE_LEN;
8718 i++, len -= WPA_SUITE_LEN) {
8719 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
8720 if (IS_WPA_CIPHER(ucast->list[i].type)) {
8721 pval |= wl_get_cipher_type(ucast->list[i].type);
8722 }
8723 }
8724 }
8725 WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count, pval));
8726
8727 /* FOR WPS , set SEC_OW_ENABLED */
8728 wsec1 = (pval | gval | SES_OW_ENABLED);
8729 WL_ERR(("wpa ie wsec = 0x%X\n", wsec1));
8730
8731 len -= (count - i) * WPA_SUITE_LEN;
8732 /* Check for auth key management suite(s) */
8733 if (len < WPA_IE_SUITE_COUNT_LEN) {
8734 WL_INFORM((" no auth key mgmt suite\n"));
8735 goto exit;
8736 }
8737 /* walk thru auth management suite list and pick up what we recognize */
8738 mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
8739 count = ltoh16_ua(&mgmt->count);
8740 len -= WPA_IE_SUITE_COUNT_LEN;
8741 for (i = 0; i < count && len >= WPA_SUITE_LEN;
8742 i++, len -= WPA_SUITE_LEN) {
8743 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
8744 if (IS_WPA_AKM(mgmt->list[i].type)) {
8745
8746 wpa_auth1 |= wl_get_suite_auth_key_mgmt_type(mgmt->list[i].type);
8747 }
8748 }
8749
8750 }
8751 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth1));
8752 WL_ERR(("\nwpa2 ie validate\n"));
8753
8754 pval = 0;
8755 gval = 0;
8756 len = wpa2ie->len;
8757 /* check the mcast cipher */
8758 mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
8759 ptmp = mcast->oui;
8760 gval = wl_get_cipher_type(ptmp[DOT11_OUI_LEN]);
8761
8762 WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval));
8763 if ((len -= WPA_SUITE_LEN) <= 0)
8764 {
8765 WL_ERR(("P:wpa2 ie len[%d]", len));
8766 return BCME_BADLEN;
8767 }
8768
8769 /* check the unicast cipher */
8770 ucast = (wpa_suite_ucast_t *)&mcast[1];
8771 suite_count = ltoh16_ua(&ucast->count);
8772 WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count));
8773 pval |= wl_get_cipher_type(ucast->list[0].type);
8774
8775 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
8776 return BCME_BADLEN;
8777
8778 WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval));
8779
8780 /* FOR WPS , set SEC_OW_ENABLED */
8781 wsec2 = (pval | gval | SES_OW_ENABLED);
8782 WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2));
8783
8784 /* check the AKM */
8785 mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
8786 suite_count = ltoh16_ua(&mgmt->count);
8787 ptmp = (u8 *)&mgmt->list[0];
8788 wpa_auth2 = wl_get_suite_auth2_key_mgmt_type(ptmp[DOT11_OUI_LEN]);
8789 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth2));
8790
8791 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
8792 rsn_cap[0] = *(u8 *)&mgmt->list[suite_count];
8793 rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1);
8794 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
8795 wme_bss_disable = 0;
8796 } else {
8797 wme_bss_disable = 1;
8798 }
8799 WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap[0], wme_bss_disable));
8800
8801 /* set wme_bss_disable to sync RSN Capabilities */
8802 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
8803 if (err < 0) {
8804 WL_ERR(("wme_bss_disable error %d\n", err));
8805 return BCME_ERROR;
8806 }
8807 } else {
8808 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
8809 }
8810
8811 wsec = (wsec1 | wsec2);
8812 wpa_auth = (wpa_auth1 | wpa_auth2);
8813 WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec, wpa_auth));
8814
8815 /* set auth */
8816 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
8817 if (err < 0) {
8818 WL_ERR(("auth error %d\n", err));
8819 return BCME_ERROR;
8820 }
8821 /* set wsec */
8822 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
8823 if (err < 0) {
8824 WL_ERR(("wsec error %d\n", err));
8825 return BCME_ERROR;
8826 }
8827 /* set upper-layer auth */
8828 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
8829 if (err < 0) {
8830 WL_ERR(("wpa_auth error %d\n", err));
8831 return BCME_ERROR;
8832 }
8833exit:
8834 return 0;
8835}
8836#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
8837
8838static s32
8839wl_cfg80211_bcn_validate_sec(
8840 struct net_device *dev,
8841 struct parsed_ies *ies,
8842 u32 dev_role,
8843 s32 bssidx,
8844 bool privacy)
8845{
8846 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8847 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
8848
8849 if (!bss) {
8850 WL_ERR(("cfgbss is NULL \n"));
8851 return BCME_ERROR;
8852 }
8853
8854 if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
8855 /* For P2P GO, the sec type is WPA2-PSK */
8856 WL_DBG(("P2P GO: validating wpa2_ie"));
8857 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0)
8858 return BCME_ERROR;
8859
8860 } else if (dev_role == NL80211_IFTYPE_AP) {
8861
8862 WL_DBG(("SoftAP: validating security"));
8863 /* If wpa2_ie or wpa_ie is present validate it */
8864
8865#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
8866 if ((ies->wpa_ie != NULL && ies->wpa2_ie != NULL)) {
8867 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie, ies->wpa2_ie, bssidx) < 0) {
8868 bss->security_mode = false;
8869 return BCME_ERROR;
8870 }
8871 }
8872 else {
8873#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
8874 if ((ies->wpa2_ie || ies->wpa_ie) &&
8875 ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
8876 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
8877 bss->security_mode = false;
8878 return BCME_ERROR;
8879 }
8880
8881 bss->security_mode = true;
8882 if (bss->rsn_ie) {
8883 kfree(bss->rsn_ie);
8884 bss->rsn_ie = NULL;
8885 }
8886 if (bss->wpa_ie) {
8887 kfree(bss->wpa_ie);
8888 bss->wpa_ie = NULL;
8889 }
8890 if (bss->wps_ie) {
8891 kfree(bss->wps_ie);
8892 bss->wps_ie = NULL;
8893 }
8894 if (ies->wpa_ie != NULL) {
8895 /* WPAIE */
8896 bss->rsn_ie = NULL;
8897 bss->wpa_ie = kmemdup(ies->wpa_ie,
8898 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
8899 GFP_KERNEL);
8900 } else if (ies->wpa2_ie != NULL) {
8901 /* RSNIE */
8902 bss->wpa_ie = NULL;
8903 bss->rsn_ie = kmemdup(ies->wpa2_ie,
8904 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
8905 GFP_KERNEL);
8906 }
8907#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
8908 }
8909#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
8910 if (!ies->wpa2_ie && !ies->wpa_ie) {
8911 wl_validate_opensecurity(dev, bssidx, privacy);
8912 bss->security_mode = false;
8913 }
8914
8915 if (ies->wps_ie) {
8916 bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
8917 }
8918 }
8919
8920 return 0;
8921
8922}
8923
8924#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
8925static s32 wl_cfg80211_bcn_set_params(
8926 struct cfg80211_ap_settings *info,
8927 struct net_device *dev,
8928 u32 dev_role, s32 bssidx)
8929{
8930 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8931 s32 err = BCME_OK;
8932
8933 WL_DBG(("interval (%d) \ndtim_period (%d) \n",
8934 info->beacon_interval, info->dtim_period));
8935
8936 if (info->beacon_interval) {
8937 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
8938 &info->beacon_interval, sizeof(s32))) < 0) {
8939 WL_ERR(("Beacon Interval Set Error, %d\n", err));
8940 return err;
8941 }
8942 }
8943
8944 if (info->dtim_period) {
8945 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
8946 &info->dtim_period, sizeof(s32))) < 0) {
8947 WL_ERR(("DTIM Interval Set Error, %d\n", err));
8948 return err;
8949 }
8950 }
8951
8952 if ((info->ssid) && (info->ssid_len > 0) &&
8953 (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
8954 WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
8955 if (dev_role == NL80211_IFTYPE_AP) {
8956 /* Store the hostapd SSID */
8957 memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
8958 memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
8959 cfg->hostapd_ssid.SSID_len = info->ssid_len;
8960 } else {
8961 /* P2P GO */
8962 memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
8963 memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
8964 cfg->p2p->ssid.SSID_len = info->ssid_len;
8965 }
8966 }
8967
8968 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) {
8969 if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
8970 WL_ERR(("failed to set hidden : %d\n", err));
8971 WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
8972 }
8973
8974 return err;
8975}
8976#endif
8977
8978static s32
8979wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies)
8980{
8981 s32 err = BCME_OK;
8982
8983 memset(ies, 0, sizeof(struct parsed_ies));
8984
8985 /* find the WPSIE */
8986 if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
8987 WL_DBG(("WPSIE in beacon \n"));
8988 ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
8989 } else {
8990 WL_DBG(("No WPSIE in beacon \n"));
8991 }
8992
8993 /* find the RSN_IE */
8994 if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len,
8995 DOT11_MNG_RSN_ID)) != NULL) {
8996 WL_DBG((" WPA2 IE found\n"));
8997 ies->wpa2_ie_len = ies->wpa2_ie->len;
8998 }
8999
9000 /* find the WPA_IE */
9001 if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
9002 WL_DBG((" WPA found\n"));
9003 ies->wpa_ie_len = ies->wpa_ie->length;
9004 }
9005
9006 return err;
9007
9008}
9009static s32
9010wl_cfg80211_set_ap_role(
9011 struct bcm_cfg80211 *cfg,
9012 struct net_device *dev)
9013{
9014 s32 err = BCME_OK;
9015 s32 infra = 1;
9016 s32 ap = 1;
9017 s32 pm;
9018 s32 is_rsdb_supported = BCME_ERROR;
9019 s32 bssidx;
9020 s32 apsta = 0;
9021
9022 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
9023 if (is_rsdb_supported < 0)
9024 return (-ENODEV);
9025
9026 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
9027 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
9028 return -EINVAL;
9029 }
9030
9031 /* AP on primary Interface */
9032 if (bssidx == 0) {
9033 if (is_rsdb_supported) {
9034 if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
9035 NL80211_IFTYPE_AP, 0, NULL)) < 0) {
9036 WL_ERR(("wl add_del_bss returned error:%d\n", err));
9037 return err;
9038 }
9039 } else if (is_rsdb_supported == 0) {
9040 /* AP mode switch not supported. Try setting up AP explicitly */
9041 err = wldev_iovar_getint(dev, "apsta", (s32 *)&apsta);
9042 if (unlikely(err)) {
9043 WL_ERR(("Could not get apsta %d\n", err));
9044 }
9045 if (1) { // terence: fix me
9046 /* If apsta is not set, set it */
9047 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
9048 if (err < 0) {
9049 WL_ERR(("WLC_DOWN error %d\n", err));
9050 return err;
9051 }
9052 err = wldev_iovar_setint(dev, "apsta", 0);
9053 if (err < 0) {
9054 WL_ERR(("wl apsta 0 error %d\n", err));
9055 return err;
9056 }
9057 if ((err = wldev_ioctl_set(dev,
9058 WLC_SET_AP, &ap, sizeof(s32))) < 0) {
9059 WL_ERR(("setting AP mode failed %d \n", err));
9060 return err;
9061 }
9062 }
9063 }
9064
9065 pm = 0;
9066 if ((err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm))) != 0) {
9067 WL_ERR(("wl PM 0 returned error:%d\n", err));
9068 /* Ignore error, if any */
9069 err = BCME_OK;
9070 }
9071 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
9072 if (err < 0) {
9073 WL_ERR(("SET INFRA error %d\n", err));
9074 return err;
9075 }
9076 } else {
9077 WL_DBG(("Bringup SoftAP on virtual Interface bssidx:%d \n", bssidx));
9078 if ((err = wl_cfg80211_add_del_bss(cfg, dev,
9079 bssidx, NL80211_IFTYPE_AP, 0, NULL)) < 0) {
9080 WL_ERR(("wl bss ap returned error:%d\n", err));
9081 return err;
9082 }
9083 }
9084
9085 /* On success, mark AP creation in progress. */
9086 wl_set_drv_status(cfg, AP_CREATING, dev);
9087 return 0;
9088}
9089
9090
9091/* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
9092#define MAX_AP_LINK_WAIT_TIME 10000
9093static s32
9094wl_cfg80211_bcn_bringup_ap(
9095 struct net_device *dev,
9096 struct parsed_ies *ies,
9097 u32 dev_role, s32 bssidx)
9098{
9099 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
9100 struct wl_join_params join_params;
9101 bool is_bssup = false;
9102 s32 infra = 1;
9103 s32 join_params_size = 0;
9104 s32 ap = 1;
9105 s32 wsec;
dfb0f3ae
RC
9106#ifdef WLMESH
9107 bool retried = false;
9108#endif
010c3a89
RC
9109#ifdef SOFTAP_UAPSD_OFF
9110 uint32 wme_apsd = 0;
9111#endif /* SOFTAP_UAPSD_OFF */
9112 s32 err = BCME_OK;
9113 s32 is_rsdb_supported = BCME_ERROR;
9114 u32 timeout;
9115#if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
9116 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
9117#endif /* DHD_DEBUG && DHD_FW_COREDUMP */
9118
9119 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
9120 if (is_rsdb_supported < 0)
9121 return (-ENODEV);
9122
9123 WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role, bssidx, dev->name));
9124
9125 /* Common code for SoftAP and P2P GO */
9126 wl_clr_drv_status(cfg, AP_CREATED, dev);
9127
9128 /* Make sure INFRA is set for AP/GO */
9129 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
9130 if (err < 0) {
9131 WL_ERR(("SET INFRA error %d\n", err));
9132 goto exit;
9133 }
9134
9135 /* Do abort scan before creating GO */
9136 wl_cfg80211_scan_abort(cfg);
9137
9138 if (dev_role == NL80211_IFTYPE_P2P_GO) {
9139 is_bssup = wl_cfg80211_bss_isup(dev, bssidx);
9140 if (!is_bssup && (ies->wpa2_ie != NULL)) {
9141
9142 err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid,
9143 sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
9144 bssidx, &cfg->ioctl_buf_sync);
9145 if (err < 0) {
9146 WL_ERR(("GO SSID setting error %d\n", err));
9147 goto exit;
9148 }
9149
9150 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
9151 WL_ERR(("GO Bring up error %d\n", err));
9152 goto exit;
9153 }
9154 } else
9155 WL_DBG(("Bss is already up\n"));
9156 } else if (dev_role == NL80211_IFTYPE_AP) {
9157
9158// if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
9159 /* Make sure fw is in proper state */
9160 err = wl_cfg80211_set_ap_role(cfg, dev);
9161 if (unlikely(err)) {
9162 WL_ERR(("set ap role failed!\n"));
9163 goto exit;
9164 }
9165// }
9166
9167 /* Device role SoftAP */
9168 WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
9169 /* Clear the status bit after use */
9170 wl_clr_drv_status(cfg, AP_CREATING, dev);
9171
9172
9173#ifdef SOFTAP_UAPSD_OFF
9174 err = wldev_iovar_setbuf_bsscfg(dev, "wme_apsd", &wme_apsd, sizeof(wme_apsd),
9175 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
9176 if (err < 0) {
9177 WL_ERR(("failed to disable uapsd, error=%d\n", err));
9178 }
9179#endif /* SOFTAP_UAPSD_OFF */
9180 dhd_conf_set_wme(cfg->pub, 1);
9181
9182 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
9183 if (unlikely(err)) {
9184 WL_ERR(("WLC_UP error (%d)\n", err));
9185 goto exit;
9186 }
9187
9188#ifdef MFP
9189 if (cfg->bip_pos) {
9190 err = wldev_iovar_setbuf_bsscfg(dev, "bip",
9191 (void *)(cfg->bip_pos), WPA_SUITE_LEN, cfg->ioctl_buf,
9192 WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
9193 if (err < 0) {
9194 WL_ERR(("bip set error %d\n", err));
9195 if (wl_customer6_legacy_chip_check(cfg,
9196 bcmcfg_to_prmry_ndev(cfg))) {
9197 /* Ignore bip error: Some older firmwares doesn't
9198 * support bip iovar/ return BCME_NOTUP while trying
9199 * to set bip from AP bring up context. These firmares
9200 * include bip in RSNIE by default. So its okay to ignore
9201 * the error.
9202 */
9203 err = BCME_OK;
9204 } else {
9205 goto exit;
9206 }
9207 }
9208 }
9209#endif /* MFP */
9210
9211 err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec);
9212 if (unlikely(err)) {
9213 WL_ERR(("Could not get wsec %d\n", err));
9214 goto exit;
9215 }
9216 if ((wsec == WEP_ENABLED) && cfg->wep_key.len) {
9217 WL_DBG(("Applying buffered WEP KEY \n"));
9218 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &cfg->wep_key,
9219 sizeof(struct wl_wsec_key), cfg->ioctl_buf,
9220 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
9221 /* clear the key after use */
9222 memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
9223 if (unlikely(err)) {
9224 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
9225 goto exit;
9226 }
9227 }
9228
9229#ifdef MFP
9230 if (cfg->mfp_mode) {
9231 /* This needs to go after wsec otherwise the wsec command will
9232 * overwrite the values set by MFP
9233 */
9234 err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx);
9235 if (err < 0) {
9236 WL_ERR(("MFP Setting failed. ret = %d \n", err));
9237 /* If fw doesn't support mfp, Ignore the error */
9238 if (err != BCME_UNSUPPORTED) {
9239 goto exit;
9240 }
9241 }
9242 }
9243#endif /* MFP */
9244
dfb0f3ae
RC
9245#ifdef WLMESH
9246ssid_retry:
9247#endif
010c3a89
RC
9248 memset(&join_params, 0, sizeof(join_params));
9249 /* join parameters starts with ssid */
9250 join_params_size = sizeof(join_params.ssid);
9251 join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
9252 (uint32)DOT11_MAX_SSID_LEN);
9253 memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
9254 join_params.ssid.SSID_len);
9255 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
9256
9257 /* create softap */
9258 if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
9259 join_params_size)) != 0) {
d964ce36 9260 WL_ERR(("SoftAP/GO set ssid failed! %d\n", err));
010c3a89
RC
9261 goto exit;
9262 } else {
9263 WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
9264 }
9265
9266 if (bssidx != 0) {
9267 /* AP on Virtual Interface */
9268 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
9269 WL_ERR(("AP Bring up error %d\n", err));
9270 goto exit;
9271 }
9272 }
9273
9274 }
9275
9276 /* Wait for Linkup event to mark successful AP/GO bring up */
9277 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
9278 wl_get_drv_status(cfg, AP_CREATED, dev), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
9279 if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) {
dfb0f3ae
RC
9280#ifdef WLMESH
9281 if (!retried) {
9282 retried = true;
9283 WL_ERR(("Link up didn't come for AP interface. Try to set ssid again to recover it! \n"));
9284 goto ssid_retry;
9285 }
9286#endif
010c3a89
RC
9287 WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
9288 if (timeout == -ERESTARTSYS) {
9289 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
9290 err = -ERESTARTSYS;
9291 goto exit;
9292 }
9293#if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
9294 if (dhdp->memdump_enabled) {
9295 dhdp->memdump_type = DUMP_TYPE_AP_LINKUP_FAILURE;
9296 dhd_bus_mem_dump(dhdp);
9297 }
9298#endif /* DHD_DEBUG && DHD_FW_COREDUMP */
9299 err = -ENODEV;
9300 goto exit;
9301 }
9302
9303exit:
9304 if (cfg->wep_key.len) {
9305 memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
9306 }
9307
9308#ifdef MFP
9309 if (cfg->mfp_mode) {
9310 cfg->mfp_mode = 0;
9311 }
9312
9313 if (cfg->bip_pos) {
9314 cfg->bip_pos = NULL;
9315 }
9316#endif /* MFP */
9317
9318 return err;
9319}
9320
9321#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
9322s32
9323wl_cfg80211_parse_ap_ies(
9324 struct net_device *dev,
9325 struct cfg80211_beacon_data *info,
9326 struct parsed_ies *ies)
9327{
9328 struct parsed_ies prb_ies;
9329 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
9330 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
9331 const u8 *vndr = NULL;
9332 u32 vndr_ie_len = 0;
9333 s32 err = BCME_OK;
9334
9335 /* Parse Beacon IEs */
9336#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
9337#pragma GCC diagnostic push
9338#pragma GCC diagnostic ignored "-Wcast-qual"
9339#endif
9340 if (wl_cfg80211_parse_ies((u8 *)info->tail,
9341 info->tail_len, ies) < 0) {
9342 WL_ERR(("Beacon get IEs failed \n"));
9343 err = -EINVAL;
9344 goto fail;
9345 }
9346#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
9347#pragma GCC diagnostic pop
9348#endif
9349 vndr = (const u8 *)info->proberesp_ies;
9350 vndr_ie_len = info->proberesp_ies_len;
9351
9352 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
9353 /* SoftAP mode */
9354 const struct ieee80211_mgmt *mgmt;
9355 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
9356 if (mgmt != NULL) {
9357 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
9358 vndr_ie_len = info->probe_resp_len -
9359 offsetof(const struct ieee80211_mgmt, u.probe_resp.variable);
9360 }
9361 }
9362#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
9363#pragma GCC diagnostic push
9364#pragma GCC diagnostic ignored "-Wcast-qual"
9365#endif
9366 /* Parse Probe Response IEs */
9367 if (wl_cfg80211_parse_ies((u8 *)vndr, vndr_ie_len, &prb_ies) < 0) {
9368 WL_ERR(("PROBE RESP get IEs failed \n"));
9369 err = -EINVAL;
9370 }
9371#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
9372#pragma GCC diagnostic pop
9373#endif
9374fail:
9375
9376 return err;
9377}
9378
9379s32
9380wl_cfg80211_set_ies(
9381 struct net_device *dev,
9382 struct cfg80211_beacon_data *info,
9383 s32 bssidx)
9384{
9385 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
9386 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
9387 const u8 *vndr = NULL;
9388 u32 vndr_ie_len = 0;
9389 s32 err = BCME_OK;
9390
9391 /* Set Beacon IEs to FW */
9392 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
9393 VNDR_IE_BEACON_FLAG, (const u8 *)info->tail,
9394 info->tail_len)) < 0) {
9395 WL_ERR(("Set Beacon IE Failed \n"));
9396 } else {
9397 WL_DBG(("Applied Vndr IEs for Beacon \n"));
9398 }
9399
9400 vndr = (const u8 *)info->proberesp_ies;
9401 vndr_ie_len = info->proberesp_ies_len;
9402
9403 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
9404 /* SoftAP mode */
9405 const struct ieee80211_mgmt *mgmt;
9406 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
9407 if (mgmt != NULL) {
9408 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
9409 vndr_ie_len = info->probe_resp_len -
9410 offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
9411 }
9412 }
9413
9414 /* Set Probe Response IEs to FW */
9415 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
9416 VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
9417 WL_ERR(("Set Probe Resp IE Failed \n"));
9418 } else {
9419 WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
9420 }
9421
9422 return err;
9423}
9424#endif
9425
9426static s32 wl_cfg80211_hostapd_sec(
9427 struct net_device *dev,
9428 struct parsed_ies *ies,
9429 s32 bssidx)
9430{
9431 bool update_bss = 0;
9432 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
9433 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
9434
9435 if (!bss) {
9436 WL_ERR(("cfgbss is NULL \n"));
9437 return -EINVAL;
9438 }
9439
9440 if (ies->wps_ie) {
9441 if (bss->wps_ie &&
9442 memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
9443 WL_DBG((" WPS IE is changed\n"));
9444 kfree(bss->wps_ie);
9445 bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
9446 } else if (bss->wps_ie == NULL) {
9447 WL_DBG((" WPS IE is added\n"));
9448 bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
9449 }
9450
9451 if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
9452 if (!bss->security_mode) {
9453 /* change from open mode to security mode */
9454 update_bss = true;
9455 if (ies->wpa_ie != NULL) {
9456 bss->wpa_ie = kmemdup(ies->wpa_ie,
9457 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
9458 GFP_KERNEL);
9459 } else {
9460 bss->rsn_ie = kmemdup(ies->wpa2_ie,
9461 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
9462 GFP_KERNEL);
9463 }
9464 } else if (bss->wpa_ie) {
9465 /* change from WPA2 mode to WPA mode */
9466 if (ies->wpa_ie != NULL) {
9467 update_bss = true;
9468 kfree(bss->rsn_ie);
9469 bss->rsn_ie = NULL;
9470 bss->wpa_ie = kmemdup(ies->wpa_ie,
9471 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
9472 GFP_KERNEL);
9473 } else if (memcmp(bss->rsn_ie,
9474 ies->wpa2_ie, ies->wpa2_ie->len
9475 + WPA_RSN_IE_TAG_FIXED_LEN)) {
9476 update_bss = true;
9477 kfree(bss->rsn_ie);
9478 bss->rsn_ie = kmemdup(ies->wpa2_ie,
9479 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
9480 GFP_KERNEL);
9481 bss->wpa_ie = NULL;
9482 }
9483 }
9484 if (update_bss) {
9485 bss->security_mode = true;
9486 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
9487 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
9488 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
9489 return BCME_ERROR;
9490 }
9491 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
9492 }
9493 }
9494 } else {
9495 WL_ERR(("No WPSIE in beacon \n"));
9496 }
9497 return 0;
9498}
9499
9500#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
9501 2, 0))
9502static s32
9503#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9504wl_cfg80211_del_station(
9505 struct wiphy *wiphy, struct net_device *ndev,
9506 struct station_del_parameters *params)
9507#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
9508wl_cfg80211_del_station(
9509 struct wiphy *wiphy,
9510 struct net_device *ndev,
9511 const u8* mac_addr)
9512#else
9513wl_cfg80211_del_station(
9514 struct wiphy *wiphy,
9515 struct net_device *ndev,
9516 u8* mac_addr)
9517#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9518{
9519 struct net_device *dev;
9520 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9521 scb_val_t scb_val;
9522 s8 eabuf[ETHER_ADDR_STR_LEN];
9523 int err;
9524 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
9525 sizeof(struct ether_addr) + sizeof(uint)] = {0};
9526 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9527 int num_associated = 0;
9528
9529#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9530 const u8 *mac_addr = params->mac;
9531#ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
9532 u16 rc = params->reason_code;
9533#endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
9534#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
32c27b7a 9535
010c3a89
RC
9536 WL_DBG(("Entry\n"));
9537 if (mac_addr == NULL) {
9538 WL_DBG(("mac_addr is NULL ignore it\n"));
9539 return 0;
9540 }
9541
9542 dev = ndev_to_wlc_ndev(ndev, cfg);
9543
9544 if (p2p_is_on(cfg)) {
9545 /* Suspend P2P discovery search-listen to prevent it from changing the
9546 * channel.
9547 */
9548 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9549 WL_ERR(("Can not disable discovery mode\n"));
9550 return -EFAULT;
9551 }
9552 }
32c27b7a
RC
9553 err = wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
9554 WL_EXT_STATUS_DELETE_GC, (void *)mac_addr);
9555 if (err) {
9556 return 0;
9557 }
010c3a89
RC
9558
9559 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9560 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
9561 assoc_maclist, sizeof(mac_buf));
9562 if (err < 0)
9563 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9564 else
9565 num_associated = assoc_maclist->count;
9566
9567 memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
9568#ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
9569#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9570 if (rc == DOT11_RC_8021X_AUTH_FAIL) {
9571 WL_ERR(("deauth will be sent at F/W\n"));
9572 scb_val.val = DOT11_RC_8021X_AUTH_FAIL;
9573 } else {
9574#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9575#endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
d964ce36 9576#ifndef BCMDBUS
9577 dhd_wait_pend8021x(dev);
9578#endif /* !BCMDBUS */
010c3a89
RC
9579 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
9580 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
9581 sizeof(scb_val_t));
9582 if (err < 0)
9583 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
9584#ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
9585#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9586 }
9587#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9588#endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
9589 printf("%s: Disconnect STA : %s scb_val.val %d\n", __FUNCTION__,
9590 bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf),
9591 scb_val.val);
9592
9593 if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
9594 wl_delay(400);
9595
9596 return 0;
9597}
9598
9599static s32
9600#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
9601wl_cfg80211_change_station(
9602 struct wiphy *wiphy,
9603 struct net_device *dev,
9604 const u8 *mac,
9605 struct station_parameters *params)
9606#else
9607wl_cfg80211_change_station(
9608 struct wiphy *wiphy,
9609 struct net_device *dev,
9610 u8 *mac,
9611 struct station_parameters *params)
9612#endif
9613{
9614 int err;
9615#if defined(WL_ENABLE_P2P_IF)
9616 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9617#endif
9618 struct net_device *ndev = ndev_to_wlc_ndev(dev, cfg);
9619
9620 WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x "
9621 "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac),
9622 params->sta_flags_mask, params->sta_flags_set, ndev->name));
9623
9624 /* Processing only authorize/de-authorize flag for now */
9625 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
9626 WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
9627 return -ENOTSUPP;
9628 }
9629
9630 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
9631#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
9632 err = wldev_ioctl_set(ndev, WLC_SCB_DEAUTHORIZE, (u8 *)mac, ETH_ALEN);
9633#else
9634 err = wldev_ioctl_set(ndev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN);
9635#endif
9636 if (err)
9637 WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
9638 return err;
9639 }
9640
9641#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
9642 err = wldev_ioctl_set(ndev, WLC_SCB_AUTHORIZE, (u8 *)mac, ETH_ALEN);
9643#else
9644 err = wldev_ioctl_set(ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN);
9645#endif
9646 if (err)
9647 WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
9648#ifdef DHD_LOSSLESS_ROAMING
9649 wl_del_roam_timeout(cfg);
9650#endif
9651 return err;
9652}
9653#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
9654
9655static s32
9656wl_cfg80211_set_scb_timings(
9657 struct bcm_cfg80211 *cfg,
9658 struct net_device *dev)
9659{
9660 int err;
9661 u32 ps_pretend;
9662 wl_scb_probe_t scb_probe;
9663
9664 bzero(&scb_probe, sizeof(wl_scb_probe_t));
9665 scb_probe.scb_timeout = WL_SCB_TIMEOUT;
9666 scb_probe.scb_activity_time = WL_SCB_ACTIVITY_TIME;
9667 scb_probe.scb_max_probe = WL_SCB_MAX_PROBE;
9668 err = wldev_iovar_setbuf(dev, "scb_probe", (void *)&scb_probe,
9669 sizeof(wl_scb_probe_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
9670 &cfg->ioctl_buf_sync);
9671 if (unlikely(err)) {
9672 WL_ERR(("set 'scb_probe' failed, error = %d\n", err));
9673 return err;
9674 }
9675
9676 ps_pretend = MAX(WL_SCB_MAX_PROBE / 2, WL_MIN_PSPRETEND_THRESHOLD);
9677 err = wldev_iovar_setint(dev, "pspretend_threshold", ps_pretend);
9678 if (unlikely(err)) {
9679 if (err == BCME_UNSUPPORTED) {
9680 /* Ignore error if fw doesn't support the iovar */
9681 WL_DBG(("wl pspretend_threshold %d set error %d\n",
9682 ps_pretend, err));
9683 } else {
9684 WL_ERR(("wl pspretend_threshold %d set error %d\n",
9685 ps_pretend, err));
9686 return err;
9687 }
9688 }
9689
9690 return 0;
9691}
9692
9693#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
9694static s32
9695wl_cfg80211_start_ap(
9696 struct wiphy *wiphy,
9697 struct net_device *dev,
9698 struct cfg80211_ap_settings *info)
9699{
9700 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9701 s32 err = BCME_OK;
9702 struct parsed_ies ies;
9703 s32 bssidx = 0;
9704 u32 dev_role = 0;
9705 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
dfb0f3ae
RC
9706#ifdef WLMESH
9707 struct wl_join_params join_params;
9708 s32 join_params_size = 0;
9709#endif
010c3a89
RC
9710
9711 WL_DBG(("Enter \n"));
9712
9713#if defined(SUPPORT_RANDOM_MAC_SCAN)
9714 wl_cfg80211_set_random_mac(dev, FALSE);
9715#endif /* SUPPORT_RANDOM_MAC_SCAN */
9716
9717 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
9718 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
9719 return BCME_ERROR;
9720 }
9721
9722 if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
9723 dev_role = NL80211_IFTYPE_P2P_GO;
9724 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
9725 dev_role = NL80211_IFTYPE_AP;
9726 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
9727 err = dhd_ndo_enable(dhd, FALSE);
9728 WL_DBG(("%s: Disabling NDO on Hostapd mode %d\n", __FUNCTION__, err));
9729 if (err) {
9730 WL_ERR(("%s: Disabling NDO Failed %d\n", __FUNCTION__, err));
9731 }
9732#ifdef PKT_FILTER_SUPPORT
9733 /* Disable packet filter */
9734 if (dhd->early_suspended) {
9735 WL_ERR(("Disable pkt_filter\n"));
9736 dhd_enable_packet_filter(0, dhd);
9737 }
9738#endif /* PKT_FILTER_SUPPORT */
9739#ifdef ARP_OFFLOAD_SUPPORT
9740 /* IF SoftAP is enabled, disable arpoe */
9741 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
9742 dhd_arp_offload_set(dhd, 0);
9743 dhd_arp_offload_enable(dhd, FALSE);
9744 }
9745#endif /* ARP_OFFLOAD_SUPPORT */
9746#ifdef SUPPORT_SET_CAC
9747 wl_cfg80211_set_cac(cfg, 0);
9748#endif /* SUPPORT_SET_CAC */
9749 } else {
9750 /* only AP or GO role need to be handled here. */
9751 err = -EINVAL;
9752 goto fail;
9753 }
9754
9755 /* disable TDLS */
9756#ifdef WLTDLS
9757 if (bssidx == 0) {
9758 /* Disable TDLS for primary Iface. For virtual interface,
9759 * tdls disable will happen from interface create context
9760 */
9761 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_CREATE, false);
9762 }
9763#endif /* WLTDLS */
9764
9765 if (!check_dev_role_integrity(cfg, dev_role)) {
9766 err = -EINVAL;
9767 goto fail;
9768 }
9769
9770#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
9771 if ((err = wl_cfg80211_set_channel(wiphy, dev,
9772 dev->ieee80211_ptr->preset_chandef.chan,
9773 NL80211_CHAN_HT20) < 0)) {
9774 WL_ERR(("Set channel failed \n"));
9775 goto fail;
9776 }
9777#endif
9778
9779 if ((err = wl_cfg80211_bcn_set_params(info, dev,
9780 dev_role, bssidx)) < 0) {
9781 WL_ERR(("Beacon params set failed \n"));
9782 goto fail;
9783 }
9784
9785 /* Parse IEs */
9786 if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) {
9787 WL_ERR(("Set IEs failed \n"));
9788 goto fail;
9789 }
9790
9791 if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies,
9792 dev_role, bssidx, info->privacy)) < 0)
9793 {
9794 WL_ERR(("Beacon set security failed \n"));
9795 goto fail;
9796 }
9797
9798 if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies,
9799 dev_role, bssidx)) < 0) {
9800 WL_ERR(("Beacon bring up AP/GO failed \n"));
9801 goto fail;
9802 }
9803
9804 /* Set GC/STA SCB expiry timings. */
9805 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
9806 WL_ERR(("scb setting failed \n"));
9807// goto fail;
9808 }
9809
dfb0f3ae
RC
9810#ifdef WLMESH
9811 OSL_SLEEP(1000);
9812 if ((dev_role == NL80211_IFTYPE_P2P_GO) || (dev_role == NL80211_IFTYPE_AP)) {
9813 memset(&join_params, 0, sizeof(join_params));
9814 /* join parameters starts with ssid */
9815 join_params_size = sizeof(join_params.ssid);
9816 if (dev_role == NL80211_IFTYPE_P2P_GO) {
9817 join_params.ssid.SSID_len = min(cfg->p2p->ssid.SSID_len,
9818 (uint32)DOT11_MAX_SSID_LEN);
9819 memcpy(join_params.ssid.SSID, cfg->p2p->ssid.SSID,
9820 join_params.ssid.SSID_len);
9821 } else if (dev_role == NL80211_IFTYPE_AP) {
9822 join_params.ssid.SSID_len = min(cfg->hostapd_ssid.SSID_len,
9823 (uint32)DOT11_MAX_SSID_LEN);
9824 memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
9825 join_params.ssid.SSID_len);
9826 }
9827 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
9828 /* create softap */
9829 if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
9830 join_params_size)) != 0) {
9831 WL_ERR(("SoftAP/GO set ssid failed! \n"));
9832 goto fail;
9833 } else {
9834 WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
9835 }
9836 }
9837#endif
9838
010c3a89
RC
9839 WL_DBG(("** AP/GO Created **\n"));
9840
9841#ifdef WL_CFG80211_ACL
9842 /* Enfoce Admission Control. */
9843 if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
9844 WL_ERR(("Set ACL failed\n"));
9845 }
9846#endif /* WL_CFG80211_ACL */
9847
9848 /* Set IEs to FW */
9849 if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
9850 WL_ERR(("Set IEs failed \n"));
9851
9852 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
9853 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
9854 bool pbc = 0;
9855 wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
9856 if (pbc) {
9857 WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
9858 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
9859 }
9860 }
9861
9862#ifdef SUPPORT_AP_RADIO_PWRSAVE
9863 if ((dev_role == NL80211_IFTYPE_AP)) {
9864 wl_set_ap_rps(dev, FALSE, dev->name);
9865 wl_cfg80211_init_ap_rps(cfg);
9866 }
9867#endif /* SUPPORT_AP_RADIO_PWRSAVE */
9868fail:
9869 if (err) {
9870 WL_ERR(("ADD/SET beacon failed\n"));
9871 wl_cfg80211_stop_ap(wiphy, dev);
9872 if (dev_role == NL80211_IFTYPE_AP) {
9873 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
9874#ifdef PKT_FILTER_SUPPORT
9875 /* Enable packet filter */
9876 if (dhd->early_suspended) {
9877 WL_ERR(("Enable pkt_filter\n"));
9878 dhd_enable_packet_filter(1, dhd);
9879 }
9880#endif /* PKT_FILTER_SUPPORT */
9881#ifdef ARP_OFFLOAD_SUPPORT
9882 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
9883 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
9884 dhd_arp_offload_set(dhd, dhd_arp_mode);
9885 dhd_arp_offload_enable(dhd, TRUE);
9886 }
9887#endif /* ARP_OFFLOAD_SUPPORT */
9888 }
9889#ifdef WLTDLS
9890 if (bssidx == 0) {
9891 /* Since AP creation failed, re-enable TDLS */
9892 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
9893 }
9894#endif /* WLTDLS */
9895
9896 }
9897
9898 return err;
9899}
9900
9901static s32
9902wl_cfg80211_stop_ap(
9903 struct wiphy *wiphy,
9904 struct net_device *dev)
9905{
9906 int err = 0;
9907 u32 dev_role = 0;
9908 int ap = 0;
9909 s32 bssidx = 0;
9910 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9911 s32 is_rsdb_supported = BCME_ERROR;
9912 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
9913
9914 WL_DBG(("Enter \n"));
9915
9916 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
9917 if (is_rsdb_supported < 0)
9918 return (-ENODEV);
9919
9920 wl_clr_drv_status(cfg, AP_CREATING, dev);
9921 wl_clr_drv_status(cfg, AP_CREATED, dev);
9922 cfg->ap_oper_channel = 0;
9923
9924 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
9925 dev_role = NL80211_IFTYPE_AP;
9926 WL_DBG(("stopping AP operation\n"));
9927 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
9928 dev_role = NL80211_IFTYPE_P2P_GO;
9929 WL_DBG(("stopping P2P GO operation\n"));
9930 } else {
9931 WL_ERR(("no AP/P2P GO interface is operational.\n"));
9932 return -EINVAL;
9933 }
9934
9935 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
9936 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
9937 return BCME_ERROR;
9938 }
9939
9940 if (!check_dev_role_integrity(cfg, dev_role)) {
9941 WL_ERR(("role integrity check failed \n"));
9942 err = -EINVAL;
9943 goto exit;
9944 }
9945
9946 /* Clear AP/GO connected status */
9947 wl_clr_drv_status(cfg, CONNECTED, dev);
9948 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
9949 WL_ERR(("bss down error %d\n", err));
9950 }
9951
9952 if (dev_role == NL80211_IFTYPE_AP) {
9953#ifdef PKT_FILTER_SUPPORT
9954 /* Enable packet filter */
9955 if (dhd->early_suspended) {
9956 WL_ERR(("Enable pkt_filter\n"));
9957 dhd_enable_packet_filter(1, dhd);
9958 }
9959#endif /* PKT_FILTER_SUPPORT */
9960#ifdef ARP_OFFLOAD_SUPPORT
9961 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
9962 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
9963 dhd_arp_offload_set(dhd, dhd_arp_mode);
9964 dhd_arp_offload_enable(dhd, TRUE);
9965 }
9966#endif /* ARP_OFFLOAD_SUPPORT */
9967
9968 if (is_rsdb_supported == 0) {
d964ce36 9969 if (dhd_download_fw_on_driverload && bssidx == 0) {
9970 wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
9971 wldev_iovar_setint(dev, "apsta", 1);
9972 }
010c3a89
RC
9973 /* For non-rsdb chips, we use stand alone AP. Do wl down on stop AP */
9974 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
9975 if (unlikely(err)) {
9976 WL_ERR(("WLC_UP error (%d)\n", err));
9977 err = -EINVAL;
9978 goto exit;
9979 }
9980 }
9981
9982 wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
9983#ifdef SUPPORT_AP_RADIO_PWRSAVE
9984 wl_set_ap_rps(dev, FALSE, dev->name);
9985 wl_cfg80211_init_ap_rps(cfg);
9986#endif /* SUPPORT_AP_RADIO_PWRSAVE */
9987 } else {
9988 WL_DBG(("Stopping P2P GO \n"));
9989 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
9990 DHD_EVENT_TIMEOUT_MS*3);
9991 DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub));
9992 }
9993exit:
9994#ifdef WLTDLS
9995 if (bssidx == 0) {
9996 /* re-enable TDLS if the number of connected interfaces is less than 2 */
9997 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
9998 }
9999#endif /* WLTDLS */
10000
10001 if (dev_role == NL80211_IFTYPE_AP) {
10002 /* clear the AP mode */
10003 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
10004 }
10005#ifdef SUPPORT_SET_CAC
10006 wl_cfg80211_set_cac(cfg, 1);
10007#endif /* SUPPORT_SET_CAC */
10008 return err;
10009}
10010
10011static s32
10012wl_cfg80211_change_beacon(
10013 struct wiphy *wiphy,
10014 struct net_device *dev,
10015 struct cfg80211_beacon_data *info)
10016{
10017 s32 err = BCME_OK;
10018 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10019 struct parsed_ies ies;
10020 u32 dev_role = 0;
10021 s32 bssidx = 0;
10022 bool pbc = 0;
10023
10024 WL_DBG(("Enter \n"));
10025
10026 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
10027 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
10028 return BCME_ERROR;
10029 }
10030
10031 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
10032 dev_role = NL80211_IFTYPE_P2P_GO;
10033 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
10034 dev_role = NL80211_IFTYPE_AP;
10035 } else {
10036 err = -EINVAL;
10037 goto fail;
10038 }
10039
10040 if (!check_dev_role_integrity(cfg, dev_role)) {
10041 err = -EINVAL;
10042 goto fail;
10043 }
10044
10045 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
10046 WL_ERR(("P2P already down status!\n"));
10047 err = BCME_ERROR;
10048 goto fail;
10049 }
10050
10051 /* Parse IEs */
10052 if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) {
10053 WL_ERR(("Parse IEs failed \n"));
10054 goto fail;
10055 }
10056
10057 /* Set IEs to FW */
10058 if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
10059 WL_ERR(("Set IEs failed \n"));
10060 goto fail;
10061 }
10062
10063 if (dev_role == NL80211_IFTYPE_AP) {
10064 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
10065 WL_ERR(("Hostapd update sec failed \n"));
10066 err = -EINVAL;
10067 goto fail;
10068 }
10069 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
10070 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
10071 wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
10072 WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
10073 if (pbc)
10074 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
10075 else
10076 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
10077 }
10078 }
10079
10080fail:
10081 return err;
10082}
10083#else
10084static s32
10085wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
10086 struct beacon_parameters *info)
10087{
10088 s32 err = BCME_OK;
10089 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10090 s32 ie_offset = 0;
10091 s32 bssidx = 0;
10092 u32 dev_role = NL80211_IFTYPE_AP;
10093 struct parsed_ies ies;
10094 bcm_tlv_t *ssid_ie;
10095 bool pbc = 0;
10096 bool privacy;
10097 bool is_bss_up = 0;
10098 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10099
10100 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
10101 info->interval, info->dtim_period, info->head_len, info->tail_len));
10102
10103 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
10104 dev_role = NL80211_IFTYPE_AP;
10105 }
10106#if defined(WL_ENABLE_P2P_IF)
10107 else if (dev == cfg->p2p_net) {
10108 /* Group Add request on p2p0 */
10109 dev = bcmcfg_to_prmry_ndev(cfg);
10110 dev_role = NL80211_IFTYPE_P2P_GO;
10111 }
10112#endif /* WL_ENABLE_P2P_IF */
10113
10114 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
10115 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
10116 return BCME_ERROR;
10117 }
10118
10119 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
10120 dev_role = NL80211_IFTYPE_P2P_GO;
10121 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
10122 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
10123 }
10124
10125 if (!check_dev_role_integrity(cfg, dev_role)) {
10126 err = -ENODEV;
10127 goto fail;
10128 }
10129
10130 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
10131 WL_ERR(("P2P already down status!\n"));
10132 err = BCME_ERROR;
10133 goto fail;
10134 }
10135
10136 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
10137 /* find the SSID */
10138 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
10139 info->head_len - ie_offset,
10140 DOT11_MNG_SSID_ID)) != NULL) {
10141 if (dev_role == NL80211_IFTYPE_AP) {
10142 /* Store the hostapd SSID */
10143 memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
10144 cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
10145 memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
10146 cfg->hostapd_ssid.SSID_len);
10147 } else {
10148 /* P2P GO */
10149 memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
10150 cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
10151 memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
10152 cfg->p2p->ssid.SSID_len);
10153 }
10154 }
10155
10156 if (wl_cfg80211_parse_ies((u8 *)info->tail,
10157 info->tail_len, &ies) < 0) {
10158 WL_ERR(("Beacon get IEs failed \n"));
10159 err = -EINVAL;
10160 goto fail;
10161 }
10162
10163 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
10164 VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
10165 info->tail_len)) < 0) {
10166 WL_ERR(("Beacon set IEs failed \n"));
10167 goto fail;
10168 } else {
10169 WL_DBG(("Applied Vndr IEs for Beacon \n"));
10170 }
10171
10172#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
10173 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
10174 VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies,
10175 info->proberesp_ies_len)) < 0) {
10176 WL_ERR(("ProbeRsp set IEs failed \n"));
10177 goto fail;
10178 } else {
10179 WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
10180 }
10181#endif
10182
10183 is_bss_up = wl_cfg80211_bss_isup(dev, bssidx);
10184
10185#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
10186 privacy = info->privacy;
10187#else
10188 privacy = 0;
10189#endif
10190 if (!is_bss_up &&
10191 (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx, privacy) < 0))
10192 {
10193 WL_ERR(("Beacon set security failed \n"));
10194 err = -EINVAL;
10195 goto fail;
10196 }
10197
10198 /* Set BI and DTIM period */
10199 if (info->interval) {
10200 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
10201 &info->interval, sizeof(s32))) < 0) {
10202 WL_ERR(("Beacon Interval Set Error, %d\n", err));
10203 return err;
10204 }
10205 }
10206 if (info->dtim_period) {
10207 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
10208 &info->dtim_period, sizeof(s32))) < 0) {
10209 WL_ERR(("DTIM Interval Set Error, %d\n", err));
10210 return err;
10211 }
10212 }
10213
10214 /* If bss is already up, skip bring up */
10215 if (!is_bss_up &&
10216 (err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0)
10217 {
10218 WL_ERR(("Beacon bring up AP/GO failed \n"));
10219 goto fail;
10220 }
10221
10222 /* Set GC/STA SCB expiry timings. */
10223 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
10224 WL_ERR(("scb setting failed \n"));
10225// goto fail;
10226 }
10227
10228 if (wl_get_drv_status(cfg, AP_CREATED, dev)) {
10229 /* Soft AP already running. Update changed params */
10230 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
10231 WL_ERR(("Hostapd update sec failed \n"));
10232 err = -EINVAL;
10233 goto fail;
10234 }
10235 }
10236
10237 /* Enable Probe Req filter */
10238 if (((dev_role == NL80211_IFTYPE_P2P_GO) ||
10239 (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) {
10240 wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
10241 if (pbc)
10242 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
10243 }
10244
10245 WL_DBG(("** ADD/SET beacon done **\n"));
10246
10247fail:
10248 if (err) {
10249 WL_ERR(("ADD/SET beacon failed\n"));
10250 if (dev_role == NL80211_IFTYPE_AP) {
10251 /* clear the AP mode */
10252 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
10253 }
10254 }
10255 return err;
10256
10257}
10258
10259static s32
10260wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
10261{
10262 int err = 0;
10263 s32 bssidx = 0;
10264 int infra = 0;
10265 struct wireless_dev *wdev = dev->ieee80211_ptr;
10266 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10267 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10268
10269 WL_DBG(("Enter. \n"));
10270
10271 if (!wdev) {
10272 WL_ERR(("wdev null \n"));
10273 return -EINVAL;
10274 }
10275
10276 if ((wdev->iftype != NL80211_IFTYPE_P2P_GO) && (wdev->iftype != NL80211_IFTYPE_AP)) {
10277 WL_ERR(("Unspported iface type iftype:%d \n", wdev->iftype));
10278 }
10279
10280 wl_clr_drv_status(cfg, AP_CREATING, dev);
10281 wl_clr_drv_status(cfg, AP_CREATED, dev);
10282
10283 /* Clear AP/GO connected status */
10284 wl_clr_drv_status(cfg, CONNECTED, dev);
10285
10286 cfg->ap_oper_channel = 0;
10287
10288
10289 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
10290 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
10291 return BCME_ERROR;
10292 }
10293
10294 /* Do bss down */
10295 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
10296 WL_ERR(("bss down error %d\n", err));
10297 }
10298
10299 /* fall through is intentional */
10300 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
10301 if (err < 0) {
10302 WL_ERR(("SET INFRA error %d\n", err));
10303 }
10304 wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
10305
10306 if (wdev->iftype == NL80211_IFTYPE_AP) {
10307 /* clear the AP mode */
10308 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
10309 }
10310
10311 return 0;
10312}
10313#endif
10314
10315#ifdef WL_SCHED_SCAN
10316#define PNO_TIME 30
10317#define PNO_REPEAT 4
10318#define PNO_FREQ_EXPO_MAX 2
10319static bool
10320is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count)
10321{
10322 int i;
10323
10324 if (!ssid || !ssid_list)
10325 return FALSE;
10326
10327 for (i = 0; i < count; i++) {
10328 if (ssid->ssid_len == ssid_list[i].ssid_len) {
10329 if (strncmp(ssid->ssid, ssid_list[i].ssid, ssid->ssid_len) == 0)
10330 return TRUE;
10331 }
10332 }
10333 return FALSE;
10334}
10335
10336static int
10337wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
10338 struct net_device *dev,
10339 struct cfg80211_sched_scan_request *request)
10340{
10341 ushort pno_time = PNO_TIME;
10342 int pno_repeat = PNO_REPEAT;
10343 int pno_freq_expo_max = PNO_FREQ_EXPO_MAX;
10344 wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
10345 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10346 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
10347 struct cfg80211_ssid *ssid = NULL;
10348 struct cfg80211_ssid *hidden_ssid_list = NULL;
10349 log_conn_event_t *event_data = NULL;
10350 tlv_log *tlv_data = NULL;
10351 u32 alloc_len, tlv_len;
10352 u32 payload_len;
10353 int ssid_cnt = 0;
10354 int i;
10355 int ret = 0;
10356 unsigned long flags;
10357
10358 if (!request) {
10359 WL_ERR(("Sched scan request was NULL\n"));
10360 return -EINVAL;
10361 }
10362
10363 WL_DBG(("Enter \n"));
10364 WL_PNO((">>> SCHED SCAN START\n"));
10365 WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n",
10366 request->n_match_sets, request->n_ssids));
10367 WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
10368 request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
10369
10370
10371 if (!request->n_ssids || !request->n_match_sets) {
10372 WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids));
10373 return -EINVAL;
10374 }
10375
10376 memset(&ssids_local, 0, sizeof(ssids_local));
10377
10378 if (request->n_ssids > 0) {
10379 hidden_ssid_list = request->ssids;
10380 }
10381
10382 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
10383 alloc_len = sizeof(log_conn_event_t) + DOT11_MAX_SSID_LEN;
10384 event_data = MALLOC(dhdp->osh, alloc_len);
10385 if (!event_data) {
10386 WL_ERR(("%s: failed to allocate log_conn_event_t with "
10387 "length(%d)\n", __func__, alloc_len));
10388 return -ENOMEM;
10389 }
10390 memset(event_data, 0, alloc_len);
10391 event_data->tlvs = NULL;
10392 tlv_len = sizeof(tlv_log);
10393 event_data->tlvs = (tlv_log *)MALLOC(dhdp->osh, tlv_len);
10394 if (!event_data->tlvs) {
10395 WL_ERR(("%s: failed to allocate log_tlv with "
10396 "length(%d)\n", __func__, tlv_len));
10397 MFREE(dhdp->osh, event_data, alloc_len);
10398 return -ENOMEM;
10399 }
10400 }
10401 for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) {
10402 ssid = &request->match_sets[i].ssid;
10403 /* No need to include null ssid */
10404 if (ssid->ssid_len) {
10405 ssids_local[ssid_cnt].SSID_len = MIN(ssid->ssid_len,
10406 (uint32)DOT11_MAX_SSID_LEN);
10407 memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid,
10408 ssids_local[ssid_cnt].SSID_len);
10409 if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) {
10410 ssids_local[ssid_cnt].hidden = TRUE;
10411 WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid));
10412 } else {
10413 ssids_local[ssid_cnt].hidden = FALSE;
10414 WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid->ssid));
10415 }
10416#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 15, 0))
10417 if (request->match_sets[i].rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) {
10418 ssids_local[ssid_cnt].rssi_thresh =
10419 (int8)request->match_sets[i].rssi_thold;
10420 }
10421#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 15, 0)) */
10422 ssid_cnt++;
10423 }
10424 }
10425
10426 if (ssid_cnt) {
10427 if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, ssid_cnt,
10428 pno_time, pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) {
10429 WL_ERR(("PNO setup failed!! ret=%d \n", ret));
10430 ret = -EINVAL;
10431 goto exit;
10432 }
10433
10434 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
10435 for (i = 0; i < ssid_cnt; i++) {
10436 payload_len = sizeof(log_conn_event_t);
10437 event_data->event = WIFI_EVENT_DRIVER_PNO_ADD;
10438 tlv_data = event_data->tlvs;
10439 /* ssid */
10440 tlv_data->tag = WIFI_TAG_SSID;
10441 tlv_data->len = ssids_local[i].SSID_len;
10442 memcpy(tlv_data->value, ssids_local[i].SSID,
10443 ssids_local[i].SSID_len);
10444 payload_len += TLV_LOG_SIZE(tlv_data);
10445
10446 dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
10447 event_data, payload_len);
10448 }
10449 }
10450
10451 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
10452 cfg->sched_scan_req = request;
10453 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
10454 } else {
10455 ret = -EINVAL;
10456 }
10457exit:
10458 if (event_data) {
10459 MFREE(dhdp->osh, event_data->tlvs, tlv_len);
10460 MFREE(dhdp->osh, event_data, alloc_len);
10461 }
10462 return ret;
10463}
10464
10465static int
dfb0f3ae
RC
10466wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
10467#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
10468 , u64 reqid
10469#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
10470)
010c3a89
RC
10471{
10472 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10473 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
10474 unsigned long flags;
10475
10476 WL_DBG(("Enter \n"));
10477 WL_PNO((">>> SCHED SCAN STOP\n"));
10478
10479 BCM_REFERENCE(dhdp);
10480 if (dhd_dev_pno_stop_for_ssid(dev) < 0) {
10481 WL_ERR(("PNO Stop for SSID failed"));
10482 } else {
10483 DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_REMOVE);
10484 }
10485
10486 if (cfg->scan_request && cfg->sched_scan_running) {
10487 WL_PNO((">>> Sched scan running. Aborting it..\n"));
10488 wl_notify_escan_complete(cfg, dev, true, true);
10489 }
10490 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
10491 cfg->sched_scan_req = NULL;
10492 cfg->sched_scan_running = FALSE;
10493 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
10494 return 0;
10495}
10496#endif /* WL_SCHED_SCAN */
10497
10498#ifdef WL_SUPPORT_ACS
10499/*
10500 * Currently the dump_obss IOVAR is returning string as output so we need to
10501 * parse the output buffer in an unoptimized way. Going forward if we get the
10502 * IOVAR output in binary format this method can be optimized
10503 */
10504static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
10505{
10506 int i;
10507 char *token;
10508 char delim[] = " \n";
10509
10510 token = strsep(&buf, delim);
10511 while (token != NULL) {
10512 if (!strcmp(token, "OBSS")) {
10513 for (i = 0; i < OBSS_TOKEN_IDX; i++)
10514 token = strsep(&buf, delim);
10515 survey->obss = simple_strtoul(token, NULL, 10);
10516 }
10517
10518 if (!strcmp(token, "IBSS")) {
10519 for (i = 0; i < IBSS_TOKEN_IDX; i++)
10520 token = strsep(&buf, delim);
10521 survey->ibss = simple_strtoul(token, NULL, 10);
10522 }
10523
10524 if (!strcmp(token, "TXDur")) {
10525 for (i = 0; i < TX_TOKEN_IDX; i++)
10526 token = strsep(&buf, delim);
10527 survey->tx = simple_strtoul(token, NULL, 10);
10528 }
10529
10530 if (!strcmp(token, "Category")) {
10531 for (i = 0; i < CTG_TOKEN_IDX; i++)
10532 token = strsep(&buf, delim);
10533 survey->no_ctg = simple_strtoul(token, NULL, 10);
10534 }
10535
10536 if (!strcmp(token, "Packet")) {
10537 for (i = 0; i < PKT_TOKEN_IDX; i++)
10538 token = strsep(&buf, delim);
10539 survey->no_pckt = simple_strtoul(token, NULL, 10);
10540 }
10541
10542 if (!strcmp(token, "Opp(time):")) {
10543 for (i = 0; i < IDLE_TOKEN_IDX; i++)
10544 token = strsep(&buf, delim);
10545 survey->idle = simple_strtoul(token, NULL, 10);
10546 }
10547
10548 token = strsep(&buf, delim);
10549 }
10550
10551 return 0;
10552}
10553
10554static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
10555 struct wl_dump_survey *survey)
10556{
10557 cca_stats_n_flags *results;
10558 char *buf;
10559 int retry, err;
10560
10561 buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL);
10562 if (unlikely(!buf)) {
10563 WL_ERR(("%s: buf alloc failed\n", __func__));
10564 return -ENOMEM;
10565 }
10566
10567 retry = IOCTL_RETRY_COUNT;
10568 while (retry--) {
10569 err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req),
10570 buf, WLC_IOCTL_MAXLEN, NULL);
10571 if (err >= 0) {
10572 break;
10573 }
10574 WL_DBG(("attempt = %d, err = %d, \n",
10575 (IOCTL_RETRY_COUNT - retry), err));
10576 }
10577
10578 if (retry <= 0) {
10579 WL_ERR(("failure, dump_obss IOVAR failed\n"));
10580 err = -EINVAL;
10581 goto exit;
10582 }
10583
10584 results = (cca_stats_n_flags *)(buf);
10585 wl_parse_dump_obss(results->buf, survey);
10586 kfree(buf);
10587
10588 return 0;
10589exit:
10590 kfree(buf);
10591 return err;
10592}
10593
10594static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
10595 int idx, struct survey_info *info)
10596{
10597 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10598 struct wl_dump_survey *survey;
10599 struct ieee80211_supported_band *band;
10600 struct ieee80211_channel*chan;
10601 cca_msrmnt_query req;
10602 int val, err, noise, retry;
10603
10604 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10605 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
10606 return -ENOENT;
10607 }
10608 band = wiphy->bands[IEEE80211_BAND_2GHZ];
10609 if (band && idx >= band->n_channels) {
10610 idx -= band->n_channels;
10611 band = NULL;
10612 }
10613
10614 if (!band || idx >= band->n_channels) {
10615 /* Move to 5G band */
10616 band = wiphy->bands[IEEE80211_BAND_5GHZ];
10617 if (idx >= band->n_channels) {
10618 return -ENOENT;
10619 }
10620 }
10621
10622 chan = &band->channels[idx];
10623 /* Setting current channel to the requested channel */
10624 if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan,
10625 NL80211_CHAN_HT20) < 0)) {
10626 WL_ERR(("Set channel failed \n"));
10627 }
10628
10629 if (!idx) {
10630 /* Set interface up, explicitly. */
10631 val = 1;
10632 err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
10633 if (err < 0) {
10634 WL_ERR(("set interface up failed, error = %d\n", err));
10635 }
10636 }
10637
10638 /* Get noise value */
10639 retry = IOCTL_RETRY_COUNT;
10640 while (retry--) {
10641 noise = 0;
10642 err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise,
10643 sizeof(noise));
10644 if (err >= 0) {
10645 break;
10646 }
10647 WL_DBG(("attempt = %d, err = %d, \n",
10648 (IOCTL_RETRY_COUNT - retry), err));
10649 }
10650
10651 if (retry <= 0) {
10652 WL_ERR(("Get Phy Noise failed, error = %d\n", err));
10653 noise = CHAN_NOISE_DUMMY;
10654 }
10655
10656 survey = (struct wl_dump_survey *) kzalloc(sizeof(struct wl_dump_survey),
10657 GFP_KERNEL);
10658 if (unlikely(!survey)) {
10659 WL_ERR(("%s: alloc failed\n", __func__));
10660 return -ENOMEM;
10661 }
10662
10663 /* Start Measurement for obss stats on current channel */
10664 req.msrmnt_query = 0;
10665 req.time_req = ACS_MSRMNT_DELAY;
10666 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
10667 goto exit;
10668 }
10669
10670 /*
10671 * Wait for the meaurement to complete, adding a buffer value of 10 to take
10672 * into consideration any delay in IOVAR completion
10673 */
10674 msleep(ACS_MSRMNT_DELAY + 10);
10675
10676 /* Issue IOVAR to collect measurement results */
10677 req.msrmnt_query = 1;
10678 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
10679 goto exit;
10680 }
10681
10682 info->channel = chan;
10683 info->noise = noise;
10684 info->channel_time = ACS_MSRMNT_DELAY;
10685 info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
10686 info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg +
10687 survey->no_pckt;
10688 info->channel_time_tx = survey->tx;
10689 info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
10690 SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
10691 SURVEY_INFO_CHANNEL_TIME_TX;
10692 kfree(survey);
10693
10694 return 0;
10695exit:
10696 kfree(survey);
10697 return err;
10698}
10699#endif /* WL_SUPPORT_ACS */
10700
10701static struct cfg80211_ops wl_cfg80211_ops = {
10702 .add_virtual_intf = wl_cfg80211_add_virtual_iface,
10703 .del_virtual_intf = wl_cfg80211_del_virtual_iface,
10704 .change_virtual_intf = wl_cfg80211_change_virtual_iface,
10705#if defined(WL_CFG80211_P2P_DEV_IF)
10706 .start_p2p_device = wl_cfgp2p_start_p2p_device,
10707 .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
10708#endif /* WL_CFG80211_P2P_DEV_IF */
10709 .scan = wl_cfg80211_scan,
10710 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
10711 .join_ibss = wl_cfg80211_join_ibss,
10712 .leave_ibss = wl_cfg80211_leave_ibss,
10713 .get_station = wl_cfg80211_get_station,
10714 .set_tx_power = wl_cfg80211_set_tx_power,
10715 .get_tx_power = wl_cfg80211_get_tx_power,
10716 .add_key = wl_cfg80211_add_key,
10717 .del_key = wl_cfg80211_del_key,
10718 .get_key = wl_cfg80211_get_key,
10719 .set_default_key = wl_cfg80211_config_default_key,
10720 .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
10721 .set_power_mgmt = wl_cfg80211_set_power_mgmt,
10722 .connect = wl_cfg80211_connect,
10723 .disconnect = wl_cfg80211_disconnect,
10724 .suspend = wl_cfg80211_suspend,
10725 .resume = wl_cfg80211_resume,
10726 .set_pmksa = wl_cfg80211_set_pmksa,
10727 .del_pmksa = wl_cfg80211_del_pmksa,
10728 .flush_pmksa = wl_cfg80211_flush_pmksa,
10729 .remain_on_channel = wl_cfg80211_remain_on_channel,
10730 .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
10731 .mgmt_tx = wl_cfg80211_mgmt_tx,
10732 .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
10733 .change_bss = wl_cfg80211_change_bss,
10734#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
10735 .set_channel = wl_cfg80211_set_channel,
10736#endif
10737#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
10738 .set_beacon = wl_cfg80211_add_set_beacon,
10739 .add_beacon = wl_cfg80211_add_set_beacon,
10740 .del_beacon = wl_cfg80211_del_beacon,
10741#else
10742 .change_beacon = wl_cfg80211_change_beacon,
10743 .start_ap = wl_cfg80211_start_ap,
10744 .stop_ap = wl_cfg80211_stop_ap,
10745#endif
10746#ifdef WL_SCHED_SCAN
10747 .sched_scan_start = wl_cfg80211_sched_scan_start,
10748 .sched_scan_stop = wl_cfg80211_sched_scan_stop,
10749#endif /* WL_SCHED_SCAN */
10750#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
10751 2, 0))
10752 .del_station = wl_cfg80211_del_station,
10753 .change_station = wl_cfg80211_change_station,
10754 .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
10755#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
dfb0f3ae
RC
10756#ifdef WLMESH
10757 .join_mesh = wl_cfg80211_join_mesh,
10758 .leave_mesh = wl_cfg80211_leave_mesh,
10759#endif /* WLMESH */
010c3a89
RC
10760#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
10761 .tdls_mgmt = wl_cfg80211_tdls_mgmt,
10762 .tdls_oper = wl_cfg80211_tdls_oper,
10763#endif
10764#ifdef WL_SUPPORT_ACS
10765 .dump_survey = wl_cfg80211_dump_survey,
10766#endif /* WL_SUPPORT_ACS */
10767#ifdef WL_CFG80211_ACL
10768 .set_mac_acl = wl_cfg80211_set_mac_acl,
10769#endif /* WL_CFG80211_ACL */
10770#ifdef GTK_OFFLOAD_SUPPORT
10771#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
10772 .set_rekey_data = wl_cfg80211_set_rekey_data,
10773#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
10774#endif /* GTK_OFFLOAD_SUPPORT */
10775};
10776
10777s32 wl_mode_to_nl80211_iftype(s32 mode)
10778{
10779 s32 err = 0;
10780
10781 switch (mode) {
10782 case WL_MODE_BSS:
10783 return NL80211_IFTYPE_STATION;
10784 case WL_MODE_IBSS:
10785 return NL80211_IFTYPE_ADHOC;
10786 case WL_MODE_AP:
10787 return NL80211_IFTYPE_AP;
dfb0f3ae
RC
10788#ifdef WLMESH
10789 case WL_MODE_MESH:
10790 return NL80211_IFTYPE_MESH_POINT;
10791#endif
010c3a89
RC
10792 default:
10793 return NL80211_IFTYPE_UNSPECIFIED;
10794 }
10795
10796 return err;
10797}
10798
10799#ifdef CONFIG_CFG80211_INTERNAL_REGDB
10800#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
10801#define WL_CFG80211_REG_NOTIFIER() static int wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
10802#else
10803#define WL_CFG80211_REG_NOTIFIER() static void wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
10804#endif /* kernel version < 3.9.0 */
10805#endif
10806
10807#ifdef CONFIG_CFG80211_INTERNAL_REGDB
10808WL_CFG80211_REG_NOTIFIER()
10809{
10810 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
10811 int ret = 0;
10812 int revinfo = -1;
10813
10814 if (!request || !cfg) {
10815 WL_ERR(("Invalid arg\n"));
10816#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
10817 return -EINVAL;
10818#else
10819 return;
10820#endif /* kernel version < 3.10.11 */
10821 }
10822
10823 WL_DBG(("ccode: %c%c Initiator: %d\n",
10824 request->alpha2[0], request->alpha2[1], request->initiator));
10825
10826 /* We support only REGDOM_SET_BY_USER as of now */
10827 if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
10828 (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
10829 WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
10830 request->initiator));
10831 /* in case of no supported country by regdb
10832 lets driver setup platform default Locale
10833 */
10834 }
10835
10836 WL_ERR(("Set country code %c%c from %s\n",
10837 request->alpha2[0], request->alpha2[1],
10838 ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User")));
10839
10840 if ((ret = wldev_set_country(bcmcfg_to_prmry_ndev(cfg), request->alpha2,
10841 false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false),
10842 revinfo)) < 0) {
10843 WL_ERR(("set country Failed :%d\n", ret));
10844 }
10845
10846#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
10847 return ret;
10848#else
10849 return;
10850#endif /* kernel version < 3.10.11 */
10851}
10852#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
10853
10854#ifdef CONFIG_PM
10855#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
10856static const struct wiphy_wowlan_support brcm_wowlan_support = {
10857 .flags = WIPHY_WOWLAN_ANY,
10858 .n_patterns = WL_WOWLAN_MAX_PATTERNS,
10859 .pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
10860 .pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
10861#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
10862 .max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
10863#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
10864};
10865#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
10866#endif /* CONFIG_PM */
10867
10868static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, dhd_pub_t *context)
10869{
10870 s32 err = 0;
10871#ifdef CONFIG_PM
10872#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
10873 struct cfg80211_wowlan *brcm_wowlan_config = NULL;
10874#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
10875#endif /* CONFIG_PM */
10876
10877//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
10878 dhd_pub_t *dhd = (dhd_pub_t *)context;
10879 BCM_REFERENCE(dhd);
10880
10881 if (!dhd) {
10882 WL_ERR(("DHD is NULL!!"));
10883 err = -ENODEV;
10884 return err;
10885 }
10886//#endif
10887
10888 wdev->wiphy =
10889 wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
10890 if (unlikely(!wdev->wiphy)) {
10891 WL_ERR(("Couldn not allocate wiphy device\n"));
10892 err = -ENOMEM;
10893 return err;
10894 }
10895 set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
10896 wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
10897 /* Report how many SSIDs Driver can support per Scan request */
10898 wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
10899 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
10900#ifdef WL_SCHED_SCAN
10901 wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
10902 wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
10903 wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
dfb0f3ae
RC
10904#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
10905 wdev->wiphy->max_sched_scan_plan_interval = PNO_SCAN_MAX_FW_SEC;
10906#else
010c3a89 10907 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
dfb0f3ae 10908#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
010c3a89 10909#endif /* WL_SCHED_SCAN */
dfb0f3ae
RC
10910#ifdef WLMESH
10911 wdev->wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
10912#endif
010c3a89
RC
10913 wdev->wiphy->interface_modes =
10914 BIT(NL80211_IFTYPE_STATION)
10915 | BIT(NL80211_IFTYPE_ADHOC)
10916#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
10917 | BIT(NL80211_IFTYPE_MONITOR)
10918#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
10919#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
10920 | BIT(NL80211_IFTYPE_P2P_CLIENT)
10921 | BIT(NL80211_IFTYPE_P2P_GO)
10922#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
10923#if defined(WL_CFG80211_P2P_DEV_IF)
10924 | BIT(NL80211_IFTYPE_P2P_DEVICE)
10925#endif /* WL_CFG80211_P2P_DEV_IF */
dfb0f3ae
RC
10926#ifdef WLMESH
10927 | BIT(NL80211_IFTYPE_MESH_POINT)
10928#endif /* WLMESH */
010c3a89
RC
10929 | BIT(NL80211_IFTYPE_AP);
10930
10931#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
10932 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
10933 WL_DBG(("Setting interface combinations for common mode\n"));
010c3a89
RC
10934 wdev->wiphy->iface_combinations = common_iface_combinations;
10935 wdev->wiphy->n_iface_combinations =
10936 ARRAY_SIZE(common_iface_combinations);
10937#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
10938
10939 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
10940
10941 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
10942 wdev->wiphy->cipher_suites = __wl_cipher_suites;
10943 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
10944 wdev->wiphy->max_remain_on_channel_duration = 5000;
10945 wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
10946#ifndef WL_POWERSAVE_DISABLED
10947 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
10948#else
10949 wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
10950#endif /* !WL_POWERSAVE_DISABLED */
10951 wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
10952 WIPHY_FLAG_4ADDR_AP |
10953#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39))
10954 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
10955#endif
10956 WIPHY_FLAG_4ADDR_STATION;
10957#if ((defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && (LINUX_VERSION_CODE >= \
10958 KERNEL_VERSION(3, 2, 0)))
10959 /*
10960 * If FW ROAM flag is advertised, upper layer wouldn't provide
10961 * the bssid & freq in the connect command. This will result a
10962 * delay in initial connection time due to firmware doing a full
10963 * channel scan to figure out the channel & bssid. However kernel
10964 * ver >= 3.15, provides bssid_hint & freq_hint and hence kernel
10965 * ver >= 3.15 won't have any issue. So if this flags need to be
10966 * advertised for kernel < 3.15, suggest to use RCC along with it
10967 * to avoid the initial connection delay.
10968 */
10969 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
10970#endif
10971#ifdef UNSET_FW_ROAM_WIPHY_FLAG
10972 wdev->wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_FW_ROAM;
10973#endif /* UNSET_FW_ROAM_WIPHY_FLAG */
10974#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
10975 wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
10976 WIPHY_FLAG_OFFCHAN_TX;
10977#endif
10978#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
10979 4, 0))
10980 /* From 3.4 kernel ownards AP_SME flag can be advertised
10981 * to remove the patch from supplicant
10982 */
10983 wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
10984
10985#ifdef WL_CFG80211_ACL
10986 /* Configure ACL capabilities. */
10987 wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
10988#endif
10989
10990#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
10991 /* Supplicant distinguish between the SoftAP mode and other
10992 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
10993 * response frame from Supplicant MR1 and Kernel 3.4.0 or
10994 * later version. To add Vendor specific IE into the
10995 * probe response frame in case of SoftAP mode,
10996 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
10997 */
10998 if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
10999 wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
11000 wdev->wiphy->probe_resp_offload = 0;
11001 }
11002#endif
11003#endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
11004
11005#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
11006 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
11007#endif
11008
11009#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
11010 /*
11011 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
11012 * disconnection of connected network before suspend. So a dummy wowlan
11013 * filter is configured for kernels linux-3.8 and above.
11014 */
11015
11016#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
11017 wdev->wiphy->wowlan = &brcm_wowlan_support;
11018 /* If this is not provided cfg stack will get disconnect
11019 * during suspend.
11020 */
11021 brcm_wowlan_config = kmalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL);
11022 if (brcm_wowlan_config) {
11023 brcm_wowlan_config->disconnect = true;
11024 brcm_wowlan_config->gtk_rekey_failure = true;
11025 brcm_wowlan_config->eap_identity_req = true;
11026 brcm_wowlan_config->four_way_handshake = true;
11027 brcm_wowlan_config->patterns = NULL;
11028 brcm_wowlan_config->n_patterns = 0;
11029 brcm_wowlan_config->tcp = NULL;
11030#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11031 brcm_wowlan_config->nd_config = NULL;
11032#endif
11033 } else {
11034 WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
11035 " So wiphy->wowlan_config is set to NULL\n"));
11036 }
11037 wdev->wiphy->wowlan_config = brcm_wowlan_config;
11038#else
11039 wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
11040 wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
11041 wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
11042 wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
11043#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
11044 wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
11045#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
11046#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
11047#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
11048
11049 WL_DBG(("Registering custom regulatory)\n"));
11050#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
11051 wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
11052#else
11053 wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
11054#endif
11055 wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
11056
11057#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
11058 WL_ERR(("Registering Vendor80211\n"));
11059 err = wl_cfgvendor_attach(wdev->wiphy, dhd);
11060 if (unlikely(err < 0)) {
11061 WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
11062 }
11063#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
11064
11065 /* Now we can register wiphy with cfg80211 module */
11066 err = wiphy_register(wdev->wiphy);
11067 if (unlikely(err < 0)) {
11068 WL_ERR(("Couldn not register wiphy device (%d)\n", err));
11069 wiphy_free(wdev->wiphy);
11070 }
11071
11072#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
11073 KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
11074 wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
11075#endif
11076
11077 return err;
11078}
11079
11080static void wl_free_wdev(struct bcm_cfg80211 *cfg)
11081{
11082 struct wireless_dev *wdev = cfg->wdev;
11083 struct wiphy *wiphy = NULL;
11084 if (!wdev) {
11085 WL_ERR(("wdev is invalid\n"));
11086 return;
11087 }
11088 if (wdev->wiphy) {
11089 wiphy = wdev->wiphy;
11090
11091#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
11092 wl_cfgvendor_detach(wdev->wiphy);
11093#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
11094#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
11095#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
11096 /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
11097 WL_DBG(("wl_free_wdev Clearing wowlan Config \n"));
11098 wdev->wiphy->wowlan = NULL;
11099#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
11100#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
11101 wiphy_unregister(wdev->wiphy);
11102 wdev->wiphy->dev.parent = NULL;
11103 wdev->wiphy = NULL;
11104 }
11105
11106 wl_delete_all_netinfo(cfg);
11107 if (wiphy)
11108 wiphy_free(wiphy);
11109
11110 /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
11111 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
11112 */
11113}
11114
11115static s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
11116{
11117 struct wl_scan_results *bss_list;
11118 struct wl_bss_info *bi = NULL; /* must be initialized */
11119 s32 err = 0;
11120 s32 i;
010c3a89 11121 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
d964ce36 11122#if defined(RSSIAVG)
010c3a89
RC
11123 int rssi;
11124#endif
11125#if defined(BSSCACHE)
11126 wl_bss_cache_t *node;
11127#endif
11128
11129 bss_list = cfg->bss_list;
11130
11131 /* Free cache in p2p scanning*/
11132 if (p2p_is_on(cfg) && p2p_scan(cfg)) {
11133#if defined(RSSIAVG)
d964ce36 11134 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
010c3a89
RC
11135#endif
11136#if defined(BSSCACHE)
d964ce36 11137 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
010c3a89
RC
11138#endif
11139 }
11140
11141 /* Delete disconnected cache */
11142#if defined(BSSCACHE)
d964ce36 11143 wl_delete_disconnected_bss_cache(&cfg->g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid);
010c3a89 11144#if defined(RSSIAVG)
d964ce36 11145 wl_delete_disconnected_rssi_cache(&cfg->g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid);
010c3a89
RC
11146#endif
11147 if (cfg->p2p_disconnected == 0)
11148 memset(&cfg->disconnected_bssid, 0, ETHER_ADDR_LEN);
11149#endif
11150
11151 /* Update cache */
11152#if defined(RSSIAVG)
d964ce36 11153 wl_update_rssi_cache(&cfg->g_rssi_cache_ctrl, bss_list);
010c3a89 11154 if (!in_atomic())
d964ce36 11155 wl_update_connected_rssi_cache(ndev, &cfg->g_rssi_cache_ctrl, &rssi);
010c3a89
RC
11156#endif
11157#if defined(BSSCACHE)
d964ce36 11158 wl_update_bss_cache(&cfg->g_bss_cache_ctrl,
010c3a89 11159#if defined(RSSIAVG)
d964ce36 11160 &cfg->g_rssi_cache_ctrl,
010c3a89
RC
11161#endif
11162 bss_list);
11163#endif
11164
11165 /* delete dirty cache */
11166#if defined(RSSIAVG)
d964ce36 11167 wl_delete_dirty_rssi_cache(&cfg->g_rssi_cache_ctrl);
11168 wl_reset_rssi_cache(&cfg->g_rssi_cache_ctrl);
010c3a89
RC
11169#endif
11170#if defined(BSSCACHE)
d964ce36 11171 wl_delete_dirty_bss_cache(&cfg->g_bss_cache_ctrl);
11172 wl_reset_bss_cache(&cfg->g_bss_cache_ctrl);
010c3a89
RC
11173#endif
11174
11175#if defined(BSSCACHE)
11176 if (cfg->p2p_disconnected > 0) {
11177 // terence 20130703: Fix for wrong group_capab (timing issue)
d964ce36 11178 wl_delete_disconnected_bss_cache(&cfg->g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid);
010c3a89 11179#if defined(RSSIAVG)
d964ce36 11180 wl_delete_disconnected_rssi_cache(&cfg->g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid);
010c3a89
RC
11181#endif
11182 }
11183 WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
d964ce36 11184 node = cfg->g_bss_cache_ctrl.m_cache_head;
010c3a89
RC
11185 for (i=0; node && i<WL_AP_MAX; i++) {
11186 bi = node->results.bss_info;
11187 err = wl_inform_single_bss(cfg, bi, false);
11188 node = node->next;
11189 }
d964ce36 11190 if (cfg->autochannel)
11191 wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, ioctl_version,
11192 &cfg->best_2g_ch, &cfg->best_5g_ch);
010c3a89
RC
11193#else
11194 WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
11195 preempt_disable();
11196 bi = next_bss(bss_list, bi);
11197 for_each_bss(bss_list, bi, i) {
11198 if (cfg->p2p_disconnected > 0 && !memcmp(&bi->BSSID, &cfg->disconnected_bssid, ETHER_ADDR_LEN))
11199 continue;
11200 err = wl_inform_single_bss(cfg, bi, false);
11201 }
11202 preempt_enable();
d964ce36 11203 if (cfg->autochannel)
11204 wl_ext_get_best_channel(ndev, bss_list, ioctl_version,
11205 &cfg->best_2g_ch, &cfg->best_5g_ch);
010c3a89
RC
11206#endif
11207
11208 if (cfg->p2p_disconnected > 0) {
11209 // terence 20130703: Fix for wrong group_capab (timing issue)
11210 cfg->p2p_disconnected++;
11211 if (cfg->p2p_disconnected >= REPEATED_SCAN_RESULT_CNT+1) {
11212 cfg->p2p_disconnected = 0;
11213 memset(&cfg->disconnected_bssid, 0, ETHER_ADDR_LEN);
11214 }
11215 }
11216
11217 return err;
11218}
11219
11220static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam)
11221{
11222 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
11223 struct ieee80211_mgmt *mgmt;
11224 struct ieee80211_channel *channel;
11225 struct ieee80211_supported_band *band;
11226 struct wl_cfg80211_bss_info *notif_bss_info;
11227 struct wl_scan_req *sr = wl_to_sr(cfg);
11228 struct beacon_proberesp *beacon_proberesp;
11229 struct cfg80211_bss *cbss = NULL;
11230 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11231 log_conn_event_t *event_data = NULL;
11232 tlv_log *tlv_data = NULL;
11233 u32 alloc_len, tlv_len;
11234 u32 payload_len;
11235 s32 mgmt_type;
11236 s32 signal;
11237 u32 freq;
11238 s32 err = 0;
11239 gfp_t aflags;
d964ce36 11240 chanspec_t chanspec;
010c3a89
RC
11241
11242 if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
11243 WL_DBG(("Beacon is larger than buffer. Discarding\n"));
11244 return err;
11245 }
11246 aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
11247 notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt)
11248 - sizeof(u8) + WL_BSS_INFO_MAX, aflags);
11249 if (unlikely(!notif_bss_info)) {
11250 WL_ERR(("notif_bss_info alloc failed\n"));
11251 return -ENOMEM;
11252 }
11253 mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
d964ce36 11254 chanspec = wl_chspec_driver_to_host(bi->chanspec);
11255 notif_bss_info->channel = wf_chspec_ctlchan(chanspec);
010c3a89
RC
11256
11257 if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
11258 band = wiphy->bands[IEEE80211_BAND_2GHZ];
11259 else
11260 band = wiphy->bands[IEEE80211_BAND_5GHZ];
11261 if (!band) {
11262 WL_ERR(("No valid band\n"));
11263 kfree(notif_bss_info);
11264 return -EINVAL;
11265 }
11266 notif_bss_info->rssi = dtoh16(bi->RSSI);
11267#if defined(RSSIAVG)
d964ce36 11268 notif_bss_info->rssi = wl_get_avg_rssi(&cfg->g_rssi_cache_ctrl, &bi->BSSID);
010c3a89
RC
11269 if (notif_bss_info->rssi == RSSI_MINVAL)
11270 notif_bss_info->rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
11271#endif
11272#if defined(RSSIOFFSET)
11273 notif_bss_info->rssi = wl_update_rssi_offset(bcmcfg_to_prmry_ndev(cfg), notif_bss_info->rssi);
11274#endif
11275#if !defined(RSSIAVG) && !defined(RSSIOFFSET)
11276 // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
11277 notif_bss_info->rssi = MIN(notif_bss_info->rssi, RSSI_MAXVAL);
11278#endif
11279 memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
11280 mgmt_type = cfg->active_scan ?
11281 IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
11282 if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
11283 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type);
11284 }
11285 beacon_proberesp = cfg->active_scan ?
11286 (struct beacon_proberesp *)&mgmt->u.probe_resp :
11287 (struct beacon_proberesp *)&mgmt->u.beacon;
11288 beacon_proberesp->timestamp = 0;
11289 beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
11290 beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
11291 wl_rst_ie(cfg);
11292 wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, roam);
11293 wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
11294 wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX -
11295 offsetof(struct wl_cfg80211_bss_info, frame_buf));
11296 notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
11297 u.beacon.variable) + wl_get_ielen(cfg);
11298#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
11299 freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
11300 (void)band->band;
11301#else
11302 freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
11303#endif
11304 if (freq == 0) {
11305 WL_ERR(("Invalid channel, fail to change channel to freq\n"));
11306 kfree(notif_bss_info);
11307 return -EINVAL;
11308 }
11309 channel = ieee80211_get_channel(wiphy, freq);
d964ce36 11310 WL_SCAN(("BSSID %pM, channel %2d(%2d %sMHz), rssi %3d, capa 0x04%x, mgmt_type %d, "
11311 "frame_len %d, SSID \"%s\"\n",
11312 &bi->BSSID, notif_bss_info->channel, CHSPEC_CHANNEL(chanspec),
11313 CHSPEC_IS20(chanspec)?"20":
11314 CHSPEC_IS40(chanspec)?"40":
11315 CHSPEC_IS80(chanspec)?"80":"160",
010c3a89
RC
11316 notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type,
11317 notif_bss_info->frame_len, bi->SSID));
11318 if (unlikely(!channel)) {
11319 WL_ERR(("ieee80211_get_channel error, freq=%d, channel=%d\n",
11320 freq, notif_bss_info->channel));
11321 kfree(notif_bss_info);
11322 return -EINVAL;
11323 }
11324
11325 signal = notif_bss_info->rssi * 100;
11326 if (!mgmt->u.probe_resp.timestamp) {
11327#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
11328 struct timespec ts;
11329 get_monotonic_boottime(&ts);
11330 mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000)
11331 + ts.tv_nsec / 1000;
11332#else
11333 struct timeval tv;
11334 do_gettimeofday(&tv);
11335 mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000)
11336 + tv.tv_usec;
11337#endif
11338 }
11339
11340
11341 cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
11342 le16_to_cpu(notif_bss_info->frame_len), signal, aflags);
11343 if (unlikely(!cbss)) {
11344 WL_ERR(("cfg80211_inform_bss_frame error\n"));
11345 err = -EINVAL;
11346 goto out_err;
11347 }
11348
11349 CFG80211_PUT_BSS(wiphy, cbss);
11350
11351 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID) &&
11352 (cfg->sched_scan_req && !cfg->scan_request)) {
11353 alloc_len = sizeof(log_conn_event_t) + IEEE80211_MAX_SSID_LEN + sizeof(uint16) +
11354 sizeof(int16);
11355 event_data = MALLOCZ(dhdp->osh, alloc_len);
11356 if (!event_data) {
11357 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
11358 "length(%d)\n", __func__, alloc_len));
11359 goto out_err;
11360 }
11361 tlv_len = 3 * sizeof(tlv_log);
11362 event_data->tlvs = MALLOC(dhdp->osh, tlv_len);
11363 if (!event_data->tlvs) {
11364 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
11365 "length(%d)\n", __func__, tlv_len));
11366 goto out_err;
11367 }
11368
11369 payload_len = sizeof(log_conn_event_t);
11370 event_data->event = WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND;
11371 tlv_data = event_data->tlvs;
11372
11373 /* ssid */
11374 tlv_data->tag = WIFI_TAG_SSID;
11375 tlv_data->len = bi->SSID_len;
11376 memcpy(tlv_data->value, bi->SSID, bi->SSID_len);
11377 payload_len += TLV_LOG_SIZE(tlv_data);
11378 tlv_data = TLV_LOG_NEXT(tlv_data);
11379
11380 /* channel */
11381 tlv_data->tag = WIFI_TAG_CHANNEL;
11382 tlv_data->len = sizeof(uint16);
11383 memcpy(tlv_data->value, &notif_bss_info->channel, sizeof(uint16));
11384 payload_len += TLV_LOG_SIZE(tlv_data);
11385 tlv_data = TLV_LOG_NEXT(tlv_data);
11386
11387 /* rssi */
11388 tlv_data->tag = WIFI_TAG_RSSI;
11389 tlv_data->len = sizeof(int16);
11390 memcpy(tlv_data->value, &notif_bss_info->rssi, sizeof(int16));
11391 payload_len += TLV_LOG_SIZE(tlv_data);
11392 tlv_data = TLV_LOG_NEXT(tlv_data);
11393
11394 dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
11395 event_data, payload_len);
11396 MFREE(dhdp->osh, event_data->tlvs, tlv_len);
11397 MFREE(dhdp->osh, event_data, alloc_len);
11398 }
11399
11400out_err:
11401 kfree(notif_bss_info);
11402 return err;
11403}
11404
11405static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev)
11406{
11407 u32 event = ntoh32(e->event_type);
11408 u32 status = ntoh32(e->status);
11409 u16 flags = ntoh16(e->flags);
11410#if defined(CUSTOM_SET_ANTNPM) || defined(CUSTOM_SET_OCLOFF)
11411 dhd_pub_t *dhd;
11412 dhd = (dhd_pub_t *)(cfg->pub);
11413#endif /* CUSTOM_SET_ANTNPM */
11414
11415 WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
11416 if (event == WLC_E_SET_SSID) {
11417 if (status == WLC_E_STATUS_SUCCESS) {
11418#ifdef CUSTOM_SET_ANTNPM
11419 if (dhd->mimo_ant_set) {
11420 int err = 0;
11421
11422 WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhd->mimo_ant_set));
11423 err = wldev_iovar_setint(ndev, "txchain", dhd->mimo_ant_set);
11424 if (err != 0) {
11425 WL_ERR(("[WIFI_SEC] Fail set txchain\n"));
11426 }
11427 err = wldev_iovar_setint(ndev, "rxchain", dhd->mimo_ant_set);
11428 if (err != 0) {
11429 WL_ERR(("[WIFI_SEC] Fail set rxchain\n"));
11430 }
11431 }
11432#endif /* CUSTOM_SET_ANTNPM */
11433#ifdef CUSTOM_SET_OCLOFF
11434 if (dhd->ocl_off) {
11435 int err = 0;
11436 int ocl_enable = 0;
11437 err = wldev_iovar_setint(ndev, "ocl_enable", ocl_enable);
11438 if (err != 0) {
11439 WL_ERR(("[WIFI_SEC] %s: Set ocl_enable %d failed %d\n",
11440 __FUNCTION__, ocl_enable, err));
11441 } else {
11442 WL_ERR(("[WIFI_SEC] %s: Set ocl_enable %d succeeded %d\n",
11443 __FUNCTION__, ocl_enable, err));
11444 }
11445 }
11446#endif /* CUSTOM_SET_OCLOFF */
11447 if (!wl_is_ibssmode(cfg, ndev))
11448 return true;
11449 }
11450 } else if (event == WLC_E_LINK) {
11451 if (flags & WLC_EVENT_MSG_LINK)
11452 return true;
11453 }
11454
11455 WL_DBG(("wl_is_linkup false\n"));
11456 return false;
11457}
11458
11459#ifdef WL_LASTEVT
11460static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, void *data)
11461{
11462 u32 event = ntoh32(e->event_type);
11463 u16 flags = ntoh16(e->flags);
11464 wl_last_event_t *last_event = (wl_last_event_t *)data;
11465 u32 len = ntoh32(e->datalen);
11466
11467 if (event == WLC_E_DEAUTH_IND ||
11468 event == WLC_E_DISASSOC_IND ||
11469 event == WLC_E_DISASSOC ||
11470 event == WLC_E_DEAUTH) {
11471 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
11472 return true;
11473 } else if (event == WLC_E_LINK) {
11474 if (!(flags & WLC_EVENT_MSG_LINK)) {
11475 if (last_event && len > 0) {
11476 u32 current_time = last_event->current_time;
11477 u32 timestamp = last_event->timestamp;
11478 u32 event_type = last_event->event.event_type;
11479 u32 status = last_event->event.status;
11480 u32 reason = last_event->event.reason;
11481
11482 WL_ERR(("Last roam event before disconnection : current_time %d,"
11483 " time %d, type %d, status %d, reason %d\n",
11484 current_time, timestamp, event_type, status, reason));
11485 }
11486 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
11487 return true;
11488 }
11489 }
11490
11491 return false;
11492}
11493#else
11494static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
11495{
11496 u32 event = ntoh32(e->event_type);
11497 u16 flags = ntoh16(e->flags);
11498
11499 if (event == WLC_E_DEAUTH_IND ||
11500 event == WLC_E_DISASSOC_IND ||
11501 event == WLC_E_DISASSOC ||
11502 event == WLC_E_DEAUTH) {
11503 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
11504 return true;
11505 } else if (event == WLC_E_LINK) {
11506 if (!(flags & WLC_EVENT_MSG_LINK)) {
11507 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
11508 return true;
11509 }
11510 }
11511
11512 return false;
11513}
11514#endif /* WL_LASTEVT */
11515
11516static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
11517{
11518 u32 event = ntoh32(e->event_type);
11519 u32 status = ntoh32(e->status);
11520
11521 if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS)
11522 return true;
11523 if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
11524 return true;
11525
11526 return false;
11527}
11528
11529/* The mainline kernel >= 3.2.0 has support for indicating new/del station
11530 * to AP/P2P GO via events. If this change is backported to kernel for which
11531 * this driver is being built, then define WL_CFG80211_STA_EVENT. You
11532 * should use this new/del sta event mechanism for BRCM supplicant >= 22.
11533 */
11534static s32
11535wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11536 const wl_event_msg_t *e, void *data)
11537{
11538 s32 err = 0;
11539 u32 event = ntoh32(e->event_type);
11540 u32 reason = ntoh32(e->reason);
11541 u32 len = ntoh32(e->datalen);
11542 u32 status = ntoh32(e->status);
11543
11544#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
11545 bool isfree = false;
11546 u8 *mgmt_frame;
11547 u8 bsscfgidx = e->bsscfgidx;
11548 s32 freq;
11549 s32 channel;
11550 u8 *body = NULL;
11551 u16 fc = 0;
11552
11553 struct ieee80211_supported_band *band;
11554 struct ether_addr da;
11555 struct ether_addr bssid;
11556 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
11557 channel_info_t ci;
11558#else
11559 struct station_info sinfo;
11560#endif
11561
11562 WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason));
11563 /* if link down, bsscfg is disabled. */
11564 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
11565 wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
11566 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
11567 WL_INFORM(("AP mode link down !! \n"));
11568 complete(&cfg->iface_disable);
11569 return 0;
11570 }
11571
11572 if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
11573 (reason == WLC_E_REASON_INITIAL_ASSOC) &&
11574 (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
11575 if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
11576 /* AP/GO brought up successfull in firmware */
11577 printf("%s: ** AP/GO Link up event **\n", __FUNCTION__);
11578 wl_set_drv_status(cfg, AP_CREATED, ndev);
11579 wake_up_interruptible(&cfg->netif_change_event);
91a2c117
RC
11580 if (!memcmp(ndev->name, WL_P2P_INTERFACE_PREFIX, strlen(WL_P2P_INTERFACE_PREFIX))) {
11581 dhd_conf_set_mchan_bw(cfg->pub, WL_P2P_IF_GO, -1);
11582 }
010c3a89
RC
11583 return 0;
11584 }
11585 }
11586
11587 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
11588 printf("%s: event %s(%d) status %d reason %d\n", __FUNCTION__,
11589 bcmevent_get_name(event), event, ntoh32(e->status), reason);
11590 }
11591
11592#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
11593 WL_DBG(("Enter \n"));
11594 if (!len && (event == WLC_E_DEAUTH)) {
11595 len = 2; /* reason code field */
11596 data = &reason;
11597 }
11598 if (len) {
11599 body = kzalloc(len, GFP_KERNEL);
11600
11601 if (body == NULL) {
11602 WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
11603 return WL_INVALID;
11604 }
11605 }
11606 memset(&bssid, 0, ETHER_ADDR_LEN);
11607 WL_DBG(("Enter event %d ndev %p\n", event, ndev));
11608 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
11609 kfree(body);
11610 return WL_INVALID;
11611 }
11612 if (len)
11613 memcpy(body, data, len);
11614
11615 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
11616 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
11617 memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
11618 memset(&bssid, 0, sizeof(bssid));
11619 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
11620 switch (event) {
11621 case WLC_E_ASSOC_IND:
11622 fc = FC_ASSOC_REQ;
11623 break;
11624 case WLC_E_REASSOC_IND:
11625 fc = FC_REASSOC_REQ;
11626 break;
11627 case WLC_E_DISASSOC_IND:
11628 fc = FC_DISASSOC;
11629 break;
11630 case WLC_E_DEAUTH_IND:
11631 fc = FC_DISASSOC;
11632 break;
11633 case WLC_E_DEAUTH:
11634 fc = FC_DISASSOC;
11635 break;
11636 default:
11637 fc = 0;
11638 goto exit;
11639 }
11640 memset(&ci, 0, sizeof(ci));
11641 if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
11642 kfree(body);
11643 return err;
11644 }
11645
11646 channel = dtoh32(ci.hw_channel);
11647 if (channel <= CH_MAX_2G_CHANNEL)
11648 band = wiphy->bands[IEEE80211_BAND_2GHZ];
11649 else
11650 band = wiphy->bands[IEEE80211_BAND_5GHZ];
11651 if (!band) {
11652 WL_ERR(("No valid band\n"));
11653 if (body)
11654 kfree(body);
11655 return -EINVAL;
11656 }
11657#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
11658 freq = ieee80211_channel_to_frequency(channel);
11659 (void)band->band;
11660#else
11661 freq = ieee80211_channel_to_frequency(channel, band->band);
11662#endif
11663
11664 err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
11665 &mgmt_frame, &len, body);
11666 if (err < 0)
11667 goto exit;
11668 isfree = true;
11669
11670 if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
11671 (event == WLC_E_DISASSOC_IND) ||
11672 ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
11673#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
11674 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
11675#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
11676 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
11677#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
11678 defined(WL_COMPAT_WIRELESS)
11679 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
11680#else
11681 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
11682#endif
11683 }
11684
11685exit:
11686 if (isfree)
11687 kfree(mgmt_frame);
11688 if (body)
11689 kfree(body);
11690#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
11691 sinfo.filled = 0;
11692 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
11693 reason == DOT11_SC_SUCCESS) {
11694 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
11695 * STATION_INFO_ASSOC_REQ_IES flag
11696 */
11697#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
11698 sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
11699#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
11700 if (!data) {
11701 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
11702 return -EINVAL;
11703 }
11704 sinfo.assoc_req_ies = data;
11705 sinfo.assoc_req_ies_len = len;
11706 printf("%s: connected device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
32c27b7a
RC
11707 wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
11708 WL_EXT_STATUS_GC_CONNECTED, NULL);
010c3a89
RC
11709 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
11710 } else if (event == WLC_E_DISASSOC_IND) {
11711 printf("%s: disassociated device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
32c27b7a
RC
11712 wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
11713 WL_EXT_STATUS_GC_DISCONNECTED, NULL);
010c3a89
RC
11714 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
11715 } else if ((event == WLC_E_DEAUTH_IND) ||
11716 ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED))) {
11717 printf("%s: deauthenticated device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
32c27b7a
RC
11718 wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
11719 WL_EXT_STATUS_GC_DISCONNECTED, NULL);
010c3a89
RC
11720 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
11721 }
11722#endif
11723 return err;
11724}
11725
11726#if defined(DHD_ENABLE_BIGDATA_LOGGING)
11727#define MAX_ASSOC_REJECT_ERR_STATUS 5
11728int wl_get_connect_failed_status(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
11729{
11730 u32 status = ntoh32(e->status);
11731
11732 cfg->assoc_reject_status = 0;
11733
11734 if (status == WLC_E_STATUS_FAIL) {
11735 WL_ERR(("auth assoc status event=%d e->status %d e->reason %d \n",
11736 ntoh32(cfg->event_auth_assoc.event_type),
11737 (int)ntoh32(cfg->event_auth_assoc.status),
11738 (int)ntoh32(cfg->event_auth_assoc.reason)));
11739
11740 switch ((int)ntoh32(cfg->event_auth_assoc.status)) {
11741 case WLC_E_STATUS_NO_ACK:
11742 cfg->assoc_reject_status = 1;
11743 break;
11744 case WLC_E_STATUS_FAIL:
11745 cfg->assoc_reject_status = 2;
11746 break;
11747 case WLC_E_STATUS_UNSOLICITED:
11748 cfg->assoc_reject_status = 3;
11749 break;
11750 case WLC_E_STATUS_TIMEOUT:
11751 cfg->assoc_reject_status = 4;
11752 break;
11753 case WLC_E_STATUS_ABORT:
11754 cfg->assoc_reject_status = 5;
11755 break;
11756 default:
11757 break;
11758 }
11759 if (cfg->assoc_reject_status) {
11760 if (ntoh32(cfg->event_auth_assoc.event_type) == WLC_E_ASSOC) {
11761 cfg->assoc_reject_status += MAX_ASSOC_REJECT_ERR_STATUS;
11762 }
11763 }
11764 }
11765
11766 WL_ERR(("assoc_reject_status %d \n", cfg->assoc_reject_status));
11767
11768 return 0;
11769}
11770
11771s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len)
11772{
11773 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11774 int bytes_written = 0;
11775
11776 if (cfg == NULL) {
11777 return -1;
11778 }
11779
11780 memset(cmd, 0, total_len);
11781 bytes_written = snprintf(cmd, 30, "assoc_reject.status %d", cfg->assoc_reject_status);
11782
11783 WL_ERR(("cmd: %s \n", cmd));
11784
11785 return bytes_written;
11786}
11787#endif /* DHD_ENABLE_BIGDATA_LOGGING */
11788
11789static s32
11790wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11791 const wl_event_msg_t *e)
11792{
11793 u32 reason = ntoh32(e->reason);
11794 u32 event = ntoh32(e->event_type);
11795 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
11796 WL_DBG(("event type : %d, reason : %d\n", event, reason));
11797
11798#if defined(DHD_ENABLE_BIGDATA_LOGGING)
11799 memcpy(&cfg->event_auth_assoc, e, sizeof(wl_event_msg_t));
11800 WL_ERR(("event=%d status %d reason %d \n",
11801 ntoh32(cfg->event_auth_assoc.event_type),
11802 ntoh32(cfg->event_auth_assoc.status),
11803 ntoh32(cfg->event_auth_assoc.reason)));
11804#endif /* DHD_ENABLE_BIGDATA_LOGGING */
11805 if (sec) {
11806 switch (event) {
11807 case WLC_E_ASSOC:
11808 case WLC_E_AUTH:
11809 sec->auth_assoc_res_status = reason;
11810 default:
11811 break;
11812 }
11813 } else
11814 WL_ERR(("sec is NULL\n"));
11815 return 0;
11816}
11817
11818static s32
11819wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11820 const wl_event_msg_t *e, void *data)
11821{
11822 s32 err = 0;
11823 u32 event = ntoh32(e->event_type);
11824 u16 flags = ntoh16(e->flags);
11825 u32 status = ntoh32(e->status);
11826 bool active;
11827#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11828 struct ieee80211_channel *channel = NULL;
11829 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
11830 u32 chanspec, chan;
11831 u32 freq, band;
11832#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
11833
11834 if (event == WLC_E_JOIN) {
11835 WL_DBG(("joined in IBSS network\n"));
11836 }
11837 if (event == WLC_E_START) {
11838 WL_DBG(("started IBSS network\n"));
11839 }
11840 if (event == WLC_E_JOIN || event == WLC_E_START ||
11841 (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
11842#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11843 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
11844 if (unlikely(err)) {
11845 WL_ERR(("Could not get chanspec %d\n", err));
11846 return err;
11847 }
11848 chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
11849 band = (chan <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
11850 freq = ieee80211_channel_to_frequency(chan, band);
11851 channel = ieee80211_get_channel(wiphy, freq);
11852#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
11853 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
11854 /* ROAM or Redundant */
11855 u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
11856 if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
11857 WL_DBG(("IBSS connected event from same BSSID("
11858 MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
11859 return err;
11860 }
11861 WL_INFORM(("IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
11862 MAC2STRDBG(cur_bssid), MAC2STRDBG((const u8 *)&e->addr)));
11863 wl_get_assoc_ies(cfg, ndev);
11864 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
11865 wl_update_bss_info(cfg, ndev, false);
11866#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11867 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
11868#else
11869 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
11870#endif
11871 }
11872 else {
11873 /* New connection */
11874 WL_INFORM(("IBSS connected to " MACDBG "\n",
11875 MAC2STRDBG((const u8 *)&e->addr)));
11876 wl_link_up(cfg);
11877 wl_get_assoc_ies(cfg, ndev);
11878 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
11879 wl_update_bss_info(cfg, ndev, false);
11880#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11881 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
11882#else
11883 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
11884#endif
11885 wl_set_drv_status(cfg, CONNECTED, ndev);
11886 active = true;
11887 wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
11888 }
11889 } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
11890 event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
11891 wl_clr_drv_status(cfg, CONNECTED, ndev);
11892 wl_link_down(cfg);
11893 wl_init_prof(cfg, ndev);
11894 }
11895 else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
11896 WL_DBG(("no action - join fail (IBSS mode)\n"));
11897 }
11898 else {
11899 WL_DBG(("no action (IBSS mode)\n"));
11900}
11901 return err;
11902}
11903
11904#if defined(DHD_ENABLE_BIGDATA_LOGGING)
11905#define WiFiALL_OUI "\x50\x6F\x9A" /* Wi-FiAll OUI */
11906#define WiFiALL_OUI_LEN 3
11907#define WiFiALL_OUI_TYPE 16
11908
11909int wl_get_bss_info(struct bcm_cfg80211 *cfg, struct net_device *dev, uint8 *mac)
11910{
11911 s32 err = 0;
11912 struct wl_bss_info *bi;
11913 uint8 eabuf[ETHER_ADDR_LEN];
11914 u32 rate, channel, freq, supported_rate, nss = 0, mcs_map, mode_80211 = 0;
11915 char rate_str[4];
11916 u8 *ie = NULL;
11917 u32 ie_len;
11918 struct wiphy *wiphy;
11919 struct cfg80211_bss *bss;
11920 bcm_tlv_t *interworking_ie = NULL;
11921 bcm_tlv_t *tlv_ie = NULL;
11922 bcm_tlv_t *vht_ie = NULL;
11923 vndr_ie_t *vndrie;
11924 int16 ie_11u_rel_num = -1, ie_mu_mimo_cap = -1;
11925 u32 i, remained_len, count = 0;
11926 char roam_count_str[4], akm_str[4];
11927 s32 val = 0;
11928
11929 /* get BSS information */
11930
11931 strncpy(cfg->bss_info, "x x x x x x x x x x x x x", GET_BSS_INFO_LEN);
11932
11933 memset(cfg->extra_buf, 0, WL_EXTRA_BUF_MAX);
11934 *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
11935
11936 err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, cfg->extra_buf, WL_EXTRA_BUF_MAX);
11937 if (unlikely(err)) {
11938 WL_ERR(("Could not get bss info %d\n", err));
11939 cfg->roam_count = 0;
11940 return -1;
11941 }
11942
11943 if (!mac) {
11944 WL_ERR(("mac is null \n"));
11945 cfg->roam_count = 0;
11946 return -1;
11947 }
11948
11949 memcpy(eabuf, mac, ETHER_ADDR_LEN);
11950
11951 bi = (struct wl_bss_info *)(cfg->extra_buf + 4);
11952 channel = wf_chspec_ctlchan(bi->chanspec);
11953
11954#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
11955 freq = ieee80211_channel_to_frequency(channel);
11956#else
11957 if (channel > 14) {
11958 freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
11959 } else {
11960 freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
11961 }
11962#endif
11963 rate = 0;
11964 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
11965 if (err) {
11966 WL_ERR(("Could not get rate (%d)\n", err));
11967 snprintf(rate_str, sizeof(rate_str), "x"); // Unknown
11968
11969 } else {
11970 rate = dtoh32(rate);
11971 snprintf(rate_str, sizeof(rate_str), "%d", (rate/2));
11972 }
11973
11974 //supported maximum rate
11975 supported_rate = (bi->rateset.rates[bi->rateset.count - 1] & 0x7f) / 2;
11976
11977 if (supported_rate < 12) {
11978 mode_80211 = 0; //11b maximum rate is 11Mbps. 11b mode
11979 } else {
11980 //It's not HT Capable case.
11981 if (channel > 14) {
11982 mode_80211 = 3; // 11a mode
11983 } else {
11984 mode_80211 = 1; // 11g mode
11985 }
11986 }
11987
11988 if (bi->n_cap) {
11989 /* check Rx MCS Map for HT */
11990 nss = 0;
11991 mode_80211 = 2;
11992 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
11993 int8 bitmap = 0xFF;
11994 if (i == MAX_STREAMS_SUPPORTED-1) {
11995 bitmap = 0x7F;
11996 }
11997 if (bi->basic_mcs[i] & bitmap) {
11998 nss++;
11999 }
12000 }
12001 }
12002
12003 if (bi->vht_cap) {
12004 nss = 0;
12005 mode_80211 = 4;
12006 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
12007 mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
12008 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
12009 nss++;
12010 }
12011 }
12012 }
12013
12014 if (nss) {
12015 nss = nss - 1;
12016 }
12017
12018 wiphy = bcmcfg_to_wiphy(cfg);
12019 bss = CFG80211_GET_BSS(wiphy, NULL, eabuf, bi->SSID, bi->SSID_len);
12020 if (!bss) {
12021 WL_ERR(("Could not find the AP\n"));
12022 } else {
12023#if defined(WL_CFG80211_P2P_DEV_IF)
12024 ie = (u8 *)bss->ies->data;
12025 ie_len = bss->ies->len;
12026#else
12027 ie = bss->information_elements;
12028 ie_len = bss->len_information_elements;
12029#endif /* WL_CFG80211_P2P_DEV_IF */
12030 }
12031
12032 if (ie) {
12033 ie_mu_mimo_cap = 0;
12034 ie_11u_rel_num = 0;
12035
12036 if (bi->vht_cap) {
12037 if ((vht_ie = bcm_parse_tlvs(ie, (u32)ie_len,
12038 DOT11_MNG_VHT_CAP_ID)) != NULL) {
12039 ie_mu_mimo_cap = (vht_ie->data[2] & 0x08) >> 3;
12040 }
12041 }
12042
12043 if ((interworking_ie = bcm_parse_tlvs(ie, (u32)ie_len,
12044 DOT11_MNG_INTERWORKING_ID)) != NULL) {
12045 if ((tlv_ie = bcm_parse_tlvs(ie, (u32)ie_len, DOT11_MNG_VS_ID)) != NULL) {
12046 remained_len = ie_len;
12047
12048 while (tlv_ie) {
12049 if (count > MAX_VNDR_IE_NUMBER)
12050 break;
12051
12052 if (tlv_ie->id == DOT11_MNG_VS_ID) {
12053 vndrie = (vndr_ie_t *) tlv_ie;
12054
12055 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
12056 WL_ERR(("%s: invalid vndr ie."
12057 "length is too small %d\n",
12058 __FUNCTION__, vndrie->len));
12059 break;
12060 }
12061
12062 if (!bcmp(vndrie->oui,
12063 (u8*)WiFiALL_OUI, WiFiALL_OUI_LEN) &&
12064 (vndrie->data[0] == WiFiALL_OUI_TYPE))
12065 {
12066 WL_ERR(("Found Wi-FiAll OUI oui.\n"));
12067 ie_11u_rel_num = vndrie->data[1];
12068 ie_11u_rel_num = (ie_11u_rel_num & 0xf0)>>4;
12069 ie_11u_rel_num += 1;
12070
12071 break;
12072 }
12073 }
12074 count++;
12075 tlv_ie = bcm_next_tlv(tlv_ie, &remained_len);
12076 }
12077 }
12078 }
12079 }
12080
12081 for (i = 0; i < bi->SSID_len; i++) {
12082 if (bi->SSID[i] == ' ') {
12083 bi->SSID[i] = '_';
12084 }
12085 }
12086
12087 //0 : None, 1 : OKC, 2 : FT, 3 : CCKM
12088 err = wldev_iovar_getint(dev, "wpa_auth", &val);
12089 if (unlikely(err)) {
12090 WL_ERR(("could not get wpa_auth (%d)\n", err));
12091 snprintf(akm_str, sizeof(akm_str), "x"); // Unknown
12092 } else {
12093 WL_ERR(("wpa_auth val %d \n", val));
12094#if defined(BCMEXTCCX)
12095 if (val & (WPA_AUTH_CCKM | WPA2_AUTH_CCKM)) {
12096 snprintf(akm_str, sizeof(akm_str), "3");
12097 } else
12098#endif
12099 if (val & WPA2_AUTH_FT) {
12100 snprintf(akm_str, sizeof(akm_str), "2");
12101 } else if (val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) {
12102 snprintf(akm_str, sizeof(akm_str), "1");
12103 } else {
12104 snprintf(akm_str, sizeof(akm_str), "0");
12105 }
12106 }
12107
12108 if (cfg->roam_offload) {
12109 snprintf(roam_count_str, sizeof(roam_count_str), "x"); // Unknown
12110 } else {
12111 snprintf(roam_count_str, sizeof(roam_count_str), "%d", cfg->roam_count);
12112 }
12113 cfg->roam_count = 0;
12114
12115 WL_ERR(("BSSID:" MACDBG " SSID %s \n", MAC2STRDBG(eabuf), bi->SSID));
12116 WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d,"
12117 "MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n"
12118 "akm:%s roam:%s \n",
12119 freq, wf_chspec_to_bw_str(bi->chanspec),
12120 dtoh32(bi->RSSI), (rate / 2), mode_80211, nss,
12121 ie_mu_mimo_cap, ie_11u_rel_num, bi->SNR, bi->phy_noise,
12122 akm_str, roam_count_str));
12123
12124 if (ie) {
12125 snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
12126 "%02x:%02x:%02x %d %s %d %s %d %d %d %d %d %d %s %s",
12127 eabuf[0], eabuf[1], eabuf[2],
12128 freq, wf_chspec_to_bw_str(bi->chanspec),
12129 dtoh32(bi->RSSI), rate_str, mode_80211, nss,
12130 ie_mu_mimo_cap, ie_11u_rel_num,
12131 bi->SNR, bi->phy_noise, akm_str, roam_count_str);
12132 } else {
12133 //ie_mu_mimo_cap and ie_11u_rel_num is unknow.
12134 snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
12135 "%02x:%02x:%02x %d %s %d %s %d %d x x %d %d %s %s",
12136 eabuf[0], eabuf[1], eabuf[2],
12137 freq, wf_chspec_to_bw_str(bi->chanspec),
12138 dtoh32(bi->RSSI), rate_str, mode_80211, nss,
12139 bi->SNR, bi->phy_noise, akm_str, roam_count_str);
12140 }
12141
12142 CFG80211_PUT_BSS(wiphy, bss);
12143
12144 return 0;
12145}
12146
12147s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len)
12148{
12149 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
12150
12151 if (cfg == NULL) {
12152 return -1;
12153 }
12154
12155 memset(cmd, 0, total_len);
12156 memcpy(cmd, cfg->bss_info, GET_BSS_INFO_LEN);
12157
12158 WL_ERR(("cmd: %s \n", cmd));
12159
12160 return GET_BSS_INFO_LEN;
12161}
12162
12163#endif /* DHD_ENABLE_BIGDATA_LOGGING */
12164
12165static s32
12166wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12167 const wl_event_msg_t *e, void *data)
12168{
12169 bool act;
12170 struct net_device *ndev = NULL;
12171 s32 err = 0;
12172 u32 event = ntoh32(e->event_type);
12173 struct wiphy *wiphy = NULL;
12174 struct cfg80211_bss *bss = NULL;
12175 struct wlc_ssid *ssid = NULL;
12176 u8 *bssid = 0;
12177 dhd_pub_t *dhdp;
12178 int vndr_oui_num = 0;
12179 char vndr_oui[MAX_VNDR_OUI_STR_LEN] = {0, };
12180
12181 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12182 dhdp = (dhd_pub_t *)(cfg->pub);
12183 BCM_REFERENCE(dhdp);
12184
12185 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
12186 err = wl_notify_connect_status_ap(cfg, ndev, e, data);
12187 } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS) {
12188 err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
12189 } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) {
12190 WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n",
12191 ntoh32(e->event_type), ntoh32(e->status), ndev));
12192 if (event == WLC_E_ASSOC || event == WLC_E_AUTH) {
12193 wl_get_auth_assoc_status(cfg, ndev, e);
12194 return 0;
12195 }
12196 DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
12197 if (wl_is_linkup(cfg, e, ndev)) {
12198 wl_link_up(cfg);
12199 act = true;
12200 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
12201 if (event == WLC_E_LINK &&
12202#ifdef DHD_LOSSLESS_ROAMING
12203 !cfg->roam_offload &&
12204#endif /* DHD_LOSSLESS_ROAMING */
12205 wl_get_drv_status(cfg, CONNECTED, ndev)) {
12206 wl_bss_roaming_done(cfg, ndev, e, data);
12207 }
12208
12209 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
12210 vndr_oui_num = wl_vndr_ies_get_vendor_oui(cfg,
12211 ndev, vndr_oui, ARRAYSIZE(vndr_oui));
12212#if defined(STAT_REPORT)
12213 /* notify STA connection only */
12214 wl_stat_report_notify_connected(cfg);
12215#endif /* STAT_REPORT */
12216 }
12217
12218 printf("wl_bss_connect_done succeeded with "
12219 MACDBG " %s%s\n", MAC2STRDBG((const u8*)(&e->addr)),
12220 vndr_oui_num > 0 ? "vndr_oui: " : "",
12221 vndr_oui_num > 0 ? vndr_oui : "");
12222
12223 wl_bss_connect_done(cfg, ndev, e, data, true);
12224 dhd_conf_set_intiovar(cfg->pub, WLC_SET_VAR, "phy_oclscdenable", cfg->pub->conf->phy_oclscdenable, 0, FALSE);
12225 WL_DBG(("joined in BSS network \"%s\"\n",
12226 ((struct wlc_ssid *)
12227 wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID));
12228
12229#ifdef WBTEXT
12230 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
12231 dhdp->wbtext_support &&
12232 event == WLC_E_SET_SSID) {
12233 /* set wnm_keepalives_max_idle after association */
12234 wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
12235 /* send nbr request or BTM query to update RCC */
12236 wl_cfg80211_wbtext_update_rcc(cfg, ndev);
12237 }
12238#endif /* WBTEXT */
12239 }
12240 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
12241 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
12242 dhd_conf_set_wme(cfg->pub, 0);
91a2c117
RC
12243 if (!memcmp(ndev->name, WL_P2P_INTERFACE_PREFIX, strlen(WL_P2P_INTERFACE_PREFIX))) {
12244 dhd_conf_set_mchan_bw(cfg->pub, WL_P2P_IF_CLIENT, -1);
12245 }
010c3a89
RC
12246 } else if (WL_IS_LINKDOWN(cfg, e, data) ||
12247 ((event == WLC_E_SET_SSID) &&
12248 (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) &&
12249 (wl_get_drv_status(cfg, CONNECTED, ndev)))) {
12250
12251 WL_INFORM(("connection state bit status: [%d:%d:%d:%d]\n",
12252 wl_get_drv_status(cfg, CONNECTING, ndev),
12253 wl_get_drv_status(cfg, CONNECTED, ndev),
12254 wl_get_drv_status(cfg, DISCONNECTING, ndev),
12255 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
12256
12257 if (wl_get_drv_status(cfg, DISCONNECTING, ndev) &&
12258 (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) ||
12259 wl_get_drv_status(cfg, CONNECTING, ndev))) {
12260 /* wl_cfg80211_connect was called before 'DISCONNECTING' was
12261 * cleared. Deauth/Link down event is caused by WLC_DISASSOC
12262 * command issued from the wl_cfg80211_connect context. Ignore
12263 * the event to avoid pre-empting the current connection
12264 */
12265 WL_INFORM(("Nested connection case. Drop event. \n"));
12266 wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
12267 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
12268 /* Not in 'CONNECTED' state, clear it */
12269 wl_clr_drv_status(cfg, CONNECTED, ndev);
12270 return 0;
12271 }
12272
12273#ifdef DHD_LOSSLESS_ROAMING
12274 wl_del_roam_timeout(cfg);
12275#endif
12276#ifdef P2PLISTEN_AP_SAMECHN
12277 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
12278 wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0);
12279 cfg->p2p_resp_apchn_status = false;
12280 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
12281 }
12282#endif /* P2PLISTEN_AP_SAMECHN */
12283 wl_cfg80211_cancel_scan(cfg);
12284
12285#if defined(DHD_ENABLE_BIGDATA_LOGGING)
12286 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12287 wl_get_bss_info(cfg, ndev, (u8*)(&e->addr));
12288 }
12289#endif /* DHD_ENABLE_BIGDATA_LOGGING */
dfb0f3ae
RC
12290 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12291 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
12292 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
12293 bool fw_assoc_state = TRUE;
12294 dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
12295 fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
12296 if (!fw_assoc_state) {
12297 WL_ERR(("Event sends up even different BSSID"
12298 " cur: " MACDBG " event: " MACDBG"\n",
12299 MAC2STRDBG(curbssid),
12300 MAC2STRDBG((const u8*)(&e->addr))));
12301 } else {
12302 WL_ERR(("BSSID of event is not the connected BSSID"
12303 "(ignore it) cur: " MACDBG
12304 " event: " MACDBG"\n",
12305 MAC2STRDBG(curbssid),
12306 MAC2STRDBG((const u8*)(&e->addr))));
12307 return 0;
12308 }
12309 }
12310 }
010c3a89
RC
12311 /* Explicitly calling unlink to remove BSS in CFG */
12312 wiphy = bcmcfg_to_wiphy(cfg);
12313 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
12314 bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
12315 if (ssid && bssid) {
12316 bss = CFG80211_GET_BSS(wiphy, NULL, bssid,
12317 ssid->SSID, ssid->SSID_len);
12318 if (bss) {
12319 cfg80211_unlink_bss(wiphy, bss);
12320 CFG80211_PUT_BSS(wiphy, bss);
12321 }
12322 }
12323
12324 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12325 scb_val_t scbval;
12326 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
12327 s32 reason = 0;
12328 struct ether_addr bssid_dongle = {{0, 0, 0, 0, 0, 0}};
12329 struct ether_addr bssid_null = {{0, 0, 0, 0, 0, 0}};
12330
12331 if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND)
12332 reason = ntoh32(e->reason);
12333 /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */
12334 reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason;
12335
12336 printf("link down if %s may call cfg80211_disconnected. "
12337 "event : %d, reason=%d from " MACDBG "\n",
12338 ndev->name, event, ntoh32(e->reason),
12339 MAC2STRDBG((const u8*)(&e->addr)));
32c27b7a
RC
12340 wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
12341 WL_EXT_STATUS_DISCONNECTED, NULL);
010c3a89
RC
12342
12343 /* roam offload does not sync BSSID always, get it from dongle */
12344 if (cfg->roam_offload) {
12345 memset(&bssid_dongle, 0, sizeof(bssid_dongle));
12346 if (wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid_dongle,
12347 sizeof(bssid_dongle)) == BCME_OK) {
12348 /* if not roam case, it would return null bssid */
12349 if (memcmp(&bssid_dongle, &bssid_null,
12350 ETHER_ADDR_LEN) != 0) {
12351 curbssid = (u8 *)&bssid_dongle;
12352 }
12353 }
12354 }
12355 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
12356 bool fw_assoc_state = TRUE;
12357 dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
12358 fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
12359 if (!fw_assoc_state) {
12360 WL_ERR(("Event sends up even different BSSID"
12361 " cur: " MACDBG " event: " MACDBG"\n",
12362 MAC2STRDBG(curbssid),
12363 MAC2STRDBG((const u8*)(&e->addr))));
12364 } else {
12365 WL_ERR(("BSSID of event is not the connected BSSID"
12366 "(ignore it) cur: " MACDBG
12367 " event: " MACDBG"\n",
12368 MAC2STRDBG(curbssid),
12369 MAC2STRDBG((const u8*)(&e->addr))));
12370 return 0;
12371 }
12372 }
12373
12374#ifdef DBG_PKT_MON
12375 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
12376 DHD_DBG_PKT_MON_STOP(dhdp);
12377 }
12378#endif /* DBG_PKT_MON */
12379
12380 /* clear RSSI monitor, framework will set new cfg */
12381#ifdef RSSI_MONITOR_SUPPORT
12382 dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
12383 FALSE, 0, 0);
12384#endif /* RSSI_MONITOR_SUPPORT */
12385 if (!memcmp(ndev->name, WL_P2P_INTERFACE_PREFIX, strlen(WL_P2P_INTERFACE_PREFIX))) {
12386 // terence 20130703: Fix for wrong group_capab (timing issue)
12387 cfg->p2p_disconnected = 1;
12388 }
12389#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
12390 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
12391 CFG80211_DISCONNECTED(ndev, reason, NULL, 0, false, GFP_KERNEL);
12392 }
12393#endif
12394 memcpy(&cfg->disconnected_bssid, curbssid, ETHER_ADDR_LEN);
12395 wl_clr_drv_status(cfg, CONNECTED, ndev);
12396
12397 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
12398 /* To make sure disconnect, explictly send dissassoc
12399 * for BSSID 00:00:00:00:00:00 issue
12400 */
12401 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
12402
12403 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
12404 scbval.val = htod32(scbval.val);
12405 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
12406 sizeof(scb_val_t));
12407 if (err < 0) {
12408 WL_ERR(("WLC_DISASSOC error %d\n", err));
12409 err = 0;
12410 }
12411 }
12412
12413 /* Send up deauth and clear states */
12414 CFG80211_DISCONNECTED(ndev, reason, NULL, 0,
12415 false, GFP_KERNEL);
12416 wl_link_down(cfg);
12417 wl_init_prof(cfg, ndev);
12418#ifdef WBTEXT
12419 /* when STA was disconnected, clear join pref and set wbtext */
12420 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) {
12421 char smbuf[WLC_IOCTL_SMLEN];
12422 char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03,
12423 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
12424 if ((err = wldev_iovar_setbuf(ndev, "join_pref",
12425 clear, sizeof(clear), smbuf,
12426 sizeof(smbuf), NULL))
12427 == BCME_OK) {
12428 if ((err = wldev_iovar_setint(ndev,
12429 "wnm_bsstrans_resp",
12430 WL_BSSTRANS_POLICY_PRODUCT_WBTEXT))
12431 == BCME_OK) {
12432 wl_cfg80211_wbtext_set_default(ndev);
12433 } else {
12434 WL_ERR(("%s: Failed to set wbtext = %d\n",
12435 __FUNCTION__, err));
12436 }
12437 } else {
12438 WL_ERR(("%s: Failed to clear join pref = %d\n",
12439 __FUNCTION__, err));
12440 }
12441 wl_cfg80211_wbtext_clear_bssid_list(cfg);
12442 }
12443#endif /* WBTEXT */
12444 wl_vndr_ies_clear_vendor_oui_list(cfg);
12445 }
12446 else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
12447 printf("link down, during connecting\n");
32c27b7a
RC
12448 wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
12449 WL_EXT_STATUS_DISCONNECTED, NULL);
010c3a89
RC
12450 /* Issue WLC_DISASSOC to prevent FW roam attempts */
12451 err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
12452 if (err < 0) {
12453 WL_ERR(("CONNECTING state, WLC_DISASSOC error %d\n", err));
12454 err = 0;
12455 }
12456 WL_INFORM(("Clear drv CONNECTING status\n"));
12457 wl_clr_drv_status(cfg, CONNECTING, ndev);
12458#ifdef ESCAN_RESULT_PATCH
12459 if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) ||
12460 (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) ||
12461 (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0))
12462 /* In case this event comes while associating another AP */
12463#endif /* ESCAN_RESULT_PATCH */
12464 wl_bss_connect_done(cfg, ndev, e, data, false);
12465 }
12466 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
12467
12468 /* if link down, bsscfg is diabled */
12469 if (ndev != bcmcfg_to_prmry_ndev(cfg))
12470 complete(&cfg->iface_disable);
12471#ifdef WLTDLS
12472 /* re-enable TDLS if the number of connected interfaces
12473 * is less than 2.
12474 */
12475 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
12476#endif /* WLTDLS */
12477 } else if (wl_is_nonetwork(cfg, e)) {
12478 printf("connect failed event=%d e->status %d e->reason %d \n",
12479 event, (int)ntoh32(e->status), (int)ntoh32(e->reason));
32c27b7a
RC
12480 wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
12481 WL_EXT_STATUS_DISCONNECTED, NULL);
010c3a89
RC
12482#if defined(DHD_ENABLE_BIGDATA_LOGGING)
12483 if (event == WLC_E_SET_SSID) {
12484 wl_get_connect_failed_status(cfg, e);
12485 }
12486#endif /* DHD_ENABLE_BIGDATA_LOGGING */
12487
12488 if (wl_get_drv_status(cfg, DISCONNECTING, ndev) &&
12489 wl_get_drv_status(cfg, CONNECTING, ndev)) {
12490 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
12491 wl_clr_drv_status(cfg, CONNECTING, ndev);
12492 wl_cfg80211_scan_abort(cfg);
12493 DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
12494 return err;
12495 }
12496 /* Clean up any pending scan request */
12497 wl_cfg80211_cancel_scan(cfg);
12498
12499 if (wl_get_drv_status(cfg, CONNECTING, ndev))
12500 wl_bss_connect_done(cfg, ndev, e, data, false);
12501 } else {
12502 WL_DBG(("%s nothing\n", __FUNCTION__));
12503 }
12504 DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
12505 }
d964ce36 12506 else {
12507 printf("wl_notify_connect_status : Invalid %s mode %d event %d status %d\n",
12508 ndev->name, wl_get_mode_by_netdev(cfg, ndev), ntoh32(e->event_type),
12509 ntoh32(e->status));
010c3a89
RC
12510 }
12511 return err;
12512}
12513
12514#ifdef WL_RELMCAST
12515void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
12516{
12517 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
12518 if (pid > 0)
12519 cfg->rmc_event_pid = pid;
12520 WL_DBG(("set pid for rmc event : pid=%d\n", pid));
12521}
12522#endif /* WL_RELMCAST */
12523
12524#ifdef WL_RELMCAST
12525static s32
12526wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12527 const wl_event_msg_t *e, void *data)
12528{
12529 u32 evt = ntoh32(e->event_type);
12530 u32 reason = ntoh32(e->reason);
12531 int ret = -1;
12532
12533 switch (reason) {
12534 case WLC_E_REASON_RMC_AR_LOST:
12535 case WLC_E_REASON_RMC_AR_NO_ACK:
12536 if (cfg->rmc_event_pid != 0) {
12537 ret = wl_netlink_send_msg(cfg->rmc_event_pid,
12538 RMC_EVENT_LEADER_CHECK_FAIL,
12539 cfg->rmc_event_seq++, NULL, 0);
12540 }
12541 break;
12542 default:
12543 break;
12544 }
12545 WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
12546 return ret;
12547}
12548#endif /* WL_RELMCAST */
12549
12550#ifdef GSCAN_SUPPORT
12551static s32
12552wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12553 const wl_event_msg_t *e, void *data)
12554{
12555 struct net_device *ndev = NULL;
12556 u32 datalen = be32_to_cpu(e->datalen);
12557
12558 if (datalen) {
12559 wl_roam_exp_event_t *evt_data = (wl_roam_exp_event_t *)data;
12560 if (evt_data->version == ROAM_EXP_EVENT_VERSION) {
12561 wlc_ssid_t *ssid = &evt_data->cur_ssid;
12562 struct wireless_dev *wdev;
12563 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12564 if (ndev) {
12565 wdev = ndev->ieee80211_ptr;
12566 wdev->ssid_len = min(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN);
12567 memcpy(wdev->ssid, ssid->SSID, wdev->ssid_len);
12568 WL_ERR(("SSID is %s\n", ssid->SSID));
12569 wl_update_prof(cfg, ndev, NULL, ssid, WL_PROF_SSID);
12570 } else {
12571 WL_ERR(("NULL ndev!\n"));
12572 }
12573 } else {
12574 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
12575 ROAM_EXP_EVENT_VERSION));
12576 }
12577 }
12578 return BCME_OK;
12579}
12580#endif /* GSCAN_SUPPORT */
12581
12582#ifdef RSSI_MONITOR_SUPPORT
12583static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12584 const wl_event_msg_t *e, void *data)
12585{
12586
12587#if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
12588 u32 datalen = be32_to_cpu(e->datalen);
12589 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12590 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
12591
12592 if (datalen) {
12593 wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data;
12594 if (evt_data->version == RSSI_MONITOR_VERSION) {
12595 dhd_rssi_monitor_evt_t monitor_data;
12596 monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION;
12597 monitor_data.cur_rssi = evt_data->cur_rssi;
12598 memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN);
12599 wl_cfgvendor_send_async_event(wiphy, ndev,
12600 GOOGLE_RSSI_MONITOR_EVENT,
12601 &monitor_data, sizeof(monitor_data));
12602 } else {
12603 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
12604 RSSI_MONITOR_VERSION));
12605 }
12606 }
12607#endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
12608 return BCME_OK;
12609}
12610#endif /* RSSI_MONITOR_SUPPORT */
12611
12612static s32
12613wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12614 const wl_event_msg_t *e, void *data)
12615{
12616 bool act;
12617 struct net_device *ndev = NULL;
12618 s32 err = 0;
12619 u32 event = be32_to_cpu(e->event_type);
12620 u32 status = be32_to_cpu(e->status);
12621#ifdef DHD_LOSSLESS_ROAMING
12622 struct wl_security *sec;
12623#endif
12624 WL_DBG(("Enter \n"));
12625
12626 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12627
12628 if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
12629 wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
12630 cfg->disable_roam_event = TRUE;
12631 }
12632
12633 if ((cfg->disable_roam_event) && (event == WLC_E_ROAM))
12634 return err;
12635
12636 if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
12637 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12638#ifdef DHD_LOSSLESS_ROAMING
12639 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
12640 /* In order to reduce roaming delay, wl_bss_roaming_done is
12641 * early called with WLC_E_LINK event. It is called from
12642 * here only if WLC_E_LINK event is blocked for specific
12643 * security type.
12644 */
12645 if (IS_AKM_SUITE_FT(sec)) {
12646 wl_bss_roaming_done(cfg, ndev, e, data);
12647 }
12648 /* Roam timer is deleted mostly from wl_cfg80211_change_station
12649 * after roaming is finished successfully. We need to delete
12650 * the timer from here only for some security types that aren't
12651 * using wl_cfg80211_change_station to authorize SCB
12652 */
12653 if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
12654 wl_del_roam_timeout(cfg);
12655 }
12656#else
12657 wl_bss_roaming_done(cfg, ndev, e, data);
12658#endif /* DHD_LOSSLESS_ROAMING */
12659 } else {
12660 wl_bss_connect_done(cfg, ndev, e, data, true);
12661 }
12662 act = true;
12663 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
12664 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
12665
12666 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
12667 wl_vndr_ies_get_vendor_oui(cfg, ndev, NULL, 0);
12668 }
12669 }
12670#ifdef DHD_LOSSLESS_ROAMING
12671 else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) {
12672 wl_del_roam_timeout(cfg);
12673 }
12674#endif
12675 return err;
12676}
12677
12678#ifdef CUSTOM_EVENT_PM_WAKE
12679uint32 last_dpm_upd_time = 0; /* ms */
12680#define DPM_UPD_LMT_TIME 25000 /* ms */
12681#define DPM_UPD_LMT_RSSI -85 /* dbm */
12682
12683static s32
12684wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12685 const wl_event_msg_t *e, void *data)
12686{
12687 s32 err = BCME_OK;
12688 struct net_device *ndev = NULL;
12689 u8 *pbuf = NULL;
12690 uint32 cur_dpm_upd_time = 0;
12691 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12692 s32 rssi;
12693 scb_val_t scb_val;
12694
12695 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12696
12697 pbuf = kzalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
12698 if (pbuf == NULL) {
12699 WL_ERR(("failed to allocate local pbuf\n"));
12700 return -ENOMEM;
12701 }
12702
12703 err = wldev_iovar_getbuf_bsscfg(ndev, "dump",
12704 "pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
12705
12706 if (err) {
12707 WL_ERR(("dump ioctl err = %d", err));
12708 } else {
12709 WL_ERR(("PM status : %s\n", pbuf));
12710 }
12711
12712 if (pbuf) {
12713 kfree(pbuf);
12714 }
12715
12716 if (dhd->early_suspended) {
12717 /* LCD off */
12718 memset(&scb_val, 0, sizeof(scb_val_t));
12719 scb_val.val = 0;
12720 err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
12721 if (err) {
12722 WL_ERR(("Could not get rssi (%d)\n", err));
12723 }
12724 rssi = wl_rssi_offset(dtoh32(scb_val.val));
12725 WL_ERR(("[%s] RSSI %d dBm\n", ndev->name, rssi));
12726 if (rssi > DPM_UPD_LMT_RSSI) {
12727 return err;
12728 }
12729 } else {
12730 /* LCD on */
12731 return err;
12732 }
12733
12734 if (last_dpm_upd_time == 0) {
12735 last_dpm_upd_time = OSL_SYSUPTIME();
12736 } else {
12737 cur_dpm_upd_time = OSL_SYSUPTIME();
12738 if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) {
12739 scb_val_t scbval;
12740 bzero(&scbval, sizeof(scb_val_t));
12741
12742 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
12743 if (err < 0) {
12744 WL_ERR(("%s: Disassoc error %d\n", __FUNCTION__, err));
12745 return err;
12746 }
12747 WL_ERR(("%s: Force Disassoc due to updated DPM event.\n", __FUNCTION__));
12748
12749 last_dpm_upd_time = 0;
12750 } else {
12751 last_dpm_upd_time = cur_dpm_upd_time;
12752 }
12753 }
12754
12755 return err;
12756}
12757#endif /* CUSTOM_EVENT_PM_WAKE */
12758
12759#ifdef QOS_MAP_SET
12760/* get user priority table */
12761uint8 *
12762wl_get_up_table(dhd_pub_t * dhdp, int idx)
12763{
12764 struct net_device *ndev;
12765 struct bcm_cfg80211 *cfg;
12766
12767 ndev = dhd_idx2net(dhdp, idx);
12768 if (ndev) {
12769 cfg = wl_get_cfg(ndev);
12770 if (cfg)
12771 return (uint8 *)(cfg->up_table);
12772 }
12773
12774 return NULL;
12775}
12776#endif /* QOS_MAP_SET */
12777
12778#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
12779static s32
12780wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12781 const wl_event_msg_t *e, void *data)
12782{
12783 struct wl_security *sec;
12784 struct net_device *ndev;
12785#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
12786 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12787#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
12788 u32 status = ntoh32(e->status);
12789 u32 reason = ntoh32(e->reason);
12790
12791 BCM_REFERENCE(sec);
12792
12793 if (status == WLC_E_STATUS_SUCCESS && reason != WLC_E_REASON_INITIAL_ASSOC) {
12794 WL_ERR(("Attempting roam with reason code : %d\n", reason));
12795 }
12796
12797 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12798
12799#ifdef DBG_PKT_MON
12800 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
12801 DHD_DBG_PKT_MON_STOP(dhdp);
12802 DHD_DBG_PKT_MON_START(dhdp);
12803 }
12804#endif /* DBG_PKT_MON */
12805
12806#ifdef DHD_LOSSLESS_ROAMING
12807sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
12808 /* Disable Lossless Roaming for specific AKM suite
12809 * Any other AKM suite can be added below if transition time
12810 * is delayed because of Lossless Roaming
12811 * and it causes any certication failure
12812 */
12813 if (IS_AKM_SUITE_FT(sec)) {
12814 return BCME_OK;
12815 }
12816 dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC;
12817 /* Restore flow control */
12818 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
12819
12820 mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
12821#endif /* DHD_LOSSLESS_ROAMING */
12822 return BCME_OK;
12823
12824}
12825#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
12826#ifdef ENABLE_TEMP_THROTTLING
12827static s32
12828wl_check_rx_throttle_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12829 const wl_event_msg_t *e, void *data)
12830{
12831 s32 err = 0;
12832 u32 status = ntoh32(e->status);
12833 u32 reason = ntoh32(e->reason);
12834
12835 WL_ERR_EX(("RX THROTTLE : status=%d, reason=0x%x\n", status, reason));
12836
12837 return err;
12838}
12839#endif /* ENABLE_TEMP_THROTTLING */
12840
12841static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
12842{
12843 wl_assoc_info_t assoc_info;
12844 struct wl_connect_info *conn_info = wl_to_conn(cfg);
12845 s32 err = 0;
12846#ifdef QOS_MAP_SET
12847 bcm_tlv_t * qos_map_ie = NULL;
12848#endif /* QOS_MAP_SET */
12849
12850 WL_DBG(("Enter \n"));
12851 err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
12852 WL_ASSOC_INFO_MAX, NULL);
12853 if (unlikely(err)) {
12854 WL_ERR(("could not get assoc info (%d)\n", err));
12855 return err;
12856 }
12857 memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
12858 assoc_info.req_len = htod32(assoc_info.req_len);
12859 assoc_info.resp_len = htod32(assoc_info.resp_len);
12860 assoc_info.flags = htod32(assoc_info.flags);
12861 if (conn_info->req_ie_len) {
12862 conn_info->req_ie_len = 0;
12863 bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
12864 }
12865 if (conn_info->resp_ie_len) {
12866 conn_info->resp_ie_len = 0;
12867 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
12868 }
12869 if (assoc_info.req_len) {
12870 err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
12871 WL_ASSOC_INFO_MAX, NULL);
12872 if (unlikely(err)) {
12873 WL_ERR(("could not get assoc req (%d)\n", err));
12874 return err;
12875 }
12876 conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req);
12877 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
12878 conn_info->req_ie_len -= ETHER_ADDR_LEN;
12879 }
12880 if (conn_info->req_ie_len <= MAX_REQ_LINE)
12881 memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
12882 else {
12883 WL_ERR(("IE size %d above max %d size \n",
12884 conn_info->req_ie_len, MAX_REQ_LINE));
12885 return err;
12886 }
12887 } else {
12888 conn_info->req_ie_len = 0;
12889 }
12890 if (assoc_info.resp_len) {
12891 err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
12892 WL_ASSOC_INFO_MAX, NULL);
12893 if (unlikely(err)) {
12894 WL_ERR(("could not get assoc resp (%d)\n", err));
12895 return err;
12896 }
12897 conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp);
12898 if (conn_info->resp_ie_len <= MAX_REQ_LINE) {
12899 memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
12900 } else {
12901 WL_ERR(("IE size %d above max %d size \n",
12902 conn_info->resp_ie_len, MAX_REQ_LINE));
12903 return err;
12904 }
12905
12906#ifdef QOS_MAP_SET
12907 /* find qos map set ie */
12908 if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
12909 DOT11_MNG_QOS_MAP_ID)) != NULL) {
12910 WL_DBG((" QoS map set IE found in assoc response\n"));
12911 if (!cfg->up_table) {
12912 cfg->up_table = kmalloc(UP_TABLE_MAX, GFP_KERNEL);
12913 }
12914 wl_set_up_table(cfg->up_table, qos_map_ie);
12915 } else {
12916 kfree(cfg->up_table);
12917 cfg->up_table = NULL;
12918 }
12919#endif /* QOS_MAP_SET */
12920 } else {
12921 conn_info->resp_ie_len = 0;
12922 }
12923 WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
12924 conn_info->resp_ie_len));
12925
12926 return err;
12927}
12928
12929static s32 wl_ch_to_chanspec(struct net_device *dev, int ch, struct wl_join_params *join_params,
12930 size_t *join_params_size)
12931{
12932 s32 bssidx = -1;
12933 chanspec_t chanspec = 0, chspec;
12934
12935 if (ch != 0) {
12936 struct bcm_cfg80211 *cfg =
12937 (struct bcm_cfg80211 *)wiphy_priv(dev->ieee80211_ptr->wiphy);
12938 join_params->params.chanspec_num = 1;
12939 join_params->params.chanspec_list[0] = ch;
12940
12941 if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
12942 chanspec |= WL_CHANSPEC_BAND_2G;
12943 else
12944 chanspec |= WL_CHANSPEC_BAND_5G;
12945
12946 /* Get the min_bw set for the interface */
12947 chspec = wl_cfg80211_ulb_get_min_bw_chspec(cfg, dev->ieee80211_ptr, bssidx);
12948 if (chspec == INVCHANSPEC) {
12949 WL_ERR(("Invalid chanspec \n"));
12950 return -EINVAL;
12951 }
12952 chanspec |= chspec;
12953 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
12954
12955 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
12956 join_params->params.chanspec_num * sizeof(chanspec_t);
12957
12958 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
12959 join_params->params.chanspec_list[0] |= chanspec;
12960 join_params->params.chanspec_list[0] =
12961 wl_chspec_host_to_driver(join_params->params.chanspec_list[0]);
12962
12963 join_params->params.chanspec_num =
12964 htod32(join_params->params.chanspec_num);
12965
12966 WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
12967 join_params->params.chanspec_list[0],
12968 join_params->params.chanspec_num));
12969 }
12970 return 0;
12971}
12972
12973static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam)
12974{
12975 struct cfg80211_bss *bss;
12976 struct wl_bss_info *bi;
12977 struct wlc_ssid *ssid;
12978 struct bcm_tlv *tim;
12979 s32 beacon_interval;
12980 s32 dtim_period;
12981 size_t ie_len;
12982 u8 *ie;
12983 u8 *curbssid;
12984 s32 err = 0;
12985 struct wiphy *wiphy;
12986 u32 channel;
12987 char *buf;
12988 u32 freq, band;
12989
12990 wiphy = bcmcfg_to_wiphy(cfg);
12991
12992 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
12993 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
12994 bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
12995 ssid->SSID, ssid->SSID_len);
12996 buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_ATOMIC);
12997 if (!buf) {
12998 WL_ERR(("buffer alloc failed.\n"));
12999 return BCME_NOMEM;
13000 }
13001 mutex_lock(&cfg->usr_sync);
13002 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
13003 err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX);
13004 if (unlikely(err)) {
13005 WL_ERR(("Could not get bss info %d\n", err));
13006 goto update_bss_info_out;
13007 }
13008 bi = (struct wl_bss_info *)(buf + 4);
13009 channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
13010 wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN);
13011
13012 if (!bss) {
13013 WL_DBG(("Could not find the AP\n"));
13014 if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
13015 WL_ERR(("Bssid doesn't match\n"));
13016 err = -EIO;
13017 goto update_bss_info_out;
13018 }
13019 err = wl_inform_single_bss(cfg, bi, roam);
13020 if (unlikely(err))
13021 goto update_bss_info_out;
13022
13023 ie = ((u8 *)bi) + bi->ie_offset;
13024 ie_len = bi->ie_length;
13025 beacon_interval = cpu_to_le16(bi->beacon_period);
13026 } else {
13027 WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
13028#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
13029 freq = ieee80211_channel_to_frequency(channel);
13030#else
13031 band = (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
13032 freq = ieee80211_channel_to_frequency(channel, band);
13033#endif
13034 bss->channel = ieee80211_get_channel(wiphy, freq);
13035#if defined(WL_CFG80211_P2P_DEV_IF)
13036#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
13037#pragma GCC diagnostic push
13038#pragma GCC diagnostic ignored "-Wcast-qual"
13039#endif
13040 ie = (u8 *)bss->ies->data;
13041 ie_len = bss->ies->len;
13042#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
13043#pragma GCC diagnostic pop
13044#endif
13045#else
13046 ie = bss->information_elements;
13047 ie_len = bss->len_information_elements;
13048#endif /* WL_CFG80211_P2P_DEV_IF */
13049 beacon_interval = bss->beacon_interval;
13050
13051 CFG80211_PUT_BSS(wiphy, bss);
13052 }
13053
13054 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
13055 if (tim) {
13056 dtim_period = tim->data[1];
13057 } else {
13058 /*
13059 * active scan was done so we could not get dtim
13060 * information out of probe response.
13061 * so we speficially query dtim information.
13062 */
13063 dtim_period = 0;
13064 err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD,
13065 &dtim_period, sizeof(dtim_period));
13066 if (unlikely(err)) {
13067 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
13068 goto update_bss_info_out;
13069 }
13070 }
13071
13072 wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
13073 wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
13074
13075update_bss_info_out:
13076 if (unlikely(err)) {
13077 WL_ERR(("Failed with error %d\n", err));
13078 }
13079
13080 kfree(buf);
13081 mutex_unlock(&cfg->usr_sync);
13082 return err;
13083}
13084
13085static s32
13086wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13087 const wl_event_msg_t *e, void *data)
13088{
13089 struct wl_connect_info *conn_info = wl_to_conn(cfg);
13090 s32 err = 0;
13091 u8 *curbssid;
13092 u32 *channel;
13093#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
13094 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13095 struct ieee80211_supported_band *band;
13096 struct ieee80211_channel *notify_channel = NULL;
13097 u32 freq;
13098#ifdef BCM4359_CHIP
13099 struct channel_info ci;
13100 u32 cur_channel;
13101#endif /* BCM4359_CHIP */
13102#endif
13103#if defined(WLADPS_SEAK_AP_WAR) || defined(WBTEXT)
13104 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
13105#endif /* WLADPS_SEAK_AP_WAR || WBTEXT */
dfb0f3ae
RC
13106#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
13107 struct cfg80211_roam_info roam_info = {};
13108#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
010c3a89
RC
13109
13110#ifdef WLADPS_SEAK_AP_WAR
13111 BCM_REFERENCE(dhdp);
13112#endif /* WLADPS_SEAK_AP_WAR */
13113
13114 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13115 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
13116#ifdef BCM4359_CHIP
13117 /* Skip calling cfg80211_roamed If the channels are same and
13118 * the current bssid/last_roamed_bssid & the new bssid are same
13119 * Also clear timer roam_timeout.
13120 * Only used on BCM4359 devices.
13121 */
13122 memset(&ci, 0, sizeof(ci));
13123 if ((wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci,
13124 sizeof(ci))) < 0) {
13125 WL_ERR(("Failed to get current channel !"));
13126 return BCME_ERROR;
13127 }
13128 cur_channel = dtoh32(ci.hw_channel);
13129 if ((*channel == cur_channel) && ((memcmp(curbssid, &e->addr,
13130 ETHER_ADDR_LEN) == 0) || (memcmp(&cfg->last_roamed_addr,
13131 &e->addr, ETHER_ADDR_LEN) == 0))) {
13132 WL_ERR(("BSS already present, Skipping roamed event to"
13133 " upper layer\n"));
13134#ifdef DHD_LOSSLESS_ROAMING
13135 wl_del_roam_timeout(cfg);
13136#endif /* DHD_LOSSLESS_ROAMING */
13137 return err;
13138 }
13139#endif /* BCM4359_CHIP */
13140
13141 wl_get_assoc_ies(cfg, ndev);
13142 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID);
13143 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13144 wl_update_bss_info(cfg, ndev, true);
13145 wl_update_pmklist(ndev, cfg->pmk_list, err);
13146
13147 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
13148#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
13149 /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
13150 if (*channel <= CH_MAX_2G_CHANNEL)
13151 band = wiphy->bands[IEEE80211_BAND_2GHZ];
13152 else
13153 band = wiphy->bands[IEEE80211_BAND_5GHZ];
13154 freq = ieee80211_channel_to_frequency(*channel, band->band);
13155 notify_channel = ieee80211_get_channel(wiphy, freq);
13156#endif
13157#ifdef WLADPS_SEAK_AP_WAR
13158 if ((dhdp->op_mode & DHD_FLAG_STA_MODE) &&
13159 (!dhdp->disabled_adps)) {
13160 bool find = FALSE;
13161 uint8 enable_mode;
13162 if (!memcmp(curbssid, (u8*)CAMEO_MAC_PREFIX, MAC_PREFIX_LEN)) {
13163 find = wl_find_vndr_ies_specific_vender(cfg, ndev, ATHEROS_OUI);
13164 }
13165 enable_mode = (find == TRUE) ? OFF : ON;
13166 wl_set_adps_mode(cfg, ndev, enable_mode);
13167 }
13168#endif /* WLADPS_SEAK_AP_WAR */
13169 printf("%s succeeded to " MACDBG " (ch:%d)\n", __FUNCTION__,
13170 MAC2STRDBG((const u8*)(&e->addr)), *channel);
13171 dhd_conf_set_wme(cfg->pub, 0);
13172
dfb0f3ae
RC
13173#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
13174 roam_info.channel = notify_channel;
13175 roam_info.bssid = curbssid;
13176 roam_info.req_ie = conn_info->req_ie;
13177 roam_info.req_ie_len = conn_info->req_ie_len;
13178 roam_info.resp_ie = conn_info->resp_ie;
13179 roam_info.resp_ie_len = conn_info->resp_ie_len;
13180#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
13181
13182#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
13183 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
13184#else
010c3a89
RC
13185 cfg80211_roamed(ndev,
13186#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
13187 notify_channel,
13188#endif
13189 curbssid,
13190 conn_info->req_ie, conn_info->req_ie_len,
13191 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
dfb0f3ae 13192#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
010c3a89
RC
13193 WL_DBG(("Report roaming result\n"));
13194
13195 memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
13196 wl_set_drv_status(cfg, CONNECTED, ndev);
13197
13198#if defined(DHD_ENABLE_BIGDATA_LOGGING)
13199 cfg->roam_count++;
13200#endif /* DHD_ENABLE_BIGDATA_LOGGING */
13201
13202#ifdef WBTEXT
13203 if (dhdp->wbtext_support) {
13204 /* set wnm_keepalives_max_idle after association */
13205 wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
13206 /* send nbr request or BTM query to update RCC */
13207 wl_cfg80211_wbtext_update_rcc(cfg, ndev);
13208 }
13209#endif /* WBTEXT */
13210
13211 return err;
13212}
13213
13214static bool
13215wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13216{
13217 struct cfg80211_bss *bss;
13218 struct wiphy *wiphy;
13219 struct wlc_ssid *ssid;
13220 uint8 *curbssid;
13221 int count = 0;
13222 int ret = false;
13223
13224 wiphy = bcmcfg_to_wiphy(cfg);
13225 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
13226 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13227 if (!ssid) {
13228 WL_ERR(("No SSID found in the saved profile \n"));
13229 return false;
13230 }
13231
13232 do {
13233 bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
13234 ssid->SSID, ssid->SSID_len);
13235 if (bss || (count > 5)) {
13236 break;
13237 }
13238
13239 count++;
13240 msleep(100);
13241 } while (bss == NULL);
13242
13243 WL_DBG(("cfg80211 bss_ptr:%p loop_cnt:%d\n", bss, count));
13244 if (bss) {
13245 /* Update the reference count after use */
13246 CFG80211_PUT_BSS(wiphy, bss);
13247 ret = true;
13248 }
13249
13250 return ret;
13251}
13252
13253static s32
13254wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13255 const wl_event_msg_t *e, void *data, bool completed)
13256{
13257 struct wl_connect_info *conn_info = wl_to_conn(cfg);
13258 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13259 s32 err = 0;
13260 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13261 dhd_pub_t *dhdp;
13262
13263 dhdp = (dhd_pub_t *)(cfg->pub);
13264 BCM_REFERENCE(dhdp);
13265
13266 if (!sec) {
13267 WL_ERR(("sec is NULL\n"));
13268 return -ENODEV;
13269 }
13270 WL_DBG((" enter\n"));
13271#ifdef ESCAN_RESULT_PATCH
13272 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
13273 if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) {
13274 WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n",
13275 ntoh32(e->event_type), ntoh32(e->status)));
13276 return err;
13277 }
13278 }
13279 if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 &&
13280 memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) {
13281 WL_DBG(("copy bssid\n"));
13282 memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN);
13283 }
13284
13285#else
13286 if (cfg->scan_request) {
13287 wl_notify_escan_complete(cfg, ndev, true, true);
13288 }
13289#endif /* ESCAN_RESULT_PATCH */
13290 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
13291 wl_cfg80211_scan_abort(cfg);
13292 wl_clr_drv_status(cfg, CONNECTING, ndev);
13293 if (completed) {
13294 wl_get_assoc_ies(cfg, ndev);
13295 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
13296 WL_PROF_BSSID);
13297 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13298 wl_update_bss_info(cfg, ndev, false);
13299 wl_update_pmklist(ndev, cfg->pmk_list, err);
13300 wl_set_drv_status(cfg, CONNECTED, ndev);
13301#ifdef WLADPS_SEAK_AP_WAR
13302 if ((dhdp->op_mode & DHD_FLAG_STA_MODE) &&
13303 (!dhdp->disabled_adps)) {
13304 bool find = FALSE;
13305 uint8 enable_mode;
13306 if (!memcmp(curbssid, (u8*)CAMEO_MAC_PREFIX, MAC_PREFIX_LEN)) {
13307 find = wl_find_vndr_ies_specific_vender(cfg,
13308 ndev, ATHEROS_OUI);
13309 }
13310 enable_mode = (find == TRUE) ? OFF : ON;
13311 wl_set_adps_mode(cfg, ndev, enable_mode);
13312 }
13313#endif /* WLADPS_SEAK_AP_WAR */
13314 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
13315#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
13316 init_completion(&cfg->iface_disable);
13317#else
13318 /* reinitialize completion to clear previous count */
13319 INIT_COMPLETION(cfg->iface_disable);
13320#endif
13321 }
13322#ifdef CUSTOM_SET_CPUCORE
13323 if (wl_get_chan_isvht80(ndev, dhdp)) {
13324 if (ndev == bcmcfg_to_prmry_ndev(cfg))
13325 dhdp->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
13326 else if (is_p2p_group_iface(ndev->ieee80211_ptr))
13327 dhdp->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
13328 dhd_set_cpucore(dhdp, TRUE);
13329 }
13330#endif /* CUSTOM_SET_CPUCORE */
13331 memset(&cfg->last_roamed_addr, 0, ETHER_ADDR_LEN);
13332 }
13333
13334 if (completed && (wl_cfg80211_verify_bss(cfg, ndev) != true)) {
13335 /* If bss entry is not available in the cfg80211 bss cache
13336 * the wireless stack will complain and won't populate
13337 * wdev->current_bss ptr
13338 */
13339 WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
13340 completed = false;
13341 sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
13342 }
13343 cfg80211_connect_result(ndev,
13344 curbssid,
13345 conn_info->req_ie,
13346 conn_info->req_ie_len,
13347 conn_info->resp_ie,
13348 conn_info->resp_ie_len,
13349 completed ? WLAN_STATUS_SUCCESS :
13350 (sec->auth_assoc_res_status) ?
13351 sec->auth_assoc_res_status :
13352 WLAN_STATUS_UNSPECIFIED_FAILURE,
13353 GFP_KERNEL);
13354 if (completed) {
13355 WL_INFORM(("Report connect result - connection succeeded\n"));
13356 dhd_conf_set_wme(cfg->pub, 0);
d964ce36 13357 } else {
010c3a89 13358 WL_ERR(("Report connect result - connection failed\n"));
32c27b7a
RC
13359 wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
13360 WL_EXT_STATUS_DISCONNECTED, NULL);
d964ce36 13361 }
010c3a89
RC
13362 }
13363#ifdef CONFIG_TCPACK_FASTTX
13364 if (wl_get_chan_isvht80(ndev, dhdp))
13365 wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
13366 else
13367 wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
13368#endif /* CONFIG_TCPACK_FASTTX */
13369
13370 return err;
13371}
13372
13373static s32
13374wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13375 const wl_event_msg_t *e, void *data)
13376{
13377 struct net_device *ndev = NULL;
13378 u16 flags = ntoh16(e->flags);
13379 enum nl80211_key_type key_type;
13380
13381 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13382
13383 mutex_lock(&cfg->usr_sync);
13384 if (flags & WLC_EVENT_MSG_GROUP)
13385 key_type = NL80211_KEYTYPE_GROUP;
13386 else
13387 key_type = NL80211_KEYTYPE_PAIRWISE;
13388
13389 cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1,
13390 NULL, GFP_KERNEL);
13391 mutex_unlock(&cfg->usr_sync);
13392
13393 return 0;
13394}
13395
13396#ifdef BT_WIFI_HANDOVER
13397static s32
13398wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13399 const wl_event_msg_t *e, void *data)
13400{
13401 struct net_device *ndev = NULL;
13402 u32 event = ntoh32(e->event_type);
13403 u32 datalen = ntoh32(e->datalen);
13404 s32 err;
13405
13406 WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen));
13407 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13408 err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0);
13409
13410 return err;
13411}
13412#endif /* BT_WIFI_HANDOVER */
13413
13414#ifdef PNO_SUPPORT
13415static s32
13416wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13417 const wl_event_msg_t *e, void *data)
13418{
13419 struct net_device *ndev = NULL;
13420#ifdef GSCAN_SUPPORT
13421 void *ptr;
13422 int send_evt_bytes = 0;
13423 u32 event = be32_to_cpu(e->event_type);
13424 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13425#endif /* GSCAN_SUPPORT */
13426
13427 WL_ERR((">>> PNO Event\n"));
13428
13429 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13430#ifdef GSCAN_SUPPORT
13431 ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes);
13432 if (ptr) {
13433 wl_cfgvendor_send_async_event(wiphy, ndev,
13434 GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes);
13435 kfree(ptr);
13436 }
13437 if (!dhd_dev_is_legacy_pno_enabled(ndev))
13438 return 0;
13439#endif /* GSCAN_SUPPORT */
13440
13441
13442#ifndef WL_SCHED_SCAN
13443 mutex_lock(&cfg->usr_sync);
13444 /* TODO: Use cfg80211_sched_scan_results(wiphy); */
13445 CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
13446 mutex_unlock(&cfg->usr_sync);
13447#else
13448 /* If cfg80211 scheduled scan is supported, report the pno results via sched
13449 * scan results
13450 */
13451 wl_notify_sched_scan_results(cfg, ndev, e, data);
13452#endif /* WL_SCHED_SCAN */
13453 return 0;
13454}
13455#endif /* PNO_SUPPORT */
13456
13457#ifdef GSCAN_SUPPORT
13458static s32
13459wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13460 const wl_event_msg_t *e, void *data)
13461{
13462 s32 err = 0;
13463 u32 event = be32_to_cpu(e->event_type);
13464 void *ptr;
13465 int send_evt_bytes = 0;
13466 int event_type;
13467 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13468 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13469 u32 len = ntoh32(e->datalen);
13470
13471 switch (event) {
13472 case WLC_E_PFN_BEST_BATCHING:
13473 err = dhd_dev_retrieve_batch_scan(ndev);
13474 if (err < 0) {
13475 WL_ERR(("Batch retrieval already in progress %d\n", err));
13476 } else {
13477 event_type = WIFI_SCAN_THRESHOLD_NUM_SCANS;
13478 if (data && len) {
13479 event_type = *((int *)data);
13480 }
13481 wl_cfgvendor_send_async_event(wiphy, ndev,
13482 GOOGLE_GSCAN_BATCH_SCAN_EVENT,
13483 &event_type, sizeof(int));
13484 }
13485 break;
13486 case WLC_E_PFN_SCAN_COMPLETE:
13487 event_type = WIFI_SCAN_COMPLETE;
13488 wl_cfgvendor_send_async_event(wiphy, ndev,
13489 GOOGLE_SCAN_COMPLETE_EVENT,
13490 &event_type, sizeof(int));
13491 break;
13492 case WLC_E_PFN_BSSID_NET_FOUND:
13493 ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes,
13494 HOTLIST_FOUND);
13495 if (ptr) {
13496 wl_cfgvendor_send_hotlist_event(wiphy, ndev,
13497 ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT);
13498 dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_FOUND);
13499 } else {
13500 err = -ENOMEM;
13501 }
13502 break;
13503 case WLC_E_PFN_BSSID_NET_LOST:
13504 /* WLC_E_PFN_BSSID_NET_LOST is conflict shared with WLC_E_PFN_SCAN_ALLGONE
13505 * We currently do not use WLC_E_PFN_SCAN_ALLGONE, so if we get it, ignore
13506 */
13507 if (len) {
13508 ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes,
13509 HOTLIST_LOST);
13510 if (ptr) {
13511 wl_cfgvendor_send_hotlist_event(wiphy, ndev,
13512 ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT);
13513 dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_LOST);
13514 } else {
13515 err = -ENOMEM;
13516 }
13517 } else {
13518 err = -EINVAL;
13519 }
13520 break;
13521 case WLC_E_PFN_GSCAN_FULL_RESULT:
13522 ptr = dhd_dev_process_full_gscan_result(ndev, data, len, &send_evt_bytes);
13523 if (ptr) {
13524 wl_cfgvendor_send_async_event(wiphy, ndev,
13525 GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes);
13526 kfree(ptr);
13527 } else {
13528 err = -ENOMEM;
13529 }
13530 break;
13531 case WLC_E_PFN_SSID_EXT:
13532 ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes);
13533 if (ptr) {
13534 wl_cfgvendor_send_async_event(wiphy, ndev,
13535 GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes);
13536 kfree(ptr);
13537 } else {
13538 err = -ENOMEM;
13539 }
13540 break;
13541 default:
13542 WL_ERR(("Unknown event %d\n", event));
13543 break;
13544 }
13545 return err;
13546}
13547#endif /* GSCAN_SUPPORT */
13548
13549static s32
13550wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13551 const wl_event_msg_t *e, void *data)
13552{
13553 struct channel_info channel_inform;
13554 struct wl_scan_results *bss_list;
13555 struct net_device *ndev = NULL;
13556 u32 len = WL_SCAN_BUF_MAX;
13557 s32 err = 0;
13558 unsigned long flags;
13559#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
13560 struct cfg80211_scan_info info;
13561#endif
13562
13563 WL_DBG(("Enter \n"));
13564 if (!wl_get_drv_status(cfg, SCANNING, ndev)) {
13565 WL_ERR(("scan is not ready \n"));
13566 return err;
13567 }
13568 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13569
13570 mutex_lock(&cfg->usr_sync);
13571 wl_clr_drv_status(cfg, SCANNING, ndev);
13572 memset(&channel_inform, 0, sizeof(channel_inform));
13573 err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &channel_inform,
13574 sizeof(channel_inform));
13575 if (unlikely(err)) {
13576 WL_ERR(("scan busy (%d)\n", err));
13577 goto scan_done_out;
13578 }
13579 channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
13580 if (unlikely(channel_inform.scan_channel)) {
13581
13582 WL_DBG(("channel_inform.scan_channel (%d)\n",
13583 channel_inform.scan_channel));
13584 }
13585 cfg->bss_list = cfg->scan_results;
13586 bss_list = cfg->bss_list;
13587 memset(bss_list, 0, len);
13588 bss_list->buflen = htod32(len);
13589 err = wldev_ioctl_get(ndev, WLC_SCAN_RESULTS, bss_list, len);
13590 if (unlikely(err) && unlikely(!cfg->scan_suppressed)) {
13591 WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
13592 err = -EINVAL;
13593 goto scan_done_out;
13594 }
13595 bss_list->buflen = dtoh32(bss_list->buflen);
13596 bss_list->version = dtoh32(bss_list->version);
13597 bss_list->count = dtoh32(bss_list->count);
13598
13599 err = wl_inform_bss(cfg);
13600
13601scan_done_out:
13602 del_timer_sync(&cfg->scan_timeout);
13603 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
13604 if (cfg->scan_request) {
13605#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
13606 info.aborted = false;
13607 cfg80211_scan_done(cfg->scan_request, &info);
13608#else
13609 cfg80211_scan_done(cfg->scan_request, false);
13610#endif
13611 cfg->scan_request = NULL;
13612 }
13613 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
13614 WL_DBG(("cfg80211_scan_done\n"));
13615 mutex_unlock(&cfg->usr_sync);
13616 return err;
13617}
13618
13619static s32
13620wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
13621 const struct ether_addr *sa, const struct ether_addr *bssid,
13622 u8 **pheader, u32 *body_len, u8 *pbody)
13623{
13624 struct dot11_management_header *hdr;
13625 u32 totlen = 0;
13626 s32 err = 0;
13627 u8 *offset;
13628 u32 prebody_len = *body_len;
13629 switch (fc) {
13630 case FC_ASSOC_REQ:
13631 /* capability , listen interval */
13632 totlen = DOT11_ASSOC_REQ_FIXED_LEN;
13633 *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
13634 break;
13635
13636 case FC_REASSOC_REQ:
13637 /* capability, listen inteval, ap address */
13638 totlen = DOT11_REASSOC_REQ_FIXED_LEN;
13639 *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
13640 break;
13641 }
13642 totlen += DOT11_MGMT_HDR_LEN + prebody_len;
13643 *pheader = kzalloc(totlen, GFP_KERNEL);
13644 if (*pheader == NULL) {
13645 WL_ERR(("memory alloc failed \n"));
13646 return -ENOMEM;
13647 }
13648 hdr = (struct dot11_management_header *) (*pheader);
13649 hdr->fc = htol16(fc);
13650 hdr->durid = 0;
13651 hdr->seq = 0;
13652 offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
13653 bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
13654 bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
13655 bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
13656 if ((pbody != NULL) && prebody_len)
13657 bcopy((const char*)pbody, offset, prebody_len);
13658 *body_len = totlen;
13659 return err;
13660}
13661
13662
13663void
13664wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 bsscfgidx)
13665{
13666 s32 err = 0;
13667
13668 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
13669 if (timer_pending(&cfg->p2p->listen_timer)) {
13670 del_timer_sync(&cfg->p2p->listen_timer);
13671 }
13672 if (cfg->afx_hdl != NULL) {
13673 if (cfg->afx_hdl->dev != NULL) {
13674 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
13675 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev);
13676 }
13677 cfg->afx_hdl->peer_chan = WL_INVALID;
13678 }
13679 complete(&cfg->act_frm_scan);
13680 WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
13681 } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
13682 if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
13683 wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
13684 wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
13685
13686 WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx));
13687 /* if channel is not zero, "actfame" uses off channel scan.
13688 * So abort scan for off channel completion.
13689 */
13690 if (cfg->af_sent_channel) {
13691 /* Scan engine is not used for sending action frames in the latest driver
13692 * branches. So, actframe_abort is used in the latest driver branches
13693 * instead of scan abort.
13694 * New driver branches:
13695 * Issue actframe_abort and it succeeded. So, don't execute scan abort.
13696 * Old driver branches:
13697 * Issue actframe_abort and it fails. So, execute scan abort.
13698 */
13699 err = wldev_iovar_setint_bsscfg(ndev, "actframe_abort", 1, bsscfgidx);
13700 if (err < 0) {
13701 wl_cfg80211_scan_abort(cfg);
13702 }
13703 }
13704 }
13705#ifdef WL_CFG80211_SYNC_GON
13706 else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
13707 WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
13708 /* So abort scan to cancel listen */
13709 wl_cfg80211_scan_abort(cfg);
13710 }
13711#endif /* WL_CFG80211_SYNC_GON */
13712}
13713
13714#if defined(WLTDLS)
13715bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len)
13716{
13717 unsigned char *data;
13718
13719 if (frame == NULL) {
13720 WL_ERR(("Invalid frame \n"));
13721 return false;
13722 }
13723
13724 if (frame_len < 5) {
13725 WL_ERR(("Invalid frame length [%d] \n", frame_len));
13726 return false;
13727 }
13728
13729 data = frame;
13730
13731 if (!memcmp(data, TDLS_TUNNELED_PRB_REQ, 5) ||
13732 !memcmp(data, TDLS_TUNNELED_PRB_RESP, 5)) {
13733 WL_DBG(("TDLS Vendor Specific Received type\n"));
13734 return true;
13735 }
13736
13737 return false;
13738}
13739#endif /* WLTDLS */
13740
13741
13742int wl_cfg80211_get_ioctl_version(void)
13743{
13744 return ioctl_version;
13745}
13746
13747static s32
13748wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13749 const wl_event_msg_t *e, void *data)
13750{
13751 struct ieee80211_supported_band *band;
13752 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13753 struct ether_addr da;
13754 struct ether_addr bssid;
13755 bool isfree = false;
13756 s32 err = 0;
13757 s32 freq;
13758#if defined(TDLS_MSG_ONLY_WFD)
13759 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
13760#endif /* TDLS_MSG_ONLY_WFD && BCMDONGLEHOST */
13761 struct net_device *ndev = NULL;
13762 wifi_p2p_pub_act_frame_t *act_frm = NULL;
13763 wifi_p2p_action_frame_t *p2p_act_frm = NULL;
13764 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
13765 wl_event_rx_frame_data_t *rxframe;
13766 u32 event;
13767 u8 *mgmt_frame;
13768 u8 bsscfgidx;
13769 u32 mgmt_frame_len;
13770 u16 channel;
13771 if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) {
13772 WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen)));
13773 return -EINVAL;
13774 }
13775 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t);
13776 event = ntoh32(e->event_type);
13777 bsscfgidx = e->bsscfgidx;
13778 rxframe = (wl_event_rx_frame_data_t *)data;
13779 if (!rxframe) {
13780 WL_ERR(("rxframe: NULL\n"));
13781 return -EINVAL;
13782 }
13783 channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK);
13784 memset(&bssid, 0, ETHER_ADDR_LEN);
13785 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13786 if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) &&
13787 (event == WLC_E_PROBREQ_MSG)) {
13788#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
13789 4 && __GNUC_MINOR__ >= 6))
13790_Pragma("GCC diagnostic push")
13791_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
13792#endif
13793 struct net_info *iter, *next;
13794 for_each_ndev(cfg, iter, next) {
13795 if (iter->ndev && iter->wdev &&
13796 iter->wdev->iftype == NL80211_IFTYPE_AP) {
13797 ndev = iter->ndev;
13798 cfgdev = ndev_to_cfgdev(ndev);
13799 break;
13800 }
13801 }
13802#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
13803 4 && __GNUC_MINOR__ >= 6))
13804_Pragma("GCC diagnostic pop")
13805#endif
13806 }
13807
13808 if (channel <= CH_MAX_2G_CHANNEL)
13809 band = wiphy->bands[IEEE80211_BAND_2GHZ];
13810 else
13811 band = wiphy->bands[IEEE80211_BAND_5GHZ];
13812 if (!band) {
13813 WL_ERR(("No valid band\n"));
13814 return -EINVAL;
13815 }
13816#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
13817 freq = ieee80211_channel_to_frequency(channel);
13818 (void)band->band;
13819#else
13820 freq = ieee80211_channel_to_frequency(channel, band->band);
13821#endif
13822 if (event == WLC_E_ACTION_FRAME_RX) {
13823 if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
13824 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx,
13825 &cfg->ioctl_buf_sync)) != BCME_OK) {
13826 WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
13827 goto exit;
13828 }
13829
13830 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
13831 if (err < 0)
13832 WL_ERR(("WLC_GET_BSSID error %d\n", err));
13833 memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
13834 err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
13835 &mgmt_frame, &mgmt_frame_len,
13836 (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
13837 if (err < 0) {
13838 WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
13839 mgmt_frame_len, channel, freq));
13840 goto exit;
13841 }
13842 isfree = true;
13843 if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
13844 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
13845 act_frm = (wifi_p2p_pub_act_frame_t *)
13846 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
13847 } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
13848 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
13849 p2p_act_frm = (wifi_p2p_action_frame_t *)
13850 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
13851 (void) p2p_act_frm;
13852 } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
13853 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
13854
13855 sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
13856 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
13857 if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
13858 if (cfg->next_af_subtype == sd_act_frm->action) {
13859 WL_DBG(("We got a right next frame of SD!(%d)\n",
13860 sd_act_frm->action));
13861 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
13862
13863 /* Stop waiting for next AF. */
13864 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
13865 }
13866 }
13867 (void) sd_act_frm;
13868#ifdef WLTDLS
13869 } else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
13870 (wl_cfg80211_is_tdls_tunneled_frame(
13871 &mgmt_frame[DOT11_MGMT_HDR_LEN],
13872 mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
13873 if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
13874 WL_ERR((" TDLS Action Frame Received type = %d \n",
13875 mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
13876 }
13877#ifdef TDLS_MSG_ONLY_WFD
13878 if (!dhdp->tdls_mode) {
13879 WL_DBG((" TDLS Frame filtered \n"));
13880 return 0;
13881 }
13882#else
13883 if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
13884 cfg->tdls_mgmt_frame = mgmt_frame;
13885 cfg->tdls_mgmt_frame_len = mgmt_frame_len;
13886 cfg->tdls_mgmt_freq = freq;
13887 return 0;
13888 }
13889#endif /* TDLS_MSG_ONLY_WFD */
13890#endif /* WLTDLS */
13891#ifdef QOS_MAP_SET
13892 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
13893 /* update QoS map set table */
13894 bcm_tlv_t * qos_map_ie = NULL;
13895 if ((qos_map_ie = bcm_parse_tlvs(&mgmt_frame[DOT11_MGMT_HDR_LEN],
13896 mgmt_frame_len - DOT11_MGMT_HDR_LEN,
13897 DOT11_MNG_QOS_MAP_ID)) != NULL) {
13898 WL_DBG((" QoS map set IE found in QoS action frame\n"));
13899 if (!cfg->up_table) {
13900 cfg->up_table = kmalloc(UP_TABLE_MAX, GFP_KERNEL);
13901 }
13902 wl_set_up_table(cfg->up_table, qos_map_ie);
13903 } else {
13904 kfree(cfg->up_table);
13905 cfg->up_table = NULL;
13906 }
13907#endif /* QOS_MAP_SET */
13908#ifdef WBTEXT
13909 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_RRM) {
13910 /* radio measurement category */
13911 switch (mgmt_frame[DOT11_MGMT_HDR_LEN+1]) {
13912 case DOT11_RM_ACTION_NR_REP:
13913 if (wl_cfg80211_recv_nbr_resp(ndev,
13914 &mgmt_frame[DOT11_MGMT_HDR_LEN],
13915 mgmt_frame_len - DOT11_MGMT_HDR_LEN)
13916 == BCME_OK) {
13917 WL_DBG(("RCC updated by nbr response\n"));
13918 }
13919 break;
13920 default:
13921 break;
13922 }
13923#endif /* WBTEXT */
13924 } else {
13925 /*
13926 * if we got normal action frame and ndev is p2p0,
13927 * we have to change ndev from p2p0 to wlan0
13928 */
13929
13930
13931 if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
13932 u8 action = 0;
13933 if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
13934 mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) {
13935 WL_DBG(("Recived action is not public action frame\n"));
13936 } else if (cfg->next_af_subtype == action) {
13937 WL_DBG(("Recived action is the waiting action(%d)\n",
13938 action));
13939 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
13940
13941 /* Stop waiting for next AF. */
13942 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
13943 }
13944 }
13945 }
13946
13947 if (act_frm) {
13948
13949 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
13950 if (cfg->next_af_subtype == act_frm->subtype) {
13951 WL_DBG(("We got a right next frame!(%d)\n",
13952 act_frm->subtype));
13953 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
13954
13955 if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
13956 OSL_SLEEP(20);
13957 }
13958
13959 /* Stop waiting for next AF. */
13960 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
13961 }
13962 }
13963 }
13964
13965 wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
13966 mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel);
13967 if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
13968 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
13969 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
13970 }
13971 } else if (event == WLC_E_PROBREQ_MSG) {
13972
13973 /* Handle probe reqs frame
13974 * WPS-AP certification 4.2.13
13975 */
13976 struct parsed_ies prbreq_ies;
13977 u32 prbreq_ie_len = 0;
13978 bool pbc = 0;
13979
13980 WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
13981 mgmt_frame = (u8 *)(data);
13982 mgmt_frame_len = ntoh32(e->datalen);
13983 if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) {
13984 WL_ERR(("wrong datalen:%d\n", mgmt_frame_len));
13985 return -EINVAL;
13986 }
13987 prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
13988
13989 /* Parse prob_req IEs */
13990 if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
13991 prbreq_ie_len, &prbreq_ies) < 0) {
13992 WL_ERR(("Prob req get IEs failed\n"));
13993 return 0;
13994 }
13995 if (prbreq_ies.wps_ie != NULL) {
13996 wl_validate_wps_ie((char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
13997 WL_DBG((" wps_ie exist pbc = %d\n", pbc));
13998 /* if pbc method, send prob_req mgmt frame to upper layer */
13999 if (!pbc)
14000 return 0;
14001 } else
14002 return 0;
14003 } else {
14004 mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
14005
14006 /* wpa supplicant use probe request event for restarting another GON Req.
14007 * but it makes GON Req repetition.
14008 * so if src addr of prb req is same as my target device,
14009 * do not send probe request event during sending action frame.
14010 */
14011 if (event == WLC_E_P2P_PROBREQ_MSG) {
14012 WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
14013 "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
14014
14015
14016 /* Filter any P2P probe reqs arriving during the
14017 * GO-NEG Phase
14018 */
14019 if (cfg->p2p &&
14020#if defined(P2P_IE_MISSING_FIX)
14021 cfg->p2p_prb_noti &&
14022#endif
14023 wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
14024 WL_DBG(("Filtering P2P probe_req while "
14025 "being in GO-Neg state\n"));
14026 return 0;
14027 }
14028 }
14029 }
14030
14031 if (discover_cfgdev(cfgdev, cfg))
14032 WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
14033 else
14034 WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
14035#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14036 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
14037#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14038 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
14039#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14040 defined(WL_COMPAT_WIRELESS)
14041 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
14042#else
14043 cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
14044#endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
14045
14046 WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
14047 mgmt_frame_len, ntoh32(e->datalen), channel, freq));
14048exit:
14049 if (isfree)
14050 kfree(mgmt_frame);
14051 return err;
14052}
14053
14054#ifdef WL_SCHED_SCAN
14055/* If target scan is not reliable, set the below define to "1" to do a
14056 * full escan
14057 */
14058#define FULL_ESCAN_ON_PFN_NET_FOUND 0
14059static s32
14060wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14061 const wl_event_msg_t *e, void *data)
14062{
14063 wl_pfn_net_info_v2_t *netinfo, *pnetinfo;
14064 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14065 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14066 int err = 0;
14067 struct cfg80211_scan_request *request = NULL;
14068 struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT];
14069 struct ieee80211_channel *channel = NULL;
14070 int channel_req = 0;
14071 int band = 0;
14072 wl_pfn_scanresults_t *pfn_result = (wl_pfn_scanresults_t *)data;
14073 int n_pfn_results = pfn_result->count;
14074 log_conn_event_t *event_data = NULL;
14075 tlv_log *tlv_data = NULL;
14076 u32 alloc_len, tlv_len;
14077 u32 payload_len;
14078
14079 WL_DBG(("Enter\n"));
14080
14081 if (pfn_result->version != PFN_SCANRESULT_VERSION) {
14082 WL_ERR(("Incorrect version %d, expected %d\n", pfn_result->version,
14083 PFN_SCANRESULT_VERSION));
14084 return BCME_VERSION;
14085 }
14086
14087 if (e->event_type == WLC_E_PFN_NET_LOST) {
14088 WL_PNO(("PFN NET LOST event. Do Nothing\n"));
14089 return 0;
14090 }
14091
14092 WL_PNO((">>> PFN NET FOUND event. count:%d \n", n_pfn_results));
14093 if (n_pfn_results > 0) {
14094 int i;
14095
14096 if (n_pfn_results > MAX_PFN_LIST_COUNT)
14097 n_pfn_results = MAX_PFN_LIST_COUNT;
14098 pnetinfo = (wl_pfn_net_info_v2_t *)((char *)data + sizeof(wl_pfn_scanresults_v2_t)
14099 - sizeof(wl_pfn_net_info_v2_t));
14100
14101 memset(&ssid, 0x00, sizeof(ssid));
14102
14103 request = kzalloc(sizeof(*request)
14104 + sizeof(*request->channels) * n_pfn_results,
14105 GFP_KERNEL);
14106 channel = (struct ieee80211_channel *)kzalloc(
14107 (sizeof(struct ieee80211_channel) * n_pfn_results),
14108 GFP_KERNEL);
14109 if (!request || !channel) {
14110 WL_ERR(("No memory"));
14111 err = -ENOMEM;
14112 goto out_err;
14113 }
14114
14115 request->wiphy = wiphy;
14116
14117 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
14118 alloc_len = sizeof(log_conn_event_t) + DOT11_MAX_SSID_LEN + sizeof(uint16) +
14119 sizeof(int16);
14120 event_data = MALLOC(dhdp->osh, alloc_len);
14121 if (!event_data) {
14122 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
14123 "length(%d)\n", __func__, alloc_len));
14124 goto out_err;
14125 }
14126 tlv_len = 3 * sizeof(tlv_log);
14127 event_data->tlvs = MALLOC(dhdp->osh, tlv_len);
14128 if (!event_data->tlvs) {
14129 WL_ERR(("%s: failed to allocate the tlv_log with "
14130 "length(%d)\n", __func__, tlv_len));
14131 goto out_err;
14132 }
14133 }
14134
14135 for (i = 0; i < n_pfn_results; i++) {
14136 netinfo = &pnetinfo[i];
14137 if (!netinfo) {
14138 WL_ERR(("Invalid netinfo ptr. index:%d", i));
14139 err = -EINVAL;
14140 goto out_err;
14141 }
14142 WL_PNO((">>> SSID:%s Channel:%d \n",
14143 netinfo->pfnsubnet.u.SSID, netinfo->pfnsubnet.channel));
14144 /* PFN result doesn't have all the info which are required by the supplicant
14145 * (For e.g IEs) Do a target Escan so that sched scan results are reported
14146 * via wl_inform_single_bss in the required format. Escan does require the
14147 * scan request in the form of cfg80211_scan_request. For timebeing, create
14148 * cfg80211_scan_request one out of the received PNO event.
14149 */
14150 ssid[i].ssid_len = MIN(DOT11_MAX_SSID_LEN, netinfo->pfnsubnet.SSID_len);
14151 memcpy(ssid[i].ssid, netinfo->pfnsubnet.u.SSID,
14152 ssid[i].ssid_len);
14153 request->n_ssids++;
14154
14155 channel_req = netinfo->pfnsubnet.channel;
14156 band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
14157 : NL80211_BAND_5GHZ;
14158 channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band);
14159 channel[i].band = band;
14160 channel[i].flags |= IEEE80211_CHAN_NO_HT40;
14161 request->channels[i] = &channel[i];
14162 request->n_channels++;
14163
14164 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) {
14165 payload_len = sizeof(log_conn_event_t);
14166 event_data->event = WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND;
14167 tlv_data = event_data->tlvs;
14168
14169 /* ssid */
14170 tlv_data->tag = WIFI_TAG_SSID;
14171 tlv_data->len = netinfo->pfnsubnet.SSID_len;
14172 memcpy(tlv_data->value, ssid[i].ssid, ssid[i].ssid_len);
14173 payload_len += TLV_LOG_SIZE(tlv_data);
14174 tlv_data = TLV_LOG_NEXT(tlv_data);
14175
14176 /* channel */
14177 tlv_data->tag = WIFI_TAG_CHANNEL;
14178 tlv_data->len = sizeof(uint16);
14179 memcpy(tlv_data->value, &channel_req, sizeof(uint16));
14180 payload_len += TLV_LOG_SIZE(tlv_data);
14181 tlv_data = TLV_LOG_NEXT(tlv_data);
14182
14183 /* rssi */
14184 tlv_data->tag = WIFI_TAG_RSSI;
14185 tlv_data->len = sizeof(int16);
14186 memcpy(tlv_data->value, &netinfo->RSSI, sizeof(int16));
14187 payload_len += TLV_LOG_SIZE(tlv_data);
14188 tlv_data = TLV_LOG_NEXT(tlv_data);
14189
14190 dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
14191 &event_data->event, payload_len);
14192 }
14193 }
14194
14195 /* assign parsed ssid array */
14196 if (request->n_ssids)
14197 request->ssids = &ssid[0];
14198
14199 if (wl_get_drv_status_all(cfg, SCANNING)) {
14200 /* Abort any on-going scan */
14201 wl_notify_escan_complete(cfg, ndev, true, true);
14202 }
14203
14204 if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
14205 WL_PNO((">>> P2P discovery was ON. Disabling it\n"));
14206 err = wl_cfgp2p_discover_enable_search(cfg, false);
14207 if (unlikely(err)) {
14208 wl_clr_drv_status(cfg, SCANNING, ndev);
14209 goto out_err;
14210 }
14211 p2p_scan(cfg) = false;
14212 }
14213
14214 wl_set_drv_status(cfg, SCANNING, ndev);
14215#if FULL_ESCAN_ON_PFN_NET_FOUND
14216 WL_PNO((">>> Doing Full ESCAN on PNO event\n"));
14217 err = wl_do_escan(cfg, wiphy, ndev, NULL);
14218#else
14219 WL_PNO((">>> Doing targeted ESCAN on PNO event\n"));
14220 err = wl_do_escan(cfg, wiphy, ndev, request);
14221#endif
14222 if (err) {
14223 wl_clr_drv_status(cfg, SCANNING, ndev);
14224 goto out_err;
14225 }
14226 DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED);
14227 cfg->sched_scan_running = TRUE;
14228 }
14229 else {
14230 WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
14231 }
14232out_err:
14233 if (request)
14234 kfree(request);
14235 if (channel)
14236 kfree(channel);
14237
14238 if (event_data) {
14239 MFREE(dhdp->osh, event_data->tlvs, tlv_len);
14240 MFREE(dhdp->osh, event_data, alloc_len);
14241 }
14242 return err;
14243}
14244#endif /* WL_SCHED_SCAN */
14245
14246static void wl_init_conf(struct wl_conf *conf)
14247{
14248 WL_DBG(("Enter \n"));
14249 conf->frag_threshold = (u32)-1;
14250 conf->rts_threshold = (u32)-1;
14251 conf->retry_short = (u32)-1;
14252 conf->retry_long = (u32)-1;
14253 conf->tx_power = -1;
14254}
14255
14256static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
14257{
14258 unsigned long flags;
14259 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
14260
14261 if (profile) {
14262 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
14263 memset(profile, 0, sizeof(struct wl_profile));
14264 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
14265 } else {
14266 WL_ERR(("%s: No profile\n", __FUNCTION__));
14267 }
14268 return;
14269}
14270
14271static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
14272{
14273 memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler));
14274
14275 cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
14276 cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
14277 cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
14278 cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
14279 cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
14280 cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
14281 cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
14282 cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
14283 cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
14284 cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
14285 cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
14286 cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
14287 cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
14288 cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
14289 cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
14290 cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
14291 cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
14292 cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
14293 cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
14294 cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
14295#ifdef PNO_SUPPORT
14296 cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
14297#endif /* PNO_SUPPORT */
14298#ifdef GSCAN_SUPPORT
14299 cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
14300 cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
14301 cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
14302 cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
14303 cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
14304 cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
14305 cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
14306 cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
14307#endif /* GSCAN_SUPPORT */
14308#ifdef RSSI_MONITOR_SUPPORT
14309 cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
14310#endif /* RSSI_MONITOR_SUPPORT */
14311#ifdef WLTDLS
14312 cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
14313#endif /* WLTDLS */
14314 cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
14315#ifdef WL_RELMCAST
14316 cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
14317#endif /* WL_RELMCAST */
14318#ifdef BT_WIFI_HANDOVER
14319 cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
14320#endif
14321 cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
14322 cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
14323#ifdef CUSTOM_EVENT_PM_WAKE
14324 cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
14325#endif /* CUSTOM_EVENT_PM_WAKE */
14326#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
14327 cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
14328#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
14329#ifdef ENABLE_TEMP_THROTTLING
14330 cfg->evt_handler[WLC_E_TEMP_THROTTLE] = wl_check_rx_throttle_status;
14331#endif /* ENABLE_TEMP_THROTTLING */
14332
14333}
14334
14335#if defined(STATIC_WL_PRIV_STRUCT)
14336static int
14337wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
14338{
14339 cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
14340 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
14341 if (cfg->escan_info.escan_buf == NULL) {
14342 WL_ERR(("Failed to alloc ESCAN_BUF\n"));
14343 return -ENOMEM;
14344 }
14345 bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
14346
14347 return 0;
14348}
14349
14350static void
14351wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
14352{
14353 if (cfg->escan_info.escan_buf != NULL) {
14354 cfg->escan_info.escan_buf = NULL;
14355 }
14356}
14357#endif /* STATIC_WL_PRIV_STRUCT */
14358
14359static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
14360{
14361 WL_DBG(("Enter \n"));
14362
14363 cfg->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
14364 if (unlikely(!cfg->scan_results)) {
14365 WL_ERR(("Scan results alloc failed\n"));
14366 goto init_priv_mem_out;
14367 }
14368 cfg->conf = (void *)kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
14369 if (unlikely(!cfg->conf)) {
14370 WL_ERR(("wl_conf alloc failed\n"));
14371 goto init_priv_mem_out;
14372 }
14373 cfg->scan_req_int =
14374 (void *)kzalloc(sizeof(*cfg->scan_req_int), GFP_KERNEL);
14375 if (unlikely(!cfg->scan_req_int)) {
14376 WL_ERR(("Scan req alloc failed\n"));
14377 goto init_priv_mem_out;
14378 }
14379 cfg->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
14380 if (unlikely(!cfg->ioctl_buf)) {
14381 WL_ERR(("Ioctl buf alloc failed\n"));
14382 goto init_priv_mem_out;
14383 }
14384 cfg->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
14385 if (unlikely(!cfg->escan_ioctl_buf)) {
14386 WL_ERR(("Ioctl buf alloc failed\n"));
14387 goto init_priv_mem_out;
14388 }
14389 cfg->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
14390 if (unlikely(!cfg->extra_buf)) {
14391 WL_ERR(("Extra buf alloc failed\n"));
14392 goto init_priv_mem_out;
14393 }
14394 cfg->pmk_list = (void *)kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
14395 if (unlikely(!cfg->pmk_list)) {
14396 WL_ERR(("pmk list alloc failed\n"));
14397 goto init_priv_mem_out;
14398 }
14399#if defined(STATIC_WL_PRIV_STRUCT)
14400 cfg->conn_info = (void *)kzalloc(sizeof(*cfg->conn_info), GFP_KERNEL);
14401 if (unlikely(!cfg->conn_info)) {
14402 WL_ERR(("cfg->conn_info alloc failed\n"));
14403 goto init_priv_mem_out;
14404 }
14405 cfg->ie = (void *)kzalloc(sizeof(*cfg->ie), GFP_KERNEL);
14406 if (unlikely(!cfg->ie)) {
14407 WL_ERR(("cfg->ie alloc failed\n"));
14408 goto init_priv_mem_out;
14409 }
14410 if (unlikely(wl_init_escan_result_buf(cfg))) {
14411 WL_ERR(("Failed to init escan resul buf\n"));
14412 goto init_priv_mem_out;
14413 }
14414#endif /* STATIC_WL_PRIV_STRUCT */
14415 cfg->afx_hdl = (void *)kzalloc(sizeof(*cfg->afx_hdl), GFP_KERNEL);
14416 if (unlikely(!cfg->afx_hdl)) {
14417 WL_ERR(("afx hdl alloc failed\n"));
14418 goto init_priv_mem_out;
14419 } else {
14420 init_completion(&cfg->act_frm_scan);
14421 init_completion(&cfg->wait_next_af);
14422
14423 INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
14424 }
14425#ifdef WLTDLS
14426 if (cfg->tdls_mgmt_frame) {
14427 kfree(cfg->tdls_mgmt_frame);
14428 cfg->tdls_mgmt_frame = NULL;
14429 }
14430#endif /* WLTDLS */
14431 return 0;
14432
14433init_priv_mem_out:
14434 wl_deinit_priv_mem(cfg);
14435
14436 return -ENOMEM;
14437}
14438
14439static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
14440{
14441 kfree(cfg->scan_results);
14442 cfg->scan_results = NULL;
14443 kfree(cfg->conf);
14444 cfg->conf = NULL;
14445 kfree(cfg->scan_req_int);
14446 cfg->scan_req_int = NULL;
14447 kfree(cfg->ioctl_buf);
14448 cfg->ioctl_buf = NULL;
14449 kfree(cfg->escan_ioctl_buf);
14450 cfg->escan_ioctl_buf = NULL;
14451 kfree(cfg->extra_buf);
14452 cfg->extra_buf = NULL;
14453 kfree(cfg->pmk_list);
14454 cfg->pmk_list = NULL;
14455#if defined(STATIC_WL_PRIV_STRUCT)
14456 kfree(cfg->conn_info);
14457 cfg->conn_info = NULL;
14458 kfree(cfg->ie);
14459 cfg->ie = NULL;
14460 wl_deinit_escan_result_buf(cfg);
14461#endif /* STATIC_WL_PRIV_STRUCT */
14462 if (cfg->afx_hdl) {
14463 cancel_work_sync(&cfg->afx_hdl->work);
14464 kfree(cfg->afx_hdl);
14465 cfg->afx_hdl = NULL;
14466 }
14467
14468}
14469
14470static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
14471{
14472 int ret = 0;
14473 WL_DBG(("Enter \n"));
14474
14475 /* Allocate workqueue for event */
14476 if (!cfg->event_workq) {
14477 cfg->event_workq = alloc_workqueue("dhd_eventd", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
14478 }
14479
14480 if (!cfg->event_workq) {
1ebe56b2 14481 WL_ERR(("event_workq alloc_workqueue failed\n"));
010c3a89
RC
14482 ret = -ENOMEM;
14483 } else {
14484 INIT_WORK(&cfg->event_work, wl_event_handler);
14485 }
14486 return ret;
14487}
14488
14489static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
14490{
14491 if (cfg && cfg->event_workq) {
14492 cancel_work_sync(&cfg->event_work);
14493 destroy_workqueue(cfg->event_workq);
14494 cfg->event_workq = NULL;
14495 }
14496}
14497
14498void wl_terminate_event_handler(struct net_device *dev)
14499{
14500 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
14501
14502 if (cfg) {
14503 wl_destroy_event_handler(cfg);
14504 wl_flush_eq(cfg);
14505 }
14506}
14507
d964ce36 14508static void wl_scan_timeout(
14509#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
14510 struct timer_list *t
14511#else
14512 unsigned long data
14513#endif
14514)
010c3a89
RC
14515{
14516 wl_event_msg_t msg;
d964ce36 14517#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
14518 struct bcm_cfg80211 *cfg = from_timer(cfg, t, scan_timeout);
14519#else
010c3a89 14520 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
d964ce36 14521#endif
010c3a89
RC
14522 struct wireless_dev *wdev = NULL;
14523 struct net_device *ndev = NULL;
14524 struct wl_scan_results *bss_list;
14525 struct wl_bss_info *bi = NULL;
14526 s32 i;
14527 u32 channel;
ccd15baf 14528#if 0
010c3a89
RC
14529 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14530 uint32 prev_memdump_mode = dhdp->memdump_enabled;
ccd15baf
RC
14531#endif /* DHD_DEBUG && DHD_FW_COREDUMP */
14532
010c3a89
RC
14533 if (!(cfg->scan_request)) {
14534 WL_ERR(("timer expired but no scan request\n"));
14535 return;
14536 }
14537
14538 bss_list = wl_escan_get_buf(cfg, FALSE);
14539 if (!bss_list) {
14540 WL_ERR(("bss_list is null. Didn't receive any partial scan results\n"));
14541 } else {
14542 WL_ERR(("scanned AP count (%d)\n", bss_list->count));
ccd15baf 14543
010c3a89
RC
14544 bi = next_bss(bss_list, bi);
14545 for_each_bss(bss_list, bi, i) {
21cf08da
RC
14546 if (bi != NULL && &(bi->chanspec) != NULL && (bi->SSID)) {
14547 channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
14548 WL_ERR(("SSID :%s SSID_LEN :%d Channel :%d\n", bi->SSID, bi->SSID_len, channel));
14549 if (bi->SSID[0] == '\0') {
14550 WL_ERR(("SSID :%s is null ssid_len:%d ,need return\n", bi->SSID, bi->SSID_len));
14551 return;
14552 }
14553 } else {
14554 WL_ERR(("SSID or Channel is null\n"));
14555 return;
14556 }
010c3a89
RC
14557 }
14558 }
ccd15baf 14559
010c3a89
RC
14560#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
14561 if (cfg->scan_request->dev)
14562 wdev = cfg->scan_request->dev->ieee80211_ptr;
14563#else
21cf08da
RC
14564 if (cfg->scan_request)
14565 wdev = cfg->scan_request->wdev;
010c3a89
RC
14566#endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
14567 if (!wdev) {
14568 WL_ERR(("No wireless_dev present\n"));
14569 return;
14570 }
14571 ndev = wdev_to_wlc_ndev(wdev, cfg);
ccd15baf 14572
010c3a89
RC
14573 bzero(&msg, sizeof(wl_event_msg_t));
14574 WL_ERR(("timer expired\n"));
ccd15baf 14575#if 0
010c3a89
RC
14576 if (dhdp->memdump_enabled) {
14577 dhdp->memdump_enabled = DUMP_MEMFILE;
14578 dhdp->memdump_type = DUMP_TYPE_SCAN_TIMEOUT;
14579 dhd_bus_mem_dump(dhdp);
14580 dhdp->memdump_enabled = prev_memdump_mode;
14581 }
ccd15baf 14582#endif /* DHD_DEBUG && DHD_FW_COREDUMP */
010c3a89
RC
14583 msg.event_type = hton32(WLC_E_ESCAN_RESULT);
14584 msg.status = hton32(WLC_E_STATUS_TIMEOUT);
14585 msg.reason = 0xFFFFFFFF;
14586 wl_cfg80211_event(ndev, &msg, NULL);
14587#ifdef CUSTOMER_HW4_DEBUG
14588 if (!wl_scan_timeout_dbg_enabled)
14589 wl_scan_timeout_dbg_set();
14590#endif /* CUSTOMER_HW4_DEBUG */
ccd15baf 14591
010c3a89
RC
14592 // terence 20130729: workaround to fix out of memory in firmware
14593// if (dhd_conf_get_chip(dhd_get_pub(ndev)) == BCM43362_CHIP_ID) {
14594// WL_ERR(("Send hang event\n"));
14595// net_os_send_hang_message(ndev);
14596// }
14597}
14598
14599#ifdef DHD_LOSSLESS_ROAMING
14600static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
14601{
14602 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14603
14604 /* restore prec_map to ALLPRIO */
14605 dhdp->dequeue_prec_map = ALLPRIO;
14606 if (timer_pending(&cfg->roam_timeout)) {
14607 del_timer_sync(&cfg->roam_timeout);
14608 }
14609
14610}
14611
d964ce36 14612static void wl_roam_timeout(
14613#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
14614 struct timer_list *t
14615#else
14616 unsigned long data
14617#endif
14618)
010c3a89 14619{
d964ce36 14620#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
14621 struct bcm_cfg80211 *cfg = from_timer(cfg, t, roam_timeout);
14622#else
010c3a89 14623 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
d964ce36 14624#endif
010c3a89
RC
14625 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14626
14627 WL_ERR(("roam timer expired\n"));
14628
14629 /* restore prec_map to ALLPRIO */
14630 dhdp->dequeue_prec_map = ALLPRIO;
14631}
14632
14633#endif /* DHD_LOSSLESS_ROAMING */
14634
14635static s32
14636wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
14637 unsigned long state, void *ptr)
14638{
14639#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
14640 struct net_device *dev = ptr;
14641#else
14642 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
14643#endif /* LINUX_VERSION < VERSION(3, 11, 0) */
14644 struct wireless_dev *wdev = ndev_to_wdev(dev);
14645 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
14646
14647 WL_DBG(("Enter \n"));
14648
14649 if (!wdev || !cfg || dev == bcmcfg_to_prmry_ndev(cfg))
14650 return NOTIFY_DONE;
14651
14652 switch (state) {
14653 case NETDEV_DOWN:
14654 {
14655#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
14656 int max_wait_timeout = 2;
14657 int max_wait_count = 100;
14658 int refcnt = 0;
14659 unsigned long limit = jiffies + max_wait_timeout * HZ;
14660 while (work_pending(&wdev->cleanup_work)) {
14661 if (refcnt%5 == 0) {
14662 WL_ERR(("[NETDEV_DOWN] wait for "
14663 "complete of cleanup_work"
14664 " (%d th)\n", refcnt));
14665 }
14666 if (!time_before(jiffies, limit)) {
14667 WL_ERR(("[NETDEV_DOWN] cleanup_work"
14668 " of CFG80211 is not"
14669 " completed in %d sec\n",
14670 max_wait_timeout));
14671 break;
14672 }
14673 if (refcnt >= max_wait_count) {
14674 WL_ERR(("[NETDEV_DOWN] cleanup_work"
14675 " of CFG80211 is not"
14676 " completed in %d loop\n",
14677 max_wait_count));
14678 break;
14679 }
14680 set_current_state(TASK_INTERRUPTIBLE);
14681 (void)schedule_timeout(100);
14682 set_current_state(TASK_RUNNING);
14683 refcnt++;
14684 }
14685#endif /* LINUX_VERSION < VERSION(3, 14, 0) */
14686 break;
14687 }
14688 case NETDEV_UNREGISTER:
14689 /* after calling list_del_rcu(&wdev->list) */
14690 wl_cfg80211_clear_per_bss_ies(cfg,
14691 wl_get_bssidx_by_wdev(cfg, wdev));
14692 wl_dealloc_netinfo_by_wdev(cfg, wdev);
14693 break;
14694 case NETDEV_GOING_DOWN:
14695 /*
14696 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
14697 * In front of door, the function checks whether current scan
14698 * is working or not. If the scanning is still working,
14699 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
14700 */
14701 if (wl_get_drv_status(cfg, SCANNING, dev))
14702 wl_notify_escan_complete(cfg, dev, true, true);
14703 break;
14704 }
14705 return NOTIFY_DONE;
14706}
14707
14708static struct notifier_block wl_cfg80211_netdev_notifier = {
14709 .notifier_call = wl_cfg80211_netdev_notifier_call,
14710};
14711
14712/*
14713 * to make sure we won't register the same notifier twice, otherwise a loop is likely to be
14714 * created in kernel notifier link list (with 'next' pointing to itself)
14715 */
14716static bool wl_cfg80211_netdev_notifier_registered = FALSE;
14717
14718static void wl_cfg80211_cancel_scan(struct bcm_cfg80211 *cfg)
14719{
14720 struct wireless_dev *wdev = NULL;
14721 struct net_device *ndev = NULL;
14722
14723 if (!cfg->scan_request)
14724 return;
14725
14726#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
14727 if (cfg->scan_request->dev)
14728 wdev = cfg->scan_request->dev->ieee80211_ptr;
14729#else
14730 wdev = cfg->scan_request->wdev;
14731#endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
14732
14733 if (!wdev) {
14734 WL_ERR(("No wireless_dev present\n"));
14735 return;
14736 }
14737
14738 ndev = wdev_to_wlc_ndev(wdev, cfg);
14739 wl_notify_escan_complete(cfg, ndev, true, true);
14740 WL_ERR(("Scan aborted! \n"));
14741}
14742
14743void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
14744{
14745 wl_scan_params_t *params = NULL;
14746 s32 params_size = 0;
14747 s32 err = BCME_OK;
14748 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
14749 if (!in_atomic()) {
14750 /* Our scan params only need space for 1 channel and 0 ssids */
14751 params = wl_cfg80211_scan_alloc_params(cfg, -1, 0, &params_size);
14752 if (params == NULL) {
14753 WL_ERR(("scan params allocation failed \n"));
14754 err = -ENOMEM;
14755 } else {
14756 /* Do a scan abort to stop the driver's scan engine */
14757 err = wldev_ioctl_set(dev, WLC_SCAN, params, params_size);
14758 if (err < 0) {
14759 WL_ERR(("scan abort failed \n"));
14760 }
14761 kfree(params);
14762 }
14763 }
14764#ifdef WLTDLS
14765 if (cfg->tdls_mgmt_frame) {
14766 kfree(cfg->tdls_mgmt_frame);
14767 cfg->tdls_mgmt_frame = NULL;
14768 }
14769#endif /* WLTDLS */
14770}
14771
14772static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
14773 struct net_device *ndev,
14774 bool aborted, bool fw_abort)
14775{
14776 s32 err = BCME_OK;
14777 unsigned long flags;
14778 struct net_device *dev;
14779 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14780#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
14781 struct cfg80211_scan_info info;
14782 info.aborted = aborted;
14783#endif
14784
14785 WL_DBG(("Enter \n"));
14786 BCM_REFERENCE(dhdp);
14787
14788 mutex_lock(&cfg->scan_complete);
14789
14790 if (!ndev) {
14791 WL_ERR(("ndev is null\n"));
14792 err = BCME_ERROR;
14793 goto out;
14794 }
14795
14796 if (cfg->escan_info.ndev != ndev) {
14797 WL_ERR(("ndev is different %p %p\n", cfg->escan_info.ndev, ndev));
14798 err = BCME_ERROR;
14799 goto out;
14800 }
14801
14802 if (cfg->scan_request) {
14803 dev = bcmcfg_to_prmry_ndev(cfg);
14804#if defined(WL_ENABLE_P2P_IF)
14805 if (cfg->scan_request->dev != cfg->p2p_net)
14806 dev = cfg->scan_request->dev;
14807#elif defined(WL_CFG80211_P2P_DEV_IF)
14808 if (cfg->scan_request->wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
14809 dev = cfg->scan_request->wdev->netdev;
14810#endif /* WL_ENABLE_P2P_IF */
14811 }
14812 else {
14813 WL_DBG(("cfg->scan_request is NULL may be internal scan."
14814 "doing scan_abort for ndev %p primary %p",
14815 ndev, bcmcfg_to_prmry_ndev(cfg)));
14816 dev = ndev;
14817 }
14818 if (fw_abort && !in_atomic())
14819 wl_cfg80211_scan_abort(cfg);
14820 if (timer_pending(&cfg->scan_timeout))
14821 del_timer_sync(&cfg->scan_timeout);
14822#if defined(ESCAN_RESULT_PATCH)
14823 if (likely(cfg->scan_request)) {
14824 cfg->bss_list = wl_escan_get_buf(cfg, aborted);
14825 wl_inform_bss(cfg);
14826 }
14827#endif /* ESCAN_RESULT_PATCH */
14828 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
14829#ifdef WL_SCHED_SCAN
14830 if (cfg->sched_scan_req && !cfg->scan_request) {
14831 WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n"));
dfb0f3ae
RC
14832 if (!aborted) {
14833#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
14834 cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy, 0);
14835#else
010c3a89 14836 cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy);
dfb0f3ae
RC
14837#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
14838 }
010c3a89
RC
14839
14840 DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE);
14841 cfg->sched_scan_running = FALSE;
14842 }
14843#endif /* WL_SCHED_SCAN */
14844 if (likely(cfg->scan_request)) {
14845#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
14846 cfg80211_scan_done(cfg->scan_request, &info);
14847#else
14848 cfg80211_scan_done(cfg->scan_request, aborted);
14849#endif
14850 cfg->scan_request = NULL;
14851 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
14852 DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)(cfg->pub));
14853 }
14854 if (p2p_is_on(cfg))
14855 wl_clr_p2p_status(cfg, SCANNING);
14856 wl_clr_drv_status(cfg, SCANNING, dev);
14857 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
14858
14859out:
14860 mutex_unlock(&cfg->scan_complete);
14861 return err;
14862}
14863
14864#ifdef ESCAN_BUF_OVERFLOW_MGMT
14865#ifndef WL_DRV_AVOID_SCANCACHE
14866static void
14867wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate)
14868{
14869 int idx;
14870 for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) {
14871 int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1;
14872 if (bss->RSSI < candidate[idx].RSSI) {
14873 if (len)
14874 memcpy(&candidate[idx + 1], &candidate[idx],
14875 sizeof(removal_element_t) * len);
14876 candidate[idx].RSSI = bss->RSSI;
14877 candidate[idx].length = bss->length;
14878 memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN);
14879 return;
14880 }
14881 }
14882}
14883
14884static void
14885wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate,
14886 wl_bss_info_t *bi)
14887{
14888 int idx1, idx2;
14889 int total_delete_len = 0;
14890 for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) {
14891 int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
14892 wl_bss_info_t *bss = NULL;
14893 if (candidate[idx1].RSSI >= bi->RSSI)
14894 continue;
14895 for (idx2 = 0; idx2 < list->count; idx2++) {
14896 bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) :
14897 list->bss_info;
14898 if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
14899 candidate[idx1].RSSI == bss->RSSI &&
14900 candidate[idx1].length == dtoh32(bss->length)) {
14901 u32 delete_len = dtoh32(bss->length);
14902 WL_DBG(("delete scan info of " MACDBG " to add new AP\n",
14903 MAC2STRDBG(bss->BSSID.octet)));
14904 if (idx2 < list->count -1) {
14905 memmove((u8 *)bss, (u8 *)bss + delete_len,
14906 list->buflen - cur_len - delete_len);
14907 }
14908 list->buflen -= delete_len;
14909 list->count--;
14910 total_delete_len += delete_len;
14911 /* if delete_len is greater than or equal to result length */
14912 if (total_delete_len >= bi->length) {
14913 return;
14914 }
14915 break;
14916 }
14917 cur_len += dtoh32(bss->length);
14918 }
14919 }
14920}
14921#endif /* WL_DRV_AVOID_SCANCACHE */
14922#endif /* ESCAN_BUF_OVERFLOW_MGMT */
14923
14924#ifdef WL_DRV_AVOID_SCANCACHE
14925static u32 wl_p2p_find_peer_channel(struct bcm_cfg80211 *cfg, s32 status, wl_bss_info_t *bi,
14926 u32 bi_length)
14927{
14928 u32 ret;
14929 u8 *p2p_dev_addr = NULL;
14930
14931 ret = wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL);
14932 if (!ret) {
14933 return ret;
14934 }
14935 if (status == WLC_E_STATUS_PARTIAL) {
14936 p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
14937 if (p2p_dev_addr && !memcmp(p2p_dev_addr,
14938 cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) {
14939 s32 channel = wf_chspec_ctlchan(
14940 wl_chspec_driver_to_host(bi->chanspec));
14941
14942 if ((channel > MAXCHANNEL) || (channel <= 0))
14943 channel = WL_INVALID;
14944 else
14945 WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found,"
14946 " channel : %d\n",
14947 MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet),
14948 channel));
14949
14950 wl_clr_p2p_status(cfg, SCANNING);
14951 cfg->afx_hdl->peer_chan = channel;
14952 complete(&cfg->act_frm_scan);
14953 }
14954 } else {
14955 WL_INFORM(("ACTION FRAME SCAN DONE\n"));
14956 wl_clr_p2p_status(cfg, SCANNING);
14957 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
14958 if (cfg->afx_hdl->peer_chan == WL_INVALID)
14959 complete(&cfg->act_frm_scan);
14960 }
14961
14962 return ret;
14963}
14964
14965static s32 wl_escan_without_scan_cache(struct bcm_cfg80211 *cfg, wl_escan_result_t *escan_result,
14966 struct net_device *ndev, const wl_event_msg_t *e, s32 status)
14967{
14968 s32 err = BCME_OK;
14969 wl_bss_info_t *bi;
14970 u32 bi_length;
14971 bool aborted = false;
14972 bool fw_abort = false;
14973 bool notify_escan_complete = false;
14974
14975 if (wl_escan_check_sync_id(status, escan_result->sync_id,
14976 cfg->escan_info.cur_sync_id) < 0) {
14977 goto exit;
14978 }
14979
14980 wl_escan_print_sync_id(status, escan_result->sync_id,
14981 cfg->escan_info.cur_sync_id);
14982
14983 if (!(status == WLC_E_STATUS_TIMEOUT) || !(status == WLC_E_STATUS_PARTIAL)) {
14984 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
14985 }
14986
14987 if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
14988 notify_escan_complete = true;
14989 }
14990
14991 if (status == WLC_E_STATUS_PARTIAL) {
14992 WL_INFORM(("WLC_E_STATUS_PARTIAL \n"));
14993 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND);
14994 if ((!escan_result) || (dtoh16(escan_result->bss_count) != 1)) {
14995 WL_ERR(("Invalid escan result (NULL pointer) or invalid bss_count\n"));
14996 goto exit;
14997 }
14998
14999 bi = escan_result->bss_info;
15000 bi_length = dtoh32(bi->length);
15001 if ((!bi) ||
15002 (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE))) {
15003 WL_ERR(("Invalid escan bss info (NULL pointer)"
15004 "or invalid bss_info length\n"));
15005 goto exit;
15006 }
15007
15008 if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
15009 if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
15010 WL_DBG(("Ignoring IBSS result\n"));
15011 goto exit;
15012 }
15013 }
15014
15015 if (wl_p2p_find_peer_channel(cfg, status, bi, bi_length)) {
15016 goto exit;
15017 } else {
15018 if (scan_req_match(cfg)) {
15019 /* p2p scan && allow only probe response */
15020 if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) &&
15021 (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
15022 goto exit;
15023 }
15024 err = wl_inform_single_bss(cfg, bi, false);
15025
15026 /*
15027 * !Broadcast && number of ssid = 1 && number of channels =1
15028 * means specific scan to association
15029 */
15030 if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) {
15031 WL_ERR(("P2P assoc scan fast aborted.\n"));
15032 aborted = false;
15033 fw_abort = true;
15034 }
15035 /* Directly exit from function here and
15036 * avoid sending notify completion to cfg80211
15037 */
15038 goto exit;
15039 }
15040 } else if (status == WLC_E_STATUS_SUCCESS) {
15041 if (wl_p2p_find_peer_channel(cfg, status, NULL, 0)) {
15042 goto exit;
15043 }
15044 WL_INFORM(("ESCAN COMPLETED\n"));
15045 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_COMPLETE);
15046
15047 /* Update escan complete status */
15048 aborted = false;
15049 fw_abort = false;
15050
15051#ifdef CUSTOMER_HW4_DEBUG
15052 if (wl_scan_timeout_dbg_enabled)
15053 wl_scan_timeout_dbg_clear();
15054#endif /* CUSTOMER_HW4_DEBUG */
15055 } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) ||
15056 (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) ||
15057 (status == WLC_E_STATUS_NEWASSOC)) {
15058 /* Handle all cases of scan abort */
15059
15060 WL_DBG(("ESCAN ABORT reason: %d\n", status));
15061 if (wl_p2p_find_peer_channel(cfg, status, NULL, 0)) {
15062 goto exit;
15063 }
15064 WL_INFORM(("ESCAN ABORTED\n"));
15065
15066 /* Update escan complete status */
15067 aborted = true;
15068 fw_abort = false;
15069
15070 } else if (status == WLC_E_STATUS_TIMEOUT) {
15071 WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request));
15072 WL_ERR(("reason[0x%x]\n", e->reason));
15073 if (e->reason == 0xFFFFFFFF) {
15074 /* Update escan complete status */
15075 aborted = true;
15076 fw_abort = true;
15077 }
15078 } else {
15079 WL_ERR(("unexpected Escan Event %d : abort\n", status));
15080
15081 if (wl_p2p_find_peer_channel(cfg, status, NULL, 0)) {
15082 goto exit;
15083 }
15084 /* Update escan complete status */
15085 aborted = true;
15086 fw_abort = false;
15087 }
15088
15089 /* Notify escan complete status */
15090 if (notify_escan_complete) {
15091 wl_notify_escan_complete(cfg, ndev, aborted, fw_abort);
15092 }
15093
15094exit:
15095 return err;
15096
15097}
15098#endif /* WL_DRV_AVOID_SCANCACHE */
32c27b7a 15099
010c3a89
RC
15100static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15101 const wl_event_msg_t *e, void *data)
15102{
15103 s32 err = BCME_OK;
15104 s32 status = ntoh32(e->status);
15105 wl_escan_result_t *escan_result;
15106 struct net_device *ndev = NULL;
15107#ifndef WL_DRV_AVOID_SCANCACHE
15108 wl_bss_info_t *bi;
15109 u32 bi_length;
15110 wifi_p2p_ie_t * p2p_ie;
15111 u8 *p2p_dev_addr = NULL;
15112 wl_scan_results_t *list;
15113 wl_bss_info_t *bss = NULL;
15114 u32 i;
15115#endif /* WL_DRV_AVOID_SCANCACHE */
15116 u16 channel;
15117 struct ieee80211_supported_band *band;
15118
15119 WL_DBG((" enter event type : %d, status : %d \n",
15120 ntoh32(e->event_type), ntoh32(e->status)));
15121
15122 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15123
15124 mutex_lock(&cfg->usr_sync);
15125 /* P2P SCAN is coming from primary interface */
15126 if (wl_get_p2p_status(cfg, SCANNING)) {
15127 if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM))
15128 ndev = cfg->afx_hdl->dev;
15129 else
15130 ndev = cfg->escan_info.ndev;
15131
15132 }
15133 if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) {
15134 WL_ERR(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n",
15135 ndev, wl_get_drv_status(cfg, SCANNING, ndev),
15136 ntoh32(e->event_type), ntoh32(e->status)));
15137 goto exit;
15138 }
15139 escan_result = (wl_escan_result_t *)data;
15140
15141#ifndef WL_DRV_AVOID_SCANCACHE
15142 if (status == WLC_E_STATUS_PARTIAL) {
15143 WL_INFORM(("WLC_E_STATUS_PARTIAL \n"));
15144 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND);
15145 if (!escan_result) {
15146 WL_ERR(("Invalid escan result (NULL pointer)\n"));
15147 goto exit;
15148 }
15149 if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) ||
15150 (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) {
15151 WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen)));
15152 goto exit;
15153 }
15154 if (dtoh16(escan_result->bss_count) != 1) {
15155 WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
15156 goto exit;
15157 }
15158 bi = escan_result->bss_info;
15159 if (!bi) {
15160 WL_ERR(("Invalid escan bss info (NULL pointer)\n"));
15161 goto exit;
15162 }
15163 bi_length = dtoh32(bi->length);
15164 if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
15165 WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
15166 goto exit;
15167 }
15168
15169 /* +++++ terence 20130524: skip invalid bss */
15170 channel =
15171 bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec));
15172 if (channel <= CH_MAX_2G_CHANNEL)
15173 band = bcmcfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
15174 else
15175 band = bcmcfg_to_wiphy(cfg)->bands[IEEE80211_BAND_5GHZ];
15176 if (!band) {
15177 WL_ERR(("No valid band\n"));
15178 goto exit;
15179 }
15180 if (!dhd_conf_match_channel(cfg->pub, channel))
15181 goto exit;
15182 /* ----- terence 20130524: skip invalid bss */
15183
15184 if (wl_escan_check_sync_id(status, escan_result->sync_id,
15185 cfg->escan_info.cur_sync_id) < 0)
15186 goto exit;
15187
15188 if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
15189 if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
15190 WL_DBG(("Ignoring IBSS result\n"));
15191 goto exit;
15192 }
15193 }
15194
15195 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
15196 p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
15197 if (p2p_dev_addr && !memcmp(p2p_dev_addr,
15198 cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) {
15199 s32 channel = wf_chspec_ctlchan(
15200 wl_chspec_driver_to_host(bi->chanspec));
15201
15202 if ((channel > MAXCHANNEL) || (channel <= 0))
15203 channel = WL_INVALID;
15204 else
15205 WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found,"
15206 " channel : %d\n",
15207 MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet),
15208 channel));
15209
15210 wl_clr_p2p_status(cfg, SCANNING);
15211 cfg->afx_hdl->peer_chan = channel;
15212 complete(&cfg->act_frm_scan);
15213 goto exit;
15214 }
15215
15216 } else {
15217 int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
15218#ifdef ESCAN_BUF_OVERFLOW_MGMT
15219 removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT];
15220 int remove_lower_rssi = FALSE;
15221
15222 bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT);
15223#endif /* ESCAN_BUF_OVERFLOW_MGMT */
15224
15225 list = wl_escan_get_buf(cfg, FALSE);
15226 if (scan_req_match(cfg)) {
15227 /* p2p scan && allow only probe response */
15228 if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) &&
15229 (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
15230 goto exit;
15231 if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset,
15232 bi->ie_length)) == NULL) {
15233 WL_ERR(("Couldn't find P2PIE in probe"
15234 " response/beacon\n"));
15235 goto exit;
15236 }
15237 }
15238#ifdef ESCAN_BUF_OVERFLOW_MGMT
15239 if (bi_length > ESCAN_BUF_SIZE - list->buflen)
15240 remove_lower_rssi = TRUE;
15241#endif /* ESCAN_BUF_OVERFLOW_MGMT */
15242
15243 WL_SCAN(("%s("MACDBG") RSSI %d flags 0x%x length %d\n", bi->SSID,
15244 MAC2STRDBG(bi->BSSID.octet), bi->RSSI, bi->flags, bi->length));
15245 for (i = 0; i < list->count; i++) {
15246 bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
15247 : list->bss_info;
15248 if (!bss) {
15249 WL_ERR(("bss is NULL\n"));
15250 goto exit;
15251 }
15252#ifdef ESCAN_BUF_OVERFLOW_MGMT
32c27b7a 15253 WL_SCAN(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n",
010c3a89
RC
15254 bss->SSID, MAC2STRDBG(bss->BSSID.octet),
15255 i, bss->RSSI, list->count));
15256
15257 if (remove_lower_rssi)
15258 wl_cfg80211_find_removal_candidate(bss, candidate);
15259#endif /* ESCAN_BUF_OVERFLOW_MGMT */
15260
15261 if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
15262 (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec))
15263 == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) &&
15264 bi->SSID_len == bss->SSID_len &&
15265 !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
15266
15267 /* do not allow beacon data to update
15268 *the data recd from a probe response
15269 */
15270 if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) &&
15271 (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
15272 goto exit;
15273
15274 WL_SCAN(("%s("MACDBG"), i=%d prev: RSSI %d"
15275 " flags 0x%x, new: RSSI %d flags 0x%x\n",
15276 bss->SSID, MAC2STRDBG(bi->BSSID.octet), i,
15277 bss->RSSI, bss->flags, bi->RSSI, bi->flags));
15278
15279 if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) ==
15280 (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) {
15281 /* preserve max RSSI if the measurements are
15282 * both on-channel or both off-channel
15283 */
15284 WL_SCAN(("%s("MACDBG"), same onchan"
15285 ", RSSI: prev %d new %d\n",
15286 bss->SSID, MAC2STRDBG(bi->BSSID.octet),
15287 bss->RSSI, bi->RSSI));
15288 bi->RSSI = MAX(bss->RSSI, bi->RSSI);
15289 } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
15290 (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) {
15291 /* preserve the on-channel rssi measurement
15292 * if the new measurement is off channel
15293 */
15294 WL_SCAN(("%s("MACDBG"), prev onchan"
15295 ", RSSI: prev %d new %d\n",
15296 bss->SSID, MAC2STRDBG(bi->BSSID.octet),
15297 bss->RSSI, bi->RSSI));
15298 bi->RSSI = bss->RSSI;
15299 bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL;
15300 }
15301 if (dtoh32(bss->length) != bi_length) {
15302 u32 prev_len = dtoh32(bss->length);
15303
15304 WL_SCAN(("bss info replacement"
15305 " is occured(bcast:%d->probresp%d)\n",
15306 bss->ie_length, bi->ie_length));
15307 WL_SCAN(("%s("MACDBG"), replacement!(%d -> %d)\n",
15308 bss->SSID, MAC2STRDBG(bi->BSSID.octet),
15309 prev_len, bi_length));
15310
15311 if (list->buflen - prev_len + bi_length
15312 > ESCAN_BUF_SIZE) {
15313 WL_ERR(("Buffer is too small: keep the"
15314 " previous result of this AP\n"));
15315 /* Only update RSSI */
15316 bss->RSSI = bi->RSSI;
15317 bss->flags |= (bi->flags
15318 & WL_BSS_FLAGS_RSSI_ONCHANNEL);
15319 goto exit;
15320 }
15321
15322 if (i < list->count - 1) {
15323 /* memory copy required by this case only */
15324 memmove((u8 *)bss + bi_length,
15325 (u8 *)bss + prev_len,
15326 list->buflen - cur_len - prev_len);
15327 }
15328 list->buflen -= prev_len;
15329 list->buflen += bi_length;
15330 }
15331 list->version = dtoh32(bi->version);
15332 memcpy((u8 *)bss, (u8 *)bi, bi_length);
15333 goto exit;
15334 }
15335 cur_len += dtoh32(bss->length);
15336 }
15337 if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
15338#ifdef ESCAN_BUF_OVERFLOW_MGMT
15339 wl_cfg80211_remove_lowRSSI_info(list, candidate, bi);
15340 if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
15341 WL_DBG(("RSSI(" MACDBG ") is too low(%d) to add Buffer\n",
15342 MAC2STRDBG(bi->BSSID.octet), bi->RSSI));
15343 goto exit;
15344 }
15345#else
15346 WL_ERR(("Buffer is too small: ignoring\n"));
15347 goto exit;
15348#endif /* ESCAN_BUF_OVERFLOW_MGMT */
15349 }
15350
15351 memcpy(&(((char *)list)[list->buflen]), bi, bi_length);
15352 list->version = dtoh32(bi->version);
15353 list->buflen += bi_length;
15354 list->count++;
15355
15356 /*
15357 * !Broadcast && number of ssid = 1 && number of channels =1
15358 * means specific scan to association
15359 */
15360 if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) {
15361 WL_ERR(("P2P assoc scan fast aborted.\n"));
15362 wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false, true);
15363 goto exit;
15364 }
15365 }
15366 }
15367 else if (status == WLC_E_STATUS_SUCCESS) {
15368 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
15369 wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id,
15370 escan_result->sync_id);
15371
15372 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
15373 WL_INFORM(("ACTION FRAME SCAN DONE\n"));
15374 wl_clr_p2p_status(cfg, SCANNING);
15375 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
15376 if (cfg->afx_hdl->peer_chan == WL_INVALID)
15377 complete(&cfg->act_frm_scan);
15378 } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
15379 WL_INFORM(("ESCAN COMPLETED\n"));
15380 DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_COMPLETE);
15381 cfg->bss_list = wl_escan_get_buf(cfg, FALSE);
15382 if (!scan_req_match(cfg)) {
32c27b7a 15383 WL_SCAN(("SCAN COMPLETED: scanned AP count=%d\n",
010c3a89
RC
15384 cfg->bss_list->count));
15385 }
15386 wl_inform_bss(cfg);
15387 wl_notify_escan_complete(cfg, ndev, false, false);
15388 }
15389 wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT);
15390#ifdef CUSTOMER_HW4_DEBUG
15391 if (wl_scan_timeout_dbg_enabled)
15392 wl_scan_timeout_dbg_clear();
15393#endif /* CUSTOMER_HW4_DEBUG */
15394 } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) ||
15395 (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) ||
15396 (status == WLC_E_STATUS_NEWASSOC)) {
15397 /* Handle all cases of scan abort */
15398 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
15399 wl_escan_print_sync_id(status, escan_result->sync_id,
15400 cfg->escan_info.cur_sync_id);
15401 WL_DBG(("ESCAN ABORT reason: %d\n", status));
15402 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
15403 WL_INFORM(("ACTION FRAME SCAN DONE\n"));
15404 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
15405 wl_clr_p2p_status(cfg, SCANNING);
15406 if (cfg->afx_hdl->peer_chan == WL_INVALID)
15407 complete(&cfg->act_frm_scan);
15408 } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
15409 WL_INFORM(("ESCAN ABORTED\n"));
15410 cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
15411 if (!scan_req_match(cfg)) {
15412 WL_TRACE_HW4(("SCAN ABORTED: scanned AP count=%d\n",
15413 cfg->bss_list->count));
15414 }
15415 wl_inform_bss(cfg);
15416 wl_notify_escan_complete(cfg, ndev, true, false);
15417 } else {
15418 /* If there is no pending host initiated scan, do nothing */
15419 WL_DBG(("ESCAN ABORT: No pending scans. Ignoring event.\n"));
15420 }
15421 wl_escan_increment_sync_id(cfg, SCAN_BUF_CNT);
15422 } else if (status == WLC_E_STATUS_TIMEOUT) {
15423 WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request));
15424 WL_ERR(("reason[0x%x]\n", e->reason));
15425 if (e->reason == 0xFFFFFFFF) {
15426 wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
15427 }
15428 } else {
15429 WL_ERR(("unexpected Escan Event %d : abort\n", status));
15430 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
15431 wl_escan_print_sync_id(status, escan_result->sync_id,
15432 cfg->escan_info.cur_sync_id);
15433 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
15434 WL_INFORM(("ACTION FRAME SCAN DONE\n"));
15435 wl_clr_p2p_status(cfg, SCANNING);
15436 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
15437 if (cfg->afx_hdl->peer_chan == WL_INVALID)
15438 complete(&cfg->act_frm_scan);
15439 } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
15440 cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
15441 if (!scan_req_match(cfg)) {
15442 WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): "
15443 "scanned AP count=%d\n",
15444 cfg->bss_list->count));
15445 }
15446 wl_inform_bss(cfg);
15447 wl_notify_escan_complete(cfg, ndev, true, false);
15448 }
15449 wl_escan_increment_sync_id(cfg, 2);
15450 }
15451#else /* WL_DRV_AVOID_SCANCACHE */
15452 err = wl_escan_without_scan_cache(cfg, escan_result, ndev, e, status);
15453#endif /* WL_DRV_AVOID_SCANCACHE */
15454exit:
15455 mutex_unlock(&cfg->usr_sync);
15456 return err;
15457}
15458
15459static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
15460{
15461 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
15462 bool p2p_connected = wl_cfgp2p_vif_created(cfg);
15463 struct net_info *iter, *next;
15464
15465 if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT))
15466 return;
15467
15468 WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
15469 enable, p2p_connected, connected_cnt));
15470 /* Disable FW roam when we have a concurrent P2P connection */
15471 if (enable && p2p_connected && connected_cnt > 1) {
15472
15473 /* Mark it as to be reverted */
15474 cfg->roam_flags |= WL_ROAM_REVERT_STATUS;
15475#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15476 4 && __GNUC_MINOR__ >= 6))
15477_Pragma("GCC diagnostic push")
15478_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
15479#endif
15480 for_each_ndev(cfg, iter, next) {
15481 if (iter->ndev && iter->wdev &&
15482 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
15483 if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE)
15484 == BCME_OK) {
15485 iter->roam_off = TRUE;
15486 }
15487 else {
15488 WL_ERR(("error to enable roam_off\n"));
15489 }
15490 }
15491 }
15492#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15493 4 && __GNUC_MINOR__ >= 6))
15494_Pragma("GCC diagnostic pop")
15495#endif
15496 }
15497 else if (!enable && (cfg->roam_flags & WL_ROAM_REVERT_STATUS)) {
15498 cfg->roam_flags &= ~WL_ROAM_REVERT_STATUS;
15499#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15500 4 && __GNUC_MINOR__ >= 6))
15501_Pragma("GCC diagnostic push")
15502_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
15503#endif
15504 for_each_ndev(cfg, iter, next) {
15505 if (iter->ndev && iter->wdev &&
15506 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
15507 if (iter->roam_off != WL_INVALID) {
15508 if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE)
15509 == BCME_OK) {
15510 iter->roam_off = FALSE;
15511 }
15512 else {
15513 WL_ERR(("error to disable roam_off\n"));
15514 }
15515 }
15516 }
15517 }
15518#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15519 4 && __GNUC_MINOR__ >= 6))
15520_Pragma("GCC diagnostic pop")
15521#endif
15522 }
15523
15524 return;
15525}
15526
15527static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
15528{
15529 struct net_info *iter, *next;
15530 u32 ctl_chan = 0;
15531 u32 chanspec = 0;
15532 u32 pre_ctl_chan = 0;
15533 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
15534 cfg->vsdb_mode = false;
15535
15536 if (connected_cnt <= 1) {
15537 return;
15538 }
15539#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15540 4 && __GNUC_MINOR__ >= 6))
15541_Pragma("GCC diagnostic push")
15542_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
15543#endif
15544 for_each_ndev(cfg, iter, next) {
15545 /* p2p discovery iface ndev could be null */
15546 if (iter->ndev) {
15547 chanspec = 0;
15548 ctl_chan = 0;
15549 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
15550 if (wldev_iovar_getint(iter->ndev, "chanspec",
15551 (s32 *)&chanspec) == BCME_OK) {
15552 chanspec = wl_chspec_driver_to_host(chanspec);
15553 ctl_chan = wf_chspec_ctlchan(chanspec);
15554 wl_update_prof(cfg, iter->ndev, NULL,
15555 &ctl_chan, WL_PROF_CHAN);
15556 }
15557 if (!cfg->vsdb_mode) {
15558 if (!pre_ctl_chan && ctl_chan)
15559 pre_ctl_chan = ctl_chan;
15560 else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) {
15561 cfg->vsdb_mode = true;
15562 }
15563 }
15564 }
15565 }
15566 }
15567#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15568 4 && __GNUC_MINOR__ >= 6))
15569_Pragma("GCC diagnostic pop")
15570#endif
15571 printf("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel");
15572 return;
15573}
15574
15575#if defined(DISABLE_FRAMEBURST_VSDB) && defined(USE_WFA_CERT_CONF)
15576extern int g_frameburst;
15577#endif /* DISABLE_FRAMEBURST_VSDB && USE_WFA_CERT_CONF */
15578
15579static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
15580 enum wl_status state, bool set)
15581{
15582 s32 pm = PM_FAST;
15583 s32 err = BCME_OK;
15584 u32 mode;
15585 u32 chan = 0;
15586 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
15587 dhd_pub_t *dhd = cfg->pub;
15588#ifdef RTT_SUPPORT
15589 rtt_status_info_t *rtt_status;
15590#endif /* RTT_SUPPORT */
15591 if (dhd->busstate == DHD_BUS_DOWN) {
15592 WL_ERR(("%s : busstate is DHD_BUS_DOWN!\n", __FUNCTION__));
15593 return 0;
15594 }
15595 WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
15596 state, set, _net_info->pm_restore, _net_info->ndev->name));
15597
15598 if (state != WL_STATUS_CONNECTED)
15599 return 0;
15600 mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
15601 if (set) {
15602 wl_cfg80211_concurrent_roam(cfg, 1);
15603 wl_cfg80211_determine_vsdb_mode(cfg);
15604 if (mode == WL_MODE_AP) {
15605 if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
15606 WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
15607 }
15608 pm = PM_OFF;
15609 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
15610 sizeof(pm))) != 0) {
15611 if (err == -ENODEV)
15612 WL_DBG(("%s:netdev not ready\n",
15613 _net_info->ndev->name));
15614 else
15615 WL_ERR(("%s:error (%d)\n",
15616 _net_info->ndev->name, err));
15617
15618 wl_cfg80211_update_power_mode(_net_info->ndev);
15619 }
15620 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
15621
15622 } else { /* clear */
15623 chan = 0;
15624 /* clear chan information when the net device is disconnected */
15625 wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
15626 wl_cfg80211_determine_vsdb_mode(cfg);
15627 if (primary_dev == _net_info->ndev) {
15628 pm = PM_FAST;
15629#ifdef RTT_SUPPORT
15630 rtt_status = GET_RTTSTATE(dhd);
15631 if (rtt_status->status != RTT_ENABLED) {
15632#endif /* RTT_SUPPORT */
15633 if (dhd_conf_get_pm(dhd) >= 0)
15634 pm = dhd_conf_get_pm(dhd);
15635 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
15636 sizeof(pm))) != 0) {
15637 if (err == -ENODEV)
15638 WL_DBG(("%s:netdev not ready\n",
15639 _net_info->ndev->name));
15640 else
15641 WL_ERR(("%s:error (%d)\n",
15642 _net_info->ndev->name, err));
15643
15644 wl_cfg80211_update_power_mode(_net_info->ndev);
15645 }
15646#ifdef RTT_SUPPORT
ccd15baf 15647 }
010c3a89
RC
15648#endif /* RTT_SUPPORT */
15649 }
15650 wl_cfg80211_concurrent_roam(cfg, 0);
15651
15652 }
15653 return err;
15654}
d964ce36 15655
010c3a89
RC
15656static s32 wl_init_scan(struct bcm_cfg80211 *cfg)
15657{
15658 int err = 0;
15659
15660 cfg->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler;
15661 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
15662 wl_escan_init_sync_id(cfg);
15663
15664 /* Init scan_timeout timer */
d964ce36 15665#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
15666 timer_setup(&cfg->scan_timeout, wl_scan_timeout, 0);
15667#else
010c3a89
RC
15668 init_timer(&cfg->scan_timeout);
15669 cfg->scan_timeout.data = (unsigned long) cfg;
15670 cfg->scan_timeout.function = wl_scan_timeout;
d964ce36 15671#endif
010c3a89
RC
15672
15673 return err;
15674}
15675
15676#ifdef DHD_LOSSLESS_ROAMING
15677static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
15678{
15679 int err = 0;
15680
15681 /* Init roam timer */
d964ce36 15682#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
15683 timer_setup(&cfg->roam_timeout, wl_roam_timeout, 0);
15684#else
010c3a89
RC
15685 init_timer(&cfg->roam_timeout);
15686 cfg->roam_timeout.data = (unsigned long) cfg;
15687 cfg->roam_timeout.function = wl_roam_timeout;
d964ce36 15688#endif
010c3a89
RC
15689
15690 return err;
15691}
15692#endif /* DHD_LOSSLESS_ROAMING */
15693
15694static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
15695{
15696 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15697 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
15698 s32 err = 0;
15699
15700 cfg->scan_request = NULL;
15701 cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
15702#ifdef DISABLE_BUILTIN_ROAM
15703 cfg->roam_on = false;
15704#else
15705 cfg->roam_on = true;
15706#endif /* DISABLE_BUILTIN_ROAM */
15707 cfg->active_scan = true;
15708 cfg->rf_blocked = false;
15709 cfg->vsdb_mode = false;
dfb0f3ae 15710#if defined(BCMSDIO) || defined(BCMDBUS)
010c3a89 15711 cfg->wlfc_on = false;
dfb0f3ae 15712#endif /* BCMSDIO || BCMDBUS */
010c3a89
RC
15713 cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
15714 cfg->disable_roam_event = false;
15715 /* register interested state */
15716 set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
15717 spin_lock_init(&cfg->cfgdrv_lock);
15718 mutex_init(&cfg->ioctl_buf_sync);
15719 init_waitqueue_head(&cfg->netif_change_event);
32c27b7a 15720 init_waitqueue_head(&cfg->wps_done_event);
010c3a89
RC
15721 init_completion(&cfg->send_af_done);
15722 init_completion(&cfg->iface_disable);
010c3a89
RC
15723 mutex_init(&cfg->usr_sync);
15724 mutex_init(&cfg->event_sync);
15725 mutex_init(&cfg->scan_complete);
15726 mutex_init(&cfg->if_sync);
1ebe56b2 15727 mutex_init(&cfg->pm_sync);
32c27b7a 15728 mutex_init(&cfg->in4way_sync);
010c3a89
RC
15729#ifdef WLTDLS
15730 mutex_init(&cfg->tdls_sync);
15731#endif /* WLTDLS */
1ebe56b2
RC
15732 wl_init_eq(cfg);
15733 err = wl_init_priv_mem(cfg);
15734 if (err)
15735 return err;
15736 if (wl_create_event_handler(cfg))
15737 return -ENOMEM;
15738 wl_init_event_handler(cfg);
010c3a89
RC
15739 err = wl_init_scan(cfg);
15740 if (err)
15741 return err;
15742#ifdef DHD_LOSSLESS_ROAMING
15743 err = wl_init_roam_timeout(cfg);
15744 if (err) {
15745 return err;
15746 }
15747#endif /* DHD_LOSSLESS_ROAMING */
15748 wl_init_conf(cfg->conf);
15749 wl_init_prof(cfg, ndev);
15750 wl_link_down(cfg);
15751 DNGL_FUNC(dhd_cfg80211_init, (cfg));
15752#ifdef NAN_DP
15753 cfg->nan_dp_state = NAN_DP_STATE_DISABLED;
15754 init_waitqueue_head(&cfg->ndp_if_change_event);
15755#endif /* NAN_DP */
15756 return err;
15757}
15758
15759static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
15760{
15761 DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
15762 wl_destroy_event_handler(cfg);
15763 wl_flush_eq(cfg);
15764 wl_link_down(cfg);
1ebe56b2
RC
15765 if (cfg->scan_timeout.function)
15766 del_timer_sync(&cfg->scan_timeout);
010c3a89 15767#ifdef DHD_LOSSLESS_ROAMING
1ebe56b2
RC
15768 if (cfg->roam_timeout.function)
15769 del_timer_sync(&cfg->roam_timeout);
010c3a89
RC
15770#endif
15771 wl_deinit_priv_mem(cfg);
15772 if (wl_cfg80211_netdev_notifier_registered) {
15773 wl_cfg80211_netdev_notifier_registered = FALSE;
15774 unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
15775 }
15776}
15777
15778#if defined(WL_ENABLE_P2P_IF)
15779static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
15780{
15781 WL_TRACE(("Enter \n"));
15782
15783 if (wl_cfgp2p_register_ndev(cfg) < 0) {
15784 WL_ERR(("P2P attach failed. \n"));
15785 return -ENODEV;
15786 }
15787
15788 return 0;
15789}
15790
15791static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
15792{
15793 struct wireless_dev *wdev;
15794
15795 WL_DBG(("Enter \n"));
15796 if (!cfg) {
15797 WL_ERR(("Invalid Ptr\n"));
15798 return -EINVAL;
15799 }
15800 else {
15801 wdev = cfg->p2p_wdev;
15802 if (!wdev) {
15803 WL_ERR(("Invalid Ptr\n"));
15804 return -EINVAL;
15805 }
15806 }
15807
15808 wl_cfgp2p_unregister_ndev(cfg);
15809
15810 cfg->p2p_wdev = NULL;
15811 cfg->p2p_net = NULL;
15812 WL_DBG(("Freeing 0x%p \n", wdev));
15813 kfree(wdev);
15814
15815 return 0;
15816}
15817#endif
15818
15819static s32 wl_cfg80211_attach_post(struct net_device *ndev)
15820{
15821 struct bcm_cfg80211 * cfg;
15822 s32 err = 0;
15823 s32 ret = 0;
15824 WL_TRACE(("In\n"));
15825 if (unlikely(!ndev)) {
15826 WL_ERR(("ndev is invaild\n"));
15827 return -ENODEV;
15828 }
15829 cfg = wl_get_cfg(ndev);
15830 if (unlikely(!cfg)) {
15831 WL_ERR(("cfg is invaild\n"));
15832 return -EINVAL;
15833 }
15834 if (!wl_get_drv_status(cfg, READY, ndev)) {
15835 if (cfg->wdev) {
15836 ret = wl_cfgp2p_supported(cfg, ndev);
15837 if (ret > 0) {
15838#if !defined(WL_ENABLE_P2P_IF)
15839 cfg->wdev->wiphy->interface_modes |=
15840 (BIT(NL80211_IFTYPE_P2P_CLIENT)|
15841 BIT(NL80211_IFTYPE_P2P_GO));
15842#endif /* !WL_ENABLE_P2P_IF */
15843 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
15844 goto fail;
15845
15846#if defined(WL_ENABLE_P2P_IF)
15847 if (cfg->p2p_net) {
15848 /* Update MAC addr for p2p0 interface here. */
15849 memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
15850 cfg->p2p_net->dev_addr[0] |= 0x02;
15851 printf("%s: p2p_dev_addr="MACDBG "\n",
15852 cfg->p2p_net->name,
15853 MAC2STRDBG(cfg->p2p_net->dev_addr));
15854 } else {
15855 WL_ERR(("p2p_net not yet populated."
15856 " Couldn't update the MAC Address for p2p0 \n"));
15857 return -ENODEV;
15858 }
15859#endif /* WL_ENABLE_P2P_IF */
15860 cfg->p2p_supported = true;
15861 } else if (ret == 0) {
15862 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
15863 goto fail;
15864 } else {
15865 /* SDIO bus timeout */
15866 err = -ENODEV;
15867 goto fail;
15868 }
15869 }
15870 }
15871 wl_set_drv_status(cfg, READY, ndev);
15872fail:
15873 return err;
15874}
15875
15876struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev)
15877{
15878 struct wireless_dev *wdev = ndev->ieee80211_ptr;
15879
1ebe56b2 15880 if (!wdev || !wdev->wiphy)
010c3a89
RC
15881 return NULL;
15882
15883 return wiphy_priv(wdev->wiphy);
15884}
15885
15886s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
15887{
15888 struct wireless_dev *wdev;
15889 struct bcm_cfg80211 *cfg;
15890 s32 err = 0;
15891 struct device *dev;
15892
15893 WL_TRACE(("In\n"));
15894 if (!ndev) {
15895 WL_ERR(("ndev is invaild\n"));
15896 return -ENODEV;
15897 }
15898 WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
15899 dev = wl_cfg80211_get_parent_dev();
15900
15901 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
15902 if (unlikely(!wdev)) {
15903 WL_ERR(("Could not allocate wireless device\n"));
15904 return -ENOMEM;
15905 }
15906 err = wl_setup_wiphy(wdev, dev, context);
15907 if (unlikely(err)) {
15908 kfree(wdev);
15909 return -ENOMEM;
15910 }
dfb0f3ae
RC
15911#ifdef WLMESH
15912 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_MESH);
15913#else
010c3a89 15914 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
dfb0f3ae 15915#endif
010c3a89
RC
15916 cfg = wiphy_priv(wdev->wiphy);
15917 cfg->wdev = wdev;
15918 cfg->pub = context;
15919 INIT_LIST_HEAD(&cfg->net_list);
15920#ifdef WBTEXT
15921 INIT_LIST_HEAD(&cfg->wbtext_bssid_list);
15922#endif /* WBTEXT */
15923 INIT_LIST_HEAD(&cfg->vndr_oui_list);
15924 spin_lock_init(&cfg->net_list_sync);
15925 ndev->ieee80211_ptr = wdev;
15926 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
15927 wdev->netdev = ndev;
15928 cfg->state_notifier = wl_notifier_change_state;
1ebe56b2 15929 err = wl_init_priv(cfg);
010c3a89 15930 if (err) {
1ebe56b2 15931 WL_ERR(("Failed to init iwm_priv (%d)\n", err));
010c3a89
RC
15932 goto cfg80211_attach_out;
15933 }
1ebe56b2 15934 err = wl_alloc_netinfo(cfg, ndev, wdev, wdev->iftype, PM_ENABLE, 0);
010c3a89 15935 if (err) {
1ebe56b2 15936 WL_ERR(("Failed to alloc net_info (%d)\n", err));
010c3a89
RC
15937 goto cfg80211_attach_out;
15938 }
15939
15940 err = wl_setup_rfkill(cfg, TRUE);
15941 if (err) {
15942 WL_ERR(("Failed to setup rfkill %d\n", err));
15943 goto cfg80211_attach_out;
15944 }
15945#ifdef DEBUGFS_CFG80211
15946 err = wl_setup_debugfs(cfg);
15947 if (err) {
15948 WL_ERR(("Failed to setup debugfs %d\n", err));
15949 goto cfg80211_attach_out;
15950 }
15951#endif
15952 if (!wl_cfg80211_netdev_notifier_registered) {
15953 wl_cfg80211_netdev_notifier_registered = TRUE;
15954 err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
15955 if (err) {
15956 wl_cfg80211_netdev_notifier_registered = FALSE;
15957 WL_ERR(("Failed to register notifierl %d\n", err));
15958 goto cfg80211_attach_out;
15959 }
15960 }
15961#if defined(COEX_DHCP)
15962 cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
15963 if (!cfg->btcoex_info)
15964 goto cfg80211_attach_out;
15965#endif
15966#if defined(SUPPORT_RANDOM_MAC_SCAN)
15967 cfg->random_mac_enabled = FALSE;
15968#endif /* SUPPORT_RANDOM_MAC_SCAN */
15969
15970#ifdef CONFIG_CFG80211_INTERNAL_REGDB
15971 wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
15972#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
15973
15974#if defined(WL_ENABLE_P2P_IF)
15975 err = wl_cfg80211_attach_p2p(cfg);
15976 if (err)
15977 goto cfg80211_attach_out;
15978#endif
15979
15980 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
010c3a89
RC
15981
15982#if defined(STAT_REPORT)
15983 err = wl_attach_stat_report(cfg);
15984 if (err) {
15985 goto cfg80211_attach_out;
15986 }
15987#endif /* STAT_REPORT */
15988 return err;
15989
15990cfg80211_attach_out:
1ebe56b2 15991 wl_cfg80211_detach(cfg);
010c3a89
RC
15992 return err;
15993}
15994
15995void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
15996{
15997
15998 WL_TRACE(("In\n"));
15999 if (!cfg)
16000 return;
16001
16002 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
16003
16004#if defined(COEX_DHCP)
16005 wl_cfg80211_btcoex_deinit();
16006 cfg->btcoex_info = NULL;
16007#endif
16008
16009 wl_setup_rfkill(cfg, FALSE);
16010#ifdef DEBUGFS_CFG80211
16011 wl_free_debugfs(cfg);
16012#endif
16013 if (cfg->p2p_supported) {
16014 if (timer_pending(&cfg->p2p->listen_timer))
16015 del_timer_sync(&cfg->p2p->listen_timer);
16016 wl_cfgp2p_deinit_priv(cfg);
16017 }
16018
16019 if (timer_pending(&cfg->scan_timeout))
16020 del_timer_sync(&cfg->scan_timeout);
16021#ifdef DHD_LOSSLESS_ROAMING
16022 if (timer_pending(&cfg->roam_timeout)) {
16023 del_timer_sync(&cfg->roam_timeout);
16024 }
16025#endif /* DHD_LOSSLESS_ROAMING */
16026
16027#if defined(WL_CFG80211_P2P_DEV_IF)
16028 if (cfg->p2p_wdev)
16029 wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
16030#endif /* WL_CFG80211_P2P_DEV_IF */
16031#if defined(WL_ENABLE_P2P_IF)
16032 wl_cfg80211_detach_p2p(cfg);
16033#endif
16034#if defined(STAT_REPORT)
16035 wl_detach_stat_report(cfg);
16036#endif /* STAT_REPORT */
16037
16038 wl_cfg80211_ibss_vsie_free(cfg);
16039 wl_cfg80211_clear_mgmt_vndr_ies(cfg);
16040 wl_deinit_priv(cfg);
16041 wl_cfg80211_clear_parent_dev();
010c3a89 16042#if defined(RSSIAVG)
d964ce36 16043 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
16044 wl_free_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
010c3a89
RC
16045#endif
16046#if defined(BSSCACHE)
d964ce36 16047 wl_release_bss_cache_ctrl(&cfg->g_bss_cache_ctrl);
010c3a89 16048#endif
d964ce36 16049 wl_free_wdev(cfg);
010c3a89
RC
16050 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
16051 * structure "cfg", which is the private part of wiphy, has been freed in
16052 * wl_free_wdev !!!!!!!!!!!
16053 */
16054}
16055
16056static void wl_event_handler(struct work_struct *work_data)
16057{
16058 struct bcm_cfg80211 *cfg = NULL;
16059 struct wl_event_q *e;
16060 struct wireless_dev *wdev = NULL;
16061
16062 BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
16063 DHD_EVENT_WAKE_LOCK(cfg->pub);
16064 while ((e = wl_deq_event(cfg))) {
16065 WL_DBG(("event type (%d), ifidx: %d bssidx: %d \n",
16066 e->etype, e->emsg.ifidx, e->emsg.bsscfgidx));
16067
16068 if (e->emsg.ifidx > WL_MAX_IFS) {
16069 WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
16070 goto fail;
16071 }
16072
16073 /* Make sure iface operations, don't creat race conditions */
16074 mutex_lock(&cfg->if_sync);
16075 if (!(wdev = wl_get_wdev_by_bssidx(cfg, e->emsg.bsscfgidx))) {
16076 /* For WLC_E_IF would be handled by wl_host_event */
16077 if (e->etype != WLC_E_IF)
16078 WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
16079 " Ignoring event.\n", e->emsg.bsscfgidx));
16080 } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
16081 dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
16082 if (dhd->busstate == DHD_BUS_DOWN) {
16083 WL_ERR((": BUS is DOWN.\n"));
16084 } else
16085 cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
16086 &e->emsg, e->edata);
16087 } else {
16088 WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
16089 }
16090 mutex_unlock(&cfg->if_sync);
16091fail:
16092 wl_put_event(e);
16093 }
16094 DHD_EVENT_WAKE_UNLOCK(cfg->pub);
16095}
16096
16097void
16098wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
16099{
16100 u32 event_type = ntoh32(e->event_type);
16101 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
16102 struct net_info *netinfo;
16103
16104 WL_DBG(("event_type (%d): %s\n", event_type, bcmevent_get_name(event_type)));
16105
16106 if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
16107 WL_ERR(("Stale event ignored\n"));
16108 return;
16109 }
16110
16111 if (cfg->event_workq == NULL) {
16112 WL_ERR(("Event handler is not created\n"));
16113 return;
16114 }
16115
16116 if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) {
16117 WL_ERR(("during IF change, ignore event %d\n", event_type));
16118 return;
16119 }
16120
16121 netinfo = wl_get_netinfo_by_bssidx(cfg, e->bsscfgidx);
16122 if (!netinfo) {
16123 /* Since the netinfo entry is not there, the netdev entry is not
16124 * created via cfg80211 interface. so the event is not of interest
16125 * to the cfg80211 layer.
16126 */
16127 WL_ERR(("ignore event %d, not interested\n", event_type));
16128 return;
16129 }
16130
16131 if (event_type == WLC_E_PFN_NET_FOUND) {
16132 WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
16133 }
16134 else if (event_type == WLC_E_PFN_NET_LOST) {
16135 WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
16136 }
16137
16138 if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
16139 queue_work(cfg->event_workq, &cfg->event_work);
16140 }
16141}
16142
16143static void wl_init_eq(struct bcm_cfg80211 *cfg)
16144{
16145 wl_init_eq_lock(cfg);
16146 INIT_LIST_HEAD(&cfg->eq_list);
16147}
16148
16149static void wl_flush_eq(struct bcm_cfg80211 *cfg)
16150{
16151 struct wl_event_q *e;
16152 unsigned long flags;
16153
16154 flags = wl_lock_eq(cfg);
16155 while (!list_empty_careful(&cfg->eq_list)) {
16156 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
16157 list_del(&e->eq_list);
16158 kfree(e);
16159 }
16160 wl_unlock_eq(cfg, flags);
16161}
16162
16163/*
16164* retrieve first queued event from head
16165*/
16166
16167static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
16168{
16169 struct wl_event_q *e = NULL;
16170 unsigned long flags;
16171
16172 flags = wl_lock_eq(cfg);
16173 if (likely(!list_empty(&cfg->eq_list))) {
16174 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
16175 list_del(&e->eq_list);
16176 }
16177 wl_unlock_eq(cfg, flags);
16178
16179 return e;
16180}
16181
16182/*
16183 * push event to tail of the queue
16184 */
16185
16186static s32
16187wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event,
16188 const wl_event_msg_t *msg, void *data)
16189{
16190 struct wl_event_q *e;
16191 s32 err = 0;
16192 uint32 evtq_size;
16193 uint32 data_len;
16194 unsigned long flags;
16195 gfp_t aflags;
16196
16197 data_len = 0;
16198 if (data)
16199 data_len = ntoh32(msg->datalen);
16200 evtq_size = sizeof(struct wl_event_q) + data_len;
16201 aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
16202 e = kzalloc(evtq_size, aflags);
16203 if (unlikely(!e)) {
16204 WL_ERR(("event alloc failed\n"));
16205 return -ENOMEM;
16206 }
16207 e->etype = event;
16208 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
16209 if (data)
16210 memcpy(e->edata, data, data_len);
16211 flags = wl_lock_eq(cfg);
16212 list_add_tail(&e->eq_list, &cfg->eq_list);
16213 wl_unlock_eq(cfg, flags);
16214
16215 return err;
16216}
16217
16218static void wl_put_event(struct wl_event_q *e)
16219{
16220 kfree(e);
16221}
16222
16223static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype)
16224{
16225 s32 infra = 0;
16226 s32 err = 0;
16227 s32 mode = 0;
16228 switch (iftype) {
16229 case NL80211_IFTYPE_MONITOR:
16230 case NL80211_IFTYPE_WDS:
16231 WL_ERR(("type (%d) : currently we do not support this mode\n",
16232 iftype));
16233 err = -EINVAL;
16234 return err;
16235 case NL80211_IFTYPE_ADHOC:
16236 mode = WL_MODE_IBSS;
16237 break;
16238 case NL80211_IFTYPE_STATION:
16239 case NL80211_IFTYPE_P2P_CLIENT:
16240 mode = WL_MODE_BSS;
16241 infra = 1;
16242 break;
dfb0f3ae
RC
16243#ifdef WLMESH
16244 case NL80211_IFTYPE_MESH_POINT:
16245 mode = WL_MODE_MESH;
16246 infra = WL_BSSTYPE_MESH;
16247 break;
16248#endif /* WLMESH */
010c3a89
RC
16249 case NL80211_IFTYPE_AP:
16250 case NL80211_IFTYPE_P2P_GO:
16251 mode = WL_MODE_AP;
16252 infra = 1;
16253 break;
16254 default:
16255 err = -EINVAL;
16256 WL_ERR(("invalid type (%d)\n", iftype));
16257 return err;
16258 }
16259 infra = htod32(infra);
16260 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
16261 if (unlikely(err)) {
16262 WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
16263 return err;
16264 }
16265
16266 wl_set_mode_by_netdev(cfg, ndev, mode);
16267
16268 return 0;
16269}
16270
16271void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set)
16272{
16273 if (!ev || (event > WLC_E_LAST))
16274 return;
16275
16276 if (ev->num < MAX_EVENT_BUF_NUM) {
16277 ev->event[ev->num].type = event;
16278 ev->event[ev->num].set = set;
16279 ev->num++;
16280 } else {
16281 WL_ERR(("evenbuffer doesn't support > %u events. Update"
16282 " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
16283 ASSERT(0);
16284 }
16285}
16286
16287s32 wl_cfg80211_apply_eventbuffer(
16288 struct net_device *ndev,
16289 struct bcm_cfg80211 *cfg,
16290 wl_eventmsg_buf_t *ev)
16291{
16292 char eventmask[WL_EVENTING_MASK_LEN];
16293 int i, ret = 0;
16294 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
16295
16296 if (!ev || (!ev->num))
16297 return -EINVAL;
16298
16299 mutex_lock(&cfg->event_sync);
16300
16301 /* Read event_msgs mask */
16302 ret = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
16303 if (unlikely(ret)) {
16304 WL_ERR(("Get event_msgs error (%d)\n", ret));
16305 goto exit;
16306 }
16307 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
16308
16309 /* apply the set bits */
16310 for (i = 0; i < ev->num; i++) {
16311 if (ev->event[i].set)
16312 setbit(eventmask, ev->event[i].type);
16313 else
16314 clrbit(eventmask, ev->event[i].type);
16315 }
16316
16317 /* Write updated Event mask */
16318 ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf,
16319 sizeof(iovbuf), NULL);
16320 if (unlikely(ret)) {
16321 WL_ERR(("Set event_msgs error (%d)\n", ret));
16322 }
16323
16324exit:
16325 mutex_unlock(&cfg->event_sync);
16326 return ret;
16327}
16328
16329s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
16330{
16331 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
16332 s8 eventmask[WL_EVENTING_MASK_LEN];
16333 s32 err = 0;
16334 struct bcm_cfg80211 *cfg;
16335
16336 if (!ndev)
16337 return -ENODEV;
16338
16339 cfg = wl_get_cfg(ndev);
16340 if (!cfg)
16341 return -ENODEV;
16342
16343 mutex_lock(&cfg->event_sync);
16344
16345 /* Setup event_msgs */
16346 err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
16347 if (unlikely(err)) {
16348 WL_ERR(("Get event_msgs error (%d)\n", err));
16349 goto eventmsg_out;
16350 }
16351 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
16352 if (add) {
16353 setbit(eventmask, event);
16354 } else {
16355 clrbit(eventmask, event);
16356 }
16357 err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
16358 sizeof(iovbuf), NULL);
16359 if (unlikely(err)) {
16360 WL_ERR(("Set event_msgs error (%d)\n", err));
16361 goto eventmsg_out;
16362 }
16363
16364eventmsg_out:
16365 mutex_unlock(&cfg->event_sync);
16366 return err;
16367}
16368
16369static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
16370{
16371 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
16372 struct ieee80211_channel *band_chan_arr = NULL;
16373 wl_uint32_list_t *list;
16374 u32 i, j, index, n_2g, n_5g, band, channel, array_size;
16375 u32 *n_cnt = NULL;
16376 chanspec_t c = 0;
16377 s32 err = BCME_OK;
16378 bool update;
16379 bool ht40_allowed;
16380 u8 *pbuf = NULL;
16381 bool dfs_radar_disabled = FALSE;
16382
16383#define LOCAL_BUF_LEN 1024
16384 pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL);
16385
16386 if (pbuf == NULL) {
16387 WL_ERR(("failed to allocate local buf\n"));
16388 return -ENOMEM;
16389 }
16390
16391 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
16392 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
16393 if (err != 0) {
16394 WL_ERR(("get chanspecs failed with %d\n", err));
16395 kfree(pbuf);
16396 return err;
16397 }
16398#undef LOCAL_BUF_LEN
16399
16400 list = (wl_uint32_list_t *)(void *)pbuf;
16401 band = array_size = n_2g = n_5g = 0;
16402 for (i = 0; i < dtoh32(list->count); i++) {
16403 index = 0;
16404 update = false;
16405 ht40_allowed = false;
16406 c = (chanspec_t)dtoh32(list->element[i]);
16407 c = wl_chspec_driver_to_host(c);
16408 channel = wf_chspec_ctlchan(c);
16409
16410 if (!CHSPEC_IS40(c) && ! CHSPEC_IS20(c)) {
16411 WL_DBG(("HT80/160/80p80 center channel : %d\n", channel));
16412 continue;
16413 }
16414 if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
16415 (channel <= CH_MAX_2G_CHANNEL)) {
16416 band_chan_arr = __wl_2ghz_channels;
16417 array_size = ARRAYSIZE(__wl_2ghz_channels);
16418 n_cnt = &n_2g;
16419 band = IEEE80211_BAND_2GHZ;
16420 ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false;
16421 } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
16422 band_chan_arr = __wl_5ghz_a_channels;
16423 array_size = ARRAYSIZE(__wl_5ghz_a_channels);
16424 n_cnt = &n_5g;
16425 band = IEEE80211_BAND_5GHZ;
16426 ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true;
16427 } else {
16428 WL_ERR(("Invalid channel Sepc. 0x%x.\n", c));
16429 continue;
16430 }
16431 if (!ht40_allowed && CHSPEC_IS40(c))
16432 continue;
16433 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
16434 if (band_chan_arr[j].hw_value == channel) {
16435 update = true;
16436 break;
16437 }
16438 }
16439 if (update)
16440 index = j;
16441 else
16442 index = *n_cnt;
16443 if (!dhd_conf_match_channel(cfg->pub, channel))
16444 continue;
16445 if (index < array_size) {
16446#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
16447 band_chan_arr[index].center_freq =
16448 ieee80211_channel_to_frequency(channel);
16449#else
16450 band_chan_arr[index].center_freq =
16451 ieee80211_channel_to_frequency(channel, band);
16452#endif
16453 band_chan_arr[index].hw_value = channel;
16454 band_chan_arr[index].beacon_found = false;
16455
16456 if (CHSPEC_IS40(c) && ht40_allowed) {
16457 /* assuming the order is HT20, HT40 Upper,
16458 * HT40 lower from chanspecs
16459 */
16460 u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
16461 if (CHSPEC_SB_UPPER(c)) {
16462 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
16463 band_chan_arr[index].flags &=
16464 ~IEEE80211_CHAN_NO_HT40;
16465 band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
16466 } else {
16467 /* It should be one of
16468 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
16469 */
16470 band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
16471 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
16472 band_chan_arr[index].flags |=
16473 IEEE80211_CHAN_NO_HT40MINUS;
16474 }
16475 } else {
16476 band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
16477 if (!dfs_radar_disabled) {
16478 if (band == IEEE80211_BAND_2GHZ)
16479 channel |= WL_CHANSPEC_BAND_2G;
16480 else
16481 channel |= WL_CHANSPEC_BAND_5G;
16482 channel |= WL_CHANSPEC_BW_20;
16483 channel = wl_chspec_host_to_driver(channel);
16484 err = wldev_iovar_getint(dev, "per_chan_info", &channel);
16485 if (!err) {
16486 if (channel & WL_CHAN_RADAR) {
16487#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
16488 band_chan_arr[index].flags |=
16489 (IEEE80211_CHAN_RADAR
16490 | IEEE80211_CHAN_NO_IBSS);
16491#else
16492 band_chan_arr[index].flags |=
16493 IEEE80211_CHAN_RADAR;
16494#endif
16495 }
16496
16497 if (channel & WL_CHAN_PASSIVE)
16498#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
16499 band_chan_arr[index].flags |=
16500 IEEE80211_CHAN_PASSIVE_SCAN;
16501#else
16502 band_chan_arr[index].flags |=
16503 IEEE80211_CHAN_NO_IR;
16504#endif
16505 } else if (err == BCME_UNSUPPORTED) {
16506 dfs_radar_disabled = TRUE;
16507 WL_ERR(("does not support per_chan_info\n"));
16508 }
16509 }
16510 }
16511 if (!update)
16512 (*n_cnt)++;
16513 }
16514
16515 }
16516 __wl_band_2ghz.n_channels = n_2g;
16517 __wl_band_5ghz_a.n_channels = n_5g;
16518 kfree(pbuf);
16519 return err;
16520}
16521
16522static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
16523{
16524 struct wiphy *wiphy;
16525 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
16526 u32 bandlist[3];
16527 u32 nband = 0;
16528 u32 i = 0;
16529 s32 err = 0;
16530 s32 index = 0;
16531 s32 nmode = 0;
16532#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
16533 u32 j = 0;
16534 s32 vhtmode = 0;
16535 s32 txstreams = 0;
16536 s32 rxstreams = 0;
16537 s32 ldpc_cap = 0;
16538 s32 stbc_rx = 0;
16539 s32 stbc_tx = 0;
16540 s32 txbf_bfe_cap = 0;
16541 s32 txbf_bfr_cap = 0;
16542#endif
16543 s32 bw_cap = 0;
16544 s32 cur_band = -1;
16545 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, };
16546
16547 memset(bandlist, 0, sizeof(bandlist));
16548 err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist,
16549 sizeof(bandlist));
16550 if (unlikely(err)) {
16551 WL_ERR(("error read bandlist (%d)\n", err));
16552 return err;
16553 }
16554 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band,
16555 sizeof(s32));
16556 if (unlikely(err)) {
16557 WL_ERR(("error (%d)\n", err));
16558 return err;
16559 }
16560
16561 err = wldev_iovar_getint(dev, "nmode", &nmode);
16562 if (unlikely(err)) {
16563 WL_ERR(("error reading nmode (%d)\n", err));
16564 }
16565
16566#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
16567 err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
16568 if (unlikely(err)) {
16569 WL_ERR(("error reading vhtmode (%d)\n", err));
16570 }
16571
16572 if (vhtmode) {
16573 err = wldev_iovar_getint(dev, "txstreams", &txstreams);
16574 if (unlikely(err)) {
16575 WL_ERR(("error reading txstreams (%d)\n", err));
16576 }
16577
16578 err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
16579 if (unlikely(err)) {
16580 WL_ERR(("error reading rxstreams (%d)\n", err));
16581 }
16582
16583 err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
16584 if (unlikely(err)) {
16585 WL_ERR(("error reading ldpc_cap (%d)\n", err));
16586 }
16587
16588 err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
16589 if (unlikely(err)) {
16590 WL_ERR(("error reading stbc_rx (%d)\n", err));
16591 }
16592
16593 err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
16594 if (unlikely(err)) {
16595 WL_ERR(("error reading stbc_tx (%d)\n", err));
16596 }
16597
16598 err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
16599 if (unlikely(err)) {
16600 WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
16601 }
16602
16603 err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
16604 if (unlikely(err)) {
16605 WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
16606 }
16607 }
16608#endif
16609
16610 /* For nmode and vhtmode check bw cap */
16611 if (nmode ||
16612#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
16613 vhtmode ||
16614#endif
16615 0) {
16616 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
16617 if (unlikely(err)) {
16618 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
16619 }
16620 }
16621
16622 err = wl_construct_reginfo(cfg, bw_cap);
16623 if (err) {
16624 WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
16625 if (err != BCME_UNSUPPORTED)
16626 return err;
16627 }
16628
16629 wiphy = bcmcfg_to_wiphy(cfg);
16630 nband = bandlist[0];
16631
16632 for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
16633 index = -1;
16634 if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
16635 bands[IEEE80211_BAND_5GHZ] =
16636 &__wl_band_5ghz_a;
16637 index = IEEE80211_BAND_5GHZ;
16638 if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
16639 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
16640
16641#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
16642 /* VHT capabilities. */
16643 if (vhtmode) {
16644 /* Supported */
16645 bands[index]->vht_cap.vht_supported = TRUE;
16646
16647 for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
16648 /* TX stream rates. */
16649 if (j <= txstreams) {
16650 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
16651 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
16652 } else {
16653 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
16654 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
16655 }
16656
16657 /* RX stream rates. */
16658 if (j <= rxstreams) {
16659 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
16660 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
16661 } else {
16662 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
16663 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
16664 }
16665 }
16666
16667
16668 /* Capabilities */
16669 /* 80 MHz is mandatory */
16670 bands[index]->vht_cap.cap |=
16671 IEEE80211_VHT_CAP_SHORT_GI_80;
16672
16673 if (WL_BW_CAP_160MHZ(bw_cap)) {
16674 bands[index]->vht_cap.cap |=
16675 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
16676 bands[index]->vht_cap.cap |=
16677 IEEE80211_VHT_CAP_SHORT_GI_160;
16678 }
16679
16680 bands[index]->vht_cap.cap |=
16681 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
16682
16683 if (ldpc_cap)
16684 bands[index]->vht_cap.cap |=
16685 IEEE80211_VHT_CAP_RXLDPC;
16686
16687 if (stbc_tx)
16688 bands[index]->vht_cap.cap |=
16689 IEEE80211_VHT_CAP_TXSTBC;
16690
16691 if (stbc_rx)
16692 bands[index]->vht_cap.cap |=
16693 (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
16694
16695 if (txbf_bfe_cap)
16696 bands[index]->vht_cap.cap |=
16697 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
16698
16699 if (txbf_bfr_cap) {
16700 bands[index]->vht_cap.cap |=
16701 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
16702 }
16703
16704 if (txbf_bfe_cap || txbf_bfr_cap) {
16705 bands[index]->vht_cap.cap |=
16706 (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
16707 bands[index]->vht_cap.cap |=
16708 ((txstreams - 1) <<
16709 VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
16710 bands[index]->vht_cap.cap |=
16711 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
16712 }
16713
16714 /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
16715 bands[index]->vht_cap.cap |=
16716 (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
16717 WL_INFORM(("%s band[%d] vht_enab=%d vht_cap=%08x "
16718 "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
16719 __FUNCTION__, index,
16720 bands[index]->vht_cap.vht_supported,
16721 bands[index]->vht_cap.cap,
16722 bands[index]->vht_cap.vht_mcs.rx_mcs_map,
16723 bands[index]->vht_cap.vht_mcs.tx_mcs_map));
16724 }
16725#endif
16726 }
16727 else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
16728 bands[IEEE80211_BAND_2GHZ] =
16729 &__wl_band_2ghz;
16730 index = IEEE80211_BAND_2GHZ;
16731 if (bw_cap == WLC_N_BW_40ALL)
16732 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
16733 }
16734
16735 if ((index >= 0) && nmode) {
16736 bands[index]->ht_cap.cap |=
16737 (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
16738 bands[index]->ht_cap.ht_supported = TRUE;
16739 bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
16740 bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
16741 /* An HT shall support all EQM rates for one spatial stream */
16742 bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
16743 }
16744
16745 }
16746
16747 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
16748 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
16749
16750 /* check if any bands populated otherwise makes 2Ghz as default */
16751 if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL &&
16752 wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) {
16753 /* Setup 2Ghz band as default */
16754 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
16755 }
16756
16757 if (notify)
16758 wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
16759
16760 return 0;
16761}
16762
16763s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
16764{
16765 s32 err;
16766
16767 mutex_lock(&cfg->usr_sync);
16768 err = __wl_update_wiphybands(cfg, notify);
16769 mutex_unlock(&cfg->usr_sync);
16770
16771 return err;
16772}
16773
16774static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
16775{
16776 s32 err = 0;
16777 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
16778 struct wireless_dev *wdev = ndev->ieee80211_ptr;
16779#ifdef WBTEXT
16780 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
16781#endif /* WBTEXT */
16782#ifdef WLTDLS
16783 u32 tdls;
16784#endif /* WLTDLS */
16785
16786 WL_DBG(("In\n"));
16787
1ebe56b2
RC
16788 if (!dhd_download_fw_on_driverload) {
16789 err = wl_create_event_handler(cfg);
16790 if (err) {
16791 WL_ERR(("wl_create_event_handler failed\n"));
16792 return err;
16793 }
16794 wl_init_event_handler(cfg);
010c3a89 16795 }
010c3a89
RC
16796
16797 err = dhd_config_dongle(cfg);
16798 if (unlikely(err))
16799 return err;
16800
16801 err = wl_config_ifmode(cfg, ndev, wdev->iftype);
16802 if (unlikely(err && err != -EINPROGRESS)) {
16803 WL_ERR(("wl_config_ifmode failed\n"));
16804 if (err == -1) {
16805 WL_ERR(("return error %d\n", err));
16806 return err;
16807 }
16808 }
16809
16810 err = wl_init_scan(cfg);
16811 if (err) {
16812 WL_ERR(("wl_init_scan failed\n"));
16813 return err;
16814 }
16815 err = __wl_update_wiphybands(cfg, true);
16816 if (unlikely(err)) {
16817 WL_ERR(("wl_update_wiphybands failed\n"));
16818 if (err == -1) {
16819 WL_ERR(("return error %d\n", err));
16820 return err;
16821 }
16822 }
1ebe56b2 16823
010c3a89
RC
16824#ifdef DHD_LOSSLESS_ROAMING
16825 if (timer_pending(&cfg->roam_timeout)) {
16826 del_timer_sync(&cfg->roam_timeout);
16827 }
16828#endif /* DHD_LOSSLESS_ROAMING */
16829
16830 err = dhd_monitor_init(cfg->pub);
16831
16832#ifdef WBTEXT
16833 /* when wifi up, set roam_prof to default value */
16834 if (dhd->wbtext_support) {
16835 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
16836 wl_cfg80211_wbtext_set_default(ndev);
16837 wl_cfg80211_wbtext_clear_bssid_list(cfg);
16838 }
16839 }
16840#endif /* WBTEXT */
16841#ifdef WLTDLS
16842 if (wldev_iovar_getint(ndev, "tdls_enable", &tdls) == 0) {
16843 WL_DBG(("TDLS supported in fw\n"));
16844 cfg->tdls_supported = true;
16845 }
16846#endif /* WLTDLS */
16847 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
16848 wl_set_drv_status(cfg, READY, ndev);
16849 return err;
16850}
16851
16852static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
16853{
16854 s32 err = 0;
16855 unsigned long flags;
16856 struct net_info *iter, *next;
16857 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
010c3a89
RC
16858#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
16859 defined(WL_NEW_CFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
16860 struct net_device *p2p_net = cfg->p2p_net;
16861#endif
16862#ifdef PROP_TXSTATUS_VSDB
dfb0f3ae 16863#if defined(BCMSDIO) || defined(BCMDBUS)
010c3a89 16864 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
dfb0f3ae 16865#endif /* BCMSDIO || BCMDBUS */
010c3a89 16866#endif /* PROP_TXSTATUS_VSDB */
ccd15baf
RC
16867#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
16868 struct cfg80211_scan_info info;
16869#endif
16870
010c3a89
RC
16871 WL_DBG(("In\n"));
16872
16873 /* Check if cfg80211 interface is already down */
16874 if (!wl_get_drv_status(cfg, READY, ndev)) {
16875 WL_DBG(("cfg80211 interface is already down\n"));
16876 return err; /* it is even not ready */
16877 }
16878
16879#ifdef WLTDLS
16880 cfg->tdls_supported = false;
16881#endif /* WLTDLS */
16882
16883 /* Delete pm_enable_work */
16884 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
16885
16886 /* clear all the security setting on primary Interface */
16887 wl_cfg80211_clear_security(cfg);
16888
16889
16890 if (cfg->p2p_supported) {
16891 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
16892#ifdef PROP_TXSTATUS_VSDB
dfb0f3ae 16893#if defined(BCMSDIO) || defined(BCMDBUS)
010c3a89
RC
16894 if (wl_cfgp2p_vif_created(cfg)) {
16895 bool enabled = false;
16896 dhd_wlfc_get_enable(dhd, &enabled);
16897 if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
16898 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
16899 dhd_wlfc_deinit(dhd);
16900 cfg->wlfc_on = false;
16901 }
16902 }
dfb0f3ae 16903#endif /* BCMSDIO || BCMDBUS */
010c3a89
RC
16904#endif /* PROP_TXSTATUS_VSDB */
16905 }
16906
16907
16908 /* clean up any left over interfaces */
16909 wl_cfg80211_cleanup_virtual_ifaces(ndev, false);
16910
16911 /* If primary BSS is operational (for e.g SoftAP), bring it down */
16912 if (wl_cfg80211_bss_isup(ndev, 0)) {
16913 if (wl_cfg80211_bss_up(cfg, ndev, 0, 0) < 0)
16914 WL_ERR(("BSS down failed \n"));
16915 }
16916
16917#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
16918 4 && __GNUC_MINOR__ >= 6))
16919_Pragma("GCC diagnostic push")
16920_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
16921#endif
16922 for_each_ndev(cfg, iter, next) {
16923 if (iter->ndev) /* p2p discovery iface is null */
16924 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
16925 }
16926#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
16927 4 && __GNUC_MINOR__ >= 6))
16928_Pragma("GCC diagnostic pop")
16929#endif
16930
16931#ifdef P2P_LISTEN_OFFLOADING
16932 wl_cfg80211_p2plo_deinit(cfg);
16933#endif /* P2P_LISTEN_OFFLOADING */
16934
16935 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
16936 if (cfg->scan_request) {
16937#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
16938 info.aborted = true;
16939 cfg80211_scan_done(cfg->scan_request, &info);
16940#else
16941 cfg80211_scan_done(cfg->scan_request, true);
16942#endif
16943 cfg->scan_request = NULL;
16944 }
16945 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
16946#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
16947 4 && __GNUC_MINOR__ >= 6))
16948_Pragma("GCC diagnostic push")
16949_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
16950#endif
16951 for_each_ndev(cfg, iter, next) {
16952 /* p2p discovery iface ndev ptr could be null */
16953 if (iter->ndev == NULL)
16954 continue;
16955#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
16956 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
16957 CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
16958 }
16959#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
16960 wl_clr_drv_status(cfg, READY, iter->ndev);
16961 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
16962 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
16963 wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
16964 wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
16965 wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
16966 wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
16967 wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
16968 }
16969#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
16970 4 && __GNUC_MINOR__ >= 6))
16971_Pragma("GCC diagnostic pop")
16972#endif
16973 bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
16974 NL80211_IFTYPE_STATION;
16975#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
16976 defined(WL_NEW_CFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
16977 if (p2p_net)
16978 dev_close(p2p_net);
16979#endif
16980
16981 /* Avoid deadlock from wl_cfg80211_down */
16982 if (!dhd_download_fw_on_driverload) {
16983 mutex_unlock(&cfg->usr_sync);
16984 wl_destroy_event_handler(cfg);
16985 mutex_lock(&cfg->usr_sync);
16986 }
16987
16988 wl_flush_eq(cfg);
010c3a89 16989 if (cfg->link_up) { //army fix wifi stop call trace issue
d964ce36 16990 CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
16991 wl_link_down(cfg);
16992 }
010c3a89
RC
16993 if (cfg->p2p_supported) {
16994 if (timer_pending(&cfg->p2p->listen_timer))
16995 del_timer_sync(&cfg->p2p->listen_timer);
16996 wl_cfgp2p_down(cfg);
16997 }
16998
16999 if (timer_pending(&cfg->scan_timeout)) {
17000 del_timer_sync(&cfg->scan_timeout);
17001 }
17002
17003 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
17004
17005 dhd_monitor_uninit();
17006#ifdef WLAIBSS_MCHAN
17007 bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
17008#endif /* WLAIBSS_MCHAN */
17009
17010
17011#ifdef WL11U
17012 /* Clear interworking element. */
17013 if (cfg->wl11u) {
17014 cfg->wl11u = FALSE;
17015 }
17016#endif /* WL11U */
17017
17018#ifdef CUSTOMER_HW4_DEBUG
17019 if (wl_scan_timeout_dbg_enabled) {
17020 wl_scan_timeout_dbg_clear();
17021 }
17022#endif /* CUSTOMER_HW4_DEBUG */
17023
17024 cfg->disable_roam_event = false;
17025
17026 DNGL_FUNC(dhd_cfg80211_down, (cfg));
17027
17028#ifdef DHD_IFDEBUG
17029 /* Printout all netinfo entries */
17030 wl_probe_wdev_all(cfg);
17031#endif /* DHD_IFDEBUG */
17032
17033 return err;
17034}
17035
17036s32 wl_cfg80211_up(struct net_device *net)
17037{
17038 struct bcm_cfg80211 *cfg;
17039 s32 err = 0;
17040 int val = 1;
17041 dhd_pub_t *dhd;
17042#ifdef DISABLE_PM_BCNRX
17043 s32 interr = 0;
17044 uint param = 0;
17045 s8 iovbuf[WLC_IOCTL_SMLEN];
17046#endif /* DISABLE_PM_BCNRX */
17047
17048 WL_DBG(("In\n"));
17049 cfg = wl_get_cfg(net);
17050
17051 if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
17052 sizeof(int)) < 0)) {
17053 WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
17054 return err;
17055 }
17056 val = dtoh32(val);
17057 if (val != WLC_IOCTL_VERSION && val != 1) {
17058 WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
17059 val, WLC_IOCTL_VERSION));
17060 return BCME_VERSION;
17061 }
17062 ioctl_version = val;
32c27b7a
RC
17063 wl_cfg80211_check_in4way(cfg, net, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
17064 WL_EXT_STATUS_DISCONNECTED, NULL);
010c3a89
RC
17065 WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
17066
17067 mutex_lock(&cfg->usr_sync);
17068 dhd = (dhd_pub_t *)(cfg->pub);
17069 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
17070 err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
17071 if (unlikely(err)) {
17072 mutex_unlock(&cfg->usr_sync);
17073 return err;
17074 }
17075 }
dfb0f3ae
RC
17076#ifdef WLMESH
17077 cfg->wdev->wiphy->features |= NL80211_FEATURE_USERSPACE_MPM;
17078#endif /* WLMESH */
17079
010c3a89
RC
17080 err = __wl_cfg80211_up(cfg);
17081 if (unlikely(err))
17082 WL_ERR(("__wl_cfg80211_up failed\n"));
17083
17084
17085
17086 /* IOVAR configurations with 'up' condition */
17087#ifdef DISABLE_PM_BCNRX
17088 interr = wldev_iovar_setbuf(bcmcfg_to_prmry_ndev(cfg), "pm_bcnrx", (char *)&param,
17089 sizeof(param), iovbuf, sizeof(iovbuf), NULL);
17090 if (unlikely(interr)) {
17091 WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
17092 }
17093#endif /* DISABLE_PM_BCNRX */
17094
17095 mutex_unlock(&cfg->usr_sync);
17096
17097#ifdef WLAIBSS_MCHAN
17098 bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
17099#endif /* WLAIBSS_MCHAN */
17100
17101#ifdef DUAL_STA_STATIC_IF
17102#ifdef WL_VIRTUAL_APSTA
17103#error "Both DUAL STA and DUAL_STA_STATIC_IF can't be enabled together"
17104#endif
17105 /* Static Interface support is currently supported only for STA only builds (without P2P) */
17106 wl_cfg80211_create_iface(cfg->wdev->wiphy, NL80211_IFTYPE_STATION, NULL, "wlan%d");
17107#endif /* DUAL_STA_STATIC_IF */
17108
17109 return err;
17110}
17111
17112/* Private Event to Supplicant with indication that chip hangs */
17113int wl_cfg80211_hang(struct net_device *dev, u16 reason)
17114{
17115 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17116 dhd_pub_t *dhd;
17117#if defined(SOFTAP_SEND_HANGEVT)
17118 /* specifc mac address used for hang event */
17119 uint8 hang_mac[ETHER_ADDR_LEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
17120#endif /* SOFTAP_SEND_HANGEVT */
17121 if (!cfg) {
17122 return BCME_ERROR;
17123 }
17124
17125 dhd = (dhd_pub_t *)(cfg->pub);
17126#if defined(DHD_HANG_SEND_UP_TEST)
17127 if (dhd->req_hang_type) {
17128 WL_ERR(("%s, Clear HANG test request 0x%x\n",
17129 __FUNCTION__, dhd->req_hang_type));
17130 dhd->req_hang_type = 0;
17131 }
17132#endif /* DHD_HANG_SEND_UP_TEST */
17133 if ((dhd->hang_reason <= HANG_REASON_MASK) || (dhd->hang_reason >= HANG_REASON_MAX)) {
17134 WL_ERR(("%s, Invalid hang reason 0x%x\n",
17135 __FUNCTION__, dhd->hang_reason));
17136 dhd->hang_reason = HANG_REASON_UNKNOWN;
17137 }
17138#ifdef DHD_USE_EXTENDED_HANG_REASON
17139 if (dhd->hang_reason != 0) {
17140 reason = dhd->hang_reason;
17141 }
17142#endif /* DHD_USE_EXTENDED_HANG_REASON */
17143 WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32)(dhd->hang_reason)));
17144
17145 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
17146#ifdef SOFTAP_SEND_HANGEVT
17147 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
17148 cfg80211_del_sta(dev, hang_mac, GFP_ATOMIC);
17149 } else
17150#endif /* SOFTAP_SEND_HANGEVT */
17151 {
17152 CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
17153 }
17154#if defined(RSSIAVG)
d964ce36 17155 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
010c3a89
RC
17156#endif
17157#if defined(BSSCACHE)
d964ce36 17158 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
010c3a89
RC
17159#endif
17160 if (cfg != NULL) {
17161 wl_link_down(cfg);
17162 }
17163 return 0;
17164}
17165
17166s32 wl_cfg80211_down(struct net_device *dev)
17167{
1ebe56b2 17168 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
50b75717 17169 s32 err = 0;
010c3a89
RC
17170
17171 WL_DBG(("In\n"));
7ea3210f
RC
17172 if (cfg == NULL)
17173 return err;
010c3a89
RC
17174 mutex_lock(&cfg->usr_sync);
17175#if defined(RSSIAVG)
d964ce36 17176 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
010c3a89
RC
17177#endif
17178#if defined(BSSCACHE)
d964ce36 17179 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
010c3a89
RC
17180#endif
17181 err = __wl_cfg80211_down(cfg);
17182 mutex_unlock(&cfg->usr_sync);
17183
17184 return err;
17185}
17186
17187static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
17188{
17189 unsigned long flags;
17190 void *rptr = NULL;
17191 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
17192
17193 if (!profile)
17194 return NULL;
17195 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
17196 switch (item) {
17197 case WL_PROF_SEC:
17198 rptr = &profile->sec;
17199 break;
17200 case WL_PROF_ACT:
17201 rptr = &profile->active;
17202 break;
17203 case WL_PROF_BSSID:
17204 rptr = profile->bssid;
17205 break;
17206 case WL_PROF_SSID:
17207 rptr = &profile->ssid;
17208 break;
17209 case WL_PROF_CHAN:
17210 rptr = &profile->channel;
17211 break;
17212 }
17213 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
17214 if (!rptr)
17215 WL_ERR(("invalid item (%d)\n", item));
17216 return rptr;
17217}
17218
17219static s32
17220wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
17221 const wl_event_msg_t *e, const void *data, s32 item)
17222{
17223 s32 err = 0;
17224 const struct wlc_ssid *ssid;
17225 unsigned long flags;
17226 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
17227
17228 if (!profile)
17229 return WL_INVALID;
17230 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
17231 switch (item) {
17232 case WL_PROF_SSID:
17233 ssid = (const wlc_ssid_t *) data;
17234 memset(profile->ssid.SSID, 0,
17235 sizeof(profile->ssid.SSID));
17236 profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
17237 memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
17238 break;
17239 case WL_PROF_BSSID:
17240 if (data)
17241 memcpy(profile->bssid, data, ETHER_ADDR_LEN);
17242 else
17243 memset(profile->bssid, 0, ETHER_ADDR_LEN);
17244 break;
17245 case WL_PROF_SEC:
17246 memcpy(&profile->sec, data, sizeof(profile->sec));
17247 break;
17248 case WL_PROF_ACT:
17249 profile->active = *(const bool *)data;
17250 break;
17251 case WL_PROF_BEACONINT:
17252 profile->beacon_interval = *(const u16 *)data;
17253 break;
17254 case WL_PROF_DTIMPERIOD:
17255 profile->dtim_period = *(const u8 *)data;
17256 break;
17257 case WL_PROF_CHAN:
17258 profile->channel = *(const u32*)data;
17259 break;
17260 default:
17261 err = -EOPNOTSUPP;
17262 break;
17263 }
17264 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
17265
17266 if (err == -EOPNOTSUPP)
17267 WL_ERR(("unsupported item (%d)\n", item));
17268
17269 return err;
17270}
17271
17272void wl_cfg80211_dbg_level(u32 level)
17273{
17274 /*
17275 * prohibit to change debug level
17276 * by insmod parameter.
17277 * eventually debug level will be configured
17278 * in compile time by using CONFIG_XXX
17279 */
17280 /* wl_dbg_level = level; */
17281}
17282
17283static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev)
17284{
17285 return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS;
17286}
17287
17288static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
17289{
17290 return cfg->ibss_starter;
17291}
17292
17293static void wl_rst_ie(struct bcm_cfg80211 *cfg)
17294{
17295 struct wl_ie *ie = wl_to_ie(cfg);
17296
17297 ie->offset = 0;
17298}
17299
17300static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
17301{
17302 struct wl_ie *ie = wl_to_ie(cfg);
17303 s32 err = 0;
17304
17305 if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
17306 WL_ERR(("ei crosses buffer boundary\n"));
17307 return -ENOSPC;
17308 }
17309 ie->buf[ie->offset] = t;
17310 ie->buf[ie->offset + 1] = l;
17311 memcpy(&ie->buf[ie->offset + 2], v, l);
17312 ie->offset += l + 2;
17313
17314 return err;
17315}
17316
17317static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, const u8 *ie_stream, u32 *ie_size,
17318 bool roam)
17319{
17320 u8 *ssidie;
17321 int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN);
17322 int32 remaining_ie_buf_len, available_buffer_len;
17323 /* cfg80211_find_ie defined in kernel returning const u8 */
17324#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17325 4 && __GNUC_MINOR__ >= 6))
17326_Pragma("GCC diagnostic push")
17327_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
17328#endif
17329 ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
17330#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17331 4 && __GNUC_MINOR__ >= 6))
17332_Pragma("GCC diagnostic pop")
17333#endif
17334 /* ERROR out if
17335 * 1. No ssid IE is FOUND or
17336 * 2. New ssid length is > what was allocated for existing ssid (as
17337 * we do not want to overwrite the rest of the IEs) or
17338 * 3. If in case of erroneous buffer input where ssid length doesnt match the space
17339 * allocated to it.
17340 */
17341 if (!ssidie) {
17342 return;
17343 }
17344 available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream);
17345 remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
17346 if ((ssid_len > ssidie[1]) ||
17347 (ssidie[1] > available_buffer_len)) {
17348 return;
17349 }
17350
17351
17352 if (ssidie[1] != ssid_len) {
17353 if (ssidie[1]) {
17354 WL_ERR(("%s: Wrong SSID len: %d != %d\n",
17355 __FUNCTION__, ssidie[1], bi->SSID_len));
17356 }
17357 if (roam) {
17358 WL_ERR(("Changing the SSID Info.\n"));
17359 memmove(ssidie + ssid_len + 2,
17360 (ssidie + 2) + ssidie[1],
17361 remaining_ie_buf_len);
17362 memcpy(ssidie + 2, bi->SSID, ssid_len);
17363 *ie_size = *ie_size + ssid_len - ssidie[1];
17364 ssidie[1] = ssid_len;
17365 }
17366 return;
17367 }
17368 if (*(ssidie + 2) == '\0')
17369 memcpy(ssidie + 2, bi->SSID, ssid_len);
17370 return;
17371}
17372
17373static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size)
17374{
17375 struct wl_ie *ie = wl_to_ie(cfg);
17376 s32 err = 0;
17377
17378 if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
17379 WL_ERR(("ei_stream crosses buffer boundary\n"));
17380 return -ENOSPC;
17381 }
17382 memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
17383 ie->offset += ie_size;
17384
17385 return err;
17386}
17387
17388static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size)
17389{
17390 struct wl_ie *ie = wl_to_ie(cfg);
17391 s32 err = 0;
17392
17393 if (unlikely(ie->offset > dst_size)) {
17394 WL_ERR(("dst_size is not enough\n"));
17395 return -ENOSPC;
17396 }
17397 memcpy(dst, &ie->buf[0], ie->offset);
17398
17399 return err;
17400}
17401
17402static u32 wl_get_ielen(struct bcm_cfg80211 *cfg)
17403{
17404 struct wl_ie *ie = wl_to_ie(cfg);
17405
17406 return ie->offset;
17407}
17408
17409static void wl_link_up(struct bcm_cfg80211 *cfg)
17410{
17411 cfg->link_up = true;
17412}
17413
17414static void wl_link_down(struct bcm_cfg80211 *cfg)
17415{
17416 struct wl_connect_info *conn_info = wl_to_conn(cfg);
17417
17418 WL_DBG(("In\n"));
17419 cfg->link_up = false;
8d40fb59
RC
17420 if (conn_info) {
17421 conn_info->req_ie_len = 0;
17422 conn_info->resp_ie_len = 0;
17423 }
010c3a89
RC
17424}
17425
17426static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
17427{
17428 unsigned long flags;
17429
17430 spin_lock_irqsave(&cfg->eq_lock, flags);
17431 return flags;
17432}
17433
17434static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
17435{
17436 spin_unlock_irqrestore(&cfg->eq_lock, flags);
17437}
17438
17439static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
17440{
17441 spin_lock_init(&cfg->eq_lock);
17442}
17443
17444static void wl_delay(u32 ms)
17445{
17446 if (in_atomic() || (ms < jiffies_to_msecs(1))) {
17447 OSL_DELAY(ms*1000);
17448 } else {
17449 OSL_SLEEP(ms);
17450 }
17451}
17452
17453s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
17454{
17455 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17456 struct ether_addr primary_mac;
17457 if (!cfg->p2p)
17458 return -1;
17459 if (!p2p_is_on(cfg)) {
17460 get_primary_mac(cfg, &primary_mac);
17461 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
17462 } else {
17463 memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
17464 ETHER_ADDR_LEN);
17465 }
17466
17467 return 0;
17468}
17469s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
17470{
17471 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17472
17473 return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
17474}
17475
17476s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
17477{
17478 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17479
17480 return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
17481}
17482
17483s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
17484{
17485 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17486
17487 return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
17488}
17489
17490s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
17491{
17492 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17493
17494 return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
17495}
17496
17497s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
17498{
17499 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17500
17501 return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
17502}
17503
17504#ifdef P2PLISTEN_AP_SAMECHN
17505s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
17506{
17507 s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
17508
17509 if ((ret == 0) && enable) {
17510 /* disable PM for p2p responding on infra AP channel */
17511 s32 pm = PM_OFF;
17512
17513 ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm));
17514 }
17515
17516 return ret;
17517}
17518#endif /* P2PLISTEN_AP_SAMECHN */
17519
17520s32 wl_cfg80211_channel_to_freq(u32 channel)
17521{
17522 int freq = 0;
17523
17524#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
17525 freq = ieee80211_channel_to_frequency(channel);
17526#else
17527 {
17528 u16 band = 0;
17529 if (channel <= CH_MAX_2G_CHANNEL)
17530 band = IEEE80211_BAND_2GHZ;
17531 else
17532 band = IEEE80211_BAND_5GHZ;
17533 freq = ieee80211_channel_to_frequency(channel, band);
17534 }
17535#endif
17536 return freq;
17537}
17538
17539
17540#ifdef WLTDLS
17541static s32
17542wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17543 const wl_event_msg_t *e, void *data) {
17544
17545 struct net_device *ndev = NULL;
17546 u32 reason = ntoh32(e->reason);
17547 s8 *msg = NULL;
17548
17549 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17550
17551 switch (reason) {
17552 case WLC_E_TDLS_PEER_DISCOVERED :
17553 msg = " TDLS PEER DISCOVERD ";
17554 break;
17555 case WLC_E_TDLS_PEER_CONNECTED :
17556 if (cfg->tdls_mgmt_frame) {
17557#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
17558 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
17559 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0);
17560#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
17561 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
17562 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0,
17563 GFP_ATOMIC);
17564#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
17565 defined(WL_COMPAT_WIRELESS)
17566 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
17567 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
17568 GFP_ATOMIC);
17569#else
17570 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
17571 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, GFP_ATOMIC);
17572#endif
17573 }
17574 msg = " TDLS PEER CONNECTED ";
17575#ifdef SUPPORT_SET_CAC
17576 /* TDLS connect reset CAC */
17577 wl_cfg80211_set_cac(cfg, 0);
17578#endif /* SUPPORT_SET_CAC */
17579 break;
17580 case WLC_E_TDLS_PEER_DISCONNECTED :
17581 if (cfg->tdls_mgmt_frame) {
17582 kfree(cfg->tdls_mgmt_frame);
17583 cfg->tdls_mgmt_frame = NULL;
17584 cfg->tdls_mgmt_freq = 0;
17585 }
17586 msg = "TDLS PEER DISCONNECTED ";
17587#ifdef SUPPORT_SET_CAC
17588 /* TDLS disconnec, set CAC */
17589 wl_cfg80211_set_cac(cfg, 1);
17590#endif /* SUPPORT_SET_CAC */
17591 break;
17592 }
17593 if (msg) {
17594 WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((const u8*)(&e->addr)),
17595 (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
17596 }
17597 return 0;
17598
17599}
17600#endif /* WLTDLS */
17601
17602#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
17603static s32
17604#if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
17605 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
17606wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
17607 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
17608 u32 peer_capability, const u8 *buf, size_t len)
17609#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
17610 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
17611wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
17612 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
17613 u32 peer_capability, const u8 *buf, size_t len)
17614#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
17615wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
17616 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
17617 u32 peer_capability, bool initiator, const u8 *buf, size_t len)
17618#else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
17619wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
17620 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
17621 const u8 *buf, size_t len)
17622#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
17623{
17624 s32 ret = 0;
17625#ifdef WLTDLS
17626 struct bcm_cfg80211 *cfg;
17627 tdls_wfd_ie_iovar_t info;
17628 memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
17629 cfg = wl_get_cfg(dev);
17630
17631#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
17632 /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
17633 * and that cuases build error
17634 */
17635 BCM_REFERENCE(peer_capability);
17636#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
17637
17638 switch (action_code) {
17639 /* We need to set TDLS Wifi Display IE to firmware
17640 * using tdls_wfd_ie iovar
17641 */
17642 case WLAN_TDLS_SET_PROBE_WFD_IE:
17643 WL_ERR(("%s WLAN_TDLS_SET_PROBE_WFD_IE\n", __FUNCTION__));
17644 info.mode = TDLS_WFD_PROBE_IE_TX;
17645 memcpy(&info.data, buf, len);
17646 info.length = len;
17647 break;
17648 case WLAN_TDLS_SET_SETUP_WFD_IE:
17649 WL_ERR(("%s WLAN_TDLS_SET_SETUP_WFD_IE\n", __FUNCTION__));
17650 info.mode = TDLS_WFD_IE_TX;
17651 memcpy(&info.data, buf, len);
17652 info.length = len;
17653 break;
17654 case WLAN_TDLS_SET_WFD_ENABLED:
17655 WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_ENABLED\n", __FUNCTION__));
17656 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
17657 goto out;
17658 case WLAN_TDLS_SET_WFD_DISABLED:
17659 WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_DISABLED\n", __FUNCTION__));
17660 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
17661 goto out;
17662 default:
17663 WL_ERR(("Unsupported action code : %d\n", action_code));
17664 goto out;
17665 }
17666 ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
17667 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
17668
17669 if (ret) {
17670 WL_ERR(("tdls_wfd_ie error %d\n", ret));
17671 }
17672
17673out:
17674#endif /* WLTDLS */
17675 return ret;
17676}
17677
17678static s32
17679#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
17680wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
17681 const u8 *peer, enum nl80211_tdls_operation oper)
17682#else
17683wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
17684 u8 *peer, enum nl80211_tdls_operation oper)
17685#endif
17686{
17687 s32 ret = 0;
17688#ifdef WLTDLS
17689 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17690 tdls_iovar_t info;
17691 dhd_pub_t *dhdp;
17692 bool tdls_auto_mode = false;
17693 dhdp = (dhd_pub_t *)(cfg->pub);
17694 memset(&info, 0, sizeof(tdls_iovar_t));
17695 if (peer) {
17696 memcpy(&info.ea, peer, ETHER_ADDR_LEN);
17697 } else {
17698 return -1;
17699 }
17700 switch (oper) {
17701 case NL80211_TDLS_DISCOVERY_REQ:
17702 /* If the discovery request is broadcast then we need to set
17703 * info.mode to Tunneled Probe Request
17704 */
17705 if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
17706 info.mode = TDLS_MANUAL_EP_WFD_TPQ;
17707 WL_ERR(("%s TDLS TUNNELED PRBOBE REQUEST\n", __FUNCTION__));
17708 } else {
17709 info.mode = TDLS_MANUAL_EP_DISCOVERY;
17710 }
17711 break;
17712 case NL80211_TDLS_SETUP:
17713 if (dhdp->tdls_mode == true) {
17714 info.mode = TDLS_MANUAL_EP_CREATE;
17715 tdls_auto_mode = false;
17716 /* Do tear down and create a fresh one */
17717 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_TEARDOWN, tdls_auto_mode);
17718 if (ret < 0) {
17719 return ret;
17720 }
17721 } else {
17722 tdls_auto_mode = true;
17723 }
17724 break;
17725 case NL80211_TDLS_TEARDOWN:
17726 info.mode = TDLS_MANUAL_EP_DELETE;
17727 break;
17728 default:
17729 WL_ERR(("Unsupported operation : %d\n", oper));
17730 goto out;
17731 }
17732 /* turn on TDLS */
17733 wl_cfg80211_tdls_config(cfg, TDLS_STATE_SETUP, tdls_auto_mode);
17734 if (ret < 0) {
17735 return ret;
17736 }
17737 if (info.mode) {
17738 ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
17739 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
17740 if (ret) {
17741 WL_ERR(("tdls_endpoint error %d\n", ret));
17742 }
17743 }
17744out:
17745 if (ret) {
17746 return -ENOTSUPP;
17747 }
17748#endif /* WLTDLS */
17749 return ret;
17750}
17751#endif
17752
17753/*
17754 * This function returns no of bytes written
17755 * In case of failure return zero, not bcme_error
17756 */
17757s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
17758 enum wl_management_type type)
17759{
17760 struct bcm_cfg80211 *cfg;
17761 s32 ret = 0;
17762 struct ether_addr primary_mac;
17763 s32 bssidx = 0;
17764 s32 pktflag = 0;
17765 cfg = wl_get_cfg(ndev);
17766
17767 if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
17768 /* Vendor IEs should be set to FW
17769 * after SoftAP interface is brought up
17770 */
17771 WL_DBG(("Skipping set IE since AP is not up \n"));
17772 goto exit;
17773 } else if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
17774 /* Either stand alone AP case or P2P discovery */
17775 if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
17776 /* Stand alone AP case on primary interface */
17777 WL_DBG(("Apply IEs for Primary AP Interface \n"));
17778 bssidx = 0;
17779 } else {
17780 if (!cfg->p2p) {
17781 /* If p2p not initialized, return failure */
17782 WL_ERR(("P2P not initialized \n"));
17783 goto exit;
17784 }
17785 /* P2P Discovery case (p2p listen) */
17786 if (!cfg->p2p->on) {
17787 /* Turn on Discovery interface */
17788 get_primary_mac(cfg, &primary_mac);
17789 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
17790 p2p_on(cfg) = true;
17791 ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
17792 if (unlikely(ret)) {
17793 WL_ERR(("Enable discovery failed \n"));
17794 goto exit;
17795 }
17796 }
17797 WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
17798 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
17799 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
17800 }
17801 } else {
17802 /* Virtual AP/ P2P Group Interface */
17803 WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
17804 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
17805 }
17806
17807 if (ndev != NULL) {
17808 switch (type) {
17809 case WL_BEACON:
17810 pktflag = VNDR_IE_BEACON_FLAG;
17811 break;
17812 case WL_PROBE_RESP:
17813 pktflag = VNDR_IE_PRBRSP_FLAG;
17814 break;
17815 case WL_ASSOC_RESP:
17816 pktflag = VNDR_IE_ASSOCRSP_FLAG;
17817 break;
17818 }
17819 if (pktflag) {
17820 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
17821 ndev_to_cfgdev(ndev), bssidx, pktflag, buf, len);
17822 }
17823 }
17824exit:
17825 return ret;
17826}
17827
17828#ifdef WL_SUPPORT_AUTO_CHANNEL
17829static s32
17830wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev)
17831{
17832 u32 val = 0;
17833 s32 ret = BCME_ERROR;
17834 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
17835 /* Set interface up, explicitly. */
17836 val = 1;
17837
17838 ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
17839 if (ret < 0) {
17840 WL_ERR(("set interface up failed, error = %d\n", ret));
17841 goto done;
17842 }
17843
17844 /* Stop all scan explicitly, till auto channel selection complete. */
17845 wl_set_drv_status(cfg, SCANNING, ndev);
17846 if (cfg->escan_info.ndev == NULL) {
17847 ret = BCME_OK;
17848 goto done;
17849 }
17850 ret = wl_notify_escan_complete(cfg, ndev, true, true);
17851 if (ret < 0) {
17852 WL_ERR(("set scan abort failed, error = %d\n", ret));
17853 ret = BCME_OK; // terence 20140115: fix escan_complete error
17854 goto done;
17855 }
17856
17857done:
17858 return ret;
17859}
17860
17861static bool
ccd15baf 17862wl_cfg80211_valid_channel_p2p(int channel)
010c3a89
RC
17863{
17864 bool valid = false;
010c3a89
RC
17865
17866 /* channel 1 to 14 */
ccd15baf 17867 if ((channel >= 1) && (channel <= 14)) {
010c3a89
RC
17868 valid = true;
17869 }
17870 /* channel 36 to 48 */
ccd15baf 17871 else if ((channel >= 36) && (channel <= 48)) {
010c3a89
RC
17872 valid = true;
17873 }
17874 /* channel 149 to 161 */
ccd15baf 17875 else if ((channel >= 149) && (channel <= 161)) {
010c3a89
RC
17876 valid = true;
17877 }
17878 else {
17879 valid = false;
ccd15baf 17880 WL_INFORM(("invalid P2P chanspec, channel = %d\n", channel));
010c3a89
RC
17881 }
17882
17883 return valid;
17884}
17885
17886s32
17887wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
17888{
17889 s32 ret = BCME_ERROR;
17890 struct bcm_cfg80211 *cfg = NULL;
17891 chanspec_t chanspec = 0;
17892
17893 cfg = wl_get_cfg(ndev);
17894
17895 /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
17896 chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 |
17897 WL_CHANSPEC_CTL_SB_NONE);
17898 chanspec = wl_chspec_host_to_driver(chanspec);
17899
17900 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
17901 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
17902 if (ret < 0) {
17903 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
17904 }
17905
17906 return ret;
17907}
17908
17909s32
17910wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
17911{
17912 u32 channel = 0;
17913 s32 ret = BCME_ERROR;
17914 s32 i = 0;
17915 s32 j = 0;
17916 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
17917 wl_uint32_list_t *list = NULL;
17918 chanspec_t chanspec = 0;
17919
17920 /* Restrict channels to 5GHz, 20MHz BW, no SB. */
17921 chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 |
17922 WL_CHANSPEC_CTL_SB_NONE);
17923 chanspec = wl_chspec_host_to_driver(chanspec);
17924
17925 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
17926 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
17927 if (ret < 0) {
17928 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
17929 goto done;
17930 }
17931
17932 list = (wl_uint32_list_t *)buf;
17933 /* Skip DFS and inavlid P2P channel. */
17934 for (i = 0, j = 0; i < dtoh32(list->count); i++) {
17935 chanspec = (chanspec_t) dtoh32(list->element[i]);
17936 channel = CHSPEC_CHANNEL(chanspec);
17937
17938 ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
17939 if (ret < 0) {
17940 WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret));
17941 goto done;
17942 }
17943
17944 if (CHANNEL_IS_RADAR(channel) ||
ccd15baf 17945 !(wl_cfg80211_valid_channel_p2p(CHSPEC_CHANNEL(chanspec)))) {
010c3a89
RC
17946 continue;
17947 } else {
17948 list->element[j] = list->element[i];
17949 }
17950
17951 j++;
17952 }
17953
17954 list->count = j;
17955
17956done:
17957 return ret;
17958}
17959
17960static s32
17961wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen,
17962 int *channel)
17963{
17964 s32 ret = BCME_ERROR;
17965 int chosen = 0;
17966 int retry = 0;
17967 uint chip;
17968
17969 /* Start auto channel selection scan. */
ccd15baf 17970 ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, buf, buflen);
010c3a89
RC
17971 if (ret < 0) {
17972 WL_ERR(("can't start auto channel scan, error = %d\n", ret));
17973 *channel = 0;
17974 goto done;
17975 }
17976
17977 /* Wait for auto channel selection, worst case possible delay is 5250ms. */
17978 retry = CHAN_SEL_RETRY_COUNT;
17979
17980 while (retry--) {
17981 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
17982 chosen = 0;
17983 ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
17984 if ((ret == 0) && (dtoh32(chosen) != 0)) {
17985 chip = dhd_conf_get_chip(dhd_get_pub(ndev));
dfb0f3ae
RC
17986 if (chip != BCM43362_CHIP_ID && chip != BCM4330_CHIP_ID &&
17987 chip != BCM43143_CHIP_ID) {
010c3a89
RC
17988 u32 chanspec = 0;
17989 int ctl_chan;
17990 chanspec = wl_chspec_driver_to_host(chosen);
dfb0f3ae 17991 WL_INFORM(("selected chanspec = 0x%x\n", chanspec));
010c3a89 17992 ctl_chan = wf_chspec_ctlchan(chanspec);
dfb0f3ae 17993 WL_INFORM(("selected ctl_chan = %d\n", ctl_chan));
010c3a89
RC
17994 *channel = (u16)(ctl_chan & 0x00FF);
17995 } else
17996 *channel = (u16)(chosen & 0x00FF);
17997 WL_INFORM(("selected channel = %d\n", *channel));
17998 break;
17999 }
18000 WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n",
18001 (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
18002 }
18003
18004 if (retry <= 0) {
18005 WL_ERR(("failure, auto channel selection timed out\n"));
18006 *channel = 0;
18007 ret = BCME_ERROR;
18008 }
ccd15baf 18009 WL_INFORM(("selected channel = %d\n", *channel));
010c3a89
RC
18010
18011done:
18012 return ret;
18013}
18014
18015static s32
18016wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev)
18017{
18018 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18019 /* Clear scan stop driver status. */
18020 wl_clr_drv_status(cfg, SCANNING, ndev);
18021
18022 return BCME_OK;
18023}
18024
18025s32
18026wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len)
18027{
18028 int channel = 0, band, band_cur;
18029 s32 ret = BCME_ERROR;
18030 u8 *buf = NULL;
18031 char *pos = cmd;
18032 struct bcm_cfg80211 *cfg = NULL;
18033 struct net_device *ndev = NULL;
18034
18035 memset(cmd, 0, total_len);
18036
18037 buf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL);
18038 if (buf == NULL) {
18039 WL_ERR(("failed to allocate chanspec buffer\n"));
18040 return -ENOMEM;
18041 }
18042
18043 /*
18044 * Always use primary interface, irrespective of interface on which
18045 * command came.
18046 */
18047 cfg = wl_get_cfg(dev);
18048 ndev = bcmcfg_to_prmry_ndev(cfg);
18049
18050 /*
18051 * Make sure that FW and driver are in right state to do auto channel
18052 * selection scan.
18053 */
18054 ret = wl_cfg80211_set_auto_channel_scan_state(ndev);
18055 if (ret < 0) {
18056 WL_ERR(("can't set auto channel scan state, error = %d\n", ret));
18057 goto done;
18058 }
18059
18060 ret = wldev_ioctl(dev, WLC_GET_BAND, &band_cur, sizeof(band_cur), false);
18061 if (band_cur != WLC_BAND_5G) {
18062 /* Best channel selection in 2.4GHz band. */
18063 ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
18064 if (ret < 0) {
18065 WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
18066 goto done;
18067 }
18068
18069 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
18070 &channel);
18071 if (ret < 0) {
18072 WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
18073 goto done;
18074 }
18075
18076 if (CHANNEL_IS_2G(channel)) {
ccd15baf 18077#if 0
010c3a89
RC
18078#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
18079 channel = ieee80211_channel_to_frequency(channel);
18080#else
18081 channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
ccd15baf 18082#endif
010c3a89
RC
18083#endif
18084 } else {
18085 WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel));
18086 channel = 0;
18087 }
ccd15baf 18088 pos += snprintf(pos, total_len, "2g=%d ", channel);
010c3a89 18089 }
010c3a89
RC
18090
18091 if (band_cur != WLC_BAND_2G) {
18092 // terence 20140120: fix for some chipsets only return 2.4GHz channel (4330b2/43341b0/4339a0)
18093 band = band_cur==WLC_BAND_2G ? band_cur : WLC_BAND_5G;
18094 ret = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true);
d964ce36 18095 if (ret < 0) {
010c3a89 18096 WL_ERR(("WLC_SET_BAND error %d\n", ret));
d964ce36 18097 goto done;
18098 }
010c3a89
RC
18099
18100 /* Best channel selection in 5GHz band. */
18101 ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
18102 if (ret < 0) {
18103 WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret));
18104 goto done;
18105 }
18106
18107 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
18108 &channel);
18109 if (ret < 0) {
18110 WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret));
18111 goto done;
18112 }
18113
18114 if (CHANNEL_IS_5G(channel)) {
ccd15baf 18115#if 0
010c3a89
RC
18116#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
18117 channel = ieee80211_channel_to_frequency(channel);
18118#else
18119 channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
ccd15baf 18120#endif
010c3a89
RC
18121#endif
18122 } else {
18123 WL_ERR(("invalid 5GHz channel, channel = %d\n", channel));
18124 channel = 0;
18125 }
18126
18127 ret = wldev_ioctl(dev, WLC_SET_BAND, &band_cur, sizeof(band_cur), true);
18128 if (ret < 0)
18129 WL_ERR(("WLC_SET_BAND error %d\n", ret));
ccd15baf 18130 pos += snprintf(pos, total_len, "5g=%d ", channel);
010c3a89 18131 }
010c3a89
RC
18132
18133done:
18134 if (NULL != buf) {
18135 kfree(buf);
18136 }
18137
18138 /* Restore FW and driver back to normal state. */
18139 ret = wl_cfg80211_restore_auto_channel_scan_state(ndev);
18140 if (ret < 0) {
18141 WL_ERR(("can't restore auto channel scan state, error = %d\n", ret));
18142 }
18143
ccd15baf 18144 printf("%s: %s\n", __FUNCTION__, cmd);
010c3a89
RC
18145
18146 return (pos - cmd);
18147}
18148#endif /* WL_SUPPORT_AUTO_CHANNEL */
18149
18150static const struct rfkill_ops wl_rfkill_ops = {
18151 .set_block = wl_rfkill_set
18152};
18153
18154static int wl_rfkill_set(void *data, bool blocked)
18155{
18156 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
18157
18158 WL_DBG(("Enter \n"));
18159 WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
18160
18161 if (!cfg)
18162 return -EINVAL;
18163
18164 cfg->rf_blocked = blocked;
18165
18166 return 0;
18167}
18168
18169static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
18170{
18171 s32 err = 0;
18172
18173 WL_DBG(("Enter \n"));
18174 if (!cfg)
18175 return -EINVAL;
18176 if (setup) {
18177 cfg->rfkill = rfkill_alloc("brcmfmac-wifi",
18178 wl_cfg80211_get_parent_dev(),
18179 RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
18180
18181 if (!cfg->rfkill) {
18182 err = -ENOMEM;
18183 goto err_out;
18184 }
18185
18186 err = rfkill_register(cfg->rfkill);
18187
18188 if (err)
18189 rfkill_destroy(cfg->rfkill);
18190 } else {
18191 if (!cfg->rfkill) {
18192 err = -ENOMEM;
18193 goto err_out;
18194 }
18195
18196 rfkill_unregister(cfg->rfkill);
18197 rfkill_destroy(cfg->rfkill);
18198 }
18199
18200err_out:
18201 return err;
18202}
18203
18204#ifdef DEBUGFS_CFG80211
18205/**
18206* Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
18207* to turn on SCAN and DBG log.
18208* To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
18209* To see current setting of debug level,
18210* cat /sys/kernel/debug/dhd/debug_level
18211*/
18212static ssize_t
18213wl_debuglevel_write(struct file *file, const char __user *userbuf,
18214 size_t count, loff_t *ppos)
18215{
18216 char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL];
18217 char *params, *token, *colon;
18218 uint i, tokens, log_on = 0;
18219 size_t minsize = min_t(size_t, (sizeof(tbuf) - 1), count);
18220
18221 memset(tbuf, 0, sizeof(tbuf));
18222 memset(sublog, 0, sizeof(sublog));
18223 if (copy_from_user(&tbuf, userbuf, minsize)) {
18224 return -EFAULT;
18225 }
18226
18227 tbuf[minsize + 1] = '\0';
18228 params = &tbuf[0];
18229 colon = strchr(params, '\n');
18230 if (colon != NULL)
18231 *colon = '\0';
18232 while ((token = strsep(&params, " ")) != NULL) {
18233 memset(sublog, 0, sizeof(sublog));
18234 if (token == NULL || !*token)
18235 break;
18236 if (*token == '\0')
18237 continue;
18238 colon = strchr(token, ':');
18239 if (colon != NULL) {
18240 *colon = ' ';
18241 }
18242 tokens = sscanf(token, "%s %u", sublog, &log_on);
18243 if (colon != NULL)
18244 *colon = ':';
18245
18246 if (tokens == 2) {
18247 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
18248 if (!strncmp(sublog, sublogname_map[i].sublogname,
18249 strlen(sublogname_map[i].sublogname))) {
18250 if (log_on)
18251 wl_dbg_level |=
18252 (sublogname_map[i].log_level);
18253 else
18254 wl_dbg_level &=
18255 ~(sublogname_map[i].log_level);
18256 }
18257 }
18258 } else
18259 WL_ERR(("%s: can't parse '%s' as a "
18260 "SUBMODULE:LEVEL (%d tokens)\n",
18261 tbuf, token, tokens));
18262
18263
18264 }
18265 return count;
18266}
18267
18268static ssize_t
18269wl_debuglevel_read(struct file *file, char __user *user_buf,
18270 size_t count, loff_t *ppos)
18271{
18272 char *param;
18273 char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)];
18274 uint i;
18275 memset(tbuf, 0, sizeof(tbuf));
18276 param = &tbuf[0];
18277 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
18278 param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
18279 sublogname_map[i].sublogname,
18280 (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0);
18281 }
18282 *param = '\n';
18283 return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0]));
18284
18285}
18286static const struct file_operations fops_debuglevel = {
18287 .open = NULL,
18288 .write = wl_debuglevel_write,
18289 .read = wl_debuglevel_read,
18290 .owner = THIS_MODULE,
18291 .llseek = NULL,
18292};
18293
18294static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg)
18295{
18296 s32 err = 0;
18297 struct dentry *_dentry;
18298 if (!cfg)
18299 return -EINVAL;
18300 cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
18301 if (!cfg->debugfs || IS_ERR(cfg->debugfs)) {
18302 if (cfg->debugfs == ERR_PTR(-ENODEV))
18303 WL_ERR(("Debugfs is not enabled on this kernel\n"));
18304 else
18305 WL_ERR(("Can not create debugfs directory\n"));
18306 cfg->debugfs = NULL;
18307 goto exit;
18308
18309 }
18310 _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR,
18311 cfg->debugfs, cfg, &fops_debuglevel);
18312 if (!_dentry || IS_ERR(_dentry)) {
18313 WL_ERR(("failed to create debug_level debug file\n"));
18314 wl_free_debugfs(cfg);
18315 }
18316exit:
18317 return err;
18318}
18319static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg)
18320{
18321 if (!cfg)
18322 return -EINVAL;
18323 if (cfg->debugfs)
18324 debugfs_remove_recursive(cfg->debugfs);
18325 cfg->debugfs = NULL;
18326 return 0;
18327}
18328#endif /* DEBUGFS_CFG80211 */
18329
18330struct device *wl_cfg80211_get_parent_dev(void)
18331{
18332 return cfg80211_parent_dev;
18333}
18334
18335void wl_cfg80211_set_parent_dev(void *dev)
18336{
18337 cfg80211_parent_dev = dev;
18338}
18339
18340static void wl_cfg80211_clear_parent_dev(void)
18341{
18342 cfg80211_parent_dev = NULL;
18343}
18344
18345void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
18346{
18347 if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr", NULL,
18348 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync) == BCME_OK) {
18349 memcpy(mac->octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
18350 } else {
18351 memset(mac->octet, 0, ETHER_ADDR_LEN);
18352 }
18353}
18354static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
18355{
18356 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
18357 if (((dev_role == NL80211_IFTYPE_AP) &&
18358 !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
18359 ((dev_role == NL80211_IFTYPE_P2P_GO) &&
18360 !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
18361 {
18362 WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
18363 return false;
18364 }
18365 return true;
18366}
18367
18368int wl_cfg80211_do_driver_init(struct net_device *net)
18369{
18370 struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
18371
18372 if (!cfg || !cfg->wdev)
18373 return -EINVAL;
18374
18375 if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
18376 return -1;
18377
18378 return 0;
18379}
18380
18381void wl_cfg80211_enable_trace(u32 level)
18382{
18383 wl_dbg_level = level;
18384 printf("%s: wl_dbg_level = 0x%x\n", __FUNCTION__, wl_dbg_level);
18385}
18386
18387#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
18388 2, 0))
18389static s32
18390wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
18391 bcm_struct_cfgdev *cfgdev, u64 cookie)
18392{
18393 /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
18394 * is passed with CMD_FRAME. This callback is supposed to cancel
18395 * the OFFCHANNEL Wait. Since we are already taking care of that
18396 * with the tx_mgmt logic, do nothing here.
18397 */
18398
18399 return 0;
18400}
18401#endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
18402
18403#ifdef WL11U
18404static bcm_tlv_t *
18405wl_cfg80211_find_interworking_ie(const u8 *parse, u32 len)
18406{
18407 bcm_tlv_t *ie;
18408
18409/* unfortunately it's too much work to dispose the const cast - bcm_parse_tlvs
18410 * is used everywhere and changing its prototype to take const qualifier needs
18411 * a massive change to all its callers...
18412 */
18413#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18414 4 && __GNUC_MINOR__ >= 6))
18415_Pragma("GCC diagnostic push")
18416_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
18417#endif
18418 if ((ie = bcm_parse_tlvs((void *)parse, (int)len, DOT11_MNG_INTERWORKING_ID))) {
18419 return ie;
18420 }
18421#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18422 4 && __GNUC_MINOR__ >= 6))
18423_Pragma("GCC diagnostic pop")
18424#endif
18425 return NULL;
18426}
18427
18428static s32
18429wl_cfg80211_clear_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx)
18430{
18431 ie_setbuf_t ie_setbuf;
18432
18433 WL_DBG(("clear interworking IE\n"));
18434
18435 memset(&ie_setbuf, 0, sizeof(ie_setbuf_t));
18436
18437 ie_setbuf.ie_buffer.iecount = htod32(1);
18438 ie_setbuf.ie_buffer.ie_list[0].ie_data.id = DOT11_MNG_INTERWORKING_ID;
18439 ie_setbuf.ie_buffer.ie_list[0].ie_data.len = 0;
18440
18441 return wldev_iovar_setbuf_bsscfg(ndev, "ie", &ie_setbuf, sizeof(ie_setbuf),
18442 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
18443}
18444
18445static s32
18446wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
18447 uint8 ie_id, uint8 *data, uint8 data_len)
18448{
18449 s32 err = BCME_OK;
18450 s32 buf_len;
18451 ie_setbuf_t *ie_setbuf;
18452 ie_getbuf_t ie_getbufp;
18453 char getbuf[WLC_IOCTL_SMLEN];
18454
18455 if (ie_id != DOT11_MNG_INTERWORKING_ID) {
18456 WL_ERR(("unsupported (id=%d)\n", ie_id));
18457 return BCME_UNSUPPORTED;
18458 }
18459
18460 /* access network options (1 octet) is the mandatory field */
18461 if (!data || data_len == 0 || data_len > IW_IES_MAX_BUF_LEN) {
18462 WL_ERR(("wrong interworking IE (len=%d)\n", data_len));
18463 return BCME_BADARG;
18464 }
18465
18466 /* Validate the pktflag parameter */
18467 if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
18468 VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
18469 VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG|
18470 VNDR_IE_CUSTOM_FLAG))) {
18471 WL_ERR(("invalid packet flag 0x%x\n", pktflag));
18472 return BCME_BADARG;
18473 }
18474
18475 buf_len = sizeof(ie_setbuf_t) + data_len - 1;
18476
18477 ie_getbufp.id = DOT11_MNG_INTERWORKING_ID;
18478 if (wldev_iovar_getbuf_bsscfg(ndev, "ie", (void *)&ie_getbufp,
18479 sizeof(ie_getbufp), getbuf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)
18480 == BCME_OK) {
18481 if (!memcmp(&getbuf[TLV_HDR_LEN], data, data_len)) {
18482 WL_DBG(("skip to set interworking IE\n"));
18483 return BCME_OK;
18484 }
18485 }
18486
18487 /* if already set with previous values, delete it first */
18488 if (cfg->wl11u) {
18489 if ((err = wl_cfg80211_clear_iw_ie(cfg, ndev, bssidx)) != BCME_OK) {
18490 return err;
18491 }
18492 }
18493
18494 ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL);
18495 if (!ie_setbuf) {
18496 WL_ERR(("Error allocating buffer for IE\n"));
18497 return -ENOMEM;
18498 }
18499 strncpy(ie_setbuf->cmd, "add", sizeof(ie_setbuf->cmd));
18500 ie_setbuf->cmd[sizeof(ie_setbuf->cmd) - 1] = '\0';
18501
18502 /* Buffer contains only 1 IE */
18503 ie_setbuf->ie_buffer.iecount = htod32(1);
18504 /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */
18505 ie_setbuf->ie_buffer.ie_list[0].pktflag = htod32(pktflag);
18506
18507 /* Now, add the IE to the buffer */
18508 ie_setbuf->ie_buffer.ie_list[0].ie_data.id = DOT11_MNG_INTERWORKING_ID;
18509 ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len;
18510 memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len);
18511
18512 if ((err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
18513 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync))
18514 == BCME_OK) {
18515 WL_DBG(("set interworking IE\n"));
18516 cfg->wl11u = TRUE;
18517 err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx);
18518 }
18519
18520 kfree(ie_setbuf);
18521 return err;
18522}
18523#endif /* WL11U */
18524
18525
18526s32
18527wl_cfg80211_set_if_band(struct net_device *ndev, int band)
18528{
18529 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18530 int ret = 0, wait_cnt;
18531 char ioctl_buf[32];
18532
18533 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
18534 WL_ERR(("Invalid band\n"));
18535 return -EINVAL;
18536 }
18537 if (wl_get_drv_status(cfg, CONNECTED, ndev) ||
18538 wl_get_drv_status(cfg, CONNECTING, ndev)) {
18539 /* if driver is connected or connecting status, try to disconnect first.
18540 * if dongle is associated, iovar 'if_band' would be rejected.
18541 */
18542 wl_set_drv_status(cfg, DISCONNECTING, ndev);
18543 ret = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
18544 if (ret < 0) {
18545 WL_ERR(("WLC_DISASSOC error %d\n", ret));
18546 /* continue to set 'if_band' */
18547 }
18548 else {
18549 /* This is to ensure that 'if_band' iovar is issued only after
18550 * disconnection is completed
18551 */
18552 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
18553 while (wl_get_drv_status(cfg, DISCONNECTING, ndev) && wait_cnt) {
18554 WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt));
18555 wait_cnt--;
18556 OSL_SLEEP(10);
18557 }
18558 }
18559 }
18560 if ((ret = wldev_iovar_setbuf(ndev, "if_band", &band,
18561 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
18562 WL_ERR(("seting if_band failed ret=%d\n", ret));
18563 /* issue 'WLC_SET_BAND' if if_band is not supported */
18564 if (ret == BCME_UNSUPPORTED) {
18565 ret = wldev_set_band(ndev, band);
18566 if (ret < 0) {
18567 WL_ERR(("seting band failed ret=%d\n", ret));
18568 }
18569 }
18570 }
18571 return ret;
18572}
18573
18574s32
18575wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int total_len)
18576{
18577 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18578 char ioctl_buf[50];
18579 int err = 0;
18580 uint32 val = 0;
18581 chanspec_t chanspec = 0;
18582 int abort;
18583 int bytes_written = 0;
18584 wl_dfs_ap_move_status_t *status;
18585 char chanbuf[CHANSPEC_STR_LEN];
18586 const char *dfs_state_str[DFS_SCAN_S_MAX] = {
18587 "Radar Free On Channel",
18588 "Radar Found On Channel",
18589 "Radar Scan In Progress",
18590 "Radar Scan Aborted",
18591 "RSDB Mode switch in Progress For Scan"
18592 };
18593 if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
18594 bytes_written = snprintf(command, total_len, "AP is not up\n");
18595 return bytes_written;
18596 }
18597 if (!*data) {
18598 if ((err = wldev_iovar_getbuf(ndev, "dfs_ap_move", NULL, 0,
18599 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
18600 WL_ERR(("setting dfs_ap_move failed with err=%d \n", err));
18601 return err;
18602 }
18603 status = (wl_dfs_ap_move_status_t *)cfg->ioctl_buf;
18604
18605 if (status->version != WL_DFS_AP_MOVE_VERSION) {
18606 err = BCME_UNSUPPORTED;
18607 WL_ERR(("err=%d version=%d\n", err, status->version));
18608 return err;
18609 }
18610
18611 if (status->move_status != (int8) DFS_SCAN_S_IDLE) {
18612 chanspec = wl_chspec_driver_to_host(status->chanspec);
18613 if (chanspec != 0 && chanspec != INVCHANSPEC) {
18614 wf_chspec_ntoa(chanspec, chanbuf);
18615 bytes_written = snprintf(command, total_len,
18616 "AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
18617
18618 }
18619 bytes_written += snprintf(command + bytes_written, total_len,
18620 "%s\n", dfs_state_str[status->move_status]);
18621 return bytes_written;
18622 } else {
18623 bytes_written = snprintf(command, total_len, "dfs AP move in IDLE state\n");
18624 return bytes_written;
18625 }
18626
18627 }
18628
18629 abort = bcm_atoi(data);
18630 if (abort == -1) {
18631 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &abort,
18632 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
18633 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
18634 return err;
18635 }
18636 } else {
18637 chanspec = wf_chspec_aton(data);
18638 if (chanspec != 0) {
18639 val = wl_chspec_host_to_driver(chanspec);
18640 if (val != INVCHANSPEC) {
18641 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &val,
18642 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
18643 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
18644 return err;
18645 }
18646 WL_DBG((" set dfs_ap_move successfull"));
18647 } else {
18648 err = BCME_USAGE_ERROR;
18649 }
18650 }
18651 }
18652 return err;
18653}
18654
18655#ifdef WBTEXT
18656s32
18657wl_cfg80211_wbtext_set_default(struct net_device *ndev)
18658{
18659 char commandp[WLC_IOCTL_SMLEN];
18660 s32 ret = BCME_OK;
18661 char *data;
18662
18663 WL_DBG(("set wbtext to default\n"));
18664
18665 /* set roam profile */
18666 memset(commandp, 0, sizeof(commandp));
18667 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18668 CMD_WBTEXT_PROFILE_CONFIG, DEFAULT_WBTEXT_PROFILE_A);
18669 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
18670 ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18671 if (ret != BCME_OK) {
18672 WL_ERR(("%s: Failed to set roam_prof %s error = %d\n",
18673 __FUNCTION__, data, ret));
18674 return ret;
18675 }
18676
18677 memset(commandp, 0, sizeof(commandp));
18678 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18679 CMD_WBTEXT_PROFILE_CONFIG, DEFAULT_WBTEXT_PROFILE_B);
18680 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
18681 ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18682 if (ret != BCME_OK) {
18683 WL_ERR(("%s: Failed to set roam_prof %s error = %d\n",
18684 __FUNCTION__, data, ret));
18685 return ret;
18686 }
18687
18688 /* set RSSI weight */
18689 memset(commandp, 0, sizeof(commandp));
18690 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18691 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_A);
18692 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
18693 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18694 if (ret != BCME_OK) {
18695 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
18696 __FUNCTION__, data, ret));
18697 return ret;
18698 }
18699
18700 memset(commandp, 0, sizeof(commandp));
18701 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18702 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_B);
18703 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
18704 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18705 if (ret != BCME_OK) {
18706 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
18707 __FUNCTION__, data, ret));
18708 return ret;
18709 }
18710
18711 /* set CU weight */
18712 memset(commandp, 0, sizeof(commandp));
18713 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18714 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_A);
18715 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
18716 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18717 if (ret != BCME_OK) {
18718 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
18719 __FUNCTION__, data, ret));
18720 return ret;
18721 }
18722
18723 memset(commandp, 0, sizeof(commandp));
18724 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18725 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_B);
18726 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
18727 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18728 if (ret != BCME_OK) {
18729 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
18730 __FUNCTION__, data, ret));
18731 return ret;
18732 }
18733
18734 /* set RSSI table */
18735 memset(commandp, 0, sizeof(commandp));
18736 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18737 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_A);
18738 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
18739 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18740 if (ret != BCME_OK) {
18741 WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
18742 __FUNCTION__, data, ret));
18743 return ret;
18744 }
18745
18746 memset(commandp, 0, sizeof(commandp));
18747 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18748 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_B);
18749 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
18750 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18751 if (ret != BCME_OK) {
18752 WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
18753 __FUNCTION__, data, ret));
18754 return ret;
18755 }
18756
18757 /* set CU table */
18758 memset(commandp, 0, sizeof(commandp));
18759 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18760 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_A);
18761 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
18762 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18763 if (ret != BCME_OK) {
18764 WL_ERR(("%s: Failed to set CU table %s error = %d\n",
18765 __FUNCTION__, data, ret));
18766 return ret;
18767 }
18768
18769 memset(commandp, 0, sizeof(commandp));
18770 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
18771 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_B);
18772 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
18773 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
18774 if (ret != BCME_OK) {
18775 WL_ERR(("%s: Failed to set CU table %s error = %d\n",
18776 __FUNCTION__, data, ret));
18777 return ret;
18778 }
18779
18780 return ret;
18781}
18782
18783s32
18784wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
18785{
18786 uint i = 0;
18787 long int rssi_lower, roam_trigger;
18788 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18789 wl_roam_prof_band_t *rp;
18790 int err = -EINVAL, bytes_written = 0;
18791 size_t len = strlen(data);
18792 int rp_len = 0;
18793 data[len] = '\0';
18794 rp = (wl_roam_prof_band_t *) kzalloc(sizeof(*rp)
18795 * WL_MAX_ROAM_PROF_BRACKETS, GFP_KERNEL);
18796 if (unlikely(!rp)) {
18797 WL_ERR(("%s: failed to allocate memory\n", __func__));
18798 err = -ENOMEM;
18799 goto exit;
18800 }
18801 rp->ver = WL_MAX_ROAM_PROF_VER;
18802 if (*data && (!strncmp(data, "b", 1))) {
18803 rp->band = WLC_BAND_2G;
18804 } else if (*data && (!strncmp(data, "a", 1))) {
18805 rp->band = WLC_BAND_5G;
18806 } else {
18807 err = snprintf(command, total_len, "Missing band\n");
18808 goto exit;
18809 }
18810 data++;
18811 rp->len = 0;
18812 /* Getting roam profile from fw */
18813 if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
18814 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
18815 WL_ERR(("Getting roam_profile failed with err=%d \n", err));
18816 goto exit;
18817 }
18818 memcpy(rp, cfg->ioctl_buf, sizeof(*rp) * WL_MAX_ROAM_PROF_BRACKETS);
18819 /* roam_prof version get */
18820 if (rp->ver != WL_MAX_ROAM_PROF_VER) {
18821 WL_ERR(("bad version (=%d) in return data\n", rp->ver));
18822 err = -EINVAL;
18823 goto exit;
18824 }
18825 if ((rp->len % sizeof(wl_roam_prof_t)) != 0) {
18826 WL_ERR(("bad length (=%d) in return data\n", rp->len));
18827 err = -EINVAL;
18828 goto exit;
18829 }
18830
18831 if (!*data) {
18832 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
18833 /* printing contents of roam profile data from fw and exits
18834 * if code hits any of one of the below condtion. If remaining
18835 * length of buffer is less than roam profile size or
18836 * if there is no valid entry.
18837 */
18838 if (((i * sizeof(wl_roam_prof_t)) > rp->len) ||
18839 (rp->roam_prof[i].fullscan_period == 0)) {
18840 break;
18841 }
18842 bytes_written += snprintf(command+bytes_written,
18843 total_len, "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)\n",
18844 rp->roam_prof[i].roam_trigger, rp->roam_prof[i].rssi_lower,
18845 rp->roam_prof[i].channel_usage,
18846 rp->roam_prof[i].cu_avg_calc_dur);
18847 }
18848 err = bytes_written;
18849 goto exit;
18850 } else {
18851 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
18852 /* reading contents of roam profile data from fw and exits
18853 * if code hits any of one of the below condtion, If remaining
18854 * length of buffer is less than roam profile size or if there
18855 * is no valid entry.
18856 */
18857 if (((i * sizeof(wl_roam_prof_t)) > rp->len) ||
18858 (rp->roam_prof[i].fullscan_period == 0)) {
18859 break;
18860 }
18861 }
18862 /* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
18863 if (i != 2) {
18864 WL_ERR(("FW must have 2 rows to fill roam_prof\n"));
18865 err = -EINVAL;
18866 goto exit;
18867 }
18868 /* setting roam profile to fw */
18869 data++;
18870 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
18871 roam_trigger = simple_strtol(data, &data, 10);
18872 if (roam_trigger >= 0) {
18873 WL_ERR(("roam trigger[%d] value must be negative\n", i));
18874 err = -EINVAL;
18875 goto exit;
18876 }
18877 rp->roam_prof[i].roam_trigger = roam_trigger;
18878 data++;
18879 rssi_lower = simple_strtol(data, &data, 10);
18880 if (rssi_lower >= 0) {
18881 WL_ERR(("rssi lower[%d] value must be negative\n", i));
18882 err = -EINVAL;
18883 goto exit;
18884 }
18885 rp->roam_prof[i].rssi_lower = rssi_lower;
18886 data++;
18887 rp->roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
18888 data++;
18889 rp->roam_prof[i].cu_avg_calc_dur = simple_strtol(data, &data, 10);
18890
18891 rp_len += sizeof(wl_roam_prof_t);
18892
18893 if (*data == '\0') {
18894 break;
18895 }
18896 data++;
18897 }
18898 if (i != 1) {
18899 WL_ERR(("Only two roam_prof rows supported.\n"));
18900 err = -EINVAL;
18901 goto exit;
18902 }
18903 rp->len = rp_len;
18904 if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
18905 sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
18906 &cfg->ioctl_buf_sync)) < 0) {
18907 WL_ERR(("seting roam_profile failed with err %d\n", err));
18908 }
18909 }
18910exit:
18911 if (rp) {
18912 kfree(rp);
18913 }
18914 return err;
18915}
18916
18917#define BUFSZ 5
18918
18919#define _S(x) #x
18920#define S(x) _S(x)
18921
18922int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
18923 char *command, int total_len)
18924{
18925 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18926 int bytes_written = 0, err = -EINVAL, argc = 0;
18927 char rssi[BUFSZ], band[BUFSZ], weight[BUFSZ];
18928 char *endptr = NULL;
18929 wnm_bss_select_weight_cfg_t *bwcfg;
18930
18931 bwcfg = kzalloc(sizeof(*bwcfg), GFP_KERNEL);
18932 if (unlikely(!bwcfg)) {
18933 WL_ERR(("%s: failed to allocate memory\n", __func__));
18934 err = -ENOMEM;
18935 goto exit;
18936 }
18937 bwcfg->version = WNM_BSSLOAD_MONITOR_VERSION;
18938 bwcfg->type = 0;
18939 bwcfg->weight = 0;
18940
18941 argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight);
18942
18943 if (!strcasecmp(rssi, "rssi"))
18944 bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
18945 else if (!strcasecmp(rssi, "cu"))
18946 bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
18947 else {
18948 /* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu> <band> <weight> */
18949 WL_ERR(("%s: Command usage error\n", __func__));
18950 goto exit;
18951 }
18952
18953 if (!strcasecmp(band, "a"))
18954 bwcfg->band = WLC_BAND_5G;
18955 else if (!strcasecmp(band, "b"))
18956 bwcfg->band = WLC_BAND_2G;
18957 else if (!strcasecmp(band, "all"))
18958 bwcfg->band = WLC_BAND_ALL;
18959 else {
18960 WL_ERR(("%s: Command usage error\n", __func__));
18961 goto exit;
18962 }
18963
18964 if (argc == 2) {
18965 /* If there is no data after band, getting wnm_bss_select_weight from fw */
18966 if (bwcfg->band == WLC_BAND_ALL) {
18967 WL_ERR(("band option \"all\" is for set only, not get\n"));
18968 goto exit;
18969 }
18970 if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
18971 sizeof(*bwcfg),
18972 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
18973 WL_ERR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
18974 goto exit;
18975 }
18976 memcpy(bwcfg, cfg->ioctl_buf, sizeof(*bwcfg));
18977 bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
18978 (bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU",
18979 (bwcfg->band == WLC_BAND_2G) ? "2G" : "5G", bwcfg->weight);
18980 err = bytes_written;
18981 goto exit;
18982 } else {
18983 /* if weight is non integer returns command usage error */
18984 bwcfg->weight = simple_strtol(weight, &endptr, 0);
18985 if (*endptr != '\0') {
18986 WL_ERR(("%s: Command usage error", __func__));
18987 goto exit;
18988 }
18989 /* setting weight for iovar wnm_bss_select_weight to fw */
18990 if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
18991 sizeof(*bwcfg),
18992 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
18993 WL_ERR(("Getting wnm_bss_select_weight failed with err=%d\n", err));
18994 }
18995 }
18996exit:
18997 if (bwcfg) {
18998 kfree(bwcfg);
18999 }
19000 return err;
19001}
19002
19003/* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
19004#define WBTEXT_TUPLE_MIN_LEN_CHECK 5
19005
19006int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
19007 char *command, int total_len)
19008{
19009 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
19010 int bytes_written = 0, err = -EINVAL;
19011 char rssi[BUFSZ], band[BUFSZ];
19012 int btcfg_len = 0, i = 0, parsed_len = 0;
19013 wnm_bss_select_factor_cfg_t *btcfg;
19014 size_t slen = strlen(data);
19015 char *start_addr = NULL;
19016 data[slen] = '\0';
19017
19018 btcfg = kzalloc((sizeof(*btcfg) + sizeof(*btcfg) *
19019 WL_FACTOR_TABLE_MAX_LIMIT), GFP_KERNEL);
19020 if (unlikely(!btcfg)) {
19021 WL_ERR(("%s: failed to allocate memory\n", __func__));
19022 err = -ENOMEM;
19023 goto exit;
19024 }
19025
19026 btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
19027 btcfg->band = WLC_BAND_AUTO;
19028 btcfg->type = 0;
19029 btcfg->count = 0;
19030
19031 sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band);
19032
19033 if (!strcasecmp(rssi, "rssi")) {
19034 btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
19035 }
19036 else if (!strcasecmp(rssi, "cu")) {
19037 btcfg->type = WNM_BSS_SELECT_TYPE_CU;
19038 }
19039 else {
19040 WL_ERR(("%s: Command usage error\n", __func__));
19041 goto exit;
19042 }
19043
19044 if (!strcasecmp(band, "a")) {
19045 btcfg->band = WLC_BAND_5G;
19046 }
19047 else if (!strcasecmp(band, "b")) {
19048 btcfg->band = WLC_BAND_2G;
19049 }
19050 else if (!strcasecmp(band, "all")) {
19051 btcfg->band = WLC_BAND_ALL;
19052 }
19053 else {
19054 WL_ERR(("%s: Command usage, Wrong band\n", __func__));
19055 goto exit;
19056 }
19057
19058 if ((slen - 1) == (strlen(rssi) + strlen(band))) {
19059 /* Getting factor table using iovar 'wnm_bss_select_table' from fw */
19060 if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
19061 sizeof(*btcfg),
19062 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
19063 WL_ERR(("Getting wnm_bss_select_table failed with err=%d \n", err));
19064 goto exit;
19065 }
19066 memcpy(btcfg, cfg->ioctl_buf, sizeof(*btcfg));
19067 memcpy(btcfg, cfg->ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
19068
19069 bytes_written += snprintf(command + bytes_written, total_len,
19070 "No of entries in table: %d\n", btcfg->count);
19071 bytes_written += snprintf(command + bytes_written, total_len, "%s factor table\n",
19072 (btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
19073 bytes_written += snprintf(command + bytes_written, total_len,
19074 "low\thigh\tfactor\n");
19075 for (i = 0; i <= btcfg->count-1; i++) {
19076 bytes_written += snprintf(command + bytes_written, total_len,
19077 "%d\t%d\t%d\n", btcfg->params[i].low, btcfg->params[i].high,
19078 btcfg->params[i].factor);
19079 }
19080 err = bytes_written;
19081 goto exit;
19082 } else {
19083 memset(btcfg->params, 0, sizeof(wnm_bss_select_factor_params_t)
19084 * WL_FACTOR_TABLE_MAX_LIMIT);
19085 data += (strlen(rssi) + strlen(band) + 2);
19086 start_addr = data;
19087 slen = slen - (strlen(rssi) + strlen(band) + 2);
19088 for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
19089 if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
19090 btcfg->params[i].low = simple_strtol(data, &data, 10);
19091 data++;
19092 btcfg->params[i].high = simple_strtol(data, &data, 10);
19093 data++;
19094 btcfg->params[i].factor = simple_strtol(data, &data, 10);
19095 btcfg->count++;
19096 if (*data == '\0') {
19097 break;
19098 }
19099 data++;
19100 parsed_len = data - start_addr;
19101 } else {
19102 WL_ERR(("%s:Command usage:less no of args\n", __func__));
19103 goto exit;
19104 }
19105 }
19106 btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
19107 if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
19108 cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
19109 WL_ERR(("seting wnm_bss_select_table failed with err %d\n", err));
19110 goto exit;
19111 }
19112 }
19113exit:
19114 if (btcfg) {
19115 kfree(btcfg);
19116 }
19117 return err;
19118}
19119
19120s32
19121wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
19122{
19123 uint i = 0;
19124 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
19125 int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
19126 char delta[BUFSZ], band[BUFSZ], *endptr = NULL;
19127 wl_roam_prof_band_t *rp;
19128
19129 rp = (wl_roam_prof_band_t *) kzalloc(sizeof(*rp)
19130 * WL_MAX_ROAM_PROF_BRACKETS, GFP_KERNEL);
19131 if (unlikely(!rp)) {
19132 WL_ERR(("%s: failed to allocate memory\n", __func__));
19133 err = -ENOMEM;
19134 goto exit;
19135 }
19136
19137 argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta);
19138 if (!strcasecmp(band, "a"))
19139 rp->band = WLC_BAND_5G;
19140 else if (!strcasecmp(band, "b"))
19141 rp->band = WLC_BAND_2G;
19142 else {
19143 WL_ERR(("%s: Missing band\n", __func__));
19144 goto exit;
19145 }
19146 /* Getting roam profile from fw */
19147 if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
19148 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
19149 WL_ERR(("Getting roam_profile failed with err=%d \n", err));
19150 goto exit;
19151 }
19152 memcpy(rp, cfg->ioctl_buf, sizeof(wl_roam_prof_band_t));
19153 if (rp->ver != WL_MAX_ROAM_PROF_VER) {
19154 WL_ERR(("bad version (=%d) in return data\n", rp->ver));
19155 err = -EINVAL;
19156 goto exit;
19157 }
19158 if ((rp->len % sizeof(wl_roam_prof_t)) != 0) {
19159 WL_ERR(("bad length (=%d) in return data\n", rp->len));
19160 err = -EINVAL;
19161 goto exit;
19162 }
19163
19164 if (argc == 2) {
19165 /* if delta is non integer returns command usage error */
19166 val = simple_strtol(delta, &endptr, 0);
19167 if (*endptr != '\0') {
19168 WL_ERR(("%s: Command usage error", __func__));
19169 goto exit;
19170 }
19171 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
19172 /*
19173 * Checking contents of roam profile data from fw and exits
19174 * if code hits below condtion. If remaining length of buffer is
19175 * less than roam profile size or if there is no valid entry.
19176 */
19177 if (((i * sizeof(wl_roam_prof_t)) > rp->len) ||
19178 (rp->roam_prof[i].fullscan_period == 0)) {
19179 break;
19180 }
19181 if (rp->roam_prof[i].channel_usage != 0) {
19182 rp->roam_prof[i].roam_delta = val;
19183 }
19184 len += sizeof(wl_roam_prof_t);
19185 }
19186 }
19187 else {
19188 if (rp->roam_prof[i].channel_usage != 0) {
19189 bytes_written = snprintf(command, total_len,
19190 "%s Delta %d\n", (rp->band == WLC_BAND_2G) ? "2G" : "5G",
19191 rp->roam_prof[0].roam_delta);
19192 }
19193 err = bytes_written;
19194 goto exit;
19195 }
19196 rp->len = len;
19197 if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
19198 sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
19199 WL_ERR(("seting roam_profile failed with err %d\n", err));
19200 }
19201exit :
19202 if (rp) {
19203 kfree(rp);
19204 }
19205 return err;
19206}
19207#endif /* WBTEXT */
19208
19209
19210int wl_cfg80211_scan_stop(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev)
19211{
19212 struct net_device *ndev = NULL;
19213 unsigned long flags;
19214 int clear_flag = 0;
19215 int ret = 0;
19216#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
19217 struct cfg80211_scan_info info;
19218#endif
19219
19220 WL_TRACE(("Enter\n"));
19221
19222 if (!cfg)
19223 return -EINVAL;
19224
19225 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
19226
19227 spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
19228#ifdef WL_CFG80211_P2P_DEV_IF
19229 if (cfg->scan_request && cfg->scan_request->wdev == cfgdev)
19230#else
19231 if (cfg->scan_request && cfg->scan_request->dev == cfgdev)
19232#endif
19233 {
19234#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
19235 info.aborted = true;
19236 cfg80211_scan_done(cfg->scan_request, &info);
19237#else
19238 cfg80211_scan_done(cfg->scan_request, true);
19239#endif
19240 cfg->scan_request = NULL;
19241 clear_flag = 1;
19242 }
19243 spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
19244
19245 if (clear_flag)
19246 wl_clr_drv_status(cfg, SCANNING, ndev);
19247
19248 return ret;
19249}
19250
19251bool wl_cfg80211_is_concurrent_mode(struct net_device *dev)
19252{
19253 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19254 if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
19255 return true;
19256 } else {
19257 return false;
19258 }
19259}
19260
19261void* wl_cfg80211_get_dhdp(struct net_device *dev)
19262{
19263 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19264
19265 return cfg->pub;
19266}
19267
19268bool wl_cfg80211_is_p2p_active(struct net_device *dev)
19269{
19270 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19271 return (cfg && cfg->p2p);
19272}
19273
19274bool wl_cfg80211_is_roam_offload(struct net_device * dev)
19275{
19276 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19277 return (cfg && cfg->roam_offload);
19278}
19279
19280bool wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev, const wl_event_msg_t *e,
19281 int ifidx)
19282{
19283 u8 *curbssid = NULL;
19284 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19285
19286 if (!cfg) {
19287 /* When interface is created using wl
19288 * ndev->ieee80211_ptr will be NULL.
19289 */
19290 return NULL;
19291 }
19292 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
19293
19294 if (!curbssid) {
19295 return NULL;
19296 }
19297
19298 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
19299 return true;
19300 }
19301 return false;
19302}
19303
19304static void wl_cfg80211_work_handler(struct work_struct * work)
19305{
19306 struct bcm_cfg80211 *cfg = NULL;
19307 struct net_info *iter, *next;
19308 s32 err = BCME_OK;
19309 s32 pm = PM_FAST;
19310 dhd_pub_t *dhd;
19311 BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
19312 WL_DBG(("Enter \n"));
19313#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19314 4 && __GNUC_MINOR__ >= 6))
19315_Pragma("GCC diagnostic push")
19316_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
19317#endif
19318 for_each_ndev(cfg, iter, next) {
19319 /* p2p discovery iface ndev could be null */
19320 if (iter->ndev) {
19321 if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
19322 (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
19323 wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
19324 continue;
19325 if (iter->ndev) {
19326 dhd = (dhd_pub_t *)(cfg->pub);
19327 if (dhd_conf_get_pm(dhd) >= 0)
19328 pm = dhd_conf_get_pm(dhd);
19329 if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM,
19330 &pm, sizeof(pm))) != 0) {
19331 if (err == -ENODEV)
19332 WL_DBG(("%s:netdev not ready\n",
19333 iter->ndev->name));
19334 else
19335 WL_ERR(("%s:error (%d)\n",
19336 iter->ndev->name, err));
19337 } else
19338 wl_cfg80211_update_power_mode(iter->ndev);
19339 }
19340 }
19341 }
19342#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19343 4 && __GNUC_MINOR__ >= 6))
19344_Pragma("GCC diagnostic pop")
19345#endif
19346 DHD_PM_WAKE_UNLOCK(cfg->pub);
19347}
19348
19349u8
19350wl_get_action_category(void *frame, u32 frame_len)
19351{
19352 u8 category;
19353 u8 *ptr = (u8 *)frame;
19354 if (frame == NULL)
19355 return DOT11_ACTION_CAT_ERR_MASK;
19356 if (frame_len < DOT11_ACTION_HDR_LEN)
19357 return DOT11_ACTION_CAT_ERR_MASK;
19358 category = ptr[DOT11_ACTION_CAT_OFF];
19359 WL_INFORM(("Action Category: %d\n", category));
19360 return category;
19361}
19362
19363int
19364wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
19365{
19366 u8 *ptr = (u8 *)frame;
19367 if (frame == NULL || ret_action == NULL)
19368 return BCME_ERROR;
19369 if (frame_len < DOT11_ACTION_HDR_LEN)
19370 return BCME_ERROR;
19371 if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
19372 return BCME_ERROR;
19373 *ret_action = ptr[DOT11_ACTION_ACT_OFF];
19374 WL_INFORM(("Public Action : %d\n", *ret_action));
19375 return BCME_OK;
19376}
19377
19378
19379static int
19380wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
19381 const struct ether_addr *bssid)
19382{
19383 s32 err;
19384 wl_event_msg_t e;
19385
19386 bzero(&e, sizeof(e));
19387 e.event_type = cpu_to_be32(WLC_E_ROAM);
19388 memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
19389 /* trigger the roam event handler */
19390 err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
19391
19392 return err;
19393}
19394
19395static s32
19396wl_cfg80211_parse_vndr_ies(u8 *parse, u32 len,
19397 struct parsed_vndr_ies *vndr_ies)
19398{
19399 s32 err = BCME_OK;
19400 vndr_ie_t *vndrie;
19401 bcm_tlv_t *ie;
19402 struct parsed_vndr_ie_info *parsed_info;
19403 u32 count = 0;
19404 s32 remained_len;
19405
19406 remained_len = (s32)len;
19407 memset(vndr_ies, 0, sizeof(*vndr_ies));
19408
19409 WL_DBG(("---> len %d\n", len));
19410 ie = (bcm_tlv_t *) parse;
19411 if (!bcm_valid_tlv(ie, remained_len))
19412 ie = NULL;
19413 while (ie) {
19414 if (count >= MAX_VNDR_IE_NUMBER)
19415 break;
19416 if (ie->id == DOT11_MNG_VS_ID) {
19417 vndrie = (vndr_ie_t *) ie;
19418 /* len should be bigger than OUI length + one data length at least */
19419 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
19420 WL_ERR(("%s: invalid vndr ie. length is too small %d\n",
19421 __FUNCTION__, vndrie->len));
19422 goto end;
19423 }
19424 /* if wpa or wme ie, do not add ie */
19425 if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
19426 ((vndrie->data[0] == WPA_OUI_TYPE) ||
19427 (vndrie->data[0] == WME_OUI_TYPE))) {
19428 WL_DBG(("Found WPA/WME oui. Do not add it\n"));
19429 goto end;
19430 }
19431
19432 parsed_info = &vndr_ies->ie_info[count++];
19433
19434 /* save vndr ie information */
19435 parsed_info->ie_ptr = (char *)vndrie;
19436 parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
19437 memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
19438 vndr_ies->count = count;
19439
19440 WL_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x len:%d\n",
19441 parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1],
19442 parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0],
19443 parsed_info->ie_len));
19444 }
19445end:
19446 ie = bcm_next_tlv(ie, &remained_len);
19447 }
19448 return err;
19449}
19450
19451#ifdef WLADPS_SEAK_AP_WAR
19452static bool
19453wl_find_vndr_ies_specific_vender(struct bcm_cfg80211 *cfg,
19454 struct net_device *ndev, const u8 *vndr_oui)
19455{
19456 struct wl_connect_info *conn_info = wl_to_conn(cfg);
19457 struct parsed_vndr_ie_info *vndr_info_list;
19458 struct parsed_vndr_ies vndr_ies;
19459 bool ret = FALSE;
19460 int i;
19461
19462 if (conn_info->resp_ie_len) {
19463 if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
19464 conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
19465 for (i = 0; i < vndr_ies.count; i++) {
19466 vndr_info_list = &vndr_ies.ie_info[i];
19467 if (!bcmp(vndr_info_list->vndrie.oui,
19468 (u8*)vndr_oui, DOT11_OUI_LEN)) {
19469 WL_ERR(("Find OUI %02x %02x %02x\n",
19470 vndr_info_list->vndrie.oui[0],
19471 vndr_info_list->vndrie.oui[1],
19472 vndr_info_list->vndrie.oui[2]));
19473 ret = TRUE;
19474 break;
19475 }
19476 }
19477 }
19478 }
19479 return ret;
19480}
19481
19482static s32
19483wl_set_adps_mode(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint8 enable_mode)
19484{
19485 int i;
19486 int len;
19487 int ret = BCME_OK;
19488
19489 bcm_iov_buf_t *iov_buf = NULL;
19490 wl_adps_params_v1_t *data = NULL;
19491
19492 len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(*data);
19493 iov_buf = kmalloc(len, GFP_KERNEL);
19494 if (iov_buf == NULL) {
19495 WL_ERR(("%s - failed to allocate %d bytes for iov_buf\n", __FUNCTION__, len));
19496 ret = BCME_NOMEM;
19497 goto exit;
19498 }
19499
19500 iov_buf->version = WL_ADPS_IOV_VER;
19501 iov_buf->len = sizeof(*data);
19502 iov_buf->id = WL_ADPS_IOV_MODE;
19503
19504 data = (wl_adps_params_v1_t *)iov_buf->data;
19505 data->version = ADPS_SUB_IOV_VERSION_1;
19506 data->length = sizeof(*data);
19507 data->mode = enable_mode;
19508
19509 for (i = 1; i <= MAX_BANDS; i++) {
19510 data->band = i;
19511 ret = wldev_iovar_setbuf(ndev, "adps", iov_buf, len,
19512 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
19513 }
19514
19515exit:
19516 if (iov_buf) {
19517 kfree(iov_buf);
19518 }
19519 return ret;
19520
19521}
19522#endif /* WLADPS_SEAK_AP_WAR */
19523
19524static bool
19525wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info *vndr_info)
19526{
19527 int i = 0;
19528
19529 while (exclude_vndr_oui_list[i]) {
19530 if (!memcmp(vndr_info->vndrie.oui,
19531 exclude_vndr_oui_list[i],
19532 DOT11_OUI_LEN)) {
19533 return TRUE;
19534 }
19535 i++;
19536 }
19537
19538 return FALSE;
19539}
19540
19541static bool
19542wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 *cfg,
19543 struct parsed_vndr_ie_info *vndr_info)
19544{
19545 wl_vndr_oui_entry_t *oui_entry = NULL;
19546
19547#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
19548#pragma GCC diagnostic push
19549#pragma GCC diagnostic ignored "-Wcast-qual"
19550#endif
19551 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
19552 if (!memcmp(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN)) {
19553 return TRUE;
19554 }
19555 }
19556#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
19557#pragma GCC diagnostic pop
19558#endif
19559
19560 return FALSE;
19561}
19562
19563static bool
19564wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 *cfg,
19565 struct parsed_vndr_ie_info *vndr_info)
19566{
19567 wl_vndr_oui_entry_t *oui_entry = NULL;
19568
19569 oui_entry = kmalloc(sizeof(*oui_entry), GFP_KERNEL);
19570 if (oui_entry == NULL) {
19571 WL_ERR(("alloc failed\n"));
19572 return FALSE;
19573 }
19574
19575 memcpy(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN);
19576
19577 INIT_LIST_HEAD(&oui_entry->list);
19578 list_add_tail(&oui_entry->list, &cfg->vndr_oui_list);
19579
19580 return TRUE;
19581}
19582
19583static void
19584wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg)
19585{
19586 wl_vndr_oui_entry_t *oui_entry = NULL;
19587
19588#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
19589#pragma GCC diagnostic push
19590#pragma GCC diagnostic ignored "-Wcast-qual"
19591#endif
19592 while (!list_empty(&cfg->vndr_oui_list)) {
19593 oui_entry = list_entry(cfg->vndr_oui_list.next, wl_vndr_oui_entry_t, list);
19594 if (oui_entry) {
19595 list_del(&oui_entry->list);
19596 kfree(oui_entry);
19597 }
19598 }
19599#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
19600#pragma GCC diagnostic pop
19601#endif
19602}
19603
19604static int
19605wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
19606 char *vndr_oui, u32 vndr_oui_len)
19607{
19608 int i;
19609 int vndr_oui_num = 0;
19610
19611 struct wl_connect_info *conn_info = wl_to_conn(cfg);
19612 wl_vndr_oui_entry_t *oui_entry = NULL;
19613 struct parsed_vndr_ie_info *vndr_info;
19614 struct parsed_vndr_ies vndr_ies;
19615
19616 char *pos = vndr_oui;
19617 u32 remained_buf_len = vndr_oui_len;
19618
19619 if (!conn_info->resp_ie_len) {
19620 return BCME_ERROR;
19621 }
19622
19623 wl_vndr_ies_clear_vendor_oui_list(cfg);
19624
19625 if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
19626 conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
19627 for (i = 0; i < vndr_ies.count; i++) {
19628 vndr_info = &vndr_ies.ie_info[i];
19629 if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
19630 continue;
19631 }
19632
19633 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
19634 continue;
19635 }
19636
19637 wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
19638 vndr_oui_num++;
19639 }
19640 }
19641
19642 if (vndr_oui) {
19643#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
19644#pragma GCC diagnostic push
19645#pragma GCC diagnostic ignored "-Wcast-qual"
19646#endif
19647 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
19648 if (remained_buf_len < VNDR_OUI_STR_LEN) {
19649 return BCME_ERROR;
19650 }
19651 pos += snprintf(pos, VNDR_OUI_STR_LEN, "%02X-%02X-%02X ",
19652 oui_entry->oui[0], oui_entry->oui[1], oui_entry->oui[2]);
19653 remained_buf_len -= VNDR_OUI_STR_LEN;
19654 }
19655#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
19656#pragma GCC diagnostic pop
19657#endif
19658 }
19659
19660 return vndr_oui_num;
19661}
19662
19663int
19664wl_cfg80211_get_vndr_ouilist(struct bcm_cfg80211 *cfg, uint8 *buf, int max_cnt)
19665{
19666 wl_vndr_oui_entry_t *oui_entry = NULL;
19667 int cnt = 0;
19668
19669#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
19670#pragma GCC diagnostic push
19671#pragma GCC diagnostic ignored "-Wcast-qual"
19672#endif
19673 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
19674 memcpy(buf, oui_entry->oui, DOT11_OUI_LEN);
19675 cnt++;
19676 if (cnt >= max_cnt) {
19677 return cnt;
19678 }
19679 buf += DOT11_OUI_LEN;
19680 }
19681#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
19682#pragma GCC diagnostic pop
19683#endif
19684 return cnt;
19685}
19686
19687s32
19688wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, s32 bssidx)
19689{
19690 s32 index;
19691 struct net_info *netinfo;
19692 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
19693 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
19694
19695 netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
19696 if (!netinfo || !netinfo->wdev) {
19697 WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
19698 return -1;
19699 }
19700
19701 WL_DBG(("clear management vendor IEs for bssidx:%d \n", bssidx));
19702 /* Clear the IEs set in the firmware so that host is in sync with firmware */
19703 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
19704 if (wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
19705 bssidx, vndrie_flag[index], NULL, 0) < 0)
19706 WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
19707 }
19708
19709 return 0;
19710}
19711
19712s32
19713wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
19714{
19715 struct net_info *iter, *next;
19716
19717 WL_DBG(("clear management vendor IEs \n"));
19718#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19719 4 && __GNUC_MINOR__ >= 6))
19720_Pragma("GCC diagnostic push")
19721_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
19722#endif
19723 for_each_ndev(cfg, iter, next) {
19724 wl_cfg80211_clear_per_bss_ies(cfg, iter->bssidx);
19725 }
19726#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19727 4 && __GNUC_MINOR__ >= 6))
19728_Pragma("GCC diagnostic pop")
19729#endif
19730 return 0;
19731}
19732
19733#define WL_VNDR_IE_MAXLEN 2048
19734static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
19735int
19736wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
19737 s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
19738{
19739 struct net_device *ndev = NULL;
19740 s32 ret = BCME_OK;
19741 u8 *curr_ie_buf = NULL;
19742 u8 *mgmt_ie_buf = NULL;
19743 u32 mgmt_ie_buf_len = 0;
19744 u32 *mgmt_ie_len = 0;
19745 u32 del_add_ie_buf_len = 0;
19746 u32 total_ie_buf_len = 0;
19747 u32 parsed_ie_buf_len = 0;
19748 struct parsed_vndr_ies old_vndr_ies;
19749 struct parsed_vndr_ies new_vndr_ies;
19750 s32 i;
19751 u8 *ptr;
19752 s32 remained_buf_len;
19753 wl_bss_vndr_ies_t *ies = NULL;
19754 struct net_info *netinfo;
19755
19756 WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d \n",
19757 pktflag, bssidx, vndr_ie_len));
19758
19759 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
19760
19761 if (bssidx > WL_MAX_IFS) {
19762 WL_ERR(("bssidx > supported concurrent Ifaces \n"));
19763 return -EINVAL;
19764 }
19765
19766 netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
19767 if (!netinfo) {
19768 WL_ERR(("net_info ptr is NULL \n"));
19769 return -EINVAL;
19770 }
19771
19772 /* Clear the global buffer */
19773 memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf));
19774 curr_ie_buf = g_mgmt_ie_buf;
19775 ies = &netinfo->bss.ies;
19776
19777 switch (pktflag) {
19778 case VNDR_IE_PRBRSP_FLAG :
19779 mgmt_ie_buf = ies->probe_res_ie;
19780 mgmt_ie_len = &ies->probe_res_ie_len;
19781 mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
19782 break;
19783 case VNDR_IE_ASSOCRSP_FLAG :
19784 mgmt_ie_buf = ies->assoc_res_ie;
19785 mgmt_ie_len = &ies->assoc_res_ie_len;
19786 mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
19787 break;
19788 case VNDR_IE_BEACON_FLAG :
19789 mgmt_ie_buf = ies->beacon_ie;
19790 mgmt_ie_len = &ies->beacon_ie_len;
19791 mgmt_ie_buf_len = sizeof(ies->beacon_ie);
19792 break;
19793 case VNDR_IE_PRBREQ_FLAG :
19794 mgmt_ie_buf = ies->probe_req_ie;
19795 mgmt_ie_len = &ies->probe_req_ie_len;
19796 mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
19797 break;
19798 case VNDR_IE_ASSOCREQ_FLAG :
19799 mgmt_ie_buf = ies->assoc_req_ie;
19800 mgmt_ie_len = &ies->assoc_req_ie_len;
19801 mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
19802 break;
19803 default:
19804 mgmt_ie_buf = NULL;
19805 mgmt_ie_len = NULL;
19806 WL_ERR(("not suitable packet type (%d)\n", pktflag));
19807 return BCME_ERROR;
19808 }
19809
19810 if (vndr_ie_len > mgmt_ie_buf_len) {
19811 WL_ERR(("extra IE size too big\n"));
19812 ret = -ENOMEM;
19813 } else {
19814 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
19815 if (vndr_ie && vndr_ie_len && curr_ie_buf) {
19816 ptr = curr_ie_buf;
19817/* must discard vndr_ie constness, attempt to change vndr_ie arg to non-const
19818 * causes cascade of errors in other places, fix involves const casts there
19819 */
19820#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19821 4 && __GNUC_MINOR__ >= 6))
19822_Pragma("GCC diagnostic push")
19823_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
19824#endif
19825 if ((ret = wl_cfg80211_parse_vndr_ies((u8 *)vndr_ie,
19826 vndr_ie_len, &new_vndr_ies)) < 0) {
19827 WL_ERR(("parse vndr ie failed \n"));
19828 goto exit;
19829 }
19830#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19831 4 && __GNUC_MINOR__ >= 6))
19832_Pragma("GCC diagnostic pop")
19833#endif
19834 for (i = 0; i < new_vndr_ies.count; i++) {
19835 struct parsed_vndr_ie_info *vndrie_info =
19836 &new_vndr_ies.ie_info[i];
19837
19838 if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
19839 WL_ERR(("IE size is too big (%d > %d)\n",
19840 parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
19841 ret = -EINVAL;
19842 goto exit;
19843 }
19844
19845 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
19846 vndrie_info->ie_len);
19847 parsed_ie_buf_len += vndrie_info->ie_len;
19848 }
19849 }
19850
19851 if (mgmt_ie_buf != NULL) {
19852 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
19853 (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
19854 WL_INFORM(("Previous mgmt IE is equals to current IE"));
19855 goto exit;
19856 }
19857
19858 /* parse old vndr_ie */
19859 if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
19860 &old_vndr_ies)) < 0) {
19861 WL_ERR(("parse vndr ie failed \n"));
19862 goto exit;
19863 }
19864 /* make a command to delete old ie */
19865 for (i = 0; i < old_vndr_ies.count; i++) {
19866 struct parsed_vndr_ie_info *vndrie_info =
19867 &old_vndr_ies.ie_info[i];
19868
19869 WL_INFORM(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
19870 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
19871 vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
19872 vndrie_info->vndrie.oui[2]));
19873
19874 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
19875 pktflag, vndrie_info->vndrie.oui,
19876 vndrie_info->vndrie.id,
19877 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
19878 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
19879 "del");
19880
19881 curr_ie_buf += del_add_ie_buf_len;
19882 total_ie_buf_len += del_add_ie_buf_len;
19883 }
19884 }
19885
19886 *mgmt_ie_len = 0;
19887 /* Add if there is any extra IE */
19888 if (mgmt_ie_buf && parsed_ie_buf_len) {
19889 ptr = mgmt_ie_buf;
19890
19891 remained_buf_len = mgmt_ie_buf_len;
19892
19893 /* make a command to add new ie */
19894 for (i = 0; i < new_vndr_ies.count; i++) {
19895 struct parsed_vndr_ie_info *vndrie_info =
19896 &new_vndr_ies.ie_info[i];
19897
19898 WL_INFORM(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n",
19899 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
19900 vndrie_info->ie_len - 2,
19901 vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
19902 vndrie_info->vndrie.oui[2]));
19903
19904 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
19905 pktflag, vndrie_info->vndrie.oui,
19906 vndrie_info->vndrie.id,
19907 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
19908 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
19909 "add");
19910
19911 /* verify remained buf size before copy data */
19912 if (remained_buf_len >= vndrie_info->ie_len) {
19913 remained_buf_len -= vndrie_info->ie_len;
19914 } else {
19915 WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
19916 "found vndr ies # = %d(cur %d), remained len %d, "
19917 "cur mgmt_ie_len %d, new ie len = %d\n",
19918 pktflag, new_vndr_ies.count, i, remained_buf_len,
19919 *mgmt_ie_len, vndrie_info->ie_len));
19920 break;
19921 }
19922
19923 /* save the parsed IE in cfg struct */
19924 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
19925 vndrie_info->ie_len);
19926 *mgmt_ie_len += vndrie_info->ie_len;
19927 curr_ie_buf += del_add_ie_buf_len;
19928 total_ie_buf_len += del_add_ie_buf_len;
19929 }
19930 }
19931
19932 if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
19933 ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
19934 total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
19935 bssidx, &cfg->ioctl_buf_sync);
19936 if (ret)
19937 WL_ERR(("vndr ie set error : %d\n", ret));
19938 }
19939 }
19940exit:
19941
19942return ret;
19943}
19944
19945#ifdef WL_CFG80211_ACL
19946static int
19947wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
19948 const struct cfg80211_acl_data *acl)
19949{
19950 int i;
19951 int ret = 0;
19952 int macnum = 0;
19953 int macmode = MACLIST_MODE_DISABLED;
19954 struct maclist *list;
19955
19956 /* get the MAC filter mode */
19957 if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
19958 macmode = MACLIST_MODE_ALLOW;
19959 } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
19960 acl->n_acl_entries) {
19961 macmode = MACLIST_MODE_DENY;
19962 }
19963
19964 /* if acl == NULL, macmode is still disabled.. */
19965 if (macmode == MACLIST_MODE_DISABLED) {
19966 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0)
19967 WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
19968
19969 return ret;
19970 }
19971
19972 macnum = acl->n_acl_entries;
19973 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
19974 WL_ERR(("%s : invalid number of MAC address entries %d\n",
19975 __FUNCTION__, macnum));
19976 return -1;
19977 }
19978
19979 /* allocate memory for the MAC list */
19980 list = (struct maclist*)kmalloc(sizeof(int) +
19981 sizeof(struct ether_addr) * macnum, GFP_KERNEL);
19982 if (!list) {
19983 WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__));
19984 return -1;
19985 }
19986
19987 /* prepare the MAC list */
19988 list->count = htod32(macnum);
19989 for (i = 0; i < macnum; i++) {
19990 memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN);
19991 }
19992 /* set the list */
19993 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0)
19994 WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
19995
19996 kfree(list);
19997
19998 return ret;
19999}
20000#endif /* WL_CFG80211_ACL */
20001
20002#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
20003int wl_chspec_chandef(chanspec_t chanspec,
20004#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
20005 struct cfg80211_chan_def *chandef,
20006#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
20007 struct chan_info *chaninfo,
20008#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
20009struct wiphy *wiphy)
20010
20011{
20012 uint16 freq = 0;
20013 int chan_type = 0;
20014 int channel = 0;
20015 struct ieee80211_channel *chan;
20016
20017 if (!chandef) {
20018 return -1;
20019 }
20020 channel = CHSPEC_CHANNEL(chanspec);
20021
20022 switch (CHSPEC_BW(chanspec)) {
20023 case WL_CHANSPEC_BW_20:
20024 chan_type = NL80211_CHAN_HT20;
20025 break;
20026 case WL_CHANSPEC_BW_40:
20027 {
20028 if (CHSPEC_SB_UPPER(chanspec)) {
20029 channel += CH_10MHZ_APART;
20030 } else {
20031 channel -= CH_10MHZ_APART;
20032 }
20033 }
20034 chan_type = NL80211_CHAN_HT40PLUS;
20035 break;
20036
20037#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
20038 case WL_CHANSPEC_BW_80:
20039 case WL_CHANSPEC_BW_8080:
20040 {
20041 uint16 sb = CHSPEC_CTL_SB(chanspec);
20042
20043 if (sb == WL_CHANSPEC_CTL_SB_LL) {
20044 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
20045 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
20046 channel -= CH_10MHZ_APART;
20047 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
20048 channel += CH_10MHZ_APART;
20049 } else {
20050 /* WL_CHANSPEC_CTL_SB_UU */
20051 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
20052 }
20053
20054 if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_LU)
20055 chan_type = NL80211_CHAN_HT40MINUS;
20056 else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU)
20057 chan_type = NL80211_CHAN_HT40PLUS;
20058 }
20059 break;
20060#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
20061 default:
20062 chan_type = NL80211_CHAN_HT20;
20063 break;
20064
20065 }
20066
20067 if (CHSPEC_IS5G(chanspec))
20068 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
20069 else
20070 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
20071
20072 chan = ieee80211_get_channel(wiphy, freq);
20073 WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
20074 channel, freq, chan_type, chan));
20075
20076 if (unlikely(!chan)) {
20077 /* fw and cfg80211 channel lists are not in sync */
20078 WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
20079 ASSERT(0);
20080 return -EINVAL;
20081 }
20082
20083#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
20084 cfg80211_chandef_create(chandef, chan, chan_type);
20085#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
20086 \
20087 \
20088 \
20089 0)))
20090 chaninfo->freq = freq;
20091 chaninfo->chan_type = chan_type;
20092#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
20093 return 0;
20094}
20095
20096void
20097wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy)
20098{
20099 u32 freq;
20100#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
20101 struct cfg80211_chan_def chandef;
20102#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
20103 \
20104 \
20105 \
20106 0)))
20107 struct chan_info chaninfo;
20108#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
20109
20110 if (!wiphy) {
20111 printf("wiphy is null\n");
20112 return;
20113 }
20114#ifndef ALLOW_CHSW_EVT
20115 /* Channel switch support is only for AP/GO/ADHOC/MESH */
20116 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
20117 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
20118 WL_ERR(("No channel switch notify support for STA/GC\n"));
20119 return;
20120 }
20121#endif /* !ALLOW_CHSW_EVT */
20122#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
20123 if (wl_chspec_chandef(chanspec, &chandef, wiphy))
20124#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
20125 if (wl_chspec_chandef(chanspec, &chaninfo, wiphy))
20126#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
20127 {
20128 WL_ERR(("chspec_chandef failed\n"));
20129 return;
20130 }
20131#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
20132 freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1;
20133 cfg80211_ch_switch_notify(dev, &chandef);
20134#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
20135 freq = chan_info.freq;
20136 cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type);
20137#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
20138
20139 WL_ERR(("Channel switch notification for freq: %d chanspec: 0x%x\n", freq, chanspec));
20140 return;
20141}
20142#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
20143
20144#ifdef WL11ULB
20145s32
20146wl_cfg80211_set_ulb_mode(struct net_device *dev, int mode)
20147{
20148 int ret;
20149 int cur_mode;
20150
20151 ret = wldev_iovar_getint(dev, "ulb_mode", &cur_mode);
20152 if (unlikely(ret)) {
20153 WL_ERR(("[ULB] ulb_mode get failed. ret:%d \n", ret));
20154 return ret;
20155 }
20156
20157 if (cur_mode == mode) {
20158 /* If request mode is same as that of the current mode, then
20159 * do nothing (Avoid unnecessary wl down and up).
20160 */
20161 WL_INFORM(("[ULB] No change in ulb_mode. Do nothing.\n"));
20162 return 0;
20163 }
20164
20165 /* setting of ulb_mode requires wl to be down */
20166 ret = wldev_ioctl_set(dev, WLC_DOWN, NULL, 0);
20167 if (unlikely(ret)) {
20168 WL_ERR(("[ULB] WLC_DOWN command failed:[%d]\n", ret));
20169 return ret;
20170 }
20171
20172 if (mode >= MAX_SUPP_ULB_MODES) {
20173 WL_ERR(("[ULB] unsupported ulb_mode :[%d]\n", mode));
20174 return -EINVAL;
20175 }
20176
20177 ret = wldev_iovar_setint(dev, "ulb_mode", mode);
20178 if (unlikely(ret)) {
20179 WL_ERR(("[ULB] ulb_mode set failed. ret:%d \n", ret));
20180 return ret;
20181 }
20182
20183 ret = wldev_ioctl_set(dev, WLC_UP, NULL, 0);
20184 if (unlikely(ret)) {
20185 WL_ERR(("[ULB] WLC_DOWN command failed:[%d]\n", ret));
20186 return ret;
20187 }
20188
20189 WL_DBG(("[ULB] ulb_mode set to %d successfully \n", mode));
20190
20191 return ret;
20192}
20193
20194static s32
20195wl_cfg80211_ulbbw_to_ulbchspec(u32 bw)
20196{
20197 if (bw == ULB_BW_DISABLED) {
20198 return WL_CHANSPEC_BW_20;
20199 } else if (bw == ULB_BW_10MHZ) {
20200 return WL_CHANSPEC_BW_10;
20201 } else if (bw == ULB_BW_5MHZ) {
20202 return WL_CHANSPEC_BW_5;
20203 } else if (bw == ULB_BW_2P5MHZ) {
20204 return WL_CHANSPEC_BW_2P5;
20205 } else {
20206 WL_ERR(("[ULB] unsupported value for ulb_bw \n"));
20207 return -EINVAL;
20208 }
20209}
20210
20211static chanspec_t
20212wl_cfg80211_ulb_get_min_bw_chspec(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev, s32 bssidx)
20213{
20214 struct net_info *_netinfo;
20215
20216 /*
20217 * Return the chspec value corresponding to the
20218 * BW setting for a particular interface
20219 */
20220 if (wdev) {
20221 /* if wdev is provided, use it */
20222 _netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
20223 } else if (bssidx >= 0) {
20224 /* if wdev is not provided, use it */
20225 _netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
20226 } else {
20227 WL_ERR(("[ULB] wdev/bssidx not provided\n"));
20228 return INVCHANSPEC;
20229 }
20230
20231 if (unlikely(!_netinfo)) {
20232 WL_ERR(("[ULB] net_info is null \n"));
20233 return INVCHANSPEC;
20234 }
20235
20236 if (_netinfo->ulb_bw) {
20237 WL_DBG(("[ULB] wdev_ptr:%p ulb_bw:0x%x \n", _netinfo->wdev, _netinfo->ulb_bw));
20238 return wl_cfg80211_ulbbw_to_ulbchspec(_netinfo->ulb_bw);
20239 } else {
20240 return WL_CHANSPEC_BW_20;
20241 }
20242}
20243
20244static s32
20245wl_cfg80211_get_ulb_bw(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
20246{
20247 struct net_info *_netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
20248
20249 /*
20250 * Return the ulb_bw setting for a
20251 * particular interface
20252 */
20253 if (unlikely(!_netinfo)) {
20254 WL_ERR(("[ULB] net_info is null \n"));
20255 return -1;
20256 }
20257
20258 return _netinfo->ulb_bw;
20259}
20260
20261s32
20262wl_cfg80211_set_ulb_bw(struct net_device *dev,
20263 u32 ulb_bw, char *ifname)
20264{
20265 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20266 int ret;
20267 int mode;
20268 struct net_info *_netinfo = NULL, *iter, *next;
20269 u32 bssidx;
20270
20271 if (!ifname)
20272 return -EINVAL;
20273
20274 WL_DBG(("[ULB] Enter. bw_type:%d \n", ulb_bw));
20275
20276 ret = wldev_iovar_getint(dev, "ulb_mode", &mode);
20277 if (unlikely(ret)) {
20278 WL_ERR(("[ULB] ulb_mode not supported \n"));
20279 return ret;
20280 }
20281
20282 if (mode != ULB_MODE_STD_ALONE_MODE) {
20283 WL_ERR(("[ULB] ulb bw modification allowed only in stand-alone mode\n"));
20284 return -EINVAL;
20285 }
20286
20287 if (ulb_bw >= MAX_SUPP_ULB_BW) {
20288 WL_ERR(("[ULB] unsupported value (%d) for ulb_bw \n", ulb_bw));
20289 return -EINVAL;
20290 }
20291
20292#ifdef WL_CFG80211_P2P_DEV_IF
20293 if (strcmp(ifname, "p2p-dev-wlan0") == 0) {
20294 /* Use wdev corresponding to the dedicated p2p discovery interface */
20295 if (likely(cfg->p2p_wdev)) {
20296 _netinfo = wl_get_netinfo_by_wdev(cfg, cfg->p2p_wdev);
20297 } else {
20298 return -ENODEV;
20299 }
20300 }
20301#endif /* WL_CFG80211_P2P_DEV_IF */
20302 if (!_netinfo) {
20303#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
20304#pragma GCC diagnostic push
20305#pragma GCC diagnostic ignored "-Wcast-qual"
20306#endif
20307 for_each_ndev(cfg, iter, next) {
20308 if (iter->ndev) {
20309 if (strncmp(iter->ndev->name, ifname, strlen(ifname)) == 0) {
20310 _netinfo = wl_get_netinfo_by_netdev(cfg, iter->ndev);
20311 }
20312 }
20313 }
20314#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
20315#pragma GCC diagnostic pop
20316#endif
20317 }
20318
20319 if (!_netinfo)
20320 return -ENODEV;
20321 bssidx = _netinfo->bssidx;
20322 _netinfo->ulb_bw = ulb_bw;
20323
20324
20325 WL_DBG(("[ULB] Applying ulb_bw:%d for bssidx:%d \n", ulb_bw, bssidx));
20326 ret = wldev_iovar_setbuf_bsscfg(dev, "ulb_bw", (void *)&ulb_bw, 4,
20327 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx,
20328 &cfg->ioctl_buf_sync);
20329 if (unlikely(ret)) {
20330 WL_ERR(("[ULB] ulb_bw set failed. ret:%d \n", ret));
20331 return ret;
20332 }
20333
20334 return ret;
20335}
20336#endif /* WL11ULB */
20337
20338static void
20339wl_ap_channel_ind(struct bcm_cfg80211 *cfg,
20340 struct net_device *ndev,
20341 chanspec_t chanspec)
20342{
20343 u32 channel = LCHSPEC_CHANNEL(chanspec);
20344
20345 WL_DBG(("(%s) AP channel:%d chspec:0x%x \n",
20346 ndev->name, channel, chanspec));
20347 if (cfg->ap_oper_channel && (cfg->ap_oper_channel != channel)) {
20348 /*
20349 * If cached channel is different from the channel indicated
20350 * by the event, notify user space about the channel switch.
20351 */
20352#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
20353 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
20354#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
20355 cfg->ap_oper_channel = channel;
20356 }
20357}
20358
20359static s32
20360wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
20361const wl_event_msg_t *e, void *data)
20362{
20363 struct net_device *ndev = NULL;
20364 chanspec_t chanspec;
20365
20366 WL_DBG(("Enter\n"));
20367 if (unlikely(e->status)) {
20368 WL_ERR(("status:0x%x \n", e->status));
20369 return -1;
20370 }
20371
20372 if (!data) {
20373 return -EINVAL;
20374 }
20375
20376 if (likely(cfgdev)) {
20377 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
20378 chanspec = *((chanspec_t *)data);
20379
20380 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
20381 /* For AP/GO role */
20382 wl_ap_channel_ind(cfg, ndev, chanspec);
20383 }
20384 }
20385
20386 return 0;
20387}
20388
20389static s32
20390wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
20391const wl_event_msg_t *e, void *data)
20392{
20393 int error = 0;
20394 u32 chanspec = 0;
20395 struct net_device *ndev = NULL;
20396
20397 WL_DBG(("Enter\n"));
20398 if (unlikely(e->status)) {
20399 WL_ERR(("status:0x%x \n", e->status));
20400 return -1;
20401 }
20402
20403 if (likely(cfgdev)) {
20404 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
20405 error = wldev_iovar_getint(ndev, "chanspec", &chanspec);
20406 if (unlikely(error)) {
20407 WL_ERR(("Get chanspec error: %d \n", error));
20408 return -1;
20409 }
20410
20411 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
20412 /* For AP/GO role */
20413 wl_ap_channel_ind(cfg, ndev, chanspec);
20414 } else {
20415#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
20416 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
20417#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
20418 }
20419
20420 }
20421
20422 return 0;
20423}
20424
20425
20426void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
20427{
20428 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
20429 int err;
20430
20431 /* Clear the security settings on the primary Interface */
20432 err = wldev_iovar_setint(dev, "wsec", 0);
20433 if (unlikely(err)) {
20434 WL_ERR(("wsec clear failed \n"));
20435 }
20436 err = wldev_iovar_setint(dev, "auth", 0);
20437 if (unlikely(err)) {
20438 WL_ERR(("auth clear failed \n"));
20439 }
20440 err = wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
20441 if (unlikely(err)) {
20442 WL_ERR(("wpa_auth clear failed \n"));
20443 }
20444}
20445
20446#ifdef WL_CFG80211_P2P_DEV_IF
20447void wl_cfg80211_del_p2p_wdev(struct net_device *dev)
20448{
20449 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20450 struct wireless_dev *wdev = NULL;
20451
20452 WL_DBG(("Enter \n"));
20453 if (!cfg) {
20454 WL_ERR(("Invalid Ptr\n"));
20455 return;
20456 } else {
20457 wdev = cfg->p2p_wdev;
20458 }
20459
20460 if (wdev && cfg->down_disc_if) {
20461 wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
20462 cfg->down_disc_if = FALSE;
20463 }
20464}
20465#endif /* WL_CFG80211_P2P_DEV_IF */
20466
20467#ifdef GTK_OFFLOAD_SUPPORT
20468#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
20469static s32
20470wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
20471 struct cfg80211_gtk_rekey_data *data)
20472{
20473 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
20474 s32 err = 0;
20475 gtk_keyinfo_t keyinfo;
20476
20477 WL_DBG(("Enter\n"));
20478 if (data == NULL || cfg->p2p_net == dev) {
20479 WL_ERR(("data is NULL or wrong net device\n"));
20480 return -EINVAL;
20481 }
20482#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
20483 prhex("kck", (uchar *) (data->kck), RSN_KCK_LENGTH);
20484 prhex("kek", (uchar *) (data->kek), RSN_KEK_LENGTH);
20485 prhex("replay_ctr", (uchar *) (data->replay_ctr), RSN_REPLAY_LEN);
20486#else
20487 prhex("kck", (uchar *)data->kck, RSN_KCK_LENGTH);
20488 prhex("kek", (uchar *)data->kek, RSN_KEK_LENGTH);
20489 prhex("replay_ctr", (uchar *)data->replay_ctr, RSN_REPLAY_LEN);
20490#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) */
20491 bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH);
20492 bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH);
20493 bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN);
20494
20495 if ((err = wldev_iovar_setbuf(dev, "gtk_key_info", &keyinfo, sizeof(keyinfo),
20496 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync)) < 0) {
20497 WL_ERR(("seting gtk_key_info failed code=%d\n", err));
20498 return err;
20499 }
20500 WL_DBG(("Exit\n"));
20501 return err;
20502}
20503#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
20504#endif /* GTK_OFFLOAD_SUPPORT */
20505
20506#if defined(WL_SUPPORT_AUTO_CHANNEL)
20507int
20508wl_cfg80211_set_spect(struct net_device *dev, int spect)
20509{
20510 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20511 int wlc_down = 1;
20512 int wlc_up = 1;
20513 int err = BCME_OK;
20514
20515 if (!wl_get_drv_status_all(cfg, CONNECTED)) {
20516 err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
20517 if (err) {
20518 WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
20519 return err;
20520 }
20521
20522 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
20523 if (err) {
20524 WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
20525 return err;
20526 }
20527
20528 err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
20529 if (err) {
20530 WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
20531 return err;
20532 }
20533 }
20534 return err;
20535}
20536
20537int
20538wl_cfg80211_get_sta_channel(struct net_device *dev)
20539{
20540 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20541 int channel = 0;
20542
20543 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
20544 channel = cfg->channel;
20545 }
20546 return channel;
20547}
20548#endif /* WL_SUPPORT_AUTO_CHANNEL */
20549#ifdef P2P_LISTEN_OFFLOADING
20550s32
20551wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
20552{
20553 s32 bssidx;
20554 int ret = 0;
20555 int p2plo_pause = 0;
20556 if (!cfg || !cfg->p2p) {
20557 WL_ERR(("Wl %p or cfg->p2p %p is null\n",
20558 cfg, cfg ? cfg->p2p : 0));
20559 return 0;
20560 }
20561
20562 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
20563 ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
20564 "p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
20565 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
20566 if (ret < 0) {
20567 WL_ERR(("p2po_stop Failed :%d\n", ret));
20568 }
20569
20570 return ret;
20571}
20572s32
20573wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
20574{
20575 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20576 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
20577 wl_p2plo_listen_t p2plo_listen;
20578 int ret = -EAGAIN;
20579 int channel = 0;
20580 int period = 0;
20581 int interval = 0;
20582 int count = 0;
20583 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
20584 WL_ERR(("Sending Action Frames. Try it again.\n"));
20585 goto exit;
20586 }
20587
20588 if (wl_get_drv_status_all(cfg, SCANNING)) {
20589 WL_ERR(("Scanning already\n"));
20590 goto exit;
20591 }
20592
20593 if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
20594 WL_ERR(("Scanning being aborted\n"));
20595 goto exit;
20596 }
20597
20598 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
20599 WL_ERR(("p2p listen offloading already running\n"));
20600 goto exit;
20601 }
20602
20603 /* Just in case if it is not enabled */
20604 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
20605 WL_ERR(("cfgp2p_enable discovery failed"));
20606 goto exit;
20607 }
20608
20609 bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
20610
20611 if (len) {
20612 sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
20613 if ((channel == 0) || (period == 0) ||
20614 (interval == 0) || (count == 0)) {
20615 WL_ERR(("Wrong argument %d/%d/%d/%d \n",
20616 channel, period, interval, count));
20617 ret = -EAGAIN;
20618 goto exit;
20619 }
20620 p2plo_listen.period = period;
20621 p2plo_listen.interval = interval;
20622 p2plo_listen.count = count;
20623
20624 WL_ERR(("channel:%d period:%d, interval:%d count:%d\n",
20625 channel, period, interval, count));
20626 } else {
20627 WL_ERR(("Argument len is wrong.\n"));
20628 ret = -EAGAIN;
20629 goto exit;
20630 }
20631
20632 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
20633 sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
20634 bssidx, &cfg->ioctl_buf_sync)) < 0) {
20635 WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
20636 goto exit;
20637 }
20638
20639 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
20640 sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
20641 bssidx, &cfg->ioctl_buf_sync)) < 0) {
20642 WL_ERR(("p2po_listen Failed :%d\n", ret));
20643 goto exit;
20644 }
20645
20646 wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
20647exit :
20648 return ret;
20649}
20650s32
20651wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
20652{
20653 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20654 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
20655 int ret = -EAGAIN;
20656
20657 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
20658 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
20659 bssidx, &cfg->ioctl_buf_sync)) < 0) {
20660 WL_ERR(("p2po_stop Failed :%d\n", ret));
20661 goto exit;
20662 }
20663
20664exit:
20665 return ret;
20666}
20667#endif /* P2P_LISTEN_OFFLOADING */
20668
20669u64
20670wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
20671{
20672 u64 id = 0;
20673 id = ++cfg->last_roc_id;
20674#ifdef P2P_LISTEN_OFFLOADING
20675 if (id == P2PO_COOKIE) {
20676 id = ++cfg->last_roc_id;
20677 }
20678#endif /* P2P_LISTEN_OFFLOADING */
20679 if (id == 0)
20680 id = ++cfg->last_roc_id;
20681 return id;
20682}
20683
20684#if defined(SUPPORT_RANDOM_MAC_SCAN)
20685int
20686wl_cfg80211_set_random_mac(struct net_device *dev, bool enable)
20687{
20688 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20689 int ret;
20690
20691 if (cfg->random_mac_enabled == enable) {
20692 WL_ERR(("Random MAC already %s\n", enable ? "Enabled" : "Disabled"));
20693 return BCME_OK;
20694 }
20695
20696 if (enable) {
20697 ret = wl_cfg80211_random_mac_enable(dev);
20698 } else {
20699 ret = wl_cfg80211_random_mac_disable(dev);
20700 }
20701
20702 if (!ret) {
20703 cfg->random_mac_enabled = enable;
20704 }
20705
20706 return ret;
20707}
20708
20709int
20710wl_cfg80211_random_mac_enable(struct net_device *dev)
20711{
20712 u8 random_mac[ETH_ALEN] = {0, };
20713 u8 rand_bytes[3] = {0, };
20714 s32 err = BCME_ERROR;
20715 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20716
20717 if (wl_get_drv_status_all(cfg, CONNECTED) || wl_get_drv_status_all(cfg, CONNECTING) ||
20718 wl_get_drv_status_all(cfg, AP_CREATED) || wl_get_drv_status_all(cfg, AP_CREATING)) {
20719 WL_ERR(("fail to Set random mac, current state is wrong\n"));
20720 return err;
20721 }
20722
20723 memcpy(random_mac, bcmcfg_to_prmry_ndev(cfg)->dev_addr, ETH_ALEN);
20724 get_random_bytes(&rand_bytes, sizeof(rand_bytes));
20725
20726 if (rand_bytes[2] == 0x0 || rand_bytes[2] == 0xff) {
20727 rand_bytes[2] = 0xf0;
20728 }
20729
20730 memcpy(&random_mac[3], rand_bytes, sizeof(rand_bytes));
20731
20732 err = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr",
20733 random_mac, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
20734
20735 if (err != BCME_OK) {
20736 WL_ERR(("failed to set random generate MAC address\n"));
20737 } else {
20738 WL_ERR(("set mac " MACDBG " to " MACDBG "\n",
20739 MAC2STRDBG((const u8 *)bcmcfg_to_prmry_ndev(cfg)->dev_addr),
20740 MAC2STRDBG((const u8 *)&random_mac)));
20741 WL_ERR(("random MAC enable done"));
20742 }
20743
20744 return err;
20745}
20746
20747int
20748wl_cfg80211_random_mac_disable(struct net_device *dev)
20749{
20750 s32 err = BCME_ERROR;
20751 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20752
20753 WL_ERR(("set original mac " MACDBG "\n",
20754 MAC2STRDBG((const u8 *)bcmcfg_to_prmry_ndev(cfg)->dev_addr)));
20755
20756 err = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr",
20757 bcmcfg_to_prmry_ndev(cfg)->dev_addr, ETH_ALEN,
20758 cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
20759
20760 if (err != BCME_OK) {
20761 WL_ERR(("failed to set original MAC address\n"));
20762 } else {
20763 WL_ERR(("random MAC disable done\n"));
20764 }
20765
20766 return err;
20767}
20768#endif /* SUPPORT_RANDOM_MAC_SCAN */
20769
20770#ifdef WLTDLS
20771static s32
20772wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg, enum wl_tdls_config state, bool auto_mode)
20773{
20774 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
20775 int err = 0;
20776 struct net_info *iter, *next;
20777 int update_reqd = 0;
20778 int enable = 0;
20779 dhd_pub_t *dhdp;
20780 dhdp = (dhd_pub_t *)(cfg->pub);
20781
20782 /*
20783 * TDLS need to be enabled only if we have a single STA/GC
20784 * connection.
20785 */
20786
20787 WL_DBG(("Enter state:%d\n", state));
20788
20789 if (!cfg->tdls_supported) {
20790 /* FW doesn't support tdls. Do nothing */
20791 return -ENODEV;
20792 }
20793
20794 /* Protect tdls config session */
20795 mutex_lock(&cfg->tdls_sync);
20796
20797 if ((state == TDLS_STATE_TEARDOWN)) {
20798 /* Host initiated TDLS tear down */
20799 err = dhd_tdls_enable(ndev, false, auto_mode, NULL);
20800 goto exit;
20801 } else if (state == TDLS_STATE_AP_CREATE) {
20802 /* We don't support tdls while AP/GO is operational */
20803 update_reqd = true;
20804 enable = false;
20805 } else if ((state == TDLS_STATE_CONNECT) || (state == TDLS_STATE_IF_CREATE)) {
20806 if (wl_get_drv_status_all(cfg,
20807 CONNECTED) >= TDLS_MAX_IFACE_FOR_ENABLE) {
20808 /* For STA/GC connect command request, disable
20809 * tdls if we have any concurrent interfaces
20810 * operational.
20811 */
20812 WL_DBG(("Interface limit restriction. disable tdls.\n"));
20813 update_reqd = true;
20814 enable = false;
20815 }
20816 } else if ((state == TDLS_STATE_DISCONNECT) ||
20817 (state == TDLS_STATE_AP_DELETE) ||
20818 (state == TDLS_STATE_SETUP) ||
20819 (state == TDLS_STATE_IF_DELETE)) {
20820 /* Enable back the tdls connection only if we have less than
20821 * or equal to a single STA/GC connection.
20822 */
20823 if (wl_get_drv_status_all(cfg,
20824 CONNECTED) == 0) {
20825 /* If there are no interfaces connected, enable tdls */
20826 update_reqd = true;
20827 enable = true;
20828 } else if (wl_get_drv_status_all(cfg,
20829 CONNECTED) == TDLS_MAX_IFACE_FOR_ENABLE) {
20830 /* We have one interface in CONNECTED state.
20831 * Verify whether its a non-AP interface before
20832 * we enable back tdls.
20833 */
20834#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
20835#pragma GCC diagnostic push
20836#pragma GCC diagnostic ignored "-Wcast-qual"
20837#endif
20838 for_each_ndev(cfg, iter, next) {
20839 if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, ndev)) &&
20840 wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
20841 WL_DBG(("AP/GO operational. Can't enable tdls. \n"));
20842 err = -ENOTSUPP;
20843 goto exit;
20844 }
20845 }
20846#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
20847#pragma GCC diagnostic pop
20848#endif
20849 /* No AP/GO found. Enable back tdls */
20850 update_reqd = true;
20851 enable = true;
20852 } else {
20853 WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
20854 err = -ENOTSUPP;
20855 goto exit;
20856 }
20857 } else {
20858 WL_ERR(("Unknown tdls state:%d \n", state));
20859 err = -EINVAL;
20860 goto exit;
20861 }
20862
20863 if (update_reqd == true) {
20864 if (dhdp->tdls_enable == enable) {
20865 WL_ERR(("No change in tdls state. Do nothing."
20866 " tdls_enable:%d\n", enable));
20867 goto exit;
20868 }
20869 err = wldev_iovar_setint(ndev, "tdls_enable", enable);
20870 if (unlikely(err)) {
20871 WL_ERR(("tdls_enable setting failed. err:%d\n", err));
20872 goto exit;
20873 } else {
20874 WL_DBG(("set tdls_enable: %d done\n", enable));
20875 /* Update the dhd state variable to be in sync */
20876 dhdp->tdls_enable = enable;
20877 if (state == TDLS_STATE_SETUP) {
20878 /* For host initiated setup, apply TDLS params
20879 * Don't propagate errors up for param config
20880 * failures
20881 */
20882 dhd_tdls_enable(ndev, true, auto_mode, NULL);
20883
20884 }
20885 }
20886 } else {
20887 WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
20888 "current_status:%d \n",
20889 state, update_reqd, dhdp->tdls_enable));
20890 }
20891
20892exit:
20893 mutex_unlock(&cfg->tdls_sync);
20894
20895 return err;
20896}
20897#endif /* WLTDLS */
20898
20899struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname)
20900{
20901 struct net_info *iter, *next;
20902 struct net_device *ndev = NULL;
20903
20904#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
20905#pragma GCC diagnostic push
20906#pragma GCC diagnostic ignored "-Wcast-qual"
20907#endif
20908 for_each_ndev(cfg, iter, next) {
20909 if (iter->ndev) {
20910 if (strncmp(iter->ndev->name, ifname, strlen(iter->ndev->name)) == 0) {
20911 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
20912 ndev = iter->ndev;
20913 break;
20914 }
20915 }
20916 }
20917 }
20918#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
20919#pragma GCC diagnostic pop
20920#endif
20921
20922 return ndev;
20923}
20924
20925struct net_device*
20926wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname)
20927{
20928 struct net_info *iter, *next;
20929 struct net_device *ndev = NULL;
20930
20931#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
20932#pragma GCC diagnostic push
20933#pragma GCC diagnostic ignored "-Wcast-qual"
20934#endif
20935 for_each_ndev(cfg, iter, next) {
20936 if (iter->ndev) {
20937 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
20938 ndev = iter->ndev;
20939 break;
20940 }
20941 }
20942 }
20943#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
20944#pragma GCC diagnostic pop
20945#endif
20946
20947 return ndev;
20948}
20949
20950#ifdef SUPPORT_AP_HIGHER_BEACONRATE
20951#define WLC_RATE_FLAG 0x80
20952#define RATE_MASK 0x7f
20953
20954int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname)
20955{
20956 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20957 dhd_pub_t *dhdp;
20958 wl_rateset_args_t rs;
20959 int error = BCME_ERROR, i;
20960 struct net_device *ndev = NULL;
20961
20962 dhdp = (dhd_pub_t *)(cfg->pub);
20963
20964 if (dhdp && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
20965 WL_ERR(("Not Hostapd mode\n"));
20966 return BCME_NOTAP;
20967 }
20968
20969 ndev = wl_get_ap_netdev(cfg, ifname);
20970
20971 if (ndev == NULL) {
20972 WL_ERR(("No softAP interface named %s\n", ifname));
20973 return BCME_NOTAP;
20974 }
20975
20976 bzero(&rs, sizeof(wl_rateset_args_t));
20977 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
20978 &rs, sizeof(wl_rateset_args_t), NULL);
20979 if (error < 0) {
20980 WL_ERR(("get rateset failed = %d\n", error));
20981 return error;
20982 }
20983
20984 if (rs.count < 1) {
20985 WL_ERR(("Failed to get rate count\n"));
20986 return BCME_ERROR;
20987 }
20988
20989 /* Host delivers target rate in the unit of 500kbps */
20990 /* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic rate */
20991 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
20992 if (rs.rates[i] & WLC_RATE_FLAG)
20993 if ((rs.rates[i] & RATE_MASK) == val)
20994 break;
20995
20996 /* Valid rate has been delivered as an argument */
20997 if (i < rs.count && i < WL_NUMRATES) {
20998 error = wldev_iovar_setint(ndev, "force_bcn_rspec", val);
20999 if (error < 0) {
21000 WL_ERR(("set beacon rate failed = %d\n", error));
21001 return BCME_ERROR;
21002 }
21003 } else {
21004 WL_ERR(("Rate is invalid"));
21005 return BCME_BADARG;
21006 }
21007
21008 return BCME_OK;
21009}
21010
21011int
21012wl_get_ap_basic_rate(struct net_device *dev, char* command, char *ifname, int total_len)
21013{
21014 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21015 dhd_pub_t *dhdp;
21016 wl_rateset_args_t rs;
21017 int error = BCME_ERROR;
21018 int i, bytes_written = 0;
21019 struct net_device *ndev = NULL;
21020
21021 dhdp = (dhd_pub_t *)(cfg->pub);
21022
21023 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
21024 WL_ERR(("Not Hostapd mode\n"));
21025 return BCME_NOTAP;
21026 }
21027
21028 ndev = wl_get_ap_netdev(cfg, ifname);
21029
21030 if (ndev == NULL) {
21031 WL_ERR(("No softAP interface named %s\n", ifname));
21032 return BCME_NOTAP;
21033 }
21034
21035 bzero(&rs, sizeof(wl_rateset_args_t));
21036 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
21037 &rs, sizeof(wl_rateset_args_t), NULL);
21038 if (error < 0) {
21039 WL_ERR(("get rateset failed = %d\n", error));
21040 return error;
21041 }
21042
21043 if (rs.count < 1) {
21044 WL_ERR(("Failed to get rate count\n"));
21045 return BCME_ERROR;
21046 }
21047
21048 /* Delivers basic rate in the unit of 500kbps to host */
21049 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
21050 if (rs.rates[i] & WLC_RATE_FLAG)
21051 bytes_written += snprintf(command + bytes_written, total_len,
21052 "%d ", rs.rates[i] & RATE_MASK);
21053
21054 /* Remove last space in the command buffer */
21055 if (bytes_written) {
21056 command[bytes_written - 1] = '\0';
21057 bytes_written--;
21058 }
21059
21060 return bytes_written;
21061
21062}
21063#endif /* SUPPORT_AP_HIGHER_BEACONRATE */
21064
21065#ifdef SUPPORT_AP_RADIO_PWRSAVE
21066static int
21067_wl_update_ap_rps_params(struct net_device *dev)
21068{
21069 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21070 rpsnoa_iovar_params_t iovar;
21071 u8 smbuf[WLC_IOCTL_SMLEN];
21072
21073 if (!dev)
21074 return BCME_BADARG;
21075
21076 memset(&iovar, 0, sizeof(iovar));
21077 memset(smbuf, 0, sizeof(smbuf));
21078
21079 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
21080 iovar.hdr.subcmd = WL_RPSNOA_CMD_PARAMS;
21081 iovar.hdr.len = sizeof(iovar);
21082 iovar.param->band = WLC_BAND_ALL;
21083 iovar.param->level = cfg->ap_rps_info.level;
21084 iovar.param->stas_assoc_check = cfg->ap_rps_info.sta_assoc_check;
21085 iovar.param->pps = cfg->ap_rps_info.pps;
21086 iovar.param->quiet_time = cfg->ap_rps_info.quiet_time;
21087
21088 if (wldev_iovar_setbuf(dev, "rpsnoa", &iovar, sizeof(iovar),
21089 smbuf, sizeof(smbuf), NULL)) {
21090 WL_ERR(("Failed to set rpsnoa params"));
21091 return BCME_ERROR;
21092 }
21093
21094 return BCME_OK;
21095}
21096
21097int
21098wl_get_ap_rps(struct net_device *dev, char* command, char *ifname, int total_len)
21099{
21100 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21101 dhd_pub_t *dhdp;
21102 int error = BCME_ERROR;
21103 int bytes_written = 0;
21104 struct net_device *ndev = NULL;
21105 rpsnoa_iovar_t iovar;
21106 u8 smbuf[WLC_IOCTL_SMLEN];
21107 u32 chanspec = 0;
21108 u8 idx = 0;
21109 u8 val;
21110
21111 dhdp = (dhd_pub_t *)(cfg->pub);
21112
21113 if (!dhdp) {
21114 error = BCME_NOTUP;
21115 goto fail;
21116 }
21117
21118 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
21119 WL_ERR(("Not Hostapd mode\n"));
21120 error = BCME_NOTAP;
21121 goto fail;
21122 }
21123
21124 ndev = wl_get_ap_netdev(cfg, ifname);
21125
21126 if (ndev == NULL) {
21127 WL_ERR(("No softAP interface named %s\n", ifname));
21128 error = BCME_NOTAP;
21129 goto fail;
21130 }
21131
21132 memset(&iovar, 0, sizeof(iovar));
21133 memset(smbuf, 0, sizeof(smbuf));
21134
21135 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
21136 iovar.hdr.subcmd = WL_RPSNOA_CMD_STATUS;
21137 iovar.hdr.len = sizeof(iovar);
21138 iovar.data->band = WLC_BAND_ALL;
21139
21140 error = wldev_iovar_getbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
21141 smbuf, sizeof(smbuf), NULL);
21142 if (error < 0) {
21143 WL_ERR(("get ap radio pwrsave failed = %d\n", error));
21144 goto fail;
21145 }
21146
21147 /* RSDB event doesn't seem to be handled correctly.
21148 * So check chanspec of AP directly from the firmware
21149 */
21150 error = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
21151 if (error < 0) {
21152 WL_ERR(("get chanspec from AP failed = %d\n", error));
21153 goto fail;
21154 }
21155
21156 chanspec = wl_chspec_driver_to_host(chanspec);
21157 if (CHSPEC_IS2G(chanspec))
21158 idx = 0;
21159 else if (CHSPEC_IS5G(chanspec))
21160 idx = 1;
21161 else {
21162 error = BCME_BADCHAN;
21163 goto fail;
21164 }
21165
21166 val = ((rpsnoa_iovar_t *)smbuf)->data[idx].value;
21167 bytes_written += snprintf(command + bytes_written, total_len, "%d", val);
21168 error = bytes_written;
21169
21170fail:
21171 return error;
21172}
21173
21174int
21175wl_set_ap_rps(struct net_device *dev, bool enable, char *ifname)
21176{
21177 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21178 dhd_pub_t *dhdp;
21179 struct net_device *ndev = NULL;
21180 rpsnoa_iovar_t iovar;
21181 u8 smbuf[WLC_IOCTL_SMLEN];
21182 int ret = BCME_OK;
21183
21184 dhdp = (dhd_pub_t *)(cfg->pub);
21185
21186 if (!dhdp) {
21187 ret = BCME_NOTUP;
21188 goto exit;
21189 }
21190
21191 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
21192 WL_ERR(("Not Hostapd mode\n"));
21193 ret = BCME_NOTAP;
21194 goto exit;
21195 }
21196
21197 ndev = wl_get_ap_netdev(cfg, ifname);
21198
21199 if (ndev == NULL) {
21200 WL_ERR(("No softAP interface named %s\n", ifname));
21201 ret = BCME_NOTAP;
21202 goto exit;
21203 }
21204
21205 if (cfg->ap_rps_info.enable != enable) {
21206 cfg->ap_rps_info.enable = enable;
21207 if (enable) {
21208 ret = _wl_update_ap_rps_params(ndev);
21209 if (ret) {
21210 WL_ERR(("Filed to update rpsnoa params\n"));
21211 goto exit;
21212 }
21213 }
21214 memset(&iovar, 0, sizeof(iovar));
21215 memset(smbuf, 0, sizeof(smbuf));
21216
21217 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
21218 iovar.hdr.subcmd = WL_RPSNOA_CMD_ENABLE;
21219 iovar.hdr.len = sizeof(iovar);
21220 iovar.data->band = WLC_BAND_ALL;
21221 iovar.data->value = (int16)enable;
21222
21223 ret = wldev_iovar_setbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
21224 smbuf, sizeof(smbuf), NULL);
21225 if (ret) {
21226 WL_ERR(("Failed to enable AP radio power save"));
21227 goto exit;
21228 }
21229 cfg->ap_rps_info.enable = enable;
21230 }
21231exit:
21232 return ret;
21233}
21234
21235int
21236wl_update_ap_rps_params(struct net_device *dev, ap_rps_info_t* rps, char *ifname)
21237{
21238 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21239 dhd_pub_t *dhdp;
21240 struct net_device *ndev = NULL;
21241
21242 dhdp = (dhd_pub_t *)(cfg->pub);
21243
21244 if (!dhdp)
21245 return BCME_NOTUP;
21246
21247 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
21248 WL_ERR(("Not Hostapd mode\n"));
21249 return BCME_NOTAP;
21250 }
21251
21252 ndev = wl_get_ap_netdev(cfg, ifname);
21253
21254 if (ndev == NULL) {
21255 WL_ERR(("No softAP interface named %s\n", ifname));
21256 return BCME_NOTAP;
21257 }
21258
21259 if (!rps)
21260 return BCME_BADARG;
21261
21262 if (rps->pps < RADIO_PWRSAVE_PPS_MIN)
21263 return BCME_BADARG;
21264
21265 if (rps->level < RADIO_PWRSAVE_LEVEL_MIN ||
21266 rps->level > RADIO_PWRSAVE_LEVEL_MAX)
21267 return BCME_BADARG;
21268
21269 if (rps->quiet_time < RADIO_PWRSAVE_QUIETTIME_MIN)
21270 return BCME_BADARG;
21271
21272 if (rps->sta_assoc_check > RADIO_PWRSAVE_ASSOCCHECK_MAX ||
21273 rps->sta_assoc_check < RADIO_PWRSAVE_ASSOCCHECK_MIN)
21274 return BCME_BADARG;
21275
21276 cfg->ap_rps_info.pps = rps->pps;
21277 cfg->ap_rps_info.level = rps->level;
21278 cfg->ap_rps_info.quiet_time = rps->quiet_time;
21279 cfg->ap_rps_info.sta_assoc_check = rps->sta_assoc_check;
21280
21281 if (cfg->ap_rps_info.enable) {
21282 if (_wl_update_ap_rps_params(ndev)) {
21283 WL_ERR(("Failed to update rpsnoa params"));
21284 return BCME_ERROR;
21285 }
21286 }
21287
21288 return BCME_OK;
21289}
21290
21291void
21292wl_cfg80211_init_ap_rps(struct bcm_cfg80211 *cfg)
21293{
21294 cfg->ap_rps_info.enable = FALSE;
21295 cfg->ap_rps_info.sta_assoc_check = RADIO_PWRSAVE_STAS_ASSOC_CHECK;
21296 cfg->ap_rps_info.pps = RADIO_PWRSAVE_PPS;
21297 cfg->ap_rps_info.quiet_time = RADIO_PWRSAVE_QUIET_TIME;
21298 cfg->ap_rps_info.level = RADIO_PWRSAVE_LEVEL;
21299}
21300#endif /* SUPPORT_AP_RADIO_PWRSAVE */
21301
21302int
21303wl_cfg80211_iface_count(struct net_device *dev)
21304{
21305 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21306 struct net_info *iter, *next;
21307 int iface_count = 0;
21308
21309 /* Return the count of network interfaces (skip netless p2p discovery
21310 * interface)
21311 */
21312#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
21313#pragma GCC diagnostic push
21314#pragma GCC diagnostic ignored "-Wcast-qual"
21315#endif
21316 for_each_ndev(cfg, iter, next) {
21317 if (iter->ndev) {
21318 iface_count++;
21319 }
21320 }
21321#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
21322#pragma GCC diagnostic pop
21323#endif
21324 return iface_count;
21325}
21326
21327#ifdef WBTEXT
21328static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
21329{
21330 wl_wbtext_bssid_t *bssid = NULL;
21331#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
21332#pragma GCC diagnostic push
21333#pragma GCC diagnostic ignored "-Wcast-qual"
21334#endif
21335
21336 /* check duplicate */
21337 list_for_each_entry(bssid, &cfg->wbtext_bssid_list, list) {
21338 if (!memcmp(bssid->ea.octet, ea, ETHER_ADDR_LEN)) {
21339 return FALSE;
21340 }
21341 }
21342
21343 return TRUE;
21344}
21345
21346static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
21347{
21348 wl_wbtext_bssid_t *bssid = NULL;
21349 char eabuf[ETHER_ADDR_STR_LEN];
21350
21351 bssid = kmalloc(sizeof(wl_wbtext_bssid_t), GFP_KERNEL);
21352 if (bssid == NULL) {
21353 WL_ERR(("alloc failed\n"));
21354 return FALSE;
21355 }
21356
21357 memcpy(bssid->ea.octet, ea, ETHER_ADDR_LEN);
21358
21359 INIT_LIST_HEAD(&bssid->list);
21360 list_add_tail(&bssid->list, &cfg->wbtext_bssid_list);
21361
21362 WL_DBG(("add wbtext bssid : %s\n", bcm_ether_ntoa(ea, eabuf)));
21363
21364 return TRUE;
21365}
21366
21367static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg)
21368{
21369 wl_wbtext_bssid_t *bssid = NULL;
21370 char eabuf[ETHER_ADDR_STR_LEN];
21371
21372 while (!list_empty(&cfg->wbtext_bssid_list)) {
21373 bssid = list_entry(cfg->wbtext_bssid_list.next, wl_wbtext_bssid_t, list);
21374 if (bssid) {
21375 WL_DBG(("clear wbtext bssid : %s\n", bcm_ether_ntoa(&bssid->ea, eabuf)));
21376 list_del(&bssid->list);
21377 kfree(bssid);
21378 }
21379 }
21380}
21381
21382static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev)
21383{
21384 struct wl_connect_info *conn_info = wl_to_conn(cfg);
21385 bcm_tlv_t * cap_ie = NULL;
21386 bool req_sent = FALSE;
21387 struct wl_profile *profile;
21388
21389 WL_DBG(("Enter\n"));
21390
21391 profile = wl_get_profile_by_netdev(cfg, dev);
21392 if (!profile) {
21393 WL_ERR(("no profile exists\n"));
21394 return;
21395 }
21396
21397 if (wl_cfg80211_wbtext_check_bssid_list(cfg,
21398 (struct ether_addr *)&profile->bssid) == FALSE) {
21399 WL_DBG(("already updated\n"));
21400 return;
21401 }
21402
21403 /* first, check NBR bit in RRM IE */
21404 if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
21405 DOT11_MNG_RRM_CAP_ID)) != NULL) {
21406 if (isset(cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
21407 req_sent = wl_cfg80211_wbtext_send_nbr_req(cfg, dev, profile);
21408 }
21409 }
21410
21411 /* if RRM nbr was not supported, check BTM bit in extend cap. IE */
21412 if (!req_sent) {
21413 if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
21414 DOT11_MNG_EXT_CAP_ID)) != NULL) {
21415 if (cap_ie->len >= DOT11_EXTCAP_LEN_BSSTRANS &&
21416 isset(cap_ie->data, DOT11_EXT_CAP_BSSTRANS_MGMT)) {
21417 wl_cfg80211_wbtext_send_btm_query(cfg, dev, profile);
21418 }
21419 }
21420 }
21421}
21422
21423static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
21424 struct wl_profile *profile)
21425{
21426 int error = -1;
21427 char *smbuf = NULL;
21428 struct wl_connect_info *conn_info = wl_to_conn(cfg);
21429 bcm_tlv_t * rrm_cap_ie = NULL;
21430 wlc_ssid_t *ssid = NULL;
21431 bool ret = FALSE;
21432
21433 WL_DBG(("Enter\n"));
21434
21435 /* check RRM nbr bit in extend cap. IE of assoc response */
21436 if ((rrm_cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
21437 DOT11_MNG_RRM_CAP_ID)) != NULL) {
21438 if (!isset(rrm_cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
21439 WL_DBG(("AP doesn't support neighbor report\n"));
21440 return FALSE;
21441 }
21442 }
21443
21444 smbuf = (char *) kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
21445 if (smbuf == NULL) {
21446 WL_ERR(("failed to allocated memory\n"));
21447 goto nbr_req_out;
21448 }
21449
21450 ssid = (wlc_ssid_t *) kzalloc(sizeof(wlc_ssid_t), GFP_KERNEL);
21451 if (ssid == NULL) {
21452 WL_ERR(("failed to allocated memory\n"));
21453 goto nbr_req_out;
21454 }
21455
21456 ssid->SSID_len = MIN(profile->ssid.SSID_len, DOT11_MAX_SSID_LEN);
21457 memcpy(ssid->SSID, profile->ssid.SSID, ssid->SSID_len);
21458
21459 error = wldev_iovar_setbuf(dev, "rrm_nbr_req", ssid,
21460 sizeof(wlc_ssid_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
21461 if (error == BCME_OK) {
21462 ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
21463 (struct ether_addr *)&profile->bssid);
21464 } else {
21465 WL_ERR(("failed to send neighbor report request, error=%d\n", error));
21466 }
21467
21468nbr_req_out:
21469 if (ssid) {
21470 kfree(ssid);
21471 }
21472
21473 if (smbuf) {
21474 kfree(smbuf);
21475 }
21476 return ret;
21477}
21478
21479static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
21480 struct wl_profile *profile)
21481
21482{
21483 int error = -1;
21484 bool ret = FALSE;
21485
21486 WL_DBG(("Enter\n"));
21487
21488 error = wldev_iovar_setbuf(dev, "wnm_bsstrans_query", NULL,
21489 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
21490 if (error == BCME_OK) {
21491 ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
21492 (struct ether_addr *)&profile->bssid);
21493 } else {
21494 WL_ERR(("%s: failed to set BTM query, error=%d\n", __FUNCTION__, error));
21495 }
21496 return ret;
21497}
21498
21499static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev)
21500{
21501 keepalives_max_idle_t keepalive = {0, 0, 0, 0};
21502 s32 bssidx, error;
21503 int wnm_maxidle = 0;
21504 struct wl_connect_info *conn_info = wl_to_conn(cfg);
21505
21506 /* AP supports wnm max idle ? */
21507 if (bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
21508 DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID) != NULL) {
21509 error = wldev_iovar_getint(dev, "wnm_maxidle", &wnm_maxidle);
21510 if (error < 0) {
21511 WL_ERR(("failed to get wnm max idle period : %d\n", error));
21512 }
21513 }
21514
21515 WL_DBG(("wnm max idle period : %d\n", wnm_maxidle));
21516
21517 /* if wnm maxidle has valid period, set it as keep alive */
21518 if (wnm_maxidle > 0) {
21519 keepalive.keepalive_count = 1;
21520 }
21521
21522 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) >= 0) {
21523 error = wldev_iovar_setbuf_bsscfg(dev, "wnm_keepalives_max_idle", &keepalive,
21524 sizeof(keepalives_max_idle_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
21525 bssidx, &cfg->ioctl_buf_sync);
21526 if (error < 0) {
21527 WL_ERR(("set wnm_keepalives_max_idle failed : %d\n", error));
21528 }
21529 }
21530}
21531
21532static int
21533wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, int body_len)
21534{
21535 dot11_rm_action_t *rm_rep;
21536 bcm_tlv_t *tlvs;
21537 int tlv_len, i, error;
21538 dot11_neighbor_rep_ie_t *nbr_rep_ie;
21539 chanspec_t ch;
21540 wl_roam_channel_list_t channel_list;
21541 char iobuf[WLC_IOCTL_SMLEN];
21542
21543 if (body_len < DOT11_RM_ACTION_LEN) {
21544 WL_ERR(("Received Neighbor Report frame with incorrect length %d\n",
21545 body_len));
21546 return BCME_ERROR;
21547 }
21548
21549 rm_rep = (dot11_rm_action_t *)body;
21550 WL_DBG(("received neighbor report (token = %d)\n", rm_rep->token));
21551
21552 tlvs = (bcm_tlv_t *)&rm_rep->data[0];
21553
21554 tlv_len = body_len - DOT11_RM_ACTION_LEN;
21555
21556 while (tlvs && tlvs->id == DOT11_MNG_NEIGHBOR_REP_ID) {
21557 nbr_rep_ie = (dot11_neighbor_rep_ie_t *)tlvs;
21558
21559 if (nbr_rep_ie->len < DOT11_NEIGHBOR_REP_IE_FIXED_LEN) {
21560 WL_ERR(("malformed Neighbor Report element with length %d\n",
21561 nbr_rep_ie->len));
21562 tlvs = bcm_next_tlv(tlvs, &tlv_len);
21563 continue;
21564 }
21565
21566 ch = CH20MHZ_CHSPEC(nbr_rep_ie->channel);
21567 WL_DBG(("ch:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x\n",
21568 ch, nbr_rep_ie->bssid.octet[0], nbr_rep_ie->bssid.octet[1],
21569 nbr_rep_ie->bssid.octet[2], nbr_rep_ie->bssid.octet[3],
21570 nbr_rep_ie->bssid.octet[4], nbr_rep_ie->bssid.octet[5]));
21571
21572 /* get RCC list */
21573 error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0,
21574 (void *)&channel_list, sizeof(channel_list), NULL);
21575 if (error) {
21576 WL_ERR(("Failed to get roamscan channels, error = %d\n", error));
21577 return BCME_ERROR;
21578 }
21579
21580 /* update RCC */
21581 if (channel_list.n < MAX_ROAM_CHANNEL) {
21582 for (i = 0; i < channel_list.n; i++) {
21583 if (channel_list.channels[i] == ch) {
21584 break;
21585 }
21586 }
21587 if (i == channel_list.n) {
21588 channel_list.channels[channel_list.n] = ch;
21589 channel_list.n++;
21590 }
21591 }
21592
21593 /* set RCC list */
21594 error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list,
21595 sizeof(channel_list), iobuf, sizeof(iobuf), NULL);
21596 if (error) {
21597 WL_DBG(("Failed to set roamscan channels, error = %d\n", error));
21598 }
21599
21600 tlvs = bcm_next_tlv(tlvs, &tlv_len);
21601 }
21602
21603 return BCME_OK;
21604}
21605#endif /* WBTEXT */
21606
21607#ifdef SUPPORT_SET_CAC
21608static void
21609wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable)
21610{
21611 int ret = 0;
21612 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
21613
21614 WL_DBG(("cac enable %d, op_mode 0x%04x\n", enable, dhd->op_mode));
21615 if (!dhd) {
21616 WL_ERR(("dhd is NULL\n"));
21617 return;
21618 }
21619 if (enable && ((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) ||
21620 (dhd->op_mode & DHD_FLAG_P2P_GC_MODE) ||
21621 (dhd->op_mode & DHD_FLAG_P2P_GO_MODE))) {
21622 WL_ERR(("op_mode 0x%04x\n", dhd->op_mode));
21623 enable = 0;
21624 }
21625 if ((ret = dhd_wl_ioctl_set_intiovar(dhd, "cac", enable,
21626 WLC_SET_VAR, TRUE, 0)) < 0) {
21627 WL_ERR(("Failed set CAC, ret=%d\n", ret));
21628 } else {
21629 WL_DBG(("CAC set successfully\n"));
21630 }
21631 return;
21632}
21633#endif /* SUPPORT_SET_CAC */
21634
21635#ifdef SUPPORT_RSSI_LOGGING
21636int
21637wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void *param)
21638{
21639 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21640 wl_rssi_ant_mimo_t *get_param = (wl_rssi_ant_mimo_t *)param;
21641 rssi_ant_param_t *set_param = NULL;
21642 struct net_device *ifdev = NULL;
21643 char iobuf[WLC_IOCTL_SMLEN];
21644 int err = BCME_OK;
21645 int iftype = 0;
21646
21647 memset(iobuf, 0, WLC_IOCTL_SMLEN);
21648
21649 /* Check the interface type */
21650 ifdev = wl_get_netdev_by_name(cfg, ifname);
21651 if (ifdev == NULL) {
21652 WL_ERR(("Could not find net_device for ifname:%s\n", ifname));
21653 err = BCME_BADARG;
21654 goto fail;
21655 }
21656
21657 iftype = ifdev->ieee80211_ptr->iftype;
21658 if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO) {
21659 if (peer_mac) {
21660 set_param = (rssi_ant_param_t *)kzalloc(sizeof(rssi_ant_param_t),
21661 GFP_KERNEL);
21662 err = wl_cfg80211_ether_atoe(peer_mac, &set_param->ea);
21663 if (!err) {
21664 WL_ERR(("Invalid Peer MAC format\n"));
21665 err = BCME_BADARG;
21666 goto fail;
21667 }
21668 } else {
21669 WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype));
21670 err = BCME_BADARG;
21671 goto fail;
21672 }
21673 }
21674
21675 err = wldev_iovar_getbuf(ifdev, "phy_rssi_ant", peer_mac ?
21676 (void *)&(set_param->ea) : NULL, peer_mac ? ETHER_ADDR_LEN : 0,
21677 (void *)iobuf, sizeof(iobuf), NULL);
21678 if (unlikely(err)) {
21679 WL_ERR(("Failed to get rssi info, err=%d\n", err));
21680 } else {
21681 memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t));
21682 if (get_param->count == 0) {
21683 WL_ERR(("Not supported on this chip\n"));
21684 err = BCME_UNSUPPORTED;
21685 }
21686 }
21687
21688fail:
21689 if (set_param) {
21690 kfree(set_param);
21691 }
21692
21693 return err;
21694}
21695
21696int
21697wl_get_rssi_logging(struct net_device *dev, void *param)
21698{
21699 rssilog_get_param_t *get_param = (rssilog_get_param_t *)param;
21700 char iobuf[WLC_IOCTL_SMLEN];
21701 int err = BCME_OK;
21702
21703 memset(iobuf, 0, WLC_IOCTL_SMLEN);
21704 memset(get_param, 0, sizeof(*get_param));
21705 err = wldev_iovar_getbuf(dev, "rssilog", NULL, 0, (void *)iobuf,
21706 sizeof(iobuf), NULL);
21707 if (err) {
21708 WL_ERR(("Failed to get rssi logging info, err=%d\n", err));
21709 } else {
21710 memcpy(get_param, iobuf, sizeof(*get_param));
21711 }
21712
21713 return err;
21714}
21715
21716int
21717wl_set_rssi_logging(struct net_device *dev, void *param)
21718{
21719 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21720 rssilog_set_param_t *set_param = (rssilog_set_param_t *)param;
21721 int err;
21722
21723 err = wldev_iovar_setbuf(dev, "rssilog", set_param,
21724 sizeof(*set_param), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
21725 &cfg->ioctl_buf_sync);
21726 if (err) {
21727 WL_ERR(("Failed to set rssi logging param, err=%d\n", err));
21728 }
21729
21730 return err;
21731}
21732#endif /* SUPPORT_RSSI_LOGGING */
d964ce36 21733
32c27b7a
RC
21734s32
21735wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len)
d964ce36 21736{
21737 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21738 int ret = 0;
21739 int bytes_written = -1;
21740
21741 sscanf(command, "%*s %d", &cfg->autochannel);
21742
21743 if (cfg->autochannel == 0) {
21744 cfg->best_2g_ch = 0;
21745 cfg->best_5g_ch = 0;
21746 } else if (cfg->autochannel == 2) {
21747 bytes_written = snprintf(command, total_len, "2g=%d 5g=%d",
21748 cfg->best_2g_ch, cfg->best_5g_ch);
21749 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
21750 ret = bytes_written;
21751 }
21752
21753 return ret;
21754}
32c27b7a
RC
21755
21756static int
21757wl_cfg80211_check_in4way(struct bcm_cfg80211 *cfg,
21758 struct net_device *dev, uint action, enum wl_ext_status status, void *context)
21759{
21760 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
21761 struct wl_security *sec;
21762 s32 bssidx = -1;
21763 int ret = 0;
21764 int max_wait_gc_time = dhdp->conf->max_wait_gc_time;
21765
21766 if (!(dhdp->conf->in4way & action))
21767 return 0;
21768
21769 mutex_lock(&cfg->in4way_sync);
21770 WL_DBG(("status=%d, action=0x%x\n", status, action));
21771
21772 switch (status) {
21773 case WL_EXT_STATUS_SCAN:
21774 if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
21775 if (cfg->handshaking > 0 && cfg->handshaking <= 3) {
21776 WL_ERR(("%s: return -EBUSY cnt %d\n",
21777 __FUNCTION__, cfg->handshaking));
21778 cfg->handshaking++;
21779 ret = -EBUSY;
21780 break;
21781 }
21782 }
21783 break;
21784 case WL_EXT_STATUS_CONNECTING:
21785 if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
21786 bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
21787 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
21788 if ((sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) &&
21789 bssidx == 0) {
21790 cfg->handshaking = 1;
21791 if (action & NO_BTC_IN4WAY)
21792 wldev_iovar_setint(dev, "btc_mode", 0);
21793 }
21794 }
21795 break;
21796 case WL_EXT_STATUS_DELETE_GC:
21797 if ((action & DONT_DELETE_GC_AFTER_WPS) &&
21798 (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
21799 u8* mac_addr = context;
21800 if (memcmp(&ether_bcast, mac_addr, ETHER_ADDR_LEN) &&
21801 dhdp->conf->eapol_status == EAPOL_STATUS_WPS_DONE) {
21802 u32 timeout;
21803 WL_TRACE(("status=%d, wps_done=%d, waiting %dms ...\n",
21804 status, cfg->wps_done, max_wait_gc_time));
21805 mutex_unlock(&cfg->in4way_sync);
21806 timeout = wait_event_interruptible_timeout(cfg->wps_done_event,
21807 cfg->wps_done, msecs_to_jiffies(max_wait_gc_time));
21808 mutex_lock(&cfg->in4way_sync);
21809 WL_TRACE(("status=%d, wps_done=%d, timeout=%d\n",
21810 status, cfg->wps_done, timeout));
21811 if (timeout > 0) {
21812 ret = -1;
21813 break;
21814 }
21815 } else {
21816 WL_TRACE(("status=%d, wps_done=%d => 0\n", status, cfg->wps_done));
21817 cfg->wps_done = FALSE;
21818 dhdp->conf->eapol_status = EAPOL_STATUS_NONE;
21819 }
21820 }
21821 break;
21822 case WL_EXT_STATUS_GC_DISCONNECTED:
21823 if ((action & DONT_DELETE_GC_AFTER_WPS) &&
21824 (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) &&
21825 dhdp->conf->eapol_status == EAPOL_STATUS_WPS_DONE) {
21826 WL_TRACE(("status=%d, wps_done=%d => 0\n", status, cfg->wps_done));
21827 cfg->wps_done = FALSE;
21828 }
21829 break;
21830 case WL_EXT_STATUS_GC_CONNECTED:
21831 if ((action & DONT_DELETE_GC_AFTER_WPS) &&
21832 (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) &&
21833 dhdp->conf->eapol_status == EAPOL_STATUS_WPS_DONE) {
21834 WL_TRACE(("status=%d, wps_done=%d => 1\n", status, cfg->wps_done));
21835 cfg->wps_done = TRUE;
21836 wake_up_interruptible(&cfg->wps_done_event);
21837 }
21838 break;
21839 case WL_EXT_STATUS_DISCONNECTED:
21840 case WL_EXT_STATUS_4WAY_DONE:
21841 if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
21842 if (cfg->handshaking) {
21843 if (action & NO_BTC_IN4WAY)
21844 wldev_iovar_setint(dev, "btc_mode", 1);
21845 cfg->handshaking = 0;
21846 }
21847 }
21848 break;
21849 default:
21850 WL_ERR(("Unknown action=0x%x, status=%d\n", action, status));
21851 }
21852
21853 mutex_unlock(&cfg->in4way_sync);
21854
21855 return ret;
21856}