• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Linux cfg80211 driver
4  *
5  * Copyright (C) 1999-2019, Broadcom.
6  *
7  *      Unless you and Broadcom execute a separate written software license
8  * agreement governing use of this software, this software is licensed to you
9  * under the terms of the GNU General Public License version 2 (the "GPL"),
10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11  * following added to such license:
12  *
13  *      As a special exception, the copyright holders of this software give you
14  * permission to link this software with independent modules, and to copy and
15  * distribute the resulting executable under terms of your choice, provided that
16  * you also meet, for each linked independent module, the terms and conditions of
17  * the license of that module.  An independent module is a module which is not
18  * derived from this software.  The special exception does not apply to any
19  * modifications of the software.
20  *
21  *      Notwithstanding the above, under no circumstances may you combine this
22  * software in any way with any other Broadcom software provided under a license
23  * other than the GPL, without Broadcom's express prior written consent.
24  *
25  *
26  * <<Broadcom-WL-IPTag/Open:>>
27  *
28  * $Id: wl_cfg80211.c 826086 2019-06-18 19:23:59Z $
29  */
30 /* */
31 #include <typedefs.h>
32 #include <linuxver.h>
33 #include <linux/kernel.h>
34 #ifdef CONFIG_AP6XXX_WIFI6_HDF
35 #include "hdf_bdh_event.h"
36 #endif
37 #include <bcmutils.h>
38 #include <bcmstdlib_s.h>
39 #include <bcmwifi_channels.h>
40 #include <bcmendian.h>
41 #include <ethernet.h>
42 #ifdef WL_WPS_SYNC
43 #include <eapol.h>
44 #endif /* WL_WPS_SYNC */
45 #include <802.11.h>
46 #include <bcmiov.h>
47 #include <linux/if_arp.h>
48 #include <linux/uaccess.h>
49 
50 #include <ethernet.h>
51 #include <linux/kernel.h>
52 #include <linux/kthread.h>
53 #include <linux/netdevice.h>
54 #include <linux/sched.h>
55 #include <linux/etherdevice.h>
56 #include <linux/wireless.h>
57 #include <linux/ieee80211.h>
58 #include <linux/wait.h>
59 #include <net/cfg80211.h>
60 #include <net/rtnetlink.h>
61 
62 #include <wlioctl.h>
63 #include <bcmevent.h>
64 #include <wldev_common.h>
65 #include <wl_cfg80211.h>
66 #include <wl_cfgp2p.h>
67 #include <wl_cfgscan.h>
68 #include <bcmdevs.h>
69 #ifdef WL_FILS
70 #include <fils.h>
71 #include <frag.h>
72 #endif /* WL_FILS */
73 #include <wl_android.h>
74 #include <dngl_stats.h>
75 #include <dhd.h>
76 #include <dhd_linux.h>
77 #include <dhd_linux_pktdump.h>
78 #include <dhd_debug.h>
79 #include <dhdioctl.h>
80 #include <wlioctl.h>
81 #include <dhd_cfg80211.h>
82 #include <dhd_bus.h>
83 #ifdef PNO_SUPPORT
84 #include <dhd_pno.h>
85 #endif /* PNO_SUPPORT */
86 #include <wl_cfgvendor.h>
87 
88 #if !defined(WL_VENDOR_EXT_SUPPORT)
89 #undef GSCAN_SUPPORT
90 #endif
91 #include <dhd_config.h>
92 
93 #ifdef WL_NAN
94 #include <wl_cfgnan.h>
95 #endif /* WL_NAN */
96 
97 #ifdef PROP_TXSTATUS
98 #include <dhd_wlfc.h>
99 #endif // endif
100 
101 #ifdef BCMPCIE
102 #include <dhd_flowring.h>
103 #endif // endif
104 #ifdef RTT_SUPPORT
105 #include <dhd_rtt.h>
106 #endif /* RTT_SUPPORT */
107 
108 #define BRCM_SAE_VENDOR_EVENT_BUF_LEN 500
109 
110 #ifdef DNGL_AXI_ERROR_LOGGING
111 #include <bcmtlv.h>
112 #endif /* DNGL_AXI_ERROR_LOGGING */
113 
114 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
115 #include <linux/dev_ril_bridge.h>
116 #include <linux/notifier.h>
117 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
118 
119 #ifdef BCMWAPI_WPI
120 /* these items should evetually go into wireless.h of the linux system headfile dir */
121 #ifndef IW_ENCODE_ALG_SM4
122 #define IW_ENCODE_ALG_SM4 0x20
123 #endif // endif
124 
125 #ifndef IW_AUTH_WAPI_ENABLED
126 #define IW_AUTH_WAPI_ENABLED 0x20
127 #endif // endif
128 
129 #ifndef IW_AUTH_WAPI_VERSION_1
130 #define IW_AUTH_WAPI_VERSION_1  0x00000008
131 #endif // endif
132 
133 #ifndef IW_AUTH_CIPHER_SMS4
134 #define IW_AUTH_CIPHER_SMS4     0x00000020
135 #endif // endif
136 
137 #ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
138 #define IW_AUTH_KEY_MGMT_WAPI_PSK 4
139 #endif // endif
140 
141 #ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
142 #define IW_AUTH_KEY_MGMT_WAPI_CERT 8
143 #endif // endif
144 #endif /* BCMWAPI_WPI */
145 
146 #ifdef BCMWAPI_WPI
147 #define IW_WSEC_ENABLED(wsec)   ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
148 #else /* BCMWAPI_WPI */
149 #define IW_WSEC_ENABLED(wsec)   ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
150 #endif /* BCMWAPI_WPI */
151 
152 #if (defined(WL_FW_OCE_AP_SELECT) || defined(BCMFW_ROAM_ENABLE) && ((LINUX_VERSION_CODE \
153 	>= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)))
154 uint fw_ap_select = true;
155 #else
156 uint fw_ap_select = false;
157 #endif /* WL_FW_OCE_AP_SELECT && (ROAM_ENABLE || BCMFW_ROAM_ENABLE) */
158 module_param(fw_ap_select, uint, 0660);
159 
160 static struct device *cfg80211_parent_dev = NULL;
161 static struct bcm_cfg80211 *g_bcmcfg = NULL;
162 //u32 wl_dbg_level = 0xff;
163 u32 wl_dbg_level = WL_DBG_ERR; // | WL_DBG_P2P_ACTION | WL_DBG_INFO;
164 
165 #define	MAX_VIF_OFFSET	15
166 #define MAX_WAIT_TIME 1500
167 #ifdef WLAIBSS_MCHAN
168 #define IBSS_IF_NAME "ibss%d"
169 #endif /* WLAIBSS_MCHAN */
170 
171 #ifdef VSDB
172 /* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
173 #define DEFAULT_SLEEP_TIME_VSDB		120
174 #define OFF_CHAN_TIME_THRESHOLD_MS	200
175 #define AF_RETRY_DELAY_TIME			40
176 
177 /* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
178 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)	\
179 	do {	\
180 		if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) ||	\
181 			wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {	\
182 			OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB);			\
183 		}	\
184 	} while (0)
185 #else /* VSDB */
186 /* if not VSDB, do nothing */
187 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
188 #endif /* VSDB */
189 
190 #define DNGL_FUNC(func, parameters) func parameters
191 #define COEX_DHCP
192 
193 #define WLAN_EID_SSID	0
194 #define CH_MIN_5G_CHANNEL 34
195 
196 #ifdef WL_RELMCAST
197 enum rmc_event_type {
198 	RMC_EVENT_NONE,
199 	RMC_EVENT_LEADER_CHECK_FAIL
200 };
201 #endif /* WL_RELMCAST */
202 
203 #ifdef CONFIG_AP6XXX_WIFI6_HDF
204 #include "hdf_wl_interface.h"
205 #include "net_device.h"
206 int32_t HdfWifiEventMgmtTxStatus(const struct NetDevice *netDev, const uint8_t *buf, size_t len, uint8_t ack);
207 int32_t HdfWifiEventRxMgmt(const struct NetDevice *netDev, int32_t freq, int32_t sigMbm, const uint8_t *buf, size_t len);
208 int32_t HdfWifiEventCsaChannelSwitch(const struct NetDevice *netDev, int32_t freq);
209 int32_t HdfWifiEventRemainOnChannel(const struct NetDevice *netDev, uint32_t freq, uint32_t duration);
210 
211 struct NetDevice * GetHdfNetDeviceByLinuxInf(struct net_device *dev);
212 
213 int ChangNewSta(struct net_device *dev, const uint8_t *macAddr, uint8_t addrLen,
214     const struct station_info *info);
215 int ChangDelSta(struct net_device *dev,const uint8_t *macAddr, uint8_t addrLen);
216 extern void HdfInformBssFrameEventCallback(struct net_device *ndev, const struct InnerBssInfo *innerBssInfo);
217 extern int32_t HdfConnectResultEventCallback(struct net_device *ndev, const struct InnerConnetResult *innerConnResult);
218 
219 extern int g_event_ifidx;
220 extern struct hdf_inf_map g_hdf_infmap[HDF_INF_MAX];
221 struct NetDevice * get_hdf_netdev(int ifidx);
222 extern int g_mgmt_tx_event_ifidx;
223 
224 #endif
225 
226 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
227  * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
228  * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
229  * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
230  * All the chnages in world regulatory domain are to be done here.
231  *
232  * this definition reuires disabling missing-field-initializer warning
233  * as the ieee80211_regdomain definition differs in plain linux and in Android
234  */
235 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
236 	4 && __GNUC_MINOR__ >= 6))
237 _Pragma("GCC diagnostic push")
238 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
239 #endif // endif
240 static const struct ieee80211_regdomain brcm_regdom = {
241 	.n_reg_rules = 4,
242 	.alpha2 =  "99",
243 	.reg_rules = {
244 		/* IEEE 802.11b/g, channels 1..11 */
245 		REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
246 		/* If any */
247 		/* IEEE 802.11 channel 14 - Only JP enables
248 		 * this and for 802.11b only
249 		 */
250 		REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
251 		/* IEEE 802.11a, channel 36..64 */
252 		REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
253 		/* IEEE 802.11a, channel 100..165 */
254 		REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
255 };
256 
257 #ifdef CONFIG_AP6XXX_WIFI6_HDF
bdh6_get_regdomain(void)258 const struct ieee80211_regdomain * bdh6_get_regdomain(void)
259 {
260     return &brcm_regdom;
261 }
262 #endif
263 
264 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
265 	4 && __GNUC_MINOR__ >= 6))
266 _Pragma("GCC diagnostic pop")
267 #endif // endif
268 
269 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
270 	(defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
271 static const struct ieee80211_iface_limit common_if_limits[] = {
272 	{
273 	/*
274 	 * Driver can support up to 2 AP's
275 	 */
276 	.max = 2,
277 	.types = BIT(NL80211_IFTYPE_AP),
278 	},
279 	{
280 	/*
281 	 * During P2P-GO removal, P2P-GO is first changed to STA and later only
282 	 * removed. So setting maximum possible number of STA interfaces according
283 	 * to kernel version.
284 	 *
285 	 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
286 	 * linux-3.8 and above - max:4
287 	 * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
288 	 * for NAN defined, registering it as STA type)
289 	 */
290 #ifdef WL_ENABLE_P2P_IF
291 	.max = 5,
292 #else
293 	.max = 4,
294 #endif /* WL_ENABLE_P2P_IF */
295 	.types = BIT(NL80211_IFTYPE_STATION),
296 	},
297 	{
298 	.max = 2,
299 	.types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
300 	},
301 #if defined(WL_CFG80211_P2P_DEV_IF)
302 	{
303 	.max = 1,
304 	.types = BIT(NL80211_IFTYPE_P2P_DEVICE),
305 	},
306 #endif /* WL_CFG80211_P2P_DEV_IF */
307 	{
308 	.max = 1,
309 	.types = BIT(NL80211_IFTYPE_ADHOC),
310 	},
311 };
312 
313 #define NUM_DIFF_CHANNELS 2
314 
315 static const struct ieee80211_iface_combination
316 common_iface_combinations[] = {
317 	{
318 	.num_different_channels = NUM_DIFF_CHANNELS,
319 	/*
320 	 * At Max 5 network interfaces can be registered concurrently
321 	 */
322 	.max_interfaces = IFACE_MAX_CNT,
323 	.limits = common_if_limits,
324 	.n_limits = ARRAY_SIZE(common_if_limits),
325 	},
326 };
327 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
328 
329 static const char *wl_if_state_strs[WL_IF_STATE_MAX + 1] = {
330 	"WL_IF_CREATE_REQ",
331 	"WL_IF_CREATE_DONE",
332 	"WL_IF_DELETE_REQ",
333 	"WL_IF_DELETE_DONE",
334 	"WL_IF_CHANGE_REQ",
335 	"WL_IF_CHANGE_DONE",
336 	"WL_IF_STATE_MAX"
337 };
338 
339 #ifdef BCMWAPI_WPI
340 #if defined(ANDROID_PLATFORM_VERSION) && (ANDROID_PLATFORM_VERSION >= 8)
341 /* WAPI define in ieee80211.h is used */
342 #else
343 #undef WLAN_AKM_SUITE_WAPI_PSK
344 #define WLAN_AKM_SUITE_WAPI_PSK         0x000FAC04
345 
346 #undef WLAN_AKM_SUITE_WAPI_CERT
347 #define WLAN_AKM_SUITE_WAPI_CERT        0x000FAC12
348 
349 #undef NL80211_WAPI_VERSION_1
350 #define NL80211_WAPI_VERSION_1			1 << 2
351 #endif /* ANDROID_PLATFORM_VERSION && ANDROID_PLATFORM_VERSION >= 8 */
352 #endif /* BCMWAPI_WPI */
353 
354 /* Data Element Definitions */
355 #define WPS_ID_CONFIG_METHODS     0x1008
356 #define WPS_ID_REQ_TYPE           0x103A
357 #define WPS_ID_DEVICE_NAME        0x1011
358 #define WPS_ID_VERSION            0x104A
359 #define WPS_ID_DEVICE_PWD_ID      0x1012
360 #define WPS_ID_REQ_DEV_TYPE       0x106A
361 #define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
362 #define WPS_ID_PRIM_DEV_TYPE      0x1054
363 
364 /* Device Password ID */
365 #define DEV_PW_DEFAULT 0x0000
366 #define DEV_PW_USER_SPECIFIED 0x0001,
367 #define DEV_PW_MACHINE_SPECIFIED 0x0002
368 #define DEV_PW_REKEY 0x0003
369 #define DEV_PW_PUSHBUTTON 0x0004
370 #define DEV_PW_REGISTRAR_SPECIFIED 0x0005
371 
372 /* Config Methods */
373 #define WPS_CONFIG_USBA 0x0001
374 #define WPS_CONFIG_ETHERNET 0x0002
375 #define WPS_CONFIG_LABEL 0x0004
376 #define WPS_CONFIG_DISPLAY 0x0008
377 #define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
378 #define WPS_CONFIG_INT_NFC_TOKEN 0x0020
379 #define WPS_CONFIG_NFC_INTERFACE 0x0040
380 #define WPS_CONFIG_PUSHBUTTON 0x0080
381 #define WPS_CONFIG_KEYPAD 0x0100
382 #define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
383 #define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
384 #define WPS_CONFIG_VIRT_DISPLAY 0x2008
385 #define WPS_CONFIG_PHY_DISPLAY 0x4008
386 
387 #define PM_BLOCK 1
388 #define PM_ENABLE 0
389 
390 /* GCMP crypto supported above kernel v4.0 */
391 #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0))
392 #define WL_GCMP
393 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0) */
394 
395 #ifndef IBSS_COALESCE_ALLOWED
396 #define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT
397 #endif // endif
398 
399 #ifndef IBSS_INITIAL_SCAN_ALLOWED
400 #define IBSS_INITIAL_SCAN_ALLOWED IBSS_INITIAL_SCAN_ALLOWED_DEFAULT
401 #endif // endif
402 
403 #define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
404 #define LONG_LISTEN_TIME 2000
405 
406 #ifdef RTT_SUPPORT
407 static s32 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
408 		const wl_event_msg_t *e, void *data);
409 #endif /* RTT_SUPPORT */
410 #ifdef WL_CHAN_UTIL
411 static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg,
412 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
413 static s32 wl_cfg80211_start_bssload_report(struct net_device *ndev);
414 #endif /* WL_CHAN_UTIL */
415 
416 #ifdef SUPPORT_AP_RADIO_PWRSAVE
417 #define RADIO_PWRSAVE_PPS					10
418 #define RADIO_PWRSAVE_QUIET_TIME			10
419 #define RADIO_PWRSAVE_LEVEL				3
420 #define RADIO_PWRSAVE_STAS_ASSOC_CHECK	0
421 
422 #define RADIO_PWRSAVE_LEVEL_MIN				1
423 #define RADIO_PWRSAVE_LEVEL_MAX				9
424 #define RADIO_PWRSAVE_PPS_MIN					1
425 #define RADIO_PWRSAVE_QUIETTIME_MIN			1
426 #define RADIO_PWRSAVE_ASSOCCHECK_MIN		0
427 #define RADIO_PWRSAVE_ASSOCCHECK_MAX		1
428 
429 #define RADIO_PWRSAVE_MAJOR_VER 1
430 #define RADIO_PWRSAVE_MINOR_VER 1
431 #define RADIO_PWRSAVE_MAJOR_VER_SHIFT 8
432 #define RADIO_PWRSAVE_VERSION \
433 	((RADIO_PWRSAVE_MAJOR_VER << RADIO_PWRSAVE_MAJOR_VER_SHIFT)| RADIO_PWRSAVE_MINOR_VER)
434 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
435 
436 /* SoftAP related parameters */
437 #define DEFAULT_2G_SOFTAP_CHANNEL	1
438 #define DEFAULT_5G_SOFTAP_CHANNEL	149
439 #define WL_MAX_NUM_CSA_COUNTERS		255
440 
441 #define MAX_VNDR_OUI_STR_LEN	256u
442 #define VNDR_OUI_STR_LEN	10u
443 #define DOT11_DISCONNECT_RC     2u
444 static const uchar *exclude_vndr_oui_list[] = {
445 	"\x00\x50\xf2",			/* Microsoft */
446 	"\x00\x00\xf0",			/* Samsung Elec */
447 	WFA_OUI,			/* WFA */
448 	NULL
449 };
450 
451 typedef struct wl_vndr_oui_entry {
452 	uchar oui[DOT11_OUI_LEN];
453 	struct list_head list;
454 } wl_vndr_oui_entry_t;
455 
456 #if defined(WL_DISABLE_HE_SOFTAP) || defined(WL_DISABLE_HE_P2P) || \
457 	defined(SUPPORT_AP_BWCTRL)
458 #define WL_HE_FEATURES_HE_AP		0x8
459 #define WL_HE_FEATURES_HE_P2P		0x20
460 #endif // endif
461 
462 static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
463 		struct net_device *ndev, char *vndr_oui, u32 vndr_oui_len);
464 static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg);
465 static s32 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
466 		struct parsed_vndr_ies *vndr_ies);
467 
468 #if defined(WL_FW_OCE_AP_SELECT)
469 static bool
470 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
471 
472 /* Check whether the given IE looks like WFA OCE IE. */
473 #define wl_cfgoce_is_oce_ie(ie, tlvs, len)      wl_cfgoce_has_ie(ie, tlvs, len, \
474 	(const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_MBO_OCE)
475 
476 /* Is any of the tlvs the expected entry? If
477  * not update the tlvs buffer pointer/length.
478  */
479 static bool
wl_cfgoce_has_ie(const u8 * ie,const u8 ** tlvs,u32 * tlvs_len,const u8 * oui,u32 oui_len,u8 type)480 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
481 {
482 	/* If the contents match the OUI and the type */
483 	if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
484 			!bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
485 			type == ie[TLV_BODY_OFF + oui_len]) {
486 		return TRUE;
487 	}
488 
489 	return FALSE;
490 }
491 #endif /* WL_FW_OCE_AP_SELECT */
492 
493 /*
494  * cfg80211_ops api/callback list
495  */
496 static s32 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
497 	const struct ether_addr *da, const struct ether_addr *sa,
498 	const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody);
499 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
500 #ifdef WLAIBSS_MCHAN
501 static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name);
502 static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
503 #endif /* WLAIBSS_MCHAN */
504 static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
505 	struct cfg80211_ibss_params *params);
506 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
507 	struct net_device *dev);
508 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
509 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
510 	struct net_device *dev, const u8 *mac,
511 	struct station_info *sinfo);
512 #else
513 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
514 	struct net_device *dev, u8 *mac,
515 	struct station_info *sinfo);
516 #endif // endif
517 static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
518 	struct net_device *dev, bool enabled,
519 	s32 timeout);
520 #ifndef CONFIG_AP6XXX_WIFI6_HDF
521 static
522 #endif
523 int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
524 	struct cfg80211_connect_params *sme);
525 #if defined(WL_FILS)
526 static int wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
527 	struct cfg80211_connect_params *sme, u32 changed);
528 #endif /* WL_FILS */
529 #ifndef CONFIG_AP6XXX_WIFI6_HDF
530 static
531 #endif
532 s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
533 	u16 reason_code);
534 #if defined(WL_CFG80211_P2P_DEV_IF)
535 static s32
536 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
537 	enum nl80211_tx_power_setting type, s32 mbm);
538 #else
539 static s32
540 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
541 	enum nl80211_tx_power_setting type, s32 dbm);
542 #endif /* WL_CFG80211_P2P_DEV_IF */
543 #if defined(WL_CFG80211_P2P_DEV_IF)
544 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
545 	struct wireless_dev *wdev, s32 *dbm);
546 #else
547 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
548 #endif /* WL_CFG80211_P2P_DEV_IF */
549 static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
550 	struct net_device *dev,
551 	u8 key_idx, bool unicast, bool multicast);
552 static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
553 	u8 key_idx, bool pairwise, const u8 *mac_addr,
554 	struct key_params *params);
555 static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
556 	u8 key_idx, bool pairwise, const u8 *mac_addr);
557 static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
558 	u8 key_idx, bool pairwise, const u8 *mac_addr,
559 	void *cookie, void (*callback) (void *cookie,
560 	struct key_params *params));
561 static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
562 	struct net_device *dev,	u8 key_idx);
563 static s32 wl_cfg80211_resume(struct wiphy *wiphy);
564 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
565 	2, 0))
566 static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
567 	bcm_struct_cfgdev *cfgdev, u64 cookie);
568 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
569 static s32 wl_cfg80211_del_station(
570 		struct wiphy *wiphy, struct net_device *ndev,
571 		struct station_del_parameters *params);
572 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
573 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
574 	struct net_device *ndev, const u8* mac_addr);
575 #else
576 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
577 	struct net_device *ndev, u8* mac_addr);
578 #endif // endif
579 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
580 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
581 	struct net_device *dev, const u8 *mac, struct station_parameters *params);
582 #else
583 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
584 	struct net_device *dev, u8 *mac, struct station_parameters *params);
585 #endif // endif
586 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
587 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
588 static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
589 #else
590 static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
591 #endif // endif
592 static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
593 	struct cfg80211_pmksa *pmksa);
594 static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
595 	struct cfg80211_pmksa *pmksa);
596 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
597 	struct net_device *dev);
598 #ifdef WL_CLIENT_SAE
599 static bool wl_is_pmkid_available(struct net_device *dev, const u8 *bssid);
600 #endif /* WL_CLIENT_SAE */
601 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
602 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
603 	KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
604 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
605 	u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
606 	u32 peer_capability, const u8 *buf, size_t len);
607 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
608 		(LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
609 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
610 	const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
611 	u32 peer_capability, const u8 *buf, size_t len);
612 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
613 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
614        const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
615        u32 peer_capability, bool initiator, const u8 *buf, size_t len);
616 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
617 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
618 	u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
619 	const u8 *buf, size_t len);
620 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
621 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
622 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
623 	const u8 *peer, enum nl80211_tdls_operation oper);
624 #else
625 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
626 	u8 *peer, enum nl80211_tdls_operation oper);
627 #endif // endif
628 #endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
629 static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg, struct net_device *dev);
630 
631 struct wireless_dev *
632 wl_cfg80211_create_iface(struct wiphy *wiphy, wl_iftype_t
633 	iface_type, u8 *mac_addr, const char *name);
634 s32
635 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
636 
637 s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
638 	struct net_device *ndev, s32 bsscfg_idx,
639 	wl_iftype_t iftype, s32 del, u8 *addr);
640 s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
641 	struct net_device *ndev, s32 bsscfg_idx,
642 	wl_iftype_t brcm_iftype, s32 del, u8 *addr);
643 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
644 static s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev);
645 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */
646 #ifdef GTK_OFFLOAD_SUPPORT
647 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
648 static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
649 	struct cfg80211_gtk_rekey_data *data);
650 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
651 #endif /* GTK_OFFLOAD_SUPPORT */
652 chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
653 chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
654 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev);
655 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
656 int wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
657         struct cfg80211_csa_settings *params);
658 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
659 
660 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
661 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
662         const struct cfg80211_pmk_conf *conf);
663 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
664         const u8 *aa);
665 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
666 
667 /*
668  * event & event Q handlers for cfg80211 interfaces
669  */
670 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
671 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
672 static void wl_event_handler(struct work_struct *work_data);
673 static void wl_init_eq(struct bcm_cfg80211 *cfg);
674 static void wl_flush_eq(struct bcm_cfg80211 *cfg);
675 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
676 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
677 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
678 static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
679 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
680 static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
681 	const wl_event_msg_t *msg, void *data);
682 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e);
683 static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
684 	const wl_event_msg_t *e, void *data);
685 static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
686 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
687 static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
688 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
689 static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
690 	const wl_event_msg_t *e, void *data, bool completed);
691 static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
692 	const wl_event_msg_t *e, void *data);
693 static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
694 	const wl_event_msg_t *e, void *data);
695 #ifdef BT_WIFI_HANDOVER
696 static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
697 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
698 #endif /* BT_WIFI_HANDOVER */
699 #ifdef GSCAN_SUPPORT
700 static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
701 	const wl_event_msg_t *e, void *data);
702 #endif /* GSCAN_SUPPORT */
703 #ifdef RSSI_MONITOR_SUPPORT
704 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
705 	const wl_event_msg_t *e, void *data);
706 #endif /* RSSI_MONITOR_SUPPORT */
707 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
708 	enum wl_status state, bool set);
709 #ifdef CUSTOM_EVENT_PM_WAKE
710 static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
711 	const wl_event_msg_t *e, void *data);
712 #endif	/* CUSTOM_EVENT_PM_WAKE */
713 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
714 static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
715 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
716 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
717 #ifdef DHD_LOSSLESS_ROAMING
718 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
719 #endif /* DHD_LOSSLESS_ROAMING */
720 
721 #ifdef WL_MBO
722 static s32
723 wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
724 	const wl_event_msg_t *e, void *data);
725 #endif /* WL_MBO */
726 
727 #ifdef WL_CLIENT_SAE
728 static s32 wl_notify_connect_status_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
729 	const wl_event_msg_t *e, void *data);
730 static s32 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
731 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
732 static s32 wl_cfg80211_external_auth(struct wiphy *wiphy,
733 	struct net_device *dev, struct cfg80211_external_auth_params *ext_auth);
734 #endif /* WL_CLIENT_SAE */
735 
736 /*
737  * register/deregister parent device
738  */
739 static void wl_cfg80211_clear_parent_dev(void);
740 /*
741  * ioctl utilites
742  */
743 
744 /*
745  * cfg80211 set_wiphy_params utilities
746  */
747 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
748 static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
749 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
750 
751 /*
752  * cfg profile utilities
753  */
754 static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
755 	const wl_event_msg_t *e, const void *data, s32 item);
756 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
757 
758 /*
759  * cfg80211 connect utilites
760  */
761 static s32 wl_set_wpa_version(struct net_device *dev,
762 	struct cfg80211_connect_params *sme);
763 static s32 wl_set_auth_type(struct net_device *dev,
764 	struct cfg80211_connect_params *sme);
765 static s32 wl_set_set_cipher(struct net_device *dev,
766 	struct cfg80211_connect_params *sme);
767 static s32 wl_set_key_mgmt(struct net_device *dev,
768 	struct cfg80211_connect_params *sme);
769 static s32 wl_set_set_sharedkey(struct net_device *dev,
770 	struct cfg80211_connect_params *sme);
771 #ifdef WL_FILS
772 static s32 wl_set_fils_params(struct net_device *dev,
773 	struct cfg80211_connect_params *sme);
774 #endif // endif
775 #ifdef BCMWAPI_WPI
776 static s32 wl_set_set_wapi_ie(struct net_device *dev,
777 	struct cfg80211_connect_params *sme);
778 #endif // endif
779 #ifdef WL_GCMP
780 static s32 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask);
781 #endif /* WL_GCMP */
782 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
783 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch,
784 	struct wl_join_params *join_params, size_t *join_params_size);
785 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
786 
787 /*
788  * information element utilities
789  */
790 static void wl_rst_ie(struct bcm_cfg80211 *cfg);
791 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
792 static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 *ie_size,
793 	bool update_ssid);
794 static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size);
795 static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size);
796 static u32 wl_get_ielen(struct bcm_cfg80211 *cfg);
797 #ifdef MFP
798 static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie, const u8** rsn_cap);
799 #endif // endif
800 
801 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, dhd_pub_t *data);
802 static void wl_free_wdev(struct bcm_cfg80211 *cfg);
803 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
804 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
805 static int
806 #else
807 static void
808 #endif /* kernel version < 3.10.11 */
809 wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
810 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
811 
812 static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool update_ssid);
813 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool update_ssid);
814 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
815 s32 wl_cfg80211_channel_to_freq(u32 channel);
816 static void wl_cfg80211_work_handler(struct work_struct *work);
817 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
818 	u8 key_idx, const u8 *mac_addr,
819 	struct key_params *params);
820 /*
821  * key indianess swap utilities
822  */
823 static void swap_key_from_BE(struct wl_wsec_key *key);
824 static void swap_key_to_BE(struct wl_wsec_key *key);
825 
826 /*
827  * bcm_cfg80211 memory init/deinit utilities
828  */
829 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
830 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
831 
832 static void wl_delay(u32 ms);
833 
834 /*
835  * ibss mode utilities
836  */
837 static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev);
838 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
839 
840 /*
841  * link up/down , default configuration utilities
842  */
843 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
844 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
845 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
846 
847 static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
848 	struct net_device *ndev);
849 static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
850 static void wl_link_up(struct bcm_cfg80211 *cfg);
851 static void wl_link_down(struct bcm_cfg80211 *cfg);
852 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype);
853 static void wl_init_conf(struct wl_conf *conf);
854 int wl_cfg80211_get_ioctl_version(void);
855 
856 /*
857  * find most significant bit set
858  */
859 static __used u32 wl_find_msb(u16 bit16);
860 
861 /*
862  * rfkill support
863  */
864 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
865 static int wl_rfkill_set(void *data, bool blocked);
866 #ifdef DEBUGFS_CFG80211
867 static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg);
868 static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg);
869 #endif // endif
870 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
871 
872 #ifdef WL_CFG80211_ACL
873 /* ACL */
874 static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
875 	const struct cfg80211_acl_data *acl);
876 #endif /* WL_CFG80211_ACL */
877 
878 /*
879  * Some external functions, TODO: move them to dhd_linux.h
880  */
881 int dhd_add_monitor(const char *name, struct net_device **new_ndev);
882 int dhd_del_monitor(struct net_device *ndev);
883 int dhd_monitor_init(void *dhd_pub);
884 int dhd_monitor_uninit(void);
885 netdev_tx_t dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
886 
887 #ifdef ESCAN_CHANNEL_CACHE
888 void reset_roam_cache(struct bcm_cfg80211 *cfg);
889 void add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi);
890 int  get_roam_channel_list(int target_chan, chanspec_t *channels,
891 	int n_channels, const wlc_ssid_t *ssid, int ioctl_ver);
892 void set_roam_band(int band);
893 #endif /* ESCAN_CHANNEL_CACHE */
894 
895 #ifdef ROAM_CHANNEL_CACHE
896 int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
897 void print_roam_cache(struct bcm_cfg80211 *cfg);
898 void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
899 #endif /* ROAM_CHANNEL_CACHE */
900 
901 #ifdef P2P_LISTEN_OFFLOADING
902 s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
903 #endif /* P2P_LISTEN_OFFLOADING */
904 
905 #ifdef PKT_FILTER_SUPPORT
906 extern uint dhd_pkt_filter_enable;
907 extern uint dhd_master_mode;
908 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
909 #endif /* PKT_FILTER_SUPPORT */
910 
911 #ifdef SUPPORT_SET_CAC
912 static void wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable);
913 #endif /* SUPPORT_SET_CAC */
914 
915 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
916 	const struct ether_addr *bssid);
917 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
918 
919 #ifdef WL_WPS_SYNC
920 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg);
921 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg);
922 static void wl_wps_reauth_timeout(unsigned long data);
923 static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg);
924 static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev);
925 static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *peer_mac);
926 static void wl_wps_session_del(struct net_device *ndev);
927 static s32 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac);
928 static void wl_wps_handle_ifdel(struct net_device *ndev);
929 #endif /* WL_WPS_SYNC */
930 
931 #if defined(WL_FW_OCE_AP_SELECT)
932 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint);
933 #endif /* WL_FW_OCE_AP_SELECT */
934 
935 #ifdef WL_BCNRECV
936 static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
937 		const wl_event_msg_t *e, void *data);
938 #endif /* WL_BCNRECV */
939 
940 #ifdef WL_CAC_TS
941 static s32 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
942 		const wl_event_msg_t *e, void *data);
943 #endif /* WL_CAC_TS */
944 
945 #if defined(WL_MBO) || defined(WL_OCE)
946 static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
947 		const wl_event_msg_t *e, void *data);
948 #endif /* WL_MBO || WL_OCE */
949 
950 static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ,
951 	WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ };
952 
953 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || (defined(CONFIG_ARCH_MSM) && \
954 	defined(CFG80211_DISCONNECTED_V2))
955 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
956 	cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len,	\
957 			IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
958 #else
959 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
960 	cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len,	\
961 			WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
962 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
963 
964 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
965 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
966 	defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || defined(WL_FILS) || \
967 	defined(CONFIG_CFG80211_FILS_BKPORT)
968 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
969 		resp_ie_len, status, gfp) \
970 	cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
971 		resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
972 #else
973 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
974 		resp_ie_len, status, gfp) \
975 	cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
976 		resp_ie_len, status, gfp);
977 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
978 	* (CFG80211_CONNECT_TIMEOUT_REASON_CODE) ||
979 	* WL_FILS || CONFIG_CFG80211_FILS_BKPORT
980 	*/
981 #elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
982 /* There are customer kernels with backported changes for
983  *  connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
984  * is available for kernels < 4.7 in such cases.
985  */
986 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
987 		resp_ie_len, status, gfp) \
988 	cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
989 		resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
990 #else
991 /* Kernels < 4.7 doesn't support cfg80211_connect_bss */
992 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
993 		resp_ie_len, status, gfp) \
994 	cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
995 		resp_ie_len, status, gfp);
996 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
997 
998 #define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE ||			\
999 				 (akm) == RSN_AKM_UNSPECIFIED ||	\
1000 				 (akm) == RSN_AKM_PSK)
1001 
1002 extern int dhd_wait_pend8021x(struct net_device *dev);
1003 #ifdef PROP_TXSTATUS_VSDB
1004 extern int disable_proptx;
1005 #endif /* PROP_TXSTATUS_VSDB */
1006 
1007 static s32
1008 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1009 	const wl_event_msg_t *e, void *data);
1010 static s32
1011 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1012 	const wl_event_msg_t *e, void *data);
1013 #ifdef SUPPORT_AP_BWCTRL
1014 static void
1015 wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg, struct net_device *ndev, chanspec_t chanspec);
1016 static void
1017 wl_restore_ap_bw(struct bcm_cfg80211 *cfg);
1018 #endif /* SUPPORT_AP_BWCTRL */
1019 
1020 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \
1021 	0)))
1022 struct chan_info {
1023 	int freq;
1024 	int chan_type;
1025 };
1026 #endif // endif
1027 
1028 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
1029 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(wiphy, bss);
1030 #else
1031 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(bss);
1032 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
1033 
1034 #define CHAN2G(_channel, _freq, _flags) {			\
1035 	.band			= IEEE80211_BAND_2GHZ,		\
1036 	.center_freq		= (_freq),			\
1037 	.hw_value		= (_channel),			\
1038 	.flags			= (_flags),			\
1039 	.max_antenna_gain	= 0,				\
1040 	.max_power		= 30,				\
1041 }
1042 
1043 #define CHAN5G(_channel, _flags) {				\
1044 	.band			= IEEE80211_BAND_5GHZ,		\
1045 	.center_freq		= 5000 + (5 * (_channel)),	\
1046 	.hw_value		= (_channel),			\
1047 	.flags			= (_flags),			\
1048 	.max_antenna_gain	= 0,				\
1049 	.max_power		= 30,				\
1050 }
1051 
1052 #define RATE_TO_BASE100KBPS(rate)   (((rate) * 10) / 2)
1053 #define RATETAB_ENT(_rateid, _flags) \
1054 	{								\
1055 		.bitrate	= RATE_TO_BASE100KBPS(_rateid),     \
1056 		.hw_value	= (_rateid),			    \
1057 		.flags	  = (_flags),			     \
1058 	}
1059 
1060 static struct ieee80211_rate __wl_rates[] = {
1061 	RATETAB_ENT(DOT11_RATE_1M, 0),
1062 	RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
1063 	RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
1064 	RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
1065 	RATETAB_ENT(DOT11_RATE_6M, 0),
1066 	RATETAB_ENT(DOT11_RATE_9M, 0),
1067 	RATETAB_ENT(DOT11_RATE_12M, 0),
1068 	RATETAB_ENT(DOT11_RATE_18M, 0),
1069 	RATETAB_ENT(DOT11_RATE_24M, 0),
1070 	RATETAB_ENT(DOT11_RATE_36M, 0),
1071 	RATETAB_ENT(DOT11_RATE_48M, 0),
1072 	RATETAB_ENT(DOT11_RATE_54M, 0)
1073 };
1074 
1075 #define wl_a_rates		(__wl_rates + 4)
1076 #define wl_a_rates_size	8
1077 #define wl_g_rates		(__wl_rates + 0)
1078 #define wl_g_rates_size	12
1079 
1080 static struct ieee80211_channel __wl_2ghz_channels[] = {
1081 	CHAN2G(1, 2412, 0),
1082 	CHAN2G(2, 2417, 0),
1083 	CHAN2G(3, 2422, 0),
1084 	CHAN2G(4, 2427, 0),
1085 	CHAN2G(5, 2432, 0),
1086 	CHAN2G(6, 2437, 0),
1087 	CHAN2G(7, 2442, 0),
1088 	CHAN2G(8, 2447, 0),
1089 	CHAN2G(9, 2452, 0),
1090 	CHAN2G(10, 2457, 0),
1091 	CHAN2G(11, 2462, 0),
1092 	CHAN2G(12, 2467, 0),
1093 	CHAN2G(13, 2472, 0),
1094 	CHAN2G(14, 2484, 0)
1095 };
1096 
1097 static struct ieee80211_channel __wl_5ghz_a_channels[] = {
1098 	CHAN5G(34, 0), CHAN5G(36, 0),
1099 	CHAN5G(38, 0), CHAN5G(40, 0),
1100 	CHAN5G(42, 0), CHAN5G(44, 0),
1101 	CHAN5G(46, 0), CHAN5G(48, 0),
1102 	CHAN5G(52, 0), CHAN5G(56, 0),
1103 	CHAN5G(60, 0), CHAN5G(64, 0),
1104 	CHAN5G(100, 0), CHAN5G(104, 0),
1105 	CHAN5G(108, 0), CHAN5G(112, 0),
1106 	CHAN5G(116, 0), CHAN5G(120, 0),
1107 	CHAN5G(124, 0), CHAN5G(128, 0),
1108 	CHAN5G(132, 0), CHAN5G(136, 0),
1109 	CHAN5G(140, 0), CHAN5G(144, 0),
1110 	CHAN5G(149, 0), CHAN5G(153, 0),
1111 	CHAN5G(157, 0), CHAN5G(161, 0),
1112 	CHAN5G(165, 0)
1113 };
1114 
1115 static struct ieee80211_supported_band __wl_band_2ghz = {
1116 	.band = IEEE80211_BAND_2GHZ,
1117 	.channels = __wl_2ghz_channels,
1118 	.n_channels = ARRAY_SIZE(__wl_2ghz_channels),
1119 	.bitrates = wl_g_rates,
1120 	.n_bitrates = wl_g_rates_size
1121 };
1122 
1123 static struct ieee80211_supported_band __wl_band_5ghz_a = {
1124 	.band = IEEE80211_BAND_5GHZ,
1125 	.channels = __wl_5ghz_a_channels,
1126 	.n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
1127 	.bitrates = wl_a_rates,
1128 	.n_bitrates = wl_a_rates_size
1129 };
1130 
1131 static const u32 __wl_cipher_suites[] = {
1132 	WLAN_CIPHER_SUITE_WEP40,
1133 	WLAN_CIPHER_SUITE_WEP104,
1134 	WLAN_CIPHER_SUITE_TKIP,
1135 	WLAN_CIPHER_SUITE_CCMP,
1136 #ifdef MFP
1137 	/*
1138 	 * Advertising AES_CMAC cipher suite to userspace would imply that we
1139 	 * are supporting MFP. So advertise only when MFP support is enabled.
1140 	 */
1141 	WLAN_CIPHER_SUITE_AES_CMAC,
1142 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1143 	WLAN_CIPHER_SUITE_BIP_GMAC_256,
1144 	WLAN_CIPHER_SUITE_BIP_GMAC_128,
1145 	WLAN_CIPHER_SUITE_BIP_CMAC_256,
1146 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1147 #endif /* MFP */
1148 
1149 #ifdef BCMWAPI_WPI
1150 	WLAN_CIPHER_SUITE_SMS4,
1151 #endif // endif
1152 #if defined(WLAN_CIPHER_SUITE_PMK)
1153 	WLAN_CIPHER_SUITE_PMK,
1154 #endif /* WLAN_CIPHER_SUITE_PMK */
1155 #ifdef WL_GCMP
1156 	WLAN_CIPHER_SUITE_GCMP,
1157 	WLAN_CIPHER_SUITE_GCMP_256,
1158 	WLAN_CIPHER_SUITE_BIP_GMAC_128,
1159 	WLAN_CIPHER_SUITE_BIP_GMAC_256,
1160 #endif /* WL_GCMP */
1161 };
1162 
1163 #ifdef WL_SUPPORT_ACS
1164 /*
1165  * The firmware code required for this feature to work is currently under
1166  * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1167  * required firmware code out of the BCMINTERNAL flag.
1168  */
1169 struct wl_dump_survey {
1170 	u32 obss;
1171 	u32 ibss;
1172 	u32 no_ctg;
1173 	u32 no_pckt;
1174 	u32 tx;
1175 	u32 idle;
1176 };
1177 #endif /* WL_SUPPORT_ACS */
1178 
1179 #ifdef WL_CFG80211_GON_COLLISION
1180 #define BLOCK_GON_REQ_MAX_NUM 5
1181 #endif /* WL_CFG80211_GON_COLLISION */
1182 
1183 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1184 static int maxrxpktglom = 0;
1185 #endif // endif
1186 
1187 /* IOCtl version read from targeted driver */
1188 int ioctl_version;
1189 #ifdef DEBUGFS_CFG80211
1190 #define SUBLOGLEVEL 20
1191 #define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1))
1192 static const struct {
1193 	u32 log_level;
1194 	char *sublogname;
1195 } sublogname_map[] = {
1196 	{WL_DBG_ERR, "ERR"},
1197 	{WL_DBG_INFO, "INFO"},
1198 	{WL_DBG_DBG, "DBG"},
1199 	{WL_DBG_SCAN, "SCAN"},
1200 	{WL_DBG_TRACE, "TRACE"},
1201 	{WL_DBG_P2P_ACTION, "P2PACTION"}
1202 };
1203 #endif // endif
1204 
1205 typedef struct rsn_cipher_algo_entry {
1206 	u32 cipher_suite;
1207 	u32 wsec_algo;
1208 	u32 wsec_key_algo;
1209 } rsn_cipher_algo_entry_t;
1210 
1211 static const rsn_cipher_algo_entry_t rsn_cipher_algo_lookup_tbl[] = {
1212 	{WLAN_CIPHER_SUITE_WEP40, WEP_ENABLED, CRYPTO_ALGO_WEP1},
1213 	{WLAN_CIPHER_SUITE_WEP104, WEP_ENABLED, CRYPTO_ALGO_WEP128},
1214 	{WLAN_CIPHER_SUITE_TKIP, TKIP_ENABLED, CRYPTO_ALGO_TKIP},
1215 	{WLAN_CIPHER_SUITE_CCMP, AES_ENABLED, CRYPTO_ALGO_AES_CCM},
1216 	{WLAN_CIPHER_SUITE_AES_CMAC, AES_ENABLED, CRYPTO_ALGO_BIP},
1217 #ifdef BCMWAPI_WPI
1218 	{WLAN_CIPHER_SUITE_SMS4, SMS4_ENABLED, CRYPTO_ALGO_SMS4},
1219 #endif /* BCMWAPI_WPI */
1220 #ifdef WL_GCMP
1221 	{WLAN_CIPHER_SUITE_GCMP, AES_ENABLED, CRYPTO_ALGO_AES_GCM},
1222 	{WLAN_CIPHER_SUITE_GCMP_256, AES_ENABLED, CRYPTO_ALGO_AES_GCM256},
1223 	{WLAN_CIPHER_SUITE_BIP_GMAC_128, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC},
1224 	{WLAN_CIPHER_SUITE_BIP_GMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC256},
1225 #endif /* WL_GCMP */
1226 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1227 	{WLAN_CIPHER_SUITE_BIP_CMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_CMAC256},
1228 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1229 };
1230 
1231 typedef struct rsn_akm_wpa_auth_entry {
1232 	u32 akm_suite;
1233 	u32 wpa_auth;
1234 } rsn_akm_wpa_auth_entry_t;
1235 
1236 static const rsn_akm_wpa_auth_entry_t rsn_akm_wpa_auth_lookup_tbl[] = {
1237 #ifdef WL_OWE
1238 	{WLAN_AKM_SUITE_OWE, WPA3_AUTH_OWE},
1239 #endif /* WL_OWE */
1240 	{WLAN_AKM_SUITE_8021X, WPA2_AUTH_UNSPECIFIED},
1241 	{WL_AKM_SUITE_SHA256_1X, WPA2_AUTH_1X_SHA256},
1242 	{WL_AKM_SUITE_SHA256_PSK, WPA2_AUTH_PSK_SHA256},
1243 	{WLAN_AKM_SUITE_PSK, WPA2_AUTH_PSK},
1244 	{WLAN_AKM_SUITE_FT_8021X, WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT},
1245 	{WLAN_AKM_SUITE_FT_PSK, WPA2_AUTH_PSK | WPA2_AUTH_FT},
1246 	{WLAN_AKM_SUITE_FILS_SHA256, WPA2_AUTH_FILS_SHA256},
1247 	{WLAN_AKM_SUITE_FILS_SHA384, WPA2_AUTH_FILS_SHA384},
1248 	{WLAN_AKM_SUITE_8021X_SUITE_B, WPA3_AUTH_1X_SUITE_B_SHA256},
1249 	{WLAN_AKM_SUITE_8021X_SUITE_B_192, WPA3_AUTH_1X_SUITE_B_SHA384},
1250 #ifdef BCMWAPI_WPI
1251 	{WLAN_AKM_SUITE_WAPI_CERT, WAPI_AUTH_UNSPECIFIED},
1252 	{WLAN_AKM_SUITE_WAPI_PSK, WAPI_AUTH_PSK},
1253 #endif /* BCMWAPI_WPI */
1254 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
1255 	{WLAN_AKM_SUITE_SAE, WPA3_AUTH_SAE_PSK},
1256 #endif /* WL_SAE || WL_CLIENT_SAE */
1257 	{WLAN_AKM_SUITE_FT_8021X_SHA384, WPA3_AUTH_1X_SUITE_B_SHA384 | WPA2_AUTH_FT}
1258 };
1259 
1260 #define BUFSZ 8
1261 #define BUFSZN	BUFSZ + 1
1262 
1263 #define _S(x) #x
1264 #define S(x) _S(x)
1265 
1266 #define SOFT_AP_IF_NAME         "swlan0"
1267 
1268 /* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1269 uint32 fw_assoc_watchdog_ms = 0;
1270 bool fw_assoc_watchdog_started = 0;
1271 #define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1272 
wl_add_remove_pm_enable_work(struct bcm_cfg80211 * cfg,enum wl_pm_workq_act_type type)1273 static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg,
1274 	enum wl_pm_workq_act_type type)
1275 {
1276 	u16 wq_duration = 0;
1277 	dhd_pub_t *dhd =  NULL;
1278 
1279 	if (cfg == NULL)
1280 		return;
1281 
1282 	dhd = (dhd_pub_t *)(cfg->pub);
1283 
1284 	mutex_lock(&cfg->pm_sync);
1285 	/*
1286 	 * Make cancel and schedule work part mutually exclusive
1287 	 * so that while cancelling, we are sure that there is no
1288 	 * work getting scheduled.
1289 	 */
1290 	if (delayed_work_pending(&cfg->pm_enable_work)) {
1291 		cancel_delayed_work(&cfg->pm_enable_work);
1292 		DHD_PM_WAKE_UNLOCK(cfg->pub);
1293 	}
1294 
1295 	if (type == WL_PM_WORKQ_SHORT) {
1296 		wq_duration = WL_PM_ENABLE_TIMEOUT;
1297 	} else if (type == WL_PM_WORKQ_LONG) {
1298 		wq_duration = (WL_PM_ENABLE_TIMEOUT*2);
1299 	}
1300 
1301 	/* It should schedule work item only if driver is up */
1302 	if (wq_duration && dhd->up) {
1303 		if (schedule_delayed_work(&cfg->pm_enable_work,
1304 				msecs_to_jiffies((const unsigned int)wq_duration))) {
1305 			DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub, wq_duration);
1306 		} else {
1307 			WL_ERR(("Can't schedule pm work handler\n"));
1308 		}
1309 	}
1310 	mutex_unlock(&cfg->pm_sync);
1311 }
1312 
1313 /* Return a new chanspec given a legacy chanspec
1314  * Returns INVCHANSPEC on error
1315  */
1316 chanspec_t
wl_chspec_from_legacy(chanspec_t legacy_chspec)1317 wl_chspec_from_legacy(chanspec_t legacy_chspec)
1318 {
1319 	chanspec_t chspec;
1320 
1321 	/* get the channel number */
1322 	chspec = LCHSPEC_CHANNEL(legacy_chspec);
1323 
1324 	/* convert the band */
1325 	if (LCHSPEC_IS2G(legacy_chspec)) {
1326 		chspec |= WL_CHANSPEC_BAND_2G;
1327 	} else {
1328 		chspec |= WL_CHANSPEC_BAND_5G;
1329 	}
1330 
1331 	/* convert the bw and sideband */
1332 	if (LCHSPEC_IS20(legacy_chspec)) {
1333 		chspec |= WL_CHANSPEC_BW_20;
1334 	} else {
1335 		chspec |= WL_CHANSPEC_BW_40;
1336 		if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
1337 			chspec |= WL_CHANSPEC_CTL_SB_L;
1338 		} else {
1339 			chspec |= WL_CHANSPEC_CTL_SB_U;
1340 		}
1341 	}
1342 
1343 	if (wf_chspec_malformed(chspec)) {
1344 		WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1345 			chspec));
1346 		return INVCHANSPEC;
1347 	}
1348 
1349 	return chspec;
1350 }
1351 
1352 /* Return a legacy chanspec given a new chanspec
1353  * Returns INVCHANSPEC on error
1354  */
1355 static chanspec_t
wl_chspec_to_legacy(chanspec_t chspec)1356 wl_chspec_to_legacy(chanspec_t chspec)
1357 {
1358 	chanspec_t lchspec;
1359 
1360 	if (wf_chspec_malformed(chspec)) {
1361 		WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1362 			chspec));
1363 		return INVCHANSPEC;
1364 	}
1365 
1366 	/* get the channel number */
1367 	lchspec = CHSPEC_CHANNEL(chspec);
1368 
1369 	/* convert the band */
1370 	if (CHSPEC_IS2G(chspec)) {
1371 		lchspec |= WL_LCHANSPEC_BAND_2G;
1372 	} else {
1373 		lchspec |= WL_LCHANSPEC_BAND_5G;
1374 	}
1375 
1376 	/* convert the bw and sideband */
1377 	if (CHSPEC_IS20(chspec)) {
1378 		lchspec |= WL_LCHANSPEC_BW_20;
1379 		lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
1380 	} else if (CHSPEC_IS40(chspec)) {
1381 		lchspec |= WL_LCHANSPEC_BW_40;
1382 		if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
1383 			lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
1384 		} else {
1385 			lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
1386 		}
1387 	} else {
1388 		/* cannot express the bandwidth */
1389 		char chanbuf[CHANSPEC_STR_LEN];
1390 		WL_ERR((
1391 			"wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1392 			"to pre-11ac format\n",
1393 			wf_chspec_ntoa(chspec, chanbuf), chspec));
1394 		return INVCHANSPEC;
1395 	}
1396 
1397 	return lchspec;
1398 }
1399 
wl_cfg80211_is_hal_started(struct bcm_cfg80211 * cfg)1400 bool wl_cfg80211_is_hal_started(struct bcm_cfg80211 *cfg)
1401 {
1402 	return cfg->hal_started;
1403 }
1404 
1405 /* given a chanspec value, do the endian and chanspec version conversion to
1406  * a chanspec_t value
1407  * Returns INVCHANSPEC on error
1408  */
1409 chanspec_t
wl_chspec_host_to_driver(chanspec_t chanspec)1410 wl_chspec_host_to_driver(chanspec_t chanspec)
1411 {
1412 	if (ioctl_version == 1) {
1413 		chanspec = wl_chspec_to_legacy(chanspec);
1414 		if (chanspec == INVCHANSPEC) {
1415 			return chanspec;
1416 		}
1417 	}
1418 	chanspec = htodchanspec(chanspec);
1419 
1420 	return chanspec;
1421 }
1422 
1423 /* given a channel value, do the endian and chanspec version conversion to
1424  * a chanspec_t value
1425  * Returns INVCHANSPEC on error
1426  */
1427 chanspec_t
wl_ch_host_to_driver(u16 channel)1428 wl_ch_host_to_driver(u16 channel)
1429 {
1430 	chanspec_t chanspec;
1431 	chanspec_band_t band;
1432 
1433 	band = WL_CHANNEL_BAND(channel);
1434 
1435 	chanspec = wf_create_20MHz_chspec(channel, band);
1436 	if (chanspec == INVCHANSPEC) {
1437 		return chanspec;
1438 	}
1439 
1440 	return wl_chspec_host_to_driver(chanspec);
1441 }
1442 
1443 /* given a chanspec value from the driver, do the endian and chanspec version conversion to
1444  * a chanspec_t value
1445  * Returns INVCHANSPEC on error
1446  */
1447 chanspec_t
wl_chspec_driver_to_host(chanspec_t chanspec)1448 wl_chspec_driver_to_host(chanspec_t chanspec)
1449 {
1450 	chanspec = dtohchanspec(chanspec);
1451 	if (ioctl_version == 1) {
1452 		chanspec = wl_chspec_from_legacy(chanspec);
1453 	}
1454 
1455 	return chanspec;
1456 }
1457 
1458 /*
1459  * convert ASCII string to MAC address (colon-delimited format)
1460  * eg: 00:11:22:33:44:55
1461  */
1462 int
wl_cfg80211_ether_atoe(const char * a,struct ether_addr * n)1463 wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
1464 {
1465 	char *c = NULL;
1466 	int count = 0;
1467 
1468 	bzero(n, ETHER_ADDR_LEN);
1469 	for (;;) {
1470 		n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
1471 		if (!*c++ || count == ETHER_ADDR_LEN)
1472 			break;
1473 		a = c;
1474 	}
1475 	return (count == ETHER_ADDR_LEN);
1476 }
1477 
1478 /* There isn't a lot of sense in it, but you can transmit anything you like */
1479 static const struct ieee80211_txrx_stypes
1480 wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1481 #ifdef WLMESH_CFG80211
1482 	[NL80211_IFTYPE_MESH_POINT] = {
1483 		.tx = 0xffff,
1484 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1485 		BIT(IEEE80211_STYPE_AUTH >> 4)
1486 	},
1487 #endif /* WLMESH_CFG80211 */
1488 	[NL80211_IFTYPE_ADHOC] = {
1489 		.tx = 0xffff,
1490 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4)
1491 	},
1492 	[NL80211_IFTYPE_STATION] = {
1493 		.tx = 0xffff,
1494 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1495 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1496 #ifdef WL_CLIENT_SAE
1497 		| BIT(IEEE80211_STYPE_AUTH >> 4)
1498 #endif /* WL_CLIENT_SAE */
1499 	},
1500 	[NL80211_IFTYPE_AP] = {
1501 		.tx = 0xffff,
1502 		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1503 		BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1504 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1505 		BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1506 		BIT(IEEE80211_STYPE_AUTH >> 4) |
1507 		BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1508 		BIT(IEEE80211_STYPE_ACTION >> 4)
1509 	},
1510 	[NL80211_IFTYPE_AP_VLAN] = {
1511 		/* copy AP */
1512 		.tx = 0xffff,
1513 		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1514 		BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1515 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1516 		BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1517 		BIT(IEEE80211_STYPE_AUTH >> 4) |
1518 		BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1519 		BIT(IEEE80211_STYPE_ACTION >> 4)
1520 	},
1521 	[NL80211_IFTYPE_P2P_CLIENT] = {
1522 		.tx = 0xffff,
1523 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1524 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1525 	},
1526 	[NL80211_IFTYPE_P2P_GO] = {
1527 		.tx = 0xffff,
1528 		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1529 		BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1530 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1531 		BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1532 		BIT(IEEE80211_STYPE_AUTH >> 4) |
1533 		BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1534 		BIT(IEEE80211_STYPE_ACTION >> 4)
1535 	},
1536 #if defined(WL_CFG80211_P2P_DEV_IF)
1537 	[NL80211_IFTYPE_P2P_DEVICE] = {
1538 		.tx = 0xffff,
1539 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1540 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1541 	},
1542 #endif /* WL_CFG80211_P2P_DEV_IF */
1543 };
1544 
swap_key_from_BE(struct wl_wsec_key * key)1545 static void swap_key_from_BE(struct wl_wsec_key *key)
1546 {
1547 	key->index = htod32(key->index);
1548 	key->len = htod32(key->len);
1549 	key->algo = htod32(key->algo);
1550 	key->flags = htod32(key->flags);
1551 	key->rxiv.hi = htod32(key->rxiv.hi);
1552 	key->rxiv.lo = htod16(key->rxiv.lo);
1553 	key->iv_initialized = htod32(key->iv_initialized);
1554 }
1555 
swap_key_to_BE(struct wl_wsec_key * key)1556 static void swap_key_to_BE(struct wl_wsec_key *key)
1557 {
1558 	key->index = dtoh32(key->index);
1559 	key->len = dtoh32(key->len);
1560 	key->algo = dtoh32(key->algo);
1561 	key->flags = dtoh32(key->flags);
1562 	key->rxiv.hi = dtoh32(key->rxiv.hi);
1563 	key->rxiv.lo = dtoh16(key->rxiv.lo);
1564 	key->iv_initialized = dtoh32(key->iv_initialized);
1565 }
1566 
1567 #if defined(WL_FW_OCE_AP_SELECT)
wl_cfg80211_is_oce_ap(struct wiphy * wiphy,const u8 * bssid_hint)1568 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint)
1569 {
1570 	const u8 *parse = NULL;
1571 	bcm_tlv_t *ie;
1572 	const struct cfg80211_bss_ies *ies;
1573 	u32 len;
1574 	struct cfg80211_bss *bss;
1575 
1576 	bss = CFG80211_GET_BSS(wiphy, NULL, bssid_hint, 0, 0);
1577 	if (!bss) {
1578 		WL_ERR(("Unable to find AP in the cache"));
1579 		return false;
1580 	}
1581 
1582 	if (rcu_access_pointer(bss->ies)) {
1583 		ies = rcu_access_pointer(bss->ies);
1584 		parse = ies->data;
1585 		len = ies->len;
1586 	} else {
1587 		WL_ERR(("ies is NULL"));
1588 		return false;
1589 	}
1590 
1591 	while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_VS_ID))) {
1592 		if (wl_cfgoce_is_oce_ie((const uint8*)ie, (u8 const **)&parse, &len) == TRUE) {
1593 			return true;
1594 		} else {
1595 			ie = bcm_next_tlv((const bcm_tlv_t*) ie, &len);
1596 			if (!ie) {
1597 				return false;
1598 			}
1599 			parse = (uint8 *)ie;
1600 			WL_DBG(("NON OCE IE. next ie ptr:%p", parse));
1601 		}
1602 	}
1603 	WL_DBG(("OCE IE NOT found"));
1604 	return false;
1605 }
1606 #endif /* WL_FW_OCE_AP_SELECT */
1607 
1608 /* Dump the contents of the encoded wps ie buffer and get pbc value */
1609 static void
wl_validate_wps_ie(const char * wps_ie,s32 wps_ie_len,bool * pbc)1610 wl_validate_wps_ie(const char *wps_ie, s32 wps_ie_len, bool *pbc)
1611 {
1612 	#define WPS_IE_FIXED_LEN 6
1613 	s16 len;
1614 	const u8 *subel = NULL;
1615 	u16 subelt_id;
1616 	u16 subelt_len;
1617 	u16 val;
1618 	u8 *valptr = (uint8*) &val;
1619 	if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
1620 		WL_ERR(("invalid argument : NULL\n"));
1621 		return;
1622 	}
1623 	len = (s16)wps_ie[TLV_LEN_OFF];
1624 
1625 	if (len > wps_ie_len) {
1626 		WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
1627 		return;
1628 	}
1629 	WL_DBG(("wps_ie len=%d\n", len));
1630 	len -= 4;	/* for the WPS IE's OUI, oui_type fields */
1631 	subel = wps_ie + WPS_IE_FIXED_LEN;
1632 	while (len >= 4) {		/* must have attr id, attr len fields */
1633 		valptr[0] = *subel++;
1634 		valptr[1] = *subel++;
1635 		subelt_id = HTON16(val);
1636 
1637 		valptr[0] = *subel++;
1638 		valptr[1] = *subel++;
1639 		subelt_len = HTON16(val);
1640 
1641 		len -= 4;			/* for the attr id, attr len fields */
1642 		len -= (s16)subelt_len;	/* for the remaining fields in this attribute */
1643 		if (len < 0) {
1644 			break;
1645 		}
1646 		WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
1647 			subel, subelt_id, subelt_len));
1648 
1649 		if (subelt_id == WPS_ID_VERSION) {
1650 			WL_DBG(("  attr WPS_ID_VERSION: %u\n", *subel));
1651 		} else if (subelt_id == WPS_ID_REQ_TYPE) {
1652 			WL_DBG(("  attr WPS_ID_REQ_TYPE: %u\n", *subel));
1653 		} else if (subelt_id == WPS_ID_CONFIG_METHODS) {
1654 			valptr[0] = *subel;
1655 			valptr[1] = *(subel + 1);
1656 			WL_DBG(("  attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
1657 		} else if (subelt_id == WPS_ID_DEVICE_NAME) {
1658 			char devname[33];
1659 			int namelen = MIN(subelt_len, (sizeof(devname) - 1));
1660 
1661 			if (namelen) {
1662 				memcpy(devname, subel, namelen);
1663 				devname[namelen] = '\0';
1664 				/* Printing len as rx'ed in the IE */
1665 				WL_DBG(("  attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1666 					devname, subelt_len));
1667 			}
1668 		} else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
1669 			valptr[0] = *subel;
1670 			valptr[1] = *(subel + 1);
1671 			WL_DBG(("  attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
1672 			*pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
1673 		} else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
1674 			valptr[0] = *subel;
1675 			valptr[1] = *(subel + 1);
1676 			WL_DBG(("  attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
1677 			valptr[0] = *(subel + 6);
1678 			valptr[1] = *(subel + 7);
1679 			WL_DBG(("  attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
1680 		} else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
1681 			valptr[0] = *subel;
1682 			valptr[1] = *(subel + 1);
1683 			WL_DBG(("  attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
1684 			valptr[0] = *(subel + 6);
1685 			valptr[1] = *(subel + 7);
1686 			WL_DBG(("  attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
1687 		} else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
1688 			valptr[0] = *subel;
1689 			valptr[1] = *(subel + 1);
1690 			WL_DBG(("  attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1691 				": cat=%u\n", HTON16(val)));
1692 		} else {
1693 			WL_DBG(("  unknown attr 0x%x\n", subelt_id));
1694 		}
1695 
1696 		subel += subelt_len;
1697 	}
1698 }
1699 
wl_set_tx_power(struct net_device * dev,enum nl80211_tx_power_setting type,s32 dbm)1700 s32 wl_set_tx_power(struct net_device *dev,
1701 	enum nl80211_tx_power_setting type, s32 dbm)
1702 {
1703 	s32 err = 0;
1704 	s32 disable = 0;
1705 	s32 txpwrqdbm;
1706 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1707 
1708 	/* Make sure radio is off or on as far as software is concerned */
1709 	disable = WL_RADIO_SW_DISABLE << 16;
1710 	disable = htod32(disable);
1711 	err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable));
1712 	if (unlikely(err)) {
1713 		WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
1714 		return err;
1715 	}
1716 
1717 	if (dbm > 0xffff)
1718 		dbm = 0xffff;
1719 	txpwrqdbm = dbm * 4;
1720 #ifdef SUPPORT_WL_TXPOWER
1721 	if (type == NL80211_TX_POWER_AUTOMATIC)
1722 		txpwrqdbm = 127;
1723 	else
1724 		txpwrqdbm |= WL_TXPWR_OVERRIDE;
1725 #endif /* SUPPORT_WL_TXPOWER */
1726 	err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
1727 		sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
1728 		&cfg->ioctl_buf_sync);
1729 	if (unlikely(err))
1730 		WL_ERR(("qtxpower error (%d)\n", err));
1731 	else
1732 		WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
1733 
1734 	return err;
1735 }
1736 
wl_get_tx_power(struct net_device * dev,s32 * dbm)1737 s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
1738 {
1739 	s32 err = 0;
1740 	s32 txpwrdbm;
1741 	char ioctl_buf[WLC_IOCTL_SMLEN];
1742 
1743 	err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
1744 		NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
1745 	if (unlikely(err)) {
1746 		WL_ERR(("error (%d)\n", err));
1747 		return err;
1748 	}
1749 
1750 	memcpy(&txpwrdbm, ioctl_buf, sizeof(txpwrdbm));
1751 	txpwrdbm = dtoh32(txpwrdbm);
1752 	*dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
1753 
1754 	WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
1755 
1756 	return err;
1757 }
1758 
wl_cfg80211_get_shared_freq(struct wiphy * wiphy)1759 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
1760 {
1761 	chanspec_t chspec;
1762 	int cur_band, err = 0;
1763 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1764 	struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
1765 	struct ether_addr bssid;
1766 	wl_bss_info_t *bss = NULL;
1767 	u16 channel = WL_P2P_TEMP_CHAN;
1768 	char *buf;
1769 
1770 	bzero(&bssid, sizeof(bssid));
1771 	if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) {
1772 		/* STA interface is not associated. So start the new interface on a temp
1773 		 * channel . Later proper channel will be applied by the above framework
1774 		 * via set_channel (cfg80211 API).
1775 		 */
1776 		WL_DBG(("Not associated. Return a temp channel. \n"));
1777 		cur_band = 0;
1778 		err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(int));
1779 		if (unlikely(err)) {
1780 			WL_ERR(("Get band failed\n"));
1781 		} else if (cur_band == WLC_BAND_5G) {
1782 			channel = WL_P2P_TEMP_CHAN_5G;
1783 		}
1784 		return wl_ch_host_to_driver(channel);
1785 	}
1786 
1787 	buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
1788 	if (!buf) {
1789 		WL_ERR(("buf alloc failed. use temp channel\n"));
1790 		return wl_ch_host_to_driver(channel);
1791 	}
1792 
1793 	*(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1794 	if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf,
1795 		WL_EXTRA_BUF_MAX))) {
1796 			WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1797 			chspec = wl_ch_host_to_driver(channel);
1798 	}
1799 	else {
1800 			bss = (wl_bss_info_t *) (buf + 4);
1801 			chspec =  bss->chanspec;
1802 
1803 			WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
1804 	}
1805 
1806 	MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
1807 	return chspec;
1808 }
1809 
1810 static void
wl_wlfc_enable(struct bcm_cfg80211 * cfg,bool enable)1811 wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable)
1812 {
1813 #ifdef PROP_TXSTATUS_VSDB
1814 #if defined(BCMSDIO) || defined(BCMDBUS)
1815 	bool wlfc_enabled = FALSE;
1816 	s32 err;
1817 	dhd_pub_t *dhd;
1818 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1819 
1820 	dhd = (dhd_pub_t *)(cfg->pub);
1821 	if (!dhd) {
1822 		return;
1823 	}
1824 
1825 	if (enable) {
1826 		if (!cfg->wlfc_on && !disable_proptx) {
1827 			dhd_wlfc_get_enable(dhd, &wlfc_enabled);
1828 			if (!wlfc_enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1829 				dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1830 				dhd_wlfc_init(dhd);
1831 				err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32));
1832 				if (err < 0)
1833 					WL_ERR(("WLC_UP return err:%d\n", err));
1834 			}
1835 			cfg->wlfc_on = true;
1836 			WL_DBG(("wlfc_on:%d \n", cfg->wlfc_on));
1837 		}
1838 	} else if (dhd->conf->disable_proptx != 0){
1839 			dhd_wlfc_deinit(dhd);
1840 			cfg->wlfc_on = false;
1841 	}
1842 #endif /* BCMSDIO || BCMDBUS */
1843 #endif /* PROP_TXSTATUS_VSDB */
1844 }
1845 
1846 struct wireless_dev *
wl_cfg80211_p2p_if_add(struct bcm_cfg80211 * cfg,wl_iftype_t wl_iftype,char const * name,u8 * mac_addr,s32 * ret_err)1847 wl_cfg80211_p2p_if_add(struct bcm_cfg80211 *cfg,
1848 	wl_iftype_t wl_iftype,
1849 	char const *name, u8 *mac_addr, s32 *ret_err)
1850 {
1851 	u16 chspec;
1852 	s16 cfg_type;
1853 	long timeout;
1854 	s32 err;
1855 	u16 p2p_iftype;
1856 	int dhd_mode;
1857 	struct net_device *new_ndev = NULL;
1858 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
1859 	struct ether_addr *p2p_addr;
1860 
1861 	*ret_err = BCME_OK;
1862 	if (!cfg->p2p) {
1863 		WL_ERR(("p2p not initialized\n"));
1864 		return NULL;
1865 	}
1866 
1867 	printk(KERN_INFO"wl_cfg80211_p2p_if_add type=%d, name=%s\n", wl_iftype, name);
1868 
1869 #if defined(WL_CFG80211_P2P_DEV_IF)
1870 	if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
1871 		/* Handle Dedicated P2P discovery Interface */
1872 #ifdef CONFIG_AP6XXX_WIFI6_HDF
1873 		// cache @mac_addr ...
1874 		memcpy(g_hdf_infmap[HDF_INF_P2P0].macaddr, mac_addr, ETH_ALEN);
1875 #endif
1876 		return wl_cfgp2p_add_p2p_disc_if(cfg);
1877 	}
1878 #endif /* WL_CFG80211_P2P_DEV_IF */
1879 
1880 	if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1881 		p2p_iftype = WL_P2P_IF_GO;
1882 	} else {
1883 		p2p_iftype = WL_P2P_IF_CLIENT;
1884 	}
1885 
1886 	/* Dual p2p doesn't support multiple P2PGO interfaces,
1887 	 * p2p_go_count is the counter for GO creation
1888 	 * requests.
1889 	 */
1890 	if ((cfg->p2p->p2p_go_count > 0) && (wl_iftype == WL_IF_TYPE_P2P_GO)) {
1891 		WL_ERR(("FW does not support multiple GO\n"));
1892 		*ret_err = -ENOTSUPP;
1893 		return NULL;
1894 	}
1895 	if (!cfg->p2p->on) {
1896 		p2p_on(cfg) = true;
1897 		wl_cfgp2p_set_firm_p2p(cfg);
1898 		wl_cfgp2p_init_discovery(cfg);
1899 	}
1900 
1901 	strlcpy(cfg->p2p->vir_ifname, name, sizeof(cfg->p2p->vir_ifname));
1902 	/* In concurrency case, STA may be already associated in a particular channel.
1903 	 * so retrieve the current channel of primary interface and then start the virtual
1904 	 * interface on that.
1905 	 */
1906 	 chspec = wl_cfg80211_get_shared_freq(wiphy);
1907 
1908 	/* For P2P mode, use P2P-specific driver features to create the
1909 	 * bss: "cfg p2p_ifadd"
1910 	 */
1911 	wl_set_p2p_status(cfg, IF_ADDING);
1912 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
1913 	cfg_type = wl_cfgp2p_get_conn_idx(cfg);
1914 	if (cfg_type == BCME_ERROR) {
1915 		wl_clr_p2p_status(cfg, IF_ADDING);
1916 		WL_ERR(("Failed to get connection idx for p2p interface\n"));
1917 		return NULL;
1918 	}
1919 
1920 	p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
1921 	memcpy(p2p_addr->octet, mac_addr, ETH_ALEN);
1922 
1923 	err = wl_cfgp2p_ifadd(cfg, p2p_addr,
1924 		htod32(p2p_iftype), chspec);
1925 	if (unlikely(err)) {
1926 		wl_clr_p2p_status(cfg, IF_ADDING);
1927 		WL_ERR((" virtual iface add failed (%d) \n", err));
1928 		return NULL;
1929 	}
1930 
1931 	/* Wait for WLC_E_IF event with IF_ADD opcode */
1932 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1933 		((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
1934 		(cfg->if_event_info.valid)),
1935 		msecs_to_jiffies(MAX_WAIT_TIME));
1936 	if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
1937 		wl_if_event_info *event = &cfg->if_event_info;
1938 		new_ndev = wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg), event,
1939 			event->mac, cfg->p2p->vir_ifname, false);
1940 		if (unlikely(!new_ndev)) {
1941 			goto fail;
1942 		}
1943 
1944 		if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1945 			cfg->p2p->p2p_go_count++;
1946 		}
1947 		/* Fill p2p specific data */
1948 		wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
1949 		wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
1950 
1951 		WL_ERR((" virtual interface(%s) is "
1952 			"created net attach done\n", cfg->p2p->vir_ifname));
1953 		dhd_mode = (wl_iftype == WL_IF_TYPE_P2P_GC) ?
1954 			DHD_FLAG_P2P_GC_MODE : DHD_FLAG_P2P_GO_MODE;
1955 		DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
1956 			/* reinitialize completion to clear previous count */
1957 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1958 			INIT_COMPLETION(cfg->iface_disable);
1959 #else
1960 			init_completion(&cfg->iface_disable);
1961 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
1962 
1963 			return new_ndev->ieee80211_ptr;
1964 	}
1965 
1966 fail:
1967 	return NULL;
1968 }
1969 
1970 bool
wl_cfg80211_check_vif_in_use(struct net_device * ndev)1971 wl_cfg80211_check_vif_in_use(struct net_device *ndev)
1972 {
1973 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1974 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
1975 	bool nan_enabled = FALSE;
1976 
1977 #ifdef WL_NAN
1978 	nan_enabled = cfg->nan_enable;
1979 #endif /* WL_NAN */
1980 
1981 	if (nan_enabled || (wl_cfgp2p_vif_created(cfg)) ||
1982 		(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
1983 		WL_MEM(("%s: Virtual interfaces in use. NAN %d P2P %d softAP %d\n",
1984 			__FUNCTION__, nan_enabled, wl_cfgp2p_vif_created(cfg),
1985 			(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)));
1986 		return TRUE;
1987 	}
1988 
1989 	return FALSE;
1990 }
1991 
1992 void
wl_cfg80211_iface_state_ops(struct wireless_dev * wdev,wl_interface_state_t state,wl_iftype_t wl_iftype,u16 wl_mode)1993 wl_cfg80211_iface_state_ops(struct wireless_dev *wdev,
1994 	wl_interface_state_t state,
1995 	wl_iftype_t wl_iftype, u16 wl_mode)
1996 {
1997 	struct net_device *ndev;
1998 	struct bcm_cfg80211 *cfg;
1999 	dhd_pub_t *dhd;
2000 	s32 bssidx;
2001 
2002 	WL_DBG(("state:%s wl_iftype:%d mode:%d\n",
2003 		wl_if_state_strs[state], wl_iftype, wl_mode));
2004 	if (!wdev) {
2005 		WL_ERR(("wdev null\n"));
2006 		return;
2007 	}
2008 
2009 	if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_NAN_NMI)) {
2010 		/* P2P discovery is a netless device and uses a
2011 		 * hidden bsscfg interface in fw. Don't apply the
2012 		 * iface ops state changes for p2p discovery I/F.
2013 		 * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
2014 		 * Don't apply iface ops state changes for NMI I/F.
2015 		 */
2016 		return;
2017 	}
2018 
2019 	cfg = wiphy_priv(wdev->wiphy);
2020 	ndev = wdev->netdev;
2021 	dhd = (dhd_pub_t *)(cfg->pub);
2022 
2023 	bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2024 	if (!ndev || (bssidx < 0)) {
2025 		WL_ERR(("ndev null. skip iface state ops\n"));
2026 		return;
2027 	}
2028 
2029 	switch (state) {
2030 		case WL_IF_CREATE_REQ:
2031 #ifdef WL_BCNRECV
2032 			/* check fakeapscan in progress then abort */
2033 			wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
2034 #endif /* WL_BCNRECV */
2035 			wl_cfg80211_scan_abort(cfg);
2036 			wl_wlfc_enable(cfg, true);
2037 #ifdef WLTDLS
2038 			/* disable TDLS if number of connected interfaces is >= 1 */
2039 			wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_CREATE, false);
2040 #endif /* WLTDLS */
2041 			break;
2042 		case WL_IF_DELETE_REQ:
2043 #ifdef WL_WPS_SYNC
2044 			wl_wps_handle_ifdel(ndev);
2045 #endif /* WPS_SYNC */
2046 			if (wl_get_drv_status(cfg, SCANNING, ndev)) {
2047 				/* Send completion for any pending scans */
2048 				wl_cfg80211_cancel_scan(cfg);
2049 			}
2050 
2051 #ifdef CUSTOM_SET_CPUCORE
2052 			dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
2053 			if (!(dhd->chan_isvht80)) {
2054 				dhd_set_cpucore(dhd, FALSE);
2055 			}
2056 #endif /* CUSTOM_SET_CPUCORE */
2057 			 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
2058 			break;
2059 		case WL_IF_CREATE_DONE:
2060 			if (wl_mode == WL_MODE_BSS) {
2061 				/* Common code for sta type interfaces - STA, GC */
2062 				wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2063 			}
2064 			if (wl_iftype == WL_IF_TYPE_P2P_GC) {
2065 				/* Disable firmware roaming for P2P interface  */
2066 				wldev_iovar_setint(ndev, "roam_off", 1);
2067 				wldev_iovar_setint(ndev, "bcn_timeout", dhd->conf->bcn_timeout);
2068 			}
2069 			if (wl_mode == WL_MODE_AP) {
2070 				/* Common code for AP/GO */
2071 			}
2072 			break;
2073 		case WL_IF_DELETE_DONE:
2074 #ifdef WLTDLS
2075 			/* Enable back TDLS if connected interface is <= 1 */
2076 			wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2077 #endif /* WLTDLS */
2078 			wl_wlfc_enable(cfg, false);
2079 			break;
2080 		case WL_IF_CHANGE_REQ:
2081 			/* Flush existing IEs from firmware on role change */
2082 			wl_cfg80211_clear_per_bss_ies(cfg, wdev);
2083 			break;
2084 		case WL_IF_CHANGE_DONE:
2085 			if (wl_mode == WL_MODE_BSS) {
2086 				/* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2087 				wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2088 			}
2089 			break;
2090 
2091 		default:
2092 			WL_ERR(("Unsupported state: %d\n", state));
2093 			return;
2094 	}
2095 }
2096 
2097 static s32
wl_cfg80211_p2p_if_del(struct wiphy * wiphy,struct wireless_dev * wdev)2098 wl_cfg80211_p2p_if_del(struct wiphy *wiphy, struct wireless_dev *wdev)
2099 {
2100 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2101 	s16 bssidx;
2102 	s16 err;
2103 	s32 cfg_type;
2104 	struct net_device *ndev;
2105 	long timeout;
2106 
2107 	if (unlikely(!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
2108 		WL_INFORM_MEM(("device is not ready\n"));
2109 		return BCME_NOTFOUND;
2110 	}
2111 #ifdef WL_CFG80211_P2P_DEV_IF
2112 	if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2113 		/* Handle dedicated P2P discovery interface. */
2114 		return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
2115 	}
2116 #endif /* WL_CFG80211_P2P_DEV_IF */
2117 
2118 	/* Handle P2P Group Interface */
2119 	bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2120 	if (bssidx <= 0) {
2121 		WL_ERR(("bssidx not found\n"));
2122 		return BCME_NOTFOUND;
2123 	}
2124 	if (wl_cfgp2p_find_type(cfg, bssidx, &cfg_type) != BCME_OK) {
2125 		/* Couldn't find matching iftype */
2126 		WL_MEM(("non P2P interface\n"));
2127 		return BCME_NOTFOUND;
2128 	}
2129 
2130 	ndev = wdev->netdev;
2131 	wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2132 	wl_clr_p2p_status(cfg, IF_ADDING);
2133 
2134 	/* for GO */
2135 	if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
2136 		wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
2137 		cfg->p2p->p2p_go_count--;
2138 		/* disable interface before bsscfg free */
2139 		err = wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2140 		/* if fw doesn't support "ifdis",
2141 		   do not wait for link down of ap mode
2142 		 */
2143 		if (err == 0) {
2144 			WL_ERR(("Wait for Link Down event for GO !!!\n"));
2145 			wait_for_completion_timeout(&cfg->iface_disable,
2146 				msecs_to_jiffies(500));
2147 		} else if (err != BCME_UNSUPPORTED) {
2148 			msleep(300);
2149 		}
2150 	} else {
2151 		/* GC case */
2152 		if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
2153 			WL_ERR(("Wait for Link Down event for GC !\n"));
2154 			wait_for_completion_timeout
2155 					(&cfg->iface_disable, msecs_to_jiffies(500));
2156 		}
2157 	}
2158 
2159 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
2160 	wl_set_p2p_status(cfg, IF_DELETING);
2161 	DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
2162 
2163 	err = wl_cfgp2p_ifdel(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2164 	if (unlikely(err)) {
2165 		WL_ERR(("IFDEL operation failed, error code = %d\n", err));
2166 		goto fail;
2167 	} else {
2168 		/* Wait for WLC_E_IF event */
2169 		timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2170 			((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
2171 			(cfg->if_event_info.valid)),
2172 			msecs_to_jiffies(MAX_WAIT_TIME));
2173 		if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
2174 			cfg->if_event_info.valid) {
2175 			WL_ERR(("P2P IFDEL operation done\n"));
2176 			err = BCME_OK;
2177 		} else {
2178 			WL_ERR(("IFDEL didn't complete properly\n"));
2179 			err = -EINVAL;
2180 		}
2181 	}
2182 
2183 fail:
2184 	/* Even in failure case, attempt to remove the host data structure.
2185 	 * Firmware would be cleaned up via WiFi reset done by the
2186 	 * user space from hang event context (for android only).
2187 	 */
2188 	bzero(cfg->p2p->vir_ifname, IFNAMSIZ);
2189 	wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
2190 	wl_to_p2p_bss_ndev(cfg, cfg_type) = NULL;
2191 	wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, cfg_type));
2192 	dhd_net_if_lock(ndev);
2193 	if (cfg->if_event_info.ifidx) {
2194 		/* Remove interface except for primary ifidx */
2195 		wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
2196 	}
2197 	dhd_net_if_unlock(ndev);
2198 	return err;
2199 }
2200 
2201 #ifdef WL_IFACE_MGMT_CONF
2202 #ifdef WL_IFACE_MGMT
2203 static s32
wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 * cfg)2204 wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 *cfg)
2205 {
2206 	s32 ret = BCME_OK;
2207 	wl_iftype_t active_sec_iface = WL_IFACE_NOT_PRESENT;
2208 	bool p2p_disc_on = false;
2209 	bool sta_assoc_state = false;
2210 
2211 	mutex_lock(&cfg->if_sync);
2212 
2213 	sta_assoc_state = (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) ||
2214 		wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg)));
2215 	active_sec_iface = wl_cfg80211_get_sec_iface(cfg);
2216 	p2p_disc_on = wl_get_p2p_status(cfg, SCANNING);
2217 
2218 	if ((sta_assoc_state == TRUE) || (p2p_disc_on == TRUE) ||
2219 			(cfg->nan_init_state == TRUE) ||
2220 			(active_sec_iface != WL_IFACE_NOT_PRESENT)) {
2221 		WL_INFORM_MEM(("Active iface matrix: sta_assoc_state = %d,"
2222 			" p2p_disc = %d, nan_disc = %d, active iface = %s\n",
2223 			sta_assoc_state, p2p_disc_on, cfg->nan_init_state,
2224 			wl_iftype_to_str(active_sec_iface)));
2225 		ret = BCME_BUSY;
2226 	}
2227 	mutex_unlock(&cfg->if_sync);
2228 	return ret;
2229 }
2230 #endif /* WL_IFACE_MGMT */
2231 #ifdef WL_NANP2P
2232 int
wl_cfg80211_set_iface_conc_disc(struct net_device * ndev,uint8 arg_val)2233 wl_cfg80211_set_iface_conc_disc(struct net_device *ndev,
2234 	uint8 arg_val)
2235 {
2236 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2237 	if (!cfg) {
2238 		WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2239 		return BCME_ERROR;
2240 	}
2241 
2242 	if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
2243 		WL_ERR(("Cant allow iface management modifications\n"));
2244 		return BCME_BUSY;
2245 	}
2246 
2247 	if (arg_val) {
2248 		cfg->conc_disc |= arg_val;
2249 	} else {
2250 		cfg->conc_disc &= ~arg_val;
2251 	}
2252 	return BCME_OK;
2253 }
2254 
2255 uint8
wl_cfg80211_get_iface_conc_disc(struct net_device * ndev)2256 wl_cfg80211_get_iface_conc_disc(struct net_device *ndev)
2257 {
2258 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2259 	if (!cfg) {
2260 		WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2261 		return BCME_ERROR;
2262 	}
2263 	return cfg->conc_disc;
2264 }
2265 #endif /* WL_NANP2P */
2266 #ifdef WL_IFACE_MGMT
2267 int
wl_cfg80211_set_iface_policy(struct net_device * ndev,char * arg,int len)2268 wl_cfg80211_set_iface_policy(struct net_device *ndev,
2269 	char *arg, int len)
2270 {
2271 	int ret = BCME_OK;
2272 	uint8 i = 0;
2273 	iface_mgmt_data_t *iface_data = NULL;
2274 
2275 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2276 	if (!cfg) {
2277 		WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2278 		return BCME_ERROR;
2279 	}
2280 
2281 	if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
2282 		WL_ERR(("Cant allow iface management modifications\n"));
2283 		return BCME_BUSY;
2284 	}
2285 
2286 	if (!arg || len <= 0 || len > sizeof(iface_mgmt_data_t)) {
2287 		return BCME_BADARG;
2288 	}
2289 
2290 	iface_data = (iface_mgmt_data_t *)arg;
2291 	if (iface_data->policy >= WL_IF_POLICY_INVALID) {
2292 		WL_ERR(("Unexpected value of policy = %d\n",
2293 			iface_data->policy));
2294 		return BCME_BADARG;
2295 	}
2296 
2297 	bzero(&cfg->iface_data, sizeof(iface_mgmt_data_t));
2298 	ret = memcpy_s(&cfg->iface_data, sizeof(iface_mgmt_data_t), arg, len);
2299 	if (ret != BCME_OK) {
2300 		WL_ERR(("Failed to copy iface data, src len = %d\n", len));
2301 		return ret;
2302 	}
2303 
2304 	if (cfg->iface_data.policy == WL_IF_POLICY_ROLE_PRIORITY) {
2305 		for (i = 0; i < WL_IF_TYPE_MAX; i++) {
2306 			WL_DBG(("iface = %s, priority[i] = %d\n",
2307 			wl_iftype_to_str(i), cfg->iface_data.priority[i]));
2308 		}
2309 	}
2310 
2311 	return ret;
2312 }
2313 
2314 uint8
wl_cfg80211_get_iface_policy(struct net_device * ndev)2315 wl_cfg80211_get_iface_policy(struct net_device *ndev)
2316 
2317 {
2318 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2319 	if (!cfg) {
2320 		WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2321 		return BCME_ERROR;
2322 	}
2323 
2324 	return cfg->iface_data.policy;
2325 }
2326 #endif /* WL_IFACE_MGMT */
2327 #endif /* WL_IFACE_MGMT_CONF */
2328 
2329 #ifdef WL_IFACE_MGMT
2330 /* Get active secondary data iface type */
2331 wl_iftype_t
wl_cfg80211_get_sec_iface(struct bcm_cfg80211 * cfg)2332 wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg)
2333 {
2334 #ifndef WL_STATIC_IF
2335 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2336 #endif /* !WL_STATIC_IF */
2337 	struct net_device *p2p_ndev = NULL;
2338 
2339 	p2p_ndev = wl_to_p2p_bss_ndev(cfg,
2340 		P2PAPI_BSSCFG_CONNECTION1);
2341 
2342 #ifdef WL_STATIC_IF
2343 	if (IS_CFG80211_STATIC_IF_ACTIVE(cfg)) {
2344 		if (IS_AP_IFACE(cfg->static_ndev->ieee80211_ptr)) {
2345 			return WL_IF_TYPE_AP;
2346 		}
2347 	}
2348 #else
2349 	if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
2350 		return WL_IF_TYPE_AP;
2351 	}
2352 #endif /* WL_STATIC_IF */
2353 
2354 	if (p2p_ndev && p2p_ndev->ieee80211_ptr) {
2355 		if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
2356 			return WL_IF_TYPE_P2P_GO;
2357 		}
2358 
2359 		if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
2360 			return WL_IF_TYPE_P2P_GC;
2361 		}
2362 	}
2363 
2364 #ifdef WL_NAN
2365 	if (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg))) {
2366 		return WL_IF_TYPE_NAN;
2367 	}
2368 #endif /* WL_NAN */
2369 	return WL_IFACE_NOT_PRESENT;
2370 }
2371 
2372 /*
2373 * Handle incoming data interface request based on policy.
2374 * If there is any conflicting interface, that will be
2375 * deleted.
2376 */
2377 s32
wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2378 wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 *cfg,
2379 	wl_iftype_t new_wl_iftype)
2380 {
2381 	s32 ret = BCME_OK;
2382 	bool del_iface = false;
2383 	wl_iftype_t sec_wl_if_type = wl_cfg80211_get_sec_iface(cfg);
2384 
2385 	if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2386 		new_wl_iftype == WL_IF_TYPE_NAN) {
2387 		/* Multi NDP is allowed irrespective of Policy */
2388 		return BCME_OK;
2389 	}
2390 
2391 	if (sec_wl_if_type == WL_IFACE_NOT_PRESENT) {
2392 		/*
2393 		* If there is no active secondary I/F, there
2394 		* is no interface conflict. Do nothing.
2395 		*/
2396 		return BCME_OK;
2397 	}
2398 
2399 	/* Handle secondary data link case */
2400 	switch (cfg->iface_data.policy) {
2401 		case WL_IF_POLICY_CUSTOM:
2402 		case WL_IF_POLICY_DEFAULT: {
2403 			if (sec_wl_if_type == WL_IF_TYPE_NAN) {
2404 				/* NAN has the lowest priority */
2405 				del_iface = true;
2406 			} else {
2407 				/* Active iface is present, returning error */
2408 				ret = BCME_ERROR;
2409 			}
2410 			break;
2411 		}
2412 		case WL_IF_POLICY_FCFS: {
2413 			WL_INFORM_MEM(("Found active iface = %s, can't support new iface = %s\n",
2414 				wl_iftype_to_str(sec_wl_if_type), wl_iftype_to_str(new_wl_iftype)));
2415 			ret = BCME_ERROR;
2416 			break;
2417 		}
2418 		case WL_IF_POLICY_LP: {
2419 			WL_INFORM_MEM(("Remove active sec data interface, allow incoming iface\n"));
2420 			/* Delete existing data iface and allow incoming sec iface */
2421 			del_iface = true;
2422 			break;
2423 		}
2424 		case WL_IF_POLICY_ROLE_PRIORITY: {
2425 			WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2426 				wl_iftype_to_str(sec_wl_if_type),
2427 				cfg->iface_data.priority[sec_wl_if_type],
2428 				wl_iftype_to_str(new_wl_iftype),
2429 				cfg->iface_data.priority[new_wl_iftype]));
2430 			if (cfg->iface_data.priority[new_wl_iftype] >
2431 				cfg->iface_data.priority[sec_wl_if_type]) {
2432 				del_iface = true;
2433 			} else {
2434 				WL_ERR(("Can't support new iface = %s\n",
2435 					wl_iftype_to_str(new_wl_iftype)));
2436 					ret = BCME_ERROR;
2437 			}
2438 			break;
2439 		}
2440 		default: {
2441 			WL_ERR(("Unsupported interface policy = %d\n",
2442 				cfg->iface_data.policy));
2443 			return BCME_ERROR;
2444 		}
2445 	}
2446 	if (del_iface) {
2447 		ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2448 	}
2449 	return ret;
2450 }
2451 
2452 /* Handle discovery ifaces based on policy */
2453 s32
wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype,bool * disable_nan,bool * disable_p2p)2454 wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 *cfg,
2455 	wl_iftype_t new_wl_iftype, bool *disable_nan, bool *disable_p2p)
2456 {
2457 	s32 ret = BCME_OK;
2458 	wl_iftype_t sec_wl_if_type =
2459 		wl_cfg80211_get_sec_iface(cfg);
2460 	*disable_p2p = false;
2461 	*disable_nan = false;
2462 
2463 	if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2464 			new_wl_iftype == WL_IF_TYPE_NAN) {
2465 		/* Multi NDP is allowed irrespective of Policy */
2466 		return BCME_OK;
2467 	}
2468 
2469 	/*
2470 	* Check for any policy conflicts with active secondary
2471 	* interface for incoming discovery iface
2472 	*/
2473 	if ((sec_wl_if_type != WL_IFACE_NOT_PRESENT) &&
2474 		(is_discovery_iface(new_wl_iftype))) {
2475 		switch (cfg->iface_data.policy) {
2476 			case WL_IF_POLICY_CUSTOM: {
2477 				if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2478 					new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2479 					WL_INFORM_MEM(("Allow P2P Discovery with active NDP\n"));
2480 					/* No further checks are required. */
2481 					return BCME_OK;
2482 				}
2483 				/*
2484 				* Intentional fall through to default policy
2485 				* as for AP and associated ifaces, both are same
2486 				*/
2487 			}
2488 			case WL_IF_POLICY_DEFAULT: {
2489 				 if (sec_wl_if_type == WL_IF_TYPE_AP) {
2490 					WL_INFORM_MEM(("AP is active, cant support new iface\n"));
2491 					ret = BCME_ERROR;
2492 				} else if (sec_wl_if_type == WL_IF_TYPE_P2P_GC ||
2493 					sec_wl_if_type == WL_IF_TYPE_P2P_GO) {
2494 					if (new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2495 						/*
2496 						* Associated discovery case,
2497 						* Fall through
2498 						*/
2499 					} else {
2500 						/* Active iface is present, returning error */
2501 						WL_INFORM_MEM(("P2P group is active,"
2502 							" cant support new iface\n"));
2503 						ret = BCME_ERROR;
2504 					}
2505 				} else if (sec_wl_if_type == WL_IF_TYPE_NAN) {
2506 					ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2507 				}
2508 				break;
2509 			}
2510 			case WL_IF_POLICY_FCFS: {
2511 				WL_INFORM_MEM(("Can't support new iface = %s\n",
2512 						wl_iftype_to_str(new_wl_iftype)));
2513 				ret = BCME_ERROR;
2514 				break;
2515 			}
2516 			case WL_IF_POLICY_LP: {
2517 				/* Delete existing data iface n allow incoming sec iface */
2518 				WL_INFORM_MEM(("Remove active sec data interface = %s\n",
2519 					wl_iftype_to_str(sec_wl_if_type)));
2520 				ret = wl_cfg80211_delete_iface(cfg,
2521 						sec_wl_if_type);
2522 				break;
2523 			}
2524 			case WL_IF_POLICY_ROLE_PRIORITY: {
2525 				WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2526 					wl_iftype_to_str(sec_wl_if_type),
2527 					cfg->iface_data.priority[sec_wl_if_type],
2528 					wl_iftype_to_str(new_wl_iftype),
2529 					cfg->iface_data.priority[new_wl_iftype]));
2530 				if (cfg->iface_data.priority[new_wl_iftype] >
2531 					cfg->iface_data.priority[sec_wl_if_type]) {
2532 					WL_INFORM_MEM(("Remove active sec data iface\n"));
2533 					ret = wl_cfg80211_delete_iface(cfg,
2534 						sec_wl_if_type);
2535 				} else {
2536 					WL_ERR(("Can't support new iface = %s"
2537 						" due to low priority\n",
2538 						wl_iftype_to_str(new_wl_iftype)));
2539 						ret = BCME_ERROR;
2540 				}
2541 				break;
2542 			}
2543 			default: {
2544 				WL_ERR(("Unsupported policy\n"));
2545 				return BCME_ERROR;
2546 			}
2547 		}
2548 	} else {
2549 		/*
2550 		* Handle incoming new secondary iface request,
2551 		* irrespective of existing discovery ifaces
2552 		*/
2553 		if ((cfg->iface_data.policy == WL_IF_POLICY_CUSTOM) &&
2554 			(new_wl_iftype == WL_IF_TYPE_NAN)) {
2555 			WL_INFORM_MEM(("Allow NAN Data Path\n"));
2556 			/* No further checks are required. */
2557 			return BCME_OK;
2558 		}
2559 	}
2560 
2561 	/* Check for any conflicting discovery iface */
2562 	switch (new_wl_iftype) {
2563 		case WL_IF_TYPE_P2P_DISC:
2564 		case WL_IF_TYPE_P2P_GO:
2565 		case WL_IF_TYPE_P2P_GC: {
2566 			*disable_nan = true;
2567 			break;
2568 		}
2569 		case WL_IF_TYPE_NAN_NMI:
2570 		case WL_IF_TYPE_NAN: {
2571 			*disable_p2p = true;
2572 			break;
2573 		}
2574 		case WL_IF_TYPE_STA:
2575 		case WL_IF_TYPE_AP: {
2576 			*disable_nan = true;
2577 			*disable_p2p = true;
2578 			break;
2579 		}
2580 		default: {
2581 			WL_ERR(("Unsupported\n"));
2582 			return BCME_ERROR;
2583 		}
2584 	}
2585 	return ret;
2586 }
2587 
2588 bool
wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2589 wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 *cfg,
2590 	wl_iftype_t new_wl_iftype)
2591 {
2592 	struct net_device *p2p_ndev = NULL;
2593 	p2p_ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
2594 
2595 	if (new_wl_iftype == WL_IF_TYPE_P2P_DISC && p2p_ndev &&
2596 		p2p_ndev->ieee80211_ptr &&
2597 		is_p2p_group_iface(p2p_ndev->ieee80211_ptr)) {
2598 			return true;
2599 	}
2600 #ifdef WL_NAN
2601 	else if ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) &&
2602 		(wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg)))) {
2603 			return true;
2604 		}
2605 #endif /* WL_NAN */
2606 	return false;
2607 }
2608 
2609 /* Handle incoming discovery iface request */
2610 s32
wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2611 wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 *cfg,
2612 	wl_iftype_t new_wl_iftype)
2613 {
2614 	s32 ret = BCME_OK;
2615 	bool disable_p2p = false;
2616 	bool disable_nan = false;
2617 
2618 	wl_iftype_t active_sec_iface =
2619 		wl_cfg80211_get_sec_iface(cfg);
2620 
2621 	if (is_discovery_iface(new_wl_iftype) &&
2622 		(active_sec_iface != WL_IFACE_NOT_PRESENT)) {
2623 		if (wl_cfg80211_is_associated_discovery(cfg,
2624 			new_wl_iftype) == TRUE) {
2625 			WL_DBG(("Associate iface request is allowed= %s\n",
2626 				wl_iftype_to_str(new_wl_iftype)));
2627 			return ret;
2628 		}
2629 	}
2630 
2631 	ret = wl_cfg80211_disc_if_mgmt(cfg, new_wl_iftype,
2632 			&disable_nan, &disable_p2p);
2633 	if (ret != BCME_OK) {
2634 		WL_ERR(("Failed at disc iface mgmt, ret = %d\n", ret));
2635 		return ret;
2636 	}
2637 #ifdef WL_NANP2P
2638 	if (((new_wl_iftype == WL_IF_TYPE_P2P_DISC) && disable_nan) ||
2639 		((new_wl_iftype == WL_IF_TYPE_NAN_NMI) && disable_p2p)) {
2640 		if ((cfg->nan_p2p_supported == TRUE) &&
2641 		(cfg->conc_disc == WL_NANP2P_CONC_SUPPORT)) {
2642 			WL_INFORM_MEM(("P2P + NAN conc is supported\n"));
2643 			disable_p2p = false;
2644 			disable_nan = false;
2645 		}
2646 	}
2647 #endif /* WL_NANP2P */
2648 
2649 	if (disable_nan) {
2650 #ifdef WL_NAN
2651 		/* Disable nan */
2652 		cfg->nancfg.disable_reason = NAN_CONCURRENCY_CONFLICT;
2653 		ret = wl_cfgnan_disable(cfg);
2654 		if (ret != BCME_OK) {
2655 			WL_ERR(("failed to disable nan, error[%d]\n", ret));
2656 			return ret;
2657 		}
2658 #endif /* WL_NAN */
2659 	}
2660 
2661 	if (disable_p2p) {
2662 		/* Disable p2p discovery */
2663 		ret = wl_cfg80211_deinit_p2p_discovery(cfg);
2664 		if (ret != BCME_OK) {
2665 			WL_ERR(("Failed to disable p2p_disc for allowing nan\n"));
2666 			return ret;
2667 		}
2668 	}
2669 	return ret;
2670 }
2671 
2672 /*
2673 * Check for any conflicting iface before adding iface.
2674 * Based on policy, either conflicting iface is removed
2675 * or new iface add request is blocked.
2676 */
2677 s32
wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2678 wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg,
2679 	wl_iftype_t new_wl_iftype)
2680 {
2681 	s32 ret = BCME_OK;
2682 
2683 	WL_INFORM_MEM(("Incoming iface = %s\n", wl_iftype_to_str(new_wl_iftype)));
2684 
2685 	if (!is_discovery_iface(new_wl_iftype)) {
2686 		/* Incoming data interface request */
2687 		if (wl_cfg80211_get_sec_iface(cfg) != WL_IFACE_NOT_PRESENT) {
2688 			/* active interface present - Apply interface data policy */
2689 			ret = wl_cfg80211_data_if_mgmt(cfg, new_wl_iftype);
2690 			if (ret != BCME_OK) {
2691 				WL_ERR(("if_mgmt fail:%d\n", ret));
2692 				return ret;
2693 			}
2694 		}
2695 	}
2696 	/* Apply discovery config */
2697 	ret = wl_cfg80211_handle_discovery_config(cfg, new_wl_iftype);
2698 	return ret;
2699 }
2700 #endif /* WL_IFACE_MGMT */
2701 
2702 static struct wireless_dev *
wl_cfg80211_add_monitor_if(struct wiphy * wiphy,const char * name)2703 wl_cfg80211_add_monitor_if(struct wiphy *wiphy, const char *name)
2704 {
2705 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
2706 	WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2707 	return ERR_PTR(-EOPNOTSUPP);
2708 #else
2709 	struct wireless_dev *wdev;
2710 	struct net_device* ndev = NULL;
2711 
2712 	dhd_add_monitor(name, &ndev);
2713 
2714 	wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2715 	if (!wdev) {
2716 		WL_ERR(("wireless_dev alloc failed! \n"));
2717 		goto fail;
2718 	}
2719 
2720 	wdev->wiphy = wiphy;
2721 	wdev->iftype = NL80211_IFTYPE_MONITOR;
2722 	ndev->ieee80211_ptr = wdev;
2723 	SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
2724 
2725 	WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
2726 	return ndev->ieee80211_ptr;
2727 fail:
2728 	return ERR_PTR(-EOPNOTSUPP);
2729 #endif // endif
2730 }
2731 
2732 static struct wireless_dev *
wl_cfg80211_add_ibss(struct wiphy * wiphy,u16 wl_iftype,char const * name)2733 wl_cfg80211_add_ibss(struct wiphy *wiphy, u16 wl_iftype, char const *name)
2734 {
2735 #ifdef WLAIBSS_MCHAN
2736 	/* AIBSS */
2737 	return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
2738 #else
2739 	/* Normal IBSS */
2740 	WL_ERR(("IBSS not supported on Virtual iface\n"));
2741 	return NULL;
2742 #endif // endif
2743 }
2744 
2745 s32
wl_release_vif_macaddr(struct bcm_cfg80211 * cfg,u8 * mac_addr,u16 wl_iftype)2746 wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype)
2747 {
2748 	struct net_device *ndev =  bcmcfg_to_prmry_ndev(cfg);
2749 	u16 org_toggle_bytes;
2750 	u16 cur_toggle_bytes;
2751 	u16 toggled_bit;
2752 
2753 	if (!ndev || !mac_addr || ETHER_ISNULLADDR(mac_addr)) {
2754 		return -EINVAL;
2755 	}
2756 	WL_DBG(("%s:Mac addr" MACDBG "\n",
2757 			__FUNCTION__, MAC2STRDBG(mac_addr)));
2758 
2759 	if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_AP) ||
2760 		(wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2761 		/* Avoid invoking release mac addr code for interfaces using
2762 		 * fixed mac addr.
2763 		 */
2764 		return BCME_OK;
2765 	}
2766 
2767 	/* Fetch last two bytes of mac address */
2768 	org_toggle_bytes = ntoh16(*((u16 *)&ndev->dev_addr[4]));
2769 	cur_toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
2770 
2771 	toggled_bit = (org_toggle_bytes ^ cur_toggle_bytes);
2772 	WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n",
2773 		org_toggle_bytes, cur_toggle_bytes));
2774 	if (toggled_bit & cfg->vif_macaddr_mask) {
2775 		/* This toggled_bit is marked in the used mac addr
2776 		 * mask. Clear it.
2777 		 */
2778 		cfg->vif_macaddr_mask &= ~toggled_bit;
2779 		WL_INFORM(("MAC address - " MACDBG " released. toggled_bit:%04X vif_mask:%04X\n",
2780 			MAC2STRDBG(mac_addr), toggled_bit, cfg->vif_macaddr_mask));
2781 	} else {
2782 		WL_ERR(("MAC address - " MACDBG " not found in the used list."
2783 			" toggled_bit:%04x vif_mask:%04x\n", MAC2STRDBG(mac_addr),
2784 			toggled_bit, cfg->vif_macaddr_mask));
2785 		return -EINVAL;
2786 	}
2787 
2788 	return BCME_OK;
2789 }
2790 
2791 s32
wl_get_vif_macaddr(struct bcm_cfg80211 * cfg,u16 wl_iftype,u8 * mac_addr)2792 wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr)
2793 {
2794 #ifdef WL_P2P_USE_RANDMAC
2795 	struct ether_addr *p2p_dev_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE);
2796 #endif // endif
2797 	struct net_device *ndev =  bcmcfg_to_prmry_ndev(cfg);
2798 	u16 toggle_mask;
2799 	u16 toggle_bit;
2800 	u16 toggle_bytes;
2801 	u16 used;
2802 	u32 offset = 0;
2803 	/* Toggle mask starts from MSB of second last byte */
2804 	u16 mask = 0x8000;
2805 	if (!mac_addr) {
2806 		return -EINVAL;
2807 	}
2808 #ifdef WL_P2P_USE_RANDMAC
2809 	if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
2810 		memcpy_s(mac_addr, ETH_ALEN, p2p_dev_addr->octet, ETH_ALEN);
2811 		return 0;
2812 	}
2813 #endif // endif
2814 	memcpy(mac_addr, ndev->dev_addr, ETH_ALEN);
2815 /*
2816  * VIF MAC address managment
2817  * P2P Device addres: Primary MAC with locally admin. bit set
2818  * P2P Group address/NAN NMI/Softap/NAN DPI: Primary MAC addr
2819  *    with local admin bit set and one additional bit toggled.
2820  * cfg->vif_macaddr_mask will hold the info regarding the mac address
2821  * released. Ensure to call wl_release_vif_macaddress to free up
2822  * the mac address.
2823  */
2824 #if defined(SPECIFIC_MAC_GEN_SCHEME)
2825 	if (wl_iftype == WL_IF_TYPE_P2P_DISC ||	wl_iftype == WL_IF_TYPE_AP) {
2826 		mac_addr[0] |= 0x02;
2827 	} else if ((wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2828 		mac_addr[0] |= 0x02;
2829 		mac_addr[4] ^= 0x80;
2830 	}
2831 #else
2832 	if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
2833 		mac_addr[0] |= 0x02;
2834 	}
2835 #endif /* SEPCIFIC_MAC_GEN_SCHEME */
2836 	else {
2837 		/* For locally administered mac addresses, we keep the
2838 		 * OUI part constant and just work on the last two bytes.
2839 		 */
2840 		mac_addr[0] |= 0x02;
2841 		toggle_mask = cfg->vif_macaddr_mask;
2842 		toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
2843 		do {
2844 			used = toggle_mask & mask;
2845 			if (!used) {
2846 				/* Use this bit position */
2847 				toggle_bit = mask >> offset;
2848 				toggle_bytes ^= toggle_bit;
2849 				cfg->vif_macaddr_mask |= toggle_bit;
2850 				WL_DBG(("toggle_bit:%04X toggle_bytes:%04X toggle_mask:%04X\n",
2851 					toggle_bit, toggle_bytes, cfg->vif_macaddr_mask));
2852 				/* Macaddress are stored in network order */
2853 				mac_addr[5] = *((u8 *)&toggle_bytes);
2854 				mac_addr[4] = *(((u8 *)&toggle_bytes + 1));
2855 				break;
2856 			}
2857 
2858 			/* Shift by one */
2859 			toggle_mask = toggle_mask << 0x1;
2860 			offset++;
2861 			if (offset > MAX_VIF_OFFSET) {
2862 				/* We have used up all macaddresses. Something wrong! */
2863 				WL_ERR(("Entire range of macaddress used up.\n"));
2864 				ASSERT(0);
2865 				break;
2866 			}
2867 		} while (true);
2868 	}
2869 	WL_INFORM_MEM(("Get virtual I/F mac addr: "MACDBG"\n", MAC2STRDBG(mac_addr)));
2870 	return 0;
2871 }
2872 #ifdef DNGL_AXI_ERROR_LOGGING
2873 static s32
_wl_cfg80211_check_axi_error(struct bcm_cfg80211 * cfg)2874 _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg)
2875 {
2876 	s32 ret = BCME_OK;
2877 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2878 	hnd_ext_trap_hdr_t *hdr;
2879 	int axi_host_error_size;
2880 	uint8 *new_dst;
2881 	uint32 *ext_data = dhd->extended_trap_data;
2882 	struct file *fp = NULL;
2883 	char *filename = DHD_COMMON_DUMP_PATH
2884 			 DHD_DUMP_AXI_ERROR_FILENAME
2885 			 DHD_DUMP_HAL_FILENAME_SUFFIX;
2886 
2887 	WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename));
2888 
2889 	fp = filp_open(filename, O_RDONLY, 0);
2890 
2891 	if (IS_ERR(fp) || (fp == NULL)) {
2892 		WL_ERR(("%s: Couldn't read the file, err %ld,File [%s]  No previous axi error \n",
2893 			__FUNCTION__, PTR_ERR(fp), filename));
2894 		return ret;
2895 	}
2896 
2897 	kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t));
2898 	filp_close(fp, NULL);
2899 
2900 	/* Delete axi error info file */
2901 	if (dhd_file_delete(filename) < 0) {
2902 		WL_ERR(("%s(): Failed to delete file: %s\n", __FUNCTION__, filename));
2903 		return ret;
2904 	}
2905 	WL_ERR(("%s(): Success to delete file: %s\n", __FUNCTION__, filename));
2906 
2907 	if (dhd->axi_err_dump->etd_axi_error_v1.signature != HND_EXT_TRAP_AXIERROR_SIGNATURE) {
2908 		WL_ERR(("%s: Invalid AXI signature: 0x%x\n",
2909 		__FUNCTION__, dhd->axi_err_dump->etd_axi_error_v1.signature));
2910 	}
2911 
2912 	/* First word is original trap_data */
2913 	ext_data++;
2914 
2915 	/* Followed by the extended trap data header */
2916 	hdr = (hnd_ext_trap_hdr_t *)ext_data;
2917 	new_dst = hdr->data;
2918 
2919 	axi_host_error_size =  sizeof(dhd->axi_err_dump->axid)
2920 		+ sizeof(dhd->axi_err_dump->fault_address);
2921 
2922 	/* TAG_TRAP_AXI_HOST_INFO tlv : host's axid, fault address */
2923 	new_dst = bcm_write_tlv(TAG_TRAP_AXI_HOST_INFO,
2924 			(const void *)dhd->axi_err_dump,
2925 			axi_host_error_size, new_dst);
2926 
2927 	/* TAG_TRAP_AXI_ERROR tlv */
2928 	new_dst = bcm_write_tlv(TAG_TRAP_AXI_ERROR,
2929 			(const void *)&dhd->axi_err_dump->etd_axi_error_v1,
2930 			sizeof(dhd->axi_err_dump->etd_axi_error_v1), new_dst);
2931 	hdr->len = new_dst - hdr->data;
2932 
2933 	dhd->dongle_trap_occured = TRUE;
2934 	memset(dhd->axi_err_dump, 0, sizeof(dhd_axi_error_dump_t));
2935 
2936 	dhd->hang_reason = HANG_REASON_DONGLE_TRAP;
2937 	net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2938 	ret = BCME_ERROR;
2939 	return ret;
2940 }
2941 #endif /* DNGL_AXI_ERROR_LOGGING */
2942 
2943 /* All Android/Linux private/Vendor Interface calls should make
2944  *  use of below API for interface creation.
2945  */
2946 struct wireless_dev *
wl_cfg80211_add_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,wl_iftype_t wl_iftype,const char * name,u8 * mac)2947 wl_cfg80211_add_if(struct bcm_cfg80211 *cfg,
2948 	struct net_device *primary_ndev,
2949 	wl_iftype_t wl_iftype, const char *name, u8 *mac)
2950 {
2951 	u8 mac_addr[ETH_ALEN];
2952 	s32 err = -ENODEV;
2953 	struct wireless_dev *wdev = NULL;
2954 	struct wiphy *wiphy;
2955 	s32 wl_mode;
2956 	dhd_pub_t *dhd;
2957 	wl_iftype_t macaddr_iftype = wl_iftype;
2958 
2959 	printk(KERN_INFO"%s if name: %s, wl_iftype:%d \n", __func__,
2960 		name ? name : "NULL", wl_iftype);
2961 	if (!cfg || !primary_ndev || !name) {
2962 		WL_ERR(("cfg/ndev/name ptr null\n"));
2963 		return NULL;
2964 	}
2965 	if (wl_cfg80211_get_wdev_from_ifname(cfg, name)) {
2966 		WL_ERR(("Interface name %s exists!\n", name));
2967 		return NULL;
2968 	}
2969 
2970 	wiphy = bcmcfg_to_wiphy(cfg);
2971 	dhd = (dhd_pub_t *)(cfg->pub);
2972 	if (!dhd) {
2973 		return NULL;
2974 	}
2975 
2976 	if ((wl_mode = wl_iftype_to_mode(wl_iftype)) < 0) {
2977 		return NULL;
2978 	}
2979 	mutex_lock(&cfg->if_sync);
2980 #ifdef WL_NAN
2981 	if (wl_iftype == WL_IF_TYPE_NAN) {
2982 	/*
2983 	* Bypass the role conflict check for NDI and handle it
2984 	* from dp req and dp resp context
2985 	* because in aware comms, ndi gets created soon after nan enable.
2986 	*/
2987 	} else
2988 #endif /* WL_NAN */
2989 #ifdef WL_IFACE_MGMT
2990 	if ((err = wl_cfg80211_handle_if_role_conflict(cfg, wl_iftype)) < 0) {
2991 		mutex_unlock(&cfg->if_sync);
2992 		return NULL;
2993 	}
2994 #endif /* WL_IFACE_MGMT */
2995 #ifdef DNGL_AXI_ERROR_LOGGING
2996 	/* Check the previous smmu fault error */
2997 	if ((err = _wl_cfg80211_check_axi_error(cfg)) < 0) {
2998 		mutex_unlock(&cfg->if_sync);
2999 		return NULL;
3000 	}
3001 #endif /* DNGL_AXI_ERROR_LOGGING */
3002 	/* Protect the interace op context */
3003 	/* Do pre-create ops */
3004 	wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CREATE_REQ,
3005 		wl_iftype, wl_mode);
3006 
3007 	if (strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)) == 0) {
3008 		macaddr_iftype = WL_IF_TYPE_AP;
3009 	}
3010 
3011 	if (mac) {
3012 		/* If mac address is provided, use that */
3013 		memcpy(mac_addr, mac, ETH_ALEN);
3014 	} else if ((wl_get_vif_macaddr(cfg, macaddr_iftype, mac_addr) != BCME_OK)) {
3015 		/* Fetch the mac address to be used for virtual interface */
3016 		err = -EINVAL;
3017 		goto fail;
3018 	}
3019 
3020 	switch (wl_iftype) {
3021 		case WL_IF_TYPE_IBSS:
3022 			wdev = wl_cfg80211_add_ibss(wiphy, wl_iftype, name);
3023 			break;
3024 		case WL_IF_TYPE_MONITOR:
3025 			wdev = wl_cfg80211_add_monitor_if(wiphy, name);
3026 			break;
3027 		case WL_IF_TYPE_STA:
3028 		case WL_IF_TYPE_AP:
3029 		case WL_IF_TYPE_NAN:
3030 			if (cfg->iface_cnt >= (IFACE_MAX_CNT - 1)) {
3031 				WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
3032 					cfg->iface_cnt));
3033 				err = -ENOTSUPP;
3034 				goto fail;
3035 			}
3036 			wdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
3037 				wl_iftype, mac_addr, name);
3038 			break;
3039 		case WL_IF_TYPE_P2P_DISC:
3040 		case WL_IF_TYPE_P2P_GO:
3041 			/* Intentional fall through */
3042 		case WL_IF_TYPE_P2P_GC:
3043 			if (cfg->p2p_supported) {
3044 				wdev = wl_cfg80211_p2p_if_add(cfg, wl_iftype,
3045 					name, mac_addr, &err);
3046 				break;
3047 			}
3048 			/* Intentionally fall through for unsupported interface
3049 			 * handling when firmware doesn't support p2p
3050 			 */
3051 		default:
3052 			WL_ERR(("Unsupported interface type\n"));
3053 			err = -ENOTSUPP;
3054 			goto fail;
3055 	}
3056 
3057 	if (!wdev) {
3058 		WL_ERR(("vif create failed. err:%d\n", err));
3059 		if (err != -ENOTSUPP) {
3060 			err = -ENODEV;
3061 		}
3062 		goto fail;
3063 	}
3064 
3065 	/* Ensure decrementing in case of failure */
3066 	cfg->vif_count++;
3067 
3068 	wl_cfg80211_iface_state_ops(wdev,
3069 		WL_IF_CREATE_DONE, wl_iftype, wl_mode);
3070 
3071 	WL_INFORM_MEM(("Vif created. dev->ifindex:%d"
3072 		" cfg_iftype:%d, vif_count:%d\n",
3073 		(wdev->netdev ? wdev->netdev->ifindex : 0xff),
3074 		wdev->iftype, cfg->vif_count));
3075 	mutex_unlock(&cfg->if_sync);
3076 	return wdev;
3077 
3078 fail:
3079 	wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3080 		WL_IF_DELETE_REQ, wl_iftype, wl_mode);
3081 
3082 	if (err != -ENOTSUPP) {
3083 		/* For non-supported interfaces, just return error and
3084 		 * skip below recovery steps.
3085 		 */
3086 		SUPP_LOG(("IF_ADD fail. err:%d\n", err));
3087 		wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3088 		if (dhd_query_bus_erros(dhd)) {
3089 			goto exit;
3090 		}
3091 		dhd->iface_op_failed = TRUE;
3092 #if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
3093 		if (dhd->memdump_enabled) {
3094 			dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3095 			dhd_bus_mem_dump(dhd);
3096 		}
3097 #endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
3098 		dhd->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
3099 		net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3100 	}
3101 exit:
3102 	mutex_unlock(&cfg->if_sync);
3103 	return NULL;
3104 }
3105 
3106 static bcm_struct_cfgdev *
wl_cfg80211_add_virtual_iface(struct wiphy * wiphy,const char * name,unsigned char name_assign_type,enum nl80211_iftype type,u32 * flags,struct vif_params * params)3107 wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
3108 #if defined(WL_CFG80211_P2P_DEV_IF)
3109 	const char *name,
3110 #else
3111 	char *name,
3112 #endif /* WL_CFG80211_P2P_DEV_IF */
3113 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
3114 	unsigned char name_assign_type,
3115 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
3116 	enum nl80211_iftype type,
3117 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3118 	u32 *flags,
3119 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3120 	struct vif_params *params)
3121 {
3122 	u16 wl_iftype;
3123 	u16 wl_mode;
3124 	struct net_device *primary_ndev;
3125 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3126 	struct wireless_dev *wdev;
3127 
3128 	WL_DBG(("Enter iftype: %d\n", type));
3129 	if (!cfg) {
3130 		return ERR_PTR(-EINVAL);
3131 	}
3132 
3133 	/* Use primary I/F for sending cmds down to firmware */
3134 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3135 	if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
3136 		WL_ERR(("device is not ready\n"));
3137 		return ERR_PTR(-ENODEV);
3138 	}
3139 
3140 	if (!name) {
3141 		WL_ERR(("Interface name not provided \n"));
3142 		return ERR_PTR(-EINVAL);
3143 	}
3144 
3145 	if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3146 		return ERR_PTR(-EINVAL);
3147 	}
3148 
3149 	wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, name, NULL);
3150 	WL_INFORM_MEM(("add inf ifname=%s, type=%d, primary ifname=%s, wdev=%p, %p\n", name, type, primary_ndev->name, wdev, wdev?wdev->netdev:NULL));
3151 	if (unlikely(!wdev)) {
3152 		return ERR_PTR(-ENODEV);
3153 	}
3154 	return wdev_to_cfgdev(wdev);
3155 }
3156 
3157 static s32
wl_cfg80211_del_ibss(struct wiphy * wiphy,struct wireless_dev * wdev)3158 wl_cfg80211_del_ibss(struct wiphy *wiphy, struct wireless_dev *wdev)
3159 {
3160 	WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev));
3161 #ifdef WLAIBSS_MCHAN
3162 	/* AIBSS */
3163 	return bcm_cfg80211_del_ibss_if(wiphy, wdev);
3164 #else
3165 	/* Normal IBSS */
3166 	return wl_cfg80211_del_iface(wiphy, wdev);
3167 #endif // endif
3168 }
3169 
3170 s32
wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)3171 wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
3172 	struct wireless_dev *wdev, char *ifname)
3173 {
3174 	int ret = BCME_OK;
3175 	mutex_lock(&cfg->if_sync);
3176 	ret = _wl_cfg80211_del_if(cfg, primary_ndev, wdev, ifname);
3177 	mutex_unlock(&cfg->if_sync);
3178 	return ret;
3179 }
3180 
3181 s32
_wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)3182 _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
3183 	struct wireless_dev *wdev, char *ifname)
3184 {
3185 	int ret = BCME_OK;
3186 	s32 bssidx;
3187 	struct wiphy *wiphy;
3188 	u16 wl_mode;
3189 	u16 wl_iftype;
3190 	struct net_info *netinfo;
3191 	dhd_pub_t *dhd;
3192 	BCM_REFERENCE(dhd);
3193 
3194 	if (!cfg) {
3195 		return -EINVAL;
3196 	}
3197 
3198 	dhd = (dhd_pub_t *)(cfg->pub);
3199 
3200 	if (!wdev && ifname) {
3201 		/* If only ifname is provided, fetch corresponding wdev ptr from our
3202 		 * internal data structure
3203 		 */
3204 		wdev = wl_cfg80211_get_wdev_from_ifname(cfg, ifname);
3205 	}
3206 
3207 	/* Check whether we have a valid wdev ptr */
3208 	if (unlikely(!wdev)) {
3209 		WL_ERR(("wdev not found. '%s' does not exists\n", ifname));
3210 		return -ENODEV;
3211 	}
3212 
3213 	WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev->iftype));
3214 
3215 	wiphy = wdev->wiphy;
3216 #ifdef WL_CFG80211_P2P_DEV_IF
3217 	if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
3218 		/* p2p discovery would be de-initialized in stop p2p
3219 		 * device context/from other virtual i/f creation context
3220 		 * so netinfo list may not have any node corresponding to
3221 		 * discovery I/F. Handle it before bssidx check.
3222 		 */
3223 		ret = wl_cfg80211_p2p_if_del(wiphy, wdev);
3224 		if (unlikely(ret)) {
3225 			goto exit;
3226 		} else {
3227 			/* success case. return from here */
3228 			if (cfg->vif_count) {
3229 				cfg->vif_count--;
3230 			}
3231 			return BCME_OK;
3232 		}
3233 	}
3234 #endif /* WL_CFG80211_P2P_DEV_IF */
3235 
3236 	if ((netinfo = wl_get_netinfo_by_wdev(cfg, wdev)) == NULL) {
3237 		WL_ERR(("Find netinfo from wdev %p failed\n", wdev));
3238 		ret = -ENODEV;
3239 		goto exit;
3240 	}
3241 
3242 	if (!wdev->netdev) {
3243 		WL_ERR(("ndev null! \n"));
3244 	} else {
3245 		/* Disable tx before del */
3246 		netif_tx_disable(wdev->netdev);
3247 	}
3248 
3249 	wl_iftype = netinfo->iftype;
3250 	wl_mode = wl_iftype_to_mode(wl_iftype);
3251 	bssidx = netinfo->bssidx;
3252 	WL_INFORM_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
3253 		wdev->iftype, wl_iftype, wl_mode, bssidx));
3254 
3255 	/* Do pre-interface del ops */
3256 	wl_cfg80211_iface_state_ops(wdev, WL_IF_DELETE_REQ, wl_iftype, wl_mode);
3257 
3258 	switch (wl_iftype) {
3259 		case WL_IF_TYPE_P2P_GO:
3260 		case WL_IF_TYPE_P2P_GC:
3261 		case WL_IF_TYPE_AP:
3262 		case WL_IF_TYPE_STA:
3263 		case WL_IF_TYPE_NAN:
3264 			ret = wl_cfg80211_del_iface(wiphy, wdev);
3265 			break;
3266 		case WL_IF_TYPE_IBSS:
3267 			ret = wl_cfg80211_del_ibss(wiphy, wdev);
3268 			break;
3269 
3270 		default:
3271 			WL_ERR(("Unsupported interface type\n"));
3272 			ret = BCME_ERROR;
3273 	}
3274 
3275 exit:
3276 	if (ret == BCME_OK) {
3277 		/* Successful case */
3278 		if (cfg->vif_count) {
3279 			cfg->vif_count--;
3280 		}
3281 		wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3282 				WL_IF_DELETE_DONE, wl_iftype, wl_mode);
3283 #ifdef WL_NAN
3284 		if (!((cfg->nancfg.mac_rand) && (wl_iftype == WL_IF_TYPE_NAN)))
3285 #endif /* WL_NAN */
3286 		{
3287 			wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype);
3288 		}
3289 		WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg->vif_count));
3290 	} else {
3291 		if (!wdev->netdev) {
3292 			WL_ERR(("ndev null! \n"));
3293 		} else {
3294 			/* IF del failed. revert back tx queue status */
3295 			netif_tx_start_all_queues(wdev->netdev);
3296 		}
3297 
3298 		/* Skip generating log files and sending HANG event
3299 		 * if driver state is not READY
3300 		 */
3301 		if (wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg))) {
3302 			SUPP_LOG(("IF_DEL fail. err:%d\n", ret));
3303 			wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3304 			/* IF dongle is down due to previous hang or other conditions, sending
3305 			* one more hang notification is not needed.
3306 			*/
3307 			if (dhd_query_bus_erros(dhd) || (ret == BCME_DONGLE_DOWN)) {
3308 				goto end;
3309 			}
3310 			dhd->iface_op_failed = TRUE;
3311 #if defined(DHD_FW_COREDUMP)
3312 			if (dhd->memdump_enabled && (ret != -EBADTYPE)) {
3313 				dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3314 				dhd_bus_mem_dump(dhd);
3315 			}
3316 #endif /* DHD_FW_COREDUMP */
3317 			WL_ERR(("Notify hang event to upper layer \n"));
3318 			dhd->hang_reason = HANG_REASON_IFACE_DEL_FAILURE;
3319 			net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3320 		}
3321 	}
3322 end:
3323 	return ret;
3324 }
3325 
3326 static s32
wl_cfg80211_del_virtual_iface(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev)3327 wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
3328 {
3329 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3330 	struct wireless_dev *wdev = cfgdev_to_wdev(cfgdev);
3331 	int ret = BCME_OK;
3332 	u16 wl_iftype;
3333 	u16 wl_mode;
3334 	struct net_device *primary_ndev;
3335 
3336 	if (!cfg) {
3337 		return -EINVAL;
3338 	}
3339 
3340 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3341 	wdev = cfgdev_to_wdev(cfgdev);
3342 	if (!wdev) {
3343 		WL_ERR(("wdev null"));
3344 		return -ENODEV;
3345 	}
3346 
3347 	WL_DBG(("Enter  wdev:%p iftype: %d\n", wdev, wdev->iftype));
3348 	if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
3349 		WL_ERR(("Wrong iftype: %d\n", wdev->iftype));
3350 		return -ENODEV;
3351 	}
3352 
3353 	if ((ret = wl_cfg80211_del_if(cfg, primary_ndev,
3354 			wdev, NULL)) < 0) {
3355 		WL_ERR(("IF del failed\n"));
3356 	}
3357 
3358 	return ret;
3359 }
3360 
3361 static s32
wl_cfg80211_change_p2prole(struct wiphy * wiphy,struct net_device * ndev,enum nl80211_iftype type)3362 wl_cfg80211_change_p2prole(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type)
3363 {
3364 	s32 wlif_type;
3365 	s32 mode = 0;
3366 	s32 index;
3367 	s32 err;
3368 	s32 conn_idx = -1;
3369 	chanspec_t chspec;
3370 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3371 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3372 
3373 	WL_INFORM_MEM(("Enter. current_role:%d new_role:%d \n", ndev->ieee80211_ptr->iftype, type));
3374 
3375 	if (!cfg->p2p || !wl_cfgp2p_vif_created(cfg)) {
3376 		WL_ERR(("P2P not initialized \n"));
3377 		return -EINVAL;
3378 	}
3379 
3380 	if (!is_p2p_group_iface(ndev->ieee80211_ptr)) {
3381 		WL_ERR(("Wrong if type \n"));
3382 		return -EINVAL;
3383 	}
3384 
3385 	/* Abort any on-going scans to avoid race condition issues */
3386 	wl_cfg80211_cancel_scan(cfg);
3387 
3388 	index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
3389 	if (index < 0) {
3390 		WL_ERR(("Find bsscfg index from ndev(%p) failed\n", ndev));
3391 		return BCME_ERROR;
3392 	}
3393 	if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK) {
3394 		return BCME_ERROR;
3395 	}
3396 
3397 	/* In concurrency case, STA may be already associated in a particular
3398 	 * channel. so retrieve the current channel of primary interface and
3399 	 * then start the virtual interface on that.
3400 	 */
3401 	chspec = wl_cfg80211_get_shared_freq(wiphy);
3402 	if (type == NL80211_IFTYPE_P2P_GO) {
3403 		/* Dual p2p doesn't support multiple P2PGO interfaces,
3404 		 * p2p_go_count is the counter for GO creation
3405 		 * requests.
3406 		 */
3407 		if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
3408 			WL_ERR(("FW does not support multiple GO\n"));
3409 			return BCME_ERROR;
3410 		}
3411 		mode = WL_MODE_AP;
3412 		wlif_type = WL_P2P_IF_GO;
3413 		dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
3414 		dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
3415 	} else {
3416 		wlif_type = WL_P2P_IF_CLIENT;
3417 		/* for GO */
3418 		if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
3419 			WL_INFORM_MEM(("Downgrading P2P GO to cfg_iftype:%d \n", type));
3420 			wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
3421 			cfg->p2p->p2p_go_count--;
3422 			/* disable interface before bsscfg free */
3423 			err = wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx));
3424 			/* if fw doesn't support "ifdis",
3425 			 * do not wait for link down of ap mode
3426 			 */
3427 			if (err == 0) {
3428 				WL_DBG(("Wait for Link Down event for GO !!!\n"));
3429 				wait_for_completion_timeout(&cfg->iface_disable,
3430 					msecs_to_jiffies(500));
3431 			} else if (err != BCME_UNSUPPORTED) {
3432 				msleep(300);
3433 			}
3434 		}
3435 	}
3436 
3437 	wl_set_p2p_status(cfg, IF_CHANGING);
3438 	wl_clr_p2p_status(cfg, IF_CHANGED);
3439 	wl_cfgp2p_ifchange(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx),
3440 		htod32(wlif_type), chspec, conn_idx);
3441 	wait_event_interruptible_timeout(cfg->netif_change_event,
3442 		(wl_get_p2p_status(cfg, IF_CHANGED) == true),
3443 		msecs_to_jiffies(MAX_WAIT_TIME));
3444 
3445 	wl_clr_p2p_status(cfg, IF_CHANGING);
3446 	wl_clr_p2p_status(cfg, IF_CHANGED);
3447 
3448 	if (mode == WL_MODE_AP) {
3449 		wl_set_drv_status(cfg, CONNECTED, ndev);
3450 	}
3451 
3452 	return BCME_OK;
3453 }
3454 
3455 static s32
wl_cfg80211_change_virtual_iface(struct wiphy * wiphy,struct net_device * ndev,enum nl80211_iftype type,u32 * flags,struct vif_params * params)3456 wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
3457 	enum nl80211_iftype type,
3458 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3459 	u32 *flags,
3460 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3461 	struct vif_params *params)
3462 {
3463 	s32 infra = 1;
3464 	s32 err = BCME_OK;
3465 	u16 wl_iftype;
3466 	u16 wl_mode;
3467 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3468 	struct net_info *netinfo = NULL;
3469 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3470 	struct net_device *primary_ndev;
3471 
3472 	if (!dhd)
3473 		return -EINVAL;
3474 
3475 	printk(KERN_INFO"[%s] Enter. current cfg_iftype:%d new cfg_iftype:%d \n",
3476 		ndev->name, ndev->ieee80211_ptr->iftype, type);
3477 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3478 
3479 	if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3480 		WL_ERR(("Unknown role \n"));
3481 		return -EINVAL;
3482 	}
3483 
3484 	mutex_lock(&cfg->if_sync);
3485 	netinfo = wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
3486 	if (unlikely(!netinfo)) {
3487 #ifdef WL_STATIC_IF
3488 		if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
3489 			/* Incase of static interfaces, the netinfo will be
3490 			 * allocated only when FW interface is initialized. So
3491 			 * store the value and use it during initialization.
3492 			 */
3493 			WL_INFORM_MEM(("skip change vif for static if\n"));
3494 			ndev->ieee80211_ptr->iftype = type;
3495 			err = BCME_OK;
3496 		} else
3497 #endif /* WL_STATIC_IF */
3498 		{
3499 			WL_ERR(("netinfo not found \n"));
3500 			err = -ENODEV;
3501 		}
3502 		goto fail;
3503 	}
3504 
3505 	/* perform pre-if-change tasks */
3506 	wl_cfg80211_iface_state_ops(ndev->ieee80211_ptr,
3507 		WL_IF_CHANGE_REQ, wl_iftype, wl_mode);
3508 
3509 	switch (type) {
3510 	case NL80211_IFTYPE_ADHOC:
3511 		infra = 0;
3512 		break;
3513 	case NL80211_IFTYPE_STATION:
3514 		/* Supplicant sets iftype to STATION while removing p2p GO */
3515 		if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
3516 			/* Downgrading P2P GO */
3517 			err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3518 			if (unlikely(err)) {
3519 				WL_ERR(("P2P downgrade failed \n"));
3520 			}
3521 		} else if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
3522 			/* Downgrade role from AP to STA */
3523 			if ((err = wl_cfg80211_add_del_bss(cfg, ndev,
3524 				netinfo->bssidx, wl_iftype, 0, NULL)) < 0) {
3525 				WL_ERR(("AP-STA Downgrade failed \n"));
3526 				goto fail;
3527 			}
3528 		}
3529 		break;
3530 	case NL80211_IFTYPE_AP:
3531 		/* intentional fall through */
3532 	case NL80211_IFTYPE_AP_VLAN:
3533 		{
3534 			if (!wl_get_drv_status(cfg, AP_CREATED, ndev) &&
3535 					wl_get_drv_status(cfg, READY, ndev)) {
3536 				err = wl_cfg80211_set_ap_role(cfg, ndev);
3537 				if (unlikely(err)) {
3538 					WL_ERR(("set ap role failed!\n"));
3539 					goto fail;
3540 				}
3541 			} else {
3542 				WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
3543 			}
3544 			break;
3545 		}
3546 	case NL80211_IFTYPE_P2P_GO:
3547 		/* Intentional fall through */
3548 	case NL80211_IFTYPE_P2P_CLIENT:
3549 		infra = 1;
3550 		err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3551 		break;
3552 	case NL80211_IFTYPE_MONITOR:
3553 	case NL80211_IFTYPE_WDS:
3554 	case NL80211_IFTYPE_MESH_POINT:
3555 		/* Intentional fall through */
3556 	default:
3557 		WL_ERR(("Unsupported type:%d \n", type));
3558 		err = -EINVAL;
3559 		goto fail;
3560 	}
3561 
3562 	if (wl_get_drv_status(cfg, READY, ndev)) {
3563 		err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(s32));
3564 		if (err < 0) {
3565 			WL_ERR(("SET INFRA/IBSS  error %d\n", err));
3566 			goto fail;
3567 		}
3568 	}
3569 
3570 	wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3571 		WL_IF_CHANGE_DONE, wl_iftype, wl_mode);
3572 
3573 	/* Update new iftype in relevant structures */
3574 	ndev->ieee80211_ptr->iftype = type;
3575 	netinfo->iftype = wl_iftype;
3576 	WL_INFORM_MEM(("[%s] cfg_iftype changed to %d\n", ndev->name, type));
3577 #ifdef WL_EXT_IAPSTA
3578 	wl_ext_iapsta_update_iftype(ndev, netinfo->ifidx, wl_iftype);
3579 #endif
3580 
3581 fail:
3582 	if (err) {
3583 		wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
3584 	}
3585 	mutex_unlock(&cfg->if_sync);
3586 	return err;
3587 }
3588 
3589 s32
wl_cfg80211_notify_ifadd(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx,uint8 role)3590 wl_cfg80211_notify_ifadd(struct net_device *dev,
3591 	int ifidx, char *name, uint8 *mac, uint8 bssidx, uint8 role)
3592 {
3593 	bool ifadd_expected = FALSE;
3594 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3595 	bool bss_pending_op = TRUE;
3596 
3597 	/* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
3598 	 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
3599 	 */
3600 	if (wl_get_p2p_status(cfg, IF_CHANGING))
3601 		return wl_cfg80211_notify_ifchange(dev, ifidx, name, mac, bssidx);
3602 
3603 	/* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
3604 	if (wl_get_p2p_status(cfg, IF_ADDING)) {
3605 		ifadd_expected = TRUE;
3606 		wl_clr_p2p_status(cfg, IF_ADDING);
3607 	} else if (cfg->bss_pending_op) {
3608 		ifadd_expected = TRUE;
3609 		bss_pending_op = FALSE;
3610 	}
3611 
3612 	if (ifadd_expected) {
3613 		wl_if_event_info *if_event_info = &cfg->if_event_info;
3614 
3615 		if_event_info->valid = TRUE;
3616 		if_event_info->ifidx = ifidx;
3617 		if_event_info->bssidx = bssidx;
3618 		if_event_info->role = role;
3619 		strlcpy(if_event_info->name, name, sizeof(if_event_info->name));
3620 		if_event_info->name[IFNAMSIZ - 1] = '\0';
3621 		if (mac)
3622 			memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
3623 
3624 		/* Update bss pendig operation status */
3625 		if (!bss_pending_op) {
3626 			cfg->bss_pending_op = FALSE;
3627 		}
3628 		WL_INFORM_MEM(("IF_ADD ifidx:%d bssidx:%d role:%d\n",
3629 			ifidx, bssidx, role));
3630 		OSL_SMP_WMB();
3631 		wake_up_interruptible(&cfg->netif_change_event);
3632 		return BCME_OK;
3633 	}
3634 
3635 	return BCME_ERROR;
3636 }
3637 
3638 s32
wl_cfg80211_notify_ifdel(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)3639 wl_cfg80211_notify_ifdel(struct net_device *dev, int ifidx, char *name, uint8 *mac, uint8 bssidx)
3640 {
3641 	bool ifdel_expected = FALSE;
3642 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3643 	wl_if_event_info *if_event_info = &cfg->if_event_info;
3644 	bool bss_pending_op = TRUE;
3645 
3646 	if (wl_get_p2p_status(cfg, IF_DELETING)) {
3647 		ifdel_expected = TRUE;
3648 		wl_clr_p2p_status(cfg, IF_DELETING);
3649 	} else if (cfg->bss_pending_op) {
3650 		ifdel_expected = TRUE;
3651 		bss_pending_op = FALSE;
3652 	}
3653 
3654 	if (ifdel_expected) {
3655 		if_event_info->valid = TRUE;
3656 		if_event_info->ifidx = ifidx;
3657 		if_event_info->bssidx = bssidx;
3658 		/* Update bss pendig operation status */
3659 		if (!bss_pending_op) {
3660 			cfg->bss_pending_op = FALSE;
3661 		}
3662 		WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx, bssidx));
3663 		OSL_SMP_WMB();
3664 		wake_up_interruptible(&cfg->netif_change_event);
3665 		return BCME_OK;
3666 	}
3667 
3668 	return BCME_ERROR;
3669 }
3670 
3671 s32
wl_cfg80211_notify_ifchange(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)3672 wl_cfg80211_notify_ifchange(struct net_device * dev, int ifidx, char *name, uint8 *mac,
3673 	uint8 bssidx)
3674 {
3675 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3676 
3677 	if (wl_get_p2p_status(cfg, IF_CHANGING)) {
3678 		wl_set_p2p_status(cfg, IF_CHANGED);
3679 		OSL_SMP_WMB();
3680 		wake_up_interruptible(&cfg->netif_change_event);
3681 		return BCME_OK;
3682 	}
3683 
3684 	return BCME_ERROR;
3685 }
3686 
wl_set_rts(struct net_device * dev,u32 rts_threshold)3687 static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
3688 {
3689 	s32 err = 0;
3690 
3691 	err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
3692 	if (unlikely(err)) {
3693 		WL_ERR(("Error (%d)\n", err));
3694 		return err;
3695 	}
3696 	return err;
3697 }
3698 
wl_set_frag(struct net_device * dev,u32 frag_threshold)3699 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
3700 {
3701 	s32 err = 0;
3702 
3703 	err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
3704 	if (unlikely(err)) {
3705 		WL_ERR(("Error (%d)\n", err));
3706 		return err;
3707 	}
3708 	return err;
3709 }
3710 
wl_set_retry(struct net_device * dev,u32 retry,bool l)3711 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
3712 {
3713 	s32 err = 0;
3714 	u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
3715 
3716 #ifdef CUSTOM_LONG_RETRY_LIMIT
3717 	if ((cmd == WLC_SET_LRL) &&
3718 		(retry != CUSTOM_LONG_RETRY_LIMIT)) {
3719 		WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
3720 		return err;
3721 	}
3722 #endif /* CUSTOM_LONG_RETRY_LIMIT */
3723 
3724 	retry = htod32(retry);
3725 	err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry));
3726 	if (unlikely(err)) {
3727 		WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
3728 		return err;
3729 	}
3730 	return err;
3731 }
3732 
wl_cfg80211_set_wiphy_params(struct wiphy * wiphy,u32 changed)3733 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
3734 {
3735 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
3736 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
3737 	s32 err = 0;
3738 
3739 	RETURN_EIO_IF_NOT_UP(cfg);
3740 	WL_DBG(("Enter\n"));
3741 	if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
3742 		(cfg->conf->rts_threshold != wiphy->rts_threshold)) {
3743 		cfg->conf->rts_threshold = wiphy->rts_threshold;
3744 		err = wl_set_rts(ndev, cfg->conf->rts_threshold);
3745 		if (err != BCME_OK)
3746 			return err;
3747 	}
3748 	if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
3749 		(cfg->conf->frag_threshold != wiphy->frag_threshold)) {
3750 		cfg->conf->frag_threshold = wiphy->frag_threshold;
3751 		err = wl_set_frag(ndev, cfg->conf->frag_threshold);
3752 		if (err != BCME_OK)
3753 			return err;
3754 	}
3755 	if (changed & WIPHY_PARAM_RETRY_LONG &&
3756 		(cfg->conf->retry_long != wiphy->retry_long)) {
3757 		cfg->conf->retry_long = wiphy->retry_long;
3758 		err = wl_set_retry(ndev, cfg->conf->retry_long, true);
3759 		if (err != BCME_OK)
3760 			return err;
3761 	}
3762 	if (changed & WIPHY_PARAM_RETRY_SHORT &&
3763 		(cfg->conf->retry_short != wiphy->retry_short)) {
3764 		cfg->conf->retry_short = wiphy->retry_short;
3765 		err = wl_set_retry(ndev, cfg->conf->retry_short, false);
3766 		if (err != BCME_OK) {
3767 			return err;
3768 		}
3769 	}
3770 
3771 	return err;
3772 }
3773 static chanspec_t
channel_to_chanspec(struct wiphy * wiphy,struct net_device * dev,u32 channel,u32 bw_cap)3774 channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap)
3775 {
3776 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3777 	u8 *buf = NULL;
3778 	wl_uint32_list_t *list;
3779 	int err = BCME_OK;
3780 	chanspec_t c = 0, ret_c = 0;
3781 	int bw = 0, tmp_bw = 0;
3782 	int i;
3783 	u32 tmp_c;
3784 
3785 #define LOCAL_BUF_SIZE	1024
3786 	buf = (u8 *)MALLOC(cfg->osh, LOCAL_BUF_SIZE);
3787 	if (!buf) {
3788 		WL_ERR(("buf memory alloc failed\n"));
3789 		goto exit;
3790 	}
3791 
3792 	err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
3793 		0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync);
3794 	if (err != BCME_OK) {
3795 		WL_ERR(("get chanspecs failed with %d\n", err));
3796 		goto exit;
3797 	}
3798 
3799 	list = (wl_uint32_list_t *)(void *)buf;
3800 	for (i = 0; i < dtoh32(list->count); i++) {
3801 		c = dtoh32(list->element[i]);
3802 		if (channel <= CH_MAX_2G_CHANNEL) {
3803 			if (!CHSPEC_IS20(c))
3804 				continue;
3805 			if (channel == CHSPEC_CHANNEL(c)) {
3806 				ret_c = c;
3807 				bw = 20;
3808 				goto exit;
3809 			}
3810 		}
3811 		tmp_c = wf_chspec_ctlchan(c);
3812 		tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT];
3813 		if (tmp_c != channel)
3814 			continue;
3815 
3816 		if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) {
3817 			bw = tmp_bw;
3818 			ret_c = c;
3819 			if (bw == bw_cap)
3820 				goto exit;
3821 		}
3822 	}
3823 exit:
3824 	if (buf) {
3825 		 MFREE(cfg->osh, buf, LOCAL_BUF_SIZE);
3826 	}
3827 #undef LOCAL_BUF_SIZE
3828 	WL_DBG(("return chanspec %x %d\n", ret_c, bw));
3829 	return ret_c;
3830 }
3831 
3832 void
wl_cfg80211_ibss_vsie_set_buffer(struct net_device * dev,vndr_ie_setbuf_t * ibss_vsie,int ibss_vsie_len)3833 wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev, vndr_ie_setbuf_t *ibss_vsie,
3834 	int ibss_vsie_len)
3835 {
3836 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3837 
3838 	if (cfg != NULL && ibss_vsie != NULL) {
3839 		if (cfg->ibss_vsie != NULL) {
3840 			MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3841 		}
3842 		cfg->ibss_vsie = ibss_vsie;
3843 		cfg->ibss_vsie_len = ibss_vsie_len;
3844 	}
3845 }
3846 
3847 static void
wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 * cfg)3848 wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
3849 {
3850 	/* free & initiralize VSIE (Vendor Specific IE) */
3851 	if (cfg->ibss_vsie != NULL) {
3852 		MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3853 		cfg->ibss_vsie_len = 0;
3854 	}
3855 }
3856 
3857 s32
wl_cfg80211_ibss_vsie_delete(struct net_device * dev)3858 wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
3859 {
3860 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3861 	char *ioctl_buf = NULL;
3862 	s32 ret = BCME_OK, bssidx;
3863 
3864 	if (cfg != NULL && cfg->ibss_vsie != NULL) {
3865 		ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
3866 		if (!ioctl_buf) {
3867 			WL_ERR(("ioctl memory alloc failed\n"));
3868 			return -ENOMEM;
3869 		}
3870 		if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3871 			WL_ERR(("Find index failed\n"));
3872 			ret = BCME_ERROR;
3873 			goto end;
3874 		}
3875 		/* change the command from "add" to "del" */
3876 		strlcpy(cfg->ibss_vsie->cmd, "del", sizeof(cfg->ibss_vsie->cmd));
3877 
3878 		ret = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie",
3879 				cfg->ibss_vsie, cfg->ibss_vsie_len,
3880 				ioctl_buf, WLC_IOCTL_MEDLEN, bssidx, NULL);
3881 		WL_ERR(("ret=%d\n", ret));
3882 
3883 		if (ret == BCME_OK) {
3884 			/* Free & initialize VSIE */
3885 			MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3886 			cfg->ibss_vsie_len = 0;
3887 		}
3888 end:
3889 		if (ioctl_buf) {
3890 			MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3891 		}
3892 	}
3893 
3894 	return ret;
3895 }
3896 
3897 #ifdef WLAIBSS_MCHAN
3898 static bcm_struct_cfgdev*
bcm_cfg80211_add_ibss_if(struct wiphy * wiphy,char * name)3899 bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name)
3900 {
3901 	int err = 0;
3902 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3903 	struct wireless_dev* wdev = NULL;
3904 	struct net_device *new_ndev = NULL;
3905 	struct net_device *primary_ndev = NULL;
3906 	long timeout;
3907 	wl_aibss_if_t aibss_if;
3908 	wl_if_event_info *event = NULL;
3909 
3910 	if (cfg->ibss_cfgdev != NULL) {
3911 		WL_ERR(("IBSS interface %s already exists\n", name));
3912 		return NULL;
3913 	}
3914 
3915 	WL_ERR(("Try to create IBSS interface %s\n", name));
3916 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3917 	/* generate a new MAC address for the IBSS interface */
3918 	get_primary_mac(cfg, &cfg->ibss_if_addr);
3919 	cfg->ibss_if_addr.octet[4] ^= 0x40;
3920 	bzero(&aibss_if, sizeof(aibss_if));
3921 	memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
3922 	aibss_if.chspec = 0;
3923 	aibss_if.len = sizeof(aibss_if);
3924 
3925 	cfg->bss_pending_op = TRUE;
3926 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3927 	err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
3928 		sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3929 	if (err) {
3930 		WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
3931 		goto fail;
3932 	}
3933 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3934 		!cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
3935 	if (timeout <= 0 || cfg->bss_pending_op)
3936 		goto fail;
3937 
3938 	event = &cfg->if_event_info;
3939 	/* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
3940 	 * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
3941 	 * and will be freed by dhd_detach unless it gets unregistered before that. The
3942 	 * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
3943 	 * be freed by wl_dealloc_netinfo
3944 	 */
3945 	new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name,
3946 		event->mac, event->bssidx, event->name);
3947 	if (new_ndev == NULL)
3948 		goto fail;
3949 	wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
3950 	if (wdev == NULL)
3951 		goto fail;
3952 	wdev->wiphy = wiphy;
3953 	wdev->iftype = NL80211_IFTYPE_ADHOC;
3954 	wdev->netdev = new_ndev;
3955 	new_ndev->ieee80211_ptr = wdev;
3956 	SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
3957 
3958 	/* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
3959 	* needs to be modified to take one parameter (bool need_rtnl_lock)
3960 	 */
3961 	ASSERT_RTNL();
3962 	if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, FALSE) != BCME_OK)
3963 		goto fail;
3964 
3965 	wl_alloc_netinfo(cfg, new_ndev, wdev, WL_IF_TYPE_IBSS,
3966 		PM_ENABLE, event->bssidx, event->ifidx);
3967 	cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
3968 	WL_ERR(("IBSS interface %s created\n", new_ndev->name));
3969 	return cfg->ibss_cfgdev;
3970 
3971 fail:
3972 	WL_ERR(("failed to create IBSS interface %s \n", name));
3973 	cfg->bss_pending_op = FALSE;
3974 	if (new_ndev)
3975 		wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
3976 	if (wdev) {
3977 		MFREE(cfg->osh, wdev, sizeof(*wdev));
3978 	}
3979 	return NULL;
3980 }
3981 
3982 static s32
bcm_cfg80211_del_ibss_if(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev)3983 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
3984 {
3985 	int err = 0;
3986 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3987 	struct net_device *ndev = NULL;
3988 	struct net_device *primary_ndev = NULL;
3989 	long timeout;
3990 
3991 	if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet))
3992 		return -EINVAL;
3993 	ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev);
3994 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3995 
3996 	cfg->bss_pending_op = TRUE;
3997 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3998 	err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
3999 		sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4000 	if (err) {
4001 		WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
4002 		goto fail;
4003 	}
4004 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4005 		!cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4006 	if (timeout <= 0 || cfg->bss_pending_op) {
4007 		WL_ERR(("timeout in waiting IF_DEL event\n"));
4008 		goto fail;
4009 	}
4010 
4011 	wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
4012 	cfg->ibss_cfgdev = NULL;
4013 	return 0;
4014 
4015 fail:
4016 	cfg->bss_pending_op = FALSE;
4017 	return -1;
4018 }
4019 #endif /* WLAIBSS_MCHAN */
4020 
4021 s32
wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)4022 wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)
4023 {
4024 	s32 ret = BCME_ERROR;
4025 
4026 	switch (iftype) {
4027 		case WL_IF_TYPE_AP:
4028 			ret = WL_INTERFACE_TYPE_AP;
4029 			break;
4030 		case WL_IF_TYPE_STA:
4031 			ret = WL_INTERFACE_TYPE_STA;
4032 			break;
4033 		case WL_IF_TYPE_NAN_NMI:
4034 		case WL_IF_TYPE_NAN:
4035 			ret = WL_INTERFACE_TYPE_NAN;
4036 			break;
4037 		case WL_IF_TYPE_P2P_DISC:
4038 			ret = WL_INTERFACE_TYPE_P2P_DISC;
4039 			break;
4040 		case WL_IF_TYPE_P2P_GO:
4041 			ret = WL_INTERFACE_TYPE_P2P_GO;
4042 			break;
4043 		case WL_IF_TYPE_P2P_GC:
4044 			ret = WL_INTERFACE_TYPE_P2P_GC;
4045 			break;
4046 
4047 		default:
4048 			WL_ERR(("Unsupported type:%d \n", iftype));
4049 			ret = -EINVAL;
4050 			break;
4051 	}
4052 	return ret;
4053 }
4054 
4055 s32
wl_cfg80211_interface_ops(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,wl_iftype_t cfg_iftype,s32 del,u8 * addr)4056 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
4057 	struct net_device *ndev, s32 bsscfg_idx,
4058 	wl_iftype_t cfg_iftype, s32 del, u8 *addr)
4059 {
4060 	s32 ret;
4061 	struct wl_interface_create_v2 iface;
4062 	wl_interface_create_v3_t iface_v3;
4063 	wl_interface_create_t iface_v0;
4064 	struct wl_interface_info_v1 *info;
4065 	wl_interface_info_v2_t *info_v2;
4066 	wl_interface_info_t *info_v0;
4067 	uint32 ifflags = 0;
4068 	bool use_iface_info_v2 = false;
4069 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
4070 	s32 iftype;
4071 
4072 	if (del) {
4073 		ret = wldev_iovar_setbuf(ndev, "interface_remove",
4074 			NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL);
4075 		if (unlikely(ret))
4076 			WL_ERR(("Interface remove failed!! ret %d\n", ret));
4077 		return ret;
4078 	}
4079 
4080 	/* Interface create */
4081 	bzero(&iface, sizeof(iface));
4082 	/*
4083 	 * flags field is still used along with iftype inorder to support the old version of the
4084 	 * FW work with the latest app changes.
4085 	 */
4086 
4087 	iftype = wl_cfg80211_to_fw_iftype(cfg_iftype);
4088 	if (iftype < 0) {
4089 		return -ENOTSUPP;
4090 	}
4091 
4092 	if (addr) {
4093 		ifflags |= WL_INTERFACE_MAC_USE;
4094 	}
4095 
4096 	/* Pass ver = 0 for fetching the interface_create iovar version */
4097 	if (wl_legacy_chip_check(ndev)) {
4098 		bzero(&iface_v0, sizeof(iface_v0));
4099 		iface_v0.ver = WL_INTERFACE_CREATE_VER;
4100 		iface_v0.flags = iftype | ifflags;
4101 		if (addr) {
4102 			memcpy(&iface_v0.mac_addr.octet, addr, ETH_ALEN);
4103 		}
4104 		ret = wldev_iovar_getbuf(ndev, "interface_create",
4105 			&iface_v0, sizeof(struct wl_interface_create),
4106 			ioctl_buf, sizeof(ioctl_buf), NULL);
4107 		if (ret == 0) {
4108 			info_v0 = (wl_interface_info_t *)ioctl_buf;
4109 			ret = info_v0->bsscfgidx;
4110 			goto exit;
4111         }
4112 	} else {
4113 		ret = wldev_iovar_getbuf(ndev, "interface_create",
4114 			&iface, sizeof(struct wl_interface_create_v2),
4115 			ioctl_buf, sizeof(ioctl_buf), NULL);
4116 	}
4117 	if (ret == BCME_UNSUPPORTED) {
4118 		WL_ERR(("interface_create iovar not supported\n"));
4119 		return ret;
4120 	} else if ((ret == 0) && *((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3) {
4121 		WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags));
4122 		use_iface_info_v2 = true;
4123 		bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
4124 		iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
4125 		iface_v3.iftype = iftype;
4126 		iface_v3.flags = ifflags;
4127 		if (addr) {
4128 			memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
4129 		}
4130 		ret = wldev_iovar_getbuf(ndev, "interface_create",
4131 			&iface_v3, sizeof(wl_interface_create_v3_t),
4132 			ioctl_buf, sizeof(ioctl_buf), NULL);
4133 	} else {
4134 		/* On any other error, attempt with iovar version 2 */
4135 		WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n", ret, ifflags));
4136 		iface.ver = WL_INTERFACE_CREATE_VER_2;
4137 		iface.iftype = iftype;
4138 		iface.flags = ifflags;
4139 		if (addr) {
4140 			memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
4141 		}
4142 		ret = wldev_iovar_getbuf(ndev, "interface_create",
4143 			&iface, sizeof(struct wl_interface_create_v2),
4144 			ioctl_buf, sizeof(ioctl_buf), NULL);
4145 	}
4146 
4147 	if (unlikely(ret)) {
4148 		WL_ERR(("Interface create failed!! ret %d\n", ret));
4149 		return ret;
4150 	}
4151 
4152 	/* success case */
4153 	if (use_iface_info_v2 == true) {
4154 		info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
4155 		ret = info_v2->bsscfgidx;
4156 	} else {
4157 		/* Use v1 struct */
4158 		info = (struct wl_interface_info_v1 *)ioctl_buf;
4159 		ret = info->bsscfgidx;
4160 	}
4161 
4162 exit:
4163 	WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
4164 	return ret;
4165 }
4166 
4167 s32
wl_cfg80211_add_del_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,wl_iftype_t brcm_iftype,s32 del,u8 * addr)4168 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
4169 	struct net_device *ndev, s32 bsscfg_idx,
4170 	wl_iftype_t brcm_iftype, s32 del, u8 *addr)
4171 {
4172 	s32 ret = BCME_OK;
4173 	s32 val = 0;
4174 
4175 	struct {
4176 		s32 cfg;
4177 		s32 val;
4178 		struct ether_addr ea;
4179 	} bss_setbuf;
4180 
4181 	WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype, del));
4182 
4183 	bzero(&bss_setbuf, sizeof(bss_setbuf));
4184 
4185 	/* AP=2, STA=3, up=1, down=0, val=-1 */
4186 	if (del) {
4187 		val = WLC_AP_IOV_OP_DELETE;
4188 	} else if (brcm_iftype == WL_IF_TYPE_AP) {
4189 		/* Add/role change to AP Interface */
4190 		WL_DBG(("Adding AP Interface \n"));
4191 		val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
4192 	} else if (brcm_iftype == WL_IF_TYPE_STA) {
4193 		/* Add/role change to STA Interface */
4194 		WL_DBG(("Adding STA Interface \n"));
4195 		val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
4196 	} else {
4197 		WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype));
4198 		return -EINVAL;
4199 	}
4200 
4201 	if (!del) {
4202 		wl_ext_bss_iovar_war(ndev, &val);
4203 	}
4204 
4205 	bss_setbuf.cfg = htod32(bsscfg_idx);
4206 	bss_setbuf.val = htod32(val);
4207 
4208 	if (addr) {
4209 		memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
4210 	}
4211 
4212 	WL_MSG(ndev->name, "wl bss %d bssidx:%d\n", val, bsscfg_idx);
4213 	ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4214 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4215 	if (ret != 0)
4216 		WL_ERR(("'bss %d' failed with %d\n", val, ret));
4217 
4218 	return ret;
4219 }
4220 
4221 s32
wl_cfg80211_bss_up(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,s32 bss_up)4222 wl_cfg80211_bss_up(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 bss_up)
4223 {
4224 	s32 ret = BCME_OK;
4225 	s32 val = bss_up ? 1 : 0;
4226 
4227 	struct {
4228 		s32 cfg;
4229 		s32 val;
4230 	} bss_setbuf;
4231 
4232 	bss_setbuf.cfg = htod32(bsscfg_idx);
4233 	bss_setbuf.val = htod32(val);
4234 
4235 	WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx, bss_up ? "up" : "down"));
4236 	ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4237 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4238 
4239 	if (ret != 0) {
4240 		WL_ERR(("'bss %d' failed with %d\n", bss_up, ret));
4241 	}
4242 
4243 	return ret;
4244 }
4245 
4246 bool
wl_cfg80211_bss_isup(struct net_device * ndev,int bsscfg_idx)4247 wl_cfg80211_bss_isup(struct net_device *ndev, int bsscfg_idx)
4248 {
4249 	s32 result, val;
4250 	bool isup = false;
4251 	s8 getbuf[64];
4252 
4253 	/* Check if the BSS is up */
4254 	*(int*)getbuf = -1;
4255 	result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
4256 		sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
4257 	if (result != 0) {
4258 		WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
4259 		WL_ERR(("NOTE: this ioctl error is normal "
4260 			"when the BSS has not been created yet.\n"));
4261 	} else {
4262 		val = *(int*)getbuf;
4263 		val = dtoh32(val);
4264 		WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx, val));
4265 		isup = (val ? TRUE : FALSE);
4266 	}
4267 	return isup;
4268 }
4269 
4270 s32
wl_iftype_to_mode(wl_iftype_t iftype)4271 wl_iftype_to_mode(wl_iftype_t iftype)
4272 {
4273 	s32 mode = BCME_ERROR;
4274 
4275 	switch (iftype) {
4276 		case WL_IF_TYPE_STA:
4277 		case WL_IF_TYPE_P2P_GC:
4278 		case WL_IF_TYPE_P2P_DISC:
4279 			mode = WL_MODE_BSS;
4280 			break;
4281 		case WL_IF_TYPE_AP:
4282 		case WL_IF_TYPE_P2P_GO:
4283 			mode = WL_MODE_AP;
4284 			break;
4285 		case WL_IF_TYPE_NAN:
4286 			mode = WL_MODE_NAN;
4287 			break;
4288 		case WL_IF_TYPE_AIBSS:
4289 			/* Intentional fall through */
4290 		case WL_IF_TYPE_IBSS:
4291 			mode = WL_MODE_IBSS;
4292 			break;
4293 #ifdef WLMESH_CFG80211
4294 		case WL_IF_TYPE_MESH:
4295 			mode = WL_MODE_MESH;
4296 			break;
4297 #endif /* WLMESH_CFG80211 */
4298 		default:
4299 			WL_ERR(("Unsupported type:%d\n", iftype));
4300 			break;
4301 	}
4302 	return mode;
4303 }
4304 
4305 s32
cfg80211_to_wl_iftype(uint16 type,uint16 * role,uint16 * mode)4306 cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode)
4307 {
4308 	switch (type) {
4309 		case NL80211_IFTYPE_STATION:
4310 			*role = WL_IF_TYPE_STA;
4311 			*mode = WL_MODE_BSS;
4312 			break;
4313 		case NL80211_IFTYPE_AP:
4314 			*role = WL_IF_TYPE_AP;
4315 			*mode = WL_MODE_AP;
4316 			break;
4317 #ifdef WL_CFG80211_P2P_DEV_IF
4318 		case NL80211_IFTYPE_P2P_DEVICE:
4319 			*role = WL_IF_TYPE_P2P_DISC;
4320 			*mode = WL_MODE_BSS;
4321 			break;
4322 #endif /* WL_CFG80211_P2P_DEV_IF */
4323 		case NL80211_IFTYPE_P2P_GO:
4324 			*role = WL_IF_TYPE_P2P_GO;
4325 			*mode = WL_MODE_AP;
4326 			break;
4327 		case NL80211_IFTYPE_P2P_CLIENT:
4328 			*role = WL_IF_TYPE_P2P_GC;
4329 			*mode = WL_MODE_BSS;
4330 			break;
4331 		case NL80211_IFTYPE_MONITOR:
4332 			WL_ERR(("Unsupported mode \n"));
4333 			return BCME_UNSUPPORTED;
4334 		case NL80211_IFTYPE_ADHOC:
4335 			*role = WL_IF_TYPE_IBSS;
4336 			*mode = WL_MODE_IBSS;
4337 			break;
4338 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
4339 		case NL80211_IFTYPE_NAN:
4340 			*role = WL_IF_TYPE_NAN;
4341 			*mode = WL_MODE_NAN;
4342 			break;
4343 #endif // endif
4344 #ifdef WLMESH_CFG80211
4345 		case NL80211_IFTYPE_MESH_POINT:
4346 			*role = WLC_E_IF_ROLE_AP;
4347 			*mode = WL_MODE_MESH;
4348 			break;
4349 #endif /* WLMESH_CFG80211 */
4350 		default:
4351 			WL_ERR(("Unknown interface type:0x%x\n", type));
4352 			return BCME_ERROR;
4353 	}
4354 	return BCME_OK;
4355 }
4356 
4357 static s32
wl_role_to_cfg80211_type(uint16 role,uint16 * wl_iftype,uint16 * mode)4358 wl_role_to_cfg80211_type(uint16 role, uint16 *wl_iftype, uint16 *mode)
4359 {
4360 	switch (role) {
4361 	case WLC_E_IF_ROLE_STA:
4362 		*wl_iftype = WL_IF_TYPE_STA;
4363 		*mode = WL_MODE_BSS;
4364 		return NL80211_IFTYPE_STATION;
4365 	case WLC_E_IF_ROLE_AP:
4366 		*wl_iftype = WL_IF_TYPE_AP;
4367 		*mode = WL_MODE_AP;
4368 		return NL80211_IFTYPE_AP;
4369 	case WLC_E_IF_ROLE_P2P_GO:
4370 		*wl_iftype = WL_IF_TYPE_P2P_GO;
4371 		*mode = WL_MODE_AP;
4372 		return NL80211_IFTYPE_P2P_GO;
4373 	case WLC_E_IF_ROLE_P2P_CLIENT:
4374 		*wl_iftype = WL_IF_TYPE_P2P_GC;
4375 		*mode = WL_MODE_BSS;
4376 		return NL80211_IFTYPE_P2P_CLIENT;
4377 	case WLC_E_IF_ROLE_IBSS:
4378 		*wl_iftype = WL_IF_TYPE_IBSS;
4379 		*mode = WL_MODE_IBSS;
4380 		return NL80211_IFTYPE_ADHOC;
4381 	case WLC_E_IF_ROLE_NAN:
4382 		*wl_iftype = WL_IF_TYPE_NAN;
4383 		*mode = WL_MODE_NAN;
4384 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
4385 		/* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
4386 		 * For Vendor HAL based NAN implementation, continue advertising
4387 		 * as a STA interface
4388 		 */
4389 		return NL80211_IFTYPE_NAN;
4390 #else
4391 		return NL80211_IFTYPE_STATION;
4392 #endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
4393 #ifdef WLDWDS
4394 	case WLC_E_IF_ROLE_WDS:
4395 		*wl_iftype = WL_IF_TYPE_AP;
4396 		*mode = WL_MODE_AP;
4397 		return NL80211_IFTYPE_AP;
4398 #endif
4399 #ifdef WLMESH_CFG80211
4400 	case WLC_E_IF_ROLE_MESH:
4401 		*wl_iftype = WL_IF_TYPE_MESH;
4402 		*mode = WL_MODE_MESH;
4403 		return NL80211_IFTYPE_MESH_POINT;
4404 #endif /* WLMESH_CFG80211 */
4405 
4406 	default:
4407 		WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role));
4408 		return BCME_ERROR;
4409 	}
4410 }
4411 
4412 struct net_device *
wl_cfg80211_post_ifcreate(struct net_device * ndev,wl_if_event_info * event,u8 * addr,const char * name,bool rtnl_lock_reqd)4413 wl_cfg80211_post_ifcreate(struct net_device *ndev,
4414 	wl_if_event_info *event, u8 *addr,
4415 	const char *name, bool rtnl_lock_reqd)
4416 {
4417 	struct bcm_cfg80211 *cfg;
4418 	struct net_device *primary_ndev;
4419 	struct net_device *new_ndev = NULL;
4420 	struct wireless_dev *wdev = NULL;
4421 	s32 iface_type;
4422 	s32 ret = BCME_OK;
4423 	u16 mode;
4424 	u8 mac_addr[ETH_ALEN];
4425 	u16 wl_iftype;
4426 
4427 	if (!ndev || !event) {
4428 		WL_ERR(("Wrong arg\n"));
4429 		return NULL;
4430 	}
4431 
4432 	cfg = wl_get_cfg(ndev);
4433 	if (!cfg) {
4434 		WL_ERR(("cfg null\n"));
4435 		return NULL;
4436 	}
4437 
4438 	WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
4439 		event->role, event->ifidx, event->bssidx));
4440 	if (!event->ifidx || !event->bssidx) {
4441 		/* Fw returned primary idx (0) for virtual interface */
4442 		WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
4443 			event->ifidx, event->bssidx));
4444 		return NULL;
4445 	}
4446 
4447 #if defined(WLMESH_CFG80211) && defined(WL_EXT_IAPSTA)
4448 	if (wl_ext_iapsta_mesh_creating(ndev)) {
4449 		event->role = WLC_E_IF_ROLE_MESH;
4450 		WL_MSG(ndev->name, "change role to WLC_E_IF_ROLE_MESH\n");
4451 	}
4452 #endif /* WLMESH_CFG80211 && WL_EXT_IAPSTA */
4453 
4454 	iface_type = wl_role_to_cfg80211_type(event->role, &wl_iftype, &mode);
4455 	if (iface_type < 0) {
4456 		/* Unknown iface type */
4457 		WL_ERR(("Wrong iface type \n"));
4458 		return NULL;
4459 	}
4460 
4461 	WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG "\n",
4462 		addr, name, event->role, iface_type, MAC2STRDBG(event->mac)));
4463 	if (!name) {
4464 		/* If iface name is not provided, use dongle ifname */
4465 		name = event->name;
4466 	}
4467 
4468 	if (!addr) {
4469 		/* If mac address is not set, use primary mac with locally administered
4470 		 * bit set.
4471 		 */
4472 		primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4473 		memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
4474 		/* For customer6 builds, use primary mac address for virtual interface */
4475 		mac_addr[0] |= 0x02;
4476 		addr = mac_addr;
4477 	}
4478 
4479 #ifdef WL_STATIC_IF
4480 	if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
4481 		new_ndev = wl_cfg80211_post_static_ifcreate(cfg, event, addr, iface_type);
4482 		if (!new_ndev) {
4483 			WL_ERR(("failed to get I/F pointer\n"));
4484 			return NULL;
4485 		}
4486 		wdev = new_ndev->ieee80211_ptr;
4487 	} else
4488 #endif /* WL_STATIC_IF */
4489 	{
4490 		new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
4491 			name, addr, event->bssidx, event->name);
4492 		if (!new_ndev) {
4493 			WL_ERR(("I/F allocation failed! \n"));
4494 			return NULL;
4495 		} else {
4496 			WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
4497 			 event->ifidx, event->bssidx));
4498 		}
4499 
4500 		wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
4501 		if (!wdev) {
4502 			WL_ERR(("wireless_dev alloc failed! \n"));
4503 			wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4504 			return NULL;
4505 		}
4506 
4507 		wdev->wiphy = bcmcfg_to_wiphy(cfg);
4508 		wdev->iftype = iface_type;
4509 
4510 		new_ndev->ieee80211_ptr = wdev;
4511 #ifdef WLDWDS
4512 		/* set wds0.x to 4addr interface here */
4513 		if (event->role == WLC_E_IF_ROLE_WDS) {
4514 			printf("\n\n\n event->role == WLC_E_IF_ROLE_WDS, set vwdev 4addr to %s\n", event->name);
4515 			wdev->use_4addr = true;
4516 		}
4517 #endif /* WLDWDS */
4518 		SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4519 
4520 		memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
4521 #ifdef WL_EXT_IAPSTA
4522 		wl_ext_iapsta_ifadding(new_ndev, event->ifidx);
4523 #endif /* WL_EXT_IAPSTA */
4524 		if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd)
4525 			!= BCME_OK) {
4526 			WL_ERR(("IFACE register failed \n"));
4527 			/* Post interface registration, wdev would be freed from the netdev
4528 			 * destructor path. For other cases, handle it here.
4529 			 */
4530 			MFREE(cfg->osh, wdev, sizeof(*wdev));
4531 			wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4532 			return NULL;
4533 		}
4534 	}
4535 
4536 	/* Initialize with the station mode params */
4537 	ret = wl_alloc_netinfo(cfg, new_ndev, wdev, wl_iftype,
4538 		PM_ENABLE, event->bssidx, event->ifidx);
4539 	if (unlikely(ret)) {
4540 		WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret));
4541 		goto fail;
4542 	}
4543 
4544 	/* Apply the mode & infra setting based on iftype */
4545 	if ((ret = wl_config_infra(cfg, new_ndev, wl_iftype)) < 0) {
4546 		WL_ERR(("config ifmode failure (%d)\n", ret));
4547 		goto fail;
4548 	}
4549 
4550 	if (mode == WL_MODE_AP) {
4551 		wl_set_drv_status(cfg, AP_CREATING, new_ndev);
4552 	}
4553 #ifdef WL_EXT_IAPSTA
4554 	wl_ext_iapsta_update_iftype(new_ndev, event->ifidx, wl_iftype);
4555 #endif
4556 
4557 	WL_INFORM_MEM(("Network Interface (%s) registered with host."
4558 		" cfg_iftype:%d wl_role:%d " MACDBG "\n",
4559 		new_ndev->name, iface_type, event->role, MAC2STRDBG(new_ndev->dev_addr)));
4560 
4561 #ifdef SUPPORT_SET_CAC
4562 	wl_cfg80211_set_cac(cfg, 0);
4563 #endif /* SUPPORT_SET_CAC */
4564 
4565 	return new_ndev;
4566 
4567 fail:
4568 #ifdef WL_STATIC_IF
4569 	/* remove static if from iflist */
4570 	if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
4571 		cfg->static_ndev_state = NDEV_STATE_FW_IF_FAILED;
4572 		wl_cfg80211_update_iflist_info(cfg, new_ndev, WL_STATIC_IFIDX, addr,
4573 			event->bssidx, event->name, NDEV_STATE_FW_IF_FAILED);
4574 	}
4575 #endif /* WL_STATIC_IF */
4576 	if (new_ndev) {
4577 		/* wdev would be freed from netdev destructor call back */
4578 		wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4579 	}
4580 
4581 	return NULL;
4582 }
4583 
4584 s32
wl_cfg80211_delete_iface(struct bcm_cfg80211 * cfg,wl_iftype_t sec_data_if_type)4585 wl_cfg80211_delete_iface(struct bcm_cfg80211 *cfg,
4586 	wl_iftype_t sec_data_if_type)
4587 {
4588 	struct net_info *iter, *next;
4589 	struct net_device *primary_ndev;
4590 	s32 ret = BCME_OK;
4591 	uint8 i = 0;
4592 
4593 	BCM_REFERENCE(i);
4594 	BCM_REFERENCE(ret);
4595 
4596 	/* Note: This function will clean up only the network interface and host
4597 	 * data structures. The firmware interface clean up will happen in the
4598 	 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4599 	 * context for the module case).
4600 	 */
4601 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4602 	WL_DBG(("Enter, deleting iftype  %s\n",
4603 		wl_iftype_to_str(sec_data_if_type)));
4604 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4605 	for_each_ndev(cfg, iter, next) {
4606 		GCC_DIAGNOSTIC_POP();
4607 		if (iter->ndev && (iter->ndev != primary_ndev)) {
4608 			if (iter->iftype != sec_data_if_type) {
4609 				continue;
4610 			}
4611 			switch (sec_data_if_type) {
4612 				case WL_IF_TYPE_P2P_GO:
4613 				case WL_IF_TYPE_P2P_GC: {
4614 					ret = _wl_cfg80211_del_if(cfg,
4615 						iter->ndev, NULL, iter->ndev->name);
4616 					break;
4617 				}
4618 #ifdef WL_NAN
4619 				case WL_IF_TYPE_NAN: {
4620 					if (cfg->nan_enable == false) {
4621 						WL_INFORM_MEM(("Nan is not active,"
4622 							" ignore NDI delete\n"));
4623 					} else {
4624 						ret = wl_cfgnan_delete_ndp(cfg, iter->ndev);
4625 					}
4626 					break;
4627 				}
4628 #endif /* WL_NAN */
4629 				case WL_IF_TYPE_AP: {
4630 					/* Cleanup AP */
4631 #ifdef WL_STATIC_IF
4632 						/* handle static ap */
4633 					if (IS_CFG80211_STATIC_IF(cfg, iter->ndev)) {
4634 						dev_close(iter->ndev);
4635 					} else
4636 #endif /* WL_STATIC_IF */
4637 					{
4638 						/* handle virtual created AP */
4639 						ret = _wl_cfg80211_del_if(cfg, iter->ndev,
4640 							NULL, iter->ndev->name);
4641 					}
4642 					break;
4643 				}
4644 				default: {
4645 					WL_ERR(("Unsupported interface type\n"));
4646 					ret = -ENOTSUPP;
4647 					goto fail;
4648 				}
4649 			}
4650 		}
4651 	}
4652 fail:
4653 	return ret;
4654 }
4655 
4656 void
wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 * cfg,bool rtnl_lock_reqd)4657 wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 *cfg, bool rtnl_lock_reqd)
4658 {
4659 	struct net_info *iter, *next;
4660 	struct net_device *primary_ndev;
4661 
4662 	/* Note: This function will clean up only the network interface and host
4663 	 * data structures. The firmware interface clean up will happen in the
4664 	 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4665 	 * context for the module case).
4666 	 */
4667 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4668 	WL_DBG(("Enter\n"));
4669 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4670 	for_each_ndev(cfg, iter, next) {
4671 		GCC_DIAGNOSTIC_POP();
4672 		if (iter->ndev && (iter->ndev != primary_ndev)) {
4673 			/* Ensure interfaces are down before deleting */
4674 #ifdef WL_STATIC_IF
4675 			/* Avoiding cleaning static ifaces */
4676 			if (!IS_CFG80211_STATIC_IF(cfg, iter->ndev))
4677 #endif /* WL_STATIC_IF */
4678 			{
4679 				dev_close(iter->ndev);
4680 				WL_DBG(("Cleaning up iface:%s \n", iter->ndev->name));
4681 				wl_cfg80211_post_ifdel(iter->ndev, rtnl_lock_reqd, 0);
4682 			}
4683 		}
4684 	}
4685 }
4686 
4687 s32
wl_cfg80211_post_ifdel(struct net_device * ndev,bool rtnl_lock_reqd,s32 ifidx)4688 wl_cfg80211_post_ifdel(struct net_device *ndev, bool rtnl_lock_reqd, s32 ifidx)
4689 {
4690 	s32 ret = BCME_OK;
4691 	struct bcm_cfg80211 *cfg;
4692 	struct net_info *netinfo = NULL;
4693 
4694 	if (!ndev || !ndev->ieee80211_ptr) {
4695 		/* No wireless dev done for this interface */
4696 		ret = -EINVAL;
4697 		goto exit;
4698 	}
4699 
4700 	cfg = wl_get_cfg(ndev);
4701 	if (!cfg) {
4702 		WL_ERR(("cfg null\n"));
4703 		ret = BCME_ERROR;
4704 		goto exit;
4705 	}
4706 
4707 	if (ifidx <= 0) {
4708 		WL_ERR(("Invalid IF idx for iface:%s\n", ndev->name));
4709 		ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
4710 		BCM_REFERENCE(ifidx);
4711 		if (ifidx <= 0) {
4712 			ASSERT(0);
4713 			ret = BCME_ERROR;
4714 			goto exit;
4715 		}
4716 	}
4717 
4718 	if ((netinfo = wl_get_netinfo_by_wdev(cfg, ndev_to_wdev(ndev))) == NULL) {
4719 		WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev)));
4720 		ret = -ENODEV;
4721 		goto exit;
4722 	}
4723 
4724 #ifdef WL_STATIC_IF
4725 	if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
4726 		ret = wl_cfg80211_post_static_ifdel(cfg, ndev);
4727 	} else
4728 #endif /* WL_STATIC_IF */
4729 	{
4730 		WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
4731 			ndev->name, ifidx, cfg->vif_count));
4732 		wl_cfg80211_remove_if(cfg, ifidx, ndev, rtnl_lock_reqd);
4733 		cfg->bss_pending_op = FALSE;
4734 	}
4735 
4736 #ifdef SUPPORT_SET_CAC
4737 	wl_cfg80211_set_cac(cfg, 1);
4738 #endif /* SUPPORT_SET_CAC */
4739 exit:
4740 	return ret;
4741 }
4742 
4743 int
wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 * cfg)4744 wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 *cfg)
4745 {
4746 	s32 ret = BCME_OK;
4747 	bcm_struct_cfgdev *cfgdev;
4748 
4749 	if (cfg->p2p) {
4750 		/* De-initialize the p2p discovery interface, if operational */
4751 		WL_ERR(("Disabling P2P Discovery Interface \n"));
4752 #ifdef WL_CFG80211_P2P_DEV_IF
4753 		cfgdev = bcmcfg_to_p2p_wdev(cfg);
4754 #else
4755 		cfgdev = cfg->p2p_net;
4756 #endif // endif
4757 		if (cfgdev) {
4758 			ret = wl_cfg80211_scan_stop(cfg, cfgdev);
4759 			if (unlikely(ret < 0)) {
4760 				CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
4761 			}
4762 		}
4763 
4764 		wl_cfgp2p_disable_discovery(cfg);
4765 		wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
4766 		p2p_on(cfg) = false;
4767 	}
4768 	return ret;
4769 }
4770 
4771 /* Create a Generic Network Interface and initialize it depending up on
4772  * the interface type
4773  */
4774 struct wireless_dev *
wl_cfg80211_create_iface(struct wiphy * wiphy,wl_iftype_t wl_iftype,u8 * mac_addr,const char * name)4775 wl_cfg80211_create_iface(struct wiphy *wiphy,
4776 	wl_iftype_t wl_iftype,
4777 	u8 *mac_addr, const char *name)
4778 {
4779 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4780 	struct net_device *new_ndev = NULL;
4781 	struct net_device *primary_ndev = NULL;
4782 	s32 ret = BCME_OK;
4783 	s32 bsscfg_idx = 0;
4784 	long timeout;
4785 	wl_if_event_info *event = NULL;
4786 	u8 addr[ETH_ALEN];
4787 	struct net_info *iter, *next;
4788 
4789 	WL_DBG(("Enter\n"));
4790 	if (!name) {
4791 		WL_ERR(("Interface name not provided\n"));
4792 		return NULL;
4793 	}
4794 	else {
4795 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4796 		for_each_ndev(cfg, iter, next) {
4797 			GCC_DIAGNOSTIC_POP();
4798 			if (iter->ndev) {
4799 				if (strncmp(iter->ndev->name, name, strlen(name)) == 0) {
4800 					WL_ERR(("Interface name,%s exists!\n", iter->ndev->name));
4801 					return NULL;
4802 				}
4803 			}
4804 		}
4805 	}
4806 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4807 	if (likely(!mac_addr)) {
4808 		/* Use primary MAC with the locally administered bit for the
4809 		 *  Secondary STA I/F
4810 		 */
4811 		memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
4812 		addr[0] |= 0x02;
4813 	} else {
4814 		/* Use the application provided mac address (if any) */
4815 		memcpy(addr, mac_addr, ETH_ALEN);
4816 	}
4817 
4818 	cfg->bss_pending_op = TRUE;
4819 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
4820 
4821 	/*
4822 	 * Intialize the firmware I/F.
4823 	 */
4824 	{
4825 		ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
4826 			wl_iftype, 0, addr);
4827 	}
4828 	if (ret == BCME_UNSUPPORTED) {
4829 		/* Use bssidx 1 by default */
4830 		bsscfg_idx = 1;
4831 		if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
4832 			bsscfg_idx, wl_iftype, 0, addr)) < 0) {
4833 			goto exit;
4834 		}
4835 	} else if (ret < 0) {
4836 		WL_ERR(("Interface create failed!! ret:%d \n", ret));
4837 		goto exit;
4838 	} else {
4839 		/* Success */
4840 		bsscfg_idx = ret;
4841 	}
4842 
4843 	WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
4844 	/*
4845 	 * Wait till the firmware send a confirmation event back.
4846 	 */
4847 	WL_DBG(("Wait for the FW I/F Event\n"));
4848 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4849 		!cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4850 	if (timeout <= 0 || cfg->bss_pending_op) {
4851 		WL_ERR(("ADD_IF event, didn't come. Return. timeout:%lu bss_pending_op:%d\n",
4852 			timeout, cfg->bss_pending_op));
4853 		if (timeout == -ERESTARTSYS) {
4854 			WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
4855 		}
4856 		goto exit;
4857 	}
4858 
4859 	event = &cfg->if_event_info;
4860 	/*
4861 	 * Since FW operation is successful,we can go ahead with the
4862 	 * the host interface creation.
4863 	 */
4864 	new_ndev = wl_cfg80211_post_ifcreate(primary_ndev,
4865 		event, addr, name, false);
4866 
4867 	if (new_ndev) {
4868 		/* Iface post ops successful. Return ndev/wdev ptr */
4869 		return new_ndev->ieee80211_ptr;
4870 	}
4871 
4872 exit:
4873 	cfg->bss_pending_op = FALSE;
4874 	return NULL;
4875 }
4876 
4877 s32
wl_cfg80211_del_iface(struct wiphy * wiphy,struct wireless_dev * wdev)4878 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
4879 {
4880 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4881 	struct net_device *ndev = NULL;
4882 	s32 ret = BCME_OK;
4883 	s32 bsscfg_idx = 1;
4884 	long timeout;
4885 	u16 wl_iftype;
4886 	u16 wl_mode;
4887 
4888 	WL_DBG(("Enter\n"));
4889 
4890 	/* If any scan is going on, abort it */
4891 	if (wl_get_drv_status_all(cfg, SCANNING)) {
4892 		WL_DBG(("Scan in progress. Aborting the scan!\n"));
4893 		wl_cfg80211_cancel_scan(cfg);
4894 	}
4895 
4896 	bsscfg_idx = wl_get_bssidx_by_wdev(cfg, wdev);
4897 	if (bsscfg_idx <= 0) {
4898 		/* validate bsscfgidx */
4899 		WL_ERR(("Wrong bssidx! \n"));
4900 		return -EINVAL;
4901 	}
4902 
4903 	/* Handle p2p iface */
4904 	if ((ret = wl_cfg80211_p2p_if_del(wiphy, wdev)) != BCME_NOTFOUND) {
4905 		WL_DBG(("P2P iface del handled \n"));
4906 #ifdef SUPPORT_SET_CAC
4907 		wl_cfg80211_set_cac(cfg, 1);
4908 #endif /* SUPPORT_SET_CAC */
4909 		return ret;
4910 	}
4911 
4912 	ndev = wdev->netdev;
4913 	if (unlikely(!ndev)) {
4914 		WL_ERR(("ndev null! \n"));
4915 		return -EINVAL;
4916 	}
4917 
4918 	memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4919 
4920 	if (cfg80211_to_wl_iftype(ndev->ieee80211_ptr->iftype,
4921 		&wl_iftype, &wl_mode) < 0) {
4922 		return -EINVAL;
4923 	}
4924 
4925 	WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d",
4926 		bsscfg_idx, ndev->ieee80211_ptr->iftype, wl_iftype));
4927 	/* Delete the firmware interface. "interface_remove" command
4928 	 * should go on the interface to be deleted
4929 	 */
4930 	if (wl_cfg80211_get_bus_state(cfg)) {
4931 		WL_ERR(("Bus state is down: %d\n", __LINE__));
4932 		ret = BCME_DONGLE_DOWN;
4933 		goto exit;
4934 	}
4935 
4936 	cfg->bss_pending_op = true;
4937 	ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx,
4938 		wl_iftype, 1, NULL);
4939 	if (ret == BCME_UNSUPPORTED) {
4940 		if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
4941 			bsscfg_idx, wl_iftype, true, NULL)) < 0) {
4942 			WL_ERR(("DEL bss failed ret:%d \n", ret));
4943 			goto exit;
4944 		}
4945 	} else if ((ret == BCME_NOTAP) || (ret == BCME_NOTSTA)) {
4946 		/* De-init sequence involving role downgrade not happened.
4947 		 * Do nothing and return error. The del command should be
4948 		 * retried.
4949 		 */
4950 		WL_ERR(("ifdel role mismatch:%d\n", ret));
4951 		ret = -EBADTYPE;
4952 		goto exit;
4953 	} else if (ret < 0) {
4954 		WL_ERR(("Interface DEL failed ret:%d \n", ret));
4955 		goto exit;
4956 	}
4957 
4958 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4959 		!cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4960 	if (timeout <= 0 || cfg->bss_pending_op) {
4961 		WL_ERR(("timeout in waiting IF_DEL event\n"));
4962 		/* The interface unregister will happen from wifi reset context */
4963 		ret = -ETIMEDOUT;
4964 		/* fall through */
4965 	}
4966 
4967 exit:
4968 	if (ret < 0) {
4969 		WL_ERR(("iface del failed:%d\n", ret));
4970 #ifdef WL_STATIC_IF
4971 		if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
4972 			/*
4973 			 * For static interface, clean up the host data,
4974 			 * irrespective of fw status. For dynamic
4975 			 * interfaces it gets cleaned from dhd_stop context
4976 			 */
4977 			wl_cfg80211_post_static_ifdel(cfg, ndev);
4978 		}
4979 #endif /* WL_STATIC_IF */
4980 	} else {
4981 		ret = wl_cfg80211_post_ifdel(ndev, false, cfg->if_event_info.ifidx);
4982 		if (unlikely(ret)) {
4983 			WL_ERR(("post_ifdel failed\n"));
4984 		}
4985 	}
4986 
4987 	cfg->bss_pending_op = false;
4988 	return ret;
4989 }
4990 
4991 static s32
wl_cfg80211_join_ibss(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ibss_params * params)4992 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
4993 	struct cfg80211_ibss_params *params)
4994 {
4995 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4996 	struct cfg80211_bss *bss;
4997 	struct ieee80211_channel *chan;
4998 	struct wl_join_params join_params;
4999 	int scan_suppress;
5000 	struct cfg80211_ssid ssid;
5001 	s32 scan_retry = 0;
5002 	s32 err = 0;
5003 	size_t join_params_size;
5004 	chanspec_t chanspec = 0;
5005 	u32 param[2] = {0, 0};
5006 	u32 bw_cap = 0;
5007 
5008 	WL_TRACE(("In\n"));
5009 	RETURN_EIO_IF_NOT_UP(cfg);
5010 	WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
5011 	if (!params->ssid || params->ssid_len <= 0 ||
5012 		params->ssid_len > DOT11_MAX_SSID_LEN) {
5013 		WL_ERR(("Invalid parameter\n"));
5014 		return -EINVAL;
5015 	}
5016 #if defined(WL_CFG80211_P2P_DEV_IF)
5017 	chan = params->chandef.chan;
5018 #else
5019 	chan = params->channel;
5020 #endif /* WL_CFG80211_P2P_DEV_IF */
5021 	if (chan)
5022 		cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
5023 	if (wl_get_drv_status(cfg, CONNECTED, dev)) {
5024 		struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
5025 		u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
5026 		u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
5027 		if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
5028 			(memcmp(params->ssid, lssid->SSID, lssid->SSID_len) == 0) &&
5029 			(*channel == cfg->channel))) {
5030 			WL_ERR(("Connection already existed to " MACDBG "\n",
5031 				MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
5032 			return -EISCONN;
5033 		}
5034 		WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n",
5035 			lssid->SSID, MAC2STRDBG(bssid)));
5036 	}
5037 
5038 	/* remove the VSIE */
5039 	wl_cfg80211_ibss_vsie_delete(dev);
5040 
5041 	bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
5042 	if (!bss) {
5043 		if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
5044 			memcpy(ssid.ssid, params->ssid, params->ssid_len);
5045 			ssid.ssid_len = params->ssid_len;
5046 			do {
5047 				if (unlikely
5048 					(__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
5049 					 -EBUSY)) {
5050 					wl_delay(150);
5051 				} else {
5052 					break;
5053 				}
5054 			} while (++scan_retry < WL_SCAN_RETRY_MAX);
5055 
5056 			/* rtnl lock code is removed here. don't see why rtnl lock
5057 			 * needs to be released.
5058 			 */
5059 
5060 			/* wait 4 secons till scan done.... */
5061 			schedule_timeout_interruptible(msecs_to_jiffies(4000));
5062 
5063 			bss = cfg80211_get_ibss(wiphy, NULL,
5064 				params->ssid, params->ssid_len);
5065 		}
5066 	}
5067 	if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
5068 		((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
5069 		!memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
5070 		cfg->ibss_starter = false;
5071 		WL_DBG(("Found IBSS\n"));
5072 	} else {
5073 		cfg->ibss_starter = true;
5074 	}
5075 
5076 	if (bss) {
5077 		CFG80211_PUT_BSS(wiphy, bss);
5078 	}
5079 
5080 	if (chan) {
5081 		if (chan->band == IEEE80211_BAND_5GHZ)
5082 			param[0] = WLC_BAND_5G;
5083 		else if (chan->band == IEEE80211_BAND_2GHZ)
5084 			param[0] = WLC_BAND_2G;
5085 		err = wldev_iovar_getint(dev, "bw_cap", param);
5086 		if (unlikely(err)) {
5087 			WL_ERR(("Get bw_cap Failed (%d)\n", err));
5088 			return err;
5089 		}
5090 		bw_cap = param[0];
5091 		chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap);
5092 	}
5093 	/*
5094 	 * Join with specific BSSID and cached SSID
5095 	 * If SSID is zero join based on BSSID only
5096 	 */
5097 	bzero(&join_params, sizeof(join_params));
5098 	memcpy((void *)join_params.ssid.SSID, (const void *)params->ssid,
5099 		params->ssid_len);
5100 	join_params.ssid.SSID_len = htod32(params->ssid_len);
5101 	if (params->bssid) {
5102 		memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
5103 		err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
5104 			ETHER_ADDR_LEN);
5105 		if (unlikely(err)) {
5106 			WL_ERR(("Error (%d)\n", err));
5107 			return err;
5108 		}
5109 	} else
5110 		bzero(&join_params.params.bssid, ETHER_ADDR_LEN);
5111 
5112 	if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5113 		scan_suppress = TRUE;
5114 		/* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
5115 		err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5116 			&scan_suppress, sizeof(int));
5117 		if (unlikely(err)) {
5118 			WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
5119 			return err;
5120 		}
5121 	}
5122 
5123 	join_params.params.chanspec_list[0] = chanspec;
5124 	join_params.params.chanspec_num = 1;
5125 	wldev_iovar_setint(dev, "chanspec", chanspec);
5126 	join_params_size = sizeof(join_params);
5127 
5128 	/* Disable Authentication, IBSS will add key if it required */
5129 	wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
5130 	wldev_iovar_setint(dev, "wsec", 0);
5131 
5132 	err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
5133 		join_params_size);
5134 	if (unlikely(err)) {
5135 		WL_ERR(("IBSS set_ssid Error (%d)\n", err));
5136 		return err;
5137 	}
5138 
5139 	if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5140 		scan_suppress = FALSE;
5141 		/* Reset the SCAN SUPPRESS Flag */
5142 		err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5143 			&scan_suppress, sizeof(int));
5144 		if (unlikely(err)) {
5145 			WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
5146 			return err;
5147 		}
5148 	}
5149 	wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
5150 	wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
5151 #ifdef WL_RELMCAST
5152 	cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
5153 #endif /* WL_RELMCAST */
5154 	return err;
5155 }
5156 
wl_cfg80211_leave_ibss(struct wiphy * wiphy,struct net_device * dev)5157 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
5158 {
5159 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5160 	s32 err = 0;
5161 	scb_val_t scbval;
5162 	u8 *curbssid;
5163 
5164 	RETURN_EIO_IF_NOT_UP(cfg);
5165 	wl_link_down(cfg);
5166 
5167 	WL_INFORM_MEM(("Leave IBSS\n"));
5168 	curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
5169 	wl_set_drv_status(cfg, DISCONNECTING, dev);
5170 	scbval.val = 0;
5171 	memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
5172 	err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
5173 		sizeof(scb_val_t));
5174 	if (unlikely(err)) {
5175 		wl_clr_drv_status(cfg, DISCONNECTING, dev);
5176 		WL_ERR(("error(%d)\n", err));
5177 		return err;
5178 	}
5179 
5180 	/* remove the VSIE */
5181 	wl_cfg80211_ibss_vsie_delete(dev);
5182 
5183 	return err;
5184 }
5185 
5186 #ifdef MFP
5187 static
wl_cfg80211_get_rsn_capa(const bcm_tlv_t * wpa2ie,const u8 ** rsn_cap)5188 int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie,
5189 	const u8** rsn_cap)
5190 {
5191 	u16 suite_count;
5192 	const wpa_suite_mcast_t *mcast;
5193 	const wpa_suite_ucast_t *ucast;
5194 	int len;
5195 	const wpa_suite_auth_key_mgmt_t *mgmt;
5196 
5197 	if (!wpa2ie)
5198 		return BCME_BADARG;
5199 
5200 	len = wpa2ie->len;
5201 
5202 	/* check for Multicast cipher suite */
5203 	if ((len -= (WPA_SUITE_LEN + WPA2_VERSION_LEN)) <= 0) {
5204 		return BCME_NOTFOUND;
5205 	}
5206 
5207 	mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
5208 
5209 	/* Check for the unicast suite(s) */
5210 	if (len < WPA_IE_SUITE_COUNT_LEN) {
5211 		return BCME_NOTFOUND;
5212 	}
5213 
5214 	ucast = (const wpa_suite_ucast_t *)&mcast[1];
5215 	suite_count = ltoh16_ua(&ucast->count);
5216 	if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
5217 		(len -= (WPA_IE_SUITE_COUNT_LEN +
5218 		(WPA_SUITE_LEN * suite_count))) <= 0)
5219 		return BCME_BADLEN;
5220 
5221 	/* Check for AUTH key management suite(s) */
5222 	if (len < WPA_IE_SUITE_COUNT_LEN) {
5223 		return BCME_NOTFOUND;
5224 	}
5225 
5226 	mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
5227 	suite_count = ltoh16_ua(&mgmt->count);
5228 
5229 	if ((suite_count <= NL80211_MAX_NR_CIPHER_SUITES) &&
5230 			(len -= (WPA_IE_SUITE_COUNT_LEN +
5231 			(WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
5232 		rsn_cap[0] = (const u8 *)&mgmt->list[suite_count];
5233 	} else {
5234 		return BCME_BADLEN;
5235 	}
5236 
5237 	return BCME_OK;
5238 }
5239 #endif /* MFP */
5240 
5241 static s32
wl_set_wpa_version(struct net_device * dev,struct cfg80211_connect_params * sme)5242 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
5243 {
5244 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5245 	struct wl_security *sec;
5246 	s32 val = 0;
5247 	s32 err = 0;
5248 	s32 bssidx;
5249 
5250 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5251 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5252 		return BCME_ERROR;
5253 	}
5254 
5255 	if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
5256 		val = WPA_AUTH_PSK |
5257 			WPA_AUTH_UNSPECIFIED;
5258 	else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
5259 		val = WPA2_AUTH_PSK|
5260 			WPA2_AUTH_UNSPECIFIED;
5261 	else
5262 		val = WPA_AUTH_DISABLED;
5263 
5264 	if (is_wps_conn(sme))
5265 		val = WPA_AUTH_DISABLED;
5266 
5267 #ifdef BCMWAPI_WPI
5268 	if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) {
5269 		WL_DBG((" * wl_set_wpa_version, set wpa_auth"
5270 			" to WPA_AUTH_WAPI 0x400"));
5271 		val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5272 	}
5273 #endif // endif
5274 	WL_INFORM_MEM(("[%s] wl wpa_auth 0x%0x\n", dev->name, val));
5275 	err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
5276 	if (unlikely(err)) {
5277 		WL_ERR(("set wpa_auth failed (%d)\n", err));
5278 		return err;
5279 	}
5280 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5281 	sec->wpa_versions = sme->crypto.wpa_versions;
5282 	return err;
5283 }
5284 
5285 #ifdef BCMWAPI_WPI
5286 static s32
wl_set_set_wapi_ie(struct net_device * dev,struct cfg80211_connect_params * sme)5287 wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme)
5288 {
5289 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5290 	s32 err = 0;
5291 	s32 bssidx;
5292 
5293 	WL_DBG((" wl_set_set_wapi_ie\n"));
5294 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5295 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5296 		return BCME_ERROR;
5297 	}
5298 
5299 	err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", (const void *)sme->ie, sme->ie_len,
5300 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5301 	if (unlikely(err)) {
5302 		WL_ERR(("set_wapi_ie Error (%d)\n", err));
5303 		return err;
5304 	}
5305 	WL_INFORM_MEM(("wapi_ie successfully (%s)\n", dev->name));
5306 	return err;
5307 }
5308 #endif /* BCMWAPI_WPI */
5309 
5310 static s32
wl_set_auth_type(struct net_device * dev,struct cfg80211_connect_params * sme)5311 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
5312 {
5313 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5314 	struct wl_security *sec;
5315 	s32 val = 0;
5316 	s32 err = 0;
5317 	s32 bssidx;
5318 
5319 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5320 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5321 		return BCME_ERROR;
5322 	}
5323 
5324 	switch (sme->auth_type) {
5325 	case NL80211_AUTHTYPE_OPEN_SYSTEM:
5326 		val = WL_AUTH_OPEN_SYSTEM;
5327 		WL_DBG(("open system\n"));
5328 		break;
5329 	case NL80211_AUTHTYPE_SHARED_KEY:
5330 		val = WL_AUTH_SHARED_KEY;
5331 		WL_DBG(("shared key\n"));
5332 		break;
5333 	case NL80211_AUTHTYPE_AUTOMATIC:
5334 		val = WL_AUTH_OPEN_SHARED;
5335 		WL_DBG(("automatic\n"));
5336 		break;
5337 #ifdef WL_FILS
5338 	case NL80211_AUTHTYPE_FILS_SK:
5339 		WL_DBG(("fils shared key\n"));
5340 		val = WL_AUTH_FILS_SHARED;
5341 		break;
5342 	case NL80211_AUTHTYPE_FILS_SK_PFS:
5343 		val = WL_AUTH_FILS_SHARED_PFS;
5344 		WL_DBG(("fils shared key with pfs\n"));
5345 		break;
5346 	case NL80211_AUTHTYPE_FILS_PK:
5347 		WL_DBG(("fils public key\n"));
5348 		val = WL_AUTH_FILS_PUBLIC;
5349 		break;
5350 #endif /* WL_FILS */
5351 #ifdef WL_CLIENT_SAE
5352 	case NL80211_AUTHTYPE_SAE:
5353 		if (!wl_is_pmkid_available(dev, sme->bssid)) {
5354 			val = WL_AUTH_SAE_KEY;
5355 		} else {
5356 			/* Fw will choose right auth type
5357 			* dynamically based on PMKID availability
5358 			*/
5359 			val = WL_AUTH_OPEN_SHARED;
5360 		}
5361 		WL_DBG(("sae auth type %d\n", val));
5362 		break;
5363 #endif /* WL_CLIENT_SAE */
5364 	default:
5365 		val = 2;
5366 		WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
5367 		break;
5368 	}
5369 
5370 	WL_INFORM_MEM(("[%s] wl auth 0x%0x \n", dev->name, val));
5371 	err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
5372 	if (unlikely(err)) {
5373 		WL_ERR(("set auth failed (%d)\n", err));
5374 		return err;
5375 	}
5376 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5377 	sec->auth_type = sme->auth_type;
5378 	return err;
5379 }
5380 
5381 #ifdef WL_CLIENT_SAE
5382 static bool
wl_is_pmkid_available(struct net_device * dev,const u8 * bssid)5383 wl_is_pmkid_available(struct net_device *dev, const u8 *bssid)
5384 {
5385 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5386 	int i;
5387 	int npmkids = (cfg->pmk_list->pmkids.length - sizeof(uint16)*2) / sizeof(pmkid_v2_t);
5388 
5389 	/* check the bssid is null or not */
5390 	if (!bssid) return FALSE;
5391 
5392 	for (i = 0; i < npmkids; i++) {
5393 		if (!memcmp(bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid, ETHER_ADDR_LEN)) {
5394 			WL_DBG(("FOUND PMKID\n"));
5395 			return TRUE;
5396 		}
5397 	}
5398 	WL_ERR(("PMKID NOT FOUND\n"));
5399 	return FALSE;
5400 }
5401 #endif /* WL_CLIENT_SAE */
5402 
5403 static u32
wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)5404 wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)
5405 {
5406 	uint i;
5407 
5408 	for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5409 		if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5410 			return rsn_cipher_algo_lookup_tbl[i].wsec_algo;
5411 		}
5412 	}
5413 	return WSEC_NONE;
5414 }
5415 
5416 static u32
wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)5417 wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)
5418 {
5419 	uint i;
5420 
5421 	for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5422 		if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5423 			return rsn_cipher_algo_lookup_tbl[i].wsec_key_algo;
5424 		}
5425 	}
5426 	return CRYPTO_ALGO_OFF;
5427 }
5428 
5429 static u32
wl_rsn_akm_wpa_auth_lookup(uint32 akm)5430 wl_rsn_akm_wpa_auth_lookup(uint32 akm)
5431 {
5432 	uint i;
5433 
5434 	for (i = 0; i < ARRAYSIZE(rsn_akm_wpa_auth_lookup_tbl); i++) {
5435 		if (akm == rsn_akm_wpa_auth_lookup_tbl[i].akm_suite) {
5436 			return rsn_akm_wpa_auth_lookup_tbl[i].wpa_auth;
5437 		}
5438 	}
5439 	return WPA_AUTH_DISABLED;
5440 }
5441 
5442 static s32
wl_set_set_cipher(struct net_device * dev,struct cfg80211_connect_params * sme)5443 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
5444 {
5445 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5446 	struct wl_security *sec;
5447 	s32 pval = 0;
5448 	s32 gval = 0;
5449 	s32 err = 0;
5450 	s32 wsec_val = 0;
5451 #ifdef BCMWAPI_WPI
5452 	s32 wapi_val = 0;
5453 	s32 val = 0;
5454 #endif // endif
5455 	s32 bssidx;
5456 #ifdef WL_GCMP
5457 	uint32 algos = 0, mask = 0;
5458 #endif /* WL_GCMP */
5459 
5460 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5461 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5462 		return BCME_ERROR;
5463 	}
5464 
5465 	if (sme->crypto.n_ciphers_pairwise) {
5466 		pval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.ciphers_pairwise[0]);
5467 		if (pval == WSEC_NONE) {
5468 			WL_ERR(("invalid cipher pairwise (%d)\n", sme->crypto.ciphers_pairwise[0]));
5469 			return BCME_BADARG;
5470 		}
5471 		switch (sme->crypto.ciphers_pairwise[0]) {
5472 #ifdef BCMWAPI_WPI
5473 		case WLAN_CIPHER_SUITE_SMS4:
5474 			val = pval;
5475 			err = wl_set_set_wapi_ie(dev, sme);
5476 			if (unlikely(err)) {
5477 				WL_DBG(("Set wapi ie failed  \n"));
5478 				return err;
5479 			} else {
5480 				WL_DBG(("Set wapi ie succeded\n"));
5481 			}
5482 			wapi_val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5483 			WL_INFORM_MEM(("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val, dev->name));
5484 			err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wapi_val, bssidx);
5485 			if (unlikely(err)) {
5486 				WL_ERR(("set wpa_auth failed (%d)\n", err));
5487 				return err;
5488 			}
5489 			break;
5490 #endif /* BCMWAPI_WPI */
5491 #ifdef WL_GCMP
5492 		case WLAN_CIPHER_SUITE_GCMP:
5493 		case WLAN_CIPHER_SUITE_GCMP_256:
5494 			algos = KEY_ALGO_MASK(wl_rsn_cipher_wsec_key_algo_lookup(
5495 					sme->crypto.ciphers_pairwise[0]));
5496 			mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
5497 			break;
5498 #endif /* WL_GCMP */
5499 		default: /* No post processing required */
5500 			break;
5501 		}
5502 	}
5503 #if defined(BCMSUP_4WAY_HANDSHAKE)
5504 	/* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
5505 	 * handshake.
5506 	 * Note that the FW feature flag only exists on kernels that support the
5507 	 * FT-EAP AKM suite.
5508 	 */
5509 	if (cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) {
5510 		err = wldev_iovar_setint_bsscfg(dev, "sup_wpa", 1, bssidx);
5511 		if (err) {
5512 			WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err));
5513 			return err;
5514 		} else {
5515 			WL_INFORM_MEM(("idsup enabled.\n"));
5516 		}
5517 	}
5518 #endif /* BCMSUP_4WAY_HANDSHAKE */
5519 	if (sme->crypto.cipher_group) {
5520 		gval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.cipher_group);
5521 		if (gval == WSEC_NONE) {
5522 			WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group));
5523 			return BCME_BADARG;
5524 		}
5525 		switch (sme->crypto.cipher_group) {
5526 #ifdef BCMWAPI_WPI
5527 		case WLAN_CIPHER_SUITE_SMS4:
5528 			val = gval;
5529 			break;
5530 #endif // endif
5531 #ifdef WL_GCMP
5532 		case WLAN_CIPHER_SUITE_GCMP:
5533 		case WLAN_CIPHER_SUITE_GCMP_256:
5534 			algos = KEY_ALGO_MASK(
5535 				wl_rsn_cipher_wsec_key_algo_lookup(sme->crypto.cipher_group));
5536 			mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
5537 			break;
5538 #endif /* WL_GCMP */
5539 		default: /* No post processing required */
5540 			break;
5541 		}
5542 	}
5543 
5544 	WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
5545 #ifdef WL_GCMP
5546 	WL_DBG(("algos:%x, mask:%x", algos, mask));
5547 #endif /* WL_GCMP */
5548 
5549 	if (is_wps_conn(sme)) {
5550 		if (sme->privacy) {
5551 			wsec_val = 4;
5552 		} else {
5553 			/* WPS-2.0 allows no security */
5554 			wsec_val = 0;
5555 		}
5556 	} else {
5557 #ifdef BCMWAPI_WPI
5558 		if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) {
5559 			WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
5560 			wsec_val = val;
5561 		} else
5562 #endif // endif
5563 		{
5564 			WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
5565 			wsec_val = pval | gval;
5566 		}
5567 	}
5568 
5569 	WL_INFORM_MEM(("[%s] wl wsec 0x%x\n", dev->name, wsec_val));
5570 	err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec_val, bssidx);
5571 	if (unlikely(err)) {
5572 		WL_ERR(("error (%d)\n", err));
5573 		return err;
5574 	}
5575 #ifdef WL_GCMP
5576 	wl_set_wsec_info_algos(dev, algos, mask);
5577 #endif /* WL_GCMP */
5578 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5579 	sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
5580 	sec->cipher_group = sme->crypto.cipher_group;
5581 	return err;
5582 }
5583 #ifdef WL_GCMP
5584 static s32
wl_set_wsec_info_algos(struct net_device * dev,uint32 algos,uint32 mask)5585 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask)
5586 {
5587 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5588 	s32 bssidx;
5589 	s32 err = 0;
5590 	wl_wsec_info_t *wsec_info;
5591 	bcm_xtlv_t *wsec_info_tlv;
5592 	uint16 tlv_data_len;
5593 	uint8 tlv_data[8];
5594 	uint32 param_len;
5595 	uint8 * buf;
5596 
5597 	WL_DBG(("enter.\n"));
5598 	if (!cfg) {
5599 		return BCME_ERROR;
5600 	}
5601 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5602 		WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
5603 		return BCME_ERROR;
5604 	}
5605 
5606 	buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5607 	if (!buf) {
5608 		WL_ERR(("No memory"));
5609 		return BCME_NOMEM;
5610 	}
5611 	wsec_info = (wl_wsec_info_t *)buf;
5612 	wsec_info->version = WL_WSEC_INFO_VERSION;
5613 	wsec_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
5614 
5615 	wsec_info->num_tlvs++;
5616 	tlv_data_len = sizeof(tlv_data);
5617 	err = memcpy_s(tlv_data, sizeof(tlv_data), &algos, sizeof(algos));
5618 	if (err) {
5619 		WL_ERR(("memcpy_s algos error (%d)\n", err));
5620 		goto exit;
5621 	}
5622 	err = memcpy_s(tlv_data + sizeof(algos), sizeof(mask), &mask, sizeof(mask));
5623 	if (err) {
5624 		WL_ERR(("memcpy_s mask error (%d)\n", err));
5625 		goto exit;
5626 	}
5627 	bcm_xtlv_pack_xtlv(wsec_info_tlv, WL_WSEC_INFO_BSS_ALGOS, tlv_data_len, tlv_data, 0);
5628 	param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN + tlv_data_len;
5629 
5630 	err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
5631 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5632 	if (unlikely(err) && (err != BCME_UNSUPPORTED))
5633 		WL_ERR(("wsec_info error (%d)\n", err));
5634 exit:
5635 	MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5636 	return err;
5637 }
5638 #endif /* WL_GCMP */
5639 #ifdef MFP
5640 static s32
wl_cfg80211_set_mfp(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme)5641 wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
5642 	struct net_device *dev,
5643 	struct cfg80211_connect_params *sme)
5644 {
5645 	s32 mfp = WL_MFP_NONE;
5646 	s32 current_mfp = WL_MFP_NONE;
5647 	const bcm_tlv_t *wpa2_ie;
5648 	const u8* rsn_cap = NULL;
5649 	bool fw_support = false;
5650 	int err, count = 0;
5651 	const u8 *eptr = NULL, *ptr = NULL;
5652 	const u8* group_mgmt_cs = NULL;
5653 	const wpa_pmkid_list_t* pmkid = NULL;
5654 
5655 	if (!sme) {
5656 		/* No connection params from userspace, Do nothing. */
5657 		return 0;
5658 	}
5659 
5660 	/* Check fw support and retreive current mfp val */
5661 	err = wldev_iovar_getint(dev, "mfp", &current_mfp);
5662 	if (!err) {
5663 		fw_support = true;
5664 	}
5665 
5666 	/* Parse the wpa2ie to decode the MFP capablity */
5667 	if (((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
5668 			DOT11_MNG_RSN_ID)) != NULL) &&
5669 			(wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) {
5670 		WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap[0], rsn_cap[1]));
5671 		/* Check for MFP cap in the RSN capability field */
5672 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
5673 		if (sme->mfp)
5674 #endif // endif
5675 		{
5676 			if (rsn_cap[0] & RSN_CAP_MFPR) {
5677 				mfp = WL_MFP_REQUIRED;
5678 			} else if (rsn_cap[0] & RSN_CAP_MFPC) {
5679 				mfp = WL_MFP_CAPABLE;
5680 			}
5681 		}
5682 		/*
5683 		 * eptr --> end/last byte addr of wpa2_ie
5684 		 * ptr --> to keep track of current/required byte addr
5685 		 */
5686 		eptr = (const u8*)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN);
5687 		/* pointing ptr to the next byte after rns_cap */
5688 		ptr = (const u8*)rsn_cap + RSN_CAP_LEN;
5689 		if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) {
5690 			/* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
5691 			pmkid = (const wpa_pmkid_list_t*)ptr;
5692 			count = pmkid->count.low | (pmkid->count.high << 8);
5693 			/* ptr now to point to last byte addr of pmkid */
5694 			ptr = (const u8*)pmkid + (count * WPA2_PMKID_LEN
5695 					+ WPA2_PMKID_COUNT_LEN);
5696 			if ((eptr - ptr) >= WPA_SUITE_LEN) {
5697 				/* group_mgmt_cs now to point to first byte addr of bip */
5698 				group_mgmt_cs = ptr;
5699 			}
5700 		}
5701 	}
5702 
5703 	WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n",
5704 		mfp, wpa2_ie, fw_support));
5705 
5706 	if (fw_support == false) {
5707 		if (mfp == WL_MFP_REQUIRED) {
5708 			/* if mfp > 0, mfp capability set in wpa ie, but
5709 			 * FW indicated error for mfp. Propagate the error up.
5710 			 */
5711 			WL_ERR(("mfp capability found in wpaie. But fw doesn't "
5712 				"seem to support MFP\n"));
5713 			err = -EINVAL;
5714 			goto exit;
5715 		} else {
5716 			/* Firmware doesn't support mfp. But since connection request
5717 			 * is for non-mfp case, don't bother.
5718 			 */
5719 			err = BCME_OK;
5720 			goto exit;
5721 		}
5722 	} else if (mfp != current_mfp) {
5723 		err = wldev_iovar_setint(dev, "mfp", mfp);
5724 		if (unlikely(err)) {
5725 			WL_ERR(("mfp (%d) set failed ret:%d \n", mfp, err));
5726 			goto exit;
5727 		}
5728 		WL_INFORM_MEM(("[%s] wl mfp 0x%x\n", dev->name, mfp));
5729 	}
5730 
5731 	if (group_mgmt_cs && bcmp((const uint8 *)WPA2_OUI,
5732 			group_mgmt_cs, (WPA_SUITE_LEN - 1)) == 0) {
5733 		WL_DBG(("BIP is found\n"));
5734 		err = wldev_iovar_setbuf(dev, "bip",
5735 			group_mgmt_cs, WPA_SUITE_LEN, cfg->ioctl_buf,
5736 			WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5737 		/*
5738 		 * Dont return failure for unsupported cases
5739 		 * of bip iovar for backward compatibility
5740 		 */
5741 		if (err != BCME_UNSUPPORTED && err < 0) {
5742 			WL_ERR(("bip set error (%d)\n", err));
5743 				{
5744 					goto exit;
5745 				}
5746 		} else {
5747 			WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n",
5748 				dev->name, group_mgmt_cs[0], group_mgmt_cs[1],
5749 				group_mgmt_cs[2]));
5750 		}
5751 	}
5752 exit:
5753 	if (err) {
5754 		wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
5755 			FW_LOGSET_MASK_ALL);
5756 	}
5757 
5758 	return 0;
5759 }
5760 #endif /* MFP */
5761 
5762 #ifdef WL_FILS
5763 bool
wl_is_fils_supported(struct net_device * ndev)5764 wl_is_fils_supported(struct net_device *ndev)
5765 {
5766 	s32 err;
5767 	u8 ioctl_buf[WLC_IOCTL_SMLEN] = {0};
5768 	bcm_iov_buf_t *iov_buf = (bcm_iov_buf_t *)ioctl_buf;
5769 
5770 	iov_buf->version = WL_FILS_IOV_VERSION;
5771 	err = wldev_iovar_getbuf(ndev, "fils", (uint8*)iov_buf, sizeof(bcm_iov_buf_t),
5772 		iov_buf, WLC_IOCTL_SMLEN, NULL);
5773 	if (err == BCME_UNSUPPORTED) {
5774 		WL_DBG(("FILS NOT supported\n"));
5775 		return false;
5776 	}
5777 
5778 	WL_INFORM(("FILS supported\n"));
5779 	return true;
5780 }
5781 
5782 #define WL_NUM_OF_TLV_IN_SET_FILS_PARAMS	4u
5783 static s32
wl_set_fils_params(struct net_device * dev,struct cfg80211_connect_params * sme)5784 wl_set_fils_params(struct net_device *dev, struct cfg80211_connect_params *sme)
5785 {
5786 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5787 	bcm_iov_buf_t *iov_buf = NULL;
5788 	bcm_xtlvbuf_t tbuf;
5789 	s32 err = BCME_OK;
5790 	uint32 buf_size;
5791 
5792 	if ((sme->auth_type != NL80211_AUTHTYPE_FILS_SK) &&
5793 		(sme->auth_type != NL80211_AUTHTYPE_FILS_SK_PFS) &&
5794 		(sme->auth_type != NL80211_AUTHTYPE_FILS_PK)) {
5795 		return BCME_OK;
5796 	}
5797 	if (sme->fils_erp_rrk_len > WL_MAX_FILS_KEY_LEN) {
5798 		WL_ERR(("%s: FILS rRK exceed allowed size\n", __FUNCTION__));
5799 		err = BCME_BADARG;
5800 		goto exit;
5801 	}
5802 	/* Check incoming buffer length */
5803 	buf_size = sme->fils_erp_username_len + sme->fils_erp_realm_len + sme->fils_erp_rrk_len +
5804 		sizeof(sme->fils_erp_next_seq_num) +
5805 		WL_NUM_OF_TLV_IN_SET_FILS_PARAMS * BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32) +
5806 		sizeof(bcm_iov_buf_t) - 1u;
5807 
5808 	if (buf_size > WLC_IOCTL_SMLEN) {
5809 		WL_ERR(("%s: FILS connect params arguments exceed allowed size\n", __FUNCTION__));
5810 		err = BCME_BADARG;
5811 		goto exit;
5812 	}
5813 	iov_buf = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
5814 	if (!iov_buf) {
5815 		WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, WLC_IOCTL_SMLEN));
5816 		err = BCME_NOMEM;
5817 		goto exit;
5818 	}
5819 	iov_buf->version = WL_FILS_IOV_VERSION;
5820 	iov_buf->id = WL_FILS_CMD_ADD_CONNECT_PARAMS;
5821 	/* check if this should be len w/o headers */
5822 	err = bcm_xtlv_buf_init(&tbuf, (uint8*)&iov_buf->data[0],
5823 		WLC_IOCTL_SMLEN - sizeof(bcm_iov_buf_t) + sizeof(uint16),
5824 		BCM_XTLV_OPTION_ALIGN32);
5825 	if (err != BCME_OK) {
5826 		WL_ERR(("%s: xtlv_context initialization failed\n", __FUNCTION__));
5827 		goto exit;
5828 	}
5829 	if (sme->fils_erp_username_len && sme->fils_erp_username != NULL) {
5830 		err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_USERNAME,
5831 			sme->fils_erp_username, sme->fils_erp_username_len);
5832 		if (err != BCME_OK) {
5833 			WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5834 			goto exit;
5835 		}
5836 	}
5837 	if (sme->fils_erp_realm_len && sme->fils_erp_realm != NULL) {
5838 		err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_REALM,
5839 			sme->fils_erp_realm, sme->fils_erp_realm_len);
5840 		if (err != BCME_OK) {
5841 			WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5842 			goto exit;
5843 		}
5844 	}
5845 	if (sme->fils_erp_rrk_len && sme->fils_erp_rrk != NULL) {
5846 		err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_RRK,
5847 			sme->fils_erp_rrk, sme->fils_erp_rrk_len);
5848 		if (err != BCME_OK) {
5849 			WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5850 			goto exit;
5851 		}
5852 	}
5853 	err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM,
5854 			(u8 *)&sme->fils_erp_next_seq_num, sizeof(sme->fils_erp_next_seq_num));
5855 	if (err != BCME_OK) {
5856 		WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5857 		goto exit;
5858 	}
5859 	iov_buf->len = bcm_xtlv_buf_len(&tbuf);
5860 	err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf->len + sizeof(bcm_iov_buf_t) -
5861 		sizeof(uint16), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5862 	if (unlikely(err)) {
5863 		 WL_ERR(("set fils params ioctl error (%d)\n", err));
5864 		 goto exit;
5865 	}
5866 
5867 exit:
5868 	if (err != BCME_OK) {
5869 		WL_ERR(("set FILS params error %d\n", err));
5870 	}
5871 	else {
5872 		WL_INFORM_MEM(("FILS parameters succesfully applied\n"));
5873 	}
5874 	if (iov_buf) {
5875 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_SMLEN);
5876 	}
5877 	return err;
5878 }
5879 
5880 #if !defined(WL_FILS_ROAM_OFFLD) && defined(WL_FILS)
5881 static s32
wl_get_bcn_timeout(struct net_device * dev,u32 * bcn_timeout)5882 wl_get_bcn_timeout(struct net_device *dev, u32 *bcn_timeout)
5883 {
5884 	s32 err = 0;
5885 
5886 	err = wldev_iovar_getint(dev, "bcn_timeout", bcn_timeout);
5887 	if (unlikely(err)) {
5888 		WL_ERR(("could not get bcn_timeout (%d)\n", err));
5889 	}
5890 	return err;
5891 }
5892 
5893 #define WL_ROAM_ENABLE	0
5894 #define WL_ROAM_DISABLE 1
5895 /* Beacon Timeout beacon loss in case FILS roaming offload is not supported by fw */
5896 #define WL_BCN_TIMEOUT	3
5897 
5898 static s32
wl_fils_toggle_roaming(struct net_device * dev,u32 auth_type)5899 wl_fils_toggle_roaming(struct net_device *dev, u32 auth_type)
5900 {
5901 	s32 err = 0;
5902 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5903 
5904 	if (WPA2_AUTH_IS_FILS(auth_type) && !cfg->fils_info.fils_roam_disabled) {
5905 		err = wl_get_bcn_timeout(dev, &cfg->fils_info.fils_bcn_timeout_cache);
5906 		if (unlikely(err)) {
5907 			return err;
5908 		}
5909 		wl_dongle_roam(dev, WL_ROAM_DISABLE, WL_BCN_TIMEOUT);
5910 		cfg->fils_info.fils_roam_disabled = true;
5911 		WL_INFORM_MEM(("fw roam disabled for FILS akm\n"));
5912 	} else if (cfg->fils_info.fils_roam_disabled) {
5913 		/* Enable roaming back for other auth types */
5914 		wl_dongle_roam(dev, WL_ROAM_ENABLE, cfg->fils_info.fils_bcn_timeout_cache);
5915 		cfg->fils_info.fils_roam_disabled = false;
5916 		WL_INFORM_MEM(("fw roam enabled\n"));
5917 	}
5918 	return err;
5919 }
5920 #endif /* !WL_FILS_ROAM_OFFLD && WL_FILS */
5921 #endif /* WL_FILS */
5922 
5923 static s32
wl_set_key_mgmt(struct net_device * dev,struct cfg80211_connect_params * sme)5924 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
5925 {
5926 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5927 	struct wl_security *sec;
5928 	s32 val = 0;
5929 	s32 err = 0;
5930 	s32 bssidx;
5931 
5932 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5933 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5934 		return BCME_ERROR;
5935 	}
5936 
5937 	if (sme->crypto.n_akm_suites) {
5938 		err = wldev_iovar_getint(dev, "wpa_auth", &val);
5939 		if (unlikely(err)) {
5940 			WL_ERR(("could not get wpa_auth (%d)\n", err));
5941 			return err;
5942 		}
5943 		if (val & (WPA_AUTH_PSK |
5944 			WPA_AUTH_UNSPECIFIED)) {
5945 			switch (sme->crypto.akm_suites[0]) {
5946 			case WLAN_AKM_SUITE_8021X:
5947 				val = WPA_AUTH_UNSPECIFIED;
5948 				break;
5949 			case WLAN_AKM_SUITE_PSK:
5950 				val = WPA_AUTH_PSK;
5951 				break;
5952 			default:
5953 				WL_ERR(("invalid akm suite (0x%x)\n",
5954 					sme->crypto.akm_suites[0]));
5955 				return -EINVAL;
5956 			}
5957 		} else if (val & (WPA2_AUTH_PSK |
5958 			WPA2_AUTH_UNSPECIFIED)) {
5959 			switch (sme->crypto.akm_suites[0]) {
5960 #ifdef MFP
5961 			case WL_AKM_SUITE_SHA256_1X:
5962 				val = WPA2_AUTH_1X_SHA256;
5963 				break;
5964 			case WL_AKM_SUITE_SHA256_PSK:
5965 				val = WPA2_AUTH_PSK_SHA256;
5966 				break;
5967 #endif /* MFP */
5968 			case WLAN_AKM_SUITE_8021X:
5969 			case WLAN_AKM_SUITE_PSK:
5970 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
5971 			case WLAN_AKM_SUITE_FT_8021X:
5972 #endif // endif
5973 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
5974 			case WLAN_AKM_SUITE_FT_PSK:
5975 #endif // endif
5976 			case WLAN_AKM_SUITE_FILS_SHA256:
5977 			case WLAN_AKM_SUITE_FILS_SHA384:
5978 			case WLAN_AKM_SUITE_8021X_SUITE_B:
5979 			case WLAN_AKM_SUITE_8021X_SUITE_B_192:
5980 #ifdef WL_OWE
5981 			case WLAN_AKM_SUITE_OWE:
5982 #endif /* WL_OWE */
5983 			case WLAN_AKM_SUITE_FT_8021X_SHA384:
5984 				val = wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[0]);
5985 				break;
5986 			case WLAN_AKM_SUITE_FT_FILS_SHA256:
5987 				val = WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT;
5988 				break;
5989 			case WLAN_AKM_SUITE_FT_FILS_SHA384:
5990 				val = WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT;
5991 				break;
5992 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
5993 			case WLAN_AKM_SUITE_SAE:
5994 				val = WPA3_AUTH_SAE_PSK;
5995 				break;
5996 #endif /* WL_SAE || WL_CLIENT_SAE */
5997 			default:
5998 				WL_ERR(("invalid akm suite (0x%x)\n",
5999 					sme->crypto.akm_suites[0]));
6000 				return -EINVAL;
6001 			}
6002 		}
6003 #ifdef BCMWAPI_WPI
6004 		else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) {
6005 			switch (sme->crypto.akm_suites[0]) {
6006 			case WLAN_AKM_SUITE_WAPI_CERT:
6007 				val = WAPI_AUTH_UNSPECIFIED;
6008 				break;
6009 			case WLAN_AKM_SUITE_WAPI_PSK:
6010 				val = WAPI_AUTH_PSK;
6011 				break;
6012 			default:
6013 				WL_ERR(("invalid akm suite (0x%x)\n",
6014 					sme->crypto.akm_suites[0]));
6015 				return -EINVAL;
6016 			}
6017 		}
6018 #endif // endif
6019 
6020 #ifdef WL_FILS
6021 #if !defined(WL_FILS_ROAM_OFFLD)
6022 	err = wl_fils_toggle_roaming(dev, val);
6023 	if (unlikely(err)) {
6024 		return err;
6025 	}
6026 #endif /* !WL_FILS_ROAM_OFFLD */
6027 #endif /* !WL_FILS */
6028 
6029 #ifdef MFP
6030 		if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) {
6031 			WL_ERR(("MFP set failed err:%d\n", err));
6032 			return -EINVAL;
6033 		}
6034 #endif /* MFP */
6035 
6036 		WL_INFORM_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val));
6037 		err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
6038 		if (unlikely(err)) {
6039 			WL_ERR(("could not set wpa_auth (0x%x)\n", err));
6040 			return err;
6041 		}
6042 	}
6043 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6044 	sec->wpa_auth = sme->crypto.akm_suites[0];
6045 
6046 	return err;
6047 }
6048 
6049 static s32
wl_set_set_sharedkey(struct net_device * dev,struct cfg80211_connect_params * sme)6050 wl_set_set_sharedkey(struct net_device *dev,
6051 	struct cfg80211_connect_params *sme)
6052 {
6053 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6054 	struct wl_security *sec;
6055 	struct wl_wsec_key key;
6056 	s32 val;
6057 	s32 err = 0;
6058 	s32 bssidx;
6059 
6060 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6061 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6062 		return BCME_ERROR;
6063 	}
6064 
6065 	WL_DBG(("key len (%d)\n", sme->key_len));
6066 	if (sme->key_len) {
6067 		sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6068 		WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
6069 			sec->wpa_versions, sec->cipher_pairwise));
6070 		if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
6071 			NL80211_WPA_VERSION_2)) &&
6072 #ifdef BCMWAPI_WPI
6073 			!is_wapi(sec->cipher_pairwise) &&
6074 #endif // endif
6075 			(sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
6076 			WLAN_CIPHER_SUITE_WEP104)))
6077 		{
6078 			bzero(&key, sizeof(key));
6079 			key.len = (u32) sme->key_len;
6080 			key.index = (u32) sme->key_idx;
6081 			if (unlikely(key.len > sizeof(key.data))) {
6082 				WL_ERR(("Too long key length (%u)\n", key.len));
6083 				return -EINVAL;
6084 			}
6085 			memcpy(key.data, sme->key, key.len);
6086 			key.flags = WL_PRIMARY_KEY;
6087 			if ((sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP40) ||
6088 			    (sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP104)) {
6089 				key.algo = wl_rsn_cipher_wsec_key_algo_lookup(sec->cipher_pairwise);
6090 			} else {
6091 				WL_ERR(("Invalid algorithm (%d)\n",
6092 					sme->crypto.ciphers_pairwise[0]));
6093 				return -EINVAL;
6094 			}
6095 			/* Set the new key/index */
6096 			WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
6097 				key.len, key.index, key.algo));
6098 			WL_DBG(("key \"%s\"\n", key.data));
6099 			swap_key_from_BE(&key);
6100 			err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6101 				cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6102 			if (unlikely(err)) {
6103 				WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6104 				return err;
6105 			}
6106 			WL_INFORM_MEM(("key applied to fw\n"));
6107 			if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
6108 				WL_DBG(("set auth_type to shared key\n"));
6109 				val = WL_AUTH_SHARED_KEY;	/* shared key */
6110 				err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
6111 				if (unlikely(err)) {
6112 					WL_ERR(("set auth failed (%d)\n", err));
6113 					return err;
6114 				}
6115 			}
6116 		}
6117 	}
6118 	return err;
6119 }
6120 
6121 #if defined(ESCAN_RESULT_PATCH)
6122 static u8 connect_req_bssid[6];
6123 static u8 broad_bssid[6];
6124 #endif /* ESCAN_RESULT_PATCH */
6125 
6126 #if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
wl_get_chan_isvht80(struct net_device * net,dhd_pub_t * dhd)6127 static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
6128 {
6129 	u32 chanspec = 0;
6130 	bool isvht80 = 0;
6131 
6132 	if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK)
6133 		chanspec = wl_chspec_driver_to_host(chanspec);
6134 
6135 	isvht80 = chanspec & WL_CHANSPEC_BW_80;
6136 	WL_DBG(("wl_get_chan_isvht80: chanspec(%x:%d)\n", chanspec, isvht80));
6137 
6138 	return isvht80;
6139 }
6140 #endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
6141 
wl_cfg80211_cleanup_mismatch_status(struct net_device * dev,struct bcm_cfg80211 * cfg,bool disassociate)6142 int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80211 *cfg,
6143 	bool disassociate)
6144 {
6145 	scb_val_t scbval;
6146 	int err = TRUE;
6147 	int wait_cnt;
6148 
6149 	if (disassociate) {
6150 		dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6151 		BCM_REFERENCE(dhdp);
6152 		DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
6153 			dhd_net2idx(dhdp->info, dev), DOT11_RC_DISASSOC_LEAVING);
6154 		WL_ERR(("Disassociate previous connection!\n"));
6155 		wl_set_drv_status(cfg, DISCONNECTING, dev);
6156 		scbval.val = DOT11_RC_DISASSOC_LEAVING;
6157 		scbval.val = htod32(scbval.val);
6158 
6159 		err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6160 				sizeof(scb_val_t));
6161 		if (unlikely(err)) {
6162 			wl_clr_drv_status(cfg, DISCONNECTING, dev);
6163 			WL_ERR(("error (%d)\n", err));
6164 			return err;
6165 		}
6166 		wait_cnt = 500/10;
6167 	} else {
6168 		wait_cnt = 200/10;
6169 		WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
6170 		if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6171 			wl_clr_drv_status(cfg, DISCONNECTING, dev);
6172 		}
6173 	}
6174 
6175 	while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
6176 		WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
6177 			wait_cnt));
6178 		wait_cnt--;
6179 		OSL_SLEEP(10);
6180 	}
6181 
6182 	if (wait_cnt == 0) {
6183 		WL_ERR(("DISCONNECING clean up failed!\n"));
6184 		/* Clear DISCONNECTING driver status as we have made sufficient attempts
6185 		* for driver clean up.
6186 		*/
6187 		wl_clr_drv_status(cfg, DISCONNECTING, dev);
6188 		wl_clr_drv_status(cfg, CONNECTED, dev);
6189 		return BCME_NOTREADY;
6190 	}
6191 	return BCME_OK;
6192 }
6193 
6194 #ifdef WL_FILS
6195 static int
wl_fils_add_hlp_container(struct bcm_cfg80211 * cfg,struct net_device * dev,const uint8 * ie_buf,uint16 ie_len)6196 wl_fils_add_hlp_container(struct bcm_cfg80211 *cfg, struct net_device *dev,
6197 	const uint8* ie_buf, uint16 ie_len)
6198 {
6199 	const bcm_tlv_ext_t *hlp_ie;
6200 
6201 	if ((hlp_ie = (const bcm_tlv_ext_t*)bcm_parse_tlvs_dot11((const uint8 *)ie_buf, ie_len,
6202 		FILS_HLP_CONTAINER_EXT_ID, TRUE))) {
6203 		u16 hlp_len = hlp_ie->len;
6204 		u16 left_len = (ie_len - ((const uint8*)hlp_ie - ie_buf));
6205 		bcm_iov_buf_t *iov_buf = 0;
6206 		uint8* pxtlv;
6207 		int err;
6208 		size_t iov_buf_len;
6209 		bcm_tlv_dot11_frag_tot_len(ie_buf, ie_len, FILS_HLP_CONTAINER_EXT_ID,
6210 			TRUE, (uint*)&hlp_len);
6211 
6212 		hlp_len += BCM_TLV_EXT_HDR_SIZE;
6213 
6214 		if ((hlp_len > DOT11_MAX_MPDU_BODY_LEN) || (hlp_len > left_len)) {
6215 			WL_ERR(("bad HLP length %d\n", hlp_len));
6216 			return EFAULT;
6217 		}
6218 		iov_buf_len = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) - 1 + hlp_len;
6219 		iov_buf = MALLOCZ(cfg->osh, iov_buf_len);
6220 		if (iov_buf == NULL) {
6221 			WL_ERR(("failed to allocated iov_buf\n"));
6222 			return ENOMEM;
6223 		}
6224 
6225 		prhex("HLP, HLP", (const uchar *)hlp_ie, hlp_len);
6226 
6227 		pxtlv = (uint8 *)&iov_buf->data[0];
6228 		((bcm_xtlv_t*)pxtlv)->id = WL_FILS_XTLV_HLP_IE;
6229 		((bcm_xtlv_t*)pxtlv)->len = hlp_len;
6230 
6231 		memcpy(((bcm_xtlv_t*)pxtlv)->data, hlp_ie, ((bcm_xtlv_t*)pxtlv)->len);
6232 
6233 		iov_buf->version = WL_FILS_IOV_VERSION;
6234 		iov_buf->id = WL_FILS_CMD_ADD_HLP_IE;
6235 		iov_buf->len = ((sizeof(bcm_xtlv_t)-1) + ((bcm_xtlv_t*)pxtlv)->len);
6236 
6237 		err = wldev_iovar_setbuf(dev, "fils", iov_buf,
6238 				sizeof(bcm_iov_buf_t) + iov_buf->len,
6239 				cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6240 		if (unlikely(err)) {
6241 			WL_ERR(("fils wldev_iovar_setbuf error (%d)\n", err));
6242 		}
6243 		else {
6244 			WL_INFORM_MEM(("FILS HLP Packet succesfully updated\n"));
6245 		}
6246 		MFREE(cfg->osh, iov_buf, iov_buf_len);
6247 	}
6248 	return BCME_OK;
6249 }
6250 #endif /* WL_FILS */
6251 
6252 #if defined(WL_FILS)
6253 #ifndef UPDATE_FILS_ERP_INFO
6254 #define UPDATE_FILS_ERP_INFO	BIT(1)
6255 #define UPDATE_AUTH_TYPE	BIT(2)
6256 #endif // endif
6257 
6258 static int
wl_cfg80211_update_connect_params(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme,u32 changed)6259 wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
6260 	struct cfg80211_connect_params *sme, u32 changed)
6261 {
6262 	s32 err = BCME_OK;
6263 	if (changed & UPDATE_FILS_ERP_INFO) {
6264 		err = wl_set_fils_params(dev, sme);
6265 
6266 		if (unlikely(err)) {
6267 			WL_ERR(("Invalid FILS params\n"));
6268 			goto exit;
6269 		}
6270 	}
6271 	if (changed & UPDATE_AUTH_TYPE) {
6272 		err = wl_set_auth_type(dev, sme);
6273 		if (unlikely(err)) {
6274 			WL_ERR(("Invalid auth type\n"));
6275 			goto exit;
6276 		}
6277 	}
6278 	if ((changed & UPDATE_FILS_ERP_INFO) && !(changed & UPDATE_AUTH_TYPE)) {
6279 		WL_DBG(("Warning: FILS ERP params are set, but authentication type - not\n"));
6280 	}
6281 exit:
6282 	return err;
6283 
6284 }
6285 #endif /* WL_FILS */
6286 
6287 #define MAX_SCAN_ABORT_WAIT_CNT 20
6288 #define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
6289 
6290 #ifndef CONFIG_AP6XXX_WIFI6_HDF
6291 static
6292 #endif
6293 s32
wl_cfg80211_connect(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme)6294 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
6295 	struct cfg80211_connect_params *sme)
6296 {
6297 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6298 	struct ieee80211_channel *chan = sme->channel;
6299 	wl_extjoin_params_t *ext_join_params;
6300 	struct wl_join_params join_params;
6301 	size_t join_params_size;
6302 	dhd_pub_t *dhdp =  (dhd_pub_t *)(cfg->pub);
6303 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6304 	s32 roam_trigger[2] = {0, 0};
6305 #endif /* ROAM_AP_ENV_DETECTION */
6306 	s32 err = 0;
6307 	const wpa_ie_fixed_t *wpa_ie;
6308 	const bcm_tlv_t *wpa2_ie;
6309 	const u8* wpaie  = 0;
6310 	u32 wpaie_len = 0;
6311 	u32 chan_cnt = 0;
6312 	struct ether_addr bssid;
6313 	s32 bssidx = -1;
6314 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6315 	bool skip_hints = fw_ap_select;
6316 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6317 #ifdef ESCAN_CHANNEL_CACHE
6318 	chanspec_t chanspec_list[MAX_ROAM_CHANNEL];
6319 #endif /* ESCAN_CHANNEL_CACHE */
6320 	int wait_cnt;
6321 	char sec[32];
6322 
6323 	WL_DBG(("In %s\n", dev->name));
6324 	if (!dev) {
6325 		WL_ERR(("dev is null\n"));
6326 		return -EINVAL;
6327 	}
6328 	BCM_REFERENCE(dhdp);
6329 	DHD_STATLOG_CTRL(dhdp, ST(ASSOC_START), dhd_net2idx(dhdp->info, dev), 0);
6330 
6331 #ifdef ESCAN_CHANNEL_CACHE
6332 	memset(chanspec_list, 0, (sizeof(chanspec_t) * MAX_ROAM_CHANNEL));
6333 #endif /* ESCAN_CHANNEL_CACHE */
6334 
6335 	/* Connection attempted via linux-wireless */
6336 	wl_set_drv_status(cfg, CFG80211_CONNECT, dev);
6337 #ifdef DHDTCPSYNC_FLOOD_BLK
6338 	dhd_reset_tcpsync_info_by_dev(dev);
6339 #endif /* DHDTCPSYNC_FLOOD_BLK */
6340 
6341 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6342 #ifdef WL_SKIP_CONNECT_HINTS
6343 	skip_hints = true;
6344 #elif defined(WL_FW_OCE_AP_SELECT)
6345 	/* override bssid_hint for oce networks */
6346 	skip_hints = (fw_ap_select && wl_cfg80211_is_oce_ap(wiphy, sme->bssid_hint));
6347 #endif // endif
6348 	if (skip_hints) {
6349 		/* Let fw choose the best AP */
6350 		WL_INFORM(("skipping bssid & channel hint\n"));
6351 	} else {
6352 		if (sme->channel_hint) {
6353 			chan = sme->channel_hint;
6354 			WL_INFORM_MEM(("channel_hint (%d), channel_hint center_freq (%d)\n",
6355 				ieee80211_frequency_to_channel(sme->channel_hint->center_freq),
6356 				sme->channel_hint->center_freq));
6357 		}
6358 		if (sme->bssid_hint) {
6359 			sme->bssid = sme->bssid_hint;
6360 			WL_INFORM_MEM(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
6361 		}
6362 	}
6363 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6364 
6365 	if (unlikely(!sme->ssid)) {
6366 		WL_ERR(("Invalid ssid\n"));
6367 		return -EOPNOTSUPP;
6368 	}
6369 
6370 	if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) {
6371 		WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n",
6372 			sme->ssid, sme->ssid_len));
6373 		return -EINVAL;
6374 	}
6375 
6376 	WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
6377 	if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
6378 		prhex(NULL, sme->ie, sme->ie_len);
6379 	}
6380 
6381 	RETURN_EIO_IF_NOT_UP(cfg);
6382 	/*
6383 	 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
6384 	 */
6385 	if (cfg->scan_request) {
6386 		WL_TRACE_HW4(("Aborting the scan! \n"));
6387 		wl_cfg80211_scan_abort(cfg);
6388 		wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
6389 		while (wl_get_drv_status(cfg, SCANNING, dev) && wait_cnt) {
6390 			WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
6391 			wait_cnt--;
6392 			OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
6393 		}
6394 		if (wl_get_drv_status(cfg, SCANNING, dev)) {
6395 			wl_cfg80211_cancel_scan(cfg);
6396 		}
6397 	}
6398 #ifdef WL_SCHED_SCAN
6399 	/* Locks are taken in wl_cfg80211_sched_scan_stop()
6400 	 * A start scan occuring during connect is unlikely
6401 	 */
6402 	if (cfg->sched_scan_req) {
6403 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
6404 		wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg),
6405 				cfg->sched_scan_req->reqid);
6406 #else
6407 		wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg));
6408 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
6409 	}
6410 #endif /* WL_SCHED_SCAN */
6411 #ifdef WL_CFG80211_GON_COLLISION
6412 	/* init block gon req count  */
6413 	cfg->block_gon_req_tx_count = 0;
6414 	cfg->block_gon_req_rx_count = 0;
6415 #endif /* WL_CFG80211_GON_COLLISION */
6416 #if defined(ESCAN_RESULT_PATCH)
6417 	if (sme->bssid)
6418 		memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN);
6419 	else
6420 		bzero(connect_req_bssid, ETHER_ADDR_LEN);
6421 	bzero(broad_bssid, ETHER_ADDR_LEN);
6422 #endif // endif
6423 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
6424 	maxrxpktglom = 0;
6425 #endif // endif
6426 	if (wl_get_drv_status(cfg, CONNECTING, dev) || wl_get_drv_status(cfg, CONNECTED, dev)) {
6427 		/* set nested connect bit to identify the context */
6428 		wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6429 		/* DHD prev status is CONNECTING/CONNECTED */
6430 		err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
6431 	} else if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6432 		/* DHD prev status is DISCONNECTING */
6433 		err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, false);
6434 	} else if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6435 		/* DHD previous status is not connected and FW connected */
6436 		if (wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) == 0) {
6437 			/* set nested connect bit to identify the context */
6438 			wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6439 			err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, true);
6440 		}
6441 	}
6442 	wl_ext_in4way_sync(dev, STA_WAIT_DISCONNECTED, WL_EXT_STATUS_CONNECTING, NULL);
6443 
6444 	if (sme->bssid) {
6445 		wl_update_prof(cfg, dev, NULL, sme->bssid, WL_PROF_LATEST_BSSID);
6446 	} else {
6447 		wl_update_prof(cfg, dev, NULL, &ether_bcast, WL_PROF_LATEST_BSSID);
6448 	}
6449 #ifdef SUPPORT_AP_BWCTRL
6450 	if (dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
6451 		wl_restore_ap_bw(cfg);
6452 	}
6453 #endif /* SUPPORT_AP_BWCTRL */
6454 	/* 'connect' request received */
6455 	wl_set_drv_status(cfg, CONNECTING, dev);
6456 	/* clear nested connect bit on proceeding for connection */
6457 	wl_clr_drv_status(cfg, NESTED_CONNECT, dev);
6458 
6459 	/* Clean BSSID */
6460 	bzero(&bssid, sizeof(bssid));
6461 	if (!wl_get_drv_status(cfg, DISCONNECTING, dev))
6462 		wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
6463 
6464 	if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) {
6465 		/* we only allow to connect using virtual interface in case of P2P */
6466 			if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6467 				WL_ERR(("Find p2p index from wdev(%p) failed\n",
6468 					dev->ieee80211_ptr));
6469 				err = BCME_ERROR;
6470 				goto exit;
6471 			}
6472 			wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6473 				VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
6474 	} else if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6475 		if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6476 			WL_ERR(("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr));
6477 			err = BCME_ERROR;
6478 			goto exit;
6479 		}
6480 
6481 		/* find the RSN_IE */
6482 		if ((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
6483 			DOT11_MNG_RSN_ID)) != NULL) {
6484 			WL_DBG((" WPA2 IE is found\n"));
6485 		}
6486 		/* find the WPA_IE */
6487 		if ((wpa_ie = wl_cfgp2p_find_wpaie(sme->ie,
6488 			sme->ie_len)) != NULL) {
6489 			WL_DBG((" WPA IE is found\n"));
6490 		}
6491 		if (wpa_ie != NULL || wpa2_ie != NULL) {
6492 			wpaie = (wpa_ie != NULL) ? (const u8 *)wpa_ie : (const u8 *)wpa2_ie;
6493 			wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
6494 			wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
6495 			err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
6496 				cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6497 			if (unlikely(err)) {
6498 				WL_ERR(("wpaie set error (%d)\n", err));
6499 				goto exit;
6500 			}
6501 		} else {
6502 			err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
6503 				cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6504 			if (unlikely(err)) {
6505 				WL_ERR(("wpaie set error (%d)\n", err));
6506 				goto exit;
6507 			}
6508 		}
6509 		err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6510 			VNDR_IE_ASSOCREQ_FLAG, (const u8 *)sme->ie, sme->ie_len);
6511 		if (unlikely(err)) {
6512 			goto exit;
6513 		}
6514 	}
6515 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6516 	if (dhdp->roam_env_detection) {
6517 		bool is_roamtrig_reset = TRUE;
6518 		bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection",
6519 			AP_ENV_DETECT_NOT_USED) == BCME_OK);
6520 #ifdef SKIP_ROAM_TRIGGER_RESET
6521 		roam_trigger[1] = WLC_BAND_2G;
6522 		is_roamtrig_reset =
6523 			(wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
6524 			sizeof(roam_trigger)) == BCME_OK) &&
6525 			(roam_trigger[0] == WL_AUTO_ROAM_TRIGGER-10);
6526 #endif /* SKIP_ROAM_TRIGGER_RESET */
6527 		if (is_roamtrig_reset && is_roam_env_ok) {
6528 			roam_trigger[0] = WL_AUTO_ROAM_TRIGGER;
6529 			roam_trigger[1] = WLC_BAND_ALL;
6530 		err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
6531 			sizeof(roam_trigger));
6532 		if (unlikely(err)) {
6533 				WL_ERR((" failed to restore roam_trigger for auto env"
6534 					" detection\n"));
6535 			}
6536 		}
6537 	}
6538 #endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
6539 	if (chan) {
6540 			cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
6541 			chan_cnt = 1;
6542 			WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel,
6543 				chan->center_freq, chan_cnt));
6544 	} else {
6545 			WL_DBG(("No channel info from user space\n"));
6546 			cfg->channel = 0;
6547 	}
6548 #ifdef ESCAN_CHANNEL_CACHE
6549 	/*
6550 	 * No channel information from user space. if ECC is enabled, the ECC
6551 	 * would prepare the channel list, else no channel would be provided
6552 	 * and firmware would need to do a full channel scan.
6553 	 *
6554 	 * Use cached channels. This might take slightly longer time compared
6555 	 * to using a single channel based join. But ECC would help choose
6556 	 * a better AP for a given ssid. For a given SSID there might multiple
6557 	 * APs on different channels and ECC would scan all those channels
6558 	 * before deciding up on the AP. This accounts for the additional delay.
6559 	 */
6560 	if (cfg->rcc_enabled || cfg->channel == 0)
6561 	{
6562 		wlc_ssid_t ssid;
6563 		int band;
6564 
6565 		err = wldev_get_band(dev, &band);
6566 		if (!err) {
6567 			set_roam_band(band);
6568 		}
6569 
6570 		memcpy(ssid.SSID, sme->ssid, sme->ssid_len);
6571 		ssid.SSID_len = (uint32)sme->ssid_len;
6572 		chan_cnt = get_roam_channel_list(cfg->channel, chanspec_list,
6573 				MAX_ROAM_CHANNEL, &ssid, ioctl_version);
6574 		WL_DBG(("RCC channel count:%d \n", chan_cnt));
6575 	}
6576 #endif /* ESCAN_CHANNEL_CACHE */
6577 	WL_DBG(("3. set wpa version \n"));
6578 
6579 	err = wl_set_wpa_version(dev, sme);
6580 	if (unlikely(err)) {
6581 		WL_ERR(("Invalid wpa_version\n"));
6582 		goto exit;
6583 	}
6584 #ifdef BCMWAPI_WPI
6585 	if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1)
6586 		WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n"));
6587 	else {
6588 		WL_DBG(("4. wl_set_auth_type\n"));
6589 #endif // endif
6590 		err = wl_set_auth_type(dev, sme);
6591 		if (unlikely(err)) {
6592 			WL_ERR(("Invalid auth type\n"));
6593 			goto exit;
6594 		}
6595 #ifdef BCMWAPI_WPI
6596 	}
6597 #endif // endif
6598 #ifdef WL_FILS
6599 	if (sme->ie && sme->ie_len) {
6600 		err = wl_fils_add_hlp_container(cfg, dev, sme->ie, sme->ie_len);
6601 		if (unlikely(err)) {
6602 			WL_ERR(("FILS sending HLP failed\n"));
6603 			goto exit;
6604 		}
6605 	}
6606 #endif /* WL_FILS */
6607 	err = wl_set_set_cipher(dev, sme);
6608 	if (unlikely(err)) {
6609 		WL_ERR(("Invalid ciper\n"));
6610 		goto exit;
6611 	}
6612 
6613 	err = wl_set_key_mgmt(dev, sme);
6614 	if (unlikely(err)) {
6615 		WL_ERR(("Invalid key mgmt\n"));
6616 		goto exit;
6617 	}
6618 
6619 	err = wl_set_set_sharedkey(dev, sme);
6620 	if (unlikely(err)) {
6621 		WL_ERR(("Invalid shared key\n"));
6622 		goto exit;
6623 	}
6624 #ifdef WL_FILS
6625 	err = wl_set_fils_params(dev, sme);
6626 	if (unlikely(err)) {
6627 		WL_ERR(("Invalid FILS params\n"));
6628 		goto exit;
6629 	}
6630 #endif /* WL_FILS */
6631 
6632 	/*
6633 	 *  Join with specific BSSID and cached SSID
6634 	 *  If SSID is zero join based on BSSID only
6635 	 */
6636 	join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
6637 		chan_cnt * sizeof(chanspec_t);
6638 	ext_join_params = (wl_extjoin_params_t *)MALLOCZ(cfg->osh, join_params_size);
6639 	if (ext_join_params == NULL) {
6640 		err = -ENOMEM;
6641 		wl_clr_drv_status(cfg, CONNECTING, dev);
6642 		goto exit;
6643 	}
6644 	ext_join_params->ssid.SSID_len =
6645 		(uint32)min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
6646 	memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
6647 	wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
6648 	ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
6649 	/* increate dwell time to receive probe response or detect Beacon
6650 	* from target AP at a noisy air only during connect command
6651 	*/
6652 	ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
6653 	ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
6654 	/* Set up join scan parameters */
6655 	ext_join_params->scan.scan_type = -1;
6656 	ext_join_params->scan.nprobes = chan_cnt ?
6657 		(ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
6658 	ext_join_params->scan.home_time = -1;
6659 
6660 	if (sme->bssid)
6661 		memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
6662 	else
6663 		memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
6664 	ext_join_params->assoc.chanspec_num = chan_cnt;
6665 
6666 	if (chan_cnt && !cfg->rcc_enabled) {
6667 		if (cfg->channel) {
6668 			/*
6669 			 * Use the channel provided by userspace
6670 			 */
6671 			u16 channel, band, bw, ctl_sb;
6672 			chanspec_t chspec;
6673 			channel = cfg->channel;
6674 			band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
6675 				: WL_CHANSPEC_BAND_5G;
6676 
6677 			/* Get min_bw set for the interface */
6678 			bw = WL_CHANSPEC_BW_20;
6679 			if (bw == INVCHANSPEC) {
6680 				WL_ERR(("Invalid chanspec \n"));
6681 				MFREE(cfg->osh, ext_join_params, join_params_size);
6682 				err = BCME_ERROR;
6683 				goto exit;
6684 			}
6685 
6686 			ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
6687 			chspec = (channel | band | bw | ctl_sb);
6688 			ext_join_params->assoc.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
6689 			ext_join_params->assoc.chanspec_list[0] |= chspec;
6690 			ext_join_params->assoc.chanspec_list[0] =
6691 				wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]);
6692 		}
6693 	}
6694 #ifdef ESCAN_CHANNEL_CACHE
6695 	 else {
6696 			memcpy(ext_join_params->assoc.chanspec_list, chanspec_list,
6697 				sizeof(chanspec_t) * chan_cnt);
6698 	}
6699 #endif /* ESCAN_CHANNEL_CACHE */
6700 	ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
6701 	if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
6702 		WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
6703 			ext_join_params->ssid.SSID_len));
6704 	}
6705 
6706 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6707 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6708 		MFREE(cfg->osh, ext_join_params, join_params_size);
6709 		err = BCME_ERROR;
6710 		goto exit;
6711 	}
6712 #ifdef WLTDLS
6713 	/* disable TDLS if number of connected interfaces is >= 1 */
6714 	wl_cfg80211_tdls_config(cfg, TDLS_STATE_CONNECT, false);
6715 #endif /* WLTDLS */
6716 #ifdef WL_EXT_IAPSTA
6717 	wl_ext_iapsta_update_channel(dhdp, dev, cfg->channel);
6718 #endif
6719 
6720 	wl_ext_get_sec(dev, 0, sec, sizeof(sec));
6721 	if (cfg->rcc_enabled) {
6722 		WL_MSG(dev->name, "Connecting with " MACDBG " ssid \"%s\", len (%d), "
6723 			"sec=%s, with rcc channels. chan_cnt:%d \n\n",
6724 			MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
6725 			ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, sec, chan_cnt);
6726 	} else {
6727 		WL_MSG(dev->name, "Connecting with " MACDBG " ssid \"%s\", len (%d), "
6728 			"sec=%s, channel=%d\n\n",
6729 			MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
6730 			ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, sec,
6731 			cfg->channel);
6732 	}
6733 	SUPP_LOG(("[%s] Connecting with " MACDBG " ssid \"%s\","
6734 		"channel:%d rcc:%d\n",
6735 		dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
6736 		ext_join_params->ssid.SSID, cfg->channel, cfg->rcc_enabled));
6737 	err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
6738 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6739 	MFREE(cfg->osh, ext_join_params, join_params_size);
6740 	if (err) {
6741 		wl_clr_drv_status(cfg, CONNECTING, dev);
6742 		if (err == BCME_UNSUPPORTED) {
6743 			WL_DBG(("join iovar is not supported\n"));
6744 			goto set_ssid;
6745 		} else {
6746 			WL_ERR(("join iovar error (%d)\n", err));
6747 			goto exit;
6748 		}
6749 	} else
6750 		goto exit;
6751 
6752 set_ssid:
6753 #if defined(ROAMEXP_SUPPORT)
6754 	/* Clear Blacklist bssid and Whitelist ssid list before join issue
6755 	 * This is temporary fix since currently firmware roaming is not
6756 	 * disabled by android framework before SSID join from framework
6757 	*/
6758 	/* Flush blacklist bssid content */
6759 	dhd_dev_set_blacklist_bssid(dev, NULL, 0, true);
6760 	/* Flush whitelist ssid content */
6761 	dhd_dev_set_whitelist_ssid(dev, NULL, 0, true);
6762 #endif /* ROAMEXP_SUPPORT */
6763 	bzero(&join_params, sizeof(join_params));
6764 	join_params_size = sizeof(join_params.ssid);
6765 
6766 	join_params.ssid.SSID_len = (uint32)min(sizeof(join_params.ssid.SSID), sme->ssid_len);
6767 	memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
6768 	join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
6769 	wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
6770 	if (sme->bssid)
6771 		memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
6772 	else
6773 		memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
6774 
6775 	if (wl_ch_to_chanspec(dev, cfg->channel, &join_params, &join_params_size) < 0) {
6776 		WL_ERR(("Invalid chanspec\n"));
6777 		return -EINVAL;
6778 	}
6779 
6780 	WL_DBG(("join_param_size %zu\n", join_params_size));
6781 
6782 	if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
6783 		WL_MSG(dev->name, "ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
6784 			join_params.ssid.SSID_len);
6785 	}
6786 	err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, join_params_size);
6787 exit:
6788 	if (err) {
6789 		WL_ERR(("error (%d)\n", err));
6790 		wl_clr_drv_status(cfg, CONNECTING, dev);
6791 		wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
6792 #ifdef WLTDLS
6793 		/* If connect fails, check whether we can enable back TDLS */
6794 		wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
6795 #endif /* WLTDLS */
6796 	}
6797 	if (!err)
6798 		wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY,
6799 			WL_EXT_STATUS_CONNECTING, NULL);
6800 #ifdef DBG_PKT_MON
6801 	if ((dev == bcmcfg_to_prmry_ndev(cfg)) && !err) {
6802 		DHD_DBG_PKT_MON_START(dhdp);
6803 	}
6804 #endif /* DBG_PKT_MON */
6805 	return err;
6806 }
6807 
wl_cfg80211_disconnect_state_sync(struct bcm_cfg80211 * cfg,struct net_device * dev)6808 static void wl_cfg80211_disconnect_state_sync(struct bcm_cfg80211 *cfg, struct net_device *dev)
6809 {
6810 	struct wireless_dev *wdev;
6811 	uint8 wait_cnt;
6812 
6813 	if (!dev || !dev->ieee80211_ptr) {
6814 		WL_ERR(("wrong ndev\n"));
6815 		return;
6816 	}
6817 
6818 	wdev = dev->ieee80211_ptr;
6819 	wait_cnt = WAIT_FOR_DISCONNECT_STATE_SYNC;
6820 	while ((wdev->current_bss) && wait_cnt) {
6821 		WL_DBG(("Waiting for disconnect sync, wait_cnt: %d\n", wait_cnt));
6822 		wait_cnt--;
6823 		OSL_SLEEP(50);
6824 	}
6825 
6826 	if (wait_cnt == 0) {
6827 		/* state didn't get cleared within given timeout */
6828 		WL_INFORM_MEM(("cfg80211 state. wdev->current_bss non null\n"));
6829 	} else {
6830 		WL_MEM(("cfg80211 disconnect state sync done\n"));
6831 	}
6832 
6833 }
6834 
wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 * cfg,struct net_device * dev)6835 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev)
6836 {
6837 	uint8 wait_cnt;
6838 	u32 status = 0;
6839 
6840 	wait_cnt = WAIT_FOR_DISCONNECT_MAX;
6841 	while ((status = wl_get_drv_status(cfg, DISCONNECTING, dev)) && wait_cnt) {
6842 		WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
6843 		wait_cnt--;
6844 		OSL_SLEEP(50);
6845 	}
6846 
6847 	WL_INFORM_MEM(("Wait for disconnection done. status:%d wait_cnt:%d\n", status, wait_cnt));
6848 	if (!wait_cnt && wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6849 		/* No response from firmware. Indicate connect result
6850 		 * to clear cfg80211 state machine
6851 		 */
6852 		WL_INFORM_MEM(("force send connect result\n"));
6853 		CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
6854 				WLAN_STATUS_UNSPECIFIED_FAILURE,
6855 				GFP_KERNEL);
6856 		wl_clr_drv_status(cfg, DISCONNECTING, dev);
6857 	}
6858 	return;
6859 }
6860 
6861 #ifndef CONFIG_AP6XXX_WIFI6_HDF
6862 static
6863 #endif
6864 s32
wl_cfg80211_disconnect(struct wiphy * wiphy,struct net_device * dev,u16 reason_code)6865 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
6866 	u16 reason_code)
6867 {
6868 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6869 	scb_val_t scbval;
6870 	bool act = false;
6871 	s32 err = 0;
6872 	u8 *curbssid = NULL;
6873 	u8 null_bssid[ETHER_ADDR_LEN];
6874 	s32 bssidx = 0;
6875 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6876 
6877 	RETURN_EIO_IF_NOT_UP(cfg);
6878 	act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
6879 	curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
6880 	WL_MSG(dev->name, "Reason %d, act %d\n", reason_code, act);
6881 
6882 	BCM_REFERENCE(dhdp);
6883 	DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_START),
6884 		dhd_net2idx(dhdp->info, dev), reason_code);
6885 #ifdef DHD_4WAYM4_FAIL_DISCONNECT
6886 	dhd_cleanup_m4_state_work(dhdp, dhd_net2idx(dhdp->info, dev));
6887 #endif /* DHD_4WAYM4_FAIL_DISCONNECT */
6888 
6889 #ifdef ESCAN_RESULT_PATCH
6890 	if (wl_get_drv_status(cfg, CONNECTING, dev)) {
6891 		if (curbssid) {
6892 			WL_ERR(("Disconnecting while CONNECTING status"
6893 				" connecting device: " MACDBG "\n", MAC2STRDBG(curbssid)));
6894 		} else {
6895 			WL_ERR(("Disconnecting while CONNECTING status \n"));
6896 		}
6897 		act = true;
6898 	}
6899 #endif /* ESCAN_RESULT_PATCH */
6900 
6901 	if (!curbssid) {
6902 		WL_ERR(("Disconnecting while CONNECTING status %d\n", (int)sizeof(null_bssid)));
6903 		bzero(null_bssid, sizeof(null_bssid));
6904 		curbssid = null_bssid;
6905 	}
6906 
6907 	if (act) {
6908 #ifdef DBG_PKT_MON
6909 		/* Stop packet monitor */
6910 		if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6911 			DHD_DBG_PKT_MON_STOP(dhdp);
6912 		}
6913 #endif /* DBG_PKT_MON */
6914 		/*
6915 		* Cancel ongoing scan to sync up with sme state machine of cfg80211.
6916 		*/
6917 		/* Let scan aborted by F/W */
6918 		if (cfg->scan_request) {
6919 			WL_TRACE_HW4(("Aborting the scan! \n"));
6920 			wl_cfg80211_cancel_scan(cfg);
6921 		}
6922 		/* Set DISCONNECTING state. We are clearing this state in all exit paths */
6923 		wl_set_drv_status(cfg, DISCONNECTING, dev);
6924 		if (wl_get_drv_status(cfg, CONNECTING, dev) ||
6925 			wl_get_drv_status(cfg, CONNECTED, dev)) {
6926 				scbval.val = reason_code;
6927 				memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
6928 				scbval.val = htod32(scbval.val);
6929 				WL_INFORM_MEM(("[%s] wl disassoc\n", dev->name));
6930 				err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6931 						sizeof(scb_val_t));
6932 				if (unlikely(err)) {
6933 					wl_clr_drv_status(cfg, DISCONNECTING, dev);
6934 					WL_ERR(("error (%d)\n", err));
6935 					goto exit;
6936 				}
6937 				wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
6938 					WL_EXT_STATUS_DISCONNECTING, NULL);
6939 		}
6940 #ifdef WL_WPS_SYNC
6941 		/* If are in WPS reauth state, then we would be
6942 		 * dropping the link down events. Ensure that
6943 		 * Event is sent up for the disconnect Req
6944 		 */
6945 		if (wl_wps_session_update(dev,
6946 			WPS_STATE_DISCONNECT, curbssid) == BCME_OK) {
6947 			WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
6948 			wl_clr_drv_status(cfg, DISCONNECTING, dev);
6949 		}
6950 #endif /* WPS_SYNC */
6951 		wl_cfg80211_wait_for_disconnection(cfg, dev);
6952 	} else {
6953 		/* Not in connecting or connected state. However since disconnect came
6954 		 * from upper layer, indicate connect fail to clear any state mismatch
6955 		 */
6956 		WL_INFORM_MEM(("act is false. report connect result fail.\n"));
6957 		CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
6958 				WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
6959 	}
6960 #ifdef CUSTOM_SET_CPUCORE
6961 	/* set default cpucore */
6962 	if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6963 		dhdp->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
6964 		if (!(dhdp->chan_isvht80))
6965 			dhd_set_cpucore(dhdp, FALSE);
6966 	}
6967 #endif /* CUSTOM_SET_CPUCORE */
6968 
6969 	cfg->rssi = 0;	/* reset backup of rssi */
6970 
6971 exit:
6972 	/* Clear IEs for disaasoc */
6973 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6974 		WL_ERR(("Find index failed\n"));
6975 		err = -EINVAL;
6976 		return err;
6977 	}
6978 	WL_ERR(("Clearing disconnect IEs \n"));
6979 	err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
6980 		ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, NULL, 0);
6981 
6982 	return err;
6983 }
6984 
6985 static s32
6986 #if defined(WL_CFG80211_P2P_DEV_IF)
wl_cfg80211_set_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,s32 mbm)6987 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
6988 	enum nl80211_tx_power_setting type, s32 mbm)
6989 #else
6990 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
6991 	enum nl80211_tx_power_setting type, s32 dbm)
6992 #endif /* WL_CFG80211_P2P_DEV_IF */
6993 {
6994 
6995 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6996 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6997 	s32 err = 0;
6998 #if defined(WL_CFG80211_P2P_DEV_IF)
6999 	s32 dbm = MBM_TO_DBM(mbm);
7000 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
7001 	defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
7002 	dbm = MBM_TO_DBM(dbm);
7003 #endif /* WL_CFG80211_P2P_DEV_IF */
7004 
7005 	RETURN_EIO_IF_NOT_UP(cfg);
7006 	switch (type) {
7007 	case NL80211_TX_POWER_AUTOMATIC:
7008 		break;
7009 	case NL80211_TX_POWER_LIMITED:
7010 		if (dbm < 0) {
7011 			WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
7012 			return -EINVAL;
7013 		}
7014 		break;
7015 	case NL80211_TX_POWER_FIXED:
7016 		if (dbm < 0) {
7017 			WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
7018 			return -EINVAL;
7019 		}
7020 		break;
7021 	}
7022 
7023 	err = wl_set_tx_power(ndev, type, dbm);
7024 	if (unlikely(err)) {
7025 		WL_ERR(("error (%d)\n", err));
7026 		return err;
7027 	}
7028 
7029 	cfg->conf->tx_power = dbm;
7030 
7031 	return err;
7032 }
7033 
7034 static s32
7035 #if defined(WL_CFG80211_P2P_DEV_IF)
wl_cfg80211_get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,s32 * dbm)7036 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
7037 	struct wireless_dev *wdev, s32 *dbm)
7038 #else
7039 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
7040 #endif /* WL_CFG80211_P2P_DEV_IF */
7041 {
7042 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7043 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7044 	s32 err = 0;
7045 
7046 	RETURN_EIO_IF_NOT_UP(cfg);
7047 	err = wl_get_tx_power(ndev, dbm);
7048 	if (unlikely(err))
7049 		WL_ERR(("error (%d)\n", err));
7050 
7051 	return err;
7052 }
7053 
7054 static s32
wl_cfg80211_config_default_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool unicast,bool multicast)7055 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
7056 	u8 key_idx, bool unicast, bool multicast)
7057 {
7058 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7059 	u32 index;
7060 	s32 wsec;
7061 	s32 err = 0;
7062 	s32 bssidx;
7063 
7064 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7065 		WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
7066 		return BCME_ERROR;
7067 	}
7068 
7069 	WL_DBG(("key index (%d)\n", key_idx));
7070 	RETURN_EIO_IF_NOT_UP(cfg);
7071 	err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7072 	if (unlikely(err)) {
7073 		WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7074 		return err;
7075 	}
7076 	if (wsec == WEP_ENABLED) {
7077 		/* Just select a new current key */
7078 		index = (u32) key_idx;
7079 		index = htod32(index);
7080 		err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index,
7081 			sizeof(index));
7082 		if (unlikely(err)) {
7083 			WL_ERR(("error (%d)\n", err));
7084 		}
7085 	}
7086 	return err;
7087 }
7088 
7089 static s32
wl_add_keyext(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,const u8 * mac_addr,struct key_params * params)7090 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
7091 	u8 key_idx, const u8 *mac_addr, struct key_params *params)
7092 {
7093 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7094 	struct wl_wsec_key key;
7095 	s32 err = 0;
7096 	s32 bssidx;
7097 	s32 mode = wl_get_mode_by_netdev(cfg, dev);
7098 
7099 	WL_MSG(dev->name, "key index (%d)\n", key_idx);
7100 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7101 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7102 		return BCME_ERROR;
7103 	}
7104 	bzero(&key, sizeof(key));
7105 	key.index = (u32) key_idx;
7106 
7107 	if (!ETHER_ISMULTI(mac_addr))
7108 		memcpy((char *)&key.ea, (const void *)mac_addr, ETHER_ADDR_LEN);
7109 	key.len = (u32) params->key_len;
7110 
7111 	/* check for key index change */
7112 	if (key.len == 0) {
7113 		/* key delete */
7114 		swap_key_from_BE(&key);
7115 		err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7116 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7117 		if (unlikely(err)) {
7118 			WL_ERR(("key delete error (%d)\n", err));
7119 			return err;
7120 		}
7121 	} else {
7122 		if (key.len > sizeof(key.data)) {
7123 			WL_ERR(("Invalid key length (%d)\n", key.len));
7124 			return -EINVAL;
7125 		}
7126 		WL_DBG(("Setting the key index %d\n", key.index));
7127 		memcpy(key.data, params->key, key.len);
7128 
7129 		if ((mode == WL_MODE_BSS) &&
7130 			(params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
7131 			u8 keybuf[8];
7132 			memcpy(keybuf, &key.data[24], sizeof(keybuf));
7133 			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
7134 			memcpy(&key.data[16], keybuf, sizeof(keybuf));
7135 		}
7136 
7137 		/* if IW_ENCODE_EXT_RX_SEQ_VALID set */
7138 		if (params->seq && params->seq_len == 6) {
7139 			/* rx iv */
7140 			const u8 *ivptr;
7141 			ivptr = (const u8 *) params->seq;
7142 			key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
7143 				(ivptr[3] << 8) | ivptr[2];
7144 			key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
7145 			key.iv_initialized = true;
7146 		}
7147 		key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7148 		if (key.algo == CRYPTO_ALGO_OFF) { //not found.
7149 			WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7150 			return -EINVAL;
7151 		}
7152 		swap_key_from_BE(&key);
7153 		/* need to guarantee EAPOL 4/4 send out before set key */
7154 		dhd_wait_pend8021x(dev);
7155 		err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7156 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7157 		if (unlikely(err)) {
7158 			WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7159 			return err;
7160 		}
7161 		WL_INFORM_MEM(("[%s] wsec key set\n", dev->name));
7162 	}
7163 	return err;
7164 }
7165 
7166 int
wl_cfg80211_enable_roam_offload(struct net_device * dev,int enable)7167 wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
7168 {
7169 	int err;
7170 	wl_eventmsg_buf_t ev_buf;
7171 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7172 
7173 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7174 		/* roam offload is only for the primary device */
7175 		return -1;
7176 	}
7177 
7178 	WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev->name, enable));
7179 	err = wldev_iovar_setint(dev, "roam_offload", enable);
7180 	if (err)
7181 		return err;
7182 
7183 	bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
7184 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
7185 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
7186 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
7187 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
7188 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
7189 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
7190 	err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
7191 	if (!err) {
7192 		cfg->roam_offload = enable;
7193 	}
7194 	return err;
7195 }
7196 
7197 struct wireless_dev *
wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 * cfg,const char * name)7198 wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 *cfg, const char *name)
7199 {
7200 	struct net_info *iter, *next;
7201 
7202 	if (name == NULL) {
7203 		WL_ERR(("Iface name is not provided\n"));
7204 		return NULL;
7205 	}
7206 
7207 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7208 	for_each_ndev(cfg, iter, next) {
7209 		GCC_DIAGNOSTIC_POP();
7210 		if (iter->ndev) {
7211 			if (strcmp(iter->ndev->name, name) == 0) {
7212 				return iter->ndev->ieee80211_ptr;
7213 			}
7214 		}
7215 	}
7216 
7217 	WL_DBG(("Iface %s not found\n", name));
7218 	return NULL;
7219 }
7220 
7221 #if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
7222 void
wl_cfg80211_block_arp(struct net_device * dev,int enable)7223 wl_cfg80211_block_arp(struct net_device *dev, int enable)
7224 {
7225 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7226 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7227 
7228 	WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev->name, enable));
7229 	if (!dhd_pkt_filter_enable) {
7230 		WL_DBG(("Packet filter isn't enabled\n"));
7231 		return;
7232 	}
7233 
7234 	/* Block/Unblock ARP frames only if STA is connected to
7235 	 * the upstream AP in case of STA+SoftAP Concurrenct mode
7236 	 */
7237 	if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
7238 		WL_DBG(("STA not connected to upstream AP\n"));
7239 		return;
7240 	}
7241 
7242 	if (enable) {
7243 		WL_DBG(("Enable ARP Filter\n"));
7244 		/* Add ARP filter */
7245 		dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
7246 
7247 		/* Enable ARP packet filter - blacklist */
7248 		dhd_master_mode = FALSE;
7249 		dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7250 			TRUE, dhd_master_mode);
7251 	} else {
7252 		WL_DBG(("Disable ARP Filter\n"));
7253 		/* Disable ARP packet filter */
7254 		dhd_master_mode = TRUE;
7255 		dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7256 			FALSE, dhd_master_mode);
7257 
7258 		/* Delete ARP filter */
7259 		dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
7260 	}
7261 }
7262 #endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
7263 
7264 static s32
wl_cfg80211_add_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr,struct key_params * params)7265 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
7266 	u8 key_idx, bool pairwise, const u8 *mac_addr,
7267 	struct key_params *params)
7268 {
7269 	struct wl_wsec_key key;
7270 	s32 val = 0;
7271 	s32 wsec = 0;
7272 	s32 err = 0;
7273 	u8 keybuf[8];
7274 	s32 bssidx = 0;
7275 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7276 	s32 mode = wl_get_mode_by_netdev(cfg, dev);
7277 #ifdef WL_GCMP
7278 	uint32 algos = 0, mask = 0;
7279 #endif /* WL_GCMP */
7280 #if defined(WLAN_CIPHER_SUITE_PMK)
7281 	int j;
7282 	wsec_pmk_t pmk;
7283 	char keystring[WSEC_MAX_PSK_LEN + 1];
7284 	char* charptr = keystring;
7285 	u16 len;
7286 	struct wl_security *sec;
7287 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7288 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7289 
7290 	WL_INFORM_MEM(("key index (%d) (0x%x)\n", key_idx, params->cipher));
7291 	RETURN_EIO_IF_NOT_UP(cfg);
7292 
7293 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7294 		WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
7295 		return BCME_ERROR;
7296 	}
7297 
7298 	if (mac_addr &&
7299 		((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
7300 		(params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
7301 			wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
7302 			goto exit;
7303 	}
7304 
7305 	BCM_REFERENCE(dhdp);
7306 	DHD_STATLOG_CTRL(dhdp, ST(INSTALL_KEY), dhd_net2idx(dhdp->info, dev), 0);
7307 
7308 	bzero(&key, sizeof(key));
7309 	/* Clear any buffered wep key */
7310 	bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
7311 
7312 	key.len = (u32) params->key_len;
7313 	key.index = (u32) key_idx;
7314 
7315 	if (unlikely(key.len > sizeof(key.data))) {
7316 		WL_ERR(("Too long key length (%u)\n", key.len));
7317 		return -EINVAL;
7318 	}
7319 	memcpy(key.data, params->key, key.len);
7320 
7321 	key.flags = WL_PRIMARY_KEY;
7322 
7323 	key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7324 	val = wl_rsn_cipher_wsec_algo_lookup(params->cipher);
7325 	if (val == WSEC_NONE) {
7326 		WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7327 #if defined(WLAN_CIPHER_SUITE_PMK)
7328 	/* WLAN_CIPHER_SUITE_PMK is not NL80211 standard ,but BRCM proprietary cipher suite.
7329 	 * so it doesn't have right algo type too. Just for now, bypass this check for
7330 	 * backward compatibility.
7331 	 * TODO: deprecate this proprietary way and replace to nl80211 set_pmk API.
7332 	 */
7333 		if (params->cipher != WLAN_CIPHER_SUITE_PMK)
7334 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7335 		return -EINVAL;
7336 	}
7337 	switch (params->cipher) {
7338 	case WLAN_CIPHER_SUITE_TKIP:
7339 		/* wpa_supplicant switches the third and fourth quarters of the TKIP key */
7340 		if (mode == WL_MODE_BSS) {
7341 			bcopy(&key.data[24], keybuf, sizeof(keybuf));
7342 			bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
7343 			bcopy(keybuf, &key.data[16], sizeof(keybuf));
7344 		}
7345 		WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7346 		break;
7347 #if defined(WLAN_CIPHER_SUITE_PMK)
7348 	case WLAN_CIPHER_SUITE_PMK:
7349 		sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7350 
7351 		WL_MEM(("set_pmk: wpa_auth:%x akm:%x\n", sec->wpa_auth, params->cipher));
7352 		/* Avoid pmk set for SAE and OWE for external supplicant case. */
7353 		if (IS_AKM_SAE(sec->wpa_auth) || IS_AKM_OWE(sec->wpa_auth)) {
7354 			WL_INFORM_MEM(("skip pmk set for akm:%x\n", sec->wpa_auth));
7355 			break;
7356 		}
7357 
7358 		if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
7359 			(sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
7360 			err = wldev_iovar_setbuf(dev, "okc_info_pmk", (const void *)params->key,
7361 				WSEC_MAX_PSK_LEN / 2, keystring, sizeof(keystring), NULL);
7362 			if (err) {
7363 				/* could fail in case that 'okc' is not supported */
7364 				WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err));
7365 			}
7366 		}
7367 		/* copy the raw hex key to the appropriate format */
7368 		for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) {
7369 			charptr += snprintf(charptr, sizeof(keystring), "%02x", params->key[j]);
7370 		}
7371 		len = (u16)strlen(keystring);
7372 		pmk.key_len = htod16(len);
7373 		bcopy(keystring, pmk.key, len);
7374 		pmk.flags = htod16(WSEC_PASSPHRASE);
7375 
7376 		err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
7377 		if (err) {
7378 			return err;
7379 		}
7380 		/* Clear key length to delete key */
7381 		key.len = 0;
7382 		break;
7383 #endif /* WLAN_CIPHER_SUITE_PMK */
7384 #ifdef WL_GCMP
7385 	case WLAN_CIPHER_SUITE_GCMP:
7386 	case WLAN_CIPHER_SUITE_GCMP_256:
7387 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
7388 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
7389 		algos = KEY_ALGO_MASK(key.algo);
7390 		mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
7391 		break;
7392 #endif /* WL_GCMP */
7393 	default: /* No post processing required */
7394 		WL_DBG(("no post processing required (0x%x)\n", params->cipher));
7395 		break;
7396 	}
7397 
7398 	/* Set the new key/index */
7399 	if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
7400 		WL_ERR(("IBSS KEY setted\n"));
7401 		wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
7402 	}
7403 	swap_key_from_BE(&key);
7404 	if ((params->cipher == WLAN_CIPHER_SUITE_WEP40) ||
7405 		(params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
7406 		/*
7407 		 * For AP role, since we are doing a wl down before bringing up AP,
7408 		 * the plumbed keys will be lost. So for AP once we bring up AP, we
7409 		 * need to plumb keys again. So buffer the keys for future use. This
7410 		 * is more like a WAR. If firmware later has the capability to do
7411 		 * interface upgrade without doing a "wl down" and "wl apsta 0", then
7412 		 * this will not be required.
7413 		 */
7414 		WL_DBG(("Buffering WEP Keys \n"));
7415 		memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key));
7416 	}
7417 	err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7418 		WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7419 	if (unlikely(err)) {
7420 		WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7421 		return err;
7422 	}
7423 
7424 exit:
7425 	err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7426 	if (unlikely(err)) {
7427 		WL_ERR(("get wsec error (%d)\n", err));
7428 		return err;
7429 	}
7430 
7431 	wsec |= val;
7432 	err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
7433 	if (unlikely(err)) {
7434 		WL_ERR(("set wsec error (%d)\n", err));
7435 		return err;
7436 	}
7437 #ifdef WL_GCMP
7438 	wl_set_wsec_info_algos(dev, algos, mask);
7439 #endif /* WL_GCMP */
7440 	wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY,
7441 		WL_EXT_STATUS_ADD_KEY, NULL);
7442 	return err;
7443 }
7444 
7445 static s32
wl_cfg80211_del_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr)7446 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
7447 	u8 key_idx, bool pairwise, const u8 *mac_addr)
7448 {
7449 	struct wl_wsec_key key;
7450 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7451 	s32 err = 0;
7452 	s32 bssidx;
7453 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7454 
7455 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7456 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7457 		return BCME_ERROR;
7458 	}
7459 	WL_DBG(("Enter\n"));
7460 
7461 #ifndef MFP
7462 	if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
7463 		return -EINVAL;
7464 #endif // endif
7465 
7466 	RETURN_EIO_IF_NOT_UP(cfg);
7467 	BCM_REFERENCE(dhdp);
7468 	DHD_STATLOG_CTRL(dhdp, ST(DELETE_KEY), dhd_net2idx(dhdp->info, dev), 0);
7469 	bzero(&key, sizeof(key));
7470 
7471 	key.flags = WL_PRIMARY_KEY;
7472 	key.algo = CRYPTO_ALGO_OFF;
7473 	key.index = (u32) key_idx;
7474 
7475 	WL_DBG(("key index (%d)\n", key_idx));
7476 	/* Set the new key/index */
7477 	swap_key_from_BE(&key);
7478 	err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7479 		WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7480 	if (unlikely(err)) {
7481 		if (err == -EINVAL) {
7482 			if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
7483 				/* we ignore this key index in this case */
7484 				WL_DBG(("invalid key index (%d)\n", key_idx));
7485 			}
7486 		} else {
7487 			WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7488 		}
7489 		return err;
7490 	}
7491 	return err;
7492 }
7493 
7494 /* NOTE : this function cannot work as is and is never called */
7495 static s32
wl_cfg80211_get_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr,void * cookie,void (* callback)(void * cookie,struct key_params * params))7496 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
7497 	u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
7498 	void (*callback) (void *cookie, struct key_params * params))
7499 {
7500 	struct key_params params;
7501 	struct wl_wsec_key key;
7502 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7503 	struct wl_security *sec;
7504 	s32 wsec;
7505 	s32 err = 0;
7506 	s32 bssidx;
7507 
7508 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7509 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7510 		return BCME_ERROR;
7511 	}
7512 	WL_DBG(("key index (%d)\n", key_idx));
7513 	RETURN_EIO_IF_NOT_UP(cfg);
7514 	bzero(&key, sizeof(key));
7515 	key.index = key_idx;
7516 	swap_key_to_BE(&key);
7517 	bzero(&params, sizeof(params));
7518 	params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
7519 	params.key = key.data;
7520 
7521 	err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7522 	if (unlikely(err)) {
7523 		WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7524 		return err;
7525 	}
7526 	switch (WSEC_ENABLED(wsec)) {
7527 		case WEP_ENABLED:
7528 			sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7529 			if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
7530 				params.cipher = WLAN_CIPHER_SUITE_WEP40;
7531 				WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7532 			} else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
7533 				params.cipher = WLAN_CIPHER_SUITE_WEP104;
7534 				WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7535 			}
7536 			break;
7537 		case TKIP_ENABLED:
7538 			params.cipher = WLAN_CIPHER_SUITE_TKIP;
7539 			WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7540 			break;
7541 		case AES_ENABLED:
7542 			params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7543 			WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7544 			break;
7545 #ifdef BCMWAPI_WPI
7546 		case SMS4_ENABLED:
7547 			params.cipher = WLAN_CIPHER_SUITE_SMS4;
7548 			WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7549 			break;
7550 #endif // endif
7551 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
7552 		/* to connect to mixed mode AP */
7553 		case (AES_ENABLED | TKIP_ENABLED): /* TKIP CCMP */
7554 			params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7555 			WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7556 			break;
7557 #endif // endif
7558 		default:
7559 			WL_ERR(("Invalid algo (0x%x)\n", wsec));
7560 			return -EINVAL;
7561 	}
7562 
7563 	callback(cookie, &params);
7564 	return err;
7565 }
7566 
7567 static s32
wl_cfg80211_config_default_mgmt_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx)7568 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
7569 	struct net_device *dev, u8 key_idx)
7570 {
7571 #ifdef MFP
7572 	return 0;
7573 #else
7574 	WL_INFORM_MEM(("Not supported\n"));
7575 	return -EOPNOTSUPP;
7576 #endif /* MFP */
7577 }
7578 
7579 static bool
wl_check_assoc_state(struct bcm_cfg80211 * cfg,struct net_device * dev)7580 wl_check_assoc_state(struct bcm_cfg80211 *cfg, struct net_device *dev)
7581 {
7582 	wl_assoc_info_t asinfo;
7583 	uint32 state = 0;
7584 	int err;
7585 
7586 	err = wldev_iovar_getbuf_bsscfg(dev, "assoc_info",
7587 		NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
7588 	if (unlikely(err)) {
7589 		WL_ERR(("failed to get assoc_info : err=%d\n", err));
7590 		return FALSE;
7591 	} else {
7592 		memcpy(&asinfo, cfg->ioctl_buf, sizeof(wl_assoc_info_t));
7593 		state = dtoh32(asinfo.state);
7594 		WL_DBG(("assoc state=%d\n", state));
7595 	}
7596 
7597 	return (state > 0)? TRUE:FALSE;
7598 }
7599 
7600 static s32
wl_cfg80211_get_rssi(struct net_device * dev,struct bcm_cfg80211 * cfg,s32 * rssi)7601 wl_cfg80211_get_rssi(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 *rssi)
7602 {
7603 	s32 err = BCME_OK;
7604 	scb_val_t scb_val;
7605 #ifdef SUPPORT_RSSI_SUM_REPORT
7606 	wl_rssi_ant_mimo_t rssi_ant_mimo;
7607 #endif /* SUPPORT_RSSI_SUM_REPORT */
7608 
7609 	if (dev == NULL || cfg == NULL) {
7610 		return BCME_ERROR;
7611 	}
7612 
7613 	/* initialize rssi */
7614 	*rssi = 0;
7615 
7616 #ifdef SUPPORT_RSSI_SUM_REPORT
7617 	/* Query RSSI sum across antennas */
7618 	bzero(&rssi_ant_mimo, sizeof(rssi_ant_mimo));
7619 	err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
7620 	if (err) {
7621 		WL_ERR(("Could not get rssi sum (%d)\n", err));
7622 		/* set rssi to zero and do not return error,
7623 		* because iovar phy_rssi_ant could return BCME_UNSUPPORTED
7624 		* when bssid was null during roaming
7625 		*/
7626 		err = BCME_OK;
7627 	} else {
7628 		cfg->rssi_sum_report = TRUE;
7629 		if ((*rssi = rssi_ant_mimo.rssi_sum) >= 0) {
7630 			*rssi = 0;
7631 		}
7632 	}
7633 #endif /* SUPPORT_RSSI_SUM_REPORT */
7634 
7635 	/* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore */
7636 	if (cfg->rssi_sum_report == FALSE) {
7637 		bzero(&scb_val, sizeof(scb_val));
7638 		scb_val.val = 0;
7639 		err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val,
7640 			sizeof(scb_val_t));
7641 		if (err) {
7642 			WL_ERR(("Could not get rssi (%d)\n", err));
7643 			return err;
7644 		}
7645 #if defined(RSSIOFFSET)
7646 		*rssi = wl_update_rssi_offset(dev, dtoh32(scb_val.val));
7647 #else
7648 		*rssi = dtoh32(scb_val.val);
7649 #endif
7650 	}
7651 
7652 	if (*rssi >= 0) {
7653 		/* check assoc status including roaming */
7654 		DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub));
7655 		if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_check_assoc_state(cfg, dev)) {
7656 			*rssi = cfg->rssi;	   /* use previous RSSI */
7657 			WL_DBG(("use previous RSSI %d dBm\n", cfg->rssi));
7658 		} else {
7659 			*rssi = 0;
7660 		}
7661 		DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
7662 	} else {
7663 		/* backup the current rssi */
7664 		cfg->rssi = *rssi;
7665 	}
7666 
7667 	return err;
7668 }
7669 
7670 static int
wl_cfg80211_ifstats_counters_cb(void * ctx,const uint8 * data,uint16 type,uint16 len)7671 wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data, uint16 type, uint16 len)
7672 {
7673 	switch (type) {
7674 	case WL_IFSTATS_XTLV_IF_INDEX:
7675 		WL_DBG(("Stats received on interface index: %d\n", *data));
7676 		break;
7677 	case WL_IFSTATS_XTLV_GENERIC: {
7678 		if (len > sizeof(wl_if_stats_t)) {
7679 			WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n",
7680 				type, len, (int)sizeof(wl_if_stats_t)));
7681 		}
7682 		memcpy(ctx, data, sizeof(wl_if_stats_t));
7683 		break;
7684 	}
7685 	default:
7686 		WL_DBG(("Unsupported counter type 0x%x\n", type));
7687 		break;
7688 	}
7689 
7690 	return BCME_OK;
7691 }
7692 
7693 /* Parameters to if_counters iovar need to be converted to XTLV format
7694  * before sending to FW. The length of the top level XTLV container
7695  * containing parameters should not exceed 228 bytes
7696  */
7697 #define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX	228
7698 
7699 int
wl_cfg80211_ifstats_counters(struct net_device * dev,wl_if_stats_t * if_stats)7700 wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats)
7701 {
7702 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7703 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7704 	uint8 *pbuf = NULL;
7705 	bcm_xtlvbuf_t xtlvbuf, local_xtlvbuf;
7706 	bcm_xtlv_t *xtlv;
7707 	uint16 expected_resp_len;
7708 	wl_stats_report_t *request = NULL, *response = NULL;
7709 	int bsscfg_idx;
7710 	int ret = BCME_OK;
7711 
7712 	pbuf = (uint8 *)MALLOCZ(dhdp->osh, WLC_IOCTL_MEDLEN);
7713 	if (!pbuf) {
7714 		WL_ERR(("Failed to allocate local pbuf\n"));
7715 		return BCME_NOMEM;
7716 	}
7717 
7718 	/* top level container length cannot exceed 228 bytes.
7719 	 * This is because the output buffer is 1535 bytes long.
7720 	 * Allow 1300 bytes for reporting stats coming in XTLV format
7721 	 */
7722 	request = (wl_stats_report_t *)
7723 		MALLOCZ(dhdp->osh, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7724 	if (!request) {
7725 		WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
7726 			IF_COUNTERS_PARAM_CONTAINER_LEN_MAX));
7727 		ret = BCME_NOMEM;
7728 		goto fail;
7729 	}
7730 
7731 	request->version = WL_STATS_REPORT_REQUEST_VERSION_V2;
7732 
7733 	/* Top level container... we will create it ourselves */
7734 	/* Leave space for report version, length, and top level XTLV
7735 	 * WL_IFSTATS_XTLV_IF.
7736 	 */
7737 	ret = bcm_xtlv_buf_init(&local_xtlvbuf,
7738 		(uint8*)(request->data) + BCM_XTLV_HDR_SIZE,
7739 		IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7740 		offsetof(wl_stats_report_t, data) - BCM_XTLV_HDR_SIZE,
7741 		BCM_XTLV_OPTION_ALIGN32);
7742 
7743 	if (ret) {
7744 		goto fail;
7745 	}
7746 
7747 	/* Populate requests using this the local_xtlvbuf context. The xtlvbuf
7748 	 * is used to fill the container containing the XTLVs populated using
7749 	 * local_xtlvbuf.
7750 	 */
7751 	ret = bcm_xtlv_buf_init(&xtlvbuf,
7752 		(uint8*)(request->data),
7753 		IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7754 		offsetof(wl_stats_report_t, data),
7755 		BCM_XTLV_OPTION_ALIGN32);
7756 
7757 	if (ret) {
7758 		goto fail;
7759 	}
7760 
7761 	/* Request generic stats */
7762 	ret = bcm_xtlv_put_data(&local_xtlvbuf,
7763 		WL_IFSTATS_XTLV_GENERIC, NULL, 0);
7764 	if (ret) {
7765 		goto fail;
7766 	}
7767 
7768 	/* Complete the outer container with type and length
7769 	 * only.
7770 	 */
7771 	ret = bcm_xtlv_put_data(&xtlvbuf,
7772 		WL_IFSTATS_XTLV_IF,
7773 		NULL, bcm_xtlv_buf_len(&local_xtlvbuf));
7774 
7775 	if (ret) {
7776 		goto fail;
7777 	}
7778 
7779 	request->length = bcm_xtlv_buf_len(&xtlvbuf) +
7780 		offsetof(wl_stats_report_t, data);
7781 	bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
7782 
7783 	/* send the command over to the device and get teh output */
7784 	ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request,
7785 		request->length, pbuf, WLC_IOCTL_MEDLEN, bsscfg_idx,
7786 		&cfg->ioctl_buf_sync);
7787 	if (ret < 0) {
7788 		WL_ERR(("if_counters not supported ret=%d\n", ret));
7789 		goto fail;
7790 	}
7791 
7792 	/* Reuse request to process response */
7793 	response = (wl_stats_report_t *)pbuf;
7794 
7795 	/* version check */
7796 	if (response->version != WL_STATS_REPORT_REQUEST_VERSION_V2) {
7797 		ret = BCME_VERSION;
7798 		goto fail;
7799 	}
7800 
7801 	xtlv = (bcm_xtlv_t *)(response->data);
7802 
7803 	expected_resp_len =
7804 		(BCM_XTLV_LEN(xtlv) + OFFSETOF(wl_stats_report_t, data));
7805 
7806 	/* Check if the received length is as expected */
7807 	if ((response->length > WLC_IOCTL_MEDLEN) ||
7808 		(response->length < expected_resp_len)) {
7809 		ret = BCME_ERROR;
7810 		WL_ERR(("Illegal response length received. Got: %d"
7811 			" Expected: %d. Expected len must be <= %u\n",
7812 			response->length, expected_resp_len, WLC_IOCTL_MEDLEN));
7813 		goto fail;
7814 	}
7815 
7816 	/* check the type. The return data will be in
7817 	 * WL_IFSTATS_XTLV_IF container. So check if that container is
7818 	 * present
7819 	 */
7820 	if (BCM_XTLV_ID(xtlv) != WL_IFSTATS_XTLV_IF) {
7821 		ret = BCME_ERROR;
7822 		WL_ERR(("unexpected type received: %d Expected: %d\n",
7823 			BCM_XTLV_ID(xtlv), WL_IFSTATS_XTLV_IF));
7824 		goto fail;
7825 	}
7826 
7827 	/* Process XTLVs within WL_IFSTATS_XTLV_IF container */
7828 	ret = bcm_unpack_xtlv_buf(if_stats,
7829 		(uint8*)response->data + BCM_XTLV_HDR_SIZE,
7830 		BCM_XTLV_LEN(xtlv), /* total length of all TLVs in container */
7831 		BCM_XTLV_OPTION_ALIGN32, wl_cfg80211_ifstats_counters_cb);
7832 	if (ret) {
7833 		WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret));
7834 	}
7835 
7836 fail:
7837 	if (pbuf) {
7838 		MFREE(dhdp->osh, pbuf, WLC_IOCTL_MEDLEN);
7839 	}
7840 
7841 	if (request) {
7842 		MFREE(dhdp->osh, request, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7843 	}
7844 	return ret;
7845 }
7846 #undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
7847 
7848 static s32
7849 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
wl_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_info * sinfo)7850 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7851         const u8 *mac, struct station_info *sinfo)
7852 #else
7853 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7854         u8 *mac, struct station_info *sinfo)
7855 #endif // endif
7856 {
7857 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7858 	s32 rssi = 0;
7859 	s32 rate = 0;
7860 	s32 err = 0;
7861 	u16 wl_iftype = 0;
7862 	u16 wl_mode = 0;
7863 	get_pktcnt_t pktcnt;
7864 	wl_if_stats_t *if_stats = NULL;
7865 	sta_info_v4_t *sta = NULL;
7866 	u8 *curmacp = NULL;
7867 	s8 eabuf[ETHER_ADDR_STR_LEN];
7868 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
7869 	bool fw_assoc_state = FALSE;
7870 	u32 dhd_assoc_state = 0;
7871 	void *buf;
7872 
7873 	RETURN_EIO_IF_NOT_UP(cfg);
7874 
7875 	if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype, &wl_iftype, &wl_mode) < 0) {
7876 		return -EINVAL;
7877 	}
7878 
7879 	buf = MALLOC(cfg->osh, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
7880 	if (buf == NULL) {
7881 		WL_ERR(("wl_cfg80211_get_station: MALLOC failed\n"));
7882 		goto error;
7883 	}
7884 
7885 	switch (wl_iftype) {
7886 		case WL_IF_TYPE_STA:
7887 		case WL_IF_TYPE_IBSS:
7888 			if (cfg->roam_offload) {
7889 				struct ether_addr bssid;
7890 				bzero(&bssid, sizeof(bssid));
7891 				err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
7892 				if (err) {
7893 					WL_ERR(("Failed to get current BSSID\n"));
7894 				} else {
7895 					if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
7896 						/* roaming is detected */
7897 						err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
7898 						if (err)
7899 							WL_ERR(("Failed to handle the delayed"
7900 								" roam, err=%d", err));
7901 						mac = (u8 *)bssid.octet;
7902 					}
7903 				}
7904 			}
7905 			dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
7906 			DHD_OS_WAKE_LOCK(dhd);
7907 			fw_assoc_state = dhd_is_associated(dhd, 0, &err);
7908 			if (dhd_assoc_state && !fw_assoc_state) {
7909 				/* check roam (join) status */
7910 				if (wl_check_assoc_state(cfg, dev)) {
7911 					fw_assoc_state = TRUE;
7912 					WL_DBG(("roam status\n"));
7913 				}
7914 			}
7915 			DHD_OS_WAKE_UNLOCK(dhd);
7916 			if (!dhd_assoc_state || !fw_assoc_state) {
7917 				WL_ERR(("NOT assoc\n"));
7918 				if (err == -ENODATA)
7919 					goto error;
7920 				if (!dhd_assoc_state) {
7921 					WL_TRACE_HW4(("drv state is not connected \n"));
7922 				}
7923 				if (!fw_assoc_state) {
7924 					WL_TRACE_HW4(("fw state is not associated \n"));
7925 				}
7926 				/* Disconnect due to fw is not associated for
7927 				 * FW_ASSOC_WATCHDOG_TIME ms.
7928 				 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
7929 				 * means that BSSID is null.
7930 				 */
7931 				if (dhd_assoc_state && !fw_assoc_state && !err) {
7932 					if (!fw_assoc_watchdog_started) {
7933 						fw_assoc_watchdog_ms = OSL_SYSUPTIME();
7934 						fw_assoc_watchdog_started = TRUE;
7935 						WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
7936 					} else if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
7937 							FW_ASSOC_WATCHDOG_TIME) {
7938 						fw_assoc_watchdog_started = FALSE;
7939 						err = -ENODEV;
7940 						WL_TRACE_HW4(("fw is not associated for %d ms \n",
7941 							(OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
7942 						goto get_station_err;
7943 					}
7944 				}
7945 				err = -ENODEV;
7946 				goto error;
7947 			}
7948 			if (dhd_is_associated(dhd, 0, NULL)) {
7949 				fw_assoc_watchdog_started = FALSE;
7950 			}
7951 			curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
7952 			if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
7953 				WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
7954 					MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
7955 			}
7956 			/* go through to get another information */
7957 		case WL_IF_TYPE_P2P_GC:
7958 		case WL_IF_TYPE_P2P_DISC:
7959 			if ((err = wl_cfg80211_get_rssi(dev, cfg, &rssi)) != BCME_OK) {
7960 				goto get_station_err;
7961 			}
7962 #if defined(RSSIAVG)
7963 			err = wl_update_connected_rssi_cache(dev, &cfg->g_connected_rssi_cache_ctrl, &rssi);
7964 			if (err) {
7965 				WL_ERR(("Could not get rssi (%d)\n", err));
7966 				goto get_station_err;
7967 			}
7968 			wl_delete_dirty_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
7969 			wl_reset_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
7970 #endif
7971 #if defined(RSSIOFFSET)
7972 			rssi = wl_update_rssi_offset(dev, rssi);
7973 #endif
7974 #if !defined(RSSIAVG) && !defined(RSSIOFFSET)
7975 			// terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
7976 			rssi = MIN(rssi, RSSI_MAXVAL);
7977 #endif
7978 			sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
7979 			sinfo->signal = rssi;
7980 			WL_DBG(("RSSI %d dBm\n", rssi));
7981 			/* go through to get another information */
7982 		case WL_IF_TYPE_P2P_GO:
7983 			/* Report the current tx rate */
7984 			rate = 0;
7985 			err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
7986 			if (err) {
7987 				WL_ERR(("Could not get rate (%d)\n", err));
7988 			} else {
7989 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7990 				int rxpktglom;
7991 #endif // endif
7992 				rate = dtoh32(rate);
7993 				sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
7994 				sinfo->txrate.legacy = rate * 5;
7995 				WL_DBG(("Rate %d Mbps\n", (rate / 2)));
7996 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7997 				rxpktglom = ((rate/2) > 150) ? 20 : 10;
7998 
7999 				if (maxrxpktglom != rxpktglom) {
8000 					maxrxpktglom = rxpktglom;
8001 					WL_DBG(("Rate %d Mbps, update bus:"
8002 						"maxtxpktglom=%d\n", (rate/2), maxrxpktglom));
8003 					err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
8004 							(char*)&maxrxpktglom, 4, cfg->ioctl_buf,
8005 							WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8006 					if (err < 0) {
8007 						WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
8008 					}
8009 				}
8010 #endif // endif
8011 			}
8012 			if_stats = (wl_if_stats_t *)buf;
8013 			bzero(if_stats, sizeof(*if_stats));
8014 			if (FW_SUPPORTED(dhd, ifst)) {
8015 				err = wl_cfg80211_ifstats_counters(dev, if_stats);
8016 			} else
8017 			{
8018 				err = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
8019 						(char *)if_stats, sizeof(*if_stats), NULL);
8020 			}
8021 
8022 			if (err) {
8023 //				WL_ERR(("if_counters not supported ret=%d\n", err));
8024 				bzero(&pktcnt, sizeof(pktcnt));
8025 				err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt,
8026 						sizeof(pktcnt));
8027 				if (!err) {
8028 					sinfo->rx_packets = pktcnt.rx_good_pkt;
8029 					sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
8030 					sinfo->tx_packets = pktcnt.tx_good_pkt;
8031 					sinfo->tx_failed  = pktcnt.tx_bad_pkt;
8032 				}
8033 			} else {
8034 				sinfo->rx_packets = (uint32)dtoh64(if_stats->rxframe);
8035 				sinfo->rx_dropped_misc = 0;
8036 				sinfo->tx_packets = (uint32)dtoh64(if_stats->txfrmsnt);
8037 				sinfo->tx_failed = (uint32)dtoh64(if_stats->txnobuf) +
8038 					(uint32)dtoh64(if_stats->txrunt) +
8039 					(uint32)dtoh64(if_stats->txfail);
8040 			}
8041 
8042 			sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
8043 					STA_INFO_BIT(INFO_RX_DROP_MISC) |
8044 					STA_INFO_BIT(INFO_TX_PACKETS) |
8045 					STA_INFO_BIT(INFO_TX_FAILED));
8046 get_station_err:
8047 			if (err && (err != -ENODATA)) {
8048 				/* Disconnect due to zero BSSID or error to get RSSI */
8049 				scb_val_t scbval;
8050 				DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
8051 					dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
8052 				scbval.val = htod32(DOT11_RC_DISASSOC_LEAVING);
8053 				err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
8054 						sizeof(scb_val_t));
8055 				if (unlikely(err)) {
8056 					WL_ERR(("disassoc error (%d)\n", err));
8057 				}
8058 
8059 				WL_ERR(("force cfg80211_disconnected: %d\n", err));
8060 				wl_clr_drv_status(cfg, CONNECTED, dev);
8061 				DHD_STATLOG_CTRL(dhd, ST(DISASSOC_DONE),
8062 					dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
8063 				CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
8064 				wl_link_down(cfg);
8065 			}
8066 			break;
8067 		case WL_IF_TYPE_AP:
8068 			err = wldev_iovar_getbuf(dev, "sta_info", (const   void*)mac,
8069 					ETHER_ADDR_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8070 			if (err < 0) {
8071 				WL_ERR(("GET STA INFO failed, %d\n", err));
8072 				goto error;
8073 			}
8074 			sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
8075 			sta = (sta_info_v4_t *)buf;
8076 			if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
8077 				WL_ERR(("GET STA INFO version mismatch, %d\n", err));
8078 				return BCME_VERSION;
8079 			}
8080 			sta->len = dtoh16(sta->len);
8081 			sta->cap = dtoh16(sta->cap);
8082 			sta->flags = dtoh32(sta->flags);
8083 			sta->idle = dtoh32(sta->idle);
8084 			sta->in = dtoh32(sta->in);
8085 			sinfo->inactive_time = sta->idle * 1000;
8086 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
8087 			if (sta->flags & WL_STA_ASSOC) {
8088 				sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
8089 				sinfo->connected_time = sta->in;
8090 			}
8091 #endif // endif
8092 			WL_INFORM_MEM(("STA %s, flags 0x%x, idle time %ds, connected time %ds\n",
8093 				bcm_ether_ntoa((const struct ether_addr *)mac, eabuf),
8094 				sta->flags, sta->idle, sta->in));
8095 			break;
8096 		default :
8097 			WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
8098 	}
8099 error:
8100 	if (buf) {
8101 		MFREE(cfg->osh, buf, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
8102 	}
8103 
8104 	return err;
8105 }
8106 
8107 static s32
wl_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool enabled,s32 timeout)8108 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
8109 	bool enabled, s32 timeout)
8110 {
8111 	s32 pm;
8112 	s32 err = 0;
8113 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8114 	struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
8115 	s32 mode;
8116 #ifdef RTT_SUPPORT
8117 	rtt_status_info_t *rtt_status;
8118 #endif /* RTT_SUPPORT */
8119 	dhd_pub_t *dhd = cfg->pub;
8120 	RETURN_EIO_IF_NOT_UP(cfg);
8121 
8122 	WL_DBG(("Enter %s enable=%d, timeout=%u\n", dev->name, enabled, timeout));
8123 	mode = wl_get_mode_by_netdev(cfg, dev);
8124 	if (cfg->p2p_net == dev || _net_info == NULL ||
8125 			!wl_get_drv_status(cfg, CONNECTED, dev) ||
8126 			((mode != WL_MODE_BSS) &&
8127 			(mode != WL_MODE_IBSS))) {
8128 		return err;
8129 	}
8130 
8131 	/* Enlarge pm_enable_work */
8132 	wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
8133 
8134 	pm = enabled ? PM_FAST : PM_OFF;
8135 	if (_net_info->pm_block) {
8136 		WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
8137 			dev->name, _net_info->pm_block));
8138 		pm = PM_OFF;
8139 	}
8140 	if (enabled && dhd_conf_get_pm(dhd) >= 0)
8141 		pm = dhd_conf_get_pm(dhd);
8142 	pm = htod32(pm);
8143 	WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
8144 #ifdef RTT_SUPPORT
8145 	rtt_status = GET_RTTSTATE(dhd);
8146 	if (rtt_status->status != RTT_ENABLED) {
8147 #endif /* RTT_SUPPORT */
8148 		err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
8149 		if (unlikely(err)) {
8150 			if (err == -ENODEV)
8151 				WL_DBG(("net_device is not ready yet\n"));
8152 			else
8153 				WL_ERR(("error (%d)\n", err));
8154 			return err;
8155 		}
8156 #ifdef RTT_SUPPORT
8157 	}
8158 #endif /* RTT_SUPPORT */
8159 	wl_cfg80211_update_power_mode(dev);
8160 	return err;
8161 }
8162 
wl_cfg80211_update_power_mode(struct net_device * dev)8163 void wl_cfg80211_update_power_mode(struct net_device *dev)
8164 {
8165 	int err, pm = -1;
8166 
8167 	err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
8168 	if (err)
8169 		WL_ERR(("error (%d)\n", err));
8170 	else if (pm != -1 && dev->ieee80211_ptr)
8171 		dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
8172 }
8173 
wl_find_msb(u16 bit16)8174 static __used u32 wl_find_msb(u16 bit16)
8175 {
8176 	u32 ret = 0;
8177 
8178 	if (bit16 & 0xff00) {
8179 		ret += 8;
8180 		bit16 >>= 8;
8181 	}
8182 
8183 	if (bit16 & 0xf0) {
8184 		ret += 4;
8185 		bit16 >>= 4;
8186 	}
8187 
8188 	if (bit16 & 0xc) {
8189 		ret += 2;
8190 		bit16 >>= 2;
8191 	}
8192 
8193 	if (bit16 & 2)
8194 		ret += bit16 & 2;
8195 	else if (bit16)
8196 		ret += bit16;
8197 
8198 	return ret;
8199 }
8200 
wl_cfg80211_resume(struct wiphy * wiphy)8201 static s32 wl_cfg80211_resume(struct wiphy *wiphy)
8202 {
8203 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8204 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8205 	s32 err = BCME_OK;
8206 
8207 	if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8208 		WL_INFORM_MEM(("device is not ready\n"));
8209 		return err;
8210 	}
8211 
8212 	return err;
8213 }
8214 
8215 static s32
8216 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
wl_cfg80211_suspend(struct wiphy * wiphy,struct cfg80211_wowlan * wow)8217 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
8218 #else
8219 wl_cfg80211_suspend(struct wiphy *wiphy)
8220 #endif // endif
8221 {
8222 	s32 err = BCME_OK;
8223 #ifdef DHD_CLEAR_ON_SUSPEND
8224 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8225 	struct net_info *iter, *next;
8226 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8227 	unsigned long flags;
8228 
8229 	if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8230 		WL_INFORM_MEM(("device is not ready : status (%d)\n",
8231 			(int)cfg->status));
8232 		return err;
8233 	}
8234 	for_each_ndev(cfg, iter, next) {
8235 		/* p2p discovery iface doesn't have a ndev associated with it (for kernel > 3.8) */
8236 		if (iter->ndev)
8237 			wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8238 		}
8239 	WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
8240 	if (cfg->scan_request) {
8241 		wl_notify_scan_done(cfg, true);
8242 		cfg->scan_request = NULL;
8243 	}
8244 	for_each_ndev(cfg, iter, next) {
8245 		if (iter->ndev) {
8246 			wl_clr_drv_status(cfg, SCANNING, iter->ndev);
8247 			wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8248 		}
8249 	}
8250 	WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
8251 	for_each_ndev(cfg, iter, next) {
8252 		if (iter->ndev) {
8253 			if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
8254 				wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false);
8255 			}
8256 		}
8257 	}
8258 #endif /* DHD_CLEAR_ON_SUSPEND */
8259 
8260 	return err;
8261 }
8262 
8263 static s32
wl_update_pmklist(struct net_device * dev,struct wl_pmk_list * pmk_list,s32 err)8264 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
8265 	s32 err)
8266 {
8267 	int i, j;
8268 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8269 	struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
8270 	int npmkids = cfg->pmk_list->pmkids.count;
8271 
8272 	ASSERT(cfg->pmk_list->pmkids.length >= (sizeof(u16)*2));
8273 	if (!pmk_list) {
8274 		WL_ERR(("pmk_list is NULL\n"));
8275 		return -EINVAL;
8276 	}
8277 	/* pmk list is supported only for STA interface i.e. primary interface
8278 	 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
8279 	 */
8280 	if (primary_dev != dev) {
8281 		WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
8282 			" interfaces than primary interface\n"));
8283 		return err;
8284 	}
8285 
8286 	WL_DBG(("No of elements %d\n", npmkids));
8287 	for (i = 0; i < npmkids; i++) {
8288 		WL_DBG(("PMKID[%d]: %pM =\n", i,
8289 			&pmk_list->pmkids.pmkid[i].bssid));
8290 		for (j = 0; j < WPA2_PMKID_LEN; j++) {
8291 			WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].pmkid[j]));
8292 		}
8293 	}
8294 	if (cfg->wlc_ver.wlc_ver_major >= MIN_PMKID_LIST_V3_FW_MAJOR) {
8295 			pmk_list->pmkids.version = PMKID_LIST_VER_3;
8296 			err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8297 				sizeof(*pmk_list), cfg->ioctl_buf,
8298 				WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8299 	}
8300 	else if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V2_FW_MAJOR) {
8301 		u32 v2_list_size = (u32)(sizeof(pmkid_list_v2_t) + npmkids*sizeof(pmkid_v2_t));
8302 		pmkid_list_v2_t *pmkid_v2_list = (pmkid_list_v2_t *)MALLOCZ(cfg->osh, v2_list_size);
8303 
8304 		if (pmkid_v2_list == NULL) {
8305 			WL_ERR(("failed to allocate pmkid list\n"));
8306 			return BCME_NOMEM;
8307 		}
8308 
8309 		pmkid_v2_list->version = PMKID_LIST_VER_2;
8310 		/* Account for version, length and pmkid_v2_t fields */
8311 		pmkid_v2_list->length = (npmkids * sizeof(pmkid_v2_t)) + (2 * sizeof(u16));
8312 
8313 		for (i = 0; i < npmkids; i++) {
8314 			/* memcpy_s return checks not needed as buffers are of same size */
8315 			(void)memcpy_s(&pmkid_v2_list->pmkid[i].BSSID,
8316 					ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8317 					ETHER_ADDR_LEN);
8318 
8319 			/* copy pmkid if available */
8320 			if (pmk_list->pmkids.pmkid[i].pmkid_len) {
8321 				(void)memcpy_s(pmkid_v2_list->pmkid[i].PMKID,
8322 						WPA2_PMKID_LEN,
8323 						pmk_list->pmkids.pmkid[i].pmkid,
8324 						pmk_list->pmkids.pmkid[i].pmkid_len);
8325 			}
8326 
8327 			if (pmk_list->pmkids.pmkid[i].pmk_len) {
8328 				(void)memcpy_s(pmkid_v2_list->pmkid[i].pmk,
8329 						pmk_list->pmkids.pmkid[i].pmk_len,
8330 						pmk_list->pmkids.pmkid[i].pmk,
8331 						pmk_list->pmkids.pmkid[i].pmk_len);
8332 				pmkid_v2_list->pmkid[i].pmk_len = pmk_list->pmkids.pmkid[i].pmk_len;
8333 			}
8334 
8335 			if (pmk_list->pmkids.pmkid[i].ssid_len) {
8336 				(void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
8337 						pmk_list->pmkids.pmkid[i].ssid_len,
8338 						pmk_list->pmkids.pmkid[i].ssid,
8339 						pmk_list->pmkids.pmkid[i].ssid_len);
8340 				pmkid_v2_list->pmkid[i].ssid.ssid_len
8341 					= pmk_list->pmkids.pmkid[i].ssid_len;
8342 			}
8343 
8344 			(void)memcpy_s(pmkid_v2_list->pmkid[i].fils_cache_id,
8345 					FILS_CACHE_ID_LEN, &pmk_list->pmkids.pmkid[i].fils_cache_id,
8346 					FILS_CACHE_ID_LEN);
8347 			pmkid_v2_list->pmkid[i].length = PMKID_ELEM_V2_LENGTH;
8348 		}
8349 		err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v2_list,
8350 				v2_list_size, cfg->ioctl_buf,
8351 				WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8352 		if (unlikely(err)) {
8353 			WL_ERR(("pmkid_info failed (%d)\n", err));
8354 		}
8355 
8356 		MFREE(cfg->osh, pmkid_v2_list, v2_list_size);
8357 	}
8358 	else {
8359 		u32 v1_list_size = (u32)(sizeof(pmkid_list_v1_t) + npmkids*sizeof(pmkid_v1_t));
8360 		pmkid_list_v1_t *pmkid_v1_list = (pmkid_list_v1_t *)MALLOCZ(cfg->osh, v1_list_size);
8361 		if (pmkid_v1_list == NULL) {
8362 			WL_ERR(("failed to allocate pmkid list\n"));
8363 			return BCME_NOMEM;
8364 		}
8365 		for (i = 0; i < npmkids; i++) {
8366 			/* memcpy_s return checks not needed as buffers are of same size */
8367 			(void)memcpy_s(&pmkid_v1_list->pmkid[i].BSSID,
8368 					ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8369 					ETHER_ADDR_LEN);
8370 			(void)memcpy_s(pmkid_v1_list->pmkid[i].PMKID,
8371 					WPA2_PMKID_LEN, pmk_list->pmkids.pmkid[i].pmkid,
8372 					WPA2_PMKID_LEN);
8373 			pmkid_v1_list->npmkid++;
8374 		}
8375 		err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v1_list,
8376 				v1_list_size, cfg->ioctl_buf,
8377 				WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8378 		if (unlikely(err)) {
8379 			WL_ERR(("pmkid_info failed (%d)\n", err));
8380 		}
8381 
8382 		MFREE(cfg->osh, pmkid_v1_list, v1_list_size);
8383 	}
8384 	return err;
8385 }
8386 
8387 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8388  * entry operation.
8389  */
8390 static s32
wl_cfg80211_set_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8391 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
8392 	struct cfg80211_pmksa *pmksa)
8393 {
8394 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8395 	s32 err = 0;
8396 	int i;
8397 	int npmkids = cfg->pmk_list->pmkids.count;
8398 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
8399 
8400 	RETURN_EIO_IF_NOT_UP(cfg);
8401 	BCM_REFERENCE(dhdp);
8402 	DHD_STATLOG_CTRL(dhdp, ST(INSTALL_PMKSA), dhd_net2idx(dhdp->info, dev), 0);
8403 
8404 	for (i = 0; i < npmkids; i++) {
8405 		if (pmksa->bssid != NULL) {
8406 			if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8407 				ETHER_ADDR_LEN))
8408 				break;
8409 		}
8410 #ifdef WL_FILS
8411 		else if (pmksa->ssid != NULL) {
8412 			if (!memcmp(pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8413 				pmksa->ssid_len))
8414 				break;
8415 		}
8416 #endif /* WL_FILS */
8417 	}
8418 	if (i < WL_NUM_PMKIDS_MAX) {
8419 		if (pmksa->bssid != NULL) {
8420 			memcpy(&cfg->pmk_list->pmkids.pmkid[i].bssid, pmksa->bssid,
8421 				ETHER_ADDR_LEN);
8422 		}
8423 #ifdef WL_FILS
8424 		else if (pmksa->ssid != NULL) {
8425 			cfg->pmk_list->pmkids.pmkid[i].ssid_len = pmksa->ssid_len;
8426 			memcpy(&cfg->pmk_list->pmkids.pmkid[i].ssid, pmksa->ssid,
8427 				pmksa->ssid_len);
8428 			memcpy(&cfg->pmk_list->pmkids.pmkid[i].fils_cache_id, pmksa->cache_id,
8429 				FILS_CACHE_ID_LEN);
8430 		}
8431 #endif /* WL_FILS */
8432 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS))
8433 		if (pmksa->pmk_len) {
8434 			if (memcpy_s(&cfg->pmk_list->pmkids.pmkid[i].pmk, PMK_LEN_MAX, pmksa->pmk,
8435 				pmksa->pmk_len)) {
8436 				WL_ERR(("invalid pmk len = %zu", pmksa->pmk_len));
8437 			} else {
8438 				cfg->pmk_list->pmkids.pmkid[i].pmk_len = pmksa->pmk_len;
8439 			}
8440 		}
8441 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS) */
8442 		/* return check not required as buffer lengths are same */
8443 		(void)memcpy_s(cfg->pmk_list->pmkids.pmkid[i].pmkid, WPA2_PMKID_LEN, pmksa->pmkid,
8444 			WPA2_PMKID_LEN);
8445 		cfg->pmk_list->pmkids.pmkid[i].pmkid_len = WPA2_PMKID_LEN;
8446 
8447 		/* set lifetime not to expire in firmware by default.
8448 		 * Currently, wpa_supplicant control PMKID lifetime on his end. e.g) set 12 hours
8449 		 * when it expired, wpa_supplicant should call set_pmksa/del_pmksa to update
8450 		 * corresponding entry.
8451 		 */
8452 		cfg->pmk_list->pmkids.pmkid[i].time_left = KEY_PERM_PMK;
8453 		if (i == npmkids) {
8454 			cfg->pmk_list->pmkids.length += sizeof(pmkid_v3_t);
8455 			cfg->pmk_list->pmkids.count++;
8456 		}
8457 	} else {
8458 		err = -EINVAL;
8459 	}
8460 
8461 #if (WL_DBG_LEVEL > 0)
8462 	if (pmksa->bssid != NULL) {
8463 		WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
8464 			&cfg->pmk_list->pmkids.pmkid[npmkids - 1].bssid));
8465 	}
8466 	for (i = 0; i < WPA2_PMKID_LEN; i++) {
8467 		WL_DBG(("%02x\n",
8468 			cfg->pmk_list->pmkids.pmkid[npmkids - 1].
8469 			pmkid[i]));
8470 	}
8471 #endif /* (WL_DBG_LEVEL > 0) */
8472 
8473 	err = wl_update_pmklist(dev, cfg->pmk_list, err);
8474 
8475 	return err;
8476 }
8477 
8478 /* sending pmkid_info IOVAR to manipulate PMKID(PMKSA) list in firmware.
8479  * input @pmksa: host given single pmksa info.
8480  * if it's NULL, assume whole list manipulated. e.g) flush all PMKIDs in firmware.
8481  * input @set: TRUE means adding PMKSA operation. FALSE means deleting.
8482  * return: log internal BCME_XXX error, and convert it to -EINVAL to linux generic error code.
8483  */
wl_cfg80211_update_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa,bool set)8484 static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
8485 	struct cfg80211_pmksa *pmksa, bool set) {
8486 
8487 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8488 	s32 err = 0;
8489 	pmkid_list_v3_t *pmk_list;
8490 	uint32 alloc_len;
8491 
8492 	RETURN_EIO_IF_NOT_UP(cfg);
8493 
8494 	if (cfg->wlc_ver.wlc_ver_major < MIN_PMKID_LIST_V3_FW_MAJOR) {
8495 		WL_ERR(("wlc_ver_major not supported:%d\n", cfg->wlc_ver.wlc_ver_major));
8496 		return BCME_VERSION;
8497 	}
8498 
8499 	alloc_len = (uint32) OFFSETOF(pmkid_list_v3_t, pmkid) + ((pmksa) ? sizeof(pmkid_v3_t) : 0);
8500 	pmk_list = (pmkid_list_v3_t *)MALLOCZ(cfg->osh, alloc_len);
8501 
8502 	if (pmk_list == NULL) {
8503 		return BCME_NOMEM;
8504 	}
8505 
8506 	pmk_list->version = PMKID_LIST_VER_3;
8507 	pmk_list->length = alloc_len;
8508 	pmk_list->count = (pmksa) ? 1 : 0; // 1 means single entry operation, 0 means whole list.
8509 
8510 	/* controll set/del action by lifetime parameter accordingly.
8511 	 * if set == TRUE, it's set PMKID action with lifetime permanent.
8512 	 * if set == FALSE, it's del PMKID action with lifetime zero.
8513 	 */
8514 	pmk_list->pmkid->time_left = (set) ? KEY_PERM_PMK : 0;
8515 
8516 	if (pmksa) {
8517 		if (pmksa->bssid) {
8518 			err = memcpy_s(&pmk_list->pmkid->bssid, sizeof(pmk_list->pmkid->bssid),
8519 				pmksa->bssid, ETHER_ADDR_LEN);
8520 			if (err) {
8521 				goto exit;
8522 			}
8523 		}
8524 		if (pmksa->pmkid) {
8525 			err = memcpy_s(&pmk_list->pmkid->pmkid, sizeof(pmk_list->pmkid->pmkid),
8526 				pmksa->pmkid, WPA2_PMKID_LEN);
8527 			if (err) {
8528 				goto exit;
8529 			}
8530 		}
8531 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
8532 		if (pmksa->pmk) {
8533 			err = memcpy_s(&pmk_list->pmkid->pmk, sizeof(pmk_list->pmkid->pmk),
8534 				pmksa->pmk, pmksa->pmk_len);
8535 			if (err) {
8536 				goto exit;
8537 			}
8538 			pmk_list->pmkid->pmk_len = pmksa->pmk_len;
8539 		}
8540 		if (pmksa->ssid) {
8541 			err = memcpy_s(&pmk_list->pmkid->ssid, sizeof(pmk_list->pmkid->ssid),
8542 				pmksa->ssid, pmksa->ssid_len);
8543 			if (err) {
8544 				goto exit;
8545 			}
8546 			pmk_list->pmkid->ssid_len = pmksa->ssid_len;
8547 		}
8548 		if (pmksa->cache_id) {
8549 			pmk_list->pmkid->fils_cache_id = *(uint16 *)pmksa->cache_id;
8550 		}
8551 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
8552 	}
8553 	err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8554 		alloc_len, cfg->ioctl_buf,
8555 		WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8556 
8557 exit:
8558 	if (pmk_list) {
8559 		MFREE(cfg->osh, pmk_list, alloc_len);
8560 	}
8561 	return err;
8562 }
8563 
8564 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8565  * entry operation.
8566  */
8567 static s32
wl_cfg80211_del_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8568 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
8569 	struct cfg80211_pmksa *pmksa)
8570 {
8571 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8572 	s32 err = 0;
8573 	int i;
8574 	int npmkids = cfg->pmk_list->pmkids.count;
8575 	RETURN_EIO_IF_NOT_UP(cfg);
8576 
8577 	if (!pmksa) {
8578 		WL_ERR(("pmksa is not initialized\n"));
8579 		return BCME_ERROR;
8580 	}
8581 	if (!npmkids) {
8582 		/* nmpkids = 0, nothing to delete */
8583 		WL_DBG(("npmkids=0. Skip del\n"));
8584 		return BCME_OK;
8585 	}
8586 
8587 #if (WL_DBG_LEVEL > 0)
8588 	if (pmksa->bssid) {
8589 		WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
8590 			pmksa->bssid));
8591 	}
8592 #ifdef WL_FILS
8593 	else if (pmksa->ssid) {
8594 		WL_DBG(("FILS: del_pmksa for ssid: "));
8595 		for (i = 0; i < pmksa->ssid_len; i++) {
8596 			WL_DBG(("%c", pmksa->ssid[i]));
8597 		}
8598 		WL_DBG(("\n"));
8599 	}
8600 #endif /* WL_FILS */
8601 	if (pmksa->pmkid) {
8602 		for (i = 0; i < WPA2_PMKID_LEN; i++) {
8603 			WL_DBG(("%02x\n", pmksa->pmkid[i]));
8604 		}
8605 	}
8606 #endif /* (WL_DBG_LEVEL > 0) */
8607 
8608 	for (i = 0; i < npmkids; i++) {
8609 		if (pmksa->bssid) {
8610 			if (!memcmp
8611 			    (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8612 			     ETHER_ADDR_LEN)) {
8613 					break;
8614 			}
8615 		}
8616 #ifdef WL_FILS
8617 		else if (pmksa->ssid) {
8618 			if (!memcmp
8619 			    (pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8620 			     pmksa->ssid_len)) {
8621 					break;
8622 			}
8623 		}
8624 #endif /* WL_FILS */
8625 	}
8626 	if ((npmkids > 0) && (i < npmkids)) {
8627 		bzero(&cfg->pmk_list->pmkids.pmkid[i], sizeof(pmkid_v3_t));
8628 		for (; i < (npmkids - 1); i++) {
8629 			(void)memcpy_s(&cfg->pmk_list->pmkids.pmkid[i],
8630 				sizeof(pmkid_v3_t),
8631 				&cfg->pmk_list->pmkids.pmkid[i + 1],
8632 				sizeof(pmkid_v3_t));
8633 		}
8634 		npmkids--;
8635 		cfg->pmk_list->pmkids.length -= sizeof(pmkid_v3_t);
8636 		cfg->pmk_list->pmkids.count--;
8637 
8638 	} else {
8639 		err = -EINVAL;
8640 	}
8641 
8642 	/* current wl_update_pmklist() doesn't delete corresponding PMKID entry.
8643 	 * inside firmware. So we need to issue delete action explicitely through
8644 	 * this function.
8645 	 */
8646 	err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
8647 	/* intentional fall through even on error.
8648 	 * it should work above MIN_PMKID_LIST_V3_FW_MAJOR, otherwise let ignore it.
8649 	 */
8650 
8651 	err = wl_update_pmklist(dev, cfg->pmk_list, err);
8652 
8653 	return err;
8654 
8655 }
8656 
8657 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8658  * entry operation.
8659  */
8660 static s32
wl_cfg80211_flush_pmksa(struct wiphy * wiphy,struct net_device * dev)8661 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
8662 {
8663 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8664 	s32 err = 0;
8665 	RETURN_EIO_IF_NOT_UP(cfg);
8666 	bzero(cfg->pmk_list, sizeof(*cfg->pmk_list));
8667 	cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
8668 	cfg->pmk_list->pmkids.count = 0;
8669 	cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
8670 	err = wl_update_pmklist(dev, cfg->pmk_list, err);
8671 	return err;
8672 }
8673 
8674 static s32
wl_cfg80211_remain_on_channel(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,struct ieee80211_channel * channel,enum nl80211_channel_type channel_type,unsigned int duration,u64 * cookie)8675 wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
8676 	struct ieee80211_channel *channel,
8677 #if !defined(WL_CFG80211_P2P_DEV_IF)
8678 	enum nl80211_channel_type channel_type,
8679 #endif /* WL_CFG80211_P2P_DEV_IF */
8680 	unsigned int duration, u64 *cookie)
8681 {
8682 	s32 target_channel;
8683 	u32 id;
8684 	s32 err = BCME_OK;
8685 	struct ether_addr primary_mac;
8686 	struct net_device *ndev = NULL;
8687 #ifdef CONFIG_AP6XXX_WIFI6_HDF
8688     NetDevice *netdev = NULL;
8689     int ret = 0;
8690 #endif
8691 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8692 
8693 	RETURN_EIO_IF_NOT_UP(cfg);
8694 #ifdef DHD_IFDEBUG
8695 	PRINT_WDEV_INFO(cfgdev);
8696 #endif /* DHD_IFDEBUG */
8697 
8698 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
8699 
8700 	mutex_lock(&cfg->usr_sync);
8701 	WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
8702 		ieee80211_frequency_to_channel(channel->center_freq),
8703 		duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO"));
8704 
8705 	if (!cfg->p2p) {
8706 		WL_ERR(("cfg->p2p is not initialized\n"));
8707 		err = BCME_ERROR;
8708 		goto exit;
8709 	}
8710 
8711 #ifdef P2P_LISTEN_OFFLOADING
8712 	if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8713 		WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
8714 		err = -EAGAIN;
8715 		goto exit;
8716 	}
8717 #endif /* P2P_LISTEN_OFFLOADING */
8718 
8719 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8720 	if (wl_get_drv_status_all(cfg, SCANNING)) {
8721 		wl_cfg80211_cancel_scan(cfg);
8722 	}
8723 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8724 
8725 	target_channel = ieee80211_frequency_to_channel(channel->center_freq);
8726 	memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel));
8727 #if defined(WL_ENABLE_P2P_IF)
8728 	cfg->remain_on_chan_type = channel_type;
8729 #endif /* WL_ENABLE_P2P_IF */
8730 	id = ++cfg->last_roc_id;
8731 	if (id == 0)
8732 		id = ++cfg->last_roc_id;
8733 	*cookie = id;
8734 
8735 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8736 	if (wl_get_drv_status(cfg, SCANNING, ndev)) {
8737 		timer_list_compat_t *_timer;
8738 		WL_DBG(("scan is running. go to fake listen state\n"));
8739 
8740 		if (duration > LONG_LISTEN_TIME) {
8741 			wl_cfg80211_scan_abort(cfg);
8742 		} else {
8743 			wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8744 
8745 			if (timer_pending(&cfg->p2p->listen_timer)) {
8746 				WL_DBG(("cancel current listen timer \n"));
8747 				del_timer_sync(&cfg->p2p->listen_timer);
8748 			}
8749 
8750 			_timer = &cfg->p2p->listen_timer;
8751 			wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
8752 
8753 			INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0);
8754 
8755 			err = BCME_OK;
8756 			goto exit;
8757 		}
8758 	}
8759 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8760 
8761 #ifdef WL_BCNRECV
8762 	/* check fakeapscan in progress then abort */
8763 	wl_android_bcnrecv_stop(ndev, WL_BCNRECV_LISTENBUSY);
8764 #endif /* WL_BCNRECV */
8765 #ifdef WL_CFG80211_SYNC_GON
8766 	if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
8767 		/* do not enter listen mode again if we are in listen mode already for next af.
8768 		 * remain on channel completion will be returned by waiting next af completion.
8769 		 */
8770 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8771 		wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8772 #else
8773 		wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8774 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8775 		goto exit;
8776 	}
8777 #endif /* WL_CFG80211_SYNC_GON */
8778 	if (cfg->p2p && !cfg->p2p->on) {
8779 		/* In case of p2p_listen command, supplicant send remain_on_channel
8780 		 * without turning on P2P
8781 		 */
8782 		get_primary_mac(cfg, &primary_mac);
8783 #ifndef WL_P2P_USE_RANDMAC
8784 		wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
8785 #endif /* WL_P2P_USE_RANDMAC */
8786 		p2p_on(cfg) = true;
8787 	}
8788 
8789 	if (p2p_is_on(cfg)) {
8790 		err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
8791 		if (unlikely(err)) {
8792 			goto exit;
8793 		}
8794 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8795 		wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8796 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8797 		err = wl_cfgp2p_discover_listen(cfg, target_channel, duration);
8798 
8799 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8800 		if (err == BCME_OK) {
8801 			wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8802 		} else {
8803 			/* if failed, firmware may be internal scanning state.
8804 			 * so other scan request shall not abort it
8805 			 */
8806 			wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8807 		}
8808 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8809 
8810 		if (err) {
8811 			wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
8812 		}
8813 
8814 		/* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant
8815 		 * and expire timer will send a completion to the upper layer
8816 		 */
8817 		err = BCME_OK;
8818 	}
8819 
8820 exit:
8821 	if (err == BCME_OK) {
8822 		WL_DBG(("Success\n"));
8823 #if defined(WL_CFG80211_P2P_DEV_IF)
8824 #ifdef CONFIG_AP6XXX_WIFI6_HDF
8825         netdev = get_hdf_netdev(HDF_INF_P2P0);
8826         ret = HdfWifiEventRemainOnChannel(netdev, channel->center_freq, duration);
8827         printk(KERN_INFO"call HdfWifiEventRemainOnChannel cookie=%llu, ret=%d\n", *cookie, ret);
8828 #else
8829 		cfg80211_ready_on_channel(cfgdev, *cookie, channel,
8830 			duration, GFP_KERNEL);
8831 #endif
8832 #else
8833 		cfg80211_ready_on_channel(cfgdev, *cookie, channel,
8834 			channel_type, duration, GFP_KERNEL);
8835 #endif /* WL_CFG80211_P2P_DEV_IF */
8836 	} else {
8837 		WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie));
8838 	}
8839 	mutex_unlock(&cfg->usr_sync);
8840 	return err;
8841 }
8842 
8843 static s32
wl_cfg80211_cancel_remain_on_channel(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u64 cookie)8844 wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
8845 	bcm_struct_cfgdev *cfgdev, u64 cookie)
8846 {
8847 	s32 err = 0;
8848 
8849 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8850 
8851 #ifdef P2PLISTEN_AP_SAMECHN
8852 	struct net_device *dev;
8853 #endif /* P2PLISTEN_AP_SAMECHN */
8854 
8855 	RETURN_EIO_IF_NOT_UP(cfg);
8856 
8857 #ifdef DHD_IFDEBUG
8858 	PRINT_WDEV_INFO(cfgdev);
8859 #endif /* DHD_IFDEBUG */
8860 
8861 #if defined(WL_CFG80211_P2P_DEV_IF)
8862 	if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
8863 		WL_DBG((" enter ) on P2P dedicated discover interface\n"));
8864 	}
8865 #else
8866 	WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex));
8867 #endif /* WL_CFG80211_P2P_DEV_IF */
8868 
8869 #ifdef P2PLISTEN_AP_SAMECHN
8870 	if (cfg && cfg->p2p_resp_apchn_status) {
8871 		dev = bcmcfg_to_prmry_ndev(cfg);
8872 		wl_cfg80211_set_p2p_resp_ap_chn(dev, 0);
8873 		cfg->p2p_resp_apchn_status = false;
8874 		WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
8875 	}
8876 #endif /* P2PLISTEN_AP_SAMECHN */
8877 
8878 	if (cfg->last_roc_id == cookie) {
8879 		wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
8880 		wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
8881 	} else {
8882 		WL_ERR(("wl_cfg80211_cancel_remain_on_channel: ignore, request cookie(%llu)"
8883 			" is not matched. (cur : %llu)\n",
8884 			cookie, cfg->last_roc_id));
8885 	}
8886 
8887 	return err;
8888 }
8889 
8890 static void
wl_cfg80211_afx_handler(struct work_struct * work)8891 wl_cfg80211_afx_handler(struct work_struct *work)
8892 {
8893 	struct afx_hdl *afx_instance;
8894 	struct bcm_cfg80211 *cfg;
8895 	s32 ret = BCME_OK;
8896 
8897 	BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
8898 	if (afx_instance) {
8899 		cfg = wl_get_cfg(afx_instance->dev);
8900 		if (cfg != NULL && cfg->afx_hdl->is_active) {
8901 			if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
8902 				ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
8903 					(100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
8904 			} else {
8905 				ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
8906 					cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
8907 					NULL);
8908 			}
8909 			if (unlikely(ret != BCME_OK)) {
8910 				WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
8911 				if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
8912 					complete(&cfg->act_frm_scan);
8913 			}
8914 		}
8915 	}
8916 }
8917 
8918 static s32
wl_cfg80211_af_searching_channel(struct bcm_cfg80211 * cfg,struct net_device * dev)8919 wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
8920 {
8921 	u32 max_retry = WL_CHANNEL_SYNC_RETRY;
8922 	bool is_p2p_gas = false;
8923 
8924 	if (dev == NULL)
8925 		return -1;
8926 
8927 	WL_DBG((" enter ) \n"));
8928 
8929 	wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8930 	cfg->afx_hdl->is_active = TRUE;
8931 
8932 	if (cfg->afx_hdl->pending_tx_act_frm) {
8933 		wl_action_frame_t *action_frame;
8934 		action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
8935 		if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len))
8936 			is_p2p_gas = true;
8937 	}
8938 
8939 	/* Loop to wait until we find a peer's channel or the
8940 	 * pending action frame tx is cancelled.
8941 	 */
8942 	while ((cfg->afx_hdl->retry < max_retry) &&
8943 		(cfg->afx_hdl->peer_chan == WL_INVALID)) {
8944 		cfg->afx_hdl->is_listen = FALSE;
8945 		wl_set_drv_status(cfg, SCANNING, dev);
8946 		WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
8947 			cfg->afx_hdl->retry));
8948 		/* search peer on peer's listen channel */
8949 		schedule_work(&cfg->afx_hdl->work);
8950 		wait_for_completion_timeout(&cfg->act_frm_scan,
8951 			msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8952 
8953 		if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8954 			!(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8955 			break;
8956 
8957 		if (is_p2p_gas)
8958 			break;
8959 
8960 		if (cfg->afx_hdl->my_listen_chan) {
8961 			WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
8962 				cfg->afx_hdl->my_listen_chan));
8963 			/* listen on my listen channel */
8964 			cfg->afx_hdl->is_listen = TRUE;
8965 			schedule_work(&cfg->afx_hdl->work);
8966 			wait_for_completion_timeout(&cfg->act_frm_scan,
8967 				msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8968 		}
8969 		if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8970 			!(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8971 			break;
8972 
8973 		cfg->afx_hdl->retry++;
8974 
8975 		WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
8976 	}
8977 
8978 	cfg->afx_hdl->is_active = FALSE;
8979 
8980 	wl_clr_drv_status(cfg, SCANNING, dev);
8981 	wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8982 
8983 	return (cfg->afx_hdl->peer_chan);
8984 }
8985 
8986 struct p2p_config_af_params {
8987 	s32 max_tx_retry;	/* max tx retry count if tx no ack */
8988 #ifdef WL_CFG80211_GON_COLLISION
8989 	/* drop tx go nego request if go nego collision occurs */
8990 	bool drop_tx_req;
8991 #endif // endif
8992 #ifdef WL_CFG80211_SYNC_GON
8993 	bool extra_listen;
8994 #endif // endif
8995 	bool search_channel;	/* 1: search peer's channel to send af */
8996 };
8997 
8998 #ifdef WL_DISABLE_HE_P2P
8999 static s32
wl_cfg80211_he_p2p_disable(struct wiphy * wiphy,struct ether_addr peer_mac)9000 wl_cfg80211_he_p2p_disable(struct wiphy *wiphy, struct ether_addr peer_mac)
9001 {
9002 	struct cfg80211_bss *bss;
9003 	u8 *ie = NULL;
9004 	u32 ie_len = 0;
9005 	struct net_device *ndev = NULL;
9006 	s32 bssidx = 0;
9007 	s32 err = BCME_OK;
9008 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9009 
9010 	bss = CFG80211_GET_BSS(wiphy, NULL, peer_mac.octet, NULL, 0);
9011 	if (!bss) {
9012 		WL_ERR(("Could not find the Peer device\n"));
9013 		return BCME_ERROR;
9014 	} else {
9015 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
9016 #if defined(WL_CFG80211_P2P_DEV_IF)
9017 		ie = (u8 *)bss->ies->data;
9018 		ie_len = bss->ies->len;
9019 #else
9020 		ie = bss->information_elements;
9021 		ie_len = bss->len_information_elements;
9022 #endif /* WL_CFG80211_P2P_DEV_IF */
9023 		GCC_DIAGNOSTIC_POP();
9024 	}
9025 	if (ie) {
9026 		if ((bcm_parse_tlvs_dot11(ie, ie_len,
9027 				EXT_MNG_HE_CAP_ID, TRUE)) == NULL) {
9028 			WL_DBG(("Peer does not support HE capability\n"));
9029 			ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
9030 			if (ndev && (bssidx =
9031 				wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
9032 				WL_ERR(("Find index failed\n"));
9033 				err = BCME_ERROR;
9034 			} else {
9035 				WL_DBG(("Disabling HE for P2P\n"));
9036 				err = wl_cfg80211_set_he_mode(ndev, cfg, bssidx,
9037 					WL_IF_TYPE_P2P_DISC, FALSE);
9038 				if (err < 0) {
9039 					WL_ERR(("failed to set he features, error=%d\n", err));
9040 				}
9041 			}
9042 		} else {
9043 			WL_DBG(("Peer supports HE capability\n"));
9044 		}
9045 	}
9046 	CFG80211_PUT_BSS(wiphy, bss);
9047 
9048 	return err;
9049 }
9050 #endif /* WL_DISABLE_HE_P2P */
9051 
9052 static s32
wl_cfg80211_config_p2p_pub_af_tx(struct wiphy * wiphy,wl_action_frame_t * action_frame,wl_af_params_t * af_params,struct p2p_config_af_params * config_af_params)9053 wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
9054 	wl_action_frame_t *action_frame, wl_af_params_t *af_params,
9055 	struct p2p_config_af_params *config_af_params)
9056 {
9057 	s32 err = BCME_OK;
9058 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9059 	wifi_p2p_pub_act_frame_t *act_frm =
9060 		(wifi_p2p_pub_act_frame_t *) (action_frame->data);
9061 
9062 	/* initialize default value */
9063 #ifdef WL_CFG80211_GON_COLLISION
9064 	config_af_params->drop_tx_req = false;
9065 #endif // endif
9066 #ifdef WL_CFG80211_SYNC_GON
9067 	config_af_params->extra_listen = true;
9068 #endif // endif
9069 	config_af_params->search_channel = false;
9070 	config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
9071 	cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
9072 
9073 	switch (act_frm->subtype) {
9074 	case P2P_PAF_GON_REQ: {
9075 		/* Disable he if peer does not support before starting GONEG */
9076 #ifdef WL_DISABLE_HE_P2P
9077 		wl_cfg80211_he_p2p_disable(wiphy, action_frame->da);
9078 #endif /* WL_DISABLE_HE_P2P */
9079 		WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
9080 		wl_set_p2p_status(cfg, GO_NEG_PHASE);
9081 
9082 		config_af_params->search_channel = true;
9083 		cfg->next_af_subtype = act_frm->subtype + 1;
9084 
9085 		/* increase dwell time to wait for RESP frame */
9086 		af_params->dwell_time = WL_MED_DWELL_TIME;
9087 
9088 #ifdef WL_CFG80211_GON_COLLISION
9089 		config_af_params->drop_tx_req = true;
9090 #endif /* WL_CFG80211_GON_COLLISION */
9091 		break;
9092 	}
9093 	case P2P_PAF_GON_RSP: {
9094 		cfg->next_af_subtype = act_frm->subtype + 1;
9095 		/* increase dwell time to wait for CONF frame */
9096 		af_params->dwell_time = WL_MED_DWELL_TIME + 100;
9097 		break;
9098 	}
9099 	case P2P_PAF_GON_CONF: {
9100 		/* If we reached till GO Neg confirmation reset the filter */
9101 		WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
9102 		wl_clr_p2p_status(cfg, GO_NEG_PHASE);
9103 
9104 		/* minimize dwell time */
9105 		af_params->dwell_time = WL_MIN_DWELL_TIME;
9106 
9107 #ifdef WL_CFG80211_GON_COLLISION
9108 		/* if go nego formation done, clear it */
9109 		cfg->block_gon_req_tx_count = 0;
9110 		cfg->block_gon_req_rx_count = 0;
9111 #endif /* WL_CFG80211_GON_COLLISION */
9112 #ifdef WL_CFG80211_SYNC_GON
9113 		config_af_params->extra_listen = false;
9114 #endif /* WL_CFG80211_SYNC_GON */
9115 		break;
9116 	}
9117 	case P2P_PAF_INVITE_REQ: {
9118 		config_af_params->search_channel = true;
9119 		cfg->next_af_subtype = act_frm->subtype + 1;
9120 
9121 		/* increase dwell time */
9122 		af_params->dwell_time = WL_MED_DWELL_TIME;
9123 		break;
9124 	}
9125 	case P2P_PAF_INVITE_RSP:
9126 		/* minimize dwell time */
9127 		af_params->dwell_time = WL_MIN_DWELL_TIME;
9128 #ifdef WL_CFG80211_SYNC_GON
9129 		config_af_params->extra_listen = false;
9130 #endif /* WL_CFG80211_SYNC_GON */
9131 		break;
9132 	case P2P_PAF_DEVDIS_REQ: {
9133 		if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
9134 			action_frame->len)) {
9135 			config_af_params->search_channel = true;
9136 		}
9137 
9138 		cfg->next_af_subtype = act_frm->subtype + 1;
9139 		/* maximize dwell time to wait for RESP frame */
9140 		af_params->dwell_time = WL_LONG_DWELL_TIME;
9141 		break;
9142 	}
9143 	case P2P_PAF_DEVDIS_RSP:
9144 		/* minimize dwell time */
9145 		af_params->dwell_time = WL_MIN_DWELL_TIME;
9146 #ifdef WL_CFG80211_SYNC_GON
9147 		config_af_params->extra_listen = false;
9148 #endif /* WL_CFG80211_SYNC_GON */
9149 		break;
9150 	case P2P_PAF_PROVDIS_REQ: {
9151 		if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
9152 			action_frame->len)) {
9153 			config_af_params->search_channel = true;
9154 		}
9155 
9156 		cfg->next_af_subtype = act_frm->subtype + 1;
9157 		/* increase dwell time to wait for RESP frame */
9158 		af_params->dwell_time = WL_MED_DWELL_TIME;
9159 		break;
9160 	}
9161 	case P2P_PAF_PROVDIS_RSP: {
9162 		cfg->next_af_subtype = P2P_PAF_GON_REQ;
9163 		af_params->dwell_time = WL_MED_DWELL_TIME;
9164 #ifdef WL_CFG80211_SYNC_GON
9165 		config_af_params->extra_listen = false;
9166 #endif /* WL_CFG80211_SYNC_GON */
9167 		break;
9168 	}
9169 	default:
9170 		WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
9171 			act_frm->subtype));
9172 		err = BCME_BADARG;
9173 	}
9174 	return err;
9175 }
9176 
9177 #ifdef WL11U
9178 static bool
wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 * cfg,wl_af_params_t * af_params,void * frame,u16 frame_len)9179 wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params,
9180 	void *frame, u16 frame_len)
9181 {
9182 	struct wl_scan_results *bss_list;
9183 	wl_bss_info_t *bi = NULL;
9184 	bool result = false;
9185 	s32 i;
9186 	chanspec_t chanspec;
9187 
9188 	/* If DFS channel is 52~148, check to block it or not */
9189 	if (af_params &&
9190 		(af_params->channel >= 52 && af_params->channel <= 148)) {
9191 		if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
9192 			bss_list = cfg->bss_list;
9193 			bi = next_bss(bss_list, bi);
9194 			for_each_bss(bss_list, bi, i) {
9195 				chanspec = wl_chspec_driver_to_host(bi->chanspec);
9196 				if (CHSPEC_IS5G(chanspec) &&
9197 					((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec))
9198 					== af_params->channel)) {
9199 					result = true;	/* do not block the action frame */
9200 					break;
9201 				}
9202 			}
9203 		}
9204 	}
9205 	else {
9206 		result = true;
9207 	}
9208 
9209 	WL_DBG(("result=%s", result?"true":"false"));
9210 	return result;
9211 }
9212 #endif /* WL11U */
9213 static bool
wl_cfg80211_check_dwell_overflow(int32 requested_dwell,ulong dwell_jiffies)9214 wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies)
9215 {
9216 	if ((requested_dwell & CUSTOM_RETRY_MASK) &&
9217 			(jiffies_to_msecs(jiffies - dwell_jiffies) >
9218 			 (requested_dwell & ~CUSTOM_RETRY_MASK))) {
9219 		WL_ERR(("Action frame TX retry time over dwell time!\n"));
9220 		return true;
9221 	}
9222 	return false;
9223 }
9224 
9225 static bool
wl_cfg80211_send_action_frame(struct wiphy * wiphy,struct net_device * dev,bcm_struct_cfgdev * cfgdev,wl_af_params_t * af_params,wl_action_frame_t * action_frame,u16 action_frame_len,s32 bssidx)9226 wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
9227 	bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
9228 	wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
9229 {
9230 #ifdef WL11U
9231 	struct net_device *ndev = NULL;
9232 #endif /* WL11U */
9233 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9234 	bool ack = false;
9235 	u8 category, action;
9236 	s32 tx_retry;
9237 	struct p2p_config_af_params config_af_params;
9238 	struct net_info *netinfo;
9239 #ifdef VSDB
9240 	ulong off_chan_started_jiffies = 0;
9241 #endif // endif
9242 	ulong dwell_jiffies = 0;
9243 	bool dwell_overflow = false;
9244 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
9245 
9246 	int32 requested_dwell = af_params->dwell_time;
9247 
9248 	/* Add the default dwell time
9249 	 * Dwell time to stay off-channel to wait for a response action frame
9250 	 * after transmitting an GO Negotiation action frame
9251 	 */
9252 	af_params->dwell_time = WL_DWELL_TIME;
9253 
9254 #ifdef WL11U
9255 #if defined(WL_CFG80211_P2P_DEV_IF)
9256 	ndev = dev;
9257 #else
9258 	ndev = ndev_to_cfgdev(cfgdev);
9259 #endif /* WL_CFG80211_P2P_DEV_IF */
9260 #endif /* WL11U */
9261 
9262 	category = action_frame->data[DOT11_ACTION_CAT_OFF];
9263 	action = action_frame->data[DOT11_ACTION_ACT_OFF];
9264 
9265 	/* initialize variables */
9266 	tx_retry = 0;
9267 	cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
9268 	config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
9269 	config_af_params.search_channel = false;
9270 #ifdef WL_CFG80211_GON_COLLISION
9271 	config_af_params.drop_tx_req = false;
9272 #endif // endif
9273 #ifdef WL_CFG80211_SYNC_GON
9274 	config_af_params.extra_listen = false;
9275 #endif // endif
9276 
9277 	/* config parameters */
9278 	/* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
9279 	if (category == DOT11_ACTION_CAT_PUBLIC) {
9280 		if ((action == P2P_PUB_AF_ACTION) &&
9281 			(action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
9282 			/* p2p public action frame process */
9283 			if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy,
9284 				action_frame, af_params, &config_af_params)) {
9285 				WL_DBG(("Unknown subtype.\n"));
9286 			}
9287 
9288 #ifdef WL_CFG80211_GON_COLLISION
9289 			if (config_af_params.drop_tx_req) {
9290 				if (cfg->block_gon_req_tx_count) {
9291 					/* drop gon req tx action frame */
9292 					WL_DBG(("Drop gon req tx action frame: count %d\n",
9293 						cfg->block_gon_req_tx_count));
9294 					goto exit;
9295 				}
9296 			}
9297 #endif /* WL_CFG80211_GON_COLLISION */
9298 		} else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
9299 			/* service discovery process */
9300 			if (action == P2PSD_ACTION_ID_GAS_IREQ ||
9301 				action == P2PSD_ACTION_ID_GAS_CREQ) {
9302 				/* configure service discovery query frame */
9303 
9304 				config_af_params.search_channel = true;
9305 
9306 				/* save next af suptype to cancel remained dwell time */
9307 				cfg->next_af_subtype = action + 1;
9308 
9309 				af_params->dwell_time = WL_MED_DWELL_TIME;
9310 				if (requested_dwell & CUSTOM_RETRY_MASK) {
9311 					config_af_params.max_tx_retry =
9312 						(requested_dwell & CUSTOM_RETRY_MASK) >> 24;
9313 					af_params->dwell_time =
9314 						(requested_dwell & ~CUSTOM_RETRY_MASK);
9315 					WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
9316 						config_af_params.max_tx_retry,
9317 						af_params->dwell_time));
9318 				}
9319 			} else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
9320 				action == P2PSD_ACTION_ID_GAS_CRESP) {
9321 				/* configure service discovery response frame */
9322 				af_params->dwell_time = WL_MIN_DWELL_TIME;
9323 			} else {
9324 				WL_DBG(("Unknown action type: %d\n", action));
9325 			}
9326 		} else {
9327 			WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
9328 				category, action, action_frame_len));
9329 		}
9330 	} else if (category == P2P_AF_CATEGORY) {
9331 		/* do not configure anything. it will be sent with a default configuration */
9332 	} else {
9333 		WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
9334 			category, action));
9335 		if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
9336 			wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9337 			return false;
9338 		}
9339 	}
9340 
9341 	netinfo = wl_get_netinfo_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
9342 	/* validate channel and p2p ies */
9343 	if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) &&
9344 		netinfo && netinfo->bss.ies.probe_req_ie_len) {
9345 		config_af_params.search_channel = true;
9346 	} else {
9347 		config_af_params.search_channel = false;
9348 	}
9349 #ifdef WL11U
9350 	if (ndev == bcmcfg_to_prmry_ndev(cfg))
9351 		config_af_params.search_channel = false;
9352 #endif /* WL11U */
9353 
9354 #ifdef VSDB
9355 	/* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
9356 	if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
9357 		OSL_SLEEP(50);
9358 	}
9359 #endif // endif
9360 
9361 	/* if scan is ongoing, abort current scan. */
9362 	if (wl_get_drv_status_all(cfg, SCANNING)) {
9363 		wl_cfg80211_cancel_scan(cfg);
9364 	}
9365 
9366 	/* Abort P2P listen */
9367 	if (discover_cfgdev(cfgdev, cfg)) {
9368 		if (cfg->p2p_supported && cfg->p2p) {
9369 			wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
9370 				wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
9371 		}
9372 	}
9373 
9374 #ifdef WL11U
9375 	/* handling DFS channel exceptions */
9376 	if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) {
9377 		return false;	/* the action frame was blocked */
9378 	}
9379 #endif /* WL11U */
9380 
9381 	/* set status and destination address before sending af */
9382 	if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
9383 		/* set this status to cancel the remained dwell time in rx process */
9384 		wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9385 	}
9386 	wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
9387 	memcpy(cfg->afx_hdl->tx_dst_addr.octet,
9388 		af_params->action_frame.da.octet,
9389 		sizeof(cfg->afx_hdl->tx_dst_addr.octet));
9390 
9391 	/* save af_params for rx process */
9392 	cfg->afx_hdl->pending_tx_act_frm = af_params;
9393 
9394 	if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
9395 		WL_DBG(("Set GAS action frame config.\n"));
9396 		config_af_params.search_channel = false;
9397 		config_af_params.max_tx_retry = 1;
9398 	}
9399 
9400 	/* search peer's channel */
9401 	if (config_af_params.search_channel) {
9402 		/* initialize afx_hdl */
9403 		if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
9404 			WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
9405 			goto exit;
9406 		}
9407 		cfg->afx_hdl->dev = dev;
9408 		cfg->afx_hdl->retry = 0;
9409 		cfg->afx_hdl->peer_chan = WL_INVALID;
9410 
9411 		if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
9412 			WL_ERR(("couldn't find peer's channel.\n"));
9413 			wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
9414 				af_params->channel);
9415 			/* Even if we couldn't find peer channel, try to send the frame
9416 			 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
9417 			 * respond to probe request (Ideally it has to be in listen and
9418 			 * responsd to probe request). However if we send Go neg req, the
9419 			 * peer is sending GO-neg resp. So instead of giving up here, just
9420 			 * proceed and attempt sending out the action frame.
9421 			 */
9422 		}
9423 
9424 		wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
9425 		/*
9426 		 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
9427 		 * but after the check of piggyback algorithm.
9428 		 * To take care of current piggback algo, lets abort the scan here itself.
9429 		 */
9430 		wl_cfg80211_cancel_scan(cfg);
9431 		/* Suspend P2P discovery's search-listen to prevent it from
9432 		 * starting a scan or changing the channel.
9433 		 */
9434 		if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9435 			WL_ERR(("Can not disable discovery mode\n"));
9436 			goto exit;
9437 		}
9438 
9439 		/* update channel */
9440 		if (cfg->afx_hdl->peer_chan != WL_INVALID) {
9441 			af_params->channel = cfg->afx_hdl->peer_chan;
9442 			WL_ERR(("Attempt tx on peer listen channel:%d ",
9443 				cfg->afx_hdl->peer_chan));
9444 		} else {
9445 			WL_ERR(("Attempt tx with the channel provided by userspace."
9446 			"Channel: %d\n", af_params->channel));
9447 		}
9448 	}
9449 
9450 #ifdef VSDB
9451 	off_chan_started_jiffies = jiffies;
9452 #endif /* VSDB */
9453 
9454 	wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel);
9455 
9456 	wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
9457 
9458 	dwell_jiffies = jiffies;
9459 	/* Now send a tx action frame */
9460 	ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
9461 	dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9462 
9463 	/* if failed, retry it. tx_retry_max value is configure by .... */
9464 	while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry) &&
9465 			!dwell_overflow) {
9466 #ifdef VSDB
9467 		if (af_params->channel) {
9468 			if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
9469 				OFF_CHAN_TIME_THRESHOLD_MS) {
9470 				WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
9471 				off_chan_started_jiffies = jiffies;
9472 			} else
9473 				OSL_SLEEP(AF_RETRY_DELAY_TIME);
9474 		}
9475 #endif /* VSDB */
9476 		ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
9477 			false : true;
9478 		dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9479 	}
9480 
9481 	if (ack == false) {
9482 		WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
9483 	}
9484 	WL_DBG(("Complete to send action frame\n"));
9485 exit:
9486 	/* Clear SENDING_ACT_FRM after all sending af is done */
9487 	wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9488 
9489 #ifdef WL_CFG80211_SYNC_GON
9490 	/* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
9491 	 * if we coundn't get the next action response frame and dongle does not keep
9492 	 * the dwell time, go to listen state again to get next action response frame.
9493 	 */
9494 	if (ack && config_af_params.extra_listen &&
9495 #ifdef WL_CFG80211_GON_COLLISION
9496 		!cfg->block_gon_req_tx_count &&
9497 #endif /* WL_CFG80211_GON_COLLISION */
9498 		wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
9499 		cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
9500 		s32 extar_listen_time;
9501 
9502 		extar_listen_time = af_params->dwell_time -
9503 			jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
9504 
9505 		if (extar_listen_time > 50) {
9506 			wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9507 			WL_DBG(("Wait more time! actual af time:%d,"
9508 				"calculated extar listen:%d\n",
9509 				af_params->dwell_time, extar_listen_time));
9510 			if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
9511 				extar_listen_time + 100) == BCME_OK) {
9512 				wait_for_completion_timeout(&cfg->wait_next_af,
9513 					msecs_to_jiffies(extar_listen_time + 100 + 300));
9514 			}
9515 			wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9516 		}
9517 	}
9518 #endif /* WL_CFG80211_SYNC_GON */
9519 	wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9520 
9521 	cfg->afx_hdl->pending_tx_act_frm = NULL;
9522 
9523 	if (ack) {
9524 		WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
9525 			cfg->afx_hdl->my_listen_chan));
9526 	} else {
9527 		WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
9528 			cfg->afx_hdl->my_listen_chan));
9529 	}
9530 
9531 #ifdef WL_CFG80211_GON_COLLISION
9532 	if (cfg->block_gon_req_tx_count) {
9533 		cfg->block_gon_req_tx_count--;
9534 		/* if ack is ture, supplicant will wait more time(100ms).
9535 		 * so we will return it as a success to get more time .
9536 		 */
9537 		ack = true;
9538 	}
9539 #endif /* WL_CFG80211_GON_COLLISION */
9540 	return ack;
9541 }
9542 
9543 #define MAX_NUM_OF_ASSOCIATED_DEV       64
9544 static s32
9545 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
wl_cfg80211_mgmt_tx(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,struct cfg80211_mgmt_tx_params * params,u64 * cookie)9546 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9547 	struct cfg80211_mgmt_tx_params *params, u64 *cookie)
9548 #else
9549 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9550 	struct ieee80211_channel *channel, bool offchan,
9551 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
9552 	enum nl80211_channel_type channel_type,
9553 	bool channel_type_valid,
9554 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
9555 	unsigned int wait, const u8* buf, size_t len,
9556 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
9557 	bool no_cck,
9558 #endif // endif
9559 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
9560 	bool dont_wait_for_ack,
9561 #endif // endif
9562 	u64 *cookie)
9563 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9564 {
9565 	wl_action_frame_t *action_frame;
9566 	wl_af_params_t *af_params;
9567 	scb_val_t scb_val;
9568 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9569 	struct ieee80211_channel *channel = params->chan;
9570 	const u8 *buf = params->buf;
9571 	size_t len = params->len;
9572 #endif // endif
9573 	const struct ieee80211_mgmt *mgmt;
9574 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9575 	struct net_device *dev = NULL;
9576 	s32 err = BCME_OK;
9577 	s32 bssidx = 0;
9578 	u32 id;
9579 	bool ack = false;
9580 	s8 eabuf[ETHER_ADDR_STR_LEN];
9581 
9582 	WL_DBG(("Enter \n"));
9583 
9584 	if (len > ACTION_FRAME_SIZE) {
9585 		WL_ERR(("bad length:%zu\n", len));
9586 		return BCME_BADLEN;
9587 	}
9588 #ifdef DHD_IFDEBUG
9589 	PRINT_WDEV_INFO(cfgdev);
9590 #endif /* DHD_IFDEBUG */
9591 
9592 	dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
9593 
9594 	if (!dev) {
9595 		WL_ERR(("dev is NULL\n"));
9596 		return -EINVAL;
9597 	}
9598 
9599 	/* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE)	*/
9600 	if (discover_cfgdev(cfgdev, cfg)) {
9601 		if (!cfg->p2p_supported || !cfg->p2p) {
9602 			WL_ERR(("P2P doesn't setup completed yet\n"));
9603 			return -EINVAL;
9604 		}
9605 		bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9606 	}
9607 	else {
9608 		if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
9609 			WL_ERR(("Find p2p index failed\n"));
9610 			return BCME_ERROR;
9611 		}
9612 	}
9613 
9614 	WL_DBG(("TX target bssidx=%d, wdev iftype=%d, center_freq=%u\n", bssidx, cfgdev->iftype, params->chan->center_freq));
9615 
9616 	if (p2p_is_on(cfg)) {
9617 		/* Suspend P2P discovery search-listen to prevent it from changing the
9618 		 * channel.
9619 		 */
9620 		if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9621 			WL_ERR(("Can not disable discovery mode\n"));
9622 			return -EFAULT;
9623 		}
9624 	}
9625 	*cookie = 0;
9626 	id = cfg->send_action_id++;
9627 	if (id == 0)
9628 		id = cfg->send_action_id++;
9629 	*cookie = id;
9630 	mgmt = (const struct ieee80211_mgmt *)buf;
9631 	if (ieee80211_is_mgmt(mgmt->frame_control)) {
9632 		if (ieee80211_is_probe_resp(mgmt->frame_control)) {
9633 			s32 ie_offset =  DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
9634 			s32 ie_len = len - ie_offset;
9635 			if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9636 				bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9637 			}
9638 			wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
9639 				VNDR_IE_PRBRSP_FLAG, (const u8 *)(buf + ie_offset), ie_len);
9640 			cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9641 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9642 			HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf, len, true);
9643 #endif
9644 #if defined(P2P_IE_MISSING_FIX)
9645 			if (!cfg->p2p_prb_noti) {
9646 				cfg->p2p_prb_noti = true;
9647 				WL_DBG(("wl_cfg80211_mgmt_tx: TX 802_1X Probe"
9648 					" Response first time.\n"));
9649 			}
9650 #endif // endif
9651 			goto exit;
9652 		} else if (ieee80211_is_disassoc(mgmt->frame_control) ||
9653 			ieee80211_is_deauth(mgmt->frame_control)) {
9654 			char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
9655 				sizeof(struct ether_addr) + sizeof(uint)] = {0};
9656 			int num_associated = 0;
9657 			struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9658 			if (!bcmp((const uint8 *)BSSID_BROADCAST,
9659 				(const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
9660 				assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9661 				err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST,
9662 					assoc_maclist, sizeof(mac_buf));
9663 				if (err < 0)
9664 					WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9665 				else
9666 					num_associated = assoc_maclist->count;
9667 			}
9668 			memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
9669 			scb_val.val = mgmt->u.disassoc.reason_code;
9670 			err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
9671 				sizeof(scb_val_t));
9672 			if (err < 0)
9673 				WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
9674 			WL_ERR(("Disconnect STA : " MACDBG " scb_val.val %d\n",
9675 				MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mgmt->da,
9676 				eabuf)), scb_val.val));
9677 
9678 			if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
9679 				wl_delay(400);
9680 
9681 			cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9682 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9683 			HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf, len, true);
9684 #endif
9685 			goto exit;
9686 
9687 		} else if (ieee80211_is_action(mgmt->frame_control)) {
9688 			/* Abort the dwell time of any previous off-channel
9689 			* action frame that may be still in effect.  Sending
9690 			* off-channel action frames relies on the driver's
9691 			* scan engine.  If a previous off-channel action frame
9692 			* tx is still in progress (including the dwell time),
9693 			* then this new action frame will not be sent out.
9694 			*/
9695 /* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
9696  * And previous off-channel action frame must be ended before new af tx.
9697  */
9698 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9699 			wl_cfg80211_cancel_scan(cfg);
9700 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9701 		}
9702 #ifdef WL_CLIENT_SAE
9703 		else if (ieee80211_is_auth(mgmt->frame_control)) {
9704 			int err = 0;
9705 			wl_assoc_mgr_cmd_t *cmd;
9706 			char *ambuf = NULL;
9707 			int param_len;
9708 
9709 			ack = true;
9710 			if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9711 				bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9712 			}
9713 			param_len = sizeof(wl_assoc_mgr_cmd_t) + len;
9714 			ambuf = MALLOCZ(cfg->osh, param_len);
9715 			if (ambuf == NULL) {
9716 				WL_ERR(("unable to allocate frame\n"));
9717 				return -ENOMEM;
9718 			}
9719 			cmd = (wl_assoc_mgr_cmd_t*)ambuf;
9720 			cmd->version = WL_ASSOC_MGR_CURRENT_VERSION;
9721 			cmd->length = len;
9722 			cmd->cmd = WL_ASSOC_MGR_CMD_SEND_AUTH;
9723 			memcpy(&cmd->params, buf, len);
9724 			err = wldev_iovar_setbuf(dev, "assoc_mgr_cmd", ambuf, param_len,
9725 				cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
9726 			if (unlikely(err)) {
9727 				WL_ERR(("Failed to send auth(%d)\n", err));
9728 				ack = false;
9729 			}
9730 			MFREE(cfg->osh, ambuf, param_len);
9731 			cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9732 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9733 			HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf, len, ack);
9734 #endif
9735 			goto exit;
9736 		}
9737 #endif /* WL_CLIENT_SAE */
9738 	} else {
9739 		WL_ERR(("Driver only allows MGMT packet type\n"));
9740 		goto exit;
9741 	}
9742 
9743 	af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
9744 
9745 	if (af_params == NULL)
9746 	{
9747 		WL_ERR(("unable to allocate frame\n"));
9748 		return -ENOMEM;
9749 	}
9750 
9751 	action_frame = &af_params->action_frame;
9752 
9753 	/* Add the packet Id */
9754 	action_frame->packetId = *cookie;
9755 	WL_DBG(("action frame %d\n", action_frame->packetId));
9756 	/* Add BSSID */
9757 	memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
9758 	memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
9759 
9760 	/* Add the length exepted for 802.11 header  */
9761 	action_frame->len = len - DOT11_MGMT_HDR_LEN;
9762 	WL_DBG(("action_frame->len: %d\n", action_frame->len));
9763 
9764 	/* Add the channel */
9765 	af_params->channel =
9766 		ieee80211_frequency_to_channel(channel->center_freq);
9767 	/* Save listen_chan for searching common channel */
9768 	cfg->afx_hdl->peer_listen_chan = af_params->channel;
9769 	WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
9770 
9771 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9772 	af_params->dwell_time = params->wait;
9773 #else
9774 	af_params->dwell_time = wait;
9775 #endif // endif
9776 
9777 	memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
9778 
9779 	ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params,
9780 		action_frame, action_frame->len, bssidx);
9781 	cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9782 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9783 	HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf, len, ack);
9784 #endif
9785 
9786 	MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
9787 exit:
9788 	return err;
9789 }
9790 
9791 static void
wl_cfg80211_mgmt_frame_register(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u16 frame,bool reg)9792 wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9793 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9794 	u16 frame, bool reg)
9795 #else
9796 	struct mgmt_frame_regs *upd)
9797 #endif
9798 {
9799 
9800 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9801 	WL_DBG(("frame_type: %x, reg: %d\n", frame, reg));
9802 
9803 	if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
9804 		return;
9805 #endif
9806 
9807 	return;
9808 }
9809 
9810 static s32
wl_cfg80211_change_bss(struct wiphy * wiphy,struct net_device * dev,struct bss_parameters * params)9811 wl_cfg80211_change_bss(struct wiphy *wiphy,
9812 	struct net_device *dev,
9813 	struct bss_parameters *params)
9814 {
9815 	s32 err = 0;
9816 	s32 ap_isolate = 0;
9817 #ifdef PCIE_FULL_DONGLE
9818 	s32 ifidx = DHD_BAD_IF;
9819 #endif // endif
9820 #if defined(PCIE_FULL_DONGLE)
9821 	dhd_pub_t *dhd;
9822 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9823 	dhd = (dhd_pub_t *)(cfg->pub);
9824 #if defined(WL_ENABLE_P2P_IF)
9825 	if (cfg->p2p_net == dev)
9826 		dev = bcmcfg_to_prmry_ndev(cfg);
9827 #endif
9828 #endif // endif
9829 
9830 	if (params->use_cts_prot >= 0) {
9831 	}
9832 
9833 	if (params->use_short_preamble >= 0) {
9834 	}
9835 
9836 	if (params->use_short_slot_time >= 0) {
9837 	}
9838 
9839 	if (params->basic_rates) {
9840 	}
9841 
9842 	if (params->ap_isolate >= 0) {
9843 		ap_isolate = params->ap_isolate;
9844 #ifdef PCIE_FULL_DONGLE
9845 		ifidx = dhd_net2idx(dhd->info, dev);
9846 
9847 		if (ifidx != DHD_BAD_IF) {
9848 			err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate);
9849 		} else {
9850 			WL_ERR(("Failed to set ap_isolate\n"));
9851 		}
9852 #else
9853 		err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
9854 		if (unlikely(err))
9855 		{
9856 			WL_ERR(("set ap_isolate Error (%d)\n", err));
9857 		}
9858 #endif /* PCIE_FULL_DONGLE */
9859 	}
9860 
9861 	if (params->ht_opmode >= 0) {
9862 	}
9863 
9864 	return err;
9865 }
9866 
9867 static int
wl_get_bandwidth_cap(struct net_device * ndev,uint32 band,uint32 * bandwidth)9868 wl_get_bandwidth_cap(struct net_device *ndev, uint32 band, uint32 *bandwidth)
9869 {
9870 	u32 bw = WL_CHANSPEC_BW_20;
9871 	s32 err = BCME_OK;
9872 	s32 bw_cap = 0;
9873 	struct {
9874 		u32 band;
9875 		u32 bw_cap;
9876 	} param = {0, 0};
9877 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
9878 
9879 	if (band == IEEE80211_BAND_5GHZ) {
9880 		param.band = WLC_BAND_5G;
9881 		err = wldev_iovar_getbuf(ndev, "bw_cap", &param, sizeof(param),
9882 			ioctl_buf, sizeof(ioctl_buf), NULL);
9883 		if (err) {
9884 			if (err != BCME_UNSUPPORTED) {
9885 				WL_ERR(("bw_cap failed, %d\n", err));
9886 				return err;
9887 			} else {
9888 				err = wldev_iovar_getint(ndev, "mimo_bw_cap", &bw_cap);
9889 				if (err) {
9890 					WL_ERR(("error get mimo_bw_cap (%d)\n", err));
9891 				}
9892 				if (bw_cap != WLC_N_BW_20ALL) {
9893 					bw = WL_CHANSPEC_BW_40;
9894 				}
9895 			}
9896 		} else {
9897 			if (WL_BW_CAP_80MHZ(ioctl_buf[0])) {
9898 				bw = WL_CHANSPEC_BW_80;
9899 			} else if (WL_BW_CAP_40MHZ(ioctl_buf[0])) {
9900 				bw = WL_CHANSPEC_BW_40;
9901 			} else {
9902 				bw = WL_CHANSPEC_BW_20;
9903 			}
9904 		}
9905 	} else if (band == IEEE80211_BAND_2GHZ) {
9906 		bw = WL_CHANSPEC_BW_20;
9907 	}
9908 
9909 	*bandwidth = bw;
9910 
9911 	return err;
9912 }
9913 
9914 static s32
wl_cfg80211_set_channel(struct wiphy * wiphy,struct net_device * dev,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type)9915 wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
9916 	struct ieee80211_channel *chan,
9917 	enum nl80211_channel_type channel_type)
9918 {
9919 	s32 _chan;
9920 	chanspec_t chspec = 0;
9921 	chanspec_t fw_chspec = 0;
9922 	u32 bw = WL_CHANSPEC_BW_20;
9923 	s32 err = BCME_OK;
9924 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9925 #if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL) || defined(WL_EXT_IAPSTA)
9926 	dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
9927 #endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
9928 
9929 	dev = ndev_to_wlc_ndev(dev, cfg);
9930 	_chan = ieee80211_frequency_to_channel(chan->center_freq);
9931 #ifdef WL_EXT_IAPSTA
9932 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
9933 		wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev), WL_IF_TYPE_AP);
9934 		_chan = wl_ext_iapsta_update_channel(dhd, dev, _chan);
9935 	}
9936 #endif
9937 	WL_MSG(dev->name, "netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
9938 		dev->ifindex, channel_type, _chan);
9939 
9940 #ifdef NOT_YET
9941 	switch (channel_type) {
9942 		case NL80211_CHAN_HT40MINUS:
9943 			/* secondary channel is below the control channel */
9944 			chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_UPPER);
9945 			break;
9946 		case NL80211_CHAN_HT40PLUS:
9947 			/* secondary channel is above the control channel */
9948 			chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_LOWER);
9949 			break;
9950 		default:
9951 			chspec = CH20MHZ_CHSPEC(channel);
9952 
9953 	}
9954 #endif /* NOT_YET */
9955 
9956 #if defined(APSTA_RESTRICTED_CHANNEL)
9957 	if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
9958 		DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
9959 		wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
9960 		u32 *sta_chan = (u32 *)wl_read_prof(cfg,
9961 			bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN);
9962 		u32 sta_band = (*sta_chan > CH_MAX_2G_CHANNEL) ?
9963 			IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
9964 		if (chan->band == sta_band) {
9965 			/* Do not try SCC in 5GHz if channel is not CH149 */
9966 			_chan = (sta_band == IEEE80211_BAND_5GHZ &&
9967 				*sta_chan != DEFAULT_5G_SOFTAP_CHANNEL) ?
9968 				DEFAULT_2G_SOFTAP_CHANNEL : *sta_chan;
9969 			WL_ERR(("target channel will be changed to %d\n", _chan));
9970 			if (_chan <= CH_MAX_2G_CHANNEL) {
9971 				bw = WL_CHANSPEC_BW_20;
9972 				goto set_channel;
9973 			}
9974 		}
9975 	}
9976 #endif /* APSTA_RESTRICTED_CHANNEL */
9977 
9978 	err = wl_get_bandwidth_cap(dev, chan->band, &bw);
9979 	if (err < 0) {
9980 		WL_ERR(("Failed to get bandwidth information, err=%d\n", err));
9981 		return err;
9982 	}
9983 
9984 set_channel:
9985 	chspec = wf_channel2chspec(_chan, bw);
9986 	if (wf_chspec_valid(chspec)) {
9987 		fw_chspec = wl_chspec_host_to_driver(chspec);
9988 		if (fw_chspec != INVCHANSPEC) {
9989 			if ((err = wldev_iovar_setint(dev, "chanspec",
9990 				fw_chspec)) == BCME_BADCHAN) {
9991 				if (bw == WL_CHANSPEC_BW_80)
9992 					goto change_bw;
9993 				err = wldev_ioctl_set(dev, WLC_SET_CHANNEL,
9994 					&_chan, sizeof(_chan));
9995 				if (err < 0) {
9996 					WL_ERR(("WLC_SET_CHANNEL error %d"
9997 					"chip may not be supporting this channel\n", err));
9998 				}
9999 			} else if (err) {
10000 				WL_ERR(("failed to set chanspec error %d\n", err));
10001 			}
10002 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
10003 			else {
10004 				/* Disable Frameburst only for stand-alone 2GHz SoftAP */
10005 				if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
10006 					DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
10007 					(_chan <= CH_MAX_2G_CHANNEL) &&
10008 					!wl_get_drv_status(cfg, CONNECTED,
10009 						bcmcfg_to_prmry_ndev(cfg))) {
10010 					WL_DBG(("Disabling frameburst on "
10011 						"stand-alone 2GHz SoftAP\n"));
10012 					wl_cfg80211_set_frameburst(cfg, FALSE);
10013 				}
10014 			}
10015 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
10016 		} else {
10017 			WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
10018 			err = BCME_ERROR;
10019 		}
10020 	} else {
10021 change_bw:
10022 		if (bw == WL_CHANSPEC_BW_80)
10023 			bw = WL_CHANSPEC_BW_40;
10024 		else if (bw == WL_CHANSPEC_BW_40)
10025 			bw = WL_CHANSPEC_BW_20;
10026 		else
10027 			bw = 0;
10028 		if (bw)
10029 			goto set_channel;
10030 		WL_ERR(("Invalid chanspec 0x%x\n", chspec));
10031 		err = BCME_ERROR;
10032 	}
10033 #ifdef CUSTOM_SET_CPUCORE
10034 	if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
10035 		WL_DBG(("SoftAP mode do not need to set cpucore\n"));
10036 	} else if (chspec & WL_CHANSPEC_BW_80) {
10037 		/* SoftAp only mode do not need to set cpucore */
10038 		if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
10039 			dev != bcmcfg_to_prmry_ndev(cfg)) {
10040 			/* Soft AP on virtual Iface (AP+STA case) */
10041 			dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
10042 			dhd_set_cpucore(dhd, TRUE);
10043 		} else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
10044 			/* If P2P IF is vht80 */
10045 			dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
10046 			dhd_set_cpucore(dhd, TRUE);
10047 		}
10048 	}
10049 #endif /* CUSTOM_SET_CPUCORE */
10050 	if (!err && (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
10051 		/* Update AP/GO operating channel */
10052 		cfg->ap_oper_channel = ieee80211_frequency_to_channel(chan->center_freq);
10053 	}
10054 	if (err) {
10055 		wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
10056 			FW_LOGSET_MASK_ALL);
10057 	}
10058 	return err;
10059 }
10060 
10061 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
10062 struct net_device *
wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 * cfg)10063 wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
10064 {
10065 	struct net_info *_net_info, *next;
10066 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
10067 	list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
10068 		GCC_DIAGNOSTIC_POP();
10069 		if (_net_info->ndev &&
10070 			test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
10071 			return _net_info->ndev;
10072 	}
10073 
10074 	return NULL;
10075 }
10076 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
10077 
10078 static s32
wl_validate_opensecurity(struct net_device * dev,s32 bssidx,bool privacy)10079 wl_validate_opensecurity(struct net_device *dev, s32 bssidx, bool privacy)
10080 {
10081 	s32 err = BCME_OK;
10082 	u32 wpa_val;
10083 	s32 wsec = 0;
10084 
10085 	/* set auth */
10086 	err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
10087 	if (err < 0) {
10088 		WL_ERR(("auth error %d\n", err));
10089 		return BCME_ERROR;
10090 	}
10091 
10092 	if (privacy) {
10093 		/* If privacy bit is set in open mode, then WEP would be enabled */
10094 		wsec = WEP_ENABLED;
10095 		WL_DBG(("Setting wsec to %d for WEP \n", wsec));
10096 	}
10097 
10098 	/* set wsec */
10099 	err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10100 	if (err < 0) {
10101 		WL_ERR(("wsec error %d\n", err));
10102 		return BCME_ERROR;
10103 	}
10104 
10105 	/* set upper-layer auth */
10106 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC)
10107 		wpa_val = WPA_AUTH_NONE;
10108 	else
10109 		wpa_val = WPA_AUTH_DISABLED;
10110 	err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_val, bssidx);
10111 	if (err < 0) {
10112 		WL_ERR(("wpa_auth error %d\n", err));
10113 		return BCME_ERROR;
10114 	}
10115 
10116 	return 0;
10117 }
10118 
10119 #define MAX_FILS_IND_IE_LEN 1024u
10120 static s32
wl_validate_fils_ind_ie(struct net_device * dev,const bcm_tlv_t * filsindie,s32 bssidx)10121 wl_validate_fils_ind_ie(struct net_device *dev, const bcm_tlv_t *filsindie, s32 bssidx)
10122 {
10123 	s32 err = BCME_OK;
10124 	struct bcm_cfg80211 *cfg = NULL;
10125 	bcm_iov_buf_t *iov_buf = NULL;
10126 	bcm_xtlv_t* pxtlv;
10127 	int iov_buf_size = 0;
10128 
10129 	if (!dev || !filsindie) {
10130 		WL_ERR(("%s: dev/filsidie is null\n", __FUNCTION__));
10131 		goto exit;
10132 	}
10133 
10134 	cfg = wl_get_cfg(dev);
10135 	if (!cfg) {
10136 		WL_ERR(("%s: cfg is null\n", __FUNCTION__));
10137 		goto exit;
10138 	}
10139 
10140 	iov_buf_size = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) + filsindie->len - 1;
10141 	iov_buf = MALLOCZ(cfg->osh, iov_buf_size);
10142 	if (!iov_buf) {
10143 		WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, iov_buf_size));
10144 		err = BCME_NOMEM;
10145 		goto exit;
10146 	}
10147 	iov_buf->version = WL_FILS_IOV_VERSION;
10148 	iov_buf->id = WL_FILS_CMD_ADD_IND_IE;
10149 	iov_buf->len = sizeof(bcm_xtlv_t) + filsindie->len - 1;
10150 	pxtlv = (bcm_xtlv_t*)&iov_buf->data[0];
10151 	pxtlv->id = WL_FILS_XTLV_IND_IE;
10152 	pxtlv->len = filsindie->len;
10153 	/* memcpy_s return check not required as buffer is allocated based on ie
10154 	 * len
10155 	 */
10156 	(void)memcpy_s(pxtlv->data, filsindie->len, filsindie->data, filsindie->len);
10157 
10158 	err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf_size,
10159 		cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
10160 	if (unlikely(err)) {
10161 		WL_ERR(("fils indication ioctl error (%d)\n", err));
10162 		 goto exit;
10163 	}
10164 
10165 exit:
10166 	if (err < 0) {
10167 		WL_ERR(("FILS Ind setting error %d\n", err));
10168 	}
10169 
10170 	if (iov_buf) {
10171 		MFREE(cfg->osh, iov_buf, iov_buf_size);
10172 	}
10173 	return err;
10174 }
10175 
10176 static s32
wl_validate_wpa2ie(struct net_device * dev,const bcm_tlv_t * wpa2ie,s32 bssidx)10177 wl_validate_wpa2ie(struct net_device *dev, const bcm_tlv_t *wpa2ie, s32 bssidx)
10178 {
10179 	s32 len = 0;
10180 	s32 err = BCME_OK;
10181 	u16 auth = 0; /* d11 open authentication */
10182 	u32 wsec;
10183 	u32 pval = 0;
10184 	u32 gval = 0;
10185 	u32 wpa_auth = 0;
10186 	const wpa_suite_mcast_t *mcast;
10187 	const wpa_suite_ucast_t *ucast;
10188 	const wpa_suite_auth_key_mgmt_t *mgmt;
10189 	const wpa_pmkid_list_t *pmkid;
10190 	int cnt = 0;
10191 #ifdef MFP
10192 	int mfp = 0;
10193 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10194 #endif /* MFP */
10195 
10196 	u16 suite_count;
10197 	u8 rsn_cap[2];
10198 	u32 wme_bss_disable;
10199 
10200 	if (wpa2ie == NULL)
10201 		goto exit;
10202 
10203 	WL_DBG(("Enter \n"));
10204 	len =  wpa2ie->len - WPA2_VERSION_LEN;
10205 	/* check the mcast cipher */
10206 	mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10207 	switch (mcast->type) {
10208 		case WPA_CIPHER_NONE:
10209 			gval = 0;
10210 			break;
10211 		case WPA_CIPHER_WEP_40:
10212 		case WPA_CIPHER_WEP_104:
10213 			gval = WEP_ENABLED;
10214 			break;
10215 		case WPA_CIPHER_TKIP:
10216 			gval = TKIP_ENABLED;
10217 			break;
10218 		case WPA_CIPHER_AES_CCM:
10219 			gval = AES_ENABLED;
10220 			break;
10221 #ifdef BCMWAPI_WPI
10222 		case WAPI_CIPHER_SMS4:
10223 			gval = SMS4_ENABLED;
10224 			break;
10225 #endif // endif
10226 		default:
10227 			WL_ERR(("No Security Info\n"));
10228 			break;
10229 	}
10230 	if ((len -= WPA_SUITE_LEN) <= 0)
10231 		return BCME_BADLEN;
10232 
10233 	/* check the unicast cipher */
10234 	ucast = (const wpa_suite_ucast_t *)&mcast[1];
10235 	suite_count = ltoh16_ua(&ucast->count);
10236 	switch (ucast->list[0].type) {
10237 		case WPA_CIPHER_NONE:
10238 			pval = 0;
10239 			break;
10240 		case WPA_CIPHER_WEP_40:
10241 		case WPA_CIPHER_WEP_104:
10242 			pval = WEP_ENABLED;
10243 			break;
10244 		case WPA_CIPHER_TKIP:
10245 			pval = TKIP_ENABLED;
10246 			break;
10247 		case WPA_CIPHER_AES_CCM:
10248 			pval = AES_ENABLED;
10249 			break;
10250 #ifdef BCMWAPI_WPI
10251 		case WAPI_CIPHER_SMS4:
10252 			pval = SMS4_ENABLED;
10253 			break;
10254 #endif // endif
10255 		default:
10256 			WL_ERR(("No Security Info\n"));
10257 	}
10258 	if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
10259 		return BCME_BADLEN;
10260 
10261 	/* FOR WPS , set SEC_OW_ENABLED */
10262 	wsec = (pval | gval | SES_OW_ENABLED);
10263 	/* check the AKM */
10264 	mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
10265 	suite_count = cnt = ltoh16_ua(&mgmt->count);
10266 	while (cnt--) {
10267 		switch (mgmt->list[cnt].type) {
10268 		case RSN_AKM_NONE:
10269 			wpa_auth |= WPA_AUTH_NONE;
10270 			break;
10271 		case RSN_AKM_UNSPECIFIED:
10272 			wpa_auth |= WPA2_AUTH_UNSPECIFIED;
10273 			break;
10274 		case RSN_AKM_PSK:
10275 			wpa_auth |= WPA2_AUTH_PSK;
10276 			break;
10277 #ifdef MFP
10278 		case RSN_AKM_MFP_PSK:
10279 			wpa_auth |= WPA2_AUTH_PSK_SHA256;
10280 			break;
10281 		case RSN_AKM_MFP_1X:
10282 			wpa_auth |= WPA2_AUTH_1X_SHA256;
10283 			break;
10284 		case RSN_AKM_FILS_SHA256:
10285 			wpa_auth |= WPA2_AUTH_FILS_SHA256;
10286 			break;
10287 		case RSN_AKM_FILS_SHA384:
10288 			wpa_auth |= WPA2_AUTH_FILS_SHA384;
10289 			break;
10290 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
10291 		case RSN_AKM_SAE_PSK:
10292 			wpa_auth |= WPA3_AUTH_SAE_PSK;
10293 			break;
10294 #endif /* WL_SAE || WL_CLIENT_SAE */
10295 #endif /* MFP */
10296 		default:
10297 			WL_ERR(("No Key Mgmt Info\n"));
10298 		}
10299 	}
10300 
10301 	if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
10302 		rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
10303 		rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
10304 
10305 		if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
10306 			wme_bss_disable = 0;
10307 		} else {
10308 			wme_bss_disable = 1;
10309 		}
10310 
10311 #ifdef MFP
10312 	if (rsn_cap[0] & RSN_CAP_MFPR) {
10313 		WL_DBG(("MFP Required \n"));
10314 		mfp = WL_MFP_REQUIRED;
10315 		/* Our firmware has requirement that WPA2_AUTH_PSK/WPA2_AUTH_UNSPECIFIED
10316 		 * be set, if SHA256 OUI is to be included in the rsn ie.
10317 		 */
10318 		if (wpa_auth & WPA2_AUTH_PSK_SHA256) {
10319 			wpa_auth |= WPA2_AUTH_PSK;
10320 		} else if (wpa_auth & WPA2_AUTH_1X_SHA256) {
10321 			wpa_auth |= WPA2_AUTH_UNSPECIFIED;
10322 		}
10323 	} else if (rsn_cap[0] & RSN_CAP_MFPC) {
10324 		WL_DBG(("MFP Capable \n"));
10325 		mfp = WL_MFP_CAPABLE;
10326 	}
10327 #endif /* MFP */
10328 
10329 		/* set wme_bss_disable to sync RSN Capabilities */
10330 		err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
10331 		if (err < 0) {
10332 			WL_ERR(("wme_bss_disable error %d\n", err));
10333 			return BCME_ERROR;
10334 		}
10335 	} else {
10336 		WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
10337 	}
10338 
10339 	len -= RSN_CAP_LEN;
10340 	if (len >= WPA2_PMKID_COUNT_LEN) {
10341 		pmkid = (const wpa_pmkid_list_t *)
10342 		        ((const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
10343 		cnt = ltoh16_ua(&pmkid->count);
10344 		if (cnt != 0) {
10345 			WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
10346 			return BCME_ERROR;
10347 		}
10348 		/* since PMKID cnt is known to be 0 for AP, */
10349 		/* so don't bother to send down this info to firmware */
10350 	}
10351 
10352 #ifdef MFP
10353 	len -= WPA2_PMKID_COUNT_LEN;
10354 	if (len >= WPA_SUITE_LEN) {
10355 		cfg->bip_pos =
10356 		        (const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN;
10357 	} else {
10358 		cfg->bip_pos = NULL;
10359 	}
10360 #endif // endif
10361 
10362 	/* set auth */
10363 	err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10364 	if (err < 0) {
10365 		WL_ERR(("auth error %d\n", err));
10366 		return BCME_ERROR;
10367 	}
10368 
10369 	/* set wsec */
10370 	err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10371 	if (err < 0) {
10372 		WL_ERR(("wsec error %d\n", err));
10373 		return BCME_ERROR;
10374 	}
10375 
10376 #ifdef MFP
10377 	cfg->mfp_mode = mfp;
10378 #endif /* MFP */
10379 
10380 	/* set upper-layer auth */
10381 	err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10382 	if (err < 0) {
10383 		WL_ERR(("wpa_auth error %d\n", err));
10384 		return BCME_ERROR;
10385 	}
10386 exit:
10387 	return 0;
10388 }
10389 
10390 static s32
wl_validate_wpaie(struct net_device * dev,const wpa_ie_fixed_t * wpaie,s32 bssidx)10391 wl_validate_wpaie(struct net_device *dev, const wpa_ie_fixed_t *wpaie, s32 bssidx)
10392 {
10393 	const wpa_suite_mcast_t *mcast;
10394 	const wpa_suite_ucast_t *ucast;
10395 	const wpa_suite_auth_key_mgmt_t *mgmt;
10396 	u16 auth = 0; /* d11 open authentication */
10397 	u16 count;
10398 	s32 err = BCME_OK;
10399 	s32 len = 0;
10400 	u32 i;
10401 	u32 wsec;
10402 	u32 pval = 0;
10403 	u32 gval = 0;
10404 	u32 wpa_auth = 0;
10405 	u32 tmp = 0;
10406 
10407 	if (wpaie == NULL)
10408 		goto exit;
10409 	WL_DBG(("Enter \n"));
10410 	len = wpaie->length;    /* value length */
10411 	len -= WPA_IE_TAG_FIXED_LEN;
10412 	/* check for multicast cipher suite */
10413 	if (len < WPA_SUITE_LEN) {
10414 		WL_INFORM_MEM(("no multicast cipher suite\n"));
10415 		goto exit;
10416 	}
10417 
10418 	/* pick up multicast cipher */
10419 	mcast = (const wpa_suite_mcast_t *)&wpaie[1];
10420 	len -= WPA_SUITE_LEN;
10421 	if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
10422 		if (IS_WPA_CIPHER(mcast->type)) {
10423 			tmp = 0;
10424 			switch (mcast->type) {
10425 				case WPA_CIPHER_NONE:
10426 					tmp = 0;
10427 					break;
10428 				case WPA_CIPHER_WEP_40:
10429 				case WPA_CIPHER_WEP_104:
10430 					tmp = WEP_ENABLED;
10431 					break;
10432 				case WPA_CIPHER_TKIP:
10433 					tmp = TKIP_ENABLED;
10434 					break;
10435 				case WPA_CIPHER_AES_CCM:
10436 					tmp = AES_ENABLED;
10437 					break;
10438 				default:
10439 					WL_ERR(("No Security Info\n"));
10440 			}
10441 			gval |= tmp;
10442 		}
10443 	}
10444 	/* Check for unicast suite(s) */
10445 	if (len < WPA_IE_SUITE_COUNT_LEN) {
10446 		WL_INFORM_MEM(("no unicast suite\n"));
10447 		goto exit;
10448 	}
10449 	/* walk thru unicast cipher list and pick up what we recognize */
10450 	ucast = (const wpa_suite_ucast_t *)&mcast[1];
10451 	count = ltoh16_ua(&ucast->count);
10452 	len -= WPA_IE_SUITE_COUNT_LEN;
10453 	for (i = 0; i < count && len >= WPA_SUITE_LEN;
10454 		i++, len -= WPA_SUITE_LEN) {
10455 		if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10456 			if (IS_WPA_CIPHER(ucast->list[i].type)) {
10457 				tmp = 0;
10458 				switch (ucast->list[i].type) {
10459 					case WPA_CIPHER_NONE:
10460 						tmp = 0;
10461 						break;
10462 					case WPA_CIPHER_WEP_40:
10463 					case WPA_CIPHER_WEP_104:
10464 						tmp = WEP_ENABLED;
10465 						break;
10466 					case WPA_CIPHER_TKIP:
10467 						tmp = TKIP_ENABLED;
10468 						break;
10469 					case WPA_CIPHER_AES_CCM:
10470 						tmp = AES_ENABLED;
10471 						break;
10472 					default:
10473 						WL_ERR(("No Security Info\n"));
10474 				}
10475 				pval |= tmp;
10476 			}
10477 		}
10478 	}
10479 	len -= (count - i) * WPA_SUITE_LEN;
10480 	/* Check for auth key management suite(s) */
10481 	if (len < WPA_IE_SUITE_COUNT_LEN) {
10482 		WL_INFORM_MEM((" no auth key mgmt suite\n"));
10483 		goto exit;
10484 	}
10485 	/* walk thru auth management suite list and pick up what we recognize */
10486 	mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
10487 	count = ltoh16_ua(&mgmt->count);
10488 	len -= WPA_IE_SUITE_COUNT_LEN;
10489 	for (i = 0; i < count && len >= WPA_SUITE_LEN;
10490 		i++, len -= WPA_SUITE_LEN) {
10491 		if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10492 			if (IS_WPA_AKM(mgmt->list[i].type)) {
10493 				tmp = 0;
10494 				switch (mgmt->list[i].type) {
10495 					case RSN_AKM_NONE:
10496 						tmp = WPA_AUTH_NONE;
10497 						break;
10498 					case RSN_AKM_UNSPECIFIED:
10499 						tmp = WPA_AUTH_UNSPECIFIED;
10500 						break;
10501 					case RSN_AKM_PSK:
10502 						tmp = WPA_AUTH_PSK;
10503 						break;
10504 					default:
10505 						WL_ERR(("No Key Mgmt Info\n"));
10506 				}
10507 				wpa_auth |= tmp;
10508 			}
10509 		}
10510 
10511 	}
10512 	/* FOR WPS , set SEC_OW_ENABLED */
10513 	wsec = (pval | gval | SES_OW_ENABLED);
10514 	/* set auth */
10515 	err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10516 	if (err < 0) {
10517 		WL_ERR(("auth error %d\n", err));
10518 		return BCME_ERROR;
10519 	}
10520 	/* set wsec */
10521 	err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10522 	if (err < 0) {
10523 		WL_ERR(("wsec error %d\n", err));
10524 		return BCME_ERROR;
10525 	}
10526 	/* set upper-layer auth */
10527 	err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10528 	if (err < 0) {
10529 		WL_ERR(("wpa_auth error %d\n", err));
10530 		return BCME_ERROR;
10531 	}
10532 exit:
10533 	return 0;
10534 }
10535 
10536 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
wl_get_cipher_type(uint8 type)10537 static u32 wl_get_cipher_type(uint8 type)
10538 {
10539 	u32 ret = 0;
10540 	switch (type) {
10541 		case WPA_CIPHER_NONE:
10542 			ret = 0;
10543 			break;
10544 		case WPA_CIPHER_WEP_40:
10545 		case WPA_CIPHER_WEP_104:
10546 			ret = WEP_ENABLED;
10547 			break;
10548 		case WPA_CIPHER_TKIP:
10549 			ret = TKIP_ENABLED;
10550 			break;
10551 		case WPA_CIPHER_AES_CCM:
10552 			ret = AES_ENABLED;
10553 			break;
10554 #ifdef BCMWAPI_WPI
10555 		case WAPI_CIPHER_SMS4:
10556 			ret = SMS4_ENABLED;
10557 			break;
10558 #endif // endif
10559 		default:
10560 			WL_ERR(("No Security Info\n"));
10561 	}
10562 	return ret;
10563 }
10564 
wl_get_suite_auth_key_mgmt_type(uint8 type,const wpa_suite_mcast_t * mcast)10565 static u32 wl_get_suite_auth_key_mgmt_type(uint8 type, const wpa_suite_mcast_t *mcast)
10566 {
10567 	u32 ret = 0;
10568 	u32 is_wpa2 = 0;
10569 
10570 	if (!bcmp(mcast->oui, WPA2_OUI, WPA2_OUI_LEN)) {
10571 		is_wpa2 = 1;
10572 	}
10573 
10574 	WL_INFORM_MEM(("%s, type = %d\n", is_wpa2 ? "WPA2":"WPA", type));
10575 	switch (type) {
10576 		case RSN_AKM_NONE:
10577 			/* For WPA and WPA2, AUTH_NONE is common */
10578 			ret = WPA_AUTH_NONE;
10579 			break;
10580 		case RSN_AKM_UNSPECIFIED:
10581 			if (is_wpa2) {
10582 				ret = WPA2_AUTH_UNSPECIFIED;
10583 			} else {
10584 				ret = WPA_AUTH_UNSPECIFIED;
10585 			}
10586 			break;
10587 		case RSN_AKM_PSK:
10588 			if (is_wpa2) {
10589 				ret = WPA2_AUTH_PSK;
10590 			} else {
10591 				ret = WPA_AUTH_PSK;
10592 			}
10593 			break;
10594 #ifdef WL_SAE
10595 		case RSN_AKM_SAE_PSK:
10596 			ret = WPA3_AUTH_SAE_PSK;
10597 			break;
10598 #endif /* WL_SAE */
10599 		default:
10600 			WL_ERR(("No Key Mgmt Info\n"));
10601 	}
10602 
10603 	return ret;
10604 }
10605 
10606 static s32
wl_validate_wpaie_wpa2ie(struct net_device * dev,const wpa_ie_fixed_t * wpaie,const bcm_tlv_t * wpa2ie,s32 bssidx)10607 wl_validate_wpaie_wpa2ie(struct net_device *dev, const wpa_ie_fixed_t *wpaie,
10608 	const bcm_tlv_t *wpa2ie, s32 bssidx)
10609 {
10610 	const wpa_suite_mcast_t *mcast;
10611 	const wpa_suite_ucast_t *ucast;
10612 	const wpa_suite_auth_key_mgmt_t *mgmt;
10613 	u16 auth = 0; /* d11 open authentication */
10614 	u16 count;
10615 	s32 err = BCME_OK;
10616 	u32 wme_bss_disable;
10617 	u16 suite_count;
10618 	u8 rsn_cap[2];
10619 	s32 len = 0;
10620 	u32 i;
10621 	u32 wsec1, wsec2, wsec;
10622 	u32 pval = 0;
10623 	u32 gval = 0;
10624 	u32 wpa_auth = 0;
10625 	u32 wpa_auth1 = 0;
10626 	u32 wpa_auth2 = 0;
10627 
10628 	if (wpaie == NULL || wpa2ie == NULL)
10629 		goto exit;
10630 
10631 	WL_DBG(("Enter \n"));
10632 	len = wpaie->length;    /* value length */
10633 	len -= WPA_IE_TAG_FIXED_LEN;
10634 	/* check for multicast cipher suite */
10635 	if (len < WPA_SUITE_LEN) {
10636 		WL_INFORM_MEM(("no multicast cipher suite\n"));
10637 		goto exit;
10638 	}
10639 
10640 	/* pick up multicast cipher */
10641 	mcast = (const wpa_suite_mcast_t *)&wpaie[1];
10642 	len -= WPA_SUITE_LEN;
10643 	if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
10644 		if (IS_WPA_CIPHER(mcast->type)) {
10645 			gval |= wl_get_cipher_type(mcast->type);
10646 		}
10647 	}
10648 	WL_DBG(("\nwpa ie validate\n"));
10649 	WL_DBG(("wpa ie mcast cipher = 0x%X\n", gval));
10650 
10651 	/* Check for unicast suite(s) */
10652 	if (len < WPA_IE_SUITE_COUNT_LEN) {
10653 		WL_INFORM_MEM(("no unicast suite\n"));
10654 		goto exit;
10655 	}
10656 
10657 	/* walk thru unicast cipher list and pick up what we recognize */
10658 	ucast = (const wpa_suite_ucast_t *)&mcast[1];
10659 	count = ltoh16_ua(&ucast->count);
10660 	len -= WPA_IE_SUITE_COUNT_LEN;
10661 	for (i = 0; i < count && len >= WPA_SUITE_LEN;
10662 		i++, len -= WPA_SUITE_LEN) {
10663 		if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10664 			if (IS_WPA_CIPHER(ucast->list[i].type)) {
10665 				pval |= wl_get_cipher_type(ucast->list[i].type);
10666 			}
10667 		}
10668 	}
10669 	WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count, pval));
10670 
10671 	/* FOR WPS , set SEC_OW_ENABLED */
10672 	wsec1 = (pval | gval | SES_OW_ENABLED);
10673 	WL_ERR(("wpa ie wsec = 0x%X\n", wsec1));
10674 
10675 	len -= (count - i) * WPA_SUITE_LEN;
10676 	/* Check for auth key management suite(s) */
10677 	if (len < WPA_IE_SUITE_COUNT_LEN) {
10678 		WL_INFORM_MEM((" no auth key mgmt suite\n"));
10679 		goto exit;
10680 	}
10681 	/* walk thru auth management suite list and pick up what we recognize */
10682 	mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
10683 	count = ltoh16_ua(&mgmt->count);
10684 	len -= WPA_IE_SUITE_COUNT_LEN;
10685 	for (i = 0; i < count && len >= WPA_SUITE_LEN;
10686 		i++, len -= WPA_SUITE_LEN) {
10687 		if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10688 			if (IS_WPA_AKM(mgmt->list[i].type)) {
10689 				wpa_auth1 |=
10690 					wl_get_suite_auth_key_mgmt_type(mgmt->list[i].type, mcast);
10691 			}
10692 		}
10693 
10694 	}
10695 	WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth1));
10696 	WL_ERR(("\nwpa2 ie validate\n"));
10697 
10698 	pval = 0;
10699 	gval = 0;
10700 	len =  wpa2ie->len;
10701 	/* check the mcast cipher */
10702 	mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10703 	gval = wl_get_cipher_type(mcast->type);
10704 
10705 	WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval));
10706 	if ((len -= WPA_SUITE_LEN) <= 0)
10707 	{
10708 		WL_ERR(("P:wpa2 ie len[%d]", len));
10709 		return BCME_BADLEN;
10710 	}
10711 
10712 	/* check the unicast cipher */
10713 	ucast = (const wpa_suite_ucast_t *)&mcast[1];
10714 	suite_count = ltoh16_ua(&ucast->count);
10715 	WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count));
10716 	pval |= wl_get_cipher_type(ucast->list[0].type);
10717 
10718 	if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
10719 		return BCME_BADLEN;
10720 
10721 	WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval));
10722 
10723 	/* FOR WPS , set SEC_OW_ENABLED */
10724 	wsec2 = (pval | gval | SES_OW_ENABLED);
10725 	WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2));
10726 
10727 	/* check the AKM */
10728 	mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
10729 	suite_count = ltoh16_ua(&mgmt->count);
10730 	wpa_auth2 = wl_get_suite_auth_key_mgmt_type(mgmt->list[0].type, mcast);
10731 	WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth2));
10732 
10733 	if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
10734 		rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
10735 		rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
10736 		if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
10737 			wme_bss_disable = 0;
10738 		} else {
10739 			wme_bss_disable = 1;
10740 		}
10741 		WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap[0], wme_bss_disable));
10742 
10743 		/* set wme_bss_disable to sync RSN Capabilities */
10744 		err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
10745 		if (err < 0) {
10746 			WL_ERR(("wme_bss_disable error %d\n", err));
10747 			return BCME_ERROR;
10748 		}
10749 	} else {
10750 		WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
10751 	}
10752 
10753 	wsec = (wsec1 | wsec2);
10754 	wpa_auth = (wpa_auth1 | wpa_auth2);
10755 	WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec, wpa_auth));
10756 
10757 	/* set auth */
10758 	err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10759 	if (err < 0) {
10760 		WL_ERR(("auth error %d\n", err));
10761 		return BCME_ERROR;
10762 	}
10763 	/* set wsec */
10764 	err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10765 	if (err < 0) {
10766 		WL_ERR(("wsec error %d\n", err));
10767 		return BCME_ERROR;
10768 	}
10769 	/* set upper-layer auth */
10770 	err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10771 	if (err < 0) {
10772 		WL_ERR(("wpa_auth error %d\n", err));
10773 		return BCME_ERROR;
10774 	}
10775 exit:
10776 	return 0;
10777 }
10778 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10779 
10780 static s32
wl_cfg80211_bcn_validate_sec(struct net_device * dev,struct parsed_ies * ies,u32 dev_role,s32 bssidx,bool privacy)10781 wl_cfg80211_bcn_validate_sec(
10782 	struct net_device *dev,
10783 	struct parsed_ies *ies,
10784 	u32 dev_role,
10785 	s32 bssidx,
10786 	bool privacy)
10787 {
10788 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10789 	wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
10790 
10791 	if (!bss) {
10792 		WL_ERR(("cfgbss is NULL \n"));
10793 		return BCME_ERROR;
10794 	}
10795 
10796 	if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
10797 		/* For P2P GO, the sec type is WPA2-PSK */
10798 		WL_DBG(("P2P GO: validating wpa2_ie"));
10799 		if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx)  < 0)
10800 			return BCME_ERROR;
10801 
10802 	} else if (dev_role == NL80211_IFTYPE_AP) {
10803 
10804 		WL_DBG(("SoftAP: validating security"));
10805 		/* If wpa2_ie or wpa_ie is present validate it */
10806 
10807 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10808 		if ((ies->wpa_ie != NULL && ies->wpa2_ie != NULL)) {
10809 			if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie, ies->wpa2_ie, bssidx)  < 0) {
10810 				bss->security_mode = false;
10811 				return BCME_ERROR;
10812 			}
10813 		}
10814 		else {
10815 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10816 		if ((ies->wpa2_ie || ies->wpa_ie) &&
10817 			((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx)  < 0 ||
10818 			wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
10819 			bss->security_mode = false;
10820 			return BCME_ERROR;
10821 		}
10822 
10823 		if (ies->fils_ind_ie &&
10824 			(wl_validate_fils_ind_ie(dev, ies->fils_ind_ie, bssidx)  < 0)) {
10825 			bss->security_mode = false;
10826 			return BCME_ERROR;
10827 		}
10828 
10829 		bss->security_mode = true;
10830 		if (bss->rsn_ie) {
10831 			MFREE(cfg->osh, bss->rsn_ie, bss->rsn_ie[1]
10832 				+ WPA_RSN_IE_TAG_FIXED_LEN);
10833 			bss->rsn_ie = NULL;
10834 		}
10835 		if (bss->wpa_ie) {
10836 			MFREE(cfg->osh, bss->wpa_ie, bss->wpa_ie[1]
10837 				+ WPA_RSN_IE_TAG_FIXED_LEN);
10838 			bss->wpa_ie = NULL;
10839 		}
10840 		if (bss->wps_ie) {
10841 			MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
10842 			bss->wps_ie = NULL;
10843 		}
10844 		if (bss->fils_ind_ie) {
10845 			MFREE(cfg->osh, bss->fils_ind_ie, bss->fils_ind_ie[1]
10846 				+ FILS_INDICATION_IE_TAG_FIXED_LEN);
10847 			bss->fils_ind_ie = NULL;
10848 		}
10849 		if (ies->wpa_ie != NULL) {
10850 			/* WPAIE */
10851 			bss->rsn_ie = NULL;
10852 			bss->wpa_ie = MALLOCZ(cfg->osh,
10853 					ies->wpa_ie->length
10854 					+ WPA_RSN_IE_TAG_FIXED_LEN);
10855 			if (bss->wpa_ie) {
10856 				memcpy(bss->wpa_ie, ies->wpa_ie,
10857 					ies->wpa_ie->length
10858 					+ WPA_RSN_IE_TAG_FIXED_LEN);
10859 			}
10860 		} else if (ies->wpa2_ie != NULL) {
10861 			/* RSNIE */
10862 			bss->wpa_ie = NULL;
10863 			bss->rsn_ie = MALLOCZ(cfg->osh,
10864 					ies->wpa2_ie->len
10865 					+ WPA_RSN_IE_TAG_FIXED_LEN);
10866 			if (bss->rsn_ie) {
10867 				memcpy(bss->rsn_ie, ies->wpa2_ie,
10868 					ies->wpa2_ie->len
10869 					+ WPA_RSN_IE_TAG_FIXED_LEN);
10870 			}
10871 		}
10872 #ifdef WL_FILS
10873 		if (ies->fils_ind_ie) {
10874 			bss->fils_ind_ie = MALLOCZ(cfg->osh,
10875 					ies->fils_ind_ie->len
10876 					+ FILS_INDICATION_IE_TAG_FIXED_LEN);
10877 			if (bss->fils_ind_ie) {
10878 				memcpy(bss->fils_ind_ie, ies->fils_ind_ie,
10879 					ies->fils_ind_ie->len
10880 					+ FILS_INDICATION_IE_TAG_FIXED_LEN);
10881 			}
10882 		}
10883 #endif /* WL_FILS */
10884 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10885 		}
10886 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10887 		if (!ies->wpa2_ie && !ies->wpa_ie) {
10888 			wl_validate_opensecurity(dev, bssidx, privacy);
10889 			bss->security_mode = false;
10890 		}
10891 
10892 		if (ies->wps_ie) {
10893 			bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
10894 			if (bss->wps_ie) {
10895 				memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
10896 			}
10897 		}
10898 	}
10899 
10900 	return 0;
10901 
10902 }
10903 
10904 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
wl_cfg80211_bcn_set_params(struct cfg80211_ap_settings * info,struct net_device * dev,u32 dev_role,s32 bssidx)10905 static s32 wl_cfg80211_bcn_set_params(
10906 	struct cfg80211_ap_settings *info,
10907 	struct net_device *dev,
10908 	u32 dev_role, s32 bssidx)
10909 {
10910 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10911 	s32 err = BCME_OK;
10912 
10913 	WL_DBG(("interval (%d) \ndtim_period (%d) \n",
10914 		info->beacon_interval, info->dtim_period));
10915 
10916 	if (info->beacon_interval) {
10917 		if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
10918 			&info->beacon_interval, sizeof(s32))) < 0) {
10919 			WL_ERR(("Beacon Interval Set Error, %d\n", err));
10920 			return err;
10921 		}
10922 	}
10923 
10924 	if (info->dtim_period) {
10925 		if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
10926 			&info->dtim_period, sizeof(s32))) < 0) {
10927 			WL_ERR(("DTIM Interval Set Error, %d\n", err));
10928 			return err;
10929 		}
10930 	}
10931 
10932 	if ((info->ssid) && (info->ssid_len > 0) &&
10933 		(info->ssid_len <= DOT11_MAX_SSID_LEN)) {
10934 		WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
10935 		if (dev_role == NL80211_IFTYPE_AP) {
10936 			/* Store the hostapd SSID */
10937 			bzero(cfg->hostapd_ssid.SSID, DOT11_MAX_SSID_LEN);
10938 			memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
10939 			cfg->hostapd_ssid.SSID_len = (uint32)info->ssid_len;
10940 		} else {
10941 				/* P2P GO */
10942 			bzero(cfg->p2p->ssid.SSID, DOT11_MAX_SSID_LEN);
10943 			memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
10944 			cfg->p2p->ssid.SSID_len = (uint32)info->ssid_len;
10945 		}
10946 	}
10947 
10948 	return err;
10949 }
10950 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
10951 
10952 static s32
wl_cfg80211_parse_ies(const u8 * ptr,u32 len,struct parsed_ies * ies)10953 wl_cfg80211_parse_ies(const u8 *ptr, u32 len, struct parsed_ies *ies)
10954 {
10955 	s32 err = BCME_OK;
10956 
10957 	bzero(ies, sizeof(struct parsed_ies));
10958 
10959 	/* find the WPSIE */
10960 	if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
10961 		WL_DBG(("WPSIE in beacon \n"));
10962 		ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
10963 	} else {
10964 		WL_DBG(("No WPSIE in beacon \n"));
10965 	}
10966 
10967 	/* find the RSN_IE */
10968 	if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len,
10969 		DOT11_MNG_RSN_ID)) != NULL) {
10970 		WL_DBG((" WPA2 IE found\n"));
10971 		ies->wpa2_ie_len = ies->wpa2_ie->len;
10972 	}
10973 
10974 	/* find the FILS_IND_IE */
10975 	if ((ies->fils_ind_ie = bcm_parse_tlvs(ptr, len,
10976 		DOT11_MNG_FILS_IND_ID)) != NULL) {
10977 		WL_DBG((" FILS IND IE found\n"));
10978 		ies->fils_ind_ie_len = ies->fils_ind_ie->len;
10979 	}
10980 
10981 	/* find the WPA_IE */
10982 	if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
10983 		WL_DBG((" WPA found\n"));
10984 		ies->wpa_ie_len = ies->wpa_ie->length;
10985 	}
10986 
10987 	return err;
10988 
10989 }
10990 
10991 static s32
wl_cfg80211_set_ap_role(struct bcm_cfg80211 * cfg,struct net_device * dev)10992 wl_cfg80211_set_ap_role(
10993 	struct bcm_cfg80211 *cfg,
10994 	struct net_device *dev)
10995 {
10996 	s32 err = BCME_OK;
10997 	s32 infra = 1;
10998 	s32 ap = 0;
10999 	s32 pm;
11000 	s32 bssidx;
11001 	s32 apsta = 0;
11002 	bool new_chip;
11003 
11004 	new_chip = wl_new_chip_check(dev);
11005 
11006 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11007 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11008 		return -EINVAL;
11009 	}
11010 
11011 	WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n", dev->name, bssidx));
11012 
11013 	if (bssidx != 0 || new_chip) {
11014 		if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
11015 				WL_IF_TYPE_AP, 0, NULL)) < 0) {
11016 			WL_ERR(("wl add_del_bss returned error:%d\n", err));
11017 			return err;
11018 		}
11019 	}
11020 
11021 	/*
11022 	 * For older chips, "bss" iovar does not support
11023 	 * bsscfg role change/upgradation, and still
11024 	 * return BCME_OK on attempt
11025 	 * Hence, below traditional way to handle the same
11026 	 */
11027 
11028 	if ((err = wldev_ioctl_get(dev,
11029 			WLC_GET_AP, &ap, sizeof(s32))) < 0) {
11030 		WL_ERR(("Getting AP mode failed %d \n", err));
11031 		return err;
11032 	}
11033 
11034 	if (!ap) {
11035 		/* AP mode switch not supported. Try setting up AP explicitly */
11036 		err = wldev_iovar_getint(dev, "apsta", (s32 *)&apsta);
11037 		if (unlikely(err)) {
11038 			WL_ERR(("Could not get apsta %d\n", err));
11039 			return err;
11040 		}
11041 		if (apsta == 0) {
11042 			/* If apsta is not set, set it */
11043 
11044 			/* Check for any connected interfaces before wl down */
11045 			if (wl_get_drv_status_all(cfg, CONNECTED) > 0) {
11046 				WL_ERR(("Concurrent i/f operational. can't do wl down"));
11047 				return BCME_ERROR;
11048 			}
11049 			err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11050 			if (err < 0) {
11051 				WL_ERR(("WLC_DOWN error %d\n", err));
11052 				return err;
11053 			}
11054 			err = wldev_iovar_setint(dev, "apsta", 0);
11055 			if (err < 0) {
11056 				WL_ERR(("wl apsta 0 error %d\n", err));
11057 				return err;
11058 			}
11059 			ap = 1;
11060 			if ((err = wldev_ioctl_set(dev,
11061 					WLC_SET_AP, &ap, sizeof(s32))) < 0) {
11062 				WL_ERR(("setting AP mode failed %d \n", err));
11063 				return err;
11064 			}
11065 		}
11066 	}
11067 	else if (bssidx == 0 && !new_chip && !wl_ext_iapsta_other_if_enabled(dev)) {
11068 		err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11069 		if (err < 0) {
11070 			WL_ERR(("WLC_DOWN error %d\n", err));
11071 			return err;
11072 		}
11073 		err = wldev_iovar_setint(dev, "apsta", 0);
11074 		if (err < 0) {
11075 			WL_ERR(("wl apsta 0 error %d\n", err));
11076 			return err;
11077 		}
11078 		ap = 1;
11079 		if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) < 0) {
11080 			WL_ERR(("setting AP mode failed %d \n", err));
11081 			return err;
11082 		}
11083 	}
11084 
11085 	if (bssidx == 0) {
11086 		pm = 0;
11087 		if ((err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm))) != 0) {
11088 			WL_ERR(("wl PM 0 returned error:%d\n", err));
11089 			/* Ignore error, if any */
11090 			err = BCME_OK;
11091 		}
11092 		err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11093 		if (err < 0) {
11094 			WL_ERR(("SET INFRA error %d\n", err));
11095 			return err;
11096 		}
11097 	}
11098 
11099 	/* On success, mark AP creation in progress. */
11100 	wl_set_drv_status(cfg, AP_CREATING, dev);
11101 	return 0;
11102 }
11103 
11104 /* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
11105 #define MAX_AP_LINK_WAIT_TIME   10000
11106 static s32
wl_cfg80211_bcn_bringup_ap(struct net_device * dev,struct parsed_ies * ies,u32 dev_role,s32 bssidx)11107 wl_cfg80211_bcn_bringup_ap(
11108 	struct net_device *dev,
11109 	struct parsed_ies *ies,
11110 	u32 dev_role, s32 bssidx)
11111 {
11112 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11113 	struct wl_join_params join_params;
11114 	bool is_bssup = false;
11115 	s32 infra = 1;
11116 	s32 join_params_size = 0;
11117 	s32 ap = 1;
11118 	s32 wsec;
11119 #ifdef DISABLE_11H_SOFTAP
11120 	s32 spect = 0;
11121 #endif /* DISABLE_11H_SOFTAP */
11122 #ifdef SOFTAP_UAPSD_OFF
11123 	uint32 wme_apsd = 0;
11124 #endif /* SOFTAP_UAPSD_OFF */
11125 	s32 err = BCME_OK;
11126 	s32 is_rsdb_supported = BCME_ERROR;
11127 	long timeout;
11128 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11129 	char sec[32];
11130 
11131 	is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
11132 	if (is_rsdb_supported < 0)
11133 		return (-ENODEV);
11134 
11135 	WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role, bssidx, dev->name));
11136 
11137 	/* Common code for SoftAP and P2P GO */
11138 	wl_clr_drv_status(cfg, AP_CREATED, dev);
11139 
11140 	/* Make sure INFRA is set for AP/GO */
11141 	err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11142 	if (err < 0) {
11143 		WL_ERR(("SET INFRA error %d\n", err));
11144 		goto exit;
11145 	}
11146 
11147 	/* Do abort scan before creating GO */
11148 	wl_cfg80211_scan_abort(cfg);
11149 
11150 	if (dev_role == NL80211_IFTYPE_P2P_GO) {
11151 		wl_ext_get_sec(dev, 0, sec, sizeof(sec));
11152 		WL_MSG(dev->name, "Creating GO with sec=%s\n", sec);
11153 		is_bssup = wl_cfg80211_bss_isup(dev, bssidx);
11154 		if (!is_bssup && (ies->wpa2_ie != NULL)) {
11155 
11156 			err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid,
11157 				sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
11158 				bssidx, &cfg->ioctl_buf_sync);
11159 			if (err < 0) {
11160 				WL_ERR(("GO SSID setting error %d\n", err));
11161 				goto exit;
11162 			}
11163 
11164 			if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
11165 				WL_ERR(("GO Bring up error %d\n", err));
11166 				goto exit;
11167 			}
11168 		} else
11169 			WL_DBG(("Bss is already up\n"));
11170 	} else if (dev_role == NL80211_IFTYPE_AP) {
11171 
11172 //		if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
11173 			/* Make sure fw is in proper state */
11174 			err = wl_cfg80211_set_ap_role(cfg, dev);
11175 			if (unlikely(err)) {
11176 				WL_ERR(("set ap role failed!\n"));
11177 				goto exit;
11178 			}
11179 //		}
11180 
11181 		/* Device role SoftAP */
11182 		WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
11183 		/* Clear the status bit after use */
11184 		wl_clr_drv_status(cfg, AP_CREATING, dev);
11185 
11186 #ifdef DISABLE_11H_SOFTAP
11187 		if (is_rsdb_supported == 0) {
11188 			err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11189 			if (err < 0) {
11190 				WL_ERR(("WLC_DOWN error %d\n", err));
11191 				goto exit;
11192 			}
11193 		}
11194 		err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT,
11195 			&spect, sizeof(s32));
11196 		if (err < 0) {
11197 			WL_ERR(("SET SPECT_MANAGMENT error %d\n", err));
11198 			goto exit;
11199 		}
11200 #endif /* DISABLE_11H_SOFTAP */
11201 
11202 #ifdef WL_DISABLE_HE_SOFTAP
11203 		err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, FALSE);
11204 		if (err < 0) {
11205 			WL_ERR(("failed to set he features, error=%d\n", err));
11206 		}
11207 #endif /* WL_DISABLE_HE_SOFTAP */
11208 
11209 #ifdef SOFTAP_UAPSD_OFF
11210 		err = wldev_iovar_setbuf_bsscfg(dev, "wme_apsd", &wme_apsd, sizeof(wme_apsd),
11211 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11212 		if (err < 0) {
11213 			WL_ERR(("failed to disable uapsd, error=%d\n", err));
11214 		}
11215 #endif /* SOFTAP_UAPSD_OFF */
11216 
11217 		err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
11218 		if (unlikely(err)) {
11219 			WL_ERR(("WLC_UP error (%d)\n", err));
11220 			goto exit;
11221 		}
11222 
11223 #ifdef MFP
11224 		if (cfg->bip_pos) {
11225 			err = wldev_iovar_setbuf_bsscfg(dev, "bip",
11226 				(const void *)(cfg->bip_pos), WPA_SUITE_LEN, cfg->ioctl_buf,
11227 				WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11228 			if (err < 0) {
11229 				WL_ERR(("bip set error %d\n", err));
11230 				{
11231 					goto exit;
11232 				}
11233 			}
11234 		}
11235 #endif /* MFP */
11236 
11237 		err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec);
11238 		if (unlikely(err)) {
11239 			WL_ERR(("Could not get wsec %d\n", err));
11240 			goto exit;
11241 		}
11242 		if (dhdp->conf->chip == BCM43430_CHIP_ID && bssidx > 0 &&
11243 				(wsec & (TKIP_ENABLED|AES_ENABLED))) {
11244 			wsec |= WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround
11245 			err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
11246 			if (err < 0) {
11247 				WL_ERR(("wsec error %d\n", err));
11248 				goto exit;
11249 			}
11250 		}
11251 		if ((wsec == WEP_ENABLED) && cfg->wep_key.len) {
11252 			WL_DBG(("Applying buffered WEP KEY \n"));
11253 			err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &cfg->wep_key,
11254 				sizeof(struct wl_wsec_key), cfg->ioctl_buf,
11255 				WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
11256 			/* clear the key after use */
11257 			bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
11258 			if (unlikely(err)) {
11259 				WL_ERR(("WLC_SET_KEY error (%d)\n", err));
11260 				goto exit;
11261 			}
11262 		}
11263 
11264 #ifdef MFP
11265 		if (cfg->mfp_mode) {
11266 			/* This needs to go after wsec otherwise the wsec command will
11267 			 * overwrite the values set by MFP
11268 			 */
11269 			err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx);
11270 			if (err < 0) {
11271 				WL_ERR(("MFP Setting failed. ret = %d \n", err));
11272 				/* If fw doesn't support mfp, Ignore the error */
11273 				if (err != BCME_UNSUPPORTED) {
11274 					goto exit;
11275 				}
11276 			}
11277 		}
11278 #endif /* MFP */
11279 
11280 		bzero(&join_params, sizeof(join_params));
11281 		/* join parameters starts with ssid */
11282 		join_params_size = sizeof(join_params.ssid);
11283 		join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
11284 			(uint32)DOT11_MAX_SSID_LEN);
11285 		memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
11286 			join_params.ssid.SSID_len);
11287 		join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
11288 
11289 		wl_ext_get_sec(dev, 0, sec, sizeof(sec));
11290 		WL_MSG(dev->name, "Creating AP with sec=%s\n", sec);
11291 		/* create softap */
11292 		if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
11293 			join_params_size)) != 0) {
11294 			WL_ERR(("SoftAP/GO set ssid failed! \n"));
11295 			goto exit;
11296 		} else {
11297 			WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
11298 		}
11299 
11300 		if (bssidx != 0) {
11301 			/* AP on Virtual Interface */
11302 			if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
11303 				WL_ERR(("AP Bring up error %d\n", err));
11304 				goto exit;
11305 			}
11306 		}
11307 
11308 	} else {
11309 		WL_ERR(("Wrong interface type %d\n", dev_role));
11310 		goto exit;
11311 	}
11312 
11313 	/* Wait for Linkup event to mark successful AP/GO bring up */
11314 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
11315 		wl_get_drv_status(cfg, AP_CREATED, dev), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
11316 	if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) {
11317 		WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
11318 		if (timeout == -ERESTARTSYS) {
11319 			WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
11320 			err = -ERESTARTSYS;
11321 			goto exit;
11322 		}
11323 		if (dhd_query_bus_erros(dhdp)) {
11324 			err = -ENODEV;
11325 			goto exit;
11326 		}
11327 		dhdp->iface_op_failed = TRUE;
11328 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
11329 		if (dhdp->memdump_enabled) {
11330 			dhdp->memdump_type = DUMP_TYPE_AP_LINKUP_FAILURE;
11331 			dhd_bus_mem_dump(dhdp);
11332 		}
11333 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
11334 		err = -ENODEV;
11335 		goto exit;
11336 	}
11337 	SUPP_LOG(("AP/GO Link up\n"));
11338 
11339 exit:
11340 	if (cfg->wep_key.len) {
11341 		bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
11342 	}
11343 
11344 #ifdef MFP
11345 	if (cfg->mfp_mode) {
11346 		cfg->mfp_mode = 0;
11347 	}
11348 
11349 	if (cfg->bip_pos) {
11350 		cfg->bip_pos = NULL;
11351 	}
11352 #endif /* MFP */
11353 
11354 	if (err) {
11355 		SUPP_LOG(("AP/GO bring up fail. err:%d\n", err));
11356 	}
11357 	return err;
11358 }
11359 
11360 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11361 s32
wl_cfg80211_parse_ap_ies(struct net_device * dev,struct cfg80211_beacon_data * info,struct parsed_ies * ies)11362 wl_cfg80211_parse_ap_ies(
11363 	struct net_device *dev,
11364 	struct cfg80211_beacon_data *info,
11365 	struct parsed_ies *ies)
11366 {
11367 	struct parsed_ies prb_ies;
11368 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11369 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11370 	const u8 *vndr = NULL;
11371 	u32 vndr_ie_len = 0;
11372 	s32 err = BCME_OK;
11373 
11374 	/* Parse Beacon IEs */
11375 	if (wl_cfg80211_parse_ies((const u8 *)info->tail,
11376 		info->tail_len, ies) < 0) {
11377 		WL_ERR(("Beacon get IEs failed \n"));
11378 		err = -EINVAL;
11379 		goto fail;
11380 	}
11381 
11382 	vndr = (const u8 *)info->proberesp_ies;
11383 	vndr_ie_len = (uint32)info->proberesp_ies_len;
11384 
11385 	if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
11386 		/* SoftAP mode */
11387 		const struct ieee80211_mgmt *mgmt;
11388 		mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
11389 		if (mgmt != NULL) {
11390 			vndr = (const u8 *)&mgmt->u.probe_resp.variable;
11391 			vndr_ie_len = (uint32)(info->probe_resp_len -
11392 				offsetof(const struct ieee80211_mgmt, u.probe_resp.variable));
11393 		}
11394 	}
11395 	/* Parse Probe Response IEs */
11396 	if (wl_cfg80211_parse_ies((const u8 *)vndr, vndr_ie_len, &prb_ies) < 0) {
11397 		WL_ERR(("PROBE RESP get IEs failed \n"));
11398 		err = -EINVAL;
11399 	}
11400 fail:
11401 
11402 	return err;
11403 }
11404 
11405 s32
wl_cfg80211_set_ies(struct net_device * dev,struct cfg80211_beacon_data * info,s32 bssidx)11406 wl_cfg80211_set_ies(
11407 	struct net_device *dev,
11408 	struct cfg80211_beacon_data *info,
11409 	s32 bssidx)
11410 {
11411 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11412 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11413 	const u8 *vndr = NULL;
11414 	u32 vndr_ie_len = 0;
11415 	s32 err = BCME_OK;
11416 
11417 	/* Set Beacon IEs to FW */
11418 	if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
11419 		VNDR_IE_BEACON_FLAG, (const u8 *)info->tail,
11420 		info->tail_len)) < 0) {
11421 		WL_ERR(("Set Beacon IE Failed \n"));
11422 	} else {
11423 		WL_DBG(("Applied Vndr IEs for Beacon \n"));
11424 	}
11425 
11426 	vndr = (const u8 *)info->proberesp_ies;
11427 	vndr_ie_len = (uint32)info->proberesp_ies_len;
11428 
11429 	if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
11430 		/* SoftAP mode */
11431 		const struct ieee80211_mgmt *mgmt;
11432 		mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
11433 		if (mgmt != NULL) {
11434 			vndr = (const u8 *)&mgmt->u.probe_resp.variable;
11435 			vndr_ie_len = (uint32)(info->probe_resp_len -
11436 				offsetof(struct ieee80211_mgmt, u.probe_resp.variable));
11437 		}
11438 	}
11439 
11440 	/* Set Probe Response IEs to FW */
11441 	if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
11442 		VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
11443 		WL_ERR(("Set Probe Resp IE Failed \n"));
11444 	} else {
11445 		WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
11446 	}
11447 
11448 	return err;
11449 }
11450 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11451 
wl_cfg80211_hostapd_sec(struct net_device * dev,struct parsed_ies * ies,s32 bssidx)11452 static s32 wl_cfg80211_hostapd_sec(
11453 	struct net_device *dev,
11454 	struct parsed_ies *ies,
11455 	s32 bssidx)
11456 {
11457 	bool update_bss = 0;
11458 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11459 	wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
11460 
11461 	if (!bss) {
11462 		WL_ERR(("cfgbss is NULL \n"));
11463 		return -EINVAL;
11464 	}
11465 
11466 	if (ies->wps_ie) {
11467 		if (bss->wps_ie &&
11468 			memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
11469 			WL_DBG((" WPS IE is changed\n"));
11470 			MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
11471 			bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11472 			if (bss->wps_ie) {
11473 				memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11474 			}
11475 		} else if (bss->wps_ie == NULL) {
11476 			WL_DBG((" WPS IE is added\n"));
11477 			bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11478 			if (bss->wps_ie) {
11479 				memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11480 			}
11481 		}
11482 
11483 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11484 		if (ies->wpa_ie != NULL && ies->wpa2_ie != NULL) {
11485 			WL_ERR(("update bss - wpa_ie and  wpa2_ie is not null\n"));
11486 			if (!bss->security_mode) {
11487 				/* change from open mode to security mode */
11488 				update_bss = true;
11489 				bss->wpa_ie = MALLOCZ(cfg->osh,
11490 					ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11491 				if (bss->wpa_ie) {
11492 					memcpy(bss->wpa_ie, ies->wpa_ie,
11493 						ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11494 				}
11495 				bss->rsn_ie = MALLOCZ(cfg->osh,
11496 						ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11497 				if (bss->rsn_ie) {
11498 					memcpy(bss->rsn_ie, ies->wpa2_ie,
11499 						ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11500 				}
11501 			} else {
11502 				/* change from (WPA or WPA2 or WPA/WPA2) to WPA/WPA2 mixed mode */
11503 				if (bss->wpa_ie) {
11504 					if (memcmp(bss->wpa_ie,
11505 					ies->wpa_ie, ies->wpa_ie->length +
11506 					WPA_RSN_IE_TAG_FIXED_LEN)) {
11507 						MFREE(cfg->osh, bss->wpa_ie,
11508 							bss->wpa_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11509 						update_bss = true;
11510 						bss->wpa_ie = MALLOCZ(cfg->osh,
11511 							ies->wpa_ie->length
11512 							+ WPA_RSN_IE_TAG_FIXED_LEN);
11513 						if (bss->wpa_ie) {
11514 							memcpy(bss->wpa_ie, ies->wpa_ie,
11515 								ies->wpa_ie->length
11516 								+ WPA_RSN_IE_TAG_FIXED_LEN);
11517 						}
11518 					}
11519 				}
11520 				else {
11521 					update_bss = true;
11522 					bss->wpa_ie = MALLOCZ(cfg->osh,
11523 						ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11524 					if (bss->wpa_ie) {
11525 						memcpy(bss->wpa_ie, ies->wpa_ie,
11526 							ies->wpa_ie->length
11527 							+ WPA_RSN_IE_TAG_FIXED_LEN);
11528 					}
11529 				}
11530 				if (bss->rsn_ie) {
11531 					if (memcmp(bss->rsn_ie,
11532 					ies->wpa2_ie,
11533 					ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
11534 						update_bss = true;
11535 						MFREE(cfg->osh, bss->rsn_ie,
11536 							bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11537 						bss->rsn_ie = MALLOCZ(cfg->osh,
11538 							ies->wpa2_ie->len
11539 							+ WPA_RSN_IE_TAG_FIXED_LEN);
11540 						if (bss->rsn_ie) {
11541 							memcpy(bss->rsn_ie, ies->wpa2_ie,
11542 								ies->wpa2_ie->len
11543 								+ WPA_RSN_IE_TAG_FIXED_LEN);
11544 						}
11545 					}
11546 				}
11547 				else {
11548 					update_bss = true;
11549 					bss->rsn_ie = MALLOCZ(cfg->osh,
11550 						ies->wpa2_ie->len
11551 						+ WPA_RSN_IE_TAG_FIXED_LEN);
11552 					if (bss->rsn_ie) {
11553 						memcpy(bss->rsn_ie, ies->wpa2_ie,
11554 							ies->wpa2_ie->len
11555 							+ WPA_RSN_IE_TAG_FIXED_LEN);
11556 					}
11557 				}
11558 			}
11559 			WL_ERR(("update_bss=%d\n", update_bss));
11560 			if (update_bss) {
11561 				bss->security_mode = true;
11562 				wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11563 				if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie,
11564 					ies->wpa2_ie, bssidx)  < 0) {
11565 					return BCME_ERROR;
11566 				}
11567 				wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11568 			}
11569 
11570 		}
11571 		else
11572 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11573 		if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
11574 			if (!bss->security_mode) {
11575 				/* change from open mode to security mode */
11576 				update_bss = true;
11577 				if (ies->wpa_ie != NULL) {
11578 					bss->wpa_ie = MALLOCZ(cfg->osh,
11579 						ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11580 					if (bss->wpa_ie) {
11581 						memcpy(bss->wpa_ie,
11582 							ies->wpa_ie,
11583 							ies->wpa_ie->length
11584 							+ WPA_RSN_IE_TAG_FIXED_LEN);
11585 					}
11586 				} else {
11587 					bss->rsn_ie = MALLOCZ(cfg->osh,
11588 						ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11589 					if (bss->rsn_ie) {
11590 						memcpy(bss->rsn_ie,
11591 							ies->wpa2_ie,
11592 							ies->wpa2_ie->len
11593 							+ WPA_RSN_IE_TAG_FIXED_LEN);
11594 					}
11595 				}
11596 			} else if (bss->wpa_ie) {
11597 				/* change from WPA2 mode to WPA mode */
11598 				if (ies->wpa_ie != NULL) {
11599 					update_bss = true;
11600 					MFREE(cfg->osh, bss->rsn_ie,
11601 						bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11602 					bss->rsn_ie = NULL;
11603 					bss->wpa_ie = MALLOCZ(cfg->osh,
11604 						ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11605 					if (bss->wpa_ie) {
11606 						memcpy(bss->wpa_ie,
11607 							ies->wpa_ie,
11608 							ies->wpa_ie->length
11609 							+ WPA_RSN_IE_TAG_FIXED_LEN);
11610 					}
11611 				} else if (memcmp(bss->rsn_ie,
11612 					ies->wpa2_ie, ies->wpa2_ie->len
11613 					+ WPA_RSN_IE_TAG_FIXED_LEN)) {
11614 					update_bss = true;
11615 					MFREE(cfg->osh, bss->rsn_ie,
11616 						bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11617 					bss->rsn_ie = MALLOCZ(cfg->osh,
11618 						ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11619 					if (bss->rsn_ie) {
11620 						memcpy(bss->rsn_ie,
11621 							ies->wpa2_ie,
11622 							ies->wpa2_ie->len
11623 							+ WPA_RSN_IE_TAG_FIXED_LEN);
11624 					}
11625 					bss->wpa_ie = NULL;
11626 				}
11627 			}
11628 			if (update_bss) {
11629 				bss->security_mode = true;
11630 				wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11631 				if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx)  < 0 ||
11632 					wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
11633 					return BCME_ERROR;
11634 				}
11635 				wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11636 			}
11637 		}
11638 	} else {
11639 		WL_ERR(("No WPSIE in beacon \n"));
11640 	}
11641 	return 0;
11642 }
11643 
11644 static s32
11645 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
11646 	2, 0))
11647 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
wl_cfg80211_del_station(struct wiphy * wiphy,struct net_device * ndev,struct station_del_parameters * params)11648 wl_cfg80211_del_station(
11649 		struct wiphy *wiphy, struct net_device *ndev,
11650 		struct station_del_parameters *params)
11651 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
11652 wl_cfg80211_del_station(
11653 	struct wiphy *wiphy,
11654 	struct net_device *ndev,
11655 	const u8* mac_addr)
11656 #else
11657 wl_cfg80211_del_station(
11658 	struct wiphy *wiphy,
11659 	struct net_device *ndev,
11660 	u8* mac_addr)
11661 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11662 {
11663 	struct net_device *dev;
11664 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11665 	scb_val_t scb_val;
11666 	int err;
11667 	char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
11668 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
11669 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
11670 	int num_associated = 0;
11671 
11672 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11673 	const u8 *mac_addr = params->mac;
11674 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11675 	u16 rc = params->reason_code;
11676 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11677 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11678 
11679 	WL_DBG(("Entry\n"));
11680 	if (mac_addr == NULL) {
11681 		WL_DBG(("mac_addr is NULL ignore it\n"));
11682 		return 0;
11683 	}
11684 
11685 	dev = ndev_to_wlc_ndev(ndev, cfg);
11686 
11687 	if (p2p_is_on(cfg)) {
11688 		/* Suspend P2P discovery search-listen to prevent it from changing the
11689 		 * channel.
11690 		 */
11691 		if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
11692 			WL_ERR(("Can not disable discovery mode\n"));
11693 			return -EFAULT;
11694 		}
11695 	}
11696 	err = wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
11697 		WL_EXT_STATUS_DELETE_STA, (void *)mac_addr);
11698 	if (err) {
11699 		return 0;
11700 	}
11701 
11702 	assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
11703 	err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
11704 		assoc_maclist, sizeof(mac_buf));
11705 	if (err < 0)
11706 		WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
11707 	else
11708 		num_associated = assoc_maclist->count;
11709 
11710 	memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
11711 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11712 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11713 	if (rc == DOT11_RC_8021X_AUTH_FAIL) {
11714 		WL_ERR(("deauth will be sent at F/W\n"));
11715 		scb_val.val = DOT11_RC_8021X_AUTH_FAIL;
11716 	} else {
11717 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11718 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11719 
11720 #ifdef WL_WPS_SYNC
11721 		if (wl_wps_session_update(ndev,
11722 			WPS_STATE_DISCONNECT_CLIENT, mac_addr) == BCME_UNSUPPORTED) {
11723 			/* Ignore disconnect command from upper layer */
11724 			WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
11725 		} else
11726 #endif /* WL_WPS_SYNC */
11727 		{
11728 			scb_val.val = DOT11_RC_DEAUTH_LEAVING;
11729 			WL_MSG(dev->name, "Disconnect STA : %pM scb_val.val %d\n",
11730 				mac_addr, scb_val.val);
11731 			/* need to guarantee EAP-Failure send out before deauth */
11732 			dhd_wait_pend8021x(dev);
11733 			err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
11734 				sizeof(scb_val_t));
11735 			if (err < 0) {
11736 				WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
11737 			}
11738 		}
11739 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11740 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11741 	}
11742 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11743 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11744 
11745 	if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
11746 		wl_delay(400);
11747 
11748 	return 0;
11749 }
11750 
11751 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
11752 static s32
wl_cfg80211_change_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)11753 wl_cfg80211_change_station(
11754 	struct wiphy *wiphy,
11755 	struct net_device *dev,
11756 	const u8 *mac,
11757 	struct station_parameters *params)
11758 #else
11759 static s32
11760 wl_cfg80211_change_station(
11761 	struct wiphy *wiphy,
11762 	struct net_device *dev,
11763 	u8 *mac,
11764 	struct station_parameters *params)
11765 #endif // endif
11766 {
11767 	int err = BCME_OK;
11768 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11769 	struct net_device *ndev = ndev_to_wlc_ndev(dev, cfg);
11770 
11771 	WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x "
11772 				"sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac),
11773 				params->sta_flags_mask, params->sta_flags_set, ndev->name));
11774 
11775 	if ((wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS) &&
11776 		!(wl_get_drv_status(cfg, CONNECTED, dev))) {
11777 		/* Return error indicating not in connected state */
11778 		WL_ERR(("Ignore SCB_AUTHORIZE/DEAUTHORIZE in non connected state\n"));
11779 		return -ENOTSUPP;
11780 	}
11781 
11782 	/* Processing only authorize/de-authorize flag for now */
11783 	if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
11784 		WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
11785 		return -ENOTSUPP;
11786 	}
11787 
11788 	if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
11789 		err = wldev_ioctl_set(ndev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN);
11790 		if (unlikely(err)) {
11791 			WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
11792 		} else {
11793 			WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG "\n",
11794 				ndev->name, MAC2STRDBG(mac)));
11795 		}
11796 		return err;
11797 	}
11798 
11799 	err = wldev_ioctl_set(ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN);
11800 	if (unlikely(err)) {
11801 		WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
11802 	} else {
11803 		WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG "\n",
11804 			ndev->name, MAC2STRDBG(mac)));
11805 #ifdef WL_WPS_SYNC
11806 		wl_wps_session_update(ndev, WPS_STATE_AUTHORIZE, mac);
11807 #endif /* WL_WPS_SYNC */
11808 	}
11809 #ifdef DHD_LOSSLESS_ROAMING
11810 	wl_del_roam_timeout(cfg);
11811 #endif // endif
11812 
11813 	return err;
11814 }
11815 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
11816 
11817 static s32
wl_cfg80211_set_scb_timings(struct bcm_cfg80211 * cfg,struct net_device * dev)11818 wl_cfg80211_set_scb_timings(
11819 	struct bcm_cfg80211 *cfg,
11820 	struct net_device *dev)
11821 {
11822 	int err;
11823 	u32 ps_pretend;
11824 	wl_scb_probe_t scb_probe;
11825 	u32 ps_pretend_retries;
11826 
11827 	bzero(&scb_probe, sizeof(wl_scb_probe_t));
11828 	scb_probe.scb_timeout = WL_SCB_TIMEOUT;
11829 	scb_probe.scb_activity_time = WL_SCB_ACTIVITY_TIME;
11830 	scb_probe.scb_max_probe = WL_SCB_MAX_PROBE;
11831 	err = wldev_iovar_setbuf(dev, "scb_probe", (void *)&scb_probe,
11832 		sizeof(wl_scb_probe_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
11833 		&cfg->ioctl_buf_sync);
11834 	if (unlikely(err)) {
11835 		WL_ERR(("set 'scb_probe' failed, error = %d\n", err));
11836 		return err;
11837 	}
11838 
11839 	ps_pretend_retries = WL_PSPRETEND_RETRY_LIMIT;
11840 	err = wldev_iovar_setint(dev, "pspretend_retry_limit", ps_pretend_retries);
11841 	if (unlikely(err)) {
11842 		if (err == BCME_UNSUPPORTED) {
11843 			/* Ignore error if fw doesn't support the iovar */
11844 			WL_DBG(("set 'pspretend_retry_limit %d' failed, error = %d\n",
11845 				ps_pretend_retries, err));
11846 		} else {
11847 			WL_ERR(("set 'pspretend_retry_limit %d' failed, error = %d\n",
11848 				ps_pretend_retries, err));
11849 			return err;
11850 		}
11851 	}
11852 
11853 	ps_pretend = MAX(WL_SCB_MAX_PROBE / 2, WL_MIN_PSPRETEND_THRESHOLD);
11854 	err = wldev_iovar_setint(dev, "pspretend_threshold", ps_pretend);
11855 	if (unlikely(err)) {
11856 		if (err == BCME_UNSUPPORTED) {
11857 			/* Ignore error if fw doesn't support the iovar */
11858 			WL_DBG(("wl pspretend_threshold %d set error %d\n",
11859 				ps_pretend, err));
11860 		} else {
11861 			WL_ERR(("wl pspretend_threshold %d set error %d\n",
11862 				ps_pretend, err));
11863 			return err;
11864 		}
11865 	}
11866 
11867 	return 0;
11868 }
11869 
11870 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11871 static s32
wl_cfg80211_start_ap(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ap_settings * info)11872 wl_cfg80211_start_ap(
11873 	struct wiphy *wiphy,
11874 	struct net_device *dev,
11875 	struct cfg80211_ap_settings *info)
11876 {
11877 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11878 	s32 err = BCME_OK;
11879 	struct parsed_ies ies;
11880 	s32 bssidx = 0;
11881 	u32 dev_role = 0;
11882 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11883 
11884 	WL_DBG(("Enter \n"));
11885 
11886 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11887 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11888 		return BCME_ERROR;
11889 	}
11890 
11891 	if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
11892 		dev_role = NL80211_IFTYPE_P2P_GO;
11893 	} else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
11894 		dev_role = NL80211_IFTYPE_AP;
11895 		dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
11896 		err = dhd_ndo_enable(dhd, FALSE);
11897 		WL_DBG(("Disabling NDO on Hostapd mode %d\n", err));
11898 		if (err) {
11899 			WL_ERR(("Disabling NDO Failed %d\n", err));
11900 		}
11901 #ifdef WL_EXT_IAPSTA
11902 		wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev), WL_IF_TYPE_AP);
11903 #endif /* WL_EXT_IAPSTA */
11904 #ifdef PKT_FILTER_SUPPORT
11905 		/* Disable packet filter */
11906 		if (dhd->early_suspended) {
11907 			WL_ERR(("Disable pkt_filter\n"));
11908 			dhd_enable_packet_filter(0, dhd);
11909 #ifdef APF
11910 			dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd));
11911 #endif /* APF */
11912 		}
11913 #endif /* PKT_FILTER_SUPPORT */
11914 #ifdef ARP_OFFLOAD_SUPPORT
11915 		/* IF SoftAP is enabled, disable arpoe */
11916 		if (dhd->op_mode & DHD_FLAG_STA_MODE) {
11917 			dhd_arp_offload_set(dhd, 0);
11918 			dhd_arp_offload_enable(dhd, FALSE);
11919 		}
11920 #endif /* ARP_OFFLOAD_SUPPORT */
11921 	} else {
11922 		/* only AP or GO role need to be handled here. */
11923 		err = -EINVAL;
11924 		goto fail;
11925 	}
11926 
11927 	/* disable TDLS */
11928 #ifdef WLTDLS
11929 	if (bssidx == 0) {
11930 		/* Disable TDLS for primary Iface. For virtual interface,
11931 		 * tdls disable will happen from interface create context
11932 		 */
11933 		wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_CREATE, false);
11934 	}
11935 #endif /*  WLTDLS */
11936 
11937 	if (!check_dev_role_integrity(cfg, dev_role)) {
11938 		err = -EINVAL;
11939 		goto fail;
11940 	}
11941 
11942 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
11943 	if (!dev->ieee80211_ptr->preset_chandef.chan) {
11944 		WL_ERR(("chan is NULL\n"));
11945 		err = -EINVAL;
11946 		goto fail;
11947 	}
11948 	if ((err = wl_cfg80211_set_channel(wiphy, dev,
11949 		dev->ieee80211_ptr->preset_chandef.chan,
11950 		NL80211_CHAN_HT20) < 0)) {
11951 		WL_ERR(("Set channel failed \n"));
11952 		goto fail;
11953 	}
11954 #endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
11955 
11956 	if ((err = wl_cfg80211_bcn_set_params(info, dev,
11957 		dev_role, bssidx)) < 0) {
11958 		WL_ERR(("Beacon params set failed \n"));
11959 		goto fail;
11960 	}
11961 
11962 	/* Parse IEs */
11963 	if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) {
11964 		WL_ERR(("Set IEs failed \n"));
11965 		goto fail;
11966 	}
11967 
11968 	if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies,
11969 		dev_role, bssidx, info->privacy)) < 0)
11970 	{
11971 		WL_ERR(("Beacon set security failed \n"));
11972 		goto fail;
11973 	}
11974 
11975 	if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies,
11976 		dev_role, bssidx)) < 0) {
11977 		WL_ERR(("Beacon bring up AP/GO failed \n"));
11978 		goto fail;
11979 	}
11980 
11981 	/* Set GC/STA SCB expiry timings. */
11982 	if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
11983 		WL_ERR(("scb setting failed \n"));
11984 //		goto fail;
11985 	}
11986 
11987 	wl_set_drv_status(cfg, CONNECTED, dev);
11988 	WL_DBG(("** AP/GO Created **\n"));
11989 
11990 #ifdef WL_CFG80211_ACL
11991 	/* Enfoce Admission Control. */
11992 	if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
11993 		WL_ERR(("Set ACL failed\n"));
11994 	}
11995 #endif /* WL_CFG80211_ACL */
11996 
11997 	/* Set IEs to FW */
11998 	if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
11999 		WL_ERR(("Set IEs failed \n"));
12000 
12001 #ifdef WLDWDS
12002 	if (dev->ieee80211_ptr->use_4addr) {
12003 		if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12004 				VNDR_IE_ASSOCRSP_FLAG, (const u8 *)info->beacon.assocresp_ies,
12005 				info->beacon.assocresp_ies_len)) < 0) {
12006 			WL_ERR(("Set ASSOC RESP IE Failed\n"));
12007 		}
12008 	}
12009 #endif /* WLDWDS */
12010 
12011 	/* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12012 	if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
12013 		bool pbc = 0;
12014 		wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12015 		if (pbc) {
12016 			WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
12017 			wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12018 		}
12019 	}
12020 
12021 	/* Configure hidden SSID */
12022 	if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) {
12023 		if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
12024 			WL_ERR(("failed to set hidden : %d\n", err));
12025 		WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
12026 	}
12027 
12028 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12029 	if (dev_role == NL80211_IFTYPE_AP) {
12030 		if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
12031 			wl_cfg80211_init_ap_rps(cfg);
12032 		} else {
12033 			WL_ERR(("Set rpsnoa failed \n"));
12034 		}
12035 	}
12036 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12037 fail:
12038 	if (err) {
12039 		WL_ERR(("ADD/SET beacon failed\n"));
12040 		wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12041 		wl_cfg80211_stop_ap(wiphy, dev);
12042 		if (dev_role == NL80211_IFTYPE_AP) {
12043 #ifdef WL_EXT_IAPSTA
12044 		if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12045 #endif /* WL_EXT_IAPSTA */
12046 			dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12047 #ifdef PKT_FILTER_SUPPORT
12048 			/* Enable packet filter */
12049 			if (dhd->early_suspended) {
12050 				WL_ERR(("Enable pkt_filter\n"));
12051 				dhd_enable_packet_filter(1, dhd);
12052 #ifdef APF
12053 				dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd));
12054 #endif /* APF */
12055 			}
12056 #endif /* PKT_FILTER_SUPPORT */
12057 #ifdef ARP_OFFLOAD_SUPPORT
12058 			/* IF SoftAP is disabled, enable arpoe back for STA mode. */
12059 			if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12060 				dhd_arp_offload_set(dhd, dhd_arp_mode);
12061 				dhd_arp_offload_enable(dhd, TRUE);
12062 			}
12063 #endif /* ARP_OFFLOAD_SUPPORT */
12064 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12065 			wl_cfg80211_set_frameburst(cfg, TRUE);
12066 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12067 #ifdef WL_EXT_IAPSTA
12068 		}
12069 #endif /* WL_EXT_IAPSTA */
12070 		}
12071 #ifdef WLTDLS
12072 		if (bssidx == 0) {
12073 			/* Since AP creation failed, re-enable TDLS */
12074 			wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
12075 		}
12076 #endif /*  WLTDLS */
12077 
12078 	}
12079 
12080 	return err;
12081 }
12082 
12083 static s32
wl_cfg80211_stop_ap(struct wiphy * wiphy,struct net_device * dev)12084 wl_cfg80211_stop_ap(
12085 	struct wiphy *wiphy,
12086 	struct net_device *dev)
12087 {
12088 	int err = 0;
12089 	u32 dev_role = 0;
12090 	int ap = 0;
12091 	s32 bssidx = 0;
12092 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12093 	s32 is_rsdb_supported = BCME_ERROR;
12094 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12095 
12096 	WL_DBG(("Enter \n"));
12097 
12098 	if (wl_cfg80211_get_bus_state(cfg)) {
12099 		/* since bus is down, iovar will fail. recovery path will bringup the bus. */
12100 		WL_ERR(("bus is not ready\n"));
12101 		return BCME_OK;
12102 	}
12103 	is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
12104 	if (is_rsdb_supported < 0)
12105 		return (-ENODEV);
12106 
12107 	wl_clr_drv_status(cfg, AP_CREATING, dev);
12108 	wl_clr_drv_status(cfg, AP_CREATED, dev);
12109 	cfg->ap_oper_channel = 0;
12110 
12111 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12112 		dev_role = NL80211_IFTYPE_AP;
12113 		WL_DBG(("stopping AP operation\n"));
12114 	} else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12115 		dev_role = NL80211_IFTYPE_P2P_GO;
12116 		WL_DBG(("stopping P2P GO operation\n"));
12117 	} else {
12118 		WL_ERR(("no AP/P2P GO interface is operational.\n"));
12119 		return -EINVAL;
12120 	}
12121 
12122 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12123 		WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12124 		return BCME_ERROR;
12125 	}
12126 
12127 	if (!check_dev_role_integrity(cfg, dev_role)) {
12128 		WL_ERR(("role integrity check failed \n"));
12129 		err = -EINVAL;
12130 		goto exit;
12131 	}
12132 
12133 	/* Free up resources */
12134 	wl_cfg80211_cleanup_if(dev);
12135 
12136 	/* Clear AP/GO connected status */
12137 	wl_clr_drv_status(cfg, CONNECTED, dev);
12138 	if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
12139 		WL_ERR(("bss down error %d\n", err));
12140 	}
12141 
12142 	if (dev_role == NL80211_IFTYPE_AP) {
12143 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12144 		wl_cfg80211_set_frameburst(cfg, TRUE);
12145 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12146 #ifdef PKT_FILTER_SUPPORT
12147 		/* Enable packet filter */
12148 		if (dhd->early_suspended) {
12149 			WL_ERR(("Enable pkt_filter\n"));
12150 			dhd_enable_packet_filter(1, dhd);
12151 #ifdef APF
12152 			dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd));
12153 #endif /* APF */
12154 		}
12155 #endif /* PKT_FILTER_SUPPORT */
12156 #ifdef ARP_OFFLOAD_SUPPORT
12157 		/* IF SoftAP is disabled, enable arpoe back for STA mode. */
12158 		if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12159 			dhd_arp_offload_set(dhd, dhd_arp_mode);
12160 			dhd_arp_offload_enable(dhd, TRUE);
12161 		}
12162 #endif /* ARP_OFFLOAD_SUPPORT */
12163 
12164 		if (is_rsdb_supported == 0) {
12165 			/* For non-rsdb chips, we use stand alone AP. Do wl down on stop AP */
12166 			err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
12167 			if (unlikely(err)) {
12168 				WL_ERR(("WLC_UP error (%d)\n", err));
12169 				err = -EINVAL;
12170 				goto exit;
12171 			}
12172 		}
12173 
12174 #ifdef WL_DISABLE_HE_SOFTAP
12175 		if (wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, TRUE) != BCME_OK) {
12176 			WL_ERR(("failed to set he features\n"));
12177 		}
12178 #endif /* WL_DISABLE_HE_SOFTAP */
12179 
12180 		wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
12181 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12182 		if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
12183 			wl_cfg80211_init_ap_rps(cfg);
12184 		} else {
12185 			WL_ERR(("Set rpsnoa failed \n"));
12186 		}
12187 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12188 	} else {
12189 		WL_DBG(("Stopping P2P GO \n"));
12190 		DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
12191 			DHD_EVENT_TIMEOUT_MS*3);
12192 		DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub));
12193 	}
12194 
12195 	SUPP_LOG(("AP/GO Link down\n"));
12196 exit:
12197 	if (err) {
12198 		/* In case of failure, flush fw logs */
12199 		wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12200 		SUPP_LOG(("AP/GO Link down fail. err:%d\n", err));
12201 	}
12202 #ifdef WLTDLS
12203 	if (bssidx == 0) {
12204 		/* re-enable TDLS if the number of connected interfaces is less than 2 */
12205 		wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
12206 	}
12207 #endif /* WLTDLS */
12208 
12209 	if (dev_role == NL80211_IFTYPE_AP) {
12210 #ifdef WL_EXT_IAPSTA
12211 		if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12212 #endif /* WL_EXT_IAPSTA */
12213 		/* clear the AP mode */
12214 		dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12215 #ifdef WL_EXT_IAPSTA
12216 		}
12217 #endif /* WL_EXT_IAPSTA */
12218 	}
12219 	return err;
12220 }
12221 
12222 static s32
wl_cfg80211_change_beacon(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_beacon_data * info)12223 wl_cfg80211_change_beacon(
12224 	struct wiphy *wiphy,
12225 	struct net_device *dev,
12226 	struct cfg80211_beacon_data *info)
12227 {
12228 	s32 err = BCME_OK;
12229 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12230 	struct parsed_ies ies;
12231 	u32 dev_role = 0;
12232 	s32 bssidx = 0;
12233 	bool pbc = 0;
12234 
12235 	WL_DBG(("Enter \n"));
12236 
12237 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12238 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12239 		return BCME_ERROR;
12240 	}
12241 
12242 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12243 		dev_role = NL80211_IFTYPE_P2P_GO;
12244 	} else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12245 		dev_role = NL80211_IFTYPE_AP;
12246 	} else {
12247 		err = -EINVAL;
12248 		goto fail;
12249 	}
12250 
12251 	if (!check_dev_role_integrity(cfg, dev_role)) {
12252 		err = -EINVAL;
12253 		goto fail;
12254 	}
12255 
12256 	if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
12257 		WL_ERR(("P2P already down status!\n"));
12258 		err = BCME_ERROR;
12259 		goto fail;
12260 	}
12261 
12262 	/* Parse IEs */
12263 	if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) {
12264 		WL_ERR(("Parse IEs failed \n"));
12265 		goto fail;
12266 	}
12267 
12268 	/* Set IEs to FW */
12269 	if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
12270 		WL_ERR(("Set IEs failed \n"));
12271 		goto fail;
12272 	}
12273 
12274 	if (dev_role == NL80211_IFTYPE_AP) {
12275 		if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
12276 			WL_ERR(("Hostapd update sec failed \n"));
12277 			err = -EINVAL;
12278 			goto fail;
12279 		}
12280 		/* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12281 		if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
12282 			wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12283 			WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
12284 			if (pbc)
12285 				wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12286 			else
12287 				wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
12288 		}
12289 	}
12290 
12291 fail:
12292 	if (err) {
12293 		wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12294 	}
12295 	return err;
12296 }
12297 #else
12298 static s32
wl_cfg80211_add_set_beacon(struct wiphy * wiphy,struct net_device * dev,struct beacon_parameters * info)12299 wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
12300 	struct beacon_parameters *info)
12301 {
12302 	s32 err = BCME_OK;
12303 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12304 	s32 ie_offset = 0;
12305 	s32 bssidx = 0;
12306 	u32 dev_role = NL80211_IFTYPE_AP;
12307 	struct parsed_ies ies;
12308 	bcm_tlv_t *ssid_ie;
12309 	bool pbc = 0;
12310 	bool privacy;
12311 	bool is_bss_up = 0;
12312 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12313 
12314 	WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
12315 		info->interval, info->dtim_period, info->head_len, info->tail_len));
12316 
12317 	if (dev == bcmcfg_to_prmry_ndev(cfg)) {
12318 		dev_role = NL80211_IFTYPE_AP;
12319 	}
12320 #if defined(WL_ENABLE_P2P_IF)
12321 	else if (dev == cfg->p2p_net) {
12322 		/* Group Add request on p2p0 */
12323 		dev = bcmcfg_to_prmry_ndev(cfg);
12324 		dev_role = NL80211_IFTYPE_P2P_GO;
12325 	}
12326 #endif /* WL_ENABLE_P2P_IF */
12327 
12328 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12329 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12330 		return BCME_ERROR;
12331 	}
12332 
12333 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12334 		dev_role = NL80211_IFTYPE_P2P_GO;
12335 	} else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12336 		dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
12337 	}
12338 
12339 	if (!check_dev_role_integrity(cfg, dev_role)) {
12340 		err = -ENODEV;
12341 		goto fail;
12342 	}
12343 
12344 	if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
12345 		WL_ERR(("P2P already down status!\n"));
12346 		err = BCME_ERROR;
12347 		goto fail;
12348 	}
12349 
12350 	ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
12351 	/* find the SSID */
12352 	if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
12353 		info->head_len - ie_offset,
12354 		DOT11_MNG_SSID_ID)) != NULL) {
12355 		if (dev_role == NL80211_IFTYPE_AP) {
12356 			/* Store the hostapd SSID */
12357 			bzero(&cfg->hostapd_ssid.SSID[0], DOT11_MAX_SSID_LEN);
12358 			cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
12359 			memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
12360 				cfg->hostapd_ssid.SSID_len);
12361 		} else {
12362 			/* P2P GO */
12363 			bzero(&cfg->p2p->ssid.SSID[0], DOT11_MAX_SSID_LEN);
12364 			cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
12365 			memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
12366 				cfg->p2p->ssid.SSID_len);
12367 		}
12368 	}
12369 
12370 	if (wl_cfg80211_parse_ies((u8 *)info->tail,
12371 		info->tail_len, &ies) < 0) {
12372 		WL_ERR(("Beacon get IEs failed \n"));
12373 		err = -EINVAL;
12374 		goto fail;
12375 	}
12376 
12377 	if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12378 		VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
12379 		info->tail_len)) < 0) {
12380 		WL_ERR(("Beacon set IEs failed \n"));
12381 		goto fail;
12382 	} else {
12383 		WL_DBG(("Applied Vndr IEs for Beacon \n"));
12384 	}
12385 
12386 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12387 	if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12388 		VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies,
12389 		info->proberesp_ies_len)) < 0) {
12390 		WL_ERR(("ProbeRsp set IEs failed \n"));
12391 		goto fail;
12392 	} else {
12393 		WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
12394 	}
12395 #endif // endif
12396 
12397 	is_bss_up = wl_cfg80211_bss_isup(dev, bssidx);
12398 
12399 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12400 	privacy = info->privacy;
12401 #else
12402 	privacy = 0;
12403 #endif // endif
12404 	if (!is_bss_up &&
12405 		(wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx, privacy) < 0))
12406 	{
12407 		WL_ERR(("Beacon set security failed \n"));
12408 		err = -EINVAL;
12409 		goto fail;
12410 	}
12411 
12412 	/* Set BI and DTIM period */
12413 	if (info->interval) {
12414 		if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
12415 			&info->interval, sizeof(s32))) < 0) {
12416 			WL_ERR(("Beacon Interval Set Error, %d\n", err));
12417 			return err;
12418 		}
12419 	}
12420 	if (info->dtim_period) {
12421 		if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
12422 			&info->dtim_period, sizeof(s32))) < 0) {
12423 			WL_ERR(("DTIM Interval Set Error, %d\n", err));
12424 			return err;
12425 		}
12426 	}
12427 
12428 	/* If bss is already up, skip bring up */
12429 	if (!is_bss_up &&
12430 		(err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0)
12431 	{
12432 		WL_ERR(("Beacon bring up AP/GO failed \n"));
12433 		goto fail;
12434 	}
12435 
12436 	/* Set GC/STA SCB expiry timings. */
12437 	if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
12438 		WL_ERR(("scb setting failed \n"));
12439 		if (err == BCME_UNSUPPORTED)
12440 			err = 0;
12441 //		goto fail;
12442 	}
12443 
12444 	if (wl_get_drv_status(cfg, AP_CREATED, dev)) {
12445 		/* Soft AP already running. Update changed params */
12446 		if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
12447 			WL_ERR(("Hostapd update sec failed \n"));
12448 			err = -EINVAL;
12449 			goto fail;
12450 		}
12451 	}
12452 
12453 	/* Enable Probe Req filter */
12454 	if (((dev_role == NL80211_IFTYPE_P2P_GO) ||
12455 		(dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) {
12456 		wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12457 		if (pbc)
12458 			wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12459 	}
12460 
12461 	WL_DBG(("** ADD/SET beacon done **\n"));
12462 	wl_set_drv_status(cfg, CONNECTED, dev);
12463 
12464 fail:
12465 	if (err) {
12466 		WL_ERR(("ADD/SET beacon failed\n"));
12467 		if (dev_role == NL80211_IFTYPE_AP) {
12468 #ifdef WL_EXT_IAPSTA
12469 		if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12470 #endif /* WL_EXT_IAPSTA */
12471 			/* clear the AP mode */
12472 			dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12473 #ifdef WL_EXT_IAPSTA
12474 		}
12475 #endif /* WL_EXT_IAPSTA */
12476 		}
12477 	}
12478 	return err;
12479 
12480 }
12481 
12482 static s32
wl_cfg80211_del_beacon(struct wiphy * wiphy,struct net_device * dev)12483 wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
12484 {
12485 	int err = 0;
12486 	s32 bssidx = 0;
12487 	int infra = 0;
12488 	struct wireless_dev *wdev = dev->ieee80211_ptr;
12489 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12490 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12491 
12492 	WL_DBG(("Enter. \n"));
12493 
12494 	if (!wdev) {
12495 		WL_ERR(("wdev null \n"));
12496 		return -EINVAL;
12497 	}
12498 
12499 	if ((wdev->iftype != NL80211_IFTYPE_P2P_GO) && (wdev->iftype != NL80211_IFTYPE_AP)) {
12500 		WL_ERR(("Unspported iface type iftype:%d \n", wdev->iftype));
12501 	}
12502 
12503 	wl_clr_drv_status(cfg, AP_CREATING, dev);
12504 	wl_clr_drv_status(cfg, AP_CREATED, dev);
12505 
12506 	/* Clear AP/GO connected status */
12507 	wl_clr_drv_status(cfg, CONNECTED, dev);
12508 
12509 	cfg->ap_oper_channel = 0;
12510 
12511 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12512 		WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12513 		return BCME_ERROR;
12514 	}
12515 
12516 	/* Do bss down */
12517 	if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
12518 		WL_ERR(("bss down error %d\n", err));
12519 	}
12520 
12521 	/* fall through is intentional */
12522 	err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
12523 	if (err < 0) {
12524 		WL_ERR(("SET INFRA error %d\n", err));
12525 	}
12526 	 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
12527 
12528 	if (wdev->iftype == NL80211_IFTYPE_AP) {
12529 #ifdef WL_EXT_IAPSTA
12530 		if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12531 #endif /* WL_EXT_IAPSTA */
12532 		/* clear the AP mode */
12533 		dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12534 #ifdef WL_EXT_IAPSTA
12535 		}
12536 #endif /* WL_EXT_IAPSTA */
12537 	}
12538 
12539 	return 0;
12540 }
12541 #endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
12542 
12543 #ifdef WL_SUPPORT_ACS
12544 /*
12545  * Currently the dump_obss IOVAR is returning string as output so we need to
12546  * parse the output buffer in an unoptimized way. Going forward if we get the
12547  * IOVAR output in binary format this method can be optimized
12548  */
wl_parse_dump_obss(char * buf,struct wl_dump_survey * survey)12549 static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
12550 {
12551 	int i;
12552 	char *token;
12553 	char delim[] = " \n";
12554 
12555 	token = strsep(&buf, delim);
12556 	while (token != NULL) {
12557 		if (!strcmp(token, "OBSS")) {
12558 			for (i = 0; i < OBSS_TOKEN_IDX; i++)
12559 				token = strsep(&buf, delim);
12560 			survey->obss = simple_strtoul(token, NULL, 10);
12561 		}
12562 
12563 		if (!strcmp(token, "IBSS")) {
12564 			for (i = 0; i < IBSS_TOKEN_IDX; i++)
12565 				token = strsep(&buf, delim);
12566 			survey->ibss = simple_strtoul(token, NULL, 10);
12567 		}
12568 
12569 		if (!strcmp(token, "TXDur")) {
12570 			for (i = 0; i < TX_TOKEN_IDX; i++)
12571 				token = strsep(&buf, delim);
12572 			survey->tx = simple_strtoul(token, NULL, 10);
12573 		}
12574 
12575 		if (!strcmp(token, "Category")) {
12576 			for (i = 0; i < CTG_TOKEN_IDX; i++)
12577 				token = strsep(&buf, delim);
12578 			survey->no_ctg = simple_strtoul(token, NULL, 10);
12579 		}
12580 
12581 		if (!strcmp(token, "Packet")) {
12582 			for (i = 0; i < PKT_TOKEN_IDX; i++)
12583 				token = strsep(&buf, delim);
12584 			survey->no_pckt = simple_strtoul(token, NULL, 10);
12585 		}
12586 
12587 		if (!strcmp(token, "Opp(time):")) {
12588 			for (i = 0; i < IDLE_TOKEN_IDX; i++)
12589 				token = strsep(&buf, delim);
12590 			survey->idle = simple_strtoul(token, NULL, 10);
12591 		}
12592 
12593 		token = strsep(&buf, delim);
12594 	}
12595 
12596 	return 0;
12597 }
12598 
wl_dump_obss(struct net_device * ndev,cca_msrmnt_query req,struct wl_dump_survey * survey)12599 static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
12600 	struct wl_dump_survey *survey)
12601 {
12602 	cca_stats_n_flags *results;
12603 	char *buf;
12604 	int retry, err;
12605 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
12606 
12607 	buf = (char *)MALLOCZ(cfg->osh, sizeof(char) * WLC_IOCTL_MAXLEN);
12608 	if (unlikely(!buf)) {
12609 		WL_ERR(("%s: buf alloc failed\n", __func__));
12610 		return -ENOMEM;
12611 	}
12612 
12613 	retry = IOCTL_RETRY_COUNT;
12614 	while (retry--) {
12615 		err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req),
12616 			buf, WLC_IOCTL_MAXLEN, NULL);
12617 		if (err >=  0) {
12618 			break;
12619 		}
12620 		WL_DBG(("attempt = %d, err = %d, \n",
12621 			(IOCTL_RETRY_COUNT - retry), err));
12622 	}
12623 
12624 	if (retry <= 0)	{
12625 		WL_ERR(("failure, dump_obss IOVAR failed\n"));
12626 		err = -EINVAL;
12627 		goto exit;
12628 	}
12629 
12630 	results = (cca_stats_n_flags *)(buf);
12631 	wl_parse_dump_obss(results->buf, survey);
12632 	MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
12633 
12634 	return 0;
12635 exit:
12636 	MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
12637 	return err;
12638 }
12639 
wl_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * ndev,int idx,struct survey_info * info)12640 static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
12641 	int idx, struct survey_info *info)
12642 {
12643 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12644 	struct wl_dump_survey *survey;
12645 	struct ieee80211_supported_band *band;
12646 	struct ieee80211_channel*chan;
12647 	cca_msrmnt_query req;
12648 	int val, err, noise, retry;
12649 
12650 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12651 	if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
12652 		return -ENOENT;
12653 	}
12654 	band = wiphy->bands[IEEE80211_BAND_2GHZ];
12655 	if (band && idx >= band->n_channels) {
12656 		idx -= band->n_channels;
12657 		band = NULL;
12658 	}
12659 
12660 	if (!band || idx >= band->n_channels) {
12661 		/* Move to 5G band */
12662 		band = wiphy->bands[IEEE80211_BAND_5GHZ];
12663 		if (idx >= band->n_channels) {
12664 			return -ENOENT;
12665 		}
12666 	}
12667 
12668 	chan = &band->channels[idx];
12669 	/* Setting current channel to the requested channel */
12670 	if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan,
12671 		NL80211_CHAN_HT20) < 0)) {
12672 		WL_ERR(("Set channel failed \n"));
12673 	}
12674 
12675 	if (!idx) {
12676 		/* Set interface up, explicitly. */
12677 		val = 1;
12678 		err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
12679 		if (err < 0) {
12680 			WL_ERR(("set interface up failed, error = %d\n", err));
12681 		}
12682 	}
12683 
12684 	/* Get noise value */
12685 	retry = IOCTL_RETRY_COUNT;
12686 	while (retry--) {
12687 		noise = 0;
12688 		err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise,
12689 			sizeof(noise));
12690 		if (err >=  0) {
12691 			break;
12692 		}
12693 		WL_DBG(("attempt = %d, err = %d, \n",
12694 			(IOCTL_RETRY_COUNT - retry), err));
12695 	}
12696 
12697 	if (retry <= 0)	{
12698 		WL_ERR(("Get Phy Noise failed, error = %d\n", err));
12699 		noise = CHAN_NOISE_DUMMY;
12700 	}
12701 
12702 	survey = (struct wl_dump_survey *)MALLOCZ(cfg->osh,
12703 		sizeof(struct wl_dump_survey));
12704 	if (unlikely(!survey)) {
12705 		WL_ERR(("%s: alloc failed\n", __func__));
12706 		return -ENOMEM;
12707 	}
12708 
12709 	/* Start Measurement for obss stats on current channel */
12710 	req.msrmnt_query = 0;
12711 	req.time_req = ACS_MSRMNT_DELAY;
12712 	if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
12713 		goto exit;
12714 	}
12715 
12716 	/*
12717 	 * Wait for the meaurement to complete, adding a buffer value of 10 to take
12718 	 * into consideration any delay in IOVAR completion
12719 	 */
12720 	msleep(ACS_MSRMNT_DELAY + 10);
12721 
12722 	/* Issue IOVAR to collect measurement results */
12723 	req.msrmnt_query = 1;
12724 	if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
12725 		goto exit;
12726 	}
12727 
12728 	info->channel = chan;
12729 	info->noise = noise;
12730 	info->channel_time = ACS_MSRMNT_DELAY;
12731 	info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
12732 	info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg +
12733 		survey->no_pckt;
12734 	info->channel_time_tx = survey->tx;
12735 	info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
12736 		SURVEY_INFO_CHANNEL_TIME_BUSY |	SURVEY_INFO_CHANNEL_TIME_RX |
12737 		SURVEY_INFO_CHANNEL_TIME_TX;
12738 	MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
12739 
12740 	return 0;
12741 exit:
12742 	MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
12743 	return err;
12744 }
12745 #endif /* WL_SUPPORT_ACS */
12746 
12747 #ifndef CONFIG_AP6XXX_WIFI6_HDF
12748 static
12749 #endif
12750 struct cfg80211_ops wl_cfg80211_ops = {
12751 	.add_virtual_intf = wl_cfg80211_add_virtual_iface,
12752 	.del_virtual_intf = wl_cfg80211_del_virtual_iface,
12753 	.change_virtual_intf = wl_cfg80211_change_virtual_iface,
12754 #if defined(WL_CFG80211_P2P_DEV_IF)
12755 	.start_p2p_device = wl_cfgp2p_start_p2p_device,
12756 	.stop_p2p_device = wl_cfgp2p_stop_p2p_device,
12757 #endif /* WL_CFG80211_P2P_DEV_IF */
12758 	.scan = wl_cfg80211_scan,
12759 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
12760 	.abort_scan = wl_cfg80211_abort_scan,
12761 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
12762 	.set_wiphy_params = wl_cfg80211_set_wiphy_params,
12763 	.join_ibss = wl_cfg80211_join_ibss,
12764 	.leave_ibss = wl_cfg80211_leave_ibss,
12765 	.get_station = wl_cfg80211_get_station,
12766 	.set_tx_power = wl_cfg80211_set_tx_power,
12767 	.get_tx_power = wl_cfg80211_get_tx_power,
12768 	.add_key = wl_cfg80211_add_key,
12769 	.del_key = wl_cfg80211_del_key,
12770 	.get_key = wl_cfg80211_get_key,
12771 	.set_default_key = wl_cfg80211_config_default_key,
12772 	.set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
12773 	.set_power_mgmt = wl_cfg80211_set_power_mgmt,
12774 	.connect = wl_cfg80211_connect,
12775 	.disconnect = wl_cfg80211_disconnect,
12776 	.suspend = wl_cfg80211_suspend,
12777 	.resume = wl_cfg80211_resume,
12778 	.set_pmksa = wl_cfg80211_set_pmksa,
12779 	.del_pmksa = wl_cfg80211_del_pmksa,
12780 	.flush_pmksa = wl_cfg80211_flush_pmksa,
12781 	.remain_on_channel = wl_cfg80211_remain_on_channel,
12782 	.cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
12783 	.mgmt_tx = wl_cfg80211_mgmt_tx,
12784 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
12785 	.mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
12786 #else
12787 	.update_mgmt_frame_registrations = wl_cfg80211_mgmt_frame_register,
12788 #endif
12789 	.change_bss = wl_cfg80211_change_bss,
12790 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS)
12791 	.set_channel = wl_cfg80211_set_channel,
12792 #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
12793 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS)
12794 	.set_beacon = wl_cfg80211_add_set_beacon,
12795 	.add_beacon = wl_cfg80211_add_set_beacon,
12796 	.del_beacon = wl_cfg80211_del_beacon,
12797 #else
12798 	.change_beacon = wl_cfg80211_change_beacon,
12799 	.start_ap = wl_cfg80211_start_ap,
12800 	.stop_ap = wl_cfg80211_stop_ap,
12801 #endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
12802 #ifdef WL_SCHED_SCAN
12803 	.sched_scan_start = wl_cfg80211_sched_scan_start,
12804 	.sched_scan_stop = wl_cfg80211_sched_scan_stop,
12805 #endif /* WL_SCHED_SCAN */
12806 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
12807 	2, 0))
12808 	.del_station = wl_cfg80211_del_station,
12809 	.change_station = wl_cfg80211_change_station,
12810 	.mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
12811 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
12812 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
12813 	.tdls_mgmt = wl_cfg80211_tdls_mgmt,
12814 	.tdls_oper = wl_cfg80211_tdls_oper,
12815 #endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
12816 #ifdef WL_SUPPORT_ACS
12817 	.dump_survey = wl_cfg80211_dump_survey,
12818 #endif /* WL_SUPPORT_ACS */
12819 #ifdef WL_CFG80211_ACL
12820 	.set_mac_acl = wl_cfg80211_set_mac_acl,
12821 #endif /* WL_CFG80211_ACL */
12822 #ifdef GTK_OFFLOAD_SUPPORT
12823 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
12824 	.set_rekey_data = wl_cfg80211_set_rekey_data,
12825 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
12826 #endif /* GTK_OFFLOAD_SUPPORT */
12827 #if defined(WL_FILS)
12828 	/* This should be enabled from kernel version which supports this */
12829 	.update_connect_params = wl_cfg80211_update_connect_params,
12830 #endif /* WL_FILS */
12831 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
12832 	.set_pmk = wl_cfg80211_set_pmk,
12833 	.del_pmk = wl_cfg80211_del_pmk,
12834 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
12835 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
12836 	.channel_switch = wl_cfg80211_channel_switch,
12837 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
12838 #ifdef WL_CLIENT_SAE
12839 	.external_auth = wl_cfg80211_external_auth,
12840 #endif /* WL_CLIENT_SAE */
12841 };
12842 
wl_mode_to_nl80211_iftype(s32 mode)12843 s32 wl_mode_to_nl80211_iftype(s32 mode)
12844 {
12845 	s32 err = 0;
12846 
12847 	switch (mode) {
12848 	case WL_MODE_BSS:
12849 		return NL80211_IFTYPE_STATION;
12850 	case WL_MODE_IBSS:
12851 		return NL80211_IFTYPE_ADHOC;
12852 	case WL_MODE_AP:
12853 		return NL80211_IFTYPE_AP;
12854 #ifdef WLMESH_CFG80211
12855 	case WL_MODE_MESH:
12856 		return NL80211_IFTYPE_MESH_POINT;
12857 #endif /* WLMESH_CFG80211 */
12858 	default:
12859 		return NL80211_IFTYPE_UNSPECIFIED;
12860 	}
12861 
12862 	return err;
12863 }
12864 
12865 s32
wl_cfg80211_set_country_code(struct net_device * net,char * country_code,bool notify,bool user_enforced,int revinfo)12866 wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
12867 	bool notify, bool user_enforced, int revinfo)
12868 {
12869 	s32 ret = BCME_OK;
12870 #ifdef WL_NAN
12871 	struct wireless_dev *wdev = ndev_to_wdev(net);
12872 	struct wiphy *wiphy = wdev->wiphy;
12873 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12874 	if (cfg->nan_enable) {
12875 		mutex_lock(&cfg->if_sync);
12876 		cfg->nancfg.disable_reason = NAN_COUNTRY_CODE_CHANGE;
12877 		ret = wl_cfgnan_disable(cfg);
12878 		mutex_unlock(&cfg->if_sync);
12879 		if (ret != BCME_OK) {
12880 			WL_ERR(("failed to disable nan, error[%d]\n", ret));
12881 			return ret;
12882 		}
12883 	}
12884 #endif /* WL_NAN */
12885 	ret = wldev_set_country(net, country_code,
12886 		notify, user_enforced, revinfo);
12887 	if (ret < 0) {
12888 		WL_ERR(("set country Failed :%d\n", ret));
12889 	}
12890 	return ret;
12891 }
12892 
12893 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
12894 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
12895 #define WL_CFG80211_REG_NOTIFIER() static int wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
12896 #else
12897 #define WL_CFG80211_REG_NOTIFIER() static void wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
12898 #endif /* kernel version < 3.9.0 */
12899 #endif
12900 
12901 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
WL_CFG80211_REG_NOTIFIER()12902 WL_CFG80211_REG_NOTIFIER()
12903 {
12904 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
12905 	int ret = 0;
12906 	int revinfo = -1;
12907 
12908 	if (!request || !cfg) {
12909 		WL_ERR(("Invalid arg\n"));
12910 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
12911 		return -EINVAL;
12912 #else
12913 		return;
12914 #endif /* kernel version < 3.10.11 */
12915 	}
12916 
12917 	WL_DBG(("ccode: %c%c Initiator: %d\n",
12918 		request->alpha2[0], request->alpha2[1], request->initiator));
12919 
12920 	/* We support only REGDOM_SET_BY_USER as of now */
12921 	if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
12922 		(request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
12923 		WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
12924 			request->initiator));
12925 		/* in case of no supported country by regdb
12926 		     lets driver setup platform default Locale
12927 		*/
12928 	}
12929 
12930 	WL_ERR(("Set country code %c%c from %s\n",
12931 		request->alpha2[0], request->alpha2[1],
12932 		((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User")));
12933 
12934 	if ((ret = wldev_set_country(bcmcfg_to_prmry_ndev(cfg), request->alpha2,
12935 		false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false),
12936 		revinfo)) < 0) {
12937 		WL_ERR(("set country Failed :%d\n", ret));
12938 	}
12939 
12940 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
12941 	return ret;
12942 #else
12943 	return;
12944 #endif /* kernel version < 3.10.11 */
12945 }
12946 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
12947 
12948 #ifdef CONFIG_PM
12949 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
12950 static const struct wiphy_wowlan_support brcm_wowlan_support = {
12951 	.flags = WIPHY_WOWLAN_ANY,
12952 	.n_patterns = WL_WOWLAN_MAX_PATTERNS,
12953 	.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
12954 	.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
12955 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
12956 	.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
12957 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
12958 };
12959 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
12960 #endif /* CONFIG_PM */
12961 
wl_features_set(u8 * array,uint8 len,u32 ftidx)12962 int wl_features_set(u8 *array, uint8 len, u32 ftidx)
12963 {
12964 	u8* ft_byte;
12965 
12966 	if ((ftidx / 8u) >= len)
12967 		return BCME_BADARG;
12968 
12969 	ft_byte = &array[ftidx / 8u];
12970 	*ft_byte |= BIT(ftidx % 8u);
12971 	return BCME_OK;
12972 }
12973 
wl_setup_wiphy(struct wireless_dev * wdev,struct device * sdiofunc_dev,dhd_pub_t * context)12974 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, dhd_pub_t *context)
12975 {
12976 	s32 err = 0;
12977 #ifdef CONFIG_PM
12978 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
12979 	struct cfg80211_wowlan *brcm_wowlan_config = NULL;
12980 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
12981 #endif /* CONFIG_PM */
12982 
12983 //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
12984 	dhd_pub_t *dhd = (dhd_pub_t *)context;
12985 	BCM_REFERENCE(dhd);
12986 
12987 	if (!dhd) {
12988 		WL_ERR(("DHD is NULL!!"));
12989 		err = -ENODEV;
12990 		return err;
12991 	}
12992 //#endif // endif
12993 
12994 	wdev->wiphy =
12995 	    wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
12996 	if (unlikely(!wdev->wiphy)) {
12997 		WL_ERR(("Couldn not allocate wiphy device\n"));
12998 		err = -ENOMEM;
12999 		return err;
13000 	}
13001 	set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
13002 	wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
13003 	/* Report  how many SSIDs Driver can support per Scan request */
13004 	wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
13005 	wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
13006 #ifdef WL_SCHED_SCAN
13007 	wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
13008 	wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
13009 	wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
13010 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
13011 	wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
13012 #endif /* LINUX_VER < 4.12 */
13013 #endif /* WL_SCHED_SCAN */
13014 #ifdef WLMESH_CFG80211
13015 	wdev->wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
13016 #endif /* WLMESH_CFG80211 */
13017 	wdev->wiphy->interface_modes =
13018 		BIT(NL80211_IFTYPE_STATION)
13019 		| BIT(NL80211_IFTYPE_ADHOC)
13020 #if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
13021 		| BIT(NL80211_IFTYPE_MONITOR)
13022 #endif // endif
13023 #if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
13024 		| BIT(NL80211_IFTYPE_P2P_CLIENT)
13025 		| BIT(NL80211_IFTYPE_P2P_GO)
13026 #endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
13027 #if defined(WL_CFG80211_P2P_DEV_IF)
13028 		| BIT(NL80211_IFTYPE_P2P_DEVICE)
13029 #endif /* WL_CFG80211_P2P_DEV_IF */
13030 #ifdef WLMESH_CFG80211
13031 		| BIT(NL80211_IFTYPE_MESH_POINT)
13032 #endif /* WLMESH_CFG80211 */
13033 		| BIT(NL80211_IFTYPE_AP);
13034 
13035 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
13036 	(defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
13037 	WL_DBG(("Setting interface combinations for common mode\n"));
13038 	wdev->wiphy->iface_combinations = common_iface_combinations;
13039 	wdev->wiphy->n_iface_combinations =
13040 		ARRAY_SIZE(common_iface_combinations);
13041 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
13042 
13043 	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
13044 
13045 	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
13046 	wdev->wiphy->cipher_suites = __wl_cipher_suites;
13047 	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
13048 	wdev->wiphy->max_remain_on_channel_duration = 5000;
13049 	wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
13050 #ifndef WL_POWERSAVE_DISABLED
13051 	wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
13052 #else
13053 	wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
13054 #endif				/* !WL_POWERSAVE_DISABLED */
13055 	wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
13056 		WIPHY_FLAG_4ADDR_AP |
13057 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS)
13058 		WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
13059 #endif // endif
13060 		WIPHY_FLAG_4ADDR_STATION;
13061 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
13062 	/*
13063 	 * If FW ROAM flag is advertised, upper layer doesn't provide the
13064 	 * bssid & freq in the connect command. However, kernel ver >= 3.15,
13065 	 * provides bssid_hint & freq_hint which can be used by the firmware.
13066 	 * fw_ap_select variable determines whether FW selects the AP or the
13067 	 * user space selects the target AP within the given ESS.
13068 	 */
13069 	wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
13070 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13071 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
13072 	wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
13073 		WIPHY_FLAG_OFFCHAN_TX;
13074 #endif // endif
13075 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
13076 	4, 0))
13077 	/* From 3.4 kernel ownards AP_SME flag can be advertised
13078 	 * to remove the patch from supplicant
13079 	 */
13080 	wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
13081 
13082 #ifdef WL_CFG80211_ACL
13083 	/* Configure ACL capabilities. */
13084 	wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
13085 #endif // endif
13086 
13087 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
13088 	/* Supplicant distinguish between the SoftAP mode and other
13089 	 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
13090 	 * response frame from Supplicant MR1 and Kernel 3.4.0 or
13091 	 * later version. To add Vendor specific IE into the
13092 	 * probe response frame in case of SoftAP mode,
13093 	 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
13094 	 */
13095 	if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
13096 		wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
13097 		wdev->wiphy->probe_resp_offload = 0;
13098 	}
13099 #endif // endif
13100 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
13101 
13102 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
13103 	wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
13104 #endif // endif
13105 
13106 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13107 	/*
13108 	 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
13109 	 * disconnection of connected network before suspend. So a dummy wowlan
13110 	 * filter is configured for kernels linux-3.8 and above.
13111 	 */
13112 
13113 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13114 	wdev->wiphy->wowlan = &brcm_wowlan_support;
13115 	/* If this is not provided cfg stack will get disconnect
13116 	* during suspend.
13117 	* Note: wiphy->wowlan_config is freed by cfg80211 layer.
13118 	* so use malloc instead of MALLOC(osh) to avoid false alarm.
13119 	*/
13120 	brcm_wowlan_config = kmalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL);
13121 	if (brcm_wowlan_config) {
13122 		brcm_wowlan_config->disconnect = true;
13123 		brcm_wowlan_config->gtk_rekey_failure = true;
13124 		brcm_wowlan_config->eap_identity_req = true;
13125 		brcm_wowlan_config->four_way_handshake = true;
13126 		brcm_wowlan_config->patterns = NULL;
13127 		brcm_wowlan_config->n_patterns = 0;
13128 		brcm_wowlan_config->tcp = NULL;
13129 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13130 		brcm_wowlan_config->nd_config = NULL;
13131 #endif // endif
13132 	} else {
13133 		WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
13134 			" So wiphy->wowlan_config is set to NULL\n"));
13135 	}
13136 	wdev->wiphy->wowlan_config = brcm_wowlan_config;
13137 #else
13138 	wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
13139 	wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
13140 	wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
13141 	wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
13142 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
13143 	wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
13144 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
13145 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13146 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13147 
13148 	WL_DBG(("Registering custom regulatory)\n"));
13149 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
13150 	wdev->wiphy->regulatory_flags |=
13151 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13152 		REGULATORY_IGNORE_STALE_KICKOFF |
13153 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
13154 		REGULATORY_CUSTOM_REG;
13155 #else
13156 	wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
13157 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
13158 	wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
13159 
13160 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13161 	WL_INFORM_MEM(("Registering Vendor80211\n"));
13162 	err = wl_cfgvendor_attach(wdev->wiphy, dhd);
13163 	if (unlikely(err < 0)) {
13164 		WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
13165 	}
13166 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
13167 #ifdef WL_FILS
13168 	wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
13169 #endif /* WL_FILS */
13170 
13171 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
13172 	wdev->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
13173 	wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS;
13174 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */
13175 
13176 	/* Now we can register wiphy with cfg80211 module */
13177 	err = wiphy_register(wdev->wiphy);
13178 	if (unlikely(err < 0)) {
13179 		WL_ERR(("Couldn not register wiphy device (%d)\n", err));
13180 		wiphy_free(wdev->wiphy);
13181 	}
13182 
13183 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
13184 	KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
13185 	wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
13186 #endif // endif
13187 
13188 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
13189 	if (wl_extsae_chip(dhd))
13190 		wdev->wiphy->features |= NL80211_FEATURE_SAE;
13191 #endif /* WL_SAE || WL_CLIENT_SAE */
13192 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE)
13193 	if (FW_SUPPORTED(dhd, idsup)) {
13194 		err = wiphy_ext_feature_set(wdev->wiphy,
13195 			NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
13196 		if (err) {
13197 			return err;
13198 		}
13199 		err = wiphy_ext_feature_set(wdev->wiphy,
13200 			NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
13201 		if (err) {
13202 			return err;
13203 		}
13204 	}
13205 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) && defined(BCMSUP_4WAY_HANDSHAKE) */
13206 #ifdef WL_SCAN_TYPE
13207 	/* These scan types will be mapped to default scan on non-supported chipset */
13208 	/* Advertise scan type capability. */
13209 	wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_SPAN_SCAN);
13210 	wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_POWER_SCAN);
13211 	wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
13212 	wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN;
13213 #endif /* WL_SCAN_TYPE */
13214 
13215 	return err;
13216 }
13217 
wl_free_wdev(struct bcm_cfg80211 * cfg)13218 static void wl_free_wdev(struct bcm_cfg80211 *cfg)
13219 {
13220 	struct wireless_dev *wdev = cfg->wdev;
13221 	struct wiphy *wiphy = NULL;
13222 	if (!wdev) {
13223 		WL_ERR(("wdev is invalid\n"));
13224 		return;
13225 	}
13226 	if (wdev->wiphy) {
13227 		wiphy = wdev->wiphy;
13228 
13229 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13230 		wl_cfgvendor_detach(wdev->wiphy);
13231 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
13232 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13233 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13234 		/* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
13235 		WL_DBG(("clear wowlan\n"));
13236 		wdev->wiphy->wowlan = NULL;
13237 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13238 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13239 		wiphy_unregister(wdev->wiphy);
13240 		wdev->wiphy->dev.parent = NULL;
13241 		wdev->wiphy = NULL;
13242 	}
13243 
13244 	wl_delete_all_netinfo(cfg);
13245 	if (wiphy) {
13246 		if (wdev->netdev)
13247 			wdev->netdev->ieee80211_ptr = NULL;
13248 		wdev->netdev = NULL;
13249 		MFREE(cfg->osh, wdev, sizeof(*wdev));
13250 		cfg->wdev = NULL;
13251 		wiphy_free(wiphy);
13252 	}
13253 
13254 	/* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
13255 	 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
13256 	 */
13257 }
13258 
13259 #if defined(BSSCACHE) || defined(RSSIAVG)
wl_cfg80211_update_bss_cache(struct bcm_cfg80211 * cfg)13260 void wl_cfg80211_update_bss_cache(struct bcm_cfg80211 *cfg)
13261 {
13262 #if defined(RSSIAVG)
13263 	int rssi;
13264 #endif
13265 	struct wl_scan_results *bss_list = cfg->bss_list;
13266 
13267 	/* Free cache in p2p scanning*/
13268 	if (p2p_is_on(cfg) && p2p_scan(cfg)) {
13269 #if defined(RSSIAVG)
13270 		wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
13271 #endif
13272 #if defined(BSSCACHE)
13273 		wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
13274 #endif
13275 	}
13276 
13277 	/* Update cache */
13278 #if defined(RSSIAVG)
13279 	wl_update_rssi_cache(&cfg->g_rssi_cache_ctrl, bss_list);
13280 	if (!in_atomic())
13281 		wl_update_connected_rssi_cache(ndev, &cfg->g_rssi_cache_ctrl, &rssi);
13282 #endif
13283 #if defined(BSSCACHE)
13284 	wl_update_bss_cache(&cfg->g_bss_cache_ctrl,
13285 #if defined(RSSIAVG)
13286 		&cfg->g_rssi_cache_ctrl,
13287 #endif
13288 		bss_list);
13289 #endif
13290 
13291 	/* delete dirty cache */
13292 #if defined(RSSIAVG)
13293 	wl_delete_dirty_rssi_cache(&cfg->g_rssi_cache_ctrl);
13294 	wl_reset_rssi_cache(&cfg->g_rssi_cache_ctrl);
13295 #endif
13296 #if defined(BSSCACHE)
13297 	wl_delete_dirty_bss_cache(&cfg->g_bss_cache_ctrl);
13298 	wl_reset_bss_cache(&cfg->g_bss_cache_ctrl);
13299 #endif
13300 
13301 }
13302 #endif
13303 
13304 #if defined(BSSCACHE)
wl_inform_bss_cache(struct bcm_cfg80211 * cfg)13305 s32 wl_inform_bss_cache(struct bcm_cfg80211 *cfg)
13306 {
13307 	struct wl_scan_results *bss_list = cfg->bss_list;
13308 	wl_bss_info_t *bi = NULL;	/* must be initialized */
13309 	s32 err = 0;
13310 	s32 i;
13311 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13312 #if defined(BSSCACHE)
13313 	wl_bss_cache_t *node;
13314 #endif
13315 
13316 	WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
13317 	node = cfg->g_bss_cache_ctrl.m_cache_head;
13318 	for (i=0; node && i<WL_AP_MAX; i++) {
13319 		bi = node->results.bss_info;
13320 		err = wl_inform_single_bss(cfg, bi, false);
13321 		node = node->next;
13322 	}
13323 	if (cfg->autochannel)
13324 		wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, ioctl_version,
13325 			&cfg->best_2g_ch, &cfg->best_5g_ch);
13326 
13327 	return err;
13328 }
13329 #endif
13330 
wl_inform_bss(struct bcm_cfg80211 * cfg)13331 s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
13332 {
13333 #if !defined(BSSCACHE)
13334 	struct wl_scan_results *bss_list;
13335 	wl_bss_info_t *bi = NULL;	/* must be initialized */
13336 	s32 i;
13337 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13338 #endif
13339 	s32 err = 0;
13340 
13341 #if defined(BSSCACHE) || defined(RSSIAVG)
13342 	wl_cfg80211_update_bss_cache(cfg);
13343 #endif
13344 
13345 #if defined(BSSCACHE)
13346 	err = wl_inform_bss_cache(cfg);
13347 #else
13348 	bss_list = cfg->bss_list;
13349 	WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
13350 #ifdef ESCAN_CHANNEL_CACHE
13351 	reset_roam_cache(cfg);
13352 #endif /* ESCAN_CHANNEL_CACHE */
13353 	preempt_disable();
13354 	bi = next_bss(bss_list, bi);
13355 	for_each_bss(bss_list, bi, i) {
13356 #ifdef ESCAN_CHANNEL_CACHE
13357 		add_roam_cache(cfg, bi);
13358 #endif /* ESCAN_CHANNEL_CACHE */
13359 		err = wl_inform_single_bss(cfg, bi, false);
13360 		if (unlikely(err)) {
13361 			WL_ERR(("bss inform failed\n"));
13362 		}
13363 	}
13364 	preempt_enable();
13365 	if (cfg->autochannel)
13366 		wl_ext_get_best_channel(ndev, bss_list, ioctl_version,
13367 			&cfg->best_2g_ch, &cfg->best_5g_ch);
13368 #endif
13369 
13370 	WL_MEM(("cfg80211 scan cache updated\n"));
13371 #ifdef ROAM_CHANNEL_CACHE
13372 	/* print_roam_cache(); */
13373 	update_roam_cache(cfg, ioctl_version);
13374 #endif /* ROAM_CHANNEL_CACHE */
13375 	return err;
13376 }
13377 
wl_inform_single_bss(struct bcm_cfg80211 * cfg,wl_bss_info_t * bi,bool update_ssid)13378 static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool update_ssid)
13379 {
13380 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13381 	struct ieee80211_mgmt *mgmt;
13382 	struct ieee80211_channel *channel;
13383 	struct ieee80211_supported_band *band;
13384 	struct wl_cfg80211_bss_info *notif_bss_info;
13385 	struct wl_scan_req *sr = wl_to_sr(cfg);
13386 	struct beacon_proberesp *beacon_proberesp;
13387 	struct cfg80211_bss *cbss = NULL;
13388 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
13389 	log_conn_event_t *event_data = NULL;
13390 	tlv_log *tlv_data = NULL;
13391 	u32 alloc_len, tlv_len;
13392 	u32 payload_len;
13393 	s32 mgmt_type;
13394 	s32 signal;
13395 	u32 freq;
13396 	s32 err = 0;
13397 	gfp_t aflags;
13398 	u8 tmp_buf[IEEE80211_MAX_SSID_LEN + 1];
13399 	chanspec_t chanspec;
13400 #ifdef CONFIG_AP6XXX_WIFI6_HDF
13401 	struct InnerBssInfo innerBssInfo;
13402 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13403 #endif
13404 	if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
13405 		WL_DBG(("Beacon is larger than buffer. Discarding\n"));
13406 		return err;
13407 	}
13408 
13409 	if (bi->SSID_len > IEEE80211_MAX_SSID_LEN) {
13410 		WL_ERR(("wrong SSID len:%d\n", bi->SSID_len));
13411 		return -EINVAL;
13412 	}
13413 
13414 	aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
13415 	notif_bss_info = (struct wl_cfg80211_bss_info *)MALLOCZ(cfg->osh,
13416 		sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13417 	if (unlikely(!notif_bss_info)) {
13418 		WL_ERR(("notif_bss_info alloc failed\n"));
13419 		return -ENOMEM;
13420 	}
13421 	mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
13422 	chanspec = wl_chspec_driver_to_host(bi->chanspec);
13423 	notif_bss_info->channel = wf_chspec_ctlchan(chanspec);
13424 
13425 	if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
13426 		band = wiphy->bands[IEEE80211_BAND_2GHZ];
13427 	else
13428 		band = wiphy->bands[IEEE80211_BAND_5GHZ];
13429 	if (!band) {
13430 		WL_ERR(("No valid band\n"));
13431 		MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
13432 			+ sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13433 		return -EINVAL;
13434 	}
13435 	notif_bss_info->rssi = dtoh16(bi->RSSI);
13436 #if defined(RSSIAVG)
13437 	notif_bss_info->rssi = wl_get_avg_rssi(&cfg->g_rssi_cache_ctrl, &bi->BSSID);
13438 	if (notif_bss_info->rssi == RSSI_MINVAL)
13439 		notif_bss_info->rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
13440 #endif
13441 #if defined(RSSIOFFSET)
13442 	notif_bss_info->rssi = wl_update_rssi_offset(bcmcfg_to_prmry_ndev(cfg), notif_bss_info->rssi);
13443 #endif
13444 #if !defined(RSSIAVG) && !defined(RSSIOFFSET)
13445 	// terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
13446 	notif_bss_info->rssi = MIN(notif_bss_info->rssi, RSSI_MAXVAL);
13447 #endif
13448 	memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
13449 	mgmt_type = cfg->active_scan ?
13450 		IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
13451 	if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
13452 	    mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type);
13453 	}
13454 	beacon_proberesp = cfg->active_scan ?
13455 		(struct beacon_proberesp *)&mgmt->u.probe_resp :
13456 		(struct beacon_proberesp *)&mgmt->u.beacon;
13457 	beacon_proberesp->timestamp = 0;
13458 	beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
13459 	beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
13460 	wl_rst_ie(cfg);
13461 	wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, update_ssid);
13462 	wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
13463 	wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX -
13464 		offsetof(struct wl_cfg80211_bss_info, frame_buf));
13465 	notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
13466 		u.beacon.variable) + wl_get_ielen(cfg);
13467 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
13468 	freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
13469 	(void)band->band;
13470 #else
13471 	freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
13472 #endif // endif
13473 	if (freq == 0) {
13474 		WL_ERR(("Invalid channel, fail to change channel to freq\n"));
13475 		MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
13476 			+ sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13477 		return -EINVAL;
13478 	}
13479 	channel = ieee80211_get_channel(wiphy, freq);
13480 	memcpy(tmp_buf, bi->SSID, bi->SSID_len);
13481 	tmp_buf[bi->SSID_len] = '\0';
13482 	WL_SCAN(("###0331###BSSID %pM, channel %3d(%3d %3sMHz), rssi %3d, capa 0x%-4x, mgmt_type %d, "
13483 		"frame_len %3d, SSID \"%s\"\n",
13484 		&bi->BSSID, notif_bss_info->channel, CHSPEC_CHANNEL(chanspec),
13485 		CHSPEC_IS20(chanspec)?"20":
13486 		CHSPEC_IS40(chanspec)?"40":
13487 		CHSPEC_IS80(chanspec)?"80":
13488 		CHSPEC_IS160(chanspec)?"160":"??",
13489 		notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type,
13490 		notif_bss_info->frame_len, tmp_buf));
13491 	if (unlikely(!channel)) {
13492 		WL_ERR(("ieee80211_get_channel error, freq=%d, channel=%d\n",
13493 			freq, notif_bss_info->channel));
13494 		MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
13495 			+ sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13496 		return -EINVAL;
13497 	}
13498 
13499 	signal = notif_bss_info->rssi*100;
13500 	if (!mgmt->u.probe_resp.timestamp) {
13501 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13502 		struct osl_timespec ts;
13503 		osl_get_monotonic_boottime(&ts);
13504 		mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000)
13505 				+ ts.tv_nsec / 1000;
13506 #else
13507 		struct osl_timespec tv;
13508 		osl_do_gettimeofday(&tv);
13509 		mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000)
13510 				+ tv.tv_usec;
13511 #endif // endif
13512 	}
13513 
13514 	cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
13515 		le16_to_cpu(notif_bss_info->frame_len), signal, aflags);
13516 	if (unlikely(!cbss)) {
13517 		WL_ERR(("cfg80211_inform_bss_frame error bssid " MACDBG " channel %d \n",
13518 			MAC2STRDBG((u8*)(&bi->BSSID)), notif_bss_info->channel));
13519 		err = -EINVAL;
13520 		goto out_err;
13521 	}
13522 
13523 	CFG80211_PUT_BSS(wiphy, cbss);
13524 #ifdef CONFIG_AP6XXX_WIFI6_HDF
13525 	innerBssInfo.channel = channel;
13526 	innerBssInfo.signal = signal;
13527 	innerBssInfo.freq = freq;
13528 	innerBssInfo.mgmt = mgmt;
13529 	innerBssInfo.mgmtLen = notif_bss_info->frame_len;
13530 	HdfInformBssFrameEventCallback(ndev, &innerBssInfo);
13531 #endif
13532 	if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID) &&
13533 			(cfg->sched_scan_req && !cfg->scan_request)) {
13534 		alloc_len = sizeof(log_conn_event_t) + IEEE80211_MAX_SSID_LEN + sizeof(uint16) +
13535 			sizeof(int16);
13536 		event_data = (log_conn_event_t *)MALLOCZ(dhdp->osh, alloc_len);
13537 		if (!event_data) {
13538 			WL_ERR(("%s: failed to allocate the log_conn_event_t with "
13539 				"length(%d)\n", __func__, alloc_len));
13540 			goto out_err;
13541 		}
13542 		tlv_len = 3 * sizeof(tlv_log);
13543 		event_data->tlvs = (tlv_log *)MALLOCZ(cfg->osh, tlv_len);
13544 		if (!event_data->tlvs) {
13545 			WL_ERR(("%s: failed to allocate the log_conn_event_t with "
13546 				"length(%d)\n", __func__, tlv_len));
13547 			goto free_evt_data;
13548 		}
13549 
13550 		payload_len = sizeof(log_conn_event_t);
13551 		event_data->event = WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND;
13552 		tlv_data = event_data->tlvs;
13553 
13554 		/* ssid */
13555 		tlv_data->tag = WIFI_TAG_SSID;
13556 		tlv_data->len = bi->SSID_len;
13557 		memcpy(tlv_data->value, bi->SSID, bi->SSID_len);
13558 		payload_len += TLV_LOG_SIZE(tlv_data);
13559 		tlv_data = TLV_LOG_NEXT(tlv_data);
13560 
13561 		/* channel */
13562 		tlv_data->tag = WIFI_TAG_CHANNEL;
13563 		tlv_data->len = sizeof(uint16);
13564 		memcpy(tlv_data->value, &notif_bss_info->channel, sizeof(uint16));
13565 		payload_len += TLV_LOG_SIZE(tlv_data);
13566 		tlv_data = TLV_LOG_NEXT(tlv_data);
13567 
13568 		/* rssi */
13569 		tlv_data->tag = WIFI_TAG_RSSI;
13570 		tlv_data->len = sizeof(int16);
13571 		memcpy(tlv_data->value, &notif_bss_info->rssi, sizeof(int16));
13572 		payload_len += TLV_LOG_SIZE(tlv_data);
13573 		tlv_data = TLV_LOG_NEXT(tlv_data);
13574 
13575 		dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
13576 			event_data, payload_len);
13577 		MFREE(dhdp->osh, event_data->tlvs, tlv_len);
13578 free_evt_data:
13579 		MFREE(dhdp->osh, event_data, alloc_len);
13580 	}
13581 
13582 out_err:
13583 	MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
13584 			+ sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13585 	return err;
13586 }
13587 
wl_is_linkup(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e,struct net_device * ndev)13588 static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev)
13589 {
13590 	u32 event = ntoh32(e->event_type);
13591 	u32 status =  ntoh32(e->status);
13592 	u16 flags = ntoh16(e->flags);
13593 #if defined(CUSTOM_SET_ANTNPM)
13594 	dhd_pub_t *dhd;
13595 	dhd = (dhd_pub_t *)(cfg->pub);
13596 #endif // endif
13597 
13598 	WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
13599 	if (event == WLC_E_SET_SSID) {
13600 		if (status == WLC_E_STATUS_SUCCESS) {
13601 #ifdef CUSTOM_SET_ANTNPM
13602 			if (dhd->mimo_ant_set) {
13603 				int err = 0;
13604 
13605 				WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhd->mimo_ant_set));
13606 				err = wldev_iovar_setint(ndev, "txchain", dhd->mimo_ant_set);
13607 				if (err != 0) {
13608 					WL_ERR(("[WIFI_SEC] Fail set txchain\n"));
13609 				}
13610 				err = wldev_iovar_setint(ndev, "rxchain", dhd->mimo_ant_set);
13611 				if (err != 0) {
13612 					WL_ERR(("[WIFI_SEC] Fail set rxchain\n"));
13613 				}
13614 			}
13615 #endif /* CUSTOM_SET_ANTNPM */
13616 			if (!wl_is_ibssmode(cfg, ndev))
13617 				return true;
13618 		}
13619 	} else if (event == WLC_E_LINK) {
13620 		if (flags & WLC_EVENT_MSG_LINK)
13621 			return true;
13622 	}
13623 
13624 	WL_DBG(("wl_is_linkup false\n"));
13625 	return false;
13626 }
13627 
wl_is_linkdown(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)13628 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13629 {
13630 	u32 event = ntoh32(e->event_type);
13631 	u16 flags = ntoh16(e->flags);
13632 
13633 	if (event == WLC_E_DEAUTH_IND ||
13634 	event == WLC_E_DISASSOC_IND ||
13635 	event == WLC_E_DISASSOC ||
13636 	event == WLC_E_DEAUTH) {
13637 		WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
13638 		return true;
13639 	} else if (event == WLC_E_LINK) {
13640 		if (!(flags & WLC_EVENT_MSG_LINK)) {
13641 			WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
13642 			return true;
13643 		}
13644 	}
13645 
13646 	return false;
13647 }
13648 
wl_is_nonetwork(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)13649 static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13650 {
13651 	u32 event = ntoh32(e->event_type);
13652 	u32 status = ntoh32(e->status);
13653 
13654 	if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS)
13655 		return true;
13656 	if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
13657 		return true;
13658 	if (event == WLC_E_ASSOC_RESP_IE && status != WLC_E_STATUS_SUCCESS)
13659 		return true;
13660 
13661 	return false;
13662 }
13663 
13664 #ifdef WL_SAE
13665 static s32
wl_cfg80211_event_sae_key(struct bcm_cfg80211 * cfg,struct net_device * ndev,wl_sae_key_info_t * sae_key)13666 wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13667 	wl_sae_key_info_t *sae_key)
13668 {
13669 	struct sk_buff *skb;
13670 	gfp_t kflags;
13671 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13672 	int err = BCME_OK;
13673 
13674 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
13675 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
13676 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
13677 	skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), BRCM_SAE_VENDOR_EVENT_BUF_LEN,
13678 		BRCM_VENDOR_EVENT_SAE_KEY, kflags);
13679 #else
13680 	skb = cfg80211_vendor_event_alloc(wiphy, BRCM_SAE_VENDOR_EVENT_BUF_LEN,
13681 		BRCM_VENDOR_EVENT_SAE_KEY, kflags);
13682 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
13683 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
13684 	if (!skb) {
13685 		WL_ERR(("skb alloc failed"));
13686 		err = BCME_NOMEM;
13687 		goto done;
13688 	}
13689 
13690 	WL_INFORM_MEM(("Received Sae Key event for "MACDBG" key length %x %x",
13691 		MAC2STRDBG(sae_key->peer_mac), sae_key->pmk_len, sae_key->pmkid_len));
13692 	nla_put(skb, BRCM_SAE_KEY_ATTR_PEER_MAC, ETHER_ADDR_LEN, sae_key->peer_mac);
13693 	nla_put(skb, BRCM_SAE_KEY_ATTR_PMK, sae_key->pmk_len, sae_key->pmk);
13694 	nla_put(skb, BRCM_SAE_KEY_ATTR_PMKID, sae_key->pmkid_len, sae_key->pmkid);
13695 	cfg80211_vendor_event(skb, kflags);
13696 
13697 done:
13698 	return err;
13699 }
13700 
13701 static s32
wl_bss_handle_sae_auth(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * event,void * data)13702 wl_bss_handle_sae_auth(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13703 	const wl_event_msg_t *event, void *data)
13704 {
13705 	int err = BCME_OK;
13706 	uint status = ntoh32(event->status);
13707 	wl_auth_event_t *auth_data;
13708 	wl_sae_key_info_t sae_key;
13709 	uint16 tlv_buf_len;
13710 
13711 	if (status == WLC_E_STATUS_SUCCESS) {
13712 		auth_data = (wl_auth_event_t *)data;
13713 		if (auth_data->version != WL_AUTH_EVENT_DATA_V1) {
13714 			WL_ERR(("unknown auth event data version %x\n",
13715 				auth_data->version));
13716 			err = BCME_VERSION;
13717 			goto done;
13718 		}
13719 
13720 		tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V1;
13721 
13722 		/* check if PMK info present */
13723 		sae_key.pmk = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13724 			WL_AUTH_PMK_TLV_ID, &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
13725 		if (!sae_key.pmk || !sae_key.pmk_len) {
13726 			WL_ERR(("Mandatory PMK info not present"));
13727 			err = BCME_NOTFOUND;
13728 			goto done;
13729 		}
13730 		/* check if PMKID info present */
13731 		sae_key.pmkid = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13732 			WL_AUTH_PMKID_TLV_ID, &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
13733 		if (!sae_key.pmkid || !sae_key.pmkid_len) {
13734 			WL_ERR(("Mandatory PMKID info not present\n"));
13735 			err = BCME_NOTFOUND;
13736 			goto done;
13737 		}
13738 		memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet, ETHER_ADDR_LEN);
13739 		err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
13740 		if (err) {
13741 			WL_ERR(("Failed to event sae key info\n"));
13742 		}
13743 	} else {
13744 		WL_ERR(("sae auth status failure:%d\n", status));
13745 	}
13746 done:
13747 	return err;
13748 }
13749 #endif /* WL_SAE */
13750 
13751 static s32
wl_get_auth_assoc_status(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)13752 wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13753 	const wl_event_msg_t *e, void *data)
13754 {
13755 	u32 reason = ntoh32(e->reason);
13756 	u32 event = ntoh32(e->event_type);
13757 #ifdef WL_SAE
13758 	uint auth_type = ntoh32(e->auth_type);
13759 #endif /* WL_SAE */
13760 	struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13761 	WL_DBG(("event type : %d, reason : %d\n", event, reason));
13762 
13763 	if (sec) {
13764 		switch (event) {
13765 		case WLC_E_ASSOC:
13766 		case WLC_E_AUTH:
13767 		case WLC_E_AUTH_IND:
13768 			sec->auth_assoc_res_status = reason;
13769 #ifdef WL_SAE
13770 			if ((event == WLC_E_AUTH || event == WLC_E_AUTH_IND) &&
13771 				auth_type == DOT11_SAE) {
13772 				wl_bss_handle_sae_auth(cfg, ndev, e, data);
13773 			}
13774 #endif /* WL_SAE */
13775 			break;
13776 		default:
13777 			break;
13778 		}
13779 	} else {
13780 		WL_ERR(("sec is NULL\n"));
13781 	}
13782 	return 0;
13783 }
13784 
13785 #ifdef WL_CLIENT_SAE
13786 static s32
wl_notify_connect_status_ap_auth(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)13787 wl_notify_connect_status_ap_auth(struct bcm_cfg80211 *cfg,
13788 	struct net_device *ndev, const wl_event_msg_t *e, void *data)
13789 {
13790 	bcm_struct_cfgdev *cfgdev = ndev_to_cfgdev(ndev);
13791 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13792 	u8 bsscfgidx = e->bsscfgidx;
13793 	u8 *mgmt_frame = NULL;
13794 	u8 *body = NULL;
13795 	u32 body_len = 0;
13796 	s32 chan;
13797 	u16 channel;
13798 	struct ieee80211_supported_band *band;
13799 	chanspec_t chanspec;
13800 	s32 freq;
13801 	struct ether_addr da;
13802 	struct ether_addr bssid;
13803 	u32 event = ntoh32(e->event_type);
13804 	u32 reason = ntoh32(e->reason);
13805 	u32 len = ntoh32(e->datalen);
13806 	s32 err = 0;
13807 
13808 	if (!len) {
13809 		WL_ERR(("event %s(%d) has no payload. status %d reason %d\n",
13810 			bcmevent_get_name(event), event, ntoh32(e->status), reason));
13811 		return 0;
13812 	}
13813 
13814 	body = (u8 *)MALLOCZ(cfg->osh, len);
13815 	if (body == NULL) {
13816 		WL_ERR(("Failed to allocate body\n"));
13817 		return WL_INVALID;
13818 	}
13819 	(void)memcpy_s(body, len, data, len);
13820 
13821 	err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
13822 		NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
13823 	if (unlikely(err)) {
13824 		WL_ERR(("Could not get cur_etheraddr %d\n", err));
13825 		goto exit;
13826 	}
13827 	(void)memcpy_s(da.octet, ETHER_ADDR_LEN, cfg->ioctl_buf, ETHER_ADDR_LEN);
13828 
13829 	bzero(&bssid, sizeof(bssid));
13830 	err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
13831 	if (unlikely(err)) {
13832 		WL_ERR(("Could not get bssid %d\n", err));
13833 		goto exit;
13834 	}
13835 
13836 	err = wldev_iovar_getint(ndev, "chanspec", &chan);
13837 	if (unlikely(err)) {
13838 		WL_ERR(("Could not get chanspec %d\n", err));
13839 		goto exit;
13840 	}
13841 	chanspec = wl_chspec_driver_to_host(chan);
13842 	channel = wf_chspec_ctlchan(chanspec);
13843 
13844 	if (channel <= CH_MAX_2G_CHANNEL)
13845 		band = wiphy->bands[IEEE80211_BAND_2GHZ];
13846 	else
13847 		band = wiphy->bands[IEEE80211_BAND_5GHZ];
13848 	if (!band) {
13849 		WL_ERR(("No valid band\n"));
13850 		goto exit;
13851 	}
13852 
13853 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
13854 	freq = ieee80211_channel_to_frequency(channel);
13855 #else
13856 	freq = ieee80211_channel_to_frequency(channel, band->band);
13857 #endif
13858 
13859 	body_len = len;
13860 	err = wl_frame_get_mgmt(cfg, FC_AUTH, &da, &e->addr, &bssid,
13861 		&mgmt_frame, &len, body);
13862 	if (!err) {
13863 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
13864 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0);
13865 #ifdef CONFIG_AP6XXX_WIFI6_HDF
13866 		HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame, len);
13867 #endif
13868 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
13869 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
13870 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
13871 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
13872 #else
13873 		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
13874 #endif
13875 		MFREE(cfg->osh, mgmt_frame, len);
13876 	}
13877 
13878 exit:
13879 	if (body) {
13880 		MFREE(cfg->osh, body, body_len);
13881 	}
13882 
13883 	return err;
13884 }
13885 #endif /* WL_CLIENT_SAE */
13886 
13887 
13888 /* The mainline kernel >= 3.2.0 has support for indicating new/del station
13889  * to AP/P2P GO via events. If this change is backported to kernel for which
13890  * this driver is being built, then define WL_CFG80211_STA_EVENT. You
13891  * should use this new/del sta event mechanism for BRCM supplicant >= 22.
13892  */
13893 static s32
wl_notify_connect_status_ap(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)13894 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13895 	const wl_event_msg_t *e, void *data)
13896 {
13897 	s32 err = 0;
13898 	u32 event = ntoh32(e->event_type);
13899 	u32 reason = ntoh32(e->reason);
13900 	u32 len = ntoh32(e->datalen);
13901 	u32 status = ntoh32(e->status);
13902 
13903 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
13904 	(LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
13905 	bool isfree = false;
13906 	u8 *mgmt_frame;
13907 	u8 bsscfgidx = e->bsscfgidx;
13908 	s32 freq;
13909 	s32 channel;
13910 	u8 *body = NULL;
13911 	u16 fc = 0;
13912 	u32 body_len = 0;
13913 
13914 	struct ieee80211_supported_band *band;
13915 	struct ether_addr da;
13916 	struct ether_addr bssid;
13917 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13918 	channel_info_t ci;
13919 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
13920 #else
13921 	struct station_info sinfo;
13922 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
13923 
13924 	WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n",
13925 		ndev->name, event, ntoh32(e->status), reason));
13926 
13927 	if (event == WLC_E_AUTH_IND) {
13928 		wl_get_auth_assoc_status(cfg, ndev, e, data);
13929 		return 0;
13930 	}
13931 	/* if link down, bsscfg is disabled. */
13932 	if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
13933 		wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
13934 		wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
13935 		WL_MSG(ndev->name, "AP mode link down !! \n");
13936 		complete(&cfg->iface_disable);
13937 		return 0;
13938 	}
13939 
13940 	if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
13941 		(reason == WLC_E_REASON_INITIAL_ASSOC) &&
13942 		(wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
13943 		if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
13944 			/* AP/GO brought up successfull in firmware */
13945 			WL_MSG(ndev->name, "AP/GO Link up\n");
13946 			wl_set_drv_status(cfg, AP_CREATED, ndev);
13947 			OSL_SMP_WMB();
13948 			wake_up_interruptible(&cfg->netif_change_event);
13949 #ifdef WL_BCNRECV
13950 			/* check fakeapscan is in progress, if progress then abort */
13951 			wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
13952 #endif /* WL_BCNRECV */
13953 			wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_AP_ENABLED, NULL);
13954 			return 0;
13955 		}
13956 	}
13957 
13958 	if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
13959 		WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
13960 			"event %s(%d) status %d reason %d\n",
13961 			bcmevent_get_name(event), event, ntoh32(e->status), reason);
13962 	}
13963 
13964 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
13965 	(LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
13966 	WL_DBG(("Enter \n"));
13967 	if (!len && (event == WLC_E_DEAUTH)) {
13968 		len = 2; /* reason code field */
13969 		data = &reason;
13970 	}
13971 	if (len) {
13972 		body = (u8 *)MALLOCZ(cfg->osh, len);
13973 		if (body == NULL) {
13974 			WL_ERR(("Failed to allocate body\n"));
13975 			return WL_INVALID;
13976 		}
13977 	}
13978 	bzero(&bssid, ETHER_ADDR_LEN);
13979 	WL_DBG(("Enter event %d ndev %p\n", event, ndev));
13980 	if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
13981 		MFREE(cfg->osh, body, len);
13982 		return WL_INVALID;
13983 	}
13984 	if (len)
13985 		memcpy(body, data, len);
13986 
13987 	wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
13988 		NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, NULL);
13989 	memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
13990 	bzero(&bssid, sizeof(bssid));
13991 	err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
13992 	switch (event) {
13993 		case WLC_E_ASSOC_IND:
13994 			fc = FC_ASSOC_REQ;
13995 			break;
13996 		case WLC_E_REASSOC_IND:
13997 			fc = FC_REASSOC_REQ;
13998 			break;
13999 		case WLC_E_DISASSOC_IND:
14000 			fc = FC_DISASSOC;
14001 			break;
14002 		case WLC_E_DEAUTH_IND:
14003 			fc = FC_DISASSOC;
14004 			break;
14005 		case WLC_E_DEAUTH:
14006 			fc = FC_DISASSOC;
14007 			break;
14008 		default:
14009 			fc = 0;
14010 			goto exit;
14011 	}
14012 	bzero(&ci, sizeof(ci));
14013 	if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
14014 		MFREE(cfg->osh, body, len);
14015 		return err;
14016 	}
14017 
14018 	channel = dtoh32(ci.hw_channel);
14019 	if (channel <= CH_MAX_2G_CHANNEL)
14020 		band = wiphy->bands[IEEE80211_BAND_2GHZ];
14021 	else
14022 		band = wiphy->bands[IEEE80211_BAND_5GHZ];
14023 	if (!band) {
14024 		WL_ERR(("No valid band\n"));
14025 		if (body) {
14026 			MFREE(cfg->osh, body, len);
14027 		}
14028 		return -EINVAL;
14029 	}
14030 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
14031 	freq = ieee80211_channel_to_frequency(channel);
14032 	(void)band->band;
14033 #else
14034 	freq = ieee80211_channel_to_frequency(channel, band->band);
14035 #endif // endif
14036 	body_len = len;
14037 	err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
14038 		&mgmt_frame, &len, body);
14039 	if (err < 0)
14040 		goto exit;
14041 	isfree = true;
14042 
14043 	if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
14044 			(event == WLC_E_DISASSOC_IND) ||
14045 			((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
14046 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14047 		cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
14048 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14049 		HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame, len);
14050 #endif
14051 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14052 		cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14053 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14054 		defined(WL_COMPAT_WIRELESS)
14055 		cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14056 #else
14057 		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14058 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
14059 	}
14060 
14061 exit:
14062 	if (isfree) {
14063 		MFREE(cfg->osh, mgmt_frame, len);
14064 	}
14065 	if (body) {
14066 		MFREE(cfg->osh, body, body_len);
14067 	}
14068 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14069 	memset(&sinfo, 0, sizeof(struct station_info));
14070 	sinfo.filled = 0;
14071 	if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
14072 		reason == DOT11_SC_SUCCESS) {
14073 		/* Linux ver >= 4.0 assoc_req_ies_len is used instead of
14074 		 * STATION_INFO_ASSOC_REQ_IES flag
14075 		 */
14076 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
14077 		sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
14078 #endif /*  (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
14079 		if (!data) {
14080 			WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
14081 			return -EINVAL;
14082 		}
14083 		sinfo.assoc_req_ies = data;
14084 		sinfo.assoc_req_ies_len = len;
14085 		WL_MSG(ndev->name, "new sta event for "MACDBG "\n",
14086 			MAC2STRDBG(e->addr.octet));
14087 		wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
14088 			WL_EXT_STATUS_STA_CONNECTED, (void *)&e->addr);
14089 		cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
14090 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14091         ChangNewSta(ndev,e->addr.octet,6,&sinfo);
14092 #endif
14093 #ifdef WL_WPS_SYNC
14094 		wl_wps_session_update(ndev, WPS_STATE_LINKUP, e->addr.octet);
14095 #endif /* WL_WPS_SYNC */
14096 	} else if ((event == WLC_E_DEAUTH_IND) ||
14097 		((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
14098 		(event == WLC_E_DISASSOC_IND)) {
14099 		WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14100 			"del sta event for "MACDBG "\n", MAC2STRDBG(e->addr.octet));
14101 		wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
14102 			WL_EXT_STATUS_STA_DISCONNECTED, (void *)&e->addr);
14103 		cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
14104 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14105         ChangDelSta(ndev,e->addr.octet,6);
14106 #endif
14107 #ifdef WL_WPS_SYNC
14108 		wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet);
14109 #endif /* WL_WPS_SYNC */
14110 	}
14111 #ifdef WL_CLIENT_SAE
14112 	else if (event == WLC_E_AUTH) {
14113 		WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14114 			"add sta auth event for "MACDBG "\n", MAC2STRDBG(e->addr.octet));
14115 		if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14116 			WL_ERR(("invalid mode\n"));
14117 			return WL_INVALID;
14118 		}
14119 		err = wl_notify_connect_status_ap_auth(cfg, ndev, e, data);
14120 	}
14121 #endif /* WL_CLIENT_SAE */
14122 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14123 	return err;
14124 }
14125 
14126 #ifdef WL_CLIENT_SAE
14127 static s32
wl_notify_start_auth(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)14128 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
14129 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
14130 {
14131 	struct cfg80211_external_auth_params ext_auth_param;
14132 	struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14133 	u32 datalen = be32_to_cpu(e->datalen);
14134 	wl_ext_auth_evt_t *evt_data = (wl_ext_auth_evt_t *)data;
14135 	wl_assoc_mgr_cmd_t cmd;
14136 	int err;
14137 
14138 	WL_DBG(("Enter\n"));
14139 
14140 	if (!datalen || !data)
14141 		return BCME_ERROR;
14142 
14143 	ext_auth_param.ssid.ssid_len = MIN(evt_data->ssid.SSID_len, DOT11_MAX_SSID_LEN);
14144 	if (ext_auth_param.ssid.ssid_len)
14145 		memcpy(&ext_auth_param.ssid.ssid, evt_data->ssid.SSID,
14146 			ext_auth_param.ssid.ssid_len);
14147 
14148 	memcpy(&ext_auth_param.bssid, &evt_data->bssid, ETHER_ADDR_LEN);
14149 	ext_auth_param.action = NL80211_EXTERNAL_AUTH_START;
14150 	ext_auth_param.key_mgmt_suite = ntoh32(WLAN_AKM_SUITE_SAE_SHA256);
14151 
14152 	WL_MSG(ndev->name, "BSSID: "MACDBG"\n", MAC2STRDBG(&evt_data->bssid));
14153 
14154 	err = cfg80211_external_auth_request(ndev, &ext_auth_param, GFP_KERNEL);
14155 	if (unlikely(err)) {
14156 		WL_ERR(("Failed to notify external auth req(%d)\n", err));
14157 	}
14158 
14159 	cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
14160 	cmd.length = sizeof(cmd);
14161 	cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
14162 	cmd.params = WL_ASSOC_MGR_PARAMS_PAUSE_EVENT_AUTH_RESP;
14163 	err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd),
14164 		cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
14165 	if (unlikely(err)) {
14166 		WL_ERR(("Failed to pause assoc(%d)\n", err));
14167 	}
14168 
14169 	return BCME_OK;
14170 }
14171 
14172 static s32
wl_notify_connect_status_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14173 wl_notify_connect_status_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14174 	const wl_event_msg_t *e, void *data)
14175 {
14176 	s32 err = 0;
14177 	u32 event = ntoh32(e->event_type);
14178 	u32 reason = ntoh32(e->reason);
14179 	u32 len = ntoh32(e->datalen);
14180 	u32 status = ntoh32(e->status);
14181 
14182 	bool isfree = false;
14183 	u8 *mgmt_frame;
14184 	u8 bsscfgidx = e->bsscfgidx;
14185 	s32 freq;
14186 	s32 channel;
14187 	u8 *body = NULL;
14188 	u16 fc = 0, rssi = 0;
14189 	bcm_struct_cfgdev *cfgdev = ndev_to_cfgdev(ndev);
14190 
14191 	struct ieee80211_supported_band *band;
14192 	struct ether_addr da;
14193 	struct ether_addr bssid;
14194 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14195 	channel_info_t ci;
14196 
14197 	WL_DBG(("event %d status %d reason %d\n", event, status, reason));
14198 
14199 	if (event == WLC_E_AUTH) {
14200 		struct wl_security *sec;
14201 		sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14202 
14203 		if (!(sec->auth_type == NL80211_AUTHTYPE_SAE)) {
14204 			WL_DBG(("Abort AUTH processing due to NOT SAE\n"));
14205 			return 0;
14206 		} else {
14207 			if (status != WLC_E_STATUS_SUCCESS && !len) {
14208 				WL_ERR(("SAE AUTH FAIL EVENT\n"));
14209 				wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
14210 					WL_EXT_STATUS_DISCONNECTED, NULL);
14211 				return 0;
14212 			}
14213 		}
14214 	}
14215 
14216 	if (!len && (event == WLC_E_DEAUTH)) {
14217 		len = 2; /* reason code field */
14218 		data = &reason;
14219 	}
14220 
14221 	if (len) {
14222 		body = kzalloc(len, GFP_KERNEL);
14223 		if (body == NULL) {
14224 			WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
14225 			return WL_INVALID;
14226 		}
14227 	}
14228 
14229 	memset(&bssid, 0, ETHER_ADDR_LEN);
14230 	if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14231 		kfree(body);
14232 		return WL_INVALID;
14233 	}
14234 	if (len)
14235 		memcpy(body, data, len);
14236 
14237 	wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
14238 		NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
14239 	memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
14240 	err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14241 	/* Use e->addr as bssid for Sta case , before association completed */
14242 	if (err == BCME_NOTASSOCIATED)
14243 		memcpy(&bssid, &e->addr, ETHER_ADDR_LEN);
14244 
14245 	switch (event) {
14246 		case WLC_E_ASSOC_IND:
14247 			fc = FC_ASSOC_REQ;
14248 			break;
14249 		case WLC_E_REASSOC_IND:
14250 			fc = FC_REASSOC_REQ;
14251 			break;
14252 		case WLC_E_DISASSOC_IND:
14253 			fc = FC_DISASSOC;
14254 			break;
14255 		case WLC_E_DEAUTH_IND:
14256 			fc = FC_DISASSOC;
14257 			break;
14258 		case WLC_E_DEAUTH:
14259 			fc = FC_DISASSOC;
14260 			break;
14261 		case WLC_E_AUTH:
14262 			fc = FC_AUTH;
14263 			break;
14264 		default:
14265 			fc = 0;
14266 			goto exit;
14267 	}
14268 	if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
14269 		kfree(body);
14270 		return err;
14271 	}
14272 
14273 	channel = dtoh32(ci.hw_channel);
14274 	if (channel <= CH_MAX_2G_CHANNEL)
14275 		band = wiphy->bands[IEEE80211_BAND_2GHZ];
14276 	else
14277 		band = wiphy->bands[IEEE80211_BAND_5GHZ];
14278 	if (!band) {
14279 		WL_ERR(("No valid band\n"));
14280 		if (body)
14281 			kfree(body);
14282 		return -EINVAL;
14283 	}
14284 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
14285 	freq = ieee80211_channel_to_frequency(channel);
14286 	(void)band->band;
14287 #else
14288 	freq = ieee80211_channel_to_frequency(channel, band->band);
14289 #endif
14290 
14291 	err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
14292 		&mgmt_frame, &len, body);
14293 	if (err < 0) {
14294 		goto exit;
14295 	}
14296 	isfree = true;
14297 
14298 	if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
14299 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14300 		cfg80211_rx_mgmt(cfgdev, freq, rssi,  mgmt_frame, len, 0);
14301 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14302 		HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, rssi, mgmt_frame, len);
14303 #endif
14304 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14305 		cfg80211_rx_mgmt(cfgdev, freq, 0,  mgmt_frame, len, 0, GFP_ATOMIC);
14306 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14307 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14308 #else
14309 		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14310 #endif
14311 	} else if (event == WLC_E_DISASSOC_IND) {
14312 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14313 		cfg80211_rx_mgmt(cfgdev, freq, rssi,  mgmt_frame, len, 0);
14314 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14315 		HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, rssi, mgmt_frame, len);
14316 #endif
14317 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14318 		cfg80211_rx_mgmt(cfgdev, freq, 0,  mgmt_frame, len, 0, GFP_ATOMIC);
14319 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14320 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14321 #else
14322 		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14323 #endif
14324 	} else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
14325 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14326 		cfg80211_rx_mgmt(cfgdev, freq, rssi,  mgmt_frame, len, 0);
14327 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14328 		HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, rssi, mgmt_frame, len);
14329 #endif
14330 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14331 		cfg80211_rx_mgmt(cfgdev, freq, 0,  mgmt_frame, len, 0, GFP_ATOMIC);
14332 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14333 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14334 #else
14335 		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14336 #endif
14337 	} else if (event == WLC_E_AUTH) {
14338 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14339 		cfg80211_rx_mgmt(cfgdev, freq, rssi,  mgmt_frame, len, 0);
14340 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14341 		HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, rssi, mgmt_frame, len);
14342 #endif
14343 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14344 		cfg80211_rx_mgmt(cfgdev, freq, 0,  mgmt_frame, len, 0, GFP_ATOMIC);
14345 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14346 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14347 #else
14348 		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14349 #endif
14350 	}
14351 exit:
14352 	if (isfree)
14353 		kfree(mgmt_frame);
14354 	if (body)
14355 		kfree(body);
14356 	return err;
14357 }
14358 #endif /* WL_CLIENT_SAE */
14359 
14360 static s32
wl_notify_connect_status_ibss(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14361 wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14362 	const wl_event_msg_t *e, void *data)
14363 {
14364 	s32 err = 0;
14365 	u32 event = ntoh32(e->event_type);
14366 	u16 flags = ntoh16(e->flags);
14367 	u32 status =  ntoh32(e->status);
14368 	bool active;
14369 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14370 	struct ieee80211_channel *channel = NULL;
14371 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14372 	u32 chanspec, chan;
14373 	u32 freq, band;
14374 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14375 
14376 	if (event == WLC_E_JOIN) {
14377 		WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev->name));
14378 	}
14379 	if (event == WLC_E_START) {
14380 		WL_INFORM_MEM(("[%s] started IBSS network\n", ndev->name));
14381 	}
14382 	if (event == WLC_E_JOIN || event == WLC_E_START ||
14383 		(event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
14384 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14385 		err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
14386 		if (unlikely(err)) {
14387 			WL_ERR(("Could not get chanspec %d\n", err));
14388 			return err;
14389 		}
14390 		chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
14391 		band = (chan <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
14392 		freq = ieee80211_channel_to_frequency(chan, band);
14393 		channel = ieee80211_get_channel(wiphy, freq);
14394 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14395 		if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
14396 			/* ROAM or Redundant */
14397 			u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14398 			if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
14399 				WL_DBG(("IBSS connected event from same BSSID("
14400 					MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
14401 				return err;
14402 			}
14403 			WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
14404 				ndev->name, MAC2STRDBG(cur_bssid),
14405 				MAC2STRDBG((const u8 *)&e->addr)));
14406 			wl_get_assoc_ies(cfg, ndev);
14407 			wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14408 			wl_update_bss_info(cfg, ndev, false);
14409 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14410 			cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
14411 #else
14412 			cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
14413 #endif // endif
14414 		}
14415 		else {
14416 			/* New connection */
14417 			WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG "\n",
14418 				ndev->name, MAC2STRDBG((const u8 *)&e->addr)));
14419 			wl_link_up(cfg);
14420 			wl_get_assoc_ies(cfg, ndev);
14421 			wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14422 			wl_update_bss_info(cfg, ndev, false);
14423 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14424 			cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
14425 #else
14426 			cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
14427 #endif // endif
14428 			wl_set_drv_status(cfg, CONNECTED, ndev);
14429 			active = true;
14430 			wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
14431 		}
14432 	} else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
14433 		event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
14434 		wl_clr_drv_status(cfg, CONNECTED, ndev);
14435 		wl_link_down(cfg);
14436 		wl_init_prof(cfg, ndev);
14437 	}
14438 	else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
14439 		WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
14440 	}
14441 	else {
14442 		WL_DBG(("no action (IBSS mode)\n"));
14443 }
14444 	return err;
14445 }
14446 
wl_cfg80211_disassoc(struct net_device * ndev,uint32 reason)14447 void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason)
14448 {
14449 	scb_val_t scbval;
14450 	s32 err;
14451 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14452 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14453 
14454 	BCM_REFERENCE(cfg);
14455 	BCM_REFERENCE(dhdp);
14456 	DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
14457 		dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
14458 
14459 	memset_s(&scbval, sizeof(scb_val_t), 0x0, sizeof(scb_val_t));
14460 	scbval.val = htod32(reason);
14461 	err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
14462 	if (err < 0) {
14463 		WL_ERR(("WLC_DISASSOC error %d\n", err));
14464 	}
14465 }
wl_cfg80211_del_all_sta(struct net_device * ndev,uint32 reason)14466 void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason)
14467 {
14468 	struct net_device *dev;
14469 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14470 	scb_val_t scb_val;
14471 	int err;
14472 	char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
14473 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
14474 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
14475 	int num_associated = 0;
14476 
14477 	dev = ndev_to_wlc_ndev(ndev, cfg);
14478 
14479 	if (p2p_is_on(cfg)) {
14480 		/* Suspend P2P discovery search-listen to prevent it from changing the
14481 		 * channel.
14482 		 */
14483 		if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
14484 			WL_ERR(("Can not disable discovery mode\n"));
14485 			return;
14486 		}
14487 	}
14488 
14489 	assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
14490 	err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
14491 		assoc_maclist, sizeof(mac_buf));
14492 	if (err < 0)
14493 		WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
14494 	else
14495 		num_associated = assoc_maclist->count;
14496 
14497 	memset(scb_val.ea.octet, 0xff, ETHER_ADDR_LEN);
14498 	scb_val.val = DOT11_RC_DEAUTH_LEAVING;
14499 	scb_val.val = htod32(reason);
14500 	err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
14501 			sizeof(scb_val_t));
14502 	if (err < 0) {
14503 		WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
14504 	}
14505 
14506 	if (num_associated > 0)
14507 		wl_delay(400);
14508 
14509 	return;
14510 }
14511 /* API to handle the Deauth from the AP.
14512 * For now we are deleting the PMKID cache in DHD/FW
14513 * in case of current connection is using SAE authnetication
14514 */
14515 static s32
wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14516 wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14517 	const wl_event_msg_t *e, void *data)
14518 {
14519 	int err = BCME_OK;
14520 #ifdef WL_SAE
14521 	uint8 bssid[ETHER_ADDR_LEN];
14522 	struct cfg80211_pmksa pmksa;
14523 	s32 val = 0;
14524 
14525 	err = wldev_iovar_getint(ndev, "wpa_auth", &val);
14526 	if (unlikely(err)) {
14527 		WL_ERR(("could not get wpa_auth (%d)\n", err));
14528 		goto done;
14529 	}
14530 	if (val == WPA3_AUTH_SAE_PSK) {
14531 		(void)memcpy_s(bssid, ETHER_ADDR_LEN,
14532 		(const uint8*)&e->addr, ETHER_ADDR_LEN);
14533 		memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
14534 		pmksa.bssid = bssid;
14535 		WL_INFORM_MEM(("Deleting the PMKSA for SAE AP "MACDBG,
14536 			MAC2STRDBG(e->addr.octet)));
14537 		wl_cfg80211_del_pmksa(cfg->wdev->wiphy, ndev, &pmksa);
14538 	}
14539 done:
14540 #endif /* WL_SAE */
14541 	return err;
14542 }
14543 
14544 static void
wl_cache_assoc_resp_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14545 wl_cache_assoc_resp_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14546 	const wl_event_msg_t *e, void *data)
14547 {
14548 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
14549 	u32 datalen = ntoh32(e->datalen);
14550 	u32 event_type = ntoh32(e->event_type);
14551 
14552 	if (datalen > VNDR_IE_MIN_LEN &&
14553 		datalen < VNDR_IE_MAX_LEN &&
14554 		data) {
14555 		conn_info->resp_ie_len = datalen;
14556 		WL_DBG((" assoc resp IES len = %d\n", conn_info->resp_ie_len));
14557 		bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
14558 		(void)memcpy_s(conn_info->resp_ie, sizeof(conn_info->resp_ie),
14559 			data, datalen);
14560 
14561 		WL_INFORM_MEM(("[%s] copied assoc resp ies, sent to upper layer:"
14562 			"event %d reason=%d ie_len=%d from " MACDBG "\n",
14563 			ndev->name,	event_type, ntoh32(e->reason), datalen,
14564 			MAC2STRDBG((const u8*)(&e->addr))));
14565 	}
14566 }
14567 
14568 #ifdef WLMESH_CFG80211
14569 static s32
wl_notify_connect_status_mesh(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14570 wl_notify_connect_status_mesh(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14571 	const wl_event_msg_t *e, void *data)
14572 {
14573 	s32 err = 0;
14574 	u32 event = ntoh32(e->event_type);
14575 	u32 reason = ntoh32(e->reason);
14576 	u32 len = ntoh32(e->datalen);
14577 	u32 status = ntoh32(e->status);
14578 
14579 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14580 	(LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14581 	bool isfree = false;
14582 	u8 *mgmt_frame;
14583 	u8 bsscfgidx = e->bsscfgidx;
14584 	s32 freq;
14585 	s32 channel;
14586 	u8 *body = NULL;
14587 	u16 fc = 0;
14588 	u32 body_len = 0;
14589 
14590 	struct ieee80211_supported_band *band;
14591 	struct ether_addr da;
14592 	struct ether_addr bssid;
14593 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14594 	channel_info_t ci;
14595 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
14596 #else
14597 	struct station_info sinfo;
14598 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14599 
14600 	WL_INFORM_MEM(("[%s] Mode Mesh. Event:%d status:%d reason:%d\n",
14601 		ndev->name, event, ntoh32(e->status), reason));
14602 
14603 	/* if link down, bsscfg is disabled. */
14604 	if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
14605 			(ndev != bcmcfg_to_prmry_ndev(cfg))) {
14606 		WL_MSG(ndev->name, "Mesh mode link down !! \n");
14607 		return 0;
14608 	}
14609 
14610 	if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
14611 			(reason == WLC_E_REASON_INITIAL_ASSOC)) {
14612 		/* AP/GO brought up successfull in firmware */
14613 		WL_MSG(ndev->name, "Mesh Link up\n");
14614 		return 0;
14615 	}
14616 
14617 	if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
14618 		WL_MSG(ndev->name, "event %s(%d) status %d reason %d\n",
14619 		bcmevent_get_name(event), event, ntoh32(e->status), reason);
14620 	}
14621 
14622 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14623 	(LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14624 	WL_DBG(("Enter \n"));
14625 	if (!len && (event == WLC_E_DEAUTH)) {
14626 		len = 2; /* reason code field */
14627 		data = &reason;
14628 	}
14629 	if (len) {
14630 		body = (u8 *)MALLOCZ(cfg->osh, len);
14631 		if (body == NULL) {
14632 			WL_ERR(("Failed to allocate body\n"));
14633 			return WL_INVALID;
14634 		}
14635 	}
14636 	bzero(&bssid, ETHER_ADDR_LEN);
14637 	WL_DBG(("Enter event %d ndev %p\n", event, ndev));
14638 	if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14639 		MFREE(cfg->osh, body, len);
14640 		return WL_INVALID;
14641 	}
14642 	if (len)
14643 		memcpy(body, data, len);
14644 
14645 	wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
14646 		NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, NULL);
14647 	memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
14648 	bzero(&bssid, sizeof(bssid));
14649 	err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14650 	switch (event) {
14651 		case WLC_E_ASSOC_IND:
14652 			fc = FC_ASSOC_REQ;
14653 			break;
14654 		case WLC_E_REASSOC_IND:
14655 			fc = FC_REASSOC_REQ;
14656 			break;
14657 		case WLC_E_DISASSOC_IND:
14658 			fc = FC_DISASSOC;
14659 			break;
14660 		case WLC_E_DEAUTH_IND:
14661 			fc = FC_DISASSOC;
14662 			break;
14663 		case WLC_E_DEAUTH:
14664 			fc = FC_DISASSOC;
14665 			break;
14666 		default:
14667 			fc = 0;
14668 			goto exit;
14669 	}
14670 	bzero(&ci, sizeof(ci));
14671 	if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
14672 		MFREE(cfg->osh, body, len);
14673 		return err;
14674 	}
14675 
14676 	channel = dtoh32(ci.hw_channel);
14677 	if (channel <= CH_MAX_2G_CHANNEL)
14678 		band = wiphy->bands[IEEE80211_BAND_2GHZ];
14679 	else
14680 		band = wiphy->bands[IEEE80211_BAND_5GHZ];
14681 	if (!band) {
14682 		WL_ERR(("No valid band\n"));
14683 		if (body) {
14684 			MFREE(cfg->osh, body, len);
14685 		}
14686 		return -EINVAL;
14687 	}
14688 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
14689 	freq = ieee80211_channel_to_frequency(channel);
14690 	(void)band->band;
14691 #else
14692 	freq = ieee80211_channel_to_frequency(channel, band->band);
14693 #endif // endif
14694 	body_len = len;
14695 	err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
14696 		&mgmt_frame, &len, body);
14697 	if (err < 0)
14698 		goto exit;
14699 	isfree = true;
14700 
14701 	if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
14702 			(event == WLC_E_DISASSOC_IND) ||
14703 			((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
14704 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14705 		cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
14706 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14707 		HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame, len);
14708 #endif
14709 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14710 		cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14711 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14712 		defined(WL_COMPAT_WIRELESS)
14713 		cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14714 #else
14715 		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14716 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
14717 	}
14718 
14719 exit:
14720 	if (isfree) {
14721 		MFREE(cfg->osh, mgmt_frame, len);
14722 	}
14723 	if (body) {
14724 		MFREE(cfg->osh, body, body_len);
14725 	}
14726 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14727 	memset(&sinfo, 0, sizeof(struct station_info));
14728 	sinfo.filled = 0;
14729 	if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
14730 		reason == DOT11_SC_SUCCESS) {
14731 		/* Linux ver >= 4.0 assoc_req_ies_len is used instead of
14732 		 * STATION_INFO_ASSOC_REQ_IES flag
14733 		 */
14734 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
14735 		sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
14736 #endif /*  (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
14737 		if (!data) {
14738 			WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
14739 			return -EINVAL;
14740 		}
14741 		sinfo.assoc_req_ies = data;
14742 		sinfo.assoc_req_ies_len = len;
14743 		WL_MSG(ndev->name, "new sta event for "MACDBG "\n",
14744 			MAC2STRDBG(e->addr.octet));
14745 		cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
14746 	} else if ((event == WLC_E_DEAUTH_IND) ||
14747 		((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
14748 		(event == WLC_E_DISASSOC_IND)) {
14749 		WL_MSG(ndev->name, "del sta event for "MACDBG "\n",
14750 			MAC2STRDBG(e->addr.octet));
14751 		cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
14752 	}
14753 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14754 	return err;
14755 }
14756 #endif /* WLMESH_CFG80211 */
14757 
14758 #ifdef CONFIG_AP6XXX_WIFI6_HDF
wl_notify_connect_sta_status(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data,bool completed,struct cfg80211_bss * bss)14759 static s32 wl_notify_connect_sta_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14760 	const wl_event_msg_t *e, void *data, bool completed, struct cfg80211_bss *bss)
14761 {
14762 	uint8_t *curbssid = NULL;
14763 	uint16_t connectStatus = 0;
14764 	uint16_t freq = 0;
14765 	struct wl_connect_info *conn_info = NULL;
14766 	struct InnerConnetResult innerConnResult;
14767 	conn_info = wl_to_conn(cfg);
14768 	curbssid = (uint8_t *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14769 
14770 	if(completed) {
14771 		connectStatus = 0;
14772 	} else {
14773 		connectStatus = 1;
14774 	}
14775 
14776     if(bss != NULL) {
14777 		if(bss->channel != NULL) {
14778 			freq = bss->channel->center_freq;
14779 		}
14780 	}
14781 
14782 	innerConnResult.bssid = curbssid;
14783 	innerConnResult.reqIe = conn_info->req_ie;
14784 	innerConnResult.rspIe = conn_info->resp_ie;
14785 	innerConnResult.reqIeLen = conn_info->req_ie_len;
14786 	innerConnResult.rspIeLen = conn_info->resp_ie_len;
14787 	innerConnResult.freq = freq;
14788 	innerConnResult.statusCode = connectStatus;
14789 	innerConnResult.connectStatus = connectStatus;
14790 	HdfConnectResultEventCallback(ndev, &innerConnResult);
14791 
14792 	return 0;
14793 }
14794 #endif
14795 
14796 static s32
wl_notify_connect_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)14797 wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14798 	const wl_event_msg_t *e, void *data)
14799 {
14800 	bool act;
14801 	struct net_device *ndev = NULL;
14802 	s32 err = 0;
14803 	u32 event = ntoh32(e->event_type);
14804 	u32 datalen = ntoh32(e->datalen);
14805 	struct wiphy *wiphy = NULL;
14806 	struct cfg80211_bss *bss = NULL;
14807 	struct wlc_ssid *ssid = NULL;
14808 	u8 *bssid = 0;
14809 	s32 bssidx = 0;
14810 	u8 *ie_ptr = NULL;
14811 	uint32 ie_len = 0;
14812 #ifdef WL_ANALYTICS
14813 	struct parsed_vndr_ies disco_vndr_ie;
14814 	struct parsed_vndr_ie_info *vndrie_info = NULL;
14815 	uint32 i = 0;
14816 #endif /* WL_ANALYTICS */
14817 
14818 	dhd_pub_t *dhdp;
14819 	u32 mode;
14820 	int vndr_oui_num = 0;
14821 	char vndr_oui[MAX_VNDR_OUI_STR_LEN] = {0, };
14822 	bool loc_gen = false;
14823 #ifdef DHD_LOSSLESS_ROAMING
14824 	struct wl_security *sec;
14825 #endif /* DHD_LOSSLESS_ROAMING */
14826 
14827 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14828 #ifdef DHD_LOSSLESS_ROAMING
14829 	sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14830 #endif /* DHD_LOSSLESS_ROAMING */
14831 	dhdp = (dhd_pub_t *)(cfg->pub);
14832 	BCM_REFERENCE(dhdp);
14833 
14834 	mode = wl_get_mode_by_netdev(cfg, ndev);
14835 	/* Push link events to upper layer log */
14836 	SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n",
14837 		ndev->name, mode, ntoh32(e->event_type),
14838 		ntoh32(e->status),  ntoh32(e->reason)));
14839 	if (mode == WL_MODE_AP) {
14840 		err = wl_notify_connect_status_ap(cfg, ndev, e, data);
14841 #ifdef WLMESH_CFG80211
14842 	} else if (mode == WL_MODE_MESH) {
14843 		err = wl_notify_connect_status_mesh(cfg, ndev, e, data);
14844 #endif /* WLMESH_CFG80211 */
14845 	} else if (mode == WL_MODE_IBSS) {
14846 		err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
14847 	} else if (mode == WL_MODE_BSS) {
14848 		WL_INFORM_MEM(("[%s] Mode BSS. event:%d status:%d reason:%d\n",
14849 			ndev->name, ntoh32(e->event_type),
14850 			ntoh32(e->status),  ntoh32(e->reason)));
14851 
14852 		if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
14853 			/* Join attempt via non-cfg80211 interface.
14854 			 * Don't send resultant events to cfg80211
14855 			 * layer
14856 			 */
14857 			WL_INFORM_MEM(("Event received in non-cfg80211"
14858 				" connect state. Ignore\n"));
14859 			return BCME_OK;
14860 		}
14861 #ifdef WL_CLIENT_SAE
14862 		if (event == WLC_E_AUTH)
14863 			wl_notify_connect_status_bss(cfg, ndev, e, data);
14864 #endif /* WL_CLIENT_SAE */
14865 
14866 		if (event == WLC_E_ASSOC || event == WLC_E_AUTH) {
14867 			wl_get_auth_assoc_status(cfg, ndev, e, data);
14868 			return 0;
14869 		}
14870 		if (event == WLC_E_ASSOC_RESP_IE) {
14871 			if (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) {
14872 				wl_cache_assoc_resp_ies(cfg, ndev, e, data);
14873 			}
14874 			return 0;
14875 		}
14876 
14877 		DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
14878 		if (wl_is_linkup(cfg, e, ndev)) {
14879 			wl_link_up(cfg);
14880 			act = true;
14881 			if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
14882 				WL_INFORM_MEM(("[%s] link up for bssid " MACDBG "\n",
14883 					ndev->name, MAC2STRDBG((const u8*)(&e->addr))));
14884 				if ((event == WLC_E_LINK) &&
14885 					(ntoh16(e->flags) & WLC_EVENT_MSG_LINK) &&
14886 					!wl_get_drv_status(cfg, CONNECTED, ndev) &&
14887 					!wl_get_drv_status(cfg, CONNECTING, ndev)) {
14888 					WL_INFORM_MEM(("link up in non-connected/"
14889 						"non-connecting state\n"));
14890 					wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
14891 					return BCME_OK;
14892 				}
14893 
14894 #ifdef WL_WPS_SYNC
14895 				/* Avoid invocation for Roam cases */
14896 				if ((event == WLC_E_LINK) &&
14897 					!wl_get_drv_status(cfg, CONNECTED, ndev)) {
14898 					wl_wps_session_update(ndev,
14899 						WPS_STATE_LINKUP, e->addr.octet);
14900 				}
14901 #endif /* WL_WPS_SYNC */
14902 
14903 				if (event == WLC_E_LINK &&
14904 #ifdef DHD_LOSSLESS_ROAMING
14905 					!cfg->roam_offload &&
14906 					!IS_AKM_SUITE_FT(sec) &&
14907 #endif /* DHD_LOSSLESS_ROAMING */
14908 					wl_get_drv_status(cfg, CONNECTED, ndev)) {
14909 					wl_bss_roaming_done(cfg, ndev, e, data);
14910 					/* Arm pkt logging timer */
14911 					dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
14912 				} else {
14913 					/* Initial Association */
14914 					wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
14915 					wl_bss_connect_done(cfg, ndev, e, data, true);
14916 					if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
14917 						vndr_oui_num = wl_vndr_ies_get_vendor_oui(cfg,
14918 							ndev, vndr_oui, ARRAY_SIZE(vndr_oui));
14919 						if (vndr_oui_num > 0) {
14920 							WL_INFORM_MEM(("[%s] vendor oui: %s\n",
14921 								ndev->name, vndr_oui));
14922 						}
14923 					}
14924 					if (event == WLC_E_LINK) {
14925 						/* Arm pkt logging timer */
14926 						dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_CONNECT);
14927 					}
14928 					WL_DBG(("joined in BSS network \"%s\"\n",
14929 						((struct wlc_ssid *)wl_read_prof(cfg, ndev,
14930 							WL_PROF_SSID))->SSID));
14931 				}
14932 			}
14933 			wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
14934 			wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14935 		} else if (wl_is_linkdown(cfg, e) ||
14936 				((event == WLC_E_SET_SSID) &&
14937 				(ntoh32(e->status) != WLC_E_STATUS_SUCCESS) &&
14938 				(wl_get_drv_status(cfg, CONNECTED, ndev)))) {
14939 			if (wl_is_linkdown(cfg, e)) {
14940 				/* Clear IEs for disaasoc */
14941 				if ((bssidx = wl_get_bssidx_by_wdev(cfg,
14942 					ndev->ieee80211_ptr)) < 0) {
14943 					WL_ERR(("Find index failed\n"));
14944 				} else {
14945 					WL_ERR(("link down--clearing disconnect IEs\n"));
14946 					if ((err =  wl_cfg80211_set_mgmt_vndr_ies(cfg,
14947 						ndev_to_cfgdev(ndev), bssidx, VNDR_IE_DISASSOC_FLAG,
14948 						NULL, 0)) != BCME_OK) {
14949 						WL_ERR(("Failed to clear ies err = %d\n", err));
14950 						}
14951 					}
14952 				}
14953 
14954 			WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n",
14955 				wl_get_drv_status(cfg, CONNECTING, ndev),
14956 				wl_get_drv_status(cfg, CONNECTED, ndev),
14957 				wl_get_drv_status(cfg, DISCONNECTING, ndev),
14958 				wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
14959 
14960 #ifdef WL_WPS_SYNC
14961 			{
14962 				u8 wps_state;
14963 				if ((event == WLC_E_SET_SSID) &&
14964 					(ntoh32(e->status) != WLC_E_STATUS_SUCCESS)) {
14965 					/* connect fail */
14966 					wps_state = WPS_STATE_CONNECT_FAIL;
14967 				} else {
14968 					wps_state = WPS_STATE_LINKDOWN;
14969 				}
14970 				if (wl_wps_session_update(ndev,
14971 					wps_state, e->addr.octet) == BCME_UNSUPPORTED) {
14972 					/* Unexpected event. Ignore it. */
14973 					return 0;
14974 				}
14975 		}
14976 #endif /* WL_WPS_SYNC */
14977 
14978 			if (wl_get_drv_status(cfg, DISCONNECTING, ndev) &&
14979 				(wl_get_drv_status(cfg, NESTED_CONNECT, ndev) ||
14980 				wl_get_drv_status(cfg, CONNECTING, ndev))) {
14981 				/* wl_cfg80211_connect was called before 'DISCONNECTING' was
14982 				 * cleared. Deauth/Link down event is caused by WLC_DISASSOC
14983 				 * command issued from the wl_cfg80211_connect context. Ignore
14984 				 * the event to avoid pre-empting the current connection
14985 				 */
14986 				WL_DBG(("Nested connection case. Drop event. \n"));
14987 				wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
14988 					WL_EXT_STATUS_DISCONNECTED, NULL);
14989 				wl_ext_iapsta_restart_master(ndev);
14990 				wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
14991 				wl_clr_drv_status(cfg, DISCONNECTING, ndev);
14992 				/* Not in 'CONNECTED' state, clear it */
14993 				wl_clr_drv_status(cfg, CONNECTED, ndev);
14994 				return 0;
14995 			}
14996 
14997 			if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
14998 				wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
14999 					FW_LOGSET_MASK_ALL);
15000 			}
15001 #ifdef DHD_LOSSLESS_ROAMING
15002 			wl_del_roam_timeout(cfg);
15003 #endif // endif
15004 #ifdef P2PLISTEN_AP_SAMECHN
15005 			if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15006 				wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0);
15007 				cfg->p2p_resp_apchn_status = false;
15008 				WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
15009 			}
15010 #endif /* P2PLISTEN_AP_SAMECHN */
15011 			wl_cfg80211_cancel_scan(cfg);
15012 
15013 			if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15014 				u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15015 				if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
15016 					bool fw_assoc_state = TRUE;
15017 					dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
15018 					fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
15019 					if (!fw_assoc_state) {
15020 						WL_ERR(("Event sends up even different BSSID"
15021 							" cur: " MACDBG " event: " MACDBG"\n",
15022 							MAC2STRDBG(curbssid),
15023 							MAC2STRDBG((const u8*)(&e->addr))));
15024 					} else {
15025 						WL_ERR(("BSSID of event is not the connected BSSID"
15026 							"(ignore it) cur: " MACDBG
15027 							" event: " MACDBG"\n",
15028 							MAC2STRDBG(curbssid),
15029 							MAC2STRDBG((const u8*)(&e->addr))));
15030 						return 0;
15031 					}
15032 				}
15033 			}
15034 			/* Explicitly calling unlink to remove BSS in CFG */
15035 			wiphy = bcmcfg_to_wiphy(cfg);
15036 			ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
15037 			bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15038 			if (ssid && bssid) {
15039 				bss = CFG80211_GET_BSS(wiphy, NULL, bssid,
15040 					ssid->SSID, ssid->SSID_len);
15041 				if (bss) {
15042 					cfg80211_unlink_bss(wiphy, bss);
15043 					CFG80211_PUT_BSS(wiphy, bss);
15044 				}
15045 			}
15046 
15047 			if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15048 				scb_val_t scbval;
15049 				u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15050 				uint32 reason = 0;
15051 				struct ether_addr bssid_dongle = {{0, 0, 0, 0, 0, 0}};
15052 				struct ether_addr bssid_null = {{0, 0, 0, 0, 0, 0}};
15053 
15054 				if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
15055 					reason = ntoh32(e->reason);
15056 					if (reason > WLC_E_DEAUTH_MAX_REASON) {
15057 						WL_ERR(("Event %d original reason is %d, "
15058 							"changed 0xFF\n", event, reason));
15059 						reason = WLC_E_DEAUTH_MAX_REASON;
15060 					}
15061 					wl_cfg80211_handle_deauth_ind(cfg, ndev, e, data);
15062 				}
15063 				wl_ext_iapsta_restart_master(ndev);
15064 #ifdef SET_SSID_FAIL_CUSTOM_RC
15065 				if ((event == WLC_E_SET_SSID) &&
15066 					(ntoh32(e->status) == WLC_E_STATUS_TIMEOUT)) {
15067 					reason = SET_SSID_FAIL_CUSTOM_RC;
15068 				}
15069 #endif /* SET_SSID_FAIL_CUSTOM_RC */
15070 
15071 				/* roam offload does not sync BSSID always, get it from dongle */
15072 				if (cfg->roam_offload) {
15073 					bzero(&bssid_dongle, sizeof(bssid_dongle));
15074 					if (wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid_dongle,
15075 							sizeof(bssid_dongle)) == BCME_OK) {
15076 						/* if not roam case, it would return null bssid */
15077 						if (memcmp(&bssid_dongle, &bssid_null,
15078 								ETHER_ADDR_LEN) != 0) {
15079 							curbssid = (u8 *)&bssid_dongle;
15080 						}
15081 					}
15082 				}
15083 				if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
15084 					bool fw_assoc_state = TRUE;
15085 					dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
15086 					fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
15087 					if (!fw_assoc_state) {
15088 						WL_ERR(("Event sends up even different BSSID"
15089 							" cur: " MACDBG " event: " MACDBG"\n",
15090 							MAC2STRDBG(curbssid),
15091 							MAC2STRDBG((const u8*)(&e->addr))));
15092 					} else {
15093 						WL_ERR(("BSSID of event is not the connected BSSID"
15094 							"(ignore it) cur: " MACDBG
15095 							" event: " MACDBG"\n",
15096 							MAC2STRDBG(curbssid),
15097 							MAC2STRDBG((const u8*)(&e->addr))));
15098 						return 0;
15099 					}
15100 				}
15101 #ifdef DBG_PKT_MON
15102 				/* Stop packet monitor */
15103 				if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15104 					DHD_DBG_PKT_MON_STOP(dhdp);
15105 				}
15106 #endif /* DBG_PKT_MON */
15107 				/* clear RSSI monitor, framework will set new cfg */
15108 #ifdef RSSI_MONITOR_SUPPORT
15109 				dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
15110 				    FALSE, 0, 0);
15111 #endif /* RSSI_MONITOR_SUPPORT */
15112 				wl_clr_drv_status(cfg, CONNECTED, ndev);
15113 
15114 				if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15115 					DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15116 						dhd_net2idx(dhdp->info, ndev),
15117 						WLAN_REASON_DEAUTH_LEAVING);
15118 					/* To make sure disconnect, explictly send dissassoc
15119 					*  for BSSID 00:00:00:00:00:00 issue
15120 					*/
15121 					scbval.val = WLAN_REASON_DEAUTH_LEAVING;
15122 					WL_INFORM_MEM(("clear fw state\n"));
15123 					memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
15124 					scbval.val = htod32(scbval.val);
15125 					err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
15126 						sizeof(scb_val_t));
15127 					if (err < 0) {
15128 						WL_ERR(("WLC_DISASSOC error %d\n", err));
15129 						err = 0;
15130 					}
15131 				}
15132 				if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15133 					loc_gen = true;
15134 				}
15135 				WL_INFORM_MEM(("[%s] Indicate disconnect event to upper layer. "
15136 					"event: %d reason=%d from " MACDBG "\n",
15137 					ndev->name, event, ntoh32(e->reason),
15138 					MAC2STRDBG((const u8*)(&e->addr))));
15139 
15140 				DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_DONE),
15141 					dhd_net2idx(dhdp->info, ndev), reason);
15142 				/* Send up deauth and clear states */
15143 
15144 				/*
15145 				* FW sends body and body len as a part of deauth
15146 				* and disassoc events (WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND)
15147 				* The VIEs sits after reason code in the body. Reason code is
15148 				* 2 bytes long.
15149 				*/
15150 				WL_DBG(("recv disconnect ies ie_len = %d\n", ie_len));
15151 				if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND) {
15152 					if ((datalen > DOT11_DISCONNECT_RC) &&
15153 						datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
15154 						data) {
15155 						ie_ptr = (uchar*)data + DOT11_DISCONNECT_RC;
15156 						ie_len = datalen - DOT11_DISCONNECT_RC;
15157 					}
15158 				} else if (event == WLC_E_LINK &&
15159 						ntoh32(e->reason) == WLC_E_LINK_BCN_LOSS) {
15160 #ifdef WL_ANALYTICS
15161 					/*
15162 					* In case of linkdown, FW sends prb rsp IEs. Disco VIE
15163 					* are appended with prb rsp ies. Remove prb rsp IES and
15164 					* send disco vie to upper layer.
15165 					* Disco VIE has fixed len of 11 octets.
15166 					* As per SS spec.(2 octet header + 9 octet VIE)
15167 					*/
15168 					if (datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
15169 						datalen >= DOT11_DISCONNECT_RC &&
15170 						((err = wl_cfg80211_parse_vndr_ies(
15171 							(const u8 *)data, datalen,
15172 							&disco_vndr_ie)) == BCME_OK)) {
15173 						for (i = 0; i < disco_vndr_ie.count; i++) {
15174 							vndrie_info = &disco_vndr_ie.ie_info[i];
15175 							if ((vndrie_info->vndrie.id ==
15176 								0xDD) && (!memcmp(
15177 								vndrie_info->vndrie.oui,
15178 								SSE_OUI, DOT11_OUI_LEN)) &&
15179 								(vndrie_info->vndrie.data[0] ==
15180 								VENDOR_ENTERPRISE_STA_OUI_TYPE)) {
15181 							ie_ptr = (u8 *)vndrie_info->ie_ptr;
15182 							ie_len = vndrie_info->ie_len;
15183 							}
15184 						}
15185 					}
15186 #endif /* WL_ANALYTICS */
15187 				}
15188 
15189 #ifdef CONFIG_AP6XXX_WIFI6_HDF
15190                 HdfDisconnectedEventCallback(ndev, reason, ie_ptr, ie_len);
15191 #endif
15192 				CFG80211_DISCONNECTED(ndev, reason, ie_ptr, ie_len,
15193 					loc_gen, GFP_KERNEL);
15194 				WL_INFORM_MEM(("[%s] Disconnect event sent to upper layer"
15195 					"event:%d reason=%d ie_len=%d from " MACDBG "\n",
15196 					ndev->name,	event, ntoh32(e->reason), ie_len,
15197 					MAC2STRDBG((const u8*)(&e->addr))));
15198 
15199 				/* Wait for status to be cleared to prevent race condition
15200 				 * issues with connect context
15201 				 */
15202 				wl_cfg80211_disconnect_state_sync(cfg, ndev);
15203 				wl_link_down(cfg);
15204 				wl_init_prof(cfg, ndev);
15205 			}
15206 			else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
15207 				DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15208 					dhd_net2idx(dhdp->info, ndev), 0);
15209 				WL_INFORM_MEM(("link down, during connecting\n"));
15210 				/* Issue WLC_DISASSOC to prevent FW roam attempts.
15211 				* Do not issue WLC_DISASSOC again if the linkdown  is
15212 				* generated due to local disassoc, to avoid connect-disconnect
15213 				* loop.
15214 				*/
15215 				if (!((event == WLC_E_LINK) &&
15216 					(ntoh32(e->reason) == WLC_E_LINK_DISASSOC) &&
15217 					(ntoh32(e->status) == WLC_E_STATUS_SUCCESS))) {
15218 					err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
15219 					if (err < 0) {
15220 						WL_ERR(("CONNECTING state,"
15221 							" WLC_DISASSOC error %d\n",
15222 							err));
15223 						err = 0;
15224 					}
15225 #ifdef ESCAN_RESULT_PATCH
15226 					if ((memcmp(connect_req_bssid, broad_bssid,
15227 						ETHER_ADDR_LEN) == 0) ||
15228 						(memcmp(&e->addr, broad_bssid,
15229 						ETHER_ADDR_LEN) == 0) ||
15230 						(memcmp(&e->addr, connect_req_bssid,
15231 						ETHER_ADDR_LEN) == 0))
15232 						/* In case this event comes while associating
15233 						* another AP
15234 						*/
15235 #endif /* ESCAN_RESULT_PATCH */
15236 						wl_bss_connect_done(cfg, ndev, e, data, false);
15237 				}
15238 			}
15239 			wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15240 			wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
15241 				WL_EXT_STATUS_DISCONNECTED, NULL);
15242 
15243 			/* if link down, bsscfg is diabled */
15244 			if (ndev != bcmcfg_to_prmry_ndev(cfg))
15245 				complete(&cfg->iface_disable);
15246 #ifdef WLTDLS
15247 			/* re-enable TDLS if the number of connected interfaces
15248 			 * is less than 2.
15249 			 */
15250 			wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
15251 #endif /* WLTDLS */
15252 		} else if (wl_is_nonetwork(cfg, e)) {
15253 			WL_ERR(("connect failed event=%d e->status %d e->reason %d \n",
15254 				event, (int)ntoh32(e->status), (int)ntoh32(e->reason)));
15255 			wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
15256 				WL_EXT_STATUS_DISCONNECTED, NULL);
15257 			wl_ext_iapsta_enable_master_if(ndev, FALSE);
15258 #ifdef WL_WPS_SYNC
15259 			if (wl_wps_session_update(ndev,
15260 				WPS_STATE_CONNECT_FAIL, e->addr.octet) == BCME_UNSUPPORTED) {
15261 				/* Unexpected event. Ignore it. */
15262 				return 0;
15263 			}
15264 #endif /* WL_WPS_SYNC */
15265 			/* Dump FW preserve buffer content */
15266 			wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
15267 
15268 			/* Clean up any pending scan request */
15269 			wl_cfg80211_cancel_scan(cfg);
15270 
15271 			if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
15272 				if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15273 					WL_INFORM_MEM(("wl dissassoc\n"));
15274 					err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
15275 					if (err < 0) {
15276 						WL_ERR(("WLC_DISASSOC error %d\n", err));
15277 						err = 0;
15278 					}
15279 				} else {
15280 					WL_DBG(("connect fail. clear disconnecting bit\n"));
15281 					wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15282 				}
15283 				wl_bss_connect_done(cfg, ndev, e, data, false);
15284 				wl_clr_drv_status(cfg, CONNECTING, ndev);
15285 				WL_INFORM_MEM(("connect fail reported\n"));
15286 			}
15287 		} else {
15288 			WL_DBG(("%s nothing\n", __FUNCTION__));
15289 		}
15290 		DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
15291 	} else {
15292 		WL_MSG(ndev->name, "Invalid mode %d event %d status %d\n",
15293 			wl_get_mode_by_netdev(cfg, ndev), ntoh32(e->event_type),
15294 			ntoh32(e->status));
15295 	}
15296 	return err;
15297 }
15298 
15299 #ifdef WL_RELMCAST
wl_cfg80211_set_rmc_pid(struct net_device * dev,int pid)15300 void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
15301 {
15302 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
15303 	if (pid > 0)
15304 		cfg->rmc_event_pid = pid;
15305 	WL_DBG(("set pid for rmc event : pid=%d\n", pid));
15306 }
15307 #endif /* WL_RELMCAST */
15308 
15309 #ifdef WL_RELMCAST
15310 static s32
wl_notify_rmc_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15311 wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15312 	const wl_event_msg_t *e, void *data)
15313 {
15314 	u32 evt = ntoh32(e->event_type);
15315 	u32 reason = ntoh32(e->reason);
15316 	int ret = -1;
15317 
15318 	switch (reason) {
15319 		case WLC_E_REASON_RMC_AR_LOST:
15320 		case WLC_E_REASON_RMC_AR_NO_ACK:
15321 			if (cfg->rmc_event_pid != 0) {
15322 				ret = wl_netlink_send_msg(cfg->rmc_event_pid,
15323 					RMC_EVENT_LEADER_CHECK_FAIL,
15324 					cfg->rmc_event_seq++, NULL, 0);
15325 			}
15326 			break;
15327 		default:
15328 			break;
15329 	}
15330 	WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
15331 	return ret;
15332 }
15333 #endif /* WL_RELMCAST */
15334 
15335 #ifdef GSCAN_SUPPORT
15336 static s32
wl_handle_roam_exp_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15337 wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15338 	const wl_event_msg_t *e, void *data)
15339 {
15340 	struct net_device *ndev = NULL;
15341 	u32 datalen = be32_to_cpu(e->datalen);
15342 
15343 	if (datalen) {
15344 		wl_roam_exp_event_t *evt_data = (wl_roam_exp_event_t *)data;
15345 		if (evt_data->version == ROAM_EXP_EVENT_VERSION) {
15346 			wlc_ssid_t *ssid = &evt_data->cur_ssid;
15347 			struct wireless_dev *wdev;
15348 			ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15349 			if (ndev) {
15350 				wdev = ndev->ieee80211_ptr;
15351 				wdev->ssid_len = min(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN);
15352 				memcpy(wdev->ssid, ssid->SSID, wdev->ssid_len);
15353 				WL_ERR(("SSID is %s\n", ssid->SSID));
15354 				wl_update_prof(cfg, ndev, NULL, ssid, WL_PROF_SSID);
15355 			} else {
15356 				WL_ERR(("NULL ndev!\n"));
15357 			}
15358 		} else {
15359 			WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
15360 			       ROAM_EXP_EVENT_VERSION));
15361 		}
15362 	}
15363 	return BCME_OK;
15364 }
15365 #endif /* GSCAN_SUPPORT */
15366 
15367 #ifdef RSSI_MONITOR_SUPPORT
wl_handle_rssi_monitor_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15368 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15369 	const wl_event_msg_t *e, void *data)
15370 {
15371 
15372 #if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
15373 	u32 datalen = be32_to_cpu(e->datalen);
15374 	struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15375 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15376 
15377 	if (datalen) {
15378 		wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data;
15379 		if (evt_data->version == RSSI_MONITOR_VERSION) {
15380 			dhd_rssi_monitor_evt_t monitor_data;
15381 			monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION;
15382 			monitor_data.cur_rssi = evt_data->cur_rssi;
15383 			memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN);
15384 			wl_cfgvendor_send_async_event(wiphy, ndev,
15385 				GOOGLE_RSSI_MONITOR_EVENT,
15386 				&monitor_data, sizeof(monitor_data));
15387 		} else {
15388 			WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
15389 			       RSSI_MONITOR_VERSION));
15390 		}
15391 	}
15392 #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
15393 	return BCME_OK;
15394 }
15395 #endif /* RSSI_MONITOR_SUPPORT */
15396 
15397 static s32
wl_notify_roaming_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15398 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15399 	const wl_event_msg_t *e, void *data)
15400 {
15401 	bool act;
15402 	struct net_device *ndev = NULL;
15403 	s32 err = 0;
15404 	u32 event = be32_to_cpu(e->event_type);
15405 	u32 status = be32_to_cpu(e->status);
15406 #ifdef DHD_LOSSLESS_ROAMING
15407 	struct wl_security *sec;
15408 #endif // endif
15409 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15410 	WL_DBG(("Enter \n"));
15411 
15412 	BCM_REFERENCE(dhdp);
15413 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15414 
15415 	if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
15416 		wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
15417 		cfg->disable_roam_event = TRUE;
15418 	}
15419 
15420 	if ((cfg->disable_roam_event) && (event == WLC_E_ROAM))
15421 		return err;
15422 
15423 	if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
15424 		if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15425 #ifdef DHD_LOSSLESS_ROAMING
15426 			sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15427 			/* In order to reduce roaming delay, wl_bss_roaming_done is
15428 			 * early called with WLC_E_LINK event. It is called from
15429 			 * here only if WLC_E_LINK event is blocked for specific
15430 			 * security type.
15431 			 */
15432 			if (IS_AKM_SUITE_FT(sec)) {
15433 				wl_bss_roaming_done(cfg, ndev, e, data);
15434 				/* Arm pkt logging timer */
15435 				dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
15436 			}
15437 			/* Roam timer is deleted mostly from wl_cfg80211_change_station
15438 			 * after roaming is finished successfully. We need to delete
15439 			 * the timer from here only for some security types that aren't
15440 			 * using wl_cfg80211_change_station to authorize SCB
15441 			 */
15442 			if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
15443 				wl_del_roam_timeout(cfg);
15444 			}
15445 #else
15446 #if !defined(DHD_NONFT_ROAMING)
15447 			wl_bss_roaming_done(cfg, ndev, e, data);
15448 #endif /* !DHD_NONFT_ROAMING */
15449 #endif /* DHD_LOSSLESS_ROAMING */
15450 		} else {
15451 			wl_bss_connect_done(cfg, ndev, e, data, true);
15452 		}
15453 		act = true;
15454 		wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
15455 		wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
15456 
15457 		if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15458 			wl_vndr_ies_get_vendor_oui(cfg, ndev, NULL, 0);
15459 		}
15460 	}
15461 #ifdef DHD_LOSSLESS_ROAMING
15462 	else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) {
15463 		wl_del_roam_timeout(cfg);
15464 	}
15465 #endif // endif
15466 	return err;
15467 }
15468 
15469 #ifdef CUSTOM_EVENT_PM_WAKE
15470 uint32 last_dpm_upd_time = 0;	/* ms */
15471 #define DPM_UPD_LMT_TIME	((CUSTOM_EVENT_PM_WAKE + (5)) * (1000) * (4))	/* ms */
15472 #define DPM_UPD_LMT_RSSI	-85	/* dbm */
15473 
15474 static s32
wl_check_pmstatus(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15475 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15476 	const wl_event_msg_t *e, void *data)
15477 {
15478 	s32 err = BCME_OK;
15479 	struct net_device *ndev = NULL;
15480 	u8 *pbuf = NULL;
15481 	uint32 cur_dpm_upd_time = 0;
15482 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
15483 	s32 rssi;
15484 #ifdef SUPPORT_RSSI_SUM_REPORT
15485 	wl_rssi_ant_mimo_t rssi_ant_mimo;
15486 #endif /* SUPPORT_RSSI_SUM_REPORT */
15487 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15488 
15489 	pbuf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
15490 	if (pbuf == NULL) {
15491 		WL_ERR(("failed to allocate local pbuf\n"));
15492 		return -ENOMEM;
15493 	}
15494 
15495 	err = wldev_iovar_getbuf_bsscfg(ndev, "dump",
15496 		"pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN,
15497 		0, &cfg->ioctl_buf_sync);
15498 
15499 	if (err) {
15500 		WL_ERR(("dump ioctl err = %d", err));
15501 	} else {
15502 		WL_ERR(("PM status : %s\n", pbuf));
15503 	}
15504 
15505 	if (pbuf) {
15506 		MFREE(cfg->osh, pbuf, WLC_IOCTL_MEDLEN);
15507 	}
15508 
15509 	if (dhd->early_suspended) {
15510 		/* LCD off */
15511 #ifdef SUPPORT_RSSI_SUM_REPORT
15512 		/* Query RSSI sum across antennas */
15513 		memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
15514 		err = wl_get_rssi_per_ant(ndev, ndev->name, NULL, &rssi_ant_mimo);
15515 		if (err) {
15516 			WL_ERR(("Could not get rssi sum (%d)\n", err));
15517 		}
15518 		rssi = rssi_ant_mimo.rssi_sum;
15519 		if (rssi == 0)
15520 #endif /* SUPPORT_RSSI_SUM_REPORT */
15521 		{
15522 			scb_val_t scb_val;
15523 			memset(&scb_val, 0, sizeof(scb_val_t));
15524 			scb_val.val = 0;
15525 			err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
15526 			if (err) {
15527 				WL_ERR(("Could not get rssi (%d)\n", err));
15528 			}
15529 #if defined(RSSIOFFSET)
15530 			rssi = wl_update_rssi_offset(ndev, dtoh32(scb_val.val));
15531 #else
15532 			rssi = dtoh32(scb_val.val);
15533 #endif
15534 		}
15535 		WL_ERR(("RSSI %d dBm\n", rssi));
15536 		if (rssi > DPM_UPD_LMT_RSSI) {
15537 			return err;
15538 		}
15539 	} else {
15540 		/* LCD on */
15541 		return err;
15542 	}
15543 
15544 	if (last_dpm_upd_time == 0) {
15545 		last_dpm_upd_time = OSL_SYSUPTIME();
15546 	} else {
15547 		cur_dpm_upd_time = OSL_SYSUPTIME();
15548 		if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) {
15549 			scb_val_t scbval;
15550 			DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
15551 				dhd_net2idx(dhd->info, ndev), 0);
15552 			bzero(&scbval, sizeof(scb_val_t));
15553 
15554 			err = wldev_ioctl_set(ndev, WLC_DISASSOC,
15555 				&scbval, sizeof(scb_val_t));
15556 			if (err < 0) {
15557 				WL_ERR(("Disassoc error %d\n", err));
15558 				return err;
15559 			}
15560 			WL_ERR(("Force Disassoc due to updated DPM event.\n"));
15561 
15562 			last_dpm_upd_time = 0;
15563 		} else {
15564 			last_dpm_upd_time = cur_dpm_upd_time;
15565 		}
15566 	}
15567 
15568 	return err;
15569 }
15570 #endif	/* CUSTOM_EVENT_PM_WAKE */
15571 
15572 #ifdef QOS_MAP_SET
15573 /* get user priority table */
15574 uint8 *
wl_get_up_table(dhd_pub_t * dhdp,int idx)15575 wl_get_up_table(dhd_pub_t * dhdp, int idx)
15576 {
15577 	struct net_device *ndev;
15578 	struct bcm_cfg80211 *cfg;
15579 
15580 	ndev = dhd_idx2net(dhdp, idx);
15581 	if (ndev) {
15582 		cfg = wl_get_cfg(ndev);
15583 		if (cfg)
15584 			return (uint8 *)(cfg->up_table);
15585 	}
15586 
15587 	return NULL;
15588 }
15589 #endif /* QOS_MAP_SET */
15590 
15591 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
15592 static s32
wl_notify_roam_prep_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15593 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15594 	const wl_event_msg_t *e, void *data)
15595 {
15596 	struct wl_security *sec;
15597 	struct net_device *ndev;
15598 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15599 	u32 status = ntoh32(e->status);
15600 	u32 reason = ntoh32(e->reason);
15601 
15602 	BCM_REFERENCE(sec);
15603 
15604 	if (status == WLC_E_STATUS_SUCCESS && reason != WLC_E_REASON_INITIAL_ASSOC) {
15605 		WL_ERR(("Attempting roam with reason code : %d\n", reason));
15606 	}
15607 
15608 #ifdef CONFIG_SILENT_ROAM
15609 	if (dhdp->in_suspend && reason == WLC_E_REASON_SILENT_ROAM) {
15610 		dhdp->sroamed = TRUE;
15611 	}
15612 #endif /* CONFIG_SILENT_ROAM */
15613 
15614 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15615 
15616 #ifdef DBG_PKT_MON
15617 	if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15618 		DHD_DBG_PKT_MON_STOP(dhdp);
15619 		DHD_DBG_PKT_MON_START(dhdp);
15620 	}
15621 #endif /* DBG_PKT_MON */
15622 #ifdef DHD_LOSSLESS_ROAMING
15623 	sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15624 	/* Disable Lossless Roaming for specific AKM suite
15625 	 * Any other AKM suite can be added below if transition time
15626 	 * is delayed because of Lossless Roaming
15627 	 * and it causes any certication failure
15628 	 */
15629 	if (IS_AKM_SUITE_FT(sec)) {
15630 		return BCME_OK;
15631 	}
15632 
15633 	dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC;
15634 	/* Restore flow control  */
15635 	dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
15636 
15637 	mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
15638 #endif /* DHD_LOSSLESS_ROAMING */
15639 
15640 	return BCME_OK;
15641 }
15642 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
15643 
15644 static s32
wl_notify_roam_start_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15645 wl_notify_roam_start_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15646 	const wl_event_msg_t *e, void *data)
15647 {
15648 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
15649 	struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15650 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15651 	int event_type;
15652 
15653 	event_type = WIFI_EVENT_ROAM_SCAN_STARTED;
15654 	wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_ROAM_EVENT_START,
15655 		&event_type, sizeof(int));
15656 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || (WL_VENDOR_EXT_SUPPORT) */
15657 
15658 	return BCME_OK;
15659 }
15660 
wl_get_assoc_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev)15661 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
15662 {
15663 	wl_assoc_info_t assoc_info;
15664 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
15665 	s32 err = 0;
15666 #ifdef QOS_MAP_SET
15667 	bcm_tlv_t * qos_map_ie = NULL;
15668 #endif /* QOS_MAP_SET */
15669 
15670 	WL_DBG(("Enter \n"));
15671 	err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
15672 		WL_ASSOC_INFO_MAX, NULL);
15673 	if (unlikely(err)) {
15674 		WL_ERR(("could not get assoc info (%d)\n", err));
15675 		return err;
15676 	}
15677 	memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
15678 	assoc_info.req_len = htod32(assoc_info.req_len);
15679 	assoc_info.resp_len = htod32(assoc_info.resp_len);
15680 	assoc_info.flags = htod32(assoc_info.flags);
15681 	if (conn_info->req_ie_len) {
15682 		conn_info->req_ie_len = 0;
15683 		bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
15684 	}
15685 	if (conn_info->resp_ie_len) {
15686 		conn_info->resp_ie_len = 0;
15687 		bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
15688 	}
15689 
15690 	if (assoc_info.req_len) {
15691 		err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
15692 			assoc_info.req_len, NULL);
15693 		if (unlikely(err)) {
15694 			WL_ERR(("could not get assoc req (%d)\n", err));
15695 			return err;
15696 		}
15697 		if (assoc_info.req_len < sizeof(struct dot11_assoc_req)) {
15698 			WL_ERR(("req_len %d lessthan %d \n", assoc_info.req_len,
15699 				(int)sizeof(struct dot11_assoc_req)));
15700 			return BCME_BADLEN;
15701 		}
15702 		conn_info->req_ie_len = (uint32)(assoc_info.req_len
15703 						- sizeof(struct dot11_assoc_req));
15704 		if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
15705 			conn_info->req_ie_len -= ETHER_ADDR_LEN;
15706 		}
15707 		if (conn_info->req_ie_len <= MAX_REQ_LINE)
15708 			memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
15709 		else {
15710 			WL_ERR(("IE size %d above max %d size \n",
15711 				conn_info->req_ie_len, MAX_REQ_LINE));
15712 			return err;
15713 		}
15714 	} else {
15715 		conn_info->req_ie_len = 0;
15716 	}
15717 
15718 	if (assoc_info.resp_len) {
15719 		err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
15720 			assoc_info.resp_len, NULL);
15721 		if (unlikely(err)) {
15722 			WL_ERR(("could not get assoc resp (%d)\n", err));
15723 			return err;
15724 		}
15725 		if (assoc_info.resp_len < sizeof(struct dot11_assoc_resp)) {
15726 			WL_ERR(("resp_len %d is lessthan %d \n", assoc_info.resp_len,
15727 				(int)sizeof(struct dot11_assoc_resp)));
15728 			return BCME_BADLEN;
15729 		}
15730 		conn_info->resp_ie_len = assoc_info.resp_len -
15731 				(uint32)sizeof(struct dot11_assoc_resp);
15732 		if (conn_info->resp_ie_len <= MAX_REQ_LINE) {
15733 			memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
15734 		} else {
15735 			WL_ERR(("IE size %d above max %d size \n",
15736 				conn_info->resp_ie_len, MAX_REQ_LINE));
15737 			return err;
15738 		}
15739 
15740 #ifdef QOS_MAP_SET
15741 		/* find qos map set ie */
15742 		if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
15743 				DOT11_MNG_QOS_MAP_ID)) != NULL) {
15744 			WL_DBG((" QoS map set IE found in assoc response\n"));
15745 			if (!cfg->up_table) {
15746 				cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
15747 			}
15748 			wl_set_up_table(cfg->up_table, qos_map_ie);
15749 		} else {
15750 			MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
15751 		}
15752 #endif /* QOS_MAP_SET */
15753 	} else {
15754 		conn_info->resp_ie_len = 0;
15755 	}
15756 	WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
15757 		conn_info->resp_ie_len));
15758 
15759 	return err;
15760 }
15761 
wl_ch_to_chanspec(struct net_device * dev,int ch,struct wl_join_params * join_params,size_t * join_params_size)15762 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch, struct wl_join_params *join_params,
15763 	size_t *join_params_size)
15764 {
15765 	chanspec_t chanspec = 0, chspec;
15766 	struct bcm_cfg80211 *cfg =
15767 		(struct bcm_cfg80211 *)wiphy_priv(dev->ieee80211_ptr->wiphy);
15768 
15769 	if ((ch != 0) && (cfg && !cfg->rcc_enabled)) {
15770 		join_params->params.chanspec_num = 1;
15771 		join_params->params.chanspec_list[0] = ch;
15772 
15773 		if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
15774 			chanspec |= WL_CHANSPEC_BAND_2G;
15775 		else
15776 			chanspec |= WL_CHANSPEC_BAND_5G;
15777 
15778 		/* Get the min_bw set for the interface */
15779 		chspec = WL_CHANSPEC_BW_20;
15780 		if (chspec == INVCHANSPEC) {
15781 			WL_ERR(("Invalid chanspec \n"));
15782 			return -EINVAL;
15783 		}
15784 		chanspec |= chspec;
15785 		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
15786 
15787 		*join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
15788 			join_params->params.chanspec_num * sizeof(chanspec_t);
15789 
15790 		join_params->params.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
15791 		join_params->params.chanspec_list[0] |= chanspec;
15792 		join_params->params.chanspec_list[0] =
15793 			wl_chspec_host_to_driver(join_params->params.chanspec_list[0]);
15794 
15795 		join_params->params.chanspec_num =
15796 			htod32(join_params->params.chanspec_num);
15797 	}
15798 #ifdef ESCAN_CHANNEL_CACHE
15799 	else {
15800 		/* If channel is not present and ESCAN_CHANNEL_CACHE is enabled,
15801 		 * use the cached channel list
15802 		 */
15803 		int n_channels;
15804 		n_channels = get_roam_channel_list(ch, join_params->params.chanspec_list,
15805 			MAX_ROAM_CHANNEL, &join_params->ssid, ioctl_version);
15806 		join_params->params.chanspec_num = htod32(n_channels);
15807 		*join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
15808 			join_params->params.chanspec_num * sizeof(chanspec_t);
15809 	}
15810 #endif /* ESCAN_CHANNEL_CACHE */
15811 
15812 	WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
15813 		join_params->params.chanspec_list[0],
15814 		join_params->params.chanspec_num));
15815 	return 0;
15816 }
15817 
wl_update_bss_info(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool update_ssid)15818 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15819 	bool update_ssid)
15820 {
15821 	struct cfg80211_bss *bss;
15822 	wl_bss_info_t *bi;
15823 	struct wlc_ssid *ssid;
15824 	const struct bcm_tlv *tim;
15825 	s32 beacon_interval;
15826 	s32 dtim_period;
15827 	size_t ie_len;
15828 	const u8 *ie;
15829 	u8 *curbssid;
15830 	s32 err = 0;
15831 	struct wiphy *wiphy;
15832 	u32 channel;
15833 	char *buf;
15834 	u32 freq, band;
15835 
15836 	wiphy = bcmcfg_to_wiphy(cfg);
15837 
15838 	ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
15839 	curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15840 	bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
15841 		ssid->SSID, ssid->SSID_len);
15842 	buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
15843 	if (!buf) {
15844 		WL_ERR(("buffer alloc failed.\n"));
15845 		return BCME_NOMEM;
15846 	}
15847 	mutex_lock(&cfg->usr_sync);
15848 	*(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
15849 	err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX);
15850 	if (unlikely(err)) {
15851 		WL_ERR(("Could not get bss info %d\n", err));
15852 		goto update_bss_info_out;
15853 	}
15854 	bi = (wl_bss_info_t *)(buf + 4);
15855 	channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
15856 	wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN);
15857 
15858 	if (!bss) {
15859 		WL_DBG(("Could not find the AP\n"));
15860 		if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
15861 			WL_ERR(("Bssid doesn't match\n"));
15862 			err = -EIO;
15863 			goto update_bss_info_out;
15864 		}
15865 		err = wl_inform_single_bss(cfg, bi, update_ssid);
15866 		if (unlikely(err))
15867 			goto update_bss_info_out;
15868 
15869 		ie = ((u8 *)bi) + bi->ie_offset;
15870 		ie_len = bi->ie_length;
15871 		beacon_interval = cpu_to_le16(bi->beacon_period);
15872 	} else {
15873 		WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
15874 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
15875 		freq = ieee80211_channel_to_frequency(channel);
15876 #else
15877 		band = (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
15878 		freq = ieee80211_channel_to_frequency(channel, band);
15879 #endif // endif
15880 		bss->channel = ieee80211_get_channel(wiphy, freq);
15881 #if defined(WL_CFG80211_P2P_DEV_IF)
15882 		ie = (const u8 *)bss->ies->data;
15883 		ie_len = bss->ies->len;
15884 #else
15885 		ie = bss->information_elements;
15886 		ie_len = bss->len_information_elements;
15887 #endif /* WL_CFG80211_P2P_DEV_IF */
15888 		beacon_interval = bss->beacon_interval;
15889 
15890 		CFG80211_PUT_BSS(wiphy, bss);
15891 	}
15892 
15893 	tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
15894 	if (tim) {
15895 		dtim_period = tim->data[1];
15896 	} else {
15897 		/*
15898 		* active scan was done so we could not get dtim
15899 		* information out of probe response.
15900 		* so we speficially query dtim information.
15901 		*/
15902 		dtim_period = 0;
15903 		err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD,
15904 			&dtim_period, sizeof(dtim_period));
15905 		if (unlikely(err)) {
15906 			WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
15907 			goto update_bss_info_out;
15908 		}
15909 	}
15910 
15911 	wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
15912 	wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
15913 
15914 update_bss_info_out:
15915 	if (unlikely(err)) {
15916 		WL_ERR(("Failed with error %d\n", err));
15917 	}
15918 
15919 	MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
15920 	mutex_unlock(&cfg->usr_sync);
15921 	return err;
15922 }
15923 
15924 static s32
wl_bss_roaming_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)15925 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15926 	const wl_event_msg_t *e, void *data)
15927 {
15928 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
15929 	s32 err = 0;
15930 	u8 *curbssid;
15931 	u32 *channel;
15932 	scb_val_t scbval;
15933 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15934 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15935 	struct ieee80211_supported_band *band;
15936 	struct ieee80211_channel *notify_channel = NULL;
15937 	u32 freq;
15938 	struct channel_info ci;
15939 	u32 cur_channel;
15940 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
15941 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
15942 	(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
15943 	defined(CFG80211_ROAM_API_GE_4_12)
15944 	struct cfg80211_roam_info roam_info;
15945 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
15946 #if defined(WL_FILS_ROAM_OFFLD)
15947 	struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
15948 	struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15949 #endif // endif
15950 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15951 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
15952 	dhd_if_t *ifp = NULL;
15953 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
15954 #ifdef WLFBT
15955 	uint32 data_len = 0;
15956 	if (data)
15957 		data_len = ntoh32(e->datalen);
15958 #endif /* WLFBT */
15959 
15960 	BCM_REFERENCE(dhdp);
15961 	curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15962 	channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
15963 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15964 	/* Skip calling cfg80211_roamed If the channels are same and
15965 	 * the current bssid & the new bssid are same
15966 	 * Also clear timer roam_timeout.
15967 	 * Only used on BCM4359 devices.
15968 	 */
15969 	bzero(&ci, sizeof(ci));
15970 	if ((wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci,
15971 			sizeof(ci))) < 0) {
15972 		WL_ERR(("Failed to get current channel !"));
15973 		err = BCME_ERROR;
15974 		goto fail;
15975 	}
15976 	cur_channel = dtoh32(ci.hw_channel);
15977 	if ((*channel == cur_channel) && ((memcmp(curbssid, &e->addr,
15978 			ETHER_ADDR_LEN) == 0) || (memcmp(&cfg->last_roamed_addr,
15979 			&e->addr, ETHER_ADDR_LEN) == 0))) {
15980 		WL_DBG(("BSS already present, Skipping roamed event to"
15981 		" upper layer\n"));
15982 		goto fail;
15983 	}
15984 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
15985 
15986 	if ((err = wl_get_assoc_ies(cfg, ndev)) != BCME_OK) {
15987 		DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15988 			dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
15989 		WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
15990 			" upper layer\n"));
15991 		/* To make sure disconnect, and fw sync, explictly send dissassoc
15992 		 * for BSSID 00:00:00:00:00:00 issue
15993 		 */
15994 		bzero(&scbval, sizeof(scb_val_t));
15995 		scbval.val = WLAN_REASON_DEAUTH_LEAVING;
15996 		memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
15997 		scbval.val = htod32(scbval.val);
15998 		if (wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
15999 				sizeof(scb_val_t)) < 0) {
16000 			WL_ERR(("WLC_DISASSOC error\n"));
16001 		}
16002 		goto fail;
16003 	}
16004 
16005 	wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID);
16006 	curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16007 	if ((err = wl_update_bss_info(cfg, ndev, true)) != BCME_OK) {
16008 		WL_ERR(("failed to update bss info, err=%d\n", err));
16009 		goto fail;
16010 	}
16011 	wl_update_pmklist(ndev, cfg->pmk_list, err);
16012 
16013 	channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
16014 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16015 	/* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
16016 	if (*channel <= CH_MAX_2G_CHANNEL)
16017 		band = wiphy->bands[IEEE80211_BAND_2GHZ];
16018 	else
16019 		band = wiphy->bands[IEEE80211_BAND_5GHZ];
16020 	freq = ieee80211_channel_to_frequency(*channel, band->band);
16021 	notify_channel = ieee80211_get_channel(wiphy, freq);
16022 #endif /* LINUX_VERSION > 2.6.39  || WL_COMPAT_WIRELESS */
16023 #ifdef WLFBT
16024 	/* back up the given FBT key for the further supplicant request,
16025 	 * currently not checking the FBT is enabled for current BSS in DHD,
16026 	 * because the supplicant decides to take it or not.
16027 	 */
16028 	if (data && (data_len == FBT_KEYLEN)) {
16029 		memcpy(cfg->fbt_key, data, FBT_KEYLEN);
16030 	}
16031 #endif /* WLFBT */
16032 #ifdef CUSTOM_LONG_RETRY_LIMIT
16033 	if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
16034 		WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
16035 	}
16036 #endif /* CUSTOM_LONG_RETRY_LIMIT */
16037 	DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM),
16038 		dhd_net2idx(dhdp->info, ndev), 0);
16039 	WL_ERR(("Report roam event to upper layer. " MACDBG " (ch:%d)\n",
16040 		MAC2STRDBG((const u8*)(&e->addr)), *channel));
16041 	wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
16042 
16043 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16044 	(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
16045 	defined(CFG80211_ROAM_API_GE_4_12)
16046 	memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
16047 	roam_info.channel = notify_channel;
16048 	roam_info.bssid = curbssid;
16049 	roam_info.req_ie = conn_info->req_ie;
16050 	roam_info.req_ie_len = conn_info->req_ie_len;
16051 	roam_info.resp_ie = conn_info->resp_ie;
16052 	roam_info.resp_ie_len = conn_info->resp_ie_len;
16053 #if defined(WL_FILS_ROAM_OFFLD)
16054 	if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
16055 		roam_info.fils.kek = fils_info->fils_kek;
16056 		roam_info.fils.kek_len = fils_info->fils_kek_len;
16057 		roam_info.fils.update_erp_next_seq_num = true;
16058 		roam_info.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
16059 		roam_info.fils.pmk = fils_info->fils_pmk;
16060 		roam_info.fils.pmk_len = fils_info->fils_kek_len;
16061 		roam_info.fils.pmkid = fils_info->fils_pmkid;
16062 	}
16063 #endif // endif
16064 	cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
16065 #else
16066 	cfg80211_roamed(ndev,
16067 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16068 		notify_channel,
16069 #endif // endif
16070 		curbssid,
16071 		conn_info->req_ie, conn_info->req_ie_len,
16072 		conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
16073 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
16074 
16075 	memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
16076 	wl_set_drv_status(cfg, CONNECTED, ndev);
16077 
16078 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16079 	ifp = dhd_get_ifp(dhdp, e->ifidx);
16080 	if (ifp) {
16081 		ifp->post_roam_evt = TRUE;
16082 	}
16083 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
16084 
16085 	return err;
16086 
16087 fail:
16088 #ifdef DHD_LOSSLESS_ROAMING
16089 	wl_del_roam_timeout(cfg);
16090 #endif  /* DHD_LOSSLESS_ROAMING */
16091 	return err;
16092 }
16093 
16094 static bool
wl_cfg80211_verify_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,struct cfg80211_bss ** bss)16095 wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16096 	struct cfg80211_bss **bss)
16097 {
16098 	struct wiphy *wiphy;
16099 	struct wlc_ssid *ssid;
16100 	uint8 *curbssid;
16101 	int count = 0;
16102 	int ret = false;
16103 	u8 cur_ssid[DOT11_MAX_SSID_LEN + 1];
16104 
16105 	wiphy = bcmcfg_to_wiphy(cfg);
16106 	ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
16107 	curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16108 	if (!ssid) {
16109 		WL_ERR(("No SSID found in the saved profile \n"));
16110 		return false;
16111 	}
16112 
16113 	do {
16114 		*bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
16115 			ssid->SSID, ssid->SSID_len);
16116 		if (*bss || (count > 5)) {
16117 			break;
16118 		}
16119 
16120 		count++;
16121 		msleep(100);
16122 	} while (*bss == NULL);
16123 
16124 	WL_DBG(("cfg80211 bss_ptr:%p loop_cnt:%d\n", *bss, count));
16125 	if (*bss) {
16126 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
16127 		/* Update the reference count after use. In case of kernel version >= 4.7
16128 		* the cfg802_put_bss is called in cfg80211_connect_bss context
16129 		*/
16130 		CFG80211_PUT_BSS(wiphy, *bss);
16131 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
16132 		ret = true;
16133 	} else {
16134 		memset(cur_ssid, 0, DOT11_MAX_SSID_LEN);
16135 		strncpy(cur_ssid, ssid->SSID,
16136 			MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN));
16137 		WL_ERR(("No bss entry for ssid:%s bssid:"MACDBG"\n",
16138 			cur_ssid, MAC2STRDBG(curbssid)));
16139 	}
16140 
16141 	return ret;
16142 }
16143 
16144 #ifdef WL_FILS
16145 static s32
wl_get_fils_connect_params(struct bcm_cfg80211 * cfg,struct net_device * ndev)16146 wl_get_fils_connect_params(struct bcm_cfg80211 *cfg, struct net_device *ndev)
16147 {
16148 	const bcm_xtlv_t* pxtlv_out;
16149 	struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
16150 	int err = BCME_OK;
16151 	bcm_iov_buf_t *iov_buf_in = NULL;
16152 	bcm_iov_buf_t iov_buf_out = {0};
16153 	u16 len;
16154 	u16 type;
16155 	const u8 *data;
16156 	iov_buf_in = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
16157 	if (!iov_buf_in) {
16158 		WL_ERR(("buf memory alloc failed\n"));
16159 		err = BCME_NOMEM;
16160 		goto exit;
16161 	}
16162 	iov_buf_out.version = WL_FILS_IOV_VERSION;
16163 	iov_buf_out.id = WL_FILS_CMD_GET_CONNECT_PARAMS;
16164 	err = wldev_iovar_getbuf(ndev, "fils", (uint8*)&iov_buf_out, sizeof(bcm_iov_buf_t),
16165 		iov_buf_in, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
16166 	if (unlikely(err)) {
16167 		WL_ERR(("Get FILS Params Error (%d)\n", err));
16168 		goto exit;
16169 	}
16170 	pxtlv_out = (bcm_xtlv_t*)((bcm_iov_buf_t*)iov_buf_in)->data;
16171 	len = iov_buf_in->len;
16172 	do {
16173 		if (!bcm_valid_xtlv(pxtlv_out, iov_buf_in->len, BCM_XTLV_OPTION_ALIGN32)) {
16174 			WL_ERR(("%s: XTLV is not valid\n", __func__));
16175 			err = BCME_BADARG;
16176 			goto exit;
16177 		}
16178 		bcm_xtlv_unpack_xtlv(pxtlv_out, &type, &len, &data, BCM_XTLV_OPTION_ALIGN32);
16179 		switch (type) {
16180 			case WL_FILS_XTLV_ERP_NEXT_SEQ_NUM:
16181 				fils_info->fils_erp_next_seq_num = *(const u16 *)data;
16182 				break;
16183 			case WL_FILS_XTLV_KEK:
16184 				if (memcpy_s(fils_info->fils_kek,
16185 						WL_MAX_FILS_KEY_LEN, data, len) < 0) {
16186 					err = BCME_BADARG;
16187 					goto exit;
16188 				}
16189 				fils_info->fils_kek_len = len;
16190 				break;
16191 			case WL_FILS_XTLV_PMK:
16192 				if (memcpy_s(fils_info->fils_pmk,
16193 						WL_MAX_FILS_KEY_LEN, data, len) < 0) {
16194 					err = BCME_BADARG;
16195 					goto exit;
16196 				}
16197 				fils_info->fils_pmk_len = len;
16198 				break;
16199 			case WL_FILS_XTLV_PMKID:
16200 				if (memcpy_s(fils_info->fils_pmkid,
16201 						WL_MAX_FILS_KEY_LEN, data, len) < 0) {
16202 					err = BCME_BADARG;
16203 					goto exit;
16204 				}
16205 				break;
16206 			default:
16207 				WL_ERR(("%s: wrong XTLV code\n", __func__));
16208 				break;
16209 
16210 		}
16211 	} while ((pxtlv_out = bcm_next_xtlv(pxtlv_out, (int *)&iov_buf_in->len,
16212 		BCM_XTLV_OPTION_ALIGN32)) && iov_buf_in->len);
16213 exit:
16214 	if (iov_buf_in) {
16215 		MFREE(cfg->osh, iov_buf_in, WLC_IOCTL_SMLEN);
16216 	}
16217 	return err;
16218 }
16219 #endif /* WL_FILS */
16220 static s32
wl_bss_connect_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data,bool completed)16221 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16222 	const wl_event_msg_t *e, void *data, bool completed)
16223 {
16224 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
16225 	struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16226 	s32 err = 0;
16227 #ifdef WL_FILS
16228 	struct cfg80211_connect_resp_params resp_params = {0};
16229 	struct wl_fils_info *fils_info = NULL;
16230 	struct wlc_ssid *ssid = NULL;
16231 	struct wiphy *wiphy = NULL;
16232 
16233 #endif /* WL_FILS */
16234 	u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16235 	u32 event_type = ntoh32(e->event_type);
16236 	struct cfg80211_bss *bss = NULL;
16237 	dhd_pub_t *dhdp;
16238 	dhdp = (dhd_pub_t *)(cfg->pub);
16239 	BCM_REFERENCE(dhdp);
16240 
16241 	if (!sec) {
16242 		WL_ERR(("sec is NULL\n"));
16243 		return -ENODEV;
16244 	}
16245 	WL_DBG((" enter\n"));
16246 #ifdef ESCAN_RESULT_PATCH
16247 	if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
16248 		if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) {
16249 			WL_INFORM_MEM((" Connected event of connected device "
16250 				"e=%d s=%d, ignore it\n",
16251 				ntoh32(e->event_type), ntoh32(e->status)));
16252 			return err;
16253 		}
16254 	}
16255 	if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 &&
16256 		memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) {
16257 		WL_DBG(("copy bssid\n"));
16258 		memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN);
16259 	}
16260 #else
16261 	if (cfg->scan_request) {
16262 		wl_cfg80211_cancel_scan(cfg);
16263 	}
16264 #endif /* ESCAN_RESULT_PATCH */
16265 	if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
16266 		wl_cfg80211_scan_abort(cfg);
16267 		if (completed) {
16268 			wl_get_assoc_ies(cfg, ndev);
16269 			wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
16270 				WL_PROF_BSSID);
16271 			curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16272 			/*
16273 			 * CFG layer relies on cached IEs (from probe/beacon) to fetch matching bss.
16274 			 * For cases, there is no match available,
16275 			 * need to update the cache based on bss info from fw.
16276 			 */
16277 			wl_update_bss_info(cfg, ndev, true);
16278 			wl_update_pmklist(ndev, cfg->pmk_list, err);
16279 			wl_set_drv_status(cfg, CONNECTED, ndev);
16280 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
16281 			if (dhdp->roam_env_detection)
16282 				wldev_iovar_setint(ndev, "roam_env_detection",
16283 					AP_ENV_INDETERMINATE);
16284 #endif /* ROAM_AP_ENV_DETECTION */
16285 			if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
16286 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
16287 				init_completion(&cfg->iface_disable);
16288 #else
16289 				/* reinitialize completion to clear previous count */
16290 				INIT_COMPLETION(cfg->iface_disable);
16291 #endif // endif
16292 			}
16293 #ifdef CUSTOM_SET_CPUCORE
16294 			if (wl_get_chan_isvht80(ndev, dhdp)) {
16295 				if (ndev == bcmcfg_to_prmry_ndev(cfg))
16296 					dhdp->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
16297 				else if (is_p2p_group_iface(ndev->ieee80211_ptr))
16298 					dhdp->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
16299 				dhd_set_cpucore(dhdp, TRUE);
16300 			}
16301 #endif /* CUSTOM_SET_CPUCORE */
16302 #ifdef CUSTOM_LONG_RETRY_LIMIT
16303 			if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
16304 				WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
16305 			}
16306 #endif /* CUSTOM_LONG_RETRY_LIMIT */
16307 			bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
16308 		}
16309 		wl_clr_drv_status(cfg, CONNECTING, ndev);
16310 
16311 		if (completed && (wl_cfg80211_verify_bss(cfg, ndev, &bss) != true)) {
16312 			/* If bss entry is not available in the cfg80211 bss cache
16313 			 * the wireless stack will complain and won't populate
16314 			 * wdev->current_bss ptr
16315 			 */
16316 			WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
16317 			completed = false;
16318 			sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
16319 		}
16320 		if (completed) {
16321 			WL_MSG(ndev->name, "Report connect result - connection succeeded\n");
16322 			wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
16323 			wl_ext_iapsta_enable_master_if(ndev, TRUE);
16324 		} else {
16325 			WL_MSG(ndev->name, "Report connect result - connection failed\n");
16326 			wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
16327 				WL_EXT_STATUS_DISCONNECTED, NULL);
16328 		}
16329 #ifdef WL_FILS
16330 		if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
16331 			wl_get_fils_connect_params(cfg, ndev);
16332 			fils_info = wl_to_fils_info(cfg);
16333 			ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
16334 			wiphy = bcmcfg_to_wiphy(cfg);
16335 			resp_params.status = completed ? WLAN_STATUS_SUCCESS :
16336 				(sec->auth_assoc_res_status) ?
16337 				sec->auth_assoc_res_status :
16338 				WLAN_STATUS_UNSPECIFIED_FAILURE;
16339 			resp_params.bssid = curbssid;
16340 			resp_params.bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
16341 				ssid->SSID, ssid->SSID_len);
16342 			resp_params.req_ie = conn_info->req_ie;
16343 			resp_params.req_ie_len = conn_info->req_ie_len;
16344 			resp_params.resp_ie = conn_info->resp_ie;
16345 			resp_params.resp_ie_len = conn_info->resp_ie_len;
16346 #if defined(WL_FILS_ROAM_OFFLD) || (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0))
16347 			resp_params.fils.kek = fils_info->fils_kek;
16348 			resp_params.fils.kek_len = fils_info->fils_kek_len;
16349 			resp_params.fils.update_erp_next_seq_num = true;
16350 			resp_params.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
16351 			resp_params.fils.pmk = fils_info->fils_pmk;
16352 			resp_params.fils.pmk_len = fils_info->fils_kek_len;
16353 			resp_params.fils.pmkid = fils_info->fils_pmkid;
16354 #else
16355 			resp_params.fils_kek = fils_info->fils_kek;
16356 			resp_params.fils_kek_len = fils_info->fils_kek_len;
16357 			resp_params.update_erp_next_seq_num = true;
16358 			resp_params.fils_erp_next_seq_num = fils_info->fils_erp_next_seq_num;
16359 			resp_params.pmk = fils_info->fils_pmk;
16360 			resp_params.pmk_len = fils_info->fils_kek_len;
16361 			resp_params.pmkid = fils_info->fils_pmkid;
16362 #endif /* WL_FILS_ROAM_OFFLD */
16363 			cfg80211_connect_done(ndev, &resp_params, GFP_KERNEL);
16364 		}
16365 		else
16366 #endif /* WL_FILS */
16367 		{
16368 			CFG80211_CONNECT_RESULT(ndev,
16369 				curbssid,
16370 				bss,
16371 				conn_info->req_ie,
16372 				conn_info->req_ie_len,
16373 				conn_info->resp_ie,
16374 				conn_info->resp_ie_len,
16375 				completed ? WLAN_STATUS_SUCCESS :
16376 				(sec->auth_assoc_res_status) ?
16377 				sec->auth_assoc_res_status :
16378 				WLAN_STATUS_UNSPECIFIED_FAILURE,
16379 				GFP_KERNEL);
16380 
16381 #ifdef CONFIG_AP6XXX_WIFI6_HDF
16382 			wl_notify_connect_sta_status(cfg, ndev, e, data, completed, bss);
16383 #endif
16384 		}
16385 	} else {
16386 		WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
16387 			" connecting:%x. connected:%d\n",
16388 			ndev->name, event_type, wl_get_drv_status(cfg, CONNECTING, ndev),
16389 			wl_get_drv_status(cfg, CONNECTED, ndev)));
16390 	}
16391 #ifdef CONFIG_TCPACK_FASTTX
16392 	if (wl_get_chan_isvht80(ndev, dhdp))
16393 		wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
16394 	else
16395 		wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
16396 #endif /* CONFIG_TCPACK_FASTTX */
16397 
16398 	return err;
16399 }
16400 
16401 static s32
wl_notify_mic_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)16402 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16403 	const wl_event_msg_t *e, void *data)
16404 {
16405 	struct net_device *ndev = NULL;
16406 	u16 flags = ntoh16(e->flags);
16407 	enum nl80211_key_type key_type;
16408 
16409 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16410 
16411 	WL_INFORM_MEM(("[%s] mic fail event - " MACDBG " \n",
16412 		ndev->name, MAC2STRDBG(e->addr.octet)));
16413 	mutex_lock(&cfg->usr_sync);
16414 	if (flags & WLC_EVENT_MSG_GROUP)
16415 		key_type = NL80211_KEYTYPE_GROUP;
16416 	else
16417 		key_type = NL80211_KEYTYPE_PAIRWISE;
16418 
16419 	wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
16420 	cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1,
16421 		NULL, GFP_KERNEL);
16422 	mutex_unlock(&cfg->usr_sync);
16423 
16424 	return 0;
16425 }
16426 
16427 #ifdef BT_WIFI_HANDOVER
16428 static s32
wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)16429 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16430 	const wl_event_msg_t *e, void *data)
16431 {
16432 	struct net_device *ndev = NULL;
16433 	u32 event = ntoh32(e->event_type);
16434 	u32 datalen = ntoh32(e->datalen);
16435 	s32 err;
16436 
16437 	WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen));
16438 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16439 	err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0);
16440 
16441 	return err;
16442 }
16443 #endif /* BT_WIFI_HANDOVER */
16444 
16445 static s32
wl_frame_get_mgmt(struct bcm_cfg80211 * cfg,u16 fc,const struct ether_addr * da,const struct ether_addr * sa,const struct ether_addr * bssid,u8 ** pheader,u32 * body_len,u8 * pbody)16446 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
16447 	const struct ether_addr *da, const struct ether_addr *sa,
16448 	const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody)
16449 {
16450 	struct dot11_management_header *hdr;
16451 	u32 totlen = 0;
16452 	s32 err = 0;
16453 	u8 *offset;
16454 	u32 prebody_len = *body_len;
16455 	switch (fc) {
16456 		case FC_ASSOC_REQ:
16457 			/* capability , listen interval */
16458 			totlen = DOT11_ASSOC_REQ_FIXED_LEN;
16459 			*body_len += DOT11_ASSOC_REQ_FIXED_LEN;
16460 			break;
16461 
16462 		case FC_REASSOC_REQ:
16463 			/* capability, listen inteval, ap address */
16464 			totlen = DOT11_REASSOC_REQ_FIXED_LEN;
16465 			*body_len += DOT11_REASSOC_REQ_FIXED_LEN;
16466 			break;
16467 	}
16468 	totlen += DOT11_MGMT_HDR_LEN + prebody_len;
16469 	*pheader = (u8 *)MALLOCZ(cfg->osh, totlen);
16470 	if (*pheader == NULL) {
16471 		WL_ERR(("memory alloc failed \n"));
16472 		return -ENOMEM;
16473 	}
16474 	hdr = (struct dot11_management_header *) (*pheader);
16475 	hdr->fc = htol16(fc);
16476 	hdr->durid = 0;
16477 	hdr->seq = 0;
16478 	offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
16479 	bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
16480 	bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
16481 	bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
16482 	if ((pbody != NULL) && prebody_len)
16483 		bcopy((const char*)pbody, offset, prebody_len);
16484 	*body_len = totlen;
16485 	return err;
16486 }
16487 
16488 #ifdef WL_CFG80211_GON_COLLISION
16489 static void
wl_gon_req_collision(struct bcm_cfg80211 * cfg,wl_action_frame_t * tx_act_frm,wifi_p2p_pub_act_frame_t * rx_act_frm,struct net_device * ndev,struct ether_addr sa,struct ether_addr da)16490 wl_gon_req_collision(struct bcm_cfg80211 *cfg, wl_action_frame_t *tx_act_frm,
16491 	wifi_p2p_pub_act_frame_t *rx_act_frm, struct net_device *ndev,
16492 	struct ether_addr sa, struct ether_addr da)
16493 {
16494 	if (cfg->afx_hdl->pending_tx_act_frm == NULL)
16495 		return;
16496 
16497 	if (tx_act_frm &&
16498 		wl_cfgp2p_is_pub_action(tx_act_frm->data, tx_act_frm->len)) {
16499 		wifi_p2p_pub_act_frame_t *pact_frm;
16500 
16501 		pact_frm = (wifi_p2p_pub_act_frame_t *)tx_act_frm->data;
16502 
16503 		if (!(pact_frm->subtype == P2P_PAF_GON_REQ &&
16504 			rx_act_frm->subtype == P2P_PAF_GON_REQ)) {
16505 			return;
16506 		}
16507 	}
16508 
16509 	WL_ERR((" GO NEGO Request COLLISION !!! \n"));
16510 
16511 	/* if sa(peer) addr is less than da(my) addr,
16512 	 * my device will process peer's gon request and block to send my gon req.
16513 	 *
16514 	 * if not (sa addr > da addr),
16515 	 * my device will process gon request and drop gon req of peer.
16516 	 */
16517 	if (memcmp(sa.octet, da.octet, ETHER_ADDR_LEN) < 0) {
16518 		/* block to send tx gon request */
16519 		cfg->block_gon_req_tx_count = BLOCK_GON_REQ_MAX_NUM;
16520 		WL_ERR((" block to send gon req tx !!!\n"));
16521 
16522 		/* if we are finding a common channel for sending af,
16523 		 * do not scan more to block to send current gon req
16524 		 */
16525 		if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
16526 			wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, ndev);
16527 			complete(&cfg->act_frm_scan);
16528 		}
16529 	} else {
16530 		/* drop gon request of peer to process gon request by my device. */
16531 		WL_ERR((" drop to receive gon req rx !!! \n"));
16532 		cfg->block_gon_req_rx_count = BLOCK_GON_REQ_MAX_NUM;
16533 	}
16534 
16535 	return;
16536 }
16537 #endif /* WL_CFG80211_GON_COLLISION */
16538 
16539 void
wl_stop_wait_next_action_frame(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 bsscfgidx)16540 wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 bsscfgidx)
16541 {
16542 	s32 err = 0;
16543 
16544 	if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
16545 		if (timer_pending(&cfg->p2p->listen_timer)) {
16546 			del_timer_sync(&cfg->p2p->listen_timer);
16547 		}
16548 		if (cfg->afx_hdl != NULL) {
16549 			if (cfg->afx_hdl->dev != NULL) {
16550 				wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
16551 				wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev);
16552 			}
16553 			cfg->afx_hdl->peer_chan = WL_INVALID;
16554 		}
16555 		complete(&cfg->act_frm_scan);
16556 		WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
16557 	} else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
16558 		if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
16559 			wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
16560 			wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
16561 
16562 		WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx));
16563 		/* Scan engine is not used for sending action frames in the latest driver
16564 		 * branches. actframe_abort is used in the latest driver branches
16565 		 * instead of scan abort.
16566 		 *  If actframe_abort iovar succeeds, don't execute scan abort.
16567 		 *  If actframe_abort fails with unsupported error,
16568 		 *  execute scan abort (for backward copmatibility).
16569 		 */
16570 		if (cfg->af_sent_channel) {
16571 			err = wldev_iovar_setint_bsscfg(ndev, "actframe_abort", 1, bsscfgidx);
16572 			if (err < 0) {
16573 				if (err == BCME_UNSUPPORTED) {
16574 					wl_cfg80211_scan_abort(cfg);
16575 				} else {
16576 					WL_ERR(("actframe_abort failed. ret:%d\n", err));
16577 				}
16578 			}
16579 		}
16580 	}
16581 #ifdef WL_CFG80211_SYNC_GON
16582 	else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
16583 		WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
16584 		/* So abort scan to cancel listen */
16585 		wl_cfg80211_scan_abort(cfg);
16586 	}
16587 #endif /* WL_CFG80211_SYNC_GON */
16588 }
16589 
16590 #if defined(WLTDLS)
wl_cfg80211_is_tdls_tunneled_frame(void * frame,u32 frame_len)16591 bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len)
16592 {
16593 	unsigned char *data;
16594 
16595 	if (frame == NULL) {
16596 		WL_ERR(("Invalid frame \n"));
16597 		return false;
16598 	}
16599 
16600 	if (frame_len < 5) {
16601 		WL_ERR(("Invalid frame length [%d] \n", frame_len));
16602 		return false;
16603 	}
16604 
16605 	data = frame;
16606 
16607 	if (!memcmp(data, TDLS_TUNNELED_PRB_REQ, 5) ||
16608 		!memcmp(data, TDLS_TUNNELED_PRB_RESP, 5)) {
16609 		WL_DBG(("TDLS Vendor Specific Received type\n"));
16610 		return true;
16611 	}
16612 
16613 	return false;
16614 }
16615 #endif /* WLTDLS */
16616 
wl_cfg80211_get_ioctl_version(void)16617 int wl_cfg80211_get_ioctl_version(void)
16618 {
16619 	return ioctl_version;
16620 }
16621 
16622 static s32
wl_notify_rx_mgmt_frame(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)16623 wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16624 	const wl_event_msg_t *e, void *data)
16625 {
16626 	struct ieee80211_supported_band *band;
16627 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
16628 //#ifdef CONFIG_AP6XXX_WIFI6_HDF
16629 //	struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
16630 //#endif
16631 	struct ether_addr da;
16632 	struct ether_addr bssid;
16633 	bool isfree = false;
16634 	s32 err = 0;
16635 	s32 freq;
16636 	struct net_device *ndev = NULL;
16637 	wifi_p2p_pub_act_frame_t *act_frm = NULL;
16638 	wifi_p2p_action_frame_t *p2p_act_frm = NULL;
16639 	wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
16640 	wl_event_rx_frame_data_t *rxframe;
16641 	u32 event;
16642 	u8 *mgmt_frame;
16643 	u8 bsscfgidx;
16644 	u32 mgmt_frame_len;
16645 	u16 channel;
16646 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
16647 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16648 #endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
16649 	if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) {
16650 		WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen)));
16651 		return -EINVAL;
16652 	}
16653 	mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_t);
16654 	event = ntoh32(e->event_type);
16655 	bsscfgidx = e->bsscfgidx;
16656 	rxframe = (wl_event_rx_frame_data_t *)data;
16657 	if (!rxframe) {
16658 		WL_ERR(("rxframe: NULL\n"));
16659 		return -EINVAL;
16660 	}
16661 	channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK);
16662 	bzero(&bssid, ETHER_ADDR_LEN);
16663 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16664 	if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) &&
16665 		(event == WLC_E_PROBREQ_MSG)) {
16666 		struct net_info *iter, *next;
16667 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
16668 		for_each_ndev(cfg, iter, next) {
16669 			GCC_DIAGNOSTIC_POP();
16670 			if (iter->ndev && iter->wdev &&
16671 					iter->wdev->iftype == NL80211_IFTYPE_AP) {
16672 					ndev = iter->ndev;
16673 					cfgdev =  ndev_to_cfgdev(ndev);
16674 					break;
16675 			}
16676 		}
16677 	}
16678 
16679 	if (channel <= CH_MAX_2G_CHANNEL)
16680 		band = wiphy->bands[IEEE80211_BAND_2GHZ];
16681 	else
16682 		band = wiphy->bands[IEEE80211_BAND_5GHZ];
16683 	if (!band) {
16684 		WL_ERR(("No valid band\n"));
16685 		return -EINVAL;
16686 	}
16687 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
16688 	freq = ieee80211_channel_to_frequency(channel);
16689 	(void)band->band;
16690 #else
16691 	freq = ieee80211_channel_to_frequency(channel, band->band);
16692 #endif // endif
16693 	if (event == WLC_E_ACTION_FRAME_RX) {
16694 		u8 ioctl_buf[WLC_IOCTL_SMLEN];
16695 
16696 		if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
16697 				NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx,
16698 				NULL)) != BCME_OK) {
16699 			WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
16700 			goto exit;
16701 		}
16702 
16703 		err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
16704 		if (err < 0)
16705 			 WL_ERR(("WLC_GET_BSSID error %d\n", err));
16706 		memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
16707 		err = wl_frame_get_mgmt(cfg, FC_ACTION, &da, &e->addr, &bssid,
16708 			&mgmt_frame, &mgmt_frame_len,
16709 			(u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
16710 		if (err < 0) {
16711 			WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
16712 				mgmt_frame_len, channel, freq));
16713 			goto exit;
16714 		}
16715 		isfree = true;
16716 		if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16717 			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
16718 			act_frm = (wifi_p2p_pub_act_frame_t *)
16719 					(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
16720 		} else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16721 			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
16722 			p2p_act_frm = (wifi_p2p_action_frame_t *)
16723 					(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
16724 			(void) p2p_act_frm;
16725 		} else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16726 			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
16727 
16728 			sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
16729 					(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
16730 			if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
16731 				if (cfg->next_af_subtype == sd_act_frm->action) {
16732 					WL_DBG(("We got a right next frame of SD!(%d)\n",
16733 						sd_act_frm->action));
16734 					wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16735 
16736 					/* Stop waiting for next AF. */
16737 					wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16738 				}
16739 			}
16740 			(void) sd_act_frm;
16741 #ifdef WLTDLS
16742 		} else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
16743 				(wl_cfg80211_is_tdls_tunneled_frame(
16744 				    &mgmt_frame[DOT11_MGMT_HDR_LEN],
16745 				    mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
16746 			if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
16747 				WL_ERR((" TDLS Action Frame Received type = %d \n",
16748 					mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
16749 			}
16750 #ifdef TDLS_MSG_ONLY_WFD
16751 			if (!dhdp->tdls_mode) {
16752 				WL_DBG((" TDLS Frame filtered \n"));
16753 				goto exit;
16754 			}
16755 #else
16756 			if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
16757 				cfg->tdls_mgmt_frame = mgmt_frame;
16758 				cfg->tdls_mgmt_frame_len = mgmt_frame_len;
16759 				cfg->tdls_mgmt_freq = freq;
16760 				return 0;
16761 			}
16762 #endif /* TDLS_MSG_ONLY_WFD */
16763 #endif /* WLTDLS */
16764 #ifdef QOS_MAP_SET
16765 		} else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
16766 			/* update QoS map set table */
16767 			bcm_tlv_t * qos_map_ie = NULL;
16768 			if ((qos_map_ie = bcm_parse_tlvs(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16769 					mgmt_frame_len - DOT11_MGMT_HDR_LEN,
16770 					DOT11_MNG_QOS_MAP_ID)) != NULL) {
16771 				WL_DBG((" QoS map set IE found in QoS action frame\n"));
16772 				if (!cfg->up_table) {
16773 					cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
16774 				}
16775 				wl_set_up_table(cfg->up_table, qos_map_ie);
16776 			} else {
16777 				MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
16778 			}
16779 #endif /* QOS_MAP_SET */
16780 		} else {
16781 			/*
16782 			 *  if we got normal action frame and ndev is p2p0,
16783 			 *  we have to change ndev from p2p0 to wlan0
16784 			 */
16785 
16786 			if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
16787 				u8 action = 0;
16788 				if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16789 					mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) {
16790 					WL_DBG(("Recived action is not public action frame\n"));
16791 				} else if (cfg->next_af_subtype == action) {
16792 					WL_DBG(("Recived action is the waiting action(%d)\n",
16793 						action));
16794 					wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16795 
16796 					/* Stop waiting for next AF. */
16797 					wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16798 				}
16799 			}
16800 		}
16801 
16802 		if (act_frm) {
16803 #ifdef WL_CFG80211_GON_COLLISION
16804 			if (act_frm->subtype == P2P_PAF_GON_REQ) {
16805 				wl_gon_req_collision(cfg,
16806 					&cfg->afx_hdl->pending_tx_act_frm->action_frame,
16807 					act_frm, ndev, e->addr, da);
16808 
16809 				if (cfg->block_gon_req_rx_count) {
16810 					WL_ERR(("drop frame GON Req Rx : count (%d)\n",
16811 						cfg->block_gon_req_rx_count));
16812 					cfg->block_gon_req_rx_count--;
16813 					goto exit;
16814 				}
16815 			} else if (act_frm->subtype == P2P_PAF_GON_CONF) {
16816 				/* if go formation done, clear it */
16817 				cfg->block_gon_req_tx_count = 0;
16818 				cfg->block_gon_req_rx_count = 0;
16819 			}
16820 #endif /* WL_CFG80211_GON_COLLISION */
16821 
16822 			if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
16823 				if (cfg->next_af_subtype == act_frm->subtype) {
16824 					WL_DBG(("We got a right next frame!(%d)\n",
16825 						act_frm->subtype));
16826 					wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16827 
16828 					if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
16829 						OSL_SLEEP(20);
16830 					}
16831 
16832 					/* Stop waiting for next AF. */
16833 					wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16834 				} else if ((cfg->next_af_subtype == P2P_PAF_GON_RSP) &&
16835 						(act_frm->subtype == P2P_PAF_GON_REQ)) {
16836 					/* If current received frame is GO NEG REQ and next
16837 					 * expected frame is GO NEG RESP, do not send it up.
16838 					 */
16839 					WL_ERR(("GO Neg req received while waiting for RESP."
16840 						"Discard incoming frame\n"));
16841 					goto exit;
16842 				}
16843 			}
16844 		}
16845 
16846 		wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
16847 			mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel);
16848 		if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
16849 			WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
16850 			wl_clr_p2p_status(cfg, GO_NEG_PHASE);
16851 		}
16852 	} else if (event == WLC_E_PROBREQ_MSG) {
16853 
16854 		/* Handle probe reqs frame
16855 		 * WPS-AP certification 4.2.13
16856 		 */
16857 		struct parsed_ies prbreq_ies;
16858 		u32 prbreq_ie_len = 0;
16859 		bool pbc = 0;
16860 
16861 		WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
16862 		mgmt_frame = (u8 *)(data);
16863 		mgmt_frame_len = ntoh32(e->datalen);
16864 		if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) {
16865 			WL_ERR(("wrong datalen:%d\n", mgmt_frame_len));
16866 			return -EINVAL;
16867 		}
16868 		prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
16869 
16870 		/* Parse prob_req IEs */
16871 		if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16872 			prbreq_ie_len, &prbreq_ies) < 0) {
16873 			WL_ERR(("Prob req get IEs failed\n"));
16874 			return 0;
16875 		}
16876 		if (prbreq_ies.wps_ie != NULL) {
16877 			wl_validate_wps_ie(
16878 				(const char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
16879 			WL_DBG((" wps_ie exist pbc = %d\n", pbc));
16880 			/* if pbc method, send prob_req mgmt frame to upper layer */
16881 			if (!pbc)
16882 				return 0;
16883 		} else
16884 			return 0;
16885 	} else {
16886 		mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
16887 
16888 		/* wpa supplicant use probe request event for restarting another GON Req.
16889 		 * but it makes GON Req repetition.
16890 		 * so if src addr of prb req is same as my target device,
16891 		 * do not send probe request event during sending action frame.
16892 		 */
16893 		if (event == WLC_E_P2P_PROBREQ_MSG) {
16894 			WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
16895 				"WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
16896 
16897 #ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
16898 			if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) &&
16899 				!memcmp(cfg->afx_hdl->tx_dst_addr.octet, e->addr.octet,
16900 				ETHER_ADDR_LEN)) {
16901 				if (cfg->afx_hdl->pending_tx_act_frm &&
16902 					wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
16903 					s32 channel = CHSPEC_CHANNEL(hton16(rxframe->channel));
16904 					WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
16905 						channel));
16906 					cfg->afx_hdl->peer_chan = channel;
16907 					complete(&cfg->act_frm_scan);
16908 				}
16909 			}
16910 #endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
16911 
16912 			/* Filter any P2P probe reqs arriving during the
16913 			 * GO-NEG Phase
16914 			 */
16915 			if (cfg->p2p &&
16916 #if defined(P2P_IE_MISSING_FIX)
16917 				cfg->p2p_prb_noti &&
16918 #endif // endif
16919 				wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
16920 				WL_DBG(("Filtering P2P probe_req while "
16921 					"being in GO-Neg state\n"));
16922 				return 0;
16923 			}
16924 		}
16925 	}
16926 
16927 	if (discover_cfgdev(cfgdev, cfg))
16928 		WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
16929 	else
16930 		WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
16931 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
16932 	 cfg80211_rx_mgmt(cfgdev, freq, 0,  mgmt_frame, mgmt_frame_len, 0);
16933 #ifdef CONFIG_AP6XXX_WIFI6_HDF
16934 	HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame, mgmt_frame_len);
16935 #endif
16936 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
16937 	cfg80211_rx_mgmt(cfgdev, freq, 0,  mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
16938 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
16939 	defined(WL_COMPAT_WIRELESS)
16940 	cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
16941 #else
16942 	cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
16943 #endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
16944 
16945 	WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
16946 		mgmt_frame_len, ntoh32(e->datalen), channel, freq));
16947 exit:
16948 	if (isfree) {
16949 		MFREE(cfg->osh, mgmt_frame, mgmt_frame_len);
16950 	}
16951 	return err;
16952 }
16953 
wl_init_conf(struct wl_conf * conf)16954 static void wl_init_conf(struct wl_conf *conf)
16955 {
16956 	WL_DBG(("Enter \n"));
16957 	conf->frag_threshold = (u32)-1;
16958 	conf->rts_threshold = (u32)-1;
16959 	conf->retry_short = (u32)-1;
16960 	conf->retry_long = (u32)-1;
16961 	conf->tx_power = -1;
16962 }
16963 
wl_init_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev)16964 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
16965 {
16966 	unsigned long flags;
16967 	struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
16968 
16969 	if (!profile) {
16970 		WL_ERR(("profile null\n"));
16971 		return;
16972 	}
16973 
16974 	WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
16975 	bzero(profile, sizeof(struct wl_profile));
16976 	WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
16977 }
16978 
wl_init_event_handler(struct bcm_cfg80211 * cfg)16979 static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
16980 {
16981 	bzero(cfg->evt_handler, sizeof(cfg->evt_handler));
16982 
16983 	cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
16984 	cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
16985 	cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
16986 	cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
16987 	cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
16988 	cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
16989 	cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
16990 	cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
16991 	cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
16992 	cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
16993 	cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
16994 	cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
16995 	cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
16996 	cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
16997 	cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
16998 	cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
16999 	cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
17000 	cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
17001 	cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
17002 	cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
17003 	cfg->evt_handler[WLC_E_AUTH_IND] = wl_notify_connect_status;
17004 	cfg->evt_handler[WLC_E_ASSOC_RESP_IE] = wl_notify_connect_status;
17005 #ifdef PNO_SUPPORT
17006 	cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
17007 #endif /* PNO_SUPPORT */
17008 #ifdef GSCAN_SUPPORT
17009 	cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
17010 	cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
17011 	cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
17012 	cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
17013 	cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
17014 	cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
17015 	cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
17016 	cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
17017 #endif /* GSCAN_SUPPORT */
17018 #ifdef RSSI_MONITOR_SUPPORT
17019 	cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
17020 #endif /* RSSI_MONITOR_SUPPORT */
17021 #ifdef WLTDLS
17022 	cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
17023 #endif /* WLTDLS */
17024 	cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
17025 #ifdef	WL_RELMCAST
17026 	cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
17027 #endif /* WL_RELMCAST */
17028 #ifdef BT_WIFI_HANDOVER
17029 	cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
17030 #endif // endif
17031 #ifdef WL_NAN
17032 	cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status;
17033 	cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status;
17034 #endif /* WL_NAN */
17035 	cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
17036 	cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
17037 #ifdef CUSTOM_EVENT_PM_WAKE
17038 	cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
17039 #endif	/* CUSTOM_EVENT_PM_WAKE */
17040 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
17041 	cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
17042 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON  */
17043 	cfg->evt_handler[WLC_E_ROAM_START] = wl_notify_roam_start_status;
17044 	cfg->evt_handler[WLC_E_PSK_SUP] = wl_cfg80211_sup_event_handler;
17045 #ifdef WL_BCNRECV
17046 	cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
17047 #endif /* WL_BCNRECV */
17048 #ifdef WL_MBO
17049 	cfg->evt_handler[WLC_E_MBO] = wl_mbo_event_handler;
17050 #endif  /* WL_MBO */
17051 #ifdef WL_CAC_TS
17052 	cfg->evt_handler[WLC_E_ADDTS_IND] = wl_cfg80211_cac_event_handler;
17053 	cfg->evt_handler[WLC_E_DELTS_IND] = wl_cfg80211_cac_event_handler;
17054 #endif /* WL_CAC_TS */
17055 #if defined(WL_MBO) || defined(WL_OCE)
17056 	cfg->evt_handler[WLC_E_PRUNE] = wl_bssid_prune_event_handler;
17057 #endif /* WL_MBO || WL_OCE */
17058 #ifdef RTT_SUPPORT
17059 	cfg->evt_handler[WLC_E_PROXD] = wl_cfg80211_rtt_event_handler;
17060 #endif // endif
17061 #ifdef WL_CHAN_UTIL
17062 	cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler;
17063 #endif /* WL_CHAN_UTIL */
17064 #ifdef WL_CLIENT_SAE
17065 	cfg->evt_handler[WLC_E_JOIN_START] = wl_notify_start_auth;
17066 #endif /* WL_CLIENT_SAE */
17067 }
17068 
17069 #ifdef WL_CLIENT_SAE
17070 /** Called by the cfg80211 framework */
17071 static s32
wl_cfg80211_external_auth(struct wiphy * wiphy,struct net_device * ndev,struct cfg80211_external_auth_params * ext_auth_param)17072 wl_cfg80211_external_auth(struct wiphy *wiphy,
17073 	struct net_device *ndev, struct cfg80211_external_auth_params *ext_auth_param)
17074 {
17075 	int err = 0;
17076 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
17077 	wl_assoc_mgr_cmd_t cmd;
17078 
17079 	WL_DBG(("Enter\n"));
17080 
17081 	if (!ext_auth_param ||
17082 		ETHER_ISNULLADDR(ext_auth_param->bssid)) {
17083 		WL_ERR(("Invalid wl_cfg80211_external_auth param\n"));
17084 		return -EINVAL;
17085 	}
17086 
17087 	cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
17088 	cmd.length = sizeof(cmd);
17089 	cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
17090 	cmd.params = WL_ASSOC_MGR_PARAMS_EVENT_NONE;
17091 	err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd), cfg->ioctl_buf,
17092 		WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
17093 	if (unlikely(err)) {
17094 		WL_ERR(("Failed to pause assoc(%d)\n", err));
17095 	}
17096 
17097 	return err;
17098 }
17099 #endif /* WL_CLIENT_SAE */
17100 
17101 #if defined(STATIC_WL_PRIV_STRUCT)
17102 static int
wl_init_escan_result_buf(struct bcm_cfg80211 * cfg)17103 wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
17104 {
17105 #ifdef DUAL_ESCAN_RESULT_BUFFER
17106 	cfg->escan_info.escan_buf[0] = DHD_OS_PREALLOC(cfg->pub,
17107 		DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
17108 	if (cfg->escan_info.escan_buf[0] == NULL) {
17109 		WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
17110 		return -ENOMEM;
17111 	}
17112 
17113 	cfg->escan_info.escan_buf[1] = DHD_OS_PREALLOC(cfg->pub,
17114 		DHD_PREALLOC_WIPHY_ESCAN1, ESCAN_BUF_SIZE);
17115 	if (cfg->escan_info.escan_buf[1] == NULL) {
17116 		WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
17117 		return -ENOMEM;
17118 	}
17119 
17120 	bzero(cfg->escan_info.escan_buf[0], ESCAN_BUF_SIZE);
17121 	bzero(cfg->escan_info.escan_buf[1], ESCAN_BUF_SIZE);
17122 	cfg->escan_info.escan_type[0] = 0;
17123 	cfg->escan_info.escan_type[1] = 0;
17124 #else
17125 	cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
17126 		DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
17127 	if (cfg->escan_info.escan_buf == NULL) {
17128 		WL_ERR(("Failed to alloc ESCAN_BUF\n"));
17129 		return -ENOMEM;
17130 	}
17131 	bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
17132 #endif /* DUAL_ESCAN_RESULT_BUFFER */
17133 
17134 	return 0;
17135 }
17136 
17137 static void
wl_deinit_escan_result_buf(struct bcm_cfg80211 * cfg)17138 wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
17139 {
17140 #ifdef DUAL_ESCAN_RESULT_BUFFER
17141 	if (cfg->escan_info.escan_buf[0] != NULL) {
17142 		cfg->escan_info.escan_buf[0] = NULL;
17143 		cfg->escan_info.escan_type[0] = 0;
17144 	}
17145 
17146 	if (cfg->escan_info.escan_buf[1] != NULL) {
17147 		cfg->escan_info.escan_buf[1] = NULL;
17148 		cfg->escan_info.escan_type[1] = 0;
17149 	}
17150 #else
17151 	if (cfg->escan_info.escan_buf != NULL) {
17152 		cfg->escan_info.escan_buf = NULL;
17153 	}
17154 #endif /* DUAL_ESCAN_RESULT_BUFFER */
17155 }
17156 #endif /* STATIC_WL_PRIV_STRUCT */
17157 
wl_init_priv_mem(struct bcm_cfg80211 * cfg)17158 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
17159 {
17160 	WL_DBG(("Enter \n"));
17161 
17162 	cfg->scan_results = (struct wl_scan_results *)MALLOCZ(cfg->osh,
17163 		WL_SCAN_BUF_MAX);
17164 	if (unlikely(!cfg->scan_results)) {
17165 		WL_ERR(("Scan results alloc failed\n"));
17166 		goto init_priv_mem_out;
17167 	}
17168 	cfg->conf = (struct wl_conf *)MALLOCZ(cfg->osh, sizeof(*cfg->conf));
17169 	if (unlikely(!cfg->conf)) {
17170 		WL_ERR(("wl_conf alloc failed\n"));
17171 		goto init_priv_mem_out;
17172 	}
17173 	cfg->scan_req_int = (void *)MALLOCZ(cfg->osh,
17174 		sizeof(*cfg->scan_req_int));
17175 	if (unlikely(!cfg->scan_req_int)) {
17176 		WL_ERR(("Scan req alloc failed\n"));
17177 		goto init_priv_mem_out;
17178 	}
17179 	cfg->ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
17180 	if (unlikely(!cfg->ioctl_buf)) {
17181 		WL_ERR(("Ioctl buf alloc failed\n"));
17182 		goto init_priv_mem_out;
17183 	}
17184 	cfg->escan_ioctl_buf = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
17185 	if (unlikely(!cfg->escan_ioctl_buf)) {
17186 		WL_ERR(("Ioctl buf alloc failed\n"));
17187 		goto init_priv_mem_out;
17188 	}
17189 	cfg->extra_buf = (void *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
17190 	if (unlikely(!cfg->extra_buf)) {
17191 		WL_ERR(("Extra buf alloc failed\n"));
17192 		goto init_priv_mem_out;
17193 	}
17194 	cfg->pmk_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->pmk_list));
17195 	if (unlikely(!cfg->pmk_list)) {
17196 		WL_ERR(("pmk list alloc failed\n"));
17197 		goto init_priv_mem_out;
17198 	}
17199 #if defined(STATIC_WL_PRIV_STRUCT)
17200 	cfg->conn_info = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->conn_info));
17201 	if (unlikely(!cfg->conn_info)) {
17202 		WL_ERR(("cfg->conn_info alloc failed\n"));
17203 		goto init_priv_mem_out;
17204 	}
17205 	cfg->ie = (void *)MALLOC(cfg->osh, sizeof(*cfg->ie));
17206 	if (unlikely(!cfg->ie)) {
17207 		WL_ERR(("cfg->ie alloc failed\n"));
17208 		goto init_priv_mem_out;
17209 	}
17210 	if (unlikely(wl_init_escan_result_buf(cfg))) {
17211 		WL_ERR(("Failed to init escan resul buf\n"));
17212 		goto init_priv_mem_out;
17213 	}
17214 #endif /* STATIC_WL_PRIV_STRUCT */
17215 	cfg->afx_hdl = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->afx_hdl));
17216 	if (unlikely(!cfg->afx_hdl)) {
17217 		WL_ERR(("afx hdl alloc failed\n"));
17218 		goto init_priv_mem_out;
17219 	} else {
17220 		init_completion(&cfg->act_frm_scan);
17221 		init_completion(&cfg->wait_next_af);
17222 
17223 		INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
17224 	}
17225 #ifdef WLTDLS
17226 	if (cfg->tdls_mgmt_frame) {
17227 		MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
17228 		cfg->tdls_mgmt_frame = NULL;
17229 		cfg->tdls_mgmt_frame_len = 0;
17230 	}
17231 #endif /* WLTDLS */
17232 	return 0;
17233 
17234 init_priv_mem_out:
17235 	wl_deinit_priv_mem(cfg);
17236 
17237 	return -ENOMEM;
17238 }
17239 
wl_deinit_priv_mem(struct bcm_cfg80211 * cfg)17240 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
17241 {
17242 	MFREE(cfg->osh, cfg->scan_results, WL_SCAN_BUF_MAX);
17243 	MFREE(cfg->osh, cfg->conf, sizeof(*cfg->conf));
17244 	MFREE(cfg->osh, cfg->scan_req_int, sizeof(*cfg->scan_req_int));
17245 	MFREE(cfg->osh, cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
17246 	MFREE(cfg->osh, cfg->escan_ioctl_buf, WLC_IOCTL_MAXLEN);
17247 	MFREE(cfg->osh, cfg->extra_buf, WL_EXTRA_BUF_MAX);
17248 	MFREE(cfg->osh, cfg->pmk_list, sizeof(*cfg->pmk_list));
17249 #if defined(STATIC_WL_PRIV_STRUCT)
17250 	MFREE(cfg->osh, cfg->conn_info, sizeof(*cfg->conn_info));
17251 	MFREE(cfg->osh, cfg->ie, sizeof(*cfg->ie));
17252 	wl_deinit_escan_result_buf(cfg);
17253 #endif /* STATIC_WL_PRIV_STRUCT */
17254 	if (cfg->afx_hdl) {
17255 		cancel_work_sync(&cfg->afx_hdl->work);
17256 		MFREE(cfg->osh, cfg->afx_hdl, sizeof(*cfg->afx_hdl));
17257 	}
17258 
17259 }
17260 
wl_create_event_handler(struct bcm_cfg80211 * cfg)17261 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
17262 {
17263 	int ret = 0;
17264 	WL_DBG(("Enter \n"));
17265 
17266 	/* Allocate workqueue for event */
17267 	if (!cfg->event_workq) {
17268 		cfg->event_workq = alloc_workqueue("dhd_eventd",
17269 			WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 1);
17270 	}
17271 
17272 	if (!cfg->event_workq) {
17273 		WL_ERR(("event_workq alloc_workqueue failed\n"));
17274 		ret = -ENOMEM;
17275 	} else {
17276 		INIT_WORK(&cfg->event_work, wl_event_handler);
17277 	}
17278 	return ret;
17279 }
17280 
wl_destroy_event_handler(struct bcm_cfg80211 * cfg)17281 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
17282 {
17283 	if (cfg && cfg->event_workq) {
17284 		cancel_work_sync(&cfg->event_work);
17285 		destroy_workqueue(cfg->event_workq);
17286 		cfg->event_workq = NULL;
17287 	}
17288 }
17289 
wl_terminate_event_handler(struct net_device * dev)17290 void wl_terminate_event_handler(struct net_device *dev)
17291 {
17292 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17293 
17294 	if (cfg) {
17295 		wl_destroy_event_handler(cfg);
17296 		wl_flush_eq(cfg);
17297 	}
17298 }
17299 
17300 #ifdef DHD_LOSSLESS_ROAMING
wl_del_roam_timeout(struct bcm_cfg80211 * cfg)17301 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
17302 {
17303 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
17304 
17305 	/* restore prec_map to ALLPRIO */
17306 	dhdp->dequeue_prec_map = ALLPRIO;
17307 	if (timer_pending(&cfg->roam_timeout)) {
17308 		del_timer_sync(&cfg->roam_timeout);
17309 	}
17310 
17311 }
17312 
wl_roam_timeout(unsigned long data)17313 static void wl_roam_timeout(unsigned long data)
17314 {
17315 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
17316 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
17317 
17318 	WL_ERR(("roam timer expired\n"));
17319 
17320 	/* restore prec_map to ALLPRIO */
17321 	dhdp->dequeue_prec_map = ALLPRIO;
17322 }
17323 
17324 #endif /* DHD_LOSSLESS_ROAMING */
17325 
17326 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
17327 #define CP_CHAN_INFO_RAT_MODE_LTE	3
17328 #define CP_CHAN_INFO_RAT_MODE_NR5G	7
17329 int g_mhs_chan_for_cpcoex = 0;
17330 
17331 struct __packed cam_cp_noti_info {
17332 	u8 rat;
17333 	u32 band;
17334 	u32 channel;
17335 };
17336 
17337 int
wl_cfg80211_send_msg_to_ril()17338 wl_cfg80211_send_msg_to_ril()
17339 {
17340 	int id, buf = 1;
17341 
17342 	id = IPC_SYSTEM_CP_CHANNEL_INFO;
17343 	dev_ril_bridge_send_msg(id, sizeof(int), &buf);
17344 	WL_ERR(("[BeyondX] send message to ril.\n"));
17345 
17346 	OSL_SLEEP(500);
17347 	return 0;
17348 }
17349 
17350 int
wl_cfg80211_ril_bridge_notifier_call(struct notifier_block * nb,unsigned long size,void * buf)17351 wl_cfg80211_ril_bridge_notifier_call(struct notifier_block *nb,
17352 	unsigned long size, void *buf)
17353 {
17354 	struct dev_ril_bridge_msg *msg;
17355 	struct cam_cp_noti_info *cp_noti_info;
17356 	static int mhs_channel_for_4g, mhs_channel_for_5g;
17357 	static int recv_msg_4g, recv_msg_5g;
17358 
17359 	WL_ERR(("[BeyondX] receive message from ril.\n"));
17360 	msg = (struct dev_ril_bridge_msg *)buf;
17361 
17362 	if (msg->dev_id == IPC_SYSTEM_CP_CHANNEL_INFO &&
17363 		msg->data_len <= sizeof(struct cam_cp_noti_info)) {
17364 		u8 rat;
17365 		u32 band;
17366 		u32 channel;
17367 
17368 		cp_noti_info = (struct cam_cp_noti_info *)msg->data;
17369 		rat = cp_noti_info->rat;
17370 		band = cp_noti_info->band;
17371 		channel = cp_noti_info->channel;
17372 
17373 		/* LTE/5G Band/Freq information => Mobile Hotspot channel mapping.
17374 		 * LTE/B40: 38650~39649 => Ch.11
17375 		 * LTE/B41: 39650~41589 => Ch.1
17376 		 * 5G/N41: 499200~537999 => Ch.1
17377 		 */
17378 		if (rat == CP_CHAN_INFO_RAT_MODE_LTE) {
17379 			recv_msg_4g = 1;
17380 			if (channel >= 38650 && channel <= 39649) {
17381 				mhs_channel_for_4g = 11;
17382 			} else if (channel >= 39650 && channel <= 41589) {
17383 				mhs_channel_for_4g = 1;
17384 			}
17385 		}
17386 		if (rat == CP_CHAN_INFO_RAT_MODE_NR5G) {
17387 			recv_msg_5g = 1;
17388 			if (channel >= 499200 && channel <= 537999) {
17389 				mhs_channel_for_5g = 1;
17390 			}
17391 		}
17392 
17393 		WL_DBG(("[BeyondX] rat: %u, band: %u, channel: %u, mhs_channel_for_4g: %u, "
17394 			"mhs_channel_for_5g: %u\n", rat, band, channel,
17395 			mhs_channel_for_4g, mhs_channel_for_5g));
17396 
17397 		if (recv_msg_4g && recv_msg_5g) {
17398 			if (mhs_channel_for_4g && mhs_channel_for_5g) {
17399 				/* if 4G/B40 + 5G/N41, select channel 6 for MHS */
17400 				if (mhs_channel_for_4g == 11 && mhs_channel_for_5g == 1) {
17401 					g_mhs_chan_for_cpcoex = 6;
17402 				/* if 4G(except for B40) + 5G/N41, select channel 1 for MHS */
17403 				} else {
17404 					g_mhs_chan_for_cpcoex = 1;
17405 				}
17406 			} else {
17407 				g_mhs_chan_for_cpcoex = mhs_channel_for_4g ? mhs_channel_for_4g :
17408 					mhs_channel_for_5g ? mhs_channel_for_5g : 0;
17409 			}
17410 			mhs_channel_for_4g = mhs_channel_for_5g = 0;
17411 			recv_msg_4g = recv_msg_5g = 0;
17412 		}
17413 	}
17414 
17415 	return 0;
17416 }
17417 
17418 static struct notifier_block wl_cfg80211_ril_bridge_notifier = {
17419 	.notifier_call = wl_cfg80211_ril_bridge_notifier_call,
17420 };
17421 
17422 static bool wl_cfg80211_ril_bridge_notifier_registered = FALSE;
17423 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
17424 
17425 static s32
wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,unsigned long state,void * ptr)17426 wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
17427 	unsigned long state, void *ptr)
17428 {
17429 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
17430 	struct net_device *dev = ptr;
17431 #else
17432 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
17433 #endif /* LINUX_VERSION < VERSION(3, 11, 0) */
17434 	struct wireless_dev *wdev = NULL;
17435 	struct bcm_cfg80211 *cfg = NULL;
17436 
17437 	WL_DBG(("Enter state:%lu  ndev%p \n", state, dev));
17438 	if (!dev) {
17439 		WL_ERR(("dev null\n"));
17440 		return NOTIFY_DONE;
17441 	}
17442 
17443 	wdev = ndev_to_wdev(dev);
17444 	if (!wdev) {
17445 		WL_ERR(("wdev null. Do nothing\n"));
17446 		return NOTIFY_DONE;
17447 	}
17448 
17449 	cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
17450 	if (!cfg || (cfg != wl_cfg80211_get_bcmcfg())) {
17451 		/* If cfg80211 priv is null or doesn't match return */
17452 		WL_ERR(("wrong cfg ptr (%p)\n", cfg));
17453 		return NOTIFY_DONE;
17454 	}
17455 
17456 	if (dev == bcmcfg_to_prmry_ndev(cfg)) {
17457 		/* Nothing to be done for primary I/F */
17458 		return NOTIFY_DONE;
17459 	}
17460 
17461 	switch (state) {
17462 		case NETDEV_DOWN:
17463 		{
17464 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
17465 			int max_wait_timeout = 2;
17466 			int max_wait_count = 100;
17467 			int refcnt = 0;
17468 			unsigned long limit = jiffies + max_wait_timeout * HZ;
17469 			while (work_pending(&wdev->cleanup_work)) {
17470 				if (refcnt%5 == 0) {
17471 					WL_ERR(("[NETDEV_DOWN] wait for "
17472 						"complete of cleanup_work"
17473 						" (%d th)\n", refcnt));
17474 				}
17475 				if (!time_before(jiffies, limit)) {
17476 					WL_ERR(("[NETDEV_DOWN] cleanup_work"
17477 						" of CFG80211 is not"
17478 						" completed in %d sec\n",
17479 						max_wait_timeout));
17480 					break;
17481 				}
17482 				if (refcnt >= max_wait_count) {
17483 					WL_ERR(("[NETDEV_DOWN] cleanup_work"
17484 						" of CFG80211 is not"
17485 						" completed in %d loop\n",
17486 						max_wait_count));
17487 					break;
17488 				}
17489 				set_current_state(TASK_INTERRUPTIBLE);
17490 				(void)schedule_timeout(100);
17491 				set_current_state(TASK_RUNNING);
17492 				refcnt++;
17493 			}
17494 #endif /* LINUX_VERSION < VERSION(3, 14, 0) */
17495 			break;
17496 		}
17497 		case NETDEV_UNREGISTER:
17498 			wl_cfg80211_clear_per_bss_ies(cfg, wdev);
17499 			/* after calling list_del_rcu(&wdev->list) */
17500 			wl_dealloc_netinfo_by_wdev(cfg, wdev);
17501 			break;
17502 		case NETDEV_GOING_DOWN:
17503 			/*
17504 			 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
17505 			 * In front of door, the function checks whether current scan
17506 			 * is working or not. If the scanning is still working,
17507 			 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
17508 			 */
17509 			if (wl_get_drv_status(cfg, SCANNING, dev))
17510 				wl_cfg80211_cancel_scan(cfg);
17511 			break;
17512 	}
17513 	return NOTIFY_DONE;
17514 }
17515 
17516 static struct notifier_block wl_cfg80211_netdev_notifier = {
17517 	.notifier_call = wl_cfg80211_netdev_notifier_call,
17518 };
17519 
17520 /*
17521  * to make sure we won't register the same notifier twice, otherwise a loop is likely to be
17522  * created in kernel notifier link list (with 'next' pointing to itself)
17523  */
17524 static bool wl_cfg80211_netdev_notifier_registered = FALSE;
17525 
wl_cfg80211_concurrent_roam(struct bcm_cfg80211 * cfg,int enable)17526 static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
17527 {
17528 	u32 connected_cnt  = wl_get_drv_status_all(cfg, CONNECTED);
17529 	bool p2p_connected  = wl_cfgp2p_vif_created(cfg);
17530 	struct net_info *iter, *next;
17531 
17532 	if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT))
17533 		return;
17534 
17535 	WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
17536 		enable, p2p_connected, connected_cnt));
17537 	/* Disable FW roam when we have a concurrent P2P connection */
17538 	if (enable && p2p_connected && connected_cnt > 1) {
17539 
17540 		/* Mark it as to be reverted */
17541 		cfg->roam_flags |= WL_ROAM_REVERT_STATUS;
17542 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17543 		for_each_ndev(cfg, iter, next) {
17544 			GCC_DIAGNOSTIC_POP();
17545 			if (iter->ndev && iter->wdev &&
17546 					iter->wdev->iftype == NL80211_IFTYPE_STATION) {
17547 				if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE)
17548 						== BCME_OK) {
17549 					iter->roam_off = TRUE;
17550 				}
17551 				else {
17552 					WL_ERR(("error to enable roam_off\n"));
17553 				}
17554 			}
17555 		}
17556 	}
17557 	else if (!enable && (cfg->roam_flags & WL_ROAM_REVERT_STATUS)) {
17558 		cfg->roam_flags &= ~WL_ROAM_REVERT_STATUS;
17559 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17560 		for_each_ndev(cfg, iter, next) {
17561 			GCC_DIAGNOSTIC_POP();
17562 			if (iter->ndev && iter->wdev &&
17563 					iter->wdev->iftype == NL80211_IFTYPE_STATION) {
17564 				if (iter->roam_off != WL_INVALID) {
17565 					if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE)
17566 							== BCME_OK) {
17567 						iter->roam_off = FALSE;
17568 					}
17569 					else {
17570 						WL_ERR(("error to disable roam_off\n"));
17571 					}
17572 				}
17573 			}
17574 		}
17575 	}
17576 
17577 	return;
17578 }
17579 
wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 * cfg)17580 static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
17581 {
17582 	struct net_info *iter, *next;
17583 	u32 ctl_chan = 0;
17584 	u32 chanspec = 0;
17585 	u32 pre_ctl_chan = 0;
17586 	u32 connected_cnt  = wl_get_drv_status_all(cfg, CONNECTED);
17587 	cfg->vsdb_mode = false;
17588 
17589 	if (connected_cnt <= 1)  {
17590 		return;
17591 	}
17592 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17593 	for_each_ndev(cfg, iter, next) {
17594 		GCC_DIAGNOSTIC_POP();
17595 		/* p2p discovery iface ndev could be null */
17596 		if (iter->ndev) {
17597 			chanspec = 0;
17598 			ctl_chan = 0;
17599 			if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
17600 				if (wldev_iovar_getint(iter->ndev, "chanspec",
17601 					(s32 *)&chanspec) == BCME_OK) {
17602 					chanspec = wl_chspec_driver_to_host(chanspec);
17603 					ctl_chan = wf_chspec_ctlchan(chanspec);
17604 					wl_update_prof(cfg, iter->ndev, NULL,
17605 						&ctl_chan, WL_PROF_CHAN);
17606 				}
17607 				if (!cfg->vsdb_mode) {
17608 					if (!pre_ctl_chan && ctl_chan)
17609 						pre_ctl_chan = ctl_chan;
17610 					else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) {
17611 						cfg->vsdb_mode = true;
17612 					}
17613 				}
17614 			}
17615 		}
17616 	}
17617 	WL_MSG("wlan", "%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel");
17618 	return;
17619 }
17620 
17621 int
wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211 * cfg)17622 wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211 *cfg)
17623 {
17624 	struct net_info *iter, *next;
17625 	u32 chanspec = 0;
17626 	u32 band = 0;
17627 	u32 pre_band = 0;
17628 	bool is_rsdb_supported = FALSE;
17629 	bool rsdb_mode = FALSE;
17630 
17631 	is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
17632 
17633 	if (!is_rsdb_supported) {
17634 		return 0;
17635 	}
17636 
17637 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17638 	for_each_ndev(cfg, iter, next) {
17639 		GCC_DIAGNOSTIC_POP();
17640 		/* p2p discovery iface ndev could be null */
17641 		if (iter->ndev) {
17642 			chanspec = 0;
17643 			band = 0;
17644 			if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
17645 				if (wldev_iovar_getint(iter->ndev, "chanspec",
17646 					(s32 *)&chanspec) == BCME_OK) {
17647 					chanspec = wl_chspec_driver_to_host(chanspec);
17648 					band = CHSPEC_BAND(chanspec);
17649 				}
17650 
17651 				if (!pre_band && band) {
17652 					pre_band = band;
17653 				} else if (pre_band && (pre_band != band)) {
17654 					rsdb_mode = TRUE;
17655 				}
17656 			}
17657 		}
17658 	}
17659 	WL_DBG(("RSDB mode is %s\n", rsdb_mode ? "enabled" : "disabled"));
17660 
17661 	return rsdb_mode;
17662 }
17663 
wl_notifier_change_state(struct bcm_cfg80211 * cfg,struct net_info * _net_info,enum wl_status state,bool set)17664 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
17665 	enum wl_status state, bool set)
17666 {
17667 	s32 pm = PM_FAST;
17668 	s32 err = BCME_OK;
17669 	u32 mode;
17670 	u32 chan = 0;
17671 	struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
17672 	dhd_pub_t *dhd = cfg->pub;
17673 #ifdef RTT_SUPPORT
17674 	rtt_status_info_t *rtt_status;
17675 #endif /* RTT_SUPPORT */
17676 	if (dhd->busstate == DHD_BUS_DOWN) {
17677 		WL_ERR(("busstate is DHD_BUS_DOWN!\n"));
17678 		return 0;
17679 	}
17680 	WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
17681 		state, set, _net_info->pm_restore, _net_info->ndev->name));
17682 
17683 	if (state != WL_STATUS_CONNECTED)
17684 		return 0;
17685 	mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
17686 	if (set) {
17687 		wl_cfg80211_concurrent_roam(cfg, 1);
17688 		wl_cfg80211_determine_vsdb_mode(cfg);
17689 		if (mode == WL_MODE_AP) {
17690 			if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
17691 				WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
17692 		}
17693 		pm = PM_OFF;
17694 		if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
17695 				sizeof(pm))) != 0) {
17696 			if (err == -ENODEV)
17697 				WL_DBG(("%s:netdev not ready\n",
17698 					_net_info->ndev->name));
17699 			else
17700 				WL_ERR(("%s:error (%d)\n",
17701 					_net_info->ndev->name, err));
17702 
17703 			wl_cfg80211_update_power_mode(_net_info->ndev);
17704 		}
17705 		wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
17706 #if defined(WLTDLS)
17707 		if (wl_cfg80211_is_concurrent_mode(primary_dev)) {
17708 			err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
17709 		}
17710 #endif /* defined(WLTDLS) */
17711 
17712 #ifdef DISABLE_FRAMEBURST_VSDB
17713 		if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
17714 			wl_cfg80211_is_concurrent_mode(primary_dev) &&
17715 			!wl_cfg80211_determine_p2p_rsdb_mode(cfg)) {
17716 			wl_cfg80211_set_frameburst(cfg, FALSE);
17717 		}
17718 #endif /* DISABLE_FRAMEBURST_VSDB */
17719 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
17720 		if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
17721 			wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
17722 			/* Enable frameburst for
17723 			 * STA/SoftAP concurrent mode
17724 			 */
17725 			wl_cfg80211_set_frameburst(cfg, TRUE);
17726 		}
17727 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
17728 	} else { /* clear */
17729 		chan = 0;
17730 		/* clear chan information when the net device is disconnected */
17731 		wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
17732 		wl_cfg80211_determine_vsdb_mode(cfg);
17733 		if (primary_dev == _net_info->ndev) {
17734 			pm = PM_FAST;
17735 #ifdef RTT_SUPPORT
17736 			rtt_status = GET_RTTSTATE(dhd);
17737 			if (rtt_status->status != RTT_ENABLED) {
17738 #endif /* RTT_SUPPORT */
17739 				if (dhd_conf_get_pm(dhd) >= 0)
17740 					pm = dhd_conf_get_pm(dhd);
17741 				if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
17742 						sizeof(pm))) != 0) {
17743 					if (err == -ENODEV)
17744 						WL_DBG(("%s:netdev not ready\n",
17745 							_net_info->ndev->name));
17746 					else
17747 						WL_ERR(("%s:error (%d)\n",
17748 							_net_info->ndev->name, err));
17749 
17750 					wl_cfg80211_update_power_mode(_net_info->ndev);
17751 				}
17752 #ifdef RTT_SUPPORT
17753 			}
17754 #endif /* RTT_SUPPORT */
17755 		}
17756 		wl_cfg80211_concurrent_roam(cfg, 0);
17757 #if defined(WLTDLS)
17758 		if (!wl_cfg80211_is_concurrent_mode(primary_dev)) {
17759 			err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
17760 		}
17761 #endif /* defined(WLTDLS) */
17762 
17763 #if defined(DISABLE_FRAMEBURST_VSDB)
17764 		if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE)) {
17765 			wl_cfg80211_set_frameburst(cfg, TRUE);
17766 		}
17767 #endif /* DISABLE_FRAMEBURST_VSDB */
17768 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
17769 		if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
17770 			(cfg->ap_oper_channel <= CH_MAX_2G_CHANNEL)) {
17771 			/* Disable frameburst for stand-alone 2GHz SoftAP */
17772 			wl_cfg80211_set_frameburst(cfg, FALSE);
17773 		}
17774 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
17775 	}
17776 	return err;
17777 }
17778 
17779 #ifdef DHD_LOSSLESS_ROAMING
wl_init_roam_timeout(struct bcm_cfg80211 * cfg)17780 static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
17781 {
17782 	int err = 0;
17783 
17784 	/* Init roam timer */
17785 	init_timer_compat(&cfg->roam_timeout, wl_roam_timeout, cfg);
17786 
17787 	return err;
17788 }
17789 #endif /* DHD_LOSSLESS_ROAMING */
17790 
wl_init_priv(struct bcm_cfg80211 * cfg)17791 static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
17792 {
17793 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
17794 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
17795 	s32 err = 0;
17796 
17797 	cfg->scan_request = NULL;
17798 	cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
17799 #ifdef DISABLE_BUILTIN_ROAM
17800 	cfg->roam_on = false;
17801 #else
17802 	cfg->roam_on = true;
17803 #endif /* DISABLE_BUILTIN_ROAM */
17804 	cfg->active_scan = true;
17805 	cfg->rf_blocked = false;
17806 	cfg->vsdb_mode = false;
17807 #if defined(BCMSDIO) || defined(BCMDBUS)
17808 	cfg->wlfc_on = false;
17809 #endif /* BCMSDIO || BCMDBUS */
17810 	cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
17811 	cfg->disable_roam_event = false;
17812 	/* register interested state */
17813 	set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
17814 	spin_lock_init(&cfg->cfgdrv_lock);
17815 	mutex_init(&cfg->ioctl_buf_sync);
17816 	init_waitqueue_head(&cfg->netif_change_event);
17817 	init_completion(&cfg->send_af_done);
17818 	init_completion(&cfg->iface_disable);
17819 	mutex_init(&cfg->usr_sync);
17820 	mutex_init(&cfg->event_sync);
17821 	mutex_init(&cfg->if_sync);
17822 	mutex_init(&cfg->scan_sync);
17823 	mutex_init(&cfg->pm_sync);
17824 #ifdef WLTDLS
17825 	mutex_init(&cfg->tdls_sync);
17826 #endif	/* WLTDLS */
17827 #ifdef WL_BCNRECV
17828 	mutex_init(&cfg->bcn_sync);
17829 #endif /* WL_BCNRECV */
17830 #ifdef WL_WPS_SYNC
17831 	wl_init_wps_reauth_sm(cfg);
17832 #endif /* WL_WPS_SYNC */
17833 	wl_init_eq(cfg);
17834 	err = wl_init_priv_mem(cfg);
17835 	if (err)
17836 		return err;
17837 	if (wl_create_event_handler(cfg))
17838 		return -ENOMEM;
17839 	wl_init_event_handler(cfg);
17840 	err = wl_init_scan(cfg);
17841 	if (err)
17842 		return err;
17843 #ifdef DHD_LOSSLESS_ROAMING
17844 	err = wl_init_roam_timeout(cfg);
17845 	if (err) {
17846 		return err;
17847 	}
17848 #endif /* DHD_LOSSLESS_ROAMING */
17849 	wl_init_conf(cfg->conf);
17850 	wl_init_prof(cfg, ndev);
17851 	wl_link_down(cfg);
17852 	DNGL_FUNC(dhd_cfg80211_init, (cfg));
17853 #ifdef WL_NAN
17854 	cfg->nan_dp_state = NAN_DP_STATE_DISABLED;
17855 	init_waitqueue_head(&cfg->ndp_if_change_event);
17856 	mutex_init(&cfg->nancfg.nan_sync);
17857 	init_waitqueue_head(&cfg->nancfg.nan_event_wait);
17858 #endif /* WL_NAN */
17859 	cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
17860 	cfg->pmk_list->pmkids.count = 0;
17861 	cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
17862 	return err;
17863 }
17864 
wl_deinit_priv(struct bcm_cfg80211 * cfg)17865 static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
17866 {
17867 	DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
17868 	wl_destroy_event_handler(cfg);
17869 	wl_flush_eq(cfg);
17870 	wl_link_down(cfg);
17871 	del_timer_sync(&cfg->scan_timeout);
17872 #ifdef DHD_LOSSLESS_ROAMING
17873 	del_timer_sync(&cfg->roam_timeout);
17874 #endif // endif
17875 	wl_deinit_priv_mem(cfg);
17876 	if (wl_cfg80211_netdev_notifier_registered) {
17877 		wl_cfg80211_netdev_notifier_registered = FALSE;
17878 		unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
17879 	}
17880 }
17881 
17882 #if defined(WL_ENABLE_P2P_IF)
wl_cfg80211_attach_p2p(struct bcm_cfg80211 * cfg)17883 static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
17884 {
17885 	WL_TRACE(("Enter \n"));
17886 
17887 	if (wl_cfgp2p_register_ndev(cfg) < 0) {
17888 		WL_ERR(("P2P attach failed. \n"));
17889 		return -ENODEV;
17890 	}
17891 
17892 	return 0;
17893 }
17894 
wl_cfg80211_detach_p2p(struct bcm_cfg80211 * cfg)17895 static s32  wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
17896 {
17897 	struct wireless_dev *wdev;
17898 
17899 	WL_DBG(("Enter \n"));
17900 	if (!cfg) {
17901 		WL_ERR(("Invalid Ptr\n"));
17902 		return -EINVAL;
17903 	}
17904 	else {
17905 		wdev = cfg->p2p_wdev;
17906 		if (!wdev) {
17907 			WL_ERR(("Invalid Ptr\n"));
17908 			return -EINVAL;
17909 		}
17910 	}
17911 
17912 	wl_cfgp2p_unregister_ndev(cfg);
17913 
17914 	cfg->p2p_wdev = NULL;
17915 	cfg->p2p_net = NULL;
17916 	WL_DBG(("Freeing 0x%p \n", wdev));
17917 	kfree(wdev);
17918 
17919 	return 0;
17920 }
17921 #endif
17922 
wl_cfg80211_attach_post(struct net_device * ndev)17923 static s32 wl_cfg80211_attach_post(struct net_device *ndev)
17924 {
17925 	struct bcm_cfg80211 * cfg;
17926 	s32 err = 0;
17927 	s32 ret = 0;
17928 	WL_TRACE(("In\n"));
17929 	if (unlikely(!ndev)) {
17930 		WL_ERR(("ndev is invaild\n"));
17931 		return -ENODEV;
17932 	}
17933 	cfg = wl_get_cfg(ndev);
17934 	if (unlikely(!cfg)) {
17935 		WL_ERR(("cfg is invaild\n"));
17936 		return -EINVAL;
17937 	}
17938 	if (!wl_get_drv_status(cfg, READY, ndev)) {
17939 		if (cfg->wdev) {
17940 			ret = wl_cfgp2p_supported(cfg, ndev);
17941 			if (ret > 0) {
17942 #if !defined(WL_ENABLE_P2P_IF)
17943 				cfg->wdev->wiphy->interface_modes |=
17944 					(BIT(NL80211_IFTYPE_P2P_CLIENT)|
17945 					BIT(NL80211_IFTYPE_P2P_GO));
17946 #endif /* !WL_ENABLE_P2P_IF */
17947 				if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
17948 					goto fail;
17949 
17950 #if defined(WL_ENABLE_P2P_IF)
17951 				if (cfg->p2p_net) {
17952 					/* Update MAC addr for p2p0 interface here. */
17953 					memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
17954 					cfg->p2p_net->dev_addr[0] |= 0x02;
17955 					WL_MSG(cfg->p2p_net->name, "p2p_dev_addr="MACDBG "\n",
17956 						MAC2STRDBG(cfg->p2p_net->dev_addr));
17957 				} else {
17958 					WL_ERR(("p2p_net not yet populated."
17959 					" Couldn't update the MAC Address for p2p0 \n"));
17960 					return -ENODEV;
17961 				}
17962 #endif /* WL_ENABLE_P2P_IF */
17963 				cfg->p2p_supported = true;
17964 			} else if (ret == 0) {
17965 				if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
17966 					goto fail;
17967 			} else {
17968 				/* SDIO bus timeout */
17969 				err = -ENODEV;
17970 				goto fail;
17971 			}
17972 		}
17973 	}
17974 	wl_set_drv_status(cfg, READY, ndev);
17975 fail:
17976 	return err;
17977 }
17978 
wl_get_cfg(struct net_device * ndev)17979 struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev)
17980 {
17981 	struct wireless_dev *wdev = ndev->ieee80211_ptr;
17982 
17983 	if (!wdev || !wdev->wiphy)
17984 		return NULL;
17985 
17986 	return wiphy_priv(wdev->wiphy);
17987 }
17988 
17989 s32
wl_cfg80211_net_attach(struct net_device * primary_ndev)17990 wl_cfg80211_net_attach(struct net_device *primary_ndev)
17991 {
17992 	struct bcm_cfg80211 *cfg = wl_get_cfg(primary_ndev);
17993 
17994 	if (!cfg) {
17995 		WL_ERR(("cfg null\n"));
17996 		return BCME_ERROR;
17997 	}
17998 #ifdef WL_STATIC_IF
17999 	/* Register dummy n/w iface. FW init will happen only from dev_open */
18000 	if (wl_cfg80211_register_static_if(cfg, NL80211_IFTYPE_STATION,
18001 		WL_STATIC_IFNAME_PREFIX) == NULL) {
18002 		WL_ERR(("static i/f registration failed!\n"));
18003 		return BCME_ERROR;
18004 	}
18005 #endif /* WL_STATIC_IF */
18006 	return BCME_OK;
18007 }
18008 
18009 #ifdef CONFIG_AP6XXX_WIFI6_HDF
18010 void set_krn_wiphy(void *pwiphy);
18011 #endif
18012 
wl_cfg80211_attach(struct net_device * ndev,void * context)18013 s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
18014 {
18015 	struct wireless_dev *wdev;
18016 	struct bcm_cfg80211 *cfg;
18017 	s32 err = 0;
18018 	struct device *dev;
18019 	u16 bssidx = 0;
18020 	u16 ifidx = 0;
18021 	dhd_pub_t *dhd = (struct dhd_pub *)(context);
18022 
18023 	WL_TRACE(("In\n"));
18024 	if (!ndev) {
18025 		WL_ERR(("ndev is invaild\n"));
18026 		return -ENODEV;
18027 	}
18028 	WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
18029 	dev = wl_cfg80211_get_parent_dev();
18030 
18031 	wdev = (struct wireless_dev *)MALLOCZ(dhd->osh, sizeof(*wdev));
18032 	if (unlikely(!wdev)) {
18033 		WL_ERR(("Could not allocate wireless device\n"));
18034 		return -ENOMEM;
18035 	}
18036 	err = wl_setup_wiphy(wdev, dev, context);
18037 	if (unlikely(err)) {
18038 		MFREE(dhd->osh, wdev, sizeof(*wdev));
18039 		return -ENOMEM;
18040 	}
18041 #ifdef WLMESH_CFG80211
18042 	wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_MESH);
18043 #else
18044 	wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
18045 #endif
18046 	cfg = wiphy_priv(wdev->wiphy);
18047 	cfg->wdev = wdev;
18048 	cfg->pub = context;
18049 	cfg->osh = dhd->osh;
18050 	INIT_LIST_HEAD(&cfg->net_list);
18051 	INIT_LIST_HEAD(&cfg->vndr_oui_list);
18052 	spin_lock_init(&cfg->vndr_oui_sync);
18053 	spin_lock_init(&cfg->net_list_sync);
18054 	ndev->ieee80211_ptr = wdev;
18055 #ifdef CONFIG_AP6XXX_WIFI6_HDF
18056     set_krn_wiphy(wdev->wiphy);
18057 #endif
18058 	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
18059 	wdev->netdev = ndev;
18060 	cfg->state_notifier = wl_notifier_change_state;
18061 	err = wl_alloc_netinfo(cfg, ndev, wdev, WL_IF_TYPE_STA, PM_ENABLE, bssidx, ifidx);
18062 	if (err) {
18063 		WL_ERR(("Failed to alloc net_info (%d)\n", err));
18064 		goto cfg80211_attach_out;
18065 	}
18066 	err = wl_init_priv(cfg);
18067 	if (err) {
18068 		WL_ERR(("Failed to init iwm_priv (%d)\n", err));
18069 		goto cfg80211_attach_out;
18070 	}
18071 
18072 	err = wl_setup_rfkill(cfg, TRUE);
18073 	if (err) {
18074 		WL_ERR(("Failed to setup rfkill %d\n", err));
18075 		goto cfg80211_attach_out;
18076 	}
18077 #ifdef DEBUGFS_CFG80211
18078 	err = wl_setup_debugfs(cfg);
18079 	if (err) {
18080 		WL_ERR(("Failed to setup debugfs %d\n", err));
18081 		goto cfg80211_attach_out;
18082 	}
18083 #endif // endif
18084 	if (!wl_cfg80211_netdev_notifier_registered) {
18085 		wl_cfg80211_netdev_notifier_registered = TRUE;
18086 		err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
18087 		if (err) {
18088 			wl_cfg80211_netdev_notifier_registered = FALSE;
18089 			WL_ERR(("Failed to register notifierl %d\n", err));
18090 			goto cfg80211_attach_out;
18091 		}
18092 	}
18093 #if defined(COEX_DHCP)
18094 	cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
18095 	if (!cfg->btcoex_info)
18096 		goto cfg80211_attach_out;
18097 #endif // endif
18098 
18099 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
18100 	wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
18101 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
18102 
18103 #if defined(WL_ENABLE_P2P_IF)
18104 	err = wl_cfg80211_attach_p2p(cfg);
18105 	if (err)
18106 		goto cfg80211_attach_out;
18107 #endif
18108 
18109 	INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
18110 #ifdef WL_NAN
18111 	WL_DBG(("NAN: Armed wl_cfgnan_delayed_disable work\n"));
18112 	INIT_DELAYED_WORK(&cfg->nan_disable, wl_cfgnan_delayed_disable);
18113 #endif /* WL_NAN */
18114 	cfg->rssi_sum_report = FALSE;
18115 	return err;
18116 
18117 cfg80211_attach_out:
18118 	wl_cfg80211_detach(cfg);
18119 	return err;
18120 }
18121 
wl_cfg80211_detach(struct bcm_cfg80211 * cfg)18122 void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
18123 {
18124 	WL_DBG(("Enter\n"));
18125 	if (!cfg) {
18126 		return;
18127 	}
18128 	wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
18129 
18130 #if defined(COEX_DHCP)
18131 	wl_cfg80211_btcoex_deinit();
18132 	cfg->btcoex_info = NULL;
18133 #endif // endif
18134 
18135 	wl_setup_rfkill(cfg, FALSE);
18136 #ifdef DEBUGFS_CFG80211
18137 	wl_free_debugfs(cfg);
18138 #endif // endif
18139 	if (cfg->p2p_supported) {
18140 		if (timer_pending(&cfg->p2p->listen_timer))
18141 			del_timer_sync(&cfg->p2p->listen_timer);
18142 		wl_cfgp2p_deinit_priv(cfg);
18143 	}
18144 
18145 #ifdef WL_WPS_SYNC
18146 	wl_deinit_wps_reauth_sm(cfg);
18147 #endif /* WL_WPS_SYNC */
18148 
18149 	if (timer_pending(&cfg->scan_timeout))
18150 		del_timer_sync(&cfg->scan_timeout);
18151 #ifdef DHD_LOSSLESS_ROAMING
18152 	if (timer_pending(&cfg->roam_timeout)) {
18153 		del_timer_sync(&cfg->roam_timeout);
18154 	}
18155 #endif /* DHD_LOSSLESS_ROAMING */
18156 
18157 #ifdef WL_STATIC_IF
18158 	wl_cfg80211_unregister_static_if(cfg);
18159 #endif /* WL_STATIC_IF */
18160 #if defined(WL_CFG80211_P2P_DEV_IF)
18161 	if (cfg->p2p_wdev)
18162 		wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
18163 #endif /* WL_CFG80211_P2P_DEV_IF  */
18164 #if defined(WL_ENABLE_P2P_IF)
18165 	wl_cfg80211_detach_p2p(cfg);
18166 #endif
18167 	wl_cfg80211_ibss_vsie_free(cfg);
18168 	wl_dealloc_netinfo_by_wdev(cfg, cfg->wdev);
18169 	wl_cfg80211_set_bcmcfg(NULL);
18170 	wl_deinit_priv(cfg);
18171 	wl_cfg80211_clear_parent_dev();
18172 #if defined(RSSIAVG)
18173 	wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
18174 	wl_free_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
18175 #endif
18176 #if defined(BSSCACHE)
18177 	wl_release_bss_cache_ctrl(&cfg->g_bss_cache_ctrl);
18178 #endif
18179 	wl_free_wdev(cfg);
18180 	/* PLEASE do NOT call any function after wl_free_wdev, the driver's private
18181 	 * structure "cfg", which is the private part of wiphy, has been freed in
18182 	 * wl_free_wdev !!!!!!!!!!!
18183 	 */
18184 	WL_DBG(("Exit\n"));
18185 }
18186 
18187 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
wl_cfg80211_register_dev_ril_bridge_event_notifier()18188 void wl_cfg80211_register_dev_ril_bridge_event_notifier()
18189 {
18190 	WL_DBG(("Enter\n"));
18191 	if (!wl_cfg80211_ril_bridge_notifier_registered) {
18192 		s32 err = 0;
18193 		wl_cfg80211_ril_bridge_notifier_registered = TRUE;
18194 		err = register_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
18195 		if (err) {
18196 			wl_cfg80211_ril_bridge_notifier_registered = FALSE;
18197 			WL_ERR(("Failed to register ril_notifier! %d\n", err));
18198 		}
18199 	}
18200 }
18201 
wl_cfg80211_unregister_dev_ril_bridge_event_notifier()18202 void wl_cfg80211_unregister_dev_ril_bridge_event_notifier()
18203 {
18204 	WL_DBG(("Enter\n"));
18205 	if (wl_cfg80211_ril_bridge_notifier_registered) {
18206 		wl_cfg80211_ril_bridge_notifier_registered = FALSE;
18207 		unregister_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
18208 	}
18209 }
18210 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
18211 
wl_print_event_data(struct bcm_cfg80211 * cfg,uint32 event_type,const wl_event_msg_t * e)18212 static void wl_print_event_data(struct bcm_cfg80211 *cfg,
18213 	uint32 event_type, const wl_event_msg_t *e)
18214 {
18215 	s32 status = ntoh32(e->status);
18216 	s32 reason = ntoh32(e->reason);
18217 	s32 ifidx = ntoh32(e->ifidx);
18218 	s32 bssidx = ntoh32(e->bsscfgidx);
18219 
18220 	switch (event_type) {
18221 		case WLC_E_ESCAN_RESULT:
18222 			if ((status == WLC_E_STATUS_SUCCESS) ||
18223 				(status == WLC_E_STATUS_ABORT)) {
18224 				WL_INFORM_MEM(("event_type (%d), ifidx: %d"
18225 					" bssidx: %d scan_type:%d\n",
18226 					event_type, ifidx, bssidx, status));
18227 			}
18228 			break;
18229 		case WLC_E_LINK:
18230 		case WLC_E_DISASSOC:
18231 		case WLC_E_DISASSOC_IND:
18232 		case WLC_E_DEAUTH:
18233 		case WLC_E_DEAUTH_IND:
18234 			WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
18235 				" status:%d reason:%d\n",
18236 				event_type, ifidx, bssidx, status, reason));
18237 				break;
18238 
18239 		default:
18240 			/* Print only when DBG verbose is enabled */
18241 			WL_DBG(("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
18242 				event_type, ifidx, bssidx, status, reason));
18243 	}
18244 }
18245 
wl_event_handler(struct work_struct * work_data)18246 static void wl_event_handler(struct work_struct *work_data)
18247 {
18248 	struct bcm_cfg80211 *cfg = NULL;
18249 	struct wl_event_q *e;
18250 	struct wireless_dev *wdev = NULL;
18251 
18252 	WL_DBG(("Enter \n"));
18253 	BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
18254 	cfg->wl_evt_hdlr_entry_time = OSL_LOCALTIME_NS();
18255 	DHD_EVENT_WAKE_LOCK(cfg->pub);
18256 	while ((e = wl_deq_event(cfg))) {
18257 		s32 status = ntoh32(e->emsg.status);
18258 		u32 event_type = ntoh32(e->emsg.event_type);
18259 		bool scan_cmplt_evt = (event_type == WLC_E_ESCAN_RESULT) &&
18260 			((status == WLC_E_STATUS_SUCCESS) || (status == WLC_E_STATUS_ABORT));
18261 
18262 		cfg->wl_evt_deq_time = OSL_LOCALTIME_NS();
18263 		if (scan_cmplt_evt) {
18264 			cfg->scan_deq_time = OSL_LOCALTIME_NS();
18265 		}
18266 		/* Print only critical events to avoid too many prints */
18267 		wl_print_event_data(cfg, e->etype, &e->emsg);
18268 
18269 		if (e->emsg.ifidx > WL_MAX_IFS) {
18270 			WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
18271 			goto fail;
18272 		}
18273 
18274 		/* Make sure iface operations, don't creat race conditions */
18275 		mutex_lock(&cfg->if_sync);
18276 		if (!(wdev = wl_get_wdev_by_fw_idx(cfg,
18277 			e->emsg.bsscfgidx, e->emsg.ifidx))) {
18278 			/* For WLC_E_IF would be handled by wl_host_event */
18279 			if (e->etype != WLC_E_IF)
18280 				WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
18281 					" Ignoring event.\n", e->emsg.bsscfgidx));
18282 		} else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
18283 			dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
18284 			if (dhd->busstate == DHD_BUS_DOWN) {
18285 				WL_ERR((": BUS is DOWN.\n"));
18286 			} else
18287 			{
18288 				WL_DBG(("event_type %d event_sub %d\n",
18289 					ntoh32(e->emsg.event_type),
18290 					ntoh32(e->emsg.reason)));
18291 				cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
18292 					&e->emsg, e->edata);
18293 				if (scan_cmplt_evt) {
18294 					cfg->scan_hdlr_cmplt_time = OSL_LOCALTIME_NS();
18295 				}
18296 			}
18297 		} else {
18298 			WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
18299 		}
18300 		mutex_unlock(&cfg->if_sync);
18301 fail:
18302 		wl_put_event(cfg, e);
18303 		if (scan_cmplt_evt) {
18304 			cfg->scan_cmplt_time = OSL_LOCALTIME_NS();
18305 		}
18306 		cfg->wl_evt_hdlr_exit_time = OSL_LOCALTIME_NS();
18307 	}
18308 	DHD_EVENT_WAKE_UNLOCK(cfg->pub);
18309 }
18310 
18311 /*
18312 * Generic API to handle critical events which doesnt need
18313 * cfg enquening and sleepable API calls.
18314 */
18315 s32
wl_cfg80211_handle_critical_events(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)18316 wl_cfg80211_handle_critical_events(struct bcm_cfg80211 *cfg,
18317 	const wl_event_msg_t * e)
18318 {
18319 	s32 ret = BCME_ERROR;
18320 	u32 event_type = ntoh32(e->event_type);
18321 
18322 	if (event_type >= WLC_E_LAST) {
18323 		return BCME_ERROR;
18324 	}
18325 
18326 	switch (event_type) {
18327 		case WLC_E_NAN_CRITICAL: {
18328 #ifdef WL_NAN
18329 		if (ntoh32(e->reason) == WL_NAN_EVENT_STOP) {
18330 			ret =
18331 			wl_cfgvendor_nan_send_async_disable_resp(cfg->static_ndev->ieee80211_ptr);
18332 		}
18333 #endif /* WL_NAN */
18334 			break;
18335 		}
18336 		default:
18337 			ret = BCME_ERROR;
18338 	}
18339 	return ret;
18340 }
18341 
18342 void
wl_cfg80211_event(struct net_device * ndev,const wl_event_msg_t * e,void * data)18343 wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
18344 {
18345 	s32 status = ntoh32(e->status);
18346 	u32 event_type = ntoh32(e->event_type);
18347 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18348 	struct net_info *netinfo;
18349 
18350 	WL_DBG(("event_type (%d): reason (%d): %s\n", event_type, ntoh32(e->reason),
18351 		bcmevent_get_name(event_type)));
18352 	if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
18353 		WL_ERR(("Stale event ignored\n"));
18354 		return;
18355 	}
18356 
18357 	if (cfg->event_workq == NULL) {
18358 		WL_ERR(("Event handler is not created\n"));
18359 		return;
18360 	}
18361 
18362 	if (event_type == WLC_E_IF) {
18363 		/* Don't process WLC_E_IF events in wl_cfg80211 layer */
18364 		return;
18365 	}
18366 
18367 	netinfo = wl_get_netinfo_by_fw_idx(cfg, e->bsscfgidx, e->ifidx);
18368 	if (!netinfo) {
18369 		/* Since the netinfo entry is not there, the netdev entry is not
18370 		 * created via cfg80211 interface. so the event is not of interest
18371 		 * to the cfg80211 layer.
18372 		 */
18373 		WL_TRACE(("ignore event %d, not interested\n", event_type));
18374 		return;
18375 	}
18376 
18377 	/* Handle wl_cfg80211_critical_events */
18378 	if (wl_cfg80211_handle_critical_events(cfg, e) == BCME_OK) {
18379 		return;
18380 	}
18381 
18382 	if (event_type == WLC_E_PFN_NET_FOUND) {
18383 		WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
18384 	}
18385 	else if (event_type == WLC_E_PFN_NET_LOST) {
18386 		WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
18387 	}
18388 
18389 	if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
18390 		queue_work(cfg->event_workq, &cfg->event_work);
18391 	}
18392 	/* Mark timeout value for thread sched */
18393 	if ((event_type == WLC_E_ESCAN_RESULT) &&
18394 		((status == WLC_E_STATUS_SUCCESS) ||
18395 		(status == WLC_E_STATUS_ABORT)))  {
18396 		cfg->scan_enq_time = OSL_LOCALTIME_NS();
18397 		WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
18398 			status, work_busy(&cfg->event_work)));
18399 	}
18400 }
18401 
wl_init_eq(struct bcm_cfg80211 * cfg)18402 static void wl_init_eq(struct bcm_cfg80211 *cfg)
18403 {
18404 	wl_init_eq_lock(cfg);
18405 	INIT_LIST_HEAD(&cfg->eq_list);
18406 }
18407 
wl_flush_eq(struct bcm_cfg80211 * cfg)18408 static void wl_flush_eq(struct bcm_cfg80211 *cfg)
18409 {
18410 	struct wl_event_q *e;
18411 	unsigned long flags;
18412 
18413 	flags = wl_lock_eq(cfg);
18414 	while (!list_empty_careful(&cfg->eq_list)) {
18415 		BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
18416 		list_del(&e->eq_list);
18417 		MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
18418 	}
18419 	wl_unlock_eq(cfg, flags);
18420 }
18421 
18422 /*
18423 * retrieve first queued event from head
18424 */
18425 
wl_deq_event(struct bcm_cfg80211 * cfg)18426 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
18427 {
18428 	struct wl_event_q *e = NULL;
18429 	unsigned long flags;
18430 
18431 	flags = wl_lock_eq(cfg);
18432 	if (likely(!list_empty(&cfg->eq_list))) {
18433 		BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
18434 		list_del(&e->eq_list);
18435 	}
18436 	wl_unlock_eq(cfg, flags);
18437 
18438 	return e;
18439 }
18440 
18441 /*
18442  * push event to tail of the queue
18443  */
18444 
18445 static s32
wl_enq_event(struct bcm_cfg80211 * cfg,struct net_device * ndev,u32 event,const wl_event_msg_t * msg,void * data)18446 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event,
18447 	const wl_event_msg_t *msg, void *data)
18448 {
18449 	struct wl_event_q *e;
18450 	s32 err = 0;
18451 	uint32 evtq_size;
18452 	uint32 data_len;
18453 	unsigned long flags;
18454 
18455 	data_len = 0;
18456 	if (data)
18457 		data_len = ntoh32(msg->datalen);
18458 	evtq_size = (uint32)(sizeof(struct wl_event_q) + data_len);
18459 	e = (struct wl_event_q *)MALLOCZ(cfg->osh, evtq_size);
18460 	if (unlikely(!e)) {
18461 		WL_ERR(("event alloc failed\n"));
18462 		return -ENOMEM;
18463 	}
18464 	e->etype = event;
18465 	memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
18466 	if (data)
18467 		memcpy(e->edata, data, data_len);
18468 	e->datalen = data_len;
18469 	flags = wl_lock_eq(cfg);
18470 	list_add_tail(&e->eq_list, &cfg->eq_list);
18471 	wl_unlock_eq(cfg, flags);
18472 
18473 	return err;
18474 }
18475 
wl_put_event(struct bcm_cfg80211 * cfg,struct wl_event_q * e)18476 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e)
18477 {
18478 	MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
18479 }
18480 
wl_config_infra(struct bcm_cfg80211 * cfg,struct net_device * ndev,u16 iftype)18481 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype)
18482 {
18483 	s32 infra = 0;
18484 	s32 err = 0;
18485 	bool skip_infra = false;
18486 
18487 	switch (iftype) {
18488 		case WL_IF_TYPE_IBSS:
18489 		case WL_IF_TYPE_AIBSS:
18490 			infra = 0;
18491 			break;
18492 		case WL_IF_TYPE_AP:
18493 		case WL_IF_TYPE_STA:
18494 		case WL_IF_TYPE_P2P_GO:
18495 		case WL_IF_TYPE_P2P_GC:
18496 			/* Intentional fall through */
18497 			infra = 1;
18498 			break;
18499 #ifdef WLMESH_CFG80211
18500 	case NL80211_IFTYPE_MESH_POINT:
18501 		infra = WL_BSSTYPE_MESH;
18502 		break;
18503 #endif /* WLMESH_CFG80211 */
18504 		case WL_IF_TYPE_MONITOR:
18505 		case WL_IF_TYPE_NAN:
18506 			/* Intentionall fall through */
18507 		default:
18508 			skip_infra = true;
18509 			WL_ERR(("Skipping infra setting for type:%d\n", iftype));
18510 			break;
18511 	}
18512 
18513 	if (!skip_infra) {
18514 		infra = htod32(infra);
18515 		err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
18516 		if (unlikely(err)) {
18517 			WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
18518 			return err;
18519 		}
18520 	}
18521 	return 0;
18522 }
18523 
wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf * ev,u16 event,bool set)18524 void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set)
18525 {
18526 	if (!ev || (event > WLC_E_LAST))
18527 		return;
18528 
18529 	if (ev->num < MAX_EVENT_BUF_NUM) {
18530 		ev->event[ev->num].type = event;
18531 		ev->event[ev->num].set = set;
18532 		ev->num++;
18533 	} else {
18534 		WL_ERR(("evenbuffer doesn't support > %u events. Update"
18535 			" the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
18536 		ASSERT(0);
18537 	}
18538 }
18539 
wl_cfg80211_apply_eventbuffer(struct net_device * ndev,struct bcm_cfg80211 * cfg,wl_eventmsg_buf_t * ev)18540 s32 wl_cfg80211_apply_eventbuffer(
18541 	struct net_device *ndev,
18542 	struct bcm_cfg80211 *cfg,
18543 	wl_eventmsg_buf_t *ev)
18544 {
18545 	char eventmask[WL_EVENTING_MASK_LEN];
18546 	int i, ret = 0;
18547 	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
18548 
18549 	if (!ev || (!ev->num))
18550 		return -EINVAL;
18551 
18552 	mutex_lock(&cfg->event_sync);
18553 
18554 	/* Read event_msgs mask */
18555 	ret = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
18556 	if (unlikely(ret)) {
18557 		WL_ERR(("Get event_msgs error (%d)\n", ret));
18558 		goto exit;
18559 	}
18560 	memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
18561 
18562 	/* apply the set bits */
18563 	for (i = 0; i < ev->num; i++) {
18564 		if (ev->event[i].set)
18565 			setbit(eventmask, ev->event[i].type);
18566 		else
18567 			clrbit(eventmask, ev->event[i].type);
18568 	}
18569 
18570 	/* Write updated Event mask */
18571 	ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf,
18572 			sizeof(iovbuf), NULL);
18573 	if (unlikely(ret)) {
18574 		WL_ERR(("Set event_msgs error (%d)\n", ret));
18575 	}
18576 
18577 exit:
18578 	mutex_unlock(&cfg->event_sync);
18579 	return ret;
18580 }
18581 
wl_add_remove_eventmsg(struct net_device * ndev,u16 event,bool add)18582 s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
18583 {
18584 	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
18585 	s8 eventmask[WL_EVENTING_MASK_LEN];
18586 	s32 err = 0;
18587 	struct bcm_cfg80211 *cfg;
18588 
18589 	if (!ndev)
18590 		return -ENODEV;
18591 
18592 	cfg = wl_get_cfg(ndev);
18593 	if (!cfg)
18594 		return -ENODEV;
18595 
18596 	mutex_lock(&cfg->event_sync);
18597 
18598 	/* Setup event_msgs */
18599 	err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
18600 	if (unlikely(err)) {
18601 		WL_ERR(("Get event_msgs error (%d)\n", err));
18602 		goto eventmsg_out;
18603 	}
18604 	memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
18605 	if (add) {
18606 		setbit(eventmask, event);
18607 	} else {
18608 		clrbit(eventmask, event);
18609 	}
18610 	err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
18611 			sizeof(iovbuf), NULL);
18612 	if (unlikely(err)) {
18613 		WL_ERR(("Set event_msgs error (%d)\n", err));
18614 		goto eventmsg_out;
18615 	}
18616 
18617 eventmsg_out:
18618 	mutex_unlock(&cfg->event_sync);
18619 	return err;
18620 }
18621 
wl_construct_reginfo(struct bcm_cfg80211 * cfg,s32 bw_cap)18622 static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
18623 {
18624 	struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
18625 	struct ieee80211_channel *band_chan_arr = NULL;
18626 	wl_uint32_list_t *list;
18627 	u32 i, j, index, n_2g, n_5g, band, channel, array_size;
18628 	u32 *n_cnt = NULL;
18629 	chanspec_t c = 0;
18630 	s32 err = BCME_OK;
18631 	bool update;
18632 	bool ht40_allowed;
18633 	u8 *pbuf = NULL;
18634 	bool dfs_radar_disabled = FALSE;
18635 
18636 #define LOCAL_BUF_LEN 2048
18637 	pbuf = (u8 *)MALLOCZ(cfg->osh, LOCAL_BUF_LEN);
18638 	if (pbuf == NULL) {
18639 		WL_ERR(("failed to allocate local buf\n"));
18640 		return -ENOMEM;
18641 	}
18642 
18643 	err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
18644 		0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
18645 	if (err != 0) {
18646 		WL_ERR(("get chanspecs failed with %d\n", err));
18647 		MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
18648 		return err;
18649 	}
18650 
18651 	list = (wl_uint32_list_t *)(void *)pbuf;
18652 	band = array_size = n_2g = n_5g = 0;
18653 	for (i = 0; i < dtoh32(list->count); i++) {
18654 		index = 0;
18655 		update = false;
18656 		ht40_allowed = false;
18657 		c = (chanspec_t)dtoh32(list->element[i]);
18658 		c = wl_chspec_driver_to_host(c);
18659 		channel = wf_chspec_ctlchan(c);
18660 
18661 		if (!CHSPEC_IS40(c) && ! CHSPEC_IS20(c)) {
18662 			WL_DBG(("HT80/160/80p80 center channel : %d\n", channel));
18663 			continue;
18664 		}
18665 		if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
18666 			(channel <= CH_MAX_2G_CHANNEL)) {
18667 			band_chan_arr = __wl_2ghz_channels;
18668 			array_size = ARRAYSIZE(__wl_2ghz_channels);
18669 			n_cnt = &n_2g;
18670 			band = IEEE80211_BAND_2GHZ;
18671 			ht40_allowed = (bw_cap  == WLC_N_BW_40ALL)? true : false;
18672 		} else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
18673 			band_chan_arr = __wl_5ghz_a_channels;
18674 			array_size = ARRAYSIZE(__wl_5ghz_a_channels);
18675 			n_cnt = &n_5g;
18676 			band = IEEE80211_BAND_5GHZ;
18677 			ht40_allowed = (bw_cap  == WLC_N_BW_20ALL)? false : true;
18678 		} else {
18679 			WL_ERR(("Invalid channel Sepc. 0x%x.\n", c));
18680 			continue;
18681 		}
18682 		if (!ht40_allowed && CHSPEC_IS40(c))
18683 			continue;
18684 		for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
18685 			if (band_chan_arr[j].hw_value == channel) {
18686 				update = true;
18687 				break;
18688 			}
18689 		}
18690 		if (update)
18691 			index = j;
18692 		else
18693 			index = *n_cnt;
18694 		if (!dhd_conf_match_channel(cfg->pub, channel))
18695 			continue;
18696 		if (index <  array_size) {
18697 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
18698 			band_chan_arr[index].center_freq =
18699 				ieee80211_channel_to_frequency(channel);
18700 #else
18701 			band_chan_arr[index].center_freq =
18702 				ieee80211_channel_to_frequency(channel, band);
18703 #endif // endif
18704 			band_chan_arr[index].hw_value = channel;
18705 			band_chan_arr[index].beacon_found = false;
18706 
18707 			if (CHSPEC_IS40(c) && ht40_allowed) {
18708 				/* assuming the order is HT20, HT40 Upper,
18709 				 *  HT40 lower from chanspecs
18710 				 */
18711 				u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
18712 				if (CHSPEC_SB_UPPER(c)) {
18713 					if (ht40_flag == IEEE80211_CHAN_NO_HT40)
18714 						band_chan_arr[index].flags &=
18715 							~IEEE80211_CHAN_NO_HT40;
18716 					band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
18717 				} else {
18718 					/* It should be one of
18719 					 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
18720 					 */
18721 					band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
18722 					if (ht40_flag == IEEE80211_CHAN_NO_HT40)
18723 						band_chan_arr[index].flags |=
18724 							IEEE80211_CHAN_NO_HT40MINUS;
18725 				}
18726 			} else {
18727 				band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
18728 				if (!dfs_radar_disabled) {
18729 					if (band == IEEE80211_BAND_2GHZ)
18730 						channel |= WL_CHANSPEC_BAND_2G;
18731 					else
18732 						channel |= WL_CHANSPEC_BAND_5G;
18733 					channel |= WL_CHANSPEC_BW_20;
18734 					channel = wl_chspec_host_to_driver(channel);
18735 					err = wldev_iovar_getint(dev, "per_chan_info", &channel);
18736 					if (!err) {
18737 						if (channel & WL_CHAN_RADAR) {
18738 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
18739 							band_chan_arr[index].flags |=
18740 								(IEEE80211_CHAN_RADAR
18741 								| IEEE80211_CHAN_NO_IBSS);
18742 #else
18743 							band_chan_arr[index].flags |=
18744 								IEEE80211_CHAN_RADAR;
18745 #endif // endif
18746 						}
18747 
18748 						if (channel & WL_CHAN_PASSIVE)
18749 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
18750 							band_chan_arr[index].flags |=
18751 								IEEE80211_CHAN_PASSIVE_SCAN;
18752 #else
18753 							band_chan_arr[index].flags |=
18754 								IEEE80211_CHAN_NO_IR;
18755 #endif // endif
18756 					} else if (err == BCME_UNSUPPORTED) {
18757 						dfs_radar_disabled = TRUE;
18758 						WL_ERR(("does not support per_chan_info\n"));
18759 					}
18760 				}
18761 			}
18762 			if (!update)
18763 				(*n_cnt)++;
18764 		}
18765 
18766 	}
18767 	__wl_band_2ghz.n_channels = n_2g;
18768 	__wl_band_5ghz_a.n_channels = n_5g;
18769 	MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
18770 #undef LOCAL_BUF_LEN
18771 
18772 	return err;
18773 }
18774 
__wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)18775 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
18776 {
18777 	struct wiphy *wiphy;
18778 	struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
18779 	u32 bandlist[3];
18780 	u32 nband = 0;
18781 	u32 i = 0;
18782 	s32 err = 0;
18783 	s32 index = 0;
18784 	s32 nmode = 0;
18785 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18786 	u32 j = 0;
18787 	s32 vhtmode = 0;
18788 	s32 txstreams = 0;
18789 	s32 rxstreams = 0;
18790 	s32 ldpc_cap = 0;
18791 	s32 stbc_rx = 0;
18792 	s32 stbc_tx = 0;
18793 	s32 txbf_bfe_cap = 0;
18794 	s32 txbf_bfr_cap = 0;
18795 #endif // endif
18796 	s32 bw_cap = 0;
18797 	s32 cur_band = -1;
18798 	struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, };
18799 
18800 	bzero(bandlist, sizeof(bandlist));
18801 	err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist,
18802 		sizeof(bandlist));
18803 	if (unlikely(err)) {
18804 		WL_ERR(("error read bandlist (%d)\n", err));
18805 		return err;
18806 	}
18807 	err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band,
18808 		sizeof(s32));
18809 	if (unlikely(err)) {
18810 		WL_ERR(("error (%d)\n", err));
18811 		return err;
18812 	}
18813 
18814 	err = wldev_iovar_getint(dev, "nmode", &nmode);
18815 	if (unlikely(err)) {
18816 		WL_ERR(("error reading nmode (%d)\n", err));
18817 	}
18818 
18819 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18820 	err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
18821 	if (unlikely(err)) {
18822 		WL_ERR(("error reading vhtmode (%d)\n", err));
18823 	}
18824 
18825 	if (vhtmode) {
18826 		err = wldev_iovar_getint(dev, "txstreams", &txstreams);
18827 		if (unlikely(err)) {
18828 			WL_ERR(("error reading txstreams (%d)\n", err));
18829 		}
18830 
18831 		err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
18832 		if (unlikely(err)) {
18833 			WL_ERR(("error reading rxstreams (%d)\n", err));
18834 		}
18835 
18836 		err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
18837 		if (unlikely(err)) {
18838 			WL_ERR(("error reading ldpc_cap (%d)\n", err));
18839 		}
18840 
18841 		err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
18842 		if (unlikely(err)) {
18843 			WL_ERR(("error reading stbc_rx (%d)\n", err));
18844 		}
18845 
18846 		err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
18847 		if (unlikely(err)) {
18848 			WL_ERR(("error reading stbc_tx (%d)\n", err));
18849 		}
18850 
18851 		err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
18852 		if (unlikely(err)) {
18853 			WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
18854 		}
18855 
18856 		err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
18857 		if (unlikely(err)) {
18858 			WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
18859 		}
18860 	}
18861 #endif // endif
18862 
18863 	/* For nmode and vhtmode   check bw cap */
18864 	if (nmode ||
18865 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18866 		vhtmode ||
18867 #endif // endif
18868 		0) {
18869 		err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
18870 		if (unlikely(err)) {
18871 			WL_ERR(("error get mimo_bw_cap (%d)\n", err));
18872 		}
18873 	}
18874 
18875 	err = wl_construct_reginfo(cfg, bw_cap);
18876 	if (err) {
18877 		WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
18878 		if (err != BCME_UNSUPPORTED)
18879 			return err;
18880 	}
18881 
18882 	wiphy = bcmcfg_to_wiphy(cfg);
18883 	nband = bandlist[0];
18884 
18885 	for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
18886 		index = -1;
18887 		if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
18888 			bands[IEEE80211_BAND_5GHZ] =
18889 				&__wl_band_5ghz_a;
18890 			index = IEEE80211_BAND_5GHZ;
18891 			if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
18892 				bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
18893 
18894 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18895 			/* VHT capabilities. */
18896 			if (vhtmode) {
18897 				/* Supported */
18898 				bands[index]->vht_cap.vht_supported = TRUE;
18899 
18900 				for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
18901 					/* TX stream rates. */
18902 					if (j <= txstreams) {
18903 						VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
18904 							bands[index]->vht_cap.vht_mcs.tx_mcs_map);
18905 					} else {
18906 						VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
18907 							bands[index]->vht_cap.vht_mcs.tx_mcs_map);
18908 					}
18909 
18910 					/* RX stream rates. */
18911 					if (j <= rxstreams) {
18912 						VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
18913 							bands[index]->vht_cap.vht_mcs.rx_mcs_map);
18914 					} else {
18915 						VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
18916 							bands[index]->vht_cap.vht_mcs.rx_mcs_map);
18917 					}
18918 				}
18919 
18920 				/* Capabilities */
18921 				/* 80 MHz is mandatory */
18922 				bands[index]->vht_cap.cap |=
18923 					IEEE80211_VHT_CAP_SHORT_GI_80;
18924 
18925 				if (WL_BW_CAP_160MHZ(bw_cap)) {
18926 					bands[index]->vht_cap.cap |=
18927 						IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
18928 					bands[index]->vht_cap.cap |=
18929 						IEEE80211_VHT_CAP_SHORT_GI_160;
18930 				}
18931 
18932 				bands[index]->vht_cap.cap |=
18933 					IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
18934 
18935 				if (ldpc_cap)
18936 					bands[index]->vht_cap.cap |=
18937 						IEEE80211_VHT_CAP_RXLDPC;
18938 
18939 				if (stbc_tx)
18940 					bands[index]->vht_cap.cap |=
18941 						IEEE80211_VHT_CAP_TXSTBC;
18942 
18943 				if (stbc_rx)
18944 					bands[index]->vht_cap.cap |=
18945 						(stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
18946 
18947 				if (txbf_bfe_cap)
18948 					bands[index]->vht_cap.cap |=
18949 						IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
18950 
18951 				if (txbf_bfr_cap) {
18952 					bands[index]->vht_cap.cap |=
18953 						IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
18954 				}
18955 
18956 				if (txbf_bfe_cap || txbf_bfr_cap) {
18957 					bands[index]->vht_cap.cap |=
18958 						(2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
18959 					bands[index]->vht_cap.cap |=
18960 						((txstreams - 1) <<
18961 							VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
18962 					bands[index]->vht_cap.cap |=
18963 						IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
18964 				}
18965 
18966 				/* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
18967 				bands[index]->vht_cap.cap |=
18968 					(7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
18969 				WL_DBG(("__wl_update_wiphybands band[%d] vht_enab=%d vht_cap=%08x "
18970 					"vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
18971 					index,
18972 					bands[index]->vht_cap.vht_supported,
18973 					bands[index]->vht_cap.cap,
18974 					bands[index]->vht_cap.vht_mcs.rx_mcs_map,
18975 					bands[index]->vht_cap.vht_mcs.tx_mcs_map));
18976 			}
18977 #endif // endif
18978 		}
18979 		else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
18980 			bands[IEEE80211_BAND_2GHZ] =
18981 				&__wl_band_2ghz;
18982 			index = IEEE80211_BAND_2GHZ;
18983 			if (bw_cap == WLC_N_BW_40ALL)
18984 				bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
18985 		}
18986 
18987 		if ((index >= 0) && nmode) {
18988 			bands[index]->ht_cap.cap |=
18989 				(IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
18990 			bands[index]->ht_cap.ht_supported = TRUE;
18991 			bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
18992 			bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
18993 			/* An HT shall support all EQM rates for one spatial stream */
18994 			bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
18995 		}
18996 
18997 	}
18998 
18999 	wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
19000 	wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
19001 
19002 	/* check if any bands populated otherwise makes 2Ghz as default */
19003 	if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL &&
19004 		wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) {
19005 		/* Setup 2Ghz band as default */
19006 		wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
19007 	}
19008 
19009 	if (notify)
19010 		wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
19011 
19012 	return 0;
19013 }
19014 
wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)19015 s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
19016 {
19017 	s32 err;
19018 
19019 	mutex_lock(&cfg->usr_sync);
19020 	err = __wl_update_wiphybands(cfg, notify);
19021 	mutex_unlock(&cfg->usr_sync);
19022 
19023 	return err;
19024 }
19025 
__wl_cfg80211_up(struct bcm_cfg80211 * cfg)19026 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
19027 {
19028 	s32 err = 0;
19029 	s32 ret = 0;
19030 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
19031 	struct wireless_dev *wdev = ndev->ieee80211_ptr;
19032 	dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
19033 #ifdef WLTDLS
19034 	u32 tdls;
19035 #endif /* WLTDLS */
19036 	u16 wl_iftype = 0;
19037 	u16 wl_mode = 0;
19038 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
19039 
19040 	WL_DBG(("In\n"));
19041 
19042 	if (!dhd_download_fw_on_driverload) {
19043 		err = wl_create_event_handler(cfg);
19044 		if (err) {
19045 			WL_ERR(("wl_create_event_handler failed\n"));
19046 			return err;
19047 		}
19048 		wl_init_event_handler(cfg);
19049 	}
19050 	/* Reserve 0x8000 toggle bit for P2P GO/GC */
19051 	cfg->vif_macaddr_mask = 0x8000;
19052 
19053 	err = dhd_config_dongle(cfg);
19054 	if (unlikely(err))
19055 		return err;
19056 
19057 #if 0
19058 	/* terence 20180108: this patch will cause to kernel panic with below
19059 	* steps in Android 4.4 with kernel 3.4
19060 	* insmod bcmdhd.ko; hostapd /data/misc/wifi/hostapd.conf
19061 	*/
19062 	/* Always bring up interface in STA mode.
19063 	* Did observe , if previous SofAP Bringup/cleanup
19064 	* is not done properly, iftype is stuck with AP mode.
19065 	* So during next wlan0 up, forcing the type to STA
19066 	*/
19067 	netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
19068 	if (!netinfo) {
19069 		WL_ERR(("there is no netinfo\n"));
19070 		return -ENODEV;
19071 	}
19072 	ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
19073 	netinfo->iftype = WL_IF_TYPE_STA;
19074 #endif
19075 
19076 	if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
19077 		return -EINVAL;
19078 	}
19079 	err = wl_config_infra(cfg, ndev, wl_iftype);
19080 	if (unlikely(err && err != -EINPROGRESS)) {
19081 		WL_ERR(("wl_config_infra failed\n"));
19082 		if (err == -1) {
19083 			WL_ERR(("return error %d\n", err));
19084 			return err;
19085 		}
19086 	}
19087 
19088 	err = wl_init_scan(cfg);
19089 	if (err) {
19090 		WL_ERR(("wl_init_scan failed\n"));
19091 		return err;
19092 	}
19093 	err = __wl_update_wiphybands(cfg, true);
19094 	if (unlikely(err)) {
19095 		WL_ERR(("wl_update_wiphybands failed\n"));
19096 		if (err == -1) {
19097 			WL_ERR(("return error %d\n", err));
19098 			return err;
19099 		}
19100 	}
19101 
19102 	/* Update wlc version in cfg struct already queried as part of DHD  initialization */
19103 	cfg->wlc_ver.wlc_ver_major = dhd->wlc_ver_major;
19104 	cfg->wlc_ver.wlc_ver_minor = dhd->wlc_ver_minor;
19105 
19106 	if ((ret = wldev_iovar_getbuf(ndev, "scan_ver", NULL, 0,
19107 		ioctl_buf, sizeof(ioctl_buf), NULL)) == BCME_OK) {
19108 		WL_INFORM_MEM(("scan_params v2\n"));
19109 		/* use scan_params ver2 */
19110 		cfg->scan_params_v2 = true;
19111 	} else {
19112 		if (ret == BCME_UNSUPPORTED) {
19113 			WL_INFORM(("scan_ver, UNSUPPORTED\n"));
19114 			ret = BCME_OK;
19115 		} else {
19116 			WL_ERR(("get scan_ver err(%d)\n", ret));
19117 		}
19118 	}
19119 #ifdef DHD_LOSSLESS_ROAMING
19120 	if (timer_pending(&cfg->roam_timeout)) {
19121 		del_timer_sync(&cfg->roam_timeout);
19122 	}
19123 #endif /* DHD_LOSSLESS_ROAMING */
19124 
19125 	err = dhd_monitor_init(cfg->pub);
19126 
19127 #ifdef WL_HOST_BAND_MGMT
19128 	/* By default the curr_band is initialized to BAND_AUTO */
19129 	if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) {
19130 		if (ret == BCME_UNSUPPORTED) {
19131 			/* Don't fail the initialization, lets just
19132 			 * fall back to the original method
19133 			 */
19134 			WL_ERR(("WL_HOST_BAND_MGMT defined, "
19135 				"but roam_band iovar not supported \n"));
19136 		} else {
19137 			WL_ERR(("roam_band failed. ret=%d", ret));
19138 			err = -1;
19139 		}
19140 	}
19141 #endif /* WL_HOST_BAND_MGMT */
19142 #ifdef WLTDLS
19143 	if (wldev_iovar_getint(ndev, "tdls_enable", &tdls) == 0) {
19144 		WL_DBG(("TDLS supported in fw\n"));
19145 		cfg->tdls_supported = true;
19146 	}
19147 #endif /* WLTDLS */
19148 #ifdef WL_IFACE_MGMT
19149 #ifdef CUSTOM_IF_MGMT_POLICY
19150 	cfg->iface_data.policy = CUSTOM_IF_MGMT_POLICY;
19151 #else
19152 	cfg->iface_data.policy = WL_IF_POLICY_DEFAULT;
19153 #endif /*  CUSTOM_IF_MGMT_POLICY */
19154 #endif /* WL_IFACE_MGMT */
19155 #ifdef WL_NAN
19156 #ifdef WL_NANP2P
19157 	if (FW_SUPPORTED(dhd, nanp2p)) {
19158 		/* Enable NANP2P concurrent support */
19159 		cfg->conc_disc = WL_NANP2P_CONC_SUPPORT;
19160 		WL_INFORM_MEM(("nan + p2p conc discovery is supported\n"));
19161 		cfg->nan_p2p_supported = true;
19162 	}
19163 #endif /* WL_NANP2P */
19164 #endif /* WL_NAN  */
19165 
19166 	INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
19167 	wl_set_drv_status(cfg, READY, ndev);
19168 	return err;
19169 }
19170 
__wl_cfg80211_down(struct bcm_cfg80211 * cfg)19171 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
19172 {
19173 	s32 err = 0;
19174 	struct net_info *iter, *next;
19175 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
19176 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
19177 	defined(WL_NEW_CFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
19178 	struct net_device *p2p_net = cfg->p2p_net;
19179 #endif
19180 
19181 	dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
19182 	WL_INFORM_MEM(("cfg80211 down\n"));
19183 
19184 	/* Check if cfg80211 interface is already down */
19185 	if (!wl_get_drv_status(cfg, READY, ndev)) {
19186 		WL_DBG(("cfg80211 interface is already down\n"));
19187 		return err;	/* it is even not ready */
19188 	}
19189 
19190 #ifdef SHOW_LOGTRACE
19191 	/* Stop the event logging */
19192 	wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
19193 #endif /* SHOW_LOGTRACE */
19194 
19195 	/* clear vendor OUI list */
19196 	wl_vndr_ies_clear_vendor_oui_list(cfg);
19197 
19198 	/* Delete pm_enable_work */
19199 	wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
19200 
19201 	if (cfg->p2p_supported) {
19202 		wl_clr_p2p_status(cfg, GO_NEG_PHASE);
19203 #ifdef PROP_TXSTATUS_VSDB
19204 #if defined(BCMSDIO) || defined(BCMDBUS)
19205 		if (wl_cfgp2p_vif_created(cfg)) {
19206 			bool enabled = false;
19207 			dhd_wlfc_get_enable(dhd, &enabled);
19208 			if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
19209 				dhd->op_mode != DHD_FLAG_IBSS_MODE) {
19210 				dhd_wlfc_deinit(dhd);
19211 				cfg->wlfc_on = false;
19212 			}
19213 		}
19214 #endif /* BCMSDIO || BCMDBUS */
19215 #endif /* PROP_TXSTATUS_VSDB */
19216 	}
19217 
19218 #ifdef WL_NAN
19219 	mutex_lock(&cfg->if_sync);
19220 	/* Cancel pending nan disable work if any */
19221 	if (delayed_work_pending(&cfg->nan_disable)) {
19222 		WL_DBG(("Unarm the nan_disable work\n"));
19223 		cancel_delayed_work_sync(&cfg->nan_disable);
19224 	}
19225 	cfg->nancfg.disable_reason = NAN_BUS_IS_DOWN;
19226 	wl_cfgnan_disable(cfg);
19227 	mutex_unlock(&cfg->if_sync);
19228 #endif /* WL_NAN */
19229 
19230 	if (!dhd_download_fw_on_driverload) {
19231 		/* For built-in drivers/other drivers that do reset on
19232 		 * "ifconfig <primary_iface> down", cleanup any left
19233 		 * over interfaces
19234 		 */
19235 		wl_cfg80211_cleanup_virtual_ifaces(cfg, false);
19236 	}
19237 	/* Clear used mac addr mask */
19238 	cfg->vif_macaddr_mask = 0;
19239 
19240 	if (dhd->up)
19241 	{
19242 		/* If primary BSS is operational (for e.g SoftAP), bring it down */
19243 		if (wl_cfg80211_bss_isup(ndev, 0)) {
19244 			if (wl_cfg80211_bss_up(cfg, ndev, 0, 0) < 0)
19245 				WL_ERR(("BSS down failed \n"));
19246 		}
19247 
19248 		/* clear all the security setting on primary Interface */
19249 		wl_cfg80211_clear_security(cfg);
19250 	}
19251 
19252 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19253 	for_each_ndev(cfg, iter, next) {
19254 		GCC_DIAGNOSTIC_POP();
19255 		if (iter->ndev) /* p2p discovery iface is null */
19256 			wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
19257 	}
19258 
19259 #ifdef P2P_LISTEN_OFFLOADING
19260 	wl_cfg80211_p2plo_deinit(cfg);
19261 #endif /* P2P_LISTEN_OFFLOADING */
19262 
19263 	/* cancel and notify scan complete, if scan request is pending */
19264 	wl_cfg80211_cancel_scan(cfg);
19265 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19266 	for_each_ndev(cfg, iter, next) {
19267 		GCC_DIAGNOSTIC_POP();
19268 		/* p2p discovery iface ndev ptr could be null */
19269 		if (iter->ndev == NULL)
19270 			continue;
19271 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19272 		WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
19273 			wl_get_drv_status(cfg, CONNECTING, ndev),
19274 			wl_get_drv_status(cfg, CONNECTED, ndev),
19275 			wl_get_drv_status(cfg, DISCONNECTING, ndev),
19276 			wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
19277 
19278 		if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
19279 			CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
19280 		}
19281 
19282 		if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
19283 			wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
19284 
19285 			u8 *latest_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
19286 			struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
19287 			struct wireless_dev *wdev = ndev->ieee80211_ptr;
19288 			struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid,
19289 				wdev->ssid, wdev->ssid_len);
19290 
19291 			BCM_REFERENCE(bss);
19292 
19293 			CFG80211_CONNECT_RESULT(ndev,
19294 				latest_bssid, bss, NULL, 0, NULL, 0,
19295 				WLAN_STATUS_UNSPECIFIED_FAILURE,
19296 				GFP_KERNEL);
19297 		}
19298 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19299 		wl_clr_drv_status(cfg, READY, iter->ndev);
19300 		wl_clr_drv_status(cfg, SCANNING, iter->ndev);
19301 		wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
19302 		wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
19303 		wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
19304 		wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
19305 		wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
19306 		wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
19307 		wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev);
19308 		wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev);
19309 	}
19310 	bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
19311 		NL80211_IFTYPE_STATION;
19312 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
19313 	defined(WL_NEW_CFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
19314 		if (p2p_net)
19315 			dev_close(p2p_net);
19316 #endif
19317 
19318 	/* Avoid deadlock from wl_cfg80211_down */
19319 	if (!dhd_download_fw_on_driverload) {
19320 		mutex_unlock(&cfg->usr_sync);
19321 		wl_destroy_event_handler(cfg);
19322 		mutex_lock(&cfg->usr_sync);
19323 	}
19324 
19325 	wl_flush_eq(cfg);
19326 	wl_link_down(cfg);
19327 	if (cfg->p2p_supported) {
19328 		if (timer_pending(&cfg->p2p->listen_timer))
19329 			del_timer_sync(&cfg->p2p->listen_timer);
19330 		wl_cfgp2p_down(cfg);
19331 	}
19332 
19333 	if (timer_pending(&cfg->scan_timeout)) {
19334 		del_timer_sync(&cfg->scan_timeout);
19335 	}
19336 
19337 	wl_cfg80211_clear_mgmt_vndr_ies(cfg);
19338 	DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
19339 
19340 	dhd_monitor_uninit();
19341 #ifdef WLAIBSS_MCHAN
19342 	bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
19343 #endif /* WLAIBSS_MCHAN */
19344 
19345 #ifdef WL11U
19346 	/* Clear interworking element. */
19347 	if (cfg->wl11u) {
19348 		cfg->wl11u = FALSE;
19349 	}
19350 #endif /* WL11U */
19351 
19352 	cfg->disable_roam_event = false;
19353 	cfg->scan_params_v2 = false;
19354 
19355 	DNGL_FUNC(dhd_cfg80211_down, (cfg));
19356 
19357 #ifdef DHD_IFDEBUG
19358 	/* Printout all netinfo entries */
19359 	wl_probe_wdev_all(cfg);
19360 #endif /* DHD_IFDEBUG */
19361 
19362 	return err;
19363 }
19364 
wl_cfg80211_up(struct net_device * net)19365 s32 wl_cfg80211_up(struct net_device *net)
19366 {
19367 	struct bcm_cfg80211 *cfg;
19368 	s32 err = 0;
19369 	int val = 1;
19370 	dhd_pub_t *dhd;
19371 #ifdef DISABLE_PM_BCNRX
19372 	s32 interr = 0;
19373 	uint param = 0;
19374 	s8 iovbuf[WLC_IOCTL_SMLEN];
19375 #endif /* DISABLE_PM_BCNRX */
19376 
19377 	WL_DBG(("In\n"));
19378 	cfg = wl_get_cfg(net);
19379 
19380 	if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
19381 		sizeof(int)) < 0)) {
19382 		WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
19383 		return err;
19384 	}
19385 	val = dtoh32(val);
19386 	if (val != WLC_IOCTL_VERSION && val != 1) {
19387 		WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
19388 			val, WLC_IOCTL_VERSION));
19389 		return BCME_VERSION;
19390 	}
19391 	ioctl_version = val;
19392 	WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
19393 	wl_ext_in4way_sync(net, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
19394 		WL_EXT_STATUS_DISCONNECTED, NULL);
19395 
19396 	mutex_lock(&cfg->usr_sync);
19397 	dhd = (dhd_pub_t *)(cfg->pub);
19398 	if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
19399 		err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
19400 		if (unlikely(err)) {
19401 			mutex_unlock(&cfg->usr_sync);
19402 			return err;
19403 		}
19404 	}
19405 #ifdef WLMESH_CFG80211
19406 	cfg->wdev->wiphy->features |= NL80211_FEATURE_USERSPACE_MPM;
19407 #endif /* WLMESH_CFG80211 */
19408 #if defined(BCMSUP_4WAY_HANDSHAKE)
19409 	if (dhd->fw_4way_handshake) {
19410 		/* This is a hacky method to indicate fw 4WHS support and
19411 		 * is used only for kernels (kernels < 3.14). For newer
19412 		 * kernels, we would be using vendor extn. path to advertise
19413 		 * FW based 4-way handshake feature support.
19414 		 */
19415 		cfg->wdev->wiphy->features |= NL80211_FEATURE_FW_4WAY_HANDSHAKE;
19416 	}
19417 #endif /* BCMSUP_4WAY_HANDSHAKE */
19418 	err = __wl_cfg80211_up(cfg);
19419 	if (unlikely(err))
19420 		WL_ERR(("__wl_cfg80211_up failed\n"));
19421 
19422 #ifdef ROAM_CHANNEL_CACHE
19423 	if (init_roam_cache(cfg, ioctl_version) == 0) {
19424 		/* Enable support for Roam cache */
19425 		cfg->rcc_enabled = true;
19426 		WL_ERR(("Roam channel cache enabled\n"));
19427 	} else {
19428 		WL_ERR(("Failed to enable RCC.\n"));
19429 	}
19430 #endif /* ROAM_CHANNEL_CACHE */
19431 
19432 	/* IOVAR configurations with 'up' condition */
19433 #ifdef DISABLE_PM_BCNRX
19434 	interr = wldev_iovar_setbuf(net, "pm_bcnrx", (char *)&param, sizeof(param), iovbuf,
19435 			sizeof(iovbuf), &cfg->ioctl_buf_sync);
19436 
19437 	if (unlikely(interr)) {
19438 		WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
19439 	}
19440 #endif /* DISABLE_PM_BCNRX */
19441 #ifdef WL_CHAN_UTIL
19442 	interr = wl_cfg80211_start_bssload_report(net);
19443 	if (unlikely(interr)) {
19444 		WL_ERR(("%s: Failed to start bssload_report eventing, err=%d\n",
19445 			__FUNCTION__, interr));
19446 	}
19447 #endif /* WL_CHAN_UTIL */
19448 
19449 	mutex_unlock(&cfg->usr_sync);
19450 
19451 #ifdef WLAIBSS_MCHAN
19452 	bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
19453 #endif /* WLAIBSS_MCHAN */
19454 	return err;
19455 }
19456 
19457 /* Private Event to Supplicant with indication that chip hangs */
wl_cfg80211_hang(struct net_device * dev,u16 reason)19458 int wl_cfg80211_hang(struct net_device *dev, u16 reason)
19459 {
19460 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19461 	dhd_pub_t *dhd;
19462 	if (!cfg) {
19463 		return BCME_ERROR;
19464 	}
19465 
19466 	RETURN_EIO_IF_NOT_UP(cfg);
19467 
19468 	dhd = (dhd_pub_t *)(cfg->pub);
19469 	if ((dhd->hang_reason <= HANG_REASON_MASK) || (dhd->hang_reason >= HANG_REASON_MAX)) {
19470 		WL_ERR(("wl_cfg80211_hang, Invalid hang reason 0x%x\n",
19471 			dhd->hang_reason));
19472 		dhd->hang_reason = HANG_REASON_UNKNOWN;
19473 	}
19474 	WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32)(dhd->hang_reason)));
19475 
19476 	wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
19477 	{
19478 		if (dhd->up == TRUE) {
19479 			CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
19480 		}
19481 	}
19482 #if defined(RSSIAVG)
19483 	wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
19484 #endif
19485 #if defined(BSSCACHE)
19486 	wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
19487 #endif
19488 	if (cfg != NULL) {
19489 		wl_link_down(cfg);
19490 	}
19491 	return 0;
19492 }
19493 
wl_cfg80211_down(struct net_device * dev)19494 s32 wl_cfg80211_down(struct net_device *dev)
19495 {
19496 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19497 	s32 err = BCME_ERROR;
19498 
19499 	WL_DBG(("In\n"));
19500 
19501 	if (cfg && (cfg == wl_cfg80211_get_bcmcfg())) {
19502 		mutex_lock(&cfg->usr_sync);
19503 #if defined(RSSIAVG)
19504 		wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
19505 #endif
19506 #if defined(BSSCACHE)
19507 		wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
19508 #endif
19509 		err = __wl_cfg80211_down(cfg);
19510 		mutex_unlock(&cfg->usr_sync);
19511 	}
19512 
19513 	return err;
19514 }
19515 
19516 void
wl_cfg80211_sta_ifdown(struct net_device * dev)19517 wl_cfg80211_sta_ifdown(struct net_device *dev)
19518 {
19519 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19520 
19521 	WL_DBG(("In\n"));
19522 
19523 	if (cfg) {
19524 		/* cancel scan if anything pending */
19525 		wl_cfg80211_cancel_scan(cfg);
19526 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19527 		if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
19528 			wl_get_drv_status(cfg, CONNECTED, dev)) {
19529 			CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
19530 		}
19531 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19532 	}
19533 }
19534 
wl_read_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 item)19535 void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
19536 {
19537 	unsigned long flags;
19538 	void *rptr = NULL;
19539 	struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
19540 
19541 	if (!profile)
19542 		return NULL;
19543 	WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
19544 	switch (item) {
19545 	case WL_PROF_SEC:
19546 		rptr = &profile->sec;
19547 		break;
19548 	case WL_PROF_ACT:
19549 		rptr = &profile->active;
19550 		break;
19551 	case WL_PROF_BSSID:
19552 		rptr = profile->bssid;
19553 		break;
19554 	case WL_PROF_SSID:
19555 		rptr = &profile->ssid;
19556 		break;
19557 	case WL_PROF_CHAN:
19558 		rptr = &profile->channel;
19559 		break;
19560 	case WL_PROF_LATEST_BSSID:
19561 		rptr = profile->latest_bssid;
19562 		break;
19563 	}
19564 	WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
19565 	if (!rptr)
19566 		WL_ERR(("invalid item (%d)\n", item));
19567 	return rptr;
19568 }
19569 
19570 static s32
wl_update_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,const void * data,s32 item)19571 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
19572 	const wl_event_msg_t *e, const void *data, s32 item)
19573 {
19574 	s32 err = 0;
19575 	const struct wlc_ssid *ssid;
19576 	unsigned long flags;
19577 	struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
19578 
19579 	if (!profile)
19580 		return WL_INVALID;
19581 	WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
19582 	switch (item) {
19583 	case WL_PROF_SSID:
19584 		ssid = (const wlc_ssid_t *) data;
19585 		bzero(profile->ssid.SSID,
19586 			sizeof(profile->ssid.SSID));
19587 		profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
19588 		memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
19589 		break;
19590 	case WL_PROF_BSSID:
19591 		if (data)
19592 			memcpy(profile->bssid, data, ETHER_ADDR_LEN);
19593 		else
19594 			bzero(profile->bssid, ETHER_ADDR_LEN);
19595 		break;
19596 	case WL_PROF_SEC:
19597 		memcpy(&profile->sec, data, sizeof(profile->sec));
19598 		break;
19599 	case WL_PROF_ACT:
19600 		profile->active = *(const bool *)data;
19601 		break;
19602 	case WL_PROF_BEACONINT:
19603 		profile->beacon_interval = *(const u16 *)data;
19604 		break;
19605 	case WL_PROF_DTIMPERIOD:
19606 		profile->dtim_period = *(const u8 *)data;
19607 		break;
19608 	case WL_PROF_CHAN:
19609 		profile->channel = *(const u32*)data;
19610 		break;
19611 	case WL_PROF_LATEST_BSSID:
19612 		if (data) {
19613 			memcpy_s(profile->latest_bssid, sizeof(profile->latest_bssid),
19614 					data, ETHER_ADDR_LEN);
19615 		} else {
19616 			memset_s(profile->latest_bssid, sizeof(profile->latest_bssid),
19617 					0, ETHER_ADDR_LEN);
19618 		}
19619 		break;
19620 	default:
19621 		err = -EOPNOTSUPP;
19622 		break;
19623 	}
19624 	WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
19625 
19626 	if (err == -EOPNOTSUPP)
19627 		WL_ERR(("unsupported item (%d)\n", item));
19628 
19629 	return err;
19630 }
19631 
wl_cfg80211_dbg_level(u32 level)19632 void wl_cfg80211_dbg_level(u32 level)
19633 {
19634 	/*
19635 	* prohibit to change debug level
19636 	* by insmod parameter.
19637 	* eventually debug level will be configured
19638 	* in compile time by using CONFIG_XXX
19639 	*/
19640 	/* wl_dbg_level = level; */
19641 }
19642 
wl_is_ibssmode(struct bcm_cfg80211 * cfg,struct net_device * ndev)19643 static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev)
19644 {
19645 	return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS;
19646 }
19647 
wl_is_ibssstarter(struct bcm_cfg80211 * cfg)19648 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
19649 {
19650 	return cfg->ibss_starter;
19651 }
19652 
wl_rst_ie(struct bcm_cfg80211 * cfg)19653 static void wl_rst_ie(struct bcm_cfg80211 *cfg)
19654 {
19655 	struct wl_ie *ie = wl_to_ie(cfg);
19656 
19657 	ie->offset = 0;
19658 	bzero(ie->buf, sizeof(ie->buf));
19659 }
19660 
wl_add_ie(struct bcm_cfg80211 * cfg,u8 t,u8 l,u8 * v)19661 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
19662 {
19663 	struct wl_ie *ie = wl_to_ie(cfg);
19664 	s32 err = 0;
19665 
19666 	if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
19667 		WL_ERR(("ei crosses buffer boundary\n"));
19668 		return -ENOSPC;
19669 	}
19670 	ie->buf[ie->offset] = t;
19671 	ie->buf[ie->offset + 1] = l;
19672 	memcpy(&ie->buf[ie->offset + 2], v, l);
19673 	ie->offset += l + 2;
19674 
19675 	return err;
19676 }
19677 
wl_update_hidden_ap_ie(wl_bss_info_t * bi,const u8 * ie_stream,u32 * ie_size,bool update_ssid)19678 static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 *ie_size,
19679 	bool update_ssid)
19680 {
19681 	u8 *ssidie;
19682 	int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN);
19683 	int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len;
19684 	/* cfg80211_find_ie defined in kernel returning const u8 */
19685 
19686 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19687 	ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
19688 	GCC_DIAGNOSTIC_POP();
19689 
19690 	/* ERROR out if
19691 	 * 1. No ssid IE is FOUND or
19692 	 * 2. New ssid length is > what was allocated for existing ssid (as
19693 	 * we do not want to overwrite the rest of the IEs) or
19694 	 * 3. If in case of erroneous buffer input where ssid length doesnt match the space
19695 	 * allocated to it.
19696 	 */
19697 	if (!ssidie) {
19698 		return;
19699 	}
19700 	available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream);
19701 	remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
19702 	unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size);
19703 	if (ssidie[1] > available_buffer_len) {
19704 		WL_ERR_MEM(("wl_update_hidden_ap_ie: skip wl_update_hidden_ap_ie : overflow\n"));
19705 		return;
19706 	}
19707 
19708 	if (ssidie[1] != ssid_len) {
19709 		if (ssidie[1]) {
19710 			WL_ERR_RLMT(("wl_update_hidden_ap_ie: Wrong SSID len: %d != %d\n",
19711 				ssidie[1], bi->SSID_len));
19712 		}
19713 		/*
19714 		 * The bss info in firmware gets updated from beacon and probe resp.
19715 		 * In case of hidden network, the bss_info that got updated by beacon,
19716 		 * will not carry SSID and this can result in cfg80211_get_bss not finding a match.
19717 		 * so include the SSID element.
19718 		 */
19719 		if ((update_ssid && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) {
19720 			WL_INFORM_MEM(("Changing the SSID Info.\n"));
19721 			memmove(ssidie + ssid_len + 2,
19722 				(ssidie + 2) + ssidie[1],
19723 				remaining_ie_buf_len);
19724 			memcpy(ssidie + 2, bi->SSID, ssid_len);
19725 			*ie_size = *ie_size + ssid_len - ssidie[1];
19726 			ssidie[1] = ssid_len;
19727 		} else if (ssid_len < ssidie[1]) {
19728 			WL_ERR_MEM(("wl_update_hidden_ap_ie: Invalid SSID len: %d < %d\n",
19729 				bi->SSID_len, ssidie[1]));
19730 		}
19731 		return;
19732 	}
19733 	if (*(ssidie + 2) == '\0')
19734 		 memcpy(ssidie + 2, bi->SSID, ssid_len);
19735 	return;
19736 }
19737 
wl_mrg_ie(struct bcm_cfg80211 * cfg,u8 * ie_stream,u16 ie_size)19738 static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size)
19739 {
19740 	struct wl_ie *ie = wl_to_ie(cfg);
19741 	s32 err = 0;
19742 
19743 	if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
19744 		WL_ERR(("ei_stream crosses buffer boundary\n"));
19745 		return -ENOSPC;
19746 	}
19747 	memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
19748 	ie->offset += ie_size;
19749 
19750 	return err;
19751 }
19752 
wl_cp_ie(struct bcm_cfg80211 * cfg,u8 * dst,u16 dst_size)19753 static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size)
19754 {
19755 	struct wl_ie *ie = wl_to_ie(cfg);
19756 	s32 err = 0;
19757 
19758 	if (unlikely(ie->offset > dst_size)) {
19759 		WL_ERR(("dst_size is not enough\n"));
19760 		return -ENOSPC;
19761 	}
19762 	memcpy(dst, &ie->buf[0], ie->offset);
19763 
19764 	return err;
19765 }
19766 
wl_get_ielen(struct bcm_cfg80211 * cfg)19767 static u32 wl_get_ielen(struct bcm_cfg80211 *cfg)
19768 {
19769 	struct wl_ie *ie = wl_to_ie(cfg);
19770 
19771 	return ie->offset;
19772 }
19773 
wl_link_up(struct bcm_cfg80211 * cfg)19774 static void wl_link_up(struct bcm_cfg80211 *cfg)
19775 {
19776 	cfg->link_up = true;
19777 }
19778 
wl_link_down(struct bcm_cfg80211 * cfg)19779 static void wl_link_down(struct bcm_cfg80211 *cfg)
19780 {
19781 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
19782 
19783 	WL_DBG(("In\n"));
19784 	cfg->link_up = false;
19785 	if (conn_info) {
19786 		conn_info->req_ie_len = 0;
19787 		conn_info->resp_ie_len = 0;
19788 	}
19789 }
19790 
wl_lock_eq(struct bcm_cfg80211 * cfg)19791 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
19792 {
19793 	unsigned long flags;
19794 
19795 	WL_CFG_EQ_LOCK(&cfg->eq_lock, flags);
19796 	return flags;
19797 }
19798 
wl_unlock_eq(struct bcm_cfg80211 * cfg,unsigned long flags)19799 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
19800 {
19801 	WL_CFG_EQ_UNLOCK(&cfg->eq_lock, flags);
19802 }
19803 
wl_init_eq_lock(struct bcm_cfg80211 * cfg)19804 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
19805 {
19806 	spin_lock_init(&cfg->eq_lock);
19807 }
19808 
wl_delay(u32 ms)19809 static void wl_delay(u32 ms)
19810 {
19811 	if (in_atomic() || (ms < jiffies_to_msecs(1))) {
19812 		OSL_DELAY(ms*1000);
19813 	} else {
19814 		OSL_SLEEP(ms);
19815 	}
19816 }
19817 
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)19818 s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
19819 {
19820 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19821 	struct ether_addr primary_mac;
19822 	if (!cfg->p2p)
19823 		return -1;
19824 	if (!p2p_is_on(cfg)) {
19825 		get_primary_mac(cfg, &primary_mac);
19826 #ifndef WL_P2P_USE_RANDMAC
19827 		wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
19828 #endif /* WL_P2P_USE_RANDMAC */
19829 		memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN);
19830 	} else {
19831 		memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
19832 			ETHER_ADDR_LEN);
19833 	}
19834 
19835 	return 0;
19836 }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)19837 s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
19838 {
19839 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19840 
19841 	return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
19842 }
19843 
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)19844 s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
19845 {
19846 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19847 
19848 	return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
19849 }
19850 
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)19851 s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
19852 {
19853 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19854 
19855 	return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
19856 }
19857 
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)19858 s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
19859 {
19860 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19861 
19862 	return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
19863 }
19864 
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)19865 s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
19866 {
19867 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19868 
19869 	return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
19870 }
19871 
19872 #ifdef P2PLISTEN_AP_SAMECHN
wl_cfg80211_set_p2p_resp_ap_chn(struct net_device * net,s32 enable)19873 s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
19874 {
19875 	s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
19876 
19877 	if ((ret == 0) && enable) {
19878 		/* disable PM for p2p responding on infra AP channel */
19879 		s32 pm = PM_OFF;
19880 
19881 		ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm));
19882 	}
19883 
19884 	return ret;
19885 }
19886 #endif /* P2PLISTEN_AP_SAMECHN */
19887 
wl_cfg80211_channel_to_freq(u32 channel)19888 s32 wl_cfg80211_channel_to_freq(u32 channel)
19889 {
19890 	int freq = 0;
19891 
19892 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
19893 	freq = ieee80211_channel_to_frequency(channel);
19894 #else
19895 	{
19896 		u16 band = 0;
19897 		if (channel <= CH_MAX_2G_CHANNEL)
19898 			band = IEEE80211_BAND_2GHZ;
19899 		else
19900 			band = IEEE80211_BAND_5GHZ;
19901 		freq = ieee80211_channel_to_frequency(channel, band);
19902 	}
19903 #endif // endif
19904 	return freq;
19905 }
19906 
19907 #ifdef WLTDLS
19908 s32
wl_tdls_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)19909 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
19910 	const wl_event_msg_t *e, void *data) {
19911 
19912 	struct net_device *ndev = NULL;
19913 	u32 reason = ntoh32(e->reason);
19914 	s8 *msg = NULL;
19915 
19916 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
19917 
19918 	switch (reason) {
19919 	case WLC_E_TDLS_PEER_DISCOVERED :
19920 		msg = " TDLS PEER DISCOVERD ";
19921 		break;
19922 	case WLC_E_TDLS_PEER_CONNECTED :
19923 		if (cfg->tdls_mgmt_frame) {
19924 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
19925 			cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
19926 					cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0);
19927 #ifdef CONFIG_AP6XXX_WIFI6_HDF
19928 			HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), cfg->tdls_mgmt_freq, 0,
19929 				cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
19930 #endif
19931 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
19932 			cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
19933 					cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,	0,
19934 					GFP_ATOMIC);
19935 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
19936 			defined(WL_COMPAT_WIRELESS)
19937 			cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
19938 					cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
19939 					GFP_ATOMIC);
19940 #else
19941 			cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
19942 					cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, GFP_ATOMIC);
19943 
19944 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
19945 		}
19946 		msg = " TDLS PEER CONNECTED ";
19947 #ifdef SUPPORT_SET_CAC
19948 		/* TDLS connect reset CAC */
19949 		wl_cfg80211_set_cac(cfg, 0);
19950 #endif /* SUPPORT_SET_CAC */
19951 		break;
19952 	case WLC_E_TDLS_PEER_DISCONNECTED :
19953 		if (cfg->tdls_mgmt_frame) {
19954 			MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
19955 			cfg->tdls_mgmt_frame_len = 0;
19956 			cfg->tdls_mgmt_freq = 0;
19957 		}
19958 		msg = "TDLS PEER DISCONNECTED ";
19959 #ifdef SUPPORT_SET_CAC
19960 		/* TDLS disconnec, set CAC */
19961 		wl_cfg80211_set_cac(cfg, 1);
19962 #endif /* SUPPORT_SET_CAC */
19963 		break;
19964 	}
19965 	if (msg) {
19966 		WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((const u8*)(&e->addr)),
19967 			(bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
19968 	}
19969 	return 0;
19970 
19971 }
19972 #endif  /* WLTDLS */
19973 
19974 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
19975 static s32
19976 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
19977 	KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
wl_cfg80211_tdls_mgmt(struct wiphy * wiphy,struct net_device * dev,u8 * peer,u8 action_code,u8 dialog_token,u16 status_code,u32 peer_capability,const u8 * buf,size_t len)19978 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
19979 	u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
19980 	u32 peer_capability, const u8 *buf, size_t len)
19981 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
19982 		(LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
19983 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
19984 	const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
19985 	u32 peer_capability, const u8 *buf, size_t len)
19986 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
19987 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
19988        const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
19989        u32 peer_capability, bool initiator, const u8 *buf, size_t len)
19990 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
19991 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
19992 	u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
19993 	const u8 *buf, size_t len)
19994 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
19995 {
19996 	s32 ret = 0;
19997 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
19998 	struct bcm_cfg80211 *cfg;
19999 	tdls_wfd_ie_iovar_t info;
20000 	bzero(&info, sizeof(info));
20001 	cfg = wl_get_cfg(dev);
20002 
20003 #if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
20004 	/* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
20005 	 * and that cuases build error
20006 	 */
20007 	BCM_REFERENCE(peer_capability);
20008 #endif  /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20009 
20010 	switch (action_code) {
20011 		/* We need to set TDLS Wifi Display IE to firmware
20012 		 * using tdls_wfd_ie iovar
20013 		 */
20014 		case WLAN_TDLS_SET_PROBE_WFD_IE:
20015 			WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_PROBE_WFD_IE\n"));
20016 			info.mode = TDLS_WFD_PROBE_IE_TX;
20017 
20018 			if (len > sizeof(info.data)) {
20019 				return -EINVAL;
20020 			}
20021 			memcpy(&info.data, buf, len);
20022 			info.length = len;
20023 			break;
20024 		case WLAN_TDLS_SET_SETUP_WFD_IE:
20025 			WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_SETUP_WFD_IE\n"));
20026 			info.mode = TDLS_WFD_IE_TX;
20027 
20028 			if (len > sizeof(info.data)) {
20029 				return -EINVAL;
20030 			}
20031 			memcpy(&info.data, buf, len);
20032 			info.length = len;
20033 			break;
20034 		case WLAN_TDLS_SET_WFD_ENABLED:
20035 			WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_ENABLED\n"));
20036 			dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
20037 			goto out;
20038 		case WLAN_TDLS_SET_WFD_DISABLED:
20039 			WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_DISABLED\n"));
20040 			dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
20041 			goto out;
20042 		default:
20043 			WL_ERR(("Unsupported action code : %d\n", action_code));
20044 			goto out;
20045 	}
20046 	ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
20047 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
20048 
20049 	if (ret) {
20050 		WL_ERR(("tdls_wfd_ie error %d\n", ret));
20051 	}
20052 
20053 out:
20054 #endif /* TDLS_MSG_ONLY_WFD && WLTDLS */
20055 	return ret;
20056 }
20057 
20058 static s32
20059 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
wl_cfg80211_tdls_oper(struct wiphy * wiphy,struct net_device * dev,const u8 * peer,enum nl80211_tdls_operation oper)20060 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
20061 	const u8 *peer, enum nl80211_tdls_operation oper)
20062 #else
20063 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
20064 	u8 *peer, enum nl80211_tdls_operation oper)
20065 #endif // endif
20066 {
20067 	s32 ret = 0;
20068 #ifdef WLTDLS
20069 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20070 	tdls_iovar_t info;
20071 	dhd_pub_t *dhdp;
20072 	bool tdls_auto_mode = false;
20073 	dhdp = (dhd_pub_t *)(cfg->pub);
20074 	bzero(&info, sizeof(tdls_iovar_t));
20075 	if (peer) {
20076 		memcpy(&info.ea, peer, ETHER_ADDR_LEN);
20077 	} else {
20078 		return -1;
20079 	}
20080 	switch (oper) {
20081 	case NL80211_TDLS_DISCOVERY_REQ:
20082 		/* If the discovery request is broadcast then we need to set
20083 		 * info.mode to Tunneled Probe Request
20084 		 */
20085 		if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
20086 			info.mode = TDLS_MANUAL_EP_WFD_TPQ;
20087 			WL_ERR(("wl_cfg80211_tdls_oper: TDLS TUNNELED PRBOBE REQUEST\n"));
20088 		} else {
20089 			info.mode = TDLS_MANUAL_EP_DISCOVERY;
20090 		}
20091 		break;
20092 	case NL80211_TDLS_SETUP:
20093 		if (dhdp->tdls_mode == true) {
20094 			info.mode = TDLS_MANUAL_EP_CREATE;
20095 			tdls_auto_mode = false;
20096 			/* Do tear down and create a fresh one */
20097 			ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_TEARDOWN, tdls_auto_mode);
20098 			if (ret < 0) {
20099 				return ret;
20100 			}
20101 		} else {
20102 			tdls_auto_mode = true;
20103 		}
20104 		break;
20105 	case NL80211_TDLS_TEARDOWN:
20106 		info.mode = TDLS_MANUAL_EP_DELETE;
20107 		break;
20108 	default:
20109 		WL_ERR(("Unsupported operation : %d\n", oper));
20110 		goto out;
20111 	}
20112 	/* turn on TDLS */
20113 	ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_SETUP, tdls_auto_mode);
20114 	if (ret < 0) {
20115 		return ret;
20116 	}
20117 	if (info.mode) {
20118 		ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
20119 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
20120 		if (ret) {
20121 			WL_ERR(("tdls_endpoint error %d\n", ret));
20122 		}
20123 	}
20124 out:
20125 	if (ret) {
20126 		wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
20127 		return -ENOTSUPP;
20128 	}
20129 #endif /* WLTDLS */
20130 	return ret;
20131 }
20132 #endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
20133 
wl_cfg80211_set_wps_p2p_ie(struct net_device * ndev,char * buf,int len,enum wl_management_type type)20134 s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
20135 	enum wl_management_type type)
20136 {
20137 	struct bcm_cfg80211 *cfg;
20138 	s32 ret = 0;
20139 	struct ether_addr primary_mac;
20140 	s32 bssidx = 0;
20141 	s32 pktflag = 0;
20142 	cfg = wl_get_cfg(ndev);
20143 
20144 	if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
20145 		/* Vendor IEs should be set to FW
20146 		 * after SoftAP interface is brought up
20147 		 */
20148 		WL_DBG(("Skipping set IE since AP is not up \n"));
20149 		goto exit;
20150 	} else  if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
20151 		/* Either stand alone AP case or P2P discovery */
20152 		if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
20153 			/* Stand alone AP case on primary interface */
20154 			WL_DBG(("Apply IEs for Primary AP Interface \n"));
20155 			bssidx = 0;
20156 		} else {
20157 			if (!cfg->p2p) {
20158 				/* If p2p not initialized, return failure */
20159 				WL_ERR(("P2P not initialized \n"));
20160 				goto exit;
20161 			}
20162 			/* P2P Discovery case (p2p listen) */
20163 			if (!cfg->p2p->on) {
20164 				/* Turn on Discovery interface */
20165 				get_primary_mac(cfg, &primary_mac);
20166 #ifndef WL_P2P_USE_RANDMAC
20167 				wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
20168 #endif /* WL_P2P_USE_RANDMAC */
20169 				p2p_on(cfg) = true;
20170 				ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
20171 				if (unlikely(ret)) {
20172 					WL_ERR(("Enable discovery failed \n"));
20173 					goto exit;
20174 				}
20175 			}
20176 			WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
20177 			ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
20178 			bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
20179 		}
20180 	} else {
20181 		/* Virtual AP/ P2P Group Interface */
20182 		WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
20183 		bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
20184 	}
20185 
20186 	if (ndev != NULL) {
20187 		switch (type) {
20188 			case WL_BEACON:
20189 				pktflag = VNDR_IE_BEACON_FLAG;
20190 				break;
20191 			case WL_PROBE_RESP:
20192 				pktflag = VNDR_IE_PRBRSP_FLAG;
20193 				break;
20194 			case WL_ASSOC_RESP:
20195 				pktflag = VNDR_IE_ASSOCRSP_FLAG;
20196 				break;
20197 		}
20198 		if (pktflag) {
20199 			ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
20200 				ndev_to_cfgdev(ndev), bssidx, pktflag, buf, len);
20201 		}
20202 	}
20203 exit:
20204 	return ret;
20205 }
20206 
20207 #ifdef WL_SUPPORT_AUTO_CHANNEL
20208 static s32
wl_cfg80211_set_auto_channel_scan_state(struct net_device * ndev)20209 wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev)
20210 {
20211 	u32 val = 0;
20212 	s32 ret = BCME_ERROR;
20213 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20214 	/* Set interface up, explicitly. */
20215 	val = 1;
20216 
20217 	ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
20218 	if (ret < 0) {
20219 		WL_ERR(("set interface up failed, error = %d\n", ret));
20220 		goto done;
20221 	}
20222 
20223 	/* Stop all scan explicitly, till auto channel selection complete. */
20224 	wl_set_drv_status(cfg, SCANNING, ndev);
20225 	if (cfg->escan_info.ndev == NULL) {
20226 		ret = BCME_OK;
20227 		goto done;
20228 	}
20229 
20230 	wl_cfg80211_cancel_scan(cfg);
20231 
20232 done:
20233 	return ret;
20234 }
20235 
20236 static bool
wl_cfg80211_valid_channel_p2p(int channel)20237 wl_cfg80211_valid_channel_p2p(int channel)
20238 {
20239 	bool valid = false;
20240 
20241 	/* channel 1 to 14 */
20242 	if ((channel >= 1) && (channel <= 14)) {
20243 		valid = true;
20244 	}
20245 	/* channel 36 to 48 */
20246 	else if ((channel >= 36) && (channel <= 48)) {
20247 		valid = true;
20248 	}
20249 	/* channel 149 to 161 */
20250 	else if ((channel >= 149) && (channel <= 161)) {
20251 		valid = true;
20252 	}
20253 	else {
20254 		valid = false;
20255 		WL_INFORM(("invalid P2P chanspec, channel = %d\n", channel));
20256 	}
20257 
20258 	return valid;
20259 }
20260 
20261 s32
wl_cfg80211_get_chanspecs_2g(struct net_device * ndev,void * buf,s32 buflen)20262 wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
20263 {
20264 	s32 ret = BCME_ERROR;
20265 	struct bcm_cfg80211 *cfg = NULL;
20266 	chanspec_t chanspec = 0;
20267 
20268 	cfg = wl_get_cfg(ndev);
20269 
20270 	/* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
20271 	chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 |
20272 		WL_CHANSPEC_CTL_SB_NONE);
20273 	chanspec = wl_chspec_host_to_driver(chanspec);
20274 
20275 	ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
20276 		sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
20277 	if (ret < 0) {
20278 		WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
20279 	}
20280 
20281 	return ret;
20282 }
20283 
20284 s32
wl_cfg80211_get_chanspecs_5g(struct net_device * ndev,void * buf,s32 buflen)20285 wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
20286 {
20287 	u32 channel = 0;
20288 	s32 ret = BCME_ERROR;
20289 	s32 i = 0;
20290 	s32 j = 0;
20291 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20292 	wl_uint32_list_t *list = NULL;
20293 	chanspec_t chanspec = 0;
20294 
20295 	/* Restrict channels to 5GHz, 20MHz BW, no SB. */
20296 	chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 |
20297 		WL_CHANSPEC_CTL_SB_NONE);
20298 	chanspec = wl_chspec_host_to_driver(chanspec);
20299 
20300 	ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
20301 		sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
20302 	if (ret < 0) {
20303 		WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
20304 		goto done;
20305 	}
20306 
20307 	list = (wl_uint32_list_t *)buf;
20308 	/* Skip DFS and inavlid P2P channel. */
20309 	for (i = 0, j = 0; i < dtoh32(list->count); i++) {
20310 		chanspec = (chanspec_t) dtoh32(list->element[i]);
20311 		channel = CHSPEC_CHANNEL(chanspec);
20312 
20313 		ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
20314 		if (ret < 0) {
20315 			WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret));
20316 			goto done;
20317 		}
20318 
20319 		if (CHANNEL_IS_RADAR(channel) ||
20320 			!(wl_cfg80211_valid_channel_p2p(CHSPEC_CHANNEL(chanspec)))) {
20321 			continue;
20322 		} else {
20323 			list->element[j] = list->element[i];
20324 		}
20325 
20326 		j++;
20327 	}
20328 
20329 	list->count = j;
20330 
20331 done:
20332 	return ret;
20333 }
20334 
20335 static s32
wl_cfg80211_get_best_channel(struct net_device * ndev,void * buf,int buflen,int * channel)20336 wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen,
20337 	int *channel)
20338 {
20339 	s32 ret = BCME_ERROR;
20340 	int chosen = 0;
20341 	int retry = 0;
20342 	uint chip;
20343 
20344 	/* Start auto channel selection scan. */
20345 	ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, buf, buflen);
20346 	if (ret < 0) {
20347 		WL_ERR(("can't start auto channel scan, error = %d\n", ret));
20348 		*channel = 0;
20349 		goto done;
20350 	}
20351 
20352 	/* Wait for auto channel selection, worst case possible delay is 5250ms. */
20353 	retry = CHAN_SEL_RETRY_COUNT;
20354 
20355 	while (retry--) {
20356 		OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
20357 		chosen = 0;
20358 		ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
20359 		if ((ret == 0) && (dtoh32(chosen) != 0)) {
20360 			chip = dhd_conf_get_chip(dhd_get_pub(ndev));
20361 			if (chip != BCM43362_CHIP_ID &&	chip != BCM4330_CHIP_ID &&
20362 					chip != BCM43143_CHIP_ID) {
20363 				u32 chanspec = 0;
20364 				int ctl_chan;
20365 				chanspec = wl_chspec_driver_to_host(chosen);
20366 				WL_INFORM(("selected chanspec = 0x%x\n", chanspec));
20367 				ctl_chan = wf_chspec_ctlchan(chanspec);
20368 				WL_INFORM(("selected ctl_chan = %d\n", ctl_chan));
20369 				*channel = (u16)(ctl_chan & 0x00FF);
20370 			} else
20371 				*channel = (u16)(chosen & 0x00FF);
20372 			WL_INFORM(("selected channel = %d\n", *channel));
20373 			break;
20374 		}
20375 		WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n",
20376 			(CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
20377 	}
20378 
20379 	if (retry <= 0)	{
20380 		WL_ERR(("failure, auto channel selection timed out\n"));
20381 		*channel = 0;
20382 		ret = BCME_ERROR;
20383 	}
20384 	WL_INFORM(("selected channel = %d\n", *channel));
20385 
20386 done:
20387 	return ret;
20388 }
20389 
20390 static s32
wl_cfg80211_restore_auto_channel_scan_state(struct net_device * ndev)20391 wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev)
20392 {
20393 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20394 	/* Clear scan stop driver status. */
20395 	wl_clr_drv_status(cfg, SCANNING, ndev);
20396 
20397 	return BCME_OK;
20398 }
20399 
20400 s32
wl_cfg80211_get_best_channels(struct net_device * dev,char * cmd,int total_len)20401 wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len)
20402 {
20403 	int channel = 0, band, band_cur;
20404 	s32 ret = BCME_ERROR;
20405 	u8 *buf = NULL;
20406 	char *pos = cmd;
20407 	struct bcm_cfg80211 *cfg = NULL;
20408 	struct net_device *ndev = NULL;
20409 
20410 	bzero(cmd, total_len);
20411 	cfg = wl_get_cfg(dev);
20412 
20413 	buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
20414 	if (buf == NULL) {
20415 		WL_ERR(("failed to allocate chanspec buffer\n"));
20416 		return -ENOMEM;
20417 	}
20418 
20419 	/*
20420 	 * Always use primary interface, irrespective of interface on which
20421 	 * command came.
20422 	 */
20423 	ndev = bcmcfg_to_prmry_ndev(cfg);
20424 
20425 	/*
20426 	 * Make sure that FW and driver are in right state to do auto channel
20427 	 * selection scan.
20428 	 */
20429 	ret = wl_cfg80211_set_auto_channel_scan_state(ndev);
20430 	if (ret < 0) {
20431 		WL_ERR(("can't set auto channel scan state, error = %d\n", ret));
20432 		goto done;
20433 	}
20434 
20435 	ret = wldev_ioctl(dev, WLC_GET_BAND, &band_cur, sizeof(band_cur), false);
20436 	if (band_cur != WLC_BAND_5G) {
20437 		/* Best channel selection in 2.4GHz band. */
20438 		ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
20439 		if (ret < 0) {
20440 			WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
20441 			goto done;
20442 		}
20443 
20444 		ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
20445 			&channel);
20446 		if (ret < 0) {
20447 			WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
20448 			goto done;
20449 		}
20450 
20451 		if (CHANNEL_IS_2G(channel)) {
20452 //			channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
20453 		} else {
20454 			WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel));
20455 			channel = 0;
20456 		}
20457 		pos += snprintf(pos, total_len, "2g=%d ", channel);
20458 	}
20459 
20460 	if (band_cur != WLC_BAND_2G) {
20461 		// terence 20140120: fix for some chipsets only return 2.4GHz channel (4330b2/43341b0/4339a0)
20462 		band = band_cur==WLC_BAND_2G ? band_cur : WLC_BAND_5G;
20463 		ret = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true);
20464 		if (ret < 0) {
20465 			WL_ERR(("WLC_SET_BAND error %d\n", ret));
20466 			goto done;
20467 		}
20468 
20469 		/* Best channel selection in 5GHz band. */
20470 		ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
20471 		if (ret < 0) {
20472 			WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret));
20473 			goto done;
20474 		}
20475 
20476 		ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
20477 			&channel);
20478 		if (ret < 0) {
20479 			WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret));
20480 			goto done;
20481 		}
20482 
20483 		if (CHANNEL_IS_5G(channel)) {
20484 //			channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
20485 		} else {
20486 			WL_ERR(("invalid 5GHz channel, channel = %d\n", channel));
20487 			channel = 0;
20488 		}
20489 
20490 		ret = wldev_ioctl(dev, WLC_SET_BAND, &band_cur, sizeof(band_cur), true);
20491 		if (ret < 0)
20492 			WL_ERR(("WLC_SET_BAND error %d\n", ret));
20493 		pos += snprintf(pos, total_len, "5g=%d ", channel);
20494 	}
20495 
20496 done:
20497 	if (NULL != buf) {
20498 		MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
20499 	}
20500 
20501 	/* Restore FW and driver back to normal state. */
20502 	ret = wl_cfg80211_restore_auto_channel_scan_state(ndev);
20503 	if (ret < 0) {
20504 		WL_ERR(("can't restore auto channel scan state, error = %d\n", ret));
20505 	}
20506 
20507 	WL_MSG(ndev->name, "%s\n", cmd);
20508 
20509 	return (pos - cmd);
20510 }
20511 #endif /* WL_SUPPORT_AUTO_CHANNEL */
20512 
20513 static const struct rfkill_ops wl_rfkill_ops = {
20514 	.set_block = wl_rfkill_set
20515 };
20516 
wl_rfkill_set(void * data,bool blocked)20517 static int wl_rfkill_set(void *data, bool blocked)
20518 {
20519 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
20520 
20521 	WL_DBG(("Enter \n"));
20522 	WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
20523 
20524 	if (!cfg)
20525 		return -EINVAL;
20526 
20527 	cfg->rf_blocked = blocked;
20528 
20529 	return 0;
20530 }
20531 
wl_setup_rfkill(struct bcm_cfg80211 * cfg,bool setup)20532 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
20533 {
20534 	s32 err = 0;
20535 
20536 	WL_DBG(("Enter \n"));
20537 	if (!cfg)
20538 		return -EINVAL;
20539 	if (setup) {
20540 		cfg->rfkill = rfkill_alloc("brcmfmac-wifi",
20541 			wl_cfg80211_get_parent_dev(),
20542 			RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
20543 
20544 		if (!cfg->rfkill) {
20545 			err = -ENOMEM;
20546 			goto err_out;
20547 		}
20548 
20549 		err = rfkill_register(cfg->rfkill);
20550 
20551 		if (err)
20552 			rfkill_destroy(cfg->rfkill);
20553 	} else {
20554 		if (!cfg->rfkill) {
20555 			err = -ENOMEM;
20556 			goto err_out;
20557 		}
20558 
20559 		rfkill_unregister(cfg->rfkill);
20560 		rfkill_destroy(cfg->rfkill);
20561 	}
20562 
20563 err_out:
20564 	return err;
20565 }
20566 
20567 #ifdef DEBUGFS_CFG80211
20568 /**
20569 * Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
20570 * to turn on SCAN and DBG log.
20571 * To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
20572 * To see current setting of debug level,
20573 * cat /sys/kernel/debug/dhd/debug_level
20574 */
20575 static ssize_t
wl_debuglevel_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)20576 wl_debuglevel_write(struct file *file, const char __user *userbuf,
20577 	size_t count, loff_t *ppos)
20578 {
20579 	char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)], sublog[SUBLOGLEVELZ];
20580 	char *params, *token, *colon;
20581 	uint i, tokens, log_on = 0;
20582 	size_t minsize = min_t(size_t, (sizeof(tbuf) - 1), count);
20583 
20584 	bzero(tbuf, sizeof(tbuf));
20585 	bzero(sublog, sizeof(sublog));
20586 	if (copy_from_user(&tbuf, userbuf, minsize)) {
20587 		return -EFAULT;
20588 	}
20589 
20590 	tbuf[minsize] = '\0';
20591 	params = &tbuf[0];
20592 	colon = strchr(params, '\n');
20593 	if (colon != NULL)
20594 		*colon = '\0';
20595 	while ((token = strsep(&params, " ")) != NULL) {
20596 		bzero(sublog, sizeof(sublog));
20597 		if (token == NULL || !*token)
20598 			break;
20599 		if (*token == '\0')
20600 			continue;
20601 		colon = strchr(token, ':');
20602 		if (colon != NULL) {
20603 			*colon = ' ';
20604 		}
20605 		tokens = sscanf(token, "%"S(SUBLOGLEVEL)"s %u", sublog, &log_on);
20606 		if (colon != NULL)
20607 			*colon = ':';
20608 
20609 		if (tokens == 2) {
20610 				for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
20611 					if (!strncmp(sublog, sublogname_map[i].sublogname,
20612 						strlen(sublogname_map[i].sublogname))) {
20613 						if (log_on)
20614 							wl_dbg_level |=
20615 							(sublogname_map[i].log_level);
20616 						else
20617 							wl_dbg_level &=
20618 							~(sublogname_map[i].log_level);
20619 					}
20620 				}
20621 		} else
20622 			WL_ERR(("%s: can't parse '%s' as a "
20623 			       "SUBMODULE:LEVEL (%d tokens)\n",
20624 			       tbuf, token, tokens));
20625 
20626 	}
20627 	return count;
20628 }
20629 
20630 static ssize_t
wl_debuglevel_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)20631 wl_debuglevel_read(struct file *file, char __user *user_buf,
20632 	size_t count, loff_t *ppos)
20633 {
20634 	char *param;
20635 	char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)];
20636 	uint i;
20637 	bzero(tbuf, sizeof(tbuf));
20638 	param = &tbuf[0];
20639 	for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
20640 		param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
20641 			sublogname_map[i].sublogname,
20642 			(wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0);
20643 	}
20644 	*param = '\n';
20645 	return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0]));
20646 
20647 }
20648 static const struct file_operations fops_debuglevel = {
20649 	.open = NULL,
20650 	.write = wl_debuglevel_write,
20651 	.read = wl_debuglevel_read,
20652 	.owner = THIS_MODULE,
20653 	.llseek = NULL,
20654 };
20655 
wl_setup_debugfs(struct bcm_cfg80211 * cfg)20656 static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg)
20657 {
20658 	s32 err = 0;
20659 	struct dentry *_dentry;
20660 	if (!cfg)
20661 		return -EINVAL;
20662 	cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
20663 	if (!cfg->debugfs || IS_ERR(cfg->debugfs)) {
20664 		if (cfg->debugfs == ERR_PTR(-ENODEV))
20665 			WL_ERR(("Debugfs is not enabled on this kernel\n"));
20666 		else
20667 			WL_ERR(("Can not create debugfs directory\n"));
20668 		cfg->debugfs = NULL;
20669 		goto exit;
20670 
20671 	}
20672 	_dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR,
20673 		cfg->debugfs, cfg, &fops_debuglevel);
20674 	if (!_dentry || IS_ERR(_dentry)) {
20675 		WL_ERR(("failed to create debug_level debug file\n"));
20676 		wl_free_debugfs(cfg);
20677 	}
20678 exit:
20679 	return err;
20680 }
wl_free_debugfs(struct bcm_cfg80211 * cfg)20681 static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg)
20682 {
20683 	if (!cfg)
20684 		return -EINVAL;
20685 	if (cfg->debugfs)
20686 		debugfs_remove_recursive(cfg->debugfs);
20687 	cfg->debugfs = NULL;
20688 	return 0;
20689 }
20690 #endif /* DEBUGFS_CFG80211 */
20691 
wl_cfg80211_get_bcmcfg(void)20692 struct bcm_cfg80211 *wl_cfg80211_get_bcmcfg(void)
20693 {
20694 	return g_bcmcfg;
20695 }
20696 
wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 * cfg)20697 void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 *cfg)
20698 {
20699 	g_bcmcfg = cfg;
20700 }
20701 
wl_cfg80211_get_parent_dev(void)20702 struct device *wl_cfg80211_get_parent_dev(void)
20703 {
20704 	return cfg80211_parent_dev;
20705 }
20706 
wl_cfg80211_set_parent_dev(void * dev)20707 void wl_cfg80211_set_parent_dev(void *dev)
20708 {
20709 	cfg80211_parent_dev = dev;
20710 }
20711 
wl_cfg80211_clear_parent_dev(void)20712 static void wl_cfg80211_clear_parent_dev(void)
20713 {
20714 	cfg80211_parent_dev = NULL;
20715 }
20716 
get_primary_mac(struct bcm_cfg80211 * cfg,struct ether_addr * mac)20717 void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
20718 {
20719 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
20720 
20721 	if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
20722 			"cur_etheraddr", NULL, 0, ioctl_buf, sizeof(ioctl_buf),
20723 			0, NULL) == BCME_OK) {
20724 		memcpy(mac->octet, ioctl_buf, ETHER_ADDR_LEN);
20725 	} else {
20726 		bzero(mac->octet, ETHER_ADDR_LEN);
20727 	}
20728 }
check_dev_role_integrity(struct bcm_cfg80211 * cfg,u32 dev_role)20729 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
20730 {
20731 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20732 	if (((dev_role == NL80211_IFTYPE_AP) &&
20733 		!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
20734 		((dev_role == NL80211_IFTYPE_P2P_GO) &&
20735 		!(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
20736 	{
20737 		WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
20738 		return false;
20739 	}
20740 	return true;
20741 }
20742 
wl_cfg80211_do_driver_init(struct net_device * net)20743 int wl_cfg80211_do_driver_init(struct net_device *net)
20744 {
20745 	struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
20746 
20747 	if (!cfg || !cfg->wdev)
20748 		return -EINVAL;
20749 
20750 	if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
20751 		return -1;
20752 
20753 	return 0;
20754 }
20755 
wl_cfg80211_enable_trace(u32 level)20756 void wl_cfg80211_enable_trace(u32 level)
20757 {
20758 	wl_dbg_level = level;
20759 	WL_MSG("wlan", "wl_dbg_level = 0x%x\n", wl_dbg_level);
20760 }
20761 
20762 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
20763 	2, 0))
20764 static s32
wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u64 cookie)20765 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
20766 	bcm_struct_cfgdev *cfgdev, u64 cookie)
20767 {
20768 	/* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
20769 	 * is passed with CMD_FRAME. This callback is supposed to cancel
20770 	 * the OFFCHANNEL Wait. Since we are already taking care of that
20771 	 *  with the tx_mgmt logic, do nothing here.
20772 	 */
20773 
20774 	return 0;
20775 }
20776 #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
20777 
20778 #ifdef WL_HOST_BAND_MGMT
20779 s32
wl_cfg80211_set_band(struct net_device * ndev,int band)20780 wl_cfg80211_set_band(struct net_device *ndev, int band)
20781 {
20782 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20783 	int ret = 0;
20784 	char ioctl_buf[50];
20785 
20786 	if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
20787 		WL_ERR(("Invalid band\n"));
20788 		return -EINVAL;
20789 	}
20790 
20791 	if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band,
20792 		sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
20793 		WL_ERR(("seting roam_band failed code=%d\n", ret));
20794 		return ret;
20795 	}
20796 
20797 	WL_DBG(("Setting band to %d\n", band));
20798 	cfg->curr_band = band;
20799 
20800 	return 0;
20801 }
20802 #endif /* WL_HOST_BAND_MGMT */
20803 
20804 s32
wl_cfg80211_set_if_band(struct net_device * ndev,int band)20805 wl_cfg80211_set_if_band(struct net_device *ndev, int band)
20806 {
20807 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20808 	int ret = 0, wait_cnt;
20809 	char ioctl_buf[32];
20810 
20811 	if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
20812 		WL_ERR(("Invalid band\n"));
20813 		return -EINVAL;
20814 	}
20815 	if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
20816 		dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
20817 		BCM_REFERENCE(dhdp);
20818 		DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
20819 			dhd_net2idx(dhdp->info, ndev), 0);
20820 		ret = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
20821 		if (ret < 0) {
20822 			WL_ERR(("WLC_DISASSOC error %d\n", ret));
20823 			/* continue to set 'if_band' */
20824 		}
20825 		else {
20826 			/* This is to ensure that 'if_band' iovar is issued only after
20827 			* disconnection is completed
20828 			*/
20829 			wait_cnt = WAIT_FOR_DISCONNECT_MAX;
20830 			while (wl_get_drv_status(cfg, CONNECTED, ndev) && wait_cnt) {
20831 				WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt));
20832 				wait_cnt--;
20833 				OSL_SLEEP(50);
20834 			}
20835 		}
20836 	}
20837 	if ((ret = wldev_iovar_setbuf(ndev, "if_band", &band,
20838 			sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
20839 		WL_ERR(("seting if_band failed ret=%d\n", ret));
20840 		/* issue 'WLC_SET_BAND' if if_band is not supported */
20841 		if (ret == BCME_UNSUPPORTED) {
20842 			ret = wldev_set_band(ndev, band);
20843 			if (ret < 0) {
20844 				WL_ERR(("seting band failed ret=%d\n", ret));
20845 			}
20846 		}
20847 	}
20848 	return ret;
20849 }
20850 
20851 s32
wl_cfg80211_dfs_ap_move(struct net_device * ndev,char * data,char * command,int total_len)20852 wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int total_len)
20853 {
20854 	char ioctl_buf[WLC_IOCTL_SMLEN];
20855 	int err = 0;
20856 	uint32 val = 0;
20857 	chanspec_t chanspec = 0;
20858 	int abort;
20859 	int bytes_written = 0;
20860 	struct wl_dfs_ap_move_status_v2 *status;
20861 	char chanbuf[CHANSPEC_STR_LEN];
20862 	const char *dfs_state_str[DFS_SCAN_S_MAX] = {
20863 		"Radar Free On Channel",
20864 		"Radar Found On Channel",
20865 		"Radar Scan In Progress",
20866 		"Radar Scan Aborted",
20867 		"RSDB Mode switch in Progress For Scan"
20868 	};
20869 	if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
20870 		bytes_written = snprintf(command, total_len, "AP is not up\n");
20871 		return bytes_written;
20872 	}
20873 	if (!*data) {
20874 		if ((err = wldev_iovar_getbuf(ndev, "dfs_ap_move", NULL, 0,
20875 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
20876 			WL_ERR(("setting dfs_ap_move failed with err=%d \n", err));
20877 			return err;
20878 		}
20879 		status = (struct wl_dfs_ap_move_status_v2 *)ioctl_buf;
20880 
20881 		if (status->version != WL_DFS_AP_MOVE_VERSION) {
20882 			err = BCME_UNSUPPORTED;
20883 			WL_ERR(("err=%d version=%d\n", err, status->version));
20884 			return err;
20885 		}
20886 
20887 		if (status->move_status != (int8) DFS_SCAN_S_IDLE) {
20888 			chanspec = wl_chspec_driver_to_host(status->chanspec);
20889 			if (chanspec != 0 && chanspec != INVCHANSPEC) {
20890 				wf_chspec_ntoa(chanspec, chanbuf);
20891 				bytes_written = snprintf(command, total_len,
20892 					"AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
20893 			}
20894 			bytes_written += snprintf(command + bytes_written,
20895 					total_len - bytes_written,
20896 					"%s\n", dfs_state_str[status->move_status]);
20897 			return bytes_written;
20898 		} else {
20899 			bytes_written = snprintf(command, total_len, "dfs AP move in IDLE state\n");
20900 			return bytes_written;
20901 		}
20902 	}
20903 
20904 	abort = bcm_atoi(data);
20905 	if (abort == -1) {
20906 		if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &abort,
20907 				sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
20908 			WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
20909 			return err;
20910 		}
20911 	} else {
20912 		chanspec = wf_chspec_aton(data);
20913 		if (chanspec != 0) {
20914 			val = wl_chspec_host_to_driver(chanspec);
20915 			if (val != INVCHANSPEC) {
20916 				if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &val,
20917 					sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
20918 					WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
20919 					return err;
20920 				}
20921 				WL_DBG((" set dfs_ap_move successfull"));
20922 			} else {
20923 				err = BCME_USAGE_ERROR;
20924 			}
20925 		}
20926 	}
20927 	return err;
20928 }
20929 
wl_cfg80211_is_concurrent_mode(struct net_device * dev)20930 bool wl_cfg80211_is_concurrent_mode(struct net_device *dev)
20931 {
20932 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20933 	if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
20934 		return true;
20935 	} else {
20936 		return false;
20937 	}
20938 }
20939 
wl_cfg80211_get_dhdp(struct net_device * dev)20940 void* wl_cfg80211_get_dhdp(struct net_device *dev)
20941 {
20942 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20943 
20944 	return cfg->pub;
20945 }
20946 
wl_cfg80211_is_p2p_active(struct net_device * dev)20947 bool wl_cfg80211_is_p2p_active(struct net_device *dev)
20948 {
20949 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20950 	return (cfg && cfg->p2p);
20951 }
20952 
wl_cfg80211_is_roam_offload(struct net_device * dev)20953 bool wl_cfg80211_is_roam_offload(struct net_device * dev)
20954 {
20955 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20956 	return (cfg && cfg->roam_offload);
20957 }
20958 
wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev,const wl_event_msg_t * e,int ifidx)20959 bool wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev, const wl_event_msg_t *e,
20960 		int ifidx)
20961 {
20962 	u8 *curbssid = NULL;
20963 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20964 
20965 	if (!cfg) {
20966 		/* When interface is created using wl
20967 		 * ndev->ieee80211_ptr will be NULL.
20968 		 */
20969 		return NULL;
20970 	}
20971 	curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
20972 
20973 	if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
20974 		return true;
20975 	}
20976 	return false;
20977 }
20978 
wl_cfg80211_work_handler(struct work_struct * work)20979 static void wl_cfg80211_work_handler(struct work_struct * work)
20980 {
20981 	struct bcm_cfg80211 *cfg = NULL;
20982 	struct net_info *iter, *next;
20983 	s32 err = BCME_OK;
20984 	s32 pm = PM_FAST;
20985 	dhd_pub_t *dhd;
20986 	BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
20987 	WL_DBG(("Enter \n"));
20988 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
20989 	for_each_ndev(cfg, iter, next) {
20990 		GCC_DIAGNOSTIC_POP();
20991 		/* p2p discovery iface ndev could be null */
20992 		if (iter->ndev) {
20993 			if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
20994 				(wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
20995 				wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
20996 				continue;
20997 			if (iter->ndev) {
20998 				dhd = (dhd_pub_t *)(cfg->pub);
20999 				if (dhd_conf_get_pm(dhd) >= 0)
21000 					pm = dhd_conf_get_pm(dhd);
21001 				if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM,
21002 						&pm, sizeof(pm))) != 0) {
21003 					if (err == -ENODEV)
21004 						WL_DBG(("%s:netdev not ready\n",
21005 							iter->ndev->name));
21006 					else
21007 						WL_ERR(("%s:error (%d)\n",
21008 							iter->ndev->name, err));
21009 				} else
21010 					wl_cfg80211_update_power_mode(iter->ndev);
21011 			}
21012 		}
21013 	}
21014 	DHD_PM_WAKE_UNLOCK(cfg->pub);
21015 }
21016 
21017 u8
wl_get_action_category(void * frame,u32 frame_len)21018 wl_get_action_category(void *frame, u32 frame_len)
21019 {
21020 	u8 category;
21021 	u8 *ptr = (u8 *)frame;
21022 	if (frame == NULL)
21023 		return DOT11_ACTION_CAT_ERR_MASK;
21024 	if (frame_len < DOT11_ACTION_HDR_LEN)
21025 		return DOT11_ACTION_CAT_ERR_MASK;
21026 	category = ptr[DOT11_ACTION_CAT_OFF];
21027 	WL_DBG(("Action Category: %d\n", category));
21028 	return category;
21029 }
21030 
21031 int
wl_get_public_action(void * frame,u32 frame_len,u8 * ret_action)21032 wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
21033 {
21034 	u8 *ptr = (u8 *)frame;
21035 	if (frame == NULL || ret_action == NULL)
21036 		return BCME_ERROR;
21037 	if (frame_len < DOT11_ACTION_HDR_LEN)
21038 		return BCME_ERROR;
21039 	if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
21040 		return BCME_ERROR;
21041 	*ret_action = ptr[DOT11_ACTION_ACT_OFF];
21042 	WL_DBG(("Public Action : %d\n", *ret_action));
21043 	return BCME_OK;
21044 }
21045 
21046 #ifdef WLFBT
21047 int
wl_cfg80211_get_fbt_key(struct net_device * dev,uint8 * key,int total_len)21048 wl_cfg80211_get_fbt_key(struct net_device *dev, uint8 *key, int total_len)
21049 {
21050 	struct bcm_cfg80211 * cfg = wl_get_cfg(dev);
21051 	int bytes_written = -1;
21052 
21053 	if (total_len < FBT_KEYLEN) {
21054 		WL_ERR(("wl_cfg80211_get_fbt_key: Insufficient buffer \n"));
21055 		goto end;
21056 	}
21057 	if (cfg) {
21058 		memcpy(key, cfg->fbt_key, FBT_KEYLEN);
21059 		bytes_written = FBT_KEYLEN;
21060 	} else {
21061 		bzero(key, FBT_KEYLEN);
21062 		WL_ERR(("wl_cfg80211_get_fbt_key: Failed to copy KCK and KEK \n"));
21063 	}
21064 	prhex("KCK, KEK", (uchar *)key, FBT_KEYLEN);
21065 end:
21066 	return bytes_written;
21067 }
21068 #endif /* WLFBT */
21069 
21070 static int
wl_cfg80211_delayed_roam(struct bcm_cfg80211 * cfg,struct net_device * ndev,const struct ether_addr * bssid)21071 wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
21072 	const struct ether_addr *bssid)
21073 {
21074 	s32 err;
21075 	wl_event_msg_t e;
21076 
21077 	bzero(&e, sizeof(e));
21078 	e.event_type = cpu_to_be32(WLC_E_ROAM);
21079 	memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
21080 	/* trigger the roam event handler */
21081 	err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
21082 
21083 	return err;
21084 }
21085 
21086 static s32
wl_cfg80211_parse_vndr_ies(const u8 * parse,u32 len,struct parsed_vndr_ies * vndr_ies)21087 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
21088     struct parsed_vndr_ies *vndr_ies)
21089 {
21090 	s32 err = BCME_OK;
21091 	const vndr_ie_t *vndrie;
21092 	const bcm_tlv_t *ie;
21093 	struct parsed_vndr_ie_info *parsed_info;
21094 	u32 count = 0;
21095 	u32 remained_len;
21096 
21097 	remained_len = len;
21098 	bzero(vndr_ies, sizeof(*vndr_ies));
21099 
21100 	WL_DBG(("---> len %d\n", len));
21101 	ie = (const bcm_tlv_t *) parse;
21102 	if (!bcm_valid_tlv(ie, remained_len))
21103 		ie = NULL;
21104 	while (ie) {
21105 		if (count >= MAX_VNDR_IE_NUMBER)
21106 			break;
21107 		if (ie->id == DOT11_MNG_VS_ID || (ie->id == DOT11_MNG_ID_EXT_ID)) {
21108 			vndrie = (const vndr_ie_t *) ie;
21109 			if (ie->id == DOT11_MNG_ID_EXT_ID) {
21110 				/* len should be bigger than sizeof ID extn field at least */
21111 				if (vndrie->len < MIN_VENDOR_EXTN_IE_LEN) {
21112 					WL_ERR(("%s: invalid vndr extn ie."
21113 						" length %d\n",
21114 						__FUNCTION__, vndrie->len));
21115 					goto end;
21116 				}
21117 			} else {
21118 				/* len should be bigger than OUI length +
21119 				 * one data length at least
21120 				 */
21121 				if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
21122 					WL_ERR(("wl_cfg80211_parse_vndr_ies:"
21123 						" invalid vndr ie. length is too small %d\n",
21124 						vndrie->len));
21125 					goto end;
21126 				}
21127 
21128 				/* if wpa or wme ie, do not add ie */
21129 				if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
21130 						((vndrie->data[0] == WPA_OUI_TYPE) ||
21131 						(vndrie->data[0] == WME_OUI_TYPE))) {
21132 					CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
21133 					goto end;
21134 				}
21135 			}
21136 
21137 			parsed_info = &vndr_ies->ie_info[count++];
21138 
21139 			/* save vndr ie information */
21140 			parsed_info->ie_ptr = (const char *)vndrie;
21141 			parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
21142 			memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
21143 			vndr_ies->count = count;
21144 			if (ie->id == DOT11_MNG_ID_EXT_ID) {
21145 				WL_DBG(("\t ** Vendor Extension ie id: 0x%02x, len:%d\n",
21146 					ie->id, parsed_info->ie_len));
21147 			} else {
21148 				WL_DBG(("\t ** OUI "MACOUIDBG", type 0x%02x len:%d\n",
21149 					MACOUI2STRDBG(parsed_info->vndrie.oui),
21150 					parsed_info->vndrie.data[0], parsed_info->ie_len));
21151 			}
21152 		}
21153 end:
21154 		ie = bcm_next_tlv(ie, &remained_len);
21155 	}
21156 	return err;
21157 }
21158 
21159 static bool
wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info * vndr_info)21160 wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info *vndr_info)
21161 {
21162 	int i = 0;
21163 
21164 	while (exclude_vndr_oui_list[i]) {
21165 		if (!memcmp(vndr_info->vndrie.oui,
21166 			exclude_vndr_oui_list[i],
21167 			DOT11_OUI_LEN)) {
21168 			return TRUE;
21169 		}
21170 		i++;
21171 	}
21172 
21173 	return FALSE;
21174 }
21175 
21176 static bool
wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)21177 wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 *cfg,
21178 		struct parsed_vndr_ie_info *vndr_info)
21179 {
21180 	wl_vndr_oui_entry_t *oui_entry = NULL;
21181 	unsigned long flags;
21182 
21183 	WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21184 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21185 	list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
21186 		GCC_DIAGNOSTIC_POP();
21187 		if (!memcmp(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN)) {
21188 			WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21189 			return TRUE;
21190 		}
21191 	}
21192 	WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21193 	return FALSE;
21194 }
21195 
21196 static bool
wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)21197 wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 *cfg,
21198 	struct parsed_vndr_ie_info *vndr_info)
21199 {
21200 	wl_vndr_oui_entry_t *oui_entry = NULL;
21201 	unsigned long flags;
21202 
21203 	oui_entry = kmalloc(sizeof(*oui_entry), GFP_KERNEL);
21204 	if (oui_entry == NULL) {
21205 		WL_ERR(("alloc failed\n"));
21206 		return FALSE;
21207 	}
21208 
21209 	memcpy(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN);
21210 
21211 	INIT_LIST_HEAD(&oui_entry->list);
21212 	WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21213 	list_add_tail(&oui_entry->list, &cfg->vndr_oui_list);
21214 	WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21215 
21216 	return TRUE;
21217 }
21218 
21219 static void
wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 * cfg)21220 wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg)
21221 {
21222 	wl_vndr_oui_entry_t *oui_entry = NULL;
21223 	unsigned long flags;
21224 
21225 	WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21226 	while (!list_empty(&cfg->vndr_oui_list)) {
21227 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21228 		oui_entry = list_entry(cfg->vndr_oui_list.next, wl_vndr_oui_entry_t, list);
21229 		GCC_DIAGNOSTIC_POP();
21230 		if (oui_entry) {
21231 			list_del(&oui_entry->list);
21232 			kfree(oui_entry);
21233 		}
21234 	}
21235 	WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21236 }
21237 
21238 static int
wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * vndr_oui,u32 vndr_oui_len)21239 wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
21240 	char *vndr_oui, u32 vndr_oui_len)
21241 {
21242 	int i;
21243 	int vndr_oui_num = 0;
21244 
21245 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
21246 	wl_vndr_oui_entry_t *oui_entry = NULL;
21247 	struct parsed_vndr_ie_info *vndr_info;
21248 	struct parsed_vndr_ies vndr_ies;
21249 
21250 	char *pos = vndr_oui;
21251 	u32 remained_buf_len = vndr_oui_len;
21252 	unsigned long flags;
21253 
21254 	if (!conn_info->resp_ie_len) {
21255 		return BCME_ERROR;
21256 	}
21257 
21258 	wl_vndr_ies_clear_vendor_oui_list(cfg);
21259 
21260 	if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
21261 		conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
21262 		for (i = 0; i < vndr_ies.count; i++) {
21263 			vndr_info = &vndr_ies.ie_info[i];
21264 			if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
21265 				continue;
21266 			}
21267 
21268 			if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
21269 				continue;
21270 			}
21271 
21272 			wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
21273 			vndr_oui_num++;
21274 		}
21275 	}
21276 
21277 	if (vndr_oui) {
21278 		WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21279 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21280 		list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
21281 			GCC_DIAGNOSTIC_POP();
21282 			if (remained_buf_len < VNDR_OUI_STR_LEN) {
21283 				WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21284 				return BCME_ERROR;
21285 			}
21286 			pos += snprintf(pos, VNDR_OUI_STR_LEN, "%02X-%02X-%02X ",
21287 				oui_entry->oui[0], oui_entry->oui[1], oui_entry->oui[2]);
21288 			remained_buf_len -= VNDR_OUI_STR_LEN;
21289 		}
21290 		WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21291 	}
21292 
21293 	return vndr_oui_num;
21294 }
21295 
21296 void
wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 * cfg)21297 wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 *cfg)
21298 {
21299 	/* Legacy P2P used to store it in primary dev cache */
21300 	s32 index;
21301 	struct net_device *ndev;
21302 	s32 bssidx;
21303 	s32 ret;
21304 	s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
21305 		VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
21306 
21307 	WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
21308 	/* certain vendors uses p2p0 interface in addition to
21309 	 * the dedicated p2p interface supported by the linux
21310 	 * kernel.
21311 	 */
21312 	ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
21313 	bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
21314 	if (bssidx == WL_INVALID) {
21315 		WL_DBG(("No discovery I/F available. Do nothing.\n"));
21316 		return;
21317 	}
21318 
21319 	for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
21320 		if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
21321 			bssidx, vndrie_flag[index], NULL, 0)) < 0) {
21322 			if (ret != BCME_NOTFOUND) {
21323 				WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret));
21324 			}
21325 		}
21326 	}
21327 
21328 	if (cfg->p2p_wdev && (ndev->ieee80211_ptr != cfg->p2p_wdev)) {
21329 		/* clear IEs for dedicated p2p interface */
21330 		wl_cfg80211_clear_per_bss_ies(cfg, cfg->p2p_wdev);
21331 	}
21332 }
21333 
21334 s32
wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev)21335 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
21336 {
21337 	s32 index;
21338 	s32 ret;
21339 	struct net_info *netinfo;
21340 	s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
21341 		VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
21342 
21343 	netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
21344 	if (!netinfo || !netinfo->wdev) {
21345 		WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
21346 		return -1;
21347 	}
21348 
21349 	WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo->bssidx));
21350 	/* Clear the IEs set in the firmware so that host is in sync with firmware */
21351 	for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
21352 		if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
21353 			netinfo->bssidx, vndrie_flag[index], NULL, 0)) < 0)
21354 			if (ret != BCME_NOTFOUND) {
21355 				WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
21356 			}
21357 	}
21358 
21359 	return 0;
21360 }
21361 
21362 s32
wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 * cfg)21363 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
21364 {
21365 	struct net_info *iter, *next;
21366 
21367 	WL_DBG(("clear management vendor IEs \n"));
21368 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21369 	for_each_ndev(cfg, iter, next) {
21370 		GCC_DIAGNOSTIC_POP();
21371 		wl_cfg80211_clear_per_bss_ies(cfg, iter->wdev);
21372 	}
21373 	return 0;
21374 }
21375 
21376 #define WL_VNDR_IE_MAXLEN 2048
21377 static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
21378 int
wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,s32 bssidx,s32 pktflag,const u8 * vndr_ie,u32 vndr_ie_len)21379 wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21380 	s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
21381 {
21382 	struct net_device *ndev = NULL;
21383 	s32 ret = BCME_OK;
21384 	u8  *curr_ie_buf = NULL;
21385 	u8  *mgmt_ie_buf = NULL;
21386 	u32 mgmt_ie_buf_len = 0;
21387 	u32 *mgmt_ie_len = 0;
21388 	u32 del_add_ie_buf_len = 0;
21389 	u32 total_ie_buf_len = 0;
21390 	u32 parsed_ie_buf_len = 0;
21391 	struct parsed_vndr_ies old_vndr_ies;
21392 	struct parsed_vndr_ies new_vndr_ies;
21393 	s32 i;
21394 	u8 *ptr;
21395 	s32 remained_buf_len;
21396 	wl_bss_vndr_ies_t *ies = NULL;
21397 	struct net_info *netinfo;
21398 	struct wireless_dev *wdev;
21399 
21400 	if (!cfgdev) {
21401 		WL_ERR(("cfgdev is NULL\n"));
21402 		return -EINVAL;
21403 	}
21404 
21405 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
21406 	wdev = cfgdev_to_wdev(cfgdev);
21407 
21408 	if (bssidx > WL_MAX_IFS) {
21409 		WL_ERR(("bssidx > supported concurrent Ifaces \n"));
21410 		return -EINVAL;
21411 	}
21412 
21413 	netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
21414 	if (!netinfo) {
21415 		WL_ERR(("net_info ptr is NULL \n"));
21416 		return -EINVAL;
21417 	}
21418 
21419 	/* Clear the global buffer */
21420 	bzero(g_mgmt_ie_buf, sizeof(g_mgmt_ie_buf));
21421 	curr_ie_buf = g_mgmt_ie_buf;
21422 	ies = &netinfo->bss.ies;
21423 
21424 	WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d wdev:%p\n",
21425 		pktflag, bssidx, vndr_ie_len, wdev));
21426 
21427 	switch (pktflag) {
21428 		case VNDR_IE_PRBRSP_FLAG :
21429 			mgmt_ie_buf = ies->probe_res_ie;
21430 			mgmt_ie_len = &ies->probe_res_ie_len;
21431 			mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
21432 			break;
21433 		case VNDR_IE_ASSOCRSP_FLAG :
21434 			mgmt_ie_buf = ies->assoc_res_ie;
21435 			mgmt_ie_len = &ies->assoc_res_ie_len;
21436 			mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
21437 			break;
21438 		case VNDR_IE_BEACON_FLAG :
21439 			mgmt_ie_buf = ies->beacon_ie;
21440 			mgmt_ie_len = &ies->beacon_ie_len;
21441 			mgmt_ie_buf_len = sizeof(ies->beacon_ie);
21442 			break;
21443 		case VNDR_IE_PRBREQ_FLAG :
21444 			mgmt_ie_buf = ies->probe_req_ie;
21445 			mgmt_ie_len = &ies->probe_req_ie_len;
21446 			mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
21447 			break;
21448 		case VNDR_IE_ASSOCREQ_FLAG :
21449 			mgmt_ie_buf = ies->assoc_req_ie;
21450 			mgmt_ie_len = &ies->assoc_req_ie_len;
21451 			mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
21452 			break;
21453 		case VNDR_IE_DISASSOC_FLAG :
21454 			mgmt_ie_buf = ies->disassoc_ie;
21455 			mgmt_ie_len = &ies->disassoc_ie_len;
21456 			mgmt_ie_buf_len = sizeof(ies->disassoc_ie);
21457 			break;
21458 		default:
21459 			mgmt_ie_buf = NULL;
21460 			mgmt_ie_len = NULL;
21461 			WL_ERR(("not suitable packet type (%d)\n", pktflag));
21462 			return BCME_ERROR;
21463 	}
21464 
21465 	if (vndr_ie_len > mgmt_ie_buf_len) {
21466 		WL_ERR(("extra IE size too big\n"));
21467 		ret = -ENOMEM;
21468 	} else {
21469 		/* parse and save new vndr_ie in curr_ie_buff before comparing it */
21470 		if (vndr_ie && vndr_ie_len && curr_ie_buf) {
21471 			ptr = curr_ie_buf;
21472 
21473 			if ((ret = wl_cfg80211_parse_vndr_ies((const u8 *)vndr_ie,
21474 			                                      vndr_ie_len, &new_vndr_ies)) < 0) {
21475 				WL_ERR(("parse vndr ie failed \n"));
21476 				goto exit;
21477 			}
21478 
21479 			for (i = 0; i < new_vndr_ies.count; i++) {
21480 				struct parsed_vndr_ie_info *vndrie_info =
21481 					&new_vndr_ies.ie_info[i];
21482 
21483 				if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
21484 					WL_ERR(("IE size is too big (%d > %d)\n",
21485 						parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
21486 					ret = -EINVAL;
21487 					goto exit;
21488 				}
21489 
21490 				memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
21491 					vndrie_info->ie_len);
21492 				parsed_ie_buf_len += vndrie_info->ie_len;
21493 			}
21494 		}
21495 
21496 		if (mgmt_ie_buf != NULL) {
21497 			if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
21498 				(memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
21499 				WL_DBG(("Previous mgmt IE is equals to current IE"));
21500 				goto exit;
21501 			}
21502 
21503 			/* parse old vndr_ie */
21504 			if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
21505 				&old_vndr_ies)) < 0) {
21506 				WL_ERR(("parse vndr ie failed \n"));
21507 				goto exit;
21508 			}
21509 			/* make a command to delete old ie */
21510 			for (i = 0; i < old_vndr_ies.count; i++) {
21511 				struct parsed_vndr_ie_info *vndrie_info =
21512 				&old_vndr_ies.ie_info[i];
21513 #if defined(WL_MBO) || defined(WL_OCE)
21514 			{
21515 				if ((vndrie_info->vndrie.id == 0xDD) &&
21516 					(!memcmp(vndrie_info->vndrie.oui, WFA_OUI, WFA_OUI_LEN)) &&
21517 					(vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
21518 					WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
21519 						", type: %0x\n",
21520 						vndrie_info->vndrie.id,
21521 						vndrie_info->vndrie.len,
21522 						MACOUI2STRDBG(vndrie_info->vndrie.oui),
21523 						vndrie_info->vndrie.data[0]));
21524 					continue;
21525 				}
21526 			}
21527 #endif /* WL_MBO || WL_OCE */
21528 
21529 				if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
21530 					WL_DBG(("DELETED VENDOR EXTN ID : %d, TYPE: %d Len: %d\n",
21531 						vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
21532 						vndrie_info->vndrie.len));
21533 				} else {
21534 					WL_DBG(("DELETED ID : %d, Len: %d , OUI:"MACOUIDBG"\n",
21535 						vndrie_info->vndrie.id, vndrie_info->vndrie.len,
21536 						MACOUI2STRDBG(vndrie_info->vndrie.oui)));
21537 				}
21538 
21539 				del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
21540 					pktflag, vndrie_info->vndrie.oui,
21541 					vndrie_info->vndrie.id,
21542 					vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
21543 					vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
21544 					"del");
21545 
21546 				curr_ie_buf += del_add_ie_buf_len;
21547 				total_ie_buf_len += del_add_ie_buf_len;
21548 			}
21549 		}
21550 
21551 		*mgmt_ie_len = 0;
21552 		/* Add if there is any extra IE */
21553 		if (mgmt_ie_buf && parsed_ie_buf_len) {
21554 			ptr = mgmt_ie_buf;
21555 
21556 			remained_buf_len = mgmt_ie_buf_len;
21557 
21558 			/* make a command to add new ie */
21559 			for (i = 0; i < new_vndr_ies.count; i++) {
21560 				struct parsed_vndr_ie_info *vndrie_info =
21561 					&new_vndr_ies.ie_info[i];
21562 #if defined(WL_MBO) || defined(WL_OCE)
21563 			{
21564 				if ((vndrie_info->vndrie.id == 0xDD) &&
21565 					(!memcmp(vndrie_info->vndrie.oui, WFA_OUI, WFA_OUI_LEN)) &&
21566 					(vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
21567 					WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
21568 						",type :%0x\n",
21569 						vndrie_info->vndrie.id,
21570 						vndrie_info->vndrie.len,
21571 						MACOUI2STRDBG(vndrie_info->vndrie.oui),
21572 						vndrie_info->vndrie.data[0]));
21573 					continue;
21574 				}
21575 			}
21576 #endif /* WL_MBO || WL_OCE */
21577 				if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
21578 					WL_DBG(("ADDED VENDOR EXTN ID : %d, TYPE = %d, Len: %d\n",
21579 						vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
21580 						vndrie_info->vndrie.len));
21581 				} else {
21582 					WL_DBG(("ADDED ID : %d, Len: %d(%d), OUI:"MACOUIDBG"\n",
21583 						vndrie_info->vndrie.id, vndrie_info->vndrie.len,
21584 						vndrie_info->ie_len - 2,
21585 						MACOUI2STRDBG(vndrie_info->vndrie.oui)));
21586 				}
21587 
21588 				del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
21589 					pktflag, vndrie_info->vndrie.oui,
21590 					vndrie_info->vndrie.id,
21591 					vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
21592 					vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
21593 					"add");
21594 
21595 				/* verify remained buf size before copy data */
21596 				if (remained_buf_len >= vndrie_info->ie_len) {
21597 					remained_buf_len -= vndrie_info->ie_len;
21598 				} else {
21599 					WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
21600 					"found vndr ies # = %d(cur %d), remained len %d, "
21601 					"cur mgmt_ie_len %d, new ie len = %d\n",
21602 					pktflag, new_vndr_ies.count, i, remained_buf_len,
21603 					*mgmt_ie_len, vndrie_info->ie_len));
21604 					break;
21605 				}
21606 
21607 				/* save the parsed IE in cfg struct */
21608 				memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
21609 					vndrie_info->ie_len);
21610 				*mgmt_ie_len += vndrie_info->ie_len;
21611 				curr_ie_buf += del_add_ie_buf_len;
21612 				total_ie_buf_len += del_add_ie_buf_len;
21613 			}
21614 		}
21615 
21616 		if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
21617 			ret  = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
21618 				total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
21619 				bssidx, &cfg->ioctl_buf_sync);
21620 			if (ret)
21621 				WL_ERR(("vndr ie set error : %d\n", ret));
21622 		}
21623 	}
21624 exit:
21625 
21626 return ret;
21627 }
21628 
21629 #ifdef WL_CFG80211_ACL
21630 static int
wl_cfg80211_set_mac_acl(struct wiphy * wiphy,struct net_device * cfgdev,const struct cfg80211_acl_data * acl)21631 wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
21632 	const struct cfg80211_acl_data *acl)
21633 {
21634 	int i;
21635 	int ret = 0;
21636 	int macnum = 0;
21637 	int macmode = MACLIST_MODE_DISABLED;
21638 	struct maclist *list;
21639 	struct bcm_cfg80211 *cfg = wl_get_cfg(cfgdev);
21640 
21641 	/* get the MAC filter mode */
21642 	if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
21643 		macmode = MACLIST_MODE_ALLOW;
21644 	} else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
21645 	acl->n_acl_entries) {
21646 		macmode = MACLIST_MODE_DENY;
21647 	}
21648 
21649 	/* if acl == NULL, macmode is still disabled.. */
21650 	if (macmode == MACLIST_MODE_DISABLED) {
21651 		if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0)
21652 			WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list"
21653 				" failed error=%d\n", ret));
21654 
21655 		return ret;
21656 	}
21657 
21658 	macnum = acl->n_acl_entries;
21659 	if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
21660 		WL_ERR(("wl_cfg80211_set_mac_acl: invalid number of MAC address entries %d\n",
21661 			macnum));
21662 		return -1;
21663 	}
21664 
21665 	/* allocate memory for the MAC list */
21666 	list = (struct maclist *)MALLOC(cfg->osh, sizeof(int) +
21667 		sizeof(struct ether_addr) * macnum);
21668 	if (!list) {
21669 		WL_ERR(("wl_cfg80211_set_mac_acl: failed to allocate memory\n"));
21670 		return -1;
21671 	}
21672 
21673 	/* prepare the MAC list */
21674 	list->count = htod32(macnum);
21675 	for (i = 0; i < macnum; i++) {
21676 		memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN);
21677 	}
21678 	/* set the list */
21679 	if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0)
21680 		WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list failed error=%d\n", ret));
21681 
21682 	MFREE(cfg->osh, list, sizeof(int) +
21683 		sizeof(struct ether_addr) * macnum);
21684 
21685 	return ret;
21686 }
21687 #endif /* WL_CFG80211_ACL */
21688 
21689 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
wl_chspec_chandef(chanspec_t chanspec,struct cfg80211_chan_def * chandef,struct wiphy * wiphy)21690 int wl_chspec_chandef(chanspec_t chanspec,
21691 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
21692 	struct cfg80211_chan_def *chandef,
21693 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
21694 	struct chan_info *chaninfo,
21695 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
21696 	struct wiphy *wiphy)
21697 {
21698 	uint16 freq = 0;
21699 	int chan_type = 0;
21700 	int channel = 0;
21701 	struct ieee80211_channel *chan;
21702 
21703 	if (!chandef) {
21704 		return -1;
21705 	}
21706 	channel = CHSPEC_CHANNEL(chanspec);
21707 
21708 	switch (CHSPEC_BW(chanspec)) {
21709 		case WL_CHANSPEC_BW_20:
21710 			chan_type = NL80211_CHAN_HT20;
21711 			break;
21712 		case WL_CHANSPEC_BW_40:
21713 		{
21714 			if (CHSPEC_SB_UPPER(chanspec)) {
21715 				channel += CH_10MHZ_APART;
21716 			} else {
21717 				channel -= CH_10MHZ_APART;
21718 			}
21719 		}
21720 			chan_type = NL80211_CHAN_HT40PLUS;
21721 			break;
21722 
21723 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21724 		case WL_CHANSPEC_BW_80:
21725 		case WL_CHANSPEC_BW_8080:
21726 		{
21727 			uint16 sb = CHSPEC_CTL_SB(chanspec);
21728 
21729 			if (sb == WL_CHANSPEC_CTL_SB_LL) {
21730 				channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
21731 			} else if (sb == WL_CHANSPEC_CTL_SB_LU) {
21732 				channel -= CH_10MHZ_APART;
21733 			} else if (sb == WL_CHANSPEC_CTL_SB_UL) {
21734 				channel += CH_10MHZ_APART;
21735 			} else {
21736 				/* WL_CHANSPEC_CTL_SB_UU */
21737 				channel += (CH_10MHZ_APART + CH_20MHZ_APART);
21738 			}
21739 
21740 			if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_LU)
21741 				chan_type = NL80211_CHAN_HT40MINUS;
21742 			else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU)
21743 				chan_type = NL80211_CHAN_HT40PLUS;
21744 		}
21745 			break;
21746 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21747 		default:
21748 			chan_type = NL80211_CHAN_HT20;
21749 			break;
21750 
21751 	}
21752 
21753 	if (CHSPEC_IS5G(chanspec))
21754 		freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
21755 	else
21756 		freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
21757 
21758 	chan = ieee80211_get_channel(wiphy, freq);
21759 	WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
21760 		channel, freq, chan_type, chan));
21761 
21762 	if (unlikely(!chan)) {
21763 		/* fw and cfg80211 channel lists are not in sync */
21764 		WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
21765 		ASSERT(0);
21766 		return -EINVAL;
21767 	}
21768 
21769 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21770 	cfg80211_chandef_create(chandef, chan, chan_type);
21771 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
21772 	\
21773 	0)))
21774 	chaninfo->freq = freq;
21775 	chaninfo->chan_type = chan_type;
21776 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21777 	return 0;
21778 }
21779 
21780 void
wl_cfg80211_ch_switch_notify(struct net_device * dev,uint16 chanspec,struct wiphy * wiphy)21781 wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy)
21782 {
21783 	u32 freq;
21784 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21785 	struct cfg80211_chan_def chandef;
21786 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
21787 	struct chan_info chaninfo;
21788 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21789 
21790 	if (!wiphy) {
21791 		WL_ERR(("wiphy is null\n"));
21792 		return;
21793 	}
21794 #if (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0))
21795 	/* Channel switch support is only for AP/GO/ADHOC/MESH */
21796 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
21797 		dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
21798 		WL_ERR(("No channel switch notify support for STA/GC\n"));
21799 		return;
21800 	}
21801 #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
21802 
21803 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21804 	if (wl_chspec_chandef(chanspec, &chandef, wiphy))
21805 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
21806 	if (wl_chspec_chandef(chanspec, &chaninfo, wiphy))
21807 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21808 	{
21809 		WL_ERR(("chspec_chandef failed\n"));
21810 		return;
21811 	}
21812 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21813 	freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1;
21814 	cfg80211_ch_switch_notify(dev, &chandef);
21815 #ifdef CONFIG_AP6XXX_WIFI6_HDF
21816 	HdfWifiEventCsaChannelSwitch(get_hdf_netdev(HDF_INF_P2P0), freq);
21817 #endif
21818 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
21819 	freq = chan_info.freq;
21820 	cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type);
21821 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21822 
21823 	WL_MSG(dev->name, "Channel switch notification for freq: %d chanspec: 0x%x\n",
21824 		freq, chanspec);
21825 	return;
21826 }
21827 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
21828 
21829 static void
wl_ap_channel_ind(struct bcm_cfg80211 * cfg,struct net_device * ndev,chanspec_t chanspec)21830 wl_ap_channel_ind(struct bcm_cfg80211 *cfg,
21831 	struct net_device *ndev,
21832 	chanspec_t chanspec)
21833 {
21834 	u32 channel = LCHSPEC_CHANNEL(chanspec);
21835 
21836 	WL_INFORM_MEM(("(%s) AP channel:%d chspec:0x%x \n",
21837 		ndev->name, channel, chanspec));
21838 
21839 #ifdef SUPPORT_AP_BWCTRL
21840 	wl_update_apchan_bwcap(cfg, ndev, chanspec);
21841 #endif /* SUPPORT_AP_BWCTRL */
21842 
21843 	if (cfg->ap_oper_channel && (cfg->ap_oper_channel != channel)) {
21844 		/*
21845 		 * If cached channel is different from the channel indicated
21846 		 * by the event, notify user space about the channel switch.
21847 		 */
21848 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
21849 		wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
21850 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
21851 		cfg->ap_oper_channel = channel;
21852 	}
21853 }
21854 
21855 static s32
wl_ap_start_ind(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21856 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21857 const wl_event_msg_t *e, void *data)
21858 {
21859 	struct net_device *ndev = NULL;
21860 	chanspec_t chanspec;
21861 
21862 	WL_DBG(("Enter\n"));
21863 	if (unlikely(e->status)) {
21864 		WL_ERR(("status:0x%x \n", e->status));
21865 		return -1;
21866 	}
21867 
21868 	if (!data) {
21869 		return -EINVAL;
21870 	}
21871 
21872 	if (likely(cfgdev)) {
21873 		ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
21874 		chanspec = *((chanspec_t *)data);
21875 
21876 		if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
21877 			/* For AP/GO role */
21878 			wl_ap_channel_ind(cfg, ndev, chanspec);
21879 		}
21880 	}
21881 
21882 	return 0;
21883 }
21884 
21885 static s32
wl_csa_complete_ind(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21886 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21887 const wl_event_msg_t *e, void *data)
21888 {
21889 	int error = 0;
21890 	u32 chanspec = 0;
21891 	struct net_device *ndev = NULL;
21892 	struct ether_addr bssid;
21893 
21894 	WL_DBG(("Enter\n"));
21895 	if (unlikely(e->status)) {
21896 		WL_ERR(("status:0x%x \n", e->status));
21897 		return -1;
21898 	}
21899 
21900 	if (likely(cfgdev)) {
21901 		ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
21902 		/* Get association state if not AP and then query chanspec */
21903 		if (!((wl_get_mode_by_netdev(cfg, ndev)) == WL_MODE_AP)) {
21904 			error = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
21905 			if (error) {
21906 				WL_ERR(("CSA on %s. Not associated. error=%d\n",
21907 					ndev->name, error));
21908 				return BCME_ERROR;
21909 			}
21910 		}
21911 
21912 		error = wldev_iovar_getint(ndev, "chanspec", &chanspec);
21913 		if (unlikely(error)) {
21914 			WL_ERR(("Get chanspec error: %d \n", error));
21915 			return -1;
21916 		}
21917 
21918 		WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev->name, chanspec));
21919 		if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
21920 			/* For AP/GO role */
21921 			wl_ap_channel_ind(cfg, ndev, chanspec);
21922 		} else {
21923 			/* STA/GC roles */
21924 			if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
21925 				WL_ERR(("CSA on %s. Not associated.\n", ndev->name));
21926 				return BCME_ERROR;
21927 			}
21928 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
21929 			wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
21930 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
21931 		}
21932 
21933 	}
21934 
21935 	return 0;
21936 }
21937 
wl_cfg80211_clear_security(struct bcm_cfg80211 * cfg)21938 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
21939 {
21940 	struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
21941 	int err;
21942 
21943 	/* Clear the security settings on the primary Interface */
21944 	err = wldev_iovar_setint(dev, "wsec", 0);
21945 	if (unlikely(err)) {
21946 		WL_ERR(("wsec clear failed \n"));
21947 	}
21948 	err = wldev_iovar_setint(dev, "auth", 0);
21949 	if (unlikely(err)) {
21950 		WL_ERR(("auth clear failed \n"));
21951 	}
21952 	err = wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
21953 	if (unlikely(err)) {
21954 		WL_ERR(("wpa_auth clear failed \n"));
21955 	}
21956 }
21957 
21958 #ifdef WL_CFG80211_P2P_DEV_IF
wl_cfg80211_del_p2p_wdev(struct net_device * dev)21959 void wl_cfg80211_del_p2p_wdev(struct net_device *dev)
21960 {
21961 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21962 	struct wireless_dev *wdev = NULL;
21963 
21964 	WL_DBG(("Enter \n"));
21965 	if (!cfg) {
21966 		WL_ERR(("Invalid Ptr\n"));
21967 		return;
21968 	} else {
21969 		wdev = cfg->p2p_wdev;
21970 	}
21971 
21972 	if (wdev) {
21973 		wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
21974 	}
21975 }
21976 #endif /* WL_CFG80211_P2P_DEV_IF */
21977 
21978 #ifdef GTK_OFFLOAD_SUPPORT
21979 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
21980 static s32
wl_cfg80211_set_rekey_data(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_gtk_rekey_data * data)21981 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
21982 		struct cfg80211_gtk_rekey_data *data)
21983 {
21984 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
21985 	s32 err = 0;
21986 	gtk_keyinfo_t keyinfo;
21987 	bcol_gtk_para_t bcol_keyinfo;
21988 
21989 	WL_DBG(("Enter\n"));
21990 	if (data == NULL || cfg->p2p_net == dev) {
21991 		WL_ERR(("data is NULL or wrong net device\n"));
21992 		return -EINVAL;
21993 	}
21994 
21995 	prhex("kck", (const u8 *) (data->kck), RSN_KCK_LENGTH);
21996 	prhex("kek", (const u8 *) (data->kek), RSN_KEK_LENGTH);
21997 	prhex("replay_ctr", (const u8 *) (data->replay_ctr), RSN_REPLAY_LEN);
21998 	bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH);
21999 	bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH);
22000 	bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN);
22001 
22002 	memset(&bcol_keyinfo, 0, sizeof(bcol_keyinfo));
22003 	bcol_keyinfo.enable = 1;
22004 	bcol_keyinfo.ptk_len = 64;
22005 	memcpy(&bcol_keyinfo.ptk[0], data->kck, RSN_KCK_LENGTH);
22006 	memcpy(&bcol_keyinfo.ptk[RSN_KCK_LENGTH], data->kek, RSN_KEK_LENGTH);
22007 	err = wldev_iovar_setbuf(dev, "bcol_gtk_rekey_ptk", &bcol_keyinfo,
22008 		sizeof(bcol_keyinfo), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
22009 	if (!err) {
22010 		return err;
22011 	}
22012 
22013 	if ((err = wldev_iovar_setbuf(dev, "gtk_key_info", &keyinfo, sizeof(keyinfo),
22014 		cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync)) < 0) {
22015 		WL_ERR(("seting gtk_key_info failed code=%d\n", err));
22016 		return err;
22017 	}
22018 
22019 	WL_DBG(("Exit\n"));
22020 	return err;
22021 }
22022 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
22023 #endif /* GTK_OFFLOAD_SUPPORT */
22024 
22025 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
wl_cfg80211_set_pmk(struct wiphy * wiphy,struct net_device * dev,const struct cfg80211_pmk_conf * conf)22026 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
22027 	const struct cfg80211_pmk_conf *conf)
22028 {
22029 	int ret = 0;
22030 	wsec_pmk_t pmk;
22031 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
22032 	struct wl_security *sec;
22033 	s32 bssidx;
22034 
22035 	pmk.key_len = conf->pmk_len;
22036 	if (pmk.key_len > sizeof(pmk.key)) {
22037 		ret = -EINVAL;
22038 		return ret;
22039 	}
22040 	pmk.flags = 0;
22041 	ret = memcpy_s(&pmk.key, sizeof(pmk.key), conf->pmk, conf->pmk_len);
22042 	if (ret) {
22043 		ret = -EINVAL;
22044 		return ret;
22045 	}
22046 
22047 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
22048 		WL_ERR(("Find index failed\n"));
22049 		ret = -EINVAL;
22050 		return ret;
22051 	}
22052 
22053 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
22054 	if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
22055 		(sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
22056 		ret = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len,
22057 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
22058 		if (ret) {
22059 			/* could fail in case that 'okc' is not supported */
22060 			WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
22061 		}
22062 	}
22063 
22064 	ret = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
22065 	if (ret) {
22066 		WL_ERR(("wl_cfg80211_set_pmk error:%d", ret));
22067 		ret = -EINVAL;
22068 		return ret;
22069 	}
22070 	return 0;
22071 }
22072 
wl_cfg80211_del_pmk(struct wiphy * wiphy,struct net_device * dev,const u8 * aa)22073 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
22074 	const u8 *aa)
22075 {
22076 	int err = BCME_OK;
22077 	struct cfg80211_pmksa pmksa;
22078 
22079 	/* build up cfg80211_pmksa structure to use existing wl_cfg80211_update_pmksa API */
22080 	bzero(&pmksa, sizeof(pmksa));
22081 	pmksa.bssid = aa;
22082 
22083 	err = wl_cfg80211_update_pmksa(wiphy, dev, &pmksa, FALSE);
22084 
22085 	if (err) {
22086 		WL_ERR(("wl_cfg80211_update_pmksa err:%d\n", err));
22087 		err = -EINVAL;
22088 	}
22089 
22090 	return err;
22091 }
22092 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
22093 
22094 #if defined(WL_SUPPORT_AUTO_CHANNEL)
22095 int
wl_cfg80211_set_spect(struct net_device * dev,int spect)22096 wl_cfg80211_set_spect(struct net_device *dev, int spect)
22097 {
22098 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22099 	int wlc_down = 1;
22100 	int wlc_up = 1;
22101 	int err = BCME_OK;
22102 
22103 	if (!wl_get_drv_status_all(cfg, CONNECTED)) {
22104 		err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
22105 		if (err) {
22106 			WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
22107 			return err;
22108 		}
22109 
22110 		err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
22111 		if (err) {
22112 			WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
22113 			return err;
22114 		}
22115 
22116 		err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
22117 		if (err) {
22118 			WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
22119 			return err;
22120 		}
22121 	}
22122 	return err;
22123 }
22124 
22125 int
wl_cfg80211_get_sta_channel(struct bcm_cfg80211 * cfg)22126 wl_cfg80211_get_sta_channel(struct bcm_cfg80211 *cfg)
22127 {
22128 	int channel = 0;
22129 
22130 	if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
22131 		channel = cfg->channel;
22132 	}
22133 	return channel;
22134 }
22135 #endif /* WL_SUPPORT_AUTO_CHANNEL */
22136 
22137 u64
wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 * cfg)22138 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
22139 {
22140 	u64 id = 0;
22141 	id = ++cfg->last_roc_id;
22142 #ifdef  P2P_LISTEN_OFFLOADING
22143 	if (id == P2PO_COOKIE) {
22144 		id = ++cfg->last_roc_id;
22145 	}
22146 #endif /* P2P_LISTEN_OFFLOADING */
22147 	if (id == 0)
22148 		id = ++cfg->last_roc_id;
22149 	return id;
22150 }
22151 
22152 #ifdef WLTDLS
22153 s32
wl_cfg80211_tdls_config(struct bcm_cfg80211 * cfg,enum wl_tdls_config state,bool auto_mode)22154 wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg, enum wl_tdls_config state, bool auto_mode)
22155 {
22156 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
22157 	int err = 0;
22158 	struct net_info *iter, *next;
22159 	int update_reqd = 0;
22160 	int enable = 0;
22161 	dhd_pub_t *dhdp;
22162 	dhdp = (dhd_pub_t *)(cfg->pub);
22163 
22164 	/*
22165 	 * TDLS need to be enabled only if we have a single STA/GC
22166 	 * connection.
22167 	 */
22168 
22169 	WL_DBG(("Enter state:%d\n", state));
22170 	if (!cfg->tdls_supported) {
22171 		/* FW doesn't support tdls. Do nothing */
22172 		return -ENODEV;
22173 	}
22174 
22175 	/* Protect tdls config session */
22176 	mutex_lock(&cfg->tdls_sync);
22177 
22178 	if (state == TDLS_STATE_TEARDOWN) {
22179 		/* Host initiated TDLS tear down */
22180 		err = dhd_tdls_enable(ndev, false, auto_mode, NULL);
22181 		goto exit;
22182 	} else if ((state == TDLS_STATE_AP_CREATE) ||
22183 		(state == TDLS_STATE_NMI_CREATE)) {
22184 		/* We don't support tdls while AP/GO/NAN is operational */
22185 		update_reqd = true;
22186 		enable = false;
22187 	} else if ((state == TDLS_STATE_CONNECT) || (state == TDLS_STATE_IF_CREATE)) {
22188 		if (wl_get_drv_status_all(cfg,
22189 			CONNECTED) >= TDLS_MAX_IFACE_FOR_ENABLE) {
22190 			/* For STA/GC connect command request, disable
22191 			 * tdls if we have any concurrent interfaces
22192 			 * operational.
22193 			 */
22194 			WL_DBG(("Interface limit restriction. disable tdls.\n"));
22195 			update_reqd = true;
22196 			enable = false;
22197 		}
22198 	} else if ((state == TDLS_STATE_DISCONNECT) ||
22199 		(state == TDLS_STATE_AP_DELETE) ||
22200 		(state == TDLS_STATE_SETUP) ||
22201 		(state == TDLS_STATE_IF_DELETE)) {
22202 		/* Enable back the tdls connection only if we have less than
22203 		 * or equal to a single STA/GC connection.
22204 		 */
22205 		if (wl_get_drv_status_all(cfg,
22206 			CONNECTED) == 0) {
22207 			/* If there are no interfaces connected, enable tdls */
22208 			update_reqd = true;
22209 			enable = true;
22210 		} else if (wl_get_drv_status_all(cfg,
22211 			CONNECTED) == TDLS_MAX_IFACE_FOR_ENABLE) {
22212 			/* We have one interface in CONNECTED state.
22213 			 * Verify whether its a STA interface before
22214 			 * we enable back tdls.
22215 			 */
22216 			GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22217 			for_each_ndev(cfg, iter, next) {
22218 				GCC_DIAGNOSTIC_POP();
22219 				if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, ndev)) &&
22220 					(ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)) {
22221 					WL_DBG(("Non STA iface operational. cfg_iftype:%d"
22222 						" Can't enable tdls.\n",
22223 						ndev->ieee80211_ptr->iftype));
22224 					err = -ENOTSUPP;
22225 					goto exit;
22226 				}
22227 			}
22228 			/* No AP/GO found. Enable back tdls */
22229 			update_reqd = true;
22230 			enable = true;
22231 		} else {
22232 			WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
22233 			err = -ENOTSUPP;
22234 			goto exit;
22235 		}
22236 	} else {
22237 		WL_ERR(("Unknown tdls state:%d \n", state));
22238 		err = -EINVAL;
22239 		goto exit;
22240 	}
22241 
22242 	if (update_reqd == true) {
22243 		if (dhdp->tdls_enable == enable) {
22244 			WL_DBG(("No change in tdls state. Do nothing."
22245 				" tdls_enable:%d\n", enable));
22246 			goto exit;
22247 		}
22248 		err = wldev_iovar_setint(ndev, "tdls_enable", enable);
22249 		if (unlikely(err)) {
22250 			WL_ERR(("tdls_enable setting failed. err:%d\n", err));
22251 			goto exit;
22252 		} else {
22253 			WL_INFORM_MEM(("tdls_enable %d state:%d\n", enable, state));
22254 			/* Update the dhd state variable to be in sync */
22255 			dhdp->tdls_enable = enable;
22256 			if (state == TDLS_STATE_SETUP) {
22257 				/* For host initiated setup, apply TDLS params
22258 				 * Don't propagate errors up for param config
22259 				 * failures
22260 				 */
22261 				dhd_tdls_enable(ndev, true, auto_mode, NULL);
22262 
22263 			}
22264 		}
22265 	} else {
22266 		WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
22267 			"current_status:%d \n",
22268 			state, update_reqd, dhdp->tdls_enable));
22269 	}
22270 
22271 exit:
22272 	if (err) {
22273 		wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
22274 	}
22275 	mutex_unlock(&cfg->tdls_sync);
22276 	return err;
22277 }
22278 #endif /* WLTDLS */
22279 
wl_get_ap_netdev(struct bcm_cfg80211 * cfg,char * ifname)22280 struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname)
22281 {
22282 	struct net_info *iter, *next;
22283 	struct net_device *ndev = NULL;
22284 
22285 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22286 	for_each_ndev(cfg, iter, next) {
22287 		GCC_DIAGNOSTIC_POP();
22288 		if (iter->ndev) {
22289 			if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
22290 				if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
22291 					ndev = iter->ndev;
22292 					break;
22293 				}
22294 			}
22295 		}
22296 	}
22297 
22298 	return ndev;
22299 }
22300 
22301 struct net_device*
wl_get_netdev_by_name(struct bcm_cfg80211 * cfg,char * ifname)22302 wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname)
22303 {
22304 	struct net_info *iter, *next;
22305 	struct net_device *ndev = NULL;
22306 
22307 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22308 	for_each_ndev(cfg, iter, next) {
22309 		GCC_DIAGNOSTIC_POP();
22310 		if (iter->ndev) {
22311 			if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
22312 				ndev = iter->ndev;
22313 				break;
22314 			}
22315 		}
22316 	}
22317 
22318 	return ndev;
22319 }
22320 
22321 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
22322 #define WLC_RATE_FLAG	0x80
22323 #define RATE_MASK		0x7f
22324 
wl_set_ap_beacon_rate(struct net_device * dev,int val,char * ifname)22325 int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname)
22326 {
22327 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22328 	dhd_pub_t *dhdp;
22329 	wl_rateset_args_t rs;
22330 	int error = BCME_ERROR, i;
22331 	struct net_device *ndev = NULL;
22332 
22333 	dhdp = (dhd_pub_t *)(cfg->pub);
22334 
22335 	if (dhdp && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22336 		WL_ERR(("Not Hostapd mode\n"));
22337 		return BCME_NOTAP;
22338 	}
22339 
22340 	ndev = wl_get_ap_netdev(cfg, ifname);
22341 
22342 	if (ndev == NULL) {
22343 		WL_ERR(("No softAP interface named %s\n", ifname));
22344 		return BCME_NOTAP;
22345 	}
22346 
22347 	bzero(&rs, sizeof(wl_rateset_args_t));
22348 	error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
22349 		&rs, sizeof(wl_rateset_args_t), NULL);
22350 	if (error < 0) {
22351 		WL_ERR(("get rateset failed = %d\n", error));
22352 		return error;
22353 	}
22354 
22355 	if (rs.count < 1) {
22356 		WL_ERR(("Failed to get rate count\n"));
22357 		return BCME_ERROR;
22358 	}
22359 
22360 	/* Host delivers target rate in the unit of 500kbps */
22361 	/* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic rate */
22362 	for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
22363 		if (rs.rates[i] & WLC_RATE_FLAG)
22364 			if ((rs.rates[i] & RATE_MASK) == val)
22365 				break;
22366 
22367 	/* Valid rate has been delivered as an argument */
22368 	if (i < rs.count && i < WL_NUMRATES) {
22369 		error = wldev_iovar_setint(ndev, "force_bcn_rspec", val);
22370 		if (error < 0) {
22371 			WL_ERR(("set beacon rate failed = %d\n", error));
22372 			return BCME_ERROR;
22373 		}
22374 	} else {
22375 		WL_ERR(("Rate is invalid"));
22376 		return BCME_BADARG;
22377 	}
22378 
22379 	return BCME_OK;
22380 }
22381 
22382 int
wl_get_ap_basic_rate(struct net_device * dev,char * command,char * ifname,int total_len)22383 wl_get_ap_basic_rate(struct net_device *dev, char* command, char *ifname, int total_len)
22384 {
22385 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22386 	dhd_pub_t *dhdp;
22387 	wl_rateset_args_t rs;
22388 	int error = BCME_ERROR;
22389 	int i, bytes_written = 0;
22390 	struct net_device *ndev = NULL;
22391 
22392 	dhdp = (dhd_pub_t *)(cfg->pub);
22393 
22394 	if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22395 		WL_ERR(("Not Hostapd mode\n"));
22396 		return BCME_NOTAP;
22397 	}
22398 
22399 	ndev = wl_get_ap_netdev(cfg, ifname);
22400 
22401 	if (ndev == NULL) {
22402 		WL_ERR(("No softAP interface named %s\n", ifname));
22403 		return BCME_NOTAP;
22404 	}
22405 
22406 	bzero(&rs, sizeof(wl_rateset_args_t));
22407 	error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
22408 		&rs, sizeof(wl_rateset_args_t), NULL);
22409 	if (error < 0) {
22410 		WL_ERR(("get rateset failed = %d\n", error));
22411 		return error;
22412 	}
22413 
22414 	if (rs.count < 1) {
22415 		WL_ERR(("Failed to get rate count\n"));
22416 		return BCME_ERROR;
22417 	}
22418 
22419 	/* Delivers basic rate in the unit of 500kbps to host */
22420 	for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
22421 		if (rs.rates[i] & WLC_RATE_FLAG)
22422 			bytes_written += snprintf(command + bytes_written, total_len,
22423 							"%d ", rs.rates[i] & RATE_MASK);
22424 
22425 	/* Remove last space in the command buffer */
22426 	if (bytes_written && (bytes_written < total_len)) {
22427 		command[bytes_written - 1] = '\0';
22428 		bytes_written--;
22429 	}
22430 
22431 	return bytes_written;
22432 
22433 }
22434 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
22435 
22436 #ifdef SUPPORT_AP_RADIO_PWRSAVE
22437 #define MSEC_PER_MIN	(60000L)
22438 
22439 static int
_wl_update_ap_rps_params(struct net_device * dev)22440 _wl_update_ap_rps_params(struct net_device *dev)
22441 {
22442 	struct bcm_cfg80211 *cfg = NULL;
22443 	rpsnoa_iovar_params_t iovar;
22444 	u8 smbuf[WLC_IOCTL_SMLEN];
22445 
22446 	if (!dev)
22447 		return BCME_BADARG;
22448 
22449 	cfg = wl_get_cfg(dev);
22450 
22451 	bzero(&iovar, sizeof(iovar));
22452 	bzero(smbuf, sizeof(smbuf));
22453 
22454 	iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
22455 	iovar.hdr.subcmd = WL_RPSNOA_CMD_PARAMS;
22456 	iovar.hdr.len = sizeof(iovar);
22457 	iovar.param->band = WLC_BAND_ALL;
22458 	iovar.param->level = cfg->ap_rps_info.level;
22459 	iovar.param->stas_assoc_check = cfg->ap_rps_info.sta_assoc_check;
22460 	iovar.param->pps = cfg->ap_rps_info.pps;
22461 	iovar.param->quiet_time = cfg->ap_rps_info.quiet_time;
22462 
22463 	if (wldev_iovar_setbuf(dev, "rpsnoa", &iovar, sizeof(iovar),
22464 		smbuf, sizeof(smbuf), NULL)) {
22465 		WL_ERR(("Failed to set rpsnoa params"));
22466 		return BCME_ERROR;
22467 	}
22468 
22469 	return BCME_OK;
22470 }
22471 
22472 int
wl_get_ap_rps(struct net_device * dev,char * command,char * ifname,int total_len)22473 wl_get_ap_rps(struct net_device *dev, char* command, char *ifname, int total_len)
22474 {
22475 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22476 	dhd_pub_t *dhdp;
22477 	int error = BCME_ERROR;
22478 	int bytes_written = 0;
22479 	struct net_device *ndev = NULL;
22480 	rpsnoa_iovar_status_t iovar;
22481 	u8 smbuf[WLC_IOCTL_SMLEN];
22482 	u32 chanspec = 0;
22483 	u8 idx = 0;
22484 	u16 state;
22485 	u32 sleep;
22486 	u32 time_since_enable;
22487 
22488 	dhdp = (dhd_pub_t *)(cfg->pub);
22489 
22490 	if (!dhdp) {
22491 		error = BCME_NOTUP;
22492 		goto fail;
22493 	}
22494 
22495 	if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22496 		WL_ERR(("Not Hostapd mode\n"));
22497 		error = BCME_NOTAP;
22498 		goto fail;
22499 	}
22500 
22501 	ndev = wl_get_ap_netdev(cfg, ifname);
22502 
22503 	if (ndev == NULL) {
22504 		WL_ERR(("No softAP interface named %s\n", ifname));
22505 		error = BCME_NOTAP;
22506 		goto fail;
22507 	}
22508 
22509 	bzero(&iovar, sizeof(iovar));
22510 	bzero(smbuf, sizeof(smbuf));
22511 
22512 	iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
22513 	iovar.hdr.subcmd = WL_RPSNOA_CMD_STATUS;
22514 	iovar.hdr.len = sizeof(iovar);
22515 	iovar.stats->band = WLC_BAND_ALL;
22516 
22517 	error = wldev_iovar_getbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
22518 		smbuf, sizeof(smbuf), NULL);
22519 	if (error < 0) {
22520 		WL_ERR(("get ap radio pwrsave failed = %d\n", error));
22521 		goto fail;
22522 	}
22523 
22524 	/* RSDB event doesn't seem to be handled correctly.
22525 	 * So check chanspec of AP directly from the firmware
22526 	 */
22527 	error = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
22528 	if (error < 0) {
22529 		WL_ERR(("get chanspec from AP failed = %d\n", error));
22530 		goto fail;
22531 	}
22532 
22533 	chanspec = wl_chspec_driver_to_host(chanspec);
22534 	if (CHSPEC_IS2G(chanspec))
22535 		idx = 0;
22536 	else if (CHSPEC_IS5G(chanspec))
22537 		idx = 1;
22538 	else {
22539 		error = BCME_BADCHAN;
22540 		goto fail;
22541 	}
22542 
22543 	state = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].state;
22544 	sleep = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_dur;
22545 	time_since_enable = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_avail_dur;
22546 
22547 	/* Conver ms to minute, round down only */
22548 	sleep = DIV_U64_BY_U32(sleep, MSEC_PER_MIN);
22549 	time_since_enable = DIV_U64_BY_U32(time_since_enable, MSEC_PER_MIN);
22550 
22551 	bytes_written += snprintf(command + bytes_written, total_len,
22552 		"state=%d sleep=%d time_since_enable=%d", state, sleep, time_since_enable);
22553 	error = bytes_written;
22554 
22555 fail:
22556 	return error;
22557 }
22558 
22559 int
wl_set_ap_rps(struct net_device * dev,bool enable,char * ifname)22560 wl_set_ap_rps(struct net_device *dev, bool enable, char *ifname)
22561 {
22562 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22563 	dhd_pub_t *dhdp;
22564 	struct net_device *ndev = NULL;
22565 	rpsnoa_iovar_t iovar;
22566 	u8 smbuf[WLC_IOCTL_SMLEN];
22567 	int ret = BCME_OK;
22568 
22569 	dhdp = (dhd_pub_t *)(cfg->pub);
22570 
22571 	if (!dhdp) {
22572 		ret = BCME_NOTUP;
22573 		goto exit;
22574 	}
22575 
22576 	if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22577 		WL_ERR(("Not Hostapd mode\n"));
22578 		ret = BCME_NOTAP;
22579 		goto exit;
22580 	}
22581 
22582 	ndev = wl_get_ap_netdev(cfg, ifname);
22583 
22584 	if (ndev == NULL) {
22585 		WL_ERR(("No softAP interface named %s\n", ifname));
22586 		ret = BCME_NOTAP;
22587 		goto exit;
22588 	}
22589 
22590 	if (cfg->ap_rps_info.enable != enable) {
22591 		cfg->ap_rps_info.enable = enable;
22592 		if (enable) {
22593 			ret = _wl_update_ap_rps_params(ndev);
22594 			if (ret) {
22595 				WL_ERR(("Filed to update rpsnoa params\n"));
22596 				goto exit;
22597 			}
22598 		}
22599 		bzero(&iovar, sizeof(iovar));
22600 		bzero(smbuf, sizeof(smbuf));
22601 
22602 		iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
22603 		iovar.hdr.subcmd = WL_RPSNOA_CMD_ENABLE;
22604 		iovar.hdr.len = sizeof(iovar);
22605 		iovar.data->band = WLC_BAND_ALL;
22606 		iovar.data->value = (int16)enable;
22607 
22608 		ret = wldev_iovar_setbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
22609 			smbuf, sizeof(smbuf), NULL);
22610 		if (ret) {
22611 			WL_ERR(("Failed to enable AP radio power save"));
22612 			goto exit;
22613 		}
22614 		cfg->ap_rps_info.enable = enable;
22615 	}
22616 exit:
22617 	return ret;
22618 }
22619 
22620 int
wl_update_ap_rps_params(struct net_device * dev,ap_rps_info_t * rps,char * ifname)22621 wl_update_ap_rps_params(struct net_device *dev, ap_rps_info_t* rps, char *ifname)
22622 {
22623 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22624 	dhd_pub_t *dhdp;
22625 	struct net_device *ndev = NULL;
22626 
22627 	dhdp = (dhd_pub_t *)(cfg->pub);
22628 
22629 	if (!dhdp)
22630 		return BCME_NOTUP;
22631 
22632 	if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22633 		WL_ERR(("Not Hostapd mode\n"));
22634 		return BCME_NOTAP;
22635 	}
22636 
22637 	ndev = wl_get_ap_netdev(cfg, ifname);
22638 
22639 	if (ndev == NULL) {
22640 		WL_ERR(("No softAP interface named %s\n", ifname));
22641 		return BCME_NOTAP;
22642 	}
22643 
22644 	if (!rps)
22645 		return BCME_BADARG;
22646 
22647 	if (rps->pps < RADIO_PWRSAVE_PPS_MIN)
22648 		return BCME_BADARG;
22649 
22650 	if (rps->level < RADIO_PWRSAVE_LEVEL_MIN ||
22651 		rps->level > RADIO_PWRSAVE_LEVEL_MAX)
22652 		return BCME_BADARG;
22653 
22654 	if (rps->quiet_time < RADIO_PWRSAVE_QUIETTIME_MIN)
22655 		return BCME_BADARG;
22656 
22657 	if (rps->sta_assoc_check > RADIO_PWRSAVE_ASSOCCHECK_MAX ||
22658 		rps->sta_assoc_check < RADIO_PWRSAVE_ASSOCCHECK_MIN)
22659 		return BCME_BADARG;
22660 
22661 	cfg->ap_rps_info.pps = rps->pps;
22662 	cfg->ap_rps_info.level = rps->level;
22663 	cfg->ap_rps_info.quiet_time = rps->quiet_time;
22664 	cfg->ap_rps_info.sta_assoc_check = rps->sta_assoc_check;
22665 
22666 	if (cfg->ap_rps_info.enable) {
22667 		if (_wl_update_ap_rps_params(ndev)) {
22668 			WL_ERR(("Failed to update rpsnoa params"));
22669 			return BCME_ERROR;
22670 		}
22671 	}
22672 
22673 	return BCME_OK;
22674 }
22675 
22676 void
wl_cfg80211_init_ap_rps(struct bcm_cfg80211 * cfg)22677 wl_cfg80211_init_ap_rps(struct bcm_cfg80211 *cfg)
22678 {
22679 	cfg->ap_rps_info.enable = FALSE;
22680 	cfg->ap_rps_info.sta_assoc_check = RADIO_PWRSAVE_STAS_ASSOC_CHECK;
22681 	cfg->ap_rps_info.pps = RADIO_PWRSAVE_PPS;
22682 	cfg->ap_rps_info.quiet_time = RADIO_PWRSAVE_QUIET_TIME;
22683 	cfg->ap_rps_info.level = RADIO_PWRSAVE_LEVEL;
22684 }
22685 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
22686 
22687 int
wl_cfg80211_iface_count(struct net_device * dev)22688 wl_cfg80211_iface_count(struct net_device *dev)
22689 {
22690 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22691 	struct net_info *iter, *next;
22692 	int iface_count = 0;
22693 
22694 	/* Return the count of network interfaces (skip netless p2p discovery
22695 	 * interface)
22696 	 */
22697 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22698 	for_each_ndev(cfg, iter, next) {
22699 		GCC_DIAGNOSTIC_POP();
22700 		if (iter->ndev) {
22701 			iface_count++;
22702 		}
22703 	}
22704 	return iface_count;
22705 }
22706 
22707 #ifdef SUPPORT_SET_CAC
22708 static void
wl_cfg80211_set_cac(struct bcm_cfg80211 * cfg,int enable)22709 wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable)
22710 {
22711 	int ret = 0;
22712 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22713 
22714 	WL_DBG(("cac enable %d\n", enable));
22715 	if (!dhd) {
22716 		WL_ERR(("dhd is NULL\n"));
22717 		return;
22718 	}
22719 	if ((ret = dhd_wl_ioctl_set_intiovar(dhd, "cac", enable,
22720 			WLC_SET_VAR, TRUE, 0)) < 0) {
22721 		WL_ERR(("Failed set CAC, ret=%d\n", ret));
22722 	} else {
22723 		WL_DBG(("CAC set successfully\n"));
22724 	}
22725 	return;
22726 }
22727 #endif /* SUPPORT_SET_CAC */
22728 
22729 #ifdef SUPPORT_RSSI_SUM_REPORT
22730 int
wl_get_rssi_per_ant(struct net_device * dev,char * ifname,char * peer_mac,void * param)22731 wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void *param)
22732 {
22733 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22734 	wl_rssi_ant_mimo_t *get_param = (wl_rssi_ant_mimo_t *)param;
22735 	rssi_ant_param_t *set_param = NULL;
22736 	struct net_device *ifdev = NULL;
22737 	char iobuf[WLC_IOCTL_SMLEN];
22738 	int err = BCME_OK;
22739 	int iftype = 0;
22740 
22741 	bzero(iobuf, WLC_IOCTL_SMLEN);
22742 
22743 	/* Check the interface type */
22744 	ifdev = wl_get_netdev_by_name(cfg, ifname);
22745 	if (ifdev == NULL) {
22746 		WL_ERR(("Could not find net_device for ifname:%s\n", ifname));
22747 		err = BCME_BADARG;
22748 		goto fail;
22749 	}
22750 
22751 	iftype = ifdev->ieee80211_ptr->iftype;
22752 	if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO) {
22753 		if (peer_mac) {
22754 			set_param = (rssi_ant_param_t *)MALLOCZ(cfg->osh, sizeof(rssi_ant_param_t));
22755 			err = wl_cfg80211_ether_atoe(peer_mac, &set_param->ea);
22756 			if (!err) {
22757 				WL_ERR(("Invalid Peer MAC format\n"));
22758 				err = BCME_BADARG;
22759 				goto fail;
22760 			}
22761 		} else {
22762 			WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype));
22763 			err = BCME_BADARG;
22764 			goto fail;
22765 		}
22766 	}
22767 
22768 	err = wldev_iovar_getbuf(ifdev, "phy_rssi_ant", peer_mac ?
22769 		(void *)&(set_param->ea) : NULL, peer_mac ? ETHER_ADDR_LEN : 0,
22770 		(void *)iobuf, sizeof(iobuf), NULL);
22771 	if (unlikely(err)) {
22772 		WL_ERR(("Failed to get rssi info, err=%d\n", err));
22773 	} else {
22774 		memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t));
22775 		if (get_param->count == 0) {
22776 			WL_ERR(("Not supported on this chip\n"));
22777 			err = BCME_UNSUPPORTED;
22778 		}
22779 	}
22780 
22781 fail:
22782 	if (set_param) {
22783 		MFREE(cfg->osh, set_param, sizeof(rssi_ant_param_t));
22784 	}
22785 
22786 	return err;
22787 }
22788 
22789 int
wl_get_rssi_logging(struct net_device * dev,void * param)22790 wl_get_rssi_logging(struct net_device *dev, void *param)
22791 {
22792 	rssilog_get_param_t *get_param = (rssilog_get_param_t *)param;
22793 	char iobuf[WLC_IOCTL_SMLEN];
22794 	int err = BCME_OK;
22795 
22796 	bzero(iobuf, WLC_IOCTL_SMLEN);
22797 	bzero(get_param, sizeof(*get_param));
22798 	err = wldev_iovar_getbuf(dev, "rssilog", NULL, 0, (void *)iobuf,
22799 		sizeof(iobuf), NULL);
22800 	if (err) {
22801 		WL_ERR(("Failed to get rssi logging info, err=%d\n", err));
22802 	} else {
22803 		memcpy(get_param, iobuf, sizeof(*get_param));
22804 	}
22805 
22806 	return err;
22807 }
22808 
22809 int
wl_set_rssi_logging(struct net_device * dev,void * param)22810 wl_set_rssi_logging(struct net_device *dev, void *param)
22811 {
22812 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22813 	rssilog_set_param_t *set_param = (rssilog_set_param_t *)param;
22814 	int err;
22815 
22816 	err = wldev_iovar_setbuf(dev, "rssilog", set_param,
22817 		sizeof(*set_param), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
22818 		&cfg->ioctl_buf_sync);
22819 	if (err) {
22820 		WL_ERR(("Failed to set rssi logging param, err=%d\n", err));
22821 	}
22822 
22823 	return err;
22824 }
22825 #endif /* SUPPORT_RSSI_SUM_REPORT */
22826 /* Function to flush the FW preserve buffer content
22827 * The buffer content is sent to host in form of events.
22828 */
22829 void
wl_flush_fw_log_buffer(struct net_device * dev,uint32 logset_mask)22830 wl_flush_fw_log_buffer(struct net_device *dev, uint32 logset_mask)
22831 {
22832 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22833 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22834 	int i;
22835 	int err = 0;
22836 	u8 buf[WLC_IOCTL_SMLEN] = {0};
22837 	wl_el_set_params_t set_param;
22838 
22839 	/* Set the size of data to retrieve */
22840 	memset(&set_param, 0, sizeof(set_param));
22841 	set_param.size = WLC_IOCTL_SMLEN;
22842 
22843 	for (i = 0; i < dhd->event_log_max_sets; i++)
22844 	{
22845 		if ((0x01u << i) & logset_mask) {
22846 			set_param.set = i;
22847 			err = wldev_iovar_setbuf(dev, "event_log_get", &set_param,
22848 				sizeof(struct wl_el_set_params_s), buf, WLC_IOCTL_SMLEN,
22849 				NULL);
22850 			if (err) {
22851 				WL_DBG(("Failed to get fw preserve logs, err=%d\n", err));
22852 			}
22853 		}
22854 	}
22855 }
22856 #ifdef USE_WFA_CERT_CONF
22857 extern int g_frameburst;
22858 #endif /* USE_WFA_CERT_CONF */
22859 
22860 int
wl_cfg80211_set_frameburst(struct bcm_cfg80211 * cfg,bool enable)22861 wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable)
22862 {
22863 	int ret = BCME_OK;
22864 	int val = enable ? 1 : 0;
22865 
22866 #ifdef USE_WFA_CERT_CONF
22867 	if (!g_frameburst) {
22868 		WL_DBG(("Skip setting frameburst\n"));
22869 		return 0;
22870 	}
22871 #endif /* USE_WFA_CERT_CONF */
22872 
22873 	WL_DBG(("Set frameburst %d\n", val));
22874 	ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg), WLC_SET_FAKEFRAG, &val, sizeof(val));
22875 	if (ret < 0) {
22876 		WL_ERR(("Failed set frameburst, ret=%d\n", ret));
22877 	} else {
22878 		WL_INFORM_MEM(("frameburst is %s\n", enable ? "enabled" : "disabled"));
22879 	}
22880 
22881 	return ret;
22882 }
22883 
22884 s32
wl_cfg80211_set_dbg_verbose(struct net_device * ndev,u32 level)22885 wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level)
22886 {
22887 	/* configure verbose level for debugging */
22888 	if (level) {
22889 		/* Enable increased verbose */
22890 		wl_dbg_level |= WL_DBG_DBG;
22891 	} else {
22892 		/* Disable */
22893 		wl_dbg_level &= ~WL_DBG_DBG;
22894 	}
22895 	WL_INFORM(("debug verbose set to %d\n", level));
22896 
22897 	return BCME_OK;
22898 }
22899 
22900 const u8 *
wl_find_attribute(const u8 * buf,u16 len,u16 element_id)22901 wl_find_attribute(const u8 *buf, u16 len, u16 element_id)
22902 {
22903 	const u8 *attrib;
22904 	u16 attrib_id;
22905 	u16 attrib_len;
22906 
22907 	if (!buf) {
22908 		WL_ERR(("buf null\n"));
22909 		return NULL;
22910 	}
22911 
22912 	attrib = buf;
22913 	while (len >= 4) {
22914 		/* attribute id */
22915 		attrib_id = *attrib++ << 8;
22916 		attrib_id |= *attrib++;
22917 		len -= 2;
22918 
22919 		/* 2-byte little endian */
22920 		attrib_len = *attrib++ << 8;
22921 		attrib_len |= *attrib++;
22922 
22923 		len -= 2;
22924 		if (attrib_id == element_id) {
22925 			/* This will point to start of subelement attrib after
22926 			 * attribute id & len
22927 			 */
22928 			return attrib;
22929 		}
22930 		if (len > attrib_len) {
22931 			len -= attrib_len;	/* for the remaining subelt fields */
22932 			WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n",
22933 				attrib_id, attrib_len, len));
22934 
22935 			/* Go to next subelement */
22936 			attrib += attrib_len;
22937 		} else {
22938 			WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n",
22939 				attrib_id, attrib_len));
22940 			return NULL;
22941 		}
22942 	}
22943 	return NULL;
22944 }
22945 
wl_cfg80211_get_bus_state(struct bcm_cfg80211 * cfg)22946 uint8 wl_cfg80211_get_bus_state(struct bcm_cfg80211 *cfg)
22947 {
22948 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22949 	WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
22950 			dhd->hang_was_sent, dhd->busstate));
22951 	return ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent);
22952 }
22953 
22954 #ifdef WL_WPS_SYNC
wl_wps_reauth_timeout(unsigned long data)22955 static void wl_wps_reauth_timeout(unsigned long data)
22956 {
22957 	struct net_device *ndev = (struct net_device *)data;
22958 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
22959 	s32 inst;
22960 	unsigned long flags;
22961 
22962 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
22963 	inst = wl_get_wps_inst_match(cfg, ndev);
22964 	if (inst >= 0) {
22965 		WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n",
22966 				ndev->name, inst, cfg->wps_session[inst].state));
22967 		if (cfg->wps_session[inst].state == WPS_STATE_REAUTH_WAIT) {
22968 			/* Session should get deleted from success (linkup) or
22969 			 * deauth case. Just in case, link reassoc failed, clear
22970 			 * state here.
22971 			 */
22972 			WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n",
22973 				ndev->name, inst));
22974 			cfg->wps_session[inst].state = WPS_STATE_IDLE;
22975 			cfg->wps_session[inst].in_use = false;
22976 		}
22977 	}
22978 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
22979 }
22980 
wl_init_wps_reauth_sm(struct bcm_cfg80211 * cfg)22981 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg)
22982 {
22983 	/* Only two instances are supported as of now. one for
22984 	 * infra STA and other for infra STA/GC.
22985 	 */
22986 	int i = 0;
22987 	struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
22988 
22989 	spin_lock_init(&cfg->wps_sync);
22990 	for (i = 0; i < WPS_MAX_SESSIONS; i++) {
22991 		/* Init scan_timeout timer */
22992 		init_timer_compat(&cfg->wps_session[i].timer, wl_wps_reauth_timeout, pdev);
22993 		cfg->wps_session[i].in_use = false;
22994 		cfg->wps_session[i].state = WPS_STATE_IDLE;
22995 	}
22996 }
22997 
wl_deinit_wps_reauth_sm(struct bcm_cfg80211 * cfg)22998 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg)
22999 {
23000 	int i = 0;
23001 
23002 	for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23003 		cfg->wps_session[i].in_use = false;
23004 		cfg->wps_session[i].state = WPS_STATE_IDLE;
23005 		if (timer_pending(&cfg->wps_session[i].timer)) {
23006 			del_timer_sync(&cfg->wps_session[i].timer);
23007 		}
23008 	}
23009 
23010 }
23011 
23012 static s32
wl_get_free_wps_inst(struct bcm_cfg80211 * cfg)23013 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg)
23014 {
23015 	int i;
23016 
23017 	for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23018 		if (!cfg->wps_session[i].in_use) {
23019 			return i;
23020 		}
23021 	}
23022 	return BCME_ERROR;
23023 }
23024 
23025 static s32
wl_get_wps_inst_match(struct bcm_cfg80211 * cfg,struct net_device * ndev)23026 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev)
23027 {
23028 	int i;
23029 
23030 	for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23031 		if ((cfg->wps_session[i].in_use) &&
23032 			(ndev == cfg->wps_session[i].ndev)) {
23033 			return i;
23034 		}
23035 	}
23036 
23037 	return BCME_ERROR;
23038 }
23039 
23040 static s32
wl_wps_session_add(struct net_device * ndev,u16 mode,u8 * mac_addr)23041 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *mac_addr)
23042 {
23043 	s32 inst;
23044 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23045 	unsigned long flags;
23046 
23047 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23048 	/* Fetch and initialize a wps instance */
23049 	inst = wl_get_free_wps_inst(cfg);
23050 	if (inst == BCME_ERROR) {
23051 		WL_ERR(("[WPS] No free insance\n"));
23052 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23053 		return BCME_ERROR;
23054 	}
23055 	cfg->wps_session[inst].in_use = true;
23056 	cfg->wps_session[inst].state = WPS_STATE_STARTED;
23057 	cfg->wps_session[inst].ndev = ndev;
23058 	cfg->wps_session[inst].mode = mode;
23059 	/* return check not required since both buffer lens are same */
23060 	(void)memcpy_s(cfg->wps_session[inst].peer_mac, ETH_ALEN, mac_addr, ETH_ALEN);
23061 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23062 
23063 	WL_INFORM_MEM(("[%s][WPS] session created.  Peer: " MACDBG "\n",
23064 		ndev->name, MAC2STRDBG(mac_addr)));
23065 	return BCME_OK;
23066 }
23067 
23068 static void
wl_wps_session_del(struct net_device * ndev)23069 wl_wps_session_del(struct net_device *ndev)
23070 {
23071 	s32 inst;
23072 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23073 	unsigned long flags;
23074 	u16 cur_state;
23075 
23076 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23077 
23078 	/* Get current instance for the given ndev */
23079 	inst = wl_get_wps_inst_match(cfg, ndev);
23080 	if (inst == BCME_ERROR) {
23081 		WL_DBG(("[WPS] instance match NOT found\n"));
23082 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23083 		return;
23084 	}
23085 
23086 	cur_state = cfg->wps_session[inst].state;
23087 	if (cur_state != WPS_STATE_DONE) {
23088 		WL_DBG(("[WPS] wrong state:%d\n", cur_state));
23089 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23090 		return;
23091 	}
23092 
23093 	/* Mark this as unused */
23094 	cfg->wps_session[inst].in_use = false;
23095 	cfg->wps_session[inst].state = WPS_STATE_IDLE;
23096 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23097 
23098 	/* Ensure this API is called from sleepable context. */
23099 	if (timer_pending(&cfg->wps_session[inst].timer)) {
23100 		del_timer_sync(&cfg->wps_session[inst].timer);
23101 	}
23102 
23103 	WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev->name));
23104 }
23105 
23106 static void
wl_wps_handle_ifdel(struct net_device * ndev)23107 wl_wps_handle_ifdel(struct net_device *ndev)
23108 {
23109 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23110 	unsigned long flags;
23111 	u16 cur_state;
23112 	s32 inst;
23113 
23114 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23115 	inst = wl_get_wps_inst_match(cfg, ndev);
23116 	if (inst == BCME_ERROR) {
23117 		WL_DBG(("[WPS] instance match NOT found\n"));
23118 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23119 		return;
23120 	}
23121 	cur_state = cfg->wps_session[inst].state;
23122 	cfg->wps_session[inst].state = WPS_STATE_DONE;
23123 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23124 
23125 	WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev->name, cur_state));
23126 	if (cur_state > WPS_STATE_IDLE) {
23127 		wl_wps_session_del(ndev);
23128 	}
23129 }
23130 
23131 static s32
wl_wps_handle_sta_linkdown(struct net_device * ndev,u16 inst)23132 wl_wps_handle_sta_linkdown(struct net_device *ndev, u16 inst)
23133 {
23134 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23135 	unsigned long flags;
23136 	u16 cur_state;
23137 	bool wps_done = false;
23138 
23139 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23140 	cur_state = cfg->wps_session[inst].state;
23141 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
23142 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23143 		wl_clr_drv_status(cfg, CONNECTED, ndev);
23144 		wl_clr_drv_status(cfg, DISCONNECTING, ndev);
23145 		WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev->name));
23146 		/* Drop the link down event while we are waiting for reauth */
23147 		return BCME_UNSUPPORTED;
23148 	} else if (cur_state == WPS_STATE_STARTED) {
23149 		/* Link down before reaching EAP-FAIL. End WPS session */
23150 		cfg->wps_session[inst].state = WPS_STATE_DONE;
23151 		wps_done = true;
23152 		WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev->name));
23153 	} else {
23154 		WL_DBG(("[%s][WPS] link down in state:%d\n",
23155 			ndev->name, cur_state));
23156 	}
23157 
23158 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23159 
23160 	if (wps_done) {
23161 		wl_wps_session_del(ndev);
23162 	}
23163 	return BCME_OK;
23164 }
23165 
23166 static s32
wl_wps_handle_peersta_linkdown(struct net_device * ndev,u16 inst,const u8 * peer_mac)23167 wl_wps_handle_peersta_linkdown(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23168 {
23169 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23170 	unsigned long flags;
23171 	u16 cur_state;
23172 	s32 ret = BCME_OK;
23173 	bool wps_done = false;
23174 
23175 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23176 	cur_state = cfg->wps_session[inst].state;
23177 
23178 	if (!peer_mac) {
23179 		WL_ERR(("Invalid arg\n"));
23180 		ret = BCME_ERROR;
23181 		goto exit;
23182 	}
23183 
23184 	/* AP/GO can have multiple clients. so validate peer_mac addr
23185 	 * and ensure states are updated only for right peer.
23186 	 */
23187 	if (memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23188 		/* Mac addr not matching. Ignore. */
23189 		WL_DBG(("[%s][WPS] No active WPS session"
23190 			"for the peer:" MACDBG "\n", ndev->name, MAC2STRDBG(peer_mac)));
23191 		ret = BCME_OK;
23192 		goto exit;
23193 	}
23194 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
23195 		WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
23196 			" Peer: " MACDBG "\n",
23197 			ndev->name, MAC2STRDBG(peer_mac)));
23198 #ifdef NOT_YET
23199 		/* Link down during REAUTH state is expected. However,
23200 		 * if this is send up, hostapd statemachine issues a
23201 		 * deauth down and that may pre-empt WPS reauth state
23202 		 * at GC.
23203 		 */
23204 		WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore."
23205 			" for client:" MACDBG "\n",
23206 			ndev->name, MAC2STRDBG(peer_mac)));
23207 		ret = BCME_UNSUPPORTED;
23208 #endif // endif
23209 	} else if (cur_state == WPS_STATE_STARTED) {
23210 		/* Link down before reaching REAUTH_WAIT state. WPS
23211 		 * session ended.
23212 		 */
23213 		cfg->wps_session[inst].state = WPS_STATE_DONE;
23214 		WL_INFORM_MEM(("[%s][WPS] link down after wps start"
23215 			" client:" MACDBG "\n",
23216 			ndev->name, MAC2STRDBG(peer_mac)));
23217 		wps_done = true;
23218 		/* since we have freed lock above, return from here */
23219 		ret = BCME_OK;
23220 	} else {
23221 		WL_ERR(("[%s][WPS] Unsupported state:%d",
23222 			ndev->name, cur_state));
23223 		ret = BCME_ERROR;
23224 	}
23225 exit:
23226 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23227 	if (wps_done) {
23228 		wl_wps_session_del(ndev);
23229 	}
23230 	return ret;
23231 }
23232 
23233 static s32
wl_wps_handle_sta_linkup(struct net_device * ndev,u16 inst)23234 wl_wps_handle_sta_linkup(struct net_device *ndev, u16 inst)
23235 {
23236 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23237 	unsigned long flags;
23238 	u16 cur_state;
23239 	s32 ret = BCME_OK;
23240 	bool wps_done = false;
23241 
23242 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23243 	cur_state = cfg->wps_session[inst].state;
23244 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
23245 		/* WPS session succeeded. del session. */
23246 		cfg->wps_session[inst].state = WPS_STATE_DONE;
23247 		wps_done = true;
23248 		WL_INFORM_MEM(("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev->name));
23249 		ret = BCME_OK;
23250 	} else {
23251 		WL_ERR(("[%s][WPS] unexpected link up in state:%d \n",
23252 			ndev->name, cur_state));
23253 		ret = BCME_ERROR;
23254 	}
23255 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23256 	if (wps_done) {
23257 		wl_wps_session_del(ndev);
23258 	}
23259 	return ret;
23260 }
23261 
23262 static s32
wl_wps_handle_peersta_linkup(struct net_device * ndev,u16 inst,const u8 * peer_mac)23263 wl_wps_handle_peersta_linkup(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23264 {
23265 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23266 	unsigned long flags;
23267 	u16 cur_state;
23268 	s32 ret = BCME_OK;
23269 
23270 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23271 	cur_state = cfg->wps_session[inst].state;
23272 
23273 	/* For AP case, check whether call came for right peer */
23274 	if (!peer_mac ||
23275 		memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23276 		WL_ERR(("[WPS] macaddr mismatch\n"));
23277 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23278 		/* Mac addr not matching. Ignore. */
23279 		return BCME_ERROR;
23280 	}
23281 
23282 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
23283 		WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev->name));
23284 		ret = BCME_OK;
23285 	} else {
23286 		WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
23287 			ndev->name, cur_state));
23288 		ret = BCME_ERROR;
23289 	}
23290 
23291 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23292 
23293 	return ret;
23294 }
23295 
23296 static s32
wl_wps_handle_authorize(struct net_device * ndev,u16 inst,const u8 * peer_mac)23297 wl_wps_handle_authorize(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23298 {
23299 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23300 	unsigned long flags;
23301 	u16 cur_state;
23302 	bool wps_done = false;
23303 	s32 ret = BCME_OK;
23304 
23305 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23306 	cur_state = cfg->wps_session[inst].state;
23307 
23308 	/* For AP case, check whether call came for right peer */
23309 	if (!peer_mac ||
23310 		memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23311 		WL_ERR(("[WPS] macaddr mismatch\n"));
23312 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23313 		/* Mac addr not matching. Ignore. */
23314 		return BCME_ERROR;
23315 	}
23316 
23317 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
23318 		/* WPS session succeeded. del session. */
23319 		cfg->wps_session[inst].state = WPS_STATE_DONE;
23320 		wps_done = true;
23321 		WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev->name));
23322 		ret = BCME_OK;
23323 	} else {
23324 		WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
23325 			ndev->name, cur_state));
23326 		ret = BCME_ERROR;
23327 	}
23328 
23329 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23330 	if (wps_done) {
23331 		wl_wps_session_del(ndev);
23332 	}
23333 	return ret;
23334 }
23335 
23336 static s32
wl_wps_handle_reauth(struct net_device * ndev,u16 inst,const u8 * peer_mac)23337 wl_wps_handle_reauth(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23338 {
23339 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23340 	unsigned long flags;
23341 	u16 cur_state;
23342 	u16 mode;
23343 	s32 ret = BCME_OK;
23344 
23345 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23346 	cur_state = cfg->wps_session[inst].state;
23347 	mode = cfg->wps_session[inst].mode;
23348 
23349 	if (((mode == WL_MODE_BSS) && (cur_state == WPS_STATE_STARTED)) ||
23350 		((mode == WL_MODE_AP) && (cur_state == WPS_STATE_M8_SENT))) {
23351 		/* Move to reauth wait */
23352 		cfg->wps_session[inst].state = WPS_STATE_REAUTH_WAIT;
23353 		/* Use ndev to find the wps instance which fired the timer */
23354 		timer_set_private(&cfg->wps_session[inst].timer, ndev);
23355 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23356 		mod_timer(&cfg->wps_session[inst].timer,
23357 			jiffies + msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT));
23358 		WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG "\n",
23359 			ndev->name, mode, MAC2STRDBG(peer_mac)));
23360 		return BCME_OK;
23361 	} else {
23362 		/* 802.1x cases */
23363 		WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev->name));
23364 	}
23365 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23366 	return ret;
23367 }
23368 
23369 static s32
wl_wps_handle_disconnect(struct net_device * ndev,u16 inst,const u8 * peer_mac)23370 wl_wps_handle_disconnect(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23371 {
23372 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23373 	unsigned long flags;
23374 	u16 cur_state;
23375 	s32 ret = BCME_OK;
23376 
23377 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23378 	cur_state = cfg->wps_session[inst].state;
23379 	/* If Disconnect command comes from  user space for STA/GC,
23380 	 * respond with event without waiting for event from fw as
23381 	 * it would be dropped by the WPS_SYNC code.
23382 	 */
23383 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
23384 		if (ETHER_ISBCAST(peer_mac)) {
23385 			WL_DBG(("[WPS] Bcast peer. Do nothing.\n"));
23386 		} else {
23387 			/* Notify link down */
23388 			CFG80211_DISCONNECTED(ndev,
23389 				WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
23390 				true, GFP_ATOMIC);
23391 		}
23392 	} else {
23393 		WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
23394 			ndev->name, cur_state));
23395 		ret = BCME_UNSUPPORTED;
23396 	}
23397 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23398 	return ret;
23399 }
23400 
23401 static s32
wl_wps_handle_disconnect_client(struct net_device * ndev,u16 inst,const u8 * peer_mac)23402 wl_wps_handle_disconnect_client(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23403 {
23404 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23405 	unsigned long flags;
23406 	u16 cur_state;
23407 	s32 ret = BCME_OK;
23408 	bool wps_done = false;
23409 
23410 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23411 	cur_state = cfg->wps_session[inst].state;
23412 	/* For GO/AP, ignore disconnect client during reauth state */
23413 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
23414 		if (ETHER_ISBCAST(peer_mac)) {
23415 			/* If there is broadcast deauth, then mark wps session as ended */
23416 			cfg->wps_session[inst].state = WPS_STATE_DONE;
23417 			wps_done = true;
23418 			WL_INFORM_MEM(("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev->name));
23419 			ret = BCME_OK;
23420 			goto exit;
23421 		} else if (!(memcmp(cfg->wps_session[inst].peer_mac,
23422 			peer_mac, ETH_ALEN))) {
23423 			WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev->name));
23424 			ret = BCME_UNSUPPORTED;
23425 		}
23426 	}
23427 
23428 exit:
23429 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23430 	if (wps_done) {
23431 		wl_wps_session_del(ndev);
23432 	}
23433 	return ret;
23434 }
23435 
23436 static s32
wl_wps_handle_connect_fail(struct net_device * ndev,u16 inst)23437 wl_wps_handle_connect_fail(struct net_device *ndev, u16 inst)
23438 {
23439 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23440 	unsigned long flags;
23441 	u16 cur_state;
23442 	bool wps_done = false;
23443 
23444 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23445 	cur_state = cfg->wps_session[inst].state;
23446 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
23447 		cfg->wps_session[inst].state = WPS_STATE_DONE;
23448 		wps_done = true;
23449 		WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n",
23450 			ndev->name));
23451 	} else {
23452 		WL_ERR(("[%s][WPS] Connect fail. state:%d\n",
23453 			ndev->name, cur_state));
23454 	}
23455 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23456 	if (wps_done) {
23457 		wl_wps_session_del(ndev);
23458 	}
23459 	return BCME_OK;
23460 }
23461 
23462 static s32
wl_wps_handle_m8_sent(struct net_device * ndev,u16 inst,const u8 * peer_mac)23463 wl_wps_handle_m8_sent(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23464 {
23465 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23466 	unsigned long flags;
23467 	u16 cur_state;
23468 	s32 ret = BCME_OK;
23469 
23470 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23471 	cur_state = cfg->wps_session[inst].state;
23472 
23473 	if (cur_state == WPS_STATE_STARTED) {
23474 		/* Move to M8 sent state */
23475 		cfg->wps_session[inst].state = WPS_STATE_M8_SENT;
23476 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23477 		return BCME_OK;
23478 	} else {
23479 		/* 802.1x cases */
23480 		WL_DBG(("[%s][WPS] Not valid state to send M8\n", ndev->name));
23481 	}
23482 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23483 	return ret;
23484 }
23485 
23486 static s32
wl_wps_session_update(struct net_device * ndev,u16 state,const u8 * peer_mac)23487 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac)
23488 {
23489 	s32 inst;
23490 	u16 mode;
23491 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23492 	s32 ret = BCME_ERROR;
23493 	unsigned long flags;
23494 
23495 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23496 	/* Get current instance for the given ndev */
23497 	inst = wl_get_wps_inst_match(cfg, ndev);
23498 	if (inst == BCME_ERROR) {
23499 		/* No active WPS session. Do Nothing. */
23500 		WL_DBG(("[%s][WPS] No matching instance.\n", ndev->name));
23501 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23502 		return BCME_NOTFOUND;
23503 	}
23504 	mode = cfg->wps_session[inst].mode;
23505 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23506 
23507 	WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG "\n",
23508 		ndev->name, state, mode, MAC2STRDBG(peer_mac)));
23509 
23510 	switch (state) {
23511 		case WPS_STATE_M8_RECVD:
23512 		{
23513 			/* Occasionally, due to race condition between ctrl
23514 			 * and data path, deauth ind is recvd before EAP-FAIL.
23515 			 * Ignore deauth ind before EAP-FAIL
23516 			 * So move to REAUTH WAIT on receiving M8 on GC and
23517 			 * ignore deauth ind before EAP-FAIL till 'x' timeout.
23518 			 * Kickoff a timer to monitor reauth status.
23519 			 */
23520 			if (mode == WL_MODE_BSS) {
23521 				ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
23522 			} else {
23523 				/* Nothing to be done for AP/GO mode */
23524 				ret = BCME_OK;
23525 			}
23526 			break;
23527 		}
23528 		case WPS_STATE_M8_SENT:
23529 		{
23530 			/* Mantain the M8 sent state to verify
23531 			 * EAP-FAIL sent is valid
23532 			 */
23533 			if (mode == WL_MODE_AP) {
23534 				ret = wl_wps_handle_m8_sent(ndev, inst, peer_mac);
23535 			} else {
23536 				/* Nothing to be done for STA/GC mode */
23537 				ret = BCME_OK;
23538 			}
23539 			break;
23540 		}
23541 		case WPS_STATE_EAP_FAIL:
23542 		{
23543 			/* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
23544 			 * Kickoff a timer to monitor reauth status
23545 			 */
23546 			if (mode == WL_MODE_AP) {
23547 				ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
23548 			} else {
23549 				/* Nothing to be done for STA/GC mode */
23550 				ret = BCME_OK;
23551 			}
23552 			break;
23553 		}
23554 		case WPS_STATE_LINKDOWN:
23555 		{
23556 			if (mode == WL_MODE_BSS) {
23557 				ret = wl_wps_handle_sta_linkdown(ndev, inst);
23558 			} else if (mode == WL_MODE_AP) {
23559 				/* Take action only for matching peer mac */
23560 				if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23561 					ret = wl_wps_handle_peersta_linkdown(ndev, inst, peer_mac);
23562 				}
23563 			}
23564 			break;
23565 		}
23566 		case WPS_STATE_LINKUP:
23567 		{
23568 			if (mode == WL_MODE_BSS) {
23569 				wl_wps_handle_sta_linkup(ndev, inst);
23570 			} else if (mode == WL_MODE_AP) {
23571 				/* Take action only for matching peer mac */
23572 				if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23573 					wl_wps_handle_peersta_linkup(ndev, inst, peer_mac);
23574 				}
23575 			}
23576 			break;
23577 		}
23578 		case WPS_STATE_DISCONNECT_CLIENT:
23579 		{
23580 			/* Disconnect STA/GC command from user space */
23581 			if (mode == WL_MODE_AP) {
23582 				ret = wl_wps_handle_disconnect_client(ndev, inst, peer_mac);
23583 			} else {
23584 				WL_ERR(("[WPS] Unsupported mode %d\n", mode));
23585 			}
23586 			break;
23587 		}
23588 		case WPS_STATE_DISCONNECT:
23589 		{
23590 			/* Disconnect command on STA/GC interface */
23591 			if (mode == WL_MODE_BSS) {
23592 				ret = wl_wps_handle_disconnect(ndev, inst, peer_mac);
23593 			}
23594 			break;
23595 		}
23596 		case WPS_STATE_CONNECT_FAIL:
23597 		{
23598 			if (mode == WL_MODE_BSS) {
23599 				ret = wl_wps_handle_connect_fail(ndev, inst);
23600 			} else {
23601 				WL_ERR(("[WPS] Unsupported mode %d\n", mode));
23602 			}
23603 			break;
23604 		}
23605 		case WPS_STATE_AUTHORIZE:
23606 		{
23607 			if (mode == WL_MODE_AP) {
23608 				/* Take action only for matching peer mac */
23609 				if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23610 					wl_wps_handle_authorize(ndev, inst, peer_mac);
23611 				} else {
23612 					WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
23613 				}
23614 			}
23615 			break;
23616 		}
23617 
23618 	default:
23619 		WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state, mode));
23620 		ret = BCME_ERROR;
23621 	}
23622 
23623 	return ret;
23624 }
23625 
23626 #define EAP_EXP_ATTRIB_DATA_OFFSET 14
23627 void
wl_handle_wps_states(struct net_device * ndev,u8 * pkt,u16 len,bool direction)23628 wl_handle_wps_states(struct net_device *ndev, u8 *pkt, u16 len, bool direction)
23629 {
23630 	eapol_header_t *eapol_hdr;
23631 	bool tx_packet = direction;
23632 	u16 eapol_type;
23633 	u16 mode;
23634 	u8 *peer_mac;
23635 
23636 	if (!ndev || !pkt) {
23637 		WL_ERR(("[WPS] Invalid arg\n"));
23638 		return;
23639 	}
23640 
23641 	if (len < (ETHER_HDR_LEN + EAPOL_HDR_LEN)) {
23642 		WL_ERR(("[WPS] Invalid len\n"));
23643 		return;
23644 	}
23645 
23646 	eapol_hdr = (eapol_header_t *)pkt;
23647 	eapol_type = eapol_hdr->type;
23648 
23649 	peer_mac = tx_packet ? eapol_hdr->eth.ether_dhost :
23650 			eapol_hdr->eth.ether_shost;
23651 	/*
23652 	 * The implementation assumes only one WPS session would be active
23653 	 * per interface at a time. Even for hostap, the wps_pin session
23654 	 * is limited to one enrollee/client at a time. A session is marked
23655 	 * started on WSC_START and gets cleared from below contexts
23656 	 * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
23657 	 * b) Link up following EAP-FAIL. (success case)
23658 	 * c) Link up timeout after EAP-FAIL. (Fail case)
23659 	 */
23660 
23661 	if (eapol_type == EAP_PACKET) {
23662 		wl_eap_header_t *eap;
23663 
23664 		if (len > sizeof(*eap)) {
23665 			eap = (wl_eap_header_t *)(pkt + ETHER_HDR_LEN + EAPOL_HDR_LEN);
23666 			if (eap->type == EAP_EXPANDED_TYPE) {
23667 				wl_eap_exp_t *exp = (wl_eap_exp_t *)eap->data;
23668 				if (eap->length > EAP_EXP_HDR_MIN_LENGTH) {
23669 					/* opcode is at fixed offset */
23670 					u8 opcode = exp->opcode;
23671 					u16 eap_len = ntoh16(eap->length);
23672 
23673 					WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
23674 						ndev->name, opcode, eap_len));
23675 					if (opcode == EAP_WSC_MSG) {
23676 						const u8 *msg;
23677 						const u8* parse_buf = exp->data;
23678 						/* Check if recvd pkt is fragmented */
23679 						if ((!tx_packet) &&
23680 							(exp->flags &
23681 							EAP_EXP_FLAGS_FRAGMENTED_DATA)) {
23682 							if ((eap_len - EAP_EXP_ATTRIB_DATA_OFFSET)
23683 							> 2) {
23684 								parse_buf +=
23685 								EAP_EXP_FRAGMENT_LEN_OFFSET;
23686 								eap_len -=
23687 								EAP_EXP_FRAGMENT_LEN_OFFSET;
23688 								WL_DBG(("Rcvd EAP"
23689 								" fragmented pkt\n"));
23690 							} else {
23691 								/* If recvd pkt is fragmented
23692 								* and does not have
23693 								* length field drop the packet.
23694 								*/
23695 								return;
23696 							}
23697 						}
23698 
23699 						msg = wl_find_attribute(parse_buf,
23700 							(eap_len - EAP_EXP_ATTRIB_DATA_OFFSET),
23701 							EAP_ATTRIB_MSGTYPE);
23702 						if (unlikely(!msg)) {
23703 							WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
23704 						} else if ((*msg == EAP_WSC_MSG_M8) &&
23705 								!tx_packet) {
23706 							WL_INFORM_MEM(("[%s][WPS] M8\n",
23707 								ndev->name));
23708 							wl_wps_session_update(ndev,
23709 								WPS_STATE_M8_RECVD, peer_mac);
23710 						} else if ((*msg == EAP_WSC_MSG_M8) &&
23711 								tx_packet) {
23712 							WL_INFORM_MEM(("[%s][WPS] M8 Sent\n",
23713 								ndev->name));
23714 							wl_wps_session_update(ndev,
23715 								WPS_STATE_M8_SENT, peer_mac);
23716 						} else {
23717 							WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n",
23718 								ndev->name, *msg));
23719 						}
23720 					} else if (opcode == EAP_WSC_START) {
23721 						/* WSC session started. WSC_START - Tx from GO/AP.
23722 						 * Session will be deleted on successful link up or
23723 						 * on failure (deauth context)
23724 						 */
23725 						mode = tx_packet ? WL_MODE_AP : WL_MODE_BSS;
23726 						wl_wps_session_add(ndev, mode, peer_mac);
23727 						WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
23728 							ndev->name, mode));
23729 					} else if (opcode == EAP_WSC_DONE) {
23730 						/* WSC session done. TX on STA/GC. RX on GO/AP
23731 						 * On devices where config file save fails, it may
23732 						 * return WPS_NAK with config_error:0. But the
23733 						 * connection would still proceed. Hence don't let
23734 						 * state machine depend on WSC DONE.
23735 						 */
23736 						WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev->name));
23737 					}
23738 				}
23739 			}
23740 
23741 			if (eap->code == EAP_CODE_FAILURE) {
23742 				/* EAP_FAIL */
23743 				WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev->name));
23744 				wl_wps_session_update(ndev,
23745 					WPS_STATE_EAP_FAIL, peer_mac);
23746 			}
23747 		}
23748 	}
23749 }
23750 #endif /* WL_WPS_SYNC */
23751 
23752 s32
wl_cfg80211_sup_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * event,void * data)23753 wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23754 	const wl_event_msg_t *event, void *data)
23755 {
23756 	int err = BCME_OK;
23757 	u32 status = ntoh32(event->status);
23758 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
23759 	u32 reason = ntoh32(event->reason);
23760 
23761 	if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
23762 		/* Join attempt via non-cfg80211 interface.
23763 		 * Don't send resultant events to cfg80211
23764 		 * layer
23765 		 */
23766 		WL_INFORM_MEM(("Event received in non-cfg80211"
23767 			" connect state. Ignore\n"));
23768 		return BCME_OK;
23769 	}
23770 
23771 	if ((status == WLC_SUP_KEYED || status == WLC_SUP_KEYXCHANGE_WAIT_G1) &&
23772 	    reason == WLC_E_SUP_OTHER) {
23773 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
23774 		/* NL80211_CMD_PORT_AUTHORIZED supported above >= 4.15 */
23775 		cfg80211_port_authorized(ndev, (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID),
23776 			GFP_KERNEL);
23777 		WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
23778 #elif ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
23779 	defined(WL_VENDOR_EXT_SUPPORT))
23780 		err = wl_cfgvendor_send_async_event(bcmcfg_to_wiphy(cfg), ndev,
23781 			BRCM_VENDOR_EVENT_PORT_AUTHORIZED, NULL, 0);
23782 		WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
23783 #else
23784 		/* not supported in kernel <= 3,14,0 */
23785 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */
23786 	} else if (status < WLC_SUP_KEYXCHANGE_WAIT_G1 && (reason != WLC_E_SUP_OTHER &&
23787 		reason != WLC_E_SUP_PTK_UPDATE)) {
23788 		/* if any failure seen while 4way HS, should send NL80211_CMD_DISCONNECT */
23789 		WL_ERR(("4way HS error. status:%d, reason:%d\n", status, reason));
23790 		CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
23791 	}
23792 
23793 	return err;
23794 }
23795 
23796 #ifdef WL_BCNRECV
23797 static s32
wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23798 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23799 		const wl_event_msg_t *e, void *data)
23800 {
23801 	s32 status = ntoh32(e->status);
23802 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
23803 	/* Abort fakeapscan, when Roam is in progress */
23804 	if (status == WLC_E_STATUS_RXBCN_ABORT) {
23805 		wl_android_bcnrecv_stop(ndev, WL_BCNRECV_ROAMABORT);
23806 	} else {
23807 		WL_ERR(("UNKNOWN STATUS. status:%d\n", status));
23808 	}
23809 	return BCME_OK;
23810 }
23811 #endif /* WL_BCNRECV */
23812 
23813 #ifdef WL_MBO
23814 static s32
wl_mbo_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23815 wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23816 	const wl_event_msg_t *e, void *data)
23817 {
23818 	s32 err = 0;
23819 	wl_event_mbo_t *mbo_evt = (wl_event_mbo_t *)data;
23820 	wl_event_mbo_cell_nw_switch_t *cell_sw_evt = NULL;
23821 	wl_btm_event_type_data_t *evt_data = NULL;
23822 
23823 	WL_INFORM(("MBO: Evt %u\n", mbo_evt->type));
23824 
23825 	if (mbo_evt->type == WL_MBO_E_CELLULAR_NW_SWITCH) {
23826 		cell_sw_evt = (wl_event_mbo_cell_nw_switch_t *)mbo_evt->data;
23827 		BCM_REFERENCE(cell_sw_evt);
23828 		SUPP_EVENT(("CTRL-EVENT-CELLULAR-SWITCH", "reason %d cur_assoc_time_left %u "
23829 			"reassoc_delay %u\n", cell_sw_evt->reason,
23830 			cell_sw_evt->assoc_time_remain, cell_sw_evt->reassoc_delay));
23831 	} else if (mbo_evt->type == WL_MBO_E_BTM_RCVD) {
23832 		evt_data = (wl_btm_event_type_data_t *)mbo_evt->data;
23833 		if (evt_data->version != WL_BTM_EVENT_DATA_VER_1) {
23834 			WL_ERR(("version mismatch. rcvd %u expected %u\n",
23835 				evt_data->version, WL_BTM_EVENT_DATA_VER_1));
23836 				return -1;
23837 		}
23838 		SUPP_EVENT(("CTRL-EVENT-BRCM-BTM-REQ-RCVD", "reason=%u\n",
23839 			evt_data->transition_reason));
23840 	} else {
23841 		WL_INFORM(("UNKNOWN EVENT. type:%u\n", mbo_evt->type));
23842 	}
23843 	return err;
23844 }
23845 #endif /* WL_MBO */
23846 
23847 #ifdef WL_CAC_TS
23848 static s32
wl_cfg80211_cac_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23849 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23850 		const wl_event_msg_t *e, void *data)
23851 {
23852 	u32 event = ntoh32(e->event_type);
23853 	s32 status = ntoh32(e->status);
23854 	s32 reason = ntoh32(e->reason);
23855 
23856 	BCM_REFERENCE(reason);
23857 
23858 	if (event == WLC_E_ADDTS_IND) {
23859 		/* The supp log format of adding ts_delay in success case needs to be maintained */
23860 		if (status == WLC_E_STATUS_SUCCESS) {
23861 			uint *ts_delay = (uint *)data;
23862 			BCM_REFERENCE(ts_delay);
23863 			SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d ts_delay=%u\n",
23864 				status, reason, *ts_delay));
23865 		} else {
23866 			SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d\n",
23867 				status, reason));
23868 		}
23869 	} else if (event == WLC_E_DELTS_IND) {
23870 		SUPP_EVENT(("CTRL-EVENT-CAC-DELTS", "status=%d reason=%d\n", status, reason));
23871 	}
23872 
23873 	return BCME_OK;
23874 }
23875 #endif /* WL_CAC_TS */
23876 
23877 #if defined(WL_MBO) || defined(WL_OCE)
23878 static s32
wl_bssid_prune_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23879 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23880 	const wl_event_msg_t *e, void *data)
23881 {
23882 	s32 err = 0;
23883 	uint reason = 0;
23884 	wl_bssid_pruned_evt_info_t *evt_info = (wl_bssid_pruned_evt_info_t *)data;
23885 
23886 	if (evt_info->version == WL_BSSID_PRUNE_EVT_VER_1) {
23887 		if (evt_info->reason == WLC_E_PRUNE_ASSOC_RETRY_DELAY) {
23888 			/* MBO assoc retry delay */
23889 			reason = WIFI_PRUNE_ASSOC_RETRY_DELAY;
23890 			SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
23891 				" reason=%u timeout_val=%u(ms)\n", evt_info->SSID,
23892 				ETHER_TO_MACF(evt_info->BSSID),	reason, evt_info->time_remaining));
23893 		} else if (evt_info->reason == WLC_E_PRUNE_RSSI_ASSOC_REJ) {
23894 			/* OCE RSSI-based assoc rejection */
23895 			reason = WIFI_PRUNE_RSSI_ASSOC_REJ;
23896 			SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
23897 				" reason=%u timeout_val=%u(ms) rssi_threshold=%d(dBm)\n",
23898 				evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID),
23899 				reason, evt_info->time_remaining, evt_info->rssi_threshold));
23900 		} else {
23901 			/* Invalid other than the assoc retry delay/RSSI assoc rejection
23902 			 * in the current handler
23903 			 */
23904 			BCM_REFERENCE(reason);
23905 			WL_INFORM(("INVALID. reason:%u\n", evt_info->reason));
23906 		}
23907 	} else {
23908 		WL_INFORM(("version mismatch. rcvd %u expected %u\n", evt_info->version,
23909 			WL_BSSID_PRUNE_EVT_VER_1));
23910 	}
23911 	return err;
23912 }
23913 #endif /* WL_MBO || WL_OCE */
23914 #ifdef RTT_SUPPORT
23915 static s32
wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23916 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23917 		const wl_event_msg_t *e, void *data)
23918 {
23919 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
23920 	wl_event_msg_t event;
23921 
23922 	(void)memcpy_s(&event, sizeof(wl_event_msg_t),
23923 		e, sizeof(wl_event_msg_t));
23924 	return dhd_rtt_event_handler(dhdp, &event, data);
23925 }
23926 #endif /* RTT_SUPPORT */
23927 
23928 void
wl_print_verinfo(struct bcm_cfg80211 * cfg)23929 wl_print_verinfo(struct bcm_cfg80211 *cfg)
23930 {
23931 	char *ver_ptr;
23932 	uint32 alloc_len = MOD_PARAM_INFOLEN;
23933 
23934 	if (!cfg) {
23935 		WL_ERR(("cfg is NULL\n"));
23936 		return;
23937 	}
23938 
23939 	ver_ptr = (char *)MALLOCZ(cfg->osh, alloc_len);
23940 	if (!ver_ptr) {
23941 		WL_ERR(("Failed to alloc ver_ptr\n"));
23942 		return;
23943 	}
23944 
23945 	if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
23946 		TRUE, &ver_ptr, alloc_len)) {
23947 		WL_ERR(("DHD Version: %s\n", ver_ptr));
23948 	}
23949 
23950 	if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
23951 		FALSE, &ver_ptr, alloc_len)) {
23952 		WL_ERR(("F/W Version: %s\n", ver_ptr));
23953 	}
23954 
23955 	MFREE(cfg->osh, ver_ptr, alloc_len);
23956 }
23957 #if defined(WL_DISABLE_HE_SOFTAP) || defined(WL_DISABLE_HE_P2P)
23958 typedef struct {
23959 	uint16 id;
23960 	uint16 len;
23961 	uint32 val;
23962 } he_xtlv_v32;
23963 
23964 	static bool
wl_he_get_uint_cb(void * ctx,uint16 * id,uint16 * len)23965 wl_he_get_uint_cb(void *ctx, uint16 *id, uint16 *len)
23966 {
23967 	he_xtlv_v32 *v32 = ctx;
23968 
23969 	*id = v32->id;
23970 	*len = v32->len;
23971 
23972 	return FALSE;
23973 }
23974 
23975 	static void
wl_he_pack_uint_cb(void * ctx,uint16 id,uint16 len,uint8 * buf)23976 wl_he_pack_uint_cb(void *ctx, uint16 id, uint16 len, uint8 *buf)
23977 {
23978 	he_xtlv_v32 *v32 = ctx;
23979 
23980 	BCM_REFERENCE(id);
23981 	BCM_REFERENCE(len);
23982 
23983 	v32->val = htod32(v32->val);
23984 
23985 	switch (v32->len) {
23986 		case sizeof(uint8):
23987 			*buf = (uint8)v32->val;
23988 			break;
23989 		case sizeof(uint16):
23990 			store16_ua(buf, (uint16)v32->val);
23991 			break;
23992 		case sizeof(uint32):
23993 			store32_ua(buf, v32->val);
23994 			break;
23995 		default:
23996 			/* ASSERT(0); */
23997 			break;
23998 	}
23999 }
24000 
wl_cfg80211_set_he_mode(struct net_device * dev,struct bcm_cfg80211 * cfg,s32 bssidx,u32 interface_type,bool set)24001 int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg,
24002 		s32 bssidx, u32 interface_type, bool set)
24003 {
24004 	bcm_xtlv_t read_he_xtlv;
24005 	uint8 se_he_xtlv[32];
24006 	int se_he_xtlv_len = sizeof(se_he_xtlv);
24007 	he_xtlv_v32 v32;
24008 	u32 he_feature = 0;
24009 	s32 err = 0;
24010 	u32 he_interface = 0;
24011 
24012 	read_he_xtlv.id = WL_HE_CMD_FEATURES;
24013 	read_he_xtlv.len = 0;
24014 	err = wldev_iovar_getbuf_bsscfg(dev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
24015 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, NULL);
24016 	if (err < 0) {
24017 		if (err == BCME_UNSUPPORTED) {
24018 			/* HE not supported. Do nothing. */
24019 			return BCME_OK;
24020 		}
24021 		WL_ERR(("HE get failed. error=%d\n", err));
24022 	} else {
24023 		he_feature =  *(int*)cfg->ioctl_buf;
24024 		he_feature = dtoh32(he_feature);
24025 	}
24026 
24027 	v32.id = WL_HE_CMD_FEATURES;
24028 	v32.len = sizeof(s32);
24029 	if (interface_type == WL_IF_TYPE_P2P_DISC) {
24030 		he_interface = WL_HE_FEATURES_HE_P2P;
24031 	} else if (interface_type == WL_IF_TYPE_AP) {
24032 		he_interface = WL_HE_FEATURES_HE_AP;
24033 	} else {
24034 		WL_ERR(("HE request for Invalid interface type"));
24035 		err = BCME_BADARG;
24036 		return err;
24037 	}
24038 
24039 	if (set) {
24040 		v32.val = (he_feature | he_interface);
24041 	} else {
24042 		v32.val = (he_feature & ~he_interface);
24043 	}
24044 
24045 	err = bcm_pack_xtlv_buf((void *)&v32, se_he_xtlv, sizeof(se_he_xtlv),
24046 			BCM_XTLV_OPTION_ALIGN32, wl_he_get_uint_cb, wl_he_pack_uint_cb,
24047 			&se_he_xtlv_len);
24048 	if (err != BCME_OK) {
24049 		WL_ERR(("failed to pack he settvl=%d\n", err));
24050 	}
24051 
24052 	err = wldev_iovar_setbuf_bsscfg(dev, "he", &se_he_xtlv, sizeof(se_he_xtlv),
24053 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
24054 	if (err < 0) {
24055 		WL_ERR(("failed to set he features, error=%d\n", err));
24056 	}
24057 	WL_INFORM(("Set HE[%d] done\n", set));
24058 
24059 	return err;
24060 }
24061 #endif /* WL_DISABLE_HE_SOFTAP || WL_DISABLE_HE_P2P */
24062 
24063 /* Get the concurrency mode */
wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 * cfg)24064 int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg)
24065 {
24066 	struct net_info *iter, *next;
24067 	uint cmode = CONCURRENCY_MODE_NONE;
24068 	u32 connected_cnt = 0;
24069 	u32 pre_channel = 0, channel = 0;
24070 	u32 pre_band = 0;
24071 	u32 chanspec = 0;
24072 	u32 band = 0;
24073 
24074 	connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
24075 	if (connected_cnt <= 1) {
24076 		return cmode;
24077 	}
24078 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
24079 	for_each_ndev(cfg, iter, next) {
24080 		if (iter->ndev) {
24081 			if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
24082 				if (wldev_iovar_getint(iter->ndev, "chanspec",
24083 					(s32 *)&chanspec) == BCME_OK) {
24084 					channel = wf_chspec_ctlchan(
24085 						wl_chspec_driver_to_host(chanspec));
24086 					band = (channel <= CH_MAX_2G_CHANNEL) ?
24087 						IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
24088 				}
24089 				if ((!pre_channel && channel)) {
24090 					pre_band = band;
24091 					pre_channel = channel;
24092 				} else if (pre_channel) {
24093 					if ((pre_band == band) && (pre_channel == channel)) {
24094 						cmode = CONCURRENCY_SCC_MODE;
24095 						goto exit;
24096 					} else if ((pre_band == band) && (pre_channel != channel)) {
24097 						cmode = CONCURRENCY_VSDB_MODE;
24098 						goto exit;
24099 					} else if (pre_band != band) {
24100 						cmode = CONCURRENCY_RSDB_MODE;
24101 						goto exit;
24102 					}
24103 				}
24104 			}
24105 		}
24106 	}
24107 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
24108 	4 && __GNUC_MINOR__ >= 6))
24109 _Pragma("GCC diagnostic pop")
24110 #endif // endif
24111 exit:
24112 	return cmode;
24113 }
24114 #ifdef WL_CHAN_UTIL
24115 static s32
wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)24116 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
24117 		const wl_event_msg_t *e, void *data)
24118 {
24119 	s32 err = BCME_OK;
24120 	struct sk_buff *skb = NULL;
24121 	s32 status = ntoh32(e->status);
24122 	u8 chan_use_percentage = 0;
24123 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
24124 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
24125 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
24126 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
24127 			/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
24128 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24129 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
24130 	uint len;
24131 	gfp_t kflags;
24132 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24133 
24134 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24135 	len = CU_ATTR_HDR_LEN + sizeof(u8);
24136 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
24137 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24138 
24139 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
24140 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
24141 	skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), len,
24142 		BRCM_VENDOR_EVENT_CU, kflags);
24143 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24144 	skb = cfg80211_vendor_event_alloc(wiphy, len, BRCM_VENDOR_EVENT_CU, kflags);
24145 #else
24146 	/* No support exist */
24147 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
24148 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
24149 	if (!skb) {
24150 		WL_ERR(("skb alloc failed"));
24151 		return -ENOMEM;
24152 	}
24153 
24154 	if ((status == WLC_E_STATUS_SUCCESS) && data) {
24155 		wl_bssload_t *bssload_report = (wl_bssload_t *)data;
24156 		chan_use_percentage = (bssload_report->chan_util * 100) / 255;
24157 		WL_DBG(("ChannelUtilization=%hhu\n", chan_use_percentage));
24158 		err = nla_put_u8(skb, CU_ATTR_PERCENTAGE, chan_use_percentage);
24159 		if (err < 0) {
24160 			WL_ERR(("Failed to put CU_ATTR_PERCENTAGE, err:%d\n", err));
24161 		}
24162 	}
24163 
24164 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24165 	cfg80211_vendor_event(skb, kflags);
24166 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24167 
24168 	return err;
24169 }
24170 
24171 #define WL_CHAN_UTIL_DEFAULT_INTERVAL	3000
24172 #define WL_CHAN_UTIL_THRESH_MIN		15
24173 #define WL_CHAN_UTIL_THRESH_INTERVAL	10
24174 #ifndef CUSTOM_CU_INTERVAL
24175 #define CUSTOM_CU_INTERVAL WL_CHAN_UTIL_DEFAULT_INTERVAL
24176 #endif /* CUSTOM_CU_INTERVAL */
24177 
24178 static s32
wl_cfg80211_start_bssload_report(struct net_device * ndev)24179 wl_cfg80211_start_bssload_report(struct net_device *ndev)
24180 {
24181 	s32 err = BCME_OK;
24182 	wl_bssload_cfg_t blcfg;
24183 	u8 i;
24184 	struct bcm_cfg80211 *cfg;
24185 
24186 	if (!ndev) {
24187 		return -ENODEV;
24188 	}
24189 
24190 	cfg = wl_get_cfg(ndev);
24191 	if (!cfg) {
24192 		return -ENODEV;
24193 	}
24194 
24195 	/* Typecasting to void as the buffer size is same as the memset size */
24196 	(void)memset_s(&blcfg, sizeof(wl_bssload_cfg_t), 0, sizeof(wl_bssload_cfg_t));
24197 	/* Set default report interval 3 sec and 8 threshhold levels between 15 to 85% */
24198 	blcfg.rate_limit_msec = CUSTOM_CU_INTERVAL;
24199 	blcfg.num_util_levels = MAX_BSSLOAD_LEVELS;
24200 	for (i = 0; i < MAX_BSSLOAD_LEVELS; i++) {
24201 		blcfg.util_levels[i] = (((WL_CHAN_UTIL_THRESH_MIN +
24202 			(i * WL_CHAN_UTIL_THRESH_INTERVAL)) * 255) / 100);
24203 	}
24204 
24205 	err = wldev_iovar_setbuf(ndev, "bssload_report_event", &blcfg,
24206 		sizeof(wl_bssload_cfg_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
24207 	if (unlikely(err)) {
24208 		WL_ERR(("Set event_msgs error (%d)\n", err));
24209 	}
24210 
24211 	return err;
24212 }
24213 #endif /* WL_CHAN_UTIL */
24214 
24215 s32
wl_cfg80211_config_suspend_events(struct net_device * ndev,bool enable)24216 wl_cfg80211_config_suspend_events(struct net_device *ndev, bool enable)
24217 {
24218 	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
24219 	s8 eventmask[WL_EVENTING_MASK_LEN];
24220 	s32 err = 0;
24221 	struct bcm_cfg80211 *cfg;
24222 
24223 	if (!ndev) {
24224 		return -ENODEV;
24225 	}
24226 
24227 	cfg = wl_get_cfg(ndev);
24228 	if (!cfg) {
24229 		return -ENODEV;
24230 	}
24231 
24232 	mutex_lock(&cfg->event_sync);
24233 	err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
24234 	if (unlikely(err)) {
24235 		WL_ERR(("Get event_msgs error (%d)\n", err));
24236 		goto eventmsg_out;
24237 	}
24238 
24239 	(void)memcpy_s(eventmask, WL_EVENTING_MASK_LEN, iovbuf, WL_EVENTING_MASK_LEN);
24240 	/* Add set/clear of event mask under feature specific flags */
24241 	if (enable) {
24242 		WL_DBG(("%s: Enabling events on resume\n", __FUNCTION__));
24243 #ifdef WL_CHAN_UTIL
24244 		setbit(eventmask, WLC_E_BSS_LOAD);
24245 #endif /* WL_CHAN_UTIL */
24246 	} else {
24247 		WL_DBG(("%s: Disabling events before suspend\n", __FUNCTION__));
24248 #ifdef WL_CHAN_UTIL
24249 		clrbit(eventmask, WLC_E_BSS_LOAD);
24250 #endif /* WL_CHAN_UTIL */
24251 	}
24252 
24253 	err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
24254 			sizeof(iovbuf), NULL);
24255 	if (unlikely(err)) {
24256 		WL_ERR(("Set event_msgs error (%d)\n", err));
24257 		goto eventmsg_out;
24258 	}
24259 
24260 eventmsg_out:
24261 	mutex_unlock(&cfg->event_sync);
24262 	return err;
24263 }
24264 
24265 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
24266 int
wl_cfg80211_channel_switch(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_csa_settings * params)24267 wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
24268 	struct cfg80211_csa_settings *params)
24269 {
24270 	s32 err = BCME_OK;
24271 	s32 chan = 0;
24272 	u32 band = 0;
24273 	u32 bw = WL_CHANSPEC_BW_20;
24274 	chanspec_t chspec = 0;
24275 	wl_chan_switch_t csa_arg;
24276 	struct cfg80211_chan_def *chandef = &params->chandef;
24277 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
24278 	struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
24279 
24280 	dev = ndev_to_wlc_ndev(dev, cfg);
24281 	chan = ieee80211_frequency_to_channel(chandef->chan->center_freq);
24282 	band = chandef->chan->band;
24283 
24284 	WL_ERR(("netdev_ifidx(%d), target channel(%d) target bandwidth(%d),"
24285 		" mode(%d), count(%d)\n", dev->ifindex, chan, chandef->width,
24286 		params->block_tx, params->count));
24287 
24288 	if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) {
24289 		WL_ERR(("Channel Switch doesn't support on "
24290 			"the non-SoftAP mode\n"));
24291 		return -EINVAL;
24292 	}
24293 
24294 	/* Check if STA is trying to associate with an AP */
24295 	if (wl_get_drv_status(cfg, CONNECTING, primary_dev)) {
24296 		WL_ERR(("Connecting is in progress\n"));
24297 		return BCME_BUSY;
24298 	}
24299 
24300 	if (chan == cfg->ap_oper_channel) {
24301 		WL_ERR(("Channel %d is same as current operating channel,"
24302 			" so skip\n", chan));
24303 		return BCME_OK;
24304 	}
24305 
24306 	if (band == IEEE80211_BAND_5GHZ) {
24307 #ifdef APSTA_RESTRICTED_CHANNEL
24308 		if (chan != DEFAULT_5G_SOFTAP_CHANNEL) {
24309 			WL_ERR(("Invalid 5G Channel, chan=%d\n", chan));
24310 			return -EINVAL;
24311 		}
24312 #endif /* APSTA_RESTRICTED_CHANNEL */
24313 		err = wl_get_bandwidth_cap(primary_dev, band, &bw);
24314 		if (err < 0) {
24315 			WL_ERR(("Failed to get bandwidth information,"
24316 				" err=%d\n", err));
24317 			return err;
24318 		}
24319 	} else if (band == IEEE80211_BAND_2GHZ) {
24320 #ifdef APSTA_RESTRICTED_CHANNEL
24321 		dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24322 		u32 *sta_chan = (u32 *)wl_read_prof(cfg,
24323 			primary_dev, WL_PROF_CHAN);
24324 
24325 		/* In 2GHz STA/SoftAP concurrent mode, the operating channel
24326 		 * of STA and SoftAP should be confgiured to the same 2GHz
24327 		 * channel. Otherwise, it is an invalid configuration.
24328 		 */
24329 		if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
24330 			wl_get_drv_status(cfg, CONNECTED, primary_dev) &&
24331 			sta_chan && (*sta_chan != chan)) {
24332 			WL_ERR(("Invalid 2G Channel in case of STA/SoftAP"
24333 				" concurrent mode, sta_chan=%d, chan=%d\n",
24334 				*sta_chan, chan));
24335 			return -EINVAL;
24336 		}
24337 #endif /* APSTA_RESTRICTED_CHANNEL */
24338 		bw = WL_CHANSPEC_BW_20;
24339 	} else {
24340 		WL_ERR(("invalid band (%d)\n", band));
24341 		return -EINVAL;
24342 	}
24343 
24344 	chspec = wf_channel2chspec(chan, bw);
24345 	if (!wf_chspec_valid(chspec)) {
24346 		WL_ERR(("Invalid chanspec 0x%x\n", chspec));
24347 		return -EINVAL;
24348 	}
24349 
24350 	/* Send CSA to associated STAs */
24351 	memset(&csa_arg, 0, sizeof(wl_chan_switch_t));
24352 	csa_arg.mode = params->block_tx;
24353 	csa_arg.count = params->count;
24354 	csa_arg.chspec = chspec;
24355 	csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME;
24356 	csa_arg.reg = 0;
24357 
24358 	err = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(wl_chan_switch_t),
24359 		cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
24360 	if (err < 0) {
24361 		WL_ERR(("Failed to switch channel, err=%d\n", err));
24362 	}
24363 
24364 	return err;
24365 }
24366 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
24367 
24368 #ifdef WL_WIPSEVT
24369 int
wl_cfg80211_wips_event_ext(wl_wips_event_info_t * wips_event)24370 wl_cfg80211_wips_event_ext(wl_wips_event_info_t *wips_event)
24371 {
24372 	s32 err = BCME_OK;
24373 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24374 	struct sk_buff *skb;
24375 	gfp_t kflags;
24376 	struct bcm_cfg80211 *cfg;
24377 	struct net_device *ndev;
24378 	struct wiphy *wiphy;
24379 
24380 	cfg = wl_cfg80211_get_bcmcfg();
24381 	if (!cfg || !cfg->wdev) {
24382 		WL_ERR(("WIPS evt invalid arg\n"));
24383 		return err;
24384 	}
24385 
24386 	ndev = bcmcfg_to_prmry_ndev(cfg);
24387 	wiphy = bcmcfg_to_wiphy(cfg);
24388 
24389 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
24390 	skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
24391 		BRCM_VENDOR_WIPS_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_WIPS, kflags);
24392 
24393 	if (!skb) {
24394 		WL_ERR(("skb alloc failed"));
24395 		return BCME_NOMEM;
24396 	}
24397 
24398 	err = nla_put_u16(skb, WIPS_ATTR_DEAUTH_CNT, wips_event->misdeauth);
24399 	if (unlikely(err)) {
24400 		WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_CNT failed\n"));
24401 		goto fail;
24402 	}
24403 	err = nla_put(skb, WIPS_ATTR_DEAUTH_BSSID, ETHER_ADDR_LEN, &wips_event->bssid);
24404 	if (unlikely(err)) {
24405 		WL_ERR(("nla_put WIPS_ATTR_DEAUTH_BSSID failed\n"));
24406 		goto fail;
24407 	}
24408 	err = nla_put_s16(skb, WIPS_ATTR_CURRENT_RSSI, wips_event->current_RSSI);
24409 	if (unlikely(err)) {
24410 		WL_ERR(("nla_put_u16 WIPS_ATTR_CURRENT_RSSI failed\n"));
24411 		goto fail;
24412 	}
24413 	err = nla_put_s16(skb, WIPS_ATTR_DEAUTH_RSSI, wips_event->deauth_RSSI);
24414 	if (unlikely(err)) {
24415 		WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_RSSI failed\n"));
24416 		goto fail;
24417 	}
24418 	cfg80211_vendor_event(skb, kflags);
24419 
24420 	return err;
24421 
24422 fail:
24423 	if (skb) {
24424 		nlmsg_free(skb);
24425 	}
24426 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24427 	return err;
24428 }
24429 
24430 int
wl_cfg80211_wips_event(uint16 misdeauth,char * bssid)24431 wl_cfg80211_wips_event(uint16 misdeauth, char* bssid)
24432 {
24433 	s32 err = BCME_OK;
24434 	wl_wips_event_info_t wips_event;
24435 
24436 	wips_event.misdeauth = misdeauth;
24437 	memcpy(&wips_event.bssid, bssid, ETHER_ADDR_LEN);
24438 	wips_event.current_RSSI = 0;
24439 	wips_event.deauth_RSSI = 0;
24440 
24441 	err = wl_cfg80211_wips_event_ext(&wips_event);
24442 	return err;
24443 }
24444 #endif /* WL_WIPSEVT */
24445 
wl_cfg80211_check_in_progress(struct net_device * dev)24446 bool wl_cfg80211_check_in_progress(struct net_device *dev)
24447 {
24448 	/* TODO: Check for cfg status like scan in progress,
24449 	 * four way handshake, etc before entering Deep Sleep.
24450 	 */
24451 	return TRUE;
24452 }
24453 
24454 #ifdef SUPPORT_AP_SUSPEND
24455 void
wl_set_ap_suspend_error_handler(struct net_device * ndev,bool suspend)24456 wl_set_ap_suspend_error_handler(struct net_device *ndev, bool suspend)
24457 {
24458 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24459 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24460 
24461 	if (wl_get_drv_status(cfg, READY, ndev)) {
24462 		/* IF dongle is down due to previous hang or other conditions, sending
24463 		* one more hang notification is not needed.
24464 		*/
24465 		if (dhd_query_bus_erros(dhdp)) {
24466 			return;
24467 		}
24468 		dhdp->iface_op_failed = TRUE;
24469 #if defined(DHD_FW_COREDUMP)
24470 		if (dhdp->memdump_enabled) {
24471 			dhdp->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
24472 			dhd_bus_mem_dump(dhdp);
24473 		}
24474 #endif /* DHD_FW_COREDUMP */
24475 		WL_ERR(("Notify hang event to upper layer \n"));
24476 		dhdp->hang_reason = suspend ?
24477 			HANG_REASON_BSS_DOWN_FAILURE : HANG_REASON_BSS_UP_FAILURE;
24478 		net_os_send_hang_message(ndev);
24479 	}
24480 }
24481 
24482 #define MAX_AP_RESUME_TIME   5000
24483 int
wl_set_ap_suspend(struct net_device * dev,bool suspend,char * ifname)24484 wl_set_ap_suspend(struct net_device *dev, bool suspend, char *ifname)
24485 {
24486 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24487 	dhd_pub_t *dhdp;
24488 	struct net_device *ndev = NULL;
24489 	int ret = BCME_OK;
24490 	bool is_bssup = FALSE;
24491 	int bssidx;
24492 	unsigned long start_j;
24493 	int time_to_sleep = MAX_AP_RESUME_TIME;
24494 
24495 	dhdp = (dhd_pub_t *)(cfg->pub);
24496 
24497 	if (!dhdp) {
24498 		return BCME_NOTUP;
24499 	}
24500 
24501 	if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
24502 		WL_ERR(("Not Hostapd mode\n"));
24503 		return BCME_NOTAP;
24504 	}
24505 
24506 	ndev = wl_get_ap_netdev(cfg, ifname);
24507 
24508 	if (ndev == NULL) {
24509 		WL_ERR(("No softAP interface named %s\n", ifname));
24510 		return BCME_NOTAP;
24511 	}
24512 
24513 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
24514 		WL_ERR(("Find p2p index from wdev(%p) failed\n", ndev->ieee80211_ptr));
24515 		return BCME_NOTFOUND;
24516 	}
24517 
24518 	is_bssup = wl_cfg80211_bss_isup(ndev, bssidx);
24519 	if (is_bssup && suspend) {
24520 		wl_clr_drv_status(cfg, AP_CREATED, ndev);
24521 		wl_clr_drv_status(cfg, CONNECTED, ndev);
24522 
24523 		if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 0)) < 0) {
24524 			WL_ERR(("AP suspend error %d, suspend %d\n", ret, suspend));
24525 			ret = BCME_NOTDOWN;
24526 			goto exit;
24527 		}
24528 	} else if (!is_bssup && !suspend) {
24529 		/* Abort scan before starting AP again */
24530 		wl_cfg80211_scan_abort(cfg);
24531 
24532 		if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 1)) < 0) {
24533 			WL_ERR(("AP resume error %d, suspend %d\n", ret, suspend));
24534 			ret = BCME_NOTUP;
24535 			goto exit;
24536 		}
24537 
24538 		while (TRUE) {
24539 			start_j = get_jiffies_64();
24540 			/* Wait for Linkup event to mark successful AP bring up */
24541 			ret = wait_event_interruptible_timeout(cfg->netif_change_event,
24542 				wl_get_drv_status(cfg, AP_CREATED, ndev),
24543 				msecs_to_jiffies(time_to_sleep));
24544 			if (ret == -ERESTARTSYS) {
24545 				WL_ERR(("waitqueue was interrupted by a signal\n"));
24546 				time_to_sleep -= jiffies_to_msecs(get_jiffies_64() - start_j);
24547 				if (time_to_sleep <= 0) {
24548 					WL_ERR(("time to sleep hits 0\n"));
24549 					ret = BCME_NOTUP;
24550 					goto exit;
24551 				}
24552 			} else if (ret == 0 || !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
24553 				WL_ERR(("AP resume failed!\n"));
24554 				ret = BCME_NOTUP;
24555 				goto exit;
24556 			} else {
24557 				wl_set_drv_status(cfg, CONNECTED, ndev);
24558 				ret = BCME_OK;
24559 				break;
24560 			}
24561 		}
24562 	} else {
24563 		/* bssup + resume or bssdown + suspend,
24564 		 * So, returns OK
24565 		 */
24566 		ret = BCME_OK;
24567 	}
24568 exit:
24569 	if (ret != BCME_OK)
24570 		wl_set_ap_suspend_error_handler(bcmcfg_to_prmry_ndev(cfg), suspend);
24571 
24572 	return ret;
24573 }
24574 #endif /* SUPPORT_AP_SUSPEND */
24575 
24576 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
wl_set_softap_elna_bypass(struct net_device * dev,char * ifname,int enable)24577 int wl_set_softap_elna_bypass(struct net_device *dev, char *ifname, int enable)
24578 {
24579 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24580 	struct net_device *ifdev = NULL;
24581 	char iobuf[WLC_IOCTL_SMLEN];
24582 	int err = BCME_OK;
24583 	int iftype = 0;
24584 
24585 	memset(iobuf, 0, WLC_IOCTL_SMLEN);
24586 
24587 	/* Check the interface type */
24588 	ifdev = wl_get_netdev_by_name(cfg, ifname);
24589 	if (ifdev == NULL) {
24590 		WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__, ifname));
24591 		err = BCME_BADARG;
24592 		goto fail;
24593 	}
24594 
24595 	iftype = ifdev->ieee80211_ptr->iftype;
24596 	if (iftype == NL80211_IFTYPE_AP) {
24597 		err = wldev_iovar_setint(ifdev, "softap_elnabypass", enable);
24598 		if (unlikely(err)) {
24599 			WL_ERR(("%s: Failed to set softap_elnabypass, err=%d\n",
24600 				__FUNCTION__, err));
24601 		}
24602 	} else {
24603 		WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
24604 			__FUNCTION__));
24605 		err = BCME_BADARG;
24606 	}
24607 fail:
24608 	return err;
24609 }
wl_get_softap_elna_bypass(struct net_device * dev,char * ifname,void * param)24610 int wl_get_softap_elna_bypass(struct net_device *dev, char *ifname, void *param)
24611 {
24612 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24613 	int *enable = (int*)param;
24614 	struct net_device *ifdev = NULL;
24615 	char iobuf[WLC_IOCTL_SMLEN];
24616 	int err = BCME_OK;
24617 	int iftype = 0;
24618 
24619 	memset(iobuf, 0, WLC_IOCTL_SMLEN);
24620 
24621 	/* Check the interface type */
24622 	ifdev = wl_get_netdev_by_name(cfg, ifname);
24623 	if (ifdev == NULL) {
24624 		WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__, ifname));
24625 		err = BCME_BADARG;
24626 		goto fail;
24627 	}
24628 
24629 	iftype = ifdev->ieee80211_ptr->iftype;
24630 	if (iftype == NL80211_IFTYPE_AP) {
24631 		err = wldev_iovar_getint(ifdev, "softap_elnabypass", enable);
24632 		if (unlikely(err)) {
24633 			WL_ERR(("%s: Failed to get softap_elnabypass, err=%d\n",
24634 				__FUNCTION__, err));
24635 		}
24636 	} else {
24637 		WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
24638 			__FUNCTION__));
24639 		err = BCME_BADARG;
24640 	}
24641 fail:
24642 	return err;
24643 
24644 }
24645 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
24646 
24647 #ifdef SUPPORT_AP_BWCTRL
24648 #define OPER_MODE_ENABLE	(1 << 8)
24649 static int op2bw[] = {20, 40, 80, 160};
24650 
24651 static int
wl_get_ap_he_mode(struct net_device * ndev,struct bcm_cfg80211 * cfg,bool * he)24652 wl_get_ap_he_mode(struct net_device *ndev, struct bcm_cfg80211 *cfg, bool *he)
24653 {
24654 	bcm_xtlv_t read_he_xtlv;
24655 	int ret = 0;
24656 	u8  he_enab = 0;
24657 	u32 he_feature = 0;
24658 	*he = FALSE;
24659 
24660 	/* Check he enab first */
24661 	read_he_xtlv.id = WL_HE_CMD_ENAB;
24662 	read_he_xtlv.len = 0;
24663 
24664 	ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
24665 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
24666 	if (ret < 0) {
24667 		if (ret == BCME_UNSUPPORTED) {
24668 			/* HE not supported */
24669 			ret = BCME_OK;
24670 		} else {
24671 			WL_ERR(("HE ENAB get failed. ret=%d\n", ret));
24672 		}
24673 		goto exit;
24674 	} else {
24675 		he_enab =  *(u8*)cfg->ioctl_buf;
24676 	}
24677 
24678 	if (!he_enab) {
24679 		goto exit;
24680 	}
24681 
24682 	/* Then check BIT3 of he features */
24683 	read_he_xtlv.id = WL_HE_CMD_FEATURES;
24684 	read_he_xtlv.len = 0;
24685 
24686 	ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
24687 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
24688 	if (ret < 0) {
24689 		WL_ERR(("HE FEATURE get failed. error=%d\n", ret));
24690 		goto exit;
24691 	} else {
24692 		he_feature =  *(int*)cfg->ioctl_buf;
24693 		he_feature = dtoh32(he_feature);
24694 	}
24695 
24696 	if (he_feature & WL_HE_FEATURES_HE_AP) {
24697 		WL_DBG(("HE is enabled in AP\n"));
24698 		*he = TRUE;
24699 	}
24700 exit:
24701 	return ret;
24702 }
24703 
24704 static void
wl_update_apchan_bwcap(struct bcm_cfg80211 * cfg,struct net_device * ndev,chanspec_t chanspec)24705 wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg, struct net_device *ndev, chanspec_t chanspec)
24706 {
24707 	struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
24708 	struct wireless_dev *wdev = ndev_to_wdev(dev);
24709 	struct wiphy *wiphy = wdev->wiphy;
24710 	int ret = BCME_OK;
24711 	u32 bw_cap;
24712 	u32 ctl_chan;
24713 	chanspec_t chanbw = WL_CHANSPEC_BW_20;
24714 
24715 	/* Update channel in profile */
24716 	ctl_chan = wf_chspec_ctlchan(chanspec);
24717 	wl_update_prof(cfg, ndev, NULL, &ctl_chan, WL_PROF_CHAN);
24718 
24719 	/* BW cap is only updated in 5GHz */
24720 	if (ctl_chan <= CH_MAX_2G_CHANNEL)
24721 		return;
24722 
24723 	/* Get WL BW CAP */
24724 	ret = wl_get_bandwidth_cap(bcmcfg_to_prmry_ndev(cfg),
24725 		IEEE80211_BAND_5GHZ, &bw_cap);
24726 	if (ret < 0) {
24727 		WL_ERR(("get bw_cap failed = %d\n", ret));
24728 		goto exit;
24729 	}
24730 
24731 	chanbw = CHSPEC_BW(channel_to_chanspec(wiphy,
24732 		ndev, wf_chspec_ctlchan(chanspec), bw_cap));
24733 
24734 exit:
24735 	cfg->bw_cap_5g = bw2cap[chanbw >> WL_CHANSPEC_BW_SHIFT];
24736 	WL_INFORM_MEM(("supported bw cap is:0x%x\n", cfg->bw_cap_5g));
24737 
24738 }
24739 
24740 int
wl_rxchain_to_opmode_nss(int rxchain)24741 wl_rxchain_to_opmode_nss(int rxchain)
24742 {
24743 	/*
24744 	 * Nss 1 -> 0, Nss 2 -> 1
24745 	 * This is from operating mode field
24746 	 * in 8.4.1.50 of 802.11ac-2013
24747 	 */
24748 	/* TODO : Nss 3 ? */
24749 	if (rxchain == 3)
24750 		return (1 << 4);
24751 	else
24752 		return 0;
24753 }
24754 
24755 int
wl_update_opmode(struct net_device * ndev,u32 bw)24756 wl_update_opmode(struct net_device *ndev, u32 bw)
24757 {
24758 	int ret = BCME_OK;
24759 	int oper_mode;
24760 	int rxchain;
24761 
24762 	ret = wldev_iovar_getint(ndev, "rxchain", (s32 *)&rxchain);
24763 	if (ret < 0) {
24764 		WL_ERR(("get rxchain failed = %d\n", ret));
24765 		goto exit;
24766 	}
24767 
24768 	oper_mode = bw;
24769 	oper_mode |= wl_rxchain_to_opmode_nss(rxchain);
24770 	/* Enable flag */
24771 	oper_mode |= OPER_MODE_ENABLE;
24772 
24773 	ret = wldev_iovar_setint(ndev, "oper_mode", oper_mode);
24774 	if (ret < 0) {
24775 		WL_ERR(("set oper_mode failed = %d\n", ret));
24776 		goto exit;
24777 	}
24778 
24779 exit:
24780 	return ret;
24781 }
24782 
24783 int
wl_set_ap_bw(struct net_device * dev,u32 bw,char * ifname)24784 wl_set_ap_bw(struct net_device *dev, u32 bw, char *ifname)
24785 {
24786 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24787 	dhd_pub_t *dhdp;
24788 	struct net_device *ndev = NULL;
24789 	int ret = BCME_OK;
24790 	u32 *channel;
24791 	bool he;
24792 
24793 	dhdp = (dhd_pub_t *)(cfg->pub);
24794 
24795 	if (!dhdp) {
24796 		return BCME_NOTUP;
24797 	}
24798 
24799 	if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
24800 		WL_ERR(("Not Hostapd mode\n"));
24801 		return BCME_NOTAP;
24802 	}
24803 
24804 	ndev = wl_get_ap_netdev(cfg, ifname);
24805 
24806 	if (ndev == NULL) {
24807 		WL_ERR(("No softAP interface named %s\n", ifname));
24808 		return BCME_NOTAP;
24809 	}
24810 
24811 	if (bw > DOT11_OPER_MODE_160MHZ) {
24812 		WL_ERR(("BW is too big %d\n", bw));
24813 		return BCME_BADARG;
24814 	}
24815 
24816 	channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
24817 	if (*channel <= CH_MAX_2G_CHANNEL) {
24818 		WL_ERR(("current channel is %d, not supported\n", *channel));
24819 		ret = BCME_BADCHAN;
24820 		goto exit;
24821 	}
24822 
24823 	if ((DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
24824 		wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) ||
24825 		cfg->nan_enable) {
24826 		WL_ERR(("BW control in concurrent mode is not supported\n"));
24827 		return BCME_BUSY;
24828 	}
24829 
24830 	/* When SCAN is on going either in STA or in AP, return BUSY */
24831 	if (wl_get_drv_status_all(cfg, SCANNING)) {
24832 		WL_ERR(("STA is SCANNING, not support BW control\n"));
24833 		return BCME_BUSY;
24834 	}
24835 
24836 	/* When SCANABORT is on going either in STA or in AP, return BUSY */
24837 	if (wl_get_drv_status_all(cfg, SCAN_ABORTING)) {
24838 		WL_ERR(("STA is SCAN_ABORTING, not support BW control\n"));
24839 		return BCME_BUSY;
24840 	}
24841 
24842 	/* When CONNECTION is on going in STA, return BUSY */
24843 	if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
24844 		WL_ERR(("STA is CONNECTING, not support BW control\n"));
24845 		return BCME_BUSY;
24846 	}
24847 
24848 	/* BW control in AX mode needs more verification */
24849 	ret = wl_get_ap_he_mode(ndev, cfg, &he);
24850 	if (ret == BCME_OK && he) {
24851 		WL_ERR(("BW control in HE mode is not supported\n"));
24852 		return BCME_UNSUPPORTED;
24853 	}
24854 	if (ret < 0) {
24855 		WL_ERR(("Check AX mode is failed\n"));
24856 		goto exit;
24857 	}
24858 
24859 	if ((!WL_BW_CAP_160MHZ(cfg->bw_cap_5g) && (bw == DOT11_OPER_MODE_160MHZ)) ||
24860 		(!WL_BW_CAP_80MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_80MHZ)) ||
24861 		(!WL_BW_CAP_40MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_40MHZ)) ||
24862 		(!WL_BW_CAP_20MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_20MHZ))) {
24863 		WL_ERR(("bw_cap %x does not support bw = %d\n", cfg->bw_cap_5g, bw));
24864 		ret = BCME_BADARG;
24865 		goto exit;
24866 	}
24867 
24868 	WL_DBG(("Updating AP BW to %d\n", op2bw[bw]));
24869 
24870 	ret = wl_update_opmode(ndev, bw);
24871 	if (ret < 0) {
24872 		WL_ERR(("opmode set failed = %d\n", ret));
24873 		goto exit;
24874 	}
24875 
24876 exit:
24877 	return ret;
24878 }
24879 
24880 int
wl_get_ap_bw(struct net_device * dev,char * command,char * ifname,int total_len)24881 wl_get_ap_bw(struct net_device *dev, char* command, char *ifname, int total_len)
24882 {
24883 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24884 	dhd_pub_t *dhdp;
24885 	struct net_device *ndev = NULL;
24886 	int ret = BCME_OK;
24887 	u32 chanspec = 0;
24888 	u32 bw = DOT11_OPER_MODE_20MHZ;
24889 	int bytes_written = 0;
24890 
24891 	dhdp = (dhd_pub_t *)(cfg->pub);
24892 
24893 	if (!dhdp) {
24894 		return BCME_NOTUP;
24895 	}
24896 
24897 	if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
24898 		WL_ERR(("Not Hostapd mode\n"));
24899 		return BCME_NOTAP;
24900 	}
24901 
24902 	ndev = wl_get_ap_netdev(cfg, ifname);
24903 
24904 	if (ndev == NULL) {
24905 		WL_ERR(("No softAP interface named %s\n", ifname));
24906 		return BCME_NOTAP;
24907 	}
24908 
24909 	ret = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
24910 	if (ret < 0) {
24911 		WL_ERR(("get chanspec from AP failed = %d\n", ret));
24912 		goto exit;
24913 	}
24914 
24915 	chanspec = wl_chspec_driver_to_host(chanspec);
24916 
24917 	if (CHSPEC_IS20(chanspec)) {
24918 		bw = DOT11_OPER_MODE_20MHZ;
24919 	} else if (CHSPEC_IS40(chanspec)) {
24920 		bw = DOT11_OPER_MODE_40MHZ;
24921 	} else if (CHSPEC_IS80(chanspec)) {
24922 		bw = DOT11_OPER_MODE_80MHZ;
24923 	} else if (CHSPEC_IS_BW_160_WIDE(chanspec)) {
24924 		bw = DOT11_OPER_MODE_160MHZ;
24925 	} else {
24926 		WL_ERR(("chanspec error %x\n", chanspec));
24927 		ret = BCME_BADCHAN;
24928 		goto exit;
24929 	}
24930 
24931 	bytes_written += snprintf(command + bytes_written, total_len,
24932 		"bw=%d", bw);
24933 	ret = bytes_written;
24934 exit:
24935 	return ret;
24936 }
24937 
24938 static void
wl_restore_ap_bw(struct bcm_cfg80211 * cfg)24939 wl_restore_ap_bw(struct bcm_cfg80211 *cfg)
24940 {
24941 	int ret = BCME_OK;
24942 	u32 bw;
24943 	bool he = FALSE;
24944 	struct net_info *iter, *next;
24945 	struct net_device *ndev = NULL;
24946 	u32 *channel;
24947 
24948 	if (!cfg) {
24949 		return;
24950 	}
24951 
24952 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
24953 	for_each_ndev(cfg, iter, next) {
24954 		GCC_DIAGNOSTIC_POP();
24955 		if (iter->ndev) {
24956 			if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
24957 				channel = (u32 *)wl_read_prof(cfg, iter->ndev, WL_PROF_CHAN);
24958 				if (*channel > CH_MAX_2G_CHANNEL) {
24959 					ndev = iter->ndev;
24960 					break;
24961 				}
24962 			}
24963 		}
24964 	}
24965 
24966 	if (!ndev) {
24967 		return;
24968 	}
24969 
24970 	/* BW control in AX mode not allowed */
24971 	ret = wl_get_ap_he_mode(bcmcfg_to_prmry_ndev(cfg), cfg, &he);
24972 	if (ret == BCME_OK && he) {
24973 		return;
24974 	}
24975 	if (ret < 0) {
24976 		WL_ERR(("Check AX mode is failed\n"));
24977 		return;
24978 	}
24979 
24980 	if (WL_BW_CAP_160MHZ(cfg->bw_cap_5g)) {
24981 		bw = DOT11_OPER_MODE_160MHZ;
24982 	} else if (WL_BW_CAP_80MHZ(cfg->bw_cap_5g)) {
24983 		bw = DOT11_OPER_MODE_80MHZ;
24984 	} else if (WL_BW_CAP_40MHZ(cfg->bw_cap_5g)) {
24985 		bw = DOT11_OPER_MODE_40MHZ;
24986 	} else {
24987 		return;
24988 	}
24989 
24990 	WL_DBG(("Restoring AP BW to %d\n", op2bw[bw]));
24991 
24992 	ret = wl_update_opmode(ndev, bw);
24993 	if (ret < 0) {
24994 		WL_ERR(("bw restore failed = %d\n", ret));
24995 		return;
24996 	}
24997 }
24998 #endif /* SUPPORT_AP_BWCTRL */
24999 
25000 s32
wl_cfg80211_autochannel(struct net_device * dev,char * command,int total_len)25001 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len)
25002 {
25003 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
25004 	int ret = 0;
25005 	int bytes_written = -1;
25006 
25007 	sscanf(command, "%*s %d", &cfg->autochannel);
25008 
25009 	if (cfg->autochannel == 0) {
25010 		cfg->best_2g_ch = 0;
25011 		cfg->best_5g_ch = 0;
25012 	} else if (cfg->autochannel == 2) {
25013 		bytes_written = snprintf(command, total_len, "2g=%d 5g=%d",
25014 			cfg->best_2g_ch, cfg->best_5g_ch);
25015 		WL_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
25016 		ret = bytes_written;
25017 	}
25018 
25019 	return ret;
25020 }
25021