dhd: import wifi and bluetooth firmware
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.101.10.240.x / wl_cfg80211.c
CommitLineData
1b4a7c03
LJ
1/*
2 * Linux cfg80211 driver
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Dual:>>
22 */
23/* */
24#include <typedefs.h>
25#include <linuxver.h>
26#include <linux/kernel.h>
27
28#include <bcmutils.h>
29#include <bcmstdlib_s.h>
30#include <bcmwifi_channels.h>
31#include <bcmendian.h>
32#include <ethernet.h>
33#ifdef WL_WPS_SYNC
34#include <eapol.h>
35#endif /* WL_WPS_SYNC */
36#include <802.11.h>
37#include <bcmiov.h>
38#include <linux/if_arp.h>
39#include <asm/uaccess.h>
40
41#include <ethernet.h>
42#include <linux/kernel.h>
43#include <linux/kthread.h>
44#include <linux/netdevice.h>
45#include <linux/sched.h>
46#include <linux/etherdevice.h>
47#include <linux/wireless.h>
48#include <linux/ieee80211.h>
49#include <linux/wait.h>
50#if defined(CONFIG_TIZEN)
51#include <linux/net_stat_tizen.h>
52#endif /* CONFIG_TIZEN */
53#include <net/cfg80211.h>
54#include <net/rtnetlink.h>
55
56#include <wlioctl.h>
57#include <bcmevent.h>
58#include <wldev_common.h>
59#include <wl_cfg80211.h>
60#include <wl_cfgp2p.h>
61#include <wl_cfgscan.h>
62#include <bcmdevs.h>
63#include <bcmdevs_legacy.h>
64#ifdef WL_FILS
65#include <fils.h>
66#include <frag.h>
67#endif /* WL_FILS */
68
69#include <wl_android.h>
70
71#include <dngl_stats.h>
72#include <dhd.h>
73#include <dhd_linux.h>
74#include <dhd_linux_pktdump.h>
75#include <dhd_debug.h>
76#include <dhdioctl.h>
77#include <wlioctl.h>
78#include <dhd_cfg80211.h>
79#include <dhd_bus.h>
80#ifdef PNO_SUPPORT
81#include <dhd_pno.h>
82#endif /* PNO_SUPPORT */
83#include <wl_cfgvendor.h>
84
85#ifdef CONFIG_SLEEP_MONITOR
86#include <linux/power/sleep_monitor.h>
87#endif
88
89#if !defined(WL_VENDOR_EXT_SUPPORT)
90#undef GSCAN_SUPPORT
91#endif
92#include <dhd_config.h>
93
94#ifdef WL_NAN
95#include <wl_cfgnan.h>
96#endif /* WL_NAN */
97
98#ifdef PROP_TXSTATUS
99#include <dhd_wlfc.h>
100#endif
101
102#ifdef BCMPCIE
103#include <dhd_flowring.h>
104#endif
105#ifdef RTT_SUPPORT
106#include <dhd_rtt.h>
107#endif /* RTT_SUPPORT */
108
109#if defined(BIGDATA_SOFTAP) || defined(DHD_ENABLE_BIGDATA_LOGGING)
110#include <wl_bigdata.h>
111#endif /* BIGDATA_SOFTAP || DHD_ENABLE_BIGDATA_LOGGING */
112
113#ifdef DHD_EVENT_LOG_FILTER
114#include <dhd_event_log_filter.h>
115#endif /* DHD_EVENT_LOG_FILTER */
116#define BRCM_SAE_VENDOR_EVENT_BUF_LEN 500
117
118#ifdef DNGL_AXI_ERROR_LOGGING
119#include <bcmtlv.h>
120#endif /* DNGL_AXI_ERROR_LOGGING */
121
122#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
123#include <linux/dev_ril_bridge.h>
124#include <linux/notifier.h>
125#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
126
127#if (defined(WL_FW_OCE_AP_SELECT) || defined(BCMFW_ROAM_ENABLE)) && \
128 ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS))
129uint fw_ap_select = true;
130#else
131uint fw_ap_select = false;
132#endif /* WL_FW_OCE_AP_SELECT && (ROAM_ENABLE || BCMFW_ROAM_ENABLE) */
133module_param(fw_ap_select, uint, 0660);
134
135#if defined(WL_REASSOC)
136uint wl_reassoc_support = true;
137#else
138uint wl_reassoc_support = false;
139#endif /* WL_REASSOC */
140module_param(wl_reassoc_support, uint, 0660);
141
142static struct device *cfg80211_parent_dev = NULL;
143static struct bcm_cfg80211 *g_bcmcfg = NULL;
144u32 wl_dbg_level = WL_DBG_ERR;
145
146#define MAX_VIF_OFFSET 15
147#define MAX_WAIT_TIME 1500
148#ifdef WLAIBSS_MCHAN
149#define IBSS_IF_NAME "ibss%d"
150#endif /* WLAIBSS_MCHAN */
151
152#ifdef VSDB
153/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
154#define DEFAULT_SLEEP_TIME_VSDB 120
155#define OFF_CHAN_TIME_THRESHOLD_MS 200
156#define AF_RETRY_DELAY_TIME 40
157
158/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
159#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
160 do { \
161 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
162 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
163 OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
164 } \
165 } while (0)
166#else /* VSDB */
167/* if not VSDB, do nothing */
168#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
169#endif /* VSDB */
170
171#define DNGL_FUNC(func, parameters) func parameters
172#define COEX_DHCP
173
174#define WLAN_EID_SSID 0
175#define CH_MIN_5G_CHANNEL 34
176#ifdef WLAIBSS
177enum abiss_event_type {
178 AIBSS_EVENT_TXFAIL
179};
180#endif
181
182#ifdef WL_RELMCAST
183enum rmc_event_type {
184 RMC_EVENT_NONE,
185 RMC_EVENT_LEADER_CHECK_FAIL
186};
187#endif /* WL_RELMCAST */
188
189/* This is to override regulatory domains defined in cfg80211 module (reg.c)
190 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
191 * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
192 * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
193 * All the chnages in world regulatory domain are to be done here.
194 *
195 * this definition reuires disabling missing-field-initializer warning
196 * as the ieee80211_regdomain definition differs in plain linux and in Android
197 */
198#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
199 4 && __GNUC_MINOR__ >= 6))
200_Pragma("GCC diagnostic push")
201_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
202#endif
203static const struct ieee80211_regdomain brcm_regdom = {
204#ifdef WL_6G_BAND
205 .n_reg_rules = 8,
206#else
207 .n_reg_rules = 4,
208#endif
209 .alpha2 = "99",
210 .reg_rules = {
211 /* IEEE 802.11b/g, channels 1..11 */
212 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
213 /* If any */
214 /* IEEE 802.11 channel 14 - Only JP enables
215 * this and for 802.11b only
216 */
217 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
218 /* IEEE 802.11a, channel 36..64 */
219 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
220 /* IEEE 802.11a, channel 100..165 */
221 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0),
222#ifdef WL_6G_BAND
223 REG_RULE(6015-80, 6975+80, 160, 6, 20, 0),
224 REG_RULE(5945-10, 7105+10, 20, 6, 20, 0),
225 REG_RULE(5955-20, 7075+20, 40, 6, 20, 0),
226 REG_RULE(5975-40, 7015+40, 80, 6, 20, 0),
227#endif /* WL_6G_BAND */
228 }
229};
230#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
231 4 && __GNUC_MINOR__ >= 6))
232_Pragma("GCC diagnostic pop")
233#endif
234
235#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
236 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
237static const struct ieee80211_iface_limit common_if_limits[] = {
238 {
239 /*
240 * Driver can support up to 2 AP's
241 */
242 .max = 2,
243 .types = BIT(NL80211_IFTYPE_AP),
244 },
245 {
246 /*
247 * During P2P-GO removal, P2P-GO is first changed to STA and later only
248 * removed. So setting maximum possible number of STA interfaces according
249 * to kernel version.
250 *
251 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
252 * linux-3.8 and above - max:4
253 * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
254 * for NAN defined, registering it as STA type)
255 */
256#ifdef WL_ENABLE_P2P_IF
257 .max = 5,
258#else
259 .max = 4,
260#endif /* WL_ENABLE_P2P_IF */
261 .types = BIT(NL80211_IFTYPE_STATION),
262 },
263 {
264 .max = 2,
265 .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
266 },
267#if defined(WL_CFG80211_P2P_DEV_IF)
268 {
269 .max = 1,
270 .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
271 },
272#endif /* WL_CFG80211_P2P_DEV_IF */
273 {
274 .max = 1,
275 .types = BIT(NL80211_IFTYPE_ADHOC),
276 },
277};
278
279#define NUM_DIFF_CHANNELS 2
280
281static const struct ieee80211_iface_combination
282common_iface_combinations[] = {
283 {
284 .num_different_channels = NUM_DIFF_CHANNELS,
285 /*
286 * At Max 5 network interfaces can be registered concurrently
287 */
288 .max_interfaces = IFACE_MAX_CNT,
289 .limits = common_if_limits,
290 .n_limits = ARRAY_SIZE(common_if_limits),
291 },
292};
293#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
294
295static const char *wl_if_state_strs[WL_IF_STATE_MAX + 1] = {
296 "WL_IF_CREATE_REQ",
297 "WL_IF_CREATE_DONE",
298 "WL_IF_DELETE_REQ",
299 "WL_IF_DELETE_DONE",
300 "WL_IF_CHANGE_REQ",
301 "WL_IF_CHANGE_DONE",
302 "WL_IF_STATE_MAX"
303};
304
305#ifdef BCMWAPI_WPI
306#if defined(ANDROID_PLATFORM_VERSION) && (ANDROID_PLATFORM_VERSION >= 8)
307/* WAPI define in ieee80211.h is used */
308#else
309#undef WLAN_AKM_SUITE_WAPI_PSK
310#define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04
311
312#undef WLAN_AKM_SUITE_WAPI_CERT
313#define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12
314
315#undef NL80211_WAPI_VERSION_1
316#define NL80211_WAPI_VERSION_1 1 << 2
317#endif /* ANDROID_PLATFORM_VERSION && ANDROID_PLATFORM_VERSION >= 8 */
318#endif /* BCMWAPI_WPI */
319
320/* Data Element Definitions */
321#define WPS_ID_CONFIG_METHODS 0x1008
322#define WPS_ID_REQ_TYPE 0x103A
323#define WPS_ID_DEVICE_NAME 0x1011
324#define WPS_ID_VERSION 0x104A
325#define WPS_ID_DEVICE_PWD_ID 0x1012
326#define WPS_ID_REQ_DEV_TYPE 0x106A
327#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
328#define WPS_ID_PRIM_DEV_TYPE 0x1054
329
330/* Device Password ID */
331#define DEV_PW_DEFAULT 0x0000
332#define DEV_PW_USER_SPECIFIED 0x0001,
333#define DEV_PW_MACHINE_SPECIFIED 0x0002
334#define DEV_PW_REKEY 0x0003
335#define DEV_PW_PUSHBUTTON 0x0004
336#define DEV_PW_REGISTRAR_SPECIFIED 0x0005
337
338/* Config Methods */
339#define WPS_CONFIG_USBA 0x0001
340#define WPS_CONFIG_ETHERNET 0x0002
341#define WPS_CONFIG_LABEL 0x0004
342#define WPS_CONFIG_DISPLAY 0x0008
343#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
344#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
345#define WPS_CONFIG_NFC_INTERFACE 0x0040
346#define WPS_CONFIG_PUSHBUTTON 0x0080
347#define WPS_CONFIG_KEYPAD 0x0100
348#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
349#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
350#define WPS_CONFIG_VIRT_DISPLAY 0x2008
351#define WPS_CONFIG_PHY_DISPLAY 0x4008
352
353#define PM_BLOCK 1
354#define PM_ENABLE 0
355
356#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
357#define IS_REGDOM_SELF_MANAGED(wiphy) \
358 (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
359#else
360#define IS_REGDOM_SELF_MANAGED(wiphy) (false)
361#endif /* KERNEL >= 4.0 */
362
363#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) && defined(WL_SELF_MANAGED_REGDOM)
364#define WL_UPDATE_CUSTOM_REGULATORY(wiphy) \
365 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
366#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
367#define WL_UPDATE_CUSTOM_REGULATORY(wiphy) \
368 wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
369#else /* kernel > 4.0 && WL_SELF_MANAGED_REGDOM */
370/* Kernels < 3.14 */
371#define WL_UPDATE_CUSTOM_REGULATORY(wiphy) \
372 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
373#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
374
375/* GCMP crypto supported above kernel v4.0 */
376#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0))
377#define WL_GCMP
378#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0) */
379
380#ifndef IBSS_COALESCE_ALLOWED
381#define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT
382#endif
383
384#ifndef IBSS_INITIAL_SCAN_ALLOWED
385#define IBSS_INITIAL_SCAN_ALLOWED IBSS_INITIAL_SCAN_ALLOWED_DEFAULT
386#endif
387
388#define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
389
390#ifdef WBTEXT
391typedef struct wl_wbtext_bssid {
392 struct ether_addr ea;
393 struct list_head list;
394} wl_wbtext_bssid_t;
395
396static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev);
397static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
398static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
399static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg);
400static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
401 struct wl_profile *profile);
402static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
403 struct wl_profile *profile);
404static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev);
405static int wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len);
406#endif /* WBTEXT */
407
408#ifdef RTT_SUPPORT
409static s32 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
410 const wl_event_msg_t *e, void *data);
411#endif /* RTT_SUPPORT */
412#ifdef WL_CHAN_UTIL
413static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg,
414 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
415static s32 wl_cfg80211_start_bssload_report(struct net_device *ndev);
416#endif /* WL_CHAN_UTIL */
417
418#ifdef SUPPORT_AP_RADIO_PWRSAVE
419#define RADIO_PWRSAVE_PPS 10
420#define RADIO_PWRSAVE_QUIET_TIME 10
421#define RADIO_PWRSAVE_LEVEL 3
422#define RADIO_PWRSAVE_STAS_ASSOC_CHECK 0
423
424#define RADIO_PWRSAVE_LEVEL_MIN 1
425#define RADIO_PWRSAVE_LEVEL_MAX 9
426#define RADIO_PWRSAVE_PPS_MIN 1
427#define RADIO_PWRSAVE_QUIETTIME_MIN 1
428#define RADIO_PWRSAVE_ASSOCCHECK_MIN 0
429#define RADIO_PWRSAVE_ASSOCCHECK_MAX 1
430
431#define RADIO_PWRSAVE_MAJOR_VER 1
432#define RADIO_PWRSAVE_MINOR_VER 1
433#define RADIO_PWRSAVE_MAJOR_VER_SHIFT 8
434#define RADIO_PWRSAVE_VERSION \
435 ((RADIO_PWRSAVE_MAJOR_VER << RADIO_PWRSAVE_MAJOR_VER_SHIFT)| RADIO_PWRSAVE_MINOR_VER)
436#endif /* SUPPORT_AP_RADIO_PWRSAVE */
437
438/* SoftAP related parameters */
439#define DEFAULT_2G_SOFTAP_CHANNEL 1
440#define DEFAULT_2G_SOFTAP_CHANSPEC 0x1006
441#define DEFAULT_5G_SOFTAP_CHANNEL 149
442#define WL_MAX_NUM_CSA_COUNTERS 255
443
444#define MAX_VNDR_OUI_STR_LEN 256u
445#define VNDR_OUI_STR_LEN 10u
446#define DOT11_DISCONNECT_RC 2u
447static const uchar *exclude_vndr_oui_list[] = {
448 "\x00\x50\xf2", /* Microsoft */
449 "\x00\x00\xf0", /* Samsung Elec */
450 WFA_OUI, /* WFA */
451 NULL
452};
453
454typedef struct wl_vndr_oui_entry {
455 uchar oui[DOT11_OUI_LEN];
456 struct list_head list;
457} wl_vndr_oui_entry_t;
458
459#ifdef WL_ANALYTICS
460static const uchar disco_bcnloss_vsie[] = {
461 0xdd, /* Vendor specific */
462 0x09, /* Length */
463 0x00, 0x00, 0xF0, /* OUI */
464 0x22, /* VENDOR_ENTERPRISE_STA_OUI_TYPE */
465 0x03, /* Sub type for additional rc */
466 0x01, /* Version */
467 0x02, /* Length */
468 0x07, 0x00 /* Reason code for BCN loss */
469};
470#endif /* WL_ANALYTICS */
471
472#define WL_HE_FEATURES_HE_AP 0x8
473#define WL_HE_FEATURES_HE_P2P 0x20
474
475static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
476 struct net_device *ndev, char *vndr_oui, u32 vndr_oui_len);
477static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg);
478#ifdef WL_ANALYTICS
479static bool wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211 *cfg,
480 struct net_device *ndev, const char *vndr_oui);
481#endif
482static s32 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
483 struct parsed_vndr_ies *vndr_ies);
484static bool wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t *vndrie);
485#if defined(WL_FW_OCE_AP_SELECT)
486static bool
487wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
488
489/* Check whether the given IE looks like WFA OCE IE. */
490#define wl_cfgoce_is_oce_ie(ie, tlvs, len) wl_cfgoce_has_ie(ie, tlvs, len, \
491 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_MBO_OCE)
492
493/* Is any of the tlvs the expected entry? If
494 * not update the tlvs buffer pointer/length.
495 */
496static bool
497wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
498{
499 /* If the contents match the OUI and the type */
500 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
501 !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
502 type == ie[TLV_BODY_OFF + oui_len]) {
503 return TRUE;
504 }
505
506 return FALSE;
507}
508#endif /* WL_FW_OCE_AP_SELECT */
509
510/*
511 * cfg80211_ops api/callback list
512 */
513static s32 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
514 const struct ether_addr *da, const struct ether_addr *sa,
515 const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody);
516static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
517#ifdef WLAIBSS_MCHAN
518static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name);
519static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
520#endif /* WLAIBSS_MCHAN */
521static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
522 struct cfg80211_ibss_params *params);
523static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
524 struct net_device *dev);
525#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
526static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
527 struct net_device *dev, const u8 *mac,
528 struct station_info *sinfo);
529#else
530static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
531 struct net_device *dev, u8 *mac,
532 struct station_info *sinfo);
533#endif
534static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
535 struct net_device *dev, bool enabled,
536 s32 timeout);
537static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
538 struct cfg80211_connect_params *sme);
539#if defined(WL_FILS)
540static int wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
541 struct cfg80211_connect_params *sme, u32 changed);
542#endif /* WL_FILS */
543static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
544 u16 reason_code);
545#if defined(WL_CFG80211_P2P_DEV_IF)
546static s32
547wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
548 enum nl80211_tx_power_setting type, s32 mbm);
549#else
550static s32
551wl_cfg80211_set_tx_power(struct wiphy *wiphy,
552 enum nl80211_tx_power_setting type, s32 dbm);
553#endif /* WL_CFG80211_P2P_DEV_IF */
554#if defined(WL_CFG80211_P2P_DEV_IF)
555static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
556 struct wireless_dev *wdev, s32 *dbm);
557#else
558static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
559#endif /* WL_CFG80211_P2P_DEV_IF */
560static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
561 struct net_device *dev,
562 u8 key_idx, bool unicast, bool multicast);
563static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
564 u8 key_idx, bool pairwise, const u8 *mac_addr,
565 struct key_params *params);
566static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
567 u8 key_idx, bool pairwise, const u8 *mac_addr);
568static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
569 u8 key_idx, bool pairwise, const u8 *mac_addr,
570 void *cookie, void (*callback) (void *cookie,
571 struct key_params *params));
572static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
573 struct net_device *dev, u8 key_idx);
574#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
575 2, 0))
576static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
577 bcm_struct_cfgdev *cfgdev, u64 cookie);
578#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
579static s32 wl_cfg80211_del_station(
580 struct wiphy *wiphy, struct net_device *ndev,
581 struct station_del_parameters *params);
582#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
583static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
584 struct net_device *ndev, const u8* mac_addr);
585#else
586static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
587 struct net_device *ndev, u8* mac_addr);
588#endif
589#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
590static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
591 struct net_device *dev, const u8 *mac, struct station_parameters *params);
592#else
593static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
594 struct net_device *dev, u8 *mac, struct station_parameters *params);
595#endif
596#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
597static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
598 struct cfg80211_pmksa *pmksa);
599static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
600 struct cfg80211_pmksa *pmksa);
601static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
602 struct net_device *dev);
603#ifdef WL_CLIENT_SAE
604static bool wl_is_pmkid_available(struct net_device *dev, const u8 *bssid);
605#endif /* WL_CLIENT_SAE */
606static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
607 struct cfg80211_pmksa *pmksa, bool set);
608#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
609#if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
610 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
611static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
612 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
613 u32 peer_capability, const u8 *buf, size_t len);
614#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
615 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
616static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
617 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
618 u32 peer_capability, const u8 *buf, size_t len);
619#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
620static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
621 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
622 u32 peer_capability, bool initiator, const u8 *buf, size_t len);
623#else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
624static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
625 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
626 const u8 *buf, size_t len);
627#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
628#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
629static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
630 const u8 *peer, enum nl80211_tdls_operation oper);
631#else
632static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
633 u8 *peer, enum nl80211_tdls_operation oper);
634#endif
635#endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
636static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg, struct net_device *dev);
637
638struct wireless_dev *
639wl_cfg80211_create_iface(struct wiphy *wiphy, wl_iftype_t
640 iface_type, u8 *mac_addr, const char *name);
641s32
642wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
643
644s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
645 struct net_device *ndev, s32 bsscfg_idx,
646 wl_iftype_t iftype, s32 del, u8 *addr);
647s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
648 struct net_device *ndev, s32 bsscfg_idx,
649 wl_iftype_t brcm_iftype, s32 del, u8 *addr);
650#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
651static s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev);
652#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */
653#ifdef GTK_OFFLOAD_SUPPORT
654#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
655static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
656 struct cfg80211_gtk_rekey_data *data);
657#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
658#endif /* GTK_OFFLOAD_SUPPORT */
659chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
660chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
661static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev);
662#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
663int wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
664 struct cfg80211_csa_settings *params);
665#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
666
667#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
668static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
669 const struct cfg80211_pmk_conf *conf);
670static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
671 const u8 *aa);
672#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
673
674/*
675 * event & event Q handlers for cfg80211 interfaces
676 */
677static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
678static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
679static void wl_event_handler(struct work_struct *work_data);
680static void wl_init_eq(struct bcm_cfg80211 *cfg);
681static void wl_flush_eq(struct bcm_cfg80211 *cfg);
682static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
683static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
684static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
685static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
686static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
687static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
688 const wl_event_msg_t *msg, void *data);
689static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e);
690static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
691 const wl_event_msg_t *e, void *data);
692static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
693 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
694static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
695 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
696static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
697 const wl_event_msg_t *e, void *data, bool completed);
698static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
699 const wl_event_msg_t *e, void *data);
700static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
701 const wl_event_msg_t *e, void *data);
702#ifdef BT_WIFI_HANDOVER
703static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
704 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
705#endif /* BT_WIFI_HANDOVER */
706#ifdef GSCAN_SUPPORT
707static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
708 const wl_event_msg_t *e, void *data);
709#endif /* GSCAN_SUPPORT */
710#ifdef RSSI_MONITOR_SUPPORT
711static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
712 const wl_event_msg_t *e, void *data);
713#endif /* RSSI_MONITOR_SUPPORT */
714static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
715 enum wl_status state, bool set);
716#ifdef CUSTOM_EVENT_PM_WAKE
717static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
718 const wl_event_msg_t *e, void *data);
719#endif /* CUSTOM_EVENT_PM_WAKE */
720#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
721static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
722 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
723#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
724#ifdef DHD_LOSSLESS_ROAMING
725static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
726#endif /* DHD_LOSSLESS_ROAMING */
727
728#ifdef WL_MBO
729static s32
730wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
731 const wl_event_msg_t *e, void *data);
732#endif /* WL_MBO */
733
734#ifdef WL_CLIENT_SAE
735static s32 wl_notify_connect_status_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
736 const wl_event_msg_t *e, void *data);
737static s32 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
738 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
739static s32 wl_cfg80211_external_auth(struct wiphy *wiphy,
740 struct net_device *dev, struct cfg80211_external_auth_params *ext_auth);
741#endif /* WL_CLIENT_SAE */
742
743/*
744 * register/deregister parent device
745 */
746static void wl_cfg80211_clear_parent_dev(void);
747/*
748 * ioctl utilites
749 */
750
751/*
752 * cfg80211 set_wiphy_params utilities
753 */
754static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
755static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
756static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
757
758/*
759 * cfg profile utilities
760 */
761static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
762 const wl_event_msg_t *e, const void *data, s32 item);
763static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
764
765/*
766 * cfg80211 connect utilites
767 */
768static s32 wl_set_wpa_version(struct net_device *dev,
769 struct cfg80211_connect_params *sme);
770static s32 wl_set_auth_type(struct net_device *dev,
771 struct cfg80211_connect_params *sme);
772static s32 wl_set_set_cipher(struct net_device *dev,
773 struct cfg80211_connect_params *sme);
774static s32 wl_set_key_mgmt(struct net_device *dev,
775 struct cfg80211_connect_params *sme);
776static s32 wl_set_set_sharedkey(struct net_device *dev,
777 struct cfg80211_connect_params *sme);
778#ifdef WL_FILS
779static s32 wl_set_fils_params(struct net_device *dev,
780 struct cfg80211_connect_params *sme);
781#endif
782
783#ifdef BCMWAPI_WPI
784static s32 wl_set_set_wapi_ie(struct net_device *dev,
785 struct cfg80211_connect_params *sme);
786#endif
787
788#ifdef WL_GCMP
789static s32 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask);
790#endif /* WL_GCMP */
791static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
792void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
793
794/*
795 * information element utilities
796 */
797static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
798
799#ifdef MFP
800static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie, const u8** rsn_cap);
801#endif
802
803static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, dhd_pub_t *data);
804static void wl_free_wdev(struct bcm_cfg80211 *cfg);
805#ifdef CONFIG_CFG80211_INTERNAL_REGDB
806#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
807static int
808#else
809static void
810#endif /* kernel version < 3.10.11 */
811wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
812#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
813
814static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool update_ssid);
815static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
816static void wl_cfg80211_work_handler(struct work_struct *work);
817static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
818 u8 key_idx, const u8 *mac_addr,
819 struct key_params *params);
820/*
821 * key indianess swap utilities
822 */
823static void swap_key_from_BE(struct wl_wsec_key *key);
824static void swap_key_to_BE(struct wl_wsec_key *key);
825
826/*
827 * bcm_cfg80211 memory init/deinit utilities
828 */
829static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
830static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
831
832static void wl_delay(u32 ms);
833
834/*
835 * ibss mode utilities
836 */
837static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev);
838static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
839
840/*
841 * link up/down , default configuration utilities
842 */
843static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
844static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
845static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
846
847static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
848 struct net_device *ndev);
849static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
850static void wl_link_up(struct bcm_cfg80211 *cfg);
851static void wl_link_down(struct bcm_cfg80211 *cfg);
852static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype);
853static void wl_init_conf(struct wl_conf *conf);
854int wl_cfg80211_get_ioctl_version(void);
855
856/*
857 * find most significant bit set
858 */
859static __used u32 wl_find_msb(u16 bit16);
860
861/*
862 * rfkill support
863 */
864static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
865static int wl_rfkill_set(void *data, bool blocked);
866#ifdef DEBUGFS_CFG80211
867static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg);
868static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg);
869#endif
870static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
871
872#ifdef WL_CFG80211_ACL
873/* ACL */
874static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
875 const struct cfg80211_acl_data *acl);
876#endif /* WL_CFG80211_ACL */
877
878/*
879 * Some external functions, TODO: move them to dhd_linux.h
880 */
881int dhd_add_monitor(const char *name, struct net_device **new_ndev);
882int dhd_del_monitor(struct net_device *ndev);
883int dhd_monitor_init(void *dhd_pub);
884int dhd_monitor_uninit(void);
885int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
886
887#ifdef ROAM_CHANNEL_CACHE
888int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
889#endif /* ROAM_CHANNEL_CACHE */
890
891#ifdef P2P_LISTEN_OFFLOADING
892s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
893#endif /* P2P_LISTEN_OFFLOADING */
894
895#ifdef CUSTOMER_HW4_DEBUG
896extern bool wl_scan_timeout_dbg_enabled;
897#endif /* CUSTOMER_HW4_DEBUG */
898#ifdef PKT_FILTER_SUPPORT
899extern uint dhd_pkt_filter_enable;
900extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
901#endif /* PKT_FILTER_SUPPORT */
902
903#ifdef SUPPORT_SET_CAC
904static void wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable);
905#endif /* SUPPORT_SET_CAC */
906
907static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
908 const struct ether_addr *bssid);
909static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
910
911#ifdef WL_WPS_SYNC
912static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg);
913static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg);
914static void wl_wps_reauth_timeout(unsigned long data);
915static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg);
916static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev);
917static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *peer_mac);
918static void wl_wps_session_del(struct net_device *ndev);
919static s32 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac);
920static void wl_wps_handle_ifdel(struct net_device *ndev);
921#endif /* WL_WPS_SYNC */
922
923#if defined(WL_FW_OCE_AP_SELECT)
924bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint);
925#endif /* WL_FW_OCE_AP_SELECT */
926
927#ifdef WL_BCNRECV
928static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
929 const wl_event_msg_t *e, void *data);
930#endif /* WL_BCNRECV */
931
932#ifdef WL_CAC_TS
933static s32 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
934 const wl_event_msg_t *e, void *data);
935#endif /* WL_CAC_TS */
936
937#if defined(WL_MBO) || defined(WL_OCE)
938static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
939 const wl_event_msg_t *e, void *data);
940#endif /* WL_MBO || WL_OCE */
941
942static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ,
943 WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ };
944
945#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || (defined(CONFIG_ARCH_MSM) && \
946 defined(CFG80211_DISCONNECTED_V2))
947#define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
948 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
949 IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
950#else
951#define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
952 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
953 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
954#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
955
956#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
957#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
958 defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || defined(WL_FILS) || \
959 defined(CONFIG_CFG80211_FILS_BKPORT)
960#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
961 resp_ie_len, status, gfp) \
962 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
963 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
964#else
965#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
966 resp_ie_len, status, gfp) \
967 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
968 resp_ie_len, status, gfp);
969#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
970 * (CFG80211_CONNECT_TIMEOUT_REASON_CODE) ||
971 * WL_FILS || CONFIG_CFG80211_FILS_BKPORT
972 */
973#elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
974/* There are customer kernels with backported changes for
975 * connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
976 * is available for kernels < 4.7 in such cases.
977 */
978#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
979 resp_ie_len, status, gfp) \
980 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
981 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
982#else
983/* Kernels < 4.7 doesn't support cfg80211_connect_bss */
984#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
985 resp_ie_len, status, gfp) \
986 cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
987 resp_ie_len, status, gfp);
988#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
989
990#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
991 (akm) == RSN_AKM_UNSPECIFIED || \
992 (akm) == RSN_AKM_PSK)
993
994extern int dhd_wait_pend8021x(struct net_device *dev);
995#ifdef PROP_TXSTATUS_VSDB
996extern int disable_proptx;
997#endif /* PROP_TXSTATUS_VSDB */
998
999/* WAR: disable pm_bcnrx , scan_ps for BCM4354 WISOL module.
1000* WISOL module have ANT_1 Rx sensitivity issue.
1001*/
1002#if defined(FORCE_DISABLE_SINGLECORE_SCAN)
1003extern void dhd_force_disable_singlcore_scan(dhd_pub_t *dhd);
1004#endif /* FORCE_DISABLE_SINGLECORE_SCAN */
1005
1006static s32
1007wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1008 const wl_event_msg_t *e, void *data);
1009static s32
1010wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1011 const wl_event_msg_t *e, void *data);
1012static int
1013wl_get_bandwidth_cap(struct net_device *ndev, uint32 band, uint32 *bandwidth);
1014#ifdef SUPPORT_AP_BWCTRL
1015static void
1016wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg, struct net_device *ndev, chanspec_t chanspec);
1017static void
1018wl_restore_ap_bw(struct bcm_cfg80211 *cfg);
1019#endif /* SUPPORT_AP_BWCTRL */
1020
1021#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \
1022 0)))
1023struct chan_info {
1024 int freq;
1025 int chan_type;
1026};
1027#endif
1028
1029#define CH_TO_CHSPC(band, _channel) \
1030 ((_channel | band) | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE)
1031#define CHAN2G(_channel, _freq, _flags) { \
1032 .band = IEEE80211_BAND_2GHZ, \
1033 .center_freq = (_freq), \
1034 .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_2G, _channel), \
1035 .flags = (_flags), \
1036 .max_antenna_gain = 0, \
1037 .max_power = 30, \
1038}
1039
1040#define CHAN5G(_channel, _flags) { \
1041 .band = IEEE80211_BAND_5GHZ, \
1042 .center_freq = 5000 + (5 * (_channel)), \
1043 .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_5G, _channel), \
1044 .flags = (_flags), \
1045 .max_antenna_gain = 0, \
1046 .max_power = 30, \
1047}
1048
1049#ifdef WL_6G_BAND
1050#define CHAN6G(_channel, _flags) { \
1051 .band = IEEE80211_BAND_5GHZ, \
1052 .center_freq = 5940 + (5 * (_channel)), \
1053 .hw_value = CH_TO_CHSPC(WL_CHANSPEC_BAND_6G, _channel), \
1054 .flags = (_flags), \
1055 .max_antenna_gain = 0, \
1056 .max_power = 30, \
1057}
1058#endif /* WL_6G_BAND */
1059
1060#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
1061#define RATETAB_ENT(_rateid, _flags) \
1062 { \
1063 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
1064 .hw_value = (_rateid), \
1065 .flags = (_flags), \
1066 }
1067
1068static struct ieee80211_rate __wl_rates[] = {
1069 RATETAB_ENT(DOT11_RATE_1M, 0),
1070 RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
1071 RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
1072 RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
1073 RATETAB_ENT(DOT11_RATE_6M, 0),
1074 RATETAB_ENT(DOT11_RATE_9M, 0),
1075 RATETAB_ENT(DOT11_RATE_12M, 0),
1076 RATETAB_ENT(DOT11_RATE_18M, 0),
1077 RATETAB_ENT(DOT11_RATE_24M, 0),
1078 RATETAB_ENT(DOT11_RATE_36M, 0),
1079 RATETAB_ENT(DOT11_RATE_48M, 0),
1080 RATETAB_ENT(DOT11_RATE_54M, 0)
1081};
1082
1083#define wl_a_rates (__wl_rates + 4)
1084#define wl_a_rates_size 8
1085#define wl_g_rates (__wl_rates + 0)
1086#define wl_g_rates_size 12
1087
1088static struct ieee80211_channel __wl_2ghz_channels[] = {
1089 CHAN2G(1, 2412, 0),
1090 CHAN2G(2, 2417, 0),
1091 CHAN2G(3, 2422, 0),
1092 CHAN2G(4, 2427, 0),
1093 CHAN2G(5, 2432, 0),
1094 CHAN2G(6, 2437, 0),
1095 CHAN2G(7, 2442, 0),
1096 CHAN2G(8, 2447, 0),
1097 CHAN2G(9, 2452, 0),
1098 CHAN2G(10, 2457, 0),
1099 CHAN2G(11, 2462, 0),
1100 CHAN2G(12, 2467, 0),
1101 CHAN2G(13, 2472, 0),
1102 CHAN2G(14, 2484, 0)
1103};
1104
1105static struct ieee80211_channel __wl_5ghz_a_channels[] = {
1106 CHAN5G(34, 0), CHAN5G(36, 0),
1107 CHAN5G(38, 0), CHAN5G(40, 0),
1108 CHAN5G(42, 0), CHAN5G(44, 0),
1109 CHAN5G(46, 0), CHAN5G(48, 0),
1110 CHAN5G(52, 0), CHAN5G(56, 0),
1111 CHAN5G(60, 0), CHAN5G(64, 0),
1112 CHAN5G(100, 0), CHAN5G(104, 0),
1113 CHAN5G(108, 0), CHAN5G(112, 0),
1114 CHAN5G(116, 0), CHAN5G(120, 0),
1115 CHAN5G(124, 0), CHAN5G(128, 0),
1116 CHAN5G(132, 0), CHAN5G(136, 0),
1117 CHAN5G(140, 0), CHAN5G(144, 0),
1118 CHAN5G(149, 0), CHAN5G(153, 0),
1119 CHAN5G(157, 0), CHAN5G(161, 0),
1120 CHAN5G(165, 0),
1121#ifdef WL_6G_BAND
1122 /* 6GHz frequency starting 5945 */
1123 CHAN6G(1, 0), CHAN6G(5, 0), CHAN6G(9, 0),
1124 CHAN6G(13, 0), CHAN6G(17, 0),
1125 CHAN6G(21, 0), CHAN6G(25, 0),
1126 CHAN6G(29, 0), CHAN6G(33, 0),
1127 CHAN6G(37, 0), CHAN6G(41, 0),
1128 CHAN6G(45, 0), CHAN6G(49, 0),
1129 CHAN6G(53, 0), CHAN6G(57, 0),
1130 CHAN6G(61, 0), CHAN6G(65, 0),
1131 CHAN6G(69, 0), CHAN6G(73, 0),
1132 CHAN6G(77, 0), CHAN6G(81, 0),
1133 CHAN6G(85, 0), CHAN6G(89, 0),
1134 CHAN6G(93, 0), CHAN6G(97, 0),
1135 CHAN6G(101, 0), CHAN6G(105, 0),
1136 CHAN6G(109, 0), CHAN6G(113, 0),
1137 CHAN6G(117, 0), CHAN6G(121, 0),
1138 CHAN6G(125, 0), CHAN6G(129, 0),
1139 CHAN6G(133, 0), CHAN6G(137, 0),
1140 CHAN6G(141, 0), CHAN6G(145, 0),
1141 CHAN6G(149, 0), CHAN6G(153, 0),
1142 CHAN6G(157, 0), CHAN6G(161, 0),
1143 CHAN6G(165, 0), CHAN6G(169, 0),
1144 CHAN6G(173, 0), CHAN6G(177, 0),
1145 CHAN6G(181, 0), CHAN6G(185, 0),
1146 CHAN6G(189, 0), CHAN6G(193, 0),
1147 CHAN6G(197, 0), CHAN6G(201, 0),
1148 CHAN6G(205, 0), CHAN6G(209, 0),
1149 CHAN6G(213, 0), CHAN6G(217, 0),
1150 CHAN6G(221, 0), CHAN6G(225, 0),
1151 CHAN6G(229, 0), CHAN6G(233, 0),
1152
1153 CHAN6G(3, 0), CHAN6G(11, 0),
1154 CHAN6G(19, 0), CHAN6G(27, 0),
1155 CHAN6G(35, 0), CHAN6G(43, 0),
1156 CHAN6G(51, 0), CHAN6G(59, 0),
1157 CHAN6G(67, 0), CHAN6G(75, 0),
1158 CHAN6G(83, 0), CHAN6G(91, 0),
1159 CHAN6G(99, 0), CHAN6G(107, 0),
1160 CHAN6G(115, 0), CHAN6G(123, 0),
1161 CHAN6G(131, 0), CHAN6G(139, 0),
1162 CHAN6G(147, 0), CHAN6G(155, 0),
1163 CHAN6G(163, 0), CHAN6G(171, 0),
1164 CHAN6G(179, 0), CHAN6G(187, 0),
1165 CHAN6G(195, 0), CHAN6G(203, 0),
1166 CHAN6G(211, 0), CHAN6G(219, 0), CHAN6G(227, 0),
1167
1168 CHAN6G(7, 0), CHAN6G(23, 0),
1169 CHAN6G(39, 0), CHAN6G(55, 0),
1170 CHAN6G(71, 0), CHAN6G(87, 0),
1171 CHAN6G(103, 0), CHAN6G(119, 0),
1172 CHAN6G(135, 0), CHAN6G(151, 0),
1173 CHAN6G(167, 0), CHAN6G(183, 0),
1174 CHAN6G(199, 0), CHAN6G(215, 0),
1175
1176 CHAN6G(15, 0), CHAN6G(47, 0),
1177 CHAN6G(79, 0), CHAN6G(111, 0),
1178 CHAN6G(143, 0), CHAN6G(175, 0), CHAN6G(207, 0),
1179#endif /* WL_6G_BAND */
1180};
1181
1182static struct ieee80211_supported_band __wl_band_2ghz = {
1183 .band = IEEE80211_BAND_2GHZ,
1184 .channels = __wl_2ghz_channels,
1185 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
1186 .bitrates = wl_g_rates,
1187 .n_bitrates = wl_g_rates_size
1188};
1189
1190static struct ieee80211_supported_band __wl_band_5ghz_a = {
1191 .band = IEEE80211_BAND_5GHZ,
1192 .channels = __wl_5ghz_a_channels,
1193 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
1194 .bitrates = wl_a_rates,
1195 .n_bitrates = wl_a_rates_size
1196};
1197
1198static const u32 __wl_cipher_suites[] = {
1199 WLAN_CIPHER_SUITE_WEP40,
1200 WLAN_CIPHER_SUITE_WEP104,
1201 WLAN_CIPHER_SUITE_TKIP,
1202 WLAN_CIPHER_SUITE_CCMP,
1203#ifdef MFP
1204 /*
1205 * Advertising AES_CMAC cipher suite to userspace would imply that we
1206 * are supporting MFP. So advertise only when MFP support is enabled.
1207 */
1208 WLAN_CIPHER_SUITE_AES_CMAC,
1209#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1210 WLAN_CIPHER_SUITE_BIP_GMAC_256,
1211 WLAN_CIPHER_SUITE_BIP_GMAC_128,
1212 WLAN_CIPHER_SUITE_BIP_CMAC_256,
1213#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1214#endif /* MFP */
1215
1216#ifdef BCMWAPI_WPI
1217 WLAN_CIPHER_SUITE_SMS4,
1218#endif
1219
1220#if defined(WLAN_CIPHER_SUITE_PMK)
1221 WLAN_CIPHER_SUITE_PMK,
1222#endif /* WLAN_CIPHER_SUITE_PMK */
1223#ifdef WL_GCMP
1224 WLAN_CIPHER_SUITE_GCMP,
1225 WLAN_CIPHER_SUITE_GCMP_256,
1226 WLAN_CIPHER_SUITE_BIP_GMAC_128,
1227 WLAN_CIPHER_SUITE_BIP_GMAC_256,
1228#endif /* WL_GCMP */
1229};
1230
1231#ifdef WL_SUPPORT_ACS
1232/*
1233 * The firmware code required for this feature to work is currently under
1234 * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1235 * required firmware code out of the BCMINTERNAL flag.
1236 */
1237struct wl_dump_survey {
1238 u32 obss;
1239 u32 ibss;
1240 u32 no_ctg;
1241 u32 no_pckt;
1242 u32 tx;
1243 u32 idle;
1244};
1245#endif /* WL_SUPPORT_ACS */
1246
1247#ifdef WL_CFG80211_GON_COLLISION
1248#define BLOCK_GON_REQ_MAX_NUM 5
1249#endif /* WL_CFG80211_GON_COLLISION */
1250
1251#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1252static int maxrxpktglom = 0;
1253#endif
1254
1255/* IOCtl version read from targeted driver */
1256int ioctl_version;
1257#ifdef DEBUGFS_CFG80211
1258#define SUBLOGLEVEL 20
1259#define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1))
1260static const struct {
1261 u32 log_level;
1262 char *sublogname;
1263} sublogname_map[] = {
1264 {WL_DBG_ERR, "ERR"},
1265 {WL_DBG_INFO, "INFO"},
1266 {WL_DBG_DBG, "DBG"},
1267 {WL_DBG_SCAN, "SCAN"},
1268 {WL_DBG_TRACE, "TRACE"},
1269 {WL_DBG_P2P_ACTION, "P2PACTION"}
1270};
1271#endif
1272
1273typedef struct rsn_cipher_algo_entry {
1274 u32 cipher_suite;
1275 u32 wsec_algo;
1276 u32 wsec_key_algo;
1277} rsn_cipher_algo_entry_t;
1278
1279static const rsn_cipher_algo_entry_t rsn_cipher_algo_lookup_tbl[] = {
1280 {WLAN_CIPHER_SUITE_WEP40, WEP_ENABLED, CRYPTO_ALGO_WEP1},
1281 {WLAN_CIPHER_SUITE_WEP104, WEP_ENABLED, CRYPTO_ALGO_WEP128},
1282 {WLAN_CIPHER_SUITE_TKIP, TKIP_ENABLED, CRYPTO_ALGO_TKIP},
1283 {WLAN_CIPHER_SUITE_CCMP, AES_ENABLED, CRYPTO_ALGO_AES_CCM},
1284 {WLAN_CIPHER_SUITE_AES_CMAC, AES_ENABLED, CRYPTO_ALGO_BIP},
1285
1286#ifdef BCMWAPI_WPI
1287 {WLAN_CIPHER_SUITE_SMS4, SMS4_ENABLED, CRYPTO_ALGO_SMS4},
1288#endif /* BCMWAPI_WPI */
1289
1290#ifdef WL_GCMP
1291 {WLAN_CIPHER_SUITE_GCMP, AES_ENABLED, CRYPTO_ALGO_AES_GCM},
1292 {WLAN_CIPHER_SUITE_GCMP_256, AES_ENABLED, CRYPTO_ALGO_AES_GCM256},
1293 {WLAN_CIPHER_SUITE_BIP_GMAC_128, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC},
1294 {WLAN_CIPHER_SUITE_BIP_GMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC256},
1295#endif /* WL_GCMP */
1296#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1297 {WLAN_CIPHER_SUITE_BIP_CMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_CMAC256},
1298#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1299};
1300
1301typedef struct rsn_akm_wpa_auth_entry {
1302 u32 akm_suite;
1303 u32 wpa_auth;
1304} rsn_akm_wpa_auth_entry_t;
1305
1306static const rsn_akm_wpa_auth_entry_t rsn_akm_wpa_auth_lookup_tbl[] = {
1307#ifdef WL_OWE
1308 {WLAN_AKM_SUITE_OWE, WPA3_AUTH_OWE},
1309#endif /* WL_OWE */
1310 {WLAN_AKM_SUITE_8021X, WPA2_AUTH_UNSPECIFIED},
1311 {WL_AKM_SUITE_SHA256_1X, WPA2_AUTH_1X_SHA256},
1312 {WL_AKM_SUITE_SHA256_PSK, WPA2_AUTH_PSK_SHA256},
1313 {WLAN_AKM_SUITE_PSK, WPA2_AUTH_PSK},
1314 {WLAN_AKM_SUITE_FT_8021X, WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT},
1315 {WLAN_AKM_SUITE_FT_PSK, WPA2_AUTH_PSK | WPA2_AUTH_FT},
1316 {WLAN_AKM_SUITE_FILS_SHA256, WPA2_AUTH_FILS_SHA256},
1317 {WLAN_AKM_SUITE_FILS_SHA384, WPA2_AUTH_FILS_SHA384},
1318 {WLAN_AKM_SUITE_8021X_SUITE_B, WPA3_AUTH_1X_SUITE_B_SHA256},
1319 {WLAN_AKM_SUITE_8021X_SUITE_B_192, WPA3_AUTH_1X_SUITE_B_SHA384},
1320
1321#ifdef BCMWAPI_WPI
1322 {WLAN_AKM_SUITE_WAPI_CERT, WAPI_AUTH_UNSPECIFIED},
1323 {WLAN_AKM_SUITE_WAPI_PSK, WAPI_AUTH_PSK},
1324#endif /* BCMWAPI_WPI */
1325
1326#if defined(WL_SAE) || defined(WL_CLIENT_SAE)
1327 {WLAN_AKM_SUITE_SAE, WPA3_AUTH_SAE_PSK},
1328#endif /* WL_SAE || WL_CLIENT_SAE */
1329#ifdef WL_SAE_FT
1330 {WLAN_AKM_SUITE_FT_OVER_SAE, WPA3_AUTH_SAE_PSK | WPA2_AUTH_FT},
1331#endif /* WL_SAE_FT */
1332 {WLAN_AKM_SUITE_DPP, WPA3_AUTH_DPP_AKM},
1333 {WLAN_AKM_SUITE_FT_8021X_SHA384, WPA3_AUTH_1X_SUITE_B_SHA384 | WPA2_AUTH_FT}
1334};
1335
1336#define BUFSZ 8
1337#define BUFSZN BUFSZ + 1
1338
1339#define _S(x) #x
1340#define S(x) _S(x)
1341
1342#define SOFT_AP_IF_NAME "swlan0"
1343
1344/* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1345uint32 fw_assoc_watchdog_ms = 0;
1346bool fw_assoc_watchdog_started = 0;
1347#define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1348
1349int wl_channel_to_frequency(u32 chan, chanspec_band_t band)
1350{
1351 if (chan == 0) {
1352 return 0; /* not supported */
1353 }
1354 switch (band) {
1355 case WL_CHANSPEC_BAND_2G:
1356 if (chan == 14)
1357 return 2484;
1358 else if (chan < 14)
1359 return 2407 + chan * 5;
1360 break;
1361 case WL_CHANSPEC_BAND_5G:
1362 if (chan >= 182 && chan <= 196)
1363 return 4000 + chan * 5;
1364 else
1365 return 5000 + chan * 5;
1366 break;
1367#ifdef WL_6G_BAND
1368 case WL_CHANSPEC_BAND_6G:
1369 return 5940 + chan * 5;
1370 break;
1371#endif /* WL_6G_BAND */
1372 default:
1373 WL_ERR(("Invalid Frequency Band\n"));
1374 }
1375 return 0; /* not supported */
1376}
1377
1378static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg,
1379 enum wl_pm_workq_act_type type)
1380{
1381 u16 wq_duration = 0;
1382
1383 dhd_pub_t *dhd = NULL;
1384
1385 if (cfg == NULL)
1386 return;
1387
1388 dhd = (dhd_pub_t *)(cfg->pub);
1389
1390 mutex_lock(&cfg->pm_sync);
1391 /*
1392 * Make cancel and schedule work part mutually exclusive
1393 * so that while cancelling, we are sure that there is no
1394 * work getting scheduled.
1395 */
1396 if (delayed_work_pending(&cfg->pm_enable_work)) {
1397 cancel_delayed_work(&cfg->pm_enable_work);
1398
1399 DHD_PM_WAKE_UNLOCK(cfg->pub);
1400
1401 }
1402
1403 if (type == WL_PM_WORKQ_SHORT) {
1404 wq_duration = WL_PM_ENABLE_TIMEOUT;
1405 } else if (type == WL_PM_WORKQ_LONG) {
1406 wq_duration = (WL_PM_ENABLE_TIMEOUT*2);
1407 }
1408
1409 /* It should schedule work item only if driver is up */
1410
1411 if (wq_duration && dhd->up) {
1412
1413 if (schedule_delayed_work(&cfg->pm_enable_work,
1414 msecs_to_jiffies((const unsigned int)wq_duration))) {
1415
1416 DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub, wq_duration);
1417
1418 } else {
1419 WL_ERR(("Can't schedule pm work handler\n"));
1420 }
1421 }
1422 mutex_unlock(&cfg->pm_sync);
1423}
1424
1425/* Return a new chanspec given a legacy chanspec
1426 * Returns INVCHANSPEC on error
1427 */
1428chanspec_t
1429wl_chspec_from_legacy(chanspec_t legacy_chspec)
1430{
1431 chanspec_t chspec;
1432
1433 /* get the channel number */
1434 chspec = LCHSPEC_CHANNEL(legacy_chspec);
1435
1436 /* convert the band */
1437 if (LCHSPEC_IS2G(legacy_chspec)) {
1438 chspec |= WL_CHANSPEC_BAND_2G;
1439 } else {
1440 chspec |= WL_CHANSPEC_BAND_5G;
1441 }
1442
1443 /* convert the bw and sideband */
1444 if (LCHSPEC_IS20(legacy_chspec)) {
1445 chspec |= WL_CHANSPEC_BW_20;
1446 } else {
1447 chspec |= WL_CHANSPEC_BW_40;
1448 if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
1449 chspec |= WL_CHANSPEC_CTL_SB_L;
1450 } else {
1451 chspec |= WL_CHANSPEC_CTL_SB_U;
1452 }
1453 }
1454
1455 if (wf_chspec_malformed(chspec)) {
1456 WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1457 chspec));
1458 return INVCHANSPEC;
1459 }
1460
1461 return chspec;
1462}
1463
1464/* Return a legacy chanspec given a new chanspec
1465 * Returns INVCHANSPEC on error
1466 */
1467static chanspec_t
1468wl_chspec_to_legacy(chanspec_t chspec)
1469{
1470 chanspec_t lchspec;
1471
1472 if (wf_chspec_malformed(chspec)) {
1473 WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1474 chspec));
1475 return INVCHANSPEC;
1476 }
1477
1478 /* get the channel number */
1479 lchspec = CHSPEC_CHANNEL(chspec);
1480
1481 /* convert the band */
1482 if (CHSPEC_IS2G(chspec)) {
1483 lchspec |= WL_LCHANSPEC_BAND_2G;
1484 } else {
1485 lchspec |= WL_LCHANSPEC_BAND_5G;
1486 }
1487
1488 /* convert the bw and sideband */
1489 if (CHSPEC_IS20(chspec)) {
1490 lchspec |= WL_LCHANSPEC_BW_20;
1491 lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
1492 } else if (CHSPEC_IS40(chspec)) {
1493 lchspec |= WL_LCHANSPEC_BW_40;
1494 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
1495 lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
1496 } else {
1497 lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
1498 }
1499 } else {
1500 /* cannot express the bandwidth */
1501 char chanbuf[CHANSPEC_STR_LEN];
1502 WL_ERR((
1503 "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1504 "to pre-11ac format\n",
1505 wf_chspec_ntoa(chspec, chanbuf), chspec));
1506 return INVCHANSPEC;
1507 }
1508
1509 return lchspec;
1510}
1511
1512bool wl_cfg80211_is_hal_started(struct bcm_cfg80211 *cfg)
1513{
1514 return cfg->hal_started;
1515}
1516
1517/* given a chanspec value, do the endian and chanspec version conversion to
1518 * a chanspec_t value
1519 * Returns INVCHANSPEC on error
1520 */
1521chanspec_t
1522wl_chspec_host_to_driver(chanspec_t chanspec)
1523{
1524 if (ioctl_version == 1) {
1525 chanspec = wl_chspec_to_legacy(chanspec);
1526 if (chanspec == INVCHANSPEC) {
1527 return chanspec;
1528 }
1529 }
1530 chanspec = htodchanspec(chanspec);
1531
1532 return chanspec;
1533}
1534
1535/* given a channel value, do the endian and chanspec version conversion to
1536 * a chanspec_t value
1537 * Returns INVCHANSPEC on error
1538 */
1539chanspec_t
1540wl_ch_host_to_driver(u16 channel)
1541{
1542 chanspec_t chanspec;
1543 chanspec_band_t band;
1544
1545 band = WL_CHANNEL_BAND(channel);
1546
1547 chanspec = wf_create_20MHz_chspec(channel, band);
1548 if (chanspec == INVCHANSPEC) {
1549 return chanspec;
1550 }
1551
1552 return wl_chspec_host_to_driver(chanspec);
1553}
1554
1555/* given a chanspec value from the driver, do the endian and chanspec version conversion to
1556 * a chanspec_t value
1557 * Returns INVCHANSPEC on error
1558 */
1559chanspec_t
1560wl_chspec_driver_to_host(chanspec_t chanspec)
1561{
1562 chanspec = dtohchanspec(chanspec);
1563 if (ioctl_version == 1) {
1564 chanspec = wl_chspec_from_legacy(chanspec);
1565 }
1566
1567 return chanspec;
1568}
1569
1570/*
1571 * convert ASCII string to MAC address (colon-delimited format)
1572 * eg: 00:11:22:33:44:55
1573 */
1574int
1575wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
1576{
1577 char *c = NULL;
1578 int count = 0;
1579
1580 bzero(n, ETHER_ADDR_LEN);
1581 for (;;) {
1582 n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
1583 if (!*c++ || count == ETHER_ADDR_LEN)
1584 break;
1585 a = c;
1586 }
1587 return (count == ETHER_ADDR_LEN);
1588}
1589
1590/* There isn't a lot of sense in it, but you can transmit anything you like */
1591static const struct ieee80211_txrx_stypes
1592wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1593#ifdef WLMESH_CFG80211
1594 [NL80211_IFTYPE_MESH_POINT] = {
1595 .tx = 0xffff,
1596 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1597 BIT(IEEE80211_STYPE_AUTH >> 4)
1598 },
1599#endif /* WLMESH_CFG80211 */
1600 [NL80211_IFTYPE_ADHOC] = {
1601 .tx = 0xffff,
1602 .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
1603 },
1604 [NL80211_IFTYPE_STATION] = {
1605 .tx = 0xffff,
1606 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1607 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1608#ifdef WL_CLIENT_SAE
1609 | BIT(IEEE80211_STYPE_AUTH >> 4)
1610#endif /* WL_CLIENT_SAE */
1611 },
1612 [NL80211_IFTYPE_AP] = {
1613 .tx = 0xffff,
1614 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1615 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1616 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1617 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1618 BIT(IEEE80211_STYPE_AUTH >> 4) |
1619 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1620 BIT(IEEE80211_STYPE_ACTION >> 4)
1621 },
1622 [NL80211_IFTYPE_AP_VLAN] = {
1623 /* copy AP */
1624 .tx = 0xffff,
1625 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1626 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1627 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1628 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1629 BIT(IEEE80211_STYPE_AUTH >> 4) |
1630 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1631 BIT(IEEE80211_STYPE_ACTION >> 4)
1632 },
1633 [NL80211_IFTYPE_P2P_CLIENT] = {
1634 .tx = 0xffff,
1635 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1636 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1637 },
1638 [NL80211_IFTYPE_P2P_GO] = {
1639 .tx = 0xffff,
1640 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1641 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1642 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1643 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1644 BIT(IEEE80211_STYPE_AUTH >> 4) |
1645 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1646 BIT(IEEE80211_STYPE_ACTION >> 4)
1647 },
1648#if defined(WL_CFG80211_P2P_DEV_IF)
1649 [NL80211_IFTYPE_P2P_DEVICE] = {
1650 .tx = 0xffff,
1651 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1652 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1653 },
1654#endif /* WL_CFG80211_P2P_DEV_IF */
1655};
1656
1657static void swap_key_from_BE(struct wl_wsec_key *key)
1658{
1659 key->index = htod32(key->index);
1660 key->len = htod32(key->len);
1661 key->algo = htod32(key->algo);
1662 key->flags = htod32(key->flags);
1663 key->rxiv.hi = htod32(key->rxiv.hi);
1664 key->rxiv.lo = htod16(key->rxiv.lo);
1665 key->iv_initialized = htod32(key->iv_initialized);
1666}
1667
1668static void swap_key_to_BE(struct wl_wsec_key *key)
1669{
1670 key->index = dtoh32(key->index);
1671 key->len = dtoh32(key->len);
1672 key->algo = dtoh32(key->algo);
1673 key->flags = dtoh32(key->flags);
1674 key->rxiv.hi = dtoh32(key->rxiv.hi);
1675 key->rxiv.lo = dtoh16(key->rxiv.lo);
1676 key->iv_initialized = dtoh32(key->iv_initialized);
1677}
1678
1679#if defined(WL_FW_OCE_AP_SELECT)
1680bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint)
1681{
1682 const u8 *parse = NULL;
1683 bcm_tlv_t *ie;
1684 const struct cfg80211_bss_ies *ies;
1685 u32 len;
1686 struct cfg80211_bss *bss;
1687
1688 bss = CFG80211_GET_BSS(wiphy, NULL, bssid_hint, 0, 0);
1689 if (!bss) {
1690 WL_ERR(("Unable to find AP in the cache"));
1691 return false;
1692 }
1693
1694 if (rcu_access_pointer(bss->ies)) {
1695 ies = rcu_access_pointer(bss->ies);
1696 parse = ies->data;
1697 len = ies->len;
1698 } else {
1699 WL_ERR(("ies is NULL"));
1700 return false;
1701 }
1702
1703 while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_VS_ID))) {
1704 if (wl_cfgoce_is_oce_ie((const uint8*)ie, (u8 const **)&parse, &len) == TRUE) {
1705 return true;
1706 } else {
1707 ie = bcm_next_tlv((const bcm_tlv_t*) ie, &len);
1708 if (!ie) {
1709 return false;
1710 }
1711 parse = (uint8 *)ie;
1712 WL_DBG(("NON OCE IE. next ie ptr:%p", parse));
1713 }
1714 }
1715 WL_DBG(("OCE IE NOT found"));
1716 return false;
1717}
1718#endif /* WL_FW_OCE_AP_SELECT */
1719
1720/* Dump the contents of the encoded wps ie buffer and get pbc value */
1721static void
1722wl_validate_wps_ie(const char *wps_ie, s32 wps_ie_len, bool *pbc)
1723{
1724 #define WPS_IE_FIXED_LEN 6
1725 s16 len;
1726 const u8 *subel = NULL;
1727 u16 subelt_id;
1728 u16 subelt_len;
1729 u16 val;
1730 u8 *valptr = (uint8*) &val;
1731 if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
1732 WL_ERR(("invalid argument : NULL\n"));
1733 return;
1734 }
1735 len = (s16)wps_ie[TLV_LEN_OFF];
1736
1737 if (len > wps_ie_len) {
1738 WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
1739 return;
1740 }
1741 WL_DBG(("wps_ie len=%d\n", len));
1742 len -= 4; /* for the WPS IE's OUI, oui_type fields */
1743 subel = wps_ie + WPS_IE_FIXED_LEN;
1744 while (len >= 4) { /* must have attr id, attr len fields */
1745 valptr[0] = *subel++;
1746 valptr[1] = *subel++;
1747 subelt_id = HTON16(val);
1748
1749 valptr[0] = *subel++;
1750 valptr[1] = *subel++;
1751 subelt_len = HTON16(val);
1752
1753 len -= 4; /* for the attr id, attr len fields */
1754 len -= (s16)subelt_len; /* for the remaining fields in this attribute */
1755 if (len < 0) {
1756 break;
1757 }
1758 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
1759 subel, subelt_id, subelt_len));
1760
1761 if (subelt_id == WPS_ID_VERSION) {
1762 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
1763 } else if (subelt_id == WPS_ID_REQ_TYPE) {
1764 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
1765 } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
1766 valptr[0] = *subel;
1767 valptr[1] = *(subel + 1);
1768 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
1769 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
1770 char devname[33];
1771 int namelen = MIN(subelt_len, (sizeof(devname) - 1));
1772
1773 if (namelen) {
1774 memcpy(devname, subel, namelen);
1775 devname[namelen] = '\0';
1776 /* Printing len as rx'ed in the IE */
1777 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1778 devname, subelt_len));
1779 }
1780 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
1781 valptr[0] = *subel;
1782 valptr[1] = *(subel + 1);
1783 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
1784 *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
1785 } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
1786 valptr[0] = *subel;
1787 valptr[1] = *(subel + 1);
1788 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
1789 valptr[0] = *(subel + 6);
1790 valptr[1] = *(subel + 7);
1791 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
1792 } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
1793 valptr[0] = *subel;
1794 valptr[1] = *(subel + 1);
1795 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
1796 valptr[0] = *(subel + 6);
1797 valptr[1] = *(subel + 7);
1798 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
1799 } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
1800 valptr[0] = *subel;
1801 valptr[1] = *(subel + 1);
1802 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1803 ": cat=%u\n", HTON16(val)));
1804 } else {
1805 WL_DBG((" unknown attr 0x%x\n", subelt_id));
1806 }
1807
1808 subel += subelt_len;
1809 }
1810}
1811
1812s32 wl_set_tx_power(struct net_device *dev,
1813 enum nl80211_tx_power_setting type, s32 dbm)
1814{
1815 s32 err = 0;
1816 s32 disable = 0;
1817 s32 txpwrqdbm;
1818 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1819
1820 /* Make sure radio is off or on as far as software is concerned */
1821 disable = WL_RADIO_SW_DISABLE << 16;
1822 disable = htod32(disable);
1823 err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable));
1824 if (unlikely(err)) {
1825 WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
1826 return err;
1827 }
1828
1829 if (dbm > 0xffff)
1830 dbm = 0xffff;
1831 txpwrqdbm = dbm * 4;
1832#ifdef SUPPORT_WL_TXPOWER
1833 if (type == NL80211_TX_POWER_AUTOMATIC)
1834 txpwrqdbm = 127;
1835 else
1836 txpwrqdbm |= WL_TXPWR_OVERRIDE;
1837#endif /* SUPPORT_WL_TXPOWER */
1838 err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
1839 sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
1840 &cfg->ioctl_buf_sync);
1841 if (unlikely(err))
1842 WL_ERR(("qtxpower error (%d)\n", err));
1843 else
1844 WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
1845
1846 return err;
1847}
1848
1849s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
1850{
1851 s32 err = 0;
1852 s32 txpwrdbm;
1853 char ioctl_buf[WLC_IOCTL_SMLEN];
1854
1855 err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
1856 NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
1857 if (unlikely(err)) {
1858 WL_ERR(("error (%d)\n", err));
1859 return err;
1860 }
1861
1862 memcpy(&txpwrdbm, ioctl_buf, sizeof(txpwrdbm));
1863 txpwrdbm = dtoh32(txpwrdbm);
1864 *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
1865
1866 WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
1867
1868 return err;
1869}
1870
1871static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
1872{
1873 chanspec_t chspec;
1874 int cur_band, err = 0;
1875 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1876 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
1877 struct ether_addr bssid;
1878 wl_bss_info_t *bss = NULL;
1879 u16 channel = WL_P2P_TEMP_CHAN;
1880 char *buf;
1881
1882 bzero(&bssid, sizeof(bssid));
1883 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) {
1884 /* STA interface is not associated. So start the new interface on a temp
1885 * channel . Later proper channel will be applied by the above framework
1886 * via set_channel (cfg80211 API).
1887 */
1888 WL_DBG(("Not associated. Return a temp channel. \n"));
1889 cur_band = 0;
1890 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(int));
1891 if (unlikely(err)) {
1892 WL_ERR(("Get band failed\n"));
1893 } else if (cur_band == WLC_BAND_5G || cur_band == WLC_BAND_6G) {
1894 channel = WL_P2P_TEMP_CHAN_5G;
1895 }
1896 return wl_ch_host_to_driver(channel);
1897 }
1898
1899 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
1900 if (!buf) {
1901 WL_ERR(("buf alloc failed. use temp channel\n"));
1902 return wl_ch_host_to_driver(channel);
1903 }
1904
1905 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1906 if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf,
1907 WL_EXTRA_BUF_MAX))) {
1908 WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1909 chspec = wl_ch_host_to_driver(channel);
1910 }
1911 else {
1912 bss = (wl_bss_info_t *) (buf + 4);
1913 chspec = bss->chanspec;
1914#ifdef WL_6G_BAND
1915 /* Avoid p2p bring up in 6G based on bssinfo */
1916 if (CHSPEC_IS6G(chspec)) {
1917 channel = WL_P2P_TEMP_CHAN_5G;
1918 chspec = wl_ch_host_to_driver(channel);
1919 }
1920#endif /* WL_6G_BAND */
1921 WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
1922 }
1923
1924 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
1925 return chspec;
1926}
1927
1928static void
1929wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable)
1930{
1931#ifdef PROP_TXSTATUS_VSDB
1932#if defined(BCMSDIO) || defined(BCMDBUS)
1933 bool wlfc_enabled = FALSE;
1934 s32 err, up =1;
1935 dhd_pub_t *dhd;
1936 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1937
1938 dhd = (dhd_pub_t *)(cfg->pub);
1939 if (!dhd) {
1940 return;
1941 }
1942
1943 if (enable) {
1944 if (!cfg->wlfc_on && !disable_proptx) {
1945 dhd_wlfc_get_enable(dhd, &wlfc_enabled);
1946 if (!wlfc_enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1947 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1948 dhd_wlfc_init(dhd);
1949 err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32));
1950 if (err < 0)
1951 WL_ERR(("WLC_UP return err:%d\n", err));
1952 }
1953 cfg->wlfc_on = true;
1954 WL_DBG(("wlfc_on:%d \n", cfg->wlfc_on));
1955 }
1956 } else if (dhd->conf->disable_proptx != 0){
1957 dhd_wlfc_deinit(dhd);
1958 cfg->wlfc_on = false;
1959 }
1960#endif /* BCMSDIO || BCMDBUS */
1961#endif /* PROP_TXSTATUS_VSDB */
1962}
1963
1964struct wireless_dev *
1965wl_cfg80211_p2p_if_add(struct bcm_cfg80211 *cfg,
1966 wl_iftype_t wl_iftype,
1967 char const *name, u8 *mac_addr, s32 *ret_err)
1968{
1969 u16 chspec;
1970 s16 cfg_type;
1971 long timeout;
1972 s32 err;
1973 u16 p2p_iftype;
1974 int dhd_mode;
1975 struct net_device *new_ndev = NULL;
1976 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
1977 struct ether_addr *p2p_addr;
1978
1979 *ret_err = BCME_OK;
1980 if (!cfg->p2p) {
1981 WL_ERR(("p2p not initialized\n"));
1982 return NULL;
1983 }
1984
1985#if defined(WL_CFG80211_P2P_DEV_IF)
1986 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
1987 /* Handle Dedicated P2P discovery Interface */
1988 return wl_cfgp2p_add_p2p_disc_if(cfg);
1989 }
1990#endif /* WL_CFG80211_P2P_DEV_IF */
1991
1992 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1993 p2p_iftype = WL_P2P_IF_GO;
1994 } else {
1995 p2p_iftype = WL_P2P_IF_CLIENT;
1996 }
1997
1998 /* Dual p2p doesn't support multiple P2PGO interfaces,
1999 * p2p_go_count is the counter for GO creation
2000 * requests.
2001 */
2002 if ((cfg->p2p->p2p_go_count > 0) && (wl_iftype == WL_IF_TYPE_P2P_GO)) {
2003 WL_ERR(("FW does not support multiple GO\n"));
2004 *ret_err = -ENOTSUPP;
2005 return NULL;
2006 }
2007 if (!cfg->p2p->on) {
2008 p2p_on(cfg) = true;
2009 wl_cfgp2p_set_firm_p2p(cfg);
2010 wl_cfgp2p_init_discovery(cfg);
2011 }
2012
2013 strlcpy(cfg->p2p->vir_ifname, name, sizeof(cfg->p2p->vir_ifname));
2014 /* In concurrency case, STA may be already associated in a particular channel.
2015 * so retrieve the current channel of primary interface and then start the virtual
2016 * interface on that.
2017 */
2018 chspec = wl_cfg80211_get_shared_freq(wiphy);
2019
2020 /* For P2P mode, use P2P-specific driver features to create the
2021 * bss: "cfg p2p_ifadd"
2022 */
2023 wl_set_p2p_status(cfg, IF_ADDING);
2024 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
2025 cfg_type = wl_cfgp2p_get_conn_idx(cfg);
2026 if (cfg_type == BCME_ERROR) {
2027 wl_clr_p2p_status(cfg, IF_ADDING);
2028 WL_ERR(("Failed to get connection idx for p2p interface\n"));
2029 return NULL;
2030 }
2031
2032 p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
2033 memcpy(p2p_addr->octet, mac_addr, ETH_ALEN);
2034
2035 err = wl_cfgp2p_ifadd(cfg, p2p_addr,
2036 htod32(p2p_iftype), chspec);
2037 if (unlikely(err)) {
2038 wl_clr_p2p_status(cfg, IF_ADDING);
2039 WL_ERR((" virtual iface add failed (%d) \n", err));
2040 return NULL;
2041 }
2042
2043 /* Wait for WLC_E_IF event with IF_ADD opcode */
2044 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2045 ((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
2046 (cfg->if_event_info.valid)),
2047 msecs_to_jiffies(MAX_WAIT_TIME));
2048 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
2049 wl_if_event_info *event = &cfg->if_event_info;
2050 new_ndev = wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg), event,
2051 event->mac, cfg->p2p->vir_ifname, false);
2052 if (unlikely(!new_ndev)) {
2053 goto fail;
2054 }
2055
2056 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
2057 cfg->p2p->p2p_go_count++;
2058 }
2059 /* Fill p2p specific data */
2060 wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
2061 wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
2062
2063 WL_ERR((" virtual interface(%s) is "
2064 "created net attach done\n", cfg->p2p->vir_ifname));
2065 dhd_mode = (wl_iftype == WL_IF_TYPE_P2P_GC) ?
2066 DHD_FLAG_P2P_GC_MODE : DHD_FLAG_P2P_GO_MODE;
2067 DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
2068 /* reinitialize completion to clear previous count */
2069#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
2070 INIT_COMPLETION(cfg->iface_disable);
2071#else
2072 init_completion(&cfg->iface_disable);
2073#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
2074
2075 return new_ndev->ieee80211_ptr;
2076 }
2077
2078fail:
2079 return NULL;
2080}
2081
2082bool
2083wl_cfg80211_check_vif_in_use(struct net_device *ndev)
2084{
2085 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2086 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2087 bool nan_enabled = FALSE;
2088
2089#ifdef WL_NAN
2090 nan_enabled = wl_cfgnan_is_enabled(cfg);
2091#endif /* WL_NAN */
2092
2093 if (nan_enabled || (wl_cfgp2p_vif_created(cfg)) ||
2094 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
2095 WL_MEM(("%s: Virtual interfaces in use. NAN %d P2P %d softAP %d\n",
2096 __FUNCTION__, nan_enabled, wl_cfgp2p_vif_created(cfg),
2097 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)));
2098 return TRUE;
2099 }
2100
2101 return FALSE;
2102}
2103
2104void
2105wl_cfg80211_iface_state_ops(struct wireless_dev *wdev,
2106 wl_interface_state_t state,
2107 wl_iftype_t wl_iftype, u16 wl_mode)
2108{
2109 struct net_device *ndev;
2110 struct bcm_cfg80211 *cfg;
2111 dhd_pub_t *dhd;
2112 s32 bssidx;
2113
2114 WL_DBG(("state:%s wl_iftype:%d mode:%d\n",
2115 wl_if_state_strs[state], wl_iftype, wl_mode));
2116 if (!wdev) {
2117 WL_ERR(("wdev null\n"));
2118 return;
2119 }
2120
2121 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_NAN_NMI)) {
2122 /* P2P discovery is a netless device and uses a
2123 * hidden bsscfg interface in fw. Don't apply the
2124 * iface ops state changes for p2p discovery I/F.
2125 * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
2126 * Don't apply iface ops state changes for NMI I/F.
2127 */
2128 return;
2129 }
2130
2131 cfg = wiphy_priv(wdev->wiphy);
2132 ndev = wdev->netdev;
2133 dhd = (dhd_pub_t *)(cfg->pub);
2134
2135 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2136 if (!ndev || (bssidx < 0)) {
2137 WL_ERR(("ndev null. skip iface state ops\n"));
2138 return;
2139 }
2140
2141 switch (state) {
2142 case WL_IF_CREATE_REQ:
2143#ifdef WL_BCNRECV
2144 /* check fakeapscan in progress then abort */
2145 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
2146#endif /* WL_BCNRECV */
2147 wl_cfg80211_scan_abort(cfg);
2148 wl_wlfc_enable(cfg, true);
2149#ifdef WLTDLS
2150 /* disable TDLS if number of connected interfaces is >= 1 */
2151 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_CREATE, false);
2152#endif /* WLTDLS */
2153 break;
2154 case WL_IF_DELETE_REQ:
2155#ifdef WL_WPS_SYNC
2156 wl_wps_handle_ifdel(ndev);
2157#endif /* WPS_SYNC */
2158 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
2159 /* Send completion for any pending scans */
2160 wl_cfg80211_cancel_scan(cfg);
2161 }
2162
2163#ifdef CUSTOM_SET_CPUCORE
2164 dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
2165 if (!(dhd->chan_isvht80)) {
2166 dhd_set_cpucore(dhd, FALSE);
2167 }
2168#endif /* CUSTOM_SET_CPUCORE */
2169 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
2170 break;
2171 case WL_IF_CREATE_DONE:
2172 if (wl_mode == WL_MODE_BSS) {
2173 /* Common code for sta type interfaces - STA, GC */
2174 /* Enable firmware key buffering before sent 4-way M4 */
2175 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2176 }
2177 if (wl_iftype == WL_IF_TYPE_P2P_GC) {
2178 /* Disable firmware roaming for P2P interface */
2179 wldev_iovar_setint(ndev, "roam_off", 1);
2180 wldev_iovar_setint(ndev, "bcn_timeout", dhd->conf->bcn_timeout);
2181 {
2182 int assoc_retry = 3;
2183#if defined(CUSTOM_ASSOC_RETRY_MAX)
2184 assoc_retry = CUSTOM_ASSOC_RETRY_MAX;
2185#endif /* CUSTOM_ASSOC_RETRY_MAX */
2186 /* set retry_max to CUSTOM_ASSOC_RETRY_MAX(3) */
2187 wldev_iovar_setint(ndev, "assoc_retry_max", assoc_retry);
2188 }
2189 }
2190 if (wl_mode == WL_MODE_AP) {
2191 /* Common code for AP/GO */
2192 }
2193 break;
2194 case WL_IF_DELETE_DONE:
2195#ifdef WLTDLS
2196 /* Enable back TDLS if connected interface is <= 1 */
2197 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2198#endif /* WLTDLS */
2199 wl_wlfc_enable(cfg, false);
2200 break;
2201 case WL_IF_CHANGE_REQ:
2202 /* Flush existing IEs from firmware on role change */
2203 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
2204 break;
2205 case WL_IF_CHANGE_DONE:
2206 if (wl_mode == WL_MODE_BSS) {
2207 /* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2208 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2209 }
2210 break;
2211
2212 default:
2213 WL_ERR(("Unsupported state: %d\n", state));
2214 return;
2215 }
2216}
2217
2218static s32
2219wl_cfg80211_p2p_if_del(struct wiphy *wiphy, struct wireless_dev *wdev)
2220{
2221 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2222 s16 bssidx;
2223 s16 err;
2224 s32 cfg_type;
2225 struct net_device *ndev;
2226 long timeout;
2227 struct ether_addr p2p_dev_addr = {{0}};
2228
2229 if (unlikely(!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
2230 WL_INFORM_MEM(("device is not ready\n"));
2231 return BCME_NOTFOUND;
2232 }
2233
2234#ifdef WL_CFG80211_P2P_DEV_IF
2235 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2236 /* Handle dedicated P2P discovery interface. */
2237 return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
2238 }
2239#endif /* WL_CFG80211_P2P_DEV_IF */
2240
2241 /* Handle P2P Group Interface */
2242 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2243 if (bssidx <= 0) {
2244 WL_ERR(("bssidx not found\n"));
2245 return BCME_NOTFOUND;
2246 }
2247 if (wl_cfgp2p_find_type(cfg, bssidx, &cfg_type) != BCME_OK) {
2248 /* Couldn't find matching iftype */
2249 WL_MEM(("non P2P interface\n"));
2250 return BCME_NOTFOUND;
2251 }
2252
2253 ndev = wdev->netdev;
2254 (void)memcpy_s(p2p_dev_addr.octet, ETHER_ADDR_LEN,
2255 ndev->dev_addr, ETHER_ADDR_LEN);
2256
2257 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2258 wl_clr_p2p_status(cfg, IF_ADDING);
2259
2260 /* for GO */
2261 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
2262 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
2263 cfg->p2p->p2p_go_count--;
2264 /* disable interface before bsscfg free */
2265 err = wl_cfgp2p_ifdisable(cfg, &p2p_dev_addr);
2266 /* if fw doesn't support "ifdis",
2267 do not wait for link down of ap mode
2268 */
2269 if (err == 0) {
2270 WL_ERR(("Wait for Link Down event for GO !!!\n"));
2271 wait_for_completion_timeout(&cfg->iface_disable,
2272 msecs_to_jiffies(500));
2273 } else if (err != BCME_UNSUPPORTED) {
2274 msleep(300);
2275 }
2276 } else {
2277 /* GC case */
2278 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
2279 WL_ERR(("Wait for Link Down event for GC !\n"));
2280 wait_for_completion_timeout
2281 (&cfg->iface_disable, msecs_to_jiffies(500));
2282 }
2283
2284 /* Force P2P disconnect in iface down context */
2285 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
2286 WL_INFORM_MEM(("force send disconnect event\n"));
2287 CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
2288 wl_clr_drv_status(cfg, AUTHORIZED, ndev);
2289 }
2290 }
2291
2292 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
2293 wl_set_p2p_status(cfg, IF_DELETING);
2294 DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
2295
2296 err = wl_cfgp2p_ifdel(cfg, &p2p_dev_addr);
2297 if (unlikely(err)) {
2298 WL_ERR(("P2P IFDEL operation failed, error code = %d\n", err));
2299 err = BCME_ERROR;
2300 goto fail;
2301 } else {
2302 /* Wait for WLC_E_IF event */
2303 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2304 ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
2305 (cfg->if_event_info.valid)),
2306 msecs_to_jiffies(MAX_WAIT_TIME));
2307 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
2308 cfg->if_event_info.valid) {
2309 WL_ERR(("P2P IFDEL operation done\n"));
2310 err = BCME_OK;
2311 } else {
2312 WL_ERR(("IFDEL didn't complete properly\n"));
2313 err = -EINVAL;
2314 }
2315 }
2316
2317fail:
2318 /* Even in failure case, attempt to remove the host data structure.
2319 * Firmware would be cleaned up via WiFi reset done by the
2320 * user space from hang event context (for android only).
2321 */
2322 bzero(cfg->p2p->vir_ifname, IFNAMSIZ);
2323 wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
2324 wl_to_p2p_bss_ndev(cfg, cfg_type) = NULL;
2325 wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, cfg_type));
2326 dhd_net_if_lock(ndev);
2327 if (cfg->if_event_info.ifidx) {
2328 /* Remove interface except for primary ifidx */
2329 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
2330 }
2331 dhd_net_if_unlock(ndev);
2332 return err;
2333}
2334
2335#ifdef WL_IFACE_MGMT
2336/* Get active secondary data iface type */
2337wl_iftype_t
2338wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg)
2339{
2340#ifndef WL_STATIC_IF
2341 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2342#endif /* !WL_STATIC_IF */
2343 struct net_device *p2p_ndev = NULL;
2344
2345 p2p_ndev = wl_to_p2p_bss_ndev(cfg,
2346 P2PAPI_BSSCFG_CONNECTION1);
2347
2348#ifdef WL_STATIC_IF
2349 if (IS_CFG80211_STATIC_IF_ACTIVE(cfg)) {
2350 if (IS_AP_IFACE(cfg->static_ndev->ieee80211_ptr)) {
2351 return WL_IF_TYPE_AP;
2352 }
2353 }
2354#else
2355 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
2356 return WL_IF_TYPE_AP;
2357 }
2358#endif /* WL_STATIC_IF */
2359
2360 if (p2p_ndev && p2p_ndev->ieee80211_ptr) {
2361 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
2362 return WL_IF_TYPE_P2P_GO;
2363 }
2364
2365 /* Set role to GC when cfg80211 layer downgrades P2P
2366 * role to station type while bringing down the interface
2367 */
2368 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) {
2369 WL_DBG_MEM(("%s, Change to GC base role\n", __FUNCTION__));
2370 return WL_IF_TYPE_P2P_GC;
2371 }
2372
2373 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
2374 return WL_IF_TYPE_P2P_GC;
2375 }
2376 }
2377
2378#ifdef WL_NAN
2379 if (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg))) {
2380 return WL_IF_TYPE_NAN;
2381 }
2382#endif /* WL_NAN */
2383 return WL_IFACE_NOT_PRESENT;
2384}
2385
2386/*
2387* Handle incoming data interface request based on policy.
2388* If there is any conflicting interface, that will be
2389* deleted.
2390*/
2391s32
2392wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 *cfg,
2393 wl_iftype_t new_wl_iftype)
2394{
2395 s32 ret = BCME_OK;
2396 bool del_iface = false;
2397 wl_iftype_t sec_wl_if_type = wl_cfg80211_get_sec_iface(cfg);
2398
2399 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2400 new_wl_iftype == WL_IF_TYPE_NAN) {
2401 /* Multi NDP is allowed irrespective of Policy */
2402 return BCME_OK;
2403 }
2404
2405 if (sec_wl_if_type == WL_IFACE_NOT_PRESENT) {
2406 /*
2407 * If there is no active secondary I/F, there
2408 * is no interface conflict. Do nothing.
2409 */
2410 return BCME_OK;
2411 }
2412
2413 /* Handle secondary data link case */
2414 switch (cfg->iface_data.policy) {
2415 case WL_IF_POLICY_CUSTOM:
2416 case WL_IF_POLICY_DEFAULT: {
2417 WL_INFORM_MEM(("%s, Delete any existing iface\n", __FUNCTION__));
2418 del_iface = true;
2419 break;
2420 }
2421 case WL_IF_POLICY_FCFS: {
2422 WL_INFORM_MEM(("Found active iface = %s, can't support new iface = %s\n",
2423 wl_iftype_to_str(sec_wl_if_type), wl_iftype_to_str(new_wl_iftype)));
2424 ret = BCME_ERROR;
2425 break;
2426 }
2427 case WL_IF_POLICY_LP: {
2428 WL_INFORM_MEM(("Remove active sec data interface, allow incoming iface\n"));
2429 /* Delete existing data iface and allow incoming sec iface */
2430 del_iface = true;
2431 break;
2432 }
2433 case WL_IF_POLICY_ROLE_PRIORITY: {
2434 WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2435 wl_iftype_to_str(sec_wl_if_type),
2436 cfg->iface_data.priority[sec_wl_if_type],
2437 wl_iftype_to_str(new_wl_iftype),
2438 cfg->iface_data.priority[new_wl_iftype]));
2439 if (cfg->iface_data.priority[new_wl_iftype] >
2440 cfg->iface_data.priority[sec_wl_if_type]) {
2441 del_iface = true;
2442 } else {
2443 WL_ERR(("Can't support new iface = %s\n",
2444 wl_iftype_to_str(new_wl_iftype)));
2445 ret = BCME_ERROR;
2446 }
2447 break;
2448 }
2449 default: {
2450 WL_ERR(("Unsupported interface policy = %d\n",
2451 cfg->iface_data.policy));
2452 return BCME_ERROR;
2453 }
2454 }
2455 if (del_iface) {
2456 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2457 }
2458 return ret;
2459}
2460
2461/* Handle discovery ifaces based on policy */
2462s32
2463wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 *cfg,
2464 wl_iftype_t new_wl_iftype, bool *disable_nan, bool *disable_p2p)
2465{
2466 s32 ret = BCME_OK;
2467 wl_iftype_t sec_wl_if_type =
2468 wl_cfg80211_get_sec_iface(cfg);
2469 *disable_p2p = false;
2470 *disable_nan = false;
2471
2472 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2473 new_wl_iftype == WL_IF_TYPE_NAN) {
2474 /* Multi NDP is allowed irrespective of Policy */
2475 return BCME_OK;
2476 }
2477
2478 /*
2479 * Check for any policy conflicts with active secondary
2480 * interface for incoming discovery iface
2481 */
2482 if ((sec_wl_if_type != WL_IFACE_NOT_PRESENT) &&
2483 (is_discovery_iface(new_wl_iftype))) {
2484 switch (cfg->iface_data.policy) {
2485 case WL_IF_POLICY_CUSTOM: {
2486 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2487 new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2488 WL_INFORM_MEM(("Allow P2P Discovery with active NDP\n"));
2489 /* No further checks are required. */
2490 return BCME_OK;
2491 }
2492 /*
2493 * Intentional fall through to default policy
2494 * as for AP and associated ifaces, both are same
2495 */
2496 }
2497 case WL_IF_POLICY_DEFAULT: {
2498 if (sec_wl_if_type == WL_IF_TYPE_AP) {
2499 WL_INFORM_MEM(("AP is active, cant support new iface\n"));
2500 ret = BCME_ERROR;
2501 } else if (sec_wl_if_type == WL_IF_TYPE_P2P_GC ||
2502 sec_wl_if_type == WL_IF_TYPE_P2P_GO) {
2503 if (new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2504 /*
2505 * Associated discovery case,
2506 * Fall through
2507 */
2508 } else {
2509 /* Active iface is present, returning error */
2510 WL_INFORM_MEM(("P2P group is active,"
2511 " cant support new iface\n"));
2512 ret = BCME_ERROR;
2513 }
2514 } else if (sec_wl_if_type == WL_IF_TYPE_NAN) {
2515 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2516 }
2517 break;
2518 }
2519 case WL_IF_POLICY_FCFS: {
2520 WL_INFORM_MEM(("Can't support new iface = %s\n",
2521 wl_iftype_to_str(new_wl_iftype)));
2522 ret = BCME_ERROR;
2523 break;
2524 }
2525 case WL_IF_POLICY_LP: {
2526 /* Delete existing data iface n allow incoming sec iface */
2527 WL_INFORM_MEM(("Remove active sec data interface = %s\n",
2528 wl_iftype_to_str(sec_wl_if_type)));
2529 ret = wl_cfg80211_delete_iface(cfg,
2530 sec_wl_if_type);
2531 break;
2532 }
2533 case WL_IF_POLICY_ROLE_PRIORITY: {
2534 WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2535 wl_iftype_to_str(sec_wl_if_type),
2536 cfg->iface_data.priority[sec_wl_if_type],
2537 wl_iftype_to_str(new_wl_iftype),
2538 cfg->iface_data.priority[new_wl_iftype]));
2539 if (cfg->iface_data.priority[new_wl_iftype] >
2540 cfg->iface_data.priority[sec_wl_if_type]) {
2541 WL_INFORM_MEM(("Remove active sec data iface\n"));
2542 ret = wl_cfg80211_delete_iface(cfg,
2543 sec_wl_if_type);
2544 } else {
2545 WL_ERR(("Can't support new iface = %s"
2546 " due to low priority\n",
2547 wl_iftype_to_str(new_wl_iftype)));
2548 ret = BCME_ERROR;
2549 }
2550 break;
2551 }
2552 default: {
2553 WL_ERR(("Unsupported policy\n"));
2554 return BCME_ERROR;
2555 }
2556 }
2557 } else {
2558 /*
2559 * Handle incoming new secondary iface request,
2560 * irrespective of existing discovery ifaces
2561 */
2562 if ((cfg->iface_data.policy == WL_IF_POLICY_CUSTOM) &&
2563 (new_wl_iftype == WL_IF_TYPE_NAN)) {
2564 WL_INFORM_MEM(("Allow NAN Data Path\n"));
2565 /* No further checks are required. */
2566 return BCME_OK;
2567 }
2568 }
2569
2570 /* Check for any conflicting discovery iface */
2571 switch (new_wl_iftype) {
2572 case WL_IF_TYPE_P2P_DISC:
2573 case WL_IF_TYPE_P2P_GO:
2574 case WL_IF_TYPE_P2P_GC: {
2575 *disable_nan = true;
2576 break;
2577 }
2578 case WL_IF_TYPE_NAN_NMI:
2579 case WL_IF_TYPE_NAN: {
2580 *disable_p2p = true;
2581 break;
2582 }
2583 case WL_IF_TYPE_STA:
2584 case WL_IF_TYPE_AP: {
2585 *disable_nan = true;
2586 *disable_p2p = true;
2587 break;
2588 }
2589 default: {
2590 WL_ERR(("Unsupported\n"));
2591 return BCME_ERROR;
2592 }
2593 }
2594 return ret;
2595}
2596
2597bool
2598wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 *cfg,
2599 wl_iftype_t new_wl_iftype)
2600{
2601 struct net_device *p2p_ndev = NULL;
2602 p2p_ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
2603
2604 if (new_wl_iftype == WL_IF_TYPE_P2P_DISC && p2p_ndev &&
2605 p2p_ndev->ieee80211_ptr &&
2606 is_p2p_group_iface(p2p_ndev->ieee80211_ptr)) {
2607 return true;
2608 }
2609#ifdef WL_NAN
2610 else if ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) &&
2611 (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg)))) {
2612 return true;
2613 }
2614#endif /* WL_NAN */
2615 return false;
2616}
2617
2618/* Handle incoming discovery iface request */
2619s32
2620wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 *cfg,
2621 wl_iftype_t new_wl_iftype)
2622{
2623 s32 ret = BCME_OK;
2624 bool disable_p2p = false;
2625 bool disable_nan = false;
2626
2627 wl_iftype_t active_sec_iface =
2628 wl_cfg80211_get_sec_iface(cfg);
2629
2630 if (is_discovery_iface(new_wl_iftype) &&
2631 (active_sec_iface != WL_IFACE_NOT_PRESENT)) {
2632 if (wl_cfg80211_is_associated_discovery(cfg,
2633 new_wl_iftype) == TRUE) {
2634 WL_DBG(("Associate iface request is allowed= %s\n",
2635 wl_iftype_to_str(new_wl_iftype)));
2636 return ret;
2637 }
2638 }
2639
2640 ret = wl_cfg80211_disc_if_mgmt(cfg, new_wl_iftype,
2641 &disable_nan, &disable_p2p);
2642 if (ret != BCME_OK) {
2643 WL_ERR(("Failed at disc iface mgmt, ret = %d\n", ret));
2644 return ret;
2645 }
2646
2647 if (disable_nan) {
2648#ifdef WL_NAN
2649 /* Disable nan to avoid conflict with p2p */
2650 ret = wl_cfgnan_check_nan_disable_pending(cfg, true, true);
2651 if (ret != BCME_OK) {
2652 WL_ERR(("failed to disable nan, error[%d]\n", ret));
2653 return ret;
2654 }
2655#endif /* WL_NAN */
2656 }
2657
2658 if (disable_p2p) {
2659 /* Disable p2p discovery */
2660 ret = wl_cfg80211_deinit_p2p_discovery(cfg);
2661 if (ret != BCME_OK) {
2662 /* Should we fail nan enab here */
2663 WL_ERR(("Failed to disable p2p_disc for allowing nan\n"));
2664 return ret;
2665 }
2666 }
2667 return ret;
2668}
2669
2670/*
2671* Check for any conflicting iface before adding iface.
2672* Based on policy, either conflicting iface is removed
2673* or new iface add request is blocked.
2674*/
2675s32
2676wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg,
2677 wl_iftype_t new_wl_iftype)
2678{
2679 s32 ret = BCME_OK;
2680
2681 WL_INFORM_MEM(("Incoming iface = %s\n", wl_iftype_to_str(new_wl_iftype)));
2682
2683 if (!is_discovery_iface(new_wl_iftype)) {
2684 /* Incoming data interface request */
2685 if (wl_cfg80211_get_sec_iface(cfg) != WL_IFACE_NOT_PRESENT) {
2686 /* active interface present - Apply interface data policy */
2687 ret = wl_cfg80211_data_if_mgmt(cfg, new_wl_iftype);
2688 if (ret != BCME_OK) {
2689 WL_ERR(("if_mgmt fail:%d\n", ret));
2690 return ret;
2691 }
2692 }
2693 }
2694 /* Apply discovery config */
2695 ret = wl_cfg80211_handle_discovery_config(cfg, new_wl_iftype);
2696 return ret;
2697}
2698#endif /* WL_IFACE_MGMT */
2699
2700static struct wireless_dev *
2701wl_cfg80211_add_monitor_if(struct wiphy *wiphy, const char *name)
2702{
2703#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
2704 WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2705 return ERR_PTR(-EOPNOTSUPP);
2706#else
2707 struct wireless_dev *wdev;
2708 struct net_device* ndev = NULL;
2709
2710 dhd_add_monitor(name, &ndev);
2711
2712 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2713 if (!wdev) {
2714 WL_ERR(("wireless_dev alloc failed! \n"));
2715 goto fail;
2716 }
2717
2718 wdev->wiphy = wiphy;
2719 wdev->iftype = NL80211_IFTYPE_MONITOR;
2720 ndev->ieee80211_ptr = wdev;
2721 SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
2722
2723 WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
2724 return ndev->ieee80211_ptr;
2725fail:
2726 return ERR_PTR(-EOPNOTSUPP);
2727#endif // endif
2728}
2729
2730static struct wireless_dev *
2731wl_cfg80211_add_ibss(struct wiphy *wiphy, u16 wl_iftype, char const *name)
2732{
2733#ifdef WLAIBSS_MCHAN
2734 /* AIBSS */
2735 return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
2736#else
2737 /* Normal IBSS */
2738 WL_ERR(("IBSS not supported on Virtual iface\n"));
2739 return NULL;
2740#endif
2741}
2742
2743s32
2744wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype)
2745{
2746 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2747 u16 org_toggle_bytes;
2748 u16 cur_toggle_bytes;
2749 u16 toggled_bit;
2750
2751 if (!ndev || !mac_addr || ETHER_ISNULLADDR(mac_addr)) {
2752 return -EINVAL;
2753 }
2754 WL_DBG(("%s:Mac addr" MACDBG "\n",
2755 __FUNCTION__, MAC2STRDBG(mac_addr)));
2756
2757 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_AP) ||
2758 (wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2759 /* Avoid invoking release mac addr code for interfaces using
2760 * fixed mac addr.
2761 */
2762 return BCME_OK;
2763 }
2764
2765 /* Fetch last two bytes of mac address */
2766 org_toggle_bytes = ntoh16(*((u16 *)&ndev->dev_addr[4]));
2767 cur_toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
2768
2769 toggled_bit = (org_toggle_bytes ^ cur_toggle_bytes);
2770 WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n",
2771 org_toggle_bytes, cur_toggle_bytes));
2772 if (toggled_bit & cfg->vif_macaddr_mask) {
2773 /* This toggled_bit is marked in the used mac addr
2774 * mask. Clear it.
2775 */
2776 cfg->vif_macaddr_mask &= ~toggled_bit;
2777 WL_INFORM(("MAC address - " MACDBG " released. toggled_bit:%04X vif_mask:%04X\n",
2778 MAC2STRDBG(mac_addr), toggled_bit, cfg->vif_macaddr_mask));
2779 } else {
2780 WL_ERR(("MAC address - " MACDBG " not found in the used list."
2781 " toggled_bit:%04x vif_mask:%04x\n", MAC2STRDBG(mac_addr),
2782 toggled_bit, cfg->vif_macaddr_mask));
2783 return -EINVAL;
2784 }
2785
2786 return BCME_OK;
2787}
2788
2789s32
2790wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr)
2791{
2792 struct ether_addr *p2p_dev_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE);
2793 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2794 u16 toggle_mask;
2795 u16 toggle_bit;
2796 u16 toggle_bytes;
2797 u16 used;
2798 u32 offset = 0;
2799 /* Toggle mask starts from MSB of second last byte */
2800 u16 mask = 0x8000;
2801 if (!mac_addr) {
2802 return -EINVAL;
2803 }
2804 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) && p2p_dev_addr &&
2805 ETHER_IS_LOCALADDR(p2p_dev_addr)) {
2806 /* If mac address is already generated return the mac */
2807 (void)memcpy_s(mac_addr, ETH_ALEN, p2p_dev_addr->octet, ETH_ALEN);
2808 return 0;
2809 }
2810 (void)memcpy_s(mac_addr, ETH_ALEN, ndev->perm_addr, ETH_ALEN);
2811/*
2812 * VIF MAC address managment
2813 * P2P Device addres: Primary MAC with locally admin. bit set
2814 * P2P Group address/NAN NMI/Softap/NAN DPI: Primary MAC addr
2815 * with local admin bit set and one additional bit toggled.
2816 * cfg->vif_macaddr_mask will hold the info regarding the mac address
2817 * released. Ensure to call wl_release_vif_macaddress to free up
2818 * the mac address.
2819 */
2820#if defined(SPECIFIC_MAC_GEN_SCHEME)
2821 if (wl_iftype == WL_IF_TYPE_P2P_DISC || wl_iftype == WL_IF_TYPE_AP) {
2822 mac_addr[0] |= 0x02;
2823 } else if ((wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2824 mac_addr[0] |= 0x02;
2825 mac_addr[4] ^= 0x80;
2826 }
2827#else
2828 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
2829 mac_addr[0] |= 0x02;
2830 }
2831#endif /* SEPCIFIC_MAC_GEN_SCHEME */
2832 else {
2833 /* For locally administered mac addresses, we keep the
2834 * OUI part constant and just work on the last two bytes.
2835 */
2836 mac_addr[0] |= 0x02;
2837 toggle_mask = cfg->vif_macaddr_mask;
2838 toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
2839 do {
2840 used = toggle_mask & mask;
2841 if (!used) {
2842 /* Use this bit position */
2843 toggle_bit = mask >> offset;
2844 toggle_bytes ^= toggle_bit;
2845 cfg->vif_macaddr_mask |= toggle_bit;
2846 WL_DBG(("toggle_bit:%04X toggle_bytes:%04X toggle_mask:%04X\n",
2847 toggle_bit, toggle_bytes, cfg->vif_macaddr_mask));
2848 /* Macaddress are stored in network order */
2849 mac_addr[5] = *((u8 *)&toggle_bytes);
2850 mac_addr[4] = *(((u8 *)&toggle_bytes + 1));
2851 break;
2852 }
2853
2854 /* Shift by one */
2855 toggle_mask = toggle_mask << 0x1;
2856 offset++;
2857 if (offset > MAX_VIF_OFFSET) {
2858 /* We have used up all macaddresses. Something wrong! */
2859 WL_ERR(("Entire range of macaddress used up.\n"));
2860 ASSERT(0);
2861 break;
2862 }
2863 } while (true);
2864 }
2865 WL_INFORM_MEM(("Get virtual I/F mac addr: "MACDBG"\n", MAC2STRDBG(mac_addr)));
2866 return 0;
2867}
2868#ifdef DNGL_AXI_ERROR_LOGGING
2869static s32
2870_wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg)
2871{
2872 s32 ret = BCME_OK;
2873 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2874 hnd_ext_trap_hdr_t *hdr;
2875 int axi_host_error_size;
2876 uint8 *new_dst;
2877 uint32 *ext_data = dhd->extended_trap_data;
2878 struct file *fp = NULL;
2879 char *filename = DHD_COMMON_DUMP_PATH
2880 DHD_DUMP_AXI_ERROR_FILENAME
2881 DHD_DUMP_HAL_FILENAME_SUFFIX;
2882
2883 WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename));
2884
2885 fp = filp_open(filename, O_RDONLY, 0);
2886
2887 if (IS_ERR(fp) || (fp == NULL)) {
2888 WL_ERR(("%s: Couldn't read the file, err %ld,File [%s] No previous axi error \n",
2889 __FUNCTION__, PTR_ERR(fp), filename));
2890 return ret;
2891 }
2892
2893 kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t));
2894 filp_close(fp, NULL);
2895
2896 /* Delete axi error info file */
2897 if (dhd_file_delete(filename) < 0) {
2898 WL_ERR(("%s(): Failed to delete file: %s\n", __FUNCTION__, filename));
2899 return ret;
2900 }
2901 WL_ERR(("%s(): Success to delete file: %s\n", __FUNCTION__, filename));
2902
2903 if (dhd->axi_err_dump->etd_axi_error_v1.signature != HND_EXT_TRAP_AXIERROR_SIGNATURE) {
2904 WL_ERR(("%s: Invalid AXI signature: 0x%x\n",
2905 __FUNCTION__, dhd->axi_err_dump->etd_axi_error_v1.signature));
2906 }
2907
2908 /* First word is original trap_data */
2909 ext_data++;
2910
2911 /* Followed by the extended trap data header */
2912 hdr = (hnd_ext_trap_hdr_t *)ext_data;
2913 new_dst = hdr->data;
2914
2915 axi_host_error_size = sizeof(dhd->axi_err_dump->axid)
2916 + sizeof(dhd->axi_err_dump->fault_address);
2917
2918 /* TAG_TRAP_AXI_HOST_INFO tlv : host's axid, fault address */
2919 new_dst = bcm_write_tlv(TAG_TRAP_AXI_HOST_INFO,
2920 (const void *)dhd->axi_err_dump,
2921 axi_host_error_size, new_dst);
2922
2923 /* TAG_TRAP_AXI_ERROR tlv */
2924 new_dst = bcm_write_tlv(TAG_TRAP_AXI_ERROR,
2925 (const void *)&dhd->axi_err_dump->etd_axi_error_v1,
2926 sizeof(dhd->axi_err_dump->etd_axi_error_v1), new_dst);
2927 hdr->len = new_dst - hdr->data;
2928
2929 dhd->dongle_trap_occured = TRUE;
2930#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2931 copy_hang_info_trap(dhd);
2932#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2933 memset(dhd->axi_err_dump, 0, sizeof(dhd_axi_error_dump_t));
2934
2935 dhd->hang_reason = HANG_REASON_DONGLE_TRAP;
2936 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2937 ret = BCME_ERROR;
2938 return ret;
2939}
2940#endif /* DNGL_AXI_ERROR_LOGGING */
2941
2942/* All Android/Linux private/Vendor Interface calls should make
2943 * use of below API for interface creation.
2944 */
2945struct wireless_dev *
2946wl_cfg80211_add_if(struct bcm_cfg80211 *cfg,
2947 struct net_device *primary_ndev,
2948 wl_iftype_t wl_iftype, const char *name, u8 *mac)
2949{
2950 u8 mac_addr[ETH_ALEN];
2951 s32 err = -ENODEV;
2952 struct wireless_dev *wdev = NULL;
2953 struct wiphy *wiphy;
2954 s32 wl_mode;
2955 dhd_pub_t *dhd;
2956 wl_iftype_t macaddr_iftype = wl_iftype;
2957
2958 WL_INFORM_MEM(("if name: %s, wl_iftype:%d \n",
2959 name ? name : "NULL", wl_iftype));
2960 if (!cfg || !primary_ndev || !name) {
2961 WL_ERR(("cfg/ndev/name ptr null\n"));
2962 return NULL;
2963 }
2964 if (wl_cfg80211_get_wdev_from_ifname(cfg, name)) {
2965 WL_ERR(("Interface name %s exists!\n", name));
2966 return NULL;
2967 }
2968
2969 wiphy = bcmcfg_to_wiphy(cfg);
2970 dhd = (dhd_pub_t *)(cfg->pub);
2971 if (!dhd) {
2972 return NULL;
2973 }
2974
2975 if ((wl_mode = wl_iftype_to_mode(wl_iftype)) < 0) {
2976 return NULL;
2977 }
2978 mutex_lock(&cfg->if_sync);
2979#ifdef WL_NAN
2980 if (wl_iftype == WL_IF_TYPE_NAN) {
2981 /*
2982 * Bypass the role conflict check for NDI and handle it
2983 * from dp req and dp resp context
2984 * because in aware comms, ndi gets created soon after nan enable.
2985 */
2986 } else
2987#endif /* WL_NAN */
2988#ifdef WL_IFACE_MGMT
2989 if ((err = wl_cfg80211_handle_if_role_conflict(cfg, wl_iftype)) < 0) {
2990 mutex_unlock(&cfg->if_sync);
2991 return NULL;
2992 }
2993#endif /* WL_IFACE_MGMT */
2994#ifdef DNGL_AXI_ERROR_LOGGING
2995 /* Check the previous smmu fault error */
2996 if ((err = _wl_cfg80211_check_axi_error(cfg)) < 0) {
2997 mutex_unlock(&cfg->if_sync);
2998 return NULL;
2999 }
3000#endif /* DNGL_AXI_ERROR_LOGGING */
3001 /* Protect the interace op context */
3002 /* Do pre-create ops */
3003 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CREATE_REQ,
3004 wl_iftype, wl_mode);
3005
3006 if (strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)) == 0) {
3007 macaddr_iftype = WL_IF_TYPE_AP;
3008 }
3009
3010 if (mac) {
3011 /* If mac address is provided, use that */
3012 memcpy(mac_addr, mac, ETH_ALEN);
3013 } else if ((wl_get_vif_macaddr(cfg, macaddr_iftype, mac_addr) != BCME_OK)) {
3014 /* Fetch the mac address to be used for virtual interface */
3015 err = -EINVAL;
3016 goto fail;
3017 }
3018
3019 switch (wl_iftype) {
3020 case WL_IF_TYPE_IBSS:
3021 wdev = wl_cfg80211_add_ibss(wiphy, wl_iftype, name);
3022 break;
3023 case WL_IF_TYPE_MONITOR:
3024 wdev = wl_cfg80211_add_monitor_if(wiphy, name);
3025 break;
3026 case WL_IF_TYPE_STA:
3027 case WL_IF_TYPE_AP:
3028 case WL_IF_TYPE_NAN:
3029 if (cfg->iface_cnt >= (IFACE_MAX_CNT - 1)) {
3030 WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
3031 cfg->iface_cnt));
3032 err = -ENOTSUPP;
3033 goto fail;
3034 }
3035 wdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
3036 wl_iftype, mac_addr, name);
3037 break;
3038 case WL_IF_TYPE_P2P_DISC:
3039 case WL_IF_TYPE_P2P_GO:
3040 /* Intentional fall through */
3041 case WL_IF_TYPE_P2P_GC:
3042 if (cfg->p2p_supported) {
3043 wdev = wl_cfg80211_p2p_if_add(cfg, wl_iftype,
3044 name, mac_addr, &err);
3045 break;
3046 }
3047 /* Intentionally fall through for unsupported interface
3048 * handling when firmware doesn't support p2p
3049 */
3050 default:
3051 WL_ERR(("Unsupported interface type\n"));
3052 err = -ENOTSUPP;
3053 goto fail;
3054 }
3055
3056 if (!wdev) {
3057 WL_ERR(("vif create failed. err:%d\n", err));
3058 if (err != -ENOTSUPP) {
3059 err = -ENODEV;
3060 }
3061 goto fail;
3062 }
3063
3064 /* Ensure decrementing in case of failure */
3065 cfg->vif_count++;
3066
3067 wl_cfg80211_iface_state_ops(wdev,
3068 WL_IF_CREATE_DONE, wl_iftype, wl_mode);
3069
3070 WL_INFORM_MEM(("Vif created. dev->ifindex:%d"
3071 " cfg_iftype:%d, vif_count:%d\n",
3072 (wdev->netdev ? wdev->netdev->ifindex : 0xff),
3073 wdev->iftype, cfg->vif_count));
3074 mutex_unlock(&cfg->if_sync);
3075 return wdev;
3076
3077fail:
3078 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3079 WL_IF_DELETE_REQ, wl_iftype, wl_mode);
3080
3081 if (err != -ENOTSUPP) {
3082 /* For non-supported interfaces, just return error and
3083 * skip below recovery steps.
3084 */
3085#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
3086 wl_copy_hang_info_if_falure(primary_ndev, HANG_REASON_IFACE_DEL_FAILURE, err);
3087#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
3088 SUPP_LOG(("IF_ADD fail. err:%d\n", err));
3089 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3090 if (dhd_query_bus_erros(dhd)) {
3091 goto exit;
3092 }
3093 dhd->iface_op_failed = TRUE;
3094#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
3095 if (dhd->memdump_enabled) {
3096 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3097 dhd_bus_mem_dump(dhd);
3098 }
3099#endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
3100
3101 /* If reached here, something wrong with DHD or firmware.
3102 * There could be a chance that firmware is in bad state.
3103 * Request the upper layer to do a Wi-Fi reset.
3104 */
3105 dhd->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
3106 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3107
3108 }
3109exit:
3110 mutex_unlock(&cfg->if_sync);
3111 return NULL;
3112}
3113
3114static bcm_struct_cfgdev *
3115wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
3116#if defined(WL_CFG80211_P2P_DEV_IF)
3117 const char *name,
3118#else
3119 char *name,
3120#endif /* WL_CFG80211_P2P_DEV_IF */
3121#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
3122 unsigned char name_assign_type,
3123#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
3124 enum nl80211_iftype type,
3125#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3126 u32 *flags,
3127#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3128 struct vif_params *params)
3129{
3130 u16 wl_iftype;
3131 u16 wl_mode;
3132 struct net_device *primary_ndev;
3133 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3134 struct wireless_dev *wdev;
3135
3136 WL_DBG(("Enter iftype: %d\n", type));
3137 if (!cfg) {
3138 return ERR_PTR(-EINVAL);
3139 }
3140
3141 /* Use primary I/F for sending cmds down to firmware */
3142 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3143 if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
3144 WL_ERR(("device is not ready\n"));
3145 return ERR_PTR(-ENODEV);
3146 }
3147
3148 if (!name) {
3149 WL_ERR(("Interface name not provided \n"));
3150 return ERR_PTR(-EINVAL);
3151 }
3152
3153 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3154 return ERR_PTR(-EINVAL);
3155 }
3156
3157 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, name, NULL);
3158 if (unlikely(!wdev)) {
3159 return ERR_PTR(-ENODEV);
3160 }
3161 return wdev_to_cfgdev(wdev);
3162}
3163
3164static s32
3165wl_cfg80211_del_ibss(struct wiphy *wiphy, struct wireless_dev *wdev)
3166{
3167 WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev));
3168#ifdef WLAIBSS_MCHAN
3169 /* AIBSS */
3170 return bcm_cfg80211_del_ibss_if(wiphy, wdev);
3171#else
3172 /* Normal IBSS */
3173 return wl_cfg80211_del_iface(wiphy, wdev);
3174#endif
3175}
3176
3177s32
3178wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
3179 struct wireless_dev *wdev, char *ifname)
3180{
3181 int ret = BCME_OK;
3182 mutex_lock(&cfg->if_sync);
3183 ret = _wl_cfg80211_del_if(cfg, primary_ndev, wdev, ifname);
3184 mutex_unlock(&cfg->if_sync);
3185 return ret;
3186}
3187
3188s32
3189_wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
3190 struct wireless_dev *wdev, char *ifname)
3191{
3192 int ret = BCME_OK;
3193 s32 bssidx;
3194 struct wiphy *wiphy;
3195 u16 wl_mode;
3196 u16 wl_iftype;
3197 struct net_info *netinfo;
3198 dhd_pub_t *dhd;
3199 BCM_REFERENCE(dhd);
3200
3201 if (!cfg) {
3202 return -EINVAL;
3203 }
3204
3205 dhd = (dhd_pub_t *)(cfg->pub);
3206
3207 if (!wdev && ifname) {
3208 /* If only ifname is provided, fetch corresponding wdev ptr from our
3209 * internal data structure
3210 */
3211 wdev = wl_cfg80211_get_wdev_from_ifname(cfg, ifname);
3212 }
3213
3214 /* Check whether we have a valid wdev ptr */
3215 if (unlikely(!wdev)) {
3216 WL_ERR(("wdev not found. '%s' does not exists\n", ifname));
3217 return -ENODEV;
3218 }
3219
3220 WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev->iftype));
3221
3222 wiphy = wdev->wiphy;
3223#ifdef WL_CFG80211_P2P_DEV_IF
3224 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
3225 /* p2p discovery would be de-initialized in stop p2p
3226 * device context/from other virtual i/f creation context
3227 * so netinfo list may not have any node corresponding to
3228 * discovery I/F. Handle it before bssidx check.
3229 */
3230 ret = wl_cfg80211_p2p_if_del(wiphy, wdev);
3231 if (unlikely(ret)) {
3232 goto exit;
3233 } else {
3234 /* success case. return from here */
3235 if (cfg->vif_count) {
3236 cfg->vif_count--;
3237 }
3238 return BCME_OK;
3239 }
3240 }
3241#endif /* WL_CFG80211_P2P_DEV_IF */
3242
3243 if ((netinfo = wl_get_netinfo_by_wdev(cfg, wdev)) == NULL) {
3244 WL_ERR(("Find netinfo from wdev %p failed\n", wdev));
3245 ret = -ENODEV;
3246 goto exit;
3247 }
3248
3249 if (!wdev->netdev) {
3250 WL_ERR(("ndev null! \n"));
3251 } else {
3252 /* Disable tx before del */
3253 netif_tx_disable(wdev->netdev);
3254 }
3255
3256 wl_iftype = netinfo->iftype;
3257 wl_mode = wl_iftype_to_mode(wl_iftype);
3258 bssidx = netinfo->bssidx;
3259 WL_DBG_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
3260 wdev->iftype, wl_iftype, wl_mode, bssidx));
3261
3262 /* Do pre-interface del ops */
3263 wl_cfg80211_iface_state_ops(wdev, WL_IF_DELETE_REQ, wl_iftype, wl_mode);
3264
3265#ifdef PCIE_FULL_DONGLE
3266 /* clean up sta info & clean up flowrings correspondign to the iface */
3267 dhd_net_del_flowrings_sta(dhd, wdev->netdev);
3268#endif /* PCIE_FULL_DONGLE */
3269
3270 switch (wl_iftype) {
3271 case WL_IF_TYPE_P2P_GO:
3272 case WL_IF_TYPE_P2P_GC:
3273 case WL_IF_TYPE_AP:
3274 case WL_IF_TYPE_STA:
3275 case WL_IF_TYPE_NAN:
3276 ret = wl_cfg80211_del_iface(wiphy, wdev);
3277 break;
3278 case WL_IF_TYPE_IBSS:
3279 ret = wl_cfg80211_del_ibss(wiphy, wdev);
3280 break;
3281
3282 default:
3283 WL_ERR(("Unsupported interface type\n"));
3284 ret = BCME_ERROR;
3285 }
3286
3287exit:
3288 if (ret == BCME_OK) {
3289 /* Successful case */
3290 if (cfg->vif_count) {
3291 cfg->vif_count--;
3292 }
3293 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3294 WL_IF_DELETE_DONE, wl_iftype, wl_mode);
3295#ifdef WL_NAN
3296 if (!((cfg->nancfg->mac_rand) && (wl_iftype == WL_IF_TYPE_NAN)))
3297#endif /* WL_NAN */
3298 {
3299 wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype);
3300 }
3301 WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg->vif_count));
3302 } else {
3303 if (!wdev->netdev) {
3304 WL_ERR(("ndev null! \n"));
3305 } else {
3306 /* IF del failed. revert back tx queue status */
3307 netif_tx_start_all_queues(wdev->netdev);
3308 }
3309
3310 /* Skip generating log files and sending HANG event
3311 * if driver state is not READY
3312 */
3313 if (wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg))) {
3314#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
3315 wl_copy_hang_info_if_falure(primary_ndev,
3316 HANG_REASON_IFACE_DEL_FAILURE, ret);
3317#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
3318 SUPP_LOG(("IF_DEL fail. err:%d\n", ret));
3319 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3320 /* IF dongle is down due to previous hang or other conditions, sending
3321 * one more hang notification is not needed.
3322 */
3323 if (dhd_query_bus_erros(dhd) || (ret == BCME_DONGLE_DOWN)) {
3324 goto end;
3325 }
3326 dhd->iface_op_failed = TRUE;
3327#if defined(DHD_FW_COREDUMP)
3328 if (dhd->memdump_enabled && (ret != -EBADTYPE)) {
3329 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3330 dhd_bus_mem_dump(dhd);
3331 }
3332#endif /* DHD_FW_COREDUMP */
3333
3334 WL_ERR(("Notify hang event to upper layer \n"));
3335 dhd->hang_reason = HANG_REASON_IFACE_DEL_FAILURE;
3336 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3337
3338 }
3339 }
3340end:
3341 return ret;
3342}
3343
3344static s32
3345wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
3346{
3347 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3348 struct wireless_dev *wdev = cfgdev_to_wdev(cfgdev);
3349 int ret = BCME_OK;
3350 u16 wl_iftype;
3351 u16 wl_mode;
3352 struct net_device *primary_ndev;
3353
3354 if (!cfg) {
3355 return -EINVAL;
3356 }
3357
3358 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3359 wdev = cfgdev_to_wdev(cfgdev);
3360 if (!wdev) {
3361 WL_ERR(("wdev null"));
3362 return -ENODEV;
3363 }
3364
3365 WL_DBG(("Enter wdev:%p iftype: %d\n", wdev, wdev->iftype));
3366 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
3367 WL_ERR(("Wrong iftype: %d\n", wdev->iftype));
3368 return -ENODEV;
3369 }
3370
3371 if ((ret = wl_cfg80211_del_if(cfg, primary_ndev,
3372 wdev, NULL)) < 0) {
3373 WL_ERR(("IF del failed\n"));
3374 }
3375
3376 return ret;
3377}
3378
3379static s32
3380wl_cfg80211_change_p2prole(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type)
3381{
3382 s32 wlif_type;
3383 s32 mode = 0;
3384 s32 index;
3385 s32 err;
3386 s32 conn_idx = -1;
3387 chanspec_t chspec;
3388 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3389 struct ether_addr p2p_dev_addr = {{0, 0, 0, 0, 0, 0}};
3390 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3391
3392 WL_INFORM_MEM(("Enter. current_role:%d new_role:%d \n", ndev->ieee80211_ptr->iftype, type));
3393
3394 (void)memcpy_s(p2p_dev_addr.octet, ETHER_ADDR_LEN,
3395 ndev->dev_addr, ETHER_ADDR_LEN);
3396
3397 if (!cfg->p2p || !wl_cfgp2p_vif_created(cfg)) {
3398 WL_ERR(("P2P not initialized \n"));
3399 return -EINVAL;
3400 }
3401
3402 if (!is_p2p_group_iface(ndev->ieee80211_ptr)) {
3403 WL_ERR(("Wrong if type \n"));
3404 return -EINVAL;
3405 }
3406
3407 /* Abort any on-going scans to avoid race condition issues */
3408 wl_cfg80211_cancel_scan(cfg);
3409
3410 index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
3411 if (index < 0) {
3412 WL_ERR(("Find bsscfg index from ndev(%p) failed\n", ndev));
3413 return BCME_ERROR;
3414 }
3415 if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK) {
3416 return BCME_ERROR;
3417 }
3418
3419 /* In concurrency case, STA may be already associated in a particular
3420 * channel. so retrieve the current channel of primary interface and
3421 * then start the virtual interface on that.
3422 */
3423 chspec = wl_cfg80211_get_shared_freq(wiphy);
3424 if (type == NL80211_IFTYPE_P2P_GO) {
3425 /* Dual p2p doesn't support multiple P2PGO interfaces,
3426 * p2p_go_count is the counter for GO creation
3427 * requests.
3428 */
3429 if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
3430 WL_ERR(("FW does not support multiple GO\n"));
3431 return BCME_ERROR;
3432 }
3433 mode = WL_MODE_AP;
3434 wlif_type = WL_P2P_IF_GO;
3435 dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
3436 dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
3437 } else {
3438 wlif_type = WL_P2P_IF_CLIENT;
3439 /* for GO */
3440 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
3441 WL_INFORM_MEM(("Downgrading P2P GO to cfg_iftype:%d \n", type));
3442 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
3443 cfg->p2p->p2p_go_count--;
3444 /* disable interface before bsscfg free */
3445 err = wl_cfgp2p_ifdisable(cfg, &p2p_dev_addr);
3446 /* if fw doesn't support "ifdis",
3447 * do not wait for link down of ap mode
3448 */
3449 if (err == 0) {
3450 WL_DBG(("Wait for Link Down event for GO !!!\n"));
3451 wait_for_completion_timeout(&cfg->iface_disable,
3452 msecs_to_jiffies(500));
3453 } else if (err != BCME_UNSUPPORTED) {
3454 msleep(300);
3455 }
3456 }
3457 }
3458
3459 wl_set_p2p_status(cfg, IF_CHANGING);
3460 wl_clr_p2p_status(cfg, IF_CHANGED);
3461 wl_cfgp2p_ifchange(cfg, &p2p_dev_addr,
3462 htod32(wlif_type), chspec, conn_idx);
3463 wait_event_interruptible_timeout(cfg->netif_change_event,
3464 (wl_get_p2p_status(cfg, IF_CHANGED) == true),
3465 msecs_to_jiffies(MAX_WAIT_TIME));
3466
3467 wl_clr_p2p_status(cfg, IF_CHANGING);
3468 wl_clr_p2p_status(cfg, IF_CHANGED);
3469
3470 if (mode == WL_MODE_AP) {
3471 wl_set_drv_status(cfg, CONNECTED, ndev);
3472 }
3473
3474 return BCME_OK;
3475}
3476
3477static s32
3478wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
3479 enum nl80211_iftype type,
3480#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3481 u32 *flags,
3482#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3483 struct vif_params *params)
3484{
3485 s32 infra = 1;
3486 s32 err = BCME_OK;
3487 u16 wl_iftype;
3488 u16 wl_mode;
3489 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3490 struct net_info *netinfo = NULL;
3491 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3492 struct net_device *primary_ndev;
3493
3494 if (!dhd)
3495 return -EINVAL;
3496
3497 WL_INFORM_MEM(("[%s] Enter. current cfg_iftype:%d new cfg_iftype:%d \n",
3498 ndev->name, ndev->ieee80211_ptr->iftype, type));
3499 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3500
3501 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3502 WL_ERR(("Unknown role \n"));
3503 return -EINVAL;
3504 }
3505
3506 mutex_lock(&cfg->if_sync);
3507 netinfo = wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
3508 if (unlikely(!netinfo)) {
3509#ifdef WL_STATIC_IF
3510 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
3511 /* Incase of static interfaces, the netinfo will be
3512 * allocated only when FW interface is initialized. So
3513 * store the value and use it during initialization.
3514 */
3515 WL_INFORM_MEM(("skip change vif for static if\n"));
3516 ndev->ieee80211_ptr->iftype = type;
3517 err = BCME_OK;
3518 } else
3519#endif /* WL_STATIC_IF */
3520 {
3521 WL_ERR(("netinfo not found \n"));
3522 err = -ENODEV;
3523 }
3524 goto fail;
3525 }
3526
3527 if ((primary_ndev == ndev) && !(ndev->flags & IFF_UP)) {
3528 /*
3529 * If interface is not initialized, store the role and
3530 * return. The role will be initilized after interface
3531 * up
3532 */
3533 WL_INFORM_MEM(("skip change role before dev up\n"));
3534 ndev->ieee80211_ptr->iftype = type;
3535 err = BCME_OK;
3536 goto fail;
3537 }
3538
3539 /* perform pre-if-change tasks */
3540 wl_cfg80211_iface_state_ops(ndev->ieee80211_ptr,
3541 WL_IF_CHANGE_REQ, wl_iftype, wl_mode);
3542
3543 switch (type) {
3544 case NL80211_IFTYPE_ADHOC:
3545 infra = 0;
3546 break;
3547 case NL80211_IFTYPE_STATION:
3548 /* Supplicant sets iftype to STATION while removing p2p GO */
3549 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
3550 /* Downgrading P2P GO */
3551 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3552 if (unlikely(err)) {
3553 WL_ERR(("P2P downgrade failed \n"));
3554 }
3555 } else if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
3556 /* Downgrade role from AP to STA */
3557 if ((err = wl_cfg80211_add_del_bss(cfg, ndev,
3558 netinfo->bssidx, wl_iftype, 0, NULL)) < 0) {
3559 WL_ERR(("AP-STA Downgrade failed \n"));
3560 goto fail;
3561 }
3562 }
3563 break;
3564 case NL80211_IFTYPE_AP:
3565 /* intentional fall through */
3566 case NL80211_IFTYPE_AP_VLAN:
3567 {
3568 if (!wl_get_drv_status(cfg, AP_CREATED, ndev) &&
3569 wl_get_drv_status(cfg, READY, ndev)) {
3570 err = wl_cfg80211_set_ap_role(cfg, ndev);
3571 if (unlikely(err)) {
3572 WL_ERR(("set ap role failed!\n"));
3573 goto fail;
3574 }
3575 } else {
3576 WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
3577 }
3578 break;
3579 }
3580 case NL80211_IFTYPE_P2P_GO:
3581 /* Intentional fall through */
3582 case NL80211_IFTYPE_P2P_CLIENT:
3583 infra = 1;
3584 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3585 break;
3586 case NL80211_IFTYPE_MONITOR:
3587 case NL80211_IFTYPE_WDS:
3588 case NL80211_IFTYPE_MESH_POINT:
3589 /* Intentional fall through */
3590 default:
3591 WL_ERR(("Unsupported type:%d \n", type));
3592 err = -EINVAL;
3593 goto fail;
3594 }
3595
3596 if (wl_get_drv_status(cfg, READY, ndev)) {
3597 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(s32));
3598 if (err < 0) {
3599 WL_ERR(("SET INFRA/IBSS error %d\n", err));
3600 goto fail;
3601 }
3602 }
3603
3604 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3605 WL_IF_CHANGE_DONE, wl_iftype, wl_mode);
3606
3607 /* Update new iftype in relevant structures */
3608 if (is_p2p_group_iface(ndev->ieee80211_ptr) && (type == NL80211_IFTYPE_STATION)) {
3609 /* For role downgrade cases, we keep interface role as GC */
3610 netinfo->iftype = WL_IF_TYPE_P2P_GC;
3611 WL_DBG_MEM(("[%s] Set base role to GC, current role"
3612 "ndev->ieee80211_ptr->iftype = %d\n",
3613 __FUNCTION__, ndev->ieee80211_ptr->iftype));
3614 } else {
3615 netinfo->iftype = wl_iftype;
3616 }
3617
3618 ndev->ieee80211_ptr->iftype = type;
3619
3620 WL_INFORM_MEM(("[%s] cfg_iftype changed to %d\n", ndev->name, type));
3621#ifdef WL_EXT_IAPSTA
3622 wl_ext_iapsta_update_iftype(ndev, netinfo->ifidx, wl_iftype);
3623#endif
3624
3625fail:
3626 if (err) {
3627 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
3628 }
3629 mutex_unlock(&cfg->if_sync);
3630 return err;
3631}
3632
3633s32
3634wl_cfg80211_notify_ifadd(struct net_device *dev,
3635 int ifidx, char *name, uint8 *mac, uint8 bssidx, uint8 role)
3636{
3637 bool ifadd_expected = FALSE;
3638 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3639 bool bss_pending_op = TRUE;
3640
3641 /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
3642 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
3643 */
3644 if (wl_get_p2p_status(cfg, IF_CHANGING))
3645 return wl_cfg80211_notify_ifchange(dev, ifidx, name, mac, bssidx);
3646
3647 /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
3648 if (wl_get_p2p_status(cfg, IF_ADDING)) {
3649 ifadd_expected = TRUE;
3650 wl_clr_p2p_status(cfg, IF_ADDING);
3651 } else if (cfg->bss_pending_op) {
3652 ifadd_expected = TRUE;
3653 bss_pending_op = FALSE;
3654 }
3655
3656 if (ifadd_expected) {
3657 wl_if_event_info *if_event_info = &cfg->if_event_info;
3658
3659 if_event_info->valid = TRUE;
3660 if_event_info->ifidx = ifidx;
3661 if_event_info->bssidx = bssidx;
3662 if_event_info->role = role;
3663 strlcpy(if_event_info->name, name, sizeof(if_event_info->name));
3664 if_event_info->name[IFNAMSIZ - 1] = '\0';
3665 if (mac)
3666 memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
3667
3668 /* Update bss pendig operation status */
3669 if (!bss_pending_op) {
3670 cfg->bss_pending_op = FALSE;
3671 }
3672 WL_INFORM_MEM(("IF_ADD ifidx:%d bssidx:%d role:%d\n",
3673 ifidx, bssidx, role));
3674 OSL_SMP_WMB();
3675 wake_up_interruptible(&cfg->netif_change_event);
3676 return BCME_OK;
3677 }
3678
3679 return BCME_ERROR;
3680}
3681
3682s32
3683wl_cfg80211_notify_ifdel(struct net_device *dev, int ifidx, char *name, uint8 *mac, uint8 bssidx)
3684{
3685 bool ifdel_expected = FALSE;
3686 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3687 wl_if_event_info *if_event_info = &cfg->if_event_info;
3688 bool bss_pending_op = TRUE;
3689
3690 if (wl_get_p2p_status(cfg, IF_DELETING)) {
3691 ifdel_expected = TRUE;
3692 wl_clr_p2p_status(cfg, IF_DELETING);
3693 } else if (cfg->bss_pending_op) {
3694 ifdel_expected = TRUE;
3695 bss_pending_op = FALSE;
3696 }
3697
3698 if (ifdel_expected) {
3699 if_event_info->valid = TRUE;
3700 if_event_info->ifidx = ifidx;
3701 if_event_info->bssidx = bssidx;
3702 /* Update bss pendig operation status */
3703 if (!bss_pending_op) {
3704 cfg->bss_pending_op = FALSE;
3705 }
3706 WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx, bssidx));
3707 OSL_SMP_WMB();
3708 wake_up_interruptible(&cfg->netif_change_event);
3709 return BCME_OK;
3710 }
3711
3712 return BCME_ERROR;
3713}
3714
3715s32
3716wl_cfg80211_notify_ifchange(struct net_device * dev, int ifidx, char *name, uint8 *mac,
3717 uint8 bssidx)
3718{
3719 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3720
3721 if (wl_get_p2p_status(cfg, IF_CHANGING)) {
3722 wl_set_p2p_status(cfg, IF_CHANGED);
3723 OSL_SMP_WMB();
3724 wake_up_interruptible(&cfg->netif_change_event);
3725 return BCME_OK;
3726 }
3727
3728 return BCME_ERROR;
3729}
3730
3731static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
3732{
3733 s32 err = 0;
3734
3735 err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
3736 if (unlikely(err)) {
3737 WL_ERR(("Error (%d)\n", err));
3738 return err;
3739 }
3740 return err;
3741}
3742
3743static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
3744{
3745 s32 err = 0;
3746
3747 err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
3748 if (unlikely(err)) {
3749 WL_ERR(("Error (%d)\n", err));
3750 return err;
3751 }
3752 return err;
3753}
3754
3755static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
3756{
3757 s32 err = 0;
3758 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
3759
3760#ifdef CUSTOM_LONG_RETRY_LIMIT
3761 if ((cmd == WLC_SET_LRL) &&
3762 (retry != CUSTOM_LONG_RETRY_LIMIT)) {
3763 WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
3764 return err;
3765 }
3766#endif /* CUSTOM_LONG_RETRY_LIMIT */
3767
3768 retry = htod32(retry);
3769 err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry));
3770 if (unlikely(err)) {
3771 WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
3772 return err;
3773 }
3774 return err;
3775}
3776
3777static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
3778{
3779 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
3780 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
3781 s32 err = 0;
3782
3783 RETURN_EIO_IF_NOT_UP(cfg);
3784 WL_DBG(("Enter\n"));
3785 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
3786 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
3787 cfg->conf->rts_threshold = wiphy->rts_threshold;
3788 err = wl_set_rts(ndev, cfg->conf->rts_threshold);
3789 if (err != BCME_OK)
3790 return err;
3791 }
3792 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
3793 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
3794 cfg->conf->frag_threshold = wiphy->frag_threshold;
3795 err = wl_set_frag(ndev, cfg->conf->frag_threshold);
3796 if (err != BCME_OK)
3797 return err;
3798 }
3799 if (changed & WIPHY_PARAM_RETRY_LONG &&
3800 (cfg->conf->retry_long != wiphy->retry_long)) {
3801 cfg->conf->retry_long = wiphy->retry_long;
3802 err = wl_set_retry(ndev, cfg->conf->retry_long, true);
3803 if (err != BCME_OK)
3804 return err;
3805 }
3806 if (changed & WIPHY_PARAM_RETRY_SHORT &&
3807 (cfg->conf->retry_short != wiphy->retry_short)) {
3808 cfg->conf->retry_short = wiphy->retry_short;
3809 err = wl_set_retry(ndev, cfg->conf->retry_short, false);
3810 if (err != BCME_OK) {
3811 return err;
3812 }
3813 }
3814
3815 return err;
3816}
3817
3818chanspec_t
3819wl_channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap)
3820{
3821 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3822 u8 *buf = NULL;
3823 wl_uint32_list_t *list;
3824 int err = BCME_OK;
3825 chanspec_t c = 0, ret_c = 0;
3826 int bw = 0, tmp_bw = 0;
3827 int i;
3828 u32 tmp_c;
3829
3830#define LOCAL_BUF_SIZE 1024
3831 buf = (u8 *)MALLOC(cfg->osh, LOCAL_BUF_SIZE);
3832 if (!buf) {
3833 WL_ERR(("buf memory alloc failed\n"));
3834 goto exit;
3835 }
3836
3837 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
3838 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync);
3839 if (err != BCME_OK) {
3840 WL_ERR(("get chanspecs failed with %d\n", err));
3841 goto exit;
3842 }
3843
3844 list = (wl_uint32_list_t *)(void *)buf;
3845 for (i = 0; i < dtoh32(list->count); i++) {
3846 c = dtoh32(list->element[i]);
3847 if (channel <= CH_MAX_2G_CHANNEL) {
3848 if (!CHSPEC_IS20(c))
3849 continue;
3850 if (channel == CHSPEC_CHANNEL(c)) {
3851 ret_c = c;
3852 bw = 20;
3853 goto exit;
3854 }
3855 }
3856 tmp_c = wf_chspec_ctlchan(c);
3857 tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT];
3858 if (tmp_c != channel)
3859 continue;
3860
3861 if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) {
3862 bw = tmp_bw;
3863 ret_c = c;
3864 if (bw == bw_cap)
3865 goto exit;
3866 }
3867 }
3868exit:
3869 if (buf) {
3870 MFREE(cfg->osh, buf, LOCAL_BUF_SIZE);
3871 }
3872#undef LOCAL_BUF_SIZE
3873 WL_DBG(("return chanspec %x %d\n", ret_c, bw));
3874 return ret_c;
3875}
3876
3877void
3878wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev, vndr_ie_setbuf_t *ibss_vsie,
3879 int ibss_vsie_len)
3880{
3881 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3882
3883 if (cfg != NULL && ibss_vsie != NULL) {
3884 if (cfg->ibss_vsie != NULL) {
3885 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3886 }
3887 cfg->ibss_vsie = ibss_vsie;
3888 cfg->ibss_vsie_len = ibss_vsie_len;
3889 }
3890}
3891
3892static void
3893wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
3894{
3895 /* free & initiralize VSIE (Vendor Specific IE) */
3896 if (cfg->ibss_vsie != NULL) {
3897 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3898 cfg->ibss_vsie_len = 0;
3899 }
3900}
3901
3902s32
3903wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
3904{
3905 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3906 char *ioctl_buf = NULL;
3907 s32 ret = BCME_OK, bssidx;
3908
3909 if (cfg != NULL && cfg->ibss_vsie != NULL) {
3910 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
3911 if (!ioctl_buf) {
3912 WL_ERR(("ioctl memory alloc failed\n"));
3913 return -ENOMEM;
3914 }
3915 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3916 WL_ERR(("Find index failed\n"));
3917 ret = BCME_ERROR;
3918 goto end;
3919 }
3920 /* change the command from "add" to "del" */
3921 strlcpy(cfg->ibss_vsie->cmd, "del", sizeof(cfg->ibss_vsie->cmd));
3922
3923 ret = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie",
3924 cfg->ibss_vsie, cfg->ibss_vsie_len,
3925 ioctl_buf, WLC_IOCTL_MEDLEN, bssidx, NULL);
3926 WL_ERR(("ret=%d\n", ret));
3927
3928 if (ret == BCME_OK) {
3929 /* Free & initialize VSIE */
3930 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3931 cfg->ibss_vsie_len = 0;
3932 }
3933end:
3934 if (ioctl_buf) {
3935 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3936 }
3937 }
3938
3939 return ret;
3940}
3941
3942#ifdef WLAIBSS_MCHAN
3943static bcm_struct_cfgdev*
3944bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name)
3945{
3946 int err = 0;
3947 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3948 struct wireless_dev* wdev = NULL;
3949 struct net_device *new_ndev = NULL;
3950 struct net_device *primary_ndev = NULL;
3951 long timeout;
3952 wl_aibss_if_t aibss_if;
3953 wl_if_event_info *event = NULL;
3954
3955 if (cfg->ibss_cfgdev != NULL) {
3956 WL_ERR(("IBSS interface %s already exists\n", name));
3957 return NULL;
3958 }
3959
3960 WL_ERR(("Try to create IBSS interface %s\n", name));
3961 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3962 /* generate a new MAC address for the IBSS interface */
3963 get_primary_mac(cfg, &cfg->ibss_if_addr);
3964 cfg->ibss_if_addr.octet[4] ^= 0x40;
3965 bzero(&aibss_if, sizeof(aibss_if));
3966 memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
3967 aibss_if.chspec = 0;
3968 aibss_if.len = sizeof(aibss_if);
3969
3970 cfg->bss_pending_op = TRUE;
3971 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3972 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
3973 sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3974 if (err) {
3975 WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
3976 goto fail;
3977 }
3978 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3979 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
3980 if (timeout <= 0 || cfg->bss_pending_op)
3981 goto fail;
3982
3983 event = &cfg->if_event_info;
3984 /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
3985 * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
3986 * and will be freed by dhd_detach unless it gets unregistered before that. The
3987 * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
3988 * be freed by wl_dealloc_netinfo
3989 */
3990 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name,
3991 event->mac, event->bssidx, event->name);
3992 if (new_ndev == NULL)
3993 goto fail;
3994 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
3995 if (wdev == NULL)
3996 goto fail;
3997 wdev->wiphy = wiphy;
3998 wdev->iftype = NL80211_IFTYPE_ADHOC;
3999 wdev->netdev = new_ndev;
4000 new_ndev->ieee80211_ptr = wdev;
4001 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4002
4003 /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
4004 * needs to be modified to take one parameter (bool need_rtnl_lock)
4005 */
4006 ASSERT_RTNL();
4007 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, FALSE) != BCME_OK)
4008 goto fail;
4009
4010 wl_alloc_netinfo(cfg, new_ndev, wdev, WL_IF_TYPE_IBSS,
4011 PM_ENABLE, event->bssidx, event->ifidx);
4012 cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
4013 WL_ERR(("IBSS interface %s created\n", new_ndev->name));
4014 return cfg->ibss_cfgdev;
4015
4016fail:
4017 WL_ERR(("failed to create IBSS interface %s \n", name));
4018 cfg->bss_pending_op = FALSE;
4019 if (new_ndev)
4020 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
4021 if (wdev) {
4022 MFREE(cfg->osh, wdev, sizeof(*wdev));
4023 }
4024 return NULL;
4025}
4026
4027static s32
4028bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
4029{
4030 int err = 0;
4031 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4032 struct net_device *ndev = NULL;
4033 struct net_device *primary_ndev = NULL;
4034 long timeout;
4035
4036 if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet))
4037 return -EINVAL;
4038 ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev);
4039 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4040
4041 cfg->bss_pending_op = TRUE;
4042 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
4043 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
4044 sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4045 if (err) {
4046 WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
4047 goto fail;
4048 }
4049 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4050 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4051 if (timeout <= 0 || cfg->bss_pending_op) {
4052 WL_ERR(("timeout in waiting IF_DEL event\n"));
4053 goto fail;
4054 }
4055
4056 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
4057 cfg->ibss_cfgdev = NULL;
4058 return 0;
4059
4060fail:
4061 cfg->bss_pending_op = FALSE;
4062 return -1;
4063}
4064#endif /* WLAIBSS_MCHAN */
4065
4066s32
4067wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)
4068{
4069 s32 ret = BCME_ERROR;
4070
4071 switch (iftype) {
4072 case WL_IF_TYPE_AP:
4073 ret = WL_INTERFACE_TYPE_AP;
4074 break;
4075 case WL_IF_TYPE_STA:
4076 ret = WL_INTERFACE_TYPE_STA;
4077 break;
4078 case WL_IF_TYPE_NAN_NMI:
4079 case WL_IF_TYPE_NAN:
4080 ret = WL_INTERFACE_TYPE_NAN;
4081 break;
4082 case WL_IF_TYPE_P2P_DISC:
4083 ret = WL_INTERFACE_TYPE_P2P_DISC;
4084 break;
4085 case WL_IF_TYPE_P2P_GO:
4086 ret = WL_INTERFACE_TYPE_P2P_GO;
4087 break;
4088 case WL_IF_TYPE_P2P_GC:
4089 ret = WL_INTERFACE_TYPE_P2P_GC;
4090 break;
4091
4092 default:
4093 WL_ERR(("Unsupported type:%d \n", iftype));
4094 ret = -EINVAL;
4095 break;
4096 }
4097 return ret;
4098}
4099
4100bool
4101wl_legacy_chip_check(struct bcm_cfg80211 *cfg)
4102{
4103 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
4104 uint chip;
4105
4106 chip = dhd_conf_get_chip(dhd);
4107
4108 if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
4109 chip == BCM43430_CHIP_ID || chip == BCM43012_CHIP_ID ||
4110 chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID ||
4111 chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID ||
4112 chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID ||
4113 chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID ||
4114 chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
4115 chip == BCM4371_CHIP_ID || chip == BCM4359_CHIP_ID ||
4116 chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
4117 chip == BCM43569_CHIP_ID) {
4118 return true;
4119 }
4120
4121 return false;
4122}
4123
4124s32
4125wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
4126 struct net_device *ndev, s32 bsscfg_idx,
4127 wl_iftype_t cfg_iftype, s32 del, u8 *addr)
4128{
4129 s32 ret;
4130 struct wl_interface_create_v2 iface;
4131 wl_interface_create_v3_t iface_v3;
4132 wl_interface_create_t iface_v0;
4133 struct wl_interface_info_v1 *info;
4134 wl_interface_info_v2_t *info_v2;
4135 wl_interface_info_t *info_v0;
4136 uint32 ifflags = 0;
4137 bool use_iface_info_v2 = false;
4138 u8 ioctl_buf[WLC_IOCTL_SMLEN];
4139 s32 iftype;
4140
4141 if (del) {
4142 ret = wldev_iovar_setbuf(ndev, "interface_remove",
4143 NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL);
4144 if (unlikely(ret))
4145 WL_ERR(("Interface remove failed!! ret %d\n", ret));
4146 return ret;
4147 }
4148
4149 /* Interface create */
4150 bzero(&iface, sizeof(iface));
4151 /*
4152 * flags field is still used along with iftype inorder to support the old version of the
4153 * FW work with the latest app changes.
4154 */
4155
4156 iftype = wl_cfg80211_to_fw_iftype(cfg_iftype);
4157 if (iftype < 0) {
4158 return -ENOTSUPP;
4159 }
4160
4161 if (addr) {
4162 ifflags |= WL_INTERFACE_MAC_USE;
4163 }
4164
4165 /* Pass ver = 0 for fetching the interface_create iovar version */
4166 if (wl_legacy_chip_check(cfg)) {
4167 bzero(&iface_v0, sizeof(iface_v0));
4168 iface_v0.ver = WL_INTERFACE_CREATE_VER;
4169 iface_v0.flags = iftype | ifflags;
4170 if (addr) {
4171 memcpy(&iface_v0.mac_addr.octet, addr, ETH_ALEN);
4172 }
4173 ret = wldev_iovar_getbuf(ndev, "interface_create",
4174 &iface_v0, sizeof(struct wl_interface_create),
4175 ioctl_buf, sizeof(ioctl_buf), NULL);
4176 if (ret == 0) {
4177 info_v0 = (wl_interface_info_t *)ioctl_buf;
4178 ret = info_v0->bsscfgidx;
4179 goto exit;
4180 }
4181 } else {
4182 ret = wldev_iovar_getbuf(ndev, "interface_create",
4183 &iface, sizeof(struct wl_interface_create_v2),
4184 ioctl_buf, sizeof(ioctl_buf), NULL);
4185 }
4186 if (ret == BCME_UNSUPPORTED) {
4187 WL_ERR(("interface_create iovar not supported\n"));
4188 return ret;
4189 } else if ((ret == 0) && *((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3) {
4190 WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags));
4191 use_iface_info_v2 = true;
4192 bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
4193 iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
4194 iface_v3.iftype = iftype;
4195 iface_v3.flags = ifflags;
4196 if (addr) {
4197 memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
4198 }
4199 ret = wldev_iovar_getbuf(ndev, "interface_create",
4200 &iface_v3, sizeof(wl_interface_create_v3_t),
4201 ioctl_buf, sizeof(ioctl_buf), NULL);
4202 } else {
4203 /* On any other error, attempt with iovar version 2 */
4204 WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n", ret, ifflags));
4205 iface.ver = WL_INTERFACE_CREATE_VER_2;
4206 iface.iftype = iftype;
4207 iface.flags = ifflags;
4208 if (addr) {
4209 memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
4210 }
4211 ret = wldev_iovar_getbuf(ndev, "interface_create",
4212 &iface, sizeof(struct wl_interface_create_v2),
4213 ioctl_buf, sizeof(ioctl_buf), NULL);
4214 }
4215
4216 if (unlikely(ret)) {
4217 WL_ERR(("Interface create failed!! ret %d\n", ret));
4218 return ret;
4219 }
4220
4221 /* success case */
4222 if (use_iface_info_v2 == true) {
4223 info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
4224 ret = info_v2->bsscfgidx;
4225 } else {
4226 /* Use v1 struct */
4227 info = (struct wl_interface_info_v1 *)ioctl_buf;
4228 ret = info->bsscfgidx;
4229 }
4230
4231exit:
4232 WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
4233 return ret;
4234}
4235
4236s32
4237wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
4238 struct net_device *ndev, s32 bsscfg_idx,
4239 wl_iftype_t brcm_iftype, s32 del, u8 *addr)
4240{
4241 s32 ret = BCME_OK;
4242 s32 val = 0;
4243
4244 struct {
4245 s32 cfg;
4246 s32 val;
4247 struct ether_addr ea;
4248 } bss_setbuf;
4249
4250 WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype, del));
4251
4252 bzero(&bss_setbuf, sizeof(bss_setbuf));
4253
4254 /* AP=2, STA=3, up=1, down=0, val=-1 */
4255 if (del) {
4256 val = WLC_AP_IOV_OP_DELETE;
4257 } else if (brcm_iftype == WL_IF_TYPE_AP) {
4258 /* Add/role change to AP Interface */
4259 WL_DBG(("Adding AP Interface \n"));
4260 val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
4261 } else if (brcm_iftype == WL_IF_TYPE_STA) {
4262 /* Add/role change to STA Interface */
4263 WL_DBG(("Adding STA Interface \n"));
4264 val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
4265 } else {
4266 WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype));
4267 return -EINVAL;
4268 }
4269
4270 if (!del) {
4271 wl_ext_bss_iovar_war(ndev, &val);
4272 }
4273
4274 bss_setbuf.cfg = htod32(bsscfg_idx);
4275 bss_setbuf.val = htod32(val);
4276
4277 if (addr) {
4278 memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
4279 }
4280
4281 WL_MSG(ndev->name, "wl bss %d bssidx:%d\n", val, bsscfg_idx);
4282 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4283 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4284 if (ret != 0)
4285 WL_ERR(("'bss %d' failed with %d\n", val, ret));
4286
4287 return ret;
4288}
4289
4290s32
4291wl_cfg80211_bss_up(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 bss_up)
4292{
4293 s32 ret = BCME_OK;
4294 s32 val = bss_up ? 1 : 0;
4295
4296 struct {
4297 s32 cfg;
4298 s32 val;
4299 } bss_setbuf;
4300
4301 bss_setbuf.cfg = htod32(bsscfg_idx);
4302 bss_setbuf.val = htod32(val);
4303
4304 WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx, bss_up ? "up" : "down"));
4305 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4306 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4307
4308 if (ret != 0) {
4309 WL_ERR(("'bss %d' failed with %d\n", bss_up, ret));
4310 }
4311
4312 return ret;
4313}
4314
4315bool
4316wl_cfg80211_bss_isup(struct net_device *ndev, int bsscfg_idx)
4317{
4318 s32 result, val;
4319 bool isup = false;
4320 s8 getbuf[64];
4321
4322 /* Check if the BSS is up */
4323 *(int*)getbuf = -1;
4324 result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
4325 sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
4326 if (result != 0) {
4327 WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
4328 WL_ERR(("NOTE: this ioctl error is normal "
4329 "when the BSS has not been created yet.\n"));
4330 } else {
4331 val = *(int*)getbuf;
4332 val = dtoh32(val);
4333 WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx, val));
4334 isup = (val ? TRUE : FALSE);
4335 }
4336 return isup;
4337}
4338
4339s32
4340wl_iftype_to_mode(wl_iftype_t iftype)
4341{
4342 s32 mode = BCME_ERROR;
4343
4344 switch (iftype) {
4345 case WL_IF_TYPE_STA:
4346 case WL_IF_TYPE_P2P_GC:
4347 case WL_IF_TYPE_P2P_DISC:
4348 mode = WL_MODE_BSS;
4349 break;
4350 case WL_IF_TYPE_AP:
4351 case WL_IF_TYPE_P2P_GO:
4352 mode = WL_MODE_AP;
4353 break;
4354 case WL_IF_TYPE_NAN:
4355 mode = WL_MODE_NAN;
4356 break;
4357
4358 case WL_IF_TYPE_AIBSS:
4359 /* Intentional fall through */
4360 case WL_IF_TYPE_IBSS:
4361 mode = WL_MODE_IBSS;
4362 break;
4363#ifdef WLMESH_CFG80211
4364 case WL_IF_TYPE_MESH:
4365 mode = WL_MODE_MESH;
4366 break;
4367#endif /* WLMESH_CFG80211 */
4368 default:
4369 WL_ERR(("Unsupported type:%d\n", iftype));
4370 break;
4371 }
4372 return mode;
4373}
4374
4375s32
4376cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode)
4377{
4378 switch (type) {
4379 case NL80211_IFTYPE_STATION:
4380 *role = WL_IF_TYPE_STA;
4381 *mode = WL_MODE_BSS;
4382 break;
4383 case NL80211_IFTYPE_AP:
4384 *role = WL_IF_TYPE_AP;
4385 *mode = WL_MODE_AP;
4386 break;
4387#ifdef WL_CFG80211_P2P_DEV_IF
4388 case NL80211_IFTYPE_P2P_DEVICE:
4389 *role = WL_IF_TYPE_P2P_DISC;
4390 *mode = WL_MODE_BSS;
4391 break;
4392#endif /* WL_CFG80211_P2P_DEV_IF */
4393 case NL80211_IFTYPE_P2P_GO:
4394 *role = WL_IF_TYPE_P2P_GO;
4395 *mode = WL_MODE_AP;
4396 break;
4397 case NL80211_IFTYPE_P2P_CLIENT:
4398 *role = WL_IF_TYPE_P2P_GC;
4399 *mode = WL_MODE_BSS;
4400 break;
4401 case NL80211_IFTYPE_MONITOR:
4402 WL_ERR(("Unsupported mode \n"));
4403 return BCME_UNSUPPORTED;
4404 case NL80211_IFTYPE_ADHOC:
4405 *role = WL_IF_TYPE_IBSS;
4406 *mode = WL_MODE_IBSS;
4407 break;
4408#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
4409 case NL80211_IFTYPE_NAN:
4410 *role = WL_IF_TYPE_NAN;
4411 *mode = WL_MODE_NAN;
4412 break;
4413#endif
4414#ifdef WLMESH_CFG80211
4415 case NL80211_IFTYPE_MESH_POINT:
4416 *role = WLC_E_IF_ROLE_AP;
4417 *mode = WL_MODE_MESH;
4418 break;
4419#endif /* WLMESH_CFG80211 */
4420 default:
4421 WL_ERR(("Unknown interface type:0x%x\n", type));
4422 return BCME_ERROR;
4423 }
4424 return BCME_OK;
4425}
4426
4427static s32
4428wl_role_to_cfg80211_type(uint16 role, uint16 *wl_iftype, uint16 *mode)
4429{
4430 switch (role) {
4431
4432 case WLC_E_IF_ROLE_STA:
4433 *wl_iftype = WL_IF_TYPE_STA;
4434 *mode = WL_MODE_BSS;
4435 return NL80211_IFTYPE_STATION;
4436 case WLC_E_IF_ROLE_AP:
4437 *wl_iftype = WL_IF_TYPE_AP;
4438 *mode = WL_MODE_AP;
4439 return NL80211_IFTYPE_AP;
4440 case WLC_E_IF_ROLE_P2P_GO:
4441 *wl_iftype = WL_IF_TYPE_P2P_GO;
4442 *mode = WL_MODE_AP;
4443 return NL80211_IFTYPE_P2P_GO;
4444 case WLC_E_IF_ROLE_P2P_CLIENT:
4445 *wl_iftype = WL_IF_TYPE_P2P_GC;
4446 *mode = WL_MODE_BSS;
4447 return NL80211_IFTYPE_P2P_CLIENT;
4448 case WLC_E_IF_ROLE_IBSS:
4449 *wl_iftype = WL_IF_TYPE_IBSS;
4450 *mode = WL_MODE_IBSS;
4451 return NL80211_IFTYPE_ADHOC;
4452 case WLC_E_IF_ROLE_NAN:
4453 *wl_iftype = WL_IF_TYPE_NAN;
4454 *mode = WL_MODE_NAN;
4455#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
4456 /* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
4457 * For Vendor HAL based NAN implementation, continue advertising
4458 * as a STA interface
4459 */
4460 return NL80211_IFTYPE_NAN;
4461#else
4462 return NL80211_IFTYPE_STATION;
4463#endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
4464#ifdef WLDWDS
4465 case WLC_E_IF_ROLE_WDS:
4466 *wl_iftype = WL_IF_TYPE_AP;
4467 *mode = WL_MODE_AP;
4468 return NL80211_IFTYPE_AP;
4469#endif
4470#ifdef WLMESH_CFG80211
4471 case WLC_E_IF_ROLE_MESH:
4472 *wl_iftype = WL_IF_TYPE_MESH;
4473 *mode = WL_MODE_MESH;
4474 return NL80211_IFTYPE_MESH_POINT;
4475#endif /* WLMESH_CFG80211 */
4476
4477 default:
4478 WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role));
4479 return BCME_ERROR;
4480 }
4481}
4482
4483struct net_device *
4484wl_cfg80211_post_ifcreate(struct net_device *ndev,
4485 wl_if_event_info *event, u8 *addr,
4486 const char *name, bool rtnl_lock_reqd)
4487{
4488 struct bcm_cfg80211 *cfg;
4489 struct net_device *primary_ndev;
4490 struct net_device *new_ndev = NULL;
4491 struct wireless_dev *wdev = NULL;
4492 s32 iface_type;
4493 s32 ret = BCME_OK;
4494 u16 mode;
4495 u8 mac_addr[ETH_ALEN];
4496 u16 wl_iftype;
4497
4498 if (!ndev || !event) {
4499 WL_ERR(("Wrong arg\n"));
4500 return NULL;
4501 }
4502
4503 cfg = wl_get_cfg(ndev);
4504 if (!cfg) {
4505 WL_ERR(("cfg null\n"));
4506 return NULL;
4507 }
4508
4509 WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
4510 event->role, event->ifidx, event->bssidx));
4511 if (!event->ifidx || !event->bssidx) {
4512 /* Fw returned primary idx (0) for virtual interface */
4513 WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
4514 event->ifidx, event->bssidx));
4515 return NULL;
4516 }
4517
4518#if defined(WLMESH_CFG80211) && defined(WL_EXT_IAPSTA)
4519 if (wl_ext_iapsta_mesh_creating(ndev)) {
4520 event->role = WLC_E_IF_ROLE_MESH;
4521 WL_MSG(ndev->name, "change role to WLC_E_IF_ROLE_MESH\n");
4522 }
4523#endif /* WLMESH_CFG80211 && WL_EXT_IAPSTA */
4524
4525 iface_type = wl_role_to_cfg80211_type(event->role, &wl_iftype, &mode);
4526 if (iface_type < 0) {
4527 /* Unknown iface type */
4528 WL_ERR(("Wrong iface type \n"));
4529 return NULL;
4530 }
4531
4532 WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG "\n",
4533 addr, name, event->role, iface_type, MAC2STRDBG(event->mac)));
4534 if (!name) {
4535 /* If iface name is not provided, use dongle ifname */
4536 name = event->name;
4537 }
4538
4539 if (!addr) {
4540 /* If mac address is not set, use primary mac with locally administered
4541 * bit set.
4542 */
4543 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4544 memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
4545 /* For customer6 builds, use primary mac address for virtual interface */
4546 mac_addr[0] |= 0x02;
4547 addr = mac_addr;
4548 }
4549
4550 if (iface_type == NL80211_IFTYPE_P2P_CLIENT) {
4551 s16 cfg_type = wl_cfgp2p_get_conn_idx(cfg);
4552 struct ether_addr *p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
4553
4554 /* check if pre-registered mac matches the mac from dongle via WLC_E_LINK */
4555 if (memcmp(p2p_addr->octet, addr, ETH_ALEN)) {
4556 WL_INFORM_MEM(("p2p pre-regsitered mac:" MACDBG
4557 " , mac from dongle:" MACDBG "\n",
4558 MAC2STRDBG(p2p_addr->octet), MAC2STRDBG(addr)));
4559
4560 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4561
4562 wl_cfg80211_handle_hang_event(primary_ndev,
4563 HANG_REASON_IFACE_ADD_FAILURE, DUMP_TYPE_IFACE_OP_FAILURE);
4564 goto fail;
4565 }
4566 }
4567
4568#ifdef WL_STATIC_IF
4569 if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
4570 new_ndev = wl_cfg80211_post_static_ifcreate(cfg, event, addr, iface_type);
4571 if (!new_ndev) {
4572 WL_ERR(("failed to get I/F pointer\n"));
4573 return NULL;
4574 }
4575 wdev = new_ndev->ieee80211_ptr;
4576 } else
4577#endif /* WL_STATIC_IF */
4578 {
4579 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
4580 name, addr, event->bssidx, event->name);
4581 if (!new_ndev) {
4582 WL_ERR(("I/F allocation failed! \n"));
4583 return NULL;
4584 } else {
4585 WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
4586 event->ifidx, event->bssidx));
4587 }
4588
4589 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
4590 if (!wdev) {
4591 WL_ERR(("wireless_dev alloc failed! \n"));
4592 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4593 return NULL;
4594 }
4595
4596 wdev->wiphy = bcmcfg_to_wiphy(cfg);
4597 wdev->iftype = iface_type;
4598
4599 new_ndev->ieee80211_ptr = wdev;
4600#ifdef WLDWDS
4601 /* set wds0.x to 4addr interface here */
4602 if (event->role == WLC_E_IF_ROLE_WDS) {
4603 printf("\n\n\n event->role == WLC_E_IF_ROLE_WDS, set vwdev 4addr to %s\n", event->name);
4604 wdev->use_4addr = true;
4605 }
4606#endif /* WLDWDS */
4607 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4608
4609 memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
4610#ifdef WL_EXT_IAPSTA
4611 wl_ext_iapsta_ifadding(new_ndev, event->ifidx);
4612#endif /* WL_EXT_IAPSTA */
4613 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd)
4614 != BCME_OK) {
4615 WL_ERR(("IFACE register failed \n"));
4616 /* Post interface registration, wdev would be freed from the netdev
4617 * destructor path. For other cases, handle it here.
4618 */
4619 MFREE(cfg->osh, wdev, sizeof(*wdev));
4620 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4621 return NULL;
4622 }
4623 }
4624
4625 /* Initialize with the station mode params */
4626 ret = wl_alloc_netinfo(cfg, new_ndev, wdev, wl_iftype,
4627 PM_ENABLE, event->bssidx, event->ifidx);
4628 if (unlikely(ret)) {
4629 WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret));
4630 goto fail;
4631 }
4632
4633 /* Apply the mode & infra setting based on iftype */
4634 if ((ret = wl_config_infra(cfg, new_ndev, wl_iftype)) < 0) {
4635 WL_ERR(("config ifmode failure (%d)\n", ret));
4636 goto fail;
4637 }
4638
4639 if (mode == WL_MODE_AP) {
4640 wl_set_drv_status(cfg, AP_CREATING, new_ndev);
4641 }
4642#ifdef WL_EXT_IAPSTA
4643 wl_ext_iapsta_update_iftype(new_ndev, event->ifidx, wl_iftype);
4644#endif
4645
4646 WL_INFORM_MEM(("Network Interface (%s) registered with host."
4647 " cfg_iftype:%d wl_role:%d " MACDBG "\n",
4648 new_ndev->name, iface_type, event->role, MAC2STRDBG(new_ndev->dev_addr)));
4649
4650#ifdef SUPPORT_SET_CAC
4651 wl_cfg80211_set_cac(cfg, 0);
4652#endif /* SUPPORT_SET_CAC */
4653
4654 return new_ndev;
4655
4656fail:
4657#ifdef WL_STATIC_IF
4658 /* remove static if from iflist */
4659 if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
4660 cfg->static_ndev_state = NDEV_STATE_FW_IF_FAILED;
4661 wl_cfg80211_update_iflist_info(cfg, new_ndev, WL_STATIC_IFIDX, addr,
4662 event->bssidx, event->name, NDEV_STATE_FW_IF_FAILED);
4663 }
4664#endif /* WL_STATIC_IF */
4665 if (new_ndev) {
4666 /* wdev would be freed from netdev destructor call back */
4667 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4668 }
4669
4670 return NULL;
4671}
4672
4673s32
4674wl_cfg80211_delete_iface(struct bcm_cfg80211 *cfg,
4675 wl_iftype_t sec_data_if_type)
4676{
4677 struct net_info *iter, *next;
4678 struct net_device *primary_ndev;
4679 s32 ret = BCME_OK;
4680 uint8 i = 0;
4681
4682 BCM_REFERENCE(i);
4683 BCM_REFERENCE(ret);
4684
4685 /* Note: This function will clean up only the network interface and host
4686 * data structures. The firmware interface clean up will happen in the
4687 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4688 * context for the module case).
4689 */
4690 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4691 WL_DBG(("Enter, deleting iftype %s\n",
4692 wl_iftype_to_str(sec_data_if_type)));
4693 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4694 for_each_ndev(cfg, iter, next) {
4695 GCC_DIAGNOSTIC_POP();
4696 if (iter->ndev && (iter->ndev != primary_ndev)) {
4697 if (iter->iftype != sec_data_if_type) {
4698 continue;
4699 }
4700 switch (sec_data_if_type) {
4701 case WL_IF_TYPE_P2P_GO:
4702 case WL_IF_TYPE_P2P_GC: {
4703 ret = _wl_cfg80211_del_if(cfg,
4704 iter->ndev, NULL, iter->ndev->name);
4705 break;
4706 }
4707#ifdef WL_NAN
4708 case WL_IF_TYPE_NAN: {
4709 if (wl_cfgnan_is_enabled(cfg) == false) {
4710 WL_INFORM_MEM(("Nan is not active,"
4711 " ignore NDI delete\n"));
4712 } else {
4713 ret = wl_cfgnan_delete_ndp(cfg, iter->ndev);
4714 }
4715 break;
4716 }
4717#endif /* WL_NAN */
4718 case WL_IF_TYPE_AP: {
4719 /* Cleanup AP */
4720#ifdef WL_STATIC_IF
4721 /* handle static ap */
4722 if (IS_CFG80211_STATIC_IF(cfg, iter->ndev)) {
4723 dev_close(iter->ndev);
4724 } else
4725#endif /* WL_STATIC_IF */
4726 {
4727 /* handle virtual created AP */
4728 ret = _wl_cfg80211_del_if(cfg, iter->ndev,
4729 NULL, iter->ndev->name);
4730 }
4731 break;
4732 }
4733 default: {
4734 WL_ERR(("Unsupported interface type\n"));
4735 ret = -ENOTSUPP;
4736 goto fail;
4737 }
4738 }
4739 }
4740 }
4741fail:
4742 return ret;
4743}
4744
4745void
4746wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 *cfg, bool rtnl_lock_reqd)
4747{
4748 struct net_info *iter, *next;
4749 struct net_device *primary_ndev;
4750
4751 /* Note: This function will clean up only the network interface and host
4752 * data structures. The firmware interface clean up will happen in the
4753 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4754 * context for the module case).
4755 */
4756 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4757 WL_DBG(("Enter\n"));
4758 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4759 for_each_ndev(cfg, iter, next) {
4760 GCC_DIAGNOSTIC_POP();
4761 if (iter->ndev && (iter->ndev != primary_ndev)) {
4762 /* Ensure interfaces are down before deleting */
4763#ifdef WL_STATIC_IF
4764 /* Avoiding cleaning static ifaces */
4765 if (!IS_CFG80211_STATIC_IF(cfg, iter->ndev))
4766#endif /* WL_STATIC_IF */
4767 {
4768 dev_close(iter->ndev);
4769 WL_DBG(("Cleaning up iface:%s \n", iter->ndev->name));
4770 wl_cfg80211_post_ifdel(iter->ndev, rtnl_lock_reqd, 0);
4771 }
4772 }
4773 }
4774}
4775
4776s32
4777wl_cfg80211_post_ifdel(struct net_device *ndev, bool rtnl_lock_reqd, s32 ifidx)
4778{
4779 s32 ret = BCME_OK;
4780 struct bcm_cfg80211 *cfg;
4781 struct net_info *netinfo = NULL;
4782
4783 if (!ndev || !ndev->ieee80211_ptr) {
4784 /* No wireless dev done for this interface */
4785 ret = -EINVAL;
4786 goto exit;
4787 }
4788
4789 cfg = wl_get_cfg(ndev);
4790 if (!cfg) {
4791 WL_ERR(("cfg null\n"));
4792 ret = BCME_ERROR;
4793 goto exit;
4794 }
4795
4796 if (ifidx <= 0) {
4797 WL_ERR(("Invalid IF idx for iface:%s\n", ndev->name));
4798 ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
4799 BCM_REFERENCE(ifidx);
4800 if (ifidx <= 0) {
4801 ASSERT(0);
4802 ret = BCME_ERROR;
4803 goto exit;
4804 }
4805 }
4806
4807 if ((netinfo = wl_get_netinfo_by_wdev(cfg, ndev_to_wdev(ndev))) == NULL) {
4808 WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev)));
4809 ret = -ENODEV;
4810 goto exit;
4811 }
4812
4813#ifdef WL_STATIC_IF
4814 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
4815 ret = wl_cfg80211_post_static_ifdel(cfg, ndev);
4816 } else
4817#endif /* WL_STATIC_IF */
4818 {
4819 WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
4820 ndev->name, ifidx, cfg->vif_count));
4821 wl_cfg80211_remove_if(cfg, ifidx, ndev, rtnl_lock_reqd);
4822 cfg->bss_pending_op = FALSE;
4823 }
4824
4825#ifdef SUPPORT_SET_CAC
4826 wl_cfg80211_set_cac(cfg, 1);
4827#endif /* SUPPORT_SET_CAC */
4828exit:
4829 return ret;
4830}
4831
4832int
4833wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 *cfg)
4834{
4835 s32 ret = BCME_OK;
4836 bcm_struct_cfgdev *cfgdev;
4837
4838 if (cfg->p2p) {
4839 /* De-initialize the p2p discovery interface, if operational */
4840 WL_ERR(("Disabling P2P Discovery Interface \n"));
4841#ifdef WL_CFG80211_P2P_DEV_IF
4842 cfgdev = bcmcfg_to_p2p_wdev(cfg);
4843#else
4844 cfgdev = cfg->p2p_net;
4845#endif
4846 if (cfgdev) {
4847 ret = wl_cfg80211_scan_stop(cfg, cfgdev);
4848 if (unlikely(ret < 0)) {
4849 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
4850 }
4851 }
4852
4853 wl_cfgp2p_disable_discovery(cfg);
4854 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
4855 p2p_on(cfg) = false;
4856 }
4857 return ret;
4858}
4859
4860/* Create a Generic Network Interface and initialize it depending up on
4861 * the interface type
4862 */
4863struct wireless_dev *
4864wl_cfg80211_create_iface(struct wiphy *wiphy,
4865 wl_iftype_t wl_iftype,
4866 u8 *mac_addr, const char *name)
4867{
4868 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4869 struct net_device *new_ndev = NULL;
4870 struct net_device *primary_ndev = NULL;
4871 s32 ret = BCME_OK;
4872 s32 bsscfg_idx = 0;
4873 long timeout;
4874 wl_if_event_info *event = NULL;
4875 u8 addr[ETH_ALEN];
4876 struct net_info *iter, *next;
4877
4878 WL_DBG(("Enter\n"));
4879 if (!name) {
4880 WL_ERR(("Interface name not provided\n"));
4881 return NULL;
4882 }
4883 else {
4884 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4885 for_each_ndev(cfg, iter, next) {
4886 GCC_DIAGNOSTIC_POP();
4887 if (iter->ndev) {
4888 if (strncmp(iter->ndev->name, name, strlen(name)) == 0) {
4889 WL_ERR(("Interface name,%s exists!\n", iter->ndev->name));
4890 return NULL;
4891 }
4892 }
4893 }
4894 }
4895 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4896 if (likely(!mac_addr)) {
4897 /* Use primary MAC with the locally administered bit for the
4898 * Secondary STA I/F
4899 */
4900 memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
4901 addr[0] |= 0x02;
4902 } else {
4903 /* Use the application provided mac address (if any) */
4904 memcpy(addr, mac_addr, ETH_ALEN);
4905 }
4906
4907 cfg->bss_pending_op = TRUE;
4908 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
4909
4910 /*
4911 * Intialize the firmware I/F.
4912 */
4913
4914 {
4915 ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
4916 wl_iftype, 0, addr);
4917 }
4918 if (ret == BCME_UNSUPPORTED) {
4919 /* Use bssidx 1 by default */
4920 bsscfg_idx = 1;
4921 if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
4922 bsscfg_idx, wl_iftype, 0, addr)) < 0) {
4923 goto exit;
4924 }
4925 } else if (ret < 0) {
4926 WL_ERR(("Interface create failed!! ret:%d \n", ret));
4927 goto exit;
4928 } else {
4929 /* Success */
4930 bsscfg_idx = ret;
4931 }
4932
4933 WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
4934 /*
4935 * Wait till the firmware send a confirmation event back.
4936 */
4937 WL_DBG(("Wait for the FW I/F Event\n"));
4938 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4939 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4940 if (timeout <= 0 || cfg->bss_pending_op) {
4941 WL_ERR(("ADD_IF event, didn't come. Return. timeout:%lu bss_pending_op:%d\n",
4942 timeout, cfg->bss_pending_op));
4943 if (timeout == -ERESTARTSYS) {
4944 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
4945 }
4946 goto exit;
4947 }
4948
4949 event = &cfg->if_event_info;
4950 /*
4951 * Since FW operation is successful,we can go ahead with the
4952 * the host interface creation.
4953 */
4954 new_ndev = wl_cfg80211_post_ifcreate(primary_ndev,
4955 event, addr, name, false);
4956
4957 if (new_ndev) {
4958 /* Iface post ops successful. Return ndev/wdev ptr */
4959 return new_ndev->ieee80211_ptr;
4960 }
4961
4962exit:
4963 cfg->bss_pending_op = FALSE;
4964 return NULL;
4965}
4966
4967s32
4968wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
4969{
4970 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4971 struct net_device *ndev = NULL;
4972 s32 ret = BCME_OK;
4973 s32 bsscfg_idx = 1;
4974 long timeout;
4975 u16 wl_iftype;
4976 u16 wl_mode;
4977
4978 WL_DBG(("Enter\n"));
4979
4980 /* If any scan is going on, abort it */
4981 if (wl_get_drv_status_all(cfg, SCANNING)) {
4982 WL_DBG(("Scan in progress. Aborting the scan!\n"));
4983 wl_cfg80211_cancel_scan(cfg);
4984 }
4985
4986 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, wdev);
4987 if (bsscfg_idx <= 0) {
4988 /* validate bsscfgidx */
4989 WL_ERR(("Wrong bssidx! \n"));
4990 return -EINVAL;
4991 }
4992
4993 /* Handle p2p iface */
4994 if ((ret = wl_cfg80211_p2p_if_del(wiphy, wdev)) != BCME_NOTFOUND) {
4995 WL_DBG(("P2P iface del handled \n"));
4996#ifdef SUPPORT_SET_CAC
4997 wl_cfg80211_set_cac(cfg, 1);
4998#endif /* SUPPORT_SET_CAC */
4999 return ret;
5000 }
5001
5002 ndev = wdev->netdev;
5003 if (unlikely(!ndev)) {
5004 WL_ERR(("ndev null! \n"));
5005 return -EINVAL;
5006 }
5007
5008 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
5009
5010 if (cfg80211_to_wl_iftype(ndev->ieee80211_ptr->iftype,
5011 &wl_iftype, &wl_mode) < 0) {
5012 return -EINVAL;
5013 }
5014
5015 WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d",
5016 bsscfg_idx, ndev->ieee80211_ptr->iftype, wl_iftype));
5017 /* Delete the firmware interface. "interface_remove" command
5018 * should go on the interface to be deleted
5019 */
5020 if (wl_cfg80211_get_bus_state(cfg)) {
5021 WL_ERR(("Bus state is down: %d\n", __LINE__));
5022 ret = BCME_DONGLE_DOWN;
5023 goto exit;
5024 }
5025
5026 cfg->bss_pending_op = true;
5027 ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx,
5028 wl_iftype, 1, NULL);
5029 if (ret == BCME_UNSUPPORTED) {
5030 if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
5031 bsscfg_idx, wl_iftype, true, NULL)) < 0) {
5032 WL_ERR(("DEL bss failed ret:%d \n", ret));
5033 goto exit;
5034 }
5035 } else if ((ret == BCME_NOTAP) || (ret == BCME_NOTSTA)) {
5036 /* De-init sequence involving role downgrade not happened.
5037 * Do nothing and return error. The del command should be
5038 * retried.
5039 */
5040 WL_ERR(("ifdel role mismatch:%d\n", ret));
5041 ret = -EBADTYPE;
5042 goto exit;
5043 } else if (ret < 0) {
5044 WL_ERR(("Interface DEL failed ret:%d \n", ret));
5045 goto exit;
5046 }
5047
5048 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
5049 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
5050 if (timeout <= 0 || cfg->bss_pending_op) {
5051 WL_ERR(("timeout in waiting IF_DEL event\n"));
5052 /* The interface unregister will happen from wifi reset context */
5053 ret = -ETIMEDOUT;
5054 /* fall through */
5055 }
5056
5057exit:
5058 if (ret < 0) {
5059 WL_ERR(("iface del failed:%d\n", ret));
5060#ifdef WL_STATIC_IF
5061 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
5062 /*
5063 * For static interface, clean up the host data,
5064 * irrespective of fw status. For dynamic
5065 * interfaces it gets cleaned from dhd_stop context
5066 */
5067 wl_cfg80211_post_static_ifdel(cfg, ndev);
5068 }
5069#endif /* WL_STATIC_IF */
5070 } else {
5071 ret = wl_cfg80211_post_ifdel(ndev, false, cfg->if_event_info.ifidx);
5072 if (unlikely(ret)) {
5073 WL_ERR(("post_ifdel failed\n"));
5074 }
5075 }
5076
5077 cfg->bss_pending_op = false;
5078 return ret;
5079}
5080
5081static s32
5082wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
5083 struct cfg80211_ibss_params *params)
5084{
5085 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5086 struct cfg80211_bss *bss;
5087 struct ieee80211_channel *chan;
5088 struct wl_join_params join_params;
5089 int scan_suppress;
5090 struct cfg80211_ssid ssid;
5091 s32 scan_retry = 0;
5092 s32 err = 0;
5093 size_t join_params_size;
5094 chanspec_t chanspec = 0;
5095
5096 WL_TRACE(("In\n"));
5097 RETURN_EIO_IF_NOT_UP(cfg);
5098 WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
5099 if (!params->ssid || params->ssid_len <= 0 ||
5100 params->ssid_len > DOT11_MAX_SSID_LEN) {
5101 WL_ERR(("Invalid parameter\n"));
5102 return -EINVAL;
5103 }
5104#if defined(WL_CFG80211_P2P_DEV_IF)
5105 chan = params->chandef.chan;
5106#else
5107 chan = params->channel;
5108#endif /* WL_CFG80211_P2P_DEV_IF */
5109 if (chan) {
5110 cfg->channel = wl_freq_to_chanspec(chan->center_freq);
5111 }
5112 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
5113 struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
5114 u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
5115 u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
5116 if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
5117 (memcmp(params->ssid, lssid->SSID, lssid->SSID_len) == 0) &&
5118 (*channel == cfg->channel))) {
5119 WL_ERR(("Connection already existed to " MACDBG "\n",
5120 MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
5121 return -EISCONN;
5122 }
5123 WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n",
5124 lssid->SSID, MAC2STRDBG(bssid)));
5125 }
5126
5127 /* remove the VSIE */
5128 wl_cfg80211_ibss_vsie_delete(dev);
5129
5130 bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
5131 if (!bss) {
5132 if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
5133 memcpy(ssid.ssid, params->ssid, params->ssid_len);
5134 ssid.ssid_len = params->ssid_len;
5135 do {
5136 if (unlikely
5137 (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
5138 -EBUSY)) {
5139 wl_delay(150);
5140 } else {
5141 break;
5142 }
5143 } while (++scan_retry < WL_SCAN_RETRY_MAX);
5144
5145 /* rtnl lock code is removed here. don't see why rtnl lock
5146 * needs to be released.
5147 */
5148
5149 /* wait 4 secons till scan done.... */
5150 schedule_timeout_interruptible(msecs_to_jiffies(4000));
5151
5152 bss = cfg80211_get_ibss(wiphy, NULL,
5153 params->ssid, params->ssid_len);
5154 }
5155 }
5156 if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
5157 ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
5158 !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
5159 cfg->ibss_starter = false;
5160 WL_DBG(("Found IBSS\n"));
5161 } else {
5162 cfg->ibss_starter = true;
5163 }
5164
5165 if (bss) {
5166 CFG80211_PUT_BSS(wiphy, bss);
5167 }
5168
5169 if (chan) {
5170 u32 bw_cap = 0;
5171 err = wl_get_bandwidth_cap(dev, CHSPEC_BAND(cfg->channel), &bw_cap);
5172 if (unlikely(err)) {
5173 WL_ERR(("Failed to get bandwidth capability (%d)\n", err));
5174 return err;
5175 }
5176 chanspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(cfg->channel),
5177 bw_cap, CHSPEC_BAND(cfg->channel));
5178 }
5179
5180 /*
5181 * Join with specific BSSID and cached SSID
5182 * If SSID is zero join based on BSSID only
5183 */
5184 bzero(&join_params, sizeof(join_params));
5185 memcpy((void *)join_params.ssid.SSID, (const void *)params->ssid,
5186 params->ssid_len);
5187 join_params.ssid.SSID_len = htod32(params->ssid_len);
5188 if (params->bssid) {
5189 memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
5190 err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
5191 ETHER_ADDR_LEN);
5192 if (unlikely(err)) {
5193 WL_ERR(("Error (%d)\n", err));
5194 return err;
5195 }
5196 } else
5197 bzero(&join_params.params.bssid, ETHER_ADDR_LEN);
5198
5199 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5200 scan_suppress = TRUE;
5201 /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
5202 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5203 &scan_suppress, sizeof(int));
5204 if (unlikely(err)) {
5205 WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
5206 return err;
5207 }
5208 }
5209
5210 join_params.params.chanspec_list[0] = chanspec;
5211 join_params.params.chanspec_num = 1;
5212 wldev_iovar_setint(dev, "chanspec", chanspec);
5213 join_params_size = sizeof(join_params);
5214
5215 /* Disable Authentication, IBSS will add key if it required */
5216 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
5217 wldev_iovar_setint(dev, "wsec", 0);
5218
5219 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
5220 join_params_size);
5221 if (unlikely(err)) {
5222 WL_ERR(("IBSS set_ssid Error (%d)\n", err));
5223 return err;
5224 }
5225
5226 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5227 scan_suppress = FALSE;
5228 /* Reset the SCAN SUPPRESS Flag */
5229 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5230 &scan_suppress, sizeof(int));
5231 if (unlikely(err)) {
5232 WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
5233 return err;
5234 }
5235 }
5236 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
5237 wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
5238#ifdef WLAIBSS
5239 cfg->aibss_txfail_seq = 0; /* initialize the sequence */
5240#endif /* WLAIBSS */
5241#ifdef WL_RELMCAST
5242 cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
5243#endif /* WL_RELMCAST */
5244 return err;
5245}
5246
5247static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
5248{
5249 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5250 s32 err = 0;
5251 scb_val_t scbval;
5252 u8 *curbssid;
5253
5254 RETURN_EIO_IF_NOT_UP(cfg);
5255 wl_link_down(cfg);
5256
5257 WL_INFORM_MEM(("Leave IBSS\n"));
5258 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
5259 wl_set_drv_status(cfg, DISCONNECTING, dev);
5260 scbval.val = 0;
5261 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
5262 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
5263 sizeof(scb_val_t));
5264 if (unlikely(err)) {
5265 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5266 WL_ERR(("error(%d)\n", err));
5267 return err;
5268 }
5269
5270 /* remove the VSIE */
5271 wl_cfg80211_ibss_vsie_delete(dev);
5272
5273 return err;
5274}
5275
5276#ifdef MFP
5277static
5278int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie,
5279 const u8** rsn_cap)
5280{
5281 u16 suite_count;
5282 const wpa_suite_mcast_t *mcast;
5283 const wpa_suite_ucast_t *ucast;
5284 int len;
5285 const wpa_suite_auth_key_mgmt_t *mgmt;
5286
5287 if (!wpa2ie)
5288 return BCME_BADARG;
5289
5290 len = wpa2ie->len;
5291
5292 /* check for Multicast cipher suite */
5293 if ((len -= (WPA_SUITE_LEN + WPA2_VERSION_LEN)) <= 0) {
5294 return BCME_NOTFOUND;
5295 }
5296
5297 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
5298
5299 /* Check for the unicast suite(s) */
5300 if (len < WPA_IE_SUITE_COUNT_LEN) {
5301 return BCME_NOTFOUND;
5302 }
5303
5304 ucast = (const wpa_suite_ucast_t *)&mcast[1];
5305 suite_count = ltoh16_ua(&ucast->count);
5306 if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
5307 (len -= (WPA_IE_SUITE_COUNT_LEN +
5308 (WPA_SUITE_LEN * suite_count))) <= 0)
5309 return BCME_BADLEN;
5310
5311 /* Check for AUTH key management suite(s) */
5312 if (len < WPA_IE_SUITE_COUNT_LEN) {
5313 return BCME_NOTFOUND;
5314 }
5315
5316 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
5317 suite_count = ltoh16_ua(&mgmt->count);
5318
5319 if ((suite_count <= NL80211_MAX_NR_CIPHER_SUITES) &&
5320 (len -= (WPA_IE_SUITE_COUNT_LEN +
5321 (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
5322 rsn_cap[0] = (const u8 *)&mgmt->list[suite_count];
5323 } else {
5324 return BCME_BADLEN;
5325 }
5326
5327 return BCME_OK;
5328}
5329#endif /* MFP */
5330
5331static s32
5332wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
5333{
5334 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5335 struct wl_security *sec;
5336 s32 val = 0;
5337 s32 err = 0;
5338 s32 bssidx;
5339
5340 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5341 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5342 return BCME_ERROR;
5343 }
5344
5345 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
5346 val = WPA_AUTH_PSK |
5347 WPA_AUTH_UNSPECIFIED;
5348 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
5349 val = WPA2_AUTH_PSK|
5350 WPA2_AUTH_UNSPECIFIED;
5351 else
5352 val = WPA_AUTH_DISABLED;
5353
5354 if (is_wps_conn(sme))
5355 val = WPA_AUTH_DISABLED;
5356
5357#ifdef BCMWAPI_WPI
5358 if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) {
5359 WL_DBG((" * wl_set_wpa_version, set wpa_auth"
5360 " to WPA_AUTH_WAPI 0x400"));
5361 val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5362 }
5363#endif
5364
5365 WL_DBG_MEM(("[%s] wl wpa_auth 0x%0x\n", dev->name, val));
5366 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
5367 if (unlikely(err)) {
5368 WL_ERR(("set wpa_auth failed (%d)\n", err));
5369 return err;
5370 }
5371 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5372 sec->wpa_versions = sme->crypto.wpa_versions;
5373 return err;
5374}
5375
5376#ifdef BCMWAPI_WPI
5377static s32
5378wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme)
5379{
5380 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5381 s32 err = 0;
5382 s32 bssidx;
5383
5384 WL_DBG((" wl_set_set_wapi_ie\n"));
5385 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5386 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5387 return BCME_ERROR;
5388 }
5389
5390 err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", (const void *)sme->ie, sme->ie_len,
5391 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5392 if (unlikely(err)) {
5393 WL_ERR(("set_wapi_ie Error (%d)\n", err));
5394 return err;
5395 }
5396 WL_DBG_MEM(("wapi_ie successfully (%s)\n", dev->name));
5397 return err;
5398}
5399#endif /* BCMWAPI_WPI */
5400
5401static s32
5402wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
5403{
5404 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5405 struct wl_security *sec;
5406 s32 val = 0;
5407 s32 err = 0;
5408 s32 bssidx;
5409
5410 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5411 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5412 return BCME_ERROR;
5413 }
5414
5415 switch (sme->auth_type) {
5416 case NL80211_AUTHTYPE_OPEN_SYSTEM:
5417 val = WL_AUTH_OPEN_SYSTEM;
5418 WL_DBG(("open system\n"));
5419 break;
5420 case NL80211_AUTHTYPE_SHARED_KEY:
5421 val = WL_AUTH_SHARED_KEY;
5422 WL_DBG(("shared key\n"));
5423 break;
5424 case NL80211_AUTHTYPE_AUTOMATIC:
5425 val = WL_AUTH_OPEN_SHARED;
5426 WL_DBG(("automatic\n"));
5427 break;
5428#ifdef WL_FILS
5429 case NL80211_AUTHTYPE_FILS_SK:
5430 WL_DBG(("fils shared key\n"));
5431 val = WL_AUTH_FILS_SHARED;
5432 break;
5433 case NL80211_AUTHTYPE_FILS_SK_PFS:
5434 val = WL_AUTH_FILS_SHARED_PFS;
5435 WL_DBG(("fils shared key with pfs\n"));
5436 break;
5437 case NL80211_AUTHTYPE_FILS_PK:
5438 WL_DBG(("fils public key\n"));
5439 val = WL_AUTH_FILS_PUBLIC;
5440 break;
5441#endif /* WL_FILS */
5442#if defined(WL_SAE) || defined(WL_CLIENT_SAE)
5443 case NL80211_AUTHTYPE_SAE:
5444 if (!wl_is_pmkid_available(dev, sme->bssid)) {
5445 val = WL_AUTH_SAE_KEY;
5446 } else {
5447 /* Fw will choose right auth type
5448 * dynamically based on PMKID availability
5449 */
5450 val = WL_AUTH_OPEN_SHARED;
5451 }
5452 WL_DBG(("sae auth type %d\n", val));
5453 break;
5454#endif /* WL_SAE || WL_CLIENT_SAE */
5455 default:
5456 val = 2;
5457 WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
5458 break;
5459 }
5460
5461 WL_DBG_MEM(("[%s] wl auth 0x%0x \n", dev->name, val));
5462 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
5463 if (unlikely(err)) {
5464 WL_ERR(("set auth failed (%d)\n", err));
5465 return err;
5466 }
5467 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5468 sec->auth_type = sme->auth_type;
5469 sec->fw_auth = val;
5470 return err;
5471}
5472
5473#ifdef WL_CLIENT_SAE
5474static bool
5475wl_is_pmkid_available(struct net_device *dev, const u8 *bssid)
5476{
5477 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5478 int i;
5479 int npmkids = (cfg->pmk_list->pmkids.length - sizeof(uint16)*2) / sizeof(pmkid_v2_t);
5480
5481 /* check the bssid is null or not */
5482 if (!bssid) return FALSE;
5483
5484 for (i = 0; i < npmkids; i++) {
5485 if (!memcmp(bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid, ETHER_ADDR_LEN)) {
5486 WL_DBG(("FOUND PMKID\n"));
5487 return TRUE;
5488 }
5489 }
5490 WL_ERR(("PMKID NOT FOUND\n"));
5491 return FALSE;
5492}
5493#endif /* WL_CLIENT_SAE */
5494
5495static u32
5496wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)
5497{
5498 uint i;
5499
5500 for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5501 if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5502 return rsn_cipher_algo_lookup_tbl[i].wsec_algo;
5503 }
5504 }
5505 return WSEC_NONE;
5506}
5507
5508static u32
5509wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)
5510{
5511 uint i;
5512
5513 for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5514 if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5515 return rsn_cipher_algo_lookup_tbl[i].wsec_key_algo;
5516 }
5517 }
5518 return CRYPTO_ALGO_OFF;
5519}
5520
5521static u32
5522wl_rsn_akm_wpa_auth_lookup(uint32 akm)
5523{
5524 uint i;
5525
5526 for (i = 0; i < ARRAYSIZE(rsn_akm_wpa_auth_lookup_tbl); i++) {
5527 if (akm == rsn_akm_wpa_auth_lookup_tbl[i].akm_suite) {
5528 return rsn_akm_wpa_auth_lookup_tbl[i].wpa_auth;
5529 }
5530 }
5531 return WPA_AUTH_DISABLED;
5532}
5533
5534static s32
5535wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
5536{
5537 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5538 struct wl_security *sec;
5539 s32 pval = 0;
5540 s32 gval = 0;
5541 s32 err = 0;
5542 s32 wsec_val = 0;
5543
5544#ifdef BCMWAPI_WPI
5545 s32 wapi_val = 0;
5546 s32 val = 0;
5547#endif
5548
5549 s32 bssidx;
5550#ifdef WL_GCMP
5551 uint32 algos = 0, mask = 0;
5552#endif /* WL_GCMP */
5553
5554 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5555 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5556 return BCME_ERROR;
5557 }
5558
5559 if (sme->crypto.n_ciphers_pairwise) {
5560 pval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.ciphers_pairwise[0]);
5561 if (pval == WSEC_NONE) {
5562 WL_ERR(("Invalid cipher (0x%x)\n",
5563 sme->crypto.ciphers_pairwise[0]));
5564 return BCME_BADARG;
5565 }
5566 switch (sme->crypto.ciphers_pairwise[0]) {
5567
5568#ifdef BCMWAPI_WPI
5569 case WLAN_CIPHER_SUITE_SMS4:
5570 val = pval;
5571 err = wl_set_set_wapi_ie(dev, sme);
5572 if (unlikely(err)) {
5573 WL_DBG(("Set wapi ie failed \n"));
5574 return err;
5575 } else {
5576 WL_DBG(("Set wapi ie succeded\n"));
5577 }
5578 wapi_val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5579 WL_DBG_MEM(("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val, dev->name));
5580 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wapi_val, bssidx);
5581 if (unlikely(err)) {
5582 WL_ERR(("set wpa_auth failed (%d)\n", err));
5583 return err;
5584 }
5585 break;
5586#endif /* BCMWAPI_WPI */
5587
5588#ifdef WL_GCMP
5589 case WLAN_CIPHER_SUITE_GCMP:
5590 case WLAN_CIPHER_SUITE_GCMP_256:
5591 algos = KEY_ALGO_MASK(wl_rsn_cipher_wsec_key_algo_lookup(
5592 sme->crypto.ciphers_pairwise[0]));
5593 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
5594 break;
5595#endif /* WL_GCMP */
5596 default: /* No post processing required */
5597 break;
5598 }
5599 }
5600#if defined(BCMSUP_4WAY_HANDSHAKE)
5601 /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
5602 * handshake.
5603 * Note that the FW feature flag only exists on kernels that support the
5604 * FT-EAP AKM suite.
5605 */
5606 if (cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) {
5607 err = wldev_iovar_setint_bsscfg(dev, "sup_wpa", 1, bssidx);
5608 if (err) {
5609 WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err));
5610 return err;
5611 } else {
5612 WL_INFORM_MEM(("idsup enabled.\n"));
5613 }
5614 }
5615#endif /* BCMSUP_4WAY_HANDSHAKE */
5616 if (sme->crypto.cipher_group) {
5617 gval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.cipher_group);
5618 if (gval == WSEC_NONE) {
5619 WL_ERR(("invalid cipher group (0x%x)\n", sme->crypto.cipher_group));
5620 return BCME_BADARG;
5621 }
5622 switch (sme->crypto.cipher_group) {
5623
5624#ifdef BCMWAPI_WPI
5625 case WLAN_CIPHER_SUITE_SMS4:
5626 val = gval;
5627 break;
5628#endif
5629
5630#ifdef WL_GCMP
5631 case WLAN_CIPHER_SUITE_GCMP:
5632 case WLAN_CIPHER_SUITE_GCMP_256:
5633 algos = KEY_ALGO_MASK(
5634 wl_rsn_cipher_wsec_key_algo_lookup(sme->crypto.cipher_group));
5635 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
5636 break;
5637#endif /* WL_GCMP */
5638 default: /* No post processing required */
5639 break;
5640 }
5641 }
5642
5643 WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
5644#ifdef WL_GCMP
5645 WL_DBG(("algos:%x, mask:%x", algos, mask));
5646#endif /* WL_GCMP */
5647
5648 if (is_wps_conn(sme)) {
5649 if (sme->privacy) {
5650 wsec_val = 4;
5651 } else {
5652 /* WPS-2.0 allows no security */
5653 wsec_val = 0;
5654 }
5655 } else {
5656
5657#ifdef BCMWAPI_WPI
5658 if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) {
5659 WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
5660 wsec_val = val;
5661 } else
5662#endif
5663
5664 {
5665 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
5666 wsec_val = pval | gval;
5667 }
5668 }
5669
5670 WL_DBG_MEM(("[%s] wl wsec 0x%x\n", dev->name, wsec_val));
5671 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec_val, bssidx);
5672 if (unlikely(err)) {
5673 WL_ERR(("error (%d)\n", err));
5674 return err;
5675 }
5676#ifdef WL_GCMP
5677 if (wl_set_wsec_info_algos(dev, algos, mask)) {
5678 WL_ERR(("set wsec_info error (%d)\n", err));
5679 }
5680#endif /* WL_GCMP */
5681 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5682 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
5683 sec->cipher_group = sme->crypto.cipher_group;
5684 sec->fw_wsec = wsec_val;
5685 return err;
5686}
5687#ifdef WL_GCMP
5688static s32
5689wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask)
5690{
5691 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5692 s32 bssidx;
5693 s32 err = 0;
5694 wl_wsec_info_t *wsec_info;
5695 bcm_xtlv_t *wsec_info_tlv;
5696 uint16 tlv_data_len;
5697 uint32 tlv_data[2];
5698 uint32 param_len;
5699 uint8 * buf;
5700
5701 WL_DBG(("enter.\n"));
5702 if (!cfg) {
5703 return BCME_ERROR;
5704 }
5705 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5706 WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
5707 return BCME_ERROR;
5708 }
5709
5710 buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5711 if (!buf) {
5712 WL_ERR(("No memory"));
5713 return BCME_NOMEM;
5714 }
5715 wsec_info = (wl_wsec_info_t *)buf;
5716 wsec_info->version = WL_WSEC_INFO_VERSION;
5717 wsec_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
5718
5719 wsec_info->num_tlvs++;
5720 tlv_data_len = sizeof(tlv_data);
5721 tlv_data[0] = algos;
5722 tlv_data[1] = mask;
5723
5724 bcm_xtlv_pack_xtlv(wsec_info_tlv, WL_WSEC_INFO_BSS_ALGOS, tlv_data_len,
5725 (const uint8 *)tlv_data, 0);
5726 param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN + tlv_data_len;
5727
5728 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
5729 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5730
5731 MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5732 return err;
5733}
5734#endif /* WL_GCMP */
5735
5736#ifdef WL_SAE
5737s32
5738wl_cfg80211_set_wsec_info(struct net_device *dev, uint32 *data,
5739 uint16 data_len, int tag)
5740{
5741 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5742 s32 bssidx;
5743 s32 err = 0;
5744 wl_wsec_info_t *wsec_info;
5745 bcm_xtlv_t *bcm_info_tlv;
5746 uint32 param_len;
5747 uint8 *buf = NULL;
5748
5749 if (!cfg) {
5750 return BCME_ERROR;
5751 }
5752
5753 if (data_len > WLC_IOCTL_SMLEN) {
5754 err = BCME_BADLEN;
5755 goto exit;
5756 }
5757
5758 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5759 WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
5760 err = BCME_ERROR;
5761 goto exit;
5762 }
5763
5764 buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + data_len);
5765 if (!buf) {
5766 WL_ERR(("No memory"));
5767 err = BCME_NOMEM;
5768 goto exit;
5769 }
5770
5771 wsec_info = (wl_wsec_info_t *)buf;
5772 bzero(wsec_info, sizeof(wl_wsec_info_t) + data_len);
5773 wsec_info->version = WL_WSEC_INFO_VERSION;
5774 bcm_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
5775
5776 wsec_info->num_tlvs++;
5777
5778 bcm_xtlv_pack_xtlv(bcm_info_tlv, tag, data_len, (const u8*)data, 0);
5779 param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN + data_len;
5780
5781 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
5782 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5783 if (unlikely(err)) {
5784 WL_ERR(("set wsec_info error (%d)\n", err));
5785 }
5786
5787exit:
5788 if (buf)
5789 MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + data_len);
5790 return err;
5791}
5792#endif /* SAE */
5793
5794#ifdef MFP
5795static s32
5796wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
5797 struct net_device *dev,
5798 struct cfg80211_connect_params *sme)
5799{
5800 s32 mfp = WL_MFP_NONE;
5801 s32 current_mfp = WL_MFP_NONE;
5802 const bcm_tlv_t *wpa2_ie;
5803 const u8* rsn_cap = NULL;
5804 bool fw_support = false;
5805 int err, count = 0;
5806 const u8 *eptr = NULL, *ptr = NULL;
5807 const u8* group_mgmt_cs = NULL;
5808 const wpa_pmkid_list_t* pmkid = NULL;
5809 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5810
5811 if (!sme) {
5812 /* No connection params from userspace, Do nothing. */
5813 return 0;
5814 }
5815
5816 /* Check fw support and retreive current mfp val */
5817 err = wldev_iovar_getint(dev, "mfp", &current_mfp);
5818 if (!err) {
5819 fw_support = true;
5820 }
5821
5822 /* Parse the wpa2ie to decode the MFP capablity */
5823 if (((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
5824 DOT11_MNG_RSN_ID)) != NULL) &&
5825 (wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) {
5826 WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap[0], rsn_cap[1]));
5827 /* Check for MFP cap in the RSN capability field */
5828#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
5829 if (sme->mfp)
5830#endif
5831 {
5832 if (rsn_cap[0] & RSN_CAP_MFPR) {
5833 mfp = WL_MFP_REQUIRED;
5834 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
5835 mfp = WL_MFP_CAPABLE;
5836 }
5837 }
5838 /*
5839 * eptr --> end/last byte addr of wpa2_ie
5840 * ptr --> to keep track of current/required byte addr
5841 */
5842 eptr = (const u8*)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN);
5843 /* pointing ptr to the next byte after rns_cap */
5844 ptr = (const u8*)rsn_cap + RSN_CAP_LEN;
5845 if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) {
5846 /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
5847 pmkid = (const wpa_pmkid_list_t*)ptr;
5848 count = pmkid->count.low | (pmkid->count.high << 8);
5849 /* ptr now to point to last byte addr of pmkid */
5850 ptr = (const u8*)pmkid + (count * WPA2_PMKID_LEN
5851 + WPA2_PMKID_COUNT_LEN);
5852 if ((eptr - ptr) >= WPA_SUITE_LEN) {
5853 /* group_mgmt_cs now to point to first byte addr of bip */
5854 group_mgmt_cs = ptr;
5855 }
5856 }
5857 }
5858
5859 WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n",
5860 mfp, wpa2_ie, fw_support));
5861
5862 if (fw_support == false) {
5863 if (mfp == WL_MFP_REQUIRED) {
5864 /* if mfp > 0, mfp capability set in wpa ie, but
5865 * FW indicated error for mfp. Propagate the error up.
5866 */
5867 WL_ERR(("mfp capability found in wpaie. But fw doesn't "
5868 "seem to support MFP\n"));
5869 err = -EINVAL;
5870 goto exit;
5871 } else {
5872 /* Firmware doesn't support mfp. But since connection request
5873 * is for non-mfp case, don't bother.
5874 */
5875 err = BCME_OK;
5876 goto exit;
5877 }
5878 } else if (mfp != current_mfp) {
5879 /* Some FW brances report error (-5) during MFP set if the BSS
5880 * is up (roam case). Typically in roaming cases, the MFP
5881 * configuration doesn't change. So in roam/reassoc cases, there is
5882 * no need to update the fw state. If we still hit corner cases
5883 * throwing (-5) error, we need to pull in RB:59117.
5884 */
5885 err = wldev_iovar_setint(dev, "mfp", mfp);
5886 if (unlikely(err)) {
5887 WL_ERR(("mfp (%d) set failed ret:%d \n", mfp, err));
5888 goto exit;
5889 }
5890 WL_DBG_MEM(("[%s] wl mfp 0x%x\n", dev->name, mfp));
5891 }
5892
5893 if (sec) {
5894 sec->fw_mfp = mfp;
5895 }
5896
5897 if (group_mgmt_cs && bcmp((const uint8 *)WPA2_OUI,
5898 group_mgmt_cs, (WPA_SUITE_LEN - 1)) == 0) {
5899 WL_DBG(("BIP is found\n"));
5900 err = wldev_iovar_setbuf(dev, "bip",
5901 group_mgmt_cs, WPA_SUITE_LEN, cfg->ioctl_buf,
5902 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5903 /*
5904 * Dont return failure for unsupported cases
5905 * of bip iovar for backward compatibility
5906 */
5907 if (err != BCME_UNSUPPORTED && err < 0) {
5908 WL_ERR(("bip set error (%d)\n", err));
5909
5910 {
5911 goto exit;
5912 }
5913 } else {
5914 WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n",
5915 dev->name, group_mgmt_cs[0], group_mgmt_cs[1],
5916 group_mgmt_cs[2]));
5917 }
5918 }
5919exit:
5920 if (err) {
5921 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
5922 FW_LOGSET_MASK_ALL);
5923 }
5924
5925 return 0;
5926}
5927#endif /* MFP */
5928
5929#ifdef WL_FILS
5930bool
5931wl_is_fils_supported(struct net_device *ndev)
5932{
5933 s32 err;
5934 u8 ioctl_buf[WLC_IOCTL_SMLEN] = {0};
5935 bcm_iov_buf_t *iov_buf = (bcm_iov_buf_t *)ioctl_buf;
5936
5937 iov_buf->version = WL_FILS_IOV_VERSION;
5938 err = wldev_iovar_getbuf(ndev, "fils", (uint8*)iov_buf, sizeof(bcm_iov_buf_t),
5939 iov_buf, WLC_IOCTL_SMLEN, NULL);
5940 if (err == BCME_UNSUPPORTED) {
5941 WL_DBG(("FILS NOT supported\n"));
5942 return false;
5943 }
5944
5945 WL_INFORM(("FILS supported\n"));
5946 return true;
5947}
5948
5949#define WL_NUM_OF_TLV_IN_SET_FILS_PARAMS 4u
5950static s32
5951wl_set_fils_params(struct net_device *dev, struct cfg80211_connect_params *sme)
5952{
5953 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5954 bcm_iov_buf_t *iov_buf = NULL;
5955 bcm_xtlvbuf_t tbuf;
5956 s32 err = BCME_OK;
5957 uint32 buf_size;
5958
5959 if ((sme->auth_type != NL80211_AUTHTYPE_FILS_SK) &&
5960 (sme->auth_type != NL80211_AUTHTYPE_FILS_SK_PFS) &&
5961 (sme->auth_type != NL80211_AUTHTYPE_FILS_PK)) {
5962 return BCME_OK;
5963 }
5964 if (sme->fils_erp_rrk_len > WL_MAX_FILS_KEY_LEN) {
5965 WL_ERR(("%s: FILS rRK exceed allowed size\n", __FUNCTION__));
5966 err = BCME_BADARG;
5967 goto exit;
5968 }
5969 /* Check incoming buffer length */
5970 buf_size = sme->fils_erp_username_len + sme->fils_erp_realm_len + sme->fils_erp_rrk_len +
5971 sizeof(sme->fils_erp_next_seq_num) +
5972 WL_NUM_OF_TLV_IN_SET_FILS_PARAMS * BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32) +
5973 sizeof(bcm_iov_buf_t) - 1u;
5974
5975 if (buf_size > WLC_IOCTL_SMLEN) {
5976 WL_ERR(("%s: FILS connect params arguments exceed allowed size\n", __FUNCTION__));
5977 err = BCME_BADARG;
5978 goto exit;
5979 }
5980 iov_buf = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
5981 if (!iov_buf) {
5982 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, WLC_IOCTL_SMLEN));
5983 err = BCME_NOMEM;
5984 goto exit;
5985 }
5986 iov_buf->version = WL_FILS_IOV_VERSION;
5987 iov_buf->id = WL_FILS_CMD_ADD_CONNECT_PARAMS;
5988 /* check if this should be len w/o headers */
5989 err = bcm_xtlv_buf_init(&tbuf, (uint8*)&iov_buf->data[0],
5990 WLC_IOCTL_SMLEN - sizeof(bcm_iov_buf_t) + sizeof(uint16),
5991 BCM_XTLV_OPTION_ALIGN32);
5992 if (err != BCME_OK) {
5993 WL_ERR(("%s: xtlv_context initialization failed\n", __FUNCTION__));
5994 goto exit;
5995 }
5996 if (sme->fils_erp_username_len && sme->fils_erp_username != NULL) {
5997 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_USERNAME,
5998 sme->fils_erp_username, sme->fils_erp_username_len);
5999 if (err != BCME_OK) {
6000 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
6001 goto exit;
6002 }
6003 }
6004 if (sme->fils_erp_realm_len && sme->fils_erp_realm != NULL) {
6005 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_REALM,
6006 sme->fils_erp_realm, sme->fils_erp_realm_len);
6007 if (err != BCME_OK) {
6008 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
6009 goto exit;
6010 }
6011 }
6012 if (sme->fils_erp_rrk_len && sme->fils_erp_rrk != NULL) {
6013 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_RRK,
6014 sme->fils_erp_rrk, sme->fils_erp_rrk_len);
6015 if (err != BCME_OK) {
6016 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
6017 goto exit;
6018 }
6019 }
6020 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM,
6021 (u8 *)&sme->fils_erp_next_seq_num, sizeof(sme->fils_erp_next_seq_num));
6022 if (err != BCME_OK) {
6023 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
6024 goto exit;
6025 }
6026 iov_buf->len = bcm_xtlv_buf_len(&tbuf);
6027 err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf->len + sizeof(bcm_iov_buf_t) -
6028 sizeof(uint16), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
6029 if (unlikely(err)) {
6030 WL_ERR(("set fils params ioctl error (%d)\n", err));
6031 goto exit;
6032 }
6033
6034exit:
6035 if (err != BCME_OK) {
6036 WL_ERR(("set FILS params error %d\n", err));
6037 }
6038 else {
6039 WL_DBG_MEM(("FILS parameters succesfully applied\n"));
6040 }
6041 if (iov_buf) {
6042 MFREE(cfg->osh, iov_buf, WLC_IOCTL_SMLEN);
6043 }
6044 return err;
6045}
6046
6047#if !defined(WL_FILS_ROAM_OFFLD) && defined(WL_FILS)
6048static s32
6049wl_get_bcn_timeout(struct net_device *dev, u32 *bcn_timeout)
6050{
6051 s32 err = 0;
6052
6053 err = wldev_iovar_getint(dev, "bcn_timeout", bcn_timeout);
6054 if (unlikely(err)) {
6055 WL_ERR(("could not get bcn_timeout (%d)\n", err));
6056 }
6057 return err;
6058}
6059
6060#define WL_ROAM_ENABLE 0
6061#define WL_ROAM_DISABLE 1
6062/* Beacon Timeout beacon loss in case FILS roaming offload is not supported by fw */
6063#define WL_BCN_TIMEOUT 3
6064
6065static s32
6066wl_fils_toggle_roaming(struct net_device *dev, u32 auth_type)
6067{
6068 s32 err = 0;
6069 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6070
6071 if (WPA2_AUTH_IS_FILS(auth_type) && !cfg->fils_info.fils_roam_disabled) {
6072 err = wl_get_bcn_timeout(dev, &cfg->fils_info.fils_bcn_timeout_cache);
6073 if (unlikely(err)) {
6074 return err;
6075 }
6076 wl_dongle_roam(dev, WL_ROAM_DISABLE, WL_BCN_TIMEOUT);
6077 cfg->fils_info.fils_roam_disabled = true;
6078 WL_DBG_MEM(("fw roam disabled for FILS akm\n"));
6079 } else if (cfg->fils_info.fils_roam_disabled) {
6080 /* Enable roaming back for other auth types */
6081 wl_dongle_roam(dev, WL_ROAM_ENABLE, cfg->fils_info.fils_bcn_timeout_cache);
6082 cfg->fils_info.fils_roam_disabled = false;
6083 WL_DBG_MEM(("fw roam enabled\n"));
6084 }
6085 return err;
6086}
6087#endif /* !WL_FILS_ROAM_OFFLD && WL_FILS */
6088#endif /* WL_FILS */
6089
6090static s32
6091wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
6092{
6093 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6094 struct wl_security *sec;
6095 s32 val = 0;
6096 s32 err = 0;
6097 s32 bssidx;
6098
6099 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6100 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6101 return BCME_ERROR;
6102 }
6103
6104 if (sme->crypto.n_akm_suites) {
6105 err = wldev_iovar_getint(dev, "wpa_auth", &val);
6106 if (unlikely(err)) {
6107 WL_ERR(("could not get wpa_auth (%d)\n", err));
6108 return err;
6109 }
6110 if (val & (WPA_AUTH_PSK |
6111 WPA_AUTH_UNSPECIFIED)) {
6112 switch (sme->crypto.akm_suites[0]) {
6113 case WLAN_AKM_SUITE_8021X:
6114 val = WPA_AUTH_UNSPECIFIED;
6115 break;
6116 case WLAN_AKM_SUITE_PSK:
6117 val = WPA_AUTH_PSK;
6118 break;
6119 default:
6120 WL_ERR(("invalid akm suite (0x%x)\n",
6121 sme->crypto.akm_suites[0]));
6122 return -EINVAL;
6123 }
6124 } else if (val & (WPA2_AUTH_PSK |
6125 WPA2_AUTH_UNSPECIFIED)) {
6126 switch (sme->crypto.akm_suites[0]) {
6127#ifdef MFP
6128
6129 case WL_AKM_SUITE_SHA256_1X:
6130 val = WPA2_AUTH_1X_SHA256;
6131 break;
6132 case WL_AKM_SUITE_SHA256_PSK:
6133 val = WPA2_AUTH_PSK_SHA256;
6134 break;
6135#endif /* MFP */
6136 case WLAN_AKM_SUITE_8021X:
6137 case WLAN_AKM_SUITE_PSK:
6138#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
6139 case WLAN_AKM_SUITE_FT_8021X:
6140#endif
6141#if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
6142 case WLAN_AKM_SUITE_FT_PSK:
6143#endif
6144 case WLAN_AKM_SUITE_FILS_SHA256:
6145 case WLAN_AKM_SUITE_FILS_SHA384:
6146 case WLAN_AKM_SUITE_8021X_SUITE_B:
6147 case WLAN_AKM_SUITE_8021X_SUITE_B_192:
6148#ifdef WL_OWE
6149 case WLAN_AKM_SUITE_OWE:
6150#endif /* WL_OWE */
6151#ifdef WL_SAE_FT
6152 case WLAN_AKM_SUITE_FT_OVER_SAE:
6153#endif /* WL_SAE_FT */
6154 case WLAN_AKM_SUITE_DPP:
6155 case WLAN_AKM_SUITE_FT_8021X_SHA384:
6156 val = wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[0]);
6157 break;
6158 case WLAN_AKM_SUITE_FT_FILS_SHA256:
6159 val = WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT;
6160 break;
6161 case WLAN_AKM_SUITE_FT_FILS_SHA384:
6162 val = WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT;
6163 break;
6164#if defined(WL_SAE) || defined(WL_CLIENT_SAE)
6165 case WLAN_AKM_SUITE_SAE:
6166 val = WPA3_AUTH_SAE_PSK;
6167 break;
6168#endif /* WL_SAE || WL_CLIENT_SAE */
6169 default:
6170 WL_ERR(("invalid akm suite (0x%x)\n",
6171 sme->crypto.akm_suites[0]));
6172 return -EINVAL;
6173 }
6174 }
6175
6176#ifdef BCMWAPI_WPI
6177 else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) {
6178 switch (sme->crypto.akm_suites[0]) {
6179 case WLAN_AKM_SUITE_WAPI_CERT:
6180 val = WAPI_AUTH_UNSPECIFIED;
6181 break;
6182 case WLAN_AKM_SUITE_WAPI_PSK:
6183 val = WAPI_AUTH_PSK;
6184 break;
6185 default:
6186 WL_ERR(("invalid akm suite (0x%x)\n",
6187 sme->crypto.akm_suites[0]));
6188 return -EINVAL;
6189 }
6190 }
6191#endif
6192
6193#ifdef WL_FILS
6194#if !defined(WL_FILS_ROAM_OFFLD)
6195 err = wl_fils_toggle_roaming(dev, val);
6196 if (unlikely(err)) {
6197 return err;
6198 }
6199#endif /* !WL_FILS_ROAM_OFFLD */
6200#endif /* !WL_FILS */
6201
6202#ifdef MFP
6203 if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) {
6204 WL_ERR(("MFP set failed err:%d\n", err));
6205 return -EINVAL;
6206 }
6207#endif /* MFP */
6208
6209 WL_DBG_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val));
6210 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
6211 if (unlikely(err)) {
6212 WL_ERR(("could not set wpa_auth (0x%x)\n", err));
6213 return err;
6214 }
6215 }
6216 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6217 sec->wpa_auth = sme->crypto.akm_suites[0];
6218 sec->fw_wpa_auth = val;
6219
6220 return err;
6221}
6222
6223static s32
6224wl_set_set_sharedkey(struct net_device *dev,
6225 struct cfg80211_connect_params *sme)
6226{
6227 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6228 struct wl_security *sec;
6229 struct wl_wsec_key key;
6230 s32 val;
6231 s32 err = 0;
6232 s32 bssidx;
6233
6234 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6235 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6236 return BCME_ERROR;
6237 }
6238
6239 WL_DBG(("key len (%d)\n", sme->key_len));
6240 if (sme->key_len) {
6241 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6242 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
6243 sec->wpa_versions, sec->cipher_pairwise));
6244 if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
6245 NL80211_WPA_VERSION_2)) &&
6246
6247#ifdef BCMWAPI_WPI
6248 !is_wapi(sec->cipher_pairwise) &&
6249#endif
6250
6251 (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
6252 WLAN_CIPHER_SUITE_WEP104)))
6253 {
6254 bzero(&key, sizeof(key));
6255 key.len = (u32) sme->key_len;
6256 key.index = (u32) sme->key_idx;
6257 if (unlikely(key.len > sizeof(key.data))) {
6258 WL_ERR(("Too long key length (%u)\n", key.len));
6259 return -EINVAL;
6260 }
6261 memcpy(key.data, sme->key, key.len);
6262 key.flags = WL_PRIMARY_KEY;
6263 if ((sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP40) ||
6264 (sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP104)) {
6265 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(sec->cipher_pairwise);
6266 } else {
6267 WL_ERR(("Invalid algorithm (%d)\n",
6268 sme->crypto.ciphers_pairwise[0]));
6269 return -EINVAL;
6270 }
6271 /* Set the new key/index */
6272 WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
6273 key.len, key.index, key.algo));
6274 WL_DBG(("key \"%s\"\n", key.data));
6275 swap_key_from_BE(&key);
6276 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6277 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6278 if (unlikely(err)) {
6279 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6280 return err;
6281 }
6282 WL_INFORM_MEM(("key applied to fw\n"));
6283 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
6284 WL_DBG(("set auth_type to shared key\n"));
6285 val = WL_AUTH_SHARED_KEY; /* shared key */
6286 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
6287 if (unlikely(err)) {
6288 WL_ERR(("set auth failed (%d)\n", err));
6289 return err;
6290 }
6291 }
6292 }
6293 }
6294 return err;
6295}
6296
6297#if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
6298static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
6299{
6300 u32 chanspec = 0;
6301 bool isvht80 = 0;
6302
6303 if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK)
6304 chanspec = wl_chspec_driver_to_host(chanspec);
6305
6306 isvht80 = chanspec & WL_CHANSPEC_BW_80;
6307 WL_DBG(("wl_get_chan_isvht80: chanspec(%x:%d)\n", chanspec, isvht80));
6308
6309 return isvht80;
6310}
6311#endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
6312
6313int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80211 *cfg,
6314 bool disassociate)
6315{
6316 scb_val_t scbval;
6317 int err = TRUE;
6318 int wait_cnt;
6319
6320 if (disassociate) {
6321 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6322 BCM_REFERENCE(dhdp);
6323 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
6324 dhd_net2idx(dhdp->info, dev), DOT11_RC_DISASSOC_LEAVING);
6325 WL_ERR(("Disassociate previous connection!\n"));
6326 wl_set_drv_status(cfg, DISCONNECTING, dev);
6327 scbval.val = DOT11_RC_DISASSOC_LEAVING;
6328 scbval.val = htod32(scbval.val);
6329
6330 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6331 sizeof(scb_val_t));
6332 if (unlikely(err)) {
6333 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6334 WL_ERR(("error (%d)\n", err));
6335 return err;
6336 }
6337 wait_cnt = 500/10;
6338 } else {
6339 wait_cnt = 200/10;
6340 WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
6341 if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6342 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6343 }
6344 }
6345
6346 while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
6347 WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
6348 wait_cnt));
6349 wait_cnt--;
6350 OSL_SLEEP(10);
6351 }
6352
6353 if (wait_cnt == 0) {
6354 WL_ERR(("DISCONNECING clean up failed!\n"));
6355 /* Clear DISCONNECTING driver status as we have made sufficient attempts
6356 * for driver clean up.
6357 */
6358 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6359 wl_clr_drv_status(cfg, CONNECTED, dev);
6360 return BCME_NOTREADY;
6361 }
6362 return BCME_OK;
6363}
6364
6365#ifdef WL_FILS
6366static int
6367wl_fils_add_hlp_container(struct bcm_cfg80211 *cfg, struct net_device *dev,
6368 const uint8* ie_buf, uint16 ie_len)
6369{
6370 const bcm_tlv_ext_t *hlp_ie;
6371
6372 if ((hlp_ie = (const bcm_tlv_ext_t*)bcm_parse_tlvs_dot11((const uint8 *)ie_buf, ie_len,
6373 FILS_HLP_CONTAINER_EXT_ID, TRUE))) {
6374 u16 hlp_len = hlp_ie->len;
6375 u16 left_len = (ie_len - ((const uint8*)hlp_ie - ie_buf));
6376 bcm_iov_buf_t *iov_buf = 0;
6377 uint8* pxtlv;
6378 int err;
6379 size_t iov_buf_len;
6380 bcm_tlv_dot11_frag_tot_len(ie_buf, ie_len, FILS_HLP_CONTAINER_EXT_ID,
6381 TRUE, (uint*)&hlp_len);
6382
6383 hlp_len += BCM_TLV_EXT_HDR_SIZE;
6384
6385 if ((hlp_len > DOT11_MAX_MPDU_BODY_LEN) || (hlp_len > left_len)) {
6386 WL_ERR(("bad HLP length %d\n", hlp_len));
6387 return EFAULT;
6388 }
6389 iov_buf_len = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) - 1 + hlp_len;
6390 iov_buf = MALLOCZ(cfg->osh, iov_buf_len);
6391 if (iov_buf == NULL) {
6392 WL_ERR(("failed to allocated iov_buf\n"));
6393 return ENOMEM;
6394 }
6395
6396 prhex("HLP, HLP", (const uchar *)hlp_ie, hlp_len);
6397
6398 pxtlv = (uint8 *)&iov_buf->data[0];
6399 ((bcm_xtlv_t*)pxtlv)->id = WL_FILS_XTLV_HLP_IE;
6400 ((bcm_xtlv_t*)pxtlv)->len = hlp_len;
6401
6402 memcpy(((bcm_xtlv_t*)pxtlv)->data, hlp_ie, ((bcm_xtlv_t*)pxtlv)->len);
6403
6404 iov_buf->version = WL_FILS_IOV_VERSION;
6405 iov_buf->id = WL_FILS_CMD_ADD_HLP_IE;
6406 iov_buf->len = ((sizeof(bcm_xtlv_t)-1) + ((bcm_xtlv_t*)pxtlv)->len);
6407
6408 err = wldev_iovar_setbuf(dev, "fils", iov_buf,
6409 sizeof(bcm_iov_buf_t) + iov_buf->len,
6410 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6411 if (unlikely(err)) {
6412 WL_ERR(("fils wldev_iovar_setbuf error (%d)\n", err));
6413 }
6414 else {
6415 WL_DBG_MEM(("FILS HLP Packet succesfully updated\n"));
6416 }
6417 MFREE(cfg->osh, iov_buf, iov_buf_len);
6418 }
6419 return BCME_OK;
6420}
6421#endif /* WL_FILS */
6422
6423#if defined(WL_FILS)
6424#ifndef UPDATE_FILS_ERP_INFO
6425#define UPDATE_FILS_ERP_INFO BIT(1)
6426#define UPDATE_AUTH_TYPE BIT(2)
6427#endif
6428
6429static int
6430wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
6431 struct cfg80211_connect_params *sme, u32 changed)
6432{
6433 s32 err = BCME_OK;
6434 if (changed & UPDATE_FILS_ERP_INFO) {
6435 err = wl_set_fils_params(dev, sme);
6436
6437 if (unlikely(err)) {
6438 WL_ERR(("Invalid FILS params\n"));
6439 goto exit;
6440 }
6441 }
6442 if (changed & UPDATE_AUTH_TYPE) {
6443 err = wl_set_auth_type(dev, sme);
6444 if (unlikely(err)) {
6445 WL_ERR(("Invalid auth type\n"));
6446 goto exit;
6447 }
6448 }
6449 if ((changed & UPDATE_FILS_ERP_INFO) && !(changed & UPDATE_AUTH_TYPE)) {
6450 WL_DBG(("Warning: FILS ERP params are set, but authentication type - not\n"));
6451 }
6452exit:
6453 return err;
6454
6455}
6456#endif /* WL_FILS */
6457
6458#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6459static s32
6460wl_config_roam_env_detection(struct bcm_cfg80211 *cfg, struct net_device *dev)
6461{
6462 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6463 s32 roam_trigger[2] = {0, 0};
6464 s32 err = BCME_OK;
6465
6466 if (dhdp->roam_env_detection && (dev == bcmcfg_to_prmry_ndev(cfg))) {
6467 bool is_roamtrig_reset = TRUE;
6468 bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection",
6469 AP_ENV_DETECT_NOT_USED) == BCME_OK);
6470#ifdef SKIP_ROAM_TRIGGER_RESET
6471 roam_trigger[1] = WLC_BAND_2G;
6472 is_roamtrig_reset =
6473 (wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
6474 sizeof(roam_trigger)) == BCME_OK) &&
6475 (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER-10);
6476#endif /* SKIP_ROAM_TRIGGER_RESET */
6477 if (is_roamtrig_reset && is_roam_env_ok) {
6478 roam_trigger[0] = WL_AUTO_ROAM_TRIGGER;
6479 roam_trigger[1] = WLC_BAND_ALL;
6480 err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
6481 sizeof(roam_trigger));
6482 if (unlikely(err)) {
6483 WL_ERR((" failed to restore roam_trigger for auto env"
6484 " detection. err:%d\n", err));
6485 }
6486 }
6487 }
6488 return err;
6489}
6490#endif /* ROAM_ENABLE && ROAMENV_DETECTION */
6491
6492s32
6493wl_do_preassoc_ops(struct bcm_cfg80211 *cfg,
6494 struct net_device *dev, struct cfg80211_connect_params *sme)
6495{
6496 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6497
6498 BCM_REFERENCE(dhdp);
6499 DHD_STATLOG_CTRL(dhdp, ST(ASSOC_START), dhd_net2idx(dhdp->info, dev), 0);
6500
6501#ifdef DHDTCPSYNC_FLOOD_BLK
6502 dhd_reset_tcpsync_info_by_dev(dev);
6503#endif /* DHDTCPSYNC_FLOOD_BLK */
6504
6505 if (wl_get_drv_status(cfg, SCANNING, dev)) {
6506 wl_cfg80211_cancel_scan(cfg);
6507 }
6508
6509#ifdef WL_SCHED_SCAN
6510 /* Locks are taken in wl_cfg80211_sched_scan_stop()
6511 * A start scan occuring during connect is unlikely
6512 */
6513 if (cfg->sched_scan_req) {
6514 struct wireless_dev *wdev = dev->ieee80211_ptr;
6515#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
6516 wl_cfg80211_sched_scan_stop(wdev->wiphy, bcmcfg_to_prmry_ndev(cfg),
6517 cfg->sched_scan_req->reqid);
6518#else
6519 wl_cfg80211_sched_scan_stop(wdev->wiphy, bcmcfg_to_prmry_ndev(cfg));
6520#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
6521 }
6522#endif /* WL_SCHED_SCAN */
6523#ifdef WL_CFG80211_GON_COLLISION
6524 /* init block gon req count */
6525 cfg->block_gon_req_tx_count = 0;
6526 cfg->block_gon_req_rx_count = 0;
6527#endif /* WL_CFG80211_GON_COLLISION */
6528
6529#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
6530 maxrxpktglom = 0;
6531#endif
6532
6533#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6534 if (wl_config_roam_env_detection(cfg, dev) != BCME_OK) {
6535 return BCME_ERROR;
6536 }
6537#endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
6538
6539#ifdef WLTDLS
6540 /* disable TDLS if number of connected interfaces is >= 1 */
6541 wl_cfg80211_tdls_config(cfg, TDLS_STATE_CONNECT, false);
6542#endif /* WLTDLS */
6543
6544#ifdef SUPPORT_AP_BWCTRL
6545 if (dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
6546 wl_restore_ap_bw(cfg);
6547 }
6548#endif /* SUPPORT_AP_BWCTRL */
6549#if defined(ROAMEXP_SUPPORT)
6550 /* Clear Blacklist bssid and Whitelist ssid list before join issue
6551 * This is temporary fix since currently firmware roaming is not
6552 * disabled by android framework before SSID join from framework
6553 */
6554 /* Flush blacklist bssid content */
6555 dhd_dev_set_blacklist_bssid(dev, NULL, 0, true);
6556 /* Flush whitelist ssid content */
6557 dhd_dev_set_whitelist_ssid(dev, NULL, 0, true);
6558#endif /* ROAMEXP_SUPPORT */
6559
6560 WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
6561 if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
6562 prhex(NULL, sme->ie, sme->ie_len);
6563 }
6564 /* Connection attempted via linux-wireless */
6565 wl_set_drv_status(cfg, CFG80211_CONNECT, dev);
6566 return BCME_OK;
6567}
6568
6569static s32
6570wl_config_assoc_security(struct bcm_cfg80211 *cfg,
6571 struct net_device *dev, struct cfg80211_connect_params *sme)
6572{
6573 s32 err = BCME_OK;
6574
6575 err = wl_set_wpa_version(dev, sme);
6576 if (unlikely(err)) {
6577 WL_ERR(("Invalid wpa_version\n"));
6578 goto exit;
6579 }
6580
6581#ifdef BCMWAPI_WPI
6582 if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) {
6583 WL_DBG(("skip auth type for wapi\n"));
6584 } else
6585#endif
6586
6587 {
6588 err = wl_set_auth_type(dev, sme);
6589 if (unlikely(err)) {
6590 WL_ERR(("Invalid auth type\n"));
6591 goto exit;
6592 }
6593 }
6594
6595#ifdef WL_FILS
6596 if (sme->ie && sme->ie_len) {
6597 err = wl_fils_add_hlp_container(cfg, dev, sme->ie, sme->ie_len);
6598 if (unlikely(err)) {
6599 WL_ERR(("FILS sending HLP failed\n"));
6600 goto exit;
6601 }
6602 }
6603#endif /* WL_FILS */
6604
6605 err = wl_set_set_cipher(dev, sme);
6606 if (unlikely(err)) {
6607 WL_ERR(("Invalid ciper\n"));
6608 goto exit;
6609 }
6610
6611 err = wl_set_key_mgmt(dev, sme);
6612 if (unlikely(err)) {
6613 WL_ERR(("Invalid key mgmt\n"));
6614 goto exit;
6615 }
6616
6617 err = wl_set_set_sharedkey(dev, sme);
6618 if (unlikely(err)) {
6619 WL_ERR(("Invalid shared key\n"));
6620 goto exit;
6621 }
6622
6623#ifdef WL_FILS
6624 err = wl_set_fils_params(dev, sme);
6625 if (unlikely(err)) {
6626 WL_ERR(("Invalid FILS params\n"));
6627 goto exit;
6628 }
6629#endif /* WL_FILS */
6630
6631exit:
6632 return err;
6633}
6634
6635static s32
6636wl_config_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *dev,
6637 struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *info)
6638{
6639 const wpa_ie_fixed_t *wpa_ie;
6640 const bcm_tlv_t *wpa2_ie;
6641 const u8* wpaie = 0;
6642 u32 wpaie_len;
6643 s32 err;
6644 s32 bssidx = info->bssidx;
6645
6646 /* configure all vendor and extended vendor IEs */
6647 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6648 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
6649
6650 /* Find the RSNXE_IE and plumb */
6651 if ((err = wl_cfg80211_config_rsnxe_ie(cfg, dev,
6652 (const u8*)sme->ie, sme->ie_len)) < 0) {
6653 WL_ERR(("Failed to configure rsnxe ie: %d\n", err));
6654 return err;
6655 }
6656
6657 /* find the RSN_IE */
6658 if ((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
6659 DOT11_MNG_RSN_ID)) != NULL) {
6660 WL_DBG((" RSN IE is found\n"));
6661 }
6662
6663 /* find the WPA_IE */
6664 if ((wpa_ie = wl_cfgp2p_find_wpaie(sme->ie,
6665 sme->ie_len)) != NULL) {
6666 WL_DBG((" WPA IE is found\n"));
6667 }
6668
6669 if (wpa_ie != NULL || wpa2_ie != NULL) {
6670 wpaie = (wpa_ie != NULL) ? (const u8 *)wpa_ie : (const u8 *)wpa2_ie;
6671 wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
6672 wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
6673 } else {
6674 wpaie = NULL;
6675 wpaie_len = 0;
6676 }
6677
6678 err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
6679 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6680 if (unlikely(err)) {
6681 WL_ERR(("wpaie set error (%d)\n", err));
6682 }
6683
6684 return err;
6685}
6686
6687s32
6688wl_cfg80211_config_rsnxe_ie(struct bcm_cfg80211 *cfg, struct net_device *dev,
6689 const u8 *parse, u32 len)
6690{
6691 bcm_tlv_t *ie = NULL;
6692 s32 err = 0;
6693 u8 ie_len = 0;
6694 char smbuf[WLC_IOCTL_SMLEN];
6695
6696 while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_RSNXE_ID))) {
6697 WL_DBG(("Found RSNXE ie\n"));
6698 break;
6699 }
6700
6701 ie_len = (ie != NULL) ? (ie->len + BCM_TLV_HDR_SIZE): 0;
6702
6703 err = wldev_iovar_setbuf(dev, "rsnxe", ie, ie_len,
6704 smbuf, sizeof(smbuf), NULL);
6705 if (!err) {
6706 WL_DBG(("Configured RSNXE IE\n"));
6707 } else if (err == BCME_UNSUPPORTED) {
6708 WL_DBG(("FW does not support rsnxe iovar\n"));
6709 err = BCME_OK;
6710 } else {
6711 WL_ERR(("rsnxe set error (%d)\n", err));
6712 }
6713 return err;
6714}
6715
6716static s32
6717wl_config_assoc_params(struct bcm_cfg80211 *cfg, struct net_device *dev,
6718 wl_extjoin_params_t *ext_join_params,
6719 u32 buf_len, wlcfg_assoc_info_t *info)
6720{
6721
6722 chanspec_t *chanspecs = info->chanspecs;
6723 u32 chan_cnt = info->chan_cnt;
6724 u32 join_scan_active_time = 0;
6725
6726 if (buf_len < (sizeof(ext_join_params->ssid.SSID) +
6727 (sizeof(chanspec_t) * chan_cnt))) {
6728 WL_ERR(("buf too short\n"));
6729 return -EINVAL;
6730 }
6731
6732 /* ssid length check is already done above */
6733 if (memcpy_s(ext_join_params->ssid.SSID, sizeof(ext_join_params->ssid.SSID),
6734 info->ssid, info->ssid_len) != BCME_OK) {
6735 WL_ERR(("ssid cpy failed info_len:%d\n", info->ssid_len));
6736 return -EINVAL;
6737 }
6738
6739 ext_join_params->ssid.SSID_len = info->ssid_len;
6740 wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
6741 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
6742 WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
6743 ext_join_params->ssid.SSID_len));
6744 }
6745 ext_join_params->ssid.SSID_len = htod32(info->ssid_len);
6746
6747 /* Use increased dwell for targeted join case to take care of noisy env */
6748 join_scan_active_time = info->targeted_join ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS :
6749 WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS;
6750 ext_join_params->scan.active_time = chan_cnt ? join_scan_active_time : -1;
6751 ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
6752 /* Set up join scan parameters */
6753 ext_join_params->scan.scan_type = -1;
6754 /* WAR to sync with presence period of VSDB GO.
6755 * send probe request more frequently
6756 * probe request will be stopped when it gets probe response from target AP/GO.
6757 */
6758 ext_join_params->scan.nprobes = chan_cnt ?
6759 (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
6760 ext_join_params->scan.home_time = -1;
6761
6762 (void)memcpy_s(&ext_join_params->assoc.bssid, ETH_ALEN, info->bssid, ETH_ALEN);
6763
6764 ext_join_params->assoc.chanspec_num = chan_cnt;
6765 /* source and target lens are same */
6766 (void)memcpy_s(ext_join_params->assoc.chanspec_list, (sizeof(chanspec_t) * chan_cnt),
6767 chanspecs, sizeof(chanspec_t) * chan_cnt);
6768
6769 ext_join_params->assoc.chanspec_num = htod32(chan_cnt);
6770 return BCME_OK;
6771}
6772
6773static s32
6774wl_handle_assoc_hints(struct bcm_cfg80211 *cfg, struct net_device *dev,
6775 struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *info)
6776{
6777#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6778 bool skip_hints = false;
6779#endif /* KERNEL >= 3.15 */
6780 chanspec_t chspec;
6781
6782 if (!sme || !info) {
6783 WL_ERR(("wrong args\n"));
6784 return -EINVAL;
6785 }
6786
6787 if (unlikely(!sme->ssid) || (sme->ssid_len > DOT11_MAX_SSID_LEN)) {
6788 WL_ERR(("Invalid ssid %p. len:%zu\n", sme->ssid, sme->ssid_len));
6789 return -EINVAL;
6790 }
6791
6792 /* Copy SSID detail */
6793 info->ssid_len = sme->ssid_len;
6794 if (memcpy_s(info->ssid, sizeof(info->ssid),
6795 sme->ssid, info->ssid_len) != BCME_OK) {
6796 WL_ERR(("ssid cpy failed\n"));
6797 return -EINVAL;
6798 }
6799
6800 /* Handle incoming BSSID and Channel info */
6801 if (sme->bssid && !ETHER_ISBCAST(sme->bssid)) {
6802 /* Use user space requested BSSID and channel */
6803 info->targeted_join = true;
6804 (void)memcpy_s(info->bssid, ETH_ALEN, sme->bssid, ETH_ALEN);
6805 if (sme->channel && ((chspec =
6806 wl_freq_to_chanspec(sme->channel->center_freq)) != INVCHANSPEC)) {
6807 info->chan_cnt = 1;
6808 info->chanspecs[0] = chspec;
6809#ifndef WL_P2P_6G
6810 /* Skip p2p connection on 6G */
6811 if (IS_P2P_GC(dev->ieee80211_ptr) && (CHSPEC_IS6G(chspec))) {
6812 WL_ERR(("P2P connection not allowed on 6G\n"));
6813 return -ENOTSUPP;
6814 }
6815#endif /* WL_P2P_6G */
6816 }
6817 }
6818#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6819 else {
6820#ifdef WL_SKIP_CONNECT_HINTS
6821 skip_hints = true;
6822 WL_DBG(("force skip connect hints\n"));
6823#else /* WL_SKIP_CONNECT_HINTS */
6824 /* override bssid_hint if overridden via module param */
6825 skip_hints = fw_ap_select;
6826#if defined(WL_FW_OCE_AP_SELECT)
6827 /* If fw select needs to be specifically done for OCE */
6828 skip_hints = fw_ap_select &&
6829 wl_cfg80211_is_oce_ap(wiphy, sme->bssid_hint);
6830#endif /* WL_FW_OCE_AP_SELECT */
6831 WL_DBG(("fw_ap_select:%d skip_hints:%d\n", fw_ap_select, skip_hints));
6832#endif /* WL_SKIP_CONNECT_HINTS */
6833
6834 /* Use bssid_hint if hints are allowed and if its unicast addr */
6835 if (!skip_hints && sme->bssid_hint && !ETHER_ISBCAST(sme->bssid_hint)) {
6836 WL_INFORM_MEM(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
6837 info->targeted_join = true;
6838 (void)memcpy_s(info->bssid, ETH_ALEN, sme->bssid_hint, ETH_ALEN);
6839 /* Use channel hint only for target bssid join case. In other
6840 * cases, use RCC or full scan to find better APs.
6841 */
6842 if (sme->channel_hint && ((chspec = wl_freq_to_chanspec(
6843 sme->channel_hint->center_freq)) != INVCHANSPEC)) {
6844 info->chan_cnt = 1;
6845 info->chanspecs[0] = chspec;
6846 WL_INFORM_MEM(("channel_hint: chspec(%x)\n", chspec));
6847 }
6848 }
6849 }
6850#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6851
6852 if (info->targeted_join != true) {
6853 /* For non targeted join, use bcast address */
6854 (void)memcpy_s(&info->bssid, ETH_ALEN, &ether_bcast, ETH_ALEN);
6855 }
6856 WL_DBG(("targeted_join:%d chan_cnt:%d\n",
6857 info->targeted_join, info->chan_cnt));
6858 return 0;
6859}
6860
6861static s32
6862wl_sync_fw_assoc_states(struct bcm_cfg80211 *cfg,
6863 struct net_device *dev, wlcfg_assoc_info_t *info)
6864{
6865 s32 err = BCME_OK;
6866 u8 bssid[ETH_ALEN];
6867
6868 if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_reassoc_support) {
6869 /* ROAM case */
6870 info->reassoc = true;
6871 } else {
6872 /* store the bssid for the connect req */
6873 wl_update_prof(cfg, dev, NULL, info->bssid, WL_PROF_LATEST_BSSID);
6874
6875 /* following scenarios are possible
6876 * In case of wrong request/abnormal status,
6877 * trigger DISASSOC to clean up status.
6878 * 1. DHD prev status is CONNECTING
6879 * => 1.1 Wrong request
6880 * 2. DHD previous status is CONNECTED
6881 * - FW connected
6882 * => Wrong request
6883 * - FW not connected
6884 * => Abnormal status
6885 * 3. DHD previous status is DISCONNECTING
6886 * => Waiting for disconnecting
6887 * 4. DHD previous status is not connected
6888 * - FW not connected
6889 * => Normal status
6890 * - FW connected
6891 * => Abnormal status
6892 */
6893 if (wl_get_drv_status(cfg, CONNECTING, dev) ||
6894 wl_get_drv_status(cfg, CONNECTED, dev)) {
6895 /* set nested connect bit to identify the context */
6896 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6897 /* DHD prev status is CONNECTING/CONNECTED */
6898 wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
6899 } else if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6900 /* DHD prev status is DISCONNECTING */
6901 wl_cfg80211_cleanup_mismatch_status(dev, cfg, false);
6902 } else if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6903 /* DHD previous status is not connected and FW connected */
6904 if (wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) == 0) {
6905 /* set nested connect bit to identify the context */
6906 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6907 wl_cfg80211_cleanup_mismatch_status(dev, cfg, true);
6908 }
6909 }
6910 wl_cfg80211_check_in4way(cfg, dev, WAIT_DISCONNECTED,
6911 WL_EXT_STATUS_CONNECTING, NULL);
6912 }
6913
6914 /* Clear BSSID if disconnecting state is not in progress */
6915 bzero(&bssid, sizeof(bssid));
6916 if (!wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6917 wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
6918 }
6919
6920 LOG_TS(cfg, conn_start);
6921 CLR_TS(cfg, authorize_start);
6922 /* clear nested connect bit on proceeding for connection */
6923 wl_clr_drv_status(cfg, NESTED_CONNECT, dev);
6924
6925 if (!info->reassoc) {
6926 /* 'connect' request received */
6927 wl_set_drv_status(cfg, CONNECTING, dev);
6928 }
6929
6930 return err;
6931}
6932
6933#if defined(DBG_PKT_MON)
6934void
6935wl_pkt_mon_start(struct bcm_cfg80211 *cfg, struct net_device *dev)
6936{
6937 if ((dev == bcmcfg_to_prmry_ndev(cfg))) {
6938 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6939 DHD_DBG_PKT_MON_START(dhdp);
6940 }
6941}
6942#endif /* DBG_PKT_MON && BCMDONGLEHOST */
6943
6944void
6945wl_conn_debug_info(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc_info_t *info)
6946{
6947 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6948 char sec_info[32];
6949
6950 if (!sec) {
6951 return;
6952 }
6953
6954 wl_ext_get_sec(dev, 0, sec_info, sizeof(sec_info));
6955 WL_MSG(dev->name, "Connecting with " MACDBG " ssid \"%s\", len (%d), "
6956 "channel=%d, sec=%s\n", MAC2STRDBG((u8*)(&info->bssid)),
6957 info->ssid, info->ssid_len, info->chan_cnt, sec_info);
6958 if (wl_dbg_level & WL_DBG_DBG) {
6959 WL_MSG(dev->name, "akm:0x%x auth:0x%x wpaver:0x%x pwise:0x%x gwise:0x%x\n",
6960 sec->wpa_auth, sec->auth_type, sec->wpa_versions,
6961 sec->cipher_pairwise, sec->cipher_group);
6962 WL_MSG(dev->name, "wpa_auth:0x%x auth:0x%x wsec:0x%x mfp:0x%x\n",
6963 sec->fw_wpa_auth, sec->fw_auth, sec->fw_wsec, sec->fw_mfp);
6964 /* print channels for assoc */
6965 prhex("chanspecs", (const u8 *)info->chanspecs,
6966 (info->chan_cnt * sizeof(chanspec_t)));
6967 }
6968 SUPP_LOG(("[%s] Connecting with " MACDBG " ssid \"%s\",chan_cnt:%d\n",
6969 dev->name, MAC2STRDBG((u8*)(&info->bssid)),
6970 info->ssid, info->chan_cnt));
6971}
6972
6973static s32
6974wl_handle_join(struct bcm_cfg80211 *cfg,
6975 struct net_device *dev, wlcfg_assoc_info_t *assoc_info)
6976{
6977 s32 err = 0;
6978 wl_extjoin_params_t *ext_join_params;
6979 size_t join_params_size;
6980
6981 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
6982 assoc_info->chan_cnt * sizeof(chanspec_t);
6983 ext_join_params = (wl_extjoin_params_t *)MALLOCZ(cfg->osh, join_params_size);
6984 if (ext_join_params == NULL) {
6985 err = -ENOMEM;
6986 WL_ERR(("Mem alloc for join_params failed\n"));
6987 goto fail;
6988 }
6989
6990 err = wl_config_assoc_params(cfg, dev, ext_join_params, join_params_size,
6991 assoc_info);
6992 if (unlikely(err)) {
6993 WL_ERR(("config assoc ies failed\n"));
6994 goto fail;
6995 }
6996
6997 err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
6998 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, assoc_info->bssidx, &cfg->ioctl_buf_sync);
6999
7000fail:
7001 MFREE(cfg->osh, ext_join_params, join_params_size);
7002 return err;
7003}
7004
7005static s32
7006wl_handle_reassoc(struct bcm_cfg80211 *cfg, struct net_device *dev,
7007 wlcfg_assoc_info_t *info)
7008{
7009 wl_reassoc_params_t reassoc_params;
7010 s32 err;
7011 char sec_info[32];
7012
7013 bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE);
7014 (void)memcpy_s(&reassoc_params.bssid.octet, ETH_ALEN, info->bssid, ETH_ALEN);
7015 wl_ext_get_sec(dev, 0, sec_info, sizeof(sec_info));
7016 WL_MSG(dev->name, "Reconnecting with " MACDBG " sec=%s\n",
7017 MAC2STRDBG((u8*)(&reassoc_params.bssid)), sec_info);
7018 err = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, sizeof(wl_reassoc_params_t));
7019 if (unlikely(err)) {
7020 WL_ERR(("reassoc failed, error=%d\n", err));
7021 return err;
7022 } else {
7023 WL_INFORM_MEM(("wl reassoc "MACDBG"\n", MAC2STRDBG(info->bssid)));
7024 }
7025
7026 return BCME_OK;
7027}
7028
7029static s32
7030wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
7031 struct cfg80211_connect_params *sme)
7032{
7033 s32 err = BCME_OK;
7034 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7035 wlcfg_assoc_info_t assoc_info;
7036 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7037
7038 WL_DBG(("Enter len=%zu\n", sme->ie_len));
7039 RETURN_EIO_IF_NOT_UP(cfg);
7040
7041 /* syncronize the connect states */
7042 mutex_lock(&cfg->connect_sync);
7043
7044 bzero(&assoc_info, sizeof(wlcfg_assoc_info_t));
7045 if ((assoc_info.bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7046 WL_ERR(("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr));
7047 goto fail;
7048 }
7049
7050 err = wl_do_preassoc_ops(cfg, dev, sme);
7051 if (unlikely(err)) {
7052 WL_ERR(("config assoc channel failed\n"));
7053 goto fail;
7054 }
7055
7056 err = wl_handle_assoc_hints(cfg, dev, sme, &assoc_info);
7057 if (unlikely(err)) {
7058 WL_ERR(("assoc hint processing failed\n"));
7059 goto fail;
7060 }
7061
7062 if (wl_sync_fw_assoc_states(cfg, dev, &assoc_info) != BCME_OK) {
7063 /* attempt best effort */
7064 WL_ERR(("fw assoc sync failed\n"));
7065 }
7066
7067 if (assoc_info.reassoc) {
7068 // terence 20200530, should call wl_ext_iapsta_update_channel() to move AP channel?
7069 /* Handle roam to same ESS */
7070 err = wl_handle_reassoc(cfg, dev, &assoc_info);
7071 } else {
7072 err = wl_config_assoc_security(cfg, dev, sme);
7073 if (unlikely(err)) {
7074 WL_ERR(("config assoc security failed\n"));
7075 goto fail;
7076 }
7077
7078 err = wl_get_assoc_channels(cfg, dev, &assoc_info);
7079 if (unlikely(err)) {
7080 WL_ERR(("get assoc channels failed\n"));
7081 goto fail;
7082 }
7083
7084 err = wl_config_assoc_ies(cfg, dev, sme, &assoc_info);
7085 if (unlikely(err)) {
7086 WL_ERR(("config assoc ies failed\n"));
7087 goto fail;
7088 }
7089
7090 /* print relevant info for debug purpose */
7091#ifdef WL_EXT_IAPSTA
7092 wl_ext_iapsta_update_channel(dhdp, dev, assoc_info.chan_cnt);
7093#endif
7094 wl_conn_debug_info(cfg, dev, &assoc_info);
7095 err = wl_handle_join(cfg, dev, &assoc_info);
7096 }
7097
7098fail:
7099 if (unlikely(err)) {
7100 WL_ERR(("connect error (%d)\n", err));
7101 wl_clr_drv_status(cfg, CONNECTING, dev);
7102 CLR_TS(cfg, conn_start);
7103 /* Flush fw logs */
7104 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
7105#ifdef WLTDLS
7106 /* If connect fails, check whether we can enable back TDLS */
7107 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
7108#endif /* WLTDLS */
7109 } else {
7110#ifdef DBG_PKT_MON
7111 /* start packet log in adv to ensure that EAPOL msgs aren't missed */
7112 wl_pkt_mon_start(cfg, dev);
7113#endif /* DBG_PKT_MON */
7114 }
7115 if (!err)
7116 wl_cfg80211_check_in4way(cfg, dev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
7117 WL_EXT_STATUS_CONNECTING, NULL);
7118
7119 mutex_unlock(&cfg->connect_sync);
7120 return err;
7121}
7122
7123static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev)
7124{
7125 uint8 wait_cnt;
7126 u32 status = 0;
7127
7128 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
7129 while ((status = wl_get_drv_status(cfg, DISCONNECTING, dev)) && wait_cnt) {
7130 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
7131 wait_cnt--;
7132 OSL_SLEEP(50);
7133 }
7134
7135 WL_INFORM_MEM(("Wait for disconnection done. status:%d wait_cnt:%d\n", status, wait_cnt));
7136 if (!wait_cnt && wl_get_drv_status(cfg, DISCONNECTING, dev)) {
7137 /* No response from firmware. Indicate connect result
7138 * to clear cfg80211 state machine
7139 */
7140 if (wl_get_drv_status(cfg, CONNECTING, dev)) {
7141 WL_INFORM_MEM(("force send connect result\n"));
7142 CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
7143 WLAN_STATUS_UNSPECIFIED_FAILURE,
7144 GFP_KERNEL);
7145 } else {
7146 WL_INFORM_MEM(("force send disconnect event\n"));
7147 CFG80211_DISCONNECTED(dev, WLAN_REASON_DEAUTH_LEAVING,
7148 NULL, 0, false, GFP_KERNEL);
7149 }
7150 CLR_TS(cfg, conn_start);
7151 CLR_TS(cfg, authorize_start);
7152 wl_clr_drv_status(cfg, DISCONNECTING, dev);
7153 }
7154 return;
7155}
7156
7157static s32
7158wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
7159 u16 reason_code)
7160{
7161 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7162 scb_val_t scbval;
7163 bool act = false;
7164 s32 err = 0;
7165 u8 *curbssid = NULL;
7166 u8 null_bssid[ETHER_ADDR_LEN];
7167 s32 bssidx = 0;
7168 bool connected;
7169 bool conn_in_progress;
7170 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7171
7172 RETURN_EIO_IF_NOT_UP(cfg);
7173 WL_MSG(dev->name, "Reason %d, act %d\n", reason_code, act);
7174
7175 BCM_REFERENCE(dhdp);
7176 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_START),
7177 dhd_net2idx(dhdp->info, dev), reason_code);
7178#ifdef DHD_4WAYM4_FAIL_DISCONNECT
7179 dhd_cleanup_m4_state_work(dhdp, dhd_net2idx(dhdp->info, dev));
7180#endif /* DHD_4WAYM4_FAIL_DISCONNECT */
7181
7182 connected = wl_get_drv_status(cfg, CONNECTED, dev);
7183 conn_in_progress = wl_get_drv_status(cfg, CONNECTING, dev);
7184 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
7185 act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
7186 WL_INFORM_MEM(("disconnect in connect state [%d:%d:%d]. reason:%d\n",
7187 connected, conn_in_progress, act, reason_code));
7188 if (connected || conn_in_progress) {
7189 if (curbssid) {
7190 WL_DBG_MEM(("curbssid:" MACDBG "\n", MAC2STRDBG(curbssid)));
7191 }
7192 act = true;
7193 }
7194
7195 if (!curbssid) {
7196 WL_ERR(("Disconnecting while CONNECTING status %d\n", (int)sizeof(null_bssid)));
7197 bzero(null_bssid, sizeof(null_bssid));
7198 curbssid = null_bssid;
7199 }
7200
7201 if (act) {
7202#ifdef DBG_PKT_MON
7203 /* Stop packet monitor */
7204 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
7205 DHD_DBG_PKT_MON_STOP(dhdp);
7206 }
7207#endif /* DBG_PKT_MON */
7208 /*
7209 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
7210 */
7211 /* Let scan aborted by F/W */
7212 if (cfg->scan_request) {
7213 WL_TRACE_HW4(("Aborting the scan! \n"));
7214 wl_cfg80211_cancel_scan(cfg);
7215 }
7216 if (conn_in_progress || connected) {
7217 scbval.val = reason_code;
7218 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
7219 scbval.val = htod32(scbval.val);
7220 WL_INFORM_MEM(("[%s] wl disassoc\n", dev->name));
7221 /* Set DISCONNECTING state. We are clearing this state
7222 in all exit paths
7223 */
7224 wl_set_drv_status(cfg, DISCONNECTING, dev);
7225 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
7226 sizeof(scb_val_t));
7227 if (unlikely(err)) {
7228 wl_clr_drv_status(cfg, DISCONNECTING, dev);
7229 WL_ERR(("error (%d)\n", err));
7230 goto exit;
7231 }
7232 wl_cfg80211_check_in4way(cfg, dev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY|WAIT_DISCONNECTED,
7233 WL_EXT_STATUS_DISCONNECTING, NULL);
7234 }
7235#ifdef WL_WPS_SYNC
7236 /* If are in WPS reauth state, then we would be
7237 * dropping the link down events. Ensure that
7238 * Event is sent up for the disconnect Req
7239 */
7240 if (wl_wps_session_update(dev,
7241 WPS_STATE_DISCONNECT, curbssid) == BCME_OK) {
7242 WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
7243 wl_clr_drv_status(cfg, DISCONNECTING, dev);
7244 goto exit;
7245 }
7246#endif /* WPS_SYNC */
7247 wl_cfg80211_wait_for_disconnection(cfg, dev);
7248 } else {
7249 /* Not in connected or connection in progres states. Still receiving
7250 * disassoc indicates state mismatch with upper layer. Check for state
7251 * and issue disconnect indication if required.
7252 */
7253
7254 if (dev->ieee80211_ptr->current_bss) {
7255 WL_INFORM_MEM(("report disconnect event\n"));
7256 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
7257 }
7258 }
7259
7260#ifdef CUSTOM_SET_CPUCORE
7261 /* set default cpucore */
7262 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
7263 dhdp->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
7264 if (!(dhdp->chan_isvht80))
7265 dhd_set_cpucore(dhdp, FALSE);
7266 }
7267#endif /* CUSTOM_SET_CPUCORE */
7268
7269 cfg->rssi = 0; /* reset backup of rssi */
7270
7271exit:
7272 CLR_TS(cfg, conn_start);
7273 CLR_TS(cfg, authorize_start);
7274
7275 /* Clear IEs for disaasoc */
7276 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7277 WL_ERR(("Find index failed\n"));
7278 err = -EINVAL;
7279 return err;
7280 }
7281 WL_ERR(("Clearing disconnect IEs \n"));
7282 err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
7283 ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, NULL, 0);
7284
7285 return err;
7286}
7287
7288static s32
7289#if defined(WL_CFG80211_P2P_DEV_IF)
7290wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
7291 enum nl80211_tx_power_setting type, s32 mbm)
7292#else
7293wl_cfg80211_set_tx_power(struct wiphy *wiphy,
7294 enum nl80211_tx_power_setting type, s32 dbm)
7295#endif /* WL_CFG80211_P2P_DEV_IF */
7296{
7297
7298 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7299 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7300 s32 err = 0;
7301#if defined(WL_CFG80211_P2P_DEV_IF)
7302 s32 dbm = MBM_TO_DBM(mbm);
7303#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
7304 defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
7305 dbm = MBM_TO_DBM(dbm);
7306#endif /* WL_CFG80211_P2P_DEV_IF */
7307
7308 RETURN_EIO_IF_NOT_UP(cfg);
7309 switch (type) {
7310 case NL80211_TX_POWER_AUTOMATIC:
7311 break;
7312 case NL80211_TX_POWER_LIMITED:
7313 if (dbm < 0) {
7314 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
7315 return -EINVAL;
7316 }
7317 break;
7318 case NL80211_TX_POWER_FIXED:
7319 if (dbm < 0) {
7320 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
7321 return -EINVAL;
7322 }
7323 break;
7324 }
7325
7326 err = wl_set_tx_power(ndev, type, dbm);
7327 if (unlikely(err)) {
7328 WL_ERR(("error (%d)\n", err));
7329 return err;
7330 }
7331
7332 cfg->conf->tx_power = dbm;
7333
7334 return err;
7335}
7336
7337static s32
7338#if defined(WL_CFG80211_P2P_DEV_IF)
7339wl_cfg80211_get_tx_power(struct wiphy *wiphy,
7340 struct wireless_dev *wdev, s32 *dbm)
7341#else
7342wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
7343#endif /* WL_CFG80211_P2P_DEV_IF */
7344{
7345 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7346 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7347 s32 err = 0;
7348
7349 RETURN_EIO_IF_NOT_UP(cfg);
7350 err = wl_get_tx_power(ndev, dbm);
7351 if (unlikely(err))
7352 WL_ERR(("error (%d)\n", err));
7353
7354 return err;
7355}
7356
7357static s32
7358wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
7359 u8 key_idx, bool unicast, bool multicast)
7360{
7361 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7362 u32 index;
7363 s32 wsec;
7364 s32 err = 0;
7365 s32 bssidx;
7366
7367 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7368 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
7369 return BCME_ERROR;
7370 }
7371
7372 WL_DBG(("key index (%d)\n", key_idx));
7373 RETURN_EIO_IF_NOT_UP(cfg);
7374 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7375 if (unlikely(err)) {
7376 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7377 return err;
7378 }
7379 /* Fix IOT issue with Apple Airport */
7380 if (wsec == WEP_ENABLED) {
7381 /* Just select a new current key */
7382 index = (u32) key_idx;
7383 index = htod32(index);
7384 err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index,
7385 sizeof(index));
7386 if (unlikely(err)) {
7387 WL_ERR(("error (%d)\n", err));
7388 }
7389 }
7390 return err;
7391}
7392
7393static s32
7394wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
7395 u8 key_idx, const u8 *mac_addr, struct key_params *params)
7396{
7397 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7398 struct wl_wsec_key key;
7399 s32 err = 0;
7400 s32 bssidx;
7401 s32 mode = wl_get_mode_by_netdev(cfg, dev);
7402
7403 WL_MSG(dev->name, "key index (%d)\n", key_idx);
7404 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7405 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7406 return BCME_ERROR;
7407 }
7408 bzero(&key, sizeof(key));
7409 key.index = (u32) key_idx;
7410
7411 if (!ETHER_ISMULTI(mac_addr))
7412 memcpy((char *)&key.ea, (const void *)mac_addr, ETHER_ADDR_LEN);
7413 key.len = (u32) params->key_len;
7414
7415 /* check for key index change */
7416 if (key.len == 0) {
7417 /* key delete */
7418 swap_key_from_BE(&key);
7419 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7420 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7421 if (unlikely(err)) {
7422 WL_ERR(("key delete error (%d)\n", err));
7423 return err;
7424 }
7425 } else {
7426 if (key.len > sizeof(key.data)) {
7427 WL_ERR(("Invalid key length (%d)\n", key.len));
7428 return -EINVAL;
7429 }
7430 WL_DBG(("Setting the key index %d\n", key.index));
7431 memcpy(key.data, params->key, key.len);
7432
7433 if ((mode == WL_MODE_BSS) &&
7434 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
7435 u8 keybuf[8];
7436 memcpy(keybuf, &key.data[24], sizeof(keybuf));
7437 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
7438 memcpy(&key.data[16], keybuf, sizeof(keybuf));
7439 }
7440
7441 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
7442 if (params->seq && params->seq_len == 6) {
7443 /* rx iv */
7444 const u8 *ivptr;
7445 ivptr = (const u8 *) params->seq;
7446 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
7447 (ivptr[3] << 8) | ivptr[2];
7448 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
7449 key.iv_initialized = true;
7450 }
7451 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7452 if (key.algo == CRYPTO_ALGO_OFF) { //not found.
7453 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7454 return -EINVAL;
7455 }
7456 swap_key_from_BE(&key);
7457#if !defined(CUSTOMER_HW4)
7458 /* need to guarantee EAPOL 4/4 send out before set key */
7459 dhd_wait_pend8021x(dev);
7460#endif /* BCMDONGLEHOST && !CUSTOMER_HW4 */
7461 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7462 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7463 if (unlikely(err)) {
7464 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7465 return err;
7466 }
7467 WL_INFORM_MEM(("[%s] wsec key set\n", dev->name));
7468 }
7469 return err;
7470}
7471
7472int
7473wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
7474{
7475 int err;
7476 wl_eventmsg_buf_t ev_buf;
7477 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7478
7479 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7480 /* roam offload is only for the primary device */
7481 return -1;
7482 }
7483
7484 WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev->name, enable));
7485 err = wldev_iovar_setint(dev, "roam_offload", enable);
7486 if (err)
7487 return err;
7488
7489 bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
7490 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
7491 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
7492 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
7493 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
7494 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
7495 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
7496 err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
7497 if (!err) {
7498 cfg->roam_offload = enable;
7499 }
7500 return err;
7501}
7502
7503struct wireless_dev *
7504wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 *cfg, const char *name)
7505{
7506 struct net_info *iter, *next;
7507
7508 if (name == NULL) {
7509 WL_ERR(("Iface name is not provided\n"));
7510 return NULL;
7511 }
7512
7513 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7514 for_each_ndev(cfg, iter, next) {
7515 GCC_DIAGNOSTIC_POP();
7516 if (iter->ndev) {
7517 if (strcmp(iter->ndev->name, name) == 0) {
7518 return iter->ndev->ieee80211_ptr;
7519 }
7520 }
7521 }
7522
7523 WL_DBG(("Iface %s not found\n", name));
7524 return NULL;
7525}
7526
7527#if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
7528void
7529wl_cfg80211_block_arp(struct net_device *dev, int enable)
7530{
7531 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7532 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7533
7534 WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev->name, enable));
7535 if (!dhd_pkt_filter_enable) {
7536 WL_DBG(("Packet filter isn't enabled\n"));
7537 return;
7538 }
7539
7540 /* Block/Unblock ARP frames only if STA is connected to
7541 * the upstream AP in case of STA+SoftAP Concurrenct mode
7542 */
7543 if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
7544 WL_DBG(("STA not connected to upstream AP\n"));
7545 return;
7546 }
7547
7548 if (enable) {
7549 WL_DBG(("Enable ARP Filter\n"));
7550 /* Add ARP filter */
7551 dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
7552
7553 /* Enable ARP packet filter - blacklist */
7554 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7555 TRUE, FALSE);
7556 } else {
7557 WL_DBG(("Disable ARP Filter\n"));
7558 /* Disable ARP packet filter */
7559 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7560 FALSE, TRUE);
7561
7562 /* Delete ARP filter */
7563 dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
7564 }
7565}
7566#endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
7567
7568static s32
7569wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
7570 u8 key_idx, bool pairwise, const u8 *mac_addr,
7571 struct key_params *params)
7572{
7573 struct wl_wsec_key key;
7574 s32 val = 0;
7575 s32 wsec = 0;
7576 s32 err = 0;
7577 u8 keybuf[8];
7578 s32 bssidx = 0;
7579 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7580 s32 mode = wl_get_mode_by_netdev(cfg, dev);
7581#ifdef WL_GCMP
7582 uint32 algos = 0, mask = 0;
7583#endif /* WL_GCMP */
7584#if defined(WLAN_CIPHER_SUITE_PMK)
7585 wsec_pmk_t pmk;
7586 struct wl_security *sec;
7587#endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7588 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7589
7590 if (dhd_query_bus_erros(dhdp)) {
7591 /* If we are hit with bus error, return success so that
7592 * don't repeatedly call del station till we recover.
7593 */
7594 return 0;
7595 }
7596
7597 WL_INFORM_MEM(("key index (%d) (0x%x)\n", key_idx, params->cipher));
7598 RETURN_EIO_IF_NOT_UP(cfg);
7599
7600 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7601 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
7602 return BCME_ERROR;
7603 }
7604
7605 if (mac_addr &&
7606 ((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
7607 (params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
7608 wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
7609 goto exit;
7610 }
7611
7612 BCM_REFERENCE(dhdp);
7613 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_KEY), dhd_net2idx(dhdp->info, dev), 0);
7614
7615 bzero(&key, sizeof(key));
7616 /* Clear any buffered wep key */
7617 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
7618
7619 key.len = (u32) params->key_len;
7620 key.index = (u32) key_idx;
7621
7622 if (unlikely(key.len > sizeof(key.data))) {
7623 WL_ERR(("Too long key length (%u)\n", key.len));
7624 return -EINVAL;
7625 }
7626 memcpy(key.data, params->key, key.len);
7627
7628 key.flags = WL_PRIMARY_KEY;
7629
7630 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7631 val = wl_rsn_cipher_wsec_algo_lookup(params->cipher);
7632 if (val == WSEC_NONE) {
7633 WL_ERR(("Invalid cipher (0x%x), key.len = %d\n", params->cipher, key.len));
7634#if defined(WLAN_CIPHER_SUITE_PMK)
7635 /* WLAN_CIPHER_SUITE_PMK is not NL80211 standard ,but BRCM proprietary cipher suite.
7636 * so it doesn't have right algo type. Just for now, bypass this check for
7637 * backward compatibility.
7638 * TODO: deprecate this proprietary way and replace to nl80211 set_pmk API.
7639 */
7640 if (params->cipher != WLAN_CIPHER_SUITE_PMK)
7641#endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7642 return -EINVAL;
7643 }
7644 switch (params->cipher) {
7645 case WLAN_CIPHER_SUITE_TKIP:
7646 if (params->key_len != TKIP_KEY_SIZE) {
7647 WL_ERR(("wrong TKIP Key length:%d", params->key_len));
7648 return -EINVAL;
7649 }
7650 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
7651 if (mode == WL_MODE_BSS) {
7652 bcopy(&key.data[24], keybuf, sizeof(keybuf));
7653 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
7654 bcopy(keybuf, &key.data[16], sizeof(keybuf));
7655 }
7656 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7657 break;
7658#if defined(WLAN_CIPHER_SUITE_PMK)
7659 case WLAN_CIPHER_SUITE_PMK:
7660 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7661
7662 WL_MEM(("set_pmk: wpa_auth:%x akm:%x\n", sec->wpa_auth, params->cipher));
7663 /* Avoid pmk set for SAE and OWE for external supplicant case. */
7664 if (IS_AKM_SAE(sec->wpa_auth) || IS_AKM_OWE(sec->wpa_auth)) {
7665 WL_INFORM_MEM(("skip pmk set for akm:%x\n", sec->wpa_auth));
7666 break;
7667 }
7668
7669 if (params->key_len > sizeof(pmk.key)) {
7670 WL_ERR(("Worng PMK key length:%d", params->key_len));
7671 return -EINVAL;
7672 }
7673 bzero(&pmk, sizeof(pmk));
7674 bcopy(params->key, &pmk.key, params->key_len);
7675 pmk.key_len = params->key_len;
7676 pmk.flags = 0; /* 0:PMK, WSEC_PASSPHRASE:PSK, WSEC_SAE_PASSPHRASE:SAE_PSK */
7677
7678 if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
7679 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
7680 err = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len,
7681 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
7682 if (err) {
7683 /* could fail in case that 'okc' is not supported */
7684 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err));
7685 }
7686 }
7687
7688 err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
7689 if (err) {
7690 WL_ERR(("pmk failed, err=%d (ignore)\n", err));
7691 return err;
7692 } else {
7693 WL_DBG(("pmk set. flags:0x%x\n", pmk.flags));
7694 }
7695 /* Clear key length to delete key */
7696 key.len = 0;
7697 break;
7698#endif /* WLAN_CIPHER_SUITE_PMK */
7699#ifdef WL_GCMP
7700 case WLAN_CIPHER_SUITE_GCMP:
7701 case WLAN_CIPHER_SUITE_GCMP_256:
7702 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
7703 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
7704 algos = KEY_ALGO_MASK(key.algo);
7705 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
7706 break;
7707#endif /* WL_GCMP */
7708 default: /* No post processing required */
7709 WL_DBG(("no post processing required (0x%x)\n", params->cipher));
7710 break;
7711 }
7712
7713 /* Set the new key/index */
7714 if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
7715 WL_ERR(("IBSS KEY setted\n"));
7716 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
7717 }
7718 swap_key_from_BE(&key);
7719 if ((params->cipher == WLAN_CIPHER_SUITE_WEP40) ||
7720 (params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
7721 /*
7722 * For AP role, since we are doing a wl down before bringing up AP,
7723 * the plumbed keys will be lost. So for AP once we bring up AP, we
7724 * need to plumb keys again. So buffer the keys for future use. This
7725 * is more like a WAR. If firmware later has the capability to do
7726 * interface upgrade without doing a "wl down" and "wl apsta 0", then
7727 * this will not be required.
7728 */
7729 WL_DBG(("Buffering WEP Keys \n"));
7730 memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key));
7731 }
7732 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7733 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7734 if (unlikely(err)) {
7735 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7736 return err;
7737 }
7738
7739exit:
7740 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7741 if (unlikely(err)) {
7742 WL_ERR(("get wsec error (%d)\n", err));
7743 return err;
7744 }
7745
7746 wsec |= val;
7747 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
7748 if (unlikely(err)) {
7749 WL_ERR(("set wsec error (%d)\n", err));
7750 return err;
7751 }
7752#ifdef WL_GCMP
7753 wl_set_wsec_info_algos(dev, algos, mask);
7754#endif /* WL_GCMP */
7755 wl_cfg80211_check_in4way(cfg, dev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
7756 WL_EXT_STATUS_ADD_KEY, NULL);
7757 return err;
7758}
7759
7760static s32
7761wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
7762 u8 key_idx, bool pairwise, const u8 *mac_addr)
7763{
7764 struct wl_wsec_key key;
7765 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7766 s32 err = 0;
7767 s32 bssidx;
7768 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7769
7770 if (dhd_query_bus_erros(dhdp)) {
7771 /* If we are hit with bus error, return success so that
7772 * don't repeatedly call del station till we recover.
7773 */
7774 return 0;
7775 }
7776
7777 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7778 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7779 return BCME_ERROR;
7780 }
7781 WL_DBG(("Enter\n"));
7782
7783#ifndef MFP
7784 if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
7785 return -EINVAL;
7786#endif
7787
7788 RETURN_EIO_IF_NOT_UP(cfg);
7789 BCM_REFERENCE(dhdp);
7790 DHD_STATLOG_CTRL(dhdp, ST(DELETE_KEY), dhd_net2idx(dhdp->info, dev), 0);
7791 bzero(&key, sizeof(key));
7792
7793 key.flags = WL_PRIMARY_KEY;
7794 key.algo = CRYPTO_ALGO_OFF;
7795 key.index = (u32) key_idx;
7796
7797 WL_DBG(("key index (%d)\n", key_idx));
7798 /* Set the new key/index */
7799 swap_key_from_BE(&key);
7800 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7801 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7802 if (unlikely(err)) {
7803 if (err == -EINVAL) {
7804 if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
7805 /* we ignore this key index in this case */
7806 WL_DBG(("invalid key index (%d)\n", key_idx));
7807 }
7808 } else {
7809 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7810 }
7811 return err;
7812 }
7813 return err;
7814}
7815
7816/* NOTE : this function cannot work as is and is never called */
7817static s32
7818wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
7819 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
7820 void (*callback) (void *cookie, struct key_params * params))
7821{
7822 struct key_params params;
7823 struct wl_wsec_key key;
7824 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7825 struct wl_security *sec;
7826 s32 wsec;
7827 s32 err = 0;
7828 s32 bssidx;
7829
7830 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7831 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7832 return BCME_ERROR;
7833 }
7834 WL_DBG(("key index (%d)\n", key_idx));
7835 RETURN_EIO_IF_NOT_UP(cfg);
7836 bzero(&key, sizeof(key));
7837 key.index = key_idx;
7838 swap_key_to_BE(&key);
7839 bzero(&params, sizeof(params));
7840 params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
7841 params.key = key.data;
7842
7843 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7844 if (unlikely(err)) {
7845 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7846 return err;
7847 }
7848 switch (WSEC_ENABLED(wsec)) {
7849 case WEP_ENABLED:
7850 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7851 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
7852 params.cipher = WLAN_CIPHER_SUITE_WEP40;
7853 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7854 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
7855 params.cipher = WLAN_CIPHER_SUITE_WEP104;
7856 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7857 }
7858 break;
7859 case TKIP_ENABLED:
7860 params.cipher = WLAN_CIPHER_SUITE_TKIP;
7861 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7862 break;
7863 case AES_ENABLED:
7864 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7865 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7866 break;
7867
7868#ifdef BCMWAPI_WPI
7869 case SMS4_ENABLED:
7870 params.cipher = WLAN_CIPHER_SUITE_SMS4;
7871 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7872 break;
7873#endif
7874
7875#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
7876 /* to connect to mixed mode AP */
7877 case (AES_ENABLED | TKIP_ENABLED): /* TKIP CCMP */
7878 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7879 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7880 break;
7881#endif
7882 default:
7883 WL_ERR(("Invalid algo (0x%x)\n", wsec));
7884 return -EINVAL;
7885 }
7886
7887 callback(cookie, &params);
7888 return err;
7889}
7890
7891static s32
7892wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
7893 struct net_device *dev, u8 key_idx)
7894{
7895#ifdef MFP
7896 /* Firmware seems to use hard coded index for Group Mgmt Key.
7897 * TODO/Need to check whether something else needs to be
7898 * taken here
7899 */
7900 return 0;
7901#else
7902 WL_INFORM_MEM(("Not supported\n"));
7903 return -EOPNOTSUPP;
7904#endif /* MFP */
7905}
7906
7907static bool
7908wl_check_assoc_state(struct bcm_cfg80211 *cfg, struct net_device *dev)
7909{
7910 wl_assoc_info_t asinfo;
7911 uint32 state = 0;
7912 int err;
7913
7914 err = wldev_iovar_getbuf_bsscfg(dev, "assoc_info",
7915 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
7916 if (unlikely(err)) {
7917 WL_ERR(("failed to get assoc_info : err=%d\n", err));
7918 return FALSE;
7919 } else {
7920 memcpy(&asinfo, cfg->ioctl_buf, sizeof(wl_assoc_info_t));
7921 state = dtoh32(asinfo.state);
7922 WL_DBG(("assoc state=%d\n", state));
7923 }
7924
7925 return (state > 0)? TRUE:FALSE;
7926}
7927
7928static s32
7929wl_cfg80211_get_rssi(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 *rssi)
7930{
7931 s32 err = BCME_OK;
7932 scb_val_t scb_val;
7933#ifdef SUPPORT_RSSI_SUM_REPORT
7934 wl_rssi_ant_mimo_t rssi_ant_mimo;
7935#endif /* SUPPORT_RSSI_SUM_REPORT */
7936
7937 if (dev == NULL || cfg == NULL) {
7938 return BCME_ERROR;
7939 }
7940
7941 /* initialize rssi */
7942 *rssi = 0;
7943
7944#ifdef SUPPORT_RSSI_SUM_REPORT
7945 /* Query RSSI sum across antennas */
7946 bzero(&rssi_ant_mimo, sizeof(rssi_ant_mimo));
7947 err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
7948 if (err) {
7949 WL_ERR(("Could not get rssi sum (%d)\n", err));
7950 /* set rssi to zero and do not return error,
7951 * because iovar phy_rssi_ant could return BCME_UNSUPPORTED
7952 * when bssid was null during roaming
7953 */
7954 err = BCME_OK;
7955 } else {
7956 cfg->rssi_sum_report = TRUE;
7957 if ((*rssi = rssi_ant_mimo.rssi_sum) >= 0) {
7958 *rssi = 0;
7959 }
7960 }
7961#endif /* SUPPORT_RSSI_SUM_REPORT */
7962
7963 /* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore */
7964 if (cfg->rssi_sum_report == FALSE) {
7965 bzero(&scb_val, sizeof(scb_val));
7966 scb_val.val = 0;
7967 err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val,
7968 sizeof(scb_val_t));
7969 if (err) {
7970 WL_ERR(("Could not get rssi (%d)\n", err));
7971 return err;
7972 }
7973#if defined(RSSIOFFSET)
7974 *rssi = wl_update_rssi_offset(dev, dtoh32(scb_val.val));
7975#else
7976 *rssi = dtoh32(scb_val.val);
7977#endif
7978 }
7979
7980 if (*rssi >= 0) {
7981 /* check assoc status including roaming */
7982 DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub));
7983 if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_check_assoc_state(cfg, dev)) {
7984 *rssi = cfg->rssi; /* use previous RSSI */
7985 WL_DBG(("use previous RSSI %d dBm\n", cfg->rssi));
7986 } else {
7987 *rssi = 0;
7988 }
7989 DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
7990 } else {
7991 /* backup the current rssi */
7992 cfg->rssi = *rssi;
7993 }
7994
7995 return err;
7996}
7997
7998static int
7999wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data, uint16 type, uint16 len)
8000{
8001 switch (type) {
8002 case WL_IFSTATS_XTLV_IF_INDEX:
8003 WL_DBG(("Stats received on interface index: %d\n", *data));
8004 break;
8005 case WL_IFSTATS_XTLV_GENERIC: {
8006 if (len > sizeof(wl_if_stats_t)) {
8007 WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n",
8008 type, len, (int)sizeof(wl_if_stats_t)));
8009 }
8010 memcpy(ctx, data, sizeof(wl_if_stats_t));
8011 break;
8012 }
8013 default:
8014 WL_DBG(("Unsupported counter type 0x%x\n", type));
8015 break;
8016 }
8017
8018 return BCME_OK;
8019}
8020
8021/* Parameters to if_counters iovar need to be converted to XTLV format
8022 * before sending to FW. The length of the top level XTLV container
8023 * containing parameters should not exceed 228 bytes
8024 */
8025#define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228
8026
8027int
8028wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats)
8029{
8030 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8031 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
8032 uint8 *pbuf = NULL;
8033 bcm_xtlvbuf_t xtlvbuf, local_xtlvbuf;
8034 bcm_xtlv_t *xtlv;
8035 uint16 expected_resp_len;
8036 wl_stats_report_t *request = NULL, *response = NULL;
8037 int bsscfg_idx;
8038 int ret = BCME_OK;
8039
8040 pbuf = (uint8 *)MALLOCZ(dhdp->osh, WLC_IOCTL_MEDLEN);
8041 if (!pbuf) {
8042 WL_ERR(("Failed to allocate local pbuf\n"));
8043 return BCME_NOMEM;
8044 }
8045
8046 /* top level container length cannot exceed 228 bytes.
8047 * This is because the output buffer is 1535 bytes long.
8048 * Allow 1300 bytes for reporting stats coming in XTLV format
8049 */
8050 request = (wl_stats_report_t *)
8051 MALLOCZ(dhdp->osh, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
8052 if (!request) {
8053 WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
8054 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX));
8055 ret = BCME_NOMEM;
8056 goto fail;
8057 }
8058
8059 request->version = WL_STATS_REPORT_REQUEST_VERSION_V2;
8060
8061 /* Top level container... we will create it ourselves */
8062 /* Leave space for report version, length, and top level XTLV
8063 * WL_IFSTATS_XTLV_IF.
8064 */
8065 ret = bcm_xtlv_buf_init(&local_xtlvbuf,
8066 (uint8*)(request->data) + BCM_XTLV_HDR_SIZE,
8067 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
8068 offsetof(wl_stats_report_t, data) - BCM_XTLV_HDR_SIZE,
8069 BCM_XTLV_OPTION_ALIGN32);
8070
8071 if (ret) {
8072 goto fail;
8073 }
8074
8075 /* Populate requests using this the local_xtlvbuf context. The xtlvbuf
8076 * is used to fill the container containing the XTLVs populated using
8077 * local_xtlvbuf.
8078 */
8079 ret = bcm_xtlv_buf_init(&xtlvbuf,
8080 (uint8*)(request->data),
8081 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
8082 offsetof(wl_stats_report_t, data),
8083 BCM_XTLV_OPTION_ALIGN32);
8084
8085 if (ret) {
8086 goto fail;
8087 }
8088
8089 /* Request generic stats */
8090 ret = bcm_xtlv_put_data(&local_xtlvbuf,
8091 WL_IFSTATS_XTLV_GENERIC, NULL, 0);
8092 if (ret) {
8093 goto fail;
8094 }
8095
8096 /* Complete the outer container with type and length
8097 * only.
8098 */
8099 ret = bcm_xtlv_put_data(&xtlvbuf,
8100 WL_IFSTATS_XTLV_IF,
8101 NULL, bcm_xtlv_buf_len(&local_xtlvbuf));
8102
8103 if (ret) {
8104 goto fail;
8105 }
8106
8107 request->length = bcm_xtlv_buf_len(&xtlvbuf) +
8108 offsetof(wl_stats_report_t, data);
8109 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
8110
8111 /* send the command over to the device and get teh output */
8112 ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request,
8113 request->length, pbuf, WLC_IOCTL_MEDLEN, bsscfg_idx,
8114 &cfg->ioctl_buf_sync);
8115 if (ret < 0) {
8116 WL_ERR(("if_counters not supported ret=%d\n", ret));
8117 goto fail;
8118 }
8119
8120 /* Reuse request to process response */
8121 response = (wl_stats_report_t *)pbuf;
8122
8123 /* version check */
8124 if (response->version != WL_STATS_REPORT_REQUEST_VERSION_V2) {
8125 ret = BCME_VERSION;
8126 goto fail;
8127 }
8128
8129 xtlv = (bcm_xtlv_t *)(response->data);
8130
8131 expected_resp_len =
8132 (BCM_XTLV_LEN(xtlv) + OFFSETOF(wl_stats_report_t, data));
8133
8134 /* Check if the received length is as expected */
8135 if ((response->length > WLC_IOCTL_MEDLEN) ||
8136 (response->length < expected_resp_len)) {
8137 ret = BCME_ERROR;
8138 WL_ERR(("Illegal response length received. Got: %d"
8139 " Expected: %d. Expected len must be <= %u\n",
8140 response->length, expected_resp_len, WLC_IOCTL_MEDLEN));
8141 goto fail;
8142 }
8143
8144 /* check the type. The return data will be in
8145 * WL_IFSTATS_XTLV_IF container. So check if that container is
8146 * present
8147 */
8148 if (BCM_XTLV_ID(xtlv) != WL_IFSTATS_XTLV_IF) {
8149 ret = BCME_ERROR;
8150 WL_ERR(("unexpected type received: %d Expected: %d\n",
8151 BCM_XTLV_ID(xtlv), WL_IFSTATS_XTLV_IF));
8152 goto fail;
8153 }
8154
8155 /* Process XTLVs within WL_IFSTATS_XTLV_IF container */
8156 ret = bcm_unpack_xtlv_buf(if_stats,
8157 (uint8*)response->data + BCM_XTLV_HDR_SIZE,
8158 BCM_XTLV_LEN(xtlv), /* total length of all TLVs in container */
8159 BCM_XTLV_OPTION_ALIGN32, wl_cfg80211_ifstats_counters_cb);
8160 if (ret) {
8161 WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret));
8162 }
8163
8164fail:
8165 if (pbuf) {
8166 MFREE(dhdp->osh, pbuf, WLC_IOCTL_MEDLEN);
8167 }
8168
8169 if (request) {
8170 MFREE(dhdp->osh, request, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
8171 }
8172 return ret;
8173}
8174#undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
8175
8176static s32
8177#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
8178wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
8179 const u8 *mac, struct station_info *sinfo)
8180#else
8181wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
8182 u8 *mac, struct station_info *sinfo)
8183#endif
8184{
8185 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8186 s32 rssi = 0;
8187#if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, \
8188 0))
8189 wl_rssi_ant_mimo_t rssi_ant_mimo;
8190 int cnt, chains;
8191#endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
8192 s32 rate = 0;
8193 s32 err = 0;
8194 u16 wl_iftype = 0;
8195 u16 wl_mode = 0;
8196 get_pktcnt_t pktcnt;
8197 wl_if_stats_t *if_stats = NULL;
8198 sta_info_v4_t *sta = NULL;
8199 u8 *curmacp = NULL;
8200 s8 eabuf[ETHER_ADDR_STR_LEN];
8201 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
8202 bool fw_assoc_state = FALSE;
8203 u32 dhd_assoc_state = 0;
8204 void *buf;
8205
8206 RETURN_EIO_IF_NOT_UP(cfg);
8207
8208 if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype, &wl_iftype, &wl_mode) < 0) {
8209 return -EINVAL;
8210 }
8211
8212 buf = MALLOC(cfg->osh, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
8213 if (buf == NULL) {
8214 WL_ERR(("wl_cfg80211_get_station: MALLOC failed\n"));
8215 goto error;
8216 }
8217
8218 switch (wl_iftype) {
8219 case WL_IF_TYPE_STA:
8220 case WL_IF_TYPE_IBSS:
8221 if (cfg->roam_offload) {
8222 struct ether_addr bssid;
8223 bzero(&bssid, sizeof(bssid));
8224 err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
8225 if (err) {
8226 WL_ERR(("Failed to get current BSSID\n"));
8227 } else {
8228 if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
8229 /* roaming is detected */
8230 err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
8231 if (err)
8232 WL_ERR(("Failed to handle the delayed"
8233 " roam, err=%d", err));
8234 mac = (u8 *)bssid.octet;
8235 }
8236 }
8237 }
8238 dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
8239 DHD_OS_WAKE_LOCK(dhd);
8240 fw_assoc_state = dhd_is_associated(dhd, 0, &err);
8241 if (dhd_assoc_state && !fw_assoc_state) {
8242 /* check roam (join) status */
8243 if (wl_check_assoc_state(cfg, dev)) {
8244 fw_assoc_state = TRUE;
8245 WL_DBG(("roam status\n"));
8246 }
8247 }
8248 DHD_OS_WAKE_UNLOCK(dhd);
8249 if (!dhd_assoc_state || !fw_assoc_state) {
8250 WL_ERR(("NOT assoc\n"));
8251 if (err == -ENODATA)
8252 goto error;
8253 if (!dhd_assoc_state) {
8254 WL_TRACE_HW4(("drv state is not connected \n"));
8255 }
8256 if (!fw_assoc_state) {
8257 WL_TRACE_HW4(("fw state is not associated \n"));
8258 }
8259 /* Disconnect due to fw is not associated for
8260 * FW_ASSOC_WATCHDOG_TIME ms.
8261 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
8262 * means that BSSID is null.
8263 */
8264 if (dhd_assoc_state && !fw_assoc_state && !err) {
8265 if (!fw_assoc_watchdog_started) {
8266 fw_assoc_watchdog_ms = OSL_SYSUPTIME();
8267 fw_assoc_watchdog_started = TRUE;
8268 WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
8269 } else if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
8270 FW_ASSOC_WATCHDOG_TIME) {
8271 fw_assoc_watchdog_started = FALSE;
8272 err = -ENODEV;
8273 WL_TRACE_HW4(("fw is not associated for %d ms \n",
8274 (OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
8275 goto get_station_err;
8276 }
8277 }
8278 err = -ENODEV;
8279 goto error;
8280 }
8281 if (dhd_is_associated(dhd, 0, NULL)) {
8282 fw_assoc_watchdog_started = FALSE;
8283 }
8284 curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
8285 if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
8286 WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
8287 MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
8288 }
8289 /* go through to get another information */
8290 case WL_IF_TYPE_P2P_GC:
8291 case WL_IF_TYPE_P2P_DISC:
8292 if ((err = wl_cfg80211_get_rssi(dev, cfg, &rssi)) != BCME_OK) {
8293 goto get_station_err;
8294 }
8295#if defined(RSSIAVG)
8296 err = wl_update_connected_rssi_cache(dev, &cfg->g_connected_rssi_cache_ctrl, &rssi);
8297 if (err) {
8298 WL_ERR(("Could not get rssi (%d)\n", err));
8299 goto get_station_err;
8300 }
8301 wl_delete_dirty_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
8302 wl_reset_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
8303#endif
8304#if defined(RSSIOFFSET)
8305 rssi = wl_update_rssi_offset(dev, rssi);
8306#endif
8307#if !defined(RSSIAVG) && !defined(RSSIOFFSET)
8308 // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
8309 rssi = MIN(rssi, RSSI_MAXVAL);
8310#endif
8311 sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
8312 sinfo->signal = rssi;
8313 WL_DBG(("RSSI %d dBm\n", rssi));
8314#if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, \
8315 0))
8316 /* Query RSSI sum across antennas */
8317 memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
8318 err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
8319 if (err) {
8320 WL_ERR(("Could not get rssi sum (%d)\n", err));
8321 } else {
8322 chains = 0;
8323 for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
8324 sinfo->chain_signal[cnt] = rssi_ant_mimo.rssi_ant[cnt];
8325 chains |= (1 << cnt);
8326 WL_DBG(("RSSI[%d]: %d dBm\n",
8327 cnt, rssi_ant_mimo.rssi_ant[cnt]));
8328 }
8329 sinfo->chains = chains;
8330 sinfo->filled |= STA_INFO_BIT(INFO_CHAIN_SIGNAL);
8331 }
8332#endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
8333 /* go through to get another information */
8334 case WL_IF_TYPE_P2P_GO:
8335 /* Report the current tx rate */
8336 rate = 0;
8337 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
8338 if (err) {
8339 WL_ERR(("Could not get rate (%d)\n", err));
8340 } else {
8341#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
8342 int rxpktglom;
8343#endif
8344 rate = dtoh32(rate);
8345 sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
8346 sinfo->txrate.legacy = rate * 5;
8347 WL_DBG(("Rate %d Mbps\n", (rate / 2)));
8348#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
8349 rxpktglom = ((rate/2) > 150) ? 20 : 10;
8350
8351 if (maxrxpktglom != rxpktglom) {
8352 maxrxpktglom = rxpktglom;
8353 WL_DBG(("Rate %d Mbps, update bus:"
8354 "maxtxpktglom=%d\n", (rate/2), maxrxpktglom));
8355 err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
8356 (char*)&maxrxpktglom, 4, cfg->ioctl_buf,
8357 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8358 if (err < 0) {
8359 WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
8360 }
8361 }
8362#endif
8363 }
8364 if_stats = (wl_if_stats_t *)buf;
8365 bzero(if_stats, sizeof(*if_stats));
8366 if (FW_SUPPORTED(dhd, ifst)) {
8367 err = wl_cfg80211_ifstats_counters(dev, if_stats);
8368 } else
8369 {
8370 err = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
8371 (char *)if_stats, sizeof(*if_stats), NULL);
8372 }
8373
8374 if (err) {
8375// WL_ERR(("if_counters not supported ret=%d\n", err));
8376 bzero(&pktcnt, sizeof(pktcnt));
8377 err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt,
8378 sizeof(pktcnt));
8379 if (!err) {
8380 sinfo->rx_packets = pktcnt.rx_good_pkt;
8381 sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
8382 sinfo->tx_packets = pktcnt.tx_good_pkt;
8383 sinfo->tx_failed = pktcnt.tx_bad_pkt;
8384 }
8385 } else {
8386 sinfo->rx_packets = (uint32)dtoh64(if_stats->rxframe);
8387 /* In this case, if_stats->rxerror is invalid.
8388 * So, force to assign '0'.
8389 */
8390 sinfo->rx_dropped_misc = 0;
8391 sinfo->tx_packets = (uint32)dtoh64(if_stats->txfrmsnt);
8392 sinfo->tx_failed = (uint32)dtoh64(if_stats->txnobuf) +
8393 (uint32)dtoh64(if_stats->txrunt) +
8394 (uint32)dtoh64(if_stats->txfail);
8395 sinfo->rx_bytes = dtoh64(if_stats->rxbyte);
8396 sinfo->tx_bytes = dtoh64(if_stats->txbyte);
8397 sinfo->tx_retries = (uint32)dtoh64(if_stats->txretry);
8398 sinfo->filled |= (STA_INFO_BIT(INFO_RX_BYTES) |
8399 STA_INFO_BIT(INFO_TX_BYTES) |
8400 STA_INFO_BIT(INFO_TX_RETRIES));
8401 }
8402
8403 sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
8404 STA_INFO_BIT(INFO_RX_DROP_MISC) |
8405 STA_INFO_BIT(INFO_TX_PACKETS) |
8406 STA_INFO_BIT(INFO_TX_FAILED));
8407get_station_err:
8408 if (err && (err != -ENODATA)) {
8409 /* Disconnect due to zero BSSID or error to get RSSI */
8410 scb_val_t scbval;
8411 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
8412 dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
8413 scbval.val = htod32(DOT11_RC_DISASSOC_LEAVING);
8414 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
8415 sizeof(scb_val_t));
8416 if (unlikely(err)) {
8417 WL_ERR(("disassoc error (%d)\n", err));
8418 }
8419
8420 WL_ERR(("force cfg80211_disconnected: %d\n", err));
8421 wl_clr_drv_status(cfg, CONNECTED, dev);
8422 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_DONE),
8423 dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
8424 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
8425 wl_link_down(cfg);
8426 }
8427 break;
8428 case WL_IF_TYPE_AP:
8429 err = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac,
8430 ETHER_ADDR_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8431 if (err < 0) {
8432 WL_ERR(("GET STA INFO failed, %d\n", err));
8433 goto error;
8434 }
8435 sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
8436 sta = (sta_info_v4_t *)buf;
8437 if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
8438 WL_ERR(("GET STA INFO version mismatch, %d\n", err));
8439 return BCME_VERSION;
8440 }
8441 sta->len = dtoh16(sta->len);
8442 sta->cap = dtoh16(sta->cap);
8443 sta->flags = dtoh32(sta->flags);
8444 sta->idle = dtoh32(sta->idle);
8445 sta->in = dtoh32(sta->in);
8446 sinfo->inactive_time = sta->idle * 1000;
8447#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
8448 if (sta->flags & WL_STA_ASSOC) {
8449 sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
8450 sinfo->connected_time = sta->in;
8451 }
8452#endif
8453 WL_INFORM_MEM(("STA %s, flags 0x%x, idle time %ds, connected time %ds\n",
8454 bcm_ether_ntoa((const struct ether_addr *)mac, eabuf),
8455 sta->flags, sta->idle, sta->in));
8456 break;
8457 default :
8458 WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
8459 }
8460error:
8461 if (buf) {
8462 MFREE(cfg->osh, buf, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
8463 }
8464
8465 return err;
8466}
8467
8468static int
8469wl_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
8470 int idx, u8 *mac, struct station_info *sinfo)
8471{
8472 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8473 struct maclist *assoc_maclist = (struct maclist *)&(cfg->assoclist);
8474 int err;
8475
8476 WL_ERR(("%s: enter, idx=%d\n", __FUNCTION__, idx));
8477
8478 if (idx == 0) {
8479 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
8480 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
8481 assoc_maclist, sizeof(cfg->assoclist));
8482 if (err < 0) {
8483 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
8484 cfg->assoclist.count = 0;
8485 return -EOPNOTSUPP;
8486 }
8487 }
8488
8489 if (idx < le32_to_cpu(cfg->assoclist.count)) {
8490 memcpy(mac, cfg->assoclist.mac[idx], ETH_ALEN);
8491 return wl_cfg80211_get_station(wiphy, ndev, mac, sinfo);
8492 }
8493
8494 return -ENOENT;
8495}
8496
8497static s32
8498wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
8499 bool enabled, s32 timeout)
8500{
8501 s32 pm;
8502 s32 err = 0;
8503 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8504 struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
8505 s32 mode;
8506#ifdef RTT_SUPPORT
8507 rtt_status_info_t *rtt_status;
8508#endif /* RTT_SUPPORT */
8509 dhd_pub_t *dhd = cfg->pub;
8510 RETURN_EIO_IF_NOT_UP(cfg);
8511
8512 WL_DBG(("Enter\n"));
8513 mode = wl_get_mode_by_netdev(cfg, dev);
8514 if (cfg->p2p_net == dev || _net_info == NULL ||
8515 !wl_get_drv_status(cfg, CONNECTED, dev) ||
8516 ((mode != WL_MODE_BSS) &&
8517 (mode != WL_MODE_IBSS))) {
8518 return err;
8519 }
8520
8521 /* Enlarge pm_enable_work */
8522 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
8523
8524 pm = enabled ? PM_FAST : PM_OFF;
8525 if (_net_info->pm_block) {
8526 WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
8527 dev->name, _net_info->pm_block));
8528 pm = PM_OFF;
8529 }
8530 if (enabled && dhd_conf_get_pm(dhd) >= 0)
8531 pm = dhd_conf_get_pm(dhd);
8532 pm = htod32(pm);
8533 WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
8534#ifdef RTT_SUPPORT
8535 rtt_status = GET_RTTSTATE(dhd);
8536 if (rtt_status->status != RTT_ENABLED) {
8537#endif /* RTT_SUPPORT */
8538 err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
8539 if (unlikely(err)) {
8540 if (err == -ENODEV)
8541 WL_DBG(("net_device is not ready yet\n"));
8542 else
8543 WL_ERR(("error (%d)\n", err));
8544 return err;
8545 }
8546#ifdef RTT_SUPPORT
8547 }
8548#endif /* RTT_SUPPORT */
8549 wl_cfg80211_update_power_mode(dev);
8550 return err;
8551}
8552
8553/* force update cfg80211 to keep power save mode in sync. BUT this is NOT
8554 * a good solution since there is no protection while changing wdev->os. Best
8555 * way of changing power saving mode is doing it through
8556 * NL80211_CMD_SET_POWER_SAVE
8557 */
8558void wl_cfg80211_update_power_mode(struct net_device *dev)
8559{
8560 int err, pm = -1;
8561
8562 err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
8563 if (err)
8564 WL_ERR(("error (%d)\n", err));
8565 else if (pm != -1 && dev->ieee80211_ptr)
8566 dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
8567}
8568
8569static __used u32 wl_find_msb(u16 bit16)
8570{
8571 u32 ret = 0;
8572
8573 if (bit16 & 0xff00) {
8574 ret += 8;
8575 bit16 >>= 8;
8576 }
8577
8578 if (bit16 & 0xf0) {
8579 ret += 4;
8580 bit16 >>= 4;
8581 }
8582
8583 if (bit16 & 0xc) {
8584 ret += 2;
8585 bit16 >>= 2;
8586 }
8587
8588 if (bit16 & 2)
8589 ret += bit16 & 2;
8590 else if (bit16)
8591 ret += bit16;
8592
8593 return ret;
8594}
8595
8596static s32
8597wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
8598 s32 err)
8599{
8600 int i, j;
8601 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8602 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
8603 int npmkids = cfg->pmk_list->pmkids.count;
8604
8605 ASSERT(cfg->pmk_list->pmkids.length >= (sizeof(u16)*2));
8606 if (!pmk_list) {
8607 WL_ERR(("pmk_list is NULL\n"));
8608 return -EINVAL;
8609 }
8610 /* pmk list is supported only for STA interface i.e. primary interface
8611 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
8612 */
8613 if (primary_dev != dev) {
8614 WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
8615 " interfaces than primary interface\n"));
8616 return err;
8617 }
8618
8619 WL_DBG(("No of elements %d\n", npmkids));
8620 for (i = 0; i < npmkids; i++) {
8621 WL_DBG(("PMKID[%d]: %pM =\n", i,
8622 &pmk_list->pmkids.pmkid[i].bssid));
8623 for (j = 0; j < WPA2_PMKID_LEN; j++) {
8624 WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].pmkid[j]));
8625 }
8626 }
8627 if (cfg->wlc_ver.wlc_ver_major >= MIN_PMKID_LIST_V3_FW_MAJOR) {
8628 pmk_list->pmkids.version = PMKID_LIST_VER_3;
8629 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8630 sizeof(*pmk_list), cfg->ioctl_buf,
8631 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8632 }
8633 else if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V2_FW_MAJOR) {
8634 u32 v2_list_size = (u32)(sizeof(pmkid_list_v2_t) + npmkids*sizeof(pmkid_v2_t));
8635 pmkid_list_v2_t *pmkid_v2_list = (pmkid_list_v2_t *)MALLOCZ(cfg->osh, v2_list_size);
8636 pmkid_list_v3_t *spmk_list = &cfg->spmk_info_list->pmkids;
8637
8638 if (pmkid_v2_list == NULL) {
8639 WL_ERR(("failed to allocate pmkid list\n"));
8640 return BCME_NOMEM;
8641 }
8642
8643 pmkid_v2_list->version = PMKID_LIST_VER_2;
8644 /* Account for version, length and pmkid_v2_t fields */
8645 pmkid_v2_list->length = (npmkids * sizeof(pmkid_v2_t)) + (2 * sizeof(u16));
8646
8647 for (i = 0; i < npmkids; i++) {
8648 /* memcpy_s return checks not needed as buffers are of same size */
8649 (void)memcpy_s(&pmkid_v2_list->pmkid[i].BSSID,
8650 ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8651 ETHER_ADDR_LEN);
8652
8653 /* copy pmkid if available */
8654 if (pmk_list->pmkids.pmkid[i].pmkid_len) {
8655 (void)memcpy_s(pmkid_v2_list->pmkid[i].PMKID,
8656 WPA2_PMKID_LEN,
8657 pmk_list->pmkids.pmkid[i].pmkid,
8658 pmk_list->pmkids.pmkid[i].pmkid_len);
8659 }
8660
8661 if (pmk_list->pmkids.pmkid[i].pmk_len) {
8662 (void)memcpy_s(pmkid_v2_list->pmkid[i].pmk,
8663 pmk_list->pmkids.pmkid[i].pmk_len,
8664 pmk_list->pmkids.pmkid[i].pmk,
8665 pmk_list->pmkids.pmkid[i].pmk_len);
8666 pmkid_v2_list->pmkid[i].pmk_len = pmk_list->pmkids.pmkid[i].pmk_len;
8667 }
8668
8669 if (pmk_list->pmkids.pmkid[i].ssid_len) {
8670 (void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
8671 pmk_list->pmkids.pmkid[i].ssid_len,
8672 pmk_list->pmkids.pmkid[i].ssid,
8673 pmk_list->pmkids.pmkid[i].ssid_len);
8674 pmkid_v2_list->pmkid[i].ssid.ssid_len
8675 = pmk_list->pmkids.pmkid[i].ssid_len;
8676 }
8677
8678 (void)memcpy_s(pmkid_v2_list->pmkid[i].fils_cache_id,
8679 FILS_CACHE_ID_LEN, &pmk_list->pmkids.pmkid[i].fils_cache_id,
8680 FILS_CACHE_ID_LEN);
8681 for (j = 0; j < spmk_list->count; j++) {
8682 if (memcmp(&pmkid_v2_list->pmkid[i].BSSID,
8683 &spmk_list->pmkid[j].bssid, ETHER_ADDR_LEN)) {
8684 continue; /* different MAC */
8685 }
8686 WL_DBG(("SPMK replace idx:%d bssid: "MACF " to SSID: %d\n", i,
8687 ETHER_TO_MACF(pmkid_v2_list->pmkid[i].BSSID),
8688 spmk_list->pmkid[j].ssid_len));
8689 bzero(&pmkid_v2_list->pmkid[i].BSSID, ETHER_ADDR_LEN);
8690 pmkid_v2_list->pmkid[i].ssid.ssid_len =
8691 spmk_list->pmkid[j].ssid_len;
8692 (void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
8693 spmk_list->pmkid[j].ssid_len,
8694 spmk_list->pmkid[j].ssid,
8695 spmk_list->pmkid[j].ssid_len);
8696 }
8697 pmkid_v2_list->pmkid[i].length = PMKID_ELEM_V2_LENGTH;
8698 }
8699
8700 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v2_list,
8701 v2_list_size, cfg->ioctl_buf,
8702 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8703 if (unlikely(err)) {
8704 WL_ERR(("pmkid_info failed (%d)\n", err));
8705 }
8706
8707 MFREE(cfg->osh, pmkid_v2_list, v2_list_size);
8708 }
8709 else {
8710 u32 v1_list_size = (u32)(sizeof(pmkid_list_v1_t) + npmkids*sizeof(pmkid_v1_t));
8711 pmkid_list_v1_t *pmkid_v1_list = (pmkid_list_v1_t *)MALLOCZ(cfg->osh, v1_list_size);
8712 if (pmkid_v1_list == NULL) {
8713 WL_ERR(("failed to allocate pmkid list\n"));
8714 return BCME_NOMEM;
8715 }
8716 for (i = 0; i < npmkids; i++) {
8717 /* memcpy_s return checks not needed as buffers are of same size */
8718 (void)memcpy_s(&pmkid_v1_list->pmkid[i].BSSID,
8719 ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8720 ETHER_ADDR_LEN);
8721 (void)memcpy_s(pmkid_v1_list->pmkid[i].PMKID,
8722 WPA2_PMKID_LEN, pmk_list->pmkids.pmkid[i].pmkid,
8723 WPA2_PMKID_LEN);
8724 pmkid_v1_list->npmkid++;
8725 }
8726 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v1_list,
8727 v1_list_size, cfg->ioctl_buf,
8728 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8729 if (unlikely(err)) {
8730 WL_ERR(("pmkid_info failed (%d)\n", err));
8731 }
8732
8733 MFREE(cfg->osh, pmkid_v1_list, v1_list_size);
8734 }
8735 return err;
8736}
8737
8738/* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8739 * entry operation.
8740 */
8741static s32
8742wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
8743 struct cfg80211_pmksa *pmksa)
8744{
8745 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8746 s32 err = 0;
8747 int i;
8748 int npmkids = cfg->pmk_list->pmkids.count;
8749 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
8750
8751 if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) {
8752 err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, TRUE);
8753 if (err != BCME_OK) {
8754 WL_ERR(("wl_cfg80211_set_pmksa err:%d\n", err));
8755 }
8756 return err;
8757 }
8758
8759 RETURN_EIO_IF_NOT_UP(cfg);
8760 BCM_REFERENCE(dhdp);
8761 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_PMKSA), dhd_net2idx(dhdp->info, dev), 0);
8762
8763 for (i = 0; i < npmkids; i++) {
8764 if (pmksa->bssid != NULL) {
8765 if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8766 ETHER_ADDR_LEN))
8767 break;
8768 }
8769#ifdef WL_FILS
8770 else if (pmksa->ssid != NULL) {
8771 if (!memcmp(pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8772 pmksa->ssid_len))
8773 break;
8774 }
8775#endif /* WL_FILS */
8776 }
8777 if (i < WL_NUM_PMKIDS_MAX) {
8778 if (pmksa->bssid != NULL) {
8779 memcpy(&cfg->pmk_list->pmkids.pmkid[i].bssid, pmksa->bssid,
8780 ETHER_ADDR_LEN);
8781 }
8782#ifdef WL_FILS
8783 else if (pmksa->ssid != NULL) {
8784 cfg->pmk_list->pmkids.pmkid[i].ssid_len = pmksa->ssid_len;
8785 memcpy(&cfg->pmk_list->pmkids.pmkid[i].ssid, pmksa->ssid,
8786 pmksa->ssid_len);
8787 memcpy(&cfg->pmk_list->pmkids.pmkid[i].fils_cache_id, pmksa->cache_id,
8788 FILS_CACHE_ID_LEN);
8789 }
8790#endif /* WL_FILS */
8791#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS))
8792 if (pmksa->pmk_len) {
8793 if (memcpy_s(&cfg->pmk_list->pmkids.pmkid[i].pmk, PMK_LEN_MAX, pmksa->pmk,
8794 pmksa->pmk_len)) {
8795 WL_ERR(("invalid pmk len = %zu", pmksa->pmk_len));
8796 } else {
8797 cfg->pmk_list->pmkids.pmkid[i].pmk_len = pmksa->pmk_len;
8798 }
8799 }
8800#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS) */
8801 /* return check not required as buffer lengths are same */
8802 (void)memcpy_s(cfg->pmk_list->pmkids.pmkid[i].pmkid, WPA2_PMKID_LEN, pmksa->pmkid,
8803 WPA2_PMKID_LEN);
8804 cfg->pmk_list->pmkids.pmkid[i].pmkid_len = WPA2_PMKID_LEN;
8805
8806 /* set lifetime not to expire in firmware by default.
8807 * Currently, wpa_supplicant control PMKID lifetime on his end. e.g) set 12 hours
8808 * when it expired, wpa_supplicant should call set_pmksa/del_pmksa to update
8809 * corresponding entry.
8810 */
8811 cfg->pmk_list->pmkids.pmkid[i].time_left = KEY_PERM_PMK;
8812 if (i == npmkids) {
8813 cfg->pmk_list->pmkids.length += sizeof(pmkid_v3_t);
8814 cfg->pmk_list->pmkids.count++;
8815 }
8816 } else {
8817 err = -EINVAL;
8818 }
8819
8820#if (WL_DBG_LEVEL > 0)
8821 if (pmksa->bssid != NULL) {
8822 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
8823 &cfg->pmk_list->pmkids.pmkid[npmkids - 1].bssid));
8824 }
8825 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8826 WL_DBG(("%02x\n",
8827 cfg->pmk_list->pmkids.pmkid[npmkids - 1].
8828 pmkid[i]));
8829 }
8830#endif /* (WL_DBG_LEVEL > 0) */
8831
8832 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8833
8834 return err;
8835}
8836
8837/* sending pmkid_info IOVAR to manipulate PMKID(PMKSA) list in firmware.
8838 * input @pmksa: host given single pmksa info.
8839 * if it's NULL, assume whole list manipulated. e.g) flush all PMKIDs in firmware.
8840 * input @set: TRUE means adding PMKSA operation. FALSE means deleting.
8841 * return: log internal BCME_XXX error, and convert it to -EINVAL to linux generic error code.
8842 */
8843static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
8844 struct cfg80211_pmksa *pmksa, bool set) {
8845
8846 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8847 s32 err = 0;
8848 pmkid_list_v3_t *pmk_list;
8849 uint32 alloc_len;
8850
8851 RETURN_EIO_IF_NOT_UP(cfg);
8852
8853 if (cfg->wlc_ver.wlc_ver_major < MIN_PMKID_LIST_V3_FW_MAJOR) {
8854 WL_DBG(("wlc_ver_major not supported:%d\n", cfg->wlc_ver.wlc_ver_major));
8855 return BCME_VERSION;
8856 }
8857
8858 alloc_len = (uint32)(OFFSETOF(pmkid_list_v3_t, pmkid) + ((pmksa) ? sizeof(pmkid_v3_t) : 0));
8859 pmk_list = (pmkid_list_v3_t *)MALLOCZ(cfg->osh, alloc_len);
8860
8861 if (pmk_list == NULL) {
8862 return BCME_NOMEM;
8863 }
8864
8865 pmk_list->version = PMKID_LIST_VER_3;
8866 pmk_list->length = alloc_len;
8867 pmk_list->count = (pmksa) ? 1 : 0; // 1 means single entry operation, 0 means whole list.
8868 pmk_list->flag = (set) ? PMKDB_SET_IOVAR : PMKDB_CLEAR_IOVAR;
8869
8870 if (pmksa) {
8871 /* controll set/del action by lifetime parameter accordingly.
8872 * if set == TRUE, it's set PMKID action with lifetime permanent.
8873 * if set == FALSE, it's del PMKID action with lifetime zero.
8874 */
8875 pmk_list->pmkid->time_left = (set) ? KEY_PERM_PMK : 0;
8876 if (pmksa->bssid) {
8877 eacopy(pmksa->bssid, &pmk_list->pmkid->bssid);
8878 }
8879 if (pmksa->pmkid) {
8880 err = memcpy_s(&pmk_list->pmkid->pmkid, sizeof(pmk_list->pmkid->pmkid),
8881 pmksa->pmkid, WPA2_PMKID_LEN);
8882 if (err) {
8883 goto exit;
8884 }
8885 pmk_list->pmkid->pmkid_len = WPA2_PMKID_LEN;
8886 }
8887#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
8888 if (pmksa->pmk) {
8889 err = memcpy_s(&pmk_list->pmkid->pmk, sizeof(pmk_list->pmkid->pmk),
8890 pmksa->pmk, pmksa->pmk_len);
8891 if (err) {
8892 goto exit;
8893 }
8894 pmk_list->pmkid->pmk_len = pmksa->pmk_len;
8895 }
8896 if (pmksa->ssid) {
8897 err = memcpy_s(&pmk_list->pmkid->ssid, sizeof(pmk_list->pmkid->ssid),
8898 pmksa->ssid, pmksa->ssid_len);
8899 if (err) {
8900 goto exit;
8901 }
8902 pmk_list->pmkid->ssid_len = pmksa->ssid_len;
8903 }
8904 if (pmksa->cache_id) {
8905 pmk_list->pmkid->fils_cache_id = *(const uint16 *)pmksa->cache_id;
8906 }
8907#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
8908 }
8909
8910 if (wl_dbg_level & WL_DBG_DBG) {
8911 prhex("pmklist_data", (char *)pmk_list, alloc_len);
8912 }
8913
8914 err = wldev_iovar_setbuf(dev, "pmkdb", (char *)pmk_list,
8915 alloc_len, cfg->ioctl_buf,
8916 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8917 if (unlikely(err)) {
8918 WL_ERR(("pmkdb set failed. err:%d\n", err));
8919 }
8920exit:
8921 if (pmk_list) {
8922 MFREE(cfg->osh, pmk_list, alloc_len);
8923 }
8924 return err;
8925}
8926
8927/* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8928 * entry operation.
8929 */
8930static s32
8931wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
8932 struct cfg80211_pmksa *pmksa)
8933{
8934 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8935 s32 err = 0;
8936 int i;
8937 int npmkids = cfg->pmk_list->pmkids.count;
8938 RETURN_EIO_IF_NOT_UP(cfg);
8939
8940 if (!pmksa) {
8941 WL_ERR(("pmksa is not initialized\n"));
8942 return BCME_ERROR;
8943 }
8944 if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) {
8945 err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
8946 if (err != BCME_OK) {
8947 WL_ERR(("wl_cfg80211_del_pmksa err:%d\n", err));
8948 }
8949 return err;
8950 }
8951
8952 if (!npmkids) {
8953 /* nmpkids = 0, nothing to delete */
8954 WL_DBG(("npmkids=0. Skip del\n"));
8955 return BCME_OK;
8956 }
8957
8958#if (WL_DBG_LEVEL > 0)
8959 if (pmksa->bssid) {
8960 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
8961 pmksa->bssid));
8962 }
8963#ifdef WL_FILS
8964 else if (pmksa->ssid) {
8965 WL_DBG(("FILS: del_pmksa for ssid: "));
8966 for (i = 0; i < pmksa->ssid_len; i++) {
8967 WL_DBG(("%c", pmksa->ssid[i]));
8968 }
8969 WL_DBG(("\n"));
8970 }
8971#endif /* WL_FILS */
8972 if (pmksa->pmkid) {
8973 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8974 WL_DBG(("%02x\n", pmksa->pmkid[i]));
8975 }
8976 }
8977#endif /* (WL_DBG_LEVEL > 0) */
8978
8979 for (i = 0; i < npmkids; i++) {
8980 if (pmksa->bssid) {
8981 if (!memcmp
8982 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8983 ETHER_ADDR_LEN)) {
8984 break;
8985 }
8986 }
8987#ifdef WL_FILS
8988 else if (pmksa->ssid) {
8989 if (!memcmp
8990 (pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8991 pmksa->ssid_len)) {
8992 break;
8993 }
8994 }
8995#endif /* WL_FILS */
8996 }
8997 if ((npmkids > 0) && (i < npmkids)) {
8998 bzero(&cfg->pmk_list->pmkids.pmkid[i], sizeof(pmkid_v3_t));
8999 for (; i < (npmkids - 1); i++) {
9000 (void)memcpy_s(&cfg->pmk_list->pmkids.pmkid[i],
9001 sizeof(pmkid_v3_t),
9002 &cfg->pmk_list->pmkids.pmkid[i + 1],
9003 sizeof(pmkid_v3_t));
9004 }
9005 npmkids--;
9006 cfg->pmk_list->pmkids.length -= sizeof(pmkid_v3_t);
9007 cfg->pmk_list->pmkids.count--;
9008
9009 } else {
9010 err = -EINVAL;
9011 }
9012
9013 /* current wl_update_pmklist() doesn't delete corresponding PMKID entry.
9014 * inside firmware. So we need to issue delete action explicitely through
9015 * this function.
9016 */
9017 err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
9018 /* intentional fall through even on error.
9019 * it should work above MIN_PMKID_LIST_V3_FW_MAJOR, otherwise let ignore it.
9020 */
9021
9022 err = wl_update_pmklist(dev, cfg->pmk_list, err);
9023
9024 return err;
9025
9026}
9027
9028/* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
9029 * entry operation.
9030 */
9031static s32
9032wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
9033{
9034 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9035 s32 err = 0;
9036 RETURN_EIO_IF_NOT_UP(cfg);
9037 if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) {
9038 /* NULL pmksa means delete whole PMKSA list */
9039 err = wl_cfg80211_update_pmksa(wiphy, dev, NULL, FALSE);
9040 if (err != BCME_OK) {
9041 WL_ERR(("wl_cfg80211_flush_pmksa err:%d\n", err));
9042 }
9043 return err;
9044 }
9045 bzero(cfg->pmk_list, sizeof(*cfg->pmk_list));
9046 cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
9047 cfg->pmk_list->pmkids.count = 0;
9048 cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
9049 err = wl_update_pmklist(dev, cfg->pmk_list, err);
9050 return err;
9051}
9052
9053static void
9054wl_cfg80211_afx_handler(struct work_struct *work)
9055{
9056 struct afx_hdl *afx_instance;
9057 struct bcm_cfg80211 *cfg;
9058 s32 ret = BCME_OK;
9059
9060 BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
9061 if (afx_instance) {
9062 cfg = wl_get_cfg(afx_instance->dev);
9063 if (cfg != NULL && cfg->afx_hdl->is_active) {
9064 if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
9065 ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
9066 (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
9067 } else {
9068 ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
9069 cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
9070 NULL);
9071 }
9072 if (unlikely(ret != BCME_OK)) {
9073 WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
9074 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
9075 complete(&cfg->act_frm_scan);
9076 }
9077 }
9078 }
9079}
9080
9081static s32
9082wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
9083{
9084 u32 max_retry = WL_CHANNEL_SYNC_RETRY;
9085 bool is_p2p_gas = false;
9086
9087 if (dev == NULL)
9088 return -1;
9089
9090 WL_DBG((" enter ) \n"));
9091
9092 wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
9093 cfg->afx_hdl->is_active = TRUE;
9094
9095 if (cfg->afx_hdl->pending_tx_act_frm) {
9096 wl_action_frame_t *action_frame;
9097 action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
9098 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len))
9099 is_p2p_gas = true;
9100 }
9101
9102 /* Loop to wait until we find a peer's channel or the
9103 * pending action frame tx is cancelled.
9104 */
9105 while ((cfg->afx_hdl->retry < max_retry) &&
9106 (cfg->afx_hdl->peer_chan == WL_INVALID)) {
9107 cfg->afx_hdl->is_listen = FALSE;
9108 wl_set_drv_status(cfg, SCANNING, dev);
9109 WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
9110 cfg->afx_hdl->retry));
9111 /* search peer on peer's listen channel */
9112 schedule_work(&cfg->afx_hdl->work);
9113 wait_for_completion_timeout(&cfg->act_frm_scan,
9114 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
9115
9116 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
9117 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
9118 break;
9119
9120 if (is_p2p_gas)
9121 break;
9122
9123 if (cfg->afx_hdl->my_listen_chan) {
9124 WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
9125 cfg->afx_hdl->my_listen_chan));
9126 /* listen on my listen channel */
9127 cfg->afx_hdl->is_listen = TRUE;
9128 schedule_work(&cfg->afx_hdl->work);
9129 wait_for_completion_timeout(&cfg->act_frm_scan,
9130 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
9131 }
9132 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
9133 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
9134 break;
9135
9136 cfg->afx_hdl->retry++;
9137
9138 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
9139 }
9140
9141 cfg->afx_hdl->is_active = FALSE;
9142
9143 wl_clr_drv_status(cfg, SCANNING, dev);
9144 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
9145
9146 return (cfg->afx_hdl->peer_chan);
9147}
9148
9149struct p2p_config_af_params {
9150 s32 max_tx_retry; /* max tx retry count if tx no ack */
9151#ifdef WL_CFG80211_GON_COLLISION
9152 /* drop tx go nego request if go nego collision occurs */
9153 bool drop_tx_req;
9154#endif
9155#ifdef WL_CFG80211_SYNC_GON
9156 /* WAR: dongle does not keep the dwell time of 'actframe' sometime.
9157 * if extra_listen is set, keep the dwell time to get af response frame
9158 */
9159 bool extra_listen;
9160#endif
9161 bool search_channel; /* 1: search peer's channel to send af */
9162};
9163
9164static s32
9165wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
9166 wl_action_frame_t *action_frame, wl_af_params_t *af_params,
9167 struct p2p_config_af_params *config_af_params)
9168{
9169 s32 err = BCME_OK;
9170 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9171 wifi_p2p_pub_act_frame_t *act_frm =
9172 (wifi_p2p_pub_act_frame_t *) (action_frame->data);
9173
9174 /* initialize default value */
9175#ifdef WL_CFG80211_GON_COLLISION
9176 config_af_params->drop_tx_req = false;
9177#endif
9178#ifdef WL_CFG80211_SYNC_GON
9179 config_af_params->extra_listen = true;
9180#endif
9181 config_af_params->search_channel = false;
9182 config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
9183 cfg->next_af_subtype = WL_PUB_AF_STYPE_INVALID;
9184
9185 switch (act_frm->subtype) {
9186 case P2P_PAF_GON_REQ: {
9187 /* Disable he if peer does not support before starting GONEG */
9188 WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
9189 wl_set_p2p_status(cfg, GO_NEG_PHASE);
9190
9191 config_af_params->search_channel = true;
9192 cfg->next_af_subtype = act_frm->subtype + 1;
9193
9194 /* increase dwell time to wait for RESP frame */
9195 af_params->dwell_time = WL_MED_DWELL_TIME;
9196
9197#ifdef WL_CFG80211_GON_COLLISION
9198 config_af_params->drop_tx_req = true;
9199#endif /* WL_CFG80211_GON_COLLISION */
9200 break;
9201 }
9202 case P2P_PAF_GON_RSP: {
9203 cfg->next_af_subtype = act_frm->subtype + 1;
9204 /* increase dwell time to wait for CONF frame */
9205 /* WAR : 100ms is added because kernel spent more time in some case.
9206 * Kernel should be fixed.
9207 */
9208 af_params->dwell_time = WL_MED_DWELL_TIME + 100;
9209 break;
9210 }
9211 case P2P_PAF_GON_CONF: {
9212 /* If we reached till GO Neg confirmation reset the filter */
9213 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
9214 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
9215
9216 /* minimize dwell time */
9217 af_params->dwell_time = WL_MIN_DWELL_TIME;
9218
9219#ifdef WL_CFG80211_GON_COLLISION
9220 /* if go nego formation done, clear it */
9221 cfg->block_gon_req_tx_count = 0;
9222 cfg->block_gon_req_rx_count = 0;
9223#endif /* WL_CFG80211_GON_COLLISION */
9224#ifdef WL_CFG80211_SYNC_GON
9225 config_af_params->extra_listen = false;
9226#endif /* WL_CFG80211_SYNC_GON */
9227 break;
9228 }
9229 case P2P_PAF_INVITE_REQ: {
9230 config_af_params->search_channel = true;
9231 cfg->next_af_subtype = act_frm->subtype + 1;
9232
9233 /* increase dwell time */
9234 af_params->dwell_time = WL_MED_DWELL_TIME;
9235 break;
9236 }
9237 case P2P_PAF_INVITE_RSP:
9238 /* minimize dwell time */
9239 af_params->dwell_time = WL_MIN_DWELL_TIME;
9240#ifdef WL_CFG80211_SYNC_GON
9241 config_af_params->extra_listen = false;
9242#endif /* WL_CFG80211_SYNC_GON */
9243 break;
9244 case P2P_PAF_DEVDIS_REQ: {
9245 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
9246 action_frame->len)) {
9247 config_af_params->search_channel = true;
9248 }
9249
9250 cfg->next_af_subtype = act_frm->subtype + 1;
9251 /* maximize dwell time to wait for RESP frame */
9252 af_params->dwell_time = WL_LONG_DWELL_TIME;
9253 break;
9254 }
9255 case P2P_PAF_DEVDIS_RSP:
9256 /* minimize dwell time */
9257 af_params->dwell_time = WL_MIN_DWELL_TIME;
9258#ifdef WL_CFG80211_SYNC_GON
9259 config_af_params->extra_listen = false;
9260#endif /* WL_CFG80211_SYNC_GON */
9261 break;
9262 case P2P_PAF_PROVDIS_REQ: {
9263 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
9264 action_frame->len)) {
9265 config_af_params->search_channel = true;
9266 }
9267
9268 cfg->next_af_subtype = act_frm->subtype + 1;
9269 /* increase dwell time to wait for RESP frame */
9270 af_params->dwell_time = WL_MED_DWELL_TIME;
9271 break;
9272 }
9273 case P2P_PAF_PROVDIS_RSP: {
9274 /* wpa_supplicant send go nego req right after prov disc */
9275 cfg->next_af_subtype = P2P_PAF_GON_REQ;
9276 af_params->dwell_time = WL_MED_DWELL_TIME;
9277#ifdef WL_CFG80211_SYNC_GON
9278 config_af_params->extra_listen = false;
9279#endif /* WL_CFG80211_SYNC_GON */
9280 break;
9281 }
9282 default:
9283 WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
9284 act_frm->subtype));
9285 err = BCME_BADARG;
9286 }
9287 return err;
9288}
9289
9290#if defined(WL11U) && defined(WL_HOST_AF_DFS_CHECK)
9291static bool
9292wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params,
9293 void *frame, u16 frame_len)
9294{
9295 struct wl_scan_results *bss_list;
9296 wl_bss_info_t *bi = NULL;
9297 bool result = false;
9298 s32 i;
9299 chanspec_t chanspec;
9300
9301 /* If DFS channel is 52~148, check to block it or not */
9302 if (af_params &&
9303 (af_params->channel >= 52 && af_params->channel <= 148)) {
9304 if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
9305 bss_list = cfg->bss_list;
9306 bi = next_bss(bss_list, bi);
9307 for_each_bss(bss_list, bi, i) {
9308 chanspec = wl_chspec_driver_to_host(bi->chanspec);
9309 if (CHSPEC_IS5G(chanspec) &&
9310 ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec))
9311 == af_params->channel)) {
9312 result = true; /* do not block the action frame */
9313 break;
9314 }
9315 }
9316 }
9317 }
9318 else {
9319 result = true;
9320 }
9321
9322 WL_DBG(("result=%s", result?"true":"false"));
9323 return result;
9324}
9325#endif /* WL11U && WL_HOST_AF_DFS_CHECK */
9326static bool
9327wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies)
9328{
9329 if ((requested_dwell & CUSTOM_RETRY_MASK) &&
9330 (jiffies_to_msecs(jiffies - dwell_jiffies) >
9331 (requested_dwell & ~CUSTOM_RETRY_MASK))) {
9332 WL_ERR(("Action frame TX retry time over dwell time!\n"));
9333 return true;
9334 }
9335 return false;
9336}
9337
9338static bool
9339wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
9340 bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
9341 wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
9342{
9343#ifdef WL11U
9344 struct net_device *ndev = NULL;
9345#endif /* WL11U */
9346 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9347 bool ack = false;
9348 u8 category, action;
9349 s32 tx_retry;
9350 struct p2p_config_af_params config_af_params;
9351 struct net_info *netinfo;
9352#ifdef VSDB
9353 ulong off_chan_started_jiffies = 0;
9354#endif
9355 ulong dwell_jiffies = 0;
9356 bool dwell_overflow = false;
9357 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
9358
9359 int32 requested_dwell = af_params->dwell_time;
9360
9361 /* Add the default dwell time
9362 * Dwell time to stay off-channel to wait for a response action frame
9363 * after transmitting an GO Negotiation action frame
9364 */
9365 af_params->dwell_time = WL_DEFAULT_DWELL_TIME;
9366
9367#ifdef WL11U
9368#if defined(WL_CFG80211_P2P_DEV_IF)
9369 ndev = dev;
9370#else
9371 ndev = ndev_to_cfgdev(cfgdev);
9372#endif /* WL_CFG80211_P2P_DEV_IF */
9373#endif /* WL11U */
9374
9375 category = action_frame->data[DOT11_ACTION_CAT_OFF];
9376 action = action_frame->data[DOT11_ACTION_ACT_OFF];
9377
9378 /* initialize variables */
9379 tx_retry = 0;
9380 cfg->next_af_subtype = WL_PUB_AF_STYPE_INVALID;
9381 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
9382 config_af_params.search_channel = false;
9383#ifdef WL_CFG80211_GON_COLLISION
9384 config_af_params.drop_tx_req = false;
9385#endif
9386#ifdef WL_CFG80211_SYNC_GON
9387 config_af_params.extra_listen = false;
9388#endif
9389
9390 /* config parameters */
9391 /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
9392 if (category == DOT11_ACTION_CAT_PUBLIC) {
9393 if (wl_cfg80211_is_dpp_frame((void *)action_frame->data, action_frame->len)) {
9394 wl_dpp_pa_frame_t *pa = (wl_dpp_pa_frame_t *)action_frame->data;
9395 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
9396 af_params->dwell_time = WL_MED_DWELL_TIME;
9397 cfg->need_wait_afrx = true;
9398 /* once matching frame is found in rx, abort dwell (upper layer
9399 * doesn't do that).
9400 */
9401 if (pa->ftype == DPP_AUTH_REQ) {
9402 cfg->next_af_subtype = DPP_AUTH_RESP;
9403 } else if (pa->ftype == DPP_AUTH_RESP) {
9404 cfg->next_af_subtype = DPP_AUTH_CONF;
9405 } else {
9406 cfg->next_af_subtype = WL_PUB_AF_STYPE_INVALID;
9407 cfg->need_wait_afrx = false;
9408 }
9409 } else if (wl_cfg80211_is_dpp_gas_action(
9410 (void *)action_frame->data, action_frame->len)) {
9411 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
9412 af_params->dwell_time = WL_MED_DWELL_TIME;
9413 cfg->need_wait_afrx = true;
9414 config_af_params.search_channel = false;
9415
9416 if (requested_dwell == 0) {
9417 /* Use minimal dwell to take care of Ack */
9418 af_params->dwell_time = WL_MIN_DWELL_TIME;
9419 }
9420 } else if ((action == P2P_PUB_AF_ACTION) &&
9421 (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
9422 /* p2p public action frame process */
9423 if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy,
9424 action_frame, af_params, &config_af_params)) {
9425 /* just send unknown subtype frame with default parameters. */
9426 WL_DBG(("Unknown subtype.\n"));
9427 }
9428
9429#ifdef WL_CFG80211_GON_COLLISION
9430 if (config_af_params.drop_tx_req) {
9431 if (cfg->block_gon_req_tx_count) {
9432 /* drop gon req tx action frame */
9433 WL_DBG(("Drop gon req tx action frame: count %d\n",
9434 cfg->block_gon_req_tx_count));
9435 goto exit;
9436 }
9437 }
9438#endif /* WL_CFG80211_GON_COLLISION */
9439 } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
9440 /* service discovery process */
9441 if (action == P2PSD_ACTION_ID_GAS_IREQ ||
9442 action == P2PSD_ACTION_ID_GAS_CREQ) {
9443 /* configure service discovery query frame */
9444 config_af_params.search_channel = true;
9445
9446 /* save next af suptype to cancel remained dwell time */
9447 cfg->next_af_subtype = action + 1;
9448
9449 af_params->dwell_time = WL_MED_DWELL_TIME;
9450 if (requested_dwell & CUSTOM_RETRY_MASK) {
9451 config_af_params.max_tx_retry =
9452 (requested_dwell & CUSTOM_RETRY_MASK) >> 24;
9453 af_params->dwell_time =
9454 (requested_dwell & ~CUSTOM_RETRY_MASK);
9455 WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
9456 config_af_params.max_tx_retry,
9457 af_params->dwell_time));
9458 }
9459 } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
9460 action == P2PSD_ACTION_ID_GAS_CRESP) {
9461 /* configure service discovery response frame */
9462 af_params->dwell_time = WL_MIN_DWELL_TIME;
9463 } else {
9464 WL_DBG(("Unknown action type: %d\n", action));
9465 }
9466 } else {
9467 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
9468 category, action, action_frame_len));
9469 }
9470 } else if (category == P2P_AF_CATEGORY) {
9471 /* do not configure anything. it will be sent with a default configuration */
9472 } else {
9473 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
9474 category, action));
9475 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
9476 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9477 return false;
9478 }
9479 }
9480
9481 netinfo = wl_get_netinfo_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
9482 /* validate channel and p2p ies */
9483 if (config_af_params.search_channel &&
9484 IS_P2P_SOCIAL(CHSPEC_CHANNEL(af_params->channel)) &&
9485 netinfo && netinfo->bss.ies.probe_req_ie_len) {
9486 config_af_params.search_channel = true;
9487 } else {
9488 config_af_params.search_channel = false;
9489 }
9490#ifdef WL11U
9491 if (ndev == bcmcfg_to_prmry_ndev(cfg))
9492 config_af_params.search_channel = false;
9493#endif /* WL11U */
9494
9495#ifdef VSDB
9496 /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
9497 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
9498 OSL_SLEEP(50);
9499 }
9500#endif
9501
9502 /* if scan is ongoing, abort current scan. */
9503 if (wl_get_drv_status_all(cfg, SCANNING)) {
9504 wl_cfg80211_cancel_scan(cfg);
9505 }
9506
9507 /* Abort P2P listen */
9508 if (discover_cfgdev(cfgdev, cfg)) {
9509 if (cfg->p2p_supported && cfg->p2p) {
9510 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
9511 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
9512 }
9513 }
9514
9515#if defined(WL11U) && defined(WL_HOST_AF_DFS_CHECK)
9516 /* handling DFS channel exceptions */
9517 if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) {
9518 return false; /* the action frame was blocked */
9519 }
9520#endif /* WL11U && WL_HOST_AF_DFS_CHECK */
9521
9522 /* set status and destination address before sending af */
9523 if (cfg->next_af_subtype != WL_PUB_AF_STYPE_INVALID) {
9524 /* set this status to cancel the remained dwell time in rx process */
9525 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9526 }
9527 wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
9528 memcpy(cfg->afx_hdl->tx_dst_addr.octet,
9529 af_params->action_frame.da.octet,
9530 sizeof(cfg->afx_hdl->tx_dst_addr.octet));
9531
9532 /* save af_params for rx process */
9533 cfg->afx_hdl->pending_tx_act_frm = af_params;
9534
9535 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
9536 WL_DBG(("Set GAS action frame config.\n"));
9537 config_af_params.search_channel = false;
9538 config_af_params.max_tx_retry = 1;
9539 }
9540
9541 /* search peer's channel */
9542 if (config_af_params.search_channel) {
9543 /* initialize afx_hdl */
9544 if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
9545 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
9546 goto exit;
9547 }
9548 cfg->afx_hdl->dev = dev;
9549 cfg->afx_hdl->retry = 0;
9550 cfg->afx_hdl->peer_chan = WL_INVALID;
9551
9552 if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
9553 WL_ERR(("couldn't find peer's channel.\n"));
9554 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
9555 af_params->channel);
9556 /* Even if we couldn't find peer channel, try to send the frame
9557 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
9558 * respond to probe request (Ideally it has to be in listen and
9559 * responsd to probe request). However if we send Go neg req, the
9560 * peer is sending GO-neg resp. So instead of giving up here, just
9561 * proceed and attempt sending out the action frame.
9562 */
9563 }
9564
9565 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
9566 /*
9567 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
9568 * but after the check of piggyback algorithm.
9569 * To take care of current piggback algo, lets abort the scan here itself.
9570 */
9571 wl_cfg80211_cancel_scan(cfg);
9572 /* Suspend P2P discovery's search-listen to prevent it from
9573 * starting a scan or changing the channel.
9574 */
9575 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9576 WL_ERR(("Can not disable discovery mode\n"));
9577 goto exit;
9578 }
9579
9580 /* update channel */
9581 if (cfg->afx_hdl->peer_chan != WL_INVALID) {
9582 af_params->channel = cfg->afx_hdl->peer_chan;
9583 WL_ERR(("Attempt tx on peer listen channel:%d ",
9584 cfg->afx_hdl->peer_chan));
9585 } else {
9586 WL_ERR(("Attempt tx with the channel provided by userspace."
9587 "Channel: %d\n", af_params->channel));
9588 }
9589 }
9590
9591#ifdef VSDB
9592 off_chan_started_jiffies = jiffies;
9593#endif /* VSDB */
9594
9595 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel);
9596
9597 wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
9598
9599 dwell_jiffies = jiffies;
9600 /* Now send a tx action frame */
9601 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
9602 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9603
9604 /* if failed, retry it. tx_retry_max value is configure by .... */
9605 while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry) &&
9606 !dwell_overflow) {
9607#ifdef VSDB
9608 if (af_params->channel) {
9609 if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
9610 OFF_CHAN_TIME_THRESHOLD_MS) {
9611 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
9612 off_chan_started_jiffies = jiffies;
9613 } else
9614 OSL_SLEEP(AF_RETRY_DELAY_TIME);
9615 }
9616#endif /* VSDB */
9617 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
9618 false : true;
9619 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9620 }
9621
9622 if (ack == false) {
9623 WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
9624 }
9625 WL_DBG(("Complete to send action frame\n"));
9626exit:
9627 /* Clear SENDING_ACT_FRM after all sending af is done */
9628 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9629
9630#ifdef WL_CFG80211_SYNC_GON
9631 /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
9632 * if we coundn't get the next action response frame and dongle does not keep
9633 * the dwell time, go to listen state again to get next action response frame.
9634 */
9635 if (ack && config_af_params.extra_listen &&
9636#ifdef WL_CFG80211_GON_COLLISION
9637 !cfg->block_gon_req_tx_count &&
9638#endif /* WL_CFG80211_GON_COLLISION */
9639 wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
9640 cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
9641 s32 extar_listen_time;
9642
9643 extar_listen_time = af_params->dwell_time -
9644 jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
9645
9646 if (extar_listen_time > 50) {
9647 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9648 WL_DBG(("Wait more time! actual af time:%d,"
9649 "calculated extar listen:%d\n",
9650 af_params->dwell_time, extar_listen_time));
9651 if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
9652 extar_listen_time + 100) == BCME_OK) {
9653 wait_for_completion_timeout(&cfg->wait_next_af,
9654 msecs_to_jiffies(extar_listen_time + 100 + 300));
9655 }
9656 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9657 }
9658 }
9659#endif /* WL_CFG80211_SYNC_GON */
9660 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9661
9662 cfg->afx_hdl->pending_tx_act_frm = NULL;
9663
9664 if (ack) {
9665 WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
9666 cfg->afx_hdl->my_listen_chan));
9667 } else {
9668 WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
9669 cfg->afx_hdl->my_listen_chan));
9670 }
9671
9672#ifdef WL_CFG80211_GON_COLLISION
9673 if (cfg->block_gon_req_tx_count) {
9674 cfg->block_gon_req_tx_count--;
9675 /* if ack is ture, supplicant will wait more time(100ms).
9676 * so we will return it as a success to get more time .
9677 */
9678 ack = true;
9679 }
9680#endif /* WL_CFG80211_GON_COLLISION */
9681 return ack;
9682}
9683
9684#define MAX_NUM_OF_ASSOCIATED_DEV 64
9685static s32
9686#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9687wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9688 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
9689#else
9690wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9691 struct ieee80211_channel *channel, bool offchan,
9692#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
9693 enum nl80211_channel_type channel_type,
9694 bool channel_type_valid,
9695#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
9696 unsigned int wait, const u8* buf, size_t len,
9697#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
9698 bool no_cck,
9699#endif
9700#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
9701 bool dont_wait_for_ack,
9702#endif
9703 u64 *cookie)
9704#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9705{
9706 wl_action_frame_t *action_frame;
9707 wl_af_params_t *af_params;
9708 scb_val_t scb_val;
9709#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9710 struct ieee80211_channel *channel = params->chan;
9711 const u8 *buf = params->buf;
9712 size_t len = params->len;
9713#endif
9714 const struct ieee80211_mgmt *mgmt;
9715 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9716 struct net_device *dev = NULL;
9717 s32 err = BCME_OK;
9718 s32 bssidx = 0;
9719 u32 id;
9720 bool ack = false;
9721 s8 eabuf[ETHER_ADDR_STR_LEN];
9722
9723 WL_DBG(("Enter \n"));
9724
9725 if (len > ACTION_FRAME_SIZE) {
9726 WL_ERR(("bad length:%zu\n", len));
9727 return BCME_BADLEN;
9728 }
9729#ifdef DHD_IFDEBUG
9730 PRINT_WDEV_INFO(cfgdev);
9731#endif /* DHD_IFDEBUG */
9732
9733 dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
9734
9735 if (!dev) {
9736 WL_ERR(("dev is NULL\n"));
9737 return -EINVAL;
9738 }
9739
9740 /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
9741 if (discover_cfgdev(cfgdev, cfg)) {
9742 if (!cfg->p2p_supported || !cfg->p2p) {
9743 WL_ERR(("P2P doesn't setup completed yet\n"));
9744 return -EINVAL;
9745 }
9746 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9747 }
9748 else {
9749 if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
9750 WL_ERR(("Find p2p index failed\n"));
9751 return BCME_ERROR;
9752 }
9753 }
9754
9755 WL_DBG(("TX target bssidx=%d\n", bssidx));
9756
9757 if (p2p_is_on(cfg)) {
9758 /* Suspend P2P discovery search-listen to prevent it from changing the
9759 * channel.
9760 */
9761 if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9762 WL_ERR(("Can not disable discovery mode\n"));
9763 return -EFAULT;
9764 }
9765 }
9766 *cookie = 0;
9767 id = cfg->send_action_id++;
9768 if (id == 0)
9769 id = cfg->send_action_id++;
9770 *cookie = id;
9771 mgmt = (const struct ieee80211_mgmt *)buf;
9772 if (ieee80211_is_mgmt(mgmt->frame_control)) {
9773 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
9774 s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
9775 s32 ie_len = len - ie_offset;
9776 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9777 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9778 }
9779 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
9780 VNDR_IE_PRBRSP_FLAG, (const u8 *)(buf + ie_offset), ie_len);
9781 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9782#if defined(P2P_IE_MISSING_FIX)
9783 if (!cfg->p2p_prb_noti) {
9784 cfg->p2p_prb_noti = true;
9785 WL_DBG(("wl_cfg80211_mgmt_tx: TX 802_1X Probe"
9786 " Response first time.\n"));
9787 }
9788#endif
9789 goto exit;
9790 } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
9791 ieee80211_is_deauth(mgmt->frame_control)) {
9792 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
9793 sizeof(struct ether_addr) + sizeof(uint)] = {0};
9794 int num_associated = 0;
9795 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9796 if (!bcmp((const uint8 *)BSSID_BROADCAST,
9797 (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
9798 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9799 err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST,
9800 assoc_maclist, sizeof(mac_buf));
9801 if (err < 0)
9802 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9803 else
9804 num_associated = assoc_maclist->count;
9805 }
9806 memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
9807 scb_val.val = mgmt->u.disassoc.reason_code;
9808 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
9809 sizeof(scb_val_t));
9810 if (err < 0)
9811 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
9812 WL_ERR(("Disconnect STA : " MACDBG " scb_val.val %d\n",
9813 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mgmt->da,
9814 eabuf)), scb_val.val));
9815
9816 /* WAR Wait for the deauth event to come,
9817 * supplicant will do the delete iface immediately
9818 * and we will have problem in sending
9819 * deauth frame if we delete the bss in firmware.
9820 * But we do not need additional delays for this WAR
9821 * during P2P connection.
9822 *
9823 * Supplicant call this function with BCAST after
9824 * delete all GC stations with each addr.
9825 * So, 400 ms delay can be called only once when GO disconnect all GC
9826 */
9827 if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
9828 wl_delay(400);
9829
9830 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9831 goto exit;
9832
9833 } else if (ieee80211_is_action(mgmt->frame_control)) {
9834 /* Abort the dwell time of any previous off-channel
9835 * action frame that may be still in effect. Sending
9836 * off-channel action frames relies on the driver's
9837 * scan engine. If a previous off-channel action frame
9838 * tx is still in progress (including the dwell time),
9839 * then this new action frame will not be sent out.
9840 */
9841/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
9842 * And previous off-channel action frame must be ended before new af tx.
9843 */
9844#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9845 wl_cfg80211_cancel_scan(cfg);
9846#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9847 }
9848#ifdef WL_CLIENT_SAE
9849 else if (ieee80211_is_auth(mgmt->frame_control)) {
9850 int err = 0;
9851 wl_assoc_mgr_cmd_t *cmd;
9852 char *ambuf = NULL;
9853 int param_len;
9854
9855 ack = true;
9856 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9857 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9858 }
9859 param_len = sizeof(wl_assoc_mgr_cmd_t) + len;
9860 ambuf = MALLOCZ(cfg->osh, param_len);
9861 if (ambuf == NULL) {
9862 WL_ERR(("unable to allocate frame\n"));
9863 return -ENOMEM;
9864 }
9865 cmd = (wl_assoc_mgr_cmd_t*)ambuf;
9866 cmd->version = WL_ASSOC_MGR_CURRENT_VERSION;
9867 cmd->length = len;
9868 cmd->cmd = WL_ASSOC_MGR_CMD_SEND_AUTH;
9869 memcpy(&cmd->params, buf, len);
9870 err = wldev_iovar_setbuf(dev, "assoc_mgr_cmd", ambuf, param_len,
9871 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
9872 if (unlikely(err)) {
9873 WL_ERR(("Failed to send auth(%d)\n", err));
9874 ack = false;
9875 }
9876 MFREE(cfg->osh, ambuf, param_len);
9877 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9878 goto exit;
9879 }
9880#endif /* WL_CLIENT_SAE */
9881 } else {
9882 WL_ERR(("Driver only allows MGMT packet type\n"));
9883 goto exit;
9884 }
9885
9886 af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
9887
9888 if (af_params == NULL)
9889 {
9890 WL_ERR(("unable to allocate frame\n"));
9891 return -ENOMEM;
9892 }
9893
9894 action_frame = &af_params->action_frame;
9895
9896 /* Add the packet Id */
9897 action_frame->packetId = *cookie;
9898 WL_DBG(("action frame %d\n", action_frame->packetId));
9899 /* Add BSSID */
9900 memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
9901 memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
9902
9903 /* Add the length exepted for 802.11 header */
9904 action_frame->len = len - DOT11_MGMT_HDR_LEN;
9905 WL_DBG(("action_frame->len: %d\n", action_frame->len));
9906
9907 /* Add the channel */
9908 af_params->channel =
9909 wl_freq_to_chanspec(channel->center_freq);
9910 /* Save listen_chan for searching common channel */
9911 cfg->afx_hdl->peer_listen_chan = af_params->channel;
9912 WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
9913
9914#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9915 af_params->dwell_time = params->wait;
9916#else
9917 af_params->dwell_time = wait;
9918#endif
9919
9920 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
9921
9922 ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params,
9923 action_frame, action_frame->len, bssidx);
9924 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9925 WL_DBG(("txstatus notified for cookie:%llu. ack:%d\n", *cookie, ack));
9926
9927 MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
9928exit:
9929 return err;
9930}
9931
9932static void
9933wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9934 u16 frame, bool reg)
9935{
9936
9937 WL_DBG(("frame_type: %x, reg: %d\n", frame, reg));
9938
9939 if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
9940 return;
9941
9942 return;
9943}
9944
9945static s32
9946wl_cfg80211_change_bss(struct wiphy *wiphy,
9947 struct net_device *dev,
9948 struct bss_parameters *params)
9949{
9950 s32 err = 0;
9951 s32 ap_isolate = 0;
9952#ifdef PCIE_FULL_DONGLE
9953 s32 ifidx = DHD_BAD_IF;
9954#endif
9955#if defined(PCIE_FULL_DONGLE)
9956 dhd_pub_t *dhd;
9957 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9958 dhd = (dhd_pub_t *)(cfg->pub);
9959#if defined(WL_ENABLE_P2P_IF)
9960 if (cfg->p2p_net == dev)
9961 dev = bcmcfg_to_prmry_ndev(cfg);
9962#endif
9963#endif
9964
9965 if (params->use_cts_prot >= 0) {
9966 }
9967
9968 if (params->use_short_preamble >= 0) {
9969 }
9970
9971 if (params->use_short_slot_time >= 0) {
9972 }
9973
9974 if (params->basic_rates) {
9975 }
9976
9977 if (params->ap_isolate >= 0) {
9978 ap_isolate = params->ap_isolate;
9979#ifdef PCIE_FULL_DONGLE
9980 ifidx = dhd_net2idx(dhd->info, dev);
9981
9982 if (ifidx != DHD_BAD_IF) {
9983 err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate);
9984 } else {
9985 WL_ERR(("Failed to set ap_isolate\n"));
9986 }
9987#else
9988 err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
9989 if (unlikely(err))
9990 {
9991 WL_ERR(("set ap_isolate Error (%d)\n", err));
9992 }
9993#endif /* PCIE_FULL_DONGLE */
9994 }
9995
9996 if (params->ht_opmode >= 0) {
9997 }
9998
9999 return err;
10000}
10001
10002static int
10003wl_get_bandwidth_cap(struct net_device *ndev, uint32 band, uint32 *bandwidth)
10004{
10005 u32 bw = WL_CHANSPEC_BW_20;
10006 s32 err = BCME_OK;
10007 s32 bw_cap = 0;
10008 struct {
10009 u32 band;
10010 u32 bw_cap;
10011 } param = {0, 0};
10012 u8 ioctl_buf[WLC_IOCTL_SMLEN];
10013
10014 if (band == WL_CHANSPEC_BAND_5G) {
10015 param.band = WLC_BAND_5G;
10016 }
10017#ifdef WL_6G_BAND
10018 else if (band == WL_CHANSPEC_BAND_6G) {
10019 param.band = WLC_BAND_6G;
10020 }
10021#endif
10022 if (param.band) {
10023 /* bw_cap is newly defined iovar for checking bandwith
10024 * capability of the band in Aardvark_branch_tob
10025 */
10026 err = wldev_iovar_getbuf(ndev, "bw_cap", &param, sizeof(param),
10027 ioctl_buf, sizeof(ioctl_buf), NULL);
10028 if (err) {
10029 if (err != BCME_UNSUPPORTED) {
10030 WL_ERR(("bw_cap failed, %d\n", err));
10031 return err;
10032 } else {
10033 /* if firmware doesn't support bw_cap iovar,
10034 * we have to use mimo_bw_cap
10035 */
10036 err = wldev_iovar_getint(ndev, "mimo_bw_cap", &bw_cap);
10037 if (err) {
10038 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
10039 }
10040 if (bw_cap != WLC_N_BW_20ALL) {
10041 bw = WL_CHANSPEC_BW_40;
10042 }
10043 }
10044 } else {
10045 if (WL_BW_CAP_160MHZ(ioctl_buf[0])) {
10046 bw = WL_CHANSPEC_BW_160;
10047 } else if (WL_BW_CAP_80MHZ(ioctl_buf[0])) {
10048 bw = WL_CHANSPEC_BW_80;
10049 } else if (WL_BW_CAP_40MHZ(ioctl_buf[0])) {
10050 bw = WL_CHANSPEC_BW_40;
10051 } else {
10052 bw = WL_CHANSPEC_BW_20;
10053 }
10054 }
10055 } else if (band == WL_CHANSPEC_BAND_2G) {
10056 bw = WL_CHANSPEC_BW_20;
10057 }
10058
10059 *bandwidth = bw;
10060
10061 return err;
10062}
10063
10064#ifdef APSTA_RESTRICTED_CHANNEL
10065static s32
10066wl_get_nl80211_band(u32 wl_band)
10067{
10068 s32 err = BCME_ERROR;
10069
10070 switch (wl_band) {
10071 case WL_CHANSPEC_BAND_2G:
10072 return IEEE80211_BAND_2GHZ;
10073 case WL_CHANSPEC_BAND_5G:
10074 return IEEE80211_BAND_5GHZ;
10075#ifdef WL_BAND_6G
10076 case WL_CHANSPEC_BAND_6G:
10077 /* current kernels doesn't support seperate
10078 * band for 6GHz. so till patch is available
10079 * map it under 5GHz
10080 */
10081 return IEEE80211_BAND_5GHZ;
10082#endif /* WL_BAND_6G */
10083 default:
10084 WL_ERR(("unsupported Band. %d\n", wl_band));
10085 }
10086
10087 return err;
10088}
10089#endif /* APSTA_RESTRICTED_CHANNEL */
10090
10091static s32
10092wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
10093 struct ieee80211_channel *chan,
10094 enum nl80211_channel_type channel_type)
10095{
10096 chanspec_t chspec = INVCHANSPEC;
10097 chanspec_t cur_chspec = INVCHANSPEC;
10098 u32 bw = WL_CHANSPEC_BW_20;
10099 s32 err = BCME_OK;
10100 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10101#if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL) || defined(WL_EXT_IAPSTA)
10102 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10103 enum nl80211_band band;
10104 s32 _chan;
10105#endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
575f4a04 10106 u16 center_freq = chan->center_freq;
1b4a7c03
LJ
10107
10108 dev = ndev_to_wlc_ndev(dev, cfg);
10109#ifdef WL_EXT_IAPSTA
10110 _chan = ieee80211_frequency_to_channel(chan->center_freq);
10111 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
10112 wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev), WL_IF_TYPE_AP);
10113 _chan = wl_ext_iapsta_update_channel(dhd, dev, _chan);
10114 }
10115 if (CHANNEL_IS_5G(_chan))
10116 band = NL80211_BAND_5GHZ;
10117 else
10118 band = NL80211_BAND_2GHZ;
575f4a04 10119 center_freq = ieee80211_channel_to_frequency(_chan, band);
1b4a7c03 10120#endif
575f4a04 10121 chspec = wl_freq_to_chanspec(center_freq);
1b4a7c03
LJ
10122
10123 WL_MSG(dev->name, "netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
10124 dev->ifindex, channel_type, CHSPEC_CHANNEL(chspec));
10125
10126#ifndef WL_P2P_6G
10127 if (IS_P2P_GO(dev->ieee80211_ptr) && (CHSPEC_IS6G(chspec))) {
10128 WL_ERR(("P2P GO not allowed on 6G\n"));
10129 return -ENOTSUPP;
10130 }
10131#endif /* WL_P2P_6G */
10132
10133#ifdef NOT_YET
10134 switch (channel_type) {
10135 case NL80211_CHAN_HT40MINUS:
10136 /* secondary channel is below the control channel */
10137 chspec = CH40MHZ_CHSPEC(CHSPEC_CHANNEL(chspec), WL_CHANSPEC_CTL_SB_UPPER);
10138 break;
10139 case NL80211_CHAN_HT40PLUS:
10140 /* secondary channel is above the control channel */
10141 chspec = CH40MHZ_CHSPEC(CHSPEC_CHANNEL(chspec), WL_CHANSPEC_CTL_SB_LOWER);
10142 break;
10143 default:
10144 chspec = CH20MHZ_CHSPEC(CHSPEC_CHANNEL(chspec));
10145
10146 }
10147#endif /* NOT_YET */
10148
10149#if defined(APSTA_RESTRICTED_CHANNEL)
10150 /* Some customer platform used limited number of channels
10151 * for SoftAP interface on STA/SoftAP concurrent mode.
10152 * - 2.4GHz Channel: CH1 - CH13
10153 * - 5GHz Channel: CH149 (it depends on the country code)
10154 * If the Android framework sent invaild channel configuration
10155 * to DHD, driver should change the channel which is sutible for
10156 * STA/SoftAP concurrent mode.
10157 * - Set operating channel to CH1 (default 2.4GHz channel for
10158 * restricted APSTA mode) if STA interface was associated to
10159 * 5GHz APs except for CH149.
10160 * - Otherwise, set the channel to the same channel as existing AP.
10161 */
10162 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
10163 DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
10164 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
10165 u32 *sta_chanspec = (u32 *)wl_read_prof(cfg,
10166 bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN);
10167 if (chan->band == wl_get_nl80211_band(CHSPEC_BAND(*sta_chanspec))) {
10168 /* Do not try SCC in 5GHz if channel is not CH149 */
10169 chspec = (
10170#ifdef WL_6G_BAND
10171 CHSPEC_IS6G(*sta_chanspec) ||
10172#endif /* WL_6G_BAND */
10173 (CHSPEC_IS5G(*sta_chanspec) &&
10174 CHSPEC_CHANNEL(*sta_chanspec) != DEFAULT_5G_SOFTAP_CHANNEL)) ?
10175 DEFAULT_2G_SOFTAP_CHANSPEC: *sta_chanspec;
10176 WL_ERR(("target chanspec will be changed to %d\n", chspec));
10177 if (CHSPEC_IS2G(chspec)) {
10178 bw = WL_CHANSPEC_BW_20;
10179 goto set_channel;
10180 }
10181 }
10182 }
10183#endif /* APSTA_RESTRICTED_CHANNEL */
10184
10185 err = wl_get_bandwidth_cap(dev, CHSPEC_BAND(chspec), &bw);
10186 if (err < 0) {
10187 WL_ERR(("Failed to get bandwidth information, err=%d\n", err));
10188 return err;
10189 }
10190
10191 /* In case of 5G downgrade BW to 80MHz as 160MHz channels falls in DFS */
10192 if (CHSPEC_IS5G(chspec) && (bw == WL_CHANSPEC_BW_160)) {
10193 bw = WL_CHANSPEC_BW_80;
10194 }
10195set_channel:
10196 cur_chspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chspec),
10197 bw, CHSPEC_BAND(chspec));
10198 if (wf_chspec_valid(cur_chspec)) {
10199 /* convert 802.11 ac chanspec to current fw chanspec type */
10200 cur_chspec = wl_chspec_host_to_driver(cur_chspec);
10201 if (cur_chspec != INVCHANSPEC) {
10202 if ((err = wldev_iovar_setint(dev, "chanspec",
10203 cur_chspec)) == BCME_BADCHAN) {
10204 u32 local_channel = CHSPEC_CHANNEL(chspec);
10205 if ((bw == WL_CHANSPEC_BW_80) || (bw == WL_CHANSPEC_BW_160))
10206 goto change_bw;
10207 err = wldev_ioctl_set(dev, WLC_SET_CHANNEL,
10208 &local_channel, sizeof(local_channel));
10209 if (err < 0) {
10210 WL_ERR(("WLC_SET_CHANNEL error %d"
10211 "chip may not be supporting this channel\n", err));
10212 }
10213 } else if (err) {
10214 WL_ERR(("failed to set chanspec error %d\n", err));
10215 }
10216#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
10217 else {
10218 /* Disable Frameburst only for stand-alone 2GHz SoftAP */
10219 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
10220 DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
10221 (CHSPEC_IS2G(chspec)) &&
10222 !wl_get_drv_status(cfg, CONNECTED,
10223 bcmcfg_to_prmry_ndev(cfg))) {
10224 WL_DBG(("Disabling frameburst on "
10225 "stand-alone 2GHz SoftAP\n"));
10226 wl_cfg80211_set_frameburst(cfg, FALSE);
10227 }
10228 }
10229#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
10230 } else {
10231 WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
10232 err = BCME_ERROR;
10233 }
10234 } else {
10235change_bw:
10236 if (bw == WL_CHANSPEC_BW_160) {
10237 bw = WL_CHANSPEC_BW_80;
10238 } else if (bw == WL_CHANSPEC_BW_80) {
10239 bw = WL_CHANSPEC_BW_40;
10240 } else if (bw == WL_CHANSPEC_BW_40) {
10241 bw = WL_CHANSPEC_BW_20;
10242 } else {
10243 bw = 0;
10244 }
10245 if (bw)
10246 goto set_channel;
10247 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
10248 err = BCME_ERROR;
10249 }
10250#ifdef CUSTOM_SET_CPUCORE
10251 if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
10252 WL_DBG(("SoftAP mode do not need to set cpucore\n"));
10253 } else if (chspec & WL_CHANSPEC_BW_80) {
10254 /* SoftAp only mode do not need to set cpucore */
10255 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
10256 dev != bcmcfg_to_prmry_ndev(cfg)) {
10257 /* Soft AP on virtual Iface (AP+STA case) */
10258 dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
10259 dhd_set_cpucore(dhd, TRUE);
10260 } else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
10261 /* If P2P IF is vht80 */
10262 dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
10263 dhd_set_cpucore(dhd, TRUE);
10264 }
10265 }
10266#endif /* CUSTOM_SET_CPUCORE */
10267 if (!err && (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
10268 /* Update AP/GO operating chanspec */
575f4a04 10269 cfg->ap_oper_channel = wl_freq_to_chanspec(center_freq);
1b4a7c03
LJ
10270 }
10271 if (err) {
10272 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
10273 FW_LOGSET_MASK_ALL);
10274 } else {
10275 WL_DBG(("Setting chanspec %x for GO/AP \n", chspec));
10276 }
10277 return err;
10278}
10279
10280#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
10281struct net_device *
10282wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
10283{
10284 struct net_info *_net_info, *next;
10285 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
10286 list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
10287 GCC_DIAGNOSTIC_POP();
10288 if (_net_info->ndev &&
10289 test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
10290 return _net_info->ndev;
10291 }
10292
10293 return NULL;
10294}
10295#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
10296
10297static s32
10298wl_validate_opensecurity(struct net_device *dev, s32 bssidx, bool privacy)
10299{
10300 s32 err = BCME_OK;
10301 u32 wpa_val;
10302 s32 wsec = 0;
10303
10304 /* set auth */
10305 err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
10306 if (err < 0) {
10307 WL_ERR(("auth error %d\n", err));
10308 return BCME_ERROR;
10309 }
10310
10311 if (privacy) {
10312 /* If privacy bit is set in open mode, then WEP would be enabled */
10313 wsec = WEP_ENABLED;
10314 WL_DBG(("Setting wsec to %d for WEP \n", wsec));
10315 }
10316
10317 /* set wsec */
10318 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10319 if (err < 0) {
10320 WL_ERR(("wsec error %d\n", err));
10321 return BCME_ERROR;
10322 }
10323
10324 /* set upper-layer auth */
10325 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC)
10326 wpa_val = WPA_AUTH_NONE;
10327 else
10328 wpa_val = WPA_AUTH_DISABLED;
10329 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_val, bssidx);
10330 if (err < 0) {
10331 WL_ERR(("wpa_auth error %d\n", err));
10332 return BCME_ERROR;
10333 }
10334
10335 return 0;
10336}
10337
10338#define MAX_FILS_IND_IE_LEN 1024u
10339static s32
10340wl_validate_fils_ind_ie(struct net_device *dev, const bcm_tlv_t *filsindie, s32 bssidx)
10341{
10342 s32 err = BCME_OK;
10343 struct bcm_cfg80211 *cfg = NULL;
10344 bcm_iov_buf_t *iov_buf = NULL;
10345 bcm_xtlv_t* pxtlv;
10346 int iov_buf_size = 0;
10347
10348 if (!dev || !filsindie) {
10349 WL_ERR(("%s: dev/filsidie is null\n", __FUNCTION__));
10350 goto exit;
10351 }
10352
10353 cfg = wl_get_cfg(dev);
10354 if (!cfg) {
10355 WL_ERR(("%s: cfg is null\n", __FUNCTION__));
10356 goto exit;
10357 }
10358
10359 iov_buf_size = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) + filsindie->len - 1;
10360 iov_buf = MALLOCZ(cfg->osh, iov_buf_size);
10361 if (!iov_buf) {
10362 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, iov_buf_size));
10363 err = BCME_NOMEM;
10364 goto exit;
10365 }
10366 iov_buf->version = WL_FILS_IOV_VERSION;
10367 iov_buf->id = WL_FILS_CMD_ADD_IND_IE;
10368 iov_buf->len = sizeof(bcm_xtlv_t) + filsindie->len - 1;
10369 pxtlv = (bcm_xtlv_t*)&iov_buf->data[0];
10370 pxtlv->id = WL_FILS_XTLV_IND_IE;
10371 pxtlv->len = filsindie->len;
10372 /* memcpy_s return check not required as buffer is allocated based on ie
10373 * len
10374 */
10375 (void)memcpy_s(pxtlv->data, filsindie->len, filsindie->data, filsindie->len);
10376
10377 err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf_size,
10378 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
10379 if (unlikely(err)) {
10380 WL_ERR(("fils indication ioctl error (%d)\n", err));
10381 goto exit;
10382 }
10383
10384exit:
10385 if (err < 0) {
10386 WL_ERR(("FILS Ind setting error %d\n", err));
10387 }
10388
10389 if (iov_buf) {
10390 MFREE(cfg->osh, iov_buf, iov_buf_size);
10391 }
10392 return err;
10393}
10394
10395static s32
10396wl_validate_wpa2ie(struct net_device *dev, const bcm_tlv_t *wpa2ie, s32 bssidx)
10397{
10398 s32 len = 0;
10399 s32 err = BCME_OK;
10400 u16 auth = 0; /* d11 open authentication */
10401 u32 wsec;
10402 u32 pval = 0;
10403 u32 gval = 0;
10404 u32 wpa_auth = 0;
10405 const wpa_suite_mcast_t *mcast;
10406 const wpa_suite_ucast_t *ucast;
10407 const wpa_suite_auth_key_mgmt_t *mgmt;
10408 const wpa_pmkid_list_t *pmkid;
10409 int cnt = 0;
10410#ifdef MFP
10411 int mfp = 0;
10412#endif /* MFP */
10413 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10414 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
10415
10416 u16 suite_count;
10417 u8 rsn_cap[2];
10418 u32 wme_bss_disable;
10419
10420 if (wpa2ie == NULL)
10421 goto exit;
10422
10423 WL_DBG(("Enter \n"));
10424 len = wpa2ie->len - WPA2_VERSION_LEN;
10425 /* check the mcast cipher */
10426 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10427 switch (mcast->type) {
10428 case WPA_CIPHER_NONE:
10429 gval = 0;
10430 break;
10431 case WPA_CIPHER_WEP_40:
10432 case WPA_CIPHER_WEP_104:
10433 gval = WEP_ENABLED;
10434 break;
10435 case WPA_CIPHER_TKIP:
10436 gval = TKIP_ENABLED;
10437 break;
10438 case WPA_CIPHER_AES_CCM:
10439 gval = AES_ENABLED;
10440 break;
10441
10442#ifdef BCMWAPI_WPI
10443 case WAPI_CIPHER_SMS4:
10444 gval = SMS4_ENABLED;
10445 break;
10446#endif
10447
10448 default:
10449 WL_ERR(("No Security Info\n"));
10450 break;
10451 }
10452 if ((len -= WPA_SUITE_LEN) <= 0)
10453 return BCME_BADLEN;
10454
10455 /* check the unicast cipher */
10456 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10457 suite_count = ltoh16_ua(&ucast->count);
10458 switch (ucast->list[0].type) {
10459 case WPA_CIPHER_NONE:
10460 pval = 0;
10461 break;
10462 case WPA_CIPHER_WEP_40:
10463 case WPA_CIPHER_WEP_104:
10464 pval = WEP_ENABLED;
10465 break;
10466 case WPA_CIPHER_TKIP:
10467 pval = TKIP_ENABLED;
10468 break;
10469 case WPA_CIPHER_AES_CCM:
10470 pval = AES_ENABLED;
10471 break;
10472
10473#ifdef BCMWAPI_WPI
10474 case WAPI_CIPHER_SMS4:
10475 pval = SMS4_ENABLED;
10476 break;
10477#endif
10478
10479 default:
10480 WL_ERR(("No Security Info\n"));
10481 }
10482 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
10483 return BCME_BADLEN;
10484
10485 /* FOR WPS , set SEC_OW_ENABLED */
10486 wsec = (pval | gval | SES_OW_ENABLED);
10487 /* check the AKM */
10488 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
10489 suite_count = cnt = ltoh16_ua(&mgmt->count);
10490 while (cnt--) {
10491 if (bcmp(mgmt->list[cnt].oui, WFA_OUI, WFA_OUI_LEN) == 0) {
10492 switch (mgmt->list[cnt].type) {
10493 case RSN_AKM_DPP:
10494 wpa_auth |= WPA3_AUTH_DPP_AKM;
10495 break;
10496 default:
10497 WL_ERR(("No Key Mgmt Info in WFA_OUI\n"));
10498 }
10499 } else {
10500 switch (mgmt->list[cnt].type) {
10501 case RSN_AKM_NONE:
10502 wpa_auth |= WPA_AUTH_NONE;
10503 break;
10504 case RSN_AKM_UNSPECIFIED:
10505 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
10506 break;
10507 case RSN_AKM_PSK:
10508 wpa_auth |= WPA2_AUTH_PSK;
10509 break;
10510#ifdef MFP
10511 case RSN_AKM_MFP_PSK:
10512 wpa_auth |= WPA2_AUTH_PSK_SHA256;
10513 break;
10514 case RSN_AKM_MFP_1X:
10515 wpa_auth |= WPA2_AUTH_1X_SHA256;
10516 break;
10517 case RSN_AKM_FILS_SHA256:
10518 wpa_auth |= WPA2_AUTH_FILS_SHA256;
10519 break;
10520 case RSN_AKM_FILS_SHA384:
10521 wpa_auth |= WPA2_AUTH_FILS_SHA384;
10522 break;
10523#if defined(WL_SAE) || defined(WL_CLIENT_SAE)
10524 case RSN_AKM_SAE_PSK:
10525 wpa_auth |= WPA3_AUTH_SAE_PSK;
10526 break;
10527#endif /* WL_SAE || WL_CLIENT_SAE */
10528#endif /* MFP */
10529 default:
10530 WL_ERR(("No Key Mgmt Info\n"));
10531 }
10532 }
10533 }
10534 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
10535 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
10536 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
10537
10538 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
10539 wme_bss_disable = 0;
10540 } else {
10541 wme_bss_disable = 1;
10542 }
10543
10544#ifdef MFP
10545 if (rsn_cap[0] & RSN_CAP_MFPR) {
10546 WL_DBG(("MFP Required \n"));
10547 mfp = WL_MFP_REQUIRED;
10548 /* Our firmware has requirement that WPA2_AUTH_PSK/WPA2_AUTH_UNSPECIFIED
10549 * be set, if SHA256 OUI is to be included in the rsn ie.
10550 */
10551 if (wpa_auth & WPA2_AUTH_PSK_SHA256) {
10552 wpa_auth |= WPA2_AUTH_PSK;
10553 } else if (wpa_auth & WPA2_AUTH_1X_SHA256) {
10554 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
10555 }
10556 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
10557 WL_DBG(("MFP Capable \n"));
10558 mfp = WL_MFP_CAPABLE;
10559 }
10560#endif /* MFP */
10561
10562 /* set wme_bss_disable to sync RSN Capabilities */
10563 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
10564 if (err < 0) {
10565 WL_ERR(("wme_bss_disable error %d\n", err));
10566 return BCME_ERROR;
10567 }
10568 } else {
10569 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
10570 }
10571
10572 len -= RSN_CAP_LEN;
10573 if (len >= WPA2_PMKID_COUNT_LEN) {
10574 pmkid = (const wpa_pmkid_list_t *)
10575 ((const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
10576 cnt = ltoh16_ua(&pmkid->count);
10577 if (cnt != 0) {
10578 WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
10579 return BCME_ERROR;
10580 }
10581 /* since PMKID cnt is known to be 0 for AP, */
10582 /* so don't bother to send down this info to firmware */
10583 }
10584
10585#ifdef MFP
10586 len -= WPA2_PMKID_COUNT_LEN;
10587 if (len >= WPA_SUITE_LEN) {
10588 cfg->bip_pos =
10589 (const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN;
10590 } else {
10591 cfg->bip_pos = NULL;
10592 }
10593#endif
10594
10595 /* set auth */
10596 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10597 if (err < 0) {
10598 WL_ERR(("auth error %d\n", err));
10599 return BCME_ERROR;
10600 }
10601
10602 /* set wsec */
10603 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10604 if (err < 0) {
10605 WL_ERR(("wsec error %d\n", err));
10606 return BCME_ERROR;
10607 }
10608
10609#ifdef MFP
10610 cfg->mfp_mode = mfp;
10611#endif /* MFP */
10612
10613 /* set upper-layer auth */
10614 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10615 if (err < 0) {
10616 WL_ERR(("wpa_auth error %d\n", err));
10617 return BCME_ERROR;
10618 }
10619
10620 if (sec) {
10621 /* store applied sec settings */
10622 sec->fw_wpa_auth = wpa_auth;
10623 sec->fw_wsec = wsec;
10624 sec->fw_auth = auth;
10625#ifdef MFP
10626 sec->fw_mfp = mfp;
10627#endif /* mfp */
10628 }
10629exit:
10630 return 0;
10631}
10632
10633static s32
10634wl_validate_wpaie(struct net_device *dev, const wpa_ie_fixed_t *wpaie, s32 bssidx)
10635{
10636 const wpa_suite_mcast_t *mcast;
10637 const wpa_suite_ucast_t *ucast;
10638 const wpa_suite_auth_key_mgmt_t *mgmt;
10639 u16 auth = 0; /* d11 open authentication */
10640 u16 count;
10641 s32 err = BCME_OK;
10642 s32 len = 0;
10643 u32 i;
10644 u32 wsec;
10645 u32 pval = 0;
10646 u32 gval = 0;
10647 u32 wpa_auth = 0;
10648 u32 tmp = 0;
10649 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10650 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
10651
10652 if (wpaie == NULL)
10653 goto exit;
10654 WL_DBG(("Enter \n"));
10655 len = wpaie->length; /* value length */
10656 len -= WPA_IE_TAG_FIXED_LEN;
10657 /* check for multicast cipher suite */
10658 if (len < WPA_SUITE_LEN) {
10659 WL_INFORM_MEM(("no multicast cipher suite\n"));
10660 goto exit;
10661 }
10662
10663 /* pick up multicast cipher */
10664 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
10665 len -= WPA_SUITE_LEN;
10666 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
10667 if (IS_WPA_CIPHER(mcast->type)) {
10668 tmp = 0;
10669 switch (mcast->type) {
10670 case WPA_CIPHER_NONE:
10671 tmp = 0;
10672 break;
10673 case WPA_CIPHER_WEP_40:
10674 case WPA_CIPHER_WEP_104:
10675 tmp = WEP_ENABLED;
10676 break;
10677 case WPA_CIPHER_TKIP:
10678 tmp = TKIP_ENABLED;
10679 break;
10680 case WPA_CIPHER_AES_CCM:
10681 tmp = AES_ENABLED;
10682 break;
10683 default:
10684 WL_ERR(("No Security Info\n"));
10685 }
10686 gval |= tmp;
10687 }
10688 }
10689 /* Check for unicast suite(s) */
10690 if (len < WPA_IE_SUITE_COUNT_LEN) {
10691 WL_INFORM_MEM(("no unicast suite\n"));
10692 goto exit;
10693 }
10694 /* walk thru unicast cipher list and pick up what we recognize */
10695 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10696 count = ltoh16_ua(&ucast->count);
10697 len -= WPA_IE_SUITE_COUNT_LEN;
10698 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10699 i++, len -= WPA_SUITE_LEN) {
10700 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10701 if (IS_WPA_CIPHER(ucast->list[i].type)) {
10702 tmp = 0;
10703 switch (ucast->list[i].type) {
10704 case WPA_CIPHER_NONE:
10705 tmp = 0;
10706 break;
10707 case WPA_CIPHER_WEP_40:
10708 case WPA_CIPHER_WEP_104:
10709 tmp = WEP_ENABLED;
10710 break;
10711 case WPA_CIPHER_TKIP:
10712 tmp = TKIP_ENABLED;
10713 break;
10714 case WPA_CIPHER_AES_CCM:
10715 tmp = AES_ENABLED;
10716 break;
10717 default:
10718 WL_ERR(("No Security Info\n"));
10719 }
10720 pval |= tmp;
10721 }
10722 }
10723 }
10724 len -= (count - i) * WPA_SUITE_LEN;
10725 /* Check for auth key management suite(s) */
10726 if (len < WPA_IE_SUITE_COUNT_LEN) {
10727 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10728 goto exit;
10729 }
10730 /* walk thru auth management suite list and pick up what we recognize */
10731 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
10732 count = ltoh16_ua(&mgmt->count);
10733 len -= WPA_IE_SUITE_COUNT_LEN;
10734 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10735 i++, len -= WPA_SUITE_LEN) {
10736 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10737 if (IS_WPA_AKM(mgmt->list[i].type)) {
10738 tmp = 0;
10739 switch (mgmt->list[i].type) {
10740 case RSN_AKM_NONE:
10741 tmp = WPA_AUTH_NONE;
10742 break;
10743 case RSN_AKM_UNSPECIFIED:
10744 tmp = WPA_AUTH_UNSPECIFIED;
10745 break;
10746 case RSN_AKM_PSK:
10747 tmp = WPA_AUTH_PSK;
10748 break;
10749 default:
10750 WL_ERR(("No Key Mgmt Info\n"));
10751 }
10752 wpa_auth |= tmp;
10753 }
10754 }
10755
10756 }
10757 /* FOR WPS , set SEC_OW_ENABLED */
10758 wsec = (pval | gval | SES_OW_ENABLED);
10759 /* set auth */
10760 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10761 if (err < 0) {
10762 WL_ERR(("auth error %d\n", err));
10763 return BCME_ERROR;
10764 }
10765 /* set wsec */
10766 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10767 if (err < 0) {
10768 WL_ERR(("wsec error %d\n", err));
10769 return BCME_ERROR;
10770 }
10771 /* set upper-layer auth */
10772 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10773 if (err < 0) {
10774 WL_ERR(("wpa_auth error %d\n", err));
10775 return BCME_ERROR;
10776 }
10777
10778 if (sec) {
10779 /* store applied sec settings */
10780 sec->fw_wpa_auth = wpa_auth;
10781 sec->fw_wsec = wsec;
10782 sec->fw_auth = auth;
10783 }
10784
10785exit:
10786 return 0;
10787}
10788
10789#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10790static u32 wl_get_cipher_type(uint8 type)
10791{
10792 u32 ret = 0;
10793 switch (type) {
10794 case WPA_CIPHER_NONE:
10795 ret = 0;
10796 break;
10797 case WPA_CIPHER_WEP_40:
10798 case WPA_CIPHER_WEP_104:
10799 ret = WEP_ENABLED;
10800 break;
10801 case WPA_CIPHER_TKIP:
10802 ret = TKIP_ENABLED;
10803 break;
10804 case WPA_CIPHER_AES_CCM:
10805 ret = AES_ENABLED;
10806 break;
10807
10808#ifdef BCMWAPI_WPI
10809 case WAPI_CIPHER_SMS4:
10810 ret = SMS4_ENABLED;
10811 break;
10812#endif
10813
10814 default:
10815 WL_ERR(("No Security Info\n"));
10816 }
10817 return ret;
10818}
10819
10820static u32 wl_get_suite_auth_key_mgmt_type(uint8 type, const wpa_suite_mcast_t *mcast)
10821{
10822 u32 ret = 0;
10823 u32 is_wpa2 = 0;
10824
10825 if (!bcmp(mcast->oui, WPA2_OUI, WPA2_OUI_LEN)) {
10826 is_wpa2 = 1;
10827 }
10828
10829 WL_INFORM_MEM(("%s, type = %d\n", is_wpa2 ? "WPA2":"WPA", type));
10830 if (bcmp(mcast->oui, WFA_OUI, WFA_OUI_LEN) == 0) {
10831 switch (type) {
10832 case RSN_AKM_DPP:
10833 ret = WPA3_AUTH_DPP_AKM;
10834 break;
10835 default:
10836 WL_ERR(("No Key Mgmt Info in WFA_OUI\n"));
10837 }
10838 } else {
10839 switch (type) {
10840 case RSN_AKM_NONE:
10841 /* For WPA and WPA2, AUTH_NONE is common */
10842 ret = WPA_AUTH_NONE;
10843 break;
10844 case RSN_AKM_UNSPECIFIED:
10845 if (is_wpa2) {
10846 ret = WPA2_AUTH_UNSPECIFIED;
10847 } else {
10848 ret = WPA_AUTH_UNSPECIFIED;
10849 }
10850 break;
10851 case RSN_AKM_PSK:
10852 if (is_wpa2) {
10853 ret = WPA2_AUTH_PSK;
10854 } else {
10855 ret = WPA_AUTH_PSK;
10856 }
10857 break;
10858#ifdef WL_SAE
10859 case RSN_AKM_SAE_PSK:
10860 ret = WPA3_AUTH_SAE_PSK;
10861 break;
10862#endif /* WL_SAE */
10863 default:
10864 WL_ERR(("No Key Mgmt Info\n"));
10865 }
10866 }
10867 return ret;
10868}
10869
10870static s32
10871wl_validate_wpaie_wpa2ie(struct net_device *dev, const wpa_ie_fixed_t *wpaie,
10872 const bcm_tlv_t *wpa2ie, s32 bssidx)
10873{
10874 const wpa_suite_mcast_t *mcast;
10875 const wpa_suite_ucast_t *ucast;
10876 const wpa_suite_auth_key_mgmt_t *mgmt;
10877 u16 auth = 0; /* d11 open authentication */
10878 u16 count;
10879 s32 err = BCME_OK;
10880 u32 wme_bss_disable;
10881 u16 suite_count;
10882 u8 rsn_cap[2];
10883 s32 len = 0;
10884 u32 i;
10885 u32 wsec1, wsec2, wsec;
10886 u32 pval = 0;
10887 u32 gval = 0;
10888 u32 wpa_auth = 0;
10889 u32 wpa_auth1 = 0;
10890 u32 wpa_auth2 = 0;
10891 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10892 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
10893
10894 if (wpaie == NULL || wpa2ie == NULL)
10895 goto exit;
10896
10897 WL_DBG(("Enter \n"));
10898 len = wpaie->length; /* value length */
10899 len -= WPA_IE_TAG_FIXED_LEN;
10900 /* check for multicast cipher suite */
10901 if (len < WPA_SUITE_LEN) {
10902 WL_INFORM_MEM(("no multicast cipher suite\n"));
10903 goto exit;
10904 }
10905
10906 /* pick up multicast cipher */
10907 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
10908 len -= WPA_SUITE_LEN;
10909 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
10910 if (IS_WPA_CIPHER(mcast->type)) {
10911 gval |= wl_get_cipher_type(mcast->type);
10912 }
10913 }
10914 WL_DBG(("\nwpa ie validate\n"));
10915 WL_DBG(("wpa ie mcast cipher = 0x%X\n", gval));
10916
10917 /* Check for unicast suite(s) */
10918 if (len < WPA_IE_SUITE_COUNT_LEN) {
10919 WL_INFORM_MEM(("no unicast suite\n"));
10920 goto exit;
10921 }
10922
10923 /* walk thru unicast cipher list and pick up what we recognize */
10924 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10925 count = ltoh16_ua(&ucast->count);
10926 len -= WPA_IE_SUITE_COUNT_LEN;
10927 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10928 i++, len -= WPA_SUITE_LEN) {
10929 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10930 if (IS_WPA_CIPHER(ucast->list[i].type)) {
10931 pval |= wl_get_cipher_type(ucast->list[i].type);
10932 }
10933 }
10934 }
10935 WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count, pval));
10936
10937 /* FOR WPS , set SEC_OW_ENABLED */
10938 wsec1 = (pval | gval | SES_OW_ENABLED);
10939 WL_ERR(("wpa ie wsec = 0x%X\n", wsec1));
10940
10941 len -= (count - i) * WPA_SUITE_LEN;
10942 /* Check for auth key management suite(s) */
10943 if (len < WPA_IE_SUITE_COUNT_LEN) {
10944 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10945 goto exit;
10946 }
10947 /* walk thru auth management suite list and pick up what we recognize */
10948 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
10949 count = ltoh16_ua(&mgmt->count);
10950 len -= WPA_IE_SUITE_COUNT_LEN;
10951 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10952 i++, len -= WPA_SUITE_LEN) {
10953 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10954 if (IS_WPA_AKM(mgmt->list[i].type)) {
10955 wpa_auth1 |=
10956 wl_get_suite_auth_key_mgmt_type(mgmt->list[i].type, mcast);
10957 }
10958 }
10959
10960 }
10961 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth1));
10962 WL_ERR(("\nwpa2 ie validate\n"));
10963
10964 pval = 0;
10965 gval = 0;
10966 len = wpa2ie->len;
10967 /* check the mcast cipher */
10968 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10969 gval = wl_get_cipher_type(mcast->type);
10970
10971 WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval));
10972 if ((len -= WPA_SUITE_LEN) <= 0)
10973 {
10974 WL_ERR(("P:wpa2 ie len[%d]", len));
10975 return BCME_BADLEN;
10976 }
10977
10978 /* check the unicast cipher */
10979 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10980 suite_count = ltoh16_ua(&ucast->count);
10981 WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count));
10982 pval |= wl_get_cipher_type(ucast->list[0].type);
10983
10984 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
10985 return BCME_BADLEN;
10986
10987 WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval));
10988
10989 /* FOR WPS , set SEC_OW_ENABLED */
10990 wsec2 = (pval | gval | SES_OW_ENABLED);
10991 WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2));
10992
10993 /* check the AKM */
10994 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
10995 suite_count = ltoh16_ua(&mgmt->count);
10996 wpa_auth2 = wl_get_suite_auth_key_mgmt_type(mgmt->list[0].type, mcast);
10997 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth2));
10998
10999 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
11000 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
11001 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
11002 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
11003 wme_bss_disable = 0;
11004 } else {
11005 wme_bss_disable = 1;
11006 }
11007 WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap[0], wme_bss_disable));
11008
11009 /* set wme_bss_disable to sync RSN Capabilities */
11010 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
11011 if (err < 0) {
11012 WL_ERR(("wme_bss_disable error %d\n", err));
11013 return BCME_ERROR;
11014 }
11015 } else {
11016 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
11017 }
11018
11019 wsec = (wsec1 | wsec2);
11020 wpa_auth = (wpa_auth1 | wpa_auth2);
11021 WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec, wpa_auth));
11022
11023 /* set auth */
11024 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
11025 if (err < 0) {
11026 WL_ERR(("auth error %d\n", err));
11027 return BCME_ERROR;
11028 }
11029 /* set wsec */
11030 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
11031 if (err < 0) {
11032 WL_ERR(("wsec error %d\n", err));
11033 return BCME_ERROR;
11034 }
11035 /* set upper-layer auth */
11036 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
11037 if (err < 0) {
11038 WL_ERR(("wpa_auth error %d\n", err));
11039 return BCME_ERROR;
11040 }
11041
11042 if (sec) {
11043 sec->fw_wpa_auth = wpa_auth;
11044 sec->fw_auth = auth;
11045 sec->fw_wsec = wsec;
11046 }
11047
11048exit:
11049 return 0;
11050}
11051#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11052
11053static s32
11054wl_cfg80211_bcn_validate_sec(
11055 struct net_device *dev,
11056 struct parsed_ies *ies,
11057 u32 dev_role,
11058 s32 bssidx,
11059 bool privacy)
11060{
11061 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11062 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
11063 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
11064
11065 if (!bss) {
11066 WL_ERR(("cfgbss is NULL \n"));
11067 return BCME_ERROR;
11068 }
11069
11070 if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
11071 /* For P2P GO, the sec type is WPA2-PSK */
11072 WL_DBG(("P2P GO: validating wpa2_ie"));
11073 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0)
11074 return BCME_ERROR;
11075
11076 } else if (dev_role == NL80211_IFTYPE_AP) {
11077
11078 WL_DBG(("SoftAP: validating security"));
11079 /* If wpa2_ie or wpa_ie is present validate it */
11080
11081#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11082 if ((ies->wpa_ie != NULL && ies->wpa2_ie != NULL)) {
11083 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie, ies->wpa2_ie, bssidx) < 0) {
11084 bss->security_mode = false;
11085 return BCME_ERROR;
11086 }
11087 }
11088 else {
11089#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11090 if ((ies->wpa2_ie || ies->wpa_ie) &&
11091 ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
11092 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
11093 bss->security_mode = false;
11094 return BCME_ERROR;
11095 }
11096
11097 if (ies->fils_ind_ie &&
11098 (wl_validate_fils_ind_ie(dev, ies->fils_ind_ie, bssidx) < 0)) {
11099 bss->security_mode = false;
11100 return BCME_ERROR;
11101 }
11102
11103 bss->security_mode = true;
11104 if (bss->rsn_ie) {
11105 MFREE(cfg->osh, bss->rsn_ie, bss->rsn_ie[1]
11106 + WPA_RSN_IE_TAG_FIXED_LEN);
11107 bss->rsn_ie = NULL;
11108 }
11109 if (bss->wpa_ie) {
11110 MFREE(cfg->osh, bss->wpa_ie, bss->wpa_ie[1]
11111 + WPA_RSN_IE_TAG_FIXED_LEN);
11112 bss->wpa_ie = NULL;
11113 }
11114 if (bss->wps_ie) {
11115 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
11116 bss->wps_ie = NULL;
11117 }
11118 if (bss->fils_ind_ie) {
11119 MFREE(cfg->osh, bss->fils_ind_ie, bss->fils_ind_ie[1]
11120 + FILS_INDICATION_IE_TAG_FIXED_LEN);
11121 bss->fils_ind_ie = NULL;
11122 }
11123 if (ies->wpa_ie != NULL) {
11124 /* WPAIE */
11125 bss->rsn_ie = NULL;
11126 bss->wpa_ie = MALLOCZ(cfg->osh,
11127 ies->wpa_ie->length
11128 + WPA_RSN_IE_TAG_FIXED_LEN);
11129 if (bss->wpa_ie) {
11130 memcpy(bss->wpa_ie, ies->wpa_ie,
11131 ies->wpa_ie->length
11132 + WPA_RSN_IE_TAG_FIXED_LEN);
11133 }
11134 } else if (ies->wpa2_ie != NULL) {
11135 /* RSNIE */
11136 bss->wpa_ie = NULL;
11137 bss->rsn_ie = MALLOCZ(cfg->osh,
11138 ies->wpa2_ie->len
11139 + WPA_RSN_IE_TAG_FIXED_LEN);
11140 if (bss->rsn_ie) {
11141 memcpy(bss->rsn_ie, ies->wpa2_ie,
11142 ies->wpa2_ie->len
11143 + WPA_RSN_IE_TAG_FIXED_LEN);
11144 }
11145 }
11146#ifdef WL_FILS
11147 if (ies->fils_ind_ie) {
11148 bss->fils_ind_ie = MALLOCZ(cfg->osh,
11149 ies->fils_ind_ie->len
11150 + FILS_INDICATION_IE_TAG_FIXED_LEN);
11151 if (bss->fils_ind_ie) {
11152 memcpy(bss->fils_ind_ie, ies->fils_ind_ie,
11153 ies->fils_ind_ie->len
11154 + FILS_INDICATION_IE_TAG_FIXED_LEN);
11155 }
11156 }
11157#endif /* WL_FILS */
11158#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11159 }
11160#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11161 if (!ies->wpa2_ie && !ies->wpa_ie) {
11162 wl_validate_opensecurity(dev, bssidx, privacy);
11163 bss->security_mode = false;
11164 }
11165
11166 if (ies->wps_ie) {
11167 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11168 if (bss->wps_ie) {
11169 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11170 }
11171 }
11172 }
11173
11174 WL_INFORM_MEM(("[%s] wpa_auth:0x%x auth:0x%x wsec:0x%x mfp:0x%x\n",
11175 dev->name, sec->fw_wpa_auth, sec->fw_auth, sec->fw_wsec, sec->fw_mfp));
11176 return 0;
11177
11178}
11179
11180#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11181static s32 wl_cfg80211_bcn_set_params(
11182 struct cfg80211_ap_settings *info,
11183 struct net_device *dev,
11184 u32 dev_role, s32 bssidx)
11185{
11186 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11187 s32 err = BCME_OK;
11188
11189 WL_DBG(("interval (%d) \ndtim_period (%d) \n",
11190 info->beacon_interval, info->dtim_period));
11191
11192 if (info->beacon_interval) {
11193 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
11194 &info->beacon_interval, sizeof(s32))) < 0) {
11195 WL_ERR(("Beacon Interval Set Error, %d\n", err));
11196 return err;
11197 }
11198 }
11199
11200 if (info->dtim_period) {
11201 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
11202 &info->dtim_period, sizeof(s32))) < 0) {
11203 WL_ERR(("DTIM Interval Set Error, %d\n", err));
11204 return err;
11205 }
11206 }
11207
11208 if ((info->ssid) && (info->ssid_len > 0) &&
11209 (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
11210 WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
11211 if (dev_role == NL80211_IFTYPE_AP) {
11212 /* Store the hostapd SSID */
11213 bzero(cfg->hostapd_ssid.SSID, DOT11_MAX_SSID_LEN);
11214 memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
11215 cfg->hostapd_ssid.SSID_len = (uint32)info->ssid_len;
11216 } else {
11217 /* P2P GO */
11218 bzero(cfg->p2p->ssid.SSID, DOT11_MAX_SSID_LEN);
11219 memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
11220 cfg->p2p->ssid.SSID_len = (uint32)info->ssid_len;
11221 }
11222 }
11223
11224 return err;
11225}
11226#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11227
11228static s32
11229wl_cfg80211_parse_ies(const u8 *ptr, u32 len, struct parsed_ies *ies)
11230{
11231 s32 err = BCME_OK;
11232
11233 bzero(ies, sizeof(struct parsed_ies));
11234
11235 /* find the WPSIE */
11236 if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
11237 WL_DBG(("WPSIE in beacon \n"));
11238 ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
11239 } else {
11240 WL_ERR(("No WPSIE in beacon \n"));
11241 }
11242
11243 /* find the RSN_IE */
11244 if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len,
11245 DOT11_MNG_RSN_ID)) != NULL) {
11246 WL_DBG((" WPA2 IE found\n"));
11247 ies->wpa2_ie_len = ies->wpa2_ie->len;
11248 }
11249
11250 /* find the FILS_IND_IE */
11251 if ((ies->fils_ind_ie = bcm_parse_tlvs(ptr, len,
11252 DOT11_MNG_FILS_IND_ID)) != NULL) {
11253 WL_DBG((" FILS IND IE found\n"));
11254 ies->fils_ind_ie_len = ies->fils_ind_ie->len;
11255 }
11256
11257 /* find the WPA_IE */
11258 if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
11259 WL_DBG((" WPA found\n"));
11260 ies->wpa_ie_len = ies->wpa_ie->length;
11261 }
11262
11263 return err;
11264
11265}
11266
11267static s32
11268wl_cfg80211_set_ap_role(
11269 struct bcm_cfg80211 *cfg,
11270 struct net_device *dev)
11271{
11272 s32 err = BCME_OK;
11273 s32 infra = 1;
11274 s32 ap = 0;
11275 s32 pm;
11276 s32 bssidx;
11277 s32 apsta = 0;
11278 bool legacy_chip;
11279
11280 legacy_chip = wl_legacy_chip_check(cfg);
11281
11282 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11283 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11284 return -EINVAL;
11285 }
11286
11287 WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n", dev->name, bssidx));
11288
11289 if (bssidx != 0 || !legacy_chip) {
11290 if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
11291 WL_IF_TYPE_AP, 0, NULL)) < 0) {
11292 WL_ERR(("wl add_del_bss returned error:%d\n", err));
11293 return err;
11294 }
11295 }
11296
11297 /*
11298 * For older chips, "bss" iovar does not support
11299 * bsscfg role change/upgradation, and still
11300 * return BCME_OK on attempt
11301 * Hence, below traditional way to handle the same
11302 */
11303
11304 if ((err = wldev_ioctl_get(dev,
11305 WLC_GET_AP, &ap, sizeof(s32))) < 0) {
11306 WL_ERR(("Getting AP mode failed %d \n", err));
11307 return err;
11308 }
11309
11310 if (!ap) {
11311 /* AP mode switch not supported. Try setting up AP explicitly */
11312 err = wldev_iovar_getint(dev, "apsta", (s32 *)&apsta);
11313 if (unlikely(err)) {
11314 WL_ERR(("Could not get apsta %d\n", err));
11315 return err;
11316 }
11317 if (apsta == 0) {
11318 /* If apsta is not set, set it */
11319
11320 /* Check for any connected interfaces before wl down */
11321 if (wl_get_drv_status_all(cfg, CONNECTED) > 0) {
11322 WL_ERR(("Concurrent i/f operational. can't do wl down"));
11323 return BCME_ERROR;
11324 }
11325 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11326 if (err < 0) {
11327 WL_ERR(("WLC_DOWN error %d\n", err));
11328 return err;
11329 }
11330 err = wldev_iovar_setint(dev, "apsta", 0);
11331 if (err < 0) {
11332 WL_ERR(("wl apsta 0 error %d\n", err));
11333 return err;
11334 }
11335 ap = 1;
11336 if ((err = wldev_ioctl_set(dev,
11337 WLC_SET_AP, &ap, sizeof(s32))) < 0) {
11338 WL_ERR(("setting AP mode failed %d \n", err));
11339 return err;
11340 }
11341 }
11342 } else if (bssidx == 0 && legacy_chip) {
11343 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11344 if (err < 0) {
11345 WL_ERR(("WLC_DOWN error %d\n", err));
11346 return err;
11347 }
11348 err = wldev_iovar_setint(dev, "apsta", 0);
11349 if (err < 0) {
11350 WL_ERR(("wl apsta 0 error %d\n", err));
11351 return err;
11352 }
11353 ap = 1;
11354 if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) < 0) {
11355 WL_ERR(("setting AP mode failed %d \n", err));
11356 return err;
11357 }
11358 }
11359
11360 if (bssidx == 0) {
11361 pm = 0;
11362 if ((err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm))) != 0) {
11363 WL_ERR(("wl PM 0 returned error:%d\n", err));
11364 /* Ignore error, if any */
11365 err = BCME_OK;
11366 }
11367 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11368 if (err < 0) {
11369 WL_ERR(("SET INFRA error %d\n", err));
11370 return err;
11371 }
11372 }
11373
11374 /* On success, mark AP creation in progress. */
11375 wl_set_drv_status(cfg, AP_CREATING, dev);
11376 return 0;
11377}
11378
11379/* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
11380#define MAX_AP_LINK_WAIT_TIME 10000
11381static s32
11382wl_cfg80211_bcn_bringup_ap(
11383 struct net_device *dev,
11384 struct parsed_ies *ies,
11385 u32 dev_role, s32 bssidx)
11386{
11387 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11388 struct wl_join_params join_params;
11389 bool is_bssup = false;
11390 s32 infra = 1;
11391 s32 join_params_size = 0;
11392 s32 ap = 1;
11393 s32 wsec;
11394#ifdef DISABLE_11H_SOFTAP
11395 s32 spect = 0;
11396#endif /* DISABLE_11H_SOFTAP */
11397#ifdef SOFTAP_UAPSD_OFF
11398 uint32 wme_apsd = 0;
11399#endif /* SOFTAP_UAPSD_OFF */
11400 s32 err = BCME_OK;
11401 s32 is_rsdb_supported = BCME_ERROR;
11402 long timeout;
11403 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11404 char sec[32];
11405
11406 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
11407 if (is_rsdb_supported < 0)
11408 return (-ENODEV);
11409
11410 WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role, bssidx, dev->name));
11411
11412 /* Common code for SoftAP and P2P GO */
11413 wl_clr_drv_status(cfg, AP_CREATED, dev);
11414
11415 /* Make sure INFRA is set for AP/GO */
11416 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11417 if (err < 0) {
11418 WL_ERR(("SET INFRA error %d\n", err));
11419 goto exit;
11420 }
11421
11422 /* Do abort scan before creating GO */
11423 wl_cfg80211_scan_abort(cfg);
11424
11425 if (dev_role == NL80211_IFTYPE_P2P_GO) {
11426 wl_ext_get_sec(dev, 0, sec, sizeof(sec));
11427 WL_MSG(dev->name, "Creating GO with sec=%s\n", sec);
11428 is_bssup = wl_cfg80211_bss_isup(dev, bssidx);
11429 if (!is_bssup && (ies->wpa2_ie != NULL)) {
11430
11431 err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid,
11432 sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
11433 bssidx, &cfg->ioctl_buf_sync);
11434 if (err < 0) {
11435 WL_ERR(("GO SSID setting error %d\n", err));
11436 goto exit;
11437 }
11438
11439 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
11440 WL_ERR(("GO Bring up error %d\n", err));
11441 goto exit;
11442 }
11443 wl_clr_drv_status(cfg, AP_CREATING, dev);
11444 } else
11445 WL_DBG(("Bss is already up\n"));
11446 } else if (dev_role == NL80211_IFTYPE_AP) {
11447
11448// if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
11449 /* Make sure fw is in proper state */
11450 err = wl_cfg80211_set_ap_role(cfg, dev);
11451 if (unlikely(err)) {
11452 WL_ERR(("set ap role failed!\n"));
11453 goto exit;
11454 }
11455// }
11456
11457 /* Device role SoftAP */
11458 WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
11459 /* Clear the status bit after use */
11460 wl_clr_drv_status(cfg, AP_CREATING, dev);
11461
11462#ifdef DISABLE_11H_SOFTAP
11463 /* Some old WLAN card (e.g. Intel PRO/Wireless 2200BG)
11464 * does not try to connect SoftAP because they cannot detect
11465 * 11h IEs. For this reason, we disable 11h feature in case
11466 * of SoftAP mode. (Related CSP case number: 661635)
11467 */
11468 if (is_rsdb_supported == 0) {
11469 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11470 if (err < 0) {
11471 WL_ERR(("WLC_DOWN error %d\n", err));
11472 goto exit;
11473 }
11474 }
11475 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT,
11476 &spect, sizeof(s32));
11477 if (err < 0) {
11478 WL_ERR(("SET SPECT_MANAGMENT error %d\n", err));
11479 goto exit;
11480 }
11481#endif /* DISABLE_11H_SOFTAP */
11482
11483#ifdef WL_DISABLE_HE_SOFTAP
11484 err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, FALSE);
11485 if (err < 0) {
11486 WL_ERR(("failed to set he features, error=%d\n", err));
11487 }
11488#endif /* WL_DISABLE_HE_SOFTAP */
11489
11490#ifdef SOFTAP_UAPSD_OFF
11491 err = wldev_iovar_setbuf_bsscfg(dev, "wme_apsd", &wme_apsd, sizeof(wme_apsd),
11492 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11493 if (err < 0) {
11494 WL_ERR(("failed to disable uapsd, error=%d\n", err));
11495 }
11496#endif /* SOFTAP_UAPSD_OFF */
11497
11498 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
11499 if (unlikely(err)) {
11500 WL_ERR(("WLC_UP error (%d)\n", err));
11501 goto exit;
11502 }
11503
11504#ifdef MFP
11505 if (cfg->bip_pos) {
11506 err = wldev_iovar_setbuf_bsscfg(dev, "bip",
11507 (const void *)(cfg->bip_pos), WPA_SUITE_LEN, cfg->ioctl_buf,
11508 WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11509 if (err < 0) {
11510 WL_ERR(("bip set error %d\n", err));
11511
11512 {
11513 goto exit;
11514 }
11515 }
11516 }
11517#endif /* MFP */
11518
11519 err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec);
11520 if (unlikely(err)) {
11521 WL_ERR(("Could not get wsec %d\n", err));
11522 goto exit;
11523 }
11524 if (dhdp->conf->chip == BCM43430_CHIP_ID && bssidx > 0 &&
11525 (wsec & (TKIP_ENABLED|AES_ENABLED))) {
11526 wsec |= WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround
11527 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
11528 if (err < 0) {
11529 WL_ERR(("wsec error %d\n", err));
11530 goto exit;
11531 }
11532 }
11533 if ((wsec == WEP_ENABLED) && cfg->wep_key.len) {
11534 WL_DBG(("Applying buffered WEP KEY \n"));
11535 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &cfg->wep_key,
11536 sizeof(struct wl_wsec_key), cfg->ioctl_buf,
11537 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
11538 /* clear the key after use */
11539 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
11540 if (unlikely(err)) {
11541 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
11542 goto exit;
11543 }
11544 }
11545
11546#ifdef MFP
11547 if (cfg->mfp_mode) {
11548 /* This needs to go after wsec otherwise the wsec command will
11549 * overwrite the values set by MFP
11550 */
11551 err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx);
11552 if (err < 0) {
11553 WL_ERR(("MFP Setting failed. ret = %d \n", err));
11554 /* If fw doesn't support mfp, Ignore the error */
11555 if (err != BCME_UNSUPPORTED) {
11556 goto exit;
11557 }
11558 }
11559 }
11560#endif /* MFP */
11561
11562 bzero(&join_params, sizeof(join_params));
11563 /* join parameters starts with ssid */
11564 join_params_size = sizeof(join_params.ssid);
11565 join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
11566 (uint32)DOT11_MAX_SSID_LEN);
11567 memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
11568 join_params.ssid.SSID_len);
11569 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
11570
11571 wl_ext_get_sec(dev, 0, sec, sizeof(sec));
11572 WL_MSG(dev->name, "Creating AP with sec=%s\n", sec);
11573 /* create softap */
11574 if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
11575 join_params_size)) != 0) {
11576 WL_ERR(("SoftAP/GO set ssid failed! \n"));
11577 goto exit;
11578 } else {
11579 WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
11580 }
11581
11582 if (bssidx != 0) {
11583 /* AP on Virtual Interface */
11584 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
11585 WL_ERR(("AP Bring up error %d\n", err));
11586 goto exit;
11587 }
11588 }
11589
11590 } else {
11591 WL_ERR(("Wrong interface type %d\n", dev_role));
11592 goto exit;
11593 }
11594
11595 /* Wait for Linkup event to mark successful AP/GO bring up */
11596 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
11597 wl_get_drv_status(cfg, AP_CREATED, dev), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
11598 if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) {
11599 WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
11600 if (timeout == -ERESTARTSYS) {
11601 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
11602 err = -ERESTARTSYS;
11603 goto exit;
11604 }
11605 if (dhd_query_bus_erros(dhdp)) {
11606 err = -ENODEV;
11607 goto exit;
11608 }
11609#ifdef DHD_PCIE_RUNTIMEPM
11610 dhdpcie_runtime_bus_wake(dhdp, CAN_SLEEP(), __builtin_return_address(0));
11611#endif /* DHD_PCIE_RUNTIMEPM */
11612 dhdp->iface_op_failed = TRUE;
11613
11614#if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
11615 if (dhdp->memdump_enabled) {
11616 dhdp->memdump_type = DUMP_TYPE_AP_LINKUP_FAILURE;
11617 dhd_bus_mem_dump(dhdp);
11618 }
11619#endif /* DHD_DEBUG && DHD_FW_COREDUMP */
11620
11621 WL_ERR(("Notify hang event to upper layer \n"));
11622 dhdp->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
11623 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
11624
11625 err = -ENODEV;
11626 goto exit;
11627 }
11628 SUPP_LOG(("AP/GO Link up\n"));
11629
11630exit:
11631 if (cfg->wep_key.len) {
11632 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
11633 }
11634
11635#ifdef MFP
11636 if (cfg->mfp_mode) {
11637 cfg->mfp_mode = 0;
11638 }
11639
11640 if (cfg->bip_pos) {
11641 cfg->bip_pos = NULL;
11642 }
11643#endif /* MFP */
11644
11645 if (err) {
11646 SUPP_LOG(("AP/GO bring up fail. err:%d\n", err));
11647 }
11648 return err;
11649}
11650
11651bool
11652wl_cfg80211_macaddr_sync_reqd(struct net_device *dev)
11653{
11654 struct wireless_dev *wdev = dev->ieee80211_ptr;
11655 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11656
11657 WL_DBG(("enter \n"));
11658 if (!wdev) {
11659 WL_ERR(("no wdev present\n"));
11660 return false;
11661 }
11662
11663 BCM_REFERENCE(cfg);
11664
11665#if defined(WL_STATIC_IF)
11666 /* In soft case too role upgrade happens
11667 * from STA to AP in some cases.These
11668 * cases will have iftype as STATION.
11669 */
11670 if (IS_CFG80211_STATIC_IF(cfg, dev)) {
11671 WL_INFORM_MEM(("STATIC interface\n"));
11672 return true;
11673 }
11674#endif /* WL_STATIC_IF && WL_SOFTAP_RAND */
11675
11676 switch (wdev->iftype) {
11677#ifdef WL_P2P_RAND
11678 case NL80211_IFTYPE_P2P_GO:
11679 case NL80211_IFTYPE_P2P_CLIENT:
11680 WL_INFORM_MEM(("P2P GO/GC interface\n"));
11681 return true;
11682#endif /* WL_P2P_RAND */
11683#if defined(WL_STA_ASSOC_RAND)
11684 case NL80211_IFTYPE_STATION:
11685 WL_INFORM_MEM(("STA interface\n"));
11686 return true;
11687#endif /* WL_STA_ASSOC_RAND */
11688#ifdef WL_SOFTAP_RAND
11689 case NL80211_IFTYPE_AP:
11690 WL_INFORM_MEM(("SOFTAP interface\n"));
11691 return true;
11692#endif /* WL_SOFTAP_RAND */
11693 default:
11694 WL_ERR(("no macthing if type\n"));
11695 }
11696 return false;
11697}
11698
11699#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11700s32
11701wl_cfg80211_parse_ap_ies(
11702 struct net_device *dev,
11703 struct cfg80211_beacon_data *info,
11704 struct parsed_ies *ies)
11705{
11706 struct parsed_ies prb_ies;
11707 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11708 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11709 const u8 *vndr = NULL;
11710 u32 vndr_ie_len = 0;
11711 s32 err = BCME_OK;
11712
11713 /* Parse Beacon IEs */
11714 if (wl_cfg80211_parse_ies((const u8 *)info->tail,
11715 info->tail_len, ies) < 0) {
11716 WL_ERR(("Beacon get IEs failed \n"));
11717 err = -EINVAL;
11718 goto fail;
11719 }
11720
11721 if ((err = wl_cfg80211_config_rsnxe_ie(cfg, dev,
11722 (const u8 *)info->tail, info->tail_len)) < 0) {
11723 WL_ERR(("Failed to configure rsnxe ie: %d\n", err));
11724 err = -EINVAL;
11725 goto fail;
11726 }
11727
11728 vndr = (const u8 *)info->proberesp_ies;
11729 vndr_ie_len = (uint32)info->proberesp_ies_len;
11730
11731 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
11732 /* SoftAP mode */
11733 const struct ieee80211_mgmt *mgmt;
11734 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
11735 if (mgmt != NULL) {
11736 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
11737 vndr_ie_len = (uint32)(info->probe_resp_len -
11738 offsetof(const struct ieee80211_mgmt, u.probe_resp.variable));
11739 }
11740 }
11741 /* Parse Probe Response IEs */
11742 if (wl_cfg80211_parse_ies((const u8 *)vndr, vndr_ie_len, &prb_ies) < 0) {
11743 WL_ERR(("PROBE RESP get IEs failed \n"));
11744 err = -EINVAL;
11745 }
11746fail:
11747
11748 return err;
11749}
11750
11751s32
11752wl_cfg80211_set_ies(
11753 struct net_device *dev,
11754 struct cfg80211_beacon_data *info,
11755 s32 bssidx)
11756{
11757 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11758 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11759 const u8 *vndr = NULL;
11760 u32 vndr_ie_len = 0;
11761 s32 err = BCME_OK;
11762
11763 /* Set Beacon IEs to FW */
11764 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
11765 VNDR_IE_BEACON_FLAG, (const u8 *)info->tail,
11766 info->tail_len)) < 0) {
11767 WL_ERR(("Set Beacon IE Failed \n"));
11768 } else {
11769 WL_DBG(("Applied Vndr IEs for Beacon \n"));
11770 }
11771
11772 vndr = (const u8 *)info->proberesp_ies;
11773 vndr_ie_len = (uint32)info->proberesp_ies_len;
11774
11775 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
11776 /* SoftAP mode */
11777 const struct ieee80211_mgmt *mgmt;
11778 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
11779 if (mgmt != NULL) {
11780 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
11781 vndr_ie_len = (uint32)(info->probe_resp_len -
11782 offsetof(struct ieee80211_mgmt, u.probe_resp.variable));
11783 }
11784 }
11785
11786 /* Set Probe Response IEs to FW */
11787 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
11788 VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
11789 WL_ERR(("Set Probe Resp IE Failed \n"));
11790 } else {
11791 WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
11792 }
11793
11794 return err;
11795}
11796#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11797
11798static s32 wl_cfg80211_hostapd_sec(
11799 struct net_device *dev,
11800 struct parsed_ies *ies,
11801 s32 bssidx)
11802{
11803 bool update_bss = 0;
11804 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11805 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
11806
11807 if (!bss) {
11808 WL_ERR(("cfgbss is NULL \n"));
11809 return -EINVAL;
11810 }
11811
11812 if (ies->wps_ie) {
11813 /* Remove after verification.
11814 * Setting IE part moved to set_ies func
11815 */
11816 if (bss->wps_ie &&
11817 memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
11818 WL_DBG((" WPS IE is changed\n"));
11819 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
11820 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11821 if (bss->wps_ie) {
11822 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11823 }
11824 } else if (bss->wps_ie == NULL) {
11825 WL_DBG((" WPS IE is added\n"));
11826 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11827 if (bss->wps_ie) {
11828 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11829 }
11830 }
11831
11832#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11833 if (ies->wpa_ie != NULL && ies->wpa2_ie != NULL) {
11834 WL_ERR(("update bss - wpa_ie and wpa2_ie is not null\n"));
11835 if (!bss->security_mode) {
11836 /* change from open mode to security mode */
11837 update_bss = true;
11838 bss->wpa_ie = MALLOCZ(cfg->osh,
11839 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11840 if (bss->wpa_ie) {
11841 memcpy(bss->wpa_ie, ies->wpa_ie,
11842 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11843 }
11844 bss->rsn_ie = MALLOCZ(cfg->osh,
11845 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11846 if (bss->rsn_ie) {
11847 memcpy(bss->rsn_ie, ies->wpa2_ie,
11848 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11849 }
11850 } else {
11851 /* change from (WPA or WPA2 or WPA/WPA2) to WPA/WPA2 mixed mode */
11852 if (bss->wpa_ie) {
11853 if (memcmp(bss->wpa_ie,
11854 ies->wpa_ie, ies->wpa_ie->length +
11855 WPA_RSN_IE_TAG_FIXED_LEN)) {
11856 MFREE(cfg->osh, bss->wpa_ie,
11857 bss->wpa_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11858 update_bss = true;
11859 bss->wpa_ie = MALLOCZ(cfg->osh,
11860 ies->wpa_ie->length
11861 + WPA_RSN_IE_TAG_FIXED_LEN);
11862 if (bss->wpa_ie) {
11863 memcpy(bss->wpa_ie, ies->wpa_ie,
11864 ies->wpa_ie->length
11865 + WPA_RSN_IE_TAG_FIXED_LEN);
11866 }
11867 }
11868 }
11869 else {
11870 update_bss = true;
11871 bss->wpa_ie = MALLOCZ(cfg->osh,
11872 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11873 if (bss->wpa_ie) {
11874 memcpy(bss->wpa_ie, ies->wpa_ie,
11875 ies->wpa_ie->length
11876 + WPA_RSN_IE_TAG_FIXED_LEN);
11877 }
11878 }
11879 if (bss->rsn_ie) {
11880 if (memcmp(bss->rsn_ie,
11881 ies->wpa2_ie,
11882 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
11883 update_bss = true;
11884 MFREE(cfg->osh, bss->rsn_ie,
11885 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11886 bss->rsn_ie = MALLOCZ(cfg->osh,
11887 ies->wpa2_ie->len
11888 + WPA_RSN_IE_TAG_FIXED_LEN);
11889 if (bss->rsn_ie) {
11890 memcpy(bss->rsn_ie, ies->wpa2_ie,
11891 ies->wpa2_ie->len
11892 + WPA_RSN_IE_TAG_FIXED_LEN);
11893 }
11894 }
11895 }
11896 else {
11897 update_bss = true;
11898 bss->rsn_ie = MALLOCZ(cfg->osh,
11899 ies->wpa2_ie->len
11900 + WPA_RSN_IE_TAG_FIXED_LEN);
11901 if (bss->rsn_ie) {
11902 memcpy(bss->rsn_ie, ies->wpa2_ie,
11903 ies->wpa2_ie->len
11904 + WPA_RSN_IE_TAG_FIXED_LEN);
11905 }
11906 }
11907 }
11908 WL_ERR(("update_bss=%d\n", update_bss));
11909 if (update_bss) {
11910 bss->security_mode = true;
11911 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11912 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie,
11913 ies->wpa2_ie, bssidx) < 0) {
11914 return BCME_ERROR;
11915 }
11916 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11917 }
11918
11919 }
11920 else
11921#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11922 if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
11923 if (!bss->security_mode) {
11924 /* change from open mode to security mode */
11925 update_bss = true;
11926 if (ies->wpa_ie != NULL) {
11927 bss->wpa_ie = MALLOCZ(cfg->osh,
11928 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11929 if (bss->wpa_ie) {
11930 memcpy(bss->wpa_ie,
11931 ies->wpa_ie,
11932 ies->wpa_ie->length
11933 + WPA_RSN_IE_TAG_FIXED_LEN);
11934 }
11935 } else {
11936 bss->rsn_ie = MALLOCZ(cfg->osh,
11937 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11938 if (bss->rsn_ie) {
11939 memcpy(bss->rsn_ie,
11940 ies->wpa2_ie,
11941 ies->wpa2_ie->len
11942 + WPA_RSN_IE_TAG_FIXED_LEN);
11943 }
11944 }
11945 } else if (bss->wpa_ie) {
11946 /* change from WPA2 mode to WPA mode */
11947 if (ies->wpa_ie != NULL) {
11948 update_bss = true;
11949 MFREE(cfg->osh, bss->rsn_ie,
11950 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11951 bss->rsn_ie = NULL;
11952 bss->wpa_ie = MALLOCZ(cfg->osh,
11953 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11954 if (bss->wpa_ie) {
11955 memcpy(bss->wpa_ie,
11956 ies->wpa_ie,
11957 ies->wpa_ie->length
11958 + WPA_RSN_IE_TAG_FIXED_LEN);
11959 }
11960 } else if (memcmp(bss->rsn_ie,
11961 ies->wpa2_ie, ies->wpa2_ie->len
11962 + WPA_RSN_IE_TAG_FIXED_LEN)) {
11963 update_bss = true;
11964 MFREE(cfg->osh, bss->rsn_ie,
11965 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11966 bss->rsn_ie = MALLOCZ(cfg->osh,
11967 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11968 if (bss->rsn_ie) {
11969 memcpy(bss->rsn_ie,
11970 ies->wpa2_ie,
11971 ies->wpa2_ie->len
11972 + WPA_RSN_IE_TAG_FIXED_LEN);
11973 }
11974 bss->wpa_ie = NULL;
11975 }
11976 }
11977 if (update_bss) {
11978 bss->security_mode = true;
11979 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11980 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
11981 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
11982 return BCME_ERROR;
11983 }
11984 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11985 }
11986 }
11987 } else {
11988 WL_ERR(("No WPSIE in beacon \n"));
11989 }
11990 return 0;
11991}
11992
11993#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
11994 2, 0))
11995static s32
11996#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11997wl_cfg80211_del_station(
11998 struct wiphy *wiphy, struct net_device *ndev,
11999 struct station_del_parameters *params)
12000#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
12001wl_cfg80211_del_station(
12002 struct wiphy *wiphy,
12003 struct net_device *ndev,
12004 const u8* mac_addr)
12005#else
12006wl_cfg80211_del_station(
12007 struct wiphy *wiphy,
12008 struct net_device *ndev,
12009 u8* mac_addr)
12010#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12011{
12012 struct net_device *dev;
12013 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12014 scb_val_t scb_val;
12015 s8 eabuf[ETHER_ADDR_STR_LEN];
12016 int err;
12017 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
12018 sizeof(struct ether_addr) + sizeof(uint)] = {0};
12019 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
12020 int num_associated = 0;
12021
12022#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12023 const u8 *mac_addr = params->mac;
12024#ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
12025 u16 rc = params->reason_code;
12026#endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
12027#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12028
12029 WL_DBG(("Entry\n"));
12030 if (mac_addr == NULL) {
12031 WL_DBG(("mac_addr is NULL ignore it\n"));
12032 return 0;
12033 }
12034
12035 dev = ndev_to_wlc_ndev(ndev, cfg);
12036
12037 if (p2p_is_on(cfg)) {
12038 /* Suspend P2P discovery search-listen to prevent it from changing the
12039 * channel.
12040 */
12041 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
12042 WL_ERR(("Can not disable discovery mode\n"));
12043 return -EFAULT;
12044 }
12045 }
12046 err = wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
12047 WL_EXT_STATUS_DELETE_STA, (void *)mac_addr);
12048 if (err) {
12049 return 0;
12050 }
12051
12052 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
12053 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
12054 assoc_maclist, sizeof(mac_buf));
12055 if (err < 0)
12056 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
12057 else
12058 num_associated = assoc_maclist->count;
12059
12060 memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
12061#ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
12062#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12063 if (rc == DOT11_RC_8021X_AUTH_FAIL) {
12064 WL_ERR(("deauth will be sent at F/W\n"));
12065 scb_val.val = DOT11_RC_8021X_AUTH_FAIL;
12066 } else {
12067#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12068#endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
12069
12070#ifdef WL_WPS_SYNC
12071 if (wl_wps_session_update(ndev,
12072 WPS_STATE_DISCONNECT_CLIENT, mac_addr) == BCME_UNSUPPORTED) {
12073 /* Ignore disconnect command from upper layer */
12074 WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
12075 } else
12076#endif /* WL_WPS_SYNC */
12077 {
12078 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
12079 WL_MSG(dev->name, "Disconnect STA : " MACDBG " scb_val.val %d\n",
12080 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mac_addr,
12081 eabuf)), scb_val.val);
12082 /* need to guarantee EAP-Failure send out before deauth */
12083 dhd_wait_pend8021x(dev);
12084 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
12085 sizeof(scb_val_t));
12086 if (err < 0) {
12087 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
12088 }
12089 }
12090#ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
12091#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12092 }
12093#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12094#endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
12095
12096 /* WAR Wait for the deauth event to come, supplicant will do the
12097 * delete iface immediately and we will have problem in sending
12098 * deauth frame if we delete the bss in firmware
12099 * But we do not need additional delays for this WAR
12100 * during P2P connection.
12101 *
12102 * Supplicant call this function with BCAST after doing
12103 * wl_cfg80211_del_station() all GC stations with each addr.
12104 * So, 400 ms delay can be called only once when GO disconnect all GC
12105 */
12106 if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
12107 wl_delay(400);
12108
12109 return 0;
12110}
12111
12112/* Implementation for post SCB authorize */
12113static void
12114wl_cfg80211_post_scb_auth(struct bcm_cfg80211 *cfg, struct net_device *dev)
12115{
12116#ifdef WBTEXT
12117 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12118#endif /* WBTEXT */
12119
12120 LOG_TS(cfg, authorize_cmplt);
12121 CLR_TS(cfg, authorize_start);
12122 wl_set_drv_status(cfg, AUTHORIZED, dev);
12123#ifdef DHD_LOSSLESS_ROAMING
12124 wl_del_roam_timeout(cfg);
12125#endif
12126#ifdef WBTEXT
12127 /* send nbr request or BTM query to update RCC
12128 * after 4-way handshake is completed
12129 */
12130 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
12131 dhdp->wbtext_support) {
12132 wl_cfg80211_wbtext_update_rcc(cfg, dev);
12133 }
12134#endif /* WBTEXT */
12135}
12136
12137/* Currently adding support only for authorize/de-authorize flag
12138 * Need to be extended in future
12139 */
12140#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
12141static s32
12142wl_cfg80211_change_station(
12143 struct wiphy *wiphy,
12144 struct net_device *dev,
12145 const u8 *mac,
12146 struct station_parameters *params)
12147#else
12148static s32
12149wl_cfg80211_change_station(
12150 struct wiphy *wiphy,
12151 struct net_device *dev,
12152 u8 *mac,
12153 struct station_parameters *params)
12154#endif
12155{
12156 int err = BCME_OK;
12157 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12158#ifdef BCMSUP_4WAY_HANDSHAKE
12159 struct wl_security *sec;
12160#endif /* BCMSUP_4WAY_HANDSHAKE */
12161 struct net_device *ndev = ndev_to_wlc_ndev(dev, cfg);
12162
12163 WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x "
12164 "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac),
12165 params->sta_flags_mask, params->sta_flags_set, ndev->name));
12166
12167 if ((wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS) &&
12168 !(wl_get_drv_status(cfg, CONNECTED, dev))) {
12169 /* Return error indicating not in connected state */
12170 WL_ERR(("Ignore SCB_AUTHORIZE/DEAUTHORIZE in non connected state\n"));
12171 return -ENOTSUPP;
12172 }
12173
12174 /* Processing only authorize/de-authorize flag for now */
12175 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
12176 WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
12177 return -ENOTSUPP;
12178 }
12179
12180 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
12181 err = wldev_ioctl_set(ndev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN);
12182 if (unlikely(err)) {
12183 WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
12184 } else {
12185 WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG "\n",
12186 ndev->name, MAC2STRDBG(mac)));
12187 }
12188 wl_clr_drv_status(cfg, AUTHORIZED, dev);
12189 CLR_TS(cfg, authorize_start);
12190 CLR_TS(cfg, conn_start);
12191 return err;
12192 }
12193 /* In case of 4way HS offloaded to FW and key_mgmt being 8021x, even the SCB
12194 * authorization is also offloaded to FW. So on reception of SCB authorize in the above
12195 * cases we avoid explicit call to ioctl WLC_SCB_AUTHORIZE. The post SCB authorize
12196 * actions are done from context of WLC_E_PSK_SUP event handler
12197 */
12198#ifdef BCMSUP_4WAY_HANDSHAKE
12199 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
12200 if (
12201#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
12202 (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X)) &&
12203#else
12204 (cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) &&
12205#endif
12206 ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
12207 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X))) {
12208 return BCME_OK;
12209 }
12210#endif /* BCMSUP_4WAY_HANDSHAKE */
12211 err = wldev_ioctl_set(ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN);
12212 if (unlikely(err)) {
12213 WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
12214 } else {
12215 WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG "\n",
12216 ndev->name, MAC2STRDBG(mac)));
12217#ifdef WL_WPS_SYNC
12218 wl_wps_session_update(ndev, WPS_STATE_AUTHORIZE, mac);
12219#endif /* WL_WPS_SYNC */
12220 }
12221
12222 /* Post SCB authorize actions */
12223 wl_cfg80211_post_scb_auth(cfg, ndev);
12224
12225 return err;
12226}
12227#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
12228
12229static s32
12230wl_cfg80211_set_scb_timings(
12231 struct bcm_cfg80211 *cfg,
12232 struct net_device *dev)
12233{
12234 int err;
12235 u32 ps_pretend;
12236 wl_scb_probe_t scb_probe;
12237 u32 ps_pretend_retries;
12238
12239 bzero(&scb_probe, sizeof(wl_scb_probe_t));
12240 scb_probe.scb_timeout = WL_SCB_TIMEOUT;
12241 scb_probe.scb_activity_time = WL_SCB_ACTIVITY_TIME;
12242 scb_probe.scb_max_probe = WL_SCB_MAX_PROBE;
12243 err = wldev_iovar_setbuf(dev, "scb_probe", (void *)&scb_probe,
12244 sizeof(wl_scb_probe_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
12245 &cfg->ioctl_buf_sync);
12246 if (unlikely(err)) {
12247 WL_ERR(("set 'scb_probe' failed, error = %d\n", err));
12248 return err;
12249 }
12250
12251 ps_pretend_retries = WL_PSPRETEND_RETRY_LIMIT;
12252 err = wldev_iovar_setint(dev, "pspretend_retry_limit", ps_pretend_retries);
12253 if (unlikely(err)) {
12254 if (err == BCME_UNSUPPORTED) {
12255 /* Ignore error if fw doesn't support the iovar */
12256 WL_DBG(("set 'pspretend_retry_limit %d' failed, error = %d\n",
12257 ps_pretend_retries, err));
12258 } else {
12259 WL_ERR(("set 'pspretend_retry_limit %d' failed, error = %d\n",
12260 ps_pretend_retries, err));
12261 return err;
12262 }
12263 }
12264
12265 ps_pretend = MAX(WL_SCB_MAX_PROBE / 2, WL_MIN_PSPRETEND_THRESHOLD);
12266 err = wldev_iovar_setint(dev, "pspretend_threshold", ps_pretend);
12267 if (unlikely(err)) {
12268 if (err == BCME_UNSUPPORTED) {
12269 /* Ignore error if fw doesn't support the iovar */
12270 WL_DBG(("wl pspretend_threshold %d set error %d\n",
12271 ps_pretend, err));
12272 } else {
12273 WL_ERR(("wl pspretend_threshold %d set error %d\n",
12274 ps_pretend, err));
12275 return err;
12276 }
12277 }
12278
12279 return 0;
12280}
12281
12282#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
12283static s32
12284wl_cfg80211_start_ap(
12285 struct wiphy *wiphy,
12286 struct net_device *dev,
12287 struct cfg80211_ap_settings *info)
12288{
12289 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12290 s32 err = BCME_OK;
12291 struct parsed_ies ies;
12292 s32 bssidx = 0;
12293 u32 dev_role = 0;
12294 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12295
12296 WL_DBG(("Enter \n"));
12297
12298 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12299 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12300 return BCME_ERROR;
12301 }
12302
12303 if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
12304 dev_role = NL80211_IFTYPE_P2P_GO;
12305 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12306
12307 if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
12308 /* Make sure fw is in proper state */
12309 err = wl_cfg80211_set_ap_role(cfg, dev);
12310 if (unlikely(err)) {
12311 WL_ERR(("set ap role failed!\n"));
12312 return BCME_ERROR;
12313 }
12314 }
12315 dev_role = NL80211_IFTYPE_AP;
12316 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
12317 err = dhd_ndo_enable(dhd, FALSE);
12318 WL_DBG(("Disabling NDO on Hostapd mode %d\n", err));
12319 if (err) {
12320 WL_ERR(("Disabling NDO Failed %d\n", err));
12321 }
12322#ifdef WL_EXT_IAPSTA
12323 wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev), WL_IF_TYPE_AP);
12324#endif /* WL_EXT_IAPSTA */
12325#ifdef PKT_FILTER_SUPPORT
12326 /* Disable packet filter */
12327 if (dhd->early_suspended) {
12328 WL_ERR(("Disable pkt_filter\n"));
12329 dhd_enable_packet_filter(0, dhd);
12330#ifdef APF
12331 dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd));
12332#endif /* APF */
12333 }
12334#endif /* PKT_FILTER_SUPPORT */
12335 } else {
12336 /* only AP or GO role need to be handled here. */
12337 err = -EINVAL;
12338 goto fail;
12339 }
12340
12341 /* disable TDLS */
12342#ifdef WLTDLS
12343 if (bssidx == 0) {
12344 /* Disable TDLS for primary Iface. For virtual interface,
12345 * tdls disable will happen from interface create context
12346 */
12347 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_CREATE, false);
12348 }
12349#endif /* WLTDLS */
12350
12351 if (!check_dev_role_integrity(cfg, dev_role)) {
12352 err = -EINVAL;
12353 goto fail;
12354 }
12355
12356/*
12357 * TODO:
12358 * Check whether 802.11ac-160MHz bandwidth channel setting has to use the
12359 * center frequencies present in 'preset_chandef' instead of using the
12360 * hardcoded values in 'wl_cfg80211_set_channel()'.
12361 */
12362#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
12363 if ((err = wl_cfg80211_set_channel(wiphy, dev,
12364 dev->ieee80211_ptr->preset_chandef.chan,
12365 NL80211_CHAN_HT20) < 0)) {
12366 WL_ERR(("Set channel failed \n"));
12367 goto fail;
12368 }
12369#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
12370
12371 if ((err = wl_cfg80211_bcn_set_params(info, dev,
12372 dev_role, bssidx)) < 0) {
12373 WL_ERR(("Beacon params set failed \n"));
12374 goto fail;
12375 }
12376
12377 /* Parse IEs */
12378 if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) {
12379 WL_ERR(("Set IEs failed \n"));
12380 goto fail;
12381 }
12382
12383 if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies,
12384 dev_role, bssidx, info->privacy)) < 0)
12385 {
12386 WL_ERR(("Beacon set security failed \n"));
12387 goto fail;
12388 }
12389
12390 if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies,
12391 dev_role, bssidx)) < 0) {
12392 WL_ERR(("Beacon bring up AP/GO failed \n"));
12393 goto fail;
12394 }
12395
12396 /* Set GC/STA SCB expiry timings. */
12397 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
12398 WL_ERR(("scb setting failed \n"));
12399// goto fail;
12400 }
12401
12402 wl_set_drv_status(cfg, CONNECTED, dev);
12403 WL_DBG(("** AP/GO Created **\n"));
12404
12405#ifdef WL_CFG80211_ACL
12406 /* Enfoce Admission Control. */
12407 if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
12408 WL_ERR(("Set ACL failed\n"));
12409 }
12410#endif /* WL_CFG80211_ACL */
12411
12412 /* Set IEs to FW */
12413 if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
12414 WL_ERR(("Set IEs failed \n"));
12415
12416#ifdef WLDWDS
12417 if (dev->ieee80211_ptr->use_4addr) {
12418 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12419 VNDR_IE_ASSOCRSP_FLAG, (const u8 *)info->beacon.assocresp_ies,
12420 info->beacon.assocresp_ies_len)) < 0) {
12421 WL_ERR(("Set ASSOC RESP IE Failed\n"));
12422 }
12423 }
12424#endif /* WLDWDS */
12425
12426 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12427 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
12428 bool pbc = 0;
12429 wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12430 if (pbc) {
12431 WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
12432 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12433 }
12434 }
12435
12436 /* Configure hidden SSID */
12437 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) {
12438 if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
12439 WL_ERR(("failed to set hidden : %d\n", err));
12440 WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
12441 }
12442
12443#ifdef SUPPORT_AP_RADIO_PWRSAVE
12444 if (dev_role == NL80211_IFTYPE_AP) {
12445 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
12446 wl_cfg80211_init_ap_rps(cfg);
12447 } else {
12448 WL_ERR(("Set rpsnoa failed \n"));
12449 }
12450 }
12451#endif /* SUPPORT_AP_RADIO_PWRSAVE */
12452fail:
12453 if (err) {
12454 WL_ERR(("ADD/SET beacon failed\n"));
12455 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12456 wl_cfg80211_stop_ap(wiphy, dev);
12457 if (dev_role == NL80211_IFTYPE_AP) {
12458#ifdef WL_EXT_IAPSTA
12459 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12460#endif /* WL_EXT_IAPSTA */
12461 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12462#ifdef PKT_FILTER_SUPPORT
12463 /* Enable packet filter */
12464 if (dhd->early_suspended) {
12465 WL_ERR(("Enable pkt_filter\n"));
12466 dhd_enable_packet_filter(1, dhd);
12467#ifdef APF
12468 dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd));
12469#endif /* APF */
12470 }
12471#endif /* PKT_FILTER_SUPPORT */
12472#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12473 wl_cfg80211_set_frameburst(cfg, TRUE);
12474#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12475#ifdef WL_EXT_IAPSTA
12476 }
12477#endif /* WL_EXT_IAPSTA */
12478 }
12479#ifdef WLTDLS
12480 if (bssidx == 0) {
12481 /* Since AP creation failed, re-enable TDLS */
12482 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
12483 }
12484#endif /* WLTDLS */
12485
12486 }
12487
12488 return err;
12489}
12490
12491static s32
12492wl_cfg80211_stop_ap(
12493 struct wiphy *wiphy,
12494 struct net_device *dev)
12495{
12496 int err = 0;
12497 u32 dev_role = 0;
12498 int ap = 0;
12499 s32 bssidx = 0;
12500 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12501 s32 is_rsdb_supported = BCME_ERROR;
12502 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12503
12504 WL_DBG(("Enter \n"));
12505
12506 if (wl_cfg80211_get_bus_state(cfg)) {
12507 /* since bus is down, iovar will fail. recovery path will bringup the bus. */
12508 WL_ERR(("bus is not ready\n"));
12509 return BCME_OK;
12510 }
12511 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
12512 if (is_rsdb_supported < 0)
12513 return (-ENODEV);
12514
12515 wl_clr_drv_status(cfg, AP_CREATING, dev);
12516 wl_clr_drv_status(cfg, AP_CREATED, dev);
12517 cfg->ap_oper_channel = INVCHANSPEC;
12518
12519 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12520 dev_role = NL80211_IFTYPE_AP;
12521 WL_DBG(("stopping AP operation\n"));
12522 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12523 dev_role = NL80211_IFTYPE_P2P_GO;
12524 WL_DBG(("stopping P2P GO operation\n"));
12525 } else {
12526 WL_ERR(("no AP/P2P GO interface is operational.\n"));
12527 return -EINVAL;
12528 }
12529
12530 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12531 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12532 return BCME_ERROR;
12533 }
12534
12535 if (!check_dev_role_integrity(cfg, dev_role)) {
12536 WL_ERR(("role integrity check failed \n"));
12537 err = -EINVAL;
12538 goto exit;
12539 }
12540
12541 /* Free up resources */
12542 wl_cfg80211_cleanup_if(dev);
12543
12544 /* Clear AP/GO connected status */
12545 wl_clr_drv_status(cfg, CONNECTED, dev);
12546 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
12547 WL_ERR(("bss down error %d\n", err));
12548 }
12549
12550 if (dev_role == NL80211_IFTYPE_AP) {
12551#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12552 wl_cfg80211_set_frameburst(cfg, TRUE);
12553#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12554#ifdef PKT_FILTER_SUPPORT
12555 /* Enable packet filter */
12556 if (dhd->early_suspended) {
12557 WL_ERR(("Enable pkt_filter\n"));
12558 dhd_enable_packet_filter(1, dhd);
12559#ifdef APF
12560 dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd));
12561#endif /* APF */
12562 }
12563#endif /* PKT_FILTER_SUPPORT */
12564
12565 if (is_rsdb_supported == 0) {
12566 /* For non-rsdb chips, we use stand alone AP. Do wl down on stop AP */
12567 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
12568 if (unlikely(err)) {
12569 WL_ERR(("WLC_UP error (%d)\n", err));
12570 err = -EINVAL;
12571 goto exit;
12572 }
12573 }
12574
12575#ifdef WL_DISABLE_HE_SOFTAP
12576 if (wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, TRUE) != BCME_OK) {
12577 WL_ERR(("failed to set he features\n"));
12578 }
12579#endif /* WL_DISABLE_HE_SOFTAP */
12580
12581 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
12582#ifdef SUPPORT_AP_RADIO_PWRSAVE
12583 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
12584 wl_cfg80211_init_ap_rps(cfg);
12585 } else {
12586 WL_ERR(("Set rpsnoa failed \n"));
12587 }
12588#endif /* SUPPORT_AP_RADIO_PWRSAVE */
12589 } else {
12590 /* Do we need to do something here */
12591 WL_DBG(("Stopping P2P GO \n"));
12592
12593 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
12594 DHD_EVENT_TIMEOUT_MS*3);
12595 DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub));
12596
12597 }
12598
12599 SUPP_LOG(("AP/GO Link down\n"));
12600exit:
12601 if (err) {
12602 /* In case of failure, flush fw logs */
12603 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12604 SUPP_LOG(("AP/GO Link down fail. err:%d\n", err));
12605 }
12606#ifdef WLTDLS
12607 if (bssidx == 0) {
12608 /* re-enable TDLS if the number of connected interfaces is less than 2 */
12609 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
12610 }
12611#endif /* WLTDLS */
12612
12613 if (dev_role == NL80211_IFTYPE_AP) {
12614#ifdef WL_EXT_IAPSTA
12615 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12616#endif /* WL_EXT_IAPSTA */
12617 /* clear the AP mode */
12618 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12619#ifdef WL_EXT_IAPSTA
12620 }
12621#endif /* WL_EXT_IAPSTA */
12622 }
12623 return err;
12624}
12625
12626static s32
12627wl_cfg80211_change_beacon(
12628 struct wiphy *wiphy,
12629 struct net_device *dev,
12630 struct cfg80211_beacon_data *info)
12631{
12632 s32 err = BCME_OK;
12633 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12634 struct parsed_ies ies;
12635 u32 dev_role = 0;
12636 s32 bssidx = 0;
12637 bool pbc = 0;
12638
12639 WL_DBG(("Enter \n"));
12640
12641 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12642 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12643 return BCME_ERROR;
12644 }
12645
12646 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12647 dev_role = NL80211_IFTYPE_P2P_GO;
12648 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12649 dev_role = NL80211_IFTYPE_AP;
12650 } else {
12651 err = -EINVAL;
12652 goto fail;
12653 }
12654
12655 if (!check_dev_role_integrity(cfg, dev_role)) {
12656 err = -EINVAL;
12657 goto fail;
12658 }
12659
12660 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
12661 WL_ERR(("P2P already down status!\n"));
12662 err = BCME_ERROR;
12663 goto fail;
12664 }
12665
12666 /* Parse IEs */
12667 if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) {
12668 WL_ERR(("Parse IEs failed \n"));
12669 goto fail;
12670 }
12671
12672 /* Set IEs to FW */
12673 if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
12674 WL_ERR(("Set IEs failed \n"));
12675 goto fail;
12676 }
12677
12678 if (dev_role == NL80211_IFTYPE_AP) {
12679 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
12680 WL_ERR(("Hostapd update sec failed \n"));
12681 err = -EINVAL;
12682 goto fail;
12683 }
12684 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12685 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
12686 wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12687 WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
12688 if (pbc)
12689 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12690 else
12691 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
12692 }
12693 }
12694
12695fail:
12696 if (err) {
12697 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12698 }
12699 return err;
12700}
12701#else
12702static s32
12703wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
12704 struct beacon_parameters *info)
12705{
12706 s32 err = BCME_OK;
12707 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12708 s32 ie_offset = 0;
12709 s32 bssidx = 0;
12710 u32 dev_role = NL80211_IFTYPE_AP;
12711 struct parsed_ies ies;
12712 bcm_tlv_t *ssid_ie;
12713 bool pbc = 0;
12714 bool privacy;
12715 bool is_bss_up = 0;
12716 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12717
12718 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
12719 info->interval, info->dtim_period, info->head_len, info->tail_len));
12720
12721 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
12722 dev_role = NL80211_IFTYPE_AP;
12723 }
12724#if defined(WL_ENABLE_P2P_IF)
12725 else if (dev == cfg->p2p_net) {
12726 /* Group Add request on p2p0 */
12727 dev = bcmcfg_to_prmry_ndev(cfg);
12728 dev_role = NL80211_IFTYPE_P2P_GO;
12729 }
12730#endif /* WL_ENABLE_P2P_IF */
12731
12732 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12733 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12734 return BCME_ERROR;
12735 }
12736
12737 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12738 dev_role = NL80211_IFTYPE_P2P_GO;
12739 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12740 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
12741 }
12742
12743 if (!check_dev_role_integrity(cfg, dev_role)) {
12744 err = -ENODEV;
12745 goto fail;
12746 }
12747
12748 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
12749 WL_ERR(("P2P already down status!\n"));
12750 err = BCME_ERROR;
12751 goto fail;
12752 }
12753
12754 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
12755 /* find the SSID */
12756 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
12757 info->head_len - ie_offset,
12758 DOT11_MNG_SSID_ID)) != NULL) {
12759 if (dev_role == NL80211_IFTYPE_AP) {
12760 /* Store the hostapd SSID */
12761 bzero(&cfg->hostapd_ssid.SSID[0], DOT11_MAX_SSID_LEN);
12762 cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
12763 memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
12764 cfg->hostapd_ssid.SSID_len);
12765 } else {
12766 /* P2P GO */
12767 bzero(&cfg->p2p->ssid.SSID[0], DOT11_MAX_SSID_LEN);
12768 cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
12769 memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
12770 cfg->p2p->ssid.SSID_len);
12771 }
12772 }
12773
12774 if (wl_cfg80211_parse_ies((u8 *)info->tail,
12775 info->tail_len, &ies) < 0) {
12776 WL_ERR(("Beacon get IEs failed \n"));
12777 err = -EINVAL;
12778 goto fail;
12779 }
12780
12781 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12782 VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
12783 info->tail_len)) < 0) {
12784 WL_ERR(("Beacon set IEs failed \n"));
12785 goto fail;
12786 } else {
12787 WL_DBG(("Applied Vndr IEs for Beacon \n"));
12788 }
12789
12790#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12791 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12792 VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies,
12793 info->proberesp_ies_len)) < 0) {
12794 WL_ERR(("ProbeRsp set IEs failed \n"));
12795 goto fail;
12796 } else {
12797 WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
12798 }
12799#endif
12800
12801 is_bss_up = wl_cfg80211_bss_isup(dev, bssidx);
12802
12803#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12804 privacy = info->privacy;
12805#else
12806 privacy = 0;
12807#endif
12808 if (!is_bss_up &&
12809 (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx, privacy) < 0))
12810 {
12811 WL_ERR(("Beacon set security failed \n"));
12812 err = -EINVAL;
12813 goto fail;
12814 }
12815
12816 /* Set BI and DTIM period */
12817 if (info->interval) {
12818 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
12819 &info->interval, sizeof(s32))) < 0) {
12820 WL_ERR(("Beacon Interval Set Error, %d\n", err));
12821 return err;
12822 }
12823 }
12824 if (info->dtim_period) {
12825 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
12826 &info->dtim_period, sizeof(s32))) < 0) {
12827 WL_ERR(("DTIM Interval Set Error, %d\n", err));
12828 return err;
12829 }
12830 }
12831
12832 /* If bss is already up, skip bring up */
12833 if (!is_bss_up &&
12834 (err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0)
12835 {
12836 WL_ERR(("Beacon bring up AP/GO failed \n"));
12837 goto fail;
12838 }
12839
12840 /* Set GC/STA SCB expiry timings. */
12841 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
12842 WL_ERR(("scb setting failed \n"));
12843 if (err == BCME_UNSUPPORTED)
12844 err = 0;
12845// goto fail;
12846 }
12847
12848 if (wl_get_drv_status(cfg, AP_CREATED, dev)) {
12849 /* Soft AP already running. Update changed params */
12850 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
12851 WL_ERR(("Hostapd update sec failed \n"));
12852 err = -EINVAL;
12853 goto fail;
12854 }
12855 }
12856
12857 /* Enable Probe Req filter */
12858 if (((dev_role == NL80211_IFTYPE_P2P_GO) ||
12859 (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) {
12860 wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12861 if (pbc)
12862 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12863 }
12864
12865 WL_DBG(("** ADD/SET beacon done **\n"));
12866 wl_set_drv_status(cfg, CONNECTED, dev);
12867
12868fail:
12869 if (err) {
12870 WL_ERR(("ADD/SET beacon failed\n"));
12871 if (dev_role == NL80211_IFTYPE_AP) {
12872#ifdef WL_EXT_IAPSTA
12873 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12874#endif /* WL_EXT_IAPSTA */
12875 /* clear the AP mode */
12876 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12877#ifdef WL_EXT_IAPSTA
12878 }
12879#endif /* WL_EXT_IAPSTA */
12880 }
12881 }
12882 return err;
12883
12884}
12885
12886static s32
12887wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
12888{
12889 int err = 0;
12890 s32 bssidx = 0;
12891 int infra = 0;
12892 struct wireless_dev *wdev = dev->ieee80211_ptr;
12893 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12894 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12895
12896 WL_DBG(("Enter. \n"));
12897
12898 if (!wdev) {
12899 WL_ERR(("wdev null \n"));
12900 return -EINVAL;
12901 }
12902
12903 if ((wdev->iftype != NL80211_IFTYPE_P2P_GO) && (wdev->iftype != NL80211_IFTYPE_AP)) {
12904 WL_ERR(("Unspported iface type iftype:%d \n", wdev->iftype));
12905 }
12906
12907 wl_clr_drv_status(cfg, AP_CREATING, dev);
12908 wl_clr_drv_status(cfg, AP_CREATED, dev);
12909
12910 /* Clear AP/GO connected status */
12911 wl_clr_drv_status(cfg, CONNECTED, dev);
12912
12913 cfg->ap_oper_channel = INVCHANSPEC;
12914
12915 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12916 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12917 return BCME_ERROR;
12918 }
12919
12920 /* Do bss down */
12921 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
12922 WL_ERR(("bss down error %d\n", err));
12923 }
12924
12925 /* fall through is intentional */
12926 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
12927 if (err < 0) {
12928 WL_ERR(("SET INFRA error %d\n", err));
12929 }
12930 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
12931
12932 if (wdev->iftype == NL80211_IFTYPE_AP) {
12933#ifdef WL_EXT_IAPSTA
12934 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12935#endif /* WL_EXT_IAPSTA */
12936 /* clear the AP mode */
12937 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12938#ifdef WL_EXT_IAPSTA
12939 }
12940#endif /* WL_EXT_IAPSTA */
12941 }
12942
12943 return 0;
12944}
12945#endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
12946
12947#ifdef WL_SUPPORT_ACS
12948/*
12949 * Currently the dump_obss IOVAR is returning string as output so we need to
12950 * parse the output buffer in an unoptimized way. Going forward if we get the
12951 * IOVAR output in binary format this method can be optimized
12952 */
12953static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
12954{
12955 int i;
12956 char *token;
12957 char delim[] = " \n";
12958
12959 token = strsep(&buf, delim);
12960 while (token != NULL) {
12961 if (!strcmp(token, "OBSS")) {
12962 for (i = 0; i < OBSS_TOKEN_IDX; i++)
12963 token = strsep(&buf, delim);
12964 survey->obss = simple_strtoul(token, NULL, 10);
12965 }
12966
12967 if (!strcmp(token, "IBSS")) {
12968 for (i = 0; i < IBSS_TOKEN_IDX; i++)
12969 token = strsep(&buf, delim);
12970 survey->ibss = simple_strtoul(token, NULL, 10);
12971 }
12972
12973 if (!strcmp(token, "TXDur")) {
12974 for (i = 0; i < TX_TOKEN_IDX; i++)
12975 token = strsep(&buf, delim);
12976 survey->tx = simple_strtoul(token, NULL, 10);
12977 }
12978
12979 if (!strcmp(token, "Category")) {
12980 for (i = 0; i < CTG_TOKEN_IDX; i++)
12981 token = strsep(&buf, delim);
12982 survey->no_ctg = simple_strtoul(token, NULL, 10);
12983 }
12984
12985 if (!strcmp(token, "Packet")) {
12986 for (i = 0; i < PKT_TOKEN_IDX; i++)
12987 token = strsep(&buf, delim);
12988 survey->no_pckt = simple_strtoul(token, NULL, 10);
12989 }
12990
12991 if (!strcmp(token, "Opp(time):")) {
12992 for (i = 0; i < IDLE_TOKEN_IDX; i++)
12993 token = strsep(&buf, delim);
12994 survey->idle = simple_strtoul(token, NULL, 10);
12995 }
12996
12997 token = strsep(&buf, delim);
12998 }
12999
13000 return 0;
13001}
13002
13003static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
13004 struct wl_dump_survey *survey)
13005{
13006 cca_stats_n_flags *results;
13007 char *buf;
13008 int retry, err;
13009 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13010
13011 buf = (char *)MALLOCZ(cfg->osh, sizeof(char) * WLC_IOCTL_MAXLEN);
13012 if (unlikely(!buf)) {
13013 WL_ERR(("%s: buf alloc failed\n", __func__));
13014 return -ENOMEM;
13015 }
13016
13017 retry = IOCTL_RETRY_COUNT;
13018 while (retry--) {
13019 err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req),
13020 buf, WLC_IOCTL_MAXLEN, NULL);
13021 if (err >= 0) {
13022 break;
13023 }
13024 WL_DBG(("attempt = %d, err = %d, \n",
13025 (IOCTL_RETRY_COUNT - retry), err));
13026 }
13027
13028 if (retry <= 0) {
13029 WL_ERR(("failure, dump_obss IOVAR failed\n"));
13030 err = -EINVAL;
13031 goto exit;
13032 }
13033
13034 results = (cca_stats_n_flags *)(buf);
13035 wl_parse_dump_obss(results->buf, survey);
13036 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
13037
13038 return 0;
13039exit:
13040 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
13041 return err;
13042}
13043
13044static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
13045 int idx, struct survey_info *info)
13046{
13047 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
13048 struct wl_dump_survey *survey;
13049 struct ieee80211_supported_band *band;
13050 struct ieee80211_channel*chan;
13051 cca_msrmnt_query req;
13052 int val, err, noise, retry;
13053
13054 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
13055 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
13056 return -ENOENT;
13057 }
13058 band = wiphy->bands[IEEE80211_BAND_2GHZ];
13059 if (band && idx >= band->n_channels) {
13060 idx -= band->n_channels;
13061 band = NULL;
13062 }
13063
13064 if (!band || idx >= band->n_channels) {
13065 /* Move to 5G band */
13066 band = wiphy->bands[IEEE80211_BAND_5GHZ];
13067 if (idx >= band->n_channels) {
13068 return -ENOENT;
13069 }
13070 }
13071
13072 chan = &band->channels[idx];
13073 /* Setting current channel to the requested channel */
13074 if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan,
13075 NL80211_CHAN_HT20) < 0)) {
13076 /*
13077 * FIXME:
13078 *
13079 * Mostly set channel should not fail. because we are
13080 * traversing through Valid channel list. In case it fails,
13081 * right now we are passing the stats for previous channel.
13082 */
13083 WL_ERR(("Set channel failed \n"));
13084 }
13085
13086 if (!idx) {
13087 /* Set interface up, explicitly. */
13088 val = 1;
13089 err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
13090 if (err < 0) {
13091 WL_ERR(("set interface up failed, error = %d\n", err));
13092 }
13093 }
13094
13095 /* Get noise value */
13096 retry = IOCTL_RETRY_COUNT;
13097 while (retry--) {
13098 noise = 0;
13099 err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise,
13100 sizeof(noise));
13101 if (err >= 0) {
13102 break;
13103 }
13104 WL_DBG(("attempt = %d, err = %d, \n",
13105 (IOCTL_RETRY_COUNT - retry), err));
13106 }
13107
13108 if (retry <= 0) {
13109 WL_ERR(("Get Phy Noise failed, error = %d\n", err));
13110 noise = CHAN_NOISE_DUMMY;
13111 }
13112
13113 survey = (struct wl_dump_survey *)MALLOCZ(cfg->osh,
13114 sizeof(struct wl_dump_survey));
13115 if (unlikely(!survey)) {
13116 WL_ERR(("%s: alloc failed\n", __func__));
13117 return -ENOMEM;
13118 }
13119
13120 /* Start Measurement for obss stats on current channel */
13121 req.msrmnt_query = 0;
13122 req.time_req = ACS_MSRMNT_DELAY;
13123 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
13124 goto exit;
13125 }
13126
13127 /*
13128 * Wait for the meaurement to complete, adding a buffer value of 10 to take
13129 * into consideration any delay in IOVAR completion
13130 */
13131 msleep(ACS_MSRMNT_DELAY + 10);
13132
13133 /* Issue IOVAR to collect measurement results */
13134 req.msrmnt_query = 1;
13135 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
13136 goto exit;
13137 }
13138
13139 info->channel = chan;
13140 info->noise = noise;
13141 info->channel_time = ACS_MSRMNT_DELAY;
13142 info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
13143 info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg +
13144 survey->no_pckt;
13145 info->channel_time_tx = survey->tx;
13146 info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
13147 SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
13148 SURVEY_INFO_CHANNEL_TIME_TX;
13149 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
13150
13151 return 0;
13152exit:
13153 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
13154 return err;
13155}
13156#endif /* WL_SUPPORT_ACS */
13157
13158static struct cfg80211_ops wl_cfg80211_ops = {
13159 .add_virtual_intf = wl_cfg80211_add_virtual_iface,
13160 .del_virtual_intf = wl_cfg80211_del_virtual_iface,
13161 .change_virtual_intf = wl_cfg80211_change_virtual_iface,
13162#if defined(WL_CFG80211_P2P_DEV_IF)
13163 .start_p2p_device = wl_cfgp2p_start_p2p_device,
13164 .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
13165#endif /* WL_CFG80211_P2P_DEV_IF */
13166 .scan = wl_cfg80211_scan,
13167#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
13168 .abort_scan = wl_cfg80211_abort_scan,
13169#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
13170 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
13171 .join_ibss = wl_cfg80211_join_ibss,
13172 .leave_ibss = wl_cfg80211_leave_ibss,
13173 .get_station = wl_cfg80211_get_station,
13174 .dump_station = wl_cfg80211_dump_station,
13175 .set_tx_power = wl_cfg80211_set_tx_power,
13176 .get_tx_power = wl_cfg80211_get_tx_power,
13177 .add_key = wl_cfg80211_add_key,
13178 .del_key = wl_cfg80211_del_key,
13179 .get_key = wl_cfg80211_get_key,
13180 .set_default_key = wl_cfg80211_config_default_key,
13181 .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
13182 .set_power_mgmt = wl_cfg80211_set_power_mgmt,
13183 .connect = wl_cfg80211_connect,
13184 .disconnect = wl_cfg80211_disconnect,
13185 .set_pmksa = wl_cfg80211_set_pmksa,
13186 .del_pmksa = wl_cfg80211_del_pmksa,
13187 .flush_pmksa = wl_cfg80211_flush_pmksa,
13188 .remain_on_channel = wl_cfgscan_remain_on_channel,
13189 .cancel_remain_on_channel = wl_cfgscan_cancel_remain_on_channel,
13190 .mgmt_tx = wl_cfg80211_mgmt_tx,
13191 .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
13192 .change_bss = wl_cfg80211_change_bss,
13193#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS)
13194 .set_channel = wl_cfg80211_set_channel,
13195#endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
13196#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS)
13197 .set_beacon = wl_cfg80211_add_set_beacon,
13198 .add_beacon = wl_cfg80211_add_set_beacon,
13199 .del_beacon = wl_cfg80211_del_beacon,
13200#else
13201 .change_beacon = wl_cfg80211_change_beacon,
13202 .start_ap = wl_cfg80211_start_ap,
13203 .stop_ap = wl_cfg80211_stop_ap,
13204#endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
13205#ifdef WL_SCHED_SCAN
13206 .sched_scan_start = wl_cfg80211_sched_scan_start,
13207 .sched_scan_stop = wl_cfg80211_sched_scan_stop,
13208#endif /* WL_SCHED_SCAN */
13209#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
13210 2, 0))
13211 .del_station = wl_cfg80211_del_station,
13212 .change_station = wl_cfg80211_change_station,
13213 .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
13214#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
13215#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
13216 .tdls_mgmt = wl_cfg80211_tdls_mgmt,
13217 .tdls_oper = wl_cfg80211_tdls_oper,
13218#endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
13219#ifdef WL_SUPPORT_ACS
13220 .dump_survey = wl_cfg80211_dump_survey,
13221#endif /* WL_SUPPORT_ACS */
13222#ifdef WL_CFG80211_ACL
13223 .set_mac_acl = wl_cfg80211_set_mac_acl,
13224#endif /* WL_CFG80211_ACL */
13225#ifdef GTK_OFFLOAD_SUPPORT
13226#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
13227 .set_rekey_data = wl_cfg80211_set_rekey_data,
13228#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
13229#endif /* GTK_OFFLOAD_SUPPORT */
13230#if defined(WL_FILS)
13231 /* This should be enabled from kernel version which supports this */
13232 .update_connect_params = wl_cfg80211_update_connect_params,
13233#endif /* WL_FILS */
13234#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
13235 .set_pmk = wl_cfg80211_set_pmk,
13236 .del_pmk = wl_cfg80211_del_pmk,
13237#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
13238#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
13239 .channel_switch = wl_cfg80211_channel_switch,
13240#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
13241#ifdef WL_CLIENT_SAE
13242 .external_auth = wl_cfg80211_external_auth,
13243#endif /* WL_CLIENT_SAE */
13244};
13245
13246s32 wl_mode_to_nl80211_iftype(s32 mode)
13247{
13248 s32 err = 0;
13249
13250 switch (mode) {
13251 case WL_MODE_BSS:
13252 return NL80211_IFTYPE_STATION;
13253 case WL_MODE_IBSS:
13254 return NL80211_IFTYPE_ADHOC;
13255 case WL_MODE_AP:
13256 return NL80211_IFTYPE_AP;
13257#ifdef WLMESH_CFG80211
13258 case WL_MODE_MESH:
13259 return NL80211_IFTYPE_MESH_POINT;
13260#endif /* WLMESH_CFG80211 */
13261 default:
13262 return NL80211_IFTYPE_UNSPECIFIED;
13263 }
13264
13265 return err;
13266}
13267
13268static bool
13269wl_is_ccode_change_required(struct net_device *net,
13270 char *country_code, int revinfo)
13271{
13272 s32 ret = BCME_OK;
13273 wl_country_t cspec = {{0}, 0, {0}};
13274 wl_country_t cur_cspec = {{0}, 0, {0}};
13275
13276 ret = wldev_iovar_getbuf(net, "country", NULL, 0, &cur_cspec,
13277 sizeof(cur_cspec), NULL);
13278 if (ret < 0) {
13279 WL_ERR(("get country code failed = %d\n", ret));
13280 return true;
13281 }
13282 /* If translation table is available, update cspec */
13283 cspec.rev = revinfo;
13284 strlcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
13285 strlcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
13286 dhd_get_customized_country_code(net, country_code, &cspec);
13287 if ((cur_cspec.rev == cspec.rev) &&
13288 (strncmp(cur_cspec.ccode, cspec.ccode, WLC_CNTRY_BUF_SZ) == 0) &&
13289 (strncmp(cur_cspec.country_abbrev, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) == 0)) {
13290 WL_INFORM_MEM(("country code = %s/%d is already configured\n",
13291 country_code, revinfo));
13292 return false;
13293 }
13294 return true;
13295}
13296
13297s32
13298wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
13299 bool notify, bool user_enforced, int revinfo)
13300{
13301 s32 ret = BCME_OK;
13302 struct wireless_dev *wdev = ndev_to_wdev(net);
13303 struct wiphy *wiphy = wdev->wiphy;
13304 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
13305 BCM_REFERENCE(cfg);
13306
13307 if (wl_is_ccode_change_required(net, country_code, revinfo) == false) {
13308 goto exit;
13309 }
13310#ifdef WL_NAN
13311 if (wl_cfgnan_is_enabled(cfg)) {
13312 mutex_lock(&cfg->if_sync);
13313 ret = wl_cfgnan_check_nan_disable_pending(cfg, true, true);
13314 mutex_unlock(&cfg->if_sync);
13315 if (ret != BCME_OK) {
13316 WL_ERR(("failed to disable nan, error[%d]\n", ret));
13317 goto exit;
13318 }
13319 }
13320#endif /* WL_NAN */
13321 ret = wldev_set_country(net, country_code,
13322 notify, user_enforced, revinfo);
13323 if (ret < 0) {
13324 WL_ERR(("set country Failed :%d\n", ret));
13325 goto exit;
13326 }
13327
13328 /* send up the hint so that upper layer apps
13329 * can refresh the channel
13330 * list
13331 */
13332 if (!IS_REGDOM_SELF_MANAGED(wiphy)) {
13333 regulatory_hint(wiphy, country_code);
13334 }
13335
13336exit:
13337 return ret;
13338}
13339
13340#ifdef CONFIG_CFG80211_INTERNAL_REGDB
13341#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
13342#define WL_CFG80211_REG_NOTIFIER() static int wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
13343#else
13344#define WL_CFG80211_REG_NOTIFIER() static void wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
13345#endif /* kernel version < 3.9.0 */
13346#endif
13347
13348#ifdef CONFIG_CFG80211_INTERNAL_REGDB
13349WL_CFG80211_REG_NOTIFIER()
13350{
13351 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
13352 int ret = 0;
13353 int revinfo = -1;
13354
13355 if (!request || !cfg) {
13356 WL_ERR(("Invalid arg\n"));
13357#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
13358 return -EINVAL;
13359#else
13360 return;
13361#endif /* kernel version < 3.10.11 */
13362 }
13363
13364 WL_DBG(("ccode: %c%c Initiator: %d\n",
13365 request->alpha2[0], request->alpha2[1], request->initiator));
13366
13367 /* We support only REGDOM_SET_BY_USER as of now */
13368 if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
13369 (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
13370 WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
13371 request->initiator));
13372 /* in case of no supported country by regdb
13373 lets driver setup platform default Locale
13374 */
13375 }
13376
13377 WL_ERR(("Set country code %c%c from %s\n",
13378 request->alpha2[0], request->alpha2[1],
13379 ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User")));
13380
13381 if ((ret = wldev_set_country(bcmcfg_to_prmry_ndev(cfg), request->alpha2,
13382 false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false),
13383 revinfo)) < 0) {
13384 WL_ERR(("set country Failed :%d\n", ret));
13385 }
13386
13387#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
13388 return ret;
13389#else
13390 return;
13391#endif /* kernel version < 3.10.11 */
13392}
13393#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
13394
13395#ifdef CONFIG_PM
13396#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
13397static const struct wiphy_wowlan_support brcm_wowlan_support = {
13398 .flags = WIPHY_WOWLAN_ANY,
13399 .n_patterns = WL_WOWLAN_MAX_PATTERNS,
13400 .pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
13401 .pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
13402#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
13403 .max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
13404#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
13405};
13406#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
13407#endif /* CONFIG_PM */
13408
13409int wl_features_set(u8 *array, uint8 len, u32 ftidx)
13410{
13411 u8* ft_byte;
13412
13413 if ((ftidx / 8u) >= len)
13414 return BCME_BADARG;
13415
13416 ft_byte = &array[ftidx / 8u];
13417 *ft_byte |= BIT(ftidx % 8u);
13418 return BCME_OK;
13419}
13420
13421static
13422void wl_config_custom_regulatory(struct wiphy *wiphy)
13423{
13424
13425#if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
13426 /* Use self managed regulatory domain */
13427 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED |
13428 REGULATORY_IGNORE_STALE_KICKOFF;
13429 wiphy->regd = &brcm_regdom;
13430 WL_DBG(("Self managed regdom\n"));
13431 return;
13432#else /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
13433
13434#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
13435 wiphy->regulatory_flags |=
13436#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13437 REGULATORY_IGNORE_STALE_KICKOFF |
13438#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
13439 REGULATORY_CUSTOM_REG;
13440#else /* KERNEL VER >= 3.14 */
13441 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
13442#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
13443 wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
13444 WL_DBG(("apply custom regulatory\n"));
13445#endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
13446}
13447
13448static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, dhd_pub_t *context)
13449{
13450 s32 err = 0;
13451#ifdef CONFIG_PM
13452#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13453 struct cfg80211_wowlan *brcm_wowlan_config = NULL;
13454#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13455#endif /* CONFIG_PM */
13456
13457//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
13458 dhd_pub_t *dhd = (dhd_pub_t *)context;
13459 BCM_REFERENCE(dhd);
13460
13461 if (!dhd) {
13462 WL_ERR(("DHD is NULL!!"));
13463 err = -ENODEV;
13464 return err;
13465 }
13466//#endif // endif
13467
13468 wdev->wiphy =
13469 wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
13470 if (unlikely(!wdev->wiphy)) {
13471 WL_ERR(("Couldn not allocate wiphy device\n"));
13472 err = -ENOMEM;
13473 return err;
13474 }
13475 set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
13476 wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
13477 /* Report how many SSIDs Driver can support per Scan request */
13478 wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
13479 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
13480#ifdef WL_SCHED_SCAN
13481 wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
13482 wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
13483 wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
13484#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
13485 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
13486#else
13487 wdev->wiphy->max_sched_scan_reqs = 1;
13488#endif /* LINUX_VER < 4.12 */
13489#endif /* WL_SCHED_SCAN */
13490#ifdef WLMESH_CFG80211
13491 wdev->wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
13492#endif /* WLMESH_CFG80211 */
13493 wdev->wiphy->interface_modes =
13494 BIT(NL80211_IFTYPE_STATION)
13495 | BIT(NL80211_IFTYPE_ADHOC)
13496#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
13497 /*
13498 * This monitor mode support creates an issue in registering
13499 * Action frame for P2P-GO, this was leading an error in receiving
13500 * action frames to GO interface.Keeping the code here because
13501 * monitor mode code has kept as it is in other modules,
13502 * though we are not supporting this mode.
13503 */
13504 | BIT(NL80211_IFTYPE_MONITOR)
13505#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
13506#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
13507 | BIT(NL80211_IFTYPE_P2P_CLIENT)
13508 | BIT(NL80211_IFTYPE_P2P_GO)
13509#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
13510#if defined(WL_CFG80211_P2P_DEV_IF)
13511 | BIT(NL80211_IFTYPE_P2P_DEVICE)
13512#endif /* WL_CFG80211_P2P_DEV_IF */
13513#ifdef WLMESH_CFG80211
13514 | BIT(NL80211_IFTYPE_MESH_POINT)
13515#endif /* WLMESH_CFG80211 */
13516 | BIT(NL80211_IFTYPE_AP);
13517
13518#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
13519 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
13520 WL_DBG(("Setting interface combinations for common mode\n"));
13521 wdev->wiphy->iface_combinations = common_iface_combinations;
13522 wdev->wiphy->n_iface_combinations =
13523 ARRAY_SIZE(common_iface_combinations);
13524#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
13525
13526 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
13527
13528 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
13529 wdev->wiphy->cipher_suites = __wl_cipher_suites;
13530 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
13531 wdev->wiphy->max_remain_on_channel_duration = 5000;
13532 wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
13533#ifndef WL_POWERSAVE_DISABLED
13534 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
13535#else
13536 wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
13537#endif /* !WL_POWERSAVE_DISABLED */
13538 wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
13539 WIPHY_FLAG_4ADDR_AP |
13540#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS)
13541 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
13542#endif
13543 WIPHY_FLAG_4ADDR_STATION;
13544#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
13545 /*
13546 * If FW ROAM flag is advertised, upper layer doesn't provide the
13547 * bssid & freq in the connect command. However, kernel ver >= 3.15,
13548 * provides bssid_hint & freq_hint which can be used by the firmware.
13549 * fw_ap_select variable determines whether FW selects the AP or the
13550 * user space selects the target AP within the given ESS.
13551 */
13552 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
13553#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13554#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
13555 /* this flag should be added to support wpa_supplicant 1.0+ */
13556 wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
13557 WIPHY_FLAG_OFFCHAN_TX;
13558#endif
13559#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
13560 4, 0))
13561 /* From 3.4 kernel ownards AP_SME flag can be advertised
13562 * to remove the patch from supplicant
13563 */
13564 wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
13565
13566#ifdef WL_CFG80211_ACL
13567 /* Configure ACL capabilities. */
13568 wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
13569#endif
13570
13571#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
13572 /* Supplicant distinguish between the SoftAP mode and other
13573 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
13574 * response frame from Supplicant MR1 and Kernel 3.4.0 or
13575 * later version. To add Vendor specific IE into the
13576 * probe response frame in case of SoftAP mode,
13577 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
13578 */
13579 if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
13580 wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
13581 wdev->wiphy->probe_resp_offload = 0;
13582 }
13583#endif
13584#endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
13585
13586#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
13587 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
13588#endif
13589
13590#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13591 /*
13592 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
13593 * disconnection of connected network before suspend. So a dummy wowlan
13594 * filter is configured for kernels linux-3.8 and above.
13595 */
13596
13597#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13598 wdev->wiphy->wowlan = &brcm_wowlan_support;
13599 /* If this is not provided cfg stack will get disconnect
13600 * during suspend.
13601 * Note: wiphy->wowlan_config is freed by cfg80211 layer.
13602 * so use malloc instead of MALLOC(osh) to avoid false alarm.
13603 */
13604 brcm_wowlan_config = kmalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL);
13605 if (brcm_wowlan_config) {
13606 brcm_wowlan_config->disconnect = true;
13607 brcm_wowlan_config->gtk_rekey_failure = true;
13608 brcm_wowlan_config->eap_identity_req = true;
13609 brcm_wowlan_config->four_way_handshake = true;
13610 brcm_wowlan_config->patterns = NULL;
13611 brcm_wowlan_config->n_patterns = 0;
13612 brcm_wowlan_config->tcp = NULL;
13613#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13614 brcm_wowlan_config->nd_config = NULL;
13615#endif
13616 } else {
13617 WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
13618 " So wiphy->wowlan_config is set to NULL\n"));
13619 }
13620 wdev->wiphy->wowlan_config = brcm_wowlan_config;
13621#else
13622 wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
13623 wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
13624 wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
13625 wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
13626#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
13627 wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
13628#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
13629#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13630#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13631
13632 WL_DBG(("Registering custom regulatory)\n"));
13633 wl_config_custom_regulatory(wdev->wiphy);
13634
13635#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13636 WL_INFORM_MEM(("Registering Vendor80211\n"));
13637 err = wl_cfgvendor_attach(wdev->wiphy, dhd);
13638 if (unlikely(err < 0)) {
13639 WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
13640 }
13641#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
13642#ifdef WL_FILS
13643 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
13644#endif /* WL_FILS */
13645
13646#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
13647 wdev->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
13648 wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS;
13649#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */
13650
13651 /* Now we can register wiphy with cfg80211 module */
13652 err = wiphy_register(wdev->wiphy);
13653 if (unlikely(err < 0)) {
13654 WL_ERR(("Couldn not register wiphy device (%d)\n", err));
13655 wiphy_free(wdev->wiphy);
13656 }
13657
13658#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
13659 KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
13660 /* Workaround for a cfg80211 bug */
13661 wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
13662#endif
13663
13664#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \
13665 defined(SUPPORT_RANDOM_MAC_SCAN)
13666 wdev->wiphy->features |= (NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
13667 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR);
13668 wdev->wiphy->max_sched_scan_plans = 1; /* multiple plans not supported */
13669#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) */
13670
13671#if defined(WL_SAE) || defined(WL_CLIENT_SAE)
13672 wdev->wiphy->features |= NL80211_FEATURE_SAE;
13673#endif /* WL_SAE || WL_CLIENT_SAE */
13674#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE)
13675 if (FW_SUPPORTED(dhd, idsup)) {
13676 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
13677 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
13678 }
13679#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) && defined(BCMSUP_4WAY_HANDSHAKE) */
13680#ifdef WL_SCAN_TYPE
13681 /* These scan types will be mapped to default scan on non-supported chipset */
13682 /* Advertise scan type capability. */
13683 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_SPAN_SCAN);
13684 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_POWER_SCAN);
13685 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
13686 wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN;
13687#endif /* WL_SCAN_TYPE */
13688
13689 return err;
13690}
13691
13692static void wl_free_wdev(struct bcm_cfg80211 *cfg)
13693{
13694 struct wireless_dev *wdev = cfg->wdev;
13695 struct wiphy *wiphy = NULL;
13696 if (!wdev) {
13697 WL_ERR(("wdev is invalid\n"));
13698 return;
13699 }
13700 if (wdev->wiphy) {
13701 wiphy = wdev->wiphy;
13702
13703#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13704 wl_cfgvendor_detach(wdev->wiphy);
13705#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
13706#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13707#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13708 /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
13709 WL_DBG(("clear wowlan\n"));
13710 wdev->wiphy->wowlan = NULL;
13711#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13712#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13713#if defined(WL_SELF_MANAGED_REGDOM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
13714 /* Making regd ptr NULL, to avoid reference/freeing by regulatory unregister */
13715 wiphy->regd = NULL;
13716#endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
13717 wiphy_unregister(wdev->wiphy);
13718 wdev->wiphy->dev.parent = NULL;
13719 wdev->wiphy = NULL;
13720 }
13721
13722 wl_delete_all_netinfo(cfg);
13723 if (wiphy) {
13724 if (wdev->netdev)
13725 wdev->netdev->ieee80211_ptr = NULL;
13726 wdev->netdev = NULL;
13727 MFREE(cfg->osh, wdev, sizeof(*wdev));
13728 cfg->wdev = NULL;
13729 wiphy_free(wiphy);
13730 }
13731
13732 /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
13733 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
13734 */
13735}
13736
13737static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev)
13738{
13739 u32 event = ntoh32(e->event_type);
13740 u32 status = ntoh32(e->status);
13741 u16 flags = ntoh16(e->flags);
13742#if defined(CUSTOM_SET_OCLOFF) || defined(CUSTOM_SET_ANTNPM)
13743 dhd_pub_t *dhd;
13744 dhd = (dhd_pub_t *)(cfg->pub);
13745#endif /* CUSTOM_SET_OCLOFF || CUSTOM_SET_ANTNPM */
13746
13747 WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
13748 if (event == WLC_E_SET_SSID) {
13749 if (status == WLC_E_STATUS_SUCCESS) {
13750#ifdef CUSTOM_SET_OCLOFF
13751 if (dhd->ocl_off) {
13752 int err = 0;
13753 int ocl_enable = 0;
13754 err = wldev_iovar_setint(ndev, "ocl_enable", ocl_enable);
13755 if (err != 0) {
13756 WL_ERR(("[WIFI_SEC] wl_is_linkup: Set ocl_enable %d"
13757 " failed %d\n",
13758 ocl_enable, err));
13759 } else {
13760 WL_ERR(("[WIFI_SEC] wl_is_linkup: Set ocl_enable %d"
13761 " succeeded %d\n",
13762 ocl_enable, err));
13763 }
13764 }
13765#endif /* CUSTOM_SET_OCLOFF */
13766#ifdef CUSTOM_SET_ANTNPM
13767 if (dhd->mimo_ant_set) {
13768 int err = 0;
13769
13770 WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhd->mimo_ant_set));
13771 err = wldev_iovar_setint(ndev, "txchain", dhd->mimo_ant_set);
13772 if (err != 0) {
13773 WL_ERR(("[WIFI_SEC] Fail set txchain\n"));
13774 }
13775 err = wldev_iovar_setint(ndev, "rxchain", dhd->mimo_ant_set);
13776 if (err != 0) {
13777 WL_ERR(("[WIFI_SEC] Fail set rxchain\n"));
13778 }
13779 }
13780#endif /* CUSTOM_SET_ANTNPM */
13781 if (!wl_is_ibssmode(cfg, ndev))
13782 return true;
13783 }
13784 } else if (event == WLC_E_LINK) {
13785 if (flags & WLC_EVENT_MSG_LINK)
13786 return true;
13787 }
13788
13789 WL_DBG(("wl_is_linkup false\n"));
13790 return false;
13791}
13792
13793static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13794{
13795 u32 event = ntoh32(e->event_type);
13796 u16 flags = ntoh16(e->flags);
13797
13798 if (event == WLC_E_DEAUTH_IND ||
13799 event == WLC_E_DISASSOC_IND ||
13800 event == WLC_E_DISASSOC ||
13801 event == WLC_E_DEAUTH) {
13802 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
13803 return true;
13804 } else if (event == WLC_E_LINK) {
13805 if (!(flags & WLC_EVENT_MSG_LINK)) {
13806 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
13807 return true;
13808 }
13809 }
13810
13811 return false;
13812}
13813
13814static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13815{
13816 u32 event = ntoh32(e->event_type);
13817 u32 status = ntoh32(e->status);
13818
13819 if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS)
13820 return true;
13821 if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
13822 return true;
13823 if (event == WLC_E_ASSOC_RESP_IE && status != WLC_E_STATUS_SUCCESS)
13824 return true;
13825
13826 return false;
13827}
13828
13829#ifdef WL_SAE
13830static s32
13831wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13832 wl_sae_key_info_t *sae_key)
13833{
13834 struct sk_buff *skb;
13835 gfp_t kflags;
13836 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13837 int err = BCME_OK;
13838 struct cfg80211_pmksa pmksa;
13839
13840 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
13841#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
13842 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
13843 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), BRCM_SAE_VENDOR_EVENT_BUF_LEN,
13844 BRCM_VENDOR_EVENT_SAE_KEY, kflags);
13845#else
13846 skb = cfg80211_vendor_event_alloc(wiphy, BRCM_SAE_VENDOR_EVENT_BUF_LEN,
13847 BRCM_VENDOR_EVENT_SAE_KEY, kflags);
13848#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
13849 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
13850 if (!skb) {
13851 WL_ERR(("skb alloc failed"));
13852 err = BCME_NOMEM;
13853 goto done;
13854 }
13855
13856 WL_INFORM_MEM(("Received Sae Key event for "MACDBG" key length %x %x",
13857 MAC2STRDBG(sae_key->peer_mac), sae_key->pmk_len, sae_key->pmkid_len));
13858 nla_put(skb, BRCM_SAE_KEY_ATTR_PEER_MAC, ETHER_ADDR_LEN, sae_key->peer_mac);
13859 nla_put(skb, BRCM_SAE_KEY_ATTR_PMK, sae_key->pmk_len, sae_key->pmk);
13860 nla_put(skb, BRCM_SAE_KEY_ATTR_PMKID, sae_key->pmkid_len, sae_key->pmkid);
13861 cfg80211_vendor_event(skb, kflags);
13862 /* wpa_supplicant will manage the PMK and PMKID from here on..
13863 * Delete the PMK cache in firmware, if wlc_ver equals to MIN_PMKID_LIST_V3_FW_MAJOR
13864 * else ignore.
13865 * MIN_PMKID_LIST_V3_FW_MAJOR has two IOVAR's(pmklist_info and PMKDB).
13866 */
13867 if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V3_FW_MAJOR) {
13868 WL_INFORM_MEM(("Deleting the SAE PMK cache Info from firmware \n"));
13869 memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
13870 pmksa.bssid = sae_key->peer_mac;
13871 pmksa.pmkid = sae_key->pmkid;
13872 err = wl_cfg80211_update_pmksa(wiphy, ndev, &pmksa, FALSE);
13873 if (err != BCME_OK) {
13874 WL_ERR(("Failed to delete the SAE PMK cache Info from firmware %d\n", err));
13875 }
13876 }
13877done:
13878 return err;
13879}
13880
13881static s32
13882wl_bss_handle_sae_auth_v1(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13883 const wl_event_msg_t *event, void *data)
13884{
13885 int err = BCME_OK;
13886 wl_auth_event_t *auth_data;
13887 wl_sae_key_info_t sae_key;
13888 uint16 tlv_buf_len;
13889 auth_data = (wl_auth_event_t *)data;
13890
13891 tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V1;
13892
13893 /* check if PMK info present */
13894 sae_key.pmk = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13895 WL_AUTH_PMK_TLV_ID, &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
13896 if (!sae_key.pmk || !sae_key.pmk_len) {
13897 WL_ERR(("Mandatory PMK info not present"));
13898 err = BCME_NOTFOUND;
13899 goto done;
13900 }
13901 /* check if PMKID info present */
13902 sae_key.pmkid = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13903 WL_AUTH_PMKID_TLV_ID, &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
13904 if (!sae_key.pmkid || !sae_key.pmkid_len) {
13905 WL_ERR(("Mandatory PMKID info not present\n"));
13906 err = BCME_NOTFOUND;
13907 goto done;
13908 }
13909 memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet, ETHER_ADDR_LEN);
13910 err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
13911 if (err) {
13912 WL_ERR(("Failed to event sae key info\n"));
13913 }
13914done:
13915 return err;
13916}
13917
13918static s32
13919wl_bss_handle_sae_auth_v2(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13920 const wl_event_msg_t *event, void *data)
13921{
13922 int err = BCME_OK;
13923 wl_auth_event_t *auth_data;
13924 wl_sae_key_info_t sae_key;
13925 uint16 tlv_buf_len;
13926 uint8 ssid[DOT11_MAX_SSID_LEN];
13927 const uint8 *tmp_buf;
13928 uint16 ssid_len;
13929 uint16 type_len;
13930 uint32 type;
13931 pmkid_v3_t *t_pmkid = NULL;
13932
13933 auth_data = (wl_auth_event_t *)data;
13934
13935 tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V2;
13936
13937 /* check if PMK info present */
13938 sae_key.pmk = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13939 WL_AUTH_PMK_TLV_ID, &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
13940 if (!sae_key.pmk || !sae_key.pmk_len) {
13941 WL_ERR(("Mandatory PMK info not present"));
13942 err = BCME_NOTFOUND;
13943 goto done;
13944 }
13945 /* check if PMKID info present */
13946 sae_key.pmkid = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13947 WL_AUTH_PMKID_TLV_ID, &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
13948 if (!sae_key.pmkid || !sae_key.pmkid_len) {
13949 WL_ERR(("Mandatory PMKID info not present\n"));
13950 err = BCME_NOTFOUND;
13951 goto done;
13952 }
13953 memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet, ETHER_ADDR_LEN);
13954
13955 tmp_buf = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13956 WL_AUTH_PMKID_TYPE_TLV_ID, &type_len, BCM_XTLV_OPTION_ALIGN32);
13957
13958 memcpy(&type, tmp_buf, MIN(type_len, sizeof(type)));
13959 if (type == WL_AUTH_PMKID_TYPE_SSID) {
13960 int idx;
13961 int idx2;
13962 pmkid_list_v3_t *spmk_list = &cfg->spmk_info_list->pmkids;
13963
13964 tmp_buf = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13965 WL_AUTH_SSID_TLV_ID, &ssid_len, BCM_XTLV_OPTION_ALIGN32);
13966 if (tmp_buf == NULL) {
13967 return BCME_ERROR;
13968 }
13969 bzero(ssid, sizeof(ssid));
13970 (void)memcpy_s(ssid, sizeof(ssid), tmp_buf, MIN(sizeof(ssid), ssid_len));
13971 for (idx = 0; idx < spmk_list->count; idx++) {
13972 t_pmkid = &spmk_list->pmkid[idx];
13973 if (ssid_len == t_pmkid->ssid_len &&
13974 !memcmp(ssid, t_pmkid->ssid, MIN(sizeof(ssid), ssid_len))) {
13975 break;
13976 }
13977 }
13978 if (idx >= spmk_list->count) {
13979 if (spmk_list->count == MAXPMKID) {
13980 /* remove oldest PMK info */
13981 for (idx2 = 0; idx2 < spmk_list->count - 1; idx2++) {
13982 (void)memcpy_s(&spmk_list->pmkid[idx2], sizeof(pmkid_v3_t),
13983 &spmk_list->pmkid[idx2 + 1], sizeof(pmkid_v3_t));
13984 }
13985 t_pmkid = &spmk_list->pmkid[spmk_list->count - 1];
13986 } else {
13987 t_pmkid = &spmk_list->pmkid[spmk_list->count++];
13988 }
13989 }
13990 if (!t_pmkid) {
13991 WL_ERR(("SPMK TPMKID is null\n"));
13992 return BCME_NOTFOUND;
13993 }
13994 bzero(t_pmkid, sizeof(pmkid_v3_t));
13995 memcpy(&t_pmkid->bssid, event->addr.octet, 6);
13996 t_pmkid->ssid_len = ssid_len;
13997 err = memcpy_s(t_pmkid->ssid, sizeof(t_pmkid->ssid), ssid, ssid_len);
13998 if (err != BCME_OK) {
13999 goto done;
14000 }
14001 /* COPY but not used */
14002 t_pmkid->pmkid_len = sae_key.pmkid_len;
14003 memcpy(t_pmkid->pmkid, sae_key.pmkid, sae_key.pmkid_len);
14004 t_pmkid->pmk_len = sae_key.pmk_len;
14005 memcpy(t_pmkid->pmk, sae_key.pmk, sae_key.pmk_len);
14006 }
14007
14008 err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
14009 if (err) {
14010 WL_ERR(("Failed to event sae key info\n"));
14011 }
14012done:
14013 return err;
14014}
14015
14016static s32
14017wl_bss_handle_sae_auth(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14018 const wl_event_msg_t *event, void *data)
14019{
14020 int err = BCME_OK;
14021 uint status = ntoh32(event->status);
14022 wl_auth_event_t *auth_data;
14023
14024 if (status == WLC_E_STATUS_SUCCESS) {
14025 auth_data = (wl_auth_event_t *)data;
14026 if (auth_data->version == WL_AUTH_EVENT_DATA_V1) {
14027 err = wl_bss_handle_sae_auth_v1(cfg, ndev, event, data);
14028 } else if (auth_data->version == WL_AUTH_EVENT_DATA_V2) {
14029 err = wl_bss_handle_sae_auth_v2(cfg, ndev, event, data);
14030 } else {
14031 printf("unknown auth event data version %x\n",
14032 auth_data->version);
14033 err = BCME_VERSION;
14034 }
14035 } else {
14036 printf("sae auth status failure:%d\n", status);
14037 }
14038 printf("SAE AUTH result: %d\n", err);
14039 return err;
14040}
14041#endif /* WL_SAE */
14042
14043static s32
14044wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14045 const wl_event_msg_t *e, void *data)
14046{
14047 u32 reason = ntoh32(e->reason);
14048 u32 event = ntoh32(e->event_type);
14049#ifdef WL_SAE
14050 uint auth_type = ntoh32(e->auth_type);
14051#endif /* WL_SAE */
14052 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14053 WL_DBG(("event type : %d, reason : %d\n", event, reason));
14054
14055#if defined(DHD_ENABLE_BIGDATA_LOGGING)
14056 (void)memcpy_s(&cfg->event_auth_assoc, sizeof(wl_event_msg_t),
14057 e, sizeof(wl_event_msg_t));
14058 WL_ERR(("event=%d status %d reason %d \n",
14059 ntoh32(cfg->event_auth_assoc.event_type),
14060 ntoh32(cfg->event_auth_assoc.status),
14061 ntoh32(cfg->event_auth_assoc.reason)));
14062#endif /* DHD_ENABLE_BIGDATA_LOGGING */
14063 if (sec) {
14064 switch (event) {
14065 case WLC_E_ASSOC:
14066 case WLC_E_AUTH:
14067 case WLC_E_AUTH_IND:
14068 sec->auth_assoc_res_status = reason;
14069#ifdef WL_SAE
14070 if ((event == WLC_E_AUTH || event == WLC_E_AUTH_IND) &&
14071 auth_type == DOT11_SAE) {
14072 wl_bss_handle_sae_auth(cfg, ndev, e, data);
14073 }
14074#endif /* WL_SAE */
14075 break;
14076 default:
14077 break;
14078 }
14079 } else {
14080 WL_ERR(("sec is NULL\n"));
14081 }
14082 return 0;
14083}
14084
14085#ifdef WL_CLIENT_SAE
14086static s32
14087wl_notify_connect_status_ap_auth(struct bcm_cfg80211 *cfg,
14088 struct net_device *ndev, const wl_event_msg_t *e, void *data)
14089{
14090 bcm_struct_cfgdev *cfgdev = ndev_to_cfgdev(ndev);
14091 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14092 u8 bsscfgidx = e->bsscfgidx;
14093 u8 *mgmt_frame = NULL;
14094 u8 *body = NULL;
14095 u32 body_len = 0;
14096 s32 chan;
14097 u16 channel;
14098 struct ieee80211_supported_band *band;
14099 chanspec_t chanspec;
14100 s32 freq;
14101 struct ether_addr da;
14102 struct ether_addr bssid;
14103 u32 event = ntoh32(e->event_type);
14104 u32 reason = ntoh32(e->reason);
14105 u32 len = ntoh32(e->datalen);
14106 s32 err = 0;
14107
14108 if (!len) {
14109 WL_ERR(("event %s(%d) has no payload. status %d reason %d\n",
14110 bcmevent_get_name(event), event, ntoh32(e->status), reason));
14111 return 0;
14112 }
14113
14114 body = (u8 *)MALLOCZ(cfg->osh, len);
14115 if (body == NULL) {
14116 WL_ERR(("Failed to allocate body\n"));
14117 return WL_INVALID;
14118 }
14119 (void)memcpy_s(body, len, data, len);
14120
14121 err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
14122 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
14123 if (unlikely(err)) {
14124 WL_ERR(("Could not get cur_etheraddr %d\n", err));
14125 goto exit;
14126 }
14127 (void)memcpy_s(da.octet, ETHER_ADDR_LEN, cfg->ioctl_buf, ETHER_ADDR_LEN);
14128
14129 bzero(&bssid, sizeof(bssid));
14130 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14131 if (unlikely(err)) {
14132 WL_ERR(("Could not get bssid %d\n", err));
14133 goto exit;
14134 }
14135
14136 err = wldev_iovar_getint(ndev, "chanspec", &chan);
14137 if (unlikely(err)) {
14138 WL_ERR(("Could not get chanspec %d\n", err));
14139 goto exit;
14140 }
14141 chanspec = wl_chspec_driver_to_host(chan);
14142 channel = wf_chspec_ctlchan(chanspec);
14143
14144 if (channel <= CH_MAX_2G_CHANNEL)
14145 band = wiphy->bands[IEEE80211_BAND_2GHZ];
14146 else
14147 band = wiphy->bands[IEEE80211_BAND_5GHZ];
14148 if (!band) {
14149 WL_ERR(("No valid band\n"));
14150 goto exit;
14151 }
14152
14153#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
14154 freq = ieee80211_channel_to_frequency(channel);
14155#else
14156 freq = ieee80211_channel_to_frequency(channel, band->band);
14157#endif
14158
14159 body_len = len;
14160 err = wl_frame_get_mgmt(cfg, FC_AUTH, &da, &e->addr, &bssid,
14161 &mgmt_frame, &len, body);
14162 if (!err) {
14163#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14164 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0);
14165#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14166 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14167#else
14168 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14169#endif
14170 MFREE(cfg->osh, mgmt_frame, len);
14171 }
14172
14173exit:
14174 if (body) {
14175 MFREE(cfg->osh, body, body_len);
14176 }
14177
14178 return err;
14179}
14180#endif /* WL_CLIENT_SAE */
14181
14182
14183/* The mainline kernel >= 3.2.0 has support for indicating new/del station
14184 * to AP/P2P GO via events. If this change is backported to kernel for which
14185 * this driver is being built, then define WL_CFG80211_STA_EVENT. You
14186 * should use this new/del sta event mechanism for BRCM supplicant >= 22.
14187 */
14188static s32
14189wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14190 const wl_event_msg_t *e, void *data)
14191{
14192 s32 err = 0;
14193 u32 event = ntoh32(e->event_type);
14194 u32 reason = ntoh32(e->reason);
14195 u32 len = ntoh32(e->datalen);
14196 u32 status = ntoh32(e->status);
14197
14198#if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14199 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14200 bool isfree = false;
14201 u8 *mgmt_frame;
14202 u8 bsscfgidx = e->bsscfgidx;
14203 s32 freq;
14204 u8 *body = NULL;
14205 u16 fc = 0;
14206 u32 body_len = 0;
14207 chanspec_t chanspec;
14208 struct ieee80211_supported_band *band;
14209 struct ether_addr da;
14210 struct ether_addr bssid;
14211 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14212 u8 ioctl_buf[WLC_IOCTL_SMLEN];
14213#else
14214 struct station_info sinfo;
14215#endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14216
14217#ifdef BIGDATA_SOFTAP
14218 dhd_pub_t *dhdp;
14219#endif /* BIGDATA_SOFTAP */
14220
14221 WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n",
14222 ndev->name, event, ntoh32(e->status), reason));
14223
14224 if (event == WLC_E_AUTH_IND) {
14225 wl_get_auth_assoc_status(cfg, ndev, e, data);
14226 return 0;
14227 }
14228 /* if link down, bsscfg is disabled. */
14229 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
14230 wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
14231 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
14232 WL_MSG(ndev->name, "AP mode link down !! \n");
14233 complete(&cfg->iface_disable);
14234 return 0;
14235 }
14236
14237 if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
14238 (reason == WLC_E_REASON_INITIAL_ASSOC) &&
14239 (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
14240 if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
14241 /* AP/GO brought up successfull in firmware */
14242 WL_MSG(ndev->name, "AP/GO Link up\n");
14243 wl_set_drv_status(cfg, AP_CREATED, ndev);
14244 OSL_SMP_WMB();
14245 wake_up_interruptible(&cfg->netif_change_event);
14246
14247#ifdef BIGDATA_SOFTAP
14248 wl_ap_stainfo_init(cfg);
14249#endif /* BIGDATA_SOFTAP */
14250
14251#ifdef WL_BCNRECV
14252 /* check fakeapscan is in progress, if progress then abort */
14253 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
14254#endif /* WL_BCNRECV */
14255 wl_cfg80211_check_in4way(cfg, ndev, 0, WL_EXT_STATUS_AP_ENABLED, NULL);
14256 return 0;
14257 }
14258 }
14259
14260 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
14261 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14262 "event %s(%d) status %d reason %d\n",
14263 bcmevent_get_name(event), event, ntoh32(e->status), reason);
14264 }
14265
14266#ifdef BIGDATA_SOFTAP
14267 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) {
14268 WL_ERR(("AP link down - skip get sta data\n"));
14269 } else {
14270 dhdp = (dhd_pub_t *)(cfg->pub);
14271 if (dhdp && dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
14272 dhd_schedule_gather_ap_stadata(cfg, ndev, e);
14273 }
14274 }
14275#endif /* BIGDATA_SOFTAP */
14276
14277#if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14278 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14279 WL_DBG(("Enter \n"));
14280 if (!len && (event == WLC_E_DEAUTH)) {
14281 len = 2; /* reason code field */
14282 data = &reason;
14283 }
14284 if (len) {
14285 body = (u8 *)MALLOCZ(cfg->osh, len);
14286 if (body == NULL) {
14287 WL_ERR(("Failed to allocate body\n"));
14288 return WL_INVALID;
14289 }
14290 }
14291 bzero(&bssid, ETHER_ADDR_LEN);
14292 WL_DBG(("Enter event %d ndev %p\n", event, ndev));
14293 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14294 MFREE(cfg->osh, body, len);
14295 return WL_INVALID;
14296 }
14297 if (len)
14298 memcpy(body, data, len);
14299
14300 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
14301 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, NULL);
14302 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
14303 bzero(&bssid, sizeof(bssid));
14304 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14305 switch (event) {
14306 case WLC_E_ASSOC_IND:
14307 fc = FC_ASSOC_REQ;
14308 break;
14309 case WLC_E_REASSOC_IND:
14310 fc = FC_REASSOC_REQ;
14311 break;
14312 case WLC_E_DISASSOC_IND:
14313 fc = FC_DISASSOC;
14314 break;
14315 case WLC_E_DEAUTH_IND:
14316 fc = FC_DISASSOC;
14317 break;
14318 case WLC_E_DEAUTH:
14319 fc = FC_DISASSOC;
14320 break;
14321 default:
14322 fc = 0;
14323 goto exit;
14324 }
14325 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
14326 if (unlikely(err)) {
14327 MFREE(cfg->osh, body, len);
14328 WL_ERR(("%s: Could not get chanspec %d\n", __FUNCTION__, err));
14329 return err;
14330 }
14331 chanspec = wl_chspec_driver_to_host(chanspec);
14332 freq = wl_channel_to_frequency(wf_chspec_ctlchan(chanspec), CHSPEC_BAND(chanspec));
14333 body_len = len;
14334 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
14335 &mgmt_frame, &len, body);
14336 if (err < 0)
14337 goto exit;
14338 isfree = true;
14339
14340 if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
14341 (event == WLC_E_DISASSOC_IND) ||
14342 ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
14343#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14344 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
14345#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14346 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14347#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14348 defined(WL_COMPAT_WIRELESS)
14349 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14350#else
14351 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14352#endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
14353 }
14354
14355exit:
14356 if (isfree) {
14357 MFREE(cfg->osh, mgmt_frame, len);
14358 }
14359 if (body) {
14360 MFREE(cfg->osh, body, body_len);
14361 }
14362#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14363 memset_s(&sinfo, sizeof(sinfo), 0, sizeof(sinfo));
14364 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
14365 reason == DOT11_SC_SUCCESS) {
14366 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
14367 * STATION_INFO_ASSOC_REQ_IES flag
14368 */
14369#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
14370 sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
14371#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
14372 if (!data) {
14373 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
14374 return -EINVAL;
14375 }
14376 sinfo.assoc_req_ies = data;
14377 sinfo.assoc_req_ies_len = len;
14378 WL_MSG(ndev->name, "new sta event for "MACDBG "\n",
14379 MAC2STRDBG(e->addr.octet));
14380 wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
14381 WL_EXT_STATUS_STA_CONNECTED, NULL);
14382 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
14383#ifdef WL_WPS_SYNC
14384 wl_wps_session_update(ndev, WPS_STATE_LINKUP, e->addr.octet);
14385#endif /* WL_WPS_SYNC */
14386 } else if ((event == WLC_E_DEAUTH_IND) ||
14387 ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
14388 (event == WLC_E_DISASSOC_IND)) {
14389 /*
14390 * WAR: Dongle sends WLC_E_DEAUTH event with DOT11_RC_RESERVED
14391 * to delete flowring in case of PCIE Full dongle.
14392 * By deleting flowring on SoftAP interface we can avoid any issues
14393 * due to stale/bad state of flowring.
14394 * Therefore, we don't need to notify the client dissaociation to Hostapd
14395 * in this case.
14396 * Please refer to the RB:115182 to understand the case more clearly.
14397 */
14398 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14399 "del sta event for "MACDBG "\n", MAC2STRDBG(e->addr.octet));
14400 wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
14401 WL_EXT_STATUS_STA_DISCONNECTED, NULL);
14402 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
14403#ifdef WL_WPS_SYNC
14404 wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet);
14405#endif /* WL_WPS_SYNC */
14406 }
14407#ifdef WL_CLIENT_SAE
14408 else if (event == WLC_E_AUTH) {
14409 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14410 "add sta auth event for "MACDBG "\n", MAC2STRDBG(e->addr.octet));
14411 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14412 WL_ERR(("invalid mode\n"));
14413 return WL_INVALID;
14414 }
14415 err = wl_notify_connect_status_ap_auth(cfg, ndev, e, data);
14416 }
14417#endif /* WL_CLIENT_SAE */
14418#endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14419 return err;
14420}
14421
14422#if defined(DHD_ENABLE_BIGDATA_LOGGING)
14423enum {
14424 BIGDATA_ASSOC_REJECT_NO_ACK = 1,
14425 BIGDATA_ASSOC_REJECT_FAIL = 2,
14426 BIGDATA_ASSOC_REJECT_UNSOLICITED = 3,
14427 BIGDATA_ASSOC_REJECT_TIMEOUT = 4,
14428 BIGDATA_ASSOC_REJECT_ABORT = 5,
14429 BIGDATA_ASSOC_REJECT_NO_NETWWORKS = 6,
14430 BIGDATA_ASSOC_REJECT_MAX = 50
14431};
14432
14433int wl_get_connect_failed_status(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
14434{
14435 u32 status = ntoh32(e->status);
14436
14437 cfg->assoc_reject_status = 0;
14438
14439 if (status != WLC_E_STATUS_SUCCESS) {
14440 WL_ERR(("auth assoc status event=%d e->status %d e->reason %d \n",
14441 ntoh32(cfg->event_auth_assoc.event_type),
14442 (int)ntoh32(cfg->event_auth_assoc.status),
14443 (int)ntoh32(cfg->event_auth_assoc.reason)));
14444
14445 switch ((int)ntoh32(cfg->event_auth_assoc.status)) {
14446 case WLC_E_STATUS_NO_ACK:
14447 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_NO_ACK;
14448 break;
14449 case WLC_E_STATUS_FAIL:
14450 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_FAIL;
14451 break;
14452 case WLC_E_STATUS_UNSOLICITED:
14453 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_UNSOLICITED;
14454 break;
14455 case WLC_E_STATUS_TIMEOUT:
14456 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_TIMEOUT;
14457 break;
14458 case WLC_E_STATUS_ABORT:
14459 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_ABORT;
14460 break;
14461 case WLC_E_STATUS_SUCCESS:
14462 if (status == WLC_E_STATUS_NO_NETWORKS) {
14463 cfg->assoc_reject_status =
14464 BIGDATA_ASSOC_REJECT_NO_NETWWORKS;
14465 break;
14466 }
14467 default:
14468 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_MAX;
14469 break;
14470 }
14471 if (cfg->assoc_reject_status) {
14472 if (ntoh32(cfg->event_auth_assoc.event_type) == WLC_E_ASSOC) {
14473 cfg->assoc_reject_status += BIGDATA_ASSOC_REJECT_MAX;
14474 }
14475 }
14476 }
14477
14478 WL_ERR(("assoc_reject_status %d \n", cfg->assoc_reject_status));
14479
14480 return 0;
14481}
14482
14483s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len)
14484{
14485 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
14486 int bytes_written = 0;
14487
14488 if (cfg == NULL) {
14489 return -1;
14490 }
14491 bytes_written = snprintf(cmd, total_len, "assoc_reject.status %d",
14492 cfg->assoc_reject_status);
14493 WL_ERR(("cmd: %s \n", cmd));
14494 return bytes_written;
14495}
14496#endif /* DHD_ENABLE_BIGDATA_LOGGING */
14497
14498#ifdef WL_CLIENT_SAE
14499static s32
14500wl_notify_start_auth(struct bcm_cfg80211 *cfg,
14501 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
14502{
14503 struct cfg80211_external_auth_params ext_auth_param;
14504 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14505 u32 datalen = be32_to_cpu(e->datalen);
14506 wl_ext_auth_evt_t *evt_data = (wl_ext_auth_evt_t *)data;
14507 wl_assoc_mgr_cmd_t cmd;
14508 int err;
14509
14510 WL_DBG(("Enter\n"));
14511
14512 if (!datalen || !data)
14513 return BCME_ERROR;
14514
14515 ext_auth_param.ssid.ssid_len = MIN(evt_data->ssid.SSID_len, DOT11_MAX_SSID_LEN);
14516 if (ext_auth_param.ssid.ssid_len)
14517 memcpy(&ext_auth_param.ssid.ssid, evt_data->ssid.SSID,
14518 ext_auth_param.ssid.ssid_len);
14519
14520 memcpy(&ext_auth_param.bssid, &evt_data->bssid, ETHER_ADDR_LEN);
14521 ext_auth_param.action = NL80211_EXTERNAL_AUTH_START;
14522 ext_auth_param.key_mgmt_suite = ntoh32(WLAN_AKM_SUITE_SAE_SHA256);
14523
14524 WL_MSG(ndev->name, "BSSID: "MACDBG"\n", MAC2STRDBG(&evt_data->bssid));
14525
14526 err = cfg80211_external_auth_request(ndev, &ext_auth_param, GFP_KERNEL);
14527 if (unlikely(err)) {
14528 WL_ERR(("Failed to notify external auth req(%d)\n", err));
14529 }
14530
14531 cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
14532 cmd.length = sizeof(cmd);
14533 cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
14534 cmd.params = WL_ASSOC_MGR_PARAMS_PAUSE_EVENT_AUTH_RESP;
14535 err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd),
14536 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
14537 if (unlikely(err)) {
14538 WL_ERR(("Failed to pause assoc(%d)\n", err));
14539 }
14540
14541 return BCME_OK;
14542}
14543
14544static s32
14545wl_notify_connect_status_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14546 const wl_event_msg_t *e, void *data)
14547{
14548 s32 err = 0;
14549 u32 event = ntoh32(e->event_type);
14550 u32 reason = ntoh32(e->reason);
14551 u32 len = ntoh32(e->datalen);
14552 u32 status = ntoh32(e->status);
14553
14554 bool isfree = false;
14555 u8 *mgmt_frame;
14556 u8 bsscfgidx = e->bsscfgidx;
14557 s32 freq;
14558 s32 channel;
14559 u8 *body = NULL;
14560 u16 fc = 0, rssi = 0;
14561 bcm_struct_cfgdev *cfgdev = ndev_to_cfgdev(ndev);
14562
14563 struct ieee80211_supported_band *band;
14564 struct ether_addr da;
14565 struct ether_addr bssid;
14566 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14567 channel_info_t ci;
14568
14569 WL_DBG(("event %d status %d reason %d\n", event, status, reason));
14570
14571 if (event == WLC_E_AUTH) {
14572 struct wl_security *sec;
14573 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14574
14575 if (!(sec->auth_type == NL80211_AUTHTYPE_SAE)) {
14576 WL_DBG(("Abort AUTH processing due to NOT SAE\n"));
14577 return 0;
14578 } else {
14579 if (status != WLC_E_STATUS_SUCCESS && !len) {
14580 WL_ERR(("SAE AUTH FAIL EVENT\n"));
14581 wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY|WAIT_DISCONNECTED,
14582 WL_EXT_STATUS_DISCONNECTED, NULL);
14583 return 0;
14584 }
14585 }
14586 }
14587
14588 if (!len && (event == WLC_E_DEAUTH)) {
14589 len = 2; /* reason code field */
14590 data = &reason;
14591 }
14592
14593 if (len) {
14594 body = kzalloc(len, GFP_KERNEL);
14595 if (body == NULL) {
14596 WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
14597 return WL_INVALID;
14598 }
14599 }
14600
14601 memset(&bssid, 0, ETHER_ADDR_LEN);
14602 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14603 kfree(body);
14604 return WL_INVALID;
14605 }
14606 if (len)
14607 memcpy(body, data, len);
14608
14609 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
14610 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
14611 memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
14612 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14613 /* Use e->addr as bssid for Sta case , before association completed */
14614 if (err == BCME_NOTASSOCIATED)
14615 memcpy(&bssid, &e->addr, ETHER_ADDR_LEN);
14616
14617 switch (event) {
14618 case WLC_E_ASSOC_IND:
14619 fc = FC_ASSOC_REQ;
14620 break;
14621 case WLC_E_REASSOC_IND:
14622 fc = FC_REASSOC_REQ;
14623 break;
14624 case WLC_E_DISASSOC_IND:
14625 fc = FC_DISASSOC;
14626 break;
14627 case WLC_E_DEAUTH_IND:
14628 fc = FC_DISASSOC;
14629 break;
14630 case WLC_E_DEAUTH:
14631 fc = FC_DISASSOC;
14632 break;
14633 case WLC_E_AUTH:
14634 fc = FC_AUTH;
14635 break;
14636 default:
14637 fc = 0;
14638 goto exit;
14639 }
14640 if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
14641 kfree(body);
14642 return err;
14643 }
14644
14645 channel = dtoh32(ci.hw_channel);
14646 if (channel <= CH_MAX_2G_CHANNEL)
14647 band = wiphy->bands[IEEE80211_BAND_2GHZ];
14648 else
14649 band = wiphy->bands[IEEE80211_BAND_5GHZ];
14650 if (!band) {
14651 WL_ERR(("No valid band\n"));
14652 if (body)
14653 kfree(body);
14654 return -EINVAL;
14655 }
14656#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
14657 freq = ieee80211_channel_to_frequency(channel);
14658 (void)band->band;
14659#else
14660 freq = ieee80211_channel_to_frequency(channel, band->band);
14661#endif
14662
14663 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
14664 &mgmt_frame, &len, body);
14665 if (err < 0) {
14666 goto exit;
14667 }
14668 isfree = true;
14669
14670 if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
14671#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14672 cfg80211_rx_mgmt(cfgdev, freq, rssi, mgmt_frame, len, 0);
14673#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14674 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14675#else
14676 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14677#endif
14678 } else if (event == WLC_E_DISASSOC_IND) {
14679#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14680 cfg80211_rx_mgmt(cfgdev, freq, rssi, mgmt_frame, len, 0);
14681#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14682 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14683#else
14684 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14685#endif
14686 } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
14687#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14688 cfg80211_rx_mgmt(cfgdev, freq, rssi, mgmt_frame, len, 0);
14689#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14690 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14691#else
14692 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14693#endif
14694 } else if (event == WLC_E_AUTH) {
14695#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14696 cfg80211_rx_mgmt(cfgdev, freq, rssi, mgmt_frame, len, 0);
14697#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14698 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14699#else
14700 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14701#endif
14702 }
14703exit:
14704 if (isfree)
14705 kfree(mgmt_frame);
14706 if (body)
14707 kfree(body);
14708 return err;
14709}
14710#endif /* WL_CLIENT_SAE */
14711
14712static s32
14713wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14714 const wl_event_msg_t *e, void *data)
14715{
14716 s32 err = 0;
14717 u32 event = ntoh32(e->event_type);
14718 u16 flags = ntoh16(e->flags);
14719 u32 status = ntoh32(e->status);
14720 bool active;
14721#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14722 struct ieee80211_channel *channel = NULL;
14723 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14724 chanspec_t chanspec;
14725 u32 freq;
14726#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14727
14728 if (event == WLC_E_JOIN) {
14729 WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev->name));
14730 }
14731 if (event == WLC_E_START) {
14732 WL_INFORM_MEM(("[%s] started IBSS network\n", ndev->name));
14733 }
14734 if (event == WLC_E_JOIN || event == WLC_E_START ||
14735 (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
14736#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14737 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
14738 if (unlikely(err)) {
14739 WL_ERR(("Could not get chanspec %d\n", err));
14740 return err;
14741 }
14742 chanspec = wl_chspec_driver_to_host(chanspec);
14743 freq = wl_channel_to_frequency(wf_chspec_ctlchan(chanspec), CHSPEC_BAND(chanspec));
14744 channel = ieee80211_get_channel(wiphy, freq);
14745#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14746 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
14747 /* ROAM or Redundant */
14748 u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14749 if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
14750 WL_DBG(("IBSS connected event from same BSSID("
14751 MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
14752 return err;
14753 }
14754 WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
14755 ndev->name, MAC2STRDBG(cur_bssid),
14756 MAC2STRDBG((const u8 *)&e->addr)));
14757 wl_get_assoc_ies(cfg, ndev);
14758 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14759 wl_update_bss_info(cfg, ndev, false);
14760#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14761 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
14762#else
14763 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
14764#endif
14765 }
14766 else {
14767 /* New connection */
14768 WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG "\n",
14769 ndev->name, MAC2STRDBG((const u8 *)&e->addr)));
14770 wl_link_up(cfg);
14771 wl_get_assoc_ies(cfg, ndev);
14772 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14773 wl_update_bss_info(cfg, ndev, false);
14774#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14775 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
14776#else
14777 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
14778#endif
14779 wl_set_drv_status(cfg, CONNECTED, ndev);
14780 active = true;
14781 wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
14782 }
14783 } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
14784 event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
14785 wl_clr_drv_status(cfg, CONNECTED, ndev);
14786 wl_link_down(cfg);
14787 wl_init_prof(cfg, ndev);
14788 }
14789 else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
14790 WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
14791 }
14792 else {
14793 WL_DBG(("no action (IBSS mode)\n"));
14794}
14795 return err;
14796}
14797
14798#if defined(DHD_ENABLE_BIGDATA_LOGGING)
14799#define WiFiALL_OUI "\x50\x6F\x9A" /* Wi-FiAll OUI */
14800#define WiFiALL_OUI_LEN 3
14801#define WiFiALL_OUI_TYPE 16
14802
14803/* 11kv feature flag for big data */
14804#define WL_BIGDATA_11KV_QBSSLOAD 0x00000001
14805#define WL_BIGDATA_11KV_PROXYARP 0x00000002
14806#define WL_BIGDATA_11KV_TFS 0x00000004
14807#define WL_BIGDATA_11KV_SLEEP 0x00000008
14808#define WL_BIGDATA_11KV_TIMBC 0x00000010
14809#define WL_BIGDATA_11KV_BSSTRANS 0x00000020
14810#define WL_BIGDATA_11KV_DMS 0x00000040
14811#define WL_BIGDATA_11KV_LINK_MEA 0x00000080
14812#define WL_BIGDATA_11KV_NBRREP 0x00000100
14813#define WL_BIGDATA_11KV_BCNPASSIVE 0x00000200
14814#define WL_BIGDATA_11KV_BCNACTIVE 0x00000400
14815#define WL_BIGDATA_11KV_BCNTABLE 0x00000800
14816#define WL_BIGDATA_11KV_BSSAAD 0x00001000
14817#define WL_BIGDATA_11KV_MAX 0x00002000
14818
14819#define WL_BIGDATA_SUPPORT_11K 0x00000001
14820#define WL_BIGDATA_SUPPORT_11V 0x00000002
14821
14822typedef struct {
14823 uint8 bitmap;
14824 uint8 octet_len;
14825 uint32 flag;
14826} bigdata_11kv_t;
14827
14828bigdata_11kv_t bigdata_11k_info[] = {
14829 {DOT11_RRM_CAP_LINK, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_LINK_MEA},
14830 {DOT11_RRM_CAP_NEIGHBOR_REPORT, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_NBRREP},
14831 {DOT11_RRM_CAP_BCN_PASSIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNPASSIVE},
14832 {DOT11_RRM_CAP_BCN_ACTIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNACTIVE},
14833 {DOT11_RRM_CAP_BCN_TABLE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNTABLE},
14834 {DOT11_RRM_CAP_BSSAAD, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BSSAAD},
14835};
14836
14837bigdata_11kv_t bigdata_11v_info[] = {
14838 {DOT11_EXT_CAP_PROXY_ARP, DOT11_EXTCAP_LEN_PROXY_ARP, WL_BIGDATA_11KV_PROXYARP},
14839 {DOT11_EXT_CAP_TFS, DOT11_EXTCAP_LEN_TFS, WL_BIGDATA_11KV_TFS},
14840 {DOT11_EXT_CAP_WNM_SLEEP, DOT11_EXTCAP_LEN_WNM_SLEEP, WL_BIGDATA_11KV_SLEEP},
14841 {DOT11_EXT_CAP_TIMBC, DOT11_EXTCAP_LEN_TIMBC, WL_BIGDATA_11KV_TIMBC},
14842 {DOT11_EXT_CAP_BSSTRANS_MGMT, DOT11_EXTCAP_LEN_BSSTRANS, WL_BIGDATA_11KV_BSSTRANS},
14843 {DOT11_EXT_CAP_DMS, DOT11_EXTCAP_LEN_DMS, WL_BIGDATA_11KV_DMS}
14844};
14845
14846static void
14847wl_get_11kv_info(u8 *ie, u32 ie_len, uint8 *support_11kv, uint32 *flag_11kv)
14848{
14849 bcm_tlv_t *ie_11kv = NULL;
14850 uint32 flag_11k = 0, flag_11v = 0;
14851 int i;
14852
14853 /* parsing QBSS load ie */
14854 if ((bcm_parse_tlvs(ie, (u32)ie_len,
14855 DOT11_MNG_QBSS_LOAD_ID)) != NULL) {
14856 flag_11k |= WL_BIGDATA_11KV_QBSSLOAD;
14857 }
14858
14859 /* parsing RM IE for 11k */
14860 if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
14861 DOT11_MNG_RRM_CAP_ID)) != NULL) {
14862 for (i = 0; i < ARRAYSIZE(bigdata_11k_info); i++) {
14863 if ((ie_11kv->len >= bigdata_11k_info[i].octet_len) &&
14864 isset(ie_11kv->data, bigdata_11k_info[i].bitmap)) {
14865 flag_11k |= bigdata_11k_info[i].flag;
14866 }
14867 }
14868 }
14869
14870 /* parsing extended cap. IE for 11v */
14871 if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
14872 DOT11_MNG_EXT_CAP_ID)) != NULL) {
14873 for (i = 0; i < ARRAYSIZE(bigdata_11v_info); i++) {
14874 if ((ie_11kv->len >= bigdata_11v_info[i].octet_len) &&
14875 isset(ie_11kv->data, bigdata_11v_info[i].bitmap)) {
14876 flag_11v |= bigdata_11v_info[i].flag;
14877 }
14878 }
14879 }
14880
14881 if (flag_11k > 0) {
14882 *support_11kv |= WL_BIGDATA_SUPPORT_11K;
14883 }
14884
14885 if (flag_11v > 0) {
14886 *support_11kv |= WL_BIGDATA_SUPPORT_11V;
14887 }
14888
14889 *flag_11kv = flag_11k | flag_11v;
14890}
14891
14892int wl_get_bss_info(struct bcm_cfg80211 *cfg, struct net_device *dev, struct ether_addr const *mac)
14893{
14894 s32 err = 0;
14895 wl_bss_info_v109_1_t *bi;
14896 uint8 eabuf[ETHER_ADDR_LEN];
14897 u32 rate, channel, freq, supported_rate, nss = 0, mcs_map, mode_80211 = 0;
14898 char rate_str[4];
14899 u8 *ie = NULL;
14900 u32 ie_len;
14901 struct wiphy *wiphy;
14902 struct cfg80211_bss *bss;
14903 bcm_tlv_t *interworking_ie = NULL;
14904 bcm_tlv_t *tlv_ie = NULL;
14905 bcm_tlv_t *vht_ie = NULL;
14906 vndr_ie_t *vndrie;
14907 int16 ie_11u_rel_num = -1, ie_mu_mimo_cap = -1;
14908 u32 i, remained_len, count = 0;
14909 char roam_count_str[4], akm_str[4];
14910 s32 val = 0;
14911 uint8 support_11kv = 0;
14912 uint32 flag_11kv = 0; /* bit flags of 11kv big data */
14913 int cfg_bss_info_len = 0;
14914
14915 /* get BSS information */
14916
14917 strlcpy(cfg->bss_info, "x x x x x x x x x x x x x x x x x", sizeof(cfg->bss_info));
14918
14919 *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
14920
14921 err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, cfg->extra_buf, WL_EXTRA_BUF_MAX);
14922 if (unlikely(err)) {
14923 WL_ERR(("Could not get bss info %d\n", err));
14924 cfg->roam_count = 0;
14925 return -1;
14926 }
14927
14928 if (!mac) {
14929 WL_ERR(("mac is null \n"));
14930 cfg->roam_count = 0;
14931 return -1;
14932 }
14933
14934 memcpy(eabuf, mac, ETHER_ADDR_LEN);
14935
14936 bi = (wl_bss_info_v109_1_t *)(cfg->extra_buf + 4);
14937 channel = wf_chspec_ctlchan(bi->chanspec);
14938 freq = wl_channel_to_frequency(channel, CHSPEC_BAND(bi->chanspec));
14939 rate = 0;
14940 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
14941 if (err) {
14942 WL_ERR(("Could not get rate (%d)\n", err));
14943 snprintf(rate_str, sizeof(rate_str), "x"); /* Unknown */
14944
14945 } else {
14946 rate = dtoh32(rate);
14947 snprintf(rate_str, sizeof(rate_str), "%d", (rate/2));
14948 }
14949
14950 /* supported maximum rate */
14951 supported_rate = (bi->rateset.rates[bi->rateset.count - 1] & 0x7f) / 2;
14952
14953 if (supported_rate < 12) {
14954 mode_80211 = BIGDATA_DOT11_11B_MODE; /* 11b maximum rate is 11Mbps. 11b mode */
14955 } else {
14956 /* It's not HT Capable case. */
14957 if (channel > 14) {
14958 mode_80211 = BIGDATA_DOT11_11A_MODE; /* 11a mode */
14959 } else {
14960 mode_80211 = BIGDATA_DOT11_11G_MODE; /* 11g mode */
14961 }
14962 }
14963
14964 if (bi->n_cap) {
14965 /* check Rx MCS Map for HT */
14966 nss = 0;
14967 mode_80211 = BIGDATA_DOT11_11N_MODE;
14968 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
14969 int8 bitmap = DOT11_HT_MCS_RATE_MASK;
14970 if (i == MAX_STREAMS_SUPPORTED-1) {
14971 bitmap = DOT11_RATE_MASK;
14972 }
14973 if (bi->basic_mcs[i] & bitmap) {
14974 nss++;
14975 }
14976 }
14977 }
14978
14979 if (bi->vht_cap) {
14980 nss = 0;
14981 mode_80211 = BIGDATA_DOT11_11AC_MODE;
14982 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
14983 mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
14984 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
14985 nss++;
14986 }
14987 }
14988 }
14989
14990#if defined(WL11AX)
14991 if (bi->he_cap) {
14992 nss = 0;
14993 mode_80211 = BIGDATA_DOT11_11AX_MODE;
14994 for (i = 1; i <= HE_MCS_MAP_NSS_MAX; i++) {
14995 mcs_map = HE_MCS_NSS_GET_MCS(i, dtoh32(bi->he_rxmcsmap));
14996 if (mcs_map != HE_MCS_CODE_NONE) {
14997 nss++;
14998 }
14999 }
15000 }
15001#endif /* WL11AX */
15002
15003 if (nss) {
15004 nss = nss - 1;
15005 }
15006
15007 wiphy = bcmcfg_to_wiphy(cfg);
15008 bss = CFG80211_GET_BSS(wiphy, NULL, eabuf, bi->SSID, bi->SSID_len);
15009 if (!bss) {
15010 WL_ERR(("Could not find the AP\n"));
15011 } else {
15012 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
15013#if defined(WL_CFG80211_P2P_DEV_IF)
15014 ie = (u8 *)bss->ies->data;
15015 ie_len = bss->ies->len;
15016#else
15017 ie = bss->information_elements;
15018 ie_len = bss->len_information_elements;
15019#endif /* WL_CFG80211_P2P_DEV_IF */
15020 GCC_DIAGNOSTIC_POP();
15021 }
15022
15023 if (ie) {
15024 ie_mu_mimo_cap = 0;
15025 ie_11u_rel_num = 0;
15026
15027 if (bi->vht_cap) {
15028 if ((vht_ie = bcm_parse_tlvs(ie, ie_len,
15029 DOT11_MNG_VHT_CAP_ID)) != NULL) {
15030 if (vht_ie->len >= VHT_CAP_IE_LEN) {
15031 ie_mu_mimo_cap = (vht_ie->data[2] & 0x08) >> 3;
15032 }
15033 }
15034 }
15035
15036 if ((interworking_ie = bcm_parse_tlvs(ie, ie_len,
15037 DOT11_MNG_INTERWORKING_ID)) != NULL) {
15038 if ((tlv_ie = bcm_parse_tlvs(ie, ie_len, DOT11_MNG_VS_ID)) != NULL) {
15039 remained_len = ie_len;
15040
15041 while (tlv_ie) {
15042 if (count > MAX_VNDR_IE_NUMBER)
15043 break;
15044
15045 if (tlv_ie->id == DOT11_MNG_VS_ID) {
15046 vndrie = (vndr_ie_t *) tlv_ie;
15047
15048 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
15049 WL_ERR(("wl_get_bss_info: invalid vndr ie."
15050 "length is too small %d\n",
15051 vndrie->len));
15052 break;
15053 }
15054
15055 if (!bcmp(vndrie->oui,
15056 (u8*)WiFiALL_OUI, WiFiALL_OUI_LEN) &&
15057 (vndrie->data[0] == WiFiALL_OUI_TYPE))
15058 {
15059 WL_ERR(("Found Wi-FiAll OUI oui.\n"));
15060 ie_11u_rel_num = vndrie->data[1];
15061 ie_11u_rel_num = (ie_11u_rel_num & 0xf0)>>4;
15062 ie_11u_rel_num += 1;
15063
15064 break;
15065 }
15066 }
15067 count++;
15068 tlv_ie = bcm_next_tlv(tlv_ie, &remained_len);
15069 }
15070 }
15071 }
15072
15073 /* get 11kv information from ie of current bss */
15074 wl_get_11kv_info(ie, ie_len, &support_11kv, &flag_11kv);
15075 }
15076
15077 for (i = 0; i < bi->SSID_len; i++) {
15078 if (bi->SSID[i] == ' ') {
15079 bi->SSID[i] = '_';
15080 }
15081 }
15082
15083 /* 0 : None, 1 : OKC, 2 : FT, 3 : CCKM */
15084 err = wldev_iovar_getint(dev, "wpa_auth", &val);
15085 if (unlikely(err)) {
15086 WL_ERR(("could not get wpa_auth (%d)\n", err));
15087 snprintf(akm_str, sizeof(akm_str), "x"); /* Unknown */
15088 } else {
15089 WL_ERR(("wpa_auth val %d \n", val));
15090 if (val & WPA2_AUTH_FT) {
15091 snprintf(akm_str, sizeof(akm_str), "2");
15092 } else if (val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) {
15093 snprintf(akm_str, sizeof(akm_str), "1");
15094 } else {
15095 snprintf(akm_str, sizeof(akm_str), "0");
15096 }
15097 }
15098
15099 if (cfg->roam_offload) {
15100 snprintf(roam_count_str, sizeof(roam_count_str), "x"); /* Unknown */
15101 } else {
15102 snprintf(roam_count_str, sizeof(roam_count_str), "%d", cfg->roam_count);
15103 }
15104 cfg->roam_count = 0;
15105
15106 WL_ERR(("BSSID:" MACDBG " SSID %s \n", MAC2STRDBG(eabuf), "*****"));
15107 WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d,"
15108 "MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n"
15109 "akm:%s, roam:%s, 11kv:%d/%d \n",
15110 freq, wf_chspec_to_bw_str(bi->chanspec),
15111 dtoh32(bi->RSSI), (rate / 2), mode_80211, nss,
15112 ie_mu_mimo_cap, ie_11u_rel_num, bi->SNR, bi->phy_noise,
15113 akm_str, roam_count_str, support_11kv, flag_11kv));
15114
15115 if (ie) {
15116 snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
15117 MACOUI" %d %s %d %s %d %d %d %d %d %d %s %s %d %d",
15118 MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
15119 dtoh32(bi->RSSI), rate_str, mode_80211, nss, ie_mu_mimo_cap,
15120 ie_11u_rel_num, bi->SNR, bi->phy_noise, akm_str, roam_count_str,
15121 support_11kv, flag_11kv);
15122 } else {
15123 /* ie_mu_mimo_cap and ie_11u_rel_num is unknow. */
15124 snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
15125 MACOUI" %d %s %d %s %d %d x x %d %d %s %s x x",
15126 MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
15127 dtoh32(bi->RSSI), rate_str, mode_80211, nss, bi->SNR,
15128 bi->phy_noise, akm_str, roam_count_str);
15129 }
15130
15131 cfg_bss_info_len = strlen(cfg->bss_info);
15132 if (GET_BSS_INFO_LEN > cfg_bss_info_len) {
15133 uint16 full_cnt = 0, partial_cnt = 0;
15134 bool cnt_valid = FALSE;
15135
15136#if defined(DHD_PUB_ROAM_EVT)
15137 wl_roam_stats_v1_t *roam_elem =
15138 (wl_roam_stats_v1_t *)dhd_get_roam_evt((dhd_pub_t *)cfg->pub);
15139
15140 if (roam_elem && roam_elem->version == WL_ROAM_STATS_VER_1) {
15141 wl_roam_stats_v1_t *roam_elem_v1;
15142 roam_elem_v1 = (wl_roam_stats_v1_t *)(uintptr_t)roam_elem;
15143
15144 cnt_valid = TRUE;
15145 full_cnt = roam_elem_v1->full_roam_scan_cnt;
15146 partial_cnt = roam_elem_v1->partial_roam_scan_cnt;
15147 }
15148#endif /* DHD_PUB_ROAM_EVT */
15149 if (cnt_valid) {
15150 WL_ERR(("GET_BSS: full roam scan count:%d partial roam scan count:%d\n",
15151 full_cnt, partial_cnt));
15152 snprintf(&cfg->bss_info[cfg_bss_info_len],
15153 GET_BSS_INFO_LEN - cfg_bss_info_len, " %d %d",
15154 full_cnt, partial_cnt);
15155 } else {
15156 WL_ERR(("GET_BSS: roam scan count invalid\n"));
15157 snprintf(&cfg->bss_info[cfg_bss_info_len],
15158 GET_BSS_INFO_LEN - cfg_bss_info_len, " x x");
15159 }
15160 } else {
15161 WL_ERR(("Buffer to short to save roam info\n"));
15162 }
15163
15164 CFG80211_PUT_BSS(wiphy, bss);
15165
15166 return 0;
15167}
15168
15169s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len)
15170{
15171 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
15172
15173 if (cfg == NULL) {
15174 return -1;
15175 }
15176
15177 if (total_len < GET_BSS_INFO_LEN) {
15178 WL_ERR(("wl_cfg80211_get_bss_info: Buffer insuffient %d\n", total_len));
15179 return -1;
15180 }
15181
15182 bzero(cmd, total_len);
15183 memcpy(cmd, cfg->bss_info, GET_BSS_INFO_LEN);
15184
15185 WL_ERR_KERN(("cmd: %s \n", cmd));
15186
15187 return GET_BSS_INFO_LEN;
15188}
15189#endif /* DHD_ENABLE_BIGDATA_LOGGING */
15190
15191void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason)
15192{
15193 scb_val_t scbval;
15194 s32 err;
15195 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
15196 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15197
15198 BCM_REFERENCE(cfg);
15199 BCM_REFERENCE(dhdp);
15200 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15201 dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
15202
15203 memset_s(&scbval, sizeof(scb_val_t), 0x0, sizeof(scb_val_t));
15204 scbval.val = htod32(reason);
15205 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
15206 if (err < 0) {
15207 WL_ERR(("WLC_DISASSOC error %d\n", err));
15208 } else {
15209 WL_INFORM_MEM(("wl disassoc. reason:%d\n", reason));
15210 }
15211}
15212void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason)
15213{
15214 struct net_device *dev;
15215 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
15216 scb_val_t scb_val;
15217 int err;
15218 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
15219 sizeof(struct ether_addr) + sizeof(uint)] = {0};
15220 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
15221 int num_associated = 0;
15222
15223 dev = ndev_to_wlc_ndev(ndev, cfg);
15224
15225 if (p2p_is_on(cfg)) {
15226 /* Suspend P2P discovery search-listen to prevent it from changing the
15227 * channel.
15228 */
15229 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
15230 WL_ERR(("Can not disable discovery mode\n"));
15231 return;
15232 }
15233 }
15234
15235 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
15236 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
15237 assoc_maclist, sizeof(mac_buf));
15238 if (err < 0)
15239 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
15240 else
15241 num_associated = assoc_maclist->count;
15242
15243 memset(scb_val.ea.octet, 0xff, ETHER_ADDR_LEN);
15244 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
15245 scb_val.val = htod32(reason);
15246 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
15247 sizeof(scb_val_t));
15248 if (err < 0) {
15249 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
15250 }
15251
15252 /* WAR Wait for the deauth event to come, supplicant will do the
15253 * delete iface immediately and we will have problem in sending
15254 * deauth frame if we delete the bss in firmware
15255 * But we do not need additional delays for this WAR
15256 * during P2P connection.
15257 *
15258 * Supplicant call this function with BCAST after doing
15259 * wl_cfg80211_del_station() all GC stations with each addr.
15260 * So, 400 ms delay can be called only once when GO disconnect all GC
15261 */
15262 if (num_associated > 0)
15263 wl_delay(400);
15264
15265 return;
15266}
15267/* API to handle the Deauth from the AP.
15268* For now we are deleting the PMKID cache in DHD/FW
15269* in case of current connection is using SAE authnetication
15270*/
15271static s32
15272wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15273 const wl_event_msg_t *e, void *data)
15274{
15275 int err = BCME_OK;
15276#ifdef WL_SAE
15277 uint8 bssid[ETHER_ADDR_LEN];
15278 struct cfg80211_pmksa pmksa;
15279 s32 val = 0;
15280 struct wlc_ssid *curssid;
15281 pmkid_list_v3_t *spmk_list = &cfg->spmk_info_list->pmkids;
15282 pmkid_v3_t *t_pmkid = NULL;
15283 int idx;
15284 bool bFound = FALSE;
15285
15286 err = wldev_iovar_getint(ndev, "wpa_auth", &val);
15287 if (unlikely(err)) {
15288 WL_ERR(("could not get wpa_auth (%d)\n", err));
15289 goto done;
15290 }
15291 if (val == WPA3_AUTH_SAE_PSK) {
15292 (void)memcpy_s(bssid, ETHER_ADDR_LEN,
15293 (const uint8*)&e->addr, ETHER_ADDR_LEN);
15294 memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
15295 pmksa.bssid = bssid;
15296 WL_INFORM_MEM(("Deleting the PMKSA for SAE AP "MACDBG,
15297 MAC2STRDBG(e->addr.octet)));
15298 wl_cfg80211_del_pmksa(cfg->wdev->wiphy, ndev, &pmksa);
15299 curssid = wl_read_prof(cfg, ndev, WL_PROF_SSID);
15300 for (idx = 0; idx < spmk_list->count; idx++) {
15301 t_pmkid = &spmk_list->pmkid[idx];
15302 if (curssid->SSID_len == t_pmkid->ssid_len &&
15303 !memcmp(curssid->SSID, t_pmkid->ssid, curssid->SSID_len)) {
15304 bFound = TRUE;
15305 break;
15306 }
15307 }
15308 if (!bFound) {
15309 goto done;
15310 }
15311 for (; idx < spmk_list->count - 1; idx++) {
15312 memcpy_s(&spmk_list->pmkid[idx], sizeof(pmkid_v3_t),
15313 &spmk_list->pmkid[idx + 1], sizeof(pmkid_v3_t));
15314 }
15315 spmk_list->count--;
15316 }
15317done:
15318#endif /* WL_SAE */
15319 return err;
15320}
15321
15322static void
15323wl_cache_assoc_resp_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15324 const wl_event_msg_t *e, void *data)
15325{
15326 struct wl_connect_info *conn_info = wl_to_conn(cfg);
15327 u32 datalen = ntoh32(e->datalen);
15328 u32 event_type = ntoh32(e->event_type);
15329
15330 if (data && datalen <= sizeof(conn_info->resp_ie)) {
15331 conn_info->resp_ie_len = datalen;
15332 WL_DBG((" assoc resp IES len = %d\n", conn_info->resp_ie_len));
15333 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
15334 (void)memcpy_s(conn_info->resp_ie, sizeof(conn_info->resp_ie),
15335 data, datalen);
15336
15337 WL_INFORM_MEM(("[%s] copied assoc resp ies, sent to upper layer:"
15338 "event %d reason=%d ie_len=%d from " MACDBG "\n",
15339 ndev->name, event_type, ntoh32(e->reason), datalen,
15340 MAC2STRDBG((const u8*)(&e->addr))));
15341 }
15342}
15343
15344#ifdef WLMESH_CFG80211
15345static s32
15346wl_notify_connect_status_mesh(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15347 const wl_event_msg_t *e, void *data)
15348{
15349 s32 err = 0;
15350 u32 event = ntoh32(e->event_type);
15351 u32 reason = ntoh32(e->reason);
15352 u32 len = ntoh32(e->datalen);
15353 u32 status = ntoh32(e->status);
15354
15355#if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
15356 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
15357 bool isfree = false;
15358 u8 *mgmt_frame;
15359 u8 bsscfgidx = e->bsscfgidx;
15360 s32 freq;
15361 s32 channel;
15362 u8 *body = NULL;
15363 u16 fc = 0;
15364 u32 body_len = 0;
15365
15366 struct ieee80211_supported_band *band;
15367 struct ether_addr da;
15368 struct ether_addr bssid;
15369 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15370 channel_info_t ci;
15371 u8 ioctl_buf[WLC_IOCTL_SMLEN];
15372#else
15373 struct station_info sinfo;
15374#endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
15375
15376 WL_INFORM_MEM(("[%s] Mode Mesh. Event:%d status:%d reason:%d\n",
15377 ndev->name, event, ntoh32(e->status), reason));
15378
15379 /* if link down, bsscfg is disabled. */
15380 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
15381 (ndev != bcmcfg_to_prmry_ndev(cfg))) {
15382 WL_MSG(ndev->name, "Mesh mode link down !! \n");
15383 return 0;
15384 }
15385
15386 if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
15387 (reason == WLC_E_REASON_INITIAL_ASSOC)) {
15388 /* AP/GO brought up successfull in firmware */
15389 WL_MSG(ndev->name, "Mesh Link up\n");
15390 return 0;
15391 }
15392
15393 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
15394 WL_MSG(ndev->name, "event %s(%d) status %d reason %d\n",
15395 bcmevent_get_name(event), event, ntoh32(e->status), reason);
15396 }
15397
15398#if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
15399 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
15400 WL_DBG(("Enter \n"));
15401 if (!len && (event == WLC_E_DEAUTH)) {
15402 len = 2; /* reason code field */
15403 data = &reason;
15404 }
15405 if (len) {
15406 body = (u8 *)MALLOCZ(cfg->osh, len);
15407 if (body == NULL) {
15408 WL_ERR(("Failed to allocate body\n"));
15409 return WL_INVALID;
15410 }
15411 }
15412 bzero(&bssid, ETHER_ADDR_LEN);
15413 WL_DBG(("Enter event %d ndev %p\n", event, ndev));
15414 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
15415 MFREE(cfg->osh, body, len);
15416 return WL_INVALID;
15417 }
15418 if (len)
15419 memcpy(body, data, len);
15420
15421 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
15422 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, NULL);
15423 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
15424 bzero(&bssid, sizeof(bssid));
15425 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
15426 switch (event) {
15427 case WLC_E_ASSOC_IND:
15428 fc = FC_ASSOC_REQ;
15429 break;
15430 case WLC_E_REASSOC_IND:
15431 fc = FC_REASSOC_REQ;
15432 break;
15433 case WLC_E_DISASSOC_IND:
15434 fc = FC_DISASSOC;
15435 break;
15436 case WLC_E_DEAUTH_IND:
15437 fc = FC_DISASSOC;
15438 break;
15439 case WLC_E_DEAUTH:
15440 fc = FC_DISASSOC;
15441 break;
15442 default:
15443 fc = 0;
15444 goto exit;
15445 }
15446 bzero(&ci, sizeof(ci));
15447 if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
15448 MFREE(cfg->osh, body, len);
15449 return err;
15450 }
15451
15452 channel = dtoh32(ci.hw_channel);
15453 if (channel <= CH_MAX_2G_CHANNEL)
15454 band = wiphy->bands[IEEE80211_BAND_2GHZ];
15455 else
15456 band = wiphy->bands[IEEE80211_BAND_5GHZ];
15457 if (!band) {
15458 WL_ERR(("No valid band\n"));
15459 if (body) {
15460 MFREE(cfg->osh, body, len);
15461 }
15462 return -EINVAL;
15463 }
15464#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
15465 freq = ieee80211_channel_to_frequency(channel);
15466 (void)band->band;
15467#else
15468 freq = ieee80211_channel_to_frequency(channel, band->band);
15469#endif // endif
15470 body_len = len;
15471 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
15472 &mgmt_frame, &len, body);
15473 if (err < 0)
15474 goto exit;
15475 isfree = true;
15476
15477 if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
15478 (event == WLC_E_DISASSOC_IND) ||
15479 ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
15480#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
15481 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
15482#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
15483 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
15484#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
15485 defined(WL_COMPAT_WIRELESS)
15486 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
15487#else
15488 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
15489#endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
15490 }
15491
15492exit:
15493 if (isfree) {
15494 MFREE(cfg->osh, mgmt_frame, len);
15495 }
15496 if (body) {
15497 MFREE(cfg->osh, body, body_len);
15498 }
15499#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
15500 memset(&sinfo, 0, sizeof(struct station_info));
15501 sinfo.filled = 0;
15502 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
15503 reason == DOT11_SC_SUCCESS) {
15504 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
15505 * STATION_INFO_ASSOC_REQ_IES flag
15506 */
15507#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
15508 sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
15509#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
15510 if (!data) {
15511 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
15512 return -EINVAL;
15513 }
15514 sinfo.assoc_req_ies = data;
15515 sinfo.assoc_req_ies_len = len;
15516 WL_MSG(ndev->name, "new sta event for "MACDBG "\n",
15517 MAC2STRDBG(e->addr.octet));
15518 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
15519 } else if ((event == WLC_E_DEAUTH_IND) ||
15520 ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
15521 (event == WLC_E_DISASSOC_IND)) {
15522 WL_MSG(ndev->name, "del sta event for "MACDBG "\n",
15523 MAC2STRDBG(e->addr.octet));
15524 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
15525 }
15526#endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
15527 return err;
15528}
15529#endif /* WLMESH_CFG80211 */
15530
15531static s32
15532wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15533 const wl_event_msg_t *e, void *data)
15534{
15535 bool act;
15536 struct net_device *ndev = NULL;
15537 s32 err = 0;
15538 u32 event = ntoh32(e->event_type);
15539 u32 datalen = ntoh32(e->datalen);
15540 struct wiphy *wiphy = NULL;
15541 struct cfg80211_bss *bss = NULL;
15542 struct wlc_ssid *ssid = NULL;
15543 u8 *bssid = 0;
15544 s32 bssidx = 0;
15545 u8 *ie_ptr = NULL;
15546 uint32 ie_len = 0;
15547
15548 dhd_pub_t *dhdp;
15549 u32 mode;
15550 int vndr_oui_num = 0;
15551 char vndr_oui[MAX_VNDR_OUI_STR_LEN] = {0, };
15552 bool loc_gen = false;
15553#ifdef DHD_LOSSLESS_ROAMING
15554 struct wl_security *sec;
15555#endif /* DHD_LOSSLESS_ROAMING */
15556#if defined(DHDTCPSYNC_FLOOD_BLK) && defined(CUSTOMER_TCPSYNC_FLOOD_DIS_RC)
15557 dhd_if_t *ifp = NULL;
15558#endif /* DHDTCPSYNC_FLOOD_BLK && CUSTOMER_TCPSYNC_FLOOD_DIS_RC */
15559
15560 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15561#ifdef DHD_LOSSLESS_ROAMING
15562 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15563#endif /* DHD_LOSSLESS_ROAMING */
15564 dhdp = (dhd_pub_t *)(cfg->pub);
15565 BCM_REFERENCE(dhdp);
15566
15567 mode = wl_get_mode_by_netdev(cfg, ndev);
15568 /* Push link events to upper layer log */
15569 SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n",
15570 ndev->name, mode, ntoh32(e->event_type),
15571 ntoh32(e->status), ntoh32(e->reason)));
15572 if (mode == WL_MODE_AP) {
15573 err = wl_notify_connect_status_ap(cfg, ndev, e, data);
15574#ifdef WLMESH_CFG80211
15575 } else if (mode == WL_MODE_MESH) {
15576 err = wl_notify_connect_status_mesh(cfg, ndev, e, data);
15577#endif /* WLMESH_CFG80211 */
15578 } else if (mode == WL_MODE_IBSS) {
15579 err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
15580 } else if (mode == WL_MODE_BSS) {
15581 WL_INFORM_MEM(("[%s] Mode BSS. event:%d status:%d reason:%d\n",
15582 ndev->name, ntoh32(e->event_type),
15583 ntoh32(e->status), ntoh32(e->reason)));
15584
15585 if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
15586 /* Join attempt via non-cfg80211 interface.
15587 * Don't send resultant events to cfg80211
15588 * layer
15589 */
15590 WL_INFORM_MEM(("Event received in non-cfg80211"
15591 " connect state. Ignore\n"));
15592 return BCME_OK;
15593 }
15594#ifdef WL_CLIENT_SAE
15595 if (event == WLC_E_AUTH)
15596 wl_notify_connect_status_bss(cfg, ndev, e, data);
15597#endif /* WL_CLIENT_SAE */
15598
15599 if (event == WLC_E_ASSOC || event == WLC_E_AUTH) {
15600 wl_get_auth_assoc_status(cfg, ndev, e, data);
15601 return 0;
15602 }
15603 if (event == WLC_E_ASSOC_RESP_IE) {
15604 if (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) {
15605 wl_cache_assoc_resp_ies(cfg, ndev, e, data);
15606 }
15607 return 0;
15608 }
15609
15610 DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
15611
15612 if (wl_is_linkup(cfg, e, ndev)) {
15613 wl_link_up(cfg);
15614 act = true;
15615 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15616 WL_INFORM_MEM(("[%s] link up for bssid " MACDBG "\n",
15617 ndev->name, MAC2STRDBG((const u8*)(&e->addr))));
15618 if ((event == WLC_E_LINK) &&
15619 (ntoh16(e->flags) & WLC_EVENT_MSG_LINK) &&
15620 !wl_get_drv_status(cfg, CONNECTED, ndev) &&
15621 !wl_get_drv_status(cfg, CONNECTING, ndev)) {
15622 WL_INFORM_MEM(("link up in non-connected/"
15623 "non-connecting state\n"));
15624 wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
15625 return BCME_OK;
15626 }
15627
15628#ifdef WL_WPS_SYNC
15629 /* Avoid invocation for Roam cases */
15630 if ((event == WLC_E_LINK) &&
15631 !wl_get_drv_status(cfg, CONNECTED, ndev)) {
15632 wl_wps_session_update(ndev,
15633 WPS_STATE_LINKUP, e->addr.octet);
15634 }
15635#endif /* WL_WPS_SYNC */
15636
15637#ifdef DHD_EVENT_LOG_FILTER
15638 if (event == WLC_E_LINK && ndev == bcmcfg_to_prmry_ndev(cfg)) {
15639 int roam = FALSE;
15640 uint8 eth_addr[ETHER_ADDR_LEN];
15641 if (TRUE &&
15642#ifdef DHD_LOSSLESS_ROAMING
15643 !cfg->roam_offload &&
15644#endif /* DHD_LOSSLESS_ROAMING */
15645 wl_get_drv_status(cfg, CONNECTED, ndev)) {
15646 roam = TRUE;
15647 }
15648 memcpy(eth_addr, &(e->addr), ETHER_ADDR_LEN);
15649 dhd_event_log_filter_notify_connect_done(dhdp,
15650 eth_addr, roam);
15651 }
15652#endif /* DHD_EVENT_LOG_FILTER */
15653 if (event == WLC_E_LINK &&
15654#ifdef DHD_LOSSLESS_ROAMING
15655 !cfg->roam_offload &&
15656 !IS_AKM_SUITE_FT(sec) &&
15657#endif /* DHD_LOSSLESS_ROAMING */
15658 wl_get_drv_status(cfg, CONNECTED, ndev)) {
15659 wl_bss_roaming_done(cfg, ndev, e, data);
15660 /* Arm pkt logging timer */
15661 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
15662 } else {
15663 /* Initial Association */
15664 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
15665#ifdef ESCAN_CHANNEL_CACHE
15666 /* Update RCC list in linkup, FW clears RCC in join path */
15667 wl_update_rcc_list(ndev);
15668#endif /* ESCAN_CHANNEL_CACHE */
15669 wl_bss_connect_done(cfg, ndev, e, data, true);
15670 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15671 vndr_oui_num = wl_vndr_ies_get_vendor_oui(cfg,
15672 ndev, vndr_oui, ARRAY_SIZE(vndr_oui));
15673 if (vndr_oui_num > 0) {
15674 WL_INFORM_MEM(("[%s] vendor oui: %s\n",
15675 ndev->name, vndr_oui));
15676 }
15677 }
15678 if (event == WLC_E_LINK) {
15679 /* Arm pkt logging timer */
15680 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_CONNECT);
15681 }
15682 WL_DBG(("joined in BSS network \"%s\"\n",
15683 ((struct wlc_ssid *)wl_read_prof(cfg, ndev,
15684 WL_PROF_SSID))->SSID));
15685 }
15686#ifdef WBTEXT
15687 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
15688 dhdp->wbtext_support && event == WLC_E_SET_SSID) {
15689 /* set wnm_keepalives_max_idle after association */
15690 wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
15691 }
15692#endif /* WBTEXT */
15693 }
15694 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
15695 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
15696
15697 } else if (wl_is_linkdown(cfg, e) ||
15698 ((event == WLC_E_SET_SSID) &&
15699 (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) &&
15700 (wl_get_drv_status(cfg, CONNECTED, ndev)))) {
15701 if (wl_is_linkdown(cfg, e)) {
15702 /* Clear IEs for disaasoc */
15703 if ((bssidx = wl_get_bssidx_by_wdev(cfg,
15704 ndev->ieee80211_ptr)) < 0) {
15705 WL_ERR(("Find index failed\n"));
15706 } else {
15707 WL_ERR(("link down--clearing disconnect IEs\n"));
15708 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
15709 ndev_to_cfgdev(ndev), bssidx, VNDR_IE_DISASSOC_FLAG,
15710 NULL, 0)) != BCME_OK) {
15711 WL_ERR(("Failed to clear ies err = %d\n", err));
15712 }
15713 }
15714#ifdef WL_GET_RCC
15715 wl_android_get_roam_scan_chanlist(cfg);
15716#endif /* WL_GET_RCC */
15717#ifdef WES_SUPPORT
15718 if (cfg->ncho_mode) {
15719 wl_android_set_ncho_mode(ndev, OFF);
15720 }
15721#endif /* WES_SUPPORT */
15722 }
15723
15724 WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n",
15725 wl_get_drv_status(cfg, CONNECTING, ndev),
15726 wl_get_drv_status(cfg, CONNECTED, ndev),
15727 wl_get_drv_status(cfg, DISCONNECTING, ndev),
15728 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
15729
15730 /* clear timestamps on disconnect */
15731 CLR_TS(cfg, conn_start);
15732 CLR_TS(cfg, conn_cmplt);
15733 CLR_TS(cfg, authorize_start);
15734 CLR_TS(cfg, authorize_cmplt);
15735#ifdef WL_WPS_SYNC
15736 {
15737 u8 wps_state;
15738 if ((event == WLC_E_SET_SSID) &&
15739 (ntoh32(e->status) != WLC_E_STATUS_SUCCESS)) {
15740 /* connect fail */
15741 wps_state = WPS_STATE_CONNECT_FAIL;
15742 } else {
15743 wps_state = WPS_STATE_LINKDOWN;
15744 }
15745 if (wl_wps_session_update(ndev,
15746 wps_state, e->addr.octet) == BCME_UNSUPPORTED) {
15747 /* Unexpected event. Ignore it. */
15748 return 0;
15749 }
15750 }
15751#endif /* WL_WPS_SYNC */
15752
15753 if (wl_get_drv_status(cfg, DISCONNECTING, ndev) &&
15754 (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) ||
15755 wl_get_drv_status(cfg, CONNECTING, ndev))) {
15756 /* wl_cfg80211_connect was called before 'DISCONNECTING' was
15757 * cleared. Deauth/Link down event is caused by WLC_DISASSOC
15758 * command issued from the wl_cfg80211_connect context. Ignore
15759 * the event to avoid pre-empting the current connection
15760 */
15761 WL_DBG(("Nested connection case. Drop event. \n"));
15762 wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY|WAIT_DISCONNECTED,
15763 WL_EXT_STATUS_DISCONNECTED, NULL);
15764 wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
15765 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15766 /* Not in 'CONNECTED' state, clear it */
15767 wl_clr_drv_status(cfg, CONNECTED, ndev);
15768 return 0;
15769 }
15770
15771 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15772 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
15773 FW_LOGSET_MASK_ALL);
15774 }
15775#ifdef DHD_LOSSLESS_ROAMING
15776 wl_del_roam_timeout(cfg);
15777#endif
15778#ifdef P2PLISTEN_AP_SAMECHN
15779 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15780 wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0);
15781 cfg->p2p_resp_apchn_status = false;
15782 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
15783 }
15784#endif /* P2PLISTEN_AP_SAMECHN */
15785
15786#if defined(DHD_ENABLE_BIGDATA_LOGGING)
15787 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15788 wl_get_bss_info(cfg, ndev, &e->addr);
15789 }
15790#endif /* DHD_ENABLE_BIGDATA_LOGGING */
15791
15792 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15793 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15794 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
15795 bool fw_assoc_state = TRUE;
15796 dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
15797 fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
15798 if (!fw_assoc_state) {
15799 WL_ERR(("Event sends up even different BSSID"
15800 " cur: " MACDBG " event: " MACDBG"\n",
15801 MAC2STRDBG(curbssid),
15802 MAC2STRDBG((const u8*)(&e->addr))));
15803 } else {
15804 WL_ERR(("BSSID of event is not the connected BSSID"
15805 "(ignore it) cur: " MACDBG
15806 " event: " MACDBG"\n",
15807 MAC2STRDBG(curbssid),
15808 MAC2STRDBG((const u8*)(&e->addr))));
15809 return 0;
15810 }
15811 }
15812 }
15813 /* Explicitly calling unlink to remove BSS in CFG */
15814 wiphy = bcmcfg_to_wiphy(cfg);
15815 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
15816 bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15817 if (ssid && bssid) {
15818 bss = CFG80211_GET_BSS(wiphy, NULL, bssid,
15819 ssid->SSID, ssid->SSID_len);
15820 if (bss) {
15821 cfg80211_unlink_bss(wiphy, bss);
15822 CFG80211_PUT_BSS(wiphy, bss);
15823 }
15824 }
15825
15826 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15827 scb_val_t scbval;
15828 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15829 uint32 reason = 0;
15830 struct ether_addr bssid_dongle = {{0, 0, 0, 0, 0, 0}};
15831 struct ether_addr bssid_null = {{0, 0, 0, 0, 0, 0}};
15832
15833 wl_cfg80211_cancel_scan(cfg);
15834 if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
15835 reason = ntoh32(e->reason);
15836 /* Specific AP send deauth by invalid reason.
15837 * If reason over 0x8XXX, framework trigger recovery.
15838 * Framework check HANG_REASON_MASK(0x8000) with reason.
15839 */
15840 if (reason > WLC_E_DEAUTH_MAX_REASON) {
15841 WL_ERR(("Event %d original reason is %d, "
15842 "changed 0xFF\n", event, reason));
15843 reason = WLC_E_DEAUTH_MAX_REASON;
15844 }
15845 wl_cfg80211_handle_deauth_ind(cfg, ndev, e, data);
15846 }
15847#ifdef SET_SSID_FAIL_CUSTOM_RC
15848 if ((event == WLC_E_SET_SSID) &&
15849 (ntoh32(e->status) == WLC_E_STATUS_TIMEOUT)) {
15850 reason = SET_SSID_FAIL_CUSTOM_RC;
15851 }
15852#endif /* SET_SSID_FAIL_CUSTOM_RC */
15853#if defined(CONFIG_TIZEN)
15854 net_stat_tizen_update_wifi(ndev, WIFISTAT_DISCONNECTION);
15855#endif /* CONFIG_TIZEN */
15856
15857 /* roam offload does not sync BSSID always, get it from dongle */
15858 if (cfg->roam_offload) {
15859 bzero(&bssid_dongle, sizeof(bssid_dongle));
15860 if (wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid_dongle,
15861 sizeof(bssid_dongle)) == BCME_OK) {
15862 /* if not roam case, it would return null bssid */
15863 if (memcmp(&bssid_dongle, &bssid_null,
15864 ETHER_ADDR_LEN) != 0) {
15865 curbssid = (u8 *)&bssid_dongle;
15866 }
15867 }
15868 }
15869 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
15870 bool fw_assoc_state = TRUE;
15871 dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
15872 fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
15873 if (!fw_assoc_state) {
15874 WL_ERR(("Event sends up even different BSSID"
15875 " cur: " MACDBG " event: " MACDBG"\n",
15876 MAC2STRDBG(curbssid),
15877 MAC2STRDBG((const u8*)(&e->addr))));
15878 } else {
15879 WL_ERR(("BSSID of event is not the connected BSSID"
15880 "(ignore it) cur: " MACDBG
15881 " event: " MACDBG"\n",
15882 MAC2STRDBG(curbssid),
15883 MAC2STRDBG((const u8*)(&e->addr))));
15884 return 0;
15885 }
15886 }
15887#ifdef DBG_PKT_MON
15888 /* Stop packet monitor */
15889 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15890 DHD_DBG_PKT_MON_STOP(dhdp);
15891 }
15892#endif /* DBG_PKT_MON */
15893 /* clear RSSI monitor, framework will set new cfg */
15894#ifdef RSSI_MONITOR_SUPPORT
15895 dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
15896 FALSE, 0, 0);
15897#endif /* RSSI_MONITOR_SUPPORT */
15898 if (dhdp->conf->eapol_status == EAPOL_STATUS_4WAY_DONE &&
15899 !memcmp(ndev->name, WL_P2P_INTERFACE_PREFIX, strlen(WL_P2P_INTERFACE_PREFIX))) {
15900 // terence 20130703: Fix for wrong group_capab (timing issue)
15901 cfg->p2p_disconnected = 1;
15902 }
15903 memcpy(&cfg->disconnected_bssid, curbssid, ETHER_ADDR_LEN);
15904 wl_clr_drv_status(cfg, CONNECTED, ndev);
15905
15906 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15907 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15908 dhd_net2idx(dhdp->info, ndev),
15909 WLAN_REASON_DEAUTH_LEAVING);
15910 /* To make sure disconnect, explictly send dissassoc
15911 * for BSSID 00:00:00:00:00:00 issue
15912 */
15913 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
15914 WL_INFORM_MEM(("clear fw state\n"));
15915 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
15916 scbval.val = htod32(scbval.val);
15917 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
15918 sizeof(scb_val_t));
15919 if (err < 0) {
15920 WL_ERR(("WLC_DISASSOC error %d\n", err));
15921 err = 0;
15922 }
15923 }
15924 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15925 loc_gen = true;
15926 }
15927 WL_INFORM_MEM(("[%s] Indicate disconnect event to upper layer. "
15928 "event: %d reason=%d from " MACDBG "\n",
15929 ndev->name, event, ntoh32(e->reason),
15930 MAC2STRDBG((const u8*)(&e->addr))));
15931
15932#ifdef WBTEXT
15933 /* when STA was disconnected, clear join pref and set wbtext */
15934 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
15935 dhdp->wbtext_policy
15936 == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) {
15937 char smbuf[WLC_IOCTL_SMLEN];
15938 if ((err = wldev_iovar_setbuf(ndev, "join_pref",
15939 NULL, 0, smbuf,
15940 sizeof(smbuf), NULL))
15941 == BCME_OK) {
15942 if ((err = wldev_iovar_setint(ndev,
15943 "wnm_bsstrans_resp",
15944 dhdp->wbtext_policy))
15945 == BCME_OK) {
15946 wl_cfg80211_wbtext_set_default(ndev);
15947 } else {
15948 WL_ERR(("wl_notify_connect_status:"
15949 " Failed to"
15950 " set wbtext = %d\n",
15951 err));
15952 }
15953 } else {
15954 WL_ERR(("wl_notify_connect_status:"
15955 " Failed to clear join pref = %d\n",
15956 err));
15957 }
15958 wl_cfg80211_wbtext_clear_bssid_list(cfg);
15959 }
15960#endif /* WBTEXT */
15961 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_DONE),
15962 dhd_net2idx(dhdp->info, ndev), reason);
15963 /* Send up deauth and clear states */
15964
15965 /*
15966 * FW sends body and body len as a part of deauth
15967 * and disassoc events (WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND)
15968 * The VIEs sits after reason code in the body. Reason code is
15969 * 2 bytes long.
15970 */
15971 WL_DBG(("recv disconnect ies ie_len = %d\n", ie_len));
15972 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND) {
15973 if ((datalen > DOT11_DISCONNECT_RC) &&
15974 datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
15975 data) {
15976 ie_ptr = (uchar*)data + DOT11_DISCONNECT_RC;
15977 ie_len = datalen - DOT11_DISCONNECT_RC;
15978 }
15979 } else if (event == WLC_E_LINK &&
15980 ntoh32(e->reason) == WLC_E_LINK_BCN_LOSS) {
15981#ifdef WL_ANALYTICS
15982 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15983 if (wl_vndr_ies_find_vendor_oui(cfg, ndev,
15984 CISCO_AIRONET_OUI)) {
15985 WL_INFORM_MEM(("Analytics Beacon loss\n"));
15986 ie_ptr = (uchar*)disco_bcnloss_vsie;
15987 ie_len = sizeof(disco_bcnloss_vsie);
15988 }
15989 }
15990#endif /* WL_ANALYTICS */
15991 }
15992#if defined(DHDTCPSYNC_FLOOD_BLK) && defined(CUSTOMER_TCPSYNC_FLOOD_DIS_RC)
15993 ifp = dhd_get_ifp(dhdp, e->ifidx);
15994 if (ifp && ifp->disconnect_tsync_flood) {
15995 reason = CUSTOMER_TCPSYNC_FLOOD_DIS_RC;
15996 }
15997#endif /* DHDTCPSYNC_FLOOD_BLK && CUSTOMER_TCPSYNC_FLOOD_DIS_RC */
15998 CFG80211_DISCONNECTED(ndev, reason, ie_ptr, ie_len,
15999 loc_gen, GFP_KERNEL);
16000 WL_INFORM_MEM(("[%s] Disconnect event sent to upper layer"
16001 "event:%d e->reason=%d reason=%d ie_len=%d "
16002 "from " MACDBG "\n",
16003 ndev->name, event, ntoh32(e->reason), reason, ie_len,
16004 MAC2STRDBG((const u8*)(&e->addr))));
16005
16006 /* Wait for status to be cleared to prevent race condition
16007 * issues with connect context
16008 */
16009 wl_link_down(cfg);
16010 wl_init_prof(cfg, ndev);
16011 wl_clr_drv_status(cfg, AUTHORIZED, ndev);
16012 CLR_TS(cfg, authorize_start);
16013 CLR_TS(cfg, authorize_cmplt);
16014 CLR_TS(cfg, conn_start);
16015 CLR_TS(cfg, conn_cmplt);
16016 }
16017 else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
16018#ifdef ESCAN_RESULT_PATCH
16019 u8 *conn_req_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
16020#endif /* ESCAN_RESULT_PATCH */
16021 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
16022 dhd_net2idx(dhdp->info, ndev), 0);
16023 WL_INFORM_MEM(("link down, during connecting\n"));
16024 /* Issue WLC_DISASSOC to prevent FW roam attempts.
16025 * Do not issue WLC_DISASSOC again if the linkdown is
16026 * generated due to local disassoc, to avoid connect-disconnect
16027 * loop.
16028 */
16029 if (!((event == WLC_E_LINK) &&
16030 (ntoh32(e->reason) == WLC_E_LINK_DISASSOC) &&
16031 (ntoh32(e->status) == WLC_E_STATUS_SUCCESS))) {
16032 err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
16033 if (err < 0) {
16034 WL_ERR(("CONNECTING state,"
16035 " WLC_DISASSOC error %d\n",
16036 err));
16037 err = 0;
16038 }
16039#ifdef ESCAN_RESULT_PATCH
16040 if (conn_req_bssid && (ETHER_ISNULLADDR(conn_req_bssid) ||
16041 ETHER_ISNULLADDR(&e->addr) ||
16042 (memcmp(&e->addr, conn_req_bssid,
16043 ETHER_ADDR_LEN) == 0)))
16044 /* In case this event comes while associating
16045 * another AP
16046 */
16047#endif /* ESCAN_RESULT_PATCH */
16048 wl_bss_connect_done(cfg, ndev, e, data, false);
16049 }
16050 }
16051 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
16052 wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY|WAIT_DISCONNECTED,
16053 WL_EXT_STATUS_DISCONNECTED, NULL);
16054
16055 /* if link down, bsscfg is diabled */
16056 if (ndev != bcmcfg_to_prmry_ndev(cfg))
16057 complete(&cfg->iface_disable);
16058#ifdef WLTDLS
16059 /* re-enable TDLS if the number of connected interfaces
16060 * is less than 2.
16061 */
16062 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
16063#endif /* WLTDLS */
16064 } else if (wl_is_nonetwork(cfg, e)) {
16065 WL_ERR(("connect failed event=%d e->status %d e->reason %d \n",
16066 event, (int)ntoh32(e->status), (int)ntoh32(e->reason)));
16067#if defined(CONFIG_TIZEN)
16068 net_stat_tizen_update_wifi(ndev, WIFISTAT_CONNECTION_FAIL);
16069#endif /* CONFIG_TIZEN */
16070 wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY|WAIT_DISCONNECTED,
16071 WL_EXT_STATUS_DISCONNECTED, NULL);
16072#ifdef WL_WPS_SYNC
16073 if (wl_wps_session_update(ndev,
16074 WPS_STATE_CONNECT_FAIL, e->addr.octet) == BCME_UNSUPPORTED) {
16075 /* Unexpected event. Ignore it. */
16076 return 0;
16077 }
16078#endif /* WL_WPS_SYNC */
16079#if defined(DHD_ENABLE_BIGDATA_LOGGING)
16080 if (event == WLC_E_SET_SSID) {
16081 wl_get_connect_failed_status(cfg, e);
16082 }
16083#endif /* DHD_ENABLE_BIGDATA_LOGGING */
16084 /* Dump FW preserve buffer content */
16085 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
16086
16087 /* Clean up any pending scan request */
16088 wl_cfg80211_cancel_scan(cfg);
16089
16090 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
16091 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
16092 WL_INFORM_MEM(("wl dissassoc\n"));
16093 err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
16094 if (err < 0) {
16095 WL_ERR(("WLC_DISASSOC error %d\n", err));
16096 err = 0;
16097 }
16098 } else {
16099 WL_DBG(("connect fail. clear disconnecting bit\n"));
16100 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
16101 }
16102 wl_bss_connect_done(cfg, ndev, e, data, false);
16103 wl_clr_drv_status(cfg, CONNECTING, ndev);
16104 WL_INFORM_MEM(("connect fail reported\n"));
16105 }
16106 } else {
16107 WL_DBG(("%s nothing\n", __FUNCTION__));
16108 }
16109
16110 DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
16111
16112 } else {
16113 WL_MSG(ndev->name, "Invalid mode %d event %d status %d\n",
16114 wl_get_mode_by_netdev(cfg, ndev), ntoh32(e->event_type),
16115 ntoh32(e->status));
16116 }
16117 return err;
16118}
16119
16120#ifdef WL_RELMCAST
16121void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
16122{
16123 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
16124 if (pid > 0)
16125 cfg->rmc_event_pid = pid;
16126 WL_DBG(("set pid for rmc event : pid=%d\n", pid));
16127}
16128#endif /* WL_RELMCAST */
16129
16130#ifdef WLAIBSS
16131void wl_cfg80211_set_txfail_pid(struct net_device *dev, int pid)
16132{
16133 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
16134 if (pid > 0)
16135 cfg->aibss_txfail_pid = pid;
16136 WL_DBG(("set pid for aibss fail event : pid=%d\n", pid));
16137}
16138
16139static s32
16140wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16141 const wl_event_msg_t *e, void *data)
16142{
16143 u32 evt = ntoh32(e->event_type);
16144 int ret = -1;
16145#ifdef PCIE_FULL_DONGLE
16146 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
16147 u32 reason = ntoh32(e->reason);
16148#endif
16149 if (cfg->aibss_txfail_pid != 0) {
16150#ifdef PCIE_FULL_DONGLE
16151 if (reason == AIBSS_PEER_FREE) {
16152 uint8 ifindex;
16153 wl_event_msg_t event;
16154
16155 bzero(&event, sizeof(wl_event_msg_t));
16156 memcpy(&event, e, sizeof(wl_event_msg_t));
16157
16158 ifindex = (uint8)dhd_ifname2idx(dhd->info, event.ifname);
16159 WL_INFORM_MEM(("Peer freed. Flow rings delete for peer.\n"));
16160 dhd_flow_rings_delete_for_peer(dhd, ifindex,
16161 (void *)&event.addr.octet[0]);
16162 return 0;
16163 }
16164#endif
16165 ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL,
16166 cfg->aibss_txfail_seq++, &e->addr, ETHER_ADDR_LEN);
16167 }
16168
16169 WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n",
16170 evt, cfg->aibss_txfail_pid, ret, CONST_ETHERP_TO_MACF(&e->addr)));
16171 return ret;
16172}
16173#endif /* WLAIBSS */
16174#ifdef WL_RELMCAST
16175static s32
16176wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16177 const wl_event_msg_t *e, void *data)
16178{
16179 u32 evt = ntoh32(e->event_type);
16180 u32 reason = ntoh32(e->reason);
16181 int ret = -1;
16182
16183 switch (reason) {
16184 case WLC_E_REASON_RMC_AR_LOST:
16185 case WLC_E_REASON_RMC_AR_NO_ACK:
16186 if (cfg->rmc_event_pid != 0) {
16187 ret = wl_netlink_send_msg(cfg->rmc_event_pid,
16188 RMC_EVENT_LEADER_CHECK_FAIL,
16189 cfg->rmc_event_seq++, NULL, 0);
16190 }
16191 break;
16192 default:
16193 break;
16194 }
16195 WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
16196 return ret;
16197}
16198#endif /* WL_RELMCAST */
16199
16200#ifdef GSCAN_SUPPORT
16201static s32
16202wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16203 const wl_event_msg_t *e, void *data)
16204{
16205 struct net_device *ndev = NULL;
16206 u32 datalen = be32_to_cpu(e->datalen);
16207
16208 if (datalen) {
16209 wl_roam_exp_event_t *evt_data = (wl_roam_exp_event_t *)data;
16210 if (evt_data->version == ROAM_EXP_EVENT_VERSION) {
16211 wlc_ssid_t *ssid = &evt_data->cur_ssid;
16212 struct wireless_dev *wdev;
16213 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16214 if (ndev) {
16215 wdev = ndev->ieee80211_ptr;
16216 wdev->ssid_len = min(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN);
16217 memcpy(wdev->ssid, ssid->SSID, wdev->ssid_len);
16218 WL_ERR(("SSID is %s\n", ssid->SSID));
16219 wl_update_prof(cfg, ndev, NULL, ssid, WL_PROF_SSID);
16220 } else {
16221 WL_ERR(("NULL ndev!\n"));
16222 }
16223 } else {
16224 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
16225 ROAM_EXP_EVENT_VERSION));
16226 }
16227 }
16228 return BCME_OK;
16229}
16230#endif /* GSCAN_SUPPORT */
16231
16232#ifdef RSSI_MONITOR_SUPPORT
16233static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16234 const wl_event_msg_t *e, void *data)
16235{
16236
16237#if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
16238 u32 datalen = be32_to_cpu(e->datalen);
16239 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16240 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
16241
16242 if (datalen) {
16243 wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data;
16244 if (evt_data->version == RSSI_MONITOR_VERSION) {
16245 dhd_rssi_monitor_evt_t monitor_data;
16246 monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION;
16247 monitor_data.cur_rssi = evt_data->cur_rssi;
16248 memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN);
16249 wl_cfgvendor_send_async_event(wiphy, ndev,
16250 GOOGLE_RSSI_MONITOR_EVENT,
16251 &monitor_data, sizeof(monitor_data));
16252 } else {
16253 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
16254 RSSI_MONITOR_VERSION));
16255 }
16256 }
16257#endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
16258 return BCME_OK;
16259}
16260#endif /* RSSI_MONITOR_SUPPORT */
16261
16262static s32
16263wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16264 const wl_event_msg_t *e, void *data)
16265{
16266 bool act;
16267 struct net_device *ndev = NULL;
16268 s32 err = 0;
16269 u32 event = be32_to_cpu(e->event_type);
16270 u32 status = be32_to_cpu(e->status);
16271#ifdef DHD_LOSSLESS_ROAMING
16272 struct wl_security *sec;
16273#endif
16274 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16275 WL_DBG(("Enter \n"));
16276
16277 BCM_REFERENCE(dhdp);
16278 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16279
16280 if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
16281
16282 wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
16283
16284 cfg->disable_roam_event = TRUE;
16285 }
16286
16287 if ((cfg->disable_roam_event) && (event == WLC_E_ROAM))
16288 return err;
16289
16290 if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
16291 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
16292#ifdef DHD_LOSSLESS_ROAMING
16293 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16294 /* In order to reduce roaming delay, wl_bss_roaming_done is
16295 * early called with WLC_E_LINK event. It is called from
16296 * here only if WLC_E_LINK event is blocked for specific
16297 * security type.
16298 */
16299 if (IS_AKM_SUITE_FT(sec)) {
16300 wl_bss_roaming_done(cfg, ndev, e, data);
16301 /* Arm pkt logging timer */
16302 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
16303 }
16304 /* Roam timer is deleted mostly from wl_cfg80211_change_station
16305 * after roaming is finished successfully. We need to delete
16306 * the timer from here only for some security types that aren't
16307 * using wl_cfg80211_change_station to authorize SCB
16308 */
16309 if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
16310 wl_del_roam_timeout(cfg);
16311 }
16312#else
16313#if !defined(DHD_NONFT_ROAMING)
16314 wl_bss_roaming_done(cfg, ndev, e, data);
16315#endif /* !DHD_NONFT_ROAMING */
16316#endif /* DHD_LOSSLESS_ROAMING */
16317#ifdef WBTEXT
16318 if (dhdp->wbtext_support) {
16319 /* set wnm_keepalives_max_idle after association */
16320 wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
16321
16322 /* Mostly nbr request of BTM query will be handled
16323 * from wl_cfg80211_change_station
16324 * after key negotiation is finished.
16325 * This part is only for some specific security
16326 * types (FT, CCKM) that don't call
16327 * wl_cfg80211_change_station after roaming
16328 */
16329 if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
16330 /* send nbr request or BTM query to update RCC
16331 * after roaming completed
16332 */
16333 wl_cfg80211_wbtext_update_rcc(cfg, ndev);
16334 }
16335 }
16336#endif /* WBTEXT */
16337 } else {
16338 wl_bss_connect_done(cfg, ndev, e, data, true);
16339 }
16340 act = true;
16341 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
16342 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
16343
16344 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
16345 wl_vndr_ies_get_vendor_oui(cfg, ndev, NULL, 0);
16346 }
16347 }
16348#ifdef DHD_LOSSLESS_ROAMING
16349 else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) {
16350 wl_del_roam_timeout(cfg);
16351 }
16352#endif
16353 return err;
16354}
16355
16356#ifdef CUSTOM_EVENT_PM_WAKE
16357uint32 last_dpm_upd_time = 0; /* ms */
16358#define DPM_UPD_LMT_TIME ((CUSTOM_EVENT_PM_WAKE + (5)) * (1000) * (4)) /* ms */
16359#define DPM_UPD_LMT_RSSI -85 /* dbm */
16360
16361static s32
16362wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16363 const wl_event_msg_t *e, void *data)
16364{
16365 s32 err = BCME_OK;
16366 struct net_device *ndev = NULL;
16367 u8 *pbuf = NULL;
16368 uint32 cur_dpm_upd_time = 0;
16369 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
16370 s32 rssi;
16371#ifdef SUPPORT_RSSI_SUM_REPORT
16372 wl_rssi_ant_mimo_t rssi_ant_mimo;
16373#endif /* SUPPORT_RSSI_SUM_REPORT */
16374 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16375
16376 pbuf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
16377 if (pbuf == NULL) {
16378 WL_ERR(("failed to allocate local pbuf\n"));
16379 return -ENOMEM;
16380 }
16381
16382 err = wldev_iovar_getbuf_bsscfg(ndev, "dump",
16383 "pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN,
16384 0, &cfg->ioctl_buf_sync);
16385
16386 if (err) {
16387 WL_ERR(("dump ioctl err = %d", err));
16388 } else {
16389 WL_ERR(("PM status : %s\n", pbuf));
16390 }
16391
16392 if (pbuf) {
16393 MFREE(cfg->osh, pbuf, WLC_IOCTL_MEDLEN);
16394 }
16395
16396 if (dhd->early_suspended) {
16397 /* LCD off */
16398#ifdef SUPPORT_RSSI_SUM_REPORT
16399 /* Query RSSI sum across antennas */
16400 memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
16401 err = wl_get_rssi_per_ant(ndev, ndev->name, NULL, &rssi_ant_mimo);
16402 if (err) {
16403 WL_ERR(("Could not get rssi sum (%d)\n", err));
16404 }
16405 rssi = rssi_ant_mimo.rssi_sum;
16406 if (rssi == 0)
16407#endif /* SUPPORT_RSSI_SUM_REPORT */
16408 {
16409 scb_val_t scb_val;
16410 memset(&scb_val, 0, sizeof(scb_val_t));
16411 scb_val.val = 0;
16412 err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
16413 if (err) {
16414 WL_ERR(("Could not get rssi (%d)\n", err));
16415 }
16416#if defined(RSSIOFFSET)
16417 rssi = wl_update_rssi_offset(ndev, dtoh32(scb_val.val));
16418#else
16419 rssi = dtoh32(scb_val.val);
16420#endif
16421 }
16422 WL_ERR(("RSSI %d dBm\n", rssi));
16423 if (rssi > DPM_UPD_LMT_RSSI) {
16424 return err;
16425 }
16426 } else {
16427 /* LCD on */
16428 return err;
16429 }
16430
16431 if (last_dpm_upd_time == 0) {
16432 last_dpm_upd_time = OSL_SYSUPTIME();
16433 } else {
16434 cur_dpm_upd_time = OSL_SYSUPTIME();
16435 if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) {
16436 scb_val_t scbval;
16437 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
16438 dhd_net2idx(dhd->info, ndev), 0);
16439 bzero(&scbval, sizeof(scb_val_t));
16440
16441 err = wldev_ioctl_set(ndev, WLC_DISASSOC,
16442 &scbval, sizeof(scb_val_t));
16443 if (err < 0) {
16444 WL_ERR(("Disassoc error %d\n", err));
16445 return err;
16446 }
16447 WL_ERR(("Force Disassoc due to updated DPM event.\n"));
16448
16449 last_dpm_upd_time = 0;
16450 } else {
16451 last_dpm_upd_time = cur_dpm_upd_time;
16452 }
16453 }
16454
16455 return err;
16456}
16457#endif /* CUSTOM_EVENT_PM_WAKE */
16458
16459#ifdef QOS_MAP_SET
16460/* get user priority table */
16461uint8 *
16462wl_get_up_table(dhd_pub_t * dhdp, int idx)
16463{
16464 struct net_device *ndev;
16465 struct bcm_cfg80211 *cfg;
16466
16467 ndev = dhd_idx2net(dhdp, idx);
16468 if (ndev) {
16469 cfg = wl_get_cfg(ndev);
16470 if (cfg)
16471 return (uint8 *)(cfg->up_table);
16472 }
16473
16474 return NULL;
16475}
16476#endif /* QOS_MAP_SET */
16477
16478#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
16479/*
16480 * start packet logging in advance to make sure that EAPOL
16481 * messages are not missed during roaming
16482 */
16483static s32
16484wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16485 const wl_event_msg_t *e, void *data)
16486{
16487 struct wl_security *sec;
16488 struct net_device *ndev;
16489 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16490 u32 status = ntoh32(e->status);
16491 u32 reason = ntoh32(e->reason);
16492
16493 BCM_REFERENCE(sec);
16494
16495 if (status == WLC_E_STATUS_SUCCESS && reason != WLC_E_REASON_INITIAL_ASSOC) {
16496 WL_ERR(("Attempting roam with reason code : %d\n", reason));
16497 }
16498
16499#ifdef CONFIG_SILENT_ROAM
16500 if (dhdp->in_suspend && reason == WLC_E_REASON_SILENT_ROAM) {
16501 dhdp->sroamed = TRUE;
16502 }
16503#endif /* CONFIG_SILENT_ROAM */
16504
16505 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16506
16507#ifdef DBG_PKT_MON
16508 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
16509 DHD_DBG_PKT_MON_STOP(dhdp);
16510 DHD_DBG_PKT_MON_START(dhdp);
16511 }
16512#endif /* DBG_PKT_MON */
16513#ifdef DHD_LOSSLESS_ROAMING
16514 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16515 /* Disable Lossless Roaming for specific AKM suite
16516 * Any other AKM suite can be added below if transition time
16517 * is delayed because of Lossless Roaming
16518 * and it causes any certication failure
16519 */
16520 if (IS_AKM_SUITE_FT(sec)) {
16521 return BCME_OK;
16522 }
16523
16524 dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC;
16525 /* Restore flow control */
16526 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
16527
16528 mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
16529#endif /* DHD_LOSSLESS_ROAMING */
16530
16531 return BCME_OK;
16532}
16533#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
16534
16535static s32
16536wl_notify_roam_start_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16537 const wl_event_msg_t *e, void *data)
16538{
16539#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
16540 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16541 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
16542 int event_type;
16543
16544 event_type = WIFI_EVENT_ROAM_SCAN_STARTED;
16545 wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_ROAM_EVENT_START,
16546 &event_type, sizeof(int));
16547#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || (WL_VENDOR_EXT_SUPPORT) */
16548
16549 return BCME_OK;
16550}
16551
16552static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
16553{
16554 wl_assoc_info_t assoc_info;
16555 struct wl_connect_info *conn_info = wl_to_conn(cfg);
16556 s32 err = 0;
16557#ifdef QOS_MAP_SET
16558 bcm_tlv_t * qos_map_ie = NULL;
16559#endif /* QOS_MAP_SET */
16560
16561 WL_DBG(("Enter \n"));
16562
16563 bzero(&assoc_info, sizeof(wl_assoc_info_t));
16564 err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
16565 WL_ASSOC_INFO_MAX, NULL);
16566 if (unlikely(err)) {
16567 WL_ERR(("could not get assoc info (%d)\n", err));
16568 return err;
16569 }
16570 memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
16571 assoc_info.req_len = htod32(assoc_info.req_len);
16572 assoc_info.resp_len = htod32(assoc_info.resp_len);
16573 assoc_info.flags = htod32(assoc_info.flags);
16574 if (conn_info->req_ie_len) {
16575 conn_info->req_ie_len = 0;
16576 bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
16577 }
16578 if (conn_info->resp_ie_len) {
16579 conn_info->resp_ie_len = 0;
16580 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
16581 }
16582
16583 if (assoc_info.req_len) {
16584 err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
16585 assoc_info.req_len, NULL);
16586 if (unlikely(err)) {
16587 WL_ERR(("could not get assoc req (%d)\n", err));
16588 return err;
16589 }
16590 if (assoc_info.req_len < sizeof(struct dot11_assoc_req)) {
16591 WL_ERR(("req_len %d lessthan %d \n", assoc_info.req_len,
16592 (int)sizeof(struct dot11_assoc_req)));
16593 return BCME_BADLEN;
16594 }
16595 conn_info->req_ie_len = (uint32)(assoc_info.req_len
16596 - sizeof(struct dot11_assoc_req));
16597 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
16598 conn_info->req_ie_len -= ETHER_ADDR_LEN;
16599 }
16600 if (conn_info->req_ie_len <= MAX_REQ_LINE)
16601 memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
16602 else {
16603 WL_ERR(("IE size %d above max %d size \n",
16604 conn_info->req_ie_len, MAX_REQ_LINE));
16605 return err;
16606 }
16607 } else {
16608 conn_info->req_ie_len = 0;
16609 }
16610
16611 if (assoc_info.resp_len) {
16612 err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
16613 assoc_info.resp_len, NULL);
16614 if (unlikely(err)) {
16615 WL_ERR(("could not get assoc resp (%d)\n", err));
16616 return err;
16617 }
16618 if (assoc_info.resp_len < sizeof(struct dot11_assoc_resp)) {
16619 WL_ERR(("resp_len %d is lessthan %d \n", assoc_info.resp_len,
16620 (int)sizeof(struct dot11_assoc_resp)));
16621 return BCME_BADLEN;
16622 }
16623 conn_info->resp_ie_len = assoc_info.resp_len -
16624 (uint32)sizeof(struct dot11_assoc_resp);
16625 if (conn_info->resp_ie_len <= MAX_REQ_LINE) {
16626 memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
16627 } else {
16628 WL_ERR(("IE size %d above max %d size \n",
16629 conn_info->resp_ie_len, MAX_REQ_LINE));
16630 return err;
16631 }
16632
16633#ifdef QOS_MAP_SET
16634 /* find qos map set ie */
16635 if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
16636 DOT11_MNG_QOS_MAP_ID)) != NULL) {
16637 WL_DBG((" QoS map set IE found in assoc response\n"));
16638 if (!cfg->up_table) {
16639 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
16640 }
16641 wl_set_up_table(cfg->up_table, qos_map_ie);
16642 } else {
16643 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
16644 }
16645#endif /* QOS_MAP_SET */
16646 } else {
16647 conn_info->resp_ie_len = 0;
16648 }
16649 WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
16650 conn_info->resp_ie_len));
16651
16652 return err;
16653}
16654
16655static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16656 bool update_ssid)
16657{
16658 struct cfg80211_bss *bss;
16659 wl_bss_info_t *bi;
16660 struct wlc_ssid *ssid;
16661 const struct bcm_tlv *tim;
16662 s32 beacon_interval;
16663 s32 dtim_period;
16664 size_t ie_len;
16665 const u8 *ie;
16666 u8 *curbssid;
16667 s32 err = 0;
16668 struct wiphy *wiphy;
16669 char *buf;
16670 u32 freq;
16671 chanspec_t chspec = INVCHANSPEC;
16672
16673 wiphy = bcmcfg_to_wiphy(cfg);
16674
16675 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
16676 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16677 bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
16678 ssid->SSID, ssid->SSID_len);
16679 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
16680 if (!buf) {
16681 WL_ERR(("buffer alloc failed.\n"));
16682 return BCME_NOMEM;
16683 }
16684 mutex_lock(&cfg->usr_sync);
16685 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
16686 err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX);
16687 if (unlikely(err)) {
16688 WL_ERR(("Could not get bss info %d\n", err));
16689 goto update_bss_info_out;
16690 }
16691 bi = (wl_bss_info_t *)(buf + 4);
16692 chspec = wl_chspec_driver_to_host(bi->chanspec);
16693 wl_update_prof(cfg, ndev, NULL, &chspec, WL_PROF_CHAN);
16694
16695 if (!bss) {
16696 WL_DBG(("Could not find the AP\n"));
16697 if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
16698 WL_ERR(("Bssid doesn't match\n"));
16699 err = -EIO;
16700 goto update_bss_info_out;
16701 }
16702 err = wl_inform_single_bss(cfg, bi, update_ssid);
16703 if (unlikely(err))
16704 goto update_bss_info_out;
16705
16706 ie = ((u8 *)bi) + bi->ie_offset;
16707 ie_len = bi->ie_length;
16708 beacon_interval = cpu_to_le16(bi->beacon_period);
16709 } else {
16710 u16 channel;
16711 WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
16712 channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
16713 freq = wl_channel_to_frequency(channel, CHSPEC_BAND(bi->chanspec));
16714 bss->channel = ieee80211_get_channel(wiphy, freq);
16715#if defined(WL_CFG80211_P2P_DEV_IF)
16716 ie = (const u8 *)bss->ies->data;
16717 ie_len = bss->ies->len;
16718#else
16719 ie = bss->information_elements;
16720 ie_len = bss->len_information_elements;
16721#endif /* WL_CFG80211_P2P_DEV_IF */
16722 beacon_interval = bss->beacon_interval;
16723
16724 CFG80211_PUT_BSS(wiphy, bss);
16725 }
16726
16727 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
16728 if (tim) {
16729 dtim_period = tim->data[1];
16730 } else {
16731 /*
16732 * active scan was done so we could not get dtim
16733 * information out of probe response.
16734 * so we speficially query dtim information.
16735 */
16736 dtim_period = 0;
16737 err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD,
16738 &dtim_period, sizeof(dtim_period));
16739 if (unlikely(err)) {
16740 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
16741 goto update_bss_info_out;
16742 }
16743 }
16744
16745 wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
16746 wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
16747
16748update_bss_info_out:
16749 if (unlikely(err)) {
16750 WL_ERR(("Failed with error %d\n", err));
16751 }
16752
16753 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
16754 mutex_unlock(&cfg->usr_sync);
16755 return err;
16756}
16757
16758static s32
16759wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16760 const wl_event_msg_t *e, void *data)
16761{
16762 struct wl_connect_info *conn_info = wl_to_conn(cfg);
16763 s32 err = 0;
16764 u8 *curbssid;
16765 chanspec_t *chanspec;
16766 scb_val_t scbval;
16767#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16768 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
16769 struct ieee80211_channel *notify_channel = NULL;
16770 u32 freq;
16771 struct channel_info ci;
16772 u32 cur_channel;
16773#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16774#if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16775 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
16776 defined(CFG80211_ROAM_API_GE_4_12)
16777 struct cfg80211_roam_info roam_info;
16778#endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
16779#if defined(WL_FILS_ROAM_OFFLD)
16780 struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
16781 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16782#endif
16783 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16784#ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16785 dhd_if_t *ifp = NULL;
16786#endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
16787#ifdef WLFBT
16788 uint32 data_len = 0;
16789 if (data)
16790 data_len = ntoh32(e->datalen);
16791#endif /* WLFBT */
16792
16793 BCM_REFERENCE(dhdp);
16794 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16795 chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
16796#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16797 /* Skip calling cfg80211_roamed If the channels are same and
16798 * the current bssid & the new bssid are same
16799 * Also clear timer roam_timeout.
16800 * Only used on BCM4359 devices.
16801 */
16802 bzero(&ci, sizeof(ci));
16803 if ((wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci,
16804 sizeof(ci))) < 0) {
16805 WL_ERR(("Failed to get current channel !"));
16806 err = BCME_ERROR;
16807 goto fail;
16808 }
16809 cur_channel = dtoh32(ci.hw_channel);
16810 if ((CHSPEC_CHANNEL(*chanspec) == cur_channel) && ((memcmp(curbssid, &e->addr,
16811 ETHER_ADDR_LEN) == 0) || (memcmp(&cfg->last_roamed_addr,
16812 &e->addr, ETHER_ADDR_LEN) == 0))) {
16813 WL_DBG(("BSS already present, Skipping roamed event to"
16814 " upper layer\n"));
16815 goto fail;
16816 }
16817#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16818
16819 if ((err = wl_get_assoc_ies(cfg, ndev)) != BCME_OK) {
16820 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
16821 dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
16822 WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
16823 " upper layer\n"));
16824 /* To make sure disconnect, and fw sync, explictly send dissassoc
16825 * for BSSID 00:00:00:00:00:00 issue
16826 */
16827 bzero(&scbval, sizeof(scb_val_t));
16828 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
16829 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
16830 scbval.val = htod32(scbval.val);
16831 if (wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
16832 sizeof(scb_val_t)) < 0) {
16833 WL_ERR(("WLC_DISASSOC error\n"));
16834 }
16835 goto fail;
16836 }
16837
16838 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID);
16839 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16840 if ((err = wl_update_bss_info(cfg, ndev, true)) != BCME_OK) {
16841 WL_ERR(("failed to update bss info, err=%d\n", err));
16842 goto fail;
16843 }
16844 if (cfg->wlc_ver.wlc_ver_major < PMKDB_WLC_VER) {
16845 wl_update_pmklist(ndev, cfg->pmk_list, err);
16846 }
16847
16848 chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
16849#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16850 /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
16851 freq = wl_channel_to_frequency(wf_chspec_ctlchan(*chanspec), CHSPEC_BAND(*chanspec));
16852 notify_channel = ieee80211_get_channel(wiphy, freq);
16853#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16854#ifdef WLFBT
16855 /* back up the given FBT key for the further supplicant request,
16856 * currently not checking the FBT is enabled for current BSS in DHD,
16857 * because the supplicant decides to take it or not.
16858 */
16859 if (data && (data_len == FBT_KEYLEN)) {
16860 memcpy(cfg->fbt_key, data, FBT_KEYLEN);
16861 }
16862#endif /* WLFBT */
16863#ifdef CUSTOM_LONG_RETRY_LIMIT
16864 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
16865 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
16866 }
16867#endif /* CUSTOM_LONG_RETRY_LIMIT */
16868 DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM),
16869 dhd_net2idx(dhdp->info, ndev), 0);
16870 WL_ERR(("Report roam event to upper layer. " MACDBG " (ch:%d)\n",
16871 MAC2STRDBG((const u8*)(&e->addr)), CHSPEC_CHANNEL(*chanspec)));
16872 wl_cfg80211_check_in4way(cfg, ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
16873
16874#if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16875 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
16876 defined(CFG80211_ROAM_API_GE_4_12)
16877 memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
16878 roam_info.channel = notify_channel;
16879 roam_info.bssid = curbssid;
16880 roam_info.req_ie = conn_info->req_ie;
16881 roam_info.req_ie_len = conn_info->req_ie_len;
16882 roam_info.resp_ie = conn_info->resp_ie;
16883 roam_info.resp_ie_len = conn_info->resp_ie_len;
16884#if defined(WL_FILS_ROAM_OFFLD)
16885 if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
16886 roam_info.fils.kek = fils_info->fils_kek;
16887 roam_info.fils.kek_len = fils_info->fils_kek_len;
16888 roam_info.fils.update_erp_next_seq_num = true;
16889 roam_info.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
16890 roam_info.fils.pmk = fils_info->fils_pmk;
16891 roam_info.fils.pmk_len = fils_info->fils_kek_len;
16892 roam_info.fils.pmkid = fils_info->fils_pmkid;
16893 }
16894#endif
16895 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
16896#else
16897 cfg80211_roamed(ndev,
16898#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16899 notify_channel,
16900#endif
16901 curbssid,
16902 conn_info->req_ie, conn_info->req_ie_len,
16903 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
16904#endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
16905
16906 memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
16907 wl_set_drv_status(cfg, CONNECTED, ndev);
16908
16909#if defined(DHD_ENABLE_BIGDATA_LOGGING)
16910 cfg->roam_count++;
16911#endif /* DHD_ENABLE_BIGDATA_LOGGING */
16912#ifdef WL_BAM
16913 if (wl_adps_bad_ap_check(cfg, &e->addr)) {
16914 if (wl_adps_enabled(cfg, ndev)) {
16915 wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
16916 }
16917 }
16918#endif /* WL_BAM */
16919
16920#ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16921 ifp = dhd_get_ifp(dhdp, e->ifidx);
16922 if (ifp) {
16923 ifp->post_roam_evt = TRUE;
16924 }
16925#endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
16926
16927 return err;
16928
16929fail:
16930#ifdef DHD_LOSSLESS_ROAMING
16931 wl_del_roam_timeout(cfg);
16932#endif /* DHD_LOSSLESS_ROAMING */
16933 return err;
16934}
16935
16936static bool
16937wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16938 struct cfg80211_bss **bss)
16939{
16940 struct wiphy *wiphy;
16941 struct wlc_ssid *ssid;
16942 uint8 *curbssid;
16943 int count = 0;
16944 int ret = false;
16945 u8 cur_ssid[DOT11_MAX_SSID_LEN + 1];
16946
16947 wiphy = bcmcfg_to_wiphy(cfg);
16948 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
16949 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16950 if (!ssid) {
16951 WL_ERR(("No SSID found in the saved profile \n"));
16952 return false;
16953 }
16954
16955 do {
16956 *bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
16957 ssid->SSID, ssid->SSID_len);
16958 if (*bss || (count > 5)) {
16959 break;
16960 }
16961
16962 count++;
16963 msleep(100);
16964 } while (*bss == NULL);
16965
16966 WL_DBG(("cfg80211 bss_ptr:%p loop_cnt:%d\n", *bss, count));
16967 if (*bss) {
16968#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
16969 /* Update the reference count after use. In case of kernel version >= 4.7
16970 * the cfg802_put_bss is called in cfg80211_connect_bss context
16971 */
16972 CFG80211_PUT_BSS(wiphy, *bss);
16973#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
16974 ret = true;
16975 } else {
16976 memset(cur_ssid, 0, DOT11_MAX_SSID_LEN);
16977 strncpy(cur_ssid, ssid->SSID,
16978 MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN));
16979 WL_ERR(("No bss entry for ssid:%s bssid:"MACDBG"\n",
16980 cur_ssid, MAC2STRDBG(curbssid)));
16981 }
16982
16983 return ret;
16984}
16985
16986#ifdef WL_FILS
16987static s32
16988wl_get_fils_connect_params(struct bcm_cfg80211 *cfg, struct net_device *ndev)
16989{
16990 const bcm_xtlv_t* pxtlv_out;
16991 struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
16992 int err = BCME_OK;
16993 bcm_iov_buf_t *iov_buf_in = NULL;
16994 bcm_iov_buf_t iov_buf_out = {0};
16995 u16 len;
16996 u16 type;
16997 const u8 *data;
16998 iov_buf_in = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
16999 if (!iov_buf_in) {
17000 WL_ERR(("buf memory alloc failed\n"));
17001 err = BCME_NOMEM;
17002 goto exit;
17003 }
17004 iov_buf_out.version = WL_FILS_IOV_VERSION;
17005 iov_buf_out.id = WL_FILS_CMD_GET_CONNECT_PARAMS;
17006 err = wldev_iovar_getbuf(ndev, "fils", (uint8*)&iov_buf_out, sizeof(bcm_iov_buf_t),
17007 iov_buf_in, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
17008 if (unlikely(err)) {
17009 WL_ERR(("Get FILS Params Error (%d)\n", err));
17010 goto exit;
17011 }
17012 pxtlv_out = (bcm_xtlv_t*)((bcm_iov_buf_t*)iov_buf_in)->data;
17013 len = iov_buf_in->len;
17014 do {
17015 if (!bcm_valid_xtlv(pxtlv_out, iov_buf_in->len, BCM_XTLV_OPTION_ALIGN32)) {
17016 WL_ERR(("%s: XTLV is not valid\n", __func__));
17017 err = BCME_BADARG;
17018 goto exit;
17019 }
17020 bcm_xtlv_unpack_xtlv(pxtlv_out, &type, &len, &data, BCM_XTLV_OPTION_ALIGN32);
17021 switch (type) {
17022 case WL_FILS_XTLV_ERP_NEXT_SEQ_NUM:
17023 fils_info->fils_erp_next_seq_num = *(const u16 *)data;
17024 break;
17025 case WL_FILS_XTLV_KEK:
17026 if (memcpy_s(fils_info->fils_kek,
17027 WL_MAX_FILS_KEY_LEN, data, len) < 0) {
17028 err = BCME_BADARG;
17029 goto exit;
17030 }
17031 fils_info->fils_kek_len = len;
17032 break;
17033 case WL_FILS_XTLV_PMK:
17034 if (memcpy_s(fils_info->fils_pmk,
17035 WL_MAX_FILS_KEY_LEN, data, len) < 0) {
17036 err = BCME_BADARG;
17037 goto exit;
17038 }
17039 fils_info->fils_pmk_len = len;
17040 break;
17041 case WL_FILS_XTLV_PMKID:
17042 if (memcpy_s(fils_info->fils_pmkid,
17043 WL_MAX_FILS_KEY_LEN, data, len) < 0) {
17044 err = BCME_BADARG;
17045 goto exit;
17046 }
17047 break;
17048 default:
17049 WL_ERR(("%s: wrong XTLV code\n", __func__));
17050 break;
17051
17052 }
17053 } while ((pxtlv_out = bcm_next_xtlv(pxtlv_out, (int *)&iov_buf_in->len,
17054 BCM_XTLV_OPTION_ALIGN32)) && iov_buf_in->len);
17055exit:
17056 if (iov_buf_in) {
17057 MFREE(cfg->osh, iov_buf_in, WLC_IOCTL_SMLEN);
17058 }
17059 return err;
17060}
17061#endif /* WL_FILS */
17062static s32
17063wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
17064 const wl_event_msg_t *e, void *data, bool completed)
17065{
17066 struct wl_connect_info *conn_info = wl_to_conn(cfg);
17067 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
17068 s32 err = 0;
17069#ifdef WL_FILS
17070 struct cfg80211_connect_resp_params resp_params = {0};
17071 struct wl_fils_info *fils_info = NULL;
17072 struct wlc_ssid *ssid = NULL;
17073 struct wiphy *wiphy = NULL;
17074
17075#endif /* WL_FILS */
17076#ifdef ESCAN_RESULT_PATCH
17077 u8 *conn_req_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
17078#endif /* ESCAN_RESULT_PATCH */
17079 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
17080 u32 event_type = ntoh32(e->event_type);
17081 struct cfg80211_bss *bss = NULL;
17082 dhd_pub_t *dhdp;
17083 dhdp = (dhd_pub_t *)(cfg->pub);
17084 BCM_REFERENCE(dhdp);
17085
17086 if (!sec) {
17087 WL_ERR(("sec is NULL\n"));
17088 return -ENODEV;
17089 }
17090 WL_DBG((" enter\n"));
17091#ifdef ESCAN_RESULT_PATCH
17092 if (!conn_req_bssid) {
17093 WL_ERR(("conn_req bssid is null\n"));
17094 return -EINVAL;
17095 }
17096 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
17097 if (memcmp(curbssid, conn_req_bssid, ETHER_ADDR_LEN) == 0) {
17098 WL_INFORM_MEM((" Connected event of connected device "
17099 "e=%d s=%d, ignore it\n",
17100 ntoh32(e->event_type), ntoh32(e->status)));
17101 return err;
17102 }
17103 }
17104 if (ETHER_ISNULLADDR(curbssid) &&
17105 !ETHER_ISNULLADDR(conn_req_bssid)) {
17106 WL_DBG(("copy bssid\n"));
17107 memcpy(curbssid, conn_req_bssid, ETHER_ADDR_LEN);
17108 }
17109#else
17110 if (cfg->scan_request) {
17111 wl_cfg80211_cancel_scan(cfg);
17112 }
17113#endif /* ESCAN_RESULT_PATCH */
17114 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
17115 wl_cfg80211_scan_abort(cfg);
17116 if (completed) {
17117 wl_get_assoc_ies(cfg, ndev);
17118 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
17119 WL_PROF_BSSID);
17120 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
17121 /*
17122 * CFG layer relies on cached IEs (from probe/beacon) to fetch matching bss.
17123 * For cases, there is no match available,
17124 * need to update the cache based on bss info from fw.
17125 */
17126 wl_update_bss_info(cfg, ndev, true);
17127 if (cfg->wlc_ver.wlc_ver_major < PMKDB_WLC_VER) {
17128 wl_update_pmklist(ndev, cfg->pmk_list, err);
17129 }
17130 wl_set_drv_status(cfg, CONNECTED, ndev);
17131#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
17132 if (dhdp->roam_env_detection)
17133 wldev_iovar_setint(ndev, "roam_env_detection",
17134 AP_ENV_INDETERMINATE);
17135#endif /* ROAM_AP_ENV_DETECTION */
17136 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
17137#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
17138 init_completion(&cfg->iface_disable);
17139#else
17140 /* reinitialize completion to clear previous count */
17141 INIT_COMPLETION(cfg->iface_disable);
17142#endif
17143 }
17144#ifdef CUSTOM_SET_CPUCORE
17145 if (wl_get_chan_isvht80(ndev, dhdp)) {
17146 if (ndev == bcmcfg_to_prmry_ndev(cfg))
17147 dhdp->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
17148 else if (is_p2p_group_iface(ndev->ieee80211_ptr))
17149 dhdp->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
17150 dhd_set_cpucore(dhdp, TRUE);
17151 }
17152#endif /* CUSTOM_SET_CPUCORE */
17153#ifdef CUSTOM_LONG_RETRY_LIMIT
17154 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
17155 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
17156 }
17157#endif /* CUSTOM_LONG_RETRY_LIMIT */
17158 bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
17159 }
17160 wl_clr_drv_status(cfg, CONNECTING, ndev);
17161
17162 if (completed) {
17163 if (wl_cfg80211_verify_bss(cfg, ndev, &bss) != true) {
17164 /* If bss entry is not available in the cfg80211 bss cache
17165 * the wireless stack will complain and won't populate
17166 * wdev->current_bss ptr
17167 */
17168 WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
17169 completed = false;
17170 sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
17171 } else if (!ndev->ieee80211_ptr->ssid_len) {
17172 /* In certain cases, the delayed cfg80211 work from
17173 * disconnect context will induce race conditions in
17174 * which the ssid_len will be cleared, but dhd is in
17175 * connecting state. Return connect failure to avoid
17176 * getting locked in connected state.
17177 */
17178 WL_ERR(("ssid_len=0. Indicate assoc event failure\n"));
17179 completed = false;
17180 sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
17181 }
17182 }
17183 if (completed) {
17184 WL_MSG(ndev->name, "Report connect result - connection succeeded\n");
17185 wl_cfg80211_check_in4way(cfg, ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
17186 } else {
17187 WL_MSG(ndev->name, "Report connect result - connection failed\n");
17188 wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY|WAIT_DISCONNECTED,
17189 WL_EXT_STATUS_DISCONNECTED, NULL);
17190 }
17191#ifdef WL_FILS
17192 if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
17193 wl_get_fils_connect_params(cfg, ndev);
17194 fils_info = wl_to_fils_info(cfg);
17195 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
17196 wiphy = bcmcfg_to_wiphy(cfg);
17197 resp_params.status = completed ? WLAN_STATUS_SUCCESS :
17198 (sec->auth_assoc_res_status) ?
17199 sec->auth_assoc_res_status :
17200 WLAN_STATUS_UNSPECIFIED_FAILURE;
17201 resp_params.bssid = curbssid;
17202 resp_params.bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
17203 ssid->SSID, ssid->SSID_len);
17204 resp_params.req_ie = conn_info->req_ie;
17205 resp_params.req_ie_len = conn_info->req_ie_len;
17206 resp_params.resp_ie = conn_info->resp_ie;
17207 resp_params.resp_ie_len = conn_info->resp_ie_len;
17208#if defined(WL_FILS_ROAM_OFFLD) || (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0))
17209 resp_params.fils.kek = fils_info->fils_kek;
17210 resp_params.fils.kek_len = fils_info->fils_kek_len;
17211 resp_params.fils.update_erp_next_seq_num = true;
17212 resp_params.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
17213 resp_params.fils.pmk = fils_info->fils_pmk;
17214 resp_params.fils.pmk_len = fils_info->fils_kek_len;
17215 resp_params.fils.pmkid = fils_info->fils_pmkid;
17216#else
17217 resp_params.fils_kek = fils_info->fils_kek;
17218 resp_params.fils_kek_len = fils_info->fils_kek_len;
17219 resp_params.update_erp_next_seq_num = true;
17220 resp_params.fils_erp_next_seq_num = fils_info->fils_erp_next_seq_num;
17221 resp_params.pmk = fils_info->fils_pmk;
17222 resp_params.pmk_len = fils_info->fils_kek_len;
17223 resp_params.pmkid = fils_info->fils_pmkid;
17224#endif /* WL_FILS_ROAM_OFFLD */
17225 cfg80211_connect_done(ndev, &resp_params, GFP_KERNEL);
17226 }
17227 else
17228#endif /* WL_FILS */
17229 {
17230 CFG80211_CONNECT_RESULT(ndev,
17231 curbssid,
17232 bss,
17233 conn_info->req_ie,
17234 conn_info->req_ie_len,
17235 conn_info->resp_ie,
17236 conn_info->resp_ie_len,
17237 completed ? WLAN_STATUS_SUCCESS :
17238 (sec->auth_assoc_res_status) ?
17239 sec->auth_assoc_res_status :
17240 WLAN_STATUS_UNSPECIFIED_FAILURE,
17241 GFP_KERNEL);
17242 }
17243 CLR_TS(cfg, conn_start);
17244 if (completed) {
17245 LOG_TS(cfg, conn_cmplt);
17246 LOG_TS(cfg, authorize_start);
17247#ifdef BCMWAPI_WPI
17248 if (sec->cipher_group == WLAN_CIPHER_SUITE_SMS4) {
17249 /* In WAPI case, there is no seperate authorized call
17250 * from upper layer. so set the state from connect done.
17251 */
17252 wl_set_drv_status(cfg, AUTHORIZED, ndev);
17253 CLR_TS(cfg, authorize_start);
17254 LOG_TS(cfg, authorize_cmplt);
17255 }
17256#endif /* WAPI */
17257
17258#if defined(CONFIG_TIZEN)
17259 net_stat_tizen_update_wifi(ndev, WIFISTAT_CONNECTION);
17260#endif /* CONFIG_TIZEN */
17261#ifdef WL_BAM
17262 if (wl_adps_bad_ap_check(cfg, &e->addr)) {
17263 if (wl_adps_enabled(cfg, ndev)) {
17264 wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
17265 }
17266 }
17267#endif /* WL_BAM */
17268 }
17269 } else {
17270 WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
17271 " connecting:%x. connected:%d\n",
17272 ndev->name, event_type, wl_get_drv_status(cfg, CONNECTING, ndev),
17273 wl_get_drv_status(cfg, CONNECTED, ndev)));
17274 }
17275#ifdef CONFIG_TCPACK_FASTTX
17276 if (wl_get_chan_isvht80(ndev, dhdp))
17277 wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
17278 else
17279 wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
17280#endif /* CONFIG_TCPACK_FASTTX */
17281
17282 return err;
17283}
17284
17285static s32
17286wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17287 const wl_event_msg_t *e, void *data)
17288{
17289 struct net_device *ndev = NULL;
17290 u16 flags = ntoh16(e->flags);
17291 enum nl80211_key_type key_type;
17292
17293 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17294
17295 WL_INFORM_MEM(("[%s] mic fail event - " MACDBG " \n",
17296 ndev->name, MAC2STRDBG(e->addr.octet)));
17297 mutex_lock(&cfg->usr_sync);
17298 if (flags & WLC_EVENT_MSG_GROUP)
17299 key_type = NL80211_KEYTYPE_GROUP;
17300 else
17301 key_type = NL80211_KEYTYPE_PAIRWISE;
17302
17303 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
17304 cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1,
17305 NULL, GFP_KERNEL);
17306 mutex_unlock(&cfg->usr_sync);
17307
17308 return 0;
17309}
17310
17311#ifdef BT_WIFI_HANDOVER
17312static s32
17313wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17314 const wl_event_msg_t *e, void *data)
17315{
17316 struct net_device *ndev = NULL;
17317 u32 event = ntoh32(e->event_type);
17318 u32 datalen = ntoh32(e->datalen);
17319 s32 err;
17320
17321 WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen));
17322 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17323 err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0);
17324
17325 return err;
17326}
17327#endif /* BT_WIFI_HANDOVER */
17328
17329static s32
17330wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
17331 const struct ether_addr *da, const struct ether_addr *sa,
17332 const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody)
17333{
17334 struct dot11_management_header *hdr;
17335 u32 totlen = 0;
17336 s32 err = 0;
17337 u8 *offset;
17338 u32 prebody_len = *body_len;
17339 switch (fc) {
17340 case FC_ASSOC_REQ:
17341 /* capability , listen interval */
17342 totlen = DOT11_ASSOC_REQ_FIXED_LEN;
17343 *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
17344 break;
17345
17346 case FC_REASSOC_REQ:
17347 /* capability, listen inteval, ap address */
17348 totlen = DOT11_REASSOC_REQ_FIXED_LEN;
17349 *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
17350 break;
17351 }
17352 totlen += DOT11_MGMT_HDR_LEN + prebody_len;
17353 *pheader = (u8 *)MALLOCZ(cfg->osh, totlen);
17354 if (*pheader == NULL) {
17355 WL_ERR(("memory alloc failed \n"));
17356 return -ENOMEM;
17357 }
17358 hdr = (struct dot11_management_header *) (*pheader);
17359 hdr->fc = htol16(fc);
17360 hdr->durid = 0;
17361 hdr->seq = 0;
17362 offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
17363 bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
17364 bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
17365 bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
17366 if ((pbody != NULL) && prebody_len)
17367 bcopy((const char*)pbody, offset, prebody_len);
17368 *body_len = totlen;
17369 return err;
17370}
17371
17372#ifdef WL_CFG80211_GON_COLLISION
17373static void
17374wl_gon_req_collision(struct bcm_cfg80211 *cfg, wl_action_frame_t *tx_act_frm,
17375 wifi_p2p_pub_act_frame_t *rx_act_frm, struct net_device *ndev,
17376 struct ether_addr sa, struct ether_addr da)
17377{
17378 if (cfg->afx_hdl->pending_tx_act_frm == NULL)
17379 return;
17380
17381 if (tx_act_frm &&
17382 wl_cfgp2p_is_pub_action(tx_act_frm->data, tx_act_frm->len)) {
17383 wifi_p2p_pub_act_frame_t *pact_frm;
17384
17385 pact_frm = (wifi_p2p_pub_act_frame_t *)tx_act_frm->data;
17386
17387 if (!(pact_frm->subtype == P2P_PAF_GON_REQ &&
17388 rx_act_frm->subtype == P2P_PAF_GON_REQ)) {
17389 return;
17390 }
17391 }
17392
17393 WL_ERR((" GO NEGO Request COLLISION !!! \n"));
17394
17395 /* if sa(peer) addr is less than da(my) addr,
17396 * my device will process peer's gon request and block to send my gon req.
17397 *
17398 * if not (sa addr > da addr),
17399 * my device will process gon request and drop gon req of peer.
17400 */
17401 if (memcmp(sa.octet, da.octet, ETHER_ADDR_LEN) < 0) {
17402 /* block to send tx gon request */
17403 cfg->block_gon_req_tx_count = BLOCK_GON_REQ_MAX_NUM;
17404 WL_ERR((" block to send gon req tx !!!\n"));
17405
17406 /* if we are finding a common channel for sending af,
17407 * do not scan more to block to send current gon req
17408 */
17409 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17410 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, ndev);
17411 complete(&cfg->act_frm_scan);
17412 }
17413 } else {
17414 /* drop gon request of peer to process gon request by my device. */
17415 WL_ERR((" drop to receive gon req rx !!! \n"));
17416 cfg->block_gon_req_rx_count = BLOCK_GON_REQ_MAX_NUM;
17417 }
17418
17419 return;
17420}
17421#endif /* WL_CFG80211_GON_COLLISION */
17422
17423void
17424wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 bsscfgidx)
17425{
17426 s32 err = 0;
17427
17428 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17429 if (timer_pending(&cfg->p2p->listen_timer)) {
17430 del_timer_sync(&cfg->p2p->listen_timer);
17431 }
17432 if (cfg->afx_hdl != NULL) {
17433 if (cfg->afx_hdl->dev != NULL) {
17434 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
17435 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev);
17436 }
17437 cfg->afx_hdl->peer_chan = WL_INVALID;
17438 }
17439 complete(&cfg->act_frm_scan);
17440 WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
17441 } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
17442 if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
17443 wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
17444 wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
17445
17446 WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx));
17447 /* Scan engine is not used for sending action frames in the latest driver
17448 * branches. actframe_abort is used in the latest driver branches
17449 * instead of scan abort.
17450 * If actframe_abort iovar succeeds, don't execute scan abort.
17451 * If actframe_abort fails with unsupported error,
17452 * execute scan abort (for backward copmatibility).
17453 */
17454 if (cfg->af_sent_channel) {
17455 err = wldev_iovar_setint_bsscfg(ndev, "actframe_abort", 1, bsscfgidx);
17456 if (err < 0) {
17457 if (err == BCME_UNSUPPORTED) {
17458 wl_cfg80211_scan_abort(cfg);
17459 } else {
17460 WL_ERR(("actframe_abort failed. ret:%d\n", err));
17461 }
17462 }
17463 }
17464 }
17465#ifdef WL_CFG80211_SYNC_GON
17466 else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
17467 WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
17468 /* So abort scan to cancel listen */
17469 wl_cfg80211_scan_abort(cfg);
17470 }
17471#endif /* WL_CFG80211_SYNC_GON */
17472}
17473
17474#if defined(WLTDLS)
17475bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len)
17476{
17477 unsigned char *data;
17478
17479 if (frame == NULL) {
17480 WL_ERR(("Invalid frame \n"));
17481 return false;
17482 }
17483
17484 if (frame_len < 5) {
17485 WL_ERR(("Invalid frame length [%d] \n", frame_len));
17486 return false;
17487 }
17488
17489 data = frame;
17490
17491 if (!memcmp(data, TDLS_TUNNELED_PRB_REQ, 5) ||
17492 !memcmp(data, TDLS_TUNNELED_PRB_RESP, 5)) {
17493 WL_DBG(("TDLS Vendor Specific Received type\n"));
17494 return true;
17495 }
17496
17497 return false;
17498}
17499#endif /* WLTDLS */
17500
17501#if defined(WES_SUPPORT)
17502int wl_cfg80211_set_wes_mode(struct net_device *dev, int mode)
17503{
17504 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17505 cfg->wes_mode = mode;
17506 return 0;
17507}
17508
17509int wl_cfg80211_get_wes_mode(struct net_device *dev)
17510{
17511 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17512 return cfg->wes_mode;
17513}
17514
17515bool wl_cfg80211_is_wes(void *frame, u32 frame_len)
17516{
17517 unsigned char *data;
17518
17519 if (frame == NULL) {
17520 WL_ERR(("Invalid frame \n"));
17521 return false;
17522 }
17523
17524 if (frame_len < 4) {
17525 WL_ERR(("Invalid frame length [%d] \n", frame_len));
17526 return false;
17527 }
17528
17529 data = frame;
17530
17531 if (memcmp(data, "\x7f\x00\x00\xf0", 4) == 0) {
17532 WL_DBG(("Receive WES VS Action Frame \n"));
17533 return true;
17534 }
17535
17536 return false;
17537}
17538
17539int
17540wl_cfg80211_set_ncho_mode(struct net_device *dev, int mode)
17541{
17542 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17543 cfg->ncho_mode = mode;
17544 return BCME_OK;
17545}
17546
17547int
17548wl_cfg80211_get_ncho_mode(struct net_device *dev)
17549{
17550 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17551 return cfg->ncho_mode;
17552}
17553#endif /* WES_SUPPORT */
17554
17555int wl_cfg80211_get_ioctl_version(void)
17556{
17557 return ioctl_version;
17558}
17559
17560static s32
17561wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17562 const wl_event_msg_t *e, void *data)
17563{
17564 struct ether_addr da;
17565 struct ether_addr bssid;
17566 bool isfree = false;
17567 s32 err = 0;
17568 s32 freq;
17569 struct net_device *ndev = NULL;
17570 wifi_p2p_pub_act_frame_t *act_frm = NULL;
17571 wifi_p2p_action_frame_t *p2p_act_frm = NULL;
17572 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
17573 wl_event_rx_frame_data_t *rxframe;
17574 u32 event;
17575 u8 *mgmt_frame;
17576 u8 bsscfgidx;
17577 u32 mgmt_frame_len;
17578 chanspec_t chspec;
17579#if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
17580 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
17581#endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
17582 if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) {
17583 WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen)));
17584 return -EINVAL;
17585 }
17586 mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_t);
17587 event = ntoh32(e->event_type);
17588 bsscfgidx = e->bsscfgidx;
17589 rxframe = (wl_event_rx_frame_data_t *)data;
17590 if (!rxframe) {
17591 WL_ERR(("rxframe: NULL\n"));
17592 return -EINVAL;
17593 }
17594 chspec = ntoh16(rxframe->channel);
17595 bzero(&bssid, ETHER_ADDR_LEN);
17596 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17597 if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) &&
17598 (event == WLC_E_PROBREQ_MSG)) {
17599 /* Probe req event comes on wlan0 interface even though
17600 * the frame have been received on correct interface(AP)
17601 * in firmware. Find the right interface to pass it up.
17602 * Required for WPS-AP certification 4.2.13.
17603 * TODO/Need a better fix. Current fix doesn't take
17604 * care of dual AP/GO scenarios.
17605 */
17606 struct net_info *iter, *next;
17607 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17608 for_each_ndev(cfg, iter, next) {
17609 GCC_DIAGNOSTIC_POP();
17610 if (iter->ndev && iter->wdev &&
17611 iter->wdev->iftype == NL80211_IFTYPE_AP) {
17612 ndev = iter->ndev;
17613 cfgdev = ndev_to_cfgdev(ndev);
17614 break;
17615 }
17616 }
17617 }
17618
17619#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
17620 freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chspec));
17621#else
17622 freq = wl_channel_to_frequency(wf_chspec_ctlchan(chspec), CHSPEC_BAND(chspec));
17623#endif
17624 if (event == WLC_E_ACTION_FRAME_RX) {
17625 u8 ioctl_buf[WLC_IOCTL_SMLEN];
17626 if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
17627 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx,
17628 NULL)) != BCME_OK) {
17629 WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
17630 goto exit;
17631 }
17632
17633 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
17634 if (err < 0)
17635 WL_ERR(("WLC_GET_BSSID error %d\n", err));
17636 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
17637 err = wl_frame_get_mgmt(cfg, FC_ACTION, &da, &e->addr, &bssid,
17638 &mgmt_frame, &mgmt_frame_len,
17639 (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
17640 if (err < 0) {
17641 WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
17642 mgmt_frame_len, CHSPEC_CHANNEL(chspec), freq));
17643 goto exit;
17644 }
17645 isfree = true;
17646
17647 wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
17648 mgmt_frame_len - DOT11_MGMT_HDR_LEN, CHSPEC_CHANNEL(chspec));
17649
17650 if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
17651 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
17652 act_frm = (wifi_p2p_pub_act_frame_t *)
17653 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
17654 } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
17655 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
17656 p2p_act_frm = (wifi_p2p_action_frame_t *)
17657 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
17658 (void) p2p_act_frm;
17659 } else if (wl_cfg80211_is_dpp_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
17660 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
17661 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
17662
17663 /* Stop waiting for next AF. */
17664 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
17665 } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
17666 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
17667 sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
17668 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
17669 if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
17670 if (cfg->next_af_subtype == sd_act_frm->action) {
17671 WL_DBG(("We got a right next frame of SD!(%d)\n",
17672 sd_act_frm->action));
17673 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
17674
17675 /* Stop waiting for next AF. */
17676 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
17677 }
17678 }
17679 (void) sd_act_frm;
17680#ifdef WLTDLS
17681 } else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
17682 (wl_cfg80211_is_tdls_tunneled_frame(
17683 &mgmt_frame[DOT11_MGMT_HDR_LEN],
17684 mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
17685 if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
17686 WL_ERR((" TDLS Action Frame Received type = %d \n",
17687 mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
17688 }
17689#ifdef TDLS_MSG_ONLY_WFD
17690 if (!dhdp->tdls_mode) {
17691 WL_DBG((" TDLS Frame filtered \n"));
17692 goto exit;
17693 }
17694#else
17695 if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
17696 cfg->tdls_mgmt_frame = mgmt_frame;
17697 cfg->tdls_mgmt_frame_len = mgmt_frame_len;
17698 cfg->tdls_mgmt_freq = freq;
17699 return 0;
17700 }
17701#endif /* TDLS_MSG_ONLY_WFD */
17702#endif /* WLTDLS */
17703#ifdef QOS_MAP_SET
17704 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
17705 /* update QoS map set table */
17706 bcm_tlv_t * qos_map_ie = NULL;
17707 uint8 offset = DOT11_MGMT_HDR_LEN + DOT11_ACTION_FRMHDR_LEN;
17708 if ((qos_map_ie = bcm_parse_tlvs(&mgmt_frame[offset],
17709 mgmt_frame_len - offset, DOT11_MNG_QOS_MAP_ID)) != NULL) {
17710 WL_DBG((" QoS map set IE found in QoS action frame\n"));
17711 if (!cfg->up_table) {
17712 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
17713 }
17714 wl_set_up_table(cfg->up_table, qos_map_ie);
17715 } else {
17716 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
17717 }
17718#endif /* QOS_MAP_SET */
17719#ifdef WBTEXT
17720 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_RRM) {
17721 /* radio measurement category */
17722 switch (mgmt_frame[DOT11_MGMT_HDR_LEN+1]) {
17723 case DOT11_RM_ACTION_NR_REP:
17724 if (wl_cfg80211_recv_nbr_resp(ndev,
17725 &mgmt_frame[DOT11_MGMT_HDR_LEN],
17726 mgmt_frame_len - DOT11_MGMT_HDR_LEN)
17727 == BCME_OK) {
17728 WL_DBG(("RCC updated by nbr response\n"));
17729 }
17730 break;
17731 default:
17732 break;
17733 }
17734#endif /* WBTEXT */
17735 } else {
17736 /* WAR : There is no way to identify DA of action frame as of now.
17737 * We have to modify firmware code to include DA and SA of Act frame
17738 * as event data
17739 */
17740 /*
17741 * if we got normal action frame and ndev is p2p0,
17742 * we have to change ndev from p2p0 to wlan0
17743 */
17744#if defined(WES_SUPPORT)
17745 if (wl_cfg80211_is_wes(&mgmt_frame[DOT11_MGMT_HDR_LEN],
17746 mgmt_frame_len - DOT11_MGMT_HDR_LEN) && cfg->wes_mode == 0) {
17747 /* Ignore WES VS Action frame */
17748 goto exit;
17749 }
17750#endif /* WES_SUPPORT */
17751
17752 /* We need to check proper action frame is received */
17753 if (cfg->next_af_subtype != WL_PUB_AF_STYPE_INVALID) {
17754 u8 action = 0;
17755 if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
17756 mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) {
17757 WL_DBG(("Recived action is not public action frame\n"));
17758 } else if (cfg->next_af_subtype == action) {
17759 WL_DBG(("Recived action is the waiting action(%d)\n",
17760 action));
17761 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
17762
17763 /* Stop waiting for next AF. */
17764 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
17765 }
17766 }
17767 }
17768
17769 if (act_frm) {
17770#ifdef WL_CFG80211_GON_COLLISION
17771 if (act_frm->subtype == P2P_PAF_GON_REQ) {
17772 wl_gon_req_collision(cfg,
17773 &cfg->afx_hdl->pending_tx_act_frm->action_frame,
17774 act_frm, ndev, e->addr, da);
17775
17776 if (cfg->block_gon_req_rx_count) {
17777 WL_ERR(("drop frame GON Req Rx : count (%d)\n",
17778 cfg->block_gon_req_rx_count));
17779 cfg->block_gon_req_rx_count--;
17780 goto exit;
17781 }
17782 } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
17783 /* if go formation done, clear it */
17784 cfg->block_gon_req_tx_count = 0;
17785 cfg->block_gon_req_rx_count = 0;
17786 }
17787#endif /* WL_CFG80211_GON_COLLISION */
17788
17789 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
17790 if (cfg->next_af_subtype == act_frm->subtype) {
17791 WL_DBG(("We got a right next frame!(%d)\n",
17792 act_frm->subtype));
17793 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
17794
17795 if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
17796 OSL_SLEEP(20);
17797 }
17798
17799 /* Stop waiting for next AF. */
17800 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
17801 } else if ((cfg->next_af_subtype == P2P_PAF_GON_RSP) &&
17802 (act_frm->subtype == P2P_PAF_GON_REQ)) {
17803 /* If current received frame is GO NEG REQ and next
17804 * expected frame is GO NEG RESP, do not send it up.
17805 */
17806 WL_ERR(("GO Neg req received while waiting for RESP."
17807 "Discard incoming frame\n"));
17808 goto exit;
17809 }
17810 }
17811 }
17812
17813 if (wl_cfg80211_is_dpp_frame(
17814 (void *)&mgmt_frame[DOT11_MGMT_HDR_LEN],
17815 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
17816 wl_dpp_pa_frame_t *pa =
17817 (wl_dpp_pa_frame_t *)&mgmt_frame[DOT11_MGMT_HDR_LEN];
17818 if (cfg->next_af_subtype == pa->ftype) {
17819 WL_DBG(("matching dpp frm (%d) found. abort dwell\n", pa->ftype));
17820 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
17821
17822 /* Stop waiting for next AF. */
17823 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
17824 }
17825 }
17826 if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
17827 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
17828 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
17829 }
17830 } else if (event == WLC_E_PROBREQ_MSG) {
17831
17832 /* Handle probe reqs frame
17833 * WPS-AP certification 4.2.13
17834 */
17835 struct parsed_ies prbreq_ies;
17836 u32 prbreq_ie_len = 0;
17837 bool pbc = 0;
17838
17839 WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
17840 mgmt_frame = (u8 *)(data);
17841 mgmt_frame_len = ntoh32(e->datalen);
17842 if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) {
17843 WL_ERR(("wrong datalen:%d\n", mgmt_frame_len));
17844 return -EINVAL;
17845 }
17846 prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
17847
17848 /* Parse prob_req IEs */
17849 if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
17850 prbreq_ie_len, &prbreq_ies) < 0) {
17851 WL_ERR(("Prob req get IEs failed\n"));
17852 return 0;
17853 }
17854 if (prbreq_ies.wps_ie != NULL) {
17855 wl_validate_wps_ie(
17856 (const char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
17857 WL_DBG((" wps_ie exist pbc = %d\n", pbc));
17858 /* if pbc method, send prob_req mgmt frame to upper layer */
17859 if (!pbc)
17860 return 0;
17861 } else
17862 return 0;
17863 } else {
17864 mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
17865
17866 /* wpa supplicant use probe request event for restarting another GON Req.
17867 * but it makes GON Req repetition.
17868 * so if src addr of prb req is same as my target device,
17869 * do not send probe request event during sending action frame.
17870 */
17871 if (event == WLC_E_P2P_PROBREQ_MSG) {
17872 WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
17873 "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
17874
17875#ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
17876 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) &&
17877 !memcmp(cfg->afx_hdl->tx_dst_addr.octet, e->addr.octet,
17878 ETHER_ADDR_LEN)) {
17879 if (cfg->afx_hdl->pending_tx_act_frm &&
17880 wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17881 chanspec_t channel = hton16(rxframe->channel);
17882 WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
17883 channel));
17884 cfg->afx_hdl->peer_chan = channel;
17885 complete(&cfg->act_frm_scan);
17886 }
17887 }
17888#endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
17889
17890 /* Filter any P2P probe reqs arriving during the
17891 * GO-NEG Phase
17892 */
17893 if (cfg->p2p &&
17894#if defined(P2P_IE_MISSING_FIX)
17895 cfg->p2p_prb_noti &&
17896#endif
17897 wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
17898 WL_DBG(("Filtering P2P probe_req while "
17899 "being in GO-Neg state\n"));
17900 return 0;
17901 }
17902 }
17903 }
17904
17905 if (discover_cfgdev(cfgdev, cfg))
17906 WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
17907 else
17908 WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
17909#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
17910 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
17911#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
17912 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
17913#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
17914 defined(WL_COMPAT_WIRELESS)
17915 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
17916#else
17917 cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
17918#endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
17919
17920 WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
17921 mgmt_frame_len, ntoh32(e->datalen), CHSPEC_CHANNEL(chspec), freq));
17922exit:
17923 if (isfree) {
17924 MFREE(cfg->osh, mgmt_frame, mgmt_frame_len);
17925 }
17926 return err;
17927}
17928
17929static void wl_init_conf(struct wl_conf *conf)
17930{
17931 WL_DBG(("Enter \n"));
17932 conf->frag_threshold = (u32)-1;
17933 conf->rts_threshold = (u32)-1;
17934 conf->retry_short = (u32)-1;
17935 conf->retry_long = (u32)-1;
17936 conf->tx_power = -1;
17937}
17938
17939static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
17940{
17941 unsigned long flags;
17942 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
17943
17944 if (!profile) {
17945 WL_ERR(("profile null\n"));
17946 return;
17947 }
17948
17949 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
17950 bzero(profile, sizeof(struct wl_profile));
17951 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
17952}
17953
17954static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
17955{
17956 bzero(cfg->evt_handler, sizeof(cfg->evt_handler));
17957
17958 cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
17959 cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
17960 cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
17961 cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
17962 cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
17963 cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
17964 cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
17965 cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
17966 cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
17967 cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
17968 cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
17969 cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
17970 cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
17971 cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
17972 cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
17973 cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
17974 cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
17975 cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
17976 cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
17977 cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
17978 cfg->evt_handler[WLC_E_AUTH_IND] = wl_notify_connect_status;
17979 cfg->evt_handler[WLC_E_ASSOC_RESP_IE] = wl_notify_connect_status;
17980#ifdef PNO_SUPPORT
17981 cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
17982#endif /* PNO_SUPPORT */
17983#ifdef GSCAN_SUPPORT
17984 cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
17985 cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
17986 cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
17987 cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
17988 cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
17989 cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
17990 cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
17991 cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
17992#endif /* GSCAN_SUPPORT */
17993#ifdef RSSI_MONITOR_SUPPORT
17994 cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
17995#endif /* RSSI_MONITOR_SUPPORT */
17996#ifdef WLTDLS
17997 cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
17998#endif /* WLTDLS */
17999 cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
18000#ifdef WLAIBSS
18001 cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail;
18002#endif /* WLAIBSS */
18003#ifdef WL_RELMCAST
18004 cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
18005#endif /* WL_RELMCAST */
18006#ifdef BT_WIFI_HANDOVER
18007 cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
18008#endif
18009#ifdef WL_NAN
18010 cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status;
18011 cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status;
18012#endif /* WL_NAN */
18013 cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
18014 cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
18015#ifdef CUSTOM_EVENT_PM_WAKE
18016 cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
18017#endif /* CUSTOM_EVENT_PM_WAKE */
18018#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
18019 cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
18020#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
18021 cfg->evt_handler[WLC_E_ROAM_START] = wl_notify_roam_start_status;
18022#ifdef WL_BAM
18023 cfg->evt_handler[WLC_E_ADPS] = wl_adps_event_handler;
18024#endif /* WL_BAM */
18025 cfg->evt_handler[WLC_E_PSK_SUP] = wl_cfg80211_sup_event_handler;
18026#ifdef WL_BCNRECV
18027 cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
18028#endif /* WL_BCNRECV */
18029#ifdef WL_MBO
18030 cfg->evt_handler[WLC_E_MBO] = wl_mbo_event_handler;
18031#endif /* WL_MBO */
18032#ifdef WL_CAC_TS
18033 cfg->evt_handler[WLC_E_ADDTS_IND] = wl_cfg80211_cac_event_handler;
18034 cfg->evt_handler[WLC_E_DELTS_IND] = wl_cfg80211_cac_event_handler;
18035#endif /* WL_CAC_TS */
18036#if defined(WL_MBO) || defined(WL_OCE)
18037 cfg->evt_handler[WLC_E_PRUNE] = wl_bssid_prune_event_handler;
18038#endif /* WL_MBO || WL_OCE */
18039#ifdef RTT_SUPPORT
18040 cfg->evt_handler[WLC_E_PROXD] = wl_cfg80211_rtt_event_handler;
18041#endif
18042#ifdef WL_CHAN_UTIL
18043 cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler;
18044#endif /* WL_CHAN_UTIL */
18045#ifdef WL_CLIENT_SAE
18046 cfg->evt_handler[WLC_E_JOIN_START] = wl_notify_start_auth;
18047#endif /* WL_CLIENT_SAE */
18048}
18049
18050#ifdef WL_CLIENT_SAE
18051/** Called by the cfg80211 framework */
18052static s32
18053wl_cfg80211_external_auth(struct wiphy *wiphy,
18054 struct net_device *ndev, struct cfg80211_external_auth_params *ext_auth_param)
18055{
18056 int err = 0;
18057 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
18058 wl_assoc_mgr_cmd_t cmd;
18059
18060 WL_DBG(("Enter\n"));
18061
18062 if (!ext_auth_param ||
18063 ETHER_ISNULLADDR(ext_auth_param->bssid)) {
18064 WL_ERR(("Invalid wl_cfg80211_external_auth param\n"));
18065 return -EINVAL;
18066 }
18067
18068 cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
18069 cmd.length = sizeof(cmd);
18070 cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
18071 cmd.params = WL_ASSOC_MGR_PARAMS_EVENT_NONE;
18072 err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd), cfg->ioctl_buf,
18073 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
18074 if (unlikely(err)) {
18075 WL_ERR(("Failed to pause assoc(%d)\n", err));
18076 }
18077
18078 return err;
18079}
18080#endif /* WL_CLIENT_SAE */
18081
18082#if defined(STATIC_WL_PRIV_STRUCT)
18083static int
18084wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
18085{
18086#ifdef DUAL_ESCAN_RESULT_BUFFER
18087 cfg->escan_info.escan_buf[0] = DHD_OS_PREALLOC(cfg->pub,
18088 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
18089 if (cfg->escan_info.escan_buf[0] == NULL) {
18090 WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
18091 return -ENOMEM;
18092 }
18093
18094 cfg->escan_info.escan_buf[1] = DHD_OS_PREALLOC(cfg->pub,
18095 DHD_PREALLOC_WIPHY_ESCAN1, ESCAN_BUF_SIZE);
18096 if (cfg->escan_info.escan_buf[1] == NULL) {
18097 WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
18098 return -ENOMEM;
18099 }
18100
18101 bzero(cfg->escan_info.escan_buf[0], ESCAN_BUF_SIZE);
18102 bzero(cfg->escan_info.escan_buf[1], ESCAN_BUF_SIZE);
18103 cfg->escan_info.escan_type[0] = 0;
18104 cfg->escan_info.escan_type[1] = 0;
18105#else
18106 cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
18107 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
18108 if (cfg->escan_info.escan_buf == NULL) {
18109 WL_ERR(("Failed to alloc ESCAN_BUF\n"));
18110 return -ENOMEM;
18111 }
18112 bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
18113#endif /* DUAL_ESCAN_RESULT_BUFFER */
18114
18115 return 0;
18116}
18117
18118static void
18119wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
18120{
18121#ifdef DUAL_ESCAN_RESULT_BUFFER
18122 if (cfg->escan_info.escan_buf[0] != NULL) {
18123 cfg->escan_info.escan_buf[0] = NULL;
18124 cfg->escan_info.escan_type[0] = 0;
18125 }
18126
18127 if (cfg->escan_info.escan_buf[1] != NULL) {
18128 cfg->escan_info.escan_buf[1] = NULL;
18129 cfg->escan_info.escan_type[1] = 0;
18130 }
18131#else
18132 if (cfg->escan_info.escan_buf != NULL) {
18133 cfg->escan_info.escan_buf = NULL;
18134 }
18135#endif /* DUAL_ESCAN_RESULT_BUFFER */
18136}
18137#endif /* STATIC_WL_PRIV_STRUCT */
18138
18139static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
18140{
18141 WL_DBG(("Enter \n"));
18142
18143 cfg->scan_results = (struct wl_scan_results *)MALLOCZ(cfg->osh,
18144 WL_SCAN_BUF_MAX);
18145 if (unlikely(!cfg->scan_results)) {
18146 WL_ERR(("Scan results alloc failed\n"));
18147 goto init_priv_mem_out;
18148 }
18149 cfg->conf = (struct wl_conf *)MALLOCZ(cfg->osh, sizeof(*cfg->conf));
18150 if (unlikely(!cfg->conf)) {
18151 WL_ERR(("wl_conf alloc failed\n"));
18152 goto init_priv_mem_out;
18153 }
18154 cfg->scan_req_int = (void *)MALLOCZ(cfg->osh,
18155 sizeof(*cfg->scan_req_int));
18156 if (unlikely(!cfg->scan_req_int)) {
18157 WL_ERR(("Scan req alloc failed\n"));
18158 goto init_priv_mem_out;
18159 }
18160 cfg->ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
18161 if (unlikely(!cfg->ioctl_buf)) {
18162 WL_ERR(("Ioctl buf alloc failed\n"));
18163 goto init_priv_mem_out;
18164 }
18165 cfg->escan_ioctl_buf = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
18166 if (unlikely(!cfg->escan_ioctl_buf)) {
18167 WL_ERR(("Ioctl buf alloc failed\n"));
18168 goto init_priv_mem_out;
18169 }
18170 cfg->extra_buf = (void *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
18171 if (unlikely(!cfg->extra_buf)) {
18172 WL_ERR(("Extra buf alloc failed\n"));
18173 goto init_priv_mem_out;
18174 }
18175 cfg->pmk_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->pmk_list));
18176 if (unlikely(!cfg->pmk_list)) {
18177 WL_ERR(("pmk list alloc failed\n"));
18178 goto init_priv_mem_out;
18179 }
18180#if defined(STATIC_WL_PRIV_STRUCT)
18181 cfg->conn_info = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->conn_info));
18182 if (unlikely(!cfg->conn_info)) {
18183 WL_ERR(("cfg->conn_info alloc failed\n"));
18184 goto init_priv_mem_out;
18185 }
18186 cfg->ie = (void *)MALLOC(cfg->osh, sizeof(*cfg->ie));
18187 if (unlikely(!cfg->ie)) {
18188 WL_ERR(("cfg->ie alloc failed\n"));
18189 goto init_priv_mem_out;
18190 }
18191 if (unlikely(wl_init_escan_result_buf(cfg))) {
18192 WL_ERR(("Failed to init escan resul buf\n"));
18193 goto init_priv_mem_out;
18194 }
18195#endif /* STATIC_WL_PRIV_STRUCT */
18196 cfg->afx_hdl = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->afx_hdl));
18197 if (unlikely(!cfg->afx_hdl)) {
18198 WL_ERR(("afx hdl alloc failed\n"));
18199 goto init_priv_mem_out;
18200 } else {
18201 init_completion(&cfg->act_frm_scan);
18202 init_completion(&cfg->wait_next_af);
18203
18204 INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
18205 }
18206#ifdef WLTDLS
18207 if (cfg->tdls_mgmt_frame) {
18208 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
18209 cfg->tdls_mgmt_frame = NULL;
18210 cfg->tdls_mgmt_frame_len = 0;
18211 }
18212#endif /* WLTDLS */
18213 cfg->spmk_info_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->spmk_info_list));
18214 if (unlikely(!cfg->spmk_info_list)) {
18215 WL_ERR(("Single PMK info list allocation falure\n"));
18216 goto init_priv_mem_out;
18217 }
18218
18219 return 0;
18220
18221init_priv_mem_out:
18222 wl_deinit_priv_mem(cfg);
18223
18224 return -ENOMEM;
18225}
18226
18227static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
18228{
18229 MFREE(cfg->osh, cfg->scan_results, WL_SCAN_BUF_MAX);
18230 MFREE(cfg->osh, cfg->conf, sizeof(*cfg->conf));
18231 MFREE(cfg->osh, cfg->scan_req_int, sizeof(*cfg->scan_req_int));
18232 MFREE(cfg->osh, cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
18233 MFREE(cfg->osh, cfg->escan_ioctl_buf, WLC_IOCTL_MAXLEN);
18234 MFREE(cfg->osh, cfg->extra_buf, WL_EXTRA_BUF_MAX);
18235 MFREE(cfg->osh, cfg->pmk_list, sizeof(*cfg->pmk_list));
18236#if defined(STATIC_WL_PRIV_STRUCT)
18237 MFREE(cfg->osh, cfg->conn_info, sizeof(*cfg->conn_info));
18238 MFREE(cfg->osh, cfg->ie, sizeof(*cfg->ie));
18239 wl_deinit_escan_result_buf(cfg);
18240#endif /* STATIC_WL_PRIV_STRUCT */
18241 if (cfg->afx_hdl) {
18242 cancel_work_sync(&cfg->afx_hdl->work);
18243 MFREE(cfg->osh, cfg->afx_hdl, sizeof(*cfg->afx_hdl));
18244 }
18245 MFREE(cfg->osh, cfg->spmk_info_list, sizeof(*cfg->spmk_info_list));
18246
18247}
18248
18249static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
18250{
18251 int ret = 0;
18252 WL_DBG(("Enter \n"));
18253
18254 /* making separate work queue needs GPL license,
18255 * but some drivers are not in GPL license, so, making seperate queue Android only
18256 */
18257
18258 /* Allocate workqueue for event */
18259 if (!cfg->event_workq) {
18260 cfg->event_workq = alloc_workqueue("dhd_eventd",
18261 WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 1);
18262 }
18263
18264 if (!cfg->event_workq) {
18265 WL_ERR(("event_workq alloc_workqueue failed\n"));
18266 ret = -ENOMEM;
18267 } else {
18268 INIT_WORK(&cfg->event_work, wl_event_handler);
18269 }
18270
18271 return ret;
18272}
18273
18274static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
18275{
18276
18277 if (cfg && cfg->event_workq) {
18278 cancel_work_sync(&cfg->event_work);
18279 destroy_workqueue(cfg->event_workq);
18280 cfg->event_workq = NULL;
18281 }
18282
18283}
18284
18285void wl_terminate_event_handler(struct net_device *dev)
18286{
18287 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18288
18289 if (cfg) {
18290 wl_destroy_event_handler(cfg);
18291 wl_flush_eq(cfg);
18292 }
18293}
18294
18295#ifdef DHD_LOSSLESS_ROAMING
18296static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
18297{
18298 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
18299
18300 /* restore prec_map to ALLPRIO */
18301 dhdp->dequeue_prec_map = ALLPRIO;
18302 if (timer_pending(&cfg->roam_timeout)) {
18303 del_timer_sync(&cfg->roam_timeout);
18304 }
18305
18306}
18307
18308static void wl_roam_timeout(unsigned long data)
18309{
18310 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
18311 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
18312
18313 WL_ERR(("roam timer expired\n"));
18314
18315 /* restore prec_map to ALLPRIO */
18316 dhdp->dequeue_prec_map = ALLPRIO;
18317}
18318
18319#endif /* DHD_LOSSLESS_ROAMING */
18320
18321#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
18322#define CP_CHAN_INFO_RAT_MODE_LTE 3
18323#define CP_CHAN_INFO_RAT_MODE_NR5G 7
18324int g_mhs_chan_for_cpcoex = 0;
18325
18326struct __packed cam_cp_noti_info {
18327 u8 rat;
18328 u32 band;
18329 u32 channel;
18330};
18331
18332int
18333wl_cfg80211_send_msg_to_ril()
18334{
18335 int id, buf = 1;
18336
18337 id = IPC_SYSTEM_CP_CHANNEL_INFO;
18338 dev_ril_bridge_send_msg(id, sizeof(int), &buf);
18339 WL_ERR(("[BeyondX] send message to ril.\n"));
18340
18341 OSL_SLEEP(500);
18342 return 0;
18343}
18344
18345int
18346wl_cfg80211_ril_bridge_notifier_call(struct notifier_block *nb,
18347 unsigned long size, void *buf)
18348{
18349 struct dev_ril_bridge_msg *msg;
18350 struct cam_cp_noti_info *cp_noti_info;
18351 static int mhs_channel_for_4g, mhs_channel_for_5g;
18352 static int recv_msg_4g, recv_msg_5g;
18353
18354 WL_ERR(("[BeyondX] receive message from ril.\n"));
18355 msg = (struct dev_ril_bridge_msg *)buf;
18356
18357 if (msg->dev_id == IPC_SYSTEM_CP_CHANNEL_INFO &&
18358 msg->data_len <= sizeof(struct cam_cp_noti_info)) {
18359 u8 rat;
18360 u32 band;
18361 u32 channel;
18362
18363 cp_noti_info = (struct cam_cp_noti_info *)msg->data;
18364 rat = cp_noti_info->rat;
18365 band = cp_noti_info->band;
18366 channel = cp_noti_info->channel;
18367
18368 /* LTE/5G Band/Freq information => Mobile Hotspot channel mapping.
18369 * LTE/B40: 38650~39649 => Ch.11
18370 * LTE/B41: 39650~41589 => Ch.1
18371 * 5G/N41: 499200~537999 => Ch.1
18372 */
18373 if (rat == CP_CHAN_INFO_RAT_MODE_LTE) {
18374 recv_msg_4g = 1;
18375 if (channel >= 38650 && channel <= 39649) {
18376 mhs_channel_for_4g = 11;
18377 } else if (channel >= 39650 && channel <= 41589) {
18378 mhs_channel_for_4g = 1;
18379 }
18380 }
18381 if (rat == CP_CHAN_INFO_RAT_MODE_NR5G) {
18382 recv_msg_5g = 1;
18383 if (channel >= 499200 && channel <= 537999) {
18384 mhs_channel_for_5g = 1;
18385 }
18386 }
18387
18388 WL_DBG(("[BeyondX] rat: %u, band: %u, channel: %u, mhs_channel_for_4g: %u, "
18389 "mhs_channel_for_5g: %u\n", rat, band, channel,
18390 mhs_channel_for_4g, mhs_channel_for_5g));
18391
18392 if (recv_msg_4g && recv_msg_5g) {
18393 if (mhs_channel_for_4g && mhs_channel_for_5g) {
18394 /* if 4G/B40 + 5G/N41, select channel 6 for MHS */
18395 if (mhs_channel_for_4g == 11 && mhs_channel_for_5g == 1) {
18396 g_mhs_chan_for_cpcoex = 6;
18397 /* if 4G(except for B40) + 5G/N41, select channel 1 for MHS */
18398 } else {
18399 g_mhs_chan_for_cpcoex = 1;
18400 }
18401 } else {
18402 g_mhs_chan_for_cpcoex = mhs_channel_for_4g ? mhs_channel_for_4g :
18403 mhs_channel_for_5g ? mhs_channel_for_5g : 0;
18404 }
18405 mhs_channel_for_4g = mhs_channel_for_5g = 0;
18406 recv_msg_4g = recv_msg_5g = 0;
18407 }
18408 }
18409
18410 return 0;
18411}
18412
18413static struct notifier_block wl_cfg80211_ril_bridge_notifier = {
18414 .notifier_call = wl_cfg80211_ril_bridge_notifier_call,
18415};
18416
18417static bool wl_cfg80211_ril_bridge_notifier_registered = FALSE;
18418#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
18419
18420static s32
18421wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
18422 unsigned long state, void *ptr)
18423{
18424#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
18425 struct net_device *dev = ptr;
18426#else
18427 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
18428#endif /* LINUX_VERSION < VERSION(3, 11, 0) */
18429 struct wireless_dev *wdev = NULL;
18430 struct bcm_cfg80211 *cfg = NULL;
18431
18432 WL_DBG(("Enter state:%lu ndev%p \n", state, dev));
18433 if (!dev) {
18434 WL_ERR(("dev null\n"));
18435 return NOTIFY_DONE;
18436 }
18437
18438 wdev = ndev_to_wdev(dev);
18439 if (!wdev) {
18440 WL_ERR(("wdev null. Do nothing\n"));
18441 return NOTIFY_DONE;
18442 }
18443
18444 cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
18445 if (!cfg || (cfg != wl_cfg80211_get_bcmcfg())) {
18446 /* If cfg80211 priv is null or doesn't match return */
18447 WL_ERR(("wrong cfg ptr (%p)\n", cfg));
18448 return NOTIFY_DONE;
18449 }
18450
18451 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
18452 /* Nothing to be done for primary I/F */
18453 return NOTIFY_DONE;
18454 }
18455
18456 switch (state) {
18457 case NETDEV_DOWN:
18458 {
18459#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
18460 int max_wait_timeout = 2;
18461 int max_wait_count = 100;
18462 int refcnt = 0;
18463 unsigned long limit = jiffies + max_wait_timeout * HZ;
18464 while (work_pending(&wdev->cleanup_work)) {
18465 if (refcnt%5 == 0) {
18466 WL_ERR(("[NETDEV_DOWN] wait for "
18467 "complete of cleanup_work"
18468 " (%d th)\n", refcnt));
18469 }
18470 if (!time_before(jiffies, limit)) {
18471 WL_ERR(("[NETDEV_DOWN] cleanup_work"
18472 " of CFG80211 is not"
18473 " completed in %d sec\n",
18474 max_wait_timeout));
18475 break;
18476 }
18477 if (refcnt >= max_wait_count) {
18478 WL_ERR(("[NETDEV_DOWN] cleanup_work"
18479 " of CFG80211 is not"
18480 " completed in %d loop\n",
18481 max_wait_count));
18482 break;
18483 }
18484 set_current_state(TASK_INTERRUPTIBLE);
18485 (void)schedule_timeout(100);
18486 set_current_state(TASK_RUNNING);
18487 refcnt++;
18488 }
18489#endif /* LINUX_VERSION < VERSION(3, 14, 0) */
18490 break;
18491 }
18492 case NETDEV_UNREGISTER:
18493 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
18494 /* after calling list_del_rcu(&wdev->list) */
18495 wl_dealloc_netinfo_by_wdev(cfg, wdev);
18496 break;
18497 case NETDEV_GOING_DOWN:
18498 /*
18499 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
18500 * In front of door, the function checks whether current scan
18501 * is working or not. If the scanning is still working,
18502 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
18503 */
18504 if (wl_get_drv_status(cfg, SCANNING, dev))
18505 wl_cfg80211_cancel_scan(cfg);
18506 break;
18507 }
18508 return NOTIFY_DONE;
18509}
18510
18511static struct notifier_block wl_cfg80211_netdev_notifier = {
18512 .notifier_call = wl_cfg80211_netdev_notifier_call,
18513};
18514
18515/*
18516 * to make sure we won't register the same notifier twice, otherwise a loop is likely to be
18517 * created in kernel notifier link list (with 'next' pointing to itself)
18518 */
18519static bool wl_cfg80211_netdev_notifier_registered = FALSE;
18520
18521static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
18522{
18523 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
18524 bool p2p_connected = wl_cfgp2p_vif_created(cfg);
18525 struct net_info *iter, *next;
18526
18527 if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT))
18528 return;
18529
18530 WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
18531 enable, p2p_connected, connected_cnt));
18532 /* Disable FW roam when we have a concurrent P2P connection */
18533 if (enable && p2p_connected && connected_cnt > 1) {
18534
18535 /* Mark it as to be reverted */
18536 cfg->roam_flags |= WL_ROAM_REVERT_STATUS;
18537 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18538 for_each_ndev(cfg, iter, next) {
18539 GCC_DIAGNOSTIC_POP();
18540 if (iter->ndev && iter->wdev &&
18541 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
18542 if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE)
18543 == BCME_OK) {
18544 iter->roam_off = TRUE;
18545 }
18546 else {
18547 WL_ERR(("error to enable roam_off\n"));
18548 }
18549 }
18550 }
18551 }
18552 else if (!enable && (cfg->roam_flags & WL_ROAM_REVERT_STATUS)) {
18553 cfg->roam_flags &= ~WL_ROAM_REVERT_STATUS;
18554 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18555 for_each_ndev(cfg, iter, next) {
18556 GCC_DIAGNOSTIC_POP();
18557 if (iter->ndev && iter->wdev &&
18558 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
18559 if (iter->roam_off != WL_INVALID) {
18560 if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE)
18561 == BCME_OK) {
18562 iter->roam_off = FALSE;
18563 }
18564 else {
18565 WL_ERR(("error to disable roam_off\n"));
18566 }
18567 }
18568 }
18569 }
18570 }
18571
18572 return;
18573}
18574
18575static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
18576{
18577 struct net_info *iter, *next;
18578 u32 ctl_chan = 0;
18579 u32 chanspec = 0;
18580 u32 pre_ctl_chan = 0;
18581 u32 band = 0;
18582 u32 pre_band = 0;
18583 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
18584 cfg->vsdb_mode = false;
18585
18586 if (connected_cnt <= 1) {
18587 return;
18588 }
18589 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18590 for_each_ndev(cfg, iter, next) {
18591 GCC_DIAGNOSTIC_POP();
18592 /* p2p discovery iface ndev could be null */
18593 if (iter->ndev) {
18594 chanspec = 0;
18595 ctl_chan = 0;
18596 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
18597 if (wldev_iovar_getint(iter->ndev, "chanspec",
18598 (s32 *)&chanspec) == BCME_OK) {
18599 chanspec = wl_chspec_driver_to_host(chanspec);
18600 ctl_chan = wf_chspec_ctlchan(chanspec);
18601 band = CHSPEC_BAND(chanspec);
18602 wl_update_prof(cfg, iter->ndev, NULL,
18603 &chanspec, WL_PROF_CHAN);
18604 }
18605 if (!cfg->vsdb_mode) {
18606 if (!pre_ctl_chan && ctl_chan) {
18607 pre_ctl_chan = ctl_chan;
18608 pre_band = band;
18609 } else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan) &&
18610 (band == pre_band)) {
18611 cfg->vsdb_mode = true;
18612 }
18613 }
18614 }
18615 }
18616 }
18617 WL_MSG("wlan", "%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel");
18618 return;
18619}
18620
18621int
18622wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211 *cfg)
18623{
18624 struct net_info *iter, *next;
18625 u32 chanspec = 0;
18626 u32 band = 0;
18627 u32 pre_band = 0;
18628 bool is_rsdb_supported = FALSE;
18629 bool rsdb_mode = FALSE;
18630
18631 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
18632
18633 if (!is_rsdb_supported) {
18634 return 0;
18635 }
18636
18637 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18638 for_each_ndev(cfg, iter, next) {
18639 GCC_DIAGNOSTIC_POP();
18640 /* p2p discovery iface ndev could be null */
18641 if (iter->ndev) {
18642 chanspec = 0;
18643 band = 0;
18644 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
18645 if (wldev_iovar_getint(iter->ndev, "chanspec",
18646 (s32 *)&chanspec) == BCME_OK) {
18647 chanspec = wl_chspec_driver_to_host(chanspec);
18648 band = CHSPEC_BAND(chanspec);
18649 }
18650
18651 if (!pre_band && band) {
18652 pre_band = band;
18653 } else if (pre_band && (pre_band != band)) {
18654 rsdb_mode = TRUE;
18655 }
18656 }
18657 }
18658 }
18659 WL_DBG(("RSDB mode is %s\n", rsdb_mode ? "enabled" : "disabled"));
18660
18661 return rsdb_mode;
18662}
18663
18664static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
18665 enum wl_status state, bool set)
18666{
18667 s32 pm = PM_FAST;
18668 s32 err = BCME_OK;
18669 u32 mode;
18670 chanspec_t chspec = 0;
18671 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
18672 dhd_pub_t *dhd = cfg->pub;
18673#ifdef RTT_SUPPORT
18674 rtt_status_info_t *rtt_status;
18675#endif /* RTT_SUPPORT */
18676 if (dhd->busstate == DHD_BUS_DOWN) {
18677 WL_ERR(("busstate is DHD_BUS_DOWN!\n"));
18678 return 0;
18679 }
18680 WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
18681 state, set, _net_info->pm_restore, _net_info->ndev->name));
18682
18683 if (state != WL_STATUS_CONNECTED)
18684 return 0;
18685 mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
18686 if (set) {
18687 wl_cfg80211_concurrent_roam(cfg, 1);
18688 wl_cfg80211_determine_vsdb_mode(cfg);
18689 if (mode == WL_MODE_AP) {
18690 if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
18691 WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
18692 }
18693 pm = PM_OFF;
18694 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
18695 sizeof(pm))) != 0) {
18696 if (err == -ENODEV)
18697 WL_DBG(("%s:netdev not ready\n",
18698 _net_info->ndev->name));
18699 else
18700 WL_ERR(("%s:error (%d)\n",
18701 _net_info->ndev->name, err));
18702
18703 wl_cfg80211_update_power_mode(_net_info->ndev);
18704 }
18705 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
18706#if defined(WLTDLS)
18707 if (wl_cfg80211_is_concurrent_mode(primary_dev)) {
18708 err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
18709 }
18710#endif /* defined(WLTDLS) */
18711
18712#ifdef DISABLE_FRAMEBURST_VSDB
18713 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
18714 wl_cfg80211_is_concurrent_mode(primary_dev) &&
18715 !wl_cfg80211_determine_p2p_rsdb_mode(cfg)) {
18716 wl_cfg80211_set_frameburst(cfg, FALSE);
18717 }
18718#endif /* DISABLE_FRAMEBURST_VSDB */
18719#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18720 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
18721 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
18722 /* Enable frameburst for
18723 * STA/SoftAP concurrent mode
18724 */
18725 wl_cfg80211_set_frameburst(cfg, TRUE);
18726 }
18727#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
18728 } else { /* clear */
18729 chspec = INVCHANSPEC;
18730 /* clear chan information when the net device is disconnected */
18731 wl_update_prof(cfg, _net_info->ndev, NULL, &chspec, WL_PROF_CHAN);
18732 wl_cfg80211_determine_vsdb_mode(cfg);
18733 if (primary_dev == _net_info->ndev) {
18734 pm = PM_FAST;
18735#ifdef RTT_SUPPORT
18736 rtt_status = GET_RTTSTATE(dhd);
18737 if (rtt_status->status != RTT_ENABLED) {
18738#endif /* RTT_SUPPORT */
18739 if (dhd_conf_get_pm(dhd) >= 0)
18740 pm = dhd_conf_get_pm(dhd);
18741 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
18742 sizeof(pm))) != 0) {
18743 if (err == -ENODEV)
18744 WL_DBG(("%s:netdev not ready\n",
18745 _net_info->ndev->name));
18746 else
18747 WL_ERR(("%s:error (%d)\n",
18748 _net_info->ndev->name, err));
18749
18750 wl_cfg80211_update_power_mode(_net_info->ndev);
18751 }
18752#ifdef RTT_SUPPORT
18753 }
18754#endif /* RTT_SUPPORT */
18755 }
18756 wl_cfg80211_concurrent_roam(cfg, 0);
18757#if defined(WLTDLS)
18758 if (!wl_cfg80211_is_concurrent_mode(primary_dev)) {
18759 err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
18760 }
18761#endif /* defined(WLTDLS) */
18762
18763#if defined(DISABLE_FRAMEBURST_VSDB)
18764 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE)) {
18765 wl_cfg80211_set_frameburst(cfg, TRUE);
18766 }
18767#endif /* DISABLE_FRAMEBURST_VSDB */
18768#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18769 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
18770 CHSPEC_IS2G(cfg->ap_oper_channel)) {
18771 /* Disable frameburst for stand-alone 2GHz SoftAP */
18772 wl_cfg80211_set_frameburst(cfg, FALSE);
18773 }
18774#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
18775 }
18776 return err;
18777}
18778
18779#ifdef DHD_LOSSLESS_ROAMING
18780static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
18781{
18782 int err = 0;
18783
18784 /* Init roam timer */
18785 init_timer_compat(&cfg->roam_timeout, wl_roam_timeout, cfg);
18786
18787 return err;
18788}
18789#endif /* DHD_LOSSLESS_ROAMING */
18790
18791#ifdef CONFIG_SLEEP_MONITOR
18792extern long long temp_raw;
18793
18794int wlan_get_sleep_monitor64_cb(void *priv, long long *raw_val,
18795 int check_level, int caller_type)
18796{
18797 struct bcm_cfg80211 *cfg = priv;
18798 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
18799 int state = DEVICE_UNKNOWN;
18800
18801 if (!dhdp->up)
18802 state = DEVICE_POWER_OFF;
18803 else {
18804 state = DEVICE_ON_ACTIVE1;
18805 if (wl_get_drv_status_all(cfg, CONNECTED))
18806 state = DEVICE_ON_ACTIVE2;
18807
18808 if (caller_type == SLEEP_MONITOR_CALL_SUSPEND) {
18809 *raw_val = temp_raw;
18810 temp_raw = 0;
18811 }
18812 }
18813
18814 return state;
18815}
18816
18817static struct sleep_monitor_ops wlan_sleep_monitor_ops = {
18818 .read64_cb_func = wlan_get_sleep_monitor64_cb,
18819};
18820#endif /* CONFIG_SLEEP_MONITOR */
18821
18822static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
18823{
18824 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
18825 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
18826 s32 err = 0;
18827
18828 cfg->scan_request = NULL;
18829 cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
18830#ifdef DISABLE_BUILTIN_ROAM
18831 cfg->roam_on = false;
18832#else
18833 cfg->roam_on = true;
18834#endif /* DISABLE_BUILTIN_ROAM */
18835 cfg->active_scan = true;
18836 cfg->rf_blocked = false;
18837 cfg->vsdb_mode = false;
18838#if defined(BCMSDIO) || defined(BCMDBUS)
18839 cfg->wlfc_on = false;
18840#endif /* BCMSDIO || BCMDBUS */
18841 cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
18842 cfg->disable_roam_event = false;
18843 /* register interested state */
18844 set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
18845 spin_lock_init(&cfg->cfgdrv_lock);
18846 mutex_init(&cfg->ioctl_buf_sync);
18847 init_waitqueue_head(&cfg->netif_change_event);
18848 init_waitqueue_head(&cfg->wps_done_event);
18849 init_completion(&cfg->send_af_done);
18850 init_completion(&cfg->iface_disable);
18851 mutex_init(&cfg->usr_sync);
18852 mutex_init(&cfg->event_sync);
18853 mutex_init(&cfg->if_sync);
18854 mutex_init(&cfg->scan_sync);
18855 mutex_init(&cfg->connect_sync);
18856 mutex_init(&cfg->pm_sync);
18857 mutex_init(&cfg->in4way_sync);
18858#ifdef WLTDLS
18859 mutex_init(&cfg->tdls_sync);
18860#endif /* WLTDLS */
18861#ifdef WL_BCNRECV
18862 mutex_init(&cfg->bcn_sync);
18863#endif /* WL_BCNRECV */
18864#ifdef WL_WPS_SYNC
18865 wl_init_wps_reauth_sm(cfg);
18866#endif /* WL_WPS_SYNC */
18867 wl_init_eq(cfg);
18868 err = wl_init_priv_mem(cfg);
18869 if (err)
18870 return err;
18871 if (wl_create_event_handler(cfg))
18872 return -ENOMEM;
18873 wl_init_event_handler(cfg);
18874 err = wl_init_scan(cfg);
18875 if (err)
18876 return err;
18877#ifdef DHD_LOSSLESS_ROAMING
18878 err = wl_init_roam_timeout(cfg);
18879 if (err) {
18880 return err;
18881 }
18882#endif /* DHD_LOSSLESS_ROAMING */
18883 wl_init_conf(cfg->conf);
18884 wl_init_prof(cfg, ndev);
18885 wl_link_down(cfg);
18886 DNGL_FUNC(dhd_cfg80211_init, (cfg));
18887 cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
18888 cfg->pmk_list->pmkids.count = 0;
18889 cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
18890
18891#ifdef CONFIG_SLEEP_MONITOR
18892 sleep_monitor_register_ops(cfg, &wlan_sleep_monitor_ops,
18893 SLEEP_MONITOR_WIFI);
18894#endif /* CONFIG_SLEEP_MONITOR */
18895 return err;
18896}
18897
18898static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
18899{
18900 DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
18901 wl_destroy_event_handler(cfg);
18902 wl_flush_eq(cfg);
18903 wl_link_down(cfg);
18904 del_timer_sync(&cfg->scan_timeout);
18905#ifdef DHD_LOSSLESS_ROAMING
18906 del_timer_sync(&cfg->roam_timeout);
18907#endif
18908 wl_deinit_priv_mem(cfg);
18909 if (wl_cfg80211_netdev_notifier_registered) {
18910 wl_cfg80211_netdev_notifier_registered = FALSE;
18911 unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
18912 }
18913
18914#ifdef CONFIG_SLEEP_MONITOR
18915 sleep_monitor_unregister_ops(SLEEP_MONITOR_WIFI);
18916#endif /* CONFIG_SLEEP_MONITOR */
18917}
18918
18919#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18920static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
18921{
18922 WL_TRACE(("Enter \n"));
18923
18924 if (wl_cfgp2p_register_ndev(cfg) < 0) {
18925 WL_ERR(("P2P attach failed. \n"));
18926 return -ENODEV;
18927 }
18928
18929 return 0;
18930}
18931
18932static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
18933{
18934#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18935 struct wireless_dev *wdev;
18936#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18937
18938 WL_DBG(("Enter \n"));
18939 if (!cfg) {
18940 WL_ERR(("Invalid Ptr\n"));
18941 return -EINVAL;
18942 }
18943#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18944 else {
18945 wdev = cfg->p2p_wdev;
18946 if (!wdev) {
18947 WL_ERR(("Invalid Ptr\n"));
18948 return -EINVAL;
18949 }
18950 }
18951#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18952
18953 wl_cfgp2p_unregister_ndev(cfg);
18954
18955 cfg->p2p_wdev = NULL;
18956 cfg->p2p_net = NULL;
18957#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18958 WL_DBG(("Freeing 0x%p \n", wdev));
18959 MFREE(cfg->osh, wdev, sizeof(*wdev));
18960#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
18961
18962 return 0;
18963}
18964#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
18965
18966static s32 wl_cfg80211_attach_post(struct net_device *ndev)
18967{
18968 struct bcm_cfg80211 * cfg;
18969 s32 err = 0;
18970 s32 ret = 0;
18971 WL_TRACE(("In\n"));
18972 if (unlikely(!ndev)) {
18973 WL_ERR(("ndev is invaild\n"));
18974 return -ENODEV;
18975 }
18976 cfg = wl_get_cfg(ndev);
18977 if (unlikely(!cfg)) {
18978 WL_ERR(("cfg is invaild\n"));
18979 return -EINVAL;
18980 }
18981 if (!wl_get_drv_status(cfg, READY, ndev)) {
18982 if (cfg->wdev) {
18983 ret = wl_cfgp2p_supported(cfg, ndev);
18984 if (ret > 0) {
18985#if !defined(WL_ENABLE_P2P_IF)
18986 cfg->wdev->wiphy->interface_modes |=
18987 (BIT(NL80211_IFTYPE_P2P_CLIENT)|
18988 BIT(NL80211_IFTYPE_P2P_GO));
18989#endif /* !WL_ENABLE_P2P_IF */
18990 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
18991 goto fail;
18992
18993#if defined(WL_ENABLE_P2P_IF)
18994 if (cfg->p2p_net) {
18995 /* Update MAC addr for p2p0 interface here. */
18996 memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
18997 cfg->p2p_net->dev_addr[0] |= 0x02;
18998 WL_MSG(cfg->p2p_net->name, "p2p_dev_addr="MACDBG "\n",
18999 MAC2STRDBG(cfg->p2p_net->dev_addr));
19000 } else {
19001 WL_ERR(("p2p_net not yet populated."
19002 " Couldn't update the MAC Address for p2p0 \n"));
19003 return -ENODEV;
19004 }
19005#endif /* WL_ENABLE_P2P_IF */
19006 cfg->p2p_supported = true;
19007 } else if (ret == 0) {
19008 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
19009 goto fail;
19010 } else {
19011 /* SDIO bus timeout */
19012 err = -ENODEV;
19013 goto fail;
19014 }
19015 }
19016 }
19017 wl_set_drv_status(cfg, READY, ndev);
19018fail:
19019 return err;
19020}
19021
19022struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev)
19023{
19024 struct wireless_dev *wdev = ndev->ieee80211_ptr;
19025
19026 if (!wdev || !wdev->wiphy)
19027 return NULL;
19028
19029 return wiphy_priv(wdev->wiphy);
19030}
19031
19032s32
19033wl_cfg80211_net_attach(struct net_device *primary_ndev)
19034{
19035 struct bcm_cfg80211 *cfg = wl_get_cfg(primary_ndev);
19036
19037 if (!cfg) {
19038 WL_ERR(("cfg null\n"));
19039 return BCME_ERROR;
19040 }
19041#ifdef WL_STATIC_IF
19042 /* Register dummy n/w iface. FW init will happen only from dev_open */
19043 if (wl_cfg80211_register_static_if(cfg, NL80211_IFTYPE_STATION,
19044 WL_STATIC_IFNAME_PREFIX) == NULL) {
19045 WL_ERR(("static i/f registration failed!\n"));
19046 return BCME_ERROR;
19047 }
19048#endif /* WL_STATIC_IF */
19049 return BCME_OK;
19050}
19051
19052s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
19053{
19054 struct wireless_dev *wdev;
19055 struct bcm_cfg80211 *cfg;
19056 s32 err = 0;
19057 struct device *dev;
19058 u16 bssidx = 0;
19059 u16 ifidx = 0;
19060 dhd_pub_t *dhd = (struct dhd_pub *)(context);
19061
19062 WL_TRACE(("In\n"));
19063 if (!ndev) {
19064 WL_ERR(("ndev is invaild\n"));
19065 return -ENODEV;
19066 }
19067 WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
19068 dev = wl_cfg80211_get_parent_dev();
19069
19070 wdev = (struct wireless_dev *)MALLOCZ(dhd->osh, sizeof(*wdev));
19071 if (unlikely(!wdev)) {
19072 WL_ERR(("Could not allocate wireless device\n"));
19073 return -ENOMEM;
19074 }
19075 err = wl_setup_wiphy(wdev, dev, context);
19076 if (unlikely(err)) {
19077 MFREE(dhd->osh, wdev, sizeof(*wdev));
19078 return -ENOMEM;
19079 }
19080#ifdef WLMESH_CFG80211
19081 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_MESH);
19082#else
19083 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
19084#endif
19085 cfg = wiphy_priv(wdev->wiphy);
19086 cfg->wdev = wdev;
19087 cfg->pub = context;
19088 cfg->osh = dhd->osh;
19089 INIT_LIST_HEAD(&cfg->net_list);
19090#ifdef WBTEXT
19091 INIT_LIST_HEAD(&cfg->wbtext_bssid_list);
19092#endif /* WBTEXT */
19093 INIT_LIST_HEAD(&cfg->vndr_oui_list);
19094 spin_lock_init(&cfg->vndr_oui_sync);
19095 spin_lock_init(&cfg->net_list_sync);
19096 ndev->ieee80211_ptr = wdev;
19097 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
19098 wdev->netdev = ndev;
19099 cfg->state_notifier = wl_notifier_change_state;
19100 err = wl_alloc_netinfo(cfg, ndev, wdev, WL_IF_TYPE_STA, PM_ENABLE, bssidx, ifidx);
19101 if (err) {
19102 WL_ERR(("Failed to alloc net_info (%d)\n", err));
19103 goto cfg80211_attach_out;
19104 }
19105 err = wl_init_priv(cfg);
19106 if (err) {
19107 WL_ERR(("Failed to init iwm_priv (%d)\n", err));
19108 goto cfg80211_attach_out;
19109 }
19110
19111 err = wl_setup_rfkill(cfg, TRUE);
19112 if (err) {
19113 WL_ERR(("Failed to setup rfkill %d\n", err));
19114 goto cfg80211_attach_out;
19115 }
19116#ifdef DEBUGFS_CFG80211
19117 err = wl_setup_debugfs(cfg);
19118 if (err) {
19119 WL_ERR(("Failed to setup debugfs %d\n", err));
19120 goto cfg80211_attach_out;
19121 }
19122#endif
19123 if (!wl_cfg80211_netdev_notifier_registered) {
19124 wl_cfg80211_netdev_notifier_registered = TRUE;
19125 err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
19126 if (err) {
19127 wl_cfg80211_netdev_notifier_registered = FALSE;
19128 WL_ERR(("Failed to register notifierl %d\n", err));
19129 goto cfg80211_attach_out;
19130 }
19131 }
19132
19133#if defined(COEX_DHCP)
19134 cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
19135 if (!cfg->btcoex_info)
19136 goto cfg80211_attach_out;
19137#endif
19138
19139#if defined(SUPPORT_RANDOM_MAC_SCAN)
19140 cfg->random_mac_enabled = FALSE;
19141#endif /* SUPPORT_RANDOM_MAC_SCAN */
19142
19143#ifdef CONFIG_CFG80211_INTERNAL_REGDB
19144 wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
19145#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
19146
19147#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
19148 err = wl_cfg80211_attach_p2p(cfg);
19149 if (err)
19150 goto cfg80211_attach_out;
19151#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
19152
19153 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
19154 INIT_DELAYED_WORK(&cfg->loc.work, wl_cfgscan_listen_complete_work);
19155 mutex_init(&cfg->pm_sync);
19156#ifdef WL_NAN
19157 err = wl_cfgnan_attach(cfg);
19158 if (err) {
19159 WL_ERR(("Failed to attach nan module %d\n", err));
19160 goto cfg80211_attach_out;
19161 }
19162#endif /* WL_NAN */
19163 cfg->rssi_sum_report = FALSE;
19164#ifdef WL_BAM
19165 wl_bad_ap_mngr_init(cfg);
19166#endif /* WL_BAM */
19167
19168#ifdef BIGDATA_SOFTAP
19169 wl_attach_ap_stainfo(cfg);
19170#endif /* BIGDATA_SOFTAP */
19171
19172 return err;
19173
19174cfg80211_attach_out:
19175 wl_cfg80211_detach(cfg);
19176 return err;
19177}
19178
19179void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
19180{
19181 WL_DBG(("Enter\n"));
19182 if (!cfg) {
19183 return;
19184 }
19185/* clean up pm_enable work item. Remove this once deinit is properly
19186 * clean up and wl_cfg8021_down is called while removing the module
19187 */
19188 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
19189
19190#if defined(COEX_DHCP)
19191 wl_cfg80211_btcoex_deinit();
19192 cfg->btcoex_info = NULL;
19193#endif
19194
19195 wl_setup_rfkill(cfg, FALSE);
19196#ifdef DEBUGFS_CFG80211
19197 wl_free_debugfs(cfg);
19198#endif
19199 if (cfg->p2p_supported) {
19200 if (timer_pending(&cfg->p2p->listen_timer))
19201 del_timer_sync(&cfg->p2p->listen_timer);
19202 wl_cfgp2p_deinit_priv(cfg);
19203 }
19204
19205#ifdef WL_WPS_SYNC
19206 wl_deinit_wps_reauth_sm(cfg);
19207#endif /* WL_WPS_SYNC */
19208
19209 if (timer_pending(&cfg->scan_timeout))
19210 del_timer_sync(&cfg->scan_timeout);
19211#ifdef DHD_LOSSLESS_ROAMING
19212 if (timer_pending(&cfg->roam_timeout)) {
19213 del_timer_sync(&cfg->roam_timeout);
19214 }
19215#endif /* DHD_LOSSLESS_ROAMING */
19216
19217#ifdef WL_STATIC_IF
19218 wl_cfg80211_unregister_static_if(cfg);
19219#endif /* WL_STATIC_IF */
19220#if defined(WL_CFG80211_P2P_DEV_IF)
19221 if (cfg->p2p_wdev)
19222 wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
19223#endif /* WL_CFG80211_P2P_DEV_IF */
19224#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
19225 wl_cfg80211_detach_p2p(cfg);
19226#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
19227#ifdef WL_BAM
19228 wl_bad_ap_mngr_deinit(cfg);
19229#endif /* WL_BAM */
19230
19231#ifdef BIGDATA_SOFTAP
19232 wl_detach_ap_stainfo(cfg);
19233#endif /* BIGDATA_SOFTAP */
19234
19235#ifdef WL_NAN
19236 wl_cfgnan_detach(cfg);
19237#endif /* WL_NAN */
19238 wl_cfg80211_ibss_vsie_free(cfg);
19239 wl_dealloc_netinfo_by_wdev(cfg, cfg->wdev);
19240 wl_cfg80211_set_bcmcfg(NULL);
19241 wl_deinit_priv(cfg);
19242 wl_cfg80211_clear_parent_dev();
19243#if defined(RSSIAVG)
19244 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
19245 wl_free_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
19246#endif
19247#if defined(BSSCACHE)
19248 wl_release_bss_cache_ctrl(&cfg->g_bss_cache_ctrl);
19249#endif
19250 wl_free_wdev(cfg);
19251 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
19252 * structure "cfg", which is the private part of wiphy, has been freed in
19253 * wl_free_wdev !!!!!!!!!!!
19254 */
19255 WL_DBG(("Exit\n"));
19256}
19257
19258#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
19259void wl_cfg80211_register_dev_ril_bridge_event_notifier()
19260{
19261 WL_DBG(("Enter\n"));
19262 if (!wl_cfg80211_ril_bridge_notifier_registered) {
19263 s32 err = 0;
19264 wl_cfg80211_ril_bridge_notifier_registered = TRUE;
19265 err = register_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
19266 if (err) {
19267 wl_cfg80211_ril_bridge_notifier_registered = FALSE;
19268 WL_ERR(("Failed to register ril_notifier! %d\n", err));
19269 }
19270 }
19271}
19272
19273void wl_cfg80211_unregister_dev_ril_bridge_event_notifier()
19274{
19275 WL_DBG(("Enter\n"));
19276 if (wl_cfg80211_ril_bridge_notifier_registered) {
19277 wl_cfg80211_ril_bridge_notifier_registered = FALSE;
19278 unregister_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
19279 }
19280}
19281#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
19282
19283static void wl_print_event_data(struct bcm_cfg80211 *cfg,
19284 uint32 event_type, const wl_event_msg_t *e)
19285{
19286 s32 status = ntoh32(e->status);
19287 s32 reason = ntoh32(e->reason);
19288 s32 ifidx = ntoh32(e->ifidx);
19289 s32 bssidx = ntoh32(e->bsscfgidx);
19290
19291 switch (event_type) {
19292 case WLC_E_ESCAN_RESULT:
19293 if ((status == WLC_E_STATUS_SUCCESS) ||
19294 (status == WLC_E_STATUS_ABORT)) {
19295 WL_INFORM_MEM(("event_type (%d), ifidx: %d"
19296 " bssidx: %d scan_type:%d\n",
19297 event_type, ifidx, bssidx, status));
19298 }
19299 break;
19300 case WLC_E_LINK:
19301 case WLC_E_DISASSOC:
19302 case WLC_E_DISASSOC_IND:
19303 case WLC_E_DEAUTH:
19304 case WLC_E_DEAUTH_IND:
19305 WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
19306 " status:%d reason:%d\n",
19307 event_type, ifidx, bssidx, status, reason));
19308 break;
19309
19310 default:
19311 /* Print only when DBG verbose is enabled */
19312 WL_DBG(("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
19313 event_type, ifidx, bssidx, status, reason));
19314 }
19315}
19316
19317static void wl_event_handler(struct work_struct *work_data)
19318{
19319 struct bcm_cfg80211 *cfg = NULL;
19320 struct wl_event_q *e;
19321 struct wireless_dev *wdev = NULL;
19322
19323 WL_DBG(("Enter \n"));
19324 BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
19325 LOG_TS(cfg, wl_evt_hdlr_entry);
19326 DHD_EVENT_WAKE_LOCK(cfg->pub);
19327 while ((e = wl_deq_event(cfg))) {
19328 s32 status = ntoh32(e->emsg.status);
19329 u32 event_type = ntoh32(e->emsg.event_type);
19330 bool scan_cmplt_evt = (event_type == WLC_E_ESCAN_RESULT) &&
19331 ((status == WLC_E_STATUS_SUCCESS) || (status == WLC_E_STATUS_ABORT));
19332
19333 LOG_TS(cfg, wl_evt_deq);
19334 if (scan_cmplt_evt) {
19335 LOG_TS(cfg, scan_deq);
19336 }
19337 /* Print only critical events to avoid too many prints */
19338 wl_print_event_data(cfg, e->etype, &e->emsg);
19339
19340 if (e->emsg.ifidx > WL_MAX_IFS) {
19341 WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
19342 goto fail;
19343 }
19344
19345 /* Make sure iface operations, don't creat race conditions */
19346 mutex_lock(&cfg->if_sync);
19347 if (!(wdev = wl_get_wdev_by_fw_idx(cfg,
19348 e->emsg.bsscfgidx, e->emsg.ifidx))) {
19349 /* For WLC_E_IF would be handled by wl_host_event */
19350 if (e->etype != WLC_E_IF)
19351 WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
19352 " Ignoring event.\n", e->emsg.bsscfgidx));
19353 } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
19354 dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
19355 if (dhd->busstate == DHD_BUS_DOWN) {
19356 WL_ERR((": BUS is DOWN.\n"));
19357 } else
19358 {
19359 WL_DBG(("event_type %d event_sub %d\n",
19360 ntoh32(e->emsg.event_type),
19361 ntoh32(e->emsg.reason)));
19362 cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
19363 &e->emsg, e->edata);
19364 if (scan_cmplt_evt) {
19365 LOG_TS(cfg, scan_hdlr_cmplt);
19366 }
19367 }
19368 } else {
19369 WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
19370 }
19371 mutex_unlock(&cfg->if_sync);
19372fail:
19373 wl_put_event(cfg, e);
19374 if (scan_cmplt_evt) {
19375 LOG_TS(cfg, scan_cmplt);
19376 }
19377 LOG_TS(cfg, wl_evt_hdlr_exit);
19378 }
19379 DHD_EVENT_WAKE_UNLOCK(cfg->pub);
19380}
19381
19382/*
19383* Generic API to handle critical events which doesnt need
19384* cfg enquening and sleepable API calls.
19385*/
19386s32
19387wl_cfg80211_handle_critical_events(struct bcm_cfg80211 *cfg,
19388 const wl_event_msg_t * e)
19389{
19390 s32 ret = BCME_ERROR;
19391 u32 event_type = ntoh32(e->event_type);
19392
19393 if (event_type >= WLC_E_LAST) {
19394 return BCME_ERROR;
19395 }
19396
19397 switch (event_type) {
19398 case WLC_E_NAN_CRITICAL: {
19399#ifdef WL_NAN
19400 if (ntoh32(e->reason) == WL_NAN_EVENT_STOP) {
19401 WL_DBG(("Received WL_NAN_EVENT_STOP\n"));
19402 }
19403#endif /* WL_NAN */
19404 break;
19405 }
19406 default:
19407 ret = BCME_ERROR;
19408 }
19409 return ret;
19410}
19411
19412void
19413wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
19414{
19415 s32 status = ntoh32(e->status);
19416 u32 event_type = ntoh32(e->event_type);
19417 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
19418 struct net_info *netinfo;
19419
19420 WL_DBG(("event_type (%d): reason (%d): %s\n", event_type, ntoh32(e->reason),
19421 bcmevent_get_name(event_type)));
19422 if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
19423 WL_ERR(("Stale event ignored\n"));
19424 return;
19425 }
19426
19427 if (cfg->event_workq == NULL) {
19428 WL_ERR(("Event handler is not created\n"));
19429 return;
19430 }
19431
19432 if (event_type == WLC_E_IF) {
19433 /* Don't process WLC_E_IF events in wl_cfg80211 layer */
19434 return;
19435 }
19436
19437 netinfo = wl_get_netinfo_by_fw_idx(cfg, e->bsscfgidx, e->ifidx);
19438 if (!netinfo) {
19439 /* Since the netinfo entry is not there, the netdev entry is not
19440 * created via cfg80211 interface. so the event is not of interest
19441 * to the cfg80211 layer.
19442 */
19443 WL_TRACE(("ignore event %d, not interested\n", event_type));
19444 return;
19445 }
19446
19447 /* Handle wl_cfg80211_critical_events */
19448 if (wl_cfg80211_handle_critical_events(cfg, e) == BCME_OK) {
19449 return;
19450 }
19451
19452 if (event_type == WLC_E_PFN_NET_FOUND) {
19453 WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
19454 }
19455 else if (event_type == WLC_E_PFN_NET_LOST) {
19456 WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
19457 }
19458
19459 if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
19460
19461 queue_work(cfg->event_workq, &cfg->event_work);
19462
19463 }
19464 /* Mark timeout value for thread sched */
19465 if ((event_type == WLC_E_ESCAN_RESULT) &&
19466 ((status == WLC_E_STATUS_SUCCESS) ||
19467 (status == WLC_E_STATUS_ABORT))) {
19468 LOG_TS(cfg, scan_enq);
19469 WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
19470 status, work_busy(&cfg->event_work)));
19471 }
19472}
19473
19474static void wl_init_eq(struct bcm_cfg80211 *cfg)
19475{
19476 wl_init_eq_lock(cfg);
19477 INIT_LIST_HEAD(&cfg->eq_list);
19478}
19479
19480static void wl_flush_eq(struct bcm_cfg80211 *cfg)
19481{
19482 struct wl_event_q *e;
19483 unsigned long flags;
19484
19485 flags = wl_lock_eq(cfg);
19486 while (!list_empty_careful(&cfg->eq_list)) {
19487 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
19488 list_del(&e->eq_list);
19489 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
19490 }
19491 wl_unlock_eq(cfg, flags);
19492}
19493
19494/*
19495* retrieve first queued event from head
19496*/
19497
19498static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
19499{
19500 struct wl_event_q *e = NULL;
19501 unsigned long flags;
19502
19503 flags = wl_lock_eq(cfg);
19504 if (likely(!list_empty(&cfg->eq_list))) {
19505 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
19506 list_del(&e->eq_list);
19507 }
19508 wl_unlock_eq(cfg, flags);
19509
19510 return e;
19511}
19512
19513/*
19514 * push event to tail of the queue
19515 */
19516
19517static s32
19518wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event,
19519 const wl_event_msg_t *msg, void *data)
19520{
19521 struct wl_event_q *e;
19522 s32 err = 0;
19523 uint32 evtq_size;
19524 uint32 data_len;
19525 unsigned long flags;
19526
19527 data_len = 0;
19528 if (data)
19529 data_len = ntoh32(msg->datalen);
19530 evtq_size = (uint32)(sizeof(struct wl_event_q) + data_len);
19531 e = (struct wl_event_q *)MALLOCZ(cfg->osh, evtq_size);
19532 if (unlikely(!e)) {
19533 WL_ERR(("event alloc failed\n"));
19534 return -ENOMEM;
19535 }
19536 e->etype = event;
19537 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
19538 if (data)
19539 memcpy(e->edata, data, data_len);
19540 e->datalen = data_len;
19541 flags = wl_lock_eq(cfg);
19542 list_add_tail(&e->eq_list, &cfg->eq_list);
19543 wl_unlock_eq(cfg, flags);
19544
19545 return err;
19546}
19547
19548static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e)
19549{
19550 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
19551}
19552
19553static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype)
19554{
19555 s32 infra = 0;
19556 s32 err = 0;
19557 bool skip_infra = false;
19558
19559 switch (iftype) {
19560 case WL_IF_TYPE_IBSS:
19561 case WL_IF_TYPE_AIBSS:
19562 infra = 0;
19563 break;
19564 case WL_IF_TYPE_AP:
19565 case WL_IF_TYPE_STA:
19566 case WL_IF_TYPE_P2P_GO:
19567 case WL_IF_TYPE_P2P_GC:
19568 /* Intentional fall through */
19569 infra = 1;
19570 break;
19571#ifdef WLMESH_CFG80211
19572 case NL80211_IFTYPE_MESH_POINT:
19573 infra = WL_BSSTYPE_MESH;
19574 break;
19575#endif /* WLMESH_CFG80211 */
19576 case WL_IF_TYPE_MONITOR:
19577
19578 case WL_IF_TYPE_NAN:
19579 /* Intentionall fall through */
19580 default:
19581 skip_infra = true;
19582 WL_ERR(("Skipping infra setting for type:%d\n", iftype));
19583 break;
19584 }
19585
19586 /* /TODO Infra iovar is stored in default bss first and
19587 * then applied to the next upcoming bss. so if there is
19588 * some other concurrent bss coming up in parallel, it
19589 * can cause problem. Ideally this iovar should get directly
19590 * applied on the target bsscfg.
19591 */
19592 if (!skip_infra) {
19593 infra = htod32(infra);
19594 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
19595 if (unlikely(err)) {
19596 WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
19597 return err;
19598 }
19599 }
19600 return 0;
19601}
19602
19603void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set)
19604{
19605 if (!ev || (event > WLC_E_LAST))
19606 return;
19607
19608 if (ev->num < MAX_EVENT_BUF_NUM) {
19609 ev->event[ev->num].type = event;
19610 ev->event[ev->num].set = set;
19611 ev->num++;
19612 } else {
19613 WL_ERR(("evenbuffer doesn't support > %u events. Update"
19614 " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
19615 ASSERT(0);
19616 }
19617}
19618
19619s32 wl_cfg80211_apply_eventbuffer(
19620 struct net_device *ndev,
19621 struct bcm_cfg80211 *cfg,
19622 wl_eventmsg_buf_t *ev)
19623{
19624 int i, ret = BCME_OK;
19625 s8 event_buf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE] = {0};
19626 /* Room for "event_msgs_ext" + '\0' + bitvec */
19627 char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16];
19628 eventmsgs_ext_t *eventmask_msg;
19629 s32 msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE;
19630
19631 if (!ev || (!ev->num)) {
19632 return -EINVAL;
19633 }
19634
19635 mutex_lock(&cfg->event_sync);
19636
19637 eventmask_msg = (eventmsgs_ext_t *)event_buf;
19638 eventmask_msg->ver = EVENTMSGS_VER;
19639 eventmask_msg->command = EVENTMSGS_NONE;
19640 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
19641 eventmask_msg->maxgetsize = WL_EVENTING_MASK_EXT_LEN;
19642
19643 /* Read event_msgs mask */
19644 ret = wldev_iovar_getbuf(ndev, "event_msgs_ext",
19645 eventmask_msg, EVENTMSGS_EXT_STRUCT_SIZE,
19646 iovbuf,
19647 sizeof(iovbuf),
19648 NULL);
19649
19650 if (unlikely(ret)) {
19651 WL_ERR(("Get event_msgs error (%d)\n", ret));
19652 goto exit;
19653 }
19654
19655 bcopy(iovbuf, eventmask_msg, msglen);
19656
19657 /* apply the set bits */
19658 for (i = 0; i < ev->num; i++) {
19659 if (ev->event[i].set)
19660 setbit(eventmask_msg->mask, ev->event[i].type);
19661 else
19662 clrbit(eventmask_msg->mask, ev->event[i].type);
19663 }
19664
19665 /* Write updated Event mask */
19666 eventmask_msg->ver = EVENTMSGS_VER;
19667 eventmask_msg->command = EVENTMSGS_SET_MASK;
19668 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
19669
19670 /* Write updated Event mask */
19671 ret = wldev_iovar_setbuf(ndev, "event_msgs_ext", eventmask_msg,
19672 WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE,
19673 iovbuf, sizeof(iovbuf), NULL);
19674
19675 if (unlikely(ret)) {
19676 WL_ERR(("Set event_msgs error (%d)\n", ret));
19677 }
19678
19679exit:
19680 mutex_unlock(&cfg->event_sync);
19681 return ret;
19682}
19683
19684s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
19685{
19686 s32 err = 0;
19687 s8 event_buf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE] = {0};
19688 eventmsgs_ext_t *eventmask_msg = NULL;
19689 struct bcm_cfg80211 *cfg;
19690 /* Room for "event_msgs_ext" + '\0' + bitvec */
19691 char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16];
19692 s32 msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE;
19693
19694 if (!ndev)
19695 return -ENODEV;
19696
19697 cfg = wl_get_cfg(ndev);
19698 if (!cfg)
19699 return -ENODEV;
19700
19701 mutex_lock(&cfg->event_sync);
19702
19703 eventmask_msg = (eventmsgs_ext_t *)event_buf;
19704 eventmask_msg->ver = EVENTMSGS_VER;
19705 eventmask_msg->command = EVENTMSGS_NONE;
19706 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
19707 eventmask_msg->maxgetsize = WL_EVENTING_MASK_EXT_LEN;
19708
19709 /* Read event_msgs mask */
19710 err = wldev_iovar_getbuf(ndev, "event_msgs_ext",
19711 eventmask_msg, EVENTMSGS_EXT_STRUCT_SIZE,
19712 iovbuf,
19713 sizeof(iovbuf),
19714 NULL);
19715
19716 if (unlikely(err)) {
19717 WL_ERR(("Get event_msgs error (%d)\n", err));
19718 goto eventmsg_out;
19719 }
19720
19721 bcopy(iovbuf, eventmask_msg, msglen);
19722
19723 if (add) {
19724 setbit(eventmask_msg->mask, event);
19725 } else {
19726 clrbit(eventmask_msg->mask, event);
19727 }
19728
19729 /* Write updated Event mask */
19730 eventmask_msg->ver = EVENTMSGS_VER;
19731 eventmask_msg->command = EVENTMSGS_SET_MASK;
19732 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
19733
19734 err = wldev_iovar_setbuf(ndev, "event_msgs_ext", eventmask_msg,
19735 WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE,
19736 iovbuf, sizeof(iovbuf), NULL);
19737
19738 if (unlikely(err)) {
19739 WL_ERR(("Set event_msgs error (%d)\n", err));
19740 goto eventmsg_out;
19741 }
19742
19743eventmsg_out:
19744 mutex_unlock(&cfg->event_sync);
19745 return err;
19746}
19747
19748void
19749wl_cfg80211_generate_mac_addr(struct ether_addr *ea_addr)
19750{
19751 RANDOM_BYTES(ea_addr->octet, ETHER_ADDR_LEN);
19752 /* restore mcast and local admin bits to 0 and 1 */
19753 ETHER_SET_UNICAST(ea_addr->octet);
19754 ETHER_SET_LOCALADDR(ea_addr->octet);
19755 WL_ERR(("%s:generated new MAC="MACDBG" \n",
19756 __FUNCTION__, MAC2STRDBG(ea_addr->octet)));
19757 return;
19758}
19759
19760static s32 wl_update_chan_param(struct net_device *dev, u32 cur_chan,
19761 struct ieee80211_channel *band_chan, bool *dfs_radar_disabled, bool legacy_chan_info)
19762{
19763 s32 err = BCME_OK;
19764 u32 channel = cur_chan;
19765
19766 if (!(*dfs_radar_disabled)) {
19767 if (legacy_chan_info) {
19768 channel |= WL_CHANSPEC_BW_20;
19769 channel = wl_chspec_host_to_driver(channel);
19770 err = wldev_iovar_getint(dev, "per_chan_info", &channel);
19771 }
19772 if (!err) {
19773 if (channel & WL_CHAN_RADAR) {
19774#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
19775 band_chan->flags |= (IEEE80211_CHAN_RADAR |
19776 IEEE80211_CHAN_NO_IBSS);
19777#else
19778 band_chan->flags |= IEEE80211_CHAN_RADAR;
19779#endif
19780 }
19781 if (channel & WL_CHAN_PASSIVE) {
19782#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
19783 band_chan->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
19784#else
19785 band_chan->flags |= IEEE80211_CHAN_NO_IR;
19786#endif
19787 }
19788 } else if (err == BCME_UNSUPPORTED) {
19789 *dfs_radar_disabled = TRUE;
19790 WL_ERR(("does not support per_chan_info\n"));
19791 }
19792 }
19793
19794 return err;
19795}
19796
19797static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
19798{
19799 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
19800 struct ieee80211_channel *band_chan_arr = NULL;
19801 void *list;
19802 u32 i, j, index, channel, array_size = 0;
19803 chanspec_t chspec = 0;
19804 s32 err = BCME_OK;
19805 bool ht40_allowed;
19806 bool dfs_radar_disabled = FALSE;
19807 bool legacy_chan_info = FALSE;
19808 u16 list_count;
19809
19810#define LOCAL_BUF_LEN 4096
19811 list = MALLOCZ(cfg->osh, LOCAL_BUF_LEN);
19812 if (list == NULL) {
19813 WL_ERR(("failed to allocate local buf\n"));
19814 return -ENOMEM;
19815 }
19816
19817 err = wldev_iovar_getbuf_bsscfg(dev, "chan_info_list", NULL,
19818 0, list, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
19819 if (err == BCME_UNSUPPORTED) {
19820 WL_INFORM(("get chan_info_list, UNSUPPORTED\n"));
19821 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
19822 0, list, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
19823 if (err != BCME_OK) {
19824 WL_ERR(("get chanspecs err(%d)\n", err));
19825 MFREE(cfg->osh, list, LOCAL_BUF_LEN);
19826 return err;
19827 }
19828 /* Update indicating legacy chan info usage */
19829 legacy_chan_info = TRUE;
19830 } else if (err != BCME_OK) {
19831 WL_ERR(("get chan_info_list err(%d)\n", err));
19832 MFREE(cfg->osh, list, LOCAL_BUF_LEN);
19833 return err;
19834 }
19835
19836 WL_CHANNEL_ARRAY_INIT(__wl_2ghz_channels);
19837 WL_CHANNEL_ARRAY_INIT(__wl_5ghz_a_channels);
19838
19839 list_count = legacy_chan_info ? ((wl_uint32_list_t *)list)->count :
19840 ((wl_chanspec_list_v1_t *)list)->count;
19841 for (i = 0; i < dtoh32(list_count); i++) {
19842 index = 0;
19843 ht40_allowed = false;
19844 if (legacy_chan_info) {
19845 chspec = (chanspec_t)dtoh32(((wl_uint32_list_t *)list)->element[i]);
19846 } else {
19847 chspec = (chanspec_t)dtoh32
19848 (((wl_chanspec_list_v1_t *)list)->chspecs[i].chanspec);
19849 }
19850 chspec = wl_chspec_driver_to_host(chspec);
19851 channel = wf_chspec_ctlchan(chspec);
19852
19853 if (!CHSPEC_IS40(chspec) &&
19854 !CHSPEC_IS20(chspec)) {
19855 WL_DBG(("HT80/160/80p80 center channel : %d\n", channel));
19856 continue;
19857 }
19858 if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) &&
19859 (channel <= CH_MAX_2G_CHANNEL)) {
19860 band_chan_arr = __wl_2ghz_channels;
19861 array_size = ARRAYSIZE(__wl_2ghz_channels);
19862 ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false;
19863 } else if (
19864#ifdef WL_6G_BAND
19865 /* Currently due to lack of kernel support both 6GHz and 5GHz
19866 * channels are published under 5GHz band
19867 */
19868 (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) &&
19869 (channel <= CH_MAX_6G_CHANNEL)) ||
19870#endif /* WL_6G_BAND */
19871 (CHSPEC_IS5G(chspec) && channel >= CH_MIN_5G_CHANNEL)) {
19872 band_chan_arr = __wl_5ghz_a_channels;
19873 array_size = ARRAYSIZE(__wl_5ghz_a_channels);
19874 ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true;
19875 } else {
19876 WL_ERR(("Invalid channel Sepc. 0x%x.\n", chspec));
19877 continue;
19878 }
19879 if (!ht40_allowed && CHSPEC_IS40(chspec))
19880 continue;
19881 for (j = 0; j < array_size; j++) {
19882 if (band_chan_arr[j].hw_value == chspec) {
19883 break;
19884 }
19885 }
19886 index = j;
19887 if (!dhd_conf_match_channel(cfg->pub, channel))
19888 continue;
19889 if (index < array_size) {
19890#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
19891 band_chan_arr[index].center_freq =
19892 ieee80211_channel_to_frequency(channel);
19893#else
19894 band_chan_arr[index].center_freq =
19895 wl_channel_to_frequency(channel, CHSPEC_BAND(chspec));
19896#endif
19897 band_chan_arr[index].hw_value = chspec;
19898 band_chan_arr[index].beacon_found = false;
19899 band_chan_arr[index].flags &= ~IEEE80211_CHAN_DISABLED;
19900
19901 if (CHSPEC_IS40(chspec) && ht40_allowed) {
19902 /* assuming the order is HT20, HT40 Upper,
19903 * HT40 lower from chanspecs
19904 */
19905 u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
19906 if (CHSPEC_SB_UPPER(chspec)) {
19907 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
19908 band_chan_arr[index].flags &=
19909 ~IEEE80211_CHAN_NO_HT40;
19910 band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
19911 } else {
19912 /* It should be one of
19913 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
19914 */
19915 band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
19916 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
19917 band_chan_arr[index].flags |=
19918 IEEE80211_CHAN_NO_HT40MINUS;
19919 }
19920 } else {
19921 band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
19922 if (!legacy_chan_info) {
19923 channel = dtoh32
19924 (((wl_chanspec_list_v1_t *)list)->chspecs[i].chaninfo);
19925 } else {
19926 channel |= CHSPEC_BAND(chspec);
19927 }
19928 /* Update channel for radar/passive support */
19929 err = wl_update_chan_param(dev, channel,
19930 &band_chan_arr[index], &dfs_radar_disabled, legacy_chan_info);
19931 }
19932 }
19933
19934 }
19935
19936 __wl_band_2ghz.n_channels = ARRAYSIZE(__wl_2ghz_channels);
19937 __wl_band_5ghz_a.n_channels = ARRAYSIZE(__wl_5ghz_a_channels);
19938
19939 MFREE(cfg->osh, list, LOCAL_BUF_LEN);
19940#undef LOCAL_BUF_LEN
19941 return err;
19942}
19943
19944#ifdef WL_6G_BAND
19945static void wl_is_6g_supported(struct bcm_cfg80211 *cfg, u32 *bandlist, u8 nbands)
19946{
19947 u32 i = 0;
19948
19949 if (nbands > WL_MAX_BAND_SUPPORT) {
19950 return;
19951 }
19952 /* Check for 6GHz band support */
19953 for (i = 1; i <= nbands; i++) {
19954 if (bandlist[i] == WLC_BAND_6G) {
19955 cfg->band_6g_supported = true;
19956 }
19957 }
19958}
19959#endif /* WL_6G_BAND */
19960
19961static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
19962{
19963 struct wiphy *wiphy;
19964 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
19965 u32 bandlist[WL_MAX_BAND_SUPPORT+1];
19966 u32 nband = 0;
19967 u32 i = 0;
19968 s32 err = 0;
19969 s32 index = 0;
19970 s32 nmode = 0;
19971#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19972 u32 j = 0;
19973 s32 vhtmode = 0;
19974 s32 txstreams = 0;
19975 s32 rxstreams = 0;
19976 s32 ldpc_cap = 0;
19977 s32 stbc_rx = 0;
19978 s32 stbc_tx = 0;
19979 s32 txbf_bfe_cap = 0;
19980 s32 txbf_bfr_cap = 0;
19981#endif
19982 s32 bw_cap = 0;
19983 s32 cur_band = -1;
19984 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, };
19985
19986 bzero(bandlist, sizeof(bandlist));
19987 err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist,
19988 sizeof(bandlist));
19989 if (unlikely(err)) {
19990 WL_ERR(("error read bandlist (%d)\n", err));
19991 return err;
19992 }
19993 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band,
19994 sizeof(s32));
19995 if (unlikely(err)) {
19996 WL_ERR(("error (%d)\n", err));
19997 return err;
19998 }
19999
20000 err = wldev_iovar_getint(dev, "nmode", &nmode);
20001 if (unlikely(err)) {
20002 WL_ERR(("error reading nmode (%d)\n", err));
20003 }
20004
20005#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
20006 err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
20007 if (unlikely(err)) {
20008 WL_ERR(("error reading vhtmode (%d)\n", err));
20009 }
20010
20011 if (vhtmode) {
20012 err = wldev_iovar_getint(dev, "txstreams", &txstreams);
20013 if (unlikely(err)) {
20014 WL_ERR(("error reading txstreams (%d)\n", err));
20015 }
20016
20017 err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
20018 if (unlikely(err)) {
20019 WL_ERR(("error reading rxstreams (%d)\n", err));
20020 }
20021
20022 err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
20023 if (unlikely(err)) {
20024 WL_ERR(("error reading ldpc_cap (%d)\n", err));
20025 }
20026
20027 err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
20028 if (unlikely(err)) {
20029 WL_ERR(("error reading stbc_rx (%d)\n", err));
20030 }
20031
20032 err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
20033 if (unlikely(err)) {
20034 WL_ERR(("error reading stbc_tx (%d)\n", err));
20035 }
20036
20037 err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
20038 if (unlikely(err)) {
20039 WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
20040 }
20041
20042 err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
20043 if (unlikely(err)) {
20044 WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
20045 }
20046 }
20047#endif
20048
20049 /* For nmode and vhtmode check bw cap */
20050 if (nmode ||
20051#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
20052 vhtmode ||
20053#endif
20054 0) {
20055 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
20056 if (unlikely(err)) {
20057 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
20058 }
20059 }
20060
20061#ifdef WL_6G_BAND
20062 wl_is_6g_supported(cfg, bandlist, bandlist[0]);
20063#endif /* WL_6G_BAND */
20064
20065 err = wl_construct_reginfo(cfg, bw_cap);
20066 if (err) {
20067 WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
20068 if (err != BCME_UNSUPPORTED)
20069 return err;
20070 }
20071
20072 wiphy = bcmcfg_to_wiphy(cfg);
20073 nband = bandlist[0];
20074
20075 for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
20076 index = -1;
20077
20078 if (((bandlist[i] == WLC_BAND_5G) || (bandlist[i] == WLC_BAND_6G)) &&
20079 (__wl_band_5ghz_a.n_channels > 0)) {
20080 bands[IEEE80211_BAND_5GHZ] =
20081 &__wl_band_5ghz_a;
20082 index = IEEE80211_BAND_5GHZ;
20083 if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
20084 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
20085
20086#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
20087 /* VHT capabilities. */
20088 if (vhtmode) {
20089 /* Supported */
20090 bands[index]->vht_cap.vht_supported = TRUE;
20091
20092 for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
20093 /* TX stream rates. */
20094 if (j <= txstreams) {
20095 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
20096 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
20097 } else {
20098 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
20099 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
20100 }
20101
20102 /* RX stream rates. */
20103 if (j <= rxstreams) {
20104 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
20105 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
20106 } else {
20107 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
20108 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
20109 }
20110 }
20111
20112 /* Capabilities */
20113 /* 80 MHz is mandatory */
20114 bands[index]->vht_cap.cap |=
20115 IEEE80211_VHT_CAP_SHORT_GI_80;
20116
20117 if (WL_BW_CAP_160MHZ(bw_cap)) {
20118 bands[index]->vht_cap.cap |=
20119 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
20120 bands[index]->vht_cap.cap |=
20121 IEEE80211_VHT_CAP_SHORT_GI_160;
20122 }
20123
20124 bands[index]->vht_cap.cap |=
20125 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
20126
20127 if (ldpc_cap)
20128 bands[index]->vht_cap.cap |=
20129 IEEE80211_VHT_CAP_RXLDPC;
20130
20131 if (stbc_tx)
20132 bands[index]->vht_cap.cap |=
20133 IEEE80211_VHT_CAP_TXSTBC;
20134
20135 if (stbc_rx)
20136 bands[index]->vht_cap.cap |=
20137 (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
20138
20139 if (txbf_bfe_cap)
20140 bands[index]->vht_cap.cap |=
20141 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
20142
20143 if (txbf_bfr_cap) {
20144 bands[index]->vht_cap.cap |=
20145 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
20146 }
20147
20148 if (txbf_bfe_cap || txbf_bfr_cap) {
20149 bands[index]->vht_cap.cap |=
20150 (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
20151 bands[index]->vht_cap.cap |=
20152 ((txstreams - 1) <<
20153 VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
20154 bands[index]->vht_cap.cap |=
20155 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
20156 }
20157
20158 /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
20159 bands[index]->vht_cap.cap |=
20160 (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
20161 WL_DBG(("__wl_update_wiphybands band[%d] vht_enab=%d vht_cap=%08x "
20162 "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
20163 index,
20164 bands[index]->vht_cap.vht_supported,
20165 bands[index]->vht_cap.cap,
20166 bands[index]->vht_cap.vht_mcs.rx_mcs_map,
20167 bands[index]->vht_cap.vht_mcs.tx_mcs_map));
20168 }
20169#endif
20170 }
20171 else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
20172 bands[IEEE80211_BAND_2GHZ] =
20173 &__wl_band_2ghz;
20174 index = IEEE80211_BAND_2GHZ;
20175 if (bw_cap == WLC_N_BW_40ALL)
20176 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
20177 }
20178
20179 if ((index >= 0) && nmode) {
20180 bands[index]->ht_cap.cap |=
20181 (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
20182 bands[index]->ht_cap.ht_supported = TRUE;
20183 bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
20184 bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
20185 /* An HT shall support all EQM rates for one spatial stream */
20186 bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
20187 }
20188
20189 }
20190
20191 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
20192 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
20193
20194 /* check if any bands populated otherwise makes 2Ghz as default */
20195 if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL &&
20196 wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) {
20197 /* Setup 2Ghz band as default */
20198 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
20199 }
20200
20201 if (notify) {
20202 if (!IS_REGDOM_SELF_MANAGED(wiphy)) {
20203 WL_UPDATE_CUSTOM_REGULATORY(wiphy);
20204 wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
20205 }
20206 }
20207
20208 return 0;
20209}
20210
20211s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
20212{
20213 s32 err;
20214
20215 mutex_lock(&cfg->usr_sync);
20216 err = __wl_update_wiphybands(cfg, notify);
20217 mutex_unlock(&cfg->usr_sync);
20218
20219 return err;
20220}
20221
20222static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
20223{
20224 s32 err = 0;
20225 s32 ret = 0;
20226
20227 struct net_info *netinfo = NULL;
20228 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
20229 struct wireless_dev *wdev = ndev->ieee80211_ptr;
20230 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20231#ifdef WLTDLS
20232 u32 tdls;
20233#endif /* WLTDLS */
20234 u16 wl_iftype = 0;
20235 u16 wl_mode = 0;
20236 u8 ioctl_buf[WLC_IOCTL_SMLEN];
20237
20238 WL_DBG(("In\n"));
20239
20240#if defined(__linux__)
20241 if (!dhd_download_fw_on_driverload) {
20242#endif
20243 err = wl_create_event_handler(cfg);
20244 if (err) {
20245 WL_ERR(("wl_create_event_handler failed\n"));
20246 return err;
20247 }
20248 wl_init_event_handler(cfg);
20249#if defined(__linux__)
20250 }
20251#endif
20252 /* Reserve 0x8000 toggle bit for P2P GO/GC */
20253 cfg->vif_macaddr_mask = 0x8000;
20254
20255 err = dhd_config_dongle(cfg);
20256 if (unlikely(err))
20257 return err;
20258
20259 (void)memcpy_s(wdev->wiphy->perm_addr, ETHER_ADDR_LEN,
20260 bcmcfg_to_prmry_ndev(cfg)->perm_addr, ETHER_ADDR_LEN);
20261 /* Always bring up interface in STA mode.
20262 * Did observe , if previous SofAP Bringup/cleanup
20263 * is not done properly, iftype is stuck with AP mode.
20264 * So during next wlan0 up, forcing the type to STA
20265 */
20266 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
20267 if (!netinfo) {
20268 WL_ERR(("there is no netinfo\n"));
20269 return -ENODEV;
20270 }
20271
20272 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
20273 /* AP on primary interface case: Supplicant will
20274 * set mode first and then do dev_open. so in this
20275 * case, the type will already be set.
20276 */
20277 netinfo->iftype = WL_IF_TYPE_AP;
20278 } else {
20279 ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
20280 netinfo->iftype = WL_IF_TYPE_STA;
20281 }
20282
20283 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
20284 return -EINVAL;
20285 }
20286 if (!dhd->fw_preinit) {
20287 err = wl_config_infra(cfg, ndev, wl_iftype);
20288 if (unlikely(err && err != -EINPROGRESS)) {
20289 WL_ERR(("wl_config_infra failed\n"));
20290 if (err == -1) {
20291 WL_ERR(("return error %d\n", err));
20292 return err;
20293 }
20294 }
20295 }
20296
20297 err = wl_init_scan(cfg);
20298 if (err) {
20299 WL_ERR(("wl_init_scan failed\n"));
20300 return err;
20301 }
20302 err = __wl_update_wiphybands(cfg, true);
20303 if (unlikely(err)) {
20304 WL_ERR(("wl_update_wiphybands failed\n"));
20305 if (err == -1) {
20306 WL_ERR(("return error %d\n", err));
20307 return err;
20308 }
20309 }
20310
20311 /* Update wlc version in cfg struct already queried as part of DHD initialization */
20312 cfg->wlc_ver.wlc_ver_major = dhd->wlc_ver_major;
20313 cfg->wlc_ver.wlc_ver_minor = dhd->wlc_ver_minor;
20314
20315 if ((ret = wldev_iovar_getbuf(ndev, "scan_ver", NULL, 0,
20316 ioctl_buf, sizeof(ioctl_buf), NULL) == BCME_OK)) {
20317 WL_INFORM_MEM(("scan_params v2\n"));
20318 /* use scan_params ver2 */
20319 cfg->scan_params_v2 = true;
20320 } else {
20321 if (ret == BCME_UNSUPPORTED) {
20322 WL_INFORM(("scan_ver, UNSUPPORTED\n"));
20323 } else {
20324 WL_ERR(("get scan_ver err(%d)\n", ret));
20325 }
20326 }
20327#ifdef DHD_LOSSLESS_ROAMING
20328 if (timer_pending(&cfg->roam_timeout)) {
20329 del_timer_sync(&cfg->roam_timeout);
20330 }
20331#endif /* DHD_LOSSLESS_ROAMING */
20332
20333 err = dhd_monitor_init(cfg->pub);
20334
20335#ifdef WL_HOST_BAND_MGMT
20336 /* By default the curr_band is initialized to BAND_AUTO */
20337 if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) {
20338 if (ret == BCME_UNSUPPORTED) {
20339 /* Don't fail the initialization, lets just
20340 * fall back to the original method
20341 */
20342 WL_ERR(("WL_HOST_BAND_MGMT defined, "
20343 "but roam_band iovar not supported \n"));
20344 } else {
20345 WL_ERR(("roam_band failed. ret=%d", ret));
20346 err = -1;
20347 }
20348 }
20349#endif /* WL_HOST_BAND_MGMT */
20350 /* Reset WES mode to 0 */
20351 cfg->wes_mode = OFF;
20352 cfg->ncho_mode = OFF;
20353 cfg->ncho_band = WLC_BAND_AUTO;
20354#ifdef WBTEXT
20355 /* when wifi up, set roam_prof to default value */
20356 if (dhd->wbtext_support) {
20357 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
20358 if (!dhd->fw_preinit) {
20359 wl_cfg80211_wbtext_set_default(ndev);
20360 }
20361 wl_cfg80211_wbtext_clear_bssid_list(cfg);
20362 }
20363 }
20364#endif /* WBTEXT */
20365#ifdef WLTDLS
20366 if (wldev_iovar_getint(ndev, "tdls_enable", &tdls) == 0) {
20367 WL_DBG(("TDLS supported in fw\n"));
20368 cfg->tdls_supported = true;
20369 }
20370#endif /* WLTDLS */
20371#ifdef WL_IFACE_MGMT
20372#ifdef CUSTOM_IF_MGMT_POLICY
20373 cfg->iface_data.policy = CUSTOM_IF_MGMT_POLICY;
20374#else
20375 cfg->iface_data.policy = WL_IF_POLICY_DEFAULT;
20376#endif /* CUSTOM_IF_MGMT_POLICY */
20377#endif /* WL_IFACE_MGMT */
20378#ifdef WL_NAN
20379#endif /* WL_NAN */
20380
20381#ifdef WL_SAR_TX_POWER
20382 cfg->wifi_tx_power_mode = WIFI_POWER_SCENARIO_INVALID;
20383#endif /* WL_SAR_TX_POWER */
20384
20385 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
20386 wl_set_drv_status(cfg, READY, ndev);
20387 return err;
20388}
20389
20390static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
20391{
20392 s32 err = 0;
20393 struct net_info *iter, *next;
20394 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
20395#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
20396 defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
20397 struct net_device *p2p_net = cfg->p2p_net;
20398#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) && !PLATFORM_SLP */
20399 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20400 WL_INFORM_MEM(("cfg80211 down\n"));
20401
20402 /* Check if cfg80211 interface is already down */
20403 if (!wl_get_drv_status(cfg, READY, ndev)) {
20404 WL_DBG(("cfg80211 interface is already down\n"));
20405 return err; /* it is even not ready */
20406 }
20407
20408#ifdef SHOW_LOGTRACE
20409 /* Stop the event logging */
20410 wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
20411#endif /* SHOW_LOGTRACE */
20412
20413 /* clear vendor OUI list */
20414 wl_vndr_ies_clear_vendor_oui_list(cfg);
20415
20416 /* clear timestamps */
20417 CLR_TS(cfg, scan_start);
20418 CLR_TS(cfg, scan_cmplt);
20419 CLR_TS(cfg, conn_start);
20420 CLR_TS(cfg, conn_cmplt);
20421 CLR_TS(cfg, authorize_start);
20422 CLR_TS(cfg, authorize_cmplt);
20423
20424 /* Delete pm_enable_work */
20425 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
20426
20427 if (cfg->loc.in_progress) {
20428 /* Listen in progress */
20429 if (delayed_work_pending(&cfg->loc.work)) {
20430 cancel_delayed_work_sync(&cfg->loc.work);
20431 }
20432 wl_cfgscan_notify_listen_complete(cfg);
20433 }
20434
20435 if (cfg->p2p_supported) {
20436 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
20437#ifdef PROP_TXSTATUS_VSDB
20438#if defined(BCMSDIO) || defined(BCMDBUS)
20439 if (wl_cfgp2p_vif_created(cfg)) {
20440 bool enabled = false;
20441 dhd_wlfc_get_enable(dhd, &enabled);
20442 /* WLFC should be turned off
20443 * while unloading dhd driver in IBSS or SoftAP mode
20444 */
20445 if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
20446 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
20447 dhd_wlfc_deinit(dhd);
20448 cfg->wlfc_on = false;
20449 }
20450 }
20451#endif /* BCMSDIO || BCMDBUS */
20452#endif /* PROP_TXSTATUS_VSDB */
20453 }
20454
20455#ifdef WL_NAN
20456 mutex_lock(&cfg->if_sync);
20457 wl_cfgnan_check_nan_disable_pending(cfg, true, false);
20458 mutex_unlock(&cfg->if_sync);
20459#endif /* WL_NAN */
20460
20461#ifdef WL_SAR_TX_POWER
20462 cfg->wifi_tx_power_mode = WIFI_POWER_SCENARIO_INVALID;
20463#endif /* WL_SAR_TX_POWER */
20464 if (!dhd_download_fw_on_driverload) {
20465 /* For built-in drivers/other drivers that do reset on
20466 * "ifconfig <primary_iface> down", cleanup any left
20467 * over interfaces
20468 */
20469 wl_cfg80211_cleanup_virtual_ifaces(cfg, false);
20470 }
20471 /* Clear used mac addr mask */
20472 cfg->vif_macaddr_mask = 0;
20473
20474 if (dhd->up)
20475 {
20476 /* If primary BSS is operational (for e.g SoftAP), bring it down */
20477 if (wl_cfg80211_bss_isup(ndev, 0)) {
20478 if (wl_cfg80211_bss_up(cfg, ndev, 0, 0) < 0)
20479 WL_ERR(("BSS down failed \n"));
20480 }
20481
20482 /* clear all the security setting on primary Interface */
20483 wl_cfg80211_clear_security(cfg);
20484 }
20485
20486 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
20487 for_each_ndev(cfg, iter, next) {
20488 GCC_DIAGNOSTIC_POP();
20489 if (iter->ndev) /* p2p discovery iface is null */
20490 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
20491 }
20492
20493#ifdef P2P_LISTEN_OFFLOADING
20494 wl_cfg80211_p2plo_deinit(cfg);
20495#endif /* P2P_LISTEN_OFFLOADING */
20496
20497 /* cancel and notify scan complete, if scan request is pending */
20498 wl_cfg80211_cancel_scan(cfg);
20499 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
20500 for_each_ndev(cfg, iter, next) {
20501 GCC_DIAGNOSTIC_POP();
20502 /* p2p discovery iface ndev ptr could be null */
20503 if (iter->ndev == NULL)
20504 continue;
20505#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
20506 WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
20507 wl_get_drv_status(cfg, CONNECTING, ndev),
20508 wl_get_drv_status(cfg, CONNECTED, ndev),
20509 wl_get_drv_status(cfg, DISCONNECTING, ndev),
20510 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
20511
20512 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
20513 CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
20514 wl_clr_drv_status(cfg, AUTHORIZED, iter->ndev);
20515 }
20516
20517 if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
20518 wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
20519
20520 u8 *latest_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
20521 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
20522 struct wireless_dev *wdev = ndev->ieee80211_ptr;
20523 struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid,
20524 wdev->ssid, wdev->ssid_len);
20525
20526 BCM_REFERENCE(bss);
20527
20528 CFG80211_CONNECT_RESULT(ndev,
20529 latest_bssid, bss, NULL, 0, NULL, 0,
20530 WLAN_STATUS_UNSPECIFIED_FAILURE,
20531 GFP_KERNEL);
20532 }
20533#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
20534 wl_clr_drv_status(cfg, READY, iter->ndev);
20535 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
20536 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
20537 wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
20538 wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
20539 wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
20540 wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
20541 wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
20542 wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev);
20543 wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev);
20544 }
20545 bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
20546 NL80211_IFTYPE_STATION;
20547#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
20548 defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
20549#ifdef SUPPORT_DEEP_SLEEP
20550 if (!trigger_deep_sleep)
20551#endif /* SUPPORT_DEEP_SLEEP */
20552 if (p2p_net)
20553 dev_close(p2p_net);
20554#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT)&& !PLATFORM_SLP */
20555
20556 /* Avoid deadlock from wl_cfg80211_down */
20557#if defined(__linux__)
20558 if (!dhd_download_fw_on_driverload) {
20559#endif
20560 mutex_unlock(&cfg->usr_sync);
20561 wl_destroy_event_handler(cfg);
20562 mutex_lock(&cfg->usr_sync);
20563#if defined(__linux__)
20564 }
20565#endif
20566
20567 wl_flush_eq(cfg);
20568 wl_link_down(cfg);
20569 if (cfg->p2p_supported) {
20570 if (timer_pending(&cfg->p2p->listen_timer))
20571 del_timer_sync(&cfg->p2p->listen_timer);
20572 wl_cfgp2p_down(cfg);
20573 }
20574
20575 if (timer_pending(&cfg->scan_timeout)) {
20576 del_timer_sync(&cfg->scan_timeout);
20577 }
20578
20579 wl_cfg80211_clear_mgmt_vndr_ies(cfg);
20580
20581 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
20582
20583 dhd_monitor_uninit();
20584#ifdef WLAIBSS_MCHAN
20585 bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
20586#endif /* WLAIBSS_MCHAN */
20587
20588#ifdef WL11U
20589 /* Clear interworking element. */
20590 if (cfg->wl11u) {
20591 cfg->wl11u = FALSE;
20592 }
20593#endif /* WL11U */
20594
20595#ifdef CUSTOMER_HW4_DEBUG
20596 if (wl_scan_timeout_dbg_enabled) {
20597 wl_scan_timeout_dbg_clear();
20598 }
20599#endif /* CUSTOMER_HW4_DEBUG */
20600
20601 cfg->disable_roam_event = false;
20602
20603 DNGL_FUNC(dhd_cfg80211_down, (cfg));
20604
20605#ifdef DHD_IFDEBUG
20606 /* Printout all netinfo entries */
20607 wl_probe_wdev_all(cfg);
20608#endif /* DHD_IFDEBUG */
20609
20610 return err;
20611}
20612
20613s32 wl_cfg80211_up(struct net_device *net)
20614{
20615 struct bcm_cfg80211 *cfg;
20616 s32 err = 0;
20617 int val = 1;
20618 dhd_pub_t *dhd;
20619#ifdef DISABLE_PM_BCNRX
20620 s32 interr = 0;
20621 uint param = 0;
20622 s8 iovbuf[WLC_IOCTL_SMLEN];
20623#endif /* DISABLE_PM_BCNRX */
20624#ifdef WL_USE_RANDOMIZED_SCAN
20625 uint8 random_addr[ETHER_ADDR_LEN] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
20626#endif /* WL_USE_RANDOMIZED_SCAN */
20627 WL_DBG(("In\n"));
20628 cfg = wl_get_cfg(net);
20629
20630 if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
20631 sizeof(int)) < 0)) {
20632 WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
20633 return err;
20634 }
20635 val = dtoh32(val);
20636 if (val != WLC_IOCTL_VERSION && val != 1) {
20637 WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
20638 val, WLC_IOCTL_VERSION));
20639 return BCME_VERSION;
20640 }
20641 ioctl_version = val;
20642 WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
20643 wl_cfg80211_check_in4way(cfg, net, NO_SCAN_IN4WAY|NO_BTC_IN4WAY|WAIT_DISCONNECTED,
20644 WL_EXT_STATUS_DISCONNECTED, NULL);
20645
20646 mutex_lock(&cfg->usr_sync);
20647 dhd = (dhd_pub_t *)(cfg->pub);
20648 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
20649 err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
20650 if (unlikely(err)) {
20651 mutex_unlock(&cfg->usr_sync);
20652 return err;
20653 }
20654 }
20655#ifdef WLMESH_CFG80211
20656 cfg->wdev->wiphy->features |= NL80211_FEATURE_USERSPACE_MPM;
20657#endif /* WLMESH_CFG80211 */
20658#if defined(BCMSUP_4WAY_HANDSHAKE)
20659 if (dhd->fw_4way_handshake) {
20660 /* This is a hacky method to indicate fw 4WHS support and
20661 * is used only for kernels (kernels < 3.14). For newer
20662 * kernels, we would be using vendor extn. path to advertise
20663 * FW based 4-way handshake feature support.
20664 */
20665 cfg->wdev->wiphy->features |= NL80211_FEATURE_FW_4WAY_HANDSHAKE;
20666 }
20667#endif /* BCMSUP_4WAY_HANDSHAKE */
20668 err = __wl_cfg80211_up(cfg);
20669 if (unlikely(err))
20670 WL_ERR(("__wl_cfg80211_up failed\n"));
20671
20672#ifdef ROAM_CHANNEL_CACHE
20673 if (init_roam_cache(cfg, ioctl_version) == 0) {
20674 /* Enable support for Roam cache */
20675 cfg->rcc_enabled = true;
20676 WL_ERR(("Roam channel cache enabled\n"));
20677 } else {
20678 WL_ERR(("Failed to enable RCC.\n"));
20679 }
20680#endif /* ROAM_CHANNEL_CACHE */
20681#ifdef WL_USE_RANDOMIZED_SCAN
20682 /* Call scanmac only for valid configuration */
20683 if (wl_cfg80211_scan_mac_enable(net)) {
20684 WL_ERR(("%s : randmac enable failed\n", __FUNCTION__));
20685 } else {
20686 /* scanmac enabled. apply configuration */
20687 if (wl_cfg80211_scan_mac_config(net, random_addr, NULL)) {
20688 WL_ERR(("%s : failed to set randmac config for scan\n", __FUNCTION__));
20689 /* if config fails, disable scan mac */
20690 wl_cfg80211_scan_mac_disable(net);
20691 }
20692 }
20693#endif /* WL_USE_RANDOMIZED_SCAN */
20694#if defined(FORCE_DISABLE_SINGLECORE_SCAN)
20695 dhd_force_disable_singlcore_scan(dhd);
20696#endif /* FORCE_DISABLE_SINGLECORE_SCAN */
20697
20698 /* IOVAR configurations with 'up' condition */
20699#ifdef DISABLE_PM_BCNRX
20700 interr = wldev_iovar_setbuf(net, "pm_bcnrx", (char *)&param, sizeof(param), iovbuf,
20701 sizeof(iovbuf), &cfg->ioctl_buf_sync);
20702
20703 if (unlikely(interr)) {
20704 WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
20705 }
20706#endif /* DISABLE_PM_BCNRX */
20707#ifdef WL_CHAN_UTIL
20708 interr = wl_cfg80211_start_bssload_report(net);
20709 if (unlikely(interr)) {
20710 WL_ERR(("%s: Failed to start bssload_report eventing, err=%d\n",
20711 __FUNCTION__, interr));
20712 }
20713#endif /* WL_CHAN_UTIL */
20714
20715 mutex_unlock(&cfg->usr_sync);
20716
20717#ifdef WLAIBSS_MCHAN
20718 bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
20719#endif /* WLAIBSS_MCHAN */
20720 cfg->spmk_info_list->pmkids.count = 0;
20721 return err;
20722}
20723
20724/* Private Event to Supplicant with indication that chip hangs */
20725int wl_cfg80211_hang(struct net_device *dev, u16 reason)
20726{
20727 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20728 dhd_pub_t *dhd;
20729#if defined(SOFTAP_SEND_HANGEVT)
20730 /* specifc mac address used for hang event */
20731 uint8 hang_mac[ETHER_ADDR_LEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
20732#endif /* SOFTAP_SEND_HANGEVT */
20733 if (!cfg) {
20734 return BCME_ERROR;
20735 }
20736
20737 RETURN_EIO_IF_NOT_UP(cfg);
20738
20739 dhd = (dhd_pub_t *)(cfg->pub);
20740#if defined(DHD_HANG_SEND_UP_TEST)
20741 if (dhd->req_hang_type) {
20742 WL_ERR(("wl_cfg80211_hang, Clear HANG test request 0x%x\n",
20743 dhd->req_hang_type));
20744 dhd->req_hang_type = 0;
20745 }
20746#endif /* DHD_HANG_SEND_UP_TEST */
20747 if ((dhd->hang_reason <= HANG_REASON_MASK) || (dhd->hang_reason >= HANG_REASON_MAX)) {
20748 WL_ERR(("wl_cfg80211_hang, Invalid hang reason 0x%x\n",
20749 dhd->hang_reason));
20750 dhd->hang_reason = HANG_REASON_UNKNOWN;
20751 }
20752#ifdef DHD_USE_EXTENDED_HANG_REASON
20753 /* The proper dhd->hang_reason handling codes should be implemented
20754 * in the WPA Supplicant/Hostapd or Android framework.
20755 * If not, HANG event may not be sent to Android framework and
20756 * driver cannot be reloaded.
20757 * Please do not enable DHD_USE_EXTENDED_HANG_REASON if your Android platform
20758 * cannot handle the dhd->hang_reason value.
20759 */
20760 if (dhd->hang_reason != 0) {
20761 reason = dhd->hang_reason;
20762 }
20763#endif /* DHD_USE_EXTENDED_HANG_REASON */
20764 WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32)(dhd->hang_reason)));
20765
20766 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
20767#ifdef SOFTAP_SEND_HANGEVT
20768 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
20769 cfg80211_del_sta(dev, hang_mac, GFP_ATOMIC);
20770 } else
20771#endif /* SOFTAP_SEND_HANGEVT */
20772 {
20773 if (dhd->up == TRUE) {
20774#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
20775 wl_cfgvendor_send_hang_event(dev, reason,
20776 dhd->hang_info, dhd->hang_info_cnt);
20777#else
20778 CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
20779#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
20780 }
20781 }
20782#if defined(RSSIAVG)
20783 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
20784#endif
20785#if defined(BSSCACHE)
20786 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
20787#endif
20788 if (cfg != NULL) {
20789 /* Do we need to call wl_cfg80211_down here ? */
20790 wl_link_down(cfg);
20791 }
20792 return 0;
20793}
20794
20795s32 wl_cfg80211_down(struct net_device *dev)
20796{
20797 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20798 s32 err = BCME_ERROR;
20799
20800 WL_DBG(("In\n"));
20801
20802 if (cfg && (cfg == wl_cfg80211_get_bcmcfg())) {
20803 mutex_lock(&cfg->usr_sync);
20804#if defined(RSSIAVG)
20805 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
20806#endif
20807#if defined(BSSCACHE)
20808 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
20809#endif
20810 err = __wl_cfg80211_down(cfg);
20811 mutex_unlock(&cfg->usr_sync);
20812 }
20813
20814 return err;
20815}
20816
20817void
20818wl_cfg80211_sta_ifdown(struct net_device *dev)
20819{
20820 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20821
20822 WL_DBG(("In\n"));
20823
20824 if (cfg) {
20825 /* cancel scan if anything pending */
20826 wl_cfg80211_cancel_scan(cfg);
20827#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
20828 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
20829 wl_get_drv_status(cfg, CONNECTED, dev)) {
20830 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
20831 }
20832#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
20833 }
20834}
20835
20836void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
20837{
20838 unsigned long flags;
20839 void *rptr = NULL;
20840 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
20841
20842 if (!profile)
20843 return NULL;
20844 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
20845 switch (item) {
20846 case WL_PROF_SEC:
20847 rptr = &profile->sec;
20848 break;
20849 case WL_PROF_ACT:
20850 rptr = &profile->active;
20851 break;
20852 case WL_PROF_BSSID:
20853 rptr = profile->bssid;
20854 break;
20855 case WL_PROF_SSID:
20856 rptr = &profile->ssid;
20857 break;
20858 case WL_PROF_CHAN:
20859 rptr = &profile->channel;
20860 break;
20861 case WL_PROF_LATEST_BSSID:
20862 rptr = profile->latest_bssid;
20863 break;
20864 }
20865 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
20866 if (!rptr)
20867 WL_ERR(("invalid item (%d)\n", item));
20868 return rptr;
20869}
20870
20871static s32
20872wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
20873 const wl_event_msg_t *e, const void *data, s32 item)
20874{
20875 s32 err = 0;
20876 const struct wlc_ssid *ssid;
20877 unsigned long flags;
20878 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
20879
20880 if (!profile)
20881 return WL_INVALID;
20882 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
20883 switch (item) {
20884 case WL_PROF_SSID:
20885 ssid = (const wlc_ssid_t *) data;
20886 bzero(profile->ssid.SSID,
20887 sizeof(profile->ssid.SSID));
20888 profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
20889 memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
20890 break;
20891 case WL_PROF_BSSID:
20892 if (data)
20893 memcpy(profile->bssid, data, ETHER_ADDR_LEN);
20894 else
20895 bzero(profile->bssid, ETHER_ADDR_LEN);
20896 break;
20897 case WL_PROF_SEC:
20898 memcpy(&profile->sec, data, sizeof(profile->sec));
20899 break;
20900 case WL_PROF_ACT:
20901 profile->active = *(const bool *)data;
20902 break;
20903 case WL_PROF_BEACONINT:
20904 profile->beacon_interval = *(const u16 *)data;
20905 break;
20906 case WL_PROF_DTIMPERIOD:
20907 profile->dtim_period = *(const u8 *)data;
20908 break;
20909 case WL_PROF_CHAN:
20910 profile->channel = *(const chanspec_t *)data;
20911 break;
20912 case WL_PROF_LATEST_BSSID:
20913 if (data) {
20914 memcpy_s(profile->latest_bssid, sizeof(profile->latest_bssid),
20915 data, ETHER_ADDR_LEN);
20916 } else {
20917 memset_s(profile->latest_bssid, sizeof(profile->latest_bssid),
20918 0, ETHER_ADDR_LEN);
20919 }
20920 break;
20921 default:
20922 err = -EOPNOTSUPP;
20923 break;
20924 }
20925 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
20926
20927 if (err == -EOPNOTSUPP)
20928 WL_ERR(("unsupported item (%d)\n", item));
20929
20930 return err;
20931}
20932
20933void wl_cfg80211_dbg_level(u32 level)
20934{
20935 /*
20936 * prohibit to change debug level
20937 * by insmod parameter.
20938 * eventually debug level will be configured
20939 * in compile time by using CONFIG_XXX
20940 */
20941 /* wl_dbg_level = level; */
20942}
20943
20944static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev)
20945{
20946 return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS;
20947}
20948
20949static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
20950{
20951 return cfg->ibss_starter;
20952}
20953
20954static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
20955{
20956 struct wl_ie *ie = wl_to_ie(cfg);
20957 s32 err = 0;
20958
20959 if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
20960 WL_ERR(("ei crosses buffer boundary\n"));
20961 return -ENOSPC;
20962 }
20963 ie->buf[ie->offset] = t;
20964 ie->buf[ie->offset + 1] = l;
20965 memcpy(&ie->buf[ie->offset + 2], v, l);
20966 ie->offset += l + 2;
20967
20968 return err;
20969}
20970
20971static void wl_link_up(struct bcm_cfg80211 *cfg)
20972{
20973 cfg->link_up = true;
20974}
20975
20976static void wl_link_down(struct bcm_cfg80211 *cfg)
20977{
20978 struct wl_connect_info *conn_info = wl_to_conn(cfg);
20979
20980 WL_DBG(("In\n"));
20981 cfg->link_up = false;
20982 if (conn_info) {
20983 conn_info->req_ie_len = 0;
20984 conn_info->resp_ie_len = 0;
20985 }
20986}
20987
20988static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
20989{
20990 unsigned long flags;
20991
20992 WL_CFG_EQ_LOCK(&cfg->eq_lock, flags);
20993 return flags;
20994}
20995
20996static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
20997{
20998 WL_CFG_EQ_UNLOCK(&cfg->eq_lock, flags);
20999}
21000
21001static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
21002{
21003 spin_lock_init(&cfg->eq_lock);
21004}
21005
21006static void wl_delay(u32 ms)
21007{
21008 if (in_atomic() || (ms < jiffies_to_msecs(1))) {
21009 OSL_DELAY(ms*1000);
21010 } else {
21011 OSL_SLEEP(ms);
21012 }
21013}
21014
21015s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
21016{
21017 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
21018 struct ether_addr primary_mac;
21019 if (!cfg->p2p)
21020 return -1;
21021 if (!p2p_is_on(cfg)) {
21022 get_primary_mac(cfg, &primary_mac);
21023 memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN);
21024 } else {
21025 memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
21026 ETHER_ADDR_LEN);
21027 }
21028
21029 return 0;
21030}
21031s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
21032{
21033 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
21034
21035 return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
21036}
21037
21038s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
21039{
21040 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
21041
21042 return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
21043}
21044
21045s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
21046{
21047 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
21048
21049 return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
21050}
21051
21052s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
21053{
21054 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
21055
21056 return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
21057}
21058
21059s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
21060{
21061 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
21062
21063 return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
21064}
21065
21066#ifdef P2PLISTEN_AP_SAMECHN
21067s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
21068{
21069 s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
21070
21071 if ((ret == 0) && enable) {
21072 /* disable PM for p2p responding on infra AP channel */
21073 s32 pm = PM_OFF;
21074
21075 ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm));
21076 }
21077
21078 return ret;
21079}
21080#endif /* P2PLISTEN_AP_SAMECHN */
21081
21082#ifdef WLTDLS
21083s32
21084wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21085 const wl_event_msg_t *e, void *data) {
21086
21087 struct net_device *ndev = NULL;
21088 u32 reason = ntoh32(e->reason);
21089 s8 *msg = NULL;
21090
21091 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
21092
21093 switch (reason) {
21094 case WLC_E_TDLS_PEER_DISCOVERED :
21095 msg = " TDLS PEER DISCOVERD ";
21096 break;
21097 case WLC_E_TDLS_PEER_CONNECTED :
21098 if (cfg->tdls_mgmt_frame) {
21099#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
21100 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
21101 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0);
21102#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
21103 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
21104 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0,
21105 GFP_ATOMIC);
21106#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
21107 defined(WL_COMPAT_WIRELESS)
21108 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
21109 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
21110 GFP_ATOMIC);
21111#else
21112 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
21113 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, GFP_ATOMIC);
21114
21115#endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
21116 }
21117 msg = " TDLS PEER CONNECTED ";
21118#ifdef SUPPORT_SET_CAC
21119 /* TDLS connect reset CAC */
21120 wl_cfg80211_set_cac(cfg, 0);
21121#endif /* SUPPORT_SET_CAC */
21122 break;
21123 case WLC_E_TDLS_PEER_DISCONNECTED :
21124 if (cfg->tdls_mgmt_frame) {
21125 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
21126 cfg->tdls_mgmt_frame_len = 0;
21127 cfg->tdls_mgmt_freq = 0;
21128 }
21129 msg = "TDLS PEER DISCONNECTED ";
21130#ifdef SUPPORT_SET_CAC
21131 /* TDLS disconnec, set CAC */
21132 wl_cfg80211_set_cac(cfg, 1);
21133#endif /* SUPPORT_SET_CAC */
21134 break;
21135 }
21136 if (msg) {
21137 WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((const u8*)(&e->addr)),
21138 (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
21139 }
21140 return 0;
21141
21142}
21143
21144#endif /* WLTDLS */
21145
21146static s32
21147#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
21148#if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
21149 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
21150wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
21151 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
21152 u32 peer_capability, const u8 *buf, size_t len)
21153#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
21154 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
21155wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
21156 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
21157 u32 peer_capability, const u8 *buf, size_t len)
21158#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
21159wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
21160 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
21161 u32 peer_capability, bool initiator, const u8 *buf, size_t len)
21162#else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
21163wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
21164 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
21165 const u8 *buf, size_t len)
21166#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
21167{
21168 s32 ret = 0;
21169#if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
21170 struct bcm_cfg80211 *cfg;
21171 tdls_wfd_ie_iovar_t info;
21172 bzero(&info, sizeof(info));
21173 cfg = wl_get_cfg(dev);
21174
21175#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
21176 /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
21177 * and that cuases build error
21178 */
21179 BCM_REFERENCE(peer_capability);
21180#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
21181
21182 switch (action_code) {
21183 /* We need to set TDLS Wifi Display IE to firmware
21184 * using tdls_wfd_ie iovar
21185 */
21186 case WLAN_TDLS_SET_PROBE_WFD_IE:
21187 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_PROBE_WFD_IE\n"));
21188 info.mode = TDLS_WFD_PROBE_IE_TX;
21189
21190 if (len > sizeof(info.data)) {
21191 return -EINVAL;
21192 }
21193 memcpy(&info.data, buf, len);
21194 info.length = len;
21195 break;
21196 case WLAN_TDLS_SET_SETUP_WFD_IE:
21197 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_SETUP_WFD_IE\n"));
21198 info.mode = TDLS_WFD_IE_TX;
21199
21200 if (len > sizeof(info.data)) {
21201 return -EINVAL;
21202 }
21203 memcpy(&info.data, buf, len);
21204 info.length = len;
21205 break;
21206 case WLAN_TDLS_SET_WFD_ENABLED:
21207 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_ENABLED\n"));
21208 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
21209 goto out;
21210 case WLAN_TDLS_SET_WFD_DISABLED:
21211 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_DISABLED\n"));
21212 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
21213 goto out;
21214 default:
21215 WL_ERR(("Unsupported action code : %d\n", action_code));
21216 goto out;
21217 }
21218 ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
21219 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
21220
21221 if (ret) {
21222 WL_ERR(("tdls_wfd_ie error %d\n", ret));
21223 }
21224
21225out:
21226#endif /* TDLS_MSG_ONLY_WFD && WLTDLS */
21227 return ret;
21228}
21229
21230#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
21231static s32
21232wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
21233 const u8 *peer, enum nl80211_tdls_operation oper)
21234#else
21235static s32
21236wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
21237 u8 *peer, enum nl80211_tdls_operation oper)
21238#endif
21239{
21240 s32 ret = 0;
21241#ifdef WLTDLS
21242 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21243 tdls_iovar_t info;
21244 dhd_pub_t *dhdp;
21245 bool tdls_auto_mode = false;
21246 dhdp = (dhd_pub_t *)(cfg->pub);
21247 bzero(&info, sizeof(tdls_iovar_t));
21248 if (peer) {
21249 memcpy(&info.ea, peer, ETHER_ADDR_LEN);
21250 } else {
21251 return -1;
21252 }
21253 switch (oper) {
21254 case NL80211_TDLS_DISCOVERY_REQ:
21255 /* If the discovery request is broadcast then we need to set
21256 * info.mode to Tunneled Probe Request
21257 */
21258 if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
21259 info.mode = TDLS_MANUAL_EP_WFD_TPQ;
21260 WL_ERR(("wl_cfg80211_tdls_oper: TDLS TUNNELED PRBOBE REQUEST\n"));
21261 } else {
21262 info.mode = TDLS_MANUAL_EP_DISCOVERY;
21263 }
21264 break;
21265 case NL80211_TDLS_SETUP:
21266 if (dhdp->tdls_mode == true) {
21267 info.mode = TDLS_MANUAL_EP_CREATE;
21268 tdls_auto_mode = false;
21269 /* Do tear down and create a fresh one */
21270 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_TEARDOWN, tdls_auto_mode);
21271 if (ret < 0) {
21272 return ret;
21273 }
21274 } else {
21275 tdls_auto_mode = true;
21276 }
21277 break;
21278 case NL80211_TDLS_TEARDOWN:
21279 info.mode = TDLS_MANUAL_EP_DELETE;
21280 break;
21281 default:
21282 WL_ERR(("Unsupported operation : %d\n", oper));
21283 goto out;
21284 }
21285 /* turn on TDLS */
21286 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_SETUP, tdls_auto_mode);
21287 if (ret < 0) {
21288 return ret;
21289 }
21290 if (info.mode) {
21291 ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
21292 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
21293 if (ret) {
21294 WL_ERR(("tdls_endpoint error %d\n", ret));
21295 }
21296 }
21297out:
21298 /* use linux generic error code instead of firmware error code */
21299 if (ret) {
21300 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
21301 return -ENOTSUPP;
21302 }
21303#endif /* WLTDLS */
21304 return ret;
21305}
21306#endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
21307
21308s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
21309 enum wl_management_type type)
21310{
21311 struct bcm_cfg80211 *cfg;
21312 s32 ret = 0;
21313 s32 bssidx = 0;
21314 s32 pktflag = 0;
21315 cfg = wl_get_cfg(ndev);
21316
21317 if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
21318 /* Vendor IEs should be set to FW
21319 * after SoftAP interface is brought up
21320 */
21321 WL_DBG(("Skipping set IE since AP is not up \n"));
21322 goto exit;
21323 } else if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
21324 /* Either stand alone AP case or P2P discovery */
21325 if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
21326 /* Stand alone AP case on primary interface */
21327 WL_DBG(("Apply IEs for Primary AP Interface \n"));
21328 bssidx = 0;
21329 } else {
21330 if (!cfg->p2p) {
21331 /* If p2p not initialized, return failure */
21332 WL_ERR(("P2P not initialized \n"));
21333 goto exit;
21334 }
21335 /* P2P Discovery case (p2p listen) */
21336 if (!cfg->p2p->on) {
21337 /* Turn on Discovery interface */
21338 p2p_on(cfg) = true;
21339 ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
21340 if (unlikely(ret)) {
21341 WL_ERR(("Enable discovery failed \n"));
21342 goto exit;
21343 }
21344 }
21345 WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
21346 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
21347 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
21348 }
21349 } else {
21350 /* Virtual AP/ P2P Group Interface */
21351 WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
21352 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
21353 }
21354
21355 if (ndev != NULL) {
21356 switch (type) {
21357 case WL_BEACON:
21358 pktflag = VNDR_IE_BEACON_FLAG;
21359 break;
21360 case WL_PROBE_RESP:
21361 pktflag = VNDR_IE_PRBRSP_FLAG;
21362 break;
21363 case WL_ASSOC_RESP:
21364 pktflag = VNDR_IE_ASSOCRSP_FLAG;
21365 break;
21366 }
21367 if (pktflag) {
21368 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
21369 ndev_to_cfgdev(ndev), bssidx, pktflag, buf, len);
21370 }
21371 }
21372exit:
21373 return ret;
21374}
21375
21376#ifdef WL_SUPPORT_AUTO_CHANNEL
21377static s32
21378wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev)
21379{
21380 u32 val = 0;
21381 s32 ret = BCME_ERROR;
21382 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21383 /* Set interface up, explicitly. */
21384 val = 1;
21385
21386 ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
21387 if (ret < 0) {
21388 WL_ERR(("set interface up failed, error = %d\n", ret));
21389 goto done;
21390 }
21391
21392 /* Stop all scan explicitly, till auto channel selection complete. */
21393 wl_set_drv_status(cfg, SCANNING, ndev);
21394 if (cfg->escan_info.ndev == NULL) {
21395 ret = BCME_OK;
21396 goto done;
21397 }
21398
21399 wl_cfg80211_cancel_scan(cfg);
21400
21401done:
21402 return ret;
21403}
21404
21405static bool
21406wl_cfg80211_valid_channel_p2p(int channel)
21407{
21408 bool valid = false;
21409
21410 /* channel 1 to 14 */
21411 if ((channel >= 1) && (channel <= 14)) {
21412 valid = true;
21413 }
21414 /* channel 36 to 48 */
21415 else if ((channel >= 36) && (channel <= 48)) {
21416 valid = true;
21417 }
21418 /* channel 149 to 161 */
21419 else if ((channel >= 149) && (channel <= 161)) {
21420 valid = true;
21421 }
21422 else {
21423 valid = false;
21424 WL_INFORM(("invalid P2P chanspec, channel = %d\n", channel));
21425 }
21426
21427 return valid;
21428}
21429
21430s32
21431wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
21432{
21433 s32 ret = BCME_ERROR;
21434 struct bcm_cfg80211 *cfg = NULL;
21435 chanspec_t chanspec = 0;
21436
21437 cfg = wl_get_cfg(ndev);
21438
21439 /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
21440 chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 |
21441 WL_CHANSPEC_CTL_SB_NONE);
21442 chanspec = wl_chspec_host_to_driver(chanspec);
21443
21444 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
21445 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
21446 if (ret < 0) {
21447 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
21448 }
21449
21450 return ret;
21451}
21452
21453s32
21454wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
21455{
21456 u32 channel = 0;
21457 s32 ret = BCME_ERROR;
21458 s32 i = 0;
21459 s32 j = 0;
21460 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21461 wl_uint32_list_t *list = NULL;
21462 chanspec_t chanspec = 0;
21463
21464 /* Restrict channels to 5GHz, 20MHz BW, no SB. */
21465 chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 |
21466 WL_CHANSPEC_CTL_SB_NONE);
21467 chanspec = wl_chspec_host_to_driver(chanspec);
21468
21469 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
21470 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
21471 if (ret < 0) {
21472 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
21473 goto done;
21474 }
21475
21476 list = (wl_uint32_list_t *)buf;
21477 /* Skip DFS and inavlid P2P channel. */
21478 for (i = 0, j = 0; i < dtoh32(list->count); i++) {
21479 chanspec = (chanspec_t) dtoh32(list->element[i]);
21480 channel = CHSPEC_CHANNEL(chanspec);
21481
21482 ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
21483 if (ret < 0) {
21484 WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret));
21485 goto done;
21486 }
21487
21488 if (CHANNEL_IS_RADAR(channel) ||
21489 !(wl_cfg80211_valid_channel_p2p(CHSPEC_CHANNEL(chanspec)))) {
21490 continue;
21491 } else {
21492 list->element[j] = list->element[i];
21493 }
21494
21495 j++;
21496 }
21497
21498 list->count = j;
21499
21500done:
21501 return ret;
21502}
21503
21504static s32
21505wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen,
21506 int *channel)
21507{
21508 s32 ret = BCME_ERROR;
21509 int chosen = 0;
21510 int retry = 0;
21511 uint chip;
21512
21513 /* Start auto channel selection scan. */
21514 ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, buf, buflen);
21515 if (ret < 0) {
21516 WL_ERR(("can't start auto channel scan, error = %d\n", ret));
21517 *channel = 0;
21518 goto done;
21519 }
21520
21521 /* Wait for auto channel selection, worst case possible delay is 5250ms. */
21522 retry = CHAN_SEL_RETRY_COUNT;
21523
21524 while (retry--) {
21525 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
21526 chosen = 0;
21527 ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
21528 if ((ret == 0) && (dtoh32(chosen) != 0)) {
21529 chip = dhd_conf_get_chip(dhd_get_pub(ndev));
21530 if (chip != BCM43362_CHIP_ID && chip != BCM4330_CHIP_ID &&
21531 chip != BCM43143_CHIP_ID) {
21532 u32 chanspec = 0;
21533 int ctl_chan;
21534 chanspec = wl_chspec_driver_to_host(chosen);
21535 WL_INFORM(("selected chanspec = 0x%x\n", chanspec));
21536 ctl_chan = wf_chspec_ctlchan(chanspec);
21537 WL_INFORM(("selected ctl_chan = %d\n", ctl_chan));
21538 *channel = (u16)(ctl_chan & 0x00FF);
21539 } else
21540 *channel = (u16)(chosen & 0x00FF);
21541 WL_INFORM(("selected channel = %d\n", *channel));
21542 break;
21543 }
21544 WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n",
21545 (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
21546 }
21547
21548 if (retry <= 0) {
21549 WL_ERR(("failure, auto channel selection timed out\n"));
21550 *channel = 0;
21551 ret = BCME_ERROR;
21552 }
21553 WL_INFORM(("selected channel = %d\n", *channel));
21554
21555done:
21556 return ret;
21557}
21558
21559static s32
21560wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev)
21561{
21562 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21563 /* Clear scan stop driver status. */
21564 wl_clr_drv_status(cfg, SCANNING, ndev);
21565
21566 return BCME_OK;
21567}
21568
21569s32
21570wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len)
21571{
21572 int channel = 0, band, band_cur;
21573 s32 ret = BCME_ERROR;
21574 u8 *buf = NULL;
21575 char *pos = cmd;
21576 struct bcm_cfg80211 *cfg = NULL;
21577 struct net_device *ndev = NULL;
21578
21579 bzero(cmd, total_len);
21580 cfg = wl_get_cfg(dev);
21581
21582 buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
21583 if (buf == NULL) {
21584 WL_ERR(("failed to allocate chanspec buffer\n"));
21585 return -ENOMEM;
21586 }
21587
21588 /*
21589 * Always use primary interface, irrespective of interface on which
21590 * command came.
21591 */
21592 ndev = bcmcfg_to_prmry_ndev(cfg);
21593
21594 /*
21595 * Make sure that FW and driver are in right state to do auto channel
21596 * selection scan.
21597 */
21598 ret = wl_cfg80211_set_auto_channel_scan_state(ndev);
21599 if (ret < 0) {
21600 WL_ERR(("can't set auto channel scan state, error = %d\n", ret));
21601 goto done;
21602 }
21603
21604 ret = wldev_ioctl(dev, WLC_GET_BAND, &band_cur, sizeof(band_cur), false);
21605 if (band_cur != WLC_BAND_5G) {
21606 /* Best channel selection in 2.4GHz band. */
21607 ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
21608 if (ret < 0) {
21609 WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
21610 goto done;
21611 }
21612
21613 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
21614 &channel);
21615 if (ret < 0) {
21616 WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
21617 goto done;
21618 }
21619
21620 if (CHANNEL_IS_2G(channel)) {
21621// channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
21622 } else {
21623 WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel));
21624 channel = 0;
21625 }
21626 pos += snprintf(pos, total_len, "2g=%d ", channel);
21627 }
21628
21629 if (band_cur != WLC_BAND_2G) {
21630 // terence 20140120: fix for some chipsets only return 2.4GHz channel (4330b2/43341b0/4339a0)
21631 band = band_cur==WLC_BAND_2G ? band_cur : WLC_BAND_5G;
21632 ret = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true);
21633 if (ret < 0) {
21634 WL_ERR(("WLC_SET_BAND error %d\n", ret));
21635 goto done;
21636 }
21637
21638 /* Best channel selection in 5GHz band. */
21639 ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
21640 if (ret < 0) {
21641 WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret));
21642 goto done;
21643 }
21644
21645 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
21646 &channel);
21647 if (ret < 0) {
21648 WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret));
21649 goto done;
21650 }
21651
21652 if (CHANNEL_IS_5G(channel)) {
21653// channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
21654 } else {
21655 WL_ERR(("invalid 5GHz channel, channel = %d\n", channel));
21656 channel = 0;
21657 }
21658
21659 ret = wldev_ioctl(dev, WLC_SET_BAND, &band_cur, sizeof(band_cur), true);
21660 if (ret < 0)
21661 WL_ERR(("WLC_SET_BAND error %d\n", ret));
21662 pos += snprintf(pos, total_len, "5g=%d ", channel);
21663 }
21664
21665done:
21666 if (NULL != buf) {
21667 MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
21668 }
21669
21670 /* Restore FW and driver back to normal state. */
21671 ret = wl_cfg80211_restore_auto_channel_scan_state(ndev);
21672 if (ret < 0) {
21673 WL_ERR(("can't restore auto channel scan state, error = %d\n", ret));
21674 }
21675
21676 WL_MSG(ndev->name, "%s\n", cmd);
21677
21678 return (pos - cmd);
21679}
21680#endif /* WL_SUPPORT_AUTO_CHANNEL */
21681
21682static const struct rfkill_ops wl_rfkill_ops = {
21683 .set_block = wl_rfkill_set
21684};
21685
21686static int wl_rfkill_set(void *data, bool blocked)
21687{
21688 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
21689
21690 WL_DBG(("Enter \n"));
21691 WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
21692
21693 if (!cfg)
21694 return -EINVAL;
21695
21696 cfg->rf_blocked = blocked;
21697
21698 return 0;
21699}
21700
21701static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
21702{
21703 s32 err = 0;
21704
21705 WL_DBG(("Enter \n"));
21706 if (!cfg)
21707 return -EINVAL;
21708 if (setup) {
21709 cfg->rfkill = rfkill_alloc("brcmfmac-wifi",
21710 wl_cfg80211_get_parent_dev(),
21711 RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
21712
21713 if (!cfg->rfkill) {
21714 err = -ENOMEM;
21715 goto err_out;
21716 }
21717
21718 err = rfkill_register(cfg->rfkill);
21719
21720 if (err)
21721 rfkill_destroy(cfg->rfkill);
21722 } else {
21723 if (!cfg->rfkill) {
21724 err = -ENOMEM;
21725 goto err_out;
21726 }
21727
21728 rfkill_unregister(cfg->rfkill);
21729 rfkill_destroy(cfg->rfkill);
21730 }
21731
21732err_out:
21733 return err;
21734}
21735
21736#ifdef DEBUGFS_CFG80211
21737/**
21738* Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
21739* to turn on SCAN and DBG log.
21740* To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
21741* To see current setting of debug level,
21742* cat /sys/kernel/debug/dhd/debug_level
21743*/
21744static ssize_t
21745wl_debuglevel_write(struct file *file, const char __user *userbuf,
21746 size_t count, loff_t *ppos)
21747{
21748 char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)], sublog[SUBLOGLEVELZ];
21749 char *params, *token, *colon;
21750 uint i, tokens, log_on = 0;
21751 size_t minsize = min_t(size_t, (sizeof(tbuf) - 1), count);
21752
21753 bzero(tbuf, sizeof(tbuf));
21754 bzero(sublog, sizeof(sublog));
21755 if (copy_from_user(&tbuf, userbuf, minsize)) {
21756 return -EFAULT;
21757 }
21758
21759 tbuf[minsize] = '\0';
21760 params = &tbuf[0];
21761 colon = strchr(params, '\n');
21762 if (colon != NULL)
21763 *colon = '\0';
21764 while ((token = strsep(&params, " ")) != NULL) {
21765 bzero(sublog, sizeof(sublog));
21766 if (token == NULL || !*token)
21767 break;
21768 if (*token == '\0')
21769 continue;
21770 colon = strchr(token, ':');
21771 if (colon != NULL) {
21772 *colon = ' ';
21773 }
21774 tokens = sscanf(token, "%"S(SUBLOGLEVEL)"s %u", sublog, &log_on);
21775 if (colon != NULL)
21776 *colon = ':';
21777
21778 if (tokens == 2) {
21779 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
21780 if (!strncmp(sublog, sublogname_map[i].sublogname,
21781 strlen(sublogname_map[i].sublogname))) {
21782 if (log_on)
21783 wl_dbg_level |=
21784 (sublogname_map[i].log_level);
21785 else
21786 wl_dbg_level &=
21787 ~(sublogname_map[i].log_level);
21788 }
21789 }
21790 } else
21791 WL_ERR(("%s: can't parse '%s' as a "
21792 "SUBMODULE:LEVEL (%d tokens)\n",
21793 tbuf, token, tokens));
21794
21795 }
21796 return count;
21797}
21798
21799static ssize_t
21800wl_debuglevel_read(struct file *file, char __user *user_buf,
21801 size_t count, loff_t *ppos)
21802{
21803 char *param;
21804 char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)];
21805 uint i;
21806 bzero(tbuf, sizeof(tbuf));
21807 param = &tbuf[0];
21808 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
21809 param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
21810 sublogname_map[i].sublogname,
21811 (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0);
21812 }
21813 *param = '\n';
21814 return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0]));
21815
21816}
21817static const struct file_operations fops_debuglevel = {
21818 .open = NULL,
21819 .write = wl_debuglevel_write,
21820 .read = wl_debuglevel_read,
21821 .owner = THIS_MODULE,
21822 .llseek = NULL,
21823};
21824
21825static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg)
21826{
21827 s32 err = 0;
21828 struct dentry *_dentry;
21829 if (!cfg)
21830 return -EINVAL;
21831 cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
21832 if (!cfg->debugfs || IS_ERR(cfg->debugfs)) {
21833 if (cfg->debugfs == ERR_PTR(-ENODEV))
21834 WL_ERR(("Debugfs is not enabled on this kernel\n"));
21835 else
21836 WL_ERR(("Can not create debugfs directory\n"));
21837 cfg->debugfs = NULL;
21838 goto exit;
21839
21840 }
21841 _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR,
21842 cfg->debugfs, cfg, &fops_debuglevel);
21843 if (!_dentry || IS_ERR(_dentry)) {
21844 WL_ERR(("failed to create debug_level debug file\n"));
21845 wl_free_debugfs(cfg);
21846 }
21847exit:
21848 return err;
21849}
21850static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg)
21851{
21852 if (!cfg)
21853 return -EINVAL;
21854 if (cfg->debugfs)
21855 debugfs_remove_recursive(cfg->debugfs);
21856 cfg->debugfs = NULL;
21857 return 0;
21858}
21859#endif /* DEBUGFS_CFG80211 */
21860
21861struct bcm_cfg80211 *wl_cfg80211_get_bcmcfg(void)
21862{
21863 return g_bcmcfg;
21864}
21865
21866void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 *cfg)
21867{
21868 g_bcmcfg = cfg;
21869}
21870
21871struct device *wl_cfg80211_get_parent_dev(void)
21872{
21873 return cfg80211_parent_dev;
21874}
21875
21876void wl_cfg80211_set_parent_dev(void *dev)
21877{
21878 cfg80211_parent_dev = dev;
21879}
21880
21881static void wl_cfg80211_clear_parent_dev(void)
21882{
21883 cfg80211_parent_dev = NULL;
21884}
21885
21886void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
21887{
21888 u8 ioctl_buf[WLC_IOCTL_SMLEN];
21889
21890 if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
21891 "cur_etheraddr", NULL, 0, ioctl_buf, sizeof(ioctl_buf),
21892 0, NULL) == BCME_OK) {
21893 memcpy(mac->octet, ioctl_buf, ETHER_ADDR_LEN);
21894 } else {
21895 bzero(mac->octet, ETHER_ADDR_LEN);
21896 }
21897}
21898static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
21899{
21900 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
21901 if (((dev_role == NL80211_IFTYPE_AP) &&
21902 !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
21903 ((dev_role == NL80211_IFTYPE_P2P_GO) &&
21904 !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
21905 {
21906 WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
21907 return false;
21908 }
21909 return true;
21910}
21911
21912int wl_cfg80211_do_driver_init(struct net_device *net)
21913{
21914 struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
21915
21916 if (!cfg || !cfg->wdev)
21917 return -EINVAL;
21918
21919 if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
21920 return -1;
21921
21922 return 0;
21923}
21924
21925void wl_cfg80211_enable_trace(u32 level)
21926{
21927 wl_dbg_level = level;
21928 WL_MSG("wlan", "wl_dbg_level = 0x%x\n", wl_dbg_level);
21929}
21930
21931#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
21932 2, 0))
21933static s32
21934wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
21935 bcm_struct_cfgdev *cfgdev, u64 cookie)
21936{
21937 /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
21938 * is passed with CMD_FRAME. This callback is supposed to cancel
21939 * the OFFCHANNEL Wait. Since we are already taking care of that
21940 * with the tx_mgmt logic, do nothing here.
21941 */
21942
21943 return 0;
21944}
21945#endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
21946
21947#ifdef WL_HOST_BAND_MGMT
21948s32
21949wl_cfg80211_set_band(struct net_device *ndev, int band)
21950{
21951 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21952 int ret = 0;
21953 char ioctl_buf[50];
21954
21955 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
21956 WL_ERR(("Invalid band\n"));
21957 return -EINVAL;
21958 }
21959
21960 if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band,
21961 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
21962 WL_ERR(("seting roam_band failed code=%d\n", ret));
21963 return ret;
21964 }
21965
21966 WL_DBG(("Setting band to %d\n", band));
21967 cfg->curr_band = band;
21968
21969 return 0;
21970}
21971#endif /* WL_HOST_BAND_MGMT */
21972
21973s32
21974wl_cfg80211_set_if_band(struct net_device *ndev, int band)
21975{
21976 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21977 int ret = BCME_OK, wait_cnt;
21978 char ioctl_buf[32];
21979
21980 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
21981 WL_ERR(("Invalid band\n"));
21982 return -EINVAL;
21983 }
21984
21985 if (cfg->ncho_band == band) {
21986 WL_ERR(("Same to Current band %d\n", cfg->ncho_band));
21987 return ret;
21988 }
21989
21990 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
21991 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
21992 BCM_REFERENCE(dhdp);
21993 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
21994 dhd_net2idx(dhdp->info, ndev), 0);
21995 ret = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
21996 if (ret < 0) {
21997 WL_ERR(("WLC_DISASSOC error %d\n", ret));
21998 /* continue to set 'if_band' */
21999 }
22000 else {
22001 /* This is to ensure that 'if_band' iovar is issued only after
22002 * disconnection is completed
22003 */
22004 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
22005 while (wl_get_drv_status(cfg, CONNECTED, ndev) && wait_cnt) {
22006 WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt));
22007 wait_cnt--;
22008 OSL_SLEEP(50);
22009 }
22010 }
22011 }
22012 if ((ret = wldev_iovar_setbuf(ndev, "if_band", &band,
22013 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
22014 WL_ERR(("seting if_band failed ret=%d\n", ret));
22015 /* issue 'WLC_SET_BAND' if if_band is not supported */
22016 if (ret == BCME_UNSUPPORTED) {
22017 ret = wldev_set_band(ndev, band);
22018 if (ret < 0) {
22019 WL_ERR(("seting band failed ret=%d\n", ret));
22020 }
22021 }
22022 }
22023
22024 if (ret == BCME_OK) {
22025 cfg->ncho_band = band;
22026 }
22027 return ret;
22028}
22029
22030s32
22031wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int total_len)
22032{
22033 char ioctl_buf[WLC_IOCTL_SMLEN];
22034 int err = 0;
22035 uint32 val = 0;
22036 chanspec_t chanspec = 0;
22037 int abort;
22038 int bytes_written = 0;
22039 struct wl_dfs_ap_move_status_v2 *status;
22040 char chanbuf[CHANSPEC_STR_LEN];
22041 const char *dfs_state_str[DFS_SCAN_S_MAX] = {
22042 "Radar Free On Channel",
22043 "Radar Found On Channel",
22044 "Radar Scan In Progress",
22045 "Radar Scan Aborted",
22046 "RSDB Mode switch in Progress For Scan"
22047 };
22048 if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
22049 bytes_written = snprintf(command, total_len, "AP is not up\n");
22050 return bytes_written;
22051 }
22052 if (!*data) {
22053 if ((err = wldev_iovar_getbuf(ndev, "dfs_ap_move", NULL, 0,
22054 ioctl_buf, sizeof(ioctl_buf), NULL))) {
22055 WL_ERR(("setting dfs_ap_move failed with err=%d \n", err));
22056 return err;
22057 }
22058 status = (struct wl_dfs_ap_move_status_v2 *)ioctl_buf;
22059
22060 if (status->version != WL_DFS_AP_MOVE_VERSION) {
22061 err = BCME_UNSUPPORTED;
22062 WL_ERR(("err=%d version=%d\n", err, status->version));
22063 return err;
22064 }
22065
22066 if (status->move_status != (int8) DFS_SCAN_S_IDLE) {
22067 chanspec = wl_chspec_driver_to_host(status->chanspec);
22068 if (chanspec != 0 && chanspec != INVCHANSPEC) {
22069 wf_chspec_ntoa(chanspec, chanbuf);
22070 bytes_written = snprintf(command, total_len,
22071 "AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
22072 }
22073 bytes_written += snprintf(command + bytes_written,
22074 total_len - bytes_written,
22075 "%s\n", dfs_state_str[status->move_status]);
22076 return bytes_written;
22077 } else {
22078 bytes_written = snprintf(command, total_len, "dfs AP move in IDLE state\n");
22079 return bytes_written;
22080 }
22081 }
22082
22083 abort = bcm_atoi(data);
22084 if (abort == -1) {
22085 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &abort,
22086 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
22087 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
22088 return err;
22089 }
22090 } else {
22091 chanspec = wf_chspec_aton(data);
22092 if (chanspec != 0) {
22093 val = wl_chspec_host_to_driver(chanspec);
22094 if (val != INVCHANSPEC) {
22095 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &val,
22096 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
22097 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
22098 return err;
22099 }
22100 WL_DBG((" set dfs_ap_move successfull"));
22101 } else {
22102 err = BCME_USAGE_ERROR;
22103 }
22104 }
22105 }
22106 return err;
22107}
22108
22109bool wl_cfg80211_is_concurrent_mode(struct net_device *dev)
22110{
22111 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22112 if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
22113 return true;
22114 } else {
22115 return false;
22116 }
22117}
22118
22119/*
22120 * This is to support existing btcoex implementation
22121 * btcoex clean up may help removing this function
22122 */
22123void* wl_cfg80211_get_dhdp(struct net_device *dev)
22124{
22125 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22126
22127 return cfg->pub;
22128}
22129
22130bool wl_cfg80211_is_p2p_active(struct net_device *dev)
22131{
22132 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22133 return (cfg && cfg->p2p);
22134}
22135
22136bool wl_cfg80211_is_roam_offload(struct net_device * dev)
22137{
22138 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22139 return (cfg && cfg->roam_offload);
22140}
22141
22142bool wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev, const wl_event_msg_t *e,
22143 int ifidx)
22144{
22145 u8 *curbssid = NULL;
22146 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22147
22148 if (!cfg) {
22149 /* When interface is created using wl
22150 * ndev->ieee80211_ptr will be NULL.
22151 */
22152 return NULL;
22153 }
22154 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
22155
22156 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
22157 return true;
22158 }
22159 return false;
22160}
22161
22162static void wl_cfg80211_work_handler(struct work_struct * work)
22163{
22164 struct bcm_cfg80211 *cfg = NULL;
22165 struct net_info *iter, *next;
22166 s32 err = BCME_OK;
22167 s32 pm = PM_FAST;
22168 dhd_pub_t *dhd;
22169 BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
22170 WL_DBG(("Enter \n"));
22171 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22172 for_each_ndev(cfg, iter, next) {
22173 GCC_DIAGNOSTIC_POP();
22174 /* p2p discovery iface ndev could be null */
22175 if (iter->ndev) {
22176 if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
22177 (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
22178 wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
22179 continue;
22180 if (iter->ndev) {
22181 dhd = (dhd_pub_t *)(cfg->pub);
22182 if (dhd_conf_get_pm(dhd) >= 0)
22183 pm = dhd_conf_get_pm(dhd);
22184 if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM,
22185 &pm, sizeof(pm))) != 0) {
22186 if (err == -ENODEV)
22187 WL_DBG(("%s:netdev not ready\n",
22188 iter->ndev->name));
22189 else
22190 WL_ERR(("%s:error (%d)\n",
22191 iter->ndev->name, err));
22192 } else
22193 wl_cfg80211_update_power_mode(iter->ndev);
22194 }
22195 }
22196 }
22197
22198 DHD_PM_WAKE_UNLOCK(cfg->pub);
22199
22200}
22201
22202u8
22203wl_get_action_category(void *frame, u32 frame_len)
22204{
22205 u8 category;
22206 u8 *ptr = (u8 *)frame;
22207 if (frame == NULL)
22208 return DOT11_ACTION_CAT_ERR_MASK;
22209 if (frame_len < DOT11_ACTION_HDR_LEN)
22210 return DOT11_ACTION_CAT_ERR_MASK;
22211 category = ptr[DOT11_ACTION_CAT_OFF];
22212 WL_DBG(("Action Category: %d\n", category));
22213 return category;
22214}
22215
22216int
22217wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
22218{
22219 u8 *ptr = (u8 *)frame;
22220 if (frame == NULL || ret_action == NULL)
22221 return BCME_ERROR;
22222 if (frame_len < DOT11_ACTION_HDR_LEN)
22223 return BCME_ERROR;
22224 if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
22225 return BCME_ERROR;
22226 *ret_action = ptr[DOT11_ACTION_ACT_OFF];
22227 WL_DBG(("Public Action : %d\n", *ret_action));
22228 return BCME_OK;
22229}
22230
22231#ifdef WLFBT
22232int
22233wl_cfg80211_get_fbt_key(struct net_device *dev, uint8 *key, int total_len)
22234{
22235 struct bcm_cfg80211 * cfg = wl_get_cfg(dev);
22236 int bytes_written = -1;
22237
22238 if (total_len < FBT_KEYLEN) {
22239 WL_ERR(("wl_cfg80211_get_fbt_key: Insufficient buffer \n"));
22240 goto end;
22241 }
22242 if (cfg) {
22243 memcpy(key, cfg->fbt_key, FBT_KEYLEN);
22244 bytes_written = FBT_KEYLEN;
22245 } else {
22246 bzero(key, FBT_KEYLEN);
22247 WL_ERR(("wl_cfg80211_get_fbt_key: Failed to copy KCK and KEK \n"));
22248 }
22249 prhex("KCK, KEK", (uchar *)key, FBT_KEYLEN);
22250end:
22251 return bytes_written;
22252}
22253#endif /* WLFBT */
22254
22255static int
22256wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
22257 const struct ether_addr *bssid)
22258{
22259 s32 err;
22260 wl_event_msg_t e;
22261
22262 bzero(&e, sizeof(e));
22263 e.event_type = cpu_to_be32(WLC_E_ROAM);
22264 memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
22265 /* trigger the roam event handler */
22266 err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
22267
22268 return err;
22269}
22270
22271static bool
22272wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t *vndrie)
22273{
22274 if (vndrie->oui[0] == FILS_EXTID_MNG_HLP_CONTAINER_ID) {
22275 /* Skip adding fils HLP IE, its already done using
22276 * "WL_FILS_CMD_ADD_HLP_IE" subcmd.
22277 */
22278 WL_DBG(("%s:SKIP ADDING FILS HLP EXTN ID\n", __func__));
22279 return true;
22280 }
22281 return false;
22282}
22283
22284static s32
22285wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
22286 struct parsed_vndr_ies *vndr_ies)
22287{
22288 s32 err = BCME_OK;
22289 const vndr_ie_t *vndrie;
22290 const bcm_tlv_t *ie;
22291 struct parsed_vndr_ie_info *parsed_info;
22292 u32 count = 0;
22293 u32 remained_len;
22294
22295 remained_len = len;
22296 bzero(vndr_ies, sizeof(*vndr_ies));
22297
22298 WL_DBG(("---> len %d\n", len));
22299 ie = (const bcm_tlv_t *) parse;
22300 if (!bcm_valid_tlv(ie, remained_len))
22301 ie = NULL;
22302 while (ie) {
22303 if (count >= MAX_VNDR_IE_NUMBER)
22304 break;
22305 if (ie->id == DOT11_MNG_VS_ID || (ie->id == DOT11_MNG_ID_EXT_ID)) {
22306 vndrie = (const vndr_ie_t *) ie;
22307 if (ie->id == DOT11_MNG_ID_EXT_ID) {
22308 /* len should be bigger than sizeof ID extn field at least */
22309 if (vndrie->len < MIN_VENDOR_EXTN_IE_LEN) {
22310 WL_ERR(("%s: invalid vndr extn ie."
22311 " length %d\n",
22312 __FUNCTION__, vndrie->len));
22313 goto end;
22314 }
22315 if (wl_cfg80211_filter_vndr_ext_id(vndrie)) {
22316 goto end;
22317 }
22318 } else {
22319 /* len should be bigger than OUI length +
22320 * one data length at least
22321 */
22322 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
22323 WL_ERR(("wl_cfg80211_parse_vndr_ies:"
22324 " invalid vndr ie. length is too small %d\n",
22325 vndrie->len));
22326 goto end;
22327 }
22328
22329 /* if wpa or wme ie, do not add ie */
22330 if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
22331 ((vndrie->data[0] == WPA_OUI_TYPE) ||
22332 (vndrie->data[0] == WME_OUI_TYPE))) {
22333 CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
22334 goto end;
22335 }
22336 }
22337
22338 parsed_info = &vndr_ies->ie_info[count++];
22339
22340 /* save vndr ie information */
22341 parsed_info->ie_ptr = (const char *)vndrie;
22342 parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
22343 memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
22344 vndr_ies->count = count;
22345 if (ie->id == DOT11_MNG_ID_EXT_ID) {
22346 WL_DBG(("\t ** Vendor Extension ie id: 0x%02x, len:%d\n",
22347 ie->id, parsed_info->ie_len));
22348 } else {
22349 WL_DBG(("\t ** OUI "MACOUIDBG", type 0x%02x len:%d\n",
22350 MACOUI2STRDBG(parsed_info->vndrie.oui),
22351 parsed_info->vndrie.data[0], parsed_info->ie_len));
22352 }
22353 }
22354end:
22355 ie = bcm_next_tlv(ie, &remained_len);
22356 }
22357 return err;
22358}
22359
22360static bool
22361wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info *vndr_info)
22362{
22363 int i = 0;
22364
22365 while (exclude_vndr_oui_list[i]) {
22366 if (!memcmp(vndr_info->vndrie.oui,
22367 exclude_vndr_oui_list[i],
22368 DOT11_OUI_LEN)) {
22369 return TRUE;
22370 }
22371 i++;
22372 }
22373
22374 return FALSE;
22375}
22376
22377static bool
22378wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 *cfg,
22379 struct parsed_vndr_ie_info *vndr_info)
22380{
22381 wl_vndr_oui_entry_t *oui_entry = NULL;
22382 unsigned long flags;
22383
22384 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
22385 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22386 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
22387 GCC_DIAGNOSTIC_POP();
22388 if (!memcmp(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN)) {
22389 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22390 return TRUE;
22391 }
22392 }
22393 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22394 return FALSE;
22395}
22396
22397static bool
22398wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 *cfg,
22399 struct parsed_vndr_ie_info *vndr_info)
22400{
22401 wl_vndr_oui_entry_t *oui_entry = NULL;
22402 unsigned long flags;
22403
22404 oui_entry = kmalloc(sizeof(*oui_entry), GFP_KERNEL);
22405 if (oui_entry == NULL) {
22406 WL_ERR(("alloc failed\n"));
22407 return FALSE;
22408 }
22409
22410 memcpy(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN);
22411
22412 INIT_LIST_HEAD(&oui_entry->list);
22413 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
22414 list_add_tail(&oui_entry->list, &cfg->vndr_oui_list);
22415 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22416
22417 return TRUE;
22418}
22419
22420static void
22421wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg)
22422{
22423 wl_vndr_oui_entry_t *oui_entry = NULL;
22424 unsigned long flags;
22425
22426 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
22427 while (!list_empty(&cfg->vndr_oui_list)) {
22428 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22429 oui_entry = list_entry(cfg->vndr_oui_list.next, wl_vndr_oui_entry_t, list);
22430 GCC_DIAGNOSTIC_POP();
22431 if (oui_entry) {
22432 list_del(&oui_entry->list);
22433 kfree(oui_entry);
22434 }
22435 }
22436 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22437}
22438
22439static int
22440wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
22441 char *vndr_oui, u32 vndr_oui_len)
22442{
22443 int i;
22444 int vndr_oui_num = 0;
22445
22446 struct wl_connect_info *conn_info = wl_to_conn(cfg);
22447 wl_vndr_oui_entry_t *oui_entry = NULL;
22448 struct parsed_vndr_ie_info *vndr_info;
22449 struct parsed_vndr_ies vndr_ies;
22450
22451 char *pos = vndr_oui;
22452 u32 remained_buf_len = vndr_oui_len;
22453 unsigned long flags;
22454
22455 if (!conn_info->resp_ie_len) {
22456 return BCME_ERROR;
22457 }
22458
22459 wl_vndr_ies_clear_vendor_oui_list(cfg);
22460
22461 if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
22462 conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
22463 for (i = 0; i < vndr_ies.count; i++) {
22464 vndr_info = &vndr_ies.ie_info[i];
22465 if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
22466 continue;
22467 }
22468
22469 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
22470 continue;
22471 }
22472
22473 wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
22474 vndr_oui_num++;
22475 }
22476 }
22477
22478 if (vndr_oui) {
22479 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
22480 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22481 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
22482 GCC_DIAGNOSTIC_POP();
22483 if (remained_buf_len < VNDR_OUI_STR_LEN) {
22484 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22485 return BCME_ERROR;
22486 }
22487 pos += snprintf(pos, VNDR_OUI_STR_LEN, "%02X-%02X-%02X ",
22488 oui_entry->oui[0], oui_entry->oui[1], oui_entry->oui[2]);
22489 remained_buf_len -= VNDR_OUI_STR_LEN;
22490 }
22491 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22492 }
22493
22494 return vndr_oui_num;
22495}
22496
22497#ifdef WL_ANALYTICS
22498static bool
22499wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
22500 const char *vndr_oui)
22501{
22502 int i;
22503 int vndr_oui_num = 0;
22504
22505 struct wl_connect_info *conn_info = wl_to_conn(cfg);
22506 wl_vndr_oui_entry_t *oui_entry = NULL;
22507 struct parsed_vndr_ie_info *vndr_info;
22508 struct parsed_vndr_ies vndr_ies;
22509
22510 unsigned long flags;
22511 bool found = FALSE;
22512
22513 if (!conn_info->resp_ie_len) {
22514 return FALSE;
22515 }
22516
22517 wl_vndr_ies_clear_vendor_oui_list(cfg);
22518
22519 if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
22520 conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
22521 for (i = 0; i < vndr_ies.count; i++) {
22522 vndr_info = &vndr_ies.ie_info[i];
22523 if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
22524 continue;
22525 }
22526
22527 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
22528 continue;
22529 }
22530
22531 wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
22532 vndr_oui_num++;
22533 }
22534 }
22535
22536 if (vndr_oui && vndr_oui_num) {
22537 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
22538 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22539 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
22540 GCC_DIAGNOSTIC_POP();
22541 if (!memcmp(vndr_oui, oui_entry->oui, DOT11_OUI_LEN)) {
22542 found = TRUE;
22543 break;
22544 }
22545 }
22546 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22547 }
22548
22549 return found;
22550}
22551#endif /* WL_ANALYTICS */
22552
22553void
22554wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 *cfg)
22555{
22556 /* Legacy P2P used to store it in primary dev cache */
22557 s32 index;
22558 struct net_device *ndev;
22559 s32 bssidx;
22560 s32 ret;
22561 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
22562 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
22563
22564 WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
22565 /* certain vendors uses p2p0 interface in addition to
22566 * the dedicated p2p interface supported by the linux
22567 * kernel.
22568 */
22569 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
22570 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
22571 if (bssidx == WL_INVALID) {
22572 WL_DBG(("No discovery I/F available. Do nothing.\n"));
22573 return;
22574 }
22575
22576 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
22577 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
22578 bssidx, vndrie_flag[index], NULL, 0)) < 0) {
22579 if (ret != BCME_NOTFOUND) {
22580 WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret));
22581 }
22582 }
22583 }
22584
22585 if (cfg->p2p_wdev && (ndev->ieee80211_ptr != cfg->p2p_wdev)) {
22586 /* clear IEs for dedicated p2p interface */
22587 wl_cfg80211_clear_per_bss_ies(cfg, cfg->p2p_wdev);
22588 }
22589}
22590
22591s32
22592wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
22593{
22594 s32 index;
22595 s32 ret;
22596 struct net_info *netinfo;
22597 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
22598 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
22599
22600 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
22601 if (!netinfo || !netinfo->wdev) {
22602 WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
22603 return -1;
22604 }
22605
22606 WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo->bssidx));
22607 /* Clear the IEs set in the firmware so that host is in sync with firmware */
22608 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
22609 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
22610 netinfo->bssidx, vndrie_flag[index], NULL, 0)) < 0)
22611 if (ret != BCME_NOTFOUND) {
22612 WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
22613 }
22614 }
22615
22616 return 0;
22617}
22618
22619s32
22620wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
22621{
22622 struct net_info *iter, *next;
22623
22624 WL_DBG(("clear management vendor IEs \n"));
22625 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22626 for_each_ndev(cfg, iter, next) {
22627 GCC_DIAGNOSTIC_POP();
22628 wl_cfg80211_clear_per_bss_ies(cfg, iter->wdev);
22629 }
22630 return 0;
22631}
22632
22633#define WL_VNDR_IE_MAXLEN 2048
22634static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
22635int
22636wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
22637 s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
22638{
22639 struct net_device *ndev = NULL;
22640 s32 ret = BCME_OK;
22641 u8 *curr_ie_buf = NULL;
22642 u8 *mgmt_ie_buf = NULL;
22643 u32 mgmt_ie_buf_len = 0;
22644 u32 *mgmt_ie_len = 0;
22645 u32 del_add_ie_buf_len = 0;
22646 u32 total_ie_buf_len = 0;
22647 u32 parsed_ie_buf_len = 0;
22648 struct parsed_vndr_ies old_vndr_ies;
22649 struct parsed_vndr_ies new_vndr_ies;
22650 s32 i;
22651 u8 *ptr;
22652 s32 remained_buf_len;
22653 wl_bss_vndr_ies_t *ies = NULL;
22654 struct net_info *netinfo;
22655 struct wireless_dev *wdev;
22656
22657 if (!cfgdev) {
22658 WL_ERR(("cfgdev is NULL\n"));
22659 return -EINVAL;
22660 }
22661
22662 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22663 wdev = cfgdev_to_wdev(cfgdev);
22664
22665 if (bssidx > WL_MAX_IFS) {
22666 WL_ERR(("bssidx > supported concurrent Ifaces \n"));
22667 return -EINVAL;
22668 }
22669
22670 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
22671 if (!netinfo) {
22672 WL_ERR(("net_info ptr is NULL \n"));
22673 return -EINVAL;
22674 }
22675
22676 /* Clear the global buffer */
22677 bzero(g_mgmt_ie_buf, sizeof(g_mgmt_ie_buf));
22678 curr_ie_buf = g_mgmt_ie_buf;
22679 ies = &netinfo->bss.ies;
22680
22681 WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d wdev:%p\n",
22682 pktflag, bssidx, vndr_ie_len, wdev));
22683
22684 switch (pktflag) {
22685 case VNDR_IE_PRBRSP_FLAG :
22686 mgmt_ie_buf = ies->probe_res_ie;
22687 mgmt_ie_len = &ies->probe_res_ie_len;
22688 mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
22689 break;
22690 case VNDR_IE_ASSOCRSP_FLAG :
22691 mgmt_ie_buf = ies->assoc_res_ie;
22692 mgmt_ie_len = &ies->assoc_res_ie_len;
22693 mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
22694 break;
22695 case VNDR_IE_BEACON_FLAG :
22696 mgmt_ie_buf = ies->beacon_ie;
22697 mgmt_ie_len = &ies->beacon_ie_len;
22698 mgmt_ie_buf_len = sizeof(ies->beacon_ie);
22699 break;
22700 case VNDR_IE_PRBREQ_FLAG :
22701 mgmt_ie_buf = ies->probe_req_ie;
22702 mgmt_ie_len = &ies->probe_req_ie_len;
22703 mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
22704 break;
22705 case VNDR_IE_ASSOCREQ_FLAG :
22706 mgmt_ie_buf = ies->assoc_req_ie;
22707 mgmt_ie_len = &ies->assoc_req_ie_len;
22708 mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
22709 break;
22710 case VNDR_IE_DISASSOC_FLAG :
22711 mgmt_ie_buf = ies->disassoc_ie;
22712 mgmt_ie_len = &ies->disassoc_ie_len;
22713 mgmt_ie_buf_len = sizeof(ies->disassoc_ie);
22714 break;
22715 default:
22716 mgmt_ie_buf = NULL;
22717 mgmt_ie_len = NULL;
22718 WL_ERR(("not suitable packet type (%d)\n", pktflag));
22719 return BCME_ERROR;
22720 }
22721
22722 if (vndr_ie_len > mgmt_ie_buf_len) {
22723 WL_ERR(("extra IE size too big\n"));
22724 ret = -ENOMEM;
22725 } else {
22726 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
22727 if (vndr_ie && vndr_ie_len && curr_ie_buf) {
22728 ptr = curr_ie_buf;
22729
22730 if ((ret = wl_cfg80211_parse_vndr_ies((const u8 *)vndr_ie,
22731 vndr_ie_len, &new_vndr_ies)) < 0) {
22732 WL_ERR(("parse vndr ie failed \n"));
22733 goto exit;
22734 }
22735
22736 for (i = 0; i < new_vndr_ies.count; i++) {
22737 struct parsed_vndr_ie_info *vndrie_info =
22738 &new_vndr_ies.ie_info[i];
22739
22740 if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
22741 WL_ERR(("IE size is too big (%d > %d)\n",
22742 parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
22743 ret = -EINVAL;
22744 goto exit;
22745 }
22746
22747 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
22748 vndrie_info->ie_len);
22749 parsed_ie_buf_len += vndrie_info->ie_len;
22750 }
22751 }
22752
22753 if (mgmt_ie_buf != NULL) {
22754 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
22755 (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
22756 WL_DBG(("Previous mgmt IE is equals to current IE"));
22757 goto exit;
22758 }
22759
22760 /* parse old vndr_ie */
22761 if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
22762 &old_vndr_ies)) < 0) {
22763 WL_ERR(("parse vndr ie failed \n"));
22764 goto exit;
22765 }
22766 /* make a command to delete old ie */
22767 for (i = 0; i < old_vndr_ies.count; i++) {
22768 struct parsed_vndr_ie_info *vndrie_info =
22769 &old_vndr_ies.ie_info[i];
22770#if defined(WL_MBO) || defined(WL_OCE)
22771 {
22772 if ((vndrie_info->vndrie.id == 0xDD) &&
22773 (!memcmp(vndrie_info->vndrie.oui, WFA_OUI, WFA_OUI_LEN)) &&
22774 (vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
22775 WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
22776 ", type: %0x\n",
22777 vndrie_info->vndrie.id,
22778 vndrie_info->vndrie.len,
22779 MACOUI2STRDBG(vndrie_info->vndrie.oui),
22780 vndrie_info->vndrie.data[0]));
22781 continue;
22782 }
22783 }
22784#endif /* WL_MBO || WL_OCE */
22785
22786 if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
22787 WL_DBG(("DELETED VENDOR EXTN ID : %d, TYPE: %d Len: %d\n",
22788 vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
22789 vndrie_info->vndrie.len));
22790 } else {
22791 WL_DBG(("DELETED ID : %d, Len: %d , OUI:"MACOUIDBG"\n",
22792 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
22793 MACOUI2STRDBG(vndrie_info->vndrie.oui)));
22794 }
22795
22796 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
22797 pktflag, vndrie_info->vndrie.oui,
22798 vndrie_info->vndrie.id,
22799 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
22800 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
22801 "del");
22802
22803 curr_ie_buf += del_add_ie_buf_len;
22804 total_ie_buf_len += del_add_ie_buf_len;
22805 }
22806 }
22807
22808 *mgmt_ie_len = 0;
22809 /* Add if there is any extra IE */
22810 if (mgmt_ie_buf && parsed_ie_buf_len) {
22811 ptr = mgmt_ie_buf;
22812
22813 remained_buf_len = mgmt_ie_buf_len;
22814
22815 /* make a command to add new ie */
22816 for (i = 0; i < new_vndr_ies.count; i++) {
22817 struct parsed_vndr_ie_info *vndrie_info =
22818 &new_vndr_ies.ie_info[i];
22819#if defined(WL_MBO) || defined(WL_OCE)
22820 {
22821 if ((vndrie_info->vndrie.id == 0xDD) &&
22822 (!memcmp(vndrie_info->vndrie.oui, WFA_OUI, WFA_OUI_LEN)) &&
22823 (vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
22824 WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
22825 ",type :%0x\n",
22826 vndrie_info->vndrie.id,
22827 vndrie_info->vndrie.len,
22828 MACOUI2STRDBG(vndrie_info->vndrie.oui),
22829 vndrie_info->vndrie.data[0]));
22830 continue;
22831 }
22832 }
22833#endif /* WL_MBO || WL_OCE */
22834 if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
22835 WL_DBG(("ADDED VENDOR EXTN ID : %d, TYPE = %d, Len: %d\n",
22836 vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
22837 vndrie_info->vndrie.len));
22838 } else {
22839 WL_DBG(("ADDED ID : %d, Len: %d(%d), OUI:"MACOUIDBG"\n",
22840 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
22841 vndrie_info->ie_len - 2,
22842 MACOUI2STRDBG(vndrie_info->vndrie.oui)));
22843 }
22844
22845 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
22846 pktflag, vndrie_info->vndrie.oui,
22847 vndrie_info->vndrie.id,
22848 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
22849 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
22850 "add");
22851
22852 /* verify remained buf size before copy data */
22853 if (remained_buf_len >= vndrie_info->ie_len) {
22854 remained_buf_len -= vndrie_info->ie_len;
22855 } else {
22856 WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
22857 "found vndr ies # = %d(cur %d), remained len %d, "
22858 "cur mgmt_ie_len %d, new ie len = %d\n",
22859 pktflag, new_vndr_ies.count, i, remained_buf_len,
22860 *mgmt_ie_len, vndrie_info->ie_len));
22861 break;
22862 }
22863
22864 /* save the parsed IE in cfg struct */
22865 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
22866 vndrie_info->ie_len);
22867 *mgmt_ie_len += vndrie_info->ie_len;
22868 curr_ie_buf += del_add_ie_buf_len;
22869 total_ie_buf_len += del_add_ie_buf_len;
22870 }
22871 }
22872
22873 if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
22874 ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
22875 total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
22876 bssidx, &cfg->ioctl_buf_sync);
22877 if (ret)
22878 WL_ERR(("vndr ie set error : %d\n", ret));
22879 }
22880 }
22881exit:
22882
22883return ret;
22884}
22885
22886#ifdef WL_CFG80211_ACL
22887static int
22888wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
22889 const struct cfg80211_acl_data *acl)
22890{
22891 int i;
22892 int ret = 0;
22893 int macnum = 0;
22894 int macmode = MACLIST_MODE_DISABLED;
22895 struct maclist *list;
22896 struct bcm_cfg80211 *cfg = wl_get_cfg(cfgdev);
22897
22898 /* get the MAC filter mode */
22899 if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
22900 macmode = MACLIST_MODE_ALLOW;
22901 } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
22902 acl->n_acl_entries) {
22903 macmode = MACLIST_MODE_DENY;
22904 }
22905
22906 /* if acl == NULL, macmode is still disabled.. */
22907 if (macmode == MACLIST_MODE_DISABLED) {
22908 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0)
22909 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list"
22910 " failed error=%d\n", ret));
22911
22912 return ret;
22913 }
22914
22915 macnum = acl->n_acl_entries;
22916 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
22917 WL_ERR(("wl_cfg80211_set_mac_acl: invalid number of MAC address entries %d\n",
22918 macnum));
22919 return -1;
22920 }
22921
22922 /* allocate memory for the MAC list */
22923 list = (struct maclist *)MALLOC(cfg->osh, sizeof(int) +
22924 sizeof(struct ether_addr) * macnum);
22925 if (!list) {
22926 WL_ERR(("wl_cfg80211_set_mac_acl: failed to allocate memory\n"));
22927 return -1;
22928 }
22929
22930 /* prepare the MAC list */
22931 list->count = htod32(macnum);
22932 for (i = 0; i < macnum; i++) {
22933 memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN);
22934 }
22935 /* set the list */
22936 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0)
22937 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list failed error=%d\n", ret));
22938
22939 MFREE(cfg->osh, list, sizeof(int) +
22940 sizeof(struct ether_addr) * macnum);
22941
22942 return ret;
22943}
22944#endif /* WL_CFG80211_ACL */
22945
22946#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22947int wl_chspec_chandef(chanspec_t chanspec,
22948#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
22949 struct cfg80211_chan_def *chandef,
22950#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
22951 struct chan_info *chaninfo,
22952#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
22953 struct wiphy *wiphy)
22954{
22955 uint16 freq = 0;
22956 int chan_type = 0;
22957 int channel = 0;
22958 struct ieee80211_channel *chan;
22959
22960 if (!chandef) {
22961 return -1;
22962 }
22963 channel = CHSPEC_CHANNEL(chanspec);
22964
22965 switch (CHSPEC_BW(chanspec)) {
22966 case WL_CHANSPEC_BW_20:
22967 chan_type = NL80211_CHAN_HT20;
22968 break;
22969 case WL_CHANSPEC_BW_40:
22970 {
22971 if (CHSPEC_SB_UPPER(chanspec)) {
22972 channel += CH_10MHZ_APART;
22973 } else {
22974 channel -= CH_10MHZ_APART;
22975 }
22976 }
22977 chan_type = NL80211_CHAN_HT40PLUS;
22978 break;
22979
22980#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
22981 case WL_CHANSPEC_BW_80:
22982 case WL_CHANSPEC_BW_8080:
22983 {
22984 uint16 sb = CHSPEC_CTL_SB(chanspec);
22985
22986 if (sb == WL_CHANSPEC_CTL_SB_LL) {
22987 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
22988 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
22989 channel -= CH_10MHZ_APART;
22990 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
22991 channel += CH_10MHZ_APART;
22992 } else {
22993 /* WL_CHANSPEC_CTL_SB_UU */
22994 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
22995 }
22996
22997 if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_LU)
22998 chan_type = NL80211_CHAN_HT40MINUS;
22999 else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU)
23000 chan_type = NL80211_CHAN_HT40PLUS;
23001 }
23002 break;
23003 case WL_CHANSPEC_BW_160:
23004 channel = wf_chspec_primary20_chan(chanspec);
23005 /* Using base chan_type as kernel does not define chan_type for 160 MHz */
23006 chan_type = NL80211_CHAN_HT20;
23007 break;
23008#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23009 default:
23010 chan_type = NL80211_CHAN_HT20;
23011 break;
23012
23013 }
23014 freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chanspec));
23015 chan = ieee80211_get_channel(wiphy, freq);
23016 WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
23017 channel, freq, chan_type, chan));
23018 if (unlikely(!chan)) {
23019 /* fw and cfg80211 channel lists are not in sync */
23020 WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
23021 ASSERT(0);
23022 return -EINVAL;
23023 }
23024
23025#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
23026 cfg80211_chandef_create(chandef, chan, chan_type);
23027#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
23028 0)))
23029 chaninfo->freq = freq;
23030 chaninfo->chan_type = chan_type;
23031#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23032 return 0;
23033}
23034
23035void
23036wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy)
23037{
23038 u32 freq;
23039#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
23040 struct cfg80211_chan_def chandef;
23041#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
23042 struct chan_info chaninfo;
23043#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23044
23045 if (!wiphy) {
23046 WL_ERR(("wiphy is null\n"));
23047 return;
23048 }
23049#if (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0))
23050 /* Channel switch support is only for AP/GO/ADHOC/MESH */
23051 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
23052 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
23053 WL_ERR(("No channel switch notify support for STA/GC\n"));
23054 return;
23055 }
23056#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
23057
23058#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
23059 if (wl_chspec_chandef(chanspec, &chandef, wiphy))
23060#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
23061 if (wl_chspec_chandef(chanspec, &chaninfo, wiphy))
23062#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23063 {
23064 WL_ERR(("chspec_chandef failed\n"));
23065 return;
23066 }
23067#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
23068 freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1;
23069 cfg80211_ch_switch_notify(dev, &chandef);
23070#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
23071 freq = chan_info.freq;
23072 cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type);
23073#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23074
23075 WL_MSG(dev->name, "Channel switch notification for freq: %d chanspec: 0x%x\n",
23076 freq, chanspec);
23077 return;
23078}
23079#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
23080
23081static void
23082wl_ap_channel_ind(struct bcm_cfg80211 *cfg,
23083 struct net_device *ndev,
23084 chanspec_t chanspec)
23085{
23086 u32 channel = LCHSPEC_CHANNEL(chanspec);
23087
23088 WL_INFORM_MEM(("(%s) AP channel:%d chspec:0x%x \n",
23089 ndev->name, channel, chanspec));
23090
23091#ifdef SUPPORT_AP_BWCTRL
23092 wl_update_apchan_bwcap(cfg, ndev, chanspec);
23093#endif /* SUPPORT_AP_BWCTRL */
23094
23095 if (!(cfg->ap_oper_channel == INVCHANSPEC) && (cfg->ap_oper_channel != chanspec)) {
23096 /*
23097 * If cached channel is different from the channel indicated
23098 * by the event, notify user space about the channel switch.
23099 */
23100#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
23101 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
23102#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
23103 cfg->ap_oper_channel = chanspec;
23104 }
23105}
23106
23107static s32
23108wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23109const wl_event_msg_t *e, void *data)
23110{
23111 struct net_device *ndev = NULL;
23112 chanspec_t chanspec;
23113
23114 WL_DBG(("Enter\n"));
23115 if (unlikely(e->status)) {
23116 WL_ERR(("status:0x%x \n", e->status));
23117 return -1;
23118 }
23119
23120 if (!data) {
23121 return -EINVAL;
23122 }
23123
23124 if (likely(cfgdev)) {
23125 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
23126 chanspec = *((chanspec_t *)data);
23127
23128 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
23129 /* For AP/GO role */
23130 wl_ap_channel_ind(cfg, ndev, chanspec);
23131 }
23132 }
23133
23134 return 0;
23135}
23136
23137static s32
23138wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23139const wl_event_msg_t *e, void *data)
23140{
23141 int error = 0;
23142 u32 chanspec = 0;
23143 struct net_device *ndev = NULL;
23144 struct ether_addr bssid;
23145
23146 WL_DBG(("Enter\n"));
23147 if (unlikely(e->status)) {
23148 WL_ERR(("status:0x%x \n", e->status));
23149 return -1;
23150 }
23151
23152 if (likely(cfgdev)) {
23153 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
23154 /* Get association state if not AP and then query chanspec */
23155 if (!((wl_get_mode_by_netdev(cfg, ndev)) == WL_MODE_AP)) {
23156 error = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
23157 if (error) {
23158 WL_ERR(("CSA on %s. Not associated. error=%d\n",
23159 ndev->name, error));
23160 return BCME_ERROR;
23161 }
23162 }
23163
23164 error = wldev_iovar_getint(ndev, "chanspec", &chanspec);
23165 if (unlikely(error)) {
23166 WL_ERR(("Get chanspec error: %d \n", error));
23167 return -1;
23168 }
23169
23170 WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev->name, chanspec));
23171 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
23172 /* For AP/GO role */
23173 wl_ap_channel_ind(cfg, ndev, chanspec);
23174 } else {
23175 /* STA/GC roles */
23176 if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
23177 WL_ERR(("CSA on %s. Not associated.\n", ndev->name));
23178 return BCME_ERROR;
23179 }
23180#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
23181 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
23182#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
23183 }
23184
23185 }
23186
23187 return 0;
23188}
23189
23190void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
23191{
23192 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
23193 int err;
23194
23195 /* Clear the security settings on the primary Interface */
23196 err = wldev_iovar_setint(dev, "wsec", 0);
23197 if (unlikely(err)) {
23198 WL_ERR(("wsec clear failed \n"));
23199 }
23200 err = wldev_iovar_setint(dev, "auth", 0);
23201 if (unlikely(err)) {
23202 WL_ERR(("auth clear failed \n"));
23203 }
23204 err = wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
23205 if (unlikely(err)) {
23206 WL_ERR(("wpa_auth clear failed \n"));
23207 }
23208}
23209
23210#ifdef WL_CFG80211_P2P_DEV_IF
23211void wl_cfg80211_del_p2p_wdev(struct net_device *dev)
23212{
23213 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23214 struct wireless_dev *wdev = NULL;
23215
23216 WL_DBG(("Enter \n"));
23217 if (!cfg) {
23218 WL_ERR(("Invalid Ptr\n"));
23219 return;
23220 } else {
23221 wdev = cfg->p2p_wdev;
23222 }
23223
23224 if (wdev) {
23225 wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
23226 }
23227}
23228#endif /* WL_CFG80211_P2P_DEV_IF */
23229
23230#ifdef GTK_OFFLOAD_SUPPORT
23231#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
23232static s32
23233wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
23234 struct cfg80211_gtk_rekey_data *data)
23235{
23236 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
23237 s32 err = 0;
23238 gtk_keyinfo_t keyinfo;
23239 bcol_gtk_para_t bcol_keyinfo;
23240
23241 WL_DBG(("Enter\n"));
23242 if (data == NULL || cfg->p2p_net == dev) {
23243 WL_ERR(("data is NULL or wrong net device\n"));
23244 return -EINVAL;
23245 }
23246
23247 prhex("kck", (const u8 *) (data->kck), RSN_KCK_LENGTH);
23248 prhex("kek", (const u8 *) (data->kek), RSN_KEK_LENGTH);
23249 prhex("replay_ctr", (const u8 *) (data->replay_ctr), RSN_REPLAY_LEN);
23250 bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH);
23251 bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH);
23252 bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN);
23253
23254 memset(&bcol_keyinfo, 0, sizeof(bcol_keyinfo));
23255 bcol_keyinfo.enable = 1;
23256 bcol_keyinfo.ptk_len = 64;
23257 memcpy(&bcol_keyinfo.ptk[0], data->kck, RSN_KCK_LENGTH);
23258 memcpy(&bcol_keyinfo.ptk[RSN_KCK_LENGTH], data->kek, RSN_KEK_LENGTH);
23259 err = wldev_iovar_setbuf(dev, "bcol_gtk_rekey_ptk", &bcol_keyinfo,
23260 sizeof(bcol_keyinfo), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
23261 if (!err) {
23262 return err;
23263 }
23264
23265 if ((err = wldev_iovar_setbuf(dev, "gtk_key_info", &keyinfo, sizeof(keyinfo),
23266 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync)) < 0) {
23267 WL_ERR(("seting gtk_key_info failed code=%d\n", err));
23268 return err;
23269 }
23270
23271 WL_DBG(("Exit\n"));
23272 return err;
23273}
23274#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
23275#endif /* GTK_OFFLOAD_SUPPORT */
23276
23277#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
23278static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
23279 const struct cfg80211_pmk_conf *conf)
23280{
23281 int ret = 0;
23282 wsec_pmk_t pmk;
23283 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
23284 struct wl_security *sec;
23285 s32 bssidx;
23286
23287 pmk.key_len = conf->pmk_len;
23288 if (pmk.key_len > sizeof(pmk.key)) {
23289 ret = -EINVAL;
23290 return ret;
23291 }
23292 pmk.flags = 0;
23293 ret = memcpy_s(&pmk.key, sizeof(pmk.key), conf->pmk, conf->pmk_len);
23294 if (ret) {
23295 ret = -EINVAL;
23296 return ret;
23297 }
23298
23299 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
23300 WL_ERR(("Find index failed\n"));
23301 ret = -EINVAL;
23302 return ret;
23303 }
23304
23305 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
23306 if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
23307 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
23308 ret = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len,
23309 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
23310 if (ret) {
23311 /* could fail in case that 'okc' is not supported */
23312 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
23313 }
23314 }
23315
23316 ret = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
23317 if (ret) {
23318 WL_ERR(("wl_cfg80211_set_pmk error:%d", ret));
23319 ret = -EINVAL;
23320 return ret;
23321 } else {
23322 WL_DBG(("pmk added for mac:"MACDBG"\n", MAC2STRDBG(conf->aa)));
23323 }
23324 return 0;
23325}
23326
23327static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
23328 const u8 *aa)
23329{
23330 int err = BCME_OK;
23331 struct cfg80211_pmksa pmksa;
23332
23333 /* build up cfg80211_pmksa structure to use existing wl_cfg80211_update_pmksa API */
23334 bzero(&pmksa, sizeof(pmksa));
23335 pmksa.bssid = aa;
23336
23337 err = wl_cfg80211_update_pmksa(wiphy, dev, &pmksa, FALSE);
23338 if (unlikely(err)) {
23339 WL_ERR(("wl_cfg80211_update_pmksa err:%d\n", err));
23340 err = -EINVAL;
23341 } else {
23342 WL_DBG(("pmk deleted for bssid:"MACDBG"\n", MAC2STRDBG(aa)));
23343 }
23344
23345 return err;
23346}
23347#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
23348
23349int
23350wl_cfg80211_get_sta_channel(struct bcm_cfg80211 *cfg)
23351{
23352 chanspec_t *sta_chanspec = NULL;
23353 u32 channel = 0;
23354
23355 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
23356 if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg,
23357 bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN))) {
23358 channel = CHSPEC_CHANNEL(*sta_chanspec);
23359 }
23360 }
23361 return channel;
23362}
23363
23364u64
23365wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
23366{
23367 u64 id = 0;
23368 id = ++cfg->last_roc_id;
23369#ifdef P2P_LISTEN_OFFLOADING
23370 if (id == P2PO_COOKIE) {
23371 id = ++cfg->last_roc_id;
23372 }
23373#endif /* P2P_LISTEN_OFFLOADING */
23374 if (id == 0)
23375 id = ++cfg->last_roc_id;
23376 return id;
23377}
23378
23379#ifdef WLTDLS
23380s32
23381wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg, enum wl_tdls_config state, bool auto_mode)
23382{
23383 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
23384 int err = 0;
23385 struct net_info *iter, *next;
23386 int update_reqd = 0;
23387 int enable = 0;
23388 dhd_pub_t *dhdp;
23389 dhdp = (dhd_pub_t *)(cfg->pub);
23390
23391 /*
23392 * TDLS need to be enabled only if we have a single STA/GC
23393 * connection.
23394 */
23395
23396 WL_DBG(("Enter state:%d\n", state));
23397 if (!cfg->tdls_supported) {
23398 /* FW doesn't support tdls. Do nothing */
23399 return -ENODEV;
23400 }
23401
23402 /* Protect tdls config session */
23403 mutex_lock(&cfg->tdls_sync);
23404
23405 if (state == TDLS_STATE_TEARDOWN) {
23406 /* Host initiated TDLS tear down */
23407 err = dhd_tdls_enable(ndev, false, auto_mode, NULL);
23408 goto exit;
23409 } else if ((state == TDLS_STATE_AP_CREATE) ||
23410 (state == TDLS_STATE_NMI_CREATE)) {
23411 /* We don't support tdls while AP/GO/NAN is operational */
23412 update_reqd = true;
23413 enable = false;
23414 } else if ((state == TDLS_STATE_CONNECT) || (state == TDLS_STATE_IF_CREATE)) {
23415 if (wl_get_drv_status_all(cfg,
23416 CONNECTED) >= TDLS_MAX_IFACE_FOR_ENABLE) {
23417 /* For STA/GC connect command request, disable
23418 * tdls if we have any concurrent interfaces
23419 * operational.
23420 */
23421 WL_DBG(("Interface limit restriction. disable tdls.\n"));
23422 update_reqd = true;
23423 enable = false;
23424 }
23425 } else if ((state == TDLS_STATE_DISCONNECT) ||
23426 (state == TDLS_STATE_AP_DELETE) ||
23427 (state == TDLS_STATE_SETUP) ||
23428 (state == TDLS_STATE_IF_DELETE)) {
23429 /* Enable back the tdls connection only if we have less than
23430 * or equal to a single STA/GC connection.
23431 */
23432 if (wl_get_drv_status_all(cfg,
23433 CONNECTED) == 0) {
23434 /* If there are no interfaces connected, enable tdls */
23435 update_reqd = true;
23436 enable = true;
23437 } else if (wl_get_drv_status_all(cfg,
23438 CONNECTED) == TDLS_MAX_IFACE_FOR_ENABLE) {
23439 /* We have one interface in CONNECTED state.
23440 * Verify whether its a STA interface before
23441 * we enable back tdls.
23442 */
23443 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23444 for_each_ndev(cfg, iter, next) {
23445 GCC_DIAGNOSTIC_POP();
23446 if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, ndev)) &&
23447 (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)) {
23448 WL_DBG(("Non STA iface operational. cfg_iftype:%d"
23449 " Can't enable tdls.\n",
23450 ndev->ieee80211_ptr->iftype));
23451 err = -ENOTSUPP;
23452 goto exit;
23453 }
23454 }
23455 /* No AP/GO found. Enable back tdls */
23456 update_reqd = true;
23457 enable = true;
23458 } else {
23459 WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
23460 err = -ENOTSUPP;
23461 goto exit;
23462 }
23463 } else {
23464 WL_ERR(("Unknown tdls state:%d \n", state));
23465 err = -EINVAL;
23466 goto exit;
23467 }
23468
23469 if (update_reqd == true) {
23470 if (dhdp->tdls_enable == enable) {
23471 WL_DBG(("No change in tdls state. Do nothing."
23472 " tdls_enable:%d\n", enable));
23473 goto exit;
23474 }
23475 err = wldev_iovar_setint(ndev, "tdls_enable", enable);
23476 if (unlikely(err)) {
23477 WL_ERR(("tdls_enable setting failed. err:%d\n", err));
23478 goto exit;
23479 } else {
23480 WL_INFORM_MEM(("tdls_enable %d state:%d\n", enable, state));
23481 /* Update the dhd state variable to be in sync */
23482 dhdp->tdls_enable = enable;
23483 if (state == TDLS_STATE_SETUP) {
23484 /* For host initiated setup, apply TDLS params
23485 * Don't propagate errors up for param config
23486 * failures
23487 */
23488 dhd_tdls_enable(ndev, true, auto_mode, NULL);
23489
23490 }
23491 }
23492 } else {
23493 WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
23494 "current_status:%d \n",
23495 state, update_reqd, dhdp->tdls_enable));
23496 }
23497
23498exit:
23499 if (err) {
23500 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
23501 }
23502 mutex_unlock(&cfg->tdls_sync);
23503 return err;
23504}
23505#endif /* WLTDLS */
23506
23507struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname)
23508{
23509 struct net_info *iter, *next;
23510 struct net_device *ndev = NULL;
23511
23512 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23513 for_each_ndev(cfg, iter, next) {
23514 GCC_DIAGNOSTIC_POP();
23515 if (iter->ndev) {
23516 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
23517 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
23518 ndev = iter->ndev;
23519 break;
23520 }
23521 }
23522 }
23523 }
23524
23525 return ndev;
23526}
23527
23528struct net_device*
23529wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname)
23530{
23531 struct net_info *iter, *next;
23532 struct net_device *ndev = NULL;
23533
23534 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23535 for_each_ndev(cfg, iter, next) {
23536 GCC_DIAGNOSTIC_POP();
23537 if (iter->ndev) {
23538 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
23539 ndev = iter->ndev;
23540 break;
23541 }
23542 }
23543 }
23544
23545 return ndev;
23546}
23547
23548#ifdef SUPPORT_AP_HIGHER_BEACONRATE
23549#define WLC_RATE_FLAG 0x80
23550#define RATE_MASK 0x7f
23551
23552int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname)
23553{
23554 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23555 dhd_pub_t *dhdp;
23556 wl_rateset_args_t rs;
23557 int error = BCME_ERROR, i;
23558 struct net_device *ndev = NULL;
23559
23560 dhdp = (dhd_pub_t *)(cfg->pub);
23561
23562 if (dhdp && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23563 WL_ERR(("Not Hostapd mode\n"));
23564 return BCME_NOTAP;
23565 }
23566
23567 ndev = wl_get_ap_netdev(cfg, ifname);
23568
23569 if (ndev == NULL) {
23570 WL_ERR(("No softAP interface named %s\n", ifname));
23571 return BCME_NOTAP;
23572 }
23573
23574 bzero(&rs, sizeof(wl_rateset_args_t));
23575 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
23576 &rs, sizeof(wl_rateset_args_t), NULL);
23577 if (error < 0) {
23578 WL_ERR(("get rateset failed = %d\n", error));
23579 return error;
23580 }
23581
23582 if (rs.count < 1) {
23583 WL_ERR(("Failed to get rate count\n"));
23584 return BCME_ERROR;
23585 }
23586
23587 /* Host delivers target rate in the unit of 500kbps */
23588 /* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic rate */
23589 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
23590 if (rs.rates[i] & WLC_RATE_FLAG)
23591 if ((rs.rates[i] & RATE_MASK) == val)
23592 break;
23593
23594 /* Valid rate has been delivered as an argument */
23595 if (i < rs.count && i < WL_NUMRATES) {
23596 error = wldev_iovar_setint(ndev, "force_bcn_rspec", val);
23597 if (error < 0) {
23598 WL_ERR(("set beacon rate failed = %d\n", error));
23599 return BCME_ERROR;
23600 }
23601 } else {
23602 WL_ERR(("Rate is invalid"));
23603 return BCME_BADARG;
23604 }
23605
23606 return BCME_OK;
23607}
23608
23609int
23610wl_get_ap_basic_rate(struct net_device *dev, char* command, char *ifname, int total_len)
23611{
23612 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23613 dhd_pub_t *dhdp;
23614 wl_rateset_args_t rs;
23615 int error = BCME_ERROR;
23616 int i, bytes_written = 0;
23617 struct net_device *ndev = NULL;
23618
23619 dhdp = (dhd_pub_t *)(cfg->pub);
23620
23621 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23622 WL_ERR(("Not Hostapd mode\n"));
23623 return BCME_NOTAP;
23624 }
23625
23626 ndev = wl_get_ap_netdev(cfg, ifname);
23627
23628 if (ndev == NULL) {
23629 WL_ERR(("No softAP interface named %s\n", ifname));
23630 return BCME_NOTAP;
23631 }
23632
23633 bzero(&rs, sizeof(wl_rateset_args_t));
23634 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
23635 &rs, sizeof(wl_rateset_args_t), NULL);
23636 if (error < 0) {
23637 WL_ERR(("get rateset failed = %d\n", error));
23638 return error;
23639 }
23640
23641 if (rs.count < 1) {
23642 WL_ERR(("Failed to get rate count\n"));
23643 return BCME_ERROR;
23644 }
23645
23646 /* Delivers basic rate in the unit of 500kbps to host */
23647 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
23648 if (rs.rates[i] & WLC_RATE_FLAG)
23649 bytes_written += snprintf(command + bytes_written, total_len,
23650 "%d ", rs.rates[i] & RATE_MASK);
23651
23652 /* Remove last space in the command buffer */
23653 if (bytes_written && (bytes_written < total_len)) {
23654 command[bytes_written - 1] = '\0';
23655 bytes_written--;
23656 }
23657
23658 return bytes_written;
23659
23660}
23661#endif /* SUPPORT_AP_HIGHER_BEACONRATE */
23662
23663#ifdef SUPPORT_AP_RADIO_PWRSAVE
23664#define MSEC_PER_MIN (60000L)
23665
23666static int
23667_wl_update_ap_rps_params(struct net_device *dev)
23668{
23669 struct bcm_cfg80211 *cfg = NULL;
23670 rpsnoa_iovar_params_t iovar;
23671 u8 smbuf[WLC_IOCTL_SMLEN];
23672
23673 if (!dev)
23674 return BCME_BADARG;
23675
23676 cfg = wl_get_cfg(dev);
23677
23678 bzero(&iovar, sizeof(iovar));
23679 bzero(smbuf, sizeof(smbuf));
23680
23681 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
23682 iovar.hdr.subcmd = WL_RPSNOA_CMD_PARAMS;
23683 iovar.hdr.len = sizeof(iovar);
23684 iovar.param->band = WLC_BAND_ALL;
23685 iovar.param->level = cfg->ap_rps_info.level;
23686 iovar.param->stas_assoc_check = cfg->ap_rps_info.sta_assoc_check;
23687 iovar.param->pps = cfg->ap_rps_info.pps;
23688 iovar.param->quiet_time = cfg->ap_rps_info.quiet_time;
23689
23690 if (wldev_iovar_setbuf(dev, "rpsnoa", &iovar, sizeof(iovar),
23691 smbuf, sizeof(smbuf), NULL)) {
23692 WL_ERR(("Failed to set rpsnoa params"));
23693 return BCME_ERROR;
23694 }
23695
23696 return BCME_OK;
23697}
23698
23699int
23700wl_get_ap_rps(struct net_device *dev, char* command, char *ifname, int total_len)
23701{
23702 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23703 dhd_pub_t *dhdp;
23704 int error = BCME_ERROR;
23705 int bytes_written = 0;
23706 struct net_device *ndev = NULL;
23707 rpsnoa_iovar_status_t iovar;
23708 u8 smbuf[WLC_IOCTL_SMLEN];
23709 u32 chanspec = 0;
23710 u8 idx = 0;
23711 u16 state;
23712 u32 sleep;
23713 u32 time_since_enable;
23714
23715 dhdp = (dhd_pub_t *)(cfg->pub);
23716
23717 if (!dhdp) {
23718 error = BCME_NOTUP;
23719 goto fail;
23720 }
23721
23722 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23723 WL_ERR(("Not Hostapd mode\n"));
23724 error = BCME_NOTAP;
23725 goto fail;
23726 }
23727
23728 ndev = wl_get_ap_netdev(cfg, ifname);
23729
23730 if (ndev == NULL) {
23731 WL_ERR(("No softAP interface named %s\n", ifname));
23732 error = BCME_NOTAP;
23733 goto fail;
23734 }
23735
23736 bzero(&iovar, sizeof(iovar));
23737 bzero(smbuf, sizeof(smbuf));
23738
23739 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
23740 iovar.hdr.subcmd = WL_RPSNOA_CMD_STATUS;
23741 iovar.hdr.len = sizeof(iovar);
23742 iovar.stats->band = WLC_BAND_ALL;
23743
23744 error = wldev_iovar_getbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
23745 smbuf, sizeof(smbuf), NULL);
23746 if (error < 0) {
23747 WL_ERR(("get ap radio pwrsave failed = %d\n", error));
23748 goto fail;
23749 }
23750
23751 /* RSDB event doesn't seem to be handled correctly.
23752 * So check chanspec of AP directly from the firmware
23753 */
23754 error = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
23755 if (error < 0) {
23756 WL_ERR(("get chanspec from AP failed = %d\n", error));
23757 goto fail;
23758 }
23759
23760 chanspec = wl_chspec_driver_to_host(chanspec);
23761 if (CHSPEC_IS2G(chanspec))
23762 idx = 0;
23763 else if (
23764#ifdef WL_6G_BAND
23765 CHSPEC_IS6G(chanspec) ||
23766#endif /* WL_6G_BAND */
23767 CHSPEC_IS5G(chanspec))
23768 idx = 1;
23769 else {
23770 error = BCME_BADCHAN;
23771 goto fail;
23772 }
23773
23774 state = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].state;
23775 sleep = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_dur;
23776 time_since_enable = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_avail_dur;
23777
23778 /* Conver ms to minute, round down only */
23779 sleep = DIV_U64_BY_U32(sleep, MSEC_PER_MIN);
23780 time_since_enable = DIV_U64_BY_U32(time_since_enable, MSEC_PER_MIN);
23781
23782 bytes_written += snprintf(command + bytes_written, total_len,
23783 "state=%d sleep=%d time_since_enable=%d", state, sleep, time_since_enable);
23784 error = bytes_written;
23785
23786fail:
23787 return error;
23788}
23789
23790int
23791wl_set_ap_rps(struct net_device *dev, bool enable, char *ifname)
23792{
23793 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23794 dhd_pub_t *dhdp;
23795 struct net_device *ndev = NULL;
23796 rpsnoa_iovar_t iovar;
23797 u8 smbuf[WLC_IOCTL_SMLEN];
23798 int ret = BCME_OK;
23799
23800 dhdp = (dhd_pub_t *)(cfg->pub);
23801
23802 if (!dhdp) {
23803 ret = BCME_NOTUP;
23804 goto exit;
23805 }
23806
23807 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23808 WL_ERR(("Not Hostapd mode\n"));
23809 ret = BCME_NOTAP;
23810 goto exit;
23811 }
23812
23813 ndev = wl_get_ap_netdev(cfg, ifname);
23814
23815 if (ndev == NULL) {
23816 WL_ERR(("No softAP interface named %s\n", ifname));
23817 ret = BCME_NOTAP;
23818 goto exit;
23819 }
23820
23821 if (cfg->ap_rps_info.enable != enable) {
23822 cfg->ap_rps_info.enable = enable;
23823 if (enable) {
23824 ret = _wl_update_ap_rps_params(ndev);
23825 if (ret) {
23826 WL_ERR(("Filed to update rpsnoa params\n"));
23827 goto exit;
23828 }
23829 }
23830 bzero(&iovar, sizeof(iovar));
23831 bzero(smbuf, sizeof(smbuf));
23832
23833 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
23834 iovar.hdr.subcmd = WL_RPSNOA_CMD_ENABLE;
23835 iovar.hdr.len = sizeof(iovar);
23836 iovar.data->band = WLC_BAND_ALL;
23837 iovar.data->value = (int16)enable;
23838
23839 ret = wldev_iovar_setbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
23840 smbuf, sizeof(smbuf), NULL);
23841 if (ret) {
23842 WL_ERR(("Failed to enable AP radio power save"));
23843 goto exit;
23844 }
23845 cfg->ap_rps_info.enable = enable;
23846 }
23847exit:
23848 return ret;
23849}
23850
23851int
23852wl_update_ap_rps_params(struct net_device *dev, ap_rps_info_t* rps, char *ifname)
23853{
23854 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23855 dhd_pub_t *dhdp;
23856 struct net_device *ndev = NULL;
23857
23858 dhdp = (dhd_pub_t *)(cfg->pub);
23859
23860 if (!dhdp)
23861 return BCME_NOTUP;
23862
23863 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23864 WL_ERR(("Not Hostapd mode\n"));
23865 return BCME_NOTAP;
23866 }
23867
23868 ndev = wl_get_ap_netdev(cfg, ifname);
23869
23870 if (ndev == NULL) {
23871 WL_ERR(("No softAP interface named %s\n", ifname));
23872 return BCME_NOTAP;
23873 }
23874
23875 if (!rps)
23876 return BCME_BADARG;
23877
23878 if (rps->pps < RADIO_PWRSAVE_PPS_MIN)
23879 return BCME_BADARG;
23880
23881 if (rps->level < RADIO_PWRSAVE_LEVEL_MIN ||
23882 rps->level > RADIO_PWRSAVE_LEVEL_MAX)
23883 return BCME_BADARG;
23884
23885 if (rps->quiet_time < RADIO_PWRSAVE_QUIETTIME_MIN)
23886 return BCME_BADARG;
23887
23888 if (rps->sta_assoc_check > RADIO_PWRSAVE_ASSOCCHECK_MAX ||
23889 rps->sta_assoc_check < RADIO_PWRSAVE_ASSOCCHECK_MIN)
23890 return BCME_BADARG;
23891
23892 cfg->ap_rps_info.pps = rps->pps;
23893 cfg->ap_rps_info.level = rps->level;
23894 cfg->ap_rps_info.quiet_time = rps->quiet_time;
23895 cfg->ap_rps_info.sta_assoc_check = rps->sta_assoc_check;
23896
23897 if (cfg->ap_rps_info.enable) {
23898 if (_wl_update_ap_rps_params(ndev)) {
23899 WL_ERR(("Failed to update rpsnoa params"));
23900 return BCME_ERROR;
23901 }
23902 }
23903
23904 return BCME_OK;
23905}
23906
23907void
23908wl_cfg80211_init_ap_rps(struct bcm_cfg80211 *cfg)
23909{
23910 cfg->ap_rps_info.enable = FALSE;
23911 cfg->ap_rps_info.sta_assoc_check = RADIO_PWRSAVE_STAS_ASSOC_CHECK;
23912 cfg->ap_rps_info.pps = RADIO_PWRSAVE_PPS;
23913 cfg->ap_rps_info.quiet_time = RADIO_PWRSAVE_QUIET_TIME;
23914 cfg->ap_rps_info.level = RADIO_PWRSAVE_LEVEL;
23915}
23916#endif /* SUPPORT_AP_RADIO_PWRSAVE */
23917
23918int
23919wl_cfg80211_iface_count(struct net_device *dev)
23920{
23921 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23922 struct net_info *iter, *next;
23923 int iface_count = 0;
23924
23925 /* Return the count of network interfaces (skip netless p2p discovery
23926 * interface)
23927 */
23928 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23929 for_each_ndev(cfg, iter, next) {
23930 GCC_DIAGNOSTIC_POP();
23931 if (iter->ndev) {
23932 iface_count++;
23933 }
23934 }
23935 return iface_count;
23936}
23937
23938#ifdef WBTEXT
23939static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
23940{
23941 wl_wbtext_bssid_t *bssid = NULL;
23942 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23943 /* check duplicate */
23944 list_for_each_entry(bssid, &cfg->wbtext_bssid_list, list) {
23945 GCC_DIAGNOSTIC_POP();
23946 if (!memcmp(bssid->ea.octet, ea, ETHER_ADDR_LEN)) {
23947 return FALSE;
23948 }
23949 }
23950
23951 return TRUE;
23952}
23953
23954static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
23955{
23956 wl_wbtext_bssid_t *bssid = NULL;
23957 char eabuf[ETHER_ADDR_STR_LEN];
23958
23959 bssid = (wl_wbtext_bssid_t *)MALLOC(cfg->osh, sizeof(wl_wbtext_bssid_t));
23960 if (bssid == NULL) {
23961 WL_ERR(("alloc failed\n"));
23962 return FALSE;
23963 }
23964
23965 memcpy(bssid->ea.octet, ea, ETHER_ADDR_LEN);
23966
23967 INIT_LIST_HEAD(&bssid->list);
23968 list_add_tail(&bssid->list, &cfg->wbtext_bssid_list);
23969
23970 WL_DBG(("add wbtext bssid : %s\n", bcm_ether_ntoa(ea, eabuf)));
23971
23972 return TRUE;
23973}
23974
23975static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg)
23976{
23977 wl_wbtext_bssid_t *bssid = NULL;
23978 char eabuf[ETHER_ADDR_STR_LEN];
23979
23980 while (!list_empty(&cfg->wbtext_bssid_list)) {
23981 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23982 bssid = list_entry(cfg->wbtext_bssid_list.next, wl_wbtext_bssid_t, list);
23983 GCC_DIAGNOSTIC_POP();
23984 if (bssid) {
23985 WL_DBG(("clear wbtext bssid : %s\n", bcm_ether_ntoa(&bssid->ea, eabuf)));
23986 list_del(&bssid->list);
23987 MFREE(cfg->osh, bssid, sizeof(wl_wbtext_bssid_t));
23988 }
23989 }
23990}
23991
23992static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev)
23993{
23994 struct wl_connect_info *conn_info = wl_to_conn(cfg);
23995 bcm_tlv_t * cap_ie = NULL;
23996 bool req_sent = FALSE;
23997 struct wl_profile *profile;
23998
23999 WL_DBG(("Enter\n"));
24000
24001 profile = wl_get_profile_by_netdev(cfg, dev);
24002 if (!profile) {
24003 WL_ERR(("no profile exists\n"));
24004 return;
24005 }
24006
24007 if (wl_cfg80211_wbtext_check_bssid_list(cfg,
24008 (struct ether_addr *)&profile->bssid) == FALSE) {
24009 WL_DBG(("already updated\n"));
24010 return;
24011 }
24012
24013 /* first, check NBR bit in RRM IE */
24014 if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24015 DOT11_MNG_RRM_CAP_ID)) != NULL) {
24016 if (isset(cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
24017 WL_DBG(("sending neighbor report\n"));
24018 req_sent = wl_cfg80211_wbtext_send_nbr_req(cfg, dev, profile);
24019 }
24020 }
24021
24022 /* if RRM nbr was not supported, check BTM bit in extend cap. IE */
24023 if (!req_sent) {
24024 if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24025 DOT11_MNG_EXT_CAP_ID)) != NULL) {
24026 if (cap_ie->len >= DOT11_EXTCAP_LEN_BSSTRANS &&
24027 isset(cap_ie->data, DOT11_EXT_CAP_BSSTRANS_MGMT)) {
24028 WL_DBG(("sending btm query\n"));
24029 wl_cfg80211_wbtext_send_btm_query(cfg, dev, profile);
24030 }
24031 }
24032 }
24033}
24034
24035static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
24036 struct wl_profile *profile)
24037{
24038 int error = -1;
24039 char *smbuf = NULL;
24040 struct wl_connect_info *conn_info = wl_to_conn(cfg);
24041 bcm_tlv_t * rrm_cap_ie = NULL;
24042 wlc_ssid_t *ssid = NULL;
24043 bool ret = FALSE;
24044
24045 WL_DBG(("Enter\n"));
24046
24047 /* check RRM nbr bit in extend cap. IE of assoc response */
24048 if ((rrm_cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24049 DOT11_MNG_RRM_CAP_ID)) != NULL) {
24050 if (!isset(rrm_cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
24051 WL_DBG(("AP doesn't support neighbor report\n"));
24052 return FALSE;
24053 }
24054 }
24055
24056 smbuf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
24057 if (smbuf == NULL) {
24058 WL_ERR(("failed to allocated memory\n"));
24059 goto nbr_req_out;
24060 }
24061
24062 ssid = (wlc_ssid_t *)MALLOCZ(cfg->osh, sizeof(wlc_ssid_t));
24063 if (ssid == NULL) {
24064 WL_ERR(("failed to allocated memory\n"));
24065 goto nbr_req_out;
24066 }
24067
24068 ssid->SSID_len = MIN(profile->ssid.SSID_len, DOT11_MAX_SSID_LEN);
24069 memcpy(ssid->SSID, profile->ssid.SSID, ssid->SSID_len);
24070
24071 error = wldev_iovar_setbuf(dev, "rrm_nbr_req", ssid,
24072 sizeof(wlc_ssid_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
24073 if (error == BCME_OK) {
24074 ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
24075 (struct ether_addr *)&profile->bssid);
24076 } else {
24077 WL_ERR(("failed to send neighbor report request, error=%d\n", error));
24078 }
24079
24080nbr_req_out:
24081 if (ssid) {
24082 MFREE(cfg->osh, ssid, sizeof(wlc_ssid_t));
24083 }
24084
24085 if (smbuf) {
24086 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
24087 }
24088 return ret;
24089}
24090
24091static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
24092 struct wl_profile *profile)
24093
24094{
24095 int error = -1;
24096 bool ret = FALSE;
24097 wl_bsstrans_query_t btq;
24098
24099 WL_DBG(("Enter\n"));
24100
24101 bzero(&btq, sizeof(wl_bsstrans_query_t));
24102
24103 btq.version = WL_BSSTRANS_QUERY_VERSION_1;
24104 error = wldev_iovar_setbuf(dev, "wnm_bsstrans_query", &btq,
24105 sizeof(btq), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
24106 if (error == BCME_OK) {
24107 ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
24108 (struct ether_addr *)&profile->bssid);
24109 } else {
24110 WL_ERR(("wl_cfg80211_wbtext_send_btm_query: failed to set BTM query,"
24111 " error=%d\n", error));
24112 }
24113 return ret;
24114}
24115
24116static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev)
24117{
24118 keepalives_max_idle_t keepalive = {0, 0, 0, 0};
24119 s32 bssidx, error;
24120 int wnm_maxidle = 0;
24121 struct wl_connect_info *conn_info = wl_to_conn(cfg);
24122
24123 /* AP supports wnm max idle ? */
24124 if (bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24125 DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID) != NULL) {
24126 error = wldev_iovar_getint(dev, "wnm_maxidle", &wnm_maxidle);
24127 if (error < 0) {
24128 WL_ERR(("failed to get wnm max idle period : %d\n", error));
24129 }
24130 }
24131
24132 WL_DBG(("wnm max idle period : %d\n", wnm_maxidle));
24133
24134 /* if wnm maxidle has valid period, set it as keep alive */
24135 if (wnm_maxidle > 0) {
24136 keepalive.keepalive_count = 1;
24137 }
24138
24139 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) >= 0) {
24140 error = wldev_iovar_setbuf_bsscfg(dev, "wnm_keepalives_max_idle", &keepalive,
24141 sizeof(keepalives_max_idle_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
24142 bssidx, &cfg->ioctl_buf_sync);
24143 if (error < 0) {
24144 if (error == BCME_BADARG) {
24145 WL_ERR(("set wnm_keepalive with invalid arguments\n"));
24146 } else {
24147 WL_ERR(("set wnm_keepalives_max_idle failed : %d\n", error));
24148 }
24149 }
24150 }
24151}
24152
24153static int
24154wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len)
24155{
24156 dot11_rm_action_t *rm_rep;
24157 bcm_tlv_t *tlvs;
24158 uint tlv_len;
24159 int i, error;
24160 dot11_neighbor_rep_ie_t *nbr_rep_ie;
24161 chanspec_t ch;
24162 wl_roam_channel_list_t channel_list;
24163 char iobuf[WLC_IOCTL_SMLEN];
24164
24165 if (body_len < DOT11_RM_ACTION_LEN) {
24166 WL_ERR(("Received Neighbor Report frame with incorrect length %d\n",
24167 body_len));
24168 return BCME_ERROR;
24169 }
24170
24171 rm_rep = (dot11_rm_action_t *)body;
24172 WL_DBG(("received neighbor report (token = %d)\n", rm_rep->token));
24173
24174 tlvs = (bcm_tlv_t *)&rm_rep->data[0];
24175
24176 tlv_len = body_len - DOT11_RM_ACTION_LEN;
24177
24178 while (tlvs && tlvs->id == DOT11_MNG_NEIGHBOR_REP_ID) {
24179 nbr_rep_ie = (dot11_neighbor_rep_ie_t *)tlvs;
24180
24181 if (nbr_rep_ie->len < DOT11_NEIGHBOR_REP_IE_FIXED_LEN) {
24182 WL_ERR(("malformed Neighbor Report element with length %d\n",
24183 nbr_rep_ie->len));
24184 tlvs = bcm_next_tlv(tlvs, &tlv_len);
24185 continue;
24186 }
24187
24188 ch = CH20MHZ_CHSPEC(nbr_rep_ie->channel);
24189 WL_DBG(("ch:%d, bssid:"MACDBG"\n",
24190 ch, MAC2STRDBG(nbr_rep_ie->bssid.octet)));
24191
24192 /* get RCC list */
24193 error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0,
24194 (void *)&channel_list, sizeof(channel_list), NULL);
24195 if (error) {
24196 WL_ERR(("Failed to get roamscan channels, error = %d\n", error));
24197 return BCME_ERROR;
24198 }
24199
24200 /* update RCC */
24201 if (channel_list.n < MAX_ROAM_CHANNEL) {
24202 for (i = 0; i < channel_list.n; i++) {
24203 if (channel_list.channels[i] == ch) {
24204 break;
24205 }
24206 }
24207 if (i == channel_list.n) {
24208 channel_list.channels[channel_list.n] = ch;
24209 channel_list.n++;
24210 }
24211 }
24212
24213 /* set RCC list */
24214 error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list,
24215 sizeof(channel_list), iobuf, sizeof(iobuf), NULL);
24216 if (error) {
24217 WL_DBG(("Failed to set roamscan channels, error = %d\n", error));
24218 }
24219
24220 tlvs = bcm_next_tlv(tlvs, &tlv_len);
24221 }
24222
24223 return BCME_OK;
24224}
24225#endif /* WBTEXT */
24226#ifdef SUPPORT_SET_CAC
24227static void
24228wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable)
24229{
24230 int ret = 0;
24231 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
24232
24233 WL_DBG(("cac enable %d\n", enable));
24234 if (!dhd) {
24235 WL_ERR(("dhd is NULL\n"));
24236 return;
24237 }
24238 if ((ret = dhd_wl_ioctl_set_intiovar(dhd, "cac", enable,
24239 WLC_SET_VAR, TRUE, 0)) < 0) {
24240 WL_ERR(("Failed set CAC, ret=%d\n", ret));
24241 } else {
24242 WL_DBG(("CAC set successfully\n"));
24243 }
24244 return;
24245}
24246#endif /* SUPPORT_SET_CAC */
24247
24248#ifdef SUPPORT_RSSI_SUM_REPORT
24249int
24250wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void *param)
24251{
24252 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24253 wl_rssi_ant_mimo_t *get_param = (wl_rssi_ant_mimo_t *)param;
24254 rssi_ant_param_t *set_param = NULL;
24255 struct net_device *ifdev = NULL;
24256 char iobuf[WLC_IOCTL_SMLEN];
24257 int err = BCME_OK;
24258 int iftype = 0;
24259
24260 bzero(iobuf, WLC_IOCTL_SMLEN);
24261
24262 /* Check the interface type */
24263 ifdev = wl_get_netdev_by_name(cfg, ifname);
24264 if (ifdev == NULL) {
24265 WL_ERR(("Could not find net_device for ifname:%s\n", ifname));
24266 err = BCME_BADARG;
24267 goto fail;
24268 }
24269
24270 iftype = ifdev->ieee80211_ptr->iftype;
24271 if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO) {
24272 if (peer_mac) {
24273 set_param = (rssi_ant_param_t *)MALLOCZ(cfg->osh, sizeof(rssi_ant_param_t));
24274 err = wl_cfg80211_ether_atoe(peer_mac, &set_param->ea);
24275 if (!err) {
24276 WL_ERR(("Invalid Peer MAC format\n"));
24277 err = BCME_BADARG;
24278 goto fail;
24279 }
24280 } else {
24281 WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype));
24282 err = BCME_BADARG;
24283 goto fail;
24284 }
24285 }
24286
24287 err = wldev_iovar_getbuf(ifdev, "phy_rssi_ant", peer_mac ?
24288 (void *)&(set_param->ea) : NULL, peer_mac ? ETHER_ADDR_LEN : 0,
24289 (void *)iobuf, sizeof(iobuf), NULL);
24290 if (unlikely(err)) {
24291 WL_ERR(("Failed to get rssi info, err=%d\n", err));
24292 } else {
24293 memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t));
24294 if (get_param->count == 0) {
24295 WL_ERR(("Not supported on this chip\n"));
24296 err = BCME_UNSUPPORTED;
24297 }
24298 }
24299
24300fail:
24301 if (set_param) {
24302 MFREE(cfg->osh, set_param, sizeof(rssi_ant_param_t));
24303 }
24304
24305 return err;
24306}
24307
24308int
24309wl_get_rssi_logging(struct net_device *dev, void *param)
24310{
24311 rssilog_get_param_t *get_param = (rssilog_get_param_t *)param;
24312 char iobuf[WLC_IOCTL_SMLEN];
24313 int err = BCME_OK;
24314
24315 bzero(iobuf, WLC_IOCTL_SMLEN);
24316 bzero(get_param, sizeof(*get_param));
24317 err = wldev_iovar_getbuf(dev, "rssilog", NULL, 0, (void *)iobuf,
24318 sizeof(iobuf), NULL);
24319 if (err) {
24320 WL_ERR(("Failed to get rssi logging info, err=%d\n", err));
24321 } else {
24322 memcpy(get_param, iobuf, sizeof(*get_param));
24323 }
24324
24325 return err;
24326}
24327
24328int
24329wl_set_rssi_logging(struct net_device *dev, void *param)
24330{
24331 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24332 rssilog_set_param_t *set_param = (rssilog_set_param_t *)param;
24333 int err;
24334
24335 err = wldev_iovar_setbuf(dev, "rssilog", set_param,
24336 sizeof(*set_param), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
24337 &cfg->ioctl_buf_sync);
24338 if (err) {
24339 WL_ERR(("Failed to set rssi logging param, err=%d\n", err));
24340 }
24341
24342 return err;
24343}
24344#endif /* SUPPORT_RSSI_SUM_REPORT */
24345/* Function to flush the FW preserve buffer content
24346* The buffer content is sent to host in form of events.
24347*/
24348void
24349wl_flush_fw_log_buffer(struct net_device *dev, uint32 logset_mask)
24350{
24351 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24352 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
24353 int i;
24354 int err = 0;
24355 u8 buf[WLC_IOCTL_SMLEN] = {0};
24356 wl_el_set_params_t set_param;
24357
24358 /* Set the size of data to retrieve */
24359 memset(&set_param, 0, sizeof(set_param));
24360 set_param.size = WLC_IOCTL_SMLEN;
24361
24362 for (i = 0; i < dhd->event_log_max_sets; i++)
24363 {
24364 if ((0x01u << i) & logset_mask) {
24365 set_param.set = i;
24366 err = wldev_iovar_setbuf(dev, "event_log_get", &set_param,
24367 sizeof(struct wl_el_set_params_s), buf, WLC_IOCTL_SMLEN,
24368 NULL);
24369 if (err) {
24370 WL_DBG(("Failed to get fw preserve logs, err=%d\n", err));
24371 }
24372 }
24373 }
24374}
24375#ifdef USE_WFA_CERT_CONF
24376extern int g_frameburst;
24377#endif /* USE_WFA_CERT_CONF */
24378
24379int
24380wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable)
24381{
24382 int ret = BCME_OK;
24383 int val = enable ? 1 : 0;
24384
24385#ifdef USE_WFA_CERT_CONF
24386 if (!g_frameburst) {
24387 WL_DBG(("Skip setting frameburst\n"));
24388 return 0;
24389 }
24390#endif /* USE_WFA_CERT_CONF */
24391
24392 WL_DBG(("Set frameburst %d\n", val));
24393 ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg), WLC_SET_FAKEFRAG, &val, sizeof(val));
24394 if (ret < 0) {
24395 WL_ERR(("Failed set frameburst, ret=%d\n", ret));
24396 } else {
24397 WL_INFORM_MEM(("frameburst is %s\n", enable ? "enabled" : "disabled"));
24398 }
24399
24400 return ret;
24401}
24402
24403s32
24404wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level)
24405{
24406 /* configure verbose level for debugging */
24407 if (level) {
24408 /* Enable increased verbose */
24409 wl_dbg_level |= WL_DBG_DBG;
24410 } else {
24411 /* Disable */
24412 wl_dbg_level &= ~WL_DBG_DBG;
24413 }
24414 WL_INFORM(("debug verbose set to %d\n", level));
24415
24416 return BCME_OK;
24417}
24418
24419const u8 *
24420wl_find_attribute(const u8 *buf, u16 len, u16 element_id)
24421{
24422 const u8 *attrib;
24423 u16 attrib_id;
24424 u16 attrib_len;
24425
24426 if (!buf) {
24427 WL_ERR(("buf null\n"));
24428 return NULL;
24429 }
24430
24431 attrib = buf;
24432 while (len >= 4) {
24433 /* attribute id */
24434 attrib_id = *attrib++ << 8;
24435 attrib_id |= *attrib++;
24436 len -= 2;
24437
24438 /* 2-byte little endian */
24439 attrib_len = *attrib++ << 8;
24440 attrib_len |= *attrib++;
24441
24442 len -= 2;
24443 if (attrib_id == element_id) {
24444 /* This will point to start of subelement attrib after
24445 * attribute id & len
24446 */
24447 return attrib;
24448 }
24449 if (len > attrib_len) {
24450 len -= attrib_len; /* for the remaining subelt fields */
24451 WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n",
24452 attrib_id, attrib_len, len));
24453
24454 /* Go to next subelement */
24455 attrib += attrib_len;
24456 } else {
24457 WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n",
24458 attrib_id, attrib_len));
24459 return NULL;
24460 }
24461 }
24462 return NULL;
24463}
24464
24465uint8 wl_cfg80211_get_bus_state(struct bcm_cfg80211 *cfg)
24466{
24467 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
24468 WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
24469 dhd->hang_was_sent, dhd->busstate));
24470 return ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent);
24471}
24472
24473#ifdef WL_WPS_SYNC
24474static void wl_wps_reauth_timeout(unsigned long data)
24475{
24476 struct net_device *ndev = (struct net_device *)data;
24477 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24478 s32 inst;
24479 unsigned long flags;
24480
24481 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24482 inst = wl_get_wps_inst_match(cfg, ndev);
24483 if (inst >= 0) {
24484 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n",
24485 ndev->name, inst, cfg->wps_session[inst].state));
24486 if (cfg->wps_session[inst].state == WPS_STATE_REAUTH_WAIT) {
24487 /* Session should get deleted from success (linkup) or
24488 * deauth case. Just in case, link reassoc failed, clear
24489 * state here.
24490 */
24491 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n",
24492 ndev->name, inst));
24493 cfg->wps_session[inst].state = WPS_STATE_IDLE;
24494 cfg->wps_session[inst].in_use = false;
24495 }
24496 }
24497 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24498}
24499
24500static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg)
24501{
24502 /* Only two instances are supported as of now. one for
24503 * infra STA and other for infra STA/GC.
24504 */
24505 int i = 0;
24506 struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
24507
24508 spin_lock_init(&cfg->wps_sync);
24509 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
24510 /* Init scan_timeout timer */
24511 init_timer_compat(&cfg->wps_session[i].timer, wl_wps_reauth_timeout, pdev);
24512 cfg->wps_session[i].in_use = false;
24513 cfg->wps_session[i].state = WPS_STATE_IDLE;
24514 }
24515}
24516
24517static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg)
24518{
24519 int i = 0;
24520
24521 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
24522 cfg->wps_session[i].in_use = false;
24523 cfg->wps_session[i].state = WPS_STATE_IDLE;
24524 if (timer_pending(&cfg->wps_session[i].timer)) {
24525 del_timer_sync(&cfg->wps_session[i].timer);
24526 }
24527 }
24528
24529}
24530
24531static s32
24532wl_get_free_wps_inst(struct bcm_cfg80211 *cfg)
24533{
24534 int i;
24535
24536 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
24537 if (!cfg->wps_session[i].in_use) {
24538 return i;
24539 }
24540 }
24541 return BCME_ERROR;
24542}
24543
24544static s32
24545wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev)
24546{
24547 int i;
24548
24549 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
24550 if ((cfg->wps_session[i].in_use) &&
24551 (ndev == cfg->wps_session[i].ndev)) {
24552 return i;
24553 }
24554 }
24555
24556 return BCME_ERROR;
24557}
24558
24559static s32
24560wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *mac_addr)
24561{
24562 s32 inst;
24563 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24564 unsigned long flags;
24565
24566 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24567 /* Fetch and initialize a wps instance */
24568 inst = wl_get_free_wps_inst(cfg);
24569 if (inst == BCME_ERROR) {
24570 WL_ERR(("[WPS] No free insance\n"));
24571 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24572 return BCME_ERROR;
24573 }
24574 cfg->wps_session[inst].in_use = true;
24575 cfg->wps_session[inst].state = WPS_STATE_STARTED;
24576 cfg->wps_session[inst].ndev = ndev;
24577 cfg->wps_session[inst].mode = mode;
24578 /* return check not required since both buffer lens are same */
24579 (void)memcpy_s(cfg->wps_session[inst].peer_mac, ETH_ALEN, mac_addr, ETH_ALEN);
24580 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24581
24582 WL_INFORM_MEM(("[%s][WPS] session created. Peer: " MACDBG "\n",
24583 ndev->name, MAC2STRDBG(mac_addr)));
24584 return BCME_OK;
24585}
24586
24587static void
24588wl_wps_session_del(struct net_device *ndev)
24589{
24590 s32 inst;
24591 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24592 unsigned long flags;
24593 u16 cur_state;
24594
24595 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24596
24597 /* Get current instance for the given ndev */
24598 inst = wl_get_wps_inst_match(cfg, ndev);
24599 if (inst == BCME_ERROR) {
24600 WL_DBG(("[WPS] instance match NOT found\n"));
24601 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24602 return;
24603 }
24604
24605 cur_state = cfg->wps_session[inst].state;
24606 if (cur_state != WPS_STATE_DONE) {
24607 WL_DBG(("[WPS] wrong state:%d\n", cur_state));
24608 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24609 return;
24610 }
24611
24612 /* Mark this as unused */
24613 cfg->wps_session[inst].in_use = false;
24614 cfg->wps_session[inst].state = WPS_STATE_IDLE;
24615 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24616
24617 /* Ensure this API is called from sleepable context. */
24618 if (timer_pending(&cfg->wps_session[inst].timer)) {
24619 del_timer_sync(&cfg->wps_session[inst].timer);
24620 }
24621
24622 WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev->name));
24623}
24624
24625static void
24626wl_wps_handle_ifdel(struct net_device *ndev)
24627{
24628 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24629 unsigned long flags;
24630 u16 cur_state;
24631 s32 inst;
24632
24633 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24634 inst = wl_get_wps_inst_match(cfg, ndev);
24635 if (inst == BCME_ERROR) {
24636 WL_DBG(("[WPS] instance match NOT found\n"));
24637 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24638 return;
24639 }
24640 cur_state = cfg->wps_session[inst].state;
24641 cfg->wps_session[inst].state = WPS_STATE_DONE;
24642 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24643
24644 WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev->name, cur_state));
24645 if (cur_state > WPS_STATE_IDLE) {
24646 wl_wps_session_del(ndev);
24647 }
24648}
24649
24650static s32
24651wl_wps_handle_sta_linkdown(struct net_device *ndev, u16 inst)
24652{
24653 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24654 unsigned long flags;
24655 u16 cur_state;
24656 bool wps_done = false;
24657
24658 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24659 cur_state = cfg->wps_session[inst].state;
24660 if (cur_state == WPS_STATE_REAUTH_WAIT) {
24661 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24662 wl_clr_drv_status(cfg, CONNECTED, ndev);
24663 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
24664 WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev->name));
24665 /* Drop the link down event while we are waiting for reauth */
24666 return BCME_UNSUPPORTED;
24667 } else if (cur_state == WPS_STATE_STARTED) {
24668 /* Link down before reaching EAP-FAIL. End WPS session */
24669 cfg->wps_session[inst].state = WPS_STATE_DONE;
24670 wps_done = true;
24671 WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev->name));
24672 } else {
24673 WL_DBG(("[%s][WPS] link down in state:%d\n",
24674 ndev->name, cur_state));
24675 }
24676
24677 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24678
24679 if (wps_done) {
24680 wl_wps_session_del(ndev);
24681 }
24682 return BCME_OK;
24683}
24684
24685static s32
24686wl_wps_handle_peersta_linkdown(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24687{
24688 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24689 unsigned long flags;
24690 u16 cur_state;
24691 s32 ret = BCME_OK;
24692 bool wps_done = false;
24693
24694 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24695 cur_state = cfg->wps_session[inst].state;
24696
24697 if (!peer_mac) {
24698 WL_ERR(("Invalid arg\n"));
24699 ret = BCME_ERROR;
24700 goto exit;
24701 }
24702
24703 /* AP/GO can have multiple clients. so validate peer_mac addr
24704 * and ensure states are updated only for right peer.
24705 */
24706 if (memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
24707 /* Mac addr not matching. Ignore. */
24708 WL_DBG(("[%s][WPS] No active WPS session"
24709 "for the peer:" MACDBG "\n", ndev->name, MAC2STRDBG(peer_mac)));
24710 ret = BCME_OK;
24711 goto exit;
24712 }
24713 if (cur_state == WPS_STATE_REAUTH_WAIT) {
24714 WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
24715 " Peer: " MACDBG "\n",
24716 ndev->name, MAC2STRDBG(peer_mac)));
24717#ifdef NOT_YET
24718 /* Link down during REAUTH state is expected. However,
24719 * if this is send up, hostapd statemachine issues a
24720 * deauth down and that may pre-empt WPS reauth state
24721 * at GC.
24722 */
24723 WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore."
24724 " for client:" MACDBG "\n",
24725 ndev->name, MAC2STRDBG(peer_mac)));
24726 ret = BCME_UNSUPPORTED;
24727#endif
24728 } else if (cur_state == WPS_STATE_STARTED) {
24729 /* Link down before reaching REAUTH_WAIT state. WPS
24730 * session ended.
24731 */
24732 cfg->wps_session[inst].state = WPS_STATE_DONE;
24733 WL_INFORM_MEM(("[%s][WPS] link down after wps start"
24734 " client:" MACDBG "\n",
24735 ndev->name, MAC2STRDBG(peer_mac)));
24736 wps_done = true;
24737 /* since we have freed lock above, return from here */
24738 ret = BCME_OK;
24739 } else {
24740 WL_ERR(("[%s][WPS] Unsupported state:%d",
24741 ndev->name, cur_state));
24742 ret = BCME_ERROR;
24743 }
24744exit:
24745 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24746 if (wps_done) {
24747 wl_wps_session_del(ndev);
24748 }
24749 return ret;
24750}
24751
24752static s32
24753wl_wps_handle_sta_linkup(struct net_device *ndev, u16 inst)
24754{
24755 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24756 unsigned long flags;
24757 u16 cur_state;
24758 s32 ret = BCME_OK;
24759 bool wps_done = false;
24760
24761 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24762 cur_state = cfg->wps_session[inst].state;
24763 if (cur_state == WPS_STATE_REAUTH_WAIT) {
24764 /* WPS session succeeded. del session. */
24765 cfg->wps_session[inst].state = WPS_STATE_DONE;
24766 wps_done = true;
24767 WL_INFORM_MEM(("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev->name));
24768 ret = BCME_OK;
24769 } else {
24770 WL_ERR(("[%s][WPS] unexpected link up in state:%d \n",
24771 ndev->name, cur_state));
24772 ret = BCME_ERROR;
24773 }
24774 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24775 if (wps_done) {
24776 wl_wps_session_del(ndev);
24777 }
24778 return ret;
24779}
24780
24781static s32
24782wl_wps_handle_peersta_linkup(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24783{
24784 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24785 unsigned long flags;
24786 u16 cur_state;
24787 s32 ret = BCME_OK;
24788
24789 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24790 cur_state = cfg->wps_session[inst].state;
24791
24792 /* For AP case, check whether call came for right peer */
24793 if (!peer_mac ||
24794 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
24795 WL_ERR(("[WPS] macaddr mismatch\n"));
24796 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24797 /* Mac addr not matching. Ignore. */
24798 return BCME_ERROR;
24799 }
24800
24801 if (cur_state == WPS_STATE_REAUTH_WAIT) {
24802 WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev->name));
24803 ret = BCME_OK;
24804 } else {
24805 WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
24806 ndev->name, cur_state));
24807 ret = BCME_ERROR;
24808 }
24809
24810 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24811
24812 return ret;
24813}
24814
24815static s32
24816wl_wps_handle_authorize(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24817{
24818 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24819 unsigned long flags;
24820 u16 cur_state;
24821 bool wps_done = false;
24822 s32 ret = BCME_OK;
24823
24824 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24825 cur_state = cfg->wps_session[inst].state;
24826
24827 /* For AP case, check whether call came for right peer */
24828 if (!peer_mac ||
24829 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
24830 WL_ERR(("[WPS] macaddr mismatch\n"));
24831 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24832 /* Mac addr not matching. Ignore. */
24833 return BCME_ERROR;
24834 }
24835
24836 if (cur_state == WPS_STATE_REAUTH_WAIT) {
24837 /* WPS session succeeded. del session. */
24838 cfg->wps_session[inst].state = WPS_STATE_DONE;
24839 wps_done = true;
24840 WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev->name));
24841 ret = BCME_OK;
24842 } else {
24843 WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
24844 ndev->name, cur_state));
24845 ret = BCME_ERROR;
24846 }
24847
24848 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24849 if (wps_done) {
24850 wl_wps_session_del(ndev);
24851 }
24852 return ret;
24853}
24854
24855static s32
24856wl_wps_handle_reauth(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24857{
24858 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24859 unsigned long flags;
24860 u16 cur_state;
24861 u16 mode;
24862 s32 ret = BCME_OK;
24863
24864 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24865 cur_state = cfg->wps_session[inst].state;
24866 mode = cfg->wps_session[inst].mode;
24867
24868 if (((mode == WL_MODE_BSS) && (cur_state == WPS_STATE_STARTED)) ||
24869 ((mode == WL_MODE_AP) && (cur_state == WPS_STATE_M8_SENT))) {
24870 /* Move to reauth wait */
24871 cfg->wps_session[inst].state = WPS_STATE_REAUTH_WAIT;
24872 /* Use ndev to find the wps instance which fired the timer */
24873 timer_set_private(&cfg->wps_session[inst].timer, ndev);
24874 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24875 mod_timer(&cfg->wps_session[inst].timer,
24876 jiffies + msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT));
24877 WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG "\n",
24878 ndev->name, mode, MAC2STRDBG(peer_mac)));
24879 return BCME_OK;
24880 } else {
24881 /* 802.1x cases */
24882 WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev->name));
24883 }
24884 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24885 return ret;
24886}
24887
24888static s32
24889wl_wps_handle_disconnect(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24890{
24891 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24892 unsigned long flags;
24893 u16 cur_state;
24894 s32 ret = BCME_OK;
24895
24896 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24897 cur_state = cfg->wps_session[inst].state;
24898 /* If Disconnect command comes from user space for STA/GC,
24899 * respond with event without waiting for event from fw as
24900 * it would be dropped by the WPS_SYNC code.
24901 */
24902 if (cur_state == WPS_STATE_REAUTH_WAIT) {
24903 if (ETHER_ISBCAST(peer_mac)) {
24904 WL_DBG(("[WPS] Bcast peer. Do nothing.\n"));
24905 } else {
24906 /* Notify link down */
24907 CFG80211_DISCONNECTED(ndev,
24908 WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
24909 true, GFP_ATOMIC);
24910 }
24911 } else {
24912 WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
24913 ndev->name, cur_state));
24914 ret = BCME_UNSUPPORTED;
24915 }
24916 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24917 return ret;
24918}
24919
24920static s32
24921wl_wps_handle_disconnect_client(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24922{
24923 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24924 unsigned long flags;
24925 u16 cur_state;
24926 s32 ret = BCME_OK;
24927 bool wps_done = false;
24928
24929 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24930 cur_state = cfg->wps_session[inst].state;
24931 /* For GO/AP, ignore disconnect client during reauth state */
24932 if (cur_state == WPS_STATE_REAUTH_WAIT) {
24933 if (ETHER_ISBCAST(peer_mac)) {
24934 /* If there is broadcast deauth, then mark wps session as ended */
24935 cfg->wps_session[inst].state = WPS_STATE_DONE;
24936 wps_done = true;
24937 WL_INFORM_MEM(("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev->name));
24938 ret = BCME_OK;
24939 goto exit;
24940 } else if (!(memcmp(cfg->wps_session[inst].peer_mac,
24941 peer_mac, ETH_ALEN))) {
24942 WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev->name));
24943 ret = BCME_UNSUPPORTED;
24944 }
24945 }
24946
24947exit:
24948 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24949 if (wps_done) {
24950 wl_wps_session_del(ndev);
24951 }
24952 return ret;
24953}
24954
24955static s32
24956wl_wps_handle_connect_fail(struct net_device *ndev, u16 inst)
24957{
24958 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24959 unsigned long flags;
24960 u16 cur_state;
24961 bool wps_done = false;
24962
24963 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24964 cur_state = cfg->wps_session[inst].state;
24965 if (cur_state == WPS_STATE_REAUTH_WAIT) {
24966 cfg->wps_session[inst].state = WPS_STATE_DONE;
24967 wps_done = true;
24968 WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n",
24969 ndev->name));
24970 } else {
24971 WL_ERR(("[%s][WPS] Connect fail. state:%d\n",
24972 ndev->name, cur_state));
24973 }
24974 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24975 if (wps_done) {
24976 wl_wps_session_del(ndev);
24977 }
24978 return BCME_OK;
24979}
24980
24981static s32
24982wl_wps_handle_m8_sent(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24983{
24984 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24985 unsigned long flags;
24986 u16 cur_state;
24987 s32 ret = BCME_OK;
24988
24989 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24990 cur_state = cfg->wps_session[inst].state;
24991
24992 if (cur_state == WPS_STATE_STARTED) {
24993 /* Move to M8 sent state */
24994 cfg->wps_session[inst].state = WPS_STATE_M8_SENT;
24995 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24996 return BCME_OK;
24997 } else {
24998 /* 802.1x cases */
24999 WL_DBG(("[%s][WPS] Not valid state to send M8\n", ndev->name));
25000 }
25001 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
25002 return ret;
25003}
25004
25005static s32
25006wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac)
25007{
25008 s32 inst;
25009 u16 mode;
25010 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25011 s32 ret = BCME_ERROR;
25012 unsigned long flags;
25013
25014 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
25015 /* Get current instance for the given ndev */
25016 inst = wl_get_wps_inst_match(cfg, ndev);
25017 if (inst == BCME_ERROR) {
25018 /* No active WPS session. Do Nothing. */
25019 WL_DBG(("[%s][WPS] No matching instance.\n", ndev->name));
25020 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
25021 return BCME_NOTFOUND;
25022 }
25023 mode = cfg->wps_session[inst].mode;
25024 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
25025
25026 WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG "\n",
25027 ndev->name, state, mode, MAC2STRDBG(peer_mac)));
25028
25029 switch (state) {
25030 case WPS_STATE_M8_RECVD:
25031 {
25032 /* Occasionally, due to race condition between ctrl
25033 * and data path, deauth ind is recvd before EAP-FAIL.
25034 * Ignore deauth ind before EAP-FAIL
25035 * So move to REAUTH WAIT on receiving M8 on GC and
25036 * ignore deauth ind before EAP-FAIL till 'x' timeout.
25037 * Kickoff a timer to monitor reauth status.
25038 */
25039 if (mode == WL_MODE_BSS) {
25040 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
25041 } else {
25042 /* Nothing to be done for AP/GO mode */
25043 ret = BCME_OK;
25044 }
25045 break;
25046 }
25047 case WPS_STATE_M8_SENT:
25048 {
25049 /* Mantain the M8 sent state to verify
25050 * EAP-FAIL sent is valid
25051 */
25052 if (mode == WL_MODE_AP) {
25053 ret = wl_wps_handle_m8_sent(ndev, inst, peer_mac);
25054 } else {
25055 /* Nothing to be done for STA/GC mode */
25056 ret = BCME_OK;
25057 }
25058 break;
25059 }
25060 case WPS_STATE_EAP_FAIL:
25061 {
25062 /* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
25063 * Kickoff a timer to monitor reauth status
25064 */
25065 if (mode == WL_MODE_AP) {
25066 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
25067 } else {
25068 /* Nothing to be done for STA/GC mode */
25069 ret = BCME_OK;
25070 }
25071 break;
25072 }
25073 case WPS_STATE_LINKDOWN:
25074 {
25075 if (mode == WL_MODE_BSS) {
25076 ret = wl_wps_handle_sta_linkdown(ndev, inst);
25077 } else if (mode == WL_MODE_AP) {
25078 /* Take action only for matching peer mac */
25079 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25080 ret = wl_wps_handle_peersta_linkdown(ndev, inst, peer_mac);
25081 }
25082 }
25083 break;
25084 }
25085 case WPS_STATE_LINKUP:
25086 {
25087 if (mode == WL_MODE_BSS) {
25088 wl_wps_handle_sta_linkup(ndev, inst);
25089 } else if (mode == WL_MODE_AP) {
25090 /* Take action only for matching peer mac */
25091 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25092 wl_wps_handle_peersta_linkup(ndev, inst, peer_mac);
25093 }
25094 }
25095 break;
25096 }
25097 case WPS_STATE_DISCONNECT_CLIENT:
25098 {
25099 /* Disconnect STA/GC command from user space */
25100 if (mode == WL_MODE_AP) {
25101 ret = wl_wps_handle_disconnect_client(ndev, inst, peer_mac);
25102 } else {
25103 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
25104 }
25105 break;
25106 }
25107 case WPS_STATE_DISCONNECT:
25108 {
25109 /* Disconnect command on STA/GC interface */
25110 if (mode == WL_MODE_BSS) {
25111 ret = wl_wps_handle_disconnect(ndev, inst, peer_mac);
25112 }
25113 break;
25114 }
25115 case WPS_STATE_CONNECT_FAIL:
25116 {
25117 if (mode == WL_MODE_BSS) {
25118 ret = wl_wps_handle_connect_fail(ndev, inst);
25119 } else {
25120 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
25121 }
25122 break;
25123 }
25124 case WPS_STATE_AUTHORIZE:
25125 {
25126 if (mode == WL_MODE_AP) {
25127 /* Take action only for matching peer mac */
25128 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25129 wl_wps_handle_authorize(ndev, inst, peer_mac);
25130 } else {
25131 WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
25132 }
25133 }
25134 break;
25135 }
25136
25137 default:
25138 WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state, mode));
25139 ret = BCME_ERROR;
25140 }
25141
25142 return ret;
25143}
25144
25145#define EAP_EXP_ATTRIB_DATA_OFFSET 14
25146void
25147wl_handle_wps_states(struct net_device *ndev, u8 *pkt, u16 len, bool direction)
25148{
25149 eapol_header_t *eapol_hdr;
25150 bool tx_packet = direction;
25151 u16 eapol_type;
25152 u16 mode;
25153 u8 *peer_mac;
25154
25155 if (!ndev || !pkt) {
25156 WL_ERR(("[WPS] Invalid arg\n"));
25157 return;
25158 }
25159
25160 if (len < (ETHER_HDR_LEN + EAPOL_HDR_LEN)) {
25161 WL_ERR(("[WPS] Invalid len\n"));
25162 return;
25163 }
25164
25165 eapol_hdr = (eapol_header_t *)pkt;
25166 eapol_type = eapol_hdr->type;
25167
25168 peer_mac = tx_packet ? eapol_hdr->eth.ether_dhost :
25169 eapol_hdr->eth.ether_shost;
25170 /*
25171 * The implementation assumes only one WPS session would be active
25172 * per interface at a time. Even for hostap, the wps_pin session
25173 * is limited to one enrollee/client at a time. A session is marked
25174 * started on WSC_START and gets cleared from below contexts
25175 * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
25176 * b) Link up following EAP-FAIL. (success case)
25177 * c) Link up timeout after EAP-FAIL. (Fail case)
25178 */
25179
25180 if (eapol_type == EAP_PACKET) {
25181 wl_eap_header_t *eap;
25182
25183 if (len > sizeof(*eap)) {
25184 eap = (wl_eap_header_t *)(pkt + ETHER_HDR_LEN + EAPOL_HDR_LEN);
25185 if (eap->type == EAP_EXPANDED_TYPE) {
25186 wl_eap_exp_t *exp = (wl_eap_exp_t *)eap->data;
25187 if (eap->length > EAP_EXP_HDR_MIN_LENGTH) {
25188 /* opcode is at fixed offset */
25189 u8 opcode = exp->opcode;
25190 u16 eap_len = ntoh16(eap->length);
25191
25192 WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
25193 ndev->name, opcode, eap_len));
25194 if (opcode == EAP_WSC_MSG) {
25195 const u8 *msg;
25196 const u8* parse_buf = exp->data;
25197 /* Check if recvd pkt is fragmented */
25198 if ((!tx_packet) &&
25199 (exp->flags &
25200 EAP_EXP_FLAGS_FRAGMENTED_DATA)) {
25201 if ((eap_len - EAP_EXP_ATTRIB_DATA_OFFSET)
25202 > 2) {
25203 parse_buf +=
25204 EAP_EXP_FRAGMENT_LEN_OFFSET;
25205 eap_len -=
25206 EAP_EXP_FRAGMENT_LEN_OFFSET;
25207 WL_DBG(("Rcvd EAP"
25208 " fragmented pkt\n"));
25209 } else {
25210 /* If recvd pkt is fragmented
25211 * and does not have
25212 * length field drop the packet.
25213 */
25214 return;
25215 }
25216 }
25217
25218 msg = wl_find_attribute(parse_buf,
25219 (eap_len - EAP_EXP_ATTRIB_DATA_OFFSET),
25220 EAP_ATTRIB_MSGTYPE);
25221 if (unlikely(!msg)) {
25222 WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
25223 } else if ((*msg == EAP_WSC_MSG_M8) &&
25224 !tx_packet) {
25225 /* In certain cases M2 can also carry
25226 * credential. So add check for
25227 * cred in M8/M2 and start reauth timer.
25228 */
25229 WL_INFORM_MEM(("[%s][WPS] M8\n",
25230 ndev->name));
25231 wl_wps_session_update(ndev,
25232 WPS_STATE_M8_RECVD, peer_mac);
25233 } else if ((*msg == EAP_WSC_MSG_M8) &&
25234 tx_packet) {
25235 WL_INFORM_MEM(("[%s][WPS] M8 Sent\n",
25236 ndev->name));
25237 wl_wps_session_update(ndev,
25238 WPS_STATE_M8_SENT, peer_mac);
25239 } else {
25240 WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n",
25241 ndev->name, *msg));
25242 }
25243 } else if (opcode == EAP_WSC_START) {
25244 /* WSC session started. WSC_START - Tx from GO/AP.
25245 * Session will be deleted on successful link up or
25246 * on failure (deauth context)
25247 */
25248 mode = tx_packet ? WL_MODE_AP : WL_MODE_BSS;
25249 wl_wps_session_add(ndev, mode, peer_mac);
25250 WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
25251 ndev->name, mode));
25252 } else if (opcode == EAP_WSC_DONE) {
25253 /* WSC session done. TX on STA/GC. RX on GO/AP
25254 * On devices where config file save fails, it may
25255 * return WPS_NAK with config_error:0. But the
25256 * connection would still proceed. Hence don't let
25257 * state machine depend on WSC DONE.
25258 */
25259 WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev->name));
25260 }
25261 }
25262 }
25263
25264 if (eap->code == EAP_CODE_FAILURE) {
25265 /* EAP_FAIL */
25266 WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev->name));
25267 wl_wps_session_update(ndev,
25268 WPS_STATE_EAP_FAIL, peer_mac);
25269 }
25270 }
25271 }
25272}
25273#endif /* WL_WPS_SYNC */
25274
25275s32
25276wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25277 const wl_event_msg_t *event, void *data)
25278{
25279 int err = BCME_OK;
25280 u32 status = ntoh32(event->status);
25281 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
25282 u32 reason = ntoh32(event->reason);
25283
25284 if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
25285 /* Join attempt via non-cfg80211 interface.
25286 * Don't send resultant events to cfg80211
25287 * layer
25288 */
25289 WL_INFORM_MEM(("Event received in non-cfg80211"
25290 " connect state. Ignore\n"));
25291 return BCME_OK;
25292 }
25293
25294 if ((status == WLC_SUP_KEYED || status == WLC_SUP_KEYXCHANGE_WAIT_G1) &&
25295 reason == WLC_E_SUP_OTHER) {
25296#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
25297 /* NL80211_CMD_PORT_AUTHORIZED supported above >= 4.15 */
25298 cfg80211_port_authorized(ndev, (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID),
25299 GFP_KERNEL);
25300 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
25301#elif ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
25302 defined(WL_VENDOR_EXT_SUPPORT))
25303 err = wl_cfgvendor_send_async_event(bcmcfg_to_wiphy(cfg), ndev,
25304 BRCM_VENDOR_EVENT_PORT_AUTHORIZED, NULL, 0);
25305 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
25306#else
25307 /* not supported in kernel <= 3,14,0 */
25308#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */
25309 /* Post SCB authorize actions */
25310 wl_cfg80211_post_scb_auth(cfg, ndev);
25311 } else if (status < WLC_SUP_KEYXCHANGE_WAIT_G1 && (reason != WLC_E_SUP_OTHER &&
25312 reason != WLC_E_SUP_PTK_UPDATE)) {
25313 /* if any failure seen while 4way HS, should send NL80211_CMD_DISCONNECT */
25314 WL_ERR(("4way HS error. status:%d, reason:%d\n", status, reason));
25315 CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
25316 }
25317
25318 return err;
25319}
25320
25321#ifdef WL_BCNRECV
25322static s32
25323wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25324 const wl_event_msg_t *e, void *data)
25325{
25326 s32 status = ntoh32(e->status);
25327 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
25328 /* Abort fakeapscan, when Roam is in progress */
25329 if (status == WLC_E_STATUS_RXBCN_ABORT) {
25330 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_ROAMABORT);
25331 } else {
25332 WL_ERR(("UNKNOWN STATUS. status:%d\n", status));
25333 }
25334 return BCME_OK;
25335}
25336#endif /* WL_BCNRECV */
25337
25338#ifdef WL_MBO
25339static s32
25340wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25341 const wl_event_msg_t *e, void *data)
25342{
25343 s32 err = 0;
25344 wl_event_mbo_t *mbo_evt = (wl_event_mbo_t *)data;
25345 wl_event_mbo_cell_nw_switch_t *cell_sw_evt = NULL;
25346 wl_btm_event_type_data_t *evt_data = NULL;
25347
25348 WL_INFORM(("MBO: Evt %u\n", mbo_evt->type));
25349
25350 if (mbo_evt->type == WL_MBO_E_CELLULAR_NW_SWITCH) {
25351 cell_sw_evt = (wl_event_mbo_cell_nw_switch_t *)mbo_evt->data;
25352 BCM_REFERENCE(cell_sw_evt);
25353 SUPP_EVENT(("CTRL-EVENT-CELLULAR-SWITCH", "reason %d cur_assoc_time_left %u "
25354 "reassoc_delay %u\n", cell_sw_evt->reason,
25355 cell_sw_evt->assoc_time_remain, cell_sw_evt->reassoc_delay));
25356 } else if (mbo_evt->type == WL_MBO_E_BTM_RCVD) {
25357 evt_data = (wl_btm_event_type_data_t *)mbo_evt->data;
25358 if (evt_data->version != WL_BTM_EVENT_DATA_VER_1) {
25359 WL_ERR(("version mismatch. rcvd %u expected %u\n",
25360 evt_data->version, WL_BTM_EVENT_DATA_VER_1));
25361 return -1;
25362 }
25363 SUPP_EVENT(("CTRL-EVENT-BRCM-BTM-REQ-RCVD", "reason=%u\n",
25364 evt_data->transition_reason));
25365 } else {
25366 WL_INFORM(("UNKNOWN EVENT. type:%u\n", mbo_evt->type));
25367 }
25368 return err;
25369}
25370#endif /* WL_MBO */
25371
25372#ifdef WL_CAC_TS
25373static s32
25374wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25375 const wl_event_msg_t *e, void *data)
25376{
25377 u32 event = ntoh32(e->event_type);
25378 s32 status = ntoh32(e->status);
25379 s32 reason = ntoh32(e->reason);
25380
25381 BCM_REFERENCE(reason);
25382
25383 if (event == WLC_E_ADDTS_IND) {
25384 /* The supp log format of adding ts_delay in success case needs to be maintained */
25385 if (status == WLC_E_STATUS_SUCCESS) {
25386 uint *ts_delay = (uint *)data;
25387 BCM_REFERENCE(ts_delay);
25388 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d ts_delay=%u\n",
25389 status, reason, *ts_delay));
25390 } else {
25391 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d\n",
25392 status, reason));
25393 }
25394 } else if (event == WLC_E_DELTS_IND) {
25395 SUPP_EVENT(("CTRL-EVENT-CAC-DELTS", "status=%d reason=%d\n", status, reason));
25396 }
25397
25398 return BCME_OK;
25399}
25400#endif /* WL_CAC_TS */
25401
25402#if defined(WL_MBO) || defined(WL_OCE)
25403static s32
25404wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25405 const wl_event_msg_t *e, void *data)
25406{
25407 s32 err = 0;
25408 uint reason = 0;
25409 wl_bssid_pruned_evt_info_t *evt_info = (wl_bssid_pruned_evt_info_t *)data;
25410
25411 if (evt_info->version == WL_BSSID_PRUNE_EVT_VER_1) {
25412 if (evt_info->reason == WLC_E_PRUNE_ASSOC_RETRY_DELAY) {
25413 /* MBO assoc retry delay */
25414 reason = WIFI_PRUNE_ASSOC_RETRY_DELAY;
25415 SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
25416 " reason=%u timeout_val=%u(ms)\n", evt_info->SSID,
25417 ETHER_TO_MACF(evt_info->BSSID), reason, evt_info->time_remaining));
25418 } else if (evt_info->reason == WLC_E_PRUNE_RSSI_ASSOC_REJ) {
25419 /* OCE RSSI-based assoc rejection */
25420 reason = WIFI_PRUNE_RSSI_ASSOC_REJ;
25421 SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
25422 " reason=%u timeout_val=%u(ms) rssi_threshold=%d(dBm)\n",
25423 evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID),
25424 reason, evt_info->time_remaining, evt_info->rssi_threshold));
25425 } else {
25426 /* Invalid other than the assoc retry delay/RSSI assoc rejection
25427 * in the current handler
25428 */
25429 BCM_REFERENCE(reason);
25430 WL_INFORM(("INVALID. reason:%u\n", evt_info->reason));
25431 }
25432 } else {
25433 WL_INFORM(("version mismatch. rcvd %u expected %u\n", evt_info->version,
25434 WL_BSSID_PRUNE_EVT_VER_1));
25435 }
25436 return err;
25437}
25438#endif /* WL_MBO || WL_OCE */
25439#ifdef RTT_SUPPORT
25440static s32
25441wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25442 const wl_event_msg_t *e, void *data)
25443{
25444 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
25445 wl_event_msg_t event;
25446
25447 (void)memcpy_s(&event, sizeof(wl_event_msg_t),
25448 e, sizeof(wl_event_msg_t));
25449 return dhd_rtt_event_handler(dhdp, &event, data);
25450}
25451#endif /* RTT_SUPPORT */
25452
25453void
25454wl_print_verinfo(struct bcm_cfg80211 *cfg)
25455{
25456 char *ver_ptr;
25457 uint32 alloc_len = MOD_PARAM_INFOLEN;
25458
25459 if (!cfg) {
25460 WL_ERR(("cfg is NULL\n"));
25461 return;
25462 }
25463
25464 ver_ptr = (char *)MALLOCZ(cfg->osh, alloc_len);
25465 if (!ver_ptr) {
25466 WL_ERR(("Failed to alloc ver_ptr\n"));
25467 return;
25468 }
25469
25470 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
25471 TRUE, &ver_ptr, alloc_len)) {
25472 WL_ERR(("DHD Version: %s\n", ver_ptr));
25473 }
25474
25475 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
25476 FALSE, &ver_ptr, alloc_len)) {
25477 WL_ERR(("F/W Version: %s\n", ver_ptr));
25478 }
25479
25480 MFREE(cfg->osh, ver_ptr, alloc_len);
25481}
25482
25483typedef struct {
25484 uint16 id;
25485 uint16 len;
25486 uint32 val;
25487} he_xtlv_v32;
25488
25489 static bool
25490wl_he_get_uint_cb(void *ctx, uint16 *id, uint16 *len)
25491{
25492 he_xtlv_v32 *v32 = ctx;
25493
25494 *id = v32->id;
25495 *len = v32->len;
25496
25497 return FALSE;
25498}
25499
25500 static void
25501wl_he_pack_uint_cb(void *ctx, uint16 id, uint16 len, uint8 *buf)
25502{
25503 he_xtlv_v32 *v32 = ctx;
25504
25505 BCM_REFERENCE(id);
25506 BCM_REFERENCE(len);
25507
25508 v32->val = htod32(v32->val);
25509
25510 switch (v32->len) {
25511 case sizeof(uint8):
25512 *buf = (uint8)v32->val;
25513 break;
25514 case sizeof(uint16):
25515 store16_ua(buf, (uint16)v32->val);
25516 break;
25517 case sizeof(uint32):
25518 store32_ua(buf, v32->val);
25519 break;
25520 default:
25521 /* ASSERT(0); */
25522 break;
25523 }
25524}
25525
25526int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg,
25527 s32 bssidx, u32 interface_type, bool set)
25528{
25529 bcm_xtlv_t read_he_xtlv;
25530 uint8 se_he_xtlv[32];
25531 int se_he_xtlv_len = sizeof(se_he_xtlv);
25532 he_xtlv_v32 v32;
25533 u32 he_feature = 0;
25534 s32 err = 0;
25535 u32 he_interface = 0;
25536
25537 read_he_xtlv.id = WL_HE_CMD_FEATURES;
25538 read_he_xtlv.len = 0;
25539 err = wldev_iovar_getbuf_bsscfg(dev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
25540 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, NULL);
25541 if (err < 0) {
25542 if (err == BCME_UNSUPPORTED) {
25543 /* HE not supported. Do nothing. */
25544 return BCME_OK;
25545 }
25546 WL_ERR(("HE get failed. error=%d\n", err));
25547 } else {
25548 he_feature = *(int*)cfg->ioctl_buf;
25549 he_feature = dtoh32(he_feature);
25550 }
25551
25552 v32.id = WL_HE_CMD_FEATURES;
25553 v32.len = sizeof(s32);
25554 if (interface_type == WL_IF_TYPE_P2P_DISC) {
25555 he_interface = WL_HE_FEATURES_HE_P2P;
25556 } else if (interface_type == WL_IF_TYPE_AP) {
25557 he_interface = WL_HE_FEATURES_HE_AP;
25558 } else {
25559 WL_ERR(("HE request for Invalid interface type"));
25560 err = BCME_BADARG;
25561 return err;
25562 }
25563
25564 if (set) {
25565 v32.val = (he_feature | he_interface);
25566 } else {
25567 v32.val = (he_feature & ~he_interface);
25568 }
25569
25570 err = bcm_pack_xtlv_buf((void *)&v32, se_he_xtlv, sizeof(se_he_xtlv),
25571 BCM_XTLV_OPTION_ALIGN32, wl_he_get_uint_cb, wl_he_pack_uint_cb,
25572 &se_he_xtlv_len);
25573 if (err != BCME_OK) {
25574 WL_ERR(("failed to pack he settvl=%d\n", err));
25575 }
25576
25577 err = wldev_iovar_setbuf_bsscfg(dev, "he", &se_he_xtlv, sizeof(se_he_xtlv),
25578 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
25579 if (err < 0) {
25580 WL_ERR(("failed to set he features, error=%d\n", err));
25581 }
25582 WL_INFORM(("Set HE[%d] done\n", set));
25583
25584 return err;
25585}
25586
25587/* Get the concurrency mode */
25588int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg)
25589{
25590 struct net_info *iter, *next;
25591 uint cmode = CONCURRENCY_MODE_NONE;
25592 u32 connected_cnt = 0;
25593 u32 pre_channel = 0, channel = 0;
25594 u32 pre_band = 0;
25595 u32 chanspec = 0;
25596 u32 band = 0;
25597
25598 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
25599 if (connected_cnt <= 1) {
25600 return cmode;
25601 }
25602 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
25603 for_each_ndev(cfg, iter, next) {
25604 if (iter->ndev) {
25605 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
25606 if (wldev_iovar_getint(iter->ndev, "chanspec",
25607 (s32 *)&chanspec) == BCME_OK) {
25608 channel = wf_chspec_ctlchan(
25609 wl_chspec_driver_to_host(chanspec));
25610 band = (channel <= CH_MAX_2G_CHANNEL) ?
25611 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
25612 }
25613 if ((!pre_channel && channel)) {
25614 pre_band = band;
25615 pre_channel = channel;
25616 } else if (pre_channel) {
25617 if ((pre_band == band) && (pre_channel == channel)) {
25618 cmode = CONCURRENCY_SCC_MODE;
25619 goto exit;
25620 } else if ((pre_band == band) && (pre_channel != channel)) {
25621 cmode = CONCURRENCY_VSDB_MODE;
25622 goto exit;
25623 } else if (pre_band != band) {
25624 cmode = CONCURRENCY_RSDB_MODE;
25625 goto exit;
25626 }
25627 }
25628 }
25629 }
25630 }
25631#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
25632 4 && __GNUC_MINOR__ >= 6))
25633_Pragma("GCC diagnostic pop")
25634#endif
25635exit:
25636 return cmode;
25637}
25638#ifdef WL_CHAN_UTIL
25639static s32
25640wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25641 const wl_event_msg_t *e, void *data)
25642{
25643 s32 err = BCME_OK;
25644 struct sk_buff *skb = NULL;
25645 s32 status = ntoh32(e->status);
25646 u8 chan_use_percentage = 0;
25647#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
25648 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
25649 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
25650#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
25651 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
25652#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25653 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
25654 uint len;
25655 gfp_t kflags;
25656#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25657
25658#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25659 len = CU_ATTR_HDR_LEN + sizeof(u8);
25660 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
25661#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25662
25663#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
25664 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
25665 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), len,
25666 BRCM_VENDOR_EVENT_CU, kflags);
25667#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25668 skb = cfg80211_vendor_event_alloc(wiphy, len, BRCM_VENDOR_EVENT_CU, kflags);
25669#else
25670 /* No support exist */
25671#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
25672 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
25673 if (!skb) {
25674 WL_ERR(("skb alloc failed"));
25675 return -ENOMEM;
25676 }
25677
25678 if ((status == WLC_E_STATUS_SUCCESS) && data) {
25679 wl_bssload_t *bssload_report = (wl_bssload_t *)data;
25680 chan_use_percentage = (bssload_report->chan_util * 100) / 255;
25681 WL_DBG(("ChannelUtilization=%hhu\n", chan_use_percentage));
25682 err = nla_put_u8(skb, CU_ATTR_PERCENTAGE, chan_use_percentage);
25683 if (err < 0) {
25684 WL_ERR(("Failed to put CU_ATTR_PERCENTAGE, err:%d\n", err));
25685 }
25686 }
25687
25688#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25689 cfg80211_vendor_event(skb, kflags);
25690#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25691
25692 return err;
25693}
25694
25695#define WL_CHAN_UTIL_DEFAULT_INTERVAL 3000
25696#define WL_CHAN_UTIL_THRESH_MIN 15
25697#define WL_CHAN_UTIL_THRESH_INTERVAL 10
25698#ifndef CUSTOM_CU_INTERVAL
25699#define CUSTOM_CU_INTERVAL WL_CHAN_UTIL_DEFAULT_INTERVAL
25700#endif /* CUSTOM_CU_INTERVAL */
25701
25702static s32
25703wl_cfg80211_start_bssload_report(struct net_device *ndev)
25704{
25705 s32 err = BCME_OK;
25706 wl_bssload_cfg_t blcfg;
25707 u8 i;
25708 struct bcm_cfg80211 *cfg;
25709
25710 if (!ndev) {
25711 return -ENODEV;
25712 }
25713
25714 cfg = wl_get_cfg(ndev);
25715 if (!cfg) {
25716 return -ENODEV;
25717 }
25718
25719 /* Typecasting to void as the buffer size is same as the memset size */
25720 (void)memset_s(&blcfg, sizeof(wl_bssload_cfg_t), 0, sizeof(wl_bssload_cfg_t));
25721 /* Set default report interval 3 sec and 8 threshhold levels between 15 to 85% */
25722 blcfg.rate_limit_msec = CUSTOM_CU_INTERVAL;
25723 blcfg.num_util_levels = MAX_BSSLOAD_LEVELS;
25724 for (i = 0; i < MAX_BSSLOAD_LEVELS; i++) {
25725 blcfg.util_levels[i] = (((WL_CHAN_UTIL_THRESH_MIN +
25726 (i * WL_CHAN_UTIL_THRESH_INTERVAL)) * 255) / 100);
25727 }
25728
25729 err = wldev_iovar_setbuf(ndev, "bssload_report_event", &blcfg,
25730 sizeof(wl_bssload_cfg_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
25731 if (unlikely(err)) {
25732 WL_ERR(("Set event_msgs error (%d)\n", err));
25733 }
25734
25735 return err;
25736}
25737#endif /* WL_CHAN_UTIL */
25738
25739s32
25740wl_cfg80211_config_suspend_events(struct net_device *ndev, bool enable)
25741{
25742 s32 err = 0;
25743 struct bcm_cfg80211 *cfg;
25744 s8 event_buf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE] = {0};
25745 eventmsgs_ext_t *eventmask_msg = NULL;
25746 /* Room for "event_msgs_ext" + '\0' + bitvec */
25747 char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16];
25748 s32 msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE;
25749
25750 if (!ndev) {
25751 return -ENODEV;
25752 }
25753
25754 cfg = wl_get_cfg(ndev);
25755 if (!cfg) {
25756 return -ENODEV;
25757 }
25758
25759 mutex_lock(&cfg->event_sync);
25760
25761 eventmask_msg = (eventmsgs_ext_t *)event_buf;
25762 eventmask_msg->ver = EVENTMSGS_VER;
25763 eventmask_msg->command = EVENTMSGS_NONE;
25764 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
25765 eventmask_msg->maxgetsize = WL_EVENTING_MASK_EXT_LEN;
25766
25767 /* Read event_msgs mask */
25768 err = wldev_iovar_getbuf(ndev, "event_msgs_ext",
25769 eventmask_msg, EVENTMSGS_EXT_STRUCT_SIZE,
25770 iovbuf,
25771 sizeof(iovbuf),
25772 NULL);
25773
25774 if (unlikely(err)) {
25775 WL_ERR(("Get event_msgs error (%d)\n", err));
25776 goto eventmsg_out;
25777 }
25778
25779 bcopy(iovbuf, eventmask_msg, msglen);
25780
25781 /* Add set/clear of event mask under feature specific flags */
25782 if (enable) {
25783 WL_DBG(("%s: Enabling events on resume\n", __FUNCTION__));
25784#ifdef WL_CHAN_UTIL
25785 setbit(eventmask_msg->mask, WLC_E_BSS_LOAD);
25786#endif /* WL_CHAN_UTIL */
25787 } else {
25788 WL_DBG(("%s: Disabling events before suspend\n", __FUNCTION__));
25789#ifdef WL_CHAN_UTIL
25790 clrbit(eventmask_msg->mask, WLC_E_BSS_LOAD);
25791#endif /* WL_CHAN_UTIL */
25792 }
25793
25794 /* Write updated Event mask */
25795 eventmask_msg->ver = EVENTMSGS_VER;
25796 eventmask_msg->command = EVENTMSGS_SET_MASK;
25797 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
25798
25799 err = wldev_iovar_setbuf(ndev, "event_msgs_ext", eventmask_msg,
25800 WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE,
25801 iovbuf, sizeof(iovbuf), NULL);
25802
25803 if (unlikely(err)) {
25804 WL_ERR(("Set event_msgs error (%d)\n", err));
25805 goto eventmsg_out;
25806 }
25807
25808eventmsg_out:
25809 mutex_unlock(&cfg->event_sync);
25810 return err;
25811}
25812
25813#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
25814int
25815wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
25816 struct cfg80211_csa_settings *params)
25817{
25818 s32 err = BCME_OK;
25819 u32 bw = WL_CHANSPEC_BW_20;
25820 chanspec_t chspec = 0;
25821 wl_chan_switch_t csa_arg;
25822 struct cfg80211_chan_def *chandef = &params->chandef;
25823 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
25824 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
25825
25826 dev = ndev_to_wlc_ndev(dev, cfg);
25827 chspec = wl_freq_to_chanspec(chandef->chan->center_freq);
25828
25829 WL_ERR(("netdev_ifidx(%d), target channel(%d) target bandwidth(%d),"
25830 " mode(%d), count(%d)\n", dev->ifindex, CHSPEC_CHANNEL(chspec), chandef->width,
25831 params->block_tx, params->count));
25832
25833 if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) {
25834 WL_ERR(("Channel Switch doesn't support on "
25835 "the non-SoftAP mode\n"));
25836 return -EINVAL;
25837 }
25838
25839 /* Check if STA is trying to associate with an AP */
25840 if (wl_get_drv_status(cfg, CONNECTING, primary_dev)) {
25841 WL_ERR(("Connecting is in progress\n"));
25842 return BCME_BUSY;
25843 }
25844
25845 if (chspec == cfg->ap_oper_channel) {
25846 WL_ERR(("Channel %d is same as current operating channel,"
25847 " so skip\n", CHSPEC_CHANNEL(chspec)));
25848 return BCME_OK;
25849 }
25850
25851 if (
25852#ifdef WL_6G_BAND
25853 CHSPEC_IS6G(chspec) ||
25854#endif
25855 CHSPEC_IS5G(chspec)) {
25856#ifdef APSTA_RESTRICTED_CHANNEL
25857 if (CHSPEC_CHANNEL(chspec) != DEFAULT_5G_SOFTAP_CHANNEL) {
25858 WL_ERR(("Invalid 5G Channel, chan=%d\n", CHSPEC_CHANNEL(chspec)));
25859 return -EINVAL;
25860 }
25861#endif /* APSTA_RESTRICTED_CHANNEL */
25862 err = wl_get_bandwidth_cap(primary_dev, CHSPEC_BAND(chspec), &bw);
25863 if (err < 0) {
25864 WL_ERR(("Failed to get bandwidth information,"
25865 " err=%d\n", err));
25866 return err;
25867 }
25868 } else if (CHSPEC_IS2G(chspec)) {
25869#ifdef APSTA_RESTRICTED_CHANNEL
25870 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
25871 chanspec_t *sta_chanspec = (chanspec_t *)wl_read_prof(cfg,
25872 primary_dev, WL_PROF_CHAN);
25873
25874 /* In 2GHz STA/SoftAP concurrent mode, the operating channel
25875 * of STA and SoftAP should be confgiured to the same 2GHz
25876 * channel. Otherwise, it is an invalid configuration.
25877 */
25878 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
25879 wl_get_drv_status(cfg, CONNECTED, primary_dev) &&
25880 sta_chanspec && (CHSPEC_CHANNEL(*sta_chanspec) != CHSPEC_CHANNEL(chspec))) {
25881 WL_ERR(("Invalid 2G Channel in case of STA/SoftAP"
25882 " concurrent mode, sta_chan=%d, chan=%d\n",
25883 CHSPEC_CHANNEL(*sta_chanspec), CHSPEC_CHANNEL(chspec)));
25884 return -EINVAL;
25885 }
25886#endif /* APSTA_RESTRICTED_CHANNEL */
25887 bw = WL_CHANSPEC_BW_20;
25888 } else {
25889 WL_ERR(("invalid band (%d)\n", CHSPEC_BAND(chspec)));
25890 return -EINVAL;
25891 }
25892
25893#ifdef WL_6G_BAND
25894 /* Avoid in case of 6G as for each center frequency bw is unique and is
25895 * detected based on centre frequency.
25896 */
25897 if (!CHSPEC_IS6G(chspec))
25898#endif /* WL_6G_BAND */
25899 {
25900 chspec = wf_channel2chspec(CHSPEC_CHANNEL(chspec), bw);
25901 }
25902 if (!wf_chspec_valid(chspec)) {
25903 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
25904 return -EINVAL;
25905 }
25906
25907 /* Send CSA to associated STAs */
25908 memset(&csa_arg, 0, sizeof(wl_chan_switch_t));
25909 csa_arg.mode = params->block_tx;
25910 csa_arg.count = params->count;
25911 csa_arg.chspec = chspec;
25912 csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME;
25913 csa_arg.reg = 0;
25914
25915 err = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(wl_chan_switch_t),
25916 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
25917 if (err < 0) {
25918 WL_ERR(("Failed to switch channel, err=%d\n", err));
25919 }
25920
25921 return err;
25922}
25923#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
25924
25925#ifdef WL_WIPSEVT
25926int
25927wl_cfg80211_wips_event_ext(wl_wips_event_info_t *wips_event)
25928{
25929 s32 err = BCME_OK;
25930#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25931 struct sk_buff *skb;
25932 gfp_t kflags;
25933 struct bcm_cfg80211 *cfg;
25934 struct net_device *ndev;
25935 struct wiphy *wiphy;
25936
25937 cfg = wl_cfg80211_get_bcmcfg();
25938 if (!cfg || !cfg->wdev) {
25939 WL_ERR(("WIPS evt invalid arg\n"));
25940 return err;
25941 }
25942
25943 ndev = bcmcfg_to_prmry_ndev(cfg);
25944 wiphy = bcmcfg_to_wiphy(cfg);
25945
25946 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
25947 skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
25948 BRCM_VENDOR_WIPS_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_WIPS, kflags);
25949
25950 if (!skb) {
25951 WL_ERR(("skb alloc failed"));
25952 return BCME_NOMEM;
25953 }
25954
25955 err = nla_put_u16(skb, WIPS_ATTR_DEAUTH_CNT, wips_event->misdeauth);
25956 if (unlikely(err)) {
25957 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_CNT failed\n"));
25958 goto fail;
25959 }
25960 err = nla_put(skb, WIPS_ATTR_DEAUTH_BSSID, ETHER_ADDR_LEN, &wips_event->bssid);
25961 if (unlikely(err)) {
25962 WL_ERR(("nla_put WIPS_ATTR_DEAUTH_BSSID failed\n"));
25963 goto fail;
25964 }
25965 err = nla_put_s16(skb, WIPS_ATTR_CURRENT_RSSI, wips_event->current_RSSI);
25966 if (unlikely(err)) {
25967 WL_ERR(("nla_put_u16 WIPS_ATTR_CURRENT_RSSI failed\n"));
25968 goto fail;
25969 }
25970 err = nla_put_s16(skb, WIPS_ATTR_DEAUTH_RSSI, wips_event->deauth_RSSI);
25971 if (unlikely(err)) {
25972 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_RSSI failed\n"));
25973 goto fail;
25974 }
25975 cfg80211_vendor_event(skb, kflags);
25976
25977 return err;
25978
25979fail:
25980 if (skb) {
25981 nlmsg_free(skb);
25982 }
25983#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25984 return err;
25985}
25986
25987int
25988wl_cfg80211_wips_event(uint16 misdeauth, char* bssid)
25989{
25990 s32 err = BCME_OK;
25991 wl_wips_event_info_t wips_event;
25992
25993 wips_event.misdeauth = misdeauth;
25994 memcpy(&wips_event.bssid, bssid, ETHER_ADDR_LEN);
25995 wips_event.current_RSSI = 0;
25996 wips_event.deauth_RSSI = 0;
25997
25998 err = wl_cfg80211_wips_event_ext(&wips_event);
25999 return err;
26000}
26001#endif /* WL_WIPSEVT */
26002
26003#ifdef PCIE_INB_DW
26004#define WL_DS(x)
26005/*
26006 * This API checks whether its okay to enter DS.
26007 * If some transaction is in progress, return true
26008 * to skip DS.
26009 */
26010bool wl_cfg80211_check_in_progress(struct net_device *dev)
26011{
26012 struct bcm_cfg80211 *cfg;
26013 struct net_device *pri_dev;
26014 u8 reason = WL_STATE_IDLE;
26015 u64 timeout;
26016 u64 start_time = 0;
26017
26018 cfg = wl_get_cfg(dev);
26019 pri_dev = bcmcfg_to_prmry_ndev(cfg);
26020
26021 /* check states like scan in progress, four way handshake, etc
26022 * before entering Deep Sleep.
26023 */
26024 if (wl_get_drv_status_all(cfg, SCANNING)) {
26025 WL_DS(("scan in progress\n"));
26026 reason = WL_STATE_SCANNING;
26027 start_time = GET_TS(cfg, scan_start);
26028 } else if (wl_get_drv_status_all(cfg, CONNECTING)) {
26029 WL_DS(("connect in progress\n"));
26030 reason = WL_STATE_CONNECTING;
26031 start_time = GET_TS(cfg, conn_start);
26032 } else if ((IS_STA_IFACE(ndev_to_wdev(dev))) &&
26033 wl_get_drv_status(cfg, CONNECTED, pri_dev) &&
26034 !wl_get_drv_status(cfg, AUTHORIZED, pri_dev)) {
26035 WL_DS(("connect-authorization in progress\n"));
26036 reason = WL_STATE_AUTHORIZING;
26037 start_time = GET_TS(cfg, authorize_start);
26038 }
26039
26040 if (reason) {
26041 u64 curtime = OSL_LOCALTIME_NS();
26042 if (unlikely(!start_time)) {
26043 WL_ERR(("state got cleared for reason:%d\n", reason));
26044 return false;
26045 }
26046 /* check whether we are stuck in a state
26047 * for too long.
26048 */
26049 timeout = (start_time + (WL_DS_SKIP_THRESHOLD_USECS * 1000L));
26050 if (time_after64(curtime, timeout)) {
26051 /* state hasn't changed for WL_DS_SKIP_THRESHOLD_USECS */
26052 WL_ERR(("DS skip threshold hit. reason:%d start_time:"
26053 SEC_USEC_FMT" cur_time:"SEC_USEC_FMT"\n",
26054 reason, GET_SEC_USEC(start_time), GET_SEC_USEC(curtime)));
26055 ASSERT((0));
26056 }
26057 /* return true to skip suspend */
26058 return true;
26059 }
26060
26061 return false;
26062}
26063#endif
26064
26065#ifdef SUPPORT_AP_SUSPEND
26066void
26067wl_set_ap_suspend_error_handler(struct net_device *ndev, bool suspend)
26068{
26069 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
26070 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
26071
26072 if (wl_get_drv_status(cfg, READY, ndev)) {
26073 /* IF dongle is down due to previous hang or other conditions, sending
26074 * one more hang notification is not needed.
26075 */
26076 if (dhd_query_bus_erros(dhdp)) {
26077 return;
26078 }
26079 dhdp->iface_op_failed = TRUE;
26080#if defined(DHD_FW_COREDUMP)
26081 if (dhdp->memdump_enabled) {
26082 dhdp->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
26083 dhd_bus_mem_dump(dhdp);
26084 }
26085#endif /* DHD_FW_COREDUMP */
26086
26087 WL_ERR(("Notify hang event to upper layer \n"));
26088 dhdp->hang_reason = suspend ?
26089 HANG_REASON_BSS_DOWN_FAILURE : HANG_REASON_BSS_UP_FAILURE;
26090 net_os_send_hang_message(ndev);
26091
26092 }
26093}
26094
26095#define MAX_AP_RESUME_TIME 5000
26096int
26097wl_set_ap_suspend(struct net_device *dev, bool suspend, char *ifname)
26098{
26099 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
26100 dhd_pub_t *dhdp;
26101 struct net_device *ndev = NULL;
26102 int ret = BCME_OK;
26103 bool is_bssup = FALSE;
26104 int bssidx;
26105 unsigned long start_j;
26106 int time_to_sleep = MAX_AP_RESUME_TIME;
26107
26108 dhdp = (dhd_pub_t *)(cfg->pub);
26109
26110 if (!dhdp) {
26111 return BCME_NOTUP;
26112 }
26113
26114 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
26115 WL_ERR(("Not Hostapd mode\n"));
26116 return BCME_NOTAP;
26117 }
26118
26119 ndev = wl_get_ap_netdev(cfg, ifname);
26120
26121 if (ndev == NULL) {
26122 WL_ERR(("No softAP interface named %s\n", ifname));
26123 return BCME_NOTAP;
26124 }
26125
26126 if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
26127 WL_ERR(("Find p2p index from wdev(%p) failed\n", ndev->ieee80211_ptr));
26128 return BCME_NOTFOUND;
26129 }
26130
26131 is_bssup = wl_cfg80211_bss_isup(ndev, bssidx);
26132 if (is_bssup && suspend) {
26133 wl_clr_drv_status(cfg, AP_CREATED, ndev);
26134 wl_clr_drv_status(cfg, CONNECTED, ndev);
26135
26136 if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 0)) < 0) {
26137 WL_ERR(("AP suspend error %d, suspend %d\n", ret, suspend));
26138 ret = BCME_NOTDOWN;
26139 goto exit;
26140 }
26141 } else if (!is_bssup && !suspend) {
26142 /* Abort scan before starting AP again */
26143 wl_cfg80211_scan_abort(cfg);
26144
26145 if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 1)) < 0) {
26146 WL_ERR(("AP resume error %d, suspend %d\n", ret, suspend));
26147 ret = BCME_NOTUP;
26148 goto exit;
26149 }
26150
26151 while (TRUE) {
26152 start_j = get_jiffies_64();
26153 /* Wait for Linkup event to mark successful AP bring up */
26154 ret = wait_event_interruptible_timeout(cfg->netif_change_event,
26155 wl_get_drv_status(cfg, AP_CREATED, ndev),
26156 msecs_to_jiffies(time_to_sleep));
26157 if (ret == -ERESTARTSYS) {
26158 WL_ERR(("waitqueue was interrupted by a signal\n"));
26159 time_to_sleep -= jiffies_to_msecs(get_jiffies_64() - start_j);
26160 if (time_to_sleep <= 0) {
26161 WL_ERR(("time to sleep hits 0\n"));
26162 ret = BCME_NOTUP;
26163 goto exit;
26164 }
26165 } else if (ret == 0 || !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
26166 WL_ERR(("AP resume failed!\n"));
26167 ret = BCME_NOTUP;
26168 goto exit;
26169 } else {
26170 wl_set_drv_status(cfg, CONNECTED, ndev);
26171 wl_clr_drv_status(cfg, AP_CREATING, ndev);
26172 ret = BCME_OK;
26173 break;
26174 }
26175 }
26176 } else {
26177 /* bssup + resume or bssdown + suspend,
26178 * So, returns OK
26179 */
26180 ret = BCME_OK;
26181 }
26182exit:
26183 if (ret != BCME_OK)
26184 wl_set_ap_suspend_error_handler(bcmcfg_to_prmry_ndev(cfg), suspend);
26185
26186 return ret;
26187}
26188#endif /* SUPPORT_AP_SUSPEND */
26189
26190#ifdef SUPPORT_SOFTAP_ELNA_BYPASS
26191int wl_set_softap_elna_bypass(struct net_device *dev, char *ifname, int enable)
26192{
26193 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
26194 struct net_device *ifdev = NULL;
26195 char iobuf[WLC_IOCTL_SMLEN];
26196 int err = BCME_OK;
26197 int iftype = 0;
26198
26199 memset(iobuf, 0, WLC_IOCTL_SMLEN);
26200
26201 /* Check the interface type */
26202 ifdev = wl_get_netdev_by_name(cfg, ifname);
26203 if (ifdev == NULL) {
26204 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__, ifname));
26205 err = BCME_BADARG;
26206 goto fail;
26207 }
26208
26209 iftype = ifdev->ieee80211_ptr->iftype;
26210 if (iftype == NL80211_IFTYPE_AP) {
26211 err = wldev_iovar_setint(ifdev, "softap_elnabypass", enable);
26212 if (unlikely(err)) {
26213 WL_ERR(("%s: Failed to set softap_elnabypass, err=%d\n",
26214 __FUNCTION__, err));
26215 }
26216 } else {
26217 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
26218 __FUNCTION__));
26219 err = BCME_BADARG;
26220 }
26221fail:
26222 return err;
26223}
26224int wl_get_softap_elna_bypass(struct net_device *dev, char *ifname, void *param)
26225{
26226 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
26227 int *enable = (int*)param;
26228 struct net_device *ifdev = NULL;
26229 char iobuf[WLC_IOCTL_SMLEN];
26230 int err = BCME_OK;
26231 int iftype = 0;
26232
26233 memset(iobuf, 0, WLC_IOCTL_SMLEN);
26234
26235 /* Check the interface type */
26236 ifdev = wl_get_netdev_by_name(cfg, ifname);
26237 if (ifdev == NULL) {
26238 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__, ifname));
26239 err = BCME_BADARG;
26240 goto fail;
26241 }
26242
26243 iftype = ifdev->ieee80211_ptr->iftype;
26244 if (iftype == NL80211_IFTYPE_AP) {
26245 err = wldev_iovar_getint(ifdev, "softap_elnabypass", enable);
26246 if (unlikely(err)) {
26247 WL_ERR(("%s: Failed to get softap_elnabypass, err=%d\n",
26248 __FUNCTION__, err));
26249 }
26250 } else {
26251 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
26252 __FUNCTION__));
26253 err = BCME_BADARG;
26254 }
26255fail:
26256 return err;
26257
26258}
26259#endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
26260
26261#ifdef SUPPORT_AP_BWCTRL
26262#define OPER_MODE_ENABLE (1 << 8)
26263static int op2bw[] = {20, 40, 80, 160};
26264
26265static int
26266wl_get_ap_he_mode(struct net_device *ndev, struct bcm_cfg80211 *cfg, bool *he)
26267{
26268 bcm_xtlv_t read_he_xtlv;
26269 int ret = 0;
26270 u8 he_enab = 0;
26271 u32 he_feature = 0;
26272 *he = FALSE;
26273
26274 /* Check he enab first */
26275 read_he_xtlv.id = WL_HE_CMD_ENAB;
26276 read_he_xtlv.len = 0;
26277
26278 ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
26279 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
26280 if (ret < 0) {
26281 if (ret == BCME_UNSUPPORTED) {
26282 /* HE not supported */
26283 ret = BCME_OK;
26284 } else {
26285 WL_ERR(("HE ENAB get failed. ret=%d\n", ret));
26286 }
26287 goto exit;
26288 } else {
26289 he_enab = *(u8*)cfg->ioctl_buf;
26290 }
26291
26292 if (!he_enab) {
26293 goto exit;
26294 }
26295
26296 /* Then check BIT3 of he features */
26297 read_he_xtlv.id = WL_HE_CMD_FEATURES;
26298 read_he_xtlv.len = 0;
26299
26300 ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
26301 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
26302 if (ret < 0) {
26303 WL_ERR(("HE FEATURE get failed. error=%d\n", ret));
26304 goto exit;
26305 } else {
26306 he_feature = *(int*)cfg->ioctl_buf;
26307 he_feature = dtoh32(he_feature);
26308 }
26309
26310 if (he_feature & WL_HE_FEATURES_HE_AP) {
26311 WL_DBG(("HE is enabled in AP\n"));
26312 *he = TRUE;
26313 }
26314exit:
26315 return ret;
26316}
26317
26318static void
26319wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg, struct net_device *ndev, chanspec_t chanspec)
26320{
26321 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
26322 struct wireless_dev *wdev = ndev_to_wdev(dev);
26323 struct wiphy *wiphy = wdev->wiphy;
26324 int ret = BCME_OK;
26325 u32 bw_cap;
26326 u32 ctl_chan;
26327 chanspec_t chanbw = WL_CHANSPEC_BW_20;
26328
26329 /* Update channel in profile */
26330 ctl_chan = wf_chspec_ctlchan(chanspec);
26331 wl_update_prof(cfg, ndev, NULL, &chanspec, WL_PROF_CHAN);
26332
26333 /* BW cap is only updated in 5GHz */
26334 if (ctl_chan <= CH_MAX_2G_CHANNEL)
26335 return;
26336
26337 /* Get WL BW CAP */
26338 ret = wl_get_bandwidth_cap(bcmcfg_to_prmry_ndev(cfg),
26339 CHSPEC_BAND(chanspec), &bw_cap);
26340 if (ret < 0) {
26341 WL_ERR(("get bw_cap failed = %d\n", ret));
26342 goto exit;
26343 }
26344
26345 chanbw = CHSPEC_BW(wl_channel_to_chanspec(wiphy,
26346 ndev, wf_chspec_ctlchan(chanspec), bw_cap));
26347
26348exit:
26349 cfg->bw_cap_5g = bw2cap[chanbw >> WL_CHANSPEC_BW_SHIFT];
26350 WL_INFORM_MEM(("supported bw cap is:0x%x\n", cfg->bw_cap_5g));
26351
26352}
26353
26354int
26355wl_rxchain_to_opmode_nss(int rxchain)
26356{
26357 /*
26358 * Nss 1 -> 0, Nss 2 -> 1
26359 * This is from operating mode field
26360 * in 8.4.1.50 of 802.11ac-2013
26361 */
26362 /* TODO : Nss 3 ? */
26363 if (rxchain == 3)
26364 return (1 << 4);
26365 else
26366 return 0;
26367}
26368
26369int
26370wl_update_opmode(struct net_device *ndev, u32 bw)
26371{
26372 int ret = BCME_OK;
26373 int oper_mode;
26374 int rxchain;
26375
26376 ret = wldev_iovar_getint(ndev, "rxchain", (s32 *)&rxchain);
26377 if (ret < 0) {
26378 WL_ERR(("get rxchain failed = %d\n", ret));
26379 goto exit;
26380 }
26381
26382 oper_mode = bw;
26383 oper_mode |= wl_rxchain_to_opmode_nss(rxchain);
26384 /* Enable flag */
26385 oper_mode |= OPER_MODE_ENABLE;
26386
26387 ret = wldev_iovar_setint(ndev, "oper_mode", oper_mode);
26388 if (ret < 0) {
26389 WL_ERR(("set oper_mode failed = %d\n", ret));
26390 goto exit;
26391 }
26392
26393exit:
26394 return ret;
26395}
26396
26397int
26398wl_set_ap_bw(struct net_device *dev, u32 bw, char *ifname)
26399{
26400 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
26401 dhd_pub_t *dhdp;
26402 struct net_device *ndev = NULL;
26403 int ret = BCME_OK;
26404 chanspec_t *chanspec;
26405 bool he;
26406
26407 dhdp = (dhd_pub_t *)(cfg->pub);
26408
26409 if (!dhdp) {
26410 return BCME_NOTUP;
26411 }
26412
26413 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
26414 WL_ERR(("Not Hostapd mode\n"));
26415 return BCME_NOTAP;
26416 }
26417
26418 ndev = wl_get_ap_netdev(cfg, ifname);
26419
26420 if (ndev == NULL) {
26421 WL_ERR(("No softAP interface named %s\n", ifname));
26422 return BCME_NOTAP;
26423 }
26424
26425 if (bw > DOT11_OPER_MODE_160MHZ) {
26426 WL_ERR(("BW is too big %d\n", bw));
26427 return BCME_BADARG;
26428 }
26429
26430 chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
26431 if (CHSPEC_IS2G(*chanspec)) {
26432 WL_ERR(("current chanspec is %d, not supported\n", *chanspec));
26433 ret = BCME_BADCHAN;
26434 goto exit;
26435 }
26436
26437 if ((DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
26438 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) ||
26439 wl_cfgnan_is_enabled(cfg)) {
26440 WL_ERR(("BW control in concurrent mode is not supported\n"));
26441 return BCME_BUSY;
26442 }
26443
26444 /* When SCAN is on going either in STA or in AP, return BUSY */
26445 if (wl_get_drv_status_all(cfg, SCANNING)) {
26446 WL_ERR(("STA is SCANNING, not support BW control\n"));
26447 return BCME_BUSY;
26448 }
26449
26450 /* When SCANABORT is on going either in STA or in AP, return BUSY */
26451 if (wl_get_drv_status_all(cfg, SCAN_ABORTING)) {
26452 WL_ERR(("STA is SCAN_ABORTING, not support BW control\n"));
26453 return BCME_BUSY;
26454 }
26455
26456 /* When CONNECTION is on going in STA, return BUSY */
26457 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
26458 WL_ERR(("STA is CONNECTING, not support BW control\n"));
26459 return BCME_BUSY;
26460 }
26461
26462 /* BW control in AX mode needs more verification */
26463 ret = wl_get_ap_he_mode(ndev, cfg, &he);
26464 if (ret == BCME_OK && he) {
26465 WL_ERR(("BW control in HE mode is not supported\n"));
26466 return BCME_UNSUPPORTED;
26467 }
26468 if (ret < 0) {
26469 WL_ERR(("Check AX mode is failed\n"));
26470 goto exit;
26471 }
26472
26473 if ((!WL_BW_CAP_160MHZ(cfg->bw_cap_5g) && (bw == DOT11_OPER_MODE_160MHZ)) ||
26474 (!WL_BW_CAP_80MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_80MHZ)) ||
26475 (!WL_BW_CAP_40MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_40MHZ)) ||
26476 (!WL_BW_CAP_20MHZ(cfg->bw_cap_5g))) {
26477 WL_ERR(("bw_cap %x does not support bw = %d\n", cfg->bw_cap_5g, bw));
26478 ret = BCME_BADARG;
26479 goto exit;
26480 }
26481
26482 WL_DBG(("Updating AP BW to %d\n", op2bw[bw]));
26483
26484 ret = wl_update_opmode(ndev, bw);
26485 if (ret < 0) {
26486 WL_ERR(("opmode set failed = %d\n", ret));
26487 goto exit;
26488 }
26489
26490exit:
26491 return ret;
26492}
26493
26494int
26495wl_get_ap_bw(struct net_device *dev, char* command, char *ifname, int total_len)
26496{
26497 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
26498 dhd_pub_t *dhdp;
26499 struct net_device *ndev = NULL;
26500 int ret = BCME_OK;
26501 u32 chanspec = 0;
26502 u32 bw = DOT11_OPER_MODE_20MHZ;
26503 int bytes_written = 0;
26504
26505 dhdp = (dhd_pub_t *)(cfg->pub);
26506
26507 if (!dhdp) {
26508 return BCME_NOTUP;
26509 }
26510
26511 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
26512 WL_ERR(("Not Hostapd mode\n"));
26513 return BCME_NOTAP;
26514 }
26515
26516 ndev = wl_get_ap_netdev(cfg, ifname);
26517
26518 if (ndev == NULL) {
26519 WL_ERR(("No softAP interface named %s\n", ifname));
26520 return BCME_NOTAP;
26521 }
26522
26523 ret = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
26524 if (ret < 0) {
26525 WL_ERR(("get chanspec from AP failed = %d\n", ret));
26526 goto exit;
26527 }
26528
26529 chanspec = wl_chspec_driver_to_host(chanspec);
26530
26531 if (CHSPEC_IS20(chanspec)) {
26532 bw = DOT11_OPER_MODE_20MHZ;
26533 } else if (CHSPEC_IS40(chanspec)) {
26534 bw = DOT11_OPER_MODE_40MHZ;
26535 } else if (CHSPEC_IS80(chanspec)) {
26536 bw = DOT11_OPER_MODE_80MHZ;
26537 } else if (CHSPEC_IS_BW_160_WIDE(chanspec)) {
26538 bw = DOT11_OPER_MODE_160MHZ;
26539 } else {
26540 WL_ERR(("chanspec error %x\n", chanspec));
26541 ret = BCME_BADCHAN;
26542 goto exit;
26543 }
26544
26545 bytes_written += snprintf(command + bytes_written, total_len,
26546 "bw=%d", bw);
26547 ret = bytes_written;
26548exit:
26549 return ret;
26550}
26551
26552static void
26553wl_restore_ap_bw(struct bcm_cfg80211 *cfg)
26554{
26555 int ret = BCME_OK;
26556 u32 bw;
26557 bool he = FALSE;
26558 struct net_info *iter, *next;
26559 struct net_device *ndev = NULL;
26560 chanspec_t *chanspec;
26561
26562 if (!cfg) {
26563 return;
26564 }
26565
26566 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
26567 for_each_ndev(cfg, iter, next) {
26568 GCC_DIAGNOSTIC_POP();
26569 if (iter->ndev) {
26570 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
26571 chanspec = (chanspec_t *)wl_read_prof(cfg, iter->ndev,
26572 WL_PROF_CHAN);
26573 if (CHSPEC_IS2G(*chanspec)) {
26574 ndev = iter->ndev;
26575 break;
26576 }
26577 }
26578 }
26579 }
26580
26581 if (!ndev) {
26582 return;
26583 }
26584
26585 /* BW control in AX mode not allowed */
26586 ret = wl_get_ap_he_mode(bcmcfg_to_prmry_ndev(cfg), cfg, &he);
26587 if (ret == BCME_OK && he) {
26588 return;
26589 }
26590 if (ret < 0) {
26591 WL_ERR(("Check AX mode is failed\n"));
26592 return;
26593 }
26594
26595 if (WL_BW_CAP_160MHZ(cfg->bw_cap_5g)) {
26596 bw = DOT11_OPER_MODE_160MHZ;
26597 } else if (WL_BW_CAP_80MHZ(cfg->bw_cap_5g)) {
26598 bw = DOT11_OPER_MODE_80MHZ;
26599 } else if (WL_BW_CAP_40MHZ(cfg->bw_cap_5g)) {
26600 bw = DOT11_OPER_MODE_40MHZ;
26601 } else {
26602 return;
26603 }
26604
26605 WL_DBG(("Restoring AP BW to %d\n", op2bw[bw]));
26606
26607 ret = wl_update_opmode(ndev, bw);
26608 if (ret < 0) {
26609 WL_ERR(("bw restore failed = %d\n", ret));
26610 return;
26611 }
26612}
26613#endif /* SUPPORT_AP_BWCTRL */
26614
26615bool wl_cfg80211_is_dpp_frame(void *frame, u32 frame_len)
26616{
26617 /* check for DPP public action frames */
26618 wl_dpp_pa_frame_t *pact_frm;
26619
26620 if (frame == NULL) {
26621 return false;
26622 }
26623 pact_frm = (wl_dpp_pa_frame_t *)frame;
26624 if (frame_len < sizeof(wl_dpp_pa_frame_t) -1) {
26625 return false;
26626 }
26627
26628 if ((pact_frm->category == WL_PUB_AF_CATEGORY) &&
26629 (pact_frm->action == WL_PUB_AF_ACTION) &&
26630 (pact_frm->oui_type == WL_PUB_AF_WFA_STYPE_DPP) &&
26631 (memcmp(pact_frm->oui, WFA_OUI, sizeof(pact_frm->oui)) == 0)) {
26632 return true;
26633 }
26634
26635 return false;
26636}
26637
26638const char *
26639get_dpp_pa_ftype(enum wl_dpp_ftype ftype)
26640{
26641 switch (ftype) {
26642 case DPP_AUTH_REQ:
26643 return "DPP_AUTH_REQ";
26644 case DPP_AUTH_RESP:
26645 return "DPP_AUTH_RESP";
26646 case DPP_AUTH_CONF:
26647 return "DPP_AUTH_CONF";
26648 default:
26649 return "Unkown DPP frame";
26650 }
26651}
26652
26653#define GAS_RESP_LEN 2
26654#define DOUBLE_TLV_BODY_OFF 4
26655bool wl_cfg80211_find_gas_subtype(u8 subtype, u16 adv_id, u8* data, u32 len)
26656{
26657 const bcm_tlv_t *ie = (bcm_tlv_t *)data;
26658 const u8 *frame = NULL;
26659 u16 id, flen;
26660
26661 /* Skipped first ANQP Element, if frame has anqp elemnt */
26662 ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID);
26663
26664 if (ie == NULL)
26665 return false;
26666
26667 frame = (const uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN;
26668 id = ((u16) (((frame)[1] << 8) | (frame)[0]));
26669 flen = ((u16) (((frame)[3] << 8) | (frame)[2]));
26670
26671 /* If the contents match the OUI and the type */
26672 if ((flen >= WFA_OUI_LEN + 1) &&
26673 (id == adv_id) &&
26674 !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) &&
26675 subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) {
26676 return true;
26677 }
26678
26679 return false;
26680}
26681
26682bool wl_cfg80211_is_dpp_gas_action(void *frame, u32 frame_len)
26683{
26684 wl_dpp_gas_af_t *act_frm = (wl_dpp_gas_af_t *)frame;
26685 u32 len;
26686 const bcm_tlv_t *ie = NULL;
26687
26688 if ((frame_len < (sizeof(wl_dpp_gas_af_t) - 1)) ||
26689 act_frm->category != WL_PUB_AF_CATEGORY) {
26690 return false;
26691 }
26692
26693 len = frame_len - (u32)(sizeof(wl_dpp_gas_af_t) - 1);
26694 if (act_frm->action == WL_PUB_AF_GAS_IREQ) {
26695 ie = (bcm_tlv_t *)act_frm->query_data;
26696 /* We are interested only in MNG ADV ID. Skip any other id. */
26697 ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID);
26698 } else if (act_frm->action == WL_PUB_AF_GAS_IRESP) {
26699 ie = (bcm_tlv_t *)&act_frm->query_data[WL_GAS_RESP_OFFSET];
26700 /* We are interested only in MNG ADV ID. Skip any other id. */
26701 ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID);
26702 } else {
26703 return false;
26704 }
26705
26706 if (ie && (ie->len >= WL_GAS_MIN_LEN) &&
26707 (memcmp(&ie->data[WL_GAS_WFA_OFFSET], WFA_OUI, 3) == 0) &&
26708 (ie->data[WL_GAS_STYPE_OFFSET] == WL_GAS_WFA_STYPE_DPP)) {
26709 WL_DBG(("DPP GAS FRAME. type:%d\n", act_frm->action));
26710 return true;
26711 }
26712
26713 /* Non DPP GAS frame */
26714 return false;
26715}
26716
26717#ifdef KEEP_ALIVE
26718#define KA_TEMP_BUF_SIZE 512
26719#define KA_FRAME_SIZE 300
26720int
26721wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id,
26722 uint16 ether_type, uint8 *ip_pkt, uint16 ip_pkt_len,
26723 uint8* src_mac, uint8* dst_mac, uint32 period_msec)
26724{
26725 const int ETHERTYPE_LEN = 2;
26726 char *pbuf = NULL;
26727 const char *str;
26728 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
26729 wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL;
26730 uint16 buf_len = 0;
26731 u8 str_len = 0;
26732 int res = BCME_ERROR;
26733 uint16 len_bytes = 0;
26734 int i = 0;
26735 uint16 pmac_frame_len = KA_FRAME_SIZE;
26736 uint16 pbuf_len = KA_TEMP_BUF_SIZE;
26737
26738 /* ether frame to have both max IP pkt (256 bytes) and ether header */
26739 char *pmac_frame = NULL;
26740 char *pmac_frame_begin = NULL;
26741 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
26742 struct net_device *primary_ndev = NULL;
26743 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
26744
26745 /*
26746 * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
26747 * dongle shall reject a mkeep_alive request.
26748 */
26749 if (!(dhd->op_mode & DHD_FLAG_STA_MODE))
26750 return res;
26751
26752 WL_TRACE(("%s execution\n", __FUNCTION__));
26753
26754 if ((pbuf = MALLOCZ(cfg->osh, KA_TEMP_BUF_SIZE)) == NULL) {
26755 WL_ERR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE));
26756 res = BCME_NOMEM;
26757 return res;
26758 }
26759
26760 if ((pmac_frame = MALLOCZ(cfg->osh, pmac_frame_len)) == NULL) {
26761 WL_ERR(("failed to allocate mac_frame with size %d\n", pmac_frame_len));
26762 res = BCME_NOMEM;
26763 goto exit;
26764 }
26765 pmac_frame_begin = pmac_frame;
26766
26767 /*
26768 * Get current mkeep-alive status.
26769 */
26770 res = wldev_iovar_getbuf(primary_ndev, "mkeep_alive", &mkeep_alive_id,
26771 sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync);
26772 if (res < 0) {
26773 WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res));
26774 goto exit;
26775 } else {
26776 /* Check available ID whether it is occupied */
26777 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf;
26778 if (dtoh32(mkeep_alive_pktp->period_msec != 0)) {
26779 WL_ERR(("%s: Get mkeep_alive failed, ID %u is in use.\n",
26780 __FUNCTION__, mkeep_alive_id));
26781
26782 /* Current occupied ID info */
26783 WL_ERR(("%s: mkeep_alive\n", __FUNCTION__));
26784 WL_ERR((" Id : %d\n"
26785 " Period: %d msec\n"
26786 " Length: %d\n"
26787 " Packet: 0x",
26788 mkeep_alive_pktp->keep_alive_id,
26789 dtoh32(mkeep_alive_pktp->period_msec),
26790 dtoh16(mkeep_alive_pktp->len_bytes)));
26791
26792 for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) {
26793 WL_ERR(("%02x", mkeep_alive_pktp->data[i]));
26794 }
26795 WL_ERR(("\n"));
26796
26797 res = BCME_NOTFOUND;
26798 goto exit;
26799 }
26800 }
26801
26802 /* Request the specified ID */
26803 bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
26804 bzero(pbuf, KA_TEMP_BUF_SIZE);
26805 str = "mkeep_alive";
26806 str_len = strlen(str);
26807 strlcpy(pbuf, str, KA_TEMP_BUF_SIZE);
26808 buf_len = str_len + 1;
26809 pbuf_len -= buf_len;
26810
26811 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + buf_len);
26812 mkeep_alive_pkt.period_msec = htod32(period_msec);
26813 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
26814 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
26815 len_bytes = (ETHER_ADDR_LEN*2) + ETHERTYPE_LEN + ip_pkt_len;
26816 mkeep_alive_pkt.len_bytes = htod16(len_bytes);
26817
26818 /* ID assigned */
26819 mkeep_alive_pkt.keep_alive_id = mkeep_alive_id;
26820
26821 buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
26822
26823 /*
26824 * Build up Ethernet Frame
26825 */
26826
26827 /* Mapping dest mac addr */
26828 res = memcpy_s(pmac_frame, pmac_frame_len, dst_mac, ETHER_ADDR_LEN);
26829 if (res) {
26830 goto exit;
26831 }
26832 pmac_frame += ETHER_ADDR_LEN;
26833 pmac_frame_len -= ETHER_ADDR_LEN;
26834
26835 /* Mapping src mac addr */
26836 res = memcpy_s(pmac_frame, pmac_frame_len, src_mac, ETHER_ADDR_LEN);
26837 if (res) {
26838 goto exit;
26839 }
26840 pmac_frame += ETHER_ADDR_LEN;
26841 pmac_frame_len -= ETHER_ADDR_LEN;
26842
26843 /* Mapping Ethernet type */
26844 ether_type = hton16(ether_type);
26845 res = memcpy_s(pmac_frame, pmac_frame_len, &ether_type, ETHERTYPE_LEN);
26846 if (res) {
26847 goto exit;
26848 }
26849 pmac_frame += ETHERTYPE_LEN;
26850 pmac_frame_len -= ETHERTYPE_LEN;
26851
26852 /* Mapping IP pkt */
26853 res = memcpy_s(pmac_frame, pmac_frame_len, ip_pkt, ip_pkt_len);
26854 if (res) {
26855 goto exit;
26856 }
26857 pmac_frame += ip_pkt_len;
26858 pmac_frame_len -= ip_pkt_len;
26859
26860 /*
26861 * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
26862 * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
26863 * guarantee that the buffer is properly aligned.
26864 */
26865 res = memcpy_s((char *)mkeep_alive_pktp, pbuf_len,
26866 &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
26867 if (res) {
26868 goto exit;
26869 }
26870 pbuf_len -= WL_MKEEP_ALIVE_FIXED_LEN;
26871
26872 /*
26873 * Length of ether frame (assume to be all hexa bytes)
26874 * = src mac + dst mac + ether type + ip pkt len
26875 */
26876 res = memcpy_s(mkeep_alive_pktp->data, pbuf_len,
26877 pmac_frame_begin, len_bytes);
26878 if (res) {
26879 goto exit;
26880 }
26881 buf_len += len_bytes;
26882
26883 res = wldev_ioctl_set(primary_ndev, WLC_SET_VAR, pbuf, buf_len);
26884exit:
26885 if (pmac_frame_begin) {
26886 MFREE(cfg->osh, pmac_frame_begin, KA_FRAME_SIZE);
26887 }
26888 if (pbuf) {
26889 MFREE(cfg->osh, pbuf, KA_TEMP_BUF_SIZE);
26890 }
26891 return res;
26892}
26893
26894int
26895wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id)
26896{
26897 char *pbuf = NULL;
26898 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
26899 wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL;
26900 int res = BCME_ERROR;
26901 int i = 0;
26902 struct net_device *primary_ndev = NULL;
26903 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
26904 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
26905
26906 /*
26907 * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
26908 * dongle shall reject a mkeep_alive request.
26909 */
26910 if (!(dhd->op_mode & DHD_FLAG_STA_MODE))
26911 return res;
26912
26913 WL_TRACE(("%s execution\n", __FUNCTION__));
26914
26915 /*
26916 * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt.
26917 */
26918 if ((pbuf = MALLOCZ(cfg->osh, KA_TEMP_BUF_SIZE)) == NULL) {
26919 WL_ERR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE));
26920 res = BCME_NOMEM;
26921 return res;
26922 }
26923
26924 res = wldev_iovar_getbuf(primary_ndev, "mkeep_alive", &mkeep_alive_id,
26925 sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync);
26926 if (res < 0) {
26927 WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res));
26928 goto exit;
26929 } else {
26930 /* Check occupied ID */
26931 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf;
26932 WL_DBG(("%s: mkeep_alive\n", __FUNCTION__));
26933 WL_DBG((" Id : %d\n"
26934 " Period: %d msec\n"
26935 " Length: %d\n"
26936 " Packet: 0x",
26937 mkeep_alive_pktp->keep_alive_id,
26938 dtoh32(mkeep_alive_pktp->period_msec),
26939 dtoh16(mkeep_alive_pktp->len_bytes)));
26940
26941 for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) {
26942 WL_DBG(("%02x", mkeep_alive_pktp->data[i]));
26943 }
26944 WL_DBG(("\n"));
26945 }
26946
26947 /* Make it stop if available */
26948 if (dtoh32(mkeep_alive_pktp->period_msec != 0)) {
26949 WL_INFORM_MEM(("stop mkeep_alive on ID %d\n", mkeep_alive_id));
26950 bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
26951
26952 mkeep_alive_pkt.period_msec = 0;
26953 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
26954 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
26955 mkeep_alive_pkt.keep_alive_id = mkeep_alive_id;
26956
26957 res = wldev_iovar_setbuf(primary_ndev, "mkeep_alive",
26958 (char *)&mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN,
26959 pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync);
26960 } else {
26961 WL_ERR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id));
26962 res = BCME_NOTFOUND;
26963 }
26964exit:
26965 if (pbuf) {
26966 MFREE(cfg->osh, pbuf, KA_TEMP_BUF_SIZE);
26967 }
26968 return res;
26969}
26970#endif /* KEEP_ALIVE */
26971
26972s32
26973wl_cfg80211_handle_macaddr_change(struct net_device *dev, u8 *macaddr)
26974{
26975 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
26976 uint8 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
26977 u32 status = TRUE;
26978
26979 if (IS_STA_IFACE(dev->ieee80211_ptr) &&
26980 wl_get_drv_status(cfg, CONNECTED, dev)) {
26981 /* Macaddress change in connected state. The curent
26982 * connection will become invalid. Issue disconnect
26983 * to current AP to let the AP know about link down
26984 */
26985 WL_INFORM_MEM(("macaddr change in connected state. Force disassoc.\n"));
26986 wl_cfg80211_disassoc(dev, WLAN_REASON_DEAUTH_LEAVING);
26987
26988 while ((status = wl_get_drv_status(cfg, CONNECTED, dev)) && wait_cnt) {
26989 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
26990 wait_cnt--;
26991 OSL_SLEEP(50);
26992 }
26993 }
26994 return BCME_OK;
26995}
26996
26997int
26998wl_cfg80211_handle_hang_event(struct net_device *ndev, uint16 hang_reason, uint32 memdump_type)
26999{
27000 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
27001 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
27002
27003 WL_INFORM_MEM(("hang reason = %d, memdump_type =%d\n",
27004 hang_reason, memdump_type));
27005
27006 /* check if pre-registered mac matches the mac from dongle via WLC_E_LINK */
27007 if (wl_get_drv_status(cfg, READY, ndev)) {
27008#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
27009 wl_copy_hang_info_if_falure(ndev,
27010 hang_reason, BCME_NOTFOUND);
27011#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
27012 SUPP_LOG(("Err. hang reason:%d, dump_type:%d\n", hang_reason, memdump_type));
27013 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
27014 /* IF dongle is down due to previous hang or other conditions,
27015 * sending 0ne more hang notification is not needed.
27016 */
27017
27018 if (dhd_query_bus_erros(dhd)) {
27019 return BCME_ERROR;
27020 }
27021 dhd->iface_op_failed = TRUE;
27022#if defined(DHD_FW_COREDUMP)
27023 if (dhd->memdump_enabled) {
27024 dhd->memdump_type = memdump_type;
27025 dhd_bus_mem_dump(dhd);
27026 }
27027#endif /* DHD_FW_COREDUMP */
27028 WL_ERR(("Notify hang event to upper layer \n"));
27029 dhd->hang_reason = hang_reason;
27030 net_os_send_hang_message(ndev);
27031 }
27032
27033 return BCME_OK;
27034}
27035
27036s32
27037wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len)
27038{
27039 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
27040 int ret = 0;
27041 int bytes_written = -1;
27042
27043 sscanf(command, "%*s %d", &cfg->autochannel);
27044
27045 if (cfg->autochannel == 0) {
27046 cfg->best_2g_ch = 0;
27047 cfg->best_5g_ch = 0;
27048 } else if (cfg->autochannel == 2) {
27049 bytes_written = snprintf(command, total_len, "2g=%d 5g=%d",
27050 cfg->best_2g_ch, cfg->best_5g_ch);
27051 WL_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
27052 ret = bytes_written;
27053 }
27054
27055 return ret;
27056}
27057
27058int
27059wl_cfg80211_check_in4way(struct bcm_cfg80211 *cfg,
27060 struct net_device *dev, uint action, enum wl_ext_status status, void *context)
27061{
27062 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
27063 struct wl_security *sec;
27064 s32 bssidx = -1;
27065 int ret = 0, cur_eapol_status, ifidx;
27066 int max_wait_time, max_wait_cnt;
27067 int suppressed = 0;
27068
27069 mutex_lock(&cfg->in4way_sync);
27070 action = action & dhdp->conf->in4way;
27071 WL_DBG(("status=%d, action=0x%x, in4way=0x%x\n", status, action, dhdp->conf->in4way));
27072
27073 cur_eapol_status = dhdp->conf->eapol_status;
27074 switch (status) {
27075 case WL_EXT_STATUS_SCAN:
27076 wldev_ioctl(dev, WLC_GET_SCANSUPPRESS, &suppressed, sizeof(int), false);
27077 if (suppressed) {
27078 WL_ERR(("scan suppressed\n"));
27079 ret = -EBUSY;
27080 break;
27081 }
27082 if (action & NO_SCAN_IN4WAY) {
27083 if (cfg->handshaking > 0 && cfg->handshaking <= 3) {
27084 WL_ERR(("return -EBUSY cnt %d\n", cfg->handshaking));
27085 cfg->handshaking++;
27086 ret = -EBUSY;
27087 break;
27088 }
27089 }
27090 break;
27091 case WL_EXT_STATUS_DISCONNECTING:
27092 if (cur_eapol_status >= EAPOL_STATUS_4WAY_START &&
27093 cur_eapol_status < EAPOL_STATUS_4WAY_DONE) {
27094 WL_ERR(("WPA failed at %d\n", cur_eapol_status));
27095 dhdp->conf->eapol_status = EAPOL_STATUS_NONE;
27096 } else if (cur_eapol_status >= EAPOL_STATUS_WSC_START &&
27097 cur_eapol_status < EAPOL_STATUS_WSC_DONE) {
27098 WL_ERR(("WPS failed at %d\n", cur_eapol_status));
27099 dhdp->conf->eapol_status = EAPOL_STATUS_NONE;
27100 }
27101 if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
27102 if (cfg->handshaking) {
27103 if ((action & NO_BTC_IN4WAY) && cfg->btc_mode) {
27104 WL_TRACE(("status=%d, restore btc_mode %d\n",
27105 status, cfg->btc_mode));
27106 wldev_iovar_setint(dev, "btc_mode", cfg->btc_mode);
27107 }
27108 cfg->handshaking = 0;
27109 }
27110 }
27111 if (action & WAIT_DISCONNECTED) {
27112 max_wait_time = 200;
27113 max_wait_cnt = 20;
27114 cfg->disconnected_jiffies = jiffies;
27115 while (!time_after(jiffies,
27116 cfg->disconnected_jiffies + msecs_to_jiffies(max_wait_time)) &&
27117 max_wait_cnt) {
27118 WL_TRACE(("status=%d, max_wait_cnt=%d waiting...\n",
27119 status, max_wait_cnt));
27120 mutex_unlock(&cfg->in4way_sync);
27121 OSL_SLEEP(50);
27122 mutex_lock(&cfg->in4way_sync);
27123 max_wait_cnt--;
27124 }
27125 wake_up_interruptible(&dhdp->conf->event_complete);
27126 }
27127 break;
27128 case WL_EXT_STATUS_CONNECTING:
27129 if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
27130 bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
27131 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
27132 if ((sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) &&
27133 bssidx == 0) {
27134 dhdp->conf->eapol_status = EAPOL_STATUS_4WAY_START;
27135 cfg->handshaking = 1;
27136 if (action & NO_BTC_IN4WAY) {
27137 ret = wldev_iovar_getint(dev, "btc_mode", &cfg->btc_mode);
27138 if (!ret && cfg->btc_mode) {
27139 WL_TRACE(("status=%d, disable current btc_mode %d\n",
27140 status, cfg->btc_mode));
27141 wldev_iovar_setint(dev, "btc_mode", 0);
27142 }
27143 }
27144 }
27145 }
27146 if (action & WAIT_DISCONNECTED) {
27147 max_wait_time = 200;
27148 max_wait_cnt = 10;
27149 while (!time_after(jiffies,
27150 cfg->disconnected_jiffies + msecs_to_jiffies(max_wait_time)) &&
27151 max_wait_cnt) {
27152 WL_TRACE(("status=%d, max_wait_cnt=%d waiting...\n",
27153 status, max_wait_cnt));
27154 mutex_unlock(&cfg->in4way_sync);
27155 OSL_SLEEP(50);
27156 mutex_lock(&cfg->in4way_sync);
27157 max_wait_cnt--;
27158 }
27159 wake_up_interruptible(&dhdp->conf->event_complete);
27160 }
27161 break;
27162 case WL_EXT_STATUS_CONNECTED:
27163 ifidx = dhd_net2idx(dhdp->info, dev);
27164 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION && ifidx >= 0) {
27165 dhd_conf_set_wme(cfg->pub, ifidx, 0);
27166 wake_up_interruptible(&dhdp->conf->event_complete);
27167 }
27168 else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
27169 dhd_conf_set_mchan_bw(cfg->pub, WL_P2P_IF_CLIENT, -1);
27170 }
27171 break;
27172 case WL_EXT_STATUS_DISCONNECTED:
27173 if (cur_eapol_status >= EAPOL_STATUS_4WAY_START &&
27174 cur_eapol_status < EAPOL_STATUS_4WAY_DONE) {
27175 WL_ERR(("WPA failed at %d\n", cur_eapol_status));
27176 dhdp->conf->eapol_status = EAPOL_STATUS_NONE;
27177 } else if (cur_eapol_status >= EAPOL_STATUS_WSC_START &&
27178 cur_eapol_status < EAPOL_STATUS_WSC_DONE) {
27179 WL_ERR(("WPS failed at %d\n", cur_eapol_status));
27180 dhdp->conf->eapol_status = EAPOL_STATUS_NONE;
27181 }
27182 if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
27183 if (cfg->handshaking) {
27184 if ((action & NO_BTC_IN4WAY) && cfg->btc_mode) {
27185 WL_TRACE(("status=%d, restore btc_mode %d\n",
27186 status, cfg->btc_mode));
27187 wldev_iovar_setint(dev, "btc_mode", cfg->btc_mode);
27188 }
27189 cfg->handshaking = 0;
27190 }
27191 }
27192 if (action & WAIT_DISCONNECTED) {
27193 cfg->disconnected_jiffies = jiffies;
27194 }
27195 wake_up_interruptible(&dhdp->conf->event_complete);
27196 break;
27197 case WL_EXT_STATUS_ADD_KEY:
27198 dhdp->conf->eapol_status = EAPOL_STATUS_4WAY_DONE;
27199 if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
27200 if (cfg->handshaking) {
27201 if ((action & NO_BTC_IN4WAY) && cfg->btc_mode) {
27202 WL_TRACE(("status=%d, restore btc_mode %d\n",
27203 status, cfg->btc_mode));
27204 wldev_iovar_setint(dev, "btc_mode", cfg->btc_mode);
27205 }
27206 cfg->handshaking = 0;
27207 }
27208 }
27209 wake_up_interruptible(&dhdp->conf->event_complete);
27210 break;
27211 case WL_EXT_STATUS_AP_ENABLED:
27212 ifidx = dhd_net2idx(dhdp->info, dev);
27213 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP && ifidx >= 0) {
27214 dhd_conf_set_wme(cfg->pub, ifidx, 1);
27215 }
27216 else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
27217 dhd_conf_set_mchan_bw(cfg->pub, WL_P2P_IF_GO, -1);
27218 }
27219 break;
27220 case WL_EXT_STATUS_DELETE_STA:
27221 if ((action & DONT_DELETE_GC_AFTER_WPS) &&
27222 (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
27223 u8* mac_addr = context;
27224 if (mac_addr && memcmp(&ether_bcast, mac_addr, ETHER_ADDR_LEN) &&
27225 cur_eapol_status == EAPOL_STATUS_WSC_DONE) {
27226 u32 timeout;
27227 max_wait_time = 300;
27228 WL_TRACE(("status=%d, wps_done=%d, waiting %dms ...\n",
27229 status, cfg->wps_done, max_wait_time));
27230 mutex_unlock(&cfg->in4way_sync);
27231 timeout = wait_event_interruptible_timeout(cfg->wps_done_event,
27232 cfg->wps_done, msecs_to_jiffies(max_wait_time));
27233 mutex_lock(&cfg->in4way_sync);
27234 WL_TRACE(("status=%d, wps_done=%d, timeout=%d\n",
27235 status, cfg->wps_done, timeout));
27236 if (timeout > 0) {
27237 ret = -1;
27238 break;
27239 }
27240 } else {
27241 WL_TRACE(("status=%d, wps_done=%d => 0\n", status, cfg->wps_done));
27242 cfg->wps_done = FALSE;
27243 dhdp->conf->eapol_status = EAPOL_STATUS_NONE;
27244 }
27245 }
27246 break;
27247 case WL_EXT_STATUS_STA_DISCONNECTED:
27248 if ((action & DONT_DELETE_GC_AFTER_WPS) &&
27249 (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) &&
27250 cur_eapol_status == EAPOL_STATUS_WSC_DONE) {
27251 WL_TRACE(("status=%d, wps_done=%d => 0\n", status, cfg->wps_done));
27252 cfg->wps_done = FALSE;
27253 }
27254 break;
27255 case WL_EXT_STATUS_STA_CONNECTED:
27256 if ((action & DONT_DELETE_GC_AFTER_WPS) &&
27257 (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) &&
27258 cur_eapol_status == EAPOL_STATUS_WSC_DONE) {
27259 WL_TRACE(("status=%d, wps_done=%d => 1\n", status, cfg->wps_done));
27260 cfg->wps_done = TRUE;
27261 wake_up_interruptible(&cfg->wps_done_event);
27262 }
27263 break;
27264 default:
27265 WL_ERR(("Unknown action=0x%x, status=%d\n", action, status));
27266 }
27267
27268 mutex_unlock(&cfg->in4way_sync);
27269
27270 return ret;
27271}