2 * Linux cfg80211 driver
4 * Copyright (C) 2020, Broadcom.
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:
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.
21 * <<Broadcom-WL-IPTag/Dual:>>
26 #include <linux/kernel.h>
29 #include <bcmstdlib_s.h>
30 #include <bcmwifi_channels.h>
31 #include <bcmendian.h>
35 #endif /* WL_WPS_SYNC */
38 #include <linux/if_arp.h>
39 #include <asm/uaccess.h>
42 #include <linux/kernel.h>
43 #include <linux/kthread.h>
44 #include <linux/netdevice.h>
45 #include <linux/sched.h>
46 #include <linux/etherdevice.h>
47 #include <linux/wireless.h>
48 #include <linux/ieee80211.h>
49 #include <linux/wait.h>
50 #if defined(CONFIG_TIZEN)
51 #include <linux/net_stat_tizen.h>
52 #endif /* CONFIG_TIZEN */
53 #include <net/cfg80211.h>
54 #include <net/rtnetlink.h>
58 #include <wldev_common.h>
59 #include <wl_cfg80211.h>
60 #include <wl_cfgp2p.h>
61 #include <wl_cfgscan.h>
63 #include <bcmdevs_legacy.h>
69 #include <wl_android.h>
71 #include <dngl_stats.h>
73 #include <dhd_linux.h>
74 #include <dhd_linux_pktdump.h>
75 #include <dhd_debug.h>
78 #include <dhd_cfg80211.h>
82 #endif /* PNO_SUPPORT */
83 #include <wl_cfgvendor.h>
85 #ifdef CONFIG_SLEEP_MONITOR
86 #include <linux/power/sleep_monitor.h>
89 #if !defined(WL_VENDOR_EXT_SUPPORT)
92 #include <dhd_config.h>
95 #include <wl_cfgnan.h>
103 #include <dhd_flowring.h>
107 #endif /* RTT_SUPPORT */
109 #if defined(BIGDATA_SOFTAP) || defined(DHD_ENABLE_BIGDATA_LOGGING)
110 #include <wl_bigdata.h>
111 #endif /* BIGDATA_SOFTAP || DHD_ENABLE_BIGDATA_LOGGING */
113 #ifdef DHD_EVENT_LOG_FILTER
114 #include <dhd_event_log_filter.h>
115 #endif /* DHD_EVENT_LOG_FILTER */
116 #define BRCM_SAE_VENDOR_EVENT_BUF_LEN 500
118 #ifdef DNGL_AXI_ERROR_LOGGING
120 #endif /* DNGL_AXI_ERROR_LOGGING */
122 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
123 #include <linux/dev_ril_bridge.h>
124 #include <linux/notifier.h>
125 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
127 #if (defined(WL_FW_OCE_AP_SELECT) || defined(BCMFW_ROAM_ENABLE)) && \
128 ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS))
129 uint fw_ap_select
= true;
131 uint fw_ap_select
= false;
132 #endif /* WL_FW_OCE_AP_SELECT && (ROAM_ENABLE || BCMFW_ROAM_ENABLE) */
133 module_param(fw_ap_select
, uint
, 0660);
135 #if defined(WL_REASSOC)
136 uint wl_reassoc_support
= true;
138 uint wl_reassoc_support
= false;
139 #endif /* WL_REASSOC */
140 module_param(wl_reassoc_support
, uint
, 0660);
142 static struct device
*cfg80211_parent_dev
= NULL
;
143 static struct bcm_cfg80211
*g_bcmcfg
= NULL
;
144 u32 wl_dbg_level
= WL_DBG_ERR
;
146 #define MAX_VIF_OFFSET 15
147 #define MAX_WAIT_TIME 1500
149 #define IBSS_IF_NAME "ibss%d"
150 #endif /* WLAIBSS_MCHAN */
153 /* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
154 #define DEFAULT_SLEEP_TIME_VSDB 120
155 #define OFF_CHAN_TIME_THRESHOLD_MS 200
156 #define AF_RETRY_DELAY_TIME 40
158 /* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
159 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
161 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
162 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
163 OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
167 /* if not VSDB, do nothing */
168 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
171 #define DNGL_FUNC(func, parameters) func parameters
174 #define WLAN_EID_SSID 0
175 #define CH_MIN_5G_CHANNEL 34
177 enum abiss_event_type
{
183 enum rmc_event_type
{
185 RMC_EVENT_LEADER_CHECK_FAIL
187 #endif /* WL_RELMCAST */
189 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
190 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
191 * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
192 * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
193 * All the chnages in world regulatory domain are to be done here.
195 * this definition reuires disabling missing-field-initializer warning
196 * as the ieee80211_regdomain definition differs in plain linux and in Android
198 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
199 4 && __GNUC_MINOR__ >= 6))
200 _Pragma("GCC diagnostic push")
201 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
203 static const struct ieee80211_regdomain brcm_regdom
= {
211 /* IEEE 802.11b/g, channels 1..11 */
212 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
214 /* IEEE 802.11 channel 14 - Only JP enables
215 * this and for 802.11b only
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),
223 REG_RULE(6015-80, 6975+80, 160, 6, 20, 0),
224 REG_RULE(5945-10, 7105+10, 20, 6, 20, 0),
225 REG_RULE(5955-20, 7075+20, 40, 6, 20, 0),
226 REG_RULE(5975-40, 7015+40, 80, 6, 20, 0),
227 #endif /* WL_6G_BAND */
230 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
231 4 && __GNUC_MINOR__ >= 6))
232 _Pragma("GCC diagnostic pop")
235 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
236 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
237 static const struct ieee80211_iface_limit common_if_limits
[] = {
240 * Driver can support up to 2 AP's
243 .types
= BIT(NL80211_IFTYPE_AP
),
247 * During P2P-GO removal, P2P-GO is first changed to STA and later only
248 * removed. So setting maximum possible number of STA interfaces according
251 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
252 * linux-3.8 and above - max:4
253 * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
254 * for NAN defined, registering it as STA type)
256 #ifdef WL_ENABLE_P2P_IF
260 #endif /* WL_ENABLE_P2P_IF */
261 .types
= BIT(NL80211_IFTYPE_STATION
),
265 .types
= BIT(NL80211_IFTYPE_P2P_GO
) | BIT(NL80211_IFTYPE_P2P_CLIENT
),
267 #if defined(WL_CFG80211_P2P_DEV_IF)
270 .types
= BIT(NL80211_IFTYPE_P2P_DEVICE
),
272 #endif /* WL_CFG80211_P2P_DEV_IF */
275 .types
= BIT(NL80211_IFTYPE_ADHOC
),
279 #define NUM_DIFF_CHANNELS 2
281 static const struct ieee80211_iface_combination
282 common_iface_combinations
[] = {
284 .num_different_channels
= NUM_DIFF_CHANNELS
,
286 * At Max 5 network interfaces can be registered concurrently
288 .max_interfaces
= IFACE_MAX_CNT
,
289 .limits
= common_if_limits
,
290 .n_limits
= ARRAY_SIZE(common_if_limits
),
293 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
295 static const char *wl_if_state_strs
[WL_IF_STATE_MAX
+ 1] = {
306 #if defined(ANDROID_PLATFORM_VERSION) && (ANDROID_PLATFORM_VERSION >= 8)
307 /* WAPI define in ieee80211.h is used */
309 #undef WLAN_AKM_SUITE_WAPI_PSK
310 #define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04
312 #undef WLAN_AKM_SUITE_WAPI_CERT
313 #define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12
315 #undef NL80211_WAPI_VERSION_1
316 #define NL80211_WAPI_VERSION_1 1 << 2
317 #endif /* ANDROID_PLATFORM_VERSION && ANDROID_PLATFORM_VERSION >= 8 */
318 #endif /* BCMWAPI_WPI */
320 /* Data Element Definitions */
321 #define WPS_ID_CONFIG_METHODS 0x1008
322 #define WPS_ID_REQ_TYPE 0x103A
323 #define WPS_ID_DEVICE_NAME 0x1011
324 #define WPS_ID_VERSION 0x104A
325 #define WPS_ID_DEVICE_PWD_ID 0x1012
326 #define WPS_ID_REQ_DEV_TYPE 0x106A
327 #define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
328 #define WPS_ID_PRIM_DEV_TYPE 0x1054
330 /* Device Password ID */
331 #define DEV_PW_DEFAULT 0x0000
332 #define DEV_PW_USER_SPECIFIED 0x0001,
333 #define DEV_PW_MACHINE_SPECIFIED 0x0002
334 #define DEV_PW_REKEY 0x0003
335 #define DEV_PW_PUSHBUTTON 0x0004
336 #define DEV_PW_REGISTRAR_SPECIFIED 0x0005
339 #define WPS_CONFIG_USBA 0x0001
340 #define WPS_CONFIG_ETHERNET 0x0002
341 #define WPS_CONFIG_LABEL 0x0004
342 #define WPS_CONFIG_DISPLAY 0x0008
343 #define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
344 #define WPS_CONFIG_INT_NFC_TOKEN 0x0020
345 #define WPS_CONFIG_NFC_INTERFACE 0x0040
346 #define WPS_CONFIG_PUSHBUTTON 0x0080
347 #define WPS_CONFIG_KEYPAD 0x0100
348 #define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
349 #define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
350 #define WPS_CONFIG_VIRT_DISPLAY 0x2008
351 #define WPS_CONFIG_PHY_DISPLAY 0x4008
356 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
357 #define IS_REGDOM_SELF_MANAGED(wiphy) \
358 (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
360 #define IS_REGDOM_SELF_MANAGED(wiphy) (false)
361 #endif /* KERNEL >= 4.0 */
363 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM)
364 #define WL_UPDATE_CUSTOM_REGULATORY(wiphy) \
365 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
366 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
367 #define WL_UPDATE_CUSTOM_REGULATORY(wiphy) \
368 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
369 #else /* kernel > 4.0 && WL_SELF_MANAGED_REGDOM */
371 #define WL_UPDATE_CUSTOM_REGULATORY(wiphy) \
372 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
373 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
375 /* GCMP crypto supported above kernel v4.0 */
376 #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0))
378 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0) */
380 #ifndef IBSS_COALESCE_ALLOWED
381 #define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT
384 #ifndef IBSS_INITIAL_SCAN_ALLOWED
385 #define IBSS_INITIAL_SCAN_ALLOWED IBSS_INITIAL_SCAN_ALLOWED_DEFAULT
388 #define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
391 typedef struct wl_wbtext_bssid
{
392 struct ether_addr ea
;
393 struct list_head list
;
396 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211
*cfg
, struct net_device
*dev
);
397 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211
*cfg
, struct ether_addr
*ea
);
398 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211
*cfg
, struct ether_addr
*ea
);
399 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211
*cfg
);
400 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
401 struct wl_profile
*profile
);
402 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
403 struct wl_profile
*profile
);
404 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211
*cfg
, struct net_device
*dev
);
405 static int wl_cfg80211_recv_nbr_resp(struct net_device
*dev
, uint8
*body
, uint body_len
);
409 static s32
wl_cfg80211_rtt_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
410 const wl_event_msg_t
*e
, void *data
);
411 #endif /* RTT_SUPPORT */
413 static s32
wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211
*cfg
,
414 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
415 static s32
wl_cfg80211_start_bssload_report(struct net_device
*ndev
);
416 #endif /* WL_CHAN_UTIL */
418 #ifdef SUPPORT_AP_RADIO_PWRSAVE
419 #define RADIO_PWRSAVE_PPS 10
420 #define RADIO_PWRSAVE_QUIET_TIME 10
421 #define RADIO_PWRSAVE_LEVEL 3
422 #define RADIO_PWRSAVE_STAS_ASSOC_CHECK 0
424 #define RADIO_PWRSAVE_LEVEL_MIN 1
425 #define RADIO_PWRSAVE_LEVEL_MAX 9
426 #define RADIO_PWRSAVE_PPS_MIN 1
427 #define RADIO_PWRSAVE_QUIETTIME_MIN 1
428 #define RADIO_PWRSAVE_ASSOCCHECK_MIN 0
429 #define RADIO_PWRSAVE_ASSOCCHECK_MAX 1
431 #define RADIO_PWRSAVE_MAJOR_VER 1
432 #define RADIO_PWRSAVE_MINOR_VER 1
433 #define RADIO_PWRSAVE_MAJOR_VER_SHIFT 8
434 #define RADIO_PWRSAVE_VERSION \
435 ((RADIO_PWRSAVE_MAJOR_VER << RADIO_PWRSAVE_MAJOR_VER_SHIFT)| RADIO_PWRSAVE_MINOR_VER)
436 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
438 /* SoftAP related parameters */
439 #define DEFAULT_2G_SOFTAP_CHANNEL 1
440 #define DEFAULT_2G_SOFTAP_CHANSPEC 0x1006
441 #define DEFAULT_5G_SOFTAP_CHANNEL 149
442 #define WL_MAX_NUM_CSA_COUNTERS 255
444 #define MAX_VNDR_OUI_STR_LEN 256u
445 #define VNDR_OUI_STR_LEN 10u
446 #define DOT11_DISCONNECT_RC 2u
447 static const uchar
*exclude_vndr_oui_list
[] = {
448 "\x00\x50\xf2", /* Microsoft */
449 "\x00\x00\xf0", /* Samsung Elec */
454 typedef struct wl_vndr_oui_entry
{
455 uchar oui
[DOT11_OUI_LEN
];
456 struct list_head list
;
457 } wl_vndr_oui_entry_t
;
460 static const uchar disco_bcnloss_vsie
[] = {
461 0xdd, /* Vendor specific */
463 0x00, 0x00, 0xF0, /* OUI */
464 0x22, /* VENDOR_ENTERPRISE_STA_OUI_TYPE */
465 0x03, /* Sub type for additional rc */
468 0x07, 0x00 /* Reason code for BCN loss */
470 #endif /* WL_ANALYTICS */
472 #define WL_HE_FEATURES_HE_AP 0x8
473 #define WL_HE_FEATURES_HE_P2P 0x20
475 static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211
*cfg
,
476 struct net_device
*ndev
, char *vndr_oui
, u32 vndr_oui_len
);
477 static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211
*cfg
);
479 static bool wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211
*cfg
,
480 struct net_device
*ndev
, const char *vndr_oui
);
482 static s32
wl_cfg80211_parse_vndr_ies(const u8
*parse
, u32 len
,
483 struct parsed_vndr_ies
*vndr_ies
);
484 static bool wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t
*vndrie
);
485 #if defined(WL_FW_OCE_AP_SELECT)
487 wl_cfgoce_has_ie(const u8
*ie
, const u8
**tlvs
, u32
*tlvs_len
, const u8
*oui
, u32 oui_len
, u8 type
);
489 /* Check whether the given IE looks like WFA OCE IE. */
490 #define wl_cfgoce_is_oce_ie(ie, tlvs, len) wl_cfgoce_has_ie(ie, tlvs, len, \
491 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_MBO_OCE)
493 /* Is any of the tlvs the expected entry? If
494 * not update the tlvs buffer pointer/length.
497 wl_cfgoce_has_ie(const u8
*ie
, const u8
**tlvs
, u32
*tlvs_len
, const u8
*oui
, u32 oui_len
, u8 type
)
499 /* If the contents match the OUI and the type */
500 if (ie
[TLV_LEN_OFF
] >= oui_len
+ 1 &&
501 !bcmp(&ie
[TLV_BODY_OFF
], oui
, oui_len
) &&
502 type
== ie
[TLV_BODY_OFF
+ oui_len
]) {
508 #endif /* WL_FW_OCE_AP_SELECT */
511 * cfg80211_ops api/callback list
513 static s32
wl_frame_get_mgmt(struct bcm_cfg80211
*cfg
, u16 fc
,
514 const struct ether_addr
*da
, const struct ether_addr
*sa
,
515 const struct ether_addr
*bssid
, u8
**pheader
, u32
*body_len
, u8
*pbody
);
516 static s32
wl_cfg80211_set_wiphy_params(struct wiphy
*wiphy
, u32 changed
);
518 static bcm_struct_cfgdev
* bcm_cfg80211_add_ibss_if(struct wiphy
*wiphy
, char *name
);
519 static s32
bcm_cfg80211_del_ibss_if(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
);
520 #endif /* WLAIBSS_MCHAN */
521 static s32
wl_cfg80211_join_ibss(struct wiphy
*wiphy
, struct net_device
*dev
,
522 struct cfg80211_ibss_params
*params
);
523 static s32
wl_cfg80211_leave_ibss(struct wiphy
*wiphy
,
524 struct net_device
*dev
);
525 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
526 static s32
wl_cfg80211_get_station(struct wiphy
*wiphy
,
527 struct net_device
*dev
, const u8
*mac
,
528 struct station_info
*sinfo
);
530 static s32
wl_cfg80211_get_station(struct wiphy
*wiphy
,
531 struct net_device
*dev
, u8
*mac
,
532 struct station_info
*sinfo
);
534 static s32
wl_cfg80211_set_power_mgmt(struct wiphy
*wiphy
,
535 struct net_device
*dev
, bool enabled
,
537 static int wl_cfg80211_connect(struct wiphy
*wiphy
, struct net_device
*dev
,
538 struct cfg80211_connect_params
*sme
);
540 static int wl_cfg80211_update_connect_params(struct wiphy
*wiphy
, struct net_device
*dev
,
541 struct cfg80211_connect_params
*sme
, u32 changed
);
543 static s32
wl_cfg80211_disconnect(struct wiphy
*wiphy
, struct net_device
*dev
,
545 #if defined(WL_CFG80211_P2P_DEV_IF)
547 wl_cfg80211_set_tx_power(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
548 enum nl80211_tx_power_setting type
, s32 mbm
);
551 wl_cfg80211_set_tx_power(struct wiphy
*wiphy
,
552 enum nl80211_tx_power_setting type
, s32 dbm
);
553 #endif /* WL_CFG80211_P2P_DEV_IF */
554 #if defined(WL_CFG80211_P2P_DEV_IF)
555 static s32
wl_cfg80211_get_tx_power(struct wiphy
*wiphy
,
556 struct wireless_dev
*wdev
, s32
*dbm
);
558 static s32
wl_cfg80211_get_tx_power(struct wiphy
*wiphy
, s32
*dbm
);
559 #endif /* WL_CFG80211_P2P_DEV_IF */
560 static s32
wl_cfg80211_config_default_key(struct wiphy
*wiphy
,
561 struct net_device
*dev
,
562 u8 key_idx
, bool unicast
, bool multicast
);
563 static s32
wl_cfg80211_add_key(struct wiphy
*wiphy
, struct net_device
*dev
,
564 u8 key_idx
, bool pairwise
, const u8
*mac_addr
,
565 struct key_params
*params
);
566 static s32
wl_cfg80211_del_key(struct wiphy
*wiphy
, struct net_device
*dev
,
567 u8 key_idx
, bool pairwise
, const u8
*mac_addr
);
568 static s32
wl_cfg80211_get_key(struct wiphy
*wiphy
, struct net_device
*dev
,
569 u8 key_idx
, bool pairwise
, const u8
*mac_addr
,
570 void *cookie
, void (*callback
) (void *cookie
,
571 struct key_params
*params
));
572 static s32
wl_cfg80211_config_default_mgmt_key(struct wiphy
*wiphy
,
573 struct net_device
*dev
, u8 key_idx
);
574 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
576 static s32
wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy
*wiphy
,
577 bcm_struct_cfgdev
*cfgdev
, u64 cookie
);
578 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
579 static s32
wl_cfg80211_del_station(
580 struct wiphy
*wiphy
, struct net_device
*ndev
,
581 struct station_del_parameters
*params
);
582 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
583 static s32
wl_cfg80211_del_station(struct wiphy
*wiphy
,
584 struct net_device
*ndev
, const u8
* mac_addr
);
586 static s32
wl_cfg80211_del_station(struct wiphy
*wiphy
,
587 struct net_device
*ndev
, u8
* mac_addr
);
589 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
590 static s32
wl_cfg80211_change_station(struct wiphy
*wiphy
,
591 struct net_device
*dev
, const u8
*mac
, struct station_parameters
*params
);
593 static s32
wl_cfg80211_change_station(struct wiphy
*wiphy
,
594 struct net_device
*dev
, u8
*mac
, struct station_parameters
*params
);
596 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
597 static s32
wl_cfg80211_set_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
598 struct cfg80211_pmksa
*pmksa
);
599 static s32
wl_cfg80211_del_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
600 struct cfg80211_pmksa
*pmksa
);
601 static s32
wl_cfg80211_flush_pmksa(struct wiphy
*wiphy
,
602 struct net_device
*dev
);
604 static bool wl_is_pmkid_available(struct net_device
*dev
, const u8
*bssid
);
605 #endif /* WL_CLIENT_SAE */
606 static s32
wl_cfg80211_update_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
607 struct cfg80211_pmksa
*pmksa
, bool set
);
608 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
609 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
610 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
611 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
612 u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
613 u32 peer_capability
, const u8
*buf
, size_t len
);
614 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
615 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
616 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
617 const u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
618 u32 peer_capability
, const u8
*buf
, size_t len
);
619 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
620 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
621 const u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
622 u32 peer_capability
, bool initiator
, const u8
*buf
, size_t len
);
623 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
624 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
625 u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
626 const u8
*buf
, size_t len
);
627 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
628 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
629 static s32
wl_cfg80211_tdls_oper(struct wiphy
*wiphy
, struct net_device
*dev
,
630 const u8
*peer
, enum nl80211_tdls_operation oper
);
632 static s32
wl_cfg80211_tdls_oper(struct wiphy
*wiphy
, struct net_device
*dev
,
633 u8
*peer
, enum nl80211_tdls_operation oper
);
635 #endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
636 static s32
wl_cfg80211_set_ap_role(struct bcm_cfg80211
*cfg
, struct net_device
*dev
);
638 struct wireless_dev
*
639 wl_cfg80211_create_iface(struct wiphy
*wiphy
, wl_iftype_t
640 iface_type
, u8
*mac_addr
, const char *name
);
642 wl_cfg80211_del_iface(struct wiphy
*wiphy
, struct wireless_dev
*wdev
);
644 s32
wl_cfg80211_interface_ops(struct bcm_cfg80211
*cfg
,
645 struct net_device
*ndev
, s32 bsscfg_idx
,
646 wl_iftype_t iftype
, s32 del
, u8
*addr
);
647 s32
wl_cfg80211_add_del_bss(struct bcm_cfg80211
*cfg
,
648 struct net_device
*ndev
, s32 bsscfg_idx
,
649 wl_iftype_t brcm_iftype
, s32 del
, u8
*addr
);
650 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
651 static s32
wl_cfg80211_stop_ap(struct wiphy
*wiphy
, struct net_device
*dev
);
652 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */
653 #ifdef GTK_OFFLOAD_SUPPORT
654 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
655 static s32
wl_cfg80211_set_rekey_data(struct wiphy
*wiphy
, struct net_device
*dev
,
656 struct cfg80211_gtk_rekey_data
*data
);
657 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
658 #endif /* GTK_OFFLOAD_SUPPORT */
659 chanspec_t
wl_chspec_driver_to_host(chanspec_t chanspec
);
660 chanspec_t
wl_chspec_host_to_driver(chanspec_t chanspec
);
661 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211
*cfg
, struct net_device
*dev
);
662 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
663 int wl_cfg80211_channel_switch(struct wiphy
*wiphy
, struct net_device
*dev
,
664 struct cfg80211_csa_settings
*params
);
665 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
667 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
668 static int wl_cfg80211_set_pmk(struct wiphy
*wiphy
, struct net_device
*dev
,
669 const struct cfg80211_pmk_conf
*conf
);
670 static int wl_cfg80211_del_pmk(struct wiphy
*wiphy
, struct net_device
*dev
,
672 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
675 * event & event Q handlers for cfg80211 interfaces
677 static s32
wl_create_event_handler(struct bcm_cfg80211
*cfg
);
678 static void wl_destroy_event_handler(struct bcm_cfg80211
*cfg
);
679 static void wl_event_handler(struct work_struct
*work_data
);
680 static void wl_init_eq(struct bcm_cfg80211
*cfg
);
681 static void wl_flush_eq(struct bcm_cfg80211
*cfg
);
682 static unsigned long wl_lock_eq(struct bcm_cfg80211
*cfg
);
683 static void wl_unlock_eq(struct bcm_cfg80211
*cfg
, unsigned long flags
);
684 static void wl_init_eq_lock(struct bcm_cfg80211
*cfg
);
685 static void wl_init_event_handler(struct bcm_cfg80211
*cfg
);
686 static struct wl_event_q
*wl_deq_event(struct bcm_cfg80211
*cfg
);
687 static s32
wl_enq_event(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u32 type
,
688 const wl_event_msg_t
*msg
, void *data
);
689 static void wl_put_event(struct bcm_cfg80211
*cfg
, struct wl_event_q
*e
);
690 static s32
wl_notify_connect_status_ap(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
691 const wl_event_msg_t
*e
, void *data
);
692 static s32
wl_notify_connect_status(struct bcm_cfg80211
*cfg
,
693 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
694 static s32
wl_notify_roaming_status(struct bcm_cfg80211
*cfg
,
695 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
696 static s32
wl_bss_connect_done(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
697 const wl_event_msg_t
*e
, void *data
, bool completed
);
698 static s32
wl_bss_roaming_done(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
699 const wl_event_msg_t
*e
, void *data
);
700 static s32
wl_notify_mic_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
701 const wl_event_msg_t
*e
, void *data
);
702 #ifdef BT_WIFI_HANDOVER
703 static s32
wl_notify_bt_wifi_handover_req(struct bcm_cfg80211
*cfg
,
704 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
705 #endif /* BT_WIFI_HANDOVER */
707 static s32
wl_handle_roam_exp_event(struct bcm_cfg80211
*wl
, bcm_struct_cfgdev
*cfgdev
,
708 const wl_event_msg_t
*e
, void *data
);
709 #endif /* GSCAN_SUPPORT */
710 #ifdef RSSI_MONITOR_SUPPORT
711 static s32
wl_handle_rssi_monitor_event(struct bcm_cfg80211
*wl
, bcm_struct_cfgdev
*cfgdev
,
712 const wl_event_msg_t
*e
, void *data
);
713 #endif /* RSSI_MONITOR_SUPPORT */
714 static s32
wl_notifier_change_state(struct bcm_cfg80211
*cfg
, struct net_info
*_net_info
,
715 enum wl_status state
, bool set
);
716 #ifdef CUSTOM_EVENT_PM_WAKE
717 static s32
wl_check_pmstatus(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
718 const wl_event_msg_t
*e
, void *data
);
719 #endif /* CUSTOM_EVENT_PM_WAKE */
720 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
721 static s32
wl_notify_roam_prep_status(struct bcm_cfg80211
*cfg
,
722 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
723 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
724 #ifdef DHD_LOSSLESS_ROAMING
725 static void wl_del_roam_timeout(struct bcm_cfg80211
*cfg
);
726 #endif /* DHD_LOSSLESS_ROAMING */
730 wl_mbo_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
731 const wl_event_msg_t
*e
, void *data
);
735 static s32
wl_notify_connect_status_bss(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
736 const wl_event_msg_t
*e
, void *data
);
737 static s32
wl_notify_start_auth(struct bcm_cfg80211
*cfg
,
738 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
739 static s32
wl_cfg80211_external_auth(struct wiphy
*wiphy
,
740 struct net_device
*dev
, struct cfg80211_external_auth_params
*ext_auth
);
741 #endif /* WL_CLIENT_SAE */
744 * register/deregister parent device
746 static void wl_cfg80211_clear_parent_dev(void);
752 * cfg80211 set_wiphy_params utilities
754 static s32
wl_set_frag(struct net_device
*dev
, u32 frag_threshold
);
755 static s32
wl_set_rts(struct net_device
*dev
, u32 frag_threshold
);
756 static s32
wl_set_retry(struct net_device
*dev
, u32 retry
, bool l
);
759 * cfg profile utilities
761 static s32
wl_update_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
762 const wl_event_msg_t
*e
, const void *data
, s32 item
);
763 static void wl_init_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
);
766 * cfg80211 connect utilites
768 static s32
wl_set_wpa_version(struct net_device
*dev
,
769 struct cfg80211_connect_params
*sme
);
770 static s32
wl_set_auth_type(struct net_device
*dev
,
771 struct cfg80211_connect_params
*sme
);
772 static s32
wl_set_set_cipher(struct net_device
*dev
,
773 struct cfg80211_connect_params
*sme
);
774 static s32
wl_set_key_mgmt(struct net_device
*dev
,
775 struct cfg80211_connect_params
*sme
);
776 static s32
wl_set_set_sharedkey(struct net_device
*dev
,
777 struct cfg80211_connect_params
*sme
);
779 static s32
wl_set_fils_params(struct net_device
*dev
,
780 struct cfg80211_connect_params
*sme
);
784 static s32
wl_set_set_wapi_ie(struct net_device
*dev
,
785 struct cfg80211_connect_params
*sme
);
789 static s32
wl_set_wsec_info_algos(struct net_device
*dev
, uint32 algos
, uint32 mask
);
791 static s32
wl_get_assoc_ies(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
);
792 void wl_cfg80211_clear_security(struct bcm_cfg80211
*cfg
);
795 * information element utilities
797 static __used s32
wl_add_ie(struct bcm_cfg80211
*cfg
, u8 t
, u8 l
, u8
*v
);
800 static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t
*wpa2ie
, const u8
** rsn_cap
);
803 static s32
wl_setup_wiphy(struct wireless_dev
*wdev
, struct device
*dev
, dhd_pub_t
*data
);
804 static void wl_free_wdev(struct bcm_cfg80211
*cfg
);
805 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
806 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
810 #endif /* kernel version < 3.10.11 */
811 wl_cfg80211_reg_notifier(struct wiphy
*wiphy
, struct regulatory_request
*request
);
812 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
814 static s32
wl_update_bss_info(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, bool update_ssid
);
815 static chanspec_t
wl_cfg80211_get_shared_freq(struct wiphy
*wiphy
);
816 static void wl_cfg80211_work_handler(struct work_struct
*work
);
817 static s32
wl_add_keyext(struct wiphy
*wiphy
, struct net_device
*dev
,
818 u8 key_idx
, const u8
*mac_addr
,
819 struct key_params
*params
);
821 * key indianess swap utilities
823 static void swap_key_from_BE(struct wl_wsec_key
*key
);
824 static void swap_key_to_BE(struct wl_wsec_key
*key
);
827 * bcm_cfg80211 memory init/deinit utilities
829 static s32
wl_init_priv_mem(struct bcm_cfg80211
*cfg
);
830 static void wl_deinit_priv_mem(struct bcm_cfg80211
*cfg
);
832 static void wl_delay(u32 ms
);
835 * ibss mode utilities
837 static bool wl_is_ibssmode(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
);
838 static __used
bool wl_is_ibssstarter(struct bcm_cfg80211
*cfg
);
841 * link up/down , default configuration utilities
843 static s32
__wl_cfg80211_up(struct bcm_cfg80211
*cfg
);
844 static s32
__wl_cfg80211_down(struct bcm_cfg80211
*cfg
);
845 static bool wl_is_linkdown(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
);
847 static bool wl_is_linkup(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
,
848 struct net_device
*ndev
);
849 static bool wl_is_nonetwork(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
);
850 static void wl_link_up(struct bcm_cfg80211
*cfg
);
851 static void wl_link_down(struct bcm_cfg80211
*cfg
);
852 static s32
wl_config_infra(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u16 iftype
);
853 static void wl_init_conf(struct wl_conf
*conf
);
854 int wl_cfg80211_get_ioctl_version(void);
857 * find most significant bit set
859 static __used u32
wl_find_msb(u16 bit16
);
864 static int wl_setup_rfkill(struct bcm_cfg80211
*cfg
, bool setup
);
865 static int wl_rfkill_set(void *data
, bool blocked
);
866 #ifdef DEBUGFS_CFG80211
867 static s32
wl_setup_debugfs(struct bcm_cfg80211
*cfg
);
868 static s32
wl_free_debugfs(struct bcm_cfg80211
*cfg
);
870 static bool check_dev_role_integrity(struct bcm_cfg80211
*cfg
, u32 dev_role
);
872 #ifdef WL_CFG80211_ACL
874 static int wl_cfg80211_set_mac_acl(struct wiphy
*wiphy
, struct net_device
*cfgdev
,
875 const struct cfg80211_acl_data
*acl
);
876 #endif /* WL_CFG80211_ACL */
879 * Some external functions, TODO: move them to dhd_linux.h
881 int dhd_add_monitor(const char *name
, struct net_device
**new_ndev
);
882 int dhd_del_monitor(struct net_device
*ndev
);
883 int dhd_monitor_init(void *dhd_pub
);
884 int dhd_monitor_uninit(void);
885 int dhd_start_xmit(struct sk_buff
*skb
, struct net_device
*net
);
887 #ifdef ROAM_CHANNEL_CACHE
888 int init_roam_cache(struct bcm_cfg80211
*cfg
, int ioctl_ver
);
889 #endif /* ROAM_CHANNEL_CACHE */
891 #ifdef P2P_LISTEN_OFFLOADING
892 s32
wl_cfg80211_p2plo_deinit(struct bcm_cfg80211
*cfg
);
893 #endif /* P2P_LISTEN_OFFLOADING */
895 #ifdef CUSTOMER_HW4_DEBUG
896 extern bool wl_scan_timeout_dbg_enabled
;
897 #endif /* CUSTOMER_HW4_DEBUG */
898 #ifdef PKT_FILTER_SUPPORT
899 extern uint dhd_pkt_filter_enable
;
900 extern void dhd_pktfilter_offload_enable(dhd_pub_t
* dhd
, char *arg
, int enable
, int master_mode
);
901 #endif /* PKT_FILTER_SUPPORT */
903 #ifdef SUPPORT_SET_CAC
904 static void wl_cfg80211_set_cac(struct bcm_cfg80211
*cfg
, int enable
);
905 #endif /* SUPPORT_SET_CAC */
907 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
908 const struct ether_addr
*bssid
);
909 static s32
__wl_update_wiphybands(struct bcm_cfg80211
*cfg
, bool notify
);
912 static void wl_init_wps_reauth_sm(struct bcm_cfg80211
*cfg
);
913 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211
*cfg
);
914 static void wl_wps_reauth_timeout(unsigned long data
);
915 static s32
wl_get_free_wps_inst(struct bcm_cfg80211
*cfg
);
916 static s32
wl_get_wps_inst_match(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
);
917 static s32
wl_wps_session_add(struct net_device
*ndev
, u16 mode
, u8
*peer_mac
);
918 static void wl_wps_session_del(struct net_device
*ndev
);
919 static s32
wl_wps_session_update(struct net_device
*ndev
, u16 state
, const u8
*peer_mac
);
920 static void wl_wps_handle_ifdel(struct net_device
*ndev
);
921 #endif /* WL_WPS_SYNC */
923 #if defined(WL_FW_OCE_AP_SELECT)
924 bool static wl_cfg80211_is_oce_ap(struct wiphy
*wiphy
, const u8
*bssid_hint
);
925 #endif /* WL_FW_OCE_AP_SELECT */
928 static s32
wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
929 const wl_event_msg_t
*e
, void *data
);
930 #endif /* WL_BCNRECV */
933 static s32
wl_cfg80211_cac_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
934 const wl_event_msg_t
*e
, void *data
);
935 #endif /* WL_CAC_TS */
937 #if defined(WL_MBO) || defined(WL_OCE)
938 static s32
wl_bssid_prune_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
939 const wl_event_msg_t
*e
, void *data
);
940 #endif /* WL_MBO || WL_OCE */
942 static int bw2cap
[] = { 0, 0, WLC_BW_CAP_20MHZ
, WLC_BW_CAP_40MHZ
, WLC_BW_CAP_80MHZ
,
943 WLC_BW_CAP_160MHZ
, WLC_BW_CAP_160MHZ
};
945 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || (defined(CONFIG_ARCH_MSM) && \
946 defined(CFG80211_DISCONNECTED_V2))
947 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
948 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
949 IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
951 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
952 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
953 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
954 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
956 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
957 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
958 defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || defined(WL_FILS) || \
959 defined(CONFIG_CFG80211_FILS_BKPORT)
960 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
961 resp_ie_len, status, gfp) \
962 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
963 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
965 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
966 resp_ie_len, status, gfp) \
967 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
968 resp_ie_len, status, gfp);
969 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
970 * (CFG80211_CONNECT_TIMEOUT_REASON_CODE) ||
971 * WL_FILS || CONFIG_CFG80211_FILS_BKPORT
973 #elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
974 /* There are customer kernels with backported changes for
975 * connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
976 * is available for kernels < 4.7 in such cases.
978 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
979 resp_ie_len, status, gfp) \
980 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
981 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
983 /* Kernels < 4.7 doesn't support cfg80211_connect_bss */
984 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
985 resp_ie_len, status, gfp) \
986 cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
987 resp_ie_len, status, gfp);
988 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
990 #define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
991 (akm) == RSN_AKM_UNSPECIFIED || \
992 (akm) == RSN_AKM_PSK)
994 extern int dhd_wait_pend8021x(struct net_device
*dev
);
995 #ifdef PROP_TXSTATUS_VSDB
996 extern int disable_proptx
;
997 #endif /* PROP_TXSTATUS_VSDB */
999 /* WAR: disable pm_bcnrx , scan_ps for BCM4354 WISOL module.
1000 * WISOL module have ANT_1 Rx sensitivity issue.
1002 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
1003 extern void dhd_force_disable_singlcore_scan(dhd_pub_t
*dhd
);
1004 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
1007 wl_ap_start_ind(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
1008 const wl_event_msg_t
*e
, void *data
);
1010 wl_csa_complete_ind(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
1011 const wl_event_msg_t
*e
, void *data
);
1013 wl_get_bandwidth_cap(struct net_device
*ndev
, uint32 band
, uint32
*bandwidth
);
1014 #ifdef SUPPORT_AP_BWCTRL
1016 wl_update_apchan_bwcap(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, chanspec_t chanspec
);
1018 wl_restore_ap_bw(struct bcm_cfg80211
*cfg
);
1019 #endif /* SUPPORT_AP_BWCTRL */
1021 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \
1029 #define CH_TO_CHSPC(band, _channel) \
1030 ((_channel | band) | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE)
1031 #define CHAN2G(_channel, _freq, _flags) { \
1032 .band = IEEE80211_BAND_2GHZ, \
1033 .center_freq = (_freq), \
1034 .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_2G, _channel), \
1035 .flags = (_flags), \
1036 .max_antenna_gain = 0, \
1040 #define CHAN5G(_channel, _flags) { \
1041 .band = IEEE80211_BAND_5GHZ, \
1042 .center_freq = 5000 + (5 * (_channel)), \
1043 .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_5G, _channel), \
1044 .flags = (_flags), \
1045 .max_antenna_gain = 0, \
1050 #define CHAN6G(_channel, _flags) { \
1051 .band = IEEE80211_BAND_5GHZ, \
1052 .center_freq = 5940 + (5 * (_channel)), \
1053 .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_6G, _channel), \
1054 .flags = (_flags), \
1055 .max_antenna_gain = 0, \
1058 #endif /* WL_6G_BAND */
1060 #define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
1061 #define RATETAB_ENT(_rateid, _flags) \
1063 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
1064 .hw_value = (_rateid), \
1065 .flags = (_flags), \
1068 static struct ieee80211_rate __wl_rates
[] = {
1069 RATETAB_ENT(DOT11_RATE_1M
, 0),
1070 RATETAB_ENT(DOT11_RATE_2M
, IEEE80211_RATE_SHORT_PREAMBLE
),
1071 RATETAB_ENT(DOT11_RATE_5M5
, IEEE80211_RATE_SHORT_PREAMBLE
),
1072 RATETAB_ENT(DOT11_RATE_11M
, IEEE80211_RATE_SHORT_PREAMBLE
),
1073 RATETAB_ENT(DOT11_RATE_6M
, 0),
1074 RATETAB_ENT(DOT11_RATE_9M
, 0),
1075 RATETAB_ENT(DOT11_RATE_12M
, 0),
1076 RATETAB_ENT(DOT11_RATE_18M
, 0),
1077 RATETAB_ENT(DOT11_RATE_24M
, 0),
1078 RATETAB_ENT(DOT11_RATE_36M
, 0),
1079 RATETAB_ENT(DOT11_RATE_48M
, 0),
1080 RATETAB_ENT(DOT11_RATE_54M
, 0)
1083 #define wl_a_rates (__wl_rates + 4)
1084 #define wl_a_rates_size 8
1085 #define wl_g_rates (__wl_rates + 0)
1086 #define wl_g_rates_size 12
1088 static struct ieee80211_channel __wl_2ghz_channels
[] = {
1098 CHAN2G(10, 2457, 0),
1099 CHAN2G(11, 2462, 0),
1100 CHAN2G(12, 2467, 0),
1101 CHAN2G(13, 2472, 0),
1105 static struct ieee80211_channel __wl_5ghz_a_channels
[] = {
1106 CHAN5G(34, 0), CHAN5G(36, 0),
1107 CHAN5G(38, 0), CHAN5G(40, 0),
1108 CHAN5G(42, 0), CHAN5G(44, 0),
1109 CHAN5G(46, 0), CHAN5G(48, 0),
1110 CHAN5G(52, 0), CHAN5G(56, 0),
1111 CHAN5G(60, 0), CHAN5G(64, 0),
1112 CHAN5G(100, 0), CHAN5G(104, 0),
1113 CHAN5G(108, 0), CHAN5G(112, 0),
1114 CHAN5G(116, 0), CHAN5G(120, 0),
1115 CHAN5G(124, 0), CHAN5G(128, 0),
1116 CHAN5G(132, 0), CHAN5G(136, 0),
1117 CHAN5G(140, 0), CHAN5G(144, 0),
1118 CHAN5G(149, 0), CHAN5G(153, 0),
1119 CHAN5G(157, 0), CHAN5G(161, 0),
1122 /* 6GHz frequency starting 5945 */
1123 CHAN6G(1, 0), CHAN6G(5, 0), CHAN6G(9, 0),
1124 CHAN6G(13, 0), CHAN6G(17, 0),
1125 CHAN6G(21, 0), CHAN6G(25, 0),
1126 CHAN6G(29, 0), CHAN6G(33, 0),
1127 CHAN6G(37, 0), CHAN6G(41, 0),
1128 CHAN6G(45, 0), CHAN6G(49, 0),
1129 CHAN6G(53, 0), CHAN6G(57, 0),
1130 CHAN6G(61, 0), CHAN6G(65, 0),
1131 CHAN6G(69, 0), CHAN6G(73, 0),
1132 CHAN6G(77, 0), CHAN6G(81, 0),
1133 CHAN6G(85, 0), CHAN6G(89, 0),
1134 CHAN6G(93, 0), CHAN6G(97, 0),
1135 CHAN6G(101, 0), CHAN6G(105, 0),
1136 CHAN6G(109, 0), CHAN6G(113, 0),
1137 CHAN6G(117, 0), CHAN6G(121, 0),
1138 CHAN6G(125, 0), CHAN6G(129, 0),
1139 CHAN6G(133, 0), CHAN6G(137, 0),
1140 CHAN6G(141, 0), CHAN6G(145, 0),
1141 CHAN6G(149, 0), CHAN6G(153, 0),
1142 CHAN6G(157, 0), CHAN6G(161, 0),
1143 CHAN6G(165, 0), CHAN6G(169, 0),
1144 CHAN6G(173, 0), CHAN6G(177, 0),
1145 CHAN6G(181, 0), CHAN6G(185, 0),
1146 CHAN6G(189, 0), CHAN6G(193, 0),
1147 CHAN6G(197, 0), CHAN6G(201, 0),
1148 CHAN6G(205, 0), CHAN6G(209, 0),
1149 CHAN6G(213, 0), CHAN6G(217, 0),
1150 CHAN6G(221, 0), CHAN6G(225, 0),
1151 CHAN6G(229, 0), CHAN6G(233, 0),
1153 CHAN6G(3, 0), CHAN6G(11, 0),
1154 CHAN6G(19, 0), CHAN6G(27, 0),
1155 CHAN6G(35, 0), CHAN6G(43, 0),
1156 CHAN6G(51, 0), CHAN6G(59, 0),
1157 CHAN6G(67, 0), CHAN6G(75, 0),
1158 CHAN6G(83, 0), CHAN6G(91, 0),
1159 CHAN6G(99, 0), CHAN6G(107, 0),
1160 CHAN6G(115, 0), CHAN6G(123, 0),
1161 CHAN6G(131, 0), CHAN6G(139, 0),
1162 CHAN6G(147, 0), CHAN6G(155, 0),
1163 CHAN6G(163, 0), CHAN6G(171, 0),
1164 CHAN6G(179, 0), CHAN6G(187, 0),
1165 CHAN6G(195, 0), CHAN6G(203, 0),
1166 CHAN6G(211, 0), CHAN6G(219, 0), CHAN6G(227, 0),
1168 CHAN6G(7, 0), CHAN6G(23, 0),
1169 CHAN6G(39, 0), CHAN6G(55, 0),
1170 CHAN6G(71, 0), CHAN6G(87, 0),
1171 CHAN6G(103, 0), CHAN6G(119, 0),
1172 CHAN6G(135, 0), CHAN6G(151, 0),
1173 CHAN6G(167, 0), CHAN6G(183, 0),
1174 CHAN6G(199, 0), CHAN6G(215, 0),
1176 CHAN6G(15, 0), CHAN6G(47, 0),
1177 CHAN6G(79, 0), CHAN6G(111, 0),
1178 CHAN6G(143, 0), CHAN6G(175, 0), CHAN6G(207, 0),
1179 #endif /* WL_6G_BAND */
1182 static struct ieee80211_supported_band __wl_band_2ghz
= {
1183 .band
= IEEE80211_BAND_2GHZ
,
1184 .channels
= __wl_2ghz_channels
,
1185 .n_channels
= ARRAY_SIZE(__wl_2ghz_channels
),
1186 .bitrates
= wl_g_rates
,
1187 .n_bitrates
= wl_g_rates_size
1190 static struct ieee80211_supported_band __wl_band_5ghz_a
= {
1191 .band
= IEEE80211_BAND_5GHZ
,
1192 .channels
= __wl_5ghz_a_channels
,
1193 .n_channels
= ARRAY_SIZE(__wl_5ghz_a_channels
),
1194 .bitrates
= wl_a_rates
,
1195 .n_bitrates
= wl_a_rates_size
1198 static const u32 __wl_cipher_suites
[] = {
1199 WLAN_CIPHER_SUITE_WEP40
,
1200 WLAN_CIPHER_SUITE_WEP104
,
1201 WLAN_CIPHER_SUITE_TKIP
,
1202 WLAN_CIPHER_SUITE_CCMP
,
1205 * Advertising AES_CMAC cipher suite to userspace would imply that we
1206 * are supporting MFP. So advertise only when MFP support is enabled.
1208 WLAN_CIPHER_SUITE_AES_CMAC
,
1209 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1210 WLAN_CIPHER_SUITE_BIP_GMAC_256
,
1211 WLAN_CIPHER_SUITE_BIP_GMAC_128
,
1212 WLAN_CIPHER_SUITE_BIP_CMAC_256
,
1213 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1217 WLAN_CIPHER_SUITE_SMS4
,
1220 #if defined(WLAN_CIPHER_SUITE_PMK)
1221 WLAN_CIPHER_SUITE_PMK
,
1222 #endif /* WLAN_CIPHER_SUITE_PMK */
1224 WLAN_CIPHER_SUITE_GCMP
,
1225 WLAN_CIPHER_SUITE_GCMP_256
,
1226 WLAN_CIPHER_SUITE_BIP_GMAC_128
,
1227 WLAN_CIPHER_SUITE_BIP_GMAC_256
,
1228 #endif /* WL_GCMP */
1231 #ifdef WL_SUPPORT_ACS
1233 * The firmware code required for this feature to work is currently under
1234 * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1235 * required firmware code out of the BCMINTERNAL flag.
1237 struct wl_dump_survey
{
1245 #endif /* WL_SUPPORT_ACS */
1247 #ifdef WL_CFG80211_GON_COLLISION
1248 #define BLOCK_GON_REQ_MAX_NUM 5
1249 #endif /* WL_CFG80211_GON_COLLISION */
1251 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1252 static int maxrxpktglom
= 0;
1255 /* IOCtl version read from targeted driver */
1257 #ifdef DEBUGFS_CFG80211
1258 #define SUBLOGLEVEL 20
1259 #define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1))
1260 static const struct {
1263 } sublogname_map
[] = {
1264 {WL_DBG_ERR
, "ERR"},
1265 {WL_DBG_INFO
, "INFO"},
1266 {WL_DBG_DBG
, "DBG"},
1267 {WL_DBG_SCAN
, "SCAN"},
1268 {WL_DBG_TRACE
, "TRACE"},
1269 {WL_DBG_P2P_ACTION
, "P2PACTION"}
1273 typedef struct rsn_cipher_algo_entry
{
1277 } rsn_cipher_algo_entry_t
;
1279 static const rsn_cipher_algo_entry_t rsn_cipher_algo_lookup_tbl
[] = {
1280 {WLAN_CIPHER_SUITE_WEP40
, WEP_ENABLED
, CRYPTO_ALGO_WEP1
},
1281 {WLAN_CIPHER_SUITE_WEP104
, WEP_ENABLED
, CRYPTO_ALGO_WEP128
},
1282 {WLAN_CIPHER_SUITE_TKIP
, TKIP_ENABLED
, CRYPTO_ALGO_TKIP
},
1283 {WLAN_CIPHER_SUITE_CCMP
, AES_ENABLED
, CRYPTO_ALGO_AES_CCM
},
1284 {WLAN_CIPHER_SUITE_AES_CMAC
, AES_ENABLED
, CRYPTO_ALGO_BIP
},
1287 {WLAN_CIPHER_SUITE_SMS4
, SMS4_ENABLED
, CRYPTO_ALGO_SMS4
},
1288 #endif /* BCMWAPI_WPI */
1291 {WLAN_CIPHER_SUITE_GCMP
, AES_ENABLED
, CRYPTO_ALGO_AES_GCM
},
1292 {WLAN_CIPHER_SUITE_GCMP_256
, AES_ENABLED
, CRYPTO_ALGO_AES_GCM256
},
1293 {WLAN_CIPHER_SUITE_BIP_GMAC_128
, AES_ENABLED
, CRYPTO_ALGO_BIP_GMAC
},
1294 {WLAN_CIPHER_SUITE_BIP_GMAC_256
, AES_ENABLED
, CRYPTO_ALGO_BIP_GMAC256
},
1295 #endif /* WL_GCMP */
1296 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1297 {WLAN_CIPHER_SUITE_BIP_CMAC_256
, AES_ENABLED
, CRYPTO_ALGO_BIP_CMAC256
},
1298 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1301 typedef struct rsn_akm_wpa_auth_entry
{
1304 } rsn_akm_wpa_auth_entry_t
;
1306 static const rsn_akm_wpa_auth_entry_t rsn_akm_wpa_auth_lookup_tbl
[] = {
1308 {WLAN_AKM_SUITE_OWE
, WPA3_AUTH_OWE
},
1310 {WLAN_AKM_SUITE_8021X
, WPA2_AUTH_UNSPECIFIED
},
1311 {WL_AKM_SUITE_SHA256_1X
, WPA2_AUTH_1X_SHA256
},
1312 {WL_AKM_SUITE_SHA256_PSK
, WPA2_AUTH_PSK_SHA256
},
1313 {WLAN_AKM_SUITE_PSK
, WPA2_AUTH_PSK
},
1314 {WLAN_AKM_SUITE_FT_8021X
, WPA2_AUTH_UNSPECIFIED
| WPA2_AUTH_FT
},
1315 {WLAN_AKM_SUITE_FT_PSK
, WPA2_AUTH_PSK
| WPA2_AUTH_FT
},
1316 {WLAN_AKM_SUITE_FILS_SHA256
, WPA2_AUTH_FILS_SHA256
},
1317 {WLAN_AKM_SUITE_FILS_SHA384
, WPA2_AUTH_FILS_SHA384
},
1318 {WLAN_AKM_SUITE_8021X_SUITE_B
, WPA3_AUTH_1X_SUITE_B_SHA256
},
1319 {WLAN_AKM_SUITE_8021X_SUITE_B_192
, WPA3_AUTH_1X_SUITE_B_SHA384
},
1322 {WLAN_AKM_SUITE_WAPI_CERT
, WAPI_AUTH_UNSPECIFIED
},
1323 {WLAN_AKM_SUITE_WAPI_PSK
, WAPI_AUTH_PSK
},
1324 #endif /* BCMWAPI_WPI */
1326 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
1327 {WLAN_AKM_SUITE_SAE
, WPA3_AUTH_SAE_PSK
},
1328 #endif /* WL_SAE || WL_CLIENT_SAE */
1330 {WLAN_AKM_SUITE_FT_OVER_SAE
, WPA3_AUTH_SAE_PSK
| WPA2_AUTH_FT
},
1331 #endif /* WL_SAE_FT */
1332 {WLAN_AKM_SUITE_DPP
, WPA3_AUTH_DPP_AKM
},
1333 {WLAN_AKM_SUITE_FT_8021X_SHA384
, WPA3_AUTH_1X_SUITE_B_SHA384
| WPA2_AUTH_FT
}
1337 #define BUFSZN BUFSZ + 1
1342 #define SOFT_AP_IF_NAME "swlan0"
1344 /* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1345 uint32 fw_assoc_watchdog_ms
= 0;
1346 bool fw_assoc_watchdog_started
= 0;
1347 #define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1349 int wl_channel_to_frequency(u32 chan
, chanspec_band_t band
)
1352 return 0; /* not supported */
1355 case WL_CHANSPEC_BAND_2G
:
1359 return 2407 + chan
* 5;
1361 case WL_CHANSPEC_BAND_5G
:
1362 if (chan
>= 182 && chan
<= 196)
1363 return 4000 + chan
* 5;
1365 return 5000 + chan
* 5;
1368 case WL_CHANSPEC_BAND_6G
:
1369 return 5940 + chan
* 5;
1371 #endif /* WL_6G_BAND */
1373 WL_ERR(("Invalid Frequency Band\n"));
1375 return 0; /* not supported */
1378 static void wl_add_remove_pm_enable_work(struct bcm_cfg80211
*cfg
,
1379 enum wl_pm_workq_act_type type
)
1381 u16 wq_duration
= 0;
1383 dhd_pub_t
*dhd
= NULL
;
1388 dhd
= (dhd_pub_t
*)(cfg
->pub
);
1390 mutex_lock(&cfg
->pm_sync
);
1392 * Make cancel and schedule work part mutually exclusive
1393 * so that while cancelling, we are sure that there is no
1394 * work getting scheduled.
1396 if (delayed_work_pending(&cfg
->pm_enable_work
)) {
1397 cancel_delayed_work(&cfg
->pm_enable_work
);
1399 DHD_PM_WAKE_UNLOCK(cfg
->pub
);
1403 if (type
== WL_PM_WORKQ_SHORT
) {
1404 wq_duration
= WL_PM_ENABLE_TIMEOUT
;
1405 } else if (type
== WL_PM_WORKQ_LONG
) {
1406 wq_duration
= (WL_PM_ENABLE_TIMEOUT
*2);
1409 /* It should schedule work item only if driver is up */
1411 if (wq_duration
&& dhd
->up
) {
1413 if (schedule_delayed_work(&cfg
->pm_enable_work
,
1414 msecs_to_jiffies((const unsigned int)wq_duration
))) {
1416 DHD_PM_WAKE_LOCK_TIMEOUT(cfg
->pub
, wq_duration
);
1419 WL_ERR(("Can't schedule pm work handler\n"));
1422 mutex_unlock(&cfg
->pm_sync
);
1425 /* Return a new chanspec given a legacy chanspec
1426 * Returns INVCHANSPEC on error
1429 wl_chspec_from_legacy(chanspec_t legacy_chspec
)
1433 /* get the channel number */
1434 chspec
= LCHSPEC_CHANNEL(legacy_chspec
);
1436 /* convert the band */
1437 if (LCHSPEC_IS2G(legacy_chspec
)) {
1438 chspec
|= WL_CHANSPEC_BAND_2G
;
1440 chspec
|= WL_CHANSPEC_BAND_5G
;
1443 /* convert the bw and sideband */
1444 if (LCHSPEC_IS20(legacy_chspec
)) {
1445 chspec
|= WL_CHANSPEC_BW_20
;
1447 chspec
|= WL_CHANSPEC_BW_40
;
1448 if (LCHSPEC_CTL_SB(legacy_chspec
) == WL_LCHANSPEC_CTL_SB_LOWER
) {
1449 chspec
|= WL_CHANSPEC_CTL_SB_L
;
1451 chspec
|= WL_CHANSPEC_CTL_SB_U
;
1455 if (wf_chspec_malformed(chspec
)) {
1456 WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1464 /* Return a legacy chanspec given a new chanspec
1465 * Returns INVCHANSPEC on error
1468 wl_chspec_to_legacy(chanspec_t chspec
)
1472 if (wf_chspec_malformed(chspec
)) {
1473 WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1478 /* get the channel number */
1479 lchspec
= CHSPEC_CHANNEL(chspec
);
1481 /* convert the band */
1482 if (CHSPEC_IS2G(chspec
)) {
1483 lchspec
|= WL_LCHANSPEC_BAND_2G
;
1485 lchspec
|= WL_LCHANSPEC_BAND_5G
;
1488 /* convert the bw and sideband */
1489 if (CHSPEC_IS20(chspec
)) {
1490 lchspec
|= WL_LCHANSPEC_BW_20
;
1491 lchspec
|= WL_LCHANSPEC_CTL_SB_NONE
;
1492 } else if (CHSPEC_IS40(chspec
)) {
1493 lchspec
|= WL_LCHANSPEC_BW_40
;
1494 if (CHSPEC_CTL_SB(chspec
) == WL_CHANSPEC_CTL_SB_L
) {
1495 lchspec
|= WL_LCHANSPEC_CTL_SB_LOWER
;
1497 lchspec
|= WL_LCHANSPEC_CTL_SB_UPPER
;
1500 /* cannot express the bandwidth */
1501 char chanbuf
[CHANSPEC_STR_LEN
];
1503 "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1504 "to pre-11ac format\n",
1505 wf_chspec_ntoa(chspec
, chanbuf
), chspec
));
1512 bool wl_cfg80211_is_hal_started(struct bcm_cfg80211
*cfg
)
1514 return cfg
->hal_started
;
1517 /* given a chanspec value, do the endian and chanspec version conversion to
1518 * a chanspec_t value
1519 * Returns INVCHANSPEC on error
1522 wl_chspec_host_to_driver(chanspec_t chanspec
)
1524 if (ioctl_version
== 1) {
1525 chanspec
= wl_chspec_to_legacy(chanspec
);
1526 if (chanspec
== INVCHANSPEC
) {
1530 chanspec
= htodchanspec(chanspec
);
1535 /* given a channel value, do the endian and chanspec version conversion to
1536 * a chanspec_t value
1537 * Returns INVCHANSPEC on error
1540 wl_ch_host_to_driver(u16 channel
)
1542 chanspec_t chanspec
;
1543 chanspec_band_t band
;
1545 band
= WL_CHANNEL_BAND(channel
);
1547 chanspec
= wf_create_20MHz_chspec(channel
, band
);
1548 if (chanspec
== INVCHANSPEC
) {
1552 return wl_chspec_host_to_driver(chanspec
);
1555 /* given a chanspec value from the driver, do the endian and chanspec version conversion to
1556 * a chanspec_t value
1557 * Returns INVCHANSPEC on error
1560 wl_chspec_driver_to_host(chanspec_t chanspec
)
1562 chanspec
= dtohchanspec(chanspec
);
1563 if (ioctl_version
== 1) {
1564 chanspec
= wl_chspec_from_legacy(chanspec
);
1571 * convert ASCII string to MAC address (colon-delimited format)
1572 * eg: 00:11:22:33:44:55
1575 wl_cfg80211_ether_atoe(const char *a
, struct ether_addr
*n
)
1580 bzero(n
, ETHER_ADDR_LEN
);
1582 n
->octet
[count
++] = (uint8
)simple_strtoul(a
, &c
, 16);
1583 if (!*c
++ || count
== ETHER_ADDR_LEN
)
1587 return (count
== ETHER_ADDR_LEN
);
1590 /* There isn't a lot of sense in it, but you can transmit anything you like */
1591 static const struct ieee80211_txrx_stypes
1592 wl_cfg80211_default_mgmt_stypes
[NUM_NL80211_IFTYPES
] = {
1593 #ifdef WLMESH_CFG80211
1594 [NL80211_IFTYPE_MESH_POINT
] = {
1596 .rx
= BIT(IEEE80211_STYPE_ACTION
>> 4) |
1597 BIT(IEEE80211_STYPE_AUTH
>> 4)
1599 #endif /* WLMESH_CFG80211 */
1600 [NL80211_IFTYPE_ADHOC
] = {
1602 .rx
= BIT(IEEE80211_STYPE_ACTION
>> 4)
1604 [NL80211_IFTYPE_STATION
] = {
1606 .rx
= BIT(IEEE80211_STYPE_ACTION
>> 4) |
1607 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4)
1608 #ifdef WL_CLIENT_SAE
1609 | BIT(IEEE80211_STYPE_AUTH
>> 4)
1610 #endif /* WL_CLIENT_SAE */
1612 [NL80211_IFTYPE_AP
] = {
1614 .rx
= BIT(IEEE80211_STYPE_ASSOC_REQ
>> 4) |
1615 BIT(IEEE80211_STYPE_REASSOC_REQ
>> 4) |
1616 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4) |
1617 BIT(IEEE80211_STYPE_DISASSOC
>> 4) |
1618 BIT(IEEE80211_STYPE_AUTH
>> 4) |
1619 BIT(IEEE80211_STYPE_DEAUTH
>> 4) |
1620 BIT(IEEE80211_STYPE_ACTION
>> 4)
1622 [NL80211_IFTYPE_AP_VLAN
] = {
1625 .rx
= BIT(IEEE80211_STYPE_ASSOC_REQ
>> 4) |
1626 BIT(IEEE80211_STYPE_REASSOC_REQ
>> 4) |
1627 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4) |
1628 BIT(IEEE80211_STYPE_DISASSOC
>> 4) |
1629 BIT(IEEE80211_STYPE_AUTH
>> 4) |
1630 BIT(IEEE80211_STYPE_DEAUTH
>> 4) |
1631 BIT(IEEE80211_STYPE_ACTION
>> 4)
1633 [NL80211_IFTYPE_P2P_CLIENT
] = {
1635 .rx
= BIT(IEEE80211_STYPE_ACTION
>> 4) |
1636 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4)
1638 [NL80211_IFTYPE_P2P_GO
] = {
1640 .rx
= BIT(IEEE80211_STYPE_ASSOC_REQ
>> 4) |
1641 BIT(IEEE80211_STYPE_REASSOC_REQ
>> 4) |
1642 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4) |
1643 BIT(IEEE80211_STYPE_DISASSOC
>> 4) |
1644 BIT(IEEE80211_STYPE_AUTH
>> 4) |
1645 BIT(IEEE80211_STYPE_DEAUTH
>> 4) |
1646 BIT(IEEE80211_STYPE_ACTION
>> 4)
1648 #if defined(WL_CFG80211_P2P_DEV_IF)
1649 [NL80211_IFTYPE_P2P_DEVICE
] = {
1651 .rx
= BIT(IEEE80211_STYPE_ACTION
>> 4) |
1652 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4)
1654 #endif /* WL_CFG80211_P2P_DEV_IF */
1657 static void swap_key_from_BE(struct wl_wsec_key
*key
)
1659 key
->index
= htod32(key
->index
);
1660 key
->len
= htod32(key
->len
);
1661 key
->algo
= htod32(key
->algo
);
1662 key
->flags
= htod32(key
->flags
);
1663 key
->rxiv
.hi
= htod32(key
->rxiv
.hi
);
1664 key
->rxiv
.lo
= htod16(key
->rxiv
.lo
);
1665 key
->iv_initialized
= htod32(key
->iv_initialized
);
1668 static void swap_key_to_BE(struct wl_wsec_key
*key
)
1670 key
->index
= dtoh32(key
->index
);
1671 key
->len
= dtoh32(key
->len
);
1672 key
->algo
= dtoh32(key
->algo
);
1673 key
->flags
= dtoh32(key
->flags
);
1674 key
->rxiv
.hi
= dtoh32(key
->rxiv
.hi
);
1675 key
->rxiv
.lo
= dtoh16(key
->rxiv
.lo
);
1676 key
->iv_initialized
= dtoh32(key
->iv_initialized
);
1679 #if defined(WL_FW_OCE_AP_SELECT)
1680 bool static wl_cfg80211_is_oce_ap(struct wiphy
*wiphy
, const u8
*bssid_hint
)
1682 const u8
*parse
= NULL
;
1684 const struct cfg80211_bss_ies
*ies
;
1686 struct cfg80211_bss
*bss
;
1688 bss
= CFG80211_GET_BSS(wiphy
, NULL
, bssid_hint
, 0, 0);
1690 WL_ERR(("Unable to find AP in the cache"));
1694 if (rcu_access_pointer(bss
->ies
)) {
1695 ies
= rcu_access_pointer(bss
->ies
);
1699 WL_ERR(("ies is NULL"));
1703 while ((ie
= bcm_parse_tlvs(parse
, len
, DOT11_MNG_VS_ID
))) {
1704 if (wl_cfgoce_is_oce_ie((const uint8
*)ie
, (u8
const **)&parse
, &len
) == TRUE
) {
1707 ie
= bcm_next_tlv((const bcm_tlv_t
*) ie
, &len
);
1711 parse
= (uint8
*)ie
;
1712 WL_DBG(("NON OCE IE. next ie ptr:%p", parse
));
1715 WL_DBG(("OCE IE NOT found"));
1718 #endif /* WL_FW_OCE_AP_SELECT */
1720 /* Dump the contents of the encoded wps ie buffer and get pbc value */
1722 wl_validate_wps_ie(const char *wps_ie
, s32 wps_ie_len
, bool *pbc
)
1724 #define WPS_IE_FIXED_LEN 6
1726 const u8
*subel
= NULL
;
1730 u8
*valptr
= (uint8
*) &val
;
1731 if (wps_ie
== NULL
|| wps_ie_len
< WPS_IE_FIXED_LEN
) {
1732 WL_ERR(("invalid argument : NULL\n"));
1735 len
= (s16
)wps_ie
[TLV_LEN_OFF
];
1737 if (len
> wps_ie_len
) {
1738 WL_ERR(("invalid length len %d, wps ie len %d\n", len
, wps_ie_len
));
1741 WL_DBG(("wps_ie len=%d\n", len
));
1742 len
-= 4; /* for the WPS IE's OUI, oui_type fields */
1743 subel
= wps_ie
+ WPS_IE_FIXED_LEN
;
1744 while (len
>= 4) { /* must have attr id, attr len fields */
1745 valptr
[0] = *subel
++;
1746 valptr
[1] = *subel
++;
1747 subelt_id
= HTON16(val
);
1749 valptr
[0] = *subel
++;
1750 valptr
[1] = *subel
++;
1751 subelt_len
= HTON16(val
);
1753 len
-= 4; /* for the attr id, attr len fields */
1754 len
-= (s16
)subelt_len
; /* for the remaining fields in this attribute */
1758 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
1759 subel
, subelt_id
, subelt_len
));
1761 if (subelt_id
== WPS_ID_VERSION
) {
1762 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel
));
1763 } else if (subelt_id
== WPS_ID_REQ_TYPE
) {
1764 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel
));
1765 } else if (subelt_id
== WPS_ID_CONFIG_METHODS
) {
1767 valptr
[1] = *(subel
+ 1);
1768 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val
)));
1769 } else if (subelt_id
== WPS_ID_DEVICE_NAME
) {
1771 int namelen
= MIN(subelt_len
, (sizeof(devname
) - 1));
1774 memcpy(devname
, subel
, namelen
);
1775 devname
[namelen
] = '\0';
1776 /* Printing len as rx'ed in the IE */
1777 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1778 devname
, subelt_len
));
1780 } else if (subelt_id
== WPS_ID_DEVICE_PWD_ID
) {
1782 valptr
[1] = *(subel
+ 1);
1783 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val
)));
1784 *pbc
= (HTON16(val
) == DEV_PW_PUSHBUTTON
) ? true : false;
1785 } else if (subelt_id
== WPS_ID_PRIM_DEV_TYPE
) {
1787 valptr
[1] = *(subel
+ 1);
1788 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val
)));
1789 valptr
[0] = *(subel
+ 6);
1790 valptr
[1] = *(subel
+ 7);
1791 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val
)));
1792 } else if (subelt_id
== WPS_ID_REQ_DEV_TYPE
) {
1794 valptr
[1] = *(subel
+ 1);
1795 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val
)));
1796 valptr
[0] = *(subel
+ 6);
1797 valptr
[1] = *(subel
+ 7);
1798 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val
)));
1799 } else if (subelt_id
== WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS
) {
1801 valptr
[1] = *(subel
+ 1);
1802 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1803 ": cat=%u\n", HTON16(val
)));
1805 WL_DBG((" unknown attr 0x%x\n", subelt_id
));
1808 subel
+= subelt_len
;
1812 s32
wl_set_tx_power(struct net_device
*dev
,
1813 enum nl80211_tx_power_setting type
, s32 dbm
)
1818 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
1820 /* Make sure radio is off or on as far as software is concerned */
1821 disable
= WL_RADIO_SW_DISABLE
<< 16;
1822 disable
= htod32(disable
);
1823 err
= wldev_ioctl_set(dev
, WLC_SET_RADIO
, &disable
, sizeof(disable
));
1824 if (unlikely(err
)) {
1825 WL_ERR(("WLC_SET_RADIO error (%d)\n", err
));
1831 txpwrqdbm
= dbm
* 4;
1832 #ifdef SUPPORT_WL_TXPOWER
1833 if (type
== NL80211_TX_POWER_AUTOMATIC
)
1836 txpwrqdbm
|= WL_TXPWR_OVERRIDE
;
1837 #endif /* SUPPORT_WL_TXPOWER */
1838 err
= wldev_iovar_setbuf_bsscfg(dev
, "qtxpower", (void *)&txpwrqdbm
,
1839 sizeof(txpwrqdbm
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, 0,
1840 &cfg
->ioctl_buf_sync
);
1842 WL_ERR(("qtxpower error (%d)\n", err
));
1844 WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm
, txpwrqdbm
));
1849 s32
wl_get_tx_power(struct net_device
*dev
, s32
*dbm
)
1853 char ioctl_buf
[WLC_IOCTL_SMLEN
];
1855 err
= wldev_iovar_getbuf_bsscfg(dev
, "qtxpower",
1856 NULL
, 0, ioctl_buf
, WLC_IOCTL_SMLEN
, 0, NULL
);
1857 if (unlikely(err
)) {
1858 WL_ERR(("error (%d)\n", err
));
1862 memcpy(&txpwrdbm
, ioctl_buf
, sizeof(txpwrdbm
));
1863 txpwrdbm
= dtoh32(txpwrdbm
);
1864 *dbm
= (txpwrdbm
& ~WL_TXPWR_OVERRIDE
) / 4;
1866 WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm
, txpwrdbm
));
1871 static chanspec_t
wl_cfg80211_get_shared_freq(struct wiphy
*wiphy
)
1874 int cur_band
, err
= 0;
1875 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
1876 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
1877 struct ether_addr bssid
;
1878 wl_bss_info_t
*bss
= NULL
;
1879 u16 channel
= WL_P2P_TEMP_CHAN
;
1882 bzero(&bssid
, sizeof(bssid
));
1883 if ((err
= wldev_ioctl_get(dev
, WLC_GET_BSSID
, &bssid
, sizeof(bssid
)))) {
1884 /* STA interface is not associated. So start the new interface on a temp
1885 * channel . Later proper channel will be applied by the above framework
1886 * via set_channel (cfg80211 API).
1888 WL_DBG(("Not associated. Return a temp channel. \n"));
1890 err
= wldev_ioctl_get(dev
, WLC_GET_BAND
, &cur_band
, sizeof(int));
1891 if (unlikely(err
)) {
1892 WL_ERR(("Get band failed\n"));
1893 } else if (cur_band
== WLC_BAND_5G
|| cur_band
== WLC_BAND_6G
) {
1894 channel
= WL_P2P_TEMP_CHAN_5G
;
1896 return wl_ch_host_to_driver(channel
);
1899 buf
= (char *)MALLOCZ(cfg
->osh
, WL_EXTRA_BUF_MAX
);
1901 WL_ERR(("buf alloc failed. use temp channel\n"));
1902 return wl_ch_host_to_driver(channel
);
1905 *(u32
*)buf
= htod32(WL_EXTRA_BUF_MAX
);
1906 if ((err
= wldev_ioctl_get(dev
, WLC_GET_BSS_INFO
, buf
,
1907 WL_EXTRA_BUF_MAX
))) {
1908 WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1909 chspec
= wl_ch_host_to_driver(channel
);
1912 bss
= (wl_bss_info_t
*) (buf
+ 4);
1913 chspec
= bss
->chanspec
;
1915 /* Avoid p2p bring up in 6G based on bssinfo */
1916 if (CHSPEC_IS6G(chspec
)) {
1917 channel
= WL_P2P_TEMP_CHAN_5G
;
1918 chspec
= wl_ch_host_to_driver(channel
);
1920 #endif /* WL_6G_BAND */
1921 WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec
));
1924 MFREE(cfg
->osh
, buf
, WL_EXTRA_BUF_MAX
);
1929 wl_wlfc_enable(struct bcm_cfg80211
*cfg
, bool enable
)
1931 #ifdef PROP_TXSTATUS_VSDB
1932 #if defined(BCMSDIO) || defined(BCMDBUS)
1933 bool wlfc_enabled
= FALSE
;
1936 struct net_device
*primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
1938 dhd
= (dhd_pub_t
*)(cfg
->pub
);
1944 if (!cfg
->wlfc_on
&& !disable_proptx
) {
1945 dhd_wlfc_get_enable(dhd
, &wlfc_enabled
);
1946 if (!wlfc_enabled
&& dhd
->op_mode
!= DHD_FLAG_HOSTAP_MODE
&&
1947 dhd
->op_mode
!= DHD_FLAG_IBSS_MODE
) {
1949 err
= wldev_ioctl_set(primary_ndev
, WLC_UP
, &up
, sizeof(s32
));
1951 WL_ERR(("WLC_UP return err:%d\n", err
));
1953 cfg
->wlfc_on
= true;
1954 WL_DBG(("wlfc_on:%d \n", cfg
->wlfc_on
));
1956 } else if (dhd
->conf
->disable_proptx
!= 0){
1957 dhd_wlfc_deinit(dhd
);
1958 cfg
->wlfc_on
= false;
1960 #endif /* BCMSDIO || BCMDBUS */
1961 #endif /* PROP_TXSTATUS_VSDB */
1964 struct wireless_dev
*
1965 wl_cfg80211_p2p_if_add(struct bcm_cfg80211
*cfg
,
1966 wl_iftype_t wl_iftype
,
1967 char const *name
, u8
*mac_addr
, s32
*ret_err
)
1975 struct net_device
*new_ndev
= NULL
;
1976 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
1977 struct ether_addr
*p2p_addr
;
1981 WL_ERR(("p2p not initialized\n"));
1985 #if defined(WL_CFG80211_P2P_DEV_IF)
1986 if (wl_iftype
== WL_IF_TYPE_P2P_DISC
) {
1987 /* Handle Dedicated P2P discovery Interface */
1988 return wl_cfgp2p_add_p2p_disc_if(cfg
);
1990 #endif /* WL_CFG80211_P2P_DEV_IF */
1992 if (wl_iftype
== WL_IF_TYPE_P2P_GO
) {
1993 p2p_iftype
= WL_P2P_IF_GO
;
1995 p2p_iftype
= WL_P2P_IF_CLIENT
;
1998 /* Dual p2p doesn't support multiple P2PGO interfaces,
1999 * p2p_go_count is the counter for GO creation
2002 if ((cfg
->p2p
->p2p_go_count
> 0) && (wl_iftype
== WL_IF_TYPE_P2P_GO
)) {
2003 WL_ERR(("FW does not support multiple GO\n"));
2004 *ret_err
= -ENOTSUPP
;
2007 if (!cfg
->p2p
->on
) {
2009 wl_cfgp2p_set_firm_p2p(cfg
);
2010 wl_cfgp2p_init_discovery(cfg
);
2013 strlcpy(cfg
->p2p
->vir_ifname
, name
, sizeof(cfg
->p2p
->vir_ifname
));
2014 /* In concurrency case, STA may be already associated in a particular channel.
2015 * so retrieve the current channel of primary interface and then start the virtual
2016 * interface on that.
2018 chspec
= wl_cfg80211_get_shared_freq(wiphy
);
2020 /* For P2P mode, use P2P-specific driver features to create the
2021 * bss: "cfg p2p_ifadd"
2023 wl_set_p2p_status(cfg
, IF_ADDING
);
2024 bzero(&cfg
->if_event_info
, sizeof(cfg
->if_event_info
));
2025 cfg_type
= wl_cfgp2p_get_conn_idx(cfg
);
2026 if (cfg_type
== BCME_ERROR
) {
2027 wl_clr_p2p_status(cfg
, IF_ADDING
);
2028 WL_ERR(("Failed to get connection idx for p2p interface\n"));
2032 p2p_addr
= wl_to_p2p_bss_macaddr(cfg
, cfg_type
);
2033 memcpy(p2p_addr
->octet
, mac_addr
, ETH_ALEN
);
2035 err
= wl_cfgp2p_ifadd(cfg
, p2p_addr
,
2036 htod32(p2p_iftype
), chspec
);
2037 if (unlikely(err
)) {
2038 wl_clr_p2p_status(cfg
, IF_ADDING
);
2039 WL_ERR((" virtual iface add failed (%d) \n", err
));
2043 /* Wait for WLC_E_IF event with IF_ADD opcode */
2044 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
2045 ((wl_get_p2p_status(cfg
, IF_ADDING
) == false) &&
2046 (cfg
->if_event_info
.valid
)),
2047 msecs_to_jiffies(MAX_WAIT_TIME
));
2048 if (timeout
> 0 && !wl_get_p2p_status(cfg
, IF_ADDING
) && cfg
->if_event_info
.valid
) {
2049 wl_if_event_info
*event
= &cfg
->if_event_info
;
2050 new_ndev
= wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg
), event
,
2051 event
->mac
, cfg
->p2p
->vir_ifname
, false);
2052 if (unlikely(!new_ndev
)) {
2056 if (wl_iftype
== WL_IF_TYPE_P2P_GO
) {
2057 cfg
->p2p
->p2p_go_count
++;
2059 /* Fill p2p specific data */
2060 wl_to_p2p_bss_ndev(cfg
, cfg_type
) = new_ndev
;
2061 wl_to_p2p_bss_bssidx(cfg
, cfg_type
) = event
->bssidx
;
2063 WL_ERR((" virtual interface(%s) is "
2064 "created net attach done\n", cfg
->p2p
->vir_ifname
));
2065 dhd_mode
= (wl_iftype
== WL_IF_TYPE_P2P_GC
) ?
2066 DHD_FLAG_P2P_GC_MODE
: DHD_FLAG_P2P_GO_MODE
;
2067 DNGL_FUNC(dhd_cfg80211_set_p2p_info
, (cfg
, dhd_mode
));
2068 /* reinitialize completion to clear previous count */
2069 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
2070 INIT_COMPLETION(cfg
->iface_disable
);
2072 init_completion(&cfg
->iface_disable
);
2073 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
2075 return new_ndev
->ieee80211_ptr
;
2083 wl_cfg80211_check_vif_in_use(struct net_device
*ndev
)
2085 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
2086 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
2087 bool nan_enabled
= FALSE
;
2090 nan_enabled
= wl_cfgnan_is_enabled(cfg
);
2093 if (nan_enabled
|| (wl_cfgp2p_vif_created(cfg
)) ||
2094 (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
2095 WL_MEM(("%s: Virtual interfaces in use. NAN %d P2P %d softAP %d\n",
2096 __FUNCTION__
, nan_enabled
, wl_cfgp2p_vif_created(cfg
),
2097 (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
)));
2105 wl_cfg80211_iface_state_ops(struct wireless_dev
*wdev
,
2106 wl_interface_state_t state
,
2107 wl_iftype_t wl_iftype
, u16 wl_mode
)
2109 struct net_device
*ndev
;
2110 struct bcm_cfg80211
*cfg
;
2114 WL_DBG(("state:%s wl_iftype:%d mode:%d\n",
2115 wl_if_state_strs
[state
], wl_iftype
, wl_mode
));
2117 WL_ERR(("wdev null\n"));
2121 if ((wl_iftype
== WL_IF_TYPE_P2P_DISC
) || (wl_iftype
== WL_IF_TYPE_NAN_NMI
)) {
2122 /* P2P discovery is a netless device and uses a
2123 * hidden bsscfg interface in fw. Don't apply the
2124 * iface ops state changes for p2p discovery I/F.
2125 * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
2126 * Don't apply iface ops state changes for NMI I/F.
2131 cfg
= wiphy_priv(wdev
->wiphy
);
2132 ndev
= wdev
->netdev
;
2133 dhd
= (dhd_pub_t
*)(cfg
->pub
);
2135 bssidx
= wl_get_bssidx_by_wdev(cfg
, wdev
);
2136 if (!ndev
|| (bssidx
< 0)) {
2137 WL_ERR(("ndev null. skip iface state ops\n"));
2142 case WL_IF_CREATE_REQ
:
2144 /* check fakeapscan in progress then abort */
2145 wl_android_bcnrecv_stop(ndev
, WL_BCNRECV_CONCURRENCY
);
2146 #endif /* WL_BCNRECV */
2147 wl_cfg80211_scan_abort(cfg
);
2148 wl_wlfc_enable(cfg
, true);
2150 /* disable TDLS if number of connected interfaces is >= 1 */
2151 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_IF_CREATE
, false);
2154 case WL_IF_DELETE_REQ
:
2156 wl_wps_handle_ifdel(ndev
);
2157 #endif /* WPS_SYNC */
2158 if (wl_get_drv_status(cfg
, SCANNING
, ndev
)) {
2159 /* Send completion for any pending scans */
2160 wl_cfg80211_cancel_scan(cfg
);
2163 #ifdef CUSTOM_SET_CPUCORE
2164 dhd
->chan_isvht80
&= ~DHD_FLAG_P2P_MODE
;
2165 if (!(dhd
->chan_isvht80
)) {
2166 dhd_set_cpucore(dhd
, FALSE
);
2168 #endif /* CUSTOM_SET_CPUCORE */
2169 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_DEL
);
2171 case WL_IF_CREATE_DONE
:
2172 if (wl_mode
== WL_MODE_BSS
) {
2173 /* Common code for sta type interfaces - STA, GC */
2174 /* Enable firmware key buffering before sent 4-way M4 */
2175 wldev_iovar_setint(ndev
, "buf_key_b4_m4", 1);
2177 if (wl_iftype
== WL_IF_TYPE_P2P_GC
) {
2178 /* Disable firmware roaming for P2P interface */
2179 wldev_iovar_setint(ndev
, "roam_off", 1);
2180 wldev_iovar_setint(ndev
, "bcn_timeout", dhd
->conf
->bcn_timeout
);
2182 int assoc_retry
= 3;
2183 #if defined(CUSTOM_ASSOC_RETRY_MAX)
2184 assoc_retry
= CUSTOM_ASSOC_RETRY_MAX
;
2185 #endif /* CUSTOM_ASSOC_RETRY_MAX */
2186 /* set retry_max to CUSTOM_ASSOC_RETRY_MAX(3) */
2187 wldev_iovar_setint(ndev
, "assoc_retry_max", assoc_retry
);
2190 if (wl_mode
== WL_MODE_AP
) {
2191 /* Common code for AP/GO */
2194 case WL_IF_DELETE_DONE
:
2196 /* Enable back TDLS if connected interface is <= 1 */
2197 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_IF_DELETE
, false);
2199 wl_wlfc_enable(cfg
, false);
2201 case WL_IF_CHANGE_REQ
:
2202 /* Flush existing IEs from firmware on role change */
2203 wl_cfg80211_clear_per_bss_ies(cfg
, wdev
);
2205 case WL_IF_CHANGE_DONE
:
2206 if (wl_mode
== WL_MODE_BSS
) {
2207 /* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2208 wldev_iovar_setint(ndev
, "buf_key_b4_m4", 1);
2213 WL_ERR(("Unsupported state: %d\n", state
));
2219 wl_cfg80211_p2p_if_del(struct wiphy
*wiphy
, struct wireless_dev
*wdev
)
2221 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2225 struct net_device
*ndev
;
2227 struct ether_addr p2p_dev_addr
= {{0}};
2229 if (unlikely(!wl_get_drv_status(cfg
, READY
, bcmcfg_to_prmry_ndev(cfg
)))) {
2230 WL_INFORM_MEM(("device is not ready\n"));
2231 return BCME_NOTFOUND
;
2234 #ifdef WL_CFG80211_P2P_DEV_IF
2235 if (wdev
->iftype
== NL80211_IFTYPE_P2P_DEVICE
) {
2236 /* Handle dedicated P2P discovery interface. */
2237 return wl_cfgp2p_del_p2p_disc_if(wdev
, cfg
);
2239 #endif /* WL_CFG80211_P2P_DEV_IF */
2241 /* Handle P2P Group Interface */
2242 bssidx
= wl_get_bssidx_by_wdev(cfg
, wdev
);
2244 WL_ERR(("bssidx not found\n"));
2245 return BCME_NOTFOUND
;
2247 if (wl_cfgp2p_find_type(cfg
, bssidx
, &cfg_type
) != BCME_OK
) {
2248 /* Couldn't find matching iftype */
2249 WL_MEM(("non P2P interface\n"));
2250 return BCME_NOTFOUND
;
2253 ndev
= wdev
->netdev
;
2254 (void)memcpy_s(p2p_dev_addr
.octet
, ETHER_ADDR_LEN
,
2255 ndev
->dev_addr
, ETHER_ADDR_LEN
);
2257 wl_clr_p2p_status(cfg
, GO_NEG_PHASE
);
2258 wl_clr_p2p_status(cfg
, IF_ADDING
);
2261 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
) {
2262 wl_add_remove_eventmsg(ndev
, WLC_E_PROBREQ_MSG
, false);
2263 cfg
->p2p
->p2p_go_count
--;
2264 /* disable interface before bsscfg free */
2265 err
= wl_cfgp2p_ifdisable(cfg
, &p2p_dev_addr
);
2266 /* if fw doesn't support "ifdis",
2267 do not wait for link down of ap mode
2270 WL_ERR(("Wait for Link Down event for GO !!!\n"));
2271 wait_for_completion_timeout(&cfg
->iface_disable
,
2272 msecs_to_jiffies(500));
2273 } else if (err
!= BCME_UNSUPPORTED
) {
2278 if (wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
2279 WL_ERR(("Wait for Link Down event for GC !\n"));
2280 wait_for_completion_timeout
2281 (&cfg
->iface_disable
, msecs_to_jiffies(500));
2284 /* Force P2P disconnect in iface down context */
2285 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
2286 WL_INFORM_MEM(("force send disconnect event\n"));
2287 CFG80211_DISCONNECTED(ndev
, 0, NULL
, 0, false, GFP_KERNEL
);
2288 wl_clr_drv_status(cfg
, AUTHORIZED
, ndev
);
2292 bzero(&cfg
->if_event_info
, sizeof(cfg
->if_event_info
));
2293 wl_set_p2p_status(cfg
, IF_DELETING
);
2294 DNGL_FUNC(dhd_cfg80211_clean_p2p_info
, (cfg
));
2296 err
= wl_cfgp2p_ifdel(cfg
, &p2p_dev_addr
);
2297 if (unlikely(err
)) {
2298 WL_ERR(("P2P IFDEL operation failed, error code = %d\n", err
));
2302 /* Wait for WLC_E_IF event */
2303 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
2304 ((wl_get_p2p_status(cfg
, IF_DELETING
) == false) &&
2305 (cfg
->if_event_info
.valid
)),
2306 msecs_to_jiffies(MAX_WAIT_TIME
));
2307 if (timeout
> 0 && !wl_get_p2p_status(cfg
, IF_DELETING
) &&
2308 cfg
->if_event_info
.valid
) {
2309 WL_ERR(("P2P IFDEL operation done\n"));
2312 WL_ERR(("IFDEL didn't complete properly\n"));
2318 /* Even in failure case, attempt to remove the host data structure.
2319 * Firmware would be cleaned up via WiFi reset done by the
2320 * user space from hang event context (for android only).
2322 bzero(cfg
->p2p
->vir_ifname
, IFNAMSIZ
);
2323 wl_to_p2p_bss_bssidx(cfg
, cfg_type
) = -1;
2324 wl_to_p2p_bss_ndev(cfg
, cfg_type
) = NULL
;
2325 wl_clr_drv_status(cfg
, CONNECTED
, wl_to_p2p_bss_ndev(cfg
, cfg_type
));
2326 dhd_net_if_lock(ndev
);
2327 if (cfg
->if_event_info
.ifidx
) {
2328 /* Remove interface except for primary ifidx */
2329 wl_cfg80211_remove_if(cfg
, cfg
->if_event_info
.ifidx
, ndev
, FALSE
);
2331 dhd_net_if_unlock(ndev
);
2335 #ifdef WL_IFACE_MGMT
2336 /* Get active secondary data iface type */
2338 wl_cfg80211_get_sec_iface(struct bcm_cfg80211
*cfg
)
2340 #ifndef WL_STATIC_IF
2341 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
2342 #endif /* !WL_STATIC_IF */
2343 struct net_device
*p2p_ndev
= NULL
;
2345 p2p_ndev
= wl_to_p2p_bss_ndev(cfg
,
2346 P2PAPI_BSSCFG_CONNECTION1
);
2349 if (IS_CFG80211_STATIC_IF_ACTIVE(cfg
)) {
2350 if (IS_AP_IFACE(cfg
->static_ndev
->ieee80211_ptr
)) {
2351 return WL_IF_TYPE_AP
;
2355 if (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
2356 return WL_IF_TYPE_AP
;
2358 #endif /* WL_STATIC_IF */
2360 if (p2p_ndev
&& p2p_ndev
->ieee80211_ptr
) {
2361 if (p2p_ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
2362 return WL_IF_TYPE_P2P_GO
;
2365 /* Set role to GC when cfg80211 layer downgrades P2P
2366 * role to station type while bringing down the interface
2368 if (p2p_ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
) {
2369 WL_DBG_MEM(("%s, Change to GC base role\n", __FUNCTION__
));
2370 return WL_IF_TYPE_P2P_GC
;
2373 if (p2p_ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_CLIENT
) {
2374 return WL_IF_TYPE_P2P_GC
;
2379 if (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg
))) {
2380 return WL_IF_TYPE_NAN
;
2383 return WL_IFACE_NOT_PRESENT
;
2387 * Handle incoming data interface request based on policy.
2388 * If there is any conflicting interface, that will be
2392 wl_cfg80211_data_if_mgmt(struct bcm_cfg80211
*cfg
,
2393 wl_iftype_t new_wl_iftype
)
2396 bool del_iface
= false;
2397 wl_iftype_t sec_wl_if_type
= wl_cfg80211_get_sec_iface(cfg
);
2399 if (sec_wl_if_type
== WL_IF_TYPE_NAN
&&
2400 new_wl_iftype
== WL_IF_TYPE_NAN
) {
2401 /* Multi NDP is allowed irrespective of Policy */
2405 if (sec_wl_if_type
== WL_IFACE_NOT_PRESENT
) {
2407 * If there is no active secondary I/F, there
2408 * is no interface conflict. Do nothing.
2413 /* Handle secondary data link case */
2414 switch (cfg
->iface_data
.policy
) {
2415 case WL_IF_POLICY_CUSTOM
:
2416 case WL_IF_POLICY_DEFAULT
: {
2417 WL_INFORM_MEM(("%s, Delete any existing iface\n", __FUNCTION__
));
2421 case WL_IF_POLICY_FCFS
: {
2422 WL_INFORM_MEM(("Found active iface = %s, can't support new iface = %s\n",
2423 wl_iftype_to_str(sec_wl_if_type
), wl_iftype_to_str(new_wl_iftype
)));
2427 case WL_IF_POLICY_LP
: {
2428 WL_INFORM_MEM(("Remove active sec data interface, allow incoming iface\n"));
2429 /* Delete existing data iface and allow incoming sec iface */
2433 case WL_IF_POLICY_ROLE_PRIORITY
: {
2434 WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2435 wl_iftype_to_str(sec_wl_if_type
),
2436 cfg
->iface_data
.priority
[sec_wl_if_type
],
2437 wl_iftype_to_str(new_wl_iftype
),
2438 cfg
->iface_data
.priority
[new_wl_iftype
]));
2439 if (cfg
->iface_data
.priority
[new_wl_iftype
] >
2440 cfg
->iface_data
.priority
[sec_wl_if_type
]) {
2443 WL_ERR(("Can't support new iface = %s\n",
2444 wl_iftype_to_str(new_wl_iftype
)));
2450 WL_ERR(("Unsupported interface policy = %d\n",
2451 cfg
->iface_data
.policy
));
2456 ret
= wl_cfg80211_delete_iface(cfg
, sec_wl_if_type
);
2461 /* Handle discovery ifaces based on policy */
2463 wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211
*cfg
,
2464 wl_iftype_t new_wl_iftype
, bool *disable_nan
, bool *disable_p2p
)
2467 wl_iftype_t sec_wl_if_type
=
2468 wl_cfg80211_get_sec_iface(cfg
);
2469 *disable_p2p
= false;
2470 *disable_nan
= false;
2472 if (sec_wl_if_type
== WL_IF_TYPE_NAN
&&
2473 new_wl_iftype
== WL_IF_TYPE_NAN
) {
2474 /* Multi NDP is allowed irrespective of Policy */
2479 * Check for any policy conflicts with active secondary
2480 * interface for incoming discovery iface
2482 if ((sec_wl_if_type
!= WL_IFACE_NOT_PRESENT
) &&
2483 (is_discovery_iface(new_wl_iftype
))) {
2484 switch (cfg
->iface_data
.policy
) {
2485 case WL_IF_POLICY_CUSTOM
: {
2486 if (sec_wl_if_type
== WL_IF_TYPE_NAN
&&
2487 new_wl_iftype
== WL_IF_TYPE_P2P_DISC
) {
2488 WL_INFORM_MEM(("Allow P2P Discovery with active NDP\n"));
2489 /* No further checks are required. */
2493 * Intentional fall through to default policy
2494 * as for AP and associated ifaces, both are same
2497 case WL_IF_POLICY_DEFAULT
: {
2498 if (sec_wl_if_type
== WL_IF_TYPE_AP
) {
2499 WL_INFORM_MEM(("AP is active, cant support new iface\n"));
2501 } else if (sec_wl_if_type
== WL_IF_TYPE_P2P_GC
||
2502 sec_wl_if_type
== WL_IF_TYPE_P2P_GO
) {
2503 if (new_wl_iftype
== WL_IF_TYPE_P2P_DISC
) {
2505 * Associated discovery case,
2509 /* Active iface is present, returning error */
2510 WL_INFORM_MEM(("P2P group is active,"
2511 " cant support new iface\n"));
2514 } else if (sec_wl_if_type
== WL_IF_TYPE_NAN
) {
2515 ret
= wl_cfg80211_delete_iface(cfg
, sec_wl_if_type
);
2519 case WL_IF_POLICY_FCFS
: {
2520 WL_INFORM_MEM(("Can't support new iface = %s\n",
2521 wl_iftype_to_str(new_wl_iftype
)));
2525 case WL_IF_POLICY_LP
: {
2526 /* Delete existing data iface n allow incoming sec iface */
2527 WL_INFORM_MEM(("Remove active sec data interface = %s\n",
2528 wl_iftype_to_str(sec_wl_if_type
)));
2529 ret
= wl_cfg80211_delete_iface(cfg
,
2533 case WL_IF_POLICY_ROLE_PRIORITY
: {
2534 WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2535 wl_iftype_to_str(sec_wl_if_type
),
2536 cfg
->iface_data
.priority
[sec_wl_if_type
],
2537 wl_iftype_to_str(new_wl_iftype
),
2538 cfg
->iface_data
.priority
[new_wl_iftype
]));
2539 if (cfg
->iface_data
.priority
[new_wl_iftype
] >
2540 cfg
->iface_data
.priority
[sec_wl_if_type
]) {
2541 WL_INFORM_MEM(("Remove active sec data iface\n"));
2542 ret
= wl_cfg80211_delete_iface(cfg
,
2545 WL_ERR(("Can't support new iface = %s"
2546 " due to low priority\n",
2547 wl_iftype_to_str(new_wl_iftype
)));
2553 WL_ERR(("Unsupported policy\n"));
2559 * Handle incoming new secondary iface request,
2560 * irrespective of existing discovery ifaces
2562 if ((cfg
->iface_data
.policy
== WL_IF_POLICY_CUSTOM
) &&
2563 (new_wl_iftype
== WL_IF_TYPE_NAN
)) {
2564 WL_INFORM_MEM(("Allow NAN Data Path\n"));
2565 /* No further checks are required. */
2570 /* Check for any conflicting discovery iface */
2571 switch (new_wl_iftype
) {
2572 case WL_IF_TYPE_P2P_DISC
:
2573 case WL_IF_TYPE_P2P_GO
:
2574 case WL_IF_TYPE_P2P_GC
: {
2575 *disable_nan
= true;
2578 case WL_IF_TYPE_NAN_NMI
:
2579 case WL_IF_TYPE_NAN
: {
2580 *disable_p2p
= true;
2583 case WL_IF_TYPE_STA
:
2584 case WL_IF_TYPE_AP
: {
2585 *disable_nan
= true;
2586 *disable_p2p
= true;
2590 WL_ERR(("Unsupported\n"));
2598 wl_cfg80211_is_associated_discovery(struct bcm_cfg80211
*cfg
,
2599 wl_iftype_t new_wl_iftype
)
2601 struct net_device
*p2p_ndev
= NULL
;
2602 p2p_ndev
= wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_CONNECTION1
);
2604 if (new_wl_iftype
== WL_IF_TYPE_P2P_DISC
&& p2p_ndev
&&
2605 p2p_ndev
->ieee80211_ptr
&&
2606 is_p2p_group_iface(p2p_ndev
->ieee80211_ptr
)) {
2610 else if ((new_wl_iftype
== WL_IF_TYPE_NAN_NMI
) &&
2611 (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg
)))) {
2618 /* Handle incoming discovery iface request */
2620 wl_cfg80211_handle_discovery_config(struct bcm_cfg80211
*cfg
,
2621 wl_iftype_t new_wl_iftype
)
2624 bool disable_p2p
= false;
2625 bool disable_nan
= false;
2627 wl_iftype_t active_sec_iface
=
2628 wl_cfg80211_get_sec_iface(cfg
);
2630 if (is_discovery_iface(new_wl_iftype
) &&
2631 (active_sec_iface
!= WL_IFACE_NOT_PRESENT
)) {
2632 if (wl_cfg80211_is_associated_discovery(cfg
,
2633 new_wl_iftype
) == TRUE
) {
2634 WL_DBG(("Associate iface request is allowed= %s\n",
2635 wl_iftype_to_str(new_wl_iftype
)));
2640 ret
= wl_cfg80211_disc_if_mgmt(cfg
, new_wl_iftype
,
2641 &disable_nan
, &disable_p2p
);
2642 if (ret
!= BCME_OK
) {
2643 WL_ERR(("Failed at disc iface mgmt, ret = %d\n", ret
));
2649 /* Disable nan to avoid conflict with p2p */
2650 ret
= wl_cfgnan_check_nan_disable_pending(cfg
, true, true);
2651 if (ret
!= BCME_OK
) {
2652 WL_ERR(("failed to disable nan, error[%d]\n", ret
));
2659 /* Disable p2p discovery */
2660 ret
= wl_cfg80211_deinit_p2p_discovery(cfg
);
2661 if (ret
!= BCME_OK
) {
2662 /* Should we fail nan enab here */
2663 WL_ERR(("Failed to disable p2p_disc for allowing nan\n"));
2671 * Check for any conflicting iface before adding iface.
2672 * Based on policy, either conflicting iface is removed
2673 * or new iface add request is blocked.
2676 wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211
*cfg
,
2677 wl_iftype_t new_wl_iftype
)
2681 WL_INFORM_MEM(("Incoming iface = %s\n", wl_iftype_to_str(new_wl_iftype
)));
2683 if (!is_discovery_iface(new_wl_iftype
)) {
2684 /* Incoming data interface request */
2685 if (wl_cfg80211_get_sec_iface(cfg
) != WL_IFACE_NOT_PRESENT
) {
2686 /* active interface present - Apply interface data policy */
2687 ret
= wl_cfg80211_data_if_mgmt(cfg
, new_wl_iftype
);
2688 if (ret
!= BCME_OK
) {
2689 WL_ERR(("if_mgmt fail:%d\n", ret
));
2694 /* Apply discovery config */
2695 ret
= wl_cfg80211_handle_discovery_config(cfg
, new_wl_iftype
);
2698 #endif /* WL_IFACE_MGMT */
2700 static struct wireless_dev
*
2701 wl_cfg80211_add_monitor_if(struct wiphy
*wiphy
, const char *name
)
2703 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
2704 WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2705 return ERR_PTR(-EOPNOTSUPP
);
2707 struct wireless_dev
*wdev
;
2708 struct net_device
* ndev
= NULL
;
2710 dhd_add_monitor(name
, &ndev
);
2712 wdev
= kzalloc(sizeof(*wdev
), GFP_KERNEL
);
2714 WL_ERR(("wireless_dev alloc failed! \n"));
2718 wdev
->wiphy
= wiphy
;
2719 wdev
->iftype
= NL80211_IFTYPE_MONITOR
;
2720 ndev
->ieee80211_ptr
= wdev
;
2721 SET_NETDEV_DEV(ndev
, wiphy_dev(wiphy
));
2723 WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev
));
2724 return ndev
->ieee80211_ptr
;
2726 return ERR_PTR(-EOPNOTSUPP
);
2730 static struct wireless_dev
*
2731 wl_cfg80211_add_ibss(struct wiphy
*wiphy
, u16 wl_iftype
, char const *name
)
2733 #ifdef WLAIBSS_MCHAN
2735 return bcm_cfg80211_add_ibss_if(wiphy
, (char *)name
);
2738 WL_ERR(("IBSS not supported on Virtual iface\n"));
2744 wl_release_vif_macaddr(struct bcm_cfg80211
*cfg
, u8
*mac_addr
, u16 wl_iftype
)
2746 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
2747 u16 org_toggle_bytes
;
2748 u16 cur_toggle_bytes
;
2751 if (!ndev
|| !mac_addr
|| ETHER_ISNULLADDR(mac_addr
)) {
2754 WL_DBG(("%s:Mac addr" MACDBG
"\n",
2755 __FUNCTION__
, MAC2STRDBG(mac_addr
)));
2757 if ((wl_iftype
== WL_IF_TYPE_P2P_DISC
) || (wl_iftype
== WL_IF_TYPE_AP
) ||
2758 (wl_iftype
== WL_IF_TYPE_P2P_GO
) || (wl_iftype
== WL_IF_TYPE_P2P_GC
)) {
2759 /* Avoid invoking release mac addr code for interfaces using
2765 /* Fetch last two bytes of mac address */
2766 org_toggle_bytes
= ntoh16(*((u16
*)&ndev
->dev_addr
[4]));
2767 cur_toggle_bytes
= ntoh16(*((u16
*)&mac_addr
[4]));
2769 toggled_bit
= (org_toggle_bytes
^ cur_toggle_bytes
);
2770 WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n",
2771 org_toggle_bytes
, cur_toggle_bytes
));
2772 if (toggled_bit
& cfg
->vif_macaddr_mask
) {
2773 /* This toggled_bit is marked in the used mac addr
2776 cfg
->vif_macaddr_mask
&= ~toggled_bit
;
2777 WL_INFORM(("MAC address - " MACDBG
" released. toggled_bit:%04X vif_mask:%04X\n",
2778 MAC2STRDBG(mac_addr
), toggled_bit
, cfg
->vif_macaddr_mask
));
2780 WL_ERR(("MAC address - " MACDBG
" not found in the used list."
2781 " toggled_bit:%04x vif_mask:%04x\n", MAC2STRDBG(mac_addr
),
2782 toggled_bit
, cfg
->vif_macaddr_mask
));
2790 wl_get_vif_macaddr(struct bcm_cfg80211
*cfg
, u16 wl_iftype
, u8
*mac_addr
)
2792 struct ether_addr
*p2p_dev_addr
= wl_to_p2p_bss_macaddr(cfg
, P2PAPI_BSSCFG_DEVICE
);
2793 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
2799 /* Toggle mask starts from MSB of second last byte */
2804 if ((wl_iftype
== WL_IF_TYPE_P2P_DISC
) && p2p_dev_addr
&&
2805 ETHER_IS_LOCALADDR(p2p_dev_addr
)) {
2806 /* If mac address is already generated return the mac */
2807 (void)memcpy_s(mac_addr
, ETH_ALEN
, p2p_dev_addr
->octet
, ETH_ALEN
);
2810 (void)memcpy_s(mac_addr
, ETH_ALEN
, ndev
->perm_addr
, ETH_ALEN
);
2812 * VIF MAC address managment
2813 * P2P Device addres: Primary MAC with locally admin. bit set
2814 * P2P Group address/NAN NMI/Softap/NAN DPI: Primary MAC addr
2815 * with local admin bit set and one additional bit toggled.
2816 * cfg->vif_macaddr_mask will hold the info regarding the mac address
2817 * released. Ensure to call wl_release_vif_macaddress to free up
2820 #if defined(SPECIFIC_MAC_GEN_SCHEME)
2821 if (wl_iftype
== WL_IF_TYPE_P2P_DISC
|| wl_iftype
== WL_IF_TYPE_AP
) {
2822 mac_addr
[0] |= 0x02;
2823 } else if ((wl_iftype
== WL_IF_TYPE_P2P_GO
) || (wl_iftype
== WL_IF_TYPE_P2P_GC
)) {
2824 mac_addr
[0] |= 0x02;
2825 mac_addr
[4] ^= 0x80;
2828 if (wl_iftype
== WL_IF_TYPE_P2P_DISC
) {
2829 mac_addr
[0] |= 0x02;
2831 #endif /* SEPCIFIC_MAC_GEN_SCHEME */
2833 /* For locally administered mac addresses, we keep the
2834 * OUI part constant and just work on the last two bytes.
2836 mac_addr
[0] |= 0x02;
2837 toggle_mask
= cfg
->vif_macaddr_mask
;
2838 toggle_bytes
= ntoh16(*((u16
*)&mac_addr
[4]));
2840 used
= toggle_mask
& mask
;
2842 /* Use this bit position */
2843 toggle_bit
= mask
>> offset
;
2844 toggle_bytes
^= toggle_bit
;
2845 cfg
->vif_macaddr_mask
|= toggle_bit
;
2846 WL_DBG(("toggle_bit:%04X toggle_bytes:%04X toggle_mask:%04X\n",
2847 toggle_bit
, toggle_bytes
, cfg
->vif_macaddr_mask
));
2848 /* Macaddress are stored in network order */
2849 mac_addr
[5] = *((u8
*)&toggle_bytes
);
2850 mac_addr
[4] = *(((u8
*)&toggle_bytes
+ 1));
2855 toggle_mask
= toggle_mask
<< 0x1;
2857 if (offset
> MAX_VIF_OFFSET
) {
2858 /* We have used up all macaddresses. Something wrong! */
2859 WL_ERR(("Entire range of macaddress used up.\n"));
2865 WL_INFORM_MEM(("Get virtual I/F mac addr: "MACDBG
"\n", MAC2STRDBG(mac_addr
)));
2868 #ifdef DNGL_AXI_ERROR_LOGGING
2870 _wl_cfg80211_check_axi_error(struct bcm_cfg80211
*cfg
)
2873 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
2874 hnd_ext_trap_hdr_t
*hdr
;
2875 int axi_host_error_size
;
2877 uint32
*ext_data
= dhd
->extended_trap_data
;
2878 struct file
*fp
= NULL
;
2879 char *filename
= DHD_COMMON_DUMP_PATH
2880 DHD_DUMP_AXI_ERROR_FILENAME
2881 DHD_DUMP_HAL_FILENAME_SUFFIX
;
2883 WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__
, filename
));
2885 fp
= filp_open(filename
, O_RDONLY
, 0);
2887 if (IS_ERR(fp
) || (fp
== NULL
)) {
2888 WL_ERR(("%s: Couldn't read the file, err %ld,File [%s] No previous axi error \n",
2889 __FUNCTION__
, PTR_ERR(fp
), filename
));
2893 kernel_read_compat(fp
, fp
->f_pos
, (char *)dhd
->axi_err_dump
, sizeof(dhd_axi_error_dump_t
));
2894 filp_close(fp
, NULL
);
2896 /* Delete axi error info file */
2897 if (dhd_file_delete(filename
) < 0) {
2898 WL_ERR(("%s(): Failed to delete file: %s\n", __FUNCTION__
, filename
));
2901 WL_ERR(("%s(): Success to delete file: %s\n", __FUNCTION__
, filename
));
2903 if (dhd
->axi_err_dump
->etd_axi_error_v1
.signature
!= HND_EXT_TRAP_AXIERROR_SIGNATURE
) {
2904 WL_ERR(("%s: Invalid AXI signature: 0x%x\n",
2905 __FUNCTION__
, dhd
->axi_err_dump
->etd_axi_error_v1
.signature
));
2908 /* First word is original trap_data */
2911 /* Followed by the extended trap data header */
2912 hdr
= (hnd_ext_trap_hdr_t
*)ext_data
;
2913 new_dst
= hdr
->data
;
2915 axi_host_error_size
= sizeof(dhd
->axi_err_dump
->axid
)
2916 + sizeof(dhd
->axi_err_dump
->fault_address
);
2918 /* TAG_TRAP_AXI_HOST_INFO tlv : host's axid, fault address */
2919 new_dst
= bcm_write_tlv(TAG_TRAP_AXI_HOST_INFO
,
2920 (const void *)dhd
->axi_err_dump
,
2921 axi_host_error_size
, new_dst
);
2923 /* TAG_TRAP_AXI_ERROR tlv */
2924 new_dst
= bcm_write_tlv(TAG_TRAP_AXI_ERROR
,
2925 (const void *)&dhd
->axi_err_dump
->etd_axi_error_v1
,
2926 sizeof(dhd
->axi_err_dump
->etd_axi_error_v1
), new_dst
);
2927 hdr
->len
= new_dst
- hdr
->data
;
2929 dhd
->dongle_trap_occured
= TRUE
;
2930 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2931 copy_hang_info_trap(dhd
);
2932 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2933 memset(dhd
->axi_err_dump
, 0, sizeof(dhd_axi_error_dump_t
));
2935 dhd
->hang_reason
= HANG_REASON_DONGLE_TRAP
;
2936 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg
));
2940 #endif /* DNGL_AXI_ERROR_LOGGING */
2942 /* All Android/Linux private/Vendor Interface calls should make
2943 * use of below API for interface creation.
2945 struct wireless_dev
*
2946 wl_cfg80211_add_if(struct bcm_cfg80211
*cfg
,
2947 struct net_device
*primary_ndev
,
2948 wl_iftype_t wl_iftype
, const char *name
, u8
*mac
)
2950 u8 mac_addr
[ETH_ALEN
];
2952 struct wireless_dev
*wdev
= NULL
;
2953 struct wiphy
*wiphy
;
2956 wl_iftype_t macaddr_iftype
= wl_iftype
;
2958 WL_INFORM_MEM(("if name: %s, wl_iftype:%d \n",
2959 name
? name
: "NULL", wl_iftype
));
2960 if (!cfg
|| !primary_ndev
|| !name
) {
2961 WL_ERR(("cfg/ndev/name ptr null\n"));
2964 if (wl_cfg80211_get_wdev_from_ifname(cfg
, name
)) {
2965 WL_ERR(("Interface name %s exists!\n", name
));
2969 wiphy
= bcmcfg_to_wiphy(cfg
);
2970 dhd
= (dhd_pub_t
*)(cfg
->pub
);
2975 if ((wl_mode
= wl_iftype_to_mode(wl_iftype
)) < 0) {
2978 mutex_lock(&cfg
->if_sync
);
2980 if (wl_iftype
== WL_IF_TYPE_NAN
) {
2982 * Bypass the role conflict check for NDI and handle it
2983 * from dp req and dp resp context
2984 * because in aware comms, ndi gets created soon after nan enable.
2988 #ifdef WL_IFACE_MGMT
2989 if ((err
= wl_cfg80211_handle_if_role_conflict(cfg
, wl_iftype
)) < 0) {
2990 mutex_unlock(&cfg
->if_sync
);
2993 #endif /* WL_IFACE_MGMT */
2994 #ifdef DNGL_AXI_ERROR_LOGGING
2995 /* Check the previous smmu fault error */
2996 if ((err
= _wl_cfg80211_check_axi_error(cfg
)) < 0) {
2997 mutex_unlock(&cfg
->if_sync
);
3000 #endif /* DNGL_AXI_ERROR_LOGGING */
3001 /* Protect the interace op context */
3002 /* Do pre-create ops */
3003 wl_cfg80211_iface_state_ops(primary_ndev
->ieee80211_ptr
, WL_IF_CREATE_REQ
,
3004 wl_iftype
, wl_mode
);
3006 if (strnicmp(name
, SOFT_AP_IF_NAME
, strlen(SOFT_AP_IF_NAME
)) == 0) {
3007 macaddr_iftype
= WL_IF_TYPE_AP
;
3011 /* If mac address is provided, use that */
3012 memcpy(mac_addr
, mac
, ETH_ALEN
);
3013 } else if ((wl_get_vif_macaddr(cfg
, macaddr_iftype
, mac_addr
) != BCME_OK
)) {
3014 /* Fetch the mac address to be used for virtual interface */
3019 switch (wl_iftype
) {
3020 case WL_IF_TYPE_IBSS
:
3021 wdev
= wl_cfg80211_add_ibss(wiphy
, wl_iftype
, name
);
3023 case WL_IF_TYPE_MONITOR
:
3024 wdev
= wl_cfg80211_add_monitor_if(wiphy
, name
);
3026 case WL_IF_TYPE_STA
:
3028 case WL_IF_TYPE_NAN
:
3029 if (cfg
->iface_cnt
>= (IFACE_MAX_CNT
- 1)) {
3030 WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
3035 wdev
= wl_cfg80211_create_iface(cfg
->wdev
->wiphy
,
3036 wl_iftype
, mac_addr
, name
);
3038 case WL_IF_TYPE_P2P_DISC
:
3039 case WL_IF_TYPE_P2P_GO
:
3040 /* Intentional fall through */
3041 case WL_IF_TYPE_P2P_GC
:
3042 if (cfg
->p2p_supported
) {
3043 wdev
= wl_cfg80211_p2p_if_add(cfg
, wl_iftype
,
3044 name
, mac_addr
, &err
);
3047 /* Intentionally fall through for unsupported interface
3048 * handling when firmware doesn't support p2p
3051 WL_ERR(("Unsupported interface type\n"));
3057 WL_ERR(("vif create failed. err:%d\n", err
));
3058 if (err
!= -ENOTSUPP
) {
3064 /* Ensure decrementing in case of failure */
3067 wl_cfg80211_iface_state_ops(wdev
,
3068 WL_IF_CREATE_DONE
, wl_iftype
, wl_mode
);
3070 WL_INFORM_MEM(("Vif created. dev->ifindex:%d"
3071 " cfg_iftype:%d, vif_count:%d\n",
3072 (wdev
->netdev
? wdev
->netdev
->ifindex
: 0xff),
3073 wdev
->iftype
, cfg
->vif_count
));
3074 mutex_unlock(&cfg
->if_sync
);
3078 wl_cfg80211_iface_state_ops(primary_ndev
->ieee80211_ptr
,
3079 WL_IF_DELETE_REQ
, wl_iftype
, wl_mode
);
3081 if (err
!= -ENOTSUPP
) {
3082 /* For non-supported interfaces, just return error and
3083 * skip below recovery steps.
3085 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
3086 wl_copy_hang_info_if_falure(primary_ndev
, HANG_REASON_IFACE_DEL_FAILURE
, err
);
3087 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
3088 SUPP_LOG(("IF_ADD fail. err:%d\n", err
));
3089 wl_flush_fw_log_buffer(primary_ndev
, FW_LOGSET_MASK_ALL
);
3090 if (dhd_query_bus_erros(dhd
)) {
3093 dhd
->iface_op_failed
= TRUE
;
3094 #if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
3095 if (dhd
->memdump_enabled
) {
3096 dhd
->memdump_type
= DUMP_TYPE_IFACE_OP_FAILURE
;
3097 dhd_bus_mem_dump(dhd
);
3099 #endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
3101 /* If reached here, something wrong with DHD or firmware.
3102 * There could be a chance that firmware is in bad state.
3103 * Request the upper layer to do a Wi-Fi reset.
3105 dhd
->hang_reason
= HANG_REASON_IFACE_ADD_FAILURE
;
3106 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg
));
3110 mutex_unlock(&cfg
->if_sync
);
3114 static bcm_struct_cfgdev
*
3115 wl_cfg80211_add_virtual_iface(struct wiphy
*wiphy
,
3116 #if defined(WL_CFG80211_P2P_DEV_IF)
3120 #endif /* WL_CFG80211_P2P_DEV_IF */
3121 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
3122 unsigned char name_assign_type
,
3123 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
3124 enum nl80211_iftype type
,
3125 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3127 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3128 struct vif_params
*params
)
3132 struct net_device
*primary_ndev
;
3133 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3134 struct wireless_dev
*wdev
;
3136 WL_DBG(("Enter iftype: %d\n", type
));
3138 return ERR_PTR(-EINVAL
);
3141 /* Use primary I/F for sending cmds down to firmware */
3142 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
3143 if (unlikely(!wl_get_drv_status(cfg
, READY
, primary_ndev
))) {
3144 WL_ERR(("device is not ready\n"));
3145 return ERR_PTR(-ENODEV
);
3149 WL_ERR(("Interface name not provided \n"));
3150 return ERR_PTR(-EINVAL
);
3153 if (cfg80211_to_wl_iftype(type
, &wl_iftype
, &wl_mode
) < 0) {
3154 return ERR_PTR(-EINVAL
);
3157 wdev
= wl_cfg80211_add_if(cfg
, primary_ndev
, wl_iftype
, name
, NULL
);
3158 if (unlikely(!wdev
)) {
3159 return ERR_PTR(-ENODEV
);
3161 return wdev_to_cfgdev(wdev
);
3165 wl_cfg80211_del_ibss(struct wiphy
*wiphy
, struct wireless_dev
*wdev
)
3167 WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev
));
3168 #ifdef WLAIBSS_MCHAN
3170 return bcm_cfg80211_del_ibss_if(wiphy
, wdev
);
3173 return wl_cfg80211_del_iface(wiphy
, wdev
);
3178 wl_cfg80211_del_if(struct bcm_cfg80211
*cfg
, struct net_device
*primary_ndev
,
3179 struct wireless_dev
*wdev
, char *ifname
)
3182 mutex_lock(&cfg
->if_sync
);
3183 ret
= _wl_cfg80211_del_if(cfg
, primary_ndev
, wdev
, ifname
);
3184 mutex_unlock(&cfg
->if_sync
);
3189 _wl_cfg80211_del_if(struct bcm_cfg80211
*cfg
, struct net_device
*primary_ndev
,
3190 struct wireless_dev
*wdev
, char *ifname
)
3194 struct wiphy
*wiphy
;
3197 struct net_info
*netinfo
;
3205 dhd
= (dhd_pub_t
*)(cfg
->pub
);
3207 if (!wdev
&& ifname
) {
3208 /* If only ifname is provided, fetch corresponding wdev ptr from our
3209 * internal data structure
3211 wdev
= wl_cfg80211_get_wdev_from_ifname(cfg
, ifname
);
3214 /* Check whether we have a valid wdev ptr */
3215 if (unlikely(!wdev
)) {
3216 WL_ERR(("wdev not found. '%s' does not exists\n", ifname
));
3220 WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev
->iftype
));
3222 wiphy
= wdev
->wiphy
;
3223 #ifdef WL_CFG80211_P2P_DEV_IF
3224 if (wdev
->iftype
== NL80211_IFTYPE_P2P_DEVICE
) {
3225 /* p2p discovery would be de-initialized in stop p2p
3226 * device context/from other virtual i/f creation context
3227 * so netinfo list may not have any node corresponding to
3228 * discovery I/F. Handle it before bssidx check.
3230 ret
= wl_cfg80211_p2p_if_del(wiphy
, wdev
);
3231 if (unlikely(ret
)) {
3234 /* success case. return from here */
3235 if (cfg
->vif_count
) {
3241 #endif /* WL_CFG80211_P2P_DEV_IF */
3243 if ((netinfo
= wl_get_netinfo_by_wdev(cfg
, wdev
)) == NULL
) {
3244 WL_ERR(("Find netinfo from wdev %p failed\n", wdev
));
3249 if (!wdev
->netdev
) {
3250 WL_ERR(("ndev null! \n"));
3252 /* Disable tx before del */
3253 netif_tx_disable(wdev
->netdev
);
3256 wl_iftype
= netinfo
->iftype
;
3257 wl_mode
= wl_iftype_to_mode(wl_iftype
);
3258 bssidx
= netinfo
->bssidx
;
3259 WL_DBG_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
3260 wdev
->iftype
, wl_iftype
, wl_mode
, bssidx
));
3262 /* Do pre-interface del ops */
3263 wl_cfg80211_iface_state_ops(wdev
, WL_IF_DELETE_REQ
, wl_iftype
, wl_mode
);
3265 #ifdef PCIE_FULL_DONGLE
3266 /* clean up sta info & clean up flowrings correspondign to the iface */
3267 dhd_net_del_flowrings_sta(dhd
, wdev
->netdev
);
3268 #endif /* PCIE_FULL_DONGLE */
3270 switch (wl_iftype
) {
3271 case WL_IF_TYPE_P2P_GO
:
3272 case WL_IF_TYPE_P2P_GC
:
3274 case WL_IF_TYPE_STA
:
3275 case WL_IF_TYPE_NAN
:
3276 ret
= wl_cfg80211_del_iface(wiphy
, wdev
);
3278 case WL_IF_TYPE_IBSS
:
3279 ret
= wl_cfg80211_del_ibss(wiphy
, wdev
);
3283 WL_ERR(("Unsupported interface type\n"));
3288 if (ret
== BCME_OK
) {
3289 /* Successful case */
3290 if (cfg
->vif_count
) {
3293 wl_cfg80211_iface_state_ops(primary_ndev
->ieee80211_ptr
,
3294 WL_IF_DELETE_DONE
, wl_iftype
, wl_mode
);
3296 if (!((cfg
->nancfg
->mac_rand
) && (wl_iftype
== WL_IF_TYPE_NAN
)))
3299 wl_release_vif_macaddr(cfg
, wdev
->netdev
->dev_addr
, wl_iftype
);
3301 WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg
->vif_count
));
3303 if (!wdev
->netdev
) {
3304 WL_ERR(("ndev null! \n"));
3306 /* IF del failed. revert back tx queue status */
3307 netif_tx_start_all_queues(wdev
->netdev
);
3310 /* Skip generating log files and sending HANG event
3311 * if driver state is not READY
3313 if (wl_get_drv_status(cfg
, READY
, bcmcfg_to_prmry_ndev(cfg
))) {
3314 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
3315 wl_copy_hang_info_if_falure(primary_ndev
,
3316 HANG_REASON_IFACE_DEL_FAILURE
, ret
);
3317 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
3318 SUPP_LOG(("IF_DEL fail. err:%d\n", ret
));
3319 wl_flush_fw_log_buffer(primary_ndev
, FW_LOGSET_MASK_ALL
);
3320 /* IF dongle is down due to previous hang or other conditions, sending
3321 * one more hang notification is not needed.
3323 if (dhd_query_bus_erros(dhd
) || (ret
== BCME_DONGLE_DOWN
)) {
3326 dhd
->iface_op_failed
= TRUE
;
3327 #if defined(DHD_FW_COREDUMP)
3328 if (dhd
->memdump_enabled
&& (ret
!= -EBADTYPE
)) {
3329 dhd
->memdump_type
= DUMP_TYPE_IFACE_OP_FAILURE
;
3330 dhd_bus_mem_dump(dhd
);
3332 #endif /* DHD_FW_COREDUMP */
3334 WL_ERR(("Notify hang event to upper layer \n"));
3335 dhd
->hang_reason
= HANG_REASON_IFACE_DEL_FAILURE
;
3336 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg
));
3345 wl_cfg80211_del_virtual_iface(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
)
3347 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3348 struct wireless_dev
*wdev
= cfgdev_to_wdev(cfgdev
);
3352 struct net_device
*primary_ndev
;
3358 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
3359 wdev
= cfgdev_to_wdev(cfgdev
);
3361 WL_ERR(("wdev null"));
3365 WL_DBG(("Enter wdev:%p iftype: %d\n", wdev
, wdev
->iftype
));
3366 if (cfg80211_to_wl_iftype(wdev
->iftype
, &wl_iftype
, &wl_mode
) < 0) {
3367 WL_ERR(("Wrong iftype: %d\n", wdev
->iftype
));
3371 if ((ret
= wl_cfg80211_del_if(cfg
, primary_ndev
,
3373 WL_ERR(("IF del failed\n"));
3380 wl_cfg80211_change_p2prole(struct wiphy
*wiphy
, struct net_device
*ndev
, enum nl80211_iftype type
)
3388 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3389 struct ether_addr p2p_dev_addr
= {{0, 0, 0, 0, 0, 0}};
3390 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
3392 WL_INFORM_MEM(("Enter. current_role:%d new_role:%d \n", ndev
->ieee80211_ptr
->iftype
, type
));
3394 (void)memcpy_s(p2p_dev_addr
.octet
, ETHER_ADDR_LEN
,
3395 ndev
->dev_addr
, ETHER_ADDR_LEN
);
3397 if (!cfg
->p2p
|| !wl_cfgp2p_vif_created(cfg
)) {
3398 WL_ERR(("P2P not initialized \n"));
3402 if (!is_p2p_group_iface(ndev
->ieee80211_ptr
)) {
3403 WL_ERR(("Wrong if type \n"));
3407 /* Abort any on-going scans to avoid race condition issues */
3408 wl_cfg80211_cancel_scan(cfg
);
3410 index
= wl_get_bssidx_by_wdev(cfg
, ndev
->ieee80211_ptr
);
3412 WL_ERR(("Find bsscfg index from ndev(%p) failed\n", ndev
));
3415 if (wl_cfgp2p_find_type(cfg
, index
, &conn_idx
) != BCME_OK
) {
3419 /* In concurrency case, STA may be already associated in a particular
3420 * channel. so retrieve the current channel of primary interface and
3421 * then start the virtual interface on that.
3423 chspec
= wl_cfg80211_get_shared_freq(wiphy
);
3424 if (type
== NL80211_IFTYPE_P2P_GO
) {
3425 /* Dual p2p doesn't support multiple P2PGO interfaces,
3426 * p2p_go_count is the counter for GO creation
3429 if ((cfg
->p2p
->p2p_go_count
> 0) && (type
== NL80211_IFTYPE_P2P_GO
)) {
3430 WL_ERR(("FW does not support multiple GO\n"));
3434 wlif_type
= WL_P2P_IF_GO
;
3435 dhd
->op_mode
&= ~DHD_FLAG_P2P_GC_MODE
;
3436 dhd
->op_mode
|= DHD_FLAG_P2P_GO_MODE
;
3438 wlif_type
= WL_P2P_IF_CLIENT
;
3440 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
) {
3441 WL_INFORM_MEM(("Downgrading P2P GO to cfg_iftype:%d \n", type
));
3442 wl_add_remove_eventmsg(ndev
, WLC_E_PROBREQ_MSG
, false);
3443 cfg
->p2p
->p2p_go_count
--;
3444 /* disable interface before bsscfg free */
3445 err
= wl_cfgp2p_ifdisable(cfg
, &p2p_dev_addr
);
3446 /* if fw doesn't support "ifdis",
3447 * do not wait for link down of ap mode
3450 WL_DBG(("Wait for Link Down event for GO !!!\n"));
3451 wait_for_completion_timeout(&cfg
->iface_disable
,
3452 msecs_to_jiffies(500));
3453 } else if (err
!= BCME_UNSUPPORTED
) {
3459 wl_set_p2p_status(cfg
, IF_CHANGING
);
3460 wl_clr_p2p_status(cfg
, IF_CHANGED
);
3461 wl_cfgp2p_ifchange(cfg
, &p2p_dev_addr
,
3462 htod32(wlif_type
), chspec
, conn_idx
);
3463 wait_event_interruptible_timeout(cfg
->netif_change_event
,
3464 (wl_get_p2p_status(cfg
, IF_CHANGED
) == true),
3465 msecs_to_jiffies(MAX_WAIT_TIME
));
3467 wl_clr_p2p_status(cfg
, IF_CHANGING
);
3468 wl_clr_p2p_status(cfg
, IF_CHANGED
);
3470 if (mode
== WL_MODE_AP
) {
3471 wl_set_drv_status(cfg
, CONNECTED
, ndev
);
3478 wl_cfg80211_change_virtual_iface(struct wiphy
*wiphy
, struct net_device
*ndev
,
3479 enum nl80211_iftype type
,
3480 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3482 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3483 struct vif_params
*params
)
3489 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3490 struct net_info
*netinfo
= NULL
;
3491 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
3492 struct net_device
*primary_ndev
;
3497 WL_INFORM_MEM(("[%s] Enter. current cfg_iftype:%d new cfg_iftype:%d \n",
3498 ndev
->name
, ndev
->ieee80211_ptr
->iftype
, type
));
3499 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
3501 if (cfg80211_to_wl_iftype(type
, &wl_iftype
, &wl_mode
) < 0) {
3502 WL_ERR(("Unknown role \n"));
3506 mutex_lock(&cfg
->if_sync
);
3507 netinfo
= wl_get_netinfo_by_wdev(cfg
, ndev
->ieee80211_ptr
);
3508 if (unlikely(!netinfo
)) {
3510 if (IS_CFG80211_STATIC_IF(cfg
, ndev
)) {
3511 /* Incase of static interfaces, the netinfo will be
3512 * allocated only when FW interface is initialized. So
3513 * store the value and use it during initialization.
3515 WL_INFORM_MEM(("skip change vif for static if\n"));
3516 ndev
->ieee80211_ptr
->iftype
= type
;
3519 #endif /* WL_STATIC_IF */
3521 WL_ERR(("netinfo not found \n"));
3527 if ((primary_ndev
== ndev
) && !(ndev
->flags
& IFF_UP
)) {
3529 * If interface is not initialized, store the role and
3530 * return. The role will be initilized after interface
3533 WL_INFORM_MEM(("skip change role before dev up\n"));
3534 ndev
->ieee80211_ptr
->iftype
= type
;
3539 /* perform pre-if-change tasks */
3540 wl_cfg80211_iface_state_ops(ndev
->ieee80211_ptr
,
3541 WL_IF_CHANGE_REQ
, wl_iftype
, wl_mode
);
3544 case NL80211_IFTYPE_ADHOC
:
3547 case NL80211_IFTYPE_STATION
:
3548 /* Supplicant sets iftype to STATION while removing p2p GO */
3549 if (ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
3550 /* Downgrading P2P GO */
3551 err
= wl_cfg80211_change_p2prole(wiphy
, ndev
, type
);
3552 if (unlikely(err
)) {
3553 WL_ERR(("P2P downgrade failed \n"));
3555 } else if (ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
3556 /* Downgrade role from AP to STA */
3557 if ((err
= wl_cfg80211_add_del_bss(cfg
, ndev
,
3558 netinfo
->bssidx
, wl_iftype
, 0, NULL
)) < 0) {
3559 WL_ERR(("AP-STA Downgrade failed \n"));
3564 case NL80211_IFTYPE_AP
:
3565 /* intentional fall through */
3566 case NL80211_IFTYPE_AP_VLAN
:
3568 if (!wl_get_drv_status(cfg
, AP_CREATED
, ndev
) &&
3569 wl_get_drv_status(cfg
, READY
, ndev
)) {
3570 err
= wl_cfg80211_set_ap_role(cfg
, ndev
);
3571 if (unlikely(err
)) {
3572 WL_ERR(("set ap role failed!\n"));
3576 WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
3580 case NL80211_IFTYPE_P2P_GO
:
3581 /* Intentional fall through */
3582 case NL80211_IFTYPE_P2P_CLIENT
:
3584 err
= wl_cfg80211_change_p2prole(wiphy
, ndev
, type
);
3586 case NL80211_IFTYPE_MONITOR
:
3587 case NL80211_IFTYPE_WDS
:
3588 case NL80211_IFTYPE_MESH_POINT
:
3589 /* Intentional fall through */
3591 WL_ERR(("Unsupported type:%d \n", type
));
3596 if (wl_get_drv_status(cfg
, READY
, ndev
)) {
3597 err
= wldev_ioctl_set(ndev
, WLC_SET_INFRA
, &infra
, sizeof(s32
));
3599 WL_ERR(("SET INFRA/IBSS error %d\n", err
));
3604 wl_cfg80211_iface_state_ops(primary_ndev
->ieee80211_ptr
,
3605 WL_IF_CHANGE_DONE
, wl_iftype
, wl_mode
);
3607 /* Update new iftype in relevant structures */
3608 if (is_p2p_group_iface(ndev
->ieee80211_ptr
) && (type
== NL80211_IFTYPE_STATION
)) {
3609 /* For role downgrade cases, we keep interface role as GC */
3610 netinfo
->iftype
= WL_IF_TYPE_P2P_GC
;
3611 WL_DBG_MEM(("[%s] Set base role to GC, current role"
3612 "ndev->ieee80211_ptr->iftype = %d\n",
3613 __FUNCTION__
, ndev
->ieee80211_ptr
->iftype
));
3615 netinfo
->iftype
= wl_iftype
;
3618 ndev
->ieee80211_ptr
->iftype
= type
;
3620 WL_INFORM_MEM(("[%s] cfg_iftype changed to %d\n", ndev
->name
, type
));
3621 #ifdef WL_EXT_IAPSTA
3622 wl_ext_iapsta_update_iftype(ndev
, netinfo
->ifidx
, wl_iftype
);
3627 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
3629 mutex_unlock(&cfg
->if_sync
);
3634 wl_cfg80211_notify_ifadd(struct net_device
*dev
,
3635 int ifidx
, char *name
, uint8
*mac
, uint8 bssidx
, uint8 role
)
3637 bool ifadd_expected
= FALSE
;
3638 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
3639 bool bss_pending_op
= TRUE
;
3641 /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
3642 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
3644 if (wl_get_p2p_status(cfg
, IF_CHANGING
))
3645 return wl_cfg80211_notify_ifchange(dev
, ifidx
, name
, mac
, bssidx
);
3647 /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
3648 if (wl_get_p2p_status(cfg
, IF_ADDING
)) {
3649 ifadd_expected
= TRUE
;
3650 wl_clr_p2p_status(cfg
, IF_ADDING
);
3651 } else if (cfg
->bss_pending_op
) {
3652 ifadd_expected
= TRUE
;
3653 bss_pending_op
= FALSE
;
3656 if (ifadd_expected
) {
3657 wl_if_event_info
*if_event_info
= &cfg
->if_event_info
;
3659 if_event_info
->valid
= TRUE
;
3660 if_event_info
->ifidx
= ifidx
;
3661 if_event_info
->bssidx
= bssidx
;
3662 if_event_info
->role
= role
;
3663 strlcpy(if_event_info
->name
, name
, sizeof(if_event_info
->name
));
3664 if_event_info
->name
[IFNAMSIZ
- 1] = '\0';
3666 memcpy(if_event_info
->mac
, mac
, ETHER_ADDR_LEN
);
3668 /* Update bss pendig operation status */
3669 if (!bss_pending_op
) {
3670 cfg
->bss_pending_op
= FALSE
;
3672 WL_INFORM_MEM(("IF_ADD ifidx:%d bssidx:%d role:%d\n",
3673 ifidx
, bssidx
, role
));
3675 wake_up_interruptible(&cfg
->netif_change_event
);
3683 wl_cfg80211_notify_ifdel(struct net_device
*dev
, int ifidx
, char *name
, uint8
*mac
, uint8 bssidx
)
3685 bool ifdel_expected
= FALSE
;
3686 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
3687 wl_if_event_info
*if_event_info
= &cfg
->if_event_info
;
3688 bool bss_pending_op
= TRUE
;
3690 if (wl_get_p2p_status(cfg
, IF_DELETING
)) {
3691 ifdel_expected
= TRUE
;
3692 wl_clr_p2p_status(cfg
, IF_DELETING
);
3693 } else if (cfg
->bss_pending_op
) {
3694 ifdel_expected
= TRUE
;
3695 bss_pending_op
= FALSE
;
3698 if (ifdel_expected
) {
3699 if_event_info
->valid
= TRUE
;
3700 if_event_info
->ifidx
= ifidx
;
3701 if_event_info
->bssidx
= bssidx
;
3702 /* Update bss pendig operation status */
3703 if (!bss_pending_op
) {
3704 cfg
->bss_pending_op
= FALSE
;
3706 WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx
, bssidx
));
3708 wake_up_interruptible(&cfg
->netif_change_event
);
3716 wl_cfg80211_notify_ifchange(struct net_device
* dev
, int ifidx
, char *name
, uint8
*mac
,
3719 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
3721 if (wl_get_p2p_status(cfg
, IF_CHANGING
)) {
3722 wl_set_p2p_status(cfg
, IF_CHANGED
);
3724 wake_up_interruptible(&cfg
->netif_change_event
);
3731 static s32
wl_set_rts(struct net_device
*dev
, u32 rts_threshold
)
3735 err
= wldev_iovar_setint(dev
, "rtsthresh", rts_threshold
);
3736 if (unlikely(err
)) {
3737 WL_ERR(("Error (%d)\n", err
));
3743 static s32
wl_set_frag(struct net_device
*dev
, u32 frag_threshold
)
3747 err
= wldev_iovar_setint_bsscfg(dev
, "fragthresh", frag_threshold
, 0);
3748 if (unlikely(err
)) {
3749 WL_ERR(("Error (%d)\n", err
));
3755 static s32
wl_set_retry(struct net_device
*dev
, u32 retry
, bool l
)
3758 u32 cmd
= (l
? WLC_SET_LRL
: WLC_SET_SRL
);
3760 #ifdef CUSTOM_LONG_RETRY_LIMIT
3761 if ((cmd
== WLC_SET_LRL
) &&
3762 (retry
!= CUSTOM_LONG_RETRY_LIMIT
)) {
3763 WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
3766 #endif /* CUSTOM_LONG_RETRY_LIMIT */
3768 retry
= htod32(retry
);
3769 err
= wldev_ioctl_set(dev
, cmd
, &retry
, sizeof(retry
));
3770 if (unlikely(err
)) {
3771 WL_ERR(("cmd (%d) , error (%d)\n", cmd
, err
));
3777 static s32
wl_cfg80211_set_wiphy_params(struct wiphy
*wiphy
, u32 changed
)
3779 struct bcm_cfg80211
*cfg
= (struct bcm_cfg80211
*)wiphy_priv(wiphy
);
3780 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
3783 RETURN_EIO_IF_NOT_UP(cfg
);
3784 WL_DBG(("Enter\n"));
3785 if (changed
& WIPHY_PARAM_RTS_THRESHOLD
&&
3786 (cfg
->conf
->rts_threshold
!= wiphy
->rts_threshold
)) {
3787 cfg
->conf
->rts_threshold
= wiphy
->rts_threshold
;
3788 err
= wl_set_rts(ndev
, cfg
->conf
->rts_threshold
);
3792 if (changed
& WIPHY_PARAM_FRAG_THRESHOLD
&&
3793 (cfg
->conf
->frag_threshold
!= wiphy
->frag_threshold
)) {
3794 cfg
->conf
->frag_threshold
= wiphy
->frag_threshold
;
3795 err
= wl_set_frag(ndev
, cfg
->conf
->frag_threshold
);
3799 if (changed
& WIPHY_PARAM_RETRY_LONG
&&
3800 (cfg
->conf
->retry_long
!= wiphy
->retry_long
)) {
3801 cfg
->conf
->retry_long
= wiphy
->retry_long
;
3802 err
= wl_set_retry(ndev
, cfg
->conf
->retry_long
, true);
3806 if (changed
& WIPHY_PARAM_RETRY_SHORT
&&
3807 (cfg
->conf
->retry_short
!= wiphy
->retry_short
)) {
3808 cfg
->conf
->retry_short
= wiphy
->retry_short
;
3809 err
= wl_set_retry(ndev
, cfg
->conf
->retry_short
, false);
3810 if (err
!= BCME_OK
) {
3819 wl_channel_to_chanspec(struct wiphy
*wiphy
, struct net_device
*dev
, u32 channel
, u32 bw_cap
)
3821 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3823 wl_uint32_list_t
*list
;
3825 chanspec_t c
= 0, ret_c
= 0;
3826 int bw
= 0, tmp_bw
= 0;
3830 #define LOCAL_BUF_SIZE 1024
3831 buf
= (u8
*)MALLOC(cfg
->osh
, LOCAL_BUF_SIZE
);
3833 WL_ERR(("buf memory alloc failed\n"));
3837 err
= wldev_iovar_getbuf_bsscfg(dev
, "chanspecs", NULL
,
3838 0, buf
, LOCAL_BUF_SIZE
, 0, &cfg
->ioctl_buf_sync
);
3839 if (err
!= BCME_OK
) {
3840 WL_ERR(("get chanspecs failed with %d\n", err
));
3844 list
= (wl_uint32_list_t
*)(void *)buf
;
3845 for (i
= 0; i
< dtoh32(list
->count
); i
++) {
3846 c
= dtoh32(list
->element
[i
]);
3847 if (channel
<= CH_MAX_2G_CHANNEL
) {
3848 if (!CHSPEC_IS20(c
))
3850 if (channel
== CHSPEC_CHANNEL(c
)) {
3856 tmp_c
= wf_chspec_ctlchan(c
);
3857 tmp_bw
= bw2cap
[CHSPEC_BW(c
) >> WL_CHANSPEC_BW_SHIFT
];
3858 if (tmp_c
!= channel
)
3861 if ((tmp_bw
> bw
) && (tmp_bw
<= bw_cap
)) {
3870 MFREE(cfg
->osh
, buf
, LOCAL_BUF_SIZE
);
3872 #undef LOCAL_BUF_SIZE
3873 WL_DBG(("return chanspec %x %d\n", ret_c
, bw
));
3878 wl_cfg80211_ibss_vsie_set_buffer(struct net_device
*dev
, vndr_ie_setbuf_t
*ibss_vsie
,
3881 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
3883 if (cfg
!= NULL
&& ibss_vsie
!= NULL
) {
3884 if (cfg
->ibss_vsie
!= NULL
) {
3885 MFREE(cfg
->osh
, cfg
->ibss_vsie
, cfg
->ibss_vsie_len
);
3887 cfg
->ibss_vsie
= ibss_vsie
;
3888 cfg
->ibss_vsie_len
= ibss_vsie_len
;
3893 wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211
*cfg
)
3895 /* free & initiralize VSIE (Vendor Specific IE) */
3896 if (cfg
->ibss_vsie
!= NULL
) {
3897 MFREE(cfg
->osh
, cfg
->ibss_vsie
, cfg
->ibss_vsie_len
);
3898 cfg
->ibss_vsie_len
= 0;
3903 wl_cfg80211_ibss_vsie_delete(struct net_device
*dev
)
3905 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
3906 char *ioctl_buf
= NULL
;
3907 s32 ret
= BCME_OK
, bssidx
;
3909 if (cfg
!= NULL
&& cfg
->ibss_vsie
!= NULL
) {
3910 ioctl_buf
= (char *)MALLOC(cfg
->osh
, WLC_IOCTL_MEDLEN
);
3912 WL_ERR(("ioctl memory alloc failed\n"));
3915 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
3916 WL_ERR(("Find index failed\n"));
3920 /* change the command from "add" to "del" */
3921 strlcpy(cfg
->ibss_vsie
->cmd
, "del", sizeof(cfg
->ibss_vsie
->cmd
));
3923 ret
= wldev_iovar_setbuf_bsscfg(dev
, "vndr_ie",
3924 cfg
->ibss_vsie
, cfg
->ibss_vsie_len
,
3925 ioctl_buf
, WLC_IOCTL_MEDLEN
, bssidx
, NULL
);
3926 WL_ERR(("ret=%d\n", ret
));
3928 if (ret
== BCME_OK
) {
3929 /* Free & initialize VSIE */
3930 MFREE(cfg
->osh
, cfg
->ibss_vsie
, cfg
->ibss_vsie_len
);
3931 cfg
->ibss_vsie_len
= 0;
3935 MFREE(cfg
->osh
, ioctl_buf
, WLC_IOCTL_MEDLEN
);
3942 #ifdef WLAIBSS_MCHAN
3943 static bcm_struct_cfgdev
*
3944 bcm_cfg80211_add_ibss_if(struct wiphy
*wiphy
, char *name
)
3947 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3948 struct wireless_dev
* wdev
= NULL
;
3949 struct net_device
*new_ndev
= NULL
;
3950 struct net_device
*primary_ndev
= NULL
;
3952 wl_aibss_if_t aibss_if
;
3953 wl_if_event_info
*event
= NULL
;
3955 if (cfg
->ibss_cfgdev
!= NULL
) {
3956 WL_ERR(("IBSS interface %s already exists\n", name
));
3960 WL_ERR(("Try to create IBSS interface %s\n", name
));
3961 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
3962 /* generate a new MAC address for the IBSS interface */
3963 get_primary_mac(cfg
, &cfg
->ibss_if_addr
);
3964 cfg
->ibss_if_addr
.octet
[4] ^= 0x40;
3965 bzero(&aibss_if
, sizeof(aibss_if
));
3966 memcpy(&aibss_if
.addr
, &cfg
->ibss_if_addr
, sizeof(aibss_if
.addr
));
3967 aibss_if
.chspec
= 0;
3968 aibss_if
.len
= sizeof(aibss_if
);
3970 cfg
->bss_pending_op
= TRUE
;
3971 bzero(&cfg
->if_event_info
, sizeof(cfg
->if_event_info
));
3972 err
= wldev_iovar_setbuf(primary_ndev
, "aibss_ifadd", &aibss_if
,
3973 sizeof(aibss_if
), cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
3975 WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err
));
3978 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
3979 !cfg
->bss_pending_op
, msecs_to_jiffies(MAX_WAIT_TIME
));
3980 if (timeout
<= 0 || cfg
->bss_pending_op
)
3983 event
= &cfg
->if_event_info
;
3984 /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
3985 * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
3986 * and will be freed by dhd_detach unless it gets unregistered before that. The
3987 * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
3988 * be freed by wl_dealloc_netinfo
3990 new_ndev
= wl_cfg80211_allocate_if(cfg
, event
->ifidx
, event
->name
,
3991 event
->mac
, event
->bssidx
, event
->name
);
3992 if (new_ndev
== NULL
)
3994 wdev
= (struct wireless_dev
*)MALLOCZ(cfg
->osh
, sizeof(*wdev
));
3997 wdev
->wiphy
= wiphy
;
3998 wdev
->iftype
= NL80211_IFTYPE_ADHOC
;
3999 wdev
->netdev
= new_ndev
;
4000 new_ndev
->ieee80211_ptr
= wdev
;
4001 SET_NETDEV_DEV(new_ndev
, wiphy_dev(wdev
->wiphy
));
4003 /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
4004 * needs to be modified to take one parameter (bool need_rtnl_lock)
4007 if (wl_cfg80211_register_if(cfg
, event
->ifidx
, new_ndev
, FALSE
) != BCME_OK
)
4010 wl_alloc_netinfo(cfg
, new_ndev
, wdev
, WL_IF_TYPE_IBSS
,
4011 PM_ENABLE
, event
->bssidx
, event
->ifidx
);
4012 cfg
->ibss_cfgdev
= ndev_to_cfgdev(new_ndev
);
4013 WL_ERR(("IBSS interface %s created\n", new_ndev
->name
));
4014 return cfg
->ibss_cfgdev
;
4017 WL_ERR(("failed to create IBSS interface %s \n", name
));
4018 cfg
->bss_pending_op
= FALSE
;
4020 wl_cfg80211_remove_if(cfg
, event
->ifidx
, new_ndev
, FALSE
);
4022 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
4028 bcm_cfg80211_del_ibss_if(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
)
4031 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
4032 struct net_device
*ndev
= NULL
;
4033 struct net_device
*primary_ndev
= NULL
;
4036 if (!cfgdev
|| cfg
->ibss_cfgdev
!= cfgdev
|| ETHER_ISNULLADDR(&cfg
->ibss_if_addr
.octet
))
4038 ndev
= (struct net_device
*)cfgdev_to_ndev(cfg
->ibss_cfgdev
);
4039 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
4041 cfg
->bss_pending_op
= TRUE
;
4042 bzero(&cfg
->if_event_info
, sizeof(cfg
->if_event_info
));
4043 err
= wldev_iovar_setbuf(primary_ndev
, "aibss_ifdel", &cfg
->ibss_if_addr
,
4044 sizeof(cfg
->ibss_if_addr
), cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
4046 WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err
));
4049 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
4050 !cfg
->bss_pending_op
, msecs_to_jiffies(MAX_WAIT_TIME
));
4051 if (timeout
<= 0 || cfg
->bss_pending_op
) {
4052 WL_ERR(("timeout in waiting IF_DEL event\n"));
4056 wl_cfg80211_remove_if(cfg
, cfg
->if_event_info
.ifidx
, ndev
, FALSE
);
4057 cfg
->ibss_cfgdev
= NULL
;
4061 cfg
->bss_pending_op
= FALSE
;
4064 #endif /* WLAIBSS_MCHAN */
4067 wl_cfg80211_to_fw_iftype(wl_iftype_t iftype
)
4069 s32 ret
= BCME_ERROR
;
4073 ret
= WL_INTERFACE_TYPE_AP
;
4075 case WL_IF_TYPE_STA
:
4076 ret
= WL_INTERFACE_TYPE_STA
;
4078 case WL_IF_TYPE_NAN_NMI
:
4079 case WL_IF_TYPE_NAN
:
4080 ret
= WL_INTERFACE_TYPE_NAN
;
4082 case WL_IF_TYPE_P2P_DISC
:
4083 ret
= WL_INTERFACE_TYPE_P2P_DISC
;
4085 case WL_IF_TYPE_P2P_GO
:
4086 ret
= WL_INTERFACE_TYPE_P2P_GO
;
4088 case WL_IF_TYPE_P2P_GC
:
4089 ret
= WL_INTERFACE_TYPE_P2P_GC
;
4093 WL_ERR(("Unsupported type:%d \n", iftype
));
4101 wl_legacy_chip_check(struct bcm_cfg80211
*cfg
)
4103 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
4106 chip
= dhd_conf_get_chip(dhd
);
4108 if (chip
== BCM43362_CHIP_ID
|| chip
== BCM4330_CHIP_ID
||
4109 chip
== BCM43430_CHIP_ID
|| chip
== BCM43012_CHIP_ID
||
4110 chip
== BCM4334_CHIP_ID
|| chip
== BCM43340_CHIP_ID
||
4111 chip
== BCM43341_CHIP_ID
|| chip
== BCM4324_CHIP_ID
||
4112 chip
== BCM4335_CHIP_ID
|| chip
== BCM4339_CHIP_ID
||
4113 chip
== BCM4345_CHIP_ID
|| chip
== BCM43454_CHIP_ID
||
4114 chip
== BCM4354_CHIP_ID
|| chip
== BCM4356_CHIP_ID
||
4115 chip
== BCM4371_CHIP_ID
|| chip
== BCM4359_CHIP_ID
||
4116 chip
== BCM43143_CHIP_ID
|| chip
== BCM43242_CHIP_ID
||
4117 chip
== BCM43569_CHIP_ID
) {
4125 wl_cfg80211_interface_ops(struct bcm_cfg80211
*cfg
,
4126 struct net_device
*ndev
, s32 bsscfg_idx
,
4127 wl_iftype_t cfg_iftype
, s32 del
, u8
*addr
)
4130 struct wl_interface_create_v2 iface
;
4131 wl_interface_create_v3_t iface_v3
;
4132 wl_interface_create_t iface_v0
;
4133 struct wl_interface_info_v1
*info
;
4134 wl_interface_info_v2_t
*info_v2
;
4135 wl_interface_info_t
*info_v0
;
4137 bool use_iface_info_v2
= false;
4138 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
4142 ret
= wldev_iovar_setbuf(ndev
, "interface_remove",
4143 NULL
, 0, ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4145 WL_ERR(("Interface remove failed!! ret %d\n", ret
));
4149 /* Interface create */
4150 bzero(&iface
, sizeof(iface
));
4152 * flags field is still used along with iftype inorder to support the old version of the
4153 * FW work with the latest app changes.
4156 iftype
= wl_cfg80211_to_fw_iftype(cfg_iftype
);
4162 ifflags
|= WL_INTERFACE_MAC_USE
;
4165 /* Pass ver = 0 for fetching the interface_create iovar version */
4166 if (wl_legacy_chip_check(cfg
)) {
4167 bzero(&iface_v0
, sizeof(iface_v0
));
4168 iface_v0
.ver
= WL_INTERFACE_CREATE_VER
;
4169 iface_v0
.flags
= iftype
| ifflags
;
4171 memcpy(&iface_v0
.mac_addr
.octet
, addr
, ETH_ALEN
);
4173 ret
= wldev_iovar_getbuf(ndev
, "interface_create",
4174 &iface_v0
, sizeof(struct wl_interface_create
),
4175 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4177 info_v0
= (wl_interface_info_t
*)ioctl_buf
;
4178 ret
= info_v0
->bsscfgidx
;
4182 ret
= wldev_iovar_getbuf(ndev
, "interface_create",
4183 &iface
, sizeof(struct wl_interface_create_v2
),
4184 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4186 if (ret
== BCME_UNSUPPORTED
) {
4187 WL_ERR(("interface_create iovar not supported\n"));
4189 } else if ((ret
== 0) && *((uint32
*)ioctl_buf
) == WL_INTERFACE_CREATE_VER_3
) {
4190 WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags
));
4191 use_iface_info_v2
= true;
4192 bzero(&iface_v3
, sizeof(wl_interface_create_v3_t
));
4193 iface_v3
.ver
= WL_INTERFACE_CREATE_VER_3
;
4194 iface_v3
.iftype
= iftype
;
4195 iface_v3
.flags
= ifflags
;
4197 memcpy(&iface_v3
.mac_addr
.octet
, addr
, ETH_ALEN
);
4199 ret
= wldev_iovar_getbuf(ndev
, "interface_create",
4200 &iface_v3
, sizeof(wl_interface_create_v3_t
),
4201 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4203 /* On any other error, attempt with iovar version 2 */
4204 WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n", ret
, ifflags
));
4205 iface
.ver
= WL_INTERFACE_CREATE_VER_2
;
4206 iface
.iftype
= iftype
;
4207 iface
.flags
= ifflags
;
4209 memcpy(&iface
.mac_addr
.octet
, addr
, ETH_ALEN
);
4211 ret
= wldev_iovar_getbuf(ndev
, "interface_create",
4212 &iface
, sizeof(struct wl_interface_create_v2
),
4213 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4216 if (unlikely(ret
)) {
4217 WL_ERR(("Interface create failed!! ret %d\n", ret
));
4222 if (use_iface_info_v2
== true) {
4223 info_v2
= (wl_interface_info_v2_t
*)ioctl_buf
;
4224 ret
= info_v2
->bsscfgidx
;
4227 info
= (struct wl_interface_info_v1
*)ioctl_buf
;
4228 ret
= info
->bsscfgidx
;
4232 WL_DBG(("wl interface create success!! bssidx:%d \n", ret
));
4237 wl_cfg80211_add_del_bss(struct bcm_cfg80211
*cfg
,
4238 struct net_device
*ndev
, s32 bsscfg_idx
,
4239 wl_iftype_t brcm_iftype
, s32 del
, u8
*addr
)
4247 struct ether_addr ea
;
4250 WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype
, del
));
4252 bzero(&bss_setbuf
, sizeof(bss_setbuf
));
4254 /* AP=2, STA=3, up=1, down=0, val=-1 */
4256 val
= WLC_AP_IOV_OP_DELETE
;
4257 } else if (brcm_iftype
== WL_IF_TYPE_AP
) {
4258 /* Add/role change to AP Interface */
4259 WL_DBG(("Adding AP Interface \n"));
4260 val
= WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE
;
4261 } else if (brcm_iftype
== WL_IF_TYPE_STA
) {
4262 /* Add/role change to STA Interface */
4263 WL_DBG(("Adding STA Interface \n"));
4264 val
= WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE
;
4266 WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype
));
4271 wl_ext_bss_iovar_war(ndev
, &val
);
4274 bss_setbuf
.cfg
= htod32(bsscfg_idx
);
4275 bss_setbuf
.val
= htod32(val
);
4278 memcpy(&bss_setbuf
.ea
.octet
, addr
, ETH_ALEN
);
4281 WL_MSG(ndev
->name
, "wl bss %d bssidx:%d\n", val
, bsscfg_idx
);
4282 ret
= wldev_iovar_setbuf(ndev
, "bss", &bss_setbuf
, sizeof(bss_setbuf
),
4283 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
4285 WL_ERR(("'bss %d' failed with %d\n", val
, ret
));
4291 wl_cfg80211_bss_up(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, s32 bsscfg_idx
, s32 bss_up
)
4294 s32 val
= bss_up
? 1 : 0;
4301 bss_setbuf
.cfg
= htod32(bsscfg_idx
);
4302 bss_setbuf
.val
= htod32(val
);
4304 WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx
, bss_up
? "up" : "down"));
4305 ret
= wldev_iovar_setbuf(ndev
, "bss", &bss_setbuf
, sizeof(bss_setbuf
),
4306 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
4309 WL_ERR(("'bss %d' failed with %d\n", bss_up
, ret
));
4316 wl_cfg80211_bss_isup(struct net_device
*ndev
, int bsscfg_idx
)
4322 /* Check if the BSS is up */
4324 result
= wldev_iovar_getbuf_bsscfg(ndev
, "bss", &bsscfg_idx
,
4325 sizeof(bsscfg_idx
), getbuf
, sizeof(getbuf
), 0, NULL
);
4327 WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx
, result
));
4328 WL_ERR(("NOTE: this ioctl error is normal "
4329 "when the BSS has not been created yet.\n"));
4331 val
= *(int*)getbuf
;
4333 WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx
, val
));
4334 isup
= (val
? TRUE
: FALSE
);
4340 wl_iftype_to_mode(wl_iftype_t iftype
)
4342 s32 mode
= BCME_ERROR
;
4345 case WL_IF_TYPE_STA
:
4346 case WL_IF_TYPE_P2P_GC
:
4347 case WL_IF_TYPE_P2P_DISC
:
4351 case WL_IF_TYPE_P2P_GO
:
4354 case WL_IF_TYPE_NAN
:
4358 case WL_IF_TYPE_AIBSS
:
4359 /* Intentional fall through */
4360 case WL_IF_TYPE_IBSS
:
4361 mode
= WL_MODE_IBSS
;
4363 #ifdef WLMESH_CFG80211
4364 case WL_IF_TYPE_MESH
:
4365 mode
= WL_MODE_MESH
;
4367 #endif /* WLMESH_CFG80211 */
4369 WL_ERR(("Unsupported type:%d\n", iftype
));
4376 cfg80211_to_wl_iftype(uint16 type
, uint16
*role
, uint16
*mode
)
4379 case NL80211_IFTYPE_STATION
:
4380 *role
= WL_IF_TYPE_STA
;
4381 *mode
= WL_MODE_BSS
;
4383 case NL80211_IFTYPE_AP
:
4384 *role
= WL_IF_TYPE_AP
;
4387 #ifdef WL_CFG80211_P2P_DEV_IF
4388 case NL80211_IFTYPE_P2P_DEVICE
:
4389 *role
= WL_IF_TYPE_P2P_DISC
;
4390 *mode
= WL_MODE_BSS
;
4392 #endif /* WL_CFG80211_P2P_DEV_IF */
4393 case NL80211_IFTYPE_P2P_GO
:
4394 *role
= WL_IF_TYPE_P2P_GO
;
4397 case NL80211_IFTYPE_P2P_CLIENT
:
4398 *role
= WL_IF_TYPE_P2P_GC
;
4399 *mode
= WL_MODE_BSS
;
4401 case NL80211_IFTYPE_MONITOR
:
4402 WL_ERR(("Unsupported mode \n"));
4403 return BCME_UNSUPPORTED
;
4404 case NL80211_IFTYPE_ADHOC
:
4405 *role
= WL_IF_TYPE_IBSS
;
4406 *mode
= WL_MODE_IBSS
;
4408 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
4409 case NL80211_IFTYPE_NAN
:
4410 *role
= WL_IF_TYPE_NAN
;
4411 *mode
= WL_MODE_NAN
;
4414 #ifdef WLMESH_CFG80211
4415 case NL80211_IFTYPE_MESH_POINT
:
4416 *role
= WLC_E_IF_ROLE_AP
;
4417 *mode
= WL_MODE_MESH
;
4419 #endif /* WLMESH_CFG80211 */
4421 WL_ERR(("Unknown interface type:0x%x\n", type
));
4428 wl_role_to_cfg80211_type(uint16 role
, uint16
*wl_iftype
, uint16
*mode
)
4432 case WLC_E_IF_ROLE_STA
:
4433 *wl_iftype
= WL_IF_TYPE_STA
;
4434 *mode
= WL_MODE_BSS
;
4435 return NL80211_IFTYPE_STATION
;
4436 case WLC_E_IF_ROLE_AP
:
4437 *wl_iftype
= WL_IF_TYPE_AP
;
4439 return NL80211_IFTYPE_AP
;
4440 case WLC_E_IF_ROLE_P2P_GO
:
4441 *wl_iftype
= WL_IF_TYPE_P2P_GO
;
4443 return NL80211_IFTYPE_P2P_GO
;
4444 case WLC_E_IF_ROLE_P2P_CLIENT
:
4445 *wl_iftype
= WL_IF_TYPE_P2P_GC
;
4446 *mode
= WL_MODE_BSS
;
4447 return NL80211_IFTYPE_P2P_CLIENT
;
4448 case WLC_E_IF_ROLE_IBSS
:
4449 *wl_iftype
= WL_IF_TYPE_IBSS
;
4450 *mode
= WL_MODE_IBSS
;
4451 return NL80211_IFTYPE_ADHOC
;
4452 case WLC_E_IF_ROLE_NAN
:
4453 *wl_iftype
= WL_IF_TYPE_NAN
;
4454 *mode
= WL_MODE_NAN
;
4455 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
4456 /* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
4457 * For Vendor HAL based NAN implementation, continue advertising
4458 * as a STA interface
4460 return NL80211_IFTYPE_NAN
;
4462 return NL80211_IFTYPE_STATION
;
4463 #endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
4465 case WLC_E_IF_ROLE_WDS
:
4466 *wl_iftype
= WL_IF_TYPE_AP
;
4468 return NL80211_IFTYPE_AP
;
4470 #ifdef WLMESH_CFG80211
4471 case WLC_E_IF_ROLE_MESH
:
4472 *wl_iftype
= WL_IF_TYPE_MESH
;
4473 *mode
= WL_MODE_MESH
;
4474 return NL80211_IFTYPE_MESH_POINT
;
4475 #endif /* WLMESH_CFG80211 */
4478 WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role
));
4484 wl_cfg80211_post_ifcreate(struct net_device
*ndev
,
4485 wl_if_event_info
*event
, u8
*addr
,
4486 const char *name
, bool rtnl_lock_reqd
)
4488 struct bcm_cfg80211
*cfg
;
4489 struct net_device
*primary_ndev
;
4490 struct net_device
*new_ndev
= NULL
;
4491 struct wireless_dev
*wdev
= NULL
;
4495 u8 mac_addr
[ETH_ALEN
];
4498 if (!ndev
|| !event
) {
4499 WL_ERR(("Wrong arg\n"));
4503 cfg
= wl_get_cfg(ndev
);
4505 WL_ERR(("cfg null\n"));
4509 WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
4510 event
->role
, event
->ifidx
, event
->bssidx
));
4511 if (!event
->ifidx
|| !event
->bssidx
) {
4512 /* Fw returned primary idx (0) for virtual interface */
4513 WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
4514 event
->ifidx
, event
->bssidx
));
4518 #if defined(WLMESH_CFG80211) && defined(WL_EXT_IAPSTA)
4519 if (wl_ext_iapsta_mesh_creating(ndev
)) {
4520 event
->role
= WLC_E_IF_ROLE_MESH
;
4521 WL_MSG(ndev
->name
, "change role to WLC_E_IF_ROLE_MESH\n");
4523 #endif /* WLMESH_CFG80211 && WL_EXT_IAPSTA */
4525 iface_type
= wl_role_to_cfg80211_type(event
->role
, &wl_iftype
, &mode
);
4526 if (iface_type
< 0) {
4527 /* Unknown iface type */
4528 WL_ERR(("Wrong iface type \n"));
4532 WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG
"\n",
4533 addr
, name
, event
->role
, iface_type
, MAC2STRDBG(event
->mac
)));
4535 /* If iface name is not provided, use dongle ifname */
4540 /* If mac address is not set, use primary mac with locally administered
4543 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
4544 memcpy(mac_addr
, primary_ndev
->dev_addr
, ETH_ALEN
);
4545 /* For customer6 builds, use primary mac address for virtual interface */
4546 mac_addr
[0] |= 0x02;
4550 if (iface_type
== NL80211_IFTYPE_P2P_CLIENT
) {
4551 s16 cfg_type
= wl_cfgp2p_get_conn_idx(cfg
);
4552 struct ether_addr
*p2p_addr
= wl_to_p2p_bss_macaddr(cfg
, cfg_type
);
4554 /* check if pre-registered mac matches the mac from dongle via WLC_E_LINK */
4555 if (memcmp(p2p_addr
->octet
, addr
, ETH_ALEN
)) {
4556 WL_INFORM_MEM(("p2p pre-regsitered mac:" MACDBG
4557 " , mac from dongle:" MACDBG
"\n",
4558 MAC2STRDBG(p2p_addr
->octet
), MAC2STRDBG(addr
)));
4560 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
4562 wl_cfg80211_handle_hang_event(primary_ndev
,
4563 HANG_REASON_IFACE_ADD_FAILURE
, DUMP_TYPE_IFACE_OP_FAILURE
);
4569 if (IS_CFG80211_STATIC_IF_NAME(cfg
, name
)) {
4570 new_ndev
= wl_cfg80211_post_static_ifcreate(cfg
, event
, addr
, iface_type
);
4572 WL_ERR(("failed to get I/F pointer\n"));
4575 wdev
= new_ndev
->ieee80211_ptr
;
4577 #endif /* WL_STATIC_IF */
4579 new_ndev
= wl_cfg80211_allocate_if(cfg
, event
->ifidx
,
4580 name
, addr
, event
->bssidx
, event
->name
);
4582 WL_ERR(("I/F allocation failed! \n"));
4585 WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
4586 event
->ifidx
, event
->bssidx
));
4589 wdev
= (struct wireless_dev
*)MALLOCZ(cfg
->osh
, sizeof(*wdev
));
4591 WL_ERR(("wireless_dev alloc failed! \n"));
4592 wl_cfg80211_remove_if(cfg
, event
->ifidx
, new_ndev
, rtnl_lock_reqd
);
4596 wdev
->wiphy
= bcmcfg_to_wiphy(cfg
);
4597 wdev
->iftype
= iface_type
;
4599 new_ndev
->ieee80211_ptr
= wdev
;
4601 /* set wds0.x to 4addr interface here */
4602 if (event
->role
== WLC_E_IF_ROLE_WDS
) {
4603 printf("\n\n\n event->role == WLC_E_IF_ROLE_WDS, set vwdev 4addr to %s\n", event
->name
);
4604 wdev
->use_4addr
= true;
4607 SET_NETDEV_DEV(new_ndev
, wiphy_dev(wdev
->wiphy
));
4609 memcpy(new_ndev
->dev_addr
, addr
, ETH_ALEN
);
4610 #ifdef WL_EXT_IAPSTA
4611 wl_ext_iapsta_ifadding(new_ndev
, event
->ifidx
);
4612 #endif /* WL_EXT_IAPSTA */
4613 if (wl_cfg80211_register_if(cfg
, event
->ifidx
, new_ndev
, rtnl_lock_reqd
)
4615 WL_ERR(("IFACE register failed \n"));
4616 /* Post interface registration, wdev would be freed from the netdev
4617 * destructor path. For other cases, handle it here.
4619 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
4620 wl_cfg80211_remove_if(cfg
, event
->ifidx
, new_ndev
, rtnl_lock_reqd
);
4625 /* Initialize with the station mode params */
4626 ret
= wl_alloc_netinfo(cfg
, new_ndev
, wdev
, wl_iftype
,
4627 PM_ENABLE
, event
->bssidx
, event
->ifidx
);
4628 if (unlikely(ret
)) {
4629 WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret
));
4633 /* Apply the mode & infra setting based on iftype */
4634 if ((ret
= wl_config_infra(cfg
, new_ndev
, wl_iftype
)) < 0) {
4635 WL_ERR(("config ifmode failure (%d)\n", ret
));
4639 if (mode
== WL_MODE_AP
) {
4640 wl_set_drv_status(cfg
, AP_CREATING
, new_ndev
);
4642 #ifdef WL_EXT_IAPSTA
4643 wl_ext_iapsta_update_iftype(new_ndev
, event
->ifidx
, wl_iftype
);
4646 WL_INFORM_MEM(("Network Interface (%s) registered with host."
4647 " cfg_iftype:%d wl_role:%d " MACDBG
"\n",
4648 new_ndev
->name
, iface_type
, event
->role
, MAC2STRDBG(new_ndev
->dev_addr
)));
4650 #ifdef SUPPORT_SET_CAC
4651 wl_cfg80211_set_cac(cfg
, 0);
4652 #endif /* SUPPORT_SET_CAC */
4658 /* remove static if from iflist */
4659 if (IS_CFG80211_STATIC_IF_NAME(cfg
, name
)) {
4660 cfg
->static_ndev_state
= NDEV_STATE_FW_IF_FAILED
;
4661 wl_cfg80211_update_iflist_info(cfg
, new_ndev
, WL_STATIC_IFIDX
, addr
,
4662 event
->bssidx
, event
->name
, NDEV_STATE_FW_IF_FAILED
);
4664 #endif /* WL_STATIC_IF */
4666 /* wdev would be freed from netdev destructor call back */
4667 wl_cfg80211_remove_if(cfg
, event
->ifidx
, new_ndev
, rtnl_lock_reqd
);
4674 wl_cfg80211_delete_iface(struct bcm_cfg80211
*cfg
,
4675 wl_iftype_t sec_data_if_type
)
4677 struct net_info
*iter
, *next
;
4678 struct net_device
*primary_ndev
;
4685 /* Note: This function will clean up only the network interface and host
4686 * data structures. The firmware interface clean up will happen in the
4687 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4688 * context for the module case).
4690 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
4691 WL_DBG(("Enter, deleting iftype %s\n",
4692 wl_iftype_to_str(sec_data_if_type
)));
4693 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4694 for_each_ndev(cfg
, iter
, next
) {
4695 GCC_DIAGNOSTIC_POP();
4696 if (iter
->ndev
&& (iter
->ndev
!= primary_ndev
)) {
4697 if (iter
->iftype
!= sec_data_if_type
) {
4700 switch (sec_data_if_type
) {
4701 case WL_IF_TYPE_P2P_GO
:
4702 case WL_IF_TYPE_P2P_GC
: {
4703 ret
= _wl_cfg80211_del_if(cfg
,
4704 iter
->ndev
, NULL
, iter
->ndev
->name
);
4708 case WL_IF_TYPE_NAN
: {
4709 if (wl_cfgnan_is_enabled(cfg
) == false) {
4710 WL_INFORM_MEM(("Nan is not active,"
4711 " ignore NDI delete\n"));
4713 ret
= wl_cfgnan_delete_ndp(cfg
, iter
->ndev
);
4718 case WL_IF_TYPE_AP
: {
4721 /* handle static ap */
4722 if (IS_CFG80211_STATIC_IF(cfg
, iter
->ndev
)) {
4723 dev_close(iter
->ndev
);
4725 #endif /* WL_STATIC_IF */
4727 /* handle virtual created AP */
4728 ret
= _wl_cfg80211_del_if(cfg
, iter
->ndev
,
4729 NULL
, iter
->ndev
->name
);
4734 WL_ERR(("Unsupported interface type\n"));
4746 wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211
*cfg
, bool rtnl_lock_reqd
)
4748 struct net_info
*iter
, *next
;
4749 struct net_device
*primary_ndev
;
4751 /* Note: This function will clean up only the network interface and host
4752 * data structures. The firmware interface clean up will happen in the
4753 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4754 * context for the module case).
4756 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
4757 WL_DBG(("Enter\n"));
4758 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4759 for_each_ndev(cfg
, iter
, next
) {
4760 GCC_DIAGNOSTIC_POP();
4761 if (iter
->ndev
&& (iter
->ndev
!= primary_ndev
)) {
4762 /* Ensure interfaces are down before deleting */
4764 /* Avoiding cleaning static ifaces */
4765 if (!IS_CFG80211_STATIC_IF(cfg
, iter
->ndev
))
4766 #endif /* WL_STATIC_IF */
4768 dev_close(iter
->ndev
);
4769 WL_DBG(("Cleaning up iface:%s \n", iter
->ndev
->name
));
4770 wl_cfg80211_post_ifdel(iter
->ndev
, rtnl_lock_reqd
, 0);
4777 wl_cfg80211_post_ifdel(struct net_device
*ndev
, bool rtnl_lock_reqd
, s32 ifidx
)
4780 struct bcm_cfg80211
*cfg
;
4781 struct net_info
*netinfo
= NULL
;
4783 if (!ndev
|| !ndev
->ieee80211_ptr
) {
4784 /* No wireless dev done for this interface */
4789 cfg
= wl_get_cfg(ndev
);
4791 WL_ERR(("cfg null\n"));
4797 WL_ERR(("Invalid IF idx for iface:%s\n", ndev
->name
));
4798 ifidx
= dhd_net2idx(((struct dhd_pub
*)(cfg
->pub
))->info
, ndev
);
4799 BCM_REFERENCE(ifidx
);
4807 if ((netinfo
= wl_get_netinfo_by_wdev(cfg
, ndev_to_wdev(ndev
))) == NULL
) {
4808 WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev
)));
4814 if (IS_CFG80211_STATIC_IF(cfg
, ndev
)) {
4815 ret
= wl_cfg80211_post_static_ifdel(cfg
, ndev
);
4817 #endif /* WL_STATIC_IF */
4819 WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
4820 ndev
->name
, ifidx
, cfg
->vif_count
));
4821 wl_cfg80211_remove_if(cfg
, ifidx
, ndev
, rtnl_lock_reqd
);
4822 cfg
->bss_pending_op
= FALSE
;
4825 #ifdef SUPPORT_SET_CAC
4826 wl_cfg80211_set_cac(cfg
, 1);
4827 #endif /* SUPPORT_SET_CAC */
4833 wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211
*cfg
)
4836 bcm_struct_cfgdev
*cfgdev
;
4839 /* De-initialize the p2p discovery interface, if operational */
4840 WL_ERR(("Disabling P2P Discovery Interface \n"));
4841 #ifdef WL_CFG80211_P2P_DEV_IF
4842 cfgdev
= bcmcfg_to_p2p_wdev(cfg
);
4844 cfgdev
= cfg
->p2p_net
;
4847 ret
= wl_cfg80211_scan_stop(cfg
, cfgdev
);
4848 if (unlikely(ret
< 0)) {
4849 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret
));
4853 wl_cfgp2p_disable_discovery(cfg
);
4854 wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
) = 0;
4855 p2p_on(cfg
) = false;
4860 /* Create a Generic Network Interface and initialize it depending up on
4861 * the interface type
4863 struct wireless_dev
*
4864 wl_cfg80211_create_iface(struct wiphy
*wiphy
,
4865 wl_iftype_t wl_iftype
,
4866 u8
*mac_addr
, const char *name
)
4868 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
4869 struct net_device
*new_ndev
= NULL
;
4870 struct net_device
*primary_ndev
= NULL
;
4874 wl_if_event_info
*event
= NULL
;
4876 struct net_info
*iter
, *next
;
4878 WL_DBG(("Enter\n"));
4880 WL_ERR(("Interface name not provided\n"));
4884 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4885 for_each_ndev(cfg
, iter
, next
) {
4886 GCC_DIAGNOSTIC_POP();
4888 if (strncmp(iter
->ndev
->name
, name
, strlen(name
)) == 0) {
4889 WL_ERR(("Interface name,%s exists!\n", iter
->ndev
->name
));
4895 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
4896 if (likely(!mac_addr
)) {
4897 /* Use primary MAC with the locally administered bit for the
4900 memcpy(addr
, primary_ndev
->dev_addr
, ETH_ALEN
);
4903 /* Use the application provided mac address (if any) */
4904 memcpy(addr
, mac_addr
, ETH_ALEN
);
4907 cfg
->bss_pending_op
= TRUE
;
4908 bzero(&cfg
->if_event_info
, sizeof(cfg
->if_event_info
));
4911 * Intialize the firmware I/F.
4915 ret
= wl_cfg80211_interface_ops(cfg
, primary_ndev
, bsscfg_idx
,
4916 wl_iftype
, 0, addr
);
4918 if (ret
== BCME_UNSUPPORTED
) {
4919 /* Use bssidx 1 by default */
4921 if ((ret
= wl_cfg80211_add_del_bss(cfg
, primary_ndev
,
4922 bsscfg_idx
, wl_iftype
, 0, addr
)) < 0) {
4925 } else if (ret
< 0) {
4926 WL_ERR(("Interface create failed!! ret:%d \n", ret
));
4933 WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx
));
4935 * Wait till the firmware send a confirmation event back.
4937 WL_DBG(("Wait for the FW I/F Event\n"));
4938 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
4939 !cfg
->bss_pending_op
, msecs_to_jiffies(MAX_WAIT_TIME
));
4940 if (timeout
<= 0 || cfg
->bss_pending_op
) {
4941 WL_ERR(("ADD_IF event, didn't come. Return. timeout:%lu bss_pending_op:%d\n",
4942 timeout
, cfg
->bss_pending_op
));
4943 if (timeout
== -ERESTARTSYS
) {
4944 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
4949 event
= &cfg
->if_event_info
;
4951 * Since FW operation is successful,we can go ahead with the
4952 * the host interface creation.
4954 new_ndev
= wl_cfg80211_post_ifcreate(primary_ndev
,
4955 event
, addr
, name
, false);
4958 /* Iface post ops successful. Return ndev/wdev ptr */
4959 return new_ndev
->ieee80211_ptr
;
4963 cfg
->bss_pending_op
= FALSE
;
4968 wl_cfg80211_del_iface(struct wiphy
*wiphy
, struct wireless_dev
*wdev
)
4970 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
4971 struct net_device
*ndev
= NULL
;
4978 WL_DBG(("Enter\n"));
4980 /* If any scan is going on, abort it */
4981 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
4982 WL_DBG(("Scan in progress. Aborting the scan!\n"));
4983 wl_cfg80211_cancel_scan(cfg
);
4986 bsscfg_idx
= wl_get_bssidx_by_wdev(cfg
, wdev
);
4987 if (bsscfg_idx
<= 0) {
4988 /* validate bsscfgidx */
4989 WL_ERR(("Wrong bssidx! \n"));
4993 /* Handle p2p iface */
4994 if ((ret
= wl_cfg80211_p2p_if_del(wiphy
, wdev
)) != BCME_NOTFOUND
) {
4995 WL_DBG(("P2P iface del handled \n"));
4996 #ifdef SUPPORT_SET_CAC
4997 wl_cfg80211_set_cac(cfg
, 1);
4998 #endif /* SUPPORT_SET_CAC */
5002 ndev
= wdev
->netdev
;
5003 if (unlikely(!ndev
)) {
5004 WL_ERR(("ndev null! \n"));
5008 memset(&cfg
->if_event_info
, 0, sizeof(cfg
->if_event_info
));
5010 if (cfg80211_to_wl_iftype(ndev
->ieee80211_ptr
->iftype
,
5011 &wl_iftype
, &wl_mode
) < 0) {
5015 WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d",
5016 bsscfg_idx
, ndev
->ieee80211_ptr
->iftype
, wl_iftype
));
5017 /* Delete the firmware interface. "interface_remove" command
5018 * should go on the interface to be deleted
5020 if (wl_cfg80211_get_bus_state(cfg
)) {
5021 WL_ERR(("Bus state is down: %d\n", __LINE__
));
5022 ret
= BCME_DONGLE_DOWN
;
5026 cfg
->bss_pending_op
= true;
5027 ret
= wl_cfg80211_interface_ops(cfg
, ndev
, bsscfg_idx
,
5028 wl_iftype
, 1, NULL
);
5029 if (ret
== BCME_UNSUPPORTED
) {
5030 if ((ret
= wl_cfg80211_add_del_bss(cfg
, ndev
,
5031 bsscfg_idx
, wl_iftype
, true, NULL
)) < 0) {
5032 WL_ERR(("DEL bss failed ret:%d \n", ret
));
5035 } else if ((ret
== BCME_NOTAP
) || (ret
== BCME_NOTSTA
)) {
5036 /* De-init sequence involving role downgrade not happened.
5037 * Do nothing and return error. The del command should be
5040 WL_ERR(("ifdel role mismatch:%d\n", ret
));
5043 } else if (ret
< 0) {
5044 WL_ERR(("Interface DEL failed ret:%d \n", ret
));
5048 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
5049 !cfg
->bss_pending_op
, msecs_to_jiffies(MAX_WAIT_TIME
));
5050 if (timeout
<= 0 || cfg
->bss_pending_op
) {
5051 WL_ERR(("timeout in waiting IF_DEL event\n"));
5052 /* The interface unregister will happen from wifi reset context */
5059 WL_ERR(("iface del failed:%d\n", ret
));
5061 if (IS_CFG80211_STATIC_IF(cfg
, ndev
)) {
5063 * For static interface, clean up the host data,
5064 * irrespective of fw status. For dynamic
5065 * interfaces it gets cleaned from dhd_stop context
5067 wl_cfg80211_post_static_ifdel(cfg
, ndev
);
5069 #endif /* WL_STATIC_IF */
5071 ret
= wl_cfg80211_post_ifdel(ndev
, false, cfg
->if_event_info
.ifidx
);
5072 if (unlikely(ret
)) {
5073 WL_ERR(("post_ifdel failed\n"));
5077 cfg
->bss_pending_op
= false;
5082 wl_cfg80211_join_ibss(struct wiphy
*wiphy
, struct net_device
*dev
,
5083 struct cfg80211_ibss_params
*params
)
5085 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
5086 struct cfg80211_bss
*bss
;
5087 struct ieee80211_channel
*chan
;
5088 struct wl_join_params join_params
;
5090 struct cfg80211_ssid ssid
;
5093 size_t join_params_size
;
5094 chanspec_t chanspec
= 0;
5097 RETURN_EIO_IF_NOT_UP(cfg
);
5098 WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG
"\n", MAC2STRDBG(params
->bssid
)));
5099 if (!params
->ssid
|| params
->ssid_len
<= 0 ||
5100 params
->ssid_len
> DOT11_MAX_SSID_LEN
) {
5101 WL_ERR(("Invalid parameter\n"));
5104 #if defined(WL_CFG80211_P2P_DEV_IF)
5105 chan
= params
->chandef
.chan
;
5107 chan
= params
->channel
;
5108 #endif /* WL_CFG80211_P2P_DEV_IF */
5110 cfg
->channel
= wl_freq_to_chanspec(chan
->center_freq
);
5112 if (wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
5113 struct wlc_ssid
*lssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, dev
, WL_PROF_SSID
);
5114 u8
*bssid
= (u8
*)wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
5115 u32
*channel
= (u32
*)wl_read_prof(cfg
, dev
, WL_PROF_CHAN
);
5116 if (!params
->bssid
|| ((memcmp(params
->bssid
, bssid
, ETHER_ADDR_LEN
) == 0) &&
5117 (memcmp(params
->ssid
, lssid
->SSID
, lssid
->SSID_len
) == 0) &&
5118 (*channel
== cfg
->channel
))) {
5119 WL_ERR(("Connection already existed to " MACDBG
"\n",
5120 MAC2STRDBG((u8
*)wl_read_prof(cfg
, dev
, WL_PROF_BSSID
))));
5123 WL_ERR(("Ignore Previous connecton to %s (" MACDBG
")\n",
5124 lssid
->SSID
, MAC2STRDBG(bssid
)));
5127 /* remove the VSIE */
5128 wl_cfg80211_ibss_vsie_delete(dev
);
5130 bss
= cfg80211_get_ibss(wiphy
, NULL
, params
->ssid
, params
->ssid_len
);
5132 if (IBSS_INITIAL_SCAN_ALLOWED
== TRUE
) {
5133 memcpy(ssid
.ssid
, params
->ssid
, params
->ssid_len
);
5134 ssid
.ssid_len
= params
->ssid_len
;
5137 (__wl_cfg80211_scan(wiphy
, dev
, NULL
, &ssid
) ==
5143 } while (++scan_retry
< WL_SCAN_RETRY_MAX
);
5145 /* rtnl lock code is removed here. don't see why rtnl lock
5146 * needs to be released.
5149 /* wait 4 secons till scan done.... */
5150 schedule_timeout_interruptible(msecs_to_jiffies(4000));
5152 bss
= cfg80211_get_ibss(wiphy
, NULL
,
5153 params
->ssid
, params
->ssid_len
);
5156 if (bss
&& ((IBSS_COALESCE_ALLOWED
== TRUE
) ||
5157 ((IBSS_COALESCE_ALLOWED
== FALSE
) && params
->bssid
&&
5158 !memcmp(bss
->bssid
, params
->bssid
, ETHER_ADDR_LEN
)))) {
5159 cfg
->ibss_starter
= false;
5160 WL_DBG(("Found IBSS\n"));
5162 cfg
->ibss_starter
= true;
5166 CFG80211_PUT_BSS(wiphy
, bss
);
5171 err
= wl_get_bandwidth_cap(dev
, CHSPEC_BAND(cfg
->channel
), &bw_cap
);
5172 if (unlikely(err
)) {
5173 WL_ERR(("Failed to get bandwidth capability (%d)\n", err
));
5176 chanspec
= wf_create_chspec_from_primary(wf_chspec_primary20_chan(cfg
->channel
),
5177 bw_cap
, CHSPEC_BAND(cfg
->channel
));
5181 * Join with specific BSSID and cached SSID
5182 * If SSID is zero join based on BSSID only
5184 bzero(&join_params
, sizeof(join_params
));
5185 memcpy((void *)join_params
.ssid
.SSID
, (const void *)params
->ssid
,
5187 join_params
.ssid
.SSID_len
= htod32(params
->ssid_len
);
5188 if (params
->bssid
) {
5189 memcpy(&join_params
.params
.bssid
, params
->bssid
, ETHER_ADDR_LEN
);
5190 err
= wldev_ioctl_set(dev
, WLC_SET_DESIRED_BSSID
, &join_params
.params
.bssid
,
5192 if (unlikely(err
)) {
5193 WL_ERR(("Error (%d)\n", err
));
5197 bzero(&join_params
.params
.bssid
, ETHER_ADDR_LEN
);
5199 if (IBSS_INITIAL_SCAN_ALLOWED
== FALSE
) {
5200 scan_suppress
= TRUE
;
5201 /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
5202 err
= wldev_ioctl_set(dev
, WLC_SET_SCANSUPPRESS
,
5203 &scan_suppress
, sizeof(int));
5204 if (unlikely(err
)) {
5205 WL_ERR(("Scan Suppress Setting Failed (%d)\n", err
));
5210 join_params
.params
.chanspec_list
[0] = chanspec
;
5211 join_params
.params
.chanspec_num
= 1;
5212 wldev_iovar_setint(dev
, "chanspec", chanspec
);
5213 join_params_size
= sizeof(join_params
);
5215 /* Disable Authentication, IBSS will add key if it required */
5216 wldev_iovar_setint(dev
, "wpa_auth", WPA_AUTH_DISABLED
);
5217 wldev_iovar_setint(dev
, "wsec", 0);
5219 err
= wldev_ioctl_set(dev
, WLC_SET_SSID
, &join_params
,
5221 if (unlikely(err
)) {
5222 WL_ERR(("IBSS set_ssid Error (%d)\n", err
));
5226 if (IBSS_INITIAL_SCAN_ALLOWED
== FALSE
) {
5227 scan_suppress
= FALSE
;
5228 /* Reset the SCAN SUPPRESS Flag */
5229 err
= wldev_ioctl_set(dev
, WLC_SET_SCANSUPPRESS
,
5230 &scan_suppress
, sizeof(int));
5231 if (unlikely(err
)) {
5232 WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err
));
5236 wl_update_prof(cfg
, dev
, NULL
, &join_params
.ssid
, WL_PROF_SSID
);
5237 wl_update_prof(cfg
, dev
, NULL
, &cfg
->channel
, WL_PROF_CHAN
);
5239 cfg
->aibss_txfail_seq
= 0; /* initialize the sequence */
5240 #endif /* WLAIBSS */
5242 cfg
->rmc_event_seq
= 0; /* initialize rmcfail sequence */
5243 #endif /* WL_RELMCAST */
5247 static s32
wl_cfg80211_leave_ibss(struct wiphy
*wiphy
, struct net_device
*dev
)
5249 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
5254 RETURN_EIO_IF_NOT_UP(cfg
);
5257 WL_INFORM_MEM(("Leave IBSS\n"));
5258 curbssid
= wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
5259 wl_set_drv_status(cfg
, DISCONNECTING
, dev
);
5261 memcpy(&scbval
.ea
, curbssid
, ETHER_ADDR_LEN
);
5262 err
= wldev_ioctl_set(dev
, WLC_DISASSOC
, &scbval
,
5264 if (unlikely(err
)) {
5265 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
5266 WL_ERR(("error(%d)\n", err
));
5270 /* remove the VSIE */
5271 wl_cfg80211_ibss_vsie_delete(dev
);
5278 int wl_cfg80211_get_rsn_capa(const bcm_tlv_t
*wpa2ie
,
5282 const wpa_suite_mcast_t
*mcast
;
5283 const wpa_suite_ucast_t
*ucast
;
5285 const wpa_suite_auth_key_mgmt_t
*mgmt
;
5292 /* check for Multicast cipher suite */
5293 if ((len
-= (WPA_SUITE_LEN
+ WPA2_VERSION_LEN
)) <= 0) {
5294 return BCME_NOTFOUND
;
5297 mcast
= (const wpa_suite_mcast_t
*)&wpa2ie
->data
[WPA2_VERSION_LEN
];
5299 /* Check for the unicast suite(s) */
5300 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
5301 return BCME_NOTFOUND
;
5304 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
5305 suite_count
= ltoh16_ua(&ucast
->count
);
5306 if ((suite_count
> NL80211_MAX_NR_CIPHER_SUITES
) ||
5307 (len
-= (WPA_IE_SUITE_COUNT_LEN
+
5308 (WPA_SUITE_LEN
* suite_count
))) <= 0)
5311 /* Check for AUTH key management suite(s) */
5312 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
5313 return BCME_NOTFOUND
;
5316 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[suite_count
];
5317 suite_count
= ltoh16_ua(&mgmt
->count
);
5319 if ((suite_count
<= NL80211_MAX_NR_CIPHER_SUITES
) &&
5320 (len
-= (WPA_IE_SUITE_COUNT_LEN
+
5321 (WPA_SUITE_LEN
* suite_count
))) >= RSN_CAP_LEN
) {
5322 rsn_cap
[0] = (const u8
*)&mgmt
->list
[suite_count
];
5332 wl_set_wpa_version(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
5334 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5335 struct wl_security
*sec
;
5340 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5341 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5345 if (sme
->crypto
.wpa_versions
& NL80211_WPA_VERSION_1
)
5346 val
= WPA_AUTH_PSK
|
5347 WPA_AUTH_UNSPECIFIED
;
5348 else if (sme
->crypto
.wpa_versions
& NL80211_WPA_VERSION_2
)
5349 val
= WPA2_AUTH_PSK
|
5350 WPA2_AUTH_UNSPECIFIED
;
5352 val
= WPA_AUTH_DISABLED
;
5354 if (is_wps_conn(sme
))
5355 val
= WPA_AUTH_DISABLED
;
5358 if (sme
->crypto
.wpa_versions
& NL80211_WAPI_VERSION_1
) {
5359 WL_DBG((" * wl_set_wpa_version, set wpa_auth"
5360 " to WPA_AUTH_WAPI 0x400"));
5361 val
= WAPI_AUTH_PSK
| WAPI_AUTH_UNSPECIFIED
;
5365 WL_DBG_MEM(("[%s] wl wpa_auth 0x%0x\n", dev
->name
, val
));
5366 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", val
, bssidx
);
5367 if (unlikely(err
)) {
5368 WL_ERR(("set wpa_auth failed (%d)\n", err
));
5371 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
5372 sec
->wpa_versions
= sme
->crypto
.wpa_versions
;
5378 wl_set_set_wapi_ie(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
5380 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5384 WL_DBG((" wl_set_set_wapi_ie\n"));
5385 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5386 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5390 err
= wldev_iovar_setbuf_bsscfg(dev
, "wapiie", (const void *)sme
->ie
, sme
->ie_len
,
5391 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
5392 if (unlikely(err
)) {
5393 WL_ERR(("set_wapi_ie Error (%d)\n", err
));
5396 WL_DBG_MEM(("wapi_ie successfully (%s)\n", dev
->name
));
5399 #endif /* BCMWAPI_WPI */
5402 wl_set_auth_type(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
5404 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5405 struct wl_security
*sec
;
5410 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5411 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5415 switch (sme
->auth_type
) {
5416 case NL80211_AUTHTYPE_OPEN_SYSTEM
:
5417 val
= WL_AUTH_OPEN_SYSTEM
;
5418 WL_DBG(("open system\n"));
5420 case NL80211_AUTHTYPE_SHARED_KEY
:
5421 val
= WL_AUTH_SHARED_KEY
;
5422 WL_DBG(("shared key\n"));
5424 case NL80211_AUTHTYPE_AUTOMATIC
:
5425 val
= WL_AUTH_OPEN_SHARED
;
5426 WL_DBG(("automatic\n"));
5429 case NL80211_AUTHTYPE_FILS_SK
:
5430 WL_DBG(("fils shared key\n"));
5431 val
= WL_AUTH_FILS_SHARED
;
5433 case NL80211_AUTHTYPE_FILS_SK_PFS
:
5434 val
= WL_AUTH_FILS_SHARED_PFS
;
5435 WL_DBG(("fils shared key with pfs\n"));
5437 case NL80211_AUTHTYPE_FILS_PK
:
5438 WL_DBG(("fils public key\n"));
5439 val
= WL_AUTH_FILS_PUBLIC
;
5441 #endif /* WL_FILS */
5442 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
5443 case NL80211_AUTHTYPE_SAE
:
5444 if (!wl_is_pmkid_available(dev
, sme
->bssid
)) {
5445 val
= WL_AUTH_SAE_KEY
;
5447 /* Fw will choose right auth type
5448 * dynamically based on PMKID availability
5450 val
= WL_AUTH_OPEN_SHARED
;
5452 WL_DBG(("sae auth type %d\n", val
));
5454 #endif /* WL_SAE || WL_CLIENT_SAE */
5457 WL_ERR(("invalid auth type (%d)\n", sme
->auth_type
));
5461 WL_DBG_MEM(("[%s] wl auth 0x%0x \n", dev
->name
, val
));
5462 err
= wldev_iovar_setint_bsscfg(dev
, "auth", val
, bssidx
);
5463 if (unlikely(err
)) {
5464 WL_ERR(("set auth failed (%d)\n", err
));
5467 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
5468 sec
->auth_type
= sme
->auth_type
;
5473 #ifdef WL_CLIENT_SAE
5475 wl_is_pmkid_available(struct net_device
*dev
, const u8
*bssid
)
5477 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5479 int npmkids
= (cfg
->pmk_list
->pmkids
.length
- sizeof(uint16
)*2) / sizeof(pmkid_v2_t
);
5481 /* check the bssid is null or not */
5482 if (!bssid
) return FALSE
;
5484 for (i
= 0; i
< npmkids
; i
++) {
5485 if (!memcmp(bssid
, &cfg
->pmk_list
->pmkids
.pmkid
[i
].bssid
, ETHER_ADDR_LEN
)) {
5486 WL_DBG(("FOUND PMKID\n"));
5490 WL_ERR(("PMKID NOT FOUND\n"));
5493 #endif /* WL_CLIENT_SAE */
5496 wl_rsn_cipher_wsec_algo_lookup(uint32 cipher
)
5500 for (i
= 0; i
< ARRAYSIZE(rsn_cipher_algo_lookup_tbl
); i
++) {
5501 if (cipher
== rsn_cipher_algo_lookup_tbl
[i
].cipher_suite
) {
5502 return rsn_cipher_algo_lookup_tbl
[i
].wsec_algo
;
5509 wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher
)
5513 for (i
= 0; i
< ARRAYSIZE(rsn_cipher_algo_lookup_tbl
); i
++) {
5514 if (cipher
== rsn_cipher_algo_lookup_tbl
[i
].cipher_suite
) {
5515 return rsn_cipher_algo_lookup_tbl
[i
].wsec_key_algo
;
5518 return CRYPTO_ALGO_OFF
;
5522 wl_rsn_akm_wpa_auth_lookup(uint32 akm
)
5526 for (i
= 0; i
< ARRAYSIZE(rsn_akm_wpa_auth_lookup_tbl
); i
++) {
5527 if (akm
== rsn_akm_wpa_auth_lookup_tbl
[i
].akm_suite
) {
5528 return rsn_akm_wpa_auth_lookup_tbl
[i
].wpa_auth
;
5531 return WPA_AUTH_DISABLED
;
5535 wl_set_set_cipher(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
5537 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5538 struct wl_security
*sec
;
5551 uint32 algos
= 0, mask
= 0;
5552 #endif /* WL_GCMP */
5554 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5555 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5559 if (sme
->crypto
.n_ciphers_pairwise
) {
5560 pval
= wl_rsn_cipher_wsec_algo_lookup(sme
->crypto
.ciphers_pairwise
[0]);
5561 if (pval
== WSEC_NONE
) {
5562 WL_ERR(("Invalid cipher (0x%x)\n",
5563 sme
->crypto
.ciphers_pairwise
[0]));
5566 switch (sme
->crypto
.ciphers_pairwise
[0]) {
5569 case WLAN_CIPHER_SUITE_SMS4
:
5571 err
= wl_set_set_wapi_ie(dev
, sme
);
5572 if (unlikely(err
)) {
5573 WL_DBG(("Set wapi ie failed \n"));
5576 WL_DBG(("Set wapi ie succeded\n"));
5578 wapi_val
= WAPI_AUTH_PSK
| WAPI_AUTH_UNSPECIFIED
;
5579 WL_DBG_MEM(("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val
, dev
->name
));
5580 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wapi_val
, bssidx
);
5581 if (unlikely(err
)) {
5582 WL_ERR(("set wpa_auth failed (%d)\n", err
));
5586 #endif /* BCMWAPI_WPI */
5589 case WLAN_CIPHER_SUITE_GCMP
:
5590 case WLAN_CIPHER_SUITE_GCMP_256
:
5591 algos
= KEY_ALGO_MASK(wl_rsn_cipher_wsec_key_algo_lookup(
5592 sme
->crypto
.ciphers_pairwise
[0]));
5593 mask
= algos
| KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM
);
5595 #endif /* WL_GCMP */
5596 default: /* No post processing required */
5600 #if defined(BCMSUP_4WAY_HANDSHAKE)
5601 /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
5603 * Note that the FW feature flag only exists on kernels that support the
5606 if (cfg
->wdev
->wiphy
->features
& NL80211_FEATURE_FW_4WAY_HANDSHAKE
) {
5607 err
= wldev_iovar_setint_bsscfg(dev
, "sup_wpa", 1, bssidx
);
5609 WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err
));
5612 WL_INFORM_MEM(("idsup enabled.\n"));
5615 #endif /* BCMSUP_4WAY_HANDSHAKE */
5616 if (sme
->crypto
.cipher_group
) {
5617 gval
= wl_rsn_cipher_wsec_algo_lookup(sme
->crypto
.cipher_group
);
5618 if (gval
== WSEC_NONE
) {
5619 WL_ERR(("invalid cipher group (0x%x)\n", sme
->crypto
.cipher_group
));
5622 switch (sme
->crypto
.cipher_group
) {
5625 case WLAN_CIPHER_SUITE_SMS4
:
5631 case WLAN_CIPHER_SUITE_GCMP
:
5632 case WLAN_CIPHER_SUITE_GCMP_256
:
5633 algos
= KEY_ALGO_MASK(
5634 wl_rsn_cipher_wsec_key_algo_lookup(sme
->crypto
.cipher_group
));
5635 mask
= algos
| KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM
);
5637 #endif /* WL_GCMP */
5638 default: /* No post processing required */
5643 WL_DBG(("pval (%d) gval (%d)\n", pval
, gval
));
5645 WL_DBG(("algos:%x, mask:%x", algos
, mask
));
5646 #endif /* WL_GCMP */
5648 if (is_wps_conn(sme
)) {
5652 /* WPS-2.0 allows no security */
5658 if (sme
->crypto
.cipher_group
== WLAN_CIPHER_SUITE_SMS4
) {
5659 WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
5665 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
5666 wsec_val
= pval
| gval
;
5670 WL_DBG_MEM(("[%s] wl wsec 0x%x\n", dev
->name
, wsec_val
));
5671 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec_val
, bssidx
);
5672 if (unlikely(err
)) {
5673 WL_ERR(("error (%d)\n", err
));
5677 if (wl_set_wsec_info_algos(dev
, algos
, mask
)) {
5678 WL_ERR(("set wsec_info error (%d)\n", err
));
5680 #endif /* WL_GCMP */
5681 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
5682 sec
->cipher_pairwise
= sme
->crypto
.ciphers_pairwise
[0];
5683 sec
->cipher_group
= sme
->crypto
.cipher_group
;
5684 sec
->fw_wsec
= wsec_val
;
5689 wl_set_wsec_info_algos(struct net_device
*dev
, uint32 algos
, uint32 mask
)
5691 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5694 wl_wsec_info_t
*wsec_info
;
5695 bcm_xtlv_t
*wsec_info_tlv
;
5696 uint16 tlv_data_len
;
5701 WL_DBG(("enter.\n"));
5705 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5706 WL_ERR(("Find index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5710 buf
= MALLOCZ(cfg
->osh
, sizeof(wl_wsec_info_t
) + sizeof(tlv_data
));
5712 WL_ERR(("No memory"));
5715 wsec_info
= (wl_wsec_info_t
*)buf
;
5716 wsec_info
->version
= WL_WSEC_INFO_VERSION
;
5717 wsec_info_tlv
= (bcm_xtlv_t
*)(buf
+ OFFSETOF(wl_wsec_info_t
, tlvs
));
5719 wsec_info
->num_tlvs
++;
5720 tlv_data_len
= sizeof(tlv_data
);
5721 tlv_data
[0] = algos
;
5724 bcm_xtlv_pack_xtlv(wsec_info_tlv
, WL_WSEC_INFO_BSS_ALGOS
, tlv_data_len
,
5725 (const uint8
*)tlv_data
, 0);
5726 param_len
= OFFSETOF(wl_wsec_info_t
, tlvs
) + WL_WSEC_INFO_TLV_HDR_LEN
+ tlv_data_len
;
5728 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_info", wsec_info
, param_len
,
5729 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
5731 MFREE(cfg
->osh
, buf
, sizeof(wl_wsec_info_t
) + sizeof(tlv_data
));
5734 #endif /* WL_GCMP */
5738 wl_cfg80211_set_wsec_info(struct net_device
*dev
, uint32
*data
,
5739 uint16 data_len
, int tag
)
5741 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5744 wl_wsec_info_t
*wsec_info
;
5745 bcm_xtlv_t
*bcm_info_tlv
;
5753 if (data_len
> WLC_IOCTL_SMLEN
) {
5758 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5759 WL_ERR(("Find index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5764 buf
= MALLOCZ(cfg
->osh
, sizeof(wl_wsec_info_t
) + data_len
);
5766 WL_ERR(("No memory"));
5771 wsec_info
= (wl_wsec_info_t
*)buf
;
5772 bzero(wsec_info
, sizeof(wl_wsec_info_t
) + data_len
);
5773 wsec_info
->version
= WL_WSEC_INFO_VERSION
;
5774 bcm_info_tlv
= (bcm_xtlv_t
*)(buf
+ OFFSETOF(wl_wsec_info_t
, tlvs
));
5776 wsec_info
->num_tlvs
++;
5778 bcm_xtlv_pack_xtlv(bcm_info_tlv
, tag
, data_len
, (const u8
*)data
, 0);
5779 param_len
= OFFSETOF(wl_wsec_info_t
, tlvs
) + WL_WSEC_INFO_TLV_HDR_LEN
+ data_len
;
5781 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_info", wsec_info
, param_len
,
5782 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
5783 if (unlikely(err
)) {
5784 WL_ERR(("set wsec_info error (%d)\n", err
));
5789 MFREE(cfg
->osh
, buf
, sizeof(wl_wsec_info_t
) + data_len
);
5796 wl_cfg80211_set_mfp(struct bcm_cfg80211
*cfg
,
5797 struct net_device
*dev
,
5798 struct cfg80211_connect_params
*sme
)
5800 s32 mfp
= WL_MFP_NONE
;
5801 s32 current_mfp
= WL_MFP_NONE
;
5802 const bcm_tlv_t
*wpa2_ie
;
5803 const u8
* rsn_cap
= NULL
;
5804 bool fw_support
= false;
5806 const u8
*eptr
= NULL
, *ptr
= NULL
;
5807 const u8
* group_mgmt_cs
= NULL
;
5808 const wpa_pmkid_list_t
* pmkid
= NULL
;
5809 struct wl_security
*sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
5812 /* No connection params from userspace, Do nothing. */
5816 /* Check fw support and retreive current mfp val */
5817 err
= wldev_iovar_getint(dev
, "mfp", ¤t_mfp
);
5822 /* Parse the wpa2ie to decode the MFP capablity */
5823 if (((wpa2_ie
= bcm_parse_tlvs((const u8
*)sme
->ie
, sme
->ie_len
,
5824 DOT11_MNG_RSN_ID
)) != NULL
) &&
5825 (wl_cfg80211_get_rsn_capa(wpa2_ie
, &rsn_cap
) == 0) && rsn_cap
) {
5826 WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap
[0], rsn_cap
[1]));
5827 /* Check for MFP cap in the RSN capability field */
5828 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
5832 if (rsn_cap
[0] & RSN_CAP_MFPR
) {
5833 mfp
= WL_MFP_REQUIRED
;
5834 } else if (rsn_cap
[0] & RSN_CAP_MFPC
) {
5835 mfp
= WL_MFP_CAPABLE
;
5839 * eptr --> end/last byte addr of wpa2_ie
5840 * ptr --> to keep track of current/required byte addr
5842 eptr
= (const u8
*)wpa2_ie
+ (wpa2_ie
->len
+ TLV_HDR_LEN
);
5843 /* pointing ptr to the next byte after rns_cap */
5844 ptr
= (const u8
*)rsn_cap
+ RSN_CAP_LEN
;
5845 if (mfp
&& (eptr
- ptr
) >= WPA2_PMKID_COUNT_LEN
) {
5846 /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
5847 pmkid
= (const wpa_pmkid_list_t
*)ptr
;
5848 count
= pmkid
->count
.low
| (pmkid
->count
.high
<< 8);
5849 /* ptr now to point to last byte addr of pmkid */
5850 ptr
= (const u8
*)pmkid
+ (count
* WPA2_PMKID_LEN
5851 + WPA2_PMKID_COUNT_LEN
);
5852 if ((eptr
- ptr
) >= WPA_SUITE_LEN
) {
5853 /* group_mgmt_cs now to point to first byte addr of bip */
5854 group_mgmt_cs
= ptr
;
5859 WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n",
5860 mfp
, wpa2_ie
, fw_support
));
5862 if (fw_support
== false) {
5863 if (mfp
== WL_MFP_REQUIRED
) {
5864 /* if mfp > 0, mfp capability set in wpa ie, but
5865 * FW indicated error for mfp. Propagate the error up.
5867 WL_ERR(("mfp capability found in wpaie. But fw doesn't "
5868 "seem to support MFP\n"));
5872 /* Firmware doesn't support mfp. But since connection request
5873 * is for non-mfp case, don't bother.
5878 } else if (mfp
!= current_mfp
) {
5879 /* Some FW brances report error (-5) during MFP set if the BSS
5880 * is up (roam case). Typically in roaming cases, the MFP
5881 * configuration doesn't change. So in roam/reassoc cases, there is
5882 * no need to update the fw state. If we still hit corner cases
5883 * throwing (-5) error, we need to pull in RB:59117.
5885 err
= wldev_iovar_setint(dev
, "mfp", mfp
);
5886 if (unlikely(err
)) {
5887 WL_ERR(("mfp (%d) set failed ret:%d \n", mfp
, err
));
5890 WL_DBG_MEM(("[%s] wl mfp 0x%x\n", dev
->name
, mfp
));
5897 if (group_mgmt_cs
&& bcmp((const uint8
*)WPA2_OUI
,
5898 group_mgmt_cs
, (WPA_SUITE_LEN
- 1)) == 0) {
5899 WL_DBG(("BIP is found\n"));
5900 err
= wldev_iovar_setbuf(dev
, "bip",
5901 group_mgmt_cs
, WPA_SUITE_LEN
, cfg
->ioctl_buf
,
5902 WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
5904 * Dont return failure for unsupported cases
5905 * of bip iovar for backward compatibility
5907 if (err
!= BCME_UNSUPPORTED
&& err
< 0) {
5908 WL_ERR(("bip set error (%d)\n", err
));
5914 WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n",
5915 dev
->name
, group_mgmt_cs
[0], group_mgmt_cs
[1],
5921 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg
),
5922 FW_LOGSET_MASK_ALL
);
5931 wl_is_fils_supported(struct net_device
*ndev
)
5934 u8 ioctl_buf
[WLC_IOCTL_SMLEN
] = {0};
5935 bcm_iov_buf_t
*iov_buf
= (bcm_iov_buf_t
*)ioctl_buf
;
5937 iov_buf
->version
= WL_FILS_IOV_VERSION
;
5938 err
= wldev_iovar_getbuf(ndev
, "fils", (uint8
*)iov_buf
, sizeof(bcm_iov_buf_t
),
5939 iov_buf
, WLC_IOCTL_SMLEN
, NULL
);
5940 if (err
== BCME_UNSUPPORTED
) {
5941 WL_DBG(("FILS NOT supported\n"));
5945 WL_INFORM(("FILS supported\n"));
5949 #define WL_NUM_OF_TLV_IN_SET_FILS_PARAMS 4u
5951 wl_set_fils_params(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
5953 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5954 bcm_iov_buf_t
*iov_buf
= NULL
;
5959 if ((sme
->auth_type
!= NL80211_AUTHTYPE_FILS_SK
) &&
5960 (sme
->auth_type
!= NL80211_AUTHTYPE_FILS_SK_PFS
) &&
5961 (sme
->auth_type
!= NL80211_AUTHTYPE_FILS_PK
)) {
5964 if (sme
->fils_erp_rrk_len
> WL_MAX_FILS_KEY_LEN
) {
5965 WL_ERR(("%s: FILS rRK exceed allowed size\n", __FUNCTION__
));
5969 /* Check incoming buffer length */
5970 buf_size
= sme
->fils_erp_username_len
+ sme
->fils_erp_realm_len
+ sme
->fils_erp_rrk_len
+
5971 sizeof(sme
->fils_erp_next_seq_num
) +
5972 WL_NUM_OF_TLV_IN_SET_FILS_PARAMS
* BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32
) +
5973 sizeof(bcm_iov_buf_t
) - 1u;
5975 if (buf_size
> WLC_IOCTL_SMLEN
) {
5976 WL_ERR(("%s: FILS connect params arguments exceed allowed size\n", __FUNCTION__
));
5980 iov_buf
= MALLOCZ(cfg
->osh
, WLC_IOCTL_SMLEN
);
5982 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__
, WLC_IOCTL_SMLEN
));
5986 iov_buf
->version
= WL_FILS_IOV_VERSION
;
5987 iov_buf
->id
= WL_FILS_CMD_ADD_CONNECT_PARAMS
;
5988 /* check if this should be len w/o headers */
5989 err
= bcm_xtlv_buf_init(&tbuf
, (uint8
*)&iov_buf
->data
[0],
5990 WLC_IOCTL_SMLEN
- sizeof(bcm_iov_buf_t
) + sizeof(uint16
),
5991 BCM_XTLV_OPTION_ALIGN32
);
5992 if (err
!= BCME_OK
) {
5993 WL_ERR(("%s: xtlv_context initialization failed\n", __FUNCTION__
));
5996 if (sme
->fils_erp_username_len
&& sme
->fils_erp_username
!= NULL
) {
5997 err
= bcm_xtlv_put_data(&tbuf
, WL_FILS_XTLV_ERP_USERNAME
,
5998 sme
->fils_erp_username
, sme
->fils_erp_username_len
);
5999 if (err
!= BCME_OK
) {
6000 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__
));
6004 if (sme
->fils_erp_realm_len
&& sme
->fils_erp_realm
!= NULL
) {
6005 err
= bcm_xtlv_put_data(&tbuf
, WL_FILS_XTLV_ERP_REALM
,
6006 sme
->fils_erp_realm
, sme
->fils_erp_realm_len
);
6007 if (err
!= BCME_OK
) {
6008 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__
));
6012 if (sme
->fils_erp_rrk_len
&& sme
->fils_erp_rrk
!= NULL
) {
6013 err
= bcm_xtlv_put_data(&tbuf
, WL_FILS_XTLV_ERP_RRK
,
6014 sme
->fils_erp_rrk
, sme
->fils_erp_rrk_len
);
6015 if (err
!= BCME_OK
) {
6016 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__
));
6020 err
= bcm_xtlv_put_data(&tbuf
, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM
,
6021 (u8
*)&sme
->fils_erp_next_seq_num
, sizeof(sme
->fils_erp_next_seq_num
));
6022 if (err
!= BCME_OK
) {
6023 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__
));
6026 iov_buf
->len
= bcm_xtlv_buf_len(&tbuf
);
6027 err
= wldev_iovar_setbuf(dev
, "fils", iov_buf
, iov_buf
->len
+ sizeof(bcm_iov_buf_t
) -
6028 sizeof(uint16
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
6029 if (unlikely(err
)) {
6030 WL_ERR(("set fils params ioctl error (%d)\n", err
));
6035 if (err
!= BCME_OK
) {
6036 WL_ERR(("set FILS params error %d\n", err
));
6039 WL_DBG_MEM(("FILS parameters succesfully applied\n"));
6042 MFREE(cfg
->osh
, iov_buf
, WLC_IOCTL_SMLEN
);
6047 #if !defined(WL_FILS_ROAM_OFFLD) && defined(WL_FILS)
6049 wl_get_bcn_timeout(struct net_device
*dev
, u32
*bcn_timeout
)
6053 err
= wldev_iovar_getint(dev
, "bcn_timeout", bcn_timeout
);
6054 if (unlikely(err
)) {
6055 WL_ERR(("could not get bcn_timeout (%d)\n", err
));
6060 #define WL_ROAM_ENABLE 0
6061 #define WL_ROAM_DISABLE 1
6062 /* Beacon Timeout beacon loss in case FILS roaming offload is not supported by fw */
6063 #define WL_BCN_TIMEOUT 3
6066 wl_fils_toggle_roaming(struct net_device
*dev
, u32 auth_type
)
6069 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
6071 if (WPA2_AUTH_IS_FILS(auth_type
) && !cfg
->fils_info
.fils_roam_disabled
) {
6072 err
= wl_get_bcn_timeout(dev
, &cfg
->fils_info
.fils_bcn_timeout_cache
);
6073 if (unlikely(err
)) {
6076 wl_dongle_roam(dev
, WL_ROAM_DISABLE
, WL_BCN_TIMEOUT
);
6077 cfg
->fils_info
.fils_roam_disabled
= true;
6078 WL_DBG_MEM(("fw roam disabled for FILS akm\n"));
6079 } else if (cfg
->fils_info
.fils_roam_disabled
) {
6080 /* Enable roaming back for other auth types */
6081 wl_dongle_roam(dev
, WL_ROAM_ENABLE
, cfg
->fils_info
.fils_bcn_timeout_cache
);
6082 cfg
->fils_info
.fils_roam_disabled
= false;
6083 WL_DBG_MEM(("fw roam enabled\n"));
6087 #endif /* !WL_FILS_ROAM_OFFLD && WL_FILS */
6088 #endif /* WL_FILS */
6091 wl_set_key_mgmt(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
6093 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
6094 struct wl_security
*sec
;
6099 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
6100 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
6104 if (sme
->crypto
.n_akm_suites
) {
6105 err
= wldev_iovar_getint(dev
, "wpa_auth", &val
);
6106 if (unlikely(err
)) {
6107 WL_ERR(("could not get wpa_auth (%d)\n", err
));
6110 if (val
& (WPA_AUTH_PSK
|
6111 WPA_AUTH_UNSPECIFIED
)) {
6112 switch (sme
->crypto
.akm_suites
[0]) {
6113 case WLAN_AKM_SUITE_8021X
:
6114 val
= WPA_AUTH_UNSPECIFIED
;
6116 case WLAN_AKM_SUITE_PSK
:
6120 WL_ERR(("invalid akm suite (0x%x)\n",
6121 sme
->crypto
.akm_suites
[0]));
6124 } else if (val
& (WPA2_AUTH_PSK
|
6125 WPA2_AUTH_UNSPECIFIED
)) {
6126 switch (sme
->crypto
.akm_suites
[0]) {
6129 case WL_AKM_SUITE_SHA256_1X
:
6130 val
= WPA2_AUTH_1X_SHA256
;
6132 case WL_AKM_SUITE_SHA256_PSK
:
6133 val
= WPA2_AUTH_PSK_SHA256
;
6136 case WLAN_AKM_SUITE_8021X
:
6137 case WLAN_AKM_SUITE_PSK
:
6138 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
6139 case WLAN_AKM_SUITE_FT_8021X
:
6141 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
6142 case WLAN_AKM_SUITE_FT_PSK
:
6144 case WLAN_AKM_SUITE_FILS_SHA256
:
6145 case WLAN_AKM_SUITE_FILS_SHA384
:
6146 case WLAN_AKM_SUITE_8021X_SUITE_B
:
6147 case WLAN_AKM_SUITE_8021X_SUITE_B_192
:
6149 case WLAN_AKM_SUITE_OWE
:
6152 case WLAN_AKM_SUITE_FT_OVER_SAE
:
6153 #endif /* WL_SAE_FT */
6154 case WLAN_AKM_SUITE_DPP
:
6155 case WLAN_AKM_SUITE_FT_8021X_SHA384
:
6156 val
= wl_rsn_akm_wpa_auth_lookup(sme
->crypto
.akm_suites
[0]);
6158 case WLAN_AKM_SUITE_FT_FILS_SHA256
:
6159 val
= WPA2_AUTH_FILS_SHA256
| WPA2_AUTH_FT
;
6161 case WLAN_AKM_SUITE_FT_FILS_SHA384
:
6162 val
= WPA2_AUTH_FILS_SHA384
| WPA2_AUTH_FT
;
6164 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
6165 case WLAN_AKM_SUITE_SAE
:
6166 val
= WPA3_AUTH_SAE_PSK
;
6168 #endif /* WL_SAE || WL_CLIENT_SAE */
6170 WL_ERR(("invalid akm suite (0x%x)\n",
6171 sme
->crypto
.akm_suites
[0]));
6177 else if (val
& (WAPI_AUTH_PSK
| WAPI_AUTH_UNSPECIFIED
)) {
6178 switch (sme
->crypto
.akm_suites
[0]) {
6179 case WLAN_AKM_SUITE_WAPI_CERT
:
6180 val
= WAPI_AUTH_UNSPECIFIED
;
6182 case WLAN_AKM_SUITE_WAPI_PSK
:
6183 val
= WAPI_AUTH_PSK
;
6186 WL_ERR(("invalid akm suite (0x%x)\n",
6187 sme
->crypto
.akm_suites
[0]));
6194 #if !defined(WL_FILS_ROAM_OFFLD)
6195 err
= wl_fils_toggle_roaming(dev
, val
);
6196 if (unlikely(err
)) {
6199 #endif /* !WL_FILS_ROAM_OFFLD */
6200 #endif /* !WL_FILS */
6203 if ((err
= wl_cfg80211_set_mfp(cfg
, dev
, sme
)) < 0) {
6204 WL_ERR(("MFP set failed err:%d\n", err
));
6209 WL_DBG_MEM(("[%s] wl wpa_auth to 0x%x\n", dev
->name
, val
));
6210 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", val
, bssidx
);
6211 if (unlikely(err
)) {
6212 WL_ERR(("could not set wpa_auth (0x%x)\n", err
));
6216 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
6217 sec
->wpa_auth
= sme
->crypto
.akm_suites
[0];
6218 sec
->fw_wpa_auth
= val
;
6224 wl_set_set_sharedkey(struct net_device
*dev
,
6225 struct cfg80211_connect_params
*sme
)
6227 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
6228 struct wl_security
*sec
;
6229 struct wl_wsec_key key
;
6234 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
6235 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
6239 WL_DBG(("key len (%d)\n", sme
->key_len
));
6241 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
6242 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
6243 sec
->wpa_versions
, sec
->cipher_pairwise
));
6244 if (!(sec
->wpa_versions
& (NL80211_WPA_VERSION_1
|
6245 NL80211_WPA_VERSION_2
)) &&
6248 !is_wapi(sec
->cipher_pairwise
) &&
6251 (sec
->cipher_pairwise
& (WLAN_CIPHER_SUITE_WEP40
|
6252 WLAN_CIPHER_SUITE_WEP104
)))
6254 bzero(&key
, sizeof(key
));
6255 key
.len
= (u32
) sme
->key_len
;
6256 key
.index
= (u32
) sme
->key_idx
;
6257 if (unlikely(key
.len
> sizeof(key
.data
))) {
6258 WL_ERR(("Too long key length (%u)\n", key
.len
));
6261 memcpy(key
.data
, sme
->key
, key
.len
);
6262 key
.flags
= WL_PRIMARY_KEY
;
6263 if ((sec
->cipher_pairwise
== WLAN_CIPHER_SUITE_WEP40
) ||
6264 (sec
->cipher_pairwise
== WLAN_CIPHER_SUITE_WEP104
)) {
6265 key
.algo
= wl_rsn_cipher_wsec_key_algo_lookup(sec
->cipher_pairwise
);
6267 WL_ERR(("Invalid algorithm (%d)\n",
6268 sme
->crypto
.ciphers_pairwise
[0]));
6271 /* Set the new key/index */
6272 WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
6273 key
.len
, key
.index
, key
.algo
));
6274 WL_DBG(("key \"%s\"\n", key
.data
));
6275 swap_key_from_BE(&key
);
6276 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
),
6277 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
6278 if (unlikely(err
)) {
6279 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
6282 WL_INFORM_MEM(("key applied to fw\n"));
6283 if (sec
->auth_type
== NL80211_AUTHTYPE_SHARED_KEY
) {
6284 WL_DBG(("set auth_type to shared key\n"));
6285 val
= WL_AUTH_SHARED_KEY
; /* shared key */
6286 err
= wldev_iovar_setint_bsscfg(dev
, "auth", val
, bssidx
);
6287 if (unlikely(err
)) {
6288 WL_ERR(("set auth failed (%d)\n", err
));
6297 #if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
6298 static bool wl_get_chan_isvht80(struct net_device
*net
, dhd_pub_t
*dhd
)
6303 if (wldev_iovar_getint(net
, "chanspec", (s32
*)&chanspec
) == BCME_OK
)
6304 chanspec
= wl_chspec_driver_to_host(chanspec
);
6306 isvht80
= chanspec
& WL_CHANSPEC_BW_80
;
6307 WL_DBG(("wl_get_chan_isvht80: chanspec(%x:%d)\n", chanspec
, isvht80
));
6311 #endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
6313 int wl_cfg80211_cleanup_mismatch_status(struct net_device
*dev
, struct bcm_cfg80211
*cfg
,
6321 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
6322 BCM_REFERENCE(dhdp
);
6323 DHD_STATLOG_CTRL(dhdp
, ST(DISASSOC_INT_START
),
6324 dhd_net2idx(dhdp
->info
, dev
), DOT11_RC_DISASSOC_LEAVING
);
6325 WL_ERR(("Disassociate previous connection!\n"));
6326 wl_set_drv_status(cfg
, DISCONNECTING
, dev
);
6327 scbval
.val
= DOT11_RC_DISASSOC_LEAVING
;
6328 scbval
.val
= htod32(scbval
.val
);
6330 err
= wldev_ioctl_set(dev
, WLC_DISASSOC
, &scbval
,
6332 if (unlikely(err
)) {
6333 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
6334 WL_ERR(("error (%d)\n", err
));
6340 WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
6341 if (wl_get_drv_status(cfg
, DISCONNECTING
, dev
)) {
6342 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
6346 while (wl_get_drv_status(cfg
, DISCONNECTING
, dev
) && wait_cnt
) {
6347 WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
6353 if (wait_cnt
== 0) {
6354 WL_ERR(("DISCONNECING clean up failed!\n"));
6355 /* Clear DISCONNECTING driver status as we have made sufficient attempts
6356 * for driver clean up.
6358 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
6359 wl_clr_drv_status(cfg
, CONNECTED
, dev
);
6360 return BCME_NOTREADY
;
6367 wl_fils_add_hlp_container(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
6368 const uint8
* ie_buf
, uint16 ie_len
)
6370 const bcm_tlv_ext_t
*hlp_ie
;
6372 if ((hlp_ie
= (const bcm_tlv_ext_t
*)bcm_parse_tlvs_dot11((const uint8
*)ie_buf
, ie_len
,
6373 FILS_HLP_CONTAINER_EXT_ID
, TRUE
))) {
6374 u16 hlp_len
= hlp_ie
->len
;
6375 u16 left_len
= (ie_len
- ((const uint8
*)hlp_ie
- ie_buf
));
6376 bcm_iov_buf_t
*iov_buf
= 0;
6380 bcm_tlv_dot11_frag_tot_len(ie_buf
, ie_len
, FILS_HLP_CONTAINER_EXT_ID
,
6381 TRUE
, (uint
*)&hlp_len
);
6383 hlp_len
+= BCM_TLV_EXT_HDR_SIZE
;
6385 if ((hlp_len
> DOT11_MAX_MPDU_BODY_LEN
) || (hlp_len
> left_len
)) {
6386 WL_ERR(("bad HLP length %d\n", hlp_len
));
6389 iov_buf_len
= sizeof(bcm_iov_buf_t
) + sizeof(bcm_xtlv_t
) - 1 + hlp_len
;
6390 iov_buf
= MALLOCZ(cfg
->osh
, iov_buf_len
);
6391 if (iov_buf
== NULL
) {
6392 WL_ERR(("failed to allocated iov_buf\n"));
6396 prhex("HLP, HLP", (const uchar
*)hlp_ie
, hlp_len
);
6398 pxtlv
= (uint8
*)&iov_buf
->data
[0];
6399 ((bcm_xtlv_t
*)pxtlv
)->id
= WL_FILS_XTLV_HLP_IE
;
6400 ((bcm_xtlv_t
*)pxtlv
)->len
= hlp_len
;
6402 memcpy(((bcm_xtlv_t
*)pxtlv
)->data
, hlp_ie
, ((bcm_xtlv_t
*)pxtlv
)->len
);
6404 iov_buf
->version
= WL_FILS_IOV_VERSION
;
6405 iov_buf
->id
= WL_FILS_CMD_ADD_HLP_IE
;
6406 iov_buf
->len
= ((sizeof(bcm_xtlv_t
)-1) + ((bcm_xtlv_t
*)pxtlv
)->len
);
6408 err
= wldev_iovar_setbuf(dev
, "fils", iov_buf
,
6409 sizeof(bcm_iov_buf_t
) + iov_buf
->len
,
6410 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
6411 if (unlikely(err
)) {
6412 WL_ERR(("fils wldev_iovar_setbuf error (%d)\n", err
));
6415 WL_DBG_MEM(("FILS HLP Packet succesfully updated\n"));
6417 MFREE(cfg
->osh
, iov_buf
, iov_buf_len
);
6421 #endif /* WL_FILS */
6423 #if defined(WL_FILS)
6424 #ifndef UPDATE_FILS_ERP_INFO
6425 #define UPDATE_FILS_ERP_INFO BIT(1)
6426 #define UPDATE_AUTH_TYPE BIT(2)
6430 wl_cfg80211_update_connect_params(struct wiphy
*wiphy
, struct net_device
*dev
,
6431 struct cfg80211_connect_params
*sme
, u32 changed
)
6434 if (changed
& UPDATE_FILS_ERP_INFO
) {
6435 err
= wl_set_fils_params(dev
, sme
);
6437 if (unlikely(err
)) {
6438 WL_ERR(("Invalid FILS params\n"));
6442 if (changed
& UPDATE_AUTH_TYPE
) {
6443 err
= wl_set_auth_type(dev
, sme
);
6444 if (unlikely(err
)) {
6445 WL_ERR(("Invalid auth type\n"));
6449 if ((changed
& UPDATE_FILS_ERP_INFO
) && !(changed
& UPDATE_AUTH_TYPE
)) {
6450 WL_DBG(("Warning: FILS ERP params are set, but authentication type - not\n"));
6456 #endif /* WL_FILS */
6458 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6460 wl_config_roam_env_detection(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
6462 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
6463 s32 roam_trigger
[2] = {0, 0};
6466 if (dhdp
->roam_env_detection
&& (dev
== bcmcfg_to_prmry_ndev(cfg
))) {
6467 bool is_roamtrig_reset
= TRUE
;
6468 bool is_roam_env_ok
= (wldev_iovar_setint(dev
, "roam_env_detection",
6469 AP_ENV_DETECT_NOT_USED
) == BCME_OK
);
6470 #ifdef SKIP_ROAM_TRIGGER_RESET
6471 roam_trigger
[1] = WLC_BAND_2G
;
6473 (wldev_ioctl_get(dev
, WLC_GET_ROAM_TRIGGER
, roam_trigger
,
6474 sizeof(roam_trigger
)) == BCME_OK
) &&
6475 (roam_trigger
[0] == WL_AUTO_ROAM_TRIGGER
-10);
6476 #endif /* SKIP_ROAM_TRIGGER_RESET */
6477 if (is_roamtrig_reset
&& is_roam_env_ok
) {
6478 roam_trigger
[0] = WL_AUTO_ROAM_TRIGGER
;
6479 roam_trigger
[1] = WLC_BAND_ALL
;
6480 err
= wldev_ioctl_set(dev
, WLC_SET_ROAM_TRIGGER
, roam_trigger
,
6481 sizeof(roam_trigger
));
6482 if (unlikely(err
)) {
6483 WL_ERR((" failed to restore roam_trigger for auto env"
6484 " detection. err:%d\n", err
));
6490 #endif /* ROAM_ENABLE && ROAMENV_DETECTION */
6493 wl_do_preassoc_ops(struct bcm_cfg80211
*cfg
,
6494 struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
6496 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
6498 BCM_REFERENCE(dhdp
);
6499 DHD_STATLOG_CTRL(dhdp
, ST(ASSOC_START
), dhd_net2idx(dhdp
->info
, dev
), 0);
6501 #ifdef DHDTCPSYNC_FLOOD_BLK
6502 dhd_reset_tcpsync_info_by_dev(dev
);
6503 #endif /* DHDTCPSYNC_FLOOD_BLK */
6505 if (wl_get_drv_status(cfg
, SCANNING
, dev
)) {
6506 wl_cfg80211_cancel_scan(cfg
);
6509 #ifdef WL_SCHED_SCAN
6510 /* Locks are taken in wl_cfg80211_sched_scan_stop()
6511 * A start scan occuring during connect is unlikely
6513 if (cfg
->sched_scan_req
) {
6514 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
6515 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
6516 wl_cfg80211_sched_scan_stop(wdev
->wiphy
, bcmcfg_to_prmry_ndev(cfg
),
6517 cfg
->sched_scan_req
->reqid
);
6519 wl_cfg80211_sched_scan_stop(wdev
->wiphy
, bcmcfg_to_prmry_ndev(cfg
));
6520 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
6522 #endif /* WL_SCHED_SCAN */
6523 #ifdef WL_CFG80211_GON_COLLISION
6524 /* init block gon req count */
6525 cfg
->block_gon_req_tx_count
= 0;
6526 cfg
->block_gon_req_rx_count
= 0;
6527 #endif /* WL_CFG80211_GON_COLLISION */
6529 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
6533 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6534 if (wl_config_roam_env_detection(cfg
, dev
) != BCME_OK
) {
6537 #endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
6540 /* disable TDLS if number of connected interfaces is >= 1 */
6541 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_CONNECT
, false);
6544 #ifdef SUPPORT_AP_BWCTRL
6545 if (dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
6546 wl_restore_ap_bw(cfg
);
6548 #endif /* SUPPORT_AP_BWCTRL */
6549 #if defined(ROAMEXP_SUPPORT)
6550 /* Clear Blacklist bssid and Whitelist ssid list before join issue
6551 * This is temporary fix since currently firmware roaming is not
6552 * disabled by android framework before SSID join from framework
6554 /* Flush blacklist bssid content */
6555 dhd_dev_set_blacklist_bssid(dev
, NULL
, 0, true);
6556 /* Flush whitelist ssid content */
6557 dhd_dev_set_whitelist_ssid(dev
, NULL
, 0, true);
6558 #endif /* ROAMEXP_SUPPORT */
6560 WL_DBG(("SME IE : len=%zu\n", sme
->ie_len
));
6561 if (sme
->ie
!= NULL
&& sme
->ie_len
> 0 && (wl_dbg_level
& WL_DBG_DBG
)) {
6562 prhex(NULL
, sme
->ie
, sme
->ie_len
);
6564 /* Connection attempted via linux-wireless */
6565 wl_set_drv_status(cfg
, CFG80211_CONNECT
, dev
);
6570 wl_config_assoc_security(struct bcm_cfg80211
*cfg
,
6571 struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
6575 err
= wl_set_wpa_version(dev
, sme
);
6576 if (unlikely(err
)) {
6577 WL_ERR(("Invalid wpa_version\n"));
6582 if (sme
->crypto
.wpa_versions
& NL80211_WAPI_VERSION_1
) {
6583 WL_DBG(("skip auth type for wapi\n"));
6588 err
= wl_set_auth_type(dev
, sme
);
6589 if (unlikely(err
)) {
6590 WL_ERR(("Invalid auth type\n"));
6596 if (sme
->ie
&& sme
->ie_len
) {
6597 err
= wl_fils_add_hlp_container(cfg
, dev
, sme
->ie
, sme
->ie_len
);
6598 if (unlikely(err
)) {
6599 WL_ERR(("FILS sending HLP failed\n"));
6603 #endif /* WL_FILS */
6605 err
= wl_set_set_cipher(dev
, sme
);
6606 if (unlikely(err
)) {
6607 WL_ERR(("Invalid ciper\n"));
6611 err
= wl_set_key_mgmt(dev
, sme
);
6612 if (unlikely(err
)) {
6613 WL_ERR(("Invalid key mgmt\n"));
6617 err
= wl_set_set_sharedkey(dev
, sme
);
6618 if (unlikely(err
)) {
6619 WL_ERR(("Invalid shared key\n"));
6624 err
= wl_set_fils_params(dev
, sme
);
6625 if (unlikely(err
)) {
6626 WL_ERR(("Invalid FILS params\n"));
6629 #endif /* WL_FILS */
6636 wl_config_assoc_ies(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
6637 struct cfg80211_connect_params
*sme
, wlcfg_assoc_info_t
*info
)
6639 const wpa_ie_fixed_t
*wpa_ie
;
6640 const bcm_tlv_t
*wpa2_ie
;
6641 const u8
* wpaie
= 0;
6644 s32 bssidx
= info
->bssidx
;
6646 /* configure all vendor and extended vendor IEs */
6647 wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
6648 VNDR_IE_ASSOCREQ_FLAG
, sme
->ie
, sme
->ie_len
);
6650 /* Find the RSNXE_IE and plumb */
6651 if ((err
= wl_cfg80211_config_rsnxe_ie(cfg
, dev
,
6652 (const u8
*)sme
->ie
, sme
->ie_len
)) < 0) {
6653 WL_ERR(("Failed to configure rsnxe ie: %d\n", err
));
6657 /* find the RSN_IE */
6658 if ((wpa2_ie
= bcm_parse_tlvs((const u8
*)sme
->ie
, sme
->ie_len
,
6659 DOT11_MNG_RSN_ID
)) != NULL
) {
6660 WL_DBG((" RSN IE is found\n"));
6663 /* find the WPA_IE */
6664 if ((wpa_ie
= wl_cfgp2p_find_wpaie(sme
->ie
,
6665 sme
->ie_len
)) != NULL
) {
6666 WL_DBG((" WPA IE is found\n"));
6669 if (wpa_ie
!= NULL
|| wpa2_ie
!= NULL
) {
6670 wpaie
= (wpa_ie
!= NULL
) ? (const u8
*)wpa_ie
: (const u8
*)wpa2_ie
;
6671 wpaie_len
= (wpa_ie
!= NULL
) ? wpa_ie
->length
: wpa2_ie
->len
;
6672 wpaie_len
+= WPA_RSN_IE_TAG_FIXED_LEN
;
6678 err
= wldev_iovar_setbuf(dev
, "wpaie", wpaie
, wpaie_len
,
6679 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
6680 if (unlikely(err
)) {
6681 WL_ERR(("wpaie set error (%d)\n", err
));
6688 wl_cfg80211_config_rsnxe_ie(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
6689 const u8
*parse
, u32 len
)
6691 bcm_tlv_t
*ie
= NULL
;
6694 char smbuf
[WLC_IOCTL_SMLEN
];
6696 while ((ie
= bcm_parse_tlvs(parse
, len
, DOT11_MNG_RSNXE_ID
))) {
6697 WL_DBG(("Found RSNXE ie\n"));
6701 ie_len
= (ie
!= NULL
) ? (ie
->len
+ BCM_TLV_HDR_SIZE
): 0;
6703 err
= wldev_iovar_setbuf(dev
, "rsnxe", ie
, ie_len
,
6704 smbuf
, sizeof(smbuf
), NULL
);
6706 WL_DBG(("Configured RSNXE IE\n"));
6707 } else if (err
== BCME_UNSUPPORTED
) {
6708 WL_DBG(("FW does not support rsnxe iovar\n"));
6711 WL_ERR(("rsnxe set error (%d)\n", err
));
6717 wl_config_assoc_params(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
6718 wl_extjoin_params_t
*ext_join_params
,
6719 u32 buf_len
, wlcfg_assoc_info_t
*info
)
6722 chanspec_t
*chanspecs
= info
->chanspecs
;
6723 u32 chan_cnt
= info
->chan_cnt
;
6724 u32 join_scan_active_time
= 0;
6726 if (buf_len
< (sizeof(ext_join_params
->ssid
.SSID
) +
6727 (sizeof(chanspec_t
) * chan_cnt
))) {
6728 WL_ERR(("buf too short\n"));
6732 /* ssid length check is already done above */
6733 if (memcpy_s(ext_join_params
->ssid
.SSID
, sizeof(ext_join_params
->ssid
.SSID
),
6734 info
->ssid
, info
->ssid_len
) != BCME_OK
) {
6735 WL_ERR(("ssid cpy failed info_len:%d\n", info
->ssid_len
));
6739 ext_join_params
->ssid
.SSID_len
= info
->ssid_len
;
6740 wl_update_prof(cfg
, dev
, NULL
, &ext_join_params
->ssid
, WL_PROF_SSID
);
6741 if (ext_join_params
->ssid
.SSID_len
< IEEE80211_MAX_SSID_LEN
) {
6742 WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params
->ssid
.SSID
,
6743 ext_join_params
->ssid
.SSID_len
));
6745 ext_join_params
->ssid
.SSID_len
= htod32(info
->ssid_len
);
6747 /* Use increased dwell for targeted join case to take care of noisy env */
6748 join_scan_active_time
= info
->targeted_join
? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS
:
6749 WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS
;
6750 ext_join_params
->scan
.active_time
= chan_cnt
? join_scan_active_time
: -1;
6751 ext_join_params
->scan
.passive_time
= chan_cnt
? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS
: -1;
6752 /* Set up join scan parameters */
6753 ext_join_params
->scan
.scan_type
= -1;
6754 /* WAR to sync with presence period of VSDB GO.
6755 * send probe request more frequently
6756 * probe request will be stopped when it gets probe response from target AP/GO.
6758 ext_join_params
->scan
.nprobes
= chan_cnt
?
6759 (ext_join_params
->scan
.active_time
/WL_SCAN_JOIN_PROBE_INTERVAL_MS
) : -1;
6760 ext_join_params
->scan
.home_time
= -1;
6762 (void)memcpy_s(&ext_join_params
->assoc
.bssid
, ETH_ALEN
, info
->bssid
, ETH_ALEN
);
6764 ext_join_params
->assoc
.chanspec_num
= chan_cnt
;
6765 /* source and target lens are same */
6766 (void)memcpy_s(ext_join_params
->assoc
.chanspec_list
, (sizeof(chanspec_t
) * chan_cnt
),
6767 chanspecs
, sizeof(chanspec_t
) * chan_cnt
);
6769 ext_join_params
->assoc
.chanspec_num
= htod32(chan_cnt
);
6774 wl_handle_assoc_hints(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
6775 struct cfg80211_connect_params
*sme
, wlcfg_assoc_info_t
*info
)
6777 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6778 bool skip_hints
= false;
6779 #endif /* KERNEL >= 3.15 */
6782 if (!sme
|| !info
) {
6783 WL_ERR(("wrong args\n"));
6787 if (unlikely(!sme
->ssid
) || (sme
->ssid_len
> DOT11_MAX_SSID_LEN
)) {
6788 WL_ERR(("Invalid ssid %p. len:%zu\n", sme
->ssid
, sme
->ssid_len
));
6792 /* Copy SSID detail */
6793 info
->ssid_len
= sme
->ssid_len
;
6794 if (memcpy_s(info
->ssid
, sizeof(info
->ssid
),
6795 sme
->ssid
, info
->ssid_len
) != BCME_OK
) {
6796 WL_ERR(("ssid cpy failed\n"));
6800 /* Handle incoming BSSID and Channel info */
6801 if (sme
->bssid
&& !ETHER_ISBCAST(sme
->bssid
)) {
6802 /* Use user space requested BSSID and channel */
6803 info
->targeted_join
= true;
6804 (void)memcpy_s(info
->bssid
, ETH_ALEN
, sme
->bssid
, ETH_ALEN
);
6805 if (sme
->channel
&& ((chspec
=
6806 wl_freq_to_chanspec(sme
->channel
->center_freq
)) != INVCHANSPEC
)) {
6808 info
->chanspecs
[0] = chspec
;
6810 /* Skip p2p connection on 6G */
6811 if (IS_P2P_GC(dev
->ieee80211_ptr
) && (CHSPEC_IS6G(chspec
))) {
6812 WL_ERR(("P2P connection not allowed on 6G\n"));
6815 #endif /* WL_P2P_6G */
6818 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6820 #ifdef WL_SKIP_CONNECT_HINTS
6822 WL_DBG(("force skip connect hints\n"));
6823 #else /* WL_SKIP_CONNECT_HINTS */
6824 /* override bssid_hint if overridden via module param */
6825 skip_hints
= fw_ap_select
;
6826 #if defined(WL_FW_OCE_AP_SELECT)
6827 /* If fw select needs to be specifically done for OCE */
6828 skip_hints
= fw_ap_select
&&
6829 wl_cfg80211_is_oce_ap(wiphy
, sme
->bssid_hint
);
6830 #endif /* WL_FW_OCE_AP_SELECT */
6831 WL_DBG(("fw_ap_select:%d skip_hints:%d\n", fw_ap_select
, skip_hints
));
6832 #endif /* WL_SKIP_CONNECT_HINTS */
6834 /* Use bssid_hint if hints are allowed and if its unicast addr */
6835 if (!skip_hints
&& sme
->bssid_hint
&& !ETHER_ISBCAST(sme
->bssid_hint
)) {
6836 WL_INFORM_MEM(("bssid_hint "MACDBG
" \n", MAC2STRDBG(sme
->bssid_hint
)));
6837 info
->targeted_join
= true;
6838 (void)memcpy_s(info
->bssid
, ETH_ALEN
, sme
->bssid_hint
, ETH_ALEN
);
6839 /* Use channel hint only for target bssid join case. In other
6840 * cases, use RCC or full scan to find better APs.
6842 if (sme
->channel_hint
&& ((chspec
= wl_freq_to_chanspec(
6843 sme
->channel_hint
->center_freq
)) != INVCHANSPEC
)) {
6845 info
->chanspecs
[0] = chspec
;
6846 WL_INFORM_MEM(("channel_hint: chspec(%x)\n", chspec
));
6850 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6852 if (info
->targeted_join
!= true) {
6853 /* For non targeted join, use bcast address */
6854 (void)memcpy_s(&info
->bssid
, ETH_ALEN
, ðer_bcast
, ETH_ALEN
);
6856 WL_DBG(("targeted_join:%d chan_cnt:%d\n",
6857 info
->targeted_join
, info
->chan_cnt
));
6862 wl_sync_fw_assoc_states(struct bcm_cfg80211
*cfg
,
6863 struct net_device
*dev
, wlcfg_assoc_info_t
*info
)
6868 if (wl_get_drv_status(cfg
, CONNECTED
, dev
) && wl_reassoc_support
) {
6870 info
->reassoc
= true;
6872 /* store the bssid for the connect req */
6873 wl_update_prof(cfg
, dev
, NULL
, info
->bssid
, WL_PROF_LATEST_BSSID
);
6875 /* following scenarios are possible
6876 * In case of wrong request/abnormal status,
6877 * trigger DISASSOC to clean up status.
6878 * 1. DHD prev status is CONNECTING
6879 * => 1.1 Wrong request
6880 * 2. DHD previous status is CONNECTED
6883 * - FW not connected
6884 * => Abnormal status
6885 * 3. DHD previous status is DISCONNECTING
6886 * => Waiting for disconnecting
6887 * 4. DHD previous status is not connected
6888 * - FW not connected
6891 * => Abnormal status
6893 if (wl_get_drv_status(cfg
, CONNECTING
, dev
) ||
6894 wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
6895 /* set nested connect bit to identify the context */
6896 wl_set_drv_status(cfg
, NESTED_CONNECT
, dev
);
6897 /* DHD prev status is CONNECTING/CONNECTED */
6898 wl_cfg80211_cleanup_mismatch_status(dev
, cfg
, TRUE
);
6899 } else if (wl_get_drv_status(cfg
, DISCONNECTING
, dev
)) {
6900 /* DHD prev status is DISCONNECTING */
6901 wl_cfg80211_cleanup_mismatch_status(dev
, cfg
, false);
6902 } else if (!wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
6903 /* DHD previous status is not connected and FW connected */
6904 if (wldev_ioctl_get(dev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
) == 0) {
6905 /* set nested connect bit to identify the context */
6906 wl_set_drv_status(cfg
, NESTED_CONNECT
, dev
);
6907 wl_cfg80211_cleanup_mismatch_status(dev
, cfg
, true);
6910 wl_cfg80211_check_in4way(cfg
, dev
, WAIT_DISCONNECTED
,
6911 WL_EXT_STATUS_CONNECTING
, NULL
);
6914 /* Clear BSSID if disconnecting state is not in progress */
6915 bzero(&bssid
, sizeof(bssid
));
6916 if (!wl_get_drv_status(cfg
, DISCONNECTING
, dev
)) {
6917 wl_update_prof(cfg
, dev
, NULL
, (void *)&bssid
, WL_PROF_BSSID
);
6920 LOG_TS(cfg
, conn_start
);
6921 CLR_TS(cfg
, authorize_start
);
6922 /* clear nested connect bit on proceeding for connection */
6923 wl_clr_drv_status(cfg
, NESTED_CONNECT
, dev
);
6925 if (!info
->reassoc
) {
6926 /* 'connect' request received */
6927 wl_set_drv_status(cfg
, CONNECTING
, dev
);
6933 #if defined(DBG_PKT_MON)
6935 wl_pkt_mon_start(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
6937 if ((dev
== bcmcfg_to_prmry_ndev(cfg
))) {
6938 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
6939 DHD_DBG_PKT_MON_START(dhdp
);
6942 #endif /* DBG_PKT_MON && BCMDONGLEHOST */
6945 wl_conn_debug_info(struct bcm_cfg80211
*cfg
, struct net_device
*dev
, wlcfg_assoc_info_t
*info
)
6947 struct wl_security
*sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
6954 wl_ext_get_sec(dev
, 0, sec_info
, sizeof(sec_info
));
6955 WL_MSG(dev
->name
, "Connecting with " MACDBG
" ssid \"%s\", len (%d), "
6956 "channel=%d, sec=%s\n", MAC2STRDBG((u8
*)(&info
->bssid
)),
6957 info
->ssid
, info
->ssid_len
, info
->chan_cnt
, sec_info
);
6958 if (wl_dbg_level
& WL_DBG_DBG
) {
6959 WL_MSG(dev
->name
, "akm:0x%x auth:0x%x wpaver:0x%x pwise:0x%x gwise:0x%x\n",
6960 sec
->wpa_auth
, sec
->auth_type
, sec
->wpa_versions
,
6961 sec
->cipher_pairwise
, sec
->cipher_group
);
6962 WL_MSG(dev
->name
, "wpa_auth:0x%x auth:0x%x wsec:0x%x mfp:0x%x\n",
6963 sec
->fw_wpa_auth
, sec
->fw_auth
, sec
->fw_wsec
, sec
->fw_mfp
);
6964 /* print channels for assoc */
6965 prhex("chanspecs", (const u8
*)info
->chanspecs
,
6966 (info
->chan_cnt
* sizeof(chanspec_t
)));
6968 SUPP_LOG(("[%s] Connecting with " MACDBG
" ssid \"%s\",chan_cnt:%d\n",
6969 dev
->name
, MAC2STRDBG((u8
*)(&info
->bssid
)),
6970 info
->ssid
, info
->chan_cnt
));
6974 wl_handle_join(struct bcm_cfg80211
*cfg
,
6975 struct net_device
*dev
, wlcfg_assoc_info_t
*assoc_info
)
6978 wl_extjoin_params_t
*ext_join_params
;
6979 size_t join_params_size
;
6981 join_params_size
= WL_EXTJOIN_PARAMS_FIXED_SIZE
+
6982 assoc_info
->chan_cnt
* sizeof(chanspec_t
);
6983 ext_join_params
= (wl_extjoin_params_t
*)MALLOCZ(cfg
->osh
, join_params_size
);
6984 if (ext_join_params
== NULL
) {
6986 WL_ERR(("Mem alloc for join_params failed\n"));
6990 err
= wl_config_assoc_params(cfg
, dev
, ext_join_params
, join_params_size
,
6992 if (unlikely(err
)) {
6993 WL_ERR(("config assoc ies failed\n"));
6997 err
= wldev_iovar_setbuf_bsscfg(dev
, "join", ext_join_params
, join_params_size
,
6998 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, assoc_info
->bssidx
, &cfg
->ioctl_buf_sync
);
7001 MFREE(cfg
->osh
, ext_join_params
, join_params_size
);
7006 wl_handle_reassoc(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
7007 wlcfg_assoc_info_t
*info
)
7009 wl_reassoc_params_t reassoc_params
;
7013 bzero(&reassoc_params
, WL_REASSOC_PARAMS_FIXED_SIZE
);
7014 (void)memcpy_s(&reassoc_params
.bssid
.octet
, ETH_ALEN
, info
->bssid
, ETH_ALEN
);
7015 wl_ext_get_sec(dev
, 0, sec_info
, sizeof(sec_info
));
7016 WL_MSG(dev
->name
, "Reconnecting with " MACDBG
" sec=%s\n",
7017 MAC2STRDBG((u8
*)(&reassoc_params
.bssid
)), sec_info
);
7018 err
= wldev_ioctl_set(dev
, WLC_REASSOC
, &reassoc_params
, sizeof(wl_reassoc_params_t
));
7019 if (unlikely(err
)) {
7020 WL_ERR(("reassoc failed, error=%d\n", err
));
7023 WL_INFORM_MEM(("wl reassoc "MACDBG
"\n", MAC2STRDBG(info
->bssid
)));
7030 wl_cfg80211_connect(struct wiphy
*wiphy
, struct net_device
*dev
,
7031 struct cfg80211_connect_params
*sme
)
7034 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7035 wlcfg_assoc_info_t assoc_info
;
7036 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
7038 WL_DBG(("Enter len=%zu\n", sme
->ie_len
));
7039 RETURN_EIO_IF_NOT_UP(cfg
);
7041 /* syncronize the connect states */
7042 mutex_lock(&cfg
->connect_sync
);
7044 bzero(&assoc_info
, sizeof(wlcfg_assoc_info_t
));
7045 if ((assoc_info
.bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7046 WL_ERR(("Find wlan index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
7050 err
= wl_do_preassoc_ops(cfg
, dev
, sme
);
7051 if (unlikely(err
)) {
7052 WL_ERR(("config assoc channel failed\n"));
7056 err
= wl_handle_assoc_hints(cfg
, dev
, sme
, &assoc_info
);
7057 if (unlikely(err
)) {
7058 WL_ERR(("assoc hint processing failed\n"));
7062 if (wl_sync_fw_assoc_states(cfg
, dev
, &assoc_info
) != BCME_OK
) {
7063 /* attempt best effort */
7064 WL_ERR(("fw assoc sync failed\n"));
7067 if (assoc_info
.reassoc
) {
7068 // terence 20200530, should call wl_ext_iapsta_update_channel() to move AP channel?
7069 /* Handle roam to same ESS */
7070 err
= wl_handle_reassoc(cfg
, dev
, &assoc_info
);
7072 err
= wl_config_assoc_security(cfg
, dev
, sme
);
7073 if (unlikely(err
)) {
7074 WL_ERR(("config assoc security failed\n"));
7078 err
= wl_get_assoc_channels(cfg
, dev
, &assoc_info
);
7079 if (unlikely(err
)) {
7080 WL_ERR(("get assoc channels failed\n"));
7084 err
= wl_config_assoc_ies(cfg
, dev
, sme
, &assoc_info
);
7085 if (unlikely(err
)) {
7086 WL_ERR(("config assoc ies failed\n"));
7090 /* print relevant info for debug purpose */
7091 #ifdef WL_EXT_IAPSTA
7092 wl_ext_iapsta_update_channel(dhdp
, dev
, assoc_info
.chan_cnt
);
7094 wl_conn_debug_info(cfg
, dev
, &assoc_info
);
7095 err
= wl_handle_join(cfg
, dev
, &assoc_info
);
7099 if (unlikely(err
)) {
7100 WL_ERR(("connect error (%d)\n", err
));
7101 wl_clr_drv_status(cfg
, CONNECTING
, dev
);
7102 CLR_TS(cfg
, conn_start
);
7104 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
7106 /* If connect fails, check whether we can enable back TDLS */
7107 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_DISCONNECT
, false);
7111 /* start packet log in adv to ensure that EAPOL msgs aren't missed */
7112 wl_pkt_mon_start(cfg
, dev
);
7113 #endif /* DBG_PKT_MON */
7116 wl_cfg80211_check_in4way(cfg
, dev
, NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
,
7117 WL_EXT_STATUS_CONNECTING
, NULL
);
7119 mutex_unlock(&cfg
->connect_sync
);
7123 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
7128 wait_cnt
= WAIT_FOR_DISCONNECT_MAX
;
7129 while ((status
= wl_get_drv_status(cfg
, DISCONNECTING
, dev
)) && wait_cnt
) {
7130 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt
));
7135 WL_INFORM_MEM(("Wait for disconnection done. status:%d wait_cnt:%d\n", status
, wait_cnt
));
7136 if (!wait_cnt
&& wl_get_drv_status(cfg
, DISCONNECTING
, dev
)) {
7137 /* No response from firmware. Indicate connect result
7138 * to clear cfg80211 state machine
7140 if (wl_get_drv_status(cfg
, CONNECTING
, dev
)) {
7141 WL_INFORM_MEM(("force send connect result\n"));
7142 CFG80211_CONNECT_RESULT(dev
, NULL
, NULL
, NULL
, 0, NULL
, 0,
7143 WLAN_STATUS_UNSPECIFIED_FAILURE
,
7146 WL_INFORM_MEM(("force send disconnect event\n"));
7147 CFG80211_DISCONNECTED(dev
, WLAN_REASON_DEAUTH_LEAVING
,
7148 NULL
, 0, false, GFP_KERNEL
);
7150 CLR_TS(cfg
, conn_start
);
7151 CLR_TS(cfg
, authorize_start
);
7152 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
7158 wl_cfg80211_disconnect(struct wiphy
*wiphy
, struct net_device
*dev
,
7161 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7165 u8
*curbssid
= NULL
;
7166 u8 null_bssid
[ETHER_ADDR_LEN
];
7169 bool conn_in_progress
;
7170 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
7172 RETURN_EIO_IF_NOT_UP(cfg
);
7173 WL_MSG(dev
->name
, "Reason %d, act %d\n", reason_code
, act
);
7175 BCM_REFERENCE(dhdp
);
7176 DHD_STATLOG_CTRL(dhdp
, ST(DISASSOC_START
),
7177 dhd_net2idx(dhdp
->info
, dev
), reason_code
);
7178 #ifdef DHD_4WAYM4_FAIL_DISCONNECT
7179 dhd_cleanup_m4_state_work(dhdp
, dhd_net2idx(dhdp
->info
, dev
));
7180 #endif /* DHD_4WAYM4_FAIL_DISCONNECT */
7182 connected
= wl_get_drv_status(cfg
, CONNECTED
, dev
);
7183 conn_in_progress
= wl_get_drv_status(cfg
, CONNECTING
, dev
);
7184 curbssid
= wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
7185 act
= *(bool *) wl_read_prof(cfg
, dev
, WL_PROF_ACT
);
7186 WL_INFORM_MEM(("disconnect in connect state [%d:%d:%d]. reason:%d\n",
7187 connected
, conn_in_progress
, act
, reason_code
));
7188 if (connected
|| conn_in_progress
) {
7190 WL_DBG_MEM(("curbssid:" MACDBG
"\n", MAC2STRDBG(curbssid
)));
7196 WL_ERR(("Disconnecting while CONNECTING status %d\n", (int)sizeof(null_bssid
)));
7197 bzero(null_bssid
, sizeof(null_bssid
));
7198 curbssid
= null_bssid
;
7203 /* Stop packet monitor */
7204 if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
7205 DHD_DBG_PKT_MON_STOP(dhdp
);
7207 #endif /* DBG_PKT_MON */
7209 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
7211 /* Let scan aborted by F/W */
7212 if (cfg
->scan_request
) {
7213 WL_TRACE_HW4(("Aborting the scan! \n"));
7214 wl_cfg80211_cancel_scan(cfg
);
7216 if (conn_in_progress
|| connected
) {
7217 scbval
.val
= reason_code
;
7218 memcpy(&scbval
.ea
, curbssid
, ETHER_ADDR_LEN
);
7219 scbval
.val
= htod32(scbval
.val
);
7220 WL_INFORM_MEM(("[%s] wl disassoc\n", dev
->name
));
7221 /* Set DISCONNECTING state. We are clearing this state
7224 wl_set_drv_status(cfg
, DISCONNECTING
, dev
);
7225 err
= wldev_ioctl_set(dev
, WLC_DISASSOC
, &scbval
,
7227 if (unlikely(err
)) {
7228 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
7229 WL_ERR(("error (%d)\n", err
));
7232 wl_cfg80211_check_in4way(cfg
, dev
, NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
|WAIT_DISCONNECTED
,
7233 WL_EXT_STATUS_DISCONNECTING
, NULL
);
7236 /* If are in WPS reauth state, then we would be
7237 * dropping the link down events. Ensure that
7238 * Event is sent up for the disconnect Req
7240 if (wl_wps_session_update(dev
,
7241 WPS_STATE_DISCONNECT
, curbssid
) == BCME_OK
) {
7242 WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
7243 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
7246 #endif /* WPS_SYNC */
7247 wl_cfg80211_wait_for_disconnection(cfg
, dev
);
7249 /* Not in connected or connection in progres states. Still receiving
7250 * disassoc indicates state mismatch with upper layer. Check for state
7251 * and issue disconnect indication if required.
7254 if (dev
->ieee80211_ptr
->current_bss
) {
7255 WL_INFORM_MEM(("report disconnect event\n"));
7256 CFG80211_DISCONNECTED(dev
, 0, NULL
, 0, false, GFP_KERNEL
);
7260 #ifdef CUSTOM_SET_CPUCORE
7261 /* set default cpucore */
7262 if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
7263 dhdp
->chan_isvht80
&= ~DHD_FLAG_STA_MODE
;
7264 if (!(dhdp
->chan_isvht80
))
7265 dhd_set_cpucore(dhdp
, FALSE
);
7267 #endif /* CUSTOM_SET_CPUCORE */
7269 cfg
->rssi
= 0; /* reset backup of rssi */
7272 CLR_TS(cfg
, conn_start
);
7273 CLR_TS(cfg
, authorize_start
);
7275 /* Clear IEs for disaasoc */
7276 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7277 WL_ERR(("Find index failed\n"));
7281 WL_ERR(("Clearing disconnect IEs \n"));
7282 err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
,
7283 ndev_to_cfgdev(dev
), bssidx
, VNDR_IE_DISASSOC_FLAG
, NULL
, 0);
7289 #if defined(WL_CFG80211_P2P_DEV_IF)
7290 wl_cfg80211_set_tx_power(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
7291 enum nl80211_tx_power_setting type
, s32 mbm
)
7293 wl_cfg80211_set_tx_power(struct wiphy
*wiphy
,
7294 enum nl80211_tx_power_setting type
, s32 dbm
)
7295 #endif /* WL_CFG80211_P2P_DEV_IF */
7298 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7299 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
7301 #if defined(WL_CFG80211_P2P_DEV_IF)
7302 s32 dbm
= MBM_TO_DBM(mbm
);
7303 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
7304 defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
7305 dbm
= MBM_TO_DBM(dbm
);
7306 #endif /* WL_CFG80211_P2P_DEV_IF */
7308 RETURN_EIO_IF_NOT_UP(cfg
);
7310 case NL80211_TX_POWER_AUTOMATIC
:
7312 case NL80211_TX_POWER_LIMITED
:
7314 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
7318 case NL80211_TX_POWER_FIXED
:
7320 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
7326 err
= wl_set_tx_power(ndev
, type
, dbm
);
7327 if (unlikely(err
)) {
7328 WL_ERR(("error (%d)\n", err
));
7332 cfg
->conf
->tx_power
= dbm
;
7338 #if defined(WL_CFG80211_P2P_DEV_IF)
7339 wl_cfg80211_get_tx_power(struct wiphy
*wiphy
,
7340 struct wireless_dev
*wdev
, s32
*dbm
)
7342 wl_cfg80211_get_tx_power(struct wiphy
*wiphy
, s32
*dbm
)
7343 #endif /* WL_CFG80211_P2P_DEV_IF */
7345 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7346 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
7349 RETURN_EIO_IF_NOT_UP(cfg
);
7350 err
= wl_get_tx_power(ndev
, dbm
);
7352 WL_ERR(("error (%d)\n", err
));
7358 wl_cfg80211_config_default_key(struct wiphy
*wiphy
, struct net_device
*dev
,
7359 u8 key_idx
, bool unicast
, bool multicast
)
7361 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7367 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7368 WL_ERR(("Find p2p index from dev(%p) failed\n", dev
->ieee80211_ptr
));
7372 WL_DBG(("key index (%d)\n", key_idx
));
7373 RETURN_EIO_IF_NOT_UP(cfg
);
7374 err
= wldev_iovar_getint_bsscfg(dev
, "wsec", &wsec
, bssidx
);
7375 if (unlikely(err
)) {
7376 WL_ERR(("WLC_GET_WSEC error (%d)\n", err
));
7379 /* Fix IOT issue with Apple Airport */
7380 if (wsec
== WEP_ENABLED
) {
7381 /* Just select a new current key */
7382 index
= (u32
) key_idx
;
7383 index
= htod32(index
);
7384 err
= wldev_ioctl_set(dev
, WLC_SET_KEY_PRIMARY
, &index
,
7386 if (unlikely(err
)) {
7387 WL_ERR(("error (%d)\n", err
));
7394 wl_add_keyext(struct wiphy
*wiphy
, struct net_device
*dev
,
7395 u8 key_idx
, const u8
*mac_addr
, struct key_params
*params
)
7397 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7398 struct wl_wsec_key key
;
7401 s32 mode
= wl_get_mode_by_netdev(cfg
, dev
);
7403 WL_MSG(dev
->name
, "key index (%d)\n", key_idx
);
7404 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7405 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
7408 bzero(&key
, sizeof(key
));
7409 key
.index
= (u32
) key_idx
;
7411 if (!ETHER_ISMULTI(mac_addr
))
7412 memcpy((char *)&key
.ea
, (const void *)mac_addr
, ETHER_ADDR_LEN
);
7413 key
.len
= (u32
) params
->key_len
;
7415 /* check for key index change */
7418 swap_key_from_BE(&key
);
7419 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
),
7420 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
7421 if (unlikely(err
)) {
7422 WL_ERR(("key delete error (%d)\n", err
));
7426 if (key
.len
> sizeof(key
.data
)) {
7427 WL_ERR(("Invalid key length (%d)\n", key
.len
));
7430 WL_DBG(("Setting the key index %d\n", key
.index
));
7431 memcpy(key
.data
, params
->key
, key
.len
);
7433 if ((mode
== WL_MODE_BSS
) &&
7434 (params
->cipher
== WLAN_CIPHER_SUITE_TKIP
)) {
7436 memcpy(keybuf
, &key
.data
[24], sizeof(keybuf
));
7437 memcpy(&key
.data
[24], &key
.data
[16], sizeof(keybuf
));
7438 memcpy(&key
.data
[16], keybuf
, sizeof(keybuf
));
7441 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
7442 if (params
->seq
&& params
->seq_len
== 6) {
7445 ivptr
= (const u8
*) params
->seq
;
7446 key
.rxiv
.hi
= (ivptr
[5] << 24) | (ivptr
[4] << 16) |
7447 (ivptr
[3] << 8) | ivptr
[2];
7448 key
.rxiv
.lo
= (ivptr
[1] << 8) | ivptr
[0];
7449 key
.iv_initialized
= true;
7451 key
.algo
= wl_rsn_cipher_wsec_key_algo_lookup(params
->cipher
);
7452 if (key
.algo
== CRYPTO_ALGO_OFF
) { //not found.
7453 WL_ERR(("Invalid cipher (0x%x)\n", params
->cipher
));
7456 swap_key_from_BE(&key
);
7457 #if !defined(CUSTOMER_HW4)
7458 /* need to guarantee EAPOL 4/4 send out before set key */
7459 dhd_wait_pend8021x(dev
);
7460 #endif /* BCMDONGLEHOST && !CUSTOMER_HW4 */
7461 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
),
7462 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
7463 if (unlikely(err
)) {
7464 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
7467 WL_INFORM_MEM(("[%s] wsec key set\n", dev
->name
));
7473 wl_cfg80211_enable_roam_offload(struct net_device
*dev
, int enable
)
7476 wl_eventmsg_buf_t ev_buf
;
7477 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
7479 if (dev
!= bcmcfg_to_prmry_ndev(cfg
)) {
7480 /* roam offload is only for the primary device */
7484 WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev
->name
, enable
));
7485 err
= wldev_iovar_setint(dev
, "roam_offload", enable
);
7489 bzero(&ev_buf
, sizeof(wl_eventmsg_buf_t
));
7490 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_PSK_SUP
, !enable
);
7491 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_ASSOC_REQ_IE
, !enable
);
7492 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_ASSOC_RESP_IE
, !enable
);
7493 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_REASSOC
, !enable
);
7494 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_JOIN
, !enable
);
7495 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_ROAM
, !enable
);
7496 err
= wl_cfg80211_apply_eventbuffer(dev
, cfg
, &ev_buf
);
7498 cfg
->roam_offload
= enable
;
7503 struct wireless_dev
*
7504 wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211
*cfg
, const char *name
)
7506 struct net_info
*iter
, *next
;
7509 WL_ERR(("Iface name is not provided\n"));
7513 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7514 for_each_ndev(cfg
, iter
, next
) {
7515 GCC_DIAGNOSTIC_POP();
7517 if (strcmp(iter
->ndev
->name
, name
) == 0) {
7518 return iter
->ndev
->ieee80211_ptr
;
7523 WL_DBG(("Iface %s not found\n", name
));
7527 #if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
7529 wl_cfg80211_block_arp(struct net_device
*dev
, int enable
)
7531 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
7532 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
7534 WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev
->name
, enable
));
7535 if (!dhd_pkt_filter_enable
) {
7536 WL_DBG(("Packet filter isn't enabled\n"));
7540 /* Block/Unblock ARP frames only if STA is connected to
7541 * the upstream AP in case of STA+SoftAP Concurrenct mode
7543 if (!wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
7544 WL_DBG(("STA not connected to upstream AP\n"));
7549 WL_DBG(("Enable ARP Filter\n"));
7550 /* Add ARP filter */
7551 dhd_packet_filter_add_remove(dhdp
, TRUE
, DHD_BROADCAST_ARP_FILTER_NUM
);
7553 /* Enable ARP packet filter - blacklist */
7554 dhd_pktfilter_offload_enable(dhdp
, dhdp
->pktfilter
[DHD_BROADCAST_ARP_FILTER_NUM
],
7557 WL_DBG(("Disable ARP Filter\n"));
7558 /* Disable ARP packet filter */
7559 dhd_pktfilter_offload_enable(dhdp
, dhdp
->pktfilter
[DHD_BROADCAST_ARP_FILTER_NUM
],
7562 /* Delete ARP filter */
7563 dhd_packet_filter_add_remove(dhdp
, FALSE
, DHD_BROADCAST_ARP_FILTER_NUM
);
7566 #endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
7569 wl_cfg80211_add_key(struct wiphy
*wiphy
, struct net_device
*dev
,
7570 u8 key_idx
, bool pairwise
, const u8
*mac_addr
,
7571 struct key_params
*params
)
7573 struct wl_wsec_key key
;
7579 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7580 s32 mode
= wl_get_mode_by_netdev(cfg
, dev
);
7582 uint32 algos
= 0, mask
= 0;
7583 #endif /* WL_GCMP */
7584 #if defined(WLAN_CIPHER_SUITE_PMK)
7586 struct wl_security
*sec
;
7587 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7588 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
7590 if (dhd_query_bus_erros(dhdp
)) {
7591 /* If we are hit with bus error, return success so that
7592 * don't repeatedly call del station till we recover.
7597 WL_INFORM_MEM(("key index (%d) (0x%x)\n", key_idx
, params
->cipher
));
7598 RETURN_EIO_IF_NOT_UP(cfg
);
7600 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7601 WL_ERR(("Find p2p index from dev(%p) failed\n", dev
->ieee80211_ptr
));
7606 ((params
->cipher
!= WLAN_CIPHER_SUITE_WEP40
) &&
7607 (params
->cipher
!= WLAN_CIPHER_SUITE_WEP104
))) {
7608 wl_add_keyext(wiphy
, dev
, key_idx
, mac_addr
, params
);
7612 BCM_REFERENCE(dhdp
);
7613 DHD_STATLOG_CTRL(dhdp
, ST(INSTALL_KEY
), dhd_net2idx(dhdp
->info
, dev
), 0);
7615 bzero(&key
, sizeof(key
));
7616 /* Clear any buffered wep key */
7617 bzero(&cfg
->wep_key
, sizeof(struct wl_wsec_key
));
7619 key
.len
= (u32
) params
->key_len
;
7620 key
.index
= (u32
) key_idx
;
7622 if (unlikely(key
.len
> sizeof(key
.data
))) {
7623 WL_ERR(("Too long key length (%u)\n", key
.len
));
7626 memcpy(key
.data
, params
->key
, key
.len
);
7628 key
.flags
= WL_PRIMARY_KEY
;
7630 key
.algo
= wl_rsn_cipher_wsec_key_algo_lookup(params
->cipher
);
7631 val
= wl_rsn_cipher_wsec_algo_lookup(params
->cipher
);
7632 if (val
== WSEC_NONE
) {
7633 WL_ERR(("Invalid cipher (0x%x), key.len = %d\n", params
->cipher
, key
.len
));
7634 #if defined(WLAN_CIPHER_SUITE_PMK)
7635 /* WLAN_CIPHER_SUITE_PMK is not NL80211 standard ,but BRCM proprietary cipher suite.
7636 * so it doesn't have right algo type. Just for now, bypass this check for
7637 * backward compatibility.
7638 * TODO: deprecate this proprietary way and replace to nl80211 set_pmk API.
7640 if (params
->cipher
!= WLAN_CIPHER_SUITE_PMK
)
7641 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7644 switch (params
->cipher
) {
7645 case WLAN_CIPHER_SUITE_TKIP
:
7646 if (params
->key_len
!= TKIP_KEY_SIZE
) {
7647 WL_ERR(("wrong TKIP Key length:%d", params
->key_len
));
7650 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
7651 if (mode
== WL_MODE_BSS
) {
7652 bcopy(&key
.data
[24], keybuf
, sizeof(keybuf
));
7653 bcopy(&key
.data
[16], &key
.data
[24], sizeof(keybuf
));
7654 bcopy(keybuf
, &key
.data
[16], sizeof(keybuf
));
7656 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7658 #if defined(WLAN_CIPHER_SUITE_PMK)
7659 case WLAN_CIPHER_SUITE_PMK
:
7660 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
7662 WL_MEM(("set_pmk: wpa_auth:%x akm:%x\n", sec
->wpa_auth
, params
->cipher
));
7663 /* Avoid pmk set for SAE and OWE for external supplicant case. */
7664 if (IS_AKM_SAE(sec
->wpa_auth
) || IS_AKM_OWE(sec
->wpa_auth
)) {
7665 WL_INFORM_MEM(("skip pmk set for akm:%x\n", sec
->wpa_auth
));
7669 if (params
->key_len
> sizeof(pmk
.key
)) {
7670 WL_ERR(("Worng PMK key length:%d", params
->key_len
));
7673 bzero(&pmk
, sizeof(pmk
));
7674 bcopy(params
->key
, &pmk
.key
, params
->key_len
);
7675 pmk
.key_len
= params
->key_len
;
7676 pmk
.flags
= 0; /* 0:PMK, WSEC_PASSPHRASE:PSK, WSEC_SAE_PASSPHRASE:SAE_PSK */
7678 if ((sec
->wpa_auth
== WLAN_AKM_SUITE_8021X
) ||
7679 (sec
->wpa_auth
== WL_AKM_SUITE_SHA256_1X
)) {
7680 err
= wldev_iovar_setbuf_bsscfg(dev
, "okc_info_pmk", pmk
.key
, pmk
.key_len
,
7681 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
7683 /* could fail in case that 'okc' is not supported */
7684 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err
));
7688 err
= wldev_ioctl_set(dev
, WLC_SET_WSEC_PMK
, &pmk
, sizeof(pmk
));
7690 WL_ERR(("pmk failed, err=%d (ignore)\n", err
));
7693 WL_DBG(("pmk set. flags:0x%x\n", pmk
.flags
));
7695 /* Clear key length to delete key */
7698 #endif /* WLAN_CIPHER_SUITE_PMK */
7700 case WLAN_CIPHER_SUITE_GCMP
:
7701 case WLAN_CIPHER_SUITE_GCMP_256
:
7702 case WLAN_CIPHER_SUITE_BIP_GMAC_128
:
7703 case WLAN_CIPHER_SUITE_BIP_GMAC_256
:
7704 algos
= KEY_ALGO_MASK(key
.algo
);
7705 mask
= algos
| KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM
);
7707 #endif /* WL_GCMP */
7708 default: /* No post processing required */
7709 WL_DBG(("no post processing required (0x%x)\n", params
->cipher
));
7713 /* Set the new key/index */
7714 if ((mode
== WL_MODE_IBSS
) && (val
& (TKIP_ENABLED
| AES_ENABLED
))) {
7715 WL_ERR(("IBSS KEY setted\n"));
7716 wldev_iovar_setint(dev
, "wpa_auth", WPA_AUTH_NONE
);
7718 swap_key_from_BE(&key
);
7719 if ((params
->cipher
== WLAN_CIPHER_SUITE_WEP40
) ||
7720 (params
->cipher
== WLAN_CIPHER_SUITE_WEP104
)) {
7722 * For AP role, since we are doing a wl down before bringing up AP,
7723 * the plumbed keys will be lost. So for AP once we bring up AP, we
7724 * need to plumb keys again. So buffer the keys for future use. This
7725 * is more like a WAR. If firmware later has the capability to do
7726 * interface upgrade without doing a "wl down" and "wl apsta 0", then
7727 * this will not be required.
7729 WL_DBG(("Buffering WEP Keys \n"));
7730 memcpy(&cfg
->wep_key
, &key
, sizeof(struct wl_wsec_key
));
7732 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
), cfg
->ioctl_buf
,
7733 WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
7734 if (unlikely(err
)) {
7735 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
7740 err
= wldev_iovar_getint_bsscfg(dev
, "wsec", &wsec
, bssidx
);
7741 if (unlikely(err
)) {
7742 WL_ERR(("get wsec error (%d)\n", err
));
7747 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
7748 if (unlikely(err
)) {
7749 WL_ERR(("set wsec error (%d)\n", err
));
7753 wl_set_wsec_info_algos(dev
, algos
, mask
);
7754 #endif /* WL_GCMP */
7755 wl_cfg80211_check_in4way(cfg
, dev
, NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
,
7756 WL_EXT_STATUS_ADD_KEY
, NULL
);
7761 wl_cfg80211_del_key(struct wiphy
*wiphy
, struct net_device
*dev
,
7762 u8 key_idx
, bool pairwise
, const u8
*mac_addr
)
7764 struct wl_wsec_key key
;
7765 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7768 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
7770 if (dhd_query_bus_erros(dhdp
)) {
7771 /* If we are hit with bus error, return success so that
7772 * don't repeatedly call del station till we recover.
7777 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7778 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
7781 WL_DBG(("Enter\n"));
7784 if ((key_idx
>= DOT11_MAX_DEFAULT_KEYS
) && (key_idx
< DOT11_MAX_DEFAULT_KEYS
+2))
7788 RETURN_EIO_IF_NOT_UP(cfg
);
7789 BCM_REFERENCE(dhdp
);
7790 DHD_STATLOG_CTRL(dhdp
, ST(DELETE_KEY
), dhd_net2idx(dhdp
->info
, dev
), 0);
7791 bzero(&key
, sizeof(key
));
7793 key
.flags
= WL_PRIMARY_KEY
;
7794 key
.algo
= CRYPTO_ALGO_OFF
;
7795 key
.index
= (u32
) key_idx
;
7797 WL_DBG(("key index (%d)\n", key_idx
));
7798 /* Set the new key/index */
7799 swap_key_from_BE(&key
);
7800 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
), cfg
->ioctl_buf
,
7801 WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
7802 if (unlikely(err
)) {
7803 if (err
== -EINVAL
) {
7804 if (key
.index
>= DOT11_MAX_DEFAULT_KEYS
) {
7805 /* we ignore this key index in this case */
7806 WL_DBG(("invalid key index (%d)\n", key_idx
));
7809 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
7816 /* NOTE : this function cannot work as is and is never called */
7818 wl_cfg80211_get_key(struct wiphy
*wiphy
, struct net_device
*dev
,
7819 u8 key_idx
, bool pairwise
, const u8
*mac_addr
, void *cookie
,
7820 void (*callback
) (void *cookie
, struct key_params
* params
))
7822 struct key_params params
;
7823 struct wl_wsec_key key
;
7824 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7825 struct wl_security
*sec
;
7830 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7831 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
7834 WL_DBG(("key index (%d)\n", key_idx
));
7835 RETURN_EIO_IF_NOT_UP(cfg
);
7836 bzero(&key
, sizeof(key
));
7837 key
.index
= key_idx
;
7838 swap_key_to_BE(&key
);
7839 bzero(¶ms
, sizeof(params
));
7840 params
.key_len
= (u8
) min_t(u8
, DOT11_MAX_KEY_SIZE
, key
.len
);
7841 params
.key
= key
.data
;
7843 err
= wldev_iovar_getint_bsscfg(dev
, "wsec", &wsec
, bssidx
);
7844 if (unlikely(err
)) {
7845 WL_ERR(("WLC_GET_WSEC error (%d)\n", err
));
7848 switch (WSEC_ENABLED(wsec
)) {
7850 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
7851 if (sec
->cipher_pairwise
& WLAN_CIPHER_SUITE_WEP40
) {
7852 params
.cipher
= WLAN_CIPHER_SUITE_WEP40
;
7853 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7854 } else if (sec
->cipher_pairwise
& WLAN_CIPHER_SUITE_WEP104
) {
7855 params
.cipher
= WLAN_CIPHER_SUITE_WEP104
;
7856 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7860 params
.cipher
= WLAN_CIPHER_SUITE_TKIP
;
7861 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7864 params
.cipher
= WLAN_CIPHER_SUITE_AES_CMAC
;
7865 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7870 params
.cipher
= WLAN_CIPHER_SUITE_SMS4
;
7871 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7875 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
7876 /* to connect to mixed mode AP */
7877 case (AES_ENABLED
| TKIP_ENABLED
): /* TKIP CCMP */
7878 params
.cipher
= WLAN_CIPHER_SUITE_AES_CMAC
;
7879 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7883 WL_ERR(("Invalid algo (0x%x)\n", wsec
));
7887 callback(cookie
, ¶ms
);
7892 wl_cfg80211_config_default_mgmt_key(struct wiphy
*wiphy
,
7893 struct net_device
*dev
, u8 key_idx
)
7896 /* Firmware seems to use hard coded index for Group Mgmt Key.
7897 * TODO/Need to check whether something else needs to be
7902 WL_INFORM_MEM(("Not supported\n"));
7908 wl_check_assoc_state(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
7910 wl_assoc_info_t asinfo
;
7914 err
= wldev_iovar_getbuf_bsscfg(dev
, "assoc_info",
7915 NULL
, 0, cfg
->ioctl_buf
, WLC_IOCTL_MEDLEN
, 0, &cfg
->ioctl_buf_sync
);
7916 if (unlikely(err
)) {
7917 WL_ERR(("failed to get assoc_info : err=%d\n", err
));
7920 memcpy(&asinfo
, cfg
->ioctl_buf
, sizeof(wl_assoc_info_t
));
7921 state
= dtoh32(asinfo
.state
);
7922 WL_DBG(("assoc state=%d\n", state
));
7925 return (state
> 0)? TRUE
:FALSE
;
7929 wl_cfg80211_get_rssi(struct net_device
*dev
, struct bcm_cfg80211
*cfg
, s32
*rssi
)
7933 #ifdef SUPPORT_RSSI_SUM_REPORT
7934 wl_rssi_ant_mimo_t rssi_ant_mimo
;
7935 #endif /* SUPPORT_RSSI_SUM_REPORT */
7937 if (dev
== NULL
|| cfg
== NULL
) {
7941 /* initialize rssi */
7944 #ifdef SUPPORT_RSSI_SUM_REPORT
7945 /* Query RSSI sum across antennas */
7946 bzero(&rssi_ant_mimo
, sizeof(rssi_ant_mimo
));
7947 err
= wl_get_rssi_per_ant(dev
, dev
->name
, NULL
, &rssi_ant_mimo
);
7949 WL_ERR(("Could not get rssi sum (%d)\n", err
));
7950 /* set rssi to zero and do not return error,
7951 * because iovar phy_rssi_ant could return BCME_UNSUPPORTED
7952 * when bssid was null during roaming
7956 cfg
->rssi_sum_report
= TRUE
;
7957 if ((*rssi
= rssi_ant_mimo
.rssi_sum
) >= 0) {
7961 #endif /* SUPPORT_RSSI_SUM_REPORT */
7963 /* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore */
7964 if (cfg
->rssi_sum_report
== FALSE
) {
7965 bzero(&scb_val
, sizeof(scb_val
));
7967 err
= wldev_ioctl_get(dev
, WLC_GET_RSSI
, &scb_val
,
7970 WL_ERR(("Could not get rssi (%d)\n", err
));
7973 #if defined(RSSIOFFSET)
7974 *rssi
= wl_update_rssi_offset(dev
, dtoh32(scb_val
.val
));
7976 *rssi
= dtoh32(scb_val
.val
);
7981 /* check assoc status including roaming */
7982 DHD_OS_WAKE_LOCK((dhd_pub_t
*)(cfg
->pub
));
7983 if (wl_get_drv_status(cfg
, CONNECTED
, dev
) && wl_check_assoc_state(cfg
, dev
)) {
7984 *rssi
= cfg
->rssi
; /* use previous RSSI */
7985 WL_DBG(("use previous RSSI %d dBm\n", cfg
->rssi
));
7989 DHD_OS_WAKE_UNLOCK((dhd_pub_t
*)(cfg
->pub
));
7991 /* backup the current rssi */
7999 wl_cfg80211_ifstats_counters_cb(void *ctx
, const uint8
*data
, uint16 type
, uint16 len
)
8002 case WL_IFSTATS_XTLV_IF_INDEX
:
8003 WL_DBG(("Stats received on interface index: %d\n", *data
));
8005 case WL_IFSTATS_XTLV_GENERIC
: {
8006 if (len
> sizeof(wl_if_stats_t
)) {
8007 WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n",
8008 type
, len
, (int)sizeof(wl_if_stats_t
)));
8010 memcpy(ctx
, data
, sizeof(wl_if_stats_t
));
8014 WL_DBG(("Unsupported counter type 0x%x\n", type
));
8021 /* Parameters to if_counters iovar need to be converted to XTLV format
8022 * before sending to FW. The length of the top level XTLV container
8023 * containing parameters should not exceed 228 bytes
8025 #define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228
8028 wl_cfg80211_ifstats_counters(struct net_device
*dev
, wl_if_stats_t
*if_stats
)
8030 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
8031 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
8033 bcm_xtlvbuf_t xtlvbuf
, local_xtlvbuf
;
8035 uint16 expected_resp_len
;
8036 wl_stats_report_t
*request
= NULL
, *response
= NULL
;
8040 pbuf
= (uint8
*)MALLOCZ(dhdp
->osh
, WLC_IOCTL_MEDLEN
);
8042 WL_ERR(("Failed to allocate local pbuf\n"));
8046 /* top level container length cannot exceed 228 bytes.
8047 * This is because the output buffer is 1535 bytes long.
8048 * Allow 1300 bytes for reporting stats coming in XTLV format
8050 request
= (wl_stats_report_t
*)
8051 MALLOCZ(dhdp
->osh
, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
);
8053 WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
8054 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
));
8059 request
->version
= WL_STATS_REPORT_REQUEST_VERSION_V2
;
8061 /* Top level container... we will create it ourselves */
8062 /* Leave space for report version, length, and top level XTLV
8063 * WL_IFSTATS_XTLV_IF.
8065 ret
= bcm_xtlv_buf_init(&local_xtlvbuf
,
8066 (uint8
*)(request
->data
) + BCM_XTLV_HDR_SIZE
,
8067 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
-
8068 offsetof(wl_stats_report_t
, data
) - BCM_XTLV_HDR_SIZE
,
8069 BCM_XTLV_OPTION_ALIGN32
);
8075 /* Populate requests using this the local_xtlvbuf context. The xtlvbuf
8076 * is used to fill the container containing the XTLVs populated using
8079 ret
= bcm_xtlv_buf_init(&xtlvbuf
,
8080 (uint8
*)(request
->data
),
8081 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
-
8082 offsetof(wl_stats_report_t
, data
),
8083 BCM_XTLV_OPTION_ALIGN32
);
8089 /* Request generic stats */
8090 ret
= bcm_xtlv_put_data(&local_xtlvbuf
,
8091 WL_IFSTATS_XTLV_GENERIC
, NULL
, 0);
8096 /* Complete the outer container with type and length
8099 ret
= bcm_xtlv_put_data(&xtlvbuf
,
8101 NULL
, bcm_xtlv_buf_len(&local_xtlvbuf
));
8107 request
->length
= bcm_xtlv_buf_len(&xtlvbuf
) +
8108 offsetof(wl_stats_report_t
, data
);
8109 bsscfg_idx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
);
8111 /* send the command over to the device and get teh output */
8112 ret
= wldev_iovar_getbuf_bsscfg(dev
, "if_counters", (void *)request
,
8113 request
->length
, pbuf
, WLC_IOCTL_MEDLEN
, bsscfg_idx
,
8114 &cfg
->ioctl_buf_sync
);
8116 WL_ERR(("if_counters not supported ret=%d\n", ret
));
8120 /* Reuse request to process response */
8121 response
= (wl_stats_report_t
*)pbuf
;
8124 if (response
->version
!= WL_STATS_REPORT_REQUEST_VERSION_V2
) {
8129 xtlv
= (bcm_xtlv_t
*)(response
->data
);
8132 (BCM_XTLV_LEN(xtlv
) + OFFSETOF(wl_stats_report_t
, data
));
8134 /* Check if the received length is as expected */
8135 if ((response
->length
> WLC_IOCTL_MEDLEN
) ||
8136 (response
->length
< expected_resp_len
)) {
8138 WL_ERR(("Illegal response length received. Got: %d"
8139 " Expected: %d. Expected len must be <= %u\n",
8140 response
->length
, expected_resp_len
, WLC_IOCTL_MEDLEN
));
8144 /* check the type. The return data will be in
8145 * WL_IFSTATS_XTLV_IF container. So check if that container is
8148 if (BCM_XTLV_ID(xtlv
) != WL_IFSTATS_XTLV_IF
) {
8150 WL_ERR(("unexpected type received: %d Expected: %d\n",
8151 BCM_XTLV_ID(xtlv
), WL_IFSTATS_XTLV_IF
));
8155 /* Process XTLVs within WL_IFSTATS_XTLV_IF container */
8156 ret
= bcm_unpack_xtlv_buf(if_stats
,
8157 (uint8
*)response
->data
+ BCM_XTLV_HDR_SIZE
,
8158 BCM_XTLV_LEN(xtlv
), /* total length of all TLVs in container */
8159 BCM_XTLV_OPTION_ALIGN32
, wl_cfg80211_ifstats_counters_cb
);
8161 WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret
));
8166 MFREE(dhdp
->osh
, pbuf
, WLC_IOCTL_MEDLEN
);
8170 MFREE(dhdp
->osh
, request
, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
);
8174 #undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
8177 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
8178 wl_cfg80211_get_station(struct wiphy
*wiphy
, struct net_device
*dev
,
8179 const u8
*mac
, struct station_info
*sinfo
)
8181 wl_cfg80211_get_station(struct wiphy
*wiphy
, struct net_device
*dev
,
8182 u8
*mac
, struct station_info
*sinfo
)
8185 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8187 #if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, \
8189 wl_rssi_ant_mimo_t rssi_ant_mimo
;
8191 #endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
8196 get_pktcnt_t pktcnt
;
8197 wl_if_stats_t
*if_stats
= NULL
;
8198 sta_info_v4_t
*sta
= NULL
;
8200 s8 eabuf
[ETHER_ADDR_STR_LEN
];
8201 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
8202 bool fw_assoc_state
= FALSE
;
8203 u32 dhd_assoc_state
= 0;
8206 RETURN_EIO_IF_NOT_UP(cfg
);
8208 if (cfg80211_to_wl_iftype(dev
->ieee80211_ptr
->iftype
, &wl_iftype
, &wl_mode
) < 0) {
8212 buf
= MALLOC(cfg
->osh
, MAX(sizeof(wl_if_stats_t
), WLC_IOCTL_SMLEN
));
8214 WL_ERR(("wl_cfg80211_get_station: MALLOC failed\n"));
8218 switch (wl_iftype
) {
8219 case WL_IF_TYPE_STA
:
8220 case WL_IF_TYPE_IBSS
:
8221 if (cfg
->roam_offload
) {
8222 struct ether_addr bssid
;
8223 bzero(&bssid
, sizeof(bssid
));
8224 err
= wldev_ioctl_get(dev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
8226 WL_ERR(("Failed to get current BSSID\n"));
8228 if (memcmp(mac
, &bssid
.octet
, ETHER_ADDR_LEN
) != 0) {
8229 /* roaming is detected */
8230 err
= wl_cfg80211_delayed_roam(cfg
, dev
, &bssid
);
8232 WL_ERR(("Failed to handle the delayed"
8233 " roam, err=%d", err
));
8234 mac
= (u8
*)bssid
.octet
;
8238 dhd_assoc_state
= wl_get_drv_status(cfg
, CONNECTED
, dev
);
8239 DHD_OS_WAKE_LOCK(dhd
);
8240 fw_assoc_state
= dhd_is_associated(dhd
, 0, &err
);
8241 if (dhd_assoc_state
&& !fw_assoc_state
) {
8242 /* check roam (join) status */
8243 if (wl_check_assoc_state(cfg
, dev
)) {
8244 fw_assoc_state
= TRUE
;
8245 WL_DBG(("roam status\n"));
8248 DHD_OS_WAKE_UNLOCK(dhd
);
8249 if (!dhd_assoc_state
|| !fw_assoc_state
) {
8250 WL_ERR(("NOT assoc\n"));
8251 if (err
== -ENODATA
)
8253 if (!dhd_assoc_state
) {
8254 WL_TRACE_HW4(("drv state is not connected \n"));
8256 if (!fw_assoc_state
) {
8257 WL_TRACE_HW4(("fw state is not associated \n"));
8259 /* Disconnect due to fw is not associated for
8260 * FW_ASSOC_WATCHDOG_TIME ms.
8261 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
8262 * means that BSSID is null.
8264 if (dhd_assoc_state
&& !fw_assoc_state
&& !err
) {
8265 if (!fw_assoc_watchdog_started
) {
8266 fw_assoc_watchdog_ms
= OSL_SYSUPTIME();
8267 fw_assoc_watchdog_started
= TRUE
;
8268 WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
8269 } else if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms
>
8270 FW_ASSOC_WATCHDOG_TIME
) {
8271 fw_assoc_watchdog_started
= FALSE
;
8273 WL_TRACE_HW4(("fw is not associated for %d ms \n",
8274 (OSL_SYSUPTIME() - fw_assoc_watchdog_ms
)));
8275 goto get_station_err
;
8281 if (dhd_is_associated(dhd
, 0, NULL
)) {
8282 fw_assoc_watchdog_started
= FALSE
;
8284 curmacp
= wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
8285 if (memcmp(mac
, curmacp
, ETHER_ADDR_LEN
)) {
8286 WL_ERR(("Wrong Mac address: "MACDBG
" != "MACDBG
"\n",
8287 MAC2STRDBG(mac
), MAC2STRDBG(curmacp
)));
8289 /* go through to get another information */
8290 case WL_IF_TYPE_P2P_GC
:
8291 case WL_IF_TYPE_P2P_DISC
:
8292 if ((err
= wl_cfg80211_get_rssi(dev
, cfg
, &rssi
)) != BCME_OK
) {
8293 goto get_station_err
;
8295 #if defined(RSSIAVG)
8296 err
= wl_update_connected_rssi_cache(dev
, &cfg
->g_connected_rssi_cache_ctrl
, &rssi
);
8298 WL_ERR(("Could not get rssi (%d)\n", err
));
8299 goto get_station_err
;
8301 wl_delete_dirty_rssi_cache(&cfg
->g_connected_rssi_cache_ctrl
);
8302 wl_reset_rssi_cache(&cfg
->g_connected_rssi_cache_ctrl
);
8304 #if defined(RSSIOFFSET)
8305 rssi
= wl_update_rssi_offset(dev
, rssi
);
8307 #if !defined(RSSIAVG) && !defined(RSSIOFFSET)
8308 // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
8309 rssi
= MIN(rssi
, RSSI_MAXVAL
);
8311 sinfo
->filled
|= STA_INFO_BIT(INFO_SIGNAL
);
8312 sinfo
->signal
= rssi
;
8313 WL_DBG(("RSSI %d dBm\n", rssi
));
8314 #if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, \
8316 /* Query RSSI sum across antennas */
8317 memset(&rssi_ant_mimo
, 0, sizeof(rssi_ant_mimo
));
8318 err
= wl_get_rssi_per_ant(dev
, dev
->name
, NULL
, &rssi_ant_mimo
);
8320 WL_ERR(("Could not get rssi sum (%d)\n", err
));
8323 for (cnt
= 0; cnt
< rssi_ant_mimo
.count
; cnt
++) {
8324 sinfo
->chain_signal
[cnt
] = rssi_ant_mimo
.rssi_ant
[cnt
];
8325 chains
|= (1 << cnt
);
8326 WL_DBG(("RSSI[%d]: %d dBm\n",
8327 cnt
, rssi_ant_mimo
.rssi_ant
[cnt
]));
8329 sinfo
->chains
= chains
;
8330 sinfo
->filled
|= STA_INFO_BIT(INFO_CHAIN_SIGNAL
);
8332 #endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
8333 /* go through to get another information */
8334 case WL_IF_TYPE_P2P_GO
:
8335 /* Report the current tx rate */
8337 err
= wldev_ioctl_get(dev
, WLC_GET_RATE
, &rate
, sizeof(rate
));
8339 WL_ERR(("Could not get rate (%d)\n", err
));
8341 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
8344 rate
= dtoh32(rate
);
8345 sinfo
->filled
|= STA_INFO_BIT(INFO_TX_BITRATE
);
8346 sinfo
->txrate
.legacy
= rate
* 5;
8347 WL_DBG(("Rate %d Mbps\n", (rate
/ 2)));
8348 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
8349 rxpktglom
= ((rate
/2) > 150) ? 20 : 10;
8351 if (maxrxpktglom
!= rxpktglom
) {
8352 maxrxpktglom
= rxpktglom
;
8353 WL_DBG(("Rate %d Mbps, update bus:"
8354 "maxtxpktglom=%d\n", (rate
/2), maxrxpktglom
));
8355 err
= wldev_iovar_setbuf(dev
, "bus:maxtxpktglom",
8356 (char*)&maxrxpktglom
, 4, cfg
->ioctl_buf
,
8357 WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
8359 WL_ERR(("set bus:maxtxpktglom failed, %d\n", err
));
8364 if_stats
= (wl_if_stats_t
*)buf
;
8365 bzero(if_stats
, sizeof(*if_stats
));
8366 if (FW_SUPPORTED(dhd
, ifst
)) {
8367 err
= wl_cfg80211_ifstats_counters(dev
, if_stats
);
8370 err
= wldev_iovar_getbuf(dev
, "if_counters", NULL
, 0,
8371 (char *)if_stats
, sizeof(*if_stats
), NULL
);
8375 // WL_ERR(("if_counters not supported ret=%d\n", err));
8376 bzero(&pktcnt
, sizeof(pktcnt
));
8377 err
= wldev_ioctl_get(dev
, WLC_GET_PKTCNTS
, &pktcnt
,
8380 sinfo
->rx_packets
= pktcnt
.rx_good_pkt
;
8381 sinfo
->rx_dropped_misc
= pktcnt
.rx_bad_pkt
;
8382 sinfo
->tx_packets
= pktcnt
.tx_good_pkt
;
8383 sinfo
->tx_failed
= pktcnt
.tx_bad_pkt
;
8386 sinfo
->rx_packets
= (uint32
)dtoh64(if_stats
->rxframe
);
8387 /* In this case, if_stats->rxerror is invalid.
8388 * So, force to assign '0'.
8390 sinfo
->rx_dropped_misc
= 0;
8391 sinfo
->tx_packets
= (uint32
)dtoh64(if_stats
->txfrmsnt
);
8392 sinfo
->tx_failed
= (uint32
)dtoh64(if_stats
->txnobuf
) +
8393 (uint32
)dtoh64(if_stats
->txrunt
) +
8394 (uint32
)dtoh64(if_stats
->txfail
);
8395 sinfo
->rx_bytes
= dtoh64(if_stats
->rxbyte
);
8396 sinfo
->tx_bytes
= dtoh64(if_stats
->txbyte
);
8397 sinfo
->tx_retries
= (uint32
)dtoh64(if_stats
->txretry
);
8398 sinfo
->filled
|= (STA_INFO_BIT(INFO_RX_BYTES
) |
8399 STA_INFO_BIT(INFO_TX_BYTES
) |
8400 STA_INFO_BIT(INFO_TX_RETRIES
));
8403 sinfo
->filled
|= (STA_INFO_BIT(INFO_RX_PACKETS
) |
8404 STA_INFO_BIT(INFO_RX_DROP_MISC
) |
8405 STA_INFO_BIT(INFO_TX_PACKETS
) |
8406 STA_INFO_BIT(INFO_TX_FAILED
));
8408 if (err
&& (err
!= -ENODATA
)) {
8409 /* Disconnect due to zero BSSID or error to get RSSI */
8411 DHD_STATLOG_CTRL(dhd
, ST(DISASSOC_INT_START
),
8412 dhd_net2idx(dhd
->info
, dev
), DOT11_RC_DISASSOC_LEAVING
);
8413 scbval
.val
= htod32(DOT11_RC_DISASSOC_LEAVING
);
8414 err
= wldev_ioctl_set(dev
, WLC_DISASSOC
, &scbval
,
8416 if (unlikely(err
)) {
8417 WL_ERR(("disassoc error (%d)\n", err
));
8420 WL_ERR(("force cfg80211_disconnected: %d\n", err
));
8421 wl_clr_drv_status(cfg
, CONNECTED
, dev
);
8422 DHD_STATLOG_CTRL(dhd
, ST(DISASSOC_DONE
),
8423 dhd_net2idx(dhd
->info
, dev
), DOT11_RC_DISASSOC_LEAVING
);
8424 CFG80211_DISCONNECTED(dev
, 0, NULL
, 0, false, GFP_KERNEL
);
8429 err
= wldev_iovar_getbuf(dev
, "sta_info", (const void*)mac
,
8430 ETHER_ADDR_LEN
, buf
, WLC_IOCTL_SMLEN
, NULL
);
8432 WL_ERR(("GET STA INFO failed, %d\n", err
));
8435 sinfo
->filled
= STA_INFO_BIT(INFO_INACTIVE_TIME
);
8436 sta
= (sta_info_v4_t
*)buf
;
8437 if (sta
->ver
!= WL_STA_VER_4
&& sta
->ver
!= WL_STA_VER_5
) {
8438 WL_ERR(("GET STA INFO version mismatch, %d\n", err
));
8439 return BCME_VERSION
;
8441 sta
->len
= dtoh16(sta
->len
);
8442 sta
->cap
= dtoh16(sta
->cap
);
8443 sta
->flags
= dtoh32(sta
->flags
);
8444 sta
->idle
= dtoh32(sta
->idle
);
8445 sta
->in
= dtoh32(sta
->in
);
8446 sinfo
->inactive_time
= sta
->idle
* 1000;
8447 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
8448 if (sta
->flags
& WL_STA_ASSOC
) {
8449 sinfo
->filled
|= STA_INFO_BIT(INFO_CONNECTED_TIME
);
8450 sinfo
->connected_time
= sta
->in
;
8453 WL_INFORM_MEM(("STA %s, flags 0x%x, idle time %ds, connected time %ds\n",
8454 bcm_ether_ntoa((const struct ether_addr
*)mac
, eabuf
),
8455 sta
->flags
, sta
->idle
, sta
->in
));
8458 WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg
, dev
)));
8462 MFREE(cfg
->osh
, buf
, MAX(sizeof(wl_if_stats_t
), WLC_IOCTL_SMLEN
));
8469 wl_cfg80211_dump_station(struct wiphy
*wiphy
, struct net_device
*ndev
,
8470 int idx
, u8
*mac
, struct station_info
*sinfo
)
8472 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8473 struct maclist
*assoc_maclist
= (struct maclist
*)&(cfg
->assoclist
);
8476 WL_ERR(("%s: enter, idx=%d\n", __FUNCTION__
, idx
));
8479 assoc_maclist
->count
= MAX_NUM_OF_ASSOCIATED_DEV
;
8480 err
= wldev_ioctl_get(ndev
, WLC_GET_ASSOCLIST
,
8481 assoc_maclist
, sizeof(cfg
->assoclist
));
8483 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err
));
8484 cfg
->assoclist
.count
= 0;
8489 if (idx
< le32_to_cpu(cfg
->assoclist
.count
)) {
8490 memcpy(mac
, cfg
->assoclist
.mac
[idx
], ETH_ALEN
);
8491 return wl_cfg80211_get_station(wiphy
, ndev
, mac
, sinfo
);
8498 wl_cfg80211_set_power_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
8499 bool enabled
, s32 timeout
)
8503 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8504 struct net_info
*_net_info
= wl_get_netinfo_by_netdev(cfg
, dev
);
8507 rtt_status_info_t
*rtt_status
;
8508 #endif /* RTT_SUPPORT */
8509 dhd_pub_t
*dhd
= cfg
->pub
;
8510 RETURN_EIO_IF_NOT_UP(cfg
);
8512 WL_DBG(("Enter\n"));
8513 mode
= wl_get_mode_by_netdev(cfg
, dev
);
8514 if (cfg
->p2p_net
== dev
|| _net_info
== NULL
||
8515 !wl_get_drv_status(cfg
, CONNECTED
, dev
) ||
8516 ((mode
!= WL_MODE_BSS
) &&
8517 (mode
!= WL_MODE_IBSS
))) {
8521 /* Enlarge pm_enable_work */
8522 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_LONG
);
8524 pm
= enabled
? PM_FAST
: PM_OFF
;
8525 if (_net_info
->pm_block
) {
8526 WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
8527 dev
->name
, _net_info
->pm_block
));
8530 if (enabled
&& dhd_conf_get_pm(dhd
) >= 0)
8531 pm
= dhd_conf_get_pm(dhd
);
8533 WL_DBG(("%s:power save %s\n", dev
->name
, (pm
? "enabled" : "disabled")));
8535 rtt_status
= GET_RTTSTATE(dhd
);
8536 if (rtt_status
->status
!= RTT_ENABLED
) {
8537 #endif /* RTT_SUPPORT */
8538 err
= wldev_ioctl_set(dev
, WLC_SET_PM
, &pm
, sizeof(pm
));
8539 if (unlikely(err
)) {
8541 WL_DBG(("net_device is not ready yet\n"));
8543 WL_ERR(("error (%d)\n", err
));
8548 #endif /* RTT_SUPPORT */
8549 wl_cfg80211_update_power_mode(dev
);
8553 /* force update cfg80211 to keep power save mode in sync. BUT this is NOT
8554 * a good solution since there is no protection while changing wdev->os. Best
8555 * way of changing power saving mode is doing it through
8556 * NL80211_CMD_SET_POWER_SAVE
8558 void wl_cfg80211_update_power_mode(struct net_device
*dev
)
8562 err
= wldev_ioctl_get(dev
, WLC_GET_PM
, &pm
, sizeof(pm
));
8564 WL_ERR(("error (%d)\n", err
));
8565 else if (pm
!= -1 && dev
->ieee80211_ptr
)
8566 dev
->ieee80211_ptr
->ps
= (pm
== PM_OFF
) ? false : true;
8569 static __used u32
wl_find_msb(u16 bit16
)
8573 if (bit16
& 0xff00) {
8597 wl_update_pmklist(struct net_device
*dev
, struct wl_pmk_list
*pmk_list
,
8601 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
8602 struct net_device
*primary_dev
= bcmcfg_to_prmry_ndev(cfg
);
8603 int npmkids
= cfg
->pmk_list
->pmkids
.count
;
8605 ASSERT(cfg
->pmk_list
->pmkids
.length
>= (sizeof(u16
)*2));
8607 WL_ERR(("pmk_list is NULL\n"));
8610 /* pmk list is supported only for STA interface i.e. primary interface
8611 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
8613 if (primary_dev
!= dev
) {
8614 WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
8615 " interfaces than primary interface\n"));
8619 WL_DBG(("No of elements %d\n", npmkids
));
8620 for (i
= 0; i
< npmkids
; i
++) {
8621 WL_DBG(("PMKID[%d]: %pM =\n", i
,
8622 &pmk_list
->pmkids
.pmkid
[i
].bssid
));
8623 for (j
= 0; j
< WPA2_PMKID_LEN
; j
++) {
8624 WL_DBG(("%02x\n", pmk_list
->pmkids
.pmkid
[i
].pmkid
[j
]));
8627 if (cfg
->wlc_ver
.wlc_ver_major
>= MIN_PMKID_LIST_V3_FW_MAJOR
) {
8628 pmk_list
->pmkids
.version
= PMKID_LIST_VER_3
;
8629 err
= wldev_iovar_setbuf(dev
, "pmkid_info", (char *)pmk_list
,
8630 sizeof(*pmk_list
), cfg
->ioctl_buf
,
8631 WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
8633 else if (cfg
->wlc_ver
.wlc_ver_major
== MIN_PMKID_LIST_V2_FW_MAJOR
) {
8634 u32 v2_list_size
= (u32
)(sizeof(pmkid_list_v2_t
) + npmkids
*sizeof(pmkid_v2_t
));
8635 pmkid_list_v2_t
*pmkid_v2_list
= (pmkid_list_v2_t
*)MALLOCZ(cfg
->osh
, v2_list_size
);
8636 pmkid_list_v3_t
*spmk_list
= &cfg
->spmk_info_list
->pmkids
;
8638 if (pmkid_v2_list
== NULL
) {
8639 WL_ERR(("failed to allocate pmkid list\n"));
8643 pmkid_v2_list
->version
= PMKID_LIST_VER_2
;
8644 /* Account for version, length and pmkid_v2_t fields */
8645 pmkid_v2_list
->length
= (npmkids
* sizeof(pmkid_v2_t
)) + (2 * sizeof(u16
));
8647 for (i
= 0; i
< npmkids
; i
++) {
8648 /* memcpy_s return checks not needed as buffers are of same size */
8649 (void)memcpy_s(&pmkid_v2_list
->pmkid
[i
].BSSID
,
8650 ETHER_ADDR_LEN
, &pmk_list
->pmkids
.pmkid
[i
].bssid
,
8653 /* copy pmkid if available */
8654 if (pmk_list
->pmkids
.pmkid
[i
].pmkid_len
) {
8655 (void)memcpy_s(pmkid_v2_list
->pmkid
[i
].PMKID
,
8657 pmk_list
->pmkids
.pmkid
[i
].pmkid
,
8658 pmk_list
->pmkids
.pmkid
[i
].pmkid_len
);
8661 if (pmk_list
->pmkids
.pmkid
[i
].pmk_len
) {
8662 (void)memcpy_s(pmkid_v2_list
->pmkid
[i
].pmk
,
8663 pmk_list
->pmkids
.pmkid
[i
].pmk_len
,
8664 pmk_list
->pmkids
.pmkid
[i
].pmk
,
8665 pmk_list
->pmkids
.pmkid
[i
].pmk_len
);
8666 pmkid_v2_list
->pmkid
[i
].pmk_len
= pmk_list
->pmkids
.pmkid
[i
].pmk_len
;
8669 if (pmk_list
->pmkids
.pmkid
[i
].ssid_len
) {
8670 (void)memcpy_s(pmkid_v2_list
->pmkid
[i
].ssid
.ssid
,
8671 pmk_list
->pmkids
.pmkid
[i
].ssid_len
,
8672 pmk_list
->pmkids
.pmkid
[i
].ssid
,
8673 pmk_list
->pmkids
.pmkid
[i
].ssid_len
);
8674 pmkid_v2_list
->pmkid
[i
].ssid
.ssid_len
8675 = pmk_list
->pmkids
.pmkid
[i
].ssid_len
;
8678 (void)memcpy_s(pmkid_v2_list
->pmkid
[i
].fils_cache_id
,
8679 FILS_CACHE_ID_LEN
, &pmk_list
->pmkids
.pmkid
[i
].fils_cache_id
,
8681 for (j
= 0; j
< spmk_list
->count
; j
++) {
8682 if (memcmp(&pmkid_v2_list
->pmkid
[i
].BSSID
,
8683 &spmk_list
->pmkid
[j
].bssid
, ETHER_ADDR_LEN
)) {
8684 continue; /* different MAC */
8686 WL_DBG(("SPMK replace idx:%d bssid: "MACF
" to SSID: %d\n", i
,
8687 ETHER_TO_MACF(pmkid_v2_list
->pmkid
[i
].BSSID
),
8688 spmk_list
->pmkid
[j
].ssid_len
));
8689 bzero(&pmkid_v2_list
->pmkid
[i
].BSSID
, ETHER_ADDR_LEN
);
8690 pmkid_v2_list
->pmkid
[i
].ssid
.ssid_len
=
8691 spmk_list
->pmkid
[j
].ssid_len
;
8692 (void)memcpy_s(pmkid_v2_list
->pmkid
[i
].ssid
.ssid
,
8693 spmk_list
->pmkid
[j
].ssid_len
,
8694 spmk_list
->pmkid
[j
].ssid
,
8695 spmk_list
->pmkid
[j
].ssid_len
);
8697 pmkid_v2_list
->pmkid
[i
].length
= PMKID_ELEM_V2_LENGTH
;
8700 err
= wldev_iovar_setbuf(dev
, "pmkid_info", (char *)pmkid_v2_list
,
8701 v2_list_size
, cfg
->ioctl_buf
,
8702 WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
8703 if (unlikely(err
)) {
8704 WL_ERR(("pmkid_info failed (%d)\n", err
));
8707 MFREE(cfg
->osh
, pmkid_v2_list
, v2_list_size
);
8710 u32 v1_list_size
= (u32
)(sizeof(pmkid_list_v1_t
) + npmkids
*sizeof(pmkid_v1_t
));
8711 pmkid_list_v1_t
*pmkid_v1_list
= (pmkid_list_v1_t
*)MALLOCZ(cfg
->osh
, v1_list_size
);
8712 if (pmkid_v1_list
== NULL
) {
8713 WL_ERR(("failed to allocate pmkid list\n"));
8716 for (i
= 0; i
< npmkids
; i
++) {
8717 /* memcpy_s return checks not needed as buffers are of same size */
8718 (void)memcpy_s(&pmkid_v1_list
->pmkid
[i
].BSSID
,
8719 ETHER_ADDR_LEN
, &pmk_list
->pmkids
.pmkid
[i
].bssid
,
8721 (void)memcpy_s(pmkid_v1_list
->pmkid
[i
].PMKID
,
8722 WPA2_PMKID_LEN
, pmk_list
->pmkids
.pmkid
[i
].pmkid
,
8724 pmkid_v1_list
->npmkid
++;
8726 err
= wldev_iovar_setbuf(dev
, "pmkid_info", (char *)pmkid_v1_list
,
8727 v1_list_size
, cfg
->ioctl_buf
,
8728 WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
8729 if (unlikely(err
)) {
8730 WL_ERR(("pmkid_info failed (%d)\n", err
));
8733 MFREE(cfg
->osh
, pmkid_v1_list
, v1_list_size
);
8738 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8742 wl_cfg80211_set_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
8743 struct cfg80211_pmksa
*pmksa
)
8745 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8748 int npmkids
= cfg
->pmk_list
->pmkids
.count
;
8749 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
8751 if (cfg
->wlc_ver
.wlc_ver_major
>= PMKDB_WLC_VER
) {
8752 err
= wl_cfg80211_update_pmksa(wiphy
, dev
, pmksa
, TRUE
);
8753 if (err
!= BCME_OK
) {
8754 WL_ERR(("wl_cfg80211_set_pmksa err:%d\n", err
));
8759 RETURN_EIO_IF_NOT_UP(cfg
);
8760 BCM_REFERENCE(dhdp
);
8761 DHD_STATLOG_CTRL(dhdp
, ST(INSTALL_PMKSA
), dhd_net2idx(dhdp
->info
, dev
), 0);
8763 for (i
= 0; i
< npmkids
; i
++) {
8764 if (pmksa
->bssid
!= NULL
) {
8765 if (!memcmp(pmksa
->bssid
, &cfg
->pmk_list
->pmkids
.pmkid
[i
].bssid
,
8770 else if (pmksa
->ssid
!= NULL
) {
8771 if (!memcmp(pmksa
->ssid
, &cfg
->pmk_list
->pmkids
.pmkid
[i
].ssid
,
8775 #endif /* WL_FILS */
8777 if (i
< WL_NUM_PMKIDS_MAX
) {
8778 if (pmksa
->bssid
!= NULL
) {
8779 memcpy(&cfg
->pmk_list
->pmkids
.pmkid
[i
].bssid
, pmksa
->bssid
,
8783 else if (pmksa
->ssid
!= NULL
) {
8784 cfg
->pmk_list
->pmkids
.pmkid
[i
].ssid_len
= pmksa
->ssid_len
;
8785 memcpy(&cfg
->pmk_list
->pmkids
.pmkid
[i
].ssid
, pmksa
->ssid
,
8787 memcpy(&cfg
->pmk_list
->pmkids
.pmkid
[i
].fils_cache_id
, pmksa
->cache_id
,
8790 #endif /* WL_FILS */
8791 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS))
8792 if (pmksa
->pmk_len
) {
8793 if (memcpy_s(&cfg
->pmk_list
->pmkids
.pmkid
[i
].pmk
, PMK_LEN_MAX
, pmksa
->pmk
,
8795 WL_ERR(("invalid pmk len = %zu", pmksa
->pmk_len
));
8797 cfg
->pmk_list
->pmkids
.pmkid
[i
].pmk_len
= pmksa
->pmk_len
;
8800 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS) */
8801 /* return check not required as buffer lengths are same */
8802 (void)memcpy_s(cfg
->pmk_list
->pmkids
.pmkid
[i
].pmkid
, WPA2_PMKID_LEN
, pmksa
->pmkid
,
8804 cfg
->pmk_list
->pmkids
.pmkid
[i
].pmkid_len
= WPA2_PMKID_LEN
;
8806 /* set lifetime not to expire in firmware by default.
8807 * Currently, wpa_supplicant control PMKID lifetime on his end. e.g) set 12 hours
8808 * when it expired, wpa_supplicant should call set_pmksa/del_pmksa to update
8809 * corresponding entry.
8811 cfg
->pmk_list
->pmkids
.pmkid
[i
].time_left
= KEY_PERM_PMK
;
8813 cfg
->pmk_list
->pmkids
.length
+= sizeof(pmkid_v3_t
);
8814 cfg
->pmk_list
->pmkids
.count
++;
8820 #if (WL_DBG_LEVEL > 0)
8821 if (pmksa
->bssid
!= NULL
) {
8822 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
8823 &cfg
->pmk_list
->pmkids
.pmkid
[npmkids
- 1].bssid
));
8825 for (i
= 0; i
< WPA2_PMKID_LEN
; i
++) {
8827 cfg
->pmk_list
->pmkids
.pmkid
[npmkids
- 1].
8830 #endif /* (WL_DBG_LEVEL > 0) */
8832 err
= wl_update_pmklist(dev
, cfg
->pmk_list
, err
);
8837 /* sending pmkid_info IOVAR to manipulate PMKID(PMKSA) list in firmware.
8838 * input @pmksa: host given single pmksa info.
8839 * if it's NULL, assume whole list manipulated. e.g) flush all PMKIDs in firmware.
8840 * input @set: TRUE means adding PMKSA operation. FALSE means deleting.
8841 * return: log internal BCME_XXX error, and convert it to -EINVAL to linux generic error code.
8843 static s32
wl_cfg80211_update_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
8844 struct cfg80211_pmksa
*pmksa
, bool set
) {
8846 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8848 pmkid_list_v3_t
*pmk_list
;
8851 RETURN_EIO_IF_NOT_UP(cfg
);
8853 if (cfg
->wlc_ver
.wlc_ver_major
< MIN_PMKID_LIST_V3_FW_MAJOR
) {
8854 WL_DBG(("wlc_ver_major not supported:%d\n", cfg
->wlc_ver
.wlc_ver_major
));
8855 return BCME_VERSION
;
8858 alloc_len
= (uint32
)(OFFSETOF(pmkid_list_v3_t
, pmkid
) + ((pmksa
) ? sizeof(pmkid_v3_t
) : 0));
8859 pmk_list
= (pmkid_list_v3_t
*)MALLOCZ(cfg
->osh
, alloc_len
);
8861 if (pmk_list
== NULL
) {
8865 pmk_list
->version
= PMKID_LIST_VER_3
;
8866 pmk_list
->length
= alloc_len
;
8867 pmk_list
->count
= (pmksa
) ? 1 : 0; // 1 means single entry operation, 0 means whole list.
8868 pmk_list
->flag
= (set
) ? PMKDB_SET_IOVAR
: PMKDB_CLEAR_IOVAR
;
8871 /* controll set/del action by lifetime parameter accordingly.
8872 * if set == TRUE, it's set PMKID action with lifetime permanent.
8873 * if set == FALSE, it's del PMKID action with lifetime zero.
8875 pmk_list
->pmkid
->time_left
= (set
) ? KEY_PERM_PMK
: 0;
8877 eacopy(pmksa
->bssid
, &pmk_list
->pmkid
->bssid
);
8880 err
= memcpy_s(&pmk_list
->pmkid
->pmkid
, sizeof(pmk_list
->pmkid
->pmkid
),
8881 pmksa
->pmkid
, WPA2_PMKID_LEN
);
8885 pmk_list
->pmkid
->pmkid_len
= WPA2_PMKID_LEN
;
8887 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
8889 err
= memcpy_s(&pmk_list
->pmkid
->pmk
, sizeof(pmk_list
->pmkid
->pmk
),
8890 pmksa
->pmk
, pmksa
->pmk_len
);
8894 pmk_list
->pmkid
->pmk_len
= pmksa
->pmk_len
;
8897 err
= memcpy_s(&pmk_list
->pmkid
->ssid
, sizeof(pmk_list
->pmkid
->ssid
),
8898 pmksa
->ssid
, pmksa
->ssid_len
);
8902 pmk_list
->pmkid
->ssid_len
= pmksa
->ssid_len
;
8904 if (pmksa
->cache_id
) {
8905 pmk_list
->pmkid
->fils_cache_id
= *(const uint16
*)pmksa
->cache_id
;
8907 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
8910 if (wl_dbg_level
& WL_DBG_DBG
) {
8911 prhex("pmklist_data", (char *)pmk_list
, alloc_len
);
8914 err
= wldev_iovar_setbuf(dev
, "pmkdb", (char *)pmk_list
,
8915 alloc_len
, cfg
->ioctl_buf
,
8916 WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
8917 if (unlikely(err
)) {
8918 WL_ERR(("pmkdb set failed. err:%d\n", err
));
8922 MFREE(cfg
->osh
, pmk_list
, alloc_len
);
8927 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8931 wl_cfg80211_del_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
8932 struct cfg80211_pmksa
*pmksa
)
8934 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8937 int npmkids
= cfg
->pmk_list
->pmkids
.count
;
8938 RETURN_EIO_IF_NOT_UP(cfg
);
8941 WL_ERR(("pmksa is not initialized\n"));
8944 if (cfg
->wlc_ver
.wlc_ver_major
>= PMKDB_WLC_VER
) {
8945 err
= wl_cfg80211_update_pmksa(wiphy
, dev
, pmksa
, FALSE
);
8946 if (err
!= BCME_OK
) {
8947 WL_ERR(("wl_cfg80211_del_pmksa err:%d\n", err
));
8953 /* nmpkids = 0, nothing to delete */
8954 WL_DBG(("npmkids=0. Skip del\n"));
8958 #if (WL_DBG_LEVEL > 0)
8960 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
8964 else if (pmksa
->ssid
) {
8965 WL_DBG(("FILS: del_pmksa for ssid: "));
8966 for (i
= 0; i
< pmksa
->ssid_len
; i
++) {
8967 WL_DBG(("%c", pmksa
->ssid
[i
]));
8971 #endif /* WL_FILS */
8973 for (i
= 0; i
< WPA2_PMKID_LEN
; i
++) {
8974 WL_DBG(("%02x\n", pmksa
->pmkid
[i
]));
8977 #endif /* (WL_DBG_LEVEL > 0) */
8979 for (i
= 0; i
< npmkids
; i
++) {
8982 (pmksa
->bssid
, &cfg
->pmk_list
->pmkids
.pmkid
[i
].bssid
,
8988 else if (pmksa
->ssid
) {
8990 (pmksa
->ssid
, &cfg
->pmk_list
->pmkids
.pmkid
[i
].ssid
,
8995 #endif /* WL_FILS */
8997 if ((npmkids
> 0) && (i
< npmkids
)) {
8998 bzero(&cfg
->pmk_list
->pmkids
.pmkid
[i
], sizeof(pmkid_v3_t
));
8999 for (; i
< (npmkids
- 1); i
++) {
9000 (void)memcpy_s(&cfg
->pmk_list
->pmkids
.pmkid
[i
],
9002 &cfg
->pmk_list
->pmkids
.pmkid
[i
+ 1],
9003 sizeof(pmkid_v3_t
));
9006 cfg
->pmk_list
->pmkids
.length
-= sizeof(pmkid_v3_t
);
9007 cfg
->pmk_list
->pmkids
.count
--;
9013 /* current wl_update_pmklist() doesn't delete corresponding PMKID entry.
9014 * inside firmware. So we need to issue delete action explicitely through
9017 err
= wl_cfg80211_update_pmksa(wiphy
, dev
, pmksa
, FALSE
);
9018 /* intentional fall through even on error.
9019 * it should work above MIN_PMKID_LIST_V3_FW_MAJOR, otherwise let ignore it.
9022 err
= wl_update_pmklist(dev
, cfg
->pmk_list
, err
);
9028 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
9032 wl_cfg80211_flush_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
)
9034 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
9036 RETURN_EIO_IF_NOT_UP(cfg
);
9037 if (cfg
->wlc_ver
.wlc_ver_major
>= PMKDB_WLC_VER
) {
9038 /* NULL pmksa means delete whole PMKSA list */
9039 err
= wl_cfg80211_update_pmksa(wiphy
, dev
, NULL
, FALSE
);
9040 if (err
!= BCME_OK
) {
9041 WL_ERR(("wl_cfg80211_flush_pmksa err:%d\n", err
));
9045 bzero(cfg
->pmk_list
, sizeof(*cfg
->pmk_list
));
9046 cfg
->pmk_list
->pmkids
.length
= OFFSETOF(pmkid_list_v3_t
, pmkid
);
9047 cfg
->pmk_list
->pmkids
.count
= 0;
9048 cfg
->pmk_list
->pmkids
.version
= PMKID_LIST_VER_3
;
9049 err
= wl_update_pmklist(dev
, cfg
->pmk_list
, err
);
9054 wl_cfg80211_afx_handler(struct work_struct
*work
)
9056 struct afx_hdl
*afx_instance
;
9057 struct bcm_cfg80211
*cfg
;
9060 BCM_SET_CONTAINER_OF(afx_instance
, work
, struct afx_hdl
, work
);
9062 cfg
= wl_get_cfg(afx_instance
->dev
);
9063 if (cfg
!= NULL
&& cfg
->afx_hdl
->is_active
) {
9064 if (cfg
->afx_hdl
->is_listen
&& cfg
->afx_hdl
->my_listen_chan
) {
9065 ret
= wl_cfgp2p_discover_listen(cfg
, cfg
->afx_hdl
->my_listen_chan
,
9066 (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
9068 ret
= wl_cfgp2p_act_frm_search(cfg
, cfg
->afx_hdl
->dev
,
9069 cfg
->afx_hdl
->bssidx
, cfg
->afx_hdl
->peer_listen_chan
,
9072 if (unlikely(ret
!= BCME_OK
)) {
9073 WL_ERR(("ERROR occurred! returned value is (%d)\n", ret
));
9074 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
))
9075 complete(&cfg
->act_frm_scan
);
9082 wl_cfg80211_af_searching_channel(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
9084 u32 max_retry
= WL_CHANNEL_SYNC_RETRY
;
9085 bool is_p2p_gas
= false;
9090 WL_DBG((" enter ) \n"));
9092 wl_set_drv_status(cfg
, FINDING_COMMON_CHANNEL
, dev
);
9093 cfg
->afx_hdl
->is_active
= TRUE
;
9095 if (cfg
->afx_hdl
->pending_tx_act_frm
) {
9096 wl_action_frame_t
*action_frame
;
9097 action_frame
= &(cfg
->afx_hdl
->pending_tx_act_frm
->action_frame
);
9098 if (wl_cfgp2p_is_p2p_gas_action(action_frame
->data
, action_frame
->len
))
9102 /* Loop to wait until we find a peer's channel or the
9103 * pending action frame tx is cancelled.
9105 while ((cfg
->afx_hdl
->retry
< max_retry
) &&
9106 (cfg
->afx_hdl
->peer_chan
== WL_INVALID
)) {
9107 cfg
->afx_hdl
->is_listen
= FALSE
;
9108 wl_set_drv_status(cfg
, SCANNING
, dev
);
9109 WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
9110 cfg
->afx_hdl
->retry
));
9111 /* search peer on peer's listen channel */
9112 schedule_work(&cfg
->afx_hdl
->work
);
9113 wait_for_completion_timeout(&cfg
->act_frm_scan
,
9114 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX
));
9116 if ((cfg
->afx_hdl
->peer_chan
!= WL_INVALID
) ||
9117 !(wl_get_drv_status(cfg
, FINDING_COMMON_CHANNEL
, dev
)))
9123 if (cfg
->afx_hdl
->my_listen_chan
) {
9124 WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
9125 cfg
->afx_hdl
->my_listen_chan
));
9126 /* listen on my listen channel */
9127 cfg
->afx_hdl
->is_listen
= TRUE
;
9128 schedule_work(&cfg
->afx_hdl
->work
);
9129 wait_for_completion_timeout(&cfg
->act_frm_scan
,
9130 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX
));
9132 if ((cfg
->afx_hdl
->peer_chan
!= WL_INVALID
) ||
9133 !(wl_get_drv_status(cfg
, FINDING_COMMON_CHANNEL
, dev
)))
9136 cfg
->afx_hdl
->retry
++;
9138 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg
);
9141 cfg
->afx_hdl
->is_active
= FALSE
;
9143 wl_clr_drv_status(cfg
, SCANNING
, dev
);
9144 wl_clr_drv_status(cfg
, FINDING_COMMON_CHANNEL
, dev
);
9146 return (cfg
->afx_hdl
->peer_chan
);
9149 struct p2p_config_af_params
{
9150 s32 max_tx_retry
; /* max tx retry count if tx no ack */
9151 #ifdef WL_CFG80211_GON_COLLISION
9152 /* drop tx go nego request if go nego collision occurs */
9155 #ifdef WL_CFG80211_SYNC_GON
9156 /* WAR: dongle does not keep the dwell time of 'actframe' sometime.
9157 * if extra_listen is set, keep the dwell time to get af response frame
9161 bool search_channel
; /* 1: search peer's channel to send af */
9165 wl_cfg80211_config_p2p_pub_af_tx(struct wiphy
*wiphy
,
9166 wl_action_frame_t
*action_frame
, wl_af_params_t
*af_params
,
9167 struct p2p_config_af_params
*config_af_params
)
9170 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
9171 wifi_p2p_pub_act_frame_t
*act_frm
=
9172 (wifi_p2p_pub_act_frame_t
*) (action_frame
->data
);
9174 /* initialize default value */
9175 #ifdef WL_CFG80211_GON_COLLISION
9176 config_af_params
->drop_tx_req
= false;
9178 #ifdef WL_CFG80211_SYNC_GON
9179 config_af_params
->extra_listen
= true;
9181 config_af_params
->search_channel
= false;
9182 config_af_params
->max_tx_retry
= WL_AF_TX_MAX_RETRY
;
9183 cfg
->next_af_subtype
= WL_PUB_AF_STYPE_INVALID
;
9185 switch (act_frm
->subtype
) {
9186 case P2P_PAF_GON_REQ
: {
9187 /* Disable he if peer does not support before starting GONEG */
9188 WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
9189 wl_set_p2p_status(cfg
, GO_NEG_PHASE
);
9191 config_af_params
->search_channel
= true;
9192 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
9194 /* increase dwell time to wait for RESP frame */
9195 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
9197 #ifdef WL_CFG80211_GON_COLLISION
9198 config_af_params
->drop_tx_req
= true;
9199 #endif /* WL_CFG80211_GON_COLLISION */
9202 case P2P_PAF_GON_RSP
: {
9203 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
9204 /* increase dwell time to wait for CONF frame */
9205 /* WAR : 100ms is added because kernel spent more time in some case.
9206 * Kernel should be fixed.
9208 af_params
->dwell_time
= WL_MED_DWELL_TIME
+ 100;
9211 case P2P_PAF_GON_CONF
: {
9212 /* If we reached till GO Neg confirmation reset the filter */
9213 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
9214 wl_clr_p2p_status(cfg
, GO_NEG_PHASE
);
9216 /* minimize dwell time */
9217 af_params
->dwell_time
= WL_MIN_DWELL_TIME
;
9219 #ifdef WL_CFG80211_GON_COLLISION
9220 /* if go nego formation done, clear it */
9221 cfg
->block_gon_req_tx_count
= 0;
9222 cfg
->block_gon_req_rx_count
= 0;
9223 #endif /* WL_CFG80211_GON_COLLISION */
9224 #ifdef WL_CFG80211_SYNC_GON
9225 config_af_params
->extra_listen
= false;
9226 #endif /* WL_CFG80211_SYNC_GON */
9229 case P2P_PAF_INVITE_REQ
: {
9230 config_af_params
->search_channel
= true;
9231 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
9233 /* increase dwell time */
9234 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
9237 case P2P_PAF_INVITE_RSP
:
9238 /* minimize dwell time */
9239 af_params
->dwell_time
= WL_MIN_DWELL_TIME
;
9240 #ifdef WL_CFG80211_SYNC_GON
9241 config_af_params
->extra_listen
= false;
9242 #endif /* WL_CFG80211_SYNC_GON */
9244 case P2P_PAF_DEVDIS_REQ
: {
9245 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm
->elts
[0],
9246 action_frame
->len
)) {
9247 config_af_params
->search_channel
= true;
9250 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
9251 /* maximize dwell time to wait for RESP frame */
9252 af_params
->dwell_time
= WL_LONG_DWELL_TIME
;
9255 case P2P_PAF_DEVDIS_RSP
:
9256 /* minimize dwell time */
9257 af_params
->dwell_time
= WL_MIN_DWELL_TIME
;
9258 #ifdef WL_CFG80211_SYNC_GON
9259 config_af_params
->extra_listen
= false;
9260 #endif /* WL_CFG80211_SYNC_GON */
9262 case P2P_PAF_PROVDIS_REQ
: {
9263 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm
->elts
[0],
9264 action_frame
->len
)) {
9265 config_af_params
->search_channel
= true;
9268 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
9269 /* increase dwell time to wait for RESP frame */
9270 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
9273 case P2P_PAF_PROVDIS_RSP
: {
9274 /* wpa_supplicant send go nego req right after prov disc */
9275 cfg
->next_af_subtype
= P2P_PAF_GON_REQ
;
9276 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
9277 #ifdef WL_CFG80211_SYNC_GON
9278 config_af_params
->extra_listen
= false;
9279 #endif /* WL_CFG80211_SYNC_GON */
9283 WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
9290 #if defined(WL11U) && defined(WL_HOST_AF_DFS_CHECK)
9292 wl_cfg80211_check_DFS_channel(struct bcm_cfg80211
*cfg
, wl_af_params_t
*af_params
,
9293 void *frame
, u16 frame_len
)
9295 struct wl_scan_results
*bss_list
;
9296 wl_bss_info_t
*bi
= NULL
;
9297 bool result
= false;
9299 chanspec_t chanspec
;
9301 /* If DFS channel is 52~148, check to block it or not */
9303 (af_params
->channel
>= 52 && af_params
->channel
<= 148)) {
9304 if (!wl_cfgp2p_is_p2p_action(frame
, frame_len
)) {
9305 bss_list
= cfg
->bss_list
;
9306 bi
= next_bss(bss_list
, bi
);
9307 for_each_bss(bss_list
, bi
, i
) {
9308 chanspec
= wl_chspec_driver_to_host(bi
->chanspec
);
9309 if (CHSPEC_IS5G(chanspec
) &&
9310 ((bi
->ctl_ch
? bi
->ctl_ch
: CHSPEC_CHANNEL(chanspec
))
9311 == af_params
->channel
)) {
9312 result
= true; /* do not block the action frame */
9322 WL_DBG(("result=%s", result
?"true":"false"));
9325 #endif /* WL11U && WL_HOST_AF_DFS_CHECK */
9327 wl_cfg80211_check_dwell_overflow(int32 requested_dwell
, ulong dwell_jiffies
)
9329 if ((requested_dwell
& CUSTOM_RETRY_MASK
) &&
9330 (jiffies_to_msecs(jiffies
- dwell_jiffies
) >
9331 (requested_dwell
& ~CUSTOM_RETRY_MASK
))) {
9332 WL_ERR(("Action frame TX retry time over dwell time!\n"));
9339 wl_cfg80211_send_action_frame(struct wiphy
*wiphy
, struct net_device
*dev
,
9340 bcm_struct_cfgdev
*cfgdev
, wl_af_params_t
*af_params
,
9341 wl_action_frame_t
*action_frame
, u16 action_frame_len
, s32 bssidx
)
9344 struct net_device
*ndev
= NULL
;
9346 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
9348 u8 category
, action
;
9350 struct p2p_config_af_params config_af_params
;
9351 struct net_info
*netinfo
;
9353 ulong off_chan_started_jiffies
= 0;
9355 ulong dwell_jiffies
= 0;
9356 bool dwell_overflow
= false;
9357 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
9359 int32 requested_dwell
= af_params
->dwell_time
;
9361 /* Add the default dwell time
9362 * Dwell time to stay off-channel to wait for a response action frame
9363 * after transmitting an GO Negotiation action frame
9365 af_params
->dwell_time
= WL_DEFAULT_DWELL_TIME
;
9368 #if defined(WL_CFG80211_P2P_DEV_IF)
9371 ndev
= ndev_to_cfgdev(cfgdev
);
9372 #endif /* WL_CFG80211_P2P_DEV_IF */
9375 category
= action_frame
->data
[DOT11_ACTION_CAT_OFF
];
9376 action
= action_frame
->data
[DOT11_ACTION_ACT_OFF
];
9378 /* initialize variables */
9380 cfg
->next_af_subtype
= WL_PUB_AF_STYPE_INVALID
;
9381 config_af_params
.max_tx_retry
= WL_AF_TX_MAX_RETRY
;
9382 config_af_params
.search_channel
= false;
9383 #ifdef WL_CFG80211_GON_COLLISION
9384 config_af_params
.drop_tx_req
= false;
9386 #ifdef WL_CFG80211_SYNC_GON
9387 config_af_params
.extra_listen
= false;
9390 /* config parameters */
9391 /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
9392 if (category
== DOT11_ACTION_CAT_PUBLIC
) {
9393 if (wl_cfg80211_is_dpp_frame((void *)action_frame
->data
, action_frame
->len
)) {
9394 wl_dpp_pa_frame_t
*pa
= (wl_dpp_pa_frame_t
*)action_frame
->data
;
9395 config_af_params
.max_tx_retry
= WL_AF_TX_MAX_RETRY
;
9396 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
9397 cfg
->need_wait_afrx
= true;
9398 /* once matching frame is found in rx, abort dwell (upper layer
9401 if (pa
->ftype
== DPP_AUTH_REQ
) {
9402 cfg
->next_af_subtype
= DPP_AUTH_RESP
;
9403 } else if (pa
->ftype
== DPP_AUTH_RESP
) {
9404 cfg
->next_af_subtype
= DPP_AUTH_CONF
;
9406 cfg
->next_af_subtype
= WL_PUB_AF_STYPE_INVALID
;
9407 cfg
->need_wait_afrx
= false;
9409 } else if (wl_cfg80211_is_dpp_gas_action(
9410 (void *)action_frame
->data
, action_frame
->len
)) {
9411 config_af_params
.max_tx_retry
= WL_AF_TX_MAX_RETRY
;
9412 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
9413 cfg
->need_wait_afrx
= true;
9414 config_af_params
.search_channel
= false;
9416 if (requested_dwell
== 0) {
9417 /* Use minimal dwell to take care of Ack */
9418 af_params
->dwell_time
= WL_MIN_DWELL_TIME
;
9420 } else if ((action
== P2P_PUB_AF_ACTION
) &&
9421 (action_frame_len
>= sizeof(wifi_p2p_pub_act_frame_t
))) {
9422 /* p2p public action frame process */
9423 if (BCME_OK
!= wl_cfg80211_config_p2p_pub_af_tx(wiphy
,
9424 action_frame
, af_params
, &config_af_params
)) {
9425 /* just send unknown subtype frame with default parameters. */
9426 WL_DBG(("Unknown subtype.\n"));
9429 #ifdef WL_CFG80211_GON_COLLISION
9430 if (config_af_params
.drop_tx_req
) {
9431 if (cfg
->block_gon_req_tx_count
) {
9432 /* drop gon req tx action frame */
9433 WL_DBG(("Drop gon req tx action frame: count %d\n",
9434 cfg
->block_gon_req_tx_count
));
9438 #endif /* WL_CFG80211_GON_COLLISION */
9439 } else if (action_frame_len
>= sizeof(wifi_p2psd_gas_pub_act_frame_t
)) {
9440 /* service discovery process */
9441 if (action
== P2PSD_ACTION_ID_GAS_IREQ
||
9442 action
== P2PSD_ACTION_ID_GAS_CREQ
) {
9443 /* configure service discovery query frame */
9444 config_af_params
.search_channel
= true;
9446 /* save next af suptype to cancel remained dwell time */
9447 cfg
->next_af_subtype
= action
+ 1;
9449 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
9450 if (requested_dwell
& CUSTOM_RETRY_MASK
) {
9451 config_af_params
.max_tx_retry
=
9452 (requested_dwell
& CUSTOM_RETRY_MASK
) >> 24;
9453 af_params
->dwell_time
=
9454 (requested_dwell
& ~CUSTOM_RETRY_MASK
);
9455 WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
9456 config_af_params
.max_tx_retry
,
9457 af_params
->dwell_time
));
9459 } else if (action
== P2PSD_ACTION_ID_GAS_IRESP
||
9460 action
== P2PSD_ACTION_ID_GAS_CRESP
) {
9461 /* configure service discovery response frame */
9462 af_params
->dwell_time
= WL_MIN_DWELL_TIME
;
9464 WL_DBG(("Unknown action type: %d\n", action
));
9467 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
9468 category
, action
, action_frame_len
));
9470 } else if (category
== P2P_AF_CATEGORY
) {
9471 /* do not configure anything. it will be sent with a default configuration */
9473 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
9475 if (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
9476 wl_clr_drv_status(cfg
, SENDING_ACT_FRM
, dev
);
9481 netinfo
= wl_get_netinfo_by_wdev(cfg
, cfgdev_to_wdev(cfgdev
));
9482 /* validate channel and p2p ies */
9483 if (config_af_params
.search_channel
&&
9484 IS_P2P_SOCIAL(CHSPEC_CHANNEL(af_params
->channel
)) &&
9485 netinfo
&& netinfo
->bss
.ies
.probe_req_ie_len
) {
9486 config_af_params
.search_channel
= true;
9488 config_af_params
.search_channel
= false;
9491 if (ndev
== bcmcfg_to_prmry_ndev(cfg
))
9492 config_af_params
.search_channel
= false;
9496 /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
9497 if (wl_get_drv_status(cfg
, CONNECTING
, bcmcfg_to_prmry_ndev(cfg
))) {
9502 /* if scan is ongoing, abort current scan. */
9503 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
9504 wl_cfg80211_cancel_scan(cfg
);
9507 /* Abort P2P listen */
9508 if (discover_cfgdev(cfgdev
, cfg
)) {
9509 if (cfg
->p2p_supported
&& cfg
->p2p
) {
9510 wl_cfgp2p_set_p2p_mode(cfg
, WL_P2P_DISC_ST_SCAN
, 0, 0,
9511 wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
));
9515 #if defined(WL11U) && defined(WL_HOST_AF_DFS_CHECK)
9516 /* handling DFS channel exceptions */
9517 if (!wl_cfg80211_check_DFS_channel(cfg
, af_params
, action_frame
->data
, action_frame
->len
)) {
9518 return false; /* the action frame was blocked */
9520 #endif /* WL11U && WL_HOST_AF_DFS_CHECK */
9522 /* set status and destination address before sending af */
9523 if (cfg
->next_af_subtype
!= WL_PUB_AF_STYPE_INVALID
) {
9524 /* set this status to cancel the remained dwell time in rx process */
9525 wl_set_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, dev
);
9527 wl_set_drv_status(cfg
, SENDING_ACT_FRM
, dev
);
9528 memcpy(cfg
->afx_hdl
->tx_dst_addr
.octet
,
9529 af_params
->action_frame
.da
.octet
,
9530 sizeof(cfg
->afx_hdl
->tx_dst_addr
.octet
));
9532 /* save af_params for rx process */
9533 cfg
->afx_hdl
->pending_tx_act_frm
= af_params
;
9535 if (wl_cfgp2p_is_p2p_gas_action(action_frame
->data
, action_frame
->len
)) {
9536 WL_DBG(("Set GAS action frame config.\n"));
9537 config_af_params
.search_channel
= false;
9538 config_af_params
.max_tx_retry
= 1;
9541 /* search peer's channel */
9542 if (config_af_params
.search_channel
) {
9543 /* initialize afx_hdl */
9544 if ((cfg
->afx_hdl
->bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
9545 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
9548 cfg
->afx_hdl
->dev
= dev
;
9549 cfg
->afx_hdl
->retry
= 0;
9550 cfg
->afx_hdl
->peer_chan
= WL_INVALID
;
9552 if (wl_cfg80211_af_searching_channel(cfg
, dev
) == WL_INVALID
) {
9553 WL_ERR(("couldn't find peer's channel.\n"));
9554 wl_cfgp2p_print_actframe(true, action_frame
->data
, action_frame
->len
,
9555 af_params
->channel
);
9556 /* Even if we couldn't find peer channel, try to send the frame
9557 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
9558 * respond to probe request (Ideally it has to be in listen and
9559 * responsd to probe request). However if we send Go neg req, the
9560 * peer is sending GO-neg resp. So instead of giving up here, just
9561 * proceed and attempt sending out the action frame.
9565 wl_clr_drv_status(cfg
, SCANNING
, cfg
->afx_hdl
->dev
);
9567 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
9568 * but after the check of piggyback algorithm.
9569 * To take care of current piggback algo, lets abort the scan here itself.
9571 wl_cfg80211_cancel_scan(cfg
);
9572 /* Suspend P2P discovery's search-listen to prevent it from
9573 * starting a scan or changing the channel.
9575 if ((wl_cfgp2p_discover_enable_search(cfg
, false)) < 0) {
9576 WL_ERR(("Can not disable discovery mode\n"));
9580 /* update channel */
9581 if (cfg
->afx_hdl
->peer_chan
!= WL_INVALID
) {
9582 af_params
->channel
= cfg
->afx_hdl
->peer_chan
;
9583 WL_ERR(("Attempt tx on peer listen channel:%d ",
9584 cfg
->afx_hdl
->peer_chan
));
9586 WL_ERR(("Attempt tx with the channel provided by userspace."
9587 "Channel: %d\n", af_params
->channel
));
9592 off_chan_started_jiffies
= jiffies
;
9595 wl_cfgp2p_print_actframe(true, action_frame
->data
, action_frame
->len
, af_params
->channel
);
9597 wl_cfgp2p_need_wait_actfrmae(cfg
, action_frame
->data
, action_frame
->len
, true);
9599 dwell_jiffies
= jiffies
;
9600 /* Now send a tx action frame */
9601 ack
= wl_cfgp2p_tx_action_frame(cfg
, dev
, af_params
, bssidx
) ? false : true;
9602 dwell_overflow
= wl_cfg80211_check_dwell_overflow(requested_dwell
, dwell_jiffies
);
9604 /* if failed, retry it. tx_retry_max value is configure by .... */
9605 while ((ack
== false) && (tx_retry
++ < config_af_params
.max_tx_retry
) &&
9608 if (af_params
->channel
) {
9609 if (jiffies_to_msecs(jiffies
- off_chan_started_jiffies
) >
9610 OFF_CHAN_TIME_THRESHOLD_MS
) {
9611 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg
);
9612 off_chan_started_jiffies
= jiffies
;
9614 OSL_SLEEP(AF_RETRY_DELAY_TIME
);
9617 ack
= wl_cfgp2p_tx_action_frame(cfg
, dev
, af_params
, bssidx
) ?
9619 dwell_overflow
= wl_cfg80211_check_dwell_overflow(requested_dwell
, dwell_jiffies
);
9623 WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry
));
9625 WL_DBG(("Complete to send action frame\n"));
9627 /* Clear SENDING_ACT_FRM after all sending af is done */
9628 wl_clr_drv_status(cfg
, SENDING_ACT_FRM
, dev
);
9630 #ifdef WL_CFG80211_SYNC_GON
9631 /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
9632 * if we coundn't get the next action response frame and dongle does not keep
9633 * the dwell time, go to listen state again to get next action response frame.
9635 if (ack
&& config_af_params
.extra_listen
&&
9636 #ifdef WL_CFG80211_GON_COLLISION
9637 !cfg
->block_gon_req_tx_count
&&
9638 #endif /* WL_CFG80211_GON_COLLISION */
9639 wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM
) &&
9640 cfg
->af_sent_channel
== cfg
->afx_hdl
->my_listen_chan
) {
9641 s32 extar_listen_time
;
9643 extar_listen_time
= af_params
->dwell_time
-
9644 jiffies_to_msecs(jiffies
- cfg
->af_tx_sent_jiffies
);
9646 if (extar_listen_time
> 50) {
9647 wl_set_drv_status(cfg
, WAITING_NEXT_ACT_FRM_LISTEN
, dev
);
9648 WL_DBG(("Wait more time! actual af time:%d,"
9649 "calculated extar listen:%d\n",
9650 af_params
->dwell_time
, extar_listen_time
));
9651 if (wl_cfgp2p_discover_listen(cfg
, cfg
->af_sent_channel
,
9652 extar_listen_time
+ 100) == BCME_OK
) {
9653 wait_for_completion_timeout(&cfg
->wait_next_af
,
9654 msecs_to_jiffies(extar_listen_time
+ 100 + 300));
9656 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM_LISTEN
, dev
);
9659 #endif /* WL_CFG80211_SYNC_GON */
9660 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, dev
);
9662 cfg
->afx_hdl
->pending_tx_act_frm
= NULL
;
9665 WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
9666 cfg
->afx_hdl
->my_listen_chan
));
9668 WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
9669 cfg
->afx_hdl
->my_listen_chan
));
9672 #ifdef WL_CFG80211_GON_COLLISION
9673 if (cfg
->block_gon_req_tx_count
) {
9674 cfg
->block_gon_req_tx_count
--;
9675 /* if ack is ture, supplicant will wait more time(100ms).
9676 * so we will return it as a success to get more time .
9680 #endif /* WL_CFG80211_GON_COLLISION */
9684 #define MAX_NUM_OF_ASSOCIATED_DEV 64
9686 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9687 wl_cfg80211_mgmt_tx(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
,
9688 struct cfg80211_mgmt_tx_params
*params
, u64
*cookie
)
9690 wl_cfg80211_mgmt_tx(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
,
9691 struct ieee80211_channel
*channel
, bool offchan
,
9692 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
9693 enum nl80211_channel_type channel_type
,
9694 bool channel_type_valid
,
9695 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
9696 unsigned int wait
, const u8
* buf
, size_t len
,
9697 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
9700 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
9701 bool dont_wait_for_ack
,
9704 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9706 wl_action_frame_t
*action_frame
;
9707 wl_af_params_t
*af_params
;
9709 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9710 struct ieee80211_channel
*channel
= params
->chan
;
9711 const u8
*buf
= params
->buf
;
9712 size_t len
= params
->len
;
9714 const struct ieee80211_mgmt
*mgmt
;
9715 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
9716 struct net_device
*dev
= NULL
;
9721 s8 eabuf
[ETHER_ADDR_STR_LEN
];
9723 WL_DBG(("Enter \n"));
9725 if (len
> ACTION_FRAME_SIZE
) {
9726 WL_ERR(("bad length:%zu\n", len
));
9730 PRINT_WDEV_INFO(cfgdev
);
9731 #endif /* DHD_IFDEBUG */
9733 dev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
9736 WL_ERR(("dev is NULL\n"));
9740 /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
9741 if (discover_cfgdev(cfgdev
, cfg
)) {
9742 if (!cfg
->p2p_supported
|| !cfg
->p2p
) {
9743 WL_ERR(("P2P doesn't setup completed yet\n"));
9746 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
9749 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, cfgdev_to_wdev(cfgdev
))) < 0) {
9750 WL_ERR(("Find p2p index failed\n"));
9755 WL_DBG(("TX target bssidx=%d\n", bssidx
));
9757 if (p2p_is_on(cfg
)) {
9758 /* Suspend P2P discovery search-listen to prevent it from changing the
9761 if ((err
= wl_cfgp2p_discover_enable_search(cfg
, false)) < 0) {
9762 WL_ERR(("Can not disable discovery mode\n"));
9767 id
= cfg
->send_action_id
++;
9769 id
= cfg
->send_action_id
++;
9771 mgmt
= (const struct ieee80211_mgmt
*)buf
;
9772 if (ieee80211_is_mgmt(mgmt
->frame_control
)) {
9773 if (ieee80211_is_probe_resp(mgmt
->frame_control
)) {
9774 s32 ie_offset
= DOT11_MGMT_HDR_LEN
+ DOT11_BCN_PRB_FIXED_LEN
;
9775 s32 ie_len
= len
- ie_offset
;
9776 if ((dev
== bcmcfg_to_prmry_ndev(cfg
)) && cfg
->p2p
) {
9777 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
9779 wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
9780 VNDR_IE_PRBRSP_FLAG
, (const u8
*)(buf
+ ie_offset
), ie_len
);
9781 cfg80211_mgmt_tx_status(cfgdev
, *cookie
, buf
, len
, true, GFP_KERNEL
);
9782 #if defined(P2P_IE_MISSING_FIX)
9783 if (!cfg
->p2p_prb_noti
) {
9784 cfg
->p2p_prb_noti
= true;
9785 WL_DBG(("wl_cfg80211_mgmt_tx: TX 802_1X Probe"
9786 " Response first time.\n"));
9790 } else if (ieee80211_is_disassoc(mgmt
->frame_control
) ||
9791 ieee80211_is_deauth(mgmt
->frame_control
)) {
9792 char mac_buf
[MAX_NUM_OF_ASSOCIATED_DEV
*
9793 sizeof(struct ether_addr
) + sizeof(uint
)] = {0};
9794 int num_associated
= 0;
9795 struct maclist
*assoc_maclist
= (struct maclist
*)mac_buf
;
9796 if (!bcmp((const uint8
*)BSSID_BROADCAST
,
9797 (const struct ether_addr
*)mgmt
->da
, ETHER_ADDR_LEN
)) {
9798 assoc_maclist
->count
= MAX_NUM_OF_ASSOCIATED_DEV
;
9799 err
= wldev_ioctl_get(dev
, WLC_GET_ASSOCLIST
,
9800 assoc_maclist
, sizeof(mac_buf
));
9802 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err
));
9804 num_associated
= assoc_maclist
->count
;
9806 memcpy(scb_val
.ea
.octet
, mgmt
->da
, ETH_ALEN
);
9807 scb_val
.val
= mgmt
->u
.disassoc
.reason_code
;
9808 err
= wldev_ioctl_set(dev
, WLC_SCB_DEAUTHENTICATE_FOR_REASON
, &scb_val
,
9811 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err
));
9812 WL_ERR(("Disconnect STA : " MACDBG
" scb_val.val %d\n",
9813 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr
*)mgmt
->da
,
9814 eabuf
)), scb_val
.val
));
9816 /* WAR Wait for the deauth event to come,
9817 * supplicant will do the delete iface immediately
9818 * and we will have problem in sending
9819 * deauth frame if we delete the bss in firmware.
9820 * But we do not need additional delays for this WAR
9821 * during P2P connection.
9823 * Supplicant call this function with BCAST after
9824 * delete all GC stations with each addr.
9825 * So, 400 ms delay can be called only once when GO disconnect all GC
9827 if (num_associated
> 0 && ETHER_ISBCAST(mgmt
->da
))
9830 cfg80211_mgmt_tx_status(cfgdev
, *cookie
, buf
, len
, true, GFP_KERNEL
);
9833 } else if (ieee80211_is_action(mgmt
->frame_control
)) {
9834 /* Abort the dwell time of any previous off-channel
9835 * action frame that may be still in effect. Sending
9836 * off-channel action frames relies on the driver's
9837 * scan engine. If a previous off-channel action frame
9838 * tx is still in progress (including the dwell time),
9839 * then this new action frame will not be sent out.
9841 /* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
9842 * And previous off-channel action frame must be ended before new af tx.
9844 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9845 wl_cfg80211_cancel_scan(cfg
);
9846 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9848 #ifdef WL_CLIENT_SAE
9849 else if (ieee80211_is_auth(mgmt
->frame_control
)) {
9851 wl_assoc_mgr_cmd_t
*cmd
;
9856 if ((dev
== bcmcfg_to_prmry_ndev(cfg
)) && cfg
->p2p
) {
9857 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
9859 param_len
= sizeof(wl_assoc_mgr_cmd_t
) + len
;
9860 ambuf
= MALLOCZ(cfg
->osh
, param_len
);
9861 if (ambuf
== NULL
) {
9862 WL_ERR(("unable to allocate frame\n"));
9865 cmd
= (wl_assoc_mgr_cmd_t
*)ambuf
;
9866 cmd
->version
= WL_ASSOC_MGR_CURRENT_VERSION
;
9868 cmd
->cmd
= WL_ASSOC_MGR_CMD_SEND_AUTH
;
9869 memcpy(&cmd
->params
, buf
, len
);
9870 err
= wldev_iovar_setbuf(dev
, "assoc_mgr_cmd", ambuf
, param_len
,
9871 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
9872 if (unlikely(err
)) {
9873 WL_ERR(("Failed to send auth(%d)\n", err
));
9876 MFREE(cfg
->osh
, ambuf
, param_len
);
9877 cfg80211_mgmt_tx_status(cfgdev
, *cookie
, buf
, len
, ack
, GFP_KERNEL
);
9880 #endif /* WL_CLIENT_SAE */
9882 WL_ERR(("Driver only allows MGMT packet type\n"));
9886 af_params
= (wl_af_params_t
*)MALLOCZ(cfg
->osh
, WL_WIFI_AF_PARAMS_SIZE
);
9888 if (af_params
== NULL
)
9890 WL_ERR(("unable to allocate frame\n"));
9894 action_frame
= &af_params
->action_frame
;
9896 /* Add the packet Id */
9897 action_frame
->packetId
= *cookie
;
9898 WL_DBG(("action frame %d\n", action_frame
->packetId
));
9900 memcpy(&action_frame
->da
, &mgmt
->da
[0], ETHER_ADDR_LEN
);
9901 memcpy(&af_params
->BSSID
, &mgmt
->bssid
[0], ETHER_ADDR_LEN
);
9903 /* Add the length exepted for 802.11 header */
9904 action_frame
->len
= len
- DOT11_MGMT_HDR_LEN
;
9905 WL_DBG(("action_frame->len: %d\n", action_frame
->len
));
9907 /* Add the channel */
9908 af_params
->channel
=
9909 wl_freq_to_chanspec(channel
->center_freq
);
9910 /* Save listen_chan for searching common channel */
9911 cfg
->afx_hdl
->peer_listen_chan
= af_params
->channel
;
9912 WL_DBG(("channel from upper layer %d\n", cfg
->afx_hdl
->peer_listen_chan
));
9914 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9915 af_params
->dwell_time
= params
->wait
;
9917 af_params
->dwell_time
= wait
;
9920 memcpy(action_frame
->data
, &buf
[DOT11_MGMT_HDR_LEN
], action_frame
->len
);
9922 ack
= wl_cfg80211_send_action_frame(wiphy
, dev
, cfgdev
, af_params
,
9923 action_frame
, action_frame
->len
, bssidx
);
9924 cfg80211_mgmt_tx_status(cfgdev
, *cookie
, buf
, len
, ack
, GFP_KERNEL
);
9925 WL_DBG(("txstatus notified for cookie:%llu. ack:%d\n", *cookie
, ack
));
9927 MFREE(cfg
->osh
, af_params
, WL_WIFI_AF_PARAMS_SIZE
);
9933 wl_cfg80211_mgmt_frame_register(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
,
9934 u16 frame
, bool reg
)
9937 WL_DBG(("frame_type: %x, reg: %d\n", frame
, reg
));
9939 if (frame
!= (IEEE80211_FTYPE_MGMT
| IEEE80211_STYPE_PROBE_REQ
))
9946 wl_cfg80211_change_bss(struct wiphy
*wiphy
,
9947 struct net_device
*dev
,
9948 struct bss_parameters
*params
)
9952 #ifdef PCIE_FULL_DONGLE
9953 s32 ifidx
= DHD_BAD_IF
;
9955 #if defined(PCIE_FULL_DONGLE)
9957 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
9958 dhd
= (dhd_pub_t
*)(cfg
->pub
);
9959 #if defined(WL_ENABLE_P2P_IF)
9960 if (cfg
->p2p_net
== dev
)
9961 dev
= bcmcfg_to_prmry_ndev(cfg
);
9965 if (params
->use_cts_prot
>= 0) {
9968 if (params
->use_short_preamble
>= 0) {
9971 if (params
->use_short_slot_time
>= 0) {
9974 if (params
->basic_rates
) {
9977 if (params
->ap_isolate
>= 0) {
9978 ap_isolate
= params
->ap_isolate
;
9979 #ifdef PCIE_FULL_DONGLE
9980 ifidx
= dhd_net2idx(dhd
->info
, dev
);
9982 if (ifidx
!= DHD_BAD_IF
) {
9983 err
= dhd_set_ap_isolate(dhd
, ifidx
, ap_isolate
);
9985 WL_ERR(("Failed to set ap_isolate\n"));
9988 err
= wldev_iovar_setint(dev
, "ap_isolate", ap_isolate
);
9991 WL_ERR(("set ap_isolate Error (%d)\n", err
));
9993 #endif /* PCIE_FULL_DONGLE */
9996 if (params
->ht_opmode
>= 0) {
10003 wl_get_bandwidth_cap(struct net_device
*ndev
, uint32 band
, uint32
*bandwidth
)
10005 u32 bw
= WL_CHANSPEC_BW_20
;
10012 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
10014 if (band
== WL_CHANSPEC_BAND_5G
) {
10015 param
.band
= WLC_BAND_5G
;
10018 else if (band
== WL_CHANSPEC_BAND_6G
) {
10019 param
.band
= WLC_BAND_6G
;
10023 /* bw_cap is newly defined iovar for checking bandwith
10024 * capability of the band in Aardvark_branch_tob
10026 err
= wldev_iovar_getbuf(ndev
, "bw_cap", ¶m
, sizeof(param
),
10027 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
10029 if (err
!= BCME_UNSUPPORTED
) {
10030 WL_ERR(("bw_cap failed, %d\n", err
));
10033 /* if firmware doesn't support bw_cap iovar,
10034 * we have to use mimo_bw_cap
10036 err
= wldev_iovar_getint(ndev
, "mimo_bw_cap", &bw_cap
);
10038 WL_ERR(("error get mimo_bw_cap (%d)\n", err
));
10040 if (bw_cap
!= WLC_N_BW_20ALL
) {
10041 bw
= WL_CHANSPEC_BW_40
;
10045 if (WL_BW_CAP_160MHZ(ioctl_buf
[0])) {
10046 bw
= WL_CHANSPEC_BW_160
;
10047 } else if (WL_BW_CAP_80MHZ(ioctl_buf
[0])) {
10048 bw
= WL_CHANSPEC_BW_80
;
10049 } else if (WL_BW_CAP_40MHZ(ioctl_buf
[0])) {
10050 bw
= WL_CHANSPEC_BW_40
;
10052 bw
= WL_CHANSPEC_BW_20
;
10055 } else if (band
== WL_CHANSPEC_BAND_2G
) {
10056 bw
= WL_CHANSPEC_BW_20
;
10064 #ifdef APSTA_RESTRICTED_CHANNEL
10066 wl_get_nl80211_band(u32 wl_band
)
10068 s32 err
= BCME_ERROR
;
10071 case WL_CHANSPEC_BAND_2G
:
10072 return IEEE80211_BAND_2GHZ
;
10073 case WL_CHANSPEC_BAND_5G
:
10074 return IEEE80211_BAND_5GHZ
;
10076 case WL_CHANSPEC_BAND_6G
:
10077 /* current kernels doesn't support seperate
10078 * band for 6GHz. so till patch is available
10079 * map it under 5GHz
10081 return IEEE80211_BAND_5GHZ
;
10082 #endif /* WL_BAND_6G */
10084 WL_ERR(("unsupported Band. %d\n", wl_band
));
10089 #endif /* APSTA_RESTRICTED_CHANNEL */
10092 wl_cfg80211_set_channel(struct wiphy
*wiphy
, struct net_device
*dev
,
10093 struct ieee80211_channel
*chan
,
10094 enum nl80211_channel_type channel_type
)
10096 chanspec_t chspec
= INVCHANSPEC
;
10097 chanspec_t cur_chspec
= INVCHANSPEC
;
10098 u32 bw
= WL_CHANSPEC_BW_20
;
10100 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
10101 #if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL) || defined(WL_EXT_IAPSTA)
10102 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
10103 enum nl80211_band band
;
10105 #endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
10106 u16 center_freq
= chan
->center_freq
;
10108 dev
= ndev_to_wlc_ndev(dev
, cfg
);
10109 #ifdef WL_EXT_IAPSTA
10110 _chan
= ieee80211_frequency_to_channel(chan
->center_freq
);
10111 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
10112 wl_ext_iapsta_update_iftype(dev
, dhd_net2idx(dhd
->info
, dev
), WL_IF_TYPE_AP
);
10113 _chan
= wl_ext_iapsta_update_channel(dhd
, dev
, _chan
);
10115 if (CHANNEL_IS_5G(_chan
))
10116 band
= NL80211_BAND_5GHZ
;
10118 band
= NL80211_BAND_2GHZ
;
10119 center_freq
= ieee80211_channel_to_frequency(_chan
, band
);
10121 chspec
= wl_freq_to_chanspec(center_freq
);
10123 WL_MSG(dev
->name
, "netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
10124 dev
->ifindex
, channel_type
, CHSPEC_CHANNEL(chspec
));
10127 if (IS_P2P_GO(dev
->ieee80211_ptr
) && (CHSPEC_IS6G(chspec
))) {
10128 WL_ERR(("P2P GO not allowed on 6G\n"));
10131 #endif /* WL_P2P_6G */
10134 switch (channel_type
) {
10135 case NL80211_CHAN_HT40MINUS
:
10136 /* secondary channel is below the control channel */
10137 chspec
= CH40MHZ_CHSPEC(CHSPEC_CHANNEL(chspec
), WL_CHANSPEC_CTL_SB_UPPER
);
10139 case NL80211_CHAN_HT40PLUS
:
10140 /* secondary channel is above the control channel */
10141 chspec
= CH40MHZ_CHSPEC(CHSPEC_CHANNEL(chspec
), WL_CHANSPEC_CTL_SB_LOWER
);
10144 chspec
= CH20MHZ_CHSPEC(CHSPEC_CHANNEL(chspec
));
10147 #endif /* NOT_YET */
10149 #if defined(APSTA_RESTRICTED_CHANNEL)
10150 /* Some customer platform used limited number of channels
10151 * for SoftAP interface on STA/SoftAP concurrent mode.
10152 * - 2.4GHz Channel: CH1 - CH13
10153 * - 5GHz Channel: CH149 (it depends on the country code)
10154 * If the Android framework sent invaild channel configuration
10155 * to DHD, driver should change the channel which is sutible for
10156 * STA/SoftAP concurrent mode.
10157 * - Set operating channel to CH1 (default 2.4GHz channel for
10158 * restricted APSTA mode) if STA interface was associated to
10159 * 5GHz APs except for CH149.
10160 * - Otherwise, set the channel to the same channel as existing AP.
10162 if (wl_get_mode_by_netdev(cfg
, dev
) == WL_MODE_AP
&&
10163 DHD_OPMODE_STA_SOFTAP_CONCURR(dhd
) &&
10164 wl_get_drv_status(cfg
, CONNECTED
, bcmcfg_to_prmry_ndev(cfg
))) {
10165 u32
*sta_chanspec
= (u32
*)wl_read_prof(cfg
,
10166 bcmcfg_to_prmry_ndev(cfg
), WL_PROF_CHAN
);
10167 if (chan
->band
== wl_get_nl80211_band(CHSPEC_BAND(*sta_chanspec
))) {
10168 /* Do not try SCC in 5GHz if channel is not CH149 */
10171 CHSPEC_IS6G(*sta_chanspec
) ||
10172 #endif /* WL_6G_BAND */
10173 (CHSPEC_IS5G(*sta_chanspec
) &&
10174 CHSPEC_CHANNEL(*sta_chanspec
) != DEFAULT_5G_SOFTAP_CHANNEL
)) ?
10175 DEFAULT_2G_SOFTAP_CHANSPEC
: *sta_chanspec
;
10176 WL_ERR(("target chanspec will be changed to %d\n", chspec
));
10177 if (CHSPEC_IS2G(chspec
)) {
10178 bw
= WL_CHANSPEC_BW_20
;
10183 #endif /* APSTA_RESTRICTED_CHANNEL */
10185 err
= wl_get_bandwidth_cap(dev
, CHSPEC_BAND(chspec
), &bw
);
10187 WL_ERR(("Failed to get bandwidth information, err=%d\n", err
));
10191 /* In case of 5G downgrade BW to 80MHz as 160MHz channels falls in DFS */
10192 if (CHSPEC_IS5G(chspec
) && (bw
== WL_CHANSPEC_BW_160
)) {
10193 bw
= WL_CHANSPEC_BW_80
;
10196 cur_chspec
= wf_create_chspec_from_primary(wf_chspec_primary20_chan(chspec
),
10197 bw
, CHSPEC_BAND(chspec
));
10198 if (wf_chspec_valid(cur_chspec
)) {
10199 /* convert 802.11 ac chanspec to current fw chanspec type */
10200 cur_chspec
= wl_chspec_host_to_driver(cur_chspec
);
10201 if (cur_chspec
!= INVCHANSPEC
) {
10202 if ((err
= wldev_iovar_setint(dev
, "chanspec",
10203 cur_chspec
)) == BCME_BADCHAN
) {
10204 u32 local_channel
= CHSPEC_CHANNEL(chspec
);
10205 if ((bw
== WL_CHANSPEC_BW_80
) || (bw
== WL_CHANSPEC_BW_160
))
10207 err
= wldev_ioctl_set(dev
, WLC_SET_CHANNEL
,
10208 &local_channel
, sizeof(local_channel
));
10210 WL_ERR(("WLC_SET_CHANNEL error %d"
10211 "chip may not be supporting this channel\n", err
));
10214 WL_ERR(("failed to set chanspec error %d\n", err
));
10216 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
10218 /* Disable Frameburst only for stand-alone 2GHz SoftAP */
10219 if (wl_get_mode_by_netdev(cfg
, dev
) == WL_MODE_AP
&&
10220 DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_HOSTAP_MODE
) &&
10221 (CHSPEC_IS2G(chspec
)) &&
10222 !wl_get_drv_status(cfg
, CONNECTED
,
10223 bcmcfg_to_prmry_ndev(cfg
))) {
10224 WL_DBG(("Disabling frameburst on "
10225 "stand-alone 2GHz SoftAP\n"));
10226 wl_cfg80211_set_frameburst(cfg
, FALSE
);
10229 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
10231 WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
10236 if (bw
== WL_CHANSPEC_BW_160
) {
10237 bw
= WL_CHANSPEC_BW_80
;
10238 } else if (bw
== WL_CHANSPEC_BW_80
) {
10239 bw
= WL_CHANSPEC_BW_40
;
10240 } else if (bw
== WL_CHANSPEC_BW_40
) {
10241 bw
= WL_CHANSPEC_BW_20
;
10247 WL_ERR(("Invalid chanspec 0x%x\n", chspec
));
10250 #ifdef CUSTOM_SET_CPUCORE
10251 if (dhd
->op_mode
== DHD_FLAG_HOSTAP_MODE
) {
10252 WL_DBG(("SoftAP mode do not need to set cpucore\n"));
10253 } else if (chspec
& WL_CHANSPEC_BW_80
) {
10254 /* SoftAp only mode do not need to set cpucore */
10255 if ((dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) &&
10256 dev
!= bcmcfg_to_prmry_ndev(cfg
)) {
10257 /* Soft AP on virtual Iface (AP+STA case) */
10258 dhd
->chan_isvht80
|= DHD_FLAG_HOSTAP_MODE
;
10259 dhd_set_cpucore(dhd
, TRUE
);
10260 } else if (is_p2p_group_iface(dev
->ieee80211_ptr
)) {
10261 /* If P2P IF is vht80 */
10262 dhd
->chan_isvht80
|= DHD_FLAG_P2P_MODE
;
10263 dhd_set_cpucore(dhd
, TRUE
);
10266 #endif /* CUSTOM_SET_CPUCORE */
10267 if (!err
&& (wl_get_mode_by_netdev(cfg
, dev
) == WL_MODE_AP
)) {
10268 /* Update AP/GO operating chanspec */
10269 cfg
->ap_oper_channel
= wl_freq_to_chanspec(center_freq
);
10272 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg
),
10273 FW_LOGSET_MASK_ALL
);
10275 WL_DBG(("Setting chanspec %x for GO/AP \n", chspec
));
10280 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
10281 struct net_device
*
10282 wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211
*cfg
)
10284 struct net_info
*_net_info
, *next
;
10285 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
10286 list_for_each_entry_safe(_net_info
, next
, &cfg
->net_list
, list
) {
10287 GCC_DIAGNOSTIC_POP();
10288 if (_net_info
->ndev
&&
10289 test_bit(WL_STATUS_REMAINING_ON_CHANNEL
, &_net_info
->sme_state
))
10290 return _net_info
->ndev
;
10295 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
10298 wl_validate_opensecurity(struct net_device
*dev
, s32 bssidx
, bool privacy
)
10305 err
= wldev_iovar_setint_bsscfg(dev
, "auth", 0, bssidx
);
10307 WL_ERR(("auth error %d\n", err
));
10312 /* If privacy bit is set in open mode, then WEP would be enabled */
10313 wsec
= WEP_ENABLED
;
10314 WL_DBG(("Setting wsec to %d for WEP \n", wsec
));
10318 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
10320 WL_ERR(("wsec error %d\n", err
));
10324 /* set upper-layer auth */
10325 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_ADHOC
)
10326 wpa_val
= WPA_AUTH_NONE
;
10328 wpa_val
= WPA_AUTH_DISABLED
;
10329 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wpa_val
, bssidx
);
10331 WL_ERR(("wpa_auth error %d\n", err
));
10338 #define MAX_FILS_IND_IE_LEN 1024u
10340 wl_validate_fils_ind_ie(struct net_device
*dev
, const bcm_tlv_t
*filsindie
, s32 bssidx
)
10343 struct bcm_cfg80211
*cfg
= NULL
;
10344 bcm_iov_buf_t
*iov_buf
= NULL
;
10346 int iov_buf_size
= 0;
10348 if (!dev
|| !filsindie
) {
10349 WL_ERR(("%s: dev/filsidie is null\n", __FUNCTION__
));
10353 cfg
= wl_get_cfg(dev
);
10355 WL_ERR(("%s: cfg is null\n", __FUNCTION__
));
10359 iov_buf_size
= sizeof(bcm_iov_buf_t
) + sizeof(bcm_xtlv_t
) + filsindie
->len
- 1;
10360 iov_buf
= MALLOCZ(cfg
->osh
, iov_buf_size
);
10362 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__
, iov_buf_size
));
10366 iov_buf
->version
= WL_FILS_IOV_VERSION
;
10367 iov_buf
->id
= WL_FILS_CMD_ADD_IND_IE
;
10368 iov_buf
->len
= sizeof(bcm_xtlv_t
) + filsindie
->len
- 1;
10369 pxtlv
= (bcm_xtlv_t
*)&iov_buf
->data
[0];
10370 pxtlv
->id
= WL_FILS_XTLV_IND_IE
;
10371 pxtlv
->len
= filsindie
->len
;
10372 /* memcpy_s return check not required as buffer is allocated based on ie
10375 (void)memcpy_s(pxtlv
->data
, filsindie
->len
, filsindie
->data
, filsindie
->len
);
10377 err
= wldev_iovar_setbuf(dev
, "fils", iov_buf
, iov_buf_size
,
10378 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
10379 if (unlikely(err
)) {
10380 WL_ERR(("fils indication ioctl error (%d)\n", err
));
10386 WL_ERR(("FILS Ind setting error %d\n", err
));
10390 MFREE(cfg
->osh
, iov_buf
, iov_buf_size
);
10396 wl_validate_wpa2ie(struct net_device
*dev
, const bcm_tlv_t
*wpa2ie
, s32 bssidx
)
10400 u16 auth
= 0; /* d11 open authentication */
10405 const wpa_suite_mcast_t
*mcast
;
10406 const wpa_suite_ucast_t
*ucast
;
10407 const wpa_suite_auth_key_mgmt_t
*mgmt
;
10408 const wpa_pmkid_list_t
*pmkid
;
10413 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
10414 struct wl_security
*sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
10418 u32 wme_bss_disable
;
10420 if (wpa2ie
== NULL
)
10423 WL_DBG(("Enter \n"));
10424 len
= wpa2ie
->len
- WPA2_VERSION_LEN
;
10425 /* check the mcast cipher */
10426 mcast
= (const wpa_suite_mcast_t
*)&wpa2ie
->data
[WPA2_VERSION_LEN
];
10427 switch (mcast
->type
) {
10428 case WPA_CIPHER_NONE
:
10431 case WPA_CIPHER_WEP_40
:
10432 case WPA_CIPHER_WEP_104
:
10433 gval
= WEP_ENABLED
;
10435 case WPA_CIPHER_TKIP
:
10436 gval
= TKIP_ENABLED
;
10438 case WPA_CIPHER_AES_CCM
:
10439 gval
= AES_ENABLED
;
10443 case WAPI_CIPHER_SMS4
:
10444 gval
= SMS4_ENABLED
;
10449 WL_ERR(("No Security Info\n"));
10452 if ((len
-= WPA_SUITE_LEN
) <= 0)
10453 return BCME_BADLEN
;
10455 /* check the unicast cipher */
10456 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
10457 suite_count
= ltoh16_ua(&ucast
->count
);
10458 switch (ucast
->list
[0].type
) {
10459 case WPA_CIPHER_NONE
:
10462 case WPA_CIPHER_WEP_40
:
10463 case WPA_CIPHER_WEP_104
:
10464 pval
= WEP_ENABLED
;
10466 case WPA_CIPHER_TKIP
:
10467 pval
= TKIP_ENABLED
;
10469 case WPA_CIPHER_AES_CCM
:
10470 pval
= AES_ENABLED
;
10474 case WAPI_CIPHER_SMS4
:
10475 pval
= SMS4_ENABLED
;
10480 WL_ERR(("No Security Info\n"));
10482 if ((len
-= (WPA_IE_SUITE_COUNT_LEN
+ (WPA_SUITE_LEN
* suite_count
))) <= 0)
10483 return BCME_BADLEN
;
10485 /* FOR WPS , set SEC_OW_ENABLED */
10486 wsec
= (pval
| gval
| SES_OW_ENABLED
);
10487 /* check the AKM */
10488 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[suite_count
];
10489 suite_count
= cnt
= ltoh16_ua(&mgmt
->count
);
10491 if (bcmp(mgmt
->list
[cnt
].oui
, WFA_OUI
, WFA_OUI_LEN
) == 0) {
10492 switch (mgmt
->list
[cnt
].type
) {
10494 wpa_auth
|= WPA3_AUTH_DPP_AKM
;
10497 WL_ERR(("No Key Mgmt Info in WFA_OUI\n"));
10500 switch (mgmt
->list
[cnt
].type
) {
10502 wpa_auth
|= WPA_AUTH_NONE
;
10504 case RSN_AKM_UNSPECIFIED
:
10505 wpa_auth
|= WPA2_AUTH_UNSPECIFIED
;
10508 wpa_auth
|= WPA2_AUTH_PSK
;
10511 case RSN_AKM_MFP_PSK
:
10512 wpa_auth
|= WPA2_AUTH_PSK_SHA256
;
10514 case RSN_AKM_MFP_1X
:
10515 wpa_auth
|= WPA2_AUTH_1X_SHA256
;
10517 case RSN_AKM_FILS_SHA256
:
10518 wpa_auth
|= WPA2_AUTH_FILS_SHA256
;
10520 case RSN_AKM_FILS_SHA384
:
10521 wpa_auth
|= WPA2_AUTH_FILS_SHA384
;
10523 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
10524 case RSN_AKM_SAE_PSK
:
10525 wpa_auth
|= WPA3_AUTH_SAE_PSK
;
10527 #endif /* WL_SAE || WL_CLIENT_SAE */
10530 WL_ERR(("No Key Mgmt Info\n"));
10534 if ((len
-= (WPA_IE_SUITE_COUNT_LEN
+ (WPA_SUITE_LEN
* suite_count
))) >= RSN_CAP_LEN
) {
10535 rsn_cap
[0] = *(const u8
*)&mgmt
->list
[suite_count
];
10536 rsn_cap
[1] = *((const u8
*)&mgmt
->list
[suite_count
] + 1);
10538 if (rsn_cap
[0] & (RSN_CAP_16_REPLAY_CNTRS
<< RSN_CAP_PTK_REPLAY_CNTR_SHIFT
)) {
10539 wme_bss_disable
= 0;
10541 wme_bss_disable
= 1;
10545 if (rsn_cap
[0] & RSN_CAP_MFPR
) {
10546 WL_DBG(("MFP Required \n"));
10547 mfp
= WL_MFP_REQUIRED
;
10548 /* Our firmware has requirement that WPA2_AUTH_PSK/WPA2_AUTH_UNSPECIFIED
10549 * be set, if SHA256 OUI is to be included in the rsn ie.
10551 if (wpa_auth
& WPA2_AUTH_PSK_SHA256
) {
10552 wpa_auth
|= WPA2_AUTH_PSK
;
10553 } else if (wpa_auth
& WPA2_AUTH_1X_SHA256
) {
10554 wpa_auth
|= WPA2_AUTH_UNSPECIFIED
;
10556 } else if (rsn_cap
[0] & RSN_CAP_MFPC
) {
10557 WL_DBG(("MFP Capable \n"));
10558 mfp
= WL_MFP_CAPABLE
;
10562 /* set wme_bss_disable to sync RSN Capabilities */
10563 err
= wldev_iovar_setint_bsscfg(dev
, "wme_bss_disable", wme_bss_disable
, bssidx
);
10565 WL_ERR(("wme_bss_disable error %d\n", err
));
10569 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len
));
10572 len
-= RSN_CAP_LEN
;
10573 if (len
>= WPA2_PMKID_COUNT_LEN
) {
10574 pmkid
= (const wpa_pmkid_list_t
*)
10575 ((const u8
*)&mgmt
->list
[suite_count
] + RSN_CAP_LEN
);
10576 cnt
= ltoh16_ua(&pmkid
->count
);
10578 WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
10581 /* since PMKID cnt is known to be 0 for AP, */
10582 /* so don't bother to send down this info to firmware */
10586 len
-= WPA2_PMKID_COUNT_LEN
;
10587 if (len
>= WPA_SUITE_LEN
) {
10589 (const u8
*)&mgmt
->list
[suite_count
] + RSN_CAP_LEN
+ WPA2_PMKID_COUNT_LEN
;
10591 cfg
->bip_pos
= NULL
;
10596 err
= wldev_iovar_setint_bsscfg(dev
, "auth", auth
, bssidx
);
10598 WL_ERR(("auth error %d\n", err
));
10603 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
10605 WL_ERR(("wsec error %d\n", err
));
10610 cfg
->mfp_mode
= mfp
;
10613 /* set upper-layer auth */
10614 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wpa_auth
, bssidx
);
10616 WL_ERR(("wpa_auth error %d\n", err
));
10621 /* store applied sec settings */
10622 sec
->fw_wpa_auth
= wpa_auth
;
10623 sec
->fw_wsec
= wsec
;
10624 sec
->fw_auth
= auth
;
10634 wl_validate_wpaie(struct net_device
*dev
, const wpa_ie_fixed_t
*wpaie
, s32 bssidx
)
10636 const wpa_suite_mcast_t
*mcast
;
10637 const wpa_suite_ucast_t
*ucast
;
10638 const wpa_suite_auth_key_mgmt_t
*mgmt
;
10639 u16 auth
= 0; /* d11 open authentication */
10649 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
10650 struct wl_security
*sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
10654 WL_DBG(("Enter \n"));
10655 len
= wpaie
->length
; /* value length */
10656 len
-= WPA_IE_TAG_FIXED_LEN
;
10657 /* check for multicast cipher suite */
10658 if (len
< WPA_SUITE_LEN
) {
10659 WL_INFORM_MEM(("no multicast cipher suite\n"));
10663 /* pick up multicast cipher */
10664 mcast
= (const wpa_suite_mcast_t
*)&wpaie
[1];
10665 len
-= WPA_SUITE_LEN
;
10666 if (!bcmp(mcast
->oui
, WPA_OUI
, WPA_OUI_LEN
)) {
10667 if (IS_WPA_CIPHER(mcast
->type
)) {
10669 switch (mcast
->type
) {
10670 case WPA_CIPHER_NONE
:
10673 case WPA_CIPHER_WEP_40
:
10674 case WPA_CIPHER_WEP_104
:
10677 case WPA_CIPHER_TKIP
:
10678 tmp
= TKIP_ENABLED
;
10680 case WPA_CIPHER_AES_CCM
:
10684 WL_ERR(("No Security Info\n"));
10689 /* Check for unicast suite(s) */
10690 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
10691 WL_INFORM_MEM(("no unicast suite\n"));
10694 /* walk thru unicast cipher list and pick up what we recognize */
10695 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
10696 count
= ltoh16_ua(&ucast
->count
);
10697 len
-= WPA_IE_SUITE_COUNT_LEN
;
10698 for (i
= 0; i
< count
&& len
>= WPA_SUITE_LEN
;
10699 i
++, len
-= WPA_SUITE_LEN
) {
10700 if (!bcmp(ucast
->list
[i
].oui
, WPA_OUI
, WPA_OUI_LEN
)) {
10701 if (IS_WPA_CIPHER(ucast
->list
[i
].type
)) {
10703 switch (ucast
->list
[i
].type
) {
10704 case WPA_CIPHER_NONE
:
10707 case WPA_CIPHER_WEP_40
:
10708 case WPA_CIPHER_WEP_104
:
10711 case WPA_CIPHER_TKIP
:
10712 tmp
= TKIP_ENABLED
;
10714 case WPA_CIPHER_AES_CCM
:
10718 WL_ERR(("No Security Info\n"));
10724 len
-= (count
- i
) * WPA_SUITE_LEN
;
10725 /* Check for auth key management suite(s) */
10726 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
10727 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10730 /* walk thru auth management suite list and pick up what we recognize */
10731 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[count
];
10732 count
= ltoh16_ua(&mgmt
->count
);
10733 len
-= WPA_IE_SUITE_COUNT_LEN
;
10734 for (i
= 0; i
< count
&& len
>= WPA_SUITE_LEN
;
10735 i
++, len
-= WPA_SUITE_LEN
) {
10736 if (!bcmp(mgmt
->list
[i
].oui
, WPA_OUI
, WPA_OUI_LEN
)) {
10737 if (IS_WPA_AKM(mgmt
->list
[i
].type
)) {
10739 switch (mgmt
->list
[i
].type
) {
10741 tmp
= WPA_AUTH_NONE
;
10743 case RSN_AKM_UNSPECIFIED
:
10744 tmp
= WPA_AUTH_UNSPECIFIED
;
10747 tmp
= WPA_AUTH_PSK
;
10750 WL_ERR(("No Key Mgmt Info\n"));
10757 /* FOR WPS , set SEC_OW_ENABLED */
10758 wsec
= (pval
| gval
| SES_OW_ENABLED
);
10760 err
= wldev_iovar_setint_bsscfg(dev
, "auth", auth
, bssidx
);
10762 WL_ERR(("auth error %d\n", err
));
10766 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
10768 WL_ERR(("wsec error %d\n", err
));
10771 /* set upper-layer auth */
10772 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wpa_auth
, bssidx
);
10774 WL_ERR(("wpa_auth error %d\n", err
));
10779 /* store applied sec settings */
10780 sec
->fw_wpa_auth
= wpa_auth
;
10781 sec
->fw_wsec
= wsec
;
10782 sec
->fw_auth
= auth
;
10789 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10790 static u32
wl_get_cipher_type(uint8 type
)
10794 case WPA_CIPHER_NONE
:
10797 case WPA_CIPHER_WEP_40
:
10798 case WPA_CIPHER_WEP_104
:
10801 case WPA_CIPHER_TKIP
:
10802 ret
= TKIP_ENABLED
;
10804 case WPA_CIPHER_AES_CCM
:
10809 case WAPI_CIPHER_SMS4
:
10810 ret
= SMS4_ENABLED
;
10815 WL_ERR(("No Security Info\n"));
10820 static u32
wl_get_suite_auth_key_mgmt_type(uint8 type
, const wpa_suite_mcast_t
*mcast
)
10825 if (!bcmp(mcast
->oui
, WPA2_OUI
, WPA2_OUI_LEN
)) {
10829 WL_INFORM_MEM(("%s, type = %d\n", is_wpa2
? "WPA2":"WPA", type
));
10830 if (bcmp(mcast
->oui
, WFA_OUI
, WFA_OUI_LEN
) == 0) {
10833 ret
= WPA3_AUTH_DPP_AKM
;
10836 WL_ERR(("No Key Mgmt Info in WFA_OUI\n"));
10841 /* For WPA and WPA2, AUTH_NONE is common */
10842 ret
= WPA_AUTH_NONE
;
10844 case RSN_AKM_UNSPECIFIED
:
10846 ret
= WPA2_AUTH_UNSPECIFIED
;
10848 ret
= WPA_AUTH_UNSPECIFIED
;
10853 ret
= WPA2_AUTH_PSK
;
10855 ret
= WPA_AUTH_PSK
;
10859 case RSN_AKM_SAE_PSK
:
10860 ret
= WPA3_AUTH_SAE_PSK
;
10862 #endif /* WL_SAE */
10864 WL_ERR(("No Key Mgmt Info\n"));
10871 wl_validate_wpaie_wpa2ie(struct net_device
*dev
, const wpa_ie_fixed_t
*wpaie
,
10872 const bcm_tlv_t
*wpa2ie
, s32 bssidx
)
10874 const wpa_suite_mcast_t
*mcast
;
10875 const wpa_suite_ucast_t
*ucast
;
10876 const wpa_suite_auth_key_mgmt_t
*mgmt
;
10877 u16 auth
= 0; /* d11 open authentication */
10880 u32 wme_bss_disable
;
10885 u32 wsec1
, wsec2
, wsec
;
10891 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
10892 struct wl_security
*sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
10894 if (wpaie
== NULL
|| wpa2ie
== NULL
)
10897 WL_DBG(("Enter \n"));
10898 len
= wpaie
->length
; /* value length */
10899 len
-= WPA_IE_TAG_FIXED_LEN
;
10900 /* check for multicast cipher suite */
10901 if (len
< WPA_SUITE_LEN
) {
10902 WL_INFORM_MEM(("no multicast cipher suite\n"));
10906 /* pick up multicast cipher */
10907 mcast
= (const wpa_suite_mcast_t
*)&wpaie
[1];
10908 len
-= WPA_SUITE_LEN
;
10909 if (!bcmp(mcast
->oui
, WPA_OUI
, WPA_OUI_LEN
)) {
10910 if (IS_WPA_CIPHER(mcast
->type
)) {
10911 gval
|= wl_get_cipher_type(mcast
->type
);
10914 WL_DBG(("\nwpa ie validate\n"));
10915 WL_DBG(("wpa ie mcast cipher = 0x%X\n", gval
));
10917 /* Check for unicast suite(s) */
10918 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
10919 WL_INFORM_MEM(("no unicast suite\n"));
10923 /* walk thru unicast cipher list and pick up what we recognize */
10924 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
10925 count
= ltoh16_ua(&ucast
->count
);
10926 len
-= WPA_IE_SUITE_COUNT_LEN
;
10927 for (i
= 0; i
< count
&& len
>= WPA_SUITE_LEN
;
10928 i
++, len
-= WPA_SUITE_LEN
) {
10929 if (!bcmp(ucast
->list
[i
].oui
, WPA_OUI
, WPA_OUI_LEN
)) {
10930 if (IS_WPA_CIPHER(ucast
->list
[i
].type
)) {
10931 pval
|= wl_get_cipher_type(ucast
->list
[i
].type
);
10935 WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count
, pval
));
10937 /* FOR WPS , set SEC_OW_ENABLED */
10938 wsec1
= (pval
| gval
| SES_OW_ENABLED
);
10939 WL_ERR(("wpa ie wsec = 0x%X\n", wsec1
));
10941 len
-= (count
- i
) * WPA_SUITE_LEN
;
10942 /* Check for auth key management suite(s) */
10943 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
10944 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10947 /* walk thru auth management suite list and pick up what we recognize */
10948 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[count
];
10949 count
= ltoh16_ua(&mgmt
->count
);
10950 len
-= WPA_IE_SUITE_COUNT_LEN
;
10951 for (i
= 0; i
< count
&& len
>= WPA_SUITE_LEN
;
10952 i
++, len
-= WPA_SUITE_LEN
) {
10953 if (!bcmp(mgmt
->list
[i
].oui
, WPA_OUI
, WPA_OUI_LEN
)) {
10954 if (IS_WPA_AKM(mgmt
->list
[i
].type
)) {
10956 wl_get_suite_auth_key_mgmt_type(mgmt
->list
[i
].type
, mcast
);
10961 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count
, wpa_auth1
));
10962 WL_ERR(("\nwpa2 ie validate\n"));
10967 /* check the mcast cipher */
10968 mcast
= (const wpa_suite_mcast_t
*)&wpa2ie
->data
[WPA2_VERSION_LEN
];
10969 gval
= wl_get_cipher_type(mcast
->type
);
10971 WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval
));
10972 if ((len
-= WPA_SUITE_LEN
) <= 0)
10974 WL_ERR(("P:wpa2 ie len[%d]", len
));
10975 return BCME_BADLEN
;
10978 /* check the unicast cipher */
10979 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
10980 suite_count
= ltoh16_ua(&ucast
->count
);
10981 WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count
));
10982 pval
|= wl_get_cipher_type(ucast
->list
[0].type
);
10984 if ((len
-= (WPA_IE_SUITE_COUNT_LEN
+ (WPA_SUITE_LEN
* suite_count
))) <= 0)
10985 return BCME_BADLEN
;
10987 WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval
));
10989 /* FOR WPS , set SEC_OW_ENABLED */
10990 wsec2
= (pval
| gval
| SES_OW_ENABLED
);
10991 WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2
));
10993 /* check the AKM */
10994 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[suite_count
];
10995 suite_count
= ltoh16_ua(&mgmt
->count
);
10996 wpa_auth2
= wl_get_suite_auth_key_mgmt_type(mgmt
->list
[0].type
, mcast
);
10997 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count
, wpa_auth2
));
10999 if ((len
-= (WPA_IE_SUITE_COUNT_LEN
+ (WPA_SUITE_LEN
* suite_count
))) >= RSN_CAP_LEN
) {
11000 rsn_cap
[0] = *(const u8
*)&mgmt
->list
[suite_count
];
11001 rsn_cap
[1] = *((const u8
*)&mgmt
->list
[suite_count
] + 1);
11002 if (rsn_cap
[0] & (RSN_CAP_16_REPLAY_CNTRS
<< RSN_CAP_PTK_REPLAY_CNTR_SHIFT
)) {
11003 wme_bss_disable
= 0;
11005 wme_bss_disable
= 1;
11007 WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap
[0], wme_bss_disable
));
11009 /* set wme_bss_disable to sync RSN Capabilities */
11010 err
= wldev_iovar_setint_bsscfg(dev
, "wme_bss_disable", wme_bss_disable
, bssidx
);
11012 WL_ERR(("wme_bss_disable error %d\n", err
));
11016 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len
));
11019 wsec
= (wsec1
| wsec2
);
11020 wpa_auth
= (wpa_auth1
| wpa_auth2
);
11021 WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec
, wpa_auth
));
11024 err
= wldev_iovar_setint_bsscfg(dev
, "auth", auth
, bssidx
);
11026 WL_ERR(("auth error %d\n", err
));
11030 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
11032 WL_ERR(("wsec error %d\n", err
));
11035 /* set upper-layer auth */
11036 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wpa_auth
, bssidx
);
11038 WL_ERR(("wpa_auth error %d\n", err
));
11043 sec
->fw_wpa_auth
= wpa_auth
;
11044 sec
->fw_auth
= auth
;
11045 sec
->fw_wsec
= wsec
;
11051 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11054 wl_cfg80211_bcn_validate_sec(
11055 struct net_device
*dev
,
11056 struct parsed_ies
*ies
,
11061 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
11062 wl_cfgbss_t
*bss
= wl_get_cfgbss_by_wdev(cfg
, dev
->ieee80211_ptr
);
11063 struct wl_security
*sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
11066 WL_ERR(("cfgbss is NULL \n"));
11070 if (dev_role
== NL80211_IFTYPE_P2P_GO
&& (ies
->wpa2_ie
)) {
11071 /* For P2P GO, the sec type is WPA2-PSK */
11072 WL_DBG(("P2P GO: validating wpa2_ie"));
11073 if (wl_validate_wpa2ie(dev
, ies
->wpa2_ie
, bssidx
) < 0)
11076 } else if (dev_role
== NL80211_IFTYPE_AP
) {
11078 WL_DBG(("SoftAP: validating security"));
11079 /* If wpa2_ie or wpa_ie is present validate it */
11081 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11082 if ((ies
->wpa_ie
!= NULL
&& ies
->wpa2_ie
!= NULL
)) {
11083 if (wl_validate_wpaie_wpa2ie(dev
, ies
->wpa_ie
, ies
->wpa2_ie
, bssidx
) < 0) {
11084 bss
->security_mode
= false;
11089 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11090 if ((ies
->wpa2_ie
|| ies
->wpa_ie
) &&
11091 ((wl_validate_wpa2ie(dev
, ies
->wpa2_ie
, bssidx
) < 0 ||
11092 wl_validate_wpaie(dev
, ies
->wpa_ie
, bssidx
) < 0))) {
11093 bss
->security_mode
= false;
11097 if (ies
->fils_ind_ie
&&
11098 (wl_validate_fils_ind_ie(dev
, ies
->fils_ind_ie
, bssidx
) < 0)) {
11099 bss
->security_mode
= false;
11103 bss
->security_mode
= true;
11105 MFREE(cfg
->osh
, bss
->rsn_ie
, bss
->rsn_ie
[1]
11106 + WPA_RSN_IE_TAG_FIXED_LEN
);
11107 bss
->rsn_ie
= NULL
;
11110 MFREE(cfg
->osh
, bss
->wpa_ie
, bss
->wpa_ie
[1]
11111 + WPA_RSN_IE_TAG_FIXED_LEN
);
11112 bss
->wpa_ie
= NULL
;
11115 MFREE(cfg
->osh
, bss
->wps_ie
, bss
->wps_ie
[1] + 2);
11116 bss
->wps_ie
= NULL
;
11118 if (bss
->fils_ind_ie
) {
11119 MFREE(cfg
->osh
, bss
->fils_ind_ie
, bss
->fils_ind_ie
[1]
11120 + FILS_INDICATION_IE_TAG_FIXED_LEN
);
11121 bss
->fils_ind_ie
= NULL
;
11123 if (ies
->wpa_ie
!= NULL
) {
11125 bss
->rsn_ie
= NULL
;
11126 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
11127 ies
->wpa_ie
->length
11128 + WPA_RSN_IE_TAG_FIXED_LEN
);
11130 memcpy(bss
->wpa_ie
, ies
->wpa_ie
,
11131 ies
->wpa_ie
->length
11132 + WPA_RSN_IE_TAG_FIXED_LEN
);
11134 } else if (ies
->wpa2_ie
!= NULL
) {
11136 bss
->wpa_ie
= NULL
;
11137 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
11139 + WPA_RSN_IE_TAG_FIXED_LEN
);
11141 memcpy(bss
->rsn_ie
, ies
->wpa2_ie
,
11143 + WPA_RSN_IE_TAG_FIXED_LEN
);
11147 if (ies
->fils_ind_ie
) {
11148 bss
->fils_ind_ie
= MALLOCZ(cfg
->osh
,
11149 ies
->fils_ind_ie
->len
11150 + FILS_INDICATION_IE_TAG_FIXED_LEN
);
11151 if (bss
->fils_ind_ie
) {
11152 memcpy(bss
->fils_ind_ie
, ies
->fils_ind_ie
,
11153 ies
->fils_ind_ie
->len
11154 + FILS_INDICATION_IE_TAG_FIXED_LEN
);
11157 #endif /* WL_FILS */
11158 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11160 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11161 if (!ies
->wpa2_ie
&& !ies
->wpa_ie
) {
11162 wl_validate_opensecurity(dev
, bssidx
, privacy
);
11163 bss
->security_mode
= false;
11167 bss
->wps_ie
= MALLOCZ(cfg
->osh
, ies
->wps_ie_len
);
11169 memcpy(bss
->wps_ie
, ies
->wps_ie
, ies
->wps_ie_len
);
11174 WL_INFORM_MEM(("[%s] wpa_auth:0x%x auth:0x%x wsec:0x%x mfp:0x%x\n",
11175 dev
->name
, sec
->fw_wpa_auth
, sec
->fw_auth
, sec
->fw_wsec
, sec
->fw_mfp
));
11180 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11181 static s32
wl_cfg80211_bcn_set_params(
11182 struct cfg80211_ap_settings
*info
,
11183 struct net_device
*dev
,
11184 u32 dev_role
, s32 bssidx
)
11186 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
11189 WL_DBG(("interval (%d) \ndtim_period (%d) \n",
11190 info
->beacon_interval
, info
->dtim_period
));
11192 if (info
->beacon_interval
) {
11193 if ((err
= wldev_ioctl_set(dev
, WLC_SET_BCNPRD
,
11194 &info
->beacon_interval
, sizeof(s32
))) < 0) {
11195 WL_ERR(("Beacon Interval Set Error, %d\n", err
));
11200 if (info
->dtim_period
) {
11201 if ((err
= wldev_ioctl_set(dev
, WLC_SET_DTIMPRD
,
11202 &info
->dtim_period
, sizeof(s32
))) < 0) {
11203 WL_ERR(("DTIM Interval Set Error, %d\n", err
));
11208 if ((info
->ssid
) && (info
->ssid_len
> 0) &&
11209 (info
->ssid_len
<= DOT11_MAX_SSID_LEN
)) {
11210 WL_DBG(("SSID (%s) len:%zd \n", info
->ssid
, info
->ssid_len
));
11211 if (dev_role
== NL80211_IFTYPE_AP
) {
11212 /* Store the hostapd SSID */
11213 bzero(cfg
->hostapd_ssid
.SSID
, DOT11_MAX_SSID_LEN
);
11214 memcpy(cfg
->hostapd_ssid
.SSID
, info
->ssid
, info
->ssid_len
);
11215 cfg
->hostapd_ssid
.SSID_len
= (uint32
)info
->ssid_len
;
11218 bzero(cfg
->p2p
->ssid
.SSID
, DOT11_MAX_SSID_LEN
);
11219 memcpy(cfg
->p2p
->ssid
.SSID
, info
->ssid
, info
->ssid_len
);
11220 cfg
->p2p
->ssid
.SSID_len
= (uint32
)info
->ssid_len
;
11226 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11229 wl_cfg80211_parse_ies(const u8
*ptr
, u32 len
, struct parsed_ies
*ies
)
11233 bzero(ies
, sizeof(struct parsed_ies
));
11235 /* find the WPSIE */
11236 if ((ies
->wps_ie
= wl_cfgp2p_find_wpsie(ptr
, len
)) != NULL
) {
11237 WL_DBG(("WPSIE in beacon \n"));
11238 ies
->wps_ie_len
= ies
->wps_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
;
11240 WL_ERR(("No WPSIE in beacon \n"));
11243 /* find the RSN_IE */
11244 if ((ies
->wpa2_ie
= bcm_parse_tlvs(ptr
, len
,
11245 DOT11_MNG_RSN_ID
)) != NULL
) {
11246 WL_DBG((" WPA2 IE found\n"));
11247 ies
->wpa2_ie_len
= ies
->wpa2_ie
->len
;
11250 /* find the FILS_IND_IE */
11251 if ((ies
->fils_ind_ie
= bcm_parse_tlvs(ptr
, len
,
11252 DOT11_MNG_FILS_IND_ID
)) != NULL
) {
11253 WL_DBG((" FILS IND IE found\n"));
11254 ies
->fils_ind_ie_len
= ies
->fils_ind_ie
->len
;
11257 /* find the WPA_IE */
11258 if ((ies
->wpa_ie
= wl_cfgp2p_find_wpaie(ptr
, len
)) != NULL
) {
11259 WL_DBG((" WPA found\n"));
11260 ies
->wpa_ie_len
= ies
->wpa_ie
->length
;
11268 wl_cfg80211_set_ap_role(
11269 struct bcm_cfg80211
*cfg
,
11270 struct net_device
*dev
)
11280 legacy_chip
= wl_legacy_chip_check(cfg
);
11282 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
11283 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
11287 WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n", dev
->name
, bssidx
));
11289 if (bssidx
!= 0 || !legacy_chip
) {
11290 if ((err
= wl_cfg80211_add_del_bss(cfg
, dev
, bssidx
,
11291 WL_IF_TYPE_AP
, 0, NULL
)) < 0) {
11292 WL_ERR(("wl add_del_bss returned error:%d\n", err
));
11298 * For older chips, "bss" iovar does not support
11299 * bsscfg role change/upgradation, and still
11300 * return BCME_OK on attempt
11301 * Hence, below traditional way to handle the same
11304 if ((err
= wldev_ioctl_get(dev
,
11305 WLC_GET_AP
, &ap
, sizeof(s32
))) < 0) {
11306 WL_ERR(("Getting AP mode failed %d \n", err
));
11311 /* AP mode switch not supported. Try setting up AP explicitly */
11312 err
= wldev_iovar_getint(dev
, "apsta", (s32
*)&apsta
);
11313 if (unlikely(err
)) {
11314 WL_ERR(("Could not get apsta %d\n", err
));
11318 /* If apsta is not set, set it */
11320 /* Check for any connected interfaces before wl down */
11321 if (wl_get_drv_status_all(cfg
, CONNECTED
) > 0) {
11322 WL_ERR(("Concurrent i/f operational. can't do wl down"));
11325 err
= wldev_ioctl_set(dev
, WLC_DOWN
, &ap
, sizeof(s32
));
11327 WL_ERR(("WLC_DOWN error %d\n", err
));
11330 err
= wldev_iovar_setint(dev
, "apsta", 0);
11332 WL_ERR(("wl apsta 0 error %d\n", err
));
11336 if ((err
= wldev_ioctl_set(dev
,
11337 WLC_SET_AP
, &ap
, sizeof(s32
))) < 0) {
11338 WL_ERR(("setting AP mode failed %d \n", err
));
11342 } else if (bssidx
== 0 && legacy_chip
) {
11343 err
= wldev_ioctl_set(dev
, WLC_DOWN
, &ap
, sizeof(s32
));
11345 WL_ERR(("WLC_DOWN error %d\n", err
));
11348 err
= wldev_iovar_setint(dev
, "apsta", 0);
11350 WL_ERR(("wl apsta 0 error %d\n", err
));
11354 if ((err
= wldev_ioctl_set(dev
, WLC_SET_AP
, &ap
, sizeof(s32
))) < 0) {
11355 WL_ERR(("setting AP mode failed %d \n", err
));
11362 if ((err
= wldev_ioctl_set(dev
, WLC_SET_PM
, &pm
, sizeof(pm
))) != 0) {
11363 WL_ERR(("wl PM 0 returned error:%d\n", err
));
11364 /* Ignore error, if any */
11367 err
= wldev_ioctl_set(dev
, WLC_SET_INFRA
, &infra
, sizeof(s32
));
11369 WL_ERR(("SET INFRA error %d\n", err
));
11374 /* On success, mark AP creation in progress. */
11375 wl_set_drv_status(cfg
, AP_CREATING
, dev
);
11379 /* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
11380 #define MAX_AP_LINK_WAIT_TIME 10000
11382 wl_cfg80211_bcn_bringup_ap(
11383 struct net_device
*dev
,
11384 struct parsed_ies
*ies
,
11385 u32 dev_role
, s32 bssidx
)
11387 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
11388 struct wl_join_params join_params
;
11389 bool is_bssup
= false;
11391 s32 join_params_size
= 0;
11394 #ifdef DISABLE_11H_SOFTAP
11396 #endif /* DISABLE_11H_SOFTAP */
11397 #ifdef SOFTAP_UAPSD_OFF
11398 uint32 wme_apsd
= 0;
11399 #endif /* SOFTAP_UAPSD_OFF */
11401 s32 is_rsdb_supported
= BCME_ERROR
;
11403 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
11406 is_rsdb_supported
= DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_RSDB_MODE
);
11407 if (is_rsdb_supported
< 0)
11410 WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role
, bssidx
, dev
->name
));
11412 /* Common code for SoftAP and P2P GO */
11413 wl_clr_drv_status(cfg
, AP_CREATED
, dev
);
11415 /* Make sure INFRA is set for AP/GO */
11416 err
= wldev_ioctl_set(dev
, WLC_SET_INFRA
, &infra
, sizeof(s32
));
11418 WL_ERR(("SET INFRA error %d\n", err
));
11422 /* Do abort scan before creating GO */
11423 wl_cfg80211_scan_abort(cfg
);
11425 if (dev_role
== NL80211_IFTYPE_P2P_GO
) {
11426 wl_ext_get_sec(dev
, 0, sec
, sizeof(sec
));
11427 WL_MSG(dev
->name
, "Creating GO with sec=%s\n", sec
);
11428 is_bssup
= wl_cfg80211_bss_isup(dev
, bssidx
);
11429 if (!is_bssup
&& (ies
->wpa2_ie
!= NULL
)) {
11431 err
= wldev_iovar_setbuf_bsscfg(dev
, "ssid", &cfg
->p2p
->ssid
,
11432 sizeof(cfg
->p2p
->ssid
), cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
,
11433 bssidx
, &cfg
->ioctl_buf_sync
);
11435 WL_ERR(("GO SSID setting error %d\n", err
));
11439 if ((err
= wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 1)) < 0) {
11440 WL_ERR(("GO Bring up error %d\n", err
));
11443 wl_clr_drv_status(cfg
, AP_CREATING
, dev
);
11445 WL_DBG(("Bss is already up\n"));
11446 } else if (dev_role
== NL80211_IFTYPE_AP
) {
11448 // if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
11449 /* Make sure fw is in proper state */
11450 err
= wl_cfg80211_set_ap_role(cfg
, dev
);
11451 if (unlikely(err
)) {
11452 WL_ERR(("set ap role failed!\n"));
11457 /* Device role SoftAP */
11458 WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx
, dev_role
));
11459 /* Clear the status bit after use */
11460 wl_clr_drv_status(cfg
, AP_CREATING
, dev
);
11462 #ifdef DISABLE_11H_SOFTAP
11463 /* Some old WLAN card (e.g. Intel PRO/Wireless 2200BG)
11464 * does not try to connect SoftAP because they cannot detect
11465 * 11h IEs. For this reason, we disable 11h feature in case
11466 * of SoftAP mode. (Related CSP case number: 661635)
11468 if (is_rsdb_supported
== 0) {
11469 err
= wldev_ioctl_set(dev
, WLC_DOWN
, &ap
, sizeof(s32
));
11471 WL_ERR(("WLC_DOWN error %d\n", err
));
11475 err
= wldev_ioctl_set(dev
, WLC_SET_SPECT_MANAGMENT
,
11476 &spect
, sizeof(s32
));
11478 WL_ERR(("SET SPECT_MANAGMENT error %d\n", err
));
11481 #endif /* DISABLE_11H_SOFTAP */
11483 #ifdef WL_DISABLE_HE_SOFTAP
11484 err
= wl_cfg80211_set_he_mode(dev
, cfg
, bssidx
, WL_IF_TYPE_AP
, FALSE
);
11486 WL_ERR(("failed to set he features, error=%d\n", err
));
11488 #endif /* WL_DISABLE_HE_SOFTAP */
11490 #ifdef SOFTAP_UAPSD_OFF
11491 err
= wldev_iovar_setbuf_bsscfg(dev
, "wme_apsd", &wme_apsd
, sizeof(wme_apsd
),
11492 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
11494 WL_ERR(("failed to disable uapsd, error=%d\n", err
));
11496 #endif /* SOFTAP_UAPSD_OFF */
11498 err
= wldev_ioctl_set(dev
, WLC_UP
, &ap
, sizeof(s32
));
11499 if (unlikely(err
)) {
11500 WL_ERR(("WLC_UP error (%d)\n", err
));
11505 if (cfg
->bip_pos
) {
11506 err
= wldev_iovar_setbuf_bsscfg(dev
, "bip",
11507 (const void *)(cfg
->bip_pos
), WPA_SUITE_LEN
, cfg
->ioctl_buf
,
11508 WLC_IOCTL_SMLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
11510 WL_ERR(("bip set error %d\n", err
));
11519 err
= wldev_iovar_getint(dev
, "wsec", (s32
*)&wsec
);
11520 if (unlikely(err
)) {
11521 WL_ERR(("Could not get wsec %d\n", err
));
11524 if (dhdp
->conf
->chip
== BCM43430_CHIP_ID
&& bssidx
> 0 &&
11525 (wsec
& (TKIP_ENABLED
|AES_ENABLED
))) {
11526 wsec
|= WSEC_SWFLAG
; // terence 20180628: fix me, this is a workaround
11527 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
11529 WL_ERR(("wsec error %d\n", err
));
11533 if ((wsec
== WEP_ENABLED
) && cfg
->wep_key
.len
) {
11534 WL_DBG(("Applying buffered WEP KEY \n"));
11535 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &cfg
->wep_key
,
11536 sizeof(struct wl_wsec_key
), cfg
->ioctl_buf
,
11537 WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
11538 /* clear the key after use */
11539 bzero(&cfg
->wep_key
, sizeof(struct wl_wsec_key
));
11540 if (unlikely(err
)) {
11541 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
11547 if (cfg
->mfp_mode
) {
11548 /* This needs to go after wsec otherwise the wsec command will
11549 * overwrite the values set by MFP
11551 err
= wldev_iovar_setint_bsscfg(dev
, "mfp", cfg
->mfp_mode
, bssidx
);
11553 WL_ERR(("MFP Setting failed. ret = %d \n", err
));
11554 /* If fw doesn't support mfp, Ignore the error */
11555 if (err
!= BCME_UNSUPPORTED
) {
11562 bzero(&join_params
, sizeof(join_params
));
11563 /* join parameters starts with ssid */
11564 join_params_size
= sizeof(join_params
.ssid
);
11565 join_params
.ssid
.SSID_len
= MIN(cfg
->hostapd_ssid
.SSID_len
,
11566 (uint32
)DOT11_MAX_SSID_LEN
);
11567 memcpy(join_params
.ssid
.SSID
, cfg
->hostapd_ssid
.SSID
,
11568 join_params
.ssid
.SSID_len
);
11569 join_params
.ssid
.SSID_len
= htod32(join_params
.ssid
.SSID_len
);
11571 wl_ext_get_sec(dev
, 0, sec
, sizeof(sec
));
11572 WL_MSG(dev
->name
, "Creating AP with sec=%s\n", sec
);
11573 /* create softap */
11574 if ((err
= wldev_ioctl_set(dev
, WLC_SET_SSID
, &join_params
,
11575 join_params_size
)) != 0) {
11576 WL_ERR(("SoftAP/GO set ssid failed! \n"));
11579 WL_DBG((" SoftAP SSID \"%s\" \n", join_params
.ssid
.SSID
));
11583 /* AP on Virtual Interface */
11584 if ((err
= wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 1)) < 0) {
11585 WL_ERR(("AP Bring up error %d\n", err
));
11591 WL_ERR(("Wrong interface type %d\n", dev_role
));
11595 /* Wait for Linkup event to mark successful AP/GO bring up */
11596 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
11597 wl_get_drv_status(cfg
, AP_CREATED
, dev
), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME
));
11598 if (timeout
<= 0 || !wl_get_drv_status(cfg
, AP_CREATED
, dev
)) {
11599 WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
11600 if (timeout
== -ERESTARTSYS
) {
11601 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
11602 err
= -ERESTARTSYS
;
11605 if (dhd_query_bus_erros(dhdp
)) {
11609 #ifdef DHD_PCIE_RUNTIMEPM
11610 dhdpcie_runtime_bus_wake(dhdp
, CAN_SLEEP(), __builtin_return_address(0));
11611 #endif /* DHD_PCIE_RUNTIMEPM */
11612 dhdp
->iface_op_failed
= TRUE
;
11614 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
11615 if (dhdp
->memdump_enabled
) {
11616 dhdp
->memdump_type
= DUMP_TYPE_AP_LINKUP_FAILURE
;
11617 dhd_bus_mem_dump(dhdp
);
11619 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
11621 WL_ERR(("Notify hang event to upper layer \n"));
11622 dhdp
->hang_reason
= HANG_REASON_IFACE_ADD_FAILURE
;
11623 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg
));
11628 SUPP_LOG(("AP/GO Link up\n"));
11631 if (cfg
->wep_key
.len
) {
11632 bzero(&cfg
->wep_key
, sizeof(struct wl_wsec_key
));
11636 if (cfg
->mfp_mode
) {
11640 if (cfg
->bip_pos
) {
11641 cfg
->bip_pos
= NULL
;
11646 SUPP_LOG(("AP/GO bring up fail. err:%d\n", err
));
11652 wl_cfg80211_macaddr_sync_reqd(struct net_device
*dev
)
11654 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
11655 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
11657 WL_DBG(("enter \n"));
11659 WL_ERR(("no wdev present\n"));
11663 BCM_REFERENCE(cfg
);
11665 #if defined(WL_STATIC_IF)
11666 /* In soft case too role upgrade happens
11667 * from STA to AP in some cases.These
11668 * cases will have iftype as STATION.
11670 if (IS_CFG80211_STATIC_IF(cfg
, dev
)) {
11671 WL_INFORM_MEM(("STATIC interface\n"));
11674 #endif /* WL_STATIC_IF && WL_SOFTAP_RAND */
11676 switch (wdev
->iftype
) {
11678 case NL80211_IFTYPE_P2P_GO
:
11679 case NL80211_IFTYPE_P2P_CLIENT
:
11680 WL_INFORM_MEM(("P2P GO/GC interface\n"));
11682 #endif /* WL_P2P_RAND */
11683 #if defined(WL_STA_ASSOC_RAND)
11684 case NL80211_IFTYPE_STATION
:
11685 WL_INFORM_MEM(("STA interface\n"));
11687 #endif /* WL_STA_ASSOC_RAND */
11688 #ifdef WL_SOFTAP_RAND
11689 case NL80211_IFTYPE_AP
:
11690 WL_INFORM_MEM(("SOFTAP interface\n"));
11692 #endif /* WL_SOFTAP_RAND */
11694 WL_ERR(("no macthing if type\n"));
11699 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11701 wl_cfg80211_parse_ap_ies(
11702 struct net_device
*dev
,
11703 struct cfg80211_beacon_data
*info
,
11704 struct parsed_ies
*ies
)
11706 struct parsed_ies prb_ies
;
11707 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
11708 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
11709 const u8
*vndr
= NULL
;
11710 u32 vndr_ie_len
= 0;
11713 /* Parse Beacon IEs */
11714 if (wl_cfg80211_parse_ies((const u8
*)info
->tail
,
11715 info
->tail_len
, ies
) < 0) {
11716 WL_ERR(("Beacon get IEs failed \n"));
11721 if ((err
= wl_cfg80211_config_rsnxe_ie(cfg
, dev
,
11722 (const u8
*)info
->tail
, info
->tail_len
)) < 0) {
11723 WL_ERR(("Failed to configure rsnxe ie: %d\n", err
));
11728 vndr
= (const u8
*)info
->proberesp_ies
;
11729 vndr_ie_len
= (uint32
)info
->proberesp_ies_len
;
11731 if (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
11733 const struct ieee80211_mgmt
*mgmt
;
11734 mgmt
= (const struct ieee80211_mgmt
*)info
->probe_resp
;
11735 if (mgmt
!= NULL
) {
11736 vndr
= (const u8
*)&mgmt
->u
.probe_resp
.variable
;
11737 vndr_ie_len
= (uint32
)(info
->probe_resp_len
-
11738 offsetof(const struct ieee80211_mgmt
, u
.probe_resp
.variable
));
11741 /* Parse Probe Response IEs */
11742 if (wl_cfg80211_parse_ies((const u8
*)vndr
, vndr_ie_len
, &prb_ies
) < 0) {
11743 WL_ERR(("PROBE RESP get IEs failed \n"));
11752 wl_cfg80211_set_ies(
11753 struct net_device
*dev
,
11754 struct cfg80211_beacon_data
*info
,
11757 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
11758 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
11759 const u8
*vndr
= NULL
;
11760 u32 vndr_ie_len
= 0;
11763 /* Set Beacon IEs to FW */
11764 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
11765 VNDR_IE_BEACON_FLAG
, (const u8
*)info
->tail
,
11766 info
->tail_len
)) < 0) {
11767 WL_ERR(("Set Beacon IE Failed \n"));
11769 WL_DBG(("Applied Vndr IEs for Beacon \n"));
11772 vndr
= (const u8
*)info
->proberesp_ies
;
11773 vndr_ie_len
= (uint32
)info
->proberesp_ies_len
;
11775 if (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
11777 const struct ieee80211_mgmt
*mgmt
;
11778 mgmt
= (const struct ieee80211_mgmt
*)info
->probe_resp
;
11779 if (mgmt
!= NULL
) {
11780 vndr
= (const u8
*)&mgmt
->u
.probe_resp
.variable
;
11781 vndr_ie_len
= (uint32
)(info
->probe_resp_len
-
11782 offsetof(struct ieee80211_mgmt
, u
.probe_resp
.variable
));
11786 /* Set Probe Response IEs to FW */
11787 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
11788 VNDR_IE_PRBRSP_FLAG
, vndr
, vndr_ie_len
)) < 0) {
11789 WL_ERR(("Set Probe Resp IE Failed \n"));
11791 WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
11796 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11798 static s32
wl_cfg80211_hostapd_sec(
11799 struct net_device
*dev
,
11800 struct parsed_ies
*ies
,
11803 bool update_bss
= 0;
11804 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
11805 wl_cfgbss_t
*bss
= wl_get_cfgbss_by_wdev(cfg
, dev
->ieee80211_ptr
);
11808 WL_ERR(("cfgbss is NULL \n"));
11813 /* Remove after verification.
11814 * Setting IE part moved to set_ies func
11817 memcmp(bss
->wps_ie
, ies
->wps_ie
, ies
->wps_ie_len
)) {
11818 WL_DBG((" WPS IE is changed\n"));
11819 MFREE(cfg
->osh
, bss
->wps_ie
, bss
->wps_ie
[1] + 2);
11820 bss
->wps_ie
= MALLOCZ(cfg
->osh
, ies
->wps_ie_len
);
11822 memcpy(bss
->wps_ie
, ies
->wps_ie
, ies
->wps_ie_len
);
11824 } else if (bss
->wps_ie
== NULL
) {
11825 WL_DBG((" WPS IE is added\n"));
11826 bss
->wps_ie
= MALLOCZ(cfg
->osh
, ies
->wps_ie_len
);
11828 memcpy(bss
->wps_ie
, ies
->wps_ie
, ies
->wps_ie_len
);
11832 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11833 if (ies
->wpa_ie
!= NULL
&& ies
->wpa2_ie
!= NULL
) {
11834 WL_ERR(("update bss - wpa_ie and wpa2_ie is not null\n"));
11835 if (!bss
->security_mode
) {
11836 /* change from open mode to security mode */
11838 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
11839 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11841 memcpy(bss
->wpa_ie
, ies
->wpa_ie
,
11842 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11844 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
11845 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11847 memcpy(bss
->rsn_ie
, ies
->wpa2_ie
,
11848 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11851 /* change from (WPA or WPA2 or WPA/WPA2) to WPA/WPA2 mixed mode */
11853 if (memcmp(bss
->wpa_ie
,
11854 ies
->wpa_ie
, ies
->wpa_ie
->length
+
11855 WPA_RSN_IE_TAG_FIXED_LEN
)) {
11856 MFREE(cfg
->osh
, bss
->wpa_ie
,
11857 bss
->wpa_ie
[1] + WPA_RSN_IE_TAG_FIXED_LEN
);
11859 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
11860 ies
->wpa_ie
->length
11861 + WPA_RSN_IE_TAG_FIXED_LEN
);
11863 memcpy(bss
->wpa_ie
, ies
->wpa_ie
,
11864 ies
->wpa_ie
->length
11865 + WPA_RSN_IE_TAG_FIXED_LEN
);
11871 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
11872 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11874 memcpy(bss
->wpa_ie
, ies
->wpa_ie
,
11875 ies
->wpa_ie
->length
11876 + WPA_RSN_IE_TAG_FIXED_LEN
);
11880 if (memcmp(bss
->rsn_ie
,
11882 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
)) {
11884 MFREE(cfg
->osh
, bss
->rsn_ie
,
11885 bss
->rsn_ie
[1] + WPA_RSN_IE_TAG_FIXED_LEN
);
11886 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
11888 + WPA_RSN_IE_TAG_FIXED_LEN
);
11890 memcpy(bss
->rsn_ie
, ies
->wpa2_ie
,
11892 + WPA_RSN_IE_TAG_FIXED_LEN
);
11898 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
11900 + WPA_RSN_IE_TAG_FIXED_LEN
);
11902 memcpy(bss
->rsn_ie
, ies
->wpa2_ie
,
11904 + WPA_RSN_IE_TAG_FIXED_LEN
);
11908 WL_ERR(("update_bss=%d\n", update_bss
));
11910 bss
->security_mode
= true;
11911 wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 0);
11912 if (wl_validate_wpaie_wpa2ie(dev
, ies
->wpa_ie
,
11913 ies
->wpa2_ie
, bssidx
) < 0) {
11916 wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 1);
11921 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11922 if ((ies
->wpa_ie
!= NULL
|| ies
->wpa2_ie
!= NULL
)) {
11923 if (!bss
->security_mode
) {
11924 /* change from open mode to security mode */
11926 if (ies
->wpa_ie
!= NULL
) {
11927 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
11928 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11930 memcpy(bss
->wpa_ie
,
11932 ies
->wpa_ie
->length
11933 + WPA_RSN_IE_TAG_FIXED_LEN
);
11936 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
11937 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11939 memcpy(bss
->rsn_ie
,
11942 + WPA_RSN_IE_TAG_FIXED_LEN
);
11945 } else if (bss
->wpa_ie
) {
11946 /* change from WPA2 mode to WPA mode */
11947 if (ies
->wpa_ie
!= NULL
) {
11949 MFREE(cfg
->osh
, bss
->rsn_ie
,
11950 bss
->rsn_ie
[1] + WPA_RSN_IE_TAG_FIXED_LEN
);
11951 bss
->rsn_ie
= NULL
;
11952 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
11953 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11955 memcpy(bss
->wpa_ie
,
11957 ies
->wpa_ie
->length
11958 + WPA_RSN_IE_TAG_FIXED_LEN
);
11960 } else if (memcmp(bss
->rsn_ie
,
11961 ies
->wpa2_ie
, ies
->wpa2_ie
->len
11962 + WPA_RSN_IE_TAG_FIXED_LEN
)) {
11964 MFREE(cfg
->osh
, bss
->rsn_ie
,
11965 bss
->rsn_ie
[1] + WPA_RSN_IE_TAG_FIXED_LEN
);
11966 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
11967 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11969 memcpy(bss
->rsn_ie
,
11972 + WPA_RSN_IE_TAG_FIXED_LEN
);
11974 bss
->wpa_ie
= NULL
;
11978 bss
->security_mode
= true;
11979 wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 0);
11980 if (wl_validate_wpa2ie(dev
, ies
->wpa2_ie
, bssidx
) < 0 ||
11981 wl_validate_wpaie(dev
, ies
->wpa_ie
, bssidx
) < 0) {
11984 wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 1);
11988 WL_ERR(("No WPSIE in beacon \n"));
11993 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
11996 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11997 wl_cfg80211_del_station(
11998 struct wiphy
*wiphy
, struct net_device
*ndev
,
11999 struct station_del_parameters
*params
)
12000 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
12001 wl_cfg80211_del_station(
12002 struct wiphy
*wiphy
,
12003 struct net_device
*ndev
,
12004 const u8
* mac_addr
)
12006 wl_cfg80211_del_station(
12007 struct wiphy
*wiphy
,
12008 struct net_device
*ndev
,
12010 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12012 struct net_device
*dev
;
12013 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
12015 s8 eabuf
[ETHER_ADDR_STR_LEN
];
12017 char mac_buf
[MAX_NUM_OF_ASSOCIATED_DEV
*
12018 sizeof(struct ether_addr
) + sizeof(uint
)] = {0};
12019 struct maclist
*assoc_maclist
= (struct maclist
*)mac_buf
;
12020 int num_associated
= 0;
12022 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12023 const u8
*mac_addr
= params
->mac
;
12024 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
12025 u16 rc
= params
->reason_code
;
12026 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
12027 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12029 WL_DBG(("Entry\n"));
12030 if (mac_addr
== NULL
) {
12031 WL_DBG(("mac_addr is NULL ignore it\n"));
12035 dev
= ndev_to_wlc_ndev(ndev
, cfg
);
12037 if (p2p_is_on(cfg
)) {
12038 /* Suspend P2P discovery search-listen to prevent it from changing the
12041 if ((wl_cfgp2p_discover_enable_search(cfg
, false)) < 0) {
12042 WL_ERR(("Can not disable discovery mode\n"));
12046 err
= wl_cfg80211_check_in4way(cfg
, ndev
, DONT_DELETE_GC_AFTER_WPS
,
12047 WL_EXT_STATUS_DELETE_STA
, (void *)mac_addr
);
12052 assoc_maclist
->count
= MAX_NUM_OF_ASSOCIATED_DEV
;
12053 err
= wldev_ioctl_get(ndev
, WLC_GET_ASSOCLIST
,
12054 assoc_maclist
, sizeof(mac_buf
));
12056 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err
));
12058 num_associated
= assoc_maclist
->count
;
12060 memcpy(scb_val
.ea
.octet
, mac_addr
, ETHER_ADDR_LEN
);
12061 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
12062 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12063 if (rc
== DOT11_RC_8021X_AUTH_FAIL
) {
12064 WL_ERR(("deauth will be sent at F/W\n"));
12065 scb_val
.val
= DOT11_RC_8021X_AUTH_FAIL
;
12067 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12068 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
12071 if (wl_wps_session_update(ndev
,
12072 WPS_STATE_DISCONNECT_CLIENT
, mac_addr
) == BCME_UNSUPPORTED
) {
12073 /* Ignore disconnect command from upper layer */
12074 WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
12076 #endif /* WL_WPS_SYNC */
12078 scb_val
.val
= DOT11_RC_DEAUTH_LEAVING
;
12079 WL_MSG(dev
->name
, "Disconnect STA : " MACDBG
" scb_val.val %d\n",
12080 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr
*)mac_addr
,
12081 eabuf
)), scb_val
.val
);
12082 /* need to guarantee EAP-Failure send out before deauth */
12083 dhd_wait_pend8021x(dev
);
12084 err
= wldev_ioctl_set(dev
, WLC_SCB_DEAUTHENTICATE_FOR_REASON
, &scb_val
,
12085 sizeof(scb_val_t
));
12087 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err
));
12090 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
12091 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12093 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12094 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
12096 /* WAR Wait for the deauth event to come, supplicant will do the
12097 * delete iface immediately and we will have problem in sending
12098 * deauth frame if we delete the bss in firmware
12099 * But we do not need additional delays for this WAR
12100 * during P2P connection.
12102 * Supplicant call this function with BCAST after doing
12103 * wl_cfg80211_del_station() all GC stations with each addr.
12104 * So, 400 ms delay can be called only once when GO disconnect all GC
12106 if (num_associated
> 0 && ETHER_ISBCAST(mac_addr
))
12112 /* Implementation for post SCB authorize */
12114 wl_cfg80211_post_scb_auth(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
12117 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
12118 #endif /* WBTEXT */
12120 LOG_TS(cfg
, authorize_cmplt
);
12121 CLR_TS(cfg
, authorize_start
);
12122 wl_set_drv_status(cfg
, AUTHORIZED
, dev
);
12123 #ifdef DHD_LOSSLESS_ROAMING
12124 wl_del_roam_timeout(cfg
);
12127 /* send nbr request or BTM query to update RCC
12128 * after 4-way handshake is completed
12130 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
&&
12131 dhdp
->wbtext_support
) {
12132 wl_cfg80211_wbtext_update_rcc(cfg
, dev
);
12134 #endif /* WBTEXT */
12137 /* Currently adding support only for authorize/de-authorize flag
12138 * Need to be extended in future
12140 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
12142 wl_cfg80211_change_station(
12143 struct wiphy
*wiphy
,
12144 struct net_device
*dev
,
12146 struct station_parameters
*params
)
12149 wl_cfg80211_change_station(
12150 struct wiphy
*wiphy
,
12151 struct net_device
*dev
,
12153 struct station_parameters
*params
)
12157 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
12158 #ifdef BCMSUP_4WAY_HANDSHAKE
12159 struct wl_security
*sec
;
12160 #endif /* BCMSUP_4WAY_HANDSHAKE */
12161 struct net_device
*ndev
= ndev_to_wlc_ndev(dev
, cfg
);
12163 WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG
" sta_flags_mask:0x%x "
12164 "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac
),
12165 params
->sta_flags_mask
, params
->sta_flags_set
, ndev
->name
));
12167 if ((wl_get_mode_by_netdev(cfg
, dev
) == WL_MODE_BSS
) &&
12168 !(wl_get_drv_status(cfg
, CONNECTED
, dev
))) {
12169 /* Return error indicating not in connected state */
12170 WL_ERR(("Ignore SCB_AUTHORIZE/DEAUTHORIZE in non connected state\n"));
12174 /* Processing only authorize/de-authorize flag for now */
12175 if (!(params
->sta_flags_mask
& BIT(NL80211_STA_FLAG_AUTHORIZED
))) {
12176 WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
12180 if (!(params
->sta_flags_set
& BIT(NL80211_STA_FLAG_AUTHORIZED
))) {
12181 err
= wldev_ioctl_set(ndev
, WLC_SCB_DEAUTHORIZE
, mac
, ETH_ALEN
);
12182 if (unlikely(err
)) {
12183 WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err
));
12185 WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG
"\n",
12186 ndev
->name
, MAC2STRDBG(mac
)));
12188 wl_clr_drv_status(cfg
, AUTHORIZED
, dev
);
12189 CLR_TS(cfg
, authorize_start
);
12190 CLR_TS(cfg
, conn_start
);
12193 /* In case of 4way HS offloaded to FW and key_mgmt being 8021x, even the SCB
12194 * authorization is also offloaded to FW. So on reception of SCB authorize in the above
12195 * cases we avoid explicit call to ioctl WLC_SCB_AUTHORIZE. The post SCB authorize
12196 * actions are done from context of WLC_E_PSK_SUP event handler
12198 #ifdef BCMSUP_4WAY_HANDSHAKE
12199 sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
12201 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
12202 (wiphy_ext_feature_isset(wiphy
, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X
)) &&
12204 (cfg
->wdev
->wiphy
->features
& NL80211_FEATURE_FW_4WAY_HANDSHAKE
) &&
12206 ((sec
->wpa_auth
== WLAN_AKM_SUITE_8021X
) ||
12207 (sec
->wpa_auth
== WL_AKM_SUITE_SHA256_1X
))) {
12210 #endif /* BCMSUP_4WAY_HANDSHAKE */
12211 err
= wldev_ioctl_set(ndev
, WLC_SCB_AUTHORIZE
, mac
, ETH_ALEN
);
12212 if (unlikely(err
)) {
12213 WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err
));
12215 WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG
"\n",
12216 ndev
->name
, MAC2STRDBG(mac
)));
12218 wl_wps_session_update(ndev
, WPS_STATE_AUTHORIZE
, mac
);
12219 #endif /* WL_WPS_SYNC */
12222 /* Post SCB authorize actions */
12223 wl_cfg80211_post_scb_auth(cfg
, ndev
);
12227 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
12230 wl_cfg80211_set_scb_timings(
12231 struct bcm_cfg80211
*cfg
,
12232 struct net_device
*dev
)
12236 wl_scb_probe_t scb_probe
;
12237 u32 ps_pretend_retries
;
12239 bzero(&scb_probe
, sizeof(wl_scb_probe_t
));
12240 scb_probe
.scb_timeout
= WL_SCB_TIMEOUT
;
12241 scb_probe
.scb_activity_time
= WL_SCB_ACTIVITY_TIME
;
12242 scb_probe
.scb_max_probe
= WL_SCB_MAX_PROBE
;
12243 err
= wldev_iovar_setbuf(dev
, "scb_probe", (void *)&scb_probe
,
12244 sizeof(wl_scb_probe_t
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
,
12245 &cfg
->ioctl_buf_sync
);
12246 if (unlikely(err
)) {
12247 WL_ERR(("set 'scb_probe' failed, error = %d\n", err
));
12251 ps_pretend_retries
= WL_PSPRETEND_RETRY_LIMIT
;
12252 err
= wldev_iovar_setint(dev
, "pspretend_retry_limit", ps_pretend_retries
);
12253 if (unlikely(err
)) {
12254 if (err
== BCME_UNSUPPORTED
) {
12255 /* Ignore error if fw doesn't support the iovar */
12256 WL_DBG(("set 'pspretend_retry_limit %d' failed, error = %d\n",
12257 ps_pretend_retries
, err
));
12259 WL_ERR(("set 'pspretend_retry_limit %d' failed, error = %d\n",
12260 ps_pretend_retries
, err
));
12265 ps_pretend
= MAX(WL_SCB_MAX_PROBE
/ 2, WL_MIN_PSPRETEND_THRESHOLD
);
12266 err
= wldev_iovar_setint(dev
, "pspretend_threshold", ps_pretend
);
12267 if (unlikely(err
)) {
12268 if (err
== BCME_UNSUPPORTED
) {
12269 /* Ignore error if fw doesn't support the iovar */
12270 WL_DBG(("wl pspretend_threshold %d set error %d\n",
12273 WL_ERR(("wl pspretend_threshold %d set error %d\n",
12282 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
12284 wl_cfg80211_start_ap(
12285 struct wiphy
*wiphy
,
12286 struct net_device
*dev
,
12287 struct cfg80211_ap_settings
*info
)
12289 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
12291 struct parsed_ies ies
;
12294 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
12296 WL_DBG(("Enter \n"));
12298 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
12299 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
12303 if (p2p_is_on(cfg
) && (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
)) {
12304 dev_role
= NL80211_IFTYPE_P2P_GO
;
12305 } else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
12307 if (!wl_get_drv_status(cfg
, AP_CREATING
, dev
)) {
12308 /* Make sure fw is in proper state */
12309 err
= wl_cfg80211_set_ap_role(cfg
, dev
);
12310 if (unlikely(err
)) {
12311 WL_ERR(("set ap role failed!\n"));
12315 dev_role
= NL80211_IFTYPE_AP
;
12316 dhd
->op_mode
|= DHD_FLAG_HOSTAP_MODE
;
12317 err
= dhd_ndo_enable(dhd
, FALSE
);
12318 WL_DBG(("Disabling NDO on Hostapd mode %d\n", err
));
12320 WL_ERR(("Disabling NDO Failed %d\n", err
));
12322 #ifdef WL_EXT_IAPSTA
12323 wl_ext_iapsta_update_iftype(dev
, dhd_net2idx(dhd
->info
, dev
), WL_IF_TYPE_AP
);
12324 #endif /* WL_EXT_IAPSTA */
12325 #ifdef PKT_FILTER_SUPPORT
12326 /* Disable packet filter */
12327 if (dhd
->early_suspended
) {
12328 WL_ERR(("Disable pkt_filter\n"));
12329 dhd_enable_packet_filter(0, dhd
);
12331 dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd
));
12334 #endif /* PKT_FILTER_SUPPORT */
12336 /* only AP or GO role need to be handled here. */
12344 /* Disable TDLS for primary Iface. For virtual interface,
12345 * tdls disable will happen from interface create context
12347 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_AP_CREATE
, false);
12349 #endif /* WLTDLS */
12351 if (!check_dev_role_integrity(cfg
, dev_role
)) {
12358 * Check whether 802.11ac-160MHz bandwidth channel setting has to use the
12359 * center frequencies present in 'preset_chandef' instead of using the
12360 * hardcoded values in 'wl_cfg80211_set_channel()'.
12362 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
12363 if ((err
= wl_cfg80211_set_channel(wiphy
, dev
,
12364 dev
->ieee80211_ptr
->preset_chandef
.chan
,
12365 NL80211_CHAN_HT20
) < 0)) {
12366 WL_ERR(("Set channel failed \n"));
12369 #endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
12371 if ((err
= wl_cfg80211_bcn_set_params(info
, dev
,
12372 dev_role
, bssidx
)) < 0) {
12373 WL_ERR(("Beacon params set failed \n"));
12378 if ((err
= wl_cfg80211_parse_ap_ies(dev
, &info
->beacon
, &ies
)) < 0) {
12379 WL_ERR(("Set IEs failed \n"));
12383 if ((err
= wl_cfg80211_bcn_validate_sec(dev
, &ies
,
12384 dev_role
, bssidx
, info
->privacy
)) < 0)
12386 WL_ERR(("Beacon set security failed \n"));
12390 if ((err
= wl_cfg80211_bcn_bringup_ap(dev
, &ies
,
12391 dev_role
, bssidx
)) < 0) {
12392 WL_ERR(("Beacon bring up AP/GO failed \n"));
12396 /* Set GC/STA SCB expiry timings. */
12397 if ((err
= wl_cfg80211_set_scb_timings(cfg
, dev
))) {
12398 WL_ERR(("scb setting failed \n"));
12402 wl_set_drv_status(cfg
, CONNECTED
, dev
);
12403 WL_DBG(("** AP/GO Created **\n"));
12405 #ifdef WL_CFG80211_ACL
12406 /* Enfoce Admission Control. */
12407 if ((err
= wl_cfg80211_set_mac_acl(wiphy
, dev
, info
->acl
)) < 0) {
12408 WL_ERR(("Set ACL failed\n"));
12410 #endif /* WL_CFG80211_ACL */
12412 /* Set IEs to FW */
12413 if ((err
= wl_cfg80211_set_ies(dev
, &info
->beacon
, bssidx
)) < 0)
12414 WL_ERR(("Set IEs failed \n"));
12417 if (dev
->ieee80211_ptr
->use_4addr
) {
12418 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
12419 VNDR_IE_ASSOCRSP_FLAG
, (const u8
*)info
->beacon
.assocresp_ies
,
12420 info
->beacon
.assocresp_ies_len
)) < 0) {
12421 WL_ERR(("Set ASSOC RESP IE Failed\n"));
12424 #endif /* WLDWDS */
12426 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12427 if ((dev_role
== NL80211_IFTYPE_AP
) && (ies
.wps_ie
!= NULL
)) {
12429 wl_validate_wps_ie((const char *) ies
.wps_ie
, ies
.wps_ie_len
, &pbc
);
12431 WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
12432 wl_add_remove_eventmsg(dev
, WLC_E_PROBREQ_MSG
, true);
12436 /* Configure hidden SSID */
12437 if (info
->hidden_ssid
!= NL80211_HIDDEN_SSID_NOT_IN_USE
) {
12438 if ((err
= wldev_iovar_setint(dev
, "closednet", 1)) < 0)
12439 WL_ERR(("failed to set hidden : %d\n", err
));
12440 WL_DBG(("hidden_ssid_enum_val: %d \n", info
->hidden_ssid
));
12443 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12444 if (dev_role
== NL80211_IFTYPE_AP
) {
12445 if (!wl_set_ap_rps(dev
, FALSE
, dev
->name
)) {
12446 wl_cfg80211_init_ap_rps(cfg
);
12448 WL_ERR(("Set rpsnoa failed \n"));
12451 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12454 WL_ERR(("ADD/SET beacon failed\n"));
12455 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
12456 wl_cfg80211_stop_ap(wiphy
, dev
);
12457 if (dev_role
== NL80211_IFTYPE_AP
) {
12458 #ifdef WL_EXT_IAPSTA
12459 if (!wl_ext_iapsta_iftype_enabled(dev
, WL_IF_TYPE_AP
)) {
12460 #endif /* WL_EXT_IAPSTA */
12461 dhd
->op_mode
&= ~DHD_FLAG_HOSTAP_MODE
;
12462 #ifdef PKT_FILTER_SUPPORT
12463 /* Enable packet filter */
12464 if (dhd
->early_suspended
) {
12465 WL_ERR(("Enable pkt_filter\n"));
12466 dhd_enable_packet_filter(1, dhd
);
12468 dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd
));
12471 #endif /* PKT_FILTER_SUPPORT */
12472 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12473 wl_cfg80211_set_frameburst(cfg
, TRUE
);
12474 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12475 #ifdef WL_EXT_IAPSTA
12477 #endif /* WL_EXT_IAPSTA */
12481 /* Since AP creation failed, re-enable TDLS */
12482 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_AP_DELETE
, false);
12484 #endif /* WLTDLS */
12492 wl_cfg80211_stop_ap(
12493 struct wiphy
*wiphy
,
12494 struct net_device
*dev
)
12500 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
12501 s32 is_rsdb_supported
= BCME_ERROR
;
12502 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
12504 WL_DBG(("Enter \n"));
12506 if (wl_cfg80211_get_bus_state(cfg
)) {
12507 /* since bus is down, iovar will fail. recovery path will bringup the bus. */
12508 WL_ERR(("bus is not ready\n"));
12511 is_rsdb_supported
= DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_RSDB_MODE
);
12512 if (is_rsdb_supported
< 0)
12515 wl_clr_drv_status(cfg
, AP_CREATING
, dev
);
12516 wl_clr_drv_status(cfg
, AP_CREATED
, dev
);
12517 cfg
->ap_oper_channel
= INVCHANSPEC
;
12519 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
12520 dev_role
= NL80211_IFTYPE_AP
;
12521 WL_DBG(("stopping AP operation\n"));
12522 } else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
12523 dev_role
= NL80211_IFTYPE_P2P_GO
;
12524 WL_DBG(("stopping P2P GO operation\n"));
12526 WL_ERR(("no AP/P2P GO interface is operational.\n"));
12530 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
12531 WL_ERR(("find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
12535 if (!check_dev_role_integrity(cfg
, dev_role
)) {
12536 WL_ERR(("role integrity check failed \n"));
12541 /* Free up resources */
12542 wl_cfg80211_cleanup_if(dev
);
12544 /* Clear AP/GO connected status */
12545 wl_clr_drv_status(cfg
, CONNECTED
, dev
);
12546 if ((err
= wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 0)) < 0) {
12547 WL_ERR(("bss down error %d\n", err
));
12550 if (dev_role
== NL80211_IFTYPE_AP
) {
12551 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12552 wl_cfg80211_set_frameburst(cfg
, TRUE
);
12553 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12554 #ifdef PKT_FILTER_SUPPORT
12555 /* Enable packet filter */
12556 if (dhd
->early_suspended
) {
12557 WL_ERR(("Enable pkt_filter\n"));
12558 dhd_enable_packet_filter(1, dhd
);
12560 dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd
));
12563 #endif /* PKT_FILTER_SUPPORT */
12565 if (is_rsdb_supported
== 0) {
12566 /* For non-rsdb chips, we use stand alone AP. Do wl down on stop AP */
12567 err
= wldev_ioctl_set(dev
, WLC_UP
, &ap
, sizeof(s32
));
12568 if (unlikely(err
)) {
12569 WL_ERR(("WLC_UP error (%d)\n", err
));
12575 #ifdef WL_DISABLE_HE_SOFTAP
12576 if (wl_cfg80211_set_he_mode(dev
, cfg
, bssidx
, WL_IF_TYPE_AP
, TRUE
) != BCME_OK
) {
12577 WL_ERR(("failed to set he features\n"));
12579 #endif /* WL_DISABLE_HE_SOFTAP */
12581 wl_cfg80211_clear_per_bss_ies(cfg
, dev
->ieee80211_ptr
);
12582 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12583 if (!wl_set_ap_rps(dev
, FALSE
, dev
->name
)) {
12584 wl_cfg80211_init_ap_rps(cfg
);
12586 WL_ERR(("Set rpsnoa failed \n"));
12588 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12590 /* Do we need to do something here */
12591 WL_DBG(("Stopping P2P GO \n"));
12593 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t
*)(cfg
->pub
),
12594 DHD_EVENT_TIMEOUT_MS
*3);
12595 DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t
*)(cfg
->pub
));
12599 SUPP_LOG(("AP/GO Link down\n"));
12602 /* In case of failure, flush fw logs */
12603 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
12604 SUPP_LOG(("AP/GO Link down fail. err:%d\n", err
));
12608 /* re-enable TDLS if the number of connected interfaces is less than 2 */
12609 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_AP_DELETE
, false);
12611 #endif /* WLTDLS */
12613 if (dev_role
== NL80211_IFTYPE_AP
) {
12614 #ifdef WL_EXT_IAPSTA
12615 if (!wl_ext_iapsta_iftype_enabled(dev
, WL_IF_TYPE_AP
)) {
12616 #endif /* WL_EXT_IAPSTA */
12617 /* clear the AP mode */
12618 dhd
->op_mode
&= ~DHD_FLAG_HOSTAP_MODE
;
12619 #ifdef WL_EXT_IAPSTA
12621 #endif /* WL_EXT_IAPSTA */
12627 wl_cfg80211_change_beacon(
12628 struct wiphy
*wiphy
,
12629 struct net_device
*dev
,
12630 struct cfg80211_beacon_data
*info
)
12633 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
12634 struct parsed_ies ies
;
12639 WL_DBG(("Enter \n"));
12641 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
12642 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
12646 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
12647 dev_role
= NL80211_IFTYPE_P2P_GO
;
12648 } else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
12649 dev_role
= NL80211_IFTYPE_AP
;
12655 if (!check_dev_role_integrity(cfg
, dev_role
)) {
12660 if ((dev_role
== NL80211_IFTYPE_P2P_GO
) && (cfg
->p2p_wdev
== NULL
)) {
12661 WL_ERR(("P2P already down status!\n"));
12667 if ((err
= wl_cfg80211_parse_ap_ies(dev
, info
, &ies
)) < 0) {
12668 WL_ERR(("Parse IEs failed \n"));
12672 /* Set IEs to FW */
12673 if ((err
= wl_cfg80211_set_ies(dev
, info
, bssidx
)) < 0) {
12674 WL_ERR(("Set IEs failed \n"));
12678 if (dev_role
== NL80211_IFTYPE_AP
) {
12679 if (wl_cfg80211_hostapd_sec(dev
, &ies
, bssidx
) < 0) {
12680 WL_ERR(("Hostapd update sec failed \n"));
12684 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12685 if ((dev_role
== NL80211_IFTYPE_AP
) && (ies
.wps_ie
!= NULL
)) {
12686 wl_validate_wps_ie((const char *) ies
.wps_ie
, ies
.wps_ie_len
, &pbc
);
12687 WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc
));
12689 wl_add_remove_eventmsg(dev
, WLC_E_PROBREQ_MSG
, true);
12691 wl_add_remove_eventmsg(dev
, WLC_E_PROBREQ_MSG
, false);
12697 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
12703 wl_cfg80211_add_set_beacon(struct wiphy
*wiphy
, struct net_device
*dev
,
12704 struct beacon_parameters
*info
)
12707 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
12710 u32 dev_role
= NL80211_IFTYPE_AP
;
12711 struct parsed_ies ies
;
12712 bcm_tlv_t
*ssid_ie
;
12715 bool is_bss_up
= 0;
12716 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
12718 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
12719 info
->interval
, info
->dtim_period
, info
->head_len
, info
->tail_len
));
12721 if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
12722 dev_role
= NL80211_IFTYPE_AP
;
12724 #if defined(WL_ENABLE_P2P_IF)
12725 else if (dev
== cfg
->p2p_net
) {
12726 /* Group Add request on p2p0 */
12727 dev
= bcmcfg_to_prmry_ndev(cfg
);
12728 dev_role
= NL80211_IFTYPE_P2P_GO
;
12730 #endif /* WL_ENABLE_P2P_IF */
12732 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
12733 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
12737 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
12738 dev_role
= NL80211_IFTYPE_P2P_GO
;
12739 } else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
12740 dhd
->op_mode
|= DHD_FLAG_HOSTAP_MODE
;
12743 if (!check_dev_role_integrity(cfg
, dev_role
)) {
12748 if ((dev_role
== NL80211_IFTYPE_P2P_GO
) && (cfg
->p2p_wdev
== NULL
)) {
12749 WL_ERR(("P2P already down status!\n"));
12754 ie_offset
= DOT11_MGMT_HDR_LEN
+ DOT11_BCN_PRB_FIXED_LEN
;
12755 /* find the SSID */
12756 if ((ssid_ie
= bcm_parse_tlvs((u8
*)&info
->head
[ie_offset
],
12757 info
->head_len
- ie_offset
,
12758 DOT11_MNG_SSID_ID
)) != NULL
) {
12759 if (dev_role
== NL80211_IFTYPE_AP
) {
12760 /* Store the hostapd SSID */
12761 bzero(&cfg
->hostapd_ssid
.SSID
[0], DOT11_MAX_SSID_LEN
);
12762 cfg
->hostapd_ssid
.SSID_len
= MIN(ssid_ie
->len
, DOT11_MAX_SSID_LEN
);
12763 memcpy(&cfg
->hostapd_ssid
.SSID
[0], ssid_ie
->data
,
12764 cfg
->hostapd_ssid
.SSID_len
);
12767 bzero(&cfg
->p2p
->ssid
.SSID
[0], DOT11_MAX_SSID_LEN
);
12768 cfg
->p2p
->ssid
.SSID_len
= MIN(ssid_ie
->len
, DOT11_MAX_SSID_LEN
);
12769 memcpy(cfg
->p2p
->ssid
.SSID
, ssid_ie
->data
,
12770 cfg
->p2p
->ssid
.SSID_len
);
12774 if (wl_cfg80211_parse_ies((u8
*)info
->tail
,
12775 info
->tail_len
, &ies
) < 0) {
12776 WL_ERR(("Beacon get IEs failed \n"));
12781 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
12782 VNDR_IE_BEACON_FLAG
, (u8
*)info
->tail
,
12783 info
->tail_len
)) < 0) {
12784 WL_ERR(("Beacon set IEs failed \n"));
12787 WL_DBG(("Applied Vndr IEs for Beacon \n"));
12790 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12791 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
12792 VNDR_IE_PRBRSP_FLAG
, (u8
*)info
->proberesp_ies
,
12793 info
->proberesp_ies_len
)) < 0) {
12794 WL_ERR(("ProbeRsp set IEs failed \n"));
12797 WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
12801 is_bss_up
= wl_cfg80211_bss_isup(dev
, bssidx
);
12803 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12804 privacy
= info
->privacy
;
12809 (wl_cfg80211_bcn_validate_sec(dev
, &ies
, dev_role
, bssidx
, privacy
) < 0))
12811 WL_ERR(("Beacon set security failed \n"));
12816 /* Set BI and DTIM period */
12817 if (info
->interval
) {
12818 if ((err
= wldev_ioctl_set(dev
, WLC_SET_BCNPRD
,
12819 &info
->interval
, sizeof(s32
))) < 0) {
12820 WL_ERR(("Beacon Interval Set Error, %d\n", err
));
12824 if (info
->dtim_period
) {
12825 if ((err
= wldev_ioctl_set(dev
, WLC_SET_DTIMPRD
,
12826 &info
->dtim_period
, sizeof(s32
))) < 0) {
12827 WL_ERR(("DTIM Interval Set Error, %d\n", err
));
12832 /* If bss is already up, skip bring up */
12834 (err
= wl_cfg80211_bcn_bringup_ap(dev
, &ies
, dev_role
, bssidx
)) < 0)
12836 WL_ERR(("Beacon bring up AP/GO failed \n"));
12840 /* Set GC/STA SCB expiry timings. */
12841 if ((err
= wl_cfg80211_set_scb_timings(cfg
, dev
))) {
12842 WL_ERR(("scb setting failed \n"));
12843 if (err
== BCME_UNSUPPORTED
)
12848 if (wl_get_drv_status(cfg
, AP_CREATED
, dev
)) {
12849 /* Soft AP already running. Update changed params */
12850 if (wl_cfg80211_hostapd_sec(dev
, &ies
, bssidx
) < 0) {
12851 WL_ERR(("Hostapd update sec failed \n"));
12857 /* Enable Probe Req filter */
12858 if (((dev_role
== NL80211_IFTYPE_P2P_GO
) ||
12859 (dev_role
== NL80211_IFTYPE_AP
)) && (ies
.wps_ie
!= NULL
)) {
12860 wl_validate_wps_ie((char *) ies
.wps_ie
, ies
.wps_ie_len
, &pbc
);
12862 wl_add_remove_eventmsg(dev
, WLC_E_PROBREQ_MSG
, true);
12865 WL_DBG(("** ADD/SET beacon done **\n"));
12866 wl_set_drv_status(cfg
, CONNECTED
, dev
);
12870 WL_ERR(("ADD/SET beacon failed\n"));
12871 if (dev_role
== NL80211_IFTYPE_AP
) {
12872 #ifdef WL_EXT_IAPSTA
12873 if (!wl_ext_iapsta_iftype_enabled(dev
, WL_IF_TYPE_AP
)) {
12874 #endif /* WL_EXT_IAPSTA */
12875 /* clear the AP mode */
12876 dhd
->op_mode
&= ~DHD_FLAG_HOSTAP_MODE
;
12877 #ifdef WL_EXT_IAPSTA
12879 #endif /* WL_EXT_IAPSTA */
12887 wl_cfg80211_del_beacon(struct wiphy
*wiphy
, struct net_device
*dev
)
12892 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
12893 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
12894 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
12896 WL_DBG(("Enter. \n"));
12899 WL_ERR(("wdev null \n"));
12903 if ((wdev
->iftype
!= NL80211_IFTYPE_P2P_GO
) && (wdev
->iftype
!= NL80211_IFTYPE_AP
)) {
12904 WL_ERR(("Unspported iface type iftype:%d \n", wdev
->iftype
));
12907 wl_clr_drv_status(cfg
, AP_CREATING
, dev
);
12908 wl_clr_drv_status(cfg
, AP_CREATED
, dev
);
12910 /* Clear AP/GO connected status */
12911 wl_clr_drv_status(cfg
, CONNECTED
, dev
);
12913 cfg
->ap_oper_channel
= INVCHANSPEC
;
12915 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
12916 WL_ERR(("find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
12921 if ((err
= wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 0)) < 0) {
12922 WL_ERR(("bss down error %d\n", err
));
12925 /* fall through is intentional */
12926 err
= wldev_ioctl_set(dev
, WLC_SET_INFRA
, &infra
, sizeof(s32
));
12928 WL_ERR(("SET INFRA error %d\n", err
));
12930 wl_cfg80211_clear_per_bss_ies(cfg
, dev
->ieee80211_ptr
);
12932 if (wdev
->iftype
== NL80211_IFTYPE_AP
) {
12933 #ifdef WL_EXT_IAPSTA
12934 if (!wl_ext_iapsta_iftype_enabled(dev
, WL_IF_TYPE_AP
)) {
12935 #endif /* WL_EXT_IAPSTA */
12936 /* clear the AP mode */
12937 dhd
->op_mode
&= ~DHD_FLAG_HOSTAP_MODE
;
12938 #ifdef WL_EXT_IAPSTA
12940 #endif /* WL_EXT_IAPSTA */
12945 #endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
12947 #ifdef WL_SUPPORT_ACS
12949 * Currently the dump_obss IOVAR is returning string as output so we need to
12950 * parse the output buffer in an unoptimized way. Going forward if we get the
12951 * IOVAR output in binary format this method can be optimized
12953 static int wl_parse_dump_obss(char *buf
, struct wl_dump_survey
*survey
)
12957 char delim
[] = " \n";
12959 token
= strsep(&buf
, delim
);
12960 while (token
!= NULL
) {
12961 if (!strcmp(token
, "OBSS")) {
12962 for (i
= 0; i
< OBSS_TOKEN_IDX
; i
++)
12963 token
= strsep(&buf
, delim
);
12964 survey
->obss
= simple_strtoul(token
, NULL
, 10);
12967 if (!strcmp(token
, "IBSS")) {
12968 for (i
= 0; i
< IBSS_TOKEN_IDX
; i
++)
12969 token
= strsep(&buf
, delim
);
12970 survey
->ibss
= simple_strtoul(token
, NULL
, 10);
12973 if (!strcmp(token
, "TXDur")) {
12974 for (i
= 0; i
< TX_TOKEN_IDX
; i
++)
12975 token
= strsep(&buf
, delim
);
12976 survey
->tx
= simple_strtoul(token
, NULL
, 10);
12979 if (!strcmp(token
, "Category")) {
12980 for (i
= 0; i
< CTG_TOKEN_IDX
; i
++)
12981 token
= strsep(&buf
, delim
);
12982 survey
->no_ctg
= simple_strtoul(token
, NULL
, 10);
12985 if (!strcmp(token
, "Packet")) {
12986 for (i
= 0; i
< PKT_TOKEN_IDX
; i
++)
12987 token
= strsep(&buf
, delim
);
12988 survey
->no_pckt
= simple_strtoul(token
, NULL
, 10);
12991 if (!strcmp(token
, "Opp(time):")) {
12992 for (i
= 0; i
< IDLE_TOKEN_IDX
; i
++)
12993 token
= strsep(&buf
, delim
);
12994 survey
->idle
= simple_strtoul(token
, NULL
, 10);
12997 token
= strsep(&buf
, delim
);
13003 static int wl_dump_obss(struct net_device
*ndev
, cca_msrmnt_query req
,
13004 struct wl_dump_survey
*survey
)
13006 cca_stats_n_flags
*results
;
13009 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
13011 buf
= (char *)MALLOCZ(cfg
->osh
, sizeof(char) * WLC_IOCTL_MAXLEN
);
13012 if (unlikely(!buf
)) {
13013 WL_ERR(("%s: buf alloc failed\n", __func__
));
13017 retry
= IOCTL_RETRY_COUNT
;
13019 err
= wldev_iovar_getbuf(ndev
, "dump_obss", &req
, sizeof(req
),
13020 buf
, WLC_IOCTL_MAXLEN
, NULL
);
13024 WL_DBG(("attempt = %d, err = %d, \n",
13025 (IOCTL_RETRY_COUNT
- retry
), err
));
13029 WL_ERR(("failure, dump_obss IOVAR failed\n"));
13034 results
= (cca_stats_n_flags
*)(buf
);
13035 wl_parse_dump_obss(results
->buf
, survey
);
13036 MFREE(cfg
->osh
, buf
, sizeof(char) * WLC_IOCTL_MAXLEN
);
13040 MFREE(cfg
->osh
, buf
, sizeof(char) * WLC_IOCTL_MAXLEN
);
13044 static int wl_cfg80211_dump_survey(struct wiphy
*wiphy
, struct net_device
*ndev
,
13045 int idx
, struct survey_info
*info
)
13047 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
13048 struct wl_dump_survey
*survey
;
13049 struct ieee80211_supported_band
*band
;
13050 struct ieee80211_channel
*chan
;
13051 cca_msrmnt_query req
;
13052 int val
, err
, noise
, retry
;
13054 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
13055 if (!(dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
13058 band
= wiphy
->bands
[IEEE80211_BAND_2GHZ
];
13059 if (band
&& idx
>= band
->n_channels
) {
13060 idx
-= band
->n_channels
;
13064 if (!band
|| idx
>= band
->n_channels
) {
13065 /* Move to 5G band */
13066 band
= wiphy
->bands
[IEEE80211_BAND_5GHZ
];
13067 if (idx
>= band
->n_channels
) {
13072 chan
= &band
->channels
[idx
];
13073 /* Setting current channel to the requested channel */
13074 if ((err
= wl_cfg80211_set_channel(wiphy
, ndev
, chan
,
13075 NL80211_CHAN_HT20
) < 0)) {
13079 * Mostly set channel should not fail. because we are
13080 * traversing through Valid channel list. In case it fails,
13081 * right now we are passing the stats for previous channel.
13083 WL_ERR(("Set channel failed \n"));
13087 /* Set interface up, explicitly. */
13089 err
= wldev_ioctl_set(ndev
, WLC_UP
, (void *)&val
, sizeof(val
));
13091 WL_ERR(("set interface up failed, error = %d\n", err
));
13095 /* Get noise value */
13096 retry
= IOCTL_RETRY_COUNT
;
13099 err
= wldev_ioctl_get(ndev
, WLC_GET_PHY_NOISE
, &noise
,
13104 WL_DBG(("attempt = %d, err = %d, \n",
13105 (IOCTL_RETRY_COUNT
- retry
), err
));
13109 WL_ERR(("Get Phy Noise failed, error = %d\n", err
));
13110 noise
= CHAN_NOISE_DUMMY
;
13113 survey
= (struct wl_dump_survey
*)MALLOCZ(cfg
->osh
,
13114 sizeof(struct wl_dump_survey
));
13115 if (unlikely(!survey
)) {
13116 WL_ERR(("%s: alloc failed\n", __func__
));
13120 /* Start Measurement for obss stats on current channel */
13121 req
.msrmnt_query
= 0;
13122 req
.time_req
= ACS_MSRMNT_DELAY
;
13123 if ((err
= wl_dump_obss(ndev
, req
, survey
)) < 0) {
13128 * Wait for the meaurement to complete, adding a buffer value of 10 to take
13129 * into consideration any delay in IOVAR completion
13131 msleep(ACS_MSRMNT_DELAY
+ 10);
13133 /* Issue IOVAR to collect measurement results */
13134 req
.msrmnt_query
= 1;
13135 if ((err
= wl_dump_obss(ndev
, req
, survey
)) < 0) {
13139 info
->channel
= chan
;
13140 info
->noise
= noise
;
13141 info
->channel_time
= ACS_MSRMNT_DELAY
;
13142 info
->channel_time_busy
= ACS_MSRMNT_DELAY
- survey
->idle
;
13143 info
->channel_time_rx
= survey
->obss
+ survey
->ibss
+ survey
->no_ctg
+
13145 info
->channel_time_tx
= survey
->tx
;
13146 info
->filled
= SURVEY_INFO_NOISE_DBM
|SURVEY_INFO_CHANNEL_TIME
|
13147 SURVEY_INFO_CHANNEL_TIME_BUSY
| SURVEY_INFO_CHANNEL_TIME_RX
|
13148 SURVEY_INFO_CHANNEL_TIME_TX
;
13149 MFREE(cfg
->osh
, survey
, sizeof(struct wl_dump_survey
));
13153 MFREE(cfg
->osh
, survey
, sizeof(struct wl_dump_survey
));
13156 #endif /* WL_SUPPORT_ACS */
13158 static struct cfg80211_ops wl_cfg80211_ops
= {
13159 .add_virtual_intf
= wl_cfg80211_add_virtual_iface
,
13160 .del_virtual_intf
= wl_cfg80211_del_virtual_iface
,
13161 .change_virtual_intf
= wl_cfg80211_change_virtual_iface
,
13162 #if defined(WL_CFG80211_P2P_DEV_IF)
13163 .start_p2p_device
= wl_cfgp2p_start_p2p_device
,
13164 .stop_p2p_device
= wl_cfgp2p_stop_p2p_device
,
13165 #endif /* WL_CFG80211_P2P_DEV_IF */
13166 .scan
= wl_cfg80211_scan
,
13167 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
13168 .abort_scan
= wl_cfg80211_abort_scan
,
13169 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
13170 .set_wiphy_params
= wl_cfg80211_set_wiphy_params
,
13171 .join_ibss
= wl_cfg80211_join_ibss
,
13172 .leave_ibss
= wl_cfg80211_leave_ibss
,
13173 .get_station
= wl_cfg80211_get_station
,
13174 .dump_station
= wl_cfg80211_dump_station
,
13175 .set_tx_power
= wl_cfg80211_set_tx_power
,
13176 .get_tx_power
= wl_cfg80211_get_tx_power
,
13177 .add_key
= wl_cfg80211_add_key
,
13178 .del_key
= wl_cfg80211_del_key
,
13179 .get_key
= wl_cfg80211_get_key
,
13180 .set_default_key
= wl_cfg80211_config_default_key
,
13181 .set_default_mgmt_key
= wl_cfg80211_config_default_mgmt_key
,
13182 .set_power_mgmt
= wl_cfg80211_set_power_mgmt
,
13183 .connect
= wl_cfg80211_connect
,
13184 .disconnect
= wl_cfg80211_disconnect
,
13185 .set_pmksa
= wl_cfg80211_set_pmksa
,
13186 .del_pmksa
= wl_cfg80211_del_pmksa
,
13187 .flush_pmksa
= wl_cfg80211_flush_pmksa
,
13188 .remain_on_channel
= wl_cfgscan_remain_on_channel
,
13189 .cancel_remain_on_channel
= wl_cfgscan_cancel_remain_on_channel
,
13190 .mgmt_tx
= wl_cfg80211_mgmt_tx
,
13191 .mgmt_frame_register
= wl_cfg80211_mgmt_frame_register
,
13192 .change_bss
= wl_cfg80211_change_bss
,
13193 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS)
13194 .set_channel
= wl_cfg80211_set_channel
,
13195 #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
13196 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS)
13197 .set_beacon
= wl_cfg80211_add_set_beacon
,
13198 .add_beacon
= wl_cfg80211_add_set_beacon
,
13199 .del_beacon
= wl_cfg80211_del_beacon
,
13201 .change_beacon
= wl_cfg80211_change_beacon
,
13202 .start_ap
= wl_cfg80211_start_ap
,
13203 .stop_ap
= wl_cfg80211_stop_ap
,
13204 #endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
13205 #ifdef WL_SCHED_SCAN
13206 .sched_scan_start
= wl_cfg80211_sched_scan_start
,
13207 .sched_scan_stop
= wl_cfg80211_sched_scan_stop
,
13208 #endif /* WL_SCHED_SCAN */
13209 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
13211 .del_station
= wl_cfg80211_del_station
,
13212 .change_station
= wl_cfg80211_change_station
,
13213 .mgmt_tx_cancel_wait
= wl_cfg80211_mgmt_tx_cancel_wait
,
13214 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
13215 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
13216 .tdls_mgmt
= wl_cfg80211_tdls_mgmt
,
13217 .tdls_oper
= wl_cfg80211_tdls_oper
,
13218 #endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
13219 #ifdef WL_SUPPORT_ACS
13220 .dump_survey
= wl_cfg80211_dump_survey
,
13221 #endif /* WL_SUPPORT_ACS */
13222 #ifdef WL_CFG80211_ACL
13223 .set_mac_acl
= wl_cfg80211_set_mac_acl
,
13224 #endif /* WL_CFG80211_ACL */
13225 #ifdef GTK_OFFLOAD_SUPPORT
13226 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
13227 .set_rekey_data
= wl_cfg80211_set_rekey_data
,
13228 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
13229 #endif /* GTK_OFFLOAD_SUPPORT */
13230 #if defined(WL_FILS)
13231 /* This should be enabled from kernel version which supports this */
13232 .update_connect_params
= wl_cfg80211_update_connect_params
,
13233 #endif /* WL_FILS */
13234 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
13235 .set_pmk
= wl_cfg80211_set_pmk
,
13236 .del_pmk
= wl_cfg80211_del_pmk
,
13237 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
13238 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
13239 .channel_switch
= wl_cfg80211_channel_switch
,
13240 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
13241 #ifdef WL_CLIENT_SAE
13242 .external_auth
= wl_cfg80211_external_auth
,
13243 #endif /* WL_CLIENT_SAE */
13246 s32
wl_mode_to_nl80211_iftype(s32 mode
)
13252 return NL80211_IFTYPE_STATION
;
13254 return NL80211_IFTYPE_ADHOC
;
13256 return NL80211_IFTYPE_AP
;
13257 #ifdef WLMESH_CFG80211
13259 return NL80211_IFTYPE_MESH_POINT
;
13260 #endif /* WLMESH_CFG80211 */
13262 return NL80211_IFTYPE_UNSPECIFIED
;
13269 wl_is_ccode_change_required(struct net_device
*net
,
13270 char *country_code
, int revinfo
)
13273 wl_country_t cspec
= {{0}, 0, {0}};
13274 wl_country_t cur_cspec
= {{0}, 0, {0}};
13276 ret
= wldev_iovar_getbuf(net
, "country", NULL
, 0, &cur_cspec
,
13277 sizeof(cur_cspec
), NULL
);
13279 WL_ERR(("get country code failed = %d\n", ret
));
13282 /* If translation table is available, update cspec */
13283 cspec
.rev
= revinfo
;
13284 strlcpy(cspec
.country_abbrev
, country_code
, WLC_CNTRY_BUF_SZ
);
13285 strlcpy(cspec
.ccode
, country_code
, WLC_CNTRY_BUF_SZ
);
13286 dhd_get_customized_country_code(net
, country_code
, &cspec
);
13287 if ((cur_cspec
.rev
== cspec
.rev
) &&
13288 (strncmp(cur_cspec
.ccode
, cspec
.ccode
, WLC_CNTRY_BUF_SZ
) == 0) &&
13289 (strncmp(cur_cspec
.country_abbrev
, cspec
.country_abbrev
, WLC_CNTRY_BUF_SZ
) == 0)) {
13290 WL_INFORM_MEM(("country code = %s/%d is already configured\n",
13291 country_code
, revinfo
));
13298 wl_cfg80211_set_country_code(struct net_device
*net
, char *country_code
,
13299 bool notify
, bool user_enforced
, int revinfo
)
13302 struct wireless_dev
*wdev
= ndev_to_wdev(net
);
13303 struct wiphy
*wiphy
= wdev
->wiphy
;
13304 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
13305 BCM_REFERENCE(cfg
);
13307 if (wl_is_ccode_change_required(net
, country_code
, revinfo
) == false) {
13311 if (wl_cfgnan_is_enabled(cfg
)) {
13312 mutex_lock(&cfg
->if_sync
);
13313 ret
= wl_cfgnan_check_nan_disable_pending(cfg
, true, true);
13314 mutex_unlock(&cfg
->if_sync
);
13315 if (ret
!= BCME_OK
) {
13316 WL_ERR(("failed to disable nan, error[%d]\n", ret
));
13320 #endif /* WL_NAN */
13321 ret
= wldev_set_country(net
, country_code
,
13322 notify
, user_enforced
, revinfo
);
13324 WL_ERR(("set country Failed :%d\n", ret
));
13328 /* send up the hint so that upper layer apps
13329 * can refresh the channel
13332 if (!IS_REGDOM_SELF_MANAGED(wiphy
)) {
13333 regulatory_hint(wiphy
, country_code
);
13340 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
13341 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
13342 #define WL_CFG80211_REG_NOTIFIER() static int wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
13344 #define WL_CFG80211_REG_NOTIFIER() static void wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
13345 #endif /* kernel version < 3.9.0 */
13348 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
13349 WL_CFG80211_REG_NOTIFIER()
13351 struct bcm_cfg80211
*cfg
= (struct bcm_cfg80211
*)wiphy_priv(wiphy
);
13355 if (!request
|| !cfg
) {
13356 WL_ERR(("Invalid arg\n"));
13357 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
13361 #endif /* kernel version < 3.10.11 */
13364 WL_DBG(("ccode: %c%c Initiator: %d\n",
13365 request
->alpha2
[0], request
->alpha2
[1], request
->initiator
));
13367 /* We support only REGDOM_SET_BY_USER as of now */
13368 if ((request
->initiator
!= NL80211_REGDOM_SET_BY_USER
) &&
13369 (request
->initiator
!= NL80211_REGDOM_SET_BY_COUNTRY_IE
)) {
13370 WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
13371 request
->initiator
));
13372 /* in case of no supported country by regdb
13373 lets driver setup platform default Locale
13377 WL_ERR(("Set country code %c%c from %s\n",
13378 request
->alpha2
[0], request
->alpha2
[1],
13379 ((request
->initiator
== NL80211_REGDOM_SET_BY_COUNTRY_IE
) ? " 11d AP" : "User")));
13381 if ((ret
= wldev_set_country(bcmcfg_to_prmry_ndev(cfg
), request
->alpha2
,
13382 false, (request
->initiator
== NL80211_REGDOM_SET_BY_USER
? true : false),
13384 WL_ERR(("set country Failed :%d\n", ret
));
13387 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
13391 #endif /* kernel version < 3.10.11 */
13393 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
13396 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
13397 static const struct wiphy_wowlan_support brcm_wowlan_support
= {
13398 .flags
= WIPHY_WOWLAN_ANY
,
13399 .n_patterns
= WL_WOWLAN_MAX_PATTERNS
,
13400 .pattern_min_len
= WL_WOWLAN_MIN_PATTERN_LEN
,
13401 .pattern_max_len
= WL_WOWLAN_MAX_PATTERN_LEN
,
13402 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
13403 .max_pkt_offset
= WL_WOWLAN_MAX_PATTERN_LEN
,
13404 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
13406 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
13407 #endif /* CONFIG_PM */
13409 int wl_features_set(u8
*array
, uint8 len
, u32 ftidx
)
13413 if ((ftidx
/ 8u) >= len
)
13414 return BCME_BADARG
;
13416 ft_byte
= &array
[ftidx
/ 8u];
13417 *ft_byte
|= BIT(ftidx
% 8u);
13422 void wl_config_custom_regulatory(struct wiphy
*wiphy
)
13425 #if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
13426 /* Use self managed regulatory domain */
13427 wiphy
->regulatory_flags
|= REGULATORY_WIPHY_SELF_MANAGED
|
13428 REGULATORY_IGNORE_STALE_KICKOFF
;
13429 wiphy
->regd
= &brcm_regdom
;
13430 WL_DBG(("Self managed regdom\n"));
13432 #else /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
13434 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
13435 wiphy
->regulatory_flags
|=
13436 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13437 REGULATORY_IGNORE_STALE_KICKOFF
|
13438 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
13439 REGULATORY_CUSTOM_REG
;
13440 #else /* KERNEL VER >= 3.14 */
13441 wiphy
->flags
|= WIPHY_FLAG_CUSTOM_REGULATORY
;
13442 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
13443 wiphy_apply_custom_regulatory(wiphy
, &brcm_regdom
);
13444 WL_DBG(("apply custom regulatory\n"));
13445 #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
13448 static s32
wl_setup_wiphy(struct wireless_dev
*wdev
, struct device
*sdiofunc_dev
, dhd_pub_t
*context
)
13452 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13453 struct cfg80211_wowlan
*brcm_wowlan_config
= NULL
;
13454 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13455 #endif /* CONFIG_PM */
13457 //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
13458 dhd_pub_t
*dhd
= (dhd_pub_t
*)context
;
13459 BCM_REFERENCE(dhd
);
13462 WL_ERR(("DHD is NULL!!"));
13469 wiphy_new(&wl_cfg80211_ops
, sizeof(struct bcm_cfg80211
));
13470 if (unlikely(!wdev
->wiphy
)) {
13471 WL_ERR(("Couldn not allocate wiphy device\n"));
13475 set_wiphy_dev(wdev
->wiphy
, sdiofunc_dev
);
13476 wdev
->wiphy
->max_scan_ie_len
= WL_SCAN_IE_LEN_MAX
;
13477 /* Report how many SSIDs Driver can support per Scan request */
13478 wdev
->wiphy
->max_scan_ssids
= WL_SCAN_PARAMS_SSID_MAX
;
13479 wdev
->wiphy
->max_num_pmkids
= WL_NUM_PMKIDS_MAX
;
13480 #ifdef WL_SCHED_SCAN
13481 wdev
->wiphy
->max_sched_scan_ssids
= MAX_PFN_LIST_COUNT
;
13482 wdev
->wiphy
->max_match_sets
= MAX_PFN_LIST_COUNT
;
13483 wdev
->wiphy
->max_sched_scan_ie_len
= WL_SCAN_IE_LEN_MAX
;
13484 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
13485 wdev
->wiphy
->flags
|= WIPHY_FLAG_SUPPORTS_SCHED_SCAN
;
13487 wdev
->wiphy
->max_sched_scan_reqs
= 1;
13488 #endif /* LINUX_VER < 4.12 */
13489 #endif /* WL_SCHED_SCAN */
13490 #ifdef WLMESH_CFG80211
13491 wdev
->wiphy
->flags
|= WIPHY_FLAG_MESH_AUTH
;
13492 #endif /* WLMESH_CFG80211 */
13493 wdev
->wiphy
->interface_modes
=
13494 BIT(NL80211_IFTYPE_STATION
)
13495 | BIT(NL80211_IFTYPE_ADHOC
)
13496 #if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
13498 * This monitor mode support creates an issue in registering
13499 * Action frame for P2P-GO, this was leading an error in receiving
13500 * action frames to GO interface.Keeping the code here because
13501 * monitor mode code has kept as it is in other modules,
13502 * though we are not supporting this mode.
13504 | BIT(NL80211_IFTYPE_MONITOR
)
13505 #endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
13506 #if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
13507 | BIT(NL80211_IFTYPE_P2P_CLIENT
)
13508 | BIT(NL80211_IFTYPE_P2P_GO
)
13509 #endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
13510 #if defined(WL_CFG80211_P2P_DEV_IF)
13511 | BIT(NL80211_IFTYPE_P2P_DEVICE
)
13512 #endif /* WL_CFG80211_P2P_DEV_IF */
13513 #ifdef WLMESH_CFG80211
13514 | BIT(NL80211_IFTYPE_MESH_POINT
)
13515 #endif /* WLMESH_CFG80211 */
13516 | BIT(NL80211_IFTYPE_AP
);
13518 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
13519 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
13520 WL_DBG(("Setting interface combinations for common mode\n"));
13521 wdev
->wiphy
->iface_combinations
= common_iface_combinations
;
13522 wdev
->wiphy
->n_iface_combinations
=
13523 ARRAY_SIZE(common_iface_combinations
);
13524 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
13526 wdev
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = &__wl_band_2ghz
;
13528 wdev
->wiphy
->signal_type
= CFG80211_SIGNAL_TYPE_MBM
;
13529 wdev
->wiphy
->cipher_suites
= __wl_cipher_suites
;
13530 wdev
->wiphy
->n_cipher_suites
= ARRAY_SIZE(__wl_cipher_suites
);
13531 wdev
->wiphy
->max_remain_on_channel_duration
= 5000;
13532 wdev
->wiphy
->mgmt_stypes
= wl_cfg80211_default_mgmt_stypes
;
13533 #ifndef WL_POWERSAVE_DISABLED
13534 wdev
->wiphy
->flags
|= WIPHY_FLAG_PS_ON_BY_DEFAULT
;
13536 wdev
->wiphy
->flags
&= ~WIPHY_FLAG_PS_ON_BY_DEFAULT
;
13537 #endif /* !WL_POWERSAVE_DISABLED */
13538 wdev
->wiphy
->flags
|= WIPHY_FLAG_NETNS_OK
|
13539 WIPHY_FLAG_4ADDR_AP
|
13540 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS)
13541 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS
|
13543 WIPHY_FLAG_4ADDR_STATION
;
13544 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
13546 * If FW ROAM flag is advertised, upper layer doesn't provide the
13547 * bssid & freq in the connect command. However, kernel ver >= 3.15,
13548 * provides bssid_hint & freq_hint which can be used by the firmware.
13549 * fw_ap_select variable determines whether FW selects the AP or the
13550 * user space selects the target AP within the given ESS.
13552 wdev
->wiphy
->flags
|= WIPHY_FLAG_SUPPORTS_FW_ROAM
;
13553 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13554 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
13555 /* this flag should be added to support wpa_supplicant 1.0+ */
13556 wdev
->wiphy
->flags
|= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
|
13557 WIPHY_FLAG_OFFCHAN_TX
;
13559 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
13561 /* From 3.4 kernel ownards AP_SME flag can be advertised
13562 * to remove the patch from supplicant
13564 wdev
->wiphy
->flags
|= WIPHY_FLAG_HAVE_AP_SME
;
13566 #ifdef WL_CFG80211_ACL
13567 /* Configure ACL capabilities. */
13568 wdev
->wiphy
->max_acl_mac_addrs
= MAX_NUM_MAC_FILT
;
13571 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
13572 /* Supplicant distinguish between the SoftAP mode and other
13573 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
13574 * response frame from Supplicant MR1 and Kernel 3.4.0 or
13575 * later version. To add Vendor specific IE into the
13576 * probe response frame in case of SoftAP mode,
13577 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
13579 if (dhd_get_fw_mode(dhd
->info
) == DHD_FLAG_HOSTAP_MODE
) {
13580 wdev
->wiphy
->flags
|= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD
;
13581 wdev
->wiphy
->probe_resp_offload
= 0;
13584 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
13586 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
13587 wdev
->wiphy
->flags
|= WIPHY_FLAG_SUPPORTS_TDLS
;
13590 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13592 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
13593 * disconnection of connected network before suspend. So a dummy wowlan
13594 * filter is configured for kernels linux-3.8 and above.
13597 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13598 wdev
->wiphy
->wowlan
= &brcm_wowlan_support
;
13599 /* If this is not provided cfg stack will get disconnect
13601 * Note: wiphy->wowlan_config is freed by cfg80211 layer.
13602 * so use malloc instead of MALLOC(osh) to avoid false alarm.
13604 brcm_wowlan_config
= kmalloc(sizeof(struct cfg80211_wowlan
), GFP_KERNEL
);
13605 if (brcm_wowlan_config
) {
13606 brcm_wowlan_config
->disconnect
= true;
13607 brcm_wowlan_config
->gtk_rekey_failure
= true;
13608 brcm_wowlan_config
->eap_identity_req
= true;
13609 brcm_wowlan_config
->four_way_handshake
= true;
13610 brcm_wowlan_config
->patterns
= NULL
;
13611 brcm_wowlan_config
->n_patterns
= 0;
13612 brcm_wowlan_config
->tcp
= NULL
;
13613 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13614 brcm_wowlan_config
->nd_config
= NULL
;
13617 WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
13618 " So wiphy->wowlan_config is set to NULL\n"));
13620 wdev
->wiphy
->wowlan_config
= brcm_wowlan_config
;
13622 wdev
->wiphy
->wowlan
.flags
= WIPHY_WOWLAN_ANY
;
13623 wdev
->wiphy
->wowlan
.n_patterns
= WL_WOWLAN_MAX_PATTERNS
;
13624 wdev
->wiphy
->wowlan
.pattern_min_len
= WL_WOWLAN_MIN_PATTERN_LEN
;
13625 wdev
->wiphy
->wowlan
.pattern_max_len
= WL_WOWLAN_MAX_PATTERN_LEN
;
13626 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
13627 wdev
->wiphy
->wowlan
.max_pkt_offset
= WL_WOWLAN_MAX_PATTERN_LEN
;
13628 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
13629 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13630 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13632 WL_DBG(("Registering custom regulatory)\n"));
13633 wl_config_custom_regulatory(wdev
->wiphy
);
13635 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13636 WL_INFORM_MEM(("Registering Vendor80211\n"));
13637 err
= wl_cfgvendor_attach(wdev
->wiphy
, dhd
);
13638 if (unlikely(err
< 0)) {
13639 WL_ERR(("Couldn not attach vendor commands (%d)\n", err
));
13641 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
13643 wiphy_ext_feature_set(wdev
->wiphy
, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD
);
13644 #endif /* WL_FILS */
13646 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
13647 wdev
->wiphy
->flags
|= WIPHY_FLAG_HAS_CHANNEL_SWITCH
;
13648 wdev
->wiphy
->max_num_csa_counters
= WL_MAX_NUM_CSA_COUNTERS
;
13649 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */
13651 /* Now we can register wiphy with cfg80211 module */
13652 err
= wiphy_register(wdev
->wiphy
);
13653 if (unlikely(err
< 0)) {
13654 WL_ERR(("Couldn not register wiphy device (%d)\n", err
));
13655 wiphy_free(wdev
->wiphy
);
13658 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
13659 KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
13660 /* Workaround for a cfg80211 bug */
13661 wdev
->wiphy
->flags
&= ~WIPHY_FLAG_ENFORCE_COMBINATIONS
;
13664 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \
13665 defined(SUPPORT_RANDOM_MAC_SCAN)
13666 wdev
->wiphy
->features
|= (NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR
|
13667 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR
);
13668 wdev
->wiphy
->max_sched_scan_plans
= 1; /* multiple plans not supported */
13669 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) */
13671 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
13672 wdev
->wiphy
->features
|= NL80211_FEATURE_SAE
;
13673 #endif /* WL_SAE || WL_CLIENT_SAE */
13674 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE)
13675 if (FW_SUPPORTED(dhd
, idsup
)) {
13676 wiphy_ext_feature_set(wdev
->wiphy
, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK
);
13677 wiphy_ext_feature_set(wdev
->wiphy
, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X
);
13679 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) && defined(BCMSUP_4WAY_HANDSHAKE) */
13680 #ifdef WL_SCAN_TYPE
13681 /* These scan types will be mapped to default scan on non-supported chipset */
13682 /* Advertise scan type capability. */
13683 wiphy_ext_feature_set(wdev
->wiphy
, NL80211_EXT_FEATURE_LOW_SPAN_SCAN
);
13684 wiphy_ext_feature_set(wdev
->wiphy
, NL80211_EXT_FEATURE_LOW_POWER_SCAN
);
13685 wiphy_ext_feature_set(wdev
->wiphy
, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN
);
13686 wdev
->wiphy
->features
|= NL80211_FEATURE_LOW_PRIORITY_SCAN
;
13687 #endif /* WL_SCAN_TYPE */
13692 static void wl_free_wdev(struct bcm_cfg80211
*cfg
)
13694 struct wireless_dev
*wdev
= cfg
->wdev
;
13695 struct wiphy
*wiphy
= NULL
;
13697 WL_ERR(("wdev is invalid\n"));
13701 wiphy
= wdev
->wiphy
;
13703 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13704 wl_cfgvendor_detach(wdev
->wiphy
);
13705 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
13706 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13707 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13708 /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
13709 WL_DBG(("clear wowlan\n"));
13710 wdev
->wiphy
->wowlan
= NULL
;
13711 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13712 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13713 #if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
13714 /* Making regd ptr NULL, to avoid reference/freeing by regulatory unregister */
13715 wiphy
->regd
= NULL
;
13716 #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
13717 wiphy_unregister(wdev
->wiphy
);
13718 wdev
->wiphy
->dev
.parent
= NULL
;
13719 wdev
->wiphy
= NULL
;
13722 wl_delete_all_netinfo(cfg
);
13725 wdev
->netdev
->ieee80211_ptr
= NULL
;
13726 wdev
->netdev
= NULL
;
13727 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
13732 /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
13733 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
13737 static bool wl_is_linkup(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
, struct net_device
*ndev
)
13739 u32 event
= ntoh32(e
->event_type
);
13740 u32 status
= ntoh32(e
->status
);
13741 u16 flags
= ntoh16(e
->flags
);
13742 #if defined(CUSTOM_SET_OCLOFF) || defined(CUSTOM_SET_ANTNPM)
13744 dhd
= (dhd_pub_t
*)(cfg
->pub
);
13745 #endif /* CUSTOM_SET_OCLOFF || CUSTOM_SET_ANTNPM */
13747 WL_DBG(("event %d, status %d flags %x\n", event
, status
, flags
));
13748 if (event
== WLC_E_SET_SSID
) {
13749 if (status
== WLC_E_STATUS_SUCCESS
) {
13750 #ifdef CUSTOM_SET_OCLOFF
13751 if (dhd
->ocl_off
) {
13753 int ocl_enable
= 0;
13754 err
= wldev_iovar_setint(ndev
, "ocl_enable", ocl_enable
);
13756 WL_ERR(("[WIFI_SEC] wl_is_linkup: Set ocl_enable %d"
13760 WL_ERR(("[WIFI_SEC] wl_is_linkup: Set ocl_enable %d"
13765 #endif /* CUSTOM_SET_OCLOFF */
13766 #ifdef CUSTOM_SET_ANTNPM
13767 if (dhd
->mimo_ant_set
) {
13770 WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhd
->mimo_ant_set
));
13771 err
= wldev_iovar_setint(ndev
, "txchain", dhd
->mimo_ant_set
);
13773 WL_ERR(("[WIFI_SEC] Fail set txchain\n"));
13775 err
= wldev_iovar_setint(ndev
, "rxchain", dhd
->mimo_ant_set
);
13777 WL_ERR(("[WIFI_SEC] Fail set rxchain\n"));
13780 #endif /* CUSTOM_SET_ANTNPM */
13781 if (!wl_is_ibssmode(cfg
, ndev
))
13784 } else if (event
== WLC_E_LINK
) {
13785 if (flags
& WLC_EVENT_MSG_LINK
)
13789 WL_DBG(("wl_is_linkup false\n"));
13793 static bool wl_is_linkdown(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
)
13795 u32 event
= ntoh32(e
->event_type
);
13796 u16 flags
= ntoh16(e
->flags
);
13798 if (event
== WLC_E_DEAUTH_IND
||
13799 event
== WLC_E_DISASSOC_IND
||
13800 event
== WLC_E_DISASSOC
||
13801 event
== WLC_E_DEAUTH
) {
13802 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event
)));
13804 } else if (event
== WLC_E_LINK
) {
13805 if (!(flags
& WLC_EVENT_MSG_LINK
)) {
13806 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event
)));
13814 static bool wl_is_nonetwork(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
)
13816 u32 event
= ntoh32(e
->event_type
);
13817 u32 status
= ntoh32(e
->status
);
13819 if (event
== WLC_E_LINK
&& status
== WLC_E_STATUS_NO_NETWORKS
)
13821 if (event
== WLC_E_SET_SSID
&& status
!= WLC_E_STATUS_SUCCESS
)
13823 if (event
== WLC_E_ASSOC_RESP_IE
&& status
!= WLC_E_STATUS_SUCCESS
)
13831 wl_cfg80211_event_sae_key(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
13832 wl_sae_key_info_t
*sae_key
)
13834 struct sk_buff
*skb
;
13836 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
13838 struct cfg80211_pmksa pmksa
;
13840 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
13841 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
13842 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
13843 skb
= cfg80211_vendor_event_alloc(wiphy
, ndev_to_wdev(ndev
), BRCM_SAE_VENDOR_EVENT_BUF_LEN
,
13844 BRCM_VENDOR_EVENT_SAE_KEY
, kflags
);
13846 skb
= cfg80211_vendor_event_alloc(wiphy
, BRCM_SAE_VENDOR_EVENT_BUF_LEN
,
13847 BRCM_VENDOR_EVENT_SAE_KEY
, kflags
);
13848 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
13849 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
13851 WL_ERR(("skb alloc failed"));
13856 WL_INFORM_MEM(("Received Sae Key event for "MACDBG
" key length %x %x",
13857 MAC2STRDBG(sae_key
->peer_mac
), sae_key
->pmk_len
, sae_key
->pmkid_len
));
13858 nla_put(skb
, BRCM_SAE_KEY_ATTR_PEER_MAC
, ETHER_ADDR_LEN
, sae_key
->peer_mac
);
13859 nla_put(skb
, BRCM_SAE_KEY_ATTR_PMK
, sae_key
->pmk_len
, sae_key
->pmk
);
13860 nla_put(skb
, BRCM_SAE_KEY_ATTR_PMKID
, sae_key
->pmkid_len
, sae_key
->pmkid
);
13861 cfg80211_vendor_event(skb
, kflags
);
13862 /* wpa_supplicant will manage the PMK and PMKID from here on..
13863 * Delete the PMK cache in firmware, if wlc_ver equals to MIN_PMKID_LIST_V3_FW_MAJOR
13865 * MIN_PMKID_LIST_V3_FW_MAJOR has two IOVAR's(pmklist_info and PMKDB).
13867 if (cfg
->wlc_ver
.wlc_ver_major
== MIN_PMKID_LIST_V3_FW_MAJOR
) {
13868 WL_INFORM_MEM(("Deleting the SAE PMK cache Info from firmware \n"));
13869 memset_s(&pmksa
, sizeof(pmksa
), 0, sizeof(pmksa
));
13870 pmksa
.bssid
= sae_key
->peer_mac
;
13871 pmksa
.pmkid
= sae_key
->pmkid
;
13872 err
= wl_cfg80211_update_pmksa(wiphy
, ndev
, &pmksa
, FALSE
);
13873 if (err
!= BCME_OK
) {
13874 WL_ERR(("Failed to delete the SAE PMK cache Info from firmware %d\n", err
));
13882 wl_bss_handle_sae_auth_v1(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
13883 const wl_event_msg_t
*event
, void *data
)
13886 wl_auth_event_t
*auth_data
;
13887 wl_sae_key_info_t sae_key
;
13888 uint16 tlv_buf_len
;
13889 auth_data
= (wl_auth_event_t
*)data
;
13891 tlv_buf_len
= auth_data
->length
- WL_AUTH_EVENT_FIXED_LEN_V1
;
13893 /* check if PMK info present */
13894 sae_key
.pmk
= bcm_get_data_from_xtlv_buf(auth_data
->xtlvs
, tlv_buf_len
,
13895 WL_AUTH_PMK_TLV_ID
, &(sae_key
.pmk_len
), BCM_XTLV_OPTION_ALIGN32
);
13896 if (!sae_key
.pmk
|| !sae_key
.pmk_len
) {
13897 WL_ERR(("Mandatory PMK info not present"));
13898 err
= BCME_NOTFOUND
;
13901 /* check if PMKID info present */
13902 sae_key
.pmkid
= bcm_get_data_from_xtlv_buf(auth_data
->xtlvs
, tlv_buf_len
,
13903 WL_AUTH_PMKID_TLV_ID
, &(sae_key
.pmkid_len
), BCM_XTLV_OPTION_ALIGN32
);
13904 if (!sae_key
.pmkid
|| !sae_key
.pmkid_len
) {
13905 WL_ERR(("Mandatory PMKID info not present\n"));
13906 err
= BCME_NOTFOUND
;
13909 memcpy_s(sae_key
.peer_mac
, ETHER_ADDR_LEN
, event
->addr
.octet
, ETHER_ADDR_LEN
);
13910 err
= wl_cfg80211_event_sae_key(cfg
, ndev
, &sae_key
);
13912 WL_ERR(("Failed to event sae key info\n"));
13919 wl_bss_handle_sae_auth_v2(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
13920 const wl_event_msg_t
*event
, void *data
)
13923 wl_auth_event_t
*auth_data
;
13924 wl_sae_key_info_t sae_key
;
13925 uint16 tlv_buf_len
;
13926 uint8 ssid
[DOT11_MAX_SSID_LEN
];
13927 const uint8
*tmp_buf
;
13931 pmkid_v3_t
*t_pmkid
= NULL
;
13933 auth_data
= (wl_auth_event_t
*)data
;
13935 tlv_buf_len
= auth_data
->length
- WL_AUTH_EVENT_FIXED_LEN_V2
;
13937 /* check if PMK info present */
13938 sae_key
.pmk
= bcm_get_data_from_xtlv_buf(auth_data
->xtlvs
, tlv_buf_len
,
13939 WL_AUTH_PMK_TLV_ID
, &(sae_key
.pmk_len
), BCM_XTLV_OPTION_ALIGN32
);
13940 if (!sae_key
.pmk
|| !sae_key
.pmk_len
) {
13941 WL_ERR(("Mandatory PMK info not present"));
13942 err
= BCME_NOTFOUND
;
13945 /* check if PMKID info present */
13946 sae_key
.pmkid
= bcm_get_data_from_xtlv_buf(auth_data
->xtlvs
, tlv_buf_len
,
13947 WL_AUTH_PMKID_TLV_ID
, &(sae_key
.pmkid_len
), BCM_XTLV_OPTION_ALIGN32
);
13948 if (!sae_key
.pmkid
|| !sae_key
.pmkid_len
) {
13949 WL_ERR(("Mandatory PMKID info not present\n"));
13950 err
= BCME_NOTFOUND
;
13953 memcpy_s(sae_key
.peer_mac
, ETHER_ADDR_LEN
, event
->addr
.octet
, ETHER_ADDR_LEN
);
13955 tmp_buf
= bcm_get_data_from_xtlv_buf(auth_data
->xtlvs
, tlv_buf_len
,
13956 WL_AUTH_PMKID_TYPE_TLV_ID
, &type_len
, BCM_XTLV_OPTION_ALIGN32
);
13958 memcpy(&type
, tmp_buf
, MIN(type_len
, sizeof(type
)));
13959 if (type
== WL_AUTH_PMKID_TYPE_SSID
) {
13962 pmkid_list_v3_t
*spmk_list
= &cfg
->spmk_info_list
->pmkids
;
13964 tmp_buf
= bcm_get_data_from_xtlv_buf(auth_data
->xtlvs
, tlv_buf_len
,
13965 WL_AUTH_SSID_TLV_ID
, &ssid_len
, BCM_XTLV_OPTION_ALIGN32
);
13966 if (tmp_buf
== NULL
) {
13969 bzero(ssid
, sizeof(ssid
));
13970 (void)memcpy_s(ssid
, sizeof(ssid
), tmp_buf
, MIN(sizeof(ssid
), ssid_len
));
13971 for (idx
= 0; idx
< spmk_list
->count
; idx
++) {
13972 t_pmkid
= &spmk_list
->pmkid
[idx
];
13973 if (ssid_len
== t_pmkid
->ssid_len
&&
13974 !memcmp(ssid
, t_pmkid
->ssid
, MIN(sizeof(ssid
), ssid_len
))) {
13978 if (idx
>= spmk_list
->count
) {
13979 if (spmk_list
->count
== MAXPMKID
) {
13980 /* remove oldest PMK info */
13981 for (idx2
= 0; idx2
< spmk_list
->count
- 1; idx2
++) {
13982 (void)memcpy_s(&spmk_list
->pmkid
[idx2
], sizeof(pmkid_v3_t
),
13983 &spmk_list
->pmkid
[idx2
+ 1], sizeof(pmkid_v3_t
));
13985 t_pmkid
= &spmk_list
->pmkid
[spmk_list
->count
- 1];
13987 t_pmkid
= &spmk_list
->pmkid
[spmk_list
->count
++];
13991 WL_ERR(("SPMK TPMKID is null\n"));
13992 return BCME_NOTFOUND
;
13994 bzero(t_pmkid
, sizeof(pmkid_v3_t
));
13995 memcpy(&t_pmkid
->bssid
, event
->addr
.octet
, 6);
13996 t_pmkid
->ssid_len
= ssid_len
;
13997 err
= memcpy_s(t_pmkid
->ssid
, sizeof(t_pmkid
->ssid
), ssid
, ssid_len
);
13998 if (err
!= BCME_OK
) {
14001 /* COPY but not used */
14002 t_pmkid
->pmkid_len
= sae_key
.pmkid_len
;
14003 memcpy(t_pmkid
->pmkid
, sae_key
.pmkid
, sae_key
.pmkid_len
);
14004 t_pmkid
->pmk_len
= sae_key
.pmk_len
;
14005 memcpy(t_pmkid
->pmk
, sae_key
.pmk
, sae_key
.pmk_len
);
14008 err
= wl_cfg80211_event_sae_key(cfg
, ndev
, &sae_key
);
14010 WL_ERR(("Failed to event sae key info\n"));
14017 wl_bss_handle_sae_auth(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
14018 const wl_event_msg_t
*event
, void *data
)
14021 uint status
= ntoh32(event
->status
);
14022 wl_auth_event_t
*auth_data
;
14024 if (status
== WLC_E_STATUS_SUCCESS
) {
14025 auth_data
= (wl_auth_event_t
*)data
;
14026 if (auth_data
->version
== WL_AUTH_EVENT_DATA_V1
) {
14027 err
= wl_bss_handle_sae_auth_v1(cfg
, ndev
, event
, data
);
14028 } else if (auth_data
->version
== WL_AUTH_EVENT_DATA_V2
) {
14029 err
= wl_bss_handle_sae_auth_v2(cfg
, ndev
, event
, data
);
14031 printf("unknown auth event data version %x\n",
14032 auth_data
->version
);
14033 err
= BCME_VERSION
;
14036 printf("sae auth status failure:%d\n", status
);
14038 printf("SAE AUTH result: %d\n", err
);
14041 #endif /* WL_SAE */
14044 wl_get_auth_assoc_status(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
14045 const wl_event_msg_t
*e
, void *data
)
14047 u32 reason
= ntoh32(e
->reason
);
14048 u32 event
= ntoh32(e
->event_type
);
14050 uint auth_type
= ntoh32(e
->auth_type
);
14051 #endif /* WL_SAE */
14052 struct wl_security
*sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
14053 WL_DBG(("event type : %d, reason : %d\n", event
, reason
));
14055 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
14056 (void)memcpy_s(&cfg
->event_auth_assoc
, sizeof(wl_event_msg_t
),
14057 e
, sizeof(wl_event_msg_t
));
14058 WL_ERR(("event=%d status %d reason %d \n",
14059 ntoh32(cfg
->event_auth_assoc
.event_type
),
14060 ntoh32(cfg
->event_auth_assoc
.status
),
14061 ntoh32(cfg
->event_auth_assoc
.reason
)));
14062 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
14067 case WLC_E_AUTH_IND
:
14068 sec
->auth_assoc_res_status
= reason
;
14070 if ((event
== WLC_E_AUTH
|| event
== WLC_E_AUTH_IND
) &&
14071 auth_type
== DOT11_SAE
) {
14072 wl_bss_handle_sae_auth(cfg
, ndev
, e
, data
);
14074 #endif /* WL_SAE */
14080 WL_ERR(("sec is NULL\n"));
14085 #ifdef WL_CLIENT_SAE
14087 wl_notify_connect_status_ap_auth(struct bcm_cfg80211
*cfg
,
14088 struct net_device
*ndev
, const wl_event_msg_t
*e
, void *data
)
14090 bcm_struct_cfgdev
*cfgdev
= ndev_to_cfgdev(ndev
);
14091 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
14092 u8 bsscfgidx
= e
->bsscfgidx
;
14093 u8
*mgmt_frame
= NULL
;
14098 struct ieee80211_supported_band
*band
;
14099 chanspec_t chanspec
;
14101 struct ether_addr da
;
14102 struct ether_addr bssid
;
14103 u32 event
= ntoh32(e
->event_type
);
14104 u32 reason
= ntoh32(e
->reason
);
14105 u32 len
= ntoh32(e
->datalen
);
14109 WL_ERR(("event %s(%d) has no payload. status %d reason %d\n",
14110 bcmevent_get_name(event
), event
, ntoh32(e
->status
), reason
));
14114 body
= (u8
*)MALLOCZ(cfg
->osh
, len
);
14115 if (body
== NULL
) {
14116 WL_ERR(("Failed to allocate body\n"));
14119 (void)memcpy_s(body
, len
, data
, len
);
14121 err
= wldev_iovar_getbuf_bsscfg(ndev
, "cur_etheraddr",
14122 NULL
, 0, cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, bsscfgidx
, &cfg
->ioctl_buf_sync
);
14123 if (unlikely(err
)) {
14124 WL_ERR(("Could not get cur_etheraddr %d\n", err
));
14127 (void)memcpy_s(da
.octet
, ETHER_ADDR_LEN
, cfg
->ioctl_buf
, ETHER_ADDR_LEN
);
14129 bzero(&bssid
, sizeof(bssid
));
14130 err
= wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
14131 if (unlikely(err
)) {
14132 WL_ERR(("Could not get bssid %d\n", err
));
14136 err
= wldev_iovar_getint(ndev
, "chanspec", &chan
);
14137 if (unlikely(err
)) {
14138 WL_ERR(("Could not get chanspec %d\n", err
));
14141 chanspec
= wl_chspec_driver_to_host(chan
);
14142 channel
= wf_chspec_ctlchan(chanspec
);
14144 if (channel
<= CH_MAX_2G_CHANNEL
)
14145 band
= wiphy
->bands
[IEEE80211_BAND_2GHZ
];
14147 band
= wiphy
->bands
[IEEE80211_BAND_5GHZ
];
14149 WL_ERR(("No valid band\n"));
14153 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
14154 freq
= ieee80211_channel_to_frequency(channel
);
14156 freq
= ieee80211_channel_to_frequency(channel
, band
->band
);
14160 err
= wl_frame_get_mgmt(cfg
, FC_AUTH
, &da
, &e
->addr
, &bssid
,
14161 &mgmt_frame
, &len
, body
);
14163 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14164 cfg80211_rx_mgmt(cfgdev
, freq
, 0, mgmt_frame
, len
, 0);
14165 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14166 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, GFP_ATOMIC
);
14168 cfg80211_rx_mgmt(ndev
, freq
, mgmt_frame
, len
, GFP_ATOMIC
);
14170 MFREE(cfg
->osh
, mgmt_frame
, len
);
14175 MFREE(cfg
->osh
, body
, body_len
);
14180 #endif /* WL_CLIENT_SAE */
14183 /* The mainline kernel >= 3.2.0 has support for indicating new/del station
14184 * to AP/P2P GO via events. If this change is backported to kernel for which
14185 * this driver is being built, then define WL_CFG80211_STA_EVENT. You
14186 * should use this new/del sta event mechanism for BRCM supplicant >= 22.
14189 wl_notify_connect_status_ap(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
14190 const wl_event_msg_t
*e
, void *data
)
14193 u32 event
= ntoh32(e
->event_type
);
14194 u32 reason
= ntoh32(e
->reason
);
14195 u32 len
= ntoh32(e
->datalen
);
14196 u32 status
= ntoh32(e
->status
);
14198 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14199 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14200 bool isfree
= false;
14202 u8 bsscfgidx
= e
->bsscfgidx
;
14207 chanspec_t chanspec
;
14208 struct ieee80211_supported_band
*band
;
14209 struct ether_addr da
;
14210 struct ether_addr bssid
;
14211 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
14212 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
14214 struct station_info sinfo
;
14215 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14217 #ifdef BIGDATA_SOFTAP
14219 #endif /* BIGDATA_SOFTAP */
14221 WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n",
14222 ndev
->name
, event
, ntoh32(e
->status
), reason
));
14224 if (event
== WLC_E_AUTH_IND
) {
14225 wl_get_auth_assoc_status(cfg
, ndev
, e
, data
);
14228 /* if link down, bsscfg is disabled. */
14229 if (event
== WLC_E_LINK
&& reason
== WLC_E_LINK_BSSCFG_DIS
&&
14230 wl_get_p2p_status(cfg
, IF_DELETING
) && (ndev
!= bcmcfg_to_prmry_ndev(cfg
))) {
14231 wl_add_remove_eventmsg(ndev
, WLC_E_PROBREQ_MSG
, false);
14232 WL_MSG(ndev
->name
, "AP mode link down !! \n");
14233 complete(&cfg
->iface_disable
);
14237 if ((event
== WLC_E_LINK
) && (status
== WLC_E_STATUS_SUCCESS
) &&
14238 (reason
== WLC_E_REASON_INITIAL_ASSOC
) &&
14239 (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
)) {
14240 if (!wl_get_drv_status(cfg
, AP_CREATED
, ndev
)) {
14241 /* AP/GO brought up successfull in firmware */
14242 WL_MSG(ndev
->name
, "AP/GO Link up\n");
14243 wl_set_drv_status(cfg
, AP_CREATED
, ndev
);
14245 wake_up_interruptible(&cfg
->netif_change_event
);
14247 #ifdef BIGDATA_SOFTAP
14248 wl_ap_stainfo_init(cfg
);
14249 #endif /* BIGDATA_SOFTAP */
14252 /* check fakeapscan is in progress, if progress then abort */
14253 wl_android_bcnrecv_stop(ndev
, WL_BCNRECV_CONCURRENCY
);
14254 #endif /* WL_BCNRECV */
14255 wl_cfg80211_check_in4way(cfg
, ndev
, 0, WL_EXT_STATUS_AP_ENABLED
, NULL
);
14260 if (event
== WLC_E_DISASSOC_IND
|| event
== WLC_E_DEAUTH_IND
|| event
== WLC_E_DEAUTH
) {
14261 WL_MSG_RLMT(ndev
->name
, &e
->addr
, ETHER_ADDR_LEN
,
14262 "event %s(%d) status %d reason %d\n",
14263 bcmevent_get_name(event
), event
, ntoh32(e
->status
), reason
);
14266 #ifdef BIGDATA_SOFTAP
14267 if (event
== WLC_E_LINK
&& reason
== WLC_E_LINK_BSSCFG_DIS
) {
14268 WL_ERR(("AP link down - skip get sta data\n"));
14270 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
14271 if (dhdp
&& dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
14272 dhd_schedule_gather_ap_stadata(cfg
, ndev
, e
);
14275 #endif /* BIGDATA_SOFTAP */
14277 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14278 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14279 WL_DBG(("Enter \n"));
14280 if (!len
&& (event
== WLC_E_DEAUTH
)) {
14281 len
= 2; /* reason code field */
14285 body
= (u8
*)MALLOCZ(cfg
->osh
, len
);
14286 if (body
== NULL
) {
14287 WL_ERR(("Failed to allocate body\n"));
14291 bzero(&bssid
, ETHER_ADDR_LEN
);
14292 WL_DBG(("Enter event %d ndev %p\n", event
, ndev
));
14293 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_INVALID
) {
14294 MFREE(cfg
->osh
, body
, len
);
14298 memcpy(body
, data
, len
);
14300 wldev_iovar_getbuf_bsscfg(ndev
, "cur_etheraddr",
14301 NULL
, 0, ioctl_buf
, sizeof(ioctl_buf
), bsscfgidx
, NULL
);
14302 memcpy(da
.octet
, ioctl_buf
, ETHER_ADDR_LEN
);
14303 bzero(&bssid
, sizeof(bssid
));
14304 err
= wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
14306 case WLC_E_ASSOC_IND
:
14309 case WLC_E_REASSOC_IND
:
14310 fc
= FC_REASSOC_REQ
;
14312 case WLC_E_DISASSOC_IND
:
14315 case WLC_E_DEAUTH_IND
:
14325 err
= wldev_iovar_getint(ndev
, "chanspec", (s32
*)&chanspec
);
14326 if (unlikely(err
)) {
14327 MFREE(cfg
->osh
, body
, len
);
14328 WL_ERR(("%s: Could not get chanspec %d\n", __FUNCTION__
, err
));
14331 chanspec
= wl_chspec_driver_to_host(chanspec
);
14332 freq
= wl_channel_to_frequency(wf_chspec_ctlchan(chanspec
), CHSPEC_BAND(chanspec
));
14334 err
= wl_frame_get_mgmt(cfg
, fc
, &da
, &e
->addr
, &bssid
,
14335 &mgmt_frame
, &len
, body
);
14340 if ((event
== WLC_E_ASSOC_IND
&& reason
== DOT11_SC_SUCCESS
) ||
14341 (event
== WLC_E_DISASSOC_IND
) ||
14342 ((event
== WLC_E_DEAUTH_IND
) || (event
== WLC_E_DEAUTH
))) {
14343 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14344 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, 0);
14345 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14346 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, 0, GFP_ATOMIC
);
14347 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14348 defined(WL_COMPAT_WIRELESS)
14349 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, GFP_ATOMIC
);
14351 cfg80211_rx_mgmt(ndev
, freq
, mgmt_frame
, len
, GFP_ATOMIC
);
14352 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
14357 MFREE(cfg
->osh
, mgmt_frame
, len
);
14360 MFREE(cfg
->osh
, body
, body_len
);
14362 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14363 memset_s(&sinfo
, sizeof(sinfo
), 0, sizeof(sinfo
));
14364 if (((event
== WLC_E_ASSOC_IND
) || (event
== WLC_E_REASSOC_IND
)) &&
14365 reason
== DOT11_SC_SUCCESS
) {
14366 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
14367 * STATION_INFO_ASSOC_REQ_IES flag
14369 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
14370 sinfo
.filled
= STA_INFO_BIT(INFO_ASSOC_REQ_IES
);
14371 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
14373 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
14376 sinfo
.assoc_req_ies
= data
;
14377 sinfo
.assoc_req_ies_len
= len
;
14378 WL_MSG(ndev
->name
, "new sta event for "MACDBG
"\n",
14379 MAC2STRDBG(e
->addr
.octet
));
14380 wl_cfg80211_check_in4way(cfg
, ndev
, DONT_DELETE_GC_AFTER_WPS
,
14381 WL_EXT_STATUS_STA_CONNECTED
, NULL
);
14382 cfg80211_new_sta(ndev
, e
->addr
.octet
, &sinfo
, GFP_ATOMIC
);
14384 wl_wps_session_update(ndev
, WPS_STATE_LINKUP
, e
->addr
.octet
);
14385 #endif /* WL_WPS_SYNC */
14386 } else if ((event
== WLC_E_DEAUTH_IND
) ||
14387 ((event
== WLC_E_DEAUTH
) && (reason
!= DOT11_RC_RESERVED
)) ||
14388 (event
== WLC_E_DISASSOC_IND
)) {
14390 * WAR: Dongle sends WLC_E_DEAUTH event with DOT11_RC_RESERVED
14391 * to delete flowring in case of PCIE Full dongle.
14392 * By deleting flowring on SoftAP interface we can avoid any issues
14393 * due to stale/bad state of flowring.
14394 * Therefore, we don't need to notify the client dissaociation to Hostapd
14396 * Please refer to the RB:115182 to understand the case more clearly.
14398 WL_MSG_RLMT(ndev
->name
, &e
->addr
, ETHER_ADDR_LEN
,
14399 "del sta event for "MACDBG
"\n", MAC2STRDBG(e
->addr
.octet
));
14400 wl_cfg80211_check_in4way(cfg
, ndev
, DONT_DELETE_GC_AFTER_WPS
,
14401 WL_EXT_STATUS_STA_DISCONNECTED
, NULL
);
14402 cfg80211_del_sta(ndev
, e
->addr
.octet
, GFP_ATOMIC
);
14404 wl_wps_session_update(ndev
, WPS_STATE_LINKDOWN
, e
->addr
.octet
);
14405 #endif /* WL_WPS_SYNC */
14407 #ifdef WL_CLIENT_SAE
14408 else if (event
== WLC_E_AUTH
) {
14409 WL_MSG_RLMT(ndev
->name
, &e
->addr
, ETHER_ADDR_LEN
,
14410 "add sta auth event for "MACDBG
"\n", MAC2STRDBG(e
->addr
.octet
));
14411 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_INVALID
) {
14412 WL_ERR(("invalid mode\n"));
14415 err
= wl_notify_connect_status_ap_auth(cfg
, ndev
, e
, data
);
14417 #endif /* WL_CLIENT_SAE */
14418 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14422 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
14424 BIGDATA_ASSOC_REJECT_NO_ACK
= 1,
14425 BIGDATA_ASSOC_REJECT_FAIL
= 2,
14426 BIGDATA_ASSOC_REJECT_UNSOLICITED
= 3,
14427 BIGDATA_ASSOC_REJECT_TIMEOUT
= 4,
14428 BIGDATA_ASSOC_REJECT_ABORT
= 5,
14429 BIGDATA_ASSOC_REJECT_NO_NETWWORKS
= 6,
14430 BIGDATA_ASSOC_REJECT_MAX
= 50
14433 int wl_get_connect_failed_status(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
)
14435 u32 status
= ntoh32(e
->status
);
14437 cfg
->assoc_reject_status
= 0;
14439 if (status
!= WLC_E_STATUS_SUCCESS
) {
14440 WL_ERR(("auth assoc status event=%d e->status %d e->reason %d \n",
14441 ntoh32(cfg
->event_auth_assoc
.event_type
),
14442 (int)ntoh32(cfg
->event_auth_assoc
.status
),
14443 (int)ntoh32(cfg
->event_auth_assoc
.reason
)));
14445 switch ((int)ntoh32(cfg
->event_auth_assoc
.status
)) {
14446 case WLC_E_STATUS_NO_ACK
:
14447 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_NO_ACK
;
14449 case WLC_E_STATUS_FAIL
:
14450 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_FAIL
;
14452 case WLC_E_STATUS_UNSOLICITED
:
14453 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_UNSOLICITED
;
14455 case WLC_E_STATUS_TIMEOUT
:
14456 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_TIMEOUT
;
14458 case WLC_E_STATUS_ABORT
:
14459 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_ABORT
;
14461 case WLC_E_STATUS_SUCCESS
:
14462 if (status
== WLC_E_STATUS_NO_NETWORKS
) {
14463 cfg
->assoc_reject_status
=
14464 BIGDATA_ASSOC_REJECT_NO_NETWWORKS
;
14468 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_MAX
;
14471 if (cfg
->assoc_reject_status
) {
14472 if (ntoh32(cfg
->event_auth_assoc
.event_type
) == WLC_E_ASSOC
) {
14473 cfg
->assoc_reject_status
+= BIGDATA_ASSOC_REJECT_MAX
;
14478 WL_ERR(("assoc_reject_status %d \n", cfg
->assoc_reject_status
));
14483 s32
wl_cfg80211_get_connect_failed_status(struct net_device
*dev
, char* cmd
, int total_len
)
14485 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
14486 int bytes_written
= 0;
14491 bytes_written
= snprintf(cmd
, total_len
, "assoc_reject.status %d",
14492 cfg
->assoc_reject_status
);
14493 WL_ERR(("cmd: %s \n", cmd
));
14494 return bytes_written
;
14496 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
14498 #ifdef WL_CLIENT_SAE
14500 wl_notify_start_auth(struct bcm_cfg80211
*cfg
,
14501 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
)
14503 struct cfg80211_external_auth_params ext_auth_param
;
14504 struct net_device
*ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
14505 u32 datalen
= be32_to_cpu(e
->datalen
);
14506 wl_ext_auth_evt_t
*evt_data
= (wl_ext_auth_evt_t
*)data
;
14507 wl_assoc_mgr_cmd_t cmd
;
14510 WL_DBG(("Enter\n"));
14512 if (!datalen
|| !data
)
14515 ext_auth_param
.ssid
.ssid_len
= MIN(evt_data
->ssid
.SSID_len
, DOT11_MAX_SSID_LEN
);
14516 if (ext_auth_param
.ssid
.ssid_len
)
14517 memcpy(&ext_auth_param
.ssid
.ssid
, evt_data
->ssid
.SSID
,
14518 ext_auth_param
.ssid
.ssid_len
);
14520 memcpy(&ext_auth_param
.bssid
, &evt_data
->bssid
, ETHER_ADDR_LEN
);
14521 ext_auth_param
.action
= NL80211_EXTERNAL_AUTH_START
;
14522 ext_auth_param
.key_mgmt_suite
= ntoh32(WLAN_AKM_SUITE_SAE_SHA256
);
14524 WL_MSG(ndev
->name
, "BSSID: "MACDBG
"\n", MAC2STRDBG(&evt_data
->bssid
));
14526 err
= cfg80211_external_auth_request(ndev
, &ext_auth_param
, GFP_KERNEL
);
14527 if (unlikely(err
)) {
14528 WL_ERR(("Failed to notify external auth req(%d)\n", err
));
14531 cmd
.version
= WL_ASSOC_MGR_CURRENT_VERSION
;
14532 cmd
.length
= sizeof(cmd
);
14533 cmd
.cmd
= WL_ASSOC_MGR_CMD_PAUSE_ON_EVT
;
14534 cmd
.params
= WL_ASSOC_MGR_PARAMS_PAUSE_EVENT_AUTH_RESP
;
14535 err
= wldev_iovar_setbuf(ndev
, "assoc_mgr_cmd", (void *)&cmd
, sizeof(cmd
),
14536 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
14537 if (unlikely(err
)) {
14538 WL_ERR(("Failed to pause assoc(%d)\n", err
));
14545 wl_notify_connect_status_bss(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
14546 const wl_event_msg_t
*e
, void *data
)
14549 u32 event
= ntoh32(e
->event_type
);
14550 u32 reason
= ntoh32(e
->reason
);
14551 u32 len
= ntoh32(e
->datalen
);
14552 u32 status
= ntoh32(e
->status
);
14554 bool isfree
= false;
14556 u8 bsscfgidx
= e
->bsscfgidx
;
14560 u16 fc
= 0, rssi
= 0;
14561 bcm_struct_cfgdev
*cfgdev
= ndev_to_cfgdev(ndev
);
14563 struct ieee80211_supported_band
*band
;
14564 struct ether_addr da
;
14565 struct ether_addr bssid
;
14566 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
14569 WL_DBG(("event %d status %d reason %d\n", event
, status
, reason
));
14571 if (event
== WLC_E_AUTH
) {
14572 struct wl_security
*sec
;
14573 sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
14575 if (!(sec
->auth_type
== NL80211_AUTHTYPE_SAE
)) {
14576 WL_DBG(("Abort AUTH processing due to NOT SAE\n"));
14579 if (status
!= WLC_E_STATUS_SUCCESS
&& !len
) {
14580 WL_ERR(("SAE AUTH FAIL EVENT\n"));
14581 wl_cfg80211_check_in4way(cfg
, ndev
, NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
|WAIT_DISCONNECTED
,
14582 WL_EXT_STATUS_DISCONNECTED
, NULL
);
14588 if (!len
&& (event
== WLC_E_DEAUTH
)) {
14589 len
= 2; /* reason code field */
14594 body
= kzalloc(len
, GFP_KERNEL
);
14595 if (body
== NULL
) {
14596 WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
14601 memset(&bssid
, 0, ETHER_ADDR_LEN
);
14602 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_INVALID
) {
14607 memcpy(body
, data
, len
);
14609 wldev_iovar_getbuf_bsscfg(ndev
, "cur_etheraddr",
14610 NULL
, 0, cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, bsscfgidx
, &cfg
->ioctl_buf_sync
);
14611 memcpy(da
.octet
, cfg
->ioctl_buf
, ETHER_ADDR_LEN
);
14612 err
= wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
14613 /* Use e->addr as bssid for Sta case , before association completed */
14614 if (err
== BCME_NOTASSOCIATED
)
14615 memcpy(&bssid
, &e
->addr
, ETHER_ADDR_LEN
);
14618 case WLC_E_ASSOC_IND
:
14621 case WLC_E_REASSOC_IND
:
14622 fc
= FC_REASSOC_REQ
;
14624 case WLC_E_DISASSOC_IND
:
14627 case WLC_E_DEAUTH_IND
:
14640 if ((err
= wldev_ioctl_get(ndev
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
)))) {
14645 channel
= dtoh32(ci
.hw_channel
);
14646 if (channel
<= CH_MAX_2G_CHANNEL
)
14647 band
= wiphy
->bands
[IEEE80211_BAND_2GHZ
];
14649 band
= wiphy
->bands
[IEEE80211_BAND_5GHZ
];
14651 WL_ERR(("No valid band\n"));
14656 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
14657 freq
= ieee80211_channel_to_frequency(channel
);
14660 freq
= ieee80211_channel_to_frequency(channel
, band
->band
);
14663 err
= wl_frame_get_mgmt(cfg
, fc
, &da
, &e
->addr
, &bssid
,
14664 &mgmt_frame
, &len
, body
);
14670 if (event
== WLC_E_ASSOC_IND
&& reason
== DOT11_SC_SUCCESS
) {
14671 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14672 cfg80211_rx_mgmt(cfgdev
, freq
, rssi
, mgmt_frame
, len
, 0);
14673 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14674 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, GFP_ATOMIC
);
14676 cfg80211_rx_mgmt(ndev
, freq
, mgmt_frame
, len
, GFP_ATOMIC
);
14678 } else if (event
== WLC_E_DISASSOC_IND
) {
14679 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14680 cfg80211_rx_mgmt(cfgdev
, freq
, rssi
, mgmt_frame
, len
, 0);
14681 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14682 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, GFP_ATOMIC
);
14684 cfg80211_rx_mgmt(ndev
, freq
, mgmt_frame
, len
, GFP_ATOMIC
);
14686 } else if ((event
== WLC_E_DEAUTH_IND
) || (event
== WLC_E_DEAUTH
)) {
14687 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14688 cfg80211_rx_mgmt(cfgdev
, freq
, rssi
, mgmt_frame
, len
, 0);
14689 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14690 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, GFP_ATOMIC
);
14692 cfg80211_rx_mgmt(ndev
, freq
, mgmt_frame
, len
, GFP_ATOMIC
);
14694 } else if (event
== WLC_E_AUTH
) {
14695 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14696 cfg80211_rx_mgmt(cfgdev
, freq
, rssi
, mgmt_frame
, len
, 0);
14697 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14698 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, GFP_ATOMIC
);
14700 cfg80211_rx_mgmt(ndev
, freq
, mgmt_frame
, len
, GFP_ATOMIC
);
14710 #endif /* WL_CLIENT_SAE */
14713 wl_notify_connect_status_ibss(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
14714 const wl_event_msg_t
*e
, void *data
)
14717 u32 event
= ntoh32(e
->event_type
);
14718 u16 flags
= ntoh16(e
->flags
);
14719 u32 status
= ntoh32(e
->status
);
14721 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14722 struct ieee80211_channel
*channel
= NULL
;
14723 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
14724 chanspec_t chanspec
;
14726 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14728 if (event
== WLC_E_JOIN
) {
14729 WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev
->name
));
14731 if (event
== WLC_E_START
) {
14732 WL_INFORM_MEM(("[%s] started IBSS network\n", ndev
->name
));
14734 if (event
== WLC_E_JOIN
|| event
== WLC_E_START
||
14735 (event
== WLC_E_LINK
&& (flags
== WLC_EVENT_MSG_LINK
))) {
14736 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14737 err
= wldev_iovar_getint(ndev
, "chanspec", (s32
*)&chanspec
);
14738 if (unlikely(err
)) {
14739 WL_ERR(("Could not get chanspec %d\n", err
));
14742 chanspec
= wl_chspec_driver_to_host(chanspec
);
14743 freq
= wl_channel_to_frequency(wf_chspec_ctlchan(chanspec
), CHSPEC_BAND(chanspec
));
14744 channel
= ieee80211_get_channel(wiphy
, freq
);
14745 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14746 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
14747 /* ROAM or Redundant */
14748 u8
*cur_bssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
14749 if (memcmp(cur_bssid
, &e
->addr
, ETHER_ADDR_LEN
) == 0) {
14750 WL_DBG(("IBSS connected event from same BSSID("
14751 MACDBG
"), ignore it\n", MAC2STRDBG(cur_bssid
)));
14754 WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG
" to " MACDBG
"\n",
14755 ndev
->name
, MAC2STRDBG(cur_bssid
),
14756 MAC2STRDBG((const u8
*)&e
->addr
)));
14757 wl_get_assoc_ies(cfg
, ndev
);
14758 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&e
->addr
, WL_PROF_BSSID
);
14759 wl_update_bss_info(cfg
, ndev
, false);
14760 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14761 cfg80211_ibss_joined(ndev
, (const s8
*)&e
->addr
, channel
, GFP_KERNEL
);
14763 cfg80211_ibss_joined(ndev
, (const s8
*)&e
->addr
, GFP_KERNEL
);
14767 /* New connection */
14768 WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG
"\n",
14769 ndev
->name
, MAC2STRDBG((const u8
*)&e
->addr
)));
14771 wl_get_assoc_ies(cfg
, ndev
);
14772 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&e
->addr
, WL_PROF_BSSID
);
14773 wl_update_bss_info(cfg
, ndev
, false);
14774 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14775 cfg80211_ibss_joined(ndev
, (const s8
*)&e
->addr
, channel
, GFP_KERNEL
);
14777 cfg80211_ibss_joined(ndev
, (const s8
*)&e
->addr
, GFP_KERNEL
);
14779 wl_set_drv_status(cfg
, CONNECTED
, ndev
);
14781 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&active
, WL_PROF_ACT
);
14783 } else if ((event
== WLC_E_LINK
&& !(flags
& WLC_EVENT_MSG_LINK
)) ||
14784 event
== WLC_E_DEAUTH_IND
|| event
== WLC_E_DISASSOC_IND
) {
14785 wl_clr_drv_status(cfg
, CONNECTED
, ndev
);
14787 wl_init_prof(cfg
, ndev
);
14789 else if (event
== WLC_E_SET_SSID
&& status
== WLC_E_STATUS_NO_NETWORKS
) {
14790 WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
14793 WL_DBG(("no action (IBSS mode)\n"));
14798 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
14799 #define WiFiALL_OUI "\x50\x6F\x9A" /* Wi-FiAll OUI */
14800 #define WiFiALL_OUI_LEN 3
14801 #define WiFiALL_OUI_TYPE 16
14803 /* 11kv feature flag for big data */
14804 #define WL_BIGDATA_11KV_QBSSLOAD 0x00000001
14805 #define WL_BIGDATA_11KV_PROXYARP 0x00000002
14806 #define WL_BIGDATA_11KV_TFS 0x00000004
14807 #define WL_BIGDATA_11KV_SLEEP 0x00000008
14808 #define WL_BIGDATA_11KV_TIMBC 0x00000010
14809 #define WL_BIGDATA_11KV_BSSTRANS 0x00000020
14810 #define WL_BIGDATA_11KV_DMS 0x00000040
14811 #define WL_BIGDATA_11KV_LINK_MEA 0x00000080
14812 #define WL_BIGDATA_11KV_NBRREP 0x00000100
14813 #define WL_BIGDATA_11KV_BCNPASSIVE 0x00000200
14814 #define WL_BIGDATA_11KV_BCNACTIVE 0x00000400
14815 #define WL_BIGDATA_11KV_BCNTABLE 0x00000800
14816 #define WL_BIGDATA_11KV_BSSAAD 0x00001000
14817 #define WL_BIGDATA_11KV_MAX 0x00002000
14819 #define WL_BIGDATA_SUPPORT_11K 0x00000001
14820 #define WL_BIGDATA_SUPPORT_11V 0x00000002
14828 bigdata_11kv_t bigdata_11k_info
[] = {
14829 {DOT11_RRM_CAP_LINK
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_LINK_MEA
},
14830 {DOT11_RRM_CAP_NEIGHBOR_REPORT
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_NBRREP
},
14831 {DOT11_RRM_CAP_BCN_PASSIVE
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_BCNPASSIVE
},
14832 {DOT11_RRM_CAP_BCN_ACTIVE
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_BCNACTIVE
},
14833 {DOT11_RRM_CAP_BCN_TABLE
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_BCNTABLE
},
14834 {DOT11_RRM_CAP_BSSAAD
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_BSSAAD
},
14837 bigdata_11kv_t bigdata_11v_info
[] = {
14838 {DOT11_EXT_CAP_PROXY_ARP
, DOT11_EXTCAP_LEN_PROXY_ARP
, WL_BIGDATA_11KV_PROXYARP
},
14839 {DOT11_EXT_CAP_TFS
, DOT11_EXTCAP_LEN_TFS
, WL_BIGDATA_11KV_TFS
},
14840 {DOT11_EXT_CAP_WNM_SLEEP
, DOT11_EXTCAP_LEN_WNM_SLEEP
, WL_BIGDATA_11KV_SLEEP
},
14841 {DOT11_EXT_CAP_TIMBC
, DOT11_EXTCAP_LEN_TIMBC
, WL_BIGDATA_11KV_TIMBC
},
14842 {DOT11_EXT_CAP_BSSTRANS_MGMT
, DOT11_EXTCAP_LEN_BSSTRANS
, WL_BIGDATA_11KV_BSSTRANS
},
14843 {DOT11_EXT_CAP_DMS
, DOT11_EXTCAP_LEN_DMS
, WL_BIGDATA_11KV_DMS
}
14847 wl_get_11kv_info(u8
*ie
, u32 ie_len
, uint8
*support_11kv
, uint32
*flag_11kv
)
14849 bcm_tlv_t
*ie_11kv
= NULL
;
14850 uint32 flag_11k
= 0, flag_11v
= 0;
14853 /* parsing QBSS load ie */
14854 if ((bcm_parse_tlvs(ie
, (u32
)ie_len
,
14855 DOT11_MNG_QBSS_LOAD_ID
)) != NULL
) {
14856 flag_11k
|= WL_BIGDATA_11KV_QBSSLOAD
;
14859 /* parsing RM IE for 11k */
14860 if ((ie_11kv
= bcm_parse_tlvs(ie
, (u32
)ie_len
,
14861 DOT11_MNG_RRM_CAP_ID
)) != NULL
) {
14862 for (i
= 0; i
< ARRAYSIZE(bigdata_11k_info
); i
++) {
14863 if ((ie_11kv
->len
>= bigdata_11k_info
[i
].octet_len
) &&
14864 isset(ie_11kv
->data
, bigdata_11k_info
[i
].bitmap
)) {
14865 flag_11k
|= bigdata_11k_info
[i
].flag
;
14870 /* parsing extended cap. IE for 11v */
14871 if ((ie_11kv
= bcm_parse_tlvs(ie
, (u32
)ie_len
,
14872 DOT11_MNG_EXT_CAP_ID
)) != NULL
) {
14873 for (i
= 0; i
< ARRAYSIZE(bigdata_11v_info
); i
++) {
14874 if ((ie_11kv
->len
>= bigdata_11v_info
[i
].octet_len
) &&
14875 isset(ie_11kv
->data
, bigdata_11v_info
[i
].bitmap
)) {
14876 flag_11v
|= bigdata_11v_info
[i
].flag
;
14881 if (flag_11k
> 0) {
14882 *support_11kv
|= WL_BIGDATA_SUPPORT_11K
;
14885 if (flag_11v
> 0) {
14886 *support_11kv
|= WL_BIGDATA_SUPPORT_11V
;
14889 *flag_11kv
= flag_11k
| flag_11v
;
14892 int wl_get_bss_info(struct bcm_cfg80211
*cfg
, struct net_device
*dev
, struct ether_addr
const *mac
)
14895 wl_bss_info_v109_1_t
*bi
;
14896 uint8 eabuf
[ETHER_ADDR_LEN
];
14897 u32 rate
, channel
, freq
, supported_rate
, nss
= 0, mcs_map
, mode_80211
= 0;
14901 struct wiphy
*wiphy
;
14902 struct cfg80211_bss
*bss
;
14903 bcm_tlv_t
*interworking_ie
= NULL
;
14904 bcm_tlv_t
*tlv_ie
= NULL
;
14905 bcm_tlv_t
*vht_ie
= NULL
;
14907 int16 ie_11u_rel_num
= -1, ie_mu_mimo_cap
= -1;
14908 u32 i
, remained_len
, count
= 0;
14909 char roam_count_str
[4], akm_str
[4];
14911 uint8 support_11kv
= 0;
14912 uint32 flag_11kv
= 0; /* bit flags of 11kv big data */
14913 int cfg_bss_info_len
= 0;
14915 /* get BSS information */
14917 strlcpy(cfg
->bss_info
, "x x x x x x x x x x x x x x x x x", sizeof(cfg
->bss_info
));
14919 *(u32
*) cfg
->extra_buf
= htod32(WL_EXTRA_BUF_MAX
);
14921 err
= wldev_ioctl_get(dev
, WLC_GET_BSS_INFO
, cfg
->extra_buf
, WL_EXTRA_BUF_MAX
);
14922 if (unlikely(err
)) {
14923 WL_ERR(("Could not get bss info %d\n", err
));
14924 cfg
->roam_count
= 0;
14929 WL_ERR(("mac is null \n"));
14930 cfg
->roam_count
= 0;
14934 memcpy(eabuf
, mac
, ETHER_ADDR_LEN
);
14936 bi
= (wl_bss_info_v109_1_t
*)(cfg
->extra_buf
+ 4);
14937 channel
= wf_chspec_ctlchan(bi
->chanspec
);
14938 freq
= wl_channel_to_frequency(channel
, CHSPEC_BAND(bi
->chanspec
));
14940 err
= wldev_ioctl_get(dev
, WLC_GET_RATE
, &rate
, sizeof(rate
));
14942 WL_ERR(("Could not get rate (%d)\n", err
));
14943 snprintf(rate_str
, sizeof(rate_str
), "x"); /* Unknown */
14946 rate
= dtoh32(rate
);
14947 snprintf(rate_str
, sizeof(rate_str
), "%d", (rate
/2));
14950 /* supported maximum rate */
14951 supported_rate
= (bi
->rateset
.rates
[bi
->rateset
.count
- 1] & 0x7f) / 2;
14953 if (supported_rate
< 12) {
14954 mode_80211
= BIGDATA_DOT11_11B_MODE
; /* 11b maximum rate is 11Mbps. 11b mode */
14956 /* It's not HT Capable case. */
14957 if (channel
> 14) {
14958 mode_80211
= BIGDATA_DOT11_11A_MODE
; /* 11a mode */
14960 mode_80211
= BIGDATA_DOT11_11G_MODE
; /* 11g mode */
14965 /* check Rx MCS Map for HT */
14967 mode_80211
= BIGDATA_DOT11_11N_MODE
;
14968 for (i
= 0; i
< MAX_STREAMS_SUPPORTED
; i
++) {
14969 int8 bitmap
= DOT11_HT_MCS_RATE_MASK
;
14970 if (i
== MAX_STREAMS_SUPPORTED
-1) {
14971 bitmap
= DOT11_RATE_MASK
;
14973 if (bi
->basic_mcs
[i
] & bitmap
) {
14981 mode_80211
= BIGDATA_DOT11_11AC_MODE
;
14982 for (i
= 1; i
<= VHT_CAP_MCS_MAP_NSS_MAX
; i
++) {
14983 mcs_map
= VHT_MCS_MAP_GET_MCS_PER_SS(i
, dtoh16(bi
->vht_rxmcsmap
));
14984 if (mcs_map
!= VHT_CAP_MCS_MAP_NONE
) {
14990 #if defined(WL11AX)
14993 mode_80211
= BIGDATA_DOT11_11AX_MODE
;
14994 for (i
= 1; i
<= HE_MCS_MAP_NSS_MAX
; i
++) {
14995 mcs_map
= HE_MCS_NSS_GET_MCS(i
, dtoh32(bi
->he_rxmcsmap
));
14996 if (mcs_map
!= HE_MCS_CODE_NONE
) {
15001 #endif /* WL11AX */
15007 wiphy
= bcmcfg_to_wiphy(cfg
);
15008 bss
= CFG80211_GET_BSS(wiphy
, NULL
, eabuf
, bi
->SSID
, bi
->SSID_len
);
15010 WL_ERR(("Could not find the AP\n"));
15012 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
15013 #if defined(WL_CFG80211_P2P_DEV_IF)
15014 ie
= (u8
*)bss
->ies
->data
;
15015 ie_len
= bss
->ies
->len
;
15017 ie
= bss
->information_elements
;
15018 ie_len
= bss
->len_information_elements
;
15019 #endif /* WL_CFG80211_P2P_DEV_IF */
15020 GCC_DIAGNOSTIC_POP();
15024 ie_mu_mimo_cap
= 0;
15025 ie_11u_rel_num
= 0;
15028 if ((vht_ie
= bcm_parse_tlvs(ie
, ie_len
,
15029 DOT11_MNG_VHT_CAP_ID
)) != NULL
) {
15030 if (vht_ie
->len
>= VHT_CAP_IE_LEN
) {
15031 ie_mu_mimo_cap
= (vht_ie
->data
[2] & 0x08) >> 3;
15036 if ((interworking_ie
= bcm_parse_tlvs(ie
, ie_len
,
15037 DOT11_MNG_INTERWORKING_ID
)) != NULL
) {
15038 if ((tlv_ie
= bcm_parse_tlvs(ie
, ie_len
, DOT11_MNG_VS_ID
)) != NULL
) {
15039 remained_len
= ie_len
;
15042 if (count
> MAX_VNDR_IE_NUMBER
)
15045 if (tlv_ie
->id
== DOT11_MNG_VS_ID
) {
15046 vndrie
= (vndr_ie_t
*) tlv_ie
;
15048 if (vndrie
->len
< (VNDR_IE_MIN_LEN
+ 1)) {
15049 WL_ERR(("wl_get_bss_info: invalid vndr ie."
15050 "length is too small %d\n",
15055 if (!bcmp(vndrie
->oui
,
15056 (u8
*)WiFiALL_OUI
, WiFiALL_OUI_LEN
) &&
15057 (vndrie
->data
[0] == WiFiALL_OUI_TYPE
))
15059 WL_ERR(("Found Wi-FiAll OUI oui.\n"));
15060 ie_11u_rel_num
= vndrie
->data
[1];
15061 ie_11u_rel_num
= (ie_11u_rel_num
& 0xf0)>>4;
15062 ie_11u_rel_num
+= 1;
15068 tlv_ie
= bcm_next_tlv(tlv_ie
, &remained_len
);
15073 /* get 11kv information from ie of current bss */
15074 wl_get_11kv_info(ie
, ie_len
, &support_11kv
, &flag_11kv
);
15077 for (i
= 0; i
< bi
->SSID_len
; i
++) {
15078 if (bi
->SSID
[i
] == ' ') {
15083 /* 0 : None, 1 : OKC, 2 : FT, 3 : CCKM */
15084 err
= wldev_iovar_getint(dev
, "wpa_auth", &val
);
15085 if (unlikely(err
)) {
15086 WL_ERR(("could not get wpa_auth (%d)\n", err
));
15087 snprintf(akm_str
, sizeof(akm_str
), "x"); /* Unknown */
15089 WL_ERR(("wpa_auth val %d \n", val
));
15090 if (val
& WPA2_AUTH_FT
) {
15091 snprintf(akm_str
, sizeof(akm_str
), "2");
15092 } else if (val
& (WPA_AUTH_UNSPECIFIED
| WPA2_AUTH_UNSPECIFIED
)) {
15093 snprintf(akm_str
, sizeof(akm_str
), "1");
15095 snprintf(akm_str
, sizeof(akm_str
), "0");
15099 if (cfg
->roam_offload
) {
15100 snprintf(roam_count_str
, sizeof(roam_count_str
), "x"); /* Unknown */
15102 snprintf(roam_count_str
, sizeof(roam_count_str
), "%d", cfg
->roam_count
);
15104 cfg
->roam_count
= 0;
15106 WL_ERR(("BSSID:" MACDBG
" SSID %s \n", MAC2STRDBG(eabuf
), "*****"));
15107 WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d,"
15108 "MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n"
15109 "akm:%s, roam:%s, 11kv:%d/%d \n",
15110 freq
, wf_chspec_to_bw_str(bi
->chanspec
),
15111 dtoh32(bi
->RSSI
), (rate
/ 2), mode_80211
, nss
,
15112 ie_mu_mimo_cap
, ie_11u_rel_num
, bi
->SNR
, bi
->phy_noise
,
15113 akm_str
, roam_count_str
, support_11kv
, flag_11kv
));
15116 snprintf(cfg
->bss_info
, GET_BSS_INFO_LEN
,
15117 MACOUI
" %d %s %d %s %d %d %d %d %d %d %s %s %d %d",
15118 MACOUI2STR(eabuf
), freq
, wf_chspec_to_bw_str(bi
->chanspec
),
15119 dtoh32(bi
->RSSI
), rate_str
, mode_80211
, nss
, ie_mu_mimo_cap
,
15120 ie_11u_rel_num
, bi
->SNR
, bi
->phy_noise
, akm_str
, roam_count_str
,
15121 support_11kv
, flag_11kv
);
15123 /* ie_mu_mimo_cap and ie_11u_rel_num is unknow. */
15124 snprintf(cfg
->bss_info
, GET_BSS_INFO_LEN
,
15125 MACOUI
" %d %s %d %s %d %d x x %d %d %s %s x x",
15126 MACOUI2STR(eabuf
), freq
, wf_chspec_to_bw_str(bi
->chanspec
),
15127 dtoh32(bi
->RSSI
), rate_str
, mode_80211
, nss
, bi
->SNR
,
15128 bi
->phy_noise
, akm_str
, roam_count_str
);
15131 cfg_bss_info_len
= strlen(cfg
->bss_info
);
15132 if (GET_BSS_INFO_LEN
> cfg_bss_info_len
) {
15133 uint16 full_cnt
= 0, partial_cnt
= 0;
15134 bool cnt_valid
= FALSE
;
15136 #if defined(DHD_PUB_ROAM_EVT)
15137 wl_roam_stats_v1_t
*roam_elem
=
15138 (wl_roam_stats_v1_t
*)dhd_get_roam_evt((dhd_pub_t
*)cfg
->pub
);
15140 if (roam_elem
&& roam_elem
->version
== WL_ROAM_STATS_VER_1
) {
15141 wl_roam_stats_v1_t
*roam_elem_v1
;
15142 roam_elem_v1
= (wl_roam_stats_v1_t
*)(uintptr_t)roam_elem
;
15145 full_cnt
= roam_elem_v1
->full_roam_scan_cnt
;
15146 partial_cnt
= roam_elem_v1
->partial_roam_scan_cnt
;
15148 #endif /* DHD_PUB_ROAM_EVT */
15150 WL_ERR(("GET_BSS: full roam scan count:%d partial roam scan count:%d\n",
15151 full_cnt
, partial_cnt
));
15152 snprintf(&cfg
->bss_info
[cfg_bss_info_len
],
15153 GET_BSS_INFO_LEN
- cfg_bss_info_len
, " %d %d",
15154 full_cnt
, partial_cnt
);
15156 WL_ERR(("GET_BSS: roam scan count invalid\n"));
15157 snprintf(&cfg
->bss_info
[cfg_bss_info_len
],
15158 GET_BSS_INFO_LEN
- cfg_bss_info_len
, " x x");
15161 WL_ERR(("Buffer to short to save roam info\n"));
15164 CFG80211_PUT_BSS(wiphy
, bss
);
15169 s32
wl_cfg80211_get_bss_info(struct net_device
*dev
, char* cmd
, int total_len
)
15171 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
15177 if (total_len
< GET_BSS_INFO_LEN
) {
15178 WL_ERR(("wl_cfg80211_get_bss_info: Buffer insuffient %d\n", total_len
));
15182 bzero(cmd
, total_len
);
15183 memcpy(cmd
, cfg
->bss_info
, GET_BSS_INFO_LEN
);
15185 WL_ERR_KERN(("cmd: %s \n", cmd
));
15187 return GET_BSS_INFO_LEN
;
15189 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
15191 void wl_cfg80211_disassoc(struct net_device
*ndev
, uint32 reason
)
15195 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
15196 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
15198 BCM_REFERENCE(cfg
);
15199 BCM_REFERENCE(dhdp
);
15200 DHD_STATLOG_CTRL(dhdp
, ST(DISASSOC_INT_START
),
15201 dhd_net2idx(dhdp
->info
, ndev
), WLAN_REASON_DEAUTH_LEAVING
);
15203 memset_s(&scbval
, sizeof(scb_val_t
), 0x0, sizeof(scb_val_t
));
15204 scbval
.val
= htod32(reason
);
15205 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, &scbval
, sizeof(scb_val_t
));
15207 WL_ERR(("WLC_DISASSOC error %d\n", err
));
15209 WL_INFORM_MEM(("wl disassoc. reason:%d\n", reason
));
15212 void wl_cfg80211_del_all_sta(struct net_device
*ndev
, uint32 reason
)
15214 struct net_device
*dev
;
15215 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
15218 char mac_buf
[MAX_NUM_OF_ASSOCIATED_DEV
*
15219 sizeof(struct ether_addr
) + sizeof(uint
)] = {0};
15220 struct maclist
*assoc_maclist
= (struct maclist
*)mac_buf
;
15221 int num_associated
= 0;
15223 dev
= ndev_to_wlc_ndev(ndev
, cfg
);
15225 if (p2p_is_on(cfg
)) {
15226 /* Suspend P2P discovery search-listen to prevent it from changing the
15229 if ((wl_cfgp2p_discover_enable_search(cfg
, false)) < 0) {
15230 WL_ERR(("Can not disable discovery mode\n"));
15235 assoc_maclist
->count
= MAX_NUM_OF_ASSOCIATED_DEV
;
15236 err
= wldev_ioctl_get(ndev
, WLC_GET_ASSOCLIST
,
15237 assoc_maclist
, sizeof(mac_buf
));
15239 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err
));
15241 num_associated
= assoc_maclist
->count
;
15243 memset(scb_val
.ea
.octet
, 0xff, ETHER_ADDR_LEN
);
15244 scb_val
.val
= DOT11_RC_DEAUTH_LEAVING
;
15245 scb_val
.val
= htod32(reason
);
15246 err
= wldev_ioctl_set(dev
, WLC_SCB_DEAUTHENTICATE_FOR_REASON
, &scb_val
,
15247 sizeof(scb_val_t
));
15249 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err
));
15252 /* WAR Wait for the deauth event to come, supplicant will do the
15253 * delete iface immediately and we will have problem in sending
15254 * deauth frame if we delete the bss in firmware
15255 * But we do not need additional delays for this WAR
15256 * during P2P connection.
15258 * Supplicant call this function with BCAST after doing
15259 * wl_cfg80211_del_station() all GC stations with each addr.
15260 * So, 400 ms delay can be called only once when GO disconnect all GC
15262 if (num_associated
> 0)
15267 /* API to handle the Deauth from the AP.
15268 * For now we are deleting the PMKID cache in DHD/FW
15269 * in case of current connection is using SAE authnetication
15272 wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
15273 const wl_event_msg_t
*e
, void *data
)
15277 uint8 bssid
[ETHER_ADDR_LEN
];
15278 struct cfg80211_pmksa pmksa
;
15280 struct wlc_ssid
*curssid
;
15281 pmkid_list_v3_t
*spmk_list
= &cfg
->spmk_info_list
->pmkids
;
15282 pmkid_v3_t
*t_pmkid
= NULL
;
15284 bool bFound
= FALSE
;
15286 err
= wldev_iovar_getint(ndev
, "wpa_auth", &val
);
15287 if (unlikely(err
)) {
15288 WL_ERR(("could not get wpa_auth (%d)\n", err
));
15291 if (val
== WPA3_AUTH_SAE_PSK
) {
15292 (void)memcpy_s(bssid
, ETHER_ADDR_LEN
,
15293 (const uint8
*)&e
->addr
, ETHER_ADDR_LEN
);
15294 memset_s(&pmksa
, sizeof(pmksa
), 0, sizeof(pmksa
));
15295 pmksa
.bssid
= bssid
;
15296 WL_INFORM_MEM(("Deleting the PMKSA for SAE AP "MACDBG
,
15297 MAC2STRDBG(e
->addr
.octet
)));
15298 wl_cfg80211_del_pmksa(cfg
->wdev
->wiphy
, ndev
, &pmksa
);
15299 curssid
= wl_read_prof(cfg
, ndev
, WL_PROF_SSID
);
15300 for (idx
= 0; idx
< spmk_list
->count
; idx
++) {
15301 t_pmkid
= &spmk_list
->pmkid
[idx
];
15302 if (curssid
->SSID_len
== t_pmkid
->ssid_len
&&
15303 !memcmp(curssid
->SSID
, t_pmkid
->ssid
, curssid
->SSID_len
)) {
15311 for (; idx
< spmk_list
->count
- 1; idx
++) {
15312 memcpy_s(&spmk_list
->pmkid
[idx
], sizeof(pmkid_v3_t
),
15313 &spmk_list
->pmkid
[idx
+ 1], sizeof(pmkid_v3_t
));
15315 spmk_list
->count
--;
15318 #endif /* WL_SAE */
15323 wl_cache_assoc_resp_ies(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
15324 const wl_event_msg_t
*e
, void *data
)
15326 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
15327 u32 datalen
= ntoh32(e
->datalen
);
15328 u32 event_type
= ntoh32(e
->event_type
);
15330 if (data
&& datalen
<= sizeof(conn_info
->resp_ie
)) {
15331 conn_info
->resp_ie_len
= datalen
;
15332 WL_DBG((" assoc resp IES len = %d\n", conn_info
->resp_ie_len
));
15333 bzero(conn_info
->resp_ie
, sizeof(conn_info
->resp_ie
));
15334 (void)memcpy_s(conn_info
->resp_ie
, sizeof(conn_info
->resp_ie
),
15337 WL_INFORM_MEM(("[%s] copied assoc resp ies, sent to upper layer:"
15338 "event %d reason=%d ie_len=%d from " MACDBG
"\n",
15339 ndev
->name
, event_type
, ntoh32(e
->reason
), datalen
,
15340 MAC2STRDBG((const u8
*)(&e
->addr
))));
15344 #ifdef WLMESH_CFG80211
15346 wl_notify_connect_status_mesh(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
15347 const wl_event_msg_t
*e
, void *data
)
15350 u32 event
= ntoh32(e
->event_type
);
15351 u32 reason
= ntoh32(e
->reason
);
15352 u32 len
= ntoh32(e
->datalen
);
15353 u32 status
= ntoh32(e
->status
);
15355 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
15356 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
15357 bool isfree
= false;
15359 u8 bsscfgidx
= e
->bsscfgidx
;
15366 struct ieee80211_supported_band
*band
;
15367 struct ether_addr da
;
15368 struct ether_addr bssid
;
15369 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
15371 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
15373 struct station_info sinfo
;
15374 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
15376 WL_INFORM_MEM(("[%s] Mode Mesh. Event:%d status:%d reason:%d\n",
15377 ndev
->name
, event
, ntoh32(e
->status
), reason
));
15379 /* if link down, bsscfg is disabled. */
15380 if (event
== WLC_E_LINK
&& reason
== WLC_E_LINK_BSSCFG_DIS
&&
15381 (ndev
!= bcmcfg_to_prmry_ndev(cfg
))) {
15382 WL_MSG(ndev
->name
, "Mesh mode link down !! \n");
15386 if ((event
== WLC_E_LINK
) && (status
== WLC_E_STATUS_SUCCESS
) &&
15387 (reason
== WLC_E_REASON_INITIAL_ASSOC
)) {
15388 /* AP/GO brought up successfull in firmware */
15389 WL_MSG(ndev
->name
, "Mesh Link up\n");
15393 if (event
== WLC_E_DISASSOC_IND
|| event
== WLC_E_DEAUTH_IND
|| event
== WLC_E_DEAUTH
) {
15394 WL_MSG(ndev
->name
, "event %s(%d) status %d reason %d\n",
15395 bcmevent_get_name(event
), event
, ntoh32(e
->status
), reason
);
15398 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
15399 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
15400 WL_DBG(("Enter \n"));
15401 if (!len
&& (event
== WLC_E_DEAUTH
)) {
15402 len
= 2; /* reason code field */
15406 body
= (u8
*)MALLOCZ(cfg
->osh
, len
);
15407 if (body
== NULL
) {
15408 WL_ERR(("Failed to allocate body\n"));
15412 bzero(&bssid
, ETHER_ADDR_LEN
);
15413 WL_DBG(("Enter event %d ndev %p\n", event
, ndev
));
15414 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_INVALID
) {
15415 MFREE(cfg
->osh
, body
, len
);
15419 memcpy(body
, data
, len
);
15421 wldev_iovar_getbuf_bsscfg(ndev
, "cur_etheraddr",
15422 NULL
, 0, ioctl_buf
, sizeof(ioctl_buf
), bsscfgidx
, NULL
);
15423 memcpy(da
.octet
, ioctl_buf
, ETHER_ADDR_LEN
);
15424 bzero(&bssid
, sizeof(bssid
));
15425 err
= wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
15427 case WLC_E_ASSOC_IND
:
15430 case WLC_E_REASSOC_IND
:
15431 fc
= FC_REASSOC_REQ
;
15433 case WLC_E_DISASSOC_IND
:
15436 case WLC_E_DEAUTH_IND
:
15446 bzero(&ci
, sizeof(ci
));
15447 if ((err
= wldev_ioctl_get(ndev
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
)))) {
15448 MFREE(cfg
->osh
, body
, len
);
15452 channel
= dtoh32(ci
.hw_channel
);
15453 if (channel
<= CH_MAX_2G_CHANNEL
)
15454 band
= wiphy
->bands
[IEEE80211_BAND_2GHZ
];
15456 band
= wiphy
->bands
[IEEE80211_BAND_5GHZ
];
15458 WL_ERR(("No valid band\n"));
15460 MFREE(cfg
->osh
, body
, len
);
15464 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
15465 freq
= ieee80211_channel_to_frequency(channel
);
15468 freq
= ieee80211_channel_to_frequency(channel
, band
->band
);
15471 err
= wl_frame_get_mgmt(cfg
, fc
, &da
, &e
->addr
, &bssid
,
15472 &mgmt_frame
, &len
, body
);
15477 if ((event
== WLC_E_ASSOC_IND
&& reason
== DOT11_SC_SUCCESS
) ||
15478 (event
== WLC_E_DISASSOC_IND
) ||
15479 ((event
== WLC_E_DEAUTH_IND
) || (event
== WLC_E_DEAUTH
))) {
15480 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
15481 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, 0);
15482 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
15483 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, 0, GFP_ATOMIC
);
15484 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
15485 defined(WL_COMPAT_WIRELESS)
15486 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, GFP_ATOMIC
);
15488 cfg80211_rx_mgmt(ndev
, freq
, mgmt_frame
, len
, GFP_ATOMIC
);
15489 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
15494 MFREE(cfg
->osh
, mgmt_frame
, len
);
15497 MFREE(cfg
->osh
, body
, body_len
);
15499 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
15500 memset(&sinfo
, 0, sizeof(struct station_info
));
15502 if (((event
== WLC_E_ASSOC_IND
) || (event
== WLC_E_REASSOC_IND
)) &&
15503 reason
== DOT11_SC_SUCCESS
) {
15504 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
15505 * STATION_INFO_ASSOC_REQ_IES flag
15507 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
15508 sinfo
.filled
= STA_INFO_BIT(INFO_ASSOC_REQ_IES
);
15509 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
15511 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
15514 sinfo
.assoc_req_ies
= data
;
15515 sinfo
.assoc_req_ies_len
= len
;
15516 WL_MSG(ndev
->name
, "new sta event for "MACDBG
"\n",
15517 MAC2STRDBG(e
->addr
.octet
));
15518 cfg80211_new_sta(ndev
, e
->addr
.octet
, &sinfo
, GFP_ATOMIC
);
15519 } else if ((event
== WLC_E_DEAUTH_IND
) ||
15520 ((event
== WLC_E_DEAUTH
) && (reason
!= DOT11_RC_RESERVED
)) ||
15521 (event
== WLC_E_DISASSOC_IND
)) {
15522 WL_MSG(ndev
->name
, "del sta event for "MACDBG
"\n",
15523 MAC2STRDBG(e
->addr
.octet
));
15524 cfg80211_del_sta(ndev
, e
->addr
.octet
, GFP_ATOMIC
);
15526 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
15529 #endif /* WLMESH_CFG80211 */
15532 wl_notify_connect_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
15533 const wl_event_msg_t
*e
, void *data
)
15536 struct net_device
*ndev
= NULL
;
15538 u32 event
= ntoh32(e
->event_type
);
15539 u32 datalen
= ntoh32(e
->datalen
);
15540 struct wiphy
*wiphy
= NULL
;
15541 struct cfg80211_bss
*bss
= NULL
;
15542 struct wlc_ssid
*ssid
= NULL
;
15550 int vndr_oui_num
= 0;
15551 char vndr_oui
[MAX_VNDR_OUI_STR_LEN
] = {0, };
15552 bool loc_gen
= false;
15553 #ifdef DHD_LOSSLESS_ROAMING
15554 struct wl_security
*sec
;
15555 #endif /* DHD_LOSSLESS_ROAMING */
15556 #if defined(DHDTCPSYNC_FLOOD_BLK) && defined(CUSTOMER_TCPSYNC_FLOOD_DIS_RC)
15557 dhd_if_t
*ifp
= NULL
;
15558 #endif /* DHDTCPSYNC_FLOOD_BLK && CUSTOMER_TCPSYNC_FLOOD_DIS_RC */
15560 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
15561 #ifdef DHD_LOSSLESS_ROAMING
15562 sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
15563 #endif /* DHD_LOSSLESS_ROAMING */
15564 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
15565 BCM_REFERENCE(dhdp
);
15567 mode
= wl_get_mode_by_netdev(cfg
, ndev
);
15568 /* Push link events to upper layer log */
15569 SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n",
15570 ndev
->name
, mode
, ntoh32(e
->event_type
),
15571 ntoh32(e
->status
), ntoh32(e
->reason
)));
15572 if (mode
== WL_MODE_AP
) {
15573 err
= wl_notify_connect_status_ap(cfg
, ndev
, e
, data
);
15574 #ifdef WLMESH_CFG80211
15575 } else if (mode
== WL_MODE_MESH
) {
15576 err
= wl_notify_connect_status_mesh(cfg
, ndev
, e
, data
);
15577 #endif /* WLMESH_CFG80211 */
15578 } else if (mode
== WL_MODE_IBSS
) {
15579 err
= wl_notify_connect_status_ibss(cfg
, ndev
, e
, data
);
15580 } else if (mode
== WL_MODE_BSS
) {
15581 WL_INFORM_MEM(("[%s] Mode BSS. event:%d status:%d reason:%d\n",
15582 ndev
->name
, ntoh32(e
->event_type
),
15583 ntoh32(e
->status
), ntoh32(e
->reason
)));
15585 if (!wl_get_drv_status(cfg
, CFG80211_CONNECT
, ndev
)) {
15586 /* Join attempt via non-cfg80211 interface.
15587 * Don't send resultant events to cfg80211
15590 WL_INFORM_MEM(("Event received in non-cfg80211"
15591 " connect state. Ignore\n"));
15594 #ifdef WL_CLIENT_SAE
15595 if (event
== WLC_E_AUTH
)
15596 wl_notify_connect_status_bss(cfg
, ndev
, e
, data
);
15597 #endif /* WL_CLIENT_SAE */
15599 if (event
== WLC_E_ASSOC
|| event
== WLC_E_AUTH
) {
15600 wl_get_auth_assoc_status(cfg
, ndev
, e
, data
);
15603 if (event
== WLC_E_ASSOC_RESP_IE
) {
15604 if (ntoh32(e
->status
) != WLC_E_STATUS_SUCCESS
) {
15605 wl_cache_assoc_resp_ies(cfg
, ndev
, e
, data
);
15610 DHD_DISABLE_RUNTIME_PM((dhd_pub_t
*)cfg
->pub
);
15612 if (wl_is_linkup(cfg
, e
, ndev
)) {
15615 if (!wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
15616 WL_INFORM_MEM(("[%s] link up for bssid " MACDBG
"\n",
15617 ndev
->name
, MAC2STRDBG((const u8
*)(&e
->addr
))));
15618 if ((event
== WLC_E_LINK
) &&
15619 (ntoh16(e
->flags
) & WLC_EVENT_MSG_LINK
) &&
15620 !wl_get_drv_status(cfg
, CONNECTED
, ndev
) &&
15621 !wl_get_drv_status(cfg
, CONNECTING
, ndev
)) {
15622 WL_INFORM_MEM(("link up in non-connected/"
15623 "non-connecting state\n"));
15624 wl_cfg80211_disassoc(ndev
, WLAN_REASON_DEAUTH_LEAVING
);
15629 /* Avoid invocation for Roam cases */
15630 if ((event
== WLC_E_LINK
) &&
15631 !wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
15632 wl_wps_session_update(ndev
,
15633 WPS_STATE_LINKUP
, e
->addr
.octet
);
15635 #endif /* WL_WPS_SYNC */
15637 #ifdef DHD_EVENT_LOG_FILTER
15638 if (event
== WLC_E_LINK
&& ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
15640 uint8 eth_addr
[ETHER_ADDR_LEN
];
15642 #ifdef DHD_LOSSLESS_ROAMING
15643 !cfg
->roam_offload
&&
15644 #endif /* DHD_LOSSLESS_ROAMING */
15645 wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
15648 memcpy(eth_addr
, &(e
->addr
), ETHER_ADDR_LEN
);
15649 dhd_event_log_filter_notify_connect_done(dhdp
,
15652 #endif /* DHD_EVENT_LOG_FILTER */
15653 if (event
== WLC_E_LINK
&&
15654 #ifdef DHD_LOSSLESS_ROAMING
15655 !cfg
->roam_offload
&&
15656 !IS_AKM_SUITE_FT(sec
) &&
15657 #endif /* DHD_LOSSLESS_ROAMING */
15658 wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
15659 wl_bss_roaming_done(cfg
, ndev
, e
, data
);
15660 /* Arm pkt logging timer */
15661 dhd_dump_mod_pkt_timer(dhdp
, PKT_CNT_RSN_ROAM
);
15663 /* Initial Association */
15664 wl_update_prof(cfg
, ndev
, e
, &act
, WL_PROF_ACT
);
15665 #ifdef ESCAN_CHANNEL_CACHE
15666 /* Update RCC list in linkup, FW clears RCC in join path */
15667 wl_update_rcc_list(ndev
);
15668 #endif /* ESCAN_CHANNEL_CACHE */
15669 wl_bss_connect_done(cfg
, ndev
, e
, data
, true);
15670 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
15671 vndr_oui_num
= wl_vndr_ies_get_vendor_oui(cfg
,
15672 ndev
, vndr_oui
, ARRAY_SIZE(vndr_oui
));
15673 if (vndr_oui_num
> 0) {
15674 WL_INFORM_MEM(("[%s] vendor oui: %s\n",
15675 ndev
->name
, vndr_oui
));
15678 if (event
== WLC_E_LINK
) {
15679 /* Arm pkt logging timer */
15680 dhd_dump_mod_pkt_timer(dhdp
, PKT_CNT_RSN_CONNECT
);
15682 WL_DBG(("joined in BSS network \"%s\"\n",
15683 ((struct wlc_ssid
*)wl_read_prof(cfg
, ndev
,
15684 WL_PROF_SSID
))->SSID
));
15687 if (ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
&&
15688 dhdp
->wbtext_support
&& event
== WLC_E_SET_SSID
) {
15689 /* set wnm_keepalives_max_idle after association */
15690 wl_cfg80211_wbtext_set_wnm_maxidle(cfg
, ndev
);
15692 #endif /* WBTEXT */
15694 wl_update_prof(cfg
, ndev
, e
, &act
, WL_PROF_ACT
);
15695 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&e
->addr
, WL_PROF_BSSID
);
15697 } else if (wl_is_linkdown(cfg
, e
) ||
15698 ((event
== WLC_E_SET_SSID
) &&
15699 (ntoh32(e
->status
) != WLC_E_STATUS_SUCCESS
) &&
15700 (wl_get_drv_status(cfg
, CONNECTED
, ndev
)))) {
15701 if (wl_is_linkdown(cfg
, e
)) {
15702 /* Clear IEs for disaasoc */
15703 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
,
15704 ndev
->ieee80211_ptr
)) < 0) {
15705 WL_ERR(("Find index failed\n"));
15707 WL_ERR(("link down--clearing disconnect IEs\n"));
15708 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
,
15709 ndev_to_cfgdev(ndev
), bssidx
, VNDR_IE_DISASSOC_FLAG
,
15710 NULL
, 0)) != BCME_OK
) {
15711 WL_ERR(("Failed to clear ies err = %d\n", err
));
15715 wl_android_get_roam_scan_chanlist(cfg
);
15716 #endif /* WL_GET_RCC */
15718 if (cfg
->ncho_mode
) {
15719 wl_android_set_ncho_mode(ndev
, OFF
);
15721 #endif /* WES_SUPPORT */
15724 WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n",
15725 wl_get_drv_status(cfg
, CONNECTING
, ndev
),
15726 wl_get_drv_status(cfg
, CONNECTED
, ndev
),
15727 wl_get_drv_status(cfg
, DISCONNECTING
, ndev
),
15728 wl_get_drv_status(cfg
, NESTED_CONNECT
, ndev
)));
15730 /* clear timestamps on disconnect */
15731 CLR_TS(cfg
, conn_start
);
15732 CLR_TS(cfg
, conn_cmplt
);
15733 CLR_TS(cfg
, authorize_start
);
15734 CLR_TS(cfg
, authorize_cmplt
);
15738 if ((event
== WLC_E_SET_SSID
) &&
15739 (ntoh32(e
->status
) != WLC_E_STATUS_SUCCESS
)) {
15741 wps_state
= WPS_STATE_CONNECT_FAIL
;
15743 wps_state
= WPS_STATE_LINKDOWN
;
15745 if (wl_wps_session_update(ndev
,
15746 wps_state
, e
->addr
.octet
) == BCME_UNSUPPORTED
) {
15747 /* Unexpected event. Ignore it. */
15751 #endif /* WL_WPS_SYNC */
15753 if (wl_get_drv_status(cfg
, DISCONNECTING
, ndev
) &&
15754 (wl_get_drv_status(cfg
, NESTED_CONNECT
, ndev
) ||
15755 wl_get_drv_status(cfg
, CONNECTING
, ndev
))) {
15756 /* wl_cfg80211_connect was called before 'DISCONNECTING' was
15757 * cleared. Deauth/Link down event is caused by WLC_DISASSOC
15758 * command issued from the wl_cfg80211_connect context. Ignore
15759 * the event to avoid pre-empting the current connection
15761 WL_DBG(("Nested connection case. Drop event. \n"));
15762 wl_cfg80211_check_in4way(cfg
, ndev
, NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
|WAIT_DISCONNECTED
,
15763 WL_EXT_STATUS_DISCONNECTED
, NULL
);
15764 wl_clr_drv_status(cfg
, NESTED_CONNECT
, ndev
);
15765 wl_clr_drv_status(cfg
, DISCONNECTING
, ndev
);
15766 /* Not in 'CONNECTED' state, clear it */
15767 wl_clr_drv_status(cfg
, CONNECTED
, ndev
);
15771 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
15772 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg
),
15773 FW_LOGSET_MASK_ALL
);
15775 #ifdef DHD_LOSSLESS_ROAMING
15776 wl_del_roam_timeout(cfg
);
15778 #ifdef P2PLISTEN_AP_SAMECHN
15779 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
15780 wl_cfg80211_set_p2p_resp_ap_chn(ndev
, 0);
15781 cfg
->p2p_resp_apchn_status
= false;
15782 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
15784 #endif /* P2PLISTEN_AP_SAMECHN */
15786 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
15787 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
15788 wl_get_bss_info(cfg
, ndev
, &e
->addr
);
15790 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
15792 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
15793 u8
*curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
15794 if (memcmp(curbssid
, &e
->addr
, ETHER_ADDR_LEN
) != 0) {
15795 bool fw_assoc_state
= TRUE
;
15796 dhd_pub_t
*dhd
= (dhd_pub_t
*)cfg
->pub
;
15797 fw_assoc_state
= dhd_is_associated(dhd
, e
->ifidx
, &err
);
15798 if (!fw_assoc_state
) {
15799 WL_ERR(("Event sends up even different BSSID"
15800 " cur: " MACDBG
" event: " MACDBG
"\n",
15801 MAC2STRDBG(curbssid
),
15802 MAC2STRDBG((const u8
*)(&e
->addr
))));
15804 WL_ERR(("BSSID of event is not the connected BSSID"
15805 "(ignore it) cur: " MACDBG
15806 " event: " MACDBG
"\n",
15807 MAC2STRDBG(curbssid
),
15808 MAC2STRDBG((const u8
*)(&e
->addr
))));
15813 /* Explicitly calling unlink to remove BSS in CFG */
15814 wiphy
= bcmcfg_to_wiphy(cfg
);
15815 ssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, ndev
, WL_PROF_SSID
);
15816 bssid
= (u8
*)wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
15817 if (ssid
&& bssid
) {
15818 bss
= CFG80211_GET_BSS(wiphy
, NULL
, bssid
,
15819 ssid
->SSID
, ssid
->SSID_len
);
15821 cfg80211_unlink_bss(wiphy
, bss
);
15822 CFG80211_PUT_BSS(wiphy
, bss
);
15826 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
15828 u8
*curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
15830 struct ether_addr bssid_dongle
= {{0, 0, 0, 0, 0, 0}};
15831 struct ether_addr bssid_null
= {{0, 0, 0, 0, 0, 0}};
15833 wl_cfg80211_cancel_scan(cfg
);
15834 if (event
== WLC_E_DEAUTH_IND
|| event
== WLC_E_DISASSOC_IND
) {
15835 reason
= ntoh32(e
->reason
);
15836 /* Specific AP send deauth by invalid reason.
15837 * If reason over 0x8XXX, framework trigger recovery.
15838 * Framework check HANG_REASON_MASK(0x8000) with reason.
15840 if (reason
> WLC_E_DEAUTH_MAX_REASON
) {
15841 WL_ERR(("Event %d original reason is %d, "
15842 "changed 0xFF\n", event
, reason
));
15843 reason
= WLC_E_DEAUTH_MAX_REASON
;
15845 wl_cfg80211_handle_deauth_ind(cfg
, ndev
, e
, data
);
15847 #ifdef SET_SSID_FAIL_CUSTOM_RC
15848 if ((event
== WLC_E_SET_SSID
) &&
15849 (ntoh32(e
->status
) == WLC_E_STATUS_TIMEOUT
)) {
15850 reason
= SET_SSID_FAIL_CUSTOM_RC
;
15852 #endif /* SET_SSID_FAIL_CUSTOM_RC */
15853 #if defined(CONFIG_TIZEN)
15854 net_stat_tizen_update_wifi(ndev
, WIFISTAT_DISCONNECTION
);
15855 #endif /* CONFIG_TIZEN */
15857 /* roam offload does not sync BSSID always, get it from dongle */
15858 if (cfg
->roam_offload
) {
15859 bzero(&bssid_dongle
, sizeof(bssid_dongle
));
15860 if (wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid_dongle
,
15861 sizeof(bssid_dongle
)) == BCME_OK
) {
15862 /* if not roam case, it would return null bssid */
15863 if (memcmp(&bssid_dongle
, &bssid_null
,
15864 ETHER_ADDR_LEN
) != 0) {
15865 curbssid
= (u8
*)&bssid_dongle
;
15869 if (memcmp(curbssid
, &e
->addr
, ETHER_ADDR_LEN
) != 0) {
15870 bool fw_assoc_state
= TRUE
;
15871 dhd_pub_t
*dhd
= (dhd_pub_t
*)cfg
->pub
;
15872 fw_assoc_state
= dhd_is_associated(dhd
, e
->ifidx
, &err
);
15873 if (!fw_assoc_state
) {
15874 WL_ERR(("Event sends up even different BSSID"
15875 " cur: " MACDBG
" event: " MACDBG
"\n",
15876 MAC2STRDBG(curbssid
),
15877 MAC2STRDBG((const u8
*)(&e
->addr
))));
15879 WL_ERR(("BSSID of event is not the connected BSSID"
15880 "(ignore it) cur: " MACDBG
15881 " event: " MACDBG
"\n",
15882 MAC2STRDBG(curbssid
),
15883 MAC2STRDBG((const u8
*)(&e
->addr
))));
15888 /* Stop packet monitor */
15889 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
15890 DHD_DBG_PKT_MON_STOP(dhdp
);
15892 #endif /* DBG_PKT_MON */
15893 /* clear RSSI monitor, framework will set new cfg */
15894 #ifdef RSSI_MONITOR_SUPPORT
15895 dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg
),
15897 #endif /* RSSI_MONITOR_SUPPORT */
15898 if (dhdp
->conf
->eapol_status
== EAPOL_STATUS_4WAY_DONE
&&
15899 !memcmp(ndev
->name
, WL_P2P_INTERFACE_PREFIX
, strlen(WL_P2P_INTERFACE_PREFIX
))) {
15900 // terence 20130703: Fix for wrong group_capab (timing issue)
15901 cfg
->p2p_disconnected
= 1;
15903 memcpy(&cfg
->disconnected_bssid
, curbssid
, ETHER_ADDR_LEN
);
15904 wl_clr_drv_status(cfg
, CONNECTED
, ndev
);
15906 if (!wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
15907 DHD_STATLOG_CTRL(dhdp
, ST(DISASSOC_INT_START
),
15908 dhd_net2idx(dhdp
->info
, ndev
),
15909 WLAN_REASON_DEAUTH_LEAVING
);
15910 /* To make sure disconnect, explictly send dissassoc
15911 * for BSSID 00:00:00:00:00:00 issue
15913 scbval
.val
= WLAN_REASON_DEAUTH_LEAVING
;
15914 WL_INFORM_MEM(("clear fw state\n"));
15915 memcpy(&scbval
.ea
, curbssid
, ETHER_ADDR_LEN
);
15916 scbval
.val
= htod32(scbval
.val
);
15917 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, &scbval
,
15918 sizeof(scb_val_t
));
15920 WL_ERR(("WLC_DISASSOC error %d\n", err
));
15924 if (wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
15927 WL_INFORM_MEM(("[%s] Indicate disconnect event to upper layer. "
15928 "event: %d reason=%d from " MACDBG
"\n",
15929 ndev
->name
, event
, ntoh32(e
->reason
),
15930 MAC2STRDBG((const u8
*)(&e
->addr
))));
15933 /* when STA was disconnected, clear join pref and set wbtext */
15934 if (ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
&&
15935 dhdp
->wbtext_policy
15936 == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT
) {
15937 char smbuf
[WLC_IOCTL_SMLEN
];
15938 if ((err
= wldev_iovar_setbuf(ndev
, "join_pref",
15940 sizeof(smbuf
), NULL
))
15942 if ((err
= wldev_iovar_setint(ndev
,
15943 "wnm_bsstrans_resp",
15944 dhdp
->wbtext_policy
))
15946 wl_cfg80211_wbtext_set_default(ndev
);
15948 WL_ERR(("wl_notify_connect_status:"
15950 " set wbtext = %d\n",
15954 WL_ERR(("wl_notify_connect_status:"
15955 " Failed to clear join pref = %d\n",
15958 wl_cfg80211_wbtext_clear_bssid_list(cfg
);
15960 #endif /* WBTEXT */
15961 DHD_STATLOG_CTRL(dhdp
, ST(DISASSOC_DONE
),
15962 dhd_net2idx(dhdp
->info
, ndev
), reason
);
15963 /* Send up deauth and clear states */
15966 * FW sends body and body len as a part of deauth
15967 * and disassoc events (WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND)
15968 * The VIEs sits after reason code in the body. Reason code is
15971 WL_DBG(("recv disconnect ies ie_len = %d\n", ie_len
));
15972 if (event
== WLC_E_DISASSOC_IND
|| event
== WLC_E_DEAUTH_IND
) {
15973 if ((datalen
> DOT11_DISCONNECT_RC
) &&
15974 datalen
< (VNDR_IE_MAX_LEN
+ DOT11_DISCONNECT_RC
) &&
15976 ie_ptr
= (uchar
*)data
+ DOT11_DISCONNECT_RC
;
15977 ie_len
= datalen
- DOT11_DISCONNECT_RC
;
15979 } else if (event
== WLC_E_LINK
&&
15980 ntoh32(e
->reason
) == WLC_E_LINK_BCN_LOSS
) {
15981 #ifdef WL_ANALYTICS
15982 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
15983 if (wl_vndr_ies_find_vendor_oui(cfg
, ndev
,
15984 CISCO_AIRONET_OUI
)) {
15985 WL_INFORM_MEM(("Analytics Beacon loss\n"));
15986 ie_ptr
= (uchar
*)disco_bcnloss_vsie
;
15987 ie_len
= sizeof(disco_bcnloss_vsie
);
15990 #endif /* WL_ANALYTICS */
15992 #if defined(DHDTCPSYNC_FLOOD_BLK) && defined(CUSTOMER_TCPSYNC_FLOOD_DIS_RC)
15993 ifp
= dhd_get_ifp(dhdp
, e
->ifidx
);
15994 if (ifp
&& ifp
->disconnect_tsync_flood
) {
15995 reason
= CUSTOMER_TCPSYNC_FLOOD_DIS_RC
;
15997 #endif /* DHDTCPSYNC_FLOOD_BLK && CUSTOMER_TCPSYNC_FLOOD_DIS_RC */
15998 CFG80211_DISCONNECTED(ndev
, reason
, ie_ptr
, ie_len
,
15999 loc_gen
, GFP_KERNEL
);
16000 WL_INFORM_MEM(("[%s] Disconnect event sent to upper layer"
16001 "event:%d e->reason=%d reason=%d ie_len=%d "
16002 "from " MACDBG
"\n",
16003 ndev
->name
, event
, ntoh32(e
->reason
), reason
, ie_len
,
16004 MAC2STRDBG((const u8
*)(&e
->addr
))));
16006 /* Wait for status to be cleared to prevent race condition
16007 * issues with connect context
16010 wl_init_prof(cfg
, ndev
);
16011 wl_clr_drv_status(cfg
, AUTHORIZED
, ndev
);
16012 CLR_TS(cfg
, authorize_start
);
16013 CLR_TS(cfg
, authorize_cmplt
);
16014 CLR_TS(cfg
, conn_start
);
16015 CLR_TS(cfg
, conn_cmplt
);
16017 else if (wl_get_drv_status(cfg
, CONNECTING
, ndev
)) {
16018 #ifdef ESCAN_RESULT_PATCH
16019 u8
*conn_req_bssid
= wl_read_prof(cfg
, ndev
, WL_PROF_LATEST_BSSID
);
16020 #endif /* ESCAN_RESULT_PATCH */
16021 DHD_STATLOG_CTRL(dhdp
, ST(DISASSOC_INT_START
),
16022 dhd_net2idx(dhdp
->info
, ndev
), 0);
16023 WL_INFORM_MEM(("link down, during connecting\n"));
16024 /* Issue WLC_DISASSOC to prevent FW roam attempts.
16025 * Do not issue WLC_DISASSOC again if the linkdown is
16026 * generated due to local disassoc, to avoid connect-disconnect
16029 if (!((event
== WLC_E_LINK
) &&
16030 (ntoh32(e
->reason
) == WLC_E_LINK_DISASSOC
) &&
16031 (ntoh32(e
->status
) == WLC_E_STATUS_SUCCESS
))) {
16032 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, NULL
, 0);
16034 WL_ERR(("CONNECTING state,"
16035 " WLC_DISASSOC error %d\n",
16039 #ifdef ESCAN_RESULT_PATCH
16040 if (conn_req_bssid
&& (ETHER_ISNULLADDR(conn_req_bssid
) ||
16041 ETHER_ISNULLADDR(&e
->addr
) ||
16042 (memcmp(&e
->addr
, conn_req_bssid
,
16043 ETHER_ADDR_LEN
) == 0)))
16044 /* In case this event comes while associating
16047 #endif /* ESCAN_RESULT_PATCH */
16048 wl_bss_connect_done(cfg
, ndev
, e
, data
, false);
16051 wl_clr_drv_status(cfg
, DISCONNECTING
, ndev
);
16052 wl_cfg80211_check_in4way(cfg
, ndev
, NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
|WAIT_DISCONNECTED
,
16053 WL_EXT_STATUS_DISCONNECTED
, NULL
);
16055 /* if link down, bsscfg is diabled */
16056 if (ndev
!= bcmcfg_to_prmry_ndev(cfg
))
16057 complete(&cfg
->iface_disable
);
16059 /* re-enable TDLS if the number of connected interfaces
16062 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_DISCONNECT
, false);
16063 #endif /* WLTDLS */
16064 } else if (wl_is_nonetwork(cfg
, e
)) {
16065 WL_ERR(("connect failed event=%d e->status %d e->reason %d \n",
16066 event
, (int)ntoh32(e
->status
), (int)ntoh32(e
->reason
)));
16067 #if defined(CONFIG_TIZEN)
16068 net_stat_tizen_update_wifi(ndev
, WIFISTAT_CONNECTION_FAIL
);
16069 #endif /* CONFIG_TIZEN */
16070 wl_cfg80211_check_in4way(cfg
, ndev
, NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
|WAIT_DISCONNECTED
,
16071 WL_EXT_STATUS_DISCONNECTED
, NULL
);
16073 if (wl_wps_session_update(ndev
,
16074 WPS_STATE_CONNECT_FAIL
, e
->addr
.octet
) == BCME_UNSUPPORTED
) {
16075 /* Unexpected event. Ignore it. */
16078 #endif /* WL_WPS_SYNC */
16079 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
16080 if (event
== WLC_E_SET_SSID
) {
16081 wl_get_connect_failed_status(cfg
, e
);
16083 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
16084 /* Dump FW preserve buffer content */
16085 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
16087 /* Clean up any pending scan request */
16088 wl_cfg80211_cancel_scan(cfg
);
16090 if (wl_get_drv_status(cfg
, CONNECTING
, ndev
)) {
16091 if (!wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
16092 WL_INFORM_MEM(("wl dissassoc\n"));
16093 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, NULL
, 0);
16095 WL_ERR(("WLC_DISASSOC error %d\n", err
));
16099 WL_DBG(("connect fail. clear disconnecting bit\n"));
16100 wl_clr_drv_status(cfg
, DISCONNECTING
, ndev
);
16102 wl_bss_connect_done(cfg
, ndev
, e
, data
, false);
16103 wl_clr_drv_status(cfg
, CONNECTING
, ndev
);
16104 WL_INFORM_MEM(("connect fail reported\n"));
16107 WL_DBG(("%s nothing\n", __FUNCTION__
));
16110 DHD_ENABLE_RUNTIME_PM((dhd_pub_t
*)cfg
->pub
);
16113 WL_MSG(ndev
->name
, "Invalid mode %d event %d status %d\n",
16114 wl_get_mode_by_netdev(cfg
, ndev
), ntoh32(e
->event_type
),
16115 ntoh32(e
->status
));
16121 void wl_cfg80211_set_rmc_pid(struct net_device
*dev
, int pid
)
16123 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
16125 cfg
->rmc_event_pid
= pid
;
16126 WL_DBG(("set pid for rmc event : pid=%d\n", pid
));
16128 #endif /* WL_RELMCAST */
16131 void wl_cfg80211_set_txfail_pid(struct net_device
*dev
, int pid
)
16133 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
16135 cfg
->aibss_txfail_pid
= pid
;
16136 WL_DBG(("set pid for aibss fail event : pid=%d\n", pid
));
16140 wl_notify_aibss_txfail(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
16141 const wl_event_msg_t
*e
, void *data
)
16143 u32 evt
= ntoh32(e
->event_type
);
16145 #ifdef PCIE_FULL_DONGLE
16146 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
16147 u32 reason
= ntoh32(e
->reason
);
16149 if (cfg
->aibss_txfail_pid
!= 0) {
16150 #ifdef PCIE_FULL_DONGLE
16151 if (reason
== AIBSS_PEER_FREE
) {
16153 wl_event_msg_t event
;
16155 bzero(&event
, sizeof(wl_event_msg_t
));
16156 memcpy(&event
, e
, sizeof(wl_event_msg_t
));
16158 ifindex
= (uint8
)dhd_ifname2idx(dhd
->info
, event
.ifname
);
16159 WL_INFORM_MEM(("Peer freed. Flow rings delete for peer.\n"));
16160 dhd_flow_rings_delete_for_peer(dhd
, ifindex
,
16161 (void *)&event
.addr
.octet
[0]);
16165 ret
= wl_netlink_send_msg(cfg
->aibss_txfail_pid
, AIBSS_EVENT_TXFAIL
,
16166 cfg
->aibss_txfail_seq
++, &e
->addr
, ETHER_ADDR_LEN
);
16169 WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF
"\n",
16170 evt
, cfg
->aibss_txfail_pid
, ret
, CONST_ETHERP_TO_MACF(&e
->addr
)));
16173 #endif /* WLAIBSS */
16176 wl_notify_rmc_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
16177 const wl_event_msg_t
*e
, void *data
)
16179 u32 evt
= ntoh32(e
->event_type
);
16180 u32 reason
= ntoh32(e
->reason
);
16184 case WLC_E_REASON_RMC_AR_LOST
:
16185 case WLC_E_REASON_RMC_AR_NO_ACK
:
16186 if (cfg
->rmc_event_pid
!= 0) {
16187 ret
= wl_netlink_send_msg(cfg
->rmc_event_pid
,
16188 RMC_EVENT_LEADER_CHECK_FAIL
,
16189 cfg
->rmc_event_seq
++, NULL
, 0);
16195 WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt
, cfg
->rmc_event_pid
, ret
));
16198 #endif /* WL_RELMCAST */
16200 #ifdef GSCAN_SUPPORT
16202 wl_handle_roam_exp_event(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
16203 const wl_event_msg_t
*e
, void *data
)
16205 struct net_device
*ndev
= NULL
;
16206 u32 datalen
= be32_to_cpu(e
->datalen
);
16209 wl_roam_exp_event_t
*evt_data
= (wl_roam_exp_event_t
*)data
;
16210 if (evt_data
->version
== ROAM_EXP_EVENT_VERSION
) {
16211 wlc_ssid_t
*ssid
= &evt_data
->cur_ssid
;
16212 struct wireless_dev
*wdev
;
16213 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
16215 wdev
= ndev
->ieee80211_ptr
;
16216 wdev
->ssid_len
= min(ssid
->SSID_len
, (uint32
)DOT11_MAX_SSID_LEN
);
16217 memcpy(wdev
->ssid
, ssid
->SSID
, wdev
->ssid_len
);
16218 WL_ERR(("SSID is %s\n", ssid
->SSID
));
16219 wl_update_prof(cfg
, ndev
, NULL
, ssid
, WL_PROF_SSID
);
16221 WL_ERR(("NULL ndev!\n"));
16224 WL_ERR(("Version mismatch %d, expected %d", evt_data
->version
,
16225 ROAM_EXP_EVENT_VERSION
));
16230 #endif /* GSCAN_SUPPORT */
16232 #ifdef RSSI_MONITOR_SUPPORT
16233 static s32
wl_handle_rssi_monitor_event(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
16234 const wl_event_msg_t
*e
, void *data
)
16237 #if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
16238 u32 datalen
= be32_to_cpu(e
->datalen
);
16239 struct net_device
*ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
16240 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
16243 wl_rssi_monitor_evt_t
*evt_data
= (wl_rssi_monitor_evt_t
*)data
;
16244 if (evt_data
->version
== RSSI_MONITOR_VERSION
) {
16245 dhd_rssi_monitor_evt_t monitor_data
;
16246 monitor_data
.version
= DHD_RSSI_MONITOR_EVT_VERSION
;
16247 monitor_data
.cur_rssi
= evt_data
->cur_rssi
;
16248 memcpy(&monitor_data
.BSSID
, &e
->addr
, ETHER_ADDR_LEN
);
16249 wl_cfgvendor_send_async_event(wiphy
, ndev
,
16250 GOOGLE_RSSI_MONITOR_EVENT
,
16251 &monitor_data
, sizeof(monitor_data
));
16253 WL_ERR(("Version mismatch %d, expected %d", evt_data
->version
,
16254 RSSI_MONITOR_VERSION
));
16257 #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
16260 #endif /* RSSI_MONITOR_SUPPORT */
16263 wl_notify_roaming_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
16264 const wl_event_msg_t
*e
, void *data
)
16267 struct net_device
*ndev
= NULL
;
16269 u32 event
= be32_to_cpu(e
->event_type
);
16270 u32 status
= be32_to_cpu(e
->status
);
16271 #ifdef DHD_LOSSLESS_ROAMING
16272 struct wl_security
*sec
;
16274 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
16275 WL_DBG(("Enter \n"));
16277 BCM_REFERENCE(dhdp
);
16278 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
16280 if ((!cfg
->disable_roam_event
) && (event
== WLC_E_BSSID
)) {
16282 wl_add_remove_eventmsg(ndev
, WLC_E_ROAM
, false);
16284 cfg
->disable_roam_event
= TRUE
;
16287 if ((cfg
->disable_roam_event
) && (event
== WLC_E_ROAM
))
16290 if ((event
== WLC_E_ROAM
|| event
== WLC_E_BSSID
) && status
== WLC_E_STATUS_SUCCESS
) {
16291 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
16292 #ifdef DHD_LOSSLESS_ROAMING
16293 sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
16294 /* In order to reduce roaming delay, wl_bss_roaming_done is
16295 * early called with WLC_E_LINK event. It is called from
16296 * here only if WLC_E_LINK event is blocked for specific
16299 if (IS_AKM_SUITE_FT(sec
)) {
16300 wl_bss_roaming_done(cfg
, ndev
, e
, data
);
16301 /* Arm pkt logging timer */
16302 dhd_dump_mod_pkt_timer(dhdp
, PKT_CNT_RSN_ROAM
);
16304 /* Roam timer is deleted mostly from wl_cfg80211_change_station
16305 * after roaming is finished successfully. We need to delete
16306 * the timer from here only for some security types that aren't
16307 * using wl_cfg80211_change_station to authorize SCB
16309 if (IS_AKM_SUITE_FT(sec
) || IS_AKM_SUITE_CCKM(sec
)) {
16310 wl_del_roam_timeout(cfg
);
16313 #if !defined(DHD_NONFT_ROAMING)
16314 wl_bss_roaming_done(cfg
, ndev
, e
, data
);
16315 #endif /* !DHD_NONFT_ROAMING */
16316 #endif /* DHD_LOSSLESS_ROAMING */
16318 if (dhdp
->wbtext_support
) {
16319 /* set wnm_keepalives_max_idle after association */
16320 wl_cfg80211_wbtext_set_wnm_maxidle(cfg
, ndev
);
16322 /* Mostly nbr request of BTM query will be handled
16323 * from wl_cfg80211_change_station
16324 * after key negotiation is finished.
16325 * This part is only for some specific security
16326 * types (FT, CCKM) that don't call
16327 * wl_cfg80211_change_station after roaming
16329 if (IS_AKM_SUITE_FT(sec
) || IS_AKM_SUITE_CCKM(sec
)) {
16330 /* send nbr request or BTM query to update RCC
16331 * after roaming completed
16333 wl_cfg80211_wbtext_update_rcc(cfg
, ndev
);
16336 #endif /* WBTEXT */
16338 wl_bss_connect_done(cfg
, ndev
, e
, data
, true);
16341 wl_update_prof(cfg
, ndev
, e
, &act
, WL_PROF_ACT
);
16342 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&e
->addr
, WL_PROF_BSSID
);
16344 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
16345 wl_vndr_ies_get_vendor_oui(cfg
, ndev
, NULL
, 0);
16348 #ifdef DHD_LOSSLESS_ROAMING
16349 else if ((event
== WLC_E_ROAM
|| event
== WLC_E_BSSID
) && status
!= WLC_E_STATUS_SUCCESS
) {
16350 wl_del_roam_timeout(cfg
);
16356 #ifdef CUSTOM_EVENT_PM_WAKE
16357 uint32 last_dpm_upd_time
= 0; /* ms */
16358 #define DPM_UPD_LMT_TIME ((CUSTOM_EVENT_PM_WAKE + (5)) * (1000) * (4)) /* ms */
16359 #define DPM_UPD_LMT_RSSI -85 /* dbm */
16362 wl_check_pmstatus(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
16363 const wl_event_msg_t
*e
, void *data
)
16366 struct net_device
*ndev
= NULL
;
16368 uint32 cur_dpm_upd_time
= 0;
16369 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
16371 #ifdef SUPPORT_RSSI_SUM_REPORT
16372 wl_rssi_ant_mimo_t rssi_ant_mimo
;
16373 #endif /* SUPPORT_RSSI_SUM_REPORT */
16374 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
16376 pbuf
= (u8
*)MALLOCZ(cfg
->osh
, WLC_IOCTL_MEDLEN
);
16377 if (pbuf
== NULL
) {
16378 WL_ERR(("failed to allocate local pbuf\n"));
16382 err
= wldev_iovar_getbuf_bsscfg(ndev
, "dump",
16383 "pm", strlen("pm"), pbuf
, WLC_IOCTL_MEDLEN
,
16384 0, &cfg
->ioctl_buf_sync
);
16387 WL_ERR(("dump ioctl err = %d", err
));
16389 WL_ERR(("PM status : %s\n", pbuf
));
16393 MFREE(cfg
->osh
, pbuf
, WLC_IOCTL_MEDLEN
);
16396 if (dhd
->early_suspended
) {
16398 #ifdef SUPPORT_RSSI_SUM_REPORT
16399 /* Query RSSI sum across antennas */
16400 memset(&rssi_ant_mimo
, 0, sizeof(rssi_ant_mimo
));
16401 err
= wl_get_rssi_per_ant(ndev
, ndev
->name
, NULL
, &rssi_ant_mimo
);
16403 WL_ERR(("Could not get rssi sum (%d)\n", err
));
16405 rssi
= rssi_ant_mimo
.rssi_sum
;
16407 #endif /* SUPPORT_RSSI_SUM_REPORT */
16410 memset(&scb_val
, 0, sizeof(scb_val_t
));
16412 err
= wldev_ioctl_get(ndev
, WLC_GET_RSSI
, &scb_val
, sizeof(scb_val_t
));
16414 WL_ERR(("Could not get rssi (%d)\n", err
));
16416 #if defined(RSSIOFFSET)
16417 rssi
= wl_update_rssi_offset(ndev
, dtoh32(scb_val
.val
));
16419 rssi
= dtoh32(scb_val
.val
);
16422 WL_ERR(("RSSI %d dBm\n", rssi
));
16423 if (rssi
> DPM_UPD_LMT_RSSI
) {
16431 if (last_dpm_upd_time
== 0) {
16432 last_dpm_upd_time
= OSL_SYSUPTIME();
16434 cur_dpm_upd_time
= OSL_SYSUPTIME();
16435 if (cur_dpm_upd_time
- last_dpm_upd_time
< DPM_UPD_LMT_TIME
) {
16437 DHD_STATLOG_CTRL(dhd
, ST(DISASSOC_INT_START
),
16438 dhd_net2idx(dhd
->info
, ndev
), 0);
16439 bzero(&scbval
, sizeof(scb_val_t
));
16441 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
,
16442 &scbval
, sizeof(scb_val_t
));
16444 WL_ERR(("Disassoc error %d\n", err
));
16447 WL_ERR(("Force Disassoc due to updated DPM event.\n"));
16449 last_dpm_upd_time
= 0;
16451 last_dpm_upd_time
= cur_dpm_upd_time
;
16457 #endif /* CUSTOM_EVENT_PM_WAKE */
16460 /* get user priority table */
16462 wl_get_up_table(dhd_pub_t
* dhdp
, int idx
)
16464 struct net_device
*ndev
;
16465 struct bcm_cfg80211
*cfg
;
16467 ndev
= dhd_idx2net(dhdp
, idx
);
16469 cfg
= wl_get_cfg(ndev
);
16471 return (uint8
*)(cfg
->up_table
);
16476 #endif /* QOS_MAP_SET */
16478 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
16480 * start packet logging in advance to make sure that EAPOL
16481 * messages are not missed during roaming
16484 wl_notify_roam_prep_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
16485 const wl_event_msg_t
*e
, void *data
)
16487 struct wl_security
*sec
;
16488 struct net_device
*ndev
;
16489 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
16490 u32 status
= ntoh32(e
->status
);
16491 u32 reason
= ntoh32(e
->reason
);
16493 BCM_REFERENCE(sec
);
16495 if (status
== WLC_E_STATUS_SUCCESS
&& reason
!= WLC_E_REASON_INITIAL_ASSOC
) {
16496 WL_ERR(("Attempting roam with reason code : %d\n", reason
));
16499 #ifdef CONFIG_SILENT_ROAM
16500 if (dhdp
->in_suspend
&& reason
== WLC_E_REASON_SILENT_ROAM
) {
16501 dhdp
->sroamed
= TRUE
;
16503 #endif /* CONFIG_SILENT_ROAM */
16505 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
16508 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
16509 DHD_DBG_PKT_MON_STOP(dhdp
);
16510 DHD_DBG_PKT_MON_START(dhdp
);
16512 #endif /* DBG_PKT_MON */
16513 #ifdef DHD_LOSSLESS_ROAMING
16514 sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
16515 /* Disable Lossless Roaming for specific AKM suite
16516 * Any other AKM suite can be added below if transition time
16517 * is delayed because of Lossless Roaming
16518 * and it causes any certication failure
16520 if (IS_AKM_SUITE_FT(sec
)) {
16524 dhdp
->dequeue_prec_map
= 1 << PRIO_8021D_NC
;
16525 /* Restore flow control */
16526 dhd_txflowcontrol(dhdp
, ALL_INTERFACES
, OFF
);
16528 mod_timer(&cfg
->roam_timeout
, jiffies
+ msecs_to_jiffies(WL_ROAM_TIMEOUT_MS
));
16529 #endif /* DHD_LOSSLESS_ROAMING */
16533 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
16536 wl_notify_roam_start_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
16537 const wl_event_msg_t
*e
, void *data
)
16539 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
16540 struct net_device
*ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
16541 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
16544 event_type
= WIFI_EVENT_ROAM_SCAN_STARTED
;
16545 wl_cfgvendor_send_async_event(wiphy
, ndev
, GOOGLE_ROAM_EVENT_START
,
16546 &event_type
, sizeof(int));
16547 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || (WL_VENDOR_EXT_SUPPORT) */
16552 static s32
wl_get_assoc_ies(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
16554 wl_assoc_info_t assoc_info
;
16555 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
16558 bcm_tlv_t
* qos_map_ie
= NULL
;
16559 #endif /* QOS_MAP_SET */
16561 WL_DBG(("Enter \n"));
16563 bzero(&assoc_info
, sizeof(wl_assoc_info_t
));
16564 err
= wldev_iovar_getbuf(ndev
, "assoc_info", NULL
, 0, cfg
->extra_buf
,
16565 WL_ASSOC_INFO_MAX
, NULL
);
16566 if (unlikely(err
)) {
16567 WL_ERR(("could not get assoc info (%d)\n", err
));
16570 memcpy(&assoc_info
, cfg
->extra_buf
, sizeof(wl_assoc_info_t
));
16571 assoc_info
.req_len
= htod32(assoc_info
.req_len
);
16572 assoc_info
.resp_len
= htod32(assoc_info
.resp_len
);
16573 assoc_info
.flags
= htod32(assoc_info
.flags
);
16574 if (conn_info
->req_ie_len
) {
16575 conn_info
->req_ie_len
= 0;
16576 bzero(conn_info
->req_ie
, sizeof(conn_info
->req_ie
));
16578 if (conn_info
->resp_ie_len
) {
16579 conn_info
->resp_ie_len
= 0;
16580 bzero(conn_info
->resp_ie
, sizeof(conn_info
->resp_ie
));
16583 if (assoc_info
.req_len
) {
16584 err
= wldev_iovar_getbuf(ndev
, "assoc_req_ies", NULL
, 0, cfg
->extra_buf
,
16585 assoc_info
.req_len
, NULL
);
16586 if (unlikely(err
)) {
16587 WL_ERR(("could not get assoc req (%d)\n", err
));
16590 if (assoc_info
.req_len
< sizeof(struct dot11_assoc_req
)) {
16591 WL_ERR(("req_len %d lessthan %d \n", assoc_info
.req_len
,
16592 (int)sizeof(struct dot11_assoc_req
)));
16593 return BCME_BADLEN
;
16595 conn_info
->req_ie_len
= (uint32
)(assoc_info
.req_len
16596 - sizeof(struct dot11_assoc_req
));
16597 if (assoc_info
.flags
& WLC_ASSOC_REQ_IS_REASSOC
) {
16598 conn_info
->req_ie_len
-= ETHER_ADDR_LEN
;
16600 if (conn_info
->req_ie_len
<= MAX_REQ_LINE
)
16601 memcpy(conn_info
->req_ie
, cfg
->extra_buf
, conn_info
->req_ie_len
);
16603 WL_ERR(("IE size %d above max %d size \n",
16604 conn_info
->req_ie_len
, MAX_REQ_LINE
));
16608 conn_info
->req_ie_len
= 0;
16611 if (assoc_info
.resp_len
) {
16612 err
= wldev_iovar_getbuf(ndev
, "assoc_resp_ies", NULL
, 0, cfg
->extra_buf
,
16613 assoc_info
.resp_len
, NULL
);
16614 if (unlikely(err
)) {
16615 WL_ERR(("could not get assoc resp (%d)\n", err
));
16618 if (assoc_info
.resp_len
< sizeof(struct dot11_assoc_resp
)) {
16619 WL_ERR(("resp_len %d is lessthan %d \n", assoc_info
.resp_len
,
16620 (int)sizeof(struct dot11_assoc_resp
)));
16621 return BCME_BADLEN
;
16623 conn_info
->resp_ie_len
= assoc_info
.resp_len
-
16624 (uint32
)sizeof(struct dot11_assoc_resp
);
16625 if (conn_info
->resp_ie_len
<= MAX_REQ_LINE
) {
16626 memcpy(conn_info
->resp_ie
, cfg
->extra_buf
, conn_info
->resp_ie_len
);
16628 WL_ERR(("IE size %d above max %d size \n",
16629 conn_info
->resp_ie_len
, MAX_REQ_LINE
));
16634 /* find qos map set ie */
16635 if ((qos_map_ie
= bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
16636 DOT11_MNG_QOS_MAP_ID
)) != NULL
) {
16637 WL_DBG((" QoS map set IE found in assoc response\n"));
16638 if (!cfg
->up_table
) {
16639 cfg
->up_table
= (uint8
*)MALLOC(cfg
->osh
, UP_TABLE_MAX
);
16641 wl_set_up_table(cfg
->up_table
, qos_map_ie
);
16643 MFREE(cfg
->osh
, cfg
->up_table
, UP_TABLE_MAX
);
16645 #endif /* QOS_MAP_SET */
16647 conn_info
->resp_ie_len
= 0;
16649 WL_DBG(("req len (%d) resp len (%d)\n", conn_info
->req_ie_len
,
16650 conn_info
->resp_ie_len
));
16655 static s32
wl_update_bss_info(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
16658 struct cfg80211_bss
*bss
;
16660 struct wlc_ssid
*ssid
;
16661 const struct bcm_tlv
*tim
;
16662 s32 beacon_interval
;
16668 struct wiphy
*wiphy
;
16671 chanspec_t chspec
= INVCHANSPEC
;
16673 wiphy
= bcmcfg_to_wiphy(cfg
);
16675 ssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, ndev
, WL_PROF_SSID
);
16676 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
16677 bss
= CFG80211_GET_BSS(wiphy
, NULL
, curbssid
,
16678 ssid
->SSID
, ssid
->SSID_len
);
16679 buf
= (char *)MALLOCZ(cfg
->osh
, WL_EXTRA_BUF_MAX
);
16681 WL_ERR(("buffer alloc failed.\n"));
16684 mutex_lock(&cfg
->usr_sync
);
16685 *(u32
*)buf
= htod32(WL_EXTRA_BUF_MAX
);
16686 err
= wldev_ioctl_get(ndev
, WLC_GET_BSS_INFO
, buf
, WL_EXTRA_BUF_MAX
);
16687 if (unlikely(err
)) {
16688 WL_ERR(("Could not get bss info %d\n", err
));
16689 goto update_bss_info_out
;
16691 bi
= (wl_bss_info_t
*)(buf
+ 4);
16692 chspec
= wl_chspec_driver_to_host(bi
->chanspec
);
16693 wl_update_prof(cfg
, ndev
, NULL
, &chspec
, WL_PROF_CHAN
);
16696 WL_DBG(("Could not find the AP\n"));
16697 if (memcmp(bi
->BSSID
.octet
, curbssid
, ETHER_ADDR_LEN
)) {
16698 WL_ERR(("Bssid doesn't match\n"));
16700 goto update_bss_info_out
;
16702 err
= wl_inform_single_bss(cfg
, bi
, update_ssid
);
16704 goto update_bss_info_out
;
16706 ie
= ((u8
*)bi
) + bi
->ie_offset
;
16707 ie_len
= bi
->ie_length
;
16708 beacon_interval
= cpu_to_le16(bi
->beacon_period
);
16711 WL_DBG(("Found the AP in the list - BSSID %pM\n", bss
->bssid
));
16712 channel
= wf_chspec_ctlchan(wl_chspec_driver_to_host(bi
->chanspec
));
16713 freq
= wl_channel_to_frequency(channel
, CHSPEC_BAND(bi
->chanspec
));
16714 bss
->channel
= ieee80211_get_channel(wiphy
, freq
);
16715 #if defined(WL_CFG80211_P2P_DEV_IF)
16716 ie
= (const u8
*)bss
->ies
->data
;
16717 ie_len
= bss
->ies
->len
;
16719 ie
= bss
->information_elements
;
16720 ie_len
= bss
->len_information_elements
;
16721 #endif /* WL_CFG80211_P2P_DEV_IF */
16722 beacon_interval
= bss
->beacon_interval
;
16724 CFG80211_PUT_BSS(wiphy
, bss
);
16727 tim
= bcm_parse_tlvs(ie
, ie_len
, WLAN_EID_TIM
);
16729 dtim_period
= tim
->data
[1];
16732 * active scan was done so we could not get dtim
16733 * information out of probe response.
16734 * so we speficially query dtim information.
16737 err
= wldev_ioctl_get(ndev
, WLC_GET_DTIMPRD
,
16738 &dtim_period
, sizeof(dtim_period
));
16739 if (unlikely(err
)) {
16740 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err
));
16741 goto update_bss_info_out
;
16745 wl_update_prof(cfg
, ndev
, NULL
, &beacon_interval
, WL_PROF_BEACONINT
);
16746 wl_update_prof(cfg
, ndev
, NULL
, &dtim_period
, WL_PROF_DTIMPERIOD
);
16748 update_bss_info_out
:
16749 if (unlikely(err
)) {
16750 WL_ERR(("Failed with error %d\n", err
));
16753 MFREE(cfg
->osh
, buf
, WL_EXTRA_BUF_MAX
);
16754 mutex_unlock(&cfg
->usr_sync
);
16759 wl_bss_roaming_done(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
16760 const wl_event_msg_t
*e
, void *data
)
16762 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
16765 chanspec_t
*chanspec
;
16767 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16768 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
16769 struct ieee80211_channel
*notify_channel
= NULL
;
16771 struct channel_info ci
;
16773 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16774 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16775 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
16776 defined(CFG80211_ROAM_API_GE_4_12)
16777 struct cfg80211_roam_info roam_info
;
16778 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
16779 #if defined(WL_FILS_ROAM_OFFLD)
16780 struct wl_fils_info
*fils_info
= wl_to_fils_info(cfg
);
16781 struct wl_security
*sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
16783 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
16784 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16785 dhd_if_t
*ifp
= NULL
;
16786 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
16788 uint32 data_len
= 0;
16790 data_len
= ntoh32(e
->datalen
);
16793 BCM_REFERENCE(dhdp
);
16794 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
16795 chanspec
= (chanspec_t
*)wl_read_prof(cfg
, ndev
, WL_PROF_CHAN
);
16796 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16797 /* Skip calling cfg80211_roamed If the channels are same and
16798 * the current bssid & the new bssid are same
16799 * Also clear timer roam_timeout.
16800 * Only used on BCM4359 devices.
16802 bzero(&ci
, sizeof(ci
));
16803 if ((wldev_ioctl_get(ndev
, WLC_GET_CHANNEL
, &ci
,
16804 sizeof(ci
))) < 0) {
16805 WL_ERR(("Failed to get current channel !"));
16809 cur_channel
= dtoh32(ci
.hw_channel
);
16810 if ((CHSPEC_CHANNEL(*chanspec
) == cur_channel
) && ((memcmp(curbssid
, &e
->addr
,
16811 ETHER_ADDR_LEN
) == 0) || (memcmp(&cfg
->last_roamed_addr
,
16812 &e
->addr
, ETHER_ADDR_LEN
) == 0))) {
16813 WL_DBG(("BSS already present, Skipping roamed event to"
16814 " upper layer\n"));
16817 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16819 if ((err
= wl_get_assoc_ies(cfg
, ndev
)) != BCME_OK
) {
16820 DHD_STATLOG_CTRL(dhdp
, ST(DISASSOC_INT_START
),
16821 dhd_net2idx(dhdp
->info
, ndev
), WLAN_REASON_DEAUTH_LEAVING
);
16822 WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
16823 " upper layer\n"));
16824 /* To make sure disconnect, and fw sync, explictly send dissassoc
16825 * for BSSID 00:00:00:00:00:00 issue
16827 bzero(&scbval
, sizeof(scb_val_t
));
16828 scbval
.val
= WLAN_REASON_DEAUTH_LEAVING
;
16829 memcpy(&scbval
.ea
, curbssid
, ETHER_ADDR_LEN
);
16830 scbval
.val
= htod32(scbval
.val
);
16831 if (wldev_ioctl_set(ndev
, WLC_DISASSOC
, &scbval
,
16832 sizeof(scb_val_t
)) < 0) {
16833 WL_ERR(("WLC_DISASSOC error\n"));
16838 wl_update_prof(cfg
, ndev
, NULL
, (const void *)(e
->addr
.octet
), WL_PROF_BSSID
);
16839 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
16840 if ((err
= wl_update_bss_info(cfg
, ndev
, true)) != BCME_OK
) {
16841 WL_ERR(("failed to update bss info, err=%d\n", err
));
16844 if (cfg
->wlc_ver
.wlc_ver_major
< PMKDB_WLC_VER
) {
16845 wl_update_pmklist(ndev
, cfg
->pmk_list
, err
);
16848 chanspec
= (chanspec_t
*)wl_read_prof(cfg
, ndev
, WL_PROF_CHAN
);
16849 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16850 /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
16851 freq
= wl_channel_to_frequency(wf_chspec_ctlchan(*chanspec
), CHSPEC_BAND(*chanspec
));
16852 notify_channel
= ieee80211_get_channel(wiphy
, freq
);
16853 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16855 /* back up the given FBT key for the further supplicant request,
16856 * currently not checking the FBT is enabled for current BSS in DHD,
16857 * because the supplicant decides to take it or not.
16859 if (data
&& (data_len
== FBT_KEYLEN
)) {
16860 memcpy(cfg
->fbt_key
, data
, FBT_KEYLEN
);
16863 #ifdef CUSTOM_LONG_RETRY_LIMIT
16864 if (wl_set_retry(ndev
, CUSTOM_LONG_RETRY_LIMIT
, 1) < 0) {
16865 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
16867 #endif /* CUSTOM_LONG_RETRY_LIMIT */
16868 DHD_STATLOG_CTRL(dhdp
, ST(REASSOC_INFORM
),
16869 dhd_net2idx(dhdp
->info
, ndev
), 0);
16870 WL_ERR(("Report roam event to upper layer. " MACDBG
" (ch:%d)\n",
16871 MAC2STRDBG((const u8
*)(&e
->addr
)), CHSPEC_CHANNEL(*chanspec
)));
16872 wl_cfg80211_check_in4way(cfg
, ndev
, 0, WL_EXT_STATUS_CONNECTED
, NULL
);
16874 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16875 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
16876 defined(CFG80211_ROAM_API_GE_4_12)
16877 memset(&roam_info
, 0, sizeof(struct cfg80211_roam_info
));
16878 roam_info
.channel
= notify_channel
;
16879 roam_info
.bssid
= curbssid
;
16880 roam_info
.req_ie
= conn_info
->req_ie
;
16881 roam_info
.req_ie_len
= conn_info
->req_ie_len
;
16882 roam_info
.resp_ie
= conn_info
->resp_ie
;
16883 roam_info
.resp_ie_len
= conn_info
->resp_ie_len
;
16884 #if defined(WL_FILS_ROAM_OFFLD)
16885 if ((sec
->auth_type
== DOT11_FILS_SKEY_PFS
)||(sec
->auth_type
== DOT11_FILS_SKEY
)) {
16886 roam_info
.fils
.kek
= fils_info
->fils_kek
;
16887 roam_info
.fils
.kek_len
= fils_info
->fils_kek_len
;
16888 roam_info
.fils
.update_erp_next_seq_num
= true;
16889 roam_info
.fils
.erp_next_seq_num
= fils_info
->fils_erp_next_seq_num
;
16890 roam_info
.fils
.pmk
= fils_info
->fils_pmk
;
16891 roam_info
.fils
.pmk_len
= fils_info
->fils_kek_len
;
16892 roam_info
.fils
.pmkid
= fils_info
->fils_pmkid
;
16895 cfg80211_roamed(ndev
, &roam_info
, GFP_KERNEL
);
16897 cfg80211_roamed(ndev
,
16898 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16902 conn_info
->req_ie
, conn_info
->req_ie_len
,
16903 conn_info
->resp_ie
, conn_info
->resp_ie_len
, GFP_KERNEL
);
16904 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
16906 memcpy(&cfg
->last_roamed_addr
, &e
->addr
, ETHER_ADDR_LEN
);
16907 wl_set_drv_status(cfg
, CONNECTED
, ndev
);
16909 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
16911 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
16913 if (wl_adps_bad_ap_check(cfg
, &e
->addr
)) {
16914 if (wl_adps_enabled(cfg
, ndev
)) {
16915 wl_adps_set_suspend(cfg
, ndev
, ADPS_SUSPEND
);
16918 #endif /* WL_BAM */
16920 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16921 ifp
= dhd_get_ifp(dhdp
, e
->ifidx
);
16923 ifp
->post_roam_evt
= TRUE
;
16925 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
16930 #ifdef DHD_LOSSLESS_ROAMING
16931 wl_del_roam_timeout(cfg
);
16932 #endif /* DHD_LOSSLESS_ROAMING */
16937 wl_cfg80211_verify_bss(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
16938 struct cfg80211_bss
**bss
)
16940 struct wiphy
*wiphy
;
16941 struct wlc_ssid
*ssid
;
16945 u8 cur_ssid
[DOT11_MAX_SSID_LEN
+ 1];
16947 wiphy
= bcmcfg_to_wiphy(cfg
);
16948 ssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, ndev
, WL_PROF_SSID
);
16949 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
16951 WL_ERR(("No SSID found in the saved profile \n"));
16956 *bss
= CFG80211_GET_BSS(wiphy
, NULL
, curbssid
,
16957 ssid
->SSID
, ssid
->SSID_len
);
16958 if (*bss
|| (count
> 5)) {
16964 } while (*bss
== NULL
);
16966 WL_DBG(("cfg80211 bss_ptr:%p loop_cnt:%d\n", *bss
, count
));
16968 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
16969 /* Update the reference count after use. In case of kernel version >= 4.7
16970 * the cfg802_put_bss is called in cfg80211_connect_bss context
16972 CFG80211_PUT_BSS(wiphy
, *bss
);
16973 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
16976 memset(cur_ssid
, 0, DOT11_MAX_SSID_LEN
);
16977 strncpy(cur_ssid
, ssid
->SSID
,
16978 MIN(ssid
->SSID_len
, DOT11_MAX_SSID_LEN
));
16979 WL_ERR(("No bss entry for ssid:%s bssid:"MACDBG
"\n",
16980 cur_ssid
, MAC2STRDBG(curbssid
)));
16988 wl_get_fils_connect_params(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
16990 const bcm_xtlv_t
* pxtlv_out
;
16991 struct wl_fils_info
*fils_info
= wl_to_fils_info(cfg
);
16993 bcm_iov_buf_t
*iov_buf_in
= NULL
;
16994 bcm_iov_buf_t iov_buf_out
= {0};
16998 iov_buf_in
= MALLOCZ(cfg
->osh
, WLC_IOCTL_SMLEN
);
17000 WL_ERR(("buf memory alloc failed\n"));
17004 iov_buf_out
.version
= WL_FILS_IOV_VERSION
;
17005 iov_buf_out
.id
= WL_FILS_CMD_GET_CONNECT_PARAMS
;
17006 err
= wldev_iovar_getbuf(ndev
, "fils", (uint8
*)&iov_buf_out
, sizeof(bcm_iov_buf_t
),
17007 iov_buf_in
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
17008 if (unlikely(err
)) {
17009 WL_ERR(("Get FILS Params Error (%d)\n", err
));
17012 pxtlv_out
= (bcm_xtlv_t
*)((bcm_iov_buf_t
*)iov_buf_in
)->data
;
17013 len
= iov_buf_in
->len
;
17015 if (!bcm_valid_xtlv(pxtlv_out
, iov_buf_in
->len
, BCM_XTLV_OPTION_ALIGN32
)) {
17016 WL_ERR(("%s: XTLV is not valid\n", __func__
));
17020 bcm_xtlv_unpack_xtlv(pxtlv_out
, &type
, &len
, &data
, BCM_XTLV_OPTION_ALIGN32
);
17022 case WL_FILS_XTLV_ERP_NEXT_SEQ_NUM
:
17023 fils_info
->fils_erp_next_seq_num
= *(const u16
*)data
;
17025 case WL_FILS_XTLV_KEK
:
17026 if (memcpy_s(fils_info
->fils_kek
,
17027 WL_MAX_FILS_KEY_LEN
, data
, len
) < 0) {
17031 fils_info
->fils_kek_len
= len
;
17033 case WL_FILS_XTLV_PMK
:
17034 if (memcpy_s(fils_info
->fils_pmk
,
17035 WL_MAX_FILS_KEY_LEN
, data
, len
) < 0) {
17039 fils_info
->fils_pmk_len
= len
;
17041 case WL_FILS_XTLV_PMKID
:
17042 if (memcpy_s(fils_info
->fils_pmkid
,
17043 WL_MAX_FILS_KEY_LEN
, data
, len
) < 0) {
17049 WL_ERR(("%s: wrong XTLV code\n", __func__
));
17053 } while ((pxtlv_out
= bcm_next_xtlv(pxtlv_out
, (int *)&iov_buf_in
->len
,
17054 BCM_XTLV_OPTION_ALIGN32
)) && iov_buf_in
->len
);
17057 MFREE(cfg
->osh
, iov_buf_in
, WLC_IOCTL_SMLEN
);
17061 #endif /* WL_FILS */
17063 wl_bss_connect_done(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
17064 const wl_event_msg_t
*e
, void *data
, bool completed
)
17066 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
17067 struct wl_security
*sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
17070 struct cfg80211_connect_resp_params resp_params
= {0};
17071 struct wl_fils_info
*fils_info
= NULL
;
17072 struct wlc_ssid
*ssid
= NULL
;
17073 struct wiphy
*wiphy
= NULL
;
17075 #endif /* WL_FILS */
17076 #ifdef ESCAN_RESULT_PATCH
17077 u8
*conn_req_bssid
= wl_read_prof(cfg
, ndev
, WL_PROF_LATEST_BSSID
);
17078 #endif /* ESCAN_RESULT_PATCH */
17079 u8
*curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
17080 u32 event_type
= ntoh32(e
->event_type
);
17081 struct cfg80211_bss
*bss
= NULL
;
17083 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
17084 BCM_REFERENCE(dhdp
);
17087 WL_ERR(("sec is NULL\n"));
17090 WL_DBG((" enter\n"));
17091 #ifdef ESCAN_RESULT_PATCH
17092 if (!conn_req_bssid
) {
17093 WL_ERR(("conn_req bssid is null\n"));
17096 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
17097 if (memcmp(curbssid
, conn_req_bssid
, ETHER_ADDR_LEN
) == 0) {
17098 WL_INFORM_MEM((" Connected event of connected device "
17099 "e=%d s=%d, ignore it\n",
17100 ntoh32(e
->event_type
), ntoh32(e
->status
)));
17104 if (ETHER_ISNULLADDR(curbssid
) &&
17105 !ETHER_ISNULLADDR(conn_req_bssid
)) {
17106 WL_DBG(("copy bssid\n"));
17107 memcpy(curbssid
, conn_req_bssid
, ETHER_ADDR_LEN
);
17110 if (cfg
->scan_request
) {
17111 wl_cfg80211_cancel_scan(cfg
);
17113 #endif /* ESCAN_RESULT_PATCH */
17114 if (wl_get_drv_status(cfg
, CONNECTING
, ndev
)) {
17115 wl_cfg80211_scan_abort(cfg
);
17117 wl_get_assoc_ies(cfg
, ndev
);
17118 wl_update_prof(cfg
, ndev
, NULL
, (const void *)(e
->addr
.octet
),
17120 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
17122 * CFG layer relies on cached IEs (from probe/beacon) to fetch matching bss.
17123 * For cases, there is no match available,
17124 * need to update the cache based on bss info from fw.
17126 wl_update_bss_info(cfg
, ndev
, true);
17127 if (cfg
->wlc_ver
.wlc_ver_major
< PMKDB_WLC_VER
) {
17128 wl_update_pmklist(ndev
, cfg
->pmk_list
, err
);
17130 wl_set_drv_status(cfg
, CONNECTED
, ndev
);
17131 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
17132 if (dhdp
->roam_env_detection
)
17133 wldev_iovar_setint(ndev
, "roam_env_detection",
17134 AP_ENV_INDETERMINATE
);
17135 #endif /* ROAM_AP_ENV_DETECTION */
17136 if (ndev
!= bcmcfg_to_prmry_ndev(cfg
)) {
17137 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
17138 init_completion(&cfg
->iface_disable
);
17140 /* reinitialize completion to clear previous count */
17141 INIT_COMPLETION(cfg
->iface_disable
);
17144 #ifdef CUSTOM_SET_CPUCORE
17145 if (wl_get_chan_isvht80(ndev
, dhdp
)) {
17146 if (ndev
== bcmcfg_to_prmry_ndev(cfg
))
17147 dhdp
->chan_isvht80
|= DHD_FLAG_STA_MODE
; /* STA mode */
17148 else if (is_p2p_group_iface(ndev
->ieee80211_ptr
))
17149 dhdp
->chan_isvht80
|= DHD_FLAG_P2P_MODE
; /* p2p mode */
17150 dhd_set_cpucore(dhdp
, TRUE
);
17152 #endif /* CUSTOM_SET_CPUCORE */
17153 #ifdef CUSTOM_LONG_RETRY_LIMIT
17154 if (wl_set_retry(ndev
, CUSTOM_LONG_RETRY_LIMIT
, 1) < 0) {
17155 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
17157 #endif /* CUSTOM_LONG_RETRY_LIMIT */
17158 bzero(&cfg
->last_roamed_addr
, ETHER_ADDR_LEN
);
17160 wl_clr_drv_status(cfg
, CONNECTING
, ndev
);
17163 if (wl_cfg80211_verify_bss(cfg
, ndev
, &bss
) != true) {
17164 /* If bss entry is not available in the cfg80211 bss cache
17165 * the wireless stack will complain and won't populate
17166 * wdev->current_bss ptr
17168 WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
17170 sec
->auth_assoc_res_status
= WLAN_STATUS_UNSPECIFIED_FAILURE
;
17171 } else if (!ndev
->ieee80211_ptr
->ssid_len
) {
17172 /* In certain cases, the delayed cfg80211 work from
17173 * disconnect context will induce race conditions in
17174 * which the ssid_len will be cleared, but dhd is in
17175 * connecting state. Return connect failure to avoid
17176 * getting locked in connected state.
17178 WL_ERR(("ssid_len=0. Indicate assoc event failure\n"));
17180 sec
->auth_assoc_res_status
= WLAN_STATUS_UNSPECIFIED_FAILURE
;
17184 WL_MSG(ndev
->name
, "Report connect result - connection succeeded\n");
17185 wl_cfg80211_check_in4way(cfg
, ndev
, 0, WL_EXT_STATUS_CONNECTED
, NULL
);
17187 WL_MSG(ndev
->name
, "Report connect result - connection failed\n");
17188 wl_cfg80211_check_in4way(cfg
, ndev
, NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
|WAIT_DISCONNECTED
,
17189 WL_EXT_STATUS_DISCONNECTED
, NULL
);
17192 if ((sec
->auth_type
== DOT11_FILS_SKEY_PFS
)||(sec
->auth_type
== DOT11_FILS_SKEY
)) {
17193 wl_get_fils_connect_params(cfg
, ndev
);
17194 fils_info
= wl_to_fils_info(cfg
);
17195 ssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, ndev
, WL_PROF_SSID
);
17196 wiphy
= bcmcfg_to_wiphy(cfg
);
17197 resp_params
.status
= completed
? WLAN_STATUS_SUCCESS
:
17198 (sec
->auth_assoc_res_status
) ?
17199 sec
->auth_assoc_res_status
:
17200 WLAN_STATUS_UNSPECIFIED_FAILURE
;
17201 resp_params
.bssid
= curbssid
;
17202 resp_params
.bss
= CFG80211_GET_BSS(wiphy
, NULL
, curbssid
,
17203 ssid
->SSID
, ssid
->SSID_len
);
17204 resp_params
.req_ie
= conn_info
->req_ie
;
17205 resp_params
.req_ie_len
= conn_info
->req_ie_len
;
17206 resp_params
.resp_ie
= conn_info
->resp_ie
;
17207 resp_params
.resp_ie_len
= conn_info
->resp_ie_len
;
17208 #if defined(WL_FILS_ROAM_OFFLD) || (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0))
17209 resp_params
.fils
.kek
= fils_info
->fils_kek
;
17210 resp_params
.fils
.kek_len
= fils_info
->fils_kek_len
;
17211 resp_params
.fils
.update_erp_next_seq_num
= true;
17212 resp_params
.fils
.erp_next_seq_num
= fils_info
->fils_erp_next_seq_num
;
17213 resp_params
.fils
.pmk
= fils_info
->fils_pmk
;
17214 resp_params
.fils
.pmk_len
= fils_info
->fils_kek_len
;
17215 resp_params
.fils
.pmkid
= fils_info
->fils_pmkid
;
17217 resp_params
.fils_kek
= fils_info
->fils_kek
;
17218 resp_params
.fils_kek_len
= fils_info
->fils_kek_len
;
17219 resp_params
.update_erp_next_seq_num
= true;
17220 resp_params
.fils_erp_next_seq_num
= fils_info
->fils_erp_next_seq_num
;
17221 resp_params
.pmk
= fils_info
->fils_pmk
;
17222 resp_params
.pmk_len
= fils_info
->fils_kek_len
;
17223 resp_params
.pmkid
= fils_info
->fils_pmkid
;
17224 #endif /* WL_FILS_ROAM_OFFLD */
17225 cfg80211_connect_done(ndev
, &resp_params
, GFP_KERNEL
);
17228 #endif /* WL_FILS */
17230 CFG80211_CONNECT_RESULT(ndev
,
17234 conn_info
->req_ie_len
,
17235 conn_info
->resp_ie
,
17236 conn_info
->resp_ie_len
,
17237 completed
? WLAN_STATUS_SUCCESS
:
17238 (sec
->auth_assoc_res_status
) ?
17239 sec
->auth_assoc_res_status
:
17240 WLAN_STATUS_UNSPECIFIED_FAILURE
,
17243 CLR_TS(cfg
, conn_start
);
17245 LOG_TS(cfg
, conn_cmplt
);
17246 LOG_TS(cfg
, authorize_start
);
17248 if (sec
->cipher_group
== WLAN_CIPHER_SUITE_SMS4
) {
17249 /* In WAPI case, there is no seperate authorized call
17250 * from upper layer. so set the state from connect done.
17252 wl_set_drv_status(cfg
, AUTHORIZED
, ndev
);
17253 CLR_TS(cfg
, authorize_start
);
17254 LOG_TS(cfg
, authorize_cmplt
);
17258 #if defined(CONFIG_TIZEN)
17259 net_stat_tizen_update_wifi(ndev
, WIFISTAT_CONNECTION
);
17260 #endif /* CONFIG_TIZEN */
17262 if (wl_adps_bad_ap_check(cfg
, &e
->addr
)) {
17263 if (wl_adps_enabled(cfg
, ndev
)) {
17264 wl_adps_set_suspend(cfg
, ndev
, ADPS_SUSPEND
);
17267 #endif /* WL_BAM */
17270 WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
17271 " connecting:%x. connected:%d\n",
17272 ndev
->name
, event_type
, wl_get_drv_status(cfg
, CONNECTING
, ndev
),
17273 wl_get_drv_status(cfg
, CONNECTED
, ndev
)));
17275 #ifdef CONFIG_TCPACK_FASTTX
17276 if (wl_get_chan_isvht80(ndev
, dhdp
))
17277 wldev_iovar_setint(ndev
, "tcpack_fast_tx", 0);
17279 wldev_iovar_setint(ndev
, "tcpack_fast_tx", 1);
17280 #endif /* CONFIG_TCPACK_FASTTX */
17286 wl_notify_mic_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
17287 const wl_event_msg_t
*e
, void *data
)
17289 struct net_device
*ndev
= NULL
;
17290 u16 flags
= ntoh16(e
->flags
);
17291 enum nl80211_key_type key_type
;
17293 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
17295 WL_INFORM_MEM(("[%s] mic fail event - " MACDBG
" \n",
17296 ndev
->name
, MAC2STRDBG(e
->addr
.octet
)));
17297 mutex_lock(&cfg
->usr_sync
);
17298 if (flags
& WLC_EVENT_MSG_GROUP
)
17299 key_type
= NL80211_KEYTYPE_GROUP
;
17301 key_type
= NL80211_KEYTYPE_PAIRWISE
;
17303 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
17304 cfg80211_michael_mic_failure(ndev
, (const u8
*)&e
->addr
, key_type
, -1,
17306 mutex_unlock(&cfg
->usr_sync
);
17311 #ifdef BT_WIFI_HANDOVER
17313 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
17314 const wl_event_msg_t
*e
, void *data
)
17316 struct net_device
*ndev
= NULL
;
17317 u32 event
= ntoh32(e
->event_type
);
17318 u32 datalen
= ntoh32(e
->datalen
);
17321 WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event
, datalen
));
17322 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
17323 err
= wl_genl_send_msg(ndev
, event
, data
, (u16
)datalen
, 0, 0);
17327 #endif /* BT_WIFI_HANDOVER */
17330 wl_frame_get_mgmt(struct bcm_cfg80211
*cfg
, u16 fc
,
17331 const struct ether_addr
*da
, const struct ether_addr
*sa
,
17332 const struct ether_addr
*bssid
, u8
**pheader
, u32
*body_len
, u8
*pbody
)
17334 struct dot11_management_header
*hdr
;
17338 u32 prebody_len
= *body_len
;
17341 /* capability , listen interval */
17342 totlen
= DOT11_ASSOC_REQ_FIXED_LEN
;
17343 *body_len
+= DOT11_ASSOC_REQ_FIXED_LEN
;
17346 case FC_REASSOC_REQ
:
17347 /* capability, listen inteval, ap address */
17348 totlen
= DOT11_REASSOC_REQ_FIXED_LEN
;
17349 *body_len
+= DOT11_REASSOC_REQ_FIXED_LEN
;
17352 totlen
+= DOT11_MGMT_HDR_LEN
+ prebody_len
;
17353 *pheader
= (u8
*)MALLOCZ(cfg
->osh
, totlen
);
17354 if (*pheader
== NULL
) {
17355 WL_ERR(("memory alloc failed \n"));
17358 hdr
= (struct dot11_management_header
*) (*pheader
);
17359 hdr
->fc
= htol16(fc
);
17362 offset
= (u8
*)(hdr
+ 1) + (totlen
- DOT11_MGMT_HDR_LEN
- prebody_len
);
17363 bcopy((const char*)da
, (u8
*)&hdr
->da
, ETHER_ADDR_LEN
);
17364 bcopy((const char*)sa
, (u8
*)&hdr
->sa
, ETHER_ADDR_LEN
);
17365 bcopy((const char*)bssid
, (u8
*)&hdr
->bssid
, ETHER_ADDR_LEN
);
17366 if ((pbody
!= NULL
) && prebody_len
)
17367 bcopy((const char*)pbody
, offset
, prebody_len
);
17368 *body_len
= totlen
;
17372 #ifdef WL_CFG80211_GON_COLLISION
17374 wl_gon_req_collision(struct bcm_cfg80211
*cfg
, wl_action_frame_t
*tx_act_frm
,
17375 wifi_p2p_pub_act_frame_t
*rx_act_frm
, struct net_device
*ndev
,
17376 struct ether_addr sa
, struct ether_addr da
)
17378 if (cfg
->afx_hdl
->pending_tx_act_frm
== NULL
)
17382 wl_cfgp2p_is_pub_action(tx_act_frm
->data
, tx_act_frm
->len
)) {
17383 wifi_p2p_pub_act_frame_t
*pact_frm
;
17385 pact_frm
= (wifi_p2p_pub_act_frame_t
*)tx_act_frm
->data
;
17387 if (!(pact_frm
->subtype
== P2P_PAF_GON_REQ
&&
17388 rx_act_frm
->subtype
== P2P_PAF_GON_REQ
)) {
17393 WL_ERR((" GO NEGO Request COLLISION !!! \n"));
17395 /* if sa(peer) addr is less than da(my) addr,
17396 * my device will process peer's gon request and block to send my gon req.
17398 * if not (sa addr > da addr),
17399 * my device will process gon request and drop gon req of peer.
17401 if (memcmp(sa
.octet
, da
.octet
, ETHER_ADDR_LEN
) < 0) {
17402 /* block to send tx gon request */
17403 cfg
->block_gon_req_tx_count
= BLOCK_GON_REQ_MAX_NUM
;
17404 WL_ERR((" block to send gon req tx !!!\n"));
17406 /* if we are finding a common channel for sending af,
17407 * do not scan more to block to send current gon req
17409 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
17410 wl_clr_drv_status(cfg
, FINDING_COMMON_CHANNEL
, ndev
);
17411 complete(&cfg
->act_frm_scan
);
17414 /* drop gon request of peer to process gon request by my device. */
17415 WL_ERR((" drop to receive gon req rx !!! \n"));
17416 cfg
->block_gon_req_rx_count
= BLOCK_GON_REQ_MAX_NUM
;
17421 #endif /* WL_CFG80211_GON_COLLISION */
17424 wl_stop_wait_next_action_frame(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u8 bsscfgidx
)
17428 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
17429 if (timer_pending(&cfg
->p2p
->listen_timer
)) {
17430 del_timer_sync(&cfg
->p2p
->listen_timer
);
17432 if (cfg
->afx_hdl
!= NULL
) {
17433 if (cfg
->afx_hdl
->dev
!= NULL
) {
17434 wl_clr_drv_status(cfg
, SCANNING
, cfg
->afx_hdl
->dev
);
17435 wl_clr_drv_status(cfg
, FINDING_COMMON_CHANNEL
, cfg
->afx_hdl
->dev
);
17437 cfg
->afx_hdl
->peer_chan
= WL_INVALID
;
17439 complete(&cfg
->act_frm_scan
);
17440 WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
17441 } else if (wl_get_drv_status_all(cfg
, SENDING_ACT_FRM
)) {
17442 if (!(wl_get_p2p_status(cfg
, ACTION_TX_COMPLETED
) ||
17443 wl_get_p2p_status(cfg
, ACTION_TX_NOACK
)))
17444 wl_set_p2p_status(cfg
, ACTION_TX_COMPLETED
);
17446 WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx
));
17447 /* Scan engine is not used for sending action frames in the latest driver
17448 * branches. actframe_abort is used in the latest driver branches
17449 * instead of scan abort.
17450 * If actframe_abort iovar succeeds, don't execute scan abort.
17451 * If actframe_abort fails with unsupported error,
17452 * execute scan abort (for backward copmatibility).
17454 if (cfg
->af_sent_channel
) {
17455 err
= wldev_iovar_setint_bsscfg(ndev
, "actframe_abort", 1, bsscfgidx
);
17457 if (err
== BCME_UNSUPPORTED
) {
17458 wl_cfg80211_scan_abort(cfg
);
17460 WL_ERR(("actframe_abort failed. ret:%d\n", err
));
17465 #ifdef WL_CFG80211_SYNC_GON
17466 else if (wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM_LISTEN
)) {
17467 WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
17468 /* So abort scan to cancel listen */
17469 wl_cfg80211_scan_abort(cfg
);
17471 #endif /* WL_CFG80211_SYNC_GON */
17474 #if defined(WLTDLS)
17475 bool wl_cfg80211_is_tdls_tunneled_frame(void *frame
, u32 frame_len
)
17477 unsigned char *data
;
17479 if (frame
== NULL
) {
17480 WL_ERR(("Invalid frame \n"));
17484 if (frame_len
< 5) {
17485 WL_ERR(("Invalid frame length [%d] \n", frame_len
));
17491 if (!memcmp(data
, TDLS_TUNNELED_PRB_REQ
, 5) ||
17492 !memcmp(data
, TDLS_TUNNELED_PRB_RESP
, 5)) {
17493 WL_DBG(("TDLS Vendor Specific Received type\n"));
17499 #endif /* WLTDLS */
17501 #if defined(WES_SUPPORT)
17502 int wl_cfg80211_set_wes_mode(struct net_device
*dev
, int mode
)
17504 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
17505 cfg
->wes_mode
= mode
;
17509 int wl_cfg80211_get_wes_mode(struct net_device
*dev
)
17511 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
17512 return cfg
->wes_mode
;
17515 bool wl_cfg80211_is_wes(void *frame
, u32 frame_len
)
17517 unsigned char *data
;
17519 if (frame
== NULL
) {
17520 WL_ERR(("Invalid frame \n"));
17524 if (frame_len
< 4) {
17525 WL_ERR(("Invalid frame length [%d] \n", frame_len
));
17531 if (memcmp(data
, "\x7f\x00\x00\xf0", 4) == 0) {
17532 WL_DBG(("Receive WES VS Action Frame \n"));
17540 wl_cfg80211_set_ncho_mode(struct net_device
*dev
, int mode
)
17542 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
17543 cfg
->ncho_mode
= mode
;
17548 wl_cfg80211_get_ncho_mode(struct net_device
*dev
)
17550 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
17551 return cfg
->ncho_mode
;
17553 #endif /* WES_SUPPORT */
17555 int wl_cfg80211_get_ioctl_version(void)
17557 return ioctl_version
;
17561 wl_notify_rx_mgmt_frame(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
17562 const wl_event_msg_t
*e
, void *data
)
17564 struct ether_addr da
;
17565 struct ether_addr bssid
;
17566 bool isfree
= false;
17569 struct net_device
*ndev
= NULL
;
17570 wifi_p2p_pub_act_frame_t
*act_frm
= NULL
;
17571 wifi_p2p_action_frame_t
*p2p_act_frm
= NULL
;
17572 wifi_p2psd_gas_pub_act_frame_t
*sd_act_frm
= NULL
;
17573 wl_event_rx_frame_data_t
*rxframe
;
17577 u32 mgmt_frame_len
;
17579 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
17580 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
17581 #endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
17582 if (ntoh32(e
->datalen
) < sizeof(wl_event_rx_frame_data_t
)) {
17583 WL_ERR(("wrong datalen:%d\n", ntoh32(e
->datalen
)));
17586 mgmt_frame_len
= ntoh32(e
->datalen
) - (uint32
)sizeof(wl_event_rx_frame_data_t
);
17587 event
= ntoh32(e
->event_type
);
17588 bsscfgidx
= e
->bsscfgidx
;
17589 rxframe
= (wl_event_rx_frame_data_t
*)data
;
17591 WL_ERR(("rxframe: NULL\n"));
17594 chspec
= ntoh16(rxframe
->channel
);
17595 bzero(&bssid
, ETHER_ADDR_LEN
);
17596 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
17597 if ((ndev
->ieee80211_ptr
->iftype
!= NL80211_IFTYPE_AP
) &&
17598 (event
== WLC_E_PROBREQ_MSG
)) {
17599 /* Probe req event comes on wlan0 interface even though
17600 * the frame have been received on correct interface(AP)
17601 * in firmware. Find the right interface to pass it up.
17602 * Required for WPS-AP certification 4.2.13.
17603 * TODO/Need a better fix. Current fix doesn't take
17604 * care of dual AP/GO scenarios.
17606 struct net_info
*iter
, *next
;
17607 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17608 for_each_ndev(cfg
, iter
, next
) {
17609 GCC_DIAGNOSTIC_POP();
17610 if (iter
->ndev
&& iter
->wdev
&&
17611 iter
->wdev
->iftype
== NL80211_IFTYPE_AP
) {
17613 cfgdev
= ndev_to_cfgdev(ndev
);
17619 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
17620 freq
= ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chspec
));
17622 freq
= wl_channel_to_frequency(wf_chspec_ctlchan(chspec
), CHSPEC_BAND(chspec
));
17624 if (event
== WLC_E_ACTION_FRAME_RX
) {
17625 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
17626 if ((err
= wldev_iovar_getbuf_bsscfg(ndev
, "cur_etheraddr",
17627 NULL
, 0, ioctl_buf
, sizeof(ioctl_buf
), bsscfgidx
,
17628 NULL
)) != BCME_OK
) {
17629 WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err
));
17633 err
= wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
17635 WL_ERR(("WLC_GET_BSSID error %d\n", err
));
17636 memcpy(da
.octet
, ioctl_buf
, ETHER_ADDR_LEN
);
17637 err
= wl_frame_get_mgmt(cfg
, FC_ACTION
, &da
, &e
->addr
, &bssid
,
17638 &mgmt_frame
, &mgmt_frame_len
,
17639 (u8
*)((wl_event_rx_frame_data_t
*)rxframe
+ 1));
17641 WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
17642 mgmt_frame_len
, CHSPEC_CHANNEL(chspec
), freq
));
17647 wl_cfgp2p_print_actframe(false, &mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17648 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
, CHSPEC_CHANNEL(chspec
));
17650 if (wl_cfgp2p_is_pub_action(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17651 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)) {
17652 act_frm
= (wifi_p2p_pub_act_frame_t
*)
17653 (&mgmt_frame
[DOT11_MGMT_HDR_LEN
]);
17654 } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17655 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)) {
17656 p2p_act_frm
= (wifi_p2p_action_frame_t
*)
17657 (&mgmt_frame
[DOT11_MGMT_HDR_LEN
]);
17658 (void) p2p_act_frm
;
17659 } else if (wl_cfg80211_is_dpp_gas_action(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17660 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)) {
17661 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, ndev
);
17663 /* Stop waiting for next AF. */
17664 wl_stop_wait_next_action_frame(cfg
, ndev
, bsscfgidx
);
17665 } else if (wl_cfgp2p_is_gas_action(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17666 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)) {
17667 sd_act_frm
= (wifi_p2psd_gas_pub_act_frame_t
*)
17668 (&mgmt_frame
[DOT11_MGMT_HDR_LEN
]);
17669 if (sd_act_frm
&& wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM
)) {
17670 if (cfg
->next_af_subtype
== sd_act_frm
->action
) {
17671 WL_DBG(("We got a right next frame of SD!(%d)\n",
17672 sd_act_frm
->action
));
17673 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, ndev
);
17675 /* Stop waiting for next AF. */
17676 wl_stop_wait_next_action_frame(cfg
, ndev
, bsscfgidx
);
17681 } else if ((mgmt_frame
[DOT11_MGMT_HDR_LEN
] == TDLS_AF_CATEGORY
) ||
17682 (wl_cfg80211_is_tdls_tunneled_frame(
17683 &mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17684 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
))) {
17685 if (mgmt_frame
[DOT11_MGMT_HDR_LEN
] == TDLS_AF_CATEGORY
) {
17686 WL_ERR((" TDLS Action Frame Received type = %d \n",
17687 mgmt_frame
[DOT11_MGMT_HDR_LEN
+ 1]));
17689 #ifdef TDLS_MSG_ONLY_WFD
17690 if (!dhdp
->tdls_mode
) {
17691 WL_DBG((" TDLS Frame filtered \n"));
17695 if (mgmt_frame
[DOT11_MGMT_HDR_LEN
+ 1] == TDLS_ACTION_SETUP_RESP
) {
17696 cfg
->tdls_mgmt_frame
= mgmt_frame
;
17697 cfg
->tdls_mgmt_frame_len
= mgmt_frame_len
;
17698 cfg
->tdls_mgmt_freq
= freq
;
17701 #endif /* TDLS_MSG_ONLY_WFD */
17702 #endif /* WLTDLS */
17704 } else if (mgmt_frame
[DOT11_MGMT_HDR_LEN
] == DOT11_ACTION_CAT_QOS
) {
17705 /* update QoS map set table */
17706 bcm_tlv_t
* qos_map_ie
= NULL
;
17707 uint8 offset
= DOT11_MGMT_HDR_LEN
+ DOT11_ACTION_FRMHDR_LEN
;
17708 if ((qos_map_ie
= bcm_parse_tlvs(&mgmt_frame
[offset
],
17709 mgmt_frame_len
- offset
, DOT11_MNG_QOS_MAP_ID
)) != NULL
) {
17710 WL_DBG((" QoS map set IE found in QoS action frame\n"));
17711 if (!cfg
->up_table
) {
17712 cfg
->up_table
= (uint8
*)MALLOC(cfg
->osh
, UP_TABLE_MAX
);
17714 wl_set_up_table(cfg
->up_table
, qos_map_ie
);
17716 MFREE(cfg
->osh
, cfg
->up_table
, UP_TABLE_MAX
);
17718 #endif /* QOS_MAP_SET */
17720 } else if (mgmt_frame
[DOT11_MGMT_HDR_LEN
] == DOT11_ACTION_CAT_RRM
) {
17721 /* radio measurement category */
17722 switch (mgmt_frame
[DOT11_MGMT_HDR_LEN
+1]) {
17723 case DOT11_RM_ACTION_NR_REP
:
17724 if (wl_cfg80211_recv_nbr_resp(ndev
,
17725 &mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17726 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)
17728 WL_DBG(("RCC updated by nbr response\n"));
17734 #endif /* WBTEXT */
17736 /* WAR : There is no way to identify DA of action frame as of now.
17737 * We have to modify firmware code to include DA and SA of Act frame
17741 * if we got normal action frame and ndev is p2p0,
17742 * we have to change ndev from p2p0 to wlan0
17744 #if defined(WES_SUPPORT)
17745 if (wl_cfg80211_is_wes(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17746 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
) && cfg
->wes_mode
== 0) {
17747 /* Ignore WES VS Action frame */
17750 #endif /* WES_SUPPORT */
17752 /* We need to check proper action frame is received */
17753 if (cfg
->next_af_subtype
!= WL_PUB_AF_STYPE_INVALID
) {
17755 if (wl_get_public_action(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17756 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
, &action
) != BCME_OK
) {
17757 WL_DBG(("Recived action is not public action frame\n"));
17758 } else if (cfg
->next_af_subtype
== action
) {
17759 WL_DBG(("Recived action is the waiting action(%d)\n",
17761 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, ndev
);
17763 /* Stop waiting for next AF. */
17764 wl_stop_wait_next_action_frame(cfg
, ndev
, bsscfgidx
);
17770 #ifdef WL_CFG80211_GON_COLLISION
17771 if (act_frm
->subtype
== P2P_PAF_GON_REQ
) {
17772 wl_gon_req_collision(cfg
,
17773 &cfg
->afx_hdl
->pending_tx_act_frm
->action_frame
,
17774 act_frm
, ndev
, e
->addr
, da
);
17776 if (cfg
->block_gon_req_rx_count
) {
17777 WL_ERR(("drop frame GON Req Rx : count (%d)\n",
17778 cfg
->block_gon_req_rx_count
));
17779 cfg
->block_gon_req_rx_count
--;
17782 } else if (act_frm
->subtype
== P2P_PAF_GON_CONF
) {
17783 /* if go formation done, clear it */
17784 cfg
->block_gon_req_tx_count
= 0;
17785 cfg
->block_gon_req_rx_count
= 0;
17787 #endif /* WL_CFG80211_GON_COLLISION */
17789 if (wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM
)) {
17790 if (cfg
->next_af_subtype
== act_frm
->subtype
) {
17791 WL_DBG(("We got a right next frame!(%d)\n",
17792 act_frm
->subtype
));
17793 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, ndev
);
17795 if (cfg
->next_af_subtype
== P2P_PAF_GON_CONF
) {
17799 /* Stop waiting for next AF. */
17800 wl_stop_wait_next_action_frame(cfg
, ndev
, bsscfgidx
);
17801 } else if ((cfg
->next_af_subtype
== P2P_PAF_GON_RSP
) &&
17802 (act_frm
->subtype
== P2P_PAF_GON_REQ
)) {
17803 /* If current received frame is GO NEG REQ and next
17804 * expected frame is GO NEG RESP, do not send it up.
17806 WL_ERR(("GO Neg req received while waiting for RESP."
17807 "Discard incoming frame\n"));
17813 if (wl_cfg80211_is_dpp_frame(
17814 (void *)&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17815 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)) {
17816 wl_dpp_pa_frame_t
*pa
=
17817 (wl_dpp_pa_frame_t
*)&mgmt_frame
[DOT11_MGMT_HDR_LEN
];
17818 if (cfg
->next_af_subtype
== pa
->ftype
) {
17819 WL_DBG(("matching dpp frm (%d) found. abort dwell\n", pa
->ftype
));
17820 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, ndev
);
17822 /* Stop waiting for next AF. */
17823 wl_stop_wait_next_action_frame(cfg
, ndev
, bsscfgidx
);
17826 if (act_frm
&& (act_frm
->subtype
== P2P_PAF_GON_CONF
)) {
17827 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
17828 wl_clr_p2p_status(cfg
, GO_NEG_PHASE
);
17830 } else if (event
== WLC_E_PROBREQ_MSG
) {
17832 /* Handle probe reqs frame
17833 * WPS-AP certification 4.2.13
17835 struct parsed_ies prbreq_ies
;
17836 u32 prbreq_ie_len
= 0;
17839 WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
17840 mgmt_frame
= (u8
*)(data
);
17841 mgmt_frame_len
= ntoh32(e
->datalen
);
17842 if (mgmt_frame_len
< DOT11_MGMT_HDR_LEN
) {
17843 WL_ERR(("wrong datalen:%d\n", mgmt_frame_len
));
17846 prbreq_ie_len
= mgmt_frame_len
- DOT11_MGMT_HDR_LEN
;
17848 /* Parse prob_req IEs */
17849 if (wl_cfg80211_parse_ies(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
17850 prbreq_ie_len
, &prbreq_ies
) < 0) {
17851 WL_ERR(("Prob req get IEs failed\n"));
17854 if (prbreq_ies
.wps_ie
!= NULL
) {
17855 wl_validate_wps_ie(
17856 (const char *)prbreq_ies
.wps_ie
, prbreq_ies
.wps_ie_len
, &pbc
);
17857 WL_DBG((" wps_ie exist pbc = %d\n", pbc
));
17858 /* if pbc method, send prob_req mgmt frame to upper layer */
17864 mgmt_frame
= (u8
*)((wl_event_rx_frame_data_t
*)rxframe
+ 1);
17866 /* wpa supplicant use probe request event for restarting another GON Req.
17867 * but it makes GON Req repetition.
17868 * so if src addr of prb req is same as my target device,
17869 * do not send probe request event during sending action frame.
17871 if (event
== WLC_E_P2P_PROBREQ_MSG
) {
17872 WL_DBG((" Event %s\n", (event
== WLC_E_P2P_PROBREQ_MSG
) ?
17873 "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
17875 #ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
17876 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg
) &&
17877 !memcmp(cfg
->afx_hdl
->tx_dst_addr
.octet
, e
->addr
.octet
,
17879 if (cfg
->afx_hdl
->pending_tx_act_frm
&&
17880 wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
17881 chanspec_t channel
= hton16(rxframe
->channel
);
17882 WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
17884 cfg
->afx_hdl
->peer_chan
= channel
;
17885 complete(&cfg
->act_frm_scan
);
17888 #endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
17890 /* Filter any P2P probe reqs arriving during the
17894 #if defined(P2P_IE_MISSING_FIX)
17895 cfg
->p2p_prb_noti
&&
17897 wl_get_p2p_status(cfg
, GO_NEG_PHASE
)) {
17898 WL_DBG(("Filtering P2P probe_req while "
17899 "being in GO-Neg state\n"));
17905 if (discover_cfgdev(cfgdev
, cfg
))
17906 WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
17908 WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev
->name
));
17909 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
17910 cfg80211_rx_mgmt(cfgdev
, freq
, 0, mgmt_frame
, mgmt_frame_len
, 0);
17911 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
17912 cfg80211_rx_mgmt(cfgdev
, freq
, 0, mgmt_frame
, mgmt_frame_len
, 0, GFP_ATOMIC
);
17913 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
17914 defined(WL_COMPAT_WIRELESS)
17915 cfg80211_rx_mgmt(cfgdev
, freq
, 0, mgmt_frame
, mgmt_frame_len
, GFP_ATOMIC
);
17917 cfg80211_rx_mgmt(cfgdev
, freq
, mgmt_frame
, mgmt_frame_len
, GFP_ATOMIC
);
17918 #endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
17920 WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
17921 mgmt_frame_len
, ntoh32(e
->datalen
), CHSPEC_CHANNEL(chspec
), freq
));
17924 MFREE(cfg
->osh
, mgmt_frame
, mgmt_frame_len
);
17929 static void wl_init_conf(struct wl_conf
*conf
)
17931 WL_DBG(("Enter \n"));
17932 conf
->frag_threshold
= (u32
)-1;
17933 conf
->rts_threshold
= (u32
)-1;
17934 conf
->retry_short
= (u32
)-1;
17935 conf
->retry_long
= (u32
)-1;
17936 conf
->tx_power
= -1;
17939 static void wl_init_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
17941 unsigned long flags
;
17942 struct wl_profile
*profile
= wl_get_profile_by_netdev(cfg
, ndev
);
17945 WL_ERR(("profile null\n"));
17949 WL_CFG_DRV_LOCK(&cfg
->cfgdrv_lock
, flags
);
17950 bzero(profile
, sizeof(struct wl_profile
));
17951 WL_CFG_DRV_UNLOCK(&cfg
->cfgdrv_lock
, flags
);
17954 static void wl_init_event_handler(struct bcm_cfg80211
*cfg
)
17956 bzero(cfg
->evt_handler
, sizeof(cfg
->evt_handler
));
17958 cfg
->evt_handler
[WLC_E_SCAN_COMPLETE
] = wl_notify_scan_status
;
17959 cfg
->evt_handler
[WLC_E_AUTH
] = wl_notify_connect_status
;
17960 cfg
->evt_handler
[WLC_E_ASSOC
] = wl_notify_connect_status
;
17961 cfg
->evt_handler
[WLC_E_LINK
] = wl_notify_connect_status
;
17962 cfg
->evt_handler
[WLC_E_DEAUTH_IND
] = wl_notify_connect_status
;
17963 cfg
->evt_handler
[WLC_E_DEAUTH
] = wl_notify_connect_status
;
17964 cfg
->evt_handler
[WLC_E_DISASSOC_IND
] = wl_notify_connect_status
;
17965 cfg
->evt_handler
[WLC_E_ASSOC_IND
] = wl_notify_connect_status
;
17966 cfg
->evt_handler
[WLC_E_REASSOC_IND
] = wl_notify_connect_status
;
17967 cfg
->evt_handler
[WLC_E_ROAM
] = wl_notify_roaming_status
;
17968 cfg
->evt_handler
[WLC_E_MIC_ERROR
] = wl_notify_mic_status
;
17969 cfg
->evt_handler
[WLC_E_SET_SSID
] = wl_notify_connect_status
;
17970 cfg
->evt_handler
[WLC_E_ACTION_FRAME_RX
] = wl_notify_rx_mgmt_frame
;
17971 cfg
->evt_handler
[WLC_E_PROBREQ_MSG
] = wl_notify_rx_mgmt_frame
;
17972 cfg
->evt_handler
[WLC_E_P2P_PROBREQ_MSG
] = wl_notify_rx_mgmt_frame
;
17973 cfg
->evt_handler
[WLC_E_P2P_DISC_LISTEN_COMPLETE
] = wl_cfgp2p_listen_complete
;
17974 cfg
->evt_handler
[WLC_E_ACTION_FRAME_COMPLETE
] = wl_cfgp2p_action_tx_complete
;
17975 cfg
->evt_handler
[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
] = wl_cfgp2p_action_tx_complete
;
17976 cfg
->evt_handler
[WLC_E_JOIN
] = wl_notify_connect_status
;
17977 cfg
->evt_handler
[WLC_E_START
] = wl_notify_connect_status
;
17978 cfg
->evt_handler
[WLC_E_AUTH_IND
] = wl_notify_connect_status
;
17979 cfg
->evt_handler
[WLC_E_ASSOC_RESP_IE
] = wl_notify_connect_status
;
17981 cfg
->evt_handler
[WLC_E_PFN_NET_FOUND
] = wl_notify_pfn_status
;
17982 #endif /* PNO_SUPPORT */
17983 #ifdef GSCAN_SUPPORT
17984 cfg
->evt_handler
[WLC_E_PFN_BEST_BATCHING
] = wl_notify_gscan_event
;
17985 cfg
->evt_handler
[WLC_E_PFN_SCAN_COMPLETE
] = wl_notify_gscan_event
;
17986 cfg
->evt_handler
[WLC_E_PFN_GSCAN_FULL_RESULT
] = wl_notify_gscan_event
;
17987 cfg
->evt_handler
[WLC_E_PFN_BSSID_NET_FOUND
] = wl_notify_gscan_event
;
17988 cfg
->evt_handler
[WLC_E_PFN_BSSID_NET_LOST
] = wl_notify_gscan_event
;
17989 cfg
->evt_handler
[WLC_E_PFN_SSID_EXT
] = wl_notify_gscan_event
;
17990 cfg
->evt_handler
[WLC_E_GAS_FRAGMENT_RX
] = wl_notify_gscan_event
;
17991 cfg
->evt_handler
[WLC_E_ROAM_EXP_EVENT
] = wl_handle_roam_exp_event
;
17992 #endif /* GSCAN_SUPPORT */
17993 #ifdef RSSI_MONITOR_SUPPORT
17994 cfg
->evt_handler
[WLC_E_RSSI_LQM
] = wl_handle_rssi_monitor_event
;
17995 #endif /* RSSI_MONITOR_SUPPORT */
17997 cfg
->evt_handler
[WLC_E_TDLS_PEER_EVENT
] = wl_tdls_event_handler
;
17998 #endif /* WLTDLS */
17999 cfg
->evt_handler
[WLC_E_BSSID
] = wl_notify_roaming_status
;
18001 cfg
->evt_handler
[WLC_E_AIBSS_TXFAIL
] = wl_notify_aibss_txfail
;
18002 #endif /* WLAIBSS */
18004 cfg
->evt_handler
[WLC_E_RMC_EVENT
] = wl_notify_rmc_status
;
18005 #endif /* WL_RELMCAST */
18006 #ifdef BT_WIFI_HANDOVER
18007 cfg
->evt_handler
[WLC_E_BT_WIFI_HANDOVER_REQ
] = wl_notify_bt_wifi_handover_req
;
18010 cfg
->evt_handler
[WLC_E_NAN_CRITICAL
] = wl_cfgnan_notify_nan_status
;
18011 cfg
->evt_handler
[WLC_E_NAN_NON_CRITICAL
] = wl_cfgnan_notify_nan_status
;
18012 #endif /* WL_NAN */
18013 cfg
->evt_handler
[WLC_E_CSA_COMPLETE_IND
] = wl_csa_complete_ind
;
18014 cfg
->evt_handler
[WLC_E_AP_STARTED
] = wl_ap_start_ind
;
18015 #ifdef CUSTOM_EVENT_PM_WAKE
18016 cfg
->evt_handler
[WLC_E_EXCESS_PM_WAKE_EVENT
] = wl_check_pmstatus
;
18017 #endif /* CUSTOM_EVENT_PM_WAKE */
18018 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
18019 cfg
->evt_handler
[WLC_E_ROAM_PREP
] = wl_notify_roam_prep_status
;
18020 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
18021 cfg
->evt_handler
[WLC_E_ROAM_START
] = wl_notify_roam_start_status
;
18023 cfg
->evt_handler
[WLC_E_ADPS
] = wl_adps_event_handler
;
18024 #endif /* WL_BAM */
18025 cfg
->evt_handler
[WLC_E_PSK_SUP
] = wl_cfg80211_sup_event_handler
;
18027 cfg
->evt_handler
[WLC_E_BCNRECV_ABORTED
] = wl_bcnrecv_aborted_event_handler
;
18028 #endif /* WL_BCNRECV */
18030 cfg
->evt_handler
[WLC_E_MBO
] = wl_mbo_event_handler
;
18031 #endif /* WL_MBO */
18033 cfg
->evt_handler
[WLC_E_ADDTS_IND
] = wl_cfg80211_cac_event_handler
;
18034 cfg
->evt_handler
[WLC_E_DELTS_IND
] = wl_cfg80211_cac_event_handler
;
18035 #endif /* WL_CAC_TS */
18036 #if defined(WL_MBO) || defined(WL_OCE)
18037 cfg
->evt_handler
[WLC_E_PRUNE
] = wl_bssid_prune_event_handler
;
18038 #endif /* WL_MBO || WL_OCE */
18040 cfg
->evt_handler
[WLC_E_PROXD
] = wl_cfg80211_rtt_event_handler
;
18042 #ifdef WL_CHAN_UTIL
18043 cfg
->evt_handler
[WLC_E_BSS_LOAD
] = wl_cfg80211_bssload_report_event_handler
;
18044 #endif /* WL_CHAN_UTIL */
18045 #ifdef WL_CLIENT_SAE
18046 cfg
->evt_handler
[WLC_E_JOIN_START
] = wl_notify_start_auth
;
18047 #endif /* WL_CLIENT_SAE */
18050 #ifdef WL_CLIENT_SAE
18051 /** Called by the cfg80211 framework */
18053 wl_cfg80211_external_auth(struct wiphy
*wiphy
,
18054 struct net_device
*ndev
, struct cfg80211_external_auth_params
*ext_auth_param
)
18057 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
18058 wl_assoc_mgr_cmd_t cmd
;
18060 WL_DBG(("Enter\n"));
18062 if (!ext_auth_param
||
18063 ETHER_ISNULLADDR(ext_auth_param
->bssid
)) {
18064 WL_ERR(("Invalid wl_cfg80211_external_auth param\n"));
18068 cmd
.version
= WL_ASSOC_MGR_CURRENT_VERSION
;
18069 cmd
.length
= sizeof(cmd
);
18070 cmd
.cmd
= WL_ASSOC_MGR_CMD_PAUSE_ON_EVT
;
18071 cmd
.params
= WL_ASSOC_MGR_PARAMS_EVENT_NONE
;
18072 err
= wldev_iovar_setbuf(ndev
, "assoc_mgr_cmd", (void *)&cmd
, sizeof(cmd
), cfg
->ioctl_buf
,
18073 WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
18074 if (unlikely(err
)) {
18075 WL_ERR(("Failed to pause assoc(%d)\n", err
));
18080 #endif /* WL_CLIENT_SAE */
18082 #if defined(STATIC_WL_PRIV_STRUCT)
18084 wl_init_escan_result_buf(struct bcm_cfg80211
*cfg
)
18086 #ifdef DUAL_ESCAN_RESULT_BUFFER
18087 cfg
->escan_info
.escan_buf
[0] = DHD_OS_PREALLOC(cfg
->pub
,
18088 DHD_PREALLOC_WIPHY_ESCAN0
, ESCAN_BUF_SIZE
);
18089 if (cfg
->escan_info
.escan_buf
[0] == NULL
) {
18090 WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
18094 cfg
->escan_info
.escan_buf
[1] = DHD_OS_PREALLOC(cfg
->pub
,
18095 DHD_PREALLOC_WIPHY_ESCAN1
, ESCAN_BUF_SIZE
);
18096 if (cfg
->escan_info
.escan_buf
[1] == NULL
) {
18097 WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
18101 bzero(cfg
->escan_info
.escan_buf
[0], ESCAN_BUF_SIZE
);
18102 bzero(cfg
->escan_info
.escan_buf
[1], ESCAN_BUF_SIZE
);
18103 cfg
->escan_info
.escan_type
[0] = 0;
18104 cfg
->escan_info
.escan_type
[1] = 0;
18106 cfg
->escan_info
.escan_buf
= DHD_OS_PREALLOC(cfg
->pub
,
18107 DHD_PREALLOC_WIPHY_ESCAN0
, ESCAN_BUF_SIZE
);
18108 if (cfg
->escan_info
.escan_buf
== NULL
) {
18109 WL_ERR(("Failed to alloc ESCAN_BUF\n"));
18112 bzero(cfg
->escan_info
.escan_buf
, ESCAN_BUF_SIZE
);
18113 #endif /* DUAL_ESCAN_RESULT_BUFFER */
18119 wl_deinit_escan_result_buf(struct bcm_cfg80211
*cfg
)
18121 #ifdef DUAL_ESCAN_RESULT_BUFFER
18122 if (cfg
->escan_info
.escan_buf
[0] != NULL
) {
18123 cfg
->escan_info
.escan_buf
[0] = NULL
;
18124 cfg
->escan_info
.escan_type
[0] = 0;
18127 if (cfg
->escan_info
.escan_buf
[1] != NULL
) {
18128 cfg
->escan_info
.escan_buf
[1] = NULL
;
18129 cfg
->escan_info
.escan_type
[1] = 0;
18132 if (cfg
->escan_info
.escan_buf
!= NULL
) {
18133 cfg
->escan_info
.escan_buf
= NULL
;
18135 #endif /* DUAL_ESCAN_RESULT_BUFFER */
18137 #endif /* STATIC_WL_PRIV_STRUCT */
18139 static s32
wl_init_priv_mem(struct bcm_cfg80211
*cfg
)
18141 WL_DBG(("Enter \n"));
18143 cfg
->scan_results
= (struct wl_scan_results
*)MALLOCZ(cfg
->osh
,
18145 if (unlikely(!cfg
->scan_results
)) {
18146 WL_ERR(("Scan results alloc failed\n"));
18147 goto init_priv_mem_out
;
18149 cfg
->conf
= (struct wl_conf
*)MALLOCZ(cfg
->osh
, sizeof(*cfg
->conf
));
18150 if (unlikely(!cfg
->conf
)) {
18151 WL_ERR(("wl_conf alloc failed\n"));
18152 goto init_priv_mem_out
;
18154 cfg
->scan_req_int
= (void *)MALLOCZ(cfg
->osh
,
18155 sizeof(*cfg
->scan_req_int
));
18156 if (unlikely(!cfg
->scan_req_int
)) {
18157 WL_ERR(("Scan req alloc failed\n"));
18158 goto init_priv_mem_out
;
18160 cfg
->ioctl_buf
= (u8
*)MALLOCZ(cfg
->osh
, WLC_IOCTL_MAXLEN
);
18161 if (unlikely(!cfg
->ioctl_buf
)) {
18162 WL_ERR(("Ioctl buf alloc failed\n"));
18163 goto init_priv_mem_out
;
18165 cfg
->escan_ioctl_buf
= (void *)MALLOCZ(cfg
->osh
, WLC_IOCTL_MAXLEN
);
18166 if (unlikely(!cfg
->escan_ioctl_buf
)) {
18167 WL_ERR(("Ioctl buf alloc failed\n"));
18168 goto init_priv_mem_out
;
18170 cfg
->extra_buf
= (void *)MALLOCZ(cfg
->osh
, WL_EXTRA_BUF_MAX
);
18171 if (unlikely(!cfg
->extra_buf
)) {
18172 WL_ERR(("Extra buf alloc failed\n"));
18173 goto init_priv_mem_out
;
18175 cfg
->pmk_list
= (void *)MALLOCZ(cfg
->osh
, sizeof(*cfg
->pmk_list
));
18176 if (unlikely(!cfg
->pmk_list
)) {
18177 WL_ERR(("pmk list alloc failed\n"));
18178 goto init_priv_mem_out
;
18180 #if defined(STATIC_WL_PRIV_STRUCT)
18181 cfg
->conn_info
= (void *)MALLOCZ(cfg
->osh
, sizeof(*cfg
->conn_info
));
18182 if (unlikely(!cfg
->conn_info
)) {
18183 WL_ERR(("cfg->conn_info alloc failed\n"));
18184 goto init_priv_mem_out
;
18186 cfg
->ie
= (void *)MALLOC(cfg
->osh
, sizeof(*cfg
->ie
));
18187 if (unlikely(!cfg
->ie
)) {
18188 WL_ERR(("cfg->ie alloc failed\n"));
18189 goto init_priv_mem_out
;
18191 if (unlikely(wl_init_escan_result_buf(cfg
))) {
18192 WL_ERR(("Failed to init escan resul buf\n"));
18193 goto init_priv_mem_out
;
18195 #endif /* STATIC_WL_PRIV_STRUCT */
18196 cfg
->afx_hdl
= (void *)MALLOCZ(cfg
->osh
, sizeof(*cfg
->afx_hdl
));
18197 if (unlikely(!cfg
->afx_hdl
)) {
18198 WL_ERR(("afx hdl alloc failed\n"));
18199 goto init_priv_mem_out
;
18201 init_completion(&cfg
->act_frm_scan
);
18202 init_completion(&cfg
->wait_next_af
);
18204 INIT_WORK(&cfg
->afx_hdl
->work
, wl_cfg80211_afx_handler
);
18207 if (cfg
->tdls_mgmt_frame
) {
18208 MFREE(cfg
->osh
, cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
);
18209 cfg
->tdls_mgmt_frame
= NULL
;
18210 cfg
->tdls_mgmt_frame_len
= 0;
18212 #endif /* WLTDLS */
18213 cfg
->spmk_info_list
= (void *)MALLOCZ(cfg
->osh
, sizeof(*cfg
->spmk_info_list
));
18214 if (unlikely(!cfg
->spmk_info_list
)) {
18215 WL_ERR(("Single PMK info list allocation falure\n"));
18216 goto init_priv_mem_out
;
18222 wl_deinit_priv_mem(cfg
);
18227 static void wl_deinit_priv_mem(struct bcm_cfg80211
*cfg
)
18229 MFREE(cfg
->osh
, cfg
->scan_results
, WL_SCAN_BUF_MAX
);
18230 MFREE(cfg
->osh
, cfg
->conf
, sizeof(*cfg
->conf
));
18231 MFREE(cfg
->osh
, cfg
->scan_req_int
, sizeof(*cfg
->scan_req_int
));
18232 MFREE(cfg
->osh
, cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
);
18233 MFREE(cfg
->osh
, cfg
->escan_ioctl_buf
, WLC_IOCTL_MAXLEN
);
18234 MFREE(cfg
->osh
, cfg
->extra_buf
, WL_EXTRA_BUF_MAX
);
18235 MFREE(cfg
->osh
, cfg
->pmk_list
, sizeof(*cfg
->pmk_list
));
18236 #if defined(STATIC_WL_PRIV_STRUCT)
18237 MFREE(cfg
->osh
, cfg
->conn_info
, sizeof(*cfg
->conn_info
));
18238 MFREE(cfg
->osh
, cfg
->ie
, sizeof(*cfg
->ie
));
18239 wl_deinit_escan_result_buf(cfg
);
18240 #endif /* STATIC_WL_PRIV_STRUCT */
18241 if (cfg
->afx_hdl
) {
18242 cancel_work_sync(&cfg
->afx_hdl
->work
);
18243 MFREE(cfg
->osh
, cfg
->afx_hdl
, sizeof(*cfg
->afx_hdl
));
18245 MFREE(cfg
->osh
, cfg
->spmk_info_list
, sizeof(*cfg
->spmk_info_list
));
18249 static s32
wl_create_event_handler(struct bcm_cfg80211
*cfg
)
18252 WL_DBG(("Enter \n"));
18254 /* making separate work queue needs GPL license,
18255 * but some drivers are not in GPL license, so, making seperate queue Android only
18258 /* Allocate workqueue for event */
18259 if (!cfg
->event_workq
) {
18260 cfg
->event_workq
= alloc_workqueue("dhd_eventd",
18261 WQ_MEM_RECLAIM
| WQ_HIGHPRI
| WQ_UNBOUND
, 1);
18264 if (!cfg
->event_workq
) {
18265 WL_ERR(("event_workq alloc_workqueue failed\n"));
18268 INIT_WORK(&cfg
->event_work
, wl_event_handler
);
18274 static void wl_destroy_event_handler(struct bcm_cfg80211
*cfg
)
18277 if (cfg
&& cfg
->event_workq
) {
18278 cancel_work_sync(&cfg
->event_work
);
18279 destroy_workqueue(cfg
->event_workq
);
18280 cfg
->event_workq
= NULL
;
18285 void wl_terminate_event_handler(struct net_device
*dev
)
18287 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
18290 wl_destroy_event_handler(cfg
);
18295 #ifdef DHD_LOSSLESS_ROAMING
18296 static void wl_del_roam_timeout(struct bcm_cfg80211
*cfg
)
18298 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
18300 /* restore prec_map to ALLPRIO */
18301 dhdp
->dequeue_prec_map
= ALLPRIO
;
18302 if (timer_pending(&cfg
->roam_timeout
)) {
18303 del_timer_sync(&cfg
->roam_timeout
);
18308 static void wl_roam_timeout(unsigned long data
)
18310 struct bcm_cfg80211
*cfg
= (struct bcm_cfg80211
*)data
;
18311 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
18313 WL_ERR(("roam timer expired\n"));
18315 /* restore prec_map to ALLPRIO */
18316 dhdp
->dequeue_prec_map
= ALLPRIO
;
18319 #endif /* DHD_LOSSLESS_ROAMING */
18321 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
18322 #define CP_CHAN_INFO_RAT_MODE_LTE 3
18323 #define CP_CHAN_INFO_RAT_MODE_NR5G 7
18324 int g_mhs_chan_for_cpcoex
= 0;
18326 struct __packed cam_cp_noti_info
{
18333 wl_cfg80211_send_msg_to_ril()
18337 id
= IPC_SYSTEM_CP_CHANNEL_INFO
;
18338 dev_ril_bridge_send_msg(id
, sizeof(int), &buf
);
18339 WL_ERR(("[BeyondX] send message to ril.\n"));
18346 wl_cfg80211_ril_bridge_notifier_call(struct notifier_block
*nb
,
18347 unsigned long size
, void *buf
)
18349 struct dev_ril_bridge_msg
*msg
;
18350 struct cam_cp_noti_info
*cp_noti_info
;
18351 static int mhs_channel_for_4g
, mhs_channel_for_5g
;
18352 static int recv_msg_4g
, recv_msg_5g
;
18354 WL_ERR(("[BeyondX] receive message from ril.\n"));
18355 msg
= (struct dev_ril_bridge_msg
*)buf
;
18357 if (msg
->dev_id
== IPC_SYSTEM_CP_CHANNEL_INFO
&&
18358 msg
->data_len
<= sizeof(struct cam_cp_noti_info
)) {
18363 cp_noti_info
= (struct cam_cp_noti_info
*)msg
->data
;
18364 rat
= cp_noti_info
->rat
;
18365 band
= cp_noti_info
->band
;
18366 channel
= cp_noti_info
->channel
;
18368 /* LTE/5G Band/Freq information => Mobile Hotspot channel mapping.
18369 * LTE/B40: 38650~39649 => Ch.11
18370 * LTE/B41: 39650~41589 => Ch.1
18371 * 5G/N41: 499200~537999 => Ch.1
18373 if (rat
== CP_CHAN_INFO_RAT_MODE_LTE
) {
18375 if (channel
>= 38650 && channel
<= 39649) {
18376 mhs_channel_for_4g
= 11;
18377 } else if (channel
>= 39650 && channel
<= 41589) {
18378 mhs_channel_for_4g
= 1;
18381 if (rat
== CP_CHAN_INFO_RAT_MODE_NR5G
) {
18383 if (channel
>= 499200 && channel
<= 537999) {
18384 mhs_channel_for_5g
= 1;
18388 WL_DBG(("[BeyondX] rat: %u, band: %u, channel: %u, mhs_channel_for_4g: %u, "
18389 "mhs_channel_for_5g: %u\n", rat
, band
, channel
,
18390 mhs_channel_for_4g
, mhs_channel_for_5g
));
18392 if (recv_msg_4g
&& recv_msg_5g
) {
18393 if (mhs_channel_for_4g
&& mhs_channel_for_5g
) {
18394 /* if 4G/B40 + 5G/N41, select channel 6 for MHS */
18395 if (mhs_channel_for_4g
== 11 && mhs_channel_for_5g
== 1) {
18396 g_mhs_chan_for_cpcoex
= 6;
18397 /* if 4G(except for B40) + 5G/N41, select channel 1 for MHS */
18399 g_mhs_chan_for_cpcoex
= 1;
18402 g_mhs_chan_for_cpcoex
= mhs_channel_for_4g
? mhs_channel_for_4g
:
18403 mhs_channel_for_5g
? mhs_channel_for_5g
: 0;
18405 mhs_channel_for_4g
= mhs_channel_for_5g
= 0;
18406 recv_msg_4g
= recv_msg_5g
= 0;
18413 static struct notifier_block wl_cfg80211_ril_bridge_notifier
= {
18414 .notifier_call
= wl_cfg80211_ril_bridge_notifier_call
,
18417 static bool wl_cfg80211_ril_bridge_notifier_registered
= FALSE
;
18418 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
18421 wl_cfg80211_netdev_notifier_call(struct notifier_block
* nb
,
18422 unsigned long state
, void *ptr
)
18424 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
18425 struct net_device
*dev
= ptr
;
18427 struct net_device
*dev
= netdev_notifier_info_to_dev(ptr
);
18428 #endif /* LINUX_VERSION < VERSION(3, 11, 0) */
18429 struct wireless_dev
*wdev
= NULL
;
18430 struct bcm_cfg80211
*cfg
= NULL
;
18432 WL_DBG(("Enter state:%lu ndev%p \n", state
, dev
));
18434 WL_ERR(("dev null\n"));
18435 return NOTIFY_DONE
;
18438 wdev
= ndev_to_wdev(dev
);
18440 WL_ERR(("wdev null. Do nothing\n"));
18441 return NOTIFY_DONE
;
18444 cfg
= (struct bcm_cfg80211
*)wiphy_priv(wdev
->wiphy
);
18445 if (!cfg
|| (cfg
!= wl_cfg80211_get_bcmcfg())) {
18446 /* If cfg80211 priv is null or doesn't match return */
18447 WL_ERR(("wrong cfg ptr (%p)\n", cfg
));
18448 return NOTIFY_DONE
;
18451 if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
18452 /* Nothing to be done for primary I/F */
18453 return NOTIFY_DONE
;
18459 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
18460 int max_wait_timeout
= 2;
18461 int max_wait_count
= 100;
18463 unsigned long limit
= jiffies
+ max_wait_timeout
* HZ
;
18464 while (work_pending(&wdev
->cleanup_work
)) {
18465 if (refcnt
%5 == 0) {
18466 WL_ERR(("[NETDEV_DOWN] wait for "
18467 "complete of cleanup_work"
18468 " (%d th)\n", refcnt
));
18470 if (!time_before(jiffies
, limit
)) {
18471 WL_ERR(("[NETDEV_DOWN] cleanup_work"
18472 " of CFG80211 is not"
18473 " completed in %d sec\n",
18474 max_wait_timeout
));
18477 if (refcnt
>= max_wait_count
) {
18478 WL_ERR(("[NETDEV_DOWN] cleanup_work"
18479 " of CFG80211 is not"
18480 " completed in %d loop\n",
18484 set_current_state(TASK_INTERRUPTIBLE
);
18485 (void)schedule_timeout(100);
18486 set_current_state(TASK_RUNNING
);
18489 #endif /* LINUX_VERSION < VERSION(3, 14, 0) */
18492 case NETDEV_UNREGISTER
:
18493 wl_cfg80211_clear_per_bss_ies(cfg
, wdev
);
18494 /* after calling list_del_rcu(&wdev->list) */
18495 wl_dealloc_netinfo_by_wdev(cfg
, wdev
);
18497 case NETDEV_GOING_DOWN
:
18499 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
18500 * In front of door, the function checks whether current scan
18501 * is working or not. If the scanning is still working,
18502 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
18504 if (wl_get_drv_status(cfg
, SCANNING
, dev
))
18505 wl_cfg80211_cancel_scan(cfg
);
18508 return NOTIFY_DONE
;
18511 static struct notifier_block wl_cfg80211_netdev_notifier
= {
18512 .notifier_call
= wl_cfg80211_netdev_notifier_call
,
18516 * to make sure we won't register the same notifier twice, otherwise a loop is likely to be
18517 * created in kernel notifier link list (with 'next' pointing to itself)
18519 static bool wl_cfg80211_netdev_notifier_registered
= FALSE
;
18521 static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211
*cfg
, int enable
)
18523 u32 connected_cnt
= wl_get_drv_status_all(cfg
, CONNECTED
);
18524 bool p2p_connected
= wl_cfgp2p_vif_created(cfg
);
18525 struct net_info
*iter
, *next
;
18527 if (!(cfg
->roam_flags
& WL_ROAM_OFF_ON_CONCURRENT
))
18530 WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
18531 enable
, p2p_connected
, connected_cnt
));
18532 /* Disable FW roam when we have a concurrent P2P connection */
18533 if (enable
&& p2p_connected
&& connected_cnt
> 1) {
18535 /* Mark it as to be reverted */
18536 cfg
->roam_flags
|= WL_ROAM_REVERT_STATUS
;
18537 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18538 for_each_ndev(cfg
, iter
, next
) {
18539 GCC_DIAGNOSTIC_POP();
18540 if (iter
->ndev
&& iter
->wdev
&&
18541 iter
->wdev
->iftype
== NL80211_IFTYPE_STATION
) {
18542 if (wldev_iovar_setint(iter
->ndev
, "roam_off", TRUE
)
18544 iter
->roam_off
= TRUE
;
18547 WL_ERR(("error to enable roam_off\n"));
18552 else if (!enable
&& (cfg
->roam_flags
& WL_ROAM_REVERT_STATUS
)) {
18553 cfg
->roam_flags
&= ~WL_ROAM_REVERT_STATUS
;
18554 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18555 for_each_ndev(cfg
, iter
, next
) {
18556 GCC_DIAGNOSTIC_POP();
18557 if (iter
->ndev
&& iter
->wdev
&&
18558 iter
->wdev
->iftype
== NL80211_IFTYPE_STATION
) {
18559 if (iter
->roam_off
!= WL_INVALID
) {
18560 if (wldev_iovar_setint(iter
->ndev
, "roam_off", FALSE
)
18562 iter
->roam_off
= FALSE
;
18565 WL_ERR(("error to disable roam_off\n"));
18575 static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211
*cfg
)
18577 struct net_info
*iter
, *next
;
18580 u32 pre_ctl_chan
= 0;
18583 u32 connected_cnt
= wl_get_drv_status_all(cfg
, CONNECTED
);
18584 cfg
->vsdb_mode
= false;
18586 if (connected_cnt
<= 1) {
18589 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18590 for_each_ndev(cfg
, iter
, next
) {
18591 GCC_DIAGNOSTIC_POP();
18592 /* p2p discovery iface ndev could be null */
18596 if (wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
)) {
18597 if (wldev_iovar_getint(iter
->ndev
, "chanspec",
18598 (s32
*)&chanspec
) == BCME_OK
) {
18599 chanspec
= wl_chspec_driver_to_host(chanspec
);
18600 ctl_chan
= wf_chspec_ctlchan(chanspec
);
18601 band
= CHSPEC_BAND(chanspec
);
18602 wl_update_prof(cfg
, iter
->ndev
, NULL
,
18603 &chanspec
, WL_PROF_CHAN
);
18605 if (!cfg
->vsdb_mode
) {
18606 if (!pre_ctl_chan
&& ctl_chan
) {
18607 pre_ctl_chan
= ctl_chan
;
18609 } else if (pre_ctl_chan
&& (pre_ctl_chan
!= ctl_chan
) &&
18610 (band
== pre_band
)) {
18611 cfg
->vsdb_mode
= true;
18617 WL_MSG("wlan", "%s concurrency is enabled\n", cfg
->vsdb_mode
? "Multi Channel" : "Same Channel");
18622 wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211
*cfg
)
18624 struct net_info
*iter
, *next
;
18628 bool is_rsdb_supported
= FALSE
;
18629 bool rsdb_mode
= FALSE
;
18631 is_rsdb_supported
= DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_RSDB_MODE
);
18633 if (!is_rsdb_supported
) {
18637 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18638 for_each_ndev(cfg
, iter
, next
) {
18639 GCC_DIAGNOSTIC_POP();
18640 /* p2p discovery iface ndev could be null */
18644 if (wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
)) {
18645 if (wldev_iovar_getint(iter
->ndev
, "chanspec",
18646 (s32
*)&chanspec
) == BCME_OK
) {
18647 chanspec
= wl_chspec_driver_to_host(chanspec
);
18648 band
= CHSPEC_BAND(chanspec
);
18651 if (!pre_band
&& band
) {
18653 } else if (pre_band
&& (pre_band
!= band
)) {
18659 WL_DBG(("RSDB mode is %s\n", rsdb_mode
? "enabled" : "disabled"));
18664 static s32
wl_notifier_change_state(struct bcm_cfg80211
*cfg
, struct net_info
*_net_info
,
18665 enum wl_status state
, bool set
)
18670 chanspec_t chspec
= 0;
18671 struct net_device
*primary_dev
= bcmcfg_to_prmry_ndev(cfg
);
18672 dhd_pub_t
*dhd
= cfg
->pub
;
18674 rtt_status_info_t
*rtt_status
;
18675 #endif /* RTT_SUPPORT */
18676 if (dhd
->busstate
== DHD_BUS_DOWN
) {
18677 WL_ERR(("busstate is DHD_BUS_DOWN!\n"));
18680 WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
18681 state
, set
, _net_info
->pm_restore
, _net_info
->ndev
->name
));
18683 if (state
!= WL_STATUS_CONNECTED
)
18685 mode
= wl_get_mode_by_netdev(cfg
, _net_info
->ndev
);
18687 wl_cfg80211_concurrent_roam(cfg
, 1);
18688 wl_cfg80211_determine_vsdb_mode(cfg
);
18689 if (mode
== WL_MODE_AP
) {
18690 if (wl_add_remove_eventmsg(primary_dev
, WLC_E_P2P_PROBREQ_MSG
, false))
18691 WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
18694 if ((err
= wldev_ioctl_set(_net_info
->ndev
, WLC_SET_PM
, &pm
,
18695 sizeof(pm
))) != 0) {
18696 if (err
== -ENODEV
)
18697 WL_DBG(("%s:netdev not ready\n",
18698 _net_info
->ndev
->name
));
18700 WL_ERR(("%s:error (%d)\n",
18701 _net_info
->ndev
->name
, err
));
18703 wl_cfg80211_update_power_mode(_net_info
->ndev
);
18705 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_SHORT
);
18706 #if defined(WLTDLS)
18707 if (wl_cfg80211_is_concurrent_mode(primary_dev
)) {
18708 err
= wldev_iovar_setint(primary_dev
, "tdls_enable", 0);
18710 #endif /* defined(WLTDLS) */
18712 #ifdef DISABLE_FRAMEBURST_VSDB
18713 if (!DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_HOSTAP_MODE
) &&
18714 wl_cfg80211_is_concurrent_mode(primary_dev
) &&
18715 !wl_cfg80211_determine_p2p_rsdb_mode(cfg
)) {
18716 wl_cfg80211_set_frameburst(cfg
, FALSE
);
18718 #endif /* DISABLE_FRAMEBURST_VSDB */
18719 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18720 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd
) &&
18721 wl_get_drv_status(cfg
, CONNECTED
, bcmcfg_to_prmry_ndev(cfg
))) {
18722 /* Enable frameburst for
18723 * STA/SoftAP concurrent mode
18725 wl_cfg80211_set_frameburst(cfg
, TRUE
);
18727 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
18728 } else { /* clear */
18729 chspec
= INVCHANSPEC
;
18730 /* clear chan information when the net device is disconnected */
18731 wl_update_prof(cfg
, _net_info
->ndev
, NULL
, &chspec
, WL_PROF_CHAN
);
18732 wl_cfg80211_determine_vsdb_mode(cfg
);
18733 if (primary_dev
== _net_info
->ndev
) {
18736 rtt_status
= GET_RTTSTATE(dhd
);
18737 if (rtt_status
->status
!= RTT_ENABLED
) {
18738 #endif /* RTT_SUPPORT */
18739 if (dhd_conf_get_pm(dhd
) >= 0)
18740 pm
= dhd_conf_get_pm(dhd
);
18741 if ((err
= wldev_ioctl_set(_net_info
->ndev
, WLC_SET_PM
, &pm
,
18742 sizeof(pm
))) != 0) {
18743 if (err
== -ENODEV
)
18744 WL_DBG(("%s:netdev not ready\n",
18745 _net_info
->ndev
->name
));
18747 WL_ERR(("%s:error (%d)\n",
18748 _net_info
->ndev
->name
, err
));
18750 wl_cfg80211_update_power_mode(_net_info
->ndev
);
18754 #endif /* RTT_SUPPORT */
18756 wl_cfg80211_concurrent_roam(cfg
, 0);
18757 #if defined(WLTDLS)
18758 if (!wl_cfg80211_is_concurrent_mode(primary_dev
)) {
18759 err
= wldev_iovar_setint(primary_dev
, "tdls_enable", 1);
18761 #endif /* defined(WLTDLS) */
18763 #if defined(DISABLE_FRAMEBURST_VSDB)
18764 if (!DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_HOSTAP_MODE
)) {
18765 wl_cfg80211_set_frameburst(cfg
, TRUE
);
18767 #endif /* DISABLE_FRAMEBURST_VSDB */
18768 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18769 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd
) &&
18770 CHSPEC_IS2G(cfg
->ap_oper_channel
)) {
18771 /* Disable frameburst for stand-alone 2GHz SoftAP */
18772 wl_cfg80211_set_frameburst(cfg
, FALSE
);
18774 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
18779 #ifdef DHD_LOSSLESS_ROAMING
18780 static s32
wl_init_roam_timeout(struct bcm_cfg80211
*cfg
)
18784 /* Init roam timer */
18785 init_timer_compat(&cfg
->roam_timeout
, wl_roam_timeout
, cfg
);
18789 #endif /* DHD_LOSSLESS_ROAMING */
18791 #ifdef CONFIG_SLEEP_MONITOR
18792 extern long long temp_raw
;
18794 int wlan_get_sleep_monitor64_cb(void *priv
, long long *raw_val
,
18795 int check_level
, int caller_type
)
18797 struct bcm_cfg80211
*cfg
= priv
;
18798 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
18799 int state
= DEVICE_UNKNOWN
;
18802 state
= DEVICE_POWER_OFF
;
18804 state
= DEVICE_ON_ACTIVE1
;
18805 if (wl_get_drv_status_all(cfg
, CONNECTED
))
18806 state
= DEVICE_ON_ACTIVE2
;
18808 if (caller_type
== SLEEP_MONITOR_CALL_SUSPEND
) {
18809 *raw_val
= temp_raw
;
18817 static struct sleep_monitor_ops wlan_sleep_monitor_ops
= {
18818 .read64_cb_func
= wlan_get_sleep_monitor64_cb
,
18820 #endif /* CONFIG_SLEEP_MONITOR */
18822 static s32
wl_init_priv(struct bcm_cfg80211
*cfg
)
18824 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
18825 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
18828 cfg
->scan_request
= NULL
;
18829 cfg
->pwr_save
= !!(wiphy
->flags
& WIPHY_FLAG_PS_ON_BY_DEFAULT
);
18830 #ifdef DISABLE_BUILTIN_ROAM
18831 cfg
->roam_on
= false;
18833 cfg
->roam_on
= true;
18834 #endif /* DISABLE_BUILTIN_ROAM */
18835 cfg
->active_scan
= true;
18836 cfg
->rf_blocked
= false;
18837 cfg
->vsdb_mode
= false;
18838 #if defined(BCMSDIO) || defined(BCMDBUS)
18839 cfg
->wlfc_on
= false;
18840 #endif /* BCMSDIO || BCMDBUS */
18841 cfg
->roam_flags
|= WL_ROAM_OFF_ON_CONCURRENT
;
18842 cfg
->disable_roam_event
= false;
18843 /* register interested state */
18844 set_bit(WL_STATUS_CONNECTED
, &cfg
->interrested_state
);
18845 spin_lock_init(&cfg
->cfgdrv_lock
);
18846 mutex_init(&cfg
->ioctl_buf_sync
);
18847 init_waitqueue_head(&cfg
->netif_change_event
);
18848 init_waitqueue_head(&cfg
->wps_done_event
);
18849 init_completion(&cfg
->send_af_done
);
18850 init_completion(&cfg
->iface_disable
);
18851 mutex_init(&cfg
->usr_sync
);
18852 mutex_init(&cfg
->event_sync
);
18853 mutex_init(&cfg
->if_sync
);
18854 mutex_init(&cfg
->scan_sync
);
18855 mutex_init(&cfg
->connect_sync
);
18856 mutex_init(&cfg
->pm_sync
);
18857 mutex_init(&cfg
->in4way_sync
);
18859 mutex_init(&cfg
->tdls_sync
);
18860 #endif /* WLTDLS */
18862 mutex_init(&cfg
->bcn_sync
);
18863 #endif /* WL_BCNRECV */
18865 wl_init_wps_reauth_sm(cfg
);
18866 #endif /* WL_WPS_SYNC */
18868 err
= wl_init_priv_mem(cfg
);
18871 if (wl_create_event_handler(cfg
))
18873 wl_init_event_handler(cfg
);
18874 err
= wl_init_scan(cfg
);
18877 #ifdef DHD_LOSSLESS_ROAMING
18878 err
= wl_init_roam_timeout(cfg
);
18882 #endif /* DHD_LOSSLESS_ROAMING */
18883 wl_init_conf(cfg
->conf
);
18884 wl_init_prof(cfg
, ndev
);
18886 DNGL_FUNC(dhd_cfg80211_init
, (cfg
));
18887 cfg
->pmk_list
->pmkids
.length
= OFFSETOF(pmkid_list_v3_t
, pmkid
);
18888 cfg
->pmk_list
->pmkids
.count
= 0;
18889 cfg
->pmk_list
->pmkids
.version
= PMKID_LIST_VER_3
;
18891 #ifdef CONFIG_SLEEP_MONITOR
18892 sleep_monitor_register_ops(cfg
, &wlan_sleep_monitor_ops
,
18893 SLEEP_MONITOR_WIFI
);
18894 #endif /* CONFIG_SLEEP_MONITOR */
18898 static void wl_deinit_priv(struct bcm_cfg80211
*cfg
)
18900 DNGL_FUNC(dhd_cfg80211_deinit
, (cfg
));
18901 wl_destroy_event_handler(cfg
);
18904 del_timer_sync(&cfg
->scan_timeout
);
18905 #ifdef DHD_LOSSLESS_ROAMING
18906 del_timer_sync(&cfg
->roam_timeout
);
18908 wl_deinit_priv_mem(cfg
);
18909 if (wl_cfg80211_netdev_notifier_registered
) {
18910 wl_cfg80211_netdev_notifier_registered
= FALSE
;
18911 unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier
);
18914 #ifdef CONFIG_SLEEP_MONITOR
18915 sleep_monitor_unregister_ops(SLEEP_MONITOR_WIFI
);
18916 #endif /* CONFIG_SLEEP_MONITOR */
18919 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18920 static s32
wl_cfg80211_attach_p2p(struct bcm_cfg80211
*cfg
)
18922 WL_TRACE(("Enter \n"));
18924 if (wl_cfgp2p_register_ndev(cfg
) < 0) {
18925 WL_ERR(("P2P attach failed. \n"));
18932 static s32
wl_cfg80211_detach_p2p(struct bcm_cfg80211
*cfg
)
18934 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18935 struct wireless_dev
*wdev
;
18936 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18938 WL_DBG(("Enter \n"));
18940 WL_ERR(("Invalid Ptr\n"));
18943 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18945 wdev
= cfg
->p2p_wdev
;
18947 WL_ERR(("Invalid Ptr\n"));
18951 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18953 wl_cfgp2p_unregister_ndev(cfg
);
18955 cfg
->p2p_wdev
= NULL
;
18956 cfg
->p2p_net
= NULL
;
18957 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18958 WL_DBG(("Freeing 0x%p \n", wdev
));
18959 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
18960 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18964 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
18966 static s32
wl_cfg80211_attach_post(struct net_device
*ndev
)
18968 struct bcm_cfg80211
* cfg
;
18971 WL_TRACE(("In\n"));
18972 if (unlikely(!ndev
)) {
18973 WL_ERR(("ndev is invaild\n"));
18976 cfg
= wl_get_cfg(ndev
);
18977 if (unlikely(!cfg
)) {
18978 WL_ERR(("cfg is invaild\n"));
18981 if (!wl_get_drv_status(cfg
, READY
, ndev
)) {
18983 ret
= wl_cfgp2p_supported(cfg
, ndev
);
18985 #if !defined(WL_ENABLE_P2P_IF)
18986 cfg
->wdev
->wiphy
->interface_modes
|=
18987 (BIT(NL80211_IFTYPE_P2P_CLIENT
)|
18988 BIT(NL80211_IFTYPE_P2P_GO
));
18989 #endif /* !WL_ENABLE_P2P_IF */
18990 if ((err
= wl_cfgp2p_init_priv(cfg
)) != 0)
18993 #if defined(WL_ENABLE_P2P_IF)
18994 if (cfg
->p2p_net
) {
18995 /* Update MAC addr for p2p0 interface here. */
18996 memcpy(cfg
->p2p_net
->dev_addr
, ndev
->dev_addr
, ETH_ALEN
);
18997 cfg
->p2p_net
->dev_addr
[0] |= 0x02;
18998 WL_MSG(cfg
->p2p_net
->name
, "p2p_dev_addr="MACDBG
"\n",
18999 MAC2STRDBG(cfg
->p2p_net
->dev_addr
));
19001 WL_ERR(("p2p_net not yet populated."
19002 " Couldn't update the MAC Address for p2p0 \n"));
19005 #endif /* WL_ENABLE_P2P_IF */
19006 cfg
->p2p_supported
= true;
19007 } else if (ret
== 0) {
19008 if ((err
= wl_cfgp2p_init_priv(cfg
)) != 0)
19011 /* SDIO bus timeout */
19017 wl_set_drv_status(cfg
, READY
, ndev
);
19022 struct bcm_cfg80211
*wl_get_cfg(struct net_device
*ndev
)
19024 struct wireless_dev
*wdev
= ndev
->ieee80211_ptr
;
19026 if (!wdev
|| !wdev
->wiphy
)
19029 return wiphy_priv(wdev
->wiphy
);
19033 wl_cfg80211_net_attach(struct net_device
*primary_ndev
)
19035 struct bcm_cfg80211
*cfg
= wl_get_cfg(primary_ndev
);
19038 WL_ERR(("cfg null\n"));
19041 #ifdef WL_STATIC_IF
19042 /* Register dummy n/w iface. FW init will happen only from dev_open */
19043 if (wl_cfg80211_register_static_if(cfg
, NL80211_IFTYPE_STATION
,
19044 WL_STATIC_IFNAME_PREFIX
) == NULL
) {
19045 WL_ERR(("static i/f registration failed!\n"));
19048 #endif /* WL_STATIC_IF */
19052 s32
wl_cfg80211_attach(struct net_device
*ndev
, void *context
)
19054 struct wireless_dev
*wdev
;
19055 struct bcm_cfg80211
*cfg
;
19057 struct device
*dev
;
19060 dhd_pub_t
*dhd
= (struct dhd_pub
*)(context
);
19062 WL_TRACE(("In\n"));
19064 WL_ERR(("ndev is invaild\n"));
19067 WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
19068 dev
= wl_cfg80211_get_parent_dev();
19070 wdev
= (struct wireless_dev
*)MALLOCZ(dhd
->osh
, sizeof(*wdev
));
19071 if (unlikely(!wdev
)) {
19072 WL_ERR(("Could not allocate wireless device\n"));
19075 err
= wl_setup_wiphy(wdev
, dev
, context
);
19076 if (unlikely(err
)) {
19077 MFREE(dhd
->osh
, wdev
, sizeof(*wdev
));
19080 #ifdef WLMESH_CFG80211
19081 wdev
->iftype
= wl_mode_to_nl80211_iftype(WL_MODE_MESH
);
19083 wdev
->iftype
= wl_mode_to_nl80211_iftype(WL_MODE_BSS
);
19085 cfg
= wiphy_priv(wdev
->wiphy
);
19087 cfg
->pub
= context
;
19088 cfg
->osh
= dhd
->osh
;
19089 INIT_LIST_HEAD(&cfg
->net_list
);
19091 INIT_LIST_HEAD(&cfg
->wbtext_bssid_list
);
19092 #endif /* WBTEXT */
19093 INIT_LIST_HEAD(&cfg
->vndr_oui_list
);
19094 spin_lock_init(&cfg
->vndr_oui_sync
);
19095 spin_lock_init(&cfg
->net_list_sync
);
19096 ndev
->ieee80211_ptr
= wdev
;
19097 SET_NETDEV_DEV(ndev
, wiphy_dev(wdev
->wiphy
));
19098 wdev
->netdev
= ndev
;
19099 cfg
->state_notifier
= wl_notifier_change_state
;
19100 err
= wl_alloc_netinfo(cfg
, ndev
, wdev
, WL_IF_TYPE_STA
, PM_ENABLE
, bssidx
, ifidx
);
19102 WL_ERR(("Failed to alloc net_info (%d)\n", err
));
19103 goto cfg80211_attach_out
;
19105 err
= wl_init_priv(cfg
);
19107 WL_ERR(("Failed to init iwm_priv (%d)\n", err
));
19108 goto cfg80211_attach_out
;
19111 err
= wl_setup_rfkill(cfg
, TRUE
);
19113 WL_ERR(("Failed to setup rfkill %d\n", err
));
19114 goto cfg80211_attach_out
;
19116 #ifdef DEBUGFS_CFG80211
19117 err
= wl_setup_debugfs(cfg
);
19119 WL_ERR(("Failed to setup debugfs %d\n", err
));
19120 goto cfg80211_attach_out
;
19123 if (!wl_cfg80211_netdev_notifier_registered
) {
19124 wl_cfg80211_netdev_notifier_registered
= TRUE
;
19125 err
= register_netdevice_notifier(&wl_cfg80211_netdev_notifier
);
19127 wl_cfg80211_netdev_notifier_registered
= FALSE
;
19128 WL_ERR(("Failed to register notifierl %d\n", err
));
19129 goto cfg80211_attach_out
;
19133 #if defined(COEX_DHCP)
19134 cfg
->btcoex_info
= wl_cfg80211_btcoex_init(cfg
->wdev
->netdev
);
19135 if (!cfg
->btcoex_info
)
19136 goto cfg80211_attach_out
;
19139 #if defined(SUPPORT_RANDOM_MAC_SCAN)
19140 cfg
->random_mac_enabled
= FALSE
;
19141 #endif /* SUPPORT_RANDOM_MAC_SCAN */
19143 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
19144 wdev
->wiphy
->reg_notifier
= wl_cfg80211_reg_notifier
;
19145 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
19147 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
19148 err
= wl_cfg80211_attach_p2p(cfg
);
19150 goto cfg80211_attach_out
;
19151 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
19153 INIT_DELAYED_WORK(&cfg
->pm_enable_work
, wl_cfg80211_work_handler
);
19154 INIT_DELAYED_WORK(&cfg
->loc
.work
, wl_cfgscan_listen_complete_work
);
19155 mutex_init(&cfg
->pm_sync
);
19157 err
= wl_cfgnan_attach(cfg
);
19159 WL_ERR(("Failed to attach nan module %d\n", err
));
19160 goto cfg80211_attach_out
;
19162 #endif /* WL_NAN */
19163 cfg
->rssi_sum_report
= FALSE
;
19165 wl_bad_ap_mngr_init(cfg
);
19166 #endif /* WL_BAM */
19168 #ifdef BIGDATA_SOFTAP
19169 wl_attach_ap_stainfo(cfg
);
19170 #endif /* BIGDATA_SOFTAP */
19174 cfg80211_attach_out
:
19175 wl_cfg80211_detach(cfg
);
19179 void wl_cfg80211_detach(struct bcm_cfg80211
*cfg
)
19181 WL_DBG(("Enter\n"));
19185 /* clean up pm_enable work item. Remove this once deinit is properly
19186 * clean up and wl_cfg8021_down is called while removing the module
19188 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_DEL
);
19190 #if defined(COEX_DHCP)
19191 wl_cfg80211_btcoex_deinit();
19192 cfg
->btcoex_info
= NULL
;
19195 wl_setup_rfkill(cfg
, FALSE
);
19196 #ifdef DEBUGFS_CFG80211
19197 wl_free_debugfs(cfg
);
19199 if (cfg
->p2p_supported
) {
19200 if (timer_pending(&cfg
->p2p
->listen_timer
))
19201 del_timer_sync(&cfg
->p2p
->listen_timer
);
19202 wl_cfgp2p_deinit_priv(cfg
);
19206 wl_deinit_wps_reauth_sm(cfg
);
19207 #endif /* WL_WPS_SYNC */
19209 if (timer_pending(&cfg
->scan_timeout
))
19210 del_timer_sync(&cfg
->scan_timeout
);
19211 #ifdef DHD_LOSSLESS_ROAMING
19212 if (timer_pending(&cfg
->roam_timeout
)) {
19213 del_timer_sync(&cfg
->roam_timeout
);
19215 #endif /* DHD_LOSSLESS_ROAMING */
19217 #ifdef WL_STATIC_IF
19218 wl_cfg80211_unregister_static_if(cfg
);
19219 #endif /* WL_STATIC_IF */
19220 #if defined(WL_CFG80211_P2P_DEV_IF)
19222 wl_cfgp2p_del_p2p_disc_if(cfg
->p2p_wdev
, cfg
);
19223 #endif /* WL_CFG80211_P2P_DEV_IF */
19224 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
19225 wl_cfg80211_detach_p2p(cfg
);
19226 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
19228 wl_bad_ap_mngr_deinit(cfg
);
19229 #endif /* WL_BAM */
19231 #ifdef BIGDATA_SOFTAP
19232 wl_detach_ap_stainfo(cfg
);
19233 #endif /* BIGDATA_SOFTAP */
19236 wl_cfgnan_detach(cfg
);
19237 #endif /* WL_NAN */
19238 wl_cfg80211_ibss_vsie_free(cfg
);
19239 wl_dealloc_netinfo_by_wdev(cfg
, cfg
->wdev
);
19240 wl_cfg80211_set_bcmcfg(NULL
);
19241 wl_deinit_priv(cfg
);
19242 wl_cfg80211_clear_parent_dev();
19243 #if defined(RSSIAVG)
19244 wl_free_rssi_cache(&cfg
->g_rssi_cache_ctrl
);
19245 wl_free_rssi_cache(&cfg
->g_connected_rssi_cache_ctrl
);
19247 #if defined(BSSCACHE)
19248 wl_release_bss_cache_ctrl(&cfg
->g_bss_cache_ctrl
);
19251 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
19252 * structure "cfg", which is the private part of wiphy, has been freed in
19253 * wl_free_wdev !!!!!!!!!!!
19255 WL_DBG(("Exit\n"));
19258 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
19259 void wl_cfg80211_register_dev_ril_bridge_event_notifier()
19261 WL_DBG(("Enter\n"));
19262 if (!wl_cfg80211_ril_bridge_notifier_registered
) {
19264 wl_cfg80211_ril_bridge_notifier_registered
= TRUE
;
19265 err
= register_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier
);
19267 wl_cfg80211_ril_bridge_notifier_registered
= FALSE
;
19268 WL_ERR(("Failed to register ril_notifier! %d\n", err
));
19273 void wl_cfg80211_unregister_dev_ril_bridge_event_notifier()
19275 WL_DBG(("Enter\n"));
19276 if (wl_cfg80211_ril_bridge_notifier_registered
) {
19277 wl_cfg80211_ril_bridge_notifier_registered
= FALSE
;
19278 unregister_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier
);
19281 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
19283 static void wl_print_event_data(struct bcm_cfg80211
*cfg
,
19284 uint32 event_type
, const wl_event_msg_t
*e
)
19286 s32 status
= ntoh32(e
->status
);
19287 s32 reason
= ntoh32(e
->reason
);
19288 s32 ifidx
= ntoh32(e
->ifidx
);
19289 s32 bssidx
= ntoh32(e
->bsscfgidx
);
19291 switch (event_type
) {
19292 case WLC_E_ESCAN_RESULT
:
19293 if ((status
== WLC_E_STATUS_SUCCESS
) ||
19294 (status
== WLC_E_STATUS_ABORT
)) {
19295 WL_INFORM_MEM(("event_type (%d), ifidx: %d"
19296 " bssidx: %d scan_type:%d\n",
19297 event_type
, ifidx
, bssidx
, status
));
19301 case WLC_E_DISASSOC
:
19302 case WLC_E_DISASSOC_IND
:
19304 case WLC_E_DEAUTH_IND
:
19305 WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
19306 " status:%d reason:%d\n",
19307 event_type
, ifidx
, bssidx
, status
, reason
));
19311 /* Print only when DBG verbose is enabled */
19312 WL_DBG(("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
19313 event_type
, ifidx
, bssidx
, status
, reason
));
19317 static void wl_event_handler(struct work_struct
*work_data
)
19319 struct bcm_cfg80211
*cfg
= NULL
;
19320 struct wl_event_q
*e
;
19321 struct wireless_dev
*wdev
= NULL
;
19323 WL_DBG(("Enter \n"));
19324 BCM_SET_CONTAINER_OF(cfg
, work_data
, struct bcm_cfg80211
, event_work
);
19325 LOG_TS(cfg
, wl_evt_hdlr_entry
);
19326 DHD_EVENT_WAKE_LOCK(cfg
->pub
);
19327 while ((e
= wl_deq_event(cfg
))) {
19328 s32 status
= ntoh32(e
->emsg
.status
);
19329 u32 event_type
= ntoh32(e
->emsg
.event_type
);
19330 bool scan_cmplt_evt
= (event_type
== WLC_E_ESCAN_RESULT
) &&
19331 ((status
== WLC_E_STATUS_SUCCESS
) || (status
== WLC_E_STATUS_ABORT
));
19333 LOG_TS(cfg
, wl_evt_deq
);
19334 if (scan_cmplt_evt
) {
19335 LOG_TS(cfg
, scan_deq
);
19337 /* Print only critical events to avoid too many prints */
19338 wl_print_event_data(cfg
, e
->etype
, &e
->emsg
);
19340 if (e
->emsg
.ifidx
> WL_MAX_IFS
) {
19341 WL_ERR((" Event ifidx not in range. val:%d \n", e
->emsg
.ifidx
));
19345 /* Make sure iface operations, don't creat race conditions */
19346 mutex_lock(&cfg
->if_sync
);
19347 if (!(wdev
= wl_get_wdev_by_fw_idx(cfg
,
19348 e
->emsg
.bsscfgidx
, e
->emsg
.ifidx
))) {
19349 /* For WLC_E_IF would be handled by wl_host_event */
19350 if (e
->etype
!= WLC_E_IF
)
19351 WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
19352 " Ignoring event.\n", e
->emsg
.bsscfgidx
));
19353 } else if (e
->etype
< WLC_E_LAST
&& cfg
->evt_handler
[e
->etype
]) {
19354 dhd_pub_t
*dhd
= (struct dhd_pub
*)(cfg
->pub
);
19355 if (dhd
->busstate
== DHD_BUS_DOWN
) {
19356 WL_ERR((": BUS is DOWN.\n"));
19359 WL_DBG(("event_type %d event_sub %d\n",
19360 ntoh32(e
->emsg
.event_type
),
19361 ntoh32(e
->emsg
.reason
)));
19362 cfg
->evt_handler
[e
->etype
](cfg
, wdev_to_cfgdev(wdev
),
19363 &e
->emsg
, e
->edata
);
19364 if (scan_cmplt_evt
) {
19365 LOG_TS(cfg
, scan_hdlr_cmplt
);
19369 WL_DBG(("Unknown Event (%d): ignoring\n", e
->etype
));
19371 mutex_unlock(&cfg
->if_sync
);
19373 wl_put_event(cfg
, e
);
19374 if (scan_cmplt_evt
) {
19375 LOG_TS(cfg
, scan_cmplt
);
19377 LOG_TS(cfg
, wl_evt_hdlr_exit
);
19379 DHD_EVENT_WAKE_UNLOCK(cfg
->pub
);
19383 * Generic API to handle critical events which doesnt need
19384 * cfg enquening and sleepable API calls.
19387 wl_cfg80211_handle_critical_events(struct bcm_cfg80211
*cfg
,
19388 const wl_event_msg_t
* e
)
19390 s32 ret
= BCME_ERROR
;
19391 u32 event_type
= ntoh32(e
->event_type
);
19393 if (event_type
>= WLC_E_LAST
) {
19397 switch (event_type
) {
19398 case WLC_E_NAN_CRITICAL
: {
19400 if (ntoh32(e
->reason
) == WL_NAN_EVENT_STOP
) {
19401 WL_DBG(("Received WL_NAN_EVENT_STOP\n"));
19403 #endif /* WL_NAN */
19413 wl_cfg80211_event(struct net_device
*ndev
, const wl_event_msg_t
* e
, void *data
)
19415 s32 status
= ntoh32(e
->status
);
19416 u32 event_type
= ntoh32(e
->event_type
);
19417 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
19418 struct net_info
*netinfo
;
19420 WL_DBG(("event_type (%d): reason (%d): %s\n", event_type
, ntoh32(e
->reason
),
19421 bcmevent_get_name(event_type
)));
19422 if ((cfg
== NULL
) || (cfg
->p2p_supported
&& cfg
->p2p
== NULL
)) {
19423 WL_ERR(("Stale event ignored\n"));
19427 if (cfg
->event_workq
== NULL
) {
19428 WL_ERR(("Event handler is not created\n"));
19432 if (event_type
== WLC_E_IF
) {
19433 /* Don't process WLC_E_IF events in wl_cfg80211 layer */
19437 netinfo
= wl_get_netinfo_by_fw_idx(cfg
, e
->bsscfgidx
, e
->ifidx
);
19439 /* Since the netinfo entry is not there, the netdev entry is not
19440 * created via cfg80211 interface. so the event is not of interest
19441 * to the cfg80211 layer.
19443 WL_TRACE(("ignore event %d, not interested\n", event_type
));
19447 /* Handle wl_cfg80211_critical_events */
19448 if (wl_cfg80211_handle_critical_events(cfg
, e
) == BCME_OK
) {
19452 if (event_type
== WLC_E_PFN_NET_FOUND
) {
19453 WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
19455 else if (event_type
== WLC_E_PFN_NET_LOST
) {
19456 WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
19459 if (likely(!wl_enq_event(cfg
, ndev
, event_type
, e
, data
))) {
19461 queue_work(cfg
->event_workq
, &cfg
->event_work
);
19464 /* Mark timeout value for thread sched */
19465 if ((event_type
== WLC_E_ESCAN_RESULT
) &&
19466 ((status
== WLC_E_STATUS_SUCCESS
) ||
19467 (status
== WLC_E_STATUS_ABORT
))) {
19468 LOG_TS(cfg
, scan_enq
);
19469 WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
19470 status
, work_busy(&cfg
->event_work
)));
19474 static void wl_init_eq(struct bcm_cfg80211
*cfg
)
19476 wl_init_eq_lock(cfg
);
19477 INIT_LIST_HEAD(&cfg
->eq_list
);
19480 static void wl_flush_eq(struct bcm_cfg80211
*cfg
)
19482 struct wl_event_q
*e
;
19483 unsigned long flags
;
19485 flags
= wl_lock_eq(cfg
);
19486 while (!list_empty_careful(&cfg
->eq_list
)) {
19487 BCM_SET_LIST_FIRST_ENTRY(e
, &cfg
->eq_list
, struct wl_event_q
, eq_list
);
19488 list_del(&e
->eq_list
);
19489 MFREE(cfg
->osh
, e
, e
->datalen
+ sizeof(struct wl_event_q
));
19491 wl_unlock_eq(cfg
, flags
);
19495 * retrieve first queued event from head
19498 static struct wl_event_q
*wl_deq_event(struct bcm_cfg80211
*cfg
)
19500 struct wl_event_q
*e
= NULL
;
19501 unsigned long flags
;
19503 flags
= wl_lock_eq(cfg
);
19504 if (likely(!list_empty(&cfg
->eq_list
))) {
19505 BCM_SET_LIST_FIRST_ENTRY(e
, &cfg
->eq_list
, struct wl_event_q
, eq_list
);
19506 list_del(&e
->eq_list
);
19508 wl_unlock_eq(cfg
, flags
);
19514 * push event to tail of the queue
19518 wl_enq_event(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u32 event
,
19519 const wl_event_msg_t
*msg
, void *data
)
19521 struct wl_event_q
*e
;
19525 unsigned long flags
;
19529 data_len
= ntoh32(msg
->datalen
);
19530 evtq_size
= (uint32
)(sizeof(struct wl_event_q
) + data_len
);
19531 e
= (struct wl_event_q
*)MALLOCZ(cfg
->osh
, evtq_size
);
19532 if (unlikely(!e
)) {
19533 WL_ERR(("event alloc failed\n"));
19537 memcpy(&e
->emsg
, msg
, sizeof(wl_event_msg_t
));
19539 memcpy(e
->edata
, data
, data_len
);
19540 e
->datalen
= data_len
;
19541 flags
= wl_lock_eq(cfg
);
19542 list_add_tail(&e
->eq_list
, &cfg
->eq_list
);
19543 wl_unlock_eq(cfg
, flags
);
19548 static void wl_put_event(struct bcm_cfg80211
*cfg
, struct wl_event_q
*e
)
19550 MFREE(cfg
->osh
, e
, e
->datalen
+ sizeof(struct wl_event_q
));
19553 static s32
wl_config_infra(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u16 iftype
)
19557 bool skip_infra
= false;
19560 case WL_IF_TYPE_IBSS
:
19561 case WL_IF_TYPE_AIBSS
:
19564 case WL_IF_TYPE_AP
:
19565 case WL_IF_TYPE_STA
:
19566 case WL_IF_TYPE_P2P_GO
:
19567 case WL_IF_TYPE_P2P_GC
:
19568 /* Intentional fall through */
19571 #ifdef WLMESH_CFG80211
19572 case NL80211_IFTYPE_MESH_POINT
:
19573 infra
= WL_BSSTYPE_MESH
;
19575 #endif /* WLMESH_CFG80211 */
19576 case WL_IF_TYPE_MONITOR
:
19578 case WL_IF_TYPE_NAN
:
19579 /* Intentionall fall through */
19582 WL_ERR(("Skipping infra setting for type:%d\n", iftype
));
19586 /* /TODO Infra iovar is stored in default bss first and
19587 * then applied to the next upcoming bss. so if there is
19588 * some other concurrent bss coming up in parallel, it
19589 * can cause problem. Ideally this iovar should get directly
19590 * applied on the target bsscfg.
19593 infra
= htod32(infra
);
19594 err
= wldev_ioctl_set(ndev
, WLC_SET_INFRA
, &infra
, sizeof(infra
));
19595 if (unlikely(err
)) {
19596 WL_ERR(("WLC_SET_INFRA error (%d)\n", err
));
19603 void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf
*ev
, u16 event
, bool set
)
19605 if (!ev
|| (event
> WLC_E_LAST
))
19608 if (ev
->num
< MAX_EVENT_BUF_NUM
) {
19609 ev
->event
[ev
->num
].type
= event
;
19610 ev
->event
[ev
->num
].set
= set
;
19613 WL_ERR(("evenbuffer doesn't support > %u events. Update"
19614 " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM
));
19619 s32
wl_cfg80211_apply_eventbuffer(
19620 struct net_device
*ndev
,
19621 struct bcm_cfg80211
*cfg
,
19622 wl_eventmsg_buf_t
*ev
)
19624 int i
, ret
= BCME_OK
;
19625 s8 event_buf
[WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
] = {0};
19626 /* Room for "event_msgs_ext" + '\0' + bitvec */
19627 char iovbuf
[WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
+ 16];
19628 eventmsgs_ext_t
*eventmask_msg
;
19629 s32 msglen
= WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
;
19631 if (!ev
|| (!ev
->num
)) {
19635 mutex_lock(&cfg
->event_sync
);
19637 eventmask_msg
= (eventmsgs_ext_t
*)event_buf
;
19638 eventmask_msg
->ver
= EVENTMSGS_VER
;
19639 eventmask_msg
->command
= EVENTMSGS_NONE
;
19640 eventmask_msg
->len
= WL_EVENTING_MASK_EXT_LEN
;
19641 eventmask_msg
->maxgetsize
= WL_EVENTING_MASK_EXT_LEN
;
19643 /* Read event_msgs mask */
19644 ret
= wldev_iovar_getbuf(ndev
, "event_msgs_ext",
19645 eventmask_msg
, EVENTMSGS_EXT_STRUCT_SIZE
,
19650 if (unlikely(ret
)) {
19651 WL_ERR(("Get event_msgs error (%d)\n", ret
));
19655 bcopy(iovbuf
, eventmask_msg
, msglen
);
19657 /* apply the set bits */
19658 for (i
= 0; i
< ev
->num
; i
++) {
19659 if (ev
->event
[i
].set
)
19660 setbit(eventmask_msg
->mask
, ev
->event
[i
].type
);
19662 clrbit(eventmask_msg
->mask
, ev
->event
[i
].type
);
19665 /* Write updated Event mask */
19666 eventmask_msg
->ver
= EVENTMSGS_VER
;
19667 eventmask_msg
->command
= EVENTMSGS_SET_MASK
;
19668 eventmask_msg
->len
= WL_EVENTING_MASK_EXT_LEN
;
19670 /* Write updated Event mask */
19671 ret
= wldev_iovar_setbuf(ndev
, "event_msgs_ext", eventmask_msg
,
19672 WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
,
19673 iovbuf
, sizeof(iovbuf
), NULL
);
19675 if (unlikely(ret
)) {
19676 WL_ERR(("Set event_msgs error (%d)\n", ret
));
19680 mutex_unlock(&cfg
->event_sync
);
19684 s32
wl_add_remove_eventmsg(struct net_device
*ndev
, u16 event
, bool add
)
19687 s8 event_buf
[WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
] = {0};
19688 eventmsgs_ext_t
*eventmask_msg
= NULL
;
19689 struct bcm_cfg80211
*cfg
;
19690 /* Room for "event_msgs_ext" + '\0' + bitvec */
19691 char iovbuf
[WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
+ 16];
19692 s32 msglen
= WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
;
19697 cfg
= wl_get_cfg(ndev
);
19701 mutex_lock(&cfg
->event_sync
);
19703 eventmask_msg
= (eventmsgs_ext_t
*)event_buf
;
19704 eventmask_msg
->ver
= EVENTMSGS_VER
;
19705 eventmask_msg
->command
= EVENTMSGS_NONE
;
19706 eventmask_msg
->len
= WL_EVENTING_MASK_EXT_LEN
;
19707 eventmask_msg
->maxgetsize
= WL_EVENTING_MASK_EXT_LEN
;
19709 /* Read event_msgs mask */
19710 err
= wldev_iovar_getbuf(ndev
, "event_msgs_ext",
19711 eventmask_msg
, EVENTMSGS_EXT_STRUCT_SIZE
,
19716 if (unlikely(err
)) {
19717 WL_ERR(("Get event_msgs error (%d)\n", err
));
19721 bcopy(iovbuf
, eventmask_msg
, msglen
);
19724 setbit(eventmask_msg
->mask
, event
);
19726 clrbit(eventmask_msg
->mask
, event
);
19729 /* Write updated Event mask */
19730 eventmask_msg
->ver
= EVENTMSGS_VER
;
19731 eventmask_msg
->command
= EVENTMSGS_SET_MASK
;
19732 eventmask_msg
->len
= WL_EVENTING_MASK_EXT_LEN
;
19734 err
= wldev_iovar_setbuf(ndev
, "event_msgs_ext", eventmask_msg
,
19735 WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
,
19736 iovbuf
, sizeof(iovbuf
), NULL
);
19738 if (unlikely(err
)) {
19739 WL_ERR(("Set event_msgs error (%d)\n", err
));
19744 mutex_unlock(&cfg
->event_sync
);
19749 wl_cfg80211_generate_mac_addr(struct ether_addr
*ea_addr
)
19751 RANDOM_BYTES(ea_addr
->octet
, ETHER_ADDR_LEN
);
19752 /* restore mcast and local admin bits to 0 and 1 */
19753 ETHER_SET_UNICAST(ea_addr
->octet
);
19754 ETHER_SET_LOCALADDR(ea_addr
->octet
);
19755 WL_ERR(("%s:generated new MAC="MACDBG
" \n",
19756 __FUNCTION__
, MAC2STRDBG(ea_addr
->octet
)));
19760 static s32
wl_update_chan_param(struct net_device
*dev
, u32 cur_chan
,
19761 struct ieee80211_channel
*band_chan
, bool *dfs_radar_disabled
, bool legacy_chan_info
)
19764 u32 channel
= cur_chan
;
19766 if (!(*dfs_radar_disabled
)) {
19767 if (legacy_chan_info
) {
19768 channel
|= WL_CHANSPEC_BW_20
;
19769 channel
= wl_chspec_host_to_driver(channel
);
19770 err
= wldev_iovar_getint(dev
, "per_chan_info", &channel
);
19773 if (channel
& WL_CHAN_RADAR
) {
19774 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
19775 band_chan
->flags
|= (IEEE80211_CHAN_RADAR
|
19776 IEEE80211_CHAN_NO_IBSS
);
19778 band_chan
->flags
|= IEEE80211_CHAN_RADAR
;
19781 if (channel
& WL_CHAN_PASSIVE
) {
19782 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
19783 band_chan
->flags
|= IEEE80211_CHAN_PASSIVE_SCAN
;
19785 band_chan
->flags
|= IEEE80211_CHAN_NO_IR
;
19788 } else if (err
== BCME_UNSUPPORTED
) {
19789 *dfs_radar_disabled
= TRUE
;
19790 WL_ERR(("does not support per_chan_info\n"));
19797 static int wl_construct_reginfo(struct bcm_cfg80211
*cfg
, s32 bw_cap
)
19799 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
19800 struct ieee80211_channel
*band_chan_arr
= NULL
;
19802 u32 i
, j
, index
, channel
, array_size
= 0;
19803 chanspec_t chspec
= 0;
19806 bool dfs_radar_disabled
= FALSE
;
19807 bool legacy_chan_info
= FALSE
;
19810 #define LOCAL_BUF_LEN 4096
19811 list
= MALLOCZ(cfg
->osh
, LOCAL_BUF_LEN
);
19812 if (list
== NULL
) {
19813 WL_ERR(("failed to allocate local buf\n"));
19817 err
= wldev_iovar_getbuf_bsscfg(dev
, "chan_info_list", NULL
,
19818 0, list
, LOCAL_BUF_LEN
, 0, &cfg
->ioctl_buf_sync
);
19819 if (err
== BCME_UNSUPPORTED
) {
19820 WL_INFORM(("get chan_info_list, UNSUPPORTED\n"));
19821 err
= wldev_iovar_getbuf_bsscfg(dev
, "chanspecs", NULL
,
19822 0, list
, LOCAL_BUF_LEN
, 0, &cfg
->ioctl_buf_sync
);
19823 if (err
!= BCME_OK
) {
19824 WL_ERR(("get chanspecs err(%d)\n", err
));
19825 MFREE(cfg
->osh
, list
, LOCAL_BUF_LEN
);
19828 /* Update indicating legacy chan info usage */
19829 legacy_chan_info
= TRUE
;
19830 } else if (err
!= BCME_OK
) {
19831 WL_ERR(("get chan_info_list err(%d)\n", err
));
19832 MFREE(cfg
->osh
, list
, LOCAL_BUF_LEN
);
19836 WL_CHANNEL_ARRAY_INIT(__wl_2ghz_channels
);
19837 WL_CHANNEL_ARRAY_INIT(__wl_5ghz_a_channels
);
19839 list_count
= legacy_chan_info
? ((wl_uint32_list_t
*)list
)->count
:
19840 ((wl_chanspec_list_v1_t
*)list
)->count
;
19841 for (i
= 0; i
< dtoh32(list_count
); i
++) {
19843 ht40_allowed
= false;
19844 if (legacy_chan_info
) {
19845 chspec
= (chanspec_t
)dtoh32(((wl_uint32_list_t
*)list
)->element
[i
]);
19847 chspec
= (chanspec_t
)dtoh32
19848 (((wl_chanspec_list_v1_t
*)list
)->chspecs
[i
].chanspec
);
19850 chspec
= wl_chspec_driver_to_host(chspec
);
19851 channel
= wf_chspec_ctlchan(chspec
);
19853 if (!CHSPEC_IS40(chspec
) &&
19854 !CHSPEC_IS20(chspec
)) {
19855 WL_DBG(("HT80/160/80p80 center channel : %d\n", channel
));
19858 if (CHSPEC_IS2G(chspec
) && (channel
>= CH_MIN_2G_CHANNEL
) &&
19859 (channel
<= CH_MAX_2G_CHANNEL
)) {
19860 band_chan_arr
= __wl_2ghz_channels
;
19861 array_size
= ARRAYSIZE(__wl_2ghz_channels
);
19862 ht40_allowed
= (bw_cap
== WLC_N_BW_40ALL
)? true : false;
19865 /* Currently due to lack of kernel support both 6GHz and 5GHz
19866 * channels are published under 5GHz band
19868 (CHSPEC_IS6G(chspec
) && (channel
>= CH_MIN_6G_CHANNEL
) &&
19869 (channel
<= CH_MAX_6G_CHANNEL
)) ||
19870 #endif /* WL_6G_BAND */
19871 (CHSPEC_IS5G(chspec
) && channel
>= CH_MIN_5G_CHANNEL
)) {
19872 band_chan_arr
= __wl_5ghz_a_channels
;
19873 array_size
= ARRAYSIZE(__wl_5ghz_a_channels
);
19874 ht40_allowed
= (bw_cap
== WLC_N_BW_20ALL
)? false : true;
19876 WL_ERR(("Invalid channel Sepc. 0x%x.\n", chspec
));
19879 if (!ht40_allowed
&& CHSPEC_IS40(chspec
))
19881 for (j
= 0; j
< array_size
; j
++) {
19882 if (band_chan_arr
[j
].hw_value
== chspec
) {
19887 if (!dhd_conf_match_channel(cfg
->pub
, channel
))
19889 if (index
< array_size
) {
19890 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
19891 band_chan_arr
[index
].center_freq
=
19892 ieee80211_channel_to_frequency(channel
);
19894 band_chan_arr
[index
].center_freq
=
19895 wl_channel_to_frequency(channel
, CHSPEC_BAND(chspec
));
19897 band_chan_arr
[index
].hw_value
= chspec
;
19898 band_chan_arr
[index
].beacon_found
= false;
19899 band_chan_arr
[index
].flags
&= ~IEEE80211_CHAN_DISABLED
;
19901 if (CHSPEC_IS40(chspec
) && ht40_allowed
) {
19902 /* assuming the order is HT20, HT40 Upper,
19903 * HT40 lower from chanspecs
19905 u32 ht40_flag
= band_chan_arr
[index
].flags
& IEEE80211_CHAN_NO_HT40
;
19906 if (CHSPEC_SB_UPPER(chspec
)) {
19907 if (ht40_flag
== IEEE80211_CHAN_NO_HT40
)
19908 band_chan_arr
[index
].flags
&=
19909 ~IEEE80211_CHAN_NO_HT40
;
19910 band_chan_arr
[index
].flags
|= IEEE80211_CHAN_NO_HT40PLUS
;
19912 /* It should be one of
19913 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
19915 band_chan_arr
[index
].flags
&= ~IEEE80211_CHAN_NO_HT40
;
19916 if (ht40_flag
== IEEE80211_CHAN_NO_HT40
)
19917 band_chan_arr
[index
].flags
|=
19918 IEEE80211_CHAN_NO_HT40MINUS
;
19921 band_chan_arr
[index
].flags
= IEEE80211_CHAN_NO_HT40
;
19922 if (!legacy_chan_info
) {
19924 (((wl_chanspec_list_v1_t
*)list
)->chspecs
[i
].chaninfo
);
19926 channel
|= CHSPEC_BAND(chspec
);
19928 /* Update channel for radar/passive support */
19929 err
= wl_update_chan_param(dev
, channel
,
19930 &band_chan_arr
[index
], &dfs_radar_disabled
, legacy_chan_info
);
19936 __wl_band_2ghz
.n_channels
= ARRAYSIZE(__wl_2ghz_channels
);
19937 __wl_band_5ghz_a
.n_channels
= ARRAYSIZE(__wl_5ghz_a_channels
);
19939 MFREE(cfg
->osh
, list
, LOCAL_BUF_LEN
);
19940 #undef LOCAL_BUF_LEN
19945 static void wl_is_6g_supported(struct bcm_cfg80211
*cfg
, u32
*bandlist
, u8 nbands
)
19949 if (nbands
> WL_MAX_BAND_SUPPORT
) {
19952 /* Check for 6GHz band support */
19953 for (i
= 1; i
<= nbands
; i
++) {
19954 if (bandlist
[i
] == WLC_BAND_6G
) {
19955 cfg
->band_6g_supported
= true;
19959 #endif /* WL_6G_BAND */
19961 static s32
__wl_update_wiphybands(struct bcm_cfg80211
*cfg
, bool notify
)
19963 struct wiphy
*wiphy
;
19964 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
19965 u32 bandlist
[WL_MAX_BAND_SUPPORT
+1];
19971 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19979 s32 txbf_bfe_cap
= 0;
19980 s32 txbf_bfr_cap
= 0;
19984 struct ieee80211_supported_band
*bands
[IEEE80211_NUM_BANDS
] = {NULL
, };
19986 bzero(bandlist
, sizeof(bandlist
));
19987 err
= wldev_ioctl_get(dev
, WLC_GET_BANDLIST
, bandlist
,
19989 if (unlikely(err
)) {
19990 WL_ERR(("error read bandlist (%d)\n", err
));
19993 err
= wldev_ioctl_get(dev
, WLC_GET_BAND
, &cur_band
,
19995 if (unlikely(err
)) {
19996 WL_ERR(("error (%d)\n", err
));
20000 err
= wldev_iovar_getint(dev
, "nmode", &nmode
);
20001 if (unlikely(err
)) {
20002 WL_ERR(("error reading nmode (%d)\n", err
));
20005 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
20006 err
= wldev_iovar_getint(dev
, "vhtmode", &vhtmode
);
20007 if (unlikely(err
)) {
20008 WL_ERR(("error reading vhtmode (%d)\n", err
));
20012 err
= wldev_iovar_getint(dev
, "txstreams", &txstreams
);
20013 if (unlikely(err
)) {
20014 WL_ERR(("error reading txstreams (%d)\n", err
));
20017 err
= wldev_iovar_getint(dev
, "rxstreams", &rxstreams
);
20018 if (unlikely(err
)) {
20019 WL_ERR(("error reading rxstreams (%d)\n", err
));
20022 err
= wldev_iovar_getint(dev
, "ldpc_cap", &ldpc_cap
);
20023 if (unlikely(err
)) {
20024 WL_ERR(("error reading ldpc_cap (%d)\n", err
));
20027 err
= wldev_iovar_getint(dev
, "stbc_rx", &stbc_rx
);
20028 if (unlikely(err
)) {
20029 WL_ERR(("error reading stbc_rx (%d)\n", err
));
20032 err
= wldev_iovar_getint(dev
, "stbc_tx", &stbc_tx
);
20033 if (unlikely(err
)) {
20034 WL_ERR(("error reading stbc_tx (%d)\n", err
));
20037 err
= wldev_iovar_getint(dev
, "txbf_bfe_cap", &txbf_bfe_cap
);
20038 if (unlikely(err
)) {
20039 WL_ERR(("error reading txbf_bfe_cap (%d)\n", err
));
20042 err
= wldev_iovar_getint(dev
, "txbf_bfr_cap", &txbf_bfr_cap
);
20043 if (unlikely(err
)) {
20044 WL_ERR(("error reading txbf_bfr_cap (%d)\n", err
));
20049 /* For nmode and vhtmode check bw cap */
20051 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
20055 err
= wldev_iovar_getint(dev
, "mimo_bw_cap", &bw_cap
);
20056 if (unlikely(err
)) {
20057 WL_ERR(("error get mimo_bw_cap (%d)\n", err
));
20062 wl_is_6g_supported(cfg
, bandlist
, bandlist
[0]);
20063 #endif /* WL_6G_BAND */
20065 err
= wl_construct_reginfo(cfg
, bw_cap
);
20067 WL_ERR(("wl_construct_reginfo() fails err=%d\n", err
));
20068 if (err
!= BCME_UNSUPPORTED
)
20072 wiphy
= bcmcfg_to_wiphy(cfg
);
20073 nband
= bandlist
[0];
20075 for (i
= 1; i
<= nband
&& i
< ARRAYSIZE(bandlist
); i
++) {
20078 if (((bandlist
[i
] == WLC_BAND_5G
) || (bandlist
[i
] == WLC_BAND_6G
)) &&
20079 (__wl_band_5ghz_a
.n_channels
> 0)) {
20080 bands
[IEEE80211_BAND_5GHZ
] =
20082 index
= IEEE80211_BAND_5GHZ
;
20083 if (nmode
&& (bw_cap
== WLC_N_BW_40ALL
|| bw_cap
== WLC_N_BW_20IN2G_40IN5G
))
20084 bands
[index
]->ht_cap
.cap
|= IEEE80211_HT_CAP_SGI_40
;
20086 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
20087 /* VHT capabilities. */
20090 bands
[index
]->vht_cap
.vht_supported
= TRUE
;
20092 for (j
= 1; j
<= VHT_CAP_MCS_MAP_NSS_MAX
; j
++) {
20093 /* TX stream rates. */
20094 if (j
<= txstreams
) {
20095 VHT_MCS_MAP_SET_MCS_PER_SS(j
, VHT_CAP_MCS_MAP_0_9
,
20096 bands
[index
]->vht_cap
.vht_mcs
.tx_mcs_map
);
20098 VHT_MCS_MAP_SET_MCS_PER_SS(j
, VHT_CAP_MCS_MAP_NONE
,
20099 bands
[index
]->vht_cap
.vht_mcs
.tx_mcs_map
);
20102 /* RX stream rates. */
20103 if (j
<= rxstreams
) {
20104 VHT_MCS_MAP_SET_MCS_PER_SS(j
, VHT_CAP_MCS_MAP_0_9
,
20105 bands
[index
]->vht_cap
.vht_mcs
.rx_mcs_map
);
20107 VHT_MCS_MAP_SET_MCS_PER_SS(j
, VHT_CAP_MCS_MAP_NONE
,
20108 bands
[index
]->vht_cap
.vht_mcs
.rx_mcs_map
);
20113 /* 80 MHz is mandatory */
20114 bands
[index
]->vht_cap
.cap
|=
20115 IEEE80211_VHT_CAP_SHORT_GI_80
;
20117 if (WL_BW_CAP_160MHZ(bw_cap
)) {
20118 bands
[index
]->vht_cap
.cap
|=
20119 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
;
20120 bands
[index
]->vht_cap
.cap
|=
20121 IEEE80211_VHT_CAP_SHORT_GI_160
;
20124 bands
[index
]->vht_cap
.cap
|=
20125 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454
;
20128 bands
[index
]->vht_cap
.cap
|=
20129 IEEE80211_VHT_CAP_RXLDPC
;
20132 bands
[index
]->vht_cap
.cap
|=
20133 IEEE80211_VHT_CAP_TXSTBC
;
20136 bands
[index
]->vht_cap
.cap
|=
20137 (stbc_rx
<< VHT_CAP_INFO_RX_STBC_SHIFT
);
20140 bands
[index
]->vht_cap
.cap
|=
20141 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE
;
20143 if (txbf_bfr_cap
) {
20144 bands
[index
]->vht_cap
.cap
|=
20145 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE
;
20148 if (txbf_bfe_cap
|| txbf_bfr_cap
) {
20149 bands
[index
]->vht_cap
.cap
|=
20150 (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT
);
20151 bands
[index
]->vht_cap
.cap
|=
20152 ((txstreams
- 1) <<
20153 VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT
);
20154 bands
[index
]->vht_cap
.cap
|=
20155 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB
;
20158 /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
20159 bands
[index
]->vht_cap
.cap
|=
20160 (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT
);
20161 WL_DBG(("__wl_update_wiphybands band[%d] vht_enab=%d vht_cap=%08x "
20162 "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
20164 bands
[index
]->vht_cap
.vht_supported
,
20165 bands
[index
]->vht_cap
.cap
,
20166 bands
[index
]->vht_cap
.vht_mcs
.rx_mcs_map
,
20167 bands
[index
]->vht_cap
.vht_mcs
.tx_mcs_map
));
20171 else if (bandlist
[i
] == WLC_BAND_2G
&& __wl_band_2ghz
.n_channels
> 0) {
20172 bands
[IEEE80211_BAND_2GHZ
] =
20174 index
= IEEE80211_BAND_2GHZ
;
20175 if (bw_cap
== WLC_N_BW_40ALL
)
20176 bands
[index
]->ht_cap
.cap
|= IEEE80211_HT_CAP_SGI_40
;
20179 if ((index
>= 0) && nmode
) {
20180 bands
[index
]->ht_cap
.cap
|=
20181 (IEEE80211_HT_CAP_SGI_20
| IEEE80211_HT_CAP_DSSSCCK40
);
20182 bands
[index
]->ht_cap
.ht_supported
= TRUE
;
20183 bands
[index
]->ht_cap
.ampdu_factor
= IEEE80211_HT_MAX_AMPDU_64K
;
20184 bands
[index
]->ht_cap
.ampdu_density
= IEEE80211_HT_MPDU_DENSITY_16
;
20185 /* An HT shall support all EQM rates for one spatial stream */
20186 bands
[index
]->ht_cap
.mcs
.rx_mask
[0] = 0xff;
20191 wiphy
->bands
[IEEE80211_BAND_2GHZ
] = bands
[IEEE80211_BAND_2GHZ
];
20192 wiphy
->bands
[IEEE80211_BAND_5GHZ
] = bands
[IEEE80211_BAND_5GHZ
];
20194 /* check if any bands populated otherwise makes 2Ghz as default */
20195 if (wiphy
->bands
[IEEE80211_BAND_2GHZ
] == NULL
&&
20196 wiphy
->bands
[IEEE80211_BAND_5GHZ
] == NULL
) {
20197 /* Setup 2Ghz band as default */
20198 wiphy
->bands
[IEEE80211_BAND_2GHZ
] = &__wl_band_2ghz
;
20202 if (!IS_REGDOM_SELF_MANAGED(wiphy
)) {
20203 WL_UPDATE_CUSTOM_REGULATORY(wiphy
);
20204 wiphy_apply_custom_regulatory(wiphy
, &brcm_regdom
);
20211 s32
wl_update_wiphybands(struct bcm_cfg80211
*cfg
, bool notify
)
20215 mutex_lock(&cfg
->usr_sync
);
20216 err
= __wl_update_wiphybands(cfg
, notify
);
20217 mutex_unlock(&cfg
->usr_sync
);
20222 static s32
__wl_cfg80211_up(struct bcm_cfg80211
*cfg
)
20227 struct net_info
*netinfo
= NULL
;
20228 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
20229 struct wireless_dev
*wdev
= ndev
->ieee80211_ptr
;
20230 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
20233 #endif /* WLTDLS */
20236 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
20240 #if defined(__linux__)
20241 if (!dhd_download_fw_on_driverload
) {
20243 err
= wl_create_event_handler(cfg
);
20245 WL_ERR(("wl_create_event_handler failed\n"));
20248 wl_init_event_handler(cfg
);
20249 #if defined(__linux__)
20252 /* Reserve 0x8000 toggle bit for P2P GO/GC */
20253 cfg
->vif_macaddr_mask
= 0x8000;
20255 err
= dhd_config_dongle(cfg
);
20259 (void)memcpy_s(wdev
->wiphy
->perm_addr
, ETHER_ADDR_LEN
,
20260 bcmcfg_to_prmry_ndev(cfg
)->perm_addr
, ETHER_ADDR_LEN
);
20261 /* Always bring up interface in STA mode.
20262 * Did observe , if previous SofAP Bringup/cleanup
20263 * is not done properly, iftype is stuck with AP mode.
20264 * So during next wlan0 up, forcing the type to STA
20266 netinfo
= wl_get_netinfo_by_wdev(cfg
, wdev
);
20268 WL_ERR(("there is no netinfo\n"));
20272 if (ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
20273 /* AP on primary interface case: Supplicant will
20274 * set mode first and then do dev_open. so in this
20275 * case, the type will already be set.
20277 netinfo
->iftype
= WL_IF_TYPE_AP
;
20279 ndev
->ieee80211_ptr
->iftype
= NL80211_IFTYPE_STATION
;
20280 netinfo
->iftype
= WL_IF_TYPE_STA
;
20283 if (cfg80211_to_wl_iftype(wdev
->iftype
, &wl_iftype
, &wl_mode
) < 0) {
20286 if (!dhd
->fw_preinit
) {
20287 err
= wl_config_infra(cfg
, ndev
, wl_iftype
);
20288 if (unlikely(err
&& err
!= -EINPROGRESS
)) {
20289 WL_ERR(("wl_config_infra failed\n"));
20291 WL_ERR(("return error %d\n", err
));
20297 err
= wl_init_scan(cfg
);
20299 WL_ERR(("wl_init_scan failed\n"));
20302 err
= __wl_update_wiphybands(cfg
, true);
20303 if (unlikely(err
)) {
20304 WL_ERR(("wl_update_wiphybands failed\n"));
20306 WL_ERR(("return error %d\n", err
));
20311 /* Update wlc version in cfg struct already queried as part of DHD initialization */
20312 cfg
->wlc_ver
.wlc_ver_major
= dhd
->wlc_ver_major
;
20313 cfg
->wlc_ver
.wlc_ver_minor
= dhd
->wlc_ver_minor
;
20315 if ((ret
= wldev_iovar_getbuf(ndev
, "scan_ver", NULL
, 0,
20316 ioctl_buf
, sizeof(ioctl_buf
), NULL
) == BCME_OK
)) {
20317 WL_INFORM_MEM(("scan_params v2\n"));
20318 /* use scan_params ver2 */
20319 cfg
->scan_params_v2
= true;
20321 if (ret
== BCME_UNSUPPORTED
) {
20322 WL_INFORM(("scan_ver, UNSUPPORTED\n"));
20324 WL_ERR(("get scan_ver err(%d)\n", ret
));
20327 #ifdef DHD_LOSSLESS_ROAMING
20328 if (timer_pending(&cfg
->roam_timeout
)) {
20329 del_timer_sync(&cfg
->roam_timeout
);
20331 #endif /* DHD_LOSSLESS_ROAMING */
20333 err
= dhd_monitor_init(cfg
->pub
);
20335 #ifdef WL_HOST_BAND_MGMT
20336 /* By default the curr_band is initialized to BAND_AUTO */
20337 if ((ret
= wl_cfg80211_set_band(ndev
, WLC_BAND_AUTO
)) < 0) {
20338 if (ret
== BCME_UNSUPPORTED
) {
20339 /* Don't fail the initialization, lets just
20340 * fall back to the original method
20342 WL_ERR(("WL_HOST_BAND_MGMT defined, "
20343 "but roam_band iovar not supported \n"));
20345 WL_ERR(("roam_band failed. ret=%d", ret
));
20349 #endif /* WL_HOST_BAND_MGMT */
20350 /* Reset WES mode to 0 */
20351 cfg
->wes_mode
= OFF
;
20352 cfg
->ncho_mode
= OFF
;
20353 cfg
->ncho_band
= WLC_BAND_AUTO
;
20355 /* when wifi up, set roam_prof to default value */
20356 if (dhd
->wbtext_support
) {
20357 if (dhd
->op_mode
& DHD_FLAG_STA_MODE
) {
20358 if (!dhd
->fw_preinit
) {
20359 wl_cfg80211_wbtext_set_default(ndev
);
20361 wl_cfg80211_wbtext_clear_bssid_list(cfg
);
20364 #endif /* WBTEXT */
20366 if (wldev_iovar_getint(ndev
, "tdls_enable", &tdls
) == 0) {
20367 WL_DBG(("TDLS supported in fw\n"));
20368 cfg
->tdls_supported
= true;
20370 #endif /* WLTDLS */
20371 #ifdef WL_IFACE_MGMT
20372 #ifdef CUSTOM_IF_MGMT_POLICY
20373 cfg
->iface_data
.policy
= CUSTOM_IF_MGMT_POLICY
;
20375 cfg
->iface_data
.policy
= WL_IF_POLICY_DEFAULT
;
20376 #endif /* CUSTOM_IF_MGMT_POLICY */
20377 #endif /* WL_IFACE_MGMT */
20379 #endif /* WL_NAN */
20381 #ifdef WL_SAR_TX_POWER
20382 cfg
->wifi_tx_power_mode
= WIFI_POWER_SCENARIO_INVALID
;
20383 #endif /* WL_SAR_TX_POWER */
20385 INIT_DELAYED_WORK(&cfg
->pm_enable_work
, wl_cfg80211_work_handler
);
20386 wl_set_drv_status(cfg
, READY
, ndev
);
20390 static s32
__wl_cfg80211_down(struct bcm_cfg80211
*cfg
)
20393 struct net_info
*iter
, *next
;
20394 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
20395 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
20396 defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
20397 struct net_device
*p2p_net
= cfg
->p2p_net
;
20398 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) && !PLATFORM_SLP */
20399 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
20400 WL_INFORM_MEM(("cfg80211 down\n"));
20402 /* Check if cfg80211 interface is already down */
20403 if (!wl_get_drv_status(cfg
, READY
, ndev
)) {
20404 WL_DBG(("cfg80211 interface is already down\n"));
20405 return err
; /* it is even not ready */
20408 #ifdef SHOW_LOGTRACE
20409 /* Stop the event logging */
20410 wl_add_remove_eventmsg(ndev
, WLC_E_TRACE
, FALSE
);
20411 #endif /* SHOW_LOGTRACE */
20413 /* clear vendor OUI list */
20414 wl_vndr_ies_clear_vendor_oui_list(cfg
);
20416 /* clear timestamps */
20417 CLR_TS(cfg
, scan_start
);
20418 CLR_TS(cfg
, scan_cmplt
);
20419 CLR_TS(cfg
, conn_start
);
20420 CLR_TS(cfg
, conn_cmplt
);
20421 CLR_TS(cfg
, authorize_start
);
20422 CLR_TS(cfg
, authorize_cmplt
);
20424 /* Delete pm_enable_work */
20425 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_DEL
);
20427 if (cfg
->loc
.in_progress
) {
20428 /* Listen in progress */
20429 if (delayed_work_pending(&cfg
->loc
.work
)) {
20430 cancel_delayed_work_sync(&cfg
->loc
.work
);
20432 wl_cfgscan_notify_listen_complete(cfg
);
20435 if (cfg
->p2p_supported
) {
20436 wl_clr_p2p_status(cfg
, GO_NEG_PHASE
);
20437 #ifdef PROP_TXSTATUS_VSDB
20438 #if defined(BCMSDIO) || defined(BCMDBUS)
20439 if (wl_cfgp2p_vif_created(cfg
)) {
20440 bool enabled
= false;
20441 dhd_wlfc_get_enable(dhd
, &enabled
);
20442 /* WLFC should be turned off
20443 * while unloading dhd driver in IBSS or SoftAP mode
20445 if (enabled
&& cfg
->wlfc_on
&& dhd
->op_mode
!= DHD_FLAG_HOSTAP_MODE
&&
20446 dhd
->op_mode
!= DHD_FLAG_IBSS_MODE
) {
20447 dhd_wlfc_deinit(dhd
);
20448 cfg
->wlfc_on
= false;
20451 #endif /* BCMSDIO || BCMDBUS */
20452 #endif /* PROP_TXSTATUS_VSDB */
20456 mutex_lock(&cfg
->if_sync
);
20457 wl_cfgnan_check_nan_disable_pending(cfg
, true, false);
20458 mutex_unlock(&cfg
->if_sync
);
20459 #endif /* WL_NAN */
20461 #ifdef WL_SAR_TX_POWER
20462 cfg
->wifi_tx_power_mode
= WIFI_POWER_SCENARIO_INVALID
;
20463 #endif /* WL_SAR_TX_POWER */
20464 if (!dhd_download_fw_on_driverload
) {
20465 /* For built-in drivers/other drivers that do reset on
20466 * "ifconfig <primary_iface> down", cleanup any left
20469 wl_cfg80211_cleanup_virtual_ifaces(cfg
, false);
20471 /* Clear used mac addr mask */
20472 cfg
->vif_macaddr_mask
= 0;
20476 /* If primary BSS is operational (for e.g SoftAP), bring it down */
20477 if (wl_cfg80211_bss_isup(ndev
, 0)) {
20478 if (wl_cfg80211_bss_up(cfg
, ndev
, 0, 0) < 0)
20479 WL_ERR(("BSS down failed \n"));
20482 /* clear all the security setting on primary Interface */
20483 wl_cfg80211_clear_security(cfg
);
20486 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
20487 for_each_ndev(cfg
, iter
, next
) {
20488 GCC_DIAGNOSTIC_POP();
20489 if (iter
->ndev
) /* p2p discovery iface is null */
20490 wl_set_drv_status(cfg
, SCAN_ABORTING
, iter
->ndev
);
20493 #ifdef P2P_LISTEN_OFFLOADING
20494 wl_cfg80211_p2plo_deinit(cfg
);
20495 #endif /* P2P_LISTEN_OFFLOADING */
20497 /* cancel and notify scan complete, if scan request is pending */
20498 wl_cfg80211_cancel_scan(cfg
);
20499 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
20500 for_each_ndev(cfg
, iter
, next
) {
20501 GCC_DIAGNOSTIC_POP();
20502 /* p2p discovery iface ndev ptr could be null */
20503 if (iter
->ndev
== NULL
)
20505 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
20506 WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
20507 wl_get_drv_status(cfg
, CONNECTING
, ndev
),
20508 wl_get_drv_status(cfg
, CONNECTED
, ndev
),
20509 wl_get_drv_status(cfg
, DISCONNECTING
, ndev
),
20510 wl_get_drv_status(cfg
, NESTED_CONNECT
, ndev
)));
20512 if (wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
)) {
20513 CFG80211_DISCONNECTED(iter
->ndev
, 0, NULL
, 0, false, GFP_KERNEL
);
20514 wl_clr_drv_status(cfg
, AUTHORIZED
, iter
->ndev
);
20517 if ((iter
->ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
) &&
20518 wl_get_drv_status(cfg
, CONNECTING
, iter
->ndev
)) {
20520 u8
*latest_bssid
= wl_read_prof(cfg
, ndev
, WL_PROF_LATEST_BSSID
);
20521 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
20522 struct wireless_dev
*wdev
= ndev
->ieee80211_ptr
;
20523 struct cfg80211_bss
*bss
= CFG80211_GET_BSS(wiphy
, NULL
, latest_bssid
,
20524 wdev
->ssid
, wdev
->ssid_len
);
20526 BCM_REFERENCE(bss
);
20528 CFG80211_CONNECT_RESULT(ndev
,
20529 latest_bssid
, bss
, NULL
, 0, NULL
, 0,
20530 WLAN_STATUS_UNSPECIFIED_FAILURE
,
20533 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
20534 wl_clr_drv_status(cfg
, READY
, iter
->ndev
);
20535 wl_clr_drv_status(cfg
, SCANNING
, iter
->ndev
);
20536 wl_clr_drv_status(cfg
, SCAN_ABORTING
, iter
->ndev
);
20537 wl_clr_drv_status(cfg
, CONNECTING
, iter
->ndev
);
20538 wl_clr_drv_status(cfg
, CONNECTED
, iter
->ndev
);
20539 wl_clr_drv_status(cfg
, DISCONNECTING
, iter
->ndev
);
20540 wl_clr_drv_status(cfg
, AP_CREATED
, iter
->ndev
);
20541 wl_clr_drv_status(cfg
, AP_CREATING
, iter
->ndev
);
20542 wl_clr_drv_status(cfg
, NESTED_CONNECT
, iter
->ndev
);
20543 wl_clr_drv_status(cfg
, CFG80211_CONNECT
, iter
->ndev
);
20545 bcmcfg_to_prmry_ndev(cfg
)->ieee80211_ptr
->iftype
=
20546 NL80211_IFTYPE_STATION
;
20547 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
20548 defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
20549 #ifdef SUPPORT_DEEP_SLEEP
20550 if (!trigger_deep_sleep
)
20551 #endif /* SUPPORT_DEEP_SLEEP */
20553 dev_close(p2p_net
);
20554 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT)&& !PLATFORM_SLP */
20556 /* Avoid deadlock from wl_cfg80211_down */
20557 #if defined(__linux__)
20558 if (!dhd_download_fw_on_driverload
) {
20560 mutex_unlock(&cfg
->usr_sync
);
20561 wl_destroy_event_handler(cfg
);
20562 mutex_lock(&cfg
->usr_sync
);
20563 #if defined(__linux__)
20569 if (cfg
->p2p_supported
) {
20570 if (timer_pending(&cfg
->p2p
->listen_timer
))
20571 del_timer_sync(&cfg
->p2p
->listen_timer
);
20572 wl_cfgp2p_down(cfg
);
20575 if (timer_pending(&cfg
->scan_timeout
)) {
20576 del_timer_sync(&cfg
->scan_timeout
);
20579 wl_cfg80211_clear_mgmt_vndr_ies(cfg
);
20581 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t
*)(cfg
->pub
));
20583 dhd_monitor_uninit();
20584 #ifdef WLAIBSS_MCHAN
20585 bcm_cfg80211_del_ibss_if(cfg
->wdev
->wiphy
, cfg
->ibss_cfgdev
);
20586 #endif /* WLAIBSS_MCHAN */
20589 /* Clear interworking element. */
20591 cfg
->wl11u
= FALSE
;
20595 #ifdef CUSTOMER_HW4_DEBUG
20596 if (wl_scan_timeout_dbg_enabled
) {
20597 wl_scan_timeout_dbg_clear();
20599 #endif /* CUSTOMER_HW4_DEBUG */
20601 cfg
->disable_roam_event
= false;
20603 DNGL_FUNC(dhd_cfg80211_down
, (cfg
));
20606 /* Printout all netinfo entries */
20607 wl_probe_wdev_all(cfg
);
20608 #endif /* DHD_IFDEBUG */
20613 s32
wl_cfg80211_up(struct net_device
*net
)
20615 struct bcm_cfg80211
*cfg
;
20619 #ifdef DISABLE_PM_BCNRX
20622 s8 iovbuf
[WLC_IOCTL_SMLEN
];
20623 #endif /* DISABLE_PM_BCNRX */
20624 #ifdef WL_USE_RANDOMIZED_SCAN
20625 uint8 random_addr
[ETHER_ADDR_LEN
] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
20626 #endif /* WL_USE_RANDOMIZED_SCAN */
20628 cfg
= wl_get_cfg(net
);
20630 if ((err
= wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg
), WLC_GET_VERSION
, &val
,
20631 sizeof(int)) < 0)) {
20632 WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err
));
20636 if (val
!= WLC_IOCTL_VERSION
&& val
!= 1) {
20637 WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
20638 val
, WLC_IOCTL_VERSION
));
20639 return BCME_VERSION
;
20641 ioctl_version
= val
;
20642 WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version
));
20643 wl_cfg80211_check_in4way(cfg
, net
, NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
|WAIT_DISCONNECTED
,
20644 WL_EXT_STATUS_DISCONNECTED
, NULL
);
20646 mutex_lock(&cfg
->usr_sync
);
20647 dhd
= (dhd_pub_t
*)(cfg
->pub
);
20648 if (!(dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
20649 err
= wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg
));
20650 if (unlikely(err
)) {
20651 mutex_unlock(&cfg
->usr_sync
);
20655 #ifdef WLMESH_CFG80211
20656 cfg
->wdev
->wiphy
->features
|= NL80211_FEATURE_USERSPACE_MPM
;
20657 #endif /* WLMESH_CFG80211 */
20658 #if defined(BCMSUP_4WAY_HANDSHAKE)
20659 if (dhd
->fw_4way_handshake
) {
20660 /* This is a hacky method to indicate fw 4WHS support and
20661 * is used only for kernels (kernels < 3.14). For newer
20662 * kernels, we would be using vendor extn. path to advertise
20663 * FW based 4-way handshake feature support.
20665 cfg
->wdev
->wiphy
->features
|= NL80211_FEATURE_FW_4WAY_HANDSHAKE
;
20667 #endif /* BCMSUP_4WAY_HANDSHAKE */
20668 err
= __wl_cfg80211_up(cfg
);
20670 WL_ERR(("__wl_cfg80211_up failed\n"));
20672 #ifdef ROAM_CHANNEL_CACHE
20673 if (init_roam_cache(cfg
, ioctl_version
) == 0) {
20674 /* Enable support for Roam cache */
20675 cfg
->rcc_enabled
= true;
20676 WL_ERR(("Roam channel cache enabled\n"));
20678 WL_ERR(("Failed to enable RCC.\n"));
20680 #endif /* ROAM_CHANNEL_CACHE */
20681 #ifdef WL_USE_RANDOMIZED_SCAN
20682 /* Call scanmac only for valid configuration */
20683 if (wl_cfg80211_scan_mac_enable(net
)) {
20684 WL_ERR(("%s : randmac enable failed\n", __FUNCTION__
));
20686 /* scanmac enabled. apply configuration */
20687 if (wl_cfg80211_scan_mac_config(net
, random_addr
, NULL
)) {
20688 WL_ERR(("%s : failed to set randmac config for scan\n", __FUNCTION__
));
20689 /* if config fails, disable scan mac */
20690 wl_cfg80211_scan_mac_disable(net
);
20693 #endif /* WL_USE_RANDOMIZED_SCAN */
20694 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
20695 dhd_force_disable_singlcore_scan(dhd
);
20696 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
20698 /* IOVAR configurations with 'up' condition */
20699 #ifdef DISABLE_PM_BCNRX
20700 interr
= wldev_iovar_setbuf(net
, "pm_bcnrx", (char *)¶m
, sizeof(param
), iovbuf
,
20701 sizeof(iovbuf
), &cfg
->ioctl_buf_sync
);
20703 if (unlikely(interr
)) {
20704 WL_ERR(("Set pm_bcnrx returned (%d)\n", interr
));
20706 #endif /* DISABLE_PM_BCNRX */
20707 #ifdef WL_CHAN_UTIL
20708 interr
= wl_cfg80211_start_bssload_report(net
);
20709 if (unlikely(interr
)) {
20710 WL_ERR(("%s: Failed to start bssload_report eventing, err=%d\n",
20711 __FUNCTION__
, interr
));
20713 #endif /* WL_CHAN_UTIL */
20715 mutex_unlock(&cfg
->usr_sync
);
20717 #ifdef WLAIBSS_MCHAN
20718 bcm_cfg80211_add_ibss_if(cfg
->wdev
->wiphy
, IBSS_IF_NAME
);
20719 #endif /* WLAIBSS_MCHAN */
20720 cfg
->spmk_info_list
->pmkids
.count
= 0;
20724 /* Private Event to Supplicant with indication that chip hangs */
20725 int wl_cfg80211_hang(struct net_device
*dev
, u16 reason
)
20727 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
20729 #if defined(SOFTAP_SEND_HANGEVT)
20730 /* specifc mac address used for hang event */
20731 uint8 hang_mac
[ETHER_ADDR_LEN
] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
20732 #endif /* SOFTAP_SEND_HANGEVT */
20737 RETURN_EIO_IF_NOT_UP(cfg
);
20739 dhd
= (dhd_pub_t
*)(cfg
->pub
);
20740 #if defined(DHD_HANG_SEND_UP_TEST)
20741 if (dhd
->req_hang_type
) {
20742 WL_ERR(("wl_cfg80211_hang, Clear HANG test request 0x%x\n",
20743 dhd
->req_hang_type
));
20744 dhd
->req_hang_type
= 0;
20746 #endif /* DHD_HANG_SEND_UP_TEST */
20747 if ((dhd
->hang_reason
<= HANG_REASON_MASK
) || (dhd
->hang_reason
>= HANG_REASON_MAX
)) {
20748 WL_ERR(("wl_cfg80211_hang, Invalid hang reason 0x%x\n",
20749 dhd
->hang_reason
));
20750 dhd
->hang_reason
= HANG_REASON_UNKNOWN
;
20752 #ifdef DHD_USE_EXTENDED_HANG_REASON
20753 /* The proper dhd->hang_reason handling codes should be implemented
20754 * in the WPA Supplicant/Hostapd or Android framework.
20755 * If not, HANG event may not be sent to Android framework and
20756 * driver cannot be reloaded.
20757 * Please do not enable DHD_USE_EXTENDED_HANG_REASON if your Android platform
20758 * cannot handle the dhd->hang_reason value.
20760 if (dhd
->hang_reason
!= 0) {
20761 reason
= dhd
->hang_reason
;
20763 #endif /* DHD_USE_EXTENDED_HANG_REASON */
20764 WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32
)(dhd
->hang_reason
)));
20766 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_DEL
);
20767 #ifdef SOFTAP_SEND_HANGEVT
20768 if (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
20769 cfg80211_del_sta(dev
, hang_mac
, GFP_ATOMIC
);
20771 #endif /* SOFTAP_SEND_HANGEVT */
20773 if (dhd
->up
== TRUE
) {
20774 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
20775 wl_cfgvendor_send_hang_event(dev
, reason
,
20776 dhd
->hang_info
, dhd
->hang_info_cnt
);
20778 CFG80211_DISCONNECTED(dev
, reason
, NULL
, 0, false, GFP_KERNEL
);
20779 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
20782 #if defined(RSSIAVG)
20783 wl_free_rssi_cache(&cfg
->g_rssi_cache_ctrl
);
20785 #if defined(BSSCACHE)
20786 wl_free_bss_cache(&cfg
->g_bss_cache_ctrl
);
20789 /* Do we need to call wl_cfg80211_down here ? */
20795 s32
wl_cfg80211_down(struct net_device
*dev
)
20797 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
20798 s32 err
= BCME_ERROR
;
20802 if (cfg
&& (cfg
== wl_cfg80211_get_bcmcfg())) {
20803 mutex_lock(&cfg
->usr_sync
);
20804 #if defined(RSSIAVG)
20805 wl_free_rssi_cache(&cfg
->g_rssi_cache_ctrl
);
20807 #if defined(BSSCACHE)
20808 wl_free_bss_cache(&cfg
->g_bss_cache_ctrl
);
20810 err
= __wl_cfg80211_down(cfg
);
20811 mutex_unlock(&cfg
->usr_sync
);
20818 wl_cfg80211_sta_ifdown(struct net_device
*dev
)
20820 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
20825 /* cancel scan if anything pending */
20826 wl_cfg80211_cancel_scan(cfg
);
20827 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
20828 if ((dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
) &&
20829 wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
20830 CFG80211_DISCONNECTED(dev
, 0, NULL
, 0, false, GFP_KERNEL
);
20832 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
20836 void *wl_read_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, s32 item
)
20838 unsigned long flags
;
20840 struct wl_profile
*profile
= wl_get_profile_by_netdev(cfg
, ndev
);
20844 WL_CFG_DRV_LOCK(&cfg
->cfgdrv_lock
, flags
);
20847 rptr
= &profile
->sec
;
20850 rptr
= &profile
->active
;
20852 case WL_PROF_BSSID
:
20853 rptr
= profile
->bssid
;
20856 rptr
= &profile
->ssid
;
20859 rptr
= &profile
->channel
;
20861 case WL_PROF_LATEST_BSSID
:
20862 rptr
= profile
->latest_bssid
;
20865 WL_CFG_DRV_UNLOCK(&cfg
->cfgdrv_lock
, flags
);
20867 WL_ERR(("invalid item (%d)\n", item
));
20872 wl_update_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
20873 const wl_event_msg_t
*e
, const void *data
, s32 item
)
20876 const struct wlc_ssid
*ssid
;
20877 unsigned long flags
;
20878 struct wl_profile
*profile
= wl_get_profile_by_netdev(cfg
, ndev
);
20882 WL_CFG_DRV_LOCK(&cfg
->cfgdrv_lock
, flags
);
20885 ssid
= (const wlc_ssid_t
*) data
;
20886 bzero(profile
->ssid
.SSID
,
20887 sizeof(profile
->ssid
.SSID
));
20888 profile
->ssid
.SSID_len
= MIN(ssid
->SSID_len
, DOT11_MAX_SSID_LEN
);
20889 memcpy(profile
->ssid
.SSID
, ssid
->SSID
, profile
->ssid
.SSID_len
);
20891 case WL_PROF_BSSID
:
20893 memcpy(profile
->bssid
, data
, ETHER_ADDR_LEN
);
20895 bzero(profile
->bssid
, ETHER_ADDR_LEN
);
20898 memcpy(&profile
->sec
, data
, sizeof(profile
->sec
));
20901 profile
->active
= *(const bool *)data
;
20903 case WL_PROF_BEACONINT
:
20904 profile
->beacon_interval
= *(const u16
*)data
;
20906 case WL_PROF_DTIMPERIOD
:
20907 profile
->dtim_period
= *(const u8
*)data
;
20910 profile
->channel
= *(const chanspec_t
*)data
;
20912 case WL_PROF_LATEST_BSSID
:
20914 memcpy_s(profile
->latest_bssid
, sizeof(profile
->latest_bssid
),
20915 data
, ETHER_ADDR_LEN
);
20917 memset_s(profile
->latest_bssid
, sizeof(profile
->latest_bssid
),
20918 0, ETHER_ADDR_LEN
);
20925 WL_CFG_DRV_UNLOCK(&cfg
->cfgdrv_lock
, flags
);
20927 if (err
== -EOPNOTSUPP
)
20928 WL_ERR(("unsupported item (%d)\n", item
));
20933 void wl_cfg80211_dbg_level(u32 level
)
20936 * prohibit to change debug level
20937 * by insmod parameter.
20938 * eventually debug level will be configured
20939 * in compile time by using CONFIG_XXX
20941 /* wl_dbg_level = level; */
20944 static bool wl_is_ibssmode(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
20946 return wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_IBSS
;
20949 static __used
bool wl_is_ibssstarter(struct bcm_cfg80211
*cfg
)
20951 return cfg
->ibss_starter
;
20954 static __used s32
wl_add_ie(struct bcm_cfg80211
*cfg
, u8 t
, u8 l
, u8
*v
)
20956 struct wl_ie
*ie
= wl_to_ie(cfg
);
20959 if (unlikely(ie
->offset
+ l
+ 2 > WL_TLV_INFO_MAX
)) {
20960 WL_ERR(("ei crosses buffer boundary\n"));
20963 ie
->buf
[ie
->offset
] = t
;
20964 ie
->buf
[ie
->offset
+ 1] = l
;
20965 memcpy(&ie
->buf
[ie
->offset
+ 2], v
, l
);
20966 ie
->offset
+= l
+ 2;
20971 static void wl_link_up(struct bcm_cfg80211
*cfg
)
20973 cfg
->link_up
= true;
20976 static void wl_link_down(struct bcm_cfg80211
*cfg
)
20978 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
20981 cfg
->link_up
= false;
20983 conn_info
->req_ie_len
= 0;
20984 conn_info
->resp_ie_len
= 0;
20988 static unsigned long wl_lock_eq(struct bcm_cfg80211
*cfg
)
20990 unsigned long flags
;
20992 WL_CFG_EQ_LOCK(&cfg
->eq_lock
, flags
);
20996 static void wl_unlock_eq(struct bcm_cfg80211
*cfg
, unsigned long flags
)
20998 WL_CFG_EQ_UNLOCK(&cfg
->eq_lock
, flags
);
21001 static void wl_init_eq_lock(struct bcm_cfg80211
*cfg
)
21003 spin_lock_init(&cfg
->eq_lock
);
21006 static void wl_delay(u32 ms
)
21008 if (in_atomic() || (ms
< jiffies_to_msecs(1))) {
21009 OSL_DELAY(ms
*1000);
21015 s32
wl_cfg80211_get_p2p_dev_addr(struct net_device
*net
, struct ether_addr
*p2pdev_addr
)
21017 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
21018 struct ether_addr primary_mac
;
21021 if (!p2p_is_on(cfg
)) {
21022 get_primary_mac(cfg
, &primary_mac
);
21023 memcpy((void *)&p2pdev_addr
, (void *)&primary_mac
, ETHER_ADDR_LEN
);
21025 memcpy(p2pdev_addr
->octet
, wl_to_p2p_bss_macaddr(cfg
, P2PAPI_BSSCFG_DEVICE
).octet
,
21031 s32
wl_cfg80211_set_p2p_noa(struct net_device
*net
, char* buf
, int len
)
21033 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
21035 return wl_cfgp2p_set_p2p_noa(cfg
, net
, buf
, len
);
21038 s32
wl_cfg80211_get_p2p_noa(struct net_device
*net
, char* buf
, int len
)
21040 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
21042 return wl_cfgp2p_get_p2p_noa(cfg
, net
, buf
, len
);
21045 s32
wl_cfg80211_set_p2p_ps(struct net_device
*net
, char* buf
, int len
)
21047 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
21049 return wl_cfgp2p_set_p2p_ps(cfg
, net
, buf
, len
);
21052 s32
wl_cfg80211_set_p2p_ecsa(struct net_device
*net
, char* buf
, int len
)
21054 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
21056 return wl_cfgp2p_set_p2p_ecsa(cfg
, net
, buf
, len
);
21059 s32
wl_cfg80211_increase_p2p_bw(struct net_device
*net
, char* buf
, int len
)
21061 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
21063 return wl_cfgp2p_increase_p2p_bw(cfg
, net
, buf
, len
);
21066 #ifdef P2PLISTEN_AP_SAMECHN
21067 s32
wl_cfg80211_set_p2p_resp_ap_chn(struct net_device
*net
, s32 enable
)
21069 s32 ret
= wldev_iovar_setint(net
, "p2p_resp_ap_chn", enable
);
21071 if ((ret
== 0) && enable
) {
21072 /* disable PM for p2p responding on infra AP channel */
21075 ret
= wldev_ioctl_set(net
, WLC_SET_PM
, &pm
, sizeof(pm
));
21080 #endif /* P2PLISTEN_AP_SAMECHN */
21084 wl_tdls_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
21085 const wl_event_msg_t
*e
, void *data
) {
21087 struct net_device
*ndev
= NULL
;
21088 u32 reason
= ntoh32(e
->reason
);
21091 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
21094 case WLC_E_TDLS_PEER_DISCOVERED
:
21095 msg
= " TDLS PEER DISCOVERD ";
21097 case WLC_E_TDLS_PEER_CONNECTED
:
21098 if (cfg
->tdls_mgmt_frame
) {
21099 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
21100 cfg80211_rx_mgmt(cfgdev
, cfg
->tdls_mgmt_freq
, 0,
21101 cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
, 0);
21102 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
21103 cfg80211_rx_mgmt(cfgdev
, cfg
->tdls_mgmt_freq
, 0,
21104 cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
, 0,
21106 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
21107 defined(WL_COMPAT_WIRELESS)
21108 cfg80211_rx_mgmt(cfgdev
, cfg
->tdls_mgmt_freq
, 0,
21109 cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
,
21112 cfg80211_rx_mgmt(cfgdev
, cfg
->tdls_mgmt_freq
,
21113 cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
, GFP_ATOMIC
);
21115 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
21117 msg
= " TDLS PEER CONNECTED ";
21118 #ifdef SUPPORT_SET_CAC
21119 /* TDLS connect reset CAC */
21120 wl_cfg80211_set_cac(cfg
, 0);
21121 #endif /* SUPPORT_SET_CAC */
21123 case WLC_E_TDLS_PEER_DISCONNECTED
:
21124 if (cfg
->tdls_mgmt_frame
) {
21125 MFREE(cfg
->osh
, cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
);
21126 cfg
->tdls_mgmt_frame_len
= 0;
21127 cfg
->tdls_mgmt_freq
= 0;
21129 msg
= "TDLS PEER DISCONNECTED ";
21130 #ifdef SUPPORT_SET_CAC
21131 /* TDLS disconnec, set CAC */
21132 wl_cfg80211_set_cac(cfg
, 1);
21133 #endif /* SUPPORT_SET_CAC */
21137 WL_ERR(("%s: " MACDBG
" on %s ndev\n", msg
, MAC2STRDBG((const u8
*)(&e
->addr
)),
21138 (bcmcfg_to_prmry_ndev(cfg
) == ndev
) ? "primary" : "secondary"));
21144 #endif /* WLTDLS */
21147 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
21148 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
21149 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
21150 wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
21151 u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
21152 u32 peer_capability
, const u8
*buf
, size_t len
)
21153 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
21154 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
21155 wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
21156 const u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
21157 u32 peer_capability
, const u8
*buf
, size_t len
)
21158 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
21159 wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
21160 const u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
21161 u32 peer_capability
, bool initiator
, const u8
*buf
, size_t len
)
21162 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
21163 wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
21164 u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
21165 const u8
*buf
, size_t len
)
21166 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
21169 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
21170 struct bcm_cfg80211
*cfg
;
21171 tdls_wfd_ie_iovar_t info
;
21172 bzero(&info
, sizeof(info
));
21173 cfg
= wl_get_cfg(dev
);
21175 #if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
21176 /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
21177 * and that cuases build error
21179 BCM_REFERENCE(peer_capability
);
21180 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
21182 switch (action_code
) {
21183 /* We need to set TDLS Wifi Display IE to firmware
21184 * using tdls_wfd_ie iovar
21186 case WLAN_TDLS_SET_PROBE_WFD_IE
:
21187 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_PROBE_WFD_IE\n"));
21188 info
.mode
= TDLS_WFD_PROBE_IE_TX
;
21190 if (len
> sizeof(info
.data
)) {
21193 memcpy(&info
.data
, buf
, len
);
21196 case WLAN_TDLS_SET_SETUP_WFD_IE
:
21197 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_SETUP_WFD_IE\n"));
21198 info
.mode
= TDLS_WFD_IE_TX
;
21200 if (len
> sizeof(info
.data
)) {
21203 memcpy(&info
.data
, buf
, len
);
21206 case WLAN_TDLS_SET_WFD_ENABLED
:
21207 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_ENABLED\n"));
21208 dhd_tdls_set_mode((dhd_pub_t
*)(cfg
->pub
), true);
21210 case WLAN_TDLS_SET_WFD_DISABLED
:
21211 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_DISABLED\n"));
21212 dhd_tdls_set_mode((dhd_pub_t
*)(cfg
->pub
), false);
21215 WL_ERR(("Unsupported action code : %d\n", action_code
));
21218 ret
= wldev_iovar_setbuf(dev
, "tdls_wfd_ie", &info
, sizeof(info
),
21219 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
21222 WL_ERR(("tdls_wfd_ie error %d\n", ret
));
21226 #endif /* TDLS_MSG_ONLY_WFD && WLTDLS */
21230 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
21232 wl_cfg80211_tdls_oper(struct wiphy
*wiphy
, struct net_device
*dev
,
21233 const u8
*peer
, enum nl80211_tdls_operation oper
)
21236 wl_cfg80211_tdls_oper(struct wiphy
*wiphy
, struct net_device
*dev
,
21237 u8
*peer
, enum nl80211_tdls_operation oper
)
21242 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
21245 bool tdls_auto_mode
= false;
21246 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
21247 bzero(&info
, sizeof(tdls_iovar_t
));
21249 memcpy(&info
.ea
, peer
, ETHER_ADDR_LEN
);
21254 case NL80211_TDLS_DISCOVERY_REQ
:
21255 /* If the discovery request is broadcast then we need to set
21256 * info.mode to Tunneled Probe Request
21258 if (memcmp(peer
, (const uint8
*)BSSID_BROADCAST
, ETHER_ADDR_LEN
) == 0) {
21259 info
.mode
= TDLS_MANUAL_EP_WFD_TPQ
;
21260 WL_ERR(("wl_cfg80211_tdls_oper: TDLS TUNNELED PRBOBE REQUEST\n"));
21262 info
.mode
= TDLS_MANUAL_EP_DISCOVERY
;
21265 case NL80211_TDLS_SETUP
:
21266 if (dhdp
->tdls_mode
== true) {
21267 info
.mode
= TDLS_MANUAL_EP_CREATE
;
21268 tdls_auto_mode
= false;
21269 /* Do tear down and create a fresh one */
21270 ret
= wl_cfg80211_tdls_config(cfg
, TDLS_STATE_TEARDOWN
, tdls_auto_mode
);
21275 tdls_auto_mode
= true;
21278 case NL80211_TDLS_TEARDOWN
:
21279 info
.mode
= TDLS_MANUAL_EP_DELETE
;
21282 WL_ERR(("Unsupported operation : %d\n", oper
));
21286 ret
= wl_cfg80211_tdls_config(cfg
, TDLS_STATE_SETUP
, tdls_auto_mode
);
21291 ret
= wldev_iovar_setbuf(dev
, "tdls_endpoint", &info
, sizeof(info
),
21292 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
21294 WL_ERR(("tdls_endpoint error %d\n", ret
));
21298 /* use linux generic error code instead of firmware error code */
21300 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
21303 #endif /* WLTDLS */
21306 #endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
21308 s32
wl_cfg80211_set_wps_p2p_ie(struct net_device
*ndev
, char *buf
, int len
,
21309 enum wl_management_type type
)
21311 struct bcm_cfg80211
*cfg
;
21315 cfg
= wl_get_cfg(ndev
);
21317 if (wl_get_drv_status(cfg
, AP_CREATING
, ndev
)) {
21318 /* Vendor IEs should be set to FW
21319 * after SoftAP interface is brought up
21321 WL_DBG(("Skipping set IE since AP is not up \n"));
21323 } else if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
21324 /* Either stand alone AP case or P2P discovery */
21325 if (wl_get_drv_status(cfg
, AP_CREATED
, ndev
)) {
21326 /* Stand alone AP case on primary interface */
21327 WL_DBG(("Apply IEs for Primary AP Interface \n"));
21331 /* If p2p not initialized, return failure */
21332 WL_ERR(("P2P not initialized \n"));
21335 /* P2P Discovery case (p2p listen) */
21336 if (!cfg
->p2p
->on
) {
21337 /* Turn on Discovery interface */
21338 p2p_on(cfg
) = true;
21339 ret
= wl_cfgp2p_enable_discovery(cfg
, ndev
, NULL
, 0);
21340 if (unlikely(ret
)) {
21341 WL_ERR(("Enable discovery failed \n"));
21345 WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
21346 ndev
= wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_PRIMARY
);
21347 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
21350 /* Virtual AP/ P2P Group Interface */
21351 WL_DBG(("Apply IEs for iface:%s\n", ndev
->name
));
21352 bssidx
= wl_get_bssidx_by_wdev(cfg
, ndev
->ieee80211_ptr
);
21355 if (ndev
!= NULL
) {
21358 pktflag
= VNDR_IE_BEACON_FLAG
;
21360 case WL_PROBE_RESP
:
21361 pktflag
= VNDR_IE_PRBRSP_FLAG
;
21363 case WL_ASSOC_RESP
:
21364 pktflag
= VNDR_IE_ASSOCRSP_FLAG
;
21368 ret
= wl_cfg80211_set_mgmt_vndr_ies(cfg
,
21369 ndev_to_cfgdev(ndev
), bssidx
, pktflag
, buf
, len
);
21376 #ifdef WL_SUPPORT_AUTO_CHANNEL
21378 wl_cfg80211_set_auto_channel_scan_state(struct net_device
*ndev
)
21381 s32 ret
= BCME_ERROR
;
21382 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21383 /* Set interface up, explicitly. */
21386 ret
= wldev_ioctl_set(ndev
, WLC_UP
, (void *)&val
, sizeof(val
));
21388 WL_ERR(("set interface up failed, error = %d\n", ret
));
21392 /* Stop all scan explicitly, till auto channel selection complete. */
21393 wl_set_drv_status(cfg
, SCANNING
, ndev
);
21394 if (cfg
->escan_info
.ndev
== NULL
) {
21399 wl_cfg80211_cancel_scan(cfg
);
21406 wl_cfg80211_valid_channel_p2p(int channel
)
21408 bool valid
= false;
21410 /* channel 1 to 14 */
21411 if ((channel
>= 1) && (channel
<= 14)) {
21414 /* channel 36 to 48 */
21415 else if ((channel
>= 36) && (channel
<= 48)) {
21418 /* channel 149 to 161 */
21419 else if ((channel
>= 149) && (channel
<= 161)) {
21424 WL_INFORM(("invalid P2P chanspec, channel = %d\n", channel
));
21431 wl_cfg80211_get_chanspecs_2g(struct net_device
*ndev
, void *buf
, s32 buflen
)
21433 s32 ret
= BCME_ERROR
;
21434 struct bcm_cfg80211
*cfg
= NULL
;
21435 chanspec_t chanspec
= 0;
21437 cfg
= wl_get_cfg(ndev
);
21439 /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
21440 chanspec
|= (WL_CHANSPEC_BAND_2G
| WL_CHANSPEC_BW_20
|
21441 WL_CHANSPEC_CTL_SB_NONE
);
21442 chanspec
= wl_chspec_host_to_driver(chanspec
);
21444 ret
= wldev_iovar_getbuf_bsscfg(ndev
, "chanspecs", (void *)&chanspec
,
21445 sizeof(chanspec
), buf
, buflen
, 0, &cfg
->ioctl_buf_sync
);
21447 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret
));
21454 wl_cfg80211_get_chanspecs_5g(struct net_device
*ndev
, void *buf
, s32 buflen
)
21457 s32 ret
= BCME_ERROR
;
21460 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21461 wl_uint32_list_t
*list
= NULL
;
21462 chanspec_t chanspec
= 0;
21464 /* Restrict channels to 5GHz, 20MHz BW, no SB. */
21465 chanspec
|= (WL_CHANSPEC_BAND_5G
| WL_CHANSPEC_BW_20
|
21466 WL_CHANSPEC_CTL_SB_NONE
);
21467 chanspec
= wl_chspec_host_to_driver(chanspec
);
21469 ret
= wldev_iovar_getbuf_bsscfg(ndev
, "chanspecs", (void *)&chanspec
,
21470 sizeof(chanspec
), buf
, buflen
, 0, &cfg
->ioctl_buf_sync
);
21472 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret
));
21476 list
= (wl_uint32_list_t
*)buf
;
21477 /* Skip DFS and inavlid P2P channel. */
21478 for (i
= 0, j
= 0; i
< dtoh32(list
->count
); i
++) {
21479 chanspec
= (chanspec_t
) dtoh32(list
->element
[i
]);
21480 channel
= CHSPEC_CHANNEL(chanspec
);
21482 ret
= wldev_iovar_getint(ndev
, "per_chan_info", &channel
);
21484 WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret
));
21488 if (CHANNEL_IS_RADAR(channel
) ||
21489 !(wl_cfg80211_valid_channel_p2p(CHSPEC_CHANNEL(chanspec
)))) {
21492 list
->element
[j
] = list
->element
[i
];
21505 wl_cfg80211_get_best_channel(struct net_device
*ndev
, void *buf
, int buflen
,
21508 s32 ret
= BCME_ERROR
;
21513 /* Start auto channel selection scan. */
21514 ret
= wldev_ioctl_set(ndev
, WLC_START_CHANNEL_SEL
, buf
, buflen
);
21516 WL_ERR(("can't start auto channel scan, error = %d\n", ret
));
21521 /* Wait for auto channel selection, worst case possible delay is 5250ms. */
21522 retry
= CHAN_SEL_RETRY_COUNT
;
21525 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY
);
21527 ret
= wldev_ioctl_get(ndev
, WLC_GET_CHANNEL_SEL
, &chosen
, sizeof(chosen
));
21528 if ((ret
== 0) && (dtoh32(chosen
) != 0)) {
21529 chip
= dhd_conf_get_chip(dhd_get_pub(ndev
));
21530 if (chip
!= BCM43362_CHIP_ID
&& chip
!= BCM4330_CHIP_ID
&&
21531 chip
!= BCM43143_CHIP_ID
) {
21534 chanspec
= wl_chspec_driver_to_host(chosen
);
21535 WL_INFORM(("selected chanspec = 0x%x\n", chanspec
));
21536 ctl_chan
= wf_chspec_ctlchan(chanspec
);
21537 WL_INFORM(("selected ctl_chan = %d\n", ctl_chan
));
21538 *channel
= (u16
)(ctl_chan
& 0x00FF);
21540 *channel
= (u16
)(chosen
& 0x00FF);
21541 WL_INFORM(("selected channel = %d\n", *channel
));
21544 WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n",
21545 (CHAN_SEL_RETRY_COUNT
- retry
), ret
, dtoh32(chosen
)));
21549 WL_ERR(("failure, auto channel selection timed out\n"));
21553 WL_INFORM(("selected channel = %d\n", *channel
));
21560 wl_cfg80211_restore_auto_channel_scan_state(struct net_device
*ndev
)
21562 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21563 /* Clear scan stop driver status. */
21564 wl_clr_drv_status(cfg
, SCANNING
, ndev
);
21570 wl_cfg80211_get_best_channels(struct net_device
*dev
, char* cmd
, int total_len
)
21572 int channel
= 0, band
, band_cur
;
21573 s32 ret
= BCME_ERROR
;
21576 struct bcm_cfg80211
*cfg
= NULL
;
21577 struct net_device
*ndev
= NULL
;
21579 bzero(cmd
, total_len
);
21580 cfg
= wl_get_cfg(dev
);
21582 buf
= (u8
*)MALLOC(cfg
->osh
, CHANSPEC_BUF_SIZE
);
21584 WL_ERR(("failed to allocate chanspec buffer\n"));
21589 * Always use primary interface, irrespective of interface on which
21592 ndev
= bcmcfg_to_prmry_ndev(cfg
);
21595 * Make sure that FW and driver are in right state to do auto channel
21598 ret
= wl_cfg80211_set_auto_channel_scan_state(ndev
);
21600 WL_ERR(("can't set auto channel scan state, error = %d\n", ret
));
21604 ret
= wldev_ioctl(dev
, WLC_GET_BAND
, &band_cur
, sizeof(band_cur
), false);
21605 if (band_cur
!= WLC_BAND_5G
) {
21606 /* Best channel selection in 2.4GHz band. */
21607 ret
= wl_cfg80211_get_chanspecs_2g(ndev
, (void *)buf
, CHANSPEC_BUF_SIZE
);
21609 WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret
));
21613 ret
= wl_cfg80211_get_best_channel(ndev
, (void *)buf
, CHANSPEC_BUF_SIZE
,
21616 WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret
));
21620 if (CHANNEL_IS_2G(channel
)) {
21621 // channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
21623 WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel
));
21626 pos
+= snprintf(pos
, total_len
, "2g=%d ", channel
);
21629 if (band_cur
!= WLC_BAND_2G
) {
21630 // terence 20140120: fix for some chipsets only return 2.4GHz channel (4330b2/43341b0/4339a0)
21631 band
= band_cur
==WLC_BAND_2G
? band_cur
: WLC_BAND_5G
;
21632 ret
= wldev_ioctl(dev
, WLC_SET_BAND
, &band
, sizeof(band
), true);
21634 WL_ERR(("WLC_SET_BAND error %d\n", ret
));
21638 /* Best channel selection in 5GHz band. */
21639 ret
= wl_cfg80211_get_chanspecs_5g(ndev
, (void *)buf
, CHANSPEC_BUF_SIZE
);
21641 WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret
));
21645 ret
= wl_cfg80211_get_best_channel(ndev
, (void *)buf
, CHANSPEC_BUF_SIZE
,
21648 WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret
));
21652 if (CHANNEL_IS_5G(channel
)) {
21653 // channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
21655 WL_ERR(("invalid 5GHz channel, channel = %d\n", channel
));
21659 ret
= wldev_ioctl(dev
, WLC_SET_BAND
, &band_cur
, sizeof(band_cur
), true);
21661 WL_ERR(("WLC_SET_BAND error %d\n", ret
));
21662 pos
+= snprintf(pos
, total_len
, "5g=%d ", channel
);
21667 MFREE(cfg
->osh
, buf
, CHANSPEC_BUF_SIZE
);
21670 /* Restore FW and driver back to normal state. */
21671 ret
= wl_cfg80211_restore_auto_channel_scan_state(ndev
);
21673 WL_ERR(("can't restore auto channel scan state, error = %d\n", ret
));
21676 WL_MSG(ndev
->name
, "%s\n", cmd
);
21678 return (pos
- cmd
);
21680 #endif /* WL_SUPPORT_AUTO_CHANNEL */
21682 static const struct rfkill_ops wl_rfkill_ops
= {
21683 .set_block
= wl_rfkill_set
21686 static int wl_rfkill_set(void *data
, bool blocked
)
21688 struct bcm_cfg80211
*cfg
= (struct bcm_cfg80211
*)data
;
21690 WL_DBG(("Enter \n"));
21691 WL_DBG(("RF %s\n", blocked
? "blocked" : "unblocked"));
21696 cfg
->rf_blocked
= blocked
;
21701 static int wl_setup_rfkill(struct bcm_cfg80211
*cfg
, bool setup
)
21705 WL_DBG(("Enter \n"));
21709 cfg
->rfkill
= rfkill_alloc("brcmfmac-wifi",
21710 wl_cfg80211_get_parent_dev(),
21711 RFKILL_TYPE_WLAN
, &wl_rfkill_ops
, (void *)cfg
);
21713 if (!cfg
->rfkill
) {
21718 err
= rfkill_register(cfg
->rfkill
);
21721 rfkill_destroy(cfg
->rfkill
);
21723 if (!cfg
->rfkill
) {
21728 rfkill_unregister(cfg
->rfkill
);
21729 rfkill_destroy(cfg
->rfkill
);
21736 #ifdef DEBUGFS_CFG80211
21738 * Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
21739 * to turn on SCAN and DBG log.
21740 * To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
21741 * To see current setting of debug level,
21742 * cat /sys/kernel/debug/dhd/debug_level
21745 wl_debuglevel_write(struct file
*file
, const char __user
*userbuf
,
21746 size_t count
, loff_t
*ppos
)
21748 char tbuf
[SUBLOGLEVELZ
* ARRAYSIZE(sublogname_map
)], sublog
[SUBLOGLEVELZ
];
21749 char *params
, *token
, *colon
;
21750 uint i
, tokens
, log_on
= 0;
21751 size_t minsize
= min_t(size_t, (sizeof(tbuf
) - 1), count
);
21753 bzero(tbuf
, sizeof(tbuf
));
21754 bzero(sublog
, sizeof(sublog
));
21755 if (copy_from_user(&tbuf
, userbuf
, minsize
)) {
21759 tbuf
[minsize
] = '\0';
21761 colon
= strchr(params
, '\n');
21764 while ((token
= strsep(¶ms
, " ")) != NULL
) {
21765 bzero(sublog
, sizeof(sublog
));
21766 if (token
== NULL
|| !*token
)
21768 if (*token
== '\0')
21770 colon
= strchr(token
, ':');
21771 if (colon
!= NULL
) {
21774 tokens
= sscanf(token
, "%"S(SUBLOGLEVEL
)"s %u", sublog
, &log_on
);
21779 for (i
= 0; i
< ARRAYSIZE(sublogname_map
); i
++) {
21780 if (!strncmp(sublog
, sublogname_map
[i
].sublogname
,
21781 strlen(sublogname_map
[i
].sublogname
))) {
21784 (sublogname_map
[i
].log_level
);
21787 ~(sublogname_map
[i
].log_level
);
21791 WL_ERR(("%s: can't parse '%s' as a "
21792 "SUBMODULE:LEVEL (%d tokens)\n",
21793 tbuf
, token
, tokens
));
21800 wl_debuglevel_read(struct file
*file
, char __user
*user_buf
,
21801 size_t count
, loff_t
*ppos
)
21804 char tbuf
[SUBLOGLEVELZ
* ARRAYSIZE(sublogname_map
)];
21806 bzero(tbuf
, sizeof(tbuf
));
21808 for (i
= 0; i
< ARRAYSIZE(sublogname_map
); i
++) {
21809 param
+= snprintf(param
, sizeof(tbuf
) - 1, "%s:%d ",
21810 sublogname_map
[i
].sublogname
,
21811 (wl_dbg_level
& sublogname_map
[i
].log_level
) ? 1 : 0);
21814 return simple_read_from_buffer(user_buf
, count
, ppos
, tbuf
, strlen(&tbuf
[0]));
21817 static const struct file_operations fops_debuglevel
= {
21819 .write
= wl_debuglevel_write
,
21820 .read
= wl_debuglevel_read
,
21821 .owner
= THIS_MODULE
,
21825 static s32
wl_setup_debugfs(struct bcm_cfg80211
*cfg
)
21828 struct dentry
*_dentry
;
21831 cfg
->debugfs
= debugfs_create_dir(KBUILD_MODNAME
, NULL
);
21832 if (!cfg
->debugfs
|| IS_ERR(cfg
->debugfs
)) {
21833 if (cfg
->debugfs
== ERR_PTR(-ENODEV
))
21834 WL_ERR(("Debugfs is not enabled on this kernel\n"));
21836 WL_ERR(("Can not create debugfs directory\n"));
21837 cfg
->debugfs
= NULL
;
21841 _dentry
= debugfs_create_file("debug_level", S_IRUSR
| S_IWUSR
,
21842 cfg
->debugfs
, cfg
, &fops_debuglevel
);
21843 if (!_dentry
|| IS_ERR(_dentry
)) {
21844 WL_ERR(("failed to create debug_level debug file\n"));
21845 wl_free_debugfs(cfg
);
21850 static s32
wl_free_debugfs(struct bcm_cfg80211
*cfg
)
21855 debugfs_remove_recursive(cfg
->debugfs
);
21856 cfg
->debugfs
= NULL
;
21859 #endif /* DEBUGFS_CFG80211 */
21861 struct bcm_cfg80211
*wl_cfg80211_get_bcmcfg(void)
21866 void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211
*cfg
)
21871 struct device
*wl_cfg80211_get_parent_dev(void)
21873 return cfg80211_parent_dev
;
21876 void wl_cfg80211_set_parent_dev(void *dev
)
21878 cfg80211_parent_dev
= dev
;
21881 static void wl_cfg80211_clear_parent_dev(void)
21883 cfg80211_parent_dev
= NULL
;
21886 void get_primary_mac(struct bcm_cfg80211
*cfg
, struct ether_addr
*mac
)
21888 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
21890 if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg
),
21891 "cur_etheraddr", NULL
, 0, ioctl_buf
, sizeof(ioctl_buf
),
21892 0, NULL
) == BCME_OK
) {
21893 memcpy(mac
->octet
, ioctl_buf
, ETHER_ADDR_LEN
);
21895 bzero(mac
->octet
, ETHER_ADDR_LEN
);
21898 static bool check_dev_role_integrity(struct bcm_cfg80211
*cfg
, u32 dev_role
)
21900 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
21901 if (((dev_role
== NL80211_IFTYPE_AP
) &&
21902 !(dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) ||
21903 ((dev_role
== NL80211_IFTYPE_P2P_GO
) &&
21904 !(dhd
->op_mode
& DHD_FLAG_P2P_GO_MODE
)))
21906 WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role
, dhd
->op_mode
));
21912 int wl_cfg80211_do_driver_init(struct net_device
*net
)
21914 struct bcm_cfg80211
*cfg
= *(struct bcm_cfg80211
**)netdev_priv(net
);
21916 if (!cfg
|| !cfg
->wdev
)
21919 if (dhd_do_driver_init(cfg
->wdev
->netdev
) < 0)
21925 void wl_cfg80211_enable_trace(u32 level
)
21927 wl_dbg_level
= level
;
21928 WL_MSG("wlan", "wl_dbg_level = 0x%x\n", wl_dbg_level
);
21931 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
21934 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy
*wiphy
,
21935 bcm_struct_cfgdev
*cfgdev
, u64 cookie
)
21937 /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
21938 * is passed with CMD_FRAME. This callback is supposed to cancel
21939 * the OFFCHANNEL Wait. Since we are already taking care of that
21940 * with the tx_mgmt logic, do nothing here.
21945 #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
21947 #ifdef WL_HOST_BAND_MGMT
21949 wl_cfg80211_set_band(struct net_device
*ndev
, int band
)
21951 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21953 char ioctl_buf
[50];
21955 if ((band
< WLC_BAND_AUTO
) || (band
> WLC_BAND_2G
)) {
21956 WL_ERR(("Invalid band\n"));
21960 if ((ret
= wldev_iovar_setbuf(ndev
, "roam_band", &band
,
21961 sizeof(int), ioctl_buf
, sizeof(ioctl_buf
), NULL
)) < 0) {
21962 WL_ERR(("seting roam_band failed code=%d\n", ret
));
21966 WL_DBG(("Setting band to %d\n", band
));
21967 cfg
->curr_band
= band
;
21971 #endif /* WL_HOST_BAND_MGMT */
21974 wl_cfg80211_set_if_band(struct net_device
*ndev
, int band
)
21976 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21977 int ret
= BCME_OK
, wait_cnt
;
21978 char ioctl_buf
[32];
21980 if ((band
< WLC_BAND_AUTO
) || (band
> WLC_BAND_2G
)) {
21981 WL_ERR(("Invalid band\n"));
21985 if (cfg
->ncho_band
== band
) {
21986 WL_ERR(("Same to Current band %d\n", cfg
->ncho_band
));
21990 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
21991 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
21992 BCM_REFERENCE(dhdp
);
21993 DHD_STATLOG_CTRL(dhdp
, ST(DISASSOC_INT_START
),
21994 dhd_net2idx(dhdp
->info
, ndev
), 0);
21995 ret
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, NULL
, 0);
21997 WL_ERR(("WLC_DISASSOC error %d\n", ret
));
21998 /* continue to set 'if_band' */
22001 /* This is to ensure that 'if_band' iovar is issued only after
22002 * disconnection is completed
22004 wait_cnt
= WAIT_FOR_DISCONNECT_MAX
;
22005 while (wl_get_drv_status(cfg
, CONNECTED
, ndev
) && wait_cnt
) {
22006 WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt
));
22012 if ((ret
= wldev_iovar_setbuf(ndev
, "if_band", &band
,
22013 sizeof(int), ioctl_buf
, sizeof(ioctl_buf
), NULL
)) < 0) {
22014 WL_ERR(("seting if_band failed ret=%d\n", ret
));
22015 /* issue 'WLC_SET_BAND' if if_band is not supported */
22016 if (ret
== BCME_UNSUPPORTED
) {
22017 ret
= wldev_set_band(ndev
, band
);
22019 WL_ERR(("seting band failed ret=%d\n", ret
));
22024 if (ret
== BCME_OK
) {
22025 cfg
->ncho_band
= band
;
22031 wl_cfg80211_dfs_ap_move(struct net_device
*ndev
, char *data
, char *command
, int total_len
)
22033 char ioctl_buf
[WLC_IOCTL_SMLEN
];
22036 chanspec_t chanspec
= 0;
22038 int bytes_written
= 0;
22039 struct wl_dfs_ap_move_status_v2
*status
;
22040 char chanbuf
[CHANSPEC_STR_LEN
];
22041 const char *dfs_state_str
[DFS_SCAN_S_MAX
] = {
22042 "Radar Free On Channel",
22043 "Radar Found On Channel",
22044 "Radar Scan In Progress",
22045 "Radar Scan Aborted",
22046 "RSDB Mode switch in Progress For Scan"
22048 if (ndev
->ieee80211_ptr
->iftype
!= NL80211_IFTYPE_AP
) {
22049 bytes_written
= snprintf(command
, total_len
, "AP is not up\n");
22050 return bytes_written
;
22053 if ((err
= wldev_iovar_getbuf(ndev
, "dfs_ap_move", NULL
, 0,
22054 ioctl_buf
, sizeof(ioctl_buf
), NULL
))) {
22055 WL_ERR(("setting dfs_ap_move failed with err=%d \n", err
));
22058 status
= (struct wl_dfs_ap_move_status_v2
*)ioctl_buf
;
22060 if (status
->version
!= WL_DFS_AP_MOVE_VERSION
) {
22061 err
= BCME_UNSUPPORTED
;
22062 WL_ERR(("err=%d version=%d\n", err
, status
->version
));
22066 if (status
->move_status
!= (int8
) DFS_SCAN_S_IDLE
) {
22067 chanspec
= wl_chspec_driver_to_host(status
->chanspec
);
22068 if (chanspec
!= 0 && chanspec
!= INVCHANSPEC
) {
22069 wf_chspec_ntoa(chanspec
, chanbuf
);
22070 bytes_written
= snprintf(command
, total_len
,
22071 "AP Target Chanspec %s (0x%x)\n", chanbuf
, chanspec
);
22073 bytes_written
+= snprintf(command
+ bytes_written
,
22074 total_len
- bytes_written
,
22075 "%s\n", dfs_state_str
[status
->move_status
]);
22076 return bytes_written
;
22078 bytes_written
= snprintf(command
, total_len
, "dfs AP move in IDLE state\n");
22079 return bytes_written
;
22083 abort
= bcm_atoi(data
);
22085 if ((err
= wldev_iovar_setbuf(ndev
, "dfs_ap_move", &abort
,
22086 sizeof(int), ioctl_buf
, sizeof(ioctl_buf
), NULL
)) < 0) {
22087 WL_ERR(("seting dfs_ap_move failed with err %d\n", err
));
22091 chanspec
= wf_chspec_aton(data
);
22092 if (chanspec
!= 0) {
22093 val
= wl_chspec_host_to_driver(chanspec
);
22094 if (val
!= INVCHANSPEC
) {
22095 if ((err
= wldev_iovar_setbuf(ndev
, "dfs_ap_move", &val
,
22096 sizeof(int), ioctl_buf
, sizeof(ioctl_buf
), NULL
)) < 0) {
22097 WL_ERR(("seting dfs_ap_move failed with err %d\n", err
));
22100 WL_DBG((" set dfs_ap_move successfull"));
22102 err
= BCME_USAGE_ERROR
;
22109 bool wl_cfg80211_is_concurrent_mode(struct net_device
*dev
)
22111 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22112 if ((cfg
) && (wl_get_drv_status_all(cfg
, CONNECTED
) > 1)) {
22120 * This is to support existing btcoex implementation
22121 * btcoex clean up may help removing this function
22123 void* wl_cfg80211_get_dhdp(struct net_device
*dev
)
22125 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22130 bool wl_cfg80211_is_p2p_active(struct net_device
*dev
)
22132 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22133 return (cfg
&& cfg
->p2p
);
22136 bool wl_cfg80211_is_roam_offload(struct net_device
* dev
)
22138 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22139 return (cfg
&& cfg
->roam_offload
);
22142 bool wl_cfg80211_is_event_from_connected_bssid(struct net_device
* dev
, const wl_event_msg_t
*e
,
22145 u8
*curbssid
= NULL
;
22146 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22149 /* When interface is created using wl
22150 * ndev->ieee80211_ptr will be NULL.
22154 curbssid
= wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
22156 if (memcmp(curbssid
, &e
->addr
, ETHER_ADDR_LEN
) == 0) {
22162 static void wl_cfg80211_work_handler(struct work_struct
* work
)
22164 struct bcm_cfg80211
*cfg
= NULL
;
22165 struct net_info
*iter
, *next
;
22169 BCM_SET_CONTAINER_OF(cfg
, work
, struct bcm_cfg80211
, pm_enable_work
.work
);
22170 WL_DBG(("Enter \n"));
22171 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22172 for_each_ndev(cfg
, iter
, next
) {
22173 GCC_DIAGNOSTIC_POP();
22174 /* p2p discovery iface ndev could be null */
22176 if (!wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
) ||
22177 (wl_get_mode_by_netdev(cfg
, iter
->ndev
) != WL_MODE_BSS
&&
22178 wl_get_mode_by_netdev(cfg
, iter
->ndev
) != WL_MODE_IBSS
))
22181 dhd
= (dhd_pub_t
*)(cfg
->pub
);
22182 if (dhd_conf_get_pm(dhd
) >= 0)
22183 pm
= dhd_conf_get_pm(dhd
);
22184 if ((err
= wldev_ioctl_set(iter
->ndev
, WLC_SET_PM
,
22185 &pm
, sizeof(pm
))) != 0) {
22186 if (err
== -ENODEV
)
22187 WL_DBG(("%s:netdev not ready\n",
22188 iter
->ndev
->name
));
22190 WL_ERR(("%s:error (%d)\n",
22191 iter
->ndev
->name
, err
));
22193 wl_cfg80211_update_power_mode(iter
->ndev
);
22198 DHD_PM_WAKE_UNLOCK(cfg
->pub
);
22203 wl_get_action_category(void *frame
, u32 frame_len
)
22206 u8
*ptr
= (u8
*)frame
;
22208 return DOT11_ACTION_CAT_ERR_MASK
;
22209 if (frame_len
< DOT11_ACTION_HDR_LEN
)
22210 return DOT11_ACTION_CAT_ERR_MASK
;
22211 category
= ptr
[DOT11_ACTION_CAT_OFF
];
22212 WL_DBG(("Action Category: %d\n", category
));
22217 wl_get_public_action(void *frame
, u32 frame_len
, u8
*ret_action
)
22219 u8
*ptr
= (u8
*)frame
;
22220 if (frame
== NULL
|| ret_action
== NULL
)
22222 if (frame_len
< DOT11_ACTION_HDR_LEN
)
22224 if (DOT11_ACTION_CAT_PUBLIC
!= wl_get_action_category(frame
, frame_len
))
22226 *ret_action
= ptr
[DOT11_ACTION_ACT_OFF
];
22227 WL_DBG(("Public Action : %d\n", *ret_action
));
22233 wl_cfg80211_get_fbt_key(struct net_device
*dev
, uint8
*key
, int total_len
)
22235 struct bcm_cfg80211
* cfg
= wl_get_cfg(dev
);
22236 int bytes_written
= -1;
22238 if (total_len
< FBT_KEYLEN
) {
22239 WL_ERR(("wl_cfg80211_get_fbt_key: Insufficient buffer \n"));
22243 memcpy(key
, cfg
->fbt_key
, FBT_KEYLEN
);
22244 bytes_written
= FBT_KEYLEN
;
22246 bzero(key
, FBT_KEYLEN
);
22247 WL_ERR(("wl_cfg80211_get_fbt_key: Failed to copy KCK and KEK \n"));
22249 prhex("KCK, KEK", (uchar
*)key
, FBT_KEYLEN
);
22251 return bytes_written
;
22256 wl_cfg80211_delayed_roam(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
22257 const struct ether_addr
*bssid
)
22262 bzero(&e
, sizeof(e
));
22263 e
.event_type
= cpu_to_be32(WLC_E_ROAM
);
22264 memcpy(&e
.addr
, bssid
, ETHER_ADDR_LEN
);
22265 /* trigger the roam event handler */
22266 err
= wl_notify_roaming_status(cfg
, ndev_to_cfgdev(ndev
), &e
, NULL
);
22272 wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t
*vndrie
)
22274 if (vndrie
->oui
[0] == FILS_EXTID_MNG_HLP_CONTAINER_ID
) {
22275 /* Skip adding fils HLP IE, its already done using
22276 * "WL_FILS_CMD_ADD_HLP_IE" subcmd.
22278 WL_DBG(("%s:SKIP ADDING FILS HLP EXTN ID\n", __func__
));
22285 wl_cfg80211_parse_vndr_ies(const u8
*parse
, u32 len
,
22286 struct parsed_vndr_ies
*vndr_ies
)
22289 const vndr_ie_t
*vndrie
;
22290 const bcm_tlv_t
*ie
;
22291 struct parsed_vndr_ie_info
*parsed_info
;
22295 remained_len
= len
;
22296 bzero(vndr_ies
, sizeof(*vndr_ies
));
22298 WL_DBG(("---> len %d\n", len
));
22299 ie
= (const bcm_tlv_t
*) parse
;
22300 if (!bcm_valid_tlv(ie
, remained_len
))
22303 if (count
>= MAX_VNDR_IE_NUMBER
)
22305 if (ie
->id
== DOT11_MNG_VS_ID
|| (ie
->id
== DOT11_MNG_ID_EXT_ID
)) {
22306 vndrie
= (const vndr_ie_t
*) ie
;
22307 if (ie
->id
== DOT11_MNG_ID_EXT_ID
) {
22308 /* len should be bigger than sizeof ID extn field at least */
22309 if (vndrie
->len
< MIN_VENDOR_EXTN_IE_LEN
) {
22310 WL_ERR(("%s: invalid vndr extn ie."
22312 __FUNCTION__
, vndrie
->len
));
22315 if (wl_cfg80211_filter_vndr_ext_id(vndrie
)) {
22319 /* len should be bigger than OUI length +
22320 * one data length at least
22322 if (vndrie
->len
< (VNDR_IE_MIN_LEN
+ 1)) {
22323 WL_ERR(("wl_cfg80211_parse_vndr_ies:"
22324 " invalid vndr ie. length is too small %d\n",
22329 /* if wpa or wme ie, do not add ie */
22330 if (!bcmp(vndrie
->oui
, (u8
*)WPA_OUI
, WPA_OUI_LEN
) &&
22331 ((vndrie
->data
[0] == WPA_OUI_TYPE
) ||
22332 (vndrie
->data
[0] == WME_OUI_TYPE
))) {
22333 CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
22338 parsed_info
= &vndr_ies
->ie_info
[count
++];
22340 /* save vndr ie information */
22341 parsed_info
->ie_ptr
= (const char *)vndrie
;
22342 parsed_info
->ie_len
= (vndrie
->len
+ TLV_HDR_LEN
);
22343 memcpy(&parsed_info
->vndrie
, vndrie
, sizeof(vndr_ie_t
));
22344 vndr_ies
->count
= count
;
22345 if (ie
->id
== DOT11_MNG_ID_EXT_ID
) {
22346 WL_DBG(("\t ** Vendor Extension ie id: 0x%02x, len:%d\n",
22347 ie
->id
, parsed_info
->ie_len
));
22349 WL_DBG(("\t ** OUI "MACOUIDBG
", type 0x%02x len:%d\n",
22350 MACOUI2STRDBG(parsed_info
->vndrie
.oui
),
22351 parsed_info
->vndrie
.data
[0], parsed_info
->ie_len
));
22355 ie
= bcm_next_tlv(ie
, &remained_len
);
22361 wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info
*vndr_info
)
22365 while (exclude_vndr_oui_list
[i
]) {
22366 if (!memcmp(vndr_info
->vndrie
.oui
,
22367 exclude_vndr_oui_list
[i
],
22378 wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211
*cfg
,
22379 struct parsed_vndr_ie_info
*vndr_info
)
22381 wl_vndr_oui_entry_t
*oui_entry
= NULL
;
22382 unsigned long flags
;
22384 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg
->vndr_oui_sync
, flags
);
22385 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22386 list_for_each_entry(oui_entry
, &cfg
->vndr_oui_list
, list
) {
22387 GCC_DIAGNOSTIC_POP();
22388 if (!memcmp(oui_entry
->oui
, vndr_info
->vndrie
.oui
, DOT11_OUI_LEN
)) {
22389 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg
->vndr_oui_sync
, flags
);
22393 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg
->vndr_oui_sync
, flags
);
22398 wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211
*cfg
,
22399 struct parsed_vndr_ie_info
*vndr_info
)
22401 wl_vndr_oui_entry_t
*oui_entry
= NULL
;
22402 unsigned long flags
;
22404 oui_entry
= kmalloc(sizeof(*oui_entry
), GFP_KERNEL
);
22405 if (oui_entry
== NULL
) {
22406 WL_ERR(("alloc failed\n"));
22410 memcpy(oui_entry
->oui
, vndr_info
->vndrie
.oui
, DOT11_OUI_LEN
);
22412 INIT_LIST_HEAD(&oui_entry
->list
);
22413 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg
->vndr_oui_sync
, flags
);
22414 list_add_tail(&oui_entry
->list
, &cfg
->vndr_oui_list
);
22415 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg
->vndr_oui_sync
, flags
);
22421 wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211
*cfg
)
22423 wl_vndr_oui_entry_t
*oui_entry
= NULL
;
22424 unsigned long flags
;
22426 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg
->vndr_oui_sync
, flags
);
22427 while (!list_empty(&cfg
->vndr_oui_list
)) {
22428 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22429 oui_entry
= list_entry(cfg
->vndr_oui_list
.next
, wl_vndr_oui_entry_t
, list
);
22430 GCC_DIAGNOSTIC_POP();
22432 list_del(&oui_entry
->list
);
22436 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg
->vndr_oui_sync
, flags
);
22440 wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
22441 char *vndr_oui
, u32 vndr_oui_len
)
22444 int vndr_oui_num
= 0;
22446 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
22447 wl_vndr_oui_entry_t
*oui_entry
= NULL
;
22448 struct parsed_vndr_ie_info
*vndr_info
;
22449 struct parsed_vndr_ies vndr_ies
;
22451 char *pos
= vndr_oui
;
22452 u32 remained_buf_len
= vndr_oui_len
;
22453 unsigned long flags
;
22455 if (!conn_info
->resp_ie_len
) {
22459 wl_vndr_ies_clear_vendor_oui_list(cfg
);
22461 if ((wl_cfg80211_parse_vndr_ies((u8
*)conn_info
->resp_ie
,
22462 conn_info
->resp_ie_len
, &vndr_ies
)) == BCME_OK
) {
22463 for (i
= 0; i
< vndr_ies
.count
; i
++) {
22464 vndr_info
= &vndr_ies
.ie_info
[i
];
22465 if (wl_vndr_ies_exclude_vndr_oui(vndr_info
)) {
22469 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg
, vndr_info
)) {
22473 wl_vndr_ies_add_vendor_oui_list(cfg
, vndr_info
);
22479 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg
->vndr_oui_sync
, flags
);
22480 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22481 list_for_each_entry(oui_entry
, &cfg
->vndr_oui_list
, list
) {
22482 GCC_DIAGNOSTIC_POP();
22483 if (remained_buf_len
< VNDR_OUI_STR_LEN
) {
22484 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg
->vndr_oui_sync
, flags
);
22487 pos
+= snprintf(pos
, VNDR_OUI_STR_LEN
, "%02X-%02X-%02X ",
22488 oui_entry
->oui
[0], oui_entry
->oui
[1], oui_entry
->oui
[2]);
22489 remained_buf_len
-= VNDR_OUI_STR_LEN
;
22491 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg
->vndr_oui_sync
, flags
);
22494 return vndr_oui_num
;
22497 #ifdef WL_ANALYTICS
22499 wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
22500 const char *vndr_oui
)
22503 int vndr_oui_num
= 0;
22505 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
22506 wl_vndr_oui_entry_t
*oui_entry
= NULL
;
22507 struct parsed_vndr_ie_info
*vndr_info
;
22508 struct parsed_vndr_ies vndr_ies
;
22510 unsigned long flags
;
22511 bool found
= FALSE
;
22513 if (!conn_info
->resp_ie_len
) {
22517 wl_vndr_ies_clear_vendor_oui_list(cfg
);
22519 if ((wl_cfg80211_parse_vndr_ies((u8
*)conn_info
->resp_ie
,
22520 conn_info
->resp_ie_len
, &vndr_ies
)) == BCME_OK
) {
22521 for (i
= 0; i
< vndr_ies
.count
; i
++) {
22522 vndr_info
= &vndr_ies
.ie_info
[i
];
22523 if (wl_vndr_ies_exclude_vndr_oui(vndr_info
)) {
22527 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg
, vndr_info
)) {
22531 wl_vndr_ies_add_vendor_oui_list(cfg
, vndr_info
);
22536 if (vndr_oui
&& vndr_oui_num
) {
22537 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg
->vndr_oui_sync
, flags
);
22538 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22539 list_for_each_entry(oui_entry
, &cfg
->vndr_oui_list
, list
) {
22540 GCC_DIAGNOSTIC_POP();
22541 if (!memcmp(vndr_oui
, oui_entry
->oui
, DOT11_OUI_LEN
)) {
22546 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg
->vndr_oui_sync
, flags
);
22551 #endif /* WL_ANALYTICS */
22554 wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211
*cfg
)
22556 /* Legacy P2P used to store it in primary dev cache */
22558 struct net_device
*ndev
;
22561 s32 vndrie_flag
[] = {VNDR_IE_BEACON_FLAG
, VNDR_IE_PRBRSP_FLAG
,
22562 VNDR_IE_ASSOCRSP_FLAG
, VNDR_IE_PRBREQ_FLAG
, VNDR_IE_ASSOCREQ_FLAG
};
22564 WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
22565 /* certain vendors uses p2p0 interface in addition to
22566 * the dedicated p2p interface supported by the linux
22569 ndev
= wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_PRIMARY
);
22570 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
22571 if (bssidx
== WL_INVALID
) {
22572 WL_DBG(("No discovery I/F available. Do nothing.\n"));
22576 for (index
= 0; index
< ARRAYSIZE(vndrie_flag
); index
++) {
22577 if ((ret
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(ndev
),
22578 bssidx
, vndrie_flag
[index
], NULL
, 0)) < 0) {
22579 if (ret
!= BCME_NOTFOUND
) {
22580 WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret
));
22585 if (cfg
->p2p_wdev
&& (ndev
->ieee80211_ptr
!= cfg
->p2p_wdev
)) {
22586 /* clear IEs for dedicated p2p interface */
22587 wl_cfg80211_clear_per_bss_ies(cfg
, cfg
->p2p_wdev
);
22592 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211
*cfg
, struct wireless_dev
*wdev
)
22596 struct net_info
*netinfo
;
22597 s32 vndrie_flag
[] = {VNDR_IE_BEACON_FLAG
, VNDR_IE_PRBRSP_FLAG
,
22598 VNDR_IE_ASSOCRSP_FLAG
, VNDR_IE_PRBREQ_FLAG
, VNDR_IE_ASSOCREQ_FLAG
};
22600 netinfo
= wl_get_netinfo_by_wdev(cfg
, wdev
);
22601 if (!netinfo
|| !netinfo
->wdev
) {
22602 WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
22606 WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo
->bssidx
));
22607 /* Clear the IEs set in the firmware so that host is in sync with firmware */
22608 for (index
= 0; index
< ARRAYSIZE(vndrie_flag
); index
++) {
22609 if ((ret
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, wdev_to_cfgdev(netinfo
->wdev
),
22610 netinfo
->bssidx
, vndrie_flag
[index
], NULL
, 0)) < 0)
22611 if (ret
!= BCME_NOTFOUND
) {
22612 WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
22620 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211
*cfg
)
22622 struct net_info
*iter
, *next
;
22624 WL_DBG(("clear management vendor IEs \n"));
22625 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22626 for_each_ndev(cfg
, iter
, next
) {
22627 GCC_DIAGNOSTIC_POP();
22628 wl_cfg80211_clear_per_bss_ies(cfg
, iter
->wdev
);
22633 #define WL_VNDR_IE_MAXLEN 2048
22634 static s8 g_mgmt_ie_buf
[WL_VNDR_IE_MAXLEN
];
22636 wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
22637 s32 bssidx
, s32 pktflag
, const u8
*vndr_ie
, u32 vndr_ie_len
)
22639 struct net_device
*ndev
= NULL
;
22641 u8
*curr_ie_buf
= NULL
;
22642 u8
*mgmt_ie_buf
= NULL
;
22643 u32 mgmt_ie_buf_len
= 0;
22644 u32
*mgmt_ie_len
= 0;
22645 u32 del_add_ie_buf_len
= 0;
22646 u32 total_ie_buf_len
= 0;
22647 u32 parsed_ie_buf_len
= 0;
22648 struct parsed_vndr_ies old_vndr_ies
;
22649 struct parsed_vndr_ies new_vndr_ies
;
22652 s32 remained_buf_len
;
22653 wl_bss_vndr_ies_t
*ies
= NULL
;
22654 struct net_info
*netinfo
;
22655 struct wireless_dev
*wdev
;
22658 WL_ERR(("cfgdev is NULL\n"));
22662 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
22663 wdev
= cfgdev_to_wdev(cfgdev
);
22665 if (bssidx
> WL_MAX_IFS
) {
22666 WL_ERR(("bssidx > supported concurrent Ifaces \n"));
22670 netinfo
= wl_get_netinfo_by_wdev(cfg
, wdev
);
22672 WL_ERR(("net_info ptr is NULL \n"));
22676 /* Clear the global buffer */
22677 bzero(g_mgmt_ie_buf
, sizeof(g_mgmt_ie_buf
));
22678 curr_ie_buf
= g_mgmt_ie_buf
;
22679 ies
= &netinfo
->bss
.ies
;
22681 WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d wdev:%p\n",
22682 pktflag
, bssidx
, vndr_ie_len
, wdev
));
22685 case VNDR_IE_PRBRSP_FLAG
:
22686 mgmt_ie_buf
= ies
->probe_res_ie
;
22687 mgmt_ie_len
= &ies
->probe_res_ie_len
;
22688 mgmt_ie_buf_len
= sizeof(ies
->probe_res_ie
);
22690 case VNDR_IE_ASSOCRSP_FLAG
:
22691 mgmt_ie_buf
= ies
->assoc_res_ie
;
22692 mgmt_ie_len
= &ies
->assoc_res_ie_len
;
22693 mgmt_ie_buf_len
= sizeof(ies
->assoc_res_ie
);
22695 case VNDR_IE_BEACON_FLAG
:
22696 mgmt_ie_buf
= ies
->beacon_ie
;
22697 mgmt_ie_len
= &ies
->beacon_ie_len
;
22698 mgmt_ie_buf_len
= sizeof(ies
->beacon_ie
);
22700 case VNDR_IE_PRBREQ_FLAG
:
22701 mgmt_ie_buf
= ies
->probe_req_ie
;
22702 mgmt_ie_len
= &ies
->probe_req_ie_len
;
22703 mgmt_ie_buf_len
= sizeof(ies
->probe_req_ie
);
22705 case VNDR_IE_ASSOCREQ_FLAG
:
22706 mgmt_ie_buf
= ies
->assoc_req_ie
;
22707 mgmt_ie_len
= &ies
->assoc_req_ie_len
;
22708 mgmt_ie_buf_len
= sizeof(ies
->assoc_req_ie
);
22710 case VNDR_IE_DISASSOC_FLAG
:
22711 mgmt_ie_buf
= ies
->disassoc_ie
;
22712 mgmt_ie_len
= &ies
->disassoc_ie_len
;
22713 mgmt_ie_buf_len
= sizeof(ies
->disassoc_ie
);
22716 mgmt_ie_buf
= NULL
;
22717 mgmt_ie_len
= NULL
;
22718 WL_ERR(("not suitable packet type (%d)\n", pktflag
));
22722 if (vndr_ie_len
> mgmt_ie_buf_len
) {
22723 WL_ERR(("extra IE size too big\n"));
22726 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
22727 if (vndr_ie
&& vndr_ie_len
&& curr_ie_buf
) {
22730 if ((ret
= wl_cfg80211_parse_vndr_ies((const u8
*)vndr_ie
,
22731 vndr_ie_len
, &new_vndr_ies
)) < 0) {
22732 WL_ERR(("parse vndr ie failed \n"));
22736 for (i
= 0; i
< new_vndr_ies
.count
; i
++) {
22737 struct parsed_vndr_ie_info
*vndrie_info
=
22738 &new_vndr_ies
.ie_info
[i
];
22740 if ((parsed_ie_buf_len
+ vndrie_info
->ie_len
) > WL_VNDR_IE_MAXLEN
) {
22741 WL_ERR(("IE size is too big (%d > %d)\n",
22742 parsed_ie_buf_len
, WL_VNDR_IE_MAXLEN
));
22747 memcpy(ptr
+ parsed_ie_buf_len
, vndrie_info
->ie_ptr
,
22748 vndrie_info
->ie_len
);
22749 parsed_ie_buf_len
+= vndrie_info
->ie_len
;
22753 if (mgmt_ie_buf
!= NULL
) {
22754 if (parsed_ie_buf_len
&& (parsed_ie_buf_len
== *mgmt_ie_len
) &&
22755 (memcmp(mgmt_ie_buf
, curr_ie_buf
, parsed_ie_buf_len
) == 0)) {
22756 WL_DBG(("Previous mgmt IE is equals to current IE"));
22760 /* parse old vndr_ie */
22761 if ((ret
= wl_cfg80211_parse_vndr_ies(mgmt_ie_buf
, *mgmt_ie_len
,
22762 &old_vndr_ies
)) < 0) {
22763 WL_ERR(("parse vndr ie failed \n"));
22766 /* make a command to delete old ie */
22767 for (i
= 0; i
< old_vndr_ies
.count
; i
++) {
22768 struct parsed_vndr_ie_info
*vndrie_info
=
22769 &old_vndr_ies
.ie_info
[i
];
22770 #if defined(WL_MBO) || defined(WL_OCE)
22772 if ((vndrie_info
->vndrie
.id
== 0xDD) &&
22773 (!memcmp(vndrie_info
->vndrie
.oui
, WFA_OUI
, WFA_OUI_LEN
)) &&
22774 (vndrie_info
->vndrie
.data
[0] == WFA_OUI_TYPE_MBO_OCE
)) {
22775 WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
22777 vndrie_info
->vndrie
.id
,
22778 vndrie_info
->vndrie
.len
,
22779 MACOUI2STRDBG(vndrie_info
->vndrie
.oui
),
22780 vndrie_info
->vndrie
.data
[0]));
22784 #endif /* WL_MBO || WL_OCE */
22786 if (vndrie_info
->vndrie
.id
== DOT11_MNG_ID_EXT_ID
) {
22787 WL_DBG(("DELETED VENDOR EXTN ID : %d, TYPE: %d Len: %d\n",
22788 vndrie_info
->vndrie
.id
, vndrie_info
->vndrie
.oui
[0],
22789 vndrie_info
->vndrie
.len
));
22791 WL_DBG(("DELETED ID : %d, Len: %d , OUI:"MACOUIDBG
"\n",
22792 vndrie_info
->vndrie
.id
, vndrie_info
->vndrie
.len
,
22793 MACOUI2STRDBG(vndrie_info
->vndrie
.oui
)));
22796 del_add_ie_buf_len
= wl_cfgp2p_vndr_ie(cfg
, curr_ie_buf
,
22797 pktflag
, vndrie_info
->vndrie
.oui
,
22798 vndrie_info
->vndrie
.id
,
22799 vndrie_info
->ie_ptr
+ VNDR_IE_FIXED_LEN
,
22800 vndrie_info
->ie_len
- VNDR_IE_FIXED_LEN
,
22803 curr_ie_buf
+= del_add_ie_buf_len
;
22804 total_ie_buf_len
+= del_add_ie_buf_len
;
22809 /* Add if there is any extra IE */
22810 if (mgmt_ie_buf
&& parsed_ie_buf_len
) {
22813 remained_buf_len
= mgmt_ie_buf_len
;
22815 /* make a command to add new ie */
22816 for (i
= 0; i
< new_vndr_ies
.count
; i
++) {
22817 struct parsed_vndr_ie_info
*vndrie_info
=
22818 &new_vndr_ies
.ie_info
[i
];
22819 #if defined(WL_MBO) || defined(WL_OCE)
22821 if ((vndrie_info
->vndrie
.id
== 0xDD) &&
22822 (!memcmp(vndrie_info
->vndrie
.oui
, WFA_OUI
, WFA_OUI_LEN
)) &&
22823 (vndrie_info
->vndrie
.data
[0] == WFA_OUI_TYPE_MBO_OCE
)) {
22824 WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
22826 vndrie_info
->vndrie
.id
,
22827 vndrie_info
->vndrie
.len
,
22828 MACOUI2STRDBG(vndrie_info
->vndrie
.oui
),
22829 vndrie_info
->vndrie
.data
[0]));
22833 #endif /* WL_MBO || WL_OCE */
22834 if (vndrie_info
->vndrie
.id
== DOT11_MNG_ID_EXT_ID
) {
22835 WL_DBG(("ADDED VENDOR EXTN ID : %d, TYPE = %d, Len: %d\n",
22836 vndrie_info
->vndrie
.id
, vndrie_info
->vndrie
.oui
[0],
22837 vndrie_info
->vndrie
.len
));
22839 WL_DBG(("ADDED ID : %d, Len: %d(%d), OUI:"MACOUIDBG
"\n",
22840 vndrie_info
->vndrie
.id
, vndrie_info
->vndrie
.len
,
22841 vndrie_info
->ie_len
- 2,
22842 MACOUI2STRDBG(vndrie_info
->vndrie
.oui
)));
22845 del_add_ie_buf_len
= wl_cfgp2p_vndr_ie(cfg
, curr_ie_buf
,
22846 pktflag
, vndrie_info
->vndrie
.oui
,
22847 vndrie_info
->vndrie
.id
,
22848 vndrie_info
->ie_ptr
+ VNDR_IE_FIXED_LEN
,
22849 vndrie_info
->ie_len
- VNDR_IE_FIXED_LEN
,
22852 /* verify remained buf size before copy data */
22853 if (remained_buf_len
>= vndrie_info
->ie_len
) {
22854 remained_buf_len
-= vndrie_info
->ie_len
;
22856 WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
22857 "found vndr ies # = %d(cur %d), remained len %d, "
22858 "cur mgmt_ie_len %d, new ie len = %d\n",
22859 pktflag
, new_vndr_ies
.count
, i
, remained_buf_len
,
22860 *mgmt_ie_len
, vndrie_info
->ie_len
));
22864 /* save the parsed IE in cfg struct */
22865 memcpy(ptr
+ (*mgmt_ie_len
), vndrie_info
->ie_ptr
,
22866 vndrie_info
->ie_len
);
22867 *mgmt_ie_len
+= vndrie_info
->ie_len
;
22868 curr_ie_buf
+= del_add_ie_buf_len
;
22869 total_ie_buf_len
+= del_add_ie_buf_len
;
22873 if (total_ie_buf_len
&& cfg
->ioctl_buf
!= NULL
) {
22874 ret
= wldev_iovar_setbuf_bsscfg(ndev
, "vndr_ie", g_mgmt_ie_buf
,
22875 total_ie_buf_len
, cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
,
22876 bssidx
, &cfg
->ioctl_buf_sync
);
22878 WL_ERR(("vndr ie set error : %d\n", ret
));
22886 #ifdef WL_CFG80211_ACL
22888 wl_cfg80211_set_mac_acl(struct wiphy
*wiphy
, struct net_device
*cfgdev
,
22889 const struct cfg80211_acl_data
*acl
)
22894 int macmode
= MACLIST_MODE_DISABLED
;
22895 struct maclist
*list
;
22896 struct bcm_cfg80211
*cfg
= wl_get_cfg(cfgdev
);
22898 /* get the MAC filter mode */
22899 if (acl
&& acl
->acl_policy
== NL80211_ACL_POLICY_DENY_UNLESS_LISTED
) {
22900 macmode
= MACLIST_MODE_ALLOW
;
22901 } else if (acl
&& acl
->acl_policy
== NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED
&&
22902 acl
->n_acl_entries
) {
22903 macmode
= MACLIST_MODE_DENY
;
22906 /* if acl == NULL, macmode is still disabled.. */
22907 if (macmode
== MACLIST_MODE_DISABLED
) {
22908 if ((ret
= wl_android_set_ap_mac_list(cfgdev
, macmode
, NULL
)) != 0)
22909 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list"
22910 " failed error=%d\n", ret
));
22915 macnum
= acl
->n_acl_entries
;
22916 if (macnum
< 0 || macnum
> MAX_NUM_MAC_FILT
) {
22917 WL_ERR(("wl_cfg80211_set_mac_acl: invalid number of MAC address entries %d\n",
22922 /* allocate memory for the MAC list */
22923 list
= (struct maclist
*)MALLOC(cfg
->osh
, sizeof(int) +
22924 sizeof(struct ether_addr
) * macnum
);
22926 WL_ERR(("wl_cfg80211_set_mac_acl: failed to allocate memory\n"));
22930 /* prepare the MAC list */
22931 list
->count
= htod32(macnum
);
22932 for (i
= 0; i
< macnum
; i
++) {
22933 memcpy(&list
->ea
[i
], &acl
->mac_addrs
[i
], ETHER_ADDR_LEN
);
22936 if ((ret
= wl_android_set_ap_mac_list(cfgdev
, macmode
, list
)) != 0)
22937 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list failed error=%d\n", ret
));
22939 MFREE(cfg
->osh
, list
, sizeof(int) +
22940 sizeof(struct ether_addr
) * macnum
);
22944 #endif /* WL_CFG80211_ACL */
22946 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22947 int wl_chspec_chandef(chanspec_t chanspec
,
22948 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
22949 struct cfg80211_chan_def
*chandef
,
22950 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
22951 struct chan_info
*chaninfo
,
22952 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
22953 struct wiphy
*wiphy
)
22958 struct ieee80211_channel
*chan
;
22963 channel
= CHSPEC_CHANNEL(chanspec
);
22965 switch (CHSPEC_BW(chanspec
)) {
22966 case WL_CHANSPEC_BW_20
:
22967 chan_type
= NL80211_CHAN_HT20
;
22969 case WL_CHANSPEC_BW_40
:
22971 if (CHSPEC_SB_UPPER(chanspec
)) {
22972 channel
+= CH_10MHZ_APART
;
22974 channel
-= CH_10MHZ_APART
;
22977 chan_type
= NL80211_CHAN_HT40PLUS
;
22980 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22981 case WL_CHANSPEC_BW_80
:
22982 case WL_CHANSPEC_BW_8080
:
22984 uint16 sb
= CHSPEC_CTL_SB(chanspec
);
22986 if (sb
== WL_CHANSPEC_CTL_SB_LL
) {
22987 channel
-= (CH_10MHZ_APART
+ CH_20MHZ_APART
);
22988 } else if (sb
== WL_CHANSPEC_CTL_SB_LU
) {
22989 channel
-= CH_10MHZ_APART
;
22990 } else if (sb
== WL_CHANSPEC_CTL_SB_UL
) {
22991 channel
+= CH_10MHZ_APART
;
22993 /* WL_CHANSPEC_CTL_SB_UU */
22994 channel
+= (CH_10MHZ_APART
+ CH_20MHZ_APART
);
22997 if (sb
== WL_CHANSPEC_CTL_SB_LL
|| sb
== WL_CHANSPEC_CTL_SB_LU
)
22998 chan_type
= NL80211_CHAN_HT40MINUS
;
22999 else if (sb
== WL_CHANSPEC_CTL_SB_UL
|| sb
== WL_CHANSPEC_CTL_SB_UU
)
23000 chan_type
= NL80211_CHAN_HT40PLUS
;
23003 case WL_CHANSPEC_BW_160
:
23004 channel
= wf_chspec_primary20_chan(chanspec
);
23005 /* Using base chan_type as kernel does not define chan_type for 160 MHz */
23006 chan_type
= NL80211_CHAN_HT20
;
23008 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23010 chan_type
= NL80211_CHAN_HT20
;
23014 freq
= wl_channel_to_frequency(channel
, CHSPEC_BAND(chanspec
));
23015 chan
= ieee80211_get_channel(wiphy
, freq
);
23016 WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
23017 channel
, freq
, chan_type
, chan
));
23018 if (unlikely(!chan
)) {
23019 /* fw and cfg80211 channel lists are not in sync */
23020 WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
23025 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
23026 cfg80211_chandef_create(chandef
, chan
, chan_type
);
23027 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
23029 chaninfo
->freq
= freq
;
23030 chaninfo
->chan_type
= chan_type
;
23031 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23036 wl_cfg80211_ch_switch_notify(struct net_device
*dev
, uint16 chanspec
, struct wiphy
*wiphy
)
23039 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
23040 struct cfg80211_chan_def chandef
;
23041 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
23042 struct chan_info chaninfo
;
23043 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23046 WL_ERR(("wiphy is null\n"));
23049 #if (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0))
23050 /* Channel switch support is only for AP/GO/ADHOC/MESH */
23051 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
||
23052 dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_CLIENT
) {
23053 WL_ERR(("No channel switch notify support for STA/GC\n"));
23056 #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
23058 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
23059 if (wl_chspec_chandef(chanspec
, &chandef
, wiphy
))
23060 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
23061 if (wl_chspec_chandef(chanspec
, &chaninfo
, wiphy
))
23062 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23064 WL_ERR(("chspec_chandef failed\n"));
23067 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
23068 freq
= chandef
.chan
? chandef
.chan
->center_freq
: chandef
.center_freq1
;
23069 cfg80211_ch_switch_notify(dev
, &chandef
);
23070 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
23071 freq
= chan_info
.freq
;
23072 cfg80211_ch_switch_notify(dev
, freq
, chan_info
.chan_type
);
23073 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23075 WL_MSG(dev
->name
, "Channel switch notification for freq: %d chanspec: 0x%x\n",
23079 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
23082 wl_ap_channel_ind(struct bcm_cfg80211
*cfg
,
23083 struct net_device
*ndev
,
23084 chanspec_t chanspec
)
23086 u32 channel
= LCHSPEC_CHANNEL(chanspec
);
23088 WL_INFORM_MEM(("(%s) AP channel:%d chspec:0x%x \n",
23089 ndev
->name
, channel
, chanspec
));
23091 #ifdef SUPPORT_AP_BWCTRL
23092 wl_update_apchan_bwcap(cfg
, ndev
, chanspec
);
23093 #endif /* SUPPORT_AP_BWCTRL */
23095 if (!(cfg
->ap_oper_channel
== INVCHANSPEC
) && (cfg
->ap_oper_channel
!= chanspec
)) {
23097 * If cached channel is different from the channel indicated
23098 * by the event, notify user space about the channel switch.
23100 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
23101 wl_cfg80211_ch_switch_notify(ndev
, chanspec
, bcmcfg_to_wiphy(cfg
));
23102 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
23103 cfg
->ap_oper_channel
= chanspec
;
23108 wl_ap_start_ind(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
23109 const wl_event_msg_t
*e
, void *data
)
23111 struct net_device
*ndev
= NULL
;
23112 chanspec_t chanspec
;
23114 WL_DBG(("Enter\n"));
23115 if (unlikely(e
->status
)) {
23116 WL_ERR(("status:0x%x \n", e
->status
));
23124 if (likely(cfgdev
)) {
23125 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
23126 chanspec
= *((chanspec_t
*)data
);
23128 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
) {
23129 /* For AP/GO role */
23130 wl_ap_channel_ind(cfg
, ndev
, chanspec
);
23138 wl_csa_complete_ind(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
23139 const wl_event_msg_t
*e
, void *data
)
23143 struct net_device
*ndev
= NULL
;
23144 struct ether_addr bssid
;
23146 WL_DBG(("Enter\n"));
23147 if (unlikely(e
->status
)) {
23148 WL_ERR(("status:0x%x \n", e
->status
));
23152 if (likely(cfgdev
)) {
23153 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
23154 /* Get association state if not AP and then query chanspec */
23155 if (!((wl_get_mode_by_netdev(cfg
, ndev
)) == WL_MODE_AP
)) {
23156 error
= wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
23158 WL_ERR(("CSA on %s. Not associated. error=%d\n",
23159 ndev
->name
, error
));
23164 error
= wldev_iovar_getint(ndev
, "chanspec", &chanspec
);
23165 if (unlikely(error
)) {
23166 WL_ERR(("Get chanspec error: %d \n", error
));
23170 WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev
->name
, chanspec
));
23171 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
) {
23172 /* For AP/GO role */
23173 wl_ap_channel_ind(cfg
, ndev
, chanspec
);
23176 if (!wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
23177 WL_ERR(("CSA on %s. Not associated.\n", ndev
->name
));
23180 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
23181 wl_cfg80211_ch_switch_notify(ndev
, chanspec
, bcmcfg_to_wiphy(cfg
));
23182 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
23190 void wl_cfg80211_clear_security(struct bcm_cfg80211
*cfg
)
23192 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
23195 /* Clear the security settings on the primary Interface */
23196 err
= wldev_iovar_setint(dev
, "wsec", 0);
23197 if (unlikely(err
)) {
23198 WL_ERR(("wsec clear failed \n"));
23200 err
= wldev_iovar_setint(dev
, "auth", 0);
23201 if (unlikely(err
)) {
23202 WL_ERR(("auth clear failed \n"));
23204 err
= wldev_iovar_setint(dev
, "wpa_auth", WPA_AUTH_DISABLED
);
23205 if (unlikely(err
)) {
23206 WL_ERR(("wpa_auth clear failed \n"));
23210 #ifdef WL_CFG80211_P2P_DEV_IF
23211 void wl_cfg80211_del_p2p_wdev(struct net_device
*dev
)
23213 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23214 struct wireless_dev
*wdev
= NULL
;
23216 WL_DBG(("Enter \n"));
23218 WL_ERR(("Invalid Ptr\n"));
23221 wdev
= cfg
->p2p_wdev
;
23225 wl_cfgp2p_del_p2p_disc_if(wdev
, cfg
);
23228 #endif /* WL_CFG80211_P2P_DEV_IF */
23230 #ifdef GTK_OFFLOAD_SUPPORT
23231 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
23233 wl_cfg80211_set_rekey_data(struct wiphy
*wiphy
, struct net_device
*dev
,
23234 struct cfg80211_gtk_rekey_data
*data
)
23236 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
23238 gtk_keyinfo_t keyinfo
;
23239 bcol_gtk_para_t bcol_keyinfo
;
23241 WL_DBG(("Enter\n"));
23242 if (data
== NULL
|| cfg
->p2p_net
== dev
) {
23243 WL_ERR(("data is NULL or wrong net device\n"));
23247 prhex("kck", (const u8
*) (data
->kck
), RSN_KCK_LENGTH
);
23248 prhex("kek", (const u8
*) (data
->kek
), RSN_KEK_LENGTH
);
23249 prhex("replay_ctr", (const u8
*) (data
->replay_ctr
), RSN_REPLAY_LEN
);
23250 bcopy(data
->kck
, keyinfo
.KCK
, RSN_KCK_LENGTH
);
23251 bcopy(data
->kek
, keyinfo
.KEK
, RSN_KEK_LENGTH
);
23252 bcopy(data
->replay_ctr
, keyinfo
.ReplayCounter
, RSN_REPLAY_LEN
);
23254 memset(&bcol_keyinfo
, 0, sizeof(bcol_keyinfo
));
23255 bcol_keyinfo
.enable
= 1;
23256 bcol_keyinfo
.ptk_len
= 64;
23257 memcpy(&bcol_keyinfo
.ptk
[0], data
->kck
, RSN_KCK_LENGTH
);
23258 memcpy(&bcol_keyinfo
.ptk
[RSN_KCK_LENGTH
], data
->kek
, RSN_KEK_LENGTH
);
23259 err
= wldev_iovar_setbuf(dev
, "bcol_gtk_rekey_ptk", &bcol_keyinfo
,
23260 sizeof(bcol_keyinfo
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
23265 if ((err
= wldev_iovar_setbuf(dev
, "gtk_key_info", &keyinfo
, sizeof(keyinfo
),
23266 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
)) < 0) {
23267 WL_ERR(("seting gtk_key_info failed code=%d\n", err
));
23271 WL_DBG(("Exit\n"));
23274 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
23275 #endif /* GTK_OFFLOAD_SUPPORT */
23277 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
23278 static int wl_cfg80211_set_pmk(struct wiphy
*wiphy
, struct net_device
*dev
,
23279 const struct cfg80211_pmk_conf
*conf
)
23283 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
23284 struct wl_security
*sec
;
23287 pmk
.key_len
= conf
->pmk_len
;
23288 if (pmk
.key_len
> sizeof(pmk
.key
)) {
23293 ret
= memcpy_s(&pmk
.key
, sizeof(pmk
.key
), conf
->pmk
, conf
->pmk_len
);
23299 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
23300 WL_ERR(("Find index failed\n"));
23305 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
23306 if ((sec
->wpa_auth
== WLAN_AKM_SUITE_8021X
) ||
23307 (sec
->wpa_auth
== WL_AKM_SUITE_SHA256_1X
)) {
23308 ret
= wldev_iovar_setbuf_bsscfg(dev
, "okc_info_pmk", pmk
.key
, pmk
.key_len
,
23309 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
23311 /* could fail in case that 'okc' is not supported */
23312 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret
));
23316 ret
= wldev_ioctl_set(dev
, WLC_SET_WSEC_PMK
, &pmk
, sizeof(pmk
));
23318 WL_ERR(("wl_cfg80211_set_pmk error:%d", ret
));
23322 WL_DBG(("pmk added for mac:"MACDBG
"\n", MAC2STRDBG(conf
->aa
)));
23327 static int wl_cfg80211_del_pmk(struct wiphy
*wiphy
, struct net_device
*dev
,
23331 struct cfg80211_pmksa pmksa
;
23333 /* build up cfg80211_pmksa structure to use existing wl_cfg80211_update_pmksa API */
23334 bzero(&pmksa
, sizeof(pmksa
));
23337 err
= wl_cfg80211_update_pmksa(wiphy
, dev
, &pmksa
, FALSE
);
23338 if (unlikely(err
)) {
23339 WL_ERR(("wl_cfg80211_update_pmksa err:%d\n", err
));
23342 WL_DBG(("pmk deleted for bssid:"MACDBG
"\n", MAC2STRDBG(aa
)));
23347 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
23350 wl_cfg80211_get_sta_channel(struct bcm_cfg80211
*cfg
)
23352 chanspec_t
*sta_chanspec
= NULL
;
23355 if (wl_get_drv_status(cfg
, CONNECTED
, bcmcfg_to_prmry_ndev(cfg
))) {
23356 if ((sta_chanspec
= (chanspec_t
*)wl_read_prof(cfg
,
23357 bcmcfg_to_prmry_ndev(cfg
), WL_PROF_CHAN
))) {
23358 channel
= CHSPEC_CHANNEL(*sta_chanspec
);
23365 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211
*cfg
)
23368 id
= ++cfg
->last_roc_id
;
23369 #ifdef P2P_LISTEN_OFFLOADING
23370 if (id
== P2PO_COOKIE
) {
23371 id
= ++cfg
->last_roc_id
;
23373 #endif /* P2P_LISTEN_OFFLOADING */
23375 id
= ++cfg
->last_roc_id
;
23381 wl_cfg80211_tdls_config(struct bcm_cfg80211
*cfg
, enum wl_tdls_config state
, bool auto_mode
)
23383 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
23385 struct net_info
*iter
, *next
;
23386 int update_reqd
= 0;
23389 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23392 * TDLS need to be enabled only if we have a single STA/GC
23396 WL_DBG(("Enter state:%d\n", state
));
23397 if (!cfg
->tdls_supported
) {
23398 /* FW doesn't support tdls. Do nothing */
23402 /* Protect tdls config session */
23403 mutex_lock(&cfg
->tdls_sync
);
23405 if (state
== TDLS_STATE_TEARDOWN
) {
23406 /* Host initiated TDLS tear down */
23407 err
= dhd_tdls_enable(ndev
, false, auto_mode
, NULL
);
23409 } else if ((state
== TDLS_STATE_AP_CREATE
) ||
23410 (state
== TDLS_STATE_NMI_CREATE
)) {
23411 /* We don't support tdls while AP/GO/NAN is operational */
23412 update_reqd
= true;
23414 } else if ((state
== TDLS_STATE_CONNECT
) || (state
== TDLS_STATE_IF_CREATE
)) {
23415 if (wl_get_drv_status_all(cfg
,
23416 CONNECTED
) >= TDLS_MAX_IFACE_FOR_ENABLE
) {
23417 /* For STA/GC connect command request, disable
23418 * tdls if we have any concurrent interfaces
23421 WL_DBG(("Interface limit restriction. disable tdls.\n"));
23422 update_reqd
= true;
23425 } else if ((state
== TDLS_STATE_DISCONNECT
) ||
23426 (state
== TDLS_STATE_AP_DELETE
) ||
23427 (state
== TDLS_STATE_SETUP
) ||
23428 (state
== TDLS_STATE_IF_DELETE
)) {
23429 /* Enable back the tdls connection only if we have less than
23430 * or equal to a single STA/GC connection.
23432 if (wl_get_drv_status_all(cfg
,
23434 /* If there are no interfaces connected, enable tdls */
23435 update_reqd
= true;
23437 } else if (wl_get_drv_status_all(cfg
,
23438 CONNECTED
) == TDLS_MAX_IFACE_FOR_ENABLE
) {
23439 /* We have one interface in CONNECTED state.
23440 * Verify whether its a STA interface before
23441 * we enable back tdls.
23443 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23444 for_each_ndev(cfg
, iter
, next
) {
23445 GCC_DIAGNOSTIC_POP();
23446 if ((iter
->ndev
) && (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) &&
23447 (ndev
->ieee80211_ptr
->iftype
!= NL80211_IFTYPE_STATION
)) {
23448 WL_DBG(("Non STA iface operational. cfg_iftype:%d"
23449 " Can't enable tdls.\n",
23450 ndev
->ieee80211_ptr
->iftype
));
23455 /* No AP/GO found. Enable back tdls */
23456 update_reqd
= true;
23459 WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
23464 WL_ERR(("Unknown tdls state:%d \n", state
));
23469 if (update_reqd
== true) {
23470 if (dhdp
->tdls_enable
== enable
) {
23471 WL_DBG(("No change in tdls state. Do nothing."
23472 " tdls_enable:%d\n", enable
));
23475 err
= wldev_iovar_setint(ndev
, "tdls_enable", enable
);
23476 if (unlikely(err
)) {
23477 WL_ERR(("tdls_enable setting failed. err:%d\n", err
));
23480 WL_INFORM_MEM(("tdls_enable %d state:%d\n", enable
, state
));
23481 /* Update the dhd state variable to be in sync */
23482 dhdp
->tdls_enable
= enable
;
23483 if (state
== TDLS_STATE_SETUP
) {
23484 /* For host initiated setup, apply TDLS params
23485 * Don't propagate errors up for param config
23488 dhd_tdls_enable(ndev
, true, auto_mode
, NULL
);
23493 WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
23494 "current_status:%d \n",
23495 state
, update_reqd
, dhdp
->tdls_enable
));
23500 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
23502 mutex_unlock(&cfg
->tdls_sync
);
23505 #endif /* WLTDLS */
23507 struct net_device
* wl_get_ap_netdev(struct bcm_cfg80211
*cfg
, char *ifname
)
23509 struct net_info
*iter
, *next
;
23510 struct net_device
*ndev
= NULL
;
23512 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23513 for_each_ndev(cfg
, iter
, next
) {
23514 GCC_DIAGNOSTIC_POP();
23516 if (strncmp(iter
->ndev
->name
, ifname
, IFNAMSIZ
) == 0) {
23517 if (iter
->ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
23529 wl_get_netdev_by_name(struct bcm_cfg80211
*cfg
, char *ifname
)
23531 struct net_info
*iter
, *next
;
23532 struct net_device
*ndev
= NULL
;
23534 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23535 for_each_ndev(cfg
, iter
, next
) {
23536 GCC_DIAGNOSTIC_POP();
23538 if (strncmp(iter
->ndev
->name
, ifname
, IFNAMSIZ
) == 0) {
23548 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
23549 #define WLC_RATE_FLAG 0x80
23550 #define RATE_MASK 0x7f
23552 int wl_set_ap_beacon_rate(struct net_device
*dev
, int val
, char *ifname
)
23554 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23556 wl_rateset_args_t rs
;
23557 int error
= BCME_ERROR
, i
;
23558 struct net_device
*ndev
= NULL
;
23560 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23562 if (dhdp
&& !(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23563 WL_ERR(("Not Hostapd mode\n"));
23567 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23569 if (ndev
== NULL
) {
23570 WL_ERR(("No softAP interface named %s\n", ifname
));
23574 bzero(&rs
, sizeof(wl_rateset_args_t
));
23575 error
= wldev_iovar_getbuf(ndev
, "rateset", NULL
, 0,
23576 &rs
, sizeof(wl_rateset_args_t
), NULL
);
23578 WL_ERR(("get rateset failed = %d\n", error
));
23582 if (rs
.count
< 1) {
23583 WL_ERR(("Failed to get rate count\n"));
23587 /* Host delivers target rate in the unit of 500kbps */
23588 /* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic rate */
23589 for (i
= 0; i
< rs
.count
&& i
< WL_NUMRATES
; i
++)
23590 if (rs
.rates
[i
] & WLC_RATE_FLAG
)
23591 if ((rs
.rates
[i
] & RATE_MASK
) == val
)
23594 /* Valid rate has been delivered as an argument */
23595 if (i
< rs
.count
&& i
< WL_NUMRATES
) {
23596 error
= wldev_iovar_setint(ndev
, "force_bcn_rspec", val
);
23598 WL_ERR(("set beacon rate failed = %d\n", error
));
23602 WL_ERR(("Rate is invalid"));
23603 return BCME_BADARG
;
23610 wl_get_ap_basic_rate(struct net_device
*dev
, char* command
, char *ifname
, int total_len
)
23612 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23614 wl_rateset_args_t rs
;
23615 int error
= BCME_ERROR
;
23616 int i
, bytes_written
= 0;
23617 struct net_device
*ndev
= NULL
;
23619 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23621 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23622 WL_ERR(("Not Hostapd mode\n"));
23626 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23628 if (ndev
== NULL
) {
23629 WL_ERR(("No softAP interface named %s\n", ifname
));
23633 bzero(&rs
, sizeof(wl_rateset_args_t
));
23634 error
= wldev_iovar_getbuf(ndev
, "rateset", NULL
, 0,
23635 &rs
, sizeof(wl_rateset_args_t
), NULL
);
23637 WL_ERR(("get rateset failed = %d\n", error
));
23641 if (rs
.count
< 1) {
23642 WL_ERR(("Failed to get rate count\n"));
23646 /* Delivers basic rate in the unit of 500kbps to host */
23647 for (i
= 0; i
< rs
.count
&& i
< WL_NUMRATES
; i
++)
23648 if (rs
.rates
[i
] & WLC_RATE_FLAG
)
23649 bytes_written
+= snprintf(command
+ bytes_written
, total_len
,
23650 "%d ", rs
.rates
[i
] & RATE_MASK
);
23652 /* Remove last space in the command buffer */
23653 if (bytes_written
&& (bytes_written
< total_len
)) {
23654 command
[bytes_written
- 1] = '\0';
23658 return bytes_written
;
23661 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
23663 #ifdef SUPPORT_AP_RADIO_PWRSAVE
23664 #define MSEC_PER_MIN (60000L)
23667 _wl_update_ap_rps_params(struct net_device
*dev
)
23669 struct bcm_cfg80211
*cfg
= NULL
;
23670 rpsnoa_iovar_params_t iovar
;
23671 u8 smbuf
[WLC_IOCTL_SMLEN
];
23674 return BCME_BADARG
;
23676 cfg
= wl_get_cfg(dev
);
23678 bzero(&iovar
, sizeof(iovar
));
23679 bzero(smbuf
, sizeof(smbuf
));
23681 iovar
.hdr
.ver
= RADIO_PWRSAVE_VERSION
;
23682 iovar
.hdr
.subcmd
= WL_RPSNOA_CMD_PARAMS
;
23683 iovar
.hdr
.len
= sizeof(iovar
);
23684 iovar
.param
->band
= WLC_BAND_ALL
;
23685 iovar
.param
->level
= cfg
->ap_rps_info
.level
;
23686 iovar
.param
->stas_assoc_check
= cfg
->ap_rps_info
.sta_assoc_check
;
23687 iovar
.param
->pps
= cfg
->ap_rps_info
.pps
;
23688 iovar
.param
->quiet_time
= cfg
->ap_rps_info
.quiet_time
;
23690 if (wldev_iovar_setbuf(dev
, "rpsnoa", &iovar
, sizeof(iovar
),
23691 smbuf
, sizeof(smbuf
), NULL
)) {
23692 WL_ERR(("Failed to set rpsnoa params"));
23700 wl_get_ap_rps(struct net_device
*dev
, char* command
, char *ifname
, int total_len
)
23702 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23704 int error
= BCME_ERROR
;
23705 int bytes_written
= 0;
23706 struct net_device
*ndev
= NULL
;
23707 rpsnoa_iovar_status_t iovar
;
23708 u8 smbuf
[WLC_IOCTL_SMLEN
];
23713 u32 time_since_enable
;
23715 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23718 error
= BCME_NOTUP
;
23722 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23723 WL_ERR(("Not Hostapd mode\n"));
23724 error
= BCME_NOTAP
;
23728 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23730 if (ndev
== NULL
) {
23731 WL_ERR(("No softAP interface named %s\n", ifname
));
23732 error
= BCME_NOTAP
;
23736 bzero(&iovar
, sizeof(iovar
));
23737 bzero(smbuf
, sizeof(smbuf
));
23739 iovar
.hdr
.ver
= RADIO_PWRSAVE_VERSION
;
23740 iovar
.hdr
.subcmd
= WL_RPSNOA_CMD_STATUS
;
23741 iovar
.hdr
.len
= sizeof(iovar
);
23742 iovar
.stats
->band
= WLC_BAND_ALL
;
23744 error
= wldev_iovar_getbuf(ndev
, "rpsnoa", &iovar
, sizeof(iovar
),
23745 smbuf
, sizeof(smbuf
), NULL
);
23747 WL_ERR(("get ap radio pwrsave failed = %d\n", error
));
23751 /* RSDB event doesn't seem to be handled correctly.
23752 * So check chanspec of AP directly from the firmware
23754 error
= wldev_iovar_getint(ndev
, "chanspec", (s32
*)&chanspec
);
23756 WL_ERR(("get chanspec from AP failed = %d\n", error
));
23760 chanspec
= wl_chspec_driver_to_host(chanspec
);
23761 if (CHSPEC_IS2G(chanspec
))
23765 CHSPEC_IS6G(chanspec
) ||
23766 #endif /* WL_6G_BAND */
23767 CHSPEC_IS5G(chanspec
))
23770 error
= BCME_BADCHAN
;
23774 state
= ((rpsnoa_iovar_status_t
*)smbuf
)->stats
[idx
].state
;
23775 sleep
= ((rpsnoa_iovar_status_t
*)smbuf
)->stats
[idx
].sleep_dur
;
23776 time_since_enable
= ((rpsnoa_iovar_status_t
*)smbuf
)->stats
[idx
].sleep_avail_dur
;
23778 /* Conver ms to minute, round down only */
23779 sleep
= DIV_U64_BY_U32(sleep
, MSEC_PER_MIN
);
23780 time_since_enable
= DIV_U64_BY_U32(time_since_enable
, MSEC_PER_MIN
);
23782 bytes_written
+= snprintf(command
+ bytes_written
, total_len
,
23783 "state=%d sleep=%d time_since_enable=%d", state
, sleep
, time_since_enable
);
23784 error
= bytes_written
;
23791 wl_set_ap_rps(struct net_device
*dev
, bool enable
, char *ifname
)
23793 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23795 struct net_device
*ndev
= NULL
;
23796 rpsnoa_iovar_t iovar
;
23797 u8 smbuf
[WLC_IOCTL_SMLEN
];
23800 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23807 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23808 WL_ERR(("Not Hostapd mode\n"));
23813 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23815 if (ndev
== NULL
) {
23816 WL_ERR(("No softAP interface named %s\n", ifname
));
23821 if (cfg
->ap_rps_info
.enable
!= enable
) {
23822 cfg
->ap_rps_info
.enable
= enable
;
23824 ret
= _wl_update_ap_rps_params(ndev
);
23826 WL_ERR(("Filed to update rpsnoa params\n"));
23830 bzero(&iovar
, sizeof(iovar
));
23831 bzero(smbuf
, sizeof(smbuf
));
23833 iovar
.hdr
.ver
= RADIO_PWRSAVE_VERSION
;
23834 iovar
.hdr
.subcmd
= WL_RPSNOA_CMD_ENABLE
;
23835 iovar
.hdr
.len
= sizeof(iovar
);
23836 iovar
.data
->band
= WLC_BAND_ALL
;
23837 iovar
.data
->value
= (int16
)enable
;
23839 ret
= wldev_iovar_setbuf(ndev
, "rpsnoa", &iovar
, sizeof(iovar
),
23840 smbuf
, sizeof(smbuf
), NULL
);
23842 WL_ERR(("Failed to enable AP radio power save"));
23845 cfg
->ap_rps_info
.enable
= enable
;
23852 wl_update_ap_rps_params(struct net_device
*dev
, ap_rps_info_t
* rps
, char *ifname
)
23854 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23856 struct net_device
*ndev
= NULL
;
23858 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23863 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23864 WL_ERR(("Not Hostapd mode\n"));
23868 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23870 if (ndev
== NULL
) {
23871 WL_ERR(("No softAP interface named %s\n", ifname
));
23876 return BCME_BADARG
;
23878 if (rps
->pps
< RADIO_PWRSAVE_PPS_MIN
)
23879 return BCME_BADARG
;
23881 if (rps
->level
< RADIO_PWRSAVE_LEVEL_MIN
||
23882 rps
->level
> RADIO_PWRSAVE_LEVEL_MAX
)
23883 return BCME_BADARG
;
23885 if (rps
->quiet_time
< RADIO_PWRSAVE_QUIETTIME_MIN
)
23886 return BCME_BADARG
;
23888 if (rps
->sta_assoc_check
> RADIO_PWRSAVE_ASSOCCHECK_MAX
||
23889 rps
->sta_assoc_check
< RADIO_PWRSAVE_ASSOCCHECK_MIN
)
23890 return BCME_BADARG
;
23892 cfg
->ap_rps_info
.pps
= rps
->pps
;
23893 cfg
->ap_rps_info
.level
= rps
->level
;
23894 cfg
->ap_rps_info
.quiet_time
= rps
->quiet_time
;
23895 cfg
->ap_rps_info
.sta_assoc_check
= rps
->sta_assoc_check
;
23897 if (cfg
->ap_rps_info
.enable
) {
23898 if (_wl_update_ap_rps_params(ndev
)) {
23899 WL_ERR(("Failed to update rpsnoa params"));
23908 wl_cfg80211_init_ap_rps(struct bcm_cfg80211
*cfg
)
23910 cfg
->ap_rps_info
.enable
= FALSE
;
23911 cfg
->ap_rps_info
.sta_assoc_check
= RADIO_PWRSAVE_STAS_ASSOC_CHECK
;
23912 cfg
->ap_rps_info
.pps
= RADIO_PWRSAVE_PPS
;
23913 cfg
->ap_rps_info
.quiet_time
= RADIO_PWRSAVE_QUIET_TIME
;
23914 cfg
->ap_rps_info
.level
= RADIO_PWRSAVE_LEVEL
;
23916 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
23919 wl_cfg80211_iface_count(struct net_device
*dev
)
23921 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23922 struct net_info
*iter
, *next
;
23923 int iface_count
= 0;
23925 /* Return the count of network interfaces (skip netless p2p discovery
23928 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23929 for_each_ndev(cfg
, iter
, next
) {
23930 GCC_DIAGNOSTIC_POP();
23935 return iface_count
;
23939 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211
*cfg
, struct ether_addr
*ea
)
23941 wl_wbtext_bssid_t
*bssid
= NULL
;
23942 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23943 /* check duplicate */
23944 list_for_each_entry(bssid
, &cfg
->wbtext_bssid_list
, list
) {
23945 GCC_DIAGNOSTIC_POP();
23946 if (!memcmp(bssid
->ea
.octet
, ea
, ETHER_ADDR_LEN
)) {
23954 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211
*cfg
, struct ether_addr
*ea
)
23956 wl_wbtext_bssid_t
*bssid
= NULL
;
23957 char eabuf
[ETHER_ADDR_STR_LEN
];
23959 bssid
= (wl_wbtext_bssid_t
*)MALLOC(cfg
->osh
, sizeof(wl_wbtext_bssid_t
));
23960 if (bssid
== NULL
) {
23961 WL_ERR(("alloc failed\n"));
23965 memcpy(bssid
->ea
.octet
, ea
, ETHER_ADDR_LEN
);
23967 INIT_LIST_HEAD(&bssid
->list
);
23968 list_add_tail(&bssid
->list
, &cfg
->wbtext_bssid_list
);
23970 WL_DBG(("add wbtext bssid : %s\n", bcm_ether_ntoa(ea
, eabuf
)));
23975 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211
*cfg
)
23977 wl_wbtext_bssid_t
*bssid
= NULL
;
23978 char eabuf
[ETHER_ADDR_STR_LEN
];
23980 while (!list_empty(&cfg
->wbtext_bssid_list
)) {
23981 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23982 bssid
= list_entry(cfg
->wbtext_bssid_list
.next
, wl_wbtext_bssid_t
, list
);
23983 GCC_DIAGNOSTIC_POP();
23985 WL_DBG(("clear wbtext bssid : %s\n", bcm_ether_ntoa(&bssid
->ea
, eabuf
)));
23986 list_del(&bssid
->list
);
23987 MFREE(cfg
->osh
, bssid
, sizeof(wl_wbtext_bssid_t
));
23992 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
23994 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
23995 bcm_tlv_t
* cap_ie
= NULL
;
23996 bool req_sent
= FALSE
;
23997 struct wl_profile
*profile
;
23999 WL_DBG(("Enter\n"));
24001 profile
= wl_get_profile_by_netdev(cfg
, dev
);
24003 WL_ERR(("no profile exists\n"));
24007 if (wl_cfg80211_wbtext_check_bssid_list(cfg
,
24008 (struct ether_addr
*)&profile
->bssid
) == FALSE
) {
24009 WL_DBG(("already updated\n"));
24013 /* first, check NBR bit in RRM IE */
24014 if ((cap_ie
= bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
24015 DOT11_MNG_RRM_CAP_ID
)) != NULL
) {
24016 if (isset(cap_ie
->data
, DOT11_RRM_CAP_NEIGHBOR_REPORT
)) {
24017 WL_DBG(("sending neighbor report\n"));
24018 req_sent
= wl_cfg80211_wbtext_send_nbr_req(cfg
, dev
, profile
);
24022 /* if RRM nbr was not supported, check BTM bit in extend cap. IE */
24024 if ((cap_ie
= bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
24025 DOT11_MNG_EXT_CAP_ID
)) != NULL
) {
24026 if (cap_ie
->len
>= DOT11_EXTCAP_LEN_BSSTRANS
&&
24027 isset(cap_ie
->data
, DOT11_EXT_CAP_BSSTRANS_MGMT
)) {
24028 WL_DBG(("sending btm query\n"));
24029 wl_cfg80211_wbtext_send_btm_query(cfg
, dev
, profile
);
24035 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
24036 struct wl_profile
*profile
)
24039 char *smbuf
= NULL
;
24040 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
24041 bcm_tlv_t
* rrm_cap_ie
= NULL
;
24042 wlc_ssid_t
*ssid
= NULL
;
24045 WL_DBG(("Enter\n"));
24047 /* check RRM nbr bit in extend cap. IE of assoc response */
24048 if ((rrm_cap_ie
= bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
24049 DOT11_MNG_RRM_CAP_ID
)) != NULL
) {
24050 if (!isset(rrm_cap_ie
->data
, DOT11_RRM_CAP_NEIGHBOR_REPORT
)) {
24051 WL_DBG(("AP doesn't support neighbor report\n"));
24056 smbuf
= (char *)MALLOCZ(cfg
->osh
, WLC_IOCTL_MAXLEN
);
24057 if (smbuf
== NULL
) {
24058 WL_ERR(("failed to allocated memory\n"));
24062 ssid
= (wlc_ssid_t
*)MALLOCZ(cfg
->osh
, sizeof(wlc_ssid_t
));
24063 if (ssid
== NULL
) {
24064 WL_ERR(("failed to allocated memory\n"));
24068 ssid
->SSID_len
= MIN(profile
->ssid
.SSID_len
, DOT11_MAX_SSID_LEN
);
24069 memcpy(ssid
->SSID
, profile
->ssid
.SSID
, ssid
->SSID_len
);
24071 error
= wldev_iovar_setbuf(dev
, "rrm_nbr_req", ssid
,
24072 sizeof(wlc_ssid_t
), smbuf
, WLC_IOCTL_MAXLEN
, NULL
);
24073 if (error
== BCME_OK
) {
24074 ret
= wl_cfg80211_wbtext_add_bssid_list(cfg
,
24075 (struct ether_addr
*)&profile
->bssid
);
24077 WL_ERR(("failed to send neighbor report request, error=%d\n", error
));
24082 MFREE(cfg
->osh
, ssid
, sizeof(wlc_ssid_t
));
24086 MFREE(cfg
->osh
, smbuf
, WLC_IOCTL_MAXLEN
);
24091 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
24092 struct wl_profile
*profile
)
24097 wl_bsstrans_query_t btq
;
24099 WL_DBG(("Enter\n"));
24101 bzero(&btq
, sizeof(wl_bsstrans_query_t
));
24103 btq
.version
= WL_BSSTRANS_QUERY_VERSION_1
;
24104 error
= wldev_iovar_setbuf(dev
, "wnm_bsstrans_query", &btq
,
24105 sizeof(btq
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
24106 if (error
== BCME_OK
) {
24107 ret
= wl_cfg80211_wbtext_add_bssid_list(cfg
,
24108 (struct ether_addr
*)&profile
->bssid
);
24110 WL_ERR(("wl_cfg80211_wbtext_send_btm_query: failed to set BTM query,"
24111 " error=%d\n", error
));
24116 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
24118 keepalives_max_idle_t keepalive
= {0, 0, 0, 0};
24120 int wnm_maxidle
= 0;
24121 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
24123 /* AP supports wnm max idle ? */
24124 if (bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
24125 DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID
) != NULL
) {
24126 error
= wldev_iovar_getint(dev
, "wnm_maxidle", &wnm_maxidle
);
24128 WL_ERR(("failed to get wnm max idle period : %d\n", error
));
24132 WL_DBG(("wnm max idle period : %d\n", wnm_maxidle
));
24134 /* if wnm maxidle has valid period, set it as keep alive */
24135 if (wnm_maxidle
> 0) {
24136 keepalive
.keepalive_count
= 1;
24139 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) >= 0) {
24140 error
= wldev_iovar_setbuf_bsscfg(dev
, "wnm_keepalives_max_idle", &keepalive
,
24141 sizeof(keepalives_max_idle_t
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
,
24142 bssidx
, &cfg
->ioctl_buf_sync
);
24144 if (error
== BCME_BADARG
) {
24145 WL_ERR(("set wnm_keepalive with invalid arguments\n"));
24147 WL_ERR(("set wnm_keepalives_max_idle failed : %d\n", error
));
24154 wl_cfg80211_recv_nbr_resp(struct net_device
*dev
, uint8
*body
, uint body_len
)
24156 dot11_rm_action_t
*rm_rep
;
24160 dot11_neighbor_rep_ie_t
*nbr_rep_ie
;
24162 wl_roam_channel_list_t channel_list
;
24163 char iobuf
[WLC_IOCTL_SMLEN
];
24165 if (body_len
< DOT11_RM_ACTION_LEN
) {
24166 WL_ERR(("Received Neighbor Report frame with incorrect length %d\n",
24171 rm_rep
= (dot11_rm_action_t
*)body
;
24172 WL_DBG(("received neighbor report (token = %d)\n", rm_rep
->token
));
24174 tlvs
= (bcm_tlv_t
*)&rm_rep
->data
[0];
24176 tlv_len
= body_len
- DOT11_RM_ACTION_LEN
;
24178 while (tlvs
&& tlvs
->id
== DOT11_MNG_NEIGHBOR_REP_ID
) {
24179 nbr_rep_ie
= (dot11_neighbor_rep_ie_t
*)tlvs
;
24181 if (nbr_rep_ie
->len
< DOT11_NEIGHBOR_REP_IE_FIXED_LEN
) {
24182 WL_ERR(("malformed Neighbor Report element with length %d\n",
24184 tlvs
= bcm_next_tlv(tlvs
, &tlv_len
);
24188 ch
= CH20MHZ_CHSPEC(nbr_rep_ie
->channel
);
24189 WL_DBG(("ch:%d, bssid:"MACDBG
"\n",
24190 ch
, MAC2STRDBG(nbr_rep_ie
->bssid
.octet
)));
24193 error
= wldev_iovar_getbuf(dev
, "roamscan_channels", 0, 0,
24194 (void *)&channel_list
, sizeof(channel_list
), NULL
);
24196 WL_ERR(("Failed to get roamscan channels, error = %d\n", error
));
24201 if (channel_list
.n
< MAX_ROAM_CHANNEL
) {
24202 for (i
= 0; i
< channel_list
.n
; i
++) {
24203 if (channel_list
.channels
[i
] == ch
) {
24207 if (i
== channel_list
.n
) {
24208 channel_list
.channels
[channel_list
.n
] = ch
;
24214 error
= wldev_iovar_setbuf(dev
, "roamscan_channels", &channel_list
,
24215 sizeof(channel_list
), iobuf
, sizeof(iobuf
), NULL
);
24217 WL_DBG(("Failed to set roamscan channels, error = %d\n", error
));
24220 tlvs
= bcm_next_tlv(tlvs
, &tlv_len
);
24225 #endif /* WBTEXT */
24226 #ifdef SUPPORT_SET_CAC
24228 wl_cfg80211_set_cac(struct bcm_cfg80211
*cfg
, int enable
)
24231 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
24233 WL_DBG(("cac enable %d\n", enable
));
24235 WL_ERR(("dhd is NULL\n"));
24238 if ((ret
= dhd_wl_ioctl_set_intiovar(dhd
, "cac", enable
,
24239 WLC_SET_VAR
, TRUE
, 0)) < 0) {
24240 WL_ERR(("Failed set CAC, ret=%d\n", ret
));
24242 WL_DBG(("CAC set successfully\n"));
24246 #endif /* SUPPORT_SET_CAC */
24248 #ifdef SUPPORT_RSSI_SUM_REPORT
24250 wl_get_rssi_per_ant(struct net_device
*dev
, char *ifname
, char *peer_mac
, void *param
)
24252 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24253 wl_rssi_ant_mimo_t
*get_param
= (wl_rssi_ant_mimo_t
*)param
;
24254 rssi_ant_param_t
*set_param
= NULL
;
24255 struct net_device
*ifdev
= NULL
;
24256 char iobuf
[WLC_IOCTL_SMLEN
];
24260 bzero(iobuf
, WLC_IOCTL_SMLEN
);
24262 /* Check the interface type */
24263 ifdev
= wl_get_netdev_by_name(cfg
, ifname
);
24264 if (ifdev
== NULL
) {
24265 WL_ERR(("Could not find net_device for ifname:%s\n", ifname
));
24270 iftype
= ifdev
->ieee80211_ptr
->iftype
;
24271 if (iftype
== NL80211_IFTYPE_AP
|| iftype
== NL80211_IFTYPE_P2P_GO
) {
24273 set_param
= (rssi_ant_param_t
*)MALLOCZ(cfg
->osh
, sizeof(rssi_ant_param_t
));
24274 err
= wl_cfg80211_ether_atoe(peer_mac
, &set_param
->ea
);
24276 WL_ERR(("Invalid Peer MAC format\n"));
24281 WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype
));
24287 err
= wldev_iovar_getbuf(ifdev
, "phy_rssi_ant", peer_mac
?
24288 (void *)&(set_param
->ea
) : NULL
, peer_mac
? ETHER_ADDR_LEN
: 0,
24289 (void *)iobuf
, sizeof(iobuf
), NULL
);
24290 if (unlikely(err
)) {
24291 WL_ERR(("Failed to get rssi info, err=%d\n", err
));
24293 memcpy(get_param
, iobuf
, sizeof(wl_rssi_ant_mimo_t
));
24294 if (get_param
->count
== 0) {
24295 WL_ERR(("Not supported on this chip\n"));
24296 err
= BCME_UNSUPPORTED
;
24302 MFREE(cfg
->osh
, set_param
, sizeof(rssi_ant_param_t
));
24309 wl_get_rssi_logging(struct net_device
*dev
, void *param
)
24311 rssilog_get_param_t
*get_param
= (rssilog_get_param_t
*)param
;
24312 char iobuf
[WLC_IOCTL_SMLEN
];
24315 bzero(iobuf
, WLC_IOCTL_SMLEN
);
24316 bzero(get_param
, sizeof(*get_param
));
24317 err
= wldev_iovar_getbuf(dev
, "rssilog", NULL
, 0, (void *)iobuf
,
24318 sizeof(iobuf
), NULL
);
24320 WL_ERR(("Failed to get rssi logging info, err=%d\n", err
));
24322 memcpy(get_param
, iobuf
, sizeof(*get_param
));
24329 wl_set_rssi_logging(struct net_device
*dev
, void *param
)
24331 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24332 rssilog_set_param_t
*set_param
= (rssilog_set_param_t
*)param
;
24335 err
= wldev_iovar_setbuf(dev
, "rssilog", set_param
,
24336 sizeof(*set_param
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
,
24337 &cfg
->ioctl_buf_sync
);
24339 WL_ERR(("Failed to set rssi logging param, err=%d\n", err
));
24344 #endif /* SUPPORT_RSSI_SUM_REPORT */
24345 /* Function to flush the FW preserve buffer content
24346 * The buffer content is sent to host in form of events.
24349 wl_flush_fw_log_buffer(struct net_device
*dev
, uint32 logset_mask
)
24351 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24352 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
24355 u8 buf
[WLC_IOCTL_SMLEN
] = {0};
24356 wl_el_set_params_t set_param
;
24358 /* Set the size of data to retrieve */
24359 memset(&set_param
, 0, sizeof(set_param
));
24360 set_param
.size
= WLC_IOCTL_SMLEN
;
24362 for (i
= 0; i
< dhd
->event_log_max_sets
; i
++)
24364 if ((0x01u
<< i
) & logset_mask
) {
24366 err
= wldev_iovar_setbuf(dev
, "event_log_get", &set_param
,
24367 sizeof(struct wl_el_set_params_s
), buf
, WLC_IOCTL_SMLEN
,
24370 WL_DBG(("Failed to get fw preserve logs, err=%d\n", err
));
24375 #ifdef USE_WFA_CERT_CONF
24376 extern int g_frameburst
;
24377 #endif /* USE_WFA_CERT_CONF */
24380 wl_cfg80211_set_frameburst(struct bcm_cfg80211
*cfg
, bool enable
)
24383 int val
= enable
? 1 : 0;
24385 #ifdef USE_WFA_CERT_CONF
24386 if (!g_frameburst
) {
24387 WL_DBG(("Skip setting frameburst\n"));
24390 #endif /* USE_WFA_CERT_CONF */
24392 WL_DBG(("Set frameburst %d\n", val
));
24393 ret
= wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg
), WLC_SET_FAKEFRAG
, &val
, sizeof(val
));
24395 WL_ERR(("Failed set frameburst, ret=%d\n", ret
));
24397 WL_INFORM_MEM(("frameburst is %s\n", enable
? "enabled" : "disabled"));
24404 wl_cfg80211_set_dbg_verbose(struct net_device
*ndev
, u32 level
)
24406 /* configure verbose level for debugging */
24408 /* Enable increased verbose */
24409 wl_dbg_level
|= WL_DBG_DBG
;
24412 wl_dbg_level
&= ~WL_DBG_DBG
;
24414 WL_INFORM(("debug verbose set to %d\n", level
));
24420 wl_find_attribute(const u8
*buf
, u16 len
, u16 element_id
)
24427 WL_ERR(("buf null\n"));
24434 attrib_id
= *attrib
++ << 8;
24435 attrib_id
|= *attrib
++;
24438 /* 2-byte little endian */
24439 attrib_len
= *attrib
++ << 8;
24440 attrib_len
|= *attrib
++;
24443 if (attrib_id
== element_id
) {
24444 /* This will point to start of subelement attrib after
24445 * attribute id & len
24449 if (len
> attrib_len
) {
24450 len
-= attrib_len
; /* for the remaining subelt fields */
24451 WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n",
24452 attrib_id
, attrib_len
, len
));
24454 /* Go to next subelement */
24455 attrib
+= attrib_len
;
24457 WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n",
24458 attrib_id
, attrib_len
));
24465 uint8
wl_cfg80211_get_bus_state(struct bcm_cfg80211
*cfg
)
24467 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
24468 WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
24469 dhd
->hang_was_sent
, dhd
->busstate
));
24470 return ((dhd
->busstate
== DHD_BUS_DOWN
) || dhd
->hang_was_sent
);
24474 static void wl_wps_reauth_timeout(unsigned long data
)
24476 struct net_device
*ndev
= (struct net_device
*)data
;
24477 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24479 unsigned long flags
;
24481 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24482 inst
= wl_get_wps_inst_match(cfg
, ndev
);
24484 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n",
24485 ndev
->name
, inst
, cfg
->wps_session
[inst
].state
));
24486 if (cfg
->wps_session
[inst
].state
== WPS_STATE_REAUTH_WAIT
) {
24487 /* Session should get deleted from success (linkup) or
24488 * deauth case. Just in case, link reassoc failed, clear
24491 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n",
24492 ndev
->name
, inst
));
24493 cfg
->wps_session
[inst
].state
= WPS_STATE_IDLE
;
24494 cfg
->wps_session
[inst
].in_use
= false;
24497 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24500 static void wl_init_wps_reauth_sm(struct bcm_cfg80211
*cfg
)
24502 /* Only two instances are supported as of now. one for
24503 * infra STA and other for infra STA/GC.
24506 struct net_device
*pdev
= bcmcfg_to_prmry_ndev(cfg
);
24508 spin_lock_init(&cfg
->wps_sync
);
24509 for (i
= 0; i
< WPS_MAX_SESSIONS
; i
++) {
24510 /* Init scan_timeout timer */
24511 init_timer_compat(&cfg
->wps_session
[i
].timer
, wl_wps_reauth_timeout
, pdev
);
24512 cfg
->wps_session
[i
].in_use
= false;
24513 cfg
->wps_session
[i
].state
= WPS_STATE_IDLE
;
24517 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211
*cfg
)
24521 for (i
= 0; i
< WPS_MAX_SESSIONS
; i
++) {
24522 cfg
->wps_session
[i
].in_use
= false;
24523 cfg
->wps_session
[i
].state
= WPS_STATE_IDLE
;
24524 if (timer_pending(&cfg
->wps_session
[i
].timer
)) {
24525 del_timer_sync(&cfg
->wps_session
[i
].timer
);
24532 wl_get_free_wps_inst(struct bcm_cfg80211
*cfg
)
24536 for (i
= 0; i
< WPS_MAX_SESSIONS
; i
++) {
24537 if (!cfg
->wps_session
[i
].in_use
) {
24545 wl_get_wps_inst_match(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
24549 for (i
= 0; i
< WPS_MAX_SESSIONS
; i
++) {
24550 if ((cfg
->wps_session
[i
].in_use
) &&
24551 (ndev
== cfg
->wps_session
[i
].ndev
)) {
24560 wl_wps_session_add(struct net_device
*ndev
, u16 mode
, u8
*mac_addr
)
24563 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24564 unsigned long flags
;
24566 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24567 /* Fetch and initialize a wps instance */
24568 inst
= wl_get_free_wps_inst(cfg
);
24569 if (inst
== BCME_ERROR
) {
24570 WL_ERR(("[WPS] No free insance\n"));
24571 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24574 cfg
->wps_session
[inst
].in_use
= true;
24575 cfg
->wps_session
[inst
].state
= WPS_STATE_STARTED
;
24576 cfg
->wps_session
[inst
].ndev
= ndev
;
24577 cfg
->wps_session
[inst
].mode
= mode
;
24578 /* return check not required since both buffer lens are same */
24579 (void)memcpy_s(cfg
->wps_session
[inst
].peer_mac
, ETH_ALEN
, mac_addr
, ETH_ALEN
);
24580 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24582 WL_INFORM_MEM(("[%s][WPS] session created. Peer: " MACDBG
"\n",
24583 ndev
->name
, MAC2STRDBG(mac_addr
)));
24588 wl_wps_session_del(struct net_device
*ndev
)
24591 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24592 unsigned long flags
;
24595 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24597 /* Get current instance for the given ndev */
24598 inst
= wl_get_wps_inst_match(cfg
, ndev
);
24599 if (inst
== BCME_ERROR
) {
24600 WL_DBG(("[WPS] instance match NOT found\n"));
24601 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24605 cur_state
= cfg
->wps_session
[inst
].state
;
24606 if (cur_state
!= WPS_STATE_DONE
) {
24607 WL_DBG(("[WPS] wrong state:%d\n", cur_state
));
24608 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24612 /* Mark this as unused */
24613 cfg
->wps_session
[inst
].in_use
= false;
24614 cfg
->wps_session
[inst
].state
= WPS_STATE_IDLE
;
24615 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24617 /* Ensure this API is called from sleepable context. */
24618 if (timer_pending(&cfg
->wps_session
[inst
].timer
)) {
24619 del_timer_sync(&cfg
->wps_session
[inst
].timer
);
24622 WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev
->name
));
24626 wl_wps_handle_ifdel(struct net_device
*ndev
)
24628 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24629 unsigned long flags
;
24633 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24634 inst
= wl_get_wps_inst_match(cfg
, ndev
);
24635 if (inst
== BCME_ERROR
) {
24636 WL_DBG(("[WPS] instance match NOT found\n"));
24637 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24640 cur_state
= cfg
->wps_session
[inst
].state
;
24641 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
24642 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24644 WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev
->name
, cur_state
));
24645 if (cur_state
> WPS_STATE_IDLE
) {
24646 wl_wps_session_del(ndev
);
24651 wl_wps_handle_sta_linkdown(struct net_device
*ndev
, u16 inst
)
24653 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24654 unsigned long flags
;
24656 bool wps_done
= false;
24658 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24659 cur_state
= cfg
->wps_session
[inst
].state
;
24660 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
24661 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24662 wl_clr_drv_status(cfg
, CONNECTED
, ndev
);
24663 wl_clr_drv_status(cfg
, DISCONNECTING
, ndev
);
24664 WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev
->name
));
24665 /* Drop the link down event while we are waiting for reauth */
24666 return BCME_UNSUPPORTED
;
24667 } else if (cur_state
== WPS_STATE_STARTED
) {
24668 /* Link down before reaching EAP-FAIL. End WPS session */
24669 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
24671 WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev
->name
));
24673 WL_DBG(("[%s][WPS] link down in state:%d\n",
24674 ndev
->name
, cur_state
));
24677 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24680 wl_wps_session_del(ndev
);
24686 wl_wps_handle_peersta_linkdown(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
24688 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24689 unsigned long flags
;
24692 bool wps_done
= false;
24694 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24695 cur_state
= cfg
->wps_session
[inst
].state
;
24698 WL_ERR(("Invalid arg\n"));
24703 /* AP/GO can have multiple clients. so validate peer_mac addr
24704 * and ensure states are updated only for right peer.
24706 if (memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
24707 /* Mac addr not matching. Ignore. */
24708 WL_DBG(("[%s][WPS] No active WPS session"
24709 "for the peer:" MACDBG
"\n", ndev
->name
, MAC2STRDBG(peer_mac
)));
24713 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
24714 WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
24715 " Peer: " MACDBG
"\n",
24716 ndev
->name
, MAC2STRDBG(peer_mac
)));
24718 /* Link down during REAUTH state is expected. However,
24719 * if this is send up, hostapd statemachine issues a
24720 * deauth down and that may pre-empt WPS reauth state
24723 WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore."
24724 " for client:" MACDBG
"\n",
24725 ndev
->name
, MAC2STRDBG(peer_mac
)));
24726 ret
= BCME_UNSUPPORTED
;
24728 } else if (cur_state
== WPS_STATE_STARTED
) {
24729 /* Link down before reaching REAUTH_WAIT state. WPS
24732 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
24733 WL_INFORM_MEM(("[%s][WPS] link down after wps start"
24734 " client:" MACDBG
"\n",
24735 ndev
->name
, MAC2STRDBG(peer_mac
)));
24737 /* since we have freed lock above, return from here */
24740 WL_ERR(("[%s][WPS] Unsupported state:%d",
24741 ndev
->name
, cur_state
));
24745 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24747 wl_wps_session_del(ndev
);
24753 wl_wps_handle_sta_linkup(struct net_device
*ndev
, u16 inst
)
24755 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24756 unsigned long flags
;
24759 bool wps_done
= false;
24761 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24762 cur_state
= cfg
->wps_session
[inst
].state
;
24763 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
24764 /* WPS session succeeded. del session. */
24765 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
24767 WL_INFORM_MEM(("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev
->name
));
24770 WL_ERR(("[%s][WPS] unexpected link up in state:%d \n",
24771 ndev
->name
, cur_state
));
24774 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24776 wl_wps_session_del(ndev
);
24782 wl_wps_handle_peersta_linkup(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
24784 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24785 unsigned long flags
;
24789 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24790 cur_state
= cfg
->wps_session
[inst
].state
;
24792 /* For AP case, check whether call came for right peer */
24794 memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
24795 WL_ERR(("[WPS] macaddr mismatch\n"));
24796 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24797 /* Mac addr not matching. Ignore. */
24801 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
24802 WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev
->name
));
24805 WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
24806 ndev
->name
, cur_state
));
24810 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24816 wl_wps_handle_authorize(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
24818 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24819 unsigned long flags
;
24821 bool wps_done
= false;
24824 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24825 cur_state
= cfg
->wps_session
[inst
].state
;
24827 /* For AP case, check whether call came for right peer */
24829 memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
24830 WL_ERR(("[WPS] macaddr mismatch\n"));
24831 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24832 /* Mac addr not matching. Ignore. */
24836 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
24837 /* WPS session succeeded. del session. */
24838 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
24840 WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev
->name
));
24843 WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
24844 ndev
->name
, cur_state
));
24848 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24850 wl_wps_session_del(ndev
);
24856 wl_wps_handle_reauth(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
24858 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24859 unsigned long flags
;
24864 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24865 cur_state
= cfg
->wps_session
[inst
].state
;
24866 mode
= cfg
->wps_session
[inst
].mode
;
24868 if (((mode
== WL_MODE_BSS
) && (cur_state
== WPS_STATE_STARTED
)) ||
24869 ((mode
== WL_MODE_AP
) && (cur_state
== WPS_STATE_M8_SENT
))) {
24870 /* Move to reauth wait */
24871 cfg
->wps_session
[inst
].state
= WPS_STATE_REAUTH_WAIT
;
24872 /* Use ndev to find the wps instance which fired the timer */
24873 timer_set_private(&cfg
->wps_session
[inst
].timer
, ndev
);
24874 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24875 mod_timer(&cfg
->wps_session
[inst
].timer
,
24876 jiffies
+ msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT
));
24877 WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG
"\n",
24878 ndev
->name
, mode
, MAC2STRDBG(peer_mac
)));
24882 WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev
->name
));
24884 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24889 wl_wps_handle_disconnect(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
24891 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24892 unsigned long flags
;
24896 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24897 cur_state
= cfg
->wps_session
[inst
].state
;
24898 /* If Disconnect command comes from user space for STA/GC,
24899 * respond with event without waiting for event from fw as
24900 * it would be dropped by the WPS_SYNC code.
24902 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
24903 if (ETHER_ISBCAST(peer_mac
)) {
24904 WL_DBG(("[WPS] Bcast peer. Do nothing.\n"));
24906 /* Notify link down */
24907 CFG80211_DISCONNECTED(ndev
,
24908 WLAN_REASON_DEAUTH_LEAVING
, NULL
, 0,
24912 WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
24913 ndev
->name
, cur_state
));
24914 ret
= BCME_UNSUPPORTED
;
24916 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24921 wl_wps_handle_disconnect_client(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
24923 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24924 unsigned long flags
;
24927 bool wps_done
= false;
24929 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24930 cur_state
= cfg
->wps_session
[inst
].state
;
24931 /* For GO/AP, ignore disconnect client during reauth state */
24932 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
24933 if (ETHER_ISBCAST(peer_mac
)) {
24934 /* If there is broadcast deauth, then mark wps session as ended */
24935 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
24937 WL_INFORM_MEM(("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev
->name
));
24940 } else if (!(memcmp(cfg
->wps_session
[inst
].peer_mac
,
24941 peer_mac
, ETH_ALEN
))) {
24942 WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev
->name
));
24943 ret
= BCME_UNSUPPORTED
;
24948 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24950 wl_wps_session_del(ndev
);
24956 wl_wps_handle_connect_fail(struct net_device
*ndev
, u16 inst
)
24958 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24959 unsigned long flags
;
24961 bool wps_done
= false;
24963 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24964 cur_state
= cfg
->wps_session
[inst
].state
;
24965 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
24966 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
24968 WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n",
24971 WL_ERR(("[%s][WPS] Connect fail. state:%d\n",
24972 ndev
->name
, cur_state
));
24974 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24976 wl_wps_session_del(ndev
);
24982 wl_wps_handle_m8_sent(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
24984 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24985 unsigned long flags
;
24989 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
24990 cur_state
= cfg
->wps_session
[inst
].state
;
24992 if (cur_state
== WPS_STATE_STARTED
) {
24993 /* Move to M8 sent state */
24994 cfg
->wps_session
[inst
].state
= WPS_STATE_M8_SENT
;
24995 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
24999 WL_DBG(("[%s][WPS] Not valid state to send M8\n", ndev
->name
));
25001 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
25006 wl_wps_session_update(struct net_device
*ndev
, u16 state
, const u8
*peer_mac
)
25010 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25011 s32 ret
= BCME_ERROR
;
25012 unsigned long flags
;
25014 WL_CFG_WPS_SYNC_LOCK(&cfg
->wps_sync
, flags
);
25015 /* Get current instance for the given ndev */
25016 inst
= wl_get_wps_inst_match(cfg
, ndev
);
25017 if (inst
== BCME_ERROR
) {
25018 /* No active WPS session. Do Nothing. */
25019 WL_DBG(("[%s][WPS] No matching instance.\n", ndev
->name
));
25020 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
25021 return BCME_NOTFOUND
;
25023 mode
= cfg
->wps_session
[inst
].mode
;
25024 WL_CFG_WPS_SYNC_UNLOCK(&cfg
->wps_sync
, flags
);
25026 WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG
"\n",
25027 ndev
->name
, state
, mode
, MAC2STRDBG(peer_mac
)));
25030 case WPS_STATE_M8_RECVD
:
25032 /* Occasionally, due to race condition between ctrl
25033 * and data path, deauth ind is recvd before EAP-FAIL.
25034 * Ignore deauth ind before EAP-FAIL
25035 * So move to REAUTH WAIT on receiving M8 on GC and
25036 * ignore deauth ind before EAP-FAIL till 'x' timeout.
25037 * Kickoff a timer to monitor reauth status.
25039 if (mode
== WL_MODE_BSS
) {
25040 ret
= wl_wps_handle_reauth(ndev
, inst
, peer_mac
);
25042 /* Nothing to be done for AP/GO mode */
25047 case WPS_STATE_M8_SENT
:
25049 /* Mantain the M8 sent state to verify
25050 * EAP-FAIL sent is valid
25052 if (mode
== WL_MODE_AP
) {
25053 ret
= wl_wps_handle_m8_sent(ndev
, inst
, peer_mac
);
25055 /* Nothing to be done for STA/GC mode */
25060 case WPS_STATE_EAP_FAIL
:
25062 /* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
25063 * Kickoff a timer to monitor reauth status
25065 if (mode
== WL_MODE_AP
) {
25066 ret
= wl_wps_handle_reauth(ndev
, inst
, peer_mac
);
25068 /* Nothing to be done for STA/GC mode */
25073 case WPS_STATE_LINKDOWN
:
25075 if (mode
== WL_MODE_BSS
) {
25076 ret
= wl_wps_handle_sta_linkdown(ndev
, inst
);
25077 } else if (mode
== WL_MODE_AP
) {
25078 /* Take action only for matching peer mac */
25079 if (!memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
25080 ret
= wl_wps_handle_peersta_linkdown(ndev
, inst
, peer_mac
);
25085 case WPS_STATE_LINKUP
:
25087 if (mode
== WL_MODE_BSS
) {
25088 wl_wps_handle_sta_linkup(ndev
, inst
);
25089 } else if (mode
== WL_MODE_AP
) {
25090 /* Take action only for matching peer mac */
25091 if (!memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
25092 wl_wps_handle_peersta_linkup(ndev
, inst
, peer_mac
);
25097 case WPS_STATE_DISCONNECT_CLIENT
:
25099 /* Disconnect STA/GC command from user space */
25100 if (mode
== WL_MODE_AP
) {
25101 ret
= wl_wps_handle_disconnect_client(ndev
, inst
, peer_mac
);
25103 WL_ERR(("[WPS] Unsupported mode %d\n", mode
));
25107 case WPS_STATE_DISCONNECT
:
25109 /* Disconnect command on STA/GC interface */
25110 if (mode
== WL_MODE_BSS
) {
25111 ret
= wl_wps_handle_disconnect(ndev
, inst
, peer_mac
);
25115 case WPS_STATE_CONNECT_FAIL
:
25117 if (mode
== WL_MODE_BSS
) {
25118 ret
= wl_wps_handle_connect_fail(ndev
, inst
);
25120 WL_ERR(("[WPS] Unsupported mode %d\n", mode
));
25124 case WPS_STATE_AUTHORIZE
:
25126 if (mode
== WL_MODE_AP
) {
25127 /* Take action only for matching peer mac */
25128 if (!memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
25129 wl_wps_handle_authorize(ndev
, inst
, peer_mac
);
25131 WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
25138 WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state
, mode
));
25145 #define EAP_EXP_ATTRIB_DATA_OFFSET 14
25147 wl_handle_wps_states(struct net_device
*ndev
, u8
*pkt
, u16 len
, bool direction
)
25149 eapol_header_t
*eapol_hdr
;
25150 bool tx_packet
= direction
;
25155 if (!ndev
|| !pkt
) {
25156 WL_ERR(("[WPS] Invalid arg\n"));
25160 if (len
< (ETHER_HDR_LEN
+ EAPOL_HDR_LEN
)) {
25161 WL_ERR(("[WPS] Invalid len\n"));
25165 eapol_hdr
= (eapol_header_t
*)pkt
;
25166 eapol_type
= eapol_hdr
->type
;
25168 peer_mac
= tx_packet
? eapol_hdr
->eth
.ether_dhost
:
25169 eapol_hdr
->eth
.ether_shost
;
25171 * The implementation assumes only one WPS session would be active
25172 * per interface at a time. Even for hostap, the wps_pin session
25173 * is limited to one enrollee/client at a time. A session is marked
25174 * started on WSC_START and gets cleared from below contexts
25175 * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
25176 * b) Link up following EAP-FAIL. (success case)
25177 * c) Link up timeout after EAP-FAIL. (Fail case)
25180 if (eapol_type
== EAP_PACKET
) {
25181 wl_eap_header_t
*eap
;
25183 if (len
> sizeof(*eap
)) {
25184 eap
= (wl_eap_header_t
*)(pkt
+ ETHER_HDR_LEN
+ EAPOL_HDR_LEN
);
25185 if (eap
->type
== EAP_EXPANDED_TYPE
) {
25186 wl_eap_exp_t
*exp
= (wl_eap_exp_t
*)eap
->data
;
25187 if (eap
->length
> EAP_EXP_HDR_MIN_LENGTH
) {
25188 /* opcode is at fixed offset */
25189 u8 opcode
= exp
->opcode
;
25190 u16 eap_len
= ntoh16(eap
->length
);
25192 WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
25193 ndev
->name
, opcode
, eap_len
));
25194 if (opcode
== EAP_WSC_MSG
) {
25196 const u8
* parse_buf
= exp
->data
;
25197 /* Check if recvd pkt is fragmented */
25198 if ((!tx_packet
) &&
25200 EAP_EXP_FLAGS_FRAGMENTED_DATA
)) {
25201 if ((eap_len
- EAP_EXP_ATTRIB_DATA_OFFSET
)
25204 EAP_EXP_FRAGMENT_LEN_OFFSET
;
25206 EAP_EXP_FRAGMENT_LEN_OFFSET
;
25208 " fragmented pkt\n"));
25210 /* If recvd pkt is fragmented
25211 * and does not have
25212 * length field drop the packet.
25218 msg
= wl_find_attribute(parse_buf
,
25219 (eap_len
- EAP_EXP_ATTRIB_DATA_OFFSET
),
25220 EAP_ATTRIB_MSGTYPE
);
25221 if (unlikely(!msg
)) {
25222 WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
25223 } else if ((*msg
== EAP_WSC_MSG_M8
) &&
25225 /* In certain cases M2 can also carry
25226 * credential. So add check for
25227 * cred in M8/M2 and start reauth timer.
25229 WL_INFORM_MEM(("[%s][WPS] M8\n",
25231 wl_wps_session_update(ndev
,
25232 WPS_STATE_M8_RECVD
, peer_mac
);
25233 } else if ((*msg
== EAP_WSC_MSG_M8
) &&
25235 WL_INFORM_MEM(("[%s][WPS] M8 Sent\n",
25237 wl_wps_session_update(ndev
,
25238 WPS_STATE_M8_SENT
, peer_mac
);
25240 WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n",
25241 ndev
->name
, *msg
));
25243 } else if (opcode
== EAP_WSC_START
) {
25244 /* WSC session started. WSC_START - Tx from GO/AP.
25245 * Session will be deleted on successful link up or
25246 * on failure (deauth context)
25248 mode
= tx_packet
? WL_MODE_AP
: WL_MODE_BSS
;
25249 wl_wps_session_add(ndev
, mode
, peer_mac
);
25250 WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
25251 ndev
->name
, mode
));
25252 } else if (opcode
== EAP_WSC_DONE
) {
25253 /* WSC session done. TX on STA/GC. RX on GO/AP
25254 * On devices where config file save fails, it may
25255 * return WPS_NAK with config_error:0. But the
25256 * connection would still proceed. Hence don't let
25257 * state machine depend on WSC DONE.
25259 WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev
->name
));
25264 if (eap
->code
== EAP_CODE_FAILURE
) {
25266 WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev
->name
));
25267 wl_wps_session_update(ndev
,
25268 WPS_STATE_EAP_FAIL
, peer_mac
);
25273 #endif /* WL_WPS_SYNC */
25276 wl_cfg80211_sup_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
25277 const wl_event_msg_t
*event
, void *data
)
25280 u32 status
= ntoh32(event
->status
);
25281 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
25282 u32 reason
= ntoh32(event
->reason
);
25284 if (!wl_get_drv_status(cfg
, CFG80211_CONNECT
, ndev
)) {
25285 /* Join attempt via non-cfg80211 interface.
25286 * Don't send resultant events to cfg80211
25289 WL_INFORM_MEM(("Event received in non-cfg80211"
25290 " connect state. Ignore\n"));
25294 if ((status
== WLC_SUP_KEYED
|| status
== WLC_SUP_KEYXCHANGE_WAIT_G1
) &&
25295 reason
== WLC_E_SUP_OTHER
) {
25296 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
25297 /* NL80211_CMD_PORT_AUTHORIZED supported above >= 4.15 */
25298 cfg80211_port_authorized(ndev
, (u8
*)wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
),
25300 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
25301 #elif ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
25302 defined(WL_VENDOR_EXT_SUPPORT))
25303 err
= wl_cfgvendor_send_async_event(bcmcfg_to_wiphy(cfg
), ndev
,
25304 BRCM_VENDOR_EVENT_PORT_AUTHORIZED
, NULL
, 0);
25305 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
25307 /* not supported in kernel <= 3,14,0 */
25308 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */
25309 /* Post SCB authorize actions */
25310 wl_cfg80211_post_scb_auth(cfg
, ndev
);
25311 } else if (status
< WLC_SUP_KEYXCHANGE_WAIT_G1
&& (reason
!= WLC_E_SUP_OTHER
&&
25312 reason
!= WLC_E_SUP_PTK_UPDATE
)) {
25313 /* if any failure seen while 4way HS, should send NL80211_CMD_DISCONNECT */
25314 WL_ERR(("4way HS error. status:%d, reason:%d\n", status
, reason
));
25315 CFG80211_DISCONNECTED(ndev
, 0, NULL
, 0, false, GFP_KERNEL
);
25323 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
25324 const wl_event_msg_t
*e
, void *data
)
25326 s32 status
= ntoh32(e
->status
);
25327 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
25328 /* Abort fakeapscan, when Roam is in progress */
25329 if (status
== WLC_E_STATUS_RXBCN_ABORT
) {
25330 wl_android_bcnrecv_stop(ndev
, WL_BCNRECV_ROAMABORT
);
25332 WL_ERR(("UNKNOWN STATUS. status:%d\n", status
));
25336 #endif /* WL_BCNRECV */
25340 wl_mbo_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
25341 const wl_event_msg_t
*e
, void *data
)
25344 wl_event_mbo_t
*mbo_evt
= (wl_event_mbo_t
*)data
;
25345 wl_event_mbo_cell_nw_switch_t
*cell_sw_evt
= NULL
;
25346 wl_btm_event_type_data_t
*evt_data
= NULL
;
25348 WL_INFORM(("MBO: Evt %u\n", mbo_evt
->type
));
25350 if (mbo_evt
->type
== WL_MBO_E_CELLULAR_NW_SWITCH
) {
25351 cell_sw_evt
= (wl_event_mbo_cell_nw_switch_t
*)mbo_evt
->data
;
25352 BCM_REFERENCE(cell_sw_evt
);
25353 SUPP_EVENT(("CTRL-EVENT-CELLULAR-SWITCH", "reason %d cur_assoc_time_left %u "
25354 "reassoc_delay %u\n", cell_sw_evt
->reason
,
25355 cell_sw_evt
->assoc_time_remain
, cell_sw_evt
->reassoc_delay
));
25356 } else if (mbo_evt
->type
== WL_MBO_E_BTM_RCVD
) {
25357 evt_data
= (wl_btm_event_type_data_t
*)mbo_evt
->data
;
25358 if (evt_data
->version
!= WL_BTM_EVENT_DATA_VER_1
) {
25359 WL_ERR(("version mismatch. rcvd %u expected %u\n",
25360 evt_data
->version
, WL_BTM_EVENT_DATA_VER_1
));
25363 SUPP_EVENT(("CTRL-EVENT-BRCM-BTM-REQ-RCVD", "reason=%u\n",
25364 evt_data
->transition_reason
));
25366 WL_INFORM(("UNKNOWN EVENT. type:%u\n", mbo_evt
->type
));
25370 #endif /* WL_MBO */
25374 wl_cfg80211_cac_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
25375 const wl_event_msg_t
*e
, void *data
)
25377 u32 event
= ntoh32(e
->event_type
);
25378 s32 status
= ntoh32(e
->status
);
25379 s32 reason
= ntoh32(e
->reason
);
25381 BCM_REFERENCE(reason
);
25383 if (event
== WLC_E_ADDTS_IND
) {
25384 /* The supp log format of adding ts_delay in success case needs to be maintained */
25385 if (status
== WLC_E_STATUS_SUCCESS
) {
25386 uint
*ts_delay
= (uint
*)data
;
25387 BCM_REFERENCE(ts_delay
);
25388 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d ts_delay=%u\n",
25389 status
, reason
, *ts_delay
));
25391 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d\n",
25394 } else if (event
== WLC_E_DELTS_IND
) {
25395 SUPP_EVENT(("CTRL-EVENT-CAC-DELTS", "status=%d reason=%d\n", status
, reason
));
25400 #endif /* WL_CAC_TS */
25402 #if defined(WL_MBO) || defined(WL_OCE)
25404 wl_bssid_prune_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
25405 const wl_event_msg_t
*e
, void *data
)
25409 wl_bssid_pruned_evt_info_t
*evt_info
= (wl_bssid_pruned_evt_info_t
*)data
;
25411 if (evt_info
->version
== WL_BSSID_PRUNE_EVT_VER_1
) {
25412 if (evt_info
->reason
== WLC_E_PRUNE_ASSOC_RETRY_DELAY
) {
25413 /* MBO assoc retry delay */
25414 reason
= WIFI_PRUNE_ASSOC_RETRY_DELAY
;
25415 SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
25416 " reason=%u timeout_val=%u(ms)\n", evt_info
->SSID
,
25417 ETHER_TO_MACF(evt_info
->BSSID
), reason
, evt_info
->time_remaining
));
25418 } else if (evt_info
->reason
== WLC_E_PRUNE_RSSI_ASSOC_REJ
) {
25419 /* OCE RSSI-based assoc rejection */
25420 reason
= WIFI_PRUNE_RSSI_ASSOC_REJ
;
25421 SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
25422 " reason=%u timeout_val=%u(ms) rssi_threshold=%d(dBm)\n",
25423 evt_info
->SSID
, ETHER_TO_MACF(evt_info
->BSSID
),
25424 reason
, evt_info
->time_remaining
, evt_info
->rssi_threshold
));
25426 /* Invalid other than the assoc retry delay/RSSI assoc rejection
25427 * in the current handler
25429 BCM_REFERENCE(reason
);
25430 WL_INFORM(("INVALID. reason:%u\n", evt_info
->reason
));
25433 WL_INFORM(("version mismatch. rcvd %u expected %u\n", evt_info
->version
,
25434 WL_BSSID_PRUNE_EVT_VER_1
));
25438 #endif /* WL_MBO || WL_OCE */
25441 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
25442 const wl_event_msg_t
*e
, void *data
)
25444 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
25445 wl_event_msg_t event
;
25447 (void)memcpy_s(&event
, sizeof(wl_event_msg_t
),
25448 e
, sizeof(wl_event_msg_t
));
25449 return dhd_rtt_event_handler(dhdp
, &event
, data
);
25451 #endif /* RTT_SUPPORT */
25454 wl_print_verinfo(struct bcm_cfg80211
*cfg
)
25457 uint32 alloc_len
= MOD_PARAM_INFOLEN
;
25460 WL_ERR(("cfg is NULL\n"));
25464 ver_ptr
= (char *)MALLOCZ(cfg
->osh
, alloc_len
);
25466 WL_ERR(("Failed to alloc ver_ptr\n"));
25470 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg
),
25471 TRUE
, &ver_ptr
, alloc_len
)) {
25472 WL_ERR(("DHD Version: %s\n", ver_ptr
));
25475 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg
),
25476 FALSE
, &ver_ptr
, alloc_len
)) {
25477 WL_ERR(("F/W Version: %s\n", ver_ptr
));
25480 MFREE(cfg
->osh
, ver_ptr
, alloc_len
);
25490 wl_he_get_uint_cb(void *ctx
, uint16
*id
, uint16
*len
)
25492 he_xtlv_v32
*v32
= ctx
;
25501 wl_he_pack_uint_cb(void *ctx
, uint16 id
, uint16 len
, uint8
*buf
)
25503 he_xtlv_v32
*v32
= ctx
;
25506 BCM_REFERENCE(len
);
25508 v32
->val
= htod32(v32
->val
);
25510 switch (v32
->len
) {
25511 case sizeof(uint8
):
25512 *buf
= (uint8
)v32
->val
;
25514 case sizeof(uint16
):
25515 store16_ua(buf
, (uint16
)v32
->val
);
25517 case sizeof(uint32
):
25518 store32_ua(buf
, v32
->val
);
25526 int wl_cfg80211_set_he_mode(struct net_device
*dev
, struct bcm_cfg80211
*cfg
,
25527 s32 bssidx
, u32 interface_type
, bool set
)
25529 bcm_xtlv_t read_he_xtlv
;
25530 uint8 se_he_xtlv
[32];
25531 int se_he_xtlv_len
= sizeof(se_he_xtlv
);
25533 u32 he_feature
= 0;
25535 u32 he_interface
= 0;
25537 read_he_xtlv
.id
= WL_HE_CMD_FEATURES
;
25538 read_he_xtlv
.len
= 0;
25539 err
= wldev_iovar_getbuf_bsscfg(dev
, "he", &read_he_xtlv
, sizeof(read_he_xtlv
),
25540 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, bssidx
, NULL
);
25542 if (err
== BCME_UNSUPPORTED
) {
25543 /* HE not supported. Do nothing. */
25546 WL_ERR(("HE get failed. error=%d\n", err
));
25548 he_feature
= *(int*)cfg
->ioctl_buf
;
25549 he_feature
= dtoh32(he_feature
);
25552 v32
.id
= WL_HE_CMD_FEATURES
;
25553 v32
.len
= sizeof(s32
);
25554 if (interface_type
== WL_IF_TYPE_P2P_DISC
) {
25555 he_interface
= WL_HE_FEATURES_HE_P2P
;
25556 } else if (interface_type
== WL_IF_TYPE_AP
) {
25557 he_interface
= WL_HE_FEATURES_HE_AP
;
25559 WL_ERR(("HE request for Invalid interface type"));
25565 v32
.val
= (he_feature
| he_interface
);
25567 v32
.val
= (he_feature
& ~he_interface
);
25570 err
= bcm_pack_xtlv_buf((void *)&v32
, se_he_xtlv
, sizeof(se_he_xtlv
),
25571 BCM_XTLV_OPTION_ALIGN32
, wl_he_get_uint_cb
, wl_he_pack_uint_cb
,
25573 if (err
!= BCME_OK
) {
25574 WL_ERR(("failed to pack he settvl=%d\n", err
));
25577 err
= wldev_iovar_setbuf_bsscfg(dev
, "he", &se_he_xtlv
, sizeof(se_he_xtlv
),
25578 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
25580 WL_ERR(("failed to set he features, error=%d\n", err
));
25582 WL_INFORM(("Set HE[%d] done\n", set
));
25587 /* Get the concurrency mode */
25588 int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211
*cfg
)
25590 struct net_info
*iter
, *next
;
25591 uint cmode
= CONCURRENCY_MODE_NONE
;
25592 u32 connected_cnt
= 0;
25593 u32 pre_channel
= 0, channel
= 0;
25598 connected_cnt
= wl_get_drv_status_all(cfg
, CONNECTED
);
25599 if (connected_cnt
<= 1) {
25602 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
25603 for_each_ndev(cfg
, iter
, next
) {
25605 if (wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
)) {
25606 if (wldev_iovar_getint(iter
->ndev
, "chanspec",
25607 (s32
*)&chanspec
) == BCME_OK
) {
25608 channel
= wf_chspec_ctlchan(
25609 wl_chspec_driver_to_host(chanspec
));
25610 band
= (channel
<= CH_MAX_2G_CHANNEL
) ?
25611 IEEE80211_BAND_2GHZ
: IEEE80211_BAND_5GHZ
;
25613 if ((!pre_channel
&& channel
)) {
25615 pre_channel
= channel
;
25616 } else if (pre_channel
) {
25617 if ((pre_band
== band
) && (pre_channel
== channel
)) {
25618 cmode
= CONCURRENCY_SCC_MODE
;
25620 } else if ((pre_band
== band
) && (pre_channel
!= channel
)) {
25621 cmode
= CONCURRENCY_VSDB_MODE
;
25623 } else if (pre_band
!= band
) {
25624 cmode
= CONCURRENCY_RSDB_MODE
;
25631 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
25632 4 && __GNUC_MINOR__ >= 6))
25633 _Pragma("GCC diagnostic pop")
25638 #ifdef WL_CHAN_UTIL
25640 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
25641 const wl_event_msg_t
*e
, void *data
)
25644 struct sk_buff
*skb
= NULL
;
25645 s32 status
= ntoh32(e
->status
);
25646 u8 chan_use_percentage
= 0;
25647 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
25648 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
25649 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
25650 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
25651 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
25652 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25653 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
25656 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25658 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25659 len
= CU_ATTR_HDR_LEN
+ sizeof(u8
);
25660 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
25661 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25663 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
25664 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
25665 skb
= cfg80211_vendor_event_alloc(wiphy
, ndev_to_wdev(ndev
), len
,
25666 BRCM_VENDOR_EVENT_CU
, kflags
);
25667 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25668 skb
= cfg80211_vendor_event_alloc(wiphy
, len
, BRCM_VENDOR_EVENT_CU
, kflags
);
25670 /* No support exist */
25671 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
25672 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
25674 WL_ERR(("skb alloc failed"));
25678 if ((status
== WLC_E_STATUS_SUCCESS
) && data
) {
25679 wl_bssload_t
*bssload_report
= (wl_bssload_t
*)data
;
25680 chan_use_percentage
= (bssload_report
->chan_util
* 100) / 255;
25681 WL_DBG(("ChannelUtilization=%hhu\n", chan_use_percentage
));
25682 err
= nla_put_u8(skb
, CU_ATTR_PERCENTAGE
, chan_use_percentage
);
25684 WL_ERR(("Failed to put CU_ATTR_PERCENTAGE, err:%d\n", err
));
25688 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25689 cfg80211_vendor_event(skb
, kflags
);
25690 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25695 #define WL_CHAN_UTIL_DEFAULT_INTERVAL 3000
25696 #define WL_CHAN_UTIL_THRESH_MIN 15
25697 #define WL_CHAN_UTIL_THRESH_INTERVAL 10
25698 #ifndef CUSTOM_CU_INTERVAL
25699 #define CUSTOM_CU_INTERVAL WL_CHAN_UTIL_DEFAULT_INTERVAL
25700 #endif /* CUSTOM_CU_INTERVAL */
25703 wl_cfg80211_start_bssload_report(struct net_device
*ndev
)
25706 wl_bssload_cfg_t blcfg
;
25708 struct bcm_cfg80211
*cfg
;
25714 cfg
= wl_get_cfg(ndev
);
25719 /* Typecasting to void as the buffer size is same as the memset size */
25720 (void)memset_s(&blcfg
, sizeof(wl_bssload_cfg_t
), 0, sizeof(wl_bssload_cfg_t
));
25721 /* Set default report interval 3 sec and 8 threshhold levels between 15 to 85% */
25722 blcfg
.rate_limit_msec
= CUSTOM_CU_INTERVAL
;
25723 blcfg
.num_util_levels
= MAX_BSSLOAD_LEVELS
;
25724 for (i
= 0; i
< MAX_BSSLOAD_LEVELS
; i
++) {
25725 blcfg
.util_levels
[i
] = (((WL_CHAN_UTIL_THRESH_MIN
+
25726 (i
* WL_CHAN_UTIL_THRESH_INTERVAL
)) * 255) / 100);
25729 err
= wldev_iovar_setbuf(ndev
, "bssload_report_event", &blcfg
,
25730 sizeof(wl_bssload_cfg_t
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
25731 if (unlikely(err
)) {
25732 WL_ERR(("Set event_msgs error (%d)\n", err
));
25737 #endif /* WL_CHAN_UTIL */
25740 wl_cfg80211_config_suspend_events(struct net_device
*ndev
, bool enable
)
25743 struct bcm_cfg80211
*cfg
;
25744 s8 event_buf
[WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
] = {0};
25745 eventmsgs_ext_t
*eventmask_msg
= NULL
;
25746 /* Room for "event_msgs_ext" + '\0' + bitvec */
25747 char iovbuf
[WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
+ 16];
25748 s32 msglen
= WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
;
25754 cfg
= wl_get_cfg(ndev
);
25759 mutex_lock(&cfg
->event_sync
);
25761 eventmask_msg
= (eventmsgs_ext_t
*)event_buf
;
25762 eventmask_msg
->ver
= EVENTMSGS_VER
;
25763 eventmask_msg
->command
= EVENTMSGS_NONE
;
25764 eventmask_msg
->len
= WL_EVENTING_MASK_EXT_LEN
;
25765 eventmask_msg
->maxgetsize
= WL_EVENTING_MASK_EXT_LEN
;
25767 /* Read event_msgs mask */
25768 err
= wldev_iovar_getbuf(ndev
, "event_msgs_ext",
25769 eventmask_msg
, EVENTMSGS_EXT_STRUCT_SIZE
,
25774 if (unlikely(err
)) {
25775 WL_ERR(("Get event_msgs error (%d)\n", err
));
25779 bcopy(iovbuf
, eventmask_msg
, msglen
);
25781 /* Add set/clear of event mask under feature specific flags */
25783 WL_DBG(("%s: Enabling events on resume\n", __FUNCTION__
));
25784 #ifdef WL_CHAN_UTIL
25785 setbit(eventmask_msg
->mask
, WLC_E_BSS_LOAD
);
25786 #endif /* WL_CHAN_UTIL */
25788 WL_DBG(("%s: Disabling events before suspend\n", __FUNCTION__
));
25789 #ifdef WL_CHAN_UTIL
25790 clrbit(eventmask_msg
->mask
, WLC_E_BSS_LOAD
);
25791 #endif /* WL_CHAN_UTIL */
25794 /* Write updated Event mask */
25795 eventmask_msg
->ver
= EVENTMSGS_VER
;
25796 eventmask_msg
->command
= EVENTMSGS_SET_MASK
;
25797 eventmask_msg
->len
= WL_EVENTING_MASK_EXT_LEN
;
25799 err
= wldev_iovar_setbuf(ndev
, "event_msgs_ext", eventmask_msg
,
25800 WL_EVENTING_MASK_EXT_LEN
+ EVENTMSGS_EXT_STRUCT_SIZE
,
25801 iovbuf
, sizeof(iovbuf
), NULL
);
25803 if (unlikely(err
)) {
25804 WL_ERR(("Set event_msgs error (%d)\n", err
));
25809 mutex_unlock(&cfg
->event_sync
);
25813 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
25815 wl_cfg80211_channel_switch(struct wiphy
*wiphy
, struct net_device
*dev
,
25816 struct cfg80211_csa_settings
*params
)
25819 u32 bw
= WL_CHANSPEC_BW_20
;
25820 chanspec_t chspec
= 0;
25821 wl_chan_switch_t csa_arg
;
25822 struct cfg80211_chan_def
*chandef
= ¶ms
->chandef
;
25823 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
25824 struct net_device
*primary_dev
= bcmcfg_to_prmry_ndev(cfg
);
25826 dev
= ndev_to_wlc_ndev(dev
, cfg
);
25827 chspec
= wl_freq_to_chanspec(chandef
->chan
->center_freq
);
25829 WL_ERR(("netdev_ifidx(%d), target channel(%d) target bandwidth(%d),"
25830 " mode(%d), count(%d)\n", dev
->ifindex
, CHSPEC_CHANNEL(chspec
), chandef
->width
,
25831 params
->block_tx
, params
->count
));
25833 if (wl_get_mode_by_netdev(cfg
, dev
) != WL_MODE_AP
) {
25834 WL_ERR(("Channel Switch doesn't support on "
25835 "the non-SoftAP mode\n"));
25839 /* Check if STA is trying to associate with an AP */
25840 if (wl_get_drv_status(cfg
, CONNECTING
, primary_dev
)) {
25841 WL_ERR(("Connecting is in progress\n"));
25845 if (chspec
== cfg
->ap_oper_channel
) {
25846 WL_ERR(("Channel %d is same as current operating channel,"
25847 " so skip\n", CHSPEC_CHANNEL(chspec
)));
25853 CHSPEC_IS6G(chspec
) ||
25855 CHSPEC_IS5G(chspec
)) {
25856 #ifdef APSTA_RESTRICTED_CHANNEL
25857 if (CHSPEC_CHANNEL(chspec
) != DEFAULT_5G_SOFTAP_CHANNEL
) {
25858 WL_ERR(("Invalid 5G Channel, chan=%d\n", CHSPEC_CHANNEL(chspec
)));
25861 #endif /* APSTA_RESTRICTED_CHANNEL */
25862 err
= wl_get_bandwidth_cap(primary_dev
, CHSPEC_BAND(chspec
), &bw
);
25864 WL_ERR(("Failed to get bandwidth information,"
25865 " err=%d\n", err
));
25868 } else if (CHSPEC_IS2G(chspec
)) {
25869 #ifdef APSTA_RESTRICTED_CHANNEL
25870 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
25871 chanspec_t
*sta_chanspec
= (chanspec_t
*)wl_read_prof(cfg
,
25872 primary_dev
, WL_PROF_CHAN
);
25874 /* In 2GHz STA/SoftAP concurrent mode, the operating channel
25875 * of STA and SoftAP should be confgiured to the same 2GHz
25876 * channel. Otherwise, it is an invalid configuration.
25878 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp
) &&
25879 wl_get_drv_status(cfg
, CONNECTED
, primary_dev
) &&
25880 sta_chanspec
&& (CHSPEC_CHANNEL(*sta_chanspec
) != CHSPEC_CHANNEL(chspec
))) {
25881 WL_ERR(("Invalid 2G Channel in case of STA/SoftAP"
25882 " concurrent mode, sta_chan=%d, chan=%d\n",
25883 CHSPEC_CHANNEL(*sta_chanspec
), CHSPEC_CHANNEL(chspec
)));
25886 #endif /* APSTA_RESTRICTED_CHANNEL */
25887 bw
= WL_CHANSPEC_BW_20
;
25889 WL_ERR(("invalid band (%d)\n", CHSPEC_BAND(chspec
)));
25894 /* Avoid in case of 6G as for each center frequency bw is unique and is
25895 * detected based on centre frequency.
25897 if (!CHSPEC_IS6G(chspec
))
25898 #endif /* WL_6G_BAND */
25900 chspec
= wf_channel2chspec(CHSPEC_CHANNEL(chspec
), bw
);
25902 if (!wf_chspec_valid(chspec
)) {
25903 WL_ERR(("Invalid chanspec 0x%x\n", chspec
));
25907 /* Send CSA to associated STAs */
25908 memset(&csa_arg
, 0, sizeof(wl_chan_switch_t
));
25909 csa_arg
.mode
= params
->block_tx
;
25910 csa_arg
.count
= params
->count
;
25911 csa_arg
.chspec
= chspec
;
25912 csa_arg
.frame_type
= CSA_BROADCAST_ACTION_FRAME
;
25915 err
= wldev_iovar_setbuf(dev
, "csa", &csa_arg
, sizeof(wl_chan_switch_t
),
25916 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
25918 WL_ERR(("Failed to switch channel, err=%d\n", err
));
25923 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
25927 wl_cfg80211_wips_event_ext(wl_wips_event_info_t
*wips_event
)
25930 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25931 struct sk_buff
*skb
;
25933 struct bcm_cfg80211
*cfg
;
25934 struct net_device
*ndev
;
25935 struct wiphy
*wiphy
;
25937 cfg
= wl_cfg80211_get_bcmcfg();
25938 if (!cfg
|| !cfg
->wdev
) {
25939 WL_ERR(("WIPS evt invalid arg\n"));
25943 ndev
= bcmcfg_to_prmry_ndev(cfg
);
25944 wiphy
= bcmcfg_to_wiphy(cfg
);
25946 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
25947 skb
= CFG80211_VENDOR_EVENT_ALLOC(wiphy
, ndev_to_wdev(ndev
),
25948 BRCM_VENDOR_WIPS_EVENT_BUF_LEN
, BRCM_VENDOR_EVENT_WIPS
, kflags
);
25951 WL_ERR(("skb alloc failed"));
25955 err
= nla_put_u16(skb
, WIPS_ATTR_DEAUTH_CNT
, wips_event
->misdeauth
);
25956 if (unlikely(err
)) {
25957 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_CNT failed\n"));
25960 err
= nla_put(skb
, WIPS_ATTR_DEAUTH_BSSID
, ETHER_ADDR_LEN
, &wips_event
->bssid
);
25961 if (unlikely(err
)) {
25962 WL_ERR(("nla_put WIPS_ATTR_DEAUTH_BSSID failed\n"));
25965 err
= nla_put_s16(skb
, WIPS_ATTR_CURRENT_RSSI
, wips_event
->current_RSSI
);
25966 if (unlikely(err
)) {
25967 WL_ERR(("nla_put_u16 WIPS_ATTR_CURRENT_RSSI failed\n"));
25970 err
= nla_put_s16(skb
, WIPS_ATTR_DEAUTH_RSSI
, wips_event
->deauth_RSSI
);
25971 if (unlikely(err
)) {
25972 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_RSSI failed\n"));
25975 cfg80211_vendor_event(skb
, kflags
);
25983 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25988 wl_cfg80211_wips_event(uint16 misdeauth
, char* bssid
)
25991 wl_wips_event_info_t wips_event
;
25993 wips_event
.misdeauth
= misdeauth
;
25994 memcpy(&wips_event
.bssid
, bssid
, ETHER_ADDR_LEN
);
25995 wips_event
.current_RSSI
= 0;
25996 wips_event
.deauth_RSSI
= 0;
25998 err
= wl_cfg80211_wips_event_ext(&wips_event
);
26001 #endif /* WL_WIPSEVT */
26006 * This API checks whether its okay to enter DS.
26007 * If some transaction is in progress, return true
26010 bool wl_cfg80211_check_in_progress(struct net_device
*dev
)
26012 struct bcm_cfg80211
*cfg
;
26013 struct net_device
*pri_dev
;
26014 u8 reason
= WL_STATE_IDLE
;
26016 u64 start_time
= 0;
26018 cfg
= wl_get_cfg(dev
);
26019 pri_dev
= bcmcfg_to_prmry_ndev(cfg
);
26021 /* check states like scan in progress, four way handshake, etc
26022 * before entering Deep Sleep.
26024 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
26025 WL_DS(("scan in progress\n"));
26026 reason
= WL_STATE_SCANNING
;
26027 start_time
= GET_TS(cfg
, scan_start
);
26028 } else if (wl_get_drv_status_all(cfg
, CONNECTING
)) {
26029 WL_DS(("connect in progress\n"));
26030 reason
= WL_STATE_CONNECTING
;
26031 start_time
= GET_TS(cfg
, conn_start
);
26032 } else if ((IS_STA_IFACE(ndev_to_wdev(dev
))) &&
26033 wl_get_drv_status(cfg
, CONNECTED
, pri_dev
) &&
26034 !wl_get_drv_status(cfg
, AUTHORIZED
, pri_dev
)) {
26035 WL_DS(("connect-authorization in progress\n"));
26036 reason
= WL_STATE_AUTHORIZING
;
26037 start_time
= GET_TS(cfg
, authorize_start
);
26041 u64 curtime
= OSL_LOCALTIME_NS();
26042 if (unlikely(!start_time
)) {
26043 WL_ERR(("state got cleared for reason:%d\n", reason
));
26046 /* check whether we are stuck in a state
26049 timeout
= (start_time
+ (WL_DS_SKIP_THRESHOLD_USECS
* 1000L));
26050 if (time_after64(curtime
, timeout
)) {
26051 /* state hasn't changed for WL_DS_SKIP_THRESHOLD_USECS */
26052 WL_ERR(("DS skip threshold hit. reason:%d start_time:"
26053 SEC_USEC_FMT
" cur_time:"SEC_USEC_FMT
"\n",
26054 reason
, GET_SEC_USEC(start_time
), GET_SEC_USEC(curtime
)));
26057 /* return true to skip suspend */
26065 #ifdef SUPPORT_AP_SUSPEND
26067 wl_set_ap_suspend_error_handler(struct net_device
*ndev
, bool suspend
)
26069 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
26070 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
26072 if (wl_get_drv_status(cfg
, READY
, ndev
)) {
26073 /* IF dongle is down due to previous hang or other conditions, sending
26074 * one more hang notification is not needed.
26076 if (dhd_query_bus_erros(dhdp
)) {
26079 dhdp
->iface_op_failed
= TRUE
;
26080 #if defined(DHD_FW_COREDUMP)
26081 if (dhdp
->memdump_enabled
) {
26082 dhdp
->memdump_type
= DUMP_TYPE_IFACE_OP_FAILURE
;
26083 dhd_bus_mem_dump(dhdp
);
26085 #endif /* DHD_FW_COREDUMP */
26087 WL_ERR(("Notify hang event to upper layer \n"));
26088 dhdp
->hang_reason
= suspend
?
26089 HANG_REASON_BSS_DOWN_FAILURE
: HANG_REASON_BSS_UP_FAILURE
;
26090 net_os_send_hang_message(ndev
);
26095 #define MAX_AP_RESUME_TIME 5000
26097 wl_set_ap_suspend(struct net_device
*dev
, bool suspend
, char *ifname
)
26099 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
26101 struct net_device
*ndev
= NULL
;
26103 bool is_bssup
= FALSE
;
26105 unsigned long start_j
;
26106 int time_to_sleep
= MAX_AP_RESUME_TIME
;
26108 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
26114 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
26115 WL_ERR(("Not Hostapd mode\n"));
26119 ndev
= wl_get_ap_netdev(cfg
, ifname
);
26121 if (ndev
== NULL
) {
26122 WL_ERR(("No softAP interface named %s\n", ifname
));
26126 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, ndev
->ieee80211_ptr
)) < 0) {
26127 WL_ERR(("Find p2p index from wdev(%p) failed\n", ndev
->ieee80211_ptr
));
26128 return BCME_NOTFOUND
;
26131 is_bssup
= wl_cfg80211_bss_isup(ndev
, bssidx
);
26132 if (is_bssup
&& suspend
) {
26133 wl_clr_drv_status(cfg
, AP_CREATED
, ndev
);
26134 wl_clr_drv_status(cfg
, CONNECTED
, ndev
);
26136 if ((ret
= wl_cfg80211_bss_up(cfg
, ndev
, bssidx
, 0)) < 0) {
26137 WL_ERR(("AP suspend error %d, suspend %d\n", ret
, suspend
));
26138 ret
= BCME_NOTDOWN
;
26141 } else if (!is_bssup
&& !suspend
) {
26142 /* Abort scan before starting AP again */
26143 wl_cfg80211_scan_abort(cfg
);
26145 if ((ret
= wl_cfg80211_bss_up(cfg
, ndev
, bssidx
, 1)) < 0) {
26146 WL_ERR(("AP resume error %d, suspend %d\n", ret
, suspend
));
26152 start_j
= get_jiffies_64();
26153 /* Wait for Linkup event to mark successful AP bring up */
26154 ret
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
26155 wl_get_drv_status(cfg
, AP_CREATED
, ndev
),
26156 msecs_to_jiffies(time_to_sleep
));
26157 if (ret
== -ERESTARTSYS
) {
26158 WL_ERR(("waitqueue was interrupted by a signal\n"));
26159 time_to_sleep
-= jiffies_to_msecs(get_jiffies_64() - start_j
);
26160 if (time_to_sleep
<= 0) {
26161 WL_ERR(("time to sleep hits 0\n"));
26165 } else if (ret
== 0 || !wl_get_drv_status(cfg
, AP_CREATED
, ndev
)) {
26166 WL_ERR(("AP resume failed!\n"));
26170 wl_set_drv_status(cfg
, CONNECTED
, ndev
);
26171 wl_clr_drv_status(cfg
, AP_CREATING
, ndev
);
26177 /* bssup + resume or bssdown + suspend,
26183 if (ret
!= BCME_OK
)
26184 wl_set_ap_suspend_error_handler(bcmcfg_to_prmry_ndev(cfg
), suspend
);
26188 #endif /* SUPPORT_AP_SUSPEND */
26190 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
26191 int wl_set_softap_elna_bypass(struct net_device
*dev
, char *ifname
, int enable
)
26193 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
26194 struct net_device
*ifdev
= NULL
;
26195 char iobuf
[WLC_IOCTL_SMLEN
];
26199 memset(iobuf
, 0, WLC_IOCTL_SMLEN
);
26201 /* Check the interface type */
26202 ifdev
= wl_get_netdev_by_name(cfg
, ifname
);
26203 if (ifdev
== NULL
) {
26204 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__
, ifname
));
26209 iftype
= ifdev
->ieee80211_ptr
->iftype
;
26210 if (iftype
== NL80211_IFTYPE_AP
) {
26211 err
= wldev_iovar_setint(ifdev
, "softap_elnabypass", enable
);
26212 if (unlikely(err
)) {
26213 WL_ERR(("%s: Failed to set softap_elnabypass, err=%d\n",
26214 __FUNCTION__
, err
));
26217 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
26224 int wl_get_softap_elna_bypass(struct net_device
*dev
, char *ifname
, void *param
)
26226 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
26227 int *enable
= (int*)param
;
26228 struct net_device
*ifdev
= NULL
;
26229 char iobuf
[WLC_IOCTL_SMLEN
];
26233 memset(iobuf
, 0, WLC_IOCTL_SMLEN
);
26235 /* Check the interface type */
26236 ifdev
= wl_get_netdev_by_name(cfg
, ifname
);
26237 if (ifdev
== NULL
) {
26238 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__
, ifname
));
26243 iftype
= ifdev
->ieee80211_ptr
->iftype
;
26244 if (iftype
== NL80211_IFTYPE_AP
) {
26245 err
= wldev_iovar_getint(ifdev
, "softap_elnabypass", enable
);
26246 if (unlikely(err
)) {
26247 WL_ERR(("%s: Failed to get softap_elnabypass, err=%d\n",
26248 __FUNCTION__
, err
));
26251 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
26259 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
26261 #ifdef SUPPORT_AP_BWCTRL
26262 #define OPER_MODE_ENABLE (1 << 8)
26263 static int op2bw
[] = {20, 40, 80, 160};
26266 wl_get_ap_he_mode(struct net_device
*ndev
, struct bcm_cfg80211
*cfg
, bool *he
)
26268 bcm_xtlv_t read_he_xtlv
;
26271 u32 he_feature
= 0;
26274 /* Check he enab first */
26275 read_he_xtlv
.id
= WL_HE_CMD_ENAB
;
26276 read_he_xtlv
.len
= 0;
26278 ret
= wldev_iovar_getbuf(ndev
, "he", &read_he_xtlv
, sizeof(read_he_xtlv
),
26279 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, NULL
);
26281 if (ret
== BCME_UNSUPPORTED
) {
26282 /* HE not supported */
26285 WL_ERR(("HE ENAB get failed. ret=%d\n", ret
));
26289 he_enab
= *(u8
*)cfg
->ioctl_buf
;
26296 /* Then check BIT3 of he features */
26297 read_he_xtlv
.id
= WL_HE_CMD_FEATURES
;
26298 read_he_xtlv
.len
= 0;
26300 ret
= wldev_iovar_getbuf(ndev
, "he", &read_he_xtlv
, sizeof(read_he_xtlv
),
26301 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, NULL
);
26303 WL_ERR(("HE FEATURE get failed. error=%d\n", ret
));
26306 he_feature
= *(int*)cfg
->ioctl_buf
;
26307 he_feature
= dtoh32(he_feature
);
26310 if (he_feature
& WL_HE_FEATURES_HE_AP
) {
26311 WL_DBG(("HE is enabled in AP\n"));
26319 wl_update_apchan_bwcap(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, chanspec_t chanspec
)
26321 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
26322 struct wireless_dev
*wdev
= ndev_to_wdev(dev
);
26323 struct wiphy
*wiphy
= wdev
->wiphy
;
26327 chanspec_t chanbw
= WL_CHANSPEC_BW_20
;
26329 /* Update channel in profile */
26330 ctl_chan
= wf_chspec_ctlchan(chanspec
);
26331 wl_update_prof(cfg
, ndev
, NULL
, &chanspec
, WL_PROF_CHAN
);
26333 /* BW cap is only updated in 5GHz */
26334 if (ctl_chan
<= CH_MAX_2G_CHANNEL
)
26337 /* Get WL BW CAP */
26338 ret
= wl_get_bandwidth_cap(bcmcfg_to_prmry_ndev(cfg
),
26339 CHSPEC_BAND(chanspec
), &bw_cap
);
26341 WL_ERR(("get bw_cap failed = %d\n", ret
));
26345 chanbw
= CHSPEC_BW(wl_channel_to_chanspec(wiphy
,
26346 ndev
, wf_chspec_ctlchan(chanspec
), bw_cap
));
26349 cfg
->bw_cap_5g
= bw2cap
[chanbw
>> WL_CHANSPEC_BW_SHIFT
];
26350 WL_INFORM_MEM(("supported bw cap is:0x%x\n", cfg
->bw_cap_5g
));
26355 wl_rxchain_to_opmode_nss(int rxchain
)
26358 * Nss 1 -> 0, Nss 2 -> 1
26359 * This is from operating mode field
26360 * in 8.4.1.50 of 802.11ac-2013
26362 /* TODO : Nss 3 ? */
26370 wl_update_opmode(struct net_device
*ndev
, u32 bw
)
26376 ret
= wldev_iovar_getint(ndev
, "rxchain", (s32
*)&rxchain
);
26378 WL_ERR(("get rxchain failed = %d\n", ret
));
26383 oper_mode
|= wl_rxchain_to_opmode_nss(rxchain
);
26385 oper_mode
|= OPER_MODE_ENABLE
;
26387 ret
= wldev_iovar_setint(ndev
, "oper_mode", oper_mode
);
26389 WL_ERR(("set oper_mode failed = %d\n", ret
));
26398 wl_set_ap_bw(struct net_device
*dev
, u32 bw
, char *ifname
)
26400 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
26402 struct net_device
*ndev
= NULL
;
26404 chanspec_t
*chanspec
;
26407 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
26413 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
26414 WL_ERR(("Not Hostapd mode\n"));
26418 ndev
= wl_get_ap_netdev(cfg
, ifname
);
26420 if (ndev
== NULL
) {
26421 WL_ERR(("No softAP interface named %s\n", ifname
));
26425 if (bw
> DOT11_OPER_MODE_160MHZ
) {
26426 WL_ERR(("BW is too big %d\n", bw
));
26427 return BCME_BADARG
;
26430 chanspec
= (chanspec_t
*)wl_read_prof(cfg
, ndev
, WL_PROF_CHAN
);
26431 if (CHSPEC_IS2G(*chanspec
)) {
26432 WL_ERR(("current chanspec is %d, not supported\n", *chanspec
));
26433 ret
= BCME_BADCHAN
;
26437 if ((DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp
) &&
26438 wl_get_drv_status(cfg
, CONNECTED
, bcmcfg_to_prmry_ndev(cfg
))) ||
26439 wl_cfgnan_is_enabled(cfg
)) {
26440 WL_ERR(("BW control in concurrent mode is not supported\n"));
26444 /* When SCAN is on going either in STA or in AP, return BUSY */
26445 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
26446 WL_ERR(("STA is SCANNING, not support BW control\n"));
26450 /* When SCANABORT is on going either in STA or in AP, return BUSY */
26451 if (wl_get_drv_status_all(cfg
, SCAN_ABORTING
)) {
26452 WL_ERR(("STA is SCAN_ABORTING, not support BW control\n"));
26456 /* When CONNECTION is on going in STA, return BUSY */
26457 if (wl_get_drv_status(cfg
, CONNECTING
, bcmcfg_to_prmry_ndev(cfg
))) {
26458 WL_ERR(("STA is CONNECTING, not support BW control\n"));
26462 /* BW control in AX mode needs more verification */
26463 ret
= wl_get_ap_he_mode(ndev
, cfg
, &he
);
26464 if (ret
== BCME_OK
&& he
) {
26465 WL_ERR(("BW control in HE mode is not supported\n"));
26466 return BCME_UNSUPPORTED
;
26469 WL_ERR(("Check AX mode is failed\n"));
26473 if ((!WL_BW_CAP_160MHZ(cfg
->bw_cap_5g
) && (bw
== DOT11_OPER_MODE_160MHZ
)) ||
26474 (!WL_BW_CAP_80MHZ(cfg
->bw_cap_5g
) && (bw
>= DOT11_OPER_MODE_80MHZ
)) ||
26475 (!WL_BW_CAP_40MHZ(cfg
->bw_cap_5g
) && (bw
>= DOT11_OPER_MODE_40MHZ
)) ||
26476 (!WL_BW_CAP_20MHZ(cfg
->bw_cap_5g
))) {
26477 WL_ERR(("bw_cap %x does not support bw = %d\n", cfg
->bw_cap_5g
, bw
));
26482 WL_DBG(("Updating AP BW to %d\n", op2bw
[bw
]));
26484 ret
= wl_update_opmode(ndev
, bw
);
26486 WL_ERR(("opmode set failed = %d\n", ret
));
26495 wl_get_ap_bw(struct net_device
*dev
, char* command
, char *ifname
, int total_len
)
26497 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
26499 struct net_device
*ndev
= NULL
;
26502 u32 bw
= DOT11_OPER_MODE_20MHZ
;
26503 int bytes_written
= 0;
26505 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
26511 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
26512 WL_ERR(("Not Hostapd mode\n"));
26516 ndev
= wl_get_ap_netdev(cfg
, ifname
);
26518 if (ndev
== NULL
) {
26519 WL_ERR(("No softAP interface named %s\n", ifname
));
26523 ret
= wldev_iovar_getint(ndev
, "chanspec", (s32
*)&chanspec
);
26525 WL_ERR(("get chanspec from AP failed = %d\n", ret
));
26529 chanspec
= wl_chspec_driver_to_host(chanspec
);
26531 if (CHSPEC_IS20(chanspec
)) {
26532 bw
= DOT11_OPER_MODE_20MHZ
;
26533 } else if (CHSPEC_IS40(chanspec
)) {
26534 bw
= DOT11_OPER_MODE_40MHZ
;
26535 } else if (CHSPEC_IS80(chanspec
)) {
26536 bw
= DOT11_OPER_MODE_80MHZ
;
26537 } else if (CHSPEC_IS_BW_160_WIDE(chanspec
)) {
26538 bw
= DOT11_OPER_MODE_160MHZ
;
26540 WL_ERR(("chanspec error %x\n", chanspec
));
26541 ret
= BCME_BADCHAN
;
26545 bytes_written
+= snprintf(command
+ bytes_written
, total_len
,
26547 ret
= bytes_written
;
26553 wl_restore_ap_bw(struct bcm_cfg80211
*cfg
)
26558 struct net_info
*iter
, *next
;
26559 struct net_device
*ndev
= NULL
;
26560 chanspec_t
*chanspec
;
26566 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
26567 for_each_ndev(cfg
, iter
, next
) {
26568 GCC_DIAGNOSTIC_POP();
26570 if (iter
->ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
26571 chanspec
= (chanspec_t
*)wl_read_prof(cfg
, iter
->ndev
,
26573 if (CHSPEC_IS2G(*chanspec
)) {
26585 /* BW control in AX mode not allowed */
26586 ret
= wl_get_ap_he_mode(bcmcfg_to_prmry_ndev(cfg
), cfg
, &he
);
26587 if (ret
== BCME_OK
&& he
) {
26591 WL_ERR(("Check AX mode is failed\n"));
26595 if (WL_BW_CAP_160MHZ(cfg
->bw_cap_5g
)) {
26596 bw
= DOT11_OPER_MODE_160MHZ
;
26597 } else if (WL_BW_CAP_80MHZ(cfg
->bw_cap_5g
)) {
26598 bw
= DOT11_OPER_MODE_80MHZ
;
26599 } else if (WL_BW_CAP_40MHZ(cfg
->bw_cap_5g
)) {
26600 bw
= DOT11_OPER_MODE_40MHZ
;
26605 WL_DBG(("Restoring AP BW to %d\n", op2bw
[bw
]));
26607 ret
= wl_update_opmode(ndev
, bw
);
26609 WL_ERR(("bw restore failed = %d\n", ret
));
26613 #endif /* SUPPORT_AP_BWCTRL */
26615 bool wl_cfg80211_is_dpp_frame(void *frame
, u32 frame_len
)
26617 /* check for DPP public action frames */
26618 wl_dpp_pa_frame_t
*pact_frm
;
26620 if (frame
== NULL
) {
26623 pact_frm
= (wl_dpp_pa_frame_t
*)frame
;
26624 if (frame_len
< sizeof(wl_dpp_pa_frame_t
) -1) {
26628 if ((pact_frm
->category
== WL_PUB_AF_CATEGORY
) &&
26629 (pact_frm
->action
== WL_PUB_AF_ACTION
) &&
26630 (pact_frm
->oui_type
== WL_PUB_AF_WFA_STYPE_DPP
) &&
26631 (memcmp(pact_frm
->oui
, WFA_OUI
, sizeof(pact_frm
->oui
)) == 0)) {
26639 get_dpp_pa_ftype(enum wl_dpp_ftype ftype
)
26643 return "DPP_AUTH_REQ";
26644 case DPP_AUTH_RESP
:
26645 return "DPP_AUTH_RESP";
26646 case DPP_AUTH_CONF
:
26647 return "DPP_AUTH_CONF";
26649 return "Unkown DPP frame";
26653 #define GAS_RESP_LEN 2
26654 #define DOUBLE_TLV_BODY_OFF 4
26655 bool wl_cfg80211_find_gas_subtype(u8 subtype
, u16 adv_id
, u8
* data
, u32 len
)
26657 const bcm_tlv_t
*ie
= (bcm_tlv_t
*)data
;
26658 const u8
*frame
= NULL
;
26661 /* Skipped first ANQP Element, if frame has anqp elemnt */
26662 ie
= bcm_parse_tlvs(ie
, len
, DOT11_MNG_ADVERTISEMENT_ID
);
26667 frame
= (const uint8
*)ie
+ ie
->len
+ TLV_HDR_LEN
+ GAS_RESP_LEN
;
26668 id
= ((u16
) (((frame
)[1] << 8) | (frame
)[0]));
26669 flen
= ((u16
) (((frame
)[3] << 8) | (frame
)[2]));
26671 /* If the contents match the OUI and the type */
26672 if ((flen
>= WFA_OUI_LEN
+ 1) &&
26674 !bcmp(&frame
[DOUBLE_TLV_BODY_OFF
], (const uint8
*)WFA_OUI
, WFA_OUI_LEN
) &&
26675 subtype
== frame
[DOUBLE_TLV_BODY_OFF
+WFA_OUI_LEN
]) {
26682 bool wl_cfg80211_is_dpp_gas_action(void *frame
, u32 frame_len
)
26684 wl_dpp_gas_af_t
*act_frm
= (wl_dpp_gas_af_t
*)frame
;
26686 const bcm_tlv_t
*ie
= NULL
;
26688 if ((frame_len
< (sizeof(wl_dpp_gas_af_t
) - 1)) ||
26689 act_frm
->category
!= WL_PUB_AF_CATEGORY
) {
26693 len
= frame_len
- (u32
)(sizeof(wl_dpp_gas_af_t
) - 1);
26694 if (act_frm
->action
== WL_PUB_AF_GAS_IREQ
) {
26695 ie
= (bcm_tlv_t
*)act_frm
->query_data
;
26696 /* We are interested only in MNG ADV ID. Skip any other id. */
26697 ie
= bcm_parse_tlvs(ie
, len
, DOT11_MNG_ADVERTISEMENT_ID
);
26698 } else if (act_frm
->action
== WL_PUB_AF_GAS_IRESP
) {
26699 ie
= (bcm_tlv_t
*)&act_frm
->query_data
[WL_GAS_RESP_OFFSET
];
26700 /* We are interested only in MNG ADV ID. Skip any other id. */
26701 ie
= bcm_parse_tlvs(ie
, len
, DOT11_MNG_ADVERTISEMENT_ID
);
26706 if (ie
&& (ie
->len
>= WL_GAS_MIN_LEN
) &&
26707 (memcmp(&ie
->data
[WL_GAS_WFA_OFFSET
], WFA_OUI
, 3) == 0) &&
26708 (ie
->data
[WL_GAS_STYPE_OFFSET
] == WL_GAS_WFA_STYPE_DPP
)) {
26709 WL_DBG(("DPP GAS FRAME. type:%d\n", act_frm
->action
));
26713 /* Non DPP GAS frame */
26718 #define KA_TEMP_BUF_SIZE 512
26719 #define KA_FRAME_SIZE 300
26721 wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211
*cfg
, uint8 mkeep_alive_id
,
26722 uint16 ether_type
, uint8
*ip_pkt
, uint16 ip_pkt_len
,
26723 uint8
* src_mac
, uint8
* dst_mac
, uint32 period_msec
)
26725 const int ETHERTYPE_LEN
= 2;
26728 wl_mkeep_alive_pkt_t mkeep_alive_pkt
;
26729 wl_mkeep_alive_pkt_t
*mkeep_alive_pktp
= NULL
;
26730 uint16 buf_len
= 0;
26732 int res
= BCME_ERROR
;
26733 uint16 len_bytes
= 0;
26735 uint16 pmac_frame_len
= KA_FRAME_SIZE
;
26736 uint16 pbuf_len
= KA_TEMP_BUF_SIZE
;
26738 /* ether frame to have both max IP pkt (256 bytes) and ether header */
26739 char *pmac_frame
= NULL
;
26740 char *pmac_frame_begin
= NULL
;
26741 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
26742 struct net_device
*primary_ndev
= NULL
;
26743 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
26746 * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
26747 * dongle shall reject a mkeep_alive request.
26749 if (!(dhd
->op_mode
& DHD_FLAG_STA_MODE
))
26752 WL_TRACE(("%s execution\n", __FUNCTION__
));
26754 if ((pbuf
= MALLOCZ(cfg
->osh
, KA_TEMP_BUF_SIZE
)) == NULL
) {
26755 WL_ERR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE
));
26760 if ((pmac_frame
= MALLOCZ(cfg
->osh
, pmac_frame_len
)) == NULL
) {
26761 WL_ERR(("failed to allocate mac_frame with size %d\n", pmac_frame_len
));
26765 pmac_frame_begin
= pmac_frame
;
26768 * Get current mkeep-alive status.
26770 res
= wldev_iovar_getbuf(primary_ndev
, "mkeep_alive", &mkeep_alive_id
,
26771 sizeof(mkeep_alive_id
), pbuf
, KA_TEMP_BUF_SIZE
, &cfg
->ioctl_buf_sync
);
26773 WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__
, res
));
26776 /* Check available ID whether it is occupied */
26777 mkeep_alive_pktp
= (wl_mkeep_alive_pkt_t
*) pbuf
;
26778 if (dtoh32(mkeep_alive_pktp
->period_msec
!= 0)) {
26779 WL_ERR(("%s: Get mkeep_alive failed, ID %u is in use.\n",
26780 __FUNCTION__
, mkeep_alive_id
));
26782 /* Current occupied ID info */
26783 WL_ERR(("%s: mkeep_alive\n", __FUNCTION__
));
26784 WL_ERR((" Id : %d\n"
26785 " Period: %d msec\n"
26788 mkeep_alive_pktp
->keep_alive_id
,
26789 dtoh32(mkeep_alive_pktp
->period_msec
),
26790 dtoh16(mkeep_alive_pktp
->len_bytes
)));
26792 for (i
= 0; i
< mkeep_alive_pktp
->len_bytes
; i
++) {
26793 WL_ERR(("%02x", mkeep_alive_pktp
->data
[i
]));
26797 res
= BCME_NOTFOUND
;
26802 /* Request the specified ID */
26803 bzero(&mkeep_alive_pkt
, sizeof(wl_mkeep_alive_pkt_t
));
26804 bzero(pbuf
, KA_TEMP_BUF_SIZE
);
26805 str
= "mkeep_alive";
26806 str_len
= strlen(str
);
26807 strlcpy(pbuf
, str
, KA_TEMP_BUF_SIZE
);
26808 buf_len
= str_len
+ 1;
26809 pbuf_len
-= buf_len
;
26811 mkeep_alive_pktp
= (wl_mkeep_alive_pkt_t
*) (pbuf
+ buf_len
);
26812 mkeep_alive_pkt
.period_msec
= htod32(period_msec
);
26813 mkeep_alive_pkt
.version
= htod16(WL_MKEEP_ALIVE_VERSION
);
26814 mkeep_alive_pkt
.length
= htod16(WL_MKEEP_ALIVE_FIXED_LEN
);
26815 len_bytes
= (ETHER_ADDR_LEN
*2) + ETHERTYPE_LEN
+ ip_pkt_len
;
26816 mkeep_alive_pkt
.len_bytes
= htod16(len_bytes
);
26819 mkeep_alive_pkt
.keep_alive_id
= mkeep_alive_id
;
26821 buf_len
+= WL_MKEEP_ALIVE_FIXED_LEN
;
26824 * Build up Ethernet Frame
26827 /* Mapping dest mac addr */
26828 res
= memcpy_s(pmac_frame
, pmac_frame_len
, dst_mac
, ETHER_ADDR_LEN
);
26832 pmac_frame
+= ETHER_ADDR_LEN
;
26833 pmac_frame_len
-= ETHER_ADDR_LEN
;
26835 /* Mapping src mac addr */
26836 res
= memcpy_s(pmac_frame
, pmac_frame_len
, src_mac
, ETHER_ADDR_LEN
);
26840 pmac_frame
+= ETHER_ADDR_LEN
;
26841 pmac_frame_len
-= ETHER_ADDR_LEN
;
26843 /* Mapping Ethernet type */
26844 ether_type
= hton16(ether_type
);
26845 res
= memcpy_s(pmac_frame
, pmac_frame_len
, ðer_type
, ETHERTYPE_LEN
);
26849 pmac_frame
+= ETHERTYPE_LEN
;
26850 pmac_frame_len
-= ETHERTYPE_LEN
;
26852 /* Mapping IP pkt */
26853 res
= memcpy_s(pmac_frame
, pmac_frame_len
, ip_pkt
, ip_pkt_len
);
26857 pmac_frame
+= ip_pkt_len
;
26858 pmac_frame_len
-= ip_pkt_len
;
26861 * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
26862 * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
26863 * guarantee that the buffer is properly aligned.
26865 res
= memcpy_s((char *)mkeep_alive_pktp
, pbuf_len
,
26866 &mkeep_alive_pkt
, WL_MKEEP_ALIVE_FIXED_LEN
);
26870 pbuf_len
-= WL_MKEEP_ALIVE_FIXED_LEN
;
26873 * Length of ether frame (assume to be all hexa bytes)
26874 * = src mac + dst mac + ether type + ip pkt len
26876 res
= memcpy_s(mkeep_alive_pktp
->data
, pbuf_len
,
26877 pmac_frame_begin
, len_bytes
);
26881 buf_len
+= len_bytes
;
26883 res
= wldev_ioctl_set(primary_ndev
, WLC_SET_VAR
, pbuf
, buf_len
);
26885 if (pmac_frame_begin
) {
26886 MFREE(cfg
->osh
, pmac_frame_begin
, KA_FRAME_SIZE
);
26889 MFREE(cfg
->osh
, pbuf
, KA_TEMP_BUF_SIZE
);
26895 wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211
*cfg
, uint8 mkeep_alive_id
)
26898 wl_mkeep_alive_pkt_t mkeep_alive_pkt
;
26899 wl_mkeep_alive_pkt_t
*mkeep_alive_pktp
= NULL
;
26900 int res
= BCME_ERROR
;
26902 struct net_device
*primary_ndev
= NULL
;
26903 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
26904 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
26907 * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
26908 * dongle shall reject a mkeep_alive request.
26910 if (!(dhd
->op_mode
& DHD_FLAG_STA_MODE
))
26913 WL_TRACE(("%s execution\n", __FUNCTION__
));
26916 * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt.
26918 if ((pbuf
= MALLOCZ(cfg
->osh
, KA_TEMP_BUF_SIZE
)) == NULL
) {
26919 WL_ERR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE
));
26924 res
= wldev_iovar_getbuf(primary_ndev
, "mkeep_alive", &mkeep_alive_id
,
26925 sizeof(mkeep_alive_id
), pbuf
, KA_TEMP_BUF_SIZE
, &cfg
->ioctl_buf_sync
);
26927 WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__
, res
));
26930 /* Check occupied ID */
26931 mkeep_alive_pktp
= (wl_mkeep_alive_pkt_t
*) pbuf
;
26932 WL_DBG(("%s: mkeep_alive\n", __FUNCTION__
));
26933 WL_DBG((" Id : %d\n"
26934 " Period: %d msec\n"
26937 mkeep_alive_pktp
->keep_alive_id
,
26938 dtoh32(mkeep_alive_pktp
->period_msec
),
26939 dtoh16(mkeep_alive_pktp
->len_bytes
)));
26941 for (i
= 0; i
< mkeep_alive_pktp
->len_bytes
; i
++) {
26942 WL_DBG(("%02x", mkeep_alive_pktp
->data
[i
]));
26947 /* Make it stop if available */
26948 if (dtoh32(mkeep_alive_pktp
->period_msec
!= 0)) {
26949 WL_INFORM_MEM(("stop mkeep_alive on ID %d\n", mkeep_alive_id
));
26950 bzero(&mkeep_alive_pkt
, sizeof(wl_mkeep_alive_pkt_t
));
26952 mkeep_alive_pkt
.period_msec
= 0;
26953 mkeep_alive_pkt
.version
= htod16(WL_MKEEP_ALIVE_VERSION
);
26954 mkeep_alive_pkt
.length
= htod16(WL_MKEEP_ALIVE_FIXED_LEN
);
26955 mkeep_alive_pkt
.keep_alive_id
= mkeep_alive_id
;
26957 res
= wldev_iovar_setbuf(primary_ndev
, "mkeep_alive",
26958 (char *)&mkeep_alive_pkt
, WL_MKEEP_ALIVE_FIXED_LEN
,
26959 pbuf
, KA_TEMP_BUF_SIZE
, &cfg
->ioctl_buf_sync
);
26961 WL_ERR(("%s: ID %u does not exist.\n", __FUNCTION__
, mkeep_alive_id
));
26962 res
= BCME_NOTFOUND
;
26966 MFREE(cfg
->osh
, pbuf
, KA_TEMP_BUF_SIZE
);
26970 #endif /* KEEP_ALIVE */
26973 wl_cfg80211_handle_macaddr_change(struct net_device
*dev
, u8
*macaddr
)
26975 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
26976 uint8 wait_cnt
= WAIT_FOR_DISCONNECT_MAX
;
26979 if (IS_STA_IFACE(dev
->ieee80211_ptr
) &&
26980 wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
26981 /* Macaddress change in connected state. The curent
26982 * connection will become invalid. Issue disconnect
26983 * to current AP to let the AP know about link down
26985 WL_INFORM_MEM(("macaddr change in connected state. Force disassoc.\n"));
26986 wl_cfg80211_disassoc(dev
, WLAN_REASON_DEAUTH_LEAVING
);
26988 while ((status
= wl_get_drv_status(cfg
, CONNECTED
, dev
)) && wait_cnt
) {
26989 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt
));
26998 wl_cfg80211_handle_hang_event(struct net_device
*ndev
, uint16 hang_reason
, uint32 memdump_type
)
27000 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
27001 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
27003 WL_INFORM_MEM(("hang reason = %d, memdump_type =%d\n",
27004 hang_reason
, memdump_type
));
27006 /* check if pre-registered mac matches the mac from dongle via WLC_E_LINK */
27007 if (wl_get_drv_status(cfg
, READY
, ndev
)) {
27008 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
27009 wl_copy_hang_info_if_falure(ndev
,
27010 hang_reason
, BCME_NOTFOUND
);
27011 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
27012 SUPP_LOG(("Err. hang reason:%d, dump_type:%d\n", hang_reason
, memdump_type
));
27013 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
27014 /* IF dongle is down due to previous hang or other conditions,
27015 * sending 0ne more hang notification is not needed.
27018 if (dhd_query_bus_erros(dhd
)) {
27021 dhd
->iface_op_failed
= TRUE
;
27022 #if defined(DHD_FW_COREDUMP)
27023 if (dhd
->memdump_enabled
) {
27024 dhd
->memdump_type
= memdump_type
;
27025 dhd_bus_mem_dump(dhd
);
27027 #endif /* DHD_FW_COREDUMP */
27028 WL_ERR(("Notify hang event to upper layer \n"));
27029 dhd
->hang_reason
= hang_reason
;
27030 net_os_send_hang_message(ndev
);
27037 wl_cfg80211_autochannel(struct net_device
*dev
, char* command
, int total_len
)
27039 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
27041 int bytes_written
= -1;
27043 sscanf(command
, "%*s %d", &cfg
->autochannel
);
27045 if (cfg
->autochannel
== 0) {
27046 cfg
->best_2g_ch
= 0;
27047 cfg
->best_5g_ch
= 0;
27048 } else if (cfg
->autochannel
== 2) {
27049 bytes_written
= snprintf(command
, total_len
, "2g=%d 5g=%d",
27050 cfg
->best_2g_ch
, cfg
->best_5g_ch
);
27051 WL_TRACE(("%s: command result is %s\n", __FUNCTION__
, command
));
27052 ret
= bytes_written
;
27059 wl_cfg80211_check_in4way(struct bcm_cfg80211
*cfg
,
27060 struct net_device
*dev
, uint action
, enum wl_ext_status status
, void *context
)
27062 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
27063 struct wl_security
*sec
;
27065 int ret
= 0, cur_eapol_status
, ifidx
;
27066 int max_wait_time
, max_wait_cnt
;
27067 int suppressed
= 0;
27069 mutex_lock(&cfg
->in4way_sync
);
27070 action
= action
& dhdp
->conf
->in4way
;
27071 WL_DBG(("status=%d, action=0x%x, in4way=0x%x\n", status
, action
, dhdp
->conf
->in4way
));
27073 cur_eapol_status
= dhdp
->conf
->eapol_status
;
27075 case WL_EXT_STATUS_SCAN
:
27076 wldev_ioctl(dev
, WLC_GET_SCANSUPPRESS
, &suppressed
, sizeof(int), false);
27078 WL_ERR(("scan suppressed\n"));
27082 if (action
& NO_SCAN_IN4WAY
) {
27083 if (cfg
->handshaking
> 0 && cfg
->handshaking
<= 3) {
27084 WL_ERR(("return -EBUSY cnt %d\n", cfg
->handshaking
));
27085 cfg
->handshaking
++;
27091 case WL_EXT_STATUS_DISCONNECTING
:
27092 if (cur_eapol_status
>= EAPOL_STATUS_4WAY_START
&&
27093 cur_eapol_status
< EAPOL_STATUS_4WAY_DONE
) {
27094 WL_ERR(("WPA failed at %d\n", cur_eapol_status
));
27095 dhdp
->conf
->eapol_status
= EAPOL_STATUS_NONE
;
27096 } else if (cur_eapol_status
>= EAPOL_STATUS_WSC_START
&&
27097 cur_eapol_status
< EAPOL_STATUS_WSC_DONE
) {
27098 WL_ERR(("WPS failed at %d\n", cur_eapol_status
));
27099 dhdp
->conf
->eapol_status
= EAPOL_STATUS_NONE
;
27101 if (action
& (NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
)) {
27102 if (cfg
->handshaking
) {
27103 if ((action
& NO_BTC_IN4WAY
) && cfg
->btc_mode
) {
27104 WL_TRACE(("status=%d, restore btc_mode %d\n",
27105 status
, cfg
->btc_mode
));
27106 wldev_iovar_setint(dev
, "btc_mode", cfg
->btc_mode
);
27108 cfg
->handshaking
= 0;
27111 if (action
& WAIT_DISCONNECTED
) {
27112 max_wait_time
= 200;
27114 cfg
->disconnected_jiffies
= jiffies
;
27115 while (!time_after(jiffies
,
27116 cfg
->disconnected_jiffies
+ msecs_to_jiffies(max_wait_time
)) &&
27118 WL_TRACE(("status=%d, max_wait_cnt=%d waiting...\n",
27119 status
, max_wait_cnt
));
27120 mutex_unlock(&cfg
->in4way_sync
);
27122 mutex_lock(&cfg
->in4way_sync
);
27125 wake_up_interruptible(&dhdp
->conf
->event_complete
);
27128 case WL_EXT_STATUS_CONNECTING
:
27129 if (action
& (NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
)) {
27130 bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
);
27131 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
27132 if ((sec
->wpa_versions
& (NL80211_WPA_VERSION_1
| NL80211_WPA_VERSION_2
)) &&
27134 dhdp
->conf
->eapol_status
= EAPOL_STATUS_4WAY_START
;
27135 cfg
->handshaking
= 1;
27136 if (action
& NO_BTC_IN4WAY
) {
27137 ret
= wldev_iovar_getint(dev
, "btc_mode", &cfg
->btc_mode
);
27138 if (!ret
&& cfg
->btc_mode
) {
27139 WL_TRACE(("status=%d, disable current btc_mode %d\n",
27140 status
, cfg
->btc_mode
));
27141 wldev_iovar_setint(dev
, "btc_mode", 0);
27146 if (action
& WAIT_DISCONNECTED
) {
27147 max_wait_time
= 200;
27149 while (!time_after(jiffies
,
27150 cfg
->disconnected_jiffies
+ msecs_to_jiffies(max_wait_time
)) &&
27152 WL_TRACE(("status=%d, max_wait_cnt=%d waiting...\n",
27153 status
, max_wait_cnt
));
27154 mutex_unlock(&cfg
->in4way_sync
);
27156 mutex_lock(&cfg
->in4way_sync
);
27159 wake_up_interruptible(&dhdp
->conf
->event_complete
);
27162 case WL_EXT_STATUS_CONNECTED
:
27163 ifidx
= dhd_net2idx(dhdp
->info
, dev
);
27164 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
&& ifidx
>= 0) {
27165 dhd_conf_set_wme(cfg
->pub
, ifidx
, 0);
27166 wake_up_interruptible(&dhdp
->conf
->event_complete
);
27168 else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_CLIENT
) {
27169 dhd_conf_set_mchan_bw(cfg
->pub
, WL_P2P_IF_CLIENT
, -1);
27172 case WL_EXT_STATUS_DISCONNECTED
:
27173 if (cur_eapol_status
>= EAPOL_STATUS_4WAY_START
&&
27174 cur_eapol_status
< EAPOL_STATUS_4WAY_DONE
) {
27175 WL_ERR(("WPA failed at %d\n", cur_eapol_status
));
27176 dhdp
->conf
->eapol_status
= EAPOL_STATUS_NONE
;
27177 } else if (cur_eapol_status
>= EAPOL_STATUS_WSC_START
&&
27178 cur_eapol_status
< EAPOL_STATUS_WSC_DONE
) {
27179 WL_ERR(("WPS failed at %d\n", cur_eapol_status
));
27180 dhdp
->conf
->eapol_status
= EAPOL_STATUS_NONE
;
27182 if (action
& (NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
)) {
27183 if (cfg
->handshaking
) {
27184 if ((action
& NO_BTC_IN4WAY
) && cfg
->btc_mode
) {
27185 WL_TRACE(("status=%d, restore btc_mode %d\n",
27186 status
, cfg
->btc_mode
));
27187 wldev_iovar_setint(dev
, "btc_mode", cfg
->btc_mode
);
27189 cfg
->handshaking
= 0;
27192 if (action
& WAIT_DISCONNECTED
) {
27193 cfg
->disconnected_jiffies
= jiffies
;
27195 wake_up_interruptible(&dhdp
->conf
->event_complete
);
27197 case WL_EXT_STATUS_ADD_KEY
:
27198 dhdp
->conf
->eapol_status
= EAPOL_STATUS_4WAY_DONE
;
27199 if (action
& (NO_SCAN_IN4WAY
|NO_BTC_IN4WAY
)) {
27200 if (cfg
->handshaking
) {
27201 if ((action
& NO_BTC_IN4WAY
) && cfg
->btc_mode
) {
27202 WL_TRACE(("status=%d, restore btc_mode %d\n",
27203 status
, cfg
->btc_mode
));
27204 wldev_iovar_setint(dev
, "btc_mode", cfg
->btc_mode
);
27206 cfg
->handshaking
= 0;
27209 wake_up_interruptible(&dhdp
->conf
->event_complete
);
27211 case WL_EXT_STATUS_AP_ENABLED
:
27212 ifidx
= dhd_net2idx(dhdp
->info
, dev
);
27213 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
&& ifidx
>= 0) {
27214 dhd_conf_set_wme(cfg
->pub
, ifidx
, 1);
27216 else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
27217 dhd_conf_set_mchan_bw(cfg
->pub
, WL_P2P_IF_GO
, -1);
27220 case WL_EXT_STATUS_DELETE_STA
:
27221 if ((action
& DONT_DELETE_GC_AFTER_WPS
) &&
27222 (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
)) {
27223 u8
* mac_addr
= context
;
27224 if (mac_addr
&& memcmp(ðer_bcast
, mac_addr
, ETHER_ADDR_LEN
) &&
27225 cur_eapol_status
== EAPOL_STATUS_WSC_DONE
) {
27227 max_wait_time
= 300;
27228 WL_TRACE(("status=%d, wps_done=%d, waiting %dms ...\n",
27229 status
, cfg
->wps_done
, max_wait_time
));
27230 mutex_unlock(&cfg
->in4way_sync
);
27231 timeout
= wait_event_interruptible_timeout(cfg
->wps_done_event
,
27232 cfg
->wps_done
, msecs_to_jiffies(max_wait_time
));
27233 mutex_lock(&cfg
->in4way_sync
);
27234 WL_TRACE(("status=%d, wps_done=%d, timeout=%d\n",
27235 status
, cfg
->wps_done
, timeout
));
27241 WL_TRACE(("status=%d, wps_done=%d => 0\n", status
, cfg
->wps_done
));
27242 cfg
->wps_done
= FALSE
;
27243 dhdp
->conf
->eapol_status
= EAPOL_STATUS_NONE
;
27247 case WL_EXT_STATUS_STA_DISCONNECTED
:
27248 if ((action
& DONT_DELETE_GC_AFTER_WPS
) &&
27249 (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) &&
27250 cur_eapol_status
== EAPOL_STATUS_WSC_DONE
) {
27251 WL_TRACE(("status=%d, wps_done=%d => 0\n", status
, cfg
->wps_done
));
27252 cfg
->wps_done
= FALSE
;
27255 case WL_EXT_STATUS_STA_CONNECTED
:
27256 if ((action
& DONT_DELETE_GC_AFTER_WPS
) &&
27257 (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) &&
27258 cur_eapol_status
== EAPOL_STATUS_WSC_DONE
) {
27259 WL_TRACE(("status=%d, wps_done=%d => 1\n", status
, cfg
->wps_done
));
27260 cfg
->wps_done
= TRUE
;
27261 wake_up_interruptible(&cfg
->wps_done_event
);
27265 WL_ERR(("Unknown action=0x%x, status=%d\n", action
, status
));
27268 mutex_unlock(&cfg
->in4way_sync
);