2 * Linux cfg80211 driver
4 * Copyright (C) 1999-2019, 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.
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
25 * <<Broadcom-WL-IPTag/Open:>>
27 * $Id: wl_cfg80211.c 820080 2019-05-16 03:05:46Z $
32 #include <linux/kernel.h>
34 #include <wlc_types.h>
36 #include <bcmwifi_channels.h>
37 #include <bcmendian.h>
41 #endif /* WL_WPS_SYNC */
47 #include <linux/if_arp.h>
48 #include <asm/uaccess.h>
51 #include <linux/kernel.h>
52 #include <linux/kthread.h>
53 #include <linux/netdevice.h>
54 #include <linux/sched.h>
55 #include <linux/etherdevice.h>
56 #include <linux/wireless.h>
57 #include <linux/ieee80211.h>
58 #include <linux/wait.h>
59 #include <net/cfg80211.h>
60 #include <net/rtnetlink.h>
63 #include <wldev_common.h>
64 #include <wl_cfg80211.h>
65 #include <wl_cfgp2p.h>
67 #include <wl_android.h>
68 #include <dngl_stats.h>
70 #include <dhd_linux.h>
71 #include <dhd_debug.h>
74 #include <dhd_cfg80211.h>
78 #endif /* PNO_SUPPORT */
79 #include <wl_cfgvendor.h>
82 #include <wl_cfgnan.h>
90 #include <dhd_flowring.h>
94 #endif /* RTT_SUPPORT */
97 #include <wl_bigdata.h>
98 #endif /* BIGDATA_SOFTAP */
100 #ifdef DHD_EVENT_LOG_FILTER
101 #include <dhd_event_log_filter.h>
102 #endif /* DHD_EVENT_LOG_FILTER */
105 /* these items should evetually go into wireless.h of the linux system headfile dir */
106 #ifndef IW_ENCODE_ALG_SM4
107 #define IW_ENCODE_ALG_SM4 0x20
110 #ifndef IW_AUTH_WAPI_ENABLED
111 #define IW_AUTH_WAPI_ENABLED 0x20
114 #ifndef IW_AUTH_WAPI_VERSION_1
115 #define IW_AUTH_WAPI_VERSION_1 0x00000008
118 #ifndef IW_AUTH_CIPHER_SMS4
119 #define IW_AUTH_CIPHER_SMS4 0x00000020
122 #ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
123 #define IW_AUTH_KEY_MGMT_WAPI_PSK 4
126 #ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
127 #define IW_AUTH_KEY_MGMT_WAPI_CERT 8
129 #endif /* BCMWAPI_WPI */
132 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
133 #else /* BCMWAPI_WPI */
134 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
135 #endif /* BCMWAPI_WPI */
137 static struct device
*cfg80211_parent_dev
= NULL
;
138 static struct bcm_cfg80211
*g_bcmcfg
= NULL
;
139 u32 wl_dbg_level
= WL_DBG_ERR
| WL_DBG_P2P_ACTION
| WL_DBG_INFO
;
141 #define MAX_VIF_OFFSET 15
142 #define MAX_WAIT_TIME 1500
144 #define IBSS_IF_NAME "ibss%d"
145 #endif /* WLAIBSS_MCHAN */
148 /* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
149 #define DEFAULT_SLEEP_TIME_VSDB 120
150 #define OFF_CHAN_TIME_THRESHOLD_MS 200
151 #define AF_RETRY_DELAY_TIME 40
153 /* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
154 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
156 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
157 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
158 OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
162 /* if not VSDB, do nothing */
163 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
166 #define DNGL_FUNC(func, parameters) func parameters
169 #define WLAN_EID_SSID 0
170 #define CH_MIN_5G_CHANNEL 34
171 #define CH_MIN_2G_CHANNEL 1
172 #define ACTIVE_SCAN 1
173 #define PASSIVE_SCAN 0
175 enum abiss_event_type
{
180 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
181 4 && __GNUC_MINOR__ >= 6))
182 #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
183 _Pragma("GCC diagnostic push") \
184 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
185 (entry) = list_first_entry((ptr), type, member); \
186 _Pragma("GCC diagnostic pop") \
188 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
189 _Pragma("GCC diagnostic push") \
190 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
191 entry = container_of((ptr), type, member); \
192 _Pragma("GCC diagnostic pop") \
195 #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
196 (entry) = list_first_entry((ptr), type, member); \
198 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
199 entry = container_of((ptr), type, member); \
201 #endif /* STRICT_GCC_WARNINGS */
204 enum rmc_event_type
{
206 RMC_EVENT_LEADER_CHECK_FAIL
208 #endif /* WL_RELMCAST */
211 typedef struct wl_last_event
{
212 uint32 current_time
; /* current tyime */
213 uint32 timestamp
; /* event timestamp */
214 wl_event_msg_t event
; /* Encapsulated event */
216 #endif /* WL_LASTEVT */
218 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
219 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
220 * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
221 * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
222 * All the chnages in world regulatory domain are to be done here.
224 * this definition reuires disabling missing-field-initializer warning
225 * as the ieee80211_regdomain definition differs in plain linux and in Android
227 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
228 4 && __GNUC_MINOR__ >= 6))
229 _Pragma("GCC diagnostic push")
230 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
232 static const struct ieee80211_regdomain brcm_regdom
= {
236 /* IEEE 802.11b/g, channels 1..11 */
237 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
239 /* IEEE 802.11 channel 14 - Only JP enables
240 * this and for 802.11b only
242 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
243 /* IEEE 802.11a, channel 36..64 */
244 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
245 /* IEEE 802.11a, channel 100..165 */
246 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
248 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
249 4 && __GNUC_MINOR__ >= 6))
250 _Pragma("GCC diagnostic pop")
253 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
254 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
255 static const struct ieee80211_iface_limit common_if_limits
[] = {
258 * Driver can support up to 2 AP's
261 .types
= BIT(NL80211_IFTYPE_AP
),
265 * During P2P-GO removal, P2P-GO is first changed to STA and later only
266 * removed. So setting maximum possible number of STA interfaces according
269 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
270 * linux-3.8 and above - max:4
271 * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
272 * for NAN defined, registering it as STA type)
274 #ifdef WL_ENABLE_P2P_IF
278 #endif /* WL_ENABLE_P2P_IF */
279 .types
= BIT(NL80211_IFTYPE_STATION
),
283 .types
= BIT(NL80211_IFTYPE_P2P_GO
) | BIT(NL80211_IFTYPE_P2P_CLIENT
),
285 #if defined(WL_CFG80211_P2P_DEV_IF)
288 .types
= BIT(NL80211_IFTYPE_P2P_DEVICE
),
290 #endif /* WL_CFG80211_P2P_DEV_IF */
293 .types
= BIT(NL80211_IFTYPE_ADHOC
),
297 #define NUM_DIFF_CHANNELS 2
299 static const struct ieee80211_iface_combination
300 common_iface_combinations
[] = {
302 .num_different_channels
= NUM_DIFF_CHANNELS
,
305 * The max no of interfaces will be used in dual p2p case.
306 * {STA, P2P Device, P2P Group 1, P2P Group 2}. Though we
307 * will not be using the STA functionality in this case, it
308 * will remain registered as it is the primary interface.
311 .limits
= common_if_limits
,
312 .n_limits
= ARRAY_SIZE(common_if_limits
),
315 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
317 static const char *wl_if_state_strs
[WL_IF_STATE_MAX
+ 1] = {
328 #if defined(ANDROID_PLATFORM_VERSION) && (ANDROID_PLATFORM_VERSION >= 8)
329 /* WAPI define in ieee80211.h is used */
331 #undef WLAN_AKM_SUITE_WAPI_PSK
332 #define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04
334 #undef WLAN_AKM_SUITE_WAPI_CERT
335 #define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12
337 #undef NL80211_WAPI_VERSION_1
338 #define NL80211_WAPI_VERSION_1 1 << 2
339 #endif /* ANDROID_PLATFORM_VERSION && ANDROID_PLATFORM_VERSION >= 8 */
340 #endif /* BCMWAPI_WPI */
342 /* Data Element Definitions */
343 #define WPS_ID_CONFIG_METHODS 0x1008
344 #define WPS_ID_REQ_TYPE 0x103A
345 #define WPS_ID_DEVICE_NAME 0x1011
346 #define WPS_ID_VERSION 0x104A
347 #define WPS_ID_DEVICE_PWD_ID 0x1012
348 #define WPS_ID_REQ_DEV_TYPE 0x106A
349 #define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
350 #define WPS_ID_PRIM_DEV_TYPE 0x1054
352 /* Device Password ID */
353 #define DEV_PW_DEFAULT 0x0000
354 #define DEV_PW_USER_SPECIFIED 0x0001,
355 #define DEV_PW_MACHINE_SPECIFIED 0x0002
356 #define DEV_PW_REKEY 0x0003
357 #define DEV_PW_PUSHBUTTON 0x0004
358 #define DEV_PW_REGISTRAR_SPECIFIED 0x0005
361 #define WPS_CONFIG_USBA 0x0001
362 #define WPS_CONFIG_ETHERNET 0x0002
363 #define WPS_CONFIG_LABEL 0x0004
364 #define WPS_CONFIG_DISPLAY 0x0008
365 #define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
366 #define WPS_CONFIG_INT_NFC_TOKEN 0x0020
367 #define WPS_CONFIG_NFC_INTERFACE 0x0040
368 #define WPS_CONFIG_PUSHBUTTON 0x0080
369 #define WPS_CONFIG_KEYPAD 0x0100
370 #define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
371 #define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
372 #define WPS_CONFIG_VIRT_DISPLAY 0x2008
373 #define WPS_CONFIG_PHY_DISPLAY 0x4008
379 #ifndef WLAN_AKM_SUITE_CCKM
380 #define WLAN_AKM_SUITE_CCKM 0x00409600
382 #define DOT11_LEAP_AUTH 0x80 /* LEAP auth frame paylod constants */
385 #define WL_AKM_SUITE_SHA256_1X 0x000FAC05
386 #define WL_AKM_SUITE_SHA256_PSK 0x000FAC06
388 #ifndef IBSS_COALESCE_ALLOWED
389 #define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT
392 #ifndef IBSS_INITIAL_SCAN_ALLOWED
393 #define IBSS_INITIAL_SCAN_ALLOWED IBSS_INITIAL_SCAN_ALLOWED_DEFAULT
396 #define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
397 #define LONG_LISTEN_TIME 2000
400 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
401 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
402 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
403 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
404 #define DEFAULT_WBTEXT_PROFILE_A "a -70 -75 70 10 -75 -128 0 10"
405 #define DEFAULT_WBTEXT_PROFILE_B "b -60 -75 70 10 -75 -128 0 10"
406 #define DEFAULT_WBTEXT_WEIGHT_RSSI_A "RSSI a 65"
407 #define DEFAULT_WBTEXT_WEIGHT_RSSI_B "RSSI b 65"
408 #define DEFAULT_WBTEXT_WEIGHT_CU_A "CU a 35"
409 #define DEFAULT_WBTEXT_WEIGHT_CU_B "CU b 35"
410 #define DEFAULT_WBTEXT_TABLE_RSSI_A "RSSI a 0 55 100 55 60 90 \
411 60 65 70 65 70 50 70 128 20"
412 #define DEFAULT_WBTEXT_TABLE_RSSI_B "RSSI b 0 55 100 55 60 90 \
413 60 65 70 65 70 50 70 128 20"
414 #define DEFAULT_WBTEXT_TABLE_CU_A "CU a 0 30 100 30 50 90 \
415 50 60 70 60 80 50 80 100 20"
416 #define DEFAULT_WBTEXT_TABLE_CU_B "CU b 0 10 100 10 25 90 \
417 25 40 70 40 70 50 70 100 20"
419 typedef struct wl_wbtext_bssid
{
420 struct ether_addr ea
;
421 struct list_head list
;
424 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211
*cfg
, struct net_device
*dev
);
425 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211
*cfg
, struct ether_addr
*ea
);
426 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211
*cfg
, struct ether_addr
*ea
);
427 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211
*cfg
);
428 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
429 struct wl_profile
*profile
);
430 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
431 struct wl_profile
*profile
);
432 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211
*cfg
, struct net_device
*dev
);
433 static int wl_cfg80211_recv_nbr_resp(struct net_device
*dev
, uint8
*body
, uint body_len
);
436 #ifdef SUPPORT_AP_RADIO_PWRSAVE
437 #define RADIO_PWRSAVE_PPS 10
438 #define RADIO_PWRSAVE_QUIET_TIME 10
439 #define RADIO_PWRSAVE_LEVEL 3
440 #define RADIO_PWRSAVE_STAS_ASSOC_CHECK 0
442 #define RADIO_PWRSAVE_LEVEL_MIN 1
443 #define RADIO_PWRSAVE_LEVEL_MAX 5
444 #define RADIO_PWRSAVE_PPS_MIN 1
445 #define RADIO_PWRSAVE_QUIETTIME_MIN 1
446 #define RADIO_PWRSAVE_ASSOCCHECK_MIN 0
447 #define RADIO_PWRSAVE_ASSOCCHECK_MAX 1
449 #define RADIO_PWRSAVE_MAJOR_VER 1
450 #define RADIO_PWRSAVE_MINOR_VER 1
451 #define RADIO_PWRSAVE_MAJOR_VER_SHIFT 8
452 #define RADIO_PWRSAVE_VERSION \
453 ((RADIO_PWRSAVE_MAJOR_VER << RADIO_PWRSAVE_MAJOR_VER_SHIFT)| RADIO_PWRSAVE_MINOR_VER)
454 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
456 #define MIN_P2P_IE_LEN 8 /* p2p_ie->OUI(3) + p2p_ie->oui_type(1) +
457 * Attribute ID(1) + Length(2) + 1(Mininum length:1)
459 #define MAX_P2P_IE_LEN 251 /* Up To 251 */
461 #define MAX_VNDR_OUI_STR_LEN 256
462 #define VNDR_OUI_STR_LEN 10
463 static const uchar
*exclude_vndr_oui_list
[] = {
464 "\x00\x50\xf2", /* Microsoft */
465 "\x00\x00\xf0", /* Samsung Elec */
470 typedef struct wl_vndr_oui_entry
{
471 uchar oui
[DOT11_OUI_LEN
];
472 struct list_head list
;
473 } wl_vndr_oui_entry_t
;
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
);
480 * cfg80211_ops api/callback list
482 static s32
wl_frame_get_mgmt(struct bcm_cfg80211
*cfg
, u16 fc
,
483 const struct ether_addr
*da
, const struct ether_addr
*sa
,
484 const struct ether_addr
*bssid
, u8
**pheader
, u32
*body_len
, u8
*pbody
);
485 static s32
__wl_cfg80211_scan(struct wiphy
*wiphy
, struct net_device
*ndev
,
486 struct cfg80211_scan_request
*request
,
487 struct cfg80211_ssid
*this_ssid
);
488 #if defined(WL_CFG80211_P2P_DEV_IF)
490 wl_cfg80211_scan(struct wiphy
*wiphy
, struct cfg80211_scan_request
*request
);
493 wl_cfg80211_scan(struct wiphy
*wiphy
, struct net_device
*ndev
,
494 struct cfg80211_scan_request
*request
);
495 #endif /* WL_CFG80211_P2P_DEV_IF */
496 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
497 static void wl_cfg80211_abort_scan(struct wiphy
*wiphy
, struct wireless_dev
*wdev
);
498 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
499 static s32
wl_cfg80211_set_wiphy_params(struct wiphy
*wiphy
, u32 changed
);
501 static bcm_struct_cfgdev
* bcm_cfg80211_add_ibss_if(struct wiphy
*wiphy
, char *name
);
502 static s32
bcm_cfg80211_del_ibss_if(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
);
503 #endif /* WLAIBSS_MCHAN */
504 static s32
wl_cfg80211_join_ibss(struct wiphy
*wiphy
, struct net_device
*dev
,
505 struct cfg80211_ibss_params
*params
);
506 static s32
wl_cfg80211_leave_ibss(struct wiphy
*wiphy
,
507 struct net_device
*dev
);
508 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
509 static s32
wl_cfg80211_get_station(struct wiphy
*wiphy
,
510 struct net_device
*dev
, const u8
*mac
,
511 struct station_info
*sinfo
);
513 static s32
wl_cfg80211_get_station(struct wiphy
*wiphy
,
514 struct net_device
*dev
, u8
*mac
,
515 struct station_info
*sinfo
);
517 static s32
wl_cfg80211_set_power_mgmt(struct wiphy
*wiphy
,
518 struct net_device
*dev
, bool enabled
,
520 static int wl_cfg80211_connect(struct wiphy
*wiphy
, struct net_device
*dev
,
521 struct cfg80211_connect_params
*sme
);
522 static s32
wl_cfg80211_disconnect(struct wiphy
*wiphy
, struct net_device
*dev
,
524 #if defined(WL_CFG80211_P2P_DEV_IF)
526 wl_cfg80211_set_tx_power(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
527 enum nl80211_tx_power_setting type
, s32 mbm
);
530 wl_cfg80211_set_tx_power(struct wiphy
*wiphy
,
531 enum nl80211_tx_power_setting type
, s32 dbm
);
532 #endif /* WL_CFG80211_P2P_DEV_IF */
533 #if defined(WL_CFG80211_P2P_DEV_IF)
534 static s32
wl_cfg80211_get_tx_power(struct wiphy
*wiphy
,
535 struct wireless_dev
*wdev
, s32
*dbm
);
537 static s32
wl_cfg80211_get_tx_power(struct wiphy
*wiphy
, s32
*dbm
);
538 #endif /* WL_CFG80211_P2P_DEV_IF */
539 static s32
wl_cfg80211_config_default_key(struct wiphy
*wiphy
,
540 struct net_device
*dev
,
541 u8 key_idx
, bool unicast
, bool multicast
);
542 static s32
wl_cfg80211_add_key(struct wiphy
*wiphy
, struct net_device
*dev
,
543 u8 key_idx
, bool pairwise
, const u8
*mac_addr
,
544 struct key_params
*params
);
545 static s32
wl_cfg80211_del_key(struct wiphy
*wiphy
, struct net_device
*dev
,
546 u8 key_idx
, bool pairwise
, const u8
*mac_addr
);
547 static s32
wl_cfg80211_get_key(struct wiphy
*wiphy
, struct net_device
*dev
,
548 u8 key_idx
, bool pairwise
, const u8
*mac_addr
,
549 void *cookie
, void (*callback
) (void *cookie
,
550 struct key_params
*params
));
551 static s32
wl_cfg80211_config_default_mgmt_key(struct wiphy
*wiphy
,
552 struct net_device
*dev
, u8 key_idx
);
553 static s32
wl_cfg80211_resume(struct wiphy
*wiphy
);
554 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
556 static s32
wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy
*wiphy
,
557 bcm_struct_cfgdev
*cfgdev
, u64 cookie
);
558 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
559 static s32
wl_cfg80211_del_station(
560 struct wiphy
*wiphy
, struct net_device
*ndev
,
561 struct station_del_parameters
*params
);
562 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
563 static s32
wl_cfg80211_del_station(struct wiphy
*wiphy
,
564 struct net_device
*ndev
, const u8
* mac_addr
);
566 static s32
wl_cfg80211_del_station(struct wiphy
*wiphy
,
567 struct net_device
*ndev
, u8
* mac_addr
);
569 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
570 static s32
wl_cfg80211_change_station(struct wiphy
*wiphy
,
571 struct net_device
*dev
, const u8
*mac
, struct station_parameters
*params
);
573 static s32
wl_cfg80211_change_station(struct wiphy
*wiphy
,
574 struct net_device
*dev
, u8
*mac
, struct station_parameters
*params
);
576 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
577 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
578 static s32
wl_cfg80211_suspend(struct wiphy
*wiphy
, struct cfg80211_wowlan
*wow
);
580 static s32
wl_cfg80211_suspend(struct wiphy
*wiphy
);
582 static s32
wl_cfg80211_set_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
583 struct cfg80211_pmksa
*pmksa
);
584 static s32
wl_cfg80211_del_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
585 struct cfg80211_pmksa
*pmksa
);
586 static s32
wl_cfg80211_flush_pmksa(struct wiphy
*wiphy
,
587 struct net_device
*dev
);
588 void wl_cfg80211_scan_abort(struct bcm_cfg80211
*cfg
);
589 static void wl_cfg80211_cancel_scan(struct bcm_cfg80211
*cfg
);
590 static s32
wl_notify_escan_complete(struct bcm_cfg80211
*cfg
,
591 struct net_device
*ndev
, bool aborted
, bool fw_abort
);
592 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
593 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
594 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
595 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
596 u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
597 u32 peer_capability
, const u8
*buf
, size_t len
);
598 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
599 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
600 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
601 const u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
602 u32 peer_capability
, const u8
*buf
, size_t len
);
603 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
604 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
605 const u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
606 u32 peer_capability
, bool initiator
, const u8
*buf
, size_t len
);
607 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
608 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
609 u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
610 const u8
*buf
, size_t len
);
611 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
612 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
613 static s32
wl_cfg80211_tdls_oper(struct wiphy
*wiphy
, struct net_device
*dev
,
614 const u8
*peer
, enum nl80211_tdls_operation oper
);
616 static s32
wl_cfg80211_tdls_oper(struct wiphy
*wiphy
, struct net_device
*dev
,
617 u8
*peer
, enum nl80211_tdls_operation oper
);
619 #endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
621 static int wl_cfg80211_sched_scan_stop(struct wiphy
*wiphy
, struct net_device
*dev
);
622 #endif /* WL_SCHED_SCAN */
623 static s32
wl_cfg80211_set_ap_role(struct bcm_cfg80211
*cfg
, struct net_device
*dev
);
625 struct wireless_dev
*
626 wl_cfg80211_create_iface(struct wiphy
*wiphy
, wl_iftype_t
627 iface_type
, u8
*mac_addr
, const char *name
);
629 wl_cfg80211_del_iface(struct wiphy
*wiphy
, struct wireless_dev
*wdev
);
631 s32
wl_cfg80211_interface_ops(struct bcm_cfg80211
*cfg
,
632 struct net_device
*ndev
, s32 bsscfg_idx
,
633 wl_iftype_t iftype
, s32 del
, u8
*addr
);
634 s32
wl_cfg80211_add_del_bss(struct bcm_cfg80211
*cfg
,
635 struct net_device
*ndev
, s32 bsscfg_idx
,
636 wl_iftype_t brcm_iftype
, s32 del
, u8
*addr
);
637 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
638 static s32
wl_cfg80211_stop_ap(struct wiphy
*wiphy
, struct net_device
*dev
);
639 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */
640 #ifdef GTK_OFFLOAD_SUPPORT
641 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
642 static s32
wl_cfg80211_set_rekey_data(struct wiphy
*wiphy
, struct net_device
*dev
,
643 struct cfg80211_gtk_rekey_data
*data
);
644 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
645 #endif /* GTK_OFFLOAD_SUPPORT */
646 chanspec_t
wl_chspec_driver_to_host(chanspec_t chanspec
);
647 chanspec_t
wl_chspec_host_to_driver(chanspec_t chanspec
);
648 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211
*cfg
, struct net_device
*dev
);
651 * event & event Q handlers for cfg80211 interfaces
653 static s32
wl_create_event_handler(struct bcm_cfg80211
*cfg
);
654 static void wl_destroy_event_handler(struct bcm_cfg80211
*cfg
);
655 static void wl_event_handler(struct work_struct
*work_data
);
656 static void wl_init_eq(struct bcm_cfg80211
*cfg
);
657 static void wl_flush_eq(struct bcm_cfg80211
*cfg
);
658 static unsigned long wl_lock_eq(struct bcm_cfg80211
*cfg
);
659 static void wl_unlock_eq(struct bcm_cfg80211
*cfg
, unsigned long flags
);
660 static void wl_init_eq_lock(struct bcm_cfg80211
*cfg
);
661 static void wl_init_event_handler(struct bcm_cfg80211
*cfg
);
662 static struct wl_event_q
*wl_deq_event(struct bcm_cfg80211
*cfg
);
663 static s32
wl_enq_event(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u32 type
,
664 const wl_event_msg_t
*msg
, void *data
);
665 static void wl_put_event(struct bcm_cfg80211
*cfg
, struct wl_event_q
*e
);
666 static s32
wl_notify_connect_status_ap(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
667 const wl_event_msg_t
*e
, void *data
);
668 static s32
wl_notify_connect_status(struct bcm_cfg80211
*cfg
,
669 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
670 static s32
wl_notify_roaming_status(struct bcm_cfg80211
*cfg
,
671 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
672 static s32
wl_notify_scan_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
673 const wl_event_msg_t
*e
, void *data
);
674 static s32
wl_bss_connect_done(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
675 const wl_event_msg_t
*e
, void *data
, bool completed
);
676 static s32
wl_bss_roaming_done(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
677 const wl_event_msg_t
*e
, void *data
);
678 static s32
wl_notify_mic_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
679 const wl_event_msg_t
*e
, void *data
);
680 #ifdef BT_WIFI_HANDOVER
681 static s32
wl_notify_bt_wifi_handover_req(struct bcm_cfg80211
*cfg
,
682 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
683 #endif /* BT_WIFI_HANDOVER */
686 wl_notify_sched_scan_results(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
687 const wl_event_msg_t
*e
, void *data
);
688 #endif /* WL_SCHED_SCAN */
690 static s32
wl_notify_pfn_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
691 const wl_event_msg_t
*e
, void *data
);
692 #endif /* PNO_SUPPORT */
694 static s32
wl_notify_gscan_event(struct bcm_cfg80211
*wl
, bcm_struct_cfgdev
*cfgdev
,
695 const wl_event_msg_t
*e
, void *data
);
696 static s32
wl_handle_roam_exp_event(struct bcm_cfg80211
*wl
, bcm_struct_cfgdev
*cfgdev
,
697 const wl_event_msg_t
*e
, void *data
);
698 #endif /* GSCAN_SUPPORT */
699 #ifdef RSSI_MONITOR_SUPPORT
700 static s32
wl_handle_rssi_monitor_event(struct bcm_cfg80211
*wl
, bcm_struct_cfgdev
*cfgdev
,
701 const wl_event_msg_t
*e
, void *data
);
702 #endif /* RSSI_MONITOR_SUPPORT */
703 static s32
wl_notifier_change_state(struct bcm_cfg80211
*cfg
, struct net_info
*_net_info
,
704 enum wl_status state
, bool set
);
705 #ifdef CUSTOM_EVENT_PM_WAKE
706 static s32
wl_check_pmstatus(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
707 const wl_event_msg_t
*e
, void *data
);
708 #endif /* CUSTOM_EVENT_PM_WAKE */
709 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
710 static s32
wl_notify_roam_prep_status(struct bcm_cfg80211
*cfg
,
711 bcm_struct_cfgdev
*cfgdev
, const wl_event_msg_t
*e
, void *data
);
712 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
713 #ifdef DHD_LOSSLESS_ROAMING
714 static void wl_del_roam_timeout(struct bcm_cfg80211
*cfg
);
715 #endif /* DHD_LOSSLESS_ROAMING */
718 static s32
wl_cfg80211_tdls_config(struct bcm_cfg80211
*cfg
,
719 enum wl_tdls_config state
, bool tdls_mode
);
720 static s32
wl_tdls_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
721 const wl_event_msg_t
*e
, void *data
);
724 * register/deregister parent device
726 static void wl_cfg80211_clear_parent_dev(void);
732 * cfg80211 set_wiphy_params utilities
734 static s32
wl_set_frag(struct net_device
*dev
, u32 frag_threshold
);
735 static s32
wl_set_rts(struct net_device
*dev
, u32 frag_threshold
);
736 static s32
wl_set_retry(struct net_device
*dev
, u32 retry
, bool l
);
739 * cfg profile utilities
741 static s32
wl_update_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
742 const wl_event_msg_t
*e
, const void *data
, s32 item
);
743 static void *wl_read_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, s32 item
);
744 static void wl_init_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
);
747 * cfg80211 connect utilites
749 static s32
wl_set_wpa_version(struct net_device
*dev
,
750 struct cfg80211_connect_params
*sme
);
751 static s32
wl_set_auth_type(struct net_device
*dev
,
752 struct cfg80211_connect_params
*sme
);
753 static s32
wl_set_set_cipher(struct net_device
*dev
,
754 struct cfg80211_connect_params
*sme
);
755 static s32
wl_set_key_mgmt(struct net_device
*dev
,
756 struct cfg80211_connect_params
*sme
);
757 static s32
wl_set_set_sharedkey(struct net_device
*dev
,
758 struct cfg80211_connect_params
*sme
);
760 static s32
wl_set_set_wapi_ie(struct net_device
*dev
,
761 struct cfg80211_connect_params
*sme
);
763 static s32
wl_get_assoc_ies(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
);
764 static s32
wl_ch_to_chanspec(struct net_device
*dev
, int ch
,
765 struct wl_join_params
*join_params
, size_t *join_params_size
);
766 void wl_cfg80211_clear_security(struct bcm_cfg80211
*cfg
);
769 * information element utilities
771 static void wl_rst_ie(struct bcm_cfg80211
*cfg
);
772 static __used s32
wl_add_ie(struct bcm_cfg80211
*cfg
, u8 t
, u8 l
, u8
*v
);
773 static void wl_update_hidden_ap_ie(wl_bss_info_t
*bi
, const u8
*ie_stream
, u32
*ie_size
,
775 static s32
wl_mrg_ie(struct bcm_cfg80211
*cfg
, u8
*ie_stream
, u16 ie_size
);
776 static s32
wl_cp_ie(struct bcm_cfg80211
*cfg
, u8
*dst
, u16 dst_size
);
777 static u32
wl_get_ielen(struct bcm_cfg80211
*cfg
);
779 static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t
*wpa2ie
, const u8
** rsn_cap
);
784 wl_cfg80211_find_interworking_ie(const u8
*parse
, u32 len
);
786 wl_cfg80211_clear_iw_ie(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, s32 bssidx
);
788 wl_cfg80211_add_iw_ie(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, s32 bssidx
, s32 pktflag
,
789 uint8 ie_id
, uint8
*data
, uint8 data_len
);
792 static s32
wl_setup_wiphy(struct wireless_dev
*wdev
, struct device
*dev
, void *data
);
793 static void wl_free_wdev(struct bcm_cfg80211
*cfg
);
795 static s32
wl_inform_bss(struct bcm_cfg80211
*cfg
);
796 static s32
wl_inform_single_bss(struct bcm_cfg80211
*cfg
, wl_bss_info_t
*bi
, bool roam
);
797 static s32
wl_update_bss_info(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, bool roam
);
798 static chanspec_t
wl_cfg80211_get_shared_freq(struct wiphy
*wiphy
);
799 s32
wl_cfg80211_channel_to_freq(u32 channel
);
801 static void wl_cfg80211_work_handler(struct work_struct
*work
);
802 static s32
wl_add_keyext(struct wiphy
*wiphy
, struct net_device
*dev
,
803 u8 key_idx
, const u8
*mac_addr
,
804 struct key_params
*params
);
806 * key indianess swap utilities
808 static void swap_key_from_BE(struct wl_wsec_key
*key
);
809 static void swap_key_to_BE(struct wl_wsec_key
*key
);
812 * bcm_cfg80211 memory init/deinit utilities
814 static s32
wl_init_priv_mem(struct bcm_cfg80211
*cfg
);
815 static void wl_deinit_priv_mem(struct bcm_cfg80211
*cfg
);
817 static void wl_delay(u32 ms
);
820 * ibss mode utilities
822 static bool wl_is_ibssmode(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
);
823 static __used
bool wl_is_ibssstarter(struct bcm_cfg80211
*cfg
);
826 * link up/down , default configuration utilities
828 static s32
__wl_cfg80211_up(struct bcm_cfg80211
*cfg
);
829 static s32
__wl_cfg80211_down(struct bcm_cfg80211
*cfg
);
832 static bool wl_is_linkdown(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
, void *data
);
833 #define WL_IS_LINKDOWN(cfg, e, data) wl_is_linkdown(cfg, e, data)
835 static bool wl_is_linkdown(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
);
836 #define WL_IS_LINKDOWN(cfg, e, data) wl_is_linkdown(cfg, e)
837 #endif /* WL_LASTEVT */
839 static bool wl_is_linkup(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
,
840 struct net_device
*ndev
);
841 static bool wl_is_nonetwork(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
);
842 static void wl_link_up(struct bcm_cfg80211
*cfg
);
843 static void wl_link_down(struct bcm_cfg80211
*cfg
);
844 static s32
wl_config_infra(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u16 iftype
);
845 static void wl_init_conf(struct wl_conf
*conf
);
846 int wl_cfg80211_get_ioctl_version(void);
849 * find most significant bit set
851 static __used u32
wl_find_msb(u16 bit16
);
856 static int wl_setup_rfkill(struct bcm_cfg80211
*cfg
, bool setup
);
857 static int wl_rfkill_set(void *data
, bool blocked
);
858 #ifdef DEBUGFS_CFG80211
859 static s32
wl_setup_debugfs(struct bcm_cfg80211
*cfg
);
860 static s32
wl_free_debugfs(struct bcm_cfg80211
*cfg
);
862 static wl_scan_params_t
*wl_cfg80211_scan_alloc_params(struct bcm_cfg80211
*cfg
,
863 int channel
, int nprobes
, int *out_params_size
);
864 static bool check_dev_role_integrity(struct bcm_cfg80211
*cfg
, u32 dev_role
);
866 #ifdef WL_CFG80211_ACL
868 static int wl_cfg80211_set_mac_acl(struct wiphy
*wiphy
, struct net_device
*cfgdev
,
869 const struct cfg80211_acl_data
*acl
);
870 #endif /* WL_CFG80211_ACL */
873 * Some external functions, TODO: move them to dhd_linux.h
875 int dhd_add_monitor(const char *name
, struct net_device
**new_ndev
);
876 int dhd_del_monitor(struct net_device
*ndev
);
877 int dhd_monitor_init(void *dhd_pub
);
878 int dhd_monitor_uninit(void);
879 int dhd_start_xmit(struct sk_buff
*skb
, struct net_device
*net
);
881 #ifdef ESCAN_CHANNEL_CACHE
882 void reset_roam_cache(struct bcm_cfg80211
*cfg
);
883 void add_roam_cache(struct bcm_cfg80211
*cfg
, wl_bss_info_t
*bi
);
884 int get_roam_channel_list(int target_chan
, chanspec_t
*channels
,
885 int n_channels
, const wlc_ssid_t
*ssid
, int ioctl_ver
);
886 void set_roam_band(int band
);
887 #endif /* ESCAN_CHANNEL_CACHE */
889 #ifdef ROAM_CHANNEL_CACHE
890 int init_roam_cache(struct bcm_cfg80211
*cfg
, int ioctl_ver
);
891 void print_roam_cache(struct bcm_cfg80211
*cfg
);
892 void update_roam_cache(struct bcm_cfg80211
*cfg
, int ioctl_ver
);
893 #endif /* ROAM_CHANNEL_CACHE */
895 #ifdef P2P_LISTEN_OFFLOADING
896 s32
wl_cfg80211_p2plo_deinit(struct bcm_cfg80211
*cfg
);
897 #endif /* P2P_LISTEN_OFFLOADING */
899 #ifdef PKT_FILTER_SUPPORT
900 extern uint dhd_pkt_filter_enable
;
901 extern uint dhd_master_mode
;
902 extern void dhd_pktfilter_offload_enable(dhd_pub_t
* dhd
, char *arg
, int enable
, int master_mode
);
903 #endif /* PKT_FILTER_SUPPORT */
905 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
906 const struct ether_addr
*bssid
);
907 static s32
__wl_update_wiphybands(struct bcm_cfg80211
*cfg
, bool notify
);
909 static s32
wl_check_vif_support(struct bcm_cfg80211
*cfg
, wl_iftype_t wl_iftype
);
910 bool wl_is_wps_enrollee_active(struct net_device
*ndev
, const u8
*ie_ptr
, u16 len
);
913 static void wl_init_wps_reauth_sm(struct bcm_cfg80211
*cfg
);
914 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211
*cfg
);
915 static void wl_wps_reauth_timeout(unsigned long data
);
916 static s32
wl_get_free_wps_inst(struct bcm_cfg80211
*cfg
);
917 static s32
wl_get_wps_inst_match(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
);
918 static s32
wl_wps_session_add(struct net_device
*ndev
, u16 mode
, u8
*peer_mac
);
919 static void wl_wps_session_del(struct net_device
*ndev
);
920 static s32
wl_wps_session_update(struct net_device
*ndev
, u16 state
, const u8
*peer_mac
);
921 static void wl_wps_handle_ifdel(struct net_device
*ndev
);
922 #endif /* WL_WPS_SYNC */
923 const u8
*wl_find_attribute(const u8
*buf
, u16 len
, u16 element_id
);
926 static s32
wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
927 const wl_event_msg_t
*e
, void *data
);
928 #endif /* WL_BCNRECV */
930 static int bw2cap
[] = { 0, 0, WLC_BW_CAP_20MHZ
, WLC_BW_CAP_40MHZ
, WLC_BW_CAP_80MHZ
,
931 WLC_BW_CAP_160MHZ
, WLC_BW_CAP_160MHZ
};
933 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || (defined(CONFIG_ARCH_MSM) && \
934 defined(CFG80211_DISCONNECTED_V2))
935 #define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
936 cfg80211_disconnected(dev, reason, ie, len, loc_gen, gfp);
937 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0))
938 #define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
939 BCM_REFERENCE(loc_gen); \
940 cfg80211_disconnected(dev, reason, ie, len, gfp);
941 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) */
943 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || (defined(CONFIG_ARCH_MSM) && \
944 defined(CFG80211_DISCONNECTED_V2))
945 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
946 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
947 IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
949 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
950 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
951 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
952 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
954 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
955 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
956 defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
957 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
958 resp_ie_len, status, gfp) \
959 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
960 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
962 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
963 resp_ie_len, status, gfp) \
964 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
965 resp_ie_len, status, gfp);
966 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
967 (CFG80211_CONNECT_TIMEOUT_REASON_CODE)
969 #elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
970 /* There are customer kernels with backported changes for
971 * connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
972 * is available for kernels < 4.7 in such cases.
974 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
975 resp_ie_len, status, gfp) \
976 cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie, \
977 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
979 /* Kernels < 4.7 doesn't support cfg80211_connect_bss */
980 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
981 resp_ie_len, status, gfp) \
982 cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
983 resp_ie_len, status, gfp);
984 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
987 static s32
wl_rssi_offset(s32 rssi
)
995 #define wl_rssi_offset(x) x
998 #define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
999 (akm) == RSN_AKM_UNSPECIFIED || \
1000 (akm) == RSN_AKM_PSK)
1002 extern int dhd_wait_pend8021x(struct net_device
*dev
);
1003 #ifdef PROP_TXSTATUS_VSDB
1004 extern int disable_proptx
;
1005 #endif /* PROP_TXSTATUS_VSDB */
1007 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
1008 extern void dhd_force_disable_singlcore_scan(dhd_pub_t
*dhd
);
1009 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
1011 extern int passive_channel_skip
;
1014 wl_ap_start_ind(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
1015 const wl_event_msg_t
*e
, void *data
);
1017 wl_csa_complete_ind(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
1018 const wl_event_msg_t
*e
, void *data
);
1019 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \
1027 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
1028 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(wiphy, bss);
1030 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(bss);
1031 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
1033 #define CHAN2G(_channel, _freq, _flags) { \
1034 .band = NL80211_BAND_2GHZ, \
1035 .center_freq = (_freq), \
1036 .hw_value = (_channel), \
1037 .flags = (_flags), \
1038 .max_antenna_gain = 0, \
1042 #define CHAN5G(_channel, _flags) { \
1043 .band = NL80211_BAND_5GHZ, \
1044 .center_freq = 5000 + (5 * (_channel)), \
1045 .hw_value = (_channel), \
1046 .flags = (_flags), \
1047 .max_antenna_gain = 0, \
1051 #define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
1052 #define RATETAB_ENT(_rateid, _flags) \
1054 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
1055 .hw_value = (_rateid), \
1056 .flags = (_flags), \
1059 static struct ieee80211_rate __wl_rates
[] = {
1060 RATETAB_ENT(DOT11_RATE_1M
, 0),
1061 RATETAB_ENT(DOT11_RATE_2M
, IEEE80211_RATE_SHORT_PREAMBLE
),
1062 RATETAB_ENT(DOT11_RATE_5M5
, IEEE80211_RATE_SHORT_PREAMBLE
),
1063 RATETAB_ENT(DOT11_RATE_11M
, IEEE80211_RATE_SHORT_PREAMBLE
),
1064 RATETAB_ENT(DOT11_RATE_6M
, 0),
1065 RATETAB_ENT(DOT11_RATE_9M
, 0),
1066 RATETAB_ENT(DOT11_RATE_12M
, 0),
1067 RATETAB_ENT(DOT11_RATE_18M
, 0),
1068 RATETAB_ENT(DOT11_RATE_24M
, 0),
1069 RATETAB_ENT(DOT11_RATE_36M
, 0),
1070 RATETAB_ENT(DOT11_RATE_48M
, 0),
1071 RATETAB_ENT(DOT11_RATE_54M
, 0)
1074 #define wl_a_rates (__wl_rates + 4)
1075 #define wl_a_rates_size 8
1076 #define wl_g_rates (__wl_rates + 0)
1077 #define wl_g_rates_size 12
1079 static struct ieee80211_channel __wl_2ghz_channels
[] = {
1089 CHAN2G(10, 2457, 0),
1090 CHAN2G(11, 2462, 0),
1091 CHAN2G(12, 2467, 0),
1092 CHAN2G(13, 2472, 0),
1096 static struct ieee80211_channel __wl_5ghz_a_channels
[] = {
1097 CHAN5G(34, 0), CHAN5G(36, 0),
1098 CHAN5G(38, 0), CHAN5G(40, 0),
1099 CHAN5G(42, 0), CHAN5G(44, 0),
1100 CHAN5G(46, 0), CHAN5G(48, 0),
1101 CHAN5G(52, 0), CHAN5G(56, 0),
1102 CHAN5G(60, 0), CHAN5G(64, 0),
1103 CHAN5G(100, 0), CHAN5G(104, 0),
1104 CHAN5G(108, 0), CHAN5G(112, 0),
1105 CHAN5G(116, 0), CHAN5G(120, 0),
1106 CHAN5G(124, 0), CHAN5G(128, 0),
1107 CHAN5G(132, 0), CHAN5G(136, 0),
1108 CHAN5G(140, 0), CHAN5G(144, 0),
1109 CHAN5G(149, 0), CHAN5G(153, 0),
1110 CHAN5G(157, 0), CHAN5G(161, 0),
1114 static struct ieee80211_supported_band __wl_band_2ghz
= {
1115 .band
= NL80211_BAND_2GHZ
,
1116 .channels
= __wl_2ghz_channels
,
1117 .n_channels
= ARRAY_SIZE(__wl_2ghz_channels
),
1118 .bitrates
= wl_g_rates
,
1119 .n_bitrates
= wl_g_rates_size
1122 static struct ieee80211_supported_band __wl_band_5ghz_a
= {
1123 .band
= NL80211_BAND_5GHZ
,
1124 .channels
= __wl_5ghz_a_channels
,
1125 .n_channels
= ARRAY_SIZE(__wl_5ghz_a_channels
),
1126 .bitrates
= wl_a_rates
,
1127 .n_bitrates
= wl_a_rates_size
1130 static const u32 __wl_cipher_suites
[] = {
1131 WLAN_CIPHER_SUITE_WEP40
,
1132 WLAN_CIPHER_SUITE_WEP104
,
1133 WLAN_CIPHER_SUITE_TKIP
,
1134 WLAN_CIPHER_SUITE_CCMP
,
1137 * Advertising AES_CMAC cipher suite to userspace would imply that we
1138 * are supporting MFP. So advertise only when MFP support is enabled.
1140 WLAN_CIPHER_SUITE_AES_CMAC
,
1143 WLAN_CIPHER_SUITE_SMS4
,
1145 #if defined(WLAN_CIPHER_SUITE_PMK)
1146 WLAN_CIPHER_SUITE_PMK
,
1147 #endif /* WLAN_CIPHER_SUITE_PMK */
1150 #ifdef WL_SUPPORT_ACS
1152 * The firmware code required for this feature to work is currently under
1153 * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1154 * required firmware code out of the BCMINTERNAL flag.
1156 struct wl_dump_survey
{
1164 #endif /* WL_SUPPORT_ACS */
1166 #ifdef WL_CFG80211_GON_COLLISION
1167 #define BLOCK_GON_REQ_MAX_NUM 5
1168 #endif /* WL_CFG80211_GON_COLLISION */
1170 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1171 static int maxrxpktglom
= 0;
1174 /* IOCtl version read from targeted driver */
1176 #ifdef DEBUGFS_CFG80211
1177 #define SUBLOGLEVEL 20
1178 #define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1))
1179 static const struct {
1182 } sublogname_map
[] = {
1183 {WL_DBG_ERR
, "ERR"},
1184 {WL_DBG_INFO
, "INFO"},
1185 {WL_DBG_DBG
, "DBG"},
1186 {WL_DBG_SCAN
, "SCAN"},
1187 {WL_DBG_TRACE
, "TRACE"},
1188 {WL_DBG_P2P_ACTION
, "P2PACTION"}
1193 #define BUFSZN BUFSZ + 1
1198 #define SOFT_AP_IF_NAME "swlan0"
1200 #ifdef P2P_LISTEN_OFFLOADING
1201 void wl_cfg80211_cancel_p2plo(struct bcm_cfg80211
*cfg
);
1202 #endif /* P2P_LISTEN_OFFLOADING */
1204 #ifdef CUSTOMER_HW4_DEBUG
1205 uint prev_dhd_console_ms
= 0;
1206 u32 prev_wl_dbg_level
= 0;
1207 bool wl_scan_timeout_dbg_enabled
= 0;
1208 static void wl_scan_timeout_dbg_set(void);
1209 static void wl_scan_timeout_dbg_clear(void);
1211 static void wl_scan_timeout_dbg_set(void)
1213 WL_ERR(("Enter \n"));
1214 prev_dhd_console_ms
= dhd_console_ms
;
1215 prev_wl_dbg_level
= wl_dbg_level
;
1218 wl_dbg_level
|= (WL_DBG_ERR
| WL_DBG_P2P_ACTION
| WL_DBG_SCAN
);
1220 wl_scan_timeout_dbg_enabled
= 1;
1222 static void wl_scan_timeout_dbg_clear(void)
1224 WL_ERR(("Enter \n"));
1225 dhd_console_ms
= prev_dhd_console_ms
;
1226 wl_dbg_level
= prev_wl_dbg_level
;
1228 wl_scan_timeout_dbg_enabled
= 0;
1230 #endif /* CUSTOMER_HW4_DEBUG */
1232 /* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1233 uint32 fw_assoc_watchdog_ms
= 0;
1234 bool fw_assoc_watchdog_started
= 0;
1235 #define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1237 static void wl_add_remove_pm_enable_work(struct bcm_cfg80211
*cfg
,
1238 enum wl_pm_workq_act_type type
)
1240 u16 wq_duration
= 0;
1241 dhd_pub_t
*dhd
= NULL
;
1246 dhd
= (dhd_pub_t
*)(cfg
->pub
);
1248 mutex_lock(&cfg
->pm_sync
);
1250 * Make cancel and schedule work part mutually exclusive
1251 * so that while cancelling, we are sure that there is no
1252 * work getting scheduled.
1254 if (delayed_work_pending(&cfg
->pm_enable_work
)) {
1255 cancel_delayed_work(&cfg
->pm_enable_work
);
1256 DHD_PM_WAKE_UNLOCK(cfg
->pub
);
1259 if (type
== WL_PM_WORKQ_SHORT
) {
1260 wq_duration
= WL_PM_ENABLE_TIMEOUT
;
1261 } else if (type
== WL_PM_WORKQ_LONG
) {
1262 wq_duration
= (WL_PM_ENABLE_TIMEOUT
*2);
1265 /* It should schedule work item only if driver is up */
1266 if (wq_duration
&& dhd
->up
) {
1267 if (schedule_delayed_work(&cfg
->pm_enable_work
,
1268 msecs_to_jiffies((const unsigned int)wq_duration
))) {
1269 DHD_PM_WAKE_LOCK_TIMEOUT(cfg
->pub
, wq_duration
);
1271 WL_ERR(("Can't schedule pm work handler\n"));
1274 mutex_unlock(&cfg
->pm_sync
);
1277 /* Return a new chanspec given a legacy chanspec
1278 * Returns INVCHANSPEC on error
1281 wl_chspec_from_legacy(chanspec_t legacy_chspec
)
1285 /* get the channel number */
1286 chspec
= LCHSPEC_CHANNEL(legacy_chspec
);
1288 /* convert the band */
1289 if (LCHSPEC_IS2G(legacy_chspec
)) {
1290 chspec
|= WL_CHANSPEC_BAND_2G
;
1292 chspec
|= WL_CHANSPEC_BAND_5G
;
1295 /* convert the bw and sideband */
1296 if (LCHSPEC_IS20(legacy_chspec
)) {
1297 chspec
|= WL_CHANSPEC_BW_20
;
1299 chspec
|= WL_CHANSPEC_BW_40
;
1300 if (LCHSPEC_CTL_SB(legacy_chspec
) == WL_LCHANSPEC_CTL_SB_LOWER
) {
1301 chspec
|= WL_CHANSPEC_CTL_SB_L
;
1303 chspec
|= WL_CHANSPEC_CTL_SB_U
;
1307 if (wf_chspec_malformed(chspec
)) {
1308 WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1316 /* Return a legacy chanspec given a new chanspec
1317 * Returns INVCHANSPEC on error
1320 wl_chspec_to_legacy(chanspec_t chspec
)
1324 if (wf_chspec_malformed(chspec
)) {
1325 WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1330 /* get the channel number */
1331 lchspec
= CHSPEC_CHANNEL(chspec
);
1333 /* convert the band */
1334 if (CHSPEC_IS2G(chspec
)) {
1335 lchspec
|= WL_LCHANSPEC_BAND_2G
;
1337 lchspec
|= WL_LCHANSPEC_BAND_5G
;
1340 /* convert the bw and sideband */
1341 if (CHSPEC_IS20(chspec
)) {
1342 lchspec
|= WL_LCHANSPEC_BW_20
;
1343 lchspec
|= WL_LCHANSPEC_CTL_SB_NONE
;
1344 } else if (CHSPEC_IS40(chspec
)) {
1345 lchspec
|= WL_LCHANSPEC_BW_40
;
1346 if (CHSPEC_CTL_SB(chspec
) == WL_CHANSPEC_CTL_SB_L
) {
1347 lchspec
|= WL_LCHANSPEC_CTL_SB_LOWER
;
1349 lchspec
|= WL_LCHANSPEC_CTL_SB_UPPER
;
1352 /* cannot express the bandwidth */
1353 char chanbuf
[CHANSPEC_STR_LEN
];
1355 "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1356 "to pre-11ac format\n",
1357 wf_chspec_ntoa(chspec
, chanbuf
), chspec
));
1364 /* given a chanspec value, do the endian and chanspec version conversion to
1365 * a chanspec_t value
1366 * Returns INVCHANSPEC on error
1369 wl_chspec_host_to_driver(chanspec_t chanspec
)
1371 if (ioctl_version
== 1) {
1372 chanspec
= wl_chspec_to_legacy(chanspec
);
1373 if (chanspec
== INVCHANSPEC
) {
1377 chanspec
= htodchanspec(chanspec
);
1382 /* given a channel value, do the endian and chanspec version conversion to
1383 * a chanspec_t value
1384 * Returns INVCHANSPEC on error
1387 wl_ch_host_to_driver(u16 channel
)
1389 chanspec_t chanspec
;
1391 chanspec
= channel
& WL_CHANSPEC_CHAN_MASK
;
1393 if (channel
<= CH_MAX_2G_CHANNEL
)
1394 chanspec
|= WL_CHANSPEC_BAND_2G
;
1396 chanspec
|= WL_CHANSPEC_BAND_5G
;
1398 chanspec
|= WL_CHANSPEC_BW_20
;
1400 chanspec
|= WL_CHANSPEC_CTL_SB_NONE
;
1402 return wl_chspec_host_to_driver(chanspec
);
1405 /* given a chanspec value from the driver, do the endian and chanspec version conversion to
1406 * a chanspec_t value
1407 * Returns INVCHANSPEC on error
1410 wl_chspec_driver_to_host(chanspec_t chanspec
)
1412 chanspec
= dtohchanspec(chanspec
);
1413 if (ioctl_version
== 1) {
1414 chanspec
= wl_chspec_from_legacy(chanspec
);
1421 * convert ASCII string to MAC address (colon-delimited format)
1422 * eg: 00:11:22:33:44:55
1425 wl_cfg80211_ether_atoe(const char *a
, struct ether_addr
*n
)
1430 memset(n
, 0, ETHER_ADDR_LEN
);
1432 n
->octet
[count
++] = (uint8
)simple_strtoul(a
, &c
, 16);
1433 if (!*c
++ || count
== ETHER_ADDR_LEN
)
1437 return (count
== ETHER_ADDR_LEN
);
1440 /* There isn't a lot of sense in it, but you can transmit anything you like */
1441 static const struct ieee80211_txrx_stypes
1442 wl_cfg80211_default_mgmt_stypes
[NUM_NL80211_IFTYPES
] = {
1443 [NL80211_IFTYPE_ADHOC
] = {
1445 .rx
= BIT(IEEE80211_STYPE_ACTION
>> 4)
1447 [NL80211_IFTYPE_STATION
] = {
1449 .rx
= BIT(IEEE80211_STYPE_ACTION
>> 4) |
1450 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4)
1452 [NL80211_IFTYPE_AP
] = {
1454 .rx
= BIT(IEEE80211_STYPE_ASSOC_REQ
>> 4) |
1455 BIT(IEEE80211_STYPE_REASSOC_REQ
>> 4) |
1456 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4) |
1457 BIT(IEEE80211_STYPE_DISASSOC
>> 4) |
1458 BIT(IEEE80211_STYPE_AUTH
>> 4) |
1459 BIT(IEEE80211_STYPE_DEAUTH
>> 4) |
1460 BIT(IEEE80211_STYPE_ACTION
>> 4)
1462 [NL80211_IFTYPE_AP_VLAN
] = {
1465 .rx
= BIT(IEEE80211_STYPE_ASSOC_REQ
>> 4) |
1466 BIT(IEEE80211_STYPE_REASSOC_REQ
>> 4) |
1467 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4) |
1468 BIT(IEEE80211_STYPE_DISASSOC
>> 4) |
1469 BIT(IEEE80211_STYPE_AUTH
>> 4) |
1470 BIT(IEEE80211_STYPE_DEAUTH
>> 4) |
1471 BIT(IEEE80211_STYPE_ACTION
>> 4)
1473 [NL80211_IFTYPE_P2P_CLIENT
] = {
1475 .rx
= BIT(IEEE80211_STYPE_ACTION
>> 4) |
1476 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4)
1478 [NL80211_IFTYPE_P2P_GO
] = {
1480 .rx
= BIT(IEEE80211_STYPE_ASSOC_REQ
>> 4) |
1481 BIT(IEEE80211_STYPE_REASSOC_REQ
>> 4) |
1482 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4) |
1483 BIT(IEEE80211_STYPE_DISASSOC
>> 4) |
1484 BIT(IEEE80211_STYPE_AUTH
>> 4) |
1485 BIT(IEEE80211_STYPE_DEAUTH
>> 4) |
1486 BIT(IEEE80211_STYPE_ACTION
>> 4)
1488 #if defined(WL_CFG80211_P2P_DEV_IF)
1489 [NL80211_IFTYPE_P2P_DEVICE
] = {
1491 .rx
= BIT(IEEE80211_STYPE_ACTION
>> 4) |
1492 BIT(IEEE80211_STYPE_PROBE_REQ
>> 4)
1494 #endif /* WL_CFG80211_P2P_DEV_IF */
1497 static void swap_key_from_BE(struct wl_wsec_key
*key
)
1499 key
->index
= htod32(key
->index
);
1500 key
->len
= htod32(key
->len
);
1501 key
->algo
= htod32(key
->algo
);
1502 key
->flags
= htod32(key
->flags
);
1503 key
->rxiv
.hi
= htod32(key
->rxiv
.hi
);
1504 key
->rxiv
.lo
= htod16(key
->rxiv
.lo
);
1505 key
->iv_initialized
= htod32(key
->iv_initialized
);
1508 static void swap_key_to_BE(struct wl_wsec_key
*key
)
1510 key
->index
= dtoh32(key
->index
);
1511 key
->len
= dtoh32(key
->len
);
1512 key
->algo
= dtoh32(key
->algo
);
1513 key
->flags
= dtoh32(key
->flags
);
1514 key
->rxiv
.hi
= dtoh32(key
->rxiv
.hi
);
1515 key
->rxiv
.lo
= dtoh16(key
->rxiv
.lo
);
1516 key
->iv_initialized
= dtoh32(key
->iv_initialized
);
1519 /* Dump the contents of the encoded wps ie buffer and get pbc value */
1521 wl_validate_wps_ie(const char *wps_ie
, s32 wps_ie_len
, bool *pbc
)
1523 #define WPS_IE_FIXED_LEN 6
1525 const u8
*subel
= NULL
;
1529 u8
*valptr
= (uint8
*) &val
;
1530 if (wps_ie
== NULL
|| wps_ie_len
< WPS_IE_FIXED_LEN
) {
1531 WL_ERR(("invalid argument : NULL\n"));
1534 len
= (s16
)wps_ie
[TLV_LEN_OFF
];
1536 if (len
> wps_ie_len
) {
1537 WL_ERR(("invalid length len %d, wps ie len %d\n", len
, wps_ie_len
));
1540 WL_DBG(("wps_ie len=%d\n", len
));
1541 len
-= 4; /* for the WPS IE's OUI, oui_type fields */
1542 subel
= wps_ie
+ WPS_IE_FIXED_LEN
;
1543 while (len
>= 4) { /* must have attr id, attr len fields */
1544 valptr
[0] = *subel
++;
1545 valptr
[1] = *subel
++;
1546 subelt_id
= HTON16(val
);
1548 valptr
[0] = *subel
++;
1549 valptr
[1] = *subel
++;
1550 subelt_len
= HTON16(val
);
1552 len
-= 4; /* for the attr id, attr len fields */
1553 len
-= (s16
)subelt_len
; /* for the remaining fields in this attribute */
1557 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
1558 subel
, subelt_id
, subelt_len
));
1560 if (subelt_id
== WPS_ID_VERSION
) {
1561 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel
));
1562 } else if (subelt_id
== WPS_ID_REQ_TYPE
) {
1563 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel
));
1564 } else if (subelt_id
== WPS_ID_CONFIG_METHODS
) {
1566 valptr
[1] = *(subel
+ 1);
1567 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val
)));
1568 } else if (subelt_id
== WPS_ID_DEVICE_NAME
) {
1570 int namelen
= MIN(subelt_len
, (sizeof(devname
) - 1));
1573 memcpy(devname
, subel
, namelen
);
1574 devname
[namelen
] = '\0';
1575 /* Printing len as rx'ed in the IE */
1576 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1577 devname
, subelt_len
));
1579 } else if (subelt_id
== WPS_ID_DEVICE_PWD_ID
) {
1581 valptr
[1] = *(subel
+ 1);
1582 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val
)));
1583 *pbc
= (HTON16(val
) == DEV_PW_PUSHBUTTON
) ? true : false;
1584 } else if (subelt_id
== WPS_ID_PRIM_DEV_TYPE
) {
1586 valptr
[1] = *(subel
+ 1);
1587 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val
)));
1588 valptr
[0] = *(subel
+ 6);
1589 valptr
[1] = *(subel
+ 7);
1590 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val
)));
1591 } else if (subelt_id
== WPS_ID_REQ_DEV_TYPE
) {
1593 valptr
[1] = *(subel
+ 1);
1594 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val
)));
1595 valptr
[0] = *(subel
+ 6);
1596 valptr
[1] = *(subel
+ 7);
1597 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val
)));
1598 } else if (subelt_id
== WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS
) {
1600 valptr
[1] = *(subel
+ 1);
1601 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1602 ": cat=%u\n", HTON16(val
)));
1604 WL_DBG((" unknown attr 0x%x\n", subelt_id
));
1607 subel
+= subelt_len
;
1611 s32
wl_set_tx_power(struct net_device
*dev
,
1612 enum nl80211_tx_power_setting type
, s32 dbm
)
1617 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
1619 /* Make sure radio is off or on as far as software is concerned */
1620 disable
= WL_RADIO_SW_DISABLE
<< 16;
1621 disable
= htod32(disable
);
1622 err
= wldev_ioctl_set(dev
, WLC_SET_RADIO
, &disable
, sizeof(disable
));
1623 if (unlikely(err
)) {
1624 WL_ERR(("WLC_SET_RADIO error (%d)\n", err
));
1630 txpwrqdbm
= dbm
* 4;
1631 #ifdef SUPPORT_WL_TXPOWER
1632 if (type
== NL80211_TX_POWER_AUTOMATIC
)
1635 txpwrqdbm
|= WL_TXPWR_OVERRIDE
;
1636 #endif /* SUPPORT_WL_TXPOWER */
1637 err
= wldev_iovar_setbuf_bsscfg(dev
, "qtxpower", (void *)&txpwrqdbm
,
1638 sizeof(txpwrqdbm
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, 0,
1639 &cfg
->ioctl_buf_sync
);
1641 WL_ERR(("qtxpower error (%d)\n", err
));
1643 WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm
, txpwrqdbm
));
1648 s32
wl_get_tx_power(struct net_device
*dev
, s32
*dbm
)
1652 char ioctl_buf
[WLC_IOCTL_SMLEN
];
1654 err
= wldev_iovar_getbuf_bsscfg(dev
, "qtxpower",
1655 NULL
, 0, ioctl_buf
, WLC_IOCTL_SMLEN
, 0, NULL
);
1656 if (unlikely(err
)) {
1657 WL_ERR(("error (%d)\n", err
));
1661 memcpy(&txpwrdbm
, ioctl_buf
, sizeof(txpwrdbm
));
1662 txpwrdbm
= dtoh32(txpwrdbm
);
1663 *dbm
= (txpwrdbm
& ~WL_TXPWR_OVERRIDE
) / 4;
1665 WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm
, txpwrdbm
));
1670 static chanspec_t
wl_cfg80211_get_shared_freq(struct wiphy
*wiphy
)
1673 int cur_band
, err
= 0;
1674 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
1675 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
1676 struct ether_addr bssid
;
1677 wl_bss_info_t
*bss
= NULL
;
1678 u16 channel
= WL_P2P_TEMP_CHAN
;
1681 memset(&bssid
, 0, sizeof(bssid
));
1682 if ((err
= wldev_ioctl_get(dev
, WLC_GET_BSSID
, &bssid
, sizeof(bssid
)))) {
1683 /* STA interface is not associated. So start the new interface on a temp
1684 * channel . Later proper channel will be applied by the above framework
1685 * via set_channel (cfg80211 API).
1687 WL_DBG(("Not associated. Return a temp channel. \n"));
1689 err
= wldev_ioctl_get(dev
, WLC_GET_BAND
, &cur_band
, sizeof(int));
1690 if (unlikely(err
)) {
1691 WL_ERR(("Get band failed\n"));
1692 } else if (cur_band
== WLC_BAND_5G
) {
1693 channel
= WL_P2P_TEMP_CHAN_5G
;
1695 return wl_ch_host_to_driver(channel
);
1698 buf
= (char *)MALLOCZ(cfg
->osh
, WL_EXTRA_BUF_MAX
);
1700 WL_ERR(("buf alloc failed. use temp channel\n"));
1701 return wl_ch_host_to_driver(channel
);
1704 *(u32
*)buf
= htod32(WL_EXTRA_BUF_MAX
);
1705 if ((err
= wldev_ioctl_get(dev
, WLC_GET_BSS_INFO
, buf
,
1706 WL_EXTRA_BUF_MAX
))) {
1707 WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1708 chspec
= wl_ch_host_to_driver(channel
);
1711 bss
= (wl_bss_info_t
*) (buf
+ 4);
1712 chspec
= bss
->chanspec
;
1714 WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec
));
1717 MFREE(cfg
->osh
, buf
, WL_EXTRA_BUF_MAX
);
1722 wl_wlfc_enable(struct bcm_cfg80211
*cfg
, bool enable
)
1724 #ifdef PROP_TXSTATUS_VSDB
1725 #if defined(BCMSDIO)
1726 bool wlfc_enabled
= FALSE
;
1729 struct net_device
*primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
1731 dhd
= (dhd_pub_t
*)(cfg
->pub
);
1737 if (!cfg
->wlfc_on
&& !disable_proptx
) {
1738 dhd_wlfc_get_enable(dhd
, &wlfc_enabled
);
1739 if (!wlfc_enabled
&& dhd
->op_mode
!= DHD_FLAG_HOSTAP_MODE
&&
1740 dhd
->op_mode
!= DHD_FLAG_IBSS_MODE
) {
1742 err
= wldev_ioctl_set(primary_ndev
, WLC_UP
, &up
, sizeof(s32
));
1744 WL_ERR(("WLC_UP return err:%d\n", err
));
1746 cfg
->wlfc_on
= true;
1747 WL_DBG(("wlfc_on:%d \n", cfg
->wlfc_on
));
1750 dhd_wlfc_deinit(dhd
);
1751 cfg
->wlfc_on
= false;
1753 #endif /* defined(BCMSDIO) */
1754 #endif /* PROP_TXSTATUS_VSDB */
1757 struct wireless_dev
*
1758 wl_cfg80211_p2p_if_add(struct bcm_cfg80211
*cfg
,
1759 wl_iftype_t wl_iftype
,
1760 char const *name
, u8
*mac_addr
, s32
*ret_err
)
1768 struct net_device
*new_ndev
= NULL
;
1769 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
1770 struct ether_addr
*p2p_addr
;
1774 WL_ERR(("p2p not initialized\n"));
1777 #if defined(WL_CFG80211_P2P_DEV_IF)
1778 if (wl_iftype
== WL_IF_TYPE_P2P_DISC
) {
1779 /* Handle Dedicated P2P discovery Interface */
1780 return wl_cfgp2p_add_p2p_disc_if(cfg
);
1782 #endif /* WL_CFG80211_P2P_DEV_IF */
1784 if (wl_iftype
== WL_IF_TYPE_P2P_GO
) {
1785 p2p_iftype
= WL_P2P_IF_GO
;
1787 p2p_iftype
= WL_P2P_IF_CLIENT
;
1790 /* Dual p2p doesn't support multiple P2PGO interfaces,
1791 * p2p_go_count is the counter for GO creation
1794 if ((cfg
->p2p
->p2p_go_count
> 0) && (wl_iftype
== WL_IF_TYPE_P2P_GO
)) {
1795 WL_ERR(("FW does not support multiple GO\n"));
1796 *ret_err
= -ENOTSUPP
;
1799 if (!cfg
->p2p
->on
) {
1801 wl_cfgp2p_set_firm_p2p(cfg
);
1802 wl_cfgp2p_init_discovery(cfg
);
1805 strncpy(cfg
->p2p
->vir_ifname
, name
, IFNAMSIZ
- 1);
1806 cfg
->p2p
->vir_ifname
[IFNAMSIZ
- 1] = '\0';
1807 /* In concurrency case, STA may be already associated in a particular channel.
1808 * so retrieve the current channel of primary interface and then start the virtual
1809 * interface on that.
1811 chspec
= wl_cfg80211_get_shared_freq(wiphy
);
1813 /* For P2P mode, use P2P-specific driver features to create the
1814 * bss: "cfg p2p_ifadd"
1816 if (wl_check_dongle_idle(wiphy
) != TRUE
) {
1817 WL_ERR(("FW is busy to add interface"));
1818 return ERR_PTR(-ENOMEM
);
1820 wl_set_p2p_status(cfg
, IF_ADDING
);
1821 memset(&cfg
->if_event_info
, 0, sizeof(cfg
->if_event_info
));
1822 cfg_type
= wl_cfgp2p_get_conn_idx(cfg
);
1823 if (cfg_type
== BCME_ERROR
) {
1824 wl_clr_p2p_status(cfg
, IF_ADDING
);
1825 WL_ERR(("Failed to get connection idx for p2p interface"));
1829 p2p_addr
= wl_to_p2p_bss_macaddr(cfg
, cfg_type
);
1830 memcpy(p2p_addr
->octet
, mac_addr
, ETH_ALEN
);
1832 err
= wl_cfgp2p_ifadd(cfg
, p2p_addr
,
1833 htod32(p2p_iftype
), chspec
);
1834 if (unlikely(err
)) {
1835 wl_clr_p2p_status(cfg
, IF_ADDING
);
1836 WL_ERR((" virtual iface add failed (%d) \n", err
));
1840 /* Wait for WLC_E_IF event with IF_ADD opcode */
1841 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
1842 ((wl_get_p2p_status(cfg
, IF_ADDING
) == false) &&
1843 (cfg
->if_event_info
.valid
)),
1844 msecs_to_jiffies(MAX_WAIT_TIME
));
1845 if (timeout
> 0 && !wl_get_p2p_status(cfg
, IF_ADDING
) && cfg
->if_event_info
.valid
) {
1846 wl_if_event_info
*event
= &cfg
->if_event_info
;
1847 new_ndev
= wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg
), event
,
1848 event
->mac
, cfg
->p2p
->vir_ifname
, false);
1849 if (unlikely(!new_ndev
)) {
1853 if (wl_iftype
== WL_IF_TYPE_P2P_GO
) {
1854 cfg
->p2p
->p2p_go_count
++;
1856 /* Fill p2p specific data */
1857 wl_to_p2p_bss_ndev(cfg
, cfg_type
) = new_ndev
;
1858 wl_to_p2p_bss_bssidx(cfg
, cfg_type
) = event
->bssidx
;
1860 WL_ERR((" virtual interface(%s) is "
1861 "created net attach done\n", cfg
->p2p
->vir_ifname
));
1862 dhd_mode
= (wl_iftype
== WL_IF_TYPE_P2P_GC
) ?
1863 DHD_FLAG_P2P_GC_MODE
: DHD_FLAG_P2P_GO_MODE
;
1864 DNGL_FUNC(dhd_cfg80211_set_p2p_info
, (cfg
, dhd_mode
));
1865 /* reinitialize completion to clear previous count */
1866 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1867 INIT_COMPLETION(cfg
->iface_disable
);
1869 init_completion(&cfg
->iface_disable
);
1870 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
1872 return new_ndev
->ieee80211_ptr
;
1880 wl_check_vif_support(struct bcm_cfg80211
*cfg
, wl_iftype_t wl_iftype
)
1883 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
1886 if ((cfg
->nan_enable
) && (wl_iftype
!= WL_IF_TYPE_NAN
)) {
1887 ret
= wl_cfgnan_disable(cfg
, NAN_CONCURRENCY_CONFLICT
);
1888 if (ret
!= BCME_OK
) {
1889 WL_ERR(("failed to disable nan, error[%d]\n", ret
));
1894 /* If P2PGroup/Softap is enabled, another VIF
1895 * iface create request can't be supported
1897 if ((wl_cfgp2p_vif_created(cfg
)) ||
1898 (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
1899 WL_ERR(("Additional vif can't be supported [%d]\n",
1909 wl_cfg80211_iface_state_ops(struct wireless_dev
*wdev
,
1910 wl_interface_state_t state
,
1911 wl_iftype_t wl_iftype
, u16 wl_mode
)
1913 struct net_device
*ndev
;
1914 struct bcm_cfg80211
*cfg
;
1915 #if defined(CUSTOM_SET_CPUCORE)
1920 WL_DBG(("state:%s wl_iftype:%d mode:%d\n",
1921 wl_if_state_strs
[state
], wl_iftype
, wl_mode
));
1923 WL_ERR(("wdev null\n"));
1927 if ((wl_iftype
== WL_IF_TYPE_P2P_DISC
) || (wl_iftype
== WL_IF_TYPE_NAN_NMI
)) {
1928 /* P2P discovery is a netless device and uses a
1929 * hidden bsscfg interface in fw. Don't apply the
1930 * iface ops state changes for p2p discovery I/F.
1931 * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
1932 * Don't apply iface ops state changes for NMI I/F.
1937 cfg
= wiphy_priv(wdev
->wiphy
);
1938 ndev
= wdev
->netdev
;
1939 #ifdef CUSTOM_SET_CPUCORE
1940 dhd
= (dhd_pub_t
*)(cfg
->pub
);
1941 #endif /* CUSTOM_SET_CPUCORE */
1943 bssidx
= wl_get_bssidx_by_wdev(cfg
, wdev
);
1944 if (!ndev
|| (bssidx
< 0)) {
1945 WL_ERR(("ndev null. skip iface state ops\n"));
1950 case WL_IF_CREATE_REQ
:
1952 /* check fakeapscan in progress then abort */
1953 wl_android_bcnrecv_stop(ndev
, WL_BCNRECV_CONCURRENCY
);
1954 #endif /* WL_BCNRECV */
1955 wl_cfg80211_scan_abort(cfg
);
1956 wl_wlfc_enable(cfg
, true);
1959 if (wl_iftype
== WL_IF_TYPE_NAN
) {
1960 /* disable TDLS on NAN IF create */
1961 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_NDI_CREATE
, false);
1964 /* disable TDLS if number of connected interfaces is >= 1 */
1965 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_IF_CREATE
, false);
1969 case WL_IF_DELETE_REQ
:
1971 wl_wps_handle_ifdel(ndev
);
1972 #endif /* WPS_SYNC */
1973 if (wl_get_drv_status(cfg
, SCANNING
, ndev
)) {
1974 /* Send completion for any pending scans */
1975 wl_cfg80211_cancel_scan(cfg
);
1978 #ifdef CUSTOM_SET_CPUCORE
1979 dhd
->chan_isvht80
&= ~DHD_FLAG_P2P_MODE
;
1980 if (!(dhd
->chan_isvht80
)) {
1981 dhd_set_cpucore(dhd
, FALSE
);
1983 #endif /* CUSTOM_SET_CPUCORE */
1984 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_DEL
);
1986 case WL_IF_CREATE_DONE
:
1987 if (wl_mode
== WL_MODE_BSS
) {
1988 /* Common code for sta type interfaces - STA, GC */
1989 wldev_iovar_setint(ndev
, "buf_key_b4_m4", 1);
1991 if (wl_iftype
== WL_IF_TYPE_P2P_GC
) {
1992 /* Disable firmware roaming for P2P interface */
1993 wldev_iovar_setint(ndev
, "roam_off", 1);
1995 if (wl_mode
== WL_MODE_AP
) {
1996 /* Common code for AP/GO */
1999 case WL_IF_DELETE_DONE
:
2001 /* Enable back TDLS if connected interface is <= 1 */
2002 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_IF_DELETE
, false);
2004 wl_wlfc_enable(cfg
, false);
2006 case WL_IF_CHANGE_REQ
:
2007 /* Flush existing IEs from firmware on role change */
2008 wl_cfg80211_clear_per_bss_ies(cfg
, wdev
);
2010 case WL_IF_CHANGE_DONE
:
2011 if (wl_mode
== WL_MODE_BSS
) {
2012 /* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2013 wldev_iovar_setint(ndev
, "buf_key_b4_m4", 1);
2018 WL_ERR(("Unsupported state: %d\n", state
));
2024 wl_cfg80211_p2p_if_del(struct wiphy
*wiphy
, struct wireless_dev
*wdev
)
2026 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2030 struct net_device
*ndev
;
2033 if (unlikely(!wl_get_drv_status(cfg
, READY
, bcmcfg_to_prmry_ndev(cfg
)))) {
2034 WL_INFORM_MEM(("device is not ready\n"));
2035 return BCME_NOTFOUND
;
2038 #ifdef WL_CFG80211_P2P_DEV_IF
2039 if (wdev
->iftype
== NL80211_IFTYPE_P2P_DEVICE
) {
2040 /* Handle dedicated P2P discovery interface. */
2041 return wl_cfgp2p_del_p2p_disc_if(wdev
, cfg
);
2043 #endif /* WL_CFG80211_P2P_DEV_IF */
2045 /* Handle P2P Group Interface */
2046 bssidx
= wl_get_bssidx_by_wdev(cfg
, wdev
);
2048 WL_ERR(("bssidx not found\n"));
2049 return BCME_NOTFOUND
;
2051 if (wl_cfgp2p_find_type(cfg
, bssidx
, &cfg_type
) != BCME_OK
) {
2052 /* Couldn't find matching iftype */
2053 WL_MEM(("non P2P interface\n"));
2054 return BCME_NOTFOUND
;
2057 if (wl_check_dongle_idle(wiphy
) != TRUE
) {
2058 WL_ERR(("FW is busy to add interface"));
2062 ndev
= wdev
->netdev
;
2063 wl_clr_p2p_status(cfg
, GO_NEG_PHASE
);
2064 wl_clr_p2p_status(cfg
, IF_ADDING
);
2067 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
) {
2068 wl_add_remove_eventmsg(ndev
, WLC_E_PROBREQ_MSG
, false);
2069 cfg
->p2p
->p2p_go_count
--;
2070 /* disable interface before bsscfg free */
2071 err
= wl_cfgp2p_ifdisable(cfg
, wl_to_p2p_bss_macaddr(cfg
, cfg_type
));
2072 /* if fw doesn't support "ifdis",
2073 do not wait for link down of ap mode
2076 WL_ERR(("Wait for Link Down event for GO !!!\n"));
2077 wait_for_completion_timeout(&cfg
->iface_disable
,
2078 msecs_to_jiffies(500));
2079 } else if (err
!= BCME_UNSUPPORTED
) {
2084 if (wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
2085 WL_ERR(("Wait for Link Down event for GC !\n"));
2086 wait_for_completion_timeout
2087 (&cfg
->iface_disable
, msecs_to_jiffies(500));
2091 memset(&cfg
->if_event_info
, 0, sizeof(cfg
->if_event_info
));
2092 wl_set_p2p_status(cfg
, IF_DELETING
);
2093 DNGL_FUNC(dhd_cfg80211_clean_p2p_info
, (cfg
));
2095 err
= wl_cfgp2p_ifdel(cfg
, wl_to_p2p_bss_macaddr(cfg
, cfg_type
));
2096 if (unlikely(err
)) {
2097 WL_ERR(("IFDEL operation failed, error code = %d\n", err
));
2100 /* Wait for WLC_E_IF event */
2101 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
2102 ((wl_get_p2p_status(cfg
, IF_DELETING
) == false) &&
2103 (cfg
->if_event_info
.valid
)),
2104 msecs_to_jiffies(MAX_WAIT_TIME
));
2105 if (timeout
> 0 && !wl_get_p2p_status(cfg
, IF_DELETING
) &&
2106 cfg
->if_event_info
.valid
) {
2107 WL_ERR(("P2P IFDEL operation done\n"));
2110 WL_ERR(("IFDEL didn't complete properly\n"));
2116 /* Even in failure case, attempt to remove the host data structure.
2117 * Firmware would be cleaned up via WiFi reset done by the
2118 * user space from hang event context (for android only).
2120 memset(cfg
->p2p
->vir_ifname
, '\0', IFNAMSIZ
);
2121 wl_to_p2p_bss_bssidx(cfg
, cfg_type
) = -1;
2122 wl_to_p2p_bss_ndev(cfg
, cfg_type
) = NULL
;
2123 wl_clr_drv_status(cfg
, CONNECTED
, wl_to_p2p_bss_ndev(cfg
, cfg_type
));
2124 dhd_net_if_lock(ndev
);
2125 if (cfg
->if_event_info
.ifidx
) {
2126 /* Remove interface except for primary ifidx */
2127 wl_cfg80211_remove_if(cfg
, cfg
->if_event_info
.ifidx
, ndev
, FALSE
);
2129 dhd_net_if_unlock(ndev
);
2133 static struct wireless_dev
*
2134 wl_cfg80211_add_monitor_if(struct wiphy
*wiphy
, const char *name
)
2136 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
2137 WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2138 return ERR_PTR(-EOPNOTSUPP
);
2140 struct wireless
*wdev
;
2141 struct net_device
* ndev
= NULL
;
2143 dhd_add_monitor(name
, &ndev
);
2145 wdev
= kzalloc(sizeof(*wdev
), GFP_KERNEL
);
2147 WL_ERR(("wireless_dev alloc failed! \n"));
2151 wdev
->wiphy
= wiphy
;
2152 wdev
->iftype
= iface_type
;
2153 ndev
->ieee80211_ptr
= wdev
;
2154 SET_NETDEV_DEV(ndev
, wiphy_dev(wiphy
));
2156 WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev
));
2157 return ndev
->ieee80211_ptr
;
2158 #endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */
2161 static struct wireless_dev
*
2162 wl_cfg80211_add_ibss(struct wiphy
*wiphy
, u16 wl_iftype
, char const *name
)
2164 #ifdef WLAIBSS_MCHAN
2166 return bcm_cfg80211_add_ibss_if(wiphy
, (char *)name
);
2169 WL_ERR(("IBSS not supported on Virtual iface\n"));
2175 wl_release_vif_macaddr(struct bcm_cfg80211
*cfg
, u8
*mac_addr
, u16 wl_iftype
)
2177 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
2178 u16 org_toggle_bytes
;
2179 u16 cur_toggle_bytes
;
2182 if (!ndev
|| !mac_addr
) {
2186 if ((wl_iftype
== WL_IF_TYPE_P2P_DISC
) || (wl_iftype
== WL_IF_TYPE_AP
) ||
2187 (wl_iftype
== WL_IF_TYPE_P2P_GO
) || (wl_iftype
== WL_IF_TYPE_P2P_GC
)) {
2188 /* Avoid invoking release mac addr code for interfaces using
2194 /* Fetch last two bytes of mac address */
2195 org_toggle_bytes
= ntoh16(*((u16
*)&ndev
->dev_addr
[4]));
2196 cur_toggle_bytes
= ntoh16(*((u16
*)&mac_addr
[4]));
2198 toggled_bit
= (org_toggle_bytes
^ cur_toggle_bytes
);
2199 WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n",
2200 org_toggle_bytes
, cur_toggle_bytes
));
2201 if (toggled_bit
& cfg
->vif_macaddr_mask
) {
2202 /* This toggled_bit is marked in the used mac addr
2205 cfg
->vif_macaddr_mask
&= ~toggled_bit
;
2206 WL_INFORM(("MAC address - " MACDBG
" released. toggled_bit:%04X vif_mask:%04X\n",
2207 MAC2STRDBG(mac_addr
), toggled_bit
, cfg
->vif_macaddr_mask
));
2209 WL_ERR(("MAC address - " MACDBG
" not found in the used list."
2210 " toggled_bit:%04x vif_mask:%04x\n", MAC2STRDBG(mac_addr
),
2211 toggled_bit
, cfg
->vif_macaddr_mask
));
2219 wl_get_vif_macaddr(struct bcm_cfg80211
*cfg
, u16 wl_iftype
, u8
*mac_addr
)
2221 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
2227 /* Toggle mask starts from MSB of second last byte */
2234 memcpy(mac_addr
, ndev
->dev_addr
, ETH_ALEN
);
2236 * VIF MAC address managment
2237 * P2P Device addres: Primary MAC with locally admin. bit set
2238 * P2P Group address/NAN NMI/Softap/NAN DPI: Primary MAC addr
2239 * with local admin bit set and one additional bit toggled.
2240 * cfg->vif_macaddr_mask will hold the info regarding the mac address
2241 * released. Ensure to call wl_release_vif_macaddress to free up
2244 if (wl_iftype
== WL_IF_TYPE_P2P_DISC
|| wl_iftype
== WL_IF_TYPE_AP
) {
2245 mac_addr
[0] |= 0x02;
2246 } else if ((wl_iftype
== WL_IF_TYPE_P2P_GO
) || (wl_iftype
== WL_IF_TYPE_P2P_GC
)) {
2247 mac_addr
[0] |= 0x02;
2248 mac_addr
[4] ^= 0x80;
2250 /* For locally administered mac addresses, we keep the
2251 * OUI part constant and just work on the last two bytes.
2253 mac_addr
[0] |= 0x02;
2254 toggle_mask
= cfg
->vif_macaddr_mask
;
2255 toggle_bytes
= ntoh16(*((u16
*)&mac_addr
[4]));
2257 used
= toggle_mask
& mask
;
2259 /* Use this bit position */
2260 toggle_bit
= mask
>> offset
;
2261 toggle_bytes
^= toggle_bit
;
2262 cfg
->vif_macaddr_mask
|= toggle_bit
;
2263 WL_DBG(("toggle_bit:%04X toggle_bytes:%04X toggle_mask:%04X\n",
2264 toggle_bit
, toggle_bytes
, cfg
->vif_macaddr_mask
));
2265 /* Macaddress are stored in network order */
2266 mac_addr
[5] = *((u8
*)&toggle_bytes
);
2267 mac_addr
[4] = *(((u8
*)&toggle_bytes
+ 1));
2272 toggle_mask
= toggle_mask
<< 0x1;
2274 if (offset
> MAX_VIF_OFFSET
) {
2275 /* We have used up all macaddresses. Something wrong! */
2276 WL_ERR(("Entire range of macaddress used up.\n"));
2282 WL_INFORM_MEM(("Get virtual I/F mac addr: "MACDBG
"\n", MAC2STRDBG(mac_addr
)));
2286 /* All Android/Linux private/Vendor Interface calls should make
2287 * use of below API for interface creation.
2289 struct wireless_dev
*
2290 wl_cfg80211_add_if(struct bcm_cfg80211
*cfg
,
2291 struct net_device
*primary_ndev
,
2292 wl_iftype_t wl_iftype
, const char *name
, u8
*mac
)
2294 u8 mac_addr
[ETH_ALEN
];
2296 struct wireless_dev
*wdev
= NULL
;
2297 struct wiphy
*wiphy
;
2300 wl_iftype_t macaddr_iftype
= wl_iftype
;
2302 WL_INFORM_MEM(("if name: %s, wl_iftype:%d \n",
2303 name
? name
: "NULL", wl_iftype
));
2304 if (!cfg
|| !primary_ndev
|| !name
) {
2305 WL_ERR(("cfg/ndev/name ptr null\n"));
2308 if (wl_cfg80211_get_wdev_from_ifname(cfg
, name
)) {
2309 WL_ERR(("Interface name %s exists!\n", name
));
2312 wiphy
= bcmcfg_to_wiphy(cfg
);
2313 dhd
= (dhd_pub_t
*)(cfg
->pub
);
2318 if ((wl_mode
= wl_iftype_to_mode(wl_iftype
)) < 0) {
2322 if ((err
= wl_check_vif_support(cfg
, wl_iftype
)) < 0) {
2326 /* Protect the interace op context */
2327 mutex_lock(&cfg
->if_sync
);
2328 /* Do pre-create ops */
2329 wl_cfg80211_iface_state_ops(primary_ndev
->ieee80211_ptr
, WL_IF_CREATE_REQ
,
2330 wl_iftype
, wl_mode
);
2332 if (strnicmp(name
, SOFT_AP_IF_NAME
, strlen(SOFT_AP_IF_NAME
)) == 0) {
2333 macaddr_iftype
= WL_IF_TYPE_AP
;
2337 /* If mac address is provided, use that */
2338 memcpy(mac_addr
, mac
, ETH_ALEN
);
2339 } else if ((wl_get_vif_macaddr(cfg
, macaddr_iftype
, mac_addr
) != BCME_OK
)) {
2340 /* Fetch the mac address to be used for virtual interface */
2345 switch (wl_iftype
) {
2346 case WL_IF_TYPE_IBSS
:
2347 wdev
= wl_cfg80211_add_ibss(wiphy
, wl_iftype
, name
);
2349 case WL_IF_TYPE_MONITOR
:
2350 wdev
= wl_cfg80211_add_monitor_if(wiphy
, name
);
2352 case WL_IF_TYPE_STA
:
2354 case WL_IF_TYPE_NAN
:
2355 if (cfg
->iface_cnt
>= (IFACE_MAX_CNT
- 1)) {
2356 WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
2361 wdev
= wl_cfg80211_create_iface(cfg
->wdev
->wiphy
,
2362 wl_iftype
, mac_addr
, name
);
2364 case WL_IF_TYPE_P2P_DISC
:
2365 case WL_IF_TYPE_P2P_GO
:
2366 /* Intentional fall through */
2367 case WL_IF_TYPE_P2P_GC
:
2368 if (cfg
->p2p_supported
) {
2369 wdev
= wl_cfg80211_p2p_if_add(cfg
, wl_iftype
,
2370 name
, mac_addr
, &err
);
2373 /* Intentionally fall through for unsupported interface
2374 * handling when firmware doesn't support p2p
2377 WL_ERR(("Unsupported interface type\n"));
2383 if (err
!= -ENOTSUPP
) {
2386 WL_ERR(("vif create failed. err:%d\n", err
));
2390 /* Ensure decrementing in case of failure */
2393 wl_cfg80211_iface_state_ops(wdev
,
2394 WL_IF_CREATE_DONE
, wl_iftype
, wl_mode
);
2396 WL_INFORM_MEM(("Vif created."
2397 " dev->ifindex:%d cfg_iftype:%d, vif_count:%d\n",
2398 (wdev
->netdev
? wdev
->netdev
->ifindex
: 0xff),
2399 wdev
->iftype
, cfg
->vif_count
));
2400 mutex_unlock(&cfg
->if_sync
);
2404 wl_cfg80211_iface_state_ops(primary_ndev
->ieee80211_ptr
,
2405 WL_IF_DELETE_REQ
, wl_iftype
, wl_mode
);
2407 if (err
!= -ENOTSUPP
) {
2408 /* For non-supported interfaces, just return error and
2409 * skip below recovery steps.
2411 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2412 wl_copy_hang_info_if_falure(primary_ndev
, HANG_REASON_IFACE_DEL_FAILURE
, err
);
2413 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2414 SUPP_LOG(("IF_ADD fail. err:%d\n", err
));
2415 wl_flush_fw_log_buffer(primary_ndev
, FW_LOGSET_MASK_ALL
);
2416 #if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
2417 if (dhd
->memdump_enabled
) {
2418 dhd
->memdump_type
= DUMP_TYPE_IFACE_OP_FAILURE
;
2419 dhd_bus_mem_dump(dhd
);
2421 #endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
2422 dhd
->hang_reason
= HANG_REASON_IFACE_ADD_FAILURE
;
2423 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg
));
2425 mutex_unlock(&cfg
->if_sync
);
2429 static bcm_struct_cfgdev
*
2430 wl_cfg80211_add_virtual_iface(struct wiphy
*wiphy
,
2431 #if defined(WL_CFG80211_P2P_DEV_IF)
2435 #endif /* WL_CFG80211_P2P_DEV_IF */
2436 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
2437 unsigned char name_assign_type
,
2438 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
2439 enum nl80211_iftype type
, u32
*flags
,
2440 struct vif_params
*params
)
2444 struct net_device
*primary_ndev
;
2445 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2446 struct wireless_dev
*wdev
;
2448 WL_DBG(("Enter iftype: %d\n", type
));
2450 return ERR_PTR(-EINVAL
);
2453 /* Use primary I/F for sending cmds down to firmware */
2454 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
2455 if (unlikely(!wl_get_drv_status(cfg
, READY
, primary_ndev
))) {
2456 WL_ERR(("device is not ready\n"));
2457 return ERR_PTR(-ENODEV
);
2459 #if defined(SUPPORT_RANDOM_MAC_SCAN) && defined(DHD_RANDOM_MAC_SCAN)
2460 wl_cfg80211_random_mac_disable(primary_ndev
);
2461 #endif /* SUPPORT_RANDOM_MAC_SCAN && DHD_RANDOM_MAC_SCAN */
2463 WL_ERR(("Interface name not provided \n"));
2464 return ERR_PTR(-EINVAL
);
2467 if (cfg80211_to_wl_iftype(type
, &wl_iftype
, &wl_mode
) < 0) {
2468 return ERR_PTR(-EINVAL
);
2471 wdev
= wl_cfg80211_add_if(cfg
, primary_ndev
, wl_iftype
, name
, NULL
);
2472 if (unlikely(!wdev
)) {
2473 return ERR_PTR(-ENODEV
);
2476 return wdev_to_cfgdev(wdev
);
2480 wl_cfg80211_del_ibss(struct wiphy
*wiphy
, struct wireless_dev
*wdev
)
2482 WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev
));
2483 #ifdef WLAIBSS_MCHAN
2485 return bcm_cfg80211_del_ibss_if(wiphy
, wdev
);
2488 return wl_cfg80211_del_iface(wiphy
, wdev
);
2493 wl_cfg80211_del_if(struct bcm_cfg80211
*cfg
, struct net_device
*primary_ndev
,
2494 struct wireless_dev
*wdev
, char *ifname
)
2498 struct wiphy
*wiphy
;
2501 struct net_info
*netinfo
;
2509 mutex_lock(&cfg
->if_sync
);
2510 dhd
= (dhd_pub_t
*)(cfg
->pub
);
2512 if (!wdev
&& ifname
) {
2513 /* If only ifname is provided, fetch corresponding wdev ptr from our
2514 * internal data structure
2516 wdev
= wl_cfg80211_get_wdev_from_ifname(cfg
, ifname
);
2519 /* Check whether we have a valid wdev ptr */
2520 if (unlikely(!wdev
)) {
2521 WL_ERR(("wdev not found. '%s' does not exists\n", ifname
));
2522 mutex_unlock(&cfg
->if_sync
);
2526 WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev
->iftype
));
2528 wiphy
= wdev
->wiphy
;
2529 #ifdef WL_CFG80211_P2P_DEV_IF
2530 if (wdev
->iftype
== NL80211_IFTYPE_P2P_DEVICE
) {
2531 /* p2p discovery would be de-initialized in stop p2p
2532 * device context/from other virtual i/f creation context
2533 * so netinfo list may not have any node corresponding to
2534 * discovery I/F. Handle it before bssidx check.
2536 ret
= wl_cfg80211_p2p_if_del(wiphy
, wdev
);
2537 if (unlikely(ret
)) {
2540 /* success case. return from here */
2541 if (cfg
->vif_count
) {
2544 mutex_unlock(&cfg
->if_sync
);
2548 #endif /* WL_CFG80211_P2P_DEV_IF */
2550 if ((netinfo
= wl_get_netinfo_by_wdev(cfg
, wdev
)) == NULL
) {
2551 WL_ERR(("Find netinfo from wdev %p failed\n", wdev
));
2556 if (!wdev
->netdev
) {
2557 WL_ERR(("ndev null! \n"));
2559 /* Disable tx before del */
2560 netif_tx_disable(wdev
->netdev
);
2563 wl_iftype
= netinfo
->iftype
;
2564 wl_mode
= wl_iftype_to_mode(wl_iftype
);
2565 bssidx
= netinfo
->bssidx
;
2566 WL_INFORM_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
2567 wdev
->iftype
, wl_iftype
, wl_mode
, bssidx
));
2569 /* Do pre-interface del ops */
2570 wl_cfg80211_iface_state_ops(wdev
, WL_IF_DELETE_REQ
, wl_iftype
, wl_mode
);
2572 switch (wl_iftype
) {
2573 case WL_IF_TYPE_P2P_GO
:
2574 case WL_IF_TYPE_P2P_GC
:
2576 case WL_IF_TYPE_STA
:
2577 case WL_IF_TYPE_NAN
:
2578 ret
= wl_cfg80211_del_iface(wiphy
, wdev
);
2580 case WL_IF_TYPE_IBSS
:
2581 ret
= wl_cfg80211_del_ibss(wiphy
, wdev
);
2585 WL_ERR(("Unsupported interface type\n"));
2590 if (ret
== BCME_OK
) {
2591 /* Successful case */
2592 if (cfg
->vif_count
) {
2595 wl_cfg80211_iface_state_ops(primary_ndev
->ieee80211_ptr
,
2596 WL_IF_DELETE_DONE
, wl_iftype
, wl_mode
);
2598 if (!((cfg
->nancfg
.mac_rand
) && (wl_iftype
== WL_IF_TYPE_NAN
)))
2601 wl_release_vif_macaddr(cfg
, wdev
->netdev
->dev_addr
, wl_iftype
);
2603 WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg
->vif_count
));
2605 if (!wdev
->netdev
) {
2606 WL_ERR(("ndev null! \n"));
2608 /* IF del failed. revert back tx queue status */
2609 netif_tx_start_all_queues(wdev
->netdev
);
2612 /* Skip generating log files and sending HANG event
2613 * if driver state is not READY
2615 if (wl_get_drv_status(cfg
, READY
, bcmcfg_to_prmry_ndev(cfg
))) {
2616 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2617 wl_copy_hang_info_if_falure(primary_ndev
,
2618 HANG_REASON_IFACE_DEL_FAILURE
, ret
);
2619 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2620 SUPP_LOG(("IF_DEL fail. err:%d\n", ret
));
2621 wl_flush_fw_log_buffer(primary_ndev
, FW_LOGSET_MASK_ALL
);
2622 #if defined(DHD_FW_COREDUMP)
2623 if (dhd
->memdump_enabled
&& (ret
!= -EBADTYPE
)) {
2624 dhd
->memdump_type
= DUMP_TYPE_IFACE_OP_FAILURE
;
2625 dhd_bus_mem_dump(dhd
);
2627 #endif /* BCMDONGLEHOST && DHD_FW_COREDUMP */
2628 WL_ERR(("Notify hang event to upper layer \n"));
2629 dhd
->hang_reason
= HANG_REASON_IFACE_DEL_FAILURE
;
2630 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg
));
2634 mutex_unlock(&cfg
->if_sync
);
2639 wl_cfg80211_del_virtual_iface(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
)
2641 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2642 struct wireless_dev
*wdev
= cfgdev_to_wdev(cfgdev
);
2646 struct net_device
*primary_ndev
;
2652 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
2653 wdev
= cfgdev_to_wdev(cfgdev
);
2655 WL_ERR(("wdev null"));
2659 WL_DBG(("Enter wdev:%p iftype: %d\n", wdev
, wdev
->iftype
));
2660 if (cfg80211_to_wl_iftype(wdev
->iftype
, &wl_iftype
, &wl_mode
) < 0) {
2661 WL_ERR(("Wrong iftype: %d\n", wdev
->iftype
));
2665 if ((ret
= wl_cfg80211_del_if(cfg
, primary_ndev
,
2667 WL_ERR(("IF del failed\n"));
2674 wl_cfg80211_change_p2prole(struct wiphy
*wiphy
, struct net_device
*ndev
, enum nl80211_iftype type
)
2682 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2683 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
2685 WL_INFORM_MEM(("Enter. current_role:%d new_role:%d \n", ndev
->ieee80211_ptr
->iftype
, type
));
2687 if (!cfg
->p2p
|| !wl_cfgp2p_vif_created(cfg
)) {
2688 WL_ERR(("P2P not initialized \n"));
2692 if (!is_p2p_group_iface(ndev
->ieee80211_ptr
)) {
2693 WL_ERR(("Wrong if type \n"));
2697 if (wl_check_dongle_idle(wiphy
) != TRUE
) {
2698 WL_ERR(("FW is busy to add interface"));
2702 /* Abort any on-going scans to avoid race condition issues */
2703 wl_cfg80211_cancel_scan(cfg
);
2705 index
= wl_get_bssidx_by_wdev(cfg
, ndev
->ieee80211_ptr
);
2707 WL_ERR(("Find bsscfg index from ndev(%p) failed\n", ndev
));
2710 if (wl_cfgp2p_find_type(cfg
, index
, &conn_idx
) != BCME_OK
) {
2714 /* In concurrency case, STA may be already associated in a particular
2715 * channel. so retrieve the current channel of primary interface and
2716 * then start the virtual interface on that.
2718 chspec
= wl_cfg80211_get_shared_freq(wiphy
);
2719 if (type
== NL80211_IFTYPE_P2P_GO
) {
2720 /* Dual p2p doesn't support multiple P2PGO interfaces,
2721 * p2p_go_count is the counter for GO creation
2724 if ((cfg
->p2p
->p2p_go_count
> 0) && (type
== NL80211_IFTYPE_P2P_GO
)) {
2725 WL_ERR(("FW does not support multiple GO\n"));
2729 wlif_type
= WL_P2P_IF_GO
;
2730 dhd
->op_mode
&= ~DHD_FLAG_P2P_GC_MODE
;
2731 dhd
->op_mode
|= DHD_FLAG_P2P_GO_MODE
;
2733 wlif_type
= WL_P2P_IF_CLIENT
;
2735 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
) {
2736 WL_INFORM_MEM(("Downgrading P2P GO to cfg_iftype:%d \n", type
));
2737 wl_add_remove_eventmsg(ndev
, WLC_E_PROBREQ_MSG
, false);
2738 cfg
->p2p
->p2p_go_count
--;
2739 /* disable interface before bsscfg free */
2740 err
= wl_cfgp2p_ifdisable(cfg
, wl_to_p2p_bss_macaddr(cfg
, conn_idx
));
2741 /* if fw doesn't support "ifdis",
2742 * do not wait for link down of ap mode
2745 WL_DBG(("Wait for Link Down event for GO !!!\n"));
2746 wait_for_completion_timeout(&cfg
->iface_disable
,
2747 msecs_to_jiffies(500));
2748 } else if (err
!= BCME_UNSUPPORTED
) {
2754 wl_set_p2p_status(cfg
, IF_CHANGING
);
2755 wl_clr_p2p_status(cfg
, IF_CHANGED
);
2756 wl_cfgp2p_ifchange(cfg
, wl_to_p2p_bss_macaddr(cfg
, conn_idx
),
2757 htod32(wlif_type
), chspec
, conn_idx
);
2758 wait_event_interruptible_timeout(cfg
->netif_change_event
,
2759 (wl_get_p2p_status(cfg
, IF_CHANGED
) == true),
2760 msecs_to_jiffies(MAX_WAIT_TIME
));
2762 wl_clr_p2p_status(cfg
, IF_CHANGING
);
2763 wl_clr_p2p_status(cfg
, IF_CHANGED
);
2765 if (mode
== WL_MODE_AP
) {
2766 wl_set_drv_status(cfg
, CONNECTED
, ndev
);
2773 wl_cfg80211_change_virtual_iface(struct wiphy
*wiphy
, struct net_device
*ndev
,
2774 enum nl80211_iftype type
, u32
*flags
,
2775 struct vif_params
*params
)
2781 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2782 struct net_info
*netinfo
= NULL
;
2783 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
2784 struct net_device
*primary_ndev
;
2789 WL_INFORM_MEM(("[%s] Enter. current cfg_iftype:%d new cfg_iftype:%d \n",
2790 ndev
->name
, ndev
->ieee80211_ptr
->iftype
, type
));
2791 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
2793 if (cfg80211_to_wl_iftype(type
, &wl_iftype
, &wl_mode
) < 0) {
2794 WL_ERR(("Unknown role \n"));
2798 /* If any scan is going on, abort it */
2799 if (wl_abort_scan_and_check(cfg
) != TRUE
) {
2800 wl_notify_escan_complete(cfg
, cfg
->escan_info
.ndev
, true, true);
2803 mutex_lock(&cfg
->if_sync
);
2804 netinfo
= wl_get_netinfo_by_wdev(cfg
, ndev
->ieee80211_ptr
);
2805 if (unlikely(!netinfo
)) {
2807 if (IS_CFG80211_STATIC_IF(cfg
, ndev
)) {
2808 /* Incase of static interfaces, the netinfo will be
2809 * allocated only when FW interface is initialized. So
2810 * store the value and use it during initialization.
2812 WL_INFORM_MEM(("skip change vif for static if\n"));
2813 ndev
->ieee80211_ptr
->iftype
= type
;
2816 #endif /* WL_STATIC_IF */
2818 WL_ERR(("netinfo not found \n"));
2824 /* perform pre-if-change tasks */
2825 wl_cfg80211_iface_state_ops(ndev
->ieee80211_ptr
,
2826 WL_IF_CHANGE_REQ
, wl_iftype
, wl_mode
);
2829 case NL80211_IFTYPE_ADHOC
:
2832 case NL80211_IFTYPE_STATION
:
2833 /* Supplicant sets iftype to STATION while removing p2p GO */
2834 if (ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
2835 /* Downgrading P2P GO */
2836 err
= wl_cfg80211_change_p2prole(wiphy
, ndev
, type
);
2837 if (unlikely(err
)) {
2838 WL_ERR(("P2P downgrade failed \n"));
2840 } else if (ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
2841 /* Downgrade role from AP to STA */
2842 if ((err
= wl_cfg80211_add_del_bss(cfg
, ndev
,
2843 netinfo
->bssidx
, wl_iftype
, 0, NULL
)) < 0) {
2844 WL_ERR(("AP-STA Downgrade failed \n"));
2849 case NL80211_IFTYPE_AP
:
2850 /* intentional fall through */
2851 case NL80211_IFTYPE_AP_VLAN
:
2853 if (!wl_get_drv_status(cfg
, AP_CREATED
, ndev
)) {
2854 err
= wl_cfg80211_set_ap_role(cfg
, ndev
);
2855 if (unlikely(err
)) {
2856 WL_ERR(("set ap role failed!\n"));
2860 WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
2864 case NL80211_IFTYPE_P2P_GO
:
2865 /* Intentional fall through */
2866 case NL80211_IFTYPE_P2P_CLIENT
:
2868 err
= wl_cfg80211_change_p2prole(wiphy
, ndev
, type
);
2870 case NL80211_IFTYPE_MONITOR
:
2871 case NL80211_IFTYPE_WDS
:
2872 case NL80211_IFTYPE_MESH_POINT
:
2873 /* Intentional fall through */
2875 WL_ERR(("Unsupported type:%d \n", type
));
2880 err
= wldev_ioctl_set(ndev
, WLC_SET_INFRA
, &infra
, sizeof(s32
));
2882 WL_ERR(("SET INFRA/IBSS error %d\n", err
));
2886 wl_cfg80211_iface_state_ops(primary_ndev
->ieee80211_ptr
,
2887 WL_IF_CHANGE_DONE
, wl_iftype
, wl_mode
);
2889 /* Update new iftype in relevant structures */
2890 ndev
->ieee80211_ptr
->iftype
= type
;
2891 netinfo
->iftype
= wl_iftype
;
2892 WL_INFORM_MEM(("[%s] cfg_iftype changed to %d\n", ndev
->name
, type
));
2896 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
2898 mutex_unlock(&cfg
->if_sync
);
2903 wl_cfg80211_notify_ifadd(struct net_device
*dev
,
2904 int ifidx
, char *name
, uint8
*mac
, uint8 bssidx
, uint8 role
)
2906 bool ifadd_expected
= FALSE
;
2907 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
2908 bool bss_pending_op
= TRUE
;
2910 /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
2911 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
2913 if (wl_get_p2p_status(cfg
, IF_CHANGING
))
2914 return wl_cfg80211_notify_ifchange(dev
, ifidx
, name
, mac
, bssidx
);
2916 /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
2917 if (wl_get_p2p_status(cfg
, IF_ADDING
)) {
2918 ifadd_expected
= TRUE
;
2919 wl_clr_p2p_status(cfg
, IF_ADDING
);
2920 } else if (cfg
->bss_pending_op
) {
2921 ifadd_expected
= TRUE
;
2922 bss_pending_op
= FALSE
;
2925 if (ifadd_expected
) {
2926 wl_if_event_info
*if_event_info
= &cfg
->if_event_info
;
2928 if_event_info
->valid
= TRUE
;
2929 if_event_info
->ifidx
= ifidx
;
2930 if_event_info
->bssidx
= bssidx
;
2931 if_event_info
->role
= role
;
2932 strncpy(if_event_info
->name
, name
, IFNAMSIZ
);
2933 if_event_info
->name
[IFNAMSIZ
] = '\0';
2935 memcpy(if_event_info
->mac
, mac
, ETHER_ADDR_LEN
);
2937 /* Update bss pendig operation status */
2938 if (!bss_pending_op
) {
2939 cfg
->bss_pending_op
= FALSE
;
2941 WL_INFORM_MEM(("IF_ADD ifidx:%d bssidx:%d role:%d\n",
2942 ifidx
, bssidx
, role
));
2943 wake_up_interruptible(&cfg
->netif_change_event
);
2951 wl_cfg80211_notify_ifdel(struct net_device
*dev
, int ifidx
, char *name
, uint8
*mac
, uint8 bssidx
)
2953 bool ifdel_expected
= FALSE
;
2954 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
2955 wl_if_event_info
*if_event_info
= &cfg
->if_event_info
;
2956 bool bss_pending_op
= TRUE
;
2958 if (wl_get_p2p_status(cfg
, IF_DELETING
)) {
2959 ifdel_expected
= TRUE
;
2960 wl_clr_p2p_status(cfg
, IF_DELETING
);
2961 } else if (cfg
->bss_pending_op
) {
2962 ifdel_expected
= TRUE
;
2963 bss_pending_op
= FALSE
;
2966 if (ifdel_expected
) {
2967 if_event_info
->valid
= TRUE
;
2968 if_event_info
->ifidx
= ifidx
;
2969 if_event_info
->bssidx
= bssidx
;
2970 /* Update bss pendig operation status */
2971 if (!bss_pending_op
) {
2972 cfg
->bss_pending_op
= FALSE
;
2974 WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx
, bssidx
));
2975 wake_up_interruptible(&cfg
->netif_change_event
);
2983 wl_cfg80211_notify_ifchange(struct net_device
* dev
, int ifidx
, char *name
, uint8
*mac
,
2986 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
2988 if (wl_get_p2p_status(cfg
, IF_CHANGING
)) {
2989 wl_set_p2p_status(cfg
, IF_CHANGED
);
2990 wake_up_interruptible(&cfg
->netif_change_event
);
2997 /* Find listen channel */
2998 static s32
wl_find_listen_channel(struct bcm_cfg80211
*cfg
,
2999 const u8
*ie
, u32 ie_len
)
3001 const wifi_p2p_ie_t
*p2p_ie
;
3002 const u8
*end
, *pos
;
3005 pos
= (const u8
*)ie
;
3007 p2p_ie
= wl_cfgp2p_find_p2pie(pos
, ie_len
);
3009 if (p2p_ie
== NULL
) {
3013 if (p2p_ie
->len
< MIN_P2P_IE_LEN
|| p2p_ie
->len
> MAX_P2P_IE_LEN
) {
3014 CFGP2P_ERR(("p2p_ie->len out of range - %d\n", p2p_ie
->len
));
3018 pos
= p2p_ie
->subelts
;
3019 end
= p2p_ie
->subelts
+ (p2p_ie
->len
- 4);
3021 CFGP2P_DBG((" found p2p ie ! lenth %d \n",
3026 if (pos
+ 2 >= end
) {
3027 CFGP2P_DBG((" -- Invalid P2P attribute"));
3030 attr_len
= ((uint16
) (((pos
+ 1)[1] << 8) | (pos
+ 1)[0]));
3032 if (pos
+ 3 + attr_len
> end
) {
3033 CFGP2P_DBG(("P2P: Attribute underflow "
3035 attr_len
, (int) (end
- pos
- 3)));
3039 /* if Listen Channel att id is 6 and the vailue is valid,
3040 * return the listen channel
3043 /* listen channel subel length format
3044 * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num)
3046 listen_channel
= pos
[1 + 2 + 3 + 1];
3048 if (listen_channel
== SOCIAL_CHAN_1
||
3049 listen_channel
== SOCIAL_CHAN_2
||
3050 listen_channel
== SOCIAL_CHAN_3
) {
3051 CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel
));
3052 return listen_channel
;
3055 pos
+= 3 + attr_len
;
3060 static void wl_scan_prep(struct bcm_cfg80211
*cfg
, struct wl_scan_params
*params
,
3061 struct cfg80211_scan_request
*request
)
3066 chanspec_t chanspec
;
3067 s32 i
= 0, j
= 0, offset
;
3071 memcpy(¶ms
->bssid
, ðer_bcast
, ETHER_ADDR_LEN
);
3072 params
->bss_type
= DOT11_BSSTYPE_ANY
;
3073 params
->scan_type
= 0;
3074 params
->nprobes
= -1;
3075 params
->active_time
= -1;
3076 params
->passive_time
= -1;
3077 params
->home_time
= -1;
3078 params
->channel_num
= 0;
3079 memset(¶ms
->ssid
, 0, sizeof(wlc_ssid_t
));
3081 WL_SCAN(("Preparing Scan request\n"));
3082 WL_SCAN(("nprobes=%d\n", params
->nprobes
));
3083 WL_SCAN(("active_time=%d\n", params
->active_time
));
3084 WL_SCAN(("passive_time=%d\n", params
->passive_time
));
3085 WL_SCAN(("home_time=%d\n", params
->home_time
));
3086 WL_SCAN(("scan_type=%d\n", params
->scan_type
));
3088 params
->nprobes
= htod32(params
->nprobes
);
3089 params
->active_time
= htod32(params
->active_time
);
3090 params
->passive_time
= htod32(params
->passive_time
);
3091 params
->home_time
= htod32(params
->home_time
);
3093 /* if request is null just exit so it will be all channel broadcast scan */
3097 n_ssids
= request
->n_ssids
;
3098 n_channels
= request
->n_channels
;
3100 /* Copy channel array if applicable */
3101 WL_SCAN(("### List of channelspecs to scan ###\n"));
3102 if (n_channels
> 0) {
3103 for (i
= 0; i
< n_channels
; i
++) {
3104 channel
= ieee80211_frequency_to_channel(request
->channels
[i
]->center_freq
);
3105 /* SKIP DFS channels for Secondary interface */
3106 if ((cfg
->escan_info
.ndev
!= bcmcfg_to_prmry_ndev(cfg
)) &&
3107 (request
->channels
[i
]->flags
&
3108 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
3109 (IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_PASSIVE_SCAN
)))
3111 (IEEE80211_CHAN_RADAR
| IEEE80211_CHAN_NO_IR
)))
3112 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */
3115 chanspec
= WL_CHANSPEC_BW_20
;
3116 if (chanspec
== INVCHANSPEC
) {
3117 WL_ERR(("Invalid chanspec! Skipping channel\n"));
3121 if (request
->channels
[i
]->band
== NL80211_BAND_2GHZ
) {
3122 #ifdef WL_HOST_BAND_MGMT
3123 if (cfg
->curr_band
== WLC_BAND_5G
) {
3124 WL_DBG(("In 5G only mode, omit 2G channel:%d\n", channel
));
3127 #endif /* WL_HOST_BAND_MGMT */
3128 chanspec
|= WL_CHANSPEC_BAND_2G
;
3130 #ifdef WL_HOST_BAND_MGMT
3131 if (cfg
->curr_band
== WLC_BAND_2G
) {
3132 WL_DBG(("In 2G only mode, omit 5G channel:%d\n", channel
));
3135 #endif /* WL_HOST_BAND_MGMT */
3136 chanspec
|= WL_CHANSPEC_BAND_5G
;
3138 params
->channel_list
[j
] = channel
;
3139 params
->channel_list
[j
] &= WL_CHANSPEC_CHAN_MASK
;
3140 params
->channel_list
[j
] |= chanspec
;
3141 WL_SCAN(("Chan : %d, Channel spec: %x \n",
3142 channel
, params
->channel_list
[j
]));
3143 params
->channel_list
[j
] = wl_chspec_host_to_driver(params
->channel_list
[j
]);
3147 WL_SCAN(("Scanning all channels\n"));
3150 /* Copy ssid array if applicable */
3151 WL_SCAN(("### List of SSIDs to scan ###\n"));
3153 offset
= offsetof(wl_scan_params_t
, channel_list
) + n_channels
* sizeof(u16
);
3154 offset
= roundup(offset
, sizeof(u32
));
3155 ptr
= (char*)params
+ offset
;
3156 for (i
= 0; i
< n_ssids
; i
++) {
3157 memset(&ssid
, 0, sizeof(wlc_ssid_t
));
3158 ssid
.SSID_len
= MIN(request
->ssids
[i
].ssid_len
, DOT11_MAX_SSID_LEN
);
3159 memcpy(ssid
.SSID
, request
->ssids
[i
].ssid
, ssid
.SSID_len
);
3161 WL_SCAN(("%d: Broadcast scan\n", i
));
3163 WL_SCAN(("%d: scan for %s size =%d\n", i
,
3164 ssid
.SSID
, ssid
.SSID_len
));
3165 memcpy(ptr
, &ssid
, sizeof(wlc_ssid_t
));
3166 ptr
+= sizeof(wlc_ssid_t
);
3169 WL_SCAN(("Broadcast scan\n"));
3171 /* Adding mask to channel numbers */
3172 params
->channel_num
=
3173 htod32((n_ssids
<< WL_SCAN_PARAMS_NSSID_SHIFT
) |
3174 (n_channels
& WL_SCAN_PARAMS_COUNT_MASK
));
3176 if (n_channels
== 1) {
3177 params
->active_time
= htod32(WL_SCAN_CONNECT_DWELL_TIME_MS
);
3178 params
->nprobes
= htod32(params
->active_time
/ WL_SCAN_JOIN_PROBE_INTERVAL_MS
);
3183 wl_get_valid_channels(struct net_device
*ndev
, u8
*valid_chan_list
, s32 size
)
3185 wl_uint32_list_t
*list
;
3187 if (valid_chan_list
== NULL
|| size
<= 0)
3190 memset(valid_chan_list
, 0, size
);
3191 list
= (wl_uint32_list_t
*)(void *) valid_chan_list
;
3192 list
->count
= htod32(WL_NUMCHANNELS
);
3193 err
= wldev_ioctl_get(ndev
, WLC_GET_VALID_CHANNELS
, valid_chan_list
, size
);
3195 WL_ERR(("get channels failed with %d\n", err
));
3201 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
3202 #define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40
3203 bool g_first_broadcast_scan
= TRUE
;
3204 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
3207 wl_run_escan(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
3208 struct cfg80211_scan_request
*request
, uint16 action
)
3213 s32 params_size
= (WL_SCAN_PARAMS_FIXED_SIZE
+ OFFSETOF(wl_escan_params_t
, params
));
3214 wl_escan_params_t
*params
= NULL
;
3215 u8 chan_buf
[sizeof(u32
)*(WL_NUMCHANNELS
+ 1)];
3219 s32 search_state
= WL_P2P_DISC_ST_SCAN
;
3220 u32 i
, j
, n_nodfs
= 0;
3221 u16
*default_chan_list
= NULL
;
3222 wl_uint32_list_t
*list
;
3224 struct net_device
*dev
= NULL
;
3225 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
3226 bool is_first_init_2g_scan
= false;
3227 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
3228 p2p_scan_purpose_t p2p_scan_purpose
= P2P_SCAN_PURPOSE_MIN
;
3230 #if defined(SUPPORT_RANDOM_MAC_SCAN)
3231 u8 mac_addr
[ETHER_ADDR_LEN
] = {0, };
3232 u8 mac_addr_mask
[ETHER_ADDR_LEN
] = {0, };
3233 #endif /* SUPPORT_RANDOM_MAC_SCAN */
3235 WL_DBG(("Enter \n"));
3237 /* scan request can come with empty request : perform all default scan */
3243 if (!cfg
->p2p_supported
|| !p2p_scan(cfg
)) {
3244 #if defined(SUPPORT_RANDOM_MAC_SCAN)
3245 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
3246 bcopy(request
->mac_addr
, mac_addr
, ETHER_ADDR_LEN
);
3247 bcopy(request
->mac_addr_mask
, mac_addr_mask
, ETHER_ADDR_LEN
);
3248 #else /* Kernel version is less than 3.19.0 */
3249 /* NL80211 default random mac addr and mask value */
3251 mac_addr_mask
[0] = 0x3;
3252 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
3253 if ((request
!= NULL
) && !ETHER_ISNULLADDR(mac_addr
) &&
3254 !ETHER_ISNULLADDR(mac_addr_mask
) &&
3255 !wl_is_wps_enrollee_active(ndev
, request
->ie
, request
->ie_len
)) {
3256 wl_cfg80211_random_mac_enable(ndev
, mac_addr
, mac_addr_mask
);
3258 if (err
== BCME_UNSUPPORTED
) {
3259 /* Ignore if chip doesnt support the feature */
3262 /* For errors other than unsupported fail the scan */
3263 WL_ERR(("%s : failed to set random mac for host scan, %d\n",
3264 __FUNCTION__
, err
));
3270 /* No randmac config provided. Ensure scanmac is disabled */
3271 wl_cfg80211_random_mac_disable(ndev
);
3273 #endif /* SUPPORT_RANDOM_MAC_SCAN */
3275 /* LEGACY SCAN TRIGGER */
3276 WL_SCAN((" LEGACY E-SCAN START\n"));
3278 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
3283 if (ndev
== bcmcfg_to_prmry_ndev(cfg
) && g_first_broadcast_scan
== true) {
3284 #ifdef USE_INITIAL_2G_SCAN
3285 struct ieee80211_channel tmp_channel_list
[CH_MAX_2G_CHANNEL
];
3286 /* allow one 5G channel to add previous connected channel in 5G */
3287 bool allow_one_5g_channel
= TRUE
;
3289 for (i
= 0; i
< request
->n_channels
; i
++) {
3290 int tmp_chan
= ieee80211_frequency_to_channel
3291 (request
->channels
[i
]->center_freq
);
3292 if (tmp_chan
> CH_MAX_2G_CHANNEL
) {
3293 if (allow_one_5g_channel
)
3294 allow_one_5g_channel
= FALSE
;
3298 if (j
> CH_MAX_2G_CHANNEL
) {
3299 WL_ERR(("Index %d exceeds max 2.4GHz channels %d"
3300 " and previous 5G connected channel\n",
3301 j
, CH_MAX_2G_CHANNEL
));
3304 bcopy(request
->channels
[i
], &tmp_channel_list
[j
],
3305 sizeof(struct ieee80211_channel
));
3306 WL_SCAN(("channel of request->channels[%d]=%d\n", i
, tmp_chan
));
3309 if ((j
> 0) && (j
<= CH_MAX_2G_CHANNEL
)) {
3310 for (i
= 0; i
< j
; i
++)
3311 bcopy(&tmp_channel_list
[i
], request
->channels
[i
],
3312 sizeof(struct ieee80211_channel
));
3314 request
->n_channels
= j
;
3315 is_first_init_2g_scan
= true;
3318 WL_ERR(("Invalid number of 2.4GHz channels %d\n", j
));
3320 WL_SCAN(("request->n_channels=%d\n", request
->n_channels
));
3321 #else /* USE_INITIAL_SHORT_DWELL_TIME */
3322 is_first_init_2g_scan
= true;
3323 #endif /* USE_INITIAL_2G_SCAN */
3324 g_first_broadcast_scan
= false;
3326 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
3328 /* if scan request is not empty parse scan request paramters */
3329 if (request
!= NULL
) {
3330 n_channels
= request
->n_channels
;
3331 n_ssids
= request
->n_ssids
;
3333 /* If n_channels is odd, add a padd of u16 */
3334 params_size
+= sizeof(u16
) * (n_channels
+ 1);
3336 params_size
+= sizeof(u16
) * n_channels
;
3338 /* Allocate space for populating ssids in wl_escan_params_t struct */
3339 params_size
+= sizeof(struct wlc_ssid
) * n_ssids
;
3341 params
= (wl_escan_params_t
*)MALLOCZ(cfg
->osh
, params_size
);
3342 if (params
== NULL
) {
3346 wl_scan_prep(cfg
, ¶ms
->params
, request
);
3348 #if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
3349 /* Override active_time to reduce scan time if it's first bradcast scan. */
3350 if (is_first_init_2g_scan
)
3351 params
->params
.active_time
= FIRST_SCAN_ACTIVE_DWELL_TIME_MS
;
3352 #endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
3354 params
->version
= htod32(ESCAN_REQ_VERSION
);
3355 params
->action
= htod16(action
);
3356 wl_escan_set_sync_id(params
->sync_id
, cfg
);
3357 wl_escan_set_type(cfg
, WL_SCANTYPE_LEGACY
);
3358 if (params_size
+ sizeof("escan") >= WLC_IOCTL_MEDLEN
) {
3359 WL_ERR(("ioctl buffer length not sufficient\n"));
3360 MFREE(cfg
->osh
, params
, params_size
);
3364 if (cfg
->active_scan
== PASSIVE_SCAN
) {
3365 params
->params
.scan_type
= DOT11_SCANTYPE_PASSIVE
;
3366 WL_DBG(("Passive scan_type %d \n", params
->params
.scan_type
));
3369 bssidx
= wl_get_bssidx_by_wdev(cfg
, ndev
->ieee80211_ptr
);
3371 err
= wldev_iovar_setbuf(ndev
, "escan", params
, params_size
,
3372 cfg
->escan_ioctl_buf
, WLC_IOCTL_MEDLEN
, NULL
);
3373 WL_INFORM_MEM(("LEGACY_SCAN sync ID: %d, bssidx: %d\n", params
->sync_id
, bssidx
));
3374 if (unlikely(err
)) {
3375 if (err
== BCME_EPERM
)
3376 /* Scan Not permitted at this point of time */
3377 WL_DBG((" Escan not permitted at this time (%d)\n", err
));
3379 WL_ERR((" Escan set error (%d)\n", err
));
3381 DBG_EVENT_LOG((dhd_pub_t
*)cfg
->pub
, WIFI_EVENT_DRIVER_SCAN_REQUESTED
);
3383 MFREE(cfg
->osh
, params
, params_size
);
3385 else if (p2p_is_on(cfg
) && p2p_scan(cfg
)) {
3386 /* P2P SCAN TRIGGER */
3391 if (wl_cfgnan_check_state(cfg
)) {
3392 WL_ERR(("nan is enabled, nan + p2p concurrency not supported\n"));
3393 return BCME_UNSUPPORTED
;
3396 if (request
&& request
->n_channels
) {
3397 num_chans
= request
->n_channels
;
3398 WL_SCAN((" chann number : %d\n", num_chans
));
3399 chan_mem
= (u32
)(num_chans
* sizeof(*default_chan_list
));
3400 default_chan_list
= MALLOCZ(cfg
->osh
, chan_mem
);
3401 if (default_chan_list
== NULL
) {
3402 WL_ERR(("channel list allocation failed \n"));
3406 if (!wl_get_valid_channels(ndev
, chan_buf
, sizeof(chan_buf
))) {
3408 int is_printed
= false;
3409 #endif /* P2P_SKIP_DFS */
3410 list
= (wl_uint32_list_t
*) chan_buf
;
3411 n_valid_chan
= dtoh32(list
->count
);
3412 if (n_valid_chan
> WL_NUMCHANNELS
) {
3413 WL_ERR(("wrong n_valid_chan:%d\n", n_valid_chan
));
3414 MFREE(cfg
->osh
, default_chan_list
, chan_mem
);
3419 for (i
= 0; i
< num_chans
; i
++)
3421 #ifdef WL_HOST_BAND_MGMT
3422 int channel_band
= 0;
3423 #endif /* WL_HOST_BAND_MGMT */
3424 _freq
= request
->channels
[i
]->center_freq
;
3425 channel
= ieee80211_frequency_to_channel(_freq
);
3426 #ifdef WL_HOST_BAND_MGMT
3427 channel_band
= (channel
> CH_MAX_2G_CHANNEL
) ?
3428 WLC_BAND_5G
: WLC_BAND_2G
;
3429 if ((cfg
->curr_band
!= WLC_BAND_AUTO
) &&
3430 (cfg
->curr_band
!= channel_band
) &&
3431 !IS_P2P_SOCIAL_CHANNEL(channel
))
3433 #endif /* WL_HOST_BAND_MGMT */
3435 /* ignore DFS channels */
3436 if (request
->channels
[i
]->flags
&
3437 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
3438 (IEEE80211_CHAN_NO_IR
3439 | IEEE80211_CHAN_RADAR
))
3441 (IEEE80211_CHAN_RADAR
3442 | IEEE80211_CHAN_PASSIVE_SCAN
))
3446 if (channel
>= 52 && channel
<= 144) {
3447 if (is_printed
== false) {
3448 WL_ERR(("SKIP DFS CHANs(52~144)\n"));
3453 #endif /* P2P_SKIP_DFS */
3455 for (j
= 0; j
< n_valid_chan
; j
++) {
3456 /* allows only supported channel on
3459 if (n_nodfs
>= num_chans
) {
3462 if (channel
== (dtoh32(list
->element
[j
]))) {
3463 default_chan_list
[n_nodfs
++] =
3470 if (num_chans
== SOCIAL_CHAN_CNT
&& (
3471 (default_chan_list
[0] == SOCIAL_CHAN_1
) &&
3472 (default_chan_list
[1] == SOCIAL_CHAN_2
) &&
3473 (default_chan_list
[2] == SOCIAL_CHAN_3
))) {
3474 /* SOCIAL CHANNELS 1, 6, 11 */
3475 search_state
= WL_P2P_DISC_ST_SEARCH
;
3476 p2p_scan_purpose
= P2P_SCAN_SOCIAL_CHANNEL
;
3477 WL_DBG(("P2P SEARCH PHASE START \n"));
3478 } else if (((dev
= wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_CONNECTION1
)) &&
3479 (wl_get_mode_by_netdev(cfg
, dev
) == WL_MODE_AP
)) ||
3480 ((dev
= wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_CONNECTION2
)) &&
3481 (wl_get_mode_by_netdev(cfg
, dev
) == WL_MODE_AP
))) {
3482 /* If you are already a GO, then do SEARCH only */
3483 WL_DBG(("Already a GO. Do SEARCH Only"));
3484 search_state
= WL_P2P_DISC_ST_SEARCH
;
3485 num_chans
= n_nodfs
;
3486 p2p_scan_purpose
= P2P_SCAN_NORMAL
;
3488 } else if (num_chans
== 1) {
3489 p2p_scan_purpose
= P2P_SCAN_CONNECT_TRY
;
3490 WL_INFORM_MEM(("Trigger p2p join scan\n"));
3491 } else if (num_chans
== SOCIAL_CHAN_CNT
+ 1) {
3492 /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by
3495 p2p_scan_purpose
= P2P_SCAN_SOCIAL_CHANNEL
;
3497 WL_DBG(("P2P SCAN STATE START \n"));
3498 num_chans
= n_nodfs
;
3499 p2p_scan_purpose
= P2P_SCAN_NORMAL
;
3505 err
= wl_cfgp2p_escan(cfg
, ndev
, ACTIVE_SCAN
, num_chans
, default_chan_list
,
3506 search_state
, action
,
3507 wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
), NULL
,
3511 cfg
->p2p
->search_state
= search_state
;
3513 MFREE(cfg
->osh
, default_chan_list
, chan_mem
);
3516 if (unlikely(err
)) {
3517 /* Don't print Error incase of Scan suppress */
3518 if ((err
== BCME_EPERM
) && cfg
->scan_suppressed
)
3519 WL_DBG(("Escan failed: Scan Suppressed \n"));
3521 WL_ERR(("scan error (%d)\n", err
));
3527 wl_do_escan(struct bcm_cfg80211
*cfg
, struct wiphy
*wiphy
, struct net_device
*ndev
,
3528 struct cfg80211_scan_request
*request
)
3532 s32 passive_scan_time
;
3533 s32 passive_scan_time_org
;
3534 wl_scan_results_t
*results
;
3535 WL_SCAN(("Enter \n"));
3537 results
= wl_escan_get_buf(cfg
, FALSE
);
3538 results
->version
= 0;
3540 results
->buflen
= WL_SCAN_RESULTS_FIXED_SIZE
;
3542 cfg
->escan_info
.ndev
= ndev
;
3543 cfg
->escan_info
.wiphy
= wiphy
;
3544 cfg
->escan_info
.escan_state
= WL_ESCAN_STATE_SCANING
;
3545 passive_scan
= cfg
->active_scan
? 0 : 1;
3546 err
= wldev_ioctl_set(ndev
, WLC_SET_PASSIVE_SCAN
,
3547 &passive_scan
, sizeof(passive_scan
));
3548 if (unlikely(err
)) {
3549 WL_ERR(("error (%d)\n", err
));
3553 if (passive_channel_skip
) {
3555 err
= wldev_ioctl_get(ndev
, WLC_GET_SCAN_PASSIVE_TIME
,
3556 &passive_scan_time_org
, sizeof(passive_scan_time_org
));
3557 if (unlikely(err
)) {
3558 WL_ERR(("== error (%d)\n", err
));
3562 WL_SCAN(("PASSIVE SCAN time : %d \n", passive_scan_time_org
));
3564 passive_scan_time
= 0;
3565 err
= wldev_ioctl_set(ndev
, WLC_SET_SCAN_PASSIVE_TIME
,
3566 &passive_scan_time
, sizeof(passive_scan_time
));
3567 if (unlikely(err
)) {
3568 WL_ERR(("== error (%d)\n", err
));
3572 WL_SCAN(("PASSIVE SCAN SKIPED!! (passive_channel_skip:%d) \n",
3573 passive_channel_skip
));
3576 err
= wl_run_escan(cfg
, ndev
, request
, WL_SCAN_ACTION_START
);
3578 if (passive_channel_skip
) {
3579 err
= wldev_ioctl_set(ndev
, WLC_SET_SCAN_PASSIVE_TIME
,
3580 &passive_scan_time_org
, sizeof(passive_scan_time_org
));
3581 if (unlikely(err
)) {
3582 WL_ERR(("== error (%d)\n", err
));
3586 WL_SCAN(("PASSIVE SCAN RECOVERED!! (passive_scan_time_org:%d) \n",
3587 passive_scan_time_org
));
3595 __wl_cfg80211_scan(struct wiphy
*wiphy
, struct net_device
*ndev
,
3596 struct cfg80211_scan_request
*request
,
3597 struct cfg80211_ssid
*this_ssid
)
3599 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3600 struct cfg80211_ssid
*ssids
;
3601 struct ether_addr primary_mac
;
3604 bcm_tlv_t
*interworking_ie
;
3610 unsigned long flags
;
3611 static s32 busy_count
= 0;
3612 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
3613 struct net_device
*remain_on_channel_ndev
= NULL
;
3616 * Hostapd triggers scan before starting automatic channel selection
3617 * to collect channel characteristics. However firmware scan engine
3618 * doesn't support any channel characteristics collection along with
3619 * scan. Hence return scan success.
3621 if (request
&& (scan_req_iftype(request
) == NL80211_IFTYPE_AP
)) {
3622 WL_DBG(("Scan Command on SoftAP Interface. Ignoring...\n"));
3626 ndev
= ndev_to_wlc_ndev(ndev
, cfg
);
3628 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg
)) {
3629 WL_ERR(("Sending Action Frames. Try it again.\n"));
3633 WL_DBG(("Enter wiphy (%p)\n", wiphy
));
3634 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
3635 if (cfg
->scan_request
== NULL
) {
3636 wl_clr_drv_status_all(cfg
, SCANNING
);
3637 WL_DBG(("<<<<<<<<<<<Force Clear Scanning Status>>>>>>>>>>>\n"));
3639 WL_ERR(("Scanning already\n"));
3643 if (wl_get_drv_status(cfg
, SCAN_ABORTING
, ndev
)) {
3644 WL_ERR(("Scanning being aborted\n"));
3647 if (request
&& request
->n_ssids
> WL_SCAN_PARAMS_SSID_MAX
) {
3648 WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
3652 /* check fakeapscan in progress then abort */
3653 wl_android_bcnrecv_stop(ndev
, WL_BCNRECV_SCANBUSY
);
3654 #endif /* WL_BCNRECV */
3656 #ifdef P2P_LISTEN_OFFLOADING
3657 if (wl_get_p2p_status(cfg
, DISC_IN_PROGRESS
)) {
3658 WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
3661 #endif /* P2P_LISTEN_OFFLOADING */
3663 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
3664 remain_on_channel_ndev
= wl_cfg80211_get_remain_on_channel_ndev(cfg
);
3665 if (remain_on_channel_ndev
) {
3666 WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n"));
3667 wl_notify_escan_complete(cfg
, remain_on_channel_ndev
, true, true);
3669 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
3671 if (request
) { /* scan bss */
3672 ssids
= request
->ssids
;
3674 for (i
= 0; i
< request
->n_ssids
; i
++) {
3675 if (ssids
[i
].ssid_len
&&
3676 IS_P2P_SSID(ssids
[i
].ssid
, ssids
[i
].ssid_len
)) {
3682 if (cfg
->p2p_supported
) {
3684 if (cfg
->nan_enable
) {
3685 err
= wl_cfgnan_disable(cfg
, NAN_CONCURRENCY_CONFLICT
);
3686 if (err
!= BCME_OK
) {
3687 WL_ERR(("failed to disable nan, error[%d]\n", err
));
3692 /* p2p scan trigger */
3693 if (p2p_on(cfg
) == false) {
3694 /* p2p on at the first time */
3696 wl_cfgp2p_set_firm_p2p(cfg
);
3697 get_primary_mac(cfg
, &primary_mac
);
3698 wl_cfgp2p_generate_bss_mac(cfg
, &primary_mac
);
3699 #if defined(P2P_IE_MISSING_FIX)
3700 cfg
->p2p_prb_noti
= false;
3703 wl_clr_p2p_status(cfg
, GO_NEG_PHASE
);
3704 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
3705 p2p_scan(cfg
) = true;
3708 /* legacy scan trigger
3709 * So, we have to disable p2p discovery if p2p discovery is on
3711 if (cfg
->p2p_supported
) {
3712 p2p_scan(cfg
) = false;
3713 /* If Netdevice is not equals to primary and p2p is on
3714 * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
3717 if (p2p_scan(cfg
) == false) {
3718 if (wl_get_p2p_status(cfg
, DISCOVERY_ON
)) {
3719 err
= wl_cfgp2p_discover_enable_search(cfg
,
3721 if (unlikely(err
)) {
3728 if (!cfg
->p2p_supported
|| !p2p_scan(cfg
)) {
3729 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
,
3730 ndev
->ieee80211_ptr
)) < 0) {
3731 WL_ERR(("Find p2p index from ndev(%p) failed\n",
3737 if (request
&& (interworking_ie
= wl_cfg80211_find_interworking_ie(
3738 request
->ie
, request
->ie_len
)) != NULL
) {
3739 if ((err
= wl_cfg80211_add_iw_ie(cfg
, ndev
, bssidx
,
3740 VNDR_IE_CUSTOM_FLAG
, interworking_ie
->id
,
3741 interworking_ie
->data
,
3742 interworking_ie
->len
)) != BCME_OK
) {
3743 WL_ERR(("Failed to add interworking IE"));
3745 } else if (cfg
->wl11u
) {
3746 /* we have to clear IW IE and disable gratuitous APR */
3747 wl_cfg80211_clear_iw_ie(cfg
, ndev
, bssidx
);
3748 err
= wldev_iovar_setint_bsscfg(ndev
, "grat_arp",
3750 /* we don't care about error here
3751 * because the only failure case is unsupported,
3754 if (unlikely(err
)) {
3755 WL_ERR(("Set grat_arp failed:(%d) Ignore!\n", err
));
3761 err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
,
3762 ndev_to_cfgdev(ndev
), bssidx
, VNDR_IE_PRBREQ_FLAG
,
3763 request
->ie
, request
->ie_len
);
3766 if (unlikely(err
)) {
3772 } else { /* scan in ibss */
3776 if (request
&& cfg
->p2p_supported
) {
3777 WL_TRACE_HW4(("START SCAN\n"));
3778 DHD_OS_SCAN_WAKE_LOCK_TIMEOUT((dhd_pub_t
*)(cfg
->pub
),
3779 SCAN_WAKE_LOCK_TIMEOUT
);
3780 DHD_DISABLE_RUNTIME_PM((dhd_pub_t
*)(cfg
->pub
));
3783 if (cfg
->p2p_supported
) {
3784 if (request
&& p2p_on(cfg
) && p2p_scan(cfg
)) {
3786 /* find my listen channel */
3787 cfg
->afx_hdl
->my_listen_chan
=
3788 wl_find_listen_channel(cfg
, request
->ie
,
3790 err
= wl_cfgp2p_enable_discovery(cfg
, ndev
,
3791 request
->ie
, request
->ie_len
);
3793 if (unlikely(err
)) {
3798 err
= wl_do_escan(cfg
, wiphy
, ndev
, request
);
3806 cfg
->scan_request
= request
;
3807 wl_set_drv_status(cfg
, SCANNING
, ndev
);
3812 if (err
== BCME_BUSY
|| err
== BCME_NOTREADY
) {
3813 WL_ERR(("Scan err = (%d), busy?%d", err
, -EBUSY
));
3815 } else if ((err
== BCME_EPERM
) && cfg
->scan_suppressed
) {
3816 WL_ERR(("Scan not permitted due to scan suppress\n"));
3819 /* For all other fw errors, use a generic error code as return
3820 * value to cfg80211 stack
3825 #define SCAN_EBUSY_RETRY_LIMIT 20
3826 if (err
== -EBUSY
) {
3827 /* Flush FW preserve buffer logs for checking failure */
3828 if (busy_count
++ > (SCAN_EBUSY_RETRY_LIMIT
/5)) {
3829 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
3831 if (busy_count
> SCAN_EBUSY_RETRY_LIMIT
) {
3832 struct ether_addr bssid
;
3834 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
3835 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
3836 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
3838 WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n",
3839 wl_get_drv_status(cfg
, SCANNING
, ndev
),
3840 wl_get_drv_status(cfg
, SCAN_ABORTING
, ndev
),
3841 wl_get_drv_status(cfg
, CONNECTING
, ndev
),
3842 wl_get_drv_status(cfg
, CONNECTED
, ndev
),
3843 wl_get_drv_status(cfg
, DISCONNECTING
, ndev
),
3844 wl_get_drv_status(cfg
, AP_CREATING
, ndev
),
3845 wl_get_drv_status(cfg
, AP_CREATED
, ndev
),
3846 wl_get_drv_status(cfg
, SENDING_ACT_FRM
, ndev
),
3847 wl_get_drv_status(cfg
, SENDING_ACT_FRM
, ndev
)));
3849 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
3850 if (dhdp
->memdump_enabled
) {
3851 dhdp
->memdump_type
= DUMP_TYPE_SCAN_BUSY
;
3852 dhd_bus_mem_dump(dhdp
);
3854 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
3856 bzero(&bssid
, sizeof(bssid
));
3857 if ((ret
= wldev_ioctl_get(ndev
, WLC_GET_BSSID
,
3858 &bssid
, ETHER_ADDR_LEN
)) == 0) {
3859 WL_ERR(("FW is connected with " MACDBG
"/n",
3860 MAC2STRDBG(bssid
.octet
)));
3862 WL_ERR(("GET BSSID failed with %d\n", ret
));
3865 wl_cfg80211_scan_abort(cfg
);
3868 /* Hold the context for 400msec, so that 10 subsequent scans
3869 * can give a buffer of 4sec which is enough to
3870 * cover any on-going scan in the firmware
3872 WL_DBG(("Enforcing delay for EBUSY case \n"));
3879 wl_clr_drv_status(cfg
, SCANNING
, ndev
);
3880 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t
*)(cfg
->pub
));
3881 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
3882 cfg
->scan_request
= NULL
;
3883 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
3889 wl_get_scan_timeout_val(struct bcm_cfg80211
*cfg
)
3891 u32 scan_timer_interval_ms
= WL_SCAN_TIMER_INTERVAL_MS
;
3894 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
3895 if ((cfg
->custom_scan_channel_time
> DHD_SCAN_ASSOC_ACTIVE_TIME
) |
3896 (cfg
->custom_scan_unassoc_time
> DHD_SCAN_UNASSOC_ACTIVE_TIME
) |
3897 (cfg
->custom_scan_passive_time
> DHD_SCAN_PASSIVE_TIME
) |
3898 (cfg
->custom_scan_home_time
> DHD_SCAN_HOME_TIME
) |
3899 (cfg
->custom_scan_home_away_time
> DHD_SCAN_HOME_AWAY_TIME
)) {
3900 scan_timer_interval_ms
= CUSTOMER_WL_SCAN_TIMER_INTERVAL_MS
;
3902 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
3903 #endif /* WES_SUPPORT */
3905 /* If NAN is enabled adding +10 sec to the existing timeout value */
3907 if (cfg
->nan_enable
) {
3908 scan_timer_interval_ms
+= WL_SCAN_TIMER_INTERVAL_MS_NAN
;
3911 WL_INFORM(("scan_timer_interval_ms %d\n", scan_timer_interval_ms
));
3912 return scan_timer_interval_ms
;
3915 #if defined(WL_CFG80211_P2P_DEV_IF)
3917 wl_cfg80211_scan(struct wiphy
*wiphy
, struct cfg80211_scan_request
*request
)
3920 wl_cfg80211_scan(struct wiphy
*wiphy
, struct net_device
*ndev
,
3921 struct cfg80211_scan_request
*request
)
3922 #endif /* WL_CFG80211_P2P_DEV_IF */
3925 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3926 #if defined(WL_CFG80211_P2P_DEV_IF)
3927 struct net_device
*ndev
= wdev_to_wlc_ndev(request
->wdev
, cfg
);
3928 #endif /* WL_CFG80211_P2P_DEV_IF */
3930 WL_DBG(("Enter\n"));
3931 RETURN_EIO_IF_NOT_UP(cfg
);
3934 #ifdef WL_CFG80211_P2P_DEV_IF
3935 PRINT_WDEV_INFO(request
->wdev
);
3937 PRINT_WDEV_INFO(ndev
);
3938 #endif /* WL_CFG80211_P2P_DEV_IF */
3939 #endif /* DHD_IFDEBUG */
3941 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
3942 if (wl_cfg_multip2p_operational(cfg
)) {
3943 WL_ERR(("wlan0 scan failed, p2p devices are operational"));
3948 mutex_lock(&cfg
->scan_sync
);
3949 err
= __wl_cfg80211_scan(wiphy
, ndev
, request
, NULL
);
3950 if (unlikely(err
)) {
3951 WL_ERR(("scan error (%d)\n", err
));
3954 mod_timer(&cfg
->scan_timeout
,
3955 jiffies
+ msecs_to_jiffies(wl_get_scan_timeout_val(cfg
)));
3957 mutex_unlock(&cfg
->scan_sync
);
3958 #ifdef WL_DRV_AVOID_SCANCACHE
3959 /* Reset roam cache after successful scan request */
3960 #ifdef ROAM_CHANNEL_CACHE
3962 reset_roam_cache(cfg
);
3964 #endif /* ROAM_CHANNEL_CACHE */
3965 #endif /* WL_DRV_AVOID_SCANCACHE */
3969 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
3971 wl_cfg80211_abort_scan(struct wiphy
*wiphy
, struct wireless_dev
*wdev
)
3973 struct bcm_cfg80211
*cfg
;
3975 WL_DBG(("Enter %s\n", __FUNCTION__
));
3976 cfg
= wiphy_priv(wdev
->wiphy
);
3978 /* Check if any scan in progress only then abort */
3979 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
3980 wl_cfg80211_scan_abort(cfg
);
3981 /* Only scan abort is issued here. As per the expectation of abort_scan
3982 * the status of abort is needed to be communicated using cfg80211_scan_done call.
3983 * Here we just issue abort request and let the scan complete path to indicate
3984 * abort to cfg80211 layer.
3986 WL_DBG(("%s: Scan abort issued to FW\n", __FUNCTION__
));
3989 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
3991 static s32
wl_set_rts(struct net_device
*dev
, u32 rts_threshold
)
3995 err
= wldev_iovar_setint(dev
, "rtsthresh", rts_threshold
);
3996 if (unlikely(err
)) {
3997 WL_ERR(("Error (%d)\n", err
));
4003 static s32
wl_set_frag(struct net_device
*dev
, u32 frag_threshold
)
4007 err
= wldev_iovar_setint_bsscfg(dev
, "fragthresh", frag_threshold
, 0);
4008 if (unlikely(err
)) {
4009 WL_ERR(("Error (%d)\n", err
));
4015 static s32
wl_set_retry(struct net_device
*dev
, u32 retry
, bool l
)
4018 u32 cmd
= (l
? WLC_SET_LRL
: WLC_SET_SRL
);
4020 #ifdef CUSTOM_LONG_RETRY_LIMIT
4021 if ((cmd
== WLC_SET_LRL
) &&
4022 (retry
!= CUSTOM_LONG_RETRY_LIMIT
)) {
4023 WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
4026 #endif /* CUSTOM_LONG_RETRY_LIMIT */
4028 retry
= htod32(retry
);
4029 err
= wldev_ioctl_set(dev
, cmd
, &retry
, sizeof(retry
));
4030 if (unlikely(err
)) {
4031 WL_ERR(("cmd (%d) , error (%d)\n", cmd
, err
));
4037 static s32
wl_cfg80211_set_wiphy_params(struct wiphy
*wiphy
, u32 changed
)
4039 struct bcm_cfg80211
*cfg
= (struct bcm_cfg80211
*)wiphy_priv(wiphy
);
4040 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
4043 RETURN_EIO_IF_NOT_UP(cfg
);
4044 WL_DBG(("Enter\n"));
4045 if (changed
& WIPHY_PARAM_RTS_THRESHOLD
&&
4046 (cfg
->conf
->rts_threshold
!= wiphy
->rts_threshold
)) {
4047 cfg
->conf
->rts_threshold
= wiphy
->rts_threshold
;
4048 err
= wl_set_rts(ndev
, cfg
->conf
->rts_threshold
);
4052 if (changed
& WIPHY_PARAM_FRAG_THRESHOLD
&&
4053 (cfg
->conf
->frag_threshold
!= wiphy
->frag_threshold
)) {
4054 cfg
->conf
->frag_threshold
= wiphy
->frag_threshold
;
4055 err
= wl_set_frag(ndev
, cfg
->conf
->frag_threshold
);
4059 if (changed
& WIPHY_PARAM_RETRY_LONG
&&
4060 (cfg
->conf
->retry_long
!= wiphy
->retry_long
)) {
4061 cfg
->conf
->retry_long
= wiphy
->retry_long
;
4062 err
= wl_set_retry(ndev
, cfg
->conf
->retry_long
, true);
4066 if (changed
& WIPHY_PARAM_RETRY_SHORT
&&
4067 (cfg
->conf
->retry_short
!= wiphy
->retry_short
)) {
4068 cfg
->conf
->retry_short
= wiphy
->retry_short
;
4069 err
= wl_set_retry(ndev
, cfg
->conf
->retry_short
, false);
4070 if (err
!= BCME_OK
) {
4078 channel_to_chanspec(struct wiphy
*wiphy
, struct net_device
*dev
, u32 channel
, u32 bw_cap
)
4080 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
4082 wl_uint32_list_t
*list
;
4084 chanspec_t c
= 0, ret_c
= 0;
4085 int bw
= 0, tmp_bw
= 0;
4088 #define LOCAL_BUF_SIZE 1024
4089 buf
= (u8
*)MALLOC(cfg
->osh
, LOCAL_BUF_SIZE
);
4091 WL_ERR(("buf memory alloc failed\n"));
4095 err
= wldev_iovar_getbuf_bsscfg(dev
, "chanspecs", NULL
,
4096 0, buf
, LOCAL_BUF_SIZE
, 0, &cfg
->ioctl_buf_sync
);
4097 if (err
!= BCME_OK
) {
4098 WL_ERR(("get chanspecs failed with %d\n", err
));
4102 list
= (wl_uint32_list_t
*)(void *)buf
;
4103 for (i
= 0; i
< dtoh32(list
->count
); i
++) {
4104 c
= dtoh32(list
->element
[i
]);
4105 if (channel
<= CH_MAX_2G_CHANNEL
) {
4106 if (!CHSPEC_IS20(c
))
4108 if (channel
== CHSPEC_CHANNEL(c
)) {
4114 tmp_c
= wf_chspec_ctlchan(c
);
4115 tmp_bw
= bw2cap
[CHSPEC_BW(c
) >> WL_CHANSPEC_BW_SHIFT
];
4116 if (tmp_c
!= channel
)
4119 if ((tmp_bw
> bw
) && (tmp_bw
<= bw_cap
)) {
4128 MFREE(cfg
->osh
, buf
, LOCAL_BUF_SIZE
);
4130 #undef LOCAL_BUF_SIZE
4131 WL_DBG(("return chanspec %x %d\n", ret_c
, bw
));
4136 wl_cfg80211_ibss_vsie_set_buffer(struct net_device
*dev
, vndr_ie_setbuf_t
*ibss_vsie
,
4139 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
4141 if (cfg
!= NULL
&& ibss_vsie
!= NULL
) {
4142 if (cfg
->ibss_vsie
!= NULL
) {
4143 MFREE(cfg
->osh
, cfg
->ibss_vsie
, cfg
->ibss_vsie_len
);
4145 cfg
->ibss_vsie
= ibss_vsie
;
4146 cfg
->ibss_vsie_len
= ibss_vsie_len
;
4151 wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211
*cfg
)
4153 /* free & initiralize VSIE (Vendor Specific IE) */
4154 if (cfg
->ibss_vsie
!= NULL
) {
4155 MFREE(cfg
->osh
, cfg
->ibss_vsie
, cfg
->ibss_vsie_len
);
4156 cfg
->ibss_vsie
= NULL
;
4157 cfg
->ibss_vsie_len
= 0;
4162 wl_cfg80211_ibss_vsie_delete(struct net_device
*dev
)
4164 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
4165 char *ioctl_buf
= NULL
;
4166 s32 ret
= BCME_OK
, bssidx
;
4168 if (cfg
!= NULL
&& cfg
->ibss_vsie
!= NULL
) {
4169 ioctl_buf
= (char *)MALLOC(cfg
->osh
, WLC_IOCTL_MEDLEN
);
4171 WL_ERR(("ioctl memory alloc failed\n"));
4174 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
4175 WL_ERR(("Find index failed\n"));
4179 /* change the command from "add" to "del" */
4180 strncpy(cfg
->ibss_vsie
->cmd
, "del", VNDR_IE_CMD_LEN
- 1);
4181 cfg
->ibss_vsie
->cmd
[VNDR_IE_CMD_LEN
- 1] = '\0';
4183 ret
= wldev_iovar_setbuf_bsscfg(dev
, "vndr_ie",
4184 cfg
->ibss_vsie
, cfg
->ibss_vsie_len
,
4185 ioctl_buf
, WLC_IOCTL_MEDLEN
, bssidx
, NULL
);
4186 WL_ERR(("ret=%d\n", ret
));
4188 if (ret
== BCME_OK
) {
4189 /* free & initialize VSIE */
4190 MFREE(cfg
->osh
, cfg
->ibss_vsie
, cfg
->ibss_vsie_len
);
4191 cfg
->ibss_vsie
= NULL
;
4192 cfg
->ibss_vsie_len
= 0;
4196 MFREE(cfg
->osh
, ioctl_buf
, WLC_IOCTL_MEDLEN
);
4203 #ifdef WLAIBSS_MCHAN
4204 static bcm_struct_cfgdev
*
4205 bcm_cfg80211_add_ibss_if(struct wiphy
*wiphy
, char *name
)
4208 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
4209 struct wireless_dev
* wdev
= NULL
;
4210 struct net_device
*new_ndev
= NULL
;
4211 struct net_device
*primary_ndev
= NULL
;
4213 wl_aibss_if_t aibss_if
;
4214 wl_if_event_info
*event
= NULL
;
4216 if (cfg
->ibss_cfgdev
!= NULL
) {
4217 WL_ERR(("IBSS interface %s already exists\n", name
));
4221 WL_ERR(("Try to create IBSS interface %s\n", name
));
4222 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
4223 /* generate a new MAC address for the IBSS interface */
4224 get_primary_mac(cfg
, &cfg
->ibss_if_addr
);
4225 cfg
->ibss_if_addr
.octet
[4] ^= 0x40;
4226 memset(&aibss_if
, sizeof(aibss_if
), 0);
4227 memcpy(&aibss_if
.addr
, &cfg
->ibss_if_addr
, sizeof(aibss_if
.addr
));
4228 aibss_if
.chspec
= 0;
4229 aibss_if
.len
= sizeof(aibss_if
);
4231 cfg
->bss_pending_op
= TRUE
;
4232 memset(&cfg
->if_event_info
, 0, sizeof(cfg
->if_event_info
));
4233 err
= wldev_iovar_setbuf(primary_ndev
, "aibss_ifadd", &aibss_if
,
4234 sizeof(aibss_if
), cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
4236 WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err
));
4239 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
4240 !cfg
->bss_pending_op
, msecs_to_jiffies(MAX_WAIT_TIME
));
4241 if (timeout
<= 0 || cfg
->bss_pending_op
)
4244 event
= &cfg
->if_event_info
;
4245 /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
4246 * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
4247 * and will be freed by dhd_detach unless it gets unregistered before that. The
4248 * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
4249 * be freed by wl_dealloc_netinfo
4251 new_ndev
= wl_cfg80211_allocate_if(cfg
, event
->ifidx
, event
->name
,
4252 event
->mac
, event
->bssidx
, event
->name
);
4253 if (new_ndev
== NULL
)
4255 wdev
= (struct wireless_dev
*)MALLOCZ(cfg
->osh
, sizeof(*wdev
));
4258 wdev
->wiphy
= wiphy
;
4259 wdev
->iftype
= NL80211_IFTYPE_ADHOC
;
4260 wdev
->netdev
= new_ndev
;
4261 new_ndev
->ieee80211_ptr
= wdev
;
4262 SET_NETDEV_DEV(new_ndev
, wiphy_dev(wdev
->wiphy
));
4264 /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
4265 * needs to be modified to take one parameter (bool need_rtnl_lock)
4268 if (wl_cfg80211_register_if(cfg
, event
->ifidx
, new_ndev
, FALSE
) != BCME_OK
)
4271 wl_alloc_netinfo(cfg
, new_ndev
, wdev
, WL_IF_TYPE_IBSS
,
4272 PM_ENABLE
, event
->bssidx
, event
->ifidx
);
4273 cfg
->ibss_cfgdev
= ndev_to_cfgdev(new_ndev
);
4274 WL_ERR(("IBSS interface %s created\n", new_ndev
->name
));
4275 return cfg
->ibss_cfgdev
;
4278 WL_ERR(("failed to create IBSS interface %s \n", name
));
4279 cfg
->bss_pending_op
= FALSE
;
4281 wl_cfg80211_remove_if(cfg
, event
->ifidx
, new_ndev
, FALSE
);
4283 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
4289 bcm_cfg80211_del_ibss_if(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
)
4292 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
4293 struct net_device
*ndev
= NULL
;
4294 struct net_device
*primary_ndev
= NULL
;
4297 if (!cfgdev
|| cfg
->ibss_cfgdev
!= cfgdev
|| ETHER_ISNULLADDR(&cfg
->ibss_if_addr
.octet
))
4299 ndev
= (struct net_device
*)cfgdev_to_ndev(cfg
->ibss_cfgdev
);
4300 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
4302 cfg
->bss_pending_op
= TRUE
;
4303 memset(&cfg
->if_event_info
, 0, sizeof(cfg
->if_event_info
));
4304 err
= wldev_iovar_setbuf(primary_ndev
, "aibss_ifdel", &cfg
->ibss_if_addr
,
4305 sizeof(cfg
->ibss_if_addr
), cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
4307 WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err
));
4310 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
4311 !cfg
->bss_pending_op
, msecs_to_jiffies(MAX_WAIT_TIME
));
4312 if (timeout
<= 0 || cfg
->bss_pending_op
) {
4313 WL_ERR(("timeout in waiting IF_DEL event\n"));
4317 wl_cfg80211_remove_if(cfg
, cfg
->if_event_info
.ifidx
, ndev
, FALSE
);
4318 cfg
->ibss_cfgdev
= NULL
;
4322 cfg
->bss_pending_op
= FALSE
;
4325 #endif /* WLAIBSS_MCHAN */
4328 wl_cfg80211_to_fw_iftype(wl_iftype_t iftype
)
4330 s32 ret
= BCME_ERROR
;
4334 ret
= WL_INTERFACE_TYPE_AP
;
4336 case WL_IF_TYPE_STA
:
4337 ret
= WL_INTERFACE_TYPE_STA
;
4339 case WL_IF_TYPE_NAN_NMI
:
4340 case WL_IF_TYPE_NAN
:
4341 ret
= WL_INTERFACE_TYPE_NAN
;
4343 case WL_IF_TYPE_P2P_DISC
:
4344 ret
= WL_INTERFACE_TYPE_P2P_DISC
;
4346 case WL_IF_TYPE_P2P_GO
:
4347 ret
= WL_INTERFACE_TYPE_P2P_GO
;
4349 case WL_IF_TYPE_P2P_GC
:
4350 ret
= WL_INTERFACE_TYPE_P2P_GC
;
4352 case WL_IF_TYPE_AWDL
:
4353 ret
= WL_INTERFACE_TYPE_AWDL
;
4357 WL_ERR(("Unsupported type:%d \n", iftype
));
4366 wl_legacy_chip_check(struct bcm_cfg80211
*cfg
)
4369 #if defined(BCMSDIO) || defined(BCMPCIE)
4370 u32 chipid
, chiprevid
;
4371 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
4373 chipid
= dhd_bus_chip_id(dhdp
);
4374 chiprevid
= dhd_bus_chiprev_id(dhdp
);
4375 WL_DBG(("chipid=0x%x, chiprevid=%x\n", chipid
, chiprevid
));
4376 if (chipid
== BCM4350_CHIP_ID
|| chipid
== BCM4345_CHIP_ID
) {
4381 #endif /* BCMSDIO || BCMPCIE */
4387 wl_check_interface_create_v0(struct bcm_cfg80211
*cfg
)
4390 #if defined(BCMSDIO) || defined(BCMPCIE)
4391 u32 chipid
, chiprevid
;
4392 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
4394 chipid
= dhd_bus_chip_id(dhdp
);
4395 chiprevid
= dhd_bus_chiprev_id(dhdp
);
4396 WL_DBG(("chipid=0x%x, chiprevid=%x\n", chipid
, chiprevid
));
4398 if (chipid
== BCM4359_CHIP_ID
&&
4399 (chiprevid
== 5 || chiprevid
== 9)) {
4402 #endif /* BCMSDIO || BCMPCIE */
4406 #endif /* CUSTOMER_HW4 */
4409 wl_cfg80211_interface_ops(struct bcm_cfg80211
*cfg
,
4410 struct net_device
*ndev
, s32 bsscfg_idx
,
4411 wl_iftype_t cfg_iftype
, s32 del
, u8
*addr
)
4414 wl_interface_create_v2_t iface
;
4415 wl_interface_create_v3_t iface_v3
;
4416 wl_interface_info_v1_t
*info
;
4417 wl_interface_info_v2_t
*info_v2
;
4419 bool use_iface_info_v2
= false;
4420 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
4423 wl_interface_info_v0_t
*info_v0
;
4424 bool use_iface_info_v0
= false;
4425 #endif /* CUSTOMER_HW4 */
4428 ret
= wldev_iovar_setbuf(ndev
, "interface_remove",
4429 NULL
, 0, ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4431 WL_ERR(("Interface remove failed!! ret %d\n", ret
));
4435 /* Interface create */
4436 bzero(&iface
, sizeof(iface
));
4439 * flags field is still used along with iftype inorder to support the old version of the
4440 * FW work with the latest app changes.
4443 iftype
= wl_cfg80211_to_fw_iftype(cfg_iftype
);
4449 ifflags
|= WL_INTERFACE_MAC_USE
;
4453 /* BCM4359B0/C0 chips are using the iovar version 0 */
4454 if (wl_check_interface_create_v0(cfg
)) {
4455 wl_interface_create_v0_t iface_v0
;
4457 WL_DBG(("interface_create version 0\n"));
4458 bzero(&iface_v0
, sizeof(iface_v0
));
4459 use_iface_info_v0
= true;
4460 iface_v0
.ver
= WL_INTERFACE_CREATE_VER_0
;
4461 iface_v0
.flags
= ifflags
;
4463 memcpy(&iface_v0
.mac_addr
.octet
, addr
, ETH_ALEN
);
4465 ret
= wldev_iovar_getbuf(ndev
, "interface_create",
4466 &iface_v0
, sizeof(wl_interface_create_v0_t
),
4467 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4469 #endif /* CUSTOMER_HW4 */
4471 /* Pass ver = 0 for fetching the interface_create iovar version */
4472 ret
= wldev_iovar_getbuf(ndev
, "interface_create",
4473 &iface
, sizeof(struct wl_interface_create_v2
),
4474 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4475 if (ret
== BCME_UNSUPPORTED
) {
4476 WL_ERR(("interface_create iovar not supported\n"));
4478 } else if ((ret
== 0) && *((uint32
*)ioctl_buf
) == WL_INTERFACE_CREATE_VER_3
) {
4479 WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags
));
4480 use_iface_info_v2
= true;
4481 bzero(&iface_v3
, sizeof(wl_interface_create_v3_t
));
4482 iface_v3
.ver
= WL_INTERFACE_CREATE_VER_3
;
4483 iface_v3
.iftype
= iftype
;
4484 iface_v3
.flags
= ifflags
;
4486 memcpy(&iface_v3
.mac_addr
.octet
, addr
, ETH_ALEN
);
4488 ret
= wldev_iovar_getbuf(ndev
, "interface_create",
4489 &iface_v3
, sizeof(wl_interface_create_v3_t
),
4490 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4492 /* On any other error, attempt with iovar version 2 */
4493 WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n",
4495 iface
.ver
= WL_INTERFACE_CREATE_VER_2
;
4496 iface
.iftype
= iftype
;
4497 iface
.flags
= ifflags
;
4499 memcpy(&iface
.mac_addr
.octet
, addr
, ETH_ALEN
);
4501 ret
= wldev_iovar_getbuf(ndev
, "interface_create",
4502 &iface
, sizeof(struct wl_interface_create_v2
),
4503 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
4507 if (unlikely(ret
)) {
4508 WL_ERR(("Interface create failed!! ret %d\n", ret
));
4513 if (use_iface_info_v2
== true) {
4514 info_v2
= (wl_interface_info_v2_t
*)ioctl_buf
;
4515 ret
= info_v2
->bsscfgidx
;
4518 else if (use_iface_info_v0
== true) {
4520 info_v0
= (wl_interface_info_v0_t
*)ioctl_buf
;
4521 ret
= info_v0
->bsscfgidx
;
4523 #endif /* CUSTOMER_HW4 */
4526 info
= (struct wl_interface_info_v1
*)ioctl_buf
;
4527 ret
= info
->bsscfgidx
;
4530 WL_DBG(("wl interface create success!! bssidx:%d \n", ret
));
4534 #if defined(CUSTOMER_HW4)
4536 wl_bss_iovar_war(struct bcm_cfg80211
*cfg
,
4537 struct net_device
*ndev
, s32
*val
)
4539 if (wl_legacy_chip_check(cfg
) || wl_check_interface_create_v0(cfg
))
4541 /* Few firmware branches have issues in bss iovar handling and
4542 * that can't be changed since they are in production.
4544 if (*val
== WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE
) {
4545 *val
= WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE
;
4546 } else if (*val
== WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE
) {
4547 *val
= WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE
;
4549 /* Ignore for other bss enums */
4552 WL_ERR(("wl bss %d\n", *val
));
4558 wl_cfg80211_add_del_bss(struct bcm_cfg80211
*cfg
,
4559 struct net_device
*ndev
, s32 bsscfg_idx
,
4560 wl_iftype_t brcm_iftype
, s32 del
, u8
*addr
)
4568 struct ether_addr ea
;
4571 WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype
, del
));
4573 bzero(&bss_setbuf
, sizeof(bss_setbuf
));
4575 /* AP=2, STA=3, up=1, down=0, val=-1 */
4577 val
= WLC_AP_IOV_OP_DELETE
;
4578 } else if (brcm_iftype
== WL_IF_TYPE_AP
) {
4579 /* Add/role change to AP Interface */
4580 WL_DBG(("Adding AP Interface \n"));
4581 val
= WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE
;
4582 } else if (brcm_iftype
== WL_IF_TYPE_STA
) {
4583 /* Add/role change to STA Interface */
4584 WL_DBG(("Adding STA Interface \n"));
4585 val
= WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE
;
4587 WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype
));
4591 #if defined(CUSTOMER_HW4)
4593 wl_bss_iovar_war(cfg
, ndev
, &val
);
4597 bss_setbuf
.cfg
= htod32(bsscfg_idx
);
4598 bss_setbuf
.val
= htod32(val
);
4601 memcpy(&bss_setbuf
.ea
.octet
, addr
, ETH_ALEN
);
4604 WL_INFORM_MEM(("wl bss %d bssidx:%d iface:%s \n", val
, bsscfg_idx
, ndev
->name
));
4605 ret
= wldev_iovar_setbuf(ndev
, "bss", &bss_setbuf
, sizeof(bss_setbuf
),
4606 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
4608 WL_ERR(("'bss %d' failed with %d\n", val
, ret
));
4614 wl_cfg80211_bss_up(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, s32 bsscfg_idx
, s32 bss_up
)
4617 s32 val
= bss_up
? 1 : 0;
4624 bss_setbuf
.cfg
= htod32(bsscfg_idx
);
4625 bss_setbuf
.val
= htod32(val
);
4627 WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx
, bss_up
? "up" : "down"));
4628 ret
= wldev_iovar_setbuf(ndev
, "bss", &bss_setbuf
, sizeof(bss_setbuf
),
4629 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
4632 WL_ERR(("'bss %d' failed with %d\n", bss_up
, ret
));
4639 wl_cfg80211_bss_isup(struct net_device
*ndev
, int bsscfg_idx
)
4645 /* Check if the BSS is up */
4647 result
= wldev_iovar_getbuf_bsscfg(ndev
, "bss", &bsscfg_idx
,
4648 sizeof(bsscfg_idx
), getbuf
, sizeof(getbuf
), 0, NULL
);
4650 WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx
, result
));
4651 WL_ERR(("NOTE: this ioctl error is normal "
4652 "when the BSS has not been created yet.\n"));
4654 val
= *(int*)getbuf
;
4656 WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx
, val
));
4657 isup
= (val
? TRUE
: FALSE
);
4663 wl_iftype_to_mode(wl_iftype_t iftype
)
4665 s32 mode
= BCME_ERROR
;
4668 case WL_IF_TYPE_STA
:
4669 case WL_IF_TYPE_P2P_GC
:
4670 case WL_IF_TYPE_P2P_DISC
:
4674 case WL_IF_TYPE_P2P_GO
:
4677 case WL_IF_TYPE_NAN
:
4680 case WL_IF_TYPE_AWDL
:
4681 mode
= WL_MODE_AWDL
;
4683 case WL_IF_TYPE_AIBSS
:
4684 /* Intentional fall through */
4685 case WL_IF_TYPE_IBSS
:
4686 mode
= WL_MODE_IBSS
;
4689 WL_ERR(("Unsupported type:%d\n", iftype
));
4696 cfg80211_to_wl_iftype(uint16 type
, uint16
*role
, uint16
*mode
)
4699 case NL80211_IFTYPE_STATION
:
4700 *role
= WL_IF_TYPE_STA
;
4701 *mode
= WL_MODE_BSS
;
4703 case NL80211_IFTYPE_AP
:
4704 *role
= WL_IF_TYPE_AP
;
4707 #ifdef WL_CFG80211_P2P_DEV_IF
4708 case NL80211_IFTYPE_P2P_DEVICE
:
4709 *role
= WL_IF_TYPE_P2P_DISC
;
4710 *mode
= WL_MODE_BSS
;
4712 #endif /* WL_CFG80211_P2P_DEV_IF */
4713 case NL80211_IFTYPE_P2P_GO
:
4714 *role
= WL_IF_TYPE_P2P_GO
;
4717 case NL80211_IFTYPE_P2P_CLIENT
:
4718 *role
= WL_IF_TYPE_P2P_GC
;
4719 *mode
= WL_MODE_BSS
;
4721 case NL80211_IFTYPE_MONITOR
:
4722 WL_ERR(("Unsupported mode \n"));
4723 return BCME_UNSUPPORTED
;
4724 case NL80211_IFTYPE_ADHOC
:
4725 *role
= WL_IF_TYPE_IBSS
;
4726 *mode
= WL_MODE_IBSS
;
4728 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
4729 case NL80211_IFTYPE_NAN
:
4730 *role
= WL_IF_TYPE_NAN
;
4731 *mode
= WL_MODE_NAN
;
4735 WL_ERR(("Unknown interface type:0x%x\n", type
));
4742 wl_role_to_cfg80211_type(uint16 role
, uint16
*wl_iftype
, uint16
*mode
)
4745 *wl_iftype
= WL_IF_TYPE_AWDL
;
4746 *mode
= WL_MODE_AWDL
;
4747 return NL80211_IFTYPE_STATION
;
4748 case WLC_E_IF_ROLE_STA
:
4749 *wl_iftype
= WL_IF_TYPE_STA
;
4750 *mode
= WL_MODE_BSS
;
4751 return NL80211_IFTYPE_STATION
;
4752 case WLC_E_IF_ROLE_AP
:
4753 *wl_iftype
= WL_IF_TYPE_AP
;
4755 return NL80211_IFTYPE_AP
;
4756 case WLC_E_IF_ROLE_P2P_GO
:
4757 *wl_iftype
= WL_IF_TYPE_P2P_GO
;
4759 return NL80211_IFTYPE_P2P_GO
;
4760 case WLC_E_IF_ROLE_P2P_CLIENT
:
4761 *wl_iftype
= WL_IF_TYPE_P2P_GC
;
4762 *mode
= WL_MODE_BSS
;
4763 return NL80211_IFTYPE_P2P_CLIENT
;
4764 case WLC_E_IF_ROLE_IBSS
:
4765 *wl_iftype
= WL_IF_TYPE_IBSS
;
4766 *mode
= WL_MODE_IBSS
;
4767 return NL80211_IFTYPE_ADHOC
;
4768 case WLC_E_IF_ROLE_NAN
:
4769 *wl_iftype
= WL_IF_TYPE_NAN
;
4770 *mode
= WL_MODE_NAN
;
4771 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
4772 /* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
4773 * For Vendor HAL based NAN implementation, continue advertising
4774 * as a STA interface
4776 return NL80211_IFTYPE_NAN
;
4778 return NL80211_IFTYPE_STATION
;
4779 #endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
4782 WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role
));
4787 #define MAX_ACTIVE_IF_LINKS 2
4789 wl_cfg80211_post_ifcreate(struct net_device
*ndev
,
4790 wl_if_event_info
*event
, u8
*addr
,
4791 const char *name
, bool rtnl_lock_reqd
)
4793 struct bcm_cfg80211
*cfg
;
4794 struct net_device
*primary_ndev
;
4795 struct net_device
*new_ndev
= NULL
;
4796 struct wireless_dev
*wdev
= NULL
;
4800 u8 mac_addr
[ETH_ALEN
];
4803 int need_legacy_war
= 0;
4804 dhd_pub_t
*dhd
= NULL
;
4805 #endif /* WL_STATIC_IF */
4807 if (!ndev
|| !event
) {
4808 WL_ERR(("Wrong arg\n"));
4812 cfg
= wl_get_cfg(ndev
);
4814 WL_ERR(("cfg null\n"));
4820 dhd
= (dhd_pub_t
*)(cfg
->pub
);
4821 if (!DHD_OPMODE_SUPPORTED(dhd
, DHD_FLAG_MFG_MODE
) && name
) {
4822 need_legacy_war
= ((wl_legacy_chip_check(cfg
) ||
4823 wl_check_interface_create_v0(cfg
)) &&
4824 !strnicmp(name
, SOFT_AP_IF_NAME
, strlen(SOFT_AP_IF_NAME
)));
4825 if (need_legacy_war
) {
4826 event
->role
= WLC_E_IF_ROLE_AP
;
4829 WL_DBG(("name: %s\n", name
));
4831 #endif /* WL_STATIC_IF */
4833 WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
4834 event
->role
, event
->ifidx
, event
->bssidx
));
4835 if (!event
->ifidx
|| !event
->bssidx
) {
4836 /* Fw returned primary idx (0) for virtual interface */
4837 WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
4838 event
->ifidx
, event
->bssidx
));
4842 if (wl_get_drv_status_all(cfg
, CONNECTED
) > MAX_ACTIVE_IF_LINKS
) {
4843 WL_ERR(("Can't support more than %d active links\n", MAX_ACTIVE_IF_LINKS
));
4847 iface_type
= wl_role_to_cfg80211_type(event
->role
, &wl_iftype
, &mode
);
4848 if (iface_type
< 0) {
4849 /* Unknown iface type */
4850 WL_ERR(("Wrong iface type \n"));
4854 WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG
"\n",
4855 addr
, name
, event
->role
, iface_type
, MAC2STRDBG(event
->mac
)));
4857 /* If iface name is not provided, use dongle ifname */
4862 /* If mac address is not set, use primary mac with locally administered
4865 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
4866 memcpy(mac_addr
, primary_ndev
->dev_addr
, ETH_ALEN
);
4867 /* For customer6 builds, use primary mac address for virtual interface */
4868 mac_addr
[0] |= 0x02;
4873 if (IS_CFG80211_STATIC_IF_NAME(cfg
, name
)) {
4874 new_ndev
= wl_cfg80211_post_static_ifcreate(cfg
, event
, addr
, iface_type
);
4875 wdev
= new_ndev
->ieee80211_ptr
;
4877 if (need_legacy_war
) {
4878 /* Check whether mac addr is in sync with fw. If not,
4879 * apply it using cur_etheraddr.
4881 if (memcmp(addr
, event
->mac
, ETH_ALEN
) != 0) {
4882 ret
= wldev_iovar_setbuf_bsscfg(new_ndev
, "cur_etheraddr",
4883 addr
, ETH_ALEN
, cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
,
4884 event
->bssidx
, &cfg
->ioctl_buf_sync
);
4885 if (unlikely(ret
)) {
4886 WL_ERR(("set cur_etheraddr Error (%d)\n", ret
));
4889 memcpy(new_ndev
->dev_addr
, addr
, ETH_ALEN
);
4890 WL_ERR(("Applying updated mac address to firmware\n"));
4893 if (!wl_get_drv_status(cfg
, AP_CREATED
, new_ndev
)) {
4895 WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n",
4896 new_ndev
->name
, event
->bssidx
));
4897 if ((err
= wl_cfg80211_add_del_bss(cfg
, new_ndev
,
4898 event
->bssidx
, WL_IF_TYPE_AP
, 0, NULL
)) < 0) {
4899 WL_ERR(("wl bss ap returned error:%d\n", err
));
4902 /* On success, mark AP creation in progress. */
4903 wl_set_drv_status(cfg
, AP_CREATING
, new_ndev
);
4905 WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
4909 #endif /* WL_STATIC_IF */
4911 new_ndev
= wl_cfg80211_allocate_if(cfg
, event
->ifidx
,
4912 name
, addr
, event
->bssidx
, event
->name
);
4914 WL_ERR(("I/F allocation failed! \n"));
4917 WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
4918 event
->ifidx
, event
->bssidx
));
4921 wdev
= (struct wireless_dev
*)MALLOCZ(cfg
->osh
, sizeof(*wdev
));
4923 WL_ERR(("wireless_dev alloc failed! \n"));
4924 wl_cfg80211_remove_if(cfg
, event
->ifidx
, new_ndev
, rtnl_lock_reqd
);
4928 wdev
->wiphy
= bcmcfg_to_wiphy(cfg
);
4929 wdev
->iftype
= iface_type
;
4931 new_ndev
->ieee80211_ptr
= wdev
;
4932 SET_NETDEV_DEV(new_ndev
, wiphy_dev(wdev
->wiphy
));
4934 memcpy(new_ndev
->dev_addr
, addr
, ETH_ALEN
);
4935 if (wl_cfg80211_register_if(cfg
, event
->ifidx
, new_ndev
, rtnl_lock_reqd
)
4937 WL_ERR(("IFACE register failed \n"));
4938 /* Post interface registration, wdev would be freed from the netdev
4939 * destructor path. For other cases, handle it here.
4941 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
4942 wl_cfg80211_remove_if(cfg
, event
->ifidx
, new_ndev
, rtnl_lock_reqd
);
4947 /* Initialize with the station mode params */
4948 ret
= wl_alloc_netinfo(cfg
, new_ndev
, wdev
, wl_iftype
,
4949 PM_ENABLE
, event
->bssidx
, event
->ifidx
);
4950 if (unlikely(ret
)) {
4951 WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret
));
4955 /* Apply the mode & infra setting based on iftype */
4956 if ((ret
= wl_config_infra(cfg
, new_ndev
, wl_iftype
)) < 0) {
4957 WL_ERR(("config ifmode failure (%d)\n", ret
));
4961 if (mode
== WL_MODE_AP
) {
4962 wl_set_drv_status(cfg
, AP_CREATING
, new_ndev
);
4965 WL_INFORM_MEM(("Network Interface (%s) registered with host."
4966 " cfg_iftype:%d wl_role:%d " MACDBG
"\n",
4967 new_ndev
->name
, iface_type
, event
->role
, MAC2STRDBG(new_ndev
->dev_addr
)));
4969 #ifdef SUPPORT_SET_CAC
4970 wl_cfg80211_set_cac(cfg
, 0);
4971 #endif /* SUPPORT_SET_CAC */
4977 /* remove static if from iflist */
4978 if (IS_CFG80211_STATIC_IF_NAME(cfg
, name
)) {
4979 cfg
->static_ndev_state
= NDEV_STATE_FW_IF_FAILED
;
4980 wl_cfg80211_update_iflist_info(cfg
, new_ndev
, WL_STATIC_IFIDX
, addr
,
4981 event
->bssidx
, event
->name
, NDEV_STATE_FW_IF_FAILED
);
4983 #endif /* WL_STATIC_IF */
4985 /* wdev would be freed from netdev destructor call back */
4986 wl_cfg80211_remove_if(cfg
, event
->ifidx
, new_ndev
, rtnl_lock_reqd
);
4993 wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211
*cfg
, bool rtnl_lock_reqd
)
4995 struct net_info
*iter
, *next
;
4996 struct net_device
*primary_ndev
;
4998 /* Note: This function will clean up only the network interface and host
4999 * data structures. The firmware interface clean up will happen in the
5000 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
5001 * context for the module case).
5003 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
5004 WL_DBG(("Enter\n"));
5005 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5006 #pragma GCC diagnostic push
5007 #pragma GCC diagnostic ignored "-Wcast-qual"
5009 for_each_ndev(cfg
, iter
, next
) {
5010 if (iter
->ndev
&& (iter
->ndev
!= primary_ndev
)) {
5011 /* Ensure interfaces are down before deleting */
5013 /* Avoiding cleaning static ifaces */
5014 if (!IS_CFG80211_STATIC_IF(cfg
, iter
->ndev
))
5015 #endif /* WL_STATIC_IF */
5017 dev_close(iter
->ndev
);
5018 WL_DBG(("Cleaning up iface:%s \n", iter
->ndev
->name
));
5019 wl_cfg80211_post_ifdel(iter
->ndev
, rtnl_lock_reqd
, 0);
5023 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5024 #pragma GCC diagnostic pop
5029 wl_cfg80211_post_ifdel(struct net_device
*ndev
, bool rtnl_lock_reqd
, s32 ifidx
)
5032 struct bcm_cfg80211
*cfg
;
5034 struct net_info
*netinfo
= NULL
;
5036 if (!ndev
|| !ndev
->ieee80211_ptr
) {
5037 /* No wireless dev done for this interface */
5042 cfg
= wl_get_cfg(ndev
);
5044 WL_ERR(("cfg null\n"));
5050 WL_ERR(("Invalid IF idx for iface:%s\n", ndev
->name
));
5051 ifidx
= dhd_net2idx(((struct dhd_pub
*)(cfg
->pub
))->info
, ndev
);
5052 BCM_REFERENCE(ifidx
);
5060 if ((netinfo
= wl_get_netinfo_by_wdev(cfg
, ndev_to_wdev(ndev
))) == NULL
) {
5061 WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev
)));
5065 wl_iftype
= netinfo
->iftype
;
5068 if (IS_CFG80211_STATIC_IF(cfg
, ndev
)) {
5069 ret
= wl_cfg80211_post_static_ifdel(cfg
, ndev
);
5071 #endif /* WL_STATIC_IF */
5074 if (!((cfg
->nancfg
.mac_rand
) && (wl_iftype
== WL_IF_TYPE_NAN
)))
5077 wl_release_vif_macaddr(cfg
, ndev
->dev_addr
, wl_iftype
);
5079 WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
5080 ndev
->name
, ifidx
, cfg
->vif_count
));
5081 wl_cfg80211_remove_if(cfg
, ifidx
, ndev
, rtnl_lock_reqd
);
5082 cfg
->bss_pending_op
= FALSE
;
5085 #ifdef SUPPORT_SET_CAC
5086 wl_cfg80211_set_cac(cfg
, 1);
5087 #endif /* SUPPORT_SET_CAC */
5092 wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211
*cfg
)
5095 bcm_struct_cfgdev
*cfgdev
;
5098 /* De-initialize the p2p discovery interface, if operational */
5099 WL_ERR(("Disabling P2P Discovery Interface \n"));
5100 #ifdef WL_CFG80211_P2P_DEV_IF
5101 cfgdev
= bcmcfg_to_p2p_wdev(cfg
);
5103 cfgdev
= cfg
->p2p_net
;
5106 ret
= wl_cfg80211_scan_stop(cfg
, cfgdev
);
5107 if (unlikely(ret
< 0)) {
5108 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret
));
5112 wl_cfgp2p_disable_discovery(cfg
);
5113 wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
) = 0;
5114 p2p_on(cfg
) = false;
5118 /* Create a Generic Network Interface and initialize it depending up on
5119 * the interface type
5121 struct wireless_dev
*
5122 wl_cfg80211_create_iface(struct wiphy
*wiphy
,
5123 wl_iftype_t wl_iftype
,
5124 u8
*mac_addr
, const char *name
)
5126 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
5127 struct net_device
*new_ndev
= NULL
;
5128 struct net_device
*primary_ndev
= NULL
;
5132 wl_if_event_info
*event
= NULL
;
5134 struct net_info
*iter
, *next
;
5136 WL_DBG(("Enter\n"));
5138 WL_ERR(("Interface name not provided\n"));
5142 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5143 #pragma GCC diagnostic push
5144 #pragma GCC diagnostic ignored "-Wcast-qual"
5146 for_each_ndev(cfg
, iter
, next
) {
5148 if (strcmp(iter
->ndev
->name
, name
) == 0) {
5149 WL_ERR(("Interface name, %s exists !\n", iter
->ndev
->name
));
5154 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5155 #pragma GCC diagnostic pop
5159 /* If any scan is going on, abort it */
5160 if (wl_abort_scan_and_check(cfg
) != TRUE
) {
5164 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
5165 if (likely(!mac_addr
)) {
5166 /* Use primary MAC with the locally administered bit for the
5169 memcpy(addr
, primary_ndev
->dev_addr
, ETH_ALEN
);
5172 /* Use the application provided mac address (if any) */
5173 memcpy(addr
, mac_addr
, ETH_ALEN
);
5176 cfg
->bss_pending_op
= TRUE
;
5177 memset(&cfg
->if_event_info
, 0, sizeof(cfg
->if_event_info
));
5179 /* De-initialize the p2p discovery interface, if operational */
5180 wl_cfg80211_deinit_p2p_discovery(cfg
);
5183 * Intialize the firmware I/F.
5185 #if defined(CUSTOMER_HW4)
5186 if (wl_legacy_chip_check(cfg
))
5188 /* Use bss iovar instead of interface_create iovar */
5189 ret
= BCME_UNSUPPORTED
;
5193 ret
= wl_cfg80211_interface_ops(cfg
, primary_ndev
, bsscfg_idx
,
5194 wl_iftype
, 0, addr
);
5196 if (ret
== BCME_UNSUPPORTED
) {
5197 /* Use bssidx 1 by default */
5199 if ((ret
= wl_cfg80211_add_del_bss(cfg
, primary_ndev
,
5200 bsscfg_idx
, wl_iftype
, 0, addr
)) < 0) {
5203 } else if (ret
< 0) {
5204 WL_ERR(("Interface create failed!! ret:%d \n", ret
));
5211 WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx
));
5213 * Wait till the firmware send a confirmation event back.
5215 WL_DBG(("Wait for the FW I/F Event\n"));
5216 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
5217 !cfg
->bss_pending_op
, msecs_to_jiffies(MAX_WAIT_TIME
));
5218 if (timeout
<= 0 || cfg
->bss_pending_op
) {
5219 WL_ERR(("ADD_IF event, didn't come. Return \n"));
5223 event
= &cfg
->if_event_info
;
5225 * Since FW operation is successful,we can go ahead with the
5226 * the host interface creation.
5228 new_ndev
= wl_cfg80211_post_ifcreate(primary_ndev
,
5229 event
, addr
, name
, false);
5232 /* Iface post ops successful. Return ndev/wdev ptr */
5233 return new_ndev
->ieee80211_ptr
;
5237 cfg
->bss_pending_op
= FALSE
;
5242 wl_cfg80211_del_iface(struct wiphy
*wiphy
, struct wireless_dev
*wdev
)
5244 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
5245 struct net_device
*ndev
= NULL
;
5252 WL_DBG(("Enter\n"));
5254 /* If any scan is going on, abort it */
5255 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
5256 WL_DBG(("Scan in progress. Aborting the scan!\n"));
5257 wl_cfg80211_cancel_scan(cfg
);
5260 bsscfg_idx
= wl_get_bssidx_by_wdev(cfg
, wdev
);
5261 if (bsscfg_idx
<= 0) {
5262 /* validate bsscfgidx */
5263 WL_ERR(("Wrong bssidx! \n"));
5267 /* Handle p2p iface */
5268 if ((ret
= wl_cfg80211_p2p_if_del(wiphy
, wdev
)) != BCME_NOTFOUND
) {
5269 WL_DBG(("P2P iface del handled \n"));
5270 #ifdef SUPPORT_SET_CAC
5271 wl_cfg80211_set_cac(cfg
, 1);
5272 #endif /* SUPPORT_SET_CAC */
5276 ndev
= wdev
->netdev
;
5277 if (unlikely(!ndev
)) {
5278 WL_ERR(("ndev null! \n"));
5282 memset(&cfg
->if_event_info
, 0, sizeof(cfg
->if_event_info
));
5284 if (cfg80211_to_wl_iftype(ndev
->ieee80211_ptr
->iftype
,
5285 &wl_iftype
, &wl_mode
) < 0) {
5289 WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d",
5290 bsscfg_idx
, ndev
->ieee80211_ptr
->iftype
, wl_iftype
));
5291 /* Delete the firmware interface. "interface_remove" command
5292 * should go on the interface to be deleted
5294 if (wl_cfg80211_get_bus_state(cfg
)) {
5295 WL_ERR(("Bus state is down: %s: %d\n", __FUNCTION__
, __LINE__
));
5296 ret
= BCME_DONGLE_DOWN
;
5300 cfg
->bss_pending_op
= true;
5301 ret
= wl_cfg80211_interface_ops(cfg
, ndev
, bsscfg_idx
,
5302 wl_iftype
, 1, NULL
);
5303 if (ret
== BCME_UNSUPPORTED
) {
5304 if ((ret
= wl_cfg80211_add_del_bss(cfg
, ndev
,
5305 bsscfg_idx
, wl_iftype
, true, NULL
)) < 0) {
5306 WL_ERR(("DEL bss failed ret:%d \n", ret
));
5309 } else if ((ret
== BCME_NOTAP
) || (ret
== BCME_NOTSTA
)) {
5310 /* De-init sequence involving role downgrade not happened.
5311 * Do nothing and return error. The del command should be
5314 WL_ERR(("ifdel role mismatch:%d\n", ret
));
5317 } else if (ret
< 0) {
5318 WL_ERR(("Interface DEL failed ret:%d \n", ret
));
5322 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
5323 !cfg
->bss_pending_op
, msecs_to_jiffies(MAX_WAIT_TIME
));
5324 if (timeout
<= 0 || cfg
->bss_pending_op
) {
5325 WL_ERR(("timeout in waiting IF_DEL event\n"));
5326 /* The interface unregister will happen from wifi reset context */
5333 WL_ERR(("iface del failed:%d\n", ret
));
5335 if (IS_CFG80211_STATIC_IF(cfg
, ndev
)) {
5337 * For static interface, clean up the host data,
5338 * irrespective of fw status. For dynamic
5339 * interfaces it gets cleaned from dhd_stop context
5341 wl_cfg80211_post_static_ifdel(cfg
, ndev
);
5343 #endif /* WL_STATIC_IF */
5345 ret
= wl_cfg80211_post_ifdel(ndev
, false, cfg
->if_event_info
.ifidx
);
5346 if (unlikely(ret
)) {
5347 WL_ERR(("post_ifdel failed\n"));
5351 cfg
->bss_pending_op
= false;
5356 wl_cfg80211_join_ibss(struct wiphy
*wiphy
, struct net_device
*dev
,
5357 struct cfg80211_ibss_params
*params
)
5359 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
5360 struct cfg80211_bss
*bss
;
5361 struct ieee80211_channel
*chan
;
5362 struct wl_join_params join_params
;
5364 struct cfg80211_ssid ssid
;
5367 size_t join_params_size
;
5368 chanspec_t chanspec
= 0;
5369 u32 param
[2] = {0, 0};
5373 RETURN_EIO_IF_NOT_UP(cfg
);
5374 WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG
"\n", MAC2STRDBG(params
->bssid
)));
5375 if (!params
->ssid
|| params
->ssid_len
<= 0 ||
5376 params
->ssid_len
> DOT11_MAX_SSID_LEN
) {
5377 WL_ERR(("Invalid parameter\n"));
5380 #if defined(WL_CFG80211_P2P_DEV_IF)
5381 chan
= params
->chandef
.chan
;
5383 chan
= params
->channel
;
5384 #endif /* WL_CFG80211_P2P_DEV_IF */
5386 cfg
->channel
= ieee80211_frequency_to_channel(chan
->center_freq
);
5387 if (wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
5388 struct wlc_ssid
*lssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, dev
, WL_PROF_SSID
);
5389 u8
*bssid
= (u8
*)wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
5390 u32
*channel
= (u32
*)wl_read_prof(cfg
, dev
, WL_PROF_CHAN
);
5391 if (!params
->bssid
|| ((memcmp(params
->bssid
, bssid
, ETHER_ADDR_LEN
) == 0) &&
5392 (memcmp(params
->ssid
, lssid
->SSID
, lssid
->SSID_len
) == 0) &&
5393 (*channel
== cfg
->channel
))) {
5394 WL_ERR(("Connection already existed to " MACDBG
"\n",
5395 MAC2STRDBG((u8
*)wl_read_prof(cfg
, dev
, WL_PROF_BSSID
))));
5398 WL_ERR(("Ignore Previous connecton to %s (" MACDBG
")\n",
5399 lssid
->SSID
, MAC2STRDBG(bssid
)));
5402 /* remove the VSIE */
5403 wl_cfg80211_ibss_vsie_delete(dev
);
5405 bss
= cfg80211_get_ibss(wiphy
, NULL
, params
->ssid
, params
->ssid_len
);
5407 if (IBSS_INITIAL_SCAN_ALLOWED
== TRUE
) {
5408 memcpy(ssid
.ssid
, params
->ssid
, params
->ssid_len
);
5409 ssid
.ssid_len
= params
->ssid_len
;
5412 (__wl_cfg80211_scan(wiphy
, dev
, NULL
, &ssid
) ==
5418 } while (++scan_retry
< WL_SCAN_RETRY_MAX
);
5420 /* rtnl lock code is removed here. don't see why rtnl lock
5421 * needs to be released.
5424 /* wait 4 secons till scan done.... */
5425 schedule_timeout_interruptible(msecs_to_jiffies(4000));
5427 bss
= cfg80211_get_ibss(wiphy
, NULL
,
5428 params
->ssid
, params
->ssid_len
);
5431 if (bss
&& ((IBSS_COALESCE_ALLOWED
== TRUE
) ||
5432 ((IBSS_COALESCE_ALLOWED
== FALSE
) && params
->bssid
&&
5433 !memcmp(bss
->bssid
, params
->bssid
, ETHER_ADDR_LEN
)))) {
5434 cfg
->ibss_starter
= false;
5435 WL_DBG(("Found IBSS\n"));
5437 cfg
->ibss_starter
= true;
5441 CFG80211_PUT_BSS(wiphy
, bss
);
5445 if (chan
->band
== NL80211_BAND_5GHZ
)
5446 param
[0] = WLC_BAND_5G
;
5447 else if (chan
->band
== NL80211_BAND_2GHZ
)
5448 param
[0] = WLC_BAND_2G
;
5449 err
= wldev_iovar_getint(dev
, "bw_cap", param
);
5450 if (unlikely(err
)) {
5451 WL_ERR(("Get bw_cap Failed (%d)\n", err
));
5455 chanspec
= channel_to_chanspec(wiphy
, dev
, cfg
->channel
, bw_cap
);
5458 * Join with specific BSSID and cached SSID
5459 * If SSID is zero join based on BSSID only
5461 memset(&join_params
, 0, sizeof(join_params
));
5462 memcpy((void *)join_params
.ssid
.SSID
, (const void *)params
->ssid
,
5464 join_params
.ssid
.SSID_len
= htod32(params
->ssid_len
);
5465 if (params
->bssid
) {
5466 memcpy(&join_params
.params
.bssid
, params
->bssid
, ETHER_ADDR_LEN
);
5467 err
= wldev_ioctl_set(dev
, WLC_SET_DESIRED_BSSID
, &join_params
.params
.bssid
,
5469 if (unlikely(err
)) {
5470 WL_ERR(("Error (%d)\n", err
));
5474 memset(&join_params
.params
.bssid
, 0, ETHER_ADDR_LEN
);
5476 if (IBSS_INITIAL_SCAN_ALLOWED
== FALSE
) {
5477 scan_suppress
= TRUE
;
5478 /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
5479 err
= wldev_ioctl_set(dev
, WLC_SET_SCANSUPPRESS
,
5480 &scan_suppress
, sizeof(int));
5481 if (unlikely(err
)) {
5482 WL_ERR(("Scan Suppress Setting Failed (%d)\n", err
));
5487 join_params
.params
.chanspec_list
[0] = chanspec
;
5488 join_params
.params
.chanspec_num
= 1;
5489 wldev_iovar_setint(dev
, "chanspec", chanspec
);
5490 join_params_size
= sizeof(join_params
);
5492 /* Disable Authentication, IBSS will add key if it required */
5493 wldev_iovar_setint(dev
, "wpa_auth", WPA_AUTH_DISABLED
);
5494 wldev_iovar_setint(dev
, "wsec", 0);
5496 err
= wldev_ioctl_set(dev
, WLC_SET_SSID
, &join_params
,
5498 if (unlikely(err
)) {
5499 WL_ERR(("IBSS set_ssid Error (%d)\n", err
));
5503 if (IBSS_INITIAL_SCAN_ALLOWED
== FALSE
) {
5504 scan_suppress
= FALSE
;
5505 /* Reset the SCAN SUPPRESS Flag */
5506 err
= wldev_ioctl_set(dev
, WLC_SET_SCANSUPPRESS
,
5507 &scan_suppress
, sizeof(int));
5508 if (unlikely(err
)) {
5509 WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err
));
5513 wl_update_prof(cfg
, dev
, NULL
, &join_params
.ssid
, WL_PROF_SSID
);
5514 wl_update_prof(cfg
, dev
, NULL
, &cfg
->channel
, WL_PROF_CHAN
);
5516 cfg
->aibss_txfail_seq
= 0; /* initialize the sequence */
5517 #endif /* WLAIBSS */
5519 cfg
->rmc_event_seq
= 0; /* initialize rmcfail sequence */
5520 #endif /* WL_RELMCAST */
5524 static s32
wl_cfg80211_leave_ibss(struct wiphy
*wiphy
, struct net_device
*dev
)
5526 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
5531 RETURN_EIO_IF_NOT_UP(cfg
);
5534 WL_INFORM_MEM(("Leave IBSS\n"));
5535 curbssid
= wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
5536 wl_set_drv_status(cfg
, DISCONNECTING
, dev
);
5538 memcpy(&scbval
.ea
, curbssid
, ETHER_ADDR_LEN
);
5539 err
= wldev_ioctl_set(dev
, WLC_DISASSOC
, &scbval
,
5541 if (unlikely(err
)) {
5542 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
5543 WL_ERR(("error(%d)\n", err
));
5547 /* remove the VSIE */
5548 wl_cfg80211_ibss_vsie_delete(dev
);
5555 int wl_cfg80211_get_rsn_capa(const bcm_tlv_t
*wpa2ie
,
5559 const wpa_suite_mcast_t
*mcast
;
5560 const wpa_suite_ucast_t
*ucast
;
5562 const wpa_suite_auth_key_mgmt_t
*mgmt
;
5569 /* check for Multicast cipher suite */
5570 if ((len
-= (WPA_SUITE_LEN
+ WPA2_VERSION_LEN
)) <= 0) {
5571 return BCME_NOTFOUND
;
5574 mcast
= (const wpa_suite_mcast_t
*)&wpa2ie
->data
[WPA2_VERSION_LEN
];
5576 /* Check for the unicast suite(s) */
5577 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
5578 return BCME_NOTFOUND
;
5581 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
5582 suite_count
= ltoh16_ua(&ucast
->count
);
5583 if ((suite_count
> NL80211_MAX_NR_CIPHER_SUITES
) ||
5584 (len
-= (WPA_IE_SUITE_COUNT_LEN
+
5585 (WPA_SUITE_LEN
* suite_count
))) <= 0)
5588 /* Check for AUTH key management suite(s) */
5589 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
5590 return BCME_NOTFOUND
;
5593 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[suite_count
];
5594 suite_count
= ltoh16_ua(&mgmt
->count
);
5596 if ((suite_count
<= NL80211_MAX_NR_CIPHER_SUITES
) &&
5597 (len
-= (WPA_IE_SUITE_COUNT_LEN
+
5598 (WPA_SUITE_LEN
* suite_count
))) >= RSN_CAP_LEN
) {
5599 rsn_cap
[0] = (const u8
*)&mgmt
->list
[suite_count
];
5609 wl_set_wpa_version(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
5611 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5612 struct wl_security
*sec
;
5617 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5618 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5622 if (sme
->crypto
.wpa_versions
& NL80211_WPA_VERSION_1
)
5623 val
= WPA_AUTH_PSK
|
5627 WPA_AUTH_UNSPECIFIED
;
5628 else if (sme
->crypto
.wpa_versions
& NL80211_WPA_VERSION_2
)
5629 val
= WPA2_AUTH_PSK
|
5633 WPA2_AUTH_UNSPECIFIED
;
5635 val
= WPA_AUTH_DISABLED
;
5637 if (is_wps_conn(sme
))
5638 val
= WPA_AUTH_DISABLED
;
5641 if (sme
->crypto
.wpa_versions
& NL80211_WAPI_VERSION_1
) {
5642 WL_DBG((" * wl_set_wpa_version, set wpa_auth"
5643 " to WPA_AUTH_WAPI 0x400"));
5644 val
= WAPI_AUTH_PSK
| WAPI_AUTH_UNSPECIFIED
;
5647 WL_INFORM_MEM(("[%s] wl wpa_auth 0x%0x\n", dev
->name
, val
));
5648 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", val
, bssidx
);
5649 if (unlikely(err
)) {
5650 WL_ERR(("set wpa_auth failed (%d)\n", err
));
5653 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
5654 sec
->wpa_versions
= sme
->crypto
.wpa_versions
;
5660 wl_set_set_wapi_ie(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
5662 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5666 WL_DBG((" %s \n", __FUNCTION__
));
5667 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5668 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5672 err
= wldev_iovar_setbuf_bsscfg(dev
, "wapiie", (const void *)sme
->ie
, sme
->ie_len
,
5673 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
5674 if (unlikely(err
)) {
5675 WL_ERR(("set_wapi_ie Error (%d)\n", err
));
5678 WL_INFORM_MEM(("wapi_ie successfully (%s)\n", dev
->name
));
5681 #endif /* BCMWAPI_WPI */
5684 wl_set_auth_type(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
5686 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5687 struct wl_security
*sec
;
5692 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5693 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5697 switch (sme
->auth_type
) {
5698 case NL80211_AUTHTYPE_OPEN_SYSTEM
:
5699 val
= WL_AUTH_OPEN_SYSTEM
;
5700 WL_DBG(("open system\n"));
5702 case NL80211_AUTHTYPE_SHARED_KEY
:
5703 val
= WL_AUTH_SHARED_KEY
;
5704 WL_DBG(("shared key\n"));
5706 case NL80211_AUTHTYPE_AUTOMATIC
:
5707 val
= WL_AUTH_OPEN_SHARED
;
5708 WL_DBG(("automatic\n"));
5711 case NL80211_AUTHTYPE_NETWORK_EAP
:
5712 WL_DBG(("network eap\n"));
5713 val
= DOT11_LEAP_AUTH
;
5718 WL_ERR(("invalid auth type (%d)\n", sme
->auth_type
));
5722 WL_INFORM_MEM(("[%s] wl auth 0x%0x \n", dev
->name
, val
));
5723 err
= wldev_iovar_setint_bsscfg(dev
, "auth", val
, bssidx
);
5724 if (unlikely(err
)) {
5725 WL_ERR(("set auth failed (%d)\n", err
));
5728 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
5729 sec
->auth_type
= sme
->auth_type
;
5734 wl_set_set_cipher(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
5736 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
5737 struct wl_security
*sec
;
5748 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
5749 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
5753 if (sme
->crypto
.n_ciphers_pairwise
) {
5754 switch (sme
->crypto
.ciphers_pairwise
[0]) {
5755 case WLAN_CIPHER_SUITE_WEP40
:
5756 case WLAN_CIPHER_SUITE_WEP104
:
5759 case WLAN_CIPHER_SUITE_TKIP
:
5760 pval
= TKIP_ENABLED
;
5762 case WLAN_CIPHER_SUITE_CCMP
:
5763 case WLAN_CIPHER_SUITE_AES_CMAC
:
5767 case WLAN_CIPHER_SUITE_SMS4
:
5769 pval
= SMS4_ENABLED
;
5770 err
= wl_set_set_wapi_ie(dev
, sme
);
5771 if (unlikely(err
)) {
5772 WL_DBG(("Set wapi ie failed \n"));
5775 WL_DBG(("Set wapi ie succeded\n"));
5777 wapi_val
= WAPI_AUTH_PSK
| WAPI_AUTH_UNSPECIFIED
;
5778 WL_INFORM_MEM(("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val
, dev
->name
));
5779 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wapi_val
, bssidx
);
5780 if (unlikely(err
)) {
5781 WL_ERR(("set wpa_auth failed (%d)\n", err
));
5785 #endif /* BCMWAPI_WPI */
5787 WL_ERR(("invalid cipher pairwise (%d)\n",
5788 sme
->crypto
.ciphers_pairwise
[0]));
5792 #if defined(BCMSUP_4WAY_HANDSHAKE)
5793 /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
5795 * Note that the FW feature flag only exists on kernels that support the
5798 if (cfg
->wdev
->wiphy
->features
& NL80211_FEATURE_FW_4WAY_HANDSHAKE
) {
5799 err
= wldev_iovar_setint_bsscfg(dev
, "sup_wpa", 1, bssidx
);
5801 WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err
));
5804 WL_INFORM_MEM(("idsup enabled.\n"));
5807 #endif /* BCMSUP_4WAY_HANDSHAKE */
5808 if (sme
->crypto
.cipher_group
) {
5809 switch (sme
->crypto
.cipher_group
) {
5810 case WLAN_CIPHER_SUITE_WEP40
:
5811 case WLAN_CIPHER_SUITE_WEP104
:
5814 case WLAN_CIPHER_SUITE_TKIP
:
5815 gval
= TKIP_ENABLED
;
5817 case WLAN_CIPHER_SUITE_CCMP
:
5820 case WLAN_CIPHER_SUITE_AES_CMAC
:
5824 case WLAN_CIPHER_SUITE_SMS4
:
5826 gval
= SMS4_ENABLED
;
5830 WL_ERR(("invalid cipher group (%d)\n",
5831 sme
->crypto
.cipher_group
));
5836 WL_DBG(("pval (%d) gval (%d)\n", pval
, gval
));
5838 if (is_wps_conn(sme
)) {
5842 /* WPS-2.0 allows no security */
5847 if (sme
->crypto
.cipher_group
== WLAN_CIPHER_SUITE_SMS4
) {
5848 WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
5853 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
5854 wsec_val
= pval
| gval
;
5858 WL_INFORM_MEM(("[%s] wl wsec 0x%x\n", dev
->name
, wsec_val
));
5859 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec_val
, bssidx
);
5860 if (unlikely(err
)) {
5861 WL_ERR(("error (%d)\n", err
));
5865 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
5866 sec
->cipher_pairwise
= sme
->crypto
.ciphers_pairwise
[0];
5867 sec
->cipher_group
= sme
->crypto
.cipher_group
;
5873 wl_cfg80211_set_mfp(struct bcm_cfg80211
*cfg
,
5874 struct net_device
*dev
,
5875 struct cfg80211_connect_params
*sme
)
5877 s32 mfp
= WL_MFP_NONE
;
5878 s32 current_mfp
= WL_MFP_NONE
;
5879 const bcm_tlv_t
*wpa2_ie
;
5880 const u8
* rsn_cap
= NULL
;
5881 bool fw_support
= false;
5883 const u8
*eptr
= NULL
, *ptr
= NULL
;
5884 const u8
* group_mgmt_cs
= NULL
;
5885 const wpa_pmkid_list_t
* pmkid
= NULL
;
5888 /* No connection params from userspace, Do nothing. */
5892 /* Check fw support and retreive current mfp val */
5893 err
= wldev_iovar_getint(dev
, "mfp", ¤t_mfp
);
5898 /* Parse the wpa2ie to decode the MFP capablity */
5899 if (((wpa2_ie
= bcm_parse_tlvs((const u8
*)sme
->ie
, sme
->ie_len
,
5900 DOT11_MNG_RSN_ID
)) != NULL
) &&
5901 (wl_cfg80211_get_rsn_capa(wpa2_ie
, &rsn_cap
) == 0) && rsn_cap
) {
5902 WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap
[0], rsn_cap
[1]));
5903 /* Check for MFP cap in the RSN capability field */
5905 if (rsn_cap
[0] & RSN_CAP_MFPR
) {
5906 mfp
= WL_MFP_REQUIRED
;
5907 } else if (rsn_cap
[0] & RSN_CAP_MFPC
) {
5908 mfp
= WL_MFP_CAPABLE
;
5912 * eptr --> end/last byte addr of wpa2_ie
5913 * ptr --> to keep track of current/required byte addr
5915 eptr
= (const u8
*)wpa2_ie
+ (wpa2_ie
->len
+ TLV_HDR_LEN
);
5916 /* pointing ptr to the next byte after rns_cap */
5917 ptr
= (const u8
*)rsn_cap
+ RSN_CAP_LEN
;
5918 if (mfp
&& (eptr
- ptr
) >= WPA2_PMKID_COUNT_LEN
) {
5919 /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
5920 pmkid
= (const wpa_pmkid_list_t
*)ptr
;
5921 count
= pmkid
->count
.low
| (pmkid
->count
.high
<< 8);
5922 /* ptr now to point to last byte addr of pmkid */
5923 ptr
= (const u8
*)pmkid
+ (count
* WPA2_PMKID_LEN
5924 + WPA2_PMKID_COUNT_LEN
);
5925 if ((eptr
- ptr
) >= WPA_SUITE_LEN
) {
5926 /* group_mgmt_cs now to point to first byte addr of bip */
5927 group_mgmt_cs
= ptr
;
5932 WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n",
5933 mfp
, wpa2_ie
, fw_support
));
5935 if (fw_support
== false) {
5937 /* if mfp > 0, mfp capability set in wpa ie, but
5938 * FW indicated error for mfp. Propagate the error up.
5940 WL_ERR(("mfp capability found in wpaie. But fw doesn't"
5941 "seem to support MFP\n"));
5945 /* Firmware doesn't support mfp. But since connection request
5946 * is for non-mfp case, don't bother.
5951 } else if (mfp
!= current_mfp
) {
5952 err
= wldev_iovar_setint(dev
, "mfp", mfp
);
5953 if (unlikely(err
)) {
5954 WL_ERR(("mfp (%d) set failed ret:%d \n", mfp
, err
));
5957 WL_INFORM_MEM(("[%s] wl mfp 0x%x\n", dev
->name
, mfp
));
5960 if (group_mgmt_cs
&& bcmp((const uint8
*)WPA2_OUI
,
5961 group_mgmt_cs
, (WPA_SUITE_LEN
- 1)) == 0) {
5962 WL_DBG(("BIP is found\n"));
5963 err
= wldev_iovar_setbuf(dev
, "bip",
5964 group_mgmt_cs
, WPA_SUITE_LEN
, cfg
->ioctl_buf
,
5965 WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
5967 * Dont return failure for unsupported cases
5968 * of bip iovar for backward compatibility
5970 if (err
!= BCME_UNSUPPORTED
&& err
< 0) {
5971 WL_ERR(("bip set error (%d)\n", err
));
5972 #if defined(CUSTOMER_HW4)
5973 if (wl_legacy_chip_check(cfg
))
5975 /* Ignore bip error: Some older firmwares doesn't
5976 * support bip iovar/ return BCME_NOTUP while trying
5977 * to set bip from connect context. These firmares
5978 * include bip in RSNIE by default. So its okay to
5989 WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n",
5990 dev
->name
, group_mgmt_cs
[0], group_mgmt_cs
[1],
5997 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg
),
5998 FW_LOGSET_MASK_ALL
);
6005 wl_set_key_mgmt(struct net_device
*dev
, struct cfg80211_connect_params
*sme
)
6007 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
6008 struct wl_security
*sec
;
6013 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
6014 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
6018 if (sme
->crypto
.n_akm_suites
) {
6019 err
= wldev_iovar_getint(dev
, "wpa_auth", &val
);
6020 if (unlikely(err
)) {
6021 WL_ERR(("could not get wpa_auth (%d)\n", err
));
6024 if (val
& (WPA_AUTH_PSK
|
6028 WPA_AUTH_UNSPECIFIED
)) {
6029 switch (sme
->crypto
.akm_suites
[0]) {
6030 case WLAN_AKM_SUITE_8021X
:
6031 val
= WPA_AUTH_UNSPECIFIED
;
6033 case WLAN_AKM_SUITE_PSK
:
6037 case WLAN_AKM_SUITE_CCKM
:
6038 val
= WPA_AUTH_CCKM
;
6042 WL_ERR(("invalid akm suite (0x%x)\n",
6043 sme
->crypto
.akm_suites
[0]));
6046 } else if (val
& (WPA2_AUTH_PSK
|
6050 WPA2_AUTH_UNSPECIFIED
)) {
6051 switch (sme
->crypto
.akm_suites
[0]) {
6052 case WLAN_AKM_SUITE_8021X
:
6053 val
= WPA2_AUTH_UNSPECIFIED
;
6056 case WL_AKM_SUITE_SHA256_1X
:
6057 val
= WPA2_AUTH_1X_SHA256
;
6059 case WL_AKM_SUITE_SHA256_PSK
:
6060 val
= WPA2_AUTH_PSK_SHA256
;
6063 case WLAN_AKM_SUITE_PSK
:
6064 val
= WPA2_AUTH_PSK
;
6066 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
6067 case WLAN_AKM_SUITE_FT_8021X
:
6068 val
= WPA2_AUTH_UNSPECIFIED
| WPA2_AUTH_FT
;
6071 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
6072 case WLAN_AKM_SUITE_FT_PSK
:
6073 val
= WPA2_AUTH_PSK
| WPA2_AUTH_FT
;
6077 case WLAN_AKM_SUITE_CCKM
:
6078 val
= WPA2_AUTH_CCKM
;
6081 case WLAN_AKM_SUITE_FILS_SHA256
:
6082 val
= WPA2_AUTH_FILS_SHA256
;
6084 case WLAN_AKM_SUITE_FILS_SHA384
:
6085 val
= WPA2_AUTH_FILS_SHA384
;
6088 WL_ERR(("invalid akm suite (0x%x)\n",
6089 sme
->crypto
.akm_suites
[0]));
6094 else if (val
& (WAPI_AUTH_PSK
| WAPI_AUTH_UNSPECIFIED
)) {
6095 switch (sme
->crypto
.akm_suites
[0]) {
6096 case WLAN_AKM_SUITE_WAPI_CERT
:
6097 val
= WAPI_AUTH_UNSPECIFIED
;
6099 case WLAN_AKM_SUITE_WAPI_PSK
:
6100 val
= WAPI_AUTH_PSK
;
6103 WL_ERR(("invalid akm suite (0x%x)\n",
6104 sme
->crypto
.akm_suites
[0]));
6111 if ((err
= wl_cfg80211_set_mfp(cfg
, dev
, sme
)) < 0) {
6112 WL_ERR(("MFP set failed err:%d\n", err
));
6117 WL_INFORM_MEM(("[%s] wl wpa_auth to 0x%x\n", dev
->name
, val
));
6118 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", val
, bssidx
);
6119 if (unlikely(err
)) {
6120 WL_ERR(("could not set wpa_auth (0x%x)\n", err
));
6124 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
6125 sec
->wpa_auth
= sme
->crypto
.akm_suites
[0];
6131 wl_set_set_sharedkey(struct net_device
*dev
,
6132 struct cfg80211_connect_params
*sme
)
6134 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
6135 struct wl_security
*sec
;
6136 struct wl_wsec_key key
;
6141 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
6142 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
6146 WL_DBG(("key len (%d)\n", sme
->key_len
));
6148 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
6149 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
6150 sec
->wpa_versions
, sec
->cipher_pairwise
));
6151 if (!(sec
->wpa_versions
& (NL80211_WPA_VERSION_1
|
6152 NL80211_WPA_VERSION_2
)) &&
6154 !is_wapi(sec
->cipher_pairwise
) &&
6156 (sec
->cipher_pairwise
& (WLAN_CIPHER_SUITE_WEP40
|
6157 WLAN_CIPHER_SUITE_WEP104
)))
6159 memset(&key
, 0, sizeof(key
));
6160 key
.len
= (u32
) sme
->key_len
;
6161 key
.index
= (u32
) sme
->key_idx
;
6162 if (unlikely(key
.len
> sizeof(key
.data
))) {
6163 WL_ERR(("Too long key length (%u)\n", key
.len
));
6166 memcpy(key
.data
, sme
->key
, key
.len
);
6167 key
.flags
= WL_PRIMARY_KEY
;
6168 switch (sec
->cipher_pairwise
) {
6169 case WLAN_CIPHER_SUITE_WEP40
:
6170 key
.algo
= CRYPTO_ALGO_WEP1
;
6172 case WLAN_CIPHER_SUITE_WEP104
:
6173 key
.algo
= CRYPTO_ALGO_WEP128
;
6176 WL_ERR(("Invalid algorithm (%d)\n",
6177 sme
->crypto
.ciphers_pairwise
[0]));
6180 /* Set the new key/index */
6181 WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
6182 key
.len
, key
.index
, key
.algo
));
6183 WL_DBG(("key \"%s\"\n", key
.data
));
6184 swap_key_from_BE(&key
);
6185 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
),
6186 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
6187 if (unlikely(err
)) {
6188 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
6191 WL_INFORM_MEM(("key applied to fw\n"));
6192 if (sec
->auth_type
== NL80211_AUTHTYPE_SHARED_KEY
) {
6193 WL_DBG(("set auth_type to shared key\n"));
6194 val
= WL_AUTH_SHARED_KEY
; /* shared key */
6195 err
= wldev_iovar_setint_bsscfg(dev
, "auth", val
, bssidx
);
6196 if (unlikely(err
)) {
6197 WL_ERR(("set auth failed (%d)\n", err
));
6206 #if defined(ESCAN_RESULT_PATCH)
6207 static u8 connect_req_bssid
[6];
6208 static u8 broad_bssid
[6];
6209 #endif /* ESCAN_RESULT_PATCH */
6211 #if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
6212 static bool wl_get_chan_isvht80(struct net_device
*net
, dhd_pub_t
*dhd
)
6217 if (wldev_iovar_getint(net
, "chanspec", (s32
*)&chanspec
) == BCME_OK
)
6218 chanspec
= wl_chspec_driver_to_host(chanspec
);
6220 isvht80
= chanspec
& WL_CHANSPEC_BW_80
;
6221 WL_DBG(("%s: chanspec(%x:%d)\n", __FUNCTION__
, chanspec
, isvht80
));
6225 #endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
6227 int wl_cfg80211_cleanup_mismatch_status(struct net_device
*dev
, struct bcm_cfg80211
*cfg
,
6235 WL_ERR(("Disassociate previous connection!\n"));
6236 wl_set_drv_status(cfg
, DISCONNECTING
, dev
);
6237 scbval
.val
= DOT11_RC_DISASSOC_LEAVING
;
6238 scbval
.val
= htod32(scbval
.val
);
6240 err
= wldev_ioctl_set(dev
, WLC_DISASSOC
, &scbval
,
6242 if (unlikely(err
)) {
6243 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
6244 WL_ERR(("error (%d)\n", err
));
6250 WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
6251 if (wl_get_drv_status(cfg
, DISCONNECTING
, dev
)) {
6252 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
6256 while (wl_get_drv_status(cfg
, DISCONNECTING
, dev
) && wait_cnt
) {
6257 WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
6263 if (wait_cnt
== 0) {
6264 WL_ERR(("DISCONNECING clean up failed!\n"));
6265 return BCME_NOTREADY
;
6270 #define MAX_SCAN_ABORT_WAIT_CNT 20
6271 #define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
6274 wl_cfg80211_connect(struct wiphy
*wiphy
, struct net_device
*dev
,
6275 struct cfg80211_connect_params
*sme
)
6277 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
6278 struct ieee80211_channel
*chan
= sme
->channel
;
6279 wl_extjoin_params_t
*ext_join_params
;
6280 struct wl_join_params join_params
;
6281 size_t join_params_size
;
6282 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
6283 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6284 s32 roam_trigger
[2] = {0, 0};
6285 #endif /* ROAM_AP_ENV_DETECTION */
6287 const wpa_ie_fixed_t
*wpa_ie
;
6288 const bcm_tlv_t
*wpa2_ie
;
6289 const u8
* wpaie
= 0;
6292 struct ether_addr bssid
;
6294 #ifdef ESCAN_CHANNEL_CACHE
6295 chanspec_t chanspec_list
[MAX_ROAM_CHANNEL
];
6296 #endif /* ESCAN_CHANNEL_CACHE */
6301 WL_ERR(("dev is null\n"));
6304 BCM_REFERENCE(dhdp
);
6306 #ifdef ESCAN_CHANNEL_CACHE
6307 memset(chanspec_list
, 0, (sizeof(chanspec_t
) * MAX_ROAM_CHANNEL
));
6308 #endif /* ESCAN_CHANNEL_CACHE */
6310 /* Connection attempted via linux-wireless */
6311 wl_set_drv_status(cfg
, CFG80211_CONNECT
, dev
);
6312 #ifdef DHDTCPSYNC_FLOOD_BLK
6313 dhd_reset_tcpsync_info_by_dev(dev
);
6314 #endif /* DHDTCPSYNC_FLOOD_BLK */
6316 #if defined(SUPPORT_RANDOM_MAC_SCAN)
6317 wl_cfg80211_random_mac_disable(dev
);
6318 #endif /* SUPPORT_RANDOM_MAC_SCAN */
6320 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6321 if (sme
->channel_hint
) {
6322 chan
= sme
->channel_hint
;
6323 WL_INFORM_MEM(("channel_hint (%d), channel_hint center_freq (%d)\n",
6324 ieee80211_frequency_to_channel(sme
->channel_hint
->center_freq
),
6325 sme
->channel_hint
->center_freq
));
6327 if (sme
->bssid_hint
) {
6328 sme
->bssid
= sme
->bssid_hint
;
6329 WL_INFORM_MEM(("bssid_hint "MACDBG
" \n", MAC2STRDBG(sme
->bssid_hint
)));
6331 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6333 if (unlikely(!sme
->ssid
)) {
6334 WL_ERR(("Invalid ssid\n"));
6338 if (unlikely(sme
->ssid_len
> DOT11_MAX_SSID_LEN
)) {
6339 WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n",
6340 sme
->ssid
, sme
->ssid_len
));
6344 WL_DBG(("SME IE : len=%zu\n", sme
->ie_len
));
6345 if (sme
->ie
!= NULL
&& sme
->ie_len
> 0 && (wl_dbg_level
& WL_DBG_DBG
)) {
6346 prhex(NULL
, sme
->ie
, sme
->ie_len
);
6349 RETURN_EIO_IF_NOT_UP(cfg
);
6351 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
6353 if (cfg
->scan_request
) {
6354 WL_TRACE_HW4(("Aborting the scan! \n"));
6355 wl_cfg80211_scan_abort(cfg
);
6356 wait_cnt
= MAX_SCAN_ABORT_WAIT_CNT
;
6357 while (wl_get_drv_status(cfg
, SCANNING
, dev
) && wait_cnt
) {
6358 WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt
));
6360 OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME
);
6362 if (wl_get_drv_status(cfg
, SCANNING
, dev
)) {
6363 wl_cfg80211_cancel_scan(cfg
);
6366 #ifdef WL_SCHED_SCAN
6367 /* Locks are taken in wl_cfg80211_sched_scan_stop()
6368 * A start scan occuring during connect is unlikely
6370 if (cfg
->sched_scan_req
) {
6371 wl_cfg80211_sched_scan_stop(wiphy
, bcmcfg_to_prmry_ndev(cfg
));
6373 #endif /* WL_SCHED_SCAN */
6374 #ifdef WL_CFG80211_GON_COLLISION
6375 /* init block gon req count */
6376 cfg
->block_gon_req_tx_count
= 0;
6377 cfg
->block_gon_req_rx_count
= 0;
6378 #endif /* WL_CFG80211_GON_COLLISION */
6379 #if defined(ESCAN_RESULT_PATCH)
6381 memcpy(connect_req_bssid
, sme
->bssid
, ETHER_ADDR_LEN
);
6383 bzero(connect_req_bssid
, ETHER_ADDR_LEN
);
6384 bzero(broad_bssid
, ETHER_ADDR_LEN
);
6386 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
6389 if (wl_get_drv_status(cfg
, CONNECTING
, dev
) || wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
6390 /* set nested connect bit to identify the context */
6391 wl_set_drv_status(cfg
, NESTED_CONNECT
, dev
);
6392 /* DHD prev status is CONNECTING/CONNECTED */
6393 err
= wl_cfg80211_cleanup_mismatch_status(dev
, cfg
, TRUE
);
6394 } else if (wl_get_drv_status(cfg
, DISCONNECTING
, dev
)) {
6395 /* DHD prev status is DISCONNECTING */
6396 err
= wl_cfg80211_cleanup_mismatch_status(dev
, cfg
, false);
6397 } else if (!wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
6398 /* DHD previous status is not connected and FW connected */
6399 if (wldev_ioctl_get(dev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
) == 0) {
6400 /* set nested connect bit to identify the context */
6401 wl_set_drv_status(cfg
, NESTED_CONNECT
, dev
);
6402 err
= wl_cfg80211_cleanup_mismatch_status(dev
, cfg
, true);
6407 wl_update_prof(cfg
, dev
, NULL
, sme
->bssid
, WL_PROF_LATEST_BSSID
);
6409 wl_update_prof(cfg
, dev
, NULL
, ðer_bcast
, WL_PROF_LATEST_BSSID
);
6412 /* 'connect' request received */
6413 wl_set_drv_status(cfg
, CONNECTING
, dev
);
6414 /* clear nested connect bit on proceeding for connection */
6415 wl_clr_drv_status(cfg
, NESTED_CONNECT
, dev
);
6418 bzero(&bssid
, sizeof(bssid
));
6419 if (!wl_get_drv_status(cfg
, DISCONNECTING
, dev
))
6420 wl_update_prof(cfg
, dev
, NULL
, (void *)&bssid
, WL_PROF_BSSID
);
6422 if (p2p_is_on(cfg
) && (dev
!= bcmcfg_to_prmry_ndev(cfg
))) {
6423 /* we only allow to connect using virtual interface in case of P2P */
6424 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
6425 WL_ERR(("Find p2p index from wdev(%p) failed\n",
6426 dev
->ieee80211_ptr
));
6430 wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
6431 VNDR_IE_ASSOCREQ_FLAG
, sme
->ie
, sme
->ie_len
);
6432 } else if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
6433 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
6434 WL_ERR(("Find wlan index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
6439 /* find the RSN_IE */
6440 if ((wpa2_ie
= bcm_parse_tlvs((const u8
*)sme
->ie
, sme
->ie_len
,
6441 DOT11_MNG_RSN_ID
)) != NULL
) {
6442 WL_DBG((" WPA2 IE is found\n"));
6444 /* find the WPA_IE */
6445 if ((wpa_ie
= wl_cfgp2p_find_wpaie(sme
->ie
,
6446 sme
->ie_len
)) != NULL
) {
6447 WL_DBG((" WPA IE is found\n"));
6449 if (wpa_ie
!= NULL
|| wpa2_ie
!= NULL
) {
6450 wpaie
= (wpa_ie
!= NULL
) ? (const u8
*)wpa_ie
: (const u8
*)wpa2_ie
;
6451 wpaie_len
= (wpa_ie
!= NULL
) ? wpa_ie
->length
: wpa2_ie
->len
;
6452 wpaie_len
+= WPA_RSN_IE_TAG_FIXED_LEN
;
6453 err
= wldev_iovar_setbuf(dev
, "wpaie", wpaie
, wpaie_len
,
6454 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
6455 if (unlikely(err
)) {
6456 WL_ERR(("wpaie set error (%d)\n", err
));
6460 err
= wldev_iovar_setbuf(dev
, "wpaie", NULL
, 0,
6461 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
6462 if (unlikely(err
)) {
6463 WL_ERR(("wpaie set error (%d)\n", err
));
6467 err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
6468 VNDR_IE_ASSOCREQ_FLAG
, (const u8
*)sme
->ie
, sme
->ie_len
);
6469 if (unlikely(err
)) {
6473 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6474 if (dhdp
->roam_env_detection
) {
6475 bool is_roamtrig_reset
= TRUE
;
6476 bool is_roam_env_ok
= (wldev_iovar_setint(dev
, "roam_env_detection",
6477 AP_ENV_DETECT_NOT_USED
) == BCME_OK
);
6479 #ifdef SKIP_ROAM_TRIGGER_RESET
6480 roam_trigger
[1] = WLC_BAND_2G
;
6482 (wldev_ioctl_get(dev
, WLC_GET_ROAM_TRIGGER
, roam_trigger
,
6483 sizeof(roam_trigger
)) == BCME_OK
) &&
6484 (roam_trigger
[0] == WL_AUTO_ROAM_TRIGGER
-10);
6485 #endif /* SKIP_ROAM_TRIGGER_RESET */
6486 if (is_roamtrig_reset
&& is_roam_env_ok
) {
6487 roam_trigger
[0] = WL_AUTO_ROAM_TRIGGER
;
6488 roam_trigger
[1] = WLC_BAND_ALL
;
6489 err
= wldev_ioctl_set(dev
, WLC_SET_ROAM_TRIGGER
, roam_trigger
,
6490 sizeof(roam_trigger
));
6491 if (unlikely(err
)) {
6492 WL_ERR((" failed to restore roam_trigger for auto env"
6497 #endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
6499 cfg
->channel
= ieee80211_frequency_to_channel(chan
->center_freq
);
6501 WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg
->channel
,
6502 chan
->center_freq
, chan_cnt
));
6504 WL_DBG(("No channel info from user space\n"));
6507 #ifdef ESCAN_CHANNEL_CACHE
6509 * No channel information from user space. if ECC is enabled, the ECC
6510 * would prepare the channel list, else no channel would be provided
6511 * and firmware would need to do a full channel scan.
6513 * Use cached channels. This might take slightly longer time compared
6514 * to using a single channel based join. But ECC would help choose
6515 * a better AP for a given ssid. For a given SSID there might multiple
6516 * APs on different channels and ECC would scan all those channels
6517 * before deciding up on the AP. This accounts for the additional delay.
6519 if (cfg
->rcc_enabled
|| cfg
->channel
== 0)
6524 err
= wldev_get_band(dev
, &band
);
6526 set_roam_band(band
);
6529 memcpy(ssid
.SSID
, sme
->ssid
, sme
->ssid_len
);
6530 ssid
.SSID_len
= (uint32
)sme
->ssid_len
;
6531 chan_cnt
= get_roam_channel_list(cfg
->channel
, chanspec_list
,
6532 MAX_ROAM_CHANNEL
, &ssid
, ioctl_version
);
6533 WL_DBG(("RCC channel count:%d \n", chan_cnt
));
6535 #endif /* ESCAN_CHANNEL_CACHE */
6536 WL_DBG(("3. set wpa version \n"));
6538 err
= wl_set_wpa_version(dev
, sme
);
6539 if (unlikely(err
)) {
6540 WL_ERR(("Invalid wpa_version\n"));
6544 if (sme
->crypto
.wpa_versions
& NL80211_WAPI_VERSION_1
)
6545 WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n"));
6547 WL_DBG(("4. wl_set_auth_type\n"));
6549 err
= wl_set_auth_type(dev
, sme
);
6550 if (unlikely(err
)) {
6551 WL_ERR(("Invalid auth type\n"));
6558 err
= wl_set_set_cipher(dev
, sme
);
6559 if (unlikely(err
)) {
6560 WL_ERR(("Invalid ciper\n"));
6564 err
= wl_set_key_mgmt(dev
, sme
);
6565 if (unlikely(err
)) {
6566 WL_ERR(("Invalid key mgmt\n"));
6570 err
= wl_set_set_sharedkey(dev
, sme
);
6571 if (unlikely(err
)) {
6572 WL_ERR(("Invalid shared key\n"));
6577 * Join with specific BSSID and cached SSID
6578 * If SSID is zero join based on BSSID only
6580 join_params_size
= WL_EXTJOIN_PARAMS_FIXED_SIZE
+
6581 chan_cnt
* sizeof(chanspec_t
);
6582 ext_join_params
= (wl_extjoin_params_t
*)MALLOCZ(cfg
->osh
, join_params_size
);
6583 if (ext_join_params
== NULL
) {
6585 wl_clr_drv_status(cfg
, CONNECTING
, dev
);
6588 ext_join_params
->ssid
.SSID_len
=
6589 (uint32
)min(sizeof(ext_join_params
->ssid
.SSID
), sme
->ssid_len
);
6590 memcpy(&ext_join_params
->ssid
.SSID
, sme
->ssid
, ext_join_params
->ssid
.SSID_len
);
6591 wl_update_prof(cfg
, dev
, NULL
, &ext_join_params
->ssid
, WL_PROF_SSID
);
6592 ext_join_params
->ssid
.SSID_len
= htod32(ext_join_params
->ssid
.SSID_len
);
6593 /* increate dwell time to receive probe response or detect Beacon
6594 * from target AP at a noisy air only during connect command
6596 ext_join_params
->scan
.active_time
= chan_cnt
? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS
: -1;
6597 ext_join_params
->scan
.passive_time
= chan_cnt
? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS
: -1;
6598 /* Set up join scan parameters */
6599 ext_join_params
->scan
.scan_type
= -1;
6600 ext_join_params
->scan
.nprobes
= chan_cnt
?
6601 (ext_join_params
->scan
.active_time
/WL_SCAN_JOIN_PROBE_INTERVAL_MS
) : -1;
6602 ext_join_params
->scan
.home_time
= -1;
6605 memcpy(&ext_join_params
->assoc
.bssid
, sme
->bssid
, ETH_ALEN
);
6607 memcpy(&ext_join_params
->assoc
.bssid
, ðer_bcast
, ETH_ALEN
);
6608 ext_join_params
->assoc
.chanspec_num
= chan_cnt
;
6610 if (chan_cnt
&& !cfg
->rcc_enabled
) {
6613 * Use the channel provided by userspace
6615 u16 channel
, band
, bw
, ctl_sb
;
6617 channel
= cfg
->channel
;
6618 band
= (channel
<= CH_MAX_2G_CHANNEL
) ? WL_CHANSPEC_BAND_2G
6619 : WL_CHANSPEC_BAND_5G
;
6621 /* Get min_bw set for the interface */
6622 bw
= WL_CHANSPEC_BW_20
;
6623 if (bw
== INVCHANSPEC
) {
6624 WL_ERR(("Invalid chanspec \n"));
6625 MFREE(cfg
->osh
, ext_join_params
, join_params_size
);
6630 ctl_sb
= WL_CHANSPEC_CTL_SB_NONE
;
6631 chspec
= (channel
| band
| bw
| ctl_sb
);
6632 ext_join_params
->assoc
.chanspec_list
[0] &= WL_CHANSPEC_CHAN_MASK
;
6633 ext_join_params
->assoc
.chanspec_list
[0] |= chspec
;
6634 ext_join_params
->assoc
.chanspec_list
[0] =
6635 wl_chspec_host_to_driver(ext_join_params
->assoc
.chanspec_list
[0]);
6638 #ifdef ESCAN_CHANNEL_CACHE
6640 memcpy(ext_join_params
->assoc
.chanspec_list
, chanspec_list
,
6641 sizeof(chanspec_t
) * chan_cnt
);
6643 #endif /* ESCAN_CHANNEL_CACHE */
6644 ext_join_params
->assoc
.chanspec_num
= htod32(ext_join_params
->assoc
.chanspec_num
);
6645 if (ext_join_params
->ssid
.SSID_len
< IEEE80211_MAX_SSID_LEN
) {
6646 WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params
->ssid
.SSID
,
6647 ext_join_params
->ssid
.SSID_len
));
6650 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
6651 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
6652 MFREE(cfg
->osh
, ext_join_params
, join_params_size
);
6656 #ifdef DHD_EVENT_LOG_FILTER
6657 if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
6658 /* inform only for STA Interface */
6659 dhd_event_log_filter_notify_connect_request(dhdp
,
6660 (uint8
*)(&ext_join_params
->assoc
.bssid
), cfg
->channel
);
6662 #endif /* DHD_EVENT_LOG_FILTER */
6664 /* disable TDLS if number of connected interfaces is >= 1 */
6665 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_CONNECT
, false);
6667 err
= wldev_iovar_setbuf_bsscfg(dev
, "join", ext_join_params
, join_params_size
,
6668 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
6669 if (cfg
->rcc_enabled
) {
6670 WL_INFORM_MEM(("[%s] Connecting with " MACDBG
" ssid \"%s\","
6671 " len (%d) with rcc channels. chan_cnt:%d \n\n",
6672 dev
->name
, MAC2STRDBG((u8
*)(&ext_join_params
->assoc
.bssid
)),
6673 "*****", ext_join_params
->ssid
.SSID_len
, chan_cnt
));
6675 WL_INFORM_MEM(("[%s] Connecting with " MACDBG
" ssid \"%s\","
6676 "len (%d) channel:%d\n\n",
6677 dev
->name
, MAC2STRDBG((u8
*)(&ext_join_params
->assoc
.bssid
)),
6678 "*****", ext_join_params
->ssid
.SSID_len
, cfg
->channel
));
6680 SUPP_LOG(("[%s] Connecting with " MACDBG
" ssid \"%s\","
6681 "channel:%d rcc:%d\n",
6682 dev
->name
, MAC2STRDBG((u8
*)(&ext_join_params
->assoc
.bssid
)),
6683 ext_join_params
->ssid
.SSID
, cfg
->channel
, cfg
->rcc_enabled
));
6684 MFREE(cfg
->osh
, ext_join_params
, join_params_size
);
6686 wl_clr_drv_status(cfg
, CONNECTING
, dev
);
6687 if (err
== BCME_UNSUPPORTED
) {
6688 WL_DBG(("join iovar is not supported\n"));
6691 WL_ERR(("join iovar error (%d)\n", err
));
6698 #if defined(ROAMEXP_SUPPORT)
6699 /* Clear Blacklist bssid and Whitelist ssid list before join issue
6700 * This is temporary fix since currently firmware roaming is not
6701 * disabled by android framework before SSID join from framework
6703 /* Flush blacklist bssid content */
6704 dhd_dev_set_blacklist_bssid(dev
, NULL
, 0, true);
6705 /* Flush whitelist ssid content */
6706 dhd_dev_set_whitelist_ssid(dev
, NULL
, 0, true);
6707 #endif /* OEM_ANDROID && ROAMEXP_SUPPORT */
6708 memset(&join_params
, 0, sizeof(join_params
));
6709 join_params_size
= sizeof(join_params
.ssid
);
6711 join_params
.ssid
.SSID_len
= (uint32
)min(sizeof(join_params
.ssid
.SSID
), sme
->ssid_len
);
6712 memcpy(&join_params
.ssid
.SSID
, sme
->ssid
, join_params
.ssid
.SSID_len
);
6713 join_params
.ssid
.SSID_len
= htod32(join_params
.ssid
.SSID_len
);
6714 wl_update_prof(cfg
, dev
, NULL
, &join_params
.ssid
, WL_PROF_SSID
);
6716 memcpy(&join_params
.params
.bssid
, sme
->bssid
, ETH_ALEN
);
6718 memcpy(&join_params
.params
.bssid
, ðer_bcast
, ETH_ALEN
);
6720 if (wl_ch_to_chanspec(dev
, cfg
->channel
, &join_params
, &join_params_size
) < 0) {
6721 WL_ERR(("Invalid chanspec\n"));
6725 WL_DBG(("join_param_size %zu\n", join_params_size
));
6727 if (join_params
.ssid
.SSID_len
< IEEE80211_MAX_SSID_LEN
) {
6728 WL_INFORM_MEM(("ssid \"%s\", len (%d)\n", join_params
.ssid
.SSID
,
6729 join_params
.ssid
.SSID_len
));
6731 err
= wldev_ioctl_set(dev
, WLC_SET_SSID
, &join_params
, join_params_size
);
6734 WL_ERR(("error (%d)\n", err
));
6735 wl_clr_drv_status(cfg
, CONNECTING
, dev
);
6736 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
6738 /* If connect fails, check whether we can enable back TDLS */
6739 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_DISCONNECT
, false);
6743 if ((dev
== bcmcfg_to_prmry_ndev(cfg
)) && !err
) {
6744 DHD_DBG_PKT_MON_START(dhdp
);
6746 #endif /* DBG_PKT_MON */
6750 #define WAIT_FOR_DISCONNECT_MAX 10
6751 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
6755 wait_cnt
= WAIT_FOR_DISCONNECT_MAX
;
6756 while (wl_get_drv_status(cfg
, DISCONNECTING
, dev
) && wait_cnt
) {
6757 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt
));
6766 wl_cfg80211_disconnect(struct wiphy
*wiphy
, struct net_device
*dev
,
6769 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
6773 u8
*curbssid
= NULL
;
6774 u8 null_bssid
[ETHER_ADDR_LEN
];
6775 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
6776 WL_ERR(("Reason %d\n", reason_code
));
6777 RETURN_EIO_IF_NOT_UP(cfg
);
6778 act
= *(bool *) wl_read_prof(cfg
, dev
, WL_PROF_ACT
);
6779 curbssid
= wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
6781 BCM_REFERENCE(dhdp
);
6783 #ifdef ESCAN_RESULT_PATCH
6784 if (wl_get_drv_status(cfg
, CONNECTING
, dev
) && curbssid
&&
6785 (memcmp(curbssid
, connect_req_bssid
, ETHER_ADDR_LEN
) == 0)) {
6786 WL_ERR(("Disconnecting from connecting device: " MACDBG
"\n",
6787 MAC2STRDBG(curbssid
)));
6790 #endif /* ESCAN_RESULT_PATCH */
6793 WL_ERR(("Disconnecting while CONNECTING status %d\n", (int)sizeof(null_bssid
)));
6794 bzero(null_bssid
, sizeof(null_bssid
));
6795 curbssid
= null_bssid
;
6800 /* Stop packet monitor */
6801 if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
6802 DHD_DBG_PKT_MON_STOP(dhdp
);
6804 #endif /* DBG_PKT_MON */
6806 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
6808 /* Let scan aborted by F/W */
6809 if (cfg
->scan_request
) {
6810 WL_TRACE_HW4(("Aborting the scan! \n"));
6811 wl_cfg80211_cancel_scan(cfg
);
6813 if (wl_get_drv_status(cfg
, CONNECTING
, dev
) ||
6814 wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
6815 wl_set_drv_status(cfg
, DISCONNECTING
, dev
);
6816 scbval
.val
= reason_code
;
6817 memcpy(&scbval
.ea
, curbssid
, ETHER_ADDR_LEN
);
6818 scbval
.val
= htod32(scbval
.val
);
6819 WL_INFORM_MEM(("[%s] wl disassoc\n", dev
->name
));
6820 err
= wldev_ioctl_set(dev
, WLC_DISASSOC
, &scbval
,
6822 if (unlikely(err
)) {
6823 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
6824 WL_ERR(("error (%d)\n", err
));
6829 /* If are in WPS reauth state, then we would be
6830 * dropping the link down events. Ensure that
6831 * Event is sent up for the disconnect Req
6833 if (wl_wps_session_update(dev
,
6834 WPS_STATE_DISCONNECT
, curbssid
) == BCME_OK
) {
6835 WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
6836 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
6838 #endif /* WPS_SYNC */
6839 wl_cfg80211_wait_for_disconnection(cfg
, dev
);
6840 if (wl_get_drv_status(cfg
, DISCONNECTING
, dev
)) {
6841 CFG80211_CONNECT_RESULT(dev
, NULL
, NULL
,
6843 WLAN_STATUS_UNSPECIFIED_FAILURE
,
6845 wl_clr_drv_status(cfg
, DISCONNECTING
, dev
);
6848 WL_INFORM_MEM(("act is false\n"));
6849 CFG80211_CONNECT_RESULT(dev
, NULL
, NULL
,
6851 WLAN_STATUS_UNSPECIFIED_FAILURE
,
6854 #ifdef CUSTOM_SET_CPUCORE
6855 /* set default cpucore */
6856 if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
6857 dhdp
->chan_isvht80
&= ~DHD_FLAG_STA_MODE
;
6858 if (!(dhdp
->chan_isvht80
))
6859 dhd_set_cpucore(dhdp
, FALSE
);
6861 #endif /* CUSTOM_SET_CPUCORE */
6863 cfg
->rssi
= 0; /* reset backup of rssi */
6868 #if defined(WL_CFG80211_P2P_DEV_IF)
6870 wl_cfg80211_set_tx_power(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
6871 enum nl80211_tx_power_setting type
, s32 mbm
)
6874 wl_cfg80211_set_tx_power(struct wiphy
*wiphy
,
6875 enum nl80211_tx_power_setting type
, s32 dbm
)
6876 #endif /* WL_CFG80211_P2P_DEV_IF */
6879 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
6880 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
6882 #if defined(WL_CFG80211_P2P_DEV_IF)
6883 s32 dbm
= MBM_TO_DBM(mbm
);
6884 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
6885 defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
6886 dbm
= MBM_TO_DBM(dbm
);
6887 #endif /* WL_CFG80211_P2P_DEV_IF */
6889 RETURN_EIO_IF_NOT_UP(cfg
);
6891 case NL80211_TX_POWER_AUTOMATIC
:
6893 case NL80211_TX_POWER_LIMITED
:
6895 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
6899 case NL80211_TX_POWER_FIXED
:
6901 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
6907 err
= wl_set_tx_power(ndev
, type
, dbm
);
6908 if (unlikely(err
)) {
6909 WL_ERR(("error (%d)\n", err
));
6913 cfg
->conf
->tx_power
= dbm
;
6918 #if defined(WL_CFG80211_P2P_DEV_IF)
6919 static s32
wl_cfg80211_get_tx_power(struct wiphy
*wiphy
,
6920 struct wireless_dev
*wdev
, s32
*dbm
)
6922 static s32
wl_cfg80211_get_tx_power(struct wiphy
*wiphy
, s32
*dbm
)
6923 #endif /* WL_CFG80211_P2P_DEV_IF */
6925 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
6926 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
6929 RETURN_EIO_IF_NOT_UP(cfg
);
6930 err
= wl_get_tx_power(ndev
, dbm
);
6932 WL_ERR(("error (%d)\n", err
));
6938 wl_cfg80211_config_default_key(struct wiphy
*wiphy
, struct net_device
*dev
,
6939 u8 key_idx
, bool unicast
, bool multicast
)
6941 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
6947 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
6948 WL_ERR(("Find p2p index from dev(%p) failed\n", dev
->ieee80211_ptr
));
6952 WL_DBG(("key index (%d)\n", key_idx
));
6953 RETURN_EIO_IF_NOT_UP(cfg
);
6954 err
= wldev_iovar_getint_bsscfg(dev
, "wsec", &wsec
, bssidx
);
6955 if (unlikely(err
)) {
6956 WL_ERR(("WLC_GET_WSEC error (%d)\n", err
));
6959 if (wsec
== WEP_ENABLED
) {
6960 /* Just select a new current key */
6961 index
= (u32
) key_idx
;
6962 index
= htod32(index
);
6963 err
= wldev_ioctl_set(dev
, WLC_SET_KEY_PRIMARY
, &index
,
6965 if (unlikely(err
)) {
6966 WL_ERR(("error (%d)\n", err
));
6973 wl_add_keyext(struct wiphy
*wiphy
, struct net_device
*dev
,
6974 u8 key_idx
, const u8
*mac_addr
, struct key_params
*params
)
6976 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
6977 struct wl_wsec_key key
;
6980 s32 mode
= wl_get_mode_by_netdev(cfg
, dev
);
6982 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
6983 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
6986 memset(&key
, 0, sizeof(key
));
6987 key
.index
= (u32
) key_idx
;
6989 if (!ETHER_ISMULTI(mac_addr
))
6990 memcpy((char *)&key
.ea
, (const void *)mac_addr
, ETHER_ADDR_LEN
);
6991 key
.len
= (u32
) params
->key_len
;
6993 /* check for key index change */
6996 swap_key_from_BE(&key
);
6997 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
),
6998 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
6999 if (unlikely(err
)) {
7000 WL_ERR(("key delete error (%d)\n", err
));
7004 if (key
.len
> sizeof(key
.data
)) {
7005 WL_ERR(("Invalid key length (%d)\n", key
.len
));
7008 WL_DBG(("Setting the key index %d\n", key
.index
));
7009 memcpy(key
.data
, params
->key
, key
.len
);
7011 if ((mode
== WL_MODE_BSS
) &&
7012 (params
->cipher
== WLAN_CIPHER_SUITE_TKIP
)) {
7014 memcpy(keybuf
, &key
.data
[24], sizeof(keybuf
));
7015 memcpy(&key
.data
[24], &key
.data
[16], sizeof(keybuf
));
7016 memcpy(&key
.data
[16], keybuf
, sizeof(keybuf
));
7019 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
7020 if (params
->seq
&& params
->seq_len
== 6) {
7023 ivptr
= (const u8
*) params
->seq
;
7024 key
.rxiv
.hi
= (ivptr
[5] << 24) | (ivptr
[4] << 16) |
7025 (ivptr
[3] << 8) | ivptr
[2];
7026 key
.rxiv
.lo
= (ivptr
[1] << 8) | ivptr
[0];
7027 key
.iv_initialized
= true;
7030 switch (params
->cipher
) {
7031 case WLAN_CIPHER_SUITE_WEP40
:
7032 key
.algo
= CRYPTO_ALGO_WEP1
;
7033 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7035 case WLAN_CIPHER_SUITE_WEP104
:
7036 key
.algo
= CRYPTO_ALGO_WEP128
;
7037 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7039 case WLAN_CIPHER_SUITE_TKIP
:
7040 key
.algo
= CRYPTO_ALGO_TKIP
;
7041 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7043 case WLAN_CIPHER_SUITE_AES_CMAC
:
7044 key
.algo
= CRYPTO_ALGO_AES_CCM
;
7045 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7047 case WLAN_CIPHER_SUITE_CCMP
:
7048 key
.algo
= CRYPTO_ALGO_AES_CCM
;
7049 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
7052 case WLAN_CIPHER_SUITE_SMS4
:
7053 key
.algo
= CRYPTO_ALGO_SMS4
;
7054 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7058 WL_ERR(("Invalid cipher (0x%x)\n", params
->cipher
));
7061 swap_key_from_BE(&key
);
7062 /* need to guarantee EAPOL 4/4 send out before set key */
7063 dhd_wait_pend8021x(dev
);
7064 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
),
7065 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
7066 if (unlikely(err
)) {
7067 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
7070 WL_INFORM_MEM(("[%s] wsec key set\n", dev
->name
));
7076 wl_cfg80211_enable_roam_offload(struct net_device
*dev
, int enable
)
7079 wl_eventmsg_buf_t ev_buf
;
7080 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
7082 if (dev
!= bcmcfg_to_prmry_ndev(cfg
)) {
7083 /* roam offload is only for the primary device */
7087 WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev
->name
, enable
));
7088 err
= wldev_iovar_setint(dev
, "roam_offload", enable
);
7092 bzero(&ev_buf
, sizeof(wl_eventmsg_buf_t
));
7093 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_PSK_SUP
, !enable
);
7094 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_ASSOC_REQ_IE
, !enable
);
7095 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_ASSOC_RESP_IE
, !enable
);
7096 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_REASSOC
, !enable
);
7097 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_JOIN
, !enable
);
7098 wl_cfg80211_add_to_eventbuffer(&ev_buf
, WLC_E_ROAM
, !enable
);
7099 err
= wl_cfg80211_apply_eventbuffer(dev
, cfg
, &ev_buf
);
7101 cfg
->roam_offload
= enable
;
7106 struct wireless_dev
*
7107 wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211
*cfg
, const char *name
)
7109 struct net_info
*iter
, *next
;
7115 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
7116 #pragma GCC diagnostic push
7117 #pragma GCC diagnostic ignored "-Wcast-qual"
7119 for_each_ndev(cfg
, iter
, next
) {
7121 if (strcmp(iter
->ndev
->name
, name
) == 0) {
7122 return iter
->ndev
->ieee80211_ptr
;
7126 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
7127 #pragma GCC diagnostic pop
7129 WL_DBG(("Iface %s not found\n", name
));
7133 #if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
7135 wl_cfg80211_block_arp(struct net_device
*dev
, int enable
)
7137 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
7138 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
7140 WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev
->name
, enable
));
7141 if (!dhd_pkt_filter_enable
) {
7142 WL_DBG(("Packet filter isn't enabled\n"));
7146 /* Block/Unblock ARP frames only if STA is connected to
7147 * the upstream AP in case of STA+SoftAP Concurrenct mode
7149 if (!wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
7150 WL_DBG(("STA not connected to upstream AP\n"));
7155 WL_DBG(("Enable ARP Filter\n"));
7156 /* Add ARP filter */
7157 dhd_packet_filter_add_remove(dhdp
, TRUE
, DHD_BROADCAST_ARP_FILTER_NUM
);
7159 /* Enable ARP packet filter - blacklist */
7160 dhd_master_mode
= FALSE
;
7161 dhd_pktfilter_offload_enable(dhdp
, dhdp
->pktfilter
[DHD_BROADCAST_ARP_FILTER_NUM
],
7162 TRUE
, dhd_master_mode
);
7164 WL_DBG(("Disable ARP Filter\n"));
7165 /* Disable ARP packet filter */
7166 dhd_master_mode
= TRUE
;
7167 dhd_pktfilter_offload_enable(dhdp
, dhdp
->pktfilter
[DHD_BROADCAST_ARP_FILTER_NUM
],
7168 FALSE
, dhd_master_mode
);
7170 /* Delete ARP filter */
7171 dhd_packet_filter_add_remove(dhdp
, FALSE
, DHD_BROADCAST_ARP_FILTER_NUM
);
7174 #endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
7177 wl_cfg80211_add_key(struct wiphy
*wiphy
, struct net_device
*dev
,
7178 u8 key_idx
, bool pairwise
, const u8
*mac_addr
,
7179 struct key_params
*params
)
7181 struct wl_wsec_key key
;
7187 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7188 s32 mode
= wl_get_mode_by_netdev(cfg
, dev
);
7189 WL_DBG(("key index (%d)\n", key_idx
));
7190 RETURN_EIO_IF_NOT_UP(cfg
);
7192 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7193 WL_ERR(("Find p2p index from dev(%p) failed\n", dev
->ieee80211_ptr
));
7198 ((params
->cipher
!= WLAN_CIPHER_SUITE_WEP40
) &&
7199 (params
->cipher
!= WLAN_CIPHER_SUITE_WEP104
))) {
7200 wl_add_keyext(wiphy
, dev
, key_idx
, mac_addr
, params
);
7203 memset(&key
, 0, sizeof(key
));
7204 /* Clear any buffered wep key */
7205 memset(&cfg
->wep_key
, 0, sizeof(struct wl_wsec_key
));
7207 key
.len
= (u32
) params
->key_len
;
7208 key
.index
= (u32
) key_idx
;
7210 if (unlikely(key
.len
> sizeof(key
.data
))) {
7211 WL_ERR(("Too long key length (%u)\n", key
.len
));
7214 memcpy(key
.data
, params
->key
, key
.len
);
7216 key
.flags
= WL_PRIMARY_KEY
;
7217 switch (params
->cipher
) {
7218 case WLAN_CIPHER_SUITE_WEP40
:
7219 key
.algo
= CRYPTO_ALGO_WEP1
;
7221 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7223 case WLAN_CIPHER_SUITE_WEP104
:
7224 key
.algo
= CRYPTO_ALGO_WEP128
;
7226 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7228 case WLAN_CIPHER_SUITE_TKIP
:
7229 key
.algo
= CRYPTO_ALGO_TKIP
;
7231 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
7232 if (mode
== WL_MODE_BSS
) {
7233 bcopy(&key
.data
[24], keybuf
, sizeof(keybuf
));
7234 bcopy(&key
.data
[16], &key
.data
[24], sizeof(keybuf
));
7235 bcopy(keybuf
, &key
.data
[16], sizeof(keybuf
));
7237 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7239 case WLAN_CIPHER_SUITE_AES_CMAC
:
7240 key
.algo
= CRYPTO_ALGO_AES_CCM
;
7242 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7244 case WLAN_CIPHER_SUITE_CCMP
:
7245 key
.algo
= CRYPTO_ALGO_AES_CCM
;
7247 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
7250 case WLAN_CIPHER_SUITE_SMS4
:
7251 key
.algo
= CRYPTO_ALGO_SMS4
;
7252 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7255 #endif /* BCMWAPI_WPI */
7256 #if defined(WLAN_CIPHER_SUITE_PMK)
7257 case WLAN_CIPHER_SUITE_PMK
: {
7260 char keystring
[WSEC_MAX_PSK_LEN
+ 1];
7261 char* charptr
= keystring
;
7263 struct wl_security
*sec
;
7265 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
7266 if (sec
->wpa_auth
== WLAN_AKM_SUITE_8021X
) {
7267 err
= wldev_iovar_setbuf(dev
, "okc_info_pmk", (const void *)params
->key
,
7268 WSEC_MAX_PSK_LEN
/ 2, keystring
, sizeof(keystring
), NULL
);
7270 /* could fail in case that 'okc' is not supported */
7271 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err
));
7274 /* copy the raw hex key to the appropriate format */
7275 for (j
= 0; j
< (WSEC_MAX_PSK_LEN
/ 2); j
++) {
7276 charptr
+= snprintf(charptr
, sizeof(keystring
), "%02x", params
->key
[j
]);
7278 len
= (u16
)strlen(keystring
);
7279 pmk
.key_len
= htod16(len
);
7280 bcopy(keystring
, pmk
.key
, len
);
7281 pmk
.flags
= htod16(WSEC_PASSPHRASE
);
7283 err
= wldev_ioctl_set(dev
, WLC_SET_WSEC_PMK
, &pmk
, sizeof(pmk
));
7286 /* Clear key length to delete key */
7289 #endif /* WLAN_CIPHER_SUITE_PMK */
7291 WL_ERR(("Invalid cipher (0x%x)\n", params
->cipher
));
7295 /* Set the new key/index */
7296 if ((mode
== WL_MODE_IBSS
) && (val
& (TKIP_ENABLED
| AES_ENABLED
))) {
7297 WL_ERR(("IBSS KEY setted\n"));
7298 wldev_iovar_setint(dev
, "wpa_auth", WPA_AUTH_NONE
);
7300 swap_key_from_BE(&key
);
7301 if ((params
->cipher
== WLAN_CIPHER_SUITE_WEP40
) ||
7302 (params
->cipher
== WLAN_CIPHER_SUITE_WEP104
)) {
7304 * For AP role, since we are doing a wl down before bringing up AP,
7305 * the plumbed keys will be lost. So for AP once we bring up AP, we
7306 * need to plumb keys again. So buffer the keys for future use. This
7307 * is more like a WAR. If firmware later has the capability to do
7308 * interface upgrade without doing a "wl down" and "wl apsta 0", then
7309 * this will not be required.
7311 WL_DBG(("Buffering WEP Keys \n"));
7312 memcpy(&cfg
->wep_key
, &key
, sizeof(struct wl_wsec_key
));
7314 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
), cfg
->ioctl_buf
,
7315 WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
7316 if (unlikely(err
)) {
7317 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
7322 err
= wldev_iovar_getint_bsscfg(dev
, "wsec", &wsec
, bssidx
);
7323 if (unlikely(err
)) {
7324 WL_ERR(("get wsec error (%d)\n", err
));
7329 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
7330 if (unlikely(err
)) {
7331 WL_ERR(("set wsec error (%d)\n", err
));
7339 wl_cfg80211_del_key(struct wiphy
*wiphy
, struct net_device
*dev
,
7340 u8 key_idx
, bool pairwise
, const u8
*mac_addr
)
7342 struct wl_wsec_key key
;
7343 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7347 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7348 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
7351 WL_DBG(("Enter\n"));
7354 if ((key_idx
>= DOT11_MAX_DEFAULT_KEYS
) && (key_idx
< DOT11_MAX_DEFAULT_KEYS
+2))
7358 RETURN_EIO_IF_NOT_UP(cfg
);
7359 memset(&key
, 0, sizeof(key
));
7361 key
.flags
= WL_PRIMARY_KEY
;
7362 key
.algo
= CRYPTO_ALGO_OFF
;
7363 key
.index
= (u32
) key_idx
;
7365 WL_DBG(("key index (%d)\n", key_idx
));
7366 /* Set the new key/index */
7367 swap_key_from_BE(&key
);
7368 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &key
, sizeof(key
), cfg
->ioctl_buf
,
7369 WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
7370 if (unlikely(err
)) {
7371 if (err
== -EINVAL
) {
7372 if (key
.index
>= DOT11_MAX_DEFAULT_KEYS
) {
7373 /* we ignore this key index in this case */
7374 WL_DBG(("invalid key index (%d)\n", key_idx
));
7377 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
7384 /* NOTE : this function cannot work as is and is never called */
7386 wl_cfg80211_get_key(struct wiphy
*wiphy
, struct net_device
*dev
,
7387 u8 key_idx
, bool pairwise
, const u8
*mac_addr
, void *cookie
,
7388 void (*callback
) (void *cookie
, struct key_params
* params
))
7390 struct key_params params
;
7391 struct wl_wsec_key key
;
7392 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7393 struct wl_security
*sec
;
7398 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
7399 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
7402 WL_DBG(("key index (%d)\n", key_idx
));
7403 RETURN_EIO_IF_NOT_UP(cfg
);
7404 memset(&key
, 0, sizeof(key
));
7405 key
.index
= key_idx
;
7406 swap_key_to_BE(&key
);
7407 memset(¶ms
, 0, sizeof(params
));
7408 params
.key_len
= (u8
) min_t(u8
, DOT11_MAX_KEY_SIZE
, key
.len
);
7409 params
.key
= key
.data
;
7411 err
= wldev_iovar_getint_bsscfg(dev
, "wsec", &wsec
, bssidx
);
7412 if (unlikely(err
)) {
7413 WL_ERR(("WLC_GET_WSEC error (%d)\n", err
));
7416 switch (WSEC_ENABLED(wsec
)) {
7418 sec
= wl_read_prof(cfg
, dev
, WL_PROF_SEC
);
7419 if (sec
->cipher_pairwise
& WLAN_CIPHER_SUITE_WEP40
) {
7420 params
.cipher
= WLAN_CIPHER_SUITE_WEP40
;
7421 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7422 } else if (sec
->cipher_pairwise
& WLAN_CIPHER_SUITE_WEP104
) {
7423 params
.cipher
= WLAN_CIPHER_SUITE_WEP104
;
7424 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7428 params
.cipher
= WLAN_CIPHER_SUITE_TKIP
;
7429 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7432 params
.cipher
= WLAN_CIPHER_SUITE_AES_CMAC
;
7433 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7437 params
.cipher
= WLAN_CIPHER_SUITE_SMS4
;
7438 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7441 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
7442 /* to connect to mixed mode AP */
7443 case (AES_ENABLED
| TKIP_ENABLED
): /* TKIP CCMP */
7444 params
.cipher
= WLAN_CIPHER_SUITE_AES_CMAC
;
7445 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7449 WL_ERR(("Invalid algo (0x%x)\n", wsec
));
7453 callback(cookie
, ¶ms
);
7458 wl_cfg80211_config_default_mgmt_key(struct wiphy
*wiphy
,
7459 struct net_device
*dev
, u8 key_idx
)
7464 WL_INFORM_MEM(("Not supported\n"));
7470 wl_cfg80211_ifstats_counters_cb(void *ctx
, const uint8
*data
, uint16 type
, uint16 len
)
7473 case WL_IFSTATS_XTLV_IF_INDEX
:
7474 WL_DBG(("Stats received on interface index: %d\n", *data
));
7476 case WL_IFSTATS_XTLV_GENERIC
: {
7477 if (len
> sizeof(wl_if_stats_t
)) {
7478 WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n",
7479 type
, len
, (int)sizeof(wl_if_stats_t
)));
7481 memcpy(ctx
, data
, sizeof(wl_if_stats_t
));
7485 WL_DBG(("Unsupported counter type 0x%x\n", type
));
7492 /* Parameters to if_counters iovar need to be converted to XTLV format
7493 * before sending to FW. The length of the top level XTLV container
7494 * containing parameters should not exceed 228 bytes
7496 #define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228
7499 wl_cfg80211_ifstats_counters(struct net_device
*dev
, wl_if_stats_t
*if_stats
)
7501 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
7502 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
7504 bcm_xtlvbuf_t xtlvbuf
, local_xtlvbuf
;
7506 uint16 expected_resp_len
;
7507 wl_stats_report_t
*request
= NULL
, *response
= NULL
;
7511 pbuf
= (uint8
*)MALLOCZ(dhdp
->osh
, WLC_IOCTL_MEDLEN
);
7513 WL_ERR(("Failed to allocate local pbuf\n"));
7517 /* top level container length cannot exceed 228 bytes.
7518 * This is because the output buffer is 1535 bytes long.
7519 * Allow 1300 bytes for reporting stats coming in XTLV format
7521 request
= (wl_stats_report_t
*)
7522 MALLOCZ(dhdp
->osh
, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
);
7524 WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
7525 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
));
7530 request
->version
= WL_STATS_REPORT_REQUEST_VERSION_V2
;
7532 /* Top level container... we will create it ourselves */
7533 /* Leave space for report version, length, and top level XTLV
7534 * WL_IFSTATS_XTLV_IF.
7536 ret
= bcm_xtlv_buf_init(&local_xtlvbuf
,
7537 (uint8
*)(request
->data
) + BCM_XTLV_HDR_SIZE
,
7538 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
-
7539 offsetof(wl_stats_report_t
, data
) - BCM_XTLV_HDR_SIZE
,
7540 BCM_XTLV_OPTION_ALIGN32
);
7546 /* Populate requests using this the local_xtlvbuf context. The xtlvbuf
7547 * is used to fill the container containing the XTLVs populated using
7550 ret
= bcm_xtlv_buf_init(&xtlvbuf
,
7551 (uint8
*)(request
->data
),
7552 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
-
7553 offsetof(wl_stats_report_t
, data
),
7554 BCM_XTLV_OPTION_ALIGN32
);
7560 /* Request generic stats */
7561 ret
= bcm_xtlv_put_data(&local_xtlvbuf
,
7562 WL_IFSTATS_XTLV_GENERIC
, NULL
, 0);
7567 /* Complete the outer container with type and length
7570 ret
= bcm_xtlv_put_data(&xtlvbuf
,
7572 NULL
, bcm_xtlv_buf_len(&local_xtlvbuf
));
7578 request
->length
= bcm_xtlv_buf_len(&xtlvbuf
) +
7579 offsetof(wl_stats_report_t
, data
);
7580 bsscfg_idx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
);
7582 /* send the command over to the device and get teh output */
7583 ret
= wldev_iovar_getbuf_bsscfg(dev
, "if_counters", (void *)request
,
7584 request
->length
, pbuf
, WLC_IOCTL_MEDLEN
, bsscfg_idx
,
7585 &cfg
->ioctl_buf_sync
);
7587 WL_ERR(("if_counters not supported ret=%d\n", ret
));
7591 /* Reuse request to process response */
7592 response
= (wl_stats_report_t
*)pbuf
;
7595 if (response
->version
!= WL_STATS_REPORT_REQUEST_VERSION_V2
) {
7600 xtlv
= (bcm_xtlv_t
*)(response
->data
);
7603 (BCM_XTLV_LEN(xtlv
) + OFFSETOF(wl_stats_report_t
, data
));
7605 /* Check if the received length is as expected */
7606 if ((response
->length
> WLC_IOCTL_MEDLEN
) ||
7607 (response
->length
< expected_resp_len
)) {
7609 WL_ERR(("Illegal response length received. Got: %d"
7610 " Expected: %d. Expected len must be <= %u\n",
7611 response
->length
, expected_resp_len
, WLC_IOCTL_MEDLEN
));
7615 /* check the type. The return data will be in
7616 * WL_IFSTATS_XTLV_IF container. So check if that container is
7619 if (BCM_XTLV_ID(xtlv
) != WL_IFSTATS_XTLV_IF
) {
7621 WL_ERR(("unexpected type received: %d Expected: %d\n",
7622 BCM_XTLV_ID(xtlv
), WL_IFSTATS_XTLV_IF
));
7626 /* Process XTLVs within WL_IFSTATS_XTLV_IF container */
7627 ret
= bcm_unpack_xtlv_buf(if_stats
,
7628 (uint8
*)response
->data
+ BCM_XTLV_HDR_SIZE
,
7629 BCM_XTLV_LEN(xtlv
), /* total length of all TLVs in container */
7630 BCM_XTLV_OPTION_ALIGN32
, wl_cfg80211_ifstats_counters_cb
);
7632 WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret
));
7637 MFREE(dhdp
->osh
, pbuf
, WLC_IOCTL_MEDLEN
);
7641 MFREE(dhdp
->osh
, request
, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
);
7645 #undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
7648 wl_check_assoc_state(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
7650 wl_assoc_info_t asinfo
;
7654 err
= wldev_iovar_getbuf_bsscfg(dev
, "assoc_info",
7655 NULL
, 0, cfg
->ioctl_buf
, WLC_IOCTL_MEDLEN
, 0, &cfg
->ioctl_buf_sync
);
7656 if (unlikely(err
)) {
7657 WL_ERR(("failed to get assoc_info : err=%d\n", err
));
7660 memcpy(&asinfo
, cfg
->ioctl_buf
, sizeof(wl_assoc_info_t
));
7661 state
= dtoh32(asinfo
.state
);
7662 WL_DBG(("assoc state=%d\n", state
));
7665 return (state
> 0)? TRUE
:FALSE
;
7669 wl_cfg80211_get_rssi(struct net_device
*dev
, struct bcm_cfg80211
*cfg
, s32
*rssi
)
7673 #ifdef SUPPORT_RSSI_SUM_REPORT
7674 wl_rssi_ant_mimo_t rssi_ant_mimo
;
7675 #endif /* SUPPORT_RSSI_SUM_REPORT */
7677 if (dev
== NULL
|| cfg
== NULL
) {
7681 /* initialize rssi */
7684 #ifdef SUPPORT_RSSI_SUM_REPORT
7685 /* Query RSSI sum across antennas */
7686 memset(&rssi_ant_mimo
, 0, sizeof(rssi_ant_mimo
));
7687 err
= wl_get_rssi_per_ant(dev
, dev
->name
, NULL
, &rssi_ant_mimo
);
7689 WL_ERR(("Could not get rssi sum (%d)\n", err
));
7690 /* set rssi to zero and do not return error,
7691 * because iovar phy_rssi_ant could return BCME_UNSUPPORTED
7692 * when bssid was null during roaming
7696 cfg
->rssi_sum_report
= TRUE
;
7697 if ((*rssi
= rssi_ant_mimo
.rssi_sum
) >= 0) {
7701 #endif /* SUPPORT_RSSI_SUM_REPORT */
7703 /* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore */
7704 if (cfg
->rssi_sum_report
== FALSE
) {
7705 memset(&scb_val
, 0, sizeof(scb_val
));
7707 err
= wldev_ioctl_get(dev
, WLC_GET_RSSI
, &scb_val
,
7710 WL_ERR(("Could not get rssi (%d)\n", err
));
7713 *rssi
= wl_rssi_offset(dtoh32(scb_val
.val
));
7717 /* check assoc status including roaming */
7718 DHD_OS_WAKE_LOCK((dhd_pub_t
*)(cfg
->pub
));
7719 if (wl_get_drv_status(cfg
, CONNECTED
, dev
) && wl_check_assoc_state(cfg
, dev
)) {
7720 *rssi
= cfg
->rssi
; /* use previous RSSI */
7721 WL_DBG(("use previous RSSI %d dBm\n", cfg
->rssi
));
7725 DHD_OS_WAKE_UNLOCK((dhd_pub_t
*)(cfg
->pub
));
7727 /* backup the current rssi */
7734 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
7736 wl_cfg80211_get_station(struct wiphy
*wiphy
, struct net_device
*dev
,
7737 const u8
*mac
, struct station_info
*sinfo
)
7740 wl_cfg80211_get_station(struct wiphy
*wiphy
, struct net_device
*dev
,
7741 u8
*mac
, struct station_info
*sinfo
)
7744 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7750 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
7751 s8 eabuf
[ETHER_ADDR_STR_LEN
];
7753 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
7754 bool fw_assoc_state
= FALSE
;
7755 u32 dhd_assoc_state
= 0;
7757 RETURN_EIO_IF_NOT_UP(cfg
);
7759 mode
= wl_get_mode_by_netdev(cfg
, dev
);
7764 buf
= MALLOC(cfg
->osh
, MAX(sizeof(wl_if_stats_t
), WLC_IOCTL_SMLEN
));
7766 WL_ERR(("%s(%d): MALLOC failed\n", __FUNCTION__
, __LINE__
));
7769 if (mode
== WL_MODE_AP
) {
7770 err
= wldev_iovar_getbuf(dev
, "sta_info", (const void*)mac
,
7771 ETHER_ADDR_LEN
, buf
, WLC_IOCTL_SMLEN
, NULL
);
7773 WL_ERR(("GET STA INFO failed, %d\n", err
));
7776 sinfo
->filled
= STA_INFO_BIT(INFO_INACTIVE_TIME
);
7777 sta
= (sta_info_v4_t
*)buf
;
7778 if (sta
->ver
!= WL_STA_VER_4
&& sta
->ver
!= WL_STA_VER_5
) {
7779 WL_ERR(("GET STA INFO version mismatch, %d\n", err
));
7780 return BCME_VERSION
;
7782 sta
->len
= dtoh16(sta
->len
);
7783 sta
->cap
= dtoh16(sta
->cap
);
7784 sta
->flags
= dtoh32(sta
->flags
);
7785 sta
->idle
= dtoh32(sta
->idle
);
7786 sta
->in
= dtoh32(sta
->in
);
7787 sinfo
->inactive_time
= sta
->idle
* 1000;
7788 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
7789 if (sta
->flags
& WL_STA_ASSOC
) {
7790 sinfo
->filled
|= STA_INFO_BIT(INFO_CONNECTED_TIME
);
7791 sinfo
->connected_time
= sta
->in
;
7793 WL_INFORM_MEM(("[%s] STA %s : idle time : %d sec, connected time :%d ms\n",
7794 dev
->name
, bcm_ether_ntoa((const struct ether_addr
*)mac
, eabuf
),
7795 sinfo
->inactive_time
, sta
->idle
* 1000));
7797 } else if ((mode
== WL_MODE_BSS
) || (mode
== WL_MODE_IBSS
)) {
7798 get_pktcnt_t pktcnt
;
7799 wl_if_stats_t
*if_stats
= NULL
;
7802 if (cfg
->roam_offload
) {
7803 struct ether_addr bssid
;
7804 memset(&bssid
, 0, sizeof(bssid
));
7805 err
= wldev_ioctl_get(dev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
7807 WL_ERR(("Failed to get current BSSID\n"));
7809 if (memcmp(mac
, &bssid
.octet
, ETHER_ADDR_LEN
) != 0) {
7810 /* roaming is detected */
7811 err
= wl_cfg80211_delayed_roam(cfg
, dev
, &bssid
);
7813 WL_ERR(("Failed to handle the delayed roam, "
7815 mac
= (u8
*)bssid
.octet
;
7819 dhd_assoc_state
= wl_get_drv_status(cfg
, CONNECTED
, dev
);
7820 DHD_OS_WAKE_LOCK(dhd
);
7821 fw_assoc_state
= dhd_is_associated(dhd
, 0, &err
);
7822 if (dhd_assoc_state
&& !fw_assoc_state
) {
7823 /* check roam (join) status */
7824 if (wl_check_assoc_state(cfg
, dev
)) {
7825 fw_assoc_state
= TRUE
;
7826 WL_DBG(("roam status\n"));
7829 DHD_OS_WAKE_UNLOCK(dhd
);
7830 if (!dhd_assoc_state
|| !fw_assoc_state
) {
7831 WL_ERR(("NOT assoc\n"));
7832 if (err
== -ENODATA
)
7834 if (!dhd_assoc_state
) {
7835 WL_TRACE_HW4(("drv state is not connected \n"));
7837 if (!fw_assoc_state
) {
7838 WL_TRACE_HW4(("fw state is not associated \n"));
7840 /* Disconnect due to fw is not associated for FW_ASSOC_WATCHDOG_TIME ms.
7841 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
7842 * means that BSSID is null.
7844 if (dhd_assoc_state
&& !fw_assoc_state
&& !err
) {
7845 if (!fw_assoc_watchdog_started
) {
7846 fw_assoc_watchdog_ms
= OSL_SYSUPTIME();
7847 fw_assoc_watchdog_started
= TRUE
;
7848 WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
7850 if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms
>
7851 FW_ASSOC_WATCHDOG_TIME
) {
7852 fw_assoc_watchdog_started
= FALSE
;
7854 WL_TRACE_HW4(("fw is not associated for %d ms \n",
7855 (OSL_SYSUPTIME() - fw_assoc_watchdog_ms
)));
7856 goto get_station_err
;
7863 if (dhd_is_associated(dhd
, 0, NULL
)) {
7864 fw_assoc_watchdog_started
= FALSE
;
7866 curmacp
= wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
7867 if (memcmp(mac
, curmacp
, ETHER_ADDR_LEN
)) {
7868 WL_ERR(("Wrong Mac address: "MACDBG
" != "MACDBG
"\n",
7869 MAC2STRDBG(mac
), MAC2STRDBG(curmacp
)));
7872 /* Report the current tx rate */
7874 err
= wldev_ioctl_get(dev
, WLC_GET_RATE
, &rate
, sizeof(rate
));
7876 WL_ERR(("Could not get rate (%d)\n", err
));
7878 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7881 rate
= dtoh32(rate
);
7882 sinfo
->filled
|= STA_INFO_BIT(INFO_TX_BITRATE
);
7883 sinfo
->txrate
.legacy
= rate
* 5;
7884 WL_DBG(("Rate %d Mbps\n", (rate
/ 2)));
7885 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7886 rxpktglom
= ((rate
/2) > 150) ? 20 : 10;
7888 if (maxrxpktglom
!= rxpktglom
) {
7889 maxrxpktglom
= rxpktglom
;
7890 WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate
/2),
7892 err
= wldev_iovar_setbuf(dev
, "bus:maxtxpktglom",
7893 (char*)&maxrxpktglom
, 4, cfg
->ioctl_buf
,
7894 WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
7896 WL_ERR(("set bus:maxtxpktglom failed, %d\n", err
));
7902 if ((err
= wl_cfg80211_get_rssi(dev
, cfg
, &rssi
)) != BCME_OK
) {
7903 goto get_station_err
;
7905 sinfo
->filled
|= STA_INFO_BIT(INFO_SIGNAL
);
7906 sinfo
->signal
= rssi
;
7907 WL_DBG(("RSSI %d dBm\n", rssi
));
7909 if_stats
= (wl_if_stats_t
*)buf
;
7910 memset(if_stats
, 0, sizeof(*if_stats
));
7912 if (FW_SUPPORTED(dhd
, ifst
)) {
7913 err
= wl_cfg80211_ifstats_counters(dev
, if_stats
);
7916 err
= wldev_iovar_getbuf(dev
, "if_counters", NULL
, 0,
7917 (char *)if_stats
, sizeof(*if_stats
), NULL
);
7921 WL_ERR(("if_counters not supported ret=%d\n", err
));
7922 memset(&pktcnt
, 0, sizeof(pktcnt
));
7923 err
= wldev_ioctl_get(dev
, WLC_GET_PKTCNTS
, &pktcnt
,
7926 sinfo
->rx_packets
= pktcnt
.rx_good_pkt
;
7927 sinfo
->rx_dropped_misc
= pktcnt
.rx_bad_pkt
;
7928 sinfo
->tx_packets
= pktcnt
.tx_good_pkt
;
7929 sinfo
->tx_failed
= pktcnt
.tx_bad_pkt
;
7932 sinfo
->rx_packets
= (uint32
)dtoh64(if_stats
->rxframe
);
7933 sinfo
->rx_dropped_misc
= 0;
7934 sinfo
->tx_packets
= (uint32
)dtoh64(if_stats
->txfrmsnt
);
7935 sinfo
->tx_failed
= (uint32
)dtoh64(if_stats
->txnobuf
) +
7936 (uint32
)dtoh64(if_stats
->txrunt
) +
7937 (uint32
)dtoh64(if_stats
->txfail
);
7940 sinfo
->filled
|= (STA_INFO_BIT(INFO_RX_PACKETS
) |
7941 STA_INFO_BIT(INFO_RX_DROP_MISC
) |
7942 STA_INFO_BIT(INFO_TX_PACKETS
) |
7943 STA_INFO_BIT(INFO_TX_FAILED
));
7946 if (err
&& (err
!= -ENODATA
)) {
7947 /* Disconnect due to zero BSSID or error to get RSSI */
7949 scbval
.val
= htod32(DOT11_RC_DISASSOC_LEAVING
);
7950 err
= wldev_ioctl_set(dev
, WLC_DISASSOC
, &scbval
, sizeof(scb_val_t
));
7951 if (unlikely(err
)) {
7952 WL_ERR(("disassoc error (%d)\n", err
));
7955 WL_ERR(("force cfg80211_disconnected: %d\n", err
));
7956 wl_clr_drv_status(cfg
, CONNECTED
, dev
);
7957 CFG80211_DISCONNECTED(dev
, 0, NULL
, 0, false, GFP_KERNEL
);
7962 WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg
, dev
)));
7966 MFREE(cfg
->osh
, buf
, MAX(sizeof(wl_if_stats_t
), WLC_IOCTL_SMLEN
));
7972 wl_cfg80211_set_power_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
7973 bool enabled
, s32 timeout
)
7977 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
7978 struct net_info
*_net_info
= wl_get_netinfo_by_netdev(cfg
, dev
);
7981 dhd_pub_t
*dhd
= cfg
->pub
;
7982 rtt_status_info_t
*rtt_status
;
7983 #endif /* RTT_SUPPORT */
7984 RETURN_EIO_IF_NOT_UP(cfg
);
7986 WL_DBG(("Enter\n"));
7987 mode
= wl_get_mode_by_netdev(cfg
, dev
);
7988 if (cfg
->p2p_net
== dev
|| _net_info
== NULL
||
7989 !wl_get_drv_status(cfg
, CONNECTED
, dev
) ||
7990 ((mode
!= WL_MODE_BSS
) &&
7991 (mode
!= WL_MODE_IBSS
))) {
7995 /* Enlarge pm_enable_work */
7996 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_LONG
);
7998 pm
= enabled
? PM_FAST
: PM_OFF
;
7999 if (_net_info
->pm_block
) {
8000 WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
8001 dev
->name
, _net_info
->pm_block
));
8005 WL_DBG(("%s:power save %s\n", dev
->name
, (pm
? "enabled" : "disabled")));
8007 rtt_status
= GET_RTTSTATE(dhd
);
8008 if (rtt_status
->status
!= RTT_ENABLED
) {
8009 #endif /* RTT_SUPPORT */
8010 err
= wldev_ioctl_set(dev
, WLC_SET_PM
, &pm
, sizeof(pm
));
8011 if (unlikely(err
)) {
8013 WL_DBG(("net_device is not ready yet\n"));
8015 WL_ERR(("error (%d)\n", err
));
8020 #endif /* RTT_SUPPORT */
8021 wl_cfg80211_update_power_mode(dev
);
8025 void wl_cfg80211_update_power_mode(struct net_device
*dev
)
8029 err
= wldev_ioctl_get(dev
, WLC_GET_PM
, &pm
, sizeof(pm
));
8031 WL_ERR(("%s:error (%d)\n", __FUNCTION__
, err
));
8032 else if (pm
!= -1 && dev
->ieee80211_ptr
)
8033 dev
->ieee80211_ptr
->ps
= (pm
== PM_OFF
) ? false : true;
8036 void wl_cfg80211_set_passive_scan(struct net_device
*dev
, char *command
)
8038 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
8040 if (strcmp(command
, "SCAN-ACTIVE") == 0) {
8041 cfg
->active_scan
= 1;
8042 } else if (strcmp(command
, "SCAN-PASSIVE") == 0) {
8043 cfg
->active_scan
= 0;
8045 WL_ERR(("Unknown command \n"));
8049 static __used u32
wl_find_msb(u16 bit16
)
8053 if (bit16
& 0xff00) {
8076 static s32
wl_cfg80211_resume(struct wiphy
*wiphy
)
8078 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8079 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
8082 if (unlikely(!wl_get_drv_status(cfg
, READY
, ndev
))) {
8083 WL_INFORM_MEM(("device is not ready\n"));
8090 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
8091 static s32
wl_cfg80211_suspend(struct wiphy
*wiphy
, struct cfg80211_wowlan
*wow
)
8093 static s32
wl_cfg80211_suspend(struct wiphy
*wiphy
)
8097 #ifdef DHD_CLEAR_ON_SUSPEND
8098 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8099 struct net_info
*iter
, *next
;
8100 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
8101 unsigned long flags
;
8102 if (unlikely(!wl_get_drv_status(cfg
, READY
, ndev
))) {
8103 WL_INFORM_MEM(("device is not ready : status (%d)\n",
8107 for_each_ndev(cfg
, iter
, next
) {
8108 /* p2p discovery iface doesn't have a ndev associated with it (for kernel > 3.8) */
8110 wl_set_drv_status(cfg
, SCAN_ABORTING
, iter
->ndev
);
8112 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
8113 if (cfg
->scan_request
) {
8114 cfg80211_scan_done(cfg
->scan_request
, true);
8115 cfg
->scan_request
= NULL
;
8117 for_each_ndev(cfg
, iter
, next
) {
8119 wl_clr_drv_status(cfg
, SCANNING
, iter
->ndev
);
8120 wl_clr_drv_status(cfg
, SCAN_ABORTING
, iter
->ndev
);
8123 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
8124 for_each_ndev(cfg
, iter
, next
) {
8126 if (wl_get_drv_status(cfg
, CONNECTING
, iter
->ndev
)) {
8127 wl_bss_connect_done(cfg
, iter
->ndev
, NULL
, NULL
, false);
8131 #endif /* DHD_CLEAR_ON_SUSPEND */
8137 wl_update_pmklist(struct net_device
*dev
, struct wl_pmk_list
*pmk_list
,
8141 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
8142 struct net_device
*primary_dev
= bcmcfg_to_prmry_ndev(cfg
);
8145 WL_INFORM_MEM(("pmk_list is NULL\n"));
8148 /* pmk list is supported only for STA interface i.e. primary interface
8149 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
8151 if (primary_dev
!= dev
) {
8152 WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
8153 " interfaces than primary interface\n"));
8157 WL_DBG(("No of elements %d\n", pmk_list
->pmkids
.npmkid
));
8158 for (i
= 0; i
< pmk_list
->pmkids
.npmkid
; i
++) {
8159 WL_DBG(("PMKID[%d]: %pM =\n", i
,
8160 &pmk_list
->pmkids
.pmkid
[i
].BSSID
));
8161 for (j
= 0; j
< WPA2_PMKID_LEN
; j
++) {
8162 WL_DBG(("%02x\n", pmk_list
->pmkids
.pmkid
[i
].PMKID
[j
]));
8166 err
= wldev_iovar_setbuf(dev
, "pmkid_info", (char *)pmk_list
,
8167 sizeof(*pmk_list
), cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
8174 wl_cfg80211_set_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
8175 struct cfg80211_pmksa
*pmksa
)
8177 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8181 RETURN_EIO_IF_NOT_UP(cfg
);
8182 for (i
= 0; i
< cfg
->pmk_list
->pmkids
.npmkid
; i
++)
8183 if (!memcmp(pmksa
->bssid
, &cfg
->pmk_list
->pmkids
.pmkid
[i
].BSSID
,
8186 if (i
< WL_NUM_PMKIDS_MAX
) {
8187 memcpy(&cfg
->pmk_list
->pmkids
.pmkid
[i
].BSSID
, pmksa
->bssid
,
8189 memcpy(&cfg
->pmk_list
->pmkids
.pmkid
[i
].PMKID
, pmksa
->pmkid
,
8191 if (i
== cfg
->pmk_list
->pmkids
.npmkid
)
8192 cfg
->pmk_list
->pmkids
.npmkid
++;
8196 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
8197 &cfg
->pmk_list
->pmkids
.pmkid
[cfg
->pmk_list
->pmkids
.npmkid
- 1].BSSID
));
8198 for (i
= 0; i
< WPA2_PMKID_LEN
; i
++) {
8200 cfg
->pmk_list
->pmkids
.pmkid
[cfg
->pmk_list
->pmkids
.npmkid
- 1].
8204 err
= wl_update_pmklist(dev
, cfg
->pmk_list
, err
);
8210 wl_cfg80211_del_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
,
8211 struct cfg80211_pmksa
*pmksa
)
8213 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8215 pmkid_list_t pmkid
= {.npmkid
= 0};
8219 RETURN_EIO_IF_NOT_UP(cfg
);
8220 memcpy(&pmkid
.pmkid
[0].BSSID
, pmksa
->bssid
, ETHER_ADDR_LEN
);
8221 memcpy(pmkid
.pmkid
[0].PMKID
, pmksa
->pmkid
, WPA2_PMKID_LEN
);
8223 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
8224 &pmkid
.pmkid
[0].BSSID
));
8225 for (i
= 0; i
< WPA2_PMKID_LEN
; i
++) {
8226 WL_DBG(("%02x\n", pmkid
.pmkid
[0].PMKID
[i
]));
8229 for (i
= 0; i
< cfg
->pmk_list
->pmkids
.npmkid
; i
++)
8231 (pmksa
->bssid
, &cfg
->pmk_list
->pmkids
.pmkid
[i
].BSSID
,
8235 if ((cfg
->pmk_list
->pmkids
.npmkid
> 0) &&
8236 (i
< cfg
->pmk_list
->pmkids
.npmkid
)) {
8237 memset(&cfg
->pmk_list
->pmkids
.pmkid
[i
], 0, sizeof(pmkid_t
));
8238 for (; i
< (cfg
->pmk_list
->pmkids
.npmkid
- 1); i
++) {
8239 memcpy(&cfg
->pmk_list
->pmkids
.pmkid
[i
].BSSID
,
8240 &cfg
->pmk_list
->pmkids
.pmkid
[i
+ 1].BSSID
,
8242 memcpy(&cfg
->pmk_list
->pmkids
.pmkid
[i
].PMKID
,
8243 &cfg
->pmk_list
->pmkids
.pmkid
[i
+ 1].PMKID
,
8246 cfg
->pmk_list
->pmkids
.npmkid
--;
8251 err
= wl_update_pmklist(dev
, cfg
->pmk_list
, err
);
8258 wl_cfg80211_flush_pmksa(struct wiphy
*wiphy
, struct net_device
*dev
)
8260 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8262 RETURN_EIO_IF_NOT_UP(cfg
);
8263 memset(cfg
->pmk_list
, 0, sizeof(*cfg
->pmk_list
));
8264 err
= wl_update_pmklist(dev
, cfg
->pmk_list
, err
);
8268 static wl_scan_params_t
*
8269 wl_cfg80211_scan_alloc_params(struct bcm_cfg80211
*cfg
, int channel
, int nprobes
,
8270 int *out_params_size
)
8272 wl_scan_params_t
*params
;
8276 *out_params_size
= 0;
8278 /* Our scan params only need space for 1 channel and 0 ssids */
8279 params_size
= WL_SCAN_PARAMS_FIXED_SIZE
+ 1 * sizeof(uint16
);
8280 params
= (wl_scan_params_t
*)MALLOCZ(cfg
->osh
, params_size
);
8281 if (params
== NULL
) {
8282 WL_ERR(("mem alloc failed (%d bytes)\n", params_size
));
8285 memset(params
, 0, params_size
);
8286 params
->nprobes
= nprobes
;
8288 num_chans
= (channel
== 0) ? 0 : 1;
8290 memcpy(¶ms
->bssid
, ðer_bcast
, ETHER_ADDR_LEN
);
8291 params
->bss_type
= DOT11_BSSTYPE_ANY
;
8292 params
->scan_type
= DOT11_SCANTYPE_ACTIVE
;
8293 params
->nprobes
= htod32(1);
8294 params
->active_time
= htod32(-1);
8295 params
->passive_time
= htod32(-1);
8296 params
->home_time
= htod32(10);
8298 params
->channel_list
[0] = htodchanspec(channel
);
8300 params
->channel_list
[0] = wl_ch_host_to_driver(channel
);
8302 /* Our scan params have 1 channel and 0 ssids */
8303 params
->channel_num
= htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT
) |
8304 (num_chans
& WL_SCAN_PARAMS_COUNT_MASK
));
8306 *out_params_size
= params_size
; /* rtn size to the caller */
8310 #if defined(WL_CFG80211_P2P_DEV_IF)
8312 wl_cfg80211_remain_on_channel(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
,
8313 struct ieee80211_channel
*channel
, unsigned int duration
, u64
*cookie
)
8316 wl_cfg80211_remain_on_channel(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
,
8317 struct ieee80211_channel
* channel
,
8318 enum nl80211_channel_type channel_type
,
8319 unsigned int duration
, u64
*cookie
)
8320 #endif /* WL_CFG80211_P2P_DEV_IF */
8325 struct ether_addr primary_mac
;
8326 struct net_device
*ndev
= NULL
;
8327 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8329 RETURN_EIO_IF_NOT_UP(cfg
);
8331 PRINT_WDEV_INFO(cfgdev
);
8332 #endif /* DHD_IFDEBUG */
8334 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
8337 if (wl_cfgnan_check_state(cfg
)) {
8338 WL_ERR(("nan is enabled, nan + p2p concurrency not supported\n"));
8339 return BCME_UNSUPPORTED
;
8343 mutex_lock(&cfg
->usr_sync
);
8344 WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
8345 ieee80211_frequency_to_channel(channel
->center_freq
),
8346 duration
, (wl_get_drv_status(cfg
, SCANNING
, ndev
)) ? "YES":"NO"));
8349 WL_ERR(("cfg->p2p is not initialized\n"));
8354 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8355 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
8356 wl_cfg80211_cancel_scan(cfg
);
8358 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8360 #ifdef P2P_LISTEN_OFFLOADING
8361 wl_cfg80211_cancel_p2plo(cfg
);
8362 #endif /* P2P_LISTEN_OFFLOADING */
8364 target_channel
= ieee80211_frequency_to_channel(channel
->center_freq
);
8365 memcpy(&cfg
->remain_on_chan
, channel
, sizeof(struct ieee80211_channel
));
8366 #if defined(WL_ENABLE_P2P_IF)
8367 cfg
->remain_on_chan_type
= channel_type
;
8368 #endif /* WL_ENABLE_P2P_IF */
8369 id
= ++cfg
->last_roc_id
;
8371 id
= ++cfg
->last_roc_id
;
8374 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8375 if (wl_get_drv_status(cfg
, SCANNING
, ndev
)) {
8376 struct timer_list
*_timer
;
8377 WL_DBG(("scan is running. go to fake listen state\n"));
8379 if (duration
> LONG_LISTEN_TIME
) {
8380 wl_cfg80211_scan_abort(cfg
);
8382 wl_set_drv_status(cfg
, FAKE_REMAINING_ON_CHANNEL
, ndev
);
8384 if (timer_pending(&cfg
->p2p
->listen_timer
)) {
8385 WL_DBG(("cancel current listen timer \n"));
8386 del_timer_sync(&cfg
->p2p
->listen_timer
);
8389 _timer
= &cfg
->p2p
->listen_timer
;
8390 wl_clr_p2p_status(cfg
, LISTEN_EXPIRED
);
8392 INIT_TIMER(_timer
, wl_cfgp2p_listen_expired
, duration
, 0);
8398 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8401 /* check fakeapscan in progress then abort */
8402 wl_android_bcnrecv_stop(ndev
, WL_BCNRECV_LISTENBUSY
);
8403 #endif /* WL_BCNRECV */
8404 #ifdef WL_CFG80211_SYNC_GON
8405 if (wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM_LISTEN
)) {
8406 /* do not enter listen mode again if we are in listen mode already for next af.
8407 * remain on channel completion will be returned by waiting next af completion.
8409 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8410 wl_set_drv_status(cfg
, FAKE_REMAINING_ON_CHANNEL
, ndev
);
8412 wl_set_drv_status(cfg
, REMAINING_ON_CHANNEL
, ndev
);
8413 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8416 #endif /* WL_CFG80211_SYNC_GON */
8417 if (cfg
->p2p
&& !cfg
->p2p
->on
) {
8418 /* In case of p2p_listen command, supplicant send remain_on_channel
8419 * without turning on P2P
8421 get_primary_mac(cfg
, &primary_mac
);
8422 wl_cfgp2p_generate_bss_mac(cfg
, &primary_mac
);
8426 if (p2p_is_on(cfg
)) {
8427 err
= wl_cfgp2p_enable_discovery(cfg
, ndev
, NULL
, 0);
8428 if (unlikely(err
)) {
8431 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8432 wl_set_drv_status(cfg
, REMAINING_ON_CHANNEL
, ndev
);
8433 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8434 err
= wl_cfgp2p_discover_listen(cfg
, target_channel
, duration
);
8436 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8437 if (err
== BCME_OK
) {
8438 wl_set_drv_status(cfg
, REMAINING_ON_CHANNEL
, ndev
);
8440 /* if failed, firmware may be internal scanning state.
8441 * so other scan request shall not abort it
8443 wl_set_drv_status(cfg
, FAKE_REMAINING_ON_CHANNEL
, ndev
);
8445 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8448 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
8451 /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant
8452 * and expire timer will send a completion to the upper layer
8458 if (err
== BCME_OK
) {
8459 WL_DBG(("Success\n"));
8460 #if defined(WL_CFG80211_P2P_DEV_IF)
8461 cfg80211_ready_on_channel(cfgdev
, *cookie
, channel
,
8462 duration
, GFP_KERNEL
);
8464 cfg80211_ready_on_channel(cfgdev
, *cookie
, channel
,
8465 channel_type
, duration
, GFP_KERNEL
);
8466 #endif /* WL_CFG80211_P2P_DEV_IF */
8468 WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err
, *cookie
));
8470 mutex_unlock(&cfg
->usr_sync
);
8475 wl_cfg80211_cancel_remain_on_channel(struct wiphy
*wiphy
,
8476 bcm_struct_cfgdev
*cfgdev
, u64 cookie
)
8480 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8482 #ifdef P2PLISTEN_AP_SAMECHN
8483 struct net_device
*dev
;
8484 #endif /* P2PLISTEN_AP_SAMECHN */
8486 RETURN_EIO_IF_NOT_UP(cfg
);
8489 PRINT_WDEV_INFO(cfgdev
);
8490 #endif /* DHD_IFDEBUG */
8492 #if defined(WL_CFG80211_P2P_DEV_IF)
8493 if (cfgdev
->iftype
== NL80211_IFTYPE_P2P_DEVICE
) {
8494 WL_DBG((" enter ) on P2P dedicated discover interface\n"));
8497 WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev
->ifindex
));
8498 #endif /* WL_CFG80211_P2P_DEV_IF */
8500 #ifdef P2PLISTEN_AP_SAMECHN
8501 if (cfg
&& cfg
->p2p_resp_apchn_status
) {
8502 dev
= bcmcfg_to_prmry_ndev(cfg
);
8503 wl_cfg80211_set_p2p_resp_ap_chn(dev
, 0);
8504 cfg
->p2p_resp_apchn_status
= false;
8505 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
8507 #endif /* P2PLISTEN_AP_SAMECHN */
8509 if (cfg
->last_roc_id
== cookie
) {
8510 wl_cfgp2p_set_p2p_mode(cfg
, WL_P2P_DISC_ST_SCAN
, 0, 0,
8511 wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
));
8513 WL_ERR(("%s : ignore, request cookie(%llu) is not matched. (cur : %llu)\n",
8514 __FUNCTION__
, cookie
, cfg
->last_roc_id
));
8521 wl_cfg80211_afx_handler(struct work_struct
*work
)
8523 struct afx_hdl
*afx_instance
;
8524 struct bcm_cfg80211
*cfg
;
8527 BCM_SET_CONTAINER_OF(afx_instance
, work
, struct afx_hdl
, work
);
8529 cfg
= wl_get_cfg(afx_instance
->dev
);
8530 if (cfg
!= NULL
&& cfg
->afx_hdl
->is_active
) {
8531 if (cfg
->afx_hdl
->is_listen
&& cfg
->afx_hdl
->my_listen_chan
) {
8532 ret
= wl_cfgp2p_discover_listen(cfg
, cfg
->afx_hdl
->my_listen_chan
,
8533 (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
8535 ret
= wl_cfgp2p_act_frm_search(cfg
, cfg
->afx_hdl
->dev
,
8536 cfg
->afx_hdl
->bssidx
, cfg
->afx_hdl
->peer_listen_chan
,
8539 if (unlikely(ret
!= BCME_OK
)) {
8540 WL_ERR(("ERROR occurred! returned value is (%d)\n", ret
));
8541 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
))
8542 complete(&cfg
->act_frm_scan
);
8549 wl_cfg80211_af_searching_channel(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
8551 u32 max_retry
= WL_CHANNEL_SYNC_RETRY
;
8552 bool is_p2p_gas
= false;
8557 WL_DBG((" enter ) \n"));
8559 wl_set_drv_status(cfg
, FINDING_COMMON_CHANNEL
, dev
);
8560 cfg
->afx_hdl
->is_active
= TRUE
;
8562 if (cfg
->afx_hdl
->pending_tx_act_frm
) {
8563 wl_action_frame_t
*action_frame
;
8564 action_frame
= &(cfg
->afx_hdl
->pending_tx_act_frm
->action_frame
);
8565 if (wl_cfgp2p_is_p2p_gas_action(action_frame
->data
, action_frame
->len
))
8569 /* Loop to wait until we find a peer's channel or the
8570 * pending action frame tx is cancelled.
8572 while ((cfg
->afx_hdl
->retry
< max_retry
) &&
8573 (cfg
->afx_hdl
->peer_chan
== WL_INVALID
)) {
8574 cfg
->afx_hdl
->is_listen
= FALSE
;
8575 wl_set_drv_status(cfg
, SCANNING
, dev
);
8576 WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
8577 cfg
->afx_hdl
->retry
));
8578 /* search peer on peer's listen channel */
8579 schedule_work(&cfg
->afx_hdl
->work
);
8580 wait_for_completion_timeout(&cfg
->act_frm_scan
,
8581 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX
));
8583 if ((cfg
->afx_hdl
->peer_chan
!= WL_INVALID
) ||
8584 !(wl_get_drv_status(cfg
, FINDING_COMMON_CHANNEL
, dev
)))
8590 if (cfg
->afx_hdl
->my_listen_chan
) {
8591 WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
8592 cfg
->afx_hdl
->my_listen_chan
));
8593 /* listen on my listen channel */
8594 cfg
->afx_hdl
->is_listen
= TRUE
;
8595 schedule_work(&cfg
->afx_hdl
->work
);
8596 wait_for_completion_timeout(&cfg
->act_frm_scan
,
8597 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX
));
8599 if ((cfg
->afx_hdl
->peer_chan
!= WL_INVALID
) ||
8600 !(wl_get_drv_status(cfg
, FINDING_COMMON_CHANNEL
, dev
)))
8603 cfg
->afx_hdl
->retry
++;
8605 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg
);
8608 cfg
->afx_hdl
->is_active
= FALSE
;
8610 wl_clr_drv_status(cfg
, SCANNING
, dev
);
8611 wl_clr_drv_status(cfg
, FINDING_COMMON_CHANNEL
, dev
);
8613 return (cfg
->afx_hdl
->peer_chan
);
8616 struct p2p_config_af_params
{
8617 s32 max_tx_retry
; /* max tx retry count if tx no ack */
8618 #ifdef WL_CFG80211_GON_COLLISION
8619 /* drop tx go nego request if go nego collision occurs */
8622 #ifdef WL_CFG80211_SYNC_GON
8625 bool search_channel
; /* 1: search peer's channel to send af */
8629 wl_cfg80211_config_p2p_pub_af_tx(struct wiphy
*wiphy
,
8630 wl_action_frame_t
*action_frame
, wl_af_params_t
*af_params
,
8631 struct p2p_config_af_params
*config_af_params
)
8634 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8635 wifi_p2p_pub_act_frame_t
*act_frm
=
8636 (wifi_p2p_pub_act_frame_t
*) (action_frame
->data
);
8638 /* initialize default value */
8639 #ifdef WL_CFG80211_GON_COLLISION
8640 config_af_params
->drop_tx_req
= false;
8642 #ifdef WL_CFG80211_SYNC_GON
8643 config_af_params
->extra_listen
= true;
8645 config_af_params
->search_channel
= false;
8646 config_af_params
->max_tx_retry
= WL_AF_TX_MAX_RETRY
;
8647 cfg
->next_af_subtype
= P2P_PAF_SUBTYPE_INVALID
;
8649 switch (act_frm
->subtype
) {
8650 case P2P_PAF_GON_REQ
: {
8651 WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
8652 wl_set_p2p_status(cfg
, GO_NEG_PHASE
);
8654 config_af_params
->search_channel
= true;
8655 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
8657 /* increase dwell time to wait for RESP frame */
8658 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
8660 #ifdef WL_CFG80211_GON_COLLISION
8661 config_af_params
->drop_tx_req
= true;
8662 #endif /* WL_CFG80211_GON_COLLISION */
8665 case P2P_PAF_GON_RSP
: {
8666 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
8667 /* increase dwell time to wait for CONF frame */
8668 af_params
->dwell_time
= WL_MED_DWELL_TIME
+ 100;
8671 case P2P_PAF_GON_CONF
: {
8672 /* If we reached till GO Neg confirmation reset the filter */
8673 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
8674 wl_clr_p2p_status(cfg
, GO_NEG_PHASE
);
8676 /* minimize dwell time */
8677 af_params
->dwell_time
= WL_MIN_DWELL_TIME
;
8679 #ifdef WL_CFG80211_GON_COLLISION
8680 /* if go nego formation done, clear it */
8681 cfg
->block_gon_req_tx_count
= 0;
8682 cfg
->block_gon_req_rx_count
= 0;
8683 #endif /* WL_CFG80211_GON_COLLISION */
8684 #ifdef WL_CFG80211_SYNC_GON
8685 config_af_params
->extra_listen
= false;
8686 #endif /* WL_CFG80211_SYNC_GON */
8689 case P2P_PAF_INVITE_REQ
: {
8690 config_af_params
->search_channel
= true;
8691 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
8693 /* increase dwell time */
8694 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
8697 case P2P_PAF_INVITE_RSP
:
8698 /* minimize dwell time */
8699 af_params
->dwell_time
= WL_MIN_DWELL_TIME
;
8700 #ifdef WL_CFG80211_SYNC_GON
8701 config_af_params
->extra_listen
= false;
8702 #endif /* WL_CFG80211_SYNC_GON */
8704 case P2P_PAF_DEVDIS_REQ
: {
8705 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm
->elts
[0],
8706 action_frame
->len
)) {
8707 config_af_params
->search_channel
= true;
8710 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
8711 /* maximize dwell time to wait for RESP frame */
8712 af_params
->dwell_time
= WL_LONG_DWELL_TIME
;
8715 case P2P_PAF_DEVDIS_RSP
:
8716 /* minimize dwell time */
8717 af_params
->dwell_time
= WL_MIN_DWELL_TIME
;
8718 #ifdef WL_CFG80211_SYNC_GON
8719 config_af_params
->extra_listen
= false;
8720 #endif /* WL_CFG80211_SYNC_GON */
8722 case P2P_PAF_PROVDIS_REQ
: {
8723 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm
->elts
[0],
8724 action_frame
->len
)) {
8725 config_af_params
->search_channel
= true;
8728 cfg
->next_af_subtype
= act_frm
->subtype
+ 1;
8729 /* increase dwell time to wait for RESP frame */
8730 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
8733 case P2P_PAF_PROVDIS_RSP
: {
8734 cfg
->next_af_subtype
= P2P_PAF_GON_REQ
;
8735 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
8736 #ifdef WL_CFG80211_SYNC_GON
8737 config_af_params
->extra_listen
= false;
8738 #endif /* WL_CFG80211_SYNC_GON */
8742 WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
8751 wl_cfg80211_check_DFS_channel(struct bcm_cfg80211
*cfg
, wl_af_params_t
*af_params
,
8752 void *frame
, u16 frame_len
)
8754 struct wl_scan_results
*bss_list
;
8755 wl_bss_info_t
*bi
= NULL
;
8756 bool result
= false;
8758 chanspec_t chanspec
;
8760 /* If DFS channel is 52~148, check to block it or not */
8762 (af_params
->channel
>= 52 && af_params
->channel
<= 148)) {
8763 if (!wl_cfgp2p_is_p2p_action(frame
, frame_len
)) {
8764 bss_list
= cfg
->bss_list
;
8765 bi
= next_bss(bss_list
, bi
);
8766 for_each_bss(bss_list
, bi
, i
) {
8767 chanspec
= wl_chspec_driver_to_host(bi
->chanspec
);
8768 if (CHSPEC_IS5G(chanspec
) &&
8769 ((bi
->ctl_ch
? bi
->ctl_ch
: CHSPEC_CHANNEL(chanspec
))
8770 == af_params
->channel
)) {
8771 result
= true; /* do not block the action frame */
8781 WL_DBG(("result=%s", result
?"true":"false"));
8786 wl_cfg80211_check_dwell_overflow(int32 requested_dwell
, ulong dwell_jiffies
)
8788 if ((requested_dwell
& CUSTOM_RETRY_MASK
) &&
8789 (jiffies_to_msecs(jiffies
- dwell_jiffies
) >
8790 (requested_dwell
& ~CUSTOM_RETRY_MASK
))) {
8791 WL_ERR(("Action frame TX retry time over dwell time!\n"));
8798 wl_cfg80211_send_action_frame(struct wiphy
*wiphy
, struct net_device
*dev
,
8799 bcm_struct_cfgdev
*cfgdev
, wl_af_params_t
*af_params
,
8800 wl_action_frame_t
*action_frame
, u16 action_frame_len
, s32 bssidx
)
8803 struct net_device
*ndev
= NULL
;
8805 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
8807 u8 category
, action
;
8809 struct p2p_config_af_params config_af_params
;
8810 struct net_info
*netinfo
;
8812 ulong off_chan_started_jiffies
= 0;
8814 ulong dwell_jiffies
= 0;
8815 bool dwell_overflow
= false;
8816 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
8818 int32 requested_dwell
= af_params
->dwell_time
;
8820 /* Add the default dwell time
8821 * Dwell time to stay off-channel to wait for a response action frame
8822 * after transmitting an GO Negotiation action frame
8824 af_params
->dwell_time
= WL_DWELL_TIME
;
8827 #if defined(WL_CFG80211_P2P_DEV_IF)
8830 ndev
= ndev_to_cfgdev(cfgdev
);
8831 #endif /* WL_CFG80211_P2P_DEV_IF */
8834 category
= action_frame
->data
[DOT11_ACTION_CAT_OFF
];
8835 action
= action_frame
->data
[DOT11_ACTION_ACT_OFF
];
8837 /* initialize variables */
8839 cfg
->next_af_subtype
= P2P_PAF_SUBTYPE_INVALID
;
8840 config_af_params
.max_tx_retry
= WL_AF_TX_MAX_RETRY
;
8841 config_af_params
.search_channel
= false;
8842 #ifdef WL_CFG80211_GON_COLLISION
8843 config_af_params
.drop_tx_req
= false;
8845 #ifdef WL_CFG80211_SYNC_GON
8846 config_af_params
.extra_listen
= false;
8849 /* config parameters */
8850 /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
8851 if (category
== DOT11_ACTION_CAT_PUBLIC
) {
8852 if ((action
== P2P_PUB_AF_ACTION
) &&
8853 (action_frame_len
>= sizeof(wifi_p2p_pub_act_frame_t
))) {
8854 /* p2p public action frame process */
8855 if (BCME_OK
!= wl_cfg80211_config_p2p_pub_af_tx(wiphy
,
8856 action_frame
, af_params
, &config_af_params
)) {
8857 WL_DBG(("Unknown subtype.\n"));
8860 #ifdef WL_CFG80211_GON_COLLISION
8861 if (config_af_params
.drop_tx_req
) {
8862 if (cfg
->block_gon_req_tx_count
) {
8863 /* drop gon req tx action frame */
8864 WL_DBG(("Drop gon req tx action frame: count %d\n",
8865 cfg
->block_gon_req_tx_count
));
8869 #endif /* WL_CFG80211_GON_COLLISION */
8870 } else if (action_frame_len
>= sizeof(wifi_p2psd_gas_pub_act_frame_t
)) {
8871 /* service discovery process */
8872 if (action
== P2PSD_ACTION_ID_GAS_IREQ
||
8873 action
== P2PSD_ACTION_ID_GAS_CREQ
) {
8874 /* configure service discovery query frame */
8876 config_af_params
.search_channel
= true;
8878 /* save next af suptype to cancel remained dwell time */
8879 cfg
->next_af_subtype
= action
+ 1;
8881 af_params
->dwell_time
= WL_MED_DWELL_TIME
;
8882 if (requested_dwell
& CUSTOM_RETRY_MASK
) {
8883 config_af_params
.max_tx_retry
=
8884 (requested_dwell
& CUSTOM_RETRY_MASK
) >> 24;
8885 af_params
->dwell_time
=
8886 (requested_dwell
& ~CUSTOM_RETRY_MASK
);
8887 WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
8888 config_af_params
.max_tx_retry
,
8889 af_params
->dwell_time
));
8891 } else if (action
== P2PSD_ACTION_ID_GAS_IRESP
||
8892 action
== P2PSD_ACTION_ID_GAS_CRESP
) {
8893 /* configure service discovery response frame */
8894 af_params
->dwell_time
= WL_MIN_DWELL_TIME
;
8896 WL_DBG(("Unknown action type: %d\n", action
));
8899 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
8900 category
, action
, action_frame_len
));
8902 } else if (category
== P2P_AF_CATEGORY
) {
8903 /* do not configure anything. it will be sent with a default configuration */
8905 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
8907 if (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
8908 wl_clr_drv_status(cfg
, SENDING_ACT_FRM
, dev
);
8913 netinfo
= wl_get_netinfo_by_wdev(cfg
, cfgdev_to_wdev(cfgdev
));
8914 /* validate channel and p2p ies */
8915 if (config_af_params
.search_channel
&& IS_P2P_SOCIAL(af_params
->channel
) &&
8916 netinfo
&& netinfo
->bss
.ies
.probe_req_ie_len
) {
8917 config_af_params
.search_channel
= true;
8919 config_af_params
.search_channel
= false;
8922 if (ndev
== bcmcfg_to_prmry_ndev(cfg
))
8923 config_af_params
.search_channel
= false;
8927 /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
8928 if (wl_get_drv_status(cfg
, CONNECTING
, bcmcfg_to_prmry_ndev(cfg
))) {
8933 /* if scan is ongoing, abort current scan. */
8934 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
8935 wl_cfg80211_cancel_scan(cfg
);
8938 /* Abort P2P listen */
8939 if (discover_cfgdev(cfgdev
, cfg
)) {
8940 if (cfg
->p2p_supported
&& cfg
->p2p
) {
8941 wl_cfgp2p_set_p2p_mode(cfg
, WL_P2P_DISC_ST_SCAN
, 0, 0,
8942 wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
));
8947 /* handling DFS channel exceptions */
8948 if (!wl_cfg80211_check_DFS_channel(cfg
, af_params
, action_frame
->data
, action_frame
->len
)) {
8949 return false; /* the action frame was blocked */
8953 /* set status and destination address before sending af */
8954 if (cfg
->next_af_subtype
!= P2P_PAF_SUBTYPE_INVALID
) {
8955 /* set this status to cancel the remained dwell time in rx process */
8956 wl_set_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, dev
);
8958 wl_set_drv_status(cfg
, SENDING_ACT_FRM
, dev
);
8959 memcpy(cfg
->afx_hdl
->tx_dst_addr
.octet
,
8960 af_params
->action_frame
.da
.octet
,
8961 sizeof(cfg
->afx_hdl
->tx_dst_addr
.octet
));
8963 /* save af_params for rx process */
8964 cfg
->afx_hdl
->pending_tx_act_frm
= af_params
;
8966 if (wl_cfgp2p_is_p2p_gas_action(action_frame
->data
, action_frame
->len
)) {
8967 WL_DBG(("Set GAS action frame config.\n"));
8968 config_af_params
.search_channel
= false;
8969 config_af_params
.max_tx_retry
= 1;
8972 /* search peer's channel */
8973 if (config_af_params
.search_channel
) {
8974 /* initialize afx_hdl */
8975 if ((cfg
->afx_hdl
->bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
8976 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
8979 cfg
->afx_hdl
->dev
= dev
;
8980 cfg
->afx_hdl
->retry
= 0;
8981 cfg
->afx_hdl
->peer_chan
= WL_INVALID
;
8983 if (wl_cfg80211_af_searching_channel(cfg
, dev
) == WL_INVALID
) {
8984 WL_ERR(("couldn't find peer's channel.\n"));
8985 wl_cfgp2p_print_actframe(true, action_frame
->data
, action_frame
->len
,
8986 af_params
->channel
);
8987 /* Even if we couldn't find peer channel, try to send the frame
8988 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
8989 * respond to probe request (Ideally it has to be in listen and
8990 * responsd to probe request). However if we send Go neg req, the
8991 * peer is sending GO-neg resp. So instead of giving up here, just
8992 * proceed and attempt sending out the action frame.
8996 wl_clr_drv_status(cfg
, SCANNING
, cfg
->afx_hdl
->dev
);
8998 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
8999 * but after the check of piggyback algorithm.
9000 * To take care of current piggback algo, lets abort the scan here itself.
9002 wl_cfg80211_cancel_scan(cfg
);
9003 /* Suspend P2P discovery's search-listen to prevent it from
9004 * starting a scan or changing the channel.
9006 if ((wl_cfgp2p_discover_enable_search(cfg
, false)) < 0) {
9007 WL_ERR(("Can not disable discovery mode\n"));
9011 /* update channel */
9012 if (cfg
->afx_hdl
->peer_chan
!= WL_INVALID
) {
9013 af_params
->channel
= cfg
->afx_hdl
->peer_chan
;
9014 WL_ERR(("Attempt tx on peer listen channel:%d ",
9015 cfg
->afx_hdl
->peer_chan
));
9017 WL_ERR(("Attempt tx with the channel provided by userspace."
9018 "Channel: %d\n", af_params
->channel
));
9023 off_chan_started_jiffies
= jiffies
;
9026 wl_cfgp2p_print_actframe(true, action_frame
->data
, action_frame
->len
, af_params
->channel
);
9028 wl_cfgp2p_need_wait_actfrmae(cfg
, action_frame
->data
, action_frame
->len
, true);
9030 dwell_jiffies
= jiffies
;
9031 /* Now send a tx action frame */
9032 ack
= wl_cfgp2p_tx_action_frame(cfg
, dev
, af_params
, bssidx
) ? false : true;
9033 dwell_overflow
= wl_cfg80211_check_dwell_overflow(requested_dwell
, dwell_jiffies
);
9035 /* if failed, retry it. tx_retry_max value is configure by .... */
9036 while ((ack
== false) && (tx_retry
++ < config_af_params
.max_tx_retry
) &&
9039 if (af_params
->channel
) {
9040 if (jiffies_to_msecs(jiffies
- off_chan_started_jiffies
) >
9041 OFF_CHAN_TIME_THRESHOLD_MS
) {
9042 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg
);
9043 off_chan_started_jiffies
= jiffies
;
9045 OSL_SLEEP(AF_RETRY_DELAY_TIME
);
9048 ack
= wl_cfgp2p_tx_action_frame(cfg
, dev
, af_params
, bssidx
) ?
9050 dwell_overflow
= wl_cfg80211_check_dwell_overflow(requested_dwell
, dwell_jiffies
);
9054 WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry
));
9056 WL_DBG(("Complete to send action frame\n"));
9058 /* Clear SENDING_ACT_FRM after all sending af is done */
9059 wl_clr_drv_status(cfg
, SENDING_ACT_FRM
, dev
);
9061 #ifdef WL_CFG80211_SYNC_GON
9062 /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
9063 * if we coundn't get the next action response frame and dongle does not keep
9064 * the dwell time, go to listen state again to get next action response frame.
9066 if (ack
&& config_af_params
.extra_listen
&&
9067 #ifdef WL_CFG80211_GON_COLLISION
9068 !cfg
->block_gon_req_tx_count
&&
9069 #endif /* WL_CFG80211_GON_COLLISION */
9070 wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM
) &&
9071 cfg
->af_sent_channel
== cfg
->afx_hdl
->my_listen_chan
) {
9072 s32 extar_listen_time
;
9074 extar_listen_time
= af_params
->dwell_time
-
9075 jiffies_to_msecs(jiffies
- cfg
->af_tx_sent_jiffies
);
9077 if (extar_listen_time
> 50) {
9078 wl_set_drv_status(cfg
, WAITING_NEXT_ACT_FRM_LISTEN
, dev
);
9079 WL_DBG(("Wait more time! actual af time:%d,"
9080 "calculated extar listen:%d\n",
9081 af_params
->dwell_time
, extar_listen_time
));
9082 if (wl_cfgp2p_discover_listen(cfg
, cfg
->af_sent_channel
,
9083 extar_listen_time
+ 100) == BCME_OK
) {
9084 wait_for_completion_timeout(&cfg
->wait_next_af
,
9085 msecs_to_jiffies(extar_listen_time
+ 100 + 300));
9087 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM_LISTEN
, dev
);
9090 #endif /* WL_CFG80211_SYNC_GON */
9091 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, dev
);
9093 cfg
->afx_hdl
->pending_tx_act_frm
= NULL
;
9096 WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
9097 cfg
->afx_hdl
->my_listen_chan
));
9099 WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
9100 cfg
->afx_hdl
->my_listen_chan
));
9103 #ifdef WL_CFG80211_GON_COLLISION
9104 if (cfg
->block_gon_req_tx_count
) {
9105 cfg
->block_gon_req_tx_count
--;
9106 /* if ack is ture, supplicant will wait more time(100ms).
9107 * so we will return it as a success to get more time .
9111 #endif /* WL_CFG80211_GON_COLLISION */
9115 #define MAX_NUM_OF_ASSOCIATED_DEV 64
9116 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9118 wl_cfg80211_mgmt_tx(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
,
9119 struct cfg80211_mgmt_tx_params
*params
, u64
*cookie
)
9122 wl_cfg80211_mgmt_tx(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
,
9123 struct ieee80211_channel
*channel
, bool offchan
,
9124 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
9125 enum nl80211_channel_type channel_type
,
9126 bool channel_type_valid
,
9127 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
9128 unsigned int wait
, const u8
* buf
, size_t len
,
9129 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
9132 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
9133 bool dont_wait_for_ack
,
9136 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9138 wl_action_frame_t
*action_frame
;
9139 wl_af_params_t
*af_params
;
9141 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9142 struct ieee80211_channel
*channel
= params
->chan
;
9143 const u8
*buf
= params
->buf
;
9144 size_t len
= params
->len
;
9146 const struct ieee80211_mgmt
*mgmt
;
9147 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
9148 struct net_device
*dev
= NULL
;
9153 s8 eabuf
[ETHER_ADDR_STR_LEN
];
9155 WL_DBG(("Enter \n"));
9157 if (len
> ACTION_FRAME_SIZE
) {
9158 WL_ERR(("bad length:%zu\n", len
));
9162 PRINT_WDEV_INFO(cfgdev
);
9163 #endif /* DHD_IFDEBUG */
9165 dev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
9168 WL_ERR(("dev is NULL\n"));
9172 /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
9173 if (discover_cfgdev(cfgdev
, cfg
)) {
9174 if (!cfg
->p2p_supported
|| !cfg
->p2p
) {
9175 WL_ERR(("P2P doesn't setup completed yet\n"));
9178 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
9181 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, cfgdev_to_wdev(cfgdev
))) < 0) {
9182 WL_ERR(("Find p2p index failed\n"));
9187 WL_DBG(("TX target bssidx=%d\n", bssidx
));
9189 if (p2p_is_on(cfg
)) {
9190 /* Suspend P2P discovery search-listen to prevent it from changing the
9193 if ((err
= wl_cfgp2p_discover_enable_search(cfg
, false)) < 0) {
9194 WL_ERR(("Can not disable discovery mode\n"));
9199 id
= cfg
->send_action_id
++;
9201 id
= cfg
->send_action_id
++;
9203 mgmt
= (const struct ieee80211_mgmt
*)buf
;
9204 if (ieee80211_is_mgmt(mgmt
->frame_control
)) {
9205 if (ieee80211_is_probe_resp(mgmt
->frame_control
)) {
9206 s32 ie_offset
= DOT11_MGMT_HDR_LEN
+ DOT11_BCN_PRB_FIXED_LEN
;
9207 s32 ie_len
= len
- ie_offset
;
9208 if ((dev
== bcmcfg_to_prmry_ndev(cfg
)) && cfg
->p2p
) {
9209 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
9211 wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
9212 VNDR_IE_PRBRSP_FLAG
, (const u8
*)(buf
+ ie_offset
), ie_len
);
9213 cfg80211_mgmt_tx_status(cfgdev
, *cookie
, buf
, len
, true, GFP_KERNEL
);
9214 #if defined(P2P_IE_MISSING_FIX)
9215 if (!cfg
->p2p_prb_noti
) {
9216 cfg
->p2p_prb_noti
= true;
9217 WL_DBG(("%s: TX 802_1X Probe Response first time.\n",
9222 } else if (ieee80211_is_disassoc(mgmt
->frame_control
) ||
9223 ieee80211_is_deauth(mgmt
->frame_control
)) {
9224 char mac_buf
[MAX_NUM_OF_ASSOCIATED_DEV
*
9225 sizeof(struct ether_addr
) + sizeof(uint
)] = {0};
9226 int num_associated
= 0;
9227 struct maclist
*assoc_maclist
= (struct maclist
*)mac_buf
;
9228 if (!bcmp((const uint8
*)BSSID_BROADCAST
,
9229 (const struct ether_addr
*)mgmt
->da
, ETHER_ADDR_LEN
)) {
9230 assoc_maclist
->count
= MAX_NUM_OF_ASSOCIATED_DEV
;
9231 err
= wldev_ioctl_get(dev
, WLC_GET_ASSOCLIST
,
9232 assoc_maclist
, sizeof(mac_buf
));
9234 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err
));
9236 num_associated
= assoc_maclist
->count
;
9238 memcpy(scb_val
.ea
.octet
, mgmt
->da
, ETH_ALEN
);
9239 scb_val
.val
= mgmt
->u
.disassoc
.reason_code
;
9240 err
= wldev_ioctl_set(dev
, WLC_SCB_DEAUTHENTICATE_FOR_REASON
, &scb_val
,
9243 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err
));
9244 WL_ERR(("Disconnect STA : " MACDBG
" scb_val.val %d\n",
9245 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr
*)mgmt
->da
,
9246 eabuf
)), scb_val
.val
));
9248 if (num_associated
> 0 && ETHER_ISBCAST(mgmt
->da
))
9251 cfg80211_mgmt_tx_status(cfgdev
, *cookie
, buf
, len
, true, GFP_KERNEL
);
9254 } else if (ieee80211_is_action(mgmt
->frame_control
)) {
9255 /* Abort the dwell time of any previous off-channel
9256 * action frame that may be still in effect. Sending
9257 * off-channel action frames relies on the driver's
9258 * scan engine. If a previous off-channel action frame
9259 * tx is still in progress (including the dwell time),
9260 * then this new action frame will not be sent out.
9262 /* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
9263 * And previous off-channel action frame must be ended before new af tx.
9265 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9266 wl_cfg80211_cancel_scan(cfg
);
9267 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9271 WL_ERR(("Driver only allows MGMT packet type\n"));
9275 af_params
= (wl_af_params_t
*)MALLOCZ(cfg
->osh
, WL_WIFI_AF_PARAMS_SIZE
);
9277 if (af_params
== NULL
)
9279 WL_ERR(("unable to allocate frame\n"));
9283 action_frame
= &af_params
->action_frame
;
9285 /* Add the packet Id */
9286 action_frame
->packetId
= *cookie
;
9287 WL_DBG(("action frame %d\n", action_frame
->packetId
));
9289 memcpy(&action_frame
->da
, &mgmt
->da
[0], ETHER_ADDR_LEN
);
9290 memcpy(&af_params
->BSSID
, &mgmt
->bssid
[0], ETHER_ADDR_LEN
);
9292 /* Add the length exepted for 802.11 header */
9293 action_frame
->len
= len
- DOT11_MGMT_HDR_LEN
;
9294 WL_DBG(("action_frame->len: %d\n", action_frame
->len
));
9296 /* Add the channel */
9297 af_params
->channel
=
9298 ieee80211_frequency_to_channel(channel
->center_freq
);
9299 /* Save listen_chan for searching common channel */
9300 cfg
->afx_hdl
->peer_listen_chan
= af_params
->channel
;
9301 WL_DBG(("channel from upper layer %d\n", cfg
->afx_hdl
->peer_listen_chan
));
9303 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9304 af_params
->dwell_time
= params
->wait
;
9306 af_params
->dwell_time
= wait
;
9309 memcpy(action_frame
->data
, &buf
[DOT11_MGMT_HDR_LEN
], action_frame
->len
);
9311 ack
= wl_cfg80211_send_action_frame(wiphy
, dev
, cfgdev
, af_params
,
9312 action_frame
, action_frame
->len
, bssidx
);
9313 cfg80211_mgmt_tx_status(cfgdev
, *cookie
, buf
, len
, ack
, GFP_KERNEL
);
9315 MFREE(cfg
->osh
, af_params
, WL_WIFI_AF_PARAMS_SIZE
);
9321 wl_cfg80211_mgmt_frame_register(struct wiphy
*wiphy
, bcm_struct_cfgdev
*cfgdev
,
9322 u16 frame
, bool reg
)
9325 WL_DBG(("frame_type: %x, reg: %d\n", frame
, reg
));
9327 if (frame
!= (IEEE80211_FTYPE_MGMT
| IEEE80211_STYPE_PROBE_REQ
))
9334 wl_cfg80211_change_bss(struct wiphy
*wiphy
,
9335 struct net_device
*dev
,
9336 struct bss_parameters
*params
)
9340 #ifdef PCIE_FULL_DONGLE
9341 s32 ifidx
= DHD_BAD_IF
;
9343 #if defined(PCIE_FULL_DONGLE)
9345 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
9346 dhd
= (dhd_pub_t
*)(cfg
->pub
);
9347 #if defined(WL_ENABLE_P2P_IF)
9348 if (cfg
->p2p_net
== dev
)
9349 dev
= bcmcfg_to_prmry_ndev(cfg
);
9353 if (params
->use_cts_prot
>= 0) {
9356 if (params
->use_short_preamble
>= 0) {
9359 if (params
->use_short_slot_time
>= 0) {
9362 if (params
->basic_rates
) {
9365 if (params
->ap_isolate
>= 0) {
9366 ap_isolate
= params
->ap_isolate
;
9367 #ifdef PCIE_FULL_DONGLE
9368 ifidx
= dhd_net2idx(dhd
->info
, dev
);
9370 if (ifidx
!= DHD_BAD_IF
) {
9371 err
= dhd_set_ap_isolate(dhd
, ifidx
, ap_isolate
);
9373 WL_ERR(("Failed to set ap_isolate\n"));
9376 err
= wldev_iovar_setint(dev
, "ap_isolate", ap_isolate
);
9379 WL_ERR(("set ap_isolate Error (%d)\n", err
));
9381 #endif /* PCIE_FULL_DONGLE */
9384 if (params
->ht_opmode
>= 0) {
9391 wl_cfg80211_set_channel(struct wiphy
*wiphy
, struct net_device
*dev
,
9392 struct ieee80211_channel
*chan
,
9393 enum nl80211_channel_type channel_type
)
9397 chanspec_t chspec
= 0;
9398 chanspec_t fw_chspec
= 0;
9399 u32 bw
= WL_CHANSPEC_BW_20
;
9407 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
9408 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
9409 #if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL)
9410 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
9411 #endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
9412 #if defined(WL_VIRTUAL_APSTA) && defined(APSTA_RESTRICTED_CHANNEL)
9413 struct net_device
*prmry_ndev
= bcmcfg_to_prmry_ndev(cfg
);
9414 #endif /* WL_VIRTUAL_APSTA && APSTA_RESTRICTED_CHANNEL */
9416 dev
= ndev_to_wlc_ndev(dev
, cfg
);
9417 _chan
= ieee80211_frequency_to_channel(chan
->center_freq
);
9419 WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
9420 dev
->ifindex
, channel_type
, _chan
));
9423 switch (channel_type
) {
9424 case NL80211_CHAN_HT40MINUS
:
9425 /* secondary channel is below the control channel */
9426 chspec
= CH40MHZ_CHSPEC(channel
, WL_CHANSPEC_CTL_SB_UPPER
);
9428 case NL80211_CHAN_HT40PLUS
:
9429 /* secondary channel is above the control channel */
9430 chspec
= CH40MHZ_CHSPEC(channel
, WL_CHANSPEC_CTL_SB_LOWER
);
9433 chspec
= CH20MHZ_CHSPEC(channel
);
9436 #endif /* NOT_YET */
9438 #if defined(APSTA_RESTRICTED_CHANNEL)
9439 #define DEFAULT_2G_SOFTAP_CHANNEL 1
9440 #define DEFAULT_5G_SOFTAP_CHANNEL 149
9441 if (wl_get_mode_by_netdev(cfg
, dev
) == WL_MODE_AP
&&
9442 DHD_OPMODE_STA_SOFTAP_CONCURR(dhd
) &&
9443 wl_get_drv_status(cfg
, CONNECTED
, prmry_ndev
)) {
9444 u32
*sta_chan
= (u32
*)wl_read_prof(cfg
,
9445 prmry_ndev
, WL_PROF_CHAN
);
9447 #ifdef WL_RESTRICTED_APSTA_SCC
9450 /* Check if current channel is restricted */
9451 if (wl_cfg80211_check_indoor_channels(prmry_ndev
, _chan
)) {
9452 wl_cfg80211_disassoc(prmry_ndev
);
9453 WL_ERR(("Force to disconnect existing AP as "
9454 "channel %d is indoor channel\n", _chan
));
9456 /* Set channel to default 2.4GHz channel */
9457 _chan
= DEFAULT_2G_SOFTAP_CHANNEL
;
9460 u32 sta_band
= (*sta_chan
> CH_MAX_2G_CHANNEL
) ?
9461 NL80211_BAND_5GHZ
: NL80211_BAND_2GHZ
;
9462 if (chan
->band
== sta_band
) {
9463 _chan
= (sta_band
== NL80211_BAND_5GHZ
&&
9464 *sta_chan
!= DEFAULT_5G_SOFTAP_CHANNEL
) ?
9465 DEFAULT_2G_SOFTAP_CHANNEL
: *sta_chan
;
9467 #endif /* WL_RESTRICTED_APSTA_SCC */
9468 _band
= (_chan
<= CH_MAX_2G_CHANNEL
) ? NL80211_BAND_2GHZ
: NL80211_BAND_5GHZ
;
9469 WL_ERR(("Target SoftAP channel will be set to %d\n", _chan
));
9471 #undef DEFAULT_2G_SOFTAP_CHANNEL
9472 #undef DEFAULT_5G_SOFTAP_CHANNEL
9473 #endif /* APSTA_RESTRICTED_CHANNEL */
9475 if (_band
== NL80211_BAND_5GHZ
) {
9476 param
.band
= WLC_BAND_5G
;
9477 err
= wldev_iovar_getbuf(dev
, "bw_cap", ¶m
, sizeof(param
),
9478 ioctl_buf
, sizeof(ioctl_buf
), NULL
);
9480 if (err
!= BCME_UNSUPPORTED
) {
9481 WL_ERR(("bw_cap failed, %d\n", err
));
9484 err
= wldev_iovar_getint(dev
, "mimo_bw_cap", &bw_cap
);
9486 WL_ERR(("error get mimo_bw_cap (%d)\n", err
));
9488 if (bw_cap
!= WLC_N_BW_20ALL
)
9489 bw
= WL_CHANSPEC_BW_40
;
9492 if (WL_BW_CAP_80MHZ(ioctl_buf
[0]))
9493 bw
= WL_CHANSPEC_BW_80
;
9494 else if (WL_BW_CAP_40MHZ(ioctl_buf
[0]))
9495 bw
= WL_CHANSPEC_BW_40
;
9497 bw
= WL_CHANSPEC_BW_20
;
9501 } else if (_band
== NL80211_BAND_2GHZ
)
9502 bw
= WL_CHANSPEC_BW_20
;
9504 chspec
= wf_channel2chspec(_chan
, bw
);
9505 if (wf_chspec_valid(chspec
)) {
9506 fw_chspec
= wl_chspec_host_to_driver(chspec
);
9507 if (fw_chspec
!= INVCHANSPEC
) {
9508 if ((err
= wldev_iovar_setint(dev
, "chanspec",
9509 fw_chspec
)) == BCME_BADCHAN
) {
9510 if (bw
== WL_CHANSPEC_BW_80
)
9512 err
= wldev_ioctl_set(dev
, WLC_SET_CHANNEL
,
9513 &_chan
, sizeof(_chan
));
9515 WL_ERR(("WLC_SET_CHANNEL error %d"
9516 "chip may not be supporting this channel\n", err
));
9519 WL_ERR(("failed to set chanspec error %d\n", err
));
9521 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
9523 /* Disable Frameburst only for stand-alone 2GHz SoftAP */
9524 if (wl_get_mode_by_netdev(cfg
, dev
) == WL_MODE_AP
&&
9525 DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_HOSTAP_MODE
) &&
9526 (_chan
<= CH_MAX_2G_CHANNEL
) &&
9527 !wl_get_drv_status(cfg
, CONNECTED
,
9528 bcmcfg_to_prmry_ndev(cfg
))) {
9529 WL_DBG(("Disabling frameburst on "
9530 "stand-alone 2GHz SoftAP\n"));
9531 wl_cfg80211_set_frameburst(cfg
, FALSE
);
9534 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
9536 WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
9541 if (bw
== WL_CHANSPEC_BW_80
)
9542 bw
= WL_CHANSPEC_BW_40
;
9543 else if (bw
== WL_CHANSPEC_BW_40
)
9544 bw
= WL_CHANSPEC_BW_20
;
9549 WL_ERR(("Invalid chanspec 0x%x\n", chspec
));
9552 #ifdef CUSTOM_SET_CPUCORE
9553 if (dhd
->op_mode
== DHD_FLAG_HOSTAP_MODE
) {
9554 WL_DBG(("SoftAP mode do not need to set cpucore\n"));
9555 } else if (chspec
& WL_CHANSPEC_BW_80
) {
9556 /* SoftAp only mode do not need to set cpucore */
9557 if ((dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) &&
9558 dev
!= bcmcfg_to_prmry_ndev(cfg
)) {
9559 /* Soft AP on virtual Iface (AP+STA case) */
9560 dhd
->chan_isvht80
|= DHD_FLAG_HOSTAP_MODE
;
9561 dhd_set_cpucore(dhd
, TRUE
);
9562 } else if (is_p2p_group_iface(dev
->ieee80211_ptr
)) {
9563 /* If P2P IF is vht80 */
9564 dhd
->chan_isvht80
|= DHD_FLAG_P2P_MODE
;
9565 dhd_set_cpucore(dhd
, TRUE
);
9568 #endif /* CUSTOM_SET_CPUCORE */
9569 if (!err
&& (wl_get_mode_by_netdev(cfg
, dev
) == WL_MODE_AP
)) {
9570 /* Update AP/GO operating channel */
9571 cfg
->ap_oper_channel
= ieee80211_frequency_to_channel(chan
->center_freq
);
9574 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg
),
9575 FW_LOGSET_MASK_ALL
);
9580 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9582 wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211
*cfg
)
9584 struct net_info
*_net_info
, *next
;
9585 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
9586 #pragma GCC diagnostic push
9587 #pragma GCC diagnostic ignored "-Wcast-qual"
9589 list_for_each_entry_safe(_net_info
, next
, &cfg
->net_list
, list
) {
9590 if (_net_info
->ndev
&&
9591 test_bit(WL_STATUS_REMAINING_ON_CHANNEL
, &_net_info
->sme_state
))
9592 return _net_info
->ndev
;
9594 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
9595 #pragma GCC diagnostic pop
9599 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9602 wl_validate_opensecurity(struct net_device
*dev
, s32 bssidx
, bool privacy
)
9609 err
= wldev_iovar_setint_bsscfg(dev
, "auth", 0, bssidx
);
9611 WL_ERR(("auth error %d\n", err
));
9616 /* If privacy bit is set in open mode, then WEP would be enabled */
9618 WL_DBG(("Setting wsec to %d for WEP \n", wsec
));
9622 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
9624 WL_ERR(("wsec error %d\n", err
));
9628 /* set upper-layer auth */
9629 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_ADHOC
)
9630 wpa_val
= WPA_AUTH_NONE
;
9632 wpa_val
= WPA_AUTH_DISABLED
;
9633 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wpa_val
, bssidx
);
9635 WL_ERR(("wpa_auth error %d\n", err
));
9643 wl_validate_fils_ind_ie(struct net_device
*dev
, const bcm_tlv_t
*filsindie
, s32 bssidx
)
9646 struct bcm_cfg80211
*cfg
= NULL
;
9648 if (!dev
|| !filsindie
) {
9649 WL_ERR(("%s: dev/filsidie is null\n", __FUNCTION__
));
9653 cfg
= wl_get_cfg(dev
);
9655 WL_ERR(("%s: cfg is null\n", __FUNCTION__
));
9659 err
= wldev_iovar_setbuf_bsscfg(dev
, "fils_ind", (const void *)filsindie
->data
,
9660 filsindie
->len
, cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
,
9661 bssidx
, &cfg
->ioctl_buf_sync
);
9663 WL_ERR(("FILS Ind setting error %d\n", err
));
9670 wl_validate_wpa2ie(struct net_device
*dev
, const bcm_tlv_t
*wpa2ie
, s32 bssidx
)
9674 u16 auth
= 0; /* d11 open authentication */
9679 const wpa_suite_mcast_t
*mcast
;
9680 const wpa_suite_ucast_t
*ucast
;
9681 const wpa_suite_auth_key_mgmt_t
*mgmt
;
9682 const wpa_pmkid_list_t
*pmkid
;
9686 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
9691 u32 wme_bss_disable
;
9696 WL_DBG(("Enter \n"));
9697 len
= wpa2ie
->len
- WPA2_VERSION_LEN
;
9698 /* check the mcast cipher */
9699 mcast
= (const wpa_suite_mcast_t
*)&wpa2ie
->data
[WPA2_VERSION_LEN
];
9700 switch (mcast
->type
) {
9701 case WPA_CIPHER_NONE
:
9704 case WPA_CIPHER_WEP_40
:
9705 case WPA_CIPHER_WEP_104
:
9708 case WPA_CIPHER_TKIP
:
9709 gval
= TKIP_ENABLED
;
9711 case WPA_CIPHER_AES_CCM
:
9715 case WAPI_CIPHER_SMS4
:
9716 gval
= SMS4_ENABLED
;
9720 WL_ERR(("No Security Info\n"));
9723 if ((len
-= WPA_SUITE_LEN
) <= 0)
9726 /* check the unicast cipher */
9727 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
9728 suite_count
= ltoh16_ua(&ucast
->count
);
9729 switch (ucast
->list
[0].type
) {
9730 case WPA_CIPHER_NONE
:
9733 case WPA_CIPHER_WEP_40
:
9734 case WPA_CIPHER_WEP_104
:
9737 case WPA_CIPHER_TKIP
:
9738 pval
= TKIP_ENABLED
;
9740 case WPA_CIPHER_AES_CCM
:
9744 case WAPI_CIPHER_SMS4
:
9745 pval
= SMS4_ENABLED
;
9749 WL_ERR(("No Security Info\n"));
9751 if ((len
-= (WPA_IE_SUITE_COUNT_LEN
+ (WPA_SUITE_LEN
* suite_count
))) <= 0)
9754 /* FOR WPS , set SEC_OW_ENABLED */
9755 wsec
= (pval
| gval
| SES_OW_ENABLED
);
9757 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[suite_count
];
9758 suite_count
= cnt
= ltoh16_ua(&mgmt
->count
);
9760 switch (mgmt
->list
[cnt
].type
) {
9762 wpa_auth
|= WPA_AUTH_NONE
;
9764 case RSN_AKM_UNSPECIFIED
:
9765 wpa_auth
|= WPA2_AUTH_UNSPECIFIED
;
9768 wpa_auth
|= WPA2_AUTH_PSK
;
9771 case RSN_AKM_MFP_PSK
:
9772 wpa_auth
|= WPA2_AUTH_PSK_SHA256
;
9774 case RSN_AKM_MFP_1X
:
9775 wpa_auth
|= WPA2_AUTH_1X_SHA256
;
9777 case RSN_AKM_FILS_SHA256
:
9778 wpa_auth
|= WPA2_AUTH_FILS_SHA256
;
9780 case RSN_AKM_FILS_SHA384
:
9781 wpa_auth
|= WPA2_AUTH_FILS_SHA384
;
9785 WL_ERR(("No Key Mgmt Info\n"));
9789 if ((len
-= (WPA_IE_SUITE_COUNT_LEN
+ (WPA_SUITE_LEN
* suite_count
))) >= RSN_CAP_LEN
) {
9790 rsn_cap
[0] = *(const u8
*)&mgmt
->list
[suite_count
];
9791 rsn_cap
[1] = *((const u8
*)&mgmt
->list
[suite_count
] + 1);
9793 if (rsn_cap
[0] & (RSN_CAP_16_REPLAY_CNTRS
<< RSN_CAP_PTK_REPLAY_CNTR_SHIFT
)) {
9794 wme_bss_disable
= 0;
9796 wme_bss_disable
= 1;
9800 if (rsn_cap
[0] & RSN_CAP_MFPR
) {
9801 WL_DBG(("MFP Required \n"));
9802 mfp
= WL_MFP_REQUIRED
;
9803 /* Our firmware has requirement that WPA2_AUTH_PSK/WPA2_AUTH_UNSPECIFIED
9804 * be set, if SHA256 OUI is to be included in the rsn ie.
9806 if (wpa_auth
& WPA2_AUTH_PSK_SHA256
) {
9807 wpa_auth
|= WPA2_AUTH_PSK
;
9808 } else if (wpa_auth
& WPA2_AUTH_1X_SHA256
) {
9809 wpa_auth
|= WPA2_AUTH_UNSPECIFIED
;
9811 } else if (rsn_cap
[0] & RSN_CAP_MFPC
) {
9812 WL_DBG(("MFP Capable \n"));
9813 mfp
= WL_MFP_CAPABLE
;
9817 /* set wme_bss_disable to sync RSN Capabilities */
9818 err
= wldev_iovar_setint_bsscfg(dev
, "wme_bss_disable", wme_bss_disable
, bssidx
);
9820 WL_ERR(("wme_bss_disable error %d\n", err
));
9824 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len
));
9828 if (len
>= WPA2_PMKID_COUNT_LEN
) {
9829 pmkid
= (const wpa_pmkid_list_t
*)
9830 ((const u8
*)&mgmt
->list
[suite_count
] + RSN_CAP_LEN
);
9831 cnt
= ltoh16_ua(&pmkid
->count
);
9833 WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
9836 /* since PMKID cnt is known to be 0 for AP, */
9837 /* so don't bother to send down this info to firmware */
9841 len
-= WPA2_PMKID_COUNT_LEN
;
9842 if (len
>= WPA_SUITE_LEN
) {
9844 (const u8
*)&mgmt
->list
[suite_count
] + RSN_CAP_LEN
+ WPA2_PMKID_COUNT_LEN
;
9846 cfg
->bip_pos
= NULL
;
9851 err
= wldev_iovar_setint_bsscfg(dev
, "auth", auth
, bssidx
);
9853 WL_ERR(("auth error %d\n", err
));
9858 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
9860 WL_ERR(("wsec error %d\n", err
));
9865 cfg
->mfp_mode
= mfp
;
9868 /* set upper-layer auth */
9869 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wpa_auth
, bssidx
);
9871 WL_ERR(("wpa_auth error %d\n", err
));
9879 wl_validate_wpaie(struct net_device
*dev
, const wpa_ie_fixed_t
*wpaie
, s32 bssidx
)
9881 const wpa_suite_mcast_t
*mcast
;
9882 const wpa_suite_ucast_t
*ucast
;
9883 const wpa_suite_auth_key_mgmt_t
*mgmt
;
9884 u16 auth
= 0; /* d11 open authentication */
9897 WL_DBG(("Enter \n"));
9898 len
= wpaie
->length
; /* value length */
9899 len
-= WPA_IE_TAG_FIXED_LEN
;
9900 /* check for multicast cipher suite */
9901 if (len
< WPA_SUITE_LEN
) {
9902 WL_INFORM_MEM(("no multicast cipher suite\n"));
9906 /* pick up multicast cipher */
9907 mcast
= (const wpa_suite_mcast_t
*)&wpaie
[1];
9908 len
-= WPA_SUITE_LEN
;
9909 if (!bcmp(mcast
->oui
, WPA_OUI
, WPA_OUI_LEN
)) {
9910 if (IS_WPA_CIPHER(mcast
->type
)) {
9912 switch (mcast
->type
) {
9913 case WPA_CIPHER_NONE
:
9916 case WPA_CIPHER_WEP_40
:
9917 case WPA_CIPHER_WEP_104
:
9920 case WPA_CIPHER_TKIP
:
9923 case WPA_CIPHER_AES_CCM
:
9927 WL_ERR(("No Security Info\n"));
9932 /* Check for unicast suite(s) */
9933 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
9934 WL_INFORM_MEM(("no unicast suite\n"));
9937 /* walk thru unicast cipher list and pick up what we recognize */
9938 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
9939 count
= ltoh16_ua(&ucast
->count
);
9940 len
-= WPA_IE_SUITE_COUNT_LEN
;
9941 for (i
= 0; i
< count
&& len
>= WPA_SUITE_LEN
;
9942 i
++, len
-= WPA_SUITE_LEN
) {
9943 if (!bcmp(ucast
->list
[i
].oui
, WPA_OUI
, WPA_OUI_LEN
)) {
9944 if (IS_WPA_CIPHER(ucast
->list
[i
].type
)) {
9946 switch (ucast
->list
[i
].type
) {
9947 case WPA_CIPHER_NONE
:
9950 case WPA_CIPHER_WEP_40
:
9951 case WPA_CIPHER_WEP_104
:
9954 case WPA_CIPHER_TKIP
:
9957 case WPA_CIPHER_AES_CCM
:
9961 WL_ERR(("No Security Info\n"));
9967 len
-= (count
- i
) * WPA_SUITE_LEN
;
9968 /* Check for auth key management suite(s) */
9969 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
9970 WL_INFORM_MEM((" no auth key mgmt suite\n"));
9973 /* walk thru auth management suite list and pick up what we recognize */
9974 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[count
];
9975 count
= ltoh16_ua(&mgmt
->count
);
9976 len
-= WPA_IE_SUITE_COUNT_LEN
;
9977 for (i
= 0; i
< count
&& len
>= WPA_SUITE_LEN
;
9978 i
++, len
-= WPA_SUITE_LEN
) {
9979 if (!bcmp(mgmt
->list
[i
].oui
, WPA_OUI
, WPA_OUI_LEN
)) {
9980 if (IS_WPA_AKM(mgmt
->list
[i
].type
)) {
9982 switch (mgmt
->list
[i
].type
) {
9984 tmp
= WPA_AUTH_NONE
;
9986 case RSN_AKM_UNSPECIFIED
:
9987 tmp
= WPA_AUTH_UNSPECIFIED
;
9993 WL_ERR(("No Key Mgmt Info\n"));
10000 /* FOR WPS , set SEC_OW_ENABLED */
10001 wsec
= (pval
| gval
| SES_OW_ENABLED
);
10003 err
= wldev_iovar_setint_bsscfg(dev
, "auth", auth
, bssidx
);
10005 WL_ERR(("auth error %d\n", err
));
10009 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
10011 WL_ERR(("wsec error %d\n", err
));
10014 /* set upper-layer auth */
10015 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wpa_auth
, bssidx
);
10017 WL_ERR(("wpa_auth error %d\n", err
));
10024 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10025 static u32
wl_get_cipher_type(uint8 type
)
10029 case WPA_CIPHER_NONE
:
10032 case WPA_CIPHER_WEP_40
:
10033 case WPA_CIPHER_WEP_104
:
10036 case WPA_CIPHER_TKIP
:
10037 ret
= TKIP_ENABLED
;
10039 case WPA_CIPHER_AES_CCM
:
10043 case WAPI_CIPHER_SMS4
:
10044 ret
= SMS4_ENABLED
;
10048 WL_ERR(("No Security Info\n"));
10053 static u32
wl_get_suite_auth_key_mgmt_type(uint8 type
, const wpa_suite_mcast_t
*mcast
)
10058 if (!bcmp(mcast
->oui
, WPA2_OUI
, WPA2_OUI_LEN
)) {
10062 WL_INFORM_MEM(("%s, type = %d\n", is_wpa2
? "WPA2":"WPA", type
));
10065 /* For WPA and WPA2, AUTH_NONE is common */
10066 ret
= WPA_AUTH_NONE
;
10068 case RSN_AKM_UNSPECIFIED
:
10070 ret
= WPA2_AUTH_UNSPECIFIED
;
10072 ret
= WPA_AUTH_UNSPECIFIED
;
10077 ret
= WPA2_AUTH_PSK
;
10079 ret
= WPA_AUTH_PSK
;
10083 WL_ERR(("No Key Mgmt Info\n"));
10090 wl_validate_wpaie_wpa2ie(struct net_device
*dev
, const wpa_ie_fixed_t
*wpaie
,
10091 const bcm_tlv_t
*wpa2ie
, s32 bssidx
)
10093 const wpa_suite_mcast_t
*mcast
;
10094 const wpa_suite_ucast_t
*ucast
;
10095 const wpa_suite_auth_key_mgmt_t
*mgmt
;
10096 u16 auth
= 0; /* d11 open authentication */
10099 u32 wme_bss_disable
;
10104 u32 wsec1
, wsec2
, wsec
;
10111 if (wpaie
== NULL
|| wpa2ie
== NULL
)
10114 WL_DBG(("Enter \n"));
10115 len
= wpaie
->length
; /* value length */
10116 len
-= WPA_IE_TAG_FIXED_LEN
;
10117 /* check for multicast cipher suite */
10118 if (len
< WPA_SUITE_LEN
) {
10119 WL_INFORM_MEM(("no multicast cipher suite\n"));
10123 /* pick up multicast cipher */
10124 mcast
= (const wpa_suite_mcast_t
*)&wpaie
[1];
10125 len
-= WPA_SUITE_LEN
;
10126 if (!bcmp(mcast
->oui
, WPA_OUI
, WPA_OUI_LEN
)) {
10127 if (IS_WPA_CIPHER(mcast
->type
)) {
10128 gval
|= wl_get_cipher_type(mcast
->type
);
10131 WL_DBG(("\nwpa ie validate\n"));
10132 WL_DBG(("wpa ie mcast cipher = 0x%X\n", gval
));
10134 /* Check for unicast suite(s) */
10135 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
10136 WL_INFORM_MEM(("no unicast suite\n"));
10140 /* walk thru unicast cipher list and pick up what we recognize */
10141 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
10142 count
= ltoh16_ua(&ucast
->count
);
10143 len
-= WPA_IE_SUITE_COUNT_LEN
;
10144 for (i
= 0; i
< count
&& len
>= WPA_SUITE_LEN
;
10145 i
++, len
-= WPA_SUITE_LEN
) {
10146 if (!bcmp(ucast
->list
[i
].oui
, WPA_OUI
, WPA_OUI_LEN
)) {
10147 if (IS_WPA_CIPHER(ucast
->list
[i
].type
)) {
10148 pval
|= wl_get_cipher_type(ucast
->list
[i
].type
);
10152 WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count
, pval
));
10154 /* FOR WPS , set SEC_OW_ENABLED */
10155 wsec1
= (pval
| gval
| SES_OW_ENABLED
);
10156 WL_ERR(("wpa ie wsec = 0x%X\n", wsec1
));
10158 len
-= (count
- i
) * WPA_SUITE_LEN
;
10159 /* Check for auth key management suite(s) */
10160 if (len
< WPA_IE_SUITE_COUNT_LEN
) {
10161 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10164 /* walk thru auth management suite list and pick up what we recognize */
10165 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[count
];
10166 count
= ltoh16_ua(&mgmt
->count
);
10167 len
-= WPA_IE_SUITE_COUNT_LEN
;
10168 for (i
= 0; i
< count
&& len
>= WPA_SUITE_LEN
;
10169 i
++, len
-= WPA_SUITE_LEN
) {
10170 if (!bcmp(mgmt
->list
[i
].oui
, WPA_OUI
, WPA_OUI_LEN
)) {
10171 if (IS_WPA_AKM(mgmt
->list
[i
].type
)) {
10173 wl_get_suite_auth_key_mgmt_type(mgmt
->list
[i
].type
, mcast
);
10178 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count
, wpa_auth1
));
10179 WL_ERR(("\nwpa2 ie validate\n"));
10184 /* check the mcast cipher */
10185 mcast
= (const wpa_suite_mcast_t
*)&wpa2ie
->data
[WPA2_VERSION_LEN
];
10186 gval
= wl_get_cipher_type(mcast
->type
);
10188 WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval
));
10189 if ((len
-= WPA_SUITE_LEN
) <= 0)
10191 WL_ERR(("P:wpa2 ie len[%d]", len
));
10192 return BCME_BADLEN
;
10195 /* check the unicast cipher */
10196 ucast
= (const wpa_suite_ucast_t
*)&mcast
[1];
10197 suite_count
= ltoh16_ua(&ucast
->count
);
10198 WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count
));
10199 pval
|= wl_get_cipher_type(ucast
->list
[0].type
);
10201 if ((len
-= (WPA_IE_SUITE_COUNT_LEN
+ (WPA_SUITE_LEN
* suite_count
))) <= 0)
10202 return BCME_BADLEN
;
10204 WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval
));
10206 /* FOR WPS , set SEC_OW_ENABLED */
10207 wsec2
= (pval
| gval
| SES_OW_ENABLED
);
10208 WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2
));
10210 /* check the AKM */
10211 mgmt
= (const wpa_suite_auth_key_mgmt_t
*)&ucast
->list
[suite_count
];
10212 suite_count
= ltoh16_ua(&mgmt
->count
);
10213 wpa_auth2
= wl_get_suite_auth_key_mgmt_type(mgmt
->list
[0].type
, mcast
);
10214 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count
, wpa_auth2
));
10216 if ((len
-= (WPA_IE_SUITE_COUNT_LEN
+ (WPA_SUITE_LEN
* suite_count
))) >= RSN_CAP_LEN
) {
10217 rsn_cap
[0] = *(const u8
*)&mgmt
->list
[suite_count
];
10218 rsn_cap
[1] = *((const u8
*)&mgmt
->list
[suite_count
] + 1);
10219 if (rsn_cap
[0] & (RSN_CAP_16_REPLAY_CNTRS
<< RSN_CAP_PTK_REPLAY_CNTR_SHIFT
)) {
10220 wme_bss_disable
= 0;
10222 wme_bss_disable
= 1;
10224 WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap
[0], wme_bss_disable
));
10226 /* set wme_bss_disable to sync RSN Capabilities */
10227 err
= wldev_iovar_setint_bsscfg(dev
, "wme_bss_disable", wme_bss_disable
, bssidx
);
10229 WL_ERR(("wme_bss_disable error %d\n", err
));
10233 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len
));
10236 wsec
= (wsec1
| wsec2
);
10237 wpa_auth
= (wpa_auth1
| wpa_auth2
);
10238 WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec
, wpa_auth
));
10241 err
= wldev_iovar_setint_bsscfg(dev
, "auth", auth
, bssidx
);
10243 WL_ERR(("auth error %d\n", err
));
10247 err
= wldev_iovar_setint_bsscfg(dev
, "wsec", wsec
, bssidx
);
10249 WL_ERR(("wsec error %d\n", err
));
10252 /* set upper-layer auth */
10253 err
= wldev_iovar_setint_bsscfg(dev
, "wpa_auth", wpa_auth
, bssidx
);
10255 WL_ERR(("wpa_auth error %d\n", err
));
10261 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10264 wl_cfg80211_bcn_validate_sec(
10265 struct net_device
*dev
,
10266 struct parsed_ies
*ies
,
10271 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
10272 wl_cfgbss_t
*bss
= wl_get_cfgbss_by_wdev(cfg
, dev
->ieee80211_ptr
);
10275 WL_ERR(("cfgbss is NULL \n"));
10279 if (dev_role
== NL80211_IFTYPE_P2P_GO
&& (ies
->wpa2_ie
)) {
10280 /* For P2P GO, the sec type is WPA2-PSK */
10281 WL_DBG(("P2P GO: validating wpa2_ie"));
10282 if (wl_validate_wpa2ie(dev
, ies
->wpa2_ie
, bssidx
) < 0)
10285 } else if (dev_role
== NL80211_IFTYPE_AP
) {
10287 WL_DBG(("SoftAP: validating security"));
10288 /* If wpa2_ie or wpa_ie is present validate it */
10290 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10291 if ((ies
->wpa_ie
!= NULL
&& ies
->wpa2_ie
!= NULL
)) {
10292 if (wl_validate_wpaie_wpa2ie(dev
, ies
->wpa_ie
, ies
->wpa2_ie
, bssidx
) < 0) {
10293 bss
->security_mode
= false;
10298 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10299 if ((ies
->wpa2_ie
|| ies
->wpa_ie
) &&
10300 ((wl_validate_wpa2ie(dev
, ies
->wpa2_ie
, bssidx
) < 0 ||
10301 wl_validate_wpaie(dev
, ies
->wpa_ie
, bssidx
) < 0))) {
10302 bss
->security_mode
= false;
10306 if (ies
->fils_ind_ie
&&
10307 (wl_validate_fils_ind_ie(dev
, ies
->fils_ind_ie
, bssidx
) < 0)) {
10308 bss
->security_mode
= false;
10312 bss
->security_mode
= true;
10314 MFREE(cfg
->osh
, bss
->rsn_ie
, bss
->rsn_ie
[1]
10315 + WPA_RSN_IE_TAG_FIXED_LEN
);
10316 bss
->rsn_ie
= NULL
;
10319 MFREE(cfg
->osh
, bss
->wpa_ie
, bss
->wpa_ie
[1]
10320 + WPA_RSN_IE_TAG_FIXED_LEN
);
10321 bss
->wpa_ie
= NULL
;
10324 MFREE(cfg
->osh
, bss
->wps_ie
, bss
->wps_ie
[1] + 2);
10325 bss
->wps_ie
= NULL
;
10327 if (bss
->fils_ind_ie
) {
10328 MFREE(cfg
->osh
, bss
->fils_ind_ie
, bss
->fils_ind_ie
[1]
10329 + FILS_INDICATION_IE_TAG_FIXED_LEN
);
10330 bss
->fils_ind_ie
= NULL
;
10332 if (ies
->wpa_ie
!= NULL
) {
10334 bss
->rsn_ie
= NULL
;
10335 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
10336 ies
->wpa_ie
->length
10337 + WPA_RSN_IE_TAG_FIXED_LEN
);
10339 memcpy(bss
->wpa_ie
, ies
->wpa_ie
,
10340 ies
->wpa_ie
->length
10341 + WPA_RSN_IE_TAG_FIXED_LEN
);
10343 } else if (ies
->wpa2_ie
!= NULL
) {
10345 bss
->wpa_ie
= NULL
;
10346 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
10348 + WPA_RSN_IE_TAG_FIXED_LEN
);
10350 memcpy(bss
->rsn_ie
, ies
->wpa2_ie
,
10352 + WPA_RSN_IE_TAG_FIXED_LEN
);
10355 #ifdef FILS_SUPPORT
10356 if (ies
->fils_ind_ie
) {
10357 bss
->fils_ind_ie
= MALLOCZ(cfg
->osh
,
10358 ies
->fils_ind_ie
->len
10359 + FILS_INDICATION_IE_TAG_FIXED_LEN
);
10360 if (bss
->fils_ind_ie
) {
10361 memcpy(bss
->fils_ind_ie
, ies
->fils_ind_ie
,
10362 ies
->fils_ind_ie
->len
10363 + FILS_INDICATION_IE_TAG_FIXED_LEN
);
10367 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10369 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10370 if (!ies
->wpa2_ie
&& !ies
->wpa_ie
) {
10371 wl_validate_opensecurity(dev
, bssidx
, privacy
);
10372 bss
->security_mode
= false;
10376 bss
->wps_ie
= MALLOCZ(cfg
->osh
, ies
->wps_ie_len
);
10378 memcpy(bss
->wps_ie
, ies
->wps_ie
, ies
->wps_ie_len
);
10387 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
10388 static s32
wl_cfg80211_bcn_set_params(
10389 struct cfg80211_ap_settings
*info
,
10390 struct net_device
*dev
,
10391 u32 dev_role
, s32 bssidx
)
10393 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
10396 WL_DBG(("interval (%d) \ndtim_period (%d) \n",
10397 info
->beacon_interval
, info
->dtim_period
));
10399 if (info
->beacon_interval
) {
10400 if ((err
= wldev_ioctl_set(dev
, WLC_SET_BCNPRD
,
10401 &info
->beacon_interval
, sizeof(s32
))) < 0) {
10402 WL_ERR(("Beacon Interval Set Error, %d\n", err
));
10407 if (info
->dtim_period
) {
10408 if ((err
= wldev_ioctl_set(dev
, WLC_SET_DTIMPRD
,
10409 &info
->dtim_period
, sizeof(s32
))) < 0) {
10410 WL_ERR(("DTIM Interval Set Error, %d\n", err
));
10415 if ((info
->ssid
) && (info
->ssid_len
> 0) &&
10416 (info
->ssid_len
<= DOT11_MAX_SSID_LEN
)) {
10417 WL_DBG(("SSID (%s) len:%zd \n", info
->ssid
, info
->ssid_len
));
10418 if (dev_role
== NL80211_IFTYPE_AP
) {
10419 /* Store the hostapd SSID */
10420 memset(cfg
->hostapd_ssid
.SSID
, 0x00, DOT11_MAX_SSID_LEN
);
10421 memcpy(cfg
->hostapd_ssid
.SSID
, info
->ssid
, info
->ssid_len
);
10422 cfg
->hostapd_ssid
.SSID_len
= (uint32
)info
->ssid_len
;
10425 memset(cfg
->p2p
->ssid
.SSID
, 0x00, DOT11_MAX_SSID_LEN
);
10426 memcpy(cfg
->p2p
->ssid
.SSID
, info
->ssid
, info
->ssid_len
);
10427 cfg
->p2p
->ssid
.SSID_len
= (uint32
)info
->ssid_len
;
10433 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
10436 wl_cfg80211_parse_ies(const u8
*ptr
, u32 len
, struct parsed_ies
*ies
)
10440 memset(ies
, 0, sizeof(struct parsed_ies
));
10442 /* find the WPSIE */
10443 if ((ies
->wps_ie
= wl_cfgp2p_find_wpsie(ptr
, len
)) != NULL
) {
10444 WL_DBG(("WPSIE in beacon \n"));
10445 ies
->wps_ie_len
= ies
->wps_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
;
10447 WL_ERR(("No WPSIE in beacon \n"));
10450 /* find the RSN_IE */
10451 if ((ies
->wpa2_ie
= bcm_parse_tlvs(ptr
, len
,
10452 DOT11_MNG_RSN_ID
)) != NULL
) {
10453 WL_DBG((" WPA2 IE found\n"));
10454 ies
->wpa2_ie_len
= ies
->wpa2_ie
->len
;
10457 /* find the FILS_IND_IE */
10458 if ((ies
->fils_ind_ie
= bcm_parse_tlvs(ptr
, len
,
10459 DOT11_MNG_FILS_IND_ID
)) != NULL
) {
10460 WL_DBG((" FILS IND IE found\n"));
10461 ies
->fils_ind_ie_len
= ies
->fils_ind_ie
->len
;
10464 /* find the WPA_IE */
10465 if ((ies
->wpa_ie
= wl_cfgp2p_find_wpaie(ptr
, len
)) != NULL
) {
10466 WL_DBG((" WPA found\n"));
10467 ies
->wpa_ie_len
= ies
->wpa_ie
->length
;
10474 wl_cfg80211_set_ap_role(
10475 struct bcm_cfg80211
*cfg
,
10476 struct net_device
*dev
)
10482 s32 is_rsdb_supported
= BCME_ERROR
;
10486 is_rsdb_supported
= DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_RSDB_MODE
);
10487 if (is_rsdb_supported
< 0)
10490 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
10491 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
10495 WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n", dev
->name
, bssidx
));
10497 /* AP on primary Interface */
10499 if (is_rsdb_supported
) {
10500 if ((err
= wl_cfg80211_add_del_bss(cfg
, dev
, bssidx
,
10501 WL_IF_TYPE_AP
, 0, NULL
)) < 0) {
10502 WL_ERR(("wl add_del_bss returned error:%d\n", err
));
10505 } else if (is_rsdb_supported
== 0) {
10506 /* AP mode switch not supported. Try setting up AP explicitly */
10507 err
= wldev_iovar_getint(dev
, "apsta", (s32
*)&apsta
);
10508 if (unlikely(err
)) {
10509 WL_ERR(("Could not get apsta %d\n", err
));
10512 /* If apsta is not set, set it */
10513 err
= wldev_ioctl_set(dev
, WLC_DOWN
, &ap
, sizeof(s32
));
10515 WL_ERR(("WLC_DOWN error %d\n", err
));
10518 err
= wldev_iovar_setint(dev
, "apsta", 0);
10520 WL_ERR(("wl apsta 0 error %d\n", err
));
10523 if ((err
= wldev_ioctl_set(dev
,
10524 WLC_SET_AP
, &ap
, sizeof(s32
))) < 0) {
10525 WL_ERR(("setting AP mode failed %d \n", err
));
10532 if ((err
= wldev_ioctl_set(dev
, WLC_SET_PM
, &pm
, sizeof(pm
))) != 0) {
10533 WL_ERR(("wl PM 0 returned error:%d\n", err
));
10534 /* Ignore error, if any */
10537 err
= wldev_ioctl_set(dev
, WLC_SET_INFRA
, &infra
, sizeof(s32
));
10539 WL_ERR(("SET INFRA error %d\n", err
));
10543 if ((err
= wl_cfg80211_add_del_bss(cfg
, dev
,
10544 bssidx
, WL_IF_TYPE_AP
, 0, NULL
)) < 0) {
10545 WL_ERR(("wl bss ap returned error:%d\n", err
));
10550 /* On success, mark AP creation in progress. */
10551 wl_set_drv_status(cfg
, AP_CREATING
, dev
);
10555 /* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
10556 #define MAX_AP_LINK_WAIT_TIME 10000
10558 wl_cfg80211_bcn_bringup_ap(
10559 struct net_device
*dev
,
10560 struct parsed_ies
*ies
,
10561 u32 dev_role
, s32 bssidx
)
10563 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
10564 struct wl_join_params join_params
;
10565 bool is_bssup
= false;
10567 s32 join_params_size
= 0;
10570 #ifdef DISABLE_11H_SOFTAP
10572 #endif /* DISABLE_11H_SOFTAP */
10573 #ifdef SOFTAP_UAPSD_OFF
10574 uint32 wme_apsd
= 0;
10575 #endif /* SOFTAP_UAPSD_OFF */
10577 s32 is_rsdb_supported
= BCME_ERROR
;
10579 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
10580 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
10581 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
10583 is_rsdb_supported
= DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_RSDB_MODE
);
10584 if (is_rsdb_supported
< 0)
10587 WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role
, bssidx
, dev
->name
));
10589 if (wl_check_dongle_idle(bcmcfg_to_wiphy(cfg
)) != TRUE
) {
10590 WL_ERR(("FW is busy to add interface"));
10594 /* Common code for SoftAP and P2P GO */
10595 wl_clr_drv_status(cfg
, AP_CREATED
, dev
);
10597 /* Make sure INFRA is set for AP/GO */
10598 err
= wldev_ioctl_set(dev
, WLC_SET_INFRA
, &infra
, sizeof(s32
));
10600 WL_ERR(("SET INFRA error %d\n", err
));
10604 /* Do abort scan before creating GO */
10605 wl_cfg80211_scan_abort(cfg
);
10607 if (dev_role
== NL80211_IFTYPE_P2P_GO
) {
10608 is_bssup
= wl_cfg80211_bss_isup(dev
, bssidx
);
10609 if (!is_bssup
&& (ies
->wpa2_ie
!= NULL
)) {
10611 err
= wldev_iovar_setbuf_bsscfg(dev
, "ssid", &cfg
->p2p
->ssid
,
10612 sizeof(cfg
->p2p
->ssid
), cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
,
10613 bssidx
, &cfg
->ioctl_buf_sync
);
10615 WL_ERR(("GO SSID setting error %d\n", err
));
10619 if ((err
= wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 1)) < 0) {
10620 WL_ERR(("GO Bring up error %d\n", err
));
10624 WL_DBG(("Bss is already up\n"));
10625 } else if (dev_role
== NL80211_IFTYPE_AP
) {
10627 if (!wl_get_drv_status(cfg
, AP_CREATING
, dev
)) {
10628 /* Make sure fw is in proper state */
10629 err
= wl_cfg80211_set_ap_role(cfg
, dev
);
10630 if (unlikely(err
)) {
10631 WL_ERR(("set ap role failed!\n"));
10636 /* Device role SoftAP */
10637 WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx
, dev_role
));
10638 /* Clear the status bit after use */
10639 wl_clr_drv_status(cfg
, AP_CREATING
, dev
);
10641 #ifdef DISABLE_11H_SOFTAP
10642 if (is_rsdb_supported
== 0) {
10643 err
= wldev_ioctl_set(dev
, WLC_DOWN
, &ap
, sizeof(s32
));
10645 WL_ERR(("WLC_DOWN error %d\n", err
));
10649 err
= wldev_ioctl_set(dev
, WLC_SET_SPECT_MANAGMENT
,
10650 &spect
, sizeof(s32
));
10652 WL_ERR(("SET SPECT_MANAGMENT error %d\n", err
));
10655 #endif /* DISABLE_11H_SOFTAP */
10657 #ifdef SOFTAP_UAPSD_OFF
10658 err
= wldev_iovar_setbuf_bsscfg(dev
, "wme_apsd", &wme_apsd
, sizeof(wme_apsd
),
10659 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
10661 WL_ERR(("failed to disable uapsd, error=%d\n", err
));
10663 #endif /* SOFTAP_UAPSD_OFF */
10665 err
= wldev_ioctl_set(dev
, WLC_UP
, &ap
, sizeof(s32
));
10666 if (unlikely(err
)) {
10667 WL_ERR(("WLC_UP error (%d)\n", err
));
10672 if (cfg
->bip_pos
) {
10673 err
= wldev_iovar_setbuf_bsscfg(dev
, "bip",
10674 (const void *)(cfg
->bip_pos
), WPA_SUITE_LEN
, cfg
->ioctl_buf
,
10675 WLC_IOCTL_SMLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
10677 WL_ERR(("bip set error %d\n", err
));
10678 #if defined(CUSTOMER_HW4)
10679 if (wl_legacy_chip_check(cfg
))
10681 /* Ignore bip error: Some older firmwares doesn't
10682 * support bip iovar/ return BCME_NOTUP while trying
10683 * to set bip from AP bring up context. These firmares
10684 * include bip in RSNIE by default. So its okay to ignore
10697 err
= wldev_iovar_getint(dev
, "wsec", (s32
*)&wsec
);
10698 if (unlikely(err
)) {
10699 WL_ERR(("Could not get wsec %d\n", err
));
10702 if ((wsec
== WEP_ENABLED
) && cfg
->wep_key
.len
) {
10703 WL_DBG(("Applying buffered WEP KEY \n"));
10704 err
= wldev_iovar_setbuf_bsscfg(dev
, "wsec_key", &cfg
->wep_key
,
10705 sizeof(struct wl_wsec_key
), cfg
->ioctl_buf
,
10706 WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
10707 /* clear the key after use */
10708 memset(&cfg
->wep_key
, 0, sizeof(struct wl_wsec_key
));
10709 if (unlikely(err
)) {
10710 WL_ERR(("WLC_SET_KEY error (%d)\n", err
));
10716 if (cfg
->mfp_mode
) {
10717 /* This needs to go after wsec otherwise the wsec command will
10718 * overwrite the values set by MFP
10720 err
= wldev_iovar_setint_bsscfg(dev
, "mfp", cfg
->mfp_mode
, bssidx
);
10722 WL_ERR(("MFP Setting failed. ret = %d \n", err
));
10723 /* If fw doesn't support mfp, Ignore the error */
10724 if (err
!= BCME_UNSUPPORTED
) {
10731 memset(&join_params
, 0, sizeof(join_params
));
10732 /* join parameters starts with ssid */
10733 join_params_size
= sizeof(join_params
.ssid
);
10734 join_params
.ssid
.SSID_len
= MIN(cfg
->hostapd_ssid
.SSID_len
,
10735 (uint32
)DOT11_MAX_SSID_LEN
);
10736 memcpy(join_params
.ssid
.SSID
, cfg
->hostapd_ssid
.SSID
,
10737 join_params
.ssid
.SSID_len
);
10738 join_params
.ssid
.SSID_len
= htod32(join_params
.ssid
.SSID_len
);
10740 /* create softap */
10741 if ((err
= wldev_ioctl_set(dev
, WLC_SET_SSID
, &join_params
,
10742 join_params_size
)) != 0) {
10743 WL_ERR(("SoftAP/GO set ssid failed! \n"));
10746 WL_DBG((" SoftAP SSID \"%s\" \n", join_params
.ssid
.SSID
));
10750 /* AP on Virtual Interface */
10751 if ((err
= wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 1)) < 0) {
10752 WL_ERR(("AP Bring up error %d\n", err
));
10758 WL_ERR(("Wrong interface type %d\n", dev_role
));
10762 /* Wait for Linkup event to mark successful AP/GO bring up */
10763 timeout
= wait_event_interruptible_timeout(cfg
->netif_change_event
,
10764 wl_get_drv_status(cfg
, AP_CREATED
, dev
), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME
));
10765 if (timeout
<= 0 || !wl_get_drv_status(cfg
, AP_CREATED
, dev
)) {
10766 WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
10767 if (timeout
== -ERESTARTSYS
) {
10768 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
10769 err
= -ERESTARTSYS
;
10772 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
10773 if (dhdp
->memdump_enabled
) {
10774 dhdp
->memdump_type
= DUMP_TYPE_AP_LINKUP_FAILURE
;
10775 dhd_bus_mem_dump(dhdp
);
10777 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
10781 SUPP_LOG(("AP/GO Link up\n"));
10784 if (cfg
->wep_key
.len
) {
10785 memset(&cfg
->wep_key
, 0, sizeof(struct wl_wsec_key
));
10789 if (cfg
->mfp_mode
) {
10793 if (cfg
->bip_pos
) {
10794 cfg
->bip_pos
= NULL
;
10799 SUPP_LOG(("AP/GO bring up fail. err:%d\n", err
));
10804 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
10806 wl_cfg80211_parse_ap_ies(
10807 struct net_device
*dev
,
10808 struct cfg80211_beacon_data
*info
,
10809 struct parsed_ies
*ies
)
10811 struct parsed_ies prb_ies
;
10812 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
10813 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
10814 const u8
*vndr
= NULL
;
10815 u32 vndr_ie_len
= 0;
10818 /* Parse Beacon IEs */
10819 if (wl_cfg80211_parse_ies((const u8
*)info
->tail
,
10820 info
->tail_len
, ies
) < 0) {
10821 WL_ERR(("Beacon get IEs failed \n"));
10826 vndr
= (const u8
*)info
->proberesp_ies
;
10827 vndr_ie_len
= (uint32
)info
->proberesp_ies_len
;
10829 if (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
10831 const struct ieee80211_mgmt
*mgmt
;
10832 mgmt
= (const struct ieee80211_mgmt
*)info
->probe_resp
;
10833 if (mgmt
!= NULL
) {
10834 vndr
= (const u8
*)&mgmt
->u
.probe_resp
.variable
;
10835 vndr_ie_len
= (uint32
)(info
->probe_resp_len
-
10836 offsetof(const struct ieee80211_mgmt
, u
.probe_resp
.variable
));
10839 /* Parse Probe Response IEs */
10840 if (wl_cfg80211_parse_ies((const u8
*)vndr
, vndr_ie_len
, &prb_ies
) < 0) {
10841 WL_ERR(("PROBE RESP get IEs failed \n"));
10850 wl_cfg80211_set_ies(
10851 struct net_device
*dev
,
10852 struct cfg80211_beacon_data
*info
,
10855 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
10856 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
10857 const u8
*vndr
= NULL
;
10858 u32 vndr_ie_len
= 0;
10861 /* Set Beacon IEs to FW */
10862 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
10863 VNDR_IE_BEACON_FLAG
, (const u8
*)info
->tail
,
10864 info
->tail_len
)) < 0) {
10865 WL_ERR(("Set Beacon IE Failed \n"));
10867 WL_DBG(("Applied Vndr IEs for Beacon \n"));
10870 vndr
= (const u8
*)info
->proberesp_ies
;
10871 vndr_ie_len
= (uint32
)info
->proberesp_ies_len
;
10873 if (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
10875 const struct ieee80211_mgmt
*mgmt
;
10876 mgmt
= (const struct ieee80211_mgmt
*)info
->probe_resp
;
10877 if (mgmt
!= NULL
) {
10878 vndr
= (const u8
*)&mgmt
->u
.probe_resp
.variable
;
10879 vndr_ie_len
= (uint32
)(info
->probe_resp_len
-
10880 offsetof(struct ieee80211_mgmt
, u
.probe_resp
.variable
));
10884 /* Set Probe Response IEs to FW */
10885 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
10886 VNDR_IE_PRBRSP_FLAG
, vndr
, vndr_ie_len
)) < 0) {
10887 WL_ERR(("Set Probe Resp IE Failed \n"));
10889 WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
10894 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
10896 static s32
wl_cfg80211_hostapd_sec(
10897 struct net_device
*dev
,
10898 struct parsed_ies
*ies
,
10901 bool update_bss
= 0;
10902 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
10903 wl_cfgbss_t
*bss
= wl_get_cfgbss_by_wdev(cfg
, dev
->ieee80211_ptr
);
10906 WL_ERR(("cfgbss is NULL \n"));
10912 memcmp(bss
->wps_ie
, ies
->wps_ie
, ies
->wps_ie_len
)) {
10913 WL_DBG((" WPS IE is changed\n"));
10914 MFREE(cfg
->osh
, bss
->wps_ie
, bss
->wps_ie
[1] + 2);
10915 bss
->wps_ie
= MALLOCZ(cfg
->osh
, ies
->wps_ie_len
);
10917 memcpy(bss
->wps_ie
, ies
->wps_ie
, ies
->wps_ie_len
);
10919 } else if (bss
->wps_ie
== NULL
) {
10920 WL_DBG((" WPS IE is added\n"));
10921 bss
->wps_ie
= MALLOCZ(cfg
->osh
, ies
->wps_ie_len
);
10923 memcpy(bss
->wps_ie
, ies
->wps_ie
, ies
->wps_ie_len
);
10927 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10928 if (ies
->wpa_ie
!= NULL
&& ies
->wpa2_ie
!= NULL
) {
10929 WL_ERR(("update bss - wpa_ie and wpa2_ie is not null\n"));
10930 if (!bss
->security_mode
) {
10931 /* change from open mode to security mode */
10933 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
10934 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
10936 memcpy(bss
->wpa_ie
, ies
->wpa_ie
,
10937 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
10939 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
10940 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
);
10942 memcpy(bss
->rsn_ie
, ies
->wpa2_ie
,
10943 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
);
10946 /* change from (WPA or WPA2 or WPA/WPA2) to WPA/WPA2 mixed mode */
10948 if (memcmp(bss
->wpa_ie
,
10949 ies
->wpa_ie
, ies
->wpa_ie
->length
+
10950 WPA_RSN_IE_TAG_FIXED_LEN
)) {
10951 MFREE(cfg
->osh
, bss
->wpa_ie
,
10952 bss
->wpa_ie
[1] + WPA_RSN_IE_TAG_FIXED_LEN
);
10954 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
10955 ies
->wpa_ie
->length
10956 + WPA_RSN_IE_TAG_FIXED_LEN
);
10958 memcpy(bss
->wpa_ie
, ies
->wpa_ie
,
10959 ies
->wpa_ie
->length
10960 + WPA_RSN_IE_TAG_FIXED_LEN
);
10966 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
10967 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
10969 memcpy(bss
->wpa_ie
, ies
->wpa_ie
,
10970 ies
->wpa_ie
->length
10971 + WPA_RSN_IE_TAG_FIXED_LEN
);
10975 if (memcmp(bss
->rsn_ie
,
10977 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
)) {
10979 MFREE(cfg
->osh
, bss
->rsn_ie
,
10980 bss
->rsn_ie
[1] + WPA_RSN_IE_TAG_FIXED_LEN
);
10981 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
10983 + WPA_RSN_IE_TAG_FIXED_LEN
);
10985 memcpy(bss
->rsn_ie
, ies
->wpa2_ie
,
10987 + WPA_RSN_IE_TAG_FIXED_LEN
);
10993 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
10995 + WPA_RSN_IE_TAG_FIXED_LEN
);
10997 memcpy(bss
->rsn_ie
, ies
->wpa2_ie
,
10999 + WPA_RSN_IE_TAG_FIXED_LEN
);
11003 WL_ERR(("update_bss=%d\n", update_bss
));
11005 bss
->security_mode
= true;
11006 wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 0);
11007 if (wl_validate_wpaie_wpa2ie(dev
, ies
->wpa_ie
,
11008 ies
->wpa2_ie
, bssidx
) < 0) {
11011 wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 1);
11016 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11017 if ((ies
->wpa_ie
!= NULL
|| ies
->wpa2_ie
!= NULL
)) {
11018 if (!bss
->security_mode
) {
11019 /* change from open mode to security mode */
11021 if (ies
->wpa_ie
!= NULL
) {
11022 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
11023 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11025 memcpy(bss
->wpa_ie
,
11027 ies
->wpa_ie
->length
11028 + WPA_RSN_IE_TAG_FIXED_LEN
);
11031 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
11032 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11034 memcpy(bss
->rsn_ie
,
11037 + WPA_RSN_IE_TAG_FIXED_LEN
);
11040 } else if (bss
->wpa_ie
) {
11041 /* change from WPA2 mode to WPA mode */
11042 if (ies
->wpa_ie
!= NULL
) {
11044 MFREE(cfg
->osh
, bss
->rsn_ie
,
11045 bss
->rsn_ie
[1] + WPA_RSN_IE_TAG_FIXED_LEN
);
11046 bss
->rsn_ie
= NULL
;
11047 bss
->wpa_ie
= MALLOCZ(cfg
->osh
,
11048 ies
->wpa_ie
->length
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11050 memcpy(bss
->wpa_ie
,
11052 ies
->wpa_ie
->length
11053 + WPA_RSN_IE_TAG_FIXED_LEN
);
11055 } else if (memcmp(bss
->rsn_ie
,
11056 ies
->wpa2_ie
, ies
->wpa2_ie
->len
11057 + WPA_RSN_IE_TAG_FIXED_LEN
)) {
11059 MFREE(cfg
->osh
, bss
->rsn_ie
,
11060 bss
->rsn_ie
[1] + WPA_RSN_IE_TAG_FIXED_LEN
);
11061 bss
->rsn_ie
= MALLOCZ(cfg
->osh
,
11062 ies
->wpa2_ie
->len
+ WPA_RSN_IE_TAG_FIXED_LEN
);
11064 memcpy(bss
->rsn_ie
,
11067 + WPA_RSN_IE_TAG_FIXED_LEN
);
11069 bss
->wpa_ie
= NULL
;
11073 bss
->security_mode
= true;
11074 wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 0);
11075 if (wl_validate_wpa2ie(dev
, ies
->wpa2_ie
, bssidx
) < 0 ||
11076 wl_validate_wpaie(dev
, ies
->wpa_ie
, bssidx
) < 0) {
11079 wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 1);
11083 WL_ERR(("No WPSIE in beacon \n"));
11088 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
11090 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11092 wl_cfg80211_del_station(
11093 struct wiphy
*wiphy
, struct net_device
*ndev
,
11094 struct station_del_parameters
*params
)
11095 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
11097 wl_cfg80211_del_station(
11098 struct wiphy
*wiphy
,
11099 struct net_device
*ndev
,
11100 const u8
* mac_addr
)
11103 wl_cfg80211_del_station(
11104 struct wiphy
*wiphy
,
11105 struct net_device
*ndev
,
11107 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11109 struct net_device
*dev
;
11110 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
11112 s8 eabuf
[ETHER_ADDR_STR_LEN
];
11114 char mac_buf
[MAX_NUM_OF_ASSOCIATED_DEV
*
11115 sizeof(struct ether_addr
) + sizeof(uint
)] = {0};
11116 struct maclist
*assoc_maclist
= (struct maclist
*)mac_buf
;
11117 int num_associated
= 0;
11119 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11120 const u8
*mac_addr
= params
->mac
;
11121 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11122 u16 rc
= params
->reason_code
;
11123 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11124 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11125 WL_DBG(("Entry\n"));
11126 if (mac_addr
== NULL
) {
11127 WL_DBG(("mac_addr is NULL ignore it\n"));
11131 dev
= ndev_to_wlc_ndev(ndev
, cfg
);
11133 if (p2p_is_on(cfg
)) {
11134 /* Suspend P2P discovery search-listen to prevent it from changing the
11137 if ((wl_cfgp2p_discover_enable_search(cfg
, false)) < 0) {
11138 WL_ERR(("Can not disable discovery mode\n"));
11143 assoc_maclist
->count
= MAX_NUM_OF_ASSOCIATED_DEV
;
11144 err
= wldev_ioctl_get(ndev
, WLC_GET_ASSOCLIST
,
11145 assoc_maclist
, sizeof(mac_buf
));
11147 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err
));
11149 num_associated
= assoc_maclist
->count
;
11151 memcpy(scb_val
.ea
.octet
, mac_addr
, ETHER_ADDR_LEN
);
11152 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11153 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11154 if (rc
== DOT11_RC_8021X_AUTH_FAIL
) {
11155 WL_ERR(("deauth will be sent at F/W\n"));
11156 scb_val
.val
= DOT11_RC_8021X_AUTH_FAIL
;
11158 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11159 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11162 if (wl_wps_session_update(ndev
,
11163 WPS_STATE_DISCONNECT_CLIENT
, mac_addr
) == BCME_UNSUPPORTED
) {
11164 /* Ignore disconnect command from upper layer */
11165 WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
11167 #endif /* WL_WPS_SYNC */
11170 /* need to guarantee EAP-Failure send out before deauth */
11171 dhd_wait_pend8021x(dev
);
11172 scb_val
.val
= DOT11_RC_DEAUTH_LEAVING
;
11173 err
= wldev_ioctl_set(dev
, WLC_SCB_DEAUTHENTICATE_FOR_REASON
, &scb_val
,
11174 sizeof(scb_val_t
));
11176 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err
));
11178 WL_INFORM_MEM(("Disconnect STA : " MACDBG
" scb_val.val %d\n",
11179 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr
*)mac_addr
,
11180 eabuf
)), scb_val
.val
));
11182 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11183 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11185 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11186 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11188 if (num_associated
> 0 && ETHER_ISBCAST(mac_addr
))
11194 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
11196 wl_cfg80211_change_station(
11197 struct wiphy
*wiphy
,
11198 struct net_device
*dev
,
11200 struct station_parameters
*params
)
11203 wl_cfg80211_change_station(
11204 struct wiphy
*wiphy
,
11205 struct net_device
*dev
,
11207 struct station_parameters
*params
)
11211 #ifdef DHD_LOSSLESS_ROAMING
11212 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
11215 WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG
" sta_flags_mask:0x%x "
11216 "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac
),
11217 params
->sta_flags_mask
, params
->sta_flags_set
, dev
->name
));
11219 /* Processing only authorize/de-authorize flag for now */
11220 if (!(params
->sta_flags_mask
& BIT(NL80211_STA_FLAG_AUTHORIZED
))) {
11221 WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
11225 if (!(params
->sta_flags_set
& BIT(NL80211_STA_FLAG_AUTHORIZED
))) {
11226 err
= wldev_ioctl_set(dev
, WLC_SCB_DEAUTHORIZE
, mac
, ETH_ALEN
);
11227 if (unlikely(err
)) {
11228 WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err
));
11230 WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG
"\n",
11231 dev
->name
, MAC2STRDBG(mac
)));
11236 err
= wldev_ioctl_set(dev
, WLC_SCB_AUTHORIZE
, mac
, ETH_ALEN
);
11237 if (unlikely(err
)) {
11238 WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err
));
11240 WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG
"\n",
11241 dev
->name
, MAC2STRDBG(mac
)));
11243 wl_wps_session_update(dev
, WPS_STATE_AUTHORIZE
, mac
);
11244 #endif /* WL_WPS_SYNC */
11246 #ifdef DHD_LOSSLESS_ROAMING
11247 wl_del_roam_timeout(cfg
);
11251 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
11254 wl_cfg80211_set_scb_timings(
11255 struct bcm_cfg80211
*cfg
,
11256 struct net_device
*dev
)
11260 wl_scb_probe_t scb_probe
;
11261 u32 ps_pretend_retries
;
11263 bzero(&scb_probe
, sizeof(wl_scb_probe_t
));
11264 scb_probe
.scb_timeout
= WL_SCB_TIMEOUT
;
11265 scb_probe
.scb_activity_time
= WL_SCB_ACTIVITY_TIME
;
11266 scb_probe
.scb_max_probe
= WL_SCB_MAX_PROBE
;
11267 err
= wldev_iovar_setbuf(dev
, "scb_probe", (void *)&scb_probe
,
11268 sizeof(wl_scb_probe_t
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
,
11269 &cfg
->ioctl_buf_sync
);
11270 if (unlikely(err
)) {
11271 WL_ERR(("set 'scb_probe' failed, error = %d\n", err
));
11275 ps_pretend_retries
= WL_PSPRETEND_RETRY_LIMIT
;
11276 err
= wldev_iovar_setint(dev
, "pspretend_retry_limit", ps_pretend_retries
);
11277 if (unlikely(err
)) {
11278 if (err
== BCME_UNSUPPORTED
) {
11279 /* Ignore error if fw doesn't support the iovar */
11280 WL_DBG(("set 'pspretend_retry_limit %d' failed, error = %d\n",
11281 ps_pretend_retries
, err
));
11283 WL_ERR(("set 'pspretend_retry_limit %d' failed, error = %d\n",
11284 ps_pretend_retries
, err
));
11289 ps_pretend
= MAX(WL_SCB_MAX_PROBE
/ 2, WL_MIN_PSPRETEND_THRESHOLD
);
11290 err
= wldev_iovar_setint(dev
, "pspretend_threshold", ps_pretend
);
11291 if (unlikely(err
)) {
11292 if (err
== BCME_UNSUPPORTED
) {
11293 /* Ignore error if fw doesn't support the iovar */
11294 WL_DBG(("wl pspretend_threshold %d set error %d\n",
11297 WL_ERR(("wl pspretend_threshold %d set error %d\n",
11306 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11308 wl_cfg80211_start_ap(
11309 struct wiphy
*wiphy
,
11310 struct net_device
*dev
,
11311 struct cfg80211_ap_settings
*info
)
11313 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
11315 struct parsed_ies ies
;
11318 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
11320 WL_DBG(("Enter \n"));
11321 #if defined(SUPPORT_RANDOM_MAC_SCAN)
11322 wl_cfg80211_random_mac_disable(dev
);
11323 #endif /* SUPPORT_RANDOM_MAC_SCAN */
11325 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
11326 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
11330 if (p2p_is_on(cfg
) && (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
)) {
11331 dev_role
= NL80211_IFTYPE_P2P_GO
;
11332 } else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
11333 dev_role
= NL80211_IFTYPE_AP
;
11334 dhd
->op_mode
|= DHD_FLAG_HOSTAP_MODE
;
11335 err
= dhd_ndo_enable(dhd
, FALSE
);
11336 WL_DBG(("%s: Disabling NDO on Hostapd mode %d\n", __FUNCTION__
, err
));
11338 WL_ERR(("%s: Disabling NDO Failed %d\n", __FUNCTION__
, err
));
11340 #ifdef PKT_FILTER_SUPPORT
11341 /* Disable packet filter */
11342 if (dhd
->early_suspended
) {
11343 WL_ERR(("Disable pkt_filter\n"));
11344 dhd_enable_packet_filter(0, dhd
);
11346 #endif /* PKT_FILTER_SUPPORT */
11347 #ifdef ARP_OFFLOAD_SUPPORT
11348 /* IF SoftAP is enabled, disable arpoe */
11349 if (dhd
->op_mode
& DHD_FLAG_STA_MODE
) {
11350 dhd_arp_offload_set(dhd
, 0);
11351 dhd_arp_offload_enable(dhd
, FALSE
);
11353 #endif /* ARP_OFFLOAD_SUPPORT */
11355 /* only AP or GO role need to be handled here. */
11363 /* Disable TDLS for primary Iface. For virtual interface,
11364 * tdls disable will happen from interface create context
11366 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_AP_CREATE
, false);
11368 #endif /* WLTDLS */
11370 if (!check_dev_role_integrity(cfg
, dev_role
)) {
11375 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
11376 if ((err
= wl_cfg80211_set_channel(wiphy
, dev
,
11377 dev
->ieee80211_ptr
->preset_chandef
.chan
,
11378 NL80211_CHAN_HT20
) < 0)) {
11379 WL_ERR(("Set channel failed \n"));
11382 #endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
11384 if ((err
= wl_cfg80211_bcn_set_params(info
, dev
,
11385 dev_role
, bssidx
)) < 0) {
11386 WL_ERR(("Beacon params set failed \n"));
11391 if ((err
= wl_cfg80211_parse_ap_ies(dev
, &info
->beacon
, &ies
)) < 0) {
11392 WL_ERR(("Set IEs failed \n"));
11396 if ((err
= wl_cfg80211_bcn_validate_sec(dev
, &ies
,
11397 dev_role
, bssidx
, info
->privacy
)) < 0)
11399 WL_ERR(("Beacon set security failed \n"));
11403 if ((err
= wl_cfg80211_bcn_bringup_ap(dev
, &ies
,
11404 dev_role
, bssidx
)) < 0) {
11405 WL_ERR(("Beacon bring up AP/GO failed \n"));
11409 /* Set GC/STA SCB expiry timings. */
11410 if ((err
= wl_cfg80211_set_scb_timings(cfg
, dev
))) {
11411 WL_ERR(("scb setting failed \n"));
11415 wl_set_drv_status(cfg
, CONNECTED
, dev
);
11416 WL_DBG(("** AP/GO Created **\n"));
11418 #ifdef WL_CFG80211_ACL
11419 /* Enfoce Admission Control. */
11420 if ((err
= wl_cfg80211_set_mac_acl(wiphy
, dev
, info
->acl
)) < 0) {
11421 WL_ERR(("Set ACL failed\n"));
11423 #endif /* WL_CFG80211_ACL */
11425 /* Set IEs to FW */
11426 if ((err
= wl_cfg80211_set_ies(dev
, &info
->beacon
, bssidx
)) < 0)
11427 WL_ERR(("Set IEs failed \n"));
11429 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
11430 if ((dev_role
== NL80211_IFTYPE_AP
) && (ies
.wps_ie
!= NULL
)) {
11432 wl_validate_wps_ie((const char *) ies
.wps_ie
, ies
.wps_ie_len
, &pbc
);
11434 WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
11435 wl_add_remove_eventmsg(dev
, WLC_E_PROBREQ_MSG
, true);
11439 /* Configure hidden SSID */
11440 if (info
->hidden_ssid
!= NL80211_HIDDEN_SSID_NOT_IN_USE
) {
11441 if ((err
= wldev_iovar_setint(dev
, "closednet", 1)) < 0)
11442 WL_ERR(("failed to set hidden : %d\n", err
));
11443 WL_DBG(("hidden_ssid_enum_val: %d \n", info
->hidden_ssid
));
11446 #ifdef SUPPORT_AP_RADIO_PWRSAVE
11447 if (dev_role
== NL80211_IFTYPE_AP
) {
11448 if (!wl_set_ap_rps(dev
, FALSE
, dev
->name
)) {
11449 wl_cfg80211_init_ap_rps(cfg
);
11451 WL_ERR(("Set rpsnoa failed \n"));
11454 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
11458 WL_ERR(("ADD/SET beacon failed\n"));
11459 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
11460 wl_cfg80211_stop_ap(wiphy
, dev
);
11461 if (dev_role
== NL80211_IFTYPE_AP
) {
11462 dhd
->op_mode
&= ~DHD_FLAG_HOSTAP_MODE
;
11463 #ifdef PKT_FILTER_SUPPORT
11464 /* Enable packet filter */
11465 if (dhd
->early_suspended
) {
11466 WL_ERR(("Enable pkt_filter\n"));
11467 dhd_enable_packet_filter(1, dhd
);
11469 #endif /* PKT_FILTER_SUPPORT */
11470 #ifdef ARP_OFFLOAD_SUPPORT
11471 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
11472 if (dhd
->op_mode
& DHD_FLAG_STA_MODE
) {
11473 dhd_arp_offload_set(dhd
, dhd_arp_mode
);
11474 dhd_arp_offload_enable(dhd
, TRUE
);
11476 #endif /* ARP_OFFLOAD_SUPPORT */
11477 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
11478 wl_cfg80211_set_frameburst(cfg
, TRUE
);
11479 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
11483 /* Since AP creation failed, re-enable TDLS */
11484 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_AP_DELETE
, false);
11486 #endif /* WLTDLS */
11494 wl_cfg80211_stop_ap(
11495 struct wiphy
*wiphy
,
11496 struct net_device
*dev
)
11502 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
11503 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
11505 WL_DBG(("Enter \n"));
11507 if (wl_cfg80211_get_bus_state(cfg
)) {
11508 /* since bus is down, iovar will fail. recovery path will bringup the bus. */
11509 WL_ERR(("bus is not ready\n"));
11517 wl_clr_drv_status(cfg
, AP_CREATING
, dev
);
11518 wl_clr_drv_status(cfg
, AP_CREATED
, dev
);
11519 cfg
->ap_oper_channel
= 0;
11521 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
11522 dev_role
= NL80211_IFTYPE_AP
;
11523 WL_DBG(("stopping AP operation\n"));
11524 } else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
11525 dev_role
= NL80211_IFTYPE_P2P_GO
;
11526 WL_DBG(("stopping P2P GO operation\n"));
11528 WL_ERR(("no AP/P2P GO interface is operational.\n"));
11532 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
11533 WL_ERR(("find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
11537 if (!check_dev_role_integrity(cfg
, dev_role
)) {
11538 WL_ERR(("role integrity check failed \n"));
11543 /* Free up resources */
11544 wl_cfg80211_cleanup_if(dev
);
11546 /* Clear AP/GO connected status */
11547 wl_clr_drv_status(cfg
, CONNECTED
, dev
);
11548 if ((err
= wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 0)) < 0) {
11549 WL_ERR(("bss down error %d\n", err
));
11552 if (dev_role
== NL80211_IFTYPE_AP
) {
11553 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
11554 wl_cfg80211_set_frameburst(cfg
, TRUE
);
11555 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
11556 #ifdef PKT_FILTER_SUPPORT
11557 /* Enable packet filter */
11558 if (dhd
->early_suspended
) {
11559 WL_ERR(("Enable pkt_filter\n"));
11560 dhd_enable_packet_filter(1, dhd
);
11562 #endif /* PKT_FILTER_SUPPORT */
11563 #ifdef ARP_OFFLOAD_SUPPORT
11564 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
11565 if (dhd
->op_mode
& DHD_FLAG_STA_MODE
) {
11566 dhd_arp_offload_set(dhd
, dhd_arp_mode
);
11567 dhd_arp_offload_enable(dhd
, TRUE
);
11569 #endif /* ARP_OFFLOAD_SUPPORT */
11571 if (!DHD_OPMODE_STA_SOFTAP_CONCURR(dhd
)) {
11572 /* For non-STA/SoftAP Concurrent mode,
11573 * we use stand alone AP. Do wl down on stop AP
11575 err
= wldev_ioctl_set(dev
, WLC_UP
, &ap
, sizeof(s32
));
11576 if (unlikely(err
)) {
11577 WL_ERR(("WLC_UP error (%d)\n", err
));
11583 wl_cfg80211_clear_per_bss_ies(cfg
, dev
->ieee80211_ptr
);
11584 #ifdef SUPPORT_AP_RADIO_PWRSAVE
11585 if (!wl_set_ap_rps(dev
, FALSE
, dev
->name
)) {
11586 wl_cfg80211_init_ap_rps(cfg
);
11588 WL_ERR(("Set rpsnoa failed \n"));
11590 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
11592 WL_DBG(("Stopping P2P GO \n"));
11593 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd
, DHD_EVENT_TIMEOUT_MS
*3);
11594 DHD_OS_WAKE_LOCK_TIMEOUT(dhd
);
11597 SUPP_LOG(("AP/GO Link down\n"));
11600 /* In case of failure, flush fw logs */
11601 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
11602 SUPP_LOG(("AP/GO Link down fail. err:%d\n", err
));
11606 /* re-enable TDLS if the number of connected interfaces is less than 2 */
11607 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_AP_DELETE
, false);
11609 #endif /* WLTDLS */
11611 if (dev_role
== NL80211_IFTYPE_AP
) {
11612 /* clear the AP mode */
11613 dhd
->op_mode
&= ~DHD_FLAG_HOSTAP_MODE
;
11619 wl_cfg80211_change_beacon(
11620 struct wiphy
*wiphy
,
11621 struct net_device
*dev
,
11622 struct cfg80211_beacon_data
*info
)
11625 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
11626 struct parsed_ies ies
;
11631 WL_DBG(("Enter \n"));
11633 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
11634 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
11638 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
11639 dev_role
= NL80211_IFTYPE_P2P_GO
;
11640 } else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
11641 dev_role
= NL80211_IFTYPE_AP
;
11647 if (!check_dev_role_integrity(cfg
, dev_role
)) {
11652 if ((dev_role
== NL80211_IFTYPE_P2P_GO
) && (cfg
->p2p_wdev
== NULL
)) {
11653 WL_ERR(("P2P already down status!\n"));
11659 if ((err
= wl_cfg80211_parse_ap_ies(dev
, info
, &ies
)) < 0) {
11660 WL_ERR(("Parse IEs failed \n"));
11664 /* Set IEs to FW */
11665 if ((err
= wl_cfg80211_set_ies(dev
, info
, bssidx
)) < 0) {
11666 WL_ERR(("Set IEs failed \n"));
11670 if (dev_role
== NL80211_IFTYPE_AP
) {
11671 if (wl_cfg80211_hostapd_sec(dev
, &ies
, bssidx
) < 0) {
11672 WL_ERR(("Hostapd update sec failed \n"));
11676 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
11677 if ((dev_role
== NL80211_IFTYPE_AP
) && (ies
.wps_ie
!= NULL
)) {
11678 wl_validate_wps_ie((const char *) ies
.wps_ie
, ies
.wps_ie_len
, &pbc
);
11679 WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc
));
11681 wl_add_remove_eventmsg(dev
, WLC_E_PROBREQ_MSG
, true);
11683 wl_add_remove_eventmsg(dev
, WLC_E_PROBREQ_MSG
, false);
11689 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
11695 wl_cfg80211_add_set_beacon(struct wiphy
*wiphy
, struct net_device
*dev
,
11696 struct beacon_parameters
*info
)
11699 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
11702 u32 dev_role
= NL80211_IFTYPE_AP
;
11703 struct parsed_ies ies
;
11704 bcm_tlv_t
*ssid_ie
;
11707 bool is_bss_up
= 0;
11708 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
11710 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
11711 info
->interval
, info
->dtim_period
, info
->head_len
, info
->tail_len
));
11713 if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
11714 dev_role
= NL80211_IFTYPE_AP
;
11716 #if defined(WL_ENABLE_P2P_IF)
11717 else if (dev
== cfg
->p2p_net
) {
11718 /* Group Add request on p2p0 */
11719 dev
= bcmcfg_to_prmry_ndev(cfg
);
11720 dev_role
= NL80211_IFTYPE_P2P_GO
;
11722 #endif /* WL_ENABLE_P2P_IF */
11724 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
11725 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
11729 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_GO
) {
11730 dev_role
= NL80211_IFTYPE_P2P_GO
;
11731 } else if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
11732 dhd
->op_mode
|= DHD_FLAG_HOSTAP_MODE
;
11735 if (!check_dev_role_integrity(cfg
, dev_role
)) {
11740 if ((dev_role
== NL80211_IFTYPE_P2P_GO
) && (cfg
->p2p_wdev
== NULL
)) {
11741 WL_ERR(("P2P already down status!\n"));
11746 ie_offset
= DOT11_MGMT_HDR_LEN
+ DOT11_BCN_PRB_FIXED_LEN
;
11747 /* find the SSID */
11748 if ((ssid_ie
= bcm_parse_tlvs((u8
*)&info
->head
[ie_offset
],
11749 info
->head_len
- ie_offset
,
11750 DOT11_MNG_SSID_ID
)) != NULL
) {
11751 if (dev_role
== NL80211_IFTYPE_AP
) {
11752 /* Store the hostapd SSID */
11753 memset(&cfg
->hostapd_ssid
.SSID
[0], 0x00, DOT11_MAX_SSID_LEN
);
11754 cfg
->hostapd_ssid
.SSID_len
= MIN(ssid_ie
->len
, DOT11_MAX_SSID_LEN
);
11755 memcpy(&cfg
->hostapd_ssid
.SSID
[0], ssid_ie
->data
,
11756 cfg
->hostapd_ssid
.SSID_len
);
11759 memset(&cfg
->p2p
->ssid
.SSID
[0], 0x00, DOT11_MAX_SSID_LEN
);
11760 cfg
->p2p
->ssid
.SSID_len
= MIN(ssid_ie
->len
, DOT11_MAX_SSID_LEN
);
11761 memcpy(cfg
->p2p
->ssid
.SSID
, ssid_ie
->data
,
11762 cfg
->p2p
->ssid
.SSID_len
);
11766 if (wl_cfg80211_parse_ies((u8
*)info
->tail
,
11767 info
->tail_len
, &ies
) < 0) {
11768 WL_ERR(("Beacon get IEs failed \n"));
11773 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
11774 VNDR_IE_BEACON_FLAG
, (u8
*)info
->tail
,
11775 info
->tail_len
)) < 0) {
11776 WL_ERR(("Beacon set IEs failed \n"));
11779 WL_DBG(("Applied Vndr IEs for Beacon \n"));
11782 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
11783 if ((err
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(dev
), bssidx
,
11784 VNDR_IE_PRBRSP_FLAG
, (u8
*)info
->proberesp_ies
,
11785 info
->proberesp_ies_len
)) < 0) {
11786 WL_ERR(("ProbeRsp set IEs failed \n"));
11789 WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
11793 is_bss_up
= wl_cfg80211_bss_isup(dev
, bssidx
);
11795 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
11796 privacy
= info
->privacy
;
11801 (wl_cfg80211_bcn_validate_sec(dev
, &ies
, dev_role
, bssidx
, privacy
) < 0))
11803 WL_ERR(("Beacon set security failed \n"));
11808 /* Set BI and DTIM period */
11809 if (info
->interval
) {
11810 if ((err
= wldev_ioctl_set(dev
, WLC_SET_BCNPRD
,
11811 &info
->interval
, sizeof(s32
))) < 0) {
11812 WL_ERR(("Beacon Interval Set Error, %d\n", err
));
11816 if (info
->dtim_period
) {
11817 if ((err
= wldev_ioctl_set(dev
, WLC_SET_DTIMPRD
,
11818 &info
->dtim_period
, sizeof(s32
))) < 0) {
11819 WL_ERR(("DTIM Interval Set Error, %d\n", err
));
11824 /* If bss is already up, skip bring up */
11826 (err
= wl_cfg80211_bcn_bringup_ap(dev
, &ies
, dev_role
, bssidx
)) < 0)
11828 WL_ERR(("Beacon bring up AP/GO failed \n"));
11832 /* Set GC/STA SCB expiry timings. */
11833 if ((err
= wl_cfg80211_set_scb_timings(cfg
, dev
))) {
11834 WL_ERR(("scb setting failed \n"));
11838 if (wl_get_drv_status(cfg
, AP_CREATED
, dev
)) {
11839 /* Soft AP already running. Update changed params */
11840 if (wl_cfg80211_hostapd_sec(dev
, &ies
, bssidx
) < 0) {
11841 WL_ERR(("Hostapd update sec failed \n"));
11847 /* Enable Probe Req filter */
11848 if (((dev_role
== NL80211_IFTYPE_P2P_GO
) ||
11849 (dev_role
== NL80211_IFTYPE_AP
)) && (ies
.wps_ie
!= NULL
)) {
11850 wl_validate_wps_ie((char *) ies
.wps_ie
, ies
.wps_ie_len
, &pbc
);
11852 wl_add_remove_eventmsg(dev
, WLC_E_PROBREQ_MSG
, true);
11855 WL_DBG(("** ADD/SET beacon done **\n"));
11856 wl_set_drv_status(cfg
, CONNECTED
, dev
);
11860 WL_ERR(("ADD/SET beacon failed\n"));
11861 if (dev_role
== NL80211_IFTYPE_AP
) {
11862 /* clear the AP mode */
11863 dhd
->op_mode
&= ~DHD_FLAG_HOSTAP_MODE
;
11871 wl_cfg80211_del_beacon(struct wiphy
*wiphy
, struct net_device
*dev
)
11876 struct wireless_dev
*wdev
= dev
->ieee80211_ptr
;
11877 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
11878 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
11880 WL_DBG(("Enter. \n"));
11883 WL_ERR(("wdev null \n"));
11887 if ((wdev
->iftype
!= NL80211_IFTYPE_P2P_GO
) && (wdev
->iftype
!= NL80211_IFTYPE_AP
)) {
11888 WL_ERR(("Unspported iface type iftype:%d \n", wdev
->iftype
));
11891 wl_clr_drv_status(cfg
, AP_CREATING
, dev
);
11892 wl_clr_drv_status(cfg
, AP_CREATED
, dev
);
11894 /* Clear AP/GO connected status */
11895 wl_clr_drv_status(cfg
, CONNECTED
, dev
);
11897 cfg
->ap_oper_channel
= 0;
11899 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) < 0) {
11900 WL_ERR(("find p2p index from wdev(%p) failed\n", dev
->ieee80211_ptr
));
11905 if ((err
= wl_cfg80211_bss_up(cfg
, dev
, bssidx
, 0)) < 0) {
11906 WL_ERR(("bss down error %d\n", err
));
11909 /* fall through is intentional */
11910 err
= wldev_ioctl_set(dev
, WLC_SET_INFRA
, &infra
, sizeof(s32
));
11912 WL_ERR(("SET INFRA error %d\n", err
));
11914 wl_cfg80211_clear_per_bss_ies(cfg
, dev
->ieee80211_ptr
);
11916 if (wdev
->iftype
== NL80211_IFTYPE_AP
) {
11917 /* clear the AP mode */
11918 dhd
->op_mode
&= ~DHD_FLAG_HOSTAP_MODE
;
11923 #endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11925 #ifdef WL_SCHED_SCAN
11926 #define PNO_TIME 30
11927 #define PNO_REPEAT 4
11928 #define PNO_FREQ_EXPO_MAX 2
11930 is_ssid_in_list(struct cfg80211_ssid
*ssid
, struct cfg80211_ssid
*ssid_list
, int count
)
11934 if (!ssid
|| !ssid_list
)
11937 for (i
= 0; i
< count
; i
++) {
11938 if (ssid
->ssid_len
== ssid_list
[i
].ssid_len
) {
11939 if (strncmp(ssid
->ssid
, ssid_list
[i
].ssid
, ssid
->ssid_len
) == 0)
11947 wl_cfg80211_sched_scan_start(struct wiphy
*wiphy
,
11948 struct net_device
*dev
,
11949 struct cfg80211_sched_scan_request
*request
)
11951 ushort pno_time
= PNO_TIME
;
11952 int pno_repeat
= PNO_REPEAT
;
11953 int pno_freq_expo_max
= PNO_FREQ_EXPO_MAX
;
11954 wlc_ssid_ext_t ssids_local
[MAX_PFN_LIST_COUNT
];
11955 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
11956 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
11957 struct cfg80211_ssid
*ssid
= NULL
;
11958 struct cfg80211_ssid
*hidden_ssid_list
= NULL
;
11959 log_conn_event_t
*event_data
= NULL
;
11960 tlv_log
*tlv_data
= NULL
;
11961 u32 alloc_len
, tlv_len
;
11966 unsigned long flags
;
11969 WL_ERR(("Sched scan request was NULL\n"));
11973 WL_DBG(("Enter \n"));
11974 WL_PNO((">>> SCHED SCAN START\n"));
11975 WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n",
11976 request
->n_match_sets
, request
->n_ssids
));
11977 WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
11978 request
->n_ssids
, pno_time
, pno_repeat
, pno_freq_expo_max
));
11980 if (!request
->n_ssids
|| !request
->n_match_sets
) {
11981 WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request
->n_ssids
));
11985 memset(&ssids_local
, 0, sizeof(ssids_local
));
11987 if (request
->n_ssids
> 0) {
11988 hidden_ssid_list
= request
->ssids
;
11991 if (DBG_RING_ACTIVE(dhdp
, DHD_EVENT_RING_ID
)) {
11992 alloc_len
= sizeof(log_conn_event_t
) + DOT11_MAX_SSID_LEN
;
11993 event_data
= (log_conn_event_t
*)MALLOC(cfg
->osh
, alloc_len
);
11995 WL_ERR(("%s: failed to allocate log_conn_event_t with "
11996 "length(%d)\n", __func__
, alloc_len
));
11999 memset(event_data
, 0, alloc_len
);
12000 event_data
->tlvs
= NULL
;
12001 tlv_len
= sizeof(tlv_log
);
12002 event_data
->tlvs
= (tlv_log
*)MALLOC(cfg
->osh
, tlv_len
);
12003 if (!event_data
->tlvs
) {
12004 WL_ERR(("%s: failed to allocate log_tlv with "
12005 "length(%d)\n", __func__
, tlv_len
));
12006 MFREE(cfg
->osh
, event_data
, alloc_len
);
12010 for (i
= 0; i
< request
->n_match_sets
&& ssid_cnt
< MAX_PFN_LIST_COUNT
; i
++) {
12011 ssid
= &request
->match_sets
[i
].ssid
;
12012 /* No need to include null ssid */
12013 if (ssid
->ssid_len
) {
12014 ssids_local
[ssid_cnt
].SSID_len
= MIN(ssid
->ssid_len
,
12015 (uint32
)DOT11_MAX_SSID_LEN
);
12016 memcpy(ssids_local
[ssid_cnt
].SSID
, ssid
->ssid
,
12017 ssids_local
[ssid_cnt
].SSID_len
);
12018 if (is_ssid_in_list(ssid
, hidden_ssid_list
, request
->n_ssids
)) {
12019 ssids_local
[ssid_cnt
].hidden
= TRUE
;
12020 WL_PNO((">>> PNO hidden SSID (%s) \n", ssid
->ssid
));
12022 ssids_local
[ssid_cnt
].hidden
= FALSE
;
12023 WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid
->ssid
));
12025 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 15, 0))
12026 if (request
->match_sets
[i
].rssi_thold
!= NL80211_SCAN_RSSI_THOLD_OFF
) {
12027 ssids_local
[ssid_cnt
].rssi_thresh
=
12028 (int8
)request
->match_sets
[i
].rssi_thold
;
12030 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 15, 0)) */
12036 if ((ret
= dhd_dev_pno_set_for_ssid(dev
, ssids_local
, ssid_cnt
,
12037 pno_time
, pno_repeat
, pno_freq_expo_max
, NULL
, 0)) < 0) {
12038 WL_ERR(("PNO setup failed!! ret=%d \n", ret
));
12043 if (DBG_RING_ACTIVE(dhdp
, DHD_EVENT_RING_ID
)) {
12044 for (i
= 0; i
< ssid_cnt
; i
++) {
12045 payload_len
= sizeof(log_conn_event_t
);
12046 event_data
->event
= WIFI_EVENT_DRIVER_PNO_ADD
;
12047 tlv_data
= event_data
->tlvs
;
12049 tlv_data
->tag
= WIFI_TAG_SSID
;
12050 tlv_data
->len
= ssids_local
[i
].SSID_len
;
12051 memcpy(tlv_data
->value
, ssids_local
[i
].SSID
,
12052 ssids_local
[i
].SSID_len
);
12053 payload_len
+= TLV_LOG_SIZE(tlv_data
);
12055 dhd_os_push_push_ring_data(dhdp
, DHD_EVENT_RING_ID
,
12056 event_data
, payload_len
);
12060 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
12061 cfg
->sched_scan_req
= request
;
12062 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
12066 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \
12067 defined(SUPPORT_RANDOM_MAC_SCAN)
12068 if (!ETHER_ISNULLADDR(request
->mac_addr
) && !ETHER_ISNULLADDR(request
->mac_addr_mask
)) {
12069 ret
= wl_cfg80211_scan_mac_enable(dev
, request
->mac_addr
, request
->mac_addr_mask
);
12070 /* Ignore if chip doesnt support the feature */
12072 if (ret
== BCME_UNSUPPORTED
) {
12073 /* If feature is not supported, ignore the error (legacy chips) */
12076 WL_ERR(("set random mac failed (%d). Ignore.\n", ret
));
12077 /* Cleanup the states and stop the pno */
12078 if (dhd_dev_pno_stop_for_ssid(dev
) < 0) {
12079 WL_ERR(("PNO Stop for SSID failed"));
12081 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
12082 cfg
->sched_scan_req
= NULL
;
12083 cfg
->sched_scan_running
= FALSE
;
12084 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
12088 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && (defined(SUPPORT_RANDOM_MAC_SCAN)) */
12091 MFREE(cfg
->osh
, event_data
->tlvs
, tlv_len
);
12092 MFREE(cfg
->osh
, event_data
, alloc_len
);
12098 wl_cfg80211_sched_scan_stop(struct wiphy
*wiphy
, struct net_device
*dev
)
12100 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
12101 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
12102 unsigned long flags
;
12104 WL_DBG(("Enter \n"));
12105 WL_PNO((">>> SCHED SCAN STOP\n"));
12107 if (dhd_dev_pno_stop_for_ssid(dev
) < 0) {
12108 WL_ERR(("PNO Stop for SSID failed"));
12110 DBG_EVENT_LOG(dhdp
, WIFI_EVENT_DRIVER_PNO_REMOVE
);
12113 if (cfg
->scan_request
&& cfg
->sched_scan_running
) {
12114 WL_PNO((">>> Sched scan running. Aborting it..\n"));
12115 wl_cfg80211_cancel_scan(cfg
);
12117 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
12118 cfg
->sched_scan_req
= NULL
;
12119 cfg
->sched_scan_running
= FALSE
;
12120 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
12123 #endif /* WL_SCHED_SCAN */
12125 #ifdef WL_SUPPORT_ACS
12127 * Currently the dump_obss IOVAR is returning string as output so we need to
12128 * parse the output buffer in an unoptimized way. Going forward if we get the
12129 * IOVAR output in binary format this method can be optimized
12131 static int wl_parse_dump_obss(char *buf
, struct wl_dump_survey
*survey
)
12135 char delim
[] = " \n";
12137 token
= strsep(&buf
, delim
);
12138 while (token
!= NULL
) {
12139 if (!strcmp(token
, "OBSS")) {
12140 for (i
= 0; i
< OBSS_TOKEN_IDX
; i
++)
12141 token
= strsep(&buf
, delim
);
12142 survey
->obss
= simple_strtoul(token
, NULL
, 10);
12145 if (!strcmp(token
, "IBSS")) {
12146 for (i
= 0; i
< IBSS_TOKEN_IDX
; i
++)
12147 token
= strsep(&buf
, delim
);
12148 survey
->ibss
= simple_strtoul(token
, NULL
, 10);
12151 if (!strcmp(token
, "TXDur")) {
12152 for (i
= 0; i
< TX_TOKEN_IDX
; i
++)
12153 token
= strsep(&buf
, delim
);
12154 survey
->tx
= simple_strtoul(token
, NULL
, 10);
12157 if (!strcmp(token
, "Category")) {
12158 for (i
= 0; i
< CTG_TOKEN_IDX
; i
++)
12159 token
= strsep(&buf
, delim
);
12160 survey
->no_ctg
= simple_strtoul(token
, NULL
, 10);
12163 if (!strcmp(token
, "Packet")) {
12164 for (i
= 0; i
< PKT_TOKEN_IDX
; i
++)
12165 token
= strsep(&buf
, delim
);
12166 survey
->no_pckt
= simple_strtoul(token
, NULL
, 10);
12169 if (!strcmp(token
, "Opp(time):")) {
12170 for (i
= 0; i
< IDLE_TOKEN_IDX
; i
++)
12171 token
= strsep(&buf
, delim
);
12172 survey
->idle
= simple_strtoul(token
, NULL
, 10);
12175 token
= strsep(&buf
, delim
);
12181 static int wl_dump_obss(struct net_device
*ndev
, cca_msrmnt_query req
,
12182 struct wl_dump_survey
*survey
)
12184 cca_stats_n_flags
*results
;
12187 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
12189 buf
= (char *)MALLOCZ(cfg
->osh
, sizeof(char) * WLC_IOCTL_MAXLEN
);
12190 if (unlikely(!buf
)) {
12191 WL_ERR(("%s: buf alloc failed\n", __func__
));
12195 retry
= IOCTL_RETRY_COUNT
;
12197 err
= wldev_iovar_getbuf(ndev
, "dump_obss", &req
, sizeof(req
),
12198 buf
, WLC_IOCTL_MAXLEN
, NULL
);
12202 WL_DBG(("attempt = %d, err = %d, \n",
12203 (IOCTL_RETRY_COUNT
- retry
), err
));
12207 WL_ERR(("failure, dump_obss IOVAR failed\n"));
12212 results
= (cca_stats_n_flags
*)(buf
);
12213 wl_parse_dump_obss(results
->buf
, survey
);
12214 MFREE(cfg
->osh
, buf
, sizeof(char) * WLC_IOCTL_MAXLEN
);
12218 MFREE(cfg
->osh
, buf
, sizeof(char) * WLC_IOCTL_MAXLEN
);
12222 static int wl_cfg80211_dump_survey(struct wiphy
*wiphy
, struct net_device
*ndev
,
12223 int idx
, struct survey_info
*info
)
12225 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
12226 struct wl_dump_survey
*survey
;
12227 struct ieee80211_supported_band
*band
;
12228 struct ieee80211_channel
*chan
;
12229 cca_msrmnt_query req
;
12230 int val
, err
, noise
, retry
;
12232 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
12233 if (!(dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
12236 band
= wiphy
->bands
[NL80211_BAND_2GHZ
];
12237 if (band
&& idx
>= band
->n_channels
) {
12238 idx
-= band
->n_channels
;
12242 if (!band
|| idx
>= band
->n_channels
) {
12243 /* Move to 5G band */
12244 band
= wiphy
->bands
[NL80211_BAND_5GHZ
];
12245 if (idx
>= band
->n_channels
) {
12250 chan
= &band
->channels
[idx
];
12251 /* Setting current channel to the requested channel */
12252 if ((err
= wl_cfg80211_set_channel(wiphy
, ndev
, chan
,
12253 NL80211_CHAN_HT20
) < 0)) {
12254 WL_ERR(("Set channel failed \n"));
12258 /* Set interface up, explicitly. */
12260 err
= wldev_ioctl_set(ndev
, WLC_UP
, (void *)&val
, sizeof(val
));
12262 WL_ERR(("set interface up failed, error = %d\n", err
));
12266 /* Get noise value */
12267 retry
= IOCTL_RETRY_COUNT
;
12270 err
= wldev_ioctl_get(ndev
, WLC_GET_PHY_NOISE
, &noise
,
12275 WL_DBG(("attempt = %d, err = %d, \n",
12276 (IOCTL_RETRY_COUNT
- retry
), err
));
12280 WL_ERR(("Get Phy Noise failed, error = %d\n", err
));
12281 noise
= CHAN_NOISE_DUMMY
;
12284 survey
= (struct wl_dump_survey
*)MALLOCZ(cfg
->osh
,
12285 sizeof(struct wl_dump_survey
));
12286 if (unlikely(!survey
)) {
12287 WL_ERR(("%s: alloc failed\n", __func__
));
12291 /* Start Measurement for obss stats on current channel */
12292 req
.msrmnt_query
= 0;
12293 req
.time_req
= ACS_MSRMNT_DELAY
;
12294 if ((err
= wl_dump_obss(ndev
, req
, survey
)) < 0) {
12299 * Wait for the meaurement to complete, adding a buffer value of 10 to take
12300 * into consideration any delay in IOVAR completion
12302 msleep(ACS_MSRMNT_DELAY
+ 10);
12304 /* Issue IOVAR to collect measurement results */
12305 req
.msrmnt_query
= 1;
12306 if ((err
= wl_dump_obss(ndev
, req
, survey
)) < 0) {
12310 info
->channel
= chan
;
12311 info
->noise
= noise
;
12312 info
->channel_time
= ACS_MSRMNT_DELAY
;
12313 info
->channel_time_busy
= ACS_MSRMNT_DELAY
- survey
->idle
;
12314 info
->channel_time_rx
= survey
->obss
+ survey
->ibss
+ survey
->no_ctg
+
12316 info
->channel_time_tx
= survey
->tx
;
12317 info
->filled
= SURVEY_INFO_NOISE_DBM
|SURVEY_INFO_CHANNEL_TIME
|
12318 SURVEY_INFO_CHANNEL_TIME_BUSY
| SURVEY_INFO_CHANNEL_TIME_RX
|
12319 SURVEY_INFO_CHANNEL_TIME_TX
;
12320 MFREE(cfg
->osh
, survey
, sizeof(struct wl_dump_survey
));
12324 MFREE(cfg
->osh
, survey
, sizeof(struct wl_dump_survey
));
12327 #endif /* WL_SUPPORT_ACS */
12329 static struct cfg80211_ops wl_cfg80211_ops
= {
12330 .add_virtual_intf
= wl_cfg80211_add_virtual_iface
,
12331 .del_virtual_intf
= wl_cfg80211_del_virtual_iface
,
12332 .change_virtual_intf
= wl_cfg80211_change_virtual_iface
,
12333 #if defined(WL_CFG80211_P2P_DEV_IF)
12334 .start_p2p_device
= wl_cfgp2p_start_p2p_device
,
12335 .stop_p2p_device
= wl_cfgp2p_stop_p2p_device
,
12336 #endif /* WL_CFG80211_P2P_DEV_IF */
12337 .scan
= wl_cfg80211_scan
,
12338 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
12339 .abort_scan
= wl_cfg80211_abort_scan
,
12340 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
12341 .set_wiphy_params
= wl_cfg80211_set_wiphy_params
,
12342 .join_ibss
= wl_cfg80211_join_ibss
,
12343 .leave_ibss
= wl_cfg80211_leave_ibss
,
12344 .get_station
= wl_cfg80211_get_station
,
12345 .set_tx_power
= wl_cfg80211_set_tx_power
,
12346 .get_tx_power
= wl_cfg80211_get_tx_power
,
12347 .add_key
= wl_cfg80211_add_key
,
12348 .del_key
= wl_cfg80211_del_key
,
12349 .get_key
= wl_cfg80211_get_key
,
12350 .set_default_key
= wl_cfg80211_config_default_key
,
12351 .set_default_mgmt_key
= wl_cfg80211_config_default_mgmt_key
,
12352 .set_power_mgmt
= wl_cfg80211_set_power_mgmt
,
12353 .connect
= wl_cfg80211_connect
,
12354 .disconnect
= wl_cfg80211_disconnect
,
12355 .suspend
= wl_cfg80211_suspend
,
12356 .resume
= wl_cfg80211_resume
,
12357 .set_pmksa
= wl_cfg80211_set_pmksa
,
12358 .del_pmksa
= wl_cfg80211_del_pmksa
,
12359 .flush_pmksa
= wl_cfg80211_flush_pmksa
,
12360 .remain_on_channel
= wl_cfg80211_remain_on_channel
,
12361 .cancel_remain_on_channel
= wl_cfg80211_cancel_remain_on_channel
,
12362 .mgmt_tx
= wl_cfg80211_mgmt_tx
,
12363 .mgmt_frame_register
= wl_cfg80211_mgmt_frame_register
,
12364 .change_bss
= wl_cfg80211_change_bss
,
12365 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS)
12366 .set_channel
= wl_cfg80211_set_channel
,
12367 #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
12368 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS)
12369 .set_beacon
= wl_cfg80211_add_set_beacon
,
12370 .add_beacon
= wl_cfg80211_add_set_beacon
,
12371 .del_beacon
= wl_cfg80211_del_beacon
,
12373 .change_beacon
= wl_cfg80211_change_beacon
,
12374 .start_ap
= wl_cfg80211_start_ap
,
12375 .stop_ap
= wl_cfg80211_stop_ap
,
12376 #endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
12377 #ifdef WL_SCHED_SCAN
12378 .sched_scan_start
= wl_cfg80211_sched_scan_start
,
12379 .sched_scan_stop
= wl_cfg80211_sched_scan_stop
,
12380 #endif /* WL_SCHED_SCAN */
12381 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
12383 .del_station
= wl_cfg80211_del_station
,
12384 .change_station
= wl_cfg80211_change_station
,
12385 .mgmt_tx_cancel_wait
= wl_cfg80211_mgmt_tx_cancel_wait
,
12386 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
12387 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
12388 .tdls_mgmt
= wl_cfg80211_tdls_mgmt
,
12389 .tdls_oper
= wl_cfg80211_tdls_oper
,
12390 #endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
12391 #ifdef WL_SUPPORT_ACS
12392 .dump_survey
= wl_cfg80211_dump_survey
,
12393 #endif /* WL_SUPPORT_ACS */
12394 #ifdef WL_CFG80211_ACL
12395 .set_mac_acl
= wl_cfg80211_set_mac_acl
,
12396 #endif /* WL_CFG80211_ACL */
12397 #ifdef GTK_OFFLOAD_SUPPORT
12398 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
12399 .set_rekey_data
= wl_cfg80211_set_rekey_data
,
12400 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
12401 #endif /* GTK_OFFLOAD_SUPPORT */
12404 s32
wl_mode_to_nl80211_iftype(s32 mode
)
12410 return NL80211_IFTYPE_STATION
;
12412 return NL80211_IFTYPE_ADHOC
;
12414 return NL80211_IFTYPE_AP
;
12416 return NL80211_IFTYPE_UNSPECIFIED
;
12423 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
12424 static const struct wiphy_wowlan_support brcm_wowlan_support
= {
12425 .flags
= WIPHY_WOWLAN_ANY
,
12426 .n_patterns
= WL_WOWLAN_MAX_PATTERNS
,
12427 .pattern_min_len
= WL_WOWLAN_MIN_PATTERN_LEN
,
12428 .pattern_max_len
= WL_WOWLAN_MAX_PATTERN_LEN
,
12429 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
12430 .max_pkt_offset
= WL_WOWLAN_MAX_PATTERN_LEN
,
12431 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
12433 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
12434 #endif /* CONFIG_PM */
12436 static s32
wl_setup_wiphy(struct wireless_dev
*wdev
, struct device
*sdiofunc_dev
, void *context
)
12440 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
12441 struct cfg80211_wowlan
*brcm_wowlan_config
= NULL
;
12442 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
12443 #endif /* CONFIG_PM */
12445 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
12446 dhd_pub_t
*dhd
= (dhd_pub_t
*)context
;
12447 BCM_REFERENCE(dhd
);
12450 WL_ERR(("DHD is NULL!!"));
12457 wiphy_new(&wl_cfg80211_ops
, sizeof(struct bcm_cfg80211
));
12458 if (unlikely(!wdev
->wiphy
)) {
12459 WL_ERR(("Couldn not allocate wiphy device\n"));
12463 set_wiphy_dev(wdev
->wiphy
, sdiofunc_dev
);
12464 wdev
->wiphy
->max_scan_ie_len
= WL_SCAN_IE_LEN_MAX
;
12465 /* Report how many SSIDs Driver can support per Scan request */
12466 wdev
->wiphy
->max_scan_ssids
= WL_SCAN_PARAMS_SSID_MAX
;
12467 wdev
->wiphy
->max_num_pmkids
= WL_NUM_PMKIDS_MAX
;
12468 #ifdef WL_SCHED_SCAN
12469 wdev
->wiphy
->max_sched_scan_ssids
= MAX_PFN_LIST_COUNT
;
12470 wdev
->wiphy
->max_match_sets
= MAX_PFN_LIST_COUNT
;
12471 wdev
->wiphy
->max_sched_scan_ie_len
= WL_SCAN_IE_LEN_MAX
;
12472 wdev
->wiphy
->flags
|= WIPHY_FLAG_SUPPORTS_SCHED_SCAN
;
12473 #endif /* WL_SCHED_SCAN */
12474 wdev
->wiphy
->interface_modes
=
12475 BIT(NL80211_IFTYPE_STATION
)
12476 | BIT(NL80211_IFTYPE_ADHOC
)
12477 #if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
12478 | BIT(NL80211_IFTYPE_MONITOR
)
12479 #endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
12480 #if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
12481 | BIT(NL80211_IFTYPE_P2P_CLIENT
)
12482 | BIT(NL80211_IFTYPE_P2P_GO
)
12483 #endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
12484 #if defined(WL_CFG80211_P2P_DEV_IF)
12485 | BIT(NL80211_IFTYPE_P2P_DEVICE
)
12486 #endif /* WL_CFG80211_P2P_DEV_IF */
12487 | BIT(NL80211_IFTYPE_AP
);
12489 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
12490 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
12491 WL_DBG(("Setting interface combinations for common mode\n"));
12492 wdev
->wiphy
->iface_combinations
= common_iface_combinations
;
12493 wdev
->wiphy
->n_iface_combinations
=
12494 ARRAY_SIZE(common_iface_combinations
);
12495 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
12497 wdev
->wiphy
->bands
[NL80211_BAND_2GHZ
] = &__wl_band_2ghz
;
12499 wdev
->wiphy
->signal_type
= CFG80211_SIGNAL_TYPE_MBM
;
12500 wdev
->wiphy
->cipher_suites
= __wl_cipher_suites
;
12501 wdev
->wiphy
->n_cipher_suites
= ARRAY_SIZE(__wl_cipher_suites
);
12502 wdev
->wiphy
->max_remain_on_channel_duration
= 5000;
12503 wdev
->wiphy
->mgmt_stypes
= wl_cfg80211_default_mgmt_stypes
;
12504 #ifndef WL_POWERSAVE_DISABLED
12505 wdev
->wiphy
->flags
|= WIPHY_FLAG_PS_ON_BY_DEFAULT
;
12507 wdev
->wiphy
->flags
&= ~WIPHY_FLAG_PS_ON_BY_DEFAULT
;
12508 #endif /* !WL_POWERSAVE_DISABLED */
12509 wdev
->wiphy
->flags
|= WIPHY_FLAG_NETNS_OK
|
12510 WIPHY_FLAG_4ADDR_AP
|
12511 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS)
12512 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS
|
12514 WIPHY_FLAG_4ADDR_STATION
;
12515 #if ((defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && ((LINUX_VERSION_CODE >= \
12516 KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)))
12518 * If FW ROAM flag is advertised, upper layer wouldn't provide
12519 * the bssid & freq in the connect command. This will result a
12520 * delay in initial connection time due to firmware doing a full
12521 * channel scan to figure out the channel & bssid. However kernel
12522 * ver >= 3.15, provides bssid_hint & freq_hint and hence kernel
12523 * ver >= 3.15 won't have any issue. So if this flags need to be
12524 * advertised for kernel < 3.15, suggest to use RCC along with it
12525 * to avoid the initial connection delay.
12527 wdev
->wiphy
->flags
|= WIPHY_FLAG_SUPPORTS_FW_ROAM
;
12528 #endif /* (ROAM_ENABLE || BCMFW_ROAM_ENABLE) && (LINUX_VERSION 3.2.0 || WL_COMPAT_WIRELESS) */
12529 #ifdef UNSET_FW_ROAM_WIPHY_FLAG
12530 wdev
->wiphy
->flags
&= ~WIPHY_FLAG_SUPPORTS_FW_ROAM
;
12531 #endif /* UNSET_FW_ROAM_WIPHY_FLAG */
12532 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
12533 wdev
->wiphy
->flags
|= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
|
12534 WIPHY_FLAG_OFFCHAN_TX
;
12536 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
12538 /* From 3.4 kernel ownards AP_SME flag can be advertised
12539 * to remove the patch from supplicant
12541 wdev
->wiphy
->flags
|= WIPHY_FLAG_HAVE_AP_SME
;
12543 #ifdef WL_CFG80211_ACL
12544 /* Configure ACL capabilities. */
12545 wdev
->wiphy
->max_acl_mac_addrs
= MAX_NUM_MAC_FILT
;
12548 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
12549 /* Supplicant distinguish between the SoftAP mode and other
12550 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
12551 * response frame from Supplicant MR1 and Kernel 3.4.0 or
12552 * later version. To add Vendor specific IE into the
12553 * probe response frame in case of SoftAP mode,
12554 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
12556 if (dhd_get_fw_mode(dhd
->info
) == DHD_FLAG_HOSTAP_MODE
) {
12557 wdev
->wiphy
->flags
|= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD
;
12558 wdev
->wiphy
->probe_resp_offload
= 0;
12561 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
12563 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
12564 wdev
->wiphy
->flags
|= WIPHY_FLAG_SUPPORTS_TDLS
;
12567 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
12569 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
12570 * disconnection of connected network before suspend. So a dummy wowlan
12571 * filter is configured for kernels linux-3.8 and above.
12574 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
12575 wdev
->wiphy
->wowlan
= &brcm_wowlan_support
;
12576 /* If this is not provided cfg stack will get disconnect
12579 brcm_wowlan_config
= MALLOC(dhd
->osh
, sizeof(struct cfg80211_wowlan
));
12580 if (brcm_wowlan_config
) {
12581 brcm_wowlan_config
->disconnect
= true;
12582 brcm_wowlan_config
->gtk_rekey_failure
= true;
12583 brcm_wowlan_config
->eap_identity_req
= true;
12584 brcm_wowlan_config
->four_way_handshake
= true;
12585 brcm_wowlan_config
->patterns
= NULL
;
12586 brcm_wowlan_config
->n_patterns
= 0;
12587 brcm_wowlan_config
->tcp
= NULL
;
12588 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12589 brcm_wowlan_config
->nd_config
= NULL
;
12592 WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
12593 " So wiphy->wowlan_config is set to NULL\n"));
12595 wdev
->wiphy
->wowlan_config
= brcm_wowlan_config
;
12597 wdev
->wiphy
->wowlan
.flags
= WIPHY_WOWLAN_ANY
;
12598 wdev
->wiphy
->wowlan
.n_patterns
= WL_WOWLAN_MAX_PATTERNS
;
12599 wdev
->wiphy
->wowlan
.pattern_min_len
= WL_WOWLAN_MIN_PATTERN_LEN
;
12600 wdev
->wiphy
->wowlan
.pattern_max_len
= WL_WOWLAN_MAX_PATTERN_LEN
;
12601 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
12602 wdev
->wiphy
->wowlan
.max_pkt_offset
= WL_WOWLAN_MAX_PATTERN_LEN
;
12603 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
12604 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
12605 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
12607 WL_DBG(("Registering custom regulatory)\n"));
12608 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
12609 wdev
->wiphy
->regulatory_flags
|= REGULATORY_CUSTOM_REG
;
12611 wdev
->wiphy
->flags
|= WIPHY_FLAG_CUSTOM_REGULATORY
;
12613 wiphy_apply_custom_regulatory(wdev
->wiphy
, &brcm_regdom
);
12615 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
12616 WL_INFORM_MEM(("Registering Vendor80211\n"));
12617 err
= wl_cfgvendor_attach(wdev
->wiphy
, dhd
);
12618 if (unlikely(err
< 0)) {
12619 WL_ERR(("Couldn not attach vendor commands (%d)\n", err
));
12621 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
12623 /* Now we can register wiphy with cfg80211 module */
12624 err
= wiphy_register(wdev
->wiphy
);
12625 if (unlikely(err
< 0)) {
12626 WL_ERR(("Couldn not register wiphy device (%d)\n", err
));
12627 wiphy_free(wdev
->wiphy
);
12630 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
12631 KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
12632 wdev
->wiphy
->flags
&= ~WIPHY_FLAG_ENFORCE_COMBINATIONS
;
12635 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) && defined(SUPPORT_RANDOM_MAC_SCAN)
12636 wdev
->wiphy
->features
|= (NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR
|
12637 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR
);
12638 wdev
->wiphy
->max_sched_scan_plans
= 1; /* multiple plans not supported */
12639 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) */
12644 static void wl_free_wdev(struct bcm_cfg80211
*cfg
)
12646 struct wireless_dev
*wdev
= cfg
->wdev
;
12647 struct wiphy
*wiphy
= NULL
;
12649 WL_ERR(("wdev is invalid\n"));
12653 wiphy
= wdev
->wiphy
;
12655 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
12656 wl_cfgvendor_detach(wdev
->wiphy
);
12657 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
12658 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
12659 /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
12660 WL_DBG(("wl_free_wdev Clearing wowlan Config \n"));
12661 if (wdev
->wiphy
->wowlan_config
) {
12662 MFREE(cfg
->osh
, wdev
->wiphy
->wowlan_config
,
12663 sizeof(struct cfg80211_wowlan
));
12664 wdev
->wiphy
->wowlan_config
= NULL
;
12666 wdev
->wiphy
->wowlan
= NULL
;
12667 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
12668 wiphy_unregister(wdev
->wiphy
);
12669 wdev
->wiphy
->dev
.parent
= NULL
;
12670 wdev
->wiphy
= NULL
;
12673 wl_delete_all_netinfo(cfg
);
12675 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
12679 /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
12680 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
12684 static s32
wl_inform_bss(struct bcm_cfg80211
*cfg
)
12686 struct wl_scan_results
*bss_list
;
12687 wl_bss_info_t
*bi
= NULL
; /* must be initialized */
12691 bss_list
= cfg
->bss_list
;
12692 WL_MEM(("scanned AP count (%d)\n", bss_list
->count
));
12693 #ifdef ESCAN_CHANNEL_CACHE
12694 reset_roam_cache(cfg
);
12695 #endif /* ESCAN_CHANNEL_CACHE */
12697 bi
= next_bss(bss_list
, bi
);
12698 for_each_bss(bss_list
, bi
, i
) {
12699 #ifdef ESCAN_CHANNEL_CACHE
12700 add_roam_cache(cfg
, bi
);
12701 #endif /* ESCAN_CHANNEL_CACHE */
12702 err
= wl_inform_single_bss(cfg
, bi
, false);
12703 if (unlikely(err
)) {
12704 WL_ERR(("bss inform failed\n"));
12708 WL_MEM(("cfg80211 scan cache updated\n"));
12709 #ifdef ROAM_CHANNEL_CACHE
12710 /* print_roam_cache(); */
12711 update_roam_cache(cfg
, ioctl_version
);
12712 #endif /* ROAM_CHANNEL_CACHE */
12716 static s32
wl_inform_single_bss(struct bcm_cfg80211
*cfg
, wl_bss_info_t
*bi
, bool roam
)
12718 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
12719 struct ieee80211_mgmt
*mgmt
;
12720 struct ieee80211_channel
*channel
;
12721 struct ieee80211_supported_band
*band
;
12722 struct wl_cfg80211_bss_info
*notif_bss_info
;
12723 struct wl_scan_req
*sr
= wl_to_sr(cfg
);
12724 struct beacon_proberesp
*beacon_proberesp
;
12725 struct cfg80211_bss
*cbss
= NULL
;
12726 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
12727 log_conn_event_t
*event_data
= NULL
;
12728 tlv_log
*tlv_data
= NULL
;
12729 u32 alloc_len
, tlv_len
;
12736 u8 tmp_buf
[IEEE80211_MAX_SSID_LEN
+ 1];
12738 if (unlikely(dtoh32(bi
->length
) > WL_BSS_INFO_MAX
)) {
12739 WL_DBG(("Beacon is larger than buffer. Discarding\n"));
12743 if (bi
->SSID_len
> IEEE80211_MAX_SSID_LEN
) {
12744 WL_ERR(("wrong SSID len:%d\n", bi
->SSID_len
));
12748 aflags
= (in_atomic()) ? GFP_ATOMIC
: GFP_KERNEL
;
12749 notif_bss_info
= (struct wl_cfg80211_bss_info
*)MALLOCZ(cfg
->osh
,
12750 sizeof(*notif_bss_info
) + sizeof(*mgmt
) - sizeof(u8
) + WL_BSS_INFO_MAX
);
12751 if (unlikely(!notif_bss_info
)) {
12752 WL_ERR(("notif_bss_info alloc failed\n"));
12755 mgmt
= (struct ieee80211_mgmt
*)notif_bss_info
->frame_buf
;
12756 notif_bss_info
->channel
=
12757 wf_chspec_ctlchan(wl_chspec_driver_to_host(bi
->chanspec
));
12759 if (notif_bss_info
->channel
<= CH_MAX_2G_CHANNEL
)
12760 band
= wiphy
->bands
[NL80211_BAND_2GHZ
];
12762 band
= wiphy
->bands
[NL80211_BAND_5GHZ
];
12764 WL_ERR(("No valid band"));
12765 MFREE(cfg
->osh
, notif_bss_info
, sizeof(*notif_bss_info
)
12766 + sizeof(*mgmt
) - sizeof(u8
) + WL_BSS_INFO_MAX
);
12769 notif_bss_info
->rssi
= wl_rssi_offset(dtoh16(bi
->RSSI
));
12770 memcpy(mgmt
->bssid
, &bi
->BSSID
, ETHER_ADDR_LEN
);
12771 mgmt_type
= cfg
->active_scan
?
12772 IEEE80211_STYPE_PROBE_RESP
: IEEE80211_STYPE_BEACON
;
12773 if (!memcmp(bi
->SSID
, sr
->ssid
.SSID
, bi
->SSID_len
)) {
12774 mgmt
->frame_control
= cpu_to_le16(IEEE80211_FTYPE_MGMT
| mgmt_type
);
12776 beacon_proberesp
= cfg
->active_scan
?
12777 (struct beacon_proberesp
*)&mgmt
->u
.probe_resp
:
12778 (struct beacon_proberesp
*)&mgmt
->u
.beacon
;
12779 beacon_proberesp
->timestamp
= 0;
12780 beacon_proberesp
->beacon_int
= cpu_to_le16(bi
->beacon_period
);
12781 beacon_proberesp
->capab_info
= cpu_to_le16(bi
->capability
);
12783 wl_update_hidden_ap_ie(bi
, ((u8
*) bi
) + bi
->ie_offset
, &bi
->ie_length
, roam
);
12784 wl_mrg_ie(cfg
, ((u8
*) bi
) + bi
->ie_offset
, bi
->ie_length
);
12785 wl_cp_ie(cfg
, beacon_proberesp
->variable
, WL_BSS_INFO_MAX
-
12786 offsetof(struct wl_cfg80211_bss_info
, frame_buf
));
12787 notif_bss_info
->frame_len
= offsetof(struct ieee80211_mgmt
,
12788 u
.beacon
.variable
) + wl_get_ielen(cfg
);
12789 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
12790 freq
= ieee80211_channel_to_frequency(notif_bss_info
->channel
);
12793 freq
= ieee80211_channel_to_frequency(notif_bss_info
->channel
, band
->band
);
12796 WL_ERR(("Invalid channel, fail to chcnage channel to freq\n"));
12797 MFREE(cfg
->osh
, notif_bss_info
, sizeof(*notif_bss_info
)
12798 + sizeof(*mgmt
) - sizeof(u8
) + WL_BSS_INFO_MAX
);
12801 channel
= ieee80211_get_channel(wiphy
, freq
);
12802 if (unlikely(!channel
)) {
12803 WL_ERR(("ieee80211_get_channel error\n"));
12804 MFREE(cfg
->osh
, notif_bss_info
, sizeof(*notif_bss_info
)
12805 + sizeof(*mgmt
) - sizeof(u8
) + WL_BSS_INFO_MAX
);
12808 memcpy(tmp_buf
, bi
->SSID
, bi
->SSID_len
);
12809 tmp_buf
[bi
->SSID_len
] = '\0';
12810 WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
12811 "mgmt_type %d frame_len %d\n", tmp_buf
,
12812 notif_bss_info
->rssi
, notif_bss_info
->channel
,
12813 mgmt
->u
.beacon
.capab_info
, &bi
->BSSID
, mgmt_type
,
12814 notif_bss_info
->frame_len
));
12816 signal
= notif_bss_info
->rssi
* 100;
12817 if (!mgmt
->u
.probe_resp
.timestamp
) {
12818 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
12819 struct timespec ts
;
12820 get_monotonic_boottime(&ts
);
12821 mgmt
->u
.probe_resp
.timestamp
= ((u64
)ts
.tv_sec
*1000000)
12822 + ts
.tv_nsec
/ 1000;
12825 do_gettimeofday(&tv
);
12826 mgmt
->u
.probe_resp
.timestamp
= ((u64
)tv
.tv_sec
*1000000)
12831 cbss
= cfg80211_inform_bss_frame(wiphy
, channel
, mgmt
,
12832 le16_to_cpu(notif_bss_info
->frame_len
), signal
, aflags
);
12833 if (unlikely(!cbss
)) {
12834 WL_ERR(("cfg80211_inform_bss_frame error bssid " MACDBG
" channel %d \n",
12835 MAC2STRDBG((u8
*)(&bi
->BSSID
)), notif_bss_info
->channel
));
12840 CFG80211_PUT_BSS(wiphy
, cbss
);
12842 if (DBG_RING_ACTIVE(dhdp
, DHD_EVENT_RING_ID
) &&
12843 (cfg
->sched_scan_req
&& !cfg
->scan_request
)) {
12844 alloc_len
= sizeof(log_conn_event_t
) + IEEE80211_MAX_SSID_LEN
+ sizeof(uint16
) +
12846 event_data
= (log_conn_event_t
*)MALLOCZ(cfg
->osh
, alloc_len
);
12848 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
12849 "length(%d)\n", __func__
, alloc_len
));
12852 tlv_len
= 3 * sizeof(tlv_log
);
12853 event_data
->tlvs
= (tlv_log
*)MALLOCZ(cfg
->osh
, tlv_len
);
12854 if (!event_data
->tlvs
) {
12855 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
12856 "length(%d)\n", __func__
, tlv_len
));
12857 goto free_evt_data
;
12860 payload_len
= sizeof(log_conn_event_t
);
12861 event_data
->event
= WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND
;
12862 tlv_data
= event_data
->tlvs
;
12865 tlv_data
->tag
= WIFI_TAG_SSID
;
12866 tlv_data
->len
= bi
->SSID_len
;
12867 memcpy(tlv_data
->value
, bi
->SSID
, bi
->SSID_len
);
12868 payload_len
+= TLV_LOG_SIZE(tlv_data
);
12869 tlv_data
= TLV_LOG_NEXT(tlv_data
);
12872 tlv_data
->tag
= WIFI_TAG_CHANNEL
;
12873 tlv_data
->len
= sizeof(uint16
);
12874 memcpy(tlv_data
->value
, ¬if_bss_info
->channel
, sizeof(uint16
));
12875 payload_len
+= TLV_LOG_SIZE(tlv_data
);
12876 tlv_data
= TLV_LOG_NEXT(tlv_data
);
12879 tlv_data
->tag
= WIFI_TAG_RSSI
;
12880 tlv_data
->len
= sizeof(int16
);
12881 memcpy(tlv_data
->value
, ¬if_bss_info
->rssi
, sizeof(int16
));
12882 payload_len
+= TLV_LOG_SIZE(tlv_data
);
12883 tlv_data
= TLV_LOG_NEXT(tlv_data
);
12885 dhd_os_push_push_ring_data(dhdp
, DHD_EVENT_RING_ID
,
12886 event_data
, payload_len
);
12887 MFREE(dhdp
->osh
, event_data
->tlvs
, tlv_len
);
12889 MFREE(dhdp
->osh
, event_data
, alloc_len
);
12893 MFREE(cfg
->osh
, notif_bss_info
, sizeof(*notif_bss_info
)
12894 + sizeof(*mgmt
) - sizeof(u8
) + WL_BSS_INFO_MAX
);
12898 static bool wl_is_linkup(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
, struct net_device
*ndev
)
12900 u32 event
= ntoh32(e
->event_type
);
12901 u32 status
= ntoh32(e
->status
);
12902 u16 flags
= ntoh16(e
->flags
);
12903 #if defined(CUSTOM_SET_OCLOFF) || defined(CUSTOM_SET_ANTNPM)
12905 dhd
= (dhd_pub_t
*)(cfg
->pub
);
12906 #endif /* CUSTOM_SET_OCLOFF || CUSTOM_SET_ANTNPM */
12908 WL_DBG(("event %d, status %d flags %x\n", event
, status
, flags
));
12909 if (event
== WLC_E_SET_SSID
) {
12910 if (status
== WLC_E_STATUS_SUCCESS
) {
12911 #ifdef CUSTOM_SET_OCLOFF
12912 if (dhd
->ocl_off
) {
12914 int ocl_enable
= 0;
12915 err
= wldev_iovar_setint(ndev
, "ocl_enable", ocl_enable
);
12917 WL_ERR(("[WIFI_SEC] %s: Set ocl_enable %d failed %d\n",
12918 __FUNCTION__
, ocl_enable
, err
));
12920 WL_ERR(("[WIFI_SEC] %s: Set ocl_enable %d succeeded %d\n",
12921 __FUNCTION__
, ocl_enable
, err
));
12924 #endif /* CUSTOM_SET_OCLOFF */
12925 #ifdef CUSTOM_SET_ANTNPM
12926 if (dhd
->mimo_ant_set
) {
12929 WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhd
->mimo_ant_set
));
12930 err
= wldev_iovar_setint(ndev
, "txchain", dhd
->mimo_ant_set
);
12932 WL_ERR(("[WIFI_SEC] Fail set txchain\n"));
12934 err
= wldev_iovar_setint(ndev
, "rxchain", dhd
->mimo_ant_set
);
12936 WL_ERR(("[WIFI_SEC] Fail set rxchain\n"));
12939 #endif /* CUSTOM_SET_ANTNPM */
12940 if (!wl_is_ibssmode(cfg
, ndev
))
12943 } else if (event
== WLC_E_LINK
) {
12944 if (flags
& WLC_EVENT_MSG_LINK
)
12948 WL_DBG(("wl_is_linkup false\n"));
12953 static bool wl_is_linkdown(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
, void *data
)
12955 u32 event
= ntoh32(e
->event_type
);
12956 u16 flags
= ntoh16(e
->flags
);
12957 wl_last_event_t
*last_event
= (wl_last_event_t
*)data
;
12958 u32 len
= ntoh32(e
->datalen
);
12960 if (event
== WLC_E_DEAUTH_IND
||
12961 event
== WLC_E_DISASSOC_IND
||
12962 event
== WLC_E_DISASSOC
||
12963 event
== WLC_E_DEAUTH
) {
12964 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event
)));
12966 } else if (event
== WLC_E_LINK
) {
12967 if (!(flags
& WLC_EVENT_MSG_LINK
)) {
12968 if (last_event
&& len
> 0) {
12969 u32 current_time
= last_event
->current_time
;
12970 u32 timestamp
= last_event
->timestamp
;
12971 u32 event_type
= last_event
->event
.event_type
;
12972 u32 status
= last_event
->event
.status
;
12973 u32 reason
= last_event
->event
.reason
;
12975 WL_ERR(("Last roam event before disconnection : current_time %d,"
12976 " time %d, type %d, status %d, reason %d\n",
12977 current_time
, timestamp
, event_type
, status
, reason
));
12979 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event
)));
12987 static bool wl_is_linkdown(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
)
12989 u32 event
= ntoh32(e
->event_type
);
12990 u16 flags
= ntoh16(e
->flags
);
12992 if (event
== WLC_E_DEAUTH_IND
||
12993 event
== WLC_E_DISASSOC_IND
||
12994 event
== WLC_E_DISASSOC
||
12995 event
== WLC_E_DEAUTH
) {
12996 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event
)));
12998 } else if (event
== WLC_E_LINK
) {
12999 if (!(flags
& WLC_EVENT_MSG_LINK
)) {
13000 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event
)));
13007 #endif /* WL_LASTEVT */
13009 static bool wl_is_nonetwork(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
)
13011 u32 event
= ntoh32(e
->event_type
);
13012 u32 status
= ntoh32(e
->status
);
13014 if (event
== WLC_E_LINK
&& status
== WLC_E_STATUS_NO_NETWORKS
)
13016 if (event
== WLC_E_SET_SSID
&& status
!= WLC_E_STATUS_SUCCESS
)
13022 /* The mainline kernel >= 3.2.0 has support for indicating new/del station
13023 * to AP/P2P GO via events. If this change is backported to kernel for which
13024 * this driver is being built, then define WL_CFG80211_STA_EVENT. You
13025 * should use this new/del sta event mechanism for BRCM supplicant >= 22.
13028 wl_notify_connect_status_ap(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
13029 const wl_event_msg_t
*e
, void *data
)
13032 u32 event
= ntoh32(e
->event_type
);
13033 u32 reason
= ntoh32(e
->reason
);
13034 u32 len
= ntoh32(e
->datalen
);
13035 u32 status
= ntoh32(e
->status
);
13037 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
13038 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
13039 bool isfree
= false;
13041 u8 bsscfgidx
= e
->bsscfgidx
;
13048 struct ieee80211_supported_band
*band
;
13049 struct ether_addr da
;
13050 struct ether_addr bssid
;
13051 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
13053 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
13055 struct station_info sinfo
;
13056 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
13057 #ifdef BIGDATA_SOFTAP
13059 #endif /* BIGDATA_SOFTAP */
13061 WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n",
13062 ndev
->name
, event
, ntoh32(e
->status
), reason
));
13063 /* if link down, bsscfg is disabled. */
13064 if (event
== WLC_E_LINK
&& reason
== WLC_E_LINK_BSSCFG_DIS
&&
13065 wl_get_p2p_status(cfg
, IF_DELETING
) && (ndev
!= bcmcfg_to_prmry_ndev(cfg
))) {
13066 wl_add_remove_eventmsg(ndev
, WLC_E_PROBREQ_MSG
, false);
13067 WL_INFORM_MEM(("AP mode link down !! \n"));
13068 complete(&cfg
->iface_disable
);
13072 if ((event
== WLC_E_LINK
) && (status
== WLC_E_STATUS_SUCCESS
) &&
13073 (reason
== WLC_E_REASON_INITIAL_ASSOC
) &&
13074 (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
)) {
13075 if (!wl_get_drv_status(cfg
, AP_CREATED
, ndev
)) {
13076 /* AP/GO brought up successfull in firmware */
13077 WL_INFORM_MEM(("AP/GO Link up\n"));
13078 wl_set_drv_status(cfg
, AP_CREATED
, ndev
);
13079 wake_up_interruptible(&cfg
->netif_change_event
);
13080 #ifdef BIGDATA_SOFTAP
13081 wl_ap_stainfo_init(cfg
);
13082 #endif /* BIGDATA_SOFTAP */
13084 /* check fakeapscan is in progress, if progress then abort */
13085 wl_android_bcnrecv_stop(ndev
, WL_BCNRECV_CONCURRENCY
);
13086 #endif /* WL_BCNRECV */
13091 if (event
== WLC_E_DISASSOC_IND
|| event
== WLC_E_DEAUTH_IND
|| event
== WLC_E_DEAUTH
) {
13092 WL_DBG(("event %s(%d) status %d reason %d\n",
13093 bcmevent_get_name(event
), event
, ntoh32(e
->status
), reason
));
13096 #ifdef BIGDATA_SOFTAP
13097 if (event
== WLC_E_LINK
&& reason
== WLC_E_LINK_BSSCFG_DIS
) {
13098 WL_ERR(("AP link down - skip get sta data\n"));
13100 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
13101 if (dhdp
&& dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
13102 dhd_schedule_gather_ap_stadata(cfg
, ndev
, e
);
13105 #endif /* BIGDATA_SOFTAP */
13107 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
13108 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
13109 WL_DBG(("Enter \n"));
13110 if (!len
&& (event
== WLC_E_DEAUTH
)) {
13111 len
= 2; /* reason code field */
13115 body
= (u8
*)MALLOCZ(cfg
->osh
, len
);
13116 if (body
== NULL
) {
13117 WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
13121 memset(&bssid
, 0, ETHER_ADDR_LEN
);
13122 WL_DBG(("Enter event %d ndev %p\n", event
, ndev
));
13123 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_INVALID
) {
13124 MFREE(cfg
->osh
, body
, len
);
13128 memcpy(body
, data
, len
);
13130 wldev_iovar_getbuf_bsscfg(ndev
, "cur_etheraddr",
13131 NULL
, 0, ioctl_buf
, sizeof(ioctl_buf
), bsscfgidx
, NULL
);
13132 memcpy(da
.octet
, ioctl_buf
, ETHER_ADDR_LEN
);
13133 memset(&bssid
, 0, sizeof(bssid
));
13134 err
= wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
13136 case WLC_E_ASSOC_IND
:
13139 case WLC_E_REASSOC_IND
:
13140 fc
= FC_REASSOC_REQ
;
13142 case WLC_E_DISASSOC_IND
:
13145 case WLC_E_DEAUTH_IND
:
13155 memset(&ci
, 0, sizeof(ci
));
13156 if ((err
= wldev_ioctl_get(ndev
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
)))) {
13157 MFREE(cfg
->osh
, body
, len
);
13161 channel
= dtoh32(ci
.hw_channel
);
13162 if (channel
<= CH_MAX_2G_CHANNEL
)
13163 band
= wiphy
->bands
[NL80211_BAND_2GHZ
];
13165 band
= wiphy
->bands
[NL80211_BAND_5GHZ
];
13167 WL_ERR(("No valid band"));
13169 MFREE(cfg
->osh
, body
, len
);
13173 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
13174 freq
= ieee80211_channel_to_frequency(channel
);
13177 freq
= ieee80211_channel_to_frequency(channel
, band
->band
);
13180 err
= wl_frame_get_mgmt(cfg
, fc
, &da
, &e
->addr
, &bssid
,
13181 &mgmt_frame
, &len
, body
);
13186 if ((event
== WLC_E_ASSOC_IND
&& reason
== DOT11_SC_SUCCESS
) ||
13187 (event
== WLC_E_DISASSOC_IND
) ||
13188 ((event
== WLC_E_DEAUTH_IND
) || (event
== WLC_E_DEAUTH
))) {
13189 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
13190 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, 0);
13191 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
13192 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, 0, GFP_ATOMIC
);
13193 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
13194 defined(WL_COMPAT_WIRELESS)
13195 cfg80211_rx_mgmt(ndev
, freq
, 0, mgmt_frame
, len
, GFP_ATOMIC
);
13197 cfg80211_rx_mgmt(ndev
, freq
, mgmt_frame
, len
, GFP_ATOMIC
);
13198 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
13203 MFREE(cfg
->osh
, mgmt_frame
, len
);
13206 MFREE(cfg
->osh
, body
, body_len
);
13208 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
13210 if (((event
== WLC_E_ASSOC_IND
) || (event
== WLC_E_REASSOC_IND
)) &&
13211 reason
== DOT11_SC_SUCCESS
) {
13212 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
13213 * STATION_INFO_ASSOC_REQ_IES flag
13215 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
13216 sinfo
.filled
= STA_INFO_BIT(INFO_ASSOC_REQ_IES
);
13217 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
13219 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
13222 sinfo
.assoc_req_ies
= data
;
13223 sinfo
.assoc_req_ies_len
= len
;
13224 WL_INFORM_MEM(("[%s] new sta event for "MACDBG
"\n",
13225 ndev
->name
, MAC2STRDBG(e
->addr
.octet
)));
13226 cfg80211_new_sta(ndev
, e
->addr
.octet
, &sinfo
, GFP_ATOMIC
);
13228 wl_wps_session_update(ndev
, WPS_STATE_LINKUP
, e
->addr
.octet
);
13229 #endif /* WL_WPS_SYNC */
13230 } else if ((event
== WLC_E_DEAUTH_IND
) ||
13231 ((event
== WLC_E_DEAUTH
) && (reason
!= DOT11_RC_RESERVED
)) ||
13232 (event
== WLC_E_DISASSOC_IND
)) {
13233 WL_INFORM_MEM(("[%s] del sta event for "MACDBG
"\n",
13234 ndev
->name
, MAC2STRDBG(e
->addr
.octet
)));
13235 cfg80211_del_sta(ndev
, e
->addr
.octet
, GFP_ATOMIC
);
13237 wl_wps_session_update(ndev
, WPS_STATE_LINKDOWN
, e
->addr
.octet
);
13238 #endif /* WL_WPS_SYNC */
13240 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
13244 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
13246 BIGDATA_ASSOC_REJECT_NO_ACK
= 1,
13247 BIGDATA_ASSOC_REJECT_FAIL
= 2,
13248 BIGDATA_ASSOC_REJECT_UNSOLICITED
= 3,
13249 BIGDATA_ASSOC_REJECT_TIMEOUT
= 4,
13250 BIGDATA_ASSOC_REJECT_ABORT
= 5,
13251 BIGDATA_ASSOC_REJECT_NO_NETWWORKS
= 6,
13252 BIGDATA_ASSOC_REJECT_MAX
= 50
13255 int wl_get_connect_failed_status(struct bcm_cfg80211
*cfg
, const wl_event_msg_t
*e
)
13257 u32 status
= ntoh32(e
->status
);
13259 cfg
->assoc_reject_status
= 0;
13261 if (status
!= WLC_E_STATUS_SUCCESS
) {
13262 WL_ERR(("auth assoc status event=%d e->status %d e->reason %d \n",
13263 ntoh32(cfg
->event_auth_assoc
.event_type
),
13264 (int)ntoh32(cfg
->event_auth_assoc
.status
),
13265 (int)ntoh32(cfg
->event_auth_assoc
.reason
)));
13267 switch ((int)ntoh32(cfg
->event_auth_assoc
.status
)) {
13268 case WLC_E_STATUS_NO_ACK
:
13269 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_NO_ACK
;
13271 case WLC_E_STATUS_FAIL
:
13272 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_FAIL
;
13274 case WLC_E_STATUS_UNSOLICITED
:
13275 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_UNSOLICITED
;
13277 case WLC_E_STATUS_TIMEOUT
:
13278 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_TIMEOUT
;
13280 case WLC_E_STATUS_ABORT
:
13281 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_ABORT
;
13283 case WLC_E_STATUS_SUCCESS
:
13284 if (status
== WLC_E_STATUS_NO_NETWORKS
) {
13285 cfg
->assoc_reject_status
=
13286 BIGDATA_ASSOC_REJECT_NO_NETWWORKS
;
13290 cfg
->assoc_reject_status
= BIGDATA_ASSOC_REJECT_MAX
;
13293 if (cfg
->assoc_reject_status
) {
13294 if (ntoh32(cfg
->event_auth_assoc
.event_type
) == WLC_E_ASSOC
) {
13295 cfg
->assoc_reject_status
+= BIGDATA_ASSOC_REJECT_MAX
;
13300 WL_ERR(("assoc_reject_status %d \n", cfg
->assoc_reject_status
));
13305 s32
wl_cfg80211_get_connect_failed_status(struct net_device
*dev
, char* cmd
, int total_len
)
13307 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
13308 int bytes_written
= 0;
13313 bytes_written
= snprintf(cmd
, total_len
, "assoc_reject.status %d",
13314 cfg
->assoc_reject_status
);
13315 WL_ERR(("cmd: %s \n", cmd
));
13316 return bytes_written
;
13318 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
13321 wl_get_auth_assoc_status(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
13322 const wl_event_msg_t
*e
)
13324 u32 reason
= ntoh32(e
->reason
);
13325 u32 event
= ntoh32(e
->event_type
);
13326 struct wl_security
*sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
13327 WL_DBG(("event type : %d, reason : %d\n", event
, reason
));
13329 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
13330 memcpy(&cfg
->event_auth_assoc
, e
, sizeof(wl_event_msg_t
));
13331 WL_ERR(("event=%d status %d reason %d \n",
13332 ntoh32(cfg
->event_auth_assoc
.event_type
),
13333 ntoh32(cfg
->event_auth_assoc
.status
),
13334 ntoh32(cfg
->event_auth_assoc
.reason
)));
13335 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
13340 sec
->auth_assoc_res_status
= reason
;
13345 WL_ERR(("sec is NULL\n"));
13350 wl_notify_connect_status_ibss(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
13351 const wl_event_msg_t
*e
, void *data
)
13354 u32 event
= ntoh32(e
->event_type
);
13355 u16 flags
= ntoh16(e
->flags
);
13356 u32 status
= ntoh32(e
->status
);
13358 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
13359 struct ieee80211_channel
*channel
= NULL
;
13360 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
13361 u32 chanspec
, chan
;
13363 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13365 if (event
== WLC_E_JOIN
) {
13366 WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev
->name
));
13368 if (event
== WLC_E_START
) {
13369 WL_INFORM_MEM(("[%s] started IBSS network\n", ndev
->name
));
13371 if (event
== WLC_E_JOIN
|| event
== WLC_E_START
||
13372 (event
== WLC_E_LINK
&& (flags
== WLC_EVENT_MSG_LINK
))) {
13373 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
13374 err
= wldev_iovar_getint(ndev
, "chanspec", (s32
*)&chanspec
);
13375 if (unlikely(err
)) {
13376 WL_ERR(("Could not get chanspec %d\n", err
));
13379 chan
= wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec
));
13380 band
= (chan
<= CH_MAX_2G_CHANNEL
) ? NL80211_BAND_2GHZ
: NL80211_BAND_5GHZ
;
13381 freq
= ieee80211_channel_to_frequency(chan
, band
);
13382 channel
= ieee80211_get_channel(wiphy
, freq
);
13383 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13384 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
13385 /* ROAM or Redundant */
13386 u8
*cur_bssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
13387 if (memcmp(cur_bssid
, &e
->addr
, ETHER_ADDR_LEN
) == 0) {
13388 WL_DBG(("IBSS connected event from same BSSID("
13389 MACDBG
"), ignore it\n", MAC2STRDBG(cur_bssid
)));
13392 WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG
" to " MACDBG
"\n",
13393 ndev
->name
, MAC2STRDBG(cur_bssid
),
13394 MAC2STRDBG((const u8
*)&e
->addr
)));
13395 wl_get_assoc_ies(cfg
, ndev
);
13396 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&e
->addr
, WL_PROF_BSSID
);
13397 wl_update_bss_info(cfg
, ndev
, false);
13398 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
13399 cfg80211_ibss_joined(ndev
, (const s8
*)&e
->addr
, channel
, GFP_KERNEL
);
13401 cfg80211_ibss_joined(ndev
, (const s8
*)&e
->addr
, GFP_KERNEL
);
13405 /* New connection */
13406 WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG
"\n",
13407 ndev
->name
, MAC2STRDBG((const u8
*)&e
->addr
)));
13409 wl_get_assoc_ies(cfg
, ndev
);
13410 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&e
->addr
, WL_PROF_BSSID
);
13411 wl_update_bss_info(cfg
, ndev
, false);
13412 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
13413 cfg80211_ibss_joined(ndev
, (const s8
*)&e
->addr
, channel
, GFP_KERNEL
);
13415 cfg80211_ibss_joined(ndev
, (const s8
*)&e
->addr
, GFP_KERNEL
);
13417 wl_set_drv_status(cfg
, CONNECTED
, ndev
);
13419 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&active
, WL_PROF_ACT
);
13421 } else if ((event
== WLC_E_LINK
&& !(flags
& WLC_EVENT_MSG_LINK
)) ||
13422 event
== WLC_E_DEAUTH_IND
|| event
== WLC_E_DISASSOC_IND
) {
13423 wl_clr_drv_status(cfg
, CONNECTED
, ndev
);
13425 wl_init_prof(cfg
, ndev
);
13427 else if (event
== WLC_E_SET_SSID
&& status
== WLC_E_STATUS_NO_NETWORKS
) {
13428 WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
13431 WL_DBG(("no action (IBSS mode)\n"));
13436 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
13437 #define WiFiALL_OUI "\x50\x6F\x9A" /* Wi-FiAll OUI */
13438 #define WiFiALL_OUI_LEN 3
13439 #define WiFiALL_OUI_TYPE 16
13441 /* 11kv feature flag for big data */
13442 #define WL_BIGDATA_11KV_QBSSLOAD 0x00000001
13443 #define WL_BIGDATA_11KV_PROXYARP 0x00000002
13444 #define WL_BIGDATA_11KV_TFS 0x00000004
13445 #define WL_BIGDATA_11KV_SLEEP 0x00000008
13446 #define WL_BIGDATA_11KV_TIMBC 0x00000010
13447 #define WL_BIGDATA_11KV_BSSTRANS 0x00000020
13448 #define WL_BIGDATA_11KV_DMS 0x00000040
13449 #define WL_BIGDATA_11KV_LINK_MEA 0x00000080
13450 #define WL_BIGDATA_11KV_NBRREP 0x00000100
13451 #define WL_BIGDATA_11KV_BCNPASSIVE 0x00000200
13452 #define WL_BIGDATA_11KV_BCNACTIVE 0x00000400
13453 #define WL_BIGDATA_11KV_BCNTABLE 0x00000800
13454 #define WL_BIGDATA_11KV_BSSAAD 0x00001000
13455 #define WL_BIGDATA_11KV_MAX 0x00002000
13457 #define WL_BIGDATA_SUPPORT_11K 0x00000001
13458 #define WL_BIGDATA_SUPPORT_11V 0x00000002
13466 bigdata_11kv_t bigdata_11k_info
[] = {
13467 {DOT11_RRM_CAP_LINK
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_LINK_MEA
},
13468 {DOT11_RRM_CAP_NEIGHBOR_REPORT
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_NBRREP
},
13469 {DOT11_RRM_CAP_BCN_PASSIVE
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_BCNPASSIVE
},
13470 {DOT11_RRM_CAP_BCN_ACTIVE
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_BCNACTIVE
},
13471 {DOT11_RRM_CAP_BCN_TABLE
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_BCNTABLE
},
13472 {DOT11_RRM_CAP_BSSAAD
, DOT11_RRM_CAP_LEN
, WL_BIGDATA_11KV_BSSAAD
},
13475 bigdata_11kv_t bigdata_11v_info
[] = {
13476 {DOT11_EXT_CAP_PROXY_ARP
, DOT11_EXTCAP_LEN_PROXY_ARP
, WL_BIGDATA_11KV_PROXYARP
},
13477 {DOT11_EXT_CAP_TFS
, DOT11_EXTCAP_LEN_TFS
, WL_BIGDATA_11KV_TFS
},
13478 {DOT11_EXT_CAP_WNM_SLEEP
, DOT11_EXTCAP_LEN_WNM_SLEEP
, WL_BIGDATA_11KV_SLEEP
},
13479 {DOT11_EXT_CAP_TIMBC
, DOT11_EXTCAP_LEN_TIMBC
, WL_BIGDATA_11KV_TIMBC
},
13480 {DOT11_EXT_CAP_BSSTRANS_MGMT
, DOT11_EXTCAP_LEN_BSSTRANS
, WL_BIGDATA_11KV_BSSTRANS
},
13481 {DOT11_EXT_CAP_DMS
, DOT11_EXTCAP_LEN_DMS
, WL_BIGDATA_11KV_DMS
}
13485 wl_get_11kv_info(u8
*ie
, u32 ie_len
, uint8
*support_11kv
, uint32
*flag_11kv
)
13487 bcm_tlv_t
*ie_11kv
= NULL
;
13488 uint32 flag_11k
= 0, flag_11v
= 0;
13491 /* parsing QBSS load ie */
13492 if ((bcm_parse_tlvs(ie
, (u32
)ie_len
,
13493 DOT11_MNG_QBSS_LOAD_ID
)) != NULL
) {
13494 flag_11k
|= WL_BIGDATA_11KV_QBSSLOAD
;
13497 /* parsing RM IE for 11k */
13498 if ((ie_11kv
= bcm_parse_tlvs(ie
, (u32
)ie_len
,
13499 DOT11_MNG_RRM_CAP_ID
)) != NULL
) {
13500 for (i
= 0; i
< ARRAYSIZE(bigdata_11k_info
); i
++) {
13501 if ((ie_11kv
->len
>= bigdata_11k_info
[i
].octet_len
) &&
13502 isset(ie_11kv
->data
, bigdata_11k_info
[i
].bitmap
)) {
13503 flag_11k
|= bigdata_11k_info
[i
].flag
;
13508 /* parsing extended cap. IE for 11v */
13509 if ((ie_11kv
= bcm_parse_tlvs(ie
, (u32
)ie_len
,
13510 DOT11_MNG_EXT_CAP_ID
)) != NULL
) {
13511 for (i
= 0; i
< ARRAYSIZE(bigdata_11v_info
); i
++) {
13512 if ((ie_11kv
->len
>= bigdata_11v_info
[i
].octet_len
) &&
13513 isset(ie_11kv
->data
, bigdata_11v_info
[i
].bitmap
)) {
13514 flag_11v
|= bigdata_11v_info
[i
].flag
;
13519 if (flag_11k
> 0) {
13520 *support_11kv
|= WL_BIGDATA_SUPPORT_11K
;
13523 if (flag_11v
> 0) {
13524 *support_11kv
|= WL_BIGDATA_SUPPORT_11V
;
13527 *flag_11kv
= flag_11k
| flag_11v
;
13530 int wl_get_bss_info(struct bcm_cfg80211
*cfg
, struct net_device
*dev
, struct ether_addr
const *mac
)
13534 uint8 eabuf
[ETHER_ADDR_LEN
];
13535 u32 rate
, channel
, freq
, supported_rate
, nss
= 0, mcs_map
, mode_80211
= 0;
13539 struct wiphy
*wiphy
;
13540 struct cfg80211_bss
*bss
;
13541 bcm_tlv_t
*interworking_ie
= NULL
;
13542 bcm_tlv_t
*tlv_ie
= NULL
;
13543 bcm_tlv_t
*vht_ie
= NULL
;
13545 int16 ie_11u_rel_num
= -1, ie_mu_mimo_cap
= -1;
13546 u32 i
, remained_len
, count
= 0;
13547 char roam_count_str
[4], akm_str
[4];
13549 uint8 support_11kv
= 0;
13550 uint32 flag_11kv
= 0; /* bit flags of 11kv big data */
13552 /* get BSS information */
13554 strncpy(cfg
->bss_info
, "x x x x x x x x x x x x x x x", GET_BSS_INFO_LEN
);
13556 *(u32
*) cfg
->extra_buf
= htod32(WL_EXTRA_BUF_MAX
);
13558 err
= wldev_ioctl_get(dev
, WLC_GET_BSS_INFO
, cfg
->extra_buf
, WL_EXTRA_BUF_MAX
);
13559 if (unlikely(err
)) {
13560 WL_ERR(("Could not get bss info %d\n", err
));
13561 cfg
->roam_count
= 0;
13566 WL_ERR(("mac is null \n"));
13567 cfg
->roam_count
= 0;
13571 memcpy(eabuf
, mac
, ETHER_ADDR_LEN
);
13573 bi
= (wl_bss_info_t
*)(cfg
->extra_buf
+ 4);
13574 channel
= wf_chspec_ctlchan(bi
->chanspec
);
13576 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
13577 freq
= ieee80211_channel_to_frequency(channel
);
13579 if (channel
> 14) {
13580 freq
= ieee80211_channel_to_frequency(channel
, NL80211_BAND_5GHZ
);
13582 freq
= ieee80211_channel_to_frequency(channel
, NL80211_BAND_2GHZ
);
13586 err
= wldev_ioctl_get(dev
, WLC_GET_RATE
, &rate
, sizeof(rate
));
13588 WL_ERR(("Could not get rate (%d)\n", err
));
13589 snprintf(rate_str
, sizeof(rate_str
), "x"); // Unknown
13592 rate
= dtoh32(rate
);
13593 snprintf(rate_str
, sizeof(rate_str
), "%d", (rate
/2));
13596 //supported maximum rate
13597 supported_rate
= (bi
->rateset
.rates
[bi
->rateset
.count
- 1] & 0x7f) / 2;
13599 if (supported_rate
< 12) {
13600 mode_80211
= 0; //11b maximum rate is 11Mbps. 11b mode
13602 //It's not HT Capable case.
13603 if (channel
> 14) {
13604 mode_80211
= 3; // 11a mode
13606 mode_80211
= 1; // 11g mode
13611 /* check Rx MCS Map for HT */
13614 for (i
= 0; i
< MAX_STREAMS_SUPPORTED
; i
++) {
13615 int8 bitmap
= 0xFF;
13616 if (i
== MAX_STREAMS_SUPPORTED
-1) {
13619 if (bi
->basic_mcs
[i
] & bitmap
) {
13628 for (i
= 1; i
<= VHT_CAP_MCS_MAP_NSS_MAX
; i
++) {
13629 mcs_map
= VHT_MCS_MAP_GET_MCS_PER_SS(i
, dtoh16(bi
->vht_rxmcsmap
));
13630 if (mcs_map
!= VHT_CAP_MCS_MAP_NONE
) {
13640 wiphy
= bcmcfg_to_wiphy(cfg
);
13641 bss
= CFG80211_GET_BSS(wiphy
, NULL
, eabuf
, bi
->SSID
, bi
->SSID_len
);
13643 WL_ERR(("Could not find the AP\n"));
13645 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
13646 #pragma GCC diagnostic push
13647 #pragma GCC diagnostic ignored "-Wcast-qual"
13649 #if defined(WL_CFG80211_P2P_DEV_IF)
13650 ie
= (u8
*)bss
->ies
->data
;
13651 ie_len
= bss
->ies
->len
;
13653 ie
= bss
->information_elements
;
13654 ie_len
= bss
->len_information_elements
;
13655 #endif /* WL_CFG80211_P2P_DEV_IF */
13656 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
13657 #pragma GCC diagnostic pop
13662 ie_mu_mimo_cap
= 0;
13663 ie_11u_rel_num
= 0;
13666 if ((vht_ie
= bcm_parse_tlvs(ie
, (u32
)ie_len
,
13667 DOT11_MNG_VHT_CAP_ID
)) != NULL
) {
13668 if (vht_ie
->len
>= VHT_CAP_IE_LEN
) {
13669 ie_mu_mimo_cap
= (vht_ie
->data
[2] & 0x08) >> 3;
13674 if ((interworking_ie
= bcm_parse_tlvs(ie
, (u32
)ie_len
,
13675 DOT11_MNG_INTERWORKING_ID
)) != NULL
) {
13676 if ((tlv_ie
= bcm_parse_tlvs(ie
, (u32
)ie_len
, DOT11_MNG_VS_ID
)) != NULL
) {
13677 remained_len
= ie_len
;
13680 if (count
> MAX_VNDR_IE_NUMBER
)
13683 if (tlv_ie
->id
== DOT11_MNG_VS_ID
) {
13684 vndrie
= (vndr_ie_t
*) tlv_ie
;
13686 if (vndrie
->len
< (VNDR_IE_MIN_LEN
+ 1)) {
13687 WL_ERR(("%s: invalid vndr ie."
13688 "length is too small %d\n",
13689 __FUNCTION__
, vndrie
->len
));
13693 if (!bcmp(vndrie
->oui
,
13694 (u8
*)WiFiALL_OUI
, WiFiALL_OUI_LEN
) &&
13695 (vndrie
->data
[0] == WiFiALL_OUI_TYPE
))
13697 WL_ERR(("Found Wi-FiAll OUI oui.\n"));
13698 ie_11u_rel_num
= vndrie
->data
[1];
13699 ie_11u_rel_num
= (ie_11u_rel_num
& 0xf0)>>4;
13700 ie_11u_rel_num
+= 1;
13706 tlv_ie
= bcm_next_tlv(tlv_ie
, &remained_len
);
13711 /* get 11kv information from ie of current bss */
13712 wl_get_11kv_info(ie
, ie_len
, &support_11kv
, &flag_11kv
);
13715 for (i
= 0; i
< bi
->SSID_len
; i
++) {
13716 if (bi
->SSID
[i
] == ' ') {
13721 //0 : None, 1 : OKC, 2 : FT, 3 : CCKM
13722 err
= wldev_iovar_getint(dev
, "wpa_auth", &val
);
13723 if (unlikely(err
)) {
13724 WL_ERR(("could not get wpa_auth (%d)\n", err
));
13725 snprintf(akm_str
, sizeof(akm_str
), "x"); // Unknown
13727 WL_ERR(("wpa_auth val %d \n", val
));
13728 #if defined(BCMCCX) || defined(BCMEXTCCX)
13729 if (val
& (WPA_AUTH_CCKM
| WPA2_AUTH_CCKM
)) {
13730 snprintf(akm_str
, sizeof(akm_str
), "3");
13732 #endif /* BCMCCX || BCMEXTCCX */
13733 if (val
& WPA2_AUTH_FT
) {
13734 snprintf(akm_str
, sizeof(akm_str
), "2");
13735 } else if (val
& (WPA_AUTH_UNSPECIFIED
| WPA2_AUTH_UNSPECIFIED
)) {
13736 snprintf(akm_str
, sizeof(akm_str
), "1");
13738 snprintf(akm_str
, sizeof(akm_str
), "0");
13742 if (cfg
->roam_offload
) {
13743 snprintf(roam_count_str
, sizeof(roam_count_str
), "x"); // Unknown
13745 snprintf(roam_count_str
, sizeof(roam_count_str
), "%d", cfg
->roam_count
);
13747 cfg
->roam_count
= 0;
13749 WL_ERR(("BSSID:" MACDBG
" SSID %s \n", MAC2STRDBG(eabuf
), "*****"));
13750 WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d,"
13751 "MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n"
13752 "akm:%s, roam:%s, 11kv:%d/%d \n",
13753 freq
, wf_chspec_to_bw_str(bi
->chanspec
),
13754 dtoh32(bi
->RSSI
), (rate
/ 2), mode_80211
, nss
,
13755 ie_mu_mimo_cap
, ie_11u_rel_num
, bi
->SNR
, bi
->phy_noise
,
13756 akm_str
, roam_count_str
, support_11kv
, flag_11kv
));
13759 snprintf(cfg
->bss_info
, GET_BSS_INFO_LEN
,
13760 MACOUI
" %d %s %d %s %d %d %d %d %d %d %s %s %d %d",
13761 MACOUI2STR(eabuf
), freq
, wf_chspec_to_bw_str(bi
->chanspec
),
13762 dtoh32(bi
->RSSI
), rate_str
, mode_80211
, nss
, ie_mu_mimo_cap
,
13763 ie_11u_rel_num
, bi
->SNR
, bi
->phy_noise
, akm_str
, roam_count_str
,
13764 support_11kv
, flag_11kv
);
13766 //ie_mu_mimo_cap and ie_11u_rel_num is unknow.
13767 snprintf(cfg
->bss_info
, GET_BSS_INFO_LEN
,
13768 MACOUI
" %d %s %d %s %d %d x x %d %d %s %s x x",
13769 MACOUI2STR(eabuf
), freq
, wf_chspec_to_bw_str(bi
->chanspec
),
13770 dtoh32(bi
->RSSI
), rate_str
, mode_80211
, nss
, bi
->SNR
,
13771 bi
->phy_noise
, akm_str
, roam_count_str
);
13774 CFG80211_PUT_BSS(wiphy
, bss
);
13779 s32
wl_cfg80211_get_bss_info(struct net_device
*dev
, char* cmd
, int total_len
)
13781 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
13787 if (total_len
< GET_BSS_INFO_LEN
) {
13788 WL_ERR(("%s: Buffer insuffient %d\n", __FUNCTION__
, total_len
));
13792 memset(cmd
, 0, total_len
);
13793 memcpy(cmd
, cfg
->bss_info
, GET_BSS_INFO_LEN
);
13795 WL_ERR_KERN(("cmd: %s \n", cmd
));
13797 return GET_BSS_INFO_LEN
;
13799 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
13801 void wl_cfg80211_disassoc(struct net_device
*ndev
)
13806 memset(&scbval
, 0x0, sizeof(scb_val_t
));
13807 scbval
.val
= htod32(WLAN_REASON_DEAUTH_LEAVING
);
13808 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, &scbval
, sizeof(scb_val_t
));
13810 WL_ERR(("WLC_DISASSOC error %d\n", err
));
13814 void wl_cfg80211_del_all_sta(struct net_device
*ndev
, uint32 reason
)
13816 struct net_device
*dev
;
13817 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
13820 char mac_buf
[MAX_NUM_OF_ASSOCIATED_DEV
*
13821 sizeof(struct ether_addr
) + sizeof(uint
)] = {0};
13822 struct maclist
*assoc_maclist
= (struct maclist
*)mac_buf
;
13823 int num_associated
= 0;
13825 dev
= ndev_to_wlc_ndev(ndev
, cfg
);
13827 if (p2p_is_on(cfg
)) {
13828 /* Suspend P2P discovery search-listen to prevent it from changing the
13831 if ((wl_cfgp2p_discover_enable_search(cfg
, false)) < 0) {
13832 WL_ERR(("Can not disable discovery mode\n"));
13837 assoc_maclist
->count
= MAX_NUM_OF_ASSOCIATED_DEV
;
13838 err
= wldev_ioctl_get(ndev
, WLC_GET_ASSOCLIST
,
13839 assoc_maclist
, sizeof(mac_buf
));
13841 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err
));
13843 num_associated
= assoc_maclist
->count
;
13845 memset(scb_val
.ea
.octet
, 0xff, ETHER_ADDR_LEN
);
13846 scb_val
.val
= DOT11_RC_DEAUTH_LEAVING
;
13847 scb_val
.val
= htod32(reason
);
13848 err
= wldev_ioctl_set(dev
, WLC_SCB_DEAUTHENTICATE_FOR_REASON
, &scb_val
,
13849 sizeof(scb_val_t
));
13851 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err
));
13854 if (num_associated
> 0)
13860 wl_notify_connect_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
13861 const wl_event_msg_t
*e
, void *data
)
13864 struct net_device
*ndev
= NULL
;
13866 u32 event
= ntoh32(e
->event_type
);
13867 struct wiphy
*wiphy
= NULL
;
13868 struct cfg80211_bss
*bss
= NULL
;
13869 struct wlc_ssid
*ssid
= NULL
;
13873 int vndr_oui_num
= 0;
13874 char vndr_oui
[MAX_VNDR_OUI_STR_LEN
] = {0, };
13875 bool loc_gen
= false;
13876 #ifdef DHD_LOSSLESS_ROAMING
13877 struct wl_security
*sec
;
13878 #endif /* DHD_LOSSLESS_ROAMING */
13880 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
13881 #ifdef DHD_LOSSLESS_ROAMING
13882 sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
13883 #endif /* DHD_LOSSLESS_ROAMING */
13884 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
13885 BCM_REFERENCE(dhdp
);
13887 mode
= wl_get_mode_by_netdev(cfg
, ndev
);
13888 /* Push link events to upper layer log */
13889 SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n",
13890 ndev
->name
, mode
, ntoh32(e
->event_type
),
13891 ntoh32(e
->status
), ntoh32(e
->reason
)));
13892 if (mode
== WL_MODE_AP
) {
13893 err
= wl_notify_connect_status_ap(cfg
, ndev
, e
, data
);
13894 } else if (mode
== WL_MODE_IBSS
) {
13895 err
= wl_notify_connect_status_ibss(cfg
, ndev
, e
, data
);
13896 } else if (mode
== WL_MODE_BSS
) {
13897 WL_INFORM_MEM(("[%s] Mode BSS. event:%d status:%d reason:%d\n",
13898 ndev
->name
, ntoh32(e
->event_type
),
13899 ntoh32(e
->status
), ntoh32(e
->reason
)));
13901 if (!wl_get_drv_status(cfg
, CFG80211_CONNECT
, ndev
)) {
13902 /* Join attempt via non-cfg80211 interface.
13903 * Don't send resultant events to cfg80211
13906 WL_INFORM_MEM(("Event received in non-cfg80211"
13907 " connect state. Ignore\n"));
13911 if (event
== WLC_E_ASSOC
|| event
== WLC_E_AUTH
) {
13912 wl_get_auth_assoc_status(cfg
, ndev
, e
);
13915 DHD_DISABLE_RUNTIME_PM((dhd_pub_t
*)cfg
->pub
);
13916 if (wl_is_linkup(cfg
, e
, ndev
)) {
13919 if (!wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
13920 WL_INFORM_MEM(("[%s] link up for bssid " MACDBG
"\n",
13921 ndev
->name
, MAC2STRDBG((const u8
*)(&e
->addr
))));
13923 if ((event
== WLC_E_LINK
) &&
13924 (ntoh16(e
->flags
) & WLC_EVENT_MSG_LINK
) &&
13925 !wl_get_drv_status(cfg
, CONNECTED
, ndev
) &&
13926 !wl_get_drv_status(cfg
, CONNECTING
, ndev
)) {
13927 WL_INFORM_MEM(("link up in non-connected/"
13928 "non-connecting state\n"));
13929 wl_cfg80211_disassoc(ndev
);
13934 /* Avoid invocation for Roam cases */
13935 if ((event
== WLC_E_LINK
) &&
13936 !wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
13937 wl_wps_session_update(ndev
,
13938 WPS_STATE_LINKUP
, e
->addr
.octet
);
13940 #endif /* WL_WPS_SYNC */
13942 if (((event
== WLC_E_ROAM
) || (event
== WLC_E_BSSID
)) &&
13943 !wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
13944 /* Roam event in disconnected state. DHD-FW state
13945 * mismatch. Issue disassoc to clear fw state
13947 WL_INFORM_MEM(("Roam even in disconnected state."
13948 " clear fw state\n"));
13949 wl_cfg80211_disassoc(ndev
);
13952 #ifdef DHD_EVENT_LOG_FILTER
13953 if (event
== WLC_E_LINK
&& ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
13955 uint8 eth_addr
[ETHER_ADDR_LEN
];
13957 #ifdef DHD_LOSSLESS_ROAMING
13958 !cfg
->roam_offload
&&
13959 #endif /* DHD_LOSSLESS_ROAMING */
13960 wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
13963 memcpy(eth_addr
, &(e
->addr
), ETHER_ADDR_LEN
);
13964 dhd_event_log_filter_notify_connect_done(dhdp
,
13967 #endif /* DHD_EVENT_LOG_FILTER */
13968 if (event
== WLC_E_LINK
&&
13969 #ifdef DHD_LOSSLESS_ROAMING
13970 !cfg
->roam_offload
&&
13971 !IS_AKM_SUITE_FT(sec
) &&
13972 #endif /* DHD_LOSSLESS_ROAMING */
13973 wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
13974 wl_bss_roaming_done(cfg
, ndev
, e
, data
);
13976 /* Initial Association */
13977 wl_update_prof(cfg
, ndev
, e
, &act
, WL_PROF_ACT
);
13978 wl_bss_connect_done(cfg
, ndev
, e
, data
, true);
13979 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
13980 vndr_oui_num
= wl_vndr_ies_get_vendor_oui(cfg
,
13981 ndev
, vndr_oui
, ARRAY_SIZE(vndr_oui
));
13982 if (vndr_oui_num
> 0) {
13983 WL_INFORM_MEM(("[%s] vendor oui: %s\n",
13984 ndev
->name
, vndr_oui
));
13987 WL_DBG(("joined in BSS network \"%s\"\n",
13988 ((struct wlc_ssid
*)
13989 wl_read_prof(cfg
, ndev
,
13990 WL_PROF_SSID
))->SSID
));
13993 if (ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
&&
13994 dhdp
->wbtext_support
&& event
== WLC_E_SET_SSID
) {
13995 /* set wnm_keepalives_max_idle after association */
13996 wl_cfg80211_wbtext_set_wnm_maxidle(cfg
, ndev
);
13997 /* send nbr request or BTM query to update RCC */
13998 wl_cfg80211_wbtext_update_rcc(cfg
, ndev
);
14000 #endif /* WBTEXT */
14002 wl_update_prof(cfg
, ndev
, e
, &act
, WL_PROF_ACT
);
14003 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&e
->addr
, WL_PROF_BSSID
);
14004 } else if (WL_IS_LINKDOWN(cfg
, e
, data
) ||
14005 ((event
== WLC_E_SET_SSID
) &&
14006 (ntoh32(e
->status
) != WLC_E_STATUS_SUCCESS
) &&
14007 (wl_get_drv_status(cfg
, CONNECTED
, ndev
)))) {
14009 WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n",
14010 wl_get_drv_status(cfg
, CONNECTING
, ndev
),
14011 wl_get_drv_status(cfg
, CONNECTED
, ndev
),
14012 wl_get_drv_status(cfg
, DISCONNECTING
, ndev
),
14013 wl_get_drv_status(cfg
, NESTED_CONNECT
, ndev
)));
14018 if ((event
== WLC_E_SET_SSID
) &&
14019 (ntoh32(e
->status
) != WLC_E_STATUS_SUCCESS
)) {
14021 wps_state
= WPS_STATE_CONNECT_FAIL
;
14023 wps_state
= WPS_STATE_LINKDOWN
;
14025 if (wl_wps_session_update(ndev
,
14026 wps_state
, e
->addr
.octet
) == BCME_UNSUPPORTED
) {
14027 /* Unexpected event. Ignore it. */
14031 #endif /* WL_WPS_SYNC */
14033 if (wl_get_drv_status(cfg
, DISCONNECTING
, ndev
) &&
14034 (wl_get_drv_status(cfg
, NESTED_CONNECT
, ndev
) ||
14035 wl_get_drv_status(cfg
, CONNECTING
, ndev
))) {
14036 /* wl_cfg80211_connect was called before 'DISCONNECTING' was
14037 * cleared. Deauth/Link down event is caused by WLC_DISASSOC
14038 * command issued from the wl_cfg80211_connect context. Ignore
14039 * the event to avoid pre-empting the current connection
14041 WL_DBG(("Nested connection case. Drop event. \n"));
14042 wl_clr_drv_status(cfg
, NESTED_CONNECT
, ndev
);
14043 wl_clr_drv_status(cfg
, DISCONNECTING
, ndev
);
14044 /* Not in 'CONNECTED' state, clear it */
14045 wl_clr_drv_status(cfg
, CONNECTED
, ndev
);
14049 #ifdef DYNAMIC_MUMIMO_CONTROL
14050 wl_set_murx_reassoc_status(cfg
, FALSE
);
14051 wl_set_murx_block_eapol_status(cfg
, FALSE
);
14052 /* Reset default murx_bfe_cap value */
14053 wl_set_murx_bfe_cap(ndev
, 1, FALSE
);
14054 #ifdef ARGOS_CPU_SCHEDULER
14055 argos_config_mumimo_reset();
14056 #endif /* ARGOS_CPU_SCHEDULER */
14057 DHD_ENABLE_RUNTIME_PM(dhdp
);
14058 #endif /* DYNAMIC_MUMIMO_CONTROL */
14060 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg
),
14061 FW_LOGSET_MASK_ALL
);
14062 #ifdef DHD_LOSSLESS_ROAMING
14063 wl_del_roam_timeout(cfg
);
14065 #ifdef P2PLISTEN_AP_SAMECHN
14066 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
14067 wl_cfg80211_set_p2p_resp_ap_chn(ndev
, 0);
14068 cfg
->p2p_resp_apchn_status
= false;
14069 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
14071 #endif /* P2PLISTEN_AP_SAMECHN */
14072 wl_cfg80211_cancel_scan(cfg
);
14074 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
14075 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
14076 wl_get_bss_info(cfg
, ndev
, &e
->addr
);
14078 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
14079 /* Explicitly calling unlink to remove BSS in CFG */
14080 wiphy
= bcmcfg_to_wiphy(cfg
);
14081 ssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, ndev
, WL_PROF_SSID
);
14082 bssid
= (u8
*)wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
14083 if (ssid
&& bssid
) {
14084 bss
= CFG80211_GET_BSS(wiphy
, NULL
, bssid
,
14085 ssid
->SSID
, ssid
->SSID_len
);
14087 cfg80211_unlink_bss(wiphy
, bss
);
14088 CFG80211_PUT_BSS(wiphy
, bss
);
14092 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
14094 u8
*curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
14096 bcm_tlv_t
*deauth_info
= NULL
;
14097 wips_detect_inform_t
*wips_detect_info
;
14098 uint8 wips_bssid
[ETHER_ADDR_LEN
];
14099 u32 len
= ntoh32(e
->datalen
) + TLV_HDR_LEN
;
14101 struct ether_addr bssid_dongle
= {{0, 0, 0, 0, 0, 0}};
14102 struct ether_addr bssid_null
= {{0, 0, 0, 0, 0, 0}};
14104 if (event
== WLC_E_DEAUTH_IND
|| event
== WLC_E_DISASSOC_IND
) {
14105 reason
= ntoh32(e
->reason
);
14106 if (reason
> WLC_E_DEAUTH_MAX_REASON
) {
14107 WL_ERR(("Event %d original reason is %d, "
14108 "changed 0xFF\n", event
, reason
));
14109 reason
= WLC_E_DEAUTH_MAX_REASON
;
14111 if ((deauth_info
= bcm_parse_tlvs(data
, len
,
14112 TAG_DEAUTH_TLV_WIPS
)) != NULL
) {
14114 (wips_detect_inform_t
*)deauth_info
->data
;
14115 memcpy(wips_bssid
, &wips_detect_info
->ea
,
14117 if (wips_detect_info
->misdeauth
> 1) {
14118 WL_ERR(("WIPS attack!! cnt=%d, curRSSI=%d, "
14119 "deauthRSSI=%d, time=%d, "
14121 wips_detect_info
->misdeauth
,
14122 wips_detect_info
->cur_bsscfg_rssi
,
14123 wips_detect_info
->deauth_rssi
,
14124 wips_detect_info
->timestamp
,
14125 MAC2STRDBG(wips_bssid
)));
14129 #ifdef SET_SSID_FAIL_CUSTOM_RC
14130 if (event
== WLC_E_SET_SSID
) {
14131 reason
= SET_SSID_FAIL_CUSTOM_RC
;
14133 #endif /* SET_SSID_FAIL_CUSTOM_RC */
14135 /* roam offload does not sync BSSID always, get it from dongle */
14136 if (cfg
->roam_offload
) {
14137 memset(&bssid_dongle
, 0, sizeof(bssid_dongle
));
14138 if (wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid_dongle
,
14139 sizeof(bssid_dongle
)) == BCME_OK
) {
14140 /* if not roam case, it would return null bssid */
14141 if (memcmp(&bssid_dongle
, &bssid_null
,
14142 ETHER_ADDR_LEN
) != 0) {
14143 curbssid
= (u8
*)&bssid_dongle
;
14147 if (memcmp(curbssid
, &e
->addr
, ETHER_ADDR_LEN
) != 0) {
14148 bool fw_assoc_state
= TRUE
;
14149 dhd_pub_t
*dhd
= (dhd_pub_t
*)cfg
->pub
;
14150 fw_assoc_state
= dhd_is_associated(dhd
, e
->ifidx
, &err
);
14151 if (!fw_assoc_state
) {
14152 WL_ERR(("Event sends up even different BSSID"
14153 " cur: " MACDBG
" event: " MACDBG
"\n",
14154 MAC2STRDBG(curbssid
),
14155 MAC2STRDBG((const u8
*)(&e
->addr
))));
14157 WL_ERR(("BSSID of event is not the connected BSSID"
14158 "(ignore it) cur: " MACDBG
14159 " event: " MACDBG
"\n",
14160 MAC2STRDBG(curbssid
),
14161 MAC2STRDBG((const u8
*)(&e
->addr
))));
14166 /* Stop packet monitor */
14167 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
14168 DHD_DBG_PKT_MON_STOP(dhdp
);
14170 #endif /* DBG_PKT_MON */
14171 /* clear RSSI monitor, framework will set new cfg */
14172 #ifdef RSSI_MONITOR_SUPPORT
14173 dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg
),
14175 #endif /* RSSI_MONITOR_SUPPORT */
14176 wl_clr_drv_status(cfg
, CONNECTED
, ndev
);
14178 if (!wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
14179 /* To make sure disconnect, explictly send dissassoc
14180 * for BSSID 00:00:00:00:00:00 issue
14182 scbval
.val
= WLAN_REASON_DEAUTH_LEAVING
;
14183 WL_INFORM_MEM(("clear fw state\n"));
14184 memcpy(&scbval
.ea
, curbssid
, ETHER_ADDR_LEN
);
14185 scbval
.val
= htod32(scbval
.val
);
14186 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, &scbval
,
14187 sizeof(scb_val_t
));
14189 WL_ERR(("WLC_DISASSOC error %d\n", err
));
14193 if (wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
14196 WL_INFORM_MEM(("[%s] Indicate disconnect event to upper layer. "
14197 "event: %d reason=%d from " MACDBG
"\n",
14198 ndev
->name
, event
, ntoh32(e
->reason
),
14199 MAC2STRDBG((const u8
*)(&e
->addr
))));
14201 /* Send up deauth and clear states */
14202 CFG80211_DISCONNECTED(ndev
, reason
, NULL
, 0,
14203 loc_gen
, GFP_KERNEL
);
14205 wl_init_prof(cfg
, ndev
);
14207 /* when STA was disconnected, clear join pref and set wbtext */
14208 if (ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
&&
14209 dhdp
->wbtext_policy
14210 == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT
) {
14211 char smbuf
[WLC_IOCTL_SMLEN
];
14212 char clear
[] = { 0x01, 0x02, 0x00, 0x00, 0x03,
14213 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
14214 if ((err
= wldev_iovar_setbuf(ndev
, "join_pref",
14215 clear
, sizeof(clear
), smbuf
,
14216 sizeof(smbuf
), NULL
))
14218 if ((err
= wldev_iovar_setint(ndev
,
14219 "wnm_bsstrans_resp",
14220 dhdp
->wbtext_policy
))
14222 wl_cfg80211_wbtext_set_default(ndev
);
14224 WL_ERR(("%s: Failed to set wbtext = %d\n",
14225 __FUNCTION__
, err
));
14228 WL_ERR(("%s: Failed to clear join pref = %d\n",
14229 __FUNCTION__
, err
));
14231 wl_cfg80211_wbtext_clear_bssid_list(cfg
);
14233 #endif /* WBTEXT */
14235 else if (wl_get_drv_status(cfg
, CONNECTING
, ndev
)) {
14236 WL_INFORM_MEM(("link down, during connecting\n"));
14237 /* Issue WLC_DISASSOC to prevent FW roam attempts */
14238 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, NULL
, 0);
14240 WL_ERR(("CONNECTING state, WLC_DISASSOC error %d\n", err
));
14243 WL_DBG(("Clear drv CONNECTING status\n"));
14244 wl_clr_drv_status(cfg
, CONNECTING
, ndev
);
14245 #ifdef ESCAN_RESULT_PATCH
14246 if ((memcmp(connect_req_bssid
, broad_bssid
, ETHER_ADDR_LEN
) == 0) ||
14247 (memcmp(&e
->addr
, broad_bssid
, ETHER_ADDR_LEN
) == 0) ||
14248 (memcmp(&e
->addr
, connect_req_bssid
, ETHER_ADDR_LEN
) == 0))
14249 /* In case this event comes while associating another AP */
14250 #endif /* ESCAN_RESULT_PATCH */
14251 wl_bss_connect_done(cfg
, ndev
, e
, data
, false);
14253 wl_clr_drv_status(cfg
, DISCONNECTING
, ndev
);
14255 /* if link down, bsscfg is diabled */
14256 if (ndev
!= bcmcfg_to_prmry_ndev(cfg
))
14257 complete(&cfg
->iface_disable
);
14259 /* re-enable TDLS if the number of connected interfaces
14262 wl_cfg80211_tdls_config(cfg
, TDLS_STATE_DISCONNECT
, false);
14263 #endif /* WLTDLS */
14264 } else if (wl_is_nonetwork(cfg
, e
)) {
14265 WL_ERR(("connect failed event=%d e->status %d e->reason %d \n",
14266 event
, (int)ntoh32(e
->status
), (int)ntoh32(e
->reason
)));
14268 if (wl_wps_session_update(ndev
,
14269 WPS_STATE_CONNECT_FAIL
, e
->addr
.octet
) == BCME_UNSUPPORTED
) {
14270 /* Unexpected event. Ignore it. */
14273 #endif /* WL_WPS_SYNC */
14274 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
14275 if (event
== WLC_E_SET_SSID
) {
14276 wl_get_connect_failed_status(cfg
, e
);
14278 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
14279 /* Dump FW preserve buffer content */
14280 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
14282 /* Clean up any pending scan request */
14283 wl_cfg80211_cancel_scan(cfg
);
14285 if (wl_get_drv_status(cfg
, CONNECTING
, ndev
)) {
14286 if (!wl_get_drv_status(cfg
, DISCONNECTING
, ndev
)) {
14287 WL_INFORM_MEM(("wl dissassoc\n"));
14288 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, NULL
, 0);
14290 WL_ERR(("WLC_DISASSOC error %d\n", err
));
14294 WL_DBG(("connect fail. clear disconnecting bit\n"));
14295 wl_clr_drv_status(cfg
, DISCONNECTING
, ndev
);
14297 wl_bss_connect_done(cfg
, ndev
, e
, data
, false);
14298 wl_clr_drv_status(cfg
, CONNECTING
, ndev
);
14299 WL_INFORM_MEM(("connect fail reported\n"));
14302 WL_DBG(("%s nothing\n", __FUNCTION__
));
14304 #ifdef DYNAMIC_MUMIMO_CONTROL
14305 if (!wl_get_murx_reassoc_status(cfg
))
14306 #endif /* DYNAMIC_MUMIMO_CONTROL */
14308 DHD_ENABLE_RUNTIME_PM(dhdp
);
14311 WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg
, ndev
)));
14317 void wl_cfg80211_set_rmc_pid(struct net_device
*dev
, int pid
)
14319 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
14321 cfg
->rmc_event_pid
= pid
;
14322 WL_DBG(("set pid for rmc event : pid=%d\n", pid
));
14324 #endif /* WL_RELMCAST */
14327 void wl_cfg80211_set_txfail_pid(struct net_device
*dev
, int pid
)
14329 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
14331 cfg
->aibss_txfail_pid
= pid
;
14332 WL_DBG(("set pid for aibss fail event : pid=%d\n", pid
));
14336 wl_notify_aibss_txfail(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
14337 const wl_event_msg_t
*e
, void *data
)
14339 u32 evt
= ntoh32(e
->event_type
);
14341 #ifdef PCIE_FULL_DONGLE
14342 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
14343 u32 reason
= ntoh32(e
->reason
);
14345 if (cfg
->aibss_txfail_pid
!= 0) {
14346 #ifdef PCIE_FULL_DONGLE
14347 if (reason
== AIBSS_PEER_FREE
) {
14349 wl_event_msg_t event
;
14351 memset(&event
, 0, sizeof(wl_event_msg_t
));
14352 memcpy(&event
, e
, sizeof(wl_event_msg_t
));
14354 ifindex
= (uint8
)dhd_ifname2idx(dhd
->info
, event
.ifname
);
14355 WL_INFORM_MEM(("Peer freed. Flow rings delete for peer.\n"));
14356 dhd_flow_rings_delete_for_peer(dhd
, ifindex
,
14357 (void *)&event
.addr
.octet
[0]);
14361 ret
= wl_netlink_send_msg(cfg
->aibss_txfail_pid
, AIBSS_EVENT_TXFAIL
,
14362 cfg
->aibss_txfail_seq
++, &e
->addr
, ETHER_ADDR_LEN
);
14365 WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF
"\n",
14366 evt
, cfg
->aibss_txfail_pid
, ret
, CONST_ETHERP_TO_MACF(&e
->addr
)));
14369 #endif /* WLAIBSS */
14372 wl_notify_rmc_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
14373 const wl_event_msg_t
*e
, void *data
)
14375 u32 evt
= ntoh32(e
->event_type
);
14376 u32 reason
= ntoh32(e
->reason
);
14380 case WLC_E_REASON_RMC_AR_LOST
:
14381 case WLC_E_REASON_RMC_AR_NO_ACK
:
14382 if (cfg
->rmc_event_pid
!= 0) {
14383 ret
= wl_netlink_send_msg(cfg
->rmc_event_pid
,
14384 RMC_EVENT_LEADER_CHECK_FAIL
,
14385 cfg
->rmc_event_seq
++, NULL
, 0);
14391 WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt
, cfg
->rmc_event_pid
, ret
));
14394 #endif /* WL_RELMCAST */
14396 #ifdef GSCAN_SUPPORT
14398 wl_handle_roam_exp_event(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
14399 const wl_event_msg_t
*e
, void *data
)
14401 struct net_device
*ndev
= NULL
;
14402 u32 datalen
= be32_to_cpu(e
->datalen
);
14405 wl_roam_exp_event_t
*evt_data
= (wl_roam_exp_event_t
*)data
;
14406 if (evt_data
->version
== ROAM_EXP_EVENT_VERSION
) {
14407 wlc_ssid_t
*ssid
= &evt_data
->cur_ssid
;
14408 struct wireless_dev
*wdev
;
14409 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
14411 wdev
= ndev
->ieee80211_ptr
;
14412 wdev
->ssid_len
= min(ssid
->SSID_len
, (uint32
)DOT11_MAX_SSID_LEN
);
14413 memcpy(wdev
->ssid
, ssid
->SSID
, wdev
->ssid_len
);
14414 WL_ERR(("SSID is %s\n", ssid
->SSID
));
14415 wl_update_prof(cfg
, ndev
, NULL
, ssid
, WL_PROF_SSID
);
14417 WL_ERR(("NULL ndev!\n"));
14420 WL_ERR(("Version mismatch %d, expected %d", evt_data
->version
,
14421 ROAM_EXP_EVENT_VERSION
));
14426 #endif /* GSCAN_SUPPORT */
14428 #ifdef RSSI_MONITOR_SUPPORT
14429 static s32
wl_handle_rssi_monitor_event(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
14430 const wl_event_msg_t
*e
, void *data
)
14433 #if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
14434 u32 datalen
= be32_to_cpu(e
->datalen
);
14435 struct net_device
*ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
14436 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
14439 wl_rssi_monitor_evt_t
*evt_data
= (wl_rssi_monitor_evt_t
*)data
;
14440 if (evt_data
->version
== RSSI_MONITOR_VERSION
) {
14441 dhd_rssi_monitor_evt_t monitor_data
;
14442 monitor_data
.version
= DHD_RSSI_MONITOR_EVT_VERSION
;
14443 monitor_data
.cur_rssi
= evt_data
->cur_rssi
;
14444 memcpy(&monitor_data
.BSSID
, &e
->addr
, ETHER_ADDR_LEN
);
14445 wl_cfgvendor_send_async_event(wiphy
, ndev
,
14446 GOOGLE_RSSI_MONITOR_EVENT
,
14447 &monitor_data
, sizeof(monitor_data
));
14449 WL_ERR(("Version mismatch %d, expected %d", evt_data
->version
,
14450 RSSI_MONITOR_VERSION
));
14453 #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
14456 #endif /* RSSI_MONITOR_SUPPORT */
14459 wl_notify_roaming_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
14460 const wl_event_msg_t
*e
, void *data
)
14463 struct net_device
*ndev
= NULL
;
14465 u32 event
= be32_to_cpu(e
->event_type
);
14466 u32 status
= be32_to_cpu(e
->status
);
14467 #ifdef DHD_LOSSLESS_ROAMING
14468 struct wl_security
*sec
;
14470 #if defined(WBTEXT)
14471 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
14472 #endif /* WBTEXT */
14473 WL_DBG(("Enter \n"));
14475 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
14477 if ((!cfg
->disable_roam_event
) && (event
== WLC_E_BSSID
)) {
14478 wl_add_remove_eventmsg(ndev
, WLC_E_ROAM
, false);
14479 cfg
->disable_roam_event
= TRUE
;
14482 if ((cfg
->disable_roam_event
) && (event
== WLC_E_ROAM
))
14485 if ((event
== WLC_E_ROAM
|| event
== WLC_E_BSSID
) && status
== WLC_E_STATUS_SUCCESS
) {
14486 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
14487 #ifdef DHD_LOSSLESS_ROAMING
14488 sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
14489 /* In order to reduce roaming delay, wl_bss_roaming_done is
14490 * early called with WLC_E_LINK event. It is called from
14491 * here only if WLC_E_LINK event is blocked for specific
14494 if (IS_AKM_SUITE_FT(sec
)) {
14495 wl_bss_roaming_done(cfg
, ndev
, e
, data
);
14497 /* Roam timer is deleted mostly from wl_cfg80211_change_station
14498 * after roaming is finished successfully. We need to delete
14499 * the timer from here only for some security types that aren't
14500 * using wl_cfg80211_change_station to authorize SCB
14502 if (IS_AKM_SUITE_FT(sec
) || IS_AKM_SUITE_CCKM(sec
)) {
14503 wl_del_roam_timeout(cfg
);
14506 wl_bss_roaming_done(cfg
, ndev
, e
, data
);
14507 #endif /* DHD_LOSSLESS_ROAMING */
14509 if (dhdp
->wbtext_support
) {
14510 /* set wnm_keepalives_max_idle after association */
14511 wl_cfg80211_wbtext_set_wnm_maxidle(cfg
, ndev
);
14512 /* send nbr request or BTM query to update RCC
14513 * after roaming completed (receiving the first beacon)
14515 wl_cfg80211_wbtext_update_rcc(cfg
, ndev
);
14517 #endif /* WBTEXT */
14519 wl_bss_connect_done(cfg
, ndev
, e
, data
, true);
14522 wl_update_prof(cfg
, ndev
, e
, &act
, WL_PROF_ACT
);
14523 wl_update_prof(cfg
, ndev
, NULL
, (const void *)&e
->addr
, WL_PROF_BSSID
);
14525 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
14526 wl_vndr_ies_get_vendor_oui(cfg
, ndev
, NULL
, 0);
14529 #ifdef DHD_LOSSLESS_ROAMING
14530 else if ((event
== WLC_E_ROAM
|| event
== WLC_E_BSSID
) && status
!= WLC_E_STATUS_SUCCESS
) {
14531 wl_del_roam_timeout(cfg
);
14537 #ifdef CUSTOM_EVENT_PM_WAKE
14538 uint32 last_dpm_upd_time
= 0; /* ms */
14539 #define DPM_UPD_LMT_TIME (CUSTOM_EVENT_PM_WAKE + 5) * 1000 * 4 /* ms */
14540 #define DPM_UPD_LMT_RSSI -85 /* dbm */
14543 wl_check_pmstatus(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
14544 const wl_event_msg_t
*e
, void *data
)
14547 struct net_device
*ndev
= NULL
;
14549 uint32 cur_dpm_upd_time
= 0;
14550 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
14552 #ifdef SUPPORT_RSSI_SUM_REPORT
14553 wl_rssi_ant_mimo_t rssi_ant_mimo
;
14554 #endif /* SUPPORT_RSSI_SUM_REPORT */
14555 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
14557 pbuf
= (u8
*)MALLOCZ(cfg
->osh
, WLC_IOCTL_MEDLEN
);
14558 if (pbuf
== NULL
) {
14559 WL_ERR(("failed to allocate local pbuf\n"));
14563 err
= wldev_iovar_getbuf_bsscfg(ndev
, "dump",
14564 "pm", strlen("pm"), pbuf
, WLC_IOCTL_MEDLEN
, 0, &cfg
->ioctl_buf_sync
);
14567 WL_ERR(("dump ioctl err = %d", err
));
14569 WL_ERR(("PM status : %s\n", pbuf
));
14573 MFREE(cfg
->osh
, pbuf
, WLC_IOCTL_MEDLEN
);
14576 if (dhd
->early_suspended
) {
14578 #ifdef SUPPORT_RSSI_SUM_REPORT
14579 /* Query RSSI sum across antennas */
14580 memset(&rssi_ant_mimo
, 0, sizeof(rssi_ant_mimo
));
14581 err
= wl_get_rssi_per_ant(ndev
, ndev
->name
, NULL
, &rssi_ant_mimo
);
14583 WL_ERR(("Could not get rssi sum (%d)\n", err
));
14585 rssi
= rssi_ant_mimo
.rssi_sum
;
14587 #endif /* SUPPORT_RSSI_SUM_REPORT */
14590 memset(&scb_val
, 0, sizeof(scb_val_t
));
14592 err
= wldev_ioctl_get(ndev
, WLC_GET_RSSI
, &scb_val
, sizeof(scb_val_t
));
14594 WL_ERR(("Could not get rssi (%d)\n", err
));
14596 rssi
= wl_rssi_offset(dtoh32(scb_val
.val
));
14598 WL_ERR(("RSSI %d dBm\n", rssi
));
14599 if (rssi
> DPM_UPD_LMT_RSSI
) {
14607 if (last_dpm_upd_time
== 0) {
14608 last_dpm_upd_time
= OSL_SYSUPTIME();
14610 cur_dpm_upd_time
= OSL_SYSUPTIME();
14611 if (cur_dpm_upd_time
- last_dpm_upd_time
< DPM_UPD_LMT_TIME
) {
14613 bzero(&scbval
, sizeof(scb_val_t
));
14615 err
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, &scbval
, sizeof(scb_val_t
));
14617 WL_ERR(("%s: Disassoc error %d\n", __FUNCTION__
, err
));
14620 WL_ERR(("%s: Force Disassoc due to updated DPM event.\n", __FUNCTION__
));
14622 last_dpm_upd_time
= 0;
14624 last_dpm_upd_time
= cur_dpm_upd_time
;
14630 #endif /* CUSTOM_EVENT_PM_WAKE */
14633 /* get user priority table */
14635 wl_get_up_table(dhd_pub_t
* dhdp
, int idx
)
14637 struct net_device
*ndev
;
14638 struct bcm_cfg80211
*cfg
;
14640 ndev
= dhd_idx2net(dhdp
, idx
);
14642 cfg
= wl_get_cfg(ndev
);
14644 return (uint8
*)(cfg
->up_table
);
14649 #endif /* QOS_MAP_SET */
14651 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
14653 wl_notify_roam_prep_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
14654 const wl_event_msg_t
*e
, void *data
)
14656 struct wl_security
*sec
;
14657 struct net_device
*ndev
;
14658 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
14659 u32 status
= ntoh32(e
->status
);
14660 u32 reason
= ntoh32(e
->reason
);
14662 BCM_REFERENCE(sec
);
14664 if (status
== WLC_E_STATUS_SUCCESS
&& reason
!= WLC_E_REASON_INITIAL_ASSOC
) {
14665 WL_ERR(("Attempting roam with reason code : %d\n", reason
));
14668 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
14671 if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
14672 DHD_DBG_PKT_MON_STOP(dhdp
);
14673 DHD_DBG_PKT_MON_START(dhdp
);
14675 #endif /* DBG_PKT_MON */
14676 #ifdef DHD_LOSSLESS_ROAMING
14677 sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
14678 /* Disable Lossless Roaming for specific AKM suite
14679 * Any other AKM suite can be added below if transition time
14680 * is delayed because of Lossless Roaming
14681 * and it causes any certication failure
14683 if (IS_AKM_SUITE_FT(sec
)) {
14687 dhdp
->dequeue_prec_map
= 1 << PRIO_8021D_NC
;
14688 #ifdef DYNAMIC_MUMIMO_CONTROL
14689 if (!wl_get_murx_reassoc_status(cfg
))
14690 #endif /* DYNAMIC_MUMIMO_CONTROL */
14692 /* Restore flow control */
14693 dhd_txflowcontrol(dhdp
, ALL_INTERFACES
, OFF
);
14696 mod_timer(&cfg
->roam_timeout
, jiffies
+ msecs_to_jiffies(WL_ROAM_TIMEOUT_MS
));
14697 #endif /* DHD_LOSSLESS_ROAMING */
14701 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
14704 wl_notify_roam_start_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
14705 const wl_event_msg_t
*e
, void *data
)
14707 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
14708 struct net_device
*ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
14709 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
14712 event_type
= WIFI_EVENT_ROAM_SCAN_STARTED
;
14713 wl_cfgvendor_send_async_event(wiphy
, ndev
, GOOGLE_ROAM_EVENT_START
,
14714 &event_type
, sizeof(int));
14715 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || (WL_VENDOR_EXT_SUPPORT) */
14720 static s32
wl_get_assoc_ies(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
14722 wl_assoc_info_t assoc_info
;
14723 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
14726 bcm_tlv_t
* qos_map_ie
= NULL
;
14727 #endif /* QOS_MAP_SET */
14729 WL_DBG(("Enter \n"));
14730 err
= wldev_iovar_getbuf(ndev
, "assoc_info", NULL
, 0, cfg
->extra_buf
,
14731 WL_ASSOC_INFO_MAX
, NULL
);
14732 if (unlikely(err
)) {
14733 WL_ERR(("could not get assoc info (%d)\n", err
));
14736 memcpy(&assoc_info
, cfg
->extra_buf
, sizeof(wl_assoc_info_t
));
14737 assoc_info
.req_len
= htod32(assoc_info
.req_len
);
14738 assoc_info
.resp_len
= htod32(assoc_info
.resp_len
);
14739 assoc_info
.flags
= htod32(assoc_info
.flags
);
14741 if (assoc_info
.req_len
> (MAX_REQ_LINE
+ sizeof(struct dot11_assoc_req
) +
14742 ((assoc_info
.flags
& WLC_ASSOC_REQ_IS_REASSOC
) ? ETHER_ADDR_LEN
: 0))) {
14746 if ((assoc_info
.req_len
> 0) &&
14747 (assoc_info
.req_len
< (sizeof(struct dot11_assoc_req
) +
14748 ((assoc_info
.flags
& WLC_ASSOC_REQ_IS_REASSOC
) ? ETHER_ADDR_LEN
: 0)))) {
14752 if (assoc_info
.resp_len
> (MAX_REQ_LINE
+ sizeof(struct dot11_assoc_resp
))) {
14756 if ((assoc_info
.resp_len
> 0) && (assoc_info
.resp_len
< sizeof(struct dot11_assoc_resp
))) {
14761 if (conn_info
->req_ie_len
) {
14762 conn_info
->req_ie_len
= 0;
14763 bzero(conn_info
->req_ie
, sizeof(conn_info
->req_ie
));
14765 if (conn_info
->resp_ie_len
) {
14766 conn_info
->resp_ie_len
= 0;
14767 bzero(conn_info
->resp_ie
, sizeof(conn_info
->resp_ie
));
14770 if (assoc_info
.req_len
) {
14771 err
= wldev_iovar_getbuf(ndev
, "assoc_req_ies", NULL
, 0, cfg
->extra_buf
,
14772 assoc_info
.req_len
, NULL
);
14773 if (unlikely(err
)) {
14774 WL_ERR(("could not get assoc req (%d)\n", err
));
14777 if (assoc_info
.req_len
< sizeof(struct dot11_assoc_req
)) {
14778 WL_ERR(("req_len %d lessthan %d \n", assoc_info
.req_len
,
14779 (int)sizeof(struct dot11_assoc_req
)));
14780 return BCME_BADLEN
;
14782 conn_info
->req_ie_len
= (uint32
)(assoc_info
.req_len
14783 - sizeof(struct dot11_assoc_req
));
14784 if (assoc_info
.flags
& WLC_ASSOC_REQ_IS_REASSOC
) {
14785 conn_info
->req_ie_len
-= ETHER_ADDR_LEN
;
14787 memcpy(conn_info
->req_ie
, cfg
->extra_buf
, conn_info
->req_ie_len
);
14790 if (assoc_info
.resp_len
) {
14791 err
= wldev_iovar_getbuf(ndev
, "assoc_resp_ies", NULL
, 0, cfg
->extra_buf
,
14792 assoc_info
.resp_len
, NULL
);
14793 if (unlikely(err
)) {
14794 WL_ERR(("could not get assoc resp (%d)\n", err
));
14797 if (assoc_info
.resp_len
< sizeof(struct dot11_assoc_resp
)) {
14798 WL_ERR(("resp_len %d is lessthan %d \n", assoc_info
.resp_len
,
14799 (int)sizeof(struct dot11_assoc_resp
)));
14801 conn_info
->resp_ie_len
= assoc_info
.resp_len
-
14802 (uint32
)sizeof(struct dot11_assoc_resp
);
14803 memcpy(conn_info
->resp_ie
, cfg
->extra_buf
, conn_info
->resp_ie_len
);
14805 /* find qos map set ie */
14806 if ((qos_map_ie
= bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
14807 DOT11_MNG_QOS_MAP_ID
)) != NULL
) {
14808 WL_DBG((" QoS map set IE found in assoc response\n"));
14809 if (!cfg
->up_table
) {
14810 cfg
->up_table
= (uint8
*)MALLOC(cfg
->osh
, UP_TABLE_MAX
);
14812 wl_set_up_table(cfg
->up_table
, qos_map_ie
);
14814 MFREE(cfg
->osh
, cfg
->up_table
, UP_TABLE_MAX
);
14815 cfg
->up_table
= NULL
;
14817 #endif /* QOS_MAP_SET */
14822 WL_ERR(("err:%d, assoc_info-req:%u,resp:%u conn_info-req:%u,resp:%u\n",
14823 err
, assoc_info
.req_len
, assoc_info
.resp_len
,
14824 conn_info
->req_ie_len
, conn_info
->resp_ie_len
));
14829 static s32
wl_ch_to_chanspec(struct net_device
*dev
, int ch
, struct wl_join_params
*join_params
,
14830 size_t *join_params_size
)
14832 chanspec_t chanspec
= 0, chspec
;
14833 struct bcm_cfg80211
*cfg
=
14834 (struct bcm_cfg80211
*)wiphy_priv(dev
->ieee80211_ptr
->wiphy
);
14836 if ((ch
!= 0) && (cfg
&& !cfg
->rcc_enabled
)) {
14837 join_params
->params
.chanspec_num
= 1;
14838 join_params
->params
.chanspec_list
[0] = ch
;
14840 if (join_params
->params
.chanspec_list
[0] <= CH_MAX_2G_CHANNEL
)
14841 chanspec
|= WL_CHANSPEC_BAND_2G
;
14843 chanspec
|= WL_CHANSPEC_BAND_5G
;
14845 /* Get the min_bw set for the interface */
14846 chspec
= WL_CHANSPEC_BW_20
;
14847 if (chspec
== INVCHANSPEC
) {
14848 WL_ERR(("Invalid chanspec \n"));
14851 chanspec
|= chspec
;
14852 chanspec
|= WL_CHANSPEC_CTL_SB_NONE
;
14854 *join_params_size
+= WL_ASSOC_PARAMS_FIXED_SIZE
+
14855 join_params
->params
.chanspec_num
* sizeof(chanspec_t
);
14857 join_params
->params
.chanspec_list
[0] &= WL_CHANSPEC_CHAN_MASK
;
14858 join_params
->params
.chanspec_list
[0] |= chanspec
;
14859 join_params
->params
.chanspec_list
[0] =
14860 wl_chspec_host_to_driver(join_params
->params
.chanspec_list
[0]);
14862 join_params
->params
.chanspec_num
=
14863 htod32(join_params
->params
.chanspec_num
);
14865 #ifdef ESCAN_CHANNEL_CACHE
14867 /* If channel is not present and ESCAN_CHANNEL_CACHE is enabled,
14868 * use the cached channel list
14871 n_channels
= get_roam_channel_list(ch
, join_params
->params
.chanspec_list
,
14872 MAX_ROAM_CHANNEL
, &join_params
->ssid
, ioctl_version
);
14873 join_params
->params
.chanspec_num
= htod32(n_channels
);
14874 *join_params_size
+= WL_ASSOC_PARAMS_FIXED_SIZE
+
14875 join_params
->params
.chanspec_num
* sizeof(chanspec_t
);
14877 #endif /* ESCAN_CHANNEL_CACHE */
14879 WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
14880 join_params
->params
.chanspec_list
[0],
14881 join_params
->params
.chanspec_num
));
14885 static s32
wl_update_bss_info(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, bool roam
)
14887 struct cfg80211_bss
*bss
;
14889 struct wlc_ssid
*ssid
;
14890 const struct bcm_tlv
*tim
;
14891 s32 beacon_interval
;
14897 struct wiphy
*wiphy
;
14902 wiphy
= bcmcfg_to_wiphy(cfg
);
14904 ssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, ndev
, WL_PROF_SSID
);
14905 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
14906 bss
= CFG80211_GET_BSS(wiphy
, NULL
, curbssid
,
14907 ssid
->SSID
, ssid
->SSID_len
);
14908 buf
= (char *)MALLOCZ(cfg
->osh
, WL_EXTRA_BUF_MAX
);
14910 WL_ERR(("buffer alloc failed.\n"));
14913 mutex_lock(&cfg
->usr_sync
);
14914 *(u32
*)buf
= htod32(WL_EXTRA_BUF_MAX
);
14915 err
= wldev_ioctl_get(ndev
, WLC_GET_BSS_INFO
, buf
, WL_EXTRA_BUF_MAX
);
14916 if (unlikely(err
)) {
14917 WL_ERR(("Could not get bss info %d\n", err
));
14918 goto update_bss_info_out
;
14920 bi
= (wl_bss_info_t
*)(buf
+ 4);
14921 channel
= wf_chspec_ctlchan(wl_chspec_driver_to_host(bi
->chanspec
));
14922 wl_update_prof(cfg
, ndev
, NULL
, &channel
, WL_PROF_CHAN
);
14925 WL_DBG(("Could not find the AP\n"));
14926 if (memcmp(bi
->BSSID
.octet
, curbssid
, ETHER_ADDR_LEN
)) {
14927 WL_ERR(("Bssid doesn't match\n"));
14929 goto update_bss_info_out
;
14931 err
= wl_inform_single_bss(cfg
, bi
, roam
);
14933 goto update_bss_info_out
;
14935 ie
= ((u8
*)bi
) + bi
->ie_offset
;
14936 ie_len
= bi
->ie_length
;
14937 beacon_interval
= cpu_to_le16(bi
->beacon_period
);
14939 WL_DBG(("Found the AP in the list - BSSID %pM\n", bss
->bssid
));
14940 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
14941 freq
= ieee80211_channel_to_frequency(channel
);
14943 band
= (channel
<= CH_MAX_2G_CHANNEL
) ? NL80211_BAND_2GHZ
: NL80211_BAND_5GHZ
;
14944 freq
= ieee80211_channel_to_frequency(channel
, band
);
14946 bss
->channel
= ieee80211_get_channel(wiphy
, freq
);
14947 #if defined(WL_CFG80211_P2P_DEV_IF)
14948 ie
= (const u8
*)bss
->ies
->data
;
14949 ie_len
= bss
->ies
->len
;
14951 ie
= bss
->information_elements
;
14952 ie_len
= bss
->len_information_elements
;
14953 #endif /* WL_CFG80211_P2P_DEV_IF */
14954 beacon_interval
= bss
->beacon_interval
;
14956 CFG80211_PUT_BSS(wiphy
, bss
);
14959 tim
= bcm_parse_tlvs(ie
, ie_len
, WLAN_EID_TIM
);
14961 dtim_period
= tim
->data
[1];
14964 * active scan was done so we could not get dtim
14965 * information out of probe response.
14966 * so we speficially query dtim information.
14969 err
= wldev_ioctl_get(ndev
, WLC_GET_DTIMPRD
,
14970 &dtim_period
, sizeof(dtim_period
));
14971 if (unlikely(err
)) {
14972 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err
));
14973 goto update_bss_info_out
;
14977 wl_update_prof(cfg
, ndev
, NULL
, &beacon_interval
, WL_PROF_BEACONINT
);
14978 wl_update_prof(cfg
, ndev
, NULL
, &dtim_period
, WL_PROF_DTIMPERIOD
);
14980 update_bss_info_out
:
14981 if (unlikely(err
)) {
14982 WL_ERR(("Failed with error %d\n", err
));
14985 MFREE(cfg
->osh
, buf
, WL_EXTRA_BUF_MAX
);
14986 mutex_unlock(&cfg
->usr_sync
);
14991 wl_bss_roaming_done(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
14992 const wl_event_msg_t
*e
, void *data
)
14994 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
14999 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15000 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
15001 struct ieee80211_supported_band
*band
;
15002 struct ieee80211_channel
*notify_channel
= NULL
;
15004 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
15005 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
15006 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
15007 struct cfg80211_roam_info roam_info
;
15008 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
15010 uint32 data_len
= 0;
15012 data_len
= ntoh32(e
->datalen
);
15015 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
15016 channel
= (u32
*)wl_read_prof(cfg
, ndev
, WL_PROF_CHAN
);
15018 if ((err
= wl_get_assoc_ies(cfg
, ndev
)) != BCME_OK
) {
15019 WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
15020 " upper layer\n"));
15021 /* To make sure disconnect, and fw sync, explictly send dissassoc
15022 * for BSSID 00:00:00:00:00:00 issue
15024 memset(&scbval
, 0, sizeof(scb_val_t
));
15025 scbval
.val
= WLAN_REASON_DEAUTH_LEAVING
;
15026 memcpy(&scbval
.ea
, curbssid
, ETHER_ADDR_LEN
);
15027 scbval
.val
= htod32(scbval
.val
);
15028 if (wldev_ioctl_set(ndev
, WLC_DISASSOC
, &scbval
,
15029 sizeof(scb_val_t
)) < 0) {
15030 WL_ERR(("WLC_DISASSOC error\n"));
15035 wl_update_prof(cfg
, ndev
, NULL
, (const void *)(e
->addr
.octet
), WL_PROF_BSSID
);
15036 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
15037 if ((err
= wl_update_bss_info(cfg
, ndev
, true)) != BCME_OK
) {
15038 WL_ERR(("failed to update bss info, err=%d\n", err
));
15041 wl_update_pmklist(ndev
, cfg
->pmk_list
, err
);
15043 channel
= (u32
*)wl_read_prof(cfg
, ndev
, WL_PROF_CHAN
);
15044 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15045 /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
15046 if (*channel
<= CH_MAX_2G_CHANNEL
)
15047 band
= wiphy
->bands
[NL80211_BAND_2GHZ
];
15049 band
= wiphy
->bands
[NL80211_BAND_5GHZ
];
15050 freq
= ieee80211_channel_to_frequency(*channel
, band
->band
);
15051 notify_channel
= ieee80211_get_channel(wiphy
, freq
);
15052 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
15054 /* back up the given FBT key for the further supplicant request,
15055 * currently not checking the FBT is enabled for current BSS in DHD,
15056 * because the supplicant decides to take it or not.
15058 if (data
&& (data_len
== FBT_KEYLEN
)) {
15059 memcpy(cfg
->fbt_key
, data
, FBT_KEYLEN
);
15062 #ifdef CUSTOM_LONG_RETRY_LIMIT
15063 if (wl_set_retry(ndev
, CUSTOM_LONG_RETRY_LIMIT
, 1) < 0) {
15064 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
15066 #endif /* CUSTOM_LONG_RETRY_LIMIT */
15067 WL_ERR(("Report roam event to upper layer. " MACDBG
" (ch:%d)\n",
15068 MAC2STRDBG((const u8
*)(&e
->addr
)), *channel
));
15070 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
15071 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
15072 memset(&roam_info
, 0, sizeof(struct cfg80211_roam_info
));
15073 roam_info
.channel
= notify_channel
;
15074 roam_info
.bssid
= curbssid
;
15075 roam_info
.req_ie
= conn_info
->req_ie
;
15076 roam_info
.req_ie_len
= conn_info
->req_ie_len
;
15077 roam_info
.resp_ie
= conn_info
->resp_ie
;
15078 roam_info
.resp_ie_len
= conn_info
->resp_ie_len
;
15080 cfg80211_roamed(ndev
, &roam_info
, GFP_KERNEL
);
15082 cfg80211_roamed(ndev
,
15083 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15087 conn_info
->req_ie
, conn_info
->req_ie_len
,
15088 conn_info
->resp_ie
, conn_info
->resp_ie_len
, GFP_KERNEL
);
15089 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
15091 memcpy(&cfg
->last_roamed_addr
, &e
->addr
, ETHER_ADDR_LEN
);
15092 wl_set_drv_status(cfg
, CONNECTED
, ndev
);
15094 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
15095 #ifdef DYNAMIC_MUMIMO_CONTROL
15096 if (!wl_get_murx_reassoc_status(cfg
))
15097 #endif /* DYNAMIC_MUMIMO_CONTROL */
15101 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
15103 #ifdef DYNAMIC_MUMIMO_CONTROL
15104 if (wl_get_murx_reassoc_status(cfg
)) {
15105 struct wl_security
*sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
15106 bool sec_wpa
= sec
? (sec
->wpa_versions
&
15107 (NL80211_WPA_VERSION_1
| NL80211_WPA_VERSION_2
)) : FALSE
;
15108 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
15110 wl_set_murx_reassoc_status(cfg
, FALSE
);
15111 WL_DBG(("Security is not WPA nor WPA2\n"));
15113 WL_DBG(("Security is WPA or WPA2\n"));
15115 wl_set_murx_block_eapol_status(cfg
, FALSE
);
15116 dhd_txflowcontrol(dhdp
, ALL_INTERFACES
, OFF
);
15118 #endif /* DYNAMIC_MUMIMO_CONTROL */
15121 if (wl_adps_bad_ap_check(cfg
, &e
->addr
)) {
15122 if (wl_adps_enabled(cfg
, ndev
)) {
15123 wl_adps_set_suspend(cfg
, ndev
, ADPS_SUSPEND
);
15126 #endif /* WL_BAM */
15131 #ifdef DHD_LOSSLESS_ROAMING
15132 wl_del_roam_timeout(cfg
);
15133 #endif /* DHD_LOSSLESS_ROAMING */
15138 wl_cfg80211_verify_bss(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
15139 struct cfg80211_bss
**bss
)
15141 struct wiphy
*wiphy
;
15142 struct wlc_ssid
*ssid
;
15146 u8 cur_ssid
[DOT11_MAX_SSID_LEN
+ 1];
15148 wiphy
= bcmcfg_to_wiphy(cfg
);
15149 ssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, ndev
, WL_PROF_SSID
);
15150 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
15152 WL_ERR(("No SSID found in the saved profile \n"));
15157 *bss
= CFG80211_GET_BSS(wiphy
, NULL
, curbssid
,
15158 ssid
->SSID
, ssid
->SSID_len
);
15159 if (*bss
|| (count
> 5)) {
15165 } while (*bss
== NULL
);
15167 WL_DBG(("cfg80211 bss_ptr:%p loop_cnt:%d\n", *bss
, count
));
15169 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
15170 /* Update the reference count after use. In case of kernel version >= 4.7
15171 * the cfg802_put_bss is called in cfg80211_connect_bss context
15173 CFG80211_PUT_BSS(wiphy
, *bss
);
15174 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
15177 memset(cur_ssid
, 0, DOT11_MAX_SSID_LEN
);
15178 strncpy(cur_ssid
, ssid
->SSID
,
15179 MIN(ssid
->SSID_len
, DOT11_MAX_SSID_LEN
));
15180 WL_ERR(("No bss entry for ssid:%s bssid:"MACDBG
"\n",
15181 cur_ssid
, MAC2STRDBG(curbssid
)));
15186 static void wl_notify_scan_done(struct bcm_cfg80211
*cfg
, bool aborted
)
15188 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0))
15189 struct cfg80211_scan_info info
;
15191 memset(&info
, 0, sizeof(struct cfg80211_scan_info
));
15192 info
.aborted
= aborted
;
15193 cfg80211_scan_done(cfg
->scan_request
, &info
);
15195 cfg80211_scan_done(cfg
->scan_request
, aborted
);
15200 wl_bss_connect_done(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
15201 const wl_event_msg_t
*e
, void *data
, bool completed
)
15203 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
15204 struct wl_security
*sec
= wl_read_prof(cfg
, ndev
, WL_PROF_SEC
);
15206 u8
*curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
15207 u32 event_type
= ntoh32(e
->event_type
);
15208 struct cfg80211_bss
*bss
= NULL
;
15210 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
15211 BCM_REFERENCE(dhdp
);
15214 WL_ERR(("sec is NULL\n"));
15217 WL_DBG((" enter\n"));
15218 #ifdef ESCAN_RESULT_PATCH
15219 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
15220 if (memcmp(curbssid
, connect_req_bssid
, ETHER_ADDR_LEN
) == 0) {
15221 WL_INFORM_MEM((" Connected event of connected "
15222 "device e=%d s=%d, ignore it\n",
15223 ntoh32(e
->event_type
), ntoh32(e
->status
)));
15227 if (memcmp(curbssid
, broad_bssid
, ETHER_ADDR_LEN
) == 0 &&
15228 memcmp(broad_bssid
, connect_req_bssid
, ETHER_ADDR_LEN
) != 0) {
15229 WL_DBG(("copy bssid\n"));
15230 memcpy(curbssid
, connect_req_bssid
, ETHER_ADDR_LEN
);
15233 if (cfg
->scan_request
) {
15234 wl_cfg80211_cancel_scan(cfg
);
15236 #endif /* ESCAN_RESULT_PATCH */
15237 if (wl_get_drv_status(cfg
, CONNECTING
, ndev
)) {
15238 wl_cfg80211_scan_abort(cfg
);
15240 wl_get_assoc_ies(cfg
, ndev
);
15241 wl_update_prof(cfg
, ndev
, NULL
, (const void *)(e
->addr
.octet
),
15243 curbssid
= wl_read_prof(cfg
, ndev
, WL_PROF_BSSID
);
15244 wl_update_bss_info(cfg
, ndev
, false);
15245 wl_update_pmklist(ndev
, cfg
->pmk_list
, err
);
15246 wl_set_drv_status(cfg
, CONNECTED
, ndev
);
15247 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
15248 if (dhdp
->roam_env_detection
)
15249 wldev_iovar_setint(ndev
, "roam_env_detection",
15250 AP_ENV_INDETERMINATE
);
15251 #endif /* ROAM_AP_ENV_DETECTION */
15252 if (ndev
!= bcmcfg_to_prmry_ndev(cfg
)) {
15253 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
15254 init_completion(&cfg
->iface_disable
);
15256 /* reinitialize completion to clear previous count */
15257 INIT_COMPLETION(cfg
->iface_disable
);
15260 #ifdef CUSTOM_SET_CPUCORE
15261 if (wl_get_chan_isvht80(ndev
, dhdp
)) {
15262 if (ndev
== bcmcfg_to_prmry_ndev(cfg
))
15263 dhdp
->chan_isvht80
|= DHD_FLAG_STA_MODE
; /* STA mode */
15264 else if (is_p2p_group_iface(ndev
->ieee80211_ptr
))
15265 dhdp
->chan_isvht80
|= DHD_FLAG_P2P_MODE
; /* p2p mode */
15266 dhd_set_cpucore(dhdp
, TRUE
);
15268 #endif /* CUSTOM_SET_CPUCORE */
15269 #ifdef CUSTOM_LONG_RETRY_LIMIT
15270 if (wl_set_retry(ndev
, CUSTOM_LONG_RETRY_LIMIT
, 1) < 0) {
15271 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
15273 #endif /* CUSTOM_LONG_RETRY_LIMIT */
15274 memset(&cfg
->last_roamed_addr
, 0, ETHER_ADDR_LEN
);
15276 wl_clr_drv_status(cfg
, CONNECTING
, ndev
);
15278 if (completed
&& (wl_cfg80211_verify_bss(cfg
, ndev
, &bss
) != true)) {
15279 /* If bss entry is not available in the cfg80211 bss cache
15280 * the wireless stack will complain and won't populate
15281 * wdev->current_bss ptr
15283 WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
15285 sec
->auth_assoc_res_status
= WLAN_STATUS_UNSPECIFIED_FAILURE
;
15288 CFG80211_CONNECT_RESULT(ndev
,
15292 conn_info
->req_ie_len
,
15293 conn_info
->resp_ie
,
15294 conn_info
->resp_ie_len
,
15295 completed
? WLAN_STATUS_SUCCESS
:
15296 (sec
->auth_assoc_res_status
) ?
15297 sec
->auth_assoc_res_status
:
15298 WLAN_STATUS_UNSPECIFIED_FAILURE
,
15302 WL_INFORM_MEM(("[%s] Report connect result - "
15303 "connection succeeded\n", ndev
->name
));
15305 if (wl_adps_bad_ap_check(cfg
, &e
->addr
)) {
15306 if (wl_adps_enabled(cfg
, ndev
)) {
15307 wl_adps_set_suspend(cfg
, ndev
, ADPS_SUSPEND
);
15310 #endif /* WL_BAM */
15312 WL_ERR(("[%s] Report connect result - connection failed\n", ndev
->name
));
15314 WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
15315 " connecting:%x. connected:%d\n",
15316 ndev
->name
, event_type
, wl_get_drv_status(cfg
, CONNECTING
, ndev
),
15317 wl_get_drv_status(cfg
, CONNECTED
, ndev
)));
15319 #ifdef CONFIG_TCPACK_FASTTX
15320 if (wl_get_chan_isvht80(ndev
, dhdp
))
15321 wldev_iovar_setint(ndev
, "tcpack_fast_tx", 0);
15323 wldev_iovar_setint(ndev
, "tcpack_fast_tx", 1);
15324 #endif /* CONFIG_TCPACK_FASTTX */
15330 wl_notify_mic_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
15331 const wl_event_msg_t
*e
, void *data
)
15333 struct net_device
*ndev
= NULL
;
15334 u16 flags
= ntoh16(e
->flags
);
15335 enum nl80211_key_type key_type
;
15337 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
15339 WL_INFORM_MEM(("[%s] mic fail event - " MACDBG
" \n",
15340 ndev
->name
, MAC2STRDBG(e
->addr
.octet
)));
15341 mutex_lock(&cfg
->usr_sync
);
15342 if (flags
& WLC_EVENT_MSG_GROUP
)
15343 key_type
= NL80211_KEYTYPE_GROUP
;
15345 key_type
= NL80211_KEYTYPE_PAIRWISE
;
15347 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
15348 cfg80211_michael_mic_failure(ndev
, (const u8
*)&e
->addr
, key_type
, -1,
15350 mutex_unlock(&cfg
->usr_sync
);
15355 #ifdef BT_WIFI_HANDOVER
15357 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
15358 const wl_event_msg_t
*e
, void *data
)
15360 struct net_device
*ndev
= NULL
;
15361 u32 event
= ntoh32(e
->event_type
);
15362 u32 datalen
= ntoh32(e
->datalen
);
15365 WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event
, datalen
));
15366 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
15367 err
= wl_genl_send_msg(ndev
, event
, data
, (u16
)datalen
, 0, 0);
15371 #endif /* BT_WIFI_HANDOVER */
15375 wl_notify_pfn_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
15376 const wl_event_msg_t
*e
, void *data
)
15378 struct net_device
*ndev
= NULL
;
15379 #ifdef GSCAN_SUPPORT
15381 int send_evt_bytes
= 0;
15382 u32 event
= be32_to_cpu(e
->event_type
);
15383 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
15384 #endif /* GSCAN_SUPPORT */
15386 WL_INFORM_MEM((">>> PNO Event\n"));
15389 WL_ERR(("Data received is NULL!\n"));
15393 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
15394 #ifdef GSCAN_SUPPORT
15395 ptr
= dhd_dev_process_epno_result(ndev
, data
, event
, &send_evt_bytes
);
15397 wl_cfgvendor_send_async_event(wiphy
, ndev
,
15398 GOOGLE_SCAN_EPNO_EVENT
, ptr
, send_evt_bytes
);
15399 MFREE(cfg
->osh
, ptr
, send_evt_bytes
);
15401 if (!dhd_dev_is_legacy_pno_enabled(ndev
))
15403 #endif /* GSCAN_SUPPORT */
15405 #ifndef WL_SCHED_SCAN
15406 mutex_lock(&cfg
->usr_sync
);
15407 /* TODO: Use cfg80211_sched_scan_results(wiphy); */
15408 CFG80211_DISCONNECTED(ndev
, 0, NULL
, 0, false, GFP_KERNEL
);
15409 mutex_unlock(&cfg
->usr_sync
);
15411 /* If cfg80211 scheduled scan is supported, report the pno results via sched
15414 wl_notify_sched_scan_results(cfg
, ndev
, e
, data
);
15415 #endif /* WL_SCHED_SCAN */
15418 #endif /* PNO_SUPPORT */
15420 #ifdef GSCAN_SUPPORT
15422 wl_notify_gscan_event(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
15423 const wl_event_msg_t
*e
, void *data
)
15426 u32 event
= be32_to_cpu(e
->event_type
);
15428 int send_evt_bytes
= 0;
15430 struct net_device
*ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
15431 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
15432 u32 len
= ntoh32(e
->datalen
);
15436 case WLC_E_PFN_BEST_BATCHING
:
15437 err
= dhd_dev_retrieve_batch_scan(ndev
);
15439 WL_ERR(("Batch retrieval already in progress %d\n", err
));
15441 event_type
= WIFI_SCAN_THRESHOLD_NUM_SCANS
;
15443 event_type
= *((int *)data
);
15445 wl_cfgvendor_send_async_event(wiphy
, ndev
,
15446 GOOGLE_GSCAN_BATCH_SCAN_EVENT
,
15447 &event_type
, sizeof(int));
15450 case WLC_E_PFN_SCAN_COMPLETE
:
15451 event_type
= WIFI_SCAN_COMPLETE
;
15452 wl_cfgvendor_send_async_event(wiphy
, ndev
,
15453 GOOGLE_SCAN_COMPLETE_EVENT
,
15454 &event_type
, sizeof(int));
15456 case WLC_E_PFN_BSSID_NET_FOUND
:
15457 ptr
= dhd_dev_hotlist_scan_event(ndev
, data
, &send_evt_bytes
,
15458 HOTLIST_FOUND
, &buf_len
);
15460 wl_cfgvendor_send_hotlist_event(wiphy
, ndev
,
15461 ptr
, send_evt_bytes
, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT
);
15462 dhd_dev_gscan_hotlist_cache_cleanup(ndev
, HOTLIST_FOUND
);
15467 case WLC_E_PFN_BSSID_NET_LOST
:
15468 /* WLC_E_PFN_BSSID_NET_LOST is conflict shared with WLC_E_PFN_SCAN_ALLGONE
15469 * We currently do not use WLC_E_PFN_SCAN_ALLGONE, so if we get it, ignore
15472 ptr
= dhd_dev_hotlist_scan_event(ndev
, data
, &send_evt_bytes
,
15473 HOTLIST_LOST
, &buf_len
);
15475 wl_cfgvendor_send_hotlist_event(wiphy
, ndev
,
15476 ptr
, send_evt_bytes
, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT
);
15477 dhd_dev_gscan_hotlist_cache_cleanup(ndev
, HOTLIST_LOST
);
15478 MFREE(cfg
->osh
, ptr
, buf_len
);
15486 case WLC_E_PFN_GSCAN_FULL_RESULT
:
15487 ptr
= dhd_dev_process_full_gscan_result(ndev
, data
, len
, &send_evt_bytes
);
15489 wl_cfgvendor_send_async_event(wiphy
, ndev
,
15490 GOOGLE_SCAN_FULL_RESULTS_EVENT
, ptr
, send_evt_bytes
);
15491 MFREE(cfg
->osh
, ptr
, send_evt_bytes
);
15496 case WLC_E_PFN_SSID_EXT
:
15497 ptr
= dhd_dev_process_epno_result(ndev
, data
, event
, &send_evt_bytes
);
15499 wl_cfgvendor_send_async_event(wiphy
, ndev
,
15500 GOOGLE_SCAN_EPNO_EVENT
, ptr
, send_evt_bytes
);
15501 MFREE(cfg
->osh
, ptr
, send_evt_bytes
);
15507 WL_ERR(("Unknown event %d\n", event
));
15512 #endif /* GSCAN_SUPPORT */
15515 wl_notify_scan_status(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
15516 const wl_event_msg_t
*e
, void *data
)
15518 struct channel_info channel_inform
;
15519 struct wl_scan_results
*bss_list
;
15520 struct net_device
*ndev
= NULL
;
15521 u32 len
= WL_SCAN_BUF_MAX
;
15523 unsigned long flags
;
15525 WL_DBG(("Enter \n"));
15526 if (!wl_get_drv_status(cfg
, SCANNING
, ndev
)) {
15527 WL_DBG(("scan is not ready \n"));
15530 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
15532 mutex_lock(&cfg
->scan_sync
);
15533 wl_clr_drv_status(cfg
, SCANNING
, ndev
);
15534 memset(&channel_inform
, 0, sizeof(channel_inform
));
15535 err
= wldev_ioctl_get(ndev
, WLC_GET_CHANNEL
, &channel_inform
,
15536 sizeof(channel_inform
));
15537 if (unlikely(err
)) {
15538 WL_ERR(("scan busy (%d)\n", err
));
15539 goto scan_done_out
;
15541 channel_inform
.scan_channel
= dtoh32(channel_inform
.scan_channel
);
15542 if (unlikely(channel_inform
.scan_channel
)) {
15544 WL_DBG(("channel_inform.scan_channel (%d)\n",
15545 channel_inform
.scan_channel
));
15547 cfg
->bss_list
= cfg
->scan_results
;
15548 bss_list
= cfg
->bss_list
;
15549 memset(bss_list
, 0, len
);
15550 bss_list
->buflen
= htod32(len
);
15551 err
= wldev_ioctl_get(ndev
, WLC_SCAN_RESULTS
, bss_list
, len
);
15552 if (unlikely(err
) && unlikely(!cfg
->scan_suppressed
)) {
15553 WL_ERR(("%s Scan_results error (%d)\n", ndev
->name
, err
));
15555 goto scan_done_out
;
15557 bss_list
->buflen
= dtoh32(bss_list
->buflen
);
15558 bss_list
->version
= dtoh32(bss_list
->version
);
15559 bss_list
->count
= dtoh32(bss_list
->count
);
15561 err
= wl_inform_bss(cfg
);
15564 del_timer_sync(&cfg
->scan_timeout
);
15565 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
15566 if (cfg
->scan_request
) {
15567 wl_notify_scan_done(cfg
, false);
15568 cfg
->scan_request
= NULL
;
15570 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
15571 WL_DBG(("cfg80211_scan_done\n"));
15572 mutex_unlock(&cfg
->scan_sync
);
15577 wl_frame_get_mgmt(struct bcm_cfg80211
*cfg
, u16 fc
,
15578 const struct ether_addr
*da
, const struct ether_addr
*sa
,
15579 const struct ether_addr
*bssid
, u8
**pheader
, u32
*body_len
, u8
*pbody
)
15581 struct dot11_management_header
*hdr
;
15585 u32 prebody_len
= *body_len
;
15588 /* capability , listen interval */
15589 totlen
= DOT11_ASSOC_REQ_FIXED_LEN
;
15590 *body_len
+= DOT11_ASSOC_REQ_FIXED_LEN
;
15593 case FC_REASSOC_REQ
:
15594 /* capability, listen inteval, ap address */
15595 totlen
= DOT11_REASSOC_REQ_FIXED_LEN
;
15596 *body_len
+= DOT11_REASSOC_REQ_FIXED_LEN
;
15599 totlen
+= DOT11_MGMT_HDR_LEN
+ prebody_len
;
15600 *pheader
= (u8
*)MALLOCZ(cfg
->osh
, totlen
);
15601 if (*pheader
== NULL
) {
15602 WL_ERR(("memory alloc failed \n"));
15605 hdr
= (struct dot11_management_header
*) (*pheader
);
15606 hdr
->fc
= htol16(fc
);
15609 offset
= (u8
*)(hdr
+ 1) + (totlen
- DOT11_MGMT_HDR_LEN
- prebody_len
);
15610 bcopy((const char*)da
, (u8
*)&hdr
->da
, ETHER_ADDR_LEN
);
15611 bcopy((const char*)sa
, (u8
*)&hdr
->sa
, ETHER_ADDR_LEN
);
15612 bcopy((const char*)bssid
, (u8
*)&hdr
->bssid
, ETHER_ADDR_LEN
);
15613 if ((pbody
!= NULL
) && prebody_len
)
15614 bcopy((const char*)pbody
, offset
, prebody_len
);
15615 *body_len
= totlen
;
15619 #ifdef WL_CFG80211_GON_COLLISION
15621 wl_gon_req_collision(struct bcm_cfg80211
*cfg
, wl_action_frame_t
*tx_act_frm
,
15622 wifi_p2p_pub_act_frame_t
*rx_act_frm
, struct net_device
*ndev
,
15623 struct ether_addr sa
, struct ether_addr da
)
15625 if (cfg
->afx_hdl
->pending_tx_act_frm
== NULL
)
15629 wl_cfgp2p_is_pub_action(tx_act_frm
->data
, tx_act_frm
->len
)) {
15630 wifi_p2p_pub_act_frame_t
*pact_frm
;
15632 pact_frm
= (wifi_p2p_pub_act_frame_t
*)tx_act_frm
->data
;
15634 if (!(pact_frm
->subtype
== P2P_PAF_GON_REQ
&&
15635 rx_act_frm
->subtype
== P2P_PAF_GON_REQ
)) {
15640 WL_ERR((" GO NEGO Request COLLISION !!! \n"));
15642 /* if sa(peer) addr is less than da(my) addr,
15643 * my device will process peer's gon request and block to send my gon req.
15645 * if not (sa addr > da addr),
15646 * my device will process gon request and drop gon req of peer.
15648 if (memcmp(sa
.octet
, da
.octet
, ETHER_ADDR_LEN
) < 0) {
15649 /* block to send tx gon request */
15650 cfg
->block_gon_req_tx_count
= BLOCK_GON_REQ_MAX_NUM
;
15651 WL_ERR((" block to send gon req tx !!!\n"));
15653 /* if we are finding a common channel for sending af,
15654 * do not scan more to block to send current gon req
15656 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
15657 wl_clr_drv_status(cfg
, FINDING_COMMON_CHANNEL
, ndev
);
15658 complete(&cfg
->act_frm_scan
);
15661 /* drop gon request of peer to process gon request by my device. */
15662 WL_ERR((" drop to receive gon req rx !!! \n"));
15663 cfg
->block_gon_req_rx_count
= BLOCK_GON_REQ_MAX_NUM
;
15668 #endif /* WL_CFG80211_GON_COLLISION */
15671 wl_stop_wait_next_action_frame(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u8 bsscfgidx
)
15675 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
15676 if (timer_pending(&cfg
->p2p
->listen_timer
)) {
15677 del_timer_sync(&cfg
->p2p
->listen_timer
);
15679 if (cfg
->afx_hdl
!= NULL
) {
15680 if (cfg
->afx_hdl
->dev
!= NULL
) {
15681 wl_clr_drv_status(cfg
, SCANNING
, cfg
->afx_hdl
->dev
);
15682 wl_clr_drv_status(cfg
, FINDING_COMMON_CHANNEL
, cfg
->afx_hdl
->dev
);
15684 cfg
->afx_hdl
->peer_chan
= WL_INVALID
;
15686 complete(&cfg
->act_frm_scan
);
15687 WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
15688 } else if (wl_get_drv_status_all(cfg
, SENDING_ACT_FRM
)) {
15689 if (!(wl_get_p2p_status(cfg
, ACTION_TX_COMPLETED
) ||
15690 wl_get_p2p_status(cfg
, ACTION_TX_NOACK
)))
15691 wl_set_p2p_status(cfg
, ACTION_TX_COMPLETED
);
15693 WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx
));
15694 /* Scan engine is not used for sending action frames in the latest driver
15695 * branches. actframe_abort is used in the latest driver branches
15696 * instead of scan abort.
15697 * If actframe_abort iovar succeeds, don't execute scan abort.
15698 * If actframe_abort fails with unsupported error,
15699 * execute scan abort (for backward copmatibility).
15701 if (cfg
->af_sent_channel
) {
15702 err
= wldev_iovar_setint_bsscfg(ndev
, "actframe_abort", 1, bsscfgidx
);
15704 if (err
== BCME_UNSUPPORTED
) {
15705 wl_cfg80211_scan_abort(cfg
);
15707 WL_ERR(("actframe_abort failed. ret:%d\n", err
));
15712 #ifdef WL_CFG80211_SYNC_GON
15713 else if (wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM_LISTEN
)) {
15714 WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
15715 /* So abort scan to cancel listen */
15716 wl_cfg80211_scan_abort(cfg
);
15718 #endif /* WL_CFG80211_SYNC_GON */
15721 #if defined(WLTDLS)
15722 bool wl_cfg80211_is_tdls_tunneled_frame(void *frame
, u32 frame_len
)
15724 unsigned char *data
;
15726 if (frame
== NULL
) {
15727 WL_ERR(("Invalid frame \n"));
15731 if (frame_len
< 5) {
15732 WL_ERR(("Invalid frame length [%d] \n", frame_len
));
15738 if (!memcmp(data
, TDLS_TUNNELED_PRB_REQ
, 5) ||
15739 !memcmp(data
, TDLS_TUNNELED_PRB_RESP
, 5)) {
15740 WL_DBG(("TDLS Vendor Specific Received type\n"));
15746 #endif /* WLTDLS */
15748 #if defined(WES_SUPPORT)
15749 static int wes_mode
= 0;
15750 int wl_cfg80211_set_wes_mode(int mode
)
15756 int wl_cfg80211_get_wes_mode(void)
15761 bool wl_cfg80211_is_wes(void *frame
, u32 frame_len
)
15763 unsigned char *data
;
15765 if (frame
== NULL
) {
15766 WL_ERR(("Invalid frame \n"));
15770 if (frame_len
< 4) {
15771 WL_ERR(("Invalid frame length [%d] \n", frame_len
));
15777 if (memcmp(data
, "\x7f\x00\x00\xf0", 4) == 0) {
15778 WL_DBG(("Receive WES VS Action Frame \n"));
15784 #endif /* WES_SUPPORT */
15786 int wl_cfg80211_get_ioctl_version(void)
15788 return ioctl_version
;
15792 wl_notify_rx_mgmt_frame(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
15793 const wl_event_msg_t
*e
, void *data
)
15795 struct ieee80211_supported_band
*band
;
15796 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
15797 struct ether_addr da
;
15798 struct ether_addr bssid
;
15799 bool isfree
= false;
15802 struct net_device
*ndev
= NULL
;
15803 wifi_p2p_pub_act_frame_t
*act_frm
= NULL
;
15804 wifi_p2p_action_frame_t
*p2p_act_frm
= NULL
;
15805 wifi_p2psd_gas_pub_act_frame_t
*sd_act_frm
= NULL
;
15806 wl_event_rx_frame_data_t
*rxframe
;
15810 u32 mgmt_frame_len
;
15812 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
15813 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
15814 #endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
15815 if (ntoh32(e
->datalen
) < sizeof(wl_event_rx_frame_data_t
)) {
15816 WL_ERR(("wrong datalen:%d\n", ntoh32(e
->datalen
)));
15819 mgmt_frame_len
= ntoh32(e
->datalen
) - (uint32
)sizeof(wl_event_rx_frame_data_t
);
15820 event
= ntoh32(e
->event_type
);
15821 bsscfgidx
= e
->bsscfgidx
;
15822 rxframe
= (wl_event_rx_frame_data_t
*)data
;
15824 WL_ERR(("rxframe: NULL\n"));
15827 channel
= (ntoh16(rxframe
->channel
) & WL_CHANSPEC_CHAN_MASK
);
15828 memset(&bssid
, 0, ETHER_ADDR_LEN
);
15829 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
15830 if ((ndev
->ieee80211_ptr
->iftype
!= NL80211_IFTYPE_AP
) &&
15831 (event
== WLC_E_PROBREQ_MSG
)) {
15832 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15833 4 && __GNUC_MINOR__ >= 6))
15834 _Pragma("GCC diagnostic push")
15835 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
15837 struct net_info
*iter
, *next
;
15838 for_each_ndev(cfg
, iter
, next
) {
15839 if (iter
->ndev
&& iter
->wdev
&&
15840 iter
->wdev
->iftype
== NL80211_IFTYPE_AP
) {
15842 cfgdev
= ndev_to_cfgdev(ndev
);
15846 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15847 4 && __GNUC_MINOR__ >= 6))
15848 _Pragma("GCC diagnostic pop")
15852 if (channel
<= CH_MAX_2G_CHANNEL
)
15853 band
= wiphy
->bands
[NL80211_BAND_2GHZ
];
15855 band
= wiphy
->bands
[NL80211_BAND_5GHZ
];
15857 WL_ERR(("No valid band"));
15860 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
15861 freq
= ieee80211_channel_to_frequency(channel
);
15864 freq
= ieee80211_channel_to_frequency(channel
, band
->band
);
15866 if (event
== WLC_E_ACTION_FRAME_RX
) {
15867 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
15869 if ((err
= wldev_iovar_getbuf_bsscfg(ndev
, "cur_etheraddr",
15870 NULL
, 0, ioctl_buf
, sizeof(ioctl_buf
), bsscfgidx
,
15871 NULL
)) != BCME_OK
) {
15872 WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err
));
15876 err
= wldev_ioctl_get(ndev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
);
15878 WL_ERR(("WLC_GET_BSSID error %d\n", err
));
15879 memcpy(da
.octet
, ioctl_buf
, ETHER_ADDR_LEN
);
15880 err
= wl_frame_get_mgmt(cfg
, FC_ACTION
, &da
, &e
->addr
, &bssid
,
15881 &mgmt_frame
, &mgmt_frame_len
,
15882 (u8
*)((wl_event_rx_frame_data_t
*)rxframe
+ 1));
15884 WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
15885 mgmt_frame_len
, channel
, freq
));
15889 if (wl_cfgp2p_is_pub_action(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
15890 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)) {
15891 act_frm
= (wifi_p2p_pub_act_frame_t
*)
15892 (&mgmt_frame
[DOT11_MGMT_HDR_LEN
]);
15893 } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
15894 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)) {
15895 p2p_act_frm
= (wifi_p2p_action_frame_t
*)
15896 (&mgmt_frame
[DOT11_MGMT_HDR_LEN
]);
15897 (void) p2p_act_frm
;
15898 } else if (wl_cfgp2p_is_gas_action(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
15899 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)) {
15901 sd_act_frm
= (wifi_p2psd_gas_pub_act_frame_t
*)
15902 (&mgmt_frame
[DOT11_MGMT_HDR_LEN
]);
15903 if (sd_act_frm
&& wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM
)) {
15904 if (cfg
->next_af_subtype
== sd_act_frm
->action
) {
15905 WL_DBG(("We got a right next frame of SD!(%d)\n",
15906 sd_act_frm
->action
));
15907 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, ndev
);
15909 /* Stop waiting for next AF. */
15910 wl_stop_wait_next_action_frame(cfg
, ndev
, bsscfgidx
);
15915 } else if ((mgmt_frame
[DOT11_MGMT_HDR_LEN
] == TDLS_AF_CATEGORY
) ||
15916 (wl_cfg80211_is_tdls_tunneled_frame(
15917 &mgmt_frame
[DOT11_MGMT_HDR_LEN
],
15918 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
))) {
15919 if (mgmt_frame
[DOT11_MGMT_HDR_LEN
] == TDLS_AF_CATEGORY
) {
15920 WL_ERR((" TDLS Action Frame Received type = %d \n",
15921 mgmt_frame
[DOT11_MGMT_HDR_LEN
+ 1]));
15923 #ifdef TDLS_MSG_ONLY_WFD
15924 if (!dhdp
->tdls_mode
) {
15925 WL_DBG((" TDLS Frame filtered \n"));
15929 if (mgmt_frame
[DOT11_MGMT_HDR_LEN
+ 1] == TDLS_ACTION_SETUP_RESP
) {
15930 cfg
->tdls_mgmt_frame
= mgmt_frame
;
15931 cfg
->tdls_mgmt_frame_len
= mgmt_frame_len
;
15932 cfg
->tdls_mgmt_freq
= freq
;
15935 #endif /* TDLS_MSG_ONLY_WFD */
15936 #endif /* WLTDLS */
15938 } else if (mgmt_frame
[DOT11_MGMT_HDR_LEN
] == DOT11_ACTION_CAT_QOS
) {
15939 /* update QoS map set table */
15940 bcm_tlv_t
* qos_map_ie
= NULL
;
15941 if ((qos_map_ie
= bcm_parse_tlvs(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
15942 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
,
15943 DOT11_MNG_QOS_MAP_ID
)) != NULL
) {
15944 WL_DBG((" QoS map set IE found in QoS action frame\n"));
15945 if (!cfg
->up_table
) {
15946 cfg
->up_table
= (uint8
*)MALLOC(cfg
->osh
, UP_TABLE_MAX
);
15948 wl_set_up_table(cfg
->up_table
, qos_map_ie
);
15950 MFREE(cfg
->osh
, cfg
->up_table
, UP_TABLE_MAX
);
15951 cfg
->up_table
= NULL
;
15953 #endif /* QOS_MAP_SET */
15955 } else if (mgmt_frame
[DOT11_MGMT_HDR_LEN
] == DOT11_ACTION_CAT_RRM
) {
15956 /* radio measurement category */
15957 switch (mgmt_frame
[DOT11_MGMT_HDR_LEN
+1]) {
15958 case DOT11_RM_ACTION_NR_REP
:
15959 if (wl_cfg80211_recv_nbr_resp(ndev
,
15960 &mgmt_frame
[DOT11_MGMT_HDR_LEN
],
15961 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
)
15963 WL_DBG(("RCC updated by nbr response\n"));
15969 #endif /* WBTEXT */
15972 * if we got normal action frame and ndev is p2p0,
15973 * we have to change ndev from p2p0 to wlan0
15975 #if defined(WES_SUPPORT)
15976 if (wl_cfg80211_is_wes(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
15977 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
) && wes_mode
== 0) {
15978 /* Ignore WES VS Action frame */
15981 #endif /* WES_SUPPORT */
15983 if (cfg
->next_af_subtype
!= P2P_PAF_SUBTYPE_INVALID
) {
15985 if (wl_get_public_action(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
15986 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
, &action
) != BCME_OK
) {
15987 WL_DBG(("Recived action is not public action frame\n"));
15988 } else if (cfg
->next_af_subtype
== action
) {
15989 WL_DBG(("Recived action is the waiting action(%d)\n",
15991 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, ndev
);
15993 /* Stop waiting for next AF. */
15994 wl_stop_wait_next_action_frame(cfg
, ndev
, bsscfgidx
);
16000 #ifdef WL_CFG80211_GON_COLLISION
16001 if (act_frm
->subtype
== P2P_PAF_GON_REQ
) {
16002 wl_gon_req_collision(cfg
,
16003 &cfg
->afx_hdl
->pending_tx_act_frm
->action_frame
,
16004 act_frm
, ndev
, e
->addr
, da
);
16006 if (cfg
->block_gon_req_rx_count
) {
16007 WL_ERR(("drop frame GON Req Rx : count (%d)\n",
16008 cfg
->block_gon_req_rx_count
));
16009 cfg
->block_gon_req_rx_count
--;
16012 } else if (act_frm
->subtype
== P2P_PAF_GON_CONF
) {
16013 /* if go formation done, clear it */
16014 cfg
->block_gon_req_tx_count
= 0;
16015 cfg
->block_gon_req_rx_count
= 0;
16017 #endif /* WL_CFG80211_GON_COLLISION */
16019 if (wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM
)) {
16020 if (cfg
->next_af_subtype
== act_frm
->subtype
) {
16021 WL_DBG(("Abort wait for next frame, Recieved frame (%d) "
16022 "Next action frame(%d)\n",
16023 act_frm
->subtype
, cfg
->next_af_subtype
));
16024 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, ndev
);
16026 if (cfg
->next_af_subtype
== P2P_PAF_GON_CONF
) {
16030 /* Stop waiting for next AF. */
16031 wl_stop_wait_next_action_frame(cfg
, ndev
, bsscfgidx
);
16032 } else if ((cfg
->next_af_subtype
== P2P_PAF_GON_RSP
) &&
16033 (act_frm
->subtype
== P2P_PAF_GON_REQ
)) {
16034 /* If current received frame is GO NEG REQ and next
16035 * expected frame is GO NEG RESP, do not send it up.
16037 WL_ERR(("GO Neg req received while waiting for RESP."
16038 "Discard incoming frame\n"));
16044 wl_cfgp2p_print_actframe(false, &mgmt_frame
[DOT11_MGMT_HDR_LEN
],
16045 mgmt_frame_len
- DOT11_MGMT_HDR_LEN
, channel
);
16046 if (act_frm
&& (act_frm
->subtype
== P2P_PAF_GON_CONF
)) {
16047 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
16048 wl_clr_p2p_status(cfg
, GO_NEG_PHASE
);
16050 } else if (event
== WLC_E_PROBREQ_MSG
) {
16052 /* Handle probe reqs frame
16053 * WPS-AP certification 4.2.13
16055 struct parsed_ies prbreq_ies
;
16056 u32 prbreq_ie_len
= 0;
16059 WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
16060 mgmt_frame
= (u8
*)(data
);
16061 mgmt_frame_len
= ntoh32(e
->datalen
);
16062 if (mgmt_frame_len
< DOT11_MGMT_HDR_LEN
) {
16063 WL_ERR(("wrong datalen:%d\n", mgmt_frame_len
));
16066 prbreq_ie_len
= mgmt_frame_len
- DOT11_MGMT_HDR_LEN
;
16068 /* Parse prob_req IEs */
16069 if (wl_cfg80211_parse_ies(&mgmt_frame
[DOT11_MGMT_HDR_LEN
],
16070 prbreq_ie_len
, &prbreq_ies
) < 0) {
16071 WL_ERR(("Prob req get IEs failed\n"));
16074 if (prbreq_ies
.wps_ie
!= NULL
) {
16075 wl_validate_wps_ie(
16076 (const char *)prbreq_ies
.wps_ie
, prbreq_ies
.wps_ie_len
, &pbc
);
16077 WL_DBG((" wps_ie exist pbc = %d\n", pbc
));
16078 /* if pbc method, send prob_req mgmt frame to upper layer */
16084 mgmt_frame
= (u8
*)((wl_event_rx_frame_data_t
*)rxframe
+ 1);
16086 /* wpa supplicant use probe request event for restarting another GON Req.
16087 * but it makes GON Req repetition.
16088 * so if src addr of prb req is same as my target device,
16089 * do not send probe request event during sending action frame.
16091 if (event
== WLC_E_P2P_PROBREQ_MSG
) {
16092 WL_DBG((" Event %s\n", (event
== WLC_E_P2P_PROBREQ_MSG
) ?
16093 "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
16095 #ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
16096 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg
) &&
16097 !memcmp(cfg
->afx_hdl
->tx_dst_addr
.octet
, e
->addr
.octet
,
16099 if (cfg
->afx_hdl
->pending_tx_act_frm
&&
16100 wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
16101 s32 channel
= CHSPEC_CHANNEL(hton16(rxframe
->channel
));
16102 WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
16104 cfg
->afx_hdl
->peer_chan
= channel
;
16105 complete(&cfg
->act_frm_scan
);
16108 #endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
16110 /* Filter any P2P probe reqs arriving during the
16114 #if defined(P2P_IE_MISSING_FIX)
16115 cfg
->p2p_prb_noti
&&
16117 wl_get_p2p_status(cfg
, GO_NEG_PHASE
)) {
16118 WL_DBG(("Filtering P2P probe_req while "
16119 "being in GO-Neg state\n"));
16125 if (discover_cfgdev(cfgdev
, cfg
))
16126 WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
16128 WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev
->name
));
16129 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
16130 cfg80211_rx_mgmt(cfgdev
, freq
, 0, mgmt_frame
, mgmt_frame_len
, 0);
16131 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
16132 cfg80211_rx_mgmt(cfgdev
, freq
, 0, mgmt_frame
, mgmt_frame_len
, 0, GFP_ATOMIC
);
16133 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
16134 defined(WL_COMPAT_WIRELESS)
16135 cfg80211_rx_mgmt(cfgdev
, freq
, 0, mgmt_frame
, mgmt_frame_len
, GFP_ATOMIC
);
16137 cfg80211_rx_mgmt(cfgdev
, freq
, mgmt_frame
, mgmt_frame_len
, GFP_ATOMIC
);
16138 #endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
16140 WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
16141 mgmt_frame_len
, ntoh32(e
->datalen
), channel
, freq
));
16144 MFREE(cfg
->osh
, mgmt_frame
, mgmt_frame_len
);
16149 #ifdef WL_SCHED_SCAN
16150 /* If target scan is not reliable, set the below define to "1" to do a
16153 #define FULL_ESCAN_ON_PFN_NET_FOUND 0
16155 wl_notify_sched_scan_results(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
16156 const wl_event_msg_t
*e
, void *data
)
16158 wl_pfn_net_info_v1_t
*netinfo
, *pnetinfo
;
16159 wl_pfn_net_info_v2_t
*netinfo_v2
, *pnetinfo_v2
;
16160 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
16161 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
16163 struct cfg80211_scan_request
*request
= NULL
;
16164 struct cfg80211_ssid ssid
[MAX_PFN_LIST_COUNT
];
16165 struct ieee80211_channel
*channel
= NULL
;
16166 int channel_req
= 0;
16168 wl_pfn_scanresults_v1_t
*pfn_result_v1
= (wl_pfn_scanresults_v1_t
*)data
;
16169 wl_pfn_scanresults_v2_t
*pfn_result_v2
= (wl_pfn_scanresults_v2_t
*)data
;
16170 int n_pfn_results
= 0;
16171 log_conn_event_t
*event_data
= NULL
;
16172 tlv_log
*tlv_data
= NULL
;
16173 u32 alloc_len
, tlv_len
;
16175 u8 tmp_buf
[DOT11_MAX_SSID_LEN
+ 1];
16177 WL_DBG(("Enter\n"));
16179 /* These static asserts guarantee v1/v2 net_info and subnet_info are compatible
16180 * in size and SSID offset, allowing v1 to be used below except for the results
16181 * fields themselves (status, count, offset to netinfo).
16183 STATIC_ASSERT(sizeof(wl_pfn_net_info_v1_t
) == sizeof(wl_pfn_net_info_v2_t
));
16184 STATIC_ASSERT(sizeof(wl_pfn_lnet_info_v1_t
) == sizeof(wl_pfn_lnet_info_v2_t
));
16185 STATIC_ASSERT(sizeof(wl_pfn_subnet_info_v1_t
) == sizeof(wl_pfn_subnet_info_v2_t
));
16186 STATIC_ASSERT(OFFSETOF(wl_pfn_subnet_info_v1_t
, SSID
) ==
16187 OFFSETOF(wl_pfn_subnet_info_v2_t
, u
.SSID
));
16189 /* Extract the version-specific items */
16190 if (pfn_result_v1
->version
== PFN_SCANRESULT_VERSION_V1
) {
16191 n_pfn_results
= pfn_result_v1
->count
;
16192 pnetinfo
= pfn_result_v1
->netinfo
;
16193 WL_INFORM_MEM(("PFN NET FOUND event. count:%d \n", n_pfn_results
));
16195 if (n_pfn_results
> 0) {
16198 if (n_pfn_results
> MAX_PFN_LIST_COUNT
)
16199 n_pfn_results
= MAX_PFN_LIST_COUNT
;
16201 memset(&ssid
, 0x00, sizeof(ssid
));
16203 request
= (struct cfg80211_scan_request
*)MALLOCZ(cfg
->osh
,
16204 sizeof(*request
) + sizeof(*request
->channels
) * n_pfn_results
);
16205 channel
= (struct ieee80211_channel
*)MALLOCZ(cfg
->osh
,
16206 (sizeof(struct ieee80211_channel
) * n_pfn_results
));
16207 if (!request
|| !channel
) {
16208 WL_ERR(("No memory"));
16213 request
->wiphy
= wiphy
;
16215 if (DBG_RING_ACTIVE(dhdp
, DHD_EVENT_RING_ID
)) {
16216 alloc_len
= sizeof(log_conn_event_t
) + DOT11_MAX_SSID_LEN
+
16217 sizeof(uint16
) + sizeof(int16
);
16218 event_data
= (log_conn_event_t
*)MALLOC(cfg
->osh
, alloc_len
);
16220 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
16221 "length(%d)\n", __func__
, alloc_len
));
16224 tlv_len
= 3 * sizeof(tlv_log
);
16225 event_data
->tlvs
= (tlv_log
*)MALLOC(cfg
->osh
, tlv_len
);
16226 if (!event_data
->tlvs
) {
16227 WL_ERR(("%s: failed to allocate the tlv_log with "
16228 "length(%d)\n", __func__
, tlv_len
));
16233 for (i
= 0; i
< n_pfn_results
; i
++) {
16234 netinfo
= &pnetinfo
[i
];
16236 WL_ERR(("Invalid netinfo ptr. index:%d", i
));
16240 if (netinfo
->pfnsubnet
.SSID_len
> DOT11_MAX_SSID_LEN
) {
16241 WL_ERR(("Wrong SSID length:%d\n",
16242 netinfo
->pfnsubnet
.SSID_len
));
16246 memcpy(tmp_buf
, netinfo
->pfnsubnet
.SSID
,
16247 netinfo
->pfnsubnet
.SSID_len
);
16248 tmp_buf
[netinfo
->pfnsubnet
.SSID_len
] = '\0';
16249 WL_PNO((">>> SSID:%s Channel:%d \n",
16250 tmp_buf
, netinfo
->pfnsubnet
.channel
));
16251 /* PFN result doesn't have all the info which are required by
16252 * the supplicant. (For e.g IEs) Do a target Escan so that
16253 * sched scan results are reported via wl_inform_single_bss in
16254 * the required format. Escan does require the scan request in
16255 * the form of cfg80211_scan_request. For timebeing, create
16256 * cfg80211_scan_request one out of the received PNO event.
16259 ssid
[i
].ssid_len
= netinfo
->pfnsubnet
.SSID_len
;
16260 memcpy(ssid
[i
].ssid
, netinfo
->pfnsubnet
.SSID
,
16262 request
->n_ssids
++;
16264 channel_req
= netinfo
->pfnsubnet
.channel
;
16265 band
= (channel_req
<= CH_MAX_2G_CHANNEL
) ? NL80211_BAND_2GHZ
16266 : NL80211_BAND_5GHZ
;
16267 channel
[i
].center_freq
=
16268 ieee80211_channel_to_frequency(channel_req
, band
);
16269 channel
[i
].band
= band
;
16270 channel
[i
].flags
|= IEEE80211_CHAN_NO_HT40
;
16271 request
->channels
[i
] = &channel
[i
];
16272 request
->n_channels
++;
16274 if (DBG_RING_ACTIVE(dhdp
, DHD_EVENT_RING_ID
)) {
16275 payload_len
= sizeof(log_conn_event_t
);
16276 event_data
->event
= WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND
;
16277 tlv_data
= event_data
->tlvs
;
16280 tlv_data
->tag
= WIFI_TAG_SSID
;
16281 tlv_data
->len
= ssid
[i
].ssid_len
;
16282 memcpy(tlv_data
->value
, ssid
[i
].ssid
, ssid
[i
].ssid_len
);
16283 payload_len
+= TLV_LOG_SIZE(tlv_data
);
16284 tlv_data
= TLV_LOG_NEXT(tlv_data
);
16287 tlv_data
->tag
= WIFI_TAG_CHANNEL
;
16288 tlv_data
->len
= sizeof(uint16
);
16289 memcpy(tlv_data
->value
, &channel_req
, sizeof(uint16
));
16290 payload_len
+= TLV_LOG_SIZE(tlv_data
);
16291 tlv_data
= TLV_LOG_NEXT(tlv_data
);
16294 tlv_data
->tag
= WIFI_TAG_RSSI
;
16295 tlv_data
->len
= sizeof(int16
);
16296 memcpy(tlv_data
->value
, &netinfo
->RSSI
, sizeof(int16
));
16297 payload_len
+= TLV_LOG_SIZE(tlv_data
);
16298 tlv_data
= TLV_LOG_NEXT(tlv_data
);
16300 dhd_os_push_push_ring_data(dhdp
, DHD_EVENT_RING_ID
,
16301 &event_data
->event
, payload_len
);
16305 /* assign parsed ssid array */
16306 if (request
->n_ssids
)
16307 request
->ssids
= &ssid
[0];
16309 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
16310 /* Abort any on-going scan */
16311 wl_cfg80211_cancel_scan(cfg
);
16314 if (wl_get_p2p_status(cfg
, DISCOVERY_ON
)) {
16315 WL_PNO((">>> P2P discovery was ON. Disabling it\n"));
16316 err
= wl_cfgp2p_discover_enable_search(cfg
, false);
16317 if (unlikely(err
)) {
16318 wl_clr_drv_status(cfg
, SCANNING
, ndev
);
16321 p2p_scan(cfg
) = false;
16323 wl_set_drv_status(cfg
, SCANNING
, ndev
);
16324 #if FULL_ESCAN_ON_PFN_NET_FOUND
16325 WL_PNO((">>> Doing Full ESCAN on PNO event\n"));
16326 err
= wl_do_escan(cfg
, wiphy
, ndev
, NULL
);
16328 WL_PNO((">>> Doing targeted ESCAN on PNO event\n"));
16329 err
= wl_do_escan(cfg
, wiphy
, ndev
, request
);
16332 wl_clr_drv_status(cfg
, SCANNING
, ndev
);
16335 DBG_EVENT_LOG(dhdp
, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED
);
16336 cfg
->sched_scan_running
= TRUE
;
16339 WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
16342 } else if (pfn_result_v2
->version
== PFN_SCANRESULT_VERSION_V2
) {
16343 n_pfn_results
= pfn_result_v2
->count
;
16344 pnetinfo_v2
= (wl_pfn_net_info_v2_t
*)pfn_result_v2
->netinfo
;
16346 if (e
->event_type
== WLC_E_PFN_NET_LOST
) {
16347 WL_PNO(("Do Nothing %d\n", e
->event_type
));
16351 WL_INFORM_MEM(("PFN NET FOUND event. count:%d \n", n_pfn_results
));
16353 if (n_pfn_results
> 0) {
16356 if (n_pfn_results
> MAX_PFN_LIST_COUNT
)
16357 n_pfn_results
= MAX_PFN_LIST_COUNT
;
16359 memset(&ssid
, 0x00, sizeof(ssid
));
16361 request
= (struct cfg80211_scan_request
*)MALLOCZ(cfg
->osh
,
16362 sizeof(*request
) + sizeof(*request
->channels
) * n_pfn_results
);
16363 channel
= (struct ieee80211_channel
*)MALLOCZ(cfg
->osh
,
16364 (sizeof(struct ieee80211_channel
) * n_pfn_results
));
16365 if (!request
|| !channel
) {
16366 WL_ERR(("No memory"));
16371 request
->wiphy
= wiphy
;
16373 if (DBG_RING_ACTIVE(dhdp
, DHD_EVENT_RING_ID
)) {
16374 alloc_len
= sizeof(log_conn_event_t
) + DOT11_MAX_SSID_LEN
+
16375 sizeof(uint16
) + sizeof(int16
);
16376 event_data
= (log_conn_event_t
*)MALLOC(cfg
->osh
, alloc_len
);
16378 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
16379 "length(%d)\n", __func__
, alloc_len
));
16382 tlv_len
= 3 * sizeof(tlv_log
);
16383 event_data
->tlvs
= (tlv_log
*)MALLOC(cfg
->osh
, tlv_len
);
16384 if (!event_data
->tlvs
) {
16385 WL_ERR(("%s: failed to allocate the tlv_log with "
16386 "length(%d)\n", __func__
, tlv_len
));
16391 for (i
= 0; i
< n_pfn_results
; i
++) {
16392 netinfo_v2
= &pnetinfo_v2
[i
];
16394 WL_ERR(("Invalid netinfo ptr. index:%d", i
));
16398 WL_PNO((">>> SSID:%s Channel:%d \n",
16399 netinfo_v2
->pfnsubnet
.u
.SSID
,
16400 netinfo_v2
->pfnsubnet
.channel
));
16401 /* PFN result doesn't have all the info which are required by the
16402 * supplicant. (For e.g IEs) Do a target Escan so that sched scan
16403 * results are reported via wl_inform_single_bss in the required
16404 * format. Escan does require the scan request in the form of
16405 * cfg80211_scan_request. For timebeing, create
16406 * cfg80211_scan_request one out of the received PNO event.
16408 ssid
[i
].ssid_len
= MIN(DOT11_MAX_SSID_LEN
,
16409 netinfo_v2
->pfnsubnet
.SSID_len
);
16410 memcpy(ssid
[i
].ssid
, netinfo_v2
->pfnsubnet
.u
.SSID
,
16412 request
->n_ssids
++;
16414 channel_req
= netinfo_v2
->pfnsubnet
.channel
;
16415 band
= (channel_req
<= CH_MAX_2G_CHANNEL
) ? NL80211_BAND_2GHZ
16416 : NL80211_BAND_5GHZ
;
16417 channel
[i
].center_freq
=
16418 ieee80211_channel_to_frequency(channel_req
, band
);
16419 channel
[i
].band
= band
;
16420 channel
[i
].flags
|= IEEE80211_CHAN_NO_HT40
;
16421 request
->channels
[i
] = &channel
[i
];
16422 request
->n_channels
++;
16424 if (DBG_RING_ACTIVE(dhdp
, DHD_EVENT_RING_ID
)) {
16425 payload_len
= sizeof(log_conn_event_t
);
16426 event_data
->event
= WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND
;
16427 tlv_data
= event_data
->tlvs
;
16430 tlv_data
->tag
= WIFI_TAG_SSID
;
16431 tlv_data
->len
= netinfo_v2
->pfnsubnet
.SSID_len
;
16432 memcpy(tlv_data
->value
, ssid
[i
].ssid
, ssid
[i
].ssid_len
);
16433 payload_len
+= TLV_LOG_SIZE(tlv_data
);
16434 tlv_data
= TLV_LOG_NEXT(tlv_data
);
16437 tlv_data
->tag
= WIFI_TAG_CHANNEL
;
16438 tlv_data
->len
= sizeof(uint16
);
16439 memcpy(tlv_data
->value
, &channel_req
, sizeof(uint16
));
16440 payload_len
+= TLV_LOG_SIZE(tlv_data
);
16441 tlv_data
= TLV_LOG_NEXT(tlv_data
);
16444 tlv_data
->tag
= WIFI_TAG_RSSI
;
16445 tlv_data
->len
= sizeof(int16
);
16446 memcpy(tlv_data
->value
, &netinfo_v2
->RSSI
, sizeof(int16
));
16447 payload_len
+= TLV_LOG_SIZE(tlv_data
);
16448 tlv_data
= TLV_LOG_NEXT(tlv_data
);
16450 dhd_os_push_push_ring_data(dhdp
, DHD_EVENT_RING_ID
,
16451 &event_data
->event
, payload_len
);
16455 /* assign parsed ssid array */
16456 if (request
->n_ssids
)
16457 request
->ssids
= &ssid
[0];
16459 if (wl_get_drv_status_all(cfg
, SCANNING
)) {
16460 /* Abort any on-going scan */
16461 wl_cfg80211_cancel_scan(cfg
);
16464 if (wl_get_p2p_status(cfg
, DISCOVERY_ON
)) {
16465 WL_PNO((">>> P2P discovery was ON. Disabling it\n"));
16466 err
= wl_cfgp2p_discover_enable_search(cfg
, false);
16467 if (unlikely(err
)) {
16468 wl_clr_drv_status(cfg
, SCANNING
, ndev
);
16471 p2p_scan(cfg
) = false;
16474 wl_set_drv_status(cfg
, SCANNING
, ndev
);
16475 #if FULL_ESCAN_ON_PFN_NET_FOUND
16476 WL_PNO((">>> Doing Full ESCAN on PNO event\n"));
16477 err
= wl_do_escan(cfg
, wiphy
, ndev
, NULL
);
16479 WL_PNO((">>> Doing targeted ESCAN on PNO event\n"));
16480 err
= wl_do_escan(cfg
, wiphy
, ndev
, request
);
16483 wl_clr_drv_status(cfg
, SCANNING
, ndev
);
16486 DBG_EVENT_LOG(dhdp
, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED
);
16487 cfg
->sched_scan_running
= TRUE
;
16490 WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
16493 WL_ERR(("Unsupported version %d, expected %d or %d\n", pfn_result_v1
->version
,
16494 PFN_SCANRESULT_VERSION_V1
, PFN_SCANRESULT_VERSION_V2
));
16499 MFREE(cfg
->osh
, request
,
16500 sizeof(*request
) + sizeof(*request
->channels
) * n_pfn_results
);
16503 MFREE(cfg
->osh
, channel
,
16504 (sizeof(struct ieee80211_channel
) * n_pfn_results
));
16508 if (event_data
->tlvs
) {
16509 MFREE(cfg
->osh
, event_data
->tlvs
, tlv_len
);
16511 MFREE(cfg
->osh
, event_data
, alloc_len
);
16515 #endif /* WL_SCHED_SCAN */
16517 static void wl_init_conf(struct wl_conf
*conf
)
16519 WL_DBG(("Enter \n"));
16520 conf
->frag_threshold
= (u32
)-1;
16521 conf
->rts_threshold
= (u32
)-1;
16522 conf
->retry_short
= (u32
)-1;
16523 conf
->retry_long
= (u32
)-1;
16524 conf
->tx_power
= -1;
16527 static void wl_init_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
16529 unsigned long flags
;
16530 struct wl_profile
*profile
= wl_get_profile_by_netdev(cfg
, ndev
);
16532 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
16533 memset(profile
, 0, sizeof(struct wl_profile
));
16534 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
16537 static void wl_init_event_handler(struct bcm_cfg80211
*cfg
)
16539 memset(cfg
->evt_handler
, 0, sizeof(cfg
->evt_handler
));
16541 cfg
->evt_handler
[WLC_E_SCAN_COMPLETE
] = wl_notify_scan_status
;
16542 cfg
->evt_handler
[WLC_E_AUTH
] = wl_notify_connect_status
;
16543 cfg
->evt_handler
[WLC_E_ASSOC
] = wl_notify_connect_status
;
16544 cfg
->evt_handler
[WLC_E_LINK
] = wl_notify_connect_status
;
16545 cfg
->evt_handler
[WLC_E_DEAUTH_IND
] = wl_notify_connect_status
;
16546 cfg
->evt_handler
[WLC_E_DEAUTH
] = wl_notify_connect_status
;
16547 cfg
->evt_handler
[WLC_E_DISASSOC_IND
] = wl_notify_connect_status
;
16548 cfg
->evt_handler
[WLC_E_ASSOC_IND
] = wl_notify_connect_status
;
16549 cfg
->evt_handler
[WLC_E_REASSOC_IND
] = wl_notify_connect_status
;
16550 cfg
->evt_handler
[WLC_E_ROAM
] = wl_notify_roaming_status
;
16551 cfg
->evt_handler
[WLC_E_MIC_ERROR
] = wl_notify_mic_status
;
16552 cfg
->evt_handler
[WLC_E_SET_SSID
] = wl_notify_connect_status
;
16553 cfg
->evt_handler
[WLC_E_ACTION_FRAME_RX
] = wl_notify_rx_mgmt_frame
;
16554 cfg
->evt_handler
[WLC_E_PROBREQ_MSG
] = wl_notify_rx_mgmt_frame
;
16555 cfg
->evt_handler
[WLC_E_P2P_PROBREQ_MSG
] = wl_notify_rx_mgmt_frame
;
16556 cfg
->evt_handler
[WLC_E_P2P_DISC_LISTEN_COMPLETE
] = wl_cfgp2p_listen_complete
;
16557 cfg
->evt_handler
[WLC_E_ACTION_FRAME_COMPLETE
] = wl_cfgp2p_action_tx_complete
;
16558 cfg
->evt_handler
[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
] = wl_cfgp2p_action_tx_complete
;
16559 cfg
->evt_handler
[WLC_E_JOIN
] = wl_notify_connect_status
;
16560 cfg
->evt_handler
[WLC_E_START
] = wl_notify_connect_status
;
16562 cfg
->evt_handler
[WLC_E_PFN_NET_FOUND
] = wl_notify_pfn_status
;
16563 #endif /* PNO_SUPPORT */
16564 #ifdef GSCAN_SUPPORT
16565 cfg
->evt_handler
[WLC_E_PFN_BEST_BATCHING
] = wl_notify_gscan_event
;
16566 cfg
->evt_handler
[WLC_E_PFN_SCAN_COMPLETE
] = wl_notify_gscan_event
;
16567 cfg
->evt_handler
[WLC_E_PFN_GSCAN_FULL_RESULT
] = wl_notify_gscan_event
;
16568 cfg
->evt_handler
[WLC_E_PFN_BSSID_NET_FOUND
] = wl_notify_gscan_event
;
16569 cfg
->evt_handler
[WLC_E_PFN_BSSID_NET_LOST
] = wl_notify_gscan_event
;
16570 cfg
->evt_handler
[WLC_E_PFN_SSID_EXT
] = wl_notify_gscan_event
;
16571 cfg
->evt_handler
[WLC_E_GAS_FRAGMENT_RX
] = wl_notify_gscan_event
;
16572 cfg
->evt_handler
[WLC_E_ROAM_EXP_EVENT
] = wl_handle_roam_exp_event
;
16573 #endif /* GSCAN_SUPPORT */
16574 #ifdef RSSI_MONITOR_SUPPORT
16575 cfg
->evt_handler
[WLC_E_RSSI_LQM
] = wl_handle_rssi_monitor_event
;
16576 #endif /* RSSI_MONITOR_SUPPORT */
16578 cfg
->evt_handler
[WLC_E_TDLS_PEER_EVENT
] = wl_tdls_event_handler
;
16579 #endif /* WLTDLS */
16580 cfg
->evt_handler
[WLC_E_BSSID
] = wl_notify_roaming_status
;
16582 cfg
->evt_handler
[WLC_E_AIBSS_TXFAIL
] = wl_notify_aibss_txfail
;
16583 #endif /* WLAIBSS */
16585 cfg
->evt_handler
[WLC_E_RMC_EVENT
] = wl_notify_rmc_status
;
16586 #endif /* WL_RELMCAST */
16587 #ifdef BT_WIFI_HANDOVER
16588 cfg
->evt_handler
[WLC_E_BT_WIFI_HANDOVER_REQ
] = wl_notify_bt_wifi_handover_req
;
16591 cfg
->evt_handler
[WLC_E_NAN_CRITICAL
] = wl_cfgnan_notify_nan_status
;
16592 cfg
->evt_handler
[WLC_E_NAN_NON_CRITICAL
] = wl_cfgnan_notify_nan_status
;
16593 #endif /* WL_NAN */
16594 cfg
->evt_handler
[WLC_E_CSA_COMPLETE_IND
] = wl_csa_complete_ind
;
16595 cfg
->evt_handler
[WLC_E_AP_STARTED
] = wl_ap_start_ind
;
16596 #ifdef CUSTOM_EVENT_PM_WAKE
16597 cfg
->evt_handler
[WLC_E_EXCESS_PM_WAKE_EVENT
] = wl_check_pmstatus
;
16598 #endif /* CUSTOM_EVENT_PM_WAKE */
16599 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
16600 cfg
->evt_handler
[WLC_E_ROAM_PREP
] = wl_notify_roam_prep_status
;
16601 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
16602 cfg
->evt_handler
[WLC_E_ROAM_START
] = wl_notify_roam_start_status
;
16604 cfg
->evt_handler
[WLC_E_ADPS
] = wl_adps_event_handler
;
16605 #endif /* WL_BAM */
16607 cfg
->evt_handler
[WLC_E_BCNRECV_ABORTED
] = wl_bcnrecv_aborted_event_handler
;
16608 #endif /* WL_BCNRECV */
16611 #if defined(STATIC_WL_PRIV_STRUCT)
16613 wl_init_escan_result_buf(struct bcm_cfg80211
*cfg
)
16615 #ifdef DUAL_ESCAN_RESULT_BUFFER
16616 cfg
->escan_info
.escan_buf
[0] = DHD_OS_PREALLOC(cfg
->pub
,
16617 DHD_PREALLOC_WIPHY_ESCAN0
, ESCAN_BUF_SIZE
);
16618 if (cfg
->escan_info
.escan_buf
[0] == NULL
) {
16619 WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
16623 cfg
->escan_info
.escan_buf
[1] = DHD_OS_PREALLOC(cfg
->pub
,
16624 DHD_PREALLOC_WIPHY_ESCAN1
, ESCAN_BUF_SIZE
);
16625 if (cfg
->escan_info
.escan_buf
[1] == NULL
) {
16626 WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
16630 bzero(cfg
->escan_info
.escan_buf
[0], ESCAN_BUF_SIZE
);
16631 bzero(cfg
->escan_info
.escan_buf
[1], ESCAN_BUF_SIZE
);
16632 cfg
->escan_info
.escan_type
[0] = 0;
16633 cfg
->escan_info
.escan_type
[1] = 0;
16635 cfg
->escan_info
.escan_buf
= DHD_OS_PREALLOC(cfg
->pub
,
16636 DHD_PREALLOC_WIPHY_ESCAN0
, ESCAN_BUF_SIZE
);
16637 if (cfg
->escan_info
.escan_buf
== NULL
) {
16638 WL_ERR(("Failed to alloc ESCAN_BUF\n"));
16641 bzero(cfg
->escan_info
.escan_buf
, ESCAN_BUF_SIZE
);
16642 #endif /* DUAL_ESCAN_RESULT_BUFFER */
16648 wl_deinit_escan_result_buf(struct bcm_cfg80211
*cfg
)
16650 #ifdef DUAL_ESCAN_RESULT_BUFFER
16651 if (cfg
->escan_info
.escan_buf
[0] != NULL
) {
16652 cfg
->escan_info
.escan_buf
[0] = NULL
;
16653 cfg
->escan_info
.escan_type
[0] = 0;
16656 if (cfg
->escan_info
.escan_buf
[1] != NULL
) {
16657 cfg
->escan_info
.escan_buf
[1] = NULL
;
16658 cfg
->escan_info
.escan_type
[1] = 0;
16661 if (cfg
->escan_info
.escan_buf
!= NULL
) {
16662 cfg
->escan_info
.escan_buf
= NULL
;
16664 #endif /* DUAL_ESCAN_RESULT_BUFFER */
16666 #endif /* STATIC_WL_PRIV_STRUCT */
16668 static s32
wl_init_priv_mem(struct bcm_cfg80211
*cfg
)
16670 WL_DBG(("Enter \n"));
16672 cfg
->scan_results
= (struct wl_scan_results
*)MALLOCZ(cfg
->osh
,
16674 if (unlikely(!cfg
->scan_results
)) {
16675 WL_ERR(("Scan results alloc failed\n"));
16676 goto init_priv_mem_out
;
16678 cfg
->conf
= (struct wl_conf
*)MALLOCZ(cfg
->osh
, sizeof(*cfg
->conf
));
16679 if (unlikely(!cfg
->conf
)) {
16680 WL_ERR(("wl_conf alloc failed\n"));
16681 goto init_priv_mem_out
;
16683 cfg
->scan_req_int
= (void *)MALLOCZ(cfg
->osh
,
16684 sizeof(*cfg
->scan_req_int
));
16685 if (unlikely(!cfg
->scan_req_int
)) {
16686 WL_ERR(("Scan req alloc failed\n"));
16687 goto init_priv_mem_out
;
16689 cfg
->ioctl_buf
= (u8
*)MALLOCZ(cfg
->osh
, WLC_IOCTL_MAXLEN
);
16690 if (unlikely(!cfg
->ioctl_buf
)) {
16691 WL_ERR(("Ioctl buf alloc failed\n"));
16692 goto init_priv_mem_out
;
16694 cfg
->escan_ioctl_buf
= (void *)MALLOCZ(cfg
->osh
, WLC_IOCTL_MAXLEN
);
16695 if (unlikely(!cfg
->escan_ioctl_buf
)) {
16696 WL_ERR(("Ioctl buf alloc failed\n"));
16697 goto init_priv_mem_out
;
16699 cfg
->extra_buf
= (void *)MALLOCZ(cfg
->osh
, WL_EXTRA_BUF_MAX
);
16700 if (unlikely(!cfg
->extra_buf
)) {
16701 WL_ERR(("Extra buf alloc failed\n"));
16702 goto init_priv_mem_out
;
16704 cfg
->pmk_list
= (void *)MALLOCZ(cfg
->osh
, sizeof(*cfg
->pmk_list
));
16705 if (unlikely(!cfg
->pmk_list
)) {
16706 WL_ERR(("pmk list alloc failed\n"));
16707 goto init_priv_mem_out
;
16709 #if defined(STATIC_WL_PRIV_STRUCT)
16710 cfg
->conn_info
= (void *)MALLOCZ(cfg
->osh
, sizeof(*cfg
->conn_info
));
16711 if (unlikely(!cfg
->conn_info
)) {
16712 WL_ERR(("cfg->conn_info alloc failed\n"));
16713 goto init_priv_mem_out
;
16715 cfg
->ie
= (void *)MALLOC(cfg
->osh
, sizeof(*cfg
->ie
));
16716 if (unlikely(!cfg
->ie
)) {
16717 WL_ERR(("cfg->ie alloc failed\n"));
16718 goto init_priv_mem_out
;
16720 if (unlikely(wl_init_escan_result_buf(cfg
))) {
16721 WL_ERR(("Failed to init escan resul buf\n"));
16722 goto init_priv_mem_out
;
16724 #endif /* STATIC_WL_PRIV_STRUCT */
16725 cfg
->afx_hdl
= (void *)MALLOCZ(cfg
->osh
, sizeof(*cfg
->afx_hdl
));
16726 if (unlikely(!cfg
->afx_hdl
)) {
16727 WL_ERR(("afx hdl alloc failed\n"));
16728 goto init_priv_mem_out
;
16730 init_completion(&cfg
->act_frm_scan
);
16731 init_completion(&cfg
->wait_next_af
);
16733 INIT_WORK(&cfg
->afx_hdl
->work
, wl_cfg80211_afx_handler
);
16736 if (cfg
->tdls_mgmt_frame
) {
16737 MFREE(cfg
->osh
, cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
);
16738 cfg
->tdls_mgmt_frame
= NULL
;
16739 cfg
->tdls_mgmt_frame_len
= 0;
16741 #endif /* WLTDLS */
16745 wl_deinit_priv_mem(cfg
);
16750 static void wl_deinit_priv_mem(struct bcm_cfg80211
*cfg
)
16752 MFREE(cfg
->osh
, cfg
->scan_results
, WL_SCAN_BUF_MAX
);
16753 cfg
->scan_results
= NULL
;
16754 MFREE(cfg
->osh
, cfg
->conf
, sizeof(*cfg
->conf
));
16756 MFREE(cfg
->osh
, cfg
->scan_req_int
, sizeof(*cfg
->scan_req_int
));
16757 cfg
->scan_req_int
= NULL
;
16758 MFREE(cfg
->osh
, cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
);
16759 cfg
->ioctl_buf
= NULL
;
16760 MFREE(cfg
->osh
, cfg
->escan_ioctl_buf
, WLC_IOCTL_MAXLEN
);
16761 cfg
->escan_ioctl_buf
= NULL
;
16762 MFREE(cfg
->osh
, cfg
->extra_buf
, WL_EXTRA_BUF_MAX
);
16763 cfg
->extra_buf
= NULL
;
16764 MFREE(cfg
->osh
, cfg
->pmk_list
, sizeof(*cfg
->pmk_list
));
16765 cfg
->pmk_list
= NULL
;
16766 #if defined(STATIC_WL_PRIV_STRUCT)
16767 MFREE(cfg
->osh
, cfg
->conn_info
, sizeof(*cfg
->conn_info
));
16768 cfg
->conn_info
= NULL
;
16769 MFREE(cfg
->osh
, cfg
->ie
, sizeof(*cfg
->ie
));
16771 wl_deinit_escan_result_buf(cfg
);
16772 #endif /* STATIC_WL_PRIV_STRUCT */
16773 if (cfg
->afx_hdl
) {
16774 cancel_work_sync(&cfg
->afx_hdl
->work
);
16775 MFREE(cfg
->osh
, cfg
->afx_hdl
, sizeof(*cfg
->afx_hdl
));
16776 cfg
->afx_hdl
= NULL
;
16781 static s32
wl_create_event_handler(struct bcm_cfg80211
*cfg
)
16784 WL_DBG(("Enter \n"));
16786 /* Allocate workqueue for event */
16787 if (!cfg
->event_workq
) {
16788 cfg
->event_workq
= alloc_workqueue("dhd_eventd",
16789 WQ_MEM_RECLAIM
| WQ_HIGHPRI
| WQ_UNBOUND
, 1);
16792 if (!cfg
->event_workq
) {
16795 INIT_WORK(&cfg
->event_work
, wl_event_handler
);
16800 static void wl_destroy_event_handler(struct bcm_cfg80211
*cfg
)
16802 if (cfg
&& cfg
->event_workq
) {
16803 cancel_work_sync(&cfg
->event_work
);
16804 destroy_workqueue(cfg
->event_workq
);
16805 cfg
->event_workq
= NULL
;
16809 void wl_terminate_event_handler(struct net_device
*dev
)
16811 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
16814 wl_destroy_event_handler(cfg
);
16819 static void wl_scan_timeout(unsigned long data
)
16821 wl_event_msg_t msg
;
16822 struct bcm_cfg80211
*cfg
= (struct bcm_cfg80211
*)data
;
16823 struct wireless_dev
*wdev
= NULL
;
16824 struct net_device
*ndev
= NULL
;
16825 struct wl_scan_results
*bss_list
;
16826 wl_bss_info_t
*bi
= NULL
;
16829 u64 cur_time
= OSL_LOCALTIME_NS();
16830 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
16831 #ifdef DHD_FW_COREDUMP
16832 uint32 prev_memdump_mode
= dhdp
->memdump_enabled
;
16833 #endif /* DHD_FW_COREDUMP */
16834 unsigned long flags
;
16836 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
16837 if (!(cfg
->scan_request
)) {
16838 WL_ERR(("timer expired but no scan request\n"));
16839 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
16842 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
16843 if (cfg
->scan_request
->dev
) {
16844 wdev
= cfg
->scan_request
->dev
->ieee80211_ptr
;
16847 wdev
= cfg
->scan_request
->wdev
;
16848 #endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
16849 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
16852 WL_ERR(("No wireless_dev present\n"));
16857 #if defined(DHD_KERNEL_SCHED_DEBUG) && defined(DHD_FW_COREDUMP)
16858 if (prev_memdump_mode
&& !dhd_query_bus_erros(dhdp
) &&
16859 ((cfg
->scan_deq_time
< cfg
->scan_enq_time
) ||
16860 dhd_bus_query_dpc_sched_errors(dhdp
))) {
16861 WL_ERR(("****SCAN event timeout due to scheduling problem\n"));
16862 /* change g_assert_type to trigger Kernel panic */
16864 /* use ASSERT() to trigger panic */
16867 #endif /* DHD_KERNEL_SCHED_DEBUG && DHD_FW_COREDUMP */
16869 WL_ERR(("***SCAN event timeout. WQ state:0x%x scan_enq_time:"SEC_USEC_FMT
16870 " evt_hdlr_entry_time:"SEC_USEC_FMT
" evt_deq_time:"SEC_USEC_FMT
16871 "\nscan_deq_time:"SEC_USEC_FMT
" scan_hdlr_cmplt_time:"SEC_USEC_FMT
16872 " scan_cmplt_time:"SEC_USEC_FMT
" evt_hdlr_exit_time:"SEC_USEC_FMT
16873 "\ncurrent_time:"SEC_USEC_FMT
"\n", work_busy(&cfg
->event_work
),
16874 GET_SEC_USEC(cfg
->scan_enq_time
), GET_SEC_USEC(cfg
->wl_evt_hdlr_entry_time
),
16875 GET_SEC_USEC(cfg
->wl_evt_deq_time
), GET_SEC_USEC(cfg
->scan_deq_time
),
16876 GET_SEC_USEC(cfg
->scan_hdlr_cmplt_time
), GET_SEC_USEC(cfg
->scan_cmplt_time
),
16877 GET_SEC_USEC(cfg
->wl_evt_hdlr_exit_time
), GET_SEC_USEC(cur_time
)));
16878 if (cfg
->scan_enq_time
) {
16879 WL_ERR(("Elapsed time(ns): %llu\n", (cur_time
- cfg
->scan_enq_time
)));
16881 WL_ERR(("lock_states:[%d:%d:%d:%d:%d:%d]\n",
16882 mutex_is_locked(&cfg
->if_sync
),
16883 mutex_is_locked(&cfg
->usr_sync
),
16884 mutex_is_locked(&cfg
->pm_sync
),
16885 mutex_is_locked(&cfg
->scan_sync
),
16886 spin_is_locked(&cfg
->cfgdrv_lock
),
16887 spin_is_locked(&cfg
->eq_lock
)));
16888 dhd_bus_intr_count_dump(dhdp
);
16890 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) && !defined(CONFIG_MODULES)
16891 /* Print WQ states. Enable only for in-built drivers as the symbol is not exported */
16892 show_workqueue_state();
16893 #endif /* LINUX_VER >= 4.1 && !CONFIG_MODULES */
16895 bss_list
= wl_escan_get_buf(cfg
, FALSE
);
16897 WL_ERR(("bss_list is null. Didn't receive any partial scan results\n"));
16899 WL_ERR(("Dump scan buffer:\n"
16900 "scanned AP count (%d)\n", bss_list
->count
));
16902 bi
= next_bss(bss_list
, bi
);
16903 for_each_bss(bss_list
, bi
, i
) {
16904 channel
= wf_chspec_ctlchan(wl_chspec_driver_to_host(bi
->chanspec
));
16905 WL_ERR(("SSID :%s Channel :%d\n", bi
->SSID
, channel
));
16909 ndev
= wdev_to_wlc_ndev(wdev
, cfg
);
16910 bzero(&msg
, sizeof(wl_event_msg_t
));
16911 WL_ERR(("timer expired\n"));
16913 (void)dhd_pcie_dump_int_regs(dhdp
);
16914 dhd_pcie_dump_rc_conf_space_cap(dhdp
);
16915 #endif /* BCMPCIE */
16916 #ifdef DHD_FW_COREDUMP
16917 if (dhdp
->memdump_enabled
) {
16918 dhdp
->memdump_enabled
= DUMP_MEMFILE
;
16919 dhdp
->memdump_type
= DUMP_TYPE_SCAN_TIMEOUT
;
16920 dhd_bus_mem_dump(dhdp
);
16921 dhdp
->memdump_enabled
= prev_memdump_mode
;
16923 #endif /* DHD_FW_COREDUMP */
16924 msg
.event_type
= hton32(WLC_E_ESCAN_RESULT
);
16925 msg
.status
= hton32(WLC_E_STATUS_TIMEOUT
);
16926 msg
.reason
= 0xFFFFFFFF;
16927 wl_cfg80211_event(ndev
, &msg
, NULL
);
16928 #ifdef CUSTOMER_HW4_DEBUG
16929 if (!wl_scan_timeout_dbg_enabled
)
16930 wl_scan_timeout_dbg_set();
16931 #endif /* CUSTOMER_HW4_DEBUG */
16934 #ifdef DHD_LOSSLESS_ROAMING
16935 static void wl_del_roam_timeout(struct bcm_cfg80211
*cfg
)
16937 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
16939 /* restore prec_map to ALLPRIO */
16940 dhdp
->dequeue_prec_map
= ALLPRIO
;
16941 if (timer_pending(&cfg
->roam_timeout
)) {
16942 del_timer_sync(&cfg
->roam_timeout
);
16947 static void wl_roam_timeout(unsigned long data
)
16949 struct bcm_cfg80211
*cfg
= (struct bcm_cfg80211
*)data
;
16950 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
16952 WL_ERR(("roam timer expired\n"));
16954 /* restore prec_map to ALLPRIO */
16955 dhdp
->dequeue_prec_map
= ALLPRIO
;
16958 #endif /* DHD_LOSSLESS_ROAMING */
16961 wl_cfg80211_netdev_notifier_call(struct notifier_block
* nb
,
16962 unsigned long state
, void *ptr
)
16964 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
16965 struct net_device
*dev
= ptr
;
16967 struct net_device
*dev
= netdev_notifier_info_to_dev(ptr
);
16968 #endif /* LINUX_VERSION < VERSION(3, 11, 0) */
16969 struct wireless_dev
*wdev
= NULL
;
16970 struct bcm_cfg80211
*cfg
= NULL
;
16972 WL_DBG(("Enter state:%lu ndev%p \n", state
, dev
));
16974 WL_ERR(("dev null\n"));
16975 return NOTIFY_DONE
;
16978 wdev
= ndev_to_wdev(dev
);
16980 WL_ERR(("wdev null. Do nothing\n"));
16981 return NOTIFY_DONE
;
16984 cfg
= (struct bcm_cfg80211
*)wiphy_priv(wdev
->wiphy
);
16985 if (!cfg
|| (cfg
!= wl_cfg80211_get_bcmcfg())) {
16986 /* If cfg80211 priv is null or doesn't match return */
16987 WL_ERR(("wrong cfg ptr (%p)\n", cfg
));
16988 return NOTIFY_DONE
;
16991 if (dev
== bcmcfg_to_prmry_ndev(cfg
)) {
16992 /* Nothing to be done for primary I/F */
16993 return NOTIFY_DONE
;
16999 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
17000 int max_wait_timeout
= 2;
17001 int max_wait_count
= 100;
17003 unsigned long limit
= jiffies
+ max_wait_timeout
* HZ
;
17004 while (work_pending(&wdev
->cleanup_work
)) {
17005 if (refcnt
%5 == 0) {
17006 WL_ERR(("[NETDEV_DOWN] wait for "
17007 "complete of cleanup_work"
17008 " (%d th)\n", refcnt
));
17010 if (!time_before(jiffies
, limit
)) {
17011 WL_ERR(("[NETDEV_DOWN] cleanup_work"
17012 " of CFG80211 is not"
17013 " completed in %d sec\n",
17014 max_wait_timeout
));
17017 if (refcnt
>= max_wait_count
) {
17018 WL_ERR(("[NETDEV_DOWN] cleanup_work"
17019 " of CFG80211 is not"
17020 " completed in %d loop\n",
17024 set_current_state(TASK_INTERRUPTIBLE
);
17025 (void)schedule_timeout(100);
17026 set_current_state(TASK_RUNNING
);
17029 #endif /* LINUX_VERSION < VERSION(3, 14, 0) */
17032 case NETDEV_UNREGISTER
:
17033 wl_cfg80211_clear_per_bss_ies(cfg
, wdev
);
17034 /* after calling list_del_rcu(&wdev->list) */
17035 wl_dealloc_netinfo_by_wdev(cfg
, wdev
);
17037 case NETDEV_GOING_DOWN
:
17039 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
17040 * In front of door, the function checks whether current scan
17041 * is working or not. If the scanning is still working,
17042 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
17044 if (wl_get_drv_status(cfg
, SCANNING
, dev
))
17045 wl_cfg80211_cancel_scan(cfg
);
17048 return NOTIFY_DONE
;
17051 static struct notifier_block wl_cfg80211_netdev_notifier
= {
17052 .notifier_call
= wl_cfg80211_netdev_notifier_call
,
17056 * to make sure we won't register the same notifier twice, otherwise a loop is likely to be
17057 * created in kernel notifier link list (with 'next' pointing to itself)
17059 static bool wl_cfg80211_netdev_notifier_registered
= FALSE
;
17061 static void wl_cfg80211_cancel_scan(struct bcm_cfg80211
*cfg
)
17063 struct wireless_dev
*wdev
= NULL
;
17064 struct net_device
*ndev
= NULL
;
17066 mutex_lock(&cfg
->scan_sync
);
17067 if (!cfg
->scan_request
) {
17071 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
17072 if (cfg
->scan_request
->dev
)
17073 wdev
= cfg
->scan_request
->dev
->ieee80211_ptr
;
17075 wdev
= cfg
->scan_request
->wdev
;
17076 #endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
17079 WL_ERR(("No wireless_dev present\n"));
17083 ndev
= wdev_to_wlc_ndev(wdev
, cfg
);
17084 wl_notify_escan_complete(cfg
, ndev
, true, true);
17085 WL_INFORM_MEM(("Scan aborted! \n"));
17087 mutex_unlock(&cfg
->scan_sync
);
17090 void wl_cfg80211_scan_abort(struct bcm_cfg80211
*cfg
)
17092 wl_scan_params_t
*params
= NULL
;
17093 s32 params_size
= 0;
17095 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
17096 if (!in_atomic()) {
17097 /* Our scan params only need space for 1 channel and 0 ssids */
17098 params
= wl_cfg80211_scan_alloc_params(cfg
, -1, 0, ¶ms_size
);
17099 if (params
== NULL
) {
17100 WL_ERR(("scan params allocation failed \n"));
17103 /* Do a scan abort to stop the driver's scan engine */
17104 err
= wldev_ioctl_set(dev
, WLC_SCAN
, params
, params_size
);
17106 /* scan abort can fail if there is no outstanding scan */
17107 WL_DBG(("scan abort failed \n"));
17109 MFREE(cfg
->osh
, params
, params_size
);
17113 if (cfg
->tdls_mgmt_frame
) {
17114 MFREE(cfg
->osh
, cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
);
17115 cfg
->tdls_mgmt_frame
= NULL
;
17116 cfg
->tdls_mgmt_frame_len
= 0;
17118 #endif /* WLTDLS */
17121 static s32
wl_notify_escan_complete(struct bcm_cfg80211
*cfg
,
17122 struct net_device
*ndev
,
17123 bool aborted
, bool fw_abort
)
17126 unsigned long flags
;
17127 struct net_device
*dev
;
17128 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
17130 WL_DBG(("Enter \n"));
17131 BCM_REFERENCE(dhdp
);
17134 WL_ERR(("ndev is null\n"));
17139 if (cfg
->escan_info
.ndev
!= ndev
) {
17140 WL_ERR(("Outstanding scan req ndev not matching (%p:%p)\n",
17141 cfg
->escan_info
.ndev
, ndev
));
17146 if (cfg
->scan_request
) {
17147 dev
= bcmcfg_to_prmry_ndev(cfg
);
17148 #if defined(WL_ENABLE_P2P_IF)
17149 if (cfg
->scan_request
->dev
!= cfg
->p2p_net
)
17150 dev
= cfg
->scan_request
->dev
;
17151 #elif defined(WL_CFG80211_P2P_DEV_IF)
17152 if (cfg
->scan_request
->wdev
->iftype
!= NL80211_IFTYPE_P2P_DEVICE
)
17153 dev
= cfg
->scan_request
->wdev
->netdev
;
17154 #endif /* WL_ENABLE_P2P_IF */
17157 WL_DBG(("cfg->scan_request is NULL. Internal scan scenario."
17158 "doing scan_abort for ndev %p primary %p",
17159 ndev
, bcmcfg_to_prmry_ndev(cfg
)));
17162 if (fw_abort
&& !in_atomic())
17163 wl_cfg80211_scan_abort(cfg
);
17164 if (timer_pending(&cfg
->scan_timeout
))
17165 del_timer_sync(&cfg
->scan_timeout
);
17166 cfg
->scan_enq_time
= 0;
17167 #if defined(ESCAN_RESULT_PATCH)
17168 if (likely(cfg
->scan_request
)) {
17169 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
17170 if (aborted
&& p2p_scan(cfg
) &&
17171 (cfg
->scan_request
->flags
& NL80211_SCAN_FLAG_FLUSH
)) {
17172 WL_ERR(("scan list is changed"));
17173 cfg
->bss_list
= wl_escan_get_buf(cfg
, !aborted
);
17176 cfg
->bss_list
= wl_escan_get_buf(cfg
, aborted
);
17178 wl_inform_bss(cfg
);
17180 #endif /* ESCAN_RESULT_PATCH */
17181 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
17182 #ifdef WL_SCHED_SCAN
17183 if (cfg
->sched_scan_req
&& !cfg
->scan_request
) {
17185 WL_INFORM_MEM(("[%s] Report sched scan done.\n", dev
->name
));
17186 cfg80211_sched_scan_results(cfg
->sched_scan_req
->wiphy
);
17189 DBG_EVENT_LOG(dhdp
, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE
);
17190 cfg
->sched_scan_running
= FALSE
;
17192 #endif /* WL_SCHED_SCAN */
17193 if (likely(cfg
->scan_request
)) {
17194 WL_INFORM_MEM(("[%s] Report scan done.\n", dev
->name
));
17195 wl_notify_scan_done(cfg
, aborted
);
17196 cfg
->scan_request
= NULL
;
17198 if (p2p_is_on(cfg
))
17199 wl_clr_p2p_status(cfg
, SCANNING
);
17200 wl_clr_drv_status(cfg
, SCANNING
, dev
);
17202 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t
*)(cfg
->pub
));
17203 DHD_ENABLE_RUNTIME_PM((dhd_pub_t
*)(cfg
->pub
));
17204 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
17210 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17211 #ifndef WL_DRV_AVOID_SCANCACHE
17213 wl_cfg80211_find_removal_candidate(wl_bss_info_t
*bss
, removal_element_t
*candidate
)
17216 for (idx
= 0; idx
< BUF_OVERFLOW_MGMT_COUNT
; idx
++) {
17217 int len
= BUF_OVERFLOW_MGMT_COUNT
- idx
- 1;
17218 if (bss
->RSSI
< candidate
[idx
].RSSI
) {
17220 memcpy(&candidate
[idx
+ 1], &candidate
[idx
],
17221 sizeof(removal_element_t
) * len
);
17222 candidate
[idx
].RSSI
= bss
->RSSI
;
17223 candidate
[idx
].length
= bss
->length
;
17224 memcpy(&candidate
[idx
].BSSID
, &bss
->BSSID
, ETHER_ADDR_LEN
);
17231 wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t
*list
, removal_element_t
*candidate
,
17235 int total_delete_len
= 0;
17236 for (idx1
= 0; idx1
< BUF_OVERFLOW_MGMT_COUNT
; idx1
++) {
17237 int cur_len
= WL_SCAN_RESULTS_FIXED_SIZE
;
17238 wl_bss_info_t
*bss
= NULL
;
17239 if (candidate
[idx1
].RSSI
>= bi
->RSSI
)
17241 for (idx2
= 0; idx2
< list
->count
; idx2
++) {
17242 bss
= bss
? (wl_bss_info_t
*)((uintptr
)bss
+ dtoh32(bss
->length
)) :
17244 if (!bcmp(&candidate
[idx1
].BSSID
, &bss
->BSSID
, ETHER_ADDR_LEN
) &&
17245 candidate
[idx1
].RSSI
== bss
->RSSI
&&
17246 candidate
[idx1
].length
== dtoh32(bss
->length
)) {
17247 u32 delete_len
= dtoh32(bss
->length
);
17248 WL_DBG(("delete scan info of " MACDBG
" to add new AP\n",
17249 MAC2STRDBG(bss
->BSSID
.octet
)));
17250 if (idx2
< list
->count
-1) {
17251 memmove((u8
*)bss
, (u8
*)bss
+ delete_len
,
17252 list
->buflen
- cur_len
- delete_len
);
17254 list
->buflen
-= delete_len
;
17256 total_delete_len
+= delete_len
;
17257 /* if delete_len is greater than or equal to result length */
17258 if (total_delete_len
>= bi
->length
) {
17263 cur_len
+= dtoh32(bss
->length
);
17267 #endif /* WL_DRV_AVOID_SCANCACHE */
17268 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17270 #ifdef WL_DRV_AVOID_SCANCACHE
17271 static u32
wl_p2p_find_peer_channel(struct bcm_cfg80211
*cfg
, s32 status
, wl_bss_info_t
*bi
,
17275 u8
*p2p_dev_addr
= NULL
;
17277 ret
= wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
);
17281 if (status
== WLC_E_STATUS_PARTIAL
) {
17282 p2p_dev_addr
= wl_cfgp2p_retreive_p2p_dev_addr(bi
, bi_length
);
17283 if (p2p_dev_addr
&& !memcmp(p2p_dev_addr
,
17284 cfg
->afx_hdl
->tx_dst_addr
.octet
, ETHER_ADDR_LEN
)) {
17285 s32 channel
= wf_chspec_ctlchan(
17286 wl_chspec_driver_to_host(bi
->chanspec
));
17288 if ((channel
> MAXCHANNEL
) || (channel
<= 0)) {
17289 channel
= WL_INVALID
;
17291 WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG
" found,"
17293 MAC2STRDBG(cfg
->afx_hdl
->tx_dst_addr
.octet
),
17296 wl_clr_p2p_status(cfg
, SCANNING
);
17297 cfg
->afx_hdl
->peer_chan
= channel
;
17298 complete(&cfg
->act_frm_scan
);
17301 WL_INFORM_MEM(("ACTION FRAME SCAN DONE\n"));
17302 wl_clr_p2p_status(cfg
, SCANNING
);
17303 wl_clr_drv_status(cfg
, SCANNING
, cfg
->afx_hdl
->dev
);
17304 if (cfg
->afx_hdl
->peer_chan
== WL_INVALID
)
17305 complete(&cfg
->act_frm_scan
);
17311 static s32
wl_escan_without_scan_cache(struct bcm_cfg80211
*cfg
, wl_escan_result_t
*escan_result
,
17312 struct net_device
*ndev
, const wl_event_msg_t
*e
, s32 status
)
17317 bool aborted
= false;
17318 bool fw_abort
= false;
17319 bool notify_escan_complete
= false;
17321 if (wl_escan_check_sync_id(status
, escan_result
->sync_id
,
17322 cfg
->escan_info
.cur_sync_id
) < 0) {
17326 wl_escan_print_sync_id(status
, escan_result
->sync_id
,
17327 cfg
->escan_info
.cur_sync_id
);
17329 if (!(status
== WLC_E_STATUS_TIMEOUT
) || !(status
== WLC_E_STATUS_PARTIAL
)) {
17330 cfg
->escan_info
.escan_state
= WL_ESCAN_STATE_IDLE
;
17333 if ((likely(cfg
->scan_request
)) || (cfg
->sched_scan_running
)) {
17334 notify_escan_complete
= true;
17337 if (status
== WLC_E_STATUS_PARTIAL
) {
17338 WL_DBG(("WLC_E_STATUS_PARTIAL \n"));
17339 DBG_EVENT_LOG((dhd_pub_t
*)cfg
->pub
, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND
);
17340 if ((!escan_result
) || (dtoh16(escan_result
->bss_count
) != 1)) {
17341 WL_ERR(("Invalid escan result (NULL pointer) or invalid bss_count\n"));
17345 bi
= escan_result
->bss_info
;
17346 bi_length
= dtoh32(bi
->length
);
17348 (bi_length
!= (dtoh32(escan_result
->buflen
) - WL_ESCAN_RESULTS_FIXED_SIZE
))) {
17349 WL_ERR(("Invalid escan bss info (NULL pointer)"
17350 "or invalid bss_info length\n"));
17354 if (!(bcmcfg_to_wiphy(cfg
)->interface_modes
& BIT(NL80211_IFTYPE_ADHOC
))) {
17355 if (dtoh16(bi
->capability
) & DOT11_CAP_IBSS
) {
17356 WL_DBG(("Ignoring IBSS result\n"));
17361 if (wl_p2p_find_peer_channel(cfg
, status
, bi
, bi_length
)) {
17364 if (scan_req_match(cfg
)) {
17365 /* p2p scan && allow only probe response */
17366 if ((cfg
->p2p
->search_state
!= WL_P2P_DISC_ST_SCAN
) &&
17367 (bi
->flags
& WL_BSS_FLAGS_FROM_BEACON
))
17370 #ifdef ROAM_CHANNEL_CACHE
17371 add_roam_cache(cfg
, bi
);
17372 #endif /* ROAM_CHANNEL_CACHE */
17373 err
= wl_inform_single_bss(cfg
, bi
, false);
17374 #ifdef ROAM_CHANNEL_CACHE
17375 /* print_roam_cache(); */
17376 update_roam_cache(cfg
, ioctl_version
);
17377 #endif /* ROAM_CHANNEL_CACHE */
17380 * !Broadcast && number of ssid = 1 && number of channels =1
17381 * means specific scan to association
17383 if (wl_cfgp2p_is_p2p_specific_scan(cfg
->scan_request
)) {
17384 WL_ERR(("P2P assoc scan fast aborted.\n"));
17388 /* Directly exit from function here and
17389 * avoid sending notify completion to cfg80211
17393 } else if (status
== WLC_E_STATUS_SUCCESS
) {
17394 if (wl_p2p_find_peer_channel(cfg
, status
, NULL
, 0)) {
17397 WL_INFORM_MEM(("ESCAN COMPLETED\n"));
17398 DBG_EVENT_LOG((dhd_pub_t
*)cfg
->pub
, WIFI_EVENT_DRIVER_SCAN_COMPLETE
);
17400 /* Update escan complete status */
17404 #ifdef CUSTOMER_HW4_DEBUG
17405 if (wl_scan_timeout_dbg_enabled
)
17406 wl_scan_timeout_dbg_clear();
17407 #endif /* CUSTOMER_HW4_DEBUG */
17408 } else if ((status
== WLC_E_STATUS_ABORT
) || (status
== WLC_E_STATUS_NEWSCAN
) ||
17410 (status
== WLC_E_STATUS_CCXFASTRM
) ||
17411 #endif /* BCMCCX */
17412 (status
== WLC_E_STATUS_11HQUIET
) || (status
== WLC_E_STATUS_CS_ABORT
) ||
17413 (status
== WLC_E_STATUS_NEWASSOC
)) {
17414 /* Handle all cases of scan abort */
17416 WL_DBG(("ESCAN ABORT reason: %d\n", status
));
17417 if (wl_p2p_find_peer_channel(cfg
, status
, NULL
, 0)) {
17420 WL_INFORM_MEM(("ESCAN ABORTED\n"));
17422 /* Update escan complete status */
17426 } else if (status
== WLC_E_STATUS_TIMEOUT
) {
17427 WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg
->scan_request
));
17428 WL_ERR(("reason[0x%x]\n", e
->reason
));
17429 if (e
->reason
== 0xFFFFFFFF) {
17430 /* Update escan complete status */
17435 WL_ERR(("unexpected Escan Event %d : abort\n", status
));
17437 if (wl_p2p_find_peer_channel(cfg
, status
, NULL
, 0)) {
17440 /* Update escan complete status */
17445 /* Notify escan complete status */
17446 if (notify_escan_complete
) {
17447 wl_notify_escan_complete(cfg
, ndev
, aborted
, fw_abort
);
17454 #endif /* WL_DRV_AVOID_SCANCACHE */
17457 /* Beacon recv results handler sending to upper layer */
17459 wl_bcnrecv_result_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
17460 wl_bss_info_v109_2_t
*bi
, uint32 scan_status
)
17463 struct wiphy
*wiphy
= NULL
;
17464 wl_bcnrecv_result_t
*bcn_recv
= NULL
;
17465 struct timespec ts
;
17467 WL_ERR(("%s: bi is NULL\n", __func__
));
17468 err
= BCME_NORESOURCE
;
17471 if ((bi
->length
- bi
->ie_length
) < sizeof(wl_bss_info_v109_2_t
)) {
17472 WL_ERR(("bi info version doesn't support bcn_recv attributes\n"));
17476 if (scan_status
== WLC_E_STATUS_RXBCN
) {
17477 wiphy
= cfg
->wdev
->wiphy
;
17479 WL_ERR(("wiphy is NULL\n"));
17480 err
= BCME_NORESOURCE
;
17483 bcn_recv
= (wl_bcnrecv_result_t
*)MALLOCZ(cfg
->osh
, sizeof(*bcn_recv
));
17484 if (unlikely(!bcn_recv
)) {
17485 WL_ERR(("Failed to allocate memory\n"));
17488 memcpy((char *)bcn_recv
->SSID
, (char *)bi
->SSID
, DOT11_MAX_SSID_LEN
);
17489 memcpy(&bcn_recv
->BSSID
, &bi
->BSSID
, ETH_ALEN
);
17490 bcn_recv
->channel
= wf_chspec_ctlchan(
17491 wl_chspec_driver_to_host(bi
->chanspec
));
17492 bcn_recv
->beacon_interval
= bi
->beacon_period
;
17494 /* kernal timestamp */
17495 get_monotonic_boottime(&ts
);
17496 bcn_recv
->system_time
= ((u64
)ts
.tv_sec
*1000000)
17497 + ts
.tv_nsec
/ 1000;
17498 bcn_recv
->timestamp
[0] = bi
->timestamp
[0];
17499 bcn_recv
->timestamp
[1] = bi
->timestamp
[1];
17501 if ((err
= wl_android_bcnrecv_event(cfgdev_to_wlc_ndev(cfgdev
, cfg
),
17502 BCNRECV_ATTR_BCNINFO
, 0, 0, (uint8
*)bcn_recv
, sizeof(*bcn_recv
)))
17504 WL_ERR(("failed to send bcnrecv event, error:%d\n", err
));
17508 WL_DBG(("Ignoring Escan Event:%d \n", scan_status
));
17512 MFREE(cfg
->osh
, bcn_recv
, sizeof(*bcn_recv
));
17516 #endif /* WL_BCNRECV */
17518 static s32
wl_escan_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
17519 const wl_event_msg_t
*e
, void *data
)
17522 s32 status
= ntoh32(e
->status
);
17523 wl_escan_result_t
*escan_result
;
17524 struct net_device
*ndev
= NULL
;
17525 #ifndef WL_DRV_AVOID_SCANCACHE
17528 const wifi_p2p_ie_t
* p2p_ie
;
17529 const u8
*p2p_dev_addr
= NULL
;
17530 wl_scan_results_t
*list
;
17531 wl_bss_info_t
*bss
= NULL
;
17533 #endif /* WL_DRV_AVOID_SCANCACHE */
17535 WL_DBG((" enter event type : %d, status : %d \n",
17536 ntoh32(e
->event_type
), ntoh32(e
->status
)));
17538 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
17540 mutex_lock(&cfg
->scan_sync
);
17541 /* P2P SCAN is coming from primary interface */
17542 if (wl_get_p2p_status(cfg
, SCANNING
)) {
17543 if (wl_get_drv_status_all(cfg
, SENDING_ACT_FRM
))
17544 ndev
= cfg
->afx_hdl
->dev
;
17546 ndev
= cfg
->escan_info
.ndev
;
17548 escan_result
= (wl_escan_result_t
*)data
;
17550 if (cfg
->bcnrecv_info
.bcnrecv_state
== BEACON_RECV_STARTED
&&
17551 status
== WLC_E_STATUS_RXBCN
) {
17552 /* handle beacon recv scan results */
17553 wl_bss_info_v109_2_t
*bi_info
;
17554 bi_info
= (wl_bss_info_v109_2_t
*)escan_result
->bss_info
;
17555 err
= wl_bcnrecv_result_handler(cfg
, cfgdev
, bi_info
, status
);
17558 #endif /* WL_BCNRECV */
17559 if (!ndev
|| (!wl_get_drv_status(cfg
, SCANNING
, ndev
) && !cfg
->sched_scan_running
)) {
17560 WL_ERR_RLMT(("escan is not ready. drv_scan_status 0x%x"
17561 " e_type %d e_states %d\n",
17562 wl_get_drv_status(cfg
, SCANNING
, ndev
),
17563 ntoh32(e
->event_type
), ntoh32(e
->status
)));
17567 #ifndef WL_DRV_AVOID_SCANCACHE
17568 if (status
== WLC_E_STATUS_PARTIAL
) {
17569 WL_DBG(("WLC_E_STATUS_PARTIAL \n"));
17570 DBG_EVENT_LOG((dhd_pub_t
*)cfg
->pub
, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND
);
17571 if (!escan_result
) {
17572 WL_ERR(("Invalid escan result (NULL pointer)\n"));
17575 if ((dtoh32(escan_result
->buflen
) > (int)ESCAN_BUF_SIZE
) ||
17576 (dtoh32(escan_result
->buflen
) < sizeof(wl_escan_result_t
))) {
17577 WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result
->buflen
)));
17580 if (dtoh16(escan_result
->bss_count
) != 1) {
17581 WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result
->bss_count
));
17584 bi
= escan_result
->bss_info
;
17586 WL_ERR(("Invalid escan bss info (NULL pointer)\n"));
17589 bi_length
= dtoh32(bi
->length
);
17590 if (bi_length
!= (dtoh32(escan_result
->buflen
) - WL_ESCAN_RESULTS_FIXED_SIZE
)) {
17591 WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length
));
17594 if (wl_escan_check_sync_id(status
, escan_result
->sync_id
,
17595 cfg
->escan_info
.cur_sync_id
) < 0)
17598 if (!(bcmcfg_to_wiphy(cfg
)->interface_modes
& BIT(NL80211_IFTYPE_ADHOC
))) {
17599 if (dtoh16(bi
->capability
) & DOT11_CAP_IBSS
) {
17600 WL_DBG(("Ignoring IBSS result\n"));
17605 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
17606 p2p_dev_addr
= wl_cfgp2p_retreive_p2p_dev_addr(bi
, bi_length
);
17607 if (p2p_dev_addr
&& !memcmp(p2p_dev_addr
,
17608 cfg
->afx_hdl
->tx_dst_addr
.octet
, ETHER_ADDR_LEN
)) {
17609 s32 channel
= wf_chspec_ctlchan(
17610 wl_chspec_driver_to_host(bi
->chanspec
));
17612 if ((channel
> MAXCHANNEL
) || (channel
<= 0))
17613 channel
= WL_INVALID
;
17615 WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG
" found,"
17617 MAC2STRDBG(cfg
->afx_hdl
->tx_dst_addr
.octet
),
17620 wl_clr_p2p_status(cfg
, SCANNING
);
17621 cfg
->afx_hdl
->peer_chan
= channel
;
17622 complete(&cfg
->act_frm_scan
);
17627 int cur_len
= WL_SCAN_RESULTS_FIXED_SIZE
;
17628 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17629 removal_element_t candidate
[BUF_OVERFLOW_MGMT_COUNT
];
17630 int remove_lower_rssi
= FALSE
;
17632 bzero(candidate
, sizeof(removal_element_t
)*BUF_OVERFLOW_MGMT_COUNT
);
17633 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17635 list
= wl_escan_get_buf(cfg
, FALSE
);
17636 if (scan_req_match(cfg
)) {
17637 #ifdef WL_HOST_BAND_MGMT
17638 s32 channel_band
= 0;
17640 #endif /* WL_HOST_BAND_MGMT */
17641 /* p2p scan && allow only probe response */
17642 if ((cfg
->p2p
->search_state
!= WL_P2P_DISC_ST_SCAN
) &&
17643 (bi
->flags
& WL_BSS_FLAGS_FROM_BEACON
))
17645 if ((p2p_ie
= wl_cfgp2p_find_p2pie(((u8
*) bi
) + bi
->ie_offset
,
17646 bi
->ie_length
)) == NULL
) {
17647 WL_ERR(("Couldn't find P2PIE in probe"
17648 " response/beacon\n"));
17651 #ifdef WL_HOST_BAND_MGMT
17652 chspec
= wl_chspec_driver_to_host(bi
->chanspec
);
17653 channel_band
= CHSPEC2WLC_BAND(chspec
);
17655 if ((cfg
->curr_band
== WLC_BAND_5G
) &&
17656 (channel_band
== WLC_BAND_2G
)) {
17657 /* Avoid sending the GO results in band conflict */
17658 if (wl_cfgp2p_retreive_p2pattrib(p2p_ie
,
17659 P2P_SEID_GROUP_ID
) != NULL
)
17662 #endif /* WL_HOST_BAND_MGMT */
17664 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17665 if (bi_length
> ESCAN_BUF_SIZE
- list
->buflen
)
17666 remove_lower_rssi
= TRUE
;
17667 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17669 for (i
= 0; i
< list
->count
; i
++) {
17670 bss
= bss
? (wl_bss_info_t
*)((uintptr
)bss
+ dtoh32(bss
->length
))
17673 WL_ERR(("bss is NULL\n"));
17676 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17677 WL_TRACE(("%s("MACDBG
"), i=%d bss: RSSI %d list->count %d\n",
17678 bss
->SSID
, MAC2STRDBG(bss
->BSSID
.octet
),
17679 i
, bss
->RSSI
, list
->count
));
17681 if (remove_lower_rssi
)
17682 wl_cfg80211_find_removal_candidate(bss
, candidate
);
17683 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17685 if (!bcmp(&bi
->BSSID
, &bss
->BSSID
, ETHER_ADDR_LEN
) &&
17686 (CHSPEC_BAND(wl_chspec_driver_to_host(bi
->chanspec
))
17687 == CHSPEC_BAND(wl_chspec_driver_to_host(bss
->chanspec
))) &&
17688 bi
->SSID_len
== bss
->SSID_len
&&
17689 !bcmp(bi
->SSID
, bss
->SSID
, bi
->SSID_len
)) {
17691 /* do not allow beacon data to update
17692 *the data recd from a probe response
17694 if (!(bss
->flags
& WL_BSS_FLAGS_FROM_BEACON
) &&
17695 (bi
->flags
& WL_BSS_FLAGS_FROM_BEACON
))
17698 WL_DBG(("%s("MACDBG
"), i=%d prev: RSSI %d"
17699 " flags 0x%x, new: RSSI %d flags 0x%x\n",
17700 bss
->SSID
, MAC2STRDBG(bi
->BSSID
.octet
), i
,
17701 bss
->RSSI
, bss
->flags
, bi
->RSSI
, bi
->flags
));
17703 if ((bss
->flags
& WL_BSS_FLAGS_RSSI_ONCHANNEL
) ==
17704 (bi
->flags
& WL_BSS_FLAGS_RSSI_ONCHANNEL
)) {
17705 /* preserve max RSSI if the measurements are
17706 * both on-channel or both off-channel
17708 WL_SCAN(("%s("MACDBG
"), same onchan"
17709 ", RSSI: prev %d new %d\n",
17710 bss
->SSID
, MAC2STRDBG(bi
->BSSID
.octet
),
17711 bss
->RSSI
, bi
->RSSI
));
17712 bi
->RSSI
= MAX(bss
->RSSI
, bi
->RSSI
);
17713 } else if ((bss
->flags
& WL_BSS_FLAGS_RSSI_ONCHANNEL
) &&
17714 (bi
->flags
& WL_BSS_FLAGS_RSSI_ONCHANNEL
) == 0) {
17715 /* preserve the on-channel rssi measurement
17716 * if the new measurement is off channel
17718 WL_SCAN(("%s("MACDBG
"), prev onchan"
17719 ", RSSI: prev %d new %d\n",
17720 bss
->SSID
, MAC2STRDBG(bi
->BSSID
.octet
),
17721 bss
->RSSI
, bi
->RSSI
));
17722 bi
->RSSI
= bss
->RSSI
;
17723 bi
->flags
|= WL_BSS_FLAGS_RSSI_ONCHANNEL
;
17725 if (dtoh32(bss
->length
) != bi_length
) {
17726 u32 prev_len
= dtoh32(bss
->length
);
17728 WL_SCAN(("bss info replacement"
17729 " is occured(bcast:%d->probresp%d)\n",
17730 bss
->ie_length
, bi
->ie_length
));
17731 WL_DBG(("%s("MACDBG
"), replacement!(%d -> %d)\n",
17732 bss
->SSID
, MAC2STRDBG(bi
->BSSID
.octet
),
17733 prev_len
, bi_length
));
17735 if (list
->buflen
- prev_len
+ bi_length
17736 > ESCAN_BUF_SIZE
) {
17737 WL_ERR(("Buffer is too small: keep the"
17738 " previous result of this AP\n"));
17739 /* Only update RSSI */
17740 bss
->RSSI
= bi
->RSSI
;
17741 bss
->flags
|= (bi
->flags
17742 & WL_BSS_FLAGS_RSSI_ONCHANNEL
);
17746 if (i
< list
->count
- 1) {
17747 /* memory copy required by this case only */
17748 memmove((u8
*)bss
+ bi_length
,
17749 (u8
*)bss
+ prev_len
,
17750 list
->buflen
- cur_len
- prev_len
);
17752 list
->buflen
-= prev_len
;
17753 list
->buflen
+= bi_length
;
17755 list
->version
= dtoh32(bi
->version
);
17756 memcpy((u8
*)bss
, (u8
*)bi
, bi_length
);
17759 cur_len
+= dtoh32(bss
->length
);
17761 if (bi_length
> ESCAN_BUF_SIZE
- list
->buflen
) {
17762 #ifdef ESCAN_BUF_OVERFLOW_MGMT
17763 wl_cfg80211_remove_lowRSSI_info(list
, candidate
, bi
);
17764 if (bi_length
> ESCAN_BUF_SIZE
- list
->buflen
) {
17765 WL_DBG(("RSSI(" MACDBG
") is too low(%d) to add Buffer\n",
17766 MAC2STRDBG(bi
->BSSID
.octet
), bi
->RSSI
));
17770 WL_ERR(("Buffer is too small: ignoring\n"));
17772 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
17775 memcpy(&(((char *)list
)[list
->buflen
]), bi
, bi_length
);
17776 list
->version
= dtoh32(bi
->version
);
17777 list
->buflen
+= bi_length
;
17781 * !Broadcast && number of ssid = 1 && number of channels =1
17782 * means specific scan to association
17784 if (wl_cfgp2p_is_p2p_specific_scan(cfg
->scan_request
)) {
17785 WL_ERR(("P2P assoc scan fast aborted.\n"));
17786 wl_notify_escan_complete(cfg
, cfg
->escan_info
.ndev
, false, true);
17791 else if (status
== WLC_E_STATUS_SUCCESS
) {
17792 cfg
->escan_info
.escan_state
= WL_ESCAN_STATE_IDLE
;
17793 wl_escan_print_sync_id(status
, cfg
->escan_info
.cur_sync_id
,
17794 escan_result
->sync_id
);
17796 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
17797 WL_DBG(("ACTION FRAME SCAN DONE\n"));
17798 wl_clr_p2p_status(cfg
, SCANNING
);
17799 wl_clr_drv_status(cfg
, SCANNING
, cfg
->afx_hdl
->dev
);
17800 if (cfg
->afx_hdl
->peer_chan
== WL_INVALID
)
17801 complete(&cfg
->act_frm_scan
);
17802 } else if ((likely(cfg
->scan_request
)) || (cfg
->sched_scan_running
)) {
17803 WL_INFORM_MEM(("ESCAN COMPLETED\n"));
17804 DBG_EVENT_LOG((dhd_pub_t
*)cfg
->pub
, WIFI_EVENT_DRIVER_SCAN_COMPLETE
);
17805 cfg
->bss_list
= wl_escan_get_buf(cfg
, FALSE
);
17806 if (!scan_req_match(cfg
)) {
17807 WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n",
17808 cfg
->bss_list
->count
));
17810 #if defined(SUPPORT_RANDOM_MAC_SCAN) && defined(DHD_RANDOM_MAC_SCAN)
17811 wl_cfg80211_random_mac_disable(ndev
);
17812 #endif /* SUPPORT_RANDOM_MAC_SCAN && DHD_RANDOM_MAC_SCAN */
17813 wl_inform_bss(cfg
);
17814 wl_notify_escan_complete(cfg
, ndev
, false, false);
17816 wl_escan_increment_sync_id(cfg
, SCAN_BUF_NEXT
);
17817 #ifdef CUSTOMER_HW4_DEBUG
17818 if (wl_scan_timeout_dbg_enabled
)
17819 wl_scan_timeout_dbg_clear();
17820 #endif /* CUSTOMER_HW4_DEBUG */
17821 } else if ((status
== WLC_E_STATUS_ABORT
) || (status
== WLC_E_STATUS_NEWSCAN
) ||
17823 (status
== WLC_E_STATUS_CCXFASTRM
) ||
17824 #endif /* BCMCCX */
17825 (status
== WLC_E_STATUS_11HQUIET
) || (status
== WLC_E_STATUS_CS_ABORT
) ||
17826 (status
== WLC_E_STATUS_NEWASSOC
)) {
17827 /* Dump FW preserve buffer content */
17828 if (status
== WLC_E_STATUS_ABORT
) {
17829 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
17831 /* Handle all cases of scan abort */
17832 cfg
->escan_info
.escan_state
= WL_ESCAN_STATE_IDLE
;
17833 wl_escan_print_sync_id(status
, escan_result
->sync_id
,
17834 cfg
->escan_info
.cur_sync_id
);
17835 WL_DBG(("ESCAN ABORT reason: %d\n", status
));
17836 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
17837 WL_DBG(("ACTION FRAME SCAN DONE\n"));
17838 wl_clr_drv_status(cfg
, SCANNING
, cfg
->afx_hdl
->dev
);
17839 wl_clr_p2p_status(cfg
, SCANNING
);
17840 if (cfg
->afx_hdl
->peer_chan
== WL_INVALID
)
17841 complete(&cfg
->act_frm_scan
);
17842 } else if ((likely(cfg
->scan_request
)) || (cfg
->sched_scan_running
)) {
17843 WL_INFORM_MEM(("ESCAN ABORTED\n"));
17845 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
17846 if (p2p_scan(cfg
) && cfg
->scan_request
&&
17847 (cfg
->scan_request
->flags
& NL80211_SCAN_FLAG_FLUSH
)) {
17848 WL_ERR(("scan list is changed"));
17849 cfg
->bss_list
= wl_escan_get_buf(cfg
, FALSE
);
17852 cfg
->bss_list
= wl_escan_get_buf(cfg
, TRUE
);
17854 if (!scan_req_match(cfg
)) {
17855 WL_TRACE_HW4(("SCAN ABORTED: scanned AP count=%d\n",
17856 cfg
->bss_list
->count
));
17858 #ifdef DUAL_ESCAN_RESULT_BUFFER
17859 if (escan_result
->sync_id
!= cfg
->escan_info
.cur_sync_id
) {
17860 /* If sync_id is not matching, then the abort might have
17861 * come for the old scan req or for the in-driver initiated
17862 * scan. So do abort for scan_req for which sync_id is
17865 WL_INFORM_MEM(("sync_id mismatch (%d != %d). "
17866 "Ignore the scan abort event.\n",
17867 escan_result
->sync_id
, cfg
->escan_info
.cur_sync_id
));
17870 /* sync id is matching, abort the scan */
17871 WL_INFORM_MEM(("scan aborted for sync_id: %d \n",
17872 cfg
->escan_info
.cur_sync_id
));
17873 wl_inform_bss(cfg
);
17874 wl_notify_escan_complete(cfg
, ndev
, true, false);
17877 wl_inform_bss(cfg
);
17878 wl_notify_escan_complete(cfg
, ndev
, true, false);
17879 #endif /* DUAL_ESCAN_RESULT_BUFFER */
17881 /* If there is no pending host initiated scan, do nothing */
17882 WL_DBG(("ESCAN ABORT: No pending scans. Ignoring event.\n"));
17884 wl_escan_increment_sync_id(cfg
, SCAN_BUF_CNT
);
17885 } else if (status
== WLC_E_STATUS_TIMEOUT
) {
17886 WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg
->scan_request
));
17887 WL_ERR(("reason[0x%x]\n", e
->reason
));
17888 if (e
->reason
== 0xFFFFFFFF) {
17889 wl_notify_escan_complete(cfg
, cfg
->escan_info
.ndev
, true, true);
17892 WL_ERR(("unexpected Escan Event %d : abort\n", status
));
17893 cfg
->escan_info
.escan_state
= WL_ESCAN_STATE_IDLE
;
17894 wl_escan_print_sync_id(status
, escan_result
->sync_id
,
17895 cfg
->escan_info
.cur_sync_id
);
17896 if (wl_get_drv_status_all(cfg
, FINDING_COMMON_CHANNEL
)) {
17897 WL_DBG(("ACTION FRAME SCAN DONE\n"));
17898 wl_clr_p2p_status(cfg
, SCANNING
);
17899 wl_clr_drv_status(cfg
, SCANNING
, cfg
->afx_hdl
->dev
);
17900 if (cfg
->afx_hdl
->peer_chan
== WL_INVALID
)
17901 complete(&cfg
->act_frm_scan
);
17902 } else if ((likely(cfg
->scan_request
)) || (cfg
->sched_scan_running
)) {
17903 cfg
->bss_list
= wl_escan_get_buf(cfg
, TRUE
);
17904 if (!scan_req_match(cfg
)) {
17905 WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): "
17906 "scanned AP count=%d\n",
17907 cfg
->bss_list
->count
));
17909 wl_inform_bss(cfg
);
17910 wl_notify_escan_complete(cfg
, ndev
, true, false);
17912 wl_escan_increment_sync_id(cfg
, 2);
17914 #else /* WL_DRV_AVOID_SCANCACHE */
17915 err
= wl_escan_without_scan_cache(cfg
, escan_result
, ndev
, e
, status
);
17916 #endif /* WL_DRV_AVOID_SCANCACHE */
17918 mutex_unlock(&cfg
->scan_sync
);
17922 static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211
*cfg
, int enable
)
17924 u32 connected_cnt
= wl_get_drv_status_all(cfg
, CONNECTED
);
17925 bool p2p_connected
= wl_cfgp2p_vif_created(cfg
);
17926 struct net_info
*iter
, *next
;
17928 if (!(cfg
->roam_flags
& WL_ROAM_OFF_ON_CONCURRENT
))
17931 WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
17932 enable
, p2p_connected
, connected_cnt
));
17933 /* Disable FW roam when we have a concurrent P2P connection */
17934 if (enable
&& p2p_connected
&& connected_cnt
> 1) {
17936 /* Mark it as to be reverted */
17937 cfg
->roam_flags
|= WL_ROAM_REVERT_STATUS
;
17938 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17939 4 && __GNUC_MINOR__ >= 6))
17940 _Pragma("GCC diagnostic push")
17941 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
17943 for_each_ndev(cfg
, iter
, next
) {
17944 if (iter
->ndev
&& iter
->wdev
&&
17945 iter
->wdev
->iftype
== NL80211_IFTYPE_STATION
) {
17946 if (wldev_iovar_setint(iter
->ndev
, "roam_off", TRUE
)
17948 iter
->roam_off
= TRUE
;
17951 WL_ERR(("error to enable roam_off\n"));
17955 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17956 4 && __GNUC_MINOR__ >= 6))
17957 _Pragma("GCC diagnostic pop")
17960 else if (!enable
&& (cfg
->roam_flags
& WL_ROAM_REVERT_STATUS
)) {
17961 cfg
->roam_flags
&= ~WL_ROAM_REVERT_STATUS
;
17962 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17963 4 && __GNUC_MINOR__ >= 6))
17964 _Pragma("GCC diagnostic push")
17965 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
17967 for_each_ndev(cfg
, iter
, next
) {
17968 if (iter
->ndev
&& iter
->wdev
&&
17969 iter
->wdev
->iftype
== NL80211_IFTYPE_STATION
) {
17970 if (iter
->roam_off
!= WL_INVALID
) {
17971 if (wldev_iovar_setint(iter
->ndev
, "roam_off", FALSE
)
17973 iter
->roam_off
= FALSE
;
17976 WL_ERR(("error to disable roam_off\n"));
17981 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
17982 4 && __GNUC_MINOR__ >= 6))
17983 _Pragma("GCC diagnostic pop")
17990 static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211
*cfg
)
17992 struct net_info
*iter
, *next
;
17995 u32 pre_ctl_chan
= 0;
17996 u32 connected_cnt
= wl_get_drv_status_all(cfg
, CONNECTED
);
17997 cfg
->vsdb_mode
= false;
17999 if (connected_cnt
<= 1) {
18002 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18003 4 && __GNUC_MINOR__ >= 6))
18004 _Pragma("GCC diagnostic push")
18005 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
18007 for_each_ndev(cfg
, iter
, next
) {
18008 /* p2p discovery iface ndev could be null */
18012 if (wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
)) {
18013 if (wldev_iovar_getint(iter
->ndev
, "chanspec",
18014 (s32
*)&chanspec
) == BCME_OK
) {
18015 chanspec
= wl_chspec_driver_to_host(chanspec
);
18016 ctl_chan
= wf_chspec_ctlchan(chanspec
);
18017 wl_update_prof(cfg
, iter
->ndev
, NULL
,
18018 &ctl_chan
, WL_PROF_CHAN
);
18020 if (!cfg
->vsdb_mode
) {
18021 if (!pre_ctl_chan
&& ctl_chan
)
18022 pre_ctl_chan
= ctl_chan
;
18023 else if (pre_ctl_chan
&& (pre_ctl_chan
!= ctl_chan
)) {
18024 cfg
->vsdb_mode
= true;
18030 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18031 4 && __GNUC_MINOR__ >= 6))
18032 _Pragma("GCC diagnostic pop")
18034 WL_ERR(("%s concurrency is enabled\n", cfg
->vsdb_mode
? "Multi Channel" : "Same Channel"));
18039 wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211
*cfg
)
18041 struct net_info
*iter
, *next
;
18045 bool is_rsdb_supported
= FALSE
;
18046 bool rsdb_mode
= FALSE
;
18048 is_rsdb_supported
= DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_RSDB_MODE
);
18050 if (!is_rsdb_supported
) {
18054 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18055 4 && __GNUC_MINOR__ >= 6))
18056 _Pragma("GCC diagnostic push")
18057 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
18059 for_each_ndev(cfg
, iter
, next
) {
18060 /* p2p discovery iface ndev could be null */
18064 if (wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
)) {
18065 if (wldev_iovar_getint(iter
->ndev
, "chanspec",
18066 (s32
*)&chanspec
) == BCME_OK
) {
18067 chanspec
= wl_chspec_driver_to_host(chanspec
);
18068 band
= CHSPEC_BAND(chanspec
);
18071 if (!pre_band
&& band
) {
18073 } else if (pre_band
&& (pre_band
!= band
)) {
18079 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
18080 4 && __GNUC_MINOR__ >= 6))
18081 _Pragma("GCC diagnostic pop")
18083 WL_DBG(("RSDB mode is %s\n", rsdb_mode
? "enabled" : "disabled"));
18088 static s32
wl_notifier_change_state(struct bcm_cfg80211
*cfg
, struct net_info
*_net_info
,
18089 enum wl_status state
, bool set
)
18095 struct net_device
*primary_dev
= bcmcfg_to_prmry_ndev(cfg
);
18096 dhd_pub_t
*dhd
= cfg
->pub
;
18098 rtt_status_info_t
*rtt_status
;
18099 #endif /* RTT_SUPPORT */
18100 if (dhd
->busstate
== DHD_BUS_DOWN
) {
18101 WL_ERR(("%s : busstate is DHD_BUS_DOWN!\n", __FUNCTION__
));
18104 WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
18105 state
, set
, _net_info
->pm_restore
, _net_info
->ndev
->name
));
18107 if (state
!= WL_STATUS_CONNECTED
)
18109 mode
= wl_get_mode_by_netdev(cfg
, _net_info
->ndev
);
18111 wl_cfg80211_concurrent_roam(cfg
, 1);
18112 wl_cfg80211_determine_vsdb_mode(cfg
);
18113 if (mode
== WL_MODE_AP
) {
18114 if (wl_add_remove_eventmsg(primary_dev
, WLC_E_P2P_PROBREQ_MSG
, false))
18115 WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
18118 if ((err
= wldev_ioctl_set(_net_info
->ndev
, WLC_SET_PM
, &pm
,
18119 sizeof(pm
))) != 0) {
18120 if (err
== -ENODEV
)
18121 WL_DBG(("%s:netdev not ready\n",
18122 _net_info
->ndev
->name
));
18124 WL_ERR(("%s:error (%d)\n",
18125 _net_info
->ndev
->name
, err
));
18127 wl_cfg80211_update_power_mode(_net_info
->ndev
);
18129 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_SHORT
);
18130 #if defined(WLTDLS)
18131 if (wl_cfg80211_is_concurrent_mode(primary_dev
)) {
18132 err
= wldev_iovar_setint(primary_dev
, "tdls_enable", 0);
18134 #endif /* defined(WLTDLS) */
18136 #ifdef DISABLE_FRAMEBURST_VSDB
18137 if (!DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_HOSTAP_MODE
) &&
18138 wl_cfg80211_is_concurrent_mode(primary_dev
) &&
18139 !wl_cfg80211_determine_p2p_rsdb_mode(cfg
)) {
18140 wl_cfg80211_set_frameburst(cfg
, FALSE
);
18142 #endif /* DISABLE_FRAMEBURST_VSDB */
18143 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18144 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd
) &&
18145 wl_get_drv_status(cfg
, CONNECTED
, bcmcfg_to_prmry_ndev(cfg
))) {
18146 /* Enable frameburst for
18147 * STA/SoftAP concurrent mode
18149 wl_cfg80211_set_frameburst(cfg
, TRUE
);
18151 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
18152 } else { /* clear */
18154 /* clear chan information when the net device is disconnected */
18155 wl_update_prof(cfg
, _net_info
->ndev
, NULL
, &chan
, WL_PROF_CHAN
);
18156 wl_cfg80211_determine_vsdb_mode(cfg
);
18157 if (primary_dev
== _net_info
->ndev
) {
18160 rtt_status
= GET_RTTSTATE(dhd
);
18161 if (rtt_status
->status
!= RTT_ENABLED
)
18162 #endif /* RTT_SUPPORT */
18163 if ((err
= wldev_ioctl_set(_net_info
->ndev
, WLC_SET_PM
, &pm
,
18164 sizeof(pm
))) != 0) {
18165 if (err
== -ENODEV
)
18166 WL_DBG(("%s:netdev not ready\n",
18167 _net_info
->ndev
->name
));
18169 WL_ERR(("%s:error (%d)\n",
18170 _net_info
->ndev
->name
, err
));
18172 wl_cfg80211_update_power_mode(_net_info
->ndev
);
18175 wl_cfg80211_concurrent_roam(cfg
, 0);
18176 #if defined(WLTDLS)
18177 if (!wl_cfg80211_is_concurrent_mode(primary_dev
)) {
18178 err
= wldev_iovar_setint(primary_dev
, "tdls_enable", 1);
18180 #endif /* defined(WLTDLS) */
18182 #if defined(DISABLE_FRAMEBURST_VSDB)
18183 if (!DHD_OPMODE_SUPPORTED(cfg
->pub
, DHD_FLAG_HOSTAP_MODE
)) {
18184 wl_cfg80211_set_frameburst(cfg
, TRUE
);
18186 #endif /* DISABLE_FRAMEBURST_VSDB */
18187 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18188 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd
) &&
18189 (cfg
->ap_oper_channel
<= CH_MAX_2G_CHANNEL
)) {
18190 /* Disable frameburst for stand-alone 2GHz SoftAP */
18191 wl_cfg80211_set_frameburst(cfg
, FALSE
);
18193 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
18197 static s32
wl_init_scan(struct bcm_cfg80211
*cfg
)
18201 cfg
->evt_handler
[WLC_E_ESCAN_RESULT
] = wl_escan_handler
;
18202 cfg
->escan_info
.escan_state
= WL_ESCAN_STATE_IDLE
;
18203 wl_escan_init_sync_id(cfg
);
18205 /* Init scan_timeout timer */
18206 init_timer(&cfg
->scan_timeout
);
18207 cfg
->scan_timeout
.data
= (unsigned long) cfg
;
18208 cfg
->scan_timeout
.function
= wl_scan_timeout
;
18213 #ifdef DHD_LOSSLESS_ROAMING
18214 static s32
wl_init_roam_timeout(struct bcm_cfg80211
*cfg
)
18218 /* Init roam timer */
18219 init_timer(&cfg
->roam_timeout
);
18220 cfg
->roam_timeout
.data
= (unsigned long) cfg
;
18221 cfg
->roam_timeout
.function
= wl_roam_timeout
;
18225 #endif /* DHD_LOSSLESS_ROAMING */
18227 static s32
wl_init_priv(struct bcm_cfg80211
*cfg
)
18229 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
18230 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
18233 cfg
->scan_request
= NULL
;
18234 cfg
->pwr_save
= !!(wiphy
->flags
& WIPHY_FLAG_PS_ON_BY_DEFAULT
);
18235 #ifdef DISABLE_BUILTIN_ROAM
18236 cfg
->roam_on
= false;
18238 cfg
->roam_on
= true;
18239 #endif /* DISABLE_BUILTIN_ROAM */
18240 cfg
->active_scan
= true;
18241 cfg
->rf_blocked
= false;
18242 cfg
->vsdb_mode
= false;
18243 #if defined(BCMSDIO)
18244 cfg
->wlfc_on
= false;
18245 #endif /* defined(BCMSDIO) */
18246 cfg
->roam_flags
|= WL_ROAM_OFF_ON_CONCURRENT
;
18247 cfg
->disable_roam_event
= false;
18248 /* register interested state */
18249 set_bit(WL_STATUS_CONNECTED
, &cfg
->interrested_state
);
18250 spin_lock_init(&cfg
->cfgdrv_lock
);
18251 mutex_init(&cfg
->ioctl_buf_sync
);
18252 init_waitqueue_head(&cfg
->netif_change_event
);
18253 init_completion(&cfg
->send_af_done
);
18254 init_completion(&cfg
->iface_disable
);
18256 err
= wl_init_priv_mem(cfg
);
18259 if (wl_create_event_handler(cfg
))
18261 wl_init_event_handler(cfg
);
18262 mutex_init(&cfg
->usr_sync
);
18263 mutex_init(&cfg
->event_sync
);
18264 mutex_init(&cfg
->if_sync
);
18265 mutex_init(&cfg
->scan_sync
);
18267 mutex_init(&cfg
->tdls_sync
);
18268 #endif /* WLTDLS */
18270 mutex_init(&cfg
->bcn_sync
);
18271 #endif /* WL_BCNRECV */
18273 wl_init_wps_reauth_sm(cfg
);
18274 #endif /* WL_WPS_SYNC */
18275 err
= wl_init_scan(cfg
);
18278 #ifdef DHD_LOSSLESS_ROAMING
18279 err
= wl_init_roam_timeout(cfg
);
18283 #endif /* DHD_LOSSLESS_ROAMING */
18284 wl_init_conf(cfg
->conf
);
18285 wl_init_prof(cfg
, ndev
);
18287 DNGL_FUNC(dhd_cfg80211_init
, (cfg
));
18289 cfg
->nan_dp_state
= NAN_DP_STATE_DISABLED
;
18290 init_waitqueue_head(&cfg
->ndp_if_change_event
);
18291 #endif /* WL_NAN */
18295 static void wl_deinit_priv(struct bcm_cfg80211
*cfg
)
18297 DNGL_FUNC(dhd_cfg80211_deinit
, (cfg
));
18298 wl_destroy_event_handler(cfg
);
18301 del_timer_sync(&cfg
->scan_timeout
);
18302 #ifdef DHD_LOSSLESS_ROAMING
18303 del_timer_sync(&cfg
->roam_timeout
);
18305 wl_deinit_priv_mem(cfg
);
18306 if (wl_cfg80211_netdev_notifier_registered
) {
18307 wl_cfg80211_netdev_notifier_registered
= FALSE
;
18308 unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier
);
18312 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18313 static s32
wl_cfg80211_attach_p2p(struct bcm_cfg80211
*cfg
)
18315 WL_TRACE(("Enter \n"));
18317 if (wl_cfgp2p_register_ndev(cfg
) < 0) {
18318 WL_ERR(("P2P attach failed. \n"));
18325 static s32
wl_cfg80211_detach_p2p(struct bcm_cfg80211
*cfg
)
18327 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18328 struct wireless_dev
*wdev
;
18329 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18331 WL_DBG(("Enter \n"));
18333 WL_ERR(("Invalid Ptr\n"));
18336 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18338 wdev
= cfg
->p2p_wdev
;
18340 WL_ERR(("Invalid Ptr\n"));
18344 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18346 wl_cfgp2p_unregister_ndev(cfg
);
18348 cfg
->p2p_wdev
= NULL
;
18349 cfg
->p2p_net
= NULL
;
18350 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18351 WL_DBG(("Freeing 0x%p \n", wdev
));
18352 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
18353 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18357 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
18359 static s32
wl_cfg80211_attach_post(struct net_device
*ndev
)
18361 struct bcm_cfg80211
* cfg
;
18364 WL_INFORM_MEM(("In\n"));
18365 if (unlikely(!ndev
)) {
18366 WL_ERR(("ndev is invaild\n"));
18369 cfg
= wl_get_cfg(ndev
);
18370 if (unlikely(!cfg
)) {
18371 WL_ERR(("cfg is invaild\n"));
18374 if (!wl_get_drv_status(cfg
, READY
, ndev
)) {
18376 ret
= wl_cfgp2p_supported(cfg
, ndev
);
18378 #if !defined(WL_ENABLE_P2P_IF)
18379 cfg
->wdev
->wiphy
->interface_modes
|=
18380 (BIT(NL80211_IFTYPE_P2P_CLIENT
)|
18381 BIT(NL80211_IFTYPE_P2P_GO
));
18382 #endif /* !WL_ENABLE_P2P_IF */
18383 if ((err
= wl_cfgp2p_init_priv(cfg
)) != 0)
18386 #if defined(WL_ENABLE_P2P_IF)
18387 if (cfg
->p2p_net
) {
18388 /* Update MAC addr for p2p0 interface here. */
18389 memcpy(cfg
->p2p_net
->dev_addr
, ndev
->dev_addr
, ETH_ALEN
);
18390 cfg
->p2p_net
->dev_addr
[0] |= 0x02;
18391 WL_ERR(("%s: p2p_dev_addr="MACDBG
"\n",
18392 cfg
->p2p_net
->name
,
18393 MAC2STRDBG(cfg
->p2p_net
->dev_addr
)));
18395 WL_ERR(("p2p_net not yet populated."
18396 " Couldn't update the MAC Address for p2p0 \n"));
18399 #endif /* WL_ENABLE_P2P_IF */
18400 cfg
->p2p_supported
= true;
18401 } else if (ret
== 0) {
18402 if ((err
= wl_cfgp2p_init_priv(cfg
)) != 0)
18405 /* SDIO bus timeout */
18411 wl_set_drv_status(cfg
, READY
, ndev
);
18416 struct bcm_cfg80211
*wl_get_cfg(struct net_device
*ndev
)
18418 struct wireless_dev
*wdev
= ndev
->ieee80211_ptr
;
18423 return wiphy_priv(wdev
->wiphy
);
18427 wl_cfg80211_net_attach(struct net_device
*primary_ndev
)
18429 struct bcm_cfg80211
*cfg
= wl_get_cfg(primary_ndev
);
18432 WL_ERR(("cfg null\n"));
18435 #ifdef WL_STATIC_IF
18436 /* Register dummy n/w iface. FW init will happen only from dev_open */
18437 if (wl_cfg80211_register_static_if(cfg
, NL80211_IFTYPE_STATION
,
18438 WL_STATIC_IFNAME_PREFIX
) == NULL
) {
18439 WL_ERR(("static i/f registration failed!\n"));
18442 #endif /* WL_STATIC_IF */
18446 s32
wl_cfg80211_attach(struct net_device
*ndev
, void *context
)
18448 struct wireless_dev
*wdev
;
18449 struct bcm_cfg80211
*cfg
;
18451 struct device
*dev
;
18454 dhd_pub_t
*dhd
= (struct dhd_pub
*)(context
);
18456 WL_TRACE(("In\n"));
18458 WL_ERR(("ndev is invaild\n"));
18461 WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
18462 dev
= wl_cfg80211_get_parent_dev();
18464 wdev
= (struct wireless_dev
*)MALLOCZ(dhd
->osh
, sizeof(*wdev
));
18465 if (unlikely(!wdev
)) {
18466 WL_ERR(("Could not allocate wireless device\n"));
18469 err
= wl_setup_wiphy(wdev
, dev
, context
);
18470 if (unlikely(err
)) {
18471 MFREE(dhd
->osh
, wdev
, sizeof(*wdev
));
18474 wdev
->iftype
= wl_mode_to_nl80211_iftype(WL_MODE_BSS
);
18475 cfg
= wiphy_priv(wdev
->wiphy
);
18477 cfg
->pub
= context
;
18478 cfg
->osh
= dhd
->osh
;
18479 INIT_LIST_HEAD(&cfg
->net_list
);
18481 INIT_LIST_HEAD(&cfg
->wbtext_bssid_list
);
18482 #endif /* WBTEXT */
18483 INIT_LIST_HEAD(&cfg
->vndr_oui_list
);
18484 spin_lock_init(&cfg
->vndr_oui_sync
);
18485 spin_lock_init(&cfg
->net_list_sync
);
18486 ndev
->ieee80211_ptr
= wdev
;
18487 SET_NETDEV_DEV(ndev
, wiphy_dev(wdev
->wiphy
));
18488 wdev
->netdev
= ndev
;
18489 cfg
->state_notifier
= wl_notifier_change_state
;
18490 err
= wl_alloc_netinfo(cfg
, ndev
, wdev
, WL_IF_TYPE_STA
, PM_ENABLE
, bssidx
, ifidx
);
18492 WL_ERR(("Failed to alloc net_info (%d)\n", err
));
18493 goto cfg80211_attach_out
;
18495 err
= wl_init_priv(cfg
);
18497 WL_ERR(("Failed to init iwm_priv (%d)\n", err
));
18498 goto cfg80211_attach_out
;
18501 err
= wl_setup_rfkill(cfg
, TRUE
);
18503 WL_ERR(("Failed to setup rfkill %d\n", err
));
18504 goto cfg80211_attach_out
;
18506 #ifdef DEBUGFS_CFG80211
18507 err
= wl_setup_debugfs(cfg
);
18509 WL_ERR(("Failed to setup debugfs %d\n", err
));
18510 goto cfg80211_attach_out
;
18513 if (!wl_cfg80211_netdev_notifier_registered
) {
18514 wl_cfg80211_netdev_notifier_registered
= TRUE
;
18515 err
= register_netdevice_notifier(&wl_cfg80211_netdev_notifier
);
18517 wl_cfg80211_netdev_notifier_registered
= FALSE
;
18518 WL_ERR(("Failed to register notifierl %d\n", err
));
18519 goto cfg80211_attach_out
;
18522 #if defined(COEX_DHCP)
18523 cfg
->btcoex_info
= wl_cfg80211_btcoex_init(cfg
->wdev
->netdev
);
18524 if (!cfg
->btcoex_info
)
18525 goto cfg80211_attach_out
;
18527 #if defined(SUPPORT_RANDOM_MAC_SCAN) && defined(DHD_RANDOM_MAC_SCAN)
18528 cfg
->random_mac_running
= FALSE
;
18529 #endif /* SUPPORT_RANDOM_MAC_SCAN && DHD_RANDOM_MAC_SCAN */
18531 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18532 err
= wl_cfg80211_attach_p2p(cfg
);
18534 goto cfg80211_attach_out
;
18535 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
18537 INIT_DELAYED_WORK(&cfg
->pm_enable_work
, wl_cfg80211_work_handler
);
18538 mutex_init(&cfg
->pm_sync
);
18540 mutex_init(&cfg
->nancfg
.nan_sync
);
18541 init_waitqueue_head(&cfg
->nancfg
.nan_event_wait
);
18542 #endif /* WL_NAN */
18543 wl_cfg80211_set_bcmcfg(cfg
);
18544 #ifdef BIGDATA_SOFTAP
18545 wl_attach_ap_stainfo(cfg
);
18546 #endif /* BIGDATA_SOFTAP */
18547 cfg
->rssi_sum_report
= FALSE
;
18549 wl_bad_ap_mngr_init(cfg
);
18550 #endif /* WL_BAM */
18554 cfg80211_attach_out
:
18555 wl_setup_rfkill(cfg
, FALSE
);
18560 void wl_cfg80211_detach(struct bcm_cfg80211
*cfg
)
18562 WL_DBG(("Enter\n"));
18566 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_DEL
);
18568 #if defined(COEX_DHCP)
18569 wl_cfg80211_btcoex_deinit();
18570 cfg
->btcoex_info
= NULL
;
18573 wl_setup_rfkill(cfg
, FALSE
);
18574 #ifdef DEBUGFS_CFG80211
18575 wl_free_debugfs(cfg
);
18577 if (cfg
->p2p_supported
) {
18578 if (timer_pending(&cfg
->p2p
->listen_timer
))
18579 del_timer_sync(&cfg
->p2p
->listen_timer
);
18580 wl_cfgp2p_deinit_priv(cfg
);
18584 wl_deinit_wps_reauth_sm(cfg
);
18585 #endif /* WL_WPS_SYNC */
18587 if (timer_pending(&cfg
->scan_timeout
))
18588 del_timer_sync(&cfg
->scan_timeout
);
18589 #ifdef DHD_LOSSLESS_ROAMING
18590 if (timer_pending(&cfg
->roam_timeout
)) {
18591 del_timer_sync(&cfg
->roam_timeout
);
18593 #endif /* DHD_LOSSLESS_ROAMING */
18595 #ifdef WL_STATIC_IF
18596 wl_cfg80211_unregister_static_if(cfg
);
18597 #endif /* WL_STATIC_IF */
18598 #if defined(WL_CFG80211_P2P_DEV_IF)
18600 wl_cfgp2p_del_p2p_disc_if(cfg
->p2p_wdev
, cfg
);
18601 #endif /* WL_CFG80211_P2P_DEV_IF */
18602 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18603 wl_cfg80211_detach_p2p(cfg
);
18604 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
18605 #ifdef BIGDATA_SOFTAP
18606 wl_detach_ap_stainfo(cfg
);
18607 #endif /* BIGDATA_SOFTAP */
18609 wl_bad_ap_mngr_deinit(cfg
);
18610 #endif /* WL_BAM */
18611 wl_cfg80211_ibss_vsie_free(cfg
);
18612 wl_dealloc_netinfo_by_wdev(cfg
, cfg
->wdev
);
18613 wl_cfg80211_set_bcmcfg(NULL
);
18614 wl_deinit_priv(cfg
);
18615 wl_cfg80211_clear_parent_dev();
18617 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
18618 * structure "cfg", which is the private part of wiphy, has been freed in
18619 * wl_free_wdev !!!!!!!!!!!
18621 WL_DBG(("Exit\n"));
18624 static void wl_print_event_data(struct bcm_cfg80211
*cfg
,
18625 uint32 event_type
, const wl_event_msg_t
*e
)
18627 s32 status
= ntoh32(e
->status
);
18628 s32 reason
= ntoh32(e
->reason
);
18629 s32 ifidx
= ntoh32(e
->ifidx
);
18630 s32 bssidx
= ntoh32(e
->bsscfgidx
);
18632 switch (event_type
) {
18633 case WLC_E_ESCAN_RESULT
:
18634 if ((status
== WLC_E_STATUS_SUCCESS
) ||
18635 (status
== WLC_E_STATUS_ABORT
)) {
18636 WL_INFORM_MEM(("event_type (%d), ifidx: %d"
18637 " bssidx: %d scan_type:%d\n",
18638 event_type
, ifidx
, bssidx
, status
));
18642 case WLC_E_DISASSOC
:
18643 case WLC_E_DISASSOC_IND
:
18645 case WLC_E_DEAUTH_IND
:
18646 WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
18647 " status:%d reason:%d\n",
18648 event_type
, ifidx
, bssidx
, status
, reason
));
18652 /* Print only when DBG verbose is enabled */
18653 WL_DBG(("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
18654 event_type
, ifidx
, bssidx
, status
, reason
));
18658 static void wl_event_handler(struct work_struct
*work_data
)
18660 struct bcm_cfg80211
*cfg
= NULL
;
18661 struct wl_event_q
*e
;
18662 struct wireless_dev
*wdev
= NULL
;
18664 WL_DBG(("Enter \n"));
18665 BCM_SET_CONTAINER_OF(cfg
, work_data
, struct bcm_cfg80211
, event_work
);
18666 cfg
->wl_evt_hdlr_entry_time
= OSL_LOCALTIME_NS();
18667 DHD_EVENT_WAKE_LOCK(cfg
->pub
);
18668 while ((e
= wl_deq_event(cfg
))) {
18669 s32 status
= ntoh32(e
->emsg
.status
);
18670 u32 event_type
= ntoh32(e
->emsg
.event_type
);
18671 bool scan_cmplt_evt
= (event_type
== WLC_E_ESCAN_RESULT
) &&
18672 ((status
== WLC_E_STATUS_SUCCESS
) || (status
== WLC_E_STATUS_ABORT
));
18674 cfg
->wl_evt_deq_time
= OSL_LOCALTIME_NS();
18675 if (scan_cmplt_evt
) {
18676 cfg
->scan_deq_time
= OSL_LOCALTIME_NS();
18678 /* Print only critical events to avoid too many prints */
18679 wl_print_event_data(cfg
, e
->etype
, &e
->emsg
);
18681 if (e
->emsg
.ifidx
> WL_MAX_IFS
) {
18682 WL_ERR((" Event ifidx not in range. val:%d \n", e
->emsg
.ifidx
));
18686 /* Make sure iface operations, don't creat race conditions */
18687 mutex_lock(&cfg
->if_sync
);
18688 if (!(wdev
= wl_get_wdev_by_fw_idx(cfg
,
18689 e
->emsg
.bsscfgidx
, e
->emsg
.ifidx
))) {
18690 /* For WLC_E_IF would be handled by wl_host_event */
18691 if (e
->etype
!= WLC_E_IF
)
18692 WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
18693 " Ignoring event.\n", e
->emsg
.bsscfgidx
));
18694 } else if (e
->etype
< WLC_E_LAST
&& cfg
->evt_handler
[e
->etype
]) {
18695 dhd_pub_t
*dhd
= (struct dhd_pub
*)(cfg
->pub
);
18696 if (dhd
->busstate
== DHD_BUS_DOWN
) {
18697 WL_ERR((": BUS is DOWN.\n"));
18700 WL_DBG(("event_type %d event_sub %d\n",
18701 ntoh32(e
->emsg
.event_type
),
18702 ntoh32(e
->emsg
.reason
)));
18703 cfg
->evt_handler
[e
->etype
](cfg
, wdev_to_cfgdev(wdev
),
18704 &e
->emsg
, e
->edata
);
18705 if (scan_cmplt_evt
) {
18706 cfg
->scan_hdlr_cmplt_time
= OSL_LOCALTIME_NS();
18710 WL_DBG(("Unknown Event (%d): ignoring\n", e
->etype
));
18712 mutex_unlock(&cfg
->if_sync
);
18714 wl_put_event(cfg
, e
);
18715 if (scan_cmplt_evt
) {
18716 cfg
->scan_cmplt_time
= OSL_LOCALTIME_NS();
18718 cfg
->wl_evt_hdlr_exit_time
= OSL_LOCALTIME_NS();
18720 DHD_EVENT_WAKE_UNLOCK(cfg
->pub
);
18724 wl_cfg80211_event(struct net_device
*ndev
, const wl_event_msg_t
* e
, void *data
)
18726 s32 status
= ntoh32(e
->status
);
18727 u32 event_type
= ntoh32(e
->event_type
);
18728 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
18729 struct net_info
*netinfo
;
18731 WL_TRACE(("event_type (%d): reason (%d): %s\n", event_type
, ntoh32(e
->reason
),
18732 bcmevent_get_name(event_type
)));
18733 if ((cfg
== NULL
) || (cfg
->p2p_supported
&& cfg
->p2p
== NULL
)) {
18734 WL_ERR(("Stale event ignored\n"));
18738 if (cfg
->event_workq
== NULL
) {
18739 WL_ERR(("Event handler is not created\n"));
18743 if (wl_get_p2p_status(cfg
, IF_CHANGING
) || wl_get_p2p_status(cfg
, IF_ADDING
)) {
18744 WL_ERR(("during IF change, ignore event %d\n", event_type
));
18748 if (event_type
== WLC_E_IF
) {
18749 /* Don't process WLC_E_IF events in wl_cfg80211 layer */
18753 netinfo
= wl_get_netinfo_by_fw_idx(cfg
, e
->bsscfgidx
, e
->ifidx
);
18755 /* Since the netinfo entry is not there, the netdev entry is not
18756 * created via cfg80211 interface. so the event is not of interest
18757 * to the cfg80211 layer.
18759 WL_TRACE(("ignore event %d, not interested\n", event_type
));
18763 if (event_type
== WLC_E_PFN_NET_FOUND
) {
18764 WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
18766 else if (event_type
== WLC_E_PFN_NET_LOST
) {
18767 WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
18770 if (likely(!wl_enq_event(cfg
, ndev
, event_type
, e
, data
))) {
18771 queue_work(cfg
->event_workq
, &cfg
->event_work
);
18773 /* Mark timeout value for thread sched */
18774 if ((event_type
== WLC_E_ESCAN_RESULT
) &&
18775 ((status
== WLC_E_STATUS_SUCCESS
) ||
18776 (status
== WLC_E_STATUS_ABORT
))) {
18777 cfg
->scan_enq_time
= OSL_LOCALTIME_NS();
18778 WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
18779 status
, work_busy(&cfg
->event_work
)));
18783 static void wl_init_eq(struct bcm_cfg80211
*cfg
)
18785 wl_init_eq_lock(cfg
);
18786 INIT_LIST_HEAD(&cfg
->eq_list
);
18789 static void wl_flush_eq(struct bcm_cfg80211
*cfg
)
18791 struct wl_event_q
*e
;
18792 unsigned long flags
;
18794 flags
= wl_lock_eq(cfg
);
18795 while (!list_empty_careful(&cfg
->eq_list
)) {
18796 BCM_SET_LIST_FIRST_ENTRY(e
, &cfg
->eq_list
, struct wl_event_q
, eq_list
);
18797 list_del(&e
->eq_list
);
18798 MFREE(cfg
->osh
, e
, e
->datalen
+ sizeof(struct wl_event_q
));
18800 wl_unlock_eq(cfg
, flags
);
18804 * retrieve first queued event from head
18807 static struct wl_event_q
*wl_deq_event(struct bcm_cfg80211
*cfg
)
18809 struct wl_event_q
*e
= NULL
;
18810 unsigned long flags
;
18812 flags
= wl_lock_eq(cfg
);
18813 if (likely(!list_empty(&cfg
->eq_list
))) {
18814 BCM_SET_LIST_FIRST_ENTRY(e
, &cfg
->eq_list
, struct wl_event_q
, eq_list
);
18815 list_del(&e
->eq_list
);
18817 wl_unlock_eq(cfg
, flags
);
18823 * push event to tail of the queue
18827 wl_enq_event(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u32 event
,
18828 const wl_event_msg_t
*msg
, void *data
)
18830 struct wl_event_q
*e
;
18834 unsigned long flags
;
18838 data_len
= ntoh32(msg
->datalen
);
18839 evtq_size
= (uint32
)(sizeof(struct wl_event_q
) + data_len
);
18840 e
= (struct wl_event_q
*)MALLOCZ(cfg
->osh
, evtq_size
);
18841 if (unlikely(!e
)) {
18842 WL_ERR(("event alloc failed\n"));
18846 memcpy(&e
->emsg
, msg
, sizeof(wl_event_msg_t
));
18848 memcpy(e
->edata
, data
, data_len
);
18849 e
->datalen
= data_len
;
18850 flags
= wl_lock_eq(cfg
);
18851 list_add_tail(&e
->eq_list
, &cfg
->eq_list
);
18852 wl_unlock_eq(cfg
, flags
);
18857 static void wl_put_event(struct bcm_cfg80211
*cfg
, struct wl_event_q
*e
)
18859 MFREE(cfg
->osh
, e
, e
->datalen
+ sizeof(struct wl_event_q
));
18862 static s32
wl_config_infra(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, u16 iftype
)
18866 bool skip_infra
= false;
18869 case WL_IF_TYPE_IBSS
:
18870 case WL_IF_TYPE_AIBSS
:
18873 case WL_IF_TYPE_AP
:
18874 case WL_IF_TYPE_STA
:
18875 case WL_IF_TYPE_P2P_GO
:
18876 case WL_IF_TYPE_P2P_GC
:
18877 /* Intentional fall through */
18880 case WL_IF_TYPE_MONITOR
:
18881 case WL_IF_TYPE_AWDL
:
18882 case WL_IF_TYPE_NAN
:
18883 /* Intentionall fall through */
18886 WL_ERR(("Skipping infra setting for type:%d\n", iftype
));
18891 infra
= htod32(infra
);
18892 err
= wldev_ioctl_set(ndev
, WLC_SET_INFRA
, &infra
, sizeof(infra
));
18893 if (unlikely(err
)) {
18894 WL_ERR(("WLC_SET_INFRA error (%d)\n", err
));
18901 void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf
*ev
, u16 event
, bool set
)
18903 if (!ev
|| (event
> WLC_E_LAST
))
18906 if (ev
->num
< MAX_EVENT_BUF_NUM
) {
18907 ev
->event
[ev
->num
].type
= event
;
18908 ev
->event
[ev
->num
].set
= set
;
18911 WL_ERR(("evenbuffer doesn't support > %u events. Update"
18912 " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM
));
18917 s32
wl_cfg80211_apply_eventbuffer(
18918 struct net_device
*ndev
,
18919 struct bcm_cfg80211
*cfg
,
18920 wl_eventmsg_buf_t
*ev
)
18922 char eventmask
[WL_EVENTING_MASK_LEN
];
18924 s8 iovbuf
[WL_EVENTING_MASK_LEN
+ 12];
18926 if (!ev
|| (!ev
->num
))
18929 mutex_lock(&cfg
->event_sync
);
18931 /* Read event_msgs mask */
18932 ret
= wldev_iovar_getbuf(ndev
, "event_msgs", NULL
, 0, iovbuf
, sizeof(iovbuf
), NULL
);
18933 if (unlikely(ret
)) {
18934 WL_ERR(("Get event_msgs error (%d)\n", ret
));
18937 memcpy(eventmask
, iovbuf
, WL_EVENTING_MASK_LEN
);
18939 /* apply the set bits */
18940 for (i
= 0; i
< ev
->num
; i
++) {
18941 if (ev
->event
[i
].set
)
18942 setbit(eventmask
, ev
->event
[i
].type
);
18944 clrbit(eventmask
, ev
->event
[i
].type
);
18947 /* Write updated Event mask */
18948 ret
= wldev_iovar_setbuf(ndev
, "event_msgs", eventmask
, sizeof(eventmask
), iovbuf
,
18949 sizeof(iovbuf
), NULL
);
18950 if (unlikely(ret
)) {
18951 WL_ERR(("Set event_msgs error (%d)\n", ret
));
18955 mutex_unlock(&cfg
->event_sync
);
18959 s32
wl_add_remove_eventmsg(struct net_device
*ndev
, u16 event
, bool add
)
18961 s8 iovbuf
[WL_EVENTING_MASK_LEN
+ 12];
18962 s8 eventmask
[WL_EVENTING_MASK_LEN
];
18964 struct bcm_cfg80211
*cfg
;
18969 cfg
= wl_get_cfg(ndev
);
18973 mutex_lock(&cfg
->event_sync
);
18975 /* Setup event_msgs */
18976 err
= wldev_iovar_getbuf(ndev
, "event_msgs", NULL
, 0, iovbuf
, sizeof(iovbuf
), NULL
);
18977 if (unlikely(err
)) {
18978 WL_ERR(("Get event_msgs error (%d)\n", err
));
18981 memcpy(eventmask
, iovbuf
, WL_EVENTING_MASK_LEN
);
18983 setbit(eventmask
, event
);
18985 clrbit(eventmask
, event
);
18987 err
= wldev_iovar_setbuf(ndev
, "event_msgs", eventmask
, WL_EVENTING_MASK_LEN
, iovbuf
,
18988 sizeof(iovbuf
), NULL
);
18989 if (unlikely(err
)) {
18990 WL_ERR(("Set event_msgs error (%d)\n", err
));
18995 mutex_unlock(&cfg
->event_sync
);
18999 static int wl_construct_reginfo(struct bcm_cfg80211
*cfg
, s32 bw_cap
)
19001 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
19002 struct ieee80211_channel
*band_chan_arr
= NULL
;
19003 wl_uint32_list_t
*list
;
19004 u32 i
, j
, index
, n_2g
, n_5g
, band
, channel
, array_size
;
19011 bool dfs_radar_disabled
= FALSE
;
19013 #define LOCAL_BUF_LEN 1024
19014 pbuf
= (u8
*)MALLOCZ(cfg
->osh
, LOCAL_BUF_LEN
);
19015 if (pbuf
== NULL
) {
19016 WL_ERR(("failed to allocate local buf\n"));
19020 err
= wldev_iovar_getbuf_bsscfg(dev
, "chanspecs", NULL
,
19021 0, pbuf
, LOCAL_BUF_LEN
, 0, &cfg
->ioctl_buf_sync
);
19023 WL_ERR(("get chanspecs failed with %d\n", err
));
19024 MFREE(cfg
->osh
, pbuf
, LOCAL_BUF_LEN
);
19028 list
= (wl_uint32_list_t
*)(void *)pbuf
;
19029 band
= array_size
= n_2g
= n_5g
= 0;
19030 for (i
= 0; i
< dtoh32(list
->count
); i
++) {
19033 ht40_allowed
= false;
19034 c
= (chanspec_t
)dtoh32(list
->element
[i
]);
19035 c
= wl_chspec_driver_to_host(c
);
19036 channel
= wf_chspec_ctlchan(c
);
19038 if (!CHSPEC_IS40(c
) && ! CHSPEC_IS20(c
)) {
19039 WL_DBG(("HT80/160/80p80 center channel : %d\n", channel
));
19042 if (CHSPEC_IS2G(c
) && (channel
>= CH_MIN_2G_CHANNEL
) &&
19043 (channel
<= CH_MAX_2G_CHANNEL
)) {
19044 band_chan_arr
= __wl_2ghz_channels
;
19045 array_size
= ARRAYSIZE(__wl_2ghz_channels
);
19047 band
= NL80211_BAND_2GHZ
;
19048 ht40_allowed
= (bw_cap
== WLC_N_BW_40ALL
)? true : false;
19049 } else if (CHSPEC_IS5G(c
) && channel
>= CH_MIN_5G_CHANNEL
) {
19050 band_chan_arr
= __wl_5ghz_a_channels
;
19051 array_size
= ARRAYSIZE(__wl_5ghz_a_channels
);
19053 band
= NL80211_BAND_5GHZ
;
19054 ht40_allowed
= (bw_cap
== WLC_N_BW_20ALL
)? false : true;
19056 WL_ERR(("Invalid channel Sepc. 0x%x.\n", c
));
19059 if (!ht40_allowed
&& CHSPEC_IS40(c
))
19061 for (j
= 0; (j
< *n_cnt
&& (*n_cnt
< array_size
)); j
++) {
19062 if (band_chan_arr
[j
].hw_value
== channel
) {
19071 if (index
< array_size
) {
19072 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
19073 band_chan_arr
[index
].center_freq
=
19074 ieee80211_channel_to_frequency(channel
);
19076 band_chan_arr
[index
].center_freq
=
19077 ieee80211_channel_to_frequency(channel
, band
);
19079 band_chan_arr
[index
].hw_value
= channel
;
19080 band_chan_arr
[index
].beacon_found
= false;
19082 if (CHSPEC_IS40(c
) && ht40_allowed
) {
19083 /* assuming the order is HT20, HT40 Upper,
19084 * HT40 lower from chanspecs
19086 u32 ht40_flag
= band_chan_arr
[index
].flags
& IEEE80211_CHAN_NO_HT40
;
19087 if (CHSPEC_SB_UPPER(c
)) {
19088 if (ht40_flag
== IEEE80211_CHAN_NO_HT40
)
19089 band_chan_arr
[index
].flags
&=
19090 ~IEEE80211_CHAN_NO_HT40
;
19091 band_chan_arr
[index
].flags
|= IEEE80211_CHAN_NO_HT40PLUS
;
19093 /* It should be one of
19094 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
19096 band_chan_arr
[index
].flags
&= ~IEEE80211_CHAN_NO_HT40
;
19097 if (ht40_flag
== IEEE80211_CHAN_NO_HT40
)
19098 band_chan_arr
[index
].flags
|=
19099 IEEE80211_CHAN_NO_HT40MINUS
;
19102 band_chan_arr
[index
].flags
= IEEE80211_CHAN_NO_HT40
;
19103 if (!dfs_radar_disabled
) {
19104 if (band
== NL80211_BAND_2GHZ
)
19105 channel
|= WL_CHANSPEC_BAND_2G
;
19107 channel
|= WL_CHANSPEC_BAND_5G
;
19108 channel
|= WL_CHANSPEC_BW_20
;
19109 channel
= wl_chspec_host_to_driver(channel
);
19110 err
= wldev_iovar_getint(dev
, "per_chan_info", &channel
);
19112 if (channel
& WL_CHAN_RADAR
) {
19113 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
19114 band_chan_arr
[index
].flags
|=
19115 (IEEE80211_CHAN_RADAR
19116 | IEEE80211_CHAN_NO_IBSS
);
19118 band_chan_arr
[index
].flags
|=
19119 IEEE80211_CHAN_RADAR
;
19123 if (channel
& WL_CHAN_PASSIVE
)
19124 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
19125 band_chan_arr
[index
].flags
|=
19126 IEEE80211_CHAN_PASSIVE_SCAN
;
19128 band_chan_arr
[index
].flags
|=
19129 IEEE80211_CHAN_NO_IR
;
19131 } else if (err
== BCME_UNSUPPORTED
) {
19132 dfs_radar_disabled
= TRUE
;
19133 WL_ERR(("does not support per_chan_info\n"));
19142 __wl_band_2ghz
.n_channels
= n_2g
;
19143 __wl_band_5ghz_a
.n_channels
= n_5g
;
19144 MFREE(cfg
->osh
, pbuf
, LOCAL_BUF_LEN
);
19145 #undef LOCAL_BUF_LEN
19150 static s32
__wl_update_wiphybands(struct bcm_cfg80211
*cfg
, bool notify
)
19152 struct wiphy
*wiphy
;
19153 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
19160 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19168 s32 txbf_bfe_cap
= 0;
19169 s32 txbf_bfr_cap
= 0;
19173 struct ieee80211_supported_band
*bands
[NUM_NL80211_BANDS
] = {NULL
, };
19175 memset(bandlist
, 0, sizeof(bandlist
));
19176 err
= wldev_ioctl_get(dev
, WLC_GET_BANDLIST
, bandlist
,
19178 if (unlikely(err
)) {
19179 WL_ERR(("error read bandlist (%d)\n", err
));
19182 err
= wldev_ioctl_get(dev
, WLC_GET_BAND
, &cur_band
,
19184 if (unlikely(err
)) {
19185 WL_ERR(("error (%d)\n", err
));
19189 err
= wldev_iovar_getint(dev
, "nmode", &nmode
);
19190 if (unlikely(err
)) {
19191 WL_ERR(("error reading nmode (%d)\n", err
));
19194 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19195 err
= wldev_iovar_getint(dev
, "vhtmode", &vhtmode
);
19196 if (unlikely(err
)) {
19197 WL_ERR(("error reading vhtmode (%d)\n", err
));
19201 err
= wldev_iovar_getint(dev
, "txstreams", &txstreams
);
19202 if (unlikely(err
)) {
19203 WL_ERR(("error reading txstreams (%d)\n", err
));
19206 err
= wldev_iovar_getint(dev
, "rxstreams", &rxstreams
);
19207 if (unlikely(err
)) {
19208 WL_ERR(("error reading rxstreams (%d)\n", err
));
19211 err
= wldev_iovar_getint(dev
, "ldpc_cap", &ldpc_cap
);
19212 if (unlikely(err
)) {
19213 WL_ERR(("error reading ldpc_cap (%d)\n", err
));
19216 err
= wldev_iovar_getint(dev
, "stbc_rx", &stbc_rx
);
19217 if (unlikely(err
)) {
19218 WL_ERR(("error reading stbc_rx (%d)\n", err
));
19221 err
= wldev_iovar_getint(dev
, "stbc_tx", &stbc_tx
);
19222 if (unlikely(err
)) {
19223 WL_ERR(("error reading stbc_tx (%d)\n", err
));
19226 err
= wldev_iovar_getint(dev
, "txbf_bfe_cap", &txbf_bfe_cap
);
19227 if (unlikely(err
)) {
19228 WL_ERR(("error reading txbf_bfe_cap (%d)\n", err
));
19231 err
= wldev_iovar_getint(dev
, "txbf_bfr_cap", &txbf_bfr_cap
);
19232 if (unlikely(err
)) {
19233 WL_ERR(("error reading txbf_bfr_cap (%d)\n", err
));
19238 /* For nmode and vhtmode check bw cap */
19240 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19244 err
= wldev_iovar_getint(dev
, "mimo_bw_cap", &bw_cap
);
19245 if (unlikely(err
)) {
19246 WL_ERR(("error get mimo_bw_cap (%d)\n", err
));
19250 err
= wl_construct_reginfo(cfg
, bw_cap
);
19252 WL_ERR(("wl_construct_reginfo() fails err=%d\n", err
));
19253 if (err
!= BCME_UNSUPPORTED
)
19257 wiphy
= bcmcfg_to_wiphy(cfg
);
19258 nband
= bandlist
[0];
19260 for (i
= 1; i
<= nband
&& i
< ARRAYSIZE(bandlist
); i
++) {
19262 if (bandlist
[i
] == WLC_BAND_5G
&& __wl_band_5ghz_a
.n_channels
> 0) {
19263 bands
[NL80211_BAND_5GHZ
] =
19265 index
= NL80211_BAND_5GHZ
;
19266 if (nmode
&& (bw_cap
== WLC_N_BW_40ALL
|| bw_cap
== WLC_N_BW_20IN2G_40IN5G
))
19267 bands
[index
]->ht_cap
.cap
|= IEEE80211_HT_CAP_SGI_40
;
19269 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19270 /* VHT capabilities. */
19273 bands
[index
]->vht_cap
.vht_supported
= TRUE
;
19275 for (j
= 1; j
<= VHT_CAP_MCS_MAP_NSS_MAX
; j
++) {
19276 /* TX stream rates. */
19277 if (j
<= txstreams
) {
19278 VHT_MCS_MAP_SET_MCS_PER_SS(j
, VHT_CAP_MCS_MAP_0_9
,
19279 bands
[index
]->vht_cap
.vht_mcs
.tx_mcs_map
);
19281 VHT_MCS_MAP_SET_MCS_PER_SS(j
, VHT_CAP_MCS_MAP_NONE
,
19282 bands
[index
]->vht_cap
.vht_mcs
.tx_mcs_map
);
19285 /* RX stream rates. */
19286 if (j
<= rxstreams
) {
19287 VHT_MCS_MAP_SET_MCS_PER_SS(j
, VHT_CAP_MCS_MAP_0_9
,
19288 bands
[index
]->vht_cap
.vht_mcs
.rx_mcs_map
);
19290 VHT_MCS_MAP_SET_MCS_PER_SS(j
, VHT_CAP_MCS_MAP_NONE
,
19291 bands
[index
]->vht_cap
.vht_mcs
.rx_mcs_map
);
19296 /* 80 MHz is mandatory */
19297 bands
[index
]->vht_cap
.cap
|=
19298 IEEE80211_VHT_CAP_SHORT_GI_80
;
19300 if (WL_BW_CAP_160MHZ(bw_cap
)) {
19301 bands
[index
]->vht_cap
.cap
|=
19302 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ
;
19303 bands
[index
]->vht_cap
.cap
|=
19304 IEEE80211_VHT_CAP_SHORT_GI_160
;
19307 bands
[index
]->vht_cap
.cap
|=
19308 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454
;
19311 bands
[index
]->vht_cap
.cap
|=
19312 IEEE80211_VHT_CAP_RXLDPC
;
19315 bands
[index
]->vht_cap
.cap
|=
19316 IEEE80211_VHT_CAP_TXSTBC
;
19319 bands
[index
]->vht_cap
.cap
|=
19320 (stbc_rx
<< VHT_CAP_INFO_RX_STBC_SHIFT
);
19323 bands
[index
]->vht_cap
.cap
|=
19324 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE
;
19326 if (txbf_bfr_cap
) {
19327 bands
[index
]->vht_cap
.cap
|=
19328 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE
;
19331 if (txbf_bfe_cap
|| txbf_bfr_cap
) {
19332 bands
[index
]->vht_cap
.cap
|=
19333 (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT
);
19334 bands
[index
]->vht_cap
.cap
|=
19335 ((txstreams
- 1) <<
19336 VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT
);
19337 bands
[index
]->vht_cap
.cap
|=
19338 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB
;
19341 /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
19342 bands
[index
]->vht_cap
.cap
|=
19343 (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT
);
19344 WL_DBG(("%s band[%d] vht_enab=%d vht_cap=%08x "
19345 "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
19346 __FUNCTION__
, index
,
19347 bands
[index
]->vht_cap
.vht_supported
,
19348 bands
[index
]->vht_cap
.cap
,
19349 bands
[index
]->vht_cap
.vht_mcs
.rx_mcs_map
,
19350 bands
[index
]->vht_cap
.vht_mcs
.tx_mcs_map
));
19354 else if (bandlist
[i
] == WLC_BAND_2G
&& __wl_band_2ghz
.n_channels
> 0) {
19355 bands
[NL80211_BAND_2GHZ
] =
19357 index
= NL80211_BAND_2GHZ
;
19358 if (bw_cap
== WLC_N_BW_40ALL
)
19359 bands
[index
]->ht_cap
.cap
|= IEEE80211_HT_CAP_SGI_40
;
19362 if ((index
>= 0) && nmode
) {
19363 bands
[index
]->ht_cap
.cap
|=
19364 (IEEE80211_HT_CAP_SGI_20
| IEEE80211_HT_CAP_DSSSCCK40
);
19365 bands
[index
]->ht_cap
.ht_supported
= TRUE
;
19366 bands
[index
]->ht_cap
.ampdu_factor
= IEEE80211_HT_MAX_AMPDU_64K
;
19367 bands
[index
]->ht_cap
.ampdu_density
= IEEE80211_HT_MPDU_DENSITY_16
;
19368 /* An HT shall support all EQM rates for one spatial stream */
19369 bands
[index
]->ht_cap
.mcs
.rx_mask
[0] = 0xff;
19374 wiphy
->bands
[NL80211_BAND_2GHZ
] = bands
[NL80211_BAND_2GHZ
];
19375 wiphy
->bands
[NL80211_BAND_5GHZ
] = bands
[NL80211_BAND_5GHZ
];
19377 /* check if any bands populated otherwise makes 2Ghz as default */
19378 if (wiphy
->bands
[NL80211_BAND_2GHZ
] == NULL
&&
19379 wiphy
->bands
[NL80211_BAND_5GHZ
] == NULL
) {
19380 /* Setup 2Ghz band as default */
19381 wiphy
->bands
[NL80211_BAND_2GHZ
] = &__wl_band_2ghz
;
19385 wiphy_apply_custom_regulatory(wiphy
, &brcm_regdom
);
19392 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
19393 const wl_event_msg_t
*e
, void *data
)
19395 s32 status
= ntoh32(e
->status
);
19396 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
19397 /* Abort fakeapscan, when Roam is in progress */
19398 if (status
== WLC_E_STATUS_RXBCN_ABORT
) {
19399 wl_android_bcnrecv_stop(ndev
, WL_BCNRECV_ROAMABORT
);
19401 WL_ERR(("UNKNOWN STATUS. status:%d\n", status
));
19405 #endif /* WL_BCNRECV */
19407 /* Get the concurrency mode */
19408 int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211
*cfg
)
19410 struct net_info
*iter
, *next
;
19411 uint cmode
= CONCURRENCY_MODE_NONE
;
19412 u32 connected_cnt
= 0;
19413 u32 pre_channel
= 0, channel
= 0;
19418 connected_cnt
= wl_get_drv_status_all(cfg
, CONNECTED
);
19419 if (connected_cnt
<= 1) {
19422 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19423 4 && __GNUC_MINOR__ >= 6))
19424 _Pragma("GCC diagnostic push")
19425 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
19427 for_each_ndev(cfg
, iter
, next
) {
19429 if (wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
)) {
19430 if (wldev_iovar_getint(iter
->ndev
, "chanspec",
19431 (s32
*)&chanspec
) == BCME_OK
) {
19432 channel
= wf_chspec_ctlchan(
19433 wl_chspec_driver_to_host(chanspec
));
19434 band
= (channel
<= CH_MAX_2G_CHANNEL
) ?
19435 NL80211_BAND_2GHZ
: NL80211_BAND_5GHZ
;
19437 if ((!pre_channel
&& channel
)) {
19439 pre_channel
= channel
;
19440 } else if (pre_channel
) {
19441 if ((pre_band
== band
) && (pre_channel
== channel
)) {
19442 cmode
= CONCURRENCY_SCC_MODE
;
19444 } else if ((pre_band
== band
) && (pre_channel
!= channel
)) {
19445 cmode
= CONCURRENCY_VSDB_MODE
;
19447 } else if (pre_band
!= band
) {
19448 cmode
= CONCURRENCY_RSDB_MODE
;
19455 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19456 4 && __GNUC_MINOR__ >= 6))
19457 _Pragma("GCC diagnostic pop")
19462 s32
wl_update_wiphybands(struct bcm_cfg80211
*cfg
, bool notify
)
19466 mutex_lock(&cfg
->usr_sync
);
19467 err
= __wl_update_wiphybands(cfg
, notify
);
19468 mutex_unlock(&cfg
->usr_sync
);
19473 static s32
__wl_cfg80211_up(struct bcm_cfg80211
*cfg
)
19476 #ifdef WL_HOST_BAND_MGMT
19478 #endif /* WL_HOST_BAND_MGMT */
19479 struct net_info
*netinfo
= NULL
;
19480 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
19481 struct wireless_dev
*wdev
= ndev
->ieee80211_ptr
;
19483 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
19484 #endif /* WBTEXT */
19487 #endif /* WLTDLS */
19493 /* Reserve 0x8000 toggle bit for P2P GO/GC */
19494 cfg
->vif_macaddr_mask
= 0x8000;
19496 err
= dhd_config_dongle(cfg
);
19500 /* Always bring up interface in STA mode.
19501 * Did observe , if previous SofAP Bringup/cleanup
19502 * is not done properly, iftype is stuck with AP mode.
19503 * So during next wlan0 up, forcing the type to STA
19505 netinfo
= wl_get_netinfo_by_wdev(cfg
, wdev
);
19507 WL_ERR(("there is no netinfo\n"));
19510 ndev
->ieee80211_ptr
->iftype
= NL80211_IFTYPE_STATION
;
19511 netinfo
->iftype
= WL_IF_TYPE_STA
;
19513 if (cfg80211_to_wl_iftype(wdev
->iftype
, &wl_iftype
, &wl_mode
) < 0) {
19516 err
= wl_config_infra(cfg
, ndev
, wl_iftype
);
19517 if (unlikely(err
&& err
!= -EINPROGRESS
)) {
19518 WL_ERR(("wl_config_infra failed\n"));
19520 WL_ERR(("return error %d\n", err
));
19524 err
= __wl_update_wiphybands(cfg
, true);
19525 if (unlikely(err
)) {
19526 WL_ERR(("wl_update_wiphybands failed\n"));
19528 WL_ERR(("return error %d\n", err
));
19532 if (!dhd_download_fw_on_driverload
) {
19533 err
= wl_create_event_handler(cfg
);
19535 WL_ERR(("wl_create_event_handler failed\n"));
19538 wl_init_event_handler(cfg
);
19540 err
= wl_init_scan(cfg
);
19542 WL_ERR(("wl_init_scan failed\n"));
19545 #ifdef DHD_LOSSLESS_ROAMING
19546 if (timer_pending(&cfg
->roam_timeout
)) {
19547 del_timer_sync(&cfg
->roam_timeout
);
19549 #endif /* DHD_LOSSLESS_ROAMING */
19551 err
= dhd_monitor_init(cfg
->pub
);
19553 #ifdef WL_HOST_BAND_MGMT
19554 /* By default the curr_band is initialized to BAND_AUTO */
19555 if ((ret
= wl_cfg80211_set_band(ndev
, WLC_BAND_AUTO
)) < 0) {
19556 if (ret
== BCME_UNSUPPORTED
) {
19557 /* Don't fail the initialization, lets just
19558 * fall back to the original method
19560 WL_ERR(("WL_HOST_BAND_MGMT defined, "
19561 "but roam_band iovar not supported \n"));
19563 WL_ERR(("roam_band failed. ret=%d", ret
));
19567 #endif /* WL_HOST_BAND_MGMT */
19568 #if defined(WES_SUPPORT)
19569 /* Reset WES mode to 0 */
19573 /* when wifi up, set roam_prof to default value */
19574 if (dhd
->wbtext_support
) {
19575 if (dhd
->op_mode
& DHD_FLAG_STA_MODE
) {
19576 wl_cfg80211_wbtext_set_default(ndev
);
19577 wl_cfg80211_wbtext_clear_bssid_list(cfg
);
19580 #endif /* WBTEXT */
19582 if (wldev_iovar_getint(ndev
, "tdls_enable", &tdls
) == 0) {
19583 WL_DBG(("TDLS supported in fw\n"));
19584 cfg
->tdls_supported
= true;
19586 #endif /* WLTDLS */
19587 INIT_DELAYED_WORK(&cfg
->pm_enable_work
, wl_cfg80211_work_handler
);
19588 wl_set_drv_status(cfg
, READY
, ndev
);
19592 static s32
__wl_cfg80211_down(struct bcm_cfg80211
*cfg
)
19595 unsigned long flags
;
19596 struct net_info
*iter
, *next
;
19597 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
19598 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
19599 defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
19600 struct net_device
*p2p_net
= cfg
->p2p_net
;
19601 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) && !PLATFORM_SLP */
19602 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
19603 WL_INFORM_MEM(("cfg80211 down\n"));
19605 /* Check if cfg80211 interface is already down */
19606 if (!wl_get_drv_status(cfg
, READY
, ndev
)) {
19607 WL_DBG(("cfg80211 interface is already down\n"));
19608 return err
; /* it is even not ready */
19611 #ifdef SHOW_LOGTRACE
19612 /* Stop the event logging */
19613 wl_add_remove_eventmsg(ndev
, WLC_E_TRACE
, FALSE
);
19614 #endif /* SHOW_LOGTRACE */
19616 /* clear vendor OUI list */
19617 wl_vndr_ies_clear_vendor_oui_list(cfg
);
19619 /* Delete pm_enable_work */
19620 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_DEL
);
19622 if (cfg
->p2p_supported
) {
19623 wl_clr_p2p_status(cfg
, GO_NEG_PHASE
);
19624 #ifdef PROP_TXSTATUS_VSDB
19625 #if defined(BCMSDIO)
19626 if (wl_cfgp2p_vif_created(cfg
)) {
19627 bool enabled
= false;
19628 dhd_wlfc_get_enable(dhd
, &enabled
);
19629 if (enabled
&& cfg
->wlfc_on
&& dhd
->op_mode
!= DHD_FLAG_HOSTAP_MODE
&&
19630 dhd
->op_mode
!= DHD_FLAG_IBSS_MODE
) {
19631 dhd_wlfc_deinit(dhd
);
19632 cfg
->wlfc_on
= false;
19635 #endif /* defined(BCMSDIO) */
19636 #endif /* PROP_TXSTATUS_VSDB */
19639 if (!dhd_download_fw_on_driverload
) {
19640 /* For built-in drivers/other drivers that do reset on
19641 * "ifconfig <primary_iface> down", cleanup any left
19644 wl_cfg80211_cleanup_virtual_ifaces(cfg
, false);
19646 /* Clear used mac addr mask */
19647 cfg
->vif_macaddr_mask
= 0;
19650 err
= wl_cfgnan_disable(cfg
, NAN_BUS_IS_DOWN
);
19651 if (err
!= BCME_OK
) {
19652 WL_ERR(("failed to disable nan, error[%d]\n", err
));
19654 #endif /* WL_NAN */
19658 /* If primary BSS is operational (for e.g SoftAP), bring it down */
19659 if (wl_cfg80211_bss_isup(ndev
, 0)) {
19660 if (wl_cfg80211_bss_up(cfg
, ndev
, 0, 0) < 0)
19661 WL_ERR(("BSS down failed \n"));
19664 /* clear all the security setting on primary Interface */
19665 wl_cfg80211_clear_security(cfg
);
19668 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19669 4 && __GNUC_MINOR__ >= 6))
19670 _Pragma("GCC diagnostic push")
19671 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
19673 for_each_ndev(cfg
, iter
, next
) {
19674 if (iter
->ndev
) /* p2p discovery iface is null */
19675 wl_set_drv_status(cfg
, SCAN_ABORTING
, iter
->ndev
);
19677 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19678 4 && __GNUC_MINOR__ >= 6))
19679 _Pragma("GCC diagnostic pop")
19682 #ifdef P2P_LISTEN_OFFLOADING
19683 wl_cfg80211_p2plo_deinit(cfg
);
19684 #endif /* P2P_LISTEN_OFFLOADING */
19686 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
19687 if (cfg
->scan_request
) {
19688 wl_notify_scan_done(cfg
, true);
19689 cfg
->scan_request
= NULL
;
19691 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
19692 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19693 4 && __GNUC_MINOR__ >= 6))
19694 _Pragma("GCC diagnostic push")
19695 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
19697 for_each_ndev(cfg
, iter
, next
) {
19698 /* p2p discovery iface ndev ptr could be null */
19699 if (iter
->ndev
== NULL
)
19701 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19702 WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
19703 wl_get_drv_status(cfg
, CONNECTING
, ndev
),
19704 wl_get_drv_status(cfg
, CONNECTED
, ndev
),
19705 wl_get_drv_status(cfg
, DISCONNECTING
, ndev
),
19706 wl_get_drv_status(cfg
, NESTED_CONNECT
, ndev
)));
19708 if ((iter
->ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
) &&
19709 wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
)) {
19710 CFG80211_DISCONNECTED(iter
->ndev
, 0, NULL
, 0, false, GFP_KERNEL
);
19713 if ((iter
->ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
) &&
19714 wl_get_drv_status(cfg
, CONNECTING
, iter
->ndev
)) {
19715 u8
*latest_bssid
= wl_read_prof(cfg
, ndev
, WL_PROF_LATEST_BSSID
);
19716 struct wiphy
*wiphy
= bcmcfg_to_wiphy(cfg
);
19717 struct wireless_dev
*wdev
= ndev
->ieee80211_ptr
;
19718 struct cfg80211_bss
*bss
= CFG80211_GET_BSS(wiphy
, NULL
, latest_bssid
,
19719 wdev
->ssid
, wdev
->ssid_len
);
19721 prhex("bssid:", (uchar
*)latest_bssid
, ETHER_ADDR_LEN
);
19722 prhex("ssid:", (uchar
*)wdev
->ssid
, wdev
->ssid_len
);
19724 WL_DBG(("null bss\n"));
19727 CFG80211_CONNECT_RESULT(ndev
,
19728 latest_bssid
, bss
, NULL
, 0, NULL
, 0,
19729 WLAN_STATUS_UNSPECIFIED_FAILURE
,
19732 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19733 wl_clr_drv_status(cfg
, READY
, iter
->ndev
);
19734 wl_clr_drv_status(cfg
, SCANNING
, iter
->ndev
);
19735 wl_clr_drv_status(cfg
, SCAN_ABORTING
, iter
->ndev
);
19736 wl_clr_drv_status(cfg
, CONNECTING
, iter
->ndev
);
19737 wl_clr_drv_status(cfg
, CONNECTED
, iter
->ndev
);
19738 wl_clr_drv_status(cfg
, DISCONNECTING
, iter
->ndev
);
19739 wl_clr_drv_status(cfg
, AP_CREATED
, iter
->ndev
);
19740 wl_clr_drv_status(cfg
, AP_CREATING
, iter
->ndev
);
19741 wl_clr_drv_status(cfg
, NESTED_CONNECT
, iter
->ndev
);
19742 wl_clr_drv_status(cfg
, CFG80211_CONNECT
, iter
->ndev
);
19744 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
19745 4 && __GNUC_MINOR__ >= 6))
19746 _Pragma("GCC diagnostic pop")
19748 bcmcfg_to_prmry_ndev(cfg
)->ieee80211_ptr
->iftype
=
19749 NL80211_IFTYPE_STATION
;
19750 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
19751 defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
19752 #ifdef SUPPORT_DEEP_SLEEP
19753 if (!trigger_deep_sleep
)
19754 #endif /* SUPPORT_DEEP_SLEEP */
19756 dev_close(p2p_net
);
19757 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT)&& !PLATFORM_SLP */
19759 /* Avoid deadlock from wl_cfg80211_down */
19760 if (!dhd_download_fw_on_driverload
) {
19761 mutex_unlock(&cfg
->usr_sync
);
19762 wl_destroy_event_handler(cfg
);
19763 mutex_lock(&cfg
->usr_sync
);
19768 if (cfg
->p2p_supported
) {
19769 if (timer_pending(&cfg
->p2p
->listen_timer
))
19770 del_timer_sync(&cfg
->p2p
->listen_timer
);
19771 wl_cfgp2p_down(cfg
);
19774 if (timer_pending(&cfg
->scan_timeout
)) {
19775 del_timer_sync(&cfg
->scan_timeout
);
19778 wl_cfg80211_clear_mgmt_vndr_ies(cfg
);
19779 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t
*)(cfg
->pub
));
19781 dhd_monitor_uninit();
19782 #ifdef WLAIBSS_MCHAN
19783 bcm_cfg80211_del_ibss_if(cfg
->wdev
->wiphy
, cfg
->ibss_cfgdev
);
19784 #endif /* WLAIBSS_MCHAN */
19787 /* Clear interworking element. */
19789 cfg
->wl11u
= FALSE
;
19793 #ifdef CUSTOMER_HW4_DEBUG
19794 if (wl_scan_timeout_dbg_enabled
) {
19795 wl_scan_timeout_dbg_clear();
19797 #endif /* CUSTOMER_HW4_DEBUG */
19799 cfg
->disable_roam_event
= false;
19801 DNGL_FUNC(dhd_cfg80211_down
, (cfg
));
19804 /* Printout all netinfo entries */
19805 wl_probe_wdev_all(cfg
);
19806 #endif /* DHD_IFDEBUG */
19811 s32
wl_cfg80211_up(struct net_device
*net
)
19813 struct bcm_cfg80211
*cfg
;
19817 #ifdef DISABLE_PM_BCNRX
19820 s8 iovbuf
[WLC_IOCTL_SMLEN
];
19821 #endif /* DISABLE_PM_BCNRX */
19824 cfg
= wl_get_cfg(net
);
19826 if ((err
= wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg
), WLC_GET_VERSION
, &val
,
19827 sizeof(int)) < 0)) {
19828 WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err
));
19832 if (val
!= WLC_IOCTL_VERSION
&& val
!= 1) {
19833 WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
19834 val
, WLC_IOCTL_VERSION
));
19835 return BCME_VERSION
;
19837 ioctl_version
= val
;
19838 WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version
));
19840 mutex_lock(&cfg
->usr_sync
);
19841 dhd
= (dhd_pub_t
*)(cfg
->pub
);
19842 if (!(dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
19843 err
= wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg
));
19844 if (unlikely(err
)) {
19845 mutex_unlock(&cfg
->usr_sync
);
19849 #if defined(BCMSUP_4WAY_HANDSHAKE)
19850 if (dhd
->fw_4way_handshake
) {
19851 /* This is a hacky method to indicate fw 4WHS support and
19852 * is used only for kernels (kernels < 3.14). For newer
19853 * kernels, we would be using vendor extn. path to advertise
19854 * FW based 4-way handshake feature support.
19856 cfg
->wdev
->wiphy
->features
|= NL80211_FEATURE_FW_4WAY_HANDSHAKE
;
19858 #endif /* BCMSUP_4WAY_HANDSHAKE */
19859 err
= __wl_cfg80211_up(cfg
);
19861 WL_ERR(("__wl_cfg80211_up failed\n"));
19863 #ifdef ROAM_CHANNEL_CACHE
19864 if (init_roam_cache(cfg
, ioctl_version
) == 0) {
19865 /* Enable support for Roam cache */
19866 cfg
->rcc_enabled
= true;
19867 WL_ERR(("Roam channel cache enabled\n"));
19869 WL_ERR(("Failed to enable RCC.\n"));
19871 #endif /* ROAM_CHANNEL_CACHE */
19873 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
19874 dhd_force_disable_singlcore_scan(dhd
);
19875 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
19877 /* IOVAR configurations with 'up' condition */
19878 #ifdef DISABLE_PM_BCNRX
19879 interr
= wldev_iovar_setbuf(net
, "pm_bcnrx", (char *)¶m
, sizeof(param
), iovbuf
,
19880 sizeof(iovbuf
), &cfg
->ioctl_buf_sync
);
19882 if (unlikely(interr
)) {
19883 WL_ERR(("Set pm_bcnrx returned (%d)\n", interr
));
19885 #endif /* DISABLE_PM_BCNRX */
19887 mutex_unlock(&cfg
->usr_sync
);
19889 #ifdef WLAIBSS_MCHAN
19890 bcm_cfg80211_add_ibss_if(cfg
->wdev
->wiphy
, IBSS_IF_NAME
);
19891 #endif /* WLAIBSS_MCHAN */
19893 #ifdef DUAL_STA_STATIC_IF
19894 /* Static Interface support is currently supported only for STA only builds (without P2P) */
19895 wl_cfg80211_create_iface(cfg
->wdev
->wiphy
, WL_IF_TYPE_STA
, NULL
, "wlan%d");
19896 #endif /* DUAL_STA_STATIC_IF */
19898 #ifdef SUPPORT_CUSTOM_SET_CAC
19899 cfg
->enable_cac
= 0;
19900 #endif /* SUPPORT_CUSTOM_SET_CAC */
19905 /* Private Event to Supplicant with indication that chip hangs */
19906 int wl_cfg80211_hang(struct net_device
*dev
, u16 reason
)
19908 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
19910 #if defined(SOFTAP_SEND_HANGEVT)
19911 /* specifc mac address used for hang event */
19912 uint8 hang_mac
[ETHER_ADDR_LEN
] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
19913 #endif /* SOFTAP_SEND_HANGEVT */
19918 RETURN_EIO_IF_NOT_UP(cfg
);
19920 dhd
= (dhd_pub_t
*)(cfg
->pub
);
19921 #if defined(DHD_HANG_SEND_UP_TEST)
19922 if (dhd
->req_hang_type
) {
19923 WL_ERR(("%s, Clear HANG test request 0x%x\n",
19924 __FUNCTION__
, dhd
->req_hang_type
));
19925 dhd
->req_hang_type
= 0;
19927 #endif /* DHD_HANG_SEND_UP_TEST */
19928 if ((dhd
->hang_reason
<= HANG_REASON_MASK
) || (dhd
->hang_reason
>= HANG_REASON_MAX
)) {
19929 WL_ERR(("%s, Invalid hang reason 0x%x\n",
19930 __FUNCTION__
, dhd
->hang_reason
));
19931 dhd
->hang_reason
= HANG_REASON_UNKNOWN
;
19933 #ifdef DHD_USE_EXTENDED_HANG_REASON
19934 if (dhd
->hang_reason
!= 0) {
19935 reason
= dhd
->hang_reason
;
19937 #endif /* DHD_USE_EXTENDED_HANG_REASON */
19938 WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32
)(dhd
->hang_reason
)));
19940 wl_add_remove_pm_enable_work(cfg
, WL_PM_WORKQ_DEL
);
19941 #ifdef SOFTAP_SEND_HANGEVT
19942 if (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) {
19943 cfg80211_del_sta(dev
, hang_mac
, GFP_ATOMIC
);
19945 #endif /* SOFTAP_SEND_HANGEVT */
19947 if (dhd
->up
== TRUE
) {
19948 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
19949 wl_cfgvendor_send_hang_event(dev
, reason
,
19950 dhd
->hang_info
, dhd
->hang_info_cnt
);
19952 CFG80211_DISCONNECTED(dev
, reason
, NULL
, 0, false, GFP_KERNEL
);
19953 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
19962 s32
wl_cfg80211_down(struct net_device
*dev
)
19964 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
19965 s32 err
= BCME_ERROR
;
19970 mutex_lock(&cfg
->usr_sync
);
19971 err
= __wl_cfg80211_down(cfg
);
19972 mutex_unlock(&cfg
->usr_sync
);
19979 wl_cfg80211_sta_ifdown(struct net_device
*dev
)
19981 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
19986 if (cfg
->scan_request
) {
19987 wl_notify_scan_done(cfg
, true);
19988 cfg
->scan_request
= NULL
;
19990 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19991 if ((dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
) &&
19992 wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
19993 CFG80211_DISCONNECTED(dev
, 0, NULL
, 0, false, GFP_KERNEL
);
19995 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19999 static void *wl_read_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, s32 item
)
20001 unsigned long flags
;
20003 struct wl_profile
*profile
= wl_get_profile_by_netdev(cfg
, ndev
);
20007 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
20010 rptr
= &profile
->sec
;
20013 rptr
= &profile
->active
;
20015 case WL_PROF_BSSID
:
20016 rptr
= profile
->bssid
;
20019 rptr
= &profile
->ssid
;
20022 rptr
= &profile
->channel
;
20024 case WL_PROF_LATEST_BSSID
:
20025 rptr
= profile
->latest_bssid
;
20028 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
20030 WL_ERR(("invalid item (%d)\n", item
));
20035 wl_update_prof(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
20036 const wl_event_msg_t
*e
, const void *data
, s32 item
)
20039 const struct wlc_ssid
*ssid
;
20040 unsigned long flags
;
20041 struct wl_profile
*profile
= wl_get_profile_by_netdev(cfg
, ndev
);
20045 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
20048 ssid
= (const wlc_ssid_t
*) data
;
20049 memset(profile
->ssid
.SSID
, 0,
20050 sizeof(profile
->ssid
.SSID
));
20051 profile
->ssid
.SSID_len
= MIN(ssid
->SSID_len
, DOT11_MAX_SSID_LEN
);
20052 memcpy(profile
->ssid
.SSID
, ssid
->SSID
, profile
->ssid
.SSID_len
);
20054 case WL_PROF_BSSID
:
20056 memcpy(profile
->bssid
, data
, ETHER_ADDR_LEN
);
20058 memset(profile
->bssid
, 0, ETHER_ADDR_LEN
);
20061 memcpy(&profile
->sec
, data
, sizeof(profile
->sec
));
20064 profile
->active
= *(const bool *)data
;
20066 case WL_PROF_BEACONINT
:
20067 profile
->beacon_interval
= *(const u16
*)data
;
20069 case WL_PROF_DTIMPERIOD
:
20070 profile
->dtim_period
= *(const u8
*)data
;
20073 profile
->channel
= *(const u32
*)data
;
20075 case WL_PROF_LATEST_BSSID
:
20077 memcpy(profile
->latest_bssid
, data
, ETHER_ADDR_LEN
);
20079 memset(profile
->latest_bssid
, 0, ETHER_ADDR_LEN
);
20086 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
20088 if (err
== -EOPNOTSUPP
)
20089 WL_ERR(("unsupported item (%d)\n", item
));
20094 void wl_cfg80211_dbg_level(u32 level
)
20097 * prohibit to change debug level
20098 * by insmod parameter.
20099 * eventually debug level will be configured
20100 * in compile time by using CONFIG_XXX
20102 /* wl_dbg_level = level; */
20105 static bool wl_is_ibssmode(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
20107 return wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_IBSS
;
20110 static __used
bool wl_is_ibssstarter(struct bcm_cfg80211
*cfg
)
20112 return cfg
->ibss_starter
;
20115 static void wl_rst_ie(struct bcm_cfg80211
*cfg
)
20117 struct wl_ie
*ie
= wl_to_ie(cfg
);
20122 static __used s32
wl_add_ie(struct bcm_cfg80211
*cfg
, u8 t
, u8 l
, u8
*v
)
20124 struct wl_ie
*ie
= wl_to_ie(cfg
);
20127 if (unlikely(ie
->offset
+ l
+ 2 > WL_TLV_INFO_MAX
)) {
20128 WL_ERR(("ei crosses buffer boundary\n"));
20131 ie
->buf
[ie
->offset
] = t
;
20132 ie
->buf
[ie
->offset
+ 1] = l
;
20133 memcpy(&ie
->buf
[ie
->offset
+ 2], v
, l
);
20134 ie
->offset
+= l
+ 2;
20139 static void wl_update_hidden_ap_ie(wl_bss_info_t
*bi
, const u8
*ie_stream
, u32
*ie_size
,
20143 int32 ssid_len
= MIN(bi
->SSID_len
, DOT11_MAX_SSID_LEN
);
20144 int32 remaining_ie_buf_len
, available_buffer_len
, unused_buf_len
;
20145 /* cfg80211_find_ie defined in kernel returning const u8 */
20147 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
20148 4 && __GNUC_MINOR__ >= 6))
20149 _Pragma("GCC diagnostic push")
20150 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
20152 ssidie
= (u8
*)cfg80211_find_ie(WLAN_EID_SSID
, ie_stream
, *ie_size
);
20153 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
20154 4 && __GNUC_MINOR__ >= 6))
20155 _Pragma("GCC diagnostic pop")
20159 * 1. No ssid IE is FOUND or
20160 * 2. New ssid length is > what was allocated for existing ssid (as
20161 * we do not want to overwrite the rest of the IEs) or
20162 * 3. If in case of erroneous buffer input where ssid length doesnt match the space
20168 available_buffer_len
= ((int)(*ie_size
)) - (ssidie
+ 2 - ie_stream
);
20169 remaining_ie_buf_len
= available_buffer_len
- (int)ssidie
[1];
20170 unused_buf_len
= WL_EXTRA_BUF_MAX
- (4 + bi
->length
+ *ie_size
);
20171 if (ssidie
[1] > available_buffer_len
) {
20172 WL_ERR_MEM(("%s: skip wl_update_hidden_ap_ie : overflow\n", __FUNCTION__
));
20176 if (ssidie
[1] != ssid_len
) {
20178 WL_INFORM_MEM(("%s: Wrong SSID len: %d != %d\n",
20179 __FUNCTION__
, ssidie
[1], bi
->SSID_len
));
20181 if ((roam
&& (ssid_len
> ssidie
[1])) && (unused_buf_len
> ssid_len
)) {
20182 WL_INFORM_MEM(("Changing the SSID Info.\n"));
20183 memmove(ssidie
+ ssid_len
+ 2,
20184 (ssidie
+ 2) + ssidie
[1],
20185 remaining_ie_buf_len
);
20186 memcpy(ssidie
+ 2, bi
->SSID
, ssid_len
);
20187 *ie_size
= *ie_size
+ ssid_len
- ssidie
[1];
20188 ssidie
[1] = ssid_len
;
20189 } else if (ssid_len
< ssidie
[1]) {
20190 WL_ERR_MEM(("%s: Invalid SSID len: %d < %d\n",
20191 __FUNCTION__
, bi
->SSID_len
, ssidie
[1]));
20195 if (*(ssidie
+ 2) == '\0')
20196 memcpy(ssidie
+ 2, bi
->SSID
, ssid_len
);
20200 static s32
wl_mrg_ie(struct bcm_cfg80211
*cfg
, u8
*ie_stream
, u16 ie_size
)
20202 struct wl_ie
*ie
= wl_to_ie(cfg
);
20205 if (unlikely(ie
->offset
+ ie_size
> WL_TLV_INFO_MAX
)) {
20206 WL_ERR(("ei_stream crosses buffer boundary\n"));
20209 memcpy(&ie
->buf
[ie
->offset
], ie_stream
, ie_size
);
20210 ie
->offset
+= ie_size
;
20215 static s32
wl_cp_ie(struct bcm_cfg80211
*cfg
, u8
*dst
, u16 dst_size
)
20217 struct wl_ie
*ie
= wl_to_ie(cfg
);
20220 if (unlikely(ie
->offset
> dst_size
)) {
20221 WL_ERR(("dst_size is not enough\n"));
20224 memcpy(dst
, &ie
->buf
[0], ie
->offset
);
20229 static u32
wl_get_ielen(struct bcm_cfg80211
*cfg
)
20231 struct wl_ie
*ie
= wl_to_ie(cfg
);
20236 static void wl_link_up(struct bcm_cfg80211
*cfg
)
20238 cfg
->link_up
= true;
20241 static void wl_link_down(struct bcm_cfg80211
*cfg
)
20243 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
20246 cfg
->link_up
= false;
20247 conn_info
->req_ie_len
= 0;
20248 conn_info
->resp_ie_len
= 0;
20251 static unsigned long wl_lock_eq(struct bcm_cfg80211
*cfg
)
20253 unsigned long flags
;
20255 spin_lock_irqsave(&cfg
->eq_lock
, flags
);
20259 static void wl_unlock_eq(struct bcm_cfg80211
*cfg
, unsigned long flags
)
20261 spin_unlock_irqrestore(&cfg
->eq_lock
, flags
);
20264 static void wl_init_eq_lock(struct bcm_cfg80211
*cfg
)
20266 spin_lock_init(&cfg
->eq_lock
);
20269 static void wl_delay(u32 ms
)
20271 if (in_atomic() || (ms
< jiffies_to_msecs(1))) {
20272 OSL_DELAY(ms
*1000);
20278 s32
wl_cfg80211_get_p2p_dev_addr(struct net_device
*net
, struct ether_addr
*p2pdev_addr
)
20280 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
20281 struct ether_addr primary_mac
;
20284 if (!p2p_is_on(cfg
)) {
20285 get_primary_mac(cfg
, &primary_mac
);
20286 wl_cfgp2p_generate_bss_mac(cfg
, &primary_mac
);
20287 memcpy((void *)&p2pdev_addr
, (void *)&primary_mac
, ETHER_ADDR_LEN
);
20289 memcpy(p2pdev_addr
->octet
, wl_to_p2p_bss_macaddr(cfg
, P2PAPI_BSSCFG_DEVICE
).octet
,
20295 s32
wl_cfg80211_set_p2p_noa(struct net_device
*net
, char* buf
, int len
)
20297 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
20299 return wl_cfgp2p_set_p2p_noa(cfg
, net
, buf
, len
);
20302 s32
wl_cfg80211_get_p2p_noa(struct net_device
*net
, char* buf
, int len
)
20304 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
20306 return wl_cfgp2p_get_p2p_noa(cfg
, net
, buf
, len
);
20309 s32
wl_cfg80211_set_p2p_ps(struct net_device
*net
, char* buf
, int len
)
20311 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
20313 return wl_cfgp2p_set_p2p_ps(cfg
, net
, buf
, len
);
20316 s32
wl_cfg80211_set_p2p_ecsa(struct net_device
*net
, char* buf
, int len
)
20318 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
20320 return wl_cfgp2p_set_p2p_ecsa(cfg
, net
, buf
, len
);
20323 s32
wl_cfg80211_increase_p2p_bw(struct net_device
*net
, char* buf
, int len
)
20325 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
20327 return wl_cfgp2p_increase_p2p_bw(cfg
, net
, buf
, len
);
20330 #ifdef P2PLISTEN_AP_SAMECHN
20331 s32
wl_cfg80211_set_p2p_resp_ap_chn(struct net_device
*net
, s32 enable
)
20333 s32 ret
= wldev_iovar_setint(net
, "p2p_resp_ap_chn", enable
);
20335 if ((ret
== 0) && enable
) {
20336 /* disable PM for p2p responding on infra AP channel */
20339 ret
= wldev_ioctl_set(net
, WLC_SET_PM
, &pm
, sizeof(pm
));
20344 #endif /* P2PLISTEN_AP_SAMECHN */
20346 s32
wl_cfg80211_channel_to_freq(u32 channel
)
20350 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
20351 freq
= ieee80211_channel_to_frequency(channel
);
20355 if (channel
<= CH_MAX_2G_CHANNEL
)
20356 band
= NL80211_BAND_2GHZ
;
20358 band
= NL80211_BAND_5GHZ
;
20359 freq
= ieee80211_channel_to_frequency(channel
, band
);
20367 wl_tdls_event_handler(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
20368 const wl_event_msg_t
*e
, void *data
) {
20370 struct net_device
*ndev
= NULL
;
20371 u32 reason
= ntoh32(e
->reason
);
20374 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
20377 case WLC_E_TDLS_PEER_DISCOVERED
:
20378 msg
= " TDLS PEER DISCOVERD ";
20380 case WLC_E_TDLS_PEER_CONNECTED
:
20381 if (cfg
->tdls_mgmt_frame
) {
20382 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
20383 cfg80211_rx_mgmt(cfgdev
, cfg
->tdls_mgmt_freq
, 0,
20384 cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
, 0);
20385 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
20386 cfg80211_rx_mgmt(cfgdev
, cfg
->tdls_mgmt_freq
, 0,
20387 cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
, 0,
20389 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
20390 defined(WL_COMPAT_WIRELESS)
20391 cfg80211_rx_mgmt(cfgdev
, cfg
->tdls_mgmt_freq
, 0,
20392 cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
,
20395 cfg80211_rx_mgmt(cfgdev
, cfg
->tdls_mgmt_freq
,
20396 cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
, GFP_ATOMIC
);
20398 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
20400 msg
= " TDLS PEER CONNECTED ";
20401 #ifdef SUPPORT_SET_CAC
20402 /* TDLS connect reset CAC */
20403 wl_cfg80211_set_cac(cfg
, 0);
20404 #endif /* SUPPORT_SET_CAC */
20406 case WLC_E_TDLS_PEER_DISCONNECTED
:
20407 if (cfg
->tdls_mgmt_frame
) {
20408 MFREE(cfg
->osh
, cfg
->tdls_mgmt_frame
, cfg
->tdls_mgmt_frame_len
);
20409 cfg
->tdls_mgmt_frame
= NULL
;
20410 cfg
->tdls_mgmt_frame_len
= 0;
20411 cfg
->tdls_mgmt_freq
= 0;
20413 msg
= "TDLS PEER DISCONNECTED ";
20414 #ifdef SUPPORT_SET_CAC
20415 /* TDLS disconnec, set CAC */
20416 wl_cfg80211_set_cac(cfg
, 1);
20417 #endif /* SUPPORT_SET_CAC */
20421 WL_ERR(("%s: " MACDBG
" on %s ndev\n", msg
, MAC2STRDBG((const u8
*)(&e
->addr
)),
20422 (bcmcfg_to_prmry_ndev(cfg
) == ndev
) ? "primary" : "secondary"));
20427 #endif /* WLTDLS */
20429 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
20430 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
20431 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
20433 wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
20434 u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
20435 u32 peer_capability
, const u8
*buf
, size_t len
)
20436 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
20437 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
20438 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
20439 const u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
20440 u32 peer_capability
, const u8
*buf
, size_t len
)
20441 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
20442 static s32
wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
20443 const u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
20444 u32 peer_capability
, bool initiator
, const u8
*buf
, size_t len
)
20445 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20447 wl_cfg80211_tdls_mgmt(struct wiphy
*wiphy
, struct net_device
*dev
,
20448 u8
*peer
, u8 action_code
, u8 dialog_token
, u16 status_code
,
20449 const u8
*buf
, size_t len
)
20450 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20454 struct bcm_cfg80211
*cfg
;
20455 tdls_wfd_ie_iovar_t info
;
20456 memset(&info
, 0, sizeof(tdls_wfd_ie_iovar_t
));
20457 cfg
= wl_get_cfg(dev
);
20459 #if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
20460 /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
20461 * and that cuases build error
20463 BCM_REFERENCE(peer_capability
);
20464 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20466 switch (action_code
) {
20467 /* We need to set TDLS Wifi Display IE to firmware
20468 * using tdls_wfd_ie iovar
20470 case WLAN_TDLS_SET_PROBE_WFD_IE
:
20471 WL_ERR(("%s WLAN_TDLS_SET_PROBE_WFD_IE\n", __FUNCTION__
));
20472 info
.mode
= TDLS_WFD_PROBE_IE_TX
;
20473 memcpy(&info
.data
, buf
, len
);
20476 case WLAN_TDLS_SET_SETUP_WFD_IE
:
20477 WL_ERR(("%s WLAN_TDLS_SET_SETUP_WFD_IE\n", __FUNCTION__
));
20478 info
.mode
= TDLS_WFD_IE_TX
;
20479 memcpy(&info
.data
, buf
, len
);
20482 case WLAN_TDLS_SET_WFD_ENABLED
:
20483 WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_ENABLED\n", __FUNCTION__
));
20484 dhd_tdls_set_mode((dhd_pub_t
*)(cfg
->pub
), true);
20486 case WLAN_TDLS_SET_WFD_DISABLED
:
20487 WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_DISABLED\n", __FUNCTION__
));
20488 dhd_tdls_set_mode((dhd_pub_t
*)(cfg
->pub
), false);
20491 WL_ERR(("Unsupported action code : %d\n", action_code
));
20494 ret
= wldev_iovar_setbuf(dev
, "tdls_wfd_ie", &info
, sizeof(info
),
20495 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
20498 WL_ERR(("tdls_wfd_ie error %d\n", ret
));
20502 #endif /* WLTDLS */
20506 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
20508 wl_cfg80211_tdls_oper(struct wiphy
*wiphy
, struct net_device
*dev
,
20509 const u8
*peer
, enum nl80211_tdls_operation oper
)
20512 wl_cfg80211_tdls_oper(struct wiphy
*wiphy
, struct net_device
*dev
,
20513 u8
*peer
, enum nl80211_tdls_operation oper
)
20518 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
20521 bool tdls_auto_mode
= false;
20522 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
20523 memset(&info
, 0, sizeof(tdls_iovar_t
));
20525 memcpy(&info
.ea
, peer
, ETHER_ADDR_LEN
);
20530 case NL80211_TDLS_DISCOVERY_REQ
:
20531 /* If the discovery request is broadcast then we need to set
20532 * info.mode to Tunneled Probe Request
20534 if (memcmp(peer
, (const uint8
*)BSSID_BROADCAST
, ETHER_ADDR_LEN
) == 0) {
20535 info
.mode
= TDLS_MANUAL_EP_WFD_TPQ
;
20536 WL_ERR(("%s TDLS TUNNELED PRBOBE REQUEST\n", __FUNCTION__
));
20538 info
.mode
= TDLS_MANUAL_EP_DISCOVERY
;
20541 case NL80211_TDLS_SETUP
:
20542 if (dhdp
->tdls_mode
== true) {
20543 info
.mode
= TDLS_MANUAL_EP_CREATE
;
20544 tdls_auto_mode
= false;
20545 /* Do tear down and create a fresh one */
20546 ret
= wl_cfg80211_tdls_config(cfg
, TDLS_STATE_TEARDOWN
, tdls_auto_mode
);
20551 tdls_auto_mode
= true;
20554 case NL80211_TDLS_TEARDOWN
:
20555 info
.mode
= TDLS_MANUAL_EP_DELETE
;
20558 WL_ERR(("Unsupported operation : %d\n", oper
));
20562 ret
= wl_cfg80211_tdls_config(cfg
, TDLS_STATE_SETUP
, tdls_auto_mode
);
20567 ret
= wldev_iovar_setbuf(dev
, "tdls_endpoint", &info
, sizeof(info
),
20568 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
20570 WL_ERR(("tdls_endpoint error %d\n", ret
));
20575 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
20578 #endif /* WLTDLS */
20581 #endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
20583 s32
wl_cfg80211_set_wps_p2p_ie(struct net_device
*ndev
, char *buf
, int len
,
20584 enum wl_management_type type
)
20586 struct bcm_cfg80211
*cfg
;
20588 struct ether_addr primary_mac
;
20591 cfg
= wl_get_cfg(ndev
);
20593 if (wl_get_drv_status(cfg
, AP_CREATING
, ndev
)) {
20594 /* Vendor IEs should be set to FW
20595 * after SoftAP interface is brought up
20597 WL_DBG(("Skipping set IE since AP is not up \n"));
20599 } else if (ndev
== bcmcfg_to_prmry_ndev(cfg
)) {
20600 /* Either stand alone AP case or P2P discovery */
20601 if (wl_get_drv_status(cfg
, AP_CREATED
, ndev
)) {
20602 /* Stand alone AP case on primary interface */
20603 WL_DBG(("Apply IEs for Primary AP Interface \n"));
20607 /* If p2p not initialized, return failure */
20608 WL_ERR(("P2P not initialized \n"));
20611 /* P2P Discovery case (p2p listen) */
20612 if (!cfg
->p2p
->on
) {
20613 /* Turn on Discovery interface */
20614 get_primary_mac(cfg
, &primary_mac
);
20615 wl_cfgp2p_generate_bss_mac(cfg
, &primary_mac
);
20616 p2p_on(cfg
) = true;
20617 ret
= wl_cfgp2p_enable_discovery(cfg
, ndev
, NULL
, 0);
20618 if (unlikely(ret
)) {
20619 WL_ERR(("Enable discovery failed \n"));
20623 WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
20624 ndev
= wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_PRIMARY
);
20625 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
20628 /* Virtual AP/ P2P Group Interface */
20629 WL_DBG(("Apply IEs for iface:%s\n", ndev
->name
));
20630 bssidx
= wl_get_bssidx_by_wdev(cfg
, ndev
->ieee80211_ptr
);
20633 if (ndev
!= NULL
) {
20636 pktflag
= VNDR_IE_BEACON_FLAG
;
20638 case WL_PROBE_RESP
:
20639 pktflag
= VNDR_IE_PRBRSP_FLAG
;
20641 case WL_ASSOC_RESP
:
20642 pktflag
= VNDR_IE_ASSOCRSP_FLAG
;
20646 ret
= wl_cfg80211_set_mgmt_vndr_ies(cfg
,
20647 ndev_to_cfgdev(ndev
), bssidx
, pktflag
, buf
, len
);
20654 #ifdef WL_SUPPORT_AUTO_CHANNEL
20656 wl_cfg80211_set_auto_channel_scan_state(struct net_device
*ndev
)
20659 s32 ret
= BCME_ERROR
;
20660 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
20662 if (wl_check_dongle_idle(bcmcfg_to_wiphy(cfg
)) != TRUE
) {
20663 WL_ERR(("FW is busy to add interface"));
20667 /* Set interface up, explicitly. */
20670 ret
= wldev_ioctl_set(ndev
, WLC_UP
, (void *)&val
, sizeof(val
));
20672 WL_ERR(("set interface up failed, error = %d\n", ret
));
20676 /* Stop all scan explicitly, till auto channel selection complete. */
20677 wl_set_drv_status(cfg
, SCANNING
, ndev
);
20678 if (cfg
->escan_info
.ndev
== NULL
) {
20683 wl_cfg80211_cancel_scan(cfg
);
20690 wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec
)
20692 bool valid
= false;
20693 char chanbuf
[CHANSPEC_STR_LEN
];
20695 /* channel 1 to 14 */
20696 if ((chanspec
>= 0x2b01) && (chanspec
<= 0x2b0e)) {
20699 /* channel 36 to 48 */
20700 else if ((chanspec
>= 0x1b24) && (chanspec
<= 0x1b30)) {
20703 /* channel 149 to 161 */
20704 else if ((chanspec
>= 0x1b95) && (chanspec
<= 0x1ba1)) {
20709 WL_INFORM_MEM(("invalid P2P chanspec, chanspec = %s\n",
20710 wf_chspec_ntoa_ex(chanspec
, chanbuf
)));
20717 wl_cfg80211_get_chanspecs_2g(struct net_device
*ndev
, void *buf
, s32 buflen
)
20719 s32 ret
= BCME_ERROR
;
20720 struct bcm_cfg80211
*cfg
= NULL
;
20721 chanspec_t chanspec
= 0;
20723 cfg
= wl_get_cfg(ndev
);
20725 /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
20726 chanspec
|= (WL_CHANSPEC_BAND_2G
| WL_CHANSPEC_BW_20
|
20727 WL_CHANSPEC_CTL_SB_NONE
);
20728 chanspec
= wl_chspec_host_to_driver(chanspec
);
20730 ret
= wldev_iovar_getbuf_bsscfg(ndev
, "chanspecs", (void *)&chanspec
,
20731 sizeof(chanspec
), buf
, buflen
, 0, &cfg
->ioctl_buf_sync
);
20733 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret
));
20740 wl_cfg80211_get_chanspecs_5g(struct net_device
*ndev
, void *buf
, s32 buflen
)
20743 s32 ret
= BCME_ERROR
;
20746 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
20747 wl_uint32_list_t
*list
= NULL
;
20748 chanspec_t chanspec
= 0;
20750 /* Restrict channels to 5GHz, 20MHz BW, no SB. */
20751 chanspec
|= (WL_CHANSPEC_BAND_5G
| WL_CHANSPEC_BW_20
|
20752 WL_CHANSPEC_CTL_SB_NONE
);
20753 chanspec
= wl_chspec_host_to_driver(chanspec
);
20755 ret
= wldev_iovar_getbuf_bsscfg(ndev
, "chanspecs", (void *)&chanspec
,
20756 sizeof(chanspec
), buf
, buflen
, 0, &cfg
->ioctl_buf_sync
);
20758 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret
));
20762 list
= (wl_uint32_list_t
*)buf
;
20763 /* Skip DFS and inavlid P2P channel. */
20764 for (i
= 0, j
= 0; i
< dtoh32(list
->count
); i
++) {
20765 chanspec
= (chanspec_t
) dtoh32(list
->element
[i
]);
20766 channel
= CHSPEC_CHANNEL(chanspec
);
20768 ret
= wldev_iovar_getint(ndev
, "per_chan_info", &channel
);
20770 WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret
));
20774 if (CHANNEL_IS_RADAR(channel
) ||
20775 !(wl_cfg80211_valid_chanspec_p2p(chanspec
))) {
20778 list
->element
[j
] = list
->element
[i
];
20791 wl_cfg80211_get_best_channel(struct net_device
*ndev
, void *buf
, int buflen
,
20794 s32 ret
= BCME_ERROR
;
20798 /* Start auto channel selection scan. */
20799 ret
= wldev_ioctl_set(ndev
, WLC_START_CHANNEL_SEL
, NULL
, 0);
20801 WL_ERR(("can't start auto channel scan, error = %d\n", ret
));
20806 /* Wait for auto channel selection, worst case possible delay is 5250ms. */
20807 retry
= CHAN_SEL_RETRY_COUNT
;
20810 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY
);
20812 ret
= wldev_ioctl_get(ndev
, WLC_GET_CHANNEL_SEL
, &chosen
, sizeof(chosen
));
20813 if ((ret
== 0) && (dtoh32(chosen
) != 0)) {
20814 *channel
= (u16
)(chosen
& 0x00FF);
20815 WL_INFORM_MEM(("selected channel = %d\n", *channel
));
20818 WL_DBG(("attempt = %d, ret = %d, chosen = %d\n",
20819 (CHAN_SEL_RETRY_COUNT
- retry
), ret
, dtoh32(chosen
)));
20823 WL_ERR(("failure, auto channel selection timed out\n"));
20833 wl_cfg80211_restore_auto_channel_scan_state(struct net_device
*ndev
)
20835 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
20836 /* Clear scan stop driver status. */
20837 wl_clr_drv_status(cfg
, SCANNING
, ndev
);
20843 wl_cfg80211_get_best_channels(struct net_device
*dev
, char* cmd
, int total_len
)
20846 s32 ret
= BCME_ERROR
;
20849 struct bcm_cfg80211
*cfg
= NULL
;
20850 struct net_device
*ndev
= NULL
;
20852 memset(cmd
, 0, total_len
);
20853 cfg
= wl_get_cfg(dev
);
20855 buf
= (u8
*)MALLOC(cfg
->osh
, CHANSPEC_BUF_SIZE
);
20857 WL_ERR(("failed to allocate chanspec buffer\n"));
20862 * Always use primary interface, irrespective of interface on which
20865 ndev
= bcmcfg_to_prmry_ndev(cfg
);
20868 * Make sure that FW and driver are in right state to do auto channel
20871 ret
= wl_cfg80211_set_auto_channel_scan_state(ndev
);
20873 WL_ERR(("can't set auto channel scan state, error = %d\n", ret
));
20877 /* Best channel selection in 2.4GHz band. */
20878 ret
= wl_cfg80211_get_chanspecs_2g(ndev
, (void *)buf
, CHANSPEC_BUF_SIZE
);
20880 WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret
));
20884 ret
= wl_cfg80211_get_best_channel(ndev
, (void *)buf
, CHANSPEC_BUF_SIZE
,
20887 WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret
));
20891 if (CHANNEL_IS_2G(channel
)) {
20892 channel
= ieee80211_channel_to_frequency(channel
, NL80211_BAND_2GHZ
);
20894 WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel
));
20898 pos
+= snprintf(pos
, total_len
, "%04d ", channel
);
20900 /* Best channel selection in 5GHz band. */
20901 ret
= wl_cfg80211_get_chanspecs_5g(ndev
, (void *)buf
, CHANSPEC_BUF_SIZE
);
20903 WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret
));
20907 ret
= wl_cfg80211_get_best_channel(ndev
, (void *)buf
, CHANSPEC_BUF_SIZE
,
20910 WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret
));
20914 if (CHANNEL_IS_5G(channel
)) {
20915 channel
= ieee80211_channel_to_frequency(channel
, NL80211_BAND_5GHZ
);
20917 WL_ERR(("invalid 5GHz channel, channel = %d\n", channel
));
20921 pos
+= snprintf(pos
, total_len
- (pos
- cmd
), "%04d ", channel
);
20923 /* Set overall best channel same as 5GHz best channel. */
20924 pos
+= snprintf(pos
, total_len
- (pos
- cmd
), "%04d ", channel
);
20928 MFREE(cfg
->osh
, buf
, CHANSPEC_BUF_SIZE
);
20931 /* Restore FW and driver back to normal state. */
20932 ret
= wl_cfg80211_restore_auto_channel_scan_state(ndev
);
20934 WL_ERR(("can't restore auto channel scan state, error = %d\n", ret
));
20937 return (pos
- cmd
);
20939 #endif /* WL_SUPPORT_AUTO_CHANNEL */
20941 static const struct rfkill_ops wl_rfkill_ops
= {
20942 .set_block
= wl_rfkill_set
20945 static int wl_rfkill_set(void *data
, bool blocked
)
20947 struct bcm_cfg80211
*cfg
= (struct bcm_cfg80211
*)data
;
20949 WL_DBG(("Enter \n"));
20950 WL_DBG(("RF %s\n", blocked
? "blocked" : "unblocked"));
20955 cfg
->rf_blocked
= blocked
;
20960 static int wl_setup_rfkill(struct bcm_cfg80211
*cfg
, bool setup
)
20964 WL_DBG(("Enter \n"));
20968 cfg
->rfkill
= rfkill_alloc("brcmfmac-wifi",
20969 wl_cfg80211_get_parent_dev(),
20970 RFKILL_TYPE_WLAN
, &wl_rfkill_ops
, (void *)cfg
);
20972 if (!cfg
->rfkill
) {
20977 err
= rfkill_register(cfg
->rfkill
);
20980 rfkill_destroy(cfg
->rfkill
);
20982 if (!cfg
->rfkill
) {
20987 rfkill_unregister(cfg
->rfkill
);
20988 rfkill_destroy(cfg
->rfkill
);
20995 #ifdef DEBUGFS_CFG80211
20997 * Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
20998 * to turn on SCAN and DBG log.
20999 * To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
21000 * To see current setting of debug level,
21001 * cat /sys/kernel/debug/dhd/debug_level
21004 wl_debuglevel_write(struct file
*file
, const char __user
*userbuf
,
21005 size_t count
, loff_t
*ppos
)
21007 char tbuf
[SUBLOGLEVELZ
* ARRAYSIZE(sublogname_map
)], sublog
[SUBLOGLEVELZ
];
21008 char *params
, *token
, *colon
;
21009 uint i
, tokens
, log_on
= 0;
21010 size_t minsize
= min_t(size_t, (sizeof(tbuf
) - 1), count
);
21012 memset(tbuf
, 0, sizeof(tbuf
));
21013 memset(sublog
, 0, sizeof(sublog
));
21014 if (copy_from_user(&tbuf
, userbuf
, minsize
)) {
21018 tbuf
[minsize
] = '\0';
21020 colon
= strchr(params
, '\n');
21023 while ((token
= strsep(¶ms
, " ")) != NULL
) {
21024 memset(sublog
, 0, sizeof(sublog
));
21025 if (token
== NULL
|| !*token
)
21027 if (*token
== '\0')
21029 colon
= strchr(token
, ':');
21030 if (colon
!= NULL
) {
21033 tokens
= sscanf(token
, "%"S(SUBLOGLEVEL
)"s %u", sublog
, &log_on
);
21038 for (i
= 0; i
< ARRAYSIZE(sublogname_map
); i
++) {
21039 if (!strncmp(sublog
, sublogname_map
[i
].sublogname
,
21040 strlen(sublogname_map
[i
].sublogname
))) {
21043 (sublogname_map
[i
].log_level
);
21046 ~(sublogname_map
[i
].log_level
);
21050 WL_ERR(("%s: can't parse '%s' as a "
21051 "SUBMODULE:LEVEL (%d tokens)\n",
21052 tbuf
, token
, tokens
));
21059 wl_debuglevel_read(struct file
*file
, char __user
*user_buf
,
21060 size_t count
, loff_t
*ppos
)
21063 char tbuf
[SUBLOGLEVELZ
* ARRAYSIZE(sublogname_map
)];
21065 memset(tbuf
, 0, sizeof(tbuf
));
21067 for (i
= 0; i
< ARRAYSIZE(sublogname_map
); i
++) {
21068 param
+= snprintf(param
, sizeof(tbuf
) - 1, "%s:%d ",
21069 sublogname_map
[i
].sublogname
,
21070 (wl_dbg_level
& sublogname_map
[i
].log_level
) ? 1 : 0);
21073 return simple_read_from_buffer(user_buf
, count
, ppos
, tbuf
, strlen(&tbuf
[0]));
21076 static const struct file_operations fops_debuglevel
= {
21078 .write
= wl_debuglevel_write
,
21079 .read
= wl_debuglevel_read
,
21080 .owner
= THIS_MODULE
,
21084 static s32
wl_setup_debugfs(struct bcm_cfg80211
*cfg
)
21087 struct dentry
*_dentry
;
21090 cfg
->debugfs
= debugfs_create_dir(KBUILD_MODNAME
, NULL
);
21091 if (!cfg
->debugfs
|| IS_ERR(cfg
->debugfs
)) {
21092 if (cfg
->debugfs
== ERR_PTR(-ENODEV
))
21093 WL_ERR(("Debugfs is not enabled on this kernel\n"));
21095 WL_ERR(("Can not create debugfs directory\n"));
21096 cfg
->debugfs
= NULL
;
21100 _dentry
= debugfs_create_file("debug_level", S_IRUSR
| S_IWUSR
,
21101 cfg
->debugfs
, cfg
, &fops_debuglevel
);
21102 if (!_dentry
|| IS_ERR(_dentry
)) {
21103 WL_ERR(("failed to create debug_level debug file\n"));
21104 wl_free_debugfs(cfg
);
21109 static s32
wl_free_debugfs(struct bcm_cfg80211
*cfg
)
21114 debugfs_remove_recursive(cfg
->debugfs
);
21115 cfg
->debugfs
= NULL
;
21118 #endif /* DEBUGFS_CFG80211 */
21120 struct bcm_cfg80211
*wl_cfg80211_get_bcmcfg(void)
21125 void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211
*cfg
)
21130 struct device
*wl_cfg80211_get_parent_dev(void)
21132 return cfg80211_parent_dev
;
21135 void wl_cfg80211_set_parent_dev(void *dev
)
21137 cfg80211_parent_dev
= dev
;
21140 static void wl_cfg80211_clear_parent_dev(void)
21142 cfg80211_parent_dev
= NULL
;
21145 void get_primary_mac(struct bcm_cfg80211
*cfg
, struct ether_addr
*mac
)
21147 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
21149 if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg
),
21150 "cur_etheraddr", NULL
, 0, ioctl_buf
, sizeof(ioctl_buf
),
21151 0, NULL
) == BCME_OK
) {
21152 memcpy(mac
->octet
, ioctl_buf
, ETHER_ADDR_LEN
);
21154 memset(mac
->octet
, 0, ETHER_ADDR_LEN
);
21157 static bool check_dev_role_integrity(struct bcm_cfg80211
*cfg
, u32 dev_role
)
21159 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
21160 if (((dev_role
== NL80211_IFTYPE_AP
) &&
21161 !(dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) ||
21162 ((dev_role
== NL80211_IFTYPE_P2P_GO
) &&
21163 !(dhd
->op_mode
& DHD_FLAG_P2P_GO_MODE
)))
21165 WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role
, dhd
->op_mode
));
21171 int wl_cfg80211_do_driver_init(struct net_device
*net
)
21173 struct bcm_cfg80211
*cfg
= *(struct bcm_cfg80211
**)netdev_priv(net
);
21175 if (!cfg
|| !cfg
->wdev
)
21178 if (dhd_do_driver_init(cfg
->wdev
->netdev
) < 0)
21184 void wl_cfg80211_enable_trace(bool set
, u32 level
)
21187 wl_dbg_level
= level
& WL_DBG_LEVEL
;
21189 wl_dbg_level
|= (WL_DBG_LEVEL
& level
);
21191 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
21194 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy
*wiphy
,
21195 bcm_struct_cfgdev
*cfgdev
, u64 cookie
)
21197 /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
21198 * is passed with CMD_FRAME. This callback is supposed to cancel
21199 * the OFFCHANNEL Wait. Since we are already taking care of that
21200 * with the tx_mgmt logic, do nothing here.
21205 #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
21209 wl_cfg80211_find_interworking_ie(const u8
*parse
, u32 len
)
21213 /* unfortunately it's too much work to dispose the const cast - bcm_parse_tlvs
21214 * is used everywhere and changing its prototype to take const qualifier needs
21215 * a massive change to all its callers...
21218 if ((ie
= bcm_parse_tlvs(parse
, len
, DOT11_MNG_INTERWORKING_ID
))) {
21225 wl_cfg80211_clear_iw_ie(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, s32 bssidx
)
21227 ie_setbuf_t ie_setbuf
;
21229 WL_DBG(("clear interworking IE\n"));
21231 memset(&ie_setbuf
, 0, sizeof(ie_setbuf_t
));
21233 ie_setbuf
.ie_buffer
.iecount
= htod32(1);
21234 ie_setbuf
.ie_buffer
.ie_list
[0].ie_data
.id
= DOT11_MNG_INTERWORKING_ID
;
21235 ie_setbuf
.ie_buffer
.ie_list
[0].ie_data
.len
= 0;
21237 return wldev_iovar_setbuf_bsscfg(ndev
, "ie", &ie_setbuf
, sizeof(ie_setbuf
),
21238 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
);
21242 wl_cfg80211_add_iw_ie(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, s32 bssidx
, s32 pktflag
,
21243 uint8 ie_id
, uint8
*data
, uint8 data_len
)
21247 ie_setbuf_t
*ie_setbuf
;
21248 ie_getbuf_t ie_getbufp
;
21249 char getbuf
[WLC_IOCTL_SMLEN
];
21251 if (ie_id
!= DOT11_MNG_INTERWORKING_ID
) {
21252 WL_ERR(("unsupported (id=%d)\n", ie_id
));
21253 return BCME_UNSUPPORTED
;
21256 /* access network options (1 octet) is the mandatory field */
21257 if (!data
|| data_len
== 0 || data_len
> IW_IES_MAX_BUF_LEN
) {
21258 WL_ERR(("wrong interworking IE (len=%d)\n", data_len
));
21259 return BCME_BADARG
;
21262 /* Validate the pktflag parameter */
21263 if ((pktflag
& ~(VNDR_IE_BEACON_FLAG
| VNDR_IE_PRBRSP_FLAG
|
21264 VNDR_IE_ASSOCRSP_FLAG
| VNDR_IE_AUTHRSP_FLAG
|
21265 VNDR_IE_PRBREQ_FLAG
| VNDR_IE_ASSOCREQ_FLAG
|
21266 VNDR_IE_CUSTOM_FLAG
))) {
21267 WL_ERR(("invalid packet flag 0x%x\n", pktflag
));
21268 return BCME_BADARG
;
21271 buf_len
= sizeof(ie_setbuf_t
) + data_len
- 1;
21273 ie_getbufp
.id
= DOT11_MNG_INTERWORKING_ID
;
21274 if (wldev_iovar_getbuf_bsscfg(ndev
, "ie", (void *)&ie_getbufp
,
21275 sizeof(ie_getbufp
), getbuf
, WLC_IOCTL_SMLEN
, bssidx
, &cfg
->ioctl_buf_sync
)
21277 if (!memcmp(&getbuf
[TLV_HDR_LEN
], data
, data_len
)) {
21278 WL_DBG(("skip to set interworking IE\n"));
21283 /* if already set with previous values, delete it first */
21285 if ((err
= wl_cfg80211_clear_iw_ie(cfg
, ndev
, bssidx
)) != BCME_OK
) {
21290 ie_setbuf
= (ie_setbuf_t
*)MALLOCZ(cfg
->osh
, buf_len
);
21292 WL_ERR(("Error allocating buffer for IE\n"));
21295 strncpy(ie_setbuf
->cmd
, "add", sizeof(ie_setbuf
->cmd
));
21296 ie_setbuf
->cmd
[sizeof(ie_setbuf
->cmd
) - 1] = '\0';
21298 /* Buffer contains only 1 IE */
21299 ie_setbuf
->ie_buffer
.iecount
= htod32(1);
21300 /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */
21301 ie_setbuf
->ie_buffer
.ie_list
[0].pktflag
= htod32(pktflag
);
21303 /* Now, add the IE to the buffer */
21304 ie_setbuf
->ie_buffer
.ie_list
[0].ie_data
.id
= DOT11_MNG_INTERWORKING_ID
;
21305 ie_setbuf
->ie_buffer
.ie_list
[0].ie_data
.len
= data_len
;
21306 memcpy((uchar
*)&ie_setbuf
->ie_buffer
.ie_list
[0].ie_data
.data
[0], data
, data_len
);
21308 if ((err
= wldev_iovar_setbuf_bsscfg(ndev
, "ie", ie_setbuf
, buf_len
,
21309 cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
, bssidx
, &cfg
->ioctl_buf_sync
))
21311 WL_DBG(("set interworking IE\n"));
21313 err
= wldev_iovar_setint_bsscfg(ndev
, "grat_arp", 1, bssidx
);
21316 MFREE(cfg
->osh
, ie_setbuf
, buf_len
);
21321 #ifdef WL_HOST_BAND_MGMT
21323 wl_cfg80211_set_band(struct net_device
*ndev
, int band
)
21325 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21327 char ioctl_buf
[50];
21329 if ((band
< WLC_BAND_AUTO
) || (band
> WLC_BAND_2G
)) {
21330 WL_ERR(("Invalid band\n"));
21334 if ((ret
= wldev_iovar_setbuf(ndev
, "roam_band", &band
,
21335 sizeof(int), ioctl_buf
, sizeof(ioctl_buf
), NULL
)) < 0) {
21336 WL_ERR(("seting roam_band failed code=%d\n", ret
));
21340 WL_DBG(("Setting band to %d\n", band
));
21341 cfg
->curr_band
= band
;
21345 #endif /* WL_HOST_BAND_MGMT */
21348 wl_cfg80211_set_if_band(struct net_device
*ndev
, int band
)
21350 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21351 int ret
= 0, wait_cnt
;
21352 char ioctl_buf
[32];
21354 if ((band
< WLC_BAND_AUTO
) || (band
> WLC_BAND_2G
)) {
21355 WL_ERR(("Invalid band\n"));
21358 if (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) {
21359 ret
= wldev_ioctl_set(ndev
, WLC_DISASSOC
, NULL
, 0);
21361 WL_ERR(("WLC_DISASSOC error %d\n", ret
));
21362 /* continue to set 'if_band' */
21365 /* This is to ensure that 'if_band' iovar is issued only after
21366 * disconnection is completed
21368 wait_cnt
= WAIT_FOR_DISCONNECT_MAX
;
21369 while (wl_get_drv_status(cfg
, CONNECTED
, ndev
) && wait_cnt
) {
21370 WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt
));
21376 if ((ret
= wldev_iovar_setbuf(ndev
, "if_band", &band
,
21377 sizeof(int), ioctl_buf
, sizeof(ioctl_buf
), NULL
)) < 0) {
21378 WL_ERR(("seting if_band failed ret=%d\n", ret
));
21379 /* issue 'WLC_SET_BAND' if if_band is not supported */
21380 if (ret
== BCME_UNSUPPORTED
) {
21381 ret
= wldev_set_band(ndev
, band
);
21383 WL_ERR(("seting band failed ret=%d\n", ret
));
21391 wl_cfg80211_dfs_ap_move(struct net_device
*ndev
, char *data
, char *command
, int total_len
)
21393 char ioctl_buf
[WLC_IOCTL_SMLEN
];
21396 chanspec_t chanspec
= 0;
21398 int bytes_written
= 0;
21399 struct wl_dfs_ap_move_status_v2
*status
;
21400 char chanbuf
[CHANSPEC_STR_LEN
];
21401 const char *dfs_state_str
[DFS_SCAN_S_MAX
] = {
21402 "Radar Free On Channel",
21403 "Radar Found On Channel",
21404 "Radar Scan In Progress",
21405 "Radar Scan Aborted",
21406 "RSDB Mode switch in Progress For Scan"
21408 if (ndev
->ieee80211_ptr
->iftype
!= NL80211_IFTYPE_AP
) {
21409 bytes_written
= snprintf(command
, total_len
, "AP is not up\n");
21410 return bytes_written
;
21413 if ((err
= wldev_iovar_getbuf(ndev
, "dfs_ap_move", NULL
, 0,
21414 ioctl_buf
, sizeof(ioctl_buf
), NULL
))) {
21415 WL_ERR(("setting dfs_ap_move failed with err=%d \n", err
));
21418 status
= (struct wl_dfs_ap_move_status_v2
*)ioctl_buf
;
21420 if (status
->version
!= WL_DFS_AP_MOVE_VERSION
) {
21421 err
= BCME_UNSUPPORTED
;
21422 WL_ERR(("err=%d version=%d\n", err
, status
->version
));
21426 if (status
->move_status
!= (int8
) DFS_SCAN_S_IDLE
) {
21427 chanspec
= wl_chspec_driver_to_host(status
->chanspec
);
21428 if (chanspec
!= 0 && chanspec
!= INVCHANSPEC
) {
21429 wf_chspec_ntoa(chanspec
, chanbuf
);
21430 bytes_written
= snprintf(command
, total_len
,
21431 "AP Target Chanspec %s (0x%x)\n", chanbuf
, chanspec
);
21433 bytes_written
+= snprintf(command
+ bytes_written
,
21434 total_len
- bytes_written
,
21435 "%s\n", dfs_state_str
[status
->move_status
]);
21436 return bytes_written
;
21438 bytes_written
= snprintf(command
, total_len
, "dfs AP move in IDLE state\n");
21439 return bytes_written
;
21443 abort
= bcm_atoi(data
);
21445 if ((err
= wldev_iovar_setbuf(ndev
, "dfs_ap_move", &abort
,
21446 sizeof(int), ioctl_buf
, sizeof(ioctl_buf
), NULL
)) < 0) {
21447 WL_ERR(("seting dfs_ap_move failed with err %d\n", err
));
21451 chanspec
= wf_chspec_aton(data
);
21452 if (chanspec
!= 0) {
21453 val
= wl_chspec_host_to_driver(chanspec
);
21454 if (val
!= INVCHANSPEC
) {
21455 if ((err
= wldev_iovar_setbuf(ndev
, "dfs_ap_move", &val
,
21456 sizeof(int), ioctl_buf
, sizeof(ioctl_buf
), NULL
)) < 0) {
21457 WL_ERR(("seting dfs_ap_move failed with err %d\n", err
));
21460 WL_DBG((" set dfs_ap_move successfull"));
21462 err
= BCME_USAGE_ERROR
;
21471 wl_cfg80211_wbtext_set_default(struct net_device
*ndev
)
21473 char commandp
[WLC_IOCTL_SMLEN
];
21477 WL_DBG(("set wbtext to default\n"));
21479 /* set roam profile */
21480 memset(commandp
, 0, sizeof(commandp
));
21481 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21482 CMD_WBTEXT_PROFILE_CONFIG
, DEFAULT_WBTEXT_PROFILE_A
);
21483 data
= (commandp
+ strlen(CMD_WBTEXT_PROFILE_CONFIG
) + 1);
21484 ret
= wl_cfg80211_wbtext_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21485 if (ret
!= BCME_OK
) {
21486 WL_ERR(("%s: Failed to set roam_prof %s error = %d\n",
21487 __FUNCTION__
, data
, ret
));
21491 memset(commandp
, 0, sizeof(commandp
));
21492 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21493 CMD_WBTEXT_PROFILE_CONFIG
, DEFAULT_WBTEXT_PROFILE_B
);
21494 data
= (commandp
+ strlen(CMD_WBTEXT_PROFILE_CONFIG
) + 1);
21495 ret
= wl_cfg80211_wbtext_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21496 if (ret
!= BCME_OK
) {
21497 WL_ERR(("%s: Failed to set roam_prof %s error = %d\n",
21498 __FUNCTION__
, data
, ret
));
21502 /* set RSSI weight */
21503 memset(commandp
, 0, sizeof(commandp
));
21504 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21505 CMD_WBTEXT_WEIGHT_CONFIG
, DEFAULT_WBTEXT_WEIGHT_RSSI_A
);
21506 data
= (commandp
+ strlen(CMD_WBTEXT_WEIGHT_CONFIG
) + 1);
21507 ret
= wl_cfg80211_wbtext_weight_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21508 if (ret
!= BCME_OK
) {
21509 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
21510 __FUNCTION__
, data
, ret
));
21514 memset(commandp
, 0, sizeof(commandp
));
21515 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21516 CMD_WBTEXT_WEIGHT_CONFIG
, DEFAULT_WBTEXT_WEIGHT_RSSI_B
);
21517 data
= (commandp
+ strlen(CMD_WBTEXT_WEIGHT_CONFIG
) + 1);
21518 ret
= wl_cfg80211_wbtext_weight_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21519 if (ret
!= BCME_OK
) {
21520 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
21521 __FUNCTION__
, data
, ret
));
21525 /* set CU weight */
21526 memset(commandp
, 0, sizeof(commandp
));
21527 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21528 CMD_WBTEXT_WEIGHT_CONFIG
, DEFAULT_WBTEXT_WEIGHT_CU_A
);
21529 data
= (commandp
+ strlen(CMD_WBTEXT_WEIGHT_CONFIG
) + 1);
21530 ret
= wl_cfg80211_wbtext_weight_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21531 if (ret
!= BCME_OK
) {
21532 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
21533 __FUNCTION__
, data
, ret
));
21537 memset(commandp
, 0, sizeof(commandp
));
21538 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21539 CMD_WBTEXT_WEIGHT_CONFIG
, DEFAULT_WBTEXT_WEIGHT_CU_B
);
21540 data
= (commandp
+ strlen(CMD_WBTEXT_WEIGHT_CONFIG
) + 1);
21541 ret
= wl_cfg80211_wbtext_weight_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21542 if (ret
!= BCME_OK
) {
21543 WL_ERR(("%s: Failed to set weight config %s error = %d\n",
21544 __FUNCTION__
, data
, ret
));
21548 /* set RSSI table */
21549 memset(commandp
, 0, sizeof(commandp
));
21550 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21551 CMD_WBTEXT_TABLE_CONFIG
, DEFAULT_WBTEXT_TABLE_RSSI_A
);
21552 data
= (commandp
+ strlen(CMD_WBTEXT_TABLE_CONFIG
) + 1);
21553 ret
= wl_cfg80211_wbtext_table_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21554 if (ret
!= BCME_OK
) {
21555 WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
21556 __FUNCTION__
, data
, ret
));
21560 memset(commandp
, 0, sizeof(commandp
));
21561 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21562 CMD_WBTEXT_TABLE_CONFIG
, DEFAULT_WBTEXT_TABLE_RSSI_B
);
21563 data
= (commandp
+ strlen(CMD_WBTEXT_TABLE_CONFIG
) + 1);
21564 ret
= wl_cfg80211_wbtext_table_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21565 if (ret
!= BCME_OK
) {
21566 WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
21567 __FUNCTION__
, data
, ret
));
21572 memset(commandp
, 0, sizeof(commandp
));
21573 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21574 CMD_WBTEXT_TABLE_CONFIG
, DEFAULT_WBTEXT_TABLE_CU_A
);
21575 data
= (commandp
+ strlen(CMD_WBTEXT_TABLE_CONFIG
) + 1);
21576 ret
= wl_cfg80211_wbtext_table_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21577 if (ret
!= BCME_OK
) {
21578 WL_ERR(("%s: Failed to set CU table %s error = %d\n",
21579 __FUNCTION__
, data
, ret
));
21583 memset(commandp
, 0, sizeof(commandp
));
21584 snprintf(commandp
, WLC_IOCTL_SMLEN
, "%s %s",
21585 CMD_WBTEXT_TABLE_CONFIG
, DEFAULT_WBTEXT_TABLE_CU_B
);
21586 data
= (commandp
+ strlen(CMD_WBTEXT_TABLE_CONFIG
) + 1);
21587 ret
= wl_cfg80211_wbtext_table_config(ndev
, data
, commandp
, WLC_IOCTL_SMLEN
);
21588 if (ret
!= BCME_OK
) {
21589 WL_ERR(("%s: Failed to set CU table %s error = %d\n",
21590 __FUNCTION__
, data
, ret
));
21598 wl_cfg80211_wbtext_config(struct net_device
*ndev
, char *data
, char *command
, int total_len
)
21601 long int rssi_lower
, roam_trigger
;
21602 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21603 wl_roam_prof_band_v2_t
*rp
;
21604 int err
= -EINVAL
, bytes_written
= 0;
21605 size_t len
= strlen(data
);
21607 u8 ioctl_buf
[WLC_IOCTL_MEDLEN
];
21610 rp
= (wl_roam_prof_band_v2_t
*)MALLOCZ(cfg
->osh
, sizeof(*rp
)
21611 * WL_MAX_ROAM_PROF_BRACKETS
);
21612 if (unlikely(!rp
)) {
21613 WL_ERR(("%s: failed to allocate memory\n", __func__
));
21617 rp
->ver
= WL_MAX_ROAM_PROF_VER
;
21618 if (*data
&& (!strncmp(data
, "b", 1))) {
21619 rp
->band
= WLC_BAND_2G
;
21620 } else if (*data
&& (!strncmp(data
, "a", 1))) {
21621 rp
->band
= WLC_BAND_5G
;
21623 err
= snprintf(command
, total_len
, "Missing band\n");
21628 /* Getting roam profile from fw */
21629 if ((err
= wldev_iovar_getbuf(ndev
, "roam_prof", rp
, sizeof(*rp
),
21630 ioctl_buf
, sizeof(ioctl_buf
), NULL
))) {
21631 WL_ERR(("Getting roam_profile failed with err=%d \n", err
));
21634 memcpy(rp
, ioctl_buf
, sizeof(*rp
) * WL_MAX_ROAM_PROF_BRACKETS
);
21635 /* roam_prof version get */
21636 if (rp
->ver
!= WL_MAX_ROAM_PROF_VER
) {
21637 WL_ERR(("bad version (=%d) in return data\n", rp
->ver
));
21641 if ((rp
->len
% sizeof(wl_roam_prof_v2_t
)) != 0) {
21642 WL_ERR(("bad length (=%d) in return data\n", rp
->len
));
21648 for (i
= 0; i
< WL_MAX_ROAM_PROF_BRACKETS
; i
++) {
21649 /* printing contents of roam profile data from fw and exits
21650 * if code hits any of one of the below condtion. If remaining
21651 * length of buffer is less than roam profile size or
21652 * if there is no valid entry.
21654 if (((i
* sizeof(wl_roam_prof_v2_t
)) > rp
->len
) ||
21655 (rp
->roam_prof
[i
].fullscan_period
== 0)) {
21658 bytes_written
+= snprintf(command
+bytes_written
,
21659 total_len
- bytes_written
,
21660 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)\n",
21661 rp
->roam_prof
[i
].roam_trigger
, rp
->roam_prof
[i
].rssi_lower
,
21662 rp
->roam_prof
[i
].channel_usage
,
21663 rp
->roam_prof
[i
].cu_avg_calc_dur
);
21665 err
= bytes_written
;
21668 for (i
= 0; i
< WL_MAX_ROAM_PROF_BRACKETS
; i
++) {
21669 /* reading contents of roam profile data from fw and exits
21670 * if code hits any of one of the below condtion, If remaining
21671 * length of buffer is less than roam profile size or if there
21672 * is no valid entry.
21674 if (((i
* sizeof(wl_roam_prof_v2_t
)) > rp
->len
) ||
21675 (rp
->roam_prof
[i
].fullscan_period
== 0)) {
21679 /* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
21681 WL_ERR(("FW must have 2 rows to fill roam_prof\n"));
21685 /* setting roam profile to fw */
21687 for (i
= 0; i
< WL_MAX_ROAM_PROF_BRACKETS
; i
++) {
21688 roam_trigger
= simple_strtol(data
, &data
, 10);
21689 if (roam_trigger
>= 0) {
21690 WL_ERR(("roam trigger[%d] value must be negative\n", i
));
21694 rp
->roam_prof
[i
].roam_trigger
= roam_trigger
;
21696 rssi_lower
= simple_strtol(data
, &data
, 10);
21697 if (rssi_lower
>= 0) {
21698 WL_ERR(("rssi lower[%d] value must be negative\n", i
));
21702 rp
->roam_prof
[i
].rssi_lower
= rssi_lower
;
21704 rp
->roam_prof
[i
].channel_usage
= simple_strtol(data
, &data
, 10);
21706 rp
->roam_prof
[i
].cu_avg_calc_dur
= simple_strtol(data
, &data
, 10);
21708 rp_len
+= sizeof(wl_roam_prof_v2_t
);
21710 if (*data
== '\0') {
21716 WL_ERR(("Only two roam_prof rows supported.\n"));
21721 if ((err
= wldev_iovar_setbuf(ndev
, "roam_prof", rp
,
21722 sizeof(*rp
), cfg
->ioctl_buf
, WLC_IOCTL_MEDLEN
,
21723 &cfg
->ioctl_buf_sync
)) < 0) {
21724 WL_ERR(("seting roam_profile failed with err %d\n", err
));
21729 MFREE(cfg
->osh
, rp
, sizeof(*rp
) * WL_MAX_ROAM_PROF_BRACKETS
);
21734 int wl_cfg80211_wbtext_weight_config(struct net_device
*ndev
, char *data
,
21735 char *command
, int total_len
)
21737 int bytes_written
= 0, err
= -EINVAL
, argc
= 0;
21738 char rssi
[BUFSZN
], band
[BUFSZN
], weight
[BUFSZN
];
21739 char *endptr
= NULL
;
21740 wnm_bss_select_weight_cfg_t
*bwcfg
;
21741 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
21742 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21744 bwcfg
= (wnm_bss_select_weight_cfg_t
*)MALLOCZ(cfg
->osh
, sizeof(*bwcfg
));
21745 if (unlikely(!bwcfg
)) {
21746 WL_ERR(("%s: failed to allocate memory\n", __func__
));
21750 bwcfg
->version
= WNM_BSSLOAD_MONITOR_VERSION
;
21754 argc
= sscanf(data
, "%"S(BUFSZ
)"s %"S(BUFSZ
)"s %"S(BUFSZ
)"s", rssi
, band
, weight
);
21756 if (!strcasecmp(rssi
, "rssi"))
21757 bwcfg
->type
= WNM_BSS_SELECT_TYPE_RSSI
;
21758 else if (!strcasecmp(rssi
, "cu"))
21759 bwcfg
->type
= WNM_BSS_SELECT_TYPE_CU
;
21761 /* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu> <band> <weight> */
21762 WL_ERR(("%s: Command usage error\n", __func__
));
21766 if (!strcasecmp(band
, "a"))
21767 bwcfg
->band
= WLC_BAND_5G
;
21768 else if (!strcasecmp(band
, "b"))
21769 bwcfg
->band
= WLC_BAND_2G
;
21770 else if (!strcasecmp(band
, "all"))
21771 bwcfg
->band
= WLC_BAND_ALL
;
21773 WL_ERR(("%s: Command usage error\n", __func__
));
21778 /* If there is no data after band, getting wnm_bss_select_weight from fw */
21779 if (bwcfg
->band
== WLC_BAND_ALL
) {
21780 WL_ERR(("band option \"all\" is for set only, not get\n"));
21783 if ((err
= wldev_iovar_getbuf(ndev
, "wnm_bss_select_weight", bwcfg
,
21785 ioctl_buf
, sizeof(ioctl_buf
), NULL
))) {
21786 WL_ERR(("Getting wnm_bss_select_weight failed with err=%d \n", err
));
21789 memcpy(bwcfg
, ioctl_buf
, sizeof(*bwcfg
));
21790 bytes_written
= snprintf(command
, total_len
, "%s %s weight = %d\n",
21791 (bwcfg
->type
== WNM_BSS_SELECT_TYPE_RSSI
) ? "RSSI" : "CU",
21792 (bwcfg
->band
== WLC_BAND_2G
) ? "2G" : "5G", bwcfg
->weight
);
21793 err
= bytes_written
;
21796 /* if weight is non integer returns command usage error */
21797 bwcfg
->weight
= simple_strtol(weight
, &endptr
, 0);
21798 if (*endptr
!= '\0') {
21799 WL_ERR(("%s: Command usage error", __func__
));
21802 /* setting weight for iovar wnm_bss_select_weight to fw */
21803 if ((err
= wldev_iovar_setbuf(ndev
, "wnm_bss_select_weight", bwcfg
,
21805 ioctl_buf
, sizeof(ioctl_buf
), NULL
))) {
21806 WL_ERR(("Getting wnm_bss_select_weight failed with err=%d\n", err
));
21811 MFREE(cfg
->osh
, bwcfg
, sizeof(*bwcfg
));
21816 /* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
21817 #define WBTEXT_TUPLE_MIN_LEN_CHECK 5
21819 int wl_cfg80211_wbtext_table_config(struct net_device
*ndev
, char *data
,
21820 char *command
, int total_len
)
21822 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21823 int bytes_written
= 0, err
= -EINVAL
;
21824 char rssi
[BUFSZN
], band
[BUFSZN
];
21825 int btcfg_len
= 0, i
= 0, parsed_len
= 0;
21826 wnm_bss_select_factor_cfg_t
*btcfg
;
21827 size_t slen
= strlen(data
);
21828 char *start_addr
= NULL
;
21829 u8 ioctl_buf
[WLC_IOCTL_SMLEN
];
21832 btcfg
= (wnm_bss_select_factor_cfg_t
*)MALLOCZ(cfg
->osh
,
21833 (sizeof(*btcfg
) + sizeof(*btcfg
) * WL_FACTOR_TABLE_MAX_LIMIT
));
21834 if (unlikely(!btcfg
)) {
21835 WL_ERR(("%s: failed to allocate memory\n", __func__
));
21840 btcfg
->version
= WNM_BSS_SELECT_FACTOR_VERSION
;
21841 btcfg
->band
= WLC_BAND_AUTO
;
21845 sscanf(data
, "%"S(BUFSZ
)"s %"S(BUFSZ
)"s", rssi
, band
);
21847 if (!strcasecmp(rssi
, "rssi")) {
21848 btcfg
->type
= WNM_BSS_SELECT_TYPE_RSSI
;
21850 else if (!strcasecmp(rssi
, "cu")) {
21851 btcfg
->type
= WNM_BSS_SELECT_TYPE_CU
;
21854 WL_ERR(("%s: Command usage error\n", __func__
));
21858 if (!strcasecmp(band
, "a")) {
21859 btcfg
->band
= WLC_BAND_5G
;
21861 else if (!strcasecmp(band
, "b")) {
21862 btcfg
->band
= WLC_BAND_2G
;
21864 else if (!strcasecmp(band
, "all")) {
21865 btcfg
->band
= WLC_BAND_ALL
;
21868 WL_ERR(("%s: Command usage, Wrong band\n", __func__
));
21872 if ((slen
- 1) == (strlen(rssi
) + strlen(band
))) {
21873 /* Getting factor table using iovar 'wnm_bss_select_table' from fw */
21874 if ((err
= wldev_iovar_getbuf(ndev
, "wnm_bss_select_table", btcfg
,
21876 ioctl_buf
, sizeof(ioctl_buf
), NULL
))) {
21877 WL_ERR(("Getting wnm_bss_select_table failed with err=%d \n", err
));
21880 memcpy(btcfg
, ioctl_buf
, sizeof(*btcfg
));
21881 memcpy(btcfg
, ioctl_buf
, (btcfg
->count
+1) * sizeof(*btcfg
));
21883 bytes_written
+= snprintf(command
+ bytes_written
, total_len
- bytes_written
,
21884 "No of entries in table: %d\n", btcfg
->count
);
21885 bytes_written
+= snprintf(command
+ bytes_written
, total_len
- bytes_written
,
21886 "%s factor table\n",
21887 (btcfg
->type
== WNM_BSS_SELECT_TYPE_RSSI
) ? "RSSI" : "CU");
21888 bytes_written
+= snprintf(command
+ bytes_written
, total_len
- bytes_written
,
21889 "low\thigh\tfactor\n");
21890 for (i
= 0; i
<= btcfg
->count
-1; i
++) {
21891 bytes_written
+= snprintf(command
+ bytes_written
,
21892 total_len
- bytes_written
, "%d\t%d\t%d\n", btcfg
->params
[i
].low
,
21893 btcfg
->params
[i
].high
, btcfg
->params
[i
].factor
);
21895 err
= bytes_written
;
21898 memset(btcfg
->params
, 0, sizeof(wnm_bss_select_factor_params_t
)
21899 * WL_FACTOR_TABLE_MAX_LIMIT
);
21900 data
+= (strlen(rssi
) + strlen(band
) + 2);
21902 slen
= slen
- (strlen(rssi
) + strlen(band
) + 2);
21903 for (i
= 0; i
< WL_FACTOR_TABLE_MAX_LIMIT
; i
++) {
21904 if (parsed_len
+ WBTEXT_TUPLE_MIN_LEN_CHECK
<= slen
) {
21905 btcfg
->params
[i
].low
= simple_strtol(data
, &data
, 10);
21907 btcfg
->params
[i
].high
= simple_strtol(data
, &data
, 10);
21909 btcfg
->params
[i
].factor
= simple_strtol(data
, &data
, 10);
21911 if (*data
== '\0') {
21915 parsed_len
= data
- start_addr
;
21917 WL_ERR(("%s:Command usage:less no of args\n", __func__
));
21921 btcfg_len
= sizeof(*btcfg
) + ((btcfg
->count
) * sizeof(*btcfg
));
21922 if ((err
= wldev_iovar_setbuf(ndev
, "wnm_bss_select_table", btcfg
, btcfg_len
,
21923 cfg
->ioctl_buf
, WLC_IOCTL_MEDLEN
, &cfg
->ioctl_buf_sync
)) < 0) {
21924 WL_ERR(("seting wnm_bss_select_table failed with err %d\n", err
));
21930 MFREE(cfg
->osh
, btcfg
,
21931 (sizeof(*btcfg
) + sizeof(*btcfg
) * WL_FACTOR_TABLE_MAX_LIMIT
));
21937 wl_cfg80211_wbtext_delta_config(struct net_device
*ndev
, char *data
, char *command
, int total_len
)
21940 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
21941 int err
= -EINVAL
, bytes_written
= 0, argc
= 0, val
, len
= 0;
21942 char delta
[BUFSZN
], band
[BUFSZN
], *endptr
= NULL
;
21943 wl_roam_prof_band_v2_t
*rp
;
21944 u8 ioctl_buf
[WLC_IOCTL_MEDLEN
];
21946 rp
= (wl_roam_prof_band_v2_t
*)MALLOCZ(cfg
->osh
, sizeof(*rp
)
21947 * WL_MAX_ROAM_PROF_BRACKETS
);
21948 if (unlikely(!rp
)) {
21949 WL_ERR(("%s: failed to allocate memory\n", __func__
));
21954 argc
= sscanf(data
, "%"S(BUFSZ
)"s %"S(BUFSZ
)"s", band
, delta
);
21955 if (!strcasecmp(band
, "a"))
21956 rp
->band
= WLC_BAND_5G
;
21957 else if (!strcasecmp(band
, "b"))
21958 rp
->band
= WLC_BAND_2G
;
21960 WL_ERR(("%s: Missing band\n", __func__
));
21963 /* Getting roam profile from fw */
21964 if ((err
= wldev_iovar_getbuf(ndev
, "roam_prof", rp
, sizeof(*rp
),
21965 ioctl_buf
, sizeof(ioctl_buf
), NULL
))) {
21966 WL_ERR(("Getting roam_profile failed with err=%d \n", err
));
21969 memcpy(rp
, ioctl_buf
, sizeof(wl_roam_prof_band_v2_t
));
21970 if (rp
->ver
!= WL_MAX_ROAM_PROF_VER
) {
21971 WL_ERR(("bad version (=%d) in return data\n", rp
->ver
));
21975 if ((rp
->len
% sizeof(wl_roam_prof_v2_t
)) != 0) {
21976 WL_ERR(("bad length (=%d) in return data\n", rp
->len
));
21982 /* if delta is non integer returns command usage error */
21983 val
= simple_strtol(delta
, &endptr
, 0);
21984 if (*endptr
!= '\0') {
21985 WL_ERR(("%s: Command usage error", __func__
));
21988 for (i
= 0; i
< WL_MAX_ROAM_PROF_BRACKETS
; i
++) {
21990 * Checking contents of roam profile data from fw and exits
21991 * if code hits below condtion. If remaining length of buffer is
21992 * less than roam profile size or if there is no valid entry.
21994 if (((i
* sizeof(wl_roam_prof_v2_t
)) > rp
->len
) ||
21995 (rp
->roam_prof
[i
].fullscan_period
== 0)) {
21998 if (rp
->roam_prof
[i
].channel_usage
!= 0) {
21999 rp
->roam_prof
[i
].roam_delta
= val
;
22001 len
+= sizeof(wl_roam_prof_v2_t
);
22005 if (rp
->roam_prof
[i
].channel_usage
!= 0) {
22006 bytes_written
= snprintf(command
, total_len
,
22007 "%s Delta %d\n", (rp
->band
== WLC_BAND_2G
) ? "2G" : "5G",
22008 rp
->roam_prof
[0].roam_delta
);
22010 err
= bytes_written
;
22014 if ((err
= wldev_iovar_setbuf(ndev
, "roam_prof", rp
,
22015 sizeof(*rp
), cfg
->ioctl_buf
, WLC_IOCTL_MEDLEN
,
22016 &cfg
->ioctl_buf_sync
)) < 0) {
22017 WL_ERR(("seting roam_profile failed with err %d\n", err
));
22021 MFREE(cfg
->osh
, rp
, sizeof(*rp
)
22022 * WL_MAX_ROAM_PROF_BRACKETS
);
22026 #endif /* WBTEXT */
22028 int wl_cfg80211_scan_stop(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
)
22030 struct net_device
*ndev
= NULL
;
22031 unsigned long flags
;
22032 int clear_flag
= 0;
22035 WL_TRACE(("Enter\n"));
22037 if (!cfg
|| !cfgdev
)
22040 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
22042 spin_lock_irqsave(&cfg
->cfgdrv_lock
, flags
);
22043 #ifdef WL_CFG80211_P2P_DEV_IF
22044 if (cfg
->scan_request
&& cfg
->scan_request
->wdev
== cfgdev
) {
22046 if (cfg
->scan_request
&& cfg
->scan_request
->dev
== cfgdev
) {
22048 wl_notify_scan_done(cfg
, true);
22049 cfg
->scan_request
= NULL
;
22052 spin_unlock_irqrestore(&cfg
->cfgdrv_lock
, flags
);
22055 wl_clr_drv_status(cfg
, SCANNING
, ndev
);
22060 bool wl_cfg80211_is_concurrent_mode(struct net_device
*dev
)
22062 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22063 if ((cfg
) && (wl_get_drv_status_all(cfg
, CONNECTED
) > 1)) {
22070 void* wl_cfg80211_get_dhdp(struct net_device
*dev
)
22072 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22077 bool wl_cfg80211_is_p2p_active(struct net_device
*dev
)
22079 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22080 return (cfg
&& cfg
->p2p
);
22083 bool wl_cfg80211_is_roam_offload(struct net_device
* dev
)
22085 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22086 return (cfg
&& cfg
->roam_offload
);
22089 bool wl_cfg80211_is_event_from_connected_bssid(struct net_device
* dev
, const wl_event_msg_t
*e
,
22092 u8
*curbssid
= NULL
;
22093 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
22098 curbssid
= wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
22100 if (memcmp(curbssid
, &e
->addr
, ETHER_ADDR_LEN
) == 0) {
22106 static void wl_cfg80211_work_handler(struct work_struct
* work
)
22108 struct bcm_cfg80211
*cfg
= NULL
;
22109 struct net_info
*iter
, *next
;
22112 BCM_SET_CONTAINER_OF(cfg
, work
, struct bcm_cfg80211
, pm_enable_work
.work
);
22113 WL_DBG(("Enter \n"));
22114 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
22115 4 && __GNUC_MINOR__ >= 6))
22116 _Pragma("GCC diagnostic push")
22117 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
22119 for_each_ndev(cfg
, iter
, next
) {
22120 /* p2p discovery iface ndev could be null */
22122 if (!wl_get_drv_status(cfg
, CONNECTED
, iter
->ndev
) ||
22123 (wl_get_mode_by_netdev(cfg
, iter
->ndev
) != WL_MODE_BSS
&&
22124 wl_get_mode_by_netdev(cfg
, iter
->ndev
) != WL_MODE_IBSS
))
22127 if ((err
= wldev_ioctl_set(iter
->ndev
, WLC_SET_PM
,
22128 &pm
, sizeof(pm
))) != 0) {
22129 if (err
== -ENODEV
)
22130 WL_DBG(("%s:netdev not ready\n",
22131 iter
->ndev
->name
));
22133 WL_ERR(("%s:error (%d)\n",
22134 iter
->ndev
->name
, err
));
22136 wl_cfg80211_update_power_mode(iter
->ndev
);
22140 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
22141 4 && __GNUC_MINOR__ >= 6))
22142 _Pragma("GCC diagnostic pop")
22144 DHD_PM_WAKE_UNLOCK(cfg
->pub
);
22148 wl_get_action_category(void *frame
, u32 frame_len
)
22151 u8
*ptr
= (u8
*)frame
;
22153 return DOT11_ACTION_CAT_ERR_MASK
;
22154 if (frame_len
< DOT11_ACTION_HDR_LEN
)
22155 return DOT11_ACTION_CAT_ERR_MASK
;
22156 category
= ptr
[DOT11_ACTION_CAT_OFF
];
22157 WL_DBG(("Action Category: %d\n", category
));
22162 wl_get_public_action(void *frame
, u32 frame_len
, u8
*ret_action
)
22164 u8
*ptr
= (u8
*)frame
;
22165 if (frame
== NULL
|| ret_action
== NULL
)
22167 if (frame_len
< DOT11_ACTION_HDR_LEN
)
22169 if (DOT11_ACTION_CAT_PUBLIC
!= wl_get_action_category(frame
, frame_len
))
22171 *ret_action
= ptr
[DOT11_ACTION_ACT_OFF
];
22172 WL_DBG(("Public Action : %d\n", *ret_action
));
22178 wl_cfg80211_get_fbt_key(struct net_device
*dev
, uint8
*key
, int total_len
)
22180 struct bcm_cfg80211
* cfg
= wl_get_cfg(dev
);
22181 int bytes_written
= -1;
22183 if (total_len
< FBT_KEYLEN
) {
22184 WL_ERR(("%s: Insufficient buffer \n", __FUNCTION__
));
22188 memcpy(key
, cfg
->fbt_key
, FBT_KEYLEN
);
22189 bytes_written
= FBT_KEYLEN
;
22191 memset(key
, 0, FBT_KEYLEN
);
22192 WL_ERR(("%s: Failed to copy KCK and KEK \n", __FUNCTION__
));
22194 prhex("KCK, KEK", (uchar
*)key
, FBT_KEYLEN
);
22196 return bytes_written
;
22201 wl_cfg80211_delayed_roam(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
22202 const struct ether_addr
*bssid
)
22207 bzero(&e
, sizeof(e
));
22208 e
.event_type
= cpu_to_be32(WLC_E_ROAM
);
22209 memcpy(&e
.addr
, bssid
, ETHER_ADDR_LEN
);
22210 /* trigger the roam event handler */
22211 err
= wl_notify_roaming_status(cfg
, ndev_to_cfgdev(ndev
), &e
, NULL
);
22217 wl_cfg80211_parse_vndr_ies(const u8
*parse
, u32 len
,
22218 struct parsed_vndr_ies
*vndr_ies
)
22221 const vndr_ie_t
*vndrie
;
22222 const bcm_tlv_t
*ie
;
22223 struct parsed_vndr_ie_info
*parsed_info
;
22227 remained_len
= (s32
)len
;
22228 memset(vndr_ies
, 0, sizeof(*vndr_ies
));
22230 WL_DBG(("---> len %d\n", len
));
22231 ie
= (const bcm_tlv_t
*) parse
;
22232 if (!bcm_valid_tlv(ie
, remained_len
))
22235 if (count
>= MAX_VNDR_IE_NUMBER
)
22237 if (ie
->id
== DOT11_MNG_VS_ID
) {
22238 vndrie
= (const vndr_ie_t
*) ie
;
22239 /* len should be bigger than OUI length + one data length at least */
22240 if (vndrie
->len
< (VNDR_IE_MIN_LEN
+ 1)) {
22241 WL_ERR(("%s: invalid vndr ie. length is too small %d\n",
22242 __FUNCTION__
, vndrie
->len
));
22245 /* if wpa or wme ie, do not add ie */
22246 if (!bcmp(vndrie
->oui
, (u8
*)WPA_OUI
, WPA_OUI_LEN
) &&
22247 ((vndrie
->data
[0] == WPA_OUI_TYPE
) ||
22248 (vndrie
->data
[0] == WME_OUI_TYPE
))) {
22249 CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
22253 parsed_info
= &vndr_ies
->ie_info
[count
++];
22255 /* save vndr ie information */
22256 parsed_info
->ie_ptr
= (const char *)vndrie
;
22257 parsed_info
->ie_len
= (vndrie
->len
+ TLV_HDR_LEN
);
22258 memcpy(&parsed_info
->vndrie
, vndrie
, sizeof(vndr_ie_t
));
22259 vndr_ies
->count
= count
;
22261 WL_DBG(("\t ** OUI "MACOUIDBG
", type 0x%02x len:%d\n",
22262 MACOUI2STRDBG(parsed_info
->vndrie
.oui
),
22263 parsed_info
->vndrie
.data
[0], parsed_info
->ie_len
));
22266 ie
= bcm_next_tlv(ie
, &remained_len
);
22272 wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info
*vndr_info
)
22276 while (exclude_vndr_oui_list
[i
]) {
22277 if (!memcmp(vndr_info
->vndrie
.oui
,
22278 exclude_vndr_oui_list
[i
],
22289 wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211
*cfg
,
22290 struct parsed_vndr_ie_info
*vndr_info
)
22292 wl_vndr_oui_entry_t
*oui_entry
= NULL
;
22293 unsigned long flags
;
22295 spin_lock_irqsave(&cfg
->vndr_oui_sync
, flags
);
22296 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22297 #pragma GCC diagnostic push
22298 #pragma GCC diagnostic ignored "-Wcast-qual"
22300 list_for_each_entry(oui_entry
, &cfg
->vndr_oui_list
, list
) {
22301 if (!memcmp(oui_entry
->oui
, vndr_info
->vndrie
.oui
, DOT11_OUI_LEN
)) {
22302 spin_unlock_irqrestore(&cfg
->vndr_oui_sync
, flags
);
22306 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22307 #pragma GCC diagnostic pop
22309 spin_unlock_irqrestore(&cfg
->vndr_oui_sync
, flags
);
22314 wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211
*cfg
,
22315 struct parsed_vndr_ie_info
*vndr_info
)
22317 wl_vndr_oui_entry_t
*oui_entry
= NULL
;
22318 unsigned long flags
;
22320 oui_entry
= (wl_vndr_oui_entry_t
*)MALLOC(cfg
->osh
, sizeof(*oui_entry
));
22321 if (oui_entry
== NULL
) {
22322 WL_ERR(("alloc failed\n"));
22326 memcpy(oui_entry
->oui
, vndr_info
->vndrie
.oui
, DOT11_OUI_LEN
);
22328 INIT_LIST_HEAD(&oui_entry
->list
);
22329 spin_lock_irqsave(&cfg
->vndr_oui_sync
, flags
);
22330 list_add_tail(&oui_entry
->list
, &cfg
->vndr_oui_list
);
22331 spin_unlock_irqrestore(&cfg
->vndr_oui_sync
, flags
);
22337 wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211
*cfg
)
22339 wl_vndr_oui_entry_t
*oui_entry
= NULL
;
22340 unsigned long flags
;
22342 spin_lock_irqsave(&cfg
->vndr_oui_sync
, flags
);
22343 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22344 #pragma GCC diagnostic push
22345 #pragma GCC diagnostic ignored "-Wcast-qual"
22347 while (!list_empty(&cfg
->vndr_oui_list
)) {
22348 oui_entry
= list_entry(cfg
->vndr_oui_list
.next
, wl_vndr_oui_entry_t
, list
);
22350 list_del(&oui_entry
->list
);
22351 MFREE(cfg
->osh
, oui_entry
, sizeof(*oui_entry
));
22354 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22355 #pragma GCC diagnostic pop
22357 spin_unlock_irqrestore(&cfg
->vndr_oui_sync
, flags
);
22361 wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
22362 char *vndr_oui
, u32 vndr_oui_len
)
22365 int vndr_oui_num
= 0;
22367 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
22368 wl_vndr_oui_entry_t
*oui_entry
= NULL
;
22369 struct parsed_vndr_ie_info
*vndr_info
;
22370 struct parsed_vndr_ies vndr_ies
;
22372 char *pos
= vndr_oui
;
22373 u32 remained_buf_len
= vndr_oui_len
;
22374 unsigned long flags
;
22376 if (!conn_info
->resp_ie_len
) {
22380 wl_vndr_ies_clear_vendor_oui_list(cfg
);
22382 if ((wl_cfg80211_parse_vndr_ies((u8
*)conn_info
->resp_ie
,
22383 conn_info
->resp_ie_len
, &vndr_ies
)) == BCME_OK
) {
22384 for (i
= 0; i
< vndr_ies
.count
; i
++) {
22385 vndr_info
= &vndr_ies
.ie_info
[i
];
22386 if (wl_vndr_ies_exclude_vndr_oui(vndr_info
)) {
22390 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg
, vndr_info
)) {
22394 wl_vndr_ies_add_vendor_oui_list(cfg
, vndr_info
);
22400 spin_lock_irqsave(&cfg
->vndr_oui_sync
, flags
);
22401 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22402 #pragma GCC diagnostic push
22403 #pragma GCC diagnostic ignored "-Wcast-qual"
22405 list_for_each_entry(oui_entry
, &cfg
->vndr_oui_list
, list
) {
22406 if (remained_buf_len
< VNDR_OUI_STR_LEN
) {
22407 spin_unlock_irqrestore(&cfg
->vndr_oui_sync
, flags
);
22410 pos
+= snprintf(pos
, VNDR_OUI_STR_LEN
, "%02X-%02X-%02X ",
22411 oui_entry
->oui
[0], oui_entry
->oui
[1], oui_entry
->oui
[2]);
22412 remained_buf_len
-= VNDR_OUI_STR_LEN
;
22414 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
22415 #pragma GCC diagnostic pop
22417 spin_unlock_irqrestore(&cfg
->vndr_oui_sync
, flags
);
22420 return vndr_oui_num
;
22424 wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211
*cfg
)
22426 /* Legacy P2P used to store it in primary dev cache */
22428 struct net_device
*ndev
;
22431 s32 vndrie_flag
[] = {VNDR_IE_BEACON_FLAG
, VNDR_IE_PRBRSP_FLAG
,
22432 VNDR_IE_ASSOCRSP_FLAG
, VNDR_IE_PRBREQ_FLAG
, VNDR_IE_ASSOCREQ_FLAG
};
22434 WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
22435 /* certain vendors uses p2p0 interface in addition to
22436 * the dedicated p2p interface supported by the linux
22439 ndev
= wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_PRIMARY
);
22440 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
22441 if (bssidx
== WL_INVALID
) {
22442 WL_DBG(("No discovery I/F available. Do nothing.\n"));
22446 for (index
= 0; index
< ARRAYSIZE(vndrie_flag
); index
++) {
22447 if ((ret
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, ndev_to_cfgdev(ndev
),
22448 bssidx
, vndrie_flag
[index
], NULL
, 0)) < 0) {
22449 if (ret
!= BCME_NOTFOUND
) {
22450 WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret
));
22455 if (cfg
->p2p_wdev
&& (ndev
->ieee80211_ptr
!= cfg
->p2p_wdev
)) {
22456 /* clear IEs for dedicated p2p interface */
22457 wl_cfg80211_clear_per_bss_ies(cfg
, cfg
->p2p_wdev
);
22462 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211
*cfg
, struct wireless_dev
*wdev
)
22466 struct net_info
*netinfo
;
22467 s32 vndrie_flag
[] = {VNDR_IE_BEACON_FLAG
, VNDR_IE_PRBRSP_FLAG
,
22468 VNDR_IE_ASSOCRSP_FLAG
, VNDR_IE_PRBREQ_FLAG
, VNDR_IE_ASSOCREQ_FLAG
};
22470 netinfo
= wl_get_netinfo_by_wdev(cfg
, wdev
);
22471 if (!netinfo
|| !netinfo
->wdev
) {
22472 WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
22476 WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo
->bssidx
));
22477 /* Clear the IEs set in the firmware so that host is in sync with firmware */
22478 for (index
= 0; index
< ARRAYSIZE(vndrie_flag
); index
++) {
22479 if ((ret
= wl_cfg80211_set_mgmt_vndr_ies(cfg
, wdev_to_cfgdev(netinfo
->wdev
),
22480 netinfo
->bssidx
, vndrie_flag
[index
], NULL
, 0)) < 0)
22481 if (ret
!= BCME_NOTFOUND
) {
22482 WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
22490 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211
*cfg
)
22492 struct net_info
*iter
, *next
;
22494 WL_DBG(("clear management vendor IEs \n"));
22495 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
22496 4 && __GNUC_MINOR__ >= 6))
22497 _Pragma("GCC diagnostic push")
22498 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
22500 for_each_ndev(cfg
, iter
, next
) {
22501 wl_cfg80211_clear_per_bss_ies(cfg
, iter
->wdev
);
22503 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
22504 4 && __GNUC_MINOR__ >= 6))
22505 _Pragma("GCC diagnostic pop")
22510 #define WL_VNDR_IE_MAXLEN 2048
22511 static s8 g_mgmt_ie_buf
[WL_VNDR_IE_MAXLEN
];
22513 wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
22514 s32 bssidx
, s32 pktflag
, const u8
*vndr_ie
, u32 vndr_ie_len
)
22516 struct net_device
*ndev
= NULL
;
22518 u8
*curr_ie_buf
= NULL
;
22519 u8
*mgmt_ie_buf
= NULL
;
22520 u32 mgmt_ie_buf_len
= 0;
22521 u32
*mgmt_ie_len
= 0;
22522 u32 del_add_ie_buf_len
= 0;
22523 u32 total_ie_buf_len
= 0;
22524 u32 parsed_ie_buf_len
= 0;
22525 struct parsed_vndr_ies old_vndr_ies
;
22526 struct parsed_vndr_ies new_vndr_ies
;
22529 s32 remained_buf_len
;
22530 wl_bss_vndr_ies_t
*ies
= NULL
;
22531 struct net_info
*netinfo
;
22532 struct wireless_dev
*wdev
;
22535 WL_ERR(("cfgdev is NULL\n"));
22539 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
22540 wdev
= cfgdev_to_wdev(cfgdev
);
22542 if (bssidx
> WL_MAX_IFS
) {
22543 WL_ERR(("bssidx > supported concurrent Ifaces \n"));
22547 netinfo
= wl_get_netinfo_by_wdev(cfg
, wdev
);
22549 WL_ERR(("net_info ptr is NULL \n"));
22553 /* Clear the global buffer */
22554 memset(g_mgmt_ie_buf
, 0, sizeof(g_mgmt_ie_buf
));
22555 curr_ie_buf
= g_mgmt_ie_buf
;
22556 ies
= &netinfo
->bss
.ies
;
22558 WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d wdev:%p\n",
22559 pktflag
, bssidx
, vndr_ie_len
, wdev
));
22562 case VNDR_IE_PRBRSP_FLAG
:
22563 mgmt_ie_buf
= ies
->probe_res_ie
;
22564 mgmt_ie_len
= &ies
->probe_res_ie_len
;
22565 mgmt_ie_buf_len
= sizeof(ies
->probe_res_ie
);
22567 case VNDR_IE_ASSOCRSP_FLAG
:
22568 mgmt_ie_buf
= ies
->assoc_res_ie
;
22569 mgmt_ie_len
= &ies
->assoc_res_ie_len
;
22570 mgmt_ie_buf_len
= sizeof(ies
->assoc_res_ie
);
22572 case VNDR_IE_BEACON_FLAG
:
22573 mgmt_ie_buf
= ies
->beacon_ie
;
22574 mgmt_ie_len
= &ies
->beacon_ie_len
;
22575 mgmt_ie_buf_len
= sizeof(ies
->beacon_ie
);
22577 case VNDR_IE_PRBREQ_FLAG
:
22578 mgmt_ie_buf
= ies
->probe_req_ie
;
22579 mgmt_ie_len
= &ies
->probe_req_ie_len
;
22580 mgmt_ie_buf_len
= sizeof(ies
->probe_req_ie
);
22582 case VNDR_IE_ASSOCREQ_FLAG
:
22583 mgmt_ie_buf
= ies
->assoc_req_ie
;
22584 mgmt_ie_len
= &ies
->assoc_req_ie_len
;
22585 mgmt_ie_buf_len
= sizeof(ies
->assoc_req_ie
);
22588 mgmt_ie_buf
= NULL
;
22589 mgmt_ie_len
= NULL
;
22590 WL_ERR(("not suitable packet type (%d)\n", pktflag
));
22594 if (vndr_ie_len
> mgmt_ie_buf_len
) {
22595 WL_ERR(("extra IE size too big\n"));
22598 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
22599 if (vndr_ie
&& vndr_ie_len
&& curr_ie_buf
) {
22602 if ((ret
= wl_cfg80211_parse_vndr_ies((const u8
*)vndr_ie
,
22603 vndr_ie_len
, &new_vndr_ies
)) < 0) {
22604 WL_ERR(("parse vndr ie failed \n"));
22608 for (i
= 0; i
< new_vndr_ies
.count
; i
++) {
22609 struct parsed_vndr_ie_info
*vndrie_info
=
22610 &new_vndr_ies
.ie_info
[i
];
22612 if ((parsed_ie_buf_len
+ vndrie_info
->ie_len
) > WL_VNDR_IE_MAXLEN
) {
22613 WL_ERR(("IE size is too big (%d > %d)\n",
22614 parsed_ie_buf_len
, WL_VNDR_IE_MAXLEN
));
22619 memcpy(ptr
+ parsed_ie_buf_len
, vndrie_info
->ie_ptr
,
22620 vndrie_info
->ie_len
);
22621 parsed_ie_buf_len
+= vndrie_info
->ie_len
;
22625 if (mgmt_ie_buf
!= NULL
) {
22626 if (parsed_ie_buf_len
&& (parsed_ie_buf_len
== *mgmt_ie_len
) &&
22627 (memcmp(mgmt_ie_buf
, curr_ie_buf
, parsed_ie_buf_len
) == 0)) {
22628 WL_DBG(("Previous mgmt IE is equals to current IE"));
22632 /* parse old vndr_ie */
22633 if ((ret
= wl_cfg80211_parse_vndr_ies(mgmt_ie_buf
, *mgmt_ie_len
,
22634 &old_vndr_ies
)) < 0) {
22635 WL_ERR(("parse vndr ie failed \n"));
22638 /* make a command to delete old ie */
22639 for (i
= 0; i
< old_vndr_ies
.count
; i
++) {
22640 struct parsed_vndr_ie_info
*vndrie_info
=
22641 &old_vndr_ies
.ie_info
[i
];
22643 WL_DBG(("DELETED ID : %d, Len: %d , OUI:"MACOUIDBG
"\n",
22644 vndrie_info
->vndrie
.id
, vndrie_info
->vndrie
.len
,
22645 MACOUI2STRDBG(vndrie_info
->vndrie
.oui
)));
22647 del_add_ie_buf_len
= wl_cfgp2p_vndr_ie(cfg
, curr_ie_buf
,
22648 pktflag
, vndrie_info
->vndrie
.oui
,
22649 vndrie_info
->vndrie
.id
,
22650 vndrie_info
->ie_ptr
+ VNDR_IE_FIXED_LEN
,
22651 vndrie_info
->ie_len
- VNDR_IE_FIXED_LEN
,
22654 curr_ie_buf
+= del_add_ie_buf_len
;
22655 total_ie_buf_len
+= del_add_ie_buf_len
;
22660 /* Add if there is any extra IE */
22661 if (mgmt_ie_buf
&& parsed_ie_buf_len
) {
22664 remained_buf_len
= mgmt_ie_buf_len
;
22666 /* make a command to add new ie */
22667 for (i
= 0; i
< new_vndr_ies
.count
; i
++) {
22668 struct parsed_vndr_ie_info
*vndrie_info
=
22669 &new_vndr_ies
.ie_info
[i
];
22671 WL_DBG(("ADDED ID : %d, Len: %d(%d), OUI:"MACOUIDBG
"\n",
22672 vndrie_info
->vndrie
.id
, vndrie_info
->vndrie
.len
,
22673 vndrie_info
->ie_len
- 2,
22674 MACOUI2STRDBG(vndrie_info
->vndrie
.oui
)));
22676 del_add_ie_buf_len
= wl_cfgp2p_vndr_ie(cfg
, curr_ie_buf
,
22677 pktflag
, vndrie_info
->vndrie
.oui
,
22678 vndrie_info
->vndrie
.id
,
22679 vndrie_info
->ie_ptr
+ VNDR_IE_FIXED_LEN
,
22680 vndrie_info
->ie_len
- VNDR_IE_FIXED_LEN
,
22683 /* verify remained buf size before copy data */
22684 if (remained_buf_len
>= vndrie_info
->ie_len
) {
22685 remained_buf_len
-= vndrie_info
->ie_len
;
22687 WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
22688 "found vndr ies # = %d(cur %d), remained len %d, "
22689 "cur mgmt_ie_len %d, new ie len = %d\n",
22690 pktflag
, new_vndr_ies
.count
, i
, remained_buf_len
,
22691 *mgmt_ie_len
, vndrie_info
->ie_len
));
22695 /* save the parsed IE in cfg struct */
22696 memcpy(ptr
+ (*mgmt_ie_len
), vndrie_info
->ie_ptr
,
22697 vndrie_info
->ie_len
);
22698 *mgmt_ie_len
+= vndrie_info
->ie_len
;
22699 curr_ie_buf
+= del_add_ie_buf_len
;
22700 total_ie_buf_len
+= del_add_ie_buf_len
;
22704 if (total_ie_buf_len
&& cfg
->ioctl_buf
!= NULL
) {
22705 ret
= wldev_iovar_setbuf_bsscfg(ndev
, "vndr_ie", g_mgmt_ie_buf
,
22706 total_ie_buf_len
, cfg
->ioctl_buf
, WLC_IOCTL_MAXLEN
,
22707 bssidx
, &cfg
->ioctl_buf_sync
);
22709 WL_ERR(("vndr ie set error : %d\n", ret
));
22717 #ifdef WL_CFG80211_ACL
22719 wl_cfg80211_set_mac_acl(struct wiphy
*wiphy
, struct net_device
*cfgdev
,
22720 const struct cfg80211_acl_data
*acl
)
22725 int macmode
= MACLIST_MODE_DISABLED
;
22726 struct maclist
*list
;
22727 struct bcm_cfg80211
*cfg
= wl_get_cfg(cfgdev
);
22729 /* get the MAC filter mode */
22730 if (acl
&& acl
->acl_policy
== NL80211_ACL_POLICY_DENY_UNLESS_LISTED
) {
22731 macmode
= MACLIST_MODE_ALLOW
;
22732 } else if (acl
&& acl
->acl_policy
== NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED
&&
22733 acl
->n_acl_entries
) {
22734 macmode
= MACLIST_MODE_DENY
;
22737 /* if acl == NULL, macmode is still disabled.. */
22738 if (macmode
== MACLIST_MODE_DISABLED
) {
22739 if ((ret
= wl_android_set_ap_mac_list(cfgdev
, macmode
, NULL
)) != 0)
22740 WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__
, ret
));
22745 macnum
= acl
->n_acl_entries
;
22746 if (macnum
< 0 || macnum
> MAX_NUM_MAC_FILT
) {
22747 WL_ERR(("%s : invalid number of MAC address entries %d\n",
22748 __FUNCTION__
, macnum
));
22752 /* allocate memory for the MAC list */
22753 list
= (struct maclist
*)MALLOC(cfg
->osh
, sizeof(int) +
22754 sizeof(struct ether_addr
) * macnum
);
22756 WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__
));
22760 /* prepare the MAC list */
22761 list
->count
= htod32(macnum
);
22762 for (i
= 0; i
< macnum
; i
++) {
22763 memcpy(&list
->ea
[i
], &acl
->mac_addrs
[i
], ETHER_ADDR_LEN
);
22766 if ((ret
= wl_android_set_ap_mac_list(cfgdev
, macmode
, list
)) != 0)
22767 WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__
, ret
));
22769 MFREE(cfg
->osh
, list
, sizeof(int) +
22770 sizeof(struct ether_addr
) * macnum
);
22774 #endif /* WL_CFG80211_ACL */
22775 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22776 int wl_chspec_chandef(chanspec_t chanspec
,
22777 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
22778 struct cfg80211_chan_def
*chandef
,
22779 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22782 struct chan_info
*chaninfo
,
22783 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
22784 struct wiphy
*wiphy
)
22789 struct ieee80211_channel
*chan
;
22794 channel
= CHSPEC_CHANNEL(chanspec
);
22796 switch (CHSPEC_BW(chanspec
)) {
22797 case WL_CHANSPEC_BW_20
:
22798 chan_type
= NL80211_CHAN_HT20
;
22800 case WL_CHANSPEC_BW_40
:
22802 if (CHSPEC_SB_UPPER(chanspec
)) {
22803 channel
+= CH_10MHZ_APART
;
22805 channel
-= CH_10MHZ_APART
;
22808 chan_type
= NL80211_CHAN_HT40PLUS
;
22811 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22812 case WL_CHANSPEC_BW_80
:
22813 case WL_CHANSPEC_BW_8080
:
22815 uint16 sb
= CHSPEC_CTL_SB(chanspec
);
22817 if (sb
== WL_CHANSPEC_CTL_SB_LL
) {
22818 channel
-= (CH_10MHZ_APART
+ CH_20MHZ_APART
);
22819 } else if (sb
== WL_CHANSPEC_CTL_SB_LU
) {
22820 channel
-= CH_10MHZ_APART
;
22821 } else if (sb
== WL_CHANSPEC_CTL_SB_UL
) {
22822 channel
+= CH_10MHZ_APART
;
22824 /* WL_CHANSPEC_CTL_SB_UU */
22825 channel
+= (CH_10MHZ_APART
+ CH_20MHZ_APART
);
22828 if (sb
== WL_CHANSPEC_CTL_SB_LL
|| sb
== WL_CHANSPEC_CTL_SB_LU
)
22829 chan_type
= NL80211_CHAN_HT40MINUS
;
22830 else if (sb
== WL_CHANSPEC_CTL_SB_UL
|| sb
== WL_CHANSPEC_CTL_SB_UU
)
22831 chan_type
= NL80211_CHAN_HT40PLUS
;
22834 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22836 chan_type
= NL80211_CHAN_HT20
;
22841 if (CHSPEC_IS5G(chanspec
))
22842 freq
= ieee80211_channel_to_frequency(channel
, NL80211_BAND_5GHZ
);
22844 freq
= ieee80211_channel_to_frequency(channel
, NL80211_BAND_2GHZ
);
22846 chan
= ieee80211_get_channel(wiphy
, freq
);
22847 WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
22848 channel
, freq
, chan_type
, chan
));
22850 if (unlikely(!chan
)) {
22851 /* fw and cfg80211 channel lists are not in sync */
22852 WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
22857 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22858 cfg80211_chandef_create(chandef
, chan
, chan_type
);
22859 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22862 chaninfo
->freq
= freq
;
22863 chaninfo
->chan_type
= chan_type
;
22864 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22869 wl_cfg80211_ch_switch_notify(struct net_device
*dev
, uint16 chanspec
, struct wiphy
*wiphy
)
22872 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22873 struct cfg80211_chan_def chandef
;
22874 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22877 struct chan_info chaninfo
;
22878 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22881 WL_ERR(("wiphy is null\n"));
22884 #if (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0))
22885 /* Channel switch support is only for AP/GO/ADHOC/MESH */
22886 if (dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_STATION
||
22887 dev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_P2P_CLIENT
) {
22888 WL_ERR(("No channel switch notify support for STA/GC\n"));
22891 #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
22892 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22893 if (wl_chspec_chandef(chanspec
, &chandef
, wiphy
)) {
22894 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22897 if (wl_chspec_chandef(chanspec
, &chaninfo
, wiphy
)) {
22898 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22900 WL_ERR(("chspec_chandef failed\n"));
22903 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22904 freq
= chandef
.chan
? chandef
.chan
->center_freq
: chandef
.center_freq1
;
22905 cfg80211_ch_switch_notify(dev
, &chandef
);
22906 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
22909 freq
= chan_info
.freq
;
22910 cfg80211_ch_switch_notify(dev
, freq
, chan_info
.chan_type
);
22911 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22913 WL_ERR(("Channel switch notification for freq: %d chanspec: 0x%x\n", freq
, chanspec
));
22916 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
22919 wl_ap_channel_ind(struct bcm_cfg80211
*cfg
,
22920 struct net_device
*ndev
,
22921 chanspec_t chanspec
)
22923 u32 channel
= LCHSPEC_CHANNEL(chanspec
);
22925 WL_INFORM_MEM(("(%s) AP channel:%d chspec:0x%x \n",
22926 ndev
->name
, channel
, chanspec
));
22927 if (cfg
->ap_oper_channel
&& (cfg
->ap_oper_channel
!= channel
)) {
22929 * If cached channel is different from the channel indicated
22930 * by the event, notify user space about the channel switch.
22932 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22933 wl_cfg80211_ch_switch_notify(ndev
, chanspec
, bcmcfg_to_wiphy(cfg
));
22934 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
22935 cfg
->ap_oper_channel
= channel
;
22940 wl_ap_start_ind(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
22941 const wl_event_msg_t
*e
, void *data
)
22943 struct net_device
*ndev
= NULL
;
22944 chanspec_t chanspec
;
22946 WL_DBG(("Enter\n"));
22947 if (unlikely(e
->status
)) {
22948 WL_ERR(("status:0x%x \n", e
->status
));
22956 if (likely(cfgdev
)) {
22957 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
22958 chanspec
= *((chanspec_t
*)data
);
22960 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
) {
22961 /* For AP/GO role */
22962 wl_ap_channel_ind(cfg
, ndev
, chanspec
);
22970 wl_csa_complete_ind(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
22971 const wl_event_msg_t
*e
, void *data
)
22975 struct net_device
*ndev
= NULL
;
22977 WL_DBG(("Enter\n"));
22978 if (unlikely(e
->status
)) {
22979 WL_ERR(("status:0x%x \n", e
->status
));
22983 if (likely(cfgdev
)) {
22984 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
22985 error
= wldev_iovar_getint(ndev
, "chanspec", &chanspec
);
22986 if (unlikely(error
)) {
22987 WL_ERR(("Get chanspec error: %d \n", error
));
22991 WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev
->name
, chanspec
));
22992 if (wl_get_mode_by_netdev(cfg
, ndev
) == WL_MODE_AP
) {
22993 /* For AP/GO role */
22994 wl_ap_channel_ind(cfg
, ndev
, chanspec
);
22996 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22997 wl_cfg80211_ch_switch_notify(ndev
, chanspec
, bcmcfg_to_wiphy(cfg
));
22998 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
23006 void wl_cfg80211_clear_security(struct bcm_cfg80211
*cfg
)
23008 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
23011 /* Clear the security settings on the primary Interface */
23012 err
= wldev_iovar_setint(dev
, "wsec", 0);
23013 if (unlikely(err
)) {
23014 WL_ERR(("wsec clear failed \n"));
23016 err
= wldev_iovar_setint(dev
, "auth", 0);
23017 if (unlikely(err
)) {
23018 WL_ERR(("auth clear failed \n"));
23020 err
= wldev_iovar_setint(dev
, "wpa_auth", WPA_AUTH_DISABLED
);
23021 if (unlikely(err
)) {
23022 WL_ERR(("wpa_auth clear failed \n"));
23026 #ifdef WL_CFG80211_P2P_DEV_IF
23027 void wl_cfg80211_del_p2p_wdev(struct net_device
*dev
)
23029 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23030 struct wireless_dev
*wdev
= NULL
;
23032 WL_DBG(("Enter \n"));
23034 WL_ERR(("Invalid Ptr\n"));
23037 wdev
= cfg
->p2p_wdev
;
23041 wl_cfgp2p_del_p2p_disc_if(wdev
, cfg
);
23044 #endif /* WL_CFG80211_P2P_DEV_IF */
23046 #ifdef GTK_OFFLOAD_SUPPORT
23047 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
23049 wl_cfg80211_set_rekey_data(struct wiphy
*wiphy
, struct net_device
*dev
,
23050 struct cfg80211_gtk_rekey_data
*data
)
23052 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
23054 gtk_keyinfo_t keyinfo
;
23056 WL_DBG(("Enter\n"));
23057 if (data
== NULL
|| cfg
->p2p_net
== dev
) {
23058 WL_ERR(("data is NULL or wrong net device\n"));
23062 prhex("kck", (const u8
*) (data
->kck
), RSN_KCK_LENGTH
);
23063 prhex("kek", (const u8
*) (data
->kek
), RSN_KEK_LENGTH
);
23064 prhex("replay_ctr", (const u8
*) (data
->replay_ctr
), RSN_REPLAY_LEN
);
23065 bcopy(data
->kck
, keyinfo
.KCK
, RSN_KCK_LENGTH
);
23066 bcopy(data
->kek
, keyinfo
.KEK
, RSN_KEK_LENGTH
);
23067 bcopy(data
->replay_ctr
, keyinfo
.ReplayCounter
, RSN_REPLAY_LEN
);
23069 if ((err
= wldev_iovar_setbuf(dev
, "gtk_key_info", &keyinfo
, sizeof(keyinfo
),
23070 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
)) < 0) {
23071 WL_ERR(("seting gtk_key_info failed code=%d\n", err
));
23074 WL_DBG(("Exit\n"));
23077 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
23078 #endif /* GTK_OFFLOAD_SUPPORT */
23080 #if defined(WL_SUPPORT_AUTO_CHANNEL)
23082 wl_cfg80211_set_spect(struct net_device
*dev
, int spect
)
23084 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23089 if (!wl_get_drv_status_all(cfg
, CONNECTED
)) {
23090 err
= wldev_ioctl_set(dev
, WLC_DOWN
, &wlc_down
, sizeof(wlc_down
));
23092 WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__
, err
));
23096 err
= wldev_ioctl_set(dev
, WLC_SET_SPECT_MANAGMENT
, &spect
, sizeof(spect
));
23098 WL_ERR(("%s: error setting spect: code: %d\n", __func__
, err
));
23102 err
= wldev_ioctl_set(dev
, WLC_UP
, &wlc_up
, sizeof(wlc_up
));
23104 WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__
, err
));
23112 wl_cfg80211_get_sta_channel(struct bcm_cfg80211
*cfg
)
23116 if (wl_get_drv_status(cfg
, CONNECTED
, bcmcfg_to_prmry_ndev(cfg
))) {
23117 channel
= cfg
->channel
;
23121 #endif /* WL_SUPPORT_AUTO_CHANNEL */
23124 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211
*cfg
)
23127 id
= ++cfg
->last_roc_id
;
23128 #ifdef P2P_LISTEN_OFFLOADING
23129 if (id
== P2PO_COOKIE
) {
23130 id
= ++cfg
->last_roc_id
;
23132 #endif /* P2P_LISTEN_OFFLOADING */
23134 id
= ++cfg
->last_roc_id
;
23138 #if defined(SUPPORT_RANDOM_MAC_SCAN)
23140 wl_cfg80211_set_random_mac(struct net_device
*dev
, bool enable
)
23145 #if defined(DHD_RANDOM_MAC_SCAN)
23147 wl_cfg80211_dhd_driven_random_mac_enable(struct net_device
*dev
, uint8
*rand_mac
, uint8
*rand_mask
)
23149 u8 random_mac_addr
[ETHER_ADDR_LEN
] = {0, };
23150 s32 err
= BCME_ERROR
;
23151 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23154 if ((rand_mac
== NULL
) || (rand_mask
== NULL
)) {
23156 WL_ERR(("Fail to Set random mac, bad argument\n"));
23157 wl_cfg80211_random_mac_disable(dev
);
23161 if (ETHER_ISNULLADDR(rand_mac
)) {
23162 WL_DBG(("Fail to Set random mac, Invalid rand mac\n"));
23163 wl_cfg80211_random_mac_disable(dev
);
23167 if (wl_get_drv_status_all(cfg
, CONNECTED
) || wl_get_drv_status_all(cfg
, CONNECTING
) ||
23168 wl_get_drv_status_all(cfg
, AP_CREATED
) || wl_get_drv_status_all(cfg
, AP_CREATING
)) {
23169 WL_ERR(("Skip to set random mac by current stastus\n"));
23173 /* Generate 6 bytes random address */
23174 get_random_bytes(&random_mac_addr
, sizeof(random_mac_addr
));
23176 /* Overwrite unmasked MAC address */
23177 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++) {
23178 if (rand_mask
[i
]) {
23179 random_mac_addr
[i
] = rand_mac
[i
];
23183 /* Modify last mac address if 0x00 or 0xff */
23184 if (random_mac_addr
[5] == 0x0 || random_mac_addr
[5] == 0xff) {
23185 random_mac_addr
[5] = 0xf0;
23187 err
= wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg
), "cur_etheraddr",
23188 random_mac_addr
, ETHER_ADDR_LEN
, cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
,
23189 0, &cfg
->ioctl_buf_sync
);
23191 if (err
!= BCME_OK
) {
23192 WL_ERR(("Failed to set random generate MAC address\n"));
23194 cfg
->random_mac_running
= TRUE
;
23195 WL_INFORM(("Set random mac " MACDBG
" to " MACDBG
"\n",
23196 MAC2STRDBG((const u8
*)bcmcfg_to_prmry_ndev(cfg
)->dev_addr
),
23197 MAC2STRDBG((const u8
*)&random_mac_addr
)));
23203 wl_cfg80211_dhd_driven_random_mac_disable(struct net_device
*dev
)
23205 s32 err
= BCME_ERROR
;
23206 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23208 if (cfg
->random_mac_running
) {
23209 WL_INFORM(("Restore to original MAC address " MACDBG
"\n",
23210 MAC2STRDBG((const u8
*)bcmcfg_to_prmry_ndev(cfg
)->dev_addr
)));
23212 err
= wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg
), "cur_etheraddr",
23213 bcmcfg_to_prmry_ndev(cfg
)->dev_addr
, ETHER_ADDR_LEN
,
23214 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, 0, &cfg
->ioctl_buf_sync
);
23216 if (err
!= BCME_OK
) {
23217 WL_ERR(("Failed to restore original MAC address\n"));
23219 cfg
->random_mac_running
= FALSE
;
23220 WL_ERR(("Random MAC disable done\n"));
23226 #endif /* DHD_RANDOM_MAC_SCAN */
23229 wl_cfg80211_random_mac_enable(struct net_device
*dev
, uint8
*rand_mac
, uint8
*rand_mask
)
23231 s32 err
= BCME_ERROR
;
23232 #if defined(DHD_RANDOM_MAC_SCAN)
23233 err
= wl_cfg80211_dhd_driven_random_mac_enable(dev
, rand_mac
, rand_mask
);
23234 #else /* Random mac by scan mac feature */
23235 err
= wl_cfg80211_scan_mac_enable(dev
, rand_mac
, rand_mask
);
23236 #endif /* DHD_RANDOM_MAC_SCAN */
23242 wl_cfg80211_random_mac_disable(struct net_device
*dev
)
23244 s32 err
= BCME_ERROR
;
23245 #if defined(DHD_RANDOM_MAC_SCAN)
23246 err
= wl_cfg80211_dhd_driven_random_mac_disable(dev
);
23247 #else /* Random mac by scan mac featur */
23248 err
= wl_cfg80211_scan_mac_disable(dev
);
23249 #endif /* DHD_RANDOM_MAC_SCAN */
23255 * This is new interface for mac randomization. It takes randmac and randmask
23256 * as arg and it uses scanmac iovar to offload the mac randomization to firmware.
23258 int wl_cfg80211_scan_mac_enable(struct net_device
*dev
, uint8
*rand_mac
, uint8
*rand_mask
)
23260 int byte_index
= 0;
23261 s32 err
= BCME_ERROR
;
23262 uint8 buffer
[WLC_IOCTL_SMLEN
] = {0, };
23263 wl_scanmac_t
*sm
= NULL
;
23265 wl_scanmac_enable_t
*sm_enable
= NULL
;
23266 wl_scanmac_config_t
*sm_config
= NULL
;
23267 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23269 if ((rand_mac
== NULL
) || (rand_mask
== NULL
)) {
23271 WL_ERR(("fail to Set random mac, bad argument\n"));
23272 /* Disable the current scanmac config */
23273 wl_cfg80211_scan_mac_disable(dev
);
23277 if (ETHER_ISNULLADDR(rand_mac
)) {
23278 WL_DBG(("fail to Set random mac, Invalid rand mac\n"));
23279 /* Disable the current scanmac config */
23280 wl_cfg80211_scan_mac_disable(dev
);
23284 if (wl_get_drv_status_all(cfg
, CONNECTED
) || wl_get_drv_status_all(cfg
, CONNECTING
) ||
23285 wl_get_drv_status_all(cfg
, AP_CREATED
) || wl_get_drv_status_all(cfg
, AP_CREATING
)) {
23286 WL_ERR(("fail to Set random mac, current state is wrong\n"));
23287 return BCME_UNSUPPORTED
;
23290 /* Enable scan mac */
23291 sm
= (wl_scanmac_t
*)buffer
;
23292 sm_enable
= (wl_scanmac_enable_t
*)sm
->data
;
23293 sm
->len
= sizeof(*sm_enable
);
23294 sm_enable
->enable
= 1;
23295 len
= OFFSETOF(wl_scanmac_t
, data
) + sm
->len
;
23296 sm
->subcmd_id
= WL_SCANMAC_SUBCMD_ENABLE
;
23298 err
= wldev_iovar_setbuf_bsscfg(dev
, "scanmac",
23299 sm
, len
, cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, 0, &cfg
->ioctl_buf_sync
);
23301 if (err
== BCME_OK
) {
23302 /* Configure scanmac */
23303 memset(buffer
, 0x0, sizeof(buffer
));
23304 sm_config
= (wl_scanmac_config_t
*)sm
->data
;
23305 sm
->len
= sizeof(*sm_config
);
23306 sm
->subcmd_id
= WL_SCANMAC_SUBCMD_CONFIG
;
23307 sm_config
->scan_bitmap
= WL_SCANMAC_SCAN_UNASSOC
;
23309 /* Set randomize mac address recv from upper layer */
23310 memcpy(&sm_config
->mac
.octet
, rand_mac
, ETH_ALEN
);
23312 /* Set randomize mask recv from upper layer */
23314 /* There is a difference in how to interpret rand_mask between
23315 * upperlayer and firmware. If the byte is set as FF then for
23316 * upper layer it means keep that byte and do not randomize whereas
23317 * for firmware it means randomize those bytes and vice versa. Hence
23318 * conversion is needed before setting the iovar
23320 memset(&sm_config
->random_mask
.octet
, 0x0, ETH_ALEN
);
23321 /* Only byte randomization is supported currently. If mask recv is 0x0F
23322 * for a particular byte then it will be treated as no randomization
23325 while (byte_index
< ETH_ALEN
) {
23326 if (rand_mask
[byte_index
] == 0xFF) {
23327 sm_config
->random_mask
.octet
[byte_index
] = 0x00;
23328 } else if (rand_mask
[byte_index
] == 0x00) {
23329 sm_config
->random_mask
.octet
[byte_index
] = 0xFF;
23334 WL_DBG(("recv random mac addr " MACDBG
"recv rand mask" MACDBG
"\n",
23335 MAC2STRDBG((const u8
*)&sm_config
->mac
.octet
),
23336 MAC2STRDBG((const u8
*)&sm_config
->random_mask
)));
23338 len
= OFFSETOF(wl_scanmac_t
, data
) + sm
->len
;
23339 err
= wldev_iovar_setbuf_bsscfg(dev
, "scanmac",
23340 sm
, len
, cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, 0, &cfg
->ioctl_buf_sync
);
23342 if (err
!= BCME_OK
) {
23343 WL_ERR(("failed scanmac configuration\n"));
23345 /* Disable scan mac for clean-up */
23346 wl_cfg80211_scan_mac_disable(dev
);
23349 WL_DBG(("scanmac enable done"));
23351 WL_ERR(("failed to enable scanmac, err=%d\n", err
));
23357 int wl_cfg80211_scan_mac_disable(struct net_device
*dev
)
23359 s32 err
= BCME_ERROR
;
23360 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23361 uint8 buffer
[WLC_IOCTL_SMLEN
] = {0, };
23362 wl_scanmac_t
*sm
= NULL
;
23364 wl_scanmac_enable_t
*sm_enable
= NULL
;
23366 sm
= (wl_scanmac_t
*)buffer
;
23367 sm_enable
= (wl_scanmac_enable_t
*)sm
->data
;
23368 sm
->len
= sizeof(*sm_enable
);
23369 /* Disable scanmac */
23370 sm_enable
->enable
= 0;
23371 len
= OFFSETOF(wl_scanmac_t
, data
) + sm
->len
;
23373 sm
->subcmd_id
= WL_SCANMAC_SUBCMD_ENABLE
;
23375 err
= wldev_iovar_setbuf_bsscfg(dev
, "scanmac",
23376 sm
, len
, cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, 0, &cfg
->ioctl_buf_sync
);
23378 if (err
!= BCME_OK
) {
23379 WL_ERR(("failed to disable scanmac, err=%d\n", err
));
23381 WL_DBG(("random MAC disable done\n"));
23385 #endif /* SUPPORT_RANDOM_MAC_SCAN */
23389 wl_cfg80211_tdls_config(struct bcm_cfg80211
*cfg
, enum wl_tdls_config state
, bool auto_mode
)
23391 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
23393 struct net_info
*iter
, *next
;
23394 int update_reqd
= 0;
23397 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23400 * TDLS need to be enabled only if we have a single STA/GC
23404 WL_DBG(("Enter state:%d\n", state
));
23405 if (!cfg
->tdls_supported
) {
23406 /* FW doesn't support tdls. Do nothing */
23410 /* Protect tdls config session */
23411 mutex_lock(&cfg
->tdls_sync
);
23413 if (state
== TDLS_STATE_TEARDOWN
) {
23414 /* Host initiated TDLS tear down */
23415 err
= dhd_tdls_enable(ndev
, false, auto_mode
, NULL
);
23417 } else if ((state
== TDLS_STATE_AP_CREATE
) ||
23418 (state
== TDLS_STATE_NDI_CREATE
)) {
23419 /* We don't support tdls while AP/GO/NAN is operational */
23420 update_reqd
= true;
23422 } else if ((state
== TDLS_STATE_CONNECT
) || (state
== TDLS_STATE_IF_CREATE
)) {
23423 if (wl_get_drv_status_all(cfg
,
23424 CONNECTED
) >= TDLS_MAX_IFACE_FOR_ENABLE
) {
23425 /* For STA/GC connect command request, disable
23426 * tdls if we have any concurrent interfaces
23429 WL_DBG(("Interface limit restriction. disable tdls.\n"));
23430 update_reqd
= true;
23433 } else if ((state
== TDLS_STATE_DISCONNECT
) ||
23434 (state
== TDLS_STATE_AP_DELETE
) ||
23435 (state
== TDLS_STATE_SETUP
) ||
23436 (state
== TDLS_STATE_IF_DELETE
)) {
23437 /* Enable back the tdls connection only if we have less than
23438 * or equal to a single STA/GC connection.
23440 if (wl_get_drv_status_all(cfg
,
23442 /* If there are no interfaces connected, enable tdls */
23443 update_reqd
= true;
23445 } else if (wl_get_drv_status_all(cfg
,
23446 CONNECTED
) == TDLS_MAX_IFACE_FOR_ENABLE
) {
23447 /* We have one interface in CONNECTED state.
23448 * Verify whether its a STA interface before
23449 * we enable back tdls.
23451 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23452 #pragma GCC diagnostic push
23453 #pragma GCC diagnostic ignored "-Wcast-qual"
23455 for_each_ndev(cfg
, iter
, next
) {
23456 if ((iter
->ndev
) &&
23457 (wl_get_drv_status(cfg
, CONNECTED
, ndev
)) &&
23458 (ndev
->ieee80211_ptr
->iftype
!= NL80211_IFTYPE_STATION
)) {
23459 WL_DBG(("Non STA iface operational. cfg_iftype:%d "
23460 "Can't enable tdls.\n",
23461 ndev
->ieee80211_ptr
->iftype
));
23466 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23467 #pragma GCC diagnostic pop
23469 /* No AP/GO found. Enable back tdls */
23470 update_reqd
= true;
23473 WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
23478 WL_ERR(("Unknown tdls state:%d \n", state
));
23483 if (update_reqd
== true) {
23484 if (dhdp
->tdls_enable
== enable
) {
23485 WL_DBG(("No change in tdls state. Do nothing."
23486 " tdls_enable:%d\n", enable
));
23489 err
= wldev_iovar_setint(ndev
, "tdls_enable", enable
);
23490 if (unlikely(err
)) {
23491 WL_ERR(("tdls_enable setting failed. err:%d\n", err
));
23494 WL_INFORM_MEM(("tdls_enable %d state:%d\n", enable
, state
));
23495 /* Update the dhd state variable to be in sync */
23496 dhdp
->tdls_enable
= enable
;
23497 if (state
== TDLS_STATE_SETUP
) {
23498 /* For host initiated setup, apply TDLS params
23499 * Don't propagate errors up for param config
23502 dhd_tdls_enable(ndev
, true, auto_mode
, NULL
);
23507 WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
23508 "current_status:%d \n",
23509 state
, update_reqd
, dhdp
->tdls_enable
));
23514 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
23516 mutex_unlock(&cfg
->tdls_sync
);
23519 #endif /* WLTDLS */
23521 struct net_device
* wl_get_ap_netdev(struct bcm_cfg80211
*cfg
, char *ifname
)
23523 struct net_info
*iter
, *next
;
23524 struct net_device
*ndev
= NULL
;
23526 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23527 #pragma GCC diagnostic push
23528 #pragma GCC diagnostic ignored "-Wcast-qual"
23530 for_each_ndev(cfg
, iter
, next
) {
23532 if (strncmp(iter
->ndev
->name
, ifname
, IFNAMSIZ
) == 0) {
23533 if (iter
->ndev
->ieee80211_ptr
->iftype
== NL80211_IFTYPE_AP
) {
23540 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23541 #pragma GCC diagnostic pop
23548 wl_get_netdev_by_name(struct bcm_cfg80211
*cfg
, char *ifname
)
23550 struct net_info
*iter
, *next
;
23551 struct net_device
*ndev
= NULL
;
23553 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23554 #pragma GCC diagnostic push
23555 #pragma GCC diagnostic ignored "-Wcast-qual"
23557 for_each_ndev(cfg
, iter
, next
) {
23559 if (strncmp(iter
->ndev
->name
, ifname
, IFNAMSIZ
) == 0) {
23565 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23566 #pragma GCC diagnostic pop
23572 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
23573 #define WLC_RATE_FLAG 0x80
23574 #define RATE_MASK 0x7f
23576 int wl_set_ap_beacon_rate(struct net_device
*dev
, int val
, char *ifname
)
23578 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23580 wl_rateset_args_t rs
;
23581 int error
= BCME_ERROR
, i
;
23582 struct net_device
*ndev
= NULL
;
23584 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23586 if (dhdp
&& !(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23587 WL_ERR(("Not Hostapd mode\n"));
23591 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23593 if (ndev
== NULL
) {
23594 WL_ERR(("No softAP interface named %s\n", ifname
));
23598 bzero(&rs
, sizeof(wl_rateset_args_t
));
23599 error
= wldev_iovar_getbuf(ndev
, "rateset", NULL
, 0,
23600 &rs
, sizeof(wl_rateset_args_t
), NULL
);
23602 WL_ERR(("get rateset failed = %d\n", error
));
23606 if (rs
.count
< 1) {
23607 WL_ERR(("Failed to get rate count\n"));
23611 /* Host delivers target rate in the unit of 500kbps */
23612 /* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic rate */
23613 for (i
= 0; i
< rs
.count
&& i
< WL_NUMRATES
; i
++)
23614 if (rs
.rates
[i
] & WLC_RATE_FLAG
)
23615 if ((rs
.rates
[i
] & RATE_MASK
) == val
)
23618 /* Valid rate has been delivered as an argument */
23619 if (i
< rs
.count
&& i
< WL_NUMRATES
) {
23620 error
= wldev_iovar_setint(ndev
, "force_bcn_rspec", val
);
23622 WL_ERR(("set beacon rate failed = %d\n", error
));
23626 WL_ERR(("Rate is invalid"));
23627 return BCME_BADARG
;
23634 wl_get_ap_basic_rate(struct net_device
*dev
, char* command
, char *ifname
, int total_len
)
23636 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23638 wl_rateset_args_t rs
;
23639 int error
= BCME_ERROR
;
23640 int i
, bytes_written
= 0;
23641 struct net_device
*ndev
= NULL
;
23643 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23645 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23646 WL_ERR(("Not Hostapd mode\n"));
23650 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23652 if (ndev
== NULL
) {
23653 WL_ERR(("No softAP interface named %s\n", ifname
));
23657 bzero(&rs
, sizeof(wl_rateset_args_t
));
23658 error
= wldev_iovar_getbuf(ndev
, "rateset", NULL
, 0,
23659 &rs
, sizeof(wl_rateset_args_t
), NULL
);
23661 WL_ERR(("get rateset failed = %d\n", error
));
23665 if (rs
.count
< 1) {
23666 WL_ERR(("Failed to get rate count\n"));
23670 /* Delivers basic rate in the unit of 500kbps to host */
23671 for (i
= 0; i
< rs
.count
&& i
< WL_NUMRATES
; i
++)
23672 if (rs
.rates
[i
] & WLC_RATE_FLAG
)
23673 bytes_written
+= snprintf(command
+ bytes_written
, total_len
,
23674 "%d ", rs
.rates
[i
] & RATE_MASK
);
23676 /* Remove last space in the command buffer */
23677 if (bytes_written
&& (bytes_written
< total_len
)) {
23678 command
[bytes_written
- 1] = '\0';
23682 return bytes_written
;
23685 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
23687 #ifdef SUPPORT_AP_RADIO_PWRSAVE
23688 #define MSEC_PER_MIN (60000L)
23691 _wl_update_ap_rps_params(struct net_device
*dev
)
23693 struct bcm_cfg80211
*cfg
= NULL
;
23694 rpsnoa_iovar_params_t iovar
;
23695 u8 smbuf
[WLC_IOCTL_SMLEN
];
23698 return BCME_BADARG
;
23700 cfg
= wl_get_cfg(dev
);
23702 memset(&iovar
, 0, sizeof(iovar
));
23703 memset(smbuf
, 0, sizeof(smbuf
));
23705 iovar
.hdr
.ver
= RADIO_PWRSAVE_VERSION
;
23706 iovar
.hdr
.subcmd
= WL_RPSNOA_CMD_PARAMS
;
23707 iovar
.hdr
.len
= sizeof(iovar
);
23708 iovar
.param
->band
= WLC_BAND_ALL
;
23709 iovar
.param
->level
= cfg
->ap_rps_info
.level
;
23710 iovar
.param
->stas_assoc_check
= cfg
->ap_rps_info
.sta_assoc_check
;
23711 iovar
.param
->pps
= cfg
->ap_rps_info
.pps
;
23712 iovar
.param
->quiet_time
= cfg
->ap_rps_info
.quiet_time
;
23714 if (wldev_iovar_setbuf(dev
, "rpsnoa", &iovar
, sizeof(iovar
),
23715 smbuf
, sizeof(smbuf
), NULL
)) {
23716 WL_ERR(("Failed to set rpsnoa params"));
23724 wl_get_ap_rps(struct net_device
*dev
, char* command
, char *ifname
, int total_len
)
23726 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23728 int error
= BCME_ERROR
;
23729 int bytes_written
= 0;
23730 struct net_device
*ndev
= NULL
;
23731 rpsnoa_iovar_status_t iovar
;
23732 u8 smbuf
[WLC_IOCTL_SMLEN
];
23737 u32 time_since_enable
;
23739 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23742 error
= BCME_NOTUP
;
23746 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23747 WL_ERR(("Not Hostapd mode\n"));
23748 error
= BCME_NOTAP
;
23752 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23754 if (ndev
== NULL
) {
23755 WL_ERR(("No softAP interface named %s\n", ifname
));
23756 error
= BCME_NOTAP
;
23760 memset(&iovar
, 0, sizeof(iovar
));
23761 memset(smbuf
, 0, sizeof(smbuf
));
23763 iovar
.hdr
.ver
= RADIO_PWRSAVE_VERSION
;
23764 iovar
.hdr
.subcmd
= WL_RPSNOA_CMD_STATUS
;
23765 iovar
.hdr
.len
= sizeof(iovar
);
23766 iovar
.stats
->band
= WLC_BAND_ALL
;
23768 error
= wldev_iovar_getbuf(ndev
, "rpsnoa", &iovar
, sizeof(iovar
),
23769 smbuf
, sizeof(smbuf
), NULL
);
23771 WL_ERR(("get ap radio pwrsave failed = %d\n", error
));
23775 /* RSDB event doesn't seem to be handled correctly.
23776 * So check chanspec of AP directly from the firmware
23778 error
= wldev_iovar_getint(ndev
, "chanspec", (s32
*)&chanspec
);
23780 WL_ERR(("get chanspec from AP failed = %d\n", error
));
23784 chanspec
= wl_chspec_driver_to_host(chanspec
);
23785 if (CHSPEC_IS2G(chanspec
))
23787 else if (CHSPEC_IS5G(chanspec
))
23790 error
= BCME_BADCHAN
;
23794 state
= ((rpsnoa_iovar_status_t
*)smbuf
)->stats
[idx
].state
;
23795 sleep
= ((rpsnoa_iovar_status_t
*)smbuf
)->stats
[idx
].sleep_dur
;
23796 time_since_enable
= ((rpsnoa_iovar_status_t
*)smbuf
)->stats
[idx
].sleep_avail_dur
;
23798 /* Conver ms to minute, round down only */
23799 sleep
= DIV_U64_BY_U32(sleep
, MSEC_PER_MIN
);
23800 time_since_enable
= DIV_U64_BY_U32(time_since_enable
, MSEC_PER_MIN
);
23802 bytes_written
+= snprintf(command
+ bytes_written
, total_len
,
23803 "state=%d sleep=%d time_since_enable=%d", state
, sleep
, time_since_enable
);
23804 error
= bytes_written
;
23811 wl_set_ap_rps(struct net_device
*dev
, bool enable
, char *ifname
)
23813 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23815 struct net_device
*ndev
= NULL
;
23816 rpsnoa_iovar_t iovar
;
23817 u8 smbuf
[WLC_IOCTL_SMLEN
];
23820 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23827 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23828 WL_ERR(("Not Hostapd mode\n"));
23833 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23835 if (ndev
== NULL
) {
23836 WL_ERR(("No softAP interface named %s\n", ifname
));
23841 if (cfg
->ap_rps_info
.enable
!= enable
) {
23842 cfg
->ap_rps_info
.enable
= enable
;
23844 ret
= _wl_update_ap_rps_params(ndev
);
23846 WL_ERR(("Filed to update rpsnoa params\n"));
23850 memset(&iovar
, 0, sizeof(iovar
));
23851 memset(smbuf
, 0, sizeof(smbuf
));
23853 iovar
.hdr
.ver
= RADIO_PWRSAVE_VERSION
;
23854 iovar
.hdr
.subcmd
= WL_RPSNOA_CMD_ENABLE
;
23855 iovar
.hdr
.len
= sizeof(iovar
);
23856 iovar
.data
->band
= WLC_BAND_ALL
;
23857 iovar
.data
->value
= (int16
)enable
;
23859 ret
= wldev_iovar_setbuf(ndev
, "rpsnoa", &iovar
, sizeof(iovar
),
23860 smbuf
, sizeof(smbuf
), NULL
);
23862 WL_ERR(("Failed to enable AP radio power save"));
23865 cfg
->ap_rps_info
.enable
= enable
;
23872 wl_update_ap_rps_params(struct net_device
*dev
, ap_rps_info_t
* rps
, char *ifname
)
23874 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23876 struct net_device
*ndev
= NULL
;
23878 dhdp
= (dhd_pub_t
*)(cfg
->pub
);
23883 if (!(dhdp
->op_mode
& DHD_FLAG_HOSTAP_MODE
)) {
23884 WL_ERR(("Not Hostapd mode\n"));
23888 ndev
= wl_get_ap_netdev(cfg
, ifname
);
23890 if (ndev
== NULL
) {
23891 WL_ERR(("No softAP interface named %s\n", ifname
));
23896 return BCME_BADARG
;
23898 if (rps
->pps
< RADIO_PWRSAVE_PPS_MIN
)
23899 return BCME_BADARG
;
23901 if (rps
->level
< RADIO_PWRSAVE_LEVEL_MIN
||
23902 rps
->level
> RADIO_PWRSAVE_LEVEL_MAX
)
23903 return BCME_BADARG
;
23905 if (rps
->quiet_time
< RADIO_PWRSAVE_QUIETTIME_MIN
)
23906 return BCME_BADARG
;
23908 if (rps
->sta_assoc_check
> RADIO_PWRSAVE_ASSOCCHECK_MAX
||
23909 rps
->sta_assoc_check
< RADIO_PWRSAVE_ASSOCCHECK_MIN
)
23910 return BCME_BADARG
;
23912 cfg
->ap_rps_info
.pps
= rps
->pps
;
23913 cfg
->ap_rps_info
.level
= rps
->level
;
23914 cfg
->ap_rps_info
.quiet_time
= rps
->quiet_time
;
23915 cfg
->ap_rps_info
.sta_assoc_check
= rps
->sta_assoc_check
;
23917 if (cfg
->ap_rps_info
.enable
) {
23918 if (_wl_update_ap_rps_params(ndev
)) {
23919 WL_ERR(("Failed to update rpsnoa params"));
23928 wl_cfg80211_init_ap_rps(struct bcm_cfg80211
*cfg
)
23930 cfg
->ap_rps_info
.enable
= FALSE
;
23931 cfg
->ap_rps_info
.sta_assoc_check
= RADIO_PWRSAVE_STAS_ASSOC_CHECK
;
23932 cfg
->ap_rps_info
.pps
= RADIO_PWRSAVE_PPS
;
23933 cfg
->ap_rps_info
.quiet_time
= RADIO_PWRSAVE_QUIET_TIME
;
23934 cfg
->ap_rps_info
.level
= RADIO_PWRSAVE_LEVEL
;
23936 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
23939 wl_cfg80211_iface_count(struct net_device
*dev
)
23941 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
23942 struct net_info
*iter
, *next
;
23943 int iface_count
= 0;
23945 /* Return the count of network interfaces (skip netless p2p discovery
23948 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23949 #pragma GCC diagnostic push
23950 #pragma GCC diagnostic ignored "-Wcast-qual"
23952 for_each_ndev(cfg
, iter
, next
) {
23957 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
23958 #pragma GCC diagnostic pop
23960 return iface_count
;
23963 #ifdef DHD_ABORT_SCAN_CREATE_INTERFACE
23965 wl_abort_scan_and_check(struct bcm_cfg80211
*cfg
)
23967 int wait_cnt
= MAX_SCAN_ABORT_WAIT_CNT
;
23970 wl_cfg80211_scan_abort(cfg
);
23971 while (wl_get_drv_status_all(cfg
, SCANNING
) && wait_cnt
) {
23972 WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt
));
23974 OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME
);
23977 if (!wait_cnt
&& wl_get_drv_status_all(cfg
, SCANNING
)) {
23978 WL_ERR(("Failed to abort scan\n"));
23984 #endif /* DHD_ABORT_SCAN_CREATE_INTERFACE */
23986 #ifdef DHD_USE_CHECK_DONGLE_IDLE
23987 #define CHECK_DONGLE_IDLE_TIME 50
23988 #define CHECK_DONGLE_IDLE_CNT 100
23991 wl_check_dongle_idle(struct wiphy
*wiphy
)
23994 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
23995 struct net_device
*primary_ndev
;
23997 struct channel_info ci
;
24003 /* Use primary I/F for sending cmds down to firmware */
24004 primary_ndev
= bcmcfg_to_prmry_ndev(cfg
);
24006 while (retry
++ < CHECK_DONGLE_IDLE_CNT
) {
24007 memset(&ci
, 0, sizeof(ci
));
24008 error
= wldev_ioctl_get(primary_ndev
, WLC_GET_CHANNEL
, &ci
, sizeof(ci
));
24009 if (error
!= BCME_OK
|| ci
.scan_channel
!= 0) {
24010 if (error
== -ENODEV
) {
24011 WL_ERR(("Firmware is not ready, return TRUE\n"));
24014 WL_DBG(("Firmware is busy(err:%d scan channel:%d). wait %dms\n",
24015 error
, ci
.scan_channel
, CHECK_DONGLE_IDLE_TIME
));
24019 wl_delay(CHECK_DONGLE_IDLE_TIME
);
24021 if (retry
>= CHECK_DONGLE_IDLE_CNT
) {
24022 WL_ERR(("DONGLE is BUSY too long\n"));
24025 WL_DBG(("DONGLE is idle\n"));
24028 #undef CHECK_DONGLE_IDLE_TIME
24029 #undef CHECK_DONGLE_IDLE_CNT
24030 #endif /* DHD_USE_CHECK_DONGLE_IDLE */
24033 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
24034 s32
wl_cfg80211_custom_scan_time(struct net_device
*dev
,
24035 enum wl_custom_scan_time_type type
, int time
)
24037 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24044 case WL_CUSTOM_SCAN_CHANNEL_TIME
:
24045 WL_ERR(("Scan Channel Time %d\n", time
));
24046 cfg
->custom_scan_channel_time
= time
;
24048 case WL_CUSTOM_SCAN_UNASSOC_TIME
:
24049 WL_ERR(("Scan Unassoc Time %d\n", time
));
24050 cfg
->custom_scan_unassoc_time
= time
;
24052 case WL_CUSTOM_SCAN_PASSIVE_TIME
:
24053 WL_ERR(("Scan Passive Time %d\n", time
));
24054 cfg
->custom_scan_passive_time
= time
;
24056 case WL_CUSTOM_SCAN_HOME_TIME
:
24057 WL_ERR(("Scan Home Time %d\n", time
));
24058 cfg
->custom_scan_home_time
= time
;
24060 case WL_CUSTOM_SCAN_HOME_AWAY_TIME
:
24061 WL_ERR(("Scan Home Away Time %d\n", time
));
24062 cfg
->custom_scan_home_away_time
= time
;
24069 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
24070 #endif /* WES_SUPPORT */
24072 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211
*cfg
, struct ether_addr
*ea
)
24074 wl_wbtext_bssid_t
*bssid
= NULL
;
24075 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
24076 #pragma GCC diagnostic push
24077 #pragma GCC diagnostic ignored "-Wcast-qual"
24080 /* check duplicate */
24081 list_for_each_entry(bssid
, &cfg
->wbtext_bssid_list
, list
) {
24082 if (!memcmp(bssid
->ea
.octet
, ea
, ETHER_ADDR_LEN
)) {
24090 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211
*cfg
, struct ether_addr
*ea
)
24092 wl_wbtext_bssid_t
*bssid
= NULL
;
24093 char eabuf
[ETHER_ADDR_STR_LEN
];
24095 bssid
= (wl_wbtext_bssid_t
*)MALLOC(cfg
->osh
, sizeof(wl_wbtext_bssid_t
));
24096 if (bssid
== NULL
) {
24097 WL_ERR(("alloc failed\n"));
24101 memcpy(bssid
->ea
.octet
, ea
, ETHER_ADDR_LEN
);
24103 INIT_LIST_HEAD(&bssid
->list
);
24104 list_add_tail(&bssid
->list
, &cfg
->wbtext_bssid_list
);
24106 WL_DBG(("add wbtext bssid : %s\n", bcm_ether_ntoa(ea
, eabuf
)));
24111 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211
*cfg
)
24113 wl_wbtext_bssid_t
*bssid
= NULL
;
24114 char eabuf
[ETHER_ADDR_STR_LEN
];
24116 while (!list_empty(&cfg
->wbtext_bssid_list
)) {
24117 bssid
= list_entry(cfg
->wbtext_bssid_list
.next
, wl_wbtext_bssid_t
, list
);
24119 WL_DBG(("clear wbtext bssid : %s\n", bcm_ether_ntoa(&bssid
->ea
, eabuf
)));
24120 list_del(&bssid
->list
);
24121 MFREE(cfg
->osh
, bssid
, sizeof(wl_wbtext_bssid_t
));
24126 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
24128 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
24129 bcm_tlv_t
* cap_ie
= NULL
;
24130 bool req_sent
= FALSE
;
24131 struct wl_profile
*profile
;
24133 WL_DBG(("Enter\n"));
24135 profile
= wl_get_profile_by_netdev(cfg
, dev
);
24137 WL_ERR(("no profile exists\n"));
24141 if (wl_cfg80211_wbtext_check_bssid_list(cfg
,
24142 (struct ether_addr
*)&profile
->bssid
) == FALSE
) {
24143 WL_DBG(("already updated\n"));
24147 /* first, check NBR bit in RRM IE */
24148 if ((cap_ie
= bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
24149 DOT11_MNG_RRM_CAP_ID
)) != NULL
) {
24150 if (isset(cap_ie
->data
, DOT11_RRM_CAP_NEIGHBOR_REPORT
)) {
24151 req_sent
= wl_cfg80211_wbtext_send_nbr_req(cfg
, dev
, profile
);
24155 /* if RRM nbr was not supported, check BTM bit in extend cap. IE */
24157 if ((cap_ie
= bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
24158 DOT11_MNG_EXT_CAP_ID
)) != NULL
) {
24159 if (cap_ie
->len
>= DOT11_EXTCAP_LEN_BSSTRANS
&&
24160 isset(cap_ie
->data
, DOT11_EXT_CAP_BSSTRANS_MGMT
)) {
24161 wl_cfg80211_wbtext_send_btm_query(cfg
, dev
, profile
);
24167 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
24168 struct wl_profile
*profile
)
24171 char *smbuf
= NULL
;
24172 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
24173 bcm_tlv_t
* rrm_cap_ie
= NULL
;
24174 wlc_ssid_t
*ssid
= NULL
;
24177 WL_DBG(("Enter\n"));
24179 /* check RRM nbr bit in extend cap. IE of assoc response */
24180 if ((rrm_cap_ie
= bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
24181 DOT11_MNG_RRM_CAP_ID
)) != NULL
) {
24182 if (!isset(rrm_cap_ie
->data
, DOT11_RRM_CAP_NEIGHBOR_REPORT
)) {
24183 WL_DBG(("AP doesn't support neighbor report\n"));
24188 smbuf
= (char *)MALLOCZ(cfg
->osh
, WLC_IOCTL_MAXLEN
);
24189 if (smbuf
== NULL
) {
24190 WL_ERR(("failed to allocated memory\n"));
24194 ssid
= (wlc_ssid_t
*)MALLOCZ(cfg
->osh
, sizeof(wlc_ssid_t
));
24195 if (ssid
== NULL
) {
24196 WL_ERR(("failed to allocated memory\n"));
24200 ssid
->SSID_len
= MIN(profile
->ssid
.SSID_len
, DOT11_MAX_SSID_LEN
);
24201 memcpy(ssid
->SSID
, profile
->ssid
.SSID
, ssid
->SSID_len
);
24203 error
= wldev_iovar_setbuf(dev
, "rrm_nbr_req", ssid
,
24204 sizeof(wlc_ssid_t
), smbuf
, WLC_IOCTL_MAXLEN
, NULL
);
24205 if (error
== BCME_OK
) {
24206 ret
= wl_cfg80211_wbtext_add_bssid_list(cfg
,
24207 (struct ether_addr
*)&profile
->bssid
);
24209 WL_ERR(("failed to send neighbor report request, error=%d\n", error
));
24214 MFREE(cfg
->osh
, ssid
, sizeof(wlc_ssid_t
));
24218 MFREE(cfg
->osh
, smbuf
, WLC_IOCTL_MAXLEN
);
24223 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
24224 struct wl_profile
*profile
)
24229 wl_bsstrans_query_t btq
;
24231 WL_DBG(("Enter\n"));
24233 memset(&btq
, 0, sizeof(wl_bsstrans_query_t
));
24235 btq
.version
= WL_BSSTRANS_QUERY_VERSION_1
;
24236 error
= wldev_iovar_setbuf(dev
, "wnm_bsstrans_query", &btq
,
24237 sizeof(btq
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
24238 if (error
== BCME_OK
) {
24239 ret
= wl_cfg80211_wbtext_add_bssid_list(cfg
,
24240 (struct ether_addr
*)&profile
->bssid
);
24242 WL_ERR(("%s: failed to set BTM query, error=%d\n", __FUNCTION__
, error
));
24247 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211
*cfg
, struct net_device
*dev
)
24249 keepalives_max_idle_t keepalive
= {0, 0, 0, 0};
24251 int wnm_maxidle
= 0;
24252 struct wl_connect_info
*conn_info
= wl_to_conn(cfg
);
24254 /* AP supports wnm max idle ? */
24255 if (bcm_parse_tlvs(conn_info
->resp_ie
, conn_info
->resp_ie_len
,
24256 DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID
) != NULL
) {
24257 error
= wldev_iovar_getint(dev
, "wnm_maxidle", &wnm_maxidle
);
24259 WL_ERR(("failed to get wnm max idle period : %d\n", error
));
24263 WL_DBG(("wnm max idle period : %d\n", wnm_maxidle
));
24265 /* if wnm maxidle has valid period, set it as keep alive */
24266 if (wnm_maxidle
> 0) {
24267 keepalive
.keepalive_count
= 1;
24270 if ((bssidx
= wl_get_bssidx_by_wdev(cfg
, dev
->ieee80211_ptr
)) >= 0) {
24271 error
= wldev_iovar_setbuf_bsscfg(dev
, "wnm_keepalives_max_idle", &keepalive
,
24272 sizeof(keepalives_max_idle_t
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
,
24273 bssidx
, &cfg
->ioctl_buf_sync
);
24275 WL_ERR(("set wnm_keepalives_max_idle failed : %d\n", error
));
24281 wl_cfg80211_recv_nbr_resp(struct net_device
*dev
, uint8
*body
, uint body_len
)
24283 dot11_rm_action_t
*rm_rep
;
24287 dot11_neighbor_rep_ie_t
*nbr_rep_ie
;
24289 wl_roam_channel_list_t channel_list
;
24290 char iobuf
[WLC_IOCTL_SMLEN
];
24292 if (body_len
< DOT11_RM_ACTION_LEN
) {
24293 WL_ERR(("Received Neighbor Report frame with incorrect length %d\n",
24298 rm_rep
= (dot11_rm_action_t
*)body
;
24299 WL_DBG(("received neighbor report (token = %d)\n", rm_rep
->token
));
24301 tlvs
= (bcm_tlv_t
*)&rm_rep
->data
[0];
24303 tlv_len
= body_len
- DOT11_RM_ACTION_LEN
;
24305 while (tlvs
&& tlvs
->id
== DOT11_MNG_NEIGHBOR_REP_ID
) {
24306 nbr_rep_ie
= (dot11_neighbor_rep_ie_t
*)tlvs
;
24308 if (nbr_rep_ie
->len
< DOT11_NEIGHBOR_REP_IE_FIXED_LEN
) {
24309 WL_ERR(("malformed Neighbor Report element with length %d\n",
24311 tlvs
= bcm_next_tlv(tlvs
, &tlv_len
);
24315 ch
= CH20MHZ_CHSPEC(nbr_rep_ie
->channel
);
24316 WL_DBG(("ch:%d, bssid:"MACDBG
"\n",
24317 ch
, MAC2STRDBG(nbr_rep_ie
->bssid
.octet
)));
24320 error
= wldev_iovar_getbuf(dev
, "roamscan_channels", 0, 0,
24321 (void *)&channel_list
, sizeof(channel_list
), NULL
);
24323 WL_ERR(("Failed to get roamscan channels, error = %d\n", error
));
24328 if (channel_list
.n
< MAX_ROAM_CHANNEL
) {
24329 for (i
= 0; i
< channel_list
.n
; i
++) {
24330 if (channel_list
.channels
[i
] == ch
) {
24334 if (i
== channel_list
.n
) {
24335 channel_list
.channels
[channel_list
.n
] = ch
;
24341 error
= wldev_iovar_setbuf(dev
, "roamscan_channels", &channel_list
,
24342 sizeof(channel_list
), iobuf
, sizeof(iobuf
), NULL
);
24344 WL_DBG(("Failed to set roamscan channels, error = %d\n", error
));
24347 tlvs
= bcm_next_tlv(tlvs
, &tlv_len
);
24352 #endif /* WBTEXT */
24354 #ifdef DYNAMIC_MUMIMO_CONTROL
24356 wl_set_murx_block_eapol_status(struct bcm_cfg80211
*cfg
, int enable
)
24358 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
24361 dhdp
->murx_block_eapol
= enable
;
24366 wl_get_murx_reassoc_status(struct bcm_cfg80211
*cfg
)
24369 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
24372 status
= dhdp
->reassoc_mumimo_sw
;
24375 return status
? TRUE
: FALSE
;
24379 wl_set_murx_reassoc_status(struct bcm_cfg80211
*cfg
, int enable
)
24381 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
24384 dhdp
->reassoc_mumimo_sw
= enable
;
24389 wl_check_bss_support_mumimo(struct net_device
*dev
)
24391 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24392 struct wiphy
*wiphy
= NULL
;
24393 struct cfg80211_bss
*bss
= NULL
;
24394 struct wlc_ssid
*ssid
= NULL
;
24395 struct wl_bss_info
*bi
= NULL
;
24396 bcm_tlv_t
*vht_ie
= NULL
;
24400 u16 ie_mu_mimo_cap
= 0;
24402 if (!wl_get_drv_status(cfg
, CONNECTED
, dev
)) {
24403 WL_DBG(("Not associated\n"));
24407 wiphy
= bcmcfg_to_wiphy(cfg
);
24408 ssid
= (struct wlc_ssid
*)wl_read_prof(cfg
, dev
, WL_PROF_SSID
);
24409 bssid
= (u8
*)wl_read_prof(cfg
, dev
, WL_PROF_BSSID
);
24411 if (wiphy
&& ssid
&& bssid
) {
24412 bss
= CFG80211_GET_BSS(wiphy
, NULL
, bssid
,
24413 ssid
->SSID
, ssid
->SSID_len
);
24415 WL_DBG(("Could not find the associated AP\n"));
24420 #if defined(WL_CFG80211_P2P_DEV_IF)
24421 ie
= (u8
*)bss
->ies
->data
;
24422 ie_len
= bss
->ies
->len
;
24424 ie
= bss
->information_elements
;
24425 ie_len
= bss
->len_information_elements
;
24426 #endif /* WL_CFG80211_P2P_DEV_IF */
24427 bi
= (struct wl_bss_info
*)(cfg
->extra_buf
+ 4);
24428 if (bi
&& bi
->vht_cap
) {
24429 vht_ie
= bcm_parse_tlvs(ie
, ie_len
, DOT11_MNG_VHT_CAP_ID
);
24431 ie_mu_mimo_cap
= (vht_ie
->data
[2] & 0x08) >> 3;
24434 CFG80211_PUT_BSS(wiphy
, bss
);
24437 return ie_mu_mimo_cap
? TRUE
: FALSE
;
24441 wl_get_murx_bfe_cap(struct net_device
*dev
, int *cap
)
24444 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24446 /* Now there is only single interface */
24447 err
= wldev_iovar_getbuf_bsscfg(dev
, "murx_bfe_cap",
24448 NULL
, 0, cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, 0, &cfg
->ioctl_buf_sync
);
24449 if (unlikely(err
)) {
24450 WL_ERR(("Failed to get murx_bfe_cap IOVAR, error = %d\n", err
));
24454 memcpy(cap
, cfg
->ioctl_buf
, sizeof(*cap
));
24460 wl_set_murx_bfe_cap(struct net_device
*dev
, int val
, bool reassoc_req
)
24464 int iface_count
= wl_cfg80211_iface_count(dev
);
24465 struct ether_addr bssid
;
24466 wl_reassoc_params_t params
;
24467 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24468 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
24470 if (iface_count
> 1) {
24471 WL_ERR(("murx_bfe_cap change is not allowed when "
24472 "there are multiple interfaces\n"));
24476 if (reassoc_req
&& wl_get_murx_reassoc_status(cfg
)) {
24477 WL_ERR(("Reassociation is in progress...\n"));
24481 /* Check the current value */
24482 err
= wl_get_murx_bfe_cap(dev
, &cur_val
);
24487 if (cur_val
== val
) {
24488 /* We don't need to configure the new value. */
24489 WL_DBG(("Already set murx_bfe_cap to %d\n", val
));
24493 /* Now there is only single interface */
24494 err
= wldev_iovar_setbuf_bsscfg(dev
, "murx_bfe_cap", (void *)&val
,
24495 sizeof(val
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, 0,
24496 &cfg
->ioctl_buf_sync
);
24497 if (unlikely(err
)) {
24498 WL_ERR(("Failed to set murx_bfe_cap IOVAR to %d,"
24499 "error %d\n", val
, err
));
24504 DHD_DISABLE_RUNTIME_PM(dhdp
);
24506 /* Enable Tx flow control not to send any data frames to dongle
24507 * while reassociation procedure is in progress
24509 dhd_txflowcontrol(dhdp
, ALL_INTERFACES
, ON
);
24511 /* If successful intiate a reassoc */
24512 if ((err
= wldev_ioctl_get(dev
, WLC_GET_BSSID
, &bssid
, ETHER_ADDR_LEN
)) < 0) {
24513 WL_ERR(("Failed to get bssid, error=%d\n", err
));
24514 DHD_ENABLE_RUNTIME_PM(dhdp
);
24515 dhd_txflowcontrol(dhdp
, ALL_INTERFACES
, OFF
);
24519 bzero(¶ms
, sizeof(wl_reassoc_params_t
));
24520 memcpy(¶ms
.bssid
, &bssid
, ETHER_ADDR_LEN
);
24522 if ((err
= wldev_ioctl_set(dev
, WLC_REASSOC
, ¶ms
,
24523 sizeof(wl_reassoc_params_t
))) < 0) {
24524 WL_ERR(("reassoc failed err:%d\n", err
));
24525 DHD_ENABLE_RUNTIME_PM(dhdp
);
24526 dhd_txflowcontrol(dhdp
, ALL_INTERFACES
, OFF
);
24527 /* configure previous value */
24528 err
= wldev_iovar_setbuf_bsscfg(dev
, "murx_bfe_cap", (void *)&cur_val
,
24529 sizeof(val
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, 0,
24530 &cfg
->ioctl_buf_sync
);
24531 if (unlikely(err
)) {
24532 WL_ERR(("Failed to set murx_bfe_cap IOVAR to %d,"
24533 "error %d\n", val
, err
));
24535 wl_set_murx_reassoc_status(cfg
, FALSE
);
24537 WL_ERR(("reassoc issued successfully\n"));
24538 wl_set_murx_reassoc_status(cfg
, TRUE
);
24539 wl_set_murx_block_eapol_status(cfg
, TRUE
);
24545 #endif /* DYNAMIC_MUMIMO_CONTROL */
24547 #ifdef SUPPORT_SET_CAC
24549 wl_cfg80211_set_cac(struct bcm_cfg80211
*cfg
, int enable
)
24552 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
24554 #ifdef SUPPORT_CUSTOM_SET_CAC
24555 if (cfg
->enable_cac
== 0) {
24556 WL_DBG(("enable_cac %d\n", cfg
->enable_cac
));
24559 #endif /* SUPPORT_CUSTOM_SET_CAC */
24561 WL_DBG(("cac enable %d, op_mode 0x%04x\n", enable
, dhd
->op_mode
));
24563 WL_ERR(("dhd is NULL\n"));
24566 if (enable
&& ((dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
) ||
24567 (dhd
->op_mode
& DHD_FLAG_P2P_GC_MODE
) ||
24568 (dhd
->op_mode
& DHD_FLAG_P2P_GO_MODE
))) {
24569 WL_ERR(("op_mode 0x%04x\n", dhd
->op_mode
));
24572 if ((ret
= dhd_wl_ioctl_set_intiovar(dhd
, "cac", enable
,
24573 WLC_SET_VAR
, TRUE
, 0)) < 0) {
24574 WL_ERR(("Failed set CAC, ret=%d\n", ret
));
24576 WL_DBG(("CAC set successfully\n"));
24582 wl_cfg80211_enable_cac(struct net_device
*dev
, int enable
)
24584 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24586 WL_DBG(("enable %d\n", enable
));
24588 #ifdef SUPPORT_CUSTOM_SET_CAC
24589 cfg
->enable_cac
= enable
;
24590 #endif /* SUPPORT_CUSTOM_SET_CAC */
24591 wl_cfg80211_set_cac(cfg
, enable
);
24594 #endif /* SUPPORT_SET_CAC */
24596 #ifdef SUPPORT_RSSI_SUM_REPORT
24598 wl_get_rssi_per_ant(struct net_device
*dev
, char *ifname
, char *peer_mac
, void *param
)
24600 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24601 wl_rssi_ant_mimo_t
*get_param
= (wl_rssi_ant_mimo_t
*)param
;
24602 rssi_ant_param_t
*set_param
= NULL
;
24603 struct net_device
*ifdev
= NULL
;
24604 char iobuf
[WLC_IOCTL_SMLEN
];
24608 memset(iobuf
, 0, WLC_IOCTL_SMLEN
);
24610 /* Check the interface type */
24611 ifdev
= wl_get_netdev_by_name(cfg
, ifname
);
24612 if (ifdev
== NULL
) {
24613 WL_ERR(("Could not find net_device for ifname:%s\n", ifname
));
24618 iftype
= ifdev
->ieee80211_ptr
->iftype
;
24619 if (iftype
== NL80211_IFTYPE_AP
|| iftype
== NL80211_IFTYPE_P2P_GO
) {
24621 set_param
= (rssi_ant_param_t
*)MALLOCZ(cfg
->osh
, sizeof(rssi_ant_param_t
));
24622 err
= wl_cfg80211_ether_atoe(peer_mac
, &set_param
->ea
);
24624 WL_ERR(("Invalid Peer MAC format\n"));
24629 WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype
));
24635 err
= wldev_iovar_getbuf(ifdev
, "phy_rssi_ant", peer_mac
?
24636 (void *)&(set_param
->ea
) : NULL
, peer_mac
? ETHER_ADDR_LEN
: 0,
24637 (void *)iobuf
, sizeof(iobuf
), NULL
);
24638 if (unlikely(err
)) {
24639 WL_ERR(("Failed to get rssi info, err=%d\n", err
));
24641 memcpy(get_param
, iobuf
, sizeof(wl_rssi_ant_mimo_t
));
24642 if (get_param
->count
== 0) {
24643 WL_ERR(("Not supported on this chip\n"));
24644 err
= BCME_UNSUPPORTED
;
24650 MFREE(cfg
->osh
, set_param
, sizeof(rssi_ant_param_t
));
24657 wl_get_rssi_logging(struct net_device
*dev
, void *param
)
24659 rssilog_get_param_t
*get_param
= (rssilog_get_param_t
*)param
;
24660 char iobuf
[WLC_IOCTL_SMLEN
];
24663 memset(iobuf
, 0, WLC_IOCTL_SMLEN
);
24664 memset(get_param
, 0, sizeof(*get_param
));
24665 err
= wldev_iovar_getbuf(dev
, "rssilog", NULL
, 0, (void *)iobuf
,
24666 sizeof(iobuf
), NULL
);
24668 WL_ERR(("Failed to get rssi logging info, err=%d\n", err
));
24670 memcpy(get_param
, iobuf
, sizeof(*get_param
));
24677 wl_set_rssi_logging(struct net_device
*dev
, void *param
)
24679 struct bcm_cfg80211
*cfg
= wl_get_cfg(dev
);
24680 rssilog_set_param_t
*set_param
= (rssilog_set_param_t
*)param
;
24683 err
= wldev_iovar_setbuf(dev
, "rssilog", set_param
,
24684 sizeof(*set_param
), cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
,
24685 &cfg
->ioctl_buf_sync
);
24687 WL_ERR(("Failed to set rssi logging param, err=%d\n", err
));
24692 #endif /* SUPPORT_RSSI_SUM_REPORT */
24694 #ifdef APSTA_RESTRICTED_CHANNEL
24695 #define CMD_BLOCK_CH "block_ch"
24696 #define BAND5G_CHANNELS_BLOCK_OP1 999
24697 #define BAND5G_CHANNELS_BLOCK_OP2 -1
24700 wl_cfg80211_check_indoor_channels(struct net_device
*ndev
, int channel
)
24703 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24704 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
24705 wl_block_ch_t
*block_ch
= NULL
;
24706 int data_len
= WLC_IOCTL_SMLEN
;
24709 /* Get operation */
24710 block_ch
= (wl_block_ch_t
*)MALLOCZ(dhdp
->osh
, data_len
);
24711 if (block_ch
== NULL
) {
24712 WL_ERR(("Fail to allocate memory\n"));
24716 if (wl_cfg80211_read_indoor_channels(ndev
, block_ch
, data_len
) < 0) {
24717 WL_ERR(("Failed to read indoor channels\n"));
24721 if (block_ch
->channel_num
) {
24722 for (i
= 0; i
< block_ch
->channel_num
; i
++) {
24723 if (channel
== block_ch
->channel
[i
]) {
24724 WL_ERR(("channel %d is in the indoor "
24725 "channel list\n", channel
));
24734 MFREE(dhdp
->osh
, block_ch
, data_len
);
24741 wl_cfg80211_read_indoor_channels(struct net_device
*ndev
, void *buf
, int buflen
)
24743 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24744 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
24745 wl_block_ch_t
*iov_buf
= NULL
;
24746 wl_block_ch_t
*block_ch
= NULL
;
24751 WL_ERR(("dhdp is NULL\n"));
24755 if (buflen
< WLC_IOCTL_SMLEN
) {
24756 WL_ERR(("Buf is too short, buflen=%d\n", buflen
));
24757 return BCME_BUFTOOSHORT
;
24760 data_len
= OFFSETOF(wl_block_ch_t
, channel
);
24761 iov_buf
= (wl_block_ch_t
*)MALLOCZ(dhdp
->osh
, data_len
);
24762 if (iov_buf
== NULL
) {
24763 WL_ERR(("Fail to allocate memory\n"));
24768 iov_buf
->version
= WL_BLOCK_CHANNEL_VER_1
;
24769 iov_buf
->len
= data_len
;
24770 iov_buf
->band
= WF_CHAN_FACTOR_5_G
;
24771 iov_buf
->channel_num
= 0;
24773 err
= wldev_iovar_getbuf(ndev
, CMD_BLOCK_CH
, iov_buf
, data_len
,
24774 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
);
24776 WL_ERR(("Setting block_ch failed with err=%d \n", err
));
24780 block_ch
= (wl_block_ch_t
*)(cfg
->ioctl_buf
);
24781 if (block_ch
->version
!= WL_BLOCK_CHANNEL_VER_1
) {
24782 WL_ERR(("Version mismatched! actual %d expected: %d\n",
24783 block_ch
->version
, WL_BLOCK_CHANNEL_VER_1
));
24786 memcpy(buf
, cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
);
24791 MFREE(dhdp
->osh
, iov_buf
, data_len
);
24798 wl_cfg80211_set_indoor_channels(struct net_device
*ndev
, char *command
, int total_len
)
24801 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24802 struct net_device
*prmry_ndev
= bcmcfg_to_prmry_ndev(cfg
);
24803 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
24804 wl_block_ch_t
*block_ch
= NULL
;
24805 int block_ch_len
= 0;
24807 ulong channel_num
= 0;
24810 u8 chan_buf
[sizeof(u32
)*(WL_NUMCHANNELS
+ 1)];
24811 wl_uint32_list_t
*list
;
24812 u32 n_valid_chan
= 0;
24813 bool band5g_all_ch
= FALSE
;
24815 BCM_REFERENCE(total_len
);
24819 token
= bcmstrtok(&pos
, " ", NULL
);
24820 /* number of channel */
24821 token
= bcmstrtok(&pos
, " ", NULL
);
24823 if (token
== NULL
) {
24828 channel_num
= bcm_strtoul(token
, NULL
, 0);
24829 if (token
== NULL
) {
24834 if ((channel_num
== BAND5G_CHANNELS_BLOCK_OP1
) ||
24835 (channel_num
== BAND5G_CHANNELS_BLOCK_OP2
)) {
24837 band5g_all_ch
= TRUE
;
24839 if ((err
= wl_get_valid_channels(ndev
, chan_buf
, sizeof(chan_buf
))) < 0) {
24840 WL_ERR(("Failed to get valid channels - err %d\n", err
));
24843 list
= (wl_uint32_list_t
*) chan_buf
;
24844 n_valid_chan
= dtoh32(list
->count
);
24847 if (n_valid_chan
> WL_NUMCHANNELS
) {
24848 WL_ERR(("wrong n_valid_chan:%d\n", n_valid_chan
));
24849 err
= BCME_OUTOFRANGECHAN
;
24853 for (i
= 0; i
< n_valid_chan
; i
++) {
24854 if (CHANNEL_IS_5G(dtoh32(list
->element
[i
]))) {
24858 if (channel_num
== 0) {
24859 WL_ERR(("5G channels are not supported\n"));
24860 err
= BCME_BADCHAN
;
24864 } else if (channel_num
> MAXCHANNEL_NUM
) {
24865 WL_ERR(("Out of Range. Max channel number is %d\n", MAXCHANNEL_NUM
));
24870 block_ch_len
= OFFSETOF(wl_block_ch_t
, channel
) + channel_num
;
24871 block_ch
= (wl_block_ch_t
*)MALLOCZ(dhdp
->osh
, block_ch_len
);
24873 if (unlikely(!block_ch
)) {
24874 WL_ERR(("Failed to allocate memory\n"));
24879 block_ch
->version
= WL_BLOCK_CHANNEL_VER_1
;
24880 block_ch
->len
= block_ch_len
;
24881 block_ch
->band
= WF_CHAN_FACTOR_5_G
;
24882 block_ch
->channel_num
= channel_num
;
24884 if (band5g_all_ch
) {
24885 for (i
= 0; i
< n_valid_chan
; i
++) {
24886 channel
= dtoh32(list
->element
[i
]);
24887 if (CHANNEL_IS_5G(channel
)) {
24888 block_ch
->channel
[j
] = channel
;
24890 if (j
>= channel_num
) {
24896 for (i
= 0; i
< channel_num
; i
++) {
24897 token
= bcmstrtok(&pos
, " ", NULL
);
24898 if (token
== NULL
) {
24902 channel
= bcm_strtoul(token
, NULL
, 0);
24904 if (!CHANNEL_IS_5G(channel
)) {
24905 WL_ERR(("%d is Invalid Channel!\n", block_ch
->channel
[i
]));
24906 err
= BCME_BADCHAN
;
24909 block_ch
->channel
[i
] = channel
;
24913 /* Abort any association before setting block channel */
24914 if (wl_get_drv_status(cfg
, CONNECTING
, prmry_ndev
)) {
24915 wl_cfg80211_disassoc(prmry_ndev
);
24918 /* Setting block channel list to fw */
24919 if ((err
= wldev_iovar_setbuf(ndev
, CMD_BLOCK_CH
, block_ch
, block_ch
->len
,
24920 cfg
->ioctl_buf
, WLC_IOCTL_SMLEN
, &cfg
->ioctl_buf_sync
))) {
24921 WL_ERR(("Setting block_ch failed with err = %d\n", err
));
24925 if (err
== BCME_BADARG
) {
24926 WL_ERR(("Failed due to Bad Argument!\n"));
24929 MFREE(dhdp
->osh
, block_ch
, block_ch_len
);
24935 wl_cfg80211_get_indoor_channels(struct net_device
*ndev
, char *command
, int total_len
)
24938 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
24939 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
24940 wl_block_ch_t
*block_ch
= NULL
;
24941 int data_len
= WLC_IOCTL_SMLEN
;
24947 /* Get operation */
24948 block_ch
= (wl_block_ch_t
*)MALLOCZ(dhdp
->osh
, data_len
);
24949 if (block_ch
== NULL
) {
24950 WL_ERR(("Fail to allocate memory\n"));
24955 err
= wl_cfg80211_read_indoor_channels(ndev
, block_ch
, data_len
);
24957 WL_ERR(("Failed to read indoor channels, err=%d\n", err
));
24961 if (block_ch
->channel_num
) {
24962 pos
+= snprintf(pos
, total_len
, "%d ", block_ch
->channel_num
);
24963 for (i
= 0; i
< block_ch
->channel_num
; i
++) {
24964 pos
+= snprintf(pos
, total_len
, "%d ", block_ch
->channel
[i
]);
24966 err
= (pos
- command
);
24971 MFREE(dhdp
->osh
, block_ch
, data_len
);
24976 #endif /* APSTA_RESTRICTED_CHANNEL */
24978 #ifdef DHD_LOG_DUMP
24979 /* Function to flush the FW preserve buffer content
24980 * The buffer content is sent to host in form of events.
24983 wl_flush_fw_log_buffer(struct net_device
*dev
, uint32 logset_mask
)
24987 u8 buf
[WLC_IOCTL_SMLEN
] = {0};
24988 wl_el_set_params_t set_param
;
24990 /* Set the size of data to retrieve */
24991 memset(&set_param
, 0, sizeof(set_param
));
24992 set_param
.size
= WLC_IOCTL_SMLEN
;
24994 for (i
= 0; i
< WL_MAX_PRESERVE_BUFFER
; i
++)
24996 if ((0x01u
<< i
) & logset_mask
) {
24998 err
= wldev_iovar_setbuf(dev
, "event_log_get", &set_param
,
24999 sizeof(struct wl_el_set_params_s
), buf
, WLC_IOCTL_SMLEN
,
25002 WL_DBG(("Failed to get fw preserve logs, err=%d\n", err
));
25007 #endif /* DHD_LOG_DUMP */
25010 wl_cfg80211_set_dbg_verbose(struct net_device
*ndev
, u32 level
)
25012 /* configure verbose level for debugging */
25014 /* Enable increased verbose */
25015 wl_dbg_level
|= WL_DBG_DBG
;
25018 wl_dbg_level
&= ~WL_DBG_DBG
;
25020 WL_INFORM(("debug verbose set to %d\n", level
));
25026 wl_cfg80211_check_for_nan_support(struct bcm_cfg80211
*cfg
)
25028 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
25029 if (((p2p_is_on(cfg
)) && (wl_get_p2p_status(cfg
, SCANNING
) ||
25030 wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_CONNECTION1
))) ||
25031 (dhd
->op_mode
& DHD_FLAG_HOSTAP_MODE
))
25033 WL_ERR(("p2p/softap is enabled, cannot support nan\n"));
25039 uint8
wl_cfg80211_get_bus_state(struct bcm_cfg80211
*cfg
)
25041 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
25042 WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
25043 dhd
->hang_was_sent
, dhd
->busstate
));
25044 return ((dhd
->busstate
== DHD_BUS_DOWN
) || dhd
->hang_was_sent
);
25048 static void wl_wps_reauth_timeout(unsigned long data
)
25050 struct net_device
*ndev
= (struct net_device
*)data
;
25051 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25053 unsigned long flags
;
25055 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25056 inst
= wl_get_wps_inst_match(cfg
, ndev
);
25058 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n",
25059 ndev
->name
, inst
, cfg
->wps_session
[inst
].state
));
25060 if (cfg
->wps_session
[inst
].state
== WPS_STATE_REAUTH_WAIT
) {
25061 /* Session should get deleted from success (linkup) or
25062 * deauth case. Just in case, link reassoc failed, clear
25065 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n",
25066 ndev
->name
, inst
));
25067 cfg
->wps_session
[inst
].state
= WPS_STATE_IDLE
;
25068 cfg
->wps_session
[inst
].in_use
= false;
25071 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25074 static void wl_init_wps_reauth_sm(struct bcm_cfg80211
*cfg
)
25076 /* Only two instances are supported as of now. one for
25077 * infra STA and other for infra STA/GC.
25080 struct net_device
*pdev
= bcmcfg_to_prmry_ndev(cfg
);
25082 spin_lock_init(&cfg
->wps_sync
);
25083 for (i
= 0; i
< WPS_MAX_SESSIONS
; i
++) {
25084 /* Init scan_timeout timer */
25085 init_timer(&cfg
->wps_session
[i
].timer
);
25086 cfg
->wps_session
[i
].timer
.data
= (unsigned long) pdev
;
25087 cfg
->wps_session
[i
].timer
.function
= wl_wps_reauth_timeout
;
25088 cfg
->wps_session
[i
].in_use
= false;
25089 cfg
->wps_session
[i
].state
= WPS_STATE_IDLE
;
25093 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211
*cfg
)
25097 for (i
= 0; i
< WPS_MAX_SESSIONS
; i
++) {
25098 cfg
->wps_session
[i
].in_use
= false;
25099 cfg
->wps_session
[i
].state
= WPS_STATE_IDLE
;
25100 if (timer_pending(&cfg
->wps_session
[i
].timer
)) {
25101 del_timer_sync(&cfg
->wps_session
[i
].timer
);
25108 wl_get_free_wps_inst(struct bcm_cfg80211
*cfg
)
25112 for (i
= 0; i
< WPS_MAX_SESSIONS
; i
++) {
25113 if (!cfg
->wps_session
[i
].in_use
) {
25121 wl_get_wps_inst_match(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
25125 for (i
= 0; i
< WPS_MAX_SESSIONS
; i
++) {
25126 if ((cfg
->wps_session
[i
].in_use
) &&
25127 (ndev
== cfg
->wps_session
[i
].ndev
)) {
25136 wl_wps_session_add(struct net_device
*ndev
, u16 mode
, u8
*mac_addr
)
25139 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25140 unsigned long flags
;
25142 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25143 /* Fetch and initialize a wps instance */
25144 inst
= wl_get_free_wps_inst(cfg
);
25145 if (inst
== BCME_ERROR
) {
25146 WL_ERR(("[WPS] No free insance\n"));
25147 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25150 cfg
->wps_session
[inst
].in_use
= true;
25151 cfg
->wps_session
[inst
].state
= WPS_STATE_STARTED
;
25152 cfg
->wps_session
[inst
].ndev
= ndev
;
25153 cfg
->wps_session
[inst
].mode
= mode
;
25154 memcpy(cfg
->wps_session
[inst
].peer_mac
, mac_addr
, ETH_ALEN
);
25155 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25157 WL_INFORM_MEM(("[%s][WPS] session created. Peer: " MACDBG
"\n",
25158 ndev
->name
, MAC2STRDBG(mac_addr
)));
25163 wl_wps_session_del(struct net_device
*ndev
)
25166 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25167 unsigned long flags
;
25170 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25172 /* Get current instance for the given ndev */
25173 inst
= wl_get_wps_inst_match(cfg
, ndev
);
25174 if (inst
== BCME_ERROR
) {
25175 WL_DBG(("[WPS] instance match NOT found\n"));
25176 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25180 cur_state
= cfg
->wps_session
[inst
].state
;
25181 if (cur_state
!= WPS_STATE_DONE
) {
25182 WL_DBG(("[WPS] wrong state:%d\n", cur_state
));
25183 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25187 /* Mark this as unused */
25188 cfg
->wps_session
[inst
].in_use
= false;
25189 cfg
->wps_session
[inst
].state
= WPS_STATE_IDLE
;
25190 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25192 /* Ensure this API is called from sleepable context. */
25193 if (timer_pending(&cfg
->wps_session
[inst
].timer
)) {
25194 del_timer_sync(&cfg
->wps_session
[inst
].timer
);
25197 WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev
->name
));
25201 wl_wps_handle_ifdel(struct net_device
*ndev
)
25203 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25204 unsigned long flags
;
25208 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25209 inst
= wl_get_wps_inst_match(cfg
, ndev
);
25210 if (inst
== BCME_ERROR
) {
25211 WL_DBG(("[WPS] instance match NOT found\n"));
25212 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25215 cur_state
= cfg
->wps_session
[inst
].state
;
25216 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
25217 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25219 WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev
->name
, cur_state
));
25220 if (cur_state
> WPS_STATE_IDLE
) {
25221 wl_wps_session_del(ndev
);
25226 wl_wps_handle_sta_linkdown(struct net_device
*ndev
, u16 inst
)
25228 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25229 unsigned long flags
;
25231 bool wps_done
= false;
25233 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25234 cur_state
= cfg
->wps_session
[inst
].state
;
25235 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
25236 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25237 wl_clr_drv_status(cfg
, CONNECTED
, ndev
);
25238 wl_clr_drv_status(cfg
, DISCONNECTING
, ndev
);
25239 WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev
->name
));
25240 /* Drop the link down event while we are waiting for reauth */
25241 return BCME_UNSUPPORTED
;
25242 } else if (cur_state
== WPS_STATE_STARTED
) {
25243 /* Link down before reaching EAP-FAIL. End WPS session */
25244 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
25246 WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev
->name
));
25248 WL_DBG(("[%s][WPS] link down in state:%d\n",
25249 ndev
->name
, cur_state
));
25252 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25255 wl_wps_session_del(ndev
);
25261 wl_wps_handle_peersta_linkdown(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
25263 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25264 unsigned long flags
;
25267 bool wps_done
= false;
25269 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25270 cur_state
= cfg
->wps_session
[inst
].state
;
25273 WL_ERR(("Invalid arg\n"));
25278 /* AP/GO can have multiple clients. so validate peer_mac addr
25279 * and ensure states are updated only for right peer.
25281 if (memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
25282 /* Mac addr not matching. Ignore. */
25283 WL_DBG(("[%s][WPS] No active WPS session"
25284 "for the peer:" MACDBG
"\n", ndev
->name
, MAC2STRDBG(peer_mac
)));
25288 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
25289 WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
25290 " Peer: " MACDBG
"\n",
25291 ndev
->name
, MAC2STRDBG(peer_mac
)));
25293 /* Link down during REAUTH state is expected. However,
25294 * if this is send up, hostapd statemachine issues a
25295 * deauth down and that may pre-empt WPS reauth state
25298 WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore."
25299 " for client:" MACDBG
"\n",
25300 ndev
->name
, MAC2STRDBG(peer_mac
)));
25301 ret
= BCME_UNSUPPORTED
;
25303 } else if (cur_state
== WPS_STATE_STARTED
) {
25304 /* Link down before reaching REAUTH_WAIT state. WPS
25307 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
25308 WL_INFORM_MEM(("[%s][WPS] link down after wps start"
25309 " client:" MACDBG
"\n",
25310 ndev
->name
, MAC2STRDBG(peer_mac
)));
25312 /* since we have freed lock above, return from here */
25315 WL_ERR(("[%s][WPS] Unsupported state:%d",
25316 ndev
->name
, cur_state
));
25320 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25322 wl_wps_session_del(ndev
);
25328 wl_wps_handle_sta_linkup(struct net_device
*ndev
, u16 inst
)
25330 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25331 unsigned long flags
;
25334 bool wps_done
= false;
25336 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25337 cur_state
= cfg
->wps_session
[inst
].state
;
25338 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
25339 /* WPS session succeeded. del session. */
25340 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
25342 WL_INFORM_MEM(("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev
->name
));
25345 WL_ERR(("[%s][WPS] unexpected link up in state:%d \n",
25346 ndev
->name
, cur_state
));
25349 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25351 wl_wps_session_del(ndev
);
25357 wl_wps_handle_peersta_linkup(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
25359 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25360 unsigned long flags
;
25364 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25365 cur_state
= cfg
->wps_session
[inst
].state
;
25367 /* For AP case, check whether call came for right peer */
25369 memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
25370 WL_ERR(("[WPS] macaddr mismatch\n"));
25371 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25372 /* Mac addr not matching. Ignore. */
25376 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
25377 WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev
->name
));
25380 WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
25381 ndev
->name
, cur_state
));
25385 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25391 wl_wps_handle_authorize(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
25393 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25394 unsigned long flags
;
25396 bool wps_done
= false;
25399 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25400 cur_state
= cfg
->wps_session
[inst
].state
;
25402 /* For AP case, check whether call came for right peer */
25404 memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
25405 WL_ERR(("[WPS] macaddr mismatch\n"));
25406 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25407 /* Mac addr not matching. Ignore. */
25411 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
25412 /* WPS session succeeded. del session. */
25413 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
25415 WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev
->name
));
25418 WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
25419 ndev
->name
, cur_state
));
25423 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25425 wl_wps_session_del(ndev
);
25431 wl_wps_handle_reauth(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
25433 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25434 unsigned long flags
;
25439 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25440 cur_state
= cfg
->wps_session
[inst
].state
;
25441 mode
= cfg
->wps_session
[inst
].mode
;
25443 if (cur_state
== WPS_STATE_STARTED
) {
25444 /* Move to reauth wait */
25445 cfg
->wps_session
[inst
].state
= WPS_STATE_REAUTH_WAIT
;
25446 /* Use ndev to find the wps instance which fired the timer */
25447 cfg
->wps_session
[inst
].timer
.data
= (unsigned long) ndev
;
25448 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25449 mod_timer(&cfg
->wps_session
[inst
].timer
,
25450 jiffies
+ msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT
));
25451 WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG
"\n",
25452 ndev
->name
, mode
, MAC2STRDBG(peer_mac
)));
25456 WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev
->name
));
25458 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25463 wl_wps_handle_disconnect(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
25465 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25466 unsigned long flags
;
25470 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25471 cur_state
= cfg
->wps_session
[inst
].state
;
25472 /* If Disconnect command comes from user space for STA/GC,
25473 * respond with event without waiting for event from fw as
25474 * it would be dropped by the WPS_SYNC code.
25476 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
25477 if (ETHER_ISBCAST(peer_mac
)) {
25478 WL_DBG(("[WPS] Bcast peer. Do nothing.\n"));
25480 /* Notify link down */
25481 CFG80211_DISCONNECTED(ndev
,
25482 WLAN_REASON_DEAUTH_LEAVING
, NULL
, 0,
25486 WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
25487 ndev
->name
, cur_state
));
25488 ret
= BCME_UNSUPPORTED
;
25490 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25495 wl_wps_handle_disconnect_client(struct net_device
*ndev
, u16 inst
, const u8
*peer_mac
)
25497 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25498 unsigned long flags
;
25501 bool wps_done
= false;
25503 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25504 cur_state
= cfg
->wps_session
[inst
].state
;
25505 /* For GO/AP, ignore disconnect client during reauth state */
25506 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
25507 if (ETHER_ISBCAST(peer_mac
)) {
25508 /* If there is broadcast deauth, then mark wps session as ended */
25509 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
25511 WL_INFORM_MEM(("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev
->name
));
25514 } else if (!(memcmp(cfg
->wps_session
[inst
].peer_mac
,
25515 peer_mac
, ETH_ALEN
))) {
25516 WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev
->name
));
25517 ret
= BCME_UNSUPPORTED
;
25522 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25524 wl_wps_session_del(ndev
);
25530 wl_wps_handle_connect_fail(struct net_device
*ndev
, u16 inst
)
25532 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25533 unsigned long flags
;
25535 bool wps_done
= false;
25537 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25538 cur_state
= cfg
->wps_session
[inst
].state
;
25539 if (cur_state
== WPS_STATE_REAUTH_WAIT
) {
25540 cfg
->wps_session
[inst
].state
= WPS_STATE_DONE
;
25542 WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n",
25545 WL_ERR(("[%s][WPS] Connect fail. state:%d\n",
25546 ndev
->name
, cur_state
));
25548 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25550 wl_wps_session_del(ndev
);
25556 wl_wps_session_update(struct net_device
*ndev
, u16 state
, const u8
*peer_mac
)
25560 struct bcm_cfg80211
*cfg
= wl_get_cfg(ndev
);
25561 s32 ret
= BCME_ERROR
;
25562 unsigned long flags
;
25564 spin_lock_irqsave(&cfg
->wps_sync
, flags
);
25565 /* Get current instance for the given ndev */
25566 inst
= wl_get_wps_inst_match(cfg
, ndev
);
25567 if (inst
== BCME_ERROR
) {
25568 /* No active WPS session. Do Nothing. */
25569 WL_DBG(("[%s][WPS] No matching instance.\n", ndev
->name
));
25570 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25573 mode
= cfg
->wps_session
[inst
].mode
;
25574 spin_unlock_irqrestore(&cfg
->wps_sync
, flags
);
25576 WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG
"\n",
25577 ndev
->name
, state
, mode
, MAC2STRDBG(peer_mac
)));
25580 case WPS_STATE_M8_RECVD
:
25582 /* Occasionally, due to race condition between ctrl
25583 * and data path, deauth ind is recvd before EAP-FAIL.
25584 * Ignore deauth ind before EAP-FAIL
25585 * So move to REAUTH WAIT on receiving M8 on GC and
25586 * ignore deauth ind before EAP-FAIL till 'x' timeout.
25587 * Kickoff a timer to monitor reauth status.
25589 if (mode
== WL_MODE_BSS
) {
25590 ret
= wl_wps_handle_reauth(ndev
, inst
, peer_mac
);
25592 /* Nothing to be done for AP/GO mode */
25597 case WPS_STATE_EAP_FAIL
:
25599 /* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
25600 * Kickoff a timer to monitor reauth status
25602 if (mode
== WL_MODE_AP
) {
25603 ret
= wl_wps_handle_reauth(ndev
, inst
, peer_mac
);
25605 /* Nothing to be done for STA/GC mode */
25610 case WPS_STATE_LINKDOWN
:
25612 if (mode
== WL_MODE_BSS
) {
25613 ret
= wl_wps_handle_sta_linkdown(ndev
, inst
);
25614 } else if (mode
== WL_MODE_AP
) {
25615 /* Take action only for matching peer mac */
25616 if (!memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
25617 ret
= wl_wps_handle_peersta_linkdown(ndev
, inst
, peer_mac
);
25622 case WPS_STATE_LINKUP
:
25624 if (mode
== WL_MODE_BSS
) {
25625 wl_wps_handle_sta_linkup(ndev
, inst
);
25626 } else if (mode
== WL_MODE_AP
) {
25627 /* Take action only for matching peer mac */
25628 if (!memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
25629 wl_wps_handle_peersta_linkup(ndev
, inst
, peer_mac
);
25634 case WPS_STATE_DISCONNECT_CLIENT
:
25636 /* Disconnect STA/GC command from user space */
25637 if (mode
== WL_MODE_AP
) {
25638 ret
= wl_wps_handle_disconnect_client(ndev
, inst
, peer_mac
);
25640 WL_ERR(("[WPS] Unsupported mode %d\n", mode
));
25644 case WPS_STATE_DISCONNECT
:
25646 /* Disconnect command on STA/GC interface */
25647 if (mode
== WL_MODE_BSS
) {
25648 ret
= wl_wps_handle_disconnect(ndev
, inst
, peer_mac
);
25652 case WPS_STATE_CONNECT_FAIL
:
25654 if (mode
== WL_MODE_BSS
) {
25655 ret
= wl_wps_handle_connect_fail(ndev
, inst
);
25657 WL_ERR(("[WPS] Unsupported mode %d\n", mode
));
25661 case WPS_STATE_AUTHORIZE
:
25663 if (mode
== WL_MODE_AP
) {
25664 /* Take action only for matching peer mac */
25665 if (!memcmp(cfg
->wps_session
[inst
].peer_mac
, peer_mac
, ETH_ALEN
)) {
25666 wl_wps_handle_authorize(ndev
, inst
, peer_mac
);
25668 WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
25675 WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state
, mode
));
25682 #define EAP_EXP_ATTRIB_DATA_OFFSET 14
25684 wl_handle_wps_states(struct net_device
*ndev
, u8
*pkt
, u16 len
, bool direction
)
25686 eapol_header_t
*eapol_hdr
;
25687 bool tx_packet
= direction
;
25692 if (!ndev
|| !pkt
) {
25693 WL_ERR(("[WPS] Invalid arg\n"));
25697 if (len
< (ETHER_HDR_LEN
+ EAPOL_HDR_LEN
)) {
25698 WL_ERR(("[WPS] Invalid len\n"));
25702 eapol_hdr
= (eapol_header_t
*)pkt
;
25703 eapol_type
= eapol_hdr
->type
;
25705 peer_mac
= tx_packet
? eapol_hdr
->eth
.ether_dhost
:
25706 eapol_hdr
->eth
.ether_shost
;
25708 * The implementation assumes only one WPS session would be active
25709 * per interface at a time. Even for hostap, the wps_pin session
25710 * is limited to one enrollee/client at a time. A session is marked
25711 * started on WSC_START and gets cleared from below contexts
25712 * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
25713 * b) Link up following EAP-FAIL. (success case)
25714 * c) Link up timeout after EAP-FAIL. (Fail case)
25717 if (eapol_type
== EAP_PACKET
) {
25718 wl_eap_header_t
*eap
;
25720 if (len
> sizeof(*eap
)) {
25721 eap
= (wl_eap_header_t
*)(pkt
+ ETHER_HDR_LEN
+ EAPOL_HDR_LEN
);
25722 if (eap
->type
== EAP_EXPANDED_TYPE
) {
25723 wl_eap_exp_t
*exp
= (wl_eap_exp_t
*)eap
->data
;
25724 if (eap
->length
> EAP_EXP_HDR_MIN_LENGTH
) {
25725 /* opcode is at fixed offset */
25726 u8 opcode
= exp
->opcode
;
25727 u16 eap_len
= ntoh16(eap
->length
);
25729 WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
25730 ndev
->name
, opcode
, eap_len
));
25731 if (opcode
== EAP_WSC_MSG
) {
25733 const u8
* parse_buf
= exp
->data
;
25734 /* Check if recvd pkt is fragmented */
25735 if ((!tx_packet
) &&
25737 EAP_EXP_FLAGS_FRAGMENTED_DATA
)) {
25738 if ((eap_len
- EAP_EXP_ATTRIB_DATA_OFFSET
)
25741 EAP_EXP_FRAGMENT_LEN_OFFSET
;
25743 EAP_EXP_FRAGMENT_LEN_OFFSET
;
25745 " fragmented pkt\n"));
25747 /* If recvd pkt is fragmented
25748 * and does not have
25749 * length field drop the packet.
25755 msg
= wl_find_attribute(parse_buf
,
25756 (eap_len
- EAP_EXP_ATTRIB_DATA_OFFSET
),
25757 EAP_ATTRIB_MSGTYPE
);
25758 if (unlikely(!msg
)) {
25759 WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
25760 } else if ((*msg
== EAP_WSC_MSG_M8
) &&
25762 WL_INFORM_MEM(("[%s][WPS] M8\n",
25764 wl_wps_session_update(ndev
,
25765 WPS_STATE_M8_RECVD
, peer_mac
);
25767 WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n",
25768 ndev
->name
, *msg
));
25770 } else if (opcode
== EAP_WSC_START
) {
25771 /* WSC session started. WSC_START - Tx from GO/AP.
25772 * Session will be deleted on successful link up or
25773 * on failure (deauth context)
25775 mode
= tx_packet
? WL_MODE_AP
: WL_MODE_BSS
;
25776 wl_wps_session_add(ndev
, mode
, peer_mac
);
25777 WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
25778 ndev
->name
, mode
));
25779 } else if (opcode
== EAP_WSC_DONE
) {
25780 /* WSC session done. TX on STA/GC. RX on GO/AP
25781 * On devices where config file save fails, it may
25782 * return WPS_NAK with config_error:0. But the
25783 * connection would still proceed. Hence don't let
25784 * state machine depend on WSC DONE.
25786 WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev
->name
));
25791 if (eap
->code
== EAP_CODE_FAILURE
) {
25793 WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev
->name
));
25794 wl_wps_session_update(ndev
,
25795 WPS_STATE_EAP_FAIL
, peer_mac
);
25800 #endif /* WL_WPS_SYNC */
25803 wl_find_attribute(const u8
*buf
, u16 len
, u16 element_id
)
25810 WL_ERR(("buf null\n"));
25817 attrib_id
= *attrib
++ << 8;
25818 attrib_id
|= *attrib
++;
25821 /* 2-byte little endian */
25822 attrib_len
= *attrib
++ << 8;
25823 attrib_len
|= *attrib
++;
25826 if (attrib_id
== element_id
) {
25827 /* This will point to start of subelement attrib after
25828 * attribute id & len
25832 if (len
> attrib_len
) {
25833 len
-= attrib_len
; /* for the remaining subelt fields */
25834 WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n",
25835 attrib_id
, attrib_len
, len
));
25837 /* Go to next subelement */
25838 attrib
+= attrib_len
;
25840 WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n",
25841 attrib_id
, attrib_len
));
25849 wl_retrieve_wps_attribute(const u8
*buf
, u16 element_id
)
25851 const wl_wps_ie_t
*ie
= NULL
;
25856 WL_ERR(("WPS IE not present"));
25860 ie
= (const wl_wps_ie_t
*) buf
;
25863 /* Point subel to the P2P IE's subelt field.
25864 * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
25866 attrib
= ie
->attrib
;
25867 len
-= 4; /* exclude OUI + OUI_TYPE */
25869 /* Search for attrib */
25870 return wl_find_attribute(attrib
, len
, element_id
);
25873 #define WPS_ATTR_REQ_TYPE 0x103a
25874 #define WPS_REQ_TYPE_ENROLLEE 0x01
25876 wl_is_wps_enrollee_active(struct net_device
*ndev
, const u8
*ie_ptr
, u16 len
)
25881 if ((ie
= (const u8
*)wl_cfgp2p_find_wpsie(ie_ptr
, len
)) == NULL
) {
25882 WL_DBG(("WPS IE not present. Do nothing.\n"));
25886 if ((attrib
= wl_retrieve_wps_attribute(ie
, WPS_ATTR_REQ_TYPE
)) == NULL
) {
25887 WL_DBG(("WPS_ATTR_REQ_TYPE not found!\n"));
25891 if (*attrib
== WPS_REQ_TYPE_ENROLLEE
) {
25892 WL_INFORM_MEM(("WPS Enrolle Active\n"));
25895 WL_DBG(("WPS_REQ_TYPE:%d\n", *attrib
));
25901 #ifdef USE_WFA_CERT_CONF
25902 extern int g_frameburst
;
25903 #endif /* USE_WFA_CERT_CONF */
25906 wl_cfg80211_set_frameburst(struct bcm_cfg80211
*cfg
, bool enable
)
25909 int val
= enable
? 1 : 0;
25911 #ifdef USE_WFA_CERT_CONF
25912 if (!g_frameburst
) {
25913 WL_DBG(("Skip setting frameburst\n"));
25916 #endif /* USE_WFA_CERT_CONF */
25918 WL_DBG(("Set frameburst %d\n", val
));
25919 ret
= wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg
), WLC_SET_FAKEFRAG
, &val
, sizeof(val
));
25921 WL_ERR(("Failed set frameburst, ret=%d\n", ret
));
25923 WL_INFORM_MEM(("frameburst is %s\n", enable
? "enabled" : "disabled"));