• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Linux cfg80211 driver
3  *
4  * Copyright (C) 2020, Broadcom.
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *
21  * <<Broadcom-WL-IPTag/Dual:>>
22  */
23 /* */
24 #include <typedefs.h>
25 #include <linuxver.h>
26 #include <linux/kernel.h>
27 
28 #include <bcmutils.h>
29 #include <bcmstdlib_s.h>
30 #include <bcmwifi_channels.h>
31 #include <bcmendian.h>
32 #include <ethernet.h>
33 #ifdef WL_WPS_SYNC
34 #include <eapol.h>
35 #endif /* WL_WPS_SYNC */
36 #include <802.11.h>
37 #include <bcmiov.h>
38 #include <linux/if_arp.h>
39 #include <asm/uaccess.h>
40 
41 #include <ethernet.h>
42 #include <linux/kernel.h>
43 #include <linux/kthread.h>
44 #include <linux/netdevice.h>
45 #include <linux/sched.h>
46 #include <linux/etherdevice.h>
47 #include <linux/wireless.h>
48 #include <linux/ieee80211.h>
49 #include <linux/wait.h>
50 #if defined(CONFIG_TIZEN)
51 #include <linux/net_stat_tizen.h>
52 #endif /* CONFIG_TIZEN */
53 #include <net/cfg80211.h>
54 #include <net/rtnetlink.h>
55 
56 #include <wlioctl.h>
57 #include <bcmevent.h>
58 #include <wldev_common.h>
59 #include <wl_cfg80211.h>
60 #include <wl_cfgp2p.h>
61 #include <wl_cfgscan.h>
62 #include <wl_cfgvif.h>
63 #include <bcmdevs.h>
64 #include <bcmdevs_legacy.h>
65 #ifdef WL_FILS
66 #include <fils.h>
67 #include <frag.h>
68 #endif /* WL_FILS */
69 
70 #ifdef OEM_ANDROID
71 #include <wl_android.h>
72 #endif
73 
74 #if defined(BCMDONGLEHOST)
75 #include <dngl_stats.h>
76 #include <dhd.h>
77 #include <dhd_linux.h>
78 #include <dhd_linux_pktdump.h>
79 #include <dhd_debug.h>
80 #include <dhdioctl.h>
81 #include <wlioctl.h>
82 #include <dhd_cfg80211.h>
83 #include <dhd_bus.h>
84 #ifdef PNO_SUPPORT
85 #include <dhd_pno.h>
86 #endif /* PNO_SUPPORT */
87 #include <wl_cfgvendor.h>
88 #endif /* defined(BCMDONGLEHOST) */
89 
90 #ifdef CONFIG_SLEEP_MONITOR
91 #include <linux/power/sleep_monitor.h>
92 #endif
93 
94 #if !defined(WL_VENDOR_EXT_SUPPORT)
95 #undef GSCAN_SUPPORT
96 #endif
97 #include <dhd_config.h>
98 
99 #ifdef WL_NAN
100 #include <wl_cfgnan.h>
101 #endif /* WL_NAN */
102 
103 #ifdef PROP_TXSTATUS
104 #include <dhd_wlfc.h>
105 #endif
106 
107 #ifdef BCMPCIE
108 #include <dhd_flowring.h>
109 #endif
110 #ifdef RTT_SUPPORT
111 #include <dhd_rtt.h>
112 #endif /* RTT_SUPPORT */
113 
114 #if defined(BIGDATA_SOFTAP) || defined(DHD_ENABLE_BIGDATA_LOGGING)
115 #include <wl_bigdata.h>
116 #endif /* BIGDATA_SOFTAP || DHD_ENABLE_BIGDATA_LOGGING */
117 
118 #ifdef DHD_EVENT_LOG_FILTER
119 #include <dhd_event_log_filter.h>
120 #endif /* DHD_EVENT_LOG_FILTER */
121 #define BRCM_SAE_VENDOR_EVENT_BUF_LEN 500
122 
123 #ifdef DNGL_AXI_ERROR_LOGGING
124 #include <bcmtlv.h>
125 #endif /* DNGL_AXI_ERROR_LOGGING */
126 
127 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
128 #include <linux/dev_ril_bridge.h>
129 #include <linux/notifier.h>
130 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
131 
132 #if (defined(WL_FW_OCE_AP_SELECT) || defined(BCMFW_ROAM_ENABLE)) && \
133 	((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS))
134 uint fw_ap_select = true;
135 #else
136 uint fw_ap_select = false;
137 #endif /* WL_FW_OCE_AP_SELECT && (ROAM_ENABLE || BCMFW_ROAM_ENABLE) */
138 module_param(fw_ap_select, uint, 0660);
139 
140 #if defined(WL_REASSOC)
141 uint wl_reassoc_support = true;
142 #else
143 uint wl_reassoc_support = false;
144 #endif /* WL_REASSOC */
145 module_param(wl_reassoc_support, uint, 0660);
146 
147 static struct device *cfg80211_parent_dev = NULL;
148 static struct bcm_cfg80211 *g_bcmcfg = NULL;
149 u32 wl_dbg_level = WL_DBG_ERR;
150 
151 #define MAX_WAIT_TIME 1500
152 #ifdef WLAIBSS_MCHAN
153 #define IBSS_IF_NAME "ibss%d"
154 #endif /* WLAIBSS_MCHAN */
155 
156 #ifdef VSDB
157 /* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
158 #define DEFAULT_SLEEP_TIME_VSDB		120
159 #define OFF_CHAN_TIME_THRESHOLD_MS	200
160 #define AF_RETRY_DELAY_TIME			40
161 
162 /* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
163 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)	\
164 	do {	\
165 		if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) ||	\
166 			wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {	\
167 			OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB);			\
168 		}	\
169 	} while (0)
170 #else /* VSDB */
171 /* if not VSDB, do nothing */
172 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
173 #endif /* VSDB */
174 
175 #if !defined(BCMDONGLEHOST)
176 #ifdef ntoh32
177 #undef ntoh32
178 #endif
179 #ifdef ntoh16
180 #undef ntoh16
181 #endif
182 #ifdef htod32
183 #undef htod32
184 #endif
185 #ifdef htod16
186 #undef htod16
187 #endif
188 #define ntoh32(i) (i)
189 #define ntoh16(i) (i)
190 #define htod32(i) (i)
191 #define htod16(i) (i)
192 #define DNGL_FUNC(func, parameters)
193 #else
194 #define DNGL_FUNC(func, parameters) func parameters
195 #define COEX_DHCP
196 
197 #endif /* defined(BCMDONGLEHOST) */
198 
199 #define WLAN_EID_SSID	0
200 #define CH_MIN_5G_CHANNEL 34
201 #ifdef WLAIBSS
202 enum abiss_event_type {
203 	AIBSS_EVENT_TXFAIL
204 };
205 #endif
206 
207 #ifdef WL_RELMCAST
208 enum rmc_event_type {
209 	RMC_EVENT_NONE,
210 	RMC_EVENT_LEADER_CHECK_FAIL
211 };
212 #endif /* WL_RELMCAST */
213 
214 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
215  * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
216  * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
217  * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
218  * All the chnages in world regulatory domain are to be done here.
219  *
220  * this definition reuires disabling missing-field-initializer warning
221  * as the ieee80211_regdomain definition differs in plain linux and in Android
222  */
223 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
224 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
225 _Pragma("GCC diagnostic push")
226 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
227 #endif
228 static const struct ieee80211_regdomain brcm_regdom = {
229 #ifdef WL_6G_BAND
230 	.n_reg_rules = 8,
231 #else
232 	.n_reg_rules = 4,
233 #endif
234 	.alpha2 =  "99",
235 	.reg_rules = {
236 		/* IEEE 802.11b/g, channels 1..11 */
237 		REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
238 		/* If any */
239 		/* IEEE 802.11 channel 14 - Only JP enables
240 		 * this and for 802.11b only
241 		 */
242 		REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
243 		/* IEEE 802.11a, channel 36..64 */
244 		REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
245 		/* IEEE 802.11a, channel 100..165 */
246 		REG_RULE(5470-10, 5850+10, 40, 6, 20, 0),
247 #ifdef WL_6G_BAND
248 		REG_RULE(6025-80, 6985+80, 160, 6, 20, 0),
249 		REG_RULE(5935-10, 7115+10, 20, 6, 20, 0),
250 		REG_RULE(5965-20, 7085+20, 40, 6, 20, 0),
251 		REG_RULE(5985-40, 7025+40, 80, 6, 20, 0),
252 #endif /* WL_6G_BAND */
253 		}
254 };
255 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
256 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
257 _Pragma("GCC diagnostic pop")
258 #endif
259 
260 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
261 	(defined(WL_IFACE_COMB_NUM_CHANNELS) || \
262 	defined(WL_CFG80211_P2P_DEV_IF))
263 static const struct ieee80211_iface_limit common_if_limits[] = {
264 	{
265 	/*
266 	 * Driver can support up to 2 AP's
267 	 */
268 	.max = 2,
269 	.types = BIT(NL80211_IFTYPE_AP),
270 	},
271 	{
272 	/*
273 	 * During P2P-GO removal, P2P-GO is first changed to STA and later only
274 	 * removed. So setting maximum possible number of STA interfaces according
275 	 * to kernel version.
276 	 *
277 	 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
278 	 * linux-3.8 and above - max:4
279 	 * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
280 	 * for NAN defined, registering it as STA type)
281 	 */
282 #ifdef WL_ENABLE_P2P_IF
283 	.max = 5,
284 #else
285 	.max = 4,
286 #endif /* WL_ENABLE_P2P_IF */
287 	.types = BIT(NL80211_IFTYPE_STATION),
288 	},
289 	{
290 	.max = 2,
291 	.types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
292 	},
293 #if defined(WL_CFG80211_P2P_DEV_IF)
294 	{
295 	.max = 1,
296 	.types = BIT(NL80211_IFTYPE_P2P_DEVICE),
297 	},
298 #endif /* WL_CFG80211_P2P_DEV_IF */
299 	{
300 	.max = 1,
301 	.types = BIT(NL80211_IFTYPE_ADHOC),
302 	},
303 };
304 
305 #define NUM_DIFF_CHANNELS 2
306 
307 static const struct ieee80211_iface_combination
308 common_iface_combinations[] = {
309 	{
310 	.num_different_channels = NUM_DIFF_CHANNELS,
311 	/*
312 	 * At Max 5 network interfaces can be registered concurrently
313 	 */
314 	.max_interfaces = IFACE_MAX_CNT,
315 	.limits = common_if_limits,
316 	.n_limits = ARRAY_SIZE(common_if_limits),
317 	},
318 };
319 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
320 
321 static const char *wl_if_state_strs[WL_IF_STATE_MAX + 1] = {
322 	"WL_IF_CREATE_REQ",
323 	"WL_IF_CREATE_DONE",
324 	"WL_IF_DELETE_REQ",
325 	"WL_IF_DELETE_DONE",
326 	"WL_IF_CHANGE_REQ",
327 	"WL_IF_CHANGE_DONE",
328 	"WL_IF_STATE_MAX"
329 };
330 
331 #ifdef WBTEXT
332 typedef struct wl_wbtext_bssid {
333 	struct ether_addr ea;
334 	struct list_head list;
335 } wl_wbtext_bssid_t;
336 
337 static void wl_cfg80211_wbtext_reset_conf(struct bcm_cfg80211 *cfg, struct net_device *ndev);
338 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev);
339 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
340 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
341 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg);
342 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
343 	struct wl_profile *profile);
344 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
345 	struct wl_profile *profile);
346 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev);
347 static int wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len);
348 #endif /* WBTEXT */
349 
350 #ifdef RTT_SUPPORT
351 static s32 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
352 		const wl_event_msg_t *e, void *data);
353 #endif /* RTT_SUPPORT */
354 #ifdef WL_CHAN_UTIL
355 static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg,
356 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
357 static s32 wl_cfg80211_start_bssload_report(struct net_device *ndev);
358 #endif /* WL_CHAN_UTIL */
359 
360 /* SoftAP related parameters */
361 #define DEFAULT_2G_SOFTAP_CHANNEL	1
362 #define DEFAULT_2G_SOFTAP_CHANSPEC	0x1006
363 #define DEFAULT_5G_SOFTAP_CHANNEL	149
364 #define WL_MAX_NUM_CSA_COUNTERS		255
365 
366 #define MAX_VNDR_OUI_STR_LEN	256u
367 #define VNDR_OUI_STR_LEN	10u
368 #define DOT11_DISCONNECT_RC     2u
369 static const uchar *exclude_vndr_oui_list[] = {
370 	"\x00\x50\xf2",			/* Microsoft */
371 	"\x00\x00\xf0",			/* Samsung Elec */
372 	WFA_OUI,			/* WFA */
373 	NULL
374 };
375 
376 typedef struct wl_vndr_oui_entry {
377 	uchar oui[DOT11_OUI_LEN];
378 	struct list_head list;
379 } wl_vndr_oui_entry_t;
380 
381 #ifdef WL_ANALYTICS
382 static const uchar disco_bcnloss_vsie[] = {
383 	0xdd, /* Vendor specific */
384 	0x09, /* Length */
385 	0x00, 0x00, 0xF0, /* OUI */
386 	0x22, /* VENDOR_ENTERPRISE_STA_OUI_TYPE */
387 	0x03, /* Sub type for additional rc */
388 	0x01, /* Version */
389 	0x02, /* Length */
390 	0x07, 0x00 /* Reason code for BCN loss */
391 };
392 #endif /* WL_ANALYTICS */
393 
394 static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
395 		struct net_device *ndev, char *vndr_oui, u32 vndr_oui_len);
396 static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg);
397 #ifdef WL_ANALYTICS
398 static bool wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211 *cfg,
399 	struct net_device *ndev, const char *vndr_oui);
400 #endif
401 static s32 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
402 		struct parsed_vndr_ies *vndr_ies);
403 static bool wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t *vndrie);
404 #if defined(WL_FW_OCE_AP_SELECT)
405 static bool
406 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
407 
408 /* Check whether the given IE looks like WFA OCE IE. */
409 #define wl_cfgoce_is_oce_ie(ie, tlvs, len)      wl_cfgoce_has_ie(ie, tlvs, len, \
410 	(const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_MBO_OCE)
411 
412 /* Is any of the tlvs the expected entry? If
413  * not update the tlvs buffer pointer/length.
414  */
415 static bool
wl_cfgoce_has_ie(const u8 * ie,const u8 ** tlvs,u32 * tlvs_len,const u8 * oui,u32 oui_len,u8 type)416 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
417 {
418 	/* If the contents match the OUI and the type */
419 	if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
420 			!bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
421 			type == ie[TLV_BODY_OFF + oui_len]) {
422 		return TRUE;
423 	}
424 
425 	return FALSE;
426 }
427 #endif /* WL_FW_OCE_AP_SELECT */
428 
429 /*
430  * cfg80211_ops api/callback list
431  */
432 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
433 #ifdef WLAIBSS_MCHAN
434 static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name);
435 static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
436 #endif /* WLAIBSS_MCHAN */
437 static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
438 	struct cfg80211_ibss_params *params);
439 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
440 	struct net_device *dev);
441 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
442 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
443 	struct net_device *dev, const u8 *mac,
444 	struct station_info *sinfo);
445 #else
446 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
447 	struct net_device *dev, u8 *mac,
448 	struct station_info *sinfo);
449 #endif
450 static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
451 	struct net_device *dev, bool enabled,
452 	s32 timeout);
453 static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
454 	struct cfg80211_connect_params *sme);
455 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
456 static int wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
457 	struct cfg80211_connect_params *sme, u32 changed);
458 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
459 static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
460 	u16 reason_code);
461 #if defined(WL_CFG80211_P2P_DEV_IF)
462 static s32
463 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
464 	enum nl80211_tx_power_setting type, s32 mbm);
465 #else
466 static s32
467 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
468 	enum nl80211_tx_power_setting type, s32 dbm);
469 #endif /* WL_CFG80211_P2P_DEV_IF */
470 #if defined(WL_CFG80211_P2P_DEV_IF)
471 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
472 	struct wireless_dev *wdev, s32 *dbm);
473 #else
474 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
475 #endif /* WL_CFG80211_P2P_DEV_IF */
476 static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
477 	struct net_device *dev,
478 	u8 key_idx, bool unicast, bool multicast);
479 static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
480 	u8 key_idx, bool pairwise, const u8 *mac_addr,
481 	struct key_params *params);
482 static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
483 	u8 key_idx, bool pairwise, const u8 *mac_addr);
484 static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
485 	u8 key_idx, bool pairwise, const u8 *mac_addr,
486 	void *cookie, void (*callback) (void *cookie,
487 	struct key_params *params));
488 static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
489 	struct net_device *dev,	u8 key_idx);
490 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
491 static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
492 	bcm_struct_cfgdev *cfgdev, u64 cookie);
493 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
494 static s32 wl_cfg80211_del_station(
495 		struct wiphy *wiphy, struct net_device *ndev,
496 		struct station_del_parameters *params);
497 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
498 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
499 	struct net_device *ndev, const u8* mac_addr);
500 #else
501 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
502 	struct net_device *ndev, u8* mac_addr);
503 #endif
504 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
505 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
506 	struct net_device *dev, const u8 *mac, struct station_parameters *params);
507 #else
508 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
509 	struct net_device *dev, u8 *mac, struct station_parameters *params);
510 #endif
511 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
512 static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
513 	struct cfg80211_pmksa *pmksa);
514 static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
515 	struct cfg80211_pmksa *pmksa);
516 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
517 	struct net_device *dev);
518 static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
519 	struct cfg80211_pmksa *pmksa, bool set);
520 static void wl_cfg80211_spmk_pmkdb_change_pmk_type(struct bcm_cfg80211 *cfg,
521 	pmkid_list_v3_t *pmk_list);
522 static void wl_cfg80211_spmk_pmkdb_del_spmk(struct bcm_cfg80211 *cfg,
523 	struct cfg80211_pmksa *pmksa);
524 
525 struct wireless_dev *
526 wl_cfg80211_create_iface(struct wiphy *wiphy, wl_iftype_t
527 	iface_type, u8 *mac_addr, const char *name);
528 s32
529 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
530 
531 s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
532 	struct net_device *ndev, s32 bsscfg_idx,
533 	wl_iftype_t iftype, s32 del, u8 *addr);
534 s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
535 	struct net_device *ndev, s32 bsscfg_idx,
536 	wl_iftype_t brcm_iftype, s32 del, u8 *addr);
537 #ifdef GTK_OFFLOAD_SUPPORT
538 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
539 static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
540 	struct cfg80211_gtk_rekey_data *data);
541 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
542 #endif /* GTK_OFFLOAD_SUPPORT */
543 chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
544 chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
545 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev);
546 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
547 #ifdef WLFBT
548 static int wl_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
549 	struct cfg80211_update_ft_ies_params *ftie);
550 #endif /* WLFBT */
551 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */
552 
553 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
554 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
555         const struct cfg80211_pmk_conf *conf);
556 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
557         const u8 *aa);
558 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
559 
560 /*
561  * event & event Q handlers for cfg80211 interfaces
562  */
563 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
564 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
565 static void wl_event_handler(struct work_struct *work_data);
566 static void wl_init_eq(struct bcm_cfg80211 *cfg);
567 static void wl_flush_eq(struct bcm_cfg80211 *cfg);
568 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
569 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
570 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
571 static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
572 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
573 static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
574 	const wl_event_msg_t *msg, void *data);
575 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e);
576 static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
577 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
578 static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
579 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
580 static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
581 	const wl_event_msg_t *e, void *data, bool completed);
582 #ifdef DHD_LOSSLESS_ROAMING
583 static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
584 	const wl_event_msg_t *e, void *data);
585 #endif /* DHD_LOSSLESS_ROAMING */
586 static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
587 	const wl_event_msg_t *e, void *data);
588 #ifdef BT_WIFI_HANDOVER
589 static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
590 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
591 #endif /* BT_WIFI_HANDOVER */
592 #ifdef GSCAN_SUPPORT
593 static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
594 	const wl_event_msg_t *e, void *data);
595 #endif /* GSCAN_SUPPORT */
596 #ifdef RSSI_MONITOR_SUPPORT
597 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
598 	const wl_event_msg_t *e, void *data);
599 #endif /* RSSI_MONITOR_SUPPORT */
600 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
601 	enum wl_status state, bool set);
602 #ifdef CUSTOM_EVENT_PM_WAKE
603 static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
604 	const wl_event_msg_t *e, void *data);
605 #endif	/* CUSTOM_EVENT_PM_WAKE */
606 #if defined(DHD_LOSSLESS_ROAMING) || defined (DBG_PKT_MON)
607 static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
608 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
609 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
610 #ifdef DHD_LOSSLESS_ROAMING
611 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
612 #endif /* DHD_LOSSLESS_ROAMING */
613 #ifdef WL_SDO
614 static s32 wl_svc_resp_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
615 	const wl_event_msg_t *e, void *data);
616 static s32 wl_notify_device_discovery(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
617 	const wl_event_msg_t *e, void *data);
618 #endif
619 
620 #ifdef WL_MBO
621 static s32
622 wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
623 	const wl_event_msg_t *e, void *data);
624 #endif /* WL_MBO */
625 
626 #ifdef WL_TWT
627 static s32
628 wl_notify_twt_event(struct bcm_cfg80211 *cfg,
629 		bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
630 #endif /* WL_TWT */
631 
632 #ifdef WL_CLIENT_SAE
633 static bool wl_is_pmkid_available(struct net_device *dev, const u8 *bssid);
634 static s32 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
635 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
636 static s32 wl_cfg80211_external_auth(struct wiphy *wiphy,
637 	struct net_device *dev, struct cfg80211_external_auth_params *ext_auth);
638 static s32
639 wl_cfg80211_mgmt_auth_tx(struct net_device *dev, bcm_struct_cfgdev *cfgdev,
640 	struct bcm_cfg80211 *cfg, const u8 *buf, size_t len, s32 bssidx, u64 *cookie);
641 #endif /* WL_CLIENT_SAE */
642 
643 /*
644  * register/deregister parent device
645  */
646 static void wl_cfg80211_clear_parent_dev(void);
647 /*
648  * ioctl utilites
649  */
650 
651 /*
652  * cfg80211 set_wiphy_params utilities
653  */
654 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
655 static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
656 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
657 
658 /*
659  * cfg profile utilities
660  */
661 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
662 
663 /*
664  * cfg80211 connect utilites
665  */
666 static s32 wl_set_wpa_version(struct net_device *dev,
667 	struct cfg80211_connect_params *sme);
668 static s32 wl_set_auth_type(struct net_device *dev,
669 	struct cfg80211_connect_params *sme);
670 static s32 wl_set_set_cipher(struct net_device *dev,
671 	struct cfg80211_connect_params *sme);
672 static s32 wl_set_key_mgmt(struct net_device *dev,
673 	struct cfg80211_connect_params *sme);
674 static s32 wl_set_set_sharedkey(struct net_device *dev,
675 	struct cfg80211_connect_params *sme);
676 #ifdef WL_FILS
677 static s32 wl_set_fils_params(struct net_device *dev,
678 	struct cfg80211_connect_params *sme);
679 #endif
680 
681 #ifdef BCMWAPI_WPI
682 static s32 wl_set_set_wapi_ie(struct net_device *dev,
683 	struct cfg80211_connect_params *sme);
684 #endif
685 
686 #ifdef WL_GCMP
687 static s32 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask);
688 #endif /* WL_GCMP */
689 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
690 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
691 
692 /*
693  * information element utilities
694  */
695 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
696 
697 #ifdef MFP
698 static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie, const u8** rsn_cap);
699 #endif
700 
701 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, dhd_pub_t *data);
702 static void wl_free_wdev(struct bcm_cfg80211 *cfg);
703 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
704 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
705 static int
706 #else
707 static void
708 #endif /* kernel version < 3.10.11 */
709 wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
710 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
711 
712 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool update_ssid);
713 static void wl_cfg80211_work_handler(struct work_struct *work);
714 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
715 	u8 key_idx, const u8 *mac_addr,
716 	struct key_params *params);
717 /*
718  * key indianess swap utilities
719  */
720 static void swap_key_from_BE(struct wl_wsec_key *key);
721 static void swap_key_to_BE(struct wl_wsec_key *key);
722 
723 /*
724  * bcm_cfg80211 memory init/deinit utilities
725  */
726 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
727 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
728 
729 static void wl_delay(u32 ms);
730 
731 /*
732  * ibss mode utilities
733  */
734 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
735 
736 /*
737  * link up/down , default configuration utilities
738  */
739 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
740 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
741 
742 static void wl_link_up(struct bcm_cfg80211 *cfg);
743 static s32 wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as);
744 static s32 wl_post_linkup_ops(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as);
745 static void wl_link_down(struct bcm_cfg80211 *cfg);
746 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype);
747 static void wl_init_conf(struct wl_conf *conf);
748 int wl_cfg80211_get_ioctl_version(void);
749 
750 /*
751  * find most significant bit set
752  */
753 static __used u32 wl_find_msb(u16 bit16);
754 
755 /*
756  * rfkill support
757  */
758 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
759 static int wl_rfkill_set(void *data, bool blocked);
760 
761 /*
762  * Some external functions, TODO: move them to dhd_linux.h
763  */
764 int dhd_add_monitor(const char *name, struct net_device **new_ndev);
765 int dhd_del_monitor(struct net_device *ndev);
766 int dhd_monitor_init(void *dhd_pub);
767 int dhd_monitor_uninit(void);
768 netdev_tx_t dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
769 
770 #ifdef ROAM_CHANNEL_CACHE
771 int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
772 #endif /* ROAM_CHANNEL_CACHE */
773 
774 #ifdef P2P_LISTEN_OFFLOADING
775 s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
776 #endif /* P2P_LISTEN_OFFLOADING */
777 
778 #ifdef CUSTOMER_HW4_DEBUG
779 extern bool wl_scan_timeout_dbg_enabled;
780 #endif /* CUSTOMER_HW4_DEBUG */
781 #ifdef PKT_FILTER_SUPPORT
782 extern uint dhd_pkt_filter_enable;
783 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
784 #endif /* PKT_FILTER_SUPPORT */
785 
786 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
787 	const struct ether_addr *bssid);
788 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
789 
790 #ifdef WL_SDO
791 s32 wl_cfg80211_sdo_init(struct bcm_cfg80211 *cfg);
792 s32 wl_cfg80211_sdo_deinit(struct bcm_cfg80211 *cfg);
793 #define MAX_SDO_PROTO 5
794 wl_sdo_proto_t wl_sdo_protos [] = {
795 	{ "all", SVC_RPOTYPE_ALL },
796 	{ "upnp", SVC_RPOTYPE_UPNP },
797 	{ "bonjour", SVC_RPOTYPE_BONJOUR },
798 	{ "wsd", SVC_RPOTYPE_WSD },
799 	{ "vendor", SVC_RPOTYPE_VENDOR },
800 };
801 #endif
802 
803 #ifdef WL_WPS_SYNC
804 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg);
805 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg);
806 static void wl_wps_reauth_timeout(unsigned long data);
807 static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg);
808 static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev);
809 static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *peer_mac);
810 static void wl_wps_session_del(struct net_device *ndev);
811 s32 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac);
812 static void wl_wps_handle_ifdel(struct net_device *ndev);
813 #endif /* WL_WPS_SYNC */
814 
815 #if defined(WL_FW_OCE_AP_SELECT)
816 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint);
817 #endif /* WL_FW_OCE_AP_SELECT */
818 
819 #ifdef WL_BCNRECV
820 static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
821 		const wl_event_msg_t *e, void *data);
822 #endif /* WL_BCNRECV */
823 
824 #ifdef WL_CAC_TS
825 static s32 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
826 		const wl_event_msg_t *e, void *data);
827 #endif /* WL_CAC_TS */
828 
829 #if defined(WL_MBO) || defined(WL_OCE)
830 static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
831 		const wl_event_msg_t *e, void *data);
832 #endif /* WL_MBO || WL_OCE */
833 static void wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as,
834 		const wl_event_msg_t *event, wl_assoc_state_t assoc_state);
835 
836 #if !defined(BCMDONGLEHOST)
837 /* Wake lock are used in Android only, which is dongle based as of now */
838 #define DHD_OS_WAKE_LOCK(pub)
839 #define DHD_OS_WAKE_UNLOCK(pub)
840 #define DHD_EVENT_WAKE_LOCK(pub)
841 #define DHD_EVENT_WAKE_UNLOCK(pub)
842 #define DHD_OS_WAKE_LOCK_TIMEOUT(pub)
843 #endif /* defined(BCMDONGLEHOST) */
844 
845 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || \
846 	   (defined(CONFIG_ARCH_MSM) && defined(CFG80211_DISCONNECTED_V2))
847 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
848 	cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len,	\
849 			IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
850 #else
851 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
852 	cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len,	\
853 			WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
854 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
855 
856 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
857 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
858 	defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || \
859 	defined(WL_FILS) || defined(CONFIG_CFG80211_FILS_BKPORT)
860 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
861 		resp_ie_len, status, gfp) \
862 	cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
863 		resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
864 #else
865 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
866 		resp_ie_len, status, gfp) \
867 	cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
868 		resp_ie_len, status, gfp);
869 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
870 	* (CFG80211_CONNECT_TIMEOUT_REASON_CODE) ||
871 	* WL_FILS || CONFIG_CFG80211_FILS_BKPORT
872 	*/
873 #elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
874 /* There are customer kernels with backported changes for
875  *  connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
876  * is available for kernels < 4.7 in such cases.
877  */
878 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
879 		resp_ie_len, status, gfp) \
880 	cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
881 		resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
882 #else
883 /* Kernels < 4.7 doesn't support cfg80211_connect_bss */
884 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
885 		resp_ie_len, status, gfp) \
886 	cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
887 		resp_ie_len, status, gfp);
888 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
889 
890 #define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE ||			\
891 				 (akm) == RSN_AKM_UNSPECIFIED ||	\
892 				 (akm) == RSN_AKM_PSK)
893 
894 #define WL_EIDX_INVALID	0xffff
895 #define WL_SET_EIDX_IN_PROGRESS(cfg, id, type)	\
896 	{ cfg->eidx.in_progress = id; \
897 	cfg->eidx.event_type = type; }
898 #define WL_CLR_EIDX_STATES(cfg)	\
899 	cfg->eidx.in_progress = WL_EIDX_INVALID;
900 extern int dhd_wait_pend8021x(struct net_device *dev);
901 #ifdef PROP_TXSTATUS_VSDB
902 extern int disable_proptx;
903 #endif /* PROP_TXSTATUS_VSDB */
904 
905 /* WAR: disable pm_bcnrx , scan_ps for BCM4354 WISOL module.
906 * WISOL module have ANT_1 Rx sensitivity issue.
907 */
908 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
909 extern void dhd_force_disable_singlcore_scan(dhd_pub_t *dhd);
910 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
911 
912 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, 0)))
913 struct chan_info {
914 	int freq;
915 	int chan_type;
916 };
917 #endif
918 
919 #define RATE_TO_BASE100KBPS(rate)   (((rate) * 10) / 2)
920 #define RATETAB_ENT(_rateid, _flags) \
921 	{								\
922 		.bitrate	= RATE_TO_BASE100KBPS(_rateid),     \
923 		.hw_value	= (_rateid),			    \
924 		.flags	  = (_flags),			     \
925 	}
926 
927 static struct ieee80211_rate __wl_rates[] = {
928 	RATETAB_ENT(DOT11_RATE_1M, 0),
929 	RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
930 	RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
931 	RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
932 	RATETAB_ENT(DOT11_RATE_6M, 0),
933 	RATETAB_ENT(DOT11_RATE_9M, 0),
934 	RATETAB_ENT(DOT11_RATE_12M, 0),
935 	RATETAB_ENT(DOT11_RATE_18M, 0),
936 	RATETAB_ENT(DOT11_RATE_24M, 0),
937 	RATETAB_ENT(DOT11_RATE_36M, 0),
938 	RATETAB_ENT(DOT11_RATE_48M, 0),
939 	RATETAB_ENT(DOT11_RATE_54M, 0)
940 };
941 
942 #define wl_a_rates		(__wl_rates + 4)
943 #define wl_a_rates_size	8
944 #define wl_g_rates		(__wl_rates + 0)
945 #define wl_g_rates_size	12
946 
947 static struct ieee80211_channel __wl_2ghz_channels[] = {
948 	CHAN2G(1, 2412, 0),
949 	CHAN2G(2, 2417, 0),
950 	CHAN2G(3, 2422, 0),
951 	CHAN2G(4, 2427, 0),
952 	CHAN2G(5, 2432, 0),
953 	CHAN2G(6, 2437, 0),
954 	CHAN2G(7, 2442, 0),
955 	CHAN2G(8, 2447, 0),
956 	CHAN2G(9, 2452, 0),
957 	CHAN2G(10, 2457, 0),
958 	CHAN2G(11, 2462, 0),
959 	CHAN2G(12, 2467, 0),
960 	CHAN2G(13, 2472, 0),
961 	CHAN2G(14, 2484, 0)
962 };
963 
964 static struct ieee80211_channel __wl_5ghz_a_channels[] = {
965 	CHAN5G(34, 0), CHAN5G(36, 0),
966 	CHAN5G(38, 0), CHAN5G(40, 0),
967 	CHAN5G(42, 0), CHAN5G(44, 0),
968 	CHAN5G(46, 0), CHAN5G(48, 0),
969 	CHAN5G(52, 0), CHAN5G(56, 0),
970 	CHAN5G(60, 0), CHAN5G(64, 0),
971 	CHAN5G(100, 0), CHAN5G(104, 0),
972 	CHAN5G(108, 0), CHAN5G(112, 0),
973 	CHAN5G(116, 0), CHAN5G(120, 0),
974 	CHAN5G(124, 0), CHAN5G(128, 0),
975 	CHAN5G(132, 0), CHAN5G(136, 0),
976 	CHAN5G(140, 0), CHAN5G(144, 0),
977 	CHAN5G(149, 0), CHAN5G(153, 0),
978 	CHAN5G(157, 0), CHAN5G(161, 0),
979 	CHAN5G(165, 0),
980 
981 #if defined(WL_6G_BAND) && !defined(CFG80211_6G_SUPPORT)
982 	/* 6GHz frequency starting 5935 */
983 	CHAN6G_CHAN2(0), CHAN6G(1, 0),
984 	CHAN6G(5, 0), CHAN6G(9, 0),
985 	CHAN6G(13, 0), CHAN6G(17, 0),
986 	CHAN6G(21, 0), CHAN6G(25, 0),
987 	CHAN6G(29, 0), CHAN6G(33, 0),
988 	CHAN6G(37, 0), CHAN6G(41, 0),
989 	CHAN6G(45, 0), CHAN6G(49, 0),
990 	CHAN6G(53, 0), CHAN6G(57, 0),
991 	CHAN6G(61, 0), CHAN6G(65, 0),
992 	CHAN6G(69, 0), CHAN6G(73, 0),
993 	CHAN6G(77, 0), CHAN6G(81, 0),
994 	CHAN6G(85, 0), CHAN6G(89, 0),
995 	CHAN6G(93, 0), CHAN6G(97, 0),
996 	CHAN6G(101, 0), CHAN6G(105, 0),
997 	CHAN6G(109, 0), CHAN6G(113, 0),
998 	CHAN6G(117, 0), CHAN6G(121, 0),
999 	CHAN6G(125, 0), CHAN6G(129, 0),
1000 	CHAN6G(133, 0), CHAN6G(137, 0),
1001 	CHAN6G(141, 0), CHAN6G(145, 0),
1002 	CHAN6G(149, 0), CHAN6G(153, 0),
1003 	CHAN6G(157, 0), CHAN6G(161, 0),
1004 	CHAN6G(165, 0), CHAN6G(169, 0),
1005 	CHAN6G(173, 0), CHAN6G(177, 0),
1006 	CHAN6G(181, 0), CHAN6G(185, 0),
1007 	CHAN6G(189, 0), CHAN6G(193, 0),
1008 	CHAN6G(197, 0), CHAN6G(201, 0),
1009 	CHAN6G(205, 0), CHAN6G(209, 0),
1010 	CHAN6G(213, 0), CHAN6G(217, 0),
1011 	CHAN6G(221, 0), CHAN6G(225, 0),
1012 	CHAN6G(229, 0), CHAN6G(233, 0),
1013 
1014 	CHAN6G(3, 0), CHAN6G(11, 0),
1015 	CHAN6G(19, 0), CHAN6G(27, 0),
1016 	CHAN6G(35, 0), CHAN6G(43, 0),
1017 	CHAN6G(51, 0), CHAN6G(59, 0),
1018 	CHAN6G(67, 0), CHAN6G(75, 0),
1019 	CHAN6G(83, 0), CHAN6G(91, 0),
1020 	CHAN6G(99, 0), CHAN6G(107, 0),
1021 	CHAN6G(115, 0), CHAN6G(123, 0),
1022 	CHAN6G(131, 0), CHAN6G(139, 0),
1023 	CHAN6G(147, 0), CHAN6G(155, 0),
1024 	CHAN6G(163, 0), CHAN6G(171, 0),
1025 	CHAN6G(179, 0), CHAN6G(187, 0),
1026 	CHAN6G(195, 0), CHAN6G(203, 0),
1027 	CHAN6G(211, 0), CHAN6G(219, 0), CHAN6G(227, 0),
1028 
1029 	CHAN6G(7, 0), CHAN6G(23, 0),
1030 	CHAN6G(39, 0), CHAN6G(55, 0),
1031 	CHAN6G(71, 0), CHAN6G(87, 0),
1032 	CHAN6G(103, 0), CHAN6G(119, 0),
1033 	CHAN6G(135, 0), CHAN6G(151, 0),
1034 	CHAN6G(167, 0), CHAN6G(183, 0),
1035 	CHAN6G(199, 0), CHAN6G(215, 0),
1036 
1037 	CHAN6G(15, 0), CHAN6G(47, 0),
1038 	CHAN6G(79, 0), CHAN6G(111, 0),
1039 	CHAN6G(143, 0), CHAN6G(175, 0), CHAN6G(207, 0),
1040 #endif /* WL_6G_BAND && !CFG80211_6G_SUPPORT */
1041 };
1042 
1043 #ifdef CFG80211_6G_SUPPORT
1044 static struct ieee80211_channel __wl_6ghz_channels[] = {
1045 	CHAN6G_CHAN2(0), CHAN6G(1, 0),
1046 	CHAN6G(5, 0), CHAN6G(9, 0),
1047 	CHAN6G(13, 0), CHAN6G(17, 0),
1048 	CHAN6G(21, 0), CHAN6G(25, 0),
1049 	CHAN6G(29, 0), CHAN6G(33, 0),
1050 	CHAN6G(37, 0), CHAN6G(41, 0),
1051 	CHAN6G(45, 0), CHAN6G(49, 0),
1052 	CHAN6G(53, 0), CHAN6G(57, 0),
1053 	CHAN6G(61, 0), CHAN6G(65, 0),
1054 	CHAN6G(69, 0), CHAN6G(73, 0),
1055 	CHAN6G(77, 0), CHAN6G(81, 0),
1056 	CHAN6G(85, 0), CHAN6G(89, 0),
1057 	CHAN6G(93, 0), CHAN6G(97, 0),
1058 	CHAN6G(101, 0), CHAN6G(105, 0),
1059 	CHAN6G(109, 0), CHAN6G(113, 0),
1060 	CHAN6G(117, 0), CHAN6G(121, 0),
1061 	CHAN6G(125, 0), CHAN6G(129, 0),
1062 	CHAN6G(133, 0), CHAN6G(137, 0),
1063 	CHAN6G(141, 0), CHAN6G(145, 0),
1064 	CHAN6G(149, 0), CHAN6G(153, 0),
1065 	CHAN6G(157, 0), CHAN6G(161, 0),
1066 	CHAN6G(165, 0), CHAN6G(169, 0),
1067 	CHAN6G(173, 0), CHAN6G(177, 0),
1068 	CHAN6G(181, 0), CHAN6G(185, 0),
1069 	CHAN6G(189, 0), CHAN6G(193, 0),
1070 	CHAN6G(197, 0), CHAN6G(201, 0),
1071 	CHAN6G(205, 0), CHAN6G(209, 0),
1072 	CHAN6G(213, 0), CHAN6G(217, 0),
1073 	CHAN6G(221, 0), CHAN6G(225, 0),
1074 	CHAN6G(229, 0), CHAN6G(233, 0),
1075 };
1076 #endif /* CFG80211_6G_SUPPORT */
1077 
1078 static struct ieee80211_supported_band __wl_band_2ghz = {
1079 	.band = IEEE80211_BAND_2GHZ,
1080 	.channels = __wl_2ghz_channels,
1081 	.n_channels = ARRAY_SIZE(__wl_2ghz_channels),
1082 	.bitrates = wl_g_rates,
1083 	.n_bitrates = wl_g_rates_size
1084 };
1085 
1086 static struct ieee80211_supported_band __wl_band_5ghz_a = {
1087 	.band = IEEE80211_BAND_5GHZ,
1088 	.channels = __wl_5ghz_a_channels,
1089 	.n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
1090 	.bitrates = wl_a_rates,
1091 	.n_bitrates = wl_a_rates_size
1092 };
1093 
1094 #ifdef CFG80211_6G_SUPPORT
1095 static struct ieee80211_supported_band __wl_band_6ghz = {
1096 	.band = IEEE80211_BAND_6GHZ,
1097 	.channels = __wl_6ghz_channels,
1098 	.n_channels = ARRAY_SIZE(__wl_6ghz_channels),
1099 	.bitrates = wl_a_rates,
1100 	.n_bitrates = wl_a_rates_size
1101 };
1102 #endif /* CFG80211_6G_SUPPORT */
1103 
1104 static const u32 __wl_cipher_suites[] = {
1105 	WLAN_CIPHER_SUITE_WEP40,
1106 	WLAN_CIPHER_SUITE_WEP104,
1107 	WLAN_CIPHER_SUITE_TKIP,
1108 	WLAN_CIPHER_SUITE_CCMP,
1109 #ifdef MFP
1110 	/*
1111 	 * Advertising AES_CMAC cipher suite to userspace would imply that we
1112 	 * are supporting MFP. So advertise only when MFP support is enabled.
1113 	 */
1114 	WLAN_CIPHER_SUITE_AES_CMAC,
1115 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1116 	WLAN_CIPHER_SUITE_BIP_GMAC_256,
1117 	WLAN_CIPHER_SUITE_BIP_GMAC_128,
1118 	WLAN_CIPHER_SUITE_BIP_CMAC_256,
1119 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1120 #endif /* MFP */
1121 
1122 #ifdef BCMWAPI_WPI
1123 	WLAN_CIPHER_SUITE_SMS4,
1124 #endif
1125 
1126 #if defined(WLAN_CIPHER_SUITE_PMK)
1127 	WLAN_CIPHER_SUITE_PMK,
1128 #endif /* WLAN_CIPHER_SUITE_PMK */
1129 #ifdef WL_GCMP
1130 	WLAN_CIPHER_SUITE_GCMP,
1131 	WLAN_CIPHER_SUITE_GCMP_256,
1132 	WLAN_CIPHER_SUITE_BIP_GMAC_128,
1133 	WLAN_CIPHER_SUITE_BIP_GMAC_256,
1134 #endif /* WL_GCMP */
1135 };
1136 
1137 #ifdef WL_SUPPORT_ACS
1138 /*
1139  * The firmware code required for this feature to work is currently under
1140  * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1141  * required firmware code out of the BCMINTERNAL flag.
1142  */
1143 struct wl_dump_survey {
1144 	u32 obss;
1145 	u32 ibss;
1146 	u32 no_ctg;
1147 	u32 no_pckt;
1148 	u32 tx;
1149 	u32 idle;
1150 };
1151 #endif /* WL_SUPPORT_ACS */
1152 
1153 #ifdef WL_CFG80211_GON_COLLISION
1154 #define BLOCK_GON_REQ_MAX_NUM 5
1155 #endif /* WL_CFG80211_GON_COLLISION */
1156 
1157 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1158 static int maxrxpktglom = 0;
1159 #endif
1160 
1161 /* IOCtl version read from targeted driver */
1162 int ioctl_version;
1163 
1164 typedef struct rsn_cipher_algo_entry {
1165 	u32 cipher_suite;
1166 	u32 wsec_algo;
1167 	u32 wsec_key_algo;
1168 } rsn_cipher_algo_entry_t;
1169 
1170 static const rsn_cipher_algo_entry_t rsn_cipher_algo_lookup_tbl[] = {
1171 	{WLAN_CIPHER_SUITE_WEP40, WEP_ENABLED, CRYPTO_ALGO_WEP1},
1172 	{WLAN_CIPHER_SUITE_WEP104, WEP_ENABLED, CRYPTO_ALGO_WEP128},
1173 	{WLAN_CIPHER_SUITE_TKIP, TKIP_ENABLED, CRYPTO_ALGO_TKIP},
1174 	{WLAN_CIPHER_SUITE_CCMP, AES_ENABLED, CRYPTO_ALGO_AES_CCM},
1175 	{WLAN_CIPHER_SUITE_AES_CMAC, AES_ENABLED, CRYPTO_ALGO_BIP},
1176 
1177 #ifdef BCMWAPI_WPI
1178 	{WLAN_CIPHER_SUITE_SMS4, SMS4_ENABLED, CRYPTO_ALGO_SMS4},
1179 #endif /* BCMWAPI_WPI */
1180 
1181 #ifdef WL_GCMP
1182 	{WLAN_CIPHER_SUITE_GCMP, AES_ENABLED, CRYPTO_ALGO_AES_GCM},
1183 	{WLAN_CIPHER_SUITE_GCMP_256, AES_ENABLED, CRYPTO_ALGO_AES_GCM256},
1184 	{WLAN_CIPHER_SUITE_BIP_GMAC_128, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC},
1185 	{WLAN_CIPHER_SUITE_BIP_GMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC256},
1186 #endif /* WL_GCMP */
1187 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1188 	{WLAN_CIPHER_SUITE_BIP_CMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_CMAC256},
1189 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1190 };
1191 
1192 typedef struct rsn_akm_wpa_auth_entry {
1193 	u32 akm_suite;
1194 	u32 wpa_auth;
1195 } rsn_akm_wpa_auth_entry_t;
1196 
1197 static const rsn_akm_wpa_auth_entry_t rsn_akm_wpa_auth_lookup_tbl[] = {
1198 #ifdef WL_OWE
1199 	{WLAN_AKM_SUITE_OWE, WPA3_AUTH_OWE},
1200 #endif /* WL_OWE */
1201 	{WLAN_AKM_SUITE_8021X, WPA2_AUTH_UNSPECIFIED},
1202 	{WL_AKM_SUITE_SHA256_1X, WPA2_AUTH_1X_SHA256},
1203 	{WL_AKM_SUITE_SHA256_PSK, WPA2_AUTH_PSK_SHA256},
1204 	{WLAN_AKM_SUITE_PSK, WPA2_AUTH_PSK},
1205 	{WLAN_AKM_SUITE_FT_8021X, WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT},
1206 	{WLAN_AKM_SUITE_FT_PSK, WPA2_AUTH_PSK | WPA2_AUTH_FT},
1207 	{WLAN_AKM_SUITE_FILS_SHA256, WPA2_AUTH_FILS_SHA256},
1208 	{WLAN_AKM_SUITE_FILS_SHA384, WPA2_AUTH_FILS_SHA384},
1209 	{WLAN_AKM_SUITE_8021X_SUITE_B, WPA3_AUTH_1X_SUITE_B_SHA256},
1210 	{WLAN_AKM_SUITE_8021X_SUITE_B_192, WPA3_AUTH_1X_SUITE_B_SHA384},
1211 
1212 #ifdef BCMWAPI_WPI
1213 	{WLAN_AKM_SUITE_WAPI_CERT, WAPI_AUTH_UNSPECIFIED},
1214 	{WLAN_AKM_SUITE_WAPI_PSK, WAPI_AUTH_PSK},
1215 #endif /* BCMWAPI_WPI */
1216 
1217 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
1218 	{WLAN_AKM_SUITE_SAE, WPA3_AUTH_SAE_PSK},
1219 #endif /* WL_SAE || WL_CLIENT_SAE */
1220 #ifdef WL_SAE_FT
1221 	{WLAN_AKM_SUITE_FT_OVER_SAE, WPA3_AUTH_SAE_PSK | WPA2_AUTH_FT},
1222 #endif /* WL_SAE_FT */
1223 	{WLAN_AKM_SUITE_DPP, WPA3_AUTH_DPP_AKM},
1224 	{WLAN_AKM_SUITE_FT_8021X_SHA384, WPA3_AUTH_1X_SUITE_B_SHA384 | WPA2_AUTH_FT}
1225 };
1226 
1227 #define BUFSZ 8
1228 #define BUFSZN	BUFSZ + 1
1229 
1230 #define _S(x) #x
1231 #define S(x) _S(x)
1232 
1233 #define SOFT_AP_IF_NAME         "swlan0"
1234 
1235 /* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1236 uint32 fw_assoc_watchdog_ms = 0;
1237 bool fw_assoc_watchdog_started = 0;
1238 #define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1239 
wl_channel_to_frequency(u32 chan,chanspec_band_t band)1240 int wl_channel_to_frequency(u32 chan, chanspec_band_t band)
1241 {
1242 	if (chan == 0) {
1243 		return 0; /* not supported */
1244 	}
1245 	switch (band) {
1246 	case WL_CHANSPEC_BAND_2G:
1247 		if (chan == 14)
1248 			return 2484;
1249 		else if (chan < 14)
1250 			return 2407 + chan * 5;
1251 		break;
1252 	case WL_CHANSPEC_BAND_5G:
1253 		if (chan >= 182 && chan <= 196)
1254 			return 4000 + chan * 5;
1255 		else
1256 			return 5000 + chan * 5;
1257 		break;
1258 #ifdef WL_6G_BAND
1259 	case WL_CHANSPEC_BAND_6G:
1260 		if (chan == 2) {
1261 			/* Specific handling for channel 2 in 6G */
1262 			return 5935;
1263 		}
1264 		return 5950 + chan * 5;
1265 		break;
1266 #endif /* WL_6G_BAND */
1267 	default:
1268 		WL_ERR(("Invalid Frequency Band\n"));
1269 	}
1270 	return 0; /* not supported */
1271 }
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 
1278 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1279 	dhd_pub_t *dhd =  NULL;
1280 #endif /* BCMDONGLEHOST && OEM_ANDROID */
1281 
1282 	if (cfg == NULL)
1283 		return;
1284 
1285 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1286 	dhd = (dhd_pub_t *)(cfg->pub);
1287 #endif /* BCMDONGLEHOST && OEM_ANDROID */
1288 
1289 	mutex_lock(&cfg->pm_sync);
1290 	/*
1291 	 * Make cancel and schedule work part mutually exclusive
1292 	 * so that while cancelling, we are sure that there is no
1293 	 * work getting scheduled.
1294 	 */
1295 	if (delayed_work_pending(&cfg->pm_enable_work)) {
1296 		cancel_delayed_work(&cfg->pm_enable_work);
1297 
1298 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1299 		DHD_PM_WAKE_UNLOCK(cfg->pub);
1300 #endif /* BCMDONGLEHOST && OEM_ANDROID */
1301 
1302 	}
1303 
1304 	if (type == WL_PM_WORKQ_SHORT) {
1305 		wq_duration = WL_PM_ENABLE_TIMEOUT;
1306 	} else if (type == WL_PM_WORKQ_LONG) {
1307 		wq_duration = (WL_PM_ENABLE_TIMEOUT*2);
1308 	}
1309 
1310 	/* It should schedule work item only if driver is up */
1311 	if (wq_duration) {
1312 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1313 		if (dhd->up)
1314 #endif /* defined(BCMDONGLEHOST) && defined(OEM_ANDROID) */
1315 		{
1316 			if (schedule_delayed_work(&cfg->pm_enable_work,
1317 				msecs_to_jiffies((const unsigned int)wq_duration))) {
1318 
1319 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1320 				DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub, wq_duration);
1321 #endif /* BCMDONGLEHOST && OEM_ANDROID */
1322 			} else {
1323 				WL_ERR(("Can't schedule pm work handler\n"));
1324 			}
1325 		}
1326 	}
1327 	mutex_unlock(&cfg->pm_sync);
1328 }
1329 
1330 /* Return a new chanspec given a legacy chanspec
1331  * Returns INVCHANSPEC on error
1332  */
1333 chanspec_t
wl_chspec_from_legacy(chanspec_t legacy_chspec)1334 wl_chspec_from_legacy(chanspec_t legacy_chspec)
1335 {
1336 	chanspec_t chspec;
1337 
1338 	/* get the channel number */
1339 	chspec = LCHSPEC_CHANNEL(legacy_chspec);
1340 
1341 	/* convert the band */
1342 	if (LCHSPEC_IS2G(legacy_chspec)) {
1343 		chspec |= WL_CHANSPEC_BAND_2G;
1344 	} else {
1345 		chspec |= WL_CHANSPEC_BAND_5G;
1346 	}
1347 
1348 	/* convert the bw and sideband */
1349 	if (LCHSPEC_IS20(legacy_chspec)) {
1350 		chspec |= WL_CHANSPEC_BW_20;
1351 	} else {
1352 		chspec |= WL_CHANSPEC_BW_40;
1353 		if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
1354 			chspec |= WL_CHANSPEC_CTL_SB_L;
1355 		} else {
1356 			chspec |= WL_CHANSPEC_CTL_SB_U;
1357 		}
1358 	}
1359 
1360 	if (wf_chspec_malformed(chspec)) {
1361 		WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1362 			chspec));
1363 		return INVCHANSPEC;
1364 	}
1365 
1366 	return chspec;
1367 }
1368 
1369 /* Return a legacy chanspec given a new chanspec
1370  * Returns INVCHANSPEC on error
1371  */
1372 static chanspec_t
wl_chspec_to_legacy(chanspec_t chspec)1373 wl_chspec_to_legacy(chanspec_t chspec)
1374 {
1375 	chanspec_t lchspec;
1376 
1377 	if (wf_chspec_malformed(chspec)) {
1378 		WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1379 			chspec));
1380 		return INVCHANSPEC;
1381 	}
1382 
1383 	/* get the channel number */
1384 	lchspec = CHSPEC_CHANNEL(chspec);
1385 
1386 	/* convert the band */
1387 	if (CHSPEC_IS2G(chspec)) {
1388 		lchspec |= WL_LCHANSPEC_BAND_2G;
1389 	} else {
1390 		lchspec |= WL_LCHANSPEC_BAND_5G;
1391 	}
1392 
1393 	/* convert the bw and sideband */
1394 	if (CHSPEC_IS20(chspec)) {
1395 		lchspec |= WL_LCHANSPEC_BW_20;
1396 		lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
1397 	} else if (CHSPEC_IS40(chspec)) {
1398 		lchspec |= WL_LCHANSPEC_BW_40;
1399 		if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
1400 			lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
1401 		} else {
1402 			lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
1403 		}
1404 	} else {
1405 		/* cannot express the bandwidth */
1406 		char chanbuf[CHANSPEC_STR_LEN];
1407 		WL_ERR((
1408 			"wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1409 			"to pre-11ac format\n",
1410 			wf_chspec_ntoa(chspec, chanbuf), chspec));
1411 		return INVCHANSPEC;
1412 	}
1413 
1414 	return lchspec;
1415 }
1416 
wl_cfg80211_is_hal_started(struct bcm_cfg80211 * cfg)1417 bool wl_cfg80211_is_hal_started(struct bcm_cfg80211 *cfg)
1418 {
1419 	return cfg->hal_started;
1420 }
1421 
1422 /* given a chanspec value, do the endian and chanspec version conversion to
1423  * a chanspec_t value
1424  * Returns INVCHANSPEC on error
1425  */
1426 chanspec_t
wl_chspec_host_to_driver(chanspec_t chanspec)1427 wl_chspec_host_to_driver(chanspec_t chanspec)
1428 {
1429 	if (ioctl_version == 1) {
1430 		chanspec = wl_chspec_to_legacy(chanspec);
1431 		if (chanspec == INVCHANSPEC) {
1432 			return chanspec;
1433 		}
1434 	}
1435 	chanspec = htodchanspec(chanspec);
1436 
1437 	return chanspec;
1438 }
1439 
1440 /* given a channel value, do the endian and chanspec version conversion to
1441  * a chanspec_t value
1442  * Returns INVCHANSPEC on error
1443  */
1444 chanspec_t
wl_ch_host_to_driver(u16 channel)1445 wl_ch_host_to_driver(u16 channel)
1446 {
1447 	chanspec_t chanspec;
1448 	chanspec_band_t band;
1449 
1450 	band = WL_CHANNEL_BAND(channel);
1451 
1452 	chanspec = wf_create_20MHz_chspec(channel, band);
1453 	if (chanspec == INVCHANSPEC) {
1454 		return chanspec;
1455 	}
1456 
1457 	return wl_chspec_host_to_driver(chanspec);
1458 }
1459 
1460 /* given a chanspec value from the driver, do the endian and chanspec version conversion to
1461  * a chanspec_t value
1462  * Returns INVCHANSPEC on error
1463  */
1464 chanspec_t
wl_chspec_driver_to_host(chanspec_t chanspec)1465 wl_chspec_driver_to_host(chanspec_t chanspec)
1466 {
1467 	chanspec = dtohchanspec(chanspec);
1468 	if (ioctl_version == 1) {
1469 		chanspec = wl_chspec_from_legacy(chanspec);
1470 	}
1471 
1472 	return chanspec;
1473 }
1474 
1475 /*
1476  * convert ASCII string to MAC address (colon-delimited format)
1477  * eg: 00:11:22:33:44:55
1478  */
1479 int
wl_cfg80211_ether_atoe(const char * a,struct ether_addr * n)1480 wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
1481 {
1482 	char *c = NULL;
1483 	int count = 0;
1484 
1485 	bzero(n, ETHER_ADDR_LEN);
1486 	for (;;) {
1487 		n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
1488 		if (!*c++ || count == ETHER_ADDR_LEN)
1489 			break;
1490 		a = c;
1491 	}
1492 	return (count == ETHER_ADDR_LEN);
1493 }
1494 
1495 /* There isn't a lot of sense in it, but you can transmit anything you like */
1496 static const struct ieee80211_txrx_stypes
1497 wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1498 #ifdef WLMESH_CFG80211
1499 	[NL80211_IFTYPE_MESH_POINT] = {
1500 		.tx = 0xffff,
1501 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1502 		BIT(IEEE80211_STYPE_AUTH >> 4)
1503 	},
1504 #endif /* WLMESH_CFG80211 */
1505 	[NL80211_IFTYPE_ADHOC] = {
1506 		.tx = 0xffff,
1507 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4)
1508 	},
1509 	[NL80211_IFTYPE_STATION] = {
1510 		.tx = 0xffff,
1511 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1512 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1513 #ifdef WL_CLIENT_SAE
1514 		| BIT(IEEE80211_STYPE_AUTH >> 4)
1515 #endif /* WL_CLIENT_SAE */
1516 	},
1517 	[NL80211_IFTYPE_AP] = {
1518 		.tx = 0xffff,
1519 		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1520 		BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1521 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1522 		BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1523 		BIT(IEEE80211_STYPE_AUTH >> 4) |
1524 		BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1525 		BIT(IEEE80211_STYPE_ACTION >> 4)
1526 	},
1527 	[NL80211_IFTYPE_AP_VLAN] = {
1528 		/* copy AP */
1529 		.tx = 0xffff,
1530 		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1531 		BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1532 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1533 		BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1534 		BIT(IEEE80211_STYPE_AUTH >> 4) |
1535 		BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1536 		BIT(IEEE80211_STYPE_ACTION >> 4)
1537 	},
1538 	[NL80211_IFTYPE_P2P_CLIENT] = {
1539 		.tx = 0xffff,
1540 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1541 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1542 	},
1543 	[NL80211_IFTYPE_P2P_GO] = {
1544 		.tx = 0xffff,
1545 		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1546 		BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1547 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1548 		BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1549 		BIT(IEEE80211_STYPE_AUTH >> 4) |
1550 		BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1551 		BIT(IEEE80211_STYPE_ACTION >> 4)
1552 	},
1553 #if defined(WL_CFG80211_P2P_DEV_IF)
1554 	[NL80211_IFTYPE_P2P_DEVICE] = {
1555 		.tx = 0xffff,
1556 		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1557 		BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1558 	},
1559 #endif /* WL_CFG80211_P2P_DEV_IF */
1560 };
1561 
swap_key_from_BE(struct wl_wsec_key * key)1562 static void swap_key_from_BE(struct wl_wsec_key *key)
1563 {
1564 	key->index = htod32(key->index);
1565 	key->len = htod32(key->len);
1566 	key->algo = htod32(key->algo);
1567 	key->flags = htod32(key->flags);
1568 	key->rxiv.hi = htod32(key->rxiv.hi);
1569 	key->rxiv.lo = htod16(key->rxiv.lo);
1570 	key->iv_initialized = htod32(key->iv_initialized);
1571 }
1572 
swap_key_to_BE(struct wl_wsec_key * key)1573 static void swap_key_to_BE(struct wl_wsec_key *key)
1574 {
1575 	key->index = dtoh32(key->index);
1576 	key->len = dtoh32(key->len);
1577 	key->algo = dtoh32(key->algo);
1578 	key->flags = dtoh32(key->flags);
1579 	key->rxiv.hi = dtoh32(key->rxiv.hi);
1580 	key->rxiv.lo = dtoh16(key->rxiv.lo);
1581 	key->iv_initialized = dtoh32(key->iv_initialized);
1582 }
1583 
1584 #if defined(WL_FW_OCE_AP_SELECT)
wl_cfg80211_is_oce_ap(struct wiphy * wiphy,const u8 * bssid_hint)1585 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint)
1586 {
1587 	const u8 *parse = NULL;
1588 	bcm_tlv_t *ie;
1589 	const struct cfg80211_bss_ies *ies;
1590 	u32 len;
1591 	struct cfg80211_bss *bss;
1592 
1593 	bss = CFG80211_GET_BSS(wiphy, NULL, bssid_hint, 0, 0);
1594 	if (!bss) {
1595 		WL_ERR(("Unable to find AP in the cache"));
1596 		return false;
1597 	}
1598 
1599 	if (rcu_access_pointer(bss->ies)) {
1600 		ies = rcu_access_pointer(bss->ies);
1601 		parse = ies->data;
1602 		len = ies->len;
1603 	} else {
1604 		WL_ERR(("ies is NULL"));
1605 		return false;
1606 	}
1607 
1608 	while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_VS_ID))) {
1609 		if (wl_cfgoce_is_oce_ie((const uint8*)ie, (u8 const **)&parse, &len) == TRUE) {
1610 			return true;
1611 		} else {
1612 			ie = bcm_next_tlv((const bcm_tlv_t*) ie, &len);
1613 			if (!ie) {
1614 				return false;
1615 			}
1616 			parse = (uint8 *)ie;
1617 			WL_DBG(("NON OCE IE. next ie ptr:%p", parse));
1618 		}
1619 	}
1620 	WL_DBG(("OCE IE NOT found"));
1621 	return false;
1622 }
1623 #endif /* WL_FW_OCE_AP_SELECT */
1624 
1625 /* Dump the contents of the encoded wps ie buffer and get pbc value */
1626 static void
wl_validate_wps_ie(const char * wps_ie,s32 wps_ie_len,bool * pbc)1627 wl_validate_wps_ie(const char *wps_ie, s32 wps_ie_len, bool *pbc)
1628 {
1629 	#define WPS_IE_FIXED_LEN 6
1630 	s16 len;
1631 	const u8 *subel = NULL;
1632 	u16 subelt_id;
1633 	u16 subelt_len;
1634 	u16 val;
1635 	u8 *valptr = (uint8*) &val;
1636 	if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
1637 		WL_ERR(("invalid argument : NULL\n"));
1638 		return;
1639 	}
1640 	len = (s16)wps_ie[TLV_LEN_OFF];
1641 
1642 	if (len > wps_ie_len) {
1643 		WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
1644 		return;
1645 	}
1646 	WL_DBG(("wps_ie len=%d\n", len));
1647 	len -= 4;	/* for the WPS IE's OUI, oui_type fields */
1648 	subel = wps_ie + WPS_IE_FIXED_LEN;
1649 	while (len >= 4) {		/* must have attr id, attr len fields */
1650 		valptr[0] = *subel++;
1651 		valptr[1] = *subel++;
1652 		subelt_id = HTON16(val);
1653 
1654 		valptr[0] = *subel++;
1655 		valptr[1] = *subel++;
1656 		subelt_len = HTON16(val);
1657 
1658 		len -= 4;			/* for the attr id, attr len fields */
1659 		len -= (s16)subelt_len;	/* for the remaining fields in this attribute */
1660 		if (len < 0) {
1661 			break;
1662 		}
1663 		WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
1664 			subel, subelt_id, subelt_len));
1665 
1666 		if (subelt_id == WPS_ID_VERSION) {
1667 			WL_DBG(("  attr WPS_ID_VERSION: %u\n", *subel));
1668 		} else if (subelt_id == WPS_ID_REQ_TYPE) {
1669 			WL_DBG(("  attr WPS_ID_REQ_TYPE: %u\n", *subel));
1670 		} else if (subelt_id == WPS_ID_CONFIG_METHODS) {
1671 			valptr[0] = *subel;
1672 			valptr[1] = *(subel + 1);
1673 			WL_DBG(("  attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
1674 		} else if (subelt_id == WPS_ID_DEVICE_NAME) {
1675 			char devname[33];
1676 			int namelen = MIN(subelt_len, (sizeof(devname) - 1));
1677 
1678 			if (namelen) {
1679 				memcpy(devname, subel, namelen);
1680 				devname[namelen] = '\0';
1681 				/* Printing len as rx'ed in the IE */
1682 				WL_DBG(("  attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1683 					devname, subelt_len));
1684 			}
1685 		} else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
1686 			valptr[0] = *subel;
1687 			valptr[1] = *(subel + 1);
1688 			WL_DBG(("  attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
1689 			*pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
1690 		} else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
1691 			valptr[0] = *subel;
1692 			valptr[1] = *(subel + 1);
1693 			WL_DBG(("  attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
1694 			valptr[0] = *(subel + 6);
1695 			valptr[1] = *(subel + 7);
1696 			WL_DBG(("  attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
1697 		} else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
1698 			valptr[0] = *subel;
1699 			valptr[1] = *(subel + 1);
1700 			WL_DBG(("  attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
1701 			valptr[0] = *(subel + 6);
1702 			valptr[1] = *(subel + 7);
1703 			WL_DBG(("  attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
1704 		} else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
1705 			valptr[0] = *subel;
1706 			valptr[1] = *(subel + 1);
1707 			WL_DBG(("  attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1708 				": cat=%u\n", HTON16(val)));
1709 		} else {
1710 			WL_DBG(("  unknown attr 0x%x\n", subelt_id));
1711 		}
1712 
1713 		subel += subelt_len;
1714 	}
1715 }
1716 
wl_set_tx_power(struct net_device * dev,enum nl80211_tx_power_setting type,s32 dbm)1717 s32 wl_set_tx_power(struct net_device *dev,
1718 	enum nl80211_tx_power_setting type, s32 dbm)
1719 {
1720 	s32 err = 0;
1721 	s32 disable = 0;
1722 	s32 txpwrqdbm;
1723 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1724 
1725 	/* Make sure radio is off or on as far as software is concerned */
1726 	disable = WL_RADIO_SW_DISABLE << 16;
1727 	disable = htod32(disable);
1728 	err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable));
1729 	if (unlikely(err)) {
1730 		WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
1731 		return err;
1732 	}
1733 
1734 	if (dbm > 0xffff)
1735 		dbm = 0xffff;
1736 	txpwrqdbm = dbm * 4;
1737 #ifdef SUPPORT_WL_TXPOWER
1738 	if (type == NL80211_TX_POWER_AUTOMATIC)
1739 		txpwrqdbm = 127;
1740 	else
1741 		txpwrqdbm |= WL_TXPWR_OVERRIDE;
1742 #endif /* SUPPORT_WL_TXPOWER */
1743 	err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
1744 		sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
1745 		&cfg->ioctl_buf_sync);
1746 	if (unlikely(err))
1747 		WL_ERR(("qtxpower error (%d)\n", err));
1748 	else
1749 		WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
1750 
1751 	return err;
1752 }
1753 
wl_get_tx_power(struct net_device * dev,s32 * dbm)1754 s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
1755 {
1756 	s32 err = 0;
1757 	s32 txpwrdbm;
1758 	char ioctl_buf[WLC_IOCTL_SMLEN];
1759 
1760 	err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
1761 		NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
1762 	if (unlikely(err)) {
1763 		WL_ERR(("error (%d)\n", err));
1764 		return err;
1765 	}
1766 
1767 	memcpy(&txpwrdbm, ioctl_buf, sizeof(txpwrdbm));
1768 	txpwrdbm = dtoh32(txpwrdbm);
1769 	*dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
1770 
1771 	WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
1772 
1773 	return err;
1774 }
1775 
wl_cfg80211_get_shared_freq(struct wiphy * wiphy)1776 chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
1777 {
1778 	chanspec_t chspec;
1779 	int cur_band, err = 0;
1780 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1781 	struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
1782 	struct ether_addr bssid;
1783 	wl_bss_info_t *bss = NULL;
1784 	u16 channel = WL_P2P_TEMP_CHAN;
1785 	char *buf;
1786 
1787 	bzero(&bssid, sizeof(bssid));
1788 	if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) {
1789 		/* STA interface is not associated. So start the new interface on a temp
1790 		 * channel . Later proper channel will be applied by the above framework
1791 		 * via set_channel (cfg80211 API).
1792 		 */
1793 		WL_DBG(("Not associated. Return a temp channel. \n"));
1794 		cur_band = 0;
1795 		err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(int));
1796 		if (unlikely(err)) {
1797 			WL_ERR(("Get band failed\n"));
1798 		} else if (cur_band == WLC_BAND_5G || cur_band == WLC_BAND_6G) {
1799 			channel = WL_P2P_TEMP_CHAN_5G;
1800 		}
1801 		return wl_ch_host_to_driver(channel);
1802 	}
1803 
1804 	buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
1805 	if (!buf) {
1806 		WL_ERR(("buf alloc failed. use temp channel\n"));
1807 		return wl_ch_host_to_driver(channel);
1808 	}
1809 
1810 	*(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1811 	if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf,
1812 		WL_EXTRA_BUF_MAX))) {
1813 			WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1814 			chspec = wl_ch_host_to_driver(channel);
1815 	}
1816 	else {
1817 			bss = (wl_bss_info_t *) (buf + 4);
1818 			chspec =  bss->chanspec;
1819 #ifdef WL_6G_BAND
1820 			/* Avoid p2p bring up in 6G based on bssinfo */
1821 			if (CHSPEC_IS6G(chspec)) {
1822 				channel = WL_P2P_TEMP_CHAN_5G;
1823 				chspec = wl_ch_host_to_driver(channel);
1824 			}
1825 #endif /* WL_6G_BAND */
1826 			WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
1827 	}
1828 
1829 	MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
1830 	return chspec;
1831 }
1832 
1833 static void
wl_wlfc_enable(struct bcm_cfg80211 * cfg,bool enable)1834 wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable)
1835 {
1836 #ifdef PROP_TXSTATUS_VSDB
1837 #if defined(BCMSDIO) || defined(BCMDBUS)
1838 	bool wlfc_enabled = FALSE;
1839 	s32 err, up =1;
1840 	dhd_pub_t *dhd;
1841 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1842 
1843 	dhd = (dhd_pub_t *)(cfg->pub);
1844 	if (!dhd) {
1845 		return;
1846 	}
1847 
1848 	if (enable) {
1849 		if (!cfg->wlfc_on && !disable_proptx) {
1850 			dhd_wlfc_get_enable(dhd, &wlfc_enabled);
1851 			if (!wlfc_enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1852 				dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1853 				dhd_wlfc_init(dhd);
1854 				err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32));
1855 				if (err < 0)
1856 					WL_ERR(("WLC_UP return err:%d\n", err));
1857 			}
1858 			cfg->wlfc_on = true;
1859 			WL_DBG(("wlfc_on:%d \n", cfg->wlfc_on));
1860 		}
1861 	} else if (dhd->conf->disable_proptx != 0){
1862 			dhd_wlfc_deinit(dhd);
1863 			cfg->wlfc_on = false;
1864 	}
1865 #endif /* BCMSDIO || BCMDBUS */
1866 #endif /* PROP_TXSTATUS_VSDB */
1867 }
1868 
1869 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)1870 wl_cfg80211_p2p_if_add(struct bcm_cfg80211 *cfg,
1871 	wl_iftype_t wl_iftype,
1872 	char const *name, u8 *mac_addr, s32 *ret_err)
1873 {
1874 	u16 chspec;
1875 	s16 cfg_type;
1876 	long timeout;
1877 	s32 err;
1878 	u16 p2p_iftype;
1879 	int dhd_mode;
1880 	struct net_device *new_ndev = NULL;
1881 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
1882 	struct ether_addr *p2p_addr;
1883 
1884 	*ret_err = BCME_OK;
1885 	if (!cfg->p2p) {
1886 		WL_ERR(("p2p not initialized\n"));
1887 		return NULL;
1888 	}
1889 
1890 #if defined(WL_CFG80211_P2P_DEV_IF)
1891 	if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
1892 		/* Handle Dedicated P2P discovery Interface */
1893 		return wl_cfgp2p_add_p2p_disc_if(cfg);
1894 	}
1895 #endif /* WL_CFG80211_P2P_DEV_IF */
1896 
1897 	if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1898 		p2p_iftype = WL_P2P_IF_GO;
1899 	} else {
1900 		p2p_iftype = WL_P2P_IF_CLIENT;
1901 	}
1902 
1903 	/* Dual p2p doesn't support multiple P2PGO interfaces,
1904 	 * p2p_go_count is the counter for GO creation
1905 	 * requests.
1906 	 */
1907 	if ((cfg->p2p->p2p_go_count > 0) && (wl_iftype == WL_IF_TYPE_P2P_GO)) {
1908 		WL_ERR(("FW does not support multiple GO\n"));
1909 		*ret_err = -ENOTSUPP;
1910 		return NULL;
1911 	}
1912 	if (!cfg->p2p->on) {
1913 		p2p_on(cfg) = true;
1914 		wl_cfgp2p_set_firm_p2p(cfg);
1915 		wl_cfgp2p_init_discovery(cfg);
1916 	}
1917 
1918 	strlcpy(cfg->p2p->vir_ifname, name, sizeof(cfg->p2p->vir_ifname));
1919 	/* In concurrency case, STA may be already associated in a particular channel.
1920 	 * so retrieve the current channel of primary interface and then start the virtual
1921 	 * interface on that.
1922 	 */
1923 	 chspec = wl_cfg80211_get_shared_freq(wiphy);
1924 
1925 	/* For P2P mode, use P2P-specific driver features to create the
1926 	 * bss: "cfg p2p_ifadd"
1927 	 */
1928 	wl_set_p2p_status(cfg, IF_ADDING);
1929 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
1930 	cfg_type = wl_cfgp2p_get_conn_idx(cfg);
1931 	if (cfg_type < BCME_OK) {
1932 		wl_clr_p2p_status(cfg, IF_ADDING);
1933 		WL_ERR(("Failed to get connection idx for p2p interface"
1934 			", error code = %d\n", cfg_type));
1935 		return NULL;
1936 	}
1937 
1938 	p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
1939 	memcpy(p2p_addr->octet, mac_addr, ETH_ALEN);
1940 
1941 	err = wl_cfgp2p_ifadd(cfg, p2p_addr,
1942 		htod32(p2p_iftype), chspec);
1943 	if (unlikely(err)) {
1944 		wl_clr_p2p_status(cfg, IF_ADDING);
1945 		WL_ERR((" virtual iface add failed (%d) \n", err));
1946 		return NULL;
1947 	}
1948 
1949 	/* Wait for WLC_E_IF event with IF_ADD opcode */
1950 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1951 		((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
1952 		(cfg->if_event_info.valid)),
1953 		msecs_to_jiffies(MAX_WAIT_TIME));
1954 	if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
1955 		wl_if_event_info *event = &cfg->if_event_info;
1956 		new_ndev = wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg), event,
1957 			event->mac, cfg->p2p->vir_ifname, false);
1958 		if (unlikely(!new_ndev)) {
1959 			goto fail;
1960 		}
1961 
1962 		if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1963 			cfg->p2p->p2p_go_count++;
1964 		}
1965 		/* Fill p2p specific data */
1966 		wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
1967 		wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
1968 
1969 		WL_ERR((" virtual interface(%s) is "
1970 			"created net attach done\n", cfg->p2p->vir_ifname));
1971 #if defined(BCMDONGLEHOST)
1972 		dhd_mode = (wl_iftype == WL_IF_TYPE_P2P_GC) ?
1973 			DHD_FLAG_P2P_GC_MODE : DHD_FLAG_P2P_GO_MODE;
1974 		DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
1975 #endif /* defined(BCMDONGLEHOST) */
1976 			/* reinitialize completion to clear previous count */
1977 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1978 			INIT_COMPLETION(cfg->iface_disable);
1979 #else
1980 			init_completion(&cfg->iface_disable);
1981 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
1982 
1983 			return new_ndev->ieee80211_ptr;
1984 	}
1985 
1986 fail:
1987 	return NULL;
1988 }
1989 
1990 void
wl_cfg80211_iface_state_ops(struct wireless_dev * wdev,wl_interface_state_t state,wl_iftype_t wl_iftype,u16 wl_mode)1991 wl_cfg80211_iface_state_ops(struct wireless_dev *wdev,
1992 	wl_interface_state_t state,
1993 	wl_iftype_t wl_iftype, u16 wl_mode)
1994 {
1995 	struct net_device *ndev;
1996 	struct bcm_cfg80211 *cfg;
1997 	dhd_pub_t *dhd;
1998 	s32 bssidx;
1999 
2000 	WL_DBG(("state:%s wl_iftype:%d mode:%d\n",
2001 		wl_if_state_strs[state], wl_iftype, wl_mode));
2002 	if (!wdev) {
2003 		WL_ERR(("wdev null\n"));
2004 		return;
2005 	}
2006 
2007 	if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_NAN_NMI)) {
2008 		/* P2P discovery is a netless device and uses a
2009 		 * hidden bsscfg interface in fw. Don't apply the
2010 		 * iface ops state changes for p2p discovery I/F.
2011 		 * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
2012 		 * Don't apply iface ops state changes for NMI I/F.
2013 		 */
2014 		return;
2015 	}
2016 
2017 	cfg = wiphy_priv(wdev->wiphy);
2018 	ndev = wdev->netdev;
2019 	dhd = (dhd_pub_t *)(cfg->pub);
2020 
2021 	bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2022 	if (!ndev || (bssidx < 0)) {
2023 		WL_ERR(("ndev null. skip iface state ops\n"));
2024 		return;
2025 	}
2026 
2027 	switch (state) {
2028 		case WL_IF_CREATE_REQ:
2029 #ifdef WL_BCNRECV
2030 			/* check fakeapscan in progress then abort */
2031 			wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
2032 #endif /* WL_BCNRECV */
2033 			wl_cfgscan_cancel_scan(cfg);
2034 			wl_wlfc_enable(cfg, true);
2035 #ifdef WLTDLS
2036 			/* disable TDLS if number of connected interfaces is >= 1 */
2037 			wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_CREATE, false);
2038 #endif /* WLTDLS */
2039 			break;
2040 		case WL_IF_DELETE_REQ:
2041 #ifdef WL_WPS_SYNC
2042 			wl_wps_handle_ifdel(ndev);
2043 #endif /* WPS_SYNC */
2044 			if (wl_get_drv_status(cfg, SCANNING, ndev)) {
2045 				/* Send completion for any pending scans */
2046 				wl_cfgscan_cancel_scan(cfg);
2047 			}
2048 
2049 #ifdef CUSTOM_SET_CPUCORE
2050 			dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
2051 			if (!(dhd->chan_isvht80)) {
2052 				dhd_set_cpucore(dhd, FALSE);
2053 			}
2054 #endif /* CUSTOM_SET_CPUCORE */
2055 			 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
2056 			break;
2057 		case WL_IF_CREATE_DONE:
2058 			if (wl_mode == WL_MODE_BSS) {
2059 				/* Common code for sta type interfaces - STA, GC */
2060 				/* Enable firmware key buffering before sent 4-way M4 */
2061 				wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2062 			}
2063 			if (wl_iftype == WL_IF_TYPE_P2P_GC) {
2064 				/* Disable firmware roaming for P2P interface  */
2065 				wldev_iovar_setint(ndev, "roam_off", 1);
2066 				wldev_iovar_setint(ndev, "bcn_timeout", dhd->conf->bcn_timeout);
2067 				{
2068 					int assoc_retry = 3;
2069 #if defined(CUSTOM_ASSOC_RETRY_MAX)
2070 					assoc_retry = CUSTOM_ASSOC_RETRY_MAX;
2071 #endif /* CUSTOM_ASSOC_RETRY_MAX */
2072 					/* set retry_max to CUSTOM_ASSOC_RETRY_MAX(3) */
2073 					wldev_iovar_setint(ndev, "assoc_retry_max", assoc_retry);
2074 				}
2075 			}
2076 			if (wl_mode == WL_MODE_AP) {
2077 				/* Common code for AP/GO */
2078 #if defined(SUPPORT_AP_POWERSAVE) && defined(BCMDONGLEHOST)
2079 				dhd_set_ap_powersave(dhd, 0, TRUE);
2080 #endif /* SUPPORT_AP_POWERSAVE && BCMDONGLEHOST */
2081 			}
2082 			break;
2083 		case WL_IF_DELETE_DONE:
2084 #ifdef WLTDLS
2085 			/* Enable back TDLS if connected interface is <= 1 */
2086 			wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2087 #endif /* WLTDLS */
2088 			wl_wlfc_enable(cfg, false);
2089 			break;
2090 		case WL_IF_CHANGE_REQ:
2091 			/* Flush existing IEs from firmware on role change */
2092 			wl_cfg80211_clear_per_bss_ies(cfg, wdev);
2093 			break;
2094 		case WL_IF_CHANGE_DONE:
2095 			if (wl_mode == WL_MODE_BSS) {
2096 #ifdef SUPPORT_AP_POWERSAVE
2097 				dhd_set_ap_powersave(dhd, 0, FALSE);
2098 #endif /* SUPPORT_AP_POWERSAVE */
2099 				/* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2100 				wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2101 			}
2102 			break;
2103 
2104 		default:
2105 			WL_ERR(("Unsupported state: %d\n", state));
2106 			return;
2107 	}
2108 }
2109 
2110 static s32
wl_cfg80211_p2p_if_del(struct wiphy * wiphy,struct wireless_dev * wdev)2111 wl_cfg80211_p2p_if_del(struct wiphy *wiphy, struct wireless_dev *wdev)
2112 {
2113 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2114 	s16 bssidx;
2115 	s16 err;
2116 	s32 cfg_type;
2117 	struct net_device *ndev;
2118 	long timeout;
2119 	struct ether_addr p2p_dev_addr = {{0}};
2120 
2121 	if (unlikely(!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
2122 		WL_INFORM_MEM(("device is not ready\n"));
2123 		return BCME_NOTFOUND;
2124 	}
2125 
2126 #ifdef WL_CFG80211_P2P_DEV_IF
2127 	if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2128 		/* Handle dedicated P2P discovery interface. */
2129 		return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
2130 	}
2131 #endif /* WL_CFG80211_P2P_DEV_IF */
2132 
2133 	/* Handle P2P Group Interface */
2134 	bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2135 	if (bssidx <= 0) {
2136 		WL_ERR(("bssidx not found\n"));
2137 		return BCME_NOTFOUND;
2138 	}
2139 	if (wl_cfgp2p_find_type(cfg, bssidx, &cfg_type) != BCME_OK) {
2140 		/* Couldn't find matching iftype */
2141 		WL_MEM(("non P2P interface\n"));
2142 		return BCME_NOTFOUND;
2143 	}
2144 
2145 	ndev = wdev->netdev;
2146 	(void)memcpy_s(p2p_dev_addr.octet, ETHER_ADDR_LEN,
2147 		ndev->dev_addr, ETHER_ADDR_LEN);
2148 
2149 	wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2150 	wl_clr_p2p_status(cfg, IF_ADDING);
2151 
2152 	/* for GO */
2153 	if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
2154 		wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
2155 		cfg->p2p->p2p_go_count--;
2156 		/* disable interface before bsscfg free */
2157 		err = wl_cfgp2p_ifdisable(cfg, &p2p_dev_addr);
2158 		/* if fw doesn't support "ifdis",
2159 		   do not wait for link down of ap mode
2160 		 */
2161 		if (err == 0) {
2162 			WL_ERR(("Wait for Link Down event for GO !!!\n"));
2163 			wait_for_completion_timeout(&cfg->iface_disable,
2164 				msecs_to_jiffies(500));
2165 		} else if (err != BCME_UNSUPPORTED) {
2166 			msleep(300);
2167 		}
2168 	} else {
2169 		/* GC case */
2170 		if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
2171 			WL_ERR(("Wait for Link Down event for GC !\n"));
2172 			wait_for_completion_timeout
2173 					(&cfg->iface_disable, msecs_to_jiffies(500));
2174 		}
2175 
2176 		/* Force P2P disconnect in iface down context */
2177 		if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
2178 			WL_INFORM_MEM(("force send disconnect event\n"));
2179 			CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
2180 			wl_clr_drv_status(cfg, AUTHORIZED, ndev);
2181 		}
2182 	}
2183 
2184 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
2185 	wl_set_p2p_status(cfg, IF_DELETING);
2186 	DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
2187 
2188 	err = wl_cfgp2p_ifdel(cfg, &p2p_dev_addr);
2189 	if (unlikely(err)) {
2190 		WL_ERR(("P2P IFDEL operation failed, error code = %d\n", err));
2191 		err = BCME_ERROR;
2192 		goto fail;
2193 	} else {
2194 		/* Wait for WLC_E_IF event */
2195 		timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2196 			((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
2197 			(cfg->if_event_info.valid)),
2198 			msecs_to_jiffies(MAX_WAIT_TIME));
2199 		if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
2200 			cfg->if_event_info.valid) {
2201 			WL_ERR(("P2P IFDEL operation done\n"));
2202 			err = BCME_OK;
2203 		} else {
2204 			WL_ERR(("IFDEL didn't complete properly\n"));
2205 			err = -EINVAL;
2206 		}
2207 	}
2208 
2209 fail:
2210 	/* Even in failure case, attempt to remove the host data structure.
2211 	 * Firmware would be cleaned up via WiFi reset done by the
2212 	 * user space from hang event context (for android only).
2213 	 */
2214 	bzero(cfg->p2p->vir_ifname, IFNAMSIZ);
2215 	wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
2216 	wl_to_p2p_bss_ndev(cfg, cfg_type) = NULL;
2217 	wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, cfg_type));
2218 
2219 	/* Clear our saved WPS and P2P IEs for the discovery BSS */
2220 	wl_cfg80211_clear_p2p_disc_ies(cfg);
2221 #ifdef BCMDONGLEHOST
2222 	dhd_net_if_lock(ndev);
2223 #endif /* BCMDONGLEHOST */
2224 	if (cfg->if_event_info.ifidx) {
2225 		/* Remove interface except for primary ifidx */
2226 		wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
2227 	}
2228 #ifdef BCMDONGLEHOST
2229 	dhd_net_if_unlock(ndev);
2230 #endif /* BCMDONGLEHOST */
2231 	return err;
2232 }
2233 
2234 static struct wireless_dev *
wl_cfg80211_add_monitor_if(struct wiphy * wiphy,const char * name)2235 wl_cfg80211_add_monitor_if(struct wiphy *wiphy, const char *name)
2236 {
2237 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
2238 	WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2239 	return ERR_PTR(-EOPNOTSUPP);
2240 #else
2241 	struct wireless_dev *wdev;
2242 	struct net_device* ndev = NULL;
2243 
2244 	dhd_add_monitor(name, &ndev);
2245 
2246 	wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2247 	if (!wdev) {
2248 		WL_ERR(("wireless_dev alloc failed! \n"));
2249 		goto fail;
2250 	}
2251 
2252 	wdev->wiphy = wiphy;
2253 	wdev->iftype = NL80211_IFTYPE_MONITOR;
2254 	ndev->ieee80211_ptr = wdev;
2255 	SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
2256 
2257 	WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
2258 	return ndev->ieee80211_ptr;
2259 fail:
2260 	return ERR_PTR(-EOPNOTSUPP);
2261 #endif // endif
2262 }
2263 
2264 static struct wireless_dev *
wl_cfg80211_add_ibss(struct wiphy * wiphy,u16 wl_iftype,char const * name)2265 wl_cfg80211_add_ibss(struct wiphy *wiphy, u16 wl_iftype, char const *name)
2266 {
2267 #ifdef WLAIBSS_MCHAN
2268 	/* AIBSS */
2269 	return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
2270 #else
2271 	/* Normal IBSS */
2272 	WL_ERR(("IBSS not supported on Virtual iface\n"));
2273 	return NULL;
2274 #endif
2275 }
2276 
2277 #ifdef DNGL_AXI_ERROR_LOGGING
2278 static s32
_wl_cfg80211_check_axi_error(struct bcm_cfg80211 * cfg)2279 _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg)
2280 {
2281 	s32 ret = BCME_OK;
2282 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2283 	hnd_ext_trap_hdr_t *hdr;
2284 	int axi_host_error_size;
2285 	uint8 *new_dst;
2286 	uint32 *ext_data = dhd->extended_trap_data;
2287 	struct file *fp = NULL;
2288 	char *filename = DHD_COMMON_DUMP_PATH
2289 			 DHD_DUMP_AXI_ERROR_FILENAME
2290 			 DHD_DUMP_HAL_FILENAME_SUFFIX;
2291 
2292 	WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename));
2293 
2294 	fp = filp_open(filename, O_RDONLY, 0);
2295 
2296 	if (IS_ERR(fp) || (fp == NULL)) {
2297 		WL_ERR(("%s: Couldn't read the file, err %ld,File [%s]  No previous axi error \n",
2298 			__FUNCTION__, PTR_ERR(fp), filename));
2299 		return ret;
2300 	}
2301 
2302 	kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t));
2303 	filp_close(fp, NULL);
2304 
2305 	/* Delete axi error info file */
2306 	if (dhd_file_delete(filename) < 0) {
2307 		WL_ERR(("%s(): Failed to delete file: %s\n", __FUNCTION__, filename));
2308 		return ret;
2309 	}
2310 	WL_ERR(("%s(): Success to delete file: %s\n", __FUNCTION__, filename));
2311 
2312 	if (dhd->axi_err_dump->etd_axi_error_v1.signature != HND_EXT_TRAP_AXIERROR_SIGNATURE) {
2313 		WL_ERR(("%s: Invalid AXI signature: 0x%x\n",
2314 		__FUNCTION__, dhd->axi_err_dump->etd_axi_error_v1.signature));
2315 	}
2316 
2317 	/* First word is original trap_data */
2318 	ext_data++;
2319 
2320 	/* Followed by the extended trap data header */
2321 	hdr = (hnd_ext_trap_hdr_t *)ext_data;
2322 	new_dst = hdr->data;
2323 
2324 	axi_host_error_size =  sizeof(dhd->axi_err_dump->axid)
2325 		+ sizeof(dhd->axi_err_dump->fault_address);
2326 
2327 	/* TAG_TRAP_AXI_HOST_INFO tlv : host's axid, fault address */
2328 	new_dst = bcm_write_tlv(TAG_TRAP_AXI_HOST_INFO,
2329 			(const void *)dhd->axi_err_dump,
2330 			axi_host_error_size, new_dst);
2331 
2332 	/* TAG_TRAP_AXI_ERROR tlv */
2333 	new_dst = bcm_write_tlv(TAG_TRAP_AXI_ERROR,
2334 			(const void *)&dhd->axi_err_dump->etd_axi_error_v1,
2335 			sizeof(dhd->axi_err_dump->etd_axi_error_v1), new_dst);
2336 	hdr->len = new_dst - hdr->data;
2337 
2338 	dhd->dongle_trap_occured = TRUE;
2339 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2340 	copy_hang_info_trap(dhd);
2341 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2342 	memset(dhd->axi_err_dump, 0, sizeof(dhd_axi_error_dump_t));
2343 
2344 	dhd->hang_reason = HANG_REASON_DONGLE_TRAP;
2345 	net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2346 	ret = BCME_ERROR;
2347 	return ret;
2348 }
2349 #endif /* DNGL_AXI_ERROR_LOGGING */
2350 
2351 /* All Android/Linux private/Vendor Interface calls should make
2352  *  use of below API for interface creation.
2353  */
2354 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)2355 wl_cfg80211_add_if(struct bcm_cfg80211 *cfg,
2356 	struct net_device *primary_ndev,
2357 	wl_iftype_t wl_iftype, const char *name, u8 *mac)
2358 {
2359 	u8 mac_addr[ETH_ALEN];
2360 	s32 err = -ENODEV;
2361 	struct wireless_dev *wdev = NULL;
2362 	struct wiphy *wiphy;
2363 	s32 wl_mode;
2364 #if defined(BCMDONGLEHOST)
2365 	dhd_pub_t *dhd;
2366 #endif /* BCMDONGLEHOST */
2367 	wl_iftype_t macaddr_iftype = wl_iftype;
2368 
2369 	WL_INFORM_MEM(("if name: %s, wl_iftype:%d \n",
2370 		name ? name : "NULL", wl_iftype));
2371 	if (!cfg || !primary_ndev || !name) {
2372 		WL_ERR(("cfg/ndev/name ptr null\n"));
2373 		return NULL;
2374 	}
2375 	if (wl_cfg80211_get_wdev_from_ifname(cfg, name)) {
2376 		WL_ERR(("Interface name %s exists!\n", name));
2377 		return NULL;
2378 	}
2379 
2380 	wiphy = bcmcfg_to_wiphy(cfg);
2381 #if defined(BCMDONGLEHOST)
2382 	dhd = (dhd_pub_t *)(cfg->pub);
2383 	if (!dhd) {
2384 		return NULL;
2385 	}
2386 #endif /* BCMDONGLEHOST */
2387 
2388 	if ((wl_mode = wl_iftype_to_mode(wl_iftype)) < 0) {
2389 		return NULL;
2390 	}
2391 	mutex_lock(&cfg->if_sync);
2392 #ifdef WL_NAN
2393 	if (wl_iftype == WL_IF_TYPE_NAN) {
2394 	/*
2395 	* Bypass the role conflict check for NDI and handle it
2396 	* from dp req and dp resp context
2397 	* because in aware comms, ndi gets created soon after nan enable.
2398 	*/
2399 	} else
2400 #endif /* WL_NAN */
2401 #ifdef WL_IFACE_MGMT
2402 	/* Allow wdev interface creation for p2p discovery to avoid failures
2403 	 * in user supplicant initialization. The role conflict rules will be
2404 	 * applied from discovery context if userspace tries to use discovery.
2405 	 */
2406 	if ((wl_iftype != WL_IF_TYPE_P2P_DISC) &&
2407 		(err = wl_cfg80211_handle_if_role_conflict(cfg, wl_iftype)) < 0) {
2408 		mutex_unlock(&cfg->if_sync);
2409 		return NULL;
2410 	}
2411 #endif /* WL_IFACE_MGMT */
2412 #ifdef DNGL_AXI_ERROR_LOGGING
2413 	/* Check the previous smmu fault error */
2414 	if ((err = _wl_cfg80211_check_axi_error(cfg)) < 0) {
2415 		mutex_unlock(&cfg->if_sync);
2416 		return NULL;
2417 	}
2418 #endif /* DNGL_AXI_ERROR_LOGGING */
2419 	/* Protect the interace op context */
2420 	/* Do pre-create ops */
2421 	wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CREATE_REQ,
2422 		wl_iftype, wl_mode);
2423 
2424 	if (strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)) == 0) {
2425 		macaddr_iftype = WL_IF_TYPE_AP;
2426 	}
2427 
2428 	if (mac) {
2429 		/* If mac address is provided, use that */
2430 		memcpy(mac_addr, mac, ETH_ALEN);
2431 	} else if ((wl_get_vif_macaddr(cfg, macaddr_iftype, mac_addr) != BCME_OK)) {
2432 		/* Fetch the mac address to be used for virtual interface */
2433 		err = -EINVAL;
2434 		goto fail;
2435 	}
2436 
2437 	switch (wl_iftype) {
2438 		case WL_IF_TYPE_IBSS:
2439 			wdev = wl_cfg80211_add_ibss(wiphy, wl_iftype, name);
2440 			break;
2441 		case WL_IF_TYPE_MONITOR:
2442 			wdev = wl_cfg80211_add_monitor_if(wiphy, name);
2443 			break;
2444 		case WL_IF_TYPE_STA:
2445 		case WL_IF_TYPE_AP:
2446 		case WL_IF_TYPE_NAN:
2447 			if (cfg->iface_cnt >= (IFACE_MAX_CNT - 1)) {
2448 				WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
2449 					cfg->iface_cnt));
2450 				err = -ENOTSUPP;
2451 				goto fail;
2452 			}
2453 			wdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
2454 				wl_iftype, mac_addr, name);
2455 			break;
2456 		case WL_IF_TYPE_P2P_DISC:
2457 		case WL_IF_TYPE_P2P_GO:
2458 			/* Intentional fall through */
2459 		case WL_IF_TYPE_P2P_GC:
2460 			if (cfg->p2p_supported) {
2461 				wdev = wl_cfg80211_p2p_if_add(cfg, wl_iftype,
2462 					name, mac_addr, &err);
2463 				break;
2464 			}
2465 			/* Intentionally fall through for unsupported interface
2466 			 * handling when firmware doesn't support p2p
2467 			 */
2468 		default:
2469 			WL_ERR(("Unsupported interface type\n"));
2470 			err = -ENOTSUPP;
2471 			goto fail;
2472 	}
2473 
2474 	if (!wdev) {
2475 		WL_ERR(("vif create failed. err:%d\n", err));
2476 		if (err != -ENOTSUPP) {
2477 			err = -ENODEV;
2478 		}
2479 		goto fail;
2480 	}
2481 
2482 	/* Ensure decrementing in case of failure */
2483 	cfg->vif_count++;
2484 
2485 	wl_cfg80211_iface_state_ops(wdev,
2486 		WL_IF_CREATE_DONE, wl_iftype, wl_mode);
2487 
2488 	WL_INFORM_MEM(("Vif created. dev->ifindex:%d"
2489 		" cfg_iftype:%d, vif_count:%d\n",
2490 		(wdev->netdev ? wdev->netdev->ifindex : 0xff),
2491 		wdev->iftype, cfg->vif_count));
2492 	mutex_unlock(&cfg->if_sync);
2493 	return wdev;
2494 
2495 fail:
2496 	wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
2497 		WL_IF_DELETE_REQ, wl_iftype, wl_mode);
2498 
2499 	if (err != -ENOTSUPP) {
2500 		/* For non-supported interfaces, just return error and
2501 		 * skip below recovery steps.
2502 		 */
2503 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2504 		wl_copy_hang_info_if_falure(primary_ndev, HANG_REASON_IFACE_DEL_FAILURE, err);
2505 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2506 		SUPP_LOG(("IF_ADD fail. err:%d\n", err));
2507 		wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
2508 #if defined(BCMDONGLEHOST)
2509 		if (dhd_query_bus_erros(dhd)) {
2510 			goto exit;
2511 		}
2512 		dhd->iface_op_failed = TRUE;
2513 #endif /* BCMDONGLEHOST */
2514 #if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
2515 		if (dhd->memdump_enabled) {
2516 			dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
2517 			dhd_bus_mem_dump(dhd);
2518 		}
2519 #endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
2520 
2521 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
2522 		/* If reached here, something wrong with DHD or firmware.
2523 		 * There could be a chance that firmware is in bad state.
2524 		 * Request the upper layer to do a Wi-Fi reset.
2525 		 */
2526 		dhd->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
2527 		net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2528 #endif /* BCMDONGLEHOST && OEM_ANDROID */
2529 
2530 	}
2531 exit:
2532 	mutex_unlock(&cfg->if_sync);
2533 	return NULL;
2534 }
2535 
2536 static s32
wl_cfg80211_del_ibss(struct wiphy * wiphy,struct wireless_dev * wdev)2537 wl_cfg80211_del_ibss(struct wiphy *wiphy, struct wireless_dev *wdev)
2538 {
2539 	WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev));
2540 #ifdef WLAIBSS_MCHAN
2541 	/* AIBSS */
2542 	return bcm_cfg80211_del_ibss_if(wiphy, wdev);
2543 #else
2544 	/* Normal IBSS */
2545 	return wl_cfg80211_del_iface(wiphy, wdev);
2546 #endif
2547 }
2548 
2549 s32
wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)2550 wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
2551 	struct wireless_dev *wdev, char *ifname)
2552 {
2553 	int ret = BCME_OK;
2554 	mutex_lock(&cfg->if_sync);
2555 	ret = _wl_cfg80211_del_if(cfg, primary_ndev, wdev, ifname);
2556 	mutex_unlock(&cfg->if_sync);
2557 	return ret;
2558 }
2559 
2560 s32
_wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)2561 _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
2562 	struct wireless_dev *wdev, char *ifname)
2563 {
2564 	int ret = BCME_OK;
2565 	s32 bssidx;
2566 	struct wiphy *wiphy;
2567 	u16 wl_mode;
2568 	u16 wl_iftype;
2569 	struct net_info *netinfo;
2570 #if defined(BCMDONGLEHOST)
2571 	dhd_pub_t *dhd;
2572 	BCM_REFERENCE(dhd);
2573 #endif /* BCMDONGLEHOST */
2574 
2575 	if (!cfg) {
2576 		return -EINVAL;
2577 	}
2578 
2579 #if defined(BCMDONGLEHOST)
2580 	dhd = (dhd_pub_t *)(cfg->pub);
2581 #endif /* BCMDONGLEHOST */
2582 
2583 	if (!wdev && ifname) {
2584 		/* If only ifname is provided, fetch corresponding wdev ptr from our
2585 		 * internal data structure
2586 		 */
2587 		wdev = wl_cfg80211_get_wdev_from_ifname(cfg, ifname);
2588 	}
2589 
2590 	/* Check whether we have a valid wdev ptr */
2591 	if (unlikely(!wdev)) {
2592 		WL_ERR(("wdev not found. '%s' does not exists\n", ifname));
2593 		return -ENODEV;
2594 	}
2595 
2596 	WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev->iftype));
2597 
2598 	wiphy = wdev->wiphy;
2599 #ifdef WL_CFG80211_P2P_DEV_IF
2600 	if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2601 		/* p2p discovery would be de-initialized in stop p2p
2602 		 * device context/from other virtual i/f creation context
2603 		 * so netinfo list may not have any node corresponding to
2604 		 * discovery I/F. Handle it before bssidx check.
2605 		 */
2606 		ret = wl_cfg80211_p2p_if_del(wiphy, wdev);
2607 		if (unlikely(ret)) {
2608 			goto exit;
2609 		} else {
2610 			/* success case. return from here */
2611 			if (cfg->vif_count) {
2612 				cfg->vif_count--;
2613 			}
2614 			return BCME_OK;
2615 		}
2616 	}
2617 #endif /* WL_CFG80211_P2P_DEV_IF */
2618 
2619 	if ((netinfo = wl_get_netinfo_by_wdev(cfg, wdev)) == NULL) {
2620 		WL_ERR(("Find netinfo from wdev %p failed\n", wdev));
2621 		ret = -ENODEV;
2622 		goto exit;
2623 	}
2624 
2625 	if (!wdev->netdev) {
2626 		WL_ERR(("ndev null! \n"));
2627 	} else {
2628 		/* Disable tx before del */
2629 		netif_tx_disable(wdev->netdev);
2630 	}
2631 
2632 	wl_iftype = netinfo->iftype;
2633 	wl_mode = wl_iftype_to_mode(wl_iftype);
2634 	bssidx = netinfo->bssidx;
2635 	WL_DBG_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
2636 		wdev->iftype, wl_iftype, wl_mode, bssidx));
2637 
2638 	/* Do pre-interface del ops */
2639 	wl_cfg80211_iface_state_ops(wdev, WL_IF_DELETE_REQ, wl_iftype, wl_mode);
2640 
2641 #ifdef PCIE_FULL_DONGLE
2642 	/* clean up sta info & clean up flowrings correspondign to the iface */
2643 	dhd_net_del_flowrings_sta(dhd, wdev->netdev);
2644 #endif /* PCIE_FULL_DONGLE */
2645 
2646 	switch (wl_iftype) {
2647 		case WL_IF_TYPE_P2P_GO:
2648 		case WL_IF_TYPE_P2P_GC:
2649 		case WL_IF_TYPE_AP:
2650 		case WL_IF_TYPE_STA:
2651 		case WL_IF_TYPE_NAN:
2652 			ret = wl_cfg80211_del_iface(wiphy, wdev);
2653 			break;
2654 		case WL_IF_TYPE_IBSS:
2655 			ret = wl_cfg80211_del_ibss(wiphy, wdev);
2656 			break;
2657 
2658 		default:
2659 			WL_ERR(("Unsupported interface type\n"));
2660 			ret = BCME_ERROR;
2661 	}
2662 
2663 exit:
2664 	if (ret == BCME_OK) {
2665 		/* Successful case */
2666 		if (cfg->vif_count) {
2667 			cfg->vif_count--;
2668 		}
2669 		wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
2670 				WL_IF_DELETE_DONE, wl_iftype, wl_mode);
2671 #ifdef WL_NAN
2672 		if (!((cfg->nancfg->mac_rand) && (wl_iftype == WL_IF_TYPE_NAN)))
2673 #endif /* WL_NAN */
2674 		{
2675 			wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype);
2676 		}
2677 		WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg->vif_count));
2678 	} else {
2679 		if (!wdev->netdev) {
2680 			WL_ERR(("ndev null! \n"));
2681 		} else {
2682 			/* IF del failed. revert back tx queue status */
2683 			netif_tx_start_all_queues(wdev->netdev);
2684 		}
2685 
2686 		/* Skip generating log files and sending HANG event
2687 		 * if driver state is not READY
2688 		 */
2689 		if (wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg))) {
2690 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2691 			wl_copy_hang_info_if_falure(primary_ndev,
2692 				HANG_REASON_IFACE_DEL_FAILURE, ret);
2693 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2694 			SUPP_LOG(("IF_DEL fail. err:%d\n", ret));
2695 			wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
2696 #if defined(BCMDONGLEHOST)
2697 			/* IF dongle is down due to previous hang or other conditions, sending
2698 			* one more hang notification is not needed.
2699 			*/
2700 			if (dhd_query_bus_erros(dhd) || (ret == BCME_DONGLE_DOWN)) {
2701 				goto end;
2702 			}
2703 			dhd->iface_op_failed = TRUE;
2704 #if defined(DHD_FW_COREDUMP)
2705 			if (dhd->memdump_enabled && (ret != -EBADTYPE)) {
2706 				dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
2707 				dhd_bus_mem_dump(dhd);
2708 			}
2709 #endif /* DHD_FW_COREDUMP */
2710 #endif /* BCMDONGLEHOST */
2711 
2712 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
2713 			WL_ERR(("Notify hang event to upper layer \n"));
2714 			dhd->hang_reason = HANG_REASON_IFACE_DEL_FAILURE;
2715 			net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2716 #endif /* BCMDONGLEHOST && OEM_ANDROID */
2717 
2718 		}
2719 	}
2720 end:
2721 	return ret;
2722 }
2723 
2724 s32
wl_cfg80211_notify_ifadd(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx,uint8 role)2725 wl_cfg80211_notify_ifadd(struct net_device *dev,
2726 	int ifidx, char *name, uint8 *mac, uint8 bssidx, uint8 role)
2727 {
2728 	bool ifadd_expected = FALSE;
2729 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2730 	bool bss_pending_op = TRUE;
2731 
2732 	/* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
2733 	 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
2734 	 */
2735 	if (wl_get_p2p_status(cfg, IF_CHANGING))
2736 		return wl_cfg80211_notify_ifchange(dev, ifidx, name, mac, bssidx);
2737 
2738 	/* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
2739 	if (wl_get_p2p_status(cfg, IF_ADDING)) {
2740 		ifadd_expected = TRUE;
2741 		wl_clr_p2p_status(cfg, IF_ADDING);
2742 	} else if (cfg->bss_pending_op) {
2743 		ifadd_expected = TRUE;
2744 		bss_pending_op = FALSE;
2745 	}
2746 
2747 	if (ifadd_expected) {
2748 		wl_if_event_info *if_event_info = &cfg->if_event_info;
2749 
2750 		if_event_info->ifidx = ifidx;
2751 		if_event_info->bssidx = bssidx;
2752 		if_event_info->role = role;
2753 		strlcpy(if_event_info->name, name, sizeof(if_event_info->name));
2754 		if_event_info->name[IFNAMSIZ - 1] = '\0';
2755 		if (mac)
2756 			memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
2757 
2758 		/* Update bss pendig operation status */
2759 		if (!bss_pending_op) {
2760 			cfg->bss_pending_op = FALSE;
2761 		}
2762 		WL_INFORM_MEM(("IF_ADD ifidx:%d bssidx:%d role:%d\n",
2763 			ifidx, bssidx, role));
2764 		OSL_SMP_WMB();
2765 		if_event_info->valid = TRUE;
2766 		wake_up_interruptible(&cfg->netif_change_event);
2767 		return BCME_OK;
2768 	}
2769 
2770 	return BCME_ERROR;
2771 }
2772 
2773 s32
wl_cfg80211_notify_ifdel(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)2774 wl_cfg80211_notify_ifdel(struct net_device *dev, int ifidx, char *name, uint8 *mac, uint8 bssidx)
2775 {
2776 	bool ifdel_expected = FALSE;
2777 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2778 	wl_if_event_info *if_event_info = &cfg->if_event_info;
2779 	bool bss_pending_op = TRUE;
2780 
2781 	if (wl_get_p2p_status(cfg, IF_DELETING)) {
2782 		ifdel_expected = TRUE;
2783 		wl_clr_p2p_status(cfg, IF_DELETING);
2784 	} else if (cfg->bss_pending_op) {
2785 		ifdel_expected = TRUE;
2786 		bss_pending_op = FALSE;
2787 	}
2788 
2789 	if (ifdel_expected) {
2790 		if_event_info->ifidx = ifidx;
2791 		if_event_info->bssidx = bssidx;
2792 		/* Update bss pendig operation status */
2793 		if (!bss_pending_op) {
2794 			cfg->bss_pending_op = FALSE;
2795 		}
2796 		WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx, bssidx));
2797 		OSL_SMP_WMB();
2798 		if_event_info->valid = TRUE;
2799 		wake_up_interruptible(&cfg->netif_change_event);
2800 		return BCME_OK;
2801 	}
2802 
2803 	return BCME_ERROR;
2804 }
2805 
2806 s32
wl_cfg80211_notify_ifchange(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)2807 wl_cfg80211_notify_ifchange(struct net_device * dev, int ifidx, char *name, uint8 *mac,
2808 	uint8 bssidx)
2809 {
2810 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2811 
2812 	if (wl_get_p2p_status(cfg, IF_CHANGING)) {
2813 		wl_set_p2p_status(cfg, IF_CHANGED);
2814 		OSL_SMP_WMB();
2815 		wake_up_interruptible(&cfg->netif_change_event);
2816 		return BCME_OK;
2817 	}
2818 
2819 	return BCME_ERROR;
2820 }
2821 
wl_set_rts(struct net_device * dev,u32 rts_threshold)2822 static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
2823 {
2824 	s32 err = 0;
2825 
2826 	err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
2827 	if (unlikely(err)) {
2828 		WL_ERR(("Error (%d)\n", err));
2829 		return err;
2830 	}
2831 	return err;
2832 }
2833 
wl_set_frag(struct net_device * dev,u32 frag_threshold)2834 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
2835 {
2836 	s32 err = 0;
2837 
2838 	err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
2839 	if (unlikely(err)) {
2840 		WL_ERR(("Error (%d)\n", err));
2841 		return err;
2842 	}
2843 	return err;
2844 }
2845 
wl_set_retry(struct net_device * dev,u32 retry,bool l)2846 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
2847 {
2848 	s32 err = 0;
2849 	u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
2850 
2851 #ifdef CUSTOM_LONG_RETRY_LIMIT
2852 	if ((cmd == WLC_SET_LRL) &&
2853 		(retry != CUSTOM_LONG_RETRY_LIMIT)) {
2854 		WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
2855 		return err;
2856 	}
2857 #endif /* CUSTOM_LONG_RETRY_LIMIT */
2858 
2859 	retry = htod32(retry);
2860 	err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry));
2861 	if (unlikely(err)) {
2862 		WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
2863 		return err;
2864 	}
2865 	return err;
2866 }
2867 
wl_cfg80211_set_wiphy_params(struct wiphy * wiphy,u32 changed)2868 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
2869 {
2870 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
2871 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2872 	s32 err = 0;
2873 
2874 	RETURN_EIO_IF_NOT_UP(cfg);
2875 	WL_DBG(("Enter\n"));
2876 	if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
2877 		(cfg->conf->rts_threshold != wiphy->rts_threshold)) {
2878 		cfg->conf->rts_threshold = wiphy->rts_threshold;
2879 		err = wl_set_rts(ndev, cfg->conf->rts_threshold);
2880 		if (err != BCME_OK)
2881 			return err;
2882 	}
2883 	if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
2884 		(cfg->conf->frag_threshold != wiphy->frag_threshold)) {
2885 		cfg->conf->frag_threshold = wiphy->frag_threshold;
2886 		err = wl_set_frag(ndev, cfg->conf->frag_threshold);
2887 		if (err != BCME_OK)
2888 			return err;
2889 	}
2890 	if (changed & WIPHY_PARAM_RETRY_LONG &&
2891 		(cfg->conf->retry_long != wiphy->retry_long)) {
2892 		cfg->conf->retry_long = wiphy->retry_long;
2893 		err = wl_set_retry(ndev, cfg->conf->retry_long, true);
2894 		if (err != BCME_OK)
2895 			return err;
2896 	}
2897 	if (changed & WIPHY_PARAM_RETRY_SHORT &&
2898 		(cfg->conf->retry_short != wiphy->retry_short)) {
2899 		cfg->conf->retry_short = wiphy->retry_short;
2900 		err = wl_set_retry(ndev, cfg->conf->retry_short, false);
2901 		if (err != BCME_OK) {
2902 			return err;
2903 		}
2904 	}
2905 
2906 	return err;
2907 }
2908 
2909 void
wl_cfg80211_ibss_vsie_set_buffer(struct net_device * dev,vndr_ie_setbuf_t * ibss_vsie,int ibss_vsie_len)2910 wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev, vndr_ie_setbuf_t *ibss_vsie,
2911 	int ibss_vsie_len)
2912 {
2913 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2914 
2915 	if (cfg != NULL && ibss_vsie != NULL) {
2916 		if (cfg->ibss_vsie != NULL) {
2917 			MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
2918 		}
2919 		cfg->ibss_vsie = ibss_vsie;
2920 		cfg->ibss_vsie_len = ibss_vsie_len;
2921 	}
2922 }
2923 
2924 static void
wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 * cfg)2925 wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
2926 {
2927 	/* free & initiralize VSIE (Vendor Specific IE) */
2928 	if (cfg->ibss_vsie != NULL) {
2929 		MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
2930 		cfg->ibss_vsie_len = 0;
2931 	}
2932 }
2933 
2934 s32
wl_cfg80211_ibss_vsie_delete(struct net_device * dev)2935 wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
2936 {
2937 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2938 	char *ioctl_buf = NULL;
2939 	s32 ret = BCME_OK, bssidx;
2940 
2941 	if (cfg != NULL && cfg->ibss_vsie != NULL) {
2942 		ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
2943 		if (!ioctl_buf) {
2944 			WL_ERR(("ioctl memory alloc failed\n"));
2945 			return -ENOMEM;
2946 		}
2947 		if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
2948 			WL_ERR(("Find index failed\n"));
2949 			ret = BCME_ERROR;
2950 			goto end;
2951 		}
2952 		/* change the command from "add" to "del" */
2953 		strlcpy(cfg->ibss_vsie->cmd, "del", sizeof(cfg->ibss_vsie->cmd));
2954 
2955 		ret = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie",
2956 				cfg->ibss_vsie, cfg->ibss_vsie_len,
2957 				ioctl_buf, WLC_IOCTL_MEDLEN, bssidx, NULL);
2958 		WL_ERR(("ret=%d\n", ret));
2959 
2960 		if (ret == BCME_OK) {
2961 			/* Free & initialize VSIE */
2962 			MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
2963 			cfg->ibss_vsie_len = 0;
2964 		}
2965 end:
2966 		if (ioctl_buf) {
2967 			MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2968 		}
2969 	}
2970 
2971 	return ret;
2972 }
2973 
2974 #ifdef WLAIBSS_MCHAN
2975 static bcm_struct_cfgdev*
bcm_cfg80211_add_ibss_if(struct wiphy * wiphy,char * name)2976 bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name)
2977 {
2978 	int err = 0;
2979 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2980 	struct wireless_dev* wdev = NULL;
2981 	struct net_device *new_ndev = NULL;
2982 	struct net_device *primary_ndev = NULL;
2983 	long timeout;
2984 	wl_aibss_if_t aibss_if;
2985 	wl_if_event_info *event = NULL;
2986 
2987 	if (cfg->ibss_cfgdev != NULL) {
2988 		WL_ERR(("IBSS interface %s already exists\n", name));
2989 		return NULL;
2990 	}
2991 
2992 	WL_ERR(("Try to create IBSS interface %s\n", name));
2993 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
2994 	/* generate a new MAC address for the IBSS interface */
2995 	get_primary_mac(cfg, &cfg->ibss_if_addr);
2996 	cfg->ibss_if_addr.octet[4] ^= 0x40;
2997 	bzero(&aibss_if, sizeof(aibss_if));
2998 	memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
2999 	aibss_if.chspec = 0;
3000 	aibss_if.len = sizeof(aibss_if);
3001 
3002 	cfg->bss_pending_op = TRUE;
3003 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3004 	err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
3005 		sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3006 	if (err) {
3007 		WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
3008 		goto fail;
3009 	}
3010 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3011 		!cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
3012 	if (timeout <= 0 || cfg->bss_pending_op)
3013 		goto fail;
3014 
3015 	event = &cfg->if_event_info;
3016 	/* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
3017 	 * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
3018 	 * and will be freed by dhd_detach unless it gets unregistered before that. The
3019 	 * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
3020 	 * be freed by wl_dealloc_netinfo
3021 	 */
3022 	new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name,
3023 		event->mac, event->bssidx, event->name);
3024 	if (new_ndev == NULL)
3025 		goto fail;
3026 	wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
3027 	if (wdev == NULL)
3028 		goto fail;
3029 	wdev->wiphy = wiphy;
3030 	wdev->iftype = NL80211_IFTYPE_ADHOC;
3031 	wdev->netdev = new_ndev;
3032 	new_ndev->ieee80211_ptr = wdev;
3033 	SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
3034 
3035 	/* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
3036 	* needs to be modified to take one parameter (bool need_rtnl_lock)
3037 	 */
3038 	ASSERT_RTNL();
3039 	if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, FALSE) != BCME_OK)
3040 		goto fail;
3041 
3042 	wl_alloc_netinfo(cfg, new_ndev, wdev, WL_IF_TYPE_IBSS,
3043 		PM_ENABLE, event->bssidx, event->ifidx);
3044 	cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
3045 	WL_ERR(("IBSS interface %s created\n", new_ndev->name));
3046 	return cfg->ibss_cfgdev;
3047 
3048 fail:
3049 	WL_ERR(("failed to create IBSS interface %s \n", name));
3050 	cfg->bss_pending_op = FALSE;
3051 	if (new_ndev)
3052 		wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
3053 	if (wdev) {
3054 		MFREE(cfg->osh, wdev, sizeof(*wdev));
3055 	}
3056 	return NULL;
3057 }
3058 
3059 static s32
bcm_cfg80211_del_ibss_if(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev)3060 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
3061 {
3062 	int err = 0;
3063 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3064 	struct net_device *ndev = NULL;
3065 	struct net_device *primary_ndev = NULL;
3066 	long timeout;
3067 
3068 	if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet))
3069 		return -EINVAL;
3070 	ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev);
3071 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3072 
3073 	cfg->bss_pending_op = TRUE;
3074 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3075 	err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
3076 		sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3077 	if (err) {
3078 		WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
3079 		goto fail;
3080 	}
3081 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3082 		!cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
3083 	if (timeout <= 0 || cfg->bss_pending_op) {
3084 		WL_ERR(("timeout in waiting IF_DEL event\n"));
3085 		goto fail;
3086 	}
3087 
3088 	wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
3089 	cfg->ibss_cfgdev = NULL;
3090 	return 0;
3091 
3092 fail:
3093 	cfg->bss_pending_op = FALSE;
3094 	return -1;
3095 }
3096 #endif /* WLAIBSS_MCHAN */
3097 
3098 s32
wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)3099 wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)
3100 {
3101 	s32 ret = BCME_ERROR;
3102 
3103 	switch (iftype) {
3104 		case WL_IF_TYPE_AP:
3105 			ret = WL_INTERFACE_TYPE_AP;
3106 			break;
3107 		case WL_IF_TYPE_STA:
3108 			ret = WL_INTERFACE_TYPE_STA;
3109 			break;
3110 		case WL_IF_TYPE_NAN_NMI:
3111 		case WL_IF_TYPE_NAN:
3112 			ret = WL_INTERFACE_TYPE_NAN;
3113 			break;
3114 		case WL_IF_TYPE_P2P_DISC:
3115 			ret = WL_INTERFACE_TYPE_P2P_DISC;
3116 			break;
3117 		case WL_IF_TYPE_P2P_GO:
3118 			ret = WL_INTERFACE_TYPE_P2P_GO;
3119 			break;
3120 		case WL_IF_TYPE_P2P_GC:
3121 			ret = WL_INTERFACE_TYPE_P2P_GC;
3122 			break;
3123 
3124 #ifdef WLAWDL
3125 		case WL_IF_TYPE_AWDL:
3126 			ret = WL_INTERFACE_TYPE_AWDL;
3127 			break;
3128 #endif /* WLAWDL */
3129 
3130 		default:
3131 			WL_ERR(("Unsupported type:%d \n", iftype));
3132 			ret = -EINVAL;
3133 			break;
3134 	}
3135 	return ret;
3136 }
3137 
3138 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)3139 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
3140 	struct net_device *ndev, s32 bsscfg_idx,
3141 	wl_iftype_t cfg_iftype, s32 del, u8 *addr)
3142 {
3143 	s32 ret;
3144 	struct wl_interface_create_v2 iface;
3145 	wl_interface_create_v3_t iface_v3;
3146 	wl_interface_create_v0_t iface_v0;
3147 	struct wl_interface_info_v1 *info;
3148 	wl_interface_info_v2_t *info_v2;
3149 	wl_interface_info_v0_t *info_v0;
3150 	uint32 ifflags = 0;
3151 	bool use_iface_info_v2 = false;
3152 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
3153 	s32 iftype;
3154 #ifdef WLEASYMESH
3155 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3156 #endif /* WLEASYMESH */
3157 
3158 	if (del) {
3159 		ret = wldev_iovar_setbuf(ndev, "interface_remove",
3160 			NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL);
3161 		if (unlikely(ret))
3162 			WL_ERR(("Interface remove failed!! ret %d\n", ret));
3163 		return ret;
3164 	}
3165 
3166 	/* Interface create */
3167 	bzero(&iface, sizeof(iface));
3168 	/*
3169 	 * flags field is still used along with iftype inorder to support the old version of the
3170 	 * FW work with the latest app changes.
3171 	 */
3172 
3173 	iftype = wl_cfg80211_to_fw_iftype(cfg_iftype);
3174 	if (iftype < 0) {
3175 		return -ENOTSUPP;
3176 	}
3177 
3178 	if (addr) {
3179 		ifflags |= WL_INTERFACE_MAC_USE;
3180 		if (wl_legacy_chip_check(ndev)) {
3181 			iface.flags = ifflags;
3182 			memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
3183 		}
3184 	}
3185 #ifdef WLEASYMESH
3186 	if (dhd->conf->fw_type == FW_TYPE_EZMESH && iftype == WL_INTERFACE_TYPE_AP) {
3187 		// this can be removed for 4359
3188 		ifflags |= WL_INTERFACE_TYPE_AP;
3189 	}
3190 #endif /* WLEASYMESH */
3191 
3192 	/* Pass ver = 0 for fetching the interface_create iovar version */
3193 	if (wl_legacy_chip_check(ndev)) {
3194 		bzero(&iface_v0, sizeof(iface_v0));
3195 		iface_v0.ver = WL_INTERFACE_CREATE_VER_0;
3196 		iface_v0.flags = iftype | ifflags;
3197 		if (addr) {
3198 			memcpy(&iface_v0.mac_addr.octet, addr, ETH_ALEN);
3199 		}
3200 		ret = wldev_iovar_getbuf(ndev, "interface_create",
3201 			&iface_v0, sizeof(struct wl_interface_create),
3202 			ioctl_buf, sizeof(ioctl_buf), NULL);
3203 		if (ret == 0) {
3204 			info_v0 = (wl_interface_info_v0_t *)ioctl_buf;
3205 			ret = info_v0->bsscfgidx;
3206 			goto exit;
3207         }
3208 	} else {
3209 		ret = wldev_iovar_getbuf(ndev, "interface_create",
3210 			&iface, sizeof(struct wl_interface_create_v2),
3211 			ioctl_buf, sizeof(ioctl_buf), NULL);
3212 	}
3213 	if (ret == BCME_UNSUPPORTED) {
3214 		WL_ERR(("interface_create iovar not supported\n"));
3215 		return ret;
3216 	} else if ((ret == 0) && *((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3) {
3217 		WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags));
3218 		use_iface_info_v2 = true;
3219 		bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
3220 		iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
3221 		iface_v3.iftype = iftype;
3222 		iface_v3.flags = ifflags;
3223 		if (addr) {
3224 			memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
3225 		}
3226 		ret = wldev_iovar_getbuf(ndev, "interface_create",
3227 			&iface_v3, sizeof(wl_interface_create_v3_t),
3228 			ioctl_buf, sizeof(ioctl_buf), NULL);
3229 	} else if ((ret == 0) &&
3230 		((*((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_2) ||
3231 		(*((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_1))) {
3232 		/* Legacy firmware could invoke iovar and reply data
3233 		 * directly. Do not try if return ver is not expected.
3234 		 * On any other error, attempt with iovar version 2 */
3235 		WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n", ret, ifflags));
3236 		iface.ver = WL_INTERFACE_CREATE_VER_2;
3237 		iface.iftype = iftype;
3238 		iface.flags = ifflags;
3239 		if (addr) {
3240 			memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
3241 		}
3242 		ret = wldev_iovar_getbuf(ndev, "interface_create",
3243 			&iface, sizeof(struct wl_interface_create_v2),
3244 			ioctl_buf, sizeof(ioctl_buf), NULL);
3245 	} else {
3246 		/* inteface_create version 0, need to add chipnum in bcmdevs_legacy.h
3247 		 * and add new chip check at wl_legacy_chip_check function */
3248 		WL_DBG(("interface_create version 0. get_ver:%d ifflags:0x%x\n", ret, ifflags));
3249 	}
3250 
3251 	if (unlikely(ret)) {
3252 		WL_ERR(("Interface create failed!! ret %d\n", ret));
3253 		return ret;
3254 	}
3255 
3256 	/* success case */
3257 	if (use_iface_info_v2 == true) {
3258 		info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
3259 		ret = info_v2->bsscfgidx;
3260 	} else {
3261 		/* Use v1 struct */
3262 		info = (struct wl_interface_info_v1 *)ioctl_buf;
3263 		ret = info->bsscfgidx;
3264 	}
3265 
3266 exit:
3267 #ifdef WLEASYMESH
3268 	//Give fw more time to process interface_create
3269 	if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
3270 		wl_delay(500);
3271 	}
3272 #endif /* WLEASYMESH */
3273 	WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
3274 	return ret;
3275 }
3276 
3277 #ifdef CUSTOMER_HW6
3278 #define BCM4355_REV_C1 0x0c
3279 bool
wl_customer6_legacy_chip_check(struct bcm_cfg80211 * cfg,struct net_device * ndev)3280 wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg,
3281 	struct net_device *ndev)
3282 {
3283 	u32 chipnum;
3284 	wlc_rev_info_t revinfo;
3285 	int ret;
3286 
3287 	/* Get the device rev info */
3288 	bzero(&revinfo, sizeof(revinfo));
3289 	ret = wldev_ioctl_get(ndev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
3290 	if (ret < 0) {
3291 		WL_ERR(("wl_customer6_legacy_chip_check: GET revinfo FAILED. ret:%d\n", ret));
3292 		ASSERT(0);
3293 		return false;
3294 	}
3295 
3296 	chipnum = revinfo.chipnum;
3297 	WL_DBG(("wl_customer6_legacy_chip_check: GET_REVINFO device 0x%x, vendor 0x%x,"
3298 		" chipnum 0x%x\n",
3299 		dtoh32(revinfo.deviceid), dtoh32(revinfo.vendorid), dtoh32(chipnum)));
3300 	if (
3301 #ifdef BCM4350_CHIP_ID
3302 		(chipnum == BCM4350_CHIP_ID) ||
3303 #endif /* BCM4350_CHIP_ID */
3304 #ifdef BCM4355_CHIP_ID
3305 		((chipnum == BCM4355_CHIP_ID) && (revinfo.chiprev < BCM4355_REV_C1)) ||
3306 #endif /* BCM4355_CHIP_ID */
3307 #ifdef BCM4345_CHIP_ID
3308 		(chipnum == BCM4345_CHIP_ID) ||
3309 #endif /* BCM4345_CHIP_ID */
3310 		false) {
3311 		/* WAR required */
3312 		WL_DBG(("%s: Customer6 legacy chip identified\n", __FUNCTION__));
3313 		return true;
3314 	}
3315 
3316 	return false;
3317 }
3318 #endif /* CUSTOMER_HW6 */
3319 
3320 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)3321 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
3322 	struct net_device *ndev, s32 bsscfg_idx,
3323 	wl_iftype_t brcm_iftype, s32 del, u8 *addr)
3324 {
3325 	s32 ret = BCME_OK;
3326 	s32 val = 0;
3327 
3328 	struct {
3329 		s32 cfg;
3330 		s32 val;
3331 		struct ether_addr ea;
3332 	} bss_setbuf;
3333 
3334 	WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype, del));
3335 
3336 	bzero(&bss_setbuf, sizeof(bss_setbuf));
3337 
3338 	/* AP=2, STA=3, up=1, down=0, val=-1 */
3339 	if (del) {
3340 		val = WLC_AP_IOV_OP_DELETE;
3341 	} else if (brcm_iftype == WL_IF_TYPE_AP) {
3342 		/* Add/role change to AP Interface */
3343 		WL_DBG(("Adding AP Interface \n"));
3344 		val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
3345 	} else if (brcm_iftype == WL_IF_TYPE_STA) {
3346 		/* Add/role change to STA Interface */
3347 		WL_DBG(("Adding STA Interface \n"));
3348 		val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
3349 	} else {
3350 		WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype));
3351 		return -EINVAL;
3352 	}
3353 
3354 	if (!del) {
3355 		wl_ext_bss_iovar_war(ndev, &val);
3356 	}
3357 
3358 	bss_setbuf.cfg = htod32(bsscfg_idx);
3359 	bss_setbuf.val = htod32(val);
3360 
3361 	if (addr) {
3362 		memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
3363 	}
3364 
3365 	WL_MSG(ndev->name, "wl bss %d bssidx:%d\n", val, bsscfg_idx);
3366 	ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3367 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3368 	if (ret != 0)
3369 		WL_ERR(("'bss %d' failed with %d\n", val, ret));
3370 
3371 	return ret;
3372 }
3373 
3374 s32
wl_cfg80211_bss_up(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,s32 bss_up)3375 wl_cfg80211_bss_up(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 bss_up)
3376 {
3377 	s32 ret = BCME_OK;
3378 	s32 val = bss_up ? 1 : 0;
3379 
3380 	struct {
3381 		s32 cfg;
3382 		s32 val;
3383 	} bss_setbuf;
3384 
3385 	bss_setbuf.cfg = htod32(bsscfg_idx);
3386 	bss_setbuf.val = htod32(val);
3387 
3388 	WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx, bss_up ? "up" : "down"));
3389 	ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3390 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3391 
3392 	if (ret != 0) {
3393 		WL_ERR(("'bss %d' failed with %d\n", bss_up, ret));
3394 	}
3395 
3396 	return ret;
3397 }
3398 
3399 bool
wl_cfg80211_bss_isup(struct net_device * ndev,int bsscfg_idx)3400 wl_cfg80211_bss_isup(struct net_device *ndev, int bsscfg_idx)
3401 {
3402 	s32 result, val;
3403 	bool isup = false;
3404 	s8 getbuf[64];
3405 
3406 	/* Check if the BSS is up */
3407 	*(int*)getbuf = -1;
3408 	result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
3409 		sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
3410 	if (result != 0) {
3411 		WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
3412 		WL_ERR(("NOTE: this ioctl error is normal "
3413 			"when the BSS has not been created yet.\n"));
3414 	} else {
3415 		val = *(int*)getbuf;
3416 		val = dtoh32(val);
3417 		WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx, val));
3418 		isup = (val ? TRUE : FALSE);
3419 	}
3420 	return isup;
3421 }
3422 
3423 s32
wl_iftype_to_mode(wl_iftype_t iftype)3424 wl_iftype_to_mode(wl_iftype_t iftype)
3425 {
3426 	s32 mode = BCME_ERROR;
3427 
3428 	switch (iftype) {
3429 		case WL_IF_TYPE_STA:
3430 		case WL_IF_TYPE_P2P_GC:
3431 		case WL_IF_TYPE_P2P_DISC:
3432 			mode = WL_MODE_BSS;
3433 			break;
3434 		case WL_IF_TYPE_AP:
3435 		case WL_IF_TYPE_P2P_GO:
3436 			mode = WL_MODE_AP;
3437 			break;
3438 		case WL_IF_TYPE_NAN:
3439 			mode = WL_MODE_NAN;
3440 			break;
3441 
3442 #ifdef WLAWDL
3443 		case WL_IF_TYPE_AWDL:
3444 			mode = WL_MODE_AWDL;
3445 			break;
3446 #endif /* WLAWDL */
3447 
3448 		case WL_IF_TYPE_AIBSS:
3449 			/* Intentional fall through */
3450 		case WL_IF_TYPE_IBSS:
3451 			mode = WL_MODE_IBSS;
3452 			break;
3453 #ifdef WLMESH_CFG80211
3454 		case WL_IF_TYPE_MESH:
3455 			mode = WL_MODE_MESH;
3456 			break;
3457 #endif /* WLMESH_CFG80211 */
3458 		default:
3459 			WL_ERR(("Unsupported type:%d\n", iftype));
3460 			break;
3461 	}
3462 	return mode;
3463 }
3464 
3465 s32
cfg80211_to_wl_iftype(uint16 type,uint16 * role,uint16 * mode)3466 cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode)
3467 {
3468 	switch (type) {
3469 		case NL80211_IFTYPE_STATION:
3470 			*role = WL_IF_TYPE_STA;
3471 			*mode = WL_MODE_BSS;
3472 			break;
3473 		case NL80211_IFTYPE_AP:
3474 			*role = WL_IF_TYPE_AP;
3475 			*mode = WL_MODE_AP;
3476 			break;
3477 #ifdef WL_CFG80211_P2P_DEV_IF
3478 		case NL80211_IFTYPE_P2P_DEVICE:
3479 			*role = WL_IF_TYPE_P2P_DISC;
3480 			*mode = WL_MODE_BSS;
3481 			break;
3482 #endif /* WL_CFG80211_P2P_DEV_IF */
3483 		case NL80211_IFTYPE_P2P_GO:
3484 			*role = WL_IF_TYPE_P2P_GO;
3485 			*mode = WL_MODE_AP;
3486 			break;
3487 		case NL80211_IFTYPE_P2P_CLIENT:
3488 			*role = WL_IF_TYPE_P2P_GC;
3489 			*mode = WL_MODE_BSS;
3490 			break;
3491 		case NL80211_IFTYPE_MONITOR:
3492 			WL_ERR(("Unsupported mode \n"));
3493 			return BCME_UNSUPPORTED;
3494 		case NL80211_IFTYPE_ADHOC:
3495 			*role = WL_IF_TYPE_IBSS;
3496 			*mode = WL_MODE_IBSS;
3497 			break;
3498 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
3499 		case NL80211_IFTYPE_NAN:
3500 			*role = WL_IF_TYPE_NAN;
3501 			*mode = WL_MODE_NAN;
3502 			break;
3503 #endif
3504 #ifdef WLMESH_CFG80211
3505 		case NL80211_IFTYPE_MESH_POINT:
3506 			*role = WLC_E_IF_ROLE_AP;
3507 			*mode = WL_MODE_MESH;
3508 			break;
3509 #endif /* WLMESH_CFG80211 */
3510 		default:
3511 			WL_ERR(("Unknown interface type:0x%x\n", type));
3512 			return BCME_ERROR;
3513 	}
3514 	return BCME_OK;
3515 }
3516 
3517 static s32
wl_role_to_cfg80211_type(uint16 role,uint16 * wl_iftype,uint16 * mode)3518 wl_role_to_cfg80211_type(uint16 role, uint16 *wl_iftype, uint16 *mode)
3519 {
3520 	switch (role) {
3521 
3522 #ifdef WLAWDL
3523 	case WLC_E_IF_ROLE_AWDL:
3524 		/* Intentional fall through - Since there is no
3525 		 * corresponding iftype in cfg80211 stack, map
3526 		 * iftype to station.
3527 		 */
3528 		*wl_iftype = WL_IF_TYPE_AWDL;
3529 		*mode = WL_MODE_AWDL;
3530 		return NL80211_IFTYPE_STATION;
3531 #endif /* WLAWDL */
3532 
3533 	case WLC_E_IF_ROLE_STA:
3534 		*wl_iftype = WL_IF_TYPE_STA;
3535 		*mode = WL_MODE_BSS;
3536 		return NL80211_IFTYPE_STATION;
3537 	case WLC_E_IF_ROLE_AP:
3538 		*wl_iftype = WL_IF_TYPE_AP;
3539 		*mode = WL_MODE_AP;
3540 		return NL80211_IFTYPE_AP;
3541 	case WLC_E_IF_ROLE_P2P_GO:
3542 		*wl_iftype = WL_IF_TYPE_P2P_GO;
3543 		*mode = WL_MODE_AP;
3544 		return NL80211_IFTYPE_P2P_GO;
3545 	case WLC_E_IF_ROLE_P2P_CLIENT:
3546 		*wl_iftype = WL_IF_TYPE_P2P_GC;
3547 		*mode = WL_MODE_BSS;
3548 		return NL80211_IFTYPE_P2P_CLIENT;
3549 	case WLC_E_IF_ROLE_IBSS:
3550 		*wl_iftype = WL_IF_TYPE_IBSS;
3551 		*mode = WL_MODE_IBSS;
3552 		return NL80211_IFTYPE_ADHOC;
3553 	case WLC_E_IF_ROLE_NAN:
3554 		*wl_iftype = WL_IF_TYPE_NAN;
3555 		*mode = WL_MODE_NAN;
3556 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
3557 		/* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
3558 		 * For Vendor HAL based NAN implementation, continue advertising
3559 		 * as a STA interface
3560 		 */
3561 		return NL80211_IFTYPE_NAN;
3562 #else
3563 		return NL80211_IFTYPE_STATION;
3564 #endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
3565 #ifdef WLDWDS
3566 	case WLC_E_IF_ROLE_WDS:
3567 		*wl_iftype = WL_IF_TYPE_AP;
3568 		*mode = WL_MODE_AP;
3569 		return NL80211_IFTYPE_AP;
3570 #endif
3571 #ifdef WLMESH_CFG80211
3572 	case WLC_E_IF_ROLE_MESH:
3573 		*wl_iftype = WL_IF_TYPE_MESH;
3574 		*mode = WL_MODE_MESH;
3575 		return NL80211_IFTYPE_MESH_POINT;
3576 #endif /* WLMESH_CFG80211 */
3577 
3578 	default:
3579 		WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role));
3580 		return BCME_ERROR;
3581 	}
3582 }
3583 
3584 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)3585 wl_cfg80211_post_ifcreate(struct net_device *ndev,
3586 	wl_if_event_info *event, u8 *addr,
3587 	const char *name, bool rtnl_lock_reqd)
3588 {
3589 	struct bcm_cfg80211 *cfg;
3590 	struct net_device *primary_ndev;
3591 	struct net_device *new_ndev = NULL;
3592 	struct wireless_dev *wdev = NULL;
3593 	s32 iface_type;
3594 	s32 ret = BCME_OK;
3595 	u16 mode;
3596 	u8 mac_addr[ETH_ALEN];
3597 	u16 wl_iftype;
3598 
3599 	if (!ndev || !event) {
3600 		WL_ERR(("Wrong arg\n"));
3601 		return NULL;
3602 	}
3603 
3604 	cfg = wl_get_cfg(ndev);
3605 	if (!cfg) {
3606 		WL_ERR(("cfg null\n"));
3607 		return NULL;
3608 	}
3609 
3610 	WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
3611 		event->role, event->ifidx, event->bssidx));
3612 	if (!event->ifidx || !event->bssidx) {
3613 		/* Fw returned primary idx (0) for virtual interface */
3614 		WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
3615 			event->ifidx, event->bssidx));
3616 		return NULL;
3617 	}
3618 
3619 #if defined(WLMESH_CFG80211) && defined(WL_EXT_IAPSTA)
3620 	if (wl_ext_iapsta_mesh_creating(ndev)) {
3621 		event->role = WLC_E_IF_ROLE_MESH;
3622 		WL_MSG(ndev->name, "change role to WLC_E_IF_ROLE_MESH\n");
3623 	}
3624 #endif /* WLMESH_CFG80211 && WL_EXT_IAPSTA */
3625 
3626 	iface_type = wl_role_to_cfg80211_type(event->role, &wl_iftype, &mode);
3627 	if (iface_type < 0) {
3628 		/* Unknown iface type */
3629 		WL_ERR(("Wrong iface type \n"));
3630 		return NULL;
3631 	}
3632 
3633 	WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG "\n",
3634 		addr, name, event->role, iface_type, MAC2STRDBG(event->mac)));
3635 	if (!name) {
3636 		/* If iface name is not provided, use dongle ifname */
3637 		name = event->name;
3638 	}
3639 
3640 	if (!addr) {
3641 		/* If mac address is not set, use primary mac with locally administered
3642 		 * bit set.
3643 		 */
3644 		primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3645 		memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
3646 #ifndef CUSTOMER_HW6
3647 		/* For customer6 builds, use primary mac address for virtual interface */
3648 		mac_addr[0] |= 0x02;
3649 #endif /* CUSTOMER_HW6 */
3650 		addr = mac_addr;
3651 	}
3652 
3653 	if (iface_type == NL80211_IFTYPE_P2P_CLIENT) {
3654 		struct ether_addr *p2p_addr;
3655 		s16 cfg_type = wl_cfgp2p_get_conn_idx(cfg);
3656 		if (cfg_type < BCME_OK) {
3657 			WL_ERR(("Failed to get connection idx for p2p interface"
3658 				", error code = %d", cfg_type));
3659 			goto fail;
3660 		}
3661 		p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
3662 
3663 		/* check if pre-registered mac matches the mac from dongle via WLC_E_LINK */
3664 		if (memcmp(p2p_addr->octet, addr, ETH_ALEN)) {
3665 			WL_INFORM_MEM(("p2p pre-regsitered mac:" MACDBG
3666 				" , mac from dongle:" MACDBG "\n",
3667 				MAC2STRDBG(p2p_addr->octet), MAC2STRDBG(addr)));
3668 
3669 			primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3670 
3671 			wl_cfg80211_handle_hang_event(primary_ndev,
3672 				HANG_REASON_IFACE_ADD_FAILURE, DUMP_TYPE_IFACE_OP_FAILURE);
3673 			goto fail;
3674 		}
3675 	}
3676 
3677 #ifdef WL_STATIC_IF
3678 	if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
3679 		new_ndev = wl_cfg80211_post_static_ifcreate(cfg, event, addr, iface_type);
3680 		if (!new_ndev) {
3681 			WL_ERR(("failed to get I/F pointer\n"));
3682 			return NULL;
3683 		}
3684 		wdev = new_ndev->ieee80211_ptr;
3685 	} else
3686 #endif /* WL_STATIC_IF */
3687 	{
3688 		new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
3689 			name, addr, event->bssidx, event->name);
3690 		if (!new_ndev) {
3691 			WL_ERR(("I/F allocation failed! \n"));
3692 			return NULL;
3693 		} else {
3694 			WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
3695 			 event->ifidx, event->bssidx));
3696 		}
3697 
3698 		wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
3699 		if (!wdev) {
3700 			WL_ERR(("wireless_dev alloc failed! \n"));
3701 			wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
3702 			return NULL;
3703 		}
3704 
3705 		wdev->wiphy = bcmcfg_to_wiphy(cfg);
3706 		wdev->iftype = iface_type;
3707 
3708 		new_ndev->ieee80211_ptr = wdev;
3709 #ifdef WLDWDS
3710 		/* set wds0.x to 4addr interface here */
3711 		if (event->role == WLC_E_IF_ROLE_WDS) {
3712 			WL_MSG(ndev->name, "set vwdev 4addr to %s\n", event->name);
3713 			wdev->use_4addr = true;
3714 		}
3715 #endif /* WLDWDS */
3716 		SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
3717 
3718 		memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
3719 #ifdef WL_EXT_IAPSTA
3720 		wl_ext_iapsta_ifadding(new_ndev, event->ifidx);
3721 #endif /* WL_EXT_IAPSTA */
3722 		if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd)
3723 			!= BCME_OK) {
3724 			WL_ERR(("IFACE register failed \n"));
3725 			/* Post interface registration, wdev would be freed from the netdev
3726 			 * destructor path. For other cases, handle it here.
3727 			 */
3728 			MFREE(cfg->osh, wdev, sizeof(*wdev));
3729 			wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
3730 			return NULL;
3731 		}
3732 	}
3733 
3734 	/* Initialize with the station mode params */
3735 	ret = wl_alloc_netinfo(cfg, new_ndev, wdev, wl_iftype,
3736 		PM_ENABLE, event->bssidx, event->ifidx);
3737 	if (unlikely(ret)) {
3738 		WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret));
3739 		goto fail;
3740 	}
3741 
3742 	/* Apply the mode & infra setting based on iftype */
3743 	if ((ret = wl_config_infra(cfg, new_ndev, wl_iftype)) < 0) {
3744 		WL_ERR(("config ifmode failure (%d)\n", ret));
3745 		goto fail;
3746 	}
3747 
3748 	if (mode == WL_MODE_AP) {
3749 		wl_set_drv_status(cfg, AP_CREATING, new_ndev);
3750 	}
3751 #ifdef WL_EXT_IAPSTA
3752 	wl_ext_iapsta_update_iftype(new_ndev, event->ifidx, wl_iftype);
3753 #endif
3754 
3755 	WL_INFORM_MEM(("Network Interface (%s) registered with host."
3756 		" cfg_iftype:%d wl_role:%d " MACDBG "\n",
3757 		new_ndev->name, iface_type, event->role, MAC2STRDBG(new_ndev->dev_addr)));
3758 
3759 #ifdef SUPPORT_SET_CAC
3760 	wl_cfg80211_set_cac(cfg, 0);
3761 #endif /* SUPPORT_SET_CAC */
3762 
3763 	return new_ndev;
3764 
3765 fail:
3766 #ifdef WL_STATIC_IF
3767 	/* remove static if from iflist */
3768 	if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
3769 		cfg->static_ndev_state = NDEV_STATE_FW_IF_FAILED;
3770 		wl_cfg80211_update_iflist_info(cfg, new_ndev, WL_STATIC_IFIDX, addr,
3771 			event->bssidx, event->name, NDEV_STATE_FW_IF_FAILED);
3772 	}
3773 #endif /* WL_STATIC_IF */
3774 	if (new_ndev) {
3775 		/* wdev would be freed from netdev destructor call back */
3776 		wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
3777 	}
3778 
3779 	return NULL;
3780 }
3781 
3782 s32
wl_cfg80211_delete_iface(struct bcm_cfg80211 * cfg,wl_iftype_t sec_data_if_type)3783 wl_cfg80211_delete_iface(struct bcm_cfg80211 *cfg,
3784 	wl_iftype_t sec_data_if_type)
3785 {
3786 	struct net_info *iter, *next;
3787 	struct net_device *primary_ndev;
3788 	s32 ret = BCME_OK;
3789 	uint8 i = 0;
3790 
3791 	BCM_REFERENCE(i);
3792 	BCM_REFERENCE(ret);
3793 
3794 	/* Note: This function will clean up only the network interface and host
3795 	 * data structures. The firmware interface clean up will happen in the
3796 	 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
3797 	 * context for the module case).
3798 	 */
3799 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3800 	WL_DBG(("Enter, deleting iftype  %s\n",
3801 		wl_iftype_to_str(sec_data_if_type)));
3802 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3803 	for_each_ndev(cfg, iter, next) {
3804 		GCC_DIAGNOSTIC_POP();
3805 		if (iter->ndev && (iter->ndev != primary_ndev)) {
3806 			if (iter->iftype != sec_data_if_type) {
3807 				continue;
3808 			}
3809 			switch (sec_data_if_type) {
3810 				case WL_IF_TYPE_P2P_GO:
3811 				case WL_IF_TYPE_P2P_GC: {
3812 					ret = _wl_cfg80211_del_if(cfg,
3813 						iter->ndev, NULL, iter->ndev->name);
3814 					break;
3815 				}
3816 #ifdef WL_NAN
3817 				case WL_IF_TYPE_NAN: {
3818 					if (wl_cfgnan_is_enabled(cfg) == false) {
3819 						WL_INFORM_MEM(("Nan is not active,"
3820 							" ignore NDI delete\n"));
3821 					} else {
3822 						ret = wl_cfgnan_delete_ndp(cfg, iter->ndev);
3823 					}
3824 					break;
3825 				}
3826 #endif /* WL_NAN */
3827 				case WL_IF_TYPE_AP: {
3828 					/* Cleanup AP */
3829 #ifdef WL_STATIC_IF
3830 						/* handle static ap */
3831 					if (IS_CFG80211_STATIC_IF(cfg, iter->ndev)) {
3832 						dev_close(iter->ndev);
3833 					} else
3834 #endif /* WL_STATIC_IF */
3835 					{
3836 						/* handle virtual created AP */
3837 						ret = _wl_cfg80211_del_if(cfg, iter->ndev,
3838 							NULL, iter->ndev->name);
3839 					}
3840 					break;
3841 				}
3842 				default: {
3843 					WL_ERR(("Unsupported interface type\n"));
3844 					ret = -ENOTSUPP;
3845 					goto fail;
3846 				}
3847 			}
3848 		}
3849 	}
3850 fail:
3851 	return ret;
3852 }
3853 
3854 s32
wl_cfg80211_post_ifdel(struct net_device * ndev,bool rtnl_lock_reqd,s32 ifidx)3855 wl_cfg80211_post_ifdel(struct net_device *ndev, bool rtnl_lock_reqd, s32 ifidx)
3856 {
3857 	s32 ret = BCME_OK;
3858 	struct bcm_cfg80211 *cfg;
3859 	struct net_info *netinfo = NULL;
3860 
3861 	if (!ndev || !ndev->ieee80211_ptr) {
3862 		/* No wireless dev done for this interface */
3863 		ret = -EINVAL;
3864 		goto exit;
3865 	}
3866 
3867 	cfg = wl_get_cfg(ndev);
3868 	if (!cfg) {
3869 		WL_ERR(("cfg null\n"));
3870 		ret = BCME_ERROR;
3871 		goto exit;
3872 	}
3873 
3874 	if (ifidx <= 0) {
3875 		WL_ERR(("Invalid IF idx for iface:%s\n", ndev->name));
3876 #if defined(BCMDONGLEHOST)
3877 		ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
3878 		BCM_REFERENCE(ifidx);
3879 #endif
3880 		if (ifidx <= 0) {
3881 			ASSERT(0);
3882 			ret = BCME_ERROR;
3883 			goto exit;
3884 		}
3885 	}
3886 
3887 	if ((netinfo = wl_get_netinfo_by_wdev(cfg, ndev_to_wdev(ndev))) == NULL) {
3888 		WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev)));
3889 		ret = -ENODEV;
3890 		goto exit;
3891 	}
3892 
3893 #ifdef WL_STATIC_IF
3894 	if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
3895 		ret = wl_cfg80211_post_static_ifdel(cfg, ndev);
3896 	} else
3897 #endif /* WL_STATIC_IF */
3898 	{
3899 		WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
3900 			ndev->name, ifidx, cfg->vif_count));
3901 		wl_cfg80211_remove_if(cfg, ifidx, ndev, rtnl_lock_reqd);
3902 		cfg->bss_pending_op = FALSE;
3903 	}
3904 
3905 #ifdef SUPPORT_SET_CAC
3906 	wl_cfg80211_set_cac(cfg, 1);
3907 #endif /* SUPPORT_SET_CAC */
3908 exit:
3909 	return ret;
3910 }
3911 
3912 int
wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 * cfg)3913 wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 *cfg)
3914 {
3915 	s32 ret = BCME_OK;
3916 	bcm_struct_cfgdev *cfgdev;
3917 
3918 	if (cfg->p2p) {
3919 		/* De-initialize the p2p discovery interface, if operational */
3920 		WL_ERR(("Disabling P2P Discovery Interface \n"));
3921 #ifdef WL_CFG80211_P2P_DEV_IF
3922 		cfgdev = bcmcfg_to_p2p_wdev(cfg);
3923 #else
3924 		cfgdev = cfg->p2p_net;
3925 #endif
3926 		if (cfgdev) {
3927 			ret = wl_cfg80211_scan_stop(cfg, cfgdev);
3928 			if (unlikely(ret < 0)) {
3929 				CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
3930 			}
3931 		}
3932 
3933 		wl_cfgp2p_disable_discovery(cfg);
3934 		wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
3935 		p2p_on(cfg) = false;
3936 	}
3937 	return ret;
3938 }
3939 
3940 /* Create a Generic Network Interface and initialize it depending up on
3941  * the interface type
3942  */
3943 struct wireless_dev *
wl_cfg80211_create_iface(struct wiphy * wiphy,wl_iftype_t wl_iftype,u8 * mac_addr,const char * name)3944 wl_cfg80211_create_iface(struct wiphy *wiphy,
3945 	wl_iftype_t wl_iftype,
3946 	u8 *mac_addr, const char *name)
3947 {
3948 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3949 	struct net_device *new_ndev = NULL;
3950 	struct net_device *primary_ndev = NULL;
3951 	s32 ret = BCME_OK;
3952 	s32 bsscfg_idx = 0;
3953 	long timeout;
3954 	wl_if_event_info *event = NULL;
3955 	u8 addr[ETH_ALEN];
3956 	struct net_info *iter, *next;
3957 
3958 	WL_DBG(("Enter\n"));
3959 	if (!name) {
3960 		WL_ERR(("Interface name not provided\n"));
3961 		return NULL;
3962 	}
3963 	else {
3964 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3965 		for_each_ndev(cfg, iter, next) {
3966 			GCC_DIAGNOSTIC_POP();
3967 			if (iter->ndev) {
3968 				if (strncmp(iter->ndev->name, name, strlen(name)) == 0) {
3969 					WL_ERR(("Interface name,%s exists!\n", iter->ndev->name));
3970 					return NULL;
3971 				}
3972 			}
3973 		}
3974 	}
3975 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3976 	if (likely(!mac_addr)) {
3977 		/* Use primary MAC with the locally administered bit for the
3978 		 *  Secondary STA I/F
3979 		 */
3980 		memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
3981 		addr[0] |= 0x02;
3982 	} else {
3983 		/* Use the application provided mac address (if any) */
3984 		memcpy(addr, mac_addr, ETH_ALEN);
3985 	}
3986 
3987 	cfg->bss_pending_op = TRUE;
3988 	bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3989 
3990 	/*
3991 	 * Intialize the firmware I/F.
3992 	 */
3993 
3994 #ifdef CUSTOMER_HW6
3995 	if (wl_customer6_legacy_chip_check(cfg, primary_ndev)) {
3996 		/* Use bss iovar instead of interface_create iovar */
3997 		ret = BCME_UNSUPPORTED;
3998 	} else
3999 #endif /* CUSTOMER_HW6 */
4000 
4001 	{
4002 		ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
4003 			wl_iftype, 0, addr);
4004 	}
4005 	if (ret == BCME_UNSUPPORTED) {
4006 		/* Use bssidx 1 by default */
4007 		bsscfg_idx = 1;
4008 		if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
4009 			bsscfg_idx, wl_iftype, 0, addr)) < 0) {
4010 			goto exit;
4011 		}
4012 	} else if (ret < 0) {
4013 		WL_ERR(("Interface create failed!! ret:%d \n", ret));
4014 		goto exit;
4015 	} else {
4016 		/* Success */
4017 		bsscfg_idx = ret;
4018 	}
4019 
4020 	WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
4021 	/*
4022 	 * Wait till the firmware send a confirmation event back.
4023 	 */
4024 	WL_DBG(("Wait for the FW I/F Event\n"));
4025 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4026 		!cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4027 	if (timeout <= 0 || cfg->bss_pending_op) {
4028 		WL_ERR(("ADD_IF event, didn't come. Return. timeout:%lu bss_pending_op:%d\n",
4029 			timeout, cfg->bss_pending_op));
4030 		if (timeout == -ERESTARTSYS) {
4031 			WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
4032 		}
4033 		goto exit;
4034 	}
4035 
4036 	event = &cfg->if_event_info;
4037 	/*
4038 	 * Since FW operation is successful,we can go ahead with the
4039 	 * the host interface creation.
4040 	 */
4041 	new_ndev = wl_cfg80211_post_ifcreate(primary_ndev,
4042 		event, addr, name, false);
4043 
4044 	if (new_ndev) {
4045 		/* Iface post ops successful. Return ndev/wdev ptr */
4046 		return new_ndev->ieee80211_ptr;
4047 	}
4048 
4049 exit:
4050 	cfg->bss_pending_op = FALSE;
4051 	return NULL;
4052 }
4053 
4054 s32
wl_cfg80211_del_iface(struct wiphy * wiphy,struct wireless_dev * wdev)4055 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
4056 {
4057 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4058 	struct net_device *ndev = NULL;
4059 	s32 ret = BCME_OK;
4060 	s32 bsscfg_idx = 1;
4061 	long timeout;
4062 	u16 wl_iftype;
4063 	u16 wl_mode;
4064 
4065 	WL_DBG(("Enter\n"));
4066 
4067 	/* If any scan is going on, abort it */
4068 	if (wl_get_drv_status_all(cfg, SCANNING)) {
4069 		WL_DBG(("Scan in progress. Aborting the scan!\n"));
4070 		wl_cfgscan_cancel_scan(cfg);
4071 	}
4072 
4073 	bsscfg_idx = wl_get_bssidx_by_wdev(cfg, wdev);
4074 	if (bsscfg_idx <= 0) {
4075 		/* validate bsscfgidx */
4076 		WL_ERR(("Wrong bssidx! \n"));
4077 		return -EINVAL;
4078 	}
4079 
4080 	/* Handle p2p iface */
4081 	if ((ret = wl_cfg80211_p2p_if_del(wiphy, wdev)) != BCME_NOTFOUND) {
4082 		WL_DBG(("P2P iface del handled \n"));
4083 #ifdef SUPPORT_SET_CAC
4084 		wl_cfg80211_set_cac(cfg, 1);
4085 #endif /* SUPPORT_SET_CAC */
4086 		return ret;
4087 	}
4088 
4089 	ndev = wdev->netdev;
4090 	if (unlikely(!ndev)) {
4091 		WL_ERR(("ndev null! \n"));
4092 		return -EINVAL;
4093 	}
4094 
4095 	memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4096 
4097 	if (cfg80211_to_wl_iftype(ndev->ieee80211_ptr->iftype,
4098 		&wl_iftype, &wl_mode) < 0) {
4099 		return -EINVAL;
4100 	}
4101 
4102 	WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d",
4103 		bsscfg_idx, ndev->ieee80211_ptr->iftype, wl_iftype));
4104 	/* Delete the firmware interface. "interface_remove" command
4105 	 * should go on the interface to be deleted
4106 	 */
4107 	if (wl_cfg80211_get_bus_state(cfg)) {
4108 		WL_ERR(("Bus state is down: %d\n", __LINE__));
4109 		ret = BCME_DONGLE_DOWN;
4110 		goto exit;
4111 	}
4112 
4113 	cfg->bss_pending_op = true;
4114 	ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx,
4115 		wl_iftype, 1, NULL);
4116 	if (ret == BCME_UNSUPPORTED) {
4117 		if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
4118 			bsscfg_idx, wl_iftype, true, NULL)) < 0) {
4119 			WL_ERR(("DEL bss failed ret:%d \n", ret));
4120 			goto exit;
4121 		}
4122 	} else if ((ret == BCME_NOTAP) || (ret == BCME_NOTSTA)) {
4123 		/* De-init sequence involving role downgrade not happened.
4124 		 * Do nothing and return error. The del command should be
4125 		 * retried.
4126 		 */
4127 		WL_ERR(("ifdel role mismatch:%d\n", ret));
4128 		ret = -EBADTYPE;
4129 		goto exit;
4130 	} else if (ret < 0) {
4131 		WL_ERR(("Interface DEL failed ret:%d \n", ret));
4132 		goto exit;
4133 	}
4134 
4135 	timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4136 		!cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4137 	if (timeout <= 0 || cfg->bss_pending_op) {
4138 		WL_ERR(("timeout in waiting IF_DEL event\n"));
4139 		/* The interface unregister will happen from wifi reset context */
4140 		ret = -ETIMEDOUT;
4141 		/* fall through */
4142 	}
4143 
4144 exit:
4145 	if (ret < 0) {
4146 		WL_ERR(("iface del failed:%d\n", ret));
4147 #ifdef WL_STATIC_IF
4148 		if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
4149 			/*
4150 			 * For static interface, clean up the host data,
4151 			 * irrespective of fw status. For dynamic
4152 			 * interfaces it gets cleaned from dhd_stop context
4153 			 */
4154 			wl_cfg80211_post_static_ifdel(cfg, ndev);
4155 		}
4156 #endif /* WL_STATIC_IF */
4157 	} else {
4158 		ret = wl_cfg80211_post_ifdel(ndev, false, cfg->if_event_info.ifidx);
4159 		if (unlikely(ret)) {
4160 			WL_ERR(("post_ifdel failed\n"));
4161 		}
4162 	}
4163 
4164 	cfg->bss_pending_op = false;
4165 	return ret;
4166 }
4167 
4168 static s32
wl_cfg80211_join_ibss(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ibss_params * params)4169 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
4170 	struct cfg80211_ibss_params *params)
4171 {
4172 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4173 	struct cfg80211_bss *bss;
4174 	struct ieee80211_channel *chan;
4175 	struct wl_join_params join_params;
4176 	int scan_suppress;
4177 	struct cfg80211_ssid ssid;
4178 	s32 scan_retry = 0;
4179 	s32 err = 0;
4180 	size_t join_params_size;
4181 	chanspec_t chanspec = 0;
4182 
4183 	WL_TRACE(("In\n"));
4184 	RETURN_EIO_IF_NOT_UP(cfg);
4185 	WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
4186 	if (!params->ssid || params->ssid_len <= 0 ||
4187 		params->ssid_len > DOT11_MAX_SSID_LEN) {
4188 		WL_ERR(("Invalid parameter\n"));
4189 		return -EINVAL;
4190 	}
4191 #if defined(WL_CFG80211_P2P_DEV_IF)
4192 	chan = params->chandef.chan;
4193 #else
4194 	chan = params->channel;
4195 #endif /* WL_CFG80211_P2P_DEV_IF */
4196 	if (chan) {
4197 		cfg->channel = wl_freq_to_chanspec(chan->center_freq);
4198 	}
4199 	if (wl_get_drv_status(cfg, CONNECTED, dev)) {
4200 		struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
4201 		u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
4202 		u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
4203 		if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
4204 			(memcmp(params->ssid, lssid->SSID, lssid->SSID_len) == 0) &&
4205 			(*channel == cfg->channel))) {
4206 			WL_ERR(("Connection already existed to " MACDBG "\n",
4207 				MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
4208 			return -EISCONN;
4209 		}
4210 		WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n",
4211 			lssid->SSID, MAC2STRDBG(bssid)));
4212 	}
4213 
4214 	/* remove the VSIE */
4215 	wl_cfg80211_ibss_vsie_delete(dev);
4216 
4217 	bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
4218 	if (!bss) {
4219 		if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
4220 			memcpy(ssid.ssid, params->ssid, params->ssid_len);
4221 			ssid.ssid_len = params->ssid_len;
4222 			do {
4223 				if (unlikely
4224 					(__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
4225 					 -EBUSY)) {
4226 					wl_delay(150);
4227 				} else {
4228 					break;
4229 				}
4230 			} while (++scan_retry < WL_SCAN_RETRY_MAX);
4231 
4232 			/* rtnl lock code is removed here. don't see why rtnl lock
4233 			 * needs to be released.
4234 			 */
4235 
4236 			/* wait 4 secons till scan done.... */
4237 			schedule_timeout_interruptible(msecs_to_jiffies(4000));
4238 
4239 			bss = cfg80211_get_ibss(wiphy, NULL,
4240 				params->ssid, params->ssid_len);
4241 		}
4242 	}
4243 	if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
4244 		((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
4245 		!memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
4246 		cfg->ibss_starter = false;
4247 		WL_DBG(("Found IBSS\n"));
4248 	} else {
4249 		cfg->ibss_starter = true;
4250 	}
4251 
4252 	if (bss) {
4253 		CFG80211_PUT_BSS(wiphy, bss);
4254 	}
4255 
4256 	if (chan) {
4257 		u32 bw_cap = 0;
4258 		err = wl_get_bandwidth_cap(dev, CHSPEC_BAND(cfg->channel), &bw_cap);
4259 		if (unlikely(err)) {
4260 			WL_ERR(("Failed to get bandwidth capability (%d)\n", err));
4261 			return err;
4262 		}
4263 		chanspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(cfg->channel),
4264 			bw_cap, CHSPEC_BAND(cfg->channel));
4265 	}
4266 
4267 	/*
4268 	 * Join with specific BSSID and cached SSID
4269 	 * If SSID is zero join based on BSSID only
4270 	 */
4271 	bzero(&join_params, sizeof(join_params));
4272 	memcpy((void *)join_params.ssid.SSID, (const void *)params->ssid,
4273 		params->ssid_len);
4274 	join_params.ssid.SSID_len = htod32(params->ssid_len);
4275 	if (params->bssid) {
4276 		memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
4277 		err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
4278 			ETHER_ADDR_LEN);
4279 		if (unlikely(err)) {
4280 			WL_ERR(("Error (%d)\n", err));
4281 			return err;
4282 		}
4283 	} else
4284 		bzero(&join_params.params.bssid, ETHER_ADDR_LEN);
4285 
4286 	if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
4287 		scan_suppress = TRUE;
4288 		/* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
4289 		err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
4290 			&scan_suppress, sizeof(int));
4291 		if (unlikely(err)) {
4292 			WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
4293 			return err;
4294 		}
4295 	}
4296 
4297 	join_params.params.chanspec_list[0] = chanspec;
4298 	join_params.params.chanspec_num = 1;
4299 	wldev_iovar_setint(dev, "chanspec", chanspec);
4300 	join_params_size = sizeof(join_params);
4301 
4302 	/* Disable Authentication, IBSS will add key if it required */
4303 	wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
4304 	wldev_iovar_setint(dev, "wsec", 0);
4305 
4306 	err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
4307 		join_params_size);
4308 	if (unlikely(err)) {
4309 		WL_ERR(("IBSS set_ssid Error (%d)\n", err));
4310 		return err;
4311 	}
4312 
4313 	if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
4314 		scan_suppress = FALSE;
4315 		/* Reset the SCAN SUPPRESS Flag */
4316 		err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
4317 			&scan_suppress, sizeof(int));
4318 		if (unlikely(err)) {
4319 			WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
4320 			return err;
4321 		}
4322 	}
4323 	wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
4324 	wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
4325 #ifdef WLAIBSS
4326 	cfg->aibss_txfail_seq = 0;	/* initialize the sequence */
4327 #endif /* WLAIBSS */
4328 #ifdef WL_RELMCAST
4329 	cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
4330 #endif /* WL_RELMCAST */
4331 	return err;
4332 }
4333 
wl_cfg80211_leave_ibss(struct wiphy * wiphy,struct net_device * dev)4334 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
4335 {
4336 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4337 	s32 err = 0;
4338 	scb_val_t scbval;
4339 	u8 *curbssid;
4340 
4341 	RETURN_EIO_IF_NOT_UP(cfg);
4342 	wl_link_down(cfg);
4343 
4344 	WL_INFORM_MEM(("Leave IBSS\n"));
4345 	curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
4346 	wl_set_drv_status(cfg, DISCONNECTING, dev);
4347 	scbval.val = 0;
4348 	memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
4349 	err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
4350 		sizeof(scb_val_t));
4351 	if (unlikely(err)) {
4352 		wl_clr_drv_status(cfg, DISCONNECTING, dev);
4353 		WL_ERR(("error(%d)\n", err));
4354 		return err;
4355 	}
4356 
4357 	/* remove the VSIE */
4358 	wl_cfg80211_ibss_vsie_delete(dev);
4359 
4360 	return err;
4361 }
4362 
4363 #ifdef MFP
4364 static
wl_cfg80211_get_rsn_capa(const bcm_tlv_t * wpa2ie,const u8 ** rsn_cap)4365 int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie,
4366 	const u8** rsn_cap)
4367 {
4368 	u16 suite_count;
4369 	const wpa_suite_mcast_t *mcast;
4370 	const wpa_suite_ucast_t *ucast;
4371 	int len;
4372 	const wpa_suite_auth_key_mgmt_t *mgmt;
4373 
4374 	if (!wpa2ie)
4375 		return BCME_BADARG;
4376 
4377 	len = wpa2ie->len;
4378 
4379 	/* check for Multicast cipher suite */
4380 	if ((len -= (WPA_SUITE_LEN + WPA2_VERSION_LEN)) <= 0) {
4381 		return BCME_NOTFOUND;
4382 	}
4383 
4384 	mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
4385 
4386 	/* Check for the unicast suite(s) */
4387 	if (len < WPA_IE_SUITE_COUNT_LEN) {
4388 		return BCME_NOTFOUND;
4389 	}
4390 
4391 	ucast = (const wpa_suite_ucast_t *)&mcast[1];
4392 	suite_count = ltoh16_ua(&ucast->count);
4393 	if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
4394 		(len -= (WPA_IE_SUITE_COUNT_LEN +
4395 		(WPA_SUITE_LEN * suite_count))) <= 0)
4396 		return BCME_BADLEN;
4397 
4398 	/* Check for AUTH key management suite(s) */
4399 	if (len < WPA_IE_SUITE_COUNT_LEN) {
4400 		return BCME_NOTFOUND;
4401 	}
4402 
4403 	mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
4404 	suite_count = ltoh16_ua(&mgmt->count);
4405 
4406 	if ((suite_count <= NL80211_MAX_NR_CIPHER_SUITES) &&
4407 			(len -= (WPA_IE_SUITE_COUNT_LEN +
4408 			(WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
4409 		rsn_cap[0] = (const u8 *)&mgmt->list[suite_count];
4410 	} else {
4411 		return BCME_BADLEN;
4412 	}
4413 
4414 	return BCME_OK;
4415 }
4416 #endif /* MFP */
4417 
4418 static s32
wl_set_wpa_version(struct net_device * dev,struct cfg80211_connect_params * sme)4419 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
4420 {
4421 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4422 	struct wl_security *sec;
4423 	s32 val = 0;
4424 	s32 err = 0;
4425 	s32 bssidx;
4426 
4427 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4428 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4429 		return BCME_ERROR;
4430 	}
4431 
4432 	if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
4433 		val = WPA_AUTH_PSK |
4434 			WPA_AUTH_UNSPECIFIED;
4435 	else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
4436 		val = WPA2_AUTH_PSK|
4437 			WPA2_AUTH_UNSPECIFIED;
4438 	else
4439 		val = WPA_AUTH_DISABLED;
4440 
4441 	if (is_wps_conn(sme))
4442 		val = WPA_AUTH_DISABLED;
4443 
4444 	WL_DBG_MEM(("[%s] wl wpa_auth 0x%0x\n", dev->name, val));
4445 	err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
4446 	if (unlikely(err)) {
4447 		WL_ERR(("set wpa_auth failed (%d)\n", err));
4448 		return err;
4449 	}
4450 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4451 	sec->wpa_versions = sme->crypto.wpa_versions;
4452 	return err;
4453 }
4454 
4455 #ifdef BCMWAPI_WPI
4456 static s32
wl_set_set_wapi_ie(struct net_device * dev,struct cfg80211_connect_params * sme)4457 wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme)
4458 {
4459 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4460 	s32 err = 0;
4461 	s32 bssidx;
4462 
4463 	WL_DBG((" wl_set_set_wapi_ie\n"));
4464 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4465 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4466 		return BCME_ERROR;
4467 	}
4468 
4469 	err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", (const void *)sme->ie, sme->ie_len,
4470 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
4471 	if (unlikely(err)) {
4472 		WL_ERR(("set_wapi_ie Error (%d)\n", err));
4473 		return err;
4474 	}
4475 	WL_DBG_MEM(("wapi_ie successfully (%s)\n", dev->name));
4476 	return err;
4477 }
4478 #endif /* BCMWAPI_WPI */
4479 
4480 static s32
wl_set_auth_type(struct net_device * dev,struct cfg80211_connect_params * sme)4481 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
4482 {
4483 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4484 	struct wl_security *sec;
4485 	s32 val = 0;
4486 	s32 err = 0;
4487 	s32 bssidx;
4488 
4489 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4490 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4491 		return BCME_ERROR;
4492 	}
4493 
4494 	switch (sme->auth_type) {
4495 	case NL80211_AUTHTYPE_OPEN_SYSTEM:
4496 		val = WL_AUTH_OPEN_SYSTEM;
4497 		WL_DBG(("open system\n"));
4498 		break;
4499 	case NL80211_AUTHTYPE_SHARED_KEY:
4500 		val = WL_AUTH_SHARED_KEY;
4501 		WL_DBG(("shared key\n"));
4502 		break;
4503 	case NL80211_AUTHTYPE_AUTOMATIC:
4504 		val = WL_AUTH_OPEN_SHARED;
4505 		WL_DBG(("automatic\n"));
4506 		break;
4507 #ifdef WL_FILS
4508 	case NL80211_AUTHTYPE_FILS_SK:
4509 		WL_DBG(("fils shared key\n"));
4510 		val = WL_AUTH_FILS_SHARED;
4511 		break;
4512 	case NL80211_AUTHTYPE_FILS_SK_PFS:
4513 		val = WL_AUTH_FILS_SHARED_PFS;
4514 		WL_DBG(("fils shared key with pfs\n"));
4515 		break;
4516 	case NL80211_AUTHTYPE_FILS_PK:
4517 		WL_DBG(("fils public key\n"));
4518 		val = WL_AUTH_FILS_PUBLIC;
4519 		break;
4520 #endif /* WL_FILS */
4521 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
4522 	case NL80211_AUTHTYPE_SAE:
4523 #ifdef WL_CLIENT_SAE
4524 		if (!wl_is_pmkid_available(dev, sme->bssid))
4525 			val = DOT11_SAE;
4526 		else
4527 #endif /* WL_CLIENT_SAE */
4528 		{
4529 			/* Fw will choose right auth type
4530 			 * dynamically based on PMKID availability
4531 			 */
4532 			val = WL_AUTH_OPEN_SHARED;
4533 		}
4534 
4535 		WL_DBG(("sae auth type\n"));
4536 		break;
4537 #endif /* WL_SAE || WL_CLIENT_SAE */
4538 	default:
4539 		val = 2;
4540 		WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
4541 		break;
4542 	}
4543 
4544 	WL_DBG_MEM(("[%s] wl auth 0x%0x \n", dev->name, val));
4545 	err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
4546 	if (unlikely(err)) {
4547 		WL_ERR(("set auth failed (%d)\n", err));
4548 		return err;
4549 	}
4550 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4551 	sec->auth_type = sme->auth_type;
4552 	sec->fw_auth = val;
4553 	return err;
4554 }
4555 
4556 static u32
wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)4557 wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)
4558 {
4559 	uint i;
4560 
4561 	for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
4562 		if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
4563 			return rsn_cipher_algo_lookup_tbl[i].wsec_algo;
4564 		}
4565 	}
4566 	return WSEC_NONE;
4567 }
4568 
4569 static u32
wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)4570 wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)
4571 {
4572 	uint i;
4573 
4574 	for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
4575 		if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
4576 			return rsn_cipher_algo_lookup_tbl[i].wsec_key_algo;
4577 		}
4578 	}
4579 	return CRYPTO_ALGO_OFF;
4580 }
4581 
4582 static u32
wl_rsn_akm_wpa_auth_lookup(uint32 akm)4583 wl_rsn_akm_wpa_auth_lookup(uint32 akm)
4584 {
4585 	uint i;
4586 
4587 	for (i = 0; i < ARRAYSIZE(rsn_akm_wpa_auth_lookup_tbl); i++) {
4588 		if (akm == rsn_akm_wpa_auth_lookup_tbl[i].akm_suite) {
4589 			return rsn_akm_wpa_auth_lookup_tbl[i].wpa_auth;
4590 		}
4591 	}
4592 	return WPA_AUTH_DISABLED;
4593 }
4594 
4595 static s32
wl_set_set_cipher(struct net_device * dev,struct cfg80211_connect_params * sme)4596 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
4597 {
4598 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4599 	struct wl_security *sec;
4600 	s32 pval = 0;
4601 	s32 gval = 0;
4602 	s32 err = 0;
4603 	s32 wsec_val = 0;
4604 
4605 #ifdef BCMWAPI_WPI
4606 	s32 wapi_val = 0;
4607 	s32 val = 0;
4608 #endif
4609 
4610 	s32 bssidx;
4611 #ifdef WL_GCMP
4612 	uint32 algos = 0, mask = 0;
4613 #endif /* WL_GCMP */
4614 
4615 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4616 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4617 		return BCME_ERROR;
4618 	}
4619 
4620 	if (sme->crypto.n_ciphers_pairwise) {
4621 		pval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.ciphers_pairwise[0]);
4622 		if (pval == WSEC_NONE) {
4623 			WL_ERR(("Invalid cipher (0x%x)\n",
4624 				sme->crypto.ciphers_pairwise[0]));
4625 			return BCME_BADARG;
4626 		}
4627 		switch (sme->crypto.ciphers_pairwise[0]) {
4628 
4629 #ifdef BCMWAPI_WPI
4630 		case WLAN_CIPHER_SUITE_SMS4:
4631 #ifndef CUSTOMER_HW6
4632 			if (!IS_WAPI_VER(sme->crypto.wpa_versions)) {
4633 				WL_ERR(("Invalid WAPI version %d\n", sme->crypto.wpa_versions));
4634 				return BCME_BADARG;
4635 			}
4636 #endif /* !CUSTOMER_HW6 */
4637 			val = pval;
4638 			err = wl_set_set_wapi_ie(dev, sme);
4639 			if (unlikely(err)) {
4640 				WL_DBG(("Set wapi ie failed  \n"));
4641 				return err;
4642 			} else {
4643 				WL_DBG(("Set wapi ie succeded\n"));
4644 			}
4645 			wapi_val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
4646 			WL_DBG_MEM(("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val, dev->name));
4647 			err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wapi_val, bssidx);
4648 			if (unlikely(err)) {
4649 				WL_ERR(("set wpa_auth failed (%d)\n", err));
4650 				return err;
4651 			}
4652 			break;
4653 #endif /* BCMWAPI_WPI */
4654 
4655 #ifdef WL_GCMP
4656 		case WLAN_CIPHER_SUITE_GCMP:
4657 		case WLAN_CIPHER_SUITE_GCMP_256:
4658 			algos = KEY_ALGO_MASK(wl_rsn_cipher_wsec_key_algo_lookup(
4659 					sme->crypto.ciphers_pairwise[0]));
4660 			mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
4661 			break;
4662 #endif /* WL_GCMP */
4663 		default: /* No post processing required */
4664 			break;
4665 		}
4666 	}
4667 #if defined(BCMSUP_4WAY_HANDSHAKE)
4668 	/* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
4669 	 * handshake.
4670 	 * Note that the FW feature flag only exists on kernels that support the
4671 	 * FT-EAP AKM suite.
4672 	 */
4673 	if (cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) {
4674 		err = wldev_iovar_setint_bsscfg(dev, "sup_wpa", 1, bssidx);
4675 		if (err) {
4676 			WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err));
4677 			return err;
4678 		} else {
4679 			WL_INFORM_MEM(("idsup enabled.\n"));
4680 		}
4681 	}
4682 #endif /* BCMSUP_4WAY_HANDSHAKE */
4683 	if (sme->crypto.cipher_group) {
4684 		gval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.cipher_group);
4685 		if (gval == WSEC_NONE) {
4686 			WL_ERR(("invalid cipher group (0x%x)\n", sme->crypto.cipher_group));
4687 			return BCME_BADARG;
4688 		}
4689 		switch (sme->crypto.cipher_group) {
4690 
4691 #ifdef BCMWAPI_WPI
4692 		case WLAN_CIPHER_SUITE_SMS4:
4693 			val = gval;
4694 			break;
4695 #endif
4696 
4697 #ifdef WL_GCMP
4698 		case WLAN_CIPHER_SUITE_GCMP:
4699 		case WLAN_CIPHER_SUITE_GCMP_256:
4700 			algos = KEY_ALGO_MASK(
4701 				wl_rsn_cipher_wsec_key_algo_lookup(sme->crypto.cipher_group));
4702 			mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
4703 			break;
4704 #endif /* WL_GCMP */
4705 		default: /* No post processing required */
4706 			break;
4707 		}
4708 	}
4709 
4710 	WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
4711 #ifdef WL_GCMP
4712 	WL_DBG(("algos:%x, mask:%x", algos, mask));
4713 #endif /* WL_GCMP */
4714 
4715 	if (is_wps_conn(sme)) {
4716 		if (sme->privacy) {
4717 			wsec_val = 4;
4718 		} else {
4719 			/* WPS-2.0 allows no security */
4720 			wsec_val = 0;
4721 		}
4722 	} else {
4723 
4724 #ifdef BCMWAPI_WPI
4725 		if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) {
4726 			WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
4727 			wsec_val = val;
4728 		} else
4729 #endif
4730 
4731 		{
4732 			WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
4733 			wsec_val = pval | gval;
4734 		}
4735 	}
4736 
4737 	WL_DBG_MEM(("[%s] wl wsec 0x%x\n", dev->name, wsec_val));
4738 	err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec_val, bssidx);
4739 	if (unlikely(err)) {
4740 		WL_ERR(("error (%d)\n", err));
4741 		return err;
4742 	}
4743 #ifdef WL_GCMP
4744 	if (wl_set_wsec_info_algos(dev, algos, mask)) {
4745 		WL_ERR(("set wsec_info error (%d)\n", err));
4746 	}
4747 #endif /* WL_GCMP */
4748 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4749 	sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
4750 	sec->cipher_group = sme->crypto.cipher_group;
4751 	sec->fw_wsec = wsec_val;
4752 	return err;
4753 }
4754 #ifdef WL_GCMP
4755 static s32
wl_set_wsec_info_algos(struct net_device * dev,uint32 algos,uint32 mask)4756 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask)
4757 {
4758 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4759 	s32 bssidx;
4760 	s32 err = 0;
4761 	wl_wsec_info_t *wsec_info;
4762 	bcm_xtlv_t *wsec_info_tlv;
4763 	uint16 tlv_data_len;
4764 	uint32 tlv_data[2];
4765 	uint32 param_len;
4766 	uint8 * buf;
4767 
4768 	WL_DBG(("enter.\n"));
4769 	if (!cfg) {
4770 		return BCME_ERROR;
4771 	}
4772 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4773 		WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
4774 		return BCME_ERROR;
4775 	}
4776 
4777 	buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
4778 	if (!buf) {
4779 		WL_ERR(("No memory"));
4780 		return BCME_NOMEM;
4781 	}
4782 	wsec_info = (wl_wsec_info_t *)buf;
4783 	wsec_info->version = WL_WSEC_INFO_VERSION;
4784 	wsec_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
4785 
4786 	wsec_info->num_tlvs++;
4787 	tlv_data_len = sizeof(tlv_data);
4788 	tlv_data[0] = algos;
4789 	tlv_data[1] = mask;
4790 
4791 	bcm_xtlv_pack_xtlv(wsec_info_tlv, WL_WSEC_INFO_BSS_ALGOS, tlv_data_len,
4792 		(const uint8 *)tlv_data, 0);
4793 	param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN + tlv_data_len;
4794 
4795 	err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
4796 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
4797 
4798 	MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
4799 	return err;
4800 }
4801 #endif /* WL_GCMP */
4802 
4803 #ifdef WL_SAE
4804 s32
wl_cfg80211_set_wsec_info(struct net_device * dev,uint32 * data,uint16 data_len,int tag)4805 wl_cfg80211_set_wsec_info(struct net_device *dev, uint32 *data,
4806 	uint16 data_len, int tag)
4807 {
4808 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4809 	s32 bssidx;
4810 	s32 err = 0;
4811 	wl_wsec_info_t *wsec_info;
4812 	bcm_xtlv_t *bcm_info_tlv;
4813 	uint32 param_len;
4814 	uint8 *buf = NULL;
4815 
4816 	if (!cfg) {
4817 		return BCME_ERROR;
4818 	}
4819 
4820 	if (data_len > WLC_IOCTL_SMLEN) {
4821 		err = BCME_BADLEN;
4822 		goto exit;
4823 	}
4824 
4825 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4826 		WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
4827 		err = BCME_ERROR;
4828 		goto exit;
4829 	}
4830 
4831 	buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + data_len);
4832 	if (!buf) {
4833 		WL_ERR(("No memory"));
4834 		err = BCME_NOMEM;
4835 		goto exit;
4836 	}
4837 
4838 	wsec_info = (wl_wsec_info_t *)buf;
4839 	bzero(wsec_info, sizeof(wl_wsec_info_t) + data_len);
4840 	wsec_info->version = WL_WSEC_INFO_VERSION;
4841 	bcm_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
4842 
4843 	wsec_info->num_tlvs++;
4844 
4845 	bcm_xtlv_pack_xtlv(bcm_info_tlv, tag, data_len, (const u8*)data, 0);
4846 	param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN + data_len;
4847 
4848 	err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
4849 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
4850 	if (unlikely(err) && (err != BCME_UNSUPPORTED)) {
4851 		WL_ERR(("set wsec_info error (%d)\n", err));
4852 	}
4853 
4854 exit:
4855 	if (buf)
4856 		MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + data_len);
4857 	return err;
4858 }
4859 #endif /* SAE */
4860 
4861 #ifdef MFP
4862 static s32
wl_cfg80211_set_mfp(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme)4863 wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
4864 	struct net_device *dev,
4865 	struct cfg80211_connect_params *sme)
4866 {
4867 	s32 mfp = WL_MFP_NONE;
4868 	s32 current_mfp = WL_MFP_NONE;
4869 	const bcm_tlv_t *wpa2_ie;
4870 	const u8* rsn_cap = NULL;
4871 	bool fw_support = false;
4872 	int err, count = 0;
4873 	const u8 *eptr = NULL, *ptr = NULL;
4874 	const u8* group_mgmt_cs = NULL;
4875 	const wpa_pmkid_list_t* pmkid = NULL;
4876 	struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4877 
4878 	if (!sme) {
4879 		/* No connection params from userspace, Do nothing. */
4880 		return 0;
4881 	}
4882 
4883 	/* Check fw support and retreive current mfp val */
4884 	err = wldev_iovar_getint(dev, "mfp", &current_mfp);
4885 	if (!err) {
4886 		fw_support = true;
4887 	}
4888 
4889 	/* Parse the wpa2ie to decode the MFP capablity */
4890 	if (((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
4891 			DOT11_MNG_RSN_ID)) != NULL) &&
4892 			(wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) {
4893 		WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap[0], rsn_cap[1]));
4894 		/* Check for MFP cap in the RSN capability field */
4895 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
4896 		if (sme->mfp)
4897 #endif
4898 		{
4899 			if (rsn_cap[0] & RSN_CAP_MFPR) {
4900 				mfp = WL_MFP_REQUIRED;
4901 			} else if (rsn_cap[0] & RSN_CAP_MFPC) {
4902 				mfp = WL_MFP_CAPABLE;
4903 			}
4904 		}
4905 		/*
4906 		 * eptr --> end/last byte addr of wpa2_ie
4907 		 * ptr --> to keep track of current/required byte addr
4908 		 */
4909 		eptr = (const u8*)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN);
4910 		/* pointing ptr to the next byte after rns_cap */
4911 		ptr = (const u8*)rsn_cap + RSN_CAP_LEN;
4912 		if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) {
4913 			/* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
4914 			pmkid = (const wpa_pmkid_list_t*)ptr;
4915 			count = pmkid->count.low | (pmkid->count.high << 8);
4916 			/* ptr now to point to last byte addr of pmkid */
4917 			ptr = (const u8*)pmkid + (count * WPA2_PMKID_LEN
4918 					+ WPA2_PMKID_COUNT_LEN);
4919 			if ((eptr - ptr) >= WPA_SUITE_LEN) {
4920 				/* group_mgmt_cs now to point to first byte addr of bip */
4921 				group_mgmt_cs = ptr;
4922 			}
4923 		}
4924 	}
4925 
4926 	WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n",
4927 		mfp, wpa2_ie, fw_support));
4928 
4929 	if (fw_support == false) {
4930 		if (mfp == WL_MFP_REQUIRED) {
4931 			/* if mfp > 0, mfp capability set in wpa ie, but
4932 			 * FW indicated error for mfp. Propagate the error up.
4933 			 */
4934 			WL_ERR(("mfp capability found in wpaie. But fw doesn't "
4935 				"seem to support MFP\n"));
4936 			err = -EINVAL;
4937 			goto exit;
4938 		} else {
4939 			/* Firmware doesn't support mfp. But since connection request
4940 			 * is for non-mfp case, don't bother.
4941 			 */
4942 			err = BCME_OK;
4943 			goto exit;
4944 		}
4945 	} else if (mfp != current_mfp) {
4946 		/* Some FW brances report error (-5) during MFP set if the BSS
4947 		 * is up (roam case). Typically in roaming cases, the MFP
4948 		 * configuration doesn't change. So in roam/reassoc cases, there is
4949 		 * no need to update the fw state. If we still hit corner cases
4950 		 * throwing (-5) error, we need to pull in RB:59117.
4951 		 */
4952 		err = wldev_iovar_setint(dev, "mfp", mfp);
4953 		if (unlikely(err)) {
4954 			WL_ERR(("mfp (%d) set failed ret:%d \n", mfp, err));
4955 			goto exit;
4956 		}
4957 		WL_DBG_MEM(("[%s] wl mfp 0x%x\n", dev->name, mfp));
4958 	}
4959 
4960 	if (sec) {
4961 		sec->fw_mfp = mfp;
4962 	}
4963 
4964 	if (group_mgmt_cs && bcmp((const uint8 *)WPA2_OUI,
4965 			group_mgmt_cs, (WPA_SUITE_LEN - 1)) == 0) {
4966 		WL_DBG(("BIP is found\n"));
4967 		err = wldev_iovar_setbuf(dev, "bip",
4968 			group_mgmt_cs, WPA_SUITE_LEN, cfg->ioctl_buf,
4969 			WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
4970 		/*
4971 		 * Dont return failure for unsupported cases
4972 		 * of bip iovar for backward compatibility
4973 		 */
4974 		if (err != BCME_UNSUPPORTED && err < 0) {
4975 			WL_ERR(("bip set error (%d)\n", err));
4976 
4977 #ifdef CUSTOMER_HW6
4978 			if (wl_customer6_legacy_chip_check(cfg,
4979 				bcmcfg_to_prmry_ndev(cfg))) {
4980 				/* Ignore bip error: Some older firmwares doesn't
4981 				 * support bip iovar/ return BCME_NOTUP while trying
4982 				 * to set bip from connect context. These firmares
4983 				 * include bip in RSNIE by default. So its okay to
4984 				 * ignore the error.
4985 				 */
4986 					err = BCME_OK;
4987 					goto exit;
4988 				} else
4989 #endif /* CUSTOMER_HW6 */
4990 
4991 				{
4992 					goto exit;
4993 				}
4994 		} else {
4995 			WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n",
4996 				dev->name, group_mgmt_cs[0], group_mgmt_cs[1],
4997 				group_mgmt_cs[2]));
4998 		}
4999 	}
5000 exit:
5001 	if (err) {
5002 		wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
5003 			FW_LOGSET_MASK_ALL);
5004 	}
5005 
5006 	return 0;
5007 }
5008 #endif /* MFP */
5009 
5010 #ifdef WL_FILS
5011 bool
wl_is_fils_supported(struct net_device * ndev)5012 wl_is_fils_supported(struct net_device *ndev)
5013 {
5014 	s32 err;
5015 	u8 ioctl_buf[WLC_IOCTL_SMLEN] = {0};
5016 	bcm_iov_buf_t *iov_buf = (bcm_iov_buf_t *)ioctl_buf;
5017 
5018 	iov_buf->version = WL_FILS_IOV_VERSION;
5019 	err = wldev_iovar_getbuf(ndev, "fils", (uint8*)iov_buf, sizeof(bcm_iov_buf_t),
5020 		iov_buf, WLC_IOCTL_SMLEN, NULL);
5021 	if (err == BCME_UNSUPPORTED) {
5022 		WL_DBG(("FILS NOT supported\n"));
5023 		return false;
5024 	}
5025 
5026 	WL_INFORM(("FILS supported\n"));
5027 	return true;
5028 }
5029 
5030 #define WL_NUM_OF_TLV_IN_SET_FILS_PARAMS	4u
5031 static s32
wl_set_fils_params(struct net_device * dev,struct cfg80211_connect_params * sme)5032 wl_set_fils_params(struct net_device *dev, struct cfg80211_connect_params *sme)
5033 {
5034 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5035 	bcm_iov_buf_t *iov_buf = NULL;
5036 	bcm_xtlvbuf_t tbuf;
5037 	s32 err = BCME_OK;
5038 	uint32 buf_size;
5039 
5040 	if ((sme->auth_type != NL80211_AUTHTYPE_FILS_SK) &&
5041 		(sme->auth_type != NL80211_AUTHTYPE_FILS_SK_PFS) &&
5042 		(sme->auth_type != NL80211_AUTHTYPE_FILS_PK)) {
5043 		return BCME_OK;
5044 	}
5045 	if (sme->fils_erp_rrk_len > WL_MAX_FILS_KEY_LEN) {
5046 		WL_ERR(("%s: FILS rRK exceed allowed size\n", __FUNCTION__));
5047 		err = BCME_BADARG;
5048 		goto exit;
5049 	}
5050 	/* Check incoming buffer length */
5051 	buf_size = sme->fils_erp_username_len + sme->fils_erp_realm_len + sme->fils_erp_rrk_len +
5052 		sizeof(sme->fils_erp_next_seq_num) +
5053 		WL_NUM_OF_TLV_IN_SET_FILS_PARAMS * BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32) +
5054 		sizeof(bcm_iov_buf_t) - 1u;
5055 
5056 	if (buf_size > WLC_IOCTL_SMLEN) {
5057 		WL_ERR(("%s: FILS connect params arguments exceed allowed size\n", __FUNCTION__));
5058 		err = BCME_BADARG;
5059 		goto exit;
5060 	}
5061 	iov_buf = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
5062 	if (!iov_buf) {
5063 		WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, WLC_IOCTL_SMLEN));
5064 		err = BCME_NOMEM;
5065 		goto exit;
5066 	}
5067 	iov_buf->version = WL_FILS_IOV_VERSION;
5068 	iov_buf->id = WL_FILS_CMD_ADD_CONNECT_PARAMS;
5069 	/* check if this should be len w/o headers */
5070 	err = bcm_xtlv_buf_init(&tbuf, (uint8*)&iov_buf->data[0],
5071 		WLC_IOCTL_SMLEN - sizeof(bcm_iov_buf_t) + sizeof(uint16),
5072 		BCM_XTLV_OPTION_ALIGN32);
5073 	if (err != BCME_OK) {
5074 		WL_ERR(("%s: xtlv_context initialization failed\n", __FUNCTION__));
5075 		goto exit;
5076 	}
5077 	if (sme->fils_erp_username_len && sme->fils_erp_username != NULL) {
5078 		err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_USERNAME,
5079 			sme->fils_erp_username, sme->fils_erp_username_len);
5080 		if (err != BCME_OK) {
5081 			WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5082 			goto exit;
5083 		}
5084 	}
5085 	if (sme->fils_erp_realm_len && sme->fils_erp_realm != NULL) {
5086 		err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_REALM,
5087 			sme->fils_erp_realm, sme->fils_erp_realm_len);
5088 		if (err != BCME_OK) {
5089 			WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5090 			goto exit;
5091 		}
5092 	}
5093 	if (sme->fils_erp_rrk_len && sme->fils_erp_rrk != NULL) {
5094 		err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_RRK,
5095 			sme->fils_erp_rrk, sme->fils_erp_rrk_len);
5096 		if (err != BCME_OK) {
5097 			WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5098 			goto exit;
5099 		}
5100 	}
5101 	err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM,
5102 			(u8 *)&sme->fils_erp_next_seq_num, sizeof(sme->fils_erp_next_seq_num));
5103 	if (err != BCME_OK) {
5104 		WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5105 		goto exit;
5106 	}
5107 	iov_buf->len = bcm_xtlv_buf_len(&tbuf);
5108 	err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf->len + sizeof(bcm_iov_buf_t) -
5109 		sizeof(uint16), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5110 	if (unlikely(err)) {
5111 		 WL_ERR(("set fils params ioctl error (%d)\n", err));
5112 		 goto exit;
5113 	}
5114 
5115 exit:
5116 	if (err != BCME_OK) {
5117 		WL_ERR(("set FILS params error %d\n", err));
5118 	}
5119 	else {
5120 		WL_DBG_MEM(("FILS parameters succesfully applied\n"));
5121 	}
5122 	if (iov_buf) {
5123 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_SMLEN);
5124 	}
5125 	return err;
5126 }
5127 
5128 #if !defined(WL_FILS_ROAM_OFFLD) && defined(WL_FILS)
5129 static s32
wl_get_bcn_timeout(struct net_device * dev,u32 * bcn_timeout)5130 wl_get_bcn_timeout(struct net_device *dev, u32 *bcn_timeout)
5131 {
5132 	s32 err = 0;
5133 
5134 	err = wldev_iovar_getint(dev, "bcn_timeout", bcn_timeout);
5135 	if (unlikely(err)) {
5136 		WL_ERR(("could not get bcn_timeout (%d)\n", err));
5137 	}
5138 	return err;
5139 }
5140 
5141 #define WL_ROAM_ENABLE	0
5142 #define WL_ROAM_DISABLE 1
5143 /* Beacon Timeout beacon loss in case FILS roaming offload is not supported by fw */
5144 #define WL_BCN_TIMEOUT	3
5145 
5146 static s32
wl_fils_toggle_roaming(struct net_device * dev,u32 auth_type)5147 wl_fils_toggle_roaming(struct net_device *dev, u32 auth_type)
5148 {
5149 	s32 err = 0;
5150 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5151 
5152 	if (WPA2_AUTH_IS_FILS(auth_type) && !cfg->fils_info.fils_roam_disabled) {
5153 		err = wl_get_bcn_timeout(dev, &cfg->fils_info.fils_bcn_timeout_cache);
5154 		if (unlikely(err)) {
5155 			return err;
5156 		}
5157 		wl_dongle_roam(dev, WL_ROAM_DISABLE, WL_BCN_TIMEOUT);
5158 		cfg->fils_info.fils_roam_disabled = true;
5159 		WL_DBG_MEM(("fw roam disabled for FILS akm\n"));
5160 	} else if (cfg->fils_info.fils_roam_disabled) {
5161 		/* Enable roaming back for other auth types */
5162 		wl_dongle_roam(dev, WL_ROAM_ENABLE, cfg->fils_info.fils_bcn_timeout_cache);
5163 		cfg->fils_info.fils_roam_disabled = false;
5164 		WL_DBG_MEM(("fw roam enabled\n"));
5165 	}
5166 	return err;
5167 }
5168 #endif /* !WL_FILS_ROAM_OFFLD && WL_FILS */
5169 #endif /* WL_FILS */
5170 
5171 static s32
wl_set_key_mgmt(struct net_device * dev,struct cfg80211_connect_params * sme)5172 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
5173 {
5174 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5175 	struct wl_security *sec;
5176 	s32 val = 0;
5177 	s32 err = 0;
5178 	s32 bssidx;
5179 
5180 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5181 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5182 		return BCME_ERROR;
5183 	}
5184 
5185 	if (sme->crypto.n_akm_suites) {
5186 		err = wldev_iovar_getint(dev, "wpa_auth", &val);
5187 		if (unlikely(err)) {
5188 			WL_ERR(("could not get wpa_auth (%d)\n", err));
5189 			return err;
5190 		}
5191 		if (val & (WPA_AUTH_PSK |
5192 			WPA_AUTH_UNSPECIFIED)) {
5193 			switch (sme->crypto.akm_suites[0]) {
5194 			case WLAN_AKM_SUITE_8021X:
5195 				val = WPA_AUTH_UNSPECIFIED;
5196 				break;
5197 			case WLAN_AKM_SUITE_PSK:
5198 				val = WPA_AUTH_PSK;
5199 				break;
5200 			default:
5201 				WL_ERR(("invalid akm suite (0x%x)\n",
5202 					sme->crypto.akm_suites[0]));
5203 				return -EINVAL;
5204 			}
5205 		} else if (val & (WPA2_AUTH_PSK |
5206 			WPA2_AUTH_UNSPECIFIED)) {
5207 			switch (sme->crypto.akm_suites[0]) {
5208 #ifdef MFP
5209 
5210 #ifdef CUSTOMER_HW6
5211 			case WL_AKM_SUITE_SHA256_1X:
5212 				if (wl_customer6_legacy_chip_check(cfg,	dev)) {
5213 					val = WPA2_AUTH_UNSPECIFIED;
5214 				} else {
5215 					val = WPA2_AUTH_1X_SHA256;
5216 				}
5217 				break;
5218 			case WL_AKM_SUITE_SHA256_PSK:
5219 				if (wl_customer6_legacy_chip_check(cfg,	dev)) {
5220 					val = WPA2_AUTH_PSK;
5221 				} else {
5222 					val = WPA2_AUTH_PSK_SHA256;
5223 				}
5224 				break;
5225 #endif /* CUSTOMER_HW6 */
5226 
5227 #ifndef CUSTOMER_HW6
5228 			case WL_AKM_SUITE_SHA256_1X:
5229 				val = WPA2_AUTH_1X_SHA256;
5230 				break;
5231 			case WL_AKM_SUITE_SHA256_PSK:
5232 				val = WPA2_AUTH_PSK_SHA256;
5233 				break;
5234 #endif /* CUSTOMER_HW6 */
5235 #endif /* MFP */
5236 			case WLAN_AKM_SUITE_8021X:
5237 			case WLAN_AKM_SUITE_PSK:
5238 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
5239 			case WLAN_AKM_SUITE_FT_8021X:
5240 #endif
5241 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
5242 			case WLAN_AKM_SUITE_FT_PSK:
5243 #endif
5244 			case WLAN_AKM_SUITE_FILS_SHA256:
5245 			case WLAN_AKM_SUITE_FILS_SHA384:
5246 			case WLAN_AKM_SUITE_8021X_SUITE_B:
5247 			case WLAN_AKM_SUITE_8021X_SUITE_B_192:
5248 #ifdef WL_OWE
5249 			case WLAN_AKM_SUITE_OWE:
5250 #endif /* WL_OWE */
5251 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
5252 			case WLAN_AKM_SUITE_SAE:
5253 #endif /* WL_SAE || WL_CLIENT_SAE */
5254 #ifdef WL_SAE_FT
5255 			case WLAN_AKM_SUITE_FT_OVER_SAE:
5256 #endif /* WL_SAE_FT */
5257 			case WLAN_AKM_SUITE_DPP:
5258 			case WLAN_AKM_SUITE_FT_8021X_SHA384:
5259 				val = wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[0]);
5260 				break;
5261 			case WLAN_AKM_SUITE_FT_FILS_SHA256:
5262 				val = WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT;
5263 				break;
5264 			case WLAN_AKM_SUITE_FT_FILS_SHA384:
5265 				val = WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT;
5266 				break;
5267 			default:
5268 				WL_ERR(("invalid akm suite (0x%x)\n",
5269 					sme->crypto.akm_suites[0]));
5270 				return -EINVAL;
5271 			}
5272 		}
5273 
5274 #ifdef BCMWAPI_WPI
5275 		else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) {
5276 			switch (sme->crypto.akm_suites[0]) {
5277 			case WLAN_AKM_SUITE_WAPI_CERT:
5278 				val = WAPI_AUTH_UNSPECIFIED;
5279 				break;
5280 			case WLAN_AKM_SUITE_WAPI_PSK:
5281 				val = WAPI_AUTH_PSK;
5282 				break;
5283 			default:
5284 				WL_ERR(("invalid akm suite (0x%x)\n",
5285 					sme->crypto.akm_suites[0]));
5286 				return -EINVAL;
5287 			}
5288 		}
5289 #endif
5290 
5291 #ifdef WL_FILS
5292 #if !defined(WL_FILS_ROAM_OFFLD)
5293 	err = wl_fils_toggle_roaming(dev, val);
5294 	if (unlikely(err)) {
5295 		return err;
5296 	}
5297 #endif /* !WL_FILS_ROAM_OFFLD */
5298 #endif /* !WL_FILS */
5299 
5300 #ifdef MFP
5301 		if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) {
5302 			WL_ERR(("MFP set failed err:%d\n", err));
5303 			return -EINVAL;
5304 		}
5305 #endif /* MFP */
5306 
5307 		WL_DBG_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val));
5308 		err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
5309 		if (unlikely(err)) {
5310 			WL_ERR(("could not set wpa_auth (0x%x)\n", err));
5311 			return err;
5312 		}
5313 	}
5314 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5315 	sec->wpa_auth = sme->crypto.akm_suites[0];
5316 	sec->fw_wpa_auth = val;
5317 
5318 	return err;
5319 }
5320 
5321 static s32
wl_set_set_sharedkey(struct net_device * dev,struct cfg80211_connect_params * sme)5322 wl_set_set_sharedkey(struct net_device *dev,
5323 	struct cfg80211_connect_params *sme)
5324 {
5325 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5326 	struct wl_security *sec;
5327 	struct wl_wsec_key key;
5328 	s32 val;
5329 	s32 err = 0;
5330 	s32 bssidx;
5331 
5332 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5333 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5334 		return BCME_ERROR;
5335 	}
5336 
5337 	WL_DBG(("key len (%d)\n", sme->key_len));
5338 	if (sme->key_len) {
5339 		sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5340 		WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
5341 			sec->wpa_versions, sec->cipher_pairwise));
5342 		if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
5343 			NL80211_WPA_VERSION_2)) &&
5344 
5345 #ifdef BCMWAPI_WPI
5346 			!is_wapi(sec->cipher_pairwise) &&
5347 #endif
5348 
5349 			(sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
5350 			WLAN_CIPHER_SUITE_WEP104)))
5351 		{
5352 			bzero(&key, sizeof(key));
5353 			key.len = (u32) sme->key_len;
5354 			key.index = (u32) sme->key_idx;
5355 			if (unlikely(key.len > sizeof(key.data))) {
5356 				WL_ERR(("Too long key length (%u)\n", key.len));
5357 				return -EINVAL;
5358 			}
5359 			memcpy(key.data, sme->key, key.len);
5360 			key.flags = WL_PRIMARY_KEY;
5361 			if ((sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP40) ||
5362 			    (sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP104)) {
5363 				key.algo = wl_rsn_cipher_wsec_key_algo_lookup(sec->cipher_pairwise);
5364 			} else {
5365 				WL_ERR(("Invalid algorithm (%d)\n",
5366 					sme->crypto.ciphers_pairwise[0]));
5367 				return -EINVAL;
5368 			}
5369 			/* Set the new key/index */
5370 			WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
5371 				key.len, key.index, key.algo));
5372 			WL_DBG(("key \"%s\"\n", key.data));
5373 			swap_key_from_BE(&key);
5374 			err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
5375 				cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5376 			if (unlikely(err)) {
5377 				WL_ERR(("WLC_SET_KEY error (%d)\n", err));
5378 				return err;
5379 			}
5380 			WL_INFORM_MEM(("key applied to fw\n"));
5381 			if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
5382 				WL_DBG(("set auth_type to shared key\n"));
5383 				val = WL_AUTH_SHARED_KEY;	/* shared key */
5384 				err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
5385 				if (unlikely(err)) {
5386 					WL_ERR(("set auth failed (%d)\n", err));
5387 					return err;
5388 				}
5389 			}
5390 		}
5391 	}
5392 	return err;
5393 }
5394 
5395 #if defined (CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
wl_get_chan_isvht80(struct net_device * net,dhd_pub_t * dhd)5396 static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
5397 {
5398 	u32 chanspec = 0;
5399 	bool isvht80 = 0;
5400 
5401 	if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK)
5402 		chanspec = wl_chspec_driver_to_host(chanspec);
5403 
5404 	isvht80 = chanspec & WL_CHANSPEC_BW_80;
5405 	WL_DBG(("wl_get_chan_isvht80: chanspec(%x:%d)\n", chanspec, isvht80));
5406 
5407 	return isvht80;
5408 }
5409 #endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
5410 
wl_cfg80211_cleanup_mismatch_status(struct net_device * dev,struct bcm_cfg80211 * cfg,bool disassociate)5411 int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80211 *cfg,
5412 	bool disassociate)
5413 {
5414 	scb_val_t scbval;
5415 	int err = TRUE;
5416 	int wait_cnt;
5417 
5418 	if (disassociate) {
5419 #ifdef BCMDONGLEHOST
5420 		dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
5421 		BCM_REFERENCE(dhdp);
5422 		DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
5423 			dhd_net2idx(dhdp->info, dev), DOT11_RC_DISASSOC_LEAVING);
5424 #endif /* BCMDONGLEHOST */
5425 		WL_ERR(("Disassociate previous connection!\n"));
5426 		wl_set_drv_status(cfg, DISCONNECTING, dev);
5427 		scbval.val = DOT11_RC_DISASSOC_LEAVING;
5428 		scbval.val = htod32(scbval.val);
5429 
5430 		err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
5431 				sizeof(scb_val_t));
5432 		if (unlikely(err)) {
5433 			wl_clr_drv_status(cfg, DISCONNECTING, dev);
5434 			WL_ERR(("error (%d)\n", err));
5435 			return err;
5436 		}
5437 		wait_cnt = 500/10;
5438 	} else {
5439 		wait_cnt = 200/10;
5440 		WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
5441 		if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
5442 			wl_clr_drv_status(cfg, DISCONNECTING, dev);
5443 		}
5444 	}
5445 
5446 	while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
5447 		WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
5448 			wait_cnt));
5449 		wait_cnt--;
5450 		OSL_SLEEP(10);
5451 	}
5452 
5453 	if (wait_cnt == 0) {
5454 		WL_ERR(("DISCONNECING clean up failed!\n"));
5455 		/* Clear DISCONNECTING driver status as we have made sufficient attempts
5456 		* for driver clean up.
5457 		*/
5458 		wl_clr_drv_status(cfg, DISCONNECTING, dev);
5459 		wl_clr_drv_status(cfg, CONNECTED, dev);
5460 		return BCME_NOTREADY;
5461 	}
5462 	return BCME_OK;
5463 }
5464 
5465 #ifdef WL_FILS
5466 static int
wl_fils_add_hlp_container(struct bcm_cfg80211 * cfg,struct net_device * dev,const uint8 * ie_buf,uint16 ie_len)5467 wl_fils_add_hlp_container(struct bcm_cfg80211 *cfg, struct net_device *dev,
5468 	const uint8* ie_buf, uint16 ie_len)
5469 {
5470 	const bcm_tlv_ext_t *hlp_ie;
5471 
5472 	if ((hlp_ie = (const bcm_tlv_ext_t*)bcm_parse_tlvs_dot11((const uint8 *)ie_buf, ie_len,
5473 		FILS_HLP_CONTAINER_EXT_ID, TRUE))) {
5474 		u16 hlp_len = hlp_ie->len;
5475 		u16 left_len = (ie_len - ((const uint8*)hlp_ie - ie_buf));
5476 		bcm_iov_buf_t *iov_buf = 0;
5477 		uint8* pxtlv;
5478 		int err;
5479 		size_t iov_buf_len;
5480 		bcm_tlv_dot11_frag_tot_len(ie_buf, ie_len, FILS_HLP_CONTAINER_EXT_ID,
5481 			TRUE, (uint*)&hlp_len);
5482 
5483 		hlp_len += BCM_TLV_EXT_HDR_SIZE;
5484 
5485 		if ((hlp_len > DOT11_MAX_MPDU_BODY_LEN) || (hlp_len > left_len)) {
5486 			WL_ERR(("bad HLP length %d\n", hlp_len));
5487 			return EFAULT;
5488 		}
5489 		iov_buf_len = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) - 1 + hlp_len;
5490 		iov_buf = MALLOCZ(cfg->osh, iov_buf_len);
5491 		if (iov_buf == NULL) {
5492 			WL_ERR(("failed to allocated iov_buf\n"));
5493 			return ENOMEM;
5494 		}
5495 
5496 		prhex("HLP, HLP", (const uchar *)hlp_ie, hlp_len);
5497 
5498 		pxtlv = (uint8 *)&iov_buf->data[0];
5499 		((bcm_xtlv_t*)pxtlv)->id = WL_FILS_XTLV_HLP_IE;
5500 		((bcm_xtlv_t*)pxtlv)->len = hlp_len;
5501 
5502 		memcpy(((bcm_xtlv_t*)pxtlv)->data, hlp_ie, ((bcm_xtlv_t*)pxtlv)->len);
5503 
5504 		iov_buf->version = WL_FILS_IOV_VERSION;
5505 		iov_buf->id = WL_FILS_CMD_ADD_HLP_IE;
5506 		iov_buf->len = ((sizeof(bcm_xtlv_t)-1) + ((bcm_xtlv_t*)pxtlv)->len);
5507 
5508 		err = wldev_iovar_setbuf(dev, "fils", iov_buf,
5509 				sizeof(bcm_iov_buf_t) + iov_buf->len,
5510 				cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
5511 		if (unlikely(err)) {
5512 			WL_ERR(("fils wldev_iovar_setbuf error (%d)\n", err));
5513 		}
5514 		else {
5515 			WL_DBG_MEM(("FILS HLP Packet succesfully updated\n"));
5516 		}
5517 		MFREE(cfg->osh, iov_buf, iov_buf_len);
5518 	}
5519 	return BCME_OK;
5520 }
5521 #endif /* WL_FILS */
5522 
5523 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
5524 #define UPDATE_ASSOC_IES	BIT(0)
5525 #ifndef UPDATE_FILS_ERP_INFO
5526 #define UPDATE_FILS_ERP_INFO	BIT(1)
5527 #define UPDATE_AUTH_TYPE	BIT(2)
5528 #endif
5529 
5530 static int
wl_cfg80211_update_connect_params(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme,u32 changed)5531 wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
5532 	struct cfg80211_connect_params *sme, u32 changed)
5533 {
5534 	s32 err = BCME_OK;
5535 #if defined(WL_FILS)
5536 	if (changed & UPDATE_FILS_ERP_INFO) {
5537 		err = wl_set_fils_params(dev, sme);
5538 		if (unlikely(err)) {
5539 			WL_ERR(("Invalid FILS params\n"));
5540 			goto exit;
5541 		}
5542 		if (!(changed & UPDATE_AUTH_TYPE)) {
5543 			WL_DBG(("Warning: FILS ERP params are set,"
5544 				"but authentication type - not\n"));
5545 		}
5546 	}
5547 	if (changed & UPDATE_AUTH_TYPE) {
5548 		err = wl_set_auth_type(dev, sme);
5549 		if (unlikely(err)) {
5550 			WL_ERR(("Invalid auth type\n"));
5551 			goto exit;
5552 		}
5553 	}
5554 #endif /* WL_FILS */
5555 	if (changed & UPDATE_ASSOC_IES) {
5556 		WL_DBG(("update assoc ies\n"));
5557 		err = wl_cfg80211_set_mgmt_vndr_ies(wl_get_cfg(dev), ndev_to_cfgdev(dev),
5558 			wl_get_bssidx_by_wdev(wl_get_cfg(dev), dev->ieee80211_ptr),
5559 			VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
5560 		if (err) {
5561 			WL_ERR(("error updating vndr ies\n"));
5562 			goto exit;
5563 		}
5564 	}
5565 exit:
5566 	return err;
5567 }
5568 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
5569 
5570 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
5571 static s32
wl_config_roam_env_detection(struct bcm_cfg80211 * cfg,struct net_device * dev)5572 wl_config_roam_env_detection(struct bcm_cfg80211 *cfg, struct net_device *dev)
5573 {
5574 #if defined(BCMDONGLEHOST)
5575 	dhd_pub_t *dhdp =  (dhd_pub_t *)(cfg->pub);
5576 #endif /* BCMDONGLEHOST */
5577 	s32 roam_trigger[2] = {0, 0};
5578 	s32 err = BCME_OK;
5579 
5580 	if (dhdp->roam_env_detection && (dev == bcmcfg_to_prmry_ndev(cfg))) {
5581 		bool is_roamtrig_reset = TRUE;
5582 		bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection",
5583 				AP_ENV_DETECT_NOT_USED) == BCME_OK);
5584 #ifdef SKIP_ROAM_TRIGGER_RESET
5585 		roam_trigger[1] = WLC_BAND_2G;
5586 		is_roamtrig_reset =
5587 			(wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
5588 				sizeof(roam_trigger)) == BCME_OK) &&
5589 			(roam_trigger[0] == WL_AUTO_ROAM_TRIGGER-10);
5590 #endif /* SKIP_ROAM_TRIGGER_RESET */
5591 		if (is_roamtrig_reset && is_roam_env_ok) {
5592 			roam_trigger[0] = WL_AUTO_ROAM_TRIGGER;
5593 			roam_trigger[1] = WLC_BAND_ALL;
5594 			err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
5595 				sizeof(roam_trigger));
5596 			if (unlikely(err)) {
5597 				WL_ERR((" failed to restore roam_trigger for auto env"
5598 						" detection. err:%d\n", err));
5599 			}
5600 		}
5601 	}
5602 	return err;
5603 }
5604 #endif /* ROAM_ENABLE && ROAMENV_DETECTION */
5605 
5606 s32
wl_do_preassoc_ops(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme)5607 wl_do_preassoc_ops(struct bcm_cfg80211 *cfg,
5608 		struct net_device *dev, struct cfg80211_connect_params *sme)
5609 {
5610 #if defined(BCMDONGLEHOST)
5611 	dhd_pub_t *dhdp =  (dhd_pub_t *)(cfg->pub);
5612 #endif /* BCMDONGLEHOST */
5613 
5614 #ifdef BCMDONGLEHOST
5615 	BCM_REFERENCE(dhdp);
5616 	DHD_STATLOG_CTRL(dhdp, ST(ASSOC_START), dhd_net2idx(dhdp->info, dev), 0);
5617 #endif /* BCMDONGLEHOST */
5618 
5619 #ifdef DHDTCPSYNC_FLOOD_BLK
5620 	dhd_reset_tcpsync_info_by_dev(dev);
5621 #endif /* DHDTCPSYNC_FLOOD_BLK */
5622 
5623 	if (wl_get_drv_status(cfg, SCANNING, dev)) {
5624 		wl_cfgscan_cancel_scan(cfg);
5625 	}
5626 
5627 #ifdef WL_SCHED_SCAN
5628 	/* Locks are taken in wl_cfg80211_sched_scan_stop()
5629 	 * A start scan occuring during connect is unlikely
5630 	 */
5631 	if (cfg->sched_scan_req) {
5632 		struct wireless_dev *wdev = dev->ieee80211_ptr;
5633 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
5634 		wl_cfg80211_sched_scan_stop(wdev->wiphy, bcmcfg_to_prmry_ndev(cfg),
5635 				cfg->sched_scan_req->reqid);
5636 #else
5637 		wl_cfg80211_sched_scan_stop(wdev->wiphy, bcmcfg_to_prmry_ndev(cfg));
5638 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
5639 	}
5640 #endif /* WL_SCHED_SCAN */
5641 #ifdef WL_CFG80211_GON_COLLISION
5642 	/* init block gon req count  */
5643 	cfg->block_gon_req_tx_count = 0;
5644 	cfg->block_gon_req_rx_count = 0;
5645 #endif /* WL_CFG80211_GON_COLLISION */
5646 
5647 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
5648 	maxrxpktglom = 0;
5649 #endif
5650 
5651 #if defined (ROAM_ENABLE) && defined (ROAM_AP_ENV_DETECTION)
5652 	if (wl_config_roam_env_detection(cfg, dev) != BCME_OK) {
5653 		return BCME_ERROR;
5654 	}
5655 #endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
5656 
5657 #ifdef WLTDLS
5658 	/* disable TDLS if number of connected interfaces is >= 1 */
5659 	wl_cfg80211_tdls_config(cfg, TDLS_STATE_CONNECT, false);
5660 #endif /* WLTDLS */
5661 
5662 #ifdef SUPPORT_AP_BWCTRL
5663 	if (dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
5664 		wl_restore_ap_bw(cfg);
5665 	}
5666 #endif /* SUPPORT_AP_BWCTRL */
5667 #if defined(ROAMEXP_SUPPORT)
5668 	/* Clear Blacklist bssid and Whitelist ssid list before join issue
5669 	 * This is temporary fix since currently firmware roaming is not
5670 	 * disabled by android framework before SSID join from framework
5671 	*/
5672 	/* Flush blacklist bssid content */
5673 	dhd_dev_set_blacklist_bssid(dev, NULL, 0, true);
5674 	/* Flush whitelist ssid content */
5675 	dhd_dev_set_whitelist_ssid(dev, NULL, 0, true);
5676 #endif /* ROAMEXP_SUPPORT */
5677 
5678 	WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
5679 	if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
5680 		prhex(NULL, sme->ie, sme->ie_len);
5681 	}
5682 	/* Connection attempted via linux-wireless */
5683 	wl_set_drv_status(cfg, CFG80211_CONNECT, dev);
5684 	return BCME_OK;
5685 }
5686 
5687 static s32
wl_config_assoc_security(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme)5688 wl_config_assoc_security(struct bcm_cfg80211 *cfg,
5689 	struct net_device *dev, struct cfg80211_connect_params *sme)
5690 {
5691 	s32 err = BCME_OK;
5692 
5693 	err = wl_set_wpa_version(dev, sme);
5694 	if (unlikely(err)) {
5695 		WL_ERR(("Invalid wpa_version\n"));
5696 		goto exit;
5697 	}
5698 
5699 	err = wl_set_auth_type(dev, sme);
5700 	if (unlikely(err)) {
5701 		WL_ERR(("Invalid auth type\n"));
5702 		goto exit;
5703 	}
5704 
5705 #ifdef WL_FILS
5706 	if (sme->ie && sme->ie_len) {
5707 		err = wl_fils_add_hlp_container(cfg, dev, sme->ie, sme->ie_len);
5708 		if (unlikely(err)) {
5709 			WL_ERR(("FILS sending HLP failed\n"));
5710 			goto exit;
5711 		}
5712 	}
5713 #endif /* WL_FILS */
5714 
5715 	err = wl_set_set_cipher(dev, sme);
5716 	if (unlikely(err)) {
5717 		WL_ERR(("Invalid ciper\n"));
5718 		goto exit;
5719 	}
5720 
5721 	err = wl_set_key_mgmt(dev, sme);
5722 	if (unlikely(err)) {
5723 		WL_ERR(("Invalid key mgmt\n"));
5724 		goto exit;
5725 	}
5726 
5727 	err = wl_set_set_sharedkey(dev, sme);
5728 	if (unlikely(err)) {
5729 		WL_ERR(("Invalid shared key\n"));
5730 		goto exit;
5731 	}
5732 
5733 #ifdef WL_FILS
5734 	err = wl_set_fils_params(dev, sme);
5735 	if (unlikely(err)) {
5736 		WL_ERR(("Invalid FILS params\n"));
5737 		goto exit;
5738 	}
5739 #endif /* WL_FILS */
5740 
5741 exit:
5742 	return err;
5743 }
5744 
5745 static s32
wl_config_assoc_ies(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme,wlcfg_assoc_info_t * info)5746 wl_config_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *dev,
5747 	struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *info)
5748 {
5749 	const wpa_ie_fixed_t *wpa_ie;
5750 	const bcm_tlv_t *wpa2_ie;
5751 	const u8* wpaie = 0;
5752 	u32 wpaie_len;
5753 	s32 err;
5754 	s32 bssidx = info->bssidx;
5755 
5756 	/* configure all vendor and extended vendor IEs */
5757 	wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
5758 		VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
5759 
5760 	/* Find the RSNXE_IE and plumb */
5761 	if ((err = wl_cfg80211_config_rsnxe_ie(cfg, dev,
5762 			(const u8*)sme->ie, sme->ie_len)) < 0) {
5763 		WL_ERR(("Failed to configure rsnxe ie: %d\n", err));
5764 		return err;
5765 	}
5766 
5767 	/* find the RSN_IE */
5768 	if ((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
5769 		DOT11_MNG_RSN_ID)) != NULL) {
5770 		WL_DBG((" RSN IE is found\n"));
5771 	}
5772 
5773 	/* find the WPA_IE */
5774 	if ((wpa_ie = wl_cfgp2p_find_wpaie(sme->ie,
5775 		sme->ie_len)) != NULL) {
5776 		WL_DBG((" WPA IE is found\n"));
5777 	}
5778 
5779 	if (wpa_ie != NULL || wpa2_ie != NULL) {
5780 		wpaie = (wpa_ie != NULL) ? (const u8 *)wpa_ie : (const u8 *)wpa2_ie;
5781 		wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
5782 		wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
5783 	} else {
5784 		wpaie = NULL;
5785 		wpaie_len = 0;
5786 	}
5787 
5788 	err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
5789 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
5790 	if (unlikely(err)) {
5791 		WL_ERR(("wpaie set error (%d)\n", err));
5792 	}
5793 
5794 	return err;
5795 }
5796 
5797 s32
wl_cfg80211_config_rsnxe_ie(struct bcm_cfg80211 * cfg,struct net_device * dev,const u8 * parse,u32 len)5798 wl_cfg80211_config_rsnxe_ie(struct bcm_cfg80211 *cfg, struct net_device *dev,
5799 		const u8 *parse, u32 len)
5800 {
5801 	bcm_tlv_t *ie = NULL;
5802 	s32 err = 0;
5803 	u8 ie_len = 0;
5804 	char smbuf[WLC_IOCTL_SMLEN];
5805 
5806 	while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_RSNXE_ID))) {
5807 		WL_DBG(("Found RSNXE ie\n"));
5808 		break;
5809 	}
5810 
5811 	ie_len = (ie != NULL) ? (ie->len + BCM_TLV_HDR_SIZE): 0;
5812 
5813 	err = wldev_iovar_setbuf(dev, "rsnxe", ie, ie_len,
5814 		smbuf, sizeof(smbuf), NULL);
5815 	if (!err) {
5816 		WL_DBG(("Configured RSNXE IE\n"));
5817 	} else if (err == BCME_UNSUPPORTED) {
5818 		WL_DBG(("FW does not support rsnxe iovar\n"));
5819 		err = BCME_OK;
5820 	} else {
5821 		WL_ERR(("rsnxe set error (%d)\n", err));
5822 	}
5823 	return err;
5824 }
5825 
5826 static s32
wl_fillup_assoc_params_v1(struct bcm_cfg80211 * cfg,struct net_device * dev,void * params,u32 buf_len,wlcfg_assoc_info_t * info)5827 wl_fillup_assoc_params_v1(struct bcm_cfg80211 *cfg, struct net_device *dev,
5828 	void *params, u32 buf_len, wlcfg_assoc_info_t *info)
5829 {
5830 	chanspec_t *chanspecs = info->chanspecs;
5831 	u32 chan_cnt = info->chan_cnt;
5832 	u32 join_scan_active_time = 0;
5833 	wl_extjoin_params_v1_t *ext_join_params = (wl_extjoin_params_v1_t *)params;
5834 
5835 	if (buf_len < (sizeof(ext_join_params->ssid.SSID) +
5836 		(sizeof(chanspec_t) * chan_cnt))) {
5837 		WL_ERR(("buf too short\n"));
5838 		return -EINVAL;
5839 	}
5840 
5841 	if (info->bssid_hint) {
5842 		/* Set bssid hint flag */
5843 		WL_DBG_MEM(("ASSOC_HINT_BSSID_PRESENT. channels:%d\n", chan_cnt));
5844 		ext_join_params->assoc.flags |= ASSOC_HINT_BSSID_PRESENT;
5845 	}
5846 
5847 	/* ssid length check is already done above */
5848 	if (memcpy_s(ext_join_params->ssid.SSID, sizeof(ext_join_params->ssid.SSID),
5849 			info->ssid, info->ssid_len) != BCME_OK) {
5850 		WL_ERR(("ssid cpy failed info_len:%d\n", info->ssid_len));
5851 		return -EINVAL;
5852 	}
5853 
5854 	ext_join_params->ssid.SSID_len = info->ssid_len;
5855 	wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
5856 	if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
5857 		WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
5858 			ext_join_params->ssid.SSID_len));
5859 	}
5860 	ext_join_params->ssid.SSID_len = htod32(info->ssid_len);
5861 
5862 	/* Use increased dwell for targeted join case to take care of noisy env */
5863 	join_scan_active_time = info->targeted_join ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS :
5864 		WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS;
5865 	ext_join_params->scan.active_time = chan_cnt ? join_scan_active_time : -1;
5866 	ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
5867 	/* Set up join scan parameters */
5868 	ext_join_params->scan.scan_type = -1;
5869 	/* WAR to sync with presence period of VSDB GO.
5870 	 * send probe request more frequently
5871 	 * probe request will be stopped when it gets probe response from target AP/GO.
5872 	 */
5873 	ext_join_params->scan.nprobes = chan_cnt ?
5874 		(ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
5875 	ext_join_params->scan.home_time = -1;
5876 
5877 	(void)memcpy_s(&ext_join_params->assoc.bssid, ETH_ALEN, info->bssid, ETH_ALEN);
5878 
5879 	ext_join_params->assoc.chanspec_num = chan_cnt;
5880 	/* source and target lens are same */
5881 	(void)memcpy_s(ext_join_params->assoc.chanspec_list, (sizeof(chanspec_t) * chan_cnt),
5882 		chanspecs, sizeof(chanspec_t) * chan_cnt);
5883 
5884 	ext_join_params->assoc.chanspec_num = htod32(chan_cnt);
5885 	return BCME_OK;
5886 }
5887 
5888 static s32
wl_fillup_assoc_params_v0(struct bcm_cfg80211 * cfg,struct net_device * dev,void * params,u32 buf_len,wlcfg_assoc_info_t * info)5889 wl_fillup_assoc_params_v0(struct bcm_cfg80211 *cfg, struct net_device *dev,
5890 	void *params, u32 buf_len, wlcfg_assoc_info_t *info)
5891 {
5892 	chanspec_t *chanspecs = info->chanspecs;
5893 	u32 chan_cnt = info->chan_cnt;
5894 	u32 join_scan_active_time = 0;
5895 	wl_extjoin_params_t *ext_join_params = (wl_extjoin_params_t *)params;
5896 
5897 	if (buf_len < (sizeof(ext_join_params->ssid.SSID) +
5898 		(sizeof(chanspec_t) * chan_cnt))) {
5899 		WL_ERR(("buf too short\n"));
5900 		return -EINVAL;
5901 	}
5902 
5903 	/* ssid length check is already done above */
5904 	if (memcpy_s(ext_join_params->ssid.SSID, sizeof(ext_join_params->ssid.SSID),
5905 			info->ssid, info->ssid_len) != BCME_OK) {
5906 		WL_ERR(("ssid cpy failed info_len:%d\n", info->ssid_len));
5907 		return -EINVAL;
5908 	}
5909 
5910 	ext_join_params->ssid.SSID_len = info->ssid_len;
5911 	wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
5912 	if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
5913 		WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
5914 			ext_join_params->ssid.SSID_len));
5915 	}
5916 	ext_join_params->ssid.SSID_len = htod32(info->ssid_len);
5917 
5918 	/* Use increased dwell for targeted join case to take care of noisy env */
5919 	join_scan_active_time = info->targeted_join ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS :
5920 		WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS;
5921 	ext_join_params->scan.active_time = chan_cnt ? join_scan_active_time : -1;
5922 	ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
5923 	/* Set up join scan parameters */
5924 	ext_join_params->scan.scan_type = -1;
5925 	/* WAR to sync with presence period of VSDB GO.
5926 	 * send probe request more frequently
5927 	 * probe request will be stopped when it gets probe response from target AP/GO.
5928 	 */
5929 	ext_join_params->scan.nprobes = chan_cnt ?
5930 		(ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
5931 	ext_join_params->scan.home_time = -1;
5932 
5933 	(void)memcpy_s(&ext_join_params->assoc.bssid, ETH_ALEN, info->bssid, ETH_ALEN);
5934 
5935 	ext_join_params->assoc.chanspec_num = chan_cnt;
5936 	/* source and target lens are same */
5937 	(void)memcpy_s(ext_join_params->assoc.chanspec_list, (sizeof(chanspec_t) * chan_cnt),
5938 		chanspecs, sizeof(chanspec_t) * chan_cnt);
5939 
5940 	ext_join_params->assoc.chanspec_num = htod32(chan_cnt);
5941 	return BCME_OK;
5942 }
5943 
5944 static s32
wl_config_assoc_params(struct bcm_cfg80211 * cfg,struct net_device * dev,void * params,u32 buf_len,wlcfg_assoc_info_t * info)5945 wl_config_assoc_params(struct bcm_cfg80211 *cfg, struct net_device *dev,
5946 	void *params, u32 buf_len, wlcfg_assoc_info_t *info)
5947 {
5948 	s32 ret;
5949 
5950 	if (!cfg->join_iovar_ver) {
5951 		ret = wl_fillup_assoc_params_v0(cfg, dev, params, buf_len, info);
5952 	} else {
5953 		ret = wl_fillup_assoc_params_v1(cfg, dev, params, buf_len, info);
5954 	}
5955 	return ret;
5956 }
5957 
5958 static s32
wl_handle_assoc_hints(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme,wlcfg_assoc_info_t * info)5959 wl_handle_assoc_hints(struct bcm_cfg80211 *cfg, struct net_device *dev,
5960 	struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *info)
5961 {
5962 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
5963 	bool skip_hints = false;
5964 #endif /* KERNEL >= 3.15 */
5965 	chanspec_t chspec;
5966 
5967 	if (!sme || !info) {
5968 		WL_ERR(("wrong args\n"));
5969 		return -EINVAL;
5970 	}
5971 
5972 	if (unlikely(!sme->ssid) || (sme->ssid_len > DOT11_MAX_SSID_LEN)) {
5973 		WL_ERR(("Invalid ssid %p. len:%zu\n", sme->ssid, sme->ssid_len));
5974 		return -EINVAL;
5975 	}
5976 
5977 	/* Copy SSID detail */
5978 	info->ssid_len = sme->ssid_len;
5979 	if (memcpy_s(info->ssid, sizeof(info->ssid),
5980 			sme->ssid, info->ssid_len) != BCME_OK) {
5981 		WL_ERR(("ssid cpy failed\n"));
5982 		return -EINVAL;
5983 	}
5984 
5985 	/* Handle incoming BSSID and Channel info */
5986 	if (sme->bssid && !ETHER_ISBCAST(sme->bssid)) {
5987 		/* Use user space requested BSSID and channel */
5988 		info->targeted_join = true;
5989 		(void)memcpy_s(info->bssid, ETH_ALEN, sme->bssid, ETH_ALEN);
5990 		if (sme->channel && ((chspec =
5991 			wl_freq_to_chanspec(sme->channel->center_freq)) != INVCHANSPEC)) {
5992 			info->chan_cnt = 1;
5993 			info->chanspecs[0] = chspec;
5994 			/* Skip p2p connection on 6G */
5995 #ifdef WL_P2P_6G
5996 			if (!(cfg->p2p_6g_enabled)) {
5997 #endif /* WL_P2P_6G */
5998 				if (IS_P2P_GC(dev->ieee80211_ptr) && (CHSPEC_IS6G(chspec))) {
5999 					WL_ERR(("P2P connection not allowed on 6G\n"));
6000 					return -ENOTSUPP;
6001 				}
6002 #ifdef WL_P2P_6G
6003 			}
6004 #endif /* WL_P2P_6G */
6005 		}
6006 	}
6007 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6008 	else {
6009 #ifdef WL_SKIP_CONNECT_HINTS
6010 		skip_hints = true;
6011 		WL_DBG(("force skip connect hints\n"));
6012 #else /* WL_SKIP_CONNECT_HINTS */
6013 		/* override bssid_hint if overridden via module param */
6014 		skip_hints = fw_ap_select;
6015 #if defined(WL_FW_OCE_AP_SELECT)
6016 		/* If fw select needs to be specifically done for OCE */
6017 		skip_hints = fw_ap_select &&
6018 			wl_cfg80211_is_oce_ap(wiphy, sme->bssid_hint);
6019 #endif /* WL_FW_OCE_AP_SELECT */
6020 		WL_DBG(("fw_ap_select:%d skip_hints:%d\n", fw_ap_select, skip_hints));
6021 #endif /* WL_SKIP_CONNECT_HINTS */
6022 
6023 		/* Use bssid_hint if hints are allowed and if its unicast addr */
6024 		if (!skip_hints && sme->bssid_hint && !ETHER_ISBCAST(sme->bssid_hint)) {
6025 			WL_INFORM_MEM(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
6026 			info->targeted_join = true;
6027 			if (cfg->join_iovar_ver) {
6028 				/* Firmware supports bssid_hint feature */
6029 				info->bssid_hint = true;
6030 			}
6031 			(void)memcpy_s(info->bssid, ETH_ALEN, sme->bssid_hint, ETH_ALEN);
6032 #ifndef WL_FORCE_RCC_LIST
6033 			/* Use channel hint only for target bssid join case. In other
6034 			 * cases, use RCC or full scan to find better APs.
6035 			 */
6036 			if (sme->channel_hint && ((chspec = wl_freq_to_chanspec(
6037 				sme->channel_hint->center_freq)) != INVCHANSPEC)) {
6038 				info->chan_cnt = 1;
6039 				info->chanspecs[0] = chspec;
6040 				WL_INFORM_MEM(("channel_hint: chspec(%x)\n", chspec));
6041 			}
6042 #endif /* !WL_FORCE_RCC_LIST */
6043 		}
6044 	}
6045 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6046 
6047 	if (info->targeted_join != true) {
6048 		/* For non targeted join, use bcast address */
6049 		(void)memcpy_s(&info->bssid, ETH_ALEN, &ether_bcast, ETH_ALEN);
6050 	}
6051 	WL_DBG(("targeted_join:%d chan_cnt:%d\n",
6052 			info->targeted_join, info->chan_cnt));
6053 	return 0;
6054 }
6055 
6056 static s32
wl_sync_fw_assoc_states(struct bcm_cfg80211 * cfg,struct net_device * dev,wlcfg_assoc_info_t * info)6057 wl_sync_fw_assoc_states(struct bcm_cfg80211 *cfg,
6058 		struct net_device *dev, wlcfg_assoc_info_t *info)
6059 {
6060 	s32 err = BCME_OK;
6061 	u8 bssid[ETH_ALEN];
6062 
6063 	if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_reassoc_support) {
6064 		/* ROAM case */
6065 		info->reassoc = true;
6066 	} else {
6067 		/* store the bssid for the connect req */
6068 		wl_update_prof(cfg, dev, NULL, info->bssid, WL_PROF_LATEST_BSSID);
6069 
6070 		/* following scenarios are possible
6071 		* In case of wrong request/abnormal status,
6072 		* trigger DISASSOC to clean up status.
6073 		* 1. DHD prev status is CONNECTING
6074 		*      => 1.1 Wrong request
6075 		* 2. DHD previous status is CONNECTED
6076 		*      -  FW connected
6077 		*              => Wrong request
6078 		*      - FW not connected
6079 		*              => Abnormal status
6080 		* 3. DHD previous status is DISCONNECTING
6081 		*      => Waiting for disconnecting
6082 		* 4. DHD previous status is not connected
6083 		*      - FW not connected
6084 		*              => Normal status
6085 		*      - FW connected
6086 		*              => Abnormal status
6087 		*/
6088 		if (wl_get_drv_status(cfg, CONNECTING, dev) ||
6089 			wl_get_drv_status(cfg, CONNECTED, dev)) {
6090 			/* set nested connect bit to identify the context */
6091 			wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6092 			/* DHD prev status is CONNECTING/CONNECTED */
6093 			wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
6094 		} else if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6095 			/* DHD prev status is DISCONNECTING */
6096 			wl_cfg80211_cleanup_mismatch_status(dev, cfg, false);
6097 		} else if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6098 			/* DHD previous status is not connected and FW connected */
6099 			if (wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) == 0) {
6100 				/* set nested connect bit to identify the context */
6101 				wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6102 				wl_cfg80211_cleanup_mismatch_status(dev, cfg, true);
6103 			}
6104 		}
6105 #ifdef WL_EXT_IAPSTA
6106 		wl_ext_in4way_sync(dev, STA_WAIT_DISCONNECTED, WL_EXT_STATUS_CONNECTING, NULL);
6107 #endif
6108 	}
6109 
6110 	/* Clear BSSID if disconnecting state is not in progress */
6111 	bzero(&bssid, sizeof(bssid));
6112 	if (!wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6113 		wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
6114 	}
6115 
6116 	LOG_TS(cfg, conn_start);
6117 	CLR_TS(cfg, authorize_start);
6118 	/* clear nested connect bit on proceeding for connection */
6119 	wl_clr_drv_status(cfg, NESTED_CONNECT, dev);
6120 
6121 	if (!info->reassoc) {
6122 		/* 'connect' request received */
6123 		wl_set_drv_status(cfg, CONNECTING, dev);
6124 	}
6125 
6126 	return err;
6127 }
6128 
6129 #if defined(DBG_PKT_MON) && defined(BCMDONGLEHOST)
6130 void
wl_pkt_mon_start(struct bcm_cfg80211 * cfg,struct net_device * dev)6131 wl_pkt_mon_start(struct bcm_cfg80211 *cfg, struct net_device *dev)
6132 {
6133 	if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6134 		dhd_pub_t *dhdp =  (dhd_pub_t *)(cfg->pub);
6135 		DHD_DBG_PKT_MON_START(dhdp);
6136 	}
6137 }
6138 #endif /* DBG_PKT_MON && BCMDONGLEHOST */
6139 
6140 static s32
wl_ext_get_rssi(struct bcm_cfg80211 * cfg,u8 * bssid)6141 wl_ext_get_rssi(struct bcm_cfg80211 *cfg, u8 *bssid)
6142 {
6143 	wl_scan_results_t *bss_list;
6144 	wl_bss_info_t *bi = NULL;
6145 	s32 i, rssi = 0;
6146 
6147 	mutex_lock(&cfg->scan_sync);
6148 	bss_list = cfg->bss_list;
6149 	bi = next_bss(bss_list, bi);
6150 	for_each_bss(bss_list, bi, i) {
6151 		if (!memcmp(&bi->BSSID, bssid, ETHER_ADDR_LEN))
6152 			rssi = dtoh32(bi->RSSI);
6153 	}
6154 	mutex_unlock(&cfg->scan_sync);
6155 
6156 	return rssi;
6157 }
6158 
6159 void
wl_conn_debug_info(struct bcm_cfg80211 * cfg,struct net_device * dev,wlcfg_assoc_info_t * info)6160 wl_conn_debug_info(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc_info_t *info)
6161 {
6162 	struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6163 	char sec_info[32];
6164 	u32 chanspec = info->chanspecs[0];
6165 	s32 rssi = 0;
6166 
6167 	if (!sec) {
6168 		WL_ERR(("no sec?\n"));
6169 		return;
6170 	}
6171 
6172 	rssi = wl_ext_get_rssi(cfg, info->bssid);
6173 	wl_ext_get_sec(dev, 0, sec_info, sizeof(sec_info), TRUE);
6174 	WL_MSG(dev->name, "Connecting with " MACDBG " ssid \"%s\", len (%d), "
6175 		"channel=%d, sec=%s, rssi=%d\n", MAC2STRDBG((u8*)(&info->bssid)),
6176 		info->ssid, info->ssid_len, wf_chspec_ctlchan(chanspec), sec_info, rssi);
6177 	if (wl_dbg_level & WL_DBG_DBG) {
6178 		WL_MSG(dev->name, "akm:0x%x auth:0x%x wpaver:0x%x pwise:0x%x gwise:0x%x\n",
6179 				sec->wpa_auth, sec->auth_type, sec->wpa_versions,
6180 				sec->cipher_pairwise, sec->cipher_group);
6181 		WL_MSG(dev->name, "wpa_auth:0x%x auth:0x%x wsec:0x%x mfp:0x%x\n",
6182 				sec->fw_wpa_auth, sec->fw_auth, sec->fw_wsec, sec->fw_mfp);
6183 		/* print channels for assoc */
6184 		prhex("chanspecs", (const u8 *)info->chanspecs,
6185 				(info->chan_cnt * sizeof(chanspec_t)));
6186 	}
6187 	SUPP_LOG(("[%s] Connecting with " MACDBG " ssid \"%s\",chan_cnt:%d\n",
6188 		dev->name, MAC2STRDBG((u8*)(&info->bssid)),
6189 		info->ssid, info->chan_cnt));
6190 }
6191 
6192 static s32
wl_handle_join(struct bcm_cfg80211 * cfg,struct net_device * dev,wlcfg_assoc_info_t * assoc_info)6193 wl_handle_join(struct bcm_cfg80211 *cfg,
6194 	struct net_device *dev, wlcfg_assoc_info_t *assoc_info)
6195 {
6196 	s32 err = 0;
6197 	size_t join_params_size;
6198 	void *join_params = NULL;
6199 
6200 	if (!cfg->join_iovar_ver) {
6201 		join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
6202 			assoc_info->chan_cnt * sizeof(chanspec_t);
6203 	} else if (cfg->join_iovar_ver == WL_EXTJOIN_VERSION_V1) {
6204 		/* Use version join struct */
6205 		join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE_V1 +
6206 			assoc_info->chan_cnt * sizeof(chanspec_t);
6207 	} else {
6208 		WL_ERR(("Unsupported join iovar version\n"));
6209 		return -EINVAL;
6210 	}
6211 
6212 	join_params = MALLOCZ(cfg->osh, join_params_size);
6213 	if (join_params == NULL) {
6214 		err = -ENOMEM;
6215 		WL_ERR(("Mem alloc for join_params failed\n"));
6216 		goto fail;
6217 	}
6218 
6219 	/* Fill up the join params */
6220 	err = wl_config_assoc_params(cfg, dev, join_params, join_params_size,
6221 			assoc_info);
6222 	if (unlikely(err)) {
6223 		WL_ERR(("config assoc ies failed\n"));
6224 		goto fail;
6225 	}
6226 
6227 	err = wldev_iovar_setbuf_bsscfg(dev, "join", join_params, join_params_size,
6228 		cfg->ioctl_buf, WLC_IOCTL_MAXLEN, assoc_info->bssidx, &cfg->ioctl_buf_sync);
6229 	if (err) {
6230 		WL_ERR(("join iovar failed. err:%d\n", err));
6231 	}
6232 
6233 fail:
6234 	if (join_params) {
6235 		MFREE(cfg->osh, join_params, join_params_size);
6236 	}
6237 	return err;
6238 }
6239 
6240 static s32
wl_handle_reassoc(struct bcm_cfg80211 * cfg,struct net_device * dev,wlcfg_assoc_info_t * info)6241 wl_handle_reassoc(struct bcm_cfg80211 *cfg, struct net_device *dev,
6242 		wlcfg_assoc_info_t *info)
6243 {
6244 	wl_reassoc_params_t reassoc_params;
6245 	s32 err;
6246 	char sec_info[32];
6247 
6248 	bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE);
6249 	(void)memcpy_s(&reassoc_params.bssid.octet, ETH_ALEN, info->bssid, ETH_ALEN);
6250 	wl_ext_get_sec(dev, 0, sec_info, sizeof(sec_info), TRUE);
6251 	WL_MSG(dev->name, "Reconnecting with " MACDBG " sec=%s\n",
6252 		MAC2STRDBG((u8*)(&reassoc_params.bssid)), sec_info);
6253 	err = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, sizeof(wl_reassoc_params_t));
6254 	if (unlikely(err)) {
6255 		WL_ERR(("reassoc failed, error=%d\n", err));
6256 		return err;
6257 	} else {
6258 		WL_INFORM_MEM(("wl reassoc "MACDBG"\n", MAC2STRDBG(info->bssid)));
6259 	}
6260 
6261 	return BCME_OK;
6262 }
6263 
6264 static s32
wl_cfg80211_connect(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme)6265 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
6266 	struct cfg80211_connect_params *sme)
6267 {
6268 	s32 err = BCME_OK;
6269 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6270 	wlcfg_assoc_info_t assoc_info;
6271 #ifdef WL_EXT_IAPSTA
6272 	dhd_pub_t *dhdp =  (dhd_pub_t *)(cfg->pub);
6273 #endif
6274 
6275 	WL_DBG(("Enter len=%zu\n", sme->ie_len));
6276 	RETURN_EIO_IF_NOT_UP(cfg);
6277 
6278 	/* syncronize the connect states */
6279 	mutex_lock(&cfg->connect_sync);
6280 
6281 	bzero(&assoc_info, sizeof(wlcfg_assoc_info_t));
6282 	if ((assoc_info.bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6283 		WL_ERR(("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr));
6284 		goto fail;
6285 	}
6286 
6287 	err = wl_do_preassoc_ops(cfg, dev, sme);
6288 	if (unlikely(err)) {
6289 		WL_ERR(("config assoc channel failed\n"));
6290 		goto fail;
6291 	}
6292 
6293 	err = wl_handle_assoc_hints(cfg, dev, sme, &assoc_info);
6294 	if (unlikely(err)) {
6295 		WL_ERR(("assoc hint processing failed\n"));
6296 		goto fail;
6297 	}
6298 
6299 	if (wl_sync_fw_assoc_states(cfg, dev, &assoc_info) != BCME_OK) {
6300 		/* attempt best effort */
6301 		WL_ERR(("fw assoc sync failed\n"));
6302 	}
6303 
6304 	if (assoc_info.reassoc) {
6305 		// terence 20200530, should call wl_ext_iapsta_update_channel() to move AP channel?
6306 		/* Handle roam to same ESS */
6307 		if ((err = wl_handle_reassoc(cfg, dev, &assoc_info)) != BCME_OK) {
6308 			goto fail;
6309 		}
6310 	} else {
6311 		err = wl_config_assoc_security(cfg, dev, sme);
6312 		if (unlikely(err)) {
6313 			WL_ERR(("config assoc security failed\n"));
6314 			goto fail;
6315 		}
6316 
6317 		err = wl_get_assoc_channels(cfg, dev, &assoc_info);
6318 		if (unlikely(err)) {
6319 			WL_ERR(("get assoc channels failed\n"));
6320 			goto fail;
6321 		}
6322 
6323 		err = wl_config_assoc_ies(cfg, dev, sme, &assoc_info);
6324 		if (unlikely(err)) {
6325 			WL_ERR(("config assoc ies failed\n"));
6326 			goto fail;
6327 		}
6328 
6329 		/* print relevant info for debug purpose */
6330 #ifdef WL_EXT_IAPSTA
6331 		wl_ext_iapsta_update_channel(dhdp, dev, CHSPEC_CHANNEL(assoc_info.chanspecs[0]));
6332 #endif
6333 		wl_conn_debug_info(cfg, dev, &assoc_info);
6334 		if ((err = wl_handle_join(cfg, dev, &assoc_info)) != BCME_OK) {
6335 			goto fail;
6336 		}
6337 	}
6338 	/* Store the minium idx expected */
6339 	cfg->eidx.min_connect_idx = cfg->eidx.enqd;
6340 
6341 fail:
6342 	if (unlikely(err)) {
6343 		WL_ERR(("connect error (%d)\n", err));
6344 		wl_clr_drv_status(cfg, CONNECTING, dev);
6345 		CLR_TS(cfg, conn_start);
6346 		/* Flush fw logs */
6347 		wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
6348 #ifdef WLTDLS
6349 		/* If connect fails, check whether we can enable back TDLS */
6350 		wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
6351 #endif /* WLTDLS */
6352 	} else {
6353 #ifdef DBG_PKT_MON
6354 		/* start packet log in adv to ensure that EAPOL msgs aren't missed */
6355 		wl_pkt_mon_start(cfg, dev);
6356 #endif /* DBG_PKT_MON */
6357 	}
6358 #ifdef WL_EXT_IAPSTA
6359 	if (!err)
6360 		wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY,
6361 			WL_EXT_STATUS_CONNECTING, NULL);
6362 #endif
6363 
6364 	mutex_unlock(&cfg->connect_sync);
6365 	return err;
6366 }
6367 
wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 * cfg,struct net_device * dev)6368 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev)
6369 {
6370 	uint8 wait_cnt;
6371 	u32 status = 0;
6372 
6373 	wait_cnt = WAIT_FOR_DISCONNECT_MAX;
6374 	while ((status = wl_get_drv_status(cfg, DISCONNECTING, dev)) && wait_cnt) {
6375 		WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
6376 		wait_cnt--;
6377 		OSL_SLEEP(50);
6378 	}
6379 
6380 	WL_INFORM_MEM(("Wait for disconnection done. status:%d wait_cnt:%d\n", status, wait_cnt));
6381 	if (!wait_cnt && wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6382 		/* No response from firmware. Indicate connect result
6383 		 * to clear cfg80211 state machine
6384 		 */
6385 		if (wl_get_drv_status(cfg, CONNECTING, dev)) {
6386 			WL_INFORM_MEM(("force send connect result\n"));
6387 			CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
6388 				WLAN_STATUS_UNSPECIFIED_FAILURE,
6389 				GFP_KERNEL);
6390 		} else {
6391 			WL_INFORM_MEM(("force send disconnect event\n"));
6392 			CFG80211_DISCONNECTED(dev, WLAN_REASON_DEAUTH_LEAVING,
6393 				NULL, 0, false, GFP_KERNEL);
6394 		}
6395 		CLR_TS(cfg, conn_start);
6396 		CLR_TS(cfg, authorize_start);
6397 		wl_clr_drv_status(cfg, DISCONNECTING, dev);
6398 	}
6399 	return;
6400 }
6401 
6402 static s32
wl_cfg80211_disconnect(struct wiphy * wiphy,struct net_device * dev,u16 reason_code)6403 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
6404 	u16 reason_code)
6405 {
6406 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6407 	scb_val_t scbval;
6408 	bool act = false;
6409 	s32 err = 0;
6410 	u8 *curbssid = NULL;
6411 	u8 null_bssid[ETHER_ADDR_LEN];
6412 	s32 bssidx = 0;
6413 	bool connected;
6414 	bool conn_in_progress;
6415 	struct wireless_dev *wdev = dev->ieee80211_ptr;
6416 #ifdef BCMDONGLEHOST
6417 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6418 #endif /* BCMDONGLEHOST */
6419 
6420 	RETURN_EIO_IF_NOT_UP(cfg);
6421 	WL_MSG(dev->name, "Reason %d, act %d\n", reason_code, act);
6422 
6423 #ifdef BCMDONGLEHOST
6424 	BCM_REFERENCE(dhdp);
6425 	DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_START),
6426 		dhd_net2idx(dhdp->info, dev), reason_code);
6427 #ifdef DHD_4WAYM4_FAIL_DISCONNECT
6428 	dhd_cleanup_m4_state_work(dhdp, dhd_net2idx(dhdp->info, dev));
6429 #endif /* DHD_4WAYM4_FAIL_DISCONNECT */
6430 #endif /* BCMDONGLEHOST */
6431 
6432 	connected = wl_get_drv_status(cfg, CONNECTED, dev);
6433 	conn_in_progress = wl_get_drv_status(cfg, CONNECTING, dev);
6434 	curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
6435 	act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
6436 	WL_INFORM_MEM(("disconnect in connect state [%d:%d:%d]. reason:%d\n",
6437 		connected, conn_in_progress, act, reason_code));
6438 	if (connected || conn_in_progress) {
6439 		if (curbssid) {
6440 			WL_DBG_MEM(("curbssid:" MACDBG "\n", MAC2STRDBG(curbssid)));
6441 		}
6442 		act = true;
6443 	}
6444 
6445 	if (!curbssid) {
6446 		WL_ERR(("Disconnecting while CONNECTING status %d\n", (int)sizeof(null_bssid)));
6447 		bzero(null_bssid, sizeof(null_bssid));
6448 		curbssid = null_bssid;
6449 	}
6450 
6451 	if (act) {
6452 #ifdef DBG_PKT_MON
6453 		/* Stop packet monitor */
6454 		if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6455 			DHD_DBG_PKT_MON_STOP(dhdp);
6456 		}
6457 #endif /* DBG_PKT_MON */
6458 		/*
6459 		* Cancel ongoing scan to sync up with sme state machine of cfg80211.
6460 		*/
6461 		/* Let scan aborted by F/W */
6462 		if (cfg->scan_request) {
6463 			WL_TRACE_HW4(("Aborting the scan! \n"));
6464 			wl_cfgscan_cancel_scan(cfg);
6465 		}
6466 		if (conn_in_progress || connected || wdev->ssid_len) {
6467 				scbval.val = reason_code;
6468 				memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
6469 				scbval.val = htod32(scbval.val);
6470 				WL_INFORM_MEM(("[%s] wl disassoc\n", dev->name));
6471 				/* Set DISCONNECTING state. We are clearing this state
6472 				 in all exit paths
6473 				 */
6474 				wl_set_drv_status(cfg, DISCONNECTING, dev);
6475 				err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6476 						sizeof(scb_val_t));
6477 				if (unlikely(err)) {
6478 					wl_clr_drv_status(cfg, DISCONNECTING, dev);
6479 					WL_ERR(("error (%d)\n", err));
6480 					goto exit;
6481 				}
6482 #ifdef WL_EXT_IAPSTA
6483 				wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
6484 					WL_EXT_STATUS_DISCONNECTING, NULL);
6485 #endif
6486 		}
6487 #ifdef WL_WPS_SYNC
6488 		/* If are in WPS reauth state, then we would be
6489 		 * dropping the link down events. Ensure that
6490 		 * Event is sent up for the disconnect Req
6491 		 */
6492 		if (wl_wps_session_update(dev,
6493 			WPS_STATE_DISCONNECT, curbssid) == BCME_OK) {
6494 			WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
6495 			wl_clr_drv_status(cfg, DISCONNECTING, dev);
6496 			if (connected) {
6497 				/* Avoid further wl disassoc iovars */
6498 				wl_clr_drv_status(cfg, CONNECTED, dev);
6499 			}
6500 			goto exit;
6501 
6502 		}
6503 #endif /* WPS_SYNC */
6504 		wl_cfg80211_wait_for_disconnection(cfg, dev);
6505 	} else {
6506 		/* Not in connected or connection in progres states. Still receiving
6507 		 * disassoc indicates state mismatch with upper layer. Check for state
6508 		 * and issue disconnect indication if required.
6509 		 */
6510 
6511 		if (wdev->current_bss || wdev->ssid_len) {
6512 			WL_INFORM_MEM(("report disconnect event\n"));
6513 			CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
6514 		}
6515 	}
6516 
6517 #ifdef CUSTOM_SET_CPUCORE
6518 	/* set default cpucore */
6519 	if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6520 		dhdp->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
6521 		if (!(dhdp->chan_isvht80))
6522 			dhd_set_cpucore(dhdp, FALSE);
6523 	}
6524 #endif /* CUSTOM_SET_CPUCORE */
6525 
6526 	cfg->rssi = 0;	/* reset backup of rssi */
6527 
6528 exit:
6529 	CLR_TS(cfg, conn_start);
6530 	CLR_TS(cfg, authorize_start);
6531 
6532 	/* Clear IEs for disaasoc */
6533 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) >= 0) {
6534 		WL_INFORM_MEM(("Clearing disconnect IEs \n"));
6535 		err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
6536 			ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, NULL, 0);
6537 	} else {
6538 		WL_ERR(("Find index failed\n"));
6539 		err = -EINVAL;
6540 	}
6541 
6542 	return err;
6543 }
6544 
6545 static s32
6546 #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)6547 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
6548 	enum nl80211_tx_power_setting type, s32 mbm)
6549 #else
6550 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
6551 	enum nl80211_tx_power_setting type, s32 dbm)
6552 #endif /* WL_CFG80211_P2P_DEV_IF */
6553 {
6554 
6555 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6556 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6557 	s32 err = 0;
6558 #if defined(WL_CFG80211_P2P_DEV_IF)
6559 	s32 dbm = MBM_TO_DBM(mbm);
6560 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
6561 	defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
6562 	dbm = MBM_TO_DBM(dbm);
6563 #endif /* WL_CFG80211_P2P_DEV_IF */
6564 
6565 	RETURN_EIO_IF_NOT_UP(cfg);
6566 	switch (type) {
6567 	case NL80211_TX_POWER_AUTOMATIC:
6568 		break;
6569 	case NL80211_TX_POWER_LIMITED:
6570 		if (dbm < 0) {
6571 			WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
6572 			return -EINVAL;
6573 		}
6574 		break;
6575 	case NL80211_TX_POWER_FIXED:
6576 		if (dbm < 0) {
6577 			WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
6578 			return -EINVAL;
6579 		}
6580 		break;
6581 	}
6582 
6583 	err = wl_set_tx_power(ndev, type, dbm);
6584 	if (unlikely(err)) {
6585 		WL_ERR(("error (%d)\n", err));
6586 		return err;
6587 	}
6588 
6589 	cfg->conf->tx_power = dbm;
6590 
6591 	return err;
6592 }
6593 
6594 static s32
6595 #if defined(WL_CFG80211_P2P_DEV_IF)
wl_cfg80211_get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,s32 * dbm)6596 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
6597 	struct wireless_dev *wdev, s32 *dbm)
6598 #else
6599 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
6600 #endif /* WL_CFG80211_P2P_DEV_IF */
6601 {
6602 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6603 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6604 	s32 err = 0;
6605 
6606 	RETURN_EIO_IF_NOT_UP(cfg);
6607 	err = wl_get_tx_power(ndev, dbm);
6608 	if (unlikely(err))
6609 		WL_ERR(("error (%d)\n", err));
6610 
6611 	return err;
6612 }
6613 
6614 static s32
wl_cfg80211_config_default_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool unicast,bool multicast)6615 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
6616 	u8 key_idx, bool unicast, bool multicast)
6617 {
6618 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6619 	u32 index;
6620 	s32 wsec;
6621 	s32 err = 0;
6622 	s32 bssidx;
6623 
6624 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6625 		WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
6626 		return BCME_ERROR;
6627 	}
6628 
6629 	WL_DBG(("key index (%d)\n", key_idx));
6630 	RETURN_EIO_IF_NOT_UP(cfg);
6631 	err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
6632 	if (unlikely(err)) {
6633 		WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
6634 		return err;
6635 	}
6636 	/* Fix IOT issue with Apple Airport */
6637 	if (wsec == WEP_ENABLED) {
6638 		/* Just select a new current key */
6639 		index = (u32) key_idx;
6640 		index = htod32(index);
6641 		err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index,
6642 			sizeof(index));
6643 		if (unlikely(err)) {
6644 			WL_ERR(("error (%d)\n", err));
6645 		}
6646 	}
6647 	return err;
6648 }
6649 
6650 static s32
wl_add_keyext(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,const u8 * mac_addr,struct key_params * params)6651 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
6652 	u8 key_idx, const u8 *mac_addr, struct key_params *params)
6653 {
6654 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6655 	struct wl_wsec_key key;
6656 	s32 err = 0;
6657 	s32 bssidx;
6658 	s32 mode = wl_get_mode_by_netdev(cfg, dev);
6659 
6660 	WL_MSG(dev->name, "key index (%d)\n", key_idx);
6661 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6662 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6663 		return BCME_ERROR;
6664 	}
6665 	bzero(&key, sizeof(key));
6666 	key.index = (u32) key_idx;
6667 
6668 	if (!ETHER_ISMULTI(mac_addr))
6669 		memcpy((char *)&key.ea, (const void *)mac_addr, ETHER_ADDR_LEN);
6670 	key.len = (u32) params->key_len;
6671 
6672 	/* check for key index change */
6673 	if (key.len == 0) {
6674 		/* key delete */
6675 		swap_key_from_BE(&key);
6676 		err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6677 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6678 		if (unlikely(err)) {
6679 			WL_ERR(("key delete error (%d)\n", err));
6680 			return err;
6681 		}
6682 	} else {
6683 		if (key.len > sizeof(key.data)) {
6684 			WL_ERR(("Invalid key length (%d)\n", key.len));
6685 			return -EINVAL;
6686 		}
6687 		WL_DBG(("Setting the key index %d\n", key.index));
6688 		memcpy(key.data, params->key, key.len);
6689 
6690 		if ((mode == WL_MODE_BSS) &&
6691 			(params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
6692 			u8 keybuf[8];
6693 			memcpy(keybuf, &key.data[24], sizeof(keybuf));
6694 			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
6695 			memcpy(&key.data[16], keybuf, sizeof(keybuf));
6696 		}
6697 
6698 		/* if IW_ENCODE_EXT_RX_SEQ_VALID set */
6699 		if (params->seq && params->seq_len == 6) {
6700 			/* rx iv */
6701 			const u8 *ivptr;
6702 			ivptr = (const u8 *) params->seq;
6703 			key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
6704 				(ivptr[3] << 8) | ivptr[2];
6705 			key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
6706 			key.iv_initialized = true;
6707 		}
6708 		key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
6709 		if (key.algo == CRYPTO_ALGO_OFF) { //not found.
6710 			WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
6711 			return -EINVAL;
6712 		}
6713 		swap_key_from_BE(&key);
6714 #if defined(BCMDONGLEHOST) && !defined(CUSTOMER_HW4)
6715 		/* need to guarantee EAPOL 4/4 send out before set key */
6716 		dhd_wait_pend8021x(dev);
6717 #endif /* BCMDONGLEHOST && !CUSTOMER_HW4 */
6718 		err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6719 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6720 		if (unlikely(err)) {
6721 			WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6722 			return err;
6723 		}
6724 		WL_INFORM_MEM(("[%s] wsec key set\n", dev->name));
6725 	}
6726 	return err;
6727 }
6728 
6729 int
wl_cfg80211_enable_roam_offload(struct net_device * dev,int enable)6730 wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
6731 {
6732 	int err;
6733 	wl_eventmsg_buf_t ev_buf;
6734 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6735 
6736 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
6737 		/* roam offload is only for the primary device */
6738 		return -1;
6739 	}
6740 
6741 	WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev->name, enable));
6742 	err = wldev_iovar_setint(dev, "roam_offload", enable);
6743 	if (err)
6744 		return err;
6745 
6746 	bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
6747 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
6748 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
6749 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
6750 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
6751 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
6752 	wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
6753 	err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
6754 	if (!err) {
6755 		cfg->roam_offload = enable;
6756 	}
6757 	return err;
6758 }
6759 
6760 struct wireless_dev *
wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 * cfg,const char * name)6761 wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 *cfg, const char *name)
6762 {
6763 	struct net_info *iter, *next;
6764 
6765 	if (name == NULL) {
6766 		WL_ERR(("Iface name is not provided\n"));
6767 		return NULL;
6768 	}
6769 
6770 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
6771 	for_each_ndev(cfg, iter, next) {
6772 		GCC_DIAGNOSTIC_POP();
6773 		if (iter->ndev) {
6774 			if (strcmp(iter->ndev->name, name) == 0) {
6775 				return iter->ndev->ieee80211_ptr;
6776 			}
6777 		}
6778 	}
6779 
6780 	WL_DBG(("Iface %s not found\n", name));
6781 	return NULL;
6782 }
6783 
6784 #if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
6785 void
wl_cfg80211_block_arp(struct net_device * dev,int enable)6786 wl_cfg80211_block_arp(struct net_device *dev, int enable)
6787 {
6788 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6789 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6790 
6791 	WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev->name, enable));
6792 	if (!dhd_pkt_filter_enable) {
6793 		WL_DBG(("Packet filter isn't enabled\n"));
6794 		return;
6795 	}
6796 
6797 	/* Block/Unblock ARP frames only if STA is connected to
6798 	 * the upstream AP in case of STA+SoftAP Concurrenct mode
6799 	 */
6800 	if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6801 		WL_DBG(("STA not connected to upstream AP\n"));
6802 		return;
6803 	}
6804 
6805 	if (enable) {
6806 		WL_DBG(("Enable ARP Filter\n"));
6807 		/* Add ARP filter */
6808 		dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
6809 
6810 		/* Enable ARP packet filter - blacklist */
6811 		dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
6812 			TRUE, FALSE);
6813 	} else {
6814 		WL_DBG(("Disable ARP Filter\n"));
6815 		/* Disable ARP packet filter */
6816 		dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
6817 			FALSE, TRUE);
6818 
6819 		/* Delete ARP filter */
6820 		dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
6821 	}
6822 }
6823 #endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
6824 
6825 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)6826 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
6827 	u8 key_idx, bool pairwise, const u8 *mac_addr,
6828 	struct key_params *params)
6829 {
6830 	struct wl_wsec_key key;
6831 	s32 val = 0;
6832 	s32 wsec = 0;
6833 	s32 err = 0;
6834 	u8 keybuf[8];
6835 	s32 bssidx = 0;
6836 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6837 	s32 mode = wl_get_mode_by_netdev(cfg, dev);
6838 #ifdef WL_GCMP
6839 	uint32 algos = 0, mask = 0;
6840 #endif /* WL_GCMP */
6841 #if defined(WLAN_CIPHER_SUITE_PMK)
6842 	wsec_pmk_t pmk;
6843 	struct wl_security *sec;
6844 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
6845 #ifdef BCMDONGLEHOST
6846 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6847 #endif /* BCMDONGLEHOST */
6848 
6849 #if defined (BCMDONGLEHOST)
6850 	if (dhd_query_bus_erros(dhdp)) {
6851 		/* If we are hit with bus error, return success so that
6852 		 * don't repeatedly call del station till we recover.
6853 		 */
6854 		return 0;
6855 	}
6856 #endif /* BCMDONGLEHOST */
6857 
6858 	WL_INFORM_MEM(("key index (%d) (0x%x)\n", key_idx, params->cipher));
6859 	RETURN_EIO_IF_NOT_UP(cfg);
6860 
6861 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6862 		WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
6863 		return BCME_ERROR;
6864 	}
6865 
6866 	if (mac_addr &&
6867 		((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
6868 		(params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
6869 			wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
6870 			goto exit;
6871 	}
6872 
6873 #ifdef BCMDONGLEHOST
6874 	BCM_REFERENCE(dhdp);
6875 	DHD_STATLOG_CTRL(dhdp, ST(INSTALL_KEY), dhd_net2idx(dhdp->info, dev), 0);
6876 #endif /* BCMDONGLEHOST */
6877 
6878 	bzero(&key, sizeof(key));
6879 	/* Clear any buffered wep key */
6880 	bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
6881 
6882 	key.len = (u32) params->key_len;
6883 	key.index = (u32) key_idx;
6884 
6885 	if (unlikely(key.len > sizeof(key.data))) {
6886 		WL_ERR(("Too long key length (%u)\n", key.len));
6887 		return -EINVAL;
6888 	}
6889 	memcpy(key.data, params->key, key.len);
6890 
6891 	key.flags = WL_PRIMARY_KEY;
6892 
6893 	key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
6894 	val = wl_rsn_cipher_wsec_algo_lookup(params->cipher);
6895 	if (val == WSEC_NONE) {
6896 		WL_ERR(("Invalid cipher (0x%x), key.len = %d\n", params->cipher, key.len));
6897 #if defined(WLAN_CIPHER_SUITE_PMK)
6898 	/* WLAN_CIPHER_SUITE_PMK is not NL80211 standard ,but BRCM proprietary cipher suite.
6899 	 * so it doesn't have right algo type. Just for now, bypass this check for
6900 	 * backward compatibility.
6901 	 * TODO: deprecate this proprietary way and replace to nl80211 set_pmk API.
6902 	 */
6903 		if (params->cipher != WLAN_CIPHER_SUITE_PMK)
6904 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
6905 		return -EINVAL;
6906 	}
6907 	switch (params->cipher) {
6908 	case WLAN_CIPHER_SUITE_TKIP:
6909 		if (params->key_len != TKIP_KEY_SIZE) {
6910 			WL_ERR(("wrong TKIP Key length:%d", params->key_len));
6911 			return -EINVAL;
6912 		}
6913 		/* wpa_supplicant switches the third and fourth quarters of the TKIP key */
6914 		if (mode == WL_MODE_BSS) {
6915 			bcopy(&key.data[24], keybuf, sizeof(keybuf));
6916 			bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
6917 			bcopy(keybuf, &key.data[16], sizeof(keybuf));
6918 		}
6919 		WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
6920 		break;
6921 #if defined(WLAN_CIPHER_SUITE_PMK)
6922 	case WLAN_CIPHER_SUITE_PMK:
6923 		sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6924 
6925 		WL_MEM(("set_pmk: wpa_auth:%x akm:%x\n", sec->wpa_auth, params->cipher));
6926 		/* Avoid pmk set for SAE and OWE for external supplicant case. */
6927 		if (IS_AKM_SAE(sec->wpa_auth) || IS_AKM_OWE(sec->wpa_auth)) {
6928 			WL_INFORM_MEM(("skip pmk set for akm:%x\n", sec->wpa_auth));
6929 			break;
6930 		}
6931 
6932 		if (params->key_len > sizeof(pmk.key)) {
6933 			WL_ERR(("Worng PMK key length:%d", params->key_len));
6934 			return -EINVAL;
6935 		}
6936 		bzero(&pmk, sizeof(pmk));
6937 		bcopy(params->key, &pmk.key, params->key_len);
6938 		pmk.key_len = params->key_len;
6939 		pmk.flags = 0; /* 0:PMK, WSEC_PASSPHRASE:PSK, WSEC_SAE_PASSPHRASE:SAE_PSK */
6940 
6941 		if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
6942 			(sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
6943 			err = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len,
6944 				cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
6945 			if (err) {
6946 				/* could fail in case that 'okc' is not supported */
6947 				WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err));
6948 			}
6949 		}
6950 
6951 		err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
6952 		if (err) {
6953 			WL_ERR(("pmk failed, err=%d (ignore)\n", err));
6954 			return err;
6955 		} else {
6956 			WL_DBG(("pmk set. flags:0x%x\n", pmk.flags));
6957 		}
6958 		/* Clear key length to delete key */
6959 		key.len = 0;
6960 		break;
6961 #endif /* WLAN_CIPHER_SUITE_PMK */
6962 #ifdef WL_GCMP
6963 	case WLAN_CIPHER_SUITE_GCMP:
6964 	case WLAN_CIPHER_SUITE_GCMP_256:
6965 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
6966 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
6967 		algos = KEY_ALGO_MASK(key.algo);
6968 		mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
6969 		break;
6970 #endif /* WL_GCMP */
6971 	default: /* No post processing required */
6972 		WL_DBG(("no post processing required (0x%x)\n", params->cipher));
6973 		break;
6974 	}
6975 
6976 	/* Set the new key/index */
6977 	if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
6978 		WL_ERR(("IBSS KEY setted\n"));
6979 		wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
6980 	}
6981 	swap_key_from_BE(&key);
6982 	if ((params->cipher == WLAN_CIPHER_SUITE_WEP40) ||
6983 		(params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
6984 		/*
6985 		 * For AP role, since we are doing a wl down before bringing up AP,
6986 		 * the plumbed keys will be lost. So for AP once we bring up AP, we
6987 		 * need to plumb keys again. So buffer the keys for future use. This
6988 		 * is more like a WAR. If firmware later has the capability to do
6989 		 * interface upgrade without doing a "wl down" and "wl apsta 0", then
6990 		 * this will not be required.
6991 		 */
6992 		WL_DBG(("Buffering WEP Keys \n"));
6993 		memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key));
6994 	}
6995 	err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
6996 		WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6997 	if (unlikely(err)) {
6998 		WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6999 		return err;
7000 	}
7001 
7002 exit:
7003 	err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7004 	if (unlikely(err)) {
7005 		WL_ERR(("get wsec error (%d)\n", err));
7006 		return err;
7007 	}
7008 
7009 	wsec |= val;
7010 	err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
7011 	if (unlikely(err)) {
7012 		WL_ERR(("set wsec error (%d)\n", err));
7013 		return err;
7014 	}
7015 #ifdef WL_GCMP
7016 	wl_set_wsec_info_algos(dev, algos, mask);
7017 #endif /* WL_GCMP */
7018 #ifdef WL_EXT_IAPSTA
7019 	wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY,
7020 		WL_EXT_STATUS_ADD_KEY, NULL);
7021 #endif
7022 	return err;
7023 }
7024 
7025 static s32
wl_cfg80211_del_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr)7026 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
7027 	u8 key_idx, bool pairwise, const u8 *mac_addr)
7028 {
7029 	struct wl_wsec_key key;
7030 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7031 	s32 err = 0;
7032 	s32 bssidx;
7033 #ifdef BCMDONGLEHOST
7034 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7035 #endif /* BCMDONGLEHOST */
7036 
7037 #if defined (BCMDONGLEHOST)
7038 	if (dhd_query_bus_erros(dhdp)) {
7039 		/* If we are hit with bus error, return success so that
7040 		 * don't repeatedly call del station till we recover.
7041 		 */
7042 		return 0;
7043 	}
7044 #endif /* BCMDONGLEHOST */
7045 
7046 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7047 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7048 		return BCME_ERROR;
7049 	}
7050 	WL_DBG(("Enter\n"));
7051 
7052 #ifndef MFP
7053 	if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
7054 		return -EINVAL;
7055 #endif
7056 
7057 	RETURN_EIO_IF_NOT_UP(cfg);
7058 #ifdef BCMDONGLEHOST
7059 	BCM_REFERENCE(dhdp);
7060 	DHD_STATLOG_CTRL(dhdp, ST(DELETE_KEY), dhd_net2idx(dhdp->info, dev), 0);
7061 #endif /* BCMDONGLEHOST */
7062 	bzero(&key, sizeof(key));
7063 
7064 	key.flags = WL_PRIMARY_KEY;
7065 	key.algo = CRYPTO_ALGO_OFF;
7066 	key.index = (u32) key_idx;
7067 
7068 	WL_DBG(("key index (%d)\n", key_idx));
7069 	/* Set the new key/index */
7070 	swap_key_from_BE(&key);
7071 	err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7072 		WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7073 	if (unlikely(err)) {
7074 		if (err == -EINVAL) {
7075 			if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
7076 				/* we ignore this key index in this case */
7077 				WL_DBG(("invalid key index (%d)\n", key_idx));
7078 			}
7079 		} else {
7080 			WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7081 		}
7082 		return err;
7083 	}
7084 	return err;
7085 }
7086 
7087 /* NOTE : this function cannot work as is and is never called */
7088 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))7089 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
7090 	u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
7091 	void (*callback) (void *cookie, struct key_params * params))
7092 {
7093 	struct key_params params;
7094 	struct wl_wsec_key key;
7095 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7096 	struct wl_security *sec;
7097 	s32 wsec;
7098 	s32 err = 0;
7099 	s32 bssidx;
7100 
7101 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7102 		WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7103 		return BCME_ERROR;
7104 	}
7105 	WL_DBG(("key index (%d)\n", key_idx));
7106 	RETURN_EIO_IF_NOT_UP(cfg);
7107 	bzero(&key, sizeof(key));
7108 	key.index = key_idx;
7109 	swap_key_to_BE(&key);
7110 	bzero(&params, sizeof(params));
7111 	params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
7112 	params.key = key.data;
7113 
7114 	err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7115 	if (unlikely(err)) {
7116 		WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7117 		return err;
7118 	}
7119 	switch (WSEC_ENABLED(wsec)) {
7120 		case WEP_ENABLED:
7121 			sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7122 			if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
7123 				params.cipher = WLAN_CIPHER_SUITE_WEP40;
7124 				WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7125 			} else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
7126 				params.cipher = WLAN_CIPHER_SUITE_WEP104;
7127 				WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7128 			}
7129 			break;
7130 		case TKIP_ENABLED:
7131 			params.cipher = WLAN_CIPHER_SUITE_TKIP;
7132 			WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7133 			break;
7134 		case AES_ENABLED:
7135 			params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7136 			WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7137 			break;
7138 
7139 #ifdef BCMWAPI_WPI
7140 		case SMS4_ENABLED:
7141 			params.cipher = WLAN_CIPHER_SUITE_SMS4;
7142 			WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7143 			break;
7144 #endif
7145 
7146 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
7147 		/* to connect to mixed mode AP */
7148 		case (AES_ENABLED | TKIP_ENABLED): /* TKIP CCMP */
7149 			params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7150 			WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7151 			break;
7152 #endif
7153 		default:
7154 			WL_ERR(("Invalid algo (0x%x)\n", wsec));
7155 			return -EINVAL;
7156 	}
7157 
7158 	callback(cookie, &params);
7159 	return err;
7160 }
7161 
7162 static s32
wl_cfg80211_config_default_mgmt_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx)7163 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
7164 	struct net_device *dev, u8 key_idx)
7165 {
7166 #ifdef MFP
7167 	/* Firmware seems to use hard coded index for Group Mgmt Key.
7168 	 * TODO/Need to check whether something else needs to be
7169 	 * taken here
7170 	 */
7171 	return 0;
7172 #else
7173 	WL_INFORM_MEM(("Not supported\n"));
7174 	return -EOPNOTSUPP;
7175 #endif /* MFP */
7176 }
7177 
7178 static bool
wl_check_assoc_state(struct bcm_cfg80211 * cfg,struct net_device * dev)7179 wl_check_assoc_state(struct bcm_cfg80211 *cfg, struct net_device *dev)
7180 {
7181 	wl_assoc_info_t asinfo;
7182 	uint32 state = 0;
7183 	int err;
7184 
7185 	err = wldev_iovar_getbuf_bsscfg(dev, "assoc_info",
7186 		NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
7187 	if (unlikely(err)) {
7188 		WL_ERR(("failed to get assoc_info : err=%d\n", err));
7189 		return FALSE;
7190 	} else {
7191 		memcpy(&asinfo, cfg->ioctl_buf, sizeof(wl_assoc_info_t));
7192 		state = dtoh32(asinfo.state);
7193 		WL_DBG(("assoc state=%d\n", state));
7194 	}
7195 
7196 	return (state > 0)? TRUE:FALSE;
7197 }
7198 
7199 static s32
wl_cfg80211_get_rssi(struct net_device * dev,struct bcm_cfg80211 * cfg,s32 * rssi)7200 wl_cfg80211_get_rssi(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 *rssi)
7201 {
7202 	s32 err = BCME_OK;
7203 	scb_val_t scb_val;
7204 #ifdef SUPPORT_RSSI_SUM_REPORT
7205 	wl_rssi_ant_mimo_t rssi_ant_mimo;
7206 #endif /* SUPPORT_RSSI_SUM_REPORT */
7207 
7208 	if (dev == NULL || cfg == NULL) {
7209 		return BCME_ERROR;
7210 	}
7211 
7212 	/* initialize rssi */
7213 	*rssi = 0;
7214 
7215 #ifdef SUPPORT_RSSI_SUM_REPORT
7216 	/* Query RSSI sum across antennas */
7217 	bzero(&rssi_ant_mimo, sizeof(rssi_ant_mimo));
7218 	err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
7219 	if (err) {
7220 		WL_ERR(("Could not get rssi sum (%d)\n", err));
7221 		/* set rssi to zero and do not return error,
7222 		* because iovar phy_rssi_ant could return BCME_UNSUPPORTED
7223 		* when bssid was null during roaming
7224 		*/
7225 		err = BCME_OK;
7226 	} else {
7227 		cfg->rssi_sum_report = TRUE;
7228 		if ((*rssi = rssi_ant_mimo.rssi_sum) >= 0) {
7229 			*rssi = 0;
7230 		}
7231 	}
7232 #endif /* SUPPORT_RSSI_SUM_REPORT */
7233 
7234 	/* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore */
7235 	if (cfg->rssi_sum_report == FALSE) {
7236 		bzero(&scb_val, sizeof(scb_val));
7237 		scb_val.val = 0;
7238 		err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val,
7239 			sizeof(scb_val_t));
7240 		if (err) {
7241 			WL_ERR(("Could not get rssi (%d)\n", err));
7242 			return err;
7243 		}
7244 #if defined(RSSIOFFSET)
7245 		*rssi = wl_update_rssi_offset(dev, dtoh32(scb_val.val));
7246 #else
7247 		*rssi = dtoh32(scb_val.val);
7248 #endif
7249 	}
7250 
7251 	if (*rssi >= 0) {
7252 		/* check assoc status including roaming */
7253 		DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub));
7254 		if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_check_assoc_state(cfg, dev)) {
7255 			*rssi = cfg->rssi;	   /* use previous RSSI */
7256 			WL_DBG(("use previous RSSI %d dBm\n", cfg->rssi));
7257 		} else {
7258 			*rssi = 0;
7259 		}
7260 		DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
7261 	} else {
7262 		/* backup the current rssi */
7263 		cfg->rssi = *rssi;
7264 	}
7265 
7266 	return err;
7267 }
7268 
7269 static int
wl_cfg80211_ifstats_counters_cb(void * ctx,const uint8 * data,uint16 type,uint16 len)7270 wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data, uint16 type, uint16 len)
7271 {
7272 	switch (type) {
7273 	case WL_IFSTATS_XTLV_IF_INDEX:
7274 		WL_DBG(("Stats received on interface index: %d\n", *data));
7275 		break;
7276 	case WL_IFSTATS_XTLV_GENERIC: {
7277 		if (len > sizeof(wl_if_stats_t)) {
7278 			WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n",
7279 				type, len, (int)sizeof(wl_if_stats_t)));
7280 		}
7281 		memcpy(ctx, data, sizeof(wl_if_stats_t));
7282 		break;
7283 	}
7284 	default:
7285 		WL_DBG(("Unsupported counter type 0x%x\n", type));
7286 		break;
7287 	}
7288 
7289 	return BCME_OK;
7290 }
7291 
7292 /* Parameters to if_counters iovar need to be converted to XTLV format
7293  * before sending to FW. The length of the top level XTLV container
7294  * containing parameters should not exceed 228 bytes
7295  */
7296 #define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX	228
7297 
7298 int
wl_cfg80211_ifstats_counters(struct net_device * dev,wl_if_stats_t * if_stats)7299 wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats)
7300 {
7301 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7302 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7303 	uint8 *pbuf = NULL;
7304 	bcm_xtlvbuf_t xtlvbuf, local_xtlvbuf;
7305 	bcm_xtlv_t *xtlv;
7306 	uint16 expected_resp_len;
7307 	wl_stats_report_t *request = NULL, *response = NULL;
7308 	int bsscfg_idx;
7309 	int ret = BCME_OK;
7310 
7311 	pbuf = (uint8 *)MALLOCZ(dhdp->osh, WLC_IOCTL_MEDLEN);
7312 	if (!pbuf) {
7313 		WL_ERR(("Failed to allocate local pbuf\n"));
7314 		return BCME_NOMEM;
7315 	}
7316 
7317 	/* top level container length cannot exceed 228 bytes.
7318 	 * This is because the output buffer is 1535 bytes long.
7319 	 * Allow 1300 bytes for reporting stats coming in XTLV format
7320 	 */
7321 	request = (wl_stats_report_t *)
7322 		MALLOCZ(dhdp->osh, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7323 	if (!request) {
7324 		WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
7325 			IF_COUNTERS_PARAM_CONTAINER_LEN_MAX));
7326 		ret = BCME_NOMEM;
7327 		goto fail;
7328 	}
7329 
7330 	request->version = WL_STATS_REPORT_REQUEST_VERSION_V2;
7331 
7332 	/* Top level container... we will create it ourselves */
7333 	/* Leave space for report version, length, and top level XTLV
7334 	 * WL_IFSTATS_XTLV_IF.
7335 	 */
7336 	ret = bcm_xtlv_buf_init(&local_xtlvbuf,
7337 		(uint8*)(request->data) + BCM_XTLV_HDR_SIZE,
7338 		IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7339 		offsetof(wl_stats_report_t, data) - BCM_XTLV_HDR_SIZE,
7340 		BCM_XTLV_OPTION_ALIGN32);
7341 
7342 	if (ret) {
7343 		goto fail;
7344 	}
7345 
7346 	/* Populate requests using this the local_xtlvbuf context. The xtlvbuf
7347 	 * is used to fill the container containing the XTLVs populated using
7348 	 * local_xtlvbuf.
7349 	 */
7350 	ret = bcm_xtlv_buf_init(&xtlvbuf,
7351 		(uint8*)(request->data),
7352 		IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7353 		offsetof(wl_stats_report_t, data),
7354 		BCM_XTLV_OPTION_ALIGN32);
7355 
7356 	if (ret) {
7357 		goto fail;
7358 	}
7359 
7360 	/* Request generic stats */
7361 	ret = bcm_xtlv_put_data(&local_xtlvbuf,
7362 		WL_IFSTATS_XTLV_GENERIC, NULL, 0);
7363 	if (ret) {
7364 		goto fail;
7365 	}
7366 
7367 	/* Complete the outer container with type and length
7368 	 * only.
7369 	 */
7370 	ret = bcm_xtlv_put_data(&xtlvbuf,
7371 		WL_IFSTATS_XTLV_IF,
7372 		NULL, bcm_xtlv_buf_len(&local_xtlvbuf));
7373 
7374 	if (ret) {
7375 		goto fail;
7376 	}
7377 
7378 	request->length = bcm_xtlv_buf_len(&xtlvbuf) +
7379 		offsetof(wl_stats_report_t, data);
7380 	bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
7381 
7382 	/* send the command over to the device and get teh output */
7383 	ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request,
7384 		request->length, pbuf, WLC_IOCTL_MEDLEN, bsscfg_idx,
7385 		&cfg->ioctl_buf_sync);
7386 	if (ret < 0) {
7387 		WL_ERR(("if_counters not supported ret=%d\n", ret));
7388 		goto fail;
7389 	}
7390 
7391 	/* Reuse request to process response */
7392 	response = (wl_stats_report_t *)pbuf;
7393 
7394 	/* version check */
7395 	if (response->version != WL_STATS_REPORT_REQUEST_VERSION_V2) {
7396 		ret = BCME_VERSION;
7397 		goto fail;
7398 	}
7399 
7400 	xtlv = (bcm_xtlv_t *)(response->data);
7401 
7402 	expected_resp_len =
7403 		(BCM_XTLV_LEN(xtlv) + OFFSETOF(wl_stats_report_t, data));
7404 
7405 	/* Check if the received length is as expected */
7406 	if ((response->length > WLC_IOCTL_MEDLEN) ||
7407 		(response->length < expected_resp_len)) {
7408 		ret = BCME_ERROR;
7409 		WL_ERR(("Illegal response length received. Got: %d"
7410 			" Expected: %d. Expected len must be <= %u\n",
7411 			response->length, expected_resp_len, WLC_IOCTL_MEDLEN));
7412 		goto fail;
7413 	}
7414 
7415 	/* check the type. The return data will be in
7416 	 * WL_IFSTATS_XTLV_IF container. So check if that container is
7417 	 * present
7418 	 */
7419 	if (BCM_XTLV_ID(xtlv) != WL_IFSTATS_XTLV_IF) {
7420 		ret = BCME_ERROR;
7421 		WL_ERR(("unexpected type received: %d Expected: %d\n",
7422 			BCM_XTLV_ID(xtlv), WL_IFSTATS_XTLV_IF));
7423 		goto fail;
7424 	}
7425 
7426 	/* Process XTLVs within WL_IFSTATS_XTLV_IF container */
7427 	ret = bcm_unpack_xtlv_buf(if_stats,
7428 		(uint8*)response->data + BCM_XTLV_HDR_SIZE,
7429 		BCM_XTLV_LEN(xtlv), /* total length of all TLVs in container */
7430 		BCM_XTLV_OPTION_ALIGN32, wl_cfg80211_ifstats_counters_cb);
7431 	if (ret) {
7432 		WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret));
7433 	}
7434 
7435 fail:
7436 	if (pbuf) {
7437 		MFREE(dhdp->osh, pbuf, WLC_IOCTL_MEDLEN);
7438 	}
7439 
7440 	if (request) {
7441 		MFREE(dhdp->osh, request, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7442 	}
7443 	return ret;
7444 }
7445 #undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
7446 
7447 static s32
7448 #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)7449 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7450         const u8 *mac, struct station_info *sinfo)
7451 #else
7452 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7453         u8 *mac, struct station_info *sinfo)
7454 #endif
7455 {
7456 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7457 	s32 rssi = 0;
7458 #if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
7459 	wl_rssi_ant_mimo_t rssi_ant_mimo;
7460 	int cnt, chains;
7461 #endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
7462 	s32 rate = 0;
7463 	s32 err = 0;
7464 	u16 wl_iftype = 0;
7465 	u16 wl_mode = 0;
7466 	get_pktcnt_t pktcnt;
7467 	wl_if_stats_t *if_stats = NULL;
7468 	sta_info_v4_t *sta = NULL;
7469 #ifdef WL_RATE_INFO
7470 	wl_rate_info_t *rates = NULL;
7471 #endif /* WL_RATE_INFO */
7472 	u8 *curmacp = NULL;
7473 	s8 eabuf[ETHER_ADDR_STR_LEN];
7474 #if defined(BCMDONGLEHOST)
7475 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
7476 	bool fw_assoc_state = FALSE;
7477 	u32 dhd_assoc_state = 0;
7478 #endif
7479 	void *buf;
7480 
7481 	RETURN_EIO_IF_NOT_UP(cfg);
7482 
7483 	if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype, &wl_iftype, &wl_mode) < 0) {
7484 		return -EINVAL;
7485 	}
7486 
7487 	buf = MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
7488 	if (buf == NULL) {
7489 		WL_ERR(("wl_cfg80211_get_station: MALLOC failed\n"));
7490 		goto error;
7491 	}
7492 
7493 	switch (wl_iftype) {
7494 		case WL_IF_TYPE_STA:
7495 		case WL_IF_TYPE_IBSS:
7496 			if (cfg->roam_offload) {
7497 				struct ether_addr bssid;
7498 				bzero(&bssid, sizeof(bssid));
7499 				err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
7500 				if (err) {
7501 					WL_ERR(("Failed to get current BSSID\n"));
7502 				} else {
7503 					if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
7504 						/* roaming is detected */
7505 						err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
7506 						if (err)
7507 							WL_ERR(("Failed to handle the delayed"
7508 								" roam, err=%d", err));
7509 						mac = (u8 *)bssid.octet;
7510 					}
7511 				}
7512 			}
7513 #if defined(BCMDONGLEHOST)
7514 			dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
7515 			DHD_OS_WAKE_LOCK(dhd);
7516 			fw_assoc_state = dhd_is_associated(dhd, 0, &err);
7517 			if (dhd_assoc_state && !fw_assoc_state) {
7518 				/* check roam (join) status */
7519 				if (wl_check_assoc_state(cfg, dev)) {
7520 					fw_assoc_state = TRUE;
7521 					WL_DBG(("roam status\n"));
7522 				}
7523 			}
7524 			DHD_OS_WAKE_UNLOCK(dhd);
7525 #endif
7526 #if defined(BCMDONGLEHOST)
7527 			if (!dhd_assoc_state || !fw_assoc_state)
7528 #else
7529 			if (!wl_get_drv_status(cfg, CONNECTED, dev))
7530 #endif /* defined(BCMDONGLEHOST) */
7531 			{
7532 				WL_ERR(("NOT assoc\n"));
7533 				if (err == -ENODATA)
7534 					goto error;
7535 #if defined(BCMDONGLEHOST)
7536 				if (!dhd_assoc_state) {
7537 					WL_TRACE_HW4(("drv state is not connected \n"));
7538 				}
7539 				if (!fw_assoc_state) {
7540 					WL_TRACE_HW4(("fw state is not associated \n"));
7541 				}
7542 				/* Disconnect due to fw is not associated for
7543 				 * FW_ASSOC_WATCHDOG_TIME ms.
7544 				 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
7545 				 * means that BSSID is null.
7546 				 */
7547 				if (dhd_assoc_state && !fw_assoc_state && !err) {
7548 					if (!fw_assoc_watchdog_started) {
7549 						fw_assoc_watchdog_ms = OSL_SYSUPTIME();
7550 						fw_assoc_watchdog_started = TRUE;
7551 						WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
7552 					} else if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
7553 							FW_ASSOC_WATCHDOG_TIME) {
7554 						fw_assoc_watchdog_started = FALSE;
7555 						err = -ENODEV;
7556 						WL_TRACE_HW4(("fw is not associated for %d ms \n",
7557 							(OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
7558 						goto get_station_err;
7559 					}
7560 				}
7561 #endif /* defined(BCMDONGLEHOST) */
7562 				err = -ENODEV;
7563 				goto error;
7564 			}
7565 #if defined(BCMDONGLEHOST)
7566 			if (dhd_is_associated(dhd, 0, NULL)) {
7567 				fw_assoc_watchdog_started = FALSE;
7568 			}
7569 #endif /* defined(BCMDONGLEHOST) */
7570 			curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
7571 			if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
7572 				WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
7573 					MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
7574 			}
7575 			sta = (sta_info_v4_t *)buf;
7576 			bzero(sta, WLC_IOCTL_MEDLEN);
7577 			err = wldev_iovar_getbuf(dev, "sta_info", (const void*)curmacp,
7578 					ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL);
7579 			if (err < 0) {
7580 				WL_ERR(("GET STA INFO failed, %d\n", err));
7581 				goto error;
7582 			}
7583 			if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
7584 				WL_ERR(("GET STA INFO version mismatch, %d\n", err));
7585 				return BCME_VERSION;
7586 			}
7587 			sta->rx_rate = dtoh32(sta->rx_rate);
7588 			if (sta->rx_rate != 0) {
7589 				sinfo->filled |= STA_INFO_BIT(INFO_RX_BITRATE);
7590 				sinfo->rxrate.legacy = sta->rx_rate / 100;
7591 				WL_DBG(("RX Rate %d Mbps\n", (sta->rx_rate / 1000)));
7592 			}
7593 			/* go through to get another information */
7594 		case WL_IF_TYPE_P2P_GC:
7595 		case WL_IF_TYPE_P2P_DISC:
7596 			if ((err = wl_cfg80211_get_rssi(dev, cfg, &rssi)) != BCME_OK) {
7597 				goto get_station_err;
7598 			}
7599 #if defined(RSSIAVG)
7600 			err = wl_update_connected_rssi_cache(dev, &cfg->g_connected_rssi_cache_ctrl, &rssi);
7601 			if (err) {
7602 				WL_ERR(("Could not get rssi (%d)\n", err));
7603 				goto get_station_err;
7604 			}
7605 			wl_delete_dirty_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
7606 			wl_reset_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
7607 #endif
7608 #if defined(RSSIOFFSET)
7609 			rssi = wl_update_rssi_offset(dev, rssi);
7610 #endif
7611 #if !defined(RSSIAVG) && !defined(RSSIOFFSET)
7612 			// terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
7613 			rssi = MIN(rssi, RSSI_MAXVAL);
7614 #endif
7615 			sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
7616 			sinfo->signal = rssi;
7617 			WL_DBG(("RSSI %d dBm\n", rssi));
7618 #if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
7619 			/* Query RSSI sum across antennas */
7620 			(void)memset_s(&rssi_ant_mimo,
7621 				sizeof(rssi_ant_mimo), 0, sizeof(rssi_ant_mimo));
7622 			err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
7623 			if (err) {
7624 				WL_ERR(("Could not get rssi sum (%d)\n", err));
7625 			} else {
7626 				chains = 0;
7627 				for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
7628 					sinfo->chain_signal[cnt] = rssi_ant_mimo.rssi_ant[cnt];
7629 					chains |= (1 << cnt);
7630 					WL_DBG(("RSSI[%d]: %d dBm\n",
7631 						cnt, rssi_ant_mimo.rssi_ant[cnt]));
7632 				}
7633 				sinfo->chains = chains;
7634 				sinfo->filled |= STA_INFO_BIT(INFO_CHAIN_SIGNAL);
7635 			}
7636 #endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
7637 			/* go through to get another information */
7638 		case WL_IF_TYPE_P2P_GO:
7639 #ifdef WL_RATE_INFO
7640 			/* Get the current tx/rx rate */
7641 			err = wldev_iovar_getbuf(dev, "rate_info", NULL, 0,
7642 				buf, WLC_IOCTL_SMLEN, NULL);
7643 #else
7644 			/* Get the current tx rate */
7645 			err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
7646 #endif /* WL_RATE_INFO */
7647 			if (err) {
7648 				WL_ERR(("Could not get rate (%d)\n", err));
7649 				goto error;
7650 			} else {
7651 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7652 				int rxpktglom;
7653 #endif
7654 #ifdef WL_RATE_INFO
7655 				rates = (wl_rate_info_t *)buf;
7656 				rates->version = dtoh32(rates->version);
7657 				rates->length = dtoh32(rates->length);
7658 				if (rates->version != WL_RATE_INFO_VERSION) {
7659 					WL_ERR(("RATE_INFO version mismatch\n"));
7660 					err = BCME_VERSION;
7661 					goto error;
7662 				}
7663 				if (rates->length != (uint16)sizeof(wl_rate_info_t)) {
7664 					WL_ERR(("RATE_INFO length mismatch\n"));
7665 					err = BCME_BADLEN;
7666 					goto error;
7667 				}
7668 				/* Report the current tx rate */
7669 				rate = dtoh32(rates->mode_tx_rate);
7670 #else
7671 				/* Report the current tx rate */
7672 				rate = dtoh32(rate);
7673 #endif /* WL_RATE_INFO */
7674 				sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
7675 				sinfo->txrate.legacy = rate * 5;
7676 				WL_DBG(("Tx rate %d Mbps\n", (rate / 2)));
7677 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7678 				rxpktglom = ((rate/2) > 150) ? 20 : 10;
7679 
7680 				if (maxrxpktglom != rxpktglom) {
7681 					maxrxpktglom = rxpktglom;
7682 					WL_DBG(("Rate %d Mbps, update bus:"
7683 						"maxtxpktglom=%d\n", (rate/2), maxrxpktglom));
7684 					err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
7685 							(char*)&maxrxpktglom, 4, cfg->ioctl_buf,
7686 							WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
7687 					if (err < 0) {
7688 						WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
7689 					}
7690 				}
7691 #endif
7692 #ifdef WL_RATE_INFO
7693 				/* Report the current rx rate */
7694 				rate = dtoh32(rates->mode_rx_rate);
7695 				sinfo->filled |= STA_INFO_BIT(INFO_RX_BITRATE);
7696 				sinfo->rxrate.legacy = rate * 5;
7697 				WL_DBG(("Rx rate %d Mbps\n", (rate / 2)));
7698 #endif /* WL_RATE_INFO */
7699 			}
7700 			if_stats = (wl_if_stats_t *)buf;
7701 			bzero(if_stats, WLC_IOCTL_MEDLEN);
7702 #ifdef BCMDONGLEHOST
7703 			if (FW_SUPPORTED(dhd, ifst)) {
7704 				err = wl_cfg80211_ifstats_counters(dev, if_stats);
7705 			} else
7706 #endif /* BCMDONGLEHOST */
7707 			{
7708 				err = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
7709 						(char *)if_stats, WLC_IOCTL_MEDLEN, NULL);
7710 			}
7711 
7712 			if (err) {
7713 //				WL_ERR(("if_counters not supported ret=%d\n", err));
7714 				bzero(&pktcnt, sizeof(pktcnt));
7715 				err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt,
7716 						sizeof(pktcnt));
7717 				if (!err) {
7718 					sinfo->rx_packets = pktcnt.rx_good_pkt;
7719 					sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
7720 					sinfo->tx_packets = pktcnt.tx_good_pkt;
7721 					sinfo->tx_failed  = pktcnt.tx_bad_pkt;
7722 				}
7723 			} else {
7724 				sinfo->rx_packets = (uint32)dtoh64(if_stats->rxframe);
7725 				/* In this case, if_stats->rxerror is invalid.
7726 				 * So, force to assign '0'.
7727 				 */
7728 				sinfo->rx_dropped_misc = 0;
7729 				sinfo->tx_packets = (uint32)dtoh64(if_stats->txfrmsnt);
7730 				sinfo->tx_failed = (uint32)dtoh64(if_stats->txnobuf) +
7731 					(uint32)dtoh64(if_stats->txrunt) +
7732 					(uint32)dtoh64(if_stats->txfail);
7733 				sinfo->rx_bytes = dtoh64(if_stats->rxbyte);
7734 				sinfo->tx_bytes = dtoh64(if_stats->txbyte);
7735 				sinfo->tx_retries = (uint32)dtoh64(if_stats->txretry);
7736 				sinfo->filled |= (STA_INFO_BIT(INFO_RX_BYTES) |
7737 					STA_INFO_BIT(INFO_TX_BYTES) |
7738 					STA_INFO_BIT(INFO_TX_RETRIES));
7739 			}
7740 
7741 			sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
7742 					STA_INFO_BIT(INFO_RX_DROP_MISC) |
7743 					STA_INFO_BIT(INFO_TX_PACKETS) |
7744 					STA_INFO_BIT(INFO_TX_FAILED));
7745 get_station_err:
7746 			if (err && (err != -ENODATA)) {
7747 				/* Disconnect due to zero BSSID or error to get RSSI */
7748 				scb_val_t scbval;
7749 #ifdef BCMDONGLEHOST
7750 				DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
7751 					dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
7752 #endif /* BCMDONGLEHOST */
7753 				scbval.val = htod32(DOT11_RC_DISASSOC_LEAVING);
7754 				err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
7755 						sizeof(scb_val_t));
7756 				if (unlikely(err)) {
7757 					WL_ERR(("disassoc error (%d)\n", err));
7758 				}
7759 
7760 				WL_ERR(("force cfg80211_disconnected: %d\n", err));
7761 				wl_clr_drv_status(cfg, CONNECTED, dev);
7762 #ifdef BCMDONGLEHOST
7763 				DHD_STATLOG_CTRL(dhd, ST(DISASSOC_DONE),
7764 					dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
7765 #endif /* BCMDONGLEHOST */
7766 				CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
7767 				wl_link_down(cfg);
7768 			}
7769 			break;
7770 		case WL_IF_TYPE_AP:
7771 			sta = (sta_info_v4_t *)buf;
7772 			bzero(sta, WLC_IOCTL_MEDLEN);
7773 			err = wldev_iovar_getbuf(dev, "sta_info", (const   void*)mac,
7774 					ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL);
7775 			if (err < 0) {
7776 				WL_ERR(("GET STA INFO failed, %d\n", err));
7777 				goto error;
7778 			}
7779 			if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
7780 				WL_ERR(("GET STA INFO version mismatch, %d\n", err));
7781 				return BCME_VERSION;
7782 			}
7783 			sta->len = dtoh16(sta->len);
7784 			sta->cap = dtoh16(sta->cap);
7785 			sta->flags = dtoh32(sta->flags);
7786 			sta->idle = dtoh32(sta->idle);
7787 			sta->in = dtoh32(sta->in);
7788 			sinfo->filled |= STA_INFO_BIT(INFO_INACTIVE_TIME);
7789 			sinfo->inactive_time = sta->idle * 1000;
7790 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || \
7791 			defined(WL_COMPAT_WIRELESS)
7792 			if (sta->flags & WL_STA_ASSOC) {
7793 				sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
7794 				sinfo->connected_time = sta->in;
7795 			}
7796 #endif
7797 			WL_INFORM_MEM(("STA %s, flags 0x%x, idle time %ds, connected time %ds\n",
7798 				bcm_ether_ntoa((const struct ether_addr *)mac, eabuf),
7799 				sta->flags, sta->idle, sta->in));
7800 			break;
7801 		default :
7802 			WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
7803 	}
7804 error:
7805 	if (buf) {
7806 		MFREE(cfg->osh, buf, WLC_IOCTL_MEDLEN);
7807 	}
7808 
7809 	return err;
7810 }
7811 
7812 static int
wl_cfg80211_dump_station(struct wiphy * wiphy,struct net_device * ndev,int idx,u8 * mac,struct station_info * sinfo)7813 wl_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
7814 	int idx, u8 *mac, struct station_info *sinfo)
7815 {
7816 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7817 	struct maclist *assoc_maclist = (struct maclist *)&(cfg->assoclist);
7818 	int err;
7819 
7820 	WL_DBG(("%s: enter, idx=%d\n", __FUNCTION__, idx));
7821 
7822 	if (idx == 0) {
7823 		assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
7824 		err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
7825 			assoc_maclist, sizeof(cfg->assoclist));
7826 		if (err < 0) {
7827 			WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
7828 			cfg->assoclist.count = 0;
7829 			return -EOPNOTSUPP;
7830 		}
7831 	}
7832 
7833 	if (idx < le32_to_cpu(cfg->assoclist.count)) {
7834 		(void)memcpy_s(mac, ETH_ALEN, cfg->assoclist.mac[idx], ETH_ALEN);
7835 		return wl_cfg80211_get_station(wiphy, ndev, mac, sinfo);
7836 	}
7837 
7838 	return -ENOENT;
7839 }
7840 
7841 static s32
wl_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool enabled,s32 timeout)7842 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
7843 	bool enabled, s32 timeout)
7844 {
7845 	s32 pm;
7846 	s32 err = 0;
7847 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7848 	struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
7849 	s32 mode;
7850 #ifdef RTT_SUPPORT
7851 	rtt_status_info_t *rtt_status;
7852 #endif /* RTT_SUPPORT */
7853 	dhd_pub_t *dhd = cfg->pub;
7854 	RETURN_EIO_IF_NOT_UP(cfg);
7855 
7856 	WL_DBG(("Enter\n"));
7857 	mode = wl_get_mode_by_netdev(cfg, dev);
7858 	if (cfg->p2p_net == dev || _net_info == NULL ||
7859 			!wl_get_drv_status(cfg, CONNECTED, dev) ||
7860 			((mode != WL_MODE_BSS) &&
7861 			(mode != WL_MODE_IBSS))) {
7862 		return err;
7863 	}
7864 
7865 	/* Enlarge pm_enable_work */
7866 	wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
7867 
7868 	pm = enabled ? PM_FAST : PM_OFF;
7869 	if (_net_info->pm_block) {
7870 		WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
7871 			dev->name, _net_info->pm_block));
7872 		pm = PM_OFF;
7873 	}
7874 	if (enabled && dhd_conf_get_pm(dhd) >= 0)
7875 		pm = dhd_conf_get_pm(dhd);
7876 	pm = htod32(pm);
7877 	WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
7878 #ifdef RTT_SUPPORT
7879 	rtt_status = GET_RTTSTATE(dhd);
7880 	if (rtt_status->status != RTT_ENABLED) {
7881 #endif /* RTT_SUPPORT */
7882 		err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
7883 		if (unlikely(err)) {
7884 			if (err == -ENODEV)
7885 				WL_DBG(("net_device is not ready yet\n"));
7886 			else
7887 				WL_ERR(("error (%d)\n", err));
7888 			return err;
7889 		}
7890 #ifdef RTT_SUPPORT
7891 	}
7892 #endif /* RTT_SUPPORT */
7893 	wl_cfg80211_update_power_mode(dev);
7894 	return err;
7895 }
7896 
7897 /* force update cfg80211 to keep power save mode in sync. BUT this is NOT
7898  * a good solution since there is no protection while changing wdev->os. Best
7899  * way of changing power saving mode is doing it through
7900  * NL80211_CMD_SET_POWER_SAVE
7901  */
wl_cfg80211_update_power_mode(struct net_device * dev)7902 void wl_cfg80211_update_power_mode(struct net_device *dev)
7903 {
7904 	int err, pm = -1;
7905 
7906 	err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
7907 	if (err)
7908 		WL_ERR(("error (%d)\n", err));
7909 	else if (pm != -1 && dev->ieee80211_ptr)
7910 		dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
7911 }
7912 
wl_find_msb(u16 bit16)7913 static __used u32 wl_find_msb(u16 bit16)
7914 {
7915 	u32 ret = 0;
7916 
7917 	if (bit16 & 0xff00) {
7918 		ret += 8;
7919 		bit16 >>= 8;
7920 	}
7921 
7922 	if (bit16 & 0xf0) {
7923 		ret += 4;
7924 		bit16 >>= 4;
7925 	}
7926 
7927 	if (bit16 & 0xc) {
7928 		ret += 2;
7929 		bit16 >>= 2;
7930 	}
7931 
7932 	if (bit16 & 2)
7933 		ret += bit16 & 2;
7934 	else if (bit16)
7935 		ret += bit16;
7936 
7937 	return ret;
7938 }
7939 
7940 #ifndef OEM_ANDROID
7941 /*
7942  * API invoked from driver .resume context
7943  */
7944 s32
wl_cfg80211_resume(struct bcm_cfg80211 * cfg)7945 wl_cfg80211_resume(struct bcm_cfg80211 *cfg)
7946 {
7947 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7948 	s32 err = BCME_OK;
7949 	int pkt_filter_id = WL_WOWLAN_PKT_FILTER_ID_FIRST;
7950 
7951 	if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
7952 		WL_INFORM_MEM(("device is not ready\n"));
7953 		return err;
7954 	}
7955 
7956 	while (pkt_filter_id <= WL_WOWLAN_PKT_FILTER_ID_LAST) {
7957 		/* delete wowlan pkt filter if any */
7958 		err = wldev_iovar_setbuf(ndev, "pkt_filter_delete", &pkt_filter_id,
7959 			sizeof(pkt_filter_id), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
7960 			&cfg->ioctl_buf_sync);
7961 		/* pkt_filter_delete would return BCME_BADARG when pkt filter id
7962 		 * does not exist in filter list of firmware, ignore it.
7963 		 */
7964 		if (BCME_BADARG == err)
7965 			err = BCME_OK;
7966 
7967 		if (BCME_OK != err) {
7968 			WL_ERR(("pkt_filter_delete failed, id=%d, err=%d\n",
7969 				pkt_filter_id, err));
7970 		}
7971 		pkt_filter_id++;
7972 	}
7973 
7974 	return err;
7975 }
7976 #endif /* !OEM_ANDROID */
7977 
7978 #if !defined(OEM_ANDROID)
7979 #ifdef CONFIG_PM
7980 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
wl_wowlan_config(struct wiphy * wiphy,struct cfg80211_wowlan * wow)7981 static s32 wl_wowlan_config(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
7982 {
7983 	s32 err = BCME_OK;
7984 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7985 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7986 
7987 	u32 i = 0, j = 0;
7988 	u32 buf_len = 0, pattern_size = 0;
7989 	wl_pkt_filter_t	*pkt_filterp = NULL;
7990 	wl_pkt_filter_enable_t	pkt_filter_enable;
7991 	u8 mask_bytes_len = 0, mask_byte_idx = 0, mask_bit_idx = 0;
7992 	const u32 max_buf_size = WL_PKT_FILTER_FIXED_LEN +
7993 		WL_PKT_FILTER_PATTERN_FIXED_LEN + (2 * WL_WOWLAN_MAX_PATTERN_LEN);
7994 
7995 	WL_DBG(("Enter\n"));
7996 
7997 	if (wow == NULL) {
7998 		WL_DBG(("wow config is null\n"));
7999 		return err;
8000 	}
8001 
8002 	/* configure wowlan pattern filters */
8003 	if (0 < wow->n_patterns) {
8004 		pkt_filterp = (wl_pkt_filter_t *)MALLOCZ(cfg->osh, max_buf_size);
8005 		if (pkt_filterp == NULL) {
8006 			WL_ERR(("Error allocating buffer for pkt filters\n"));
8007 			return -ENOMEM;
8008 		}
8009 
8010 		WL_DBG(("Pattern count=%d\n", wow->n_patterns));
8011 		while (i < wow->n_patterns) {
8012 
8013 			/* reset buffers */
8014 			buf_len = 0;
8015 			bzero(pkt_filterp, max_buf_size);
8016 
8017 			/* copy filter id */
8018 			store32_ua(&pkt_filterp->id, (WL_WOWLAN_PKT_FILTER_ID_FIRST + i));
8019 
8020 			/* copy filter type */
8021 			store32_ua(&pkt_filterp->type, WL_PKT_FILTER_TYPE_PATTERN_MATCH);
8022 
8023 			/* copy size */
8024 			pattern_size = htod32(wow->patterns[i].pattern_len);
8025 			store32_ua(&pkt_filterp->u.pattern.size_bytes, pattern_size);
8026 
8027 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
8028 			/* copy offset */
8029 			store32_ua(&pkt_filterp->u.pattern.offset, wow->patterns[i].pkt_offset);
8030 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
8031 
8032 			/* convert mask from bit to byte format */
8033 			j = 0;
8034 			mask_bit_idx = 0;
8035 			mask_byte_idx = 0;
8036 			mask_bytes_len = DIV_ROUND_UP(pattern_size, 8);
8037 			while ((mask_byte_idx < mask_bytes_len) &&
8038 					(mask_bit_idx < pattern_size)) {
8039 
8040 				if (isbitset(wow->patterns[i].mask[mask_byte_idx], mask_bit_idx++))
8041 					pkt_filterp->u.pattern.mask_and_pattern[j] = 0xFF;
8042 				j++;
8043 				if (mask_bit_idx >= 8) {
8044 					/* move to next mask byte */
8045 					mask_bit_idx = 0;
8046 					mask_byte_idx++;
8047 				}
8048 			}
8049 
8050 			/* copy pattern to be matched */
8051 			memcpy(&pkt_filterp->u.pattern.mask_and_pattern[pattern_size],
8052 				wow->patterns[i].pattern, pattern_size);
8053 
8054 			/* calculate filter buffer len */
8055 			buf_len += WL_PKT_FILTER_FIXED_LEN;
8056 			buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + (2 * pattern_size));
8057 
8058 			/* add pkt filter */
8059 			err = wldev_iovar_setbuf(ndev, "pkt_filter_add", pkt_filterp, buf_len,
8060 				cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync);
8061 			if (BCME_OK != err) {
8062 				WL_ERR(("pkt_filter_add failed, id=%d, err=%d\n",
8063 					pkt_filterp->id, err));
8064 				goto exit;
8065 			}
8066 
8067 			/* enable pkt filter id */
8068 			pkt_filter_enable.id = pkt_filterp->id;
8069 			pkt_filter_enable.enable = TRUE;
8070 			err = wldev_iovar_setbuf(ndev, "pkt_filter_enable", &pkt_filter_enable,
8071 				sizeof(pkt_filter_enable),
8072 				cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
8073 			if (BCME_OK != err) {
8074 				WL_ERR(("pkt_filter_enable failed, id=%d, err=%d\n",
8075 					pkt_filterp->id, err));
8076 				goto exit;
8077 			}
8078 			i++; /* move to next pattern */
8079 		}
8080 	} else
8081 		WL_DBG(("wowlan filters not found\n"));
8082 
8083 exit:
8084 	if (pkt_filterp) {
8085 		MFREE(cfg->osh, pkt_filterp, max_buf_size);
8086 	}
8087 
8088 	return err;
8089 }
8090 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
8091 #endif /* CONFIG_PM */
8092 #endif /* !OEM_ANDROID */
8093 
8094 #ifndef OEM_ANDROID
8095 /*
8096  * API invoked from driver .suspend context
8097  */
8098 s32
wl_cfg80211_suspend(struct bcm_cfg80211 * cfg)8099 wl_cfg80211_suspend(struct bcm_cfg80211 *cfg)
8100 {
8101 	s32 err = BCME_OK;
8102 #ifdef CONFIG_PM
8103 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
8104 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
8105 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
8106 #endif /* CONFIG_PM */
8107 #ifdef DHD_CLEAR_ON_SUSPEND
8108 	struct net_info *iter, *next;
8109 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8110 	unsigned long flags;
8111 
8112 	if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8113 		WL_INFORM_MEM(("device is not ready : status (%d)\n",
8114 			(int)cfg->status));
8115 		return err;
8116 	}
8117 	for_each_ndev(cfg, iter, next) {
8118 		/* p2p discovery iface doesn't have a ndev associated with it (for kernel > 3.8) */
8119 		if (iter->ndev)
8120 			wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8121 		}
8122 	WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
8123 	if (cfg->scan_request) {
8124 		cfg80211_scan_done(cfg->scan_request, true);
8125 		cfg->scan_request = NULL;
8126 	}
8127 	for_each_ndev(cfg, iter, next) {
8128 		if (iter->ndev) {
8129 			wl_clr_drv_status(cfg, SCANNING, iter->ndev);
8130 			wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8131 		}
8132 	}
8133 	WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
8134 	for_each_ndev(cfg, iter, next) {
8135 		if (iter->ndev) {
8136 			if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
8137 				wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false);
8138 			}
8139 		}
8140 	}
8141 #endif /* DHD_CLEAR_ON_SUSPEND */
8142 #ifdef CONFIG_PM
8143 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
8144 	err = wl_wowlan_config(wiphy, wiphy->wowlan_config);
8145 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
8146 #endif /* CONFIG_PM */
8147 
8148 	return err;
8149 }
8150 #endif /* !OEM_ANDROID */
8151 
8152 static s32
wl_update_pmklist(struct net_device * dev,struct wl_pmk_list * pmk_list,s32 err)8153 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
8154 	s32 err)
8155 {
8156 	int i, j;
8157 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8158 	struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
8159 	int npmkids = cfg->pmk_list->pmkids.count;
8160 
8161 	ASSERT(cfg->pmk_list->pmkids.length >= (sizeof(u16)*2));
8162 	if (!pmk_list) {
8163 		WL_ERR(("pmk_list is NULL\n"));
8164 		return -EINVAL;
8165 	}
8166 	/* pmk list is supported only for STA interface i.e. primary interface
8167 	 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
8168 	 */
8169 	if (primary_dev != dev) {
8170 		WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
8171 			" interfaces than primary interface\n"));
8172 		return err;
8173 	}
8174 
8175 	WL_DBG(("No of elements %d\n", npmkids));
8176 	for (i = 0; i < npmkids; i++) {
8177 		WL_DBG(("PMKID[%d]: %pM =\n", i,
8178 			&pmk_list->pmkids.pmkid[i].bssid));
8179 		for (j = 0; j < WPA2_PMKID_LEN; j++) {
8180 			WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].pmkid[j]));
8181 		}
8182 	}
8183 	if (cfg->wlc_ver.wlc_ver_major >= MIN_PMKID_LIST_V3_FW_MAJOR) {
8184 			pmk_list->pmkids.version = PMKID_LIST_VER_3;
8185 			err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8186 				sizeof(*pmk_list), cfg->ioctl_buf,
8187 				WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8188 	}
8189 	else if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V2_FW_MAJOR) {
8190 		u32 v2_list_size = (u32)(sizeof(pmkid_list_v2_t) + npmkids*sizeof(pmkid_v2_t));
8191 		pmkid_list_v2_t *pmkid_v2_list = (pmkid_list_v2_t *)MALLOCZ(cfg->osh, v2_list_size);
8192 		pmkid_list_v3_t *spmk_list = &cfg->spmk_info_list->pmkids;
8193 
8194 		if (pmkid_v2_list == NULL) {
8195 			WL_ERR(("failed to allocate pmkid list\n"));
8196 			return BCME_NOMEM;
8197 		}
8198 
8199 		pmkid_v2_list->version = PMKID_LIST_VER_2;
8200 		/* Account for version, length and pmkid_v2_t fields */
8201 		pmkid_v2_list->length = (npmkids * sizeof(pmkid_v2_t)) + (2 * sizeof(u16));
8202 
8203 		for (i = 0; i < npmkids; i++) {
8204 			/* memcpy_s return checks not needed as buffers are of same size */
8205 			(void)memcpy_s(&pmkid_v2_list->pmkid[i].BSSID,
8206 					ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8207 					ETHER_ADDR_LEN);
8208 
8209 			/* copy pmkid if available */
8210 			if (pmk_list->pmkids.pmkid[i].pmkid_len) {
8211 				(void)memcpy_s(pmkid_v2_list->pmkid[i].PMKID,
8212 						WPA2_PMKID_LEN,
8213 						pmk_list->pmkids.pmkid[i].pmkid,
8214 						pmk_list->pmkids.pmkid[i].pmkid_len);
8215 			}
8216 
8217 			if (pmk_list->pmkids.pmkid[i].pmk_len) {
8218 				(void)memcpy_s(pmkid_v2_list->pmkid[i].pmk,
8219 						pmk_list->pmkids.pmkid[i].pmk_len,
8220 						pmk_list->pmkids.pmkid[i].pmk,
8221 						pmk_list->pmkids.pmkid[i].pmk_len);
8222 				pmkid_v2_list->pmkid[i].pmk_len = pmk_list->pmkids.pmkid[i].pmk_len;
8223 			}
8224 
8225 			if (pmk_list->pmkids.pmkid[i].ssid_len) {
8226 				(void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
8227 						pmk_list->pmkids.pmkid[i].ssid_len,
8228 						pmk_list->pmkids.pmkid[i].ssid,
8229 						pmk_list->pmkids.pmkid[i].ssid_len);
8230 				pmkid_v2_list->pmkid[i].ssid.ssid_len
8231 					= pmk_list->pmkids.pmkid[i].ssid_len;
8232 			}
8233 
8234 			(void)memcpy_s(pmkid_v2_list->pmkid[i].fils_cache_id,
8235 					FILS_CACHE_ID_LEN, &pmk_list->pmkids.pmkid[i].fils_cache_id,
8236 					FILS_CACHE_ID_LEN);
8237 			for (j = 0; j < spmk_list->count; j++) {
8238 				if (memcmp(&pmkid_v2_list->pmkid[i].BSSID,
8239 					&spmk_list->pmkid[j].bssid, ETHER_ADDR_LEN)) {
8240 					continue; /* different MAC */
8241 				}
8242 				WL_DBG(("SPMK replace idx:%d bssid: "MACF " to SSID: %d\n", i,
8243 					ETHER_TO_MACF(pmkid_v2_list->pmkid[i].BSSID),
8244 					spmk_list->pmkid[j].ssid_len));
8245 				bzero(&pmkid_v2_list->pmkid[i].BSSID, ETHER_ADDR_LEN);
8246 				pmkid_v2_list->pmkid[i].ssid.ssid_len =
8247 					spmk_list->pmkid[j].ssid_len;
8248 				(void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
8249 					spmk_list->pmkid[j].ssid_len,
8250 					spmk_list->pmkid[j].ssid,
8251 					spmk_list->pmkid[j].ssid_len);
8252 			}
8253 			pmkid_v2_list->pmkid[i].length = PMKID_ELEM_V2_LENGTH;
8254 		}
8255 
8256 		err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v2_list,
8257 				v2_list_size, cfg->ioctl_buf,
8258 				WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8259 		if (unlikely(err)) {
8260 			WL_ERR(("pmkid_info failed (%d)\n", err));
8261 		}
8262 
8263 		MFREE(cfg->osh, pmkid_v2_list, v2_list_size);
8264 	}
8265 	else {
8266 		u32 v1_list_size = (u32)(sizeof(pmkid_list_v1_t) + npmkids*sizeof(pmkid_v1_t));
8267 		pmkid_list_v1_t *pmkid_v1_list = (pmkid_list_v1_t *)MALLOCZ(cfg->osh, v1_list_size);
8268 		if (pmkid_v1_list == NULL) {
8269 			WL_ERR(("failed to allocate pmkid list\n"));
8270 			return BCME_NOMEM;
8271 		}
8272 		for (i = 0; i < npmkids; i++) {
8273 			/* memcpy_s return checks not needed as buffers are of same size */
8274 			(void)memcpy_s(&pmkid_v1_list->pmkid[i].BSSID,
8275 					ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8276 					ETHER_ADDR_LEN);
8277 			(void)memcpy_s(pmkid_v1_list->pmkid[i].PMKID,
8278 					WPA2_PMKID_LEN, pmk_list->pmkids.pmkid[i].pmkid,
8279 					WPA2_PMKID_LEN);
8280 			pmkid_v1_list->npmkid++;
8281 		}
8282 		err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v1_list,
8283 				v1_list_size, cfg->ioctl_buf,
8284 				WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8285 		if (unlikely(err)) {
8286 			WL_ERR(("pmkid_info failed (%d)\n", err));
8287 		}
8288 
8289 		MFREE(cfg->osh, pmkid_v1_list, v1_list_size);
8290 	}
8291 	return err;
8292 }
8293 
8294 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8295  * entry operation.
8296  */
8297 static s32
wl_cfg80211_set_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8298 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
8299 	struct cfg80211_pmksa *pmksa)
8300 {
8301 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8302 	s32 err = 0;
8303 	int i;
8304 	int npmkids = cfg->pmk_list->pmkids.count;
8305 #ifdef BCMDONGLEHOST
8306 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
8307 #endif /* BCMDONGLEHOST */
8308 
8309 	if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) {
8310 		err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, TRUE);
8311 		if (err != BCME_OK) {
8312 			WL_ERR(("wl_cfg80211_set_pmksa err:%d\n", err));
8313 		}
8314 		return err;
8315 	}
8316 
8317 	RETURN_EIO_IF_NOT_UP(cfg);
8318 #ifdef BCMDONGLEHOST
8319 	BCM_REFERENCE(dhdp);
8320 	DHD_STATLOG_CTRL(dhdp, ST(INSTALL_PMKSA), dhd_net2idx(dhdp->info, dev), 0);
8321 #endif /* BCMDONGLEHOST */
8322 
8323 	for (i = 0; i < npmkids; i++) {
8324 		if (pmksa->bssid != NULL) {
8325 			if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8326 				ETHER_ADDR_LEN))
8327 				break;
8328 		}
8329 #ifdef WL_FILS
8330 		else if (pmksa->ssid != NULL) {
8331 			if (!memcmp(pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8332 				pmksa->ssid_len))
8333 				break;
8334 		}
8335 #endif /* WL_FILS */
8336 	}
8337 	if (i < WL_NUM_PMKIDS_MAX) {
8338 		if (pmksa->bssid != NULL) {
8339 			memcpy(&cfg->pmk_list->pmkids.pmkid[i].bssid, pmksa->bssid,
8340 				ETHER_ADDR_LEN);
8341 		}
8342 #ifdef WL_FILS
8343 		else if (pmksa->ssid != NULL) {
8344 			cfg->pmk_list->pmkids.pmkid[i].ssid_len = pmksa->ssid_len;
8345 			memcpy(&cfg->pmk_list->pmkids.pmkid[i].ssid, pmksa->ssid,
8346 				pmksa->ssid_len);
8347 			memcpy(&cfg->pmk_list->pmkids.pmkid[i].fils_cache_id, pmksa->cache_id,
8348 				FILS_CACHE_ID_LEN);
8349 		}
8350 #endif /* WL_FILS */
8351 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || \
8352 	defined(WL_FILS))
8353 		if (pmksa->pmk_len) {
8354 			if (memcpy_s(&cfg->pmk_list->pmkids.pmkid[i].pmk, PMK_LEN_MAX, pmksa->pmk,
8355 				pmksa->pmk_len)) {
8356 				WL_ERR(("invalid pmk len = %zu", pmksa->pmk_len));
8357 			} else {
8358 				cfg->pmk_list->pmkids.pmkid[i].pmk_len = pmksa->pmk_len;
8359 			}
8360 		}
8361 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS) */
8362 		/* return check not required as buffer lengths are same */
8363 		(void)memcpy_s(cfg->pmk_list->pmkids.pmkid[i].pmkid, WPA2_PMKID_LEN, pmksa->pmkid,
8364 			WPA2_PMKID_LEN);
8365 		cfg->pmk_list->pmkids.pmkid[i].pmkid_len = WPA2_PMKID_LEN;
8366 
8367 		/* set lifetime not to expire in firmware by default.
8368 		 * Currently, wpa_supplicant control PMKID lifetime on his end. e.g) set 12 hours
8369 		 * when it expired, wpa_supplicant should call set_pmksa/del_pmksa to update
8370 		 * corresponding entry.
8371 		 */
8372 		cfg->pmk_list->pmkids.pmkid[i].time_left = KEY_PERM_PMK;
8373 		if (i == npmkids) {
8374 			cfg->pmk_list->pmkids.length += sizeof(pmkid_v3_t);
8375 			cfg->pmk_list->pmkids.count++;
8376 		}
8377 	} else {
8378 		err = -EINVAL;
8379 	}
8380 
8381 #if (WL_DBG_LEVEL > 0)
8382 	if (pmksa->bssid != NULL) {
8383 		WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
8384 			&cfg->pmk_list->pmkids.pmkid[npmkids - 1].bssid));
8385 	}
8386 	for (i = 0; i < WPA2_PMKID_LEN; i++) {
8387 		WL_DBG(("%02x\n",
8388 			cfg->pmk_list->pmkids.pmkid[npmkids - 1].
8389 			pmkid[i]));
8390 	}
8391 #endif /* (WL_DBG_LEVEL > 0) */
8392 
8393 	err = wl_update_pmklist(dev, cfg->pmk_list, err);
8394 
8395 	return err;
8396 }
8397 
8398 /* sending pmkid_info IOVAR to manipulate PMKID(PMKSA) list in firmware.
8399  * input @pmksa: host given single pmksa info.
8400  * if it's NULL, assume whole list manipulated. e.g) flush all PMKIDs in firmware.
8401  * input @set: TRUE means adding PMKSA operation. FALSE means deleting.
8402  * return: log internal BCME_XXX error, and convert it to -EINVAL to linux generic error code.
8403  */
wl_cfg80211_update_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa,bool set)8404 static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
8405 	struct cfg80211_pmksa *pmksa, bool set) {
8406 
8407 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8408 	s32 err = 0;
8409 	pmkid_list_v3_t *pmk_list;
8410 	uint32 alloc_len;
8411 
8412 	RETURN_EIO_IF_NOT_UP(cfg);
8413 
8414 	if (cfg->wlc_ver.wlc_ver_major < MIN_PMKID_LIST_V3_FW_MAJOR) {
8415 		WL_DBG(("wlc_ver_major not supported:%d\n", cfg->wlc_ver.wlc_ver_major));
8416 		return BCME_VERSION;
8417 	}
8418 
8419 	alloc_len = (uint32)(OFFSETOF(pmkid_list_v3_t, pmkid) + ((pmksa) ? sizeof(pmkid_v3_t) : 0));
8420 	pmk_list = (pmkid_list_v3_t *)MALLOCZ(cfg->osh, alloc_len);
8421 
8422 	if (pmk_list == NULL) {
8423 		return BCME_NOMEM;
8424 	}
8425 
8426 	pmk_list->version = PMKID_LIST_VER_3;
8427 	pmk_list->length = alloc_len;
8428 	pmk_list->count = (pmksa) ? 1 : 0; // 1 means single entry operation, 0 means whole list.
8429 	pmk_list->flag = (set) ? PMKDB_SET_IOVAR : PMKDB_CLEAR_IOVAR;
8430 
8431 	if (pmksa) {
8432 		/* controll set/del action by lifetime parameter accordingly.
8433 		 * if set == TRUE, it's set PMKID action with lifetime permanent.
8434 		 * if set == FALSE, it's del PMKID action with lifetime zero.
8435 		 */
8436 		pmk_list->pmkid->time_left = (set) ? KEY_PERM_PMK : 0;
8437 		if (pmksa->bssid) {
8438 			eacopy(pmksa->bssid, &pmk_list->pmkid->bssid);
8439 		}
8440 		if (pmksa->pmkid) {
8441 			err = memcpy_s(&pmk_list->pmkid->pmkid, sizeof(pmk_list->pmkid->pmkid),
8442 				pmksa->pmkid, WPA2_PMKID_LEN);
8443 			if (err) {
8444 				goto exit;
8445 			}
8446 			pmk_list->pmkid->pmkid_len = WPA2_PMKID_LEN;
8447 		}
8448 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
8449 		if (pmksa->pmk) {
8450 			err = memcpy_s(&pmk_list->pmkid->pmk, sizeof(pmk_list->pmkid->pmk),
8451 				pmksa->pmk, pmksa->pmk_len);
8452 			if (err) {
8453 				goto exit;
8454 			}
8455 			pmk_list->pmkid->pmk_len = pmksa->pmk_len;
8456 		}
8457 		if (pmksa->ssid) {
8458 			err = memcpy_s(&pmk_list->pmkid->ssid, sizeof(pmk_list->pmkid->ssid),
8459 				pmksa->ssid, pmksa->ssid_len);
8460 			if (err) {
8461 				goto exit;
8462 			}
8463 			pmk_list->pmkid->ssid_len = pmksa->ssid_len;
8464 		}
8465 		if (pmksa->cache_id) {
8466 			/* supplicant passes data received on air as is(network order).
8467 			 * convert it before using.
8468 			 */
8469 			pmk_list->pmkid->fils_cache_id = ntoh16(*(const uint16 *)pmksa->cache_id);
8470 		}
8471 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
8472 		wl_cfg80211_spmk_pmkdb_change_pmk_type(cfg, pmk_list);
8473 	}
8474 
8475 	if (wl_dbg_level & WL_DBG_DBG) {
8476 		prhex("pmklist_data", (char *)pmk_list, alloc_len);
8477 	}
8478 
8479 	err = wldev_iovar_setbuf(dev, "pmkdb", (char *)pmk_list,
8480 		alloc_len, cfg->ioctl_buf,
8481 		WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8482 	if (unlikely(err)) {
8483 		WL_ERR(("pmkdb set failed. err:%d\n", err));
8484 	}
8485 exit:
8486 	if (pmk_list) {
8487 		MFREE(cfg->osh, pmk_list, alloc_len);
8488 	}
8489 	return err;
8490 }
8491 
8492 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8493  * entry operation.
8494  */
8495 static s32
wl_cfg80211_del_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8496 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
8497 	struct cfg80211_pmksa *pmksa)
8498 {
8499 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8500 	s32 err = 0;
8501 	int i;
8502 	int npmkids = cfg->pmk_list->pmkids.count;
8503 	RETURN_EIO_IF_NOT_UP(cfg);
8504 
8505 	if (!pmksa) {
8506 		WL_ERR(("pmksa is not initialized\n"));
8507 		return BCME_ERROR;
8508 	}
8509 	if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) {
8510 		err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
8511 		if (err != BCME_OK) {
8512 			WL_ERR(("wl_cfg80211_del_pmksa err:%d\n", err));
8513 		}
8514 		wl_cfg80211_spmk_pmkdb_del_spmk(cfg, pmksa);
8515 		return err;
8516 	}
8517 
8518 	if (!npmkids) {
8519 		/* nmpkids = 0, nothing to delete */
8520 		WL_DBG(("npmkids=0. Skip del\n"));
8521 		return BCME_OK;
8522 	}
8523 
8524 #if (WL_DBG_LEVEL > 0)
8525 	if (pmksa->bssid) {
8526 		WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
8527 			pmksa->bssid));
8528 	}
8529 #ifdef WL_FILS
8530 	else if (pmksa->ssid) {
8531 		WL_DBG(("FILS: del_pmksa for ssid: "));
8532 		for (i = 0; i < pmksa->ssid_len; i++) {
8533 			WL_DBG(("%c", pmksa->ssid[i]));
8534 		}
8535 		WL_DBG(("\n"));
8536 	}
8537 #endif /* WL_FILS */
8538 	if (pmksa->pmkid) {
8539 		for (i = 0; i < WPA2_PMKID_LEN; i++) {
8540 			WL_DBG(("%02x\n", pmksa->pmkid[i]));
8541 		}
8542 	}
8543 #endif /* (WL_DBG_LEVEL > 0) */
8544 
8545 	for (i = 0; i < npmkids; i++) {
8546 		if (pmksa->bssid) {
8547 			if (!memcmp
8548 			    (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8549 			     ETHER_ADDR_LEN)) {
8550 					break;
8551 			}
8552 		}
8553 #ifdef WL_FILS
8554 		else if (pmksa->ssid) {
8555 			if (!memcmp
8556 			    (pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8557 			     pmksa->ssid_len)) {
8558 					break;
8559 			}
8560 		}
8561 #endif /* WL_FILS */
8562 	}
8563 	if ((npmkids > 0) && (i < npmkids)) {
8564 		bzero(&cfg->pmk_list->pmkids.pmkid[i], sizeof(pmkid_v3_t));
8565 		for (; i < (npmkids - 1); i++) {
8566 			(void)memcpy_s(&cfg->pmk_list->pmkids.pmkid[i],
8567 				sizeof(pmkid_v3_t),
8568 				&cfg->pmk_list->pmkids.pmkid[i + 1],
8569 				sizeof(pmkid_v3_t));
8570 		}
8571 		npmkids--;
8572 		cfg->pmk_list->pmkids.length -= sizeof(pmkid_v3_t);
8573 		cfg->pmk_list->pmkids.count--;
8574 
8575 	} else {
8576 		err = -EINVAL;
8577 	}
8578 
8579 	/* current wl_update_pmklist() doesn't delete corresponding PMKID entry.
8580 	 * inside firmware. So we need to issue delete action explicitely through
8581 	 * this function.
8582 	 */
8583 	err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
8584 	/* intentional fall through even on error.
8585 	 * it should work above MIN_PMKID_LIST_V3_FW_MAJOR, otherwise let ignore it.
8586 	 */
8587 
8588 	err = wl_update_pmklist(dev, cfg->pmk_list, err);
8589 
8590 	return err;
8591 
8592 }
8593 
8594 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8595  * entry operation.
8596  */
8597 static s32
wl_cfg80211_flush_pmksa(struct wiphy * wiphy,struct net_device * dev)8598 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
8599 {
8600 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8601 	s32 err = 0;
8602 	RETURN_EIO_IF_NOT_UP(cfg);
8603 	if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) {
8604 		/* NULL pmksa means delete whole PMKSA list */
8605 		err = wl_cfg80211_update_pmksa(wiphy, dev, NULL, FALSE);
8606 		if (err != BCME_OK) {
8607 			WL_ERR(("wl_cfg80211_flush_pmksa err:%d\n", err));
8608 		}
8609 		return err;
8610 	}
8611 	bzero(cfg->pmk_list, sizeof(*cfg->pmk_list));
8612 	cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
8613 	cfg->pmk_list->pmkids.count = 0;
8614 	cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
8615 	err = wl_update_pmklist(dev, cfg->pmk_list, err);
8616 	return err;
8617 }
8618 
8619 static void
wl_cfg80211_afx_handler(struct work_struct * work)8620 wl_cfg80211_afx_handler(struct work_struct *work)
8621 {
8622 	struct afx_hdl *afx_instance;
8623 	struct bcm_cfg80211 *cfg;
8624 	s32 ret = BCME_OK;
8625 
8626 	BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
8627 	if (afx_instance) {
8628 		cfg = wl_get_cfg(afx_instance->dev);
8629 		if (cfg != NULL && cfg->afx_hdl->is_active) {
8630 			if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
8631 				ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
8632 					(100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
8633 			} else {
8634 				ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
8635 					cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
8636 					NULL);
8637 			}
8638 			if (unlikely(ret != BCME_OK)) {
8639 				WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
8640 				if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
8641 					complete(&cfg->act_frm_scan);
8642 			}
8643 		}
8644 	}
8645 }
8646 
8647 static s32
wl_cfg80211_af_searching_channel(struct bcm_cfg80211 * cfg,struct net_device * dev)8648 wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
8649 {
8650 	u32 max_retry = WL_CHANNEL_SYNC_RETRY;
8651 	bool is_p2p_gas = false;
8652 
8653 	if (dev == NULL)
8654 		return -1;
8655 
8656 	WL_DBG((" enter ) \n"));
8657 
8658 	wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8659 	cfg->afx_hdl->is_active = TRUE;
8660 
8661 	if (cfg->afx_hdl->pending_tx_act_frm) {
8662 		wl_action_frame_t *action_frame;
8663 		action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
8664 		if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len))
8665 			is_p2p_gas = true;
8666 	}
8667 
8668 	/* Loop to wait until we find a peer's channel or the
8669 	 * pending action frame tx is cancelled.
8670 	 */
8671 	while ((cfg->afx_hdl->retry < max_retry) &&
8672 		(cfg->afx_hdl->peer_chan == WL_INVALID)) {
8673 		cfg->afx_hdl->is_listen = FALSE;
8674 		wl_set_drv_status(cfg, SCANNING, dev);
8675 		WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
8676 			cfg->afx_hdl->retry));
8677 		/* search peer on peer's listen channel */
8678 		schedule_work(&cfg->afx_hdl->work);
8679 		wait_for_completion_timeout(&cfg->act_frm_scan,
8680 			msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8681 
8682 		if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8683 			!(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8684 			break;
8685 
8686 		if (is_p2p_gas)
8687 			break;
8688 
8689 		if (cfg->afx_hdl->my_listen_chan) {
8690 			WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
8691 				cfg->afx_hdl->my_listen_chan));
8692 			/* listen on my listen channel */
8693 			cfg->afx_hdl->is_listen = TRUE;
8694 			schedule_work(&cfg->afx_hdl->work);
8695 			wait_for_completion_timeout(&cfg->act_frm_scan,
8696 				msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8697 		}
8698 		if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8699 			!(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8700 			break;
8701 
8702 		cfg->afx_hdl->retry++;
8703 
8704 		WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
8705 	}
8706 
8707 	cfg->afx_hdl->is_active = FALSE;
8708 
8709 	wl_clr_drv_status(cfg, SCANNING, dev);
8710 	wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8711 
8712 	return (cfg->afx_hdl->peer_chan);
8713 }
8714 
8715 struct p2p_config_af_params {
8716 	s32 max_tx_retry;	/* max tx retry count if tx no ack */
8717 #ifdef WL_CFG80211_GON_COLLISION
8718 	/* drop tx go nego request if go nego collision occurs */
8719 	bool drop_tx_req;
8720 #endif
8721 #ifdef WL_CFG80211_SYNC_GON
8722 	/* WAR: dongle does not keep the dwell time of 'actframe' sometime.
8723 	 * if extra_listen is set, keep the dwell time to get af response frame
8724 	 */
8725 	bool extra_listen;
8726 #endif
8727 	bool search_channel;	/* 1: search peer's channel to send af */
8728 };
8729 
8730 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)8731 wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
8732 	wl_action_frame_t *action_frame, wl_af_params_t *af_params,
8733 	struct p2p_config_af_params *config_af_params)
8734 {
8735 	s32 err = BCME_OK;
8736 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8737 	wifi_p2p_pub_act_frame_t *act_frm =
8738 		(wifi_p2p_pub_act_frame_t *) (action_frame->data);
8739 
8740 	/* initialize default value */
8741 #ifdef WL_CFG80211_GON_COLLISION
8742 	config_af_params->drop_tx_req = false;
8743 #endif
8744 #ifdef WL_CFG80211_SYNC_GON
8745 	config_af_params->extra_listen = true;
8746 #endif
8747 	config_af_params->search_channel = false;
8748 	config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
8749 	cfg->next_af_subtype = WL_PUB_AF_STYPE_INVALID;
8750 
8751 	switch (act_frm->subtype) {
8752 	case P2P_PAF_GON_REQ: {
8753 		/* Disable he if peer does not support before starting GONEG */
8754 		WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
8755 		wl_set_p2p_status(cfg, GO_NEG_PHASE);
8756 
8757 		config_af_params->search_channel = true;
8758 		cfg->next_af_subtype = act_frm->subtype + 1;
8759 
8760 		/* increase dwell time to wait for RESP frame */
8761 		af_params->dwell_time = WL_MED_DWELL_TIME;
8762 
8763 #ifdef WL_CFG80211_GON_COLLISION
8764 		config_af_params->drop_tx_req = true;
8765 #endif /* WL_CFG80211_GON_COLLISION */
8766 		break;
8767 	}
8768 	case P2P_PAF_GON_RSP: {
8769 		cfg->next_af_subtype = act_frm->subtype + 1;
8770 		/* increase dwell time to wait for CONF frame */
8771 		/* WAR : 100ms is added because kernel spent more time in some case.
8772 		 *              Kernel should be fixed.
8773 		 */
8774 		af_params->dwell_time = WL_MED_DWELL_TIME + 100;
8775 		break;
8776 	}
8777 	case P2P_PAF_GON_CONF: {
8778 		/* If we reached till GO Neg confirmation reset the filter */
8779 		WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
8780 		wl_clr_p2p_status(cfg, GO_NEG_PHASE);
8781 
8782 		/* minimize dwell time */
8783 		af_params->dwell_time = WL_MIN_DWELL_TIME;
8784 
8785 #ifdef WL_CFG80211_GON_COLLISION
8786 		/* if go nego formation done, clear it */
8787 		cfg->block_gon_req_tx_count = 0;
8788 		cfg->block_gon_req_rx_count = 0;
8789 #endif /* WL_CFG80211_GON_COLLISION */
8790 #ifdef WL_CFG80211_SYNC_GON
8791 		config_af_params->extra_listen = false;
8792 #endif /* WL_CFG80211_SYNC_GON */
8793 		break;
8794 	}
8795 	case P2P_PAF_INVITE_REQ: {
8796 		config_af_params->search_channel = true;
8797 		cfg->next_af_subtype = act_frm->subtype + 1;
8798 
8799 		/* increase dwell time */
8800 		af_params->dwell_time = WL_MED_DWELL_TIME;
8801 		break;
8802 	}
8803 	case P2P_PAF_INVITE_RSP:
8804 		/* minimize dwell time */
8805 		af_params->dwell_time = WL_MIN_DWELL_TIME;
8806 #ifdef WL_CFG80211_SYNC_GON
8807 		config_af_params->extra_listen = false;
8808 #endif /* WL_CFG80211_SYNC_GON */
8809 		break;
8810 	case P2P_PAF_DEVDIS_REQ: {
8811 		if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
8812 			action_frame->len)) {
8813 			config_af_params->search_channel = true;
8814 		}
8815 
8816 		cfg->next_af_subtype = act_frm->subtype + 1;
8817 		/* maximize dwell time to wait for RESP frame */
8818 		af_params->dwell_time = WL_LONG_DWELL_TIME;
8819 		break;
8820 	}
8821 	case P2P_PAF_DEVDIS_RSP:
8822 		/* minimize dwell time */
8823 		af_params->dwell_time = WL_MIN_DWELL_TIME;
8824 #ifdef WL_CFG80211_SYNC_GON
8825 		config_af_params->extra_listen = false;
8826 #endif /* WL_CFG80211_SYNC_GON */
8827 		break;
8828 	case P2P_PAF_PROVDIS_REQ: {
8829 		if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
8830 			action_frame->len)) {
8831 			config_af_params->search_channel = true;
8832 		}
8833 
8834 		cfg->next_af_subtype = act_frm->subtype + 1;
8835 		/* increase dwell time to wait for RESP frame */
8836 		af_params->dwell_time = WL_MED_DWELL_TIME;
8837 		break;
8838 	}
8839 	case P2P_PAF_PROVDIS_RSP: {
8840 		/* wpa_supplicant send go nego req right after prov disc */
8841 		cfg->next_af_subtype = P2P_PAF_GON_REQ;
8842 		af_params->dwell_time = WL_MED_DWELL_TIME;
8843 #ifdef WL_CFG80211_SYNC_GON
8844 		config_af_params->extra_listen = false;
8845 #endif /* WL_CFG80211_SYNC_GON */
8846 		break;
8847 	}
8848 	default:
8849 		WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
8850 			act_frm->subtype));
8851 		err = BCME_BADARG;
8852 	}
8853 	return err;
8854 }
8855 
8856 #if defined(WL11U) && defined(WL_HOST_AF_DFS_CHECK)
8857 static bool
wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 * cfg,wl_af_params_t * af_params,void * frame,u16 frame_len)8858 wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params,
8859 	void *frame, u16 frame_len)
8860 {
8861 	wl_scan_results *bss_list;
8862 	wl_bss_info_t *bi = NULL;
8863 	bool result = false;
8864 	s32 i;
8865 	chanspec_t chanspec;
8866 
8867 	/* If DFS channel is 52~148, check to block it or not */
8868 	if (af_params &&
8869 		(af_params->channel >= 52 && af_params->channel <= 148)) {
8870 		if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
8871 			bss_list = cfg->bss_list;
8872 			bi = next_bss(bss_list, bi);
8873 			for_each_bss(bss_list, bi, i) {
8874 				chanspec = wl_chspec_driver_to_host(bi->chanspec);
8875 				if (CHSPEC_IS5G(chanspec) &&
8876 					((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec))
8877 					== af_params->channel)) {
8878 					result = true;	/* do not block the action frame */
8879 					break;
8880 				}
8881 			}
8882 		}
8883 	}
8884 	else {
8885 		result = true;
8886 	}
8887 
8888 	WL_DBG(("result=%s", result?"true":"false"));
8889 	return result;
8890 }
8891 #endif /* WL11U && WL_HOST_AF_DFS_CHECK */
8892 static bool
wl_cfg80211_check_dwell_overflow(int32 requested_dwell,ulong dwell_jiffies)8893 wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies)
8894 {
8895 	if ((requested_dwell & CUSTOM_RETRY_MASK) &&
8896 			(jiffies_to_msecs(jiffies - dwell_jiffies) >
8897 			 (requested_dwell & ~CUSTOM_RETRY_MASK))) {
8898 		WL_ERR(("Action frame TX retry time over dwell time!\n"));
8899 		return true;
8900 	}
8901 	return false;
8902 }
8903 
8904 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)8905 wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
8906 	bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
8907 	wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
8908 {
8909 #ifdef WL11U
8910 	struct net_device *ndev = NULL;
8911 #endif /* WL11U */
8912 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8913 	bool ack = false;
8914 	u8 category, action;
8915 	s32 tx_retry;
8916 	struct p2p_config_af_params config_af_params;
8917 	struct net_info *netinfo;
8918 #ifdef VSDB
8919 	ulong off_chan_started_jiffies = 0;
8920 #endif
8921 	ulong dwell_jiffies = 0;
8922 	bool dwell_overflow = false;
8923 #ifdef BCMDONGLEHOST
8924 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
8925 #endif /* BCMDONGLEHOST */
8926 
8927 	int32 requested_dwell = af_params->dwell_time;
8928 
8929 	/* Add the default dwell time
8930 	 * Dwell time to stay off-channel to wait for a response action frame
8931 	 * after transmitting an GO Negotiation action frame
8932 	 */
8933 	af_params->dwell_time = WL_DEFAULT_DWELL_TIME;
8934 
8935 #ifdef WL11U
8936 #if defined(WL_CFG80211_P2P_DEV_IF)
8937 	ndev = dev;
8938 #else
8939 	ndev = ndev_to_cfgdev(cfgdev);
8940 #endif /* WL_CFG80211_P2P_DEV_IF */
8941 #endif /* WL11U */
8942 
8943 	category = action_frame->data[DOT11_ACTION_CAT_OFF];
8944 	action = action_frame->data[DOT11_ACTION_ACT_OFF];
8945 
8946 	/* initialize variables */
8947 	tx_retry = 0;
8948 	cfg->next_af_subtype = WL_PUB_AF_STYPE_INVALID;
8949 	config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
8950 	config_af_params.search_channel = false;
8951 #ifdef WL_CFG80211_GON_COLLISION
8952 	config_af_params.drop_tx_req = false;
8953 #endif
8954 #ifdef WL_CFG80211_SYNC_GON
8955 	config_af_params.extra_listen = false;
8956 #endif
8957 
8958 	/* config parameters */
8959 	/* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
8960 	if (category == DOT11_ACTION_CAT_PUBLIC) {
8961 		if (wl_cfg80211_is_dpp_frame((void *)action_frame->data, action_frame->len)) {
8962 			wl_dpp_pa_frame_t *pa = (wl_dpp_pa_frame_t *)action_frame->data;
8963 			config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
8964 			af_params->dwell_time = WL_MED_DWELL_TIME;
8965 			cfg->need_wait_afrx = true;
8966 			/* once matching frame is found in rx, abort dwell (upper layer
8967 			 * doesn't do that).
8968 			 */
8969 			if (pa->ftype == DPP_AUTH_REQ) {
8970 				cfg->next_af_subtype = DPP_AUTH_RESP;
8971 			} else if (pa->ftype == DPP_AUTH_RESP) {
8972 				cfg->next_af_subtype = DPP_AUTH_CONF;
8973 			} else {
8974 				cfg->next_af_subtype = WL_PUB_AF_STYPE_INVALID;
8975 				cfg->need_wait_afrx = false;
8976 			}
8977 		} else if (wl_cfg80211_is_dpp_gas_action(
8978 				(void *)action_frame->data, action_frame->len)) {
8979 			config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
8980 			af_params->dwell_time = WL_MED_DWELL_TIME;
8981 			cfg->need_wait_afrx = true;
8982 			config_af_params.search_channel = false;
8983 
8984 			if (requested_dwell == 0) {
8985 				/* Use minimal dwell to take care of Ack */
8986 				af_params->dwell_time = WL_MIN_DWELL_TIME;
8987 			}
8988 		} else if ((action == P2P_PUB_AF_ACTION) &&
8989 			(action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
8990 			/* p2p public action frame process */
8991 			if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy,
8992 				action_frame, af_params, &config_af_params)) {
8993 				/* just send unknown subtype frame with default parameters. */
8994 				WL_DBG(("Unknown subtype.\n"));
8995 			}
8996 
8997 #ifdef WL_CFG80211_GON_COLLISION
8998 			if (config_af_params.drop_tx_req) {
8999 				if (cfg->block_gon_req_tx_count) {
9000 					/* drop gon req tx action frame */
9001 					WL_DBG(("Drop gon req tx action frame: count %d\n",
9002 						cfg->block_gon_req_tx_count));
9003 					goto exit;
9004 				}
9005 			}
9006 #endif /* WL_CFG80211_GON_COLLISION */
9007 		} else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
9008 			/* service discovery process */
9009 			if (action == P2PSD_ACTION_ID_GAS_IREQ ||
9010 				action == P2PSD_ACTION_ID_GAS_CREQ) {
9011 				/* configure service discovery query frame */
9012 				config_af_params.search_channel = true;
9013 
9014 				/* save next af suptype to cancel remained dwell time */
9015 				cfg->next_af_subtype = action + 1;
9016 
9017 				af_params->dwell_time = WL_MED_DWELL_TIME;
9018 				if (requested_dwell & CUSTOM_RETRY_MASK) {
9019 					config_af_params.max_tx_retry =
9020 						(requested_dwell & CUSTOM_RETRY_MASK) >> 24;
9021 					af_params->dwell_time =
9022 						(requested_dwell & ~CUSTOM_RETRY_MASK);
9023 					WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
9024 						config_af_params.max_tx_retry,
9025 						af_params->dwell_time));
9026 				}
9027 			} else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
9028 				action == P2PSD_ACTION_ID_GAS_CRESP) {
9029 				/* configure service discovery response frame */
9030 				af_params->dwell_time = WL_MIN_DWELL_TIME;
9031 			} else {
9032 				WL_DBG(("Unknown action type: %d\n", action));
9033 			}
9034 		} else {
9035 			WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
9036 				category, action, action_frame_len));
9037 		}
9038 	} else if (category == P2P_AF_CATEGORY) {
9039 		/* do not configure anything. it will be sent with a default configuration */
9040 	} else {
9041 		WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
9042 			category, action));
9043 #ifdef BCMDONGLEHOST
9044 		if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
9045 			wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9046 			return false;
9047 		}
9048 #endif /* BCMDONGLEHOST */
9049 	}
9050 
9051 	netinfo = wl_get_netinfo_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
9052 	/* validate channel and p2p ies */
9053 	if (config_af_params.search_channel &&
9054 		IS_P2P_SOCIAL(CHSPEC_CHANNEL(af_params->channel)) &&
9055 		netinfo && netinfo->bss.ies.probe_req_ie_len) {
9056 		config_af_params.search_channel = true;
9057 	} else {
9058 		config_af_params.search_channel = false;
9059 	}
9060 #ifdef WL11U
9061 	if (ndev == bcmcfg_to_prmry_ndev(cfg))
9062 		config_af_params.search_channel = false;
9063 #endif /* WL11U */
9064 
9065 #ifdef VSDB
9066 	/* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
9067 	if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
9068 		OSL_SLEEP(50);
9069 	}
9070 #endif
9071 
9072 	/* if scan is ongoing, abort current scan. */
9073 	if (wl_get_drv_status_all(cfg, SCANNING)) {
9074 		wl_cfgscan_cancel_scan(cfg);
9075 	}
9076 
9077 	/* Abort P2P listen */
9078 	if (discover_cfgdev(cfgdev, cfg)) {
9079 		if (cfg->p2p_supported && cfg->p2p) {
9080 			wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
9081 				wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
9082 		}
9083 	}
9084 
9085 #if defined(WL11U) && defined(WL_HOST_AF_DFS_CHECK)
9086 	/* handling DFS channel exceptions */
9087 	if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) {
9088 		return false;	/* the action frame was blocked */
9089 	}
9090 #endif /* WL11U && WL_HOST_AF_DFS_CHECK */
9091 
9092 	/* set status and destination address before sending af */
9093 	if (cfg->next_af_subtype != WL_PUB_AF_STYPE_INVALID) {
9094 		/* set this status to cancel the remained dwell time in rx process */
9095 		wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9096 	}
9097 	wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
9098 	memcpy(cfg->afx_hdl->tx_dst_addr.octet,
9099 		af_params->action_frame.da.octet,
9100 		sizeof(cfg->afx_hdl->tx_dst_addr.octet));
9101 
9102 	/* save af_params for rx process */
9103 	cfg->afx_hdl->pending_tx_act_frm = af_params;
9104 
9105 	if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
9106 		WL_DBG(("Set GAS action frame config.\n"));
9107 		config_af_params.search_channel = false;
9108 		config_af_params.max_tx_retry = 1;
9109 	}
9110 
9111 	/* search peer's channel */
9112 	if (config_af_params.search_channel) {
9113 		/* initialize afx_hdl */
9114 		if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
9115 			WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
9116 			goto exit;
9117 		}
9118 		cfg->afx_hdl->dev = dev;
9119 		cfg->afx_hdl->retry = 0;
9120 		cfg->afx_hdl->peer_chan = WL_INVALID;
9121 
9122 		if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
9123 			WL_ERR(("couldn't find peer's channel.\n"));
9124 			wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
9125 				af_params->channel);
9126 			/* Even if we couldn't find peer channel, try to send the frame
9127 			 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
9128 			 * respond to probe request (Ideally it has to be in listen and
9129 			 * responsd to probe request). However if we send Go neg req, the
9130 			 * peer is sending GO-neg resp. So instead of giving up here, just
9131 			 * proceed and attempt sending out the action frame.
9132 			 */
9133 		}
9134 
9135 		wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
9136 		/*
9137 		 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
9138 		 * but after the check of piggyback algorithm.
9139 		 * To take care of current piggback algo, lets abort the scan here itself.
9140 		 */
9141 		wl_cfgscan_cancel_scan(cfg);
9142 		/* Suspend P2P discovery's search-listen to prevent it from
9143 		 * starting a scan or changing the channel.
9144 		 */
9145 		if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9146 			WL_ERR(("Can not disable discovery mode\n"));
9147 			goto exit;
9148 		}
9149 
9150 		/* update channel */
9151 		if (cfg->afx_hdl->peer_chan != WL_INVALID) {
9152 			af_params->channel = cfg->afx_hdl->peer_chan;
9153 			WL_ERR(("Attempt tx on peer listen channel:%d\n",
9154 				cfg->afx_hdl->peer_chan));
9155 		} else {
9156 			WL_ERR(("Attempt tx with the channel provided by userspace."
9157 			"Channel: %d\n", CHSPEC_CHANNEL(af_params->channel)));
9158 		}
9159 	}
9160 
9161 #ifdef VSDB
9162 	off_chan_started_jiffies = jiffies;
9163 #endif /* VSDB */
9164 
9165 	wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel);
9166 
9167 	wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
9168 
9169 	dwell_jiffies = jiffies;
9170 	/* Now send a tx action frame */
9171 	ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
9172 	dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9173 
9174 	/* if failed, retry it. tx_retry_max value is configure by .... */
9175 	while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry) &&
9176 			!dwell_overflow) {
9177 #ifdef VSDB
9178 		if (af_params->channel) {
9179 			if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
9180 				OFF_CHAN_TIME_THRESHOLD_MS) {
9181 				WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
9182 				off_chan_started_jiffies = jiffies;
9183 			} else
9184 				OSL_SLEEP(AF_RETRY_DELAY_TIME);
9185 		}
9186 #endif /* VSDB */
9187 		ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
9188 			false : true;
9189 		dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9190 	}
9191 
9192 	if (ack == false) {
9193 		WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
9194 	}
9195 	WL_DBG(("Complete to send action frame\n"));
9196 exit:
9197 	/* Clear SENDING_ACT_FRM after all sending af is done */
9198 	wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9199 
9200 #ifdef WL_CFG80211_SYNC_GON
9201 	/* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
9202 	 * if we coundn't get the next action response frame and dongle does not keep
9203 	 * the dwell time, go to listen state again to get next action response frame.
9204 	 */
9205 	if (ack && config_af_params.extra_listen &&
9206 #ifdef WL_CFG80211_GON_COLLISION
9207 		!cfg->block_gon_req_tx_count &&
9208 #endif /* WL_CFG80211_GON_COLLISION */
9209 		wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
9210 		cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
9211 		s32 extar_listen_time;
9212 
9213 		extar_listen_time = af_params->dwell_time -
9214 			jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
9215 
9216 		if (extar_listen_time > 50) {
9217 			wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9218 			WL_DBG(("Wait more time! actual af time:%d,"
9219 				"calculated extar listen:%d\n",
9220 				af_params->dwell_time, extar_listen_time));
9221 			if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
9222 				extar_listen_time + 100) == BCME_OK) {
9223 				wait_for_completion_timeout(&cfg->wait_next_af,
9224 					msecs_to_jiffies(extar_listen_time + 100 + 300));
9225 			}
9226 			wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9227 		}
9228 	}
9229 #endif /* WL_CFG80211_SYNC_GON */
9230 	wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9231 
9232 	cfg->afx_hdl->pending_tx_act_frm = NULL;
9233 
9234 	if (ack) {
9235 		WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
9236 			cfg->afx_hdl->my_listen_chan));
9237 	} else {
9238 		WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
9239 			cfg->afx_hdl->my_listen_chan));
9240 	}
9241 
9242 #ifdef WL_CFG80211_GON_COLLISION
9243 	if (cfg->block_gon_req_tx_count) {
9244 		cfg->block_gon_req_tx_count--;
9245 		/* if ack is ture, supplicant will wait more time(100ms).
9246 		 * so we will return it as a success to get more time .
9247 		 */
9248 		ack = true;
9249 	}
9250 #endif /* WL_CFG80211_GON_COLLISION */
9251 	return ack;
9252 }
9253 
9254 #define MAX_NUM_OF_ASSOCIATED_DEV       64
9255 static s32
9256 #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)9257 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9258 	struct cfg80211_mgmt_tx_params *params, u64 *cookie)
9259 #else
9260 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9261 	struct ieee80211_channel *channel, bool offchan,
9262 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
9263 	enum nl80211_channel_type channel_type,
9264 	bool channel_type_valid,
9265 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
9266 	unsigned int wait, const u8* buf, size_t len,
9267 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || \
9268 	defined(WL_COMPAT_WIRELESS)
9269 	bool no_cck,
9270 #endif
9271 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
9272 	defined(WL_COMPAT_WIRELESS)
9273 	bool dont_wait_for_ack,
9274 #endif
9275 	u64 *cookie)
9276 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9277 {
9278 	wl_action_frame_t *action_frame;
9279 	wl_af_params_t *af_params;
9280 	scb_val_t scb_val;
9281 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9282 	struct ieee80211_channel *channel = params->chan;
9283 	const u8 *buf = params->buf;
9284 	size_t len = params->len;
9285 #endif
9286 	const struct ieee80211_mgmt *mgmt;
9287 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9288 	struct net_device *dev = NULL;
9289 	s32 err = BCME_OK;
9290 	s32 bssidx = 0;
9291 	u32 id;
9292 	bool ack = false;
9293 	s8 eabuf[ETHER_ADDR_STR_LEN];
9294 
9295 	WL_DBG(("Enter \n"));
9296 
9297 	if (len > ACTION_FRAME_SIZE) {
9298 		WL_ERR(("bad length:%zu\n", len));
9299 		return BCME_BADLEN;
9300 	}
9301 
9302 #ifdef DHD_IFDEBUG
9303 	PRINT_WDEV_INFO(cfgdev);
9304 #endif /* DHD_IFDEBUG */
9305 
9306 	dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
9307 
9308 	if (!dev) {
9309 		WL_ERR(("dev is NULL\n"));
9310 		return -EINVAL;
9311 	}
9312 
9313 	/* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE)	*/
9314 	if (discover_cfgdev(cfgdev, cfg)) {
9315 		if (!cfg->p2p_supported || !cfg->p2p) {
9316 			WL_ERR(("P2P doesn't setup completed yet\n"));
9317 			return -EINVAL;
9318 		}
9319 		bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9320 	}
9321 	else {
9322 		if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
9323 			WL_ERR(("Failed to find bssidx\n"));
9324 			return BCME_ERROR;
9325 		}
9326 	}
9327 
9328 	WL_DBG(("TX target bssidx=%d\n", bssidx));
9329 
9330 	if (p2p_is_on(cfg)) {
9331 		/* Suspend P2P discovery search-listen to prevent it from changing the
9332 		 * channel.
9333 		 */
9334 		if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9335 			WL_ERR(("Can not disable discovery mode\n"));
9336 			return -EFAULT;
9337 		}
9338 	}
9339 	*cookie = 0;
9340 	id = cfg->send_action_id++;
9341 	if (id == 0)
9342 		id = cfg->send_action_id++;
9343 	*cookie = id;
9344 	mgmt = (const struct ieee80211_mgmt *)buf;
9345 	if (ieee80211_is_mgmt(mgmt->frame_control)) {
9346 		if (ieee80211_is_probe_resp(mgmt->frame_control)) {
9347 			s32 ie_offset =  DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
9348 			s32 ie_len = len - ie_offset;
9349 			if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9350 				bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9351 			}
9352 			wl_cfg80211_set_mgmt_vndr_ies(cfg, cfgdev, bssidx,
9353 				VNDR_IE_PRBRSP_FLAG, (const u8 *)(buf + ie_offset), ie_len);
9354 			cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9355 #if defined(P2P_IE_MISSING_FIX)
9356 			if (!cfg->p2p_prb_noti) {
9357 				cfg->p2p_prb_noti = true;
9358 				WL_DBG(("wl_cfg80211_mgmt_tx: TX 802_1X Probe"
9359 					" Response first time.\n"));
9360 			}
9361 #endif
9362 			goto exit;
9363 		} else if (ieee80211_is_disassoc(mgmt->frame_control) ||
9364 			ieee80211_is_deauth(mgmt->frame_control)) {
9365 			char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
9366 				sizeof(struct ether_addr) + sizeof(uint)] = {0};
9367 			int num_associated = 0;
9368 			struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9369 			if (!bcmp((const uint8 *)BSSID_BROADCAST,
9370 				(const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
9371 				assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9372 				err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST,
9373 					assoc_maclist, sizeof(mac_buf));
9374 				if (err < 0)
9375 					WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9376 				else
9377 					num_associated = assoc_maclist->count;
9378 			}
9379 			memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
9380 			scb_val.val = mgmt->u.disassoc.reason_code;
9381 			err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
9382 				sizeof(scb_val_t));
9383 			if (err < 0)
9384 				WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
9385 			WL_ERR(("Disconnect STA : " MACDBG " scb_val.val %d\n",
9386 				MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mgmt->da,
9387 				eabuf)), scb_val.val));
9388 
9389 			/* WAR Wait for the deauth event to come,
9390 			 * supplicant will do the delete iface immediately
9391 			 * and we will have problem in sending
9392 			 * deauth frame if we delete the bss in firmware.
9393 			 * But we do not need additional delays for this WAR
9394 			 * during P2P connection.
9395 			 *
9396 			 * Supplicant call this function with BCAST after
9397 			 * delete all GC stations with each addr.
9398 			 * So, 400 ms delay can be called only once when GO disconnect all GC
9399 			*/
9400 			if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
9401 				wl_delay(400);
9402 
9403 			cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9404 			goto exit;
9405 
9406 		} else if (ieee80211_is_action(mgmt->frame_control)) {
9407 			/* Abort the dwell time of any previous off-channel
9408 			* action frame that may be still in effect.  Sending
9409 			* off-channel action frames relies on the driver's
9410 			* scan engine.  If a previous off-channel action frame
9411 			* tx is still in progress (including the dwell time),
9412 			* then this new action frame will not be sent out.
9413 			*/
9414 /* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
9415  * And previous off-channel action frame must be ended before new af tx.
9416  */
9417 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9418 			wl_cfgscan_cancel_scan(cfg);
9419 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9420 		}
9421 #ifdef WL_CLIENT_SAE
9422 		else if (ieee80211_is_auth(mgmt->frame_control)) {
9423 			err = wl_cfg80211_mgmt_auth_tx(dev, cfgdev, cfg, buf, len,
9424 				bssidx, cookie);
9425 			goto exit;
9426 		}
9427 #endif /* WL_CLIENT_SAE */
9428 
9429 	} else {
9430 		WL_ERR(("Driver only allows MGMT packet type\n"));
9431 		goto exit;
9432 	}
9433 
9434 	af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
9435 
9436 	if (af_params == NULL)
9437 	{
9438 		WL_ERR(("unable to allocate frame\n"));
9439 		return -ENOMEM;
9440 	}
9441 
9442 	action_frame = &af_params->action_frame;
9443 
9444 	/* Add the packet Id */
9445 	action_frame->packetId = *cookie;
9446 	WL_DBG(("action frame %d\n", action_frame->packetId));
9447 	/* Add BSSID */
9448 	memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
9449 	memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
9450 
9451 	/* Add the length exepted for 802.11 header  */
9452 	action_frame->len = len - DOT11_MGMT_HDR_LEN;
9453 	WL_DBG(("action_frame->len: %d\n", action_frame->len));
9454 
9455 	if (channel) {
9456 		/* Add the channel */
9457 		af_params->channel =
9458 			wl_freq_to_chanspec(channel->center_freq);
9459 	} else {
9460 		af_params->channel = 0;
9461 	}
9462 
9463 	/* Save listen_chan for searching common channel */
9464 	cfg->afx_hdl->peer_listen_chan = af_params->channel;
9465 	WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
9466 
9467 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9468 	af_params->dwell_time = params->wait;
9469 #else
9470 	af_params->dwell_time = wait;
9471 #endif
9472 
9473 	memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
9474 
9475 	ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params,
9476 		action_frame, action_frame->len, bssidx);
9477 	cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9478 	WL_DBG(("txstatus notified for cookie:%llu. ack:%d\n", *cookie, ack));
9479 
9480 	MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
9481 exit:
9482 	return err;
9483 }
9484 
9485 static void
wl_cfg80211_mgmt_frame_register(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u16 frame,bool reg)9486 wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9487 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9488 	u16 frame, bool reg)
9489 #else
9490 	struct mgmt_frame_regs *upd)
9491 #endif
9492 {
9493 
9494 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9495 	WL_DBG(("frame_type: %x, reg: %d\n", frame, reg));
9496 
9497 	if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
9498 		return;
9499 #endif
9500 
9501 	return;
9502 }
9503 
9504 static s32
wl_cfg80211_change_bss(struct wiphy * wiphy,struct net_device * dev,struct bss_parameters * params)9505 wl_cfg80211_change_bss(struct wiphy *wiphy,
9506 	struct net_device *dev,
9507 	struct bss_parameters *params)
9508 {
9509 	s32 err = 0;
9510 	s32 ap_isolate = 0;
9511 #ifdef PCIE_FULL_DONGLE
9512 	s32 ifidx = DHD_BAD_IF;
9513 #endif
9514 #if defined(SUPPORT_HOSTAPD_BGN_MODE)
9515 	s32 gmode = -1, nmode = -1;
9516 	s32 gmode_prev = -1, nmode_prev = -1;
9517 #endif /* SUPPORT_HOSTAPD_BGN_MODE */
9518 #if defined(PCIE_FULL_DONGLE) || defined(SUPPORT_HOSTAPD_BGN_MODE)
9519 	dhd_pub_t *dhd;
9520 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9521 	dhd = (dhd_pub_t *)(cfg->pub);
9522 #if defined(WL_ENABLE_P2P_IF)
9523 	if (cfg->p2p_net == dev)
9524 		dev = bcmcfg_to_prmry_ndev(cfg);
9525 #endif
9526 #endif /* PCIE_FULL_DONGLE || SUPPORT_HOSTAPD_BGN_MODE */
9527 
9528 	if (params->use_cts_prot >= 0) {
9529 	}
9530 
9531 	if (params->use_short_preamble >= 0) {
9532 	}
9533 
9534 	if (params->use_short_slot_time >= 0) {
9535 	}
9536 
9537 	if (params->basic_rates) {
9538 #if defined(SUPPORT_HOSTAPD_BGN_MODE)
9539 		switch ((int)(params->basic_rates[params->basic_rates_len -1])) {
9540 			case 22: /* B only , rate 11 */
9541 				gmode = 0;
9542 				nmode = 0;
9543 				break;
9544 			case 108: /* G only , rate 54 */
9545 				gmode = 2;
9546 				nmode = 0;
9547 				break;
9548 			default:
9549 				gmode = -1;
9550 				nmode = -1;
9551 				break;
9552 		}
9553 #endif /* SUPPORT_HOSTAPD_BGN_MODE */
9554 	}
9555 
9556 	if (params->ap_isolate >= 0) {
9557 		ap_isolate = params->ap_isolate;
9558 #ifdef PCIE_FULL_DONGLE
9559 		ifidx = dhd_net2idx(dhd->info, dev);
9560 
9561 		if (ifidx != DHD_BAD_IF) {
9562 			err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate);
9563 		} else {
9564 			WL_ERR(("Failed to set ap_isolate\n"));
9565 		}
9566 #else
9567 		err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
9568 		if (unlikely(err))
9569 		{
9570 			WL_ERR(("set ap_isolate Error (%d)\n", err));
9571 		}
9572 #endif /* PCIE_FULL_DONGLE */
9573 	}
9574 
9575 	if (params->ht_opmode >= 0) {
9576 #if defined(SUPPORT_HOSTAPD_BGN_MODE)
9577 		nmode = 1;
9578 		gmode = 1;
9579 	} else {
9580 		nmode = 0;
9581 #endif /* SUPPORT_HOSTAPD_BGN_MODE */
9582 	}
9583 
9584 #if defined(SUPPORT_HOSTAPD_BGN_MODE)
9585 	err = wldev_iovar_getint(dev, "nmode", &nmode_prev);
9586 	if (unlikely(err)) {
9587 		WL_ERR(("error reading nmode (%d)\n", err));
9588 	}
9589 	if (nmode == nmode_prev) {
9590 		nmode = -1;
9591 	}
9592 	err = wldev_ioctl_get(dev, WLC_GET_GMODE, &gmode_prev, sizeof(gmode_prev));
9593 	if (unlikely(err)) {
9594 		WL_ERR(("error reading gmode (%d)\n", err));
9595 	}
9596 	if (gmode == gmode_prev) {
9597 		gmode = -1;
9598 	}
9599 
9600 	if (((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) == DHD_FLAG_HOSTAP_MODE) &&
9601 		((gmode > -1) || (nmode > -1))) {
9602 		s32 val = 0;
9603 
9604 		err = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
9605 		if (unlikely(err))
9606 			WL_ERR(("WLC_DOWN command failed:[%d]\n", err));
9607 
9608 		if (nmode > -1) {
9609 			err = wldev_iovar_setint(dev, "nmode", nmode);
9610 			if (unlikely(err))
9611 				WL_ERR(("nmode command failed:mode[%d]:err[%d]\n", nmode, err));
9612 		}
9613 
9614 		if (gmode > -1) {
9615 			err = wldev_ioctl_set(dev, WLC_SET_GMODE, &gmode, sizeof(s32));
9616 			if (unlikely(err))
9617 				WL_ERR(("WLC_SET_GMODE command failed:mode[%d]:err[%d]\n",
9618 					gmode, err));
9619 		}
9620 
9621 		val = 0;
9622 		err = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
9623 		if (unlikely(err))
9624 			WL_ERR(("WLC_UP command failed:err[%d]\n", err));
9625 
9626 	}
9627 #endif /* SUPPORT_HOSTAPD_BGN_MODE */
9628 
9629 	return err;
9630 }
9631 
9632 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9633 struct net_device *
wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 * cfg)9634 wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
9635 {
9636 	struct net_info *_net_info, *next;
9637 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
9638 	list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
9639 		GCC_DIAGNOSTIC_POP();
9640 		if (_net_info->ndev &&
9641 			test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
9642 			return _net_info->ndev;
9643 	}
9644 
9645 	return NULL;
9646 }
9647 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9648 
9649 bool
wl_cfg80211_macaddr_sync_reqd(struct net_device * dev)9650 wl_cfg80211_macaddr_sync_reqd(struct net_device *dev)
9651 {
9652 	struct wireless_dev *wdev = dev->ieee80211_ptr;
9653 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
9654 
9655 	WL_DBG(("enter \n"));
9656 	if (!wdev) {
9657 		WL_ERR(("no wdev present\n"));
9658 		return false;
9659 	}
9660 
9661 	BCM_REFERENCE(cfg);
9662 
9663 #if defined(WL_STATIC_IF)
9664 	/* In soft case too role upgrade happens
9665 	 * from STA to AP in some cases.These
9666 	 * cases will have iftype as STATION.
9667 	 */
9668 	if (IS_CFG80211_STATIC_IF(cfg, dev)) {
9669 		WL_INFORM_MEM(("STATIC interface\n"));
9670 		return true;
9671 	}
9672 #endif /* WL_STATIC_IF && WL_SOFTAP_RAND */
9673 
9674 	switch (wdev->iftype) {
9675 #ifdef WL_P2P_RAND
9676 		case NL80211_IFTYPE_P2P_GO:
9677 		case NL80211_IFTYPE_P2P_CLIENT:
9678 			WL_INFORM_MEM(("P2P GO/GC interface\n"));
9679 			return true;
9680 #endif /* WL_P2P_RAND */
9681 #if defined(WL_STA_ASSOC_RAND)
9682 		case NL80211_IFTYPE_STATION:
9683 			WL_INFORM_MEM(("STA interface\n"));
9684 			return true;
9685 #endif /* WL_STA_ASSOC_RAND */
9686 #ifdef WL_SOFTAP_RAND
9687 		case NL80211_IFTYPE_AP:
9688 			WL_INFORM_MEM(("SOFTAP interface\n"));
9689 			return true;
9690 #endif /* WL_SOFTAP_RAND */
9691 		default:
9692 			WL_ERR(("no macthing if type\n"));
9693 	}
9694 	return false;
9695 }
9696 
9697 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
9698 static s32
9699 #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)9700 wl_cfg80211_del_station(
9701 		struct wiphy *wiphy, struct net_device *ndev,
9702 		struct station_del_parameters *params)
9703 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
9704 wl_cfg80211_del_station(
9705 	struct wiphy *wiphy,
9706 	struct net_device *ndev,
9707 	const u8* mac_addr)
9708 #else
9709 wl_cfg80211_del_station(
9710 	struct wiphy *wiphy,
9711 	struct net_device *ndev,
9712 	u8* mac_addr)
9713 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9714 {
9715 	struct net_device *dev;
9716 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9717 	scb_val_t scb_val;
9718 	int err;
9719 	char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
9720 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
9721 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9722 	int num_associated = 0;
9723 
9724 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9725 	const u8 *mac_addr = params->mac;
9726 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
9727 	u16 rc = params->reason_code;
9728 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
9729 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9730 
9731 	WL_DBG(("Entry\n"));
9732 	if (mac_addr == NULL) {
9733 		WL_DBG(("mac_addr is NULL ignore it\n"));
9734 		return 0;
9735 	}
9736 
9737 	dev = ndev_to_wlc_ndev(ndev, cfg);
9738 
9739 	if (p2p_is_on(cfg)) {
9740 		/* Suspend P2P discovery search-listen to prevent it from changing the
9741 		 * channel.
9742 		 */
9743 		if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9744 			WL_ERR(("Can not disable discovery mode\n"));
9745 			return -EFAULT;
9746 		}
9747 	}
9748 #ifdef WL_EXT_IAPSTA
9749 	err = wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
9750 		WL_EXT_STATUS_DELETE_STA, (void *)mac_addr);
9751 	if (err) {
9752 		return 0;
9753 	}
9754 #endif
9755 
9756 	assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9757 	err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
9758 		assoc_maclist, sizeof(mac_buf));
9759 	if (err < 0)
9760 		WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9761 	else
9762 		num_associated = assoc_maclist->count;
9763 
9764 	memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
9765 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
9766 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9767 	if (rc == DOT11_RC_8021X_AUTH_FAIL) {
9768 		WL_ERR(("deauth will be sent at F/W\n"));
9769 		scb_val.val = DOT11_RC_8021X_AUTH_FAIL;
9770 	} else {
9771 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9772 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
9773 
9774 #ifdef WL_WPS_SYNC
9775 		if (wl_wps_session_update(ndev,
9776 			WPS_STATE_DISCONNECT_CLIENT, mac_addr) == BCME_UNSUPPORTED) {
9777 			/* Ignore disconnect command from upper layer */
9778 			WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
9779 		} else
9780 #endif /* WL_WPS_SYNC */
9781 		{
9782 			scb_val.val = DOT11_RC_DEAUTH_LEAVING;
9783 			WL_MSG(dev->name, "Disconnect STA : %pM scb_val.val %d\n",
9784 				mac_addr, scb_val.val);
9785 #if defined(BCMDONGLEHOST)
9786 			/* need to guarantee EAP-Failure send out before deauth */
9787 			dhd_wait_pend8021x(dev);
9788 #endif
9789 			err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
9790 				sizeof(scb_val_t));
9791 			if (err < 0) {
9792 				WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
9793 			}
9794 		}
9795 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
9796 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9797 	}
9798 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9799 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
9800 
9801 	/* WAR Wait for the deauth event to come, supplicant will do the
9802 	 * delete iface immediately and we will have problem in sending
9803 	 * deauth frame if we delete the bss in firmware
9804 	 * But we do not need additional delays for this WAR
9805 	 * during P2P connection.
9806 	 *
9807 	 * Supplicant call this function with BCAST after doing
9808 	 * wl_cfg80211_del_station() all GC stations with each addr.
9809 	 * So, 400 ms delay can be called only once when GO disconnect all GC
9810 	*/
9811 	if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
9812 		wl_delay(400);
9813 
9814 	return 0;
9815 }
9816 
9817 /* Implementation for post SCB authorize */
9818 static void
wl_cfg80211_post_scb_auth(struct bcm_cfg80211 * cfg,struct net_device * dev)9819 wl_cfg80211_post_scb_auth(struct bcm_cfg80211 *cfg, struct net_device *dev)
9820 {
9821 #ifdef WBTEXT
9822 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
9823 #endif /* WBTEXT */
9824 
9825 	LOG_TS(cfg, authorize_cmplt);
9826 	CLR_TS(cfg, authorize_start);
9827 	wl_set_drv_status(cfg, AUTHORIZED, dev);
9828 #ifdef DHD_LOSSLESS_ROAMING
9829 	wl_del_roam_timeout(cfg);
9830 #endif
9831 #ifdef WBTEXT
9832 	/* send nbr request or BTM query to update RCC
9833 	 * after 4-way handshake is completed
9834 	 */
9835 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
9836 		dhdp->wbtext_support) {
9837 		wl_cfg80211_wbtext_update_rcc(cfg, dev);
9838 	}
9839 #endif /* WBTEXT */
9840 }
9841 
9842 /* Currently adding support only for authorize/de-authorize flag
9843  * Need to be extended in future
9844  */
9845 static s32
9846 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
wl_cfg80211_change_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)9847 wl_cfg80211_change_station(
9848 	struct wiphy *wiphy,
9849 	struct net_device *dev,
9850 	const u8 *mac,
9851 	struct station_parameters *params)
9852 #else
9853 wl_cfg80211_change_station(
9854 	struct wiphy *wiphy,
9855 	struct net_device *dev,
9856 	u8 *mac,
9857 	struct station_parameters *params)
9858 #endif
9859 {
9860 	int err = BCME_OK;
9861 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9862 #ifdef BCMSUP_4WAY_HANDSHAKE
9863 	struct wl_security *sec;
9864 #endif /* BCMSUP_4WAY_HANDSHAKE */
9865 	struct net_device *ndev = ndev_to_wlc_ndev(dev, cfg);
9866 
9867 	WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x "
9868 				"sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac),
9869 				params->sta_flags_mask, params->sta_flags_set, ndev->name));
9870 
9871 	if ((wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS) &&
9872 		!(wl_get_drv_status(cfg, CONNECTED, dev))) {
9873 		/* Return error indicating not in connected state */
9874 		WL_ERR(("Ignore SCB_AUTHORIZE/DEAUTHORIZE in non connected state\n"));
9875 		return -ENOTSUPP;
9876 	}
9877 
9878 	/* Processing only authorize/de-authorize flag for now */
9879 	if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
9880 		WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
9881 		return -ENOTSUPP;
9882 	}
9883 
9884 	if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
9885 		err = wldev_ioctl_set(ndev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN);
9886 		if (unlikely(err)) {
9887 			WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
9888 		} else {
9889 			WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG "\n",
9890 				ndev->name, MAC2STRDBG(mac)));
9891 		}
9892 		wl_clr_drv_status(cfg, AUTHORIZED, dev);
9893 		CLR_TS(cfg, authorize_start);
9894 		CLR_TS(cfg, conn_start);
9895 		return err;
9896 	}
9897 	/* In case of 4way HS offloaded to FW and key_mgmt being 8021x, even the SCB
9898 	* authorization is also offloaded to FW. So on reception of SCB authorize in the above
9899 	* cases we avoid explicit call to ioctl WLC_SCB_AUTHORIZE. The post SCB authorize
9900 	* actions are done from context of WLC_E_PSK_SUP event handler
9901 	*/
9902 #ifdef BCMSUP_4WAY_HANDSHAKE
9903 	sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
9904 	if (
9905 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
9906 		(wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X)) &&
9907 #else
9908 		(cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) &&
9909 #endif
9910 		((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
9911 		(sec->wpa_auth == WL_AKM_SUITE_SHA256_1X))) {
9912 		return BCME_OK;
9913 	}
9914 #endif /* BCMSUP_4WAY_HANDSHAKE */
9915 	err = wldev_ioctl_set(ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN);
9916 	if (unlikely(err)) {
9917 		WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
9918 	} else {
9919 		WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG "\n",
9920 			ndev->name, MAC2STRDBG(mac)));
9921 #ifdef WL_WPS_SYNC
9922 		wl_wps_session_update(ndev, WPS_STATE_AUTHORIZE, mac);
9923 #endif /* WL_WPS_SYNC */
9924 	}
9925 
9926 	/* Post SCB authorize actions */
9927 	wl_cfg80211_post_scb_auth(cfg, ndev);
9928 
9929 	return err;
9930 }
9931 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
9932 
9933 #ifdef WL_SUPPORT_ACS
9934 /*
9935  * Currently the dump_obss IOVAR is returning string as output so we need to
9936  * parse the output buffer in an unoptimized way. Going forward if we get the
9937  * IOVAR output in binary format this method can be optimized
9938  */
wl_parse_dump_obss(char * buf,struct wl_dump_survey * survey)9939 static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
9940 {
9941 	int i;
9942 	char *token;
9943 	char delim[] = " \n";
9944 
9945 	token = strsep(&buf, delim);
9946 	while (token != NULL) {
9947 		if (!strcmp(token, "OBSS")) {
9948 			for (i = 0; i < OBSS_TOKEN_IDX; i++)
9949 				token = strsep(&buf, delim);
9950 			survey->obss = simple_strtoul(token, NULL, 10);
9951 		}
9952 
9953 		if (!strcmp(token, "IBSS")) {
9954 			for (i = 0; i < IBSS_TOKEN_IDX; i++)
9955 				token = strsep(&buf, delim);
9956 			survey->ibss = simple_strtoul(token, NULL, 10);
9957 		}
9958 
9959 		if (!strcmp(token, "TXDur")) {
9960 			for (i = 0; i < TX_TOKEN_IDX; i++)
9961 				token = strsep(&buf, delim);
9962 			survey->tx = simple_strtoul(token, NULL, 10);
9963 		}
9964 
9965 		if (!strcmp(token, "Category")) {
9966 			for (i = 0; i < CTG_TOKEN_IDX; i++)
9967 				token = strsep(&buf, delim);
9968 			survey->no_ctg = simple_strtoul(token, NULL, 10);
9969 		}
9970 
9971 		if (!strcmp(token, "Packet")) {
9972 			for (i = 0; i < PKT_TOKEN_IDX; i++)
9973 				token = strsep(&buf, delim);
9974 			survey->no_pckt = simple_strtoul(token, NULL, 10);
9975 		}
9976 
9977 		if (!strcmp(token, "Opp(time):")) {
9978 			for (i = 0; i < IDLE_TOKEN_IDX; i++)
9979 				token = strsep(&buf, delim);
9980 			survey->idle = simple_strtoul(token, NULL, 10);
9981 		}
9982 
9983 		token = strsep(&buf, delim);
9984 	}
9985 
9986 	return 0;
9987 }
9988 
wl_dump_obss(struct net_device * ndev,cca_msrmnt_query req,struct wl_dump_survey * survey)9989 static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
9990 	struct wl_dump_survey *survey)
9991 {
9992 	cca_stats_n_flags *results;
9993 	char *buf;
9994 	int retry, err;
9995 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
9996 
9997 	buf = (char *)MALLOCZ(cfg->osh, sizeof(char) * WLC_IOCTL_MAXLEN);
9998 	if (unlikely(!buf)) {
9999 		WL_ERR(("%s: buf alloc failed\n", __func__));
10000 		return -ENOMEM;
10001 	}
10002 
10003 	retry = IOCTL_RETRY_COUNT;
10004 	while (retry--) {
10005 		err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req),
10006 			buf, WLC_IOCTL_MAXLEN, NULL);
10007 		if (err >=  0) {
10008 			break;
10009 		}
10010 		WL_DBG(("attempt = %d, err = %d, \n",
10011 			(IOCTL_RETRY_COUNT - retry), err));
10012 	}
10013 
10014 	if (retry <= 0)	{
10015 		WL_ERR(("failure, dump_obss IOVAR failed\n"));
10016 		err = -EINVAL;
10017 		goto exit;
10018 	}
10019 
10020 	results = (cca_stats_n_flags *)(buf);
10021 	wl_parse_dump_obss(results->buf, survey);
10022 	MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
10023 
10024 	return 0;
10025 exit:
10026 	MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
10027 	return err;
10028 }
10029 
wl_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * ndev,int idx,struct survey_info * info)10030 static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
10031 	int idx, struct survey_info *info)
10032 {
10033 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10034 	struct wl_dump_survey *survey;
10035 	struct ieee80211_supported_band *band;
10036 	struct ieee80211_channel*chan;
10037 	cca_msrmnt_query req;
10038 	int val, err, noise, retry;
10039 
10040 #ifdef BCMDONGLEHOST
10041 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10042 	if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
10043 		return -ENOENT;
10044 	}
10045 #endif
10046 	band = wiphy->bands[IEEE80211_BAND_2GHZ];
10047 	if (band && idx >= band->n_channels) {
10048 		idx -= band->n_channels;
10049 		band = NULL;
10050 	}
10051 
10052 	if (!band || idx >= band->n_channels) {
10053 		/* Move to 5G band */
10054 		band = wiphy->bands[IEEE80211_BAND_5GHZ];
10055 		if (idx >= band->n_channels) {
10056 			return -ENOENT;
10057 		}
10058 	}
10059 
10060 	chan = &band->channels[idx];
10061 	/* Setting current channel to the requested channel */
10062 	if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan,
10063 		NL80211_CHAN_HT20) < 0)) {
10064 		/*
10065 		 * FIXME:
10066 		 *
10067 		 *	Mostly set channel should not fail. because we are
10068 		 *	traversing through Valid channel list. In case it fails,
10069 		 *	right now we are passing the stats for previous channel.
10070 		 */
10071 		WL_ERR(("Set channel failed \n"));
10072 	}
10073 
10074 	if (!idx) {
10075 		/* Set interface up, explicitly. */
10076 		val = 1;
10077 		err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
10078 		if (err < 0) {
10079 			WL_ERR(("set interface up failed, error = %d\n", err));
10080 		}
10081 	}
10082 
10083 	/* Get noise value */
10084 	retry = IOCTL_RETRY_COUNT;
10085 	while (retry--) {
10086 		noise = 0;
10087 		err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise,
10088 			sizeof(noise));
10089 		if (err >=  0) {
10090 			break;
10091 		}
10092 		WL_DBG(("attempt = %d, err = %d, \n",
10093 			(IOCTL_RETRY_COUNT - retry), err));
10094 	}
10095 
10096 	if (retry <= 0)	{
10097 		WL_ERR(("Get Phy Noise failed, error = %d\n", err));
10098 		noise = CHAN_NOISE_DUMMY;
10099 	}
10100 
10101 	survey = (struct wl_dump_survey *)MALLOCZ(cfg->osh,
10102 		sizeof(struct wl_dump_survey));
10103 	if (unlikely(!survey)) {
10104 		WL_ERR(("%s: alloc failed\n", __func__));
10105 		return -ENOMEM;
10106 	}
10107 
10108 	/* Start Measurement for obss stats on current channel */
10109 	req.msrmnt_query = 0;
10110 	req.time_req = ACS_MSRMNT_DELAY;
10111 	if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
10112 		goto exit;
10113 	}
10114 
10115 	/*
10116 	 * Wait for the meaurement to complete, adding a buffer value of 10 to take
10117 	 * into consideration any delay in IOVAR completion
10118 	 */
10119 	msleep(ACS_MSRMNT_DELAY + 10);
10120 
10121 	/* Issue IOVAR to collect measurement results */
10122 	req.msrmnt_query = 1;
10123 	if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
10124 		goto exit;
10125 	}
10126 
10127 	info->channel = chan;
10128 	info->noise = noise;
10129 	info->channel_time = ACS_MSRMNT_DELAY;
10130 	info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
10131 	info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg +
10132 		survey->no_pckt;
10133 	info->channel_time_tx = survey->tx;
10134 	info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
10135 		SURVEY_INFO_CHANNEL_TIME_BUSY |	SURVEY_INFO_CHANNEL_TIME_RX |
10136 		SURVEY_INFO_CHANNEL_TIME_TX;
10137 	MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
10138 
10139 	return 0;
10140 exit:
10141 	MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
10142 	return err;
10143 }
10144 #endif /* WL_SUPPORT_ACS */
10145 
10146 static struct cfg80211_ops wl_cfg80211_ops = {
10147 	.add_virtual_intf = wl_cfg80211_add_virtual_iface,
10148 	.del_virtual_intf = wl_cfg80211_del_virtual_iface,
10149 	.change_virtual_intf = wl_cfg80211_change_virtual_iface,
10150 #if defined(WL_CFG80211_P2P_DEV_IF)
10151 	.start_p2p_device = wl_cfgp2p_start_p2p_device,
10152 	.stop_p2p_device = wl_cfgp2p_stop_p2p_device,
10153 #endif /* WL_CFG80211_P2P_DEV_IF */
10154 	.scan = wl_cfg80211_scan,
10155 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
10156 	.abort_scan = wl_cfg80211_abort_scan,
10157 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
10158 	.set_wiphy_params = wl_cfg80211_set_wiphy_params,
10159 	.join_ibss = wl_cfg80211_join_ibss,
10160 	.leave_ibss = wl_cfg80211_leave_ibss,
10161 	.get_station = wl_cfg80211_get_station,
10162 	.dump_station = wl_cfg80211_dump_station,
10163 	.set_tx_power = wl_cfg80211_set_tx_power,
10164 	.get_tx_power = wl_cfg80211_get_tx_power,
10165 	.add_key = wl_cfg80211_add_key,
10166 	.del_key = wl_cfg80211_del_key,
10167 	.get_key = wl_cfg80211_get_key,
10168 	.set_default_key = wl_cfg80211_config_default_key,
10169 	.set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
10170 	.set_power_mgmt = wl_cfg80211_set_power_mgmt,
10171 	.connect = wl_cfg80211_connect,
10172 	.disconnect = wl_cfg80211_disconnect,
10173 	.set_pmksa = wl_cfg80211_set_pmksa,
10174 	.del_pmksa = wl_cfg80211_del_pmksa,
10175 	.flush_pmksa = wl_cfg80211_flush_pmksa,
10176 	.remain_on_channel = wl_cfgscan_remain_on_channel,
10177 	.cancel_remain_on_channel = wl_cfgscan_cancel_remain_on_channel,
10178 	.mgmt_tx = wl_cfg80211_mgmt_tx,
10179 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
10180 	.mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
10181 #else
10182 	.update_mgmt_frame_registrations = wl_cfg80211_mgmt_frame_register,
10183 #endif
10184 	.change_bss = wl_cfg80211_change_bss,
10185 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || \
10186 	defined(WL_COMPAT_WIRELESS)
10187 	.set_channel = wl_cfg80211_set_channel,
10188 #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
10189 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && \
10190 	!defined(WL_COMPAT_WIRELESS)
10191 	.set_beacon = wl_cfg80211_add_set_beacon,
10192 	.add_beacon = wl_cfg80211_add_set_beacon,
10193 	.del_beacon = wl_cfg80211_del_beacon,
10194 #else
10195 	.change_beacon = wl_cfg80211_change_beacon,
10196 	.start_ap = wl_cfg80211_start_ap,
10197 	.stop_ap = wl_cfg80211_stop_ap,
10198 #endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
10199 #ifdef WL_SCHED_SCAN
10200 	.sched_scan_start = wl_cfg80211_sched_scan_start,
10201 	.sched_scan_stop = wl_cfg80211_sched_scan_stop,
10202 #endif /* WL_SCHED_SCAN */
10203 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
10204 	.del_station = wl_cfg80211_del_station,
10205 	.change_station = wl_cfg80211_change_station,
10206 	.mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
10207 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
10208 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \
10209 	defined(WL_COMPAT_WIRELESS)
10210 	.tdls_mgmt = wl_cfg80211_tdls_mgmt,
10211 	.tdls_oper = wl_cfg80211_tdls_oper,
10212 #endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
10213 #ifdef WL_SUPPORT_ACS
10214 	.dump_survey = wl_cfg80211_dump_survey,
10215 #endif /* WL_SUPPORT_ACS */
10216 #ifdef WL_CFG80211_ACL
10217 	.set_mac_acl = wl_cfg80211_set_mac_acl,
10218 #endif /* WL_CFG80211_ACL */
10219 #ifdef GTK_OFFLOAD_SUPPORT
10220 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
10221 	.set_rekey_data = wl_cfg80211_set_rekey_data,
10222 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
10223 #endif /* GTK_OFFLOAD_SUPPORT */
10224 #ifdef WL_CLIENT_SAE
10225 	.external_auth = wl_cfg80211_external_auth,
10226 #endif /* WL_CLIENT_SAE */
10227 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
10228 	/* This should be enabled from kernel version which supports this */
10229 	.update_connect_params = wl_cfg80211_update_connect_params,
10230 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
10231 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
10232 	.set_pmk = wl_cfg80211_set_pmk,
10233 	.del_pmk = wl_cfg80211_del_pmk,
10234 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
10235 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
10236 	.channel_switch = wl_cfg80211_channel_switch,
10237 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
10238 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
10239 #ifdef WLFBT
10240 	.update_ft_ies = wl_cfg80211_update_ft_ies,
10241 #endif /* WLFBT */
10242 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */
10243 };
10244 
wl_mode_to_nl80211_iftype(s32 mode)10245 s32 wl_mode_to_nl80211_iftype(s32 mode)
10246 {
10247 	s32 err = 0;
10248 
10249 	switch (mode) {
10250 	case WL_MODE_BSS:
10251 		return NL80211_IFTYPE_STATION;
10252 	case WL_MODE_IBSS:
10253 		return NL80211_IFTYPE_ADHOC;
10254 	case WL_MODE_AP:
10255 		return NL80211_IFTYPE_AP;
10256 #ifdef WLMESH_CFG80211
10257 	case WL_MODE_MESH:
10258 		return NL80211_IFTYPE_MESH_POINT;
10259 #endif /* WLMESH_CFG80211 */
10260 	default:
10261 		return NL80211_IFTYPE_UNSPECIFIED;
10262 	}
10263 
10264 	return err;
10265 }
10266 
10267 static bool
wl_is_ccode_change_required(struct net_device * net,char * country_code,int revinfo)10268 wl_is_ccode_change_required(struct net_device *net,
10269 	char *country_code, int revinfo)
10270 {
10271 	s32 ret = BCME_OK;
10272 	wl_country_t cspec = {{0}, 0, {0}};
10273 	wl_country_t cur_cspec = {{0}, 0, {0}};
10274 
10275 	ret = wldev_iovar_getbuf(net, "country", NULL, 0, &cur_cspec,
10276 		sizeof(cur_cspec), NULL);
10277 	if (ret < 0) {
10278 		WL_ERR(("get country code failed = %d\n", ret));
10279 		return true;
10280 	}
10281 	/* If translation table is available, update cspec */
10282 	cspec.rev = revinfo;
10283 	strlcpy(cspec.country_abbrev, country_code, WL_CCODE_LEN + 1);
10284 	strlcpy(cspec.ccode, country_code, WL_CCODE_LEN + 1);
10285 	dhd_get_customized_country_code(net, cspec.country_abbrev, &cspec);
10286 	if ((cur_cspec.rev == cspec.rev) &&
10287 		(strncmp(cur_cspec.ccode, cspec.ccode, WL_CCODE_LEN) == 0) &&
10288 		(strncmp(cur_cspec.country_abbrev, cspec.country_abbrev, WL_CCODE_LEN) == 0)) {
10289 			WL_INFORM_MEM(("country code = %s/%d is already configured\n",
10290 				country_code, revinfo));
10291 			return false;
10292 	}
10293 	return true;
10294 }
10295 
10296 void
wl_cfg80211_cleanup_connection(struct net_device * net,bool user_enforced)10297 wl_cfg80211_cleanup_connection(struct net_device *net, bool user_enforced)
10298 {
10299 	s32 ret = BCME_OK;
10300 	struct wireless_dev *wdev = ndev_to_wdev(net);
10301 	struct wiphy *wiphy = wdev->wiphy;
10302 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10303 	struct net_info *iter, *next;
10304 	scb_val_t scbval;
10305 
10306 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
10307 	for_each_ndev(cfg, iter, next) {
10308 		GCC_DIAGNOSTIC_POP();
10309 		if (iter->ndev) {
10310 			if (wl_get_drv_status(cfg, AP_CREATED, iter->ndev)) {
10311 				memset(scbval.ea.octet, 0xff, ETHER_ADDR_LEN);
10312 				scbval.val = DOT11_RC_DEAUTH_LEAVING;
10313 				if ((ret = wldev_ioctl_set(iter->ndev,
10314 						WLC_SCB_DEAUTHENTICATE_FOR_REASON,
10315 						&scbval, sizeof(scb_val_t))) != 0) {
10316 					WL_ERR(("Failed to disconnect STAs %d\n", ret));
10317 				}
10318 
10319 			} else if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
10320 				if ((iter->ndev == net) && !user_enforced)
10321 					continue;
10322 				wl_cfg80211_disassoc(iter->ndev, WLAN_REASON_DEAUTH_LEAVING);
10323 			} else {
10324 				WL_INFORM(("Disconnected state. Interface clean "
10325 					"up skipped for ifname:%s\n", iter->ndev->name));
10326 			}
10327 		}
10328 	}
10329 
10330 	wl_cfgscan_cancel_scan(cfg);
10331 
10332 	/* Clean up NAN connection */
10333 #ifdef WL_NAN
10334 	if (wl_cfgnan_is_enabled(cfg)) {
10335 		mutex_lock(&cfg->if_sync);
10336 		ret = wl_cfgnan_check_nan_disable_pending(cfg, true, true);
10337 		mutex_unlock(&cfg->if_sync);
10338 		if (ret != BCME_OK) {
10339 			WL_ERR(("failed to disable nan, error[%d]\n", ret));
10340 		}
10341 	}
10342 #endif /* WL_NAN */
10343 }
10344 
10345 s32
wl_cfg80211_set_country_code(struct net_device * net,char * country_code,bool notify,bool user_enforced,int revinfo)10346 wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
10347 	bool notify, bool user_enforced, int revinfo)
10348 {
10349 	s32 ret = BCME_OK;
10350 	struct wireless_dev *wdev = ndev_to_wdev(net);
10351 	struct wiphy *wiphy = wdev->wiphy;
10352 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10353 	BCM_REFERENCE(cfg);
10354 
10355 	if (revinfo < 0) {
10356 		WL_ERR(("country revinfo wrong : %d\n", revinfo));
10357 		ret = BCME_BADARG;
10358 		goto exit;
10359 	}
10360 
10361 	if ((wl_is_ccode_change_required(net, country_code, revinfo) == false) &&
10362 		!dhd_force_country_change(net)) {
10363 		goto exit;
10364 	}
10365 
10366 	wl_cfg80211_cleanup_connection(net, user_enforced);
10367 
10368 	ret = wldev_set_country(net, country_code,
10369 		notify, revinfo);
10370 	if (ret < 0) {
10371 		WL_ERR(("set country Failed :%d\n", ret));
10372 		goto exit;
10373 	}
10374 
10375 	/* send up the hint so that upper layer apps
10376 	 * can refresh the channel
10377 	 * list
10378 	 */
10379 	if (!IS_REGDOM_SELF_MANAGED(wiphy)) {
10380 		regulatory_hint(wiphy, country_code);
10381 	}
10382 
10383 exit:
10384 	return ret;
10385 }
10386 
10387 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
10388 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
10389 #define WL_CFG80211_REG_NOTIFIER() static int wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
10390 #else
10391 #define WL_CFG80211_REG_NOTIFIER() static void wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
10392 #endif /* kernel version < 3.9.0 */
10393 #endif
10394 
10395 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
WL_CFG80211_REG_NOTIFIER()10396 WL_CFG80211_REG_NOTIFIER()
10397 {
10398 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
10399 	int ret = 0;
10400 	int revinfo = -1;
10401 
10402 	if (!request || !cfg) {
10403 		WL_ERR(("Invalid arg\n"));
10404 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
10405 		return -EINVAL;
10406 #else
10407 		return;
10408 #endif /* kernel version < 3.10.11 */
10409 	}
10410 
10411 	WL_DBG(("ccode: %c%c Initiator: %d\n",
10412 		request->alpha2[0], request->alpha2[1], request->initiator));
10413 
10414 	/* We support only REGDOM_SET_BY_USER as of now */
10415 	if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
10416 		(request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
10417 		WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
10418 			request->initiator));
10419 		/* in case of no supported country by regdb
10420 		     lets driver setup platform default Locale
10421 		*/
10422 	}
10423 
10424 	WL_ERR(("Set country code %c%c from %s\n",
10425 		request->alpha2[0], request->alpha2[1],
10426 		((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User")));
10427 	ret = wl_cfg80211_set_country_code(bcmcfg_to_prmry_ndev(cfg), request->alpha2, false,
10428 			(request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false),
10429 			revinfo);
10430 	if (ret < 0) {
10431 		WL_ERR(("Set country failed ret:%d\n", ret));
10432 	}
10433 
10434 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
10435 	return ret;
10436 #else
10437 	return;
10438 #endif /* kernel version < 3.10.11 */
10439 }
10440 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
10441 
10442 #ifdef CONFIG_PM
10443 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
10444 static const struct wiphy_wowlan_support brcm_wowlan_support = {
10445 	.flags = WIPHY_WOWLAN_ANY,
10446 	.n_patterns = WL_WOWLAN_MAX_PATTERNS,
10447 	.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
10448 	.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
10449 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
10450 	.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
10451 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
10452 };
10453 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
10454 #endif /* CONFIG_PM */
10455 
wl_features_set(u8 * array,uint8 len,u32 ftidx)10456 int wl_features_set(u8 *array, uint8 len, u32 ftidx)
10457 {
10458 	u8* ft_byte;
10459 
10460 	if ((ftidx / 8u) >= len)
10461 		return BCME_BADARG;
10462 
10463 	ft_byte = &array[ftidx / 8u];
10464 	*ft_byte |= BIT(ftidx % 8u);
10465 	return BCME_OK;
10466 }
10467 
10468 static
wl_config_custom_regulatory(struct wiphy * wiphy)10469 void wl_config_custom_regulatory(struct wiphy *wiphy)
10470 {
10471 
10472 #if defined(WL_SELF_MANAGED_REGDOM) && \
10473 	(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
10474 	/* Use self managed regulatory domain */
10475 	wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED |
10476 			REGULATORY_IGNORE_STALE_KICKOFF;
10477 	wiphy->regd = &brcm_regdom;
10478 	WL_DBG(("Self managed regdom\n"));
10479 	return;
10480 #else /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
10481 
10482 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
10483 	wiphy->regulatory_flags |=
10484 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
10485 		REGULATORY_IGNORE_STALE_KICKOFF |
10486 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
10487 		REGULATORY_CUSTOM_REG;
10488 #else /* KERNEL VER >= 3.14 */
10489 	wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
10490 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
10491 	wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
10492 	WL_DBG(("apply custom regulatory\n"));
10493 #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
10494 }
10495 
wl_setup_wiphy(struct wireless_dev * wdev,struct device * sdiofunc_dev,dhd_pub_t * context)10496 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, dhd_pub_t *context)
10497 {
10498 	s32 err = 0;
10499 #ifdef CONFIG_PM
10500 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
10501 	struct cfg80211_wowlan *brcm_wowlan_config = NULL;
10502 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
10503 #endif /* CONFIG_PM */
10504 
10505 //#if defined(BCMDONGLEHOST) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
10506 	dhd_pub_t *dhd = (dhd_pub_t *)context;
10507 	BCM_REFERENCE(dhd);
10508 
10509 	if (!dhd) {
10510 		WL_ERR(("DHD is NULL!!"));
10511 		err = -ENODEV;
10512 		return err;
10513 	}
10514 //#endif /* defined(BCMDONGLEHOST) && KERNEL >= 3, 4, 0 || defined(WL_COMPAT_WIRELESS)) */
10515 
10516 	wdev->wiphy =
10517 	    wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
10518 	if (unlikely(!wdev->wiphy)) {
10519 		WL_ERR(("Couldn not allocate wiphy device\n"));
10520 		err = -ENOMEM;
10521 		return err;
10522 	}
10523 	set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
10524 	wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
10525 	/* Report  how many SSIDs Driver can support per Scan request */
10526 	wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
10527 	wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
10528 #ifdef WL_SCHED_SCAN
10529 	wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
10530 	wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
10531 	wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
10532 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
10533 	wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
10534 #else
10535 	wdev->wiphy->max_sched_scan_reqs = 1;
10536 #endif /* LINUX_VER < 4.12 */
10537 #endif /* WL_SCHED_SCAN */
10538 #ifdef WLMESH_CFG80211
10539 	wdev->wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
10540 #endif /* WLMESH_CFG80211 */
10541 	wdev->wiphy->interface_modes =
10542 		BIT(NL80211_IFTYPE_STATION)
10543 		| BIT(NL80211_IFTYPE_ADHOC)
10544 #if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
10545 	/*
10546 	 * This monitor mode support creates an issue in registering
10547 	 * Action frame for P2P-GO, this was leading an error in receiving
10548 	 * action frames to GO interface.Keeping the code here because
10549 	 * monitor mode code has kept as it is in other modules,
10550 	 * though we are not supporting this mode.
10551 	 */
10552 		| BIT(NL80211_IFTYPE_MONITOR)
10553 #endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
10554 #if defined(WL_IFACE_COMB_NUM_CHANNELS) || \
10555 	defined(WL_CFG80211_P2P_DEV_IF)
10556 		| BIT(NL80211_IFTYPE_P2P_CLIENT)
10557 		| BIT(NL80211_IFTYPE_P2P_GO)
10558 #endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
10559 #if defined(WL_CFG80211_P2P_DEV_IF)
10560 		| BIT(NL80211_IFTYPE_P2P_DEVICE)
10561 #endif /* WL_CFG80211_P2P_DEV_IF */
10562 #ifdef WLMESH_CFG80211
10563 		| BIT(NL80211_IFTYPE_MESH_POINT)
10564 #endif /* WLMESH_CFG80211 */
10565 		| BIT(NL80211_IFTYPE_AP);
10566 
10567 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
10568 	(defined(WL_IFACE_COMB_NUM_CHANNELS) || \
10569 	defined(WL_CFG80211_P2P_DEV_IF))
10570 	WL_DBG(("Setting interface combinations for common mode\n"));
10571 	wdev->wiphy->iface_combinations = common_iface_combinations;
10572 	wdev->wiphy->n_iface_combinations =
10573 		ARRAY_SIZE(common_iface_combinations);
10574 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
10575 
10576 	wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
10577 
10578 	wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
10579 	wdev->wiphy->cipher_suites = __wl_cipher_suites;
10580 	wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
10581 	wdev->wiphy->max_remain_on_channel_duration = 5000;
10582 	wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
10583 #ifndef WL_POWERSAVE_DISABLED
10584 	wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
10585 #else
10586 	wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
10587 #endif				/* !WL_POWERSAVE_DISABLED */
10588 	wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
10589 		WIPHY_FLAG_4ADDR_AP |
10590 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && \
10591 	!defined(WL_COMPAT_WIRELESS)
10592 		WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
10593 #endif
10594 		WIPHY_FLAG_4ADDR_STATION;
10595 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
10596 	/*
10597 	 * If FW ROAM flag is advertised, upper layer doesn't provide the
10598 	 * bssid & freq in the connect command. However, kernel ver >= 3.15,
10599 	 * provides bssid_hint & freq_hint which can be used by the firmware.
10600 	 * fw_ap_select variable determines whether FW selects the AP or the
10601 	 * user space selects the target AP within the given ESS.
10602 	 */
10603 	wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
10604 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
10605 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
10606 	defined(WL_COMPAT_WIRELESS)
10607 	/* this flag should be added to support wpa_supplicant 1.0+ */
10608 	wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
10609 		WIPHY_FLAG_OFFCHAN_TX;
10610 #endif
10611 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
10612 	/* From 3.4 kernel ownards AP_SME flag can be advertised
10613 	 * to remove the patch from supplicant
10614 	 */
10615 	wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
10616 
10617 #ifdef WL_CFG80211_ACL
10618 	/* Configure ACL capabilities. */
10619 	wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
10620 #endif
10621 
10622 #if defined(BCMDONGLEHOST) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || \
10623 	defined(WL_COMPAT_WIRELESS))
10624 	/* Supplicant distinguish between the SoftAP mode and other
10625 	 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
10626 	 * response frame from Supplicant MR1 and Kernel 3.4.0 or
10627 	 * later version. To add Vendor specific IE into the
10628 	 * probe response frame in case of SoftAP mode,
10629 	 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
10630 	 */
10631 	if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
10632 		wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
10633 		wdev->wiphy->probe_resp_offload = 0;
10634 	}
10635 #endif /* defined(BCMDONGLEHOST) && KERNEL >= 3, 4, 0 || defined(WL_COMPAT_WIRELESS)) */
10636 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
10637 
10638 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \
10639 	defined(WL_COMPAT_WIRELESS)
10640 	wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
10641 #endif
10642 
10643 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
10644 	/*
10645 	 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
10646 	 * disconnection of connected network before suspend. So a dummy wowlan
10647 	 * filter is configured for kernels linux-3.8 and above.
10648 	 */
10649 
10650 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
10651 	wdev->wiphy->wowlan = &brcm_wowlan_support;
10652 	/* If this is not provided cfg stack will get disconnect
10653 	* during suspend.
10654 	* Note: wiphy->wowlan_config is freed by cfg80211 layer.
10655 	* so use malloc instead of MALLOC(osh) to avoid false alarm.
10656 	*/
10657 	brcm_wowlan_config = kmalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL);
10658 	if (brcm_wowlan_config) {
10659 		brcm_wowlan_config->disconnect = true;
10660 		brcm_wowlan_config->gtk_rekey_failure = true;
10661 		brcm_wowlan_config->eap_identity_req = true;
10662 		brcm_wowlan_config->four_way_handshake = true;
10663 		brcm_wowlan_config->patterns = NULL;
10664 		brcm_wowlan_config->n_patterns = 0;
10665 		brcm_wowlan_config->tcp = NULL;
10666 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
10667 		brcm_wowlan_config->nd_config = NULL;
10668 #endif
10669 	} else {
10670 		WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
10671 			" So wiphy->wowlan_config is set to NULL\n"));
10672 	}
10673 	wdev->wiphy->wowlan_config = brcm_wowlan_config;
10674 #else
10675 	wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
10676 	wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
10677 	wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
10678 	wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
10679 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
10680 	wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
10681 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
10682 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
10683 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
10684 
10685 	WL_DBG(("Registering custom regulatory)\n"));
10686 	wl_config_custom_regulatory(wdev->wiphy);
10687 
10688 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
10689 	WL_INFORM_MEM(("Registering Vendor80211\n"));
10690 	err = wl_cfgvendor_attach(wdev->wiphy, dhd);
10691 	if (unlikely(err < 0)) {
10692 		WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
10693 	}
10694 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
10695 #ifdef WL_FILS
10696 	wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
10697 #endif /* WL_FILS */
10698 
10699 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
10700 	wdev->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
10701 	wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS;
10702 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */
10703 
10704 	/* Now we can register wiphy with cfg80211 module */
10705 	err = wiphy_register(wdev->wiphy);
10706 	if (unlikely(err < 0)) {
10707 		WL_ERR(("Couldn not register wiphy device (%d)\n", err));
10708 		wiphy_free(wdev->wiphy);
10709 	}
10710 
10711 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
10712 	(LINUX_VERSION_CODE <= KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
10713 	/* Workaround for a cfg80211 bug */
10714 	wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
10715 #endif
10716 
10717 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN)
10718 		wdev->wiphy->features |= (NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
10719 			NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR);
10720 		wdev->wiphy->max_sched_scan_plans = 1; /* multiple plans not supported */
10721 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) */
10722 
10723 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
10724 	if (wl_extsae_chip(dhd))
10725 		wdev->wiphy->features |= NL80211_FEATURE_SAE;
10726 #endif /* WL_SAE || WL_CLIENT_SAE */
10727 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE)
10728 	if (FW_SUPPORTED(dhd, idsup)) {
10729 		wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
10730 		wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
10731 	}
10732 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) && defined(BCMSUP_4WAY_HANDSHAKE) */
10733 #ifdef WL_SCAN_TYPE
10734 	/* These scan types will be mapped to default scan on non-supported chipset */
10735 	/* Advertise scan type capability. */
10736 	wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_SPAN_SCAN);
10737 	wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_POWER_SCAN);
10738 	wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
10739 	wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN;
10740 #endif /* WL_SCAN_TYPE */
10741 
10742 	return err;
10743 }
10744 
wl_free_wdev(struct bcm_cfg80211 * cfg)10745 static void wl_free_wdev(struct bcm_cfg80211 *cfg)
10746 {
10747 	struct wireless_dev *wdev = cfg->wdev;
10748 	struct wiphy *wiphy = NULL;
10749 	if (!wdev) {
10750 		WL_ERR(("wdev is invalid\n"));
10751 		return;
10752 	}
10753 	if (wdev->wiphy) {
10754 		wiphy = wdev->wiphy;
10755 
10756 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
10757 		wl_cfgvendor_detach(wdev->wiphy);
10758 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
10759 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
10760 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
10761 		/* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
10762 		WL_DBG(("clear wowlan\n"));
10763 		wdev->wiphy->wowlan = NULL;
10764 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
10765 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
10766 #if defined(WL_SELF_MANAGED_REGDOM) && \
10767 			(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
10768 		/* Making regd ptr NULL, to avoid reference/freeing by regulatory unregister */
10769 		wiphy->regd = NULL;
10770 #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
10771 		wiphy_unregister(wdev->wiphy);
10772 		wdev->wiphy->dev.parent = NULL;
10773 		wdev->wiphy = NULL;
10774 	}
10775 
10776 	wl_delete_all_netinfo(cfg);
10777 	if (wiphy) {
10778 		if (wdev->netdev)
10779 			wdev->netdev->ieee80211_ptr = NULL;
10780 		wdev->netdev = NULL;
10781 		MFREE(cfg->osh, wdev, sizeof(*wdev));
10782 		cfg->wdev = NULL;
10783 		wiphy_free(wiphy);
10784 	}
10785 
10786 	/* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
10787 	 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
10788 	 */
10789 }
10790 
10791 static s32
wl_post_linkup_ops(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)10792 wl_post_linkup_ops(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
10793 {
10794 	s32 ret = BCME_OK;
10795 	int vndr_oui_num = 0;
10796 	struct net_device *ndev = as->ndev;
10797 	char vndr_oui[MAX_VNDR_OUI_STR_LEN] = {0, };
10798 #ifdef BCMDONGLEHOST
10799 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
10800 #endif /* BCMDONGLEHOST */
10801 
10802 #ifdef WL_WPS_SYNC
10803 	wl_wps_session_update(ndev, WPS_STATE_LINKUP, as->addr);
10804 #endif /** WL_WPS_SYNC */
10805 
10806 	if (IS_PRIMARY_NDEV(cfg, ndev)) {
10807 		vndr_oui_num = wl_vndr_ies_get_vendor_oui(cfg,
10808 			ndev, vndr_oui, ARRAY_SIZE(vndr_oui));
10809 		if (vndr_oui_num > 0) {
10810 			WL_INFORM_MEM(("[%s] vendor oui: %s\n",
10811 				ndev->name, vndr_oui));
10812 		}
10813 	}
10814 
10815 #ifdef ESCAN_CHANNEL_CACHE
10816 	/* Update RCC list. FW clears RCC from join iovar context */
10817 	update_roam_cache(cfg, ioctl_version);
10818 #endif /* ESCAN_CHANNEL_CACHE */
10819 
10820 #ifdef BCMDONGLEHOST
10821 	if (as->event_type == WLC_E_LINK) {
10822 		/* Arm pkt logging timer */
10823 		dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_CONNECT);
10824 	}
10825 #endif /* BCMDONGLEHOST */
10826 #ifdef WBTEXT
10827 	if ((ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
10828 		dhdp->wbtext_support &&	(as->event_type == WLC_E_SET_SSID)) {
10829 		/* set wnm_keepalives_max_idle after association */
10830 		wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
10831 	}
10832 #endif /* WBTEXT */
10833 
10834 #ifdef DHD_EVENT_LOG_FILTER
10835 	dhd_event_log_filter_notify_connect_done(dhdp,
10836 			as->addr, false);
10837 #endif /* DHD_EVENT_LOG_FILTER */
10838 
10839 #ifdef CUSTOM_SET_OCLOFF
10840 	if (dhdp->ocl_off) {
10841 		int err = 0;
10842 		int ocl_enable = 0;
10843 		err = wldev_iovar_setint(ndev, "ocl_enable", ocl_enable);
10844 		if (err != 0) {
10845 			WL_ERR(("[WIFI_SEC] Set ocl_enable %d"
10846 				" failed %d\n",
10847 				ocl_enable, err));
10848 		} else {
10849 			WL_ERR(("[WIFI_SEC] Set ocl_enable %d"
10850 				" succeeded %d\n",
10851 				ocl_enable, err));
10852 		}
10853 	}
10854 #endif /* CUSTOM_SET_OCLOFF */
10855 #ifdef CUSTOM_SET_ANTNPM
10856 	if (dhdp->mimo_ant_set) {
10857 		int err = 0;
10858 
10859 		WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhdp->mimo_ant_set));
10860 		err = wldev_iovar_setint(ndev, "txchain", dhdp->mimo_ant_set);
10861 		if (err != 0) {
10862 			WL_ERR(("[WIFI_SEC] Fail set txchain. err:%d\n", err));
10863 		}
10864 		err = wldev_iovar_setint(ndev, "rxchain", dhdp->mimo_ant_set);
10865 		if (err != 0) {
10866 			WL_ERR(("[WIFI_SEC] Fail set rxchain. err:%d\n", err));
10867 		}
10868 	}
10869 #endif /* CUSTOM_SET_ANTNPM */
10870 
10871 #if defined (ROAM_ENABLE) && defined (ROAM_AP_ENV_DETECTION)
10872 	if (dhdp->roam_env_detection) {
10873 		wldev_iovar_setint(ndev, "roam_env_detection",
10874 			AP_ENV_INDETERMINATE);
10875 	}
10876 #endif /* ROAM_AP_ENV_DETECTION */
10877 
10878 	if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
10879 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
10880 		init_completion(&cfg->iface_disable);
10881 #else
10882 		/* reinitialize completion to clear previous count */
10883 		INIT_COMPLETION(cfg->iface_disable);
10884 #endif
10885 	}
10886 
10887 #ifdef CUSTOM_SET_CPUCORE
10888 	if (wl_get_chan_isvht80(ndev, dhdp)) {
10889 		if (ndev == bcmcfg_to_prmry_ndev(cfg))
10890 			dhdp->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
10891 		else if (is_p2p_group_iface(ndev->ieee80211_ptr))
10892 			dhdp->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
10893 		dhd_set_cpucore(dhdp, TRUE);
10894 	}
10895 #endif /* CUSTOM_SET_CPUCORE */
10896 
10897 #ifdef CUSTOM_LONG_RETRY_LIMIT
10898 	if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
10899 		WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
10900 	}
10901 #endif /* CUSTOM_LONG_RETRY_LIMIT */
10902 
10903 #if defined(CONFIG_TIZEN)
10904 	net_stat_tizen_update_wifi(ndev, WIFISTAT_CONNECTION);
10905 #endif /* CONFIG_TIZEN */
10906 
10907 #ifdef WL_BAM
10908 	{
10909 		struct ether_addr eth = {{0}};
10910 		(void)memcpy_s(&eth.octet, ETH_ALEN, as->addr, ETH_ALEN);
10911 		if (wl_adps_bad_ap_check(cfg, &eth)) {
10912 			if (wl_adps_enabled(cfg, ndev)) {
10913 				wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
10914 			}
10915 		}
10916 	}
10917 #endif	/* WL_BAM */
10918 
10919 #ifdef CONFIG_TCPACK_FASTTX
10920 	if (wl_get_chan_isvht80(ndev, dhdp))
10921 		wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
10922 	else
10923 		wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
10924 #endif /* CONFIG_TCPACK_FASTTX */
10925 	return ret;
10926 }
10927 
10928 #ifdef WL_SAE
10929 static s32
wl_cfg80211_event_sae_key(struct bcm_cfg80211 * cfg,struct net_device * ndev,wl_sae_key_info_t * sae_key)10930 wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg, struct net_device *ndev,
10931 	wl_sae_key_info_t *sae_key)
10932 {
10933 	struct sk_buff *skb;
10934 	gfp_t kflags;
10935 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
10936 	int err = BCME_OK;
10937 	struct cfg80211_pmksa pmksa;
10938 
10939 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
10940 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
10941 		LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
10942 	skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), BRCM_SAE_VENDOR_EVENT_BUF_LEN,
10943 		BRCM_VENDOR_EVENT_SAE_KEY, kflags);
10944 #else
10945 	skb = cfg80211_vendor_event_alloc(wiphy, BRCM_SAE_VENDOR_EVENT_BUF_LEN,
10946 		BRCM_VENDOR_EVENT_SAE_KEY, kflags);
10947 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
10948 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
10949 	if (!skb) {
10950 		WL_ERR(("skb alloc failed"));
10951 		err = BCME_NOMEM;
10952 		goto done;
10953 	}
10954 
10955 	WL_INFORM_MEM(("Received Sae Key event for "MACDBG" key length %x %x",
10956 		MAC2STRDBG(sae_key->peer_mac), sae_key->pmk_len, sae_key->pmkid_len));
10957 	nla_put(skb, BRCM_SAE_KEY_ATTR_PEER_MAC, ETHER_ADDR_LEN, sae_key->peer_mac);
10958 	nla_put(skb, BRCM_SAE_KEY_ATTR_PMK, sae_key->pmk_len, sae_key->pmk);
10959 	nla_put(skb, BRCM_SAE_KEY_ATTR_PMKID, sae_key->pmkid_len, sae_key->pmkid);
10960 	cfg80211_vendor_event(skb, kflags);
10961 	/* wpa_supplicant will manage the PMK and PMKID from here on..
10962 	 * Delete the PMK cache in firmware, if wlc_ver equals to MIN_PMKID_LIST_V3_FW_MAJOR
10963 	 * else ignore.
10964 	 * MIN_PMKID_LIST_V3_FW_MAJOR has two IOVAR's(pmklist_info and PMKDB).
10965 	 */
10966 	if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V3_FW_MAJOR) {
10967 		WL_INFORM_MEM(("Deleting the SAE PMK cache Info from firmware \n"));
10968 		memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
10969 		pmksa.bssid = sae_key->peer_mac;
10970 		pmksa.pmkid = sae_key->pmkid;
10971 		err = wl_cfg80211_update_pmksa(wiphy, ndev, &pmksa, FALSE);
10972 		if (err != BCME_OK) {
10973 			WL_ERR(("Failed to delete the SAE PMK cache Info from firmware %d\n", err));
10974 		}
10975 	}
10976 done:
10977 	return err;
10978 }
10979 
10980 static s32
wl_bss_handle_sae_auth_v1(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * event,void * data)10981 wl_bss_handle_sae_auth_v1(struct bcm_cfg80211 *cfg, struct net_device *ndev,
10982 	const wl_event_msg_t *event, void *data)
10983 {
10984 	int err = BCME_OK;
10985 	wl_auth_event_t *auth_data;
10986 	wl_sae_key_info_t sae_key;
10987 	uint16 tlv_buf_len;
10988 	auth_data = (wl_auth_event_t *)data;
10989 
10990 	tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V1;
10991 
10992 	/* check if PMK info present */
10993 	sae_key.pmk = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
10994 		WL_AUTH_PMK_TLV_ID, &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
10995 	if (!sae_key.pmk || !sae_key.pmk_len) {
10996 		WL_ERR(("Mandatory PMK info not present"));
10997 		err = BCME_NOTFOUND;
10998 		goto done;
10999 	}
11000 	/* check if PMKID info present */
11001 	sae_key.pmkid = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11002 		WL_AUTH_PMKID_TLV_ID, &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
11003 	if (!sae_key.pmkid || !sae_key.pmkid_len) {
11004 		WL_ERR(("Mandatory PMKID info not present\n"));
11005 		err = BCME_NOTFOUND;
11006 		goto done;
11007 	}
11008 	memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet, ETHER_ADDR_LEN);
11009 	err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
11010 	if (err) {
11011 		WL_ERR(("Failed to event sae key info\n"));
11012 	}
11013 done:
11014 	return err;
11015 }
11016 
11017 static s32
wl_bss_handle_sae_auth_v2(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * event,void * data)11018 wl_bss_handle_sae_auth_v2(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11019 	const wl_event_msg_t *event, void *data)
11020 {
11021 	int err = BCME_OK;
11022 	wl_auth_event_t *auth_data;
11023 	wl_sae_key_info_t sae_key;
11024 	uint16 tlv_buf_len;
11025 	uint8 ssid[DOT11_MAX_SSID_LEN];
11026 	const uint8 *tmp_buf;
11027 	uint16 ssid_len;
11028 	uint16 type_len;
11029 	uint32 type;
11030 	pmkid_v3_t *t_pmkid = NULL;
11031 
11032 	auth_data = (wl_auth_event_t *)data;
11033 
11034 	tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V2;
11035 
11036 	/* check if PMK info present */
11037 	sae_key.pmk = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11038 		WL_AUTH_PMK_TLV_ID, &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
11039 	if (!sae_key.pmk || !sae_key.pmk_len) {
11040 		WL_ERR(("Mandatory PMK info not present"));
11041 		err = BCME_NOTFOUND;
11042 		goto done;
11043 	}
11044 	/* check if PMKID info present */
11045 	sae_key.pmkid = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11046 		WL_AUTH_PMKID_TLV_ID, &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
11047 	if (!sae_key.pmkid || !sae_key.pmkid_len) {
11048 		WL_ERR(("Mandatory PMKID info not present\n"));
11049 		err = BCME_NOTFOUND;
11050 		goto done;
11051 	}
11052 	(void)memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet, ETHER_ADDR_LEN);
11053 
11054 	tmp_buf = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11055 		WL_AUTH_PMKID_TYPE_TLV_ID, &type_len, BCM_XTLV_OPTION_ALIGN32);
11056 
11057 	memcpy(&type, tmp_buf, MIN(type_len, sizeof(type)));
11058 	if (type == WL_AUTH_PMKID_TYPE_SSID) {
11059 		int idx;
11060 		int idx2;
11061 		pmkid_list_v3_t *spmk_list = &cfg->spmk_info_list->pmkids;
11062 
11063 		tmp_buf = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11064 			WL_AUTH_SSID_TLV_ID, &ssid_len, BCM_XTLV_OPTION_ALIGN32);
11065 		if (tmp_buf == NULL) {
11066 			return BCME_ERROR;
11067 		}
11068 		bzero(ssid, sizeof(ssid));
11069 		(void)memcpy_s(ssid, sizeof(ssid), tmp_buf, MIN(sizeof(ssid), ssid_len));
11070 		for (idx = 0; idx < spmk_list->count; idx++) {
11071 			t_pmkid = &spmk_list->pmkid[idx];
11072 			if (ssid_len == t_pmkid->ssid_len &&
11073 				!memcmp(ssid, t_pmkid->ssid, MIN(sizeof(ssid), ssid_len))) {
11074 				break;
11075 			}
11076 		}
11077 		if (idx >= spmk_list->count) {
11078 			if (spmk_list->count == MAXPMKID) {
11079 				/* remove oldest PMK info */
11080 				for (idx2 = 0; idx2 < spmk_list->count - 1; idx2++) {
11081 					(void)memcpy_s(&spmk_list->pmkid[idx2], sizeof(pmkid_v3_t),
11082 						&spmk_list->pmkid[idx2 + 1], sizeof(pmkid_v3_t));
11083 				}
11084 				t_pmkid = &spmk_list->pmkid[spmk_list->count - 1];
11085 			} else {
11086 				t_pmkid = &spmk_list->pmkid[spmk_list->count++];
11087 			}
11088 		}
11089 		if (!t_pmkid) {
11090 			WL_ERR(("SPMK TPMKID is null\n"));
11091 			return BCME_NOTFOUND;
11092 		}
11093 		bzero(t_pmkid, sizeof(pmkid_v3_t));
11094 		memcpy(&t_pmkid->bssid, event->addr.octet, 6);
11095 		t_pmkid->ssid_len = ssid_len;
11096 		err = memcpy_s(t_pmkid->ssid, sizeof(t_pmkid->ssid), ssid, ssid_len);
11097 		if (err != BCME_OK) {
11098 			goto done;
11099 		}
11100 		/* COPY but not used */
11101 		t_pmkid->pmkid_len = sae_key.pmkid_len;
11102 		memcpy(t_pmkid->pmkid, sae_key.pmkid, sae_key.pmkid_len);
11103 		t_pmkid->pmk_len = sae_key.pmk_len;
11104 		memcpy(t_pmkid->pmk, sae_key.pmk, sae_key.pmk_len);
11105 	}
11106 
11107 	err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
11108 	if (err) {
11109 		WL_ERR(("Failed to event sae key info\n"));
11110 	}
11111 done:
11112 	return err;
11113 }
11114 
11115 s32
wl_bss_handle_sae_auth(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * event,void * data)11116 wl_bss_handle_sae_auth(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11117 	const wl_event_msg_t *event, void *data)
11118 {
11119 	int err = BCME_OK;
11120 	uint status = ntoh32(event->status);
11121 	wl_auth_event_t *auth_data;
11122 
11123 	if (status == WLC_E_STATUS_SUCCESS) {
11124 		auth_data = (wl_auth_event_t *)data;
11125 		if (auth_data->version == WL_AUTH_EVENT_DATA_V1) {
11126 			err = wl_bss_handle_sae_auth_v1(cfg, ndev, event, data);
11127 		} else if (auth_data->version == WL_AUTH_EVENT_DATA_V2) {
11128 			err = wl_bss_handle_sae_auth_v2(cfg, ndev, event, data);
11129 		} else {
11130 			WL_ERR(("unknown auth event data version %x\n",
11131 				auth_data->version));
11132 			err = BCME_VERSION;
11133 		}
11134 	}
11135 	WL_INFORM_MEM(("SAE AUTH status:%d ret: %d\n", status, err));
11136 	return err;
11137 }
11138 #endif /* WL_SAE */
11139 
11140 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
11141 enum {
11142 	BIGDATA_ASSOC_REJECT_NO_ACK = 1,
11143 	BIGDATA_ASSOC_REJECT_FAIL = 2,
11144 	BIGDATA_ASSOC_REJECT_UNSOLICITED = 3,
11145 	BIGDATA_ASSOC_REJECT_TIMEOUT = 4,
11146 	BIGDATA_ASSOC_REJECT_ABORT = 5,
11147 	BIGDATA_ASSOC_REJECT_NO_NETWWORKS = 6,
11148 	BIGDATA_ASSOC_REJECT_MAX = 50
11149 };
11150 
wl_get_connect_failed_status(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)11151 int wl_get_connect_failed_status(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
11152 {
11153 	u32 status = ntoh32(e->status);
11154 
11155 	cfg->assoc_reject_status = 0;
11156 
11157 	if (status != WLC_E_STATUS_SUCCESS) {
11158 		WL_INFORM(("auth assoc status event=%d e->status %d e->reason %d \n",
11159 			ntoh32(cfg->event_auth_assoc.event_type),
11160 			(int)ntoh32(cfg->event_auth_assoc.status),
11161 			(int)ntoh32(cfg->event_auth_assoc.reason)));
11162 
11163 		/* Populate status based on cached auth/assoc status value */
11164 		switch ((int)ntoh32(cfg->event_auth_assoc.status)) {
11165 			case WLC_E_STATUS_NO_ACK:
11166 				cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_NO_ACK;
11167 				break;
11168 			case WLC_E_STATUS_FAIL:
11169 				cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_FAIL;
11170 				break;
11171 			case WLC_E_STATUS_UNSOLICITED:
11172 				cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_UNSOLICITED;
11173 				break;
11174 			case WLC_E_STATUS_TIMEOUT:
11175 				cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_TIMEOUT;
11176 				break;
11177 			case WLC_E_STATUS_ABORT:
11178 				cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_ABORT;
11179 				break;
11180 			case WLC_E_STATUS_SUCCESS:
11181 				if (status == WLC_E_STATUS_NO_NETWORKS) {
11182 					cfg->assoc_reject_status =
11183 						BIGDATA_ASSOC_REJECT_NO_NETWWORKS;
11184 					break;
11185 				}
11186 			default:
11187 				cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_MAX;
11188 				break;
11189 		}
11190 		if (cfg->assoc_reject_status) {
11191 			if (ntoh32(cfg->event_auth_assoc.event_type) == WLC_E_ASSOC) {
11192 				cfg->assoc_reject_status += BIGDATA_ASSOC_REJECT_MAX;
11193 			}
11194 		}
11195 	}
11196 
11197 	WL_INFORM_MEM(("assoc_reject_status %d \n", cfg->assoc_reject_status));
11198 
11199 	return 0;
11200 }
11201 
wl_cfg80211_get_connect_failed_status(struct net_device * dev,char * cmd,int total_len)11202 s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len)
11203 {
11204 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11205 	int bytes_written = 0;
11206 
11207 	if (cfg == NULL) {
11208 		return -1;
11209 	}
11210 	bytes_written = snprintf(cmd, total_len, "assoc_reject.status %d",
11211 			cfg->assoc_reject_status);
11212 	WL_ERR(("cmd: %s \n", cmd));
11213 	return bytes_written;
11214 }
11215 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
11216 
11217 static s32
wl_notify_connect_status_ibss(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)11218 wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11219 	const wl_event_msg_t *e, void *data)
11220 {
11221 	s32 err = 0;
11222 	u32 event = ntoh32(e->event_type);
11223 	u16 flags = ntoh16(e->flags);
11224 	u32 status =  ntoh32(e->status);
11225 	bool active;
11226 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11227 	struct ieee80211_channel *channel = NULL;
11228 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
11229 	chanspec_t chanspec;
11230 	u32 freq;
11231 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
11232 
11233 	if (event == WLC_E_JOIN) {
11234 		WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev->name));
11235 	}
11236 	if (event == WLC_E_START) {
11237 		WL_INFORM_MEM(("[%s] started IBSS network\n", ndev->name));
11238 	}
11239 	if (event == WLC_E_JOIN || event == WLC_E_START ||
11240 		(event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
11241 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11242 		err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
11243 		if (unlikely(err)) {
11244 			WL_ERR(("Could not get chanspec %d\n", err));
11245 			return err;
11246 		}
11247 		chanspec = wl_chspec_driver_to_host(chanspec);
11248 		freq = wl_channel_to_frequency(wf_chspec_ctlchan(chanspec), CHSPEC_BAND(chanspec));
11249 		channel = ieee80211_get_channel(wiphy, freq);
11250 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
11251 		if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
11252 			/* ROAM or Redundant */
11253 			u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
11254 			if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
11255 				WL_DBG(("IBSS connected event from same BSSID("
11256 					MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
11257 				return err;
11258 			}
11259 			WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
11260 				ndev->name, MAC2STRDBG(cur_bssid),
11261 				MAC2STRDBG((const u8 *)&e->addr)));
11262 			wl_get_assoc_ies(cfg, ndev);
11263 			wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
11264 			wl_update_bss_info(cfg, ndev, false);
11265 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11266 			cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
11267 #else
11268 			cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
11269 #endif
11270 		}
11271 		else {
11272 			/* New connection */
11273 			WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG "\n",
11274 				ndev->name, MAC2STRDBG((const u8 *)&e->addr)));
11275 			wl_link_up(cfg);
11276 			wl_get_assoc_ies(cfg, ndev);
11277 			wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
11278 			wl_update_bss_info(cfg, ndev, false);
11279 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11280 			cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
11281 #else
11282 			cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
11283 #endif
11284 			wl_set_drv_status(cfg, CONNECTED, ndev);
11285 			active = true;
11286 			wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
11287 		}
11288 	} else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
11289 		event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
11290 		wl_clr_drv_status(cfg, CONNECTED, ndev);
11291 		wl_link_down(cfg);
11292 		wl_init_prof(cfg, ndev);
11293 	}
11294 	else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
11295 		WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
11296 	}
11297 	else {
11298 		WL_DBG(("no action (IBSS mode)\n"));
11299 }
11300 	return err;
11301 }
11302 
11303 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
11304 #define WiFiALL_OUI         "\x50\x6F\x9A"  /* Wi-FiAll OUI */
11305 #define WiFiALL_OUI_LEN     3
11306 #define WiFiALL_OUI_TYPE    16
11307 
11308 /* 11kv feature flag for big data */
11309 #define WL_BIGDATA_11KV_QBSSLOAD		0x00000001
11310 #define WL_BIGDATA_11KV_PROXYARP		0x00000002
11311 #define WL_BIGDATA_11KV_TFS			0x00000004
11312 #define WL_BIGDATA_11KV_SLEEP			0x00000008
11313 #define WL_BIGDATA_11KV_TIMBC			0x00000010
11314 #define WL_BIGDATA_11KV_BSSTRANS		0x00000020
11315 #define WL_BIGDATA_11KV_DMS			0x00000040
11316 #define WL_BIGDATA_11KV_LINK_MEA		0x00000080
11317 #define WL_BIGDATA_11KV_NBRREP			0x00000100
11318 #define WL_BIGDATA_11KV_BCNPASSIVE		0x00000200
11319 #define WL_BIGDATA_11KV_BCNACTIVE		0x00000400
11320 #define WL_BIGDATA_11KV_BCNTABLE		0x00000800
11321 #define WL_BIGDATA_11KV_BSSAAD			0x00001000
11322 #define WL_BIGDATA_11KV_MAX			0x00002000
11323 
11324 #define WL_BIGDATA_SUPPORT_11K		0x00000001
11325 #define WL_BIGDATA_SUPPORT_11V		0x00000002
11326 
11327 typedef struct {
11328 	uint8	bitmap;
11329 	uint8	octet_len;
11330 	uint32	flag;
11331 } bigdata_11kv_t;
11332 
11333 bigdata_11kv_t bigdata_11k_info[] = {
11334 	{DOT11_RRM_CAP_LINK, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_LINK_MEA},
11335 	{DOT11_RRM_CAP_NEIGHBOR_REPORT, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_NBRREP},
11336 	{DOT11_RRM_CAP_BCN_PASSIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNPASSIVE},
11337 	{DOT11_RRM_CAP_BCN_ACTIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNACTIVE},
11338 	{DOT11_RRM_CAP_BCN_TABLE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNTABLE},
11339 	{DOT11_RRM_CAP_BSSAAD, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BSSAAD},
11340 };
11341 
11342 bigdata_11kv_t bigdata_11v_info[] = {
11343 	{DOT11_EXT_CAP_PROXY_ARP, DOT11_EXTCAP_LEN_PROXY_ARP, WL_BIGDATA_11KV_PROXYARP},
11344 	{DOT11_EXT_CAP_TFS, DOT11_EXTCAP_LEN_TFS, WL_BIGDATA_11KV_TFS},
11345 	{DOT11_EXT_CAP_WNM_SLEEP, DOT11_EXTCAP_LEN_WNM_SLEEP, WL_BIGDATA_11KV_SLEEP},
11346 	{DOT11_EXT_CAP_TIMBC, DOT11_EXTCAP_LEN_TIMBC, WL_BIGDATA_11KV_TIMBC},
11347 	{DOT11_EXT_CAP_BSSTRANS_MGMT, DOT11_EXTCAP_LEN_BSSTRANS, WL_BIGDATA_11KV_BSSTRANS},
11348 	{DOT11_EXT_CAP_DMS, DOT11_EXTCAP_LEN_DMS, WL_BIGDATA_11KV_DMS}
11349 };
11350 
11351 static void
wl_get_11kv_info(u8 * ie,u32 ie_len,uint8 * support_11kv,uint32 * flag_11kv)11352 wl_get_11kv_info(u8 *ie, u32 ie_len, uint8 *support_11kv, uint32 *flag_11kv)
11353 {
11354 	bcm_tlv_t *ie_11kv = NULL;
11355 	uint32 flag_11k = 0, flag_11v = 0;
11356 	int i;
11357 
11358 	/* parsing QBSS load ie */
11359 	if ((bcm_parse_tlvs(ie, (u32)ie_len,
11360 			DOT11_MNG_QBSS_LOAD_ID)) != NULL) {
11361 		flag_11k |= WL_BIGDATA_11KV_QBSSLOAD;
11362 	}
11363 
11364 	/* parsing RM IE for 11k */
11365 	if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
11366 			DOT11_MNG_RRM_CAP_ID)) != NULL) {
11367 		for (i = 0; i < ARRAYSIZE(bigdata_11k_info); i++) {
11368 			if ((ie_11kv->len >= bigdata_11k_info[i].octet_len) &&
11369 					isset(ie_11kv->data, bigdata_11k_info[i].bitmap)) {
11370 				flag_11k |= bigdata_11k_info[i].flag;
11371 			}
11372 		}
11373 	}
11374 
11375 	/* parsing extended cap. IE for 11v */
11376 	if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
11377 			DOT11_MNG_EXT_CAP_ID)) != NULL) {
11378 		for (i = 0; i < ARRAYSIZE(bigdata_11v_info); i++) {
11379 			if ((ie_11kv->len >= bigdata_11v_info[i].octet_len) &&
11380 					isset(ie_11kv->data, bigdata_11v_info[i].bitmap)) {
11381 				flag_11v |= bigdata_11v_info[i].flag;
11382 			}
11383 		}
11384 	}
11385 
11386 	if (flag_11k > 0) {
11387 		*support_11kv |= WL_BIGDATA_SUPPORT_11K;
11388 	}
11389 
11390 	if (flag_11v > 0) {
11391 		*support_11kv |= WL_BIGDATA_SUPPORT_11V;
11392 	}
11393 
11394 	*flag_11kv = flag_11k | flag_11v;
11395 }
11396 
wl_get_bss_info(struct bcm_cfg80211 * cfg,struct net_device * dev,const u8 * mac)11397 int wl_get_bss_info(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *mac)
11398 {
11399 	s32 err = 0;
11400 	wl_bss_info_v109_1_t *bi;
11401 	uint8 eabuf[ETHER_ADDR_LEN];
11402 	u32 rate, channel, freq, supported_rate, nss = 0, mcs_map, mode_80211 = 0;
11403 	char rate_str[4];
11404 	u8 *ie = NULL;
11405 	u32 ie_len;
11406 	struct wiphy *wiphy;
11407 	struct cfg80211_bss *bss;
11408 	bcm_tlv_t *interworking_ie = NULL;
11409 	bcm_tlv_t *tlv_ie = NULL;
11410 	bcm_tlv_t *vht_ie = NULL;
11411 	vndr_ie_t *vndrie;
11412 	int16 ie_11u_rel_num = -1, ie_mu_mimo_cap = -1;
11413 	u32 i, remained_len, count = 0;
11414 	char roam_count_str[4], akm_str[4];
11415 	s32 val = 0;
11416 	uint8 support_11kv = 0;
11417 	uint32 flag_11kv = 0;	/* bit flags of 11kv big data */
11418 	int cfg_bss_info_len = 0;
11419 
11420 	/* get BSS information */
11421 
11422 	strlcpy(cfg->bss_info, "x x x x x x x x x x x x x x x x x", sizeof(cfg->bss_info));
11423 
11424 	*(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
11425 
11426 	err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, cfg->extra_buf, WL_EXTRA_BUF_MAX);
11427 	if (unlikely(err)) {
11428 		WL_ERR(("Could not get bss info %d\n", err));
11429 		cfg->roam_count = 0;
11430 		return -1;
11431 	}
11432 
11433 	if (!mac) {
11434 		WL_ERR(("mac is null \n"));
11435 		cfg->roam_count = 0;
11436 		return -1;
11437 	}
11438 
11439 	memcpy(eabuf, mac, ETHER_ADDR_LEN);
11440 
11441 	bi = (wl_bss_info_v109_1_t *)(cfg->extra_buf + 4);
11442 	channel = wf_chspec_ctlchan(bi->chanspec);
11443 	freq = wl_channel_to_frequency(channel, CHSPEC_BAND(bi->chanspec));
11444 	rate = 0;
11445 	err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
11446 	if (err) {
11447 		WL_ERR(("Could not get rate (%d)\n", err));
11448 		snprintf(rate_str, sizeof(rate_str), "x"); /* Unknown */
11449 
11450 	} else {
11451 		rate = dtoh32(rate);
11452 		snprintf(rate_str, sizeof(rate_str), "%d", (rate/2));
11453 	}
11454 
11455 	/* supported maximum rate */
11456 	supported_rate = (bi->rateset.rates[bi->rateset.count - 1] & 0x7f) / 2;
11457 
11458 	if (supported_rate < 12) {
11459 		mode_80211 = BIGDATA_DOT11_11B_MODE; /* 11b maximum rate is 11Mbps. 11b mode */
11460 	} else {
11461 		/* It's not HT Capable case. */
11462 		if (channel > 14) {
11463 			mode_80211 = BIGDATA_DOT11_11A_MODE; /* 11a mode */
11464 		} else {
11465 			mode_80211 = BIGDATA_DOT11_11G_MODE; /* 11g mode */
11466 		}
11467 	}
11468 
11469 	if (bi->n_cap) {
11470 		/* check Rx MCS Map for HT */
11471 		nss = 0;
11472 		mode_80211 = BIGDATA_DOT11_11N_MODE;
11473 		for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
11474 			int8 bitmap = DOT11_HT_MCS_RATE_MASK;
11475 			if (i == MAX_STREAMS_SUPPORTED-1) {
11476 				bitmap = DOT11_RATE_MASK;
11477 			}
11478 			if (bi->basic_mcs[i] & bitmap) {
11479 				nss++;
11480 			}
11481 		}
11482 	}
11483 
11484 	if (bi->vht_cap) {
11485 		nss = 0;
11486 		mode_80211 = BIGDATA_DOT11_11AC_MODE;
11487 		for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
11488 			mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
11489 			if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
11490 				nss++;
11491 			}
11492 		}
11493 	}
11494 
11495 #if defined(WL11AX)
11496 	if (bi->he_cap) {
11497 		nss = 0;
11498 		mode_80211 = BIGDATA_DOT11_11AX_MODE;
11499 		for (i = 1; i <= HE_MCS_MAP_NSS_MAX; i++) {
11500 			mcs_map = HE_MCS_NSS_GET_MCS(i, dtoh32(bi->he_rxmcsmap));
11501 			if (mcs_map != HE_MCS_CODE_NONE) {
11502 				nss++;
11503 			}
11504 		}
11505 	}
11506 #endif /* WL11AX */
11507 
11508 	if (nss) {
11509 		nss = nss - 1;
11510 	}
11511 
11512 	wiphy = bcmcfg_to_wiphy(cfg);
11513 	bss = CFG80211_GET_BSS(wiphy, NULL, eabuf, bi->SSID, bi->SSID_len);
11514 	if (!bss) {
11515 		WL_ERR(("Could not find the AP\n"));
11516 	} else {
11517 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
11518 #if defined(WL_CFG80211_P2P_DEV_IF)
11519 		ie = (u8 *)bss->ies->data;
11520 		ie_len = bss->ies->len;
11521 #else
11522 		ie = bss->information_elements;
11523 		ie_len = bss->len_information_elements;
11524 #endif /* WL_CFG80211_P2P_DEV_IF */
11525 		GCC_DIAGNOSTIC_POP();
11526 	}
11527 
11528 	if (ie) {
11529 		ie_mu_mimo_cap = 0;
11530 		ie_11u_rel_num = 0;
11531 
11532 		if (bi->vht_cap) {
11533 			if ((vht_ie = bcm_parse_tlvs(ie, ie_len,
11534 					DOT11_MNG_VHT_CAP_ID)) != NULL) {
11535 					if (vht_ie->len >= VHT_CAP_IE_LEN) {
11536 						ie_mu_mimo_cap = (vht_ie->data[2] & 0x08) >> 3;
11537 					}
11538 			}
11539 		}
11540 
11541 		if ((interworking_ie = bcm_parse_tlvs(ie, ie_len,
11542 				DOT11_MNG_INTERWORKING_ID)) != NULL) {
11543 			if ((tlv_ie = bcm_parse_tlvs(ie, ie_len, DOT11_MNG_VS_ID)) != NULL) {
11544 				remained_len = ie_len;
11545 
11546 				while (tlv_ie) {
11547 					if (count > MAX_VNDR_IE_NUMBER)
11548 						break;
11549 
11550 					if (tlv_ie->id == DOT11_MNG_VS_ID) {
11551 						vndrie = (vndr_ie_t *) tlv_ie;
11552 
11553 						if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
11554 							WL_ERR(("wl_get_bss_info: invalid vndr ie."
11555 								"length is too small %d\n",
11556 								vndrie->len));
11557 							break;
11558 						}
11559 
11560 						if (!bcmp(vndrie->oui,
11561 							(u8*)WiFiALL_OUI, WiFiALL_OUI_LEN) &&
11562 							(vndrie->data[0] == WiFiALL_OUI_TYPE))
11563 						{
11564 							WL_ERR(("Found Wi-FiAll OUI oui.\n"));
11565 							ie_11u_rel_num = vndrie->data[1];
11566 							ie_11u_rel_num = (ie_11u_rel_num & 0xf0)>>4;
11567 							ie_11u_rel_num += 1;
11568 
11569 							break;
11570 						}
11571 					}
11572 					count++;
11573 					tlv_ie = bcm_next_tlv(tlv_ie, &remained_len);
11574 				}
11575 			}
11576 		}
11577 
11578 		/* get 11kv information from ie of current bss */
11579 		wl_get_11kv_info(ie, ie_len, &support_11kv, &flag_11kv);
11580 	}
11581 
11582 	for (i = 0; i < bi->SSID_len; i++) {
11583 		if (bi->SSID[i] == ' ') {
11584 			bi->SSID[i] = '_';
11585 		}
11586 	}
11587 
11588 	/* 0 : None, 1 : OKC, 2 : FT, 3 : CCKM */
11589 	err = wldev_iovar_getint(dev, "wpa_auth", &val);
11590 	if (unlikely(err)) {
11591 		WL_ERR(("could not get wpa_auth (%d)\n", err));
11592 		snprintf(akm_str, sizeof(akm_str), "x"); /* Unknown */
11593 	} else {
11594 		WL_ERR(("wpa_auth val %d \n", val));
11595 			if (val & WPA2_AUTH_FT) {
11596 				snprintf(akm_str, sizeof(akm_str), "2");
11597 			} else if (val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) {
11598 				snprintf(akm_str, sizeof(akm_str), "1");
11599 			} else {
11600 				snprintf(akm_str, sizeof(akm_str), "0");
11601 			}
11602 	}
11603 
11604 	if (cfg->roam_offload) {
11605 		snprintf(roam_count_str, sizeof(roam_count_str), "x"); /* Unknown */
11606 	} else {
11607 		snprintf(roam_count_str, sizeof(roam_count_str), "%d", cfg->roam_count);
11608 	}
11609 	cfg->roam_count = 0;
11610 
11611 	WL_ERR(("BSSID:" MACDBG " SSID %s \n", MAC2STRDBG(eabuf), "*****"));
11612 	WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d,"
11613 				"MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n"
11614 				"akm:%s, roam:%s, 11kv:%d/%d \n",
11615 				freq, wf_chspec_to_bw_str(bi->chanspec),
11616 				dtoh32(bi->RSSI), (rate / 2), mode_80211, nss,
11617 				ie_mu_mimo_cap, ie_11u_rel_num, bi->SNR, bi->phy_noise,
11618 				akm_str, roam_count_str, support_11kv, flag_11kv));
11619 
11620 	if (ie) {
11621 		snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
11622 				MACOUI" %d %s %d %s %d %d %d %d %d %d %s %s %d %d",
11623 				MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
11624 				dtoh32(bi->RSSI), rate_str, mode_80211, nss, ie_mu_mimo_cap,
11625 				ie_11u_rel_num, bi->SNR, bi->phy_noise, akm_str, roam_count_str,
11626 				support_11kv, flag_11kv);
11627 	} else {
11628 		/* ie_mu_mimo_cap and ie_11u_rel_num is unknow. */
11629 		snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
11630 				MACOUI" %d %s %d %s %d %d x x %d %d %s %s x x",
11631 				MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
11632 				dtoh32(bi->RSSI), rate_str, mode_80211, nss, bi->SNR,
11633 				bi->phy_noise, akm_str, roam_count_str);
11634 	}
11635 
11636 	cfg_bss_info_len = strlen(cfg->bss_info);
11637 	if (GET_BSS_INFO_LEN > cfg_bss_info_len) {
11638 		uint16 full_cnt = 0, partial_cnt = 0;
11639 		bool cnt_valid = FALSE;
11640 
11641 #if defined(DHD_PUB_ROAM_EVT)
11642 		wl_roam_stats_v1_t *roam_elem =
11643 			(wl_roam_stats_v1_t *)dhd_get_roam_evt((dhd_pub_t *)cfg->pub);
11644 
11645 		if (roam_elem && roam_elem->version == WL_ROAM_STATS_VER_1) {
11646 			wl_roam_stats_v1_t *roam_elem_v1;
11647 			roam_elem_v1 = (wl_roam_stats_v1_t *)(uintptr_t)roam_elem;
11648 
11649 			cnt_valid = TRUE;
11650 			full_cnt = roam_elem_v1->full_roam_scan_cnt;
11651 			partial_cnt = roam_elem_v1->partial_roam_scan_cnt;
11652 		}
11653 #endif /* DHD_PUB_ROAM_EVT */
11654 		if (cnt_valid) {
11655 			WL_ERR(("GET_BSS: full roam scan count:%d partial roam scan count:%d\n",
11656 				full_cnt, partial_cnt));
11657 			snprintf(&cfg->bss_info[cfg_bss_info_len],
11658 				GET_BSS_INFO_LEN - cfg_bss_info_len, " %d %d",
11659 				full_cnt, partial_cnt);
11660 		} else {
11661 			WL_ERR(("GET_BSS: roam scan count invalid\n"));
11662 			snprintf(&cfg->bss_info[cfg_bss_info_len],
11663 				GET_BSS_INFO_LEN - cfg_bss_info_len, " x x");
11664 		}
11665 	} else {
11666 		WL_ERR(("Buffer to short to save roam info\n"));
11667 	}
11668 
11669 	CFG80211_PUT_BSS(wiphy, bss);
11670 
11671 	return 0;
11672 }
11673 
wl_cfg80211_get_bss_info(struct net_device * dev,char * cmd,int total_len)11674 s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len)
11675 {
11676 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11677 
11678 	if (cfg == NULL) {
11679 		return -1;
11680 	}
11681 
11682 	if (total_len < GET_BSS_INFO_LEN) {
11683 		WL_ERR(("wl_cfg80211_get_bss_info: Buffer insuffient %d\n", total_len));
11684 		return -1;
11685 	}
11686 
11687 	bzero(cmd, total_len);
11688 	memcpy(cmd, cfg->bss_info, GET_BSS_INFO_LEN);
11689 
11690 	WL_ERR_KERN(("cmd: %s \n", cmd));
11691 
11692 	return GET_BSS_INFO_LEN;
11693 }
11694 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
11695 
wl_cfg80211_disassoc(struct net_device * ndev,uint32 reason)11696 void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason)
11697 {
11698 	scb_val_t scbval;
11699 	s32 err;
11700 #ifdef BCMDONGLEHOST
11701 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
11702 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11703 
11704 	BCM_REFERENCE(cfg);
11705 	BCM_REFERENCE(dhdp);
11706 	DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
11707 		dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
11708 #endif /* BCMDONGLEHOST */
11709 
11710 	memset_s(&scbval, sizeof(scb_val_t), 0x0, sizeof(scb_val_t));
11711 	scbval.val = htod32(reason);
11712 	err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
11713 	if (err < 0) {
11714 		WL_ERR(("WLC_DISASSOC error %d\n", err));
11715 	} else {
11716 		WL_INFORM_MEM(("wl disassoc. reason:%d\n", reason));
11717 	}
11718 }
wl_cfg80211_del_all_sta(struct net_device * ndev,uint32 reason)11719 void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason)
11720 {
11721 	struct net_device *dev;
11722 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
11723 	scb_val_t scb_val;
11724 	int err;
11725 	char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
11726 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
11727 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
11728 	int num_associated = 0;
11729 
11730 	dev = ndev_to_wlc_ndev(ndev, cfg);
11731 
11732 	if (p2p_is_on(cfg)) {
11733 		/* Suspend P2P discovery search-listen to prevent it from changing the
11734 		 * channel.
11735 		 */
11736 		if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
11737 			WL_ERR(("Can not disable discovery mode\n"));
11738 			return;
11739 		}
11740 	}
11741 
11742 	assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
11743 	err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
11744 		assoc_maclist, sizeof(mac_buf));
11745 	if (err < 0)
11746 		WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
11747 	else
11748 		num_associated = assoc_maclist->count;
11749 
11750 	memset(scb_val.ea.octet, 0xff, ETHER_ADDR_LEN);
11751 	scb_val.val = DOT11_RC_DEAUTH_LEAVING;
11752 	scb_val.val = htod32(reason);
11753 	err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
11754 			sizeof(scb_val_t));
11755 	if (err < 0) {
11756 		WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
11757 	}
11758 
11759 	/* WAR Wait for the deauth event to come, supplicant will do the
11760 	 * delete iface immediately and we will have problem in sending
11761 	 * deauth frame if we delete the bss in firmware
11762 	 * But we do not need additional delays for this WAR
11763 	 * during P2P connection.
11764 	 *
11765 	 * Supplicant call this function with BCAST after doing
11766 	 * wl_cfg80211_del_station() all GC stations with each addr.
11767 	 * So, 400 ms delay can be called only once when GO disconnect all GC
11768 	*/
11769 	if (num_associated > 0)
11770 		wl_delay(400);
11771 
11772 	return;
11773 }
11774 /* API to handle the Deauth from the AP.
11775 * For now we are deleting the PMKID cache in DHD/FW
11776 * in case of current connection is using SAE authnetication
11777 */
11778 static s32
wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)11779 wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
11780 {
11781 	int err = BCME_OK;
11782 #ifdef WL_SAE
11783 	struct net_device *ndev = as->ndev;
11784 	const wl_event_msg_t *e = as->event_msg;
11785 	uint8 bssid[ETHER_ADDR_LEN];
11786 	struct cfg80211_pmksa pmksa;
11787 	s32 val = 0;
11788 	struct wlc_ssid *curssid;
11789 	pmkid_list_v3_t *spmk_list = &cfg->spmk_info_list->pmkids;
11790 	pmkid_v3_t *t_pmkid = NULL;
11791 	int idx;
11792 	bool bFound = FALSE;
11793 #endif /* WL_SAE */
11794 
11795 	if (as->reason > WLC_E_DEAUTH_MAX_REASON) {
11796 		/* Specific AP send deauth by invalid reason.
11797 		 * If reason over 0x8XXX, framework trigger recovery.
11798 		 * Framework check HANG_REASON_MASK(0x8000) with reason.
11799 		 */
11800 		WL_ERR(("Event %d original reason is %d, "
11801 			"changed 0xFF\n", as->event_type, as->reason));
11802 		as->reason = WLC_E_DEAUTH_MAX_REASON;
11803 	}
11804 #ifdef WL_SAE
11805 	err = wldev_iovar_getint(ndev, "wpa_auth", &val);
11806 	if (unlikely(err)) {
11807 		WL_ERR(("could not get wpa_auth (%d)\n", err));
11808 		goto done;
11809 	}
11810 	if (val == WPA3_AUTH_SAE_PSK) {
11811 		(void)memcpy_s(bssid, ETHER_ADDR_LEN,
11812 		(const uint8*)&e->addr, ETHER_ADDR_LEN);
11813 		memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
11814 		pmksa.bssid = bssid;
11815 		WL_INFORM_MEM(("Deleting the PMKSA for SAE AP "MACDBG,
11816 			MAC2STRDBG(e->addr.octet)));
11817 		wl_cfg80211_del_pmksa(cfg->wdev->wiphy, ndev, &pmksa);
11818 		curssid = wl_read_prof(cfg, ndev, WL_PROF_SSID);
11819 		for (idx = 0; idx < spmk_list->count; idx++) {
11820 			t_pmkid = &spmk_list->pmkid[idx];
11821 			if (curssid->SSID_len == t_pmkid->ssid_len &&
11822 				!memcmp(curssid->SSID, t_pmkid->ssid, curssid->SSID_len)) {
11823 				bFound = TRUE;
11824 				break;
11825 			}
11826 		}
11827 		if (!bFound) {
11828 			goto done;
11829 		}
11830 		for (; idx < spmk_list->count - 1; idx++) {
11831 			memcpy_s(&spmk_list->pmkid[idx], sizeof(pmkid_v3_t),
11832 				&spmk_list->pmkid[idx + 1], sizeof(pmkid_v3_t));
11833 		}
11834 		spmk_list->count--;
11835 	}
11836 done:
11837 #endif /* WL_SAE */
11838 	return err;
11839 }
11840 
11841 static void
wl_cache_assoc_resp_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)11842 wl_cache_assoc_resp_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11843 	const wl_event_msg_t *e, void *data)
11844 {
11845 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
11846 	u32 datalen = ntoh32(e->datalen);
11847 	u32 event_type = ntoh32(e->event_type);
11848 
11849 	if (data && datalen <= sizeof(conn_info->resp_ie)) {
11850 		conn_info->resp_ie_len = datalen;
11851 		WL_DBG((" assoc resp IES len = %d\n", conn_info->resp_ie_len));
11852 		bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
11853 		(void)memcpy_s(conn_info->resp_ie, sizeof(conn_info->resp_ie),
11854 			data, datalen);
11855 
11856 		WL_INFORM_MEM(("[%s] cached assoc resp ies"
11857 			"event %d reason=%d ie_len=%d from " MACDBG "\n",
11858 			ndev->name,	event_type, ntoh32(e->reason), datalen,
11859 			MAC2STRDBG((const u8*)(&e->addr))));
11860 	}
11861 }
11862 
11863 char *
wl_get_link_action_str(u16 link_action)11864 wl_get_link_action_str(u16 link_action)
11865 {
11866 	switch (link_action) {
11867 	case WL_LINK_NONE:
11868 		return "LINK_NONE";
11869 	case WL_LINK_ASSOC_FAIL:
11870 		return "ASSOC_FAIL";
11871 	case WL_LINK_ASSOC_DONE:
11872 		return "ASSOC_DONE";
11873 	case WL_LINK_DOWN:
11874 		return "LINK_DOWN";
11875 	case WL_LINK_ROAM_DONE:
11876 		return "ROAM_DONE";
11877 	case WL_LINK_FORCE_DEAUTH:
11878 		return "SEND_DEAUTH";
11879 	default:
11880 		return "UNKOWN_STATE";
11881 	}
11882 }
11883 
11884 char *
wl_get_assoc_state_str(u16 assoc_state)11885 wl_get_assoc_state_str(u16 assoc_state)
11886 {
11887 	switch (assoc_state) {
11888 	case WL_STATE_ASSOC_IDLE:
11889 		return "ASSOC_IDLE";
11890 	case WL_STATE_ASSOCIATING:
11891 		return "ASSOCIATING";
11892 	case WL_STATE_ASSOCIATED:
11893 		return "ASSOCIATED";
11894 	default:
11895 		return "UNKOWN_STATE";
11896 	}
11897 }
11898 
11899 static u32
wl_set_link_action(wl_assoc_state_t assoc_state,bool link_up)11900 wl_set_link_action(wl_assoc_state_t assoc_state, bool link_up)
11901 {
11902 	wl_link_action_t action = WL_LINK_NONE;
11903 
11904 	switch (assoc_state) {
11905 		case WL_STATE_ASSOCIATING:
11906 			if (link_up) {
11907 				action = WL_LINK_ASSOC_DONE;
11908 			} else {
11909 				action = WL_LINK_ASSOC_FAIL;
11910 			}
11911 			break;
11912 		case WL_STATE_ASSOCIATED:
11913 			if (link_up) {
11914 				action = WL_LINK_ROAM_DONE;
11915 			} else {
11916 				action = WL_LINK_DOWN;
11917 			}
11918 			break;
11919 		case WL_STATE_ASSOC_IDLE:
11920 			if (link_up) {
11921 				/* link up while cfg80211 state is not in
11922 				 * 'ASSOCIATING/ASSOCIATED. Sync up the fw
11923 				 *  by disconnecting.
11924 				 */
11925 				WL_ERR(("Unexpected link up\n"));
11926 				action = WL_LINK_FORCE_DEAUTH;
11927 			}
11928 			break;
11929 		default:
11930 			WL_ERR(("unknown state:%d\n", assoc_state));
11931 			action = WL_LINK_NONE;
11932 	}
11933 
11934 	return action;
11935 }
11936 
11937 static void
wl_cfg8021_unlink_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 * bssid)11938 wl_cfg8021_unlink_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 *bssid)
11939 {
11940 	struct cfg80211_bss *bss;
11941 	wlc_ssid_t *ssid;
11942 	struct wireless_dev *wdev = ndev->ieee80211_ptr;
11943 
11944 	ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
11945 	if (ssid && bssid) {
11946 		bss = CFG80211_GET_BSS(wdev->wiphy, NULL, bssid, ssid->SSID, ssid->SSID_len);
11947 		if (bss) {
11948 			cfg80211_unlink_bss(wdev->wiphy, bss);
11949 			CFG80211_PUT_BSS(wdev->wiphy, bss);
11950 			WL_INFORM_MEM(("bss unlinked"));
11951 		}
11952 	}
11953 }
11954 
11955 static s32
wl_post_linkdown_ops(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as,struct net_device * ndev)11956 wl_post_linkdown_ops(struct bcm_cfg80211 *cfg,
11957 	wl_assoc_status_t *as, struct net_device *ndev)
11958 {
11959 	s32 ret = BCME_OK;
11960 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11961 
11962 	/* Common Code for connect failure & link down */
11963 	BCM_REFERENCE(dhdp);
11964 
11965 	WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n",
11966 		wl_get_drv_status(cfg, CONNECTING, ndev),
11967 		wl_get_drv_status(cfg, CONNECTED, ndev),
11968 		wl_get_drv_status(cfg, DISCONNECTING, ndev),
11969 		wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
11970 
11971 	/* clear timestamps on disconnect */
11972 	CLR_TS(cfg, conn_start);
11973 	CLR_TS(cfg, conn_cmplt);
11974 	CLR_TS(cfg, authorize_start);
11975 	CLR_TS(cfg, authorize_cmplt);
11976 
11977 	wl_link_down(cfg);
11978 	wl_clr_drv_status(cfg, AUTHORIZED, ndev);
11979 	wl_clr_drv_status(cfg, CONNECTED, ndev);
11980 	wl_clr_drv_status(cfg, DISCONNECTING, ndev);
11981 
11982 #ifdef DBG_PKT_MON
11983 	if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
11984 		/* Stop packet monitor */
11985 		DHD_DBG_PKT_MON_STOP(dhdp);
11986 	}
11987 #endif /* DHD_PKT_MON */
11988 
11989 	/* Flush preserve logs */
11990 	wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
11991 			FW_LOGSET_MASK_ALL);
11992 
11993 #ifdef WL_GET_RCC
11994 	wl_android_get_roam_scan_chanlist(cfg);
11995 #endif /* WL_GET_RCC */
11996 
11997 #ifdef WES_SUPPORT
11998 	if (cfg->ncho_mode) {
11999 		/* Turn off NCHO mode */
12000 		wl_android_set_ncho_mode(ndev, FALSE);
12001 	}
12002 #endif /* WES_SUPPORT */
12003 
12004 #ifdef WLTDLS
12005 	wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
12006 #endif /* WLTDLS */
12007 
12008 	/* clear RSSI monitor, framework will set new cfg */
12009 #ifdef RSSI_MONITOR_SUPPORT
12010 	dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
12011 		FALSE, 0, 0);
12012 #endif /* RSSI_MONITOR_SUPPORT */
12013 
12014 #ifdef WBTEXT
12015 	wl_cfg80211_wbtext_reset_conf(cfg, as->ndev);
12016 #endif /* WBTEXT */
12017 
12018 #ifdef P2PLISTEN_AP_SAMECHN
12019 	if (as->ndev == bcmcfg_to_prmry_ndev(cfg)) {
12020 		wl_cfg80211_set_p2p_resp_ap_chn(as->ndev, 0);
12021 		cfg->p2p_resp_apchn_status = false;
12022 		WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
12023 	}
12024 #endif /* P2PLISTEN_AP_SAMECHN */
12025 
12026 #ifdef WL_NAN
12027 	if (wl_cfgnan_is_enabled(cfg)) {
12028 		wl_cfgnan_get_stats(cfg);
12029 	}
12030 #endif /* WL_NAN */
12031 
12032 	return ret;
12033 }
12034 
12035 static s32
wl_handle_assoc_fail(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as,bool completed)12036 wl_handle_assoc_fail(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as, bool completed)
12037 {
12038 	s32 ret = BCME_OK;
12039 	struct net_device *ndev = as->ndev;
12040 	u8 *connect_req_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
12041 #ifdef BCMDONGLEHOST
12042 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12043 #endif /* BCMDONGLEHOST */
12044 
12045 #ifdef BCMDONGLEHOST
12046 	BCM_REFERENCE(dhdp);
12047 #endif /* BCMDONGLEHOST */
12048 	WL_INFORM_MEM(("event: %s\n", bcmevent_get_name(as->event_type)));
12049 
12050 	if (connect_req_bssid && !ETHER_ISNULLADDR(as->addr) &&
12051 		memcmp(&as->addr, connect_req_bssid, ETH_ALEN) != 0) {
12052 		WL_ERR(("Event:%d Wrong bssid:" MACDBG "\n", as->event_type, MAC2STRDBG(as->addr)));
12053 		return BCME_OK;
12054 	}
12055 #ifdef WL_EXT_IAPSTA
12056 	wl_ext_iapsta_enable_master_if(ndev, FALSE);
12057 #endif
12058 
12059 	/* A connect request in Connected/Connecting will have the
12060 	 * NESTED_CONNECT state set.
12061 	 */
12062 	if (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) &&
12063 	   wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
12064 		wl_clr_drv_status(cfg, DISCONNECTING, ndev);
12065 		wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
12066 		WL_INFORM_MEM(("Disconnect from nested connect context\n"));
12067 #ifdef WL_EXT_IAPSTA
12068 		wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
12069 			WL_EXT_STATUS_DISCONNECTED, NULL);
12070 #endif
12071 		return BCME_OK;
12072 	}
12073 
12074 #ifdef WL_WPS_SYNC
12075 	if (wl_wps_session_update(ndev,
12076 			WPS_STATE_CONNECT_FAIL, as->addr) == BCME_UNSUPPORTED) {
12077 		/* Skip the event handling */
12078 		return BCME_OK;
12079 	}
12080 #endif /* WL_WPS_SYNC */
12081 
12082 #ifdef BCMDONGLEHOST
12083 	DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
12084 		dhd_net2idx(dhdp->info, ndev), 0);
12085 #endif /* BCMDONGLEHOST */
12086 
12087 #if defined(CONFIG_TIZEN)
12088 	net_stat_tizen_update_wifi(ndev, WIFISTAT_CONNECTION_FAIL);
12089 #endif /* CONFIG_TIZEN */
12090 
12091 	/* if link down, bsscfg is disabled */
12092 	if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
12093 		complete(&cfg->iface_disable);
12094 	}
12095 
12096 	/* Report connect result to upper layer */
12097 	ret = wl_bss_connect_done(cfg, ndev, as->event_msg, as->data, false);
12098 	if (unlikely(ret)) {
12099 		WL_ERR(("connect result reporting failed.\n"));
12100 	}
12101 
12102 	/* Issue WLC_DISASSOC to prevent FW roam attempts. Do not issue
12103 	 * WLC_DISASSOC again if the linkdown  is generated due to local
12104 	 * disassoc, to avoid connect-disconnect loop.
12105 	 */
12106 	if (!((as->event_type == WLC_E_LINK) && (as->reason == WLC_E_LINK_DISASSOC))) {
12107 		wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
12108 	}
12109 
12110 	/* Common handler for assoc fail/link down */
12111 	wl_post_linkdown_ops(cfg, as, as->ndev);
12112 
12113 	return ret;
12114 }
12115 
12116 s32
wl_get_connected_bssid(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 * mac_addr)12117 wl_get_connected_bssid(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 *mac_addr)
12118 {
12119 	u8 bssid_dongle[ETH_ALEN] = {0};
12120 	u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
12121 
12122 	if (!mac_addr) {
12123 		return -EINVAL;
12124 	}
12125 
12126 	/* roam offload does not sync BSSID always, get it from dongle */
12127 	if (cfg->roam_offload) {
12128 		if (wldev_ioctl_get(ndev, WLC_GET_BSSID, bssid_dongle,
12129 				sizeof(bssid_dongle)) == BCME_OK) {
12130 			/* if not roam case, it would return null bssid */
12131 			if (!ETHER_ISNULLADDR(bssid_dongle)) {
12132 				curbssid = (u8 *)&bssid_dongle;
12133 			}
12134 		}
12135 	}
12136 
12137 	if (curbssid) {
12138 		(void)memcpy_s(mac_addr, ETH_ALEN, curbssid, ETH_ALEN);
12139 	}
12140 	return BCME_OK;
12141 }
12142 
12143 #ifdef WBTEXT
12144 static void
wl_cfg80211_wbtext_reset_conf(struct bcm_cfg80211 * cfg,struct net_device * ndev)12145 wl_cfg80211_wbtext_reset_conf(struct bcm_cfg80211 *cfg, struct net_device *ndev)
12146 {
12147 #ifdef BCMDONGLEHOST
12148 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12149 	s32 err;
12150 
12151 	/* when STA was disconnected, clear join pref and set wbtext */
12152 	if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
12153 		dhdp->wbtext_policy
12154 		== WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) {
12155 		char smbuf[WLC_IOCTL_SMLEN];
12156 		if ((err = wldev_iovar_setbuf(ndev, "join_pref",
12157 			NULL, 0, smbuf, sizeof(smbuf), NULL)) == BCME_OK) {
12158 			if ((err = wldev_iovar_setint(ndev, "wnm_bsstrans_resp",
12159 				dhdp->wbtext_policy)) == BCME_OK) {
12160 				wl_cfg80211_wbtext_set_default(ndev);
12161 			} else {
12162 				WL_ERR(("Failed to set wbtext = %d\n", err));
12163 			}
12164 		} else {
12165 			WL_ERR(("Failed to clear join pref = %d\n", err));
12166 		}
12167 		wl_cfg80211_wbtext_clear_bssid_list(cfg);
12168 	} else {
12169 		WL_ERR(("wbtext not applicable\n"));
12170 	}
12171 #endif /* BCMDONGLEHOST */
12172 }
12173 #endif /* WBTEXT */
12174 
12175 static s32
wl_handle_link_down(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)12176 wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
12177 {
12178 	s32 ret = BCME_OK;
12179 #if defined(BCMDONGLEHOST)
12180 	dhd_pub_t *dhdp = (dhd_pub_t *)cfg->pub;
12181 #endif /* BCMDONGLEHOST */
12182 	struct net_device *ndev = as->ndev;
12183 	u32 datalen = as->data_len;
12184 	u32 event = as->event_type;
12185 	u8 *data = as->data;
12186 	u8 *ie_ptr = NULL;
12187 	u16 ie_len = 0;
12188 	bool loc_gen = 0;
12189 	u16 reason = as->reason;
12190 
12191 #ifdef BCMDONGLEHOST
12192 	BCM_REFERENCE(dhdp);
12193 #endif /* BCMDONGLEHOST */
12194 	WL_MSG(ndev->name, "Link down Reason: %s\n", bcmevent_get_name(as->event_type));
12195 	if ((BCME_OK != wl_get_connected_bssid(cfg, ndev, as->curbssid))) {
12196 		WL_ERR(("bssid not found\n"));
12197 		return -1;
12198 	}
12199 
12200 	if (memcmp(as->curbssid, as->addr, ETHER_ADDR_LEN) != 0) {
12201 		WL_ERR(("BSSID of event is not the connected BSSID"
12202 			"(ignore it) cur: " MACDBG
12203 			" event: " MACDBG"\n",
12204 			MAC2STRDBG(as->curbssid),
12205 			MAC2STRDBG((const u8*)(&as->addr))));
12206 		return 0;
12207 	}
12208 
12209 	/* A connect request in Connected/Connecting will have the
12210 	 * NESTED_CONNECT state set.
12211 	 */
12212 	if (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) &&
12213 	   wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
12214 		wl_clr_drv_status(cfg, DISCONNECTING, ndev);
12215 		wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
12216 		WL_INFORM_MEM(("Disconnect from nested connect context\n"));
12217 #ifdef WL_EXT_IAPSTA
12218 		wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
12219 			WL_EXT_STATUS_DISCONNECTED, NULL);
12220 		wl_ext_iapsta_restart_master(ndev);
12221 #endif
12222 		return 0;
12223 	}
12224 
12225 #ifdef WL_WPS_SYNC
12226 	if (wl_wps_session_update(ndev,
12227 		WPS_STATE_LINKDOWN, as->addr) == BCME_UNSUPPORTED) {
12228 		/* Skip event handling */
12229 		return 0;
12230 	}
12231 #endif /* WL_WPS_SYNC */
12232 
12233 	if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
12234 #ifdef BCMDONGLEHOST
12235 		DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
12236 			dhd_net2idx(dhdp->info, ndev),
12237 			WLAN_REASON_DEAUTH_LEAVING);
12238 #endif /* BCMDONGLEHOST */
12239 		wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
12240 	}
12241 
12242 #ifdef BCMDONGLEHOST
12243 	DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_DONE),
12244 		dhd_net2idx(dhdp->info, ndev), as->reason);
12245 #endif /* BCMDONGLEHOST */
12246 
12247 #if defined(CONFIG_TIZEN)
12248 	net_stat_tizen_update_wifi(ndev, WIFISTAT_CONNECTION_FAIL);
12249 #endif /* CONFIG_TIZEN */
12250 
12251 #ifdef DHD_LOSSLESS_ROAMING
12252 	wl_del_roam_timeout(cfg);
12253 #endif /* DHD_LOSSLESS_ROAMING */
12254 	/*
12255 	* FW sends body and body len as a part of deauth
12256 	* and disassoc events (WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND)
12257 	* The VIEs sits after reason code in the body. Reason code is
12258 	* 2 bytes long.
12259 	*/
12260 	WL_DBG(("recv disconnect ies ie_len = %d\n", ie_len));
12261 	if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND) {
12262 		if ((datalen > DOT11_DISCONNECT_RC) &&
12263 			datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
12264 			data) {
12265 			ie_ptr = (uchar*)data + DOT11_DISCONNECT_RC;
12266 			ie_len = datalen - DOT11_DISCONNECT_RC;
12267 		}
12268 	}
12269 #ifdef WL_ANALYTICS
12270 	else if ((event == WLC_E_LINK) &&
12271 			(reason == WLC_E_LINK_BCN_LOSS)) {
12272 		if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
12273 			if (wl_vndr_ies_find_vendor_oui(cfg, ndev,
12274 				CISCO_AIRONET_OUI)) {
12275 				WL_INFORM_MEM(("Analytics Beacon loss\n"));
12276 				ie_ptr = (uchar*)disco_bcnloss_vsie;
12277 				ie_len = sizeof(disco_bcnloss_vsie);
12278 			}
12279 		}
12280 	}
12281 #endif /* WL_ANALYTICS */
12282 
12283 #ifdef BCMDONGLEHOST
12284 #if defined(DHDTCPSYNC_FLOOD_BLK) && defined(CUSTOMER_TCPSYNC_FLOOD_DIS_RC)
12285 	{
12286 		u32 ifidx = ntoh32(as->event_msg->ifidx);
12287 		struct dhd_if *ifp = dhd_get_ifp(dhdp, ifidx);
12288 		if (ifp && ifp->disconnect_tsync_flood) {
12289 			reason = CUSTOMER_TCPSYNC_FLOOD_DIS_RC;
12290 		}
12291 	}
12292 #endif /* DHDTCPSYNC_FLOOD_BLK && CUSTOMER_TCPSYNC_FLOOD_DIS_RC */
12293 #endif /* BCMDONGLEHOST */
12294 
12295 #ifdef DHD_ENABLE_BIGDATA_LOGGING
12296 	wl_get_bss_info(cfg, ndev, as->addr);
12297 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
12298 
12299 	/* unlink from bss list - to force fresh add from next scan/connect */
12300 	wl_cfg8021_unlink_bss(cfg, ndev, as->addr);
12301 
12302 	/* clear profile before reporting link down */
12303 	wl_init_prof(cfg, ndev);
12304 #ifdef WL_EXT_IAPSTA
12305 	wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
12306 		WL_EXT_STATUS_DISCONNECTED, NULL);
12307 	wl_ext_iapsta_restart_master(ndev);
12308 #endif
12309 
12310 	CFG80211_DISCONNECTED(ndev, reason, ie_ptr, ie_len,
12311 		loc_gen, GFP_KERNEL);
12312 	WL_MSG(ndev->name, "Disconnect event sent to upper layer"
12313 		"event:%d e->reason=%d reason=%d ie_len=%d "
12314 		"from " MACDBG "\n",
12315 		event, ntoh32(as->reason), reason, ie_len,
12316 		MAC2STRDBG((const u8*)(&as->addr)));
12317 
12318 	/* clear connected state */
12319 	wl_clr_drv_status(cfg, CONNECTED, ndev);
12320 
12321 	/* Common handler for assoc fail/link down */
12322 	wl_post_linkdown_ops(cfg, as, as->ndev);
12323 
12324 	return ret;
12325 }
12326 
12327 static s32
wl_handle_assoc_done(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)12328 wl_handle_assoc_done(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
12329 {
12330 	s32 ret = BCME_OK;
12331 	bool act = true;
12332 	struct net_device *ndev = as->ndev;
12333 
12334 	wl_update_prof(cfg, ndev, as->event_msg, &act, WL_PROF_ACT);
12335 
12336 	if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12337 		u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
12338 		u8 *conn_req_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
12339 		if (memcmp(curbssid, conn_req_bssid, ETHER_ADDR_LEN) == 0) {
12340 			/* connected bssid and outstanding connect req bssid are same */
12341 			WL_INFORM_MEM((" Connected event of connected device "
12342 				"e=%d s=%d, ignore it\n",
12343 				as->event_type, as->status));
12344 			return ret;
12345 		}
12346 	}
12347 
12348 	/* Report connect result to cfg80211 layer */
12349 	ret = wl_bss_connect_done(cfg, ndev, as->event_msg, as->data, true);
12350 	if (unlikely(ret)) {
12351 		WL_ERR(("Connect report failed!\n"));
12352 		/* Sync with fw */
12353 		wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
12354 		ret = BCME_ERROR;
12355 		goto exit;
12356 	}
12357 
12358 	WL_DBG(("joined in BSS network \"%s\"\n",
12359 		((struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID));
12360 	wl_update_prof(cfg, ndev, NULL, (const void *)&as->addr, WL_PROF_BSSID);
12361 
12362 	wl_link_up(cfg);
12363 
12364 	/* Handle feature specific handling on linkup event */
12365 	ret = wl_post_linkup_ops(cfg, as);
12366 
12367 exit:
12368 	return ret;
12369 }
12370 
12371 static s32
wl_handle_roam_done(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)12372 wl_handle_roam_done(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
12373 {
12374 	s32 ret = BCME_OK;
12375 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12376 
12377 	if (cfg->roam_offload) {
12378 		/* roam offload enabled, avoid roam events to wake up host */
12379 		WL_ERR(("roamoffload enabled. Ignore event\n"));
12380 		return ret;
12381 	}
12382 
12383 #ifdef DHD_EVENT_LOG_FILTER
12384 	dhd_event_log_filter_notify_connect_done(dhdp,
12385 			as->addr, true);
12386 #endif /* DHD_EVENT_LOG_FILTER */
12387 
12388 #ifdef DHD_LOSSLESS_ROAMING
12389 	{
12390 		struct wl_security *sec = wl_read_prof(cfg,
12391 				as->ndev, WL_PROF_SEC);
12392 		if (!IS_AKM_SUITE_FT(sec)) {
12393 			wl_bss_roaming_done(cfg, as->ndev, as->event_msg, as->data);
12394 		}
12395 	}
12396 #endif /* DHD_LOSSLESS_ROAMING */
12397 
12398 	/* Arm pkt logging timer */
12399 	dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
12400 
12401 	return ret;
12402 }
12403 
12404 static s32
wl_handle_sta_link_action(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)12405 wl_handle_sta_link_action(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
12406 {
12407 	s32 ret = BCME_OK;
12408 
12409 	WL_INFORM_MEM(("assoc_state:%s link action:%s\n",
12410 		wl_get_assoc_state_str(as->assoc_state),
12411 		wl_get_link_action_str(as->link_action)));
12412 
12413 	switch (as->link_action) {
12414 		case WL_LINK_ASSOC_DONE:
12415 			ret = wl_handle_assoc_done(cfg, as);
12416 			break;
12417 		case WL_LINK_ASSOC_FAIL:
12418 			ret = wl_handle_assoc_fail(cfg, as, FALSE);
12419 			break;
12420 		case WL_LINK_DOWN:
12421 			ret = wl_handle_link_down(cfg, as);
12422 			break;
12423 		case WL_LINK_ROAM_DONE:
12424 			ret = wl_handle_roam_done(cfg, as);
12425 			break;
12426 		case WL_LINK_FORCE_DEAUTH:
12427 			wl_cfg80211_disassoc(as->ndev, WLAN_REASON_DEAUTH_LEAVING);
12428 			break;
12429 		default:
12430 			WL_ERR(("Unsupported link state:%d\n", as->link_action));
12431 			ret = -ENOTSUPP;
12432 	}
12433 
12434 	if (unlikely(ret)) {
12435 		WL_ERR(("link_action:%d handling failed\n", as->link_action));
12436 	}
12437 
12438 	return ret;
12439 }
12440 
12441 static s32
wl_handle_assoc_events(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const wl_event_msg_t * e,void * data,wl_assoc_state_t assoc_state)12442 wl_handle_assoc_events(struct bcm_cfg80211 *cfg,
12443 	struct wireless_dev *wdev, const wl_event_msg_t *e,
12444 	void *data, wl_assoc_state_t assoc_state)
12445 {
12446 	s32 err = BCME_OK;
12447 	wl_assoc_status_t as;
12448 
12449 	if (!wdev || !e) {
12450 		WL_ERR(("wrong input\n"));
12451 		return -EINVAL;
12452 	}
12453 
12454 	bzero(&as, sizeof(wl_assoc_status_t));
12455 	as.event_type = ntoh32(e->event_type);
12456 	as.status = ntoh32(e->status);
12457 	as.reason = ntoh32(e->reason);
12458 	as.flags = ntoh16(e->flags);
12459 	as.ndev = wdev->netdev;
12460 	as.data = data;
12461 	as.data_len = ntoh32(e->datalen);
12462 	as.event_msg = e;
12463 	(void)memcpy_s(as.addr, ETH_ALEN, e->addr.octet, ETH_ALEN);
12464 
12465 	WL_INFORM_MEM(("[%s] Mode BSS. assoc_state:%d event:%d "
12466 		"status:%d reason:%d e_idx:%d " MACDBG "\n",
12467 		as.ndev->name, as.assoc_state, as.event_type, as.status, as.reason,
12468 		cfg->eidx.in_progress, MAC2STRDBG((const u8*)(&e->addr))));
12469 
12470 	/* Handle FW events */
12471 	switch (as.event_type) {
12472 		case WLC_E_AUTH:
12473 			if (ntoh32(e->auth_type) == DOT11_SAE) {
12474 #ifdef WL_SAE
12475 				wl_bss_handle_sae_auth(cfg, as.ndev, e, data);
12476 #endif /* WL_SAE */
12477 
12478 #ifdef WL_CLIENT_SAE
12479 				wl_handle_auth_event(cfg, as.ndev, e, data);
12480 #endif /* WL_CLIENT_SAE */
12481 			}
12482 
12483 			/* Intentional fall through */
12484 		case WLC_E_ASSOC:
12485 			wl_get_auth_assoc_status(cfg, as.ndev, e, data);
12486 			break;
12487 		case WLC_E_ASSOC_RESP_IE:
12488 			if (as.status != WLC_E_STATUS_SUCCESS) {
12489 				wl_cache_assoc_resp_ies(cfg, as.ndev, e, data);
12490 			}
12491 			break;
12492 		case WLC_E_SET_SSID:
12493 			wl_cfg80211_handle_set_ssid_complete(cfg, &as, e, assoc_state);
12494 			break;
12495 		case WLC_E_DEAUTH_IND:
12496 		case WLC_E_DISASSOC_IND:
12497 			wl_cfg80211_handle_deauth_ind(cfg, &as);
12498 			/* intentional fall through */
12499 		case WLC_E_DISASSOC:
12500 		case WLC_E_DEAUTH:
12501 			as.link_action = wl_set_link_action(assoc_state, false);
12502 			break;
12503 		case WLC_E_LINK:
12504 			if (as.flags & WLC_EVENT_MSG_LINK) {
12505 				as.link_action = wl_set_link_action(assoc_state, true);
12506 			} else {
12507 				as.link_action = wl_set_link_action(assoc_state, false);
12508 			}
12509 			break;
12510 		default:
12511 			WL_DBG(("Ignore event:%d\n", as.event_type));
12512 			as.link_action = 0;
12513 	}
12514 
12515 	if (as.link_action) {
12516 		/* Handle change in link state (if any) */
12517 		err = wl_handle_sta_link_action(cfg, &as);
12518 	}
12519 
12520 	return err;
12521 }
12522 
12523 #define IS_OBSOLETE_EVENT(cur_idx, marker_idx) ((s32)(cur_idx - marker_idx) < 0)
12524 static s32
wl_notify_connect_status_sta(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const wl_event_msg_t * e,void * data)12525 wl_notify_connect_status_sta(struct bcm_cfg80211 *cfg,
12526 	struct wireless_dev *wdev, const wl_event_msg_t *e, void *data)
12527 {
12528 	u32 event_type;
12529 	wl_assoc_state_t assoc_state;
12530 	struct net_device *ndev;
12531 	s32 ret = BCME_OK;
12532 	wl_event_idx_t *idx = &cfg->eidx;
12533 
12534 	if (!wdev || !e) {
12535 		WL_ERR(("wrong input\n"));
12536 		return -EINVAL;
12537 	}
12538 
12539 	event_type = ntoh32(e->event_type);
12540 	if (IS_OBSOLETE_EVENT(idx->in_progress, idx->min_connect_idx)) {
12541 		/* If this event is enqd before the connect req, discard */
12542 		WL_ERR(("discard obsolete event:%d. cur_idx:%d min_idx:%d\n",
12543 			event_type, idx->in_progress, idx->min_connect_idx));
12544 		return -EINVAL;
12545 	}
12546 
12547 	ndev = wdev->netdev;
12548 	if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
12549 		/* Join attempt via non-cfg80211 interface.
12550 		 * Don't send events to cfg80211 layer
12551 		 */
12552 		WL_INFORM_MEM(("Event received in non-cfg80211"
12553 				" connect state. Ignore\n"));
12554 		goto exit;
12555 	}
12556 
12557 	if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
12558 		assoc_state = WL_STATE_ASSOCIATING;
12559 	} else if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12560 		assoc_state = WL_STATE_ASSOCIATED;
12561 	} else {
12562 		WL_ERR(("Unexpected event:%d in assoc idle state\n", event_type));
12563 		assoc_state = WL_STATE_ASSOC_IDLE;
12564 	}
12565 
12566 	ret = wl_handle_assoc_events(cfg, wdev, e, data, assoc_state);
12567 exit:
12568 	return ret;
12569 }
12570 
12571 static s32
wl_notify_connect_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12572 wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12573 	const wl_event_msg_t *e, void *data)
12574 {
12575 	struct net_device *ndev = NULL;
12576 	s32 err = 0;
12577 	u32 mode;
12578 
12579 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
12580 	DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
12581 #endif /* BCMDONGLEHOST && OEM_ANDROID */
12582 
12583 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12584 	mode = wl_get_mode_by_netdev(cfg, ndev);
12585 
12586 	/* Push link events to upper layer log */
12587 	SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n",
12588 		ndev->name, mode, ntoh32(e->event_type),
12589 		ntoh32(e->status),  ntoh32(e->reason)));
12590 
12591 	if (mode == WL_MODE_AP) {
12592 		/* AP/P2O GO cases */
12593 		err = wl_notify_connect_status_ap(cfg, ndev, e, data);
12594 	} else if (mode == WL_MODE_IBSS) {
12595 		err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
12596 	} else if (mode == WL_MODE_BSS) {
12597 		/* STA/GC cases */
12598 		err = wl_notify_connect_status_sta(cfg, ndev->ieee80211_ptr, e, data);
12599 	} else {
12600 		WL_ERR(("Unexpected event:%d for mode:%d\n", e->event_type, mode));
12601 	}
12602 
12603 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
12604 	DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
12605 #endif /* BCMDONGLEHOST && OEM_ANDROID */
12606 	return err;
12607 }
12608 
12609 #ifdef WL_RELMCAST
wl_cfg80211_set_rmc_pid(struct net_device * dev,int pid)12610 void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
12611 {
12612 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
12613 	if (pid > 0)
12614 		cfg->rmc_event_pid = pid;
12615 	WL_DBG(("set pid for rmc event : pid=%d\n", pid));
12616 }
12617 #endif /* WL_RELMCAST */
12618 
12619 #ifdef WLAIBSS
wl_cfg80211_set_txfail_pid(struct net_device * dev,int pid)12620 void wl_cfg80211_set_txfail_pid(struct net_device *dev, int pid)
12621 {
12622 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
12623 	if (pid > 0)
12624 		cfg->aibss_txfail_pid = pid;
12625 	WL_DBG(("set pid for aibss fail event : pid=%d\n", pid));
12626 }
12627 
12628 static s32
wl_notify_aibss_txfail(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12629 wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12630 	const wl_event_msg_t *e, void *data)
12631 {
12632 	u32 evt = ntoh32(e->event_type);
12633 	int ret = -1;
12634 #ifdef PCIE_FULL_DONGLE
12635 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12636 	u32 reason = ntoh32(e->reason);
12637 #endif
12638 	if (cfg->aibss_txfail_pid != 0) {
12639 #ifdef PCIE_FULL_DONGLE
12640 		if (reason == AIBSS_PEER_FREE) {
12641 			uint8 ifindex;
12642 			wl_event_msg_t event;
12643 
12644 			bzero(&event, sizeof(wl_event_msg_t));
12645 			memcpy(&event, e, sizeof(wl_event_msg_t));
12646 
12647 			ifindex = (uint8)dhd_ifname2idx(dhd->info, event.ifname);
12648 			WL_INFORM_MEM(("Peer freed. Flow rings delete for peer.\n"));
12649 			dhd_flow_rings_delete_for_peer(dhd, ifindex,
12650 				(void *)&event.addr.octet[0]);
12651 			return 0;
12652 		}
12653 #endif
12654 		ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL,
12655 			cfg->aibss_txfail_seq++, &e->addr, ETHER_ADDR_LEN);
12656 	}
12657 
12658 	WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n",
12659 		evt, cfg->aibss_txfail_pid, ret, CONST_ETHERP_TO_MACF(&e->addr)));
12660 	return ret;
12661 }
12662 #endif /* WLAIBSS */
12663 #ifdef WL_RELMCAST
12664 static s32
wl_notify_rmc_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12665 wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12666 	const wl_event_msg_t *e, void *data)
12667 {
12668 	u32 evt = ntoh32(e->event_type);
12669 	u32 reason = ntoh32(e->reason);
12670 	int ret = -1;
12671 
12672 	switch (reason) {
12673 		case WLC_E_REASON_RMC_AR_LOST:
12674 		case WLC_E_REASON_RMC_AR_NO_ACK:
12675 			if (cfg->rmc_event_pid != 0) {
12676 				ret = wl_netlink_send_msg(cfg->rmc_event_pid,
12677 					RMC_EVENT_LEADER_CHECK_FAIL,
12678 					cfg->rmc_event_seq++, NULL, 0);
12679 			}
12680 			break;
12681 		default:
12682 			break;
12683 	}
12684 	WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
12685 	return ret;
12686 }
12687 #endif /* WL_RELMCAST */
12688 
12689 #ifdef GSCAN_SUPPORT
12690 static s32
wl_handle_roam_exp_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12691 wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12692 	const wl_event_msg_t *e, void *data)
12693 {
12694 	struct net_device *ndev = NULL;
12695 	u32 datalen = be32_to_cpu(e->datalen);
12696 
12697 	if (datalen) {
12698 		wl_roam_exp_event_t *evt_data = (wl_roam_exp_event_t *)data;
12699 		if (evt_data->version == ROAM_EXP_EVENT_VERSION) {
12700 			wlc_ssid_t *ssid = &evt_data->cur_ssid;
12701 			struct wireless_dev *wdev;
12702 			ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12703 			if (ndev) {
12704 				wdev = ndev->ieee80211_ptr;
12705 				wdev->ssid_len = min(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN);
12706 				memcpy(wdev->ssid, ssid->SSID, wdev->ssid_len);
12707 				WL_ERR(("SSID is %s\n", ssid->SSID));
12708 				wl_update_prof(cfg, ndev, NULL, ssid, WL_PROF_SSID);
12709 			} else {
12710 				WL_ERR(("NULL ndev!\n"));
12711 			}
12712 		} else {
12713 			WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
12714 			       ROAM_EXP_EVENT_VERSION));
12715 		}
12716 	}
12717 	return BCME_OK;
12718 }
12719 #endif /* GSCAN_SUPPORT */
12720 
12721 #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)12722 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12723 	const wl_event_msg_t *e, void *data)
12724 {
12725 
12726 #if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
12727 	u32 datalen = be32_to_cpu(e->datalen);
12728 	struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12729 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
12730 
12731 	if (datalen) {
12732 		wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data;
12733 		if (evt_data->version == RSSI_MONITOR_VERSION) {
12734 			dhd_rssi_monitor_evt_t monitor_data;
12735 			monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION;
12736 			monitor_data.cur_rssi = evt_data->cur_rssi;
12737 			memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN);
12738 			wl_cfgvendor_send_async_event(wiphy, ndev,
12739 				GOOGLE_RSSI_MONITOR_EVENT,
12740 				&monitor_data, sizeof(monitor_data));
12741 		} else {
12742 			WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
12743 			       RSSI_MONITOR_VERSION));
12744 		}
12745 	}
12746 #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
12747 	return BCME_OK;
12748 }
12749 #endif /* RSSI_MONITOR_SUPPORT */
12750 
12751 static s32
wl_notify_roaming_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12752 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12753 	const wl_event_msg_t *e, void *data)
12754 {
12755 	bool act;
12756 	struct net_device *ndev = NULL;
12757 	s32 err = 0;
12758 	u32 event = be32_to_cpu(e->event_type);
12759 	u32 status = be32_to_cpu(e->status);
12760 #ifdef DHD_LOSSLESS_ROAMING
12761 	struct wl_security *sec;
12762 #endif
12763 #ifdef BCMDONGLEHOST
12764 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12765 #endif /* BCMDONGLEHOST */
12766 	WL_DBG(("Enter \n"));
12767 
12768 #ifdef BCMDONGLEHOST
12769 	BCM_REFERENCE(dhdp);
12770 #endif /* BCMDONGLEHOST */
12771 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12772 
12773 	if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
12774 
12775 #ifdef OEM_ANDROID
12776 		wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
12777 #endif /* OEM_ANDROID */
12778 
12779 		cfg->disable_roam_event = TRUE;
12780 	}
12781 
12782 	if ((cfg->disable_roam_event) && (event == WLC_E_ROAM))
12783 		return err;
12784 
12785 	if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
12786 		if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12787 #ifdef DHD_LOSSLESS_ROAMING
12788 			sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
12789 			/* In order to reduce roaming delay, wl_bss_roaming_done is
12790 			 * early called with WLC_E_LINK event. It is called from
12791 			 * here only if WLC_E_LINK event is blocked for specific
12792 			 * security type.
12793 			 */
12794 			if (IS_AKM_SUITE_FT(sec)) {
12795 				wl_bss_roaming_done(cfg, ndev, e, data);
12796 #ifdef BCMDONGLEHOST
12797 				/* Arm pkt logging timer */
12798 				dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
12799 #endif /* BCMDONGLEHOST */
12800 			}
12801 			/* Roam timer is deleted mostly from wl_cfg80211_change_station
12802 			 * after roaming is finished successfully. We need to delete
12803 			 * the timer from here only for some security types that aren't
12804 			 * using wl_cfg80211_change_station to authorize SCB
12805 			 */
12806 			if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
12807 				wl_del_roam_timeout(cfg);
12808 			}
12809 #else
12810 #if !defined(DHD_NONFT_ROAMING)
12811 			wl_bss_roaming_done(cfg, ndev, e, data);
12812 #endif /* !DHD_NONFT_ROAMING */
12813 #endif /* DHD_LOSSLESS_ROAMING */
12814 #ifdef WBTEXT
12815 			if (dhdp->wbtext_support) {
12816 				/* set wnm_keepalives_max_idle after association */
12817 				wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
12818 
12819 				/* Mostly nbr request of BTM query will be handled
12820 				 * from wl_cfg80211_change_station
12821 				 * after key negotiation is finished.
12822 				 * This part is only for some specific security
12823 				 * types (FT, CCKM) that don't call
12824 				 * wl_cfg80211_change_station after roaming
12825 				 */
12826 				if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
12827 					/* send nbr request or BTM query to update RCC
12828 					 * after roaming completed
12829 					 */
12830 					wl_cfg80211_wbtext_update_rcc(cfg, ndev);
12831 				}
12832 			}
12833 #endif /* WBTEXT */
12834 		} else {
12835 			wl_bss_connect_done(cfg, ndev, e, data, true);
12836 		}
12837 		act = true;
12838 		wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
12839 		wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
12840 
12841 		if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
12842 			wl_vndr_ies_get_vendor_oui(cfg, ndev, NULL, 0);
12843 		}
12844 	}
12845 #ifdef DHD_LOSSLESS_ROAMING
12846 	else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) {
12847 		wl_del_roam_timeout(cfg);
12848 	}
12849 #endif
12850 	return err;
12851 }
12852 
12853 #ifdef CUSTOM_EVENT_PM_WAKE
12854 uint32 last_dpm_upd_time = 0;	/* ms */
12855 #define DPM_UPD_LMT_TIME	((CUSTOM_EVENT_PM_WAKE + (5)) * (1000) * (4))	/* ms */
12856 #define DPM_UPD_LMT_RSSI	-85	/* dbm */
12857 
12858 static s32
wl_check_pmstatus(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12859 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12860 	const wl_event_msg_t *e, void *data)
12861 {
12862 	s32 err = BCME_OK;
12863 	struct net_device *ndev = NULL;
12864 	u8 *pbuf = NULL;
12865 	uint32 cur_dpm_upd_time = 0;
12866 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12867 	s32 rssi;
12868 #ifdef SUPPORT_RSSI_SUM_REPORT
12869 	wl_rssi_ant_mimo_t rssi_ant_mimo;
12870 #endif /* SUPPORT_RSSI_SUM_REPORT */
12871 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12872 
12873 	pbuf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
12874 	if (pbuf == NULL) {
12875 		WL_ERR(("failed to allocate local pbuf\n"));
12876 		return -ENOMEM;
12877 	}
12878 
12879 	err = wldev_iovar_getbuf_bsscfg(ndev, "dump",
12880 		"pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN,
12881 		0, &cfg->ioctl_buf_sync);
12882 
12883 	if (err) {
12884 		WL_ERR(("dump ioctl err = %d", err));
12885 	} else {
12886 		WL_ERR(("PM status : %s\n", pbuf));
12887 	}
12888 
12889 	if (pbuf) {
12890 		MFREE(cfg->osh, pbuf, WLC_IOCTL_MEDLEN);
12891 	}
12892 
12893 	if (dhd->early_suspended) {
12894 		/* LCD off */
12895 #ifdef SUPPORT_RSSI_SUM_REPORT
12896 		/* Query RSSI sum across antennas */
12897 		memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
12898 		err = wl_get_rssi_per_ant(ndev, ndev->name, NULL, &rssi_ant_mimo);
12899 		if (err) {
12900 			WL_ERR(("Could not get rssi sum (%d)\n", err));
12901 		}
12902 		rssi = rssi_ant_mimo.rssi_sum;
12903 		if (rssi == 0)
12904 #endif /* SUPPORT_RSSI_SUM_REPORT */
12905 		{
12906 			scb_val_t scb_val;
12907 			memset(&scb_val, 0, sizeof(scb_val_t));
12908 			scb_val.val = 0;
12909 			err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
12910 			if (err) {
12911 				WL_ERR(("Could not get rssi (%d)\n", err));
12912 			}
12913 			rssi = wl_rssi_offset(dtoh32(scb_val.val));
12914 		}
12915 		WL_ERR(("RSSI %d dBm\n", rssi));
12916 		if (rssi > DPM_UPD_LMT_RSSI) {
12917 			return err;
12918 		}
12919 	} else {
12920 		/* LCD on */
12921 		return err;
12922 	}
12923 
12924 	if (last_dpm_upd_time == 0) {
12925 		last_dpm_upd_time = OSL_SYSUPTIME();
12926 	} else {
12927 		cur_dpm_upd_time = OSL_SYSUPTIME();
12928 		if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) {
12929 			scb_val_t scbval;
12930 			DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
12931 				dhd_net2idx(dhd->info, ndev), 0);
12932 			bzero(&scbval, sizeof(scb_val_t));
12933 
12934 			err = wldev_ioctl_set(ndev, WLC_DISASSOC,
12935 				&scbval, sizeof(scb_val_t));
12936 			if (err < 0) {
12937 				WL_ERR(("Disassoc error %d\n", err));
12938 				return err;
12939 			}
12940 			WL_ERR(("Force Disassoc due to updated DPM event.\n"));
12941 
12942 			last_dpm_upd_time = 0;
12943 		} else {
12944 			last_dpm_upd_time = cur_dpm_upd_time;
12945 		}
12946 	}
12947 
12948 	return err;
12949 }
12950 #endif	/* CUSTOM_EVENT_PM_WAKE */
12951 
12952 #ifdef QOS_MAP_SET
12953 /* get user priority table */
12954 uint8 *
wl_get_up_table(dhd_pub_t * dhdp,int idx)12955 wl_get_up_table(dhd_pub_t * dhdp, int idx)
12956 {
12957 	struct net_device *ndev;
12958 	struct bcm_cfg80211 *cfg;
12959 
12960 	ndev = dhd_idx2net(dhdp, idx);
12961 	if (ndev) {
12962 		cfg = wl_get_cfg(ndev);
12963 		if (cfg)
12964 			return (uint8 *)(cfg->up_table);
12965 	}
12966 
12967 	return NULL;
12968 }
12969 #endif /* QOS_MAP_SET */
12970 
12971 #if defined(DHD_LOSSLESS_ROAMING) || defined (DBG_PKT_MON)
12972 /*
12973  * start packet logging in advance to make sure that EAPOL
12974  * messages are not missed during roaming
12975  */
12976 static s32
wl_notify_roam_prep_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12977 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12978 	const wl_event_msg_t *e, void *data)
12979 {
12980 	struct wl_security *sec;
12981 	struct net_device *ndev;
12982 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12983 	u32 status = ntoh32(e->status);
12984 	u32 reason = ntoh32(e->reason);
12985 
12986 	BCM_REFERENCE(sec);
12987 
12988 	if (status == WLC_E_STATUS_SUCCESS && reason != WLC_E_REASON_INITIAL_ASSOC) {
12989 		WL_ERR(("Attempting roam with reason code : %d\n", reason));
12990 	}
12991 
12992 #ifdef CONFIG_SILENT_ROAM
12993 	if (dhdp->in_suspend && reason == WLC_E_REASON_SILENT_ROAM) {
12994 		dhdp->sroamed = TRUE;
12995 	}
12996 #endif /* CONFIG_SILENT_ROAM */
12997 
12998 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12999 
13000 #ifdef DBG_PKT_MON
13001 	if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
13002 		DHD_DBG_PKT_MON_STOP(dhdp);
13003 		DHD_DBG_PKT_MON_START(dhdp);
13004 	}
13005 #endif /* DBG_PKT_MON */
13006 #ifdef DHD_LOSSLESS_ROAMING
13007 	sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13008 	/* Disable Lossless Roaming for specific AKM suite
13009 	 * Any other AKM suite can be added below if transition time
13010 	 * is delayed because of Lossless Roaming
13011 	 * and it causes any certication failure
13012 	 */
13013 	if (IS_AKM_SUITE_FT(sec) || IS_AKM_OWE(sec->wpa_auth)) {
13014 		return BCME_OK;
13015 	}
13016 
13017 	dhdp->dequeue_prec_map = 1 << dhdp->flow_prio_map[PRIO_8021D_NC];
13018 	/* Restore flow control  */
13019 	dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
13020 
13021 	mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
13022 #endif /* DHD_LOSSLESS_ROAMING */
13023 
13024 	return BCME_OK;
13025 }
13026 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
13027 
13028 static s32
wl_notify_roam_start_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)13029 wl_notify_roam_start_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13030 	const wl_event_msg_t *e, void *data)
13031 {
13032 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13033 	struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13034 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13035 	int event_type;
13036 
13037 	event_type = WIFI_EVENT_ROAM_SCAN_STARTED;
13038 	wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_ROAM_EVENT_START,
13039 		&event_type, sizeof(int));
13040 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || (WL_VENDOR_EXT_SUPPORT) */
13041 
13042 	return BCME_OK;
13043 }
13044 
wl_get_assoc_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev)13045 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13046 {
13047 	wl_assoc_info_t assoc_info;
13048 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
13049 	s32 err = 0;
13050 #ifdef QOS_MAP_SET
13051 	bcm_tlv_t * qos_map_ie = NULL;
13052 #endif /* QOS_MAP_SET */
13053 
13054 	WL_DBG(("Enter \n"));
13055 
13056 	bzero(&assoc_info, sizeof(wl_assoc_info_t));
13057 	err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
13058 		WL_ASSOC_INFO_MAX, NULL);
13059 	if (unlikely(err)) {
13060 		WL_ERR(("could not get assoc info (%d)\n", err));
13061 		return err;
13062 	}
13063 	memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
13064 	assoc_info.req_len = htod32(assoc_info.req_len);
13065 	assoc_info.resp_len = htod32(assoc_info.resp_len);
13066 	assoc_info.flags = htod32(assoc_info.flags);
13067 	if (conn_info->req_ie_len) {
13068 		conn_info->req_ie_len = 0;
13069 		bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
13070 	}
13071 	if (conn_info->resp_ie_len) {
13072 		conn_info->resp_ie_len = 0;
13073 		bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
13074 	}
13075 
13076 	if (assoc_info.req_len) {
13077 		err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
13078 			assoc_info.req_len, NULL);
13079 		if (unlikely(err)) {
13080 			WL_ERR(("could not get assoc req (%d)\n", err));
13081 			return err;
13082 		}
13083 		if (assoc_info.req_len < sizeof(struct dot11_assoc_req)) {
13084 			WL_ERR(("req_len %d lessthan %d \n", assoc_info.req_len,
13085 				(int)sizeof(struct dot11_assoc_req)));
13086 			return BCME_BADLEN;
13087 		}
13088 		conn_info->req_ie_len = (uint32)(assoc_info.req_len
13089 						- sizeof(struct dot11_assoc_req));
13090 		if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
13091 			conn_info->req_ie_len -= ETHER_ADDR_LEN;
13092 		}
13093 		if (conn_info->req_ie_len <= MAX_REQ_LINE)
13094 			memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
13095 		else {
13096 			WL_ERR(("IE size %d above max %d size \n",
13097 				conn_info->req_ie_len, MAX_REQ_LINE));
13098 			return err;
13099 		}
13100 	} else {
13101 		conn_info->req_ie_len = 0;
13102 	}
13103 
13104 	if (assoc_info.resp_len) {
13105 		err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
13106 			assoc_info.resp_len, NULL);
13107 		if (unlikely(err)) {
13108 			WL_ERR(("could not get assoc resp (%d)\n", err));
13109 			return err;
13110 		}
13111 		if (assoc_info.resp_len < sizeof(struct dot11_assoc_resp)) {
13112 			WL_ERR(("resp_len %d is lessthan %d \n", assoc_info.resp_len,
13113 				(int)sizeof(struct dot11_assoc_resp)));
13114 			return BCME_BADLEN;
13115 		}
13116 		conn_info->resp_ie_len = assoc_info.resp_len -
13117 				(uint32)sizeof(struct dot11_assoc_resp);
13118 		if (conn_info->resp_ie_len <= MAX_REQ_LINE) {
13119 			memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
13120 		} else {
13121 			WL_ERR(("IE size %d above max %d size \n",
13122 				conn_info->resp_ie_len, MAX_REQ_LINE));
13123 			return err;
13124 		}
13125 
13126 #ifdef QOS_MAP_SET
13127 		/* find qos map set ie */
13128 		if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
13129 				DOT11_MNG_QOS_MAP_ID)) != NULL) {
13130 			WL_DBG((" QoS map set IE found in assoc response\n"));
13131 			if (!cfg->up_table) {
13132 				cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
13133 			}
13134 			wl_set_up_table(cfg->up_table, qos_map_ie);
13135 		} else {
13136 			MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
13137 		}
13138 #endif /* QOS_MAP_SET */
13139 	} else {
13140 		conn_info->resp_ie_len = 0;
13141 	}
13142 	WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
13143 		conn_info->resp_ie_len));
13144 
13145 	return err;
13146 }
13147 
wl_update_bss_info(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool update_ssid)13148 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13149 	bool update_ssid)
13150 {
13151 	struct cfg80211_bss *bss;
13152 	wl_bss_info_t *bi;
13153 	struct wlc_ssid *ssid;
13154 	const struct bcm_tlv *tim;
13155 	s32 beacon_interval;
13156 	s32 dtim_period;
13157 	size_t ie_len;
13158 	const u8 *ie;
13159 	u8 *curbssid;
13160 	s32 err = 0;
13161 	struct wiphy *wiphy;
13162 	char *buf;
13163 	u32 freq;
13164 	chanspec_t chspec = INVCHANSPEC;
13165 
13166 	wiphy = bcmcfg_to_wiphy(cfg);
13167 
13168 	ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
13169 	curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13170 	bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
13171 		ssid->SSID, ssid->SSID_len);
13172 	buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
13173 	if (!buf) {
13174 		WL_ERR(("buffer alloc failed.\n"));
13175 		return BCME_NOMEM;
13176 	}
13177 	mutex_lock(&cfg->usr_sync);
13178 	*(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
13179 	err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX);
13180 	if (unlikely(err)) {
13181 		WL_ERR(("Could not get bss info %d\n", err));
13182 		goto update_bss_info_out;
13183 	}
13184 	bi = (wl_bss_info_t *)(buf + 4);
13185 	chspec = wl_chspec_driver_to_host(bi->chanspec);
13186 	wl_update_prof(cfg, ndev, NULL, &chspec, WL_PROF_CHAN);
13187 
13188 	if (!bss) {
13189 		if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
13190 			WL_ERR(("Bssid doesn't match\n"));
13191 			err = -EIO;
13192 			goto update_bss_info_out;
13193 		}
13194 		err = wl_inform_single_bss(cfg, bi, update_ssid);
13195 		if (unlikely(err)) {
13196 			WL_ERR(("Could not update the AP detail in cache\n"));
13197 			goto update_bss_info_out;
13198 		}
13199 
13200 		WL_INFORM_MEM(("Updated the AP %pM detail in cache\n", curbssid));
13201 		ie = ((u8 *)bi) + bi->ie_offset;
13202 		ie_len = bi->ie_length;
13203 		beacon_interval = cpu_to_le16(bi->beacon_period);
13204 	} else {
13205 		u16 channel;
13206 		WL_INFORM_MEM(("Found AP in the cache - BSSID %pM\n", bss->bssid));
13207 		channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
13208 		freq = wl_channel_to_frequency(channel, CHSPEC_BAND(bi->chanspec));
13209 		bss->channel = ieee80211_get_channel(wiphy, freq);
13210 #if defined(WL_CFG80211_P2P_DEV_IF)
13211 		ie = (const u8 *)bss->ies->data;
13212 		ie_len = bss->ies->len;
13213 #else
13214 		ie = bss->information_elements;
13215 		ie_len = bss->len_information_elements;
13216 #endif /* WL_CFG80211_P2P_DEV_IF */
13217 		beacon_interval = bss->beacon_interval;
13218 
13219 		CFG80211_PUT_BSS(wiphy, bss);
13220 	}
13221 
13222 	tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
13223 	if (tim) {
13224 		dtim_period = tim->data[1];
13225 	} else {
13226 		/*
13227 		* active scan was done so we could not get dtim
13228 		* information out of probe response.
13229 		* so we speficially query dtim information.
13230 		*/
13231 		dtim_period = 0;
13232 		err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD,
13233 			&dtim_period, sizeof(dtim_period));
13234 		if (unlikely(err)) {
13235 			WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
13236 			goto update_bss_info_out;
13237 		}
13238 	}
13239 
13240 	wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
13241 	wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
13242 
13243 update_bss_info_out:
13244 	if (unlikely(err)) {
13245 		WL_ERR(("Failed with error %d\n", err));
13246 	}
13247 
13248 	MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
13249 	mutex_unlock(&cfg->usr_sync);
13250 	return err;
13251 }
13252 
13253 #ifdef DHD_LOSSLESS_ROAMING
13254 static s32
wl_bss_roaming_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)13255 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13256 	const wl_event_msg_t *e, void *data)
13257 {
13258 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
13259 	s32 err = 0;
13260 	u8 *curbssid;
13261 	chanspec_t *chanspec;
13262 	scb_val_t scbval;
13263 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
13264 	defined(WL_COMPAT_WIRELESS)
13265 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13266 	struct ieee80211_channel *notify_channel = NULL;
13267 	u32 freq;
13268 	u32 cur_channel, cur_chanspec, orig_channel;
13269 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
13270 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
13271 	(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \
13272 	defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12)
13273 	struct cfg80211_roam_info roam_info;
13274 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
13275 #if defined(WL_FILS_ROAM_OFFLD)
13276 	struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
13277 	struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13278 #endif
13279 #ifdef BCMDONGLEHOST
13280 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
13281 #endif /* BCMDONGLEHOST */
13282 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
13283 	dhd_if_t *ifp = NULL;
13284 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
13285 #ifdef WLFBT
13286 	uint32 data_len = 0;
13287 	if (data)
13288 		data_len = ntoh32(e->datalen);
13289 #endif /* WLFBT */
13290 
13291 	BCM_REFERENCE(dhdp);
13292 	curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13293 	chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
13294 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
13295 	defined(WL_COMPAT_WIRELESS)
13296 	/* Skip calling cfg80211_roamed If the channels are same and
13297 	 * the current bssid & the new bssid are same
13298 	 * Also clear timer roam_timeout.
13299 	 * Only used on BCM4359 devices.
13300 	 */
13301 	err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&cur_chanspec);
13302 	if (unlikely(err)) {
13303 		return  err;
13304 	}
13305 	cur_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(cur_chanspec));
13306 	orig_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(*chanspec));
13307 	if ((orig_channel == cur_channel) &&
13308 			((memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) ||
13309 			(memcmp(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN) == 0))) {
13310 		WL_DBG(("BSS already present, Skipping roamed event to"
13311 		" upper layer\n"));
13312 		goto fail;
13313 	}
13314 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
13315 
13316 	if ((err = wl_get_assoc_ies(cfg, ndev)) != BCME_OK) {
13317 #ifdef BCMDONGLEHOST
13318 		DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
13319 			dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
13320 #endif /* BCMDONGLEHOST */
13321 		WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
13322 			" upper layer\n"));
13323 		/* To make sure disconnect, and fw sync, explictly send dissassoc
13324 		 * for BSSID 00:00:00:00:00:00 issue
13325 		 */
13326 		bzero(&scbval, sizeof(scb_val_t));
13327 		scbval.val = WLAN_REASON_DEAUTH_LEAVING;
13328 		memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
13329 		scbval.val = htod32(scbval.val);
13330 		if (wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
13331 				sizeof(scb_val_t)) < 0) {
13332 			WL_ERR(("WLC_DISASSOC error\n"));
13333 		}
13334 		goto fail;
13335 	}
13336 
13337 	WL_MSG(ndev->name, "%pM(ch:%3d/%sMHz) => %pM(ch:%3d/%sMHz)\n",
13338 		curbssid, orig_channel,
13339 		CHSPEC_IS20(*chanspec)?"20":
13340 		CHSPEC_IS40(*chanspec)?"40":
13341 		CHSPEC_IS80(*chanspec)?"80":
13342 		CHSPEC_IS160(*chanspec)?"160":"??",
13343 		(const u8*)(&e->addr), cur_channel,
13344 		CHSPEC_IS20(cur_chanspec)?"20":
13345 		CHSPEC_IS40(cur_chanspec)?"40":
13346 		CHSPEC_IS80(cur_chanspec)?"80":
13347 		CHSPEC_IS160(cur_chanspec)?"160":"??");
13348 
13349 	wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID);
13350 	curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13351 	if ((err = wl_update_bss_info(cfg, ndev, true)) != BCME_OK) {
13352 		WL_ERR(("failed to update bss info, err=%d\n", err));
13353 		goto fail;
13354 	}
13355 	if (cfg->wlc_ver.wlc_ver_major < PMKDB_WLC_VER) {
13356 		wl_update_pmklist(ndev, cfg->pmk_list, err);
13357 	}
13358 
13359 	chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
13360 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
13361 	defined(WL_COMPAT_WIRELESS)
13362 	/* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
13363 	freq = wl_channel_to_frequency(wf_chspec_ctlchan(*chanspec), CHSPEC_BAND(*chanspec));
13364 	notify_channel = ieee80211_get_channel(wiphy, freq);
13365 #endif /* LINUX_VERSION > 2.6.39  || WL_COMPAT_WIRELESS */
13366 #ifdef WLFBT
13367 	/* back up the given FBT key for the further supplicant request,
13368 	 * currently not checking the FBT is enabled for current BSS in DHD,
13369 	 * because the supplicant decides to take it or not.
13370 	 */
13371 	if (data && (data_len == FBT_KEYLEN)) {
13372 		memcpy(cfg->fbt_key, data, FBT_KEYLEN);
13373 	}
13374 #endif /* WLFBT */
13375 #ifdef CUSTOM_LONG_RETRY_LIMIT
13376 	if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
13377 		WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
13378 	}
13379 #endif /* CUSTOM_LONG_RETRY_LIMIT */
13380 	DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM),
13381 		dhd_net2idx(dhdp->info, ndev), 0);
13382 #ifdef WL_EXT_IAPSTA
13383 	wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
13384 #endif
13385 
13386 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
13387 	(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \
13388 	defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12)
13389 	memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
13390 	roam_info.channel = notify_channel;
13391 	roam_info.bssid = curbssid;
13392 	roam_info.req_ie = conn_info->req_ie;
13393 	roam_info.req_ie_len = conn_info->req_ie_len;
13394 	roam_info.resp_ie = conn_info->resp_ie;
13395 	roam_info.resp_ie_len = conn_info->resp_ie_len;
13396 #if defined(WL_FILS_ROAM_OFFLD)
13397 	if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
13398 		roam_info.fils.kek = fils_info->fils_kek;
13399 		roam_info.fils.kek_len = fils_info->fils_kek_len;
13400 		roam_info.fils.update_erp_next_seq_num = true;
13401 		roam_info.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
13402 		roam_info.fils.pmk = fils_info->fils_pmk;
13403 		roam_info.fils.pmk_len = fils_info->fils_kek_len;
13404 		roam_info.fils.pmkid = fils_info->fils_pmkid;
13405 	}
13406 #endif
13407 	cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
13408 #else
13409 	cfg80211_roamed(ndev,
13410 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
13411 	defined(WL_COMPAT_WIRELESS)
13412 		notify_channel,
13413 #endif
13414 		curbssid,
13415 		conn_info->req_ie, conn_info->req_ie_len,
13416 		conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
13417 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
13418 
13419 	memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
13420 	wl_set_drv_status(cfg, CONNECTED, ndev);
13421 
13422 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
13423 	cfg->roam_count++;
13424 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
13425 #ifdef WL_BAM
13426 	if (wl_adps_bad_ap_check(cfg, &e->addr)) {
13427 		if (wl_adps_enabled(cfg, ndev)) {
13428 			wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
13429 		}
13430 	}
13431 #endif	/* WL_BAM */
13432 
13433 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
13434 	ifp = dhd_get_ifp(dhdp, e->ifidx);
13435 	if (ifp) {
13436 		ifp->post_roam_evt = TRUE;
13437 	}
13438 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
13439 
13440 	return err;
13441 
13442 fail:
13443 #ifdef DHD_LOSSLESS_ROAMING
13444 	wl_del_roam_timeout(cfg);
13445 #endif  /* DHD_LOSSLESS_ROAMING */
13446 	return err;
13447 }
13448 #endif /* DHD_LOSSLESS_ROAMING */
13449 
13450 static bool
wl_cfg80211_verify_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,struct cfg80211_bss ** bss)13451 wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13452 	struct cfg80211_bss **bss)
13453 {
13454 	struct wiphy *wiphy;
13455 	struct wlc_ssid *ssid;
13456 	uint8 *curbssid;
13457 	bool ret = false;
13458 
13459 	wiphy = bcmcfg_to_wiphy(cfg);
13460 	ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
13461 	curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13462 	if (!ssid || !curbssid) {
13463 		WL_ERR(("No SSID/bssid found in the saved profile \n"));
13464 		return false;
13465 	}
13466 
13467 	*bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
13468 		ssid->SSID, ssid->SSID_len);
13469 	if (*bss) {
13470 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
13471 		/* Update the reference count after use. In case of kernel version >= 4.7
13472 		* the cfg802_put_bss is called in cfg80211_connect_bss context
13473 		*/
13474 		CFG80211_PUT_BSS(wiphy, *bss);
13475 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
13476 		ret = true;
13477 	} else {
13478 		WL_ERR(("No bss entry for bssid:"MACDBG" ssid_len:%d\n",
13479 			MAC2STRDBG(curbssid), ssid->SSID_len));
13480 	}
13481 
13482 	return ret;
13483 }
13484 
13485 #ifdef WL_FILS
13486 static s32
wl_get_fils_connect_params(struct bcm_cfg80211 * cfg,struct net_device * ndev)13487 wl_get_fils_connect_params(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13488 {
13489 	const bcm_xtlv_t* pxtlv_out;
13490 	struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
13491 	int err = BCME_OK;
13492 	bcm_iov_buf_t *iov_buf_in = NULL;
13493 	bcm_iov_buf_t iov_buf_out = {0};
13494 	u16 len;
13495 	u16 type;
13496 	const u8 *data;
13497 	iov_buf_in = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13498 	if (!iov_buf_in) {
13499 		WL_ERR(("buf memory alloc failed\n"));
13500 		err = BCME_NOMEM;
13501 		goto exit;
13502 	}
13503 	iov_buf_out.version = WL_FILS_IOV_VERSION;
13504 	iov_buf_out.id = WL_FILS_CMD_GET_CONNECT_PARAMS;
13505 	err = wldev_iovar_getbuf(ndev, "fils", (uint8*)&iov_buf_out, sizeof(bcm_iov_buf_t),
13506 		iov_buf_in, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
13507 	if (unlikely(err)) {
13508 		WL_ERR(("Get FILS Params Error (%d)\n", err));
13509 		goto exit;
13510 	}
13511 	pxtlv_out = (bcm_xtlv_t*)((bcm_iov_buf_t*)iov_buf_in)->data;
13512 	len = iov_buf_in->len;
13513 	do {
13514 		if (!bcm_valid_xtlv(pxtlv_out, iov_buf_in->len, BCM_XTLV_OPTION_ALIGN32)) {
13515 			WL_ERR(("%s: XTLV is not valid\n", __func__));
13516 			err = BCME_BADARG;
13517 			goto exit;
13518 		}
13519 		bcm_xtlv_unpack_xtlv(pxtlv_out, &type, &len, &data, BCM_XTLV_OPTION_ALIGN32);
13520 		switch (type) {
13521 			case WL_FILS_XTLV_ERP_NEXT_SEQ_NUM:
13522 				fils_info->fils_erp_next_seq_num = *(const u16 *)data;
13523 				break;
13524 			case WL_FILS_XTLV_KEK:
13525 				if (memcpy_s(fils_info->fils_kek,
13526 						WL_MAX_FILS_KEY_LEN, data, len) < 0) {
13527 					err = BCME_BADARG;
13528 					goto exit;
13529 				}
13530 				fils_info->fils_kek_len = len;
13531 				break;
13532 			case WL_FILS_XTLV_PMK:
13533 				if (memcpy_s(fils_info->fils_pmk,
13534 						WL_MAX_FILS_KEY_LEN, data, len) < 0) {
13535 					err = BCME_BADARG;
13536 					goto exit;
13537 				}
13538 				fils_info->fils_pmk_len = len;
13539 				break;
13540 			case WL_FILS_XTLV_PMKID:
13541 				if (memcpy_s(fils_info->fils_pmkid,
13542 						WL_MAX_FILS_KEY_LEN, data, len) < 0) {
13543 					err = BCME_BADARG;
13544 					goto exit;
13545 				}
13546 				break;
13547 			default:
13548 				WL_ERR(("%s: wrong XTLV code\n", __func__));
13549 				break;
13550 
13551 		}
13552 	} while ((pxtlv_out = bcm_next_xtlv(pxtlv_out, (int *)&iov_buf_in->len,
13553 		BCM_XTLV_OPTION_ALIGN32)) && iov_buf_in->len);
13554 exit:
13555 	if (iov_buf_in) {
13556 		MFREE(cfg->osh, iov_buf_in, WLC_IOCTL_SMLEN);
13557 	}
13558 	return err;
13559 }
13560 #endif /* WL_FILS */
13561 
13562 #ifdef WL_FILS
13563 static s32
wl_fillup_resp_params(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 * curbssid,void * params,u32 status)13564 wl_fillup_resp_params(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13565 	u8 *curbssid, void *params, u32 status)
13566 {
13567 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
13568 	struct cfg80211_connect_resp_params *resp_params;
13569 	struct wl_fils_info *fils_info = NULL;
13570 	struct wlc_ssid *ssid = NULL;
13571 	struct wiphy *wiphy = NULL;
13572 	s32 ret = BCME_OK;
13573 
13574 	fils_info = wl_to_fils_info(cfg);
13575 	ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
13576 	wiphy = bcmcfg_to_wiphy(cfg);
13577 	if (!ssid) {
13578 		WL_ERR(("ssid profile not found\n"));
13579 		return BCME_ERROR;
13580 	}
13581 
13582 	resp_params = (struct cfg80211_connect_resp_params *)params;
13583 	resp_params->status = status;
13584 	resp_params->bssid = curbssid;
13585 	resp_params->bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
13586 		ssid->SSID, ssid->SSID_len);
13587 	if (!resp_params->bss) {
13588 		WL_ERR(("null bss\n"));
13589 		return BCME_ERROR;
13590 	}
13591 
13592 	resp_params->req_ie = conn_info->req_ie;
13593 	resp_params->req_ie_len = conn_info->req_ie_len;
13594 	resp_params->resp_ie = conn_info->resp_ie;
13595 	resp_params->resp_ie_len = conn_info->resp_ie_len;
13596 #ifdef WL_FILS_ROAM_OFFLD
13597 	/* Kernel >= 4.17 has introduced FILS data struct inside resp params */
13598 	resp_params->fils.kek = fils_info->fils_kek;
13599 	resp_params->fils.kek_len = fils_info->fils_kek_len;
13600 	resp_params->fils.update_erp_next_seq_num = true;
13601 	resp_params->fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
13602 	resp_params->fils.pmk = fils_info->fils_pmk;
13603 	resp_params->fils.pmk_len = fils_info->fils_kek_len;
13604 	resp_params->fils.pmkid = fils_info->fils_pmkid;
13605 #else
13606 	resp_params->fils_kek = fils_info->fils_kek;
13607 	resp_params->fils_kek_len = fils_info->fils_kek_len;
13608 	resp_params->update_erp_next_seq_num = true;
13609 	resp_params->fils_erp_next_seq_num = fils_info->fils_erp_next_seq_num;
13610 	resp_params->pmk = fils_info->fils_pmk;
13611 	resp_params->pmk_len = fils_info->fils_kek_len;
13612 	resp_params->pmkid = fils_info->fils_pmkid;
13613 #endif /* WL_FILS_ROAM_OFFLD */
13614 
13615 	return ret;
13616 }
13617 #endif /* WL_FILS */
13618 
13619 static s32
wl_bss_connect_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data,bool completed)13620 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13621 	const wl_event_msg_t *e, void *data, bool completed)
13622 {
13623 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
13624 	struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13625 	s32 err = 0;
13626 	u8 *conn_req_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
13627 	u32 status;
13628 #ifdef WL_FILS
13629 	struct cfg80211_connect_resp_params resp_params = {0};
13630 #endif /* WL_FILS */
13631 
13632 	u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13633 	u32 event_type = ntoh32(e->event_type);
13634 	struct cfg80211_bss *bss = NULL;
13635 #ifdef BCMDONGLEHOST
13636 	dhd_pub_t *dhdp;
13637 	dhdp = (dhd_pub_t *)(cfg->pub);
13638 	BCM_REFERENCE(dhdp);
13639 #endif /* BCMDONGLEHOST */
13640 
13641 	WL_DBG((" enter\n"));
13642 	if (!sec) {
13643 		WL_ERR(("sec is NULL\n"));
13644 		err = -ENODEV;
13645 		goto exit;
13646 	}
13647 
13648 	if (!wl_get_drv_status(cfg, CONNECTING, ndev)) {
13649 		WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
13650 				" connecting:%x. connected:%d\n",
13651 				ndev->name, event_type, wl_get_drv_status(cfg, CONNECTING, ndev),
13652 				wl_get_drv_status(cfg, CONNECTED, ndev)));
13653 		err = BCME_OK;
13654 		goto exit;
13655 	}
13656 
13657 	if (!conn_req_bssid) {
13658 		WL_ERR(("conn_req bssid is null\n"));
13659 		err = -EINVAL;
13660 		goto exit;
13661 	}
13662 
13663 	if (ETHER_ISNULLADDR(curbssid) &&
13664 		!ETHER_ISNULLADDR(conn_req_bssid)) {
13665 		WL_DBG(("copy bssid\n"));
13666 		memcpy(curbssid, conn_req_bssid, ETHER_ADDR_LEN);
13667 	}
13668 
13669 	wl_cfgscan_cancel_scan(cfg);
13670 	bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
13671 
13672 	if (completed) {
13673 		wl_get_assoc_ies(cfg, ndev);
13674 		wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
13675 			WL_PROF_BSSID);
13676 		curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13677 		/*
13678 			* CFG layer relies on cached IEs (from probe/beacon) to fetch matching bss.
13679 			* For cases, there is no match available,
13680 			* need to update the cache based on bss info from fw.
13681 			*/
13682 		wl_update_bss_info(cfg, ndev, true);
13683 		if (cfg->wlc_ver.wlc_ver_major < PMKDB_WLC_VER) {
13684 			wl_update_pmklist(ndev, cfg->pmk_list, err);
13685 		}
13686 		wl_set_drv_status(cfg, CONNECTED, ndev);
13687 
13688 		if (wl_cfg80211_verify_bss(cfg, ndev, &bss) != true) {
13689 			/* If bss entry is not available in the cfg80211 bss cache
13690 				* the wireless stack will complain and won't populate
13691 				* wdev->current_bss ptr
13692 				*/
13693 			WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
13694 			completed = false;
13695 			sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
13696 		}
13697 		if (!ndev->ieee80211_ptr->ssid_len) {
13698 			/* In certain cases, the delayed cfg80211 work from
13699 				* disconnect context will induce race conditions in
13700 				* which the ssid_len will be cleared, but dhd is in
13701 				* connecting state. Return connect failure to avoid
13702 				* getting locked in connected state.
13703 				*/
13704 			WL_ERR(("ssid_len=0. Indicate assoc event failure\n"));
13705 			completed = false;
13706 			sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
13707 		}
13708 	}
13709 
13710 	/* Clear status after updating CONNECTED status */
13711 	wl_clr_drv_status(cfg, CONNECTING, ndev);
13712 
13713 	/* update status field */
13714 	if (completed) {
13715 		status = WLAN_STATUS_SUCCESS;
13716 	} else if (sec->auth_assoc_res_status) {
13717 			status = sec->auth_assoc_res_status;
13718 	} else {
13719 		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
13720 	}
13721 
13722 	if (completed) {
13723 		WL_MSG(ndev->name, "Report connect result - connection succeeded\n");
13724 #ifdef WL_EXT_IAPSTA
13725 		wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
13726 		wl_ext_iapsta_enable_master_if(ndev, TRUE);
13727 #endif
13728 	} else {
13729 		WL_MSG(ndev->name, "Report connect result - connection failed\n");
13730 #ifdef WL_EXT_IAPSTA
13731 		wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
13732 			WL_EXT_STATUS_DISCONNECTED, NULL);
13733 #endif
13734 	}
13735 
13736 #ifdef WL_FILS
13737 	if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
13738 		if ((err = wl_get_fils_connect_params(cfg, ndev)) != BCME_OK) {
13739 			WL_ERR(("FILS params fetch failed.\n"));
13740 			goto exit;
13741 		}
13742 
13743 		if (wl_fillup_resp_params(cfg, ndev, curbssid, &resp_params, status) != BCME_OK) {
13744 			WL_ERR(("connect resp_params failure\n"));
13745 			err = BCME_ERROR;
13746 			goto exit;
13747 		}
13748 		cfg80211_connect_done(ndev, &resp_params, GFP_KERNEL);
13749 	}
13750 	else
13751 #endif /* WL_FILS */
13752 	{
13753 		CFG80211_CONNECT_RESULT(ndev, curbssid, bss,
13754 			conn_info->req_ie, conn_info->req_ie_len,
13755 			conn_info->resp_ie, conn_info->resp_ie_len,
13756 			status, GFP_KERNEL);
13757 	}
13758 
13759 	if (completed) {
13760 		LOG_TS(cfg, conn_cmplt);
13761 		LOG_TS(cfg, authorize_start);
13762 		WL_INFORM_MEM(("[%s] Report connect result - "
13763 			"connection succeeded\n", ndev->name));
13764 
13765 #ifdef BCMWAPI_WPI
13766 		if (sec->cipher_group == WLAN_CIPHER_SUITE_SMS4) {
13767 			/* In WAPI case, there is no seperate authorized call
13768 				* from upper layer. so set the state from connect done.
13769 				*/
13770 			wl_set_drv_status(cfg, AUTHORIZED, ndev);
13771 			CLR_TS(cfg, authorize_start);
13772 			LOG_TS(cfg, authorize_cmplt);
13773 		}
13774 #endif /* WAPI */
13775 	}
13776 
13777 exit:
13778 	CLR_TS(cfg, conn_start);
13779 	return err;
13780 }
13781 
13782 static s32
wl_notify_mic_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)13783 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13784 	const wl_event_msg_t *e, void *data)
13785 {
13786 	struct net_device *ndev = NULL;
13787 	u16 flags = ntoh16(e->flags);
13788 	enum nl80211_key_type key_type;
13789 
13790 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13791 
13792 	WL_INFORM_MEM(("[%s] mic fail event - " MACDBG " \n",
13793 		ndev->name, MAC2STRDBG(e->addr.octet)));
13794 	mutex_lock(&cfg->usr_sync);
13795 	if (flags & WLC_EVENT_MSG_GROUP)
13796 		key_type = NL80211_KEYTYPE_GROUP;
13797 	else
13798 		key_type = NL80211_KEYTYPE_PAIRWISE;
13799 
13800 	wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
13801 	cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1,
13802 		NULL, GFP_KERNEL);
13803 	mutex_unlock(&cfg->usr_sync);
13804 
13805 	return 0;
13806 }
13807 
13808 #ifdef BT_WIFI_HANDOVER
13809 static s32
wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)13810 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13811 	const wl_event_msg_t *e, void *data)
13812 {
13813 	struct net_device *ndev = NULL;
13814 	u32 event = ntoh32(e->event_type);
13815 	u32 datalen = ntoh32(e->datalen);
13816 	s32 err;
13817 
13818 	WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen));
13819 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13820 	err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0);
13821 
13822 	return err;
13823 }
13824 #endif /* BT_WIFI_HANDOVER */
13825 
13826 #ifdef WL_CFG80211_GON_COLLISION
13827 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)13828 wl_gon_req_collision(struct bcm_cfg80211 *cfg, wl_action_frame_t *tx_act_frm,
13829 	wifi_p2p_pub_act_frame_t *rx_act_frm, struct net_device *ndev,
13830 	struct ether_addr sa, struct ether_addr da)
13831 {
13832 	if (cfg->afx_hdl->pending_tx_act_frm == NULL)
13833 		return;
13834 
13835 	if (tx_act_frm &&
13836 		wl_cfgp2p_is_pub_action(tx_act_frm->data, tx_act_frm->len)) {
13837 		wifi_p2p_pub_act_frame_t *pact_frm;
13838 
13839 		pact_frm = (wifi_p2p_pub_act_frame_t *)tx_act_frm->data;
13840 
13841 		if (!(pact_frm->subtype == P2P_PAF_GON_REQ &&
13842 			rx_act_frm->subtype == P2P_PAF_GON_REQ)) {
13843 			return;
13844 		}
13845 	}
13846 
13847 	WL_ERR((" GO NEGO Request COLLISION !!! \n"));
13848 
13849 	/* if sa(peer) addr is less than da(my) addr,
13850 	 * my device will process peer's gon request and block to send my gon req.
13851 	 *
13852 	 * if not (sa addr > da addr),
13853 	 * my device will process gon request and drop gon req of peer.
13854 	 */
13855 	if (memcmp(sa.octet, da.octet, ETHER_ADDR_LEN) < 0) {
13856 		/* block to send tx gon request */
13857 		cfg->block_gon_req_tx_count = BLOCK_GON_REQ_MAX_NUM;
13858 		WL_ERR((" block to send gon req tx !!!\n"));
13859 
13860 		/* if we are finding a common channel for sending af,
13861 		 * do not scan more to block to send current gon req
13862 		 */
13863 		if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
13864 			wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, ndev);
13865 			complete(&cfg->act_frm_scan);
13866 		}
13867 	} else {
13868 		/* drop gon request of peer to process gon request by my device. */
13869 		WL_ERR((" drop to receive gon req rx !!! \n"));
13870 		cfg->block_gon_req_rx_count = BLOCK_GON_REQ_MAX_NUM;
13871 	}
13872 
13873 	return;
13874 }
13875 #endif /* WL_CFG80211_GON_COLLISION */
13876 
13877 void
wl_stop_wait_next_action_frame(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 bsscfgidx)13878 wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 bsscfgidx)
13879 {
13880 	s32 err = 0;
13881 
13882 	if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
13883 		del_timer_sync(&cfg->p2p->listen_timer);
13884 		if (cfg->afx_hdl != NULL) {
13885 			if (cfg->afx_hdl->dev != NULL) {
13886 				wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
13887 				wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev);
13888 			}
13889 			cfg->afx_hdl->peer_chan = WL_INVALID;
13890 		}
13891 		complete(&cfg->act_frm_scan);
13892 		WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
13893 	} else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
13894 		if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
13895 			wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
13896 			wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
13897 
13898 		WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx));
13899 		/* Scan engine is not used for sending action frames in the latest driver
13900 		 * branches. actframe_abort is used in the latest driver branches
13901 		 * instead of scan abort.
13902 		 *  If actframe_abort iovar succeeds, don't execute scan abort.
13903 		 *  If actframe_abort fails with unsupported error,
13904 		 *  execute scan abort (for backward copmatibility).
13905 		 */
13906 		if (cfg->af_sent_channel) {
13907 			err = wldev_iovar_setint_bsscfg(ndev, "actframe_abort", 1, bsscfgidx);
13908 			if (err < 0) {
13909 				if (err == BCME_UNSUPPORTED) {
13910 					mutex_lock(&cfg->scan_sync);
13911 					wl_cfgscan_scan_abort(cfg);
13912 					mutex_unlock(&cfg->scan_sync);
13913 				} else {
13914 					WL_ERR(("actframe_abort failed. ret:%d\n", err));
13915 				}
13916 			}
13917 		}
13918 	}
13919 #ifdef WL_CFG80211_SYNC_GON
13920 	else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
13921 		WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
13922 		/* So abort scan to cancel listen */
13923 		wl_cfgscan_cancel_scan(cfg);
13924 	}
13925 #endif /* WL_CFG80211_SYNC_GON */
13926 }
13927 
13928 #if defined(WES_SUPPORT)
wl_cfg80211_set_wes_mode(struct net_device * dev,int mode)13929 int wl_cfg80211_set_wes_mode(struct net_device *dev, int mode)
13930 {
13931 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13932 	cfg->wes_mode = mode;
13933 	return 0;
13934 }
13935 
wl_cfg80211_get_wes_mode(struct net_device * dev)13936 int wl_cfg80211_get_wes_mode(struct net_device *dev)
13937 {
13938 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13939 	return cfg->wes_mode;
13940 }
13941 
wl_cfg80211_is_wes(void * frame,u32 frame_len)13942 bool wl_cfg80211_is_wes(void *frame, u32 frame_len)
13943 {
13944 	unsigned char *data;
13945 
13946 	if (frame == NULL) {
13947 		WL_ERR(("Invalid frame \n"));
13948 		return false;
13949 	}
13950 
13951 	if (frame_len < 4) {
13952 		WL_ERR(("Invalid frame length [%d] \n", frame_len));
13953 		return false;
13954 	}
13955 
13956 	data = frame;
13957 
13958 	if (memcmp(data, "\x7f\x00\x00\xf0", 4) == 0) {
13959 		WL_DBG(("Receive WES VS Action Frame \n"));
13960 		return true;
13961 	}
13962 
13963 	return false;
13964 }
13965 
13966 int
wl_cfg80211_set_ncho_mode(struct net_device * dev,int mode)13967 wl_cfg80211_set_ncho_mode(struct net_device *dev, int mode)
13968 {
13969 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13970 	cfg->ncho_mode = mode;
13971 	return BCME_OK;
13972 }
13973 
13974 int
wl_cfg80211_get_ncho_mode(struct net_device * dev)13975 wl_cfg80211_get_ncho_mode(struct net_device *dev)
13976 {
13977 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13978 	return cfg->ncho_mode;
13979 }
13980 #endif /* WES_SUPPORT */
13981 
wl_cfg80211_get_ioctl_version(void)13982 int wl_cfg80211_get_ioctl_version(void)
13983 {
13984 	return ioctl_version;
13985 }
13986 
13987 static s32
wl_notify_rx_mgmt_frame(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)13988 wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13989 	const wl_event_msg_t *e, void *data)
13990 {
13991 	struct ether_addr da;
13992 	struct ether_addr bssid;
13993 	bool isfree = false;
13994 	s32 err = 0;
13995 	s32 freq;
13996 	struct net_device *ndev = NULL;
13997 	wifi_p2p_pub_act_frame_t *act_frm = NULL;
13998 	wifi_p2p_action_frame_t *p2p_act_frm = NULL;
13999 	wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
14000 	wl_event_rx_frame_data_t *rxframe;
14001 	u32 event;
14002 	u8 *mgmt_frame;
14003 	u8 bsscfgidx;
14004 	u32 mgmt_frame_len;
14005 	chanspec_t chspec;
14006 #if defined(BCMDONGLEHOST) && defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
14007 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14008 #endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
14009 	if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) {
14010 		WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen)));
14011 		return -EINVAL;
14012 	}
14013 	mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_t);
14014 	event = ntoh32(e->event_type);
14015 	bsscfgidx = e->bsscfgidx;
14016 	rxframe = (wl_event_rx_frame_data_t *)data;
14017 	if (!rxframe) {
14018 		WL_ERR(("rxframe: NULL\n"));
14019 		return -EINVAL;
14020 	}
14021 	chspec = ntoh16(rxframe->channel);
14022 	bzero(&bssid, ETHER_ADDR_LEN);
14023 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14024 	if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) &&
14025 		(event == WLC_E_PROBREQ_MSG)) {
14026 		/* Probe req event comes on wlan0 interface even though
14027 		 * the frame have been received on correct interface(AP)
14028 		 * in firmware. Find the right interface to pass it up.
14029 		 * Required for WPS-AP certification 4.2.13.
14030 		 *  TODO/Need a better fix. Current fix doesn't take
14031 		 * care of dual AP/GO scenarios.
14032 		 */
14033 		struct net_info *iter, *next;
14034 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
14035 		for_each_ndev(cfg, iter, next) {
14036 			GCC_DIAGNOSTIC_POP();
14037 			if (iter->ndev && iter->wdev &&
14038 					iter->wdev->iftype == NL80211_IFTYPE_AP) {
14039 					ndev = iter->ndev;
14040 					cfgdev =  ndev_to_cfgdev(ndev);
14041 					break;
14042 			}
14043 		}
14044 	}
14045 
14046 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
14047 	freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chspec));
14048 #else
14049 	freq = wl_channel_to_frequency(wf_chspec_ctlchan(chspec), CHSPEC_BAND(chspec));
14050 #endif
14051 	if (event == WLC_E_ACTION_FRAME_RX) {
14052 		u8 ioctl_buf[WLC_IOCTL_SMLEN];
14053 		if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
14054 				NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx,
14055 				NULL)) != BCME_OK) {
14056 			WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
14057 			goto exit;
14058 		}
14059 
14060 		err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14061 		if (err < 0)
14062 			 WL_ERR(("WLC_GET_BSSID error %d\n", err));
14063 		memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
14064 		err = wl_frame_get_mgmt(cfg, FC_ACTION, &da, &e->addr, &bssid,
14065 			&mgmt_frame, &mgmt_frame_len,
14066 			(u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
14067 		if (err < 0) {
14068 			WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
14069 				mgmt_frame_len, CHSPEC_CHANNEL(chspec), freq));
14070 			goto exit;
14071 		}
14072 		isfree = true;
14073 
14074 		wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
14075 			mgmt_frame_len - DOT11_MGMT_HDR_LEN, CHSPEC_CHANNEL(chspec));
14076 
14077 		if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14078 			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14079 			act_frm = (wifi_p2p_pub_act_frame_t *)
14080 					(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
14081 		} else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14082 			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14083 			p2p_act_frm = (wifi_p2p_action_frame_t *)
14084 					(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
14085 			(void) p2p_act_frm;
14086 		} else if (wl_cfg80211_is_dpp_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14087 			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14088 			wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14089 
14090 			/* Stop waiting for next AF. */
14091 			wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14092 		} else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14093 			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14094 #ifdef WL_SDO
14095 			if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
14096 				WL_ERR(("SD offload is in progress. Don't report the"
14097 					"frame via rx_mgmt path\n"));
14098 				goto exit;
14099 			}
14100 #endif
14101 			sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
14102 					(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
14103 			if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
14104 				if (cfg->next_af_subtype == sd_act_frm->action) {
14105 					WL_DBG(("We got a right next frame of SD!(%d)\n",
14106 						sd_act_frm->action));
14107 					wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14108 
14109 					/* Stop waiting for next AF. */
14110 					wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14111 				}
14112 			}
14113 			(void) sd_act_frm;
14114 #ifdef WLTDLS
14115 		} else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
14116 				(wl_cfg80211_is_tdls_tunneled_frame(
14117 				    &mgmt_frame[DOT11_MGMT_HDR_LEN],
14118 				    mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
14119 			if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
14120 				WL_ERR((" TDLS Action Frame Received type = %d \n",
14121 					mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
14122 			}
14123 #ifdef TDLS_MSG_ONLY_WFD
14124 #ifdef BCMDONGLEHOST
14125 			if (!dhdp->tdls_mode) {
14126 				WL_DBG((" TDLS Frame filtered \n"));
14127 				goto exit;
14128 			}
14129 #endif /* BCMDONGLEHOST */
14130 #else
14131 			if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
14132 				cfg->tdls_mgmt_frame = mgmt_frame;
14133 				cfg->tdls_mgmt_frame_len = mgmt_frame_len;
14134 				cfg->tdls_mgmt_freq = freq;
14135 				return 0;
14136 			}
14137 #endif /* TDLS_MSG_ONLY_WFD */
14138 #endif /* WLTDLS */
14139 #ifdef QOS_MAP_SET
14140 		} else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
14141 			/* update QoS map set table */
14142 			bcm_tlv_t * qos_map_ie = NULL;
14143 			uint8 offset = DOT11_MGMT_HDR_LEN + DOT11_ACTION_FRMHDR_LEN;
14144 			if ((qos_map_ie = bcm_parse_tlvs(&mgmt_frame[offset],
14145 					mgmt_frame_len - offset, DOT11_MNG_QOS_MAP_ID)) != NULL) {
14146 				WL_DBG((" QoS map set IE found in QoS action frame\n"));
14147 				if (!cfg->up_table) {
14148 					cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
14149 				}
14150 				wl_set_up_table(cfg->up_table, qos_map_ie);
14151 			} else {
14152 				MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
14153 			}
14154 #endif /* QOS_MAP_SET */
14155 #ifdef WBTEXT
14156 		} else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_RRM) {
14157 			/* radio measurement category */
14158 			switch (mgmt_frame[DOT11_MGMT_HDR_LEN+1]) {
14159 				case DOT11_RM_ACTION_NR_REP:
14160 					if (wl_cfg80211_recv_nbr_resp(ndev,
14161 							&mgmt_frame[DOT11_MGMT_HDR_LEN],
14162 							mgmt_frame_len - DOT11_MGMT_HDR_LEN)
14163 							== BCME_OK) {
14164 						WL_DBG(("RCC updated by nbr response\n"));
14165 					}
14166 					break;
14167 				default:
14168 					break;
14169 			}
14170 #endif /* WBTEXT */
14171 		} else {
14172 			/* WAR : There is no way to identify DA of action frame as of now.
14173 			 *  We have to modify firmware code to include DA and SA of Act frame
14174 			 *  as event data
14175 			 */
14176 			/*
14177 			 *  if we got normal action frame and ndev is p2p0,
14178 			 *  we have to change ndev from p2p0 to wlan0
14179 			 */
14180 #if defined(WES_SUPPORT)
14181 			if (wl_cfg80211_is_wes(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14182 			mgmt_frame_len - DOT11_MGMT_HDR_LEN) && cfg->wes_mode == 0) {
14183 			/* Ignore WES VS Action frame */
14184 			goto exit;
14185 			}
14186 #endif /* WES_SUPPORT */
14187 
14188 			/* We need to check proper action frame is received */
14189 			if (cfg->next_af_subtype != WL_PUB_AF_STYPE_INVALID) {
14190 				u8 action = 0;
14191 				if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14192 					mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) {
14193 					WL_DBG(("Recived action is not public action frame\n"));
14194 				} else if (cfg->next_af_subtype == action) {
14195 					WL_DBG(("Recived action is the waiting action(%d)\n",
14196 						action));
14197 					wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14198 
14199 					/* Stop waiting for next AF. */
14200 					wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14201 				}
14202 			}
14203 		}
14204 
14205 		if (act_frm) {
14206 #ifdef WL_CFG80211_GON_COLLISION
14207 			if (act_frm->subtype == P2P_PAF_GON_REQ) {
14208 				wl_gon_req_collision(cfg,
14209 					&cfg->afx_hdl->pending_tx_act_frm->action_frame,
14210 					act_frm, ndev, e->addr, da);
14211 
14212 				if (cfg->block_gon_req_rx_count) {
14213 					WL_ERR(("drop frame GON Req Rx : count (%d)\n",
14214 						cfg->block_gon_req_rx_count));
14215 					cfg->block_gon_req_rx_count--;
14216 					goto exit;
14217 				}
14218 			} else if (act_frm->subtype == P2P_PAF_GON_CONF) {
14219 				/* if go formation done, clear it */
14220 				cfg->block_gon_req_tx_count = 0;
14221 				cfg->block_gon_req_rx_count = 0;
14222 			}
14223 #endif /* WL_CFG80211_GON_COLLISION */
14224 
14225 			if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
14226 				if (cfg->next_af_subtype == act_frm->subtype) {
14227 					WL_DBG(("We got a right next frame!(%d)\n",
14228 						act_frm->subtype));
14229 					wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14230 
14231 					if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
14232 						OSL_SLEEP(20);
14233 					}
14234 
14235 					/* Stop waiting for next AF. */
14236 					wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14237 				} else if ((cfg->next_af_subtype == P2P_PAF_GON_RSP) &&
14238 						(act_frm->subtype == P2P_PAF_GON_REQ)) {
14239 					/* If current received frame is GO NEG REQ and next
14240 					 * expected frame is GO NEG RESP, do not send it up.
14241 					 */
14242 					WL_ERR(("GO Neg req received while waiting for RESP."
14243 						"Discard incoming frame\n"));
14244 					goto exit;
14245 				}
14246 			}
14247 		}
14248 
14249 		if (wl_cfg80211_is_dpp_frame(
14250 			(void *)&mgmt_frame[DOT11_MGMT_HDR_LEN],
14251 			mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14252 			wl_dpp_pa_frame_t *pa =
14253 				(wl_dpp_pa_frame_t *)&mgmt_frame[DOT11_MGMT_HDR_LEN];
14254 			if (cfg->next_af_subtype == pa->ftype) {
14255 				WL_DBG(("matching dpp frm (%d) found. abort dwell\n", pa->ftype));
14256 				wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14257 
14258 				/* Stop waiting for next AF. */
14259 				wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14260 			}
14261 		}
14262 		if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
14263 			WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
14264 			wl_clr_p2p_status(cfg, GO_NEG_PHASE);
14265 		}
14266 	} else if (event == WLC_E_PROBREQ_MSG) {
14267 
14268 		/* Handle probe reqs frame
14269 		 * WPS-AP certification 4.2.13
14270 		 */
14271 		struct parsed_ies prbreq_ies;
14272 		u32 prbreq_ie_len = 0;
14273 		bool pbc = 0;
14274 
14275 		WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
14276 		mgmt_frame = (u8 *)(data);
14277 		mgmt_frame_len = ntoh32(e->datalen);
14278 		if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) {
14279 			WL_ERR(("wrong datalen:%d\n", mgmt_frame_len));
14280 			return -EINVAL;
14281 		}
14282 		prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
14283 
14284 		/* Parse prob_req IEs */
14285 		if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14286 			prbreq_ie_len, &prbreq_ies) < 0) {
14287 			WL_ERR(("Prob req get IEs failed\n"));
14288 			return 0;
14289 		}
14290 
14291 		if (prbreq_ies.wps_ie != NULL) {
14292 			wl_validate_wps_ie(
14293 				(const char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
14294 			WL_DBG((" wps_ie exist pbc = %d\n", pbc));
14295 			/* if pbc method, send prob_req mgmt frame to upper layer */
14296 			if (!pbc)
14297 				return 0;
14298 		} else
14299 			return 0;
14300 	} else {
14301 		mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
14302 
14303 		/* wpa supplicant use probe request event for restarting another GON Req.
14304 		 * but it makes GON Req repetition.
14305 		 * so if src addr of prb req is same as my target device,
14306 		 * do not send probe request event during sending action frame.
14307 		 */
14308 		if (event == WLC_E_P2P_PROBREQ_MSG) {
14309 			WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
14310 				"WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
14311 
14312 #ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
14313 			if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) &&
14314 				!memcmp(cfg->afx_hdl->tx_dst_addr.octet, e->addr.octet,
14315 				ETHER_ADDR_LEN)) {
14316 				if (cfg->afx_hdl->pending_tx_act_frm &&
14317 					wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
14318 					chanspec_t channel = hton16(rxframe->channel);
14319 					WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
14320 						channel));
14321 					cfg->afx_hdl->peer_chan = channel;
14322 					complete(&cfg->act_frm_scan);
14323 				}
14324 			}
14325 #endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
14326 
14327 			/* Filter any P2P probe reqs arriving during the
14328 			 * GO-NEG Phase
14329 			 */
14330 			if (cfg->p2p &&
14331 #if defined(P2P_IE_MISSING_FIX)
14332 				cfg->p2p_prb_noti &&
14333 #endif
14334 				wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
14335 				WL_DBG(("Filtering P2P probe_req while "
14336 					"being in GO-Neg state\n"));
14337 				return 0;
14338 			}
14339 		}
14340 	}
14341 
14342 	if (discover_cfgdev(cfgdev, cfg))
14343 		WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
14344 	else
14345 		WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
14346 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14347 	 cfg80211_rx_mgmt(cfgdev, freq, 0,  mgmt_frame, mgmt_frame_len, 0);
14348 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14349 	cfg80211_rx_mgmt(cfgdev, freq, 0,  mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
14350 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14351 	defined(WL_COMPAT_WIRELESS)
14352 	cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
14353 #else
14354 	cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
14355 #endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
14356 
14357 	WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
14358 		mgmt_frame_len, ntoh32(e->datalen), CHSPEC_CHANNEL(chspec), freq));
14359 exit:
14360 	if (isfree) {
14361 		MFREE(cfg->osh, mgmt_frame, mgmt_frame_len);
14362 	}
14363 	return err;
14364 }
14365 
14366 #ifdef CUSTOMER_HW6
14367 static s32
wl_cfg80211_ccode_evt_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * event,void * data)14368 wl_cfg80211_ccode_evt_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14369 	const wl_event_msg_t *event, void *data)
14370 {
14371 	s32 err = 0;
14372 	/* Indicate to upper layer for regdom change */
14373 	WL_INFORM_MEM(("Received country code change event\n"));
14374 	err = wl_update_wiphybands(cfg, true);
14375 
14376 	return err;
14377 }
14378 #endif /* CUSTOMER_HW6 */
14379 
wl_init_conf(struct wl_conf * conf)14380 static void wl_init_conf(struct wl_conf *conf)
14381 {
14382 	WL_DBG(("Enter \n"));
14383 	conf->frag_threshold = (u32)-1;
14384 	conf->rts_threshold = (u32)-1;
14385 	conf->retry_short = (u32)-1;
14386 	conf->retry_long = (u32)-1;
14387 	conf->tx_power = -1;
14388 }
14389 
wl_init_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev)14390 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
14391 {
14392 	unsigned long flags;
14393 	struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
14394 
14395 	if (!profile) {
14396 		WL_ERR(("profile null\n"));
14397 		return;
14398 	}
14399 
14400 	WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
14401 	bzero(profile, sizeof(struct wl_profile));
14402 	WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
14403 }
14404 
wl_init_event_handler(struct bcm_cfg80211 * cfg)14405 static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
14406 {
14407 	bzero(cfg->evt_handler, sizeof(cfg->evt_handler));
14408 
14409 	cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
14410 	cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
14411 	cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
14412 	cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
14413 	cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
14414 	cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
14415 	cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
14416 	cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
14417 	cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
14418 	cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
14419 	cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
14420 	cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
14421 	cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
14422 	cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
14423 	cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
14424 	cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
14425 	cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
14426 	cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
14427 	cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
14428 	cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
14429 	cfg->evt_handler[WLC_E_AUTH_IND] = wl_notify_connect_status;
14430 	cfg->evt_handler[WLC_E_ASSOC_RESP_IE] = wl_notify_connect_status;
14431 #ifdef PNO_SUPPORT
14432 	cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
14433 #endif /* PNO_SUPPORT */
14434 #ifdef GSCAN_SUPPORT
14435 	cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
14436 	cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
14437 	cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
14438 	cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
14439 	cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
14440 	cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
14441 	cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
14442 	cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
14443 #endif /* GSCAN_SUPPORT */
14444 #ifdef RSSI_MONITOR_SUPPORT
14445 	cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
14446 #endif /* RSSI_MONITOR_SUPPORT */
14447 #ifdef WL_SDO
14448 	cfg->evt_handler[WLC_E_SERVICE_FOUND] = wl_svc_resp_handler;
14449 	cfg->evt_handler[WLC_E_P2PO_ADD_DEVICE] = wl_notify_device_discovery;
14450 	cfg->evt_handler[WLC_E_P2PO_DEL_DEVICE] = wl_notify_device_discovery;
14451 #endif
14452 #ifdef WLTDLS
14453 	cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
14454 #endif /* WLTDLS */
14455 	cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
14456 #ifdef WLAIBSS
14457 	cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail;
14458 #endif /* WLAIBSS */
14459 #ifdef	WL_RELMCAST
14460 	cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
14461 #endif /* WL_RELMCAST */
14462 #ifdef BT_WIFI_HANDOVER
14463 	cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
14464 #endif
14465 #ifdef WL_NAN
14466 	cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status;
14467 	cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status;
14468 #endif /* WL_NAN */
14469 	cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
14470 	cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
14471 #ifdef CUSTOM_EVENT_PM_WAKE
14472 	cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
14473 #endif	/* CUSTOM_EVENT_PM_WAKE */
14474 #if defined(DHD_LOSSLESS_ROAMING) || defined (DBG_PKT_MON)
14475 	cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
14476 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON  */
14477 	cfg->evt_handler[WLC_E_ROAM_START] = wl_notify_roam_start_status;
14478 #ifdef WL_BAM
14479 	cfg->evt_handler[WLC_E_ADPS] = wl_adps_event_handler;
14480 #endif	/* WL_BAM */
14481 	cfg->evt_handler[WLC_E_PSK_SUP] = wl_cfg80211_sup_event_handler;
14482 #ifdef CUSTOMER_HW6
14483 	cfg->evt_handler[WLC_E_COUNTRY_CODE_CHANGED] = wl_cfg80211_ccode_evt_handler;
14484 #endif /* CUSTOMER_HW6 */
14485 #ifdef WL_BCNRECV
14486 	cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
14487 #endif /* WL_BCNRECV */
14488 #ifdef WL_MBO
14489 	cfg->evt_handler[WLC_E_MBO] = wl_mbo_event_handler;
14490 #endif  /* WL_MBO */
14491 #ifdef WL_CAC_TS
14492 	cfg->evt_handler[WLC_E_ADDTS_IND] = wl_cfg80211_cac_event_handler;
14493 	cfg->evt_handler[WLC_E_DELTS_IND] = wl_cfg80211_cac_event_handler;
14494 #endif /* WL_CAC_TS */
14495 #if defined(WL_MBO) || defined(WL_OCE)
14496 	cfg->evt_handler[WLC_E_PRUNE] = wl_bssid_prune_event_handler;
14497 #endif /* WL_MBO || WL_OCE */
14498 #ifdef RTT_SUPPORT
14499 	cfg->evt_handler[WLC_E_PROXD] = wl_cfg80211_rtt_event_handler;
14500 #endif
14501 #ifdef WL_CHAN_UTIL
14502 	cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler;
14503 #endif /* WL_CHAN_UTIL */
14504 #ifdef WL_TWT
14505 	cfg->evt_handler[WLC_E_TWT_SETUP] = wl_notify_twt_event;
14506 	cfg->evt_handler[WLC_E_TWT_TEARDOWN] = wl_notify_twt_event;
14507 	cfg->evt_handler[WLC_E_TWT_INFO_FRM] = wl_notify_twt_event;
14508 #endif /* WL_TWT */
14509 #ifdef WL_CLIENT_SAE
14510 	cfg->evt_handler[WLC_E_JOIN_START] = wl_notify_start_auth;
14511 #endif /* WL_CLIENT_SAE */
14512 }
14513 
14514 #if defined(STATIC_WL_PRIV_STRUCT)
14515 static int
wl_init_escan_result_buf(struct bcm_cfg80211 * cfg)14516 wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
14517 {
14518 #ifdef DUAL_ESCAN_RESULT_BUFFER
14519 	cfg->escan_info.escan_buf[0] = DHD_OS_PREALLOC(cfg->pub,
14520 		DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
14521 	if (cfg->escan_info.escan_buf[0] == NULL) {
14522 		WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
14523 		return -ENOMEM;
14524 	}
14525 
14526 	cfg->escan_info.escan_buf[1] = DHD_OS_PREALLOC(cfg->pub,
14527 		DHD_PREALLOC_WIPHY_ESCAN1, ESCAN_BUF_SIZE);
14528 	if (cfg->escan_info.escan_buf[1] == NULL) {
14529 		WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
14530 		return -ENOMEM;
14531 	}
14532 
14533 	bzero(cfg->escan_info.escan_buf[0], ESCAN_BUF_SIZE);
14534 	bzero(cfg->escan_info.escan_buf[1], ESCAN_BUF_SIZE);
14535 	cfg->escan_info.escan_type[0] = 0;
14536 	cfg->escan_info.escan_type[1] = 0;
14537 #else
14538 	cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
14539 		DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
14540 	if (cfg->escan_info.escan_buf == NULL) {
14541 		WL_ERR(("Failed to alloc ESCAN_BUF\n"));
14542 		return -ENOMEM;
14543 	}
14544 	bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
14545 #endif /* DUAL_ESCAN_RESULT_BUFFER */
14546 
14547 	return 0;
14548 }
14549 
14550 static void
wl_deinit_escan_result_buf(struct bcm_cfg80211 * cfg)14551 wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
14552 {
14553 #ifdef DUAL_ESCAN_RESULT_BUFFER
14554 	if (cfg->escan_info.escan_buf[0] != NULL) {
14555 		cfg->escan_info.escan_buf[0] = NULL;
14556 		cfg->escan_info.escan_type[0] = 0;
14557 	}
14558 
14559 	if (cfg->escan_info.escan_buf[1] != NULL) {
14560 		cfg->escan_info.escan_buf[1] = NULL;
14561 		cfg->escan_info.escan_type[1] = 0;
14562 	}
14563 #else
14564 	if (cfg->escan_info.escan_buf != NULL) {
14565 		cfg->escan_info.escan_buf = NULL;
14566 	}
14567 #endif /* DUAL_ESCAN_RESULT_BUFFER */
14568 }
14569 #endif /* STATIC_WL_PRIV_STRUCT */
14570 
wl_init_priv_mem(struct bcm_cfg80211 * cfg)14571 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
14572 {
14573 	WL_DBG(("Enter \n"));
14574 
14575 	cfg->scan_results = (wl_scan_results_t *)MALLOCZ(cfg->osh,
14576 		WL_SCAN_BUF_MAX);
14577 	if (unlikely(!cfg->scan_results)) {
14578 		WL_ERR(("Scan results alloc failed\n"));
14579 		goto init_priv_mem_out;
14580 	}
14581 	cfg->conf = (struct wl_conf *)MALLOCZ(cfg->osh, sizeof(*cfg->conf));
14582 	if (unlikely(!cfg->conf)) {
14583 		WL_ERR(("wl_conf alloc failed\n"));
14584 		goto init_priv_mem_out;
14585 	}
14586 	cfg->scan_req_int = (void *)MALLOCZ(cfg->osh,
14587 		sizeof(*cfg->scan_req_int));
14588 	if (unlikely(!cfg->scan_req_int)) {
14589 		WL_ERR(("Scan req alloc failed\n"));
14590 		goto init_priv_mem_out;
14591 	}
14592 	cfg->ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
14593 	if (unlikely(!cfg->ioctl_buf)) {
14594 		WL_ERR(("Ioctl buf alloc failed\n"));
14595 		goto init_priv_mem_out;
14596 	}
14597 	cfg->escan_ioctl_buf = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
14598 	if (unlikely(!cfg->escan_ioctl_buf)) {
14599 		WL_ERR(("Ioctl buf alloc failed\n"));
14600 		goto init_priv_mem_out;
14601 	}
14602 	cfg->extra_buf = (void *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
14603 	if (unlikely(!cfg->extra_buf)) {
14604 		WL_ERR(("Extra buf alloc failed\n"));
14605 		goto init_priv_mem_out;
14606 	}
14607 	cfg->pmk_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->pmk_list));
14608 	if (unlikely(!cfg->pmk_list)) {
14609 		WL_ERR(("pmk list alloc failed\n"));
14610 		goto init_priv_mem_out;
14611 	}
14612 #if defined(STATIC_WL_PRIV_STRUCT)
14613 	cfg->conn_info = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->conn_info));
14614 	if (unlikely(!cfg->conn_info)) {
14615 		WL_ERR(("cfg->conn_info alloc failed\n"));
14616 		goto init_priv_mem_out;
14617 	}
14618 	cfg->ie = (void *)MALLOC(cfg->osh, sizeof(*cfg->ie));
14619 	if (unlikely(!cfg->ie)) {
14620 		WL_ERR(("cfg->ie alloc failed\n"));
14621 		goto init_priv_mem_out;
14622 	}
14623 	if (unlikely(wl_init_escan_result_buf(cfg))) {
14624 		WL_ERR(("Failed to init escan resul buf\n"));
14625 		goto init_priv_mem_out;
14626 	}
14627 #endif /* STATIC_WL_PRIV_STRUCT */
14628 	cfg->afx_hdl = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->afx_hdl));
14629 	if (unlikely(!cfg->afx_hdl)) {
14630 		WL_ERR(("afx hdl alloc failed\n"));
14631 		goto init_priv_mem_out;
14632 	} else {
14633 		init_completion(&cfg->act_frm_scan);
14634 		init_completion(&cfg->wait_next_af);
14635 
14636 		INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
14637 	}
14638 #ifdef WLTDLS
14639 	if (cfg->tdls_mgmt_frame) {
14640 		MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
14641 		cfg->tdls_mgmt_frame = NULL;
14642 		cfg->tdls_mgmt_frame_len = 0;
14643 	}
14644 #endif /* WLTDLS */
14645 	cfg->spmk_info_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->spmk_info_list));
14646 	if (unlikely(!cfg->spmk_info_list)) {
14647 		WL_ERR(("Single PMK info list allocation falure\n"));
14648 		goto init_priv_mem_out;
14649 	}
14650 
14651 	return 0;
14652 
14653 init_priv_mem_out:
14654 	wl_deinit_priv_mem(cfg);
14655 
14656 	return -ENOMEM;
14657 }
14658 
wl_deinit_priv_mem(struct bcm_cfg80211 * cfg)14659 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
14660 {
14661 	MFREE(cfg->osh, cfg->scan_results, WL_SCAN_BUF_MAX);
14662 	MFREE(cfg->osh, cfg->conf, sizeof(*cfg->conf));
14663 	MFREE(cfg->osh, cfg->scan_req_int, sizeof(*cfg->scan_req_int));
14664 	MFREE(cfg->osh, cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
14665 	MFREE(cfg->osh, cfg->escan_ioctl_buf, WLC_IOCTL_MAXLEN);
14666 	MFREE(cfg->osh, cfg->extra_buf, WL_EXTRA_BUF_MAX);
14667 	MFREE(cfg->osh, cfg->pmk_list, sizeof(*cfg->pmk_list));
14668 #if defined(STATIC_WL_PRIV_STRUCT)
14669 	MFREE(cfg->osh, cfg->conn_info, sizeof(*cfg->conn_info));
14670 	MFREE(cfg->osh, cfg->ie, sizeof(*cfg->ie));
14671 	wl_deinit_escan_result_buf(cfg);
14672 #endif /* STATIC_WL_PRIV_STRUCT */
14673 	if (cfg->afx_hdl) {
14674 #if defined(BCMDONGLEHOST)
14675 		cancel_work_sync(&cfg->afx_hdl->work);
14676 #endif
14677 		MFREE(cfg->osh, cfg->afx_hdl, sizeof(*cfg->afx_hdl));
14678 	}
14679 	MFREE(cfg->osh, cfg->spmk_info_list, sizeof(*cfg->spmk_info_list));
14680 
14681 }
14682 
wl_create_event_handler(struct bcm_cfg80211 * cfg)14683 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
14684 {
14685 	int ret = 0;
14686 	WL_DBG(("Enter \n"));
14687 
14688 	/* making separate work queue needs GPL license,
14689 	 * but some drivers are not in GPL license, so, making seperate queue Android only
14690 	 */
14691 
14692 #ifdef OEM_ANDROID
14693 	/* Allocate workqueue for event */
14694 	if (!cfg->event_workq) {
14695 		cfg->event_workq = alloc_workqueue("dhd_eventd",
14696 			WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 1);
14697 	}
14698 
14699 	if (!cfg->event_workq) {
14700 		WL_ERR(("event_workq alloc_workqueue failed\n"));
14701 		ret = -ENOMEM;
14702 	} else {
14703 		INIT_WORK(&cfg->event_work, wl_event_handler);
14704 	}
14705 #endif /* OEM_ANDROID */
14706 
14707 #ifndef OEM_ANDROID
14708 		INIT_WORK(&cfg->event_work, wl_event_handler);
14709 		cfg->event_workq_init = true;
14710 #endif /* OEM_ANDROID */
14711 	return ret;
14712 }
14713 
wl_destroy_event_handler(struct bcm_cfg80211 * cfg)14714 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
14715 {
14716 
14717 #ifdef OEM_ANDROID
14718 	if (cfg && cfg->event_workq) {
14719 		cancel_work_sync(&cfg->event_work);
14720 		destroy_workqueue(cfg->event_workq);
14721 		cfg->event_workq = NULL;
14722 	}
14723 #endif /* OEM_ANDROID */
14724 
14725 #ifndef OEM_ANDROID
14726 	if (cfg && cfg->event_workq_init) {
14727 #ifdef BCMDONGLEHOST
14728 		cancel_work_sync(&cfg->event_work);
14729 #endif /* BCMDONGLEHOST */
14730 		cfg->event_workq_init = false;
14731 	}
14732 #endif /* OEM_ANDROID */
14733 }
14734 
wl_terminate_event_handler(struct net_device * dev)14735 void wl_terminate_event_handler(struct net_device *dev)
14736 {
14737 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
14738 
14739 	if (cfg) {
14740 		wl_destroy_event_handler(cfg);
14741 		wl_flush_eq(cfg);
14742 	}
14743 }
14744 
14745 #ifdef DHD_LOSSLESS_ROAMING
wl_del_roam_timeout(struct bcm_cfg80211 * cfg)14746 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
14747 {
14748 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14749 
14750 	/* restore prec_map to ALLPRIO */
14751 	dhdp->dequeue_prec_map = ALLPRIO;
14752 	del_timer_sync(&cfg->roam_timeout);
14753 }
14754 
wl_roam_timeout(unsigned long data)14755 static void wl_roam_timeout(unsigned long data)
14756 {
14757 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
14758 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14759 
14760 	WL_ERR(("roam timer expired\n"));
14761 
14762 	/* restore prec_map to ALLPRIO */
14763 	dhdp->dequeue_prec_map = ALLPRIO;
14764 }
14765 
14766 #endif /* DHD_LOSSLESS_ROAMING */
14767 
14768 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
14769 #define CP_CHAN_INFO_RAT_MODE_LTE	3
14770 #define CP_CHAN_INFO_RAT_MODE_NR5G	7
14771 int g_mhs_chan_for_cpcoex = 0;
14772 
14773 struct __packed cam_cp_noti_info {
14774 	u8 rat;
14775 	u32 band;
14776 	u32 channel;
14777 };
14778 
14779 int
wl_cfg80211_send_msg_to_ril()14780 wl_cfg80211_send_msg_to_ril()
14781 {
14782 	int id, buf = 1;
14783 
14784 	id = IPC_SYSTEM_CP_CHANNEL_INFO;
14785 	dev_ril_bridge_send_msg(id, sizeof(int), &buf);
14786 	WL_ERR(("[BeyondX] send message to ril.\n"));
14787 
14788 	OSL_SLEEP(500);
14789 	return 0;
14790 }
14791 
14792 int
wl_cfg80211_ril_bridge_notifier_call(struct notifier_block * nb,unsigned long size,void * buf)14793 wl_cfg80211_ril_bridge_notifier_call(struct notifier_block *nb,
14794 	unsigned long size, void *buf)
14795 {
14796 	struct dev_ril_bridge_msg *msg;
14797 	struct cam_cp_noti_info *cp_noti_info;
14798 	static int mhs_channel_for_4g, mhs_channel_for_5g;
14799 	static int recv_msg_4g, recv_msg_5g;
14800 
14801 	WL_ERR(("[BeyondX] receive message from ril.\n"));
14802 	msg = (struct dev_ril_bridge_msg *)buf;
14803 
14804 	if (msg->dev_id == IPC_SYSTEM_CP_CHANNEL_INFO &&
14805 		msg->data_len <= sizeof(struct cam_cp_noti_info)) {
14806 		u8 rat;
14807 		u32 band;
14808 		u32 channel;
14809 
14810 		cp_noti_info = (struct cam_cp_noti_info *)msg->data;
14811 		rat = cp_noti_info->rat;
14812 		band = cp_noti_info->band;
14813 		channel = cp_noti_info->channel;
14814 
14815 		/* LTE/5G Band/Freq information => Mobile Hotspot channel mapping.
14816 		 * LTE/B40: 38650~39649 => Ch.11
14817 		 * LTE/B41: 39650~41589 => Ch.1
14818 		 * 5G/N41: 499200~537999 => Ch.1
14819 		 */
14820 		if (rat == CP_CHAN_INFO_RAT_MODE_LTE) {
14821 			recv_msg_4g = 1;
14822 			if (channel >= 38650 && channel <= 39649) {
14823 				mhs_channel_for_4g = 11;
14824 			} else if (channel >= 39650 && channel <= 41589) {
14825 				mhs_channel_for_4g = 1;
14826 			}
14827 		}
14828 		if (rat == CP_CHAN_INFO_RAT_MODE_NR5G) {
14829 			recv_msg_5g = 1;
14830 			if (channel >= 499200 && channel <= 537999) {
14831 				mhs_channel_for_5g = 1;
14832 			}
14833 		}
14834 
14835 		WL_DBG(("[BeyondX] rat: %u, band: %u, channel: %u, mhs_channel_for_4g: %u, "
14836 			"mhs_channel_for_5g: %u\n", rat, band, channel,
14837 			mhs_channel_for_4g, mhs_channel_for_5g));
14838 
14839 		if (recv_msg_4g && recv_msg_5g) {
14840 			if (mhs_channel_for_4g && mhs_channel_for_5g) {
14841 				/* if 4G/B40 + 5G/N41, select channel 6 for MHS */
14842 				if (mhs_channel_for_4g == 11 && mhs_channel_for_5g == 1) {
14843 					g_mhs_chan_for_cpcoex = 6;
14844 				/* if 4G(except for B40) + 5G/N41, select channel 1 for MHS */
14845 				} else {
14846 					g_mhs_chan_for_cpcoex = 1;
14847 				}
14848 			} else {
14849 				g_mhs_chan_for_cpcoex = mhs_channel_for_4g ? mhs_channel_for_4g :
14850 					mhs_channel_for_5g ? mhs_channel_for_5g : 0;
14851 			}
14852 			mhs_channel_for_4g = mhs_channel_for_5g = 0;
14853 			recv_msg_4g = recv_msg_5g = 0;
14854 		}
14855 	}
14856 
14857 	return 0;
14858 }
14859 
14860 static struct notifier_block wl_cfg80211_ril_bridge_notifier = {
14861 	.notifier_call = wl_cfg80211_ril_bridge_notifier_call,
14862 };
14863 
14864 static bool wl_cfg80211_ril_bridge_notifier_registered = FALSE;
14865 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
14866 
14867 static s32
wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,unsigned long state,void * ptr)14868 wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
14869 	unsigned long state, void *ptr)
14870 {
14871 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
14872 	struct net_device *dev = ptr;
14873 #else
14874 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
14875 #endif /* LINUX_VERSION < VERSION(3, 11, 0) */
14876 	struct wireless_dev *wdev = NULL;
14877 	struct bcm_cfg80211 *cfg = NULL;
14878 
14879 	WL_DBG(("Enter state:%lu  ndev%p \n", state, dev));
14880 	if (!dev) {
14881 		WL_ERR(("dev null\n"));
14882 		return NOTIFY_DONE;
14883 	}
14884 
14885 	wdev = ndev_to_wdev(dev);
14886 	if (!wdev) {
14887 		WL_ERR(("wdev null. Do nothing\n"));
14888 		return NOTIFY_DONE;
14889 	}
14890 
14891 	cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
14892 	if (!cfg || (cfg != wl_cfg80211_get_bcmcfg())) {
14893 		/* If cfg80211 priv is null or doesn't match return */
14894 		WL_ERR(("wrong cfg ptr (%p)\n", cfg));
14895 		return NOTIFY_DONE;
14896 	}
14897 
14898 	if (dev == bcmcfg_to_prmry_ndev(cfg)) {
14899 		/* Nothing to be done for primary I/F */
14900 		return NOTIFY_DONE;
14901 	}
14902 
14903 	switch (state) {
14904 		case NETDEV_DOWN:
14905 		{
14906 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
14907 			int max_wait_timeout = 2;
14908 			int max_wait_count = 100;
14909 			int refcnt = 0;
14910 			unsigned long limit = jiffies + max_wait_timeout * HZ;
14911 			while (work_pending(&wdev->cleanup_work)) {
14912 				if (refcnt%5 == 0) {
14913 					WL_ERR(("[NETDEV_DOWN] wait for "
14914 						"complete of cleanup_work"
14915 						" (%d th)\n", refcnt));
14916 				}
14917 				if (!time_before(jiffies, limit)) {
14918 					WL_ERR(("[NETDEV_DOWN] cleanup_work"
14919 						" of CFG80211 is not"
14920 						" completed in %d sec\n",
14921 						max_wait_timeout));
14922 					break;
14923 				}
14924 				if (refcnt >= max_wait_count) {
14925 					WL_ERR(("[NETDEV_DOWN] cleanup_work"
14926 						" of CFG80211 is not"
14927 						" completed in %d loop\n",
14928 						max_wait_count));
14929 					break;
14930 				}
14931 				set_current_state(TASK_INTERRUPTIBLE);
14932 				(void)schedule_timeout(100);
14933 				set_current_state(TASK_RUNNING);
14934 				refcnt++;
14935 			}
14936 #endif /* LINUX_VERSION < VERSION(3, 14, 0) */
14937 			break;
14938 		}
14939 		case NETDEV_UNREGISTER:
14940 			wl_cfg80211_clear_per_bss_ies(cfg, wdev);
14941 			/* after calling list_del_rcu(&wdev->list) */
14942 			wl_dealloc_netinfo_by_wdev(cfg, wdev);
14943 			break;
14944 		case NETDEV_GOING_DOWN:
14945 			/*
14946 			 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
14947 			 * In front of door, the function checks whether current scan
14948 			 * is working or not. If the scanning is still working,
14949 			 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
14950 			 */
14951 			if (wl_get_drv_status(cfg, SCANNING, dev))
14952 				wl_cfgscan_cancel_scan(cfg);
14953 			break;
14954 	}
14955 	return NOTIFY_DONE;
14956 }
14957 
14958 static struct notifier_block wl_cfg80211_netdev_notifier = {
14959 	.notifier_call = wl_cfg80211_netdev_notifier_call,
14960 };
14961 
14962 /*
14963  * to make sure we won't register the same notifier twice, otherwise a loop is likely to be
14964  * created in kernel notifier link list (with 'next' pointing to itself)
14965  */
14966 static bool wl_cfg80211_netdev_notifier_registered = FALSE;
14967 
wl_cfg80211_concurrent_roam(struct bcm_cfg80211 * cfg,int enable)14968 void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
14969 {
14970 	u32 connected_cnt  = wl_get_drv_status_all(cfg, CONNECTED);
14971 	bool p2p_connected  = wl_cfgp2p_vif_created(cfg);
14972 #ifdef WL_NAN
14973 	bool nan_connected  = wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg));
14974 #endif /* WL_NAN */
14975 	struct net_info *iter, *next;
14976 
14977 	if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT))
14978 		return;
14979 
14980 	WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
14981 		enable, p2p_connected, connected_cnt));
14982 	/* Disable FW roam when we have a concurrent P2P connection */
14983 	if (enable &&
14984 		((p2p_connected && connected_cnt > 1) ||
14985 #ifdef WL_NAN
14986 		nan_connected ||
14987 #endif /* WL_NAN */
14988 		FALSE)) {
14989 
14990 		/* Mark it as to be reverted */
14991 		cfg->roam_flags |= WL_ROAM_REVERT_STATUS;
14992 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
14993 		for_each_ndev(cfg, iter, next) {
14994 			GCC_DIAGNOSTIC_POP();
14995 			if (iter->ndev && iter->wdev &&
14996 					iter->wdev->iftype == NL80211_IFTYPE_STATION) {
14997 				if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE)
14998 						== BCME_OK) {
14999 					iter->roam_off = TRUE;
15000 				}
15001 				else {
15002 					WL_ERR(("error to enable roam_off\n"));
15003 				}
15004 			}
15005 		}
15006 	}
15007 	else if (!enable && (cfg->roam_flags & WL_ROAM_REVERT_STATUS)) {
15008 		cfg->roam_flags &= ~WL_ROAM_REVERT_STATUS;
15009 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
15010 		for_each_ndev(cfg, iter, next) {
15011 			GCC_DIAGNOSTIC_POP();
15012 			if (iter->ndev && iter->wdev &&
15013 					iter->wdev->iftype == NL80211_IFTYPE_STATION) {
15014 				if (iter->roam_off != WL_INVALID) {
15015 					if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE)
15016 							== BCME_OK) {
15017 						iter->roam_off = FALSE;
15018 					}
15019 					else {
15020 						WL_ERR(("error to disable roam_off\n"));
15021 					}
15022 				}
15023 			}
15024 		}
15025 	}
15026 
15027 	return;
15028 }
15029 
wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 * cfg)15030 static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
15031 {
15032 	struct net_info *iter, *next;
15033 #ifdef WLEASYMESH
15034 	struct net_device *primary_dev;
15035 	dhd_pub_t *dhd = cfg->pub;
15036 #endif /* WLEASYMESH */
15037 	u32 ctl_chan = 0;
15038 	u32 chanspec = 0;
15039 	u32 pre_ctl_chan = 0;
15040 	u32 band = 0;
15041 	u32 pre_band = 0;
15042 	u32 connected_cnt  = wl_get_drv_status_all(cfg, CONNECTED);
15043 	cfg->vsdb_mode = false;
15044 
15045 	if (connected_cnt <= 1)  {
15046 		return;
15047 	}
15048 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
15049 	for_each_ndev(cfg, iter, next) {
15050 		GCC_DIAGNOSTIC_POP();
15051 		/* p2p discovery iface ndev could be null */
15052 		if (iter->ndev) {
15053 			chanspec = 0;
15054 			ctl_chan = 0;
15055 			if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
15056 				if (wldev_iovar_getint(iter->ndev, "chanspec",
15057 					(s32 *)&chanspec) == BCME_OK) {
15058 					chanspec = wl_chspec_driver_to_host(chanspec);
15059 					ctl_chan = wf_chspec_ctlchan(chanspec);
15060 					band = CHSPEC_BAND(chanspec);
15061 					wl_update_prof(cfg, iter->ndev, NULL,
15062 						&chanspec, WL_PROF_CHAN);
15063 				}
15064 				if (!cfg->vsdb_mode) {
15065 					if (!pre_ctl_chan && ctl_chan) {
15066 						pre_ctl_chan = ctl_chan;
15067 						pre_band = band;
15068 					} else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan) &&
15069 						(band == pre_band)) {
15070 						cfg->vsdb_mode = true;
15071 					}
15072 				}
15073 			}
15074 		}
15075 	}
15076 #ifdef WLEASYMESH
15077     if(dhd->conf->fw_type == FW_TYPE_EZMESH && cfg->vsdb_mode) {
15078 		primary_dev = bcmcfg_to_prmry_ndev(cfg);
15079 		WL_MSG("wlan", "check primary chanspec\n");
15080 		if (wldev_iovar_getint(primary_dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
15081 			//chanspec = wl_chspec_driver_to_host(chanspec);
15082 			WL_MSG("wlan", "set primary chanspec to 0x%d\n", chanspec);
15083 			wldev_iovar_setint(primary_dev, "chanspec", chanspec);
15084 		}
15085 		cfg->vsdb_mode = false;
15086     }
15087 #endif /* WLEASYMESH*/
15088 	WL_MSG("wlan", "%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel");
15089 	return;
15090 }
15091 
15092 int
wl_cfg80211_determine_p2p_rsdb_scc_mode(struct bcm_cfg80211 * cfg)15093 wl_cfg80211_determine_p2p_rsdb_scc_mode(struct bcm_cfg80211 *cfg)
15094 {
15095 	struct net_info *iter, *next;
15096 	u32 chanspec = 0;
15097 	u32 pre_chanspec = 0;
15098 	u32 band = 0;
15099 	u32 pre_band = INVCHANSPEC;
15100 	bool is_rsdb_supported = FALSE;
15101 	bool rsdb_or_scc_mode = FALSE;
15102 
15103 #ifdef BCMDONGLEHOST
15104 	is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
15105 #endif /* BCMDONGLEHOST */
15106 
15107 	if (!is_rsdb_supported) {
15108 		return 0;
15109 	}
15110 
15111 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
15112 	for_each_ndev(cfg, iter, next) {
15113 		GCC_DIAGNOSTIC_POP();
15114 		/* p2p discovery iface ndev could be null */
15115 		if (iter->ndev) {
15116 			chanspec = 0;
15117 			band = 0;
15118 			if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
15119 				if (wldev_iovar_getint(iter->ndev, "chanspec",
15120 					(s32 *)&chanspec) == BCME_OK) {
15121 					chanspec = wl_chspec_driver_to_host(chanspec);
15122 					band = CHSPEC_BAND(chanspec);
15123 				}
15124 
15125 				if (pre_band == INVCHANSPEC && chanspec) {
15126 					pre_band = band;
15127 					pre_chanspec = chanspec;
15128 				} else {
15129 					if ((pre_band == band) && (pre_chanspec != chanspec)) {
15130 						/* VSDB case */
15131 						rsdb_or_scc_mode = FALSE;
15132 					} else {
15133 						/* RSDB/SCC case */
15134 						rsdb_or_scc_mode = TRUE;
15135 					}
15136 				}
15137 			}
15138 		}
15139 	}
15140 	WL_DBG(("RSDB or SCC mode is %s\n", rsdb_or_scc_mode ? "enabled" : "disabled"));
15141 
15142 	return rsdb_or_scc_mode;
15143 }
15144 
wl_notifier_change_state(struct bcm_cfg80211 * cfg,struct net_info * _net_info,enum wl_status state,bool set)15145 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
15146 	enum wl_status state, bool set)
15147 {
15148 	s32 pm = PM_FAST;
15149 	s32 err = BCME_OK;
15150 	u32 mode;
15151 	chanspec_t chspec = 0;
15152 	struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
15153 #ifdef BCMDONGLEHOST
15154 	dhd_pub_t *dhd = cfg->pub;
15155 #endif /* BCMDONGLEHOST */
15156 #ifdef RTT_SUPPORT
15157 	rtt_status_info_t *rtt_status;
15158 #endif /* RTT_SUPPORT */
15159 #ifdef DISABLE_FRAMEBURST_VSDB
15160 	bool rsdb_scc_flag = FALSE;
15161 #endif /* DISABLE_FRAMEBURST_VSDB */
15162 #ifdef BCMDONGLEHOST
15163 	if (dhd->busstate == DHD_BUS_DOWN) {
15164 		WL_ERR(("busstate is DHD_BUS_DOWN!\n"));
15165 		return 0;
15166 	}
15167 #endif /* BCMDONGLEHOST */
15168 	WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
15169 		state, set, _net_info->pm_restore, _net_info->ndev->name));
15170 
15171 	if (state != WL_STATUS_CONNECTED)
15172 		return 0;
15173 	mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
15174 	if (set) {
15175 		wl_cfg80211_concurrent_roam(cfg, 1);
15176 		wl_cfg80211_determine_vsdb_mode(cfg);
15177 		if (mode == WL_MODE_AP) {
15178 			if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
15179 				WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
15180 		}
15181 		pm = PM_OFF;
15182 		if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
15183 				sizeof(pm))) != 0) {
15184 			if (err == -ENODEV)
15185 				WL_DBG(("%s:netdev not ready\n",
15186 					_net_info->ndev->name));
15187 			else
15188 				WL_ERR(("%s:error (%d)\n",
15189 					_net_info->ndev->name, err));
15190 
15191 			wl_cfg80211_update_power_mode(_net_info->ndev);
15192 		}
15193 		wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
15194 #if defined(WLTDLS)
15195 		if (wl_cfg80211_is_concurrent_mode(primary_dev)) {
15196 			err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
15197 		}
15198 #endif /* defined(WLTDLS) */
15199 
15200 #ifdef BCMDONGLEHOST
15201 #ifdef DISABLE_FRAMEBURST_VSDB
15202 		if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
15203 			wl_cfg80211_is_concurrent_mode(primary_dev)) {
15204 			rsdb_scc_flag = wl_cfg80211_determine_p2p_rsdb_scc_mode(cfg);
15205 			wl_cfg80211_set_frameburst(cfg, rsdb_scc_flag);
15206 		}
15207 #endif /* DISABLE_FRAMEBURST_VSDB */
15208 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
15209 		if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
15210 			wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
15211 			/* Enable frameburst for
15212 			 * STA/SoftAP concurrent mode
15213 			 */
15214 			wl_cfg80211_set_frameburst(cfg, TRUE);
15215 		}
15216 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
15217 #endif /* BCMDONGLEHOST */
15218 	} else { /* clear */
15219 		chspec = INVCHANSPEC;
15220 		/* clear chan information when the net device is disconnected */
15221 		wl_update_prof(cfg, _net_info->ndev, NULL, &chspec, WL_PROF_CHAN);
15222 		wl_cfg80211_determine_vsdb_mode(cfg);
15223 		if (primary_dev == _net_info->ndev) {
15224 			pm = PM_FAST;
15225 #ifdef RTT_SUPPORT
15226 			rtt_status = GET_RTTSTATE(dhd);
15227 			if (rtt_status->status != RTT_ENABLED) {
15228 #endif /* RTT_SUPPORT */
15229 				if (dhd_conf_get_pm(dhd) >= 0)
15230 					pm = dhd_conf_get_pm(dhd);
15231 				if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
15232 						sizeof(pm))) != 0) {
15233 					if (err == -ENODEV)
15234 						WL_DBG(("%s:netdev not ready\n",
15235 							_net_info->ndev->name));
15236 					else
15237 						WL_ERR(("%s:error (%d)\n",
15238 							_net_info->ndev->name, err));
15239 
15240 					wl_cfg80211_update_power_mode(_net_info->ndev);
15241 				}
15242 #ifdef RTT_SUPPORT
15243 			}
15244 #endif /* RTT_SUPPORT */
15245 		}
15246 		wl_cfg80211_concurrent_roam(cfg, 0);
15247 #if defined(WLTDLS)
15248 		if (!wl_cfg80211_is_concurrent_mode(primary_dev)) {
15249 			err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
15250 		}
15251 #endif /* defined(WLTDLS) */
15252 
15253 #ifdef BCMDONGLEHOST
15254 #if defined(DISABLE_FRAMEBURST_VSDB)
15255 		if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE)) {
15256 			wl_cfg80211_set_frameburst(cfg, TRUE);
15257 		}
15258 #endif /* DISABLE_FRAMEBURST_VSDB */
15259 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
15260 		if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
15261 			CHSPEC_IS2G(cfg->ap_oper_channel)) {
15262 			/* Disable frameburst for stand-alone 2GHz SoftAP */
15263 			wl_cfg80211_set_frameburst(cfg, FALSE);
15264 		}
15265 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
15266 #endif /* BCMDONGLEHOST */
15267 	}
15268 	return err;
15269 }
15270 
15271 #ifdef DHD_LOSSLESS_ROAMING
wl_init_roam_timeout(struct bcm_cfg80211 * cfg)15272 static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
15273 {
15274 	int err = 0;
15275 
15276 	/* Init roam timer */
15277 	init_timer_compat(&cfg->roam_timeout, wl_roam_timeout, cfg);
15278 
15279 	return err;
15280 }
15281 #endif /* DHD_LOSSLESS_ROAMING */
15282 
15283 #ifdef CONFIG_SLEEP_MONITOR
15284 extern long long temp_raw;
15285 
wlan_get_sleep_monitor64_cb(void * priv,long long * raw_val,int check_level,int caller_type)15286 int wlan_get_sleep_monitor64_cb(void *priv, long long *raw_val,
15287 	int check_level, int caller_type)
15288 {
15289 	struct bcm_cfg80211 *cfg = priv;
15290 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15291 	int state = DEVICE_UNKNOWN;
15292 
15293 	if (!dhdp->up)
15294 		state = DEVICE_POWER_OFF;
15295 	else {
15296 		state = DEVICE_ON_ACTIVE1;
15297 		if (wl_get_drv_status_all(cfg, CONNECTED))
15298 			state = DEVICE_ON_ACTIVE2;
15299 
15300 		if (caller_type == SLEEP_MONITOR_CALL_SUSPEND) {
15301 			*raw_val = temp_raw;
15302 			temp_raw = 0;
15303 		}
15304 	}
15305 
15306 	return state;
15307 }
15308 
15309 static struct sleep_monitor_ops wlan_sleep_monitor_ops = {
15310 	.read64_cb_func = wlan_get_sleep_monitor64_cb,
15311 };
15312 #endif /* CONFIG_SLEEP_MONITOR */
15313 
wl_init_priv(struct bcm_cfg80211 * cfg)15314 static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
15315 {
15316 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15317 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
15318 	s32 err = 0;
15319 
15320 	cfg->scan_request = NULL;
15321 	cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
15322 #ifdef DISABLE_BUILTIN_ROAM
15323 	cfg->roam_on = false;
15324 #else
15325 	cfg->roam_on = true;
15326 #endif /* DISABLE_BUILTIN_ROAM */
15327 	cfg->active_scan = true;
15328 	cfg->rf_blocked = false;
15329 	cfg->vsdb_mode = false;
15330 #if defined(BCMSDIO) || defined(BCMDBUS)
15331 	cfg->wlfc_on = false;
15332 #endif /* BCMSDIO || BCMDBUS */
15333 	cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
15334 	cfg->disable_roam_event = false;
15335 	/* register interested state */
15336 	set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
15337 	spin_lock_init(&cfg->cfgdrv_lock);
15338 	mutex_init(&cfg->ioctl_buf_sync);
15339 	init_waitqueue_head(&cfg->netif_change_event);
15340 	init_completion(&cfg->send_af_done);
15341 	init_completion(&cfg->iface_disable);
15342 	mutex_init(&cfg->usr_sync);
15343 	mutex_init(&cfg->event_sync);
15344 	mutex_init(&cfg->if_sync);
15345 	mutex_init(&cfg->scan_sync);
15346 	mutex_init(&cfg->connect_sync);
15347 	mutex_init(&cfg->pm_sync);
15348 #ifdef WLTDLS
15349 	mutex_init(&cfg->tdls_sync);
15350 #endif	/* WLTDLS */
15351 #ifdef WL_BCNRECV
15352 	mutex_init(&cfg->bcn_sync);
15353 #endif /* WL_BCNRECV */
15354 #ifdef WL_WPS_SYNC
15355 	wl_init_wps_reauth_sm(cfg);
15356 #endif /* WL_WPS_SYNC */
15357 	wl_init_eq(cfg);
15358 	err = wl_init_priv_mem(cfg);
15359 	if (err)
15360 		return err;
15361 	if (wl_create_event_handler(cfg))
15362 		return -ENOMEM;
15363 	wl_init_event_handler(cfg);
15364 	err = wl_init_scan(cfg);
15365 	if (err)
15366 		return err;
15367 #ifdef DHD_LOSSLESS_ROAMING
15368 	err = wl_init_roam_timeout(cfg);
15369 	if (err) {
15370 		return err;
15371 	}
15372 #endif /* DHD_LOSSLESS_ROAMING */
15373 	wl_init_conf(cfg->conf);
15374 	wl_init_prof(cfg, ndev);
15375 	wl_link_down(cfg);
15376 	DNGL_FUNC(dhd_cfg80211_init, (cfg));
15377 	cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
15378 	cfg->pmk_list->pmkids.count = 0;
15379 	cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
15380 
15381 #ifdef CONFIG_SLEEP_MONITOR
15382 	sleep_monitor_register_ops(cfg, &wlan_sleep_monitor_ops,
15383 		SLEEP_MONITOR_WIFI);
15384 #endif /* CONFIG_SLEEP_MONITOR */
15385 	return err;
15386 }
15387 
wl_deinit_priv(struct bcm_cfg80211 * cfg)15388 static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
15389 {
15390 	DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
15391 	wl_destroy_event_handler(cfg);
15392 	wl_flush_eq(cfg);
15393 	wl_link_down(cfg);
15394 	del_timer_sync(&cfg->scan_timeout);
15395 #ifdef DHD_LOSSLESS_ROAMING
15396 	del_timer_sync(&cfg->roam_timeout);
15397 #endif
15398 	wl_deinit_priv_mem(cfg);
15399 	if (wl_cfg80211_netdev_notifier_registered) {
15400 		wl_cfg80211_netdev_notifier_registered = FALSE;
15401 		unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
15402 	}
15403 
15404 #ifdef CONFIG_SLEEP_MONITOR
15405 	sleep_monitor_unregister_ops(SLEEP_MONITOR_WIFI);
15406 #endif /* CONFIG_SLEEP_MONITOR */
15407 }
15408 
15409 #if defined(WL_ENABLE_P2P_IF) || defined (WL_NEWCFG_PRIVCMD_SUPPORT)
wl_cfg80211_attach_p2p(struct bcm_cfg80211 * cfg)15410 static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
15411 {
15412 	WL_TRACE(("Enter \n"));
15413 
15414 	if (wl_cfgp2p_register_ndev(cfg) < 0) {
15415 		WL_ERR(("P2P attach failed. \n"));
15416 		return -ENODEV;
15417 	}
15418 
15419 	return 0;
15420 }
15421 
wl_cfg80211_detach_p2p(struct bcm_cfg80211 * cfg)15422 static s32  wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
15423 {
15424 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
15425 	struct wireless_dev *wdev;
15426 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
15427 
15428 	WL_DBG(("Enter \n"));
15429 	if (!cfg) {
15430 		WL_ERR(("Invalid Ptr\n"));
15431 		return -EINVAL;
15432 	}
15433 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
15434 	else {
15435 		wdev = cfg->p2p_wdev;
15436 		if (!wdev) {
15437 			WL_ERR(("Invalid Ptr\n"));
15438 			return -EINVAL;
15439 		}
15440 	}
15441 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
15442 
15443 	wl_cfgp2p_unregister_ndev(cfg);
15444 
15445 	cfg->p2p_wdev = NULL;
15446 	cfg->p2p_net = NULL;
15447 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
15448 	WL_DBG(("Freeing 0x%p \n", wdev));
15449 	MFREE(cfg->osh, wdev, sizeof(*wdev));
15450 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
15451 
15452 	return 0;
15453 }
15454 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
15455 
15456 #if defined(BCMDONGLEHOST)
wl_cfg80211_attach_post(struct net_device * ndev)15457 static s32 wl_cfg80211_attach_post(struct net_device *ndev)
15458 {
15459 	struct bcm_cfg80211 * cfg;
15460 	s32 err = 0;
15461 	s32 ret = 0;
15462 	WL_TRACE(("In\n"));
15463 	if (unlikely(!ndev)) {
15464 		WL_ERR(("ndev is invaild\n"));
15465 		return -ENODEV;
15466 	}
15467 	cfg = wl_get_cfg(ndev);
15468 	if (unlikely(!cfg)) {
15469 		WL_ERR(("cfg is invaild\n"));
15470 		return -EINVAL;
15471 	}
15472 	if (!wl_get_drv_status(cfg, READY, ndev)) {
15473 		if (cfg->wdev) {
15474 			ret = wl_cfgp2p_supported(cfg, ndev);
15475 			if (ret > 0) {
15476 #if !defined(WL_ENABLE_P2P_IF)
15477 				cfg->wdev->wiphy->interface_modes |=
15478 					(BIT(NL80211_IFTYPE_P2P_CLIENT)|
15479 					BIT(NL80211_IFTYPE_P2P_GO));
15480 #endif /* !WL_ENABLE_P2P_IF */
15481 				if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
15482 					goto fail;
15483 
15484 #if defined(WL_ENABLE_P2P_IF)
15485 				if (cfg->p2p_net) {
15486 					/* Update MAC addr for p2p0 interface here. */
15487 					memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
15488 					cfg->p2p_net->dev_addr[0] |= 0x02;
15489 					WL_MSG(cfg->p2p_net->name, "p2p_dev_addr="MACDBG "\n",
15490 						MAC2STRDBG(cfg->p2p_net->dev_addr));
15491 				} else {
15492 					WL_ERR(("p2p_net not yet populated."
15493 					" Couldn't update the MAC Address for p2p0 \n"));
15494 					return -ENODEV;
15495 				}
15496 #endif /* WL_ENABLE_P2P_IF */
15497 				cfg->p2p_supported = true;
15498 			} else if (ret == 0) {
15499 				if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
15500 					goto fail;
15501 			} else {
15502 				/* SDIO bus timeout */
15503 				err = -ENODEV;
15504 				goto fail;
15505 			}
15506 		}
15507 	}
15508 	wl_set_drv_status(cfg, READY, ndev);
15509 fail:
15510 	return err;
15511 }
15512 #endif /* BCMDONGLEHOST */
15513 
wl_get_cfg(struct net_device * ndev)15514 struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev)
15515 {
15516 	struct wireless_dev *wdev = ndev->ieee80211_ptr;
15517 
15518 	if (!wdev || !wdev->wiphy)
15519 		return NULL;
15520 
15521 	return wiphy_priv(wdev->wiphy);
15522 }
15523 
15524 s32
wl_cfg80211_net_attach(struct net_device * primary_ndev)15525 wl_cfg80211_net_attach(struct net_device *primary_ndev)
15526 {
15527 	struct bcm_cfg80211 *cfg = wl_get_cfg(primary_ndev);
15528 #ifdef WL_STATIC_IF
15529 	enum nl80211_iftype ntype;
15530 #endif
15531 
15532 	if (!cfg) {
15533 		WL_ERR(("cfg null\n"));
15534 		return BCME_ERROR;
15535 	}
15536 #ifdef WL_STATIC_IF
15537 	/* Register dummy n/w iface. FW init will happen only from dev_open */
15538 #ifdef WLEASYMESH
15539 	ntype = NL80211_IFTYPE_AP;
15540 #else
15541 	ntype = NL80211_IFTYPE_STATION;
15542 #endif
15543 	if (wl_cfg80211_register_static_if(cfg, ntype,
15544 			WL_STATIC_IFNAME_PREFIX) == NULL) {
15545 		WL_ERR(("static i/f registration failed!\n"));
15546 		return BCME_ERROR;
15547 	}
15548 #endif /* WL_STATIC_IF */
15549 	return BCME_OK;
15550 }
15551 
wl_cfg80211_attach(struct net_device * ndev,void * context)15552 s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
15553 {
15554 	struct wireless_dev *wdev;
15555 	struct bcm_cfg80211 *cfg;
15556 	s32 err = 0;
15557 	struct device *dev;
15558 	u16 bssidx = 0;
15559 	u16 ifidx = 0;
15560 	dhd_pub_t *dhd = (struct dhd_pub *)(context);
15561 
15562 	WL_TRACE(("In\n"));
15563 	if (!ndev) {
15564 		WL_ERR(("ndev is invaild\n"));
15565 		return -ENODEV;
15566 	}
15567 	WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
15568 #if !defined(BCMDONGLEHOST)
15569 	wl_cfg80211_set_parent_dev(context);
15570 #endif
15571 	dev = wl_cfg80211_get_parent_dev();
15572 
15573 	wdev = (struct wireless_dev *)MALLOCZ(dhd->osh, sizeof(*wdev));
15574 	if (unlikely(!wdev)) {
15575 		WL_ERR(("Could not allocate wireless device\n"));
15576 		return -ENOMEM;
15577 	}
15578 	err = wl_setup_wiphy(wdev, dev, context);
15579 	if (unlikely(err)) {
15580 		MFREE(dhd->osh, wdev, sizeof(*wdev));
15581 		return -ENOMEM;
15582 	}
15583 #ifdef WLMESH_CFG80211
15584 	wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_MESH);
15585 #else
15586 	wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
15587 #endif
15588 	cfg = wiphy_priv(wdev->wiphy);
15589 	cfg->wdev = wdev;
15590 	cfg->pub = context;
15591 	cfg->osh = dhd->osh;
15592 	INIT_LIST_HEAD(&cfg->net_list);
15593 #ifdef WBTEXT
15594 	INIT_LIST_HEAD(&cfg->wbtext_bssid_list);
15595 #endif /* WBTEXT */
15596 	INIT_LIST_HEAD(&cfg->vndr_oui_list);
15597 	spin_lock_init(&cfg->vndr_oui_sync);
15598 	spin_lock_init(&cfg->net_list_sync);
15599 	ndev->ieee80211_ptr = wdev;
15600 	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
15601 	wdev->netdev = ndev;
15602 	cfg->state_notifier = wl_notifier_change_state;
15603 	err = wl_alloc_netinfo(cfg, ndev, wdev, WL_IF_TYPE_STA, PM_ENABLE, bssidx, ifidx);
15604 	if (err) {
15605 		WL_ERR(("Failed to alloc net_info (%d)\n", err));
15606 		goto cfg80211_attach_out;
15607 	}
15608 	err = wl_init_priv(cfg);
15609 	if (err) {
15610 		WL_ERR(("Failed to init iwm_priv (%d)\n", err));
15611 		goto cfg80211_attach_out;
15612 	}
15613 
15614 	err = wl_setup_rfkill(cfg, TRUE);
15615 	if (err) {
15616 		WL_ERR(("Failed to setup rfkill %d\n", err));
15617 		goto cfg80211_attach_out;
15618 	}
15619 
15620 	if (!wl_cfg80211_netdev_notifier_registered) {
15621 		wl_cfg80211_netdev_notifier_registered = TRUE;
15622 		err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
15623 		if (err) {
15624 			wl_cfg80211_netdev_notifier_registered = FALSE;
15625 			WL_ERR(("Failed to register notifierl %d\n", err));
15626 			goto cfg80211_attach_out;
15627 		}
15628 	}
15629 
15630 #if defined(OEM_ANDROID) && defined(COEX_DHCP)
15631 	cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
15632 	if (!cfg->btcoex_info)
15633 		goto cfg80211_attach_out;
15634 #endif /* defined(OEM_ANDROID) && defined(COEX_DHCP) */
15635 
15636 #if defined(SUPPORT_RANDOM_MAC_SCAN)
15637 	cfg->random_mac_enabled = FALSE;
15638 #endif /* SUPPORT_RANDOM_MAC_SCAN */
15639 
15640 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
15641 	wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
15642 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
15643 
15644 #if defined(WL_ENABLE_P2P_IF) || defined (WL_NEWCFG_PRIVCMD_SUPPORT)
15645 	err = wl_cfg80211_attach_p2p(cfg);
15646 	if (err)
15647 		goto cfg80211_attach_out;
15648 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
15649 
15650 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
15651 	/* wlan scan_supp timer and work thread info */
15652 	init_timer_compat(&cfg->scan_supp_timer, wl_cfg80211_scan_supp_timerfunc, cfg);
15653 	INIT_WORK(&cfg->wlan_work, wl_cfg80211_work_handler);
15654 #endif /* DHCP_SCAN_SUPPRESS */
15655 
15656 	INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
15657 	INIT_DELAYED_WORK(&cfg->loc.work, wl_cfgscan_listen_complete_work);
15658 	INIT_DELAYED_WORK(&cfg->ap_work, wl_cfg80211_ap_timeout_work);
15659 	mutex_init(&cfg->pm_sync);
15660 #ifdef WL_NAN
15661 	err = wl_cfgnan_attach(cfg);
15662 	if (err) {
15663 		WL_ERR(("Failed to attach nan module %d\n", err));
15664 		goto cfg80211_attach_out;
15665 	}
15666 #endif /* WL_NAN */
15667 	cfg->rssi_sum_report = FALSE;
15668 #ifdef WL_BAM
15669 	wl_bad_ap_mngr_init(cfg);
15670 #endif	/* WL_BAM */
15671 
15672 #ifdef BIGDATA_SOFTAP
15673 	wl_attach_ap_stainfo(cfg);
15674 #endif /* BIGDATA_SOFTAP */
15675 
15676 	return err;
15677 
15678 cfg80211_attach_out:
15679 	wl_cfg80211_detach(cfg);
15680 	return err;
15681 }
15682 
wl_cfg80211_detach(struct bcm_cfg80211 * cfg)15683 void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
15684 {
15685 	WL_DBG(("Enter\n"));
15686 	if (!cfg) {
15687 		return;
15688 	}
15689 /* clean up pm_enable work item. Remove this once deinit is properly
15690  * clean up and wl_cfg8021_down is called while removing the module
15691  */
15692 	wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
15693 
15694 #if defined(OEM_ANDROID) && defined(COEX_DHCP)
15695 	wl_cfg80211_btcoex_deinit();
15696 	cfg->btcoex_info = NULL;
15697 #endif /* defined(OEM_ANDROID) && defined(COEX_DHCP) */
15698 
15699 	wl_setup_rfkill(cfg, FALSE);
15700 
15701 #ifdef WL_WPS_SYNC
15702 	wl_deinit_wps_reauth_sm(cfg);
15703 #endif /* WL_WPS_SYNC */
15704 
15705 	del_timer_sync(&cfg->scan_timeout);
15706 #ifdef DHD_LOSSLESS_ROAMING
15707 	del_timer_sync(&cfg->roam_timeout);
15708 #endif /* DHD_LOSSLESS_ROAMING */
15709 
15710 #ifdef WL_STATIC_IF
15711 	wl_cfg80211_unregister_static_if(cfg);
15712 #endif /* WL_STATIC_IF */
15713 #if defined(WL_ENABLE_P2P_IF) || defined (WL_NEWCFG_PRIVCMD_SUPPORT)
15714 	wl_cfg80211_detach_p2p(cfg);
15715 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
15716 #ifdef WL_BAM
15717 	wl_bad_ap_mngr_deinit(cfg);
15718 #endif	/* WL_BAM */
15719 
15720 #ifdef BIGDATA_SOFTAP
15721 	wl_detach_ap_stainfo(cfg);
15722 #endif /* BIGDATA_SOFTAP */
15723 
15724 #ifdef WL_NAN
15725 	wl_cfgnan_detach(cfg);
15726 #endif /* WL_NAN */
15727 	wl_cfg80211_ibss_vsie_free(cfg);
15728 	wl_dealloc_netinfo_by_wdev(cfg, cfg->wdev);
15729 	wl_cfg80211_set_bcmcfg(NULL);
15730 	wl_deinit_priv(cfg);
15731 	wl_cfg80211_clear_parent_dev();
15732 #if defined(RSSIAVG)
15733 	wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
15734 	wl_free_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
15735 #endif
15736 #if defined(BSSCACHE)
15737 	wl_release_bss_cache_ctrl(&cfg->g_bss_cache_ctrl);
15738 #endif
15739 	wl_free_wdev(cfg);
15740 	/* PLEASE do NOT call any function after wl_free_wdev, the driver's private
15741 	 * structure "cfg", which is the private part of wiphy, has been freed in
15742 	 * wl_free_wdev !!!!!!!!!!!
15743 	 */
15744 	WL_DBG(("Exit\n"));
15745 }
15746 
15747 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
wl_cfg80211_register_dev_ril_bridge_event_notifier()15748 void wl_cfg80211_register_dev_ril_bridge_event_notifier()
15749 {
15750 	WL_DBG(("Enter\n"));
15751 	if (!wl_cfg80211_ril_bridge_notifier_registered) {
15752 		s32 err = 0;
15753 		wl_cfg80211_ril_bridge_notifier_registered = TRUE;
15754 		err = register_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
15755 		if (err) {
15756 			wl_cfg80211_ril_bridge_notifier_registered = FALSE;
15757 			WL_ERR(("Failed to register ril_notifier! %d\n", err));
15758 		}
15759 	}
15760 }
15761 
wl_cfg80211_unregister_dev_ril_bridge_event_notifier()15762 void wl_cfg80211_unregister_dev_ril_bridge_event_notifier()
15763 {
15764 	WL_DBG(("Enter\n"));
15765 	if (wl_cfg80211_ril_bridge_notifier_registered) {
15766 		wl_cfg80211_ril_bridge_notifier_registered = FALSE;
15767 		unregister_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
15768 	}
15769 }
15770 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
15771 
wl_print_event_data(struct bcm_cfg80211 * cfg,uint32 event_type,const wl_event_msg_t * e)15772 static void wl_print_event_data(struct bcm_cfg80211 *cfg,
15773 	uint32 event_type, const wl_event_msg_t *e)
15774 {
15775 	s32 status = ntoh32(e->status);
15776 	s32 reason = ntoh32(e->reason);
15777 	s32 ifidx = ntoh32(e->ifidx);
15778 	s32 bssidx = ntoh32(e->bsscfgidx);
15779 
15780 	switch (event_type) {
15781 		case WLC_E_ESCAN_RESULT:
15782 			if ((status == WLC_E_STATUS_SUCCESS) ||
15783 				(status == WLC_E_STATUS_ABORT)) {
15784 				WL_INFORM_MEM(("event_type (%d), ifidx: %d"
15785 					" bssidx: %d scan_type:%d\n",
15786 					event_type, ifidx, bssidx, status));
15787 			}
15788 			break;
15789 		case WLC_E_LINK:
15790 		case WLC_E_DISASSOC:
15791 		case WLC_E_DISASSOC_IND:
15792 		case WLC_E_DEAUTH:
15793 		case WLC_E_DEAUTH_IND:
15794 			WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
15795 				" status:%d reason:%d\n",
15796 				event_type, ifidx, bssidx, status, reason));
15797 				break;
15798 
15799 		default:
15800 			/* Print only when DBG verbose is enabled */
15801 			WL_DBG(("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
15802 				event_type, ifidx, bssidx, status, reason));
15803 	}
15804 }
15805 
wl_event_handler(struct work_struct * work_data)15806 static void wl_event_handler(struct work_struct *work_data)
15807 {
15808 	struct bcm_cfg80211 *cfg = NULL;
15809 	struct wl_event_q *e;
15810 	struct wireless_dev *wdev = NULL;
15811 
15812 	WL_DBG(("Enter \n"));
15813 	BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
15814 	LOG_TS(cfg, wl_evt_hdlr_entry);
15815 	DHD_EVENT_WAKE_LOCK(cfg->pub);
15816 	while ((e = wl_deq_event(cfg))) {
15817 		s32 status = ntoh32(e->emsg.status);
15818 		u32 event_type = ntoh32(e->emsg.event_type);
15819 		bool scan_cmplt_evt = (event_type == WLC_E_ESCAN_RESULT) &&
15820 			((status == WLC_E_STATUS_SUCCESS) || (status == WLC_E_STATUS_ABORT));
15821 
15822 		LOG_TS(cfg, wl_evt_deq);
15823 		if (scan_cmplt_evt) {
15824 			LOG_TS(cfg, scan_deq);
15825 		}
15826 		/* Print only critical events to avoid too many prints */
15827 		wl_print_event_data(cfg, e->etype, &e->emsg);
15828 
15829 		if (e->emsg.ifidx > WL_MAX_IFS) {
15830 			WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
15831 			goto fail;
15832 		}
15833 
15834 		/* Make sure iface operations, don't creat race conditions */
15835 		mutex_lock(&cfg->if_sync);
15836 		if (!(wdev = wl_get_wdev_by_fw_idx(cfg,
15837 			e->emsg.bsscfgidx, e->emsg.ifidx))) {
15838 			/* For WLC_E_IF would be handled by wl_host_event */
15839 			if (e->etype != WLC_E_IF)
15840 				WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
15841 					" Ignoring event.\n", e->emsg.bsscfgidx));
15842 		} else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
15843 #if defined(BCMDONGLEHOST)
15844 			dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
15845 			if (dhd->busstate == DHD_BUS_DOWN) {
15846 				WL_ERR((": BUS is DOWN.\n"));
15847 			} else
15848 #endif /* defined(BCMDONGLEHOST) */
15849 			{
15850 				WL_DBG(("event_type %d event_sub %d\n",
15851 					ntoh32(e->emsg.event_type),
15852 					ntoh32(e->emsg.reason)));
15853 				WL_SET_EIDX_IN_PROGRESS(cfg, e->id, e->etype);
15854 				cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
15855 					&e->emsg, e->edata);
15856 				WL_CLR_EIDX_STATES(cfg);
15857 				if (scan_cmplt_evt) {
15858 					LOG_TS(cfg, scan_hdlr_cmplt);
15859 				}
15860 			}
15861 		} else {
15862 			WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
15863 		}
15864 		mutex_unlock(&cfg->if_sync);
15865 fail:
15866 		wl_put_event(cfg, e);
15867 		if (scan_cmplt_evt) {
15868 			LOG_TS(cfg, scan_cmplt);
15869 		}
15870 		LOG_TS(cfg, wl_evt_hdlr_exit);
15871 	}
15872 	DHD_EVENT_WAKE_UNLOCK(cfg->pub);
15873 }
15874 
15875 /*
15876 * Generic API to handle critical events which doesnt need
15877 * cfg enquening and sleepable API calls.
15878 */
15879 s32
wl_cfg80211_handle_critical_events(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const wl_event_msg_t * e)15880 wl_cfg80211_handle_critical_events(struct bcm_cfg80211 *cfg,
15881 	struct wireless_dev *wdev, const wl_event_msg_t * e)
15882 {
15883 	s32 ret = BCME_ERROR;
15884 	u32 event_type = ntoh32(e->event_type);
15885 
15886 	if (event_type >= WLC_E_LAST) {
15887 		return BCME_ERROR;
15888 	}
15889 
15890 	switch (event_type) {
15891 		case WLC_E_NAN_CRITICAL: {
15892 #ifdef WL_NAN
15893 		if (ntoh32(e->reason) == WL_NAN_EVENT_STOP) {
15894 			WL_DBG(("Received WL_NAN_EVENT_STOP\n"));
15895 		}
15896 #endif /* WL_NAN */
15897 			break;
15898 		}
15899 		default:
15900 			ret = BCME_ERROR;
15901 	}
15902 	return ret;
15903 }
15904 
15905 void
wl_cfg80211_event(struct net_device * ndev,const wl_event_msg_t * e,void * data)15906 wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
15907 {
15908 	s32 status = ntoh32(e->status);
15909 	u32 event_type = ntoh32(e->event_type);
15910 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
15911 	struct net_info *netinfo;
15912 
15913 	WL_DBG(("event_type (%d): reason (%d): %s\n", event_type, ntoh32(e->reason),
15914 		bcmevent_get_name(event_type)));
15915 	if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
15916 		WL_ERR(("Stale event ignored\n"));
15917 		return;
15918 	}
15919 
15920 #ifdef OEM_ANDROID
15921 	if (cfg->event_workq == NULL) {
15922 		WL_ERR(("Event handler is not created\n"));
15923 		return;
15924 	}
15925 #endif /* OEM_ANDROID */
15926 
15927 #ifndef OEM_ANDROID
15928 	if (!cfg->event_workq_init) {
15929 		WL_ERR(("Event handler is not created\n"));
15930 		return;
15931 	}
15932 #endif /* OEM_ANDROID */
15933 
15934 	if (event_type == WLC_E_IF) {
15935 		/* Don't process WLC_E_IF events in wl_cfg80211 layer */
15936 		return;
15937 	}
15938 
15939 	netinfo = wl_get_netinfo_by_fw_idx(cfg, e->bsscfgidx, e->ifidx);
15940 	if (!netinfo) {
15941 		/* Since the netinfo entry is not there, the netdev entry is not
15942 		 * created via cfg80211 interface. so the event is not of interest
15943 		 * to the cfg80211 layer.
15944 		 */
15945 		WL_TRACE(("ignore event %d, not interested\n", event_type));
15946 		return;
15947 	}
15948 
15949 	/* Handle wl_cfg80211_critical_events */
15950 	if (wl_cfg80211_handle_critical_events(cfg, netinfo->wdev, e) == BCME_OK) {
15951 		return;
15952 	}
15953 
15954 	if (event_type == WLC_E_PFN_NET_FOUND) {
15955 		WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
15956 	}
15957 	else if (event_type == WLC_E_PFN_NET_LOST) {
15958 		WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
15959 	}
15960 
15961 	if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
15962 
15963 #ifdef OEM_ANDROID
15964 		queue_work(cfg->event_workq, &cfg->event_work);
15965 #endif /* OEM_ANDROID */
15966 
15967 #ifndef OEM_ANDROID
15968 		schedule_work(&cfg->event_work);
15969 #endif /* OEM_ANDROID */
15970 	}
15971 	/* Mark timeout value for thread sched */
15972 	if ((event_type == WLC_E_ESCAN_RESULT) &&
15973 		((status == WLC_E_STATUS_SUCCESS) ||
15974 		(status == WLC_E_STATUS_ABORT)))  {
15975 		LOG_TS(cfg, scan_enq);
15976 		WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
15977 			status, work_busy(&cfg->event_work)));
15978 	}
15979 }
15980 
wl_init_eq(struct bcm_cfg80211 * cfg)15981 static void wl_init_eq(struct bcm_cfg80211 *cfg)
15982 {
15983 	wl_init_eq_lock(cfg);
15984 	INIT_LIST_HEAD(&cfg->eq_list);
15985 }
15986 
wl_flush_eq(struct bcm_cfg80211 * cfg)15987 static void wl_flush_eq(struct bcm_cfg80211 *cfg)
15988 {
15989 	struct wl_event_q *e;
15990 	unsigned long flags;
15991 
15992 	flags = wl_lock_eq(cfg);
15993 	while (!list_empty_careful(&cfg->eq_list)) {
15994 		BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
15995 		list_del(&e->eq_list);
15996 		MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
15997 	}
15998 	wl_unlock_eq(cfg, flags);
15999 }
16000 
16001 /*
16002 * retrieve first queued event from head
16003 */
16004 
wl_deq_event(struct bcm_cfg80211 * cfg)16005 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
16006 {
16007 	struct wl_event_q *e = NULL;
16008 	unsigned long flags;
16009 
16010 	flags = wl_lock_eq(cfg);
16011 	if (likely(!list_empty(&cfg->eq_list))) {
16012 		BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
16013 		list_del(&e->eq_list);
16014 	}
16015 	wl_unlock_eq(cfg, flags);
16016 
16017 	return e;
16018 }
16019 
16020 /*
16021  * push event to tail of the queue
16022  */
16023 
16024 static s32
wl_enq_event(struct bcm_cfg80211 * cfg,struct net_device * ndev,u32 event,const wl_event_msg_t * msg,void * data)16025 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event,
16026 	const wl_event_msg_t *msg, void *data)
16027 {
16028 	struct wl_event_q *e;
16029 	s32 err = 0;
16030 	uint32 evtq_size;
16031 	uint32 data_len;
16032 	unsigned long flags;
16033 
16034 	data_len = 0;
16035 	if (data)
16036 		data_len = ntoh32(msg->datalen);
16037 	evtq_size = (uint32)(sizeof(struct wl_event_q) + data_len);
16038 	e = (struct wl_event_q *)MALLOCZ(cfg->osh, evtq_size);
16039 	if (unlikely(!e)) {
16040 		WL_ERR(("event alloc failed\n"));
16041 		return -ENOMEM;
16042 	}
16043 	e->etype = event;
16044 	memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
16045 	if (data)
16046 		memcpy(e->edata, data, data_len);
16047 	e->datalen = data_len;
16048 	e->id = cfg->eidx.enqd++;
16049 	flags = wl_lock_eq(cfg);
16050 	list_add_tail(&e->eq_list, &cfg->eq_list);
16051 	wl_unlock_eq(cfg, flags);
16052 
16053 	return err;
16054 }
16055 
wl_put_event(struct bcm_cfg80211 * cfg,struct wl_event_q * e)16056 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e)
16057 {
16058 	MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
16059 }
16060 
wl_config_infra(struct bcm_cfg80211 * cfg,struct net_device * ndev,u16 iftype)16061 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype)
16062 {
16063 	s32 infra = 0;
16064 	s32 err = 0;
16065 	bool skip_infra = false;
16066 
16067 	switch (iftype) {
16068 		case WL_IF_TYPE_IBSS:
16069 		case WL_IF_TYPE_AIBSS:
16070 			infra = 0;
16071 			break;
16072 		case WL_IF_TYPE_AP:
16073 		case WL_IF_TYPE_STA:
16074 		case WL_IF_TYPE_P2P_GO:
16075 		case WL_IF_TYPE_P2P_GC:
16076 			/* Intentional fall through */
16077 			infra = 1;
16078 			break;
16079 #ifdef WLMESH_CFG80211
16080 	case NL80211_IFTYPE_MESH_POINT:
16081 		infra = WL_BSSTYPE_MESH;
16082 		break;
16083 #endif /* WLMESH_CFG80211 */
16084 		case WL_IF_TYPE_MONITOR:
16085 
16086 #ifdef WLAWDL
16087 		case WL_IF_TYPE_AWDL:
16088 #endif /* WLAWDL */
16089 
16090 		case WL_IF_TYPE_NAN:
16091 			/* Intentionall fall through */
16092 		default:
16093 			skip_infra = true;
16094 			WL_ERR(("Skipping infra setting for type:%d\n", iftype));
16095 			break;
16096 	}
16097 
16098 	/* /TODO Infra iovar is stored in default bss first and
16099 	 * then applied to the next upcoming bss. so if there is
16100 	 * some other concurrent bss coming up in parallel, it
16101 	 * can cause problem. Ideally this iovar should get directly
16102 	 * applied on the target bsscfg.
16103 	 */
16104 	if (!skip_infra) {
16105 		infra = htod32(infra);
16106 		err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
16107 		if (unlikely(err)) {
16108 			WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
16109 			return err;
16110 		}
16111 	}
16112 	return 0;
16113 }
16114 
wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf * ev,u16 event,bool set)16115 void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set)
16116 {
16117 	if (!ev || (event > WLC_E_LAST))
16118 		return;
16119 
16120 	if (ev->num < MAX_EVENT_BUF_NUM) {
16121 		ev->event[ev->num].type = event;
16122 		ev->event[ev->num].set = set;
16123 		ev->num++;
16124 	} else {
16125 		WL_ERR(("evenbuffer doesn't support > %u events. Update"
16126 			" the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
16127 		ASSERT(0);
16128 	}
16129 }
16130 
wl_cfg80211_apply_eventbuffer(struct net_device * ndev,struct bcm_cfg80211 * cfg,wl_eventmsg_buf_t * ev)16131 s32 wl_cfg80211_apply_eventbuffer(
16132 	struct net_device *ndev,
16133 	struct bcm_cfg80211 *cfg,
16134 	wl_eventmsg_buf_t *ev)
16135 {
16136 	int i, ret = BCME_OK;
16137 	s8 event_buf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE] = {0};
16138 	/*  Room for "event_msgs_ext" + '\0' + bitvec  */
16139 	char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16];
16140 	eventmsgs_ext_t *eventmask_msg;
16141 	s32 msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE;
16142 
16143 	if (!ev || (!ev->num)) {
16144 		return -EINVAL;
16145 	}
16146 
16147 	mutex_lock(&cfg->event_sync);
16148 
16149 	eventmask_msg = (eventmsgs_ext_t *)event_buf;
16150 	eventmask_msg->ver = EVENTMSGS_VER;
16151 	eventmask_msg->command = EVENTMSGS_NONE;
16152 	eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
16153 	eventmask_msg->maxgetsize = WL_EVENTING_MASK_EXT_LEN;
16154 
16155 	/* Read event_msgs mask */
16156 	ret = wldev_iovar_getbuf(ndev, "event_msgs_ext",
16157 		eventmask_msg, EVENTMSGS_EXT_STRUCT_SIZE,
16158 		iovbuf,
16159 		sizeof(iovbuf),
16160 		NULL);
16161 
16162 	if (unlikely(ret)) {
16163 		WL_ERR(("Get event_msgs error (%d)\n", ret));
16164 		goto exit;
16165 	}
16166 
16167 	bcopy(iovbuf, eventmask_msg, msglen);
16168 
16169 	/* apply the set bits */
16170 	for (i = 0; i < ev->num; i++) {
16171 		if (ev->event[i].set)
16172 			setbit(eventmask_msg->mask, ev->event[i].type);
16173 		else
16174 			clrbit(eventmask_msg->mask, ev->event[i].type);
16175 	}
16176 
16177 	/* Write updated Event mask */
16178 	eventmask_msg->ver = EVENTMSGS_VER;
16179 	eventmask_msg->command = EVENTMSGS_SET_MASK;
16180 	eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
16181 
16182 	/* Write updated Event mask */
16183 	ret = wldev_iovar_setbuf(ndev, "event_msgs_ext", eventmask_msg,
16184 		WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE,
16185 		iovbuf, sizeof(iovbuf), NULL);
16186 
16187 	if (unlikely(ret)) {
16188 		WL_ERR(("Set event_msgs error (%d)\n", ret));
16189 	}
16190 
16191 exit:
16192 	mutex_unlock(&cfg->event_sync);
16193 	return ret;
16194 }
16195 
wl_add_remove_eventmsg(struct net_device * ndev,u16 event,bool add)16196 s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
16197 {
16198 	s32 err = 0;
16199 	s8 event_buf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE] = {0};
16200 	eventmsgs_ext_t *eventmask_msg = NULL;
16201 	struct bcm_cfg80211 *cfg;
16202 	/*  Room for "event_msgs_ext" + '\0' + bitvec  */
16203 	char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16];
16204 	s32 msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE;
16205 
16206 	if (!ndev)
16207 		return -ENODEV;
16208 
16209 	cfg = wl_get_cfg(ndev);
16210 	if (!cfg)
16211 		return -ENODEV;
16212 
16213 	mutex_lock(&cfg->event_sync);
16214 
16215 	eventmask_msg = (eventmsgs_ext_t *)event_buf;
16216 	eventmask_msg->ver = EVENTMSGS_VER;
16217 	eventmask_msg->command = EVENTMSGS_NONE;
16218 	eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
16219 	eventmask_msg->maxgetsize = WL_EVENTING_MASK_EXT_LEN;
16220 
16221 	/* Read event_msgs mask */
16222 	err = wldev_iovar_getbuf(ndev, "event_msgs_ext",
16223 		eventmask_msg, EVENTMSGS_EXT_STRUCT_SIZE,
16224 		iovbuf,
16225 		sizeof(iovbuf),
16226 		NULL);
16227 
16228 	if (unlikely(err)) {
16229 		WL_ERR(("Get event_msgs error (%d)\n", err));
16230 		goto eventmsg_out;
16231 	}
16232 
16233 	bcopy(iovbuf, eventmask_msg, msglen);
16234 
16235 	if (add) {
16236 		setbit(eventmask_msg->mask, event);
16237 	} else {
16238 		clrbit(eventmask_msg->mask, event);
16239 	}
16240 
16241 	/* Write updated Event mask */
16242 	eventmask_msg->ver = EVENTMSGS_VER;
16243 	eventmask_msg->command = EVENTMSGS_SET_MASK;
16244 	eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
16245 
16246 	err = wldev_iovar_setbuf(ndev, "event_msgs_ext", eventmask_msg,
16247 		WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE,
16248 		iovbuf, sizeof(iovbuf), NULL);
16249 
16250 	if (unlikely(err)) {
16251 		WL_ERR(("Set event_msgs error (%d)\n", err));
16252 		goto eventmsg_out;
16253 	}
16254 
16255 eventmsg_out:
16256 	mutex_unlock(&cfg->event_sync);
16257 	return err;
16258 }
16259 
16260 void
wl_cfg80211_generate_mac_addr(struct ether_addr * ea_addr)16261 wl_cfg80211_generate_mac_addr(struct ether_addr *ea_addr)
16262 {
16263 	RANDOM_BYTES(ea_addr->octet, ETHER_ADDR_LEN);
16264 	/* restore mcast and local admin bits to 0 and 1 */
16265 	ETHER_SET_UNICAST(ea_addr->octet);
16266 	ETHER_SET_LOCALADDR(ea_addr->octet);
16267 	WL_ERR(("%s:generated new MAC="MACDBG" \n",
16268 		__FUNCTION__, MAC2STRDBG(ea_addr->octet)));
16269 	return;
16270 }
16271 
wl_update_chan_param(struct net_device * dev,u32 cur_chan,struct ieee80211_channel * band_chan,bool * dfs_radar_disabled,bool legacy_chan_info)16272 static s32 wl_update_chan_param(struct net_device *dev, u32 cur_chan,
16273 	struct ieee80211_channel *band_chan, bool *dfs_radar_disabled, bool legacy_chan_info)
16274 {
16275 	s32 err = BCME_OK;
16276 	u32 channel = cur_chan;
16277 
16278 	if (!(*dfs_radar_disabled)) {
16279 		if (legacy_chan_info) {
16280 			channel |= WL_CHANSPEC_BW_20;
16281 			channel = wl_chspec_host_to_driver(channel);
16282 			err = wldev_iovar_getint(dev, "per_chan_info", &channel);
16283 		}
16284 		if (!err) {
16285 			if (channel & WL_CHAN_RADAR) {
16286 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
16287 				band_chan->flags |= (IEEE80211_CHAN_RADAR |
16288 					IEEE80211_CHAN_NO_IBSS);
16289 #else
16290 				band_chan->flags |= IEEE80211_CHAN_RADAR;
16291 #endif
16292 			}
16293 			if (channel & WL_CHAN_PASSIVE) {
16294 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
16295 				band_chan->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
16296 #else
16297 				band_chan->flags |= IEEE80211_CHAN_NO_IR;
16298 #endif
16299 			}
16300 		} else if (err == BCME_UNSUPPORTED) {
16301 			*dfs_radar_disabled = TRUE;
16302 			WL_ERR(("does not support per_chan_info\n"));
16303 		}
16304 	}
16305 
16306 	return err;
16307 }
16308 
wl_construct_reginfo(struct bcm_cfg80211 * cfg,s32 bw_cap)16309 static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
16310 {
16311 	struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
16312 	struct ieee80211_channel *band_chan_arr = NULL;
16313 	void *list;
16314 	u32 i, j, index, channel, array_size = 0;
16315 	chanspec_t chspec = 0;
16316 	s32 err = BCME_OK;
16317 	bool ht40_allowed;
16318 	bool dfs_radar_disabled = FALSE;
16319 	bool legacy_chan_info = FALSE;
16320 	u16 list_count;
16321 
16322 #define LOCAL_BUF_LEN 4096
16323 	list = MALLOCZ(cfg->osh, LOCAL_BUF_LEN);
16324 	if (list == NULL) {
16325 		WL_ERR(("failed to allocate local buf\n"));
16326 		return -ENOMEM;
16327 	}
16328 
16329 	err = wldev_iovar_getbuf_bsscfg(dev, "chan_info_list", NULL,
16330 		0, list, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
16331 	if (err == BCME_UNSUPPORTED) {
16332 		WL_INFORM(("get chan_info_list, UNSUPPORTED\n"));
16333 		err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
16334 			0, list, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
16335 		if (err != BCME_OK) {
16336 			WL_ERR(("get chanspecs err(%d)\n", err));
16337 			MFREE(cfg->osh, list, LOCAL_BUF_LEN);
16338 			return err;
16339 		}
16340 		/* Update indicating legacy chan info usage */
16341 		legacy_chan_info = TRUE;
16342 	} else if (err != BCME_OK) {
16343 		WL_ERR(("get chan_info_list err(%d)\n", err));
16344 		MFREE(cfg->osh, list, LOCAL_BUF_LEN);
16345 		return err;
16346 	}
16347 
16348 	WL_CHANNEL_ARRAY_INIT(__wl_2ghz_channels);
16349 	WL_CHANNEL_ARRAY_INIT(__wl_5ghz_a_channels);
16350 #ifdef CFG80211_6G_SUPPORT
16351 	WL_CHANNEL_ARRAY_INIT(__wl_6ghz_channels);
16352 #endif /* CFG80211_6G_SUPPORT */
16353 
16354 	list_count = legacy_chan_info ? ((wl_uint32_list_t *)list)->count :
16355 		((wl_chanspec_list_v1_t *)list)->count;
16356 	for (i = 0; i < dtoh32(list_count); i++) {
16357 		index = 0;
16358 		ht40_allowed = false;
16359 		if (legacy_chan_info) {
16360 			chspec = (chanspec_t)dtoh32(((wl_uint32_list_t *)list)->element[i]);
16361 		} else {
16362 			chspec = (chanspec_t)dtoh32
16363 			(((wl_chanspec_list_v1_t *)list)->chspecs[i].chanspec);
16364 		}
16365 		chspec = wl_chspec_driver_to_host(chspec);
16366 		channel = wf_chspec_ctlchan(chspec);
16367 
16368 		if (!CHSPEC_IS40(chspec) &&
16369 			!CHSPEC_IS20(chspec)) {
16370 			WL_DBG(("HT80/160/80p80 center channel : %d\n", channel));
16371 			continue;
16372 		}
16373 		if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) &&
16374 			(channel <= CH_MAX_2G_CHANNEL)) {
16375 			band_chan_arr = __wl_2ghz_channels;
16376 			array_size = ARRAYSIZE(__wl_2ghz_channels);
16377 			ht40_allowed = (bw_cap  == WLC_N_BW_40ALL)? true : false;
16378 		}
16379 #ifdef CFG80211_6G_SUPPORT
16380 		else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) &&
16381 			(channel <= CH_MAX_6G_CHANNEL)) {
16382 			band_chan_arr = __wl_6ghz_channels;
16383 			array_size = ARRAYSIZE(__wl_6ghz_channels);
16384 			ht40_allowed = (bw_cap  == WLC_N_BW_20ALL)? false : true;
16385 		}
16386 #endif /* CFG80211_6G_SUPPORT */
16387 		else if (
16388 #ifdef WL_6G_BAND
16389 			/* Currently due to lack of kernel support both 6GHz and 5GHz
16390 			* channels are published under 5GHz band
16391 			*/
16392 			(CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) &&
16393 			(channel <= CH_MAX_6G_CHANNEL)) ||
16394 #endif /* WL_6G_BAND */
16395 			(CHSPEC_IS5G(chspec) && channel >= CH_MIN_5G_CHANNEL)) {
16396 				band_chan_arr = __wl_5ghz_a_channels;
16397 				array_size = ARRAYSIZE(__wl_5ghz_a_channels);
16398 			ht40_allowed = (bw_cap  == WLC_N_BW_20ALL)? false : true;
16399 		} else {
16400 			WL_ERR(("Invalid channel Sepc. 0x%x.\n", chspec));
16401 			continue;
16402 		}
16403 		if (!ht40_allowed && CHSPEC_IS40(chspec))
16404 			continue;
16405 		for (j = 0; j < array_size; j++) {
16406 			if (band_chan_arr[j].hw_value == chspec) {
16407 				break;
16408 			}
16409 		}
16410 		index = j;
16411 		if (!dhd_conf_match_channel(cfg->pub, channel))
16412 			continue;
16413 		if (index <  array_size) {
16414 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
16415 			band_chan_arr[index].center_freq =
16416 				ieee80211_channel_to_frequency(channel);
16417 #else
16418 			band_chan_arr[index].center_freq =
16419 				wl_channel_to_frequency(channel, CHSPEC_BAND(chspec));
16420 #endif
16421 			band_chan_arr[index].hw_value = chspec;
16422 			band_chan_arr[index].beacon_found = false;
16423 			band_chan_arr[index].flags &= ~IEEE80211_CHAN_DISABLED;
16424 
16425 			if (CHSPEC_IS40(chspec) && ht40_allowed) {
16426 				/* assuming the order is HT20, HT40 Upper,
16427 				 *  HT40 lower from chanspecs
16428 				 */
16429 				u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
16430 				if (CHSPEC_SB_UPPER(chspec)) {
16431 					if (ht40_flag == IEEE80211_CHAN_NO_HT40)
16432 						band_chan_arr[index].flags &=
16433 							~IEEE80211_CHAN_NO_HT40;
16434 					band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
16435 				} else {
16436 					/* It should be one of
16437 					 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
16438 					 */
16439 					band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
16440 					if (ht40_flag == IEEE80211_CHAN_NO_HT40)
16441 						band_chan_arr[index].flags |=
16442 							IEEE80211_CHAN_NO_HT40MINUS;
16443 				}
16444 			} else {
16445 				band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
16446 				if (!legacy_chan_info) {
16447 					channel = dtoh32
16448 					(((wl_chanspec_list_v1_t *)list)->chspecs[i].chaninfo);
16449 				} else {
16450 					channel |= CHSPEC_BAND(chspec);
16451 				}
16452 				/* Update channel for radar/passive support */
16453 				err = wl_update_chan_param(dev, channel,
16454 				&band_chan_arr[index], &dfs_radar_disabled, legacy_chan_info);
16455 			}
16456 		}
16457 
16458 	}
16459 
16460 	__wl_band_2ghz.n_channels = ARRAYSIZE(__wl_2ghz_channels);
16461 	__wl_band_5ghz_a.n_channels = ARRAYSIZE(__wl_5ghz_a_channels);
16462 #ifdef CFG80211_6G_SUPPORT
16463 	__wl_band_6ghz.n_channels = ARRAYSIZE(__wl_6ghz_channels);
16464 #endif /* CFG80211_6G_SUPPORT */
16465 
16466 	MFREE(cfg->osh, list, LOCAL_BUF_LEN);
16467 #undef LOCAL_BUF_LEN
16468 	return err;
16469 }
16470 
16471 #ifdef WL_6G_BAND
wl_is_6g_supported(struct bcm_cfg80211 * cfg,u32 * bandlist,u8 nbands)16472 static void wl_is_6g_supported(struct bcm_cfg80211 *cfg, u32 *bandlist, u8 nbands)
16473 {
16474 	u32 i = 0;
16475 
16476 	if (nbands > WL_MAX_BAND_SUPPORT) {
16477 		return;
16478 	}
16479 	/* Check for 6GHz band support */
16480 	for (i = 1; i <= nbands; i++) {
16481 		if (bandlist[i] == WLC_BAND_6G) {
16482 			cfg->band_6g_supported = true;
16483 		}
16484 	}
16485 }
16486 #endif /* WL_6G_BAND */
16487 
__wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)16488 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
16489 {
16490 	struct wiphy *wiphy;
16491 	struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
16492 	u32 bandlist[WL_MAX_BAND_SUPPORT+1];
16493 	u32 nband = 0;
16494 	u32 i = 0;
16495 	s32 err = 0;
16496 	s32 index = 0;
16497 	s32 nmode = 0;
16498 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5)
16499 	u32 j = 0;
16500 	s32 vhtmode = 0;
16501 	s32 txstreams = 0;
16502 	s32 rxstreams = 0;
16503 	s32 ldpc_cap = 0;
16504 	s32 stbc_rx = 0;
16505 	s32 stbc_tx = 0;
16506 	s32 txbf_bfe_cap = 0;
16507 	s32 txbf_bfr_cap = 0;
16508 #endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */
16509 	s32 bw_cap = 0;
16510 	s32 cur_band = -1;
16511 	struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, };
16512 
16513 	bzero(bandlist, sizeof(bandlist));
16514 	err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist,
16515 		sizeof(bandlist));
16516 	if (unlikely(err)) {
16517 		WL_ERR(("error read bandlist (%d)\n", err));
16518 		return err;
16519 	}
16520 	err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band,
16521 		sizeof(s32));
16522 	if (unlikely(err)) {
16523 		WL_ERR(("error (%d)\n", err));
16524 		return err;
16525 	}
16526 
16527 	err = wldev_iovar_getint(dev, "nmode", &nmode);
16528 	if (unlikely(err)) {
16529 		WL_ERR(("error reading nmode (%d)\n", err));
16530 	}
16531 
16532 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5)
16533 	err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
16534 	if (unlikely(err)) {
16535 		WL_ERR(("error reading vhtmode (%d)\n", err));
16536 	}
16537 
16538 	if (vhtmode) {
16539 		err = wldev_iovar_getint(dev, "txstreams", &txstreams);
16540 		if (unlikely(err)) {
16541 			WL_ERR(("error reading txstreams (%d)\n", err));
16542 		}
16543 
16544 		err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
16545 		if (unlikely(err)) {
16546 			WL_ERR(("error reading rxstreams (%d)\n", err));
16547 		}
16548 
16549 		err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
16550 		if (unlikely(err)) {
16551 			WL_ERR(("error reading ldpc_cap (%d)\n", err));
16552 		}
16553 
16554 		err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
16555 		if (unlikely(err)) {
16556 			WL_ERR(("error reading stbc_rx (%d)\n", err));
16557 		}
16558 
16559 		err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
16560 		if (unlikely(err)) {
16561 			WL_ERR(("error reading stbc_tx (%d)\n", err));
16562 		}
16563 
16564 		err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
16565 		if (unlikely(err)) {
16566 			WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
16567 		}
16568 
16569 		err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
16570 		if (unlikely(err)) {
16571 			WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
16572 		}
16573 	}
16574 #endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */
16575 
16576 	/* For nmode and vhtmode   check bw cap */
16577 	if (nmode ||
16578 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5)
16579 		vhtmode ||
16580 #endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */
16581 		0) {
16582 		err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
16583 		if (unlikely(err)) {
16584 			WL_ERR(("error get mimo_bw_cap (%d)\n", err));
16585 		}
16586 	}
16587 
16588 #ifdef WL_6G_BAND
16589 	wl_is_6g_supported(cfg, bandlist, bandlist[0]);
16590 #endif /* WL_6G_BAND */
16591 
16592 	err = wl_construct_reginfo(cfg, bw_cap);
16593 	if (err) {
16594 		WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
16595 		if (err != BCME_UNSUPPORTED)
16596 			return err;
16597 	}
16598 
16599 	wiphy = bcmcfg_to_wiphy(cfg);
16600 	nband = bandlist[0];
16601 
16602 	for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
16603 		index = -1;
16604 
16605 		if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
16606 			bands[IEEE80211_BAND_2GHZ] =
16607 				&__wl_band_2ghz;
16608 			index = IEEE80211_BAND_2GHZ;
16609 			if (bw_cap == WLC_N_BW_40ALL)
16610 				bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
16611 		} else {
16612 			if (bandlist[i] == WLC_BAND_6G) {
16613 #ifdef CFG80211_6G_SUPPORT
16614 				if (__wl_band_6ghz.n_channels > 0) {
16615 					bands[IEEE80211_BAND_6GHZ] = &__wl_band_6ghz;
16616 					index = IEEE80211_BAND_6GHZ;
16617 				} else {
16618 					WL_ERR(("6GHz channels not listed\n"));
16619 					continue;
16620 				}
16621 #else /* CFG80211_6G_SUPPORT */
16622 				/* Both 6G/5G channels will be under 5G band list */
16623 				if (__wl_band_5ghz_a.n_channels > 0)
16624 				{
16625 					bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
16626 					index = IEEE80211_BAND_5GHZ;
16627 				} else {
16628 					WL_ERR(("5GHz channels not listed\n"));
16629 					continue;
16630 				}
16631 #endif /* CFG80211_6G_SUPPORT */
16632 			} else if ((bandlist[i] == WLC_BAND_5G) &&
16633 				(__wl_band_5ghz_a.n_channels > 0)) {
16634 				bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
16635 				index = IEEE80211_BAND_5GHZ;
16636 			} else {
16637 				WL_ERR(("Invalid band\n"));
16638 				continue;
16639 			}
16640 
16641 			if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
16642 				bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
16643 
16644 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5)
16645 			/* VHT capabilities. */
16646 			if (vhtmode) {
16647 				/* Supported */
16648 				bands[index]->vht_cap.vht_supported = TRUE;
16649 
16650 				for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
16651 					/* TX stream rates. */
16652 					if (j <= txstreams) {
16653 						VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
16654 							bands[index]->vht_cap.vht_mcs.tx_mcs_map);
16655 					} else {
16656 						VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
16657 							bands[index]->vht_cap.vht_mcs.tx_mcs_map);
16658 					}
16659 
16660 					/* RX stream rates. */
16661 					if (j <= rxstreams) {
16662 						VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
16663 							bands[index]->vht_cap.vht_mcs.rx_mcs_map);
16664 					} else {
16665 						VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
16666 							bands[index]->vht_cap.vht_mcs.rx_mcs_map);
16667 					}
16668 				}
16669 
16670 				/* Capabilities */
16671 				/* 80 MHz is mandatory */
16672 				bands[index]->vht_cap.cap |=
16673 					IEEE80211_VHT_CAP_SHORT_GI_80;
16674 
16675 				if (WL_BW_CAP_160MHZ(bw_cap)) {
16676 					bands[index]->vht_cap.cap |=
16677 						IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
16678 					bands[index]->vht_cap.cap |=
16679 						IEEE80211_VHT_CAP_SHORT_GI_160;
16680 				}
16681 
16682 				bands[index]->vht_cap.cap |=
16683 					IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
16684 
16685 				if (ldpc_cap)
16686 					bands[index]->vht_cap.cap |=
16687 						IEEE80211_VHT_CAP_RXLDPC;
16688 
16689 				if (stbc_tx)
16690 					bands[index]->vht_cap.cap |=
16691 						IEEE80211_VHT_CAP_TXSTBC;
16692 
16693 				if (stbc_rx)
16694 					bands[index]->vht_cap.cap |=
16695 						(stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
16696 
16697 				if (txbf_bfe_cap)
16698 					bands[index]->vht_cap.cap |=
16699 						IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
16700 
16701 				if (txbf_bfr_cap) {
16702 					bands[index]->vht_cap.cap |=
16703 						IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
16704 				}
16705 
16706 				if (txbf_bfe_cap || txbf_bfr_cap) {
16707 					bands[index]->vht_cap.cap |=
16708 						(2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
16709 					bands[index]->vht_cap.cap |=
16710 						((txstreams - 1) <<
16711 							VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
16712 					bands[index]->vht_cap.cap |=
16713 						IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
16714 				}
16715 
16716 				/* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
16717 				bands[index]->vht_cap.cap |=
16718 					(7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
16719 				WL_DBG(("__wl_update_wiphybands band[%d] vht_enab=%d vht_cap=%08x "
16720 					"vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
16721 					index,
16722 					bands[index]->vht_cap.vht_supported,
16723 					bands[index]->vht_cap.cap,
16724 					bands[index]->vht_cap.vht_mcs.rx_mcs_map,
16725 					bands[index]->vht_cap.vht_mcs.tx_mcs_map));
16726 			}
16727 #endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */
16728 		}
16729 
16730 		if ((index >= 0) && nmode) {
16731 			bands[index]->ht_cap.cap |=
16732 				(IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
16733 			bands[index]->ht_cap.ht_supported = TRUE;
16734 			bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
16735 			bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
16736 			/* An HT shall support all EQM rates for one spatial stream */
16737 			bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
16738 		}
16739 
16740 	}
16741 
16742 	wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
16743 	wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
16744 #ifdef CFG80211_6G_SUPPORT
16745 	wiphy->bands[IEEE80211_BAND_6GHZ] = bands[IEEE80211_BAND_6GHZ];
16746 #endif /* CFG80211_6G_SUPPORT */
16747 
16748 	/* check if any bands populated otherwise makes 2Ghz as default */
16749 	if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL &&
16750 #ifdef CFG80211_6G_SUPPORT
16751 		wiphy->bands[IEEE80211_BAND_6GHZ] == NULL &&
16752 #endif /* CFG80211_6G_SUPPORT */
16753 		wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) {
16754 		/* Setup 2Ghz band as default */
16755 		wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
16756 	}
16757 
16758 	if (notify) {
16759 		if (!IS_REGDOM_SELF_MANAGED(wiphy)) {
16760 			WL_UPDATE_CUSTOM_REGULATORY(wiphy);
16761 			wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
16762 		}
16763 	}
16764 
16765 	return 0;
16766 }
16767 
wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)16768 s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
16769 {
16770 	s32 err;
16771 
16772 	mutex_lock(&cfg->usr_sync);
16773 	err = __wl_update_wiphybands(cfg, notify);
16774 	mutex_unlock(&cfg->usr_sync);
16775 
16776 	return err;
16777 }
16778 
__wl_cfg80211_up(struct bcm_cfg80211 * cfg)16779 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
16780 {
16781 	s32 err = 0;
16782 	s32 ret = 0;
16783 
16784 	struct net_info *netinfo = NULL;
16785 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
16786 	struct wireless_dev *wdev = ndev->ieee80211_ptr;
16787 	dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
16788 #ifdef WLTDLS
16789 	u32 tdls;
16790 #endif /* WLTDLS */
16791 	u16 wl_iftype = 0;
16792 	u16 wl_mode = 0;
16793 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
16794 
16795 	WL_DBG(("In\n"));
16796 
16797 #if defined(__linux__)
16798 	if (!dhd_download_fw_on_driverload) {
16799 #endif
16800 		err = wl_create_event_handler(cfg);
16801 		if (err) {
16802 			WL_ERR(("wl_create_event_handler failed\n"));
16803 			return err;
16804 		}
16805 		wl_init_event_handler(cfg);
16806 #if defined(__linux__)
16807 	}
16808 #endif
16809 	/* Reserve 0x8000 toggle bit for P2P GO/GC */
16810 	cfg->vif_macaddr_mask = 0x8000;
16811 
16812 #if defined(BCMDONGLEHOST)
16813 	err = dhd_config_dongle(cfg);
16814 	if (unlikely(err))
16815 		return err;
16816 #endif /* defined(BCMDONGLEHOST) */
16817 
16818 #ifdef SHOW_LOGTRACE
16819 	/* Start the event logging */
16820 	wl_add_remove_eventmsg(ndev, WLC_E_TRACE, TRUE);
16821 #endif /* SHOW_LOGTRACE */
16822 
16823 	(void)memcpy_s(wdev->wiphy->perm_addr, ETHER_ADDR_LEN,
16824 		bcmcfg_to_prmry_ndev(cfg)->perm_addr, ETHER_ADDR_LEN);
16825 	/* Always bring up interface in STA mode.
16826 	* Did observe , if previous SofAP Bringup/cleanup
16827 	* is not done properly, iftype is stuck with AP mode.
16828 	* So during next wlan0 up, forcing the type to STA
16829 	*/
16830 	netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
16831 	if (!netinfo) {
16832 		WL_ERR(("there is no netinfo\n"));
16833 		return -ENODEV;
16834 	}
16835 
16836 	if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
16837 		/* AP on primary interface case: Supplicant will
16838 		 * set mode first and then do dev_open. so in this
16839 		 * case, the type will already be set.
16840 		 */
16841 		netinfo->iftype = WL_IF_TYPE_AP;
16842 	} else {
16843 		ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
16844 		netinfo->iftype = WL_IF_TYPE_STA;
16845 	}
16846 
16847 	if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
16848 		return -EINVAL;
16849 	}
16850 	if (!dhd->fw_preinit) {
16851 		err = wl_config_infra(cfg, ndev, wl_iftype);
16852 		if (unlikely(err && err != -EINPROGRESS)) {
16853 			WL_ERR(("wl_config_infra failed\n"));
16854 			if (err == -1) {
16855 				WL_ERR(("return error %d\n", err));
16856 				return err;
16857 			}
16858 		}
16859 	}
16860 
16861 	err = wl_init_scan(cfg);
16862 	if (err) {
16863 		WL_ERR(("wl_init_scan failed\n"));
16864 		return err;
16865 	}
16866 	err = __wl_update_wiphybands(cfg, true);
16867 	if (unlikely(err)) {
16868 		WL_ERR(("wl_update_wiphybands failed\n"));
16869 		if (err == -1) {
16870 			WL_ERR(("return error %d\n", err));
16871 			return err;
16872 		}
16873 	}
16874 
16875 	/* Update wlc version in cfg struct already queried as part of DHD  initialization */
16876 	cfg->wlc_ver.wlc_ver_major = dhd->wlc_ver_major;
16877 	cfg->wlc_ver.wlc_ver_minor = dhd->wlc_ver_minor;
16878 
16879 	if ((ret = wldev_iovar_getbuf(ndev, "scan_ver", NULL, 0,
16880 		ioctl_buf, sizeof(ioctl_buf), NULL)) == BCME_OK) {
16881 		WL_INFORM_MEM(("scan_params v2\n"));
16882 		/* use scan_params ver2 */
16883 		cfg->scan_params_v2 = true;
16884 	} else {
16885 		if (ret == BCME_UNSUPPORTED) {
16886 			WL_INFORM(("scan_ver, UNSUPPORTED\n"));
16887 			ret = BCME_OK;
16888 		} else {
16889 			WL_INFORM(("get scan_ver err(%d)\n", ret));
16890 		}
16891 	}
16892 
16893 	if (((cfg->wlc_ver.wlc_ver_major == MIN_JOINEXT_V1_BR1_FW_MAJOR) &&
16894 			(cfg->wlc_ver.wlc_ver_minor == MIN_JOINEXT_V1_BR1_FW_MINOR)) ||
16895 			((cfg->wlc_ver.wlc_ver_major == MIN_JOINEXT_V1_BR2_FW_MAJOR) &&
16896 			(cfg->wlc_ver.wlc_ver_minor >= MIN_JOINEXT_V1_BR2_FW_MINOR)) ||
16897 			(cfg->wlc_ver.wlc_ver_major >= MIN_JOINEXT_V1_FW_MAJOR)) {
16898 		cfg->join_iovar_ver = WL_EXTJOIN_VERSION_V1;
16899 		WL_INFORM_MEM(("join_ver:%d\n", cfg->join_iovar_ver));
16900 	}
16901 
16902 #ifdef DHD_LOSSLESS_ROAMING
16903 	del_timer_sync(&cfg->roam_timeout);
16904 #endif /* DHD_LOSSLESS_ROAMING */
16905 
16906 	err = dhd_monitor_init(cfg->pub);
16907 
16908 #ifdef WL_HOST_BAND_MGMT
16909 	/* By default the curr_band is initialized to BAND_AUTO */
16910 	if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) {
16911 		if (ret == BCME_UNSUPPORTED) {
16912 			/* Don't fail the initialization, lets just
16913 			 * fall back to the original method
16914 			 */
16915 			WL_ERR(("WL_HOST_BAND_MGMT defined, "
16916 				"but roam_band iovar not supported \n"));
16917 		} else {
16918 			WL_ERR(("roam_band failed. ret=%d", ret));
16919 			err = -1;
16920 		}
16921 	}
16922 #endif /* WL_HOST_BAND_MGMT */
16923 	/* Reset WES mode to 0 */
16924 	cfg->wes_mode = OFF;
16925 	cfg->ncho_mode = OFF;
16926 	cfg->ncho_band = WLC_BAND_AUTO;
16927 #ifdef WBTEXT
16928 	/* when wifi up, set roam_prof to default value */
16929 	if (dhd->wbtext_support) {
16930 		if (dhd->op_mode & DHD_FLAG_STA_MODE) {
16931 			if (!dhd->fw_preinit) {
16932 				wl_cfg80211_wbtext_set_default(ndev);
16933 			}
16934 			wl_cfg80211_wbtext_clear_bssid_list(cfg);
16935 		}
16936 	}
16937 #endif /* WBTEXT */
16938 #ifdef WLTDLS
16939 	if (wldev_iovar_getint(ndev, "tdls_enable", &tdls) == 0) {
16940 		WL_DBG(("TDLS supported in fw\n"));
16941 		cfg->tdls_supported = true;
16942 	}
16943 #endif /* WLTDLS */
16944 #ifdef WL_IFACE_MGMT
16945 #ifdef CUSTOM_IF_MGMT_POLICY
16946 	cfg->iface_data.policy = CUSTOM_IF_MGMT_POLICY;
16947 #else
16948 	cfg->iface_data.policy = WL_IF_POLICY_DEFAULT;
16949 #endif /*  CUSTOM_IF_MGMT_POLICY */
16950 #endif /* WL_IFACE_MGMT */
16951 #ifdef WL_NAN
16952 #ifdef WL_NANP2P
16953 	if (FW_SUPPORTED(dhd, nanp2p)) {
16954 		/* Enable NANP2P concurrent support */
16955 		cfg->conc_disc = WL_NANP2P_CONC_SUPPORT;
16956 		WL_INFORM_MEM(("nan + p2p conc discovery is supported\n"));
16957 		cfg->nan_p2p_supported = true;
16958 	}
16959 #endif /* WL_NANP2P */
16960 #endif /* WL_NAN  */
16961 
16962 #ifdef WL_SAR_TX_POWER
16963 	cfg->wifi_tx_power_mode = WIFI_POWER_SCENARIO_INVALID;
16964 #endif /* WL_SAR_TX_POWER */
16965 
16966 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
16967 	/* wlan scan_supp timer and work thread info */
16968 	init_timer_compat(&cfg->scan_supp_timer, wl_cfg80211_scan_supp_timerfunc, cfg);
16969 	INIT_WORK(&cfg->wlan_work, wl_cfg80211_work_handler);
16970 #endif /* DHCP_SCAN_SUPPRESS */
16971 
16972 	INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
16973 	wl_set_drv_status(cfg, READY, ndev);
16974 
16975 	return err;
16976 }
16977 
__wl_cfg80211_down(struct bcm_cfg80211 * cfg)16978 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
16979 {
16980 	s32 err = 0;
16981 	struct net_info *iter, *next;
16982 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
16983 #if defined(WL_CFG80211) && \
16984 	(defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && \
16985 	!defined(PLATFORM_SLP)
16986 	struct net_device *p2p_net = cfg->p2p_net;
16987 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) && !PLATFORM_SLP */
16988 #ifdef BCMDONGLEHOST
16989 	dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
16990 #endif /* BCMDONGLEHOST */
16991 	WL_INFORM_MEM(("cfg80211 down\n"));
16992 
16993 	/* Check if cfg80211 interface is already down */
16994 	if (!wl_get_drv_status(cfg, READY, ndev)) {
16995 		WL_DBG(("cfg80211 interface is already down\n"));
16996 		return err;	/* it is even not ready */
16997 	}
16998 
16999 #ifdef SHOW_LOGTRACE
17000 	/* Stop the event logging */
17001 	wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
17002 #endif /* SHOW_LOGTRACE */
17003 
17004 	/* clear vendor OUI list */
17005 	wl_vndr_ies_clear_vendor_oui_list(cfg);
17006 
17007 	/* clear timestamps */
17008 	CLR_TS(cfg, scan_start);
17009 	CLR_TS(cfg, scan_cmplt);
17010 	CLR_TS(cfg, conn_start);
17011 	CLR_TS(cfg, conn_cmplt);
17012 	CLR_TS(cfg, authorize_start);
17013 	CLR_TS(cfg, authorize_cmplt);
17014 
17015 	/* Delete pm_enable_work */
17016 	wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
17017 
17018 	if (cfg->loc.in_progress) {
17019 		/* Listen in progress */
17020 		if (delayed_work_pending(&cfg->loc.work)) {
17021 			cancel_delayed_work_sync(&cfg->loc.work);
17022 		}
17023 		wl_cfgscan_notify_listen_complete(cfg);
17024 	}
17025 
17026 	if (delayed_work_pending(&cfg->ap_work)) {
17027 		cancel_delayed_work_sync(&cfg->ap_work);
17028 	}
17029 
17030 	if (cfg->p2p_supported) {
17031 		wl_clr_p2p_status(cfg, GO_NEG_PHASE);
17032 #ifdef PROP_TXSTATUS_VSDB
17033 #if defined(BCMSDIO) || defined(BCMDBUS)
17034 		if (wl_cfgp2p_vif_created(cfg)) {
17035 			bool enabled = false;
17036 			dhd_wlfc_get_enable(dhd, &enabled);
17037 			/* WLFC should be turned off
17038 			*	while unloading dhd driver in IBSS or SoftAP mode
17039 			*/
17040 			if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
17041 				dhd->op_mode != DHD_FLAG_IBSS_MODE) {
17042 				dhd_wlfc_deinit(dhd);
17043 				cfg->wlfc_on = false;
17044 			}
17045 		}
17046 #endif /* BCMSDIO || BCMDBUS */
17047 #endif /* PROP_TXSTATUS_VSDB */
17048 	}
17049 
17050 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
17051 	/* Force clear of scan_suppress */
17052 	if (cfg->scan_suppressed)
17053 		wl_cfg80211_scan_suppress(ndev, 0);
17054 	del_timer_sync(&cfg->scan_supp_timer);
17055 	cancel_work_sync(&cfg->wlan_work);
17056 #endif /* DHCP_SCAN_SUPPRESS */
17057 
17058 #ifdef WL_SAR_TX_POWER
17059 	cfg->wifi_tx_power_mode = WIFI_POWER_SCENARIO_INVALID;
17060 #endif /* WL_SAR_TX_POWER */
17061 	if (!dhd_download_fw_on_driverload) {
17062 		/* For built-in drivers/other drivers that do reset on
17063 		 * "ifconfig <primary_iface> down", cleanup any left
17064 		 * over interfaces
17065 		 */
17066 		wl_cfg80211_cleanup_virtual_ifaces(cfg, false);
17067 	}
17068 	/* Clear used mac addr mask */
17069 	cfg->vif_macaddr_mask = 0;
17070 
17071 #ifdef BCMDONGLEHOST
17072 	if (dhd->up)
17073 #endif /* BCMDONGLEHOST */
17074 	{
17075 		/* If primary BSS is operational (for e.g SoftAP), bring it down */
17076 		if (wl_cfg80211_bss_isup(ndev, 0)) {
17077 			if (wl_cfg80211_bss_up(cfg, ndev, 0, 0) < 0)
17078 				WL_ERR(("BSS down failed \n"));
17079 		}
17080 
17081 		/* clear all the security setting on primary Interface */
17082 		wl_cfg80211_clear_security(cfg);
17083 	}
17084 
17085 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17086 	for_each_ndev(cfg, iter, next) {
17087 		GCC_DIAGNOSTIC_POP();
17088 		if (iter->ndev) /* p2p discovery iface is null */
17089 			wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
17090 	}
17091 #ifdef WL_SDO
17092 	wl_cfg80211_sdo_deinit(cfg);
17093 #endif
17094 
17095 #ifdef P2P_LISTEN_OFFLOADING
17096 	wl_cfg80211_p2plo_deinit(cfg);
17097 #endif /* P2P_LISTEN_OFFLOADING */
17098 
17099 	/* cancel and notify scan complete, if scan request is pending */
17100 	wl_cfgscan_cancel_scan(cfg);
17101 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17102 	for_each_ndev(cfg, iter, next) {
17103 		GCC_DIAGNOSTIC_POP();
17104 		/* p2p discovery iface ndev ptr could be null */
17105 		if (iter->ndev == NULL)
17106 			continue;
17107 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
17108 		WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
17109 			wl_get_drv_status(cfg, CONNECTING, ndev),
17110 			wl_get_drv_status(cfg, CONNECTED, ndev),
17111 			wl_get_drv_status(cfg, DISCONNECTING, ndev),
17112 			wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
17113 
17114 		if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
17115 			CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
17116 			wl_clr_drv_status(cfg, AUTHORIZED, iter->ndev);
17117 		}
17118 
17119 		if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
17120 			wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
17121 
17122 			u8 *latest_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
17123 			struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
17124 			struct wireless_dev *wdev = ndev->ieee80211_ptr;
17125 			struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid,
17126 				wdev->ssid, wdev->ssid_len);
17127 
17128 			BCM_REFERENCE(bss);
17129 
17130 			CFG80211_CONNECT_RESULT(ndev,
17131 				latest_bssid, bss, NULL, 0, NULL, 0,
17132 				WLAN_STATUS_UNSPECIFIED_FAILURE,
17133 				GFP_KERNEL);
17134 		}
17135 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
17136 		wl_clr_drv_status(cfg, READY, iter->ndev);
17137 		wl_clr_drv_status(cfg, SCANNING, iter->ndev);
17138 		wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
17139 		wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
17140 		wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
17141 		wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
17142 		wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
17143 		wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
17144 		wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev);
17145 		wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev);
17146 	}
17147 	bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
17148 		NL80211_IFTYPE_STATION;
17149 #if defined(WL_CFG80211) && \
17150 	(defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && \
17151 	!defined(PLATFORM_SLP)
17152 #ifdef SUPPORT_DEEP_SLEEP
17153 	if (!trigger_deep_sleep)
17154 #endif /* SUPPORT_DEEP_SLEEP */
17155 		if (p2p_net)
17156 			dev_close(p2p_net);
17157 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT)&& !PLATFORM_SLP */
17158 
17159 	/* Avoid deadlock from wl_cfg80211_down */
17160 #if defined(BCMDONGLEHOST) && defined(__linux__)
17161 	if (!dhd_download_fw_on_driverload) {
17162 #endif
17163 		mutex_unlock(&cfg->usr_sync);
17164 		wl_destroy_event_handler(cfg);
17165 		mutex_lock(&cfg->usr_sync);
17166 #if defined(BCMDONGLEHOST) && defined(__linux__)
17167 	}
17168 #endif
17169 
17170 	wl_flush_eq(cfg);
17171 	wl_link_down(cfg);
17172 	if (cfg->p2p_supported) {
17173 		if (timer_pending(&cfg->p2p->listen_timer))
17174 			del_timer_sync(&cfg->p2p->listen_timer);
17175 		wl_cfgp2p_down(cfg);
17176 	}
17177 
17178 	del_timer_sync(&cfg->scan_timeout);
17179 
17180 	wl_cfg80211_clear_mgmt_vndr_ies(cfg);
17181 
17182 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
17183 	DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
17184 #endif
17185 
17186 	dhd_monitor_uninit();
17187 #ifdef WLAIBSS_MCHAN
17188 	bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
17189 #endif /* WLAIBSS_MCHAN */
17190 
17191 #ifdef WL11U
17192 	/* Clear interworking element. */
17193 	if (cfg->wl11u) {
17194 		cfg->wl11u = FALSE;
17195 	}
17196 #endif /* WL11U */
17197 
17198 #ifdef CUSTOMER_HW4_DEBUG
17199 	if (wl_scan_timeout_dbg_enabled) {
17200 		wl_scan_timeout_dbg_clear();
17201 	}
17202 #endif /* CUSTOMER_HW4_DEBUG */
17203 
17204 	cfg->disable_roam_event = false;
17205 	cfg->scan_params_v2 = false;
17206 
17207 	DNGL_FUNC(dhd_cfg80211_down, (cfg));
17208 
17209 #ifdef DHD_IFDEBUG
17210 	/* Printout all netinfo entries */
17211 	wl_probe_wdev_all(cfg);
17212 #endif /* DHD_IFDEBUG */
17213 
17214 	return err;
17215 }
17216 
wl_cfg80211_up(struct net_device * net)17217 s32 wl_cfg80211_up(struct net_device *net)
17218 {
17219 	struct bcm_cfg80211 *cfg;
17220 	s32 err = 0;
17221 	int val = 1;
17222 #ifdef BCMDONGLEHOST
17223 	dhd_pub_t *dhd;
17224 #endif /* BCMDONGLEHOST */
17225 #ifdef DISABLE_PM_BCNRX
17226 	s32 interr = 0;
17227 	uint param = 0;
17228 	s8 iovbuf[WLC_IOCTL_SMLEN];
17229 #endif /* DISABLE_PM_BCNRX */
17230 #ifdef WL_USE_RANDOMIZED_SCAN
17231 	uint8 random_addr[ETHER_ADDR_LEN] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
17232 #endif /* WL_USE_RANDOMIZED_SCAN */
17233 	WL_DBG(("In\n"));
17234 	cfg = wl_get_cfg(net);
17235 
17236 	if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
17237 		sizeof(int)) < 0)) {
17238 		WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
17239 		return err;
17240 	}
17241 	val = dtoh32(val);
17242 	if (val != WLC_IOCTL_VERSION && val != 1) {
17243 		WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
17244 			val, WLC_IOCTL_VERSION));
17245 		return BCME_VERSION;
17246 	}
17247 	ioctl_version = val;
17248 	WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
17249 #ifdef WL_EXT_IAPSTA
17250 	wl_ext_in4way_sync(net, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
17251 		WL_EXT_STATUS_DISCONNECTED, NULL);
17252 #endif
17253 
17254 	mutex_lock(&cfg->usr_sync);
17255 #if defined(BCMDONGLEHOST)
17256 	dhd = (dhd_pub_t *)(cfg->pub);
17257 	if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
17258 		err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
17259 		if (unlikely(err)) {
17260 			mutex_unlock(&cfg->usr_sync);
17261 			return err;
17262 		}
17263 	}
17264 #ifdef WLMESH_CFG80211
17265 	cfg->wdev->wiphy->features |= NL80211_FEATURE_USERSPACE_MPM;
17266 #endif /* WLMESH_CFG80211 */
17267 #if defined(BCMSUP_4WAY_HANDSHAKE)
17268 	if (dhd->fw_4way_handshake) {
17269 		/* This is a hacky method to indicate fw 4WHS support and
17270 		 * is used only for kernels (kernels < 3.14). For newer
17271 		 * kernels, we would be using vendor extn. path to advertise
17272 		 * FW based 4-way handshake feature support.
17273 		 */
17274 		cfg->wdev->wiphy->features |= NL80211_FEATURE_FW_4WAY_HANDSHAKE;
17275 	}
17276 #endif /* BCMSUP_4WAY_HANDSHAKE */
17277 #endif /* defined(BCMDONGLEHOST) */
17278 	err = __wl_cfg80211_up(cfg);
17279 	if (unlikely(err))
17280 		WL_ERR(("__wl_cfg80211_up failed\n"));
17281 
17282 #ifdef ROAM_CHANNEL_CACHE
17283 	if (init_roam_cache(cfg, ioctl_version) == 0) {
17284 		/* Enable support for Roam cache */
17285 		cfg->rcc_enabled = true;
17286 		WL_ERR(("Roam channel cache enabled\n"));
17287 	} else {
17288 		WL_ERR(("Failed to enable RCC.\n"));
17289 	}
17290 #endif /* ROAM_CHANNEL_CACHE */
17291 #ifdef WL_USE_RANDOMIZED_SCAN
17292 	/* Call scanmac only for valid configuration */
17293 	if (wl_cfg80211_scan_mac_enable(net)) {
17294 		WL_ERR(("%s : randmac enable failed\n", __FUNCTION__));
17295 	} else {
17296 		/* scanmac enabled. apply configuration */
17297 		if (wl_cfg80211_scan_mac_config(net, random_addr, NULL)) {
17298 			WL_ERR(("%s : failed to set randmac config for scan\n", __FUNCTION__));
17299 			/* if config fails, disable scan mac */
17300 			wl_cfg80211_scan_mac_disable(net);
17301 		}
17302 	}
17303 #endif /* WL_USE_RANDOMIZED_SCAN */
17304 /* WAR: disable pm_bcnrx , scan_ps for BCM4354 WISOL module.
17305  * WISOL module have ANT_1 Rx sensitivity issue.
17306  */
17307 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
17308 	dhd_force_disable_singlcore_scan(dhd);
17309 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
17310 
17311 	/* IOVAR configurations with 'up' condition */
17312 #ifdef DISABLE_PM_BCNRX
17313 	interr = wldev_iovar_setbuf(net, "pm_bcnrx", (char *)&param, sizeof(param), iovbuf,
17314 			sizeof(iovbuf), &cfg->ioctl_buf_sync);
17315 
17316 	if (unlikely(interr)) {
17317 		WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
17318 	}
17319 #endif /* DISABLE_PM_BCNRX */
17320 #ifdef WL_CHAN_UTIL
17321 	interr = wl_cfg80211_start_bssload_report(net);
17322 	if (unlikely(interr)) {
17323 		WL_ERR(("%s: Failed to start bssload_report eventing, err=%d\n",
17324 			__FUNCTION__, interr));
17325 	}
17326 #endif /* WL_CHAN_UTIL */
17327 
17328 	mutex_unlock(&cfg->usr_sync);
17329 
17330 #ifdef WLAIBSS_MCHAN
17331 	bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
17332 #endif /* WLAIBSS_MCHAN */
17333 	cfg->spmk_info_list->pmkids.count = 0;
17334 	return err;
17335 }
17336 
17337 /* Private Event to Supplicant with indication that chip hangs */
wl_cfg80211_hang(struct net_device * dev,u16 reason)17338 int wl_cfg80211_hang(struct net_device *dev, u16 reason)
17339 {
17340 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17341 #ifdef BCMDONGLEHOST
17342 	dhd_pub_t *dhd;
17343 #if defined(SOFTAP_SEND_HANGEVT)
17344 	/* specifc mac address used for hang event */
17345 	uint8 hang_mac[ETHER_ADDR_LEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
17346 #endif /* SOFTAP_SEND_HANGEVT */
17347 #endif /* BCMDONGLEHOST */
17348 	if (!cfg) {
17349 		return BCME_ERROR;
17350 	}
17351 
17352 	RETURN_EIO_IF_NOT_UP(cfg);
17353 
17354 #ifdef BCMDONGLEHOST
17355 	dhd = (dhd_pub_t *)(cfg->pub);
17356 #if defined(DHD_HANG_SEND_UP_TEST)
17357 	if (dhd->req_hang_type) {
17358 		WL_ERR(("wl_cfg80211_hang, Clear HANG test request 0x%x\n",
17359 			dhd->req_hang_type));
17360 		dhd->req_hang_type = 0;
17361 	}
17362 #endif /* DHD_HANG_SEND_UP_TEST */
17363 	if ((dhd->hang_reason <= HANG_REASON_MASK) || (dhd->hang_reason >= HANG_REASON_MAX)) {
17364 		WL_ERR(("wl_cfg80211_hang, Invalid hang reason 0x%x\n",
17365 			dhd->hang_reason));
17366 		dhd->hang_reason = HANG_REASON_UNKNOWN;
17367 	}
17368 #ifdef DHD_USE_EXTENDED_HANG_REASON
17369 	/* The proper dhd->hang_reason handling codes should be implemented
17370 	 * in the WPA Supplicant/Hostapd or Android framework.
17371 	 * If not, HANG event may not be sent to Android framework and
17372 	 * driver cannot be reloaded.
17373 	 * Please do not enable DHD_USE_EXTENDED_HANG_REASON if your Android platform
17374 	 * cannot handle the dhd->hang_reason value.
17375 	 */
17376 	if (dhd->hang_reason != 0) {
17377 		reason = dhd->hang_reason;
17378 	}
17379 #endif /* DHD_USE_EXTENDED_HANG_REASON */
17380 	WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32)(dhd->hang_reason)));
17381 #else
17382 	WL_ERR(("In : chip crash eventing\n"));
17383 #endif /* BCMDONGLEHOST */
17384 
17385 	wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
17386 #ifdef BCMDONGLEHOST
17387 #ifdef SOFTAP_SEND_HANGEVT
17388 	if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
17389 		cfg80211_del_sta(dev, hang_mac, GFP_ATOMIC);
17390 	} else
17391 #endif /* SOFTAP_SEND_HANGEVT */
17392 #endif /* BCMDONGLEHOST */
17393 	{
17394 		if (dhd->up == TRUE) {
17395 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
17396 #ifdef CUSOMER_HW4
17397 			wl_cfgvendor_send_hang_event(dev, reason,
17398 					dhd->hang_info, dhd->hang_info_cnt);
17399 #else
17400 			wl_cfgvendor_simple_hang_event(dev, reason);
17401 #endif
17402 #else
17403 			CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
17404 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
17405 		}
17406 	}
17407 #if defined(RSSIAVG)
17408 	wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
17409 #endif
17410 #if defined(BSSCACHE)
17411 	wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
17412 #endif
17413 	if (cfg != NULL) {
17414 		/* Do we need to call wl_cfg80211_down here ? */
17415 		wl_link_down(cfg);
17416 	}
17417 	return 0;
17418 }
17419 
wl_cfg80211_down(struct net_device * dev)17420 s32 wl_cfg80211_down(struct net_device *dev)
17421 {
17422 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17423 #ifdef RTT_SUPPORT
17424 	dhd_pub_t *dhdp;
17425 #endif /* RTT_SUPPORT */
17426 
17427 	s32 err = BCME_ERROR;
17428 
17429 	WL_DBG(("In\n"));
17430 
17431 	if (cfg && (cfg == wl_cfg80211_get_bcmcfg())) {
17432 #ifdef WL_NAN
17433 		mutex_lock(&cfg->if_sync);
17434 		wl_cfgnan_check_nan_disable_pending(cfg, true, false);
17435 		mutex_unlock(&cfg->if_sync);
17436 #endif /* WL_NAN */
17437 
17438 #ifdef RTT_SUPPORT
17439 		dhdp = (dhd_pub_t *)(cfg->pub);
17440 		if (dhdp->rtt_state) {
17441 			dhd_rtt_deinit(dhdp);
17442 		}
17443 #endif /* RTT_SUPPORT */
17444 		mutex_lock(&cfg->usr_sync);
17445 #if defined(RSSIAVG)
17446 		wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
17447 #endif
17448 #if defined(BSSCACHE)
17449 		wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
17450 #endif
17451 		err = __wl_cfg80211_down(cfg);
17452 		mutex_unlock(&cfg->usr_sync);
17453 	}
17454 
17455 	return err;
17456 }
17457 
17458 void
wl_cfg80211_sta_ifdown(struct net_device * dev)17459 wl_cfg80211_sta_ifdown(struct net_device *dev)
17460 {
17461 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17462 
17463 	WL_DBG(("In\n"));
17464 
17465 	if (cfg) {
17466 		/* cancel scan if anything pending */
17467 		wl_cfgscan_cancel_scan(cfg);
17468 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
17469 		if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
17470 			wl_get_drv_status(cfg, CONNECTED, dev)) {
17471 			CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
17472 		}
17473 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
17474 	}
17475 }
17476 
wl_read_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 item)17477 void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
17478 {
17479 	unsigned long flags;
17480 	void *rptr = NULL;
17481 	struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
17482 
17483 	if (!profile)
17484 		return NULL;
17485 	WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
17486 	switch (item) {
17487 	case WL_PROF_SEC:
17488 		rptr = &profile->sec;
17489 		break;
17490 	case WL_PROF_ACT:
17491 		rptr = &profile->active;
17492 		break;
17493 	case WL_PROF_BSSID:
17494 		rptr = profile->bssid;
17495 		break;
17496 	case WL_PROF_SSID:
17497 		rptr = &profile->ssid;
17498 		break;
17499 	case WL_PROF_CHAN:
17500 		rptr = &profile->channel;
17501 		break;
17502 	case WL_PROF_LATEST_BSSID:
17503 		rptr = profile->latest_bssid;
17504 		break;
17505 	}
17506 	WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
17507 	if (!rptr)
17508 		WL_ERR(("invalid item (%d)\n", item));
17509 	return rptr;
17510 }
17511 
17512 s32
wl_update_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,const void * data,s32 item)17513 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
17514 	const wl_event_msg_t *e, const void *data, s32 item)
17515 {
17516 	s32 err = 0;
17517 	const struct wlc_ssid *ssid;
17518 	unsigned long flags;
17519 	struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
17520 
17521 	if (!profile)
17522 		return WL_INVALID;
17523 	WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
17524 	switch (item) {
17525 	case WL_PROF_SSID:
17526 		ssid = (const wlc_ssid_t *) data;
17527 		bzero(profile->ssid.SSID,
17528 			sizeof(profile->ssid.SSID));
17529 		profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
17530 		memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
17531 		break;
17532 	case WL_PROF_BSSID:
17533 		if (data)
17534 			memcpy(profile->bssid, data, ETHER_ADDR_LEN);
17535 		else
17536 			bzero(profile->bssid, ETHER_ADDR_LEN);
17537 		break;
17538 	case WL_PROF_SEC:
17539 		memcpy(&profile->sec, data, sizeof(profile->sec));
17540 		break;
17541 	case WL_PROF_ACT:
17542 		profile->active = *(const bool *)data;
17543 		break;
17544 	case WL_PROF_BEACONINT:
17545 		profile->beacon_interval = *(const u16 *)data;
17546 		break;
17547 	case WL_PROF_DTIMPERIOD:
17548 		profile->dtim_period = *(const u8 *)data;
17549 		break;
17550 	case WL_PROF_CHAN:
17551 		profile->channel = *(const chanspec_t *)data;
17552 		break;
17553 	case WL_PROF_LATEST_BSSID:
17554 		if (data) {
17555 			memcpy_s(profile->latest_bssid, sizeof(profile->latest_bssid),
17556 					data, ETHER_ADDR_LEN);
17557 		} else {
17558 			memset_s(profile->latest_bssid, sizeof(profile->latest_bssid),
17559 					0, ETHER_ADDR_LEN);
17560 		}
17561 		break;
17562 	default:
17563 		err = -EOPNOTSUPP;
17564 		break;
17565 	}
17566 	WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
17567 
17568 	if (err == -EOPNOTSUPP)
17569 		WL_ERR(("unsupported item (%d)\n", item));
17570 
17571 	return err;
17572 }
17573 
wl_cfg80211_dbg_level(u32 level)17574 void wl_cfg80211_dbg_level(u32 level)
17575 {
17576 	/*
17577 	* prohibit to change debug level
17578 	* by insmod parameter.
17579 	* eventually debug level will be configured
17580 	* in compile time by using CONFIG_XXX
17581 	*/
17582 	/* wl_dbg_level = level; */
17583 }
17584 
wl_is_ibssstarter(struct bcm_cfg80211 * cfg)17585 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
17586 {
17587 	return cfg->ibss_starter;
17588 }
17589 
wl_add_ie(struct bcm_cfg80211 * cfg,u8 t,u8 l,u8 * v)17590 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
17591 {
17592 	struct wl_ie *ie = wl_to_ie(cfg);
17593 	s32 err = 0;
17594 
17595 	if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
17596 		WL_ERR(("ei crosses buffer boundary\n"));
17597 		return -ENOSPC;
17598 	}
17599 	ie->buf[ie->offset] = t;
17600 	ie->buf[ie->offset + 1] = l;
17601 	memcpy(&ie->buf[ie->offset + 2], v, l);
17602 	ie->offset += l + 2;
17603 
17604 	return err;
17605 }
17606 
wl_link_up(struct bcm_cfg80211 * cfg)17607 static void wl_link_up(struct bcm_cfg80211 *cfg)
17608 {
17609 	cfg->link_up = true;
17610 }
17611 
wl_link_down(struct bcm_cfg80211 * cfg)17612 static void wl_link_down(struct bcm_cfg80211 *cfg)
17613 {
17614 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
17615 
17616 	WL_DBG(("In\n"));
17617 	cfg->link_up = false;
17618 	if (conn_info) {
17619 		conn_info->req_ie_len = 0;
17620 		conn_info->resp_ie_len = 0;
17621 	}
17622 }
17623 
wl_lock_eq(struct bcm_cfg80211 * cfg)17624 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
17625 {
17626 	unsigned long flags;
17627 
17628 	WL_CFG_EQ_LOCK(&cfg->eq_lock, flags);
17629 	return flags;
17630 }
17631 
wl_unlock_eq(struct bcm_cfg80211 * cfg,unsigned long flags)17632 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
17633 {
17634 	WL_CFG_EQ_UNLOCK(&cfg->eq_lock, flags);
17635 }
17636 
wl_init_eq_lock(struct bcm_cfg80211 * cfg)17637 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
17638 {
17639 	spin_lock_init(&cfg->eq_lock);
17640 }
17641 
wl_delay(u32 ms)17642 static void wl_delay(u32 ms)
17643 {
17644 	if (in_atomic() || (ms < jiffies_to_msecs(1))) {
17645 		OSL_DELAY(ms*1000);
17646 	} else {
17647 		OSL_SLEEP(ms);
17648 	}
17649 }
17650 
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)17651 s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
17652 {
17653 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17654 	struct ether_addr primary_mac;
17655 	if (!cfg->p2p)
17656 		return -1;
17657 	if (!p2p_is_on(cfg)) {
17658 		get_primary_mac(cfg, &primary_mac);
17659 		memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN);
17660 	} else {
17661 		memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
17662 			ETHER_ADDR_LEN);
17663 	}
17664 
17665 	return 0;
17666 }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)17667 s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
17668 {
17669 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17670 
17671 	return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
17672 }
17673 
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)17674 s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
17675 {
17676 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17677 
17678 	return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
17679 }
17680 
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)17681 s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
17682 {
17683 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17684 
17685 	return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
17686 }
17687 
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)17688 s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
17689 {
17690 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17691 
17692 	return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
17693 }
17694 
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)17695 s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
17696 {
17697 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17698 
17699 	return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
17700 }
17701 
17702 #ifdef P2PLISTEN_AP_SAMECHN
wl_cfg80211_set_p2p_resp_ap_chn(struct net_device * net,s32 enable)17703 s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
17704 {
17705 	s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
17706 
17707 	if ((ret == 0) && enable) {
17708 		/* disable PM for p2p responding on infra AP channel */
17709 		s32 pm = PM_OFF;
17710 
17711 		ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm));
17712 	}
17713 
17714 	return ret;
17715 }
17716 #endif /* P2PLISTEN_AP_SAMECHN */
17717 
17718 #ifdef WL_SDO
17719 #define MAX_QR_LEN NLMSG_GOODSIZE
17720 
17721 typedef struct wl_cfg80211_dev_info {
17722 	u16 band;
17723 	u16 freq;
17724 	s16 rssi;
17725 	u16 ie_len;
17726 	u8 bssid[ETH_ALEN];
17727 } wl_cfg80211_dev_info_t;
17728 
17729 static s32
wl_notify_device_discovery(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)17730 wl_notify_device_discovery(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17731 	const wl_event_msg_t *e, void *data)
17732 {
17733 	int err = 0;
17734 	u32 event = ntoh32(e->event_type);
17735 	wl_cfg80211_dev_info_t info;
17736 	wl_bss_info_t *bi = NULL;
17737 	struct net_device *ndev = NULL;
17738 	u8 *buf = NULL;
17739 	u32 buflen = 0;
17740 	u16 channel = 0;
17741 	wl_escan_result_t *escan_result;
17742 	chanspec_t chspec = INVCHANSPEC;
17743 
17744 	WL_SD(("Enter. type:%d \n", event));
17745 
17746 	if ((event != WLC_E_P2PO_ADD_DEVICE) && (event != WLC_E_P2PO_DEL_DEVICE)) {
17747 		WL_ERR(("Unknown Event\n"));
17748 		return -EINVAL;
17749 	}
17750 
17751 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17752 
17753 	mutex_lock(&cfg->usr_sync);
17754 	if (event == WLC_E_P2PO_DEL_DEVICE) {
17755 		WL_SD(("DEV_LOST MAC:"MACDBG" \n", MAC2STRDBG(e->addr.octet)));
17756 		err = wl_genl_send_msg(ndev, event, (const u8 *)e->addr.octet, ETH_ALEN, 0, 0);
17757 	} else {
17758 
17759 		escan_result = (wl_escan_result_t *) data;
17760 
17761 		if (dtoh16(escan_result->bss_count) != 1) {
17762 			WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
17763 			err = -EINVAL;
17764 			goto exit;
17765 		}
17766 
17767 		bi = escan_result->bss_info;
17768 		buflen = dtoh32(bi->length);
17769 		if (unlikely(buflen > WL_BSS_INFO_MAX)) {
17770 			WL_DBG(("Beacon is larger than buffer. Discarding\n"));
17771 			err = -EINVAL;
17772 			goto exit;
17773 		}
17774 
17775 		/* Update sub-header */
17776 		bzero(&info, sizeof(wl_cfg80211_dev_info_t));
17777 		chspec = wl_chspec_driver_to_host(bi->chanspec);
17778 		channel = wf_chspec_ctlchan(chspec);
17779 		info.freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chspec));
17780 		info.rssi = wl_rssi_offset(dtoh16(bi->RSSI));
17781 		memcpy(info.bssid, &bi->BSSID, ETH_ALEN);
17782 		info.ie_len = buflen;
17783 
17784 		WL_SD(("DEV_FOUND band:%x Freq:%d rssi:%x "MACDBG" \n",
17785 			info.band, info.freq, info.rssi, MAC2STRDBG(info.bssid)));
17786 
17787 		buf =  ((u8 *) bi) + bi->ie_offset;
17788 		err = wl_genl_send_msg(ndev, event, buf,
17789 			buflen, (u8 *)&info, sizeof(wl_cfg80211_dev_info_t));
17790 	}
17791 exit:
17792 	mutex_unlock(&cfg->usr_sync);
17793 	return err;
17794 }
17795 
17796 s32
wl_cfg80211_sdo_init(struct bcm_cfg80211 * cfg)17797 wl_cfg80211_sdo_init(struct bcm_cfg80211 *cfg)
17798 {
17799 	if (cfg->sdo) {
17800 		WL_SD(("SDO already initialized\n"));
17801 		return 0;
17802 	}
17803 
17804 	cfg->sdo = (sd_offload_t *)MALLOCZ(cfg->osh, sizeof(sd_offload_t));
17805 	if (!cfg->sdo) {
17806 		WL_ERR(("MALLOCZ failed for SDO \n"));
17807 		return -ENOMEM;
17808 	}
17809 
17810 	return  0;
17811 }
17812 
17813 s32
wl_cfg80211_sdo_deinit(struct bcm_cfg80211 * cfg)17814 wl_cfg80211_sdo_deinit(struct bcm_cfg80211 *cfg)
17815 {
17816 	s32 bssidx;
17817 	int ret = 0;
17818 	int sdo_pause = 0;
17819 	if (!cfg || !cfg->p2p) {
17820 		WL_ERR(("Wl %p or cfg->p2p %p is null\n",
17821 			cfg, cfg ? cfg->p2p : 0));
17822 		return 0;
17823 	}
17824 
17825 	bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
17826 	if (!cfg->sdo) {
17827 		WL_DBG(("SDO Not Initialized. Do nothing. \n"));
17828 		return 0;
17829 	}
17830 	if (cfg->sdo->dd_state &&
17831 		(ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
17832 		"p2po_stop", (void*)&sdo_pause, sizeof(sdo_pause),
17833 		cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) {
17834 		WL_ERR(("p2po_stop Failed :%d\n", ret));
17835 	}
17836 	MFREE(cfg->osh, cfg->sdo, sizeof(sd_offload_t));
17837 
17838 	WL_SD(("SDO Deinit Done \n"));
17839 
17840 	return  0;
17841 }
17842 
17843 s32
wl_cfg80211_resume_sdo(struct net_device * dev,struct bcm_cfg80211 * cfg)17844 wl_cfg80211_resume_sdo(struct net_device *dev, struct bcm_cfg80211 *cfg)
17845 {
17846 	wl_sd_listen_t sd_listen;
17847 	int ret = 0;
17848 	s32 bssidx =  wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
17849 
17850 	WL_DBG(("Enter\n"));
17851 
17852 	if (!cfg->sdo) {
17853 		return -EINVAL;
17854 	}
17855 
17856 	if (dev == NULL)
17857 		dev = bcmcfg_to_prmry_ndev(cfg);
17858 
17859 	/* Disable back the ESCAN events for the offload */
17860 	wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, false);
17861 
17862 	/* Resume according to the saved state */
17863 	if (cfg->sdo->dd_state == WL_DD_STATE_SEARCH) {
17864 		if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_find", NULL, 0,
17865 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) {
17866 			WL_ERR(("p2po_find Failed :%d\n", ret));
17867 		}
17868 	} else if (cfg->sdo->dd_state == WL_DD_STATE_LISTEN) {
17869 		/* Need to save the listen params in the set context
17870 		 * so that those values can be restored in the resume context
17871 		 */
17872 		sd_listen.interval = cfg->sdo->sd_listen.interval;
17873 		sd_listen.period = cfg->sdo->sd_listen.period;
17874 
17875 		if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&sd_listen,
17876 			sizeof(wl_sd_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
17877 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
17878 			WL_ERR(("p2po_listen Failed :%d\n", ret));
17879 		}
17880 
17881 	}
17882 
17883 	 /* p2po_stop clears of the eventmask for GAS. Set it back */
17884 	 wl_add_remove_eventmsg(dev, WLC_E_SERVICE_FOUND, true);
17885 	 wl_add_remove_eventmsg(dev, WLC_E_GAS_FRAGMENT_RX, true);
17886 	 wl_add_remove_eventmsg(dev, WLC_E_GAS_COMPLETE, true);
17887 
17888 	WL_SD(("SDO Resumed \n"));
17889 
17890 	return ret;
17891 }
17892 
wl_cfg80211_pause_sdo(struct net_device * dev,struct bcm_cfg80211 * cfg)17893 s32 wl_cfg80211_pause_sdo(struct net_device *dev, struct bcm_cfg80211 *cfg)
17894 {
17895 
17896 	int ret = 0;
17897 	s32 bssidx =  wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
17898 	int sdo_pause = 1;
17899 
17900 	WL_DBG(("Enter \n"));
17901 
17902 	if (!cfg->sdo) {
17903 		WL_ERR(("SDO not initialized \n"));
17904 		return -EINVAL;
17905 	}
17906 
17907 	if (dev == NULL)
17908 		dev = bcmcfg_to_prmry_ndev(cfg);
17909 
17910 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop",
17911 		(void*)&sdo_pause, sizeof(sdo_pause),
17912 		cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) {
17913 		WL_ERR(("p2po_stop Failed :%d\n", ret));
17914 	}
17915 
17916 	/* Enable back the ESCAN events for the SCAN */
17917 	wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, true);
17918 
17919 	WL_SD(("SDO Paused \n"));
17920 
17921 	return ret;
17922 }
17923 
17924 static s32
wl_svc_resp_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)17925 wl_svc_resp_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17926 	const wl_event_msg_t *e, void *data)
17927 {
17928 	u32 event = ntoh32(e->event_type);
17929 	struct net_device *ndev = NULL;
17930 	const u8 *dst_mac = (const u8 *)e->addr.octet;
17931 	int ret = 0;
17932 	wl_event_sd_t *gas = NULL;
17933 	int status = ntoh32(e->status);
17934 	sdo_event_t sdo_hdr;
17935 	u32 data_len = ntoh32(e->datalen);
17936 	u8 *data_ptr = NULL;
17937 	u32 tot_len = 0;
17938 
17939 	WL_SD(("Enter event_type:%d status:%d\n", event, status));
17940 
17941 	if (!cfg->sdo) {
17942 		WL_ERR(("SDO Not initialized \n"));
17943 		return -EINVAL;
17944 	}
17945 
17946 	if (!(cfg->sdo->sd_state & WL_SD_SEARCH_SVC)) {
17947 		/* We are not searching for any service. Drop
17948 		 * any bogus Event
17949 		 */
17950 		WL_ERR(("Bogus SDO Event. Do nothing.. \n"));
17951 		return -1;
17952 	}
17953 
17954 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17955 
17956 	mutex_lock(&cfg->usr_sync);
17957 	if (event == WLC_E_SERVICE_FOUND) {
17958 
17959 		if ((status != WLC_E_STATUS_SUCCESS) && (status != WLC_E_STATUS_PARTIAL)) {
17960 			WL_ERR(("WLC_E_SERVICE_FOUND: unknown status \n"));
17961 			goto exit;
17962 		}
17963 
17964 		gas = (wl_event_sd_t *)data;
17965 		if (!gas) {
17966 			ret = -EINVAL;
17967 			goto exit;
17968 		}
17969 
17970 		bzero(&sdo_hdr, sizeof(sdo_event_t));
17971 		sdo_hdr.freq = wl_channel_to_frequency(gas->channel, WL_CHANSPEC_BAND_2G);
17972 		sdo_hdr.count = gas->count;
17973 		memcpy(sdo_hdr.addr, dst_mac, ETH_ALEN);
17974 		data_ptr = (char *)gas->tlv;
17975 		tot_len = data_len - (sizeof(wl_event_sd_t) - sizeof(wl_sd_tlv_t));
17976 
17977 		WL_SD(("WLC_E_SERVICE_FOUND "MACDBG" data_len:%d tlv_count:%d \n",
17978 			MAC2STRDBG(dst_mac), data_len, sdo_hdr.count));
17979 
17980 		if (tot_len > NLMSG_DEFAULT_SIZE) {
17981 			WL_ERR(("size(%u)  > %lu not supported \n", tot_len, NLMSG_DEFAULT_SIZE));
17982 			ret = -ENOMEM;
17983 			goto exit;
17984 		}
17985 
17986 		if (wl_genl_send_msg(ndev, event, data_ptr,
17987 			tot_len, (u8 *)&sdo_hdr, sizeof(sdo_event_t)) < 0)
17988 			WL_ERR(("Couldn't send up the NETLINK Event \n"));
17989 		else
17990 			WL_SD(("GAS event sent up \n"));
17991 	} else {
17992 		WL_ERR(("Unsupported Event: %d \n", event));
17993 	}
17994 
17995 exit:
17996 	mutex_unlock(&cfg->usr_sync);
17997 	return ret;
17998 }
17999 
wl_cfg80211_DsdOffloadParseProto(char * proto_str,u8 * proto)18000 s32 wl_cfg80211_DsdOffloadParseProto(char* proto_str, u8* proto)
18001 {
18002 	s32 len = -1;
18003 	int i = 0;
18004 
18005 	for (i = 0; i < MAX_SDO_PROTO; i++) {
18006 		if (strncmp(proto_str, wl_sdo_protos[i].str, strlen(wl_sdo_protos[i].str)) == 0) {
18007 			WL_SD(("Matching proto (%d) found \n", wl_sdo_protos[i].val));
18008 			*proto = wl_sdo_protos[i].val;
18009 			len = strlen(wl_sdo_protos[i].str);
18010 			break;
18011 		}
18012 	}
18013 	return len;
18014 }
18015 
18016 /*
18017  * register to search for a UPnP service
18018  * ./DRIVER P2P_SD_REQ upnp 0x10urn:schemas-upnporg:device:InternetGatewayDevice:1
18019  *
18020  * Enable discovery
18021  * ./cfg p2po_find
18022 */
18023 #define UPNP_QUERY_VER_OFFSET 3
wl_sd_handle_sd_req(struct net_device * dev,u8 * buf,int len)18024 s32 wl_sd_handle_sd_req(
18025 	struct net_device *dev,
18026 	u8 * buf,
18027 	int len)
18028 {
18029 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18030 	s32 bssidx = 0;
18031 	wl_sd_qr_t *sdreq;
18032 	u8 proto = 0;
18033 	s32 ret = 0;
18034 	u32 tot_len = len + sizeof(wl_sd_qr_t);
18035 	u16 version = 0;
18036 
18037 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
18038 		WL_ERR(("find_idx failed\n"));
18039 		return -EINVAL;
18040 	}
18041 	/* Check for the least arg length expected */
18042 	if (!buf || (len < strlen("all"))) {
18043 		WL_ERR(("Wrong Arg\n"));
18044 		return -EINVAL;
18045 	}
18046 
18047 	if (tot_len > WLC_IOCTL_MAXLEN) {
18048 		WL_ERR(("Length > %lu not supported \n", MAX_QR_LEN));
18049 		return -EINVAL;
18050 	}
18051 
18052 	sdreq = (wl_sd_qr_t *)MALLOCZ(cfg->osh, tot_len);
18053 	if (!sdreq) {
18054 		WL_ERR(("MALLOCZ failed\n"));
18055 		return -ENOMEM;
18056 	}
18057 
18058 	WL_SD(("%s Len: %d\n", buf, len));
18059 	if ((ret = wl_cfg80211_DsdOffloadParseProto(buf, &proto)) < 0) {
18060 		WL_ERR(("Unknown proto \n"));
18061 		goto exit;
18062 	}
18063 
18064 	sdreq->protocol = proto;
18065 	buf += ret;
18066 	buf++; /* skip the space */
18067 	sdreq->transaction_id = simple_strtoul(buf, NULL, 16);
18068 	WL_SD(("transaction_id:%d\n", sdreq->transaction_id));
18069 	buf += sizeof(sdreq->transaction_id);
18070 
18071 	if (*buf == '\0') {
18072 		WL_SD(("No Query present. Proto:%d \n", proto));
18073 		sdreq->query_len = 0;
18074 	} else {
18075 		buf++; /* skip the space */
18076 		/* UPNP version needs to put as binary val */
18077 		if (sdreq->protocol == SVC_RPOTYPE_UPNP) {
18078 			/* Extract UPNP version */
18079 			version = simple_strtoul(buf, NULL, 16);
18080 			buf = buf + UPNP_QUERY_VER_OFFSET;
18081 			buf[0] = version;
18082 			WL_SD(("Upnp version: 0x%x \n", version));
18083 		}
18084 
18085 		len = strlen(buf);
18086 		WL_SD(("Len after stripping proto: %d Query: %s\n", len, buf));
18087 		/* copy the query part */
18088 		memcpy(sdreq->qrbuf, buf, len);
18089 		sdreq->query_len = len;
18090 	}
18091 
18092 	/* Enable discovery */
18093 	if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
18094 		WL_ERR(("cfgp2p_enable discovery failed"));
18095 		goto exit;
18096 	}
18097 
18098 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_sd_req_resp", (void*)sdreq,
18099 		tot_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
18100 		bssidx, &cfg->ioctl_buf_sync)) < 0) {
18101 		WL_ERR(("Find SVC Failed \n"));
18102 		goto exit;
18103 	}
18104 
18105 	cfg->sdo->sd_state |= WL_SD_SEARCH_SVC;
18106 
18107 exit:
18108 	MFREE(cfg->osh, sdreq, tot_len);
18109 	return ret;
18110 }
18111 
wl_sd_handle_sd_cancel_req(struct net_device * dev,u8 * buf)18112 s32 wl_sd_handle_sd_cancel_req(
18113 	struct net_device *dev,
18114 	u8 *buf)
18115 {
18116 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18117 	s32 bssidx =  wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18118 
18119 	if (wldev_iovar_setbuf_bsscfg(dev, "p2po_sd_cancel", NULL,
18120 		0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18121 		bssidx, &cfg->ioctl_buf_sync) < 0) {
18122 		WL_ERR(("Cancel SD Failed \n"));
18123 		return -EINVAL;
18124 	}
18125 
18126 	cfg->sdo->sd_state &= ~WL_SD_SEARCH_SVC;
18127 
18128 	return 0;
18129 }
18130 
18131 /*
18132  * register a UPnP service to be discovered
18133  * ./cfg P2P_SD_SVC_ADD upnp 0x10urn:schemas-upnporg:device:InternetGatewayDevice:1 0x10uu
18134  * id:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnporg:device:InternetGate
18135  * wayDevice:1
18136 */
wl_sd_handle_sd_add_svc(struct net_device * dev,u8 * buf,int len)18137 s32 wl_sd_handle_sd_add_svc(
18138 	struct net_device *dev,
18139 	u8 * buf,
18140 	int len)
18141 {
18142 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18143 	s32 bssidx = 0;
18144 	wl_sd_qr_t *sdreq;
18145 	u8 proto = 0;
18146 	u16 version = 0;
18147 	s32 ret = 0;
18148 	u8 *resp = NULL;
18149 	u8 *query = NULL;
18150 	u32 tot_len = len + sizeof(wl_sd_qr_t);
18151 
18152 	if (!buf || !len)
18153 		return -EINVAL;
18154 
18155 	WL_SD(("%s Len: %d\n", buf, len));
18156 	if (tot_len > WLC_IOCTL_MAXLEN) {
18157 		WL_ERR(("Query-Resp length > %d not supported \n", WLC_IOCTL_MAXLEN));
18158 		return -ENOMEM;
18159 	}
18160 
18161 	sdreq = (wl_sd_qr_t *)MALLOCZ(cfg->osh, tot_len);
18162 	if (!sdreq) {
18163 		WL_ERR(("malloc failed\n"));
18164 		return -ENOMEM;
18165 	}
18166 
18167 	if ((ret = wl_cfg80211_DsdOffloadParseProto(buf, &proto)) < 0) {
18168 		WL_ERR(("Unknown Proto \n"));
18169 		goto exit;
18170 	}
18171 
18172 	sdreq->protocol = proto;
18173 	buf += ret;
18174 
18175 	if (*buf == '\0') {
18176 		WL_ERR(("No Query Resp pair present \n"));
18177 		ret = -EINVAL;
18178 		goto exit;
18179 	}
18180 
18181 	buf++; /* Skip the space */
18182 	len = strlen(buf);
18183 	query = strsep((char **)&buf, " ");
18184 	if (!query || !buf) {
18185 		WL_ERR(("No Query RESP Present\n"));
18186 		ret = -EINVAL;
18187 		goto exit;
18188 	}
18189 	resp = buf;
18190 
18191 	if (sdreq->protocol == SVC_RPOTYPE_UPNP) {
18192 		/* Extract UPNP version */
18193 		version = simple_strtoul(query, NULL, 16);
18194 		query = query + UPNP_QUERY_VER_OFFSET;
18195 		resp = resp + UPNP_QUERY_VER_OFFSET;
18196 		query[0] = version;
18197 		resp[0] = version;
18198 		WL_SD(("Upnp version: 0x%x \n", version));
18199 	}
18200 
18201 	sdreq->query_len = strlen(query);
18202 	sdreq->response_len = strlen(buf);
18203 	WL_SD(("query:%s len:%u \n", query, sdreq->query_len));
18204 	WL_SD(("resp:%s len:%u \n", buf, sdreq->response_len));
18205 
18206 	memcpy(sdreq->qrbuf, query, sdreq->query_len);
18207 	memcpy((sdreq->qrbuf + sdreq->query_len), resp, sdreq->response_len);
18208 
18209 	/* Enable discovery */
18210 	if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
18211 		WL_ERR(("cfgp2p_enable discovery failed"));
18212 		goto exit;
18213 	}
18214 
18215 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_addsvc", (void*)sdreq,
18216 		tot_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
18217 		bssidx, &cfg->ioctl_buf_sync)) < 0) {
18218 		WL_ERR(("FW Failed in doing p2po_addsvc. RET:%d \n", ret));
18219 		goto exit;
18220 	}
18221 
18222 	cfg->sdo->sd_state |= WL_SD_ADV_SVC;
18223 
18224 exit:
18225 	MFREE(cfg->osh, sdreq, tot_len);
18226 	return ret;
18227 }
18228 
wl_sd_handle_sd_del_svc(struct net_device * dev,u8 * buf,int len)18229 s32 wl_sd_handle_sd_del_svc(
18230 	struct net_device *dev,
18231 	u8 * buf,
18232 	int len)
18233 {
18234 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18235 	s32 bssidx = 0;
18236 	wl_sd_qr_t *sdreq;
18237 	u8 proto = 0;
18238 	s32 ret = 0;
18239 	u32 tot_len = len + sizeof(wl_sd_qr_t);
18240 	u16 version = 0;
18241 
18242 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
18243 		WL_ERR(("find_idx failed\n"));
18244 		return -EINVAL;
18245 	}
18246 
18247 	sdreq = (wl_sd_qr_t *)MALLOCZ(cfg->osh, tot_len);
18248 	if (!sdreq) {
18249 		WL_ERR(("malloc failed\n"));
18250 		ret = -ENOMEM;
18251 		goto exit;
18252 	}
18253 
18254 	/* Check for the least arg length expected */
18255 	if (buf && len >= strlen("all")) {
18256 		WL_DBG(("%s Len: %d\n", buf, len));
18257 		if ((ret = wl_cfg80211_DsdOffloadParseProto(buf, &proto)) < 0) {
18258 			WL_ERR(("Unknown Proto \n"));
18259 			goto exit;
18260 		}
18261 		sdreq->protocol = proto;
18262 		buf += ret;
18263 
18264 		if (*buf == ' ') {
18265 			/* Query present */
18266 			buf++; /* Skip the space */
18267 			/* UPNP version needs to put as binary val */
18268 			if (sdreq->protocol == SVC_RPOTYPE_UPNP) {
18269 				/* Extract UPNP version */
18270 				version = simple_strtoul(buf, NULL, 16);
18271 				buf = buf + UPNP_QUERY_VER_OFFSET;
18272 				buf[0] = version;
18273 				WL_SD(("Upnp version: 0x%x \n", version));
18274 			}
18275 			memcpy(sdreq->qrbuf, buf, strlen(buf));
18276 			sdreq->query_len = strlen(buf);
18277 			WL_SD(("Query to be deleted:%s len:%d\n", buf, sdreq->query_len));
18278 		}
18279 	} else {
18280 		/* ALL */
18281 		proto = 0;
18282 	}
18283 
18284 	sdreq->protocol = proto;
18285 	WL_SD(("Proto: %d \n", proto));
18286 
18287 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_delsvc", (void*)sdreq,
18288 		tot_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
18289 		bssidx, &cfg->ioctl_buf_sync)) < 0) {
18290 		WL_ERR(("FW Failed in doing sd_delsvc. ret=%d \n", ret));
18291 		goto exit;
18292 	}
18293 
18294 	cfg->sdo->sd_state &= ~WL_SD_ADV_SVC;
18295 
18296 exit:
18297 	if (sdreq) {
18298 		MFREE(cfg->osh, sdreq, tot_len);
18299 	}
18300 
18301 	return ret;
18302 }
18303 
wl_sd_handle_sd_stop_discovery(struct net_device * dev,u8 * buf,int len)18304 s32 wl_sd_handle_sd_stop_discovery(
18305 	struct net_device *dev,
18306 	u8 * buf,
18307 	int len)
18308 {
18309 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18310 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18311 	int ret = 0;
18312 	int sdo_pause = 0;
18313 
18314 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", (void*)&sdo_pause,
18315 		sizeof(sdo_pause), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18316 		bssidx, &cfg->ioctl_buf_sync)) < 0) {
18317 		WL_ERR(("p2po_stop Failed :%d\n", ret));
18318 		return -1;
18319 	}
18320 
18321 	/* clear the states */
18322 	cfg->sdo->dd_state = WL_DD_STATE_IDLE;
18323 	wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
18324 
18325 	bzero(&cfg->sdo->sd_listen, sizeof(wl_sd_listen_t));
18326 
18327 	/* Remove ESCAN from waking up the host if ofind/olisten is enabled */
18328 	wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, true);
18329 
18330 	return ret;
18331 }
18332 
wl_sd_handle_sd_find(struct net_device * dev,u8 * buf,int len)18333 s32 wl_sd_handle_sd_find(
18334 	struct net_device *dev,
18335 	u8 * buf,
18336 	int len)
18337 {
18338 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18339 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18340 	int ret = 0;
18341 	s32 disc_bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18342 	vndr_ie_setbuf_t *ie_setbuf;
18343 	vndr_ie_t *vndrie;
18344 	vndr_ie_buf_t *vndriebuf;
18345 	int tot_len = 0;
18346 	uint channel = 0;
18347 
18348 	u8 p2pie_buf[] = {
18349 				0x09, 0x02, 0x02, 0x00, 0x27, 0x0c, 0x06, 0x05, 0x00,
18350 				0x55, 0x53, 0x04, 0x51, 0x0b, 0x11, 0x05, 0x00, 0x55,
18351 				0x53, 0x04, 0x51, 0x0b
18352 			  };
18353 
18354 	/* Enable discovery */
18355 	if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
18356 		WL_ERR(("cfgp2p_enable discovery failed"));
18357 		return -1;
18358 	}
18359 
18360 	if (buf && strncmp(buf, "chan=", strlen("chan=")) == 0) {
18361 		buf += strlen("chan=");
18362 		channel = simple_strtol(buf, NULL, 10);
18363 		WL_SD(("listen_chan to be set:%d\n", channel));
18364 		if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
18365 			sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18366 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
18367 				WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
18368 				return -1;
18369 		}
18370 	}
18371 
18372 	tot_len = sizeof(vndr_ie_setbuf_t) + sizeof(p2pie_buf);
18373 	ie_setbuf = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
18374 	if (!ie_setbuf) {
18375 		WL_ERR(("IE memory alloc failed\n"));
18376 		return -ENOMEM;
18377 	}
18378 
18379 	/* Apply the p2p_ie for p2po_find */
18380 	strlcpy(ie_setbuf->cmd, "add", sizeof(ie_setbuf->cmd));
18381 
18382 	vndriebuf = &ie_setbuf->vndr_ie_buffer;
18383 	vndriebuf->iecount = htod32(1);
18384 	vndriebuf->vndr_ie_list[0].pktflag =  htod32(16);
18385 
18386 	vndrie =  &vndriebuf->vndr_ie_list[0].vndr_ie_data;
18387 
18388 	vndrie->id = (uchar) DOT11_MNG_PROPR_ID;
18389 	vndrie->len = sizeof(p2pie_buf);
18390 	memcpy(vndrie->oui, WFA_OUI, WFA_OUI_LEN);
18391 	memcpy(vndrie->data, p2pie_buf, sizeof(p2pie_buf));
18392 
18393 	/* Remove ESCAN from waking up the host if SDO is enabled */
18394 	wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, false);
18395 
18396 	if (wldev_iovar_setbuf_bsscfg(dev, "ie", (void*)ie_setbuf,
18397 		tot_len, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18398 		disc_bssidx, &cfg->ioctl_buf_sync) < 0) {
18399 		WL_ERR(("p2p add_ie failed \n"));
18400 		ret = -EINVAL;
18401 		goto exit;
18402 	} else
18403 		WL_SD(("p2p add_ie applied successfully len:%d \n", tot_len));
18404 
18405 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_find", NULL, 0,
18406 		cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) {
18407 		WL_ERR(("p2po_find Failed :%d\n", ret));
18408 		ret = -1;
18409 		goto exit;
18410 	}
18411 
18412 	/* set the states */
18413 	cfg->sdo->dd_state = WL_DD_STATE_SEARCH;
18414 	wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
18415 
18416 exit:
18417 	if (ie_setbuf) {
18418 		MFREE(cfg->osh, ie_setbuf, tot_len);
18419 	}
18420 
18421 	/* Incase of failure enable back the ESCAN event */
18422 	if (ret)
18423 		wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, true);
18424 
18425 	return ret;
18426 }
18427 
wl_sd_handle_sd_listen(struct net_device * dev,u8 * buf,int len)18428 s32 wl_sd_handle_sd_listen(
18429 	struct net_device *dev,
18430 	u8 *buf,
18431 	int len)
18432 {
18433 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18434 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18435 	wl_sd_listen_t sd_listen;
18436 	int ret = 0;
18437 	u8 * ptr = NULL;
18438 	uint channel = 0;
18439 
18440 	/* Just in case if it is not enabled */
18441 	if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
18442 		WL_ERR(("cfgp2p_enable discovery failed"));
18443 		return -1;
18444 	}
18445 	bzero(&sd_listen, sizeof(wl_sd_listen_t));
18446 	if (len) {
18447 		ptr = strsep((char **)&buf, " ");
18448 		if (ptr == NULL) {
18449 			/* period and duration given wrongly */
18450 			WL_ERR(("Arguments in wrong format \n"));
18451 			return -EINVAL;
18452 		}
18453 		else if (strncmp(ptr, "chan=", strlen("chan=")) == 0) {
18454 			sd_listen.interval = 65535;
18455 			sd_listen.period = 65535;
18456 			ptr += strlen("chan=");
18457 			channel = simple_strtol(ptr, NULL, 10);
18458 		}
18459 		else {
18460 			sd_listen.period = simple_strtol(ptr, NULL, 10);
18461 			ptr = strsep((char **)&buf, " ");
18462 			if (ptr == NULL) {
18463 				WL_ERR(("Arguments in wrong format \n"));
18464 				return -EINVAL;
18465 			}
18466 			sd_listen.interval = simple_strtol(ptr, NULL, 10);
18467 			if (buf && strncmp(buf, "chan=", strlen("chan=")) == 0) {
18468 				buf += strlen("chan=");
18469 				channel = simple_strtol(buf, NULL, 10);
18470 			}
18471 		}
18472 		WL_SD(("listen_period:%d, listen_interval:%d and listen_channel:%d\n",
18473 			sd_listen.period, sd_listen.interval, channel));
18474 	}
18475 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
18476 		sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18477 		bssidx, &cfg->ioctl_buf_sync)) < 0) {
18478 			WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
18479 			return -1;
18480 	}
18481 
18482 	WL_SD(("p2po_listen period:%d  interval:%d \n",
18483 		sd_listen.period, sd_listen.interval));
18484 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&sd_listen,
18485 		sizeof(wl_sd_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18486 		bssidx, &cfg->ioctl_buf_sync)) < 0) {
18487 		WL_ERR(("p2po_listen Failed :%d\n", ret));
18488 		return -1;
18489 	}
18490 
18491 	/* Remove ESCAN from waking up the host if ofind/olisten is enabled */
18492 	wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, false);
18493 
18494 	/* Store the extended listen values for use in sdo_resume */
18495 	cfg->sdo->sd_listen.interval = sd_listen.interval;
18496 	cfg->sdo->sd_listen.period = sd_listen.period;
18497 
18498 	/* set the states */
18499 	cfg->sdo->dd_state = WL_DD_STATE_LISTEN;
18500 	wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
18501 
18502 	return 0;
18503 }
18504 
wl_cfg80211_sd_offload(struct net_device * dev,char * cmd,char * buf,int len)18505 s32 wl_cfg80211_sd_offload(struct net_device *dev, char *cmd, char* buf, int len)
18506 {
18507 	int ret = 0;
18508 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18509 
18510 	WL_SD(("Entry cmd:%s arg_len:%d \n", cmd, len));
18511 
18512 	if (!cfg->sdo) {
18513 		WL_SD(("Initializing SDO \n"));
18514 		if ((ret = wl_cfg80211_sdo_init(cfg)) < 0)
18515 			goto exit;
18516 	}
18517 
18518 	if (strncmp(cmd, "P2P_SD_REQ", strlen("P2P_SD_REQ")) == 0) {
18519 		ret = wl_sd_handle_sd_req(dev, buf, len);
18520 	} else if (strncmp(cmd, "P2P_SD_CANCEL_REQ", strlen("P2P_SD_CANCEL_REQ")) == 0) {
18521 		ret = wl_sd_handle_sd_cancel_req(dev, buf);
18522 	} else if (strncmp(cmd, "P2P_SD_SVC_ADD", strlen("P2P_SD_SVC_ADD")) == 0) {
18523 		ret = wl_sd_handle_sd_add_svc(dev, buf, len);
18524 	} else if (strncmp(cmd, "P2P_SD_SVC_DEL", strlen("P2P_SD_SVC_DEL")) == 0) {
18525 		ret = wl_sd_handle_sd_del_svc(dev, buf, len);
18526 	} else if (strncmp(cmd, "P2P_SD_FIND", strlen("P2P_SD_FIND")) == 0) {
18527 		ret = wl_sd_handle_sd_find(dev, buf, len);
18528 	} else if (strncmp(cmd, "P2P_SD_LISTEN", strlen("P2P_SD_LISTEN")) == 0) {
18529 		ret = wl_sd_handle_sd_listen(dev, buf, len);
18530 	} else if (strncmp(cmd, "P2P_SD_STOP", strlen("P2P_STOP")) == 0) {
18531 		ret = wl_sd_handle_sd_stop_discovery(dev, buf, len);
18532 	} else {
18533 		WL_ERR(("Request for Unsupported CMD:%s \n", buf));
18534 		ret = -EINVAL;
18535 	}
18536 
18537 exit:
18538 	return ret;
18539 }
18540 #endif /* WL_SDO */
18541 
wl_cfg80211_set_wps_p2p_ie(struct net_device * ndev,char * buf,int len,enum wl_management_type type)18542 s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
18543 	enum wl_management_type type)
18544 {
18545 	struct bcm_cfg80211 *cfg;
18546 	s32 ret = 0;
18547 	s32 bssidx = 0;
18548 	s32 pktflag = 0;
18549 	struct wireless_dev *wdev = ndev->ieee80211_ptr;
18550 
18551 	cfg = wl_get_cfg(ndev);
18552 	if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
18553 		/* Vendor IEs should be set to FW
18554 		 * after SoftAP interface is brought up
18555 		 */
18556 		WL_DBG(("Skipping set IE since AP is not up \n"));
18557 		goto exit;
18558 	} else  if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
18559 		/* Either stand alone AP case or P2P discovery */
18560 		if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
18561 			/* Stand alone AP case on primary interface */
18562 			WL_DBG(("Apply IEs for Primary AP Interface \n"));
18563 			bssidx = 0;
18564 		} else {
18565 			if (!cfg->p2p) {
18566 				/* If p2p not initialized, return failure */
18567 				WL_ERR(("P2P not initialized \n"));
18568 				goto exit;
18569 			}
18570 			/* P2P Discovery case (p2p listen) */
18571 			if (!cfg->p2p->on) {
18572 				/* Turn on Discovery interface */
18573 				p2p_on(cfg) = true;
18574 				ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
18575 				if (unlikely(ret)) {
18576 					WL_ERR(("Enable discovery failed \n"));
18577 					goto exit;
18578 				}
18579 			}
18580 			ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
18581 			if (!cfg->p2p_wdev) {
18582 				WL_ERR(("p2p_wdev not present\n"));
18583 				goto exit;
18584 			}
18585 			wdev = cfg->p2p_wdev;
18586 			WL_DBG(("Apply IEs for P2P Discovery Iface wdev:%p\n", wdev));
18587 			bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18588 		}
18589 	} else {
18590 		/* Virtual AP/ P2P Group Interface */
18591 		WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
18592 		bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
18593 	}
18594 
18595 	if (wdev != NULL) {
18596 		switch (type) {
18597 			case WL_BEACON:
18598 				pktflag = VNDR_IE_BEACON_FLAG;
18599 				break;
18600 			case WL_PROBE_RESP:
18601 				pktflag = VNDR_IE_PRBRSP_FLAG;
18602 				break;
18603 			case WL_ASSOC_RESP:
18604 				pktflag = VNDR_IE_ASSOCRSP_FLAG;
18605 				break;
18606 		}
18607 		if (pktflag) {
18608 			ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
18609 				wdev_to_cfgdev(wdev), bssidx, pktflag, buf, len);
18610 		}
18611 	}
18612 exit:
18613 	return ret;
18614 }
18615 
18616 static const struct rfkill_ops wl_rfkill_ops = {
18617 	.set_block = wl_rfkill_set
18618 };
18619 
wl_rfkill_set(void * data,bool blocked)18620 static int wl_rfkill_set(void *data, bool blocked)
18621 {
18622 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
18623 
18624 	WL_DBG(("Enter \n"));
18625 	WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
18626 
18627 	if (!cfg)
18628 		return -EINVAL;
18629 
18630 	cfg->rf_blocked = blocked;
18631 
18632 	return 0;
18633 }
18634 
wl_setup_rfkill(struct bcm_cfg80211 * cfg,bool setup)18635 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
18636 {
18637 	s32 err = 0;
18638 
18639 	WL_DBG(("Enter \n"));
18640 	if (!cfg)
18641 		return -EINVAL;
18642 	if (setup) {
18643 		cfg->rfkill = rfkill_alloc("brcmfmac-wifi",
18644 			wl_cfg80211_get_parent_dev(),
18645 			RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
18646 
18647 		if (!cfg->rfkill) {
18648 			err = -ENOMEM;
18649 			goto err_out;
18650 		}
18651 
18652 		err = rfkill_register(cfg->rfkill);
18653 
18654 		if (err)
18655 			rfkill_destroy(cfg->rfkill);
18656 	} else {
18657 		if (!cfg->rfkill) {
18658 			err = -ENOMEM;
18659 			goto err_out;
18660 		}
18661 
18662 		rfkill_unregister(cfg->rfkill);
18663 		rfkill_destroy(cfg->rfkill);
18664 	}
18665 
18666 err_out:
18667 	return err;
18668 }
18669 
wl_cfg80211_get_bcmcfg(void)18670 struct bcm_cfg80211 *wl_cfg80211_get_bcmcfg(void)
18671 {
18672 	return g_bcmcfg;
18673 }
18674 
wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 * cfg)18675 void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 *cfg)
18676 {
18677 	g_bcmcfg = cfg;
18678 }
18679 
wl_cfg80211_get_parent_dev(void)18680 struct device *wl_cfg80211_get_parent_dev(void)
18681 {
18682 	return cfg80211_parent_dev;
18683 }
18684 
wl_cfg80211_set_parent_dev(void * dev)18685 void wl_cfg80211_set_parent_dev(void *dev)
18686 {
18687 	cfg80211_parent_dev = dev;
18688 }
18689 
wl_cfg80211_clear_parent_dev(void)18690 static void wl_cfg80211_clear_parent_dev(void)
18691 {
18692 	cfg80211_parent_dev = NULL;
18693 }
18694 
get_primary_mac(struct bcm_cfg80211 * cfg,struct ether_addr * mac)18695 void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
18696 {
18697 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
18698 
18699 	if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
18700 			"cur_etheraddr", NULL, 0, ioctl_buf, sizeof(ioctl_buf),
18701 			0, NULL) == BCME_OK) {
18702 		memcpy(mac->octet, ioctl_buf, ETHER_ADDR_LEN);
18703 	} else {
18704 		bzero(mac->octet, ETHER_ADDR_LEN);
18705 	}
18706 }
18707 
wl_cfg80211_do_driver_init(struct net_device * net)18708 int wl_cfg80211_do_driver_init(struct net_device *net)
18709 {
18710 	struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
18711 
18712 	if (!cfg || !cfg->wdev)
18713 		return -EINVAL;
18714 
18715 #if defined(BCMDONGLEHOST)
18716 	if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
18717 		return -1;
18718 #endif /* BCMDONGLEHOST */
18719 
18720 	return 0;
18721 }
18722 
wl_cfg80211_enable_trace(u32 level)18723 void wl_cfg80211_enable_trace(u32 level)
18724 {
18725 	wl_dbg_level = level;
18726 	WL_MSG("wlan", "wl_dbg_level = 0x%x\n", wl_dbg_level);
18727 }
18728 
18729 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
18730 static s32
wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u64 cookie)18731 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
18732 	bcm_struct_cfgdev *cfgdev, u64 cookie)
18733 {
18734 	/* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
18735 	 * is passed with CMD_FRAME. This callback is supposed to cancel
18736 	 * the OFFCHANNEL Wait. Since we are already taking care of that
18737 	 *  with the tx_mgmt logic, do nothing here.
18738 	 */
18739 
18740 	return 0;
18741 }
18742 #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
18743 
18744 #ifdef WL_HOST_BAND_MGMT
18745 s32
wl_cfg80211_set_band(struct net_device * ndev,int band)18746 wl_cfg80211_set_band(struct net_device *ndev, int band)
18747 {
18748 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18749 	int ret = 0;
18750 	char ioctl_buf[50];
18751 
18752 	if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
18753 		WL_ERR(("Invalid band\n"));
18754 		return -EINVAL;
18755 	}
18756 
18757 	if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band,
18758 		sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
18759 		WL_ERR(("seting roam_band failed code=%d\n", ret));
18760 		return ret;
18761 	}
18762 
18763 	WL_DBG(("Setting band to %d\n", band));
18764 	cfg->curr_band = band;
18765 
18766 	return 0;
18767 }
18768 #endif /* WL_HOST_BAND_MGMT */
18769 
18770 s32
wl_cfg80211_set_if_band(struct net_device * ndev,int band)18771 wl_cfg80211_set_if_band(struct net_device *ndev, int band)
18772 {
18773 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18774 	int ret = BCME_OK, wait_cnt;
18775 	char ioctl_buf[32];
18776 
18777 	if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
18778 		WL_ERR(("Invalid band\n"));
18779 		return -EINVAL;
18780 	}
18781 
18782 	if (cfg->ncho_band == band) {
18783 		WL_ERR(("Same to Current band %d\n", cfg->ncho_band));
18784 		return ret;
18785 	}
18786 
18787 	if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
18788 #ifdef BCMDONGLEHOST
18789 		dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
18790 		BCM_REFERENCE(dhdp);
18791 		DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
18792 			dhd_net2idx(dhdp->info, ndev), 0);
18793 #endif /* BCMDONGLEHOST */
18794 		ret = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
18795 		if (ret < 0) {
18796 			WL_ERR(("WLC_DISASSOC error %d\n", ret));
18797 			/* continue to set 'if_band' */
18798 		}
18799 		else {
18800 			/* This is to ensure that 'if_band' iovar is issued only after
18801 			* disconnection is completed
18802 			*/
18803 			wait_cnt = WAIT_FOR_DISCONNECT_MAX;
18804 			while (wl_get_drv_status(cfg, CONNECTED, ndev) && wait_cnt) {
18805 				WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt));
18806 				wait_cnt--;
18807 				OSL_SLEEP(50);
18808 			}
18809 		}
18810 	}
18811 	if ((ret = wldev_iovar_setbuf(ndev, "if_band", &band,
18812 			sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
18813 		WL_ERR(("seting if_band failed ret=%d\n", ret));
18814 		/* issue 'WLC_SET_BAND' if if_band is not supported */
18815 		if (ret == BCME_UNSUPPORTED) {
18816 			ret = wldev_set_band(ndev, band);
18817 			if (ret < 0) {
18818 				WL_ERR(("seting band failed ret=%d\n", ret));
18819 			}
18820 		}
18821 	}
18822 
18823 	if (ret == BCME_OK) {
18824 		cfg->ncho_band = band;
18825 	}
18826 	return ret;
18827 }
18828 
wl_cfg80211_is_concurrent_mode(struct net_device * dev)18829 bool wl_cfg80211_is_concurrent_mode(struct net_device *dev)
18830 {
18831 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18832 	if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
18833 		return true;
18834 	} else {
18835 		return false;
18836 	}
18837 }
18838 
18839 /*
18840  * This is to support existing btcoex implementation
18841  * btcoex clean up may help removing this function
18842  */
wl_cfg80211_get_dhdp(struct net_device * dev)18843 void* wl_cfg80211_get_dhdp(struct net_device *dev)
18844 {
18845 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18846 
18847 	return cfg->pub;
18848 }
18849 
wl_cfg80211_is_p2p_active(struct net_device * dev)18850 bool wl_cfg80211_is_p2p_active(struct net_device *dev)
18851 {
18852 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18853 	return (cfg && cfg->p2p);
18854 }
18855 
wl_cfg80211_is_roam_offload(struct net_device * dev)18856 bool wl_cfg80211_is_roam_offload(struct net_device * dev)
18857 {
18858 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18859 	return (cfg && cfg->roam_offload);
18860 }
18861 
wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev,const wl_event_msg_t * e,int ifidx)18862 bool wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev, const wl_event_msg_t *e,
18863 		int ifidx)
18864 {
18865 #ifdef BCMDONGLEHOST
18866 	u8 *curbssid = NULL;
18867 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18868 
18869 	if (!cfg) {
18870 		/* When interface is created using wl
18871 		 * ndev->ieee80211_ptr will be NULL.
18872 		 */
18873 		return NULL;
18874 	}
18875 	curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
18876 
18877 	if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
18878 		return true;
18879 	}
18880 #endif /* BCMDONGLEHOST */
18881 	return false;
18882 }
18883 
wl_cfg80211_work_handler(struct work_struct * work)18884 static void wl_cfg80211_work_handler(struct work_struct * work)
18885 {
18886 	struct bcm_cfg80211 *cfg = NULL;
18887 	struct net_info *iter, *next;
18888 	s32 err = BCME_OK;
18889 	s32 pm = PM_FAST;
18890 	dhd_pub_t *dhd;
18891 	BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
18892 	WL_DBG(("Enter \n"));
18893 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18894 	for_each_ndev(cfg, iter, next) {
18895 		GCC_DIAGNOSTIC_POP();
18896 		/* p2p discovery iface ndev could be null */
18897 		if (iter->ndev) {
18898 			if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
18899 				(wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
18900 				wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
18901 				continue;
18902 			if (iter->ndev) {
18903 				dhd = (dhd_pub_t *)(cfg->pub);
18904 				if (dhd_conf_get_pm(dhd) >= 0)
18905 					pm = dhd_conf_get_pm(dhd);
18906 				if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM,
18907 						&pm, sizeof(pm))) != 0) {
18908 					if (err == -ENODEV)
18909 						WL_DBG(("%s:netdev not ready\n",
18910 							iter->ndev->name));
18911 					else
18912 						WL_ERR(("%s:error (%d)\n",
18913 							iter->ndev->name, err));
18914 				} else
18915 					wl_cfg80211_update_power_mode(iter->ndev);
18916 			}
18917 		}
18918 	}
18919 
18920 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
18921 	DHD_PM_WAKE_UNLOCK(cfg->pub);
18922 #endif /* BCMDONGLEHOST && OEM_ANDROID */
18923 
18924 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
18925 	if (cfg->scan_suppressed) {
18926 		/* There is pending scan_suppress. Clean it */
18927 		WL_ERR(("Clean up from timer after %d msec\n", WL_SCAN_SUPPRESS_TIMEOUT));
18928 		wl_cfg80211_scan_suppress(bcmcfg_to_prmry_ndev(cfg), 0);
18929 	}
18930 #endif /* DHCP_SCAN_SUPPRESS */
18931 
18932 }
18933 
18934 u8
wl_get_action_category(void * frame,u32 frame_len)18935 wl_get_action_category(void *frame, u32 frame_len)
18936 {
18937 	u8 category;
18938 	u8 *ptr = (u8 *)frame;
18939 	if (frame == NULL)
18940 		return DOT11_ACTION_CAT_ERR_MASK;
18941 	if (frame_len < DOT11_ACTION_HDR_LEN)
18942 		return DOT11_ACTION_CAT_ERR_MASK;
18943 	category = ptr[DOT11_ACTION_CAT_OFF];
18944 	WL_DBG(("Action Category: %d\n", category));
18945 	return category;
18946 }
18947 
18948 int
wl_get_public_action(void * frame,u32 frame_len,u8 * ret_action)18949 wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
18950 {
18951 	u8 *ptr = (u8 *)frame;
18952 	if (frame == NULL || ret_action == NULL)
18953 		return BCME_ERROR;
18954 	if (frame_len < DOT11_ACTION_HDR_LEN)
18955 		return BCME_ERROR;
18956 	if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
18957 		return BCME_ERROR;
18958 	*ret_action = ptr[DOT11_ACTION_ACT_OFF];
18959 	WL_DBG(("Public Action : %d\n", *ret_action));
18960 	return BCME_OK;
18961 }
18962 
18963 #ifdef WLFBT
18964 int
wl_cfg80211_get_fbt_key(struct net_device * dev,uint8 * key,int total_len)18965 wl_cfg80211_get_fbt_key(struct net_device *dev, uint8 *key, int total_len)
18966 {
18967 	struct bcm_cfg80211 * cfg = wl_get_cfg(dev);
18968 	int bytes_written = -1;
18969 
18970 	if (total_len < FBT_KEYLEN) {
18971 		WL_ERR(("wl_cfg80211_get_fbt_key: Insufficient buffer \n"));
18972 		goto end;
18973 	}
18974 	if (cfg) {
18975 		memcpy(key, cfg->fbt_key, FBT_KEYLEN);
18976 		bytes_written = FBT_KEYLEN;
18977 	} else {
18978 		bzero(key, FBT_KEYLEN);
18979 		WL_ERR(("wl_cfg80211_get_fbt_key: Failed to copy KCK and KEK \n"));
18980 	}
18981 	prhex("KCK, KEK", (uchar *)key, FBT_KEYLEN);
18982 end:
18983 	return bytes_written;
18984 }
18985 #endif /* WLFBT */
18986 
18987 static int
wl_cfg80211_delayed_roam(struct bcm_cfg80211 * cfg,struct net_device * ndev,const struct ether_addr * bssid)18988 wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
18989 	const struct ether_addr *bssid)
18990 {
18991 	s32 err;
18992 	wl_event_msg_t e;
18993 
18994 	bzero(&e, sizeof(e));
18995 	e.event_type = cpu_to_be32(WLC_E_ROAM);
18996 	memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
18997 	/* trigger the roam event handler */
18998 	err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
18999 
19000 	return err;
19001 }
19002 
19003 static bool
wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t * vndrie)19004 wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t *vndrie)
19005 {
19006 	if (vndrie->oui[0] == FILS_EXTID_MNG_HLP_CONTAINER_ID) {
19007 		/* Skip adding fils HLP IE, its already done using
19008 		 * "WL_FILS_CMD_ADD_HLP_IE" subcmd.
19009 		 */
19010 		WL_DBG(("%s:SKIP ADDING FILS HLP EXTN ID\n", __func__));
19011 		return true;
19012 	}
19013 	return false;
19014 }
19015 
19016 static s32
wl_cfg80211_parse_vndr_ies(const u8 * parse,u32 len,struct parsed_vndr_ies * vndr_ies)19017 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
19018     struct parsed_vndr_ies *vndr_ies)
19019 {
19020 	s32 err = BCME_OK;
19021 	const vndr_ie_t *vndrie;
19022 	const bcm_tlv_t *ie;
19023 	struct parsed_vndr_ie_info *parsed_info;
19024 	u32 count = 0;
19025 	u32 remained_len;
19026 
19027 	remained_len = len;
19028 	bzero(vndr_ies, sizeof(*vndr_ies));
19029 
19030 	ie = (const bcm_tlv_t *) parse;
19031 	if (!bcm_valid_tlv(ie, remained_len))
19032 		ie = NULL;
19033 	while (ie) {
19034 		if (count >= MAX_VNDR_IE_NUMBER)
19035 			break;
19036 		if (ie->id == DOT11_MNG_VS_ID || (ie->id == DOT11_MNG_ID_EXT_ID)) {
19037 			vndrie = (const vndr_ie_t *) ie;
19038 			if (ie->id == DOT11_MNG_ID_EXT_ID) {
19039 				/* len should be bigger than sizeof ID extn field at least */
19040 				if (vndrie->len < MIN_VENDOR_EXTN_IE_LEN) {
19041 					WL_ERR(("%s: invalid vndr extn ie."
19042 						" length %d\n",
19043 						__FUNCTION__, vndrie->len));
19044 					goto end;
19045 				}
19046 				if (wl_cfg80211_filter_vndr_ext_id(vndrie)) {
19047 					goto end;
19048 				}
19049 			} else {
19050 				/* len should be bigger than OUI length +
19051 				 * one data length at least
19052 				 */
19053 				if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
19054 					WL_ERR(("wl_cfg80211_parse_vndr_ies:"
19055 						" invalid vndr ie. length is too small %d\n",
19056 						vndrie->len));
19057 					goto end;
19058 				}
19059 
19060 				/* if wpa or wme ie, do not add ie */
19061 				if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
19062 						((vndrie->data[0] == WPA_OUI_TYPE) ||
19063 						(vndrie->data[0] == WME_OUI_TYPE))) {
19064 					CFGP2P_DBG(("SKIP WPA/WME oui \n"));
19065 					goto end;
19066 				}
19067 #if defined(WL_MBO) || defined(WL_OCE)
19068 				if ((!memcmp(vndrie->oui, (u8 *)WFA_OUI, WFA_OUI_LEN)) &&
19069 					(vndrie->data[0] == WFA_OUI_TYPE_MBO_OCE)) {
19070 					WL_DBG(("SKIP ID : %d Len: %d OUI:"MACOUIDBG
19071 						" TYPE:%0x\n", vndrie->id, vndrie->len,
19072 						MACOUI2STRDBG(vndrie->oui), vndrie->data[0]));
19073 					goto end;
19074 				}
19075 #endif /* WL_MBO || WL_OCE */
19076 			}
19077 
19078 			parsed_info = &vndr_ies->ie_info[count++];
19079 
19080 			/* save vndr ie information */
19081 			parsed_info->ie_ptr = (const char *)vndrie;
19082 			parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
19083 			memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
19084 			vndr_ies->count = count;
19085 			if (ie->id == DOT11_MNG_ID_EXT_ID) {
19086 				WL_DBG(("** Vendor Extension ie id: 0x%02x, len:%d\n",
19087 					ie->id, vndrie->len));
19088 			} else {
19089 				WL_DBG(("** OUI "MACOUIDBG", type 0x%02x len:%d\n",
19090 					MACOUI2STRDBG(parsed_info->vndrie.oui),
19091 					parsed_info->vndrie.data[0], vndrie->len));
19092 			}
19093 		}
19094 end:
19095 		ie = bcm_next_tlv(ie, &remained_len);
19096 	}
19097 	return err;
19098 }
19099 
19100 static bool
wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info * vndr_info)19101 wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info *vndr_info)
19102 {
19103 	int i = 0;
19104 
19105 	while (exclude_vndr_oui_list[i]) {
19106 		if (!memcmp(vndr_info->vndrie.oui,
19107 			exclude_vndr_oui_list[i],
19108 			DOT11_OUI_LEN)) {
19109 			return TRUE;
19110 		}
19111 		i++;
19112 	}
19113 
19114 	return FALSE;
19115 }
19116 
19117 static bool
wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)19118 wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 *cfg,
19119 		struct parsed_vndr_ie_info *vndr_info)
19120 {
19121 	wl_vndr_oui_entry_t *oui_entry = NULL;
19122 	unsigned long flags;
19123 
19124 	WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19125 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19126 	list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
19127 		GCC_DIAGNOSTIC_POP();
19128 		if (!memcmp(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN)) {
19129 			WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19130 			return TRUE;
19131 		}
19132 	}
19133 	WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19134 	return FALSE;
19135 }
19136 
19137 static bool
wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)19138 wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 *cfg,
19139 	struct parsed_vndr_ie_info *vndr_info)
19140 {
19141 	wl_vndr_oui_entry_t *oui_entry = NULL;
19142 	unsigned long flags;
19143 
19144 	oui_entry = kmalloc(sizeof(*oui_entry), GFP_KERNEL);
19145 	if (oui_entry == NULL) {
19146 		WL_ERR(("alloc failed\n"));
19147 		return FALSE;
19148 	}
19149 
19150 	memcpy(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN);
19151 
19152 	INIT_LIST_HEAD(&oui_entry->list);
19153 	WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19154 	list_add_tail(&oui_entry->list, &cfg->vndr_oui_list);
19155 	WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19156 
19157 	return TRUE;
19158 }
19159 
19160 static void
wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 * cfg)19161 wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg)
19162 {
19163 	wl_vndr_oui_entry_t *oui_entry = NULL;
19164 	unsigned long flags;
19165 
19166 	WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19167 	while (!list_empty(&cfg->vndr_oui_list)) {
19168 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19169 		oui_entry = list_entry(cfg->vndr_oui_list.next, wl_vndr_oui_entry_t, list);
19170 		GCC_DIAGNOSTIC_POP();
19171 		if (oui_entry) {
19172 			list_del(&oui_entry->list);
19173 			kfree(oui_entry);
19174 		}
19175 	}
19176 	WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19177 }
19178 
19179 static int
wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * vndr_oui,u32 vndr_oui_len)19180 wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
19181 	char *vndr_oui, u32 vndr_oui_len)
19182 {
19183 	int i;
19184 	int vndr_oui_num = 0;
19185 
19186 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
19187 	wl_vndr_oui_entry_t *oui_entry = NULL;
19188 	struct parsed_vndr_ie_info *vndr_info;
19189 	struct parsed_vndr_ies vndr_ies;
19190 
19191 	char *pos = vndr_oui;
19192 	u32 remained_buf_len = vndr_oui_len;
19193 	unsigned long flags;
19194 
19195 	if (!conn_info->resp_ie_len) {
19196 		return BCME_ERROR;
19197 	}
19198 
19199 	wl_vndr_ies_clear_vendor_oui_list(cfg);
19200 
19201 	if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
19202 		conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
19203 		for (i = 0; i < vndr_ies.count; i++) {
19204 			vndr_info = &vndr_ies.ie_info[i];
19205 			if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
19206 				continue;
19207 			}
19208 
19209 			if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
19210 				continue;
19211 			}
19212 
19213 			wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
19214 			vndr_oui_num++;
19215 		}
19216 	}
19217 
19218 	if (vndr_oui) {
19219 		WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19220 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19221 		list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
19222 			GCC_DIAGNOSTIC_POP();
19223 			if (remained_buf_len < VNDR_OUI_STR_LEN) {
19224 				WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19225 				return BCME_ERROR;
19226 			}
19227 			pos += snprintf(pos, VNDR_OUI_STR_LEN, "%02X-%02X-%02X ",
19228 				oui_entry->oui[0], oui_entry->oui[1], oui_entry->oui[2]);
19229 			remained_buf_len -= VNDR_OUI_STR_LEN;
19230 		}
19231 		WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19232 	}
19233 
19234 	return vndr_oui_num;
19235 }
19236 
19237 #ifdef WL_ANALYTICS
19238 static bool
wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211 * cfg,struct net_device * ndev,const char * vndr_oui)19239 wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
19240 	const char *vndr_oui)
19241 {
19242 	int i;
19243 	int vndr_oui_num = 0;
19244 
19245 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
19246 	wl_vndr_oui_entry_t *oui_entry = NULL;
19247 	struct parsed_vndr_ie_info *vndr_info;
19248 	struct parsed_vndr_ies vndr_ies;
19249 
19250 	unsigned long flags;
19251 	bool found = FALSE;
19252 
19253 	if (!conn_info->resp_ie_len) {
19254 		return FALSE;
19255 	}
19256 
19257 	wl_vndr_ies_clear_vendor_oui_list(cfg);
19258 
19259 	if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
19260 		conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
19261 		for (i = 0; i < vndr_ies.count; i++) {
19262 			vndr_info = &vndr_ies.ie_info[i];
19263 			if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
19264 				continue;
19265 			}
19266 
19267 			if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
19268 				continue;
19269 			}
19270 
19271 			wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
19272 			vndr_oui_num++;
19273 		}
19274 	}
19275 
19276 	if (vndr_oui && vndr_oui_num) {
19277 		WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19278 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19279 		list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
19280 			GCC_DIAGNOSTIC_POP();
19281 			if (!memcmp(vndr_oui, oui_entry->oui, DOT11_OUI_LEN)) {
19282 				found = TRUE;
19283 				break;
19284 			}
19285 		}
19286 		WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19287 	}
19288 
19289 	return found;
19290 }
19291 #endif /* WL_ANALYTICS */
19292 
19293 void
wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 * cfg)19294 wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 *cfg)
19295 {
19296 #ifdef WL_CFG80211_P2P_DEV_IF
19297 	if (cfg->p2p_wdev) {
19298 		/* clear IEs for dedicated p2p interface */
19299 		WL_DBG_MEM(("Clear IEs for P2P Discovery Iface\n"));
19300 		wl_cfg80211_clear_per_bss_ies(cfg, cfg->p2p_wdev);
19301 	}
19302 #else
19303 	/* Legacy P2P used to store it in primary dev cache */
19304 	s32 index;
19305 	struct net_device *ndev;
19306 	s32 bssidx;
19307 	s32 ret;
19308 	s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
19309 		VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
19310 
19311 	WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
19312 	/* certain vendors uses p2p0 interface in addition to
19313 	 * the dedicated p2p interface supported by the linux
19314 	 * kernel.
19315 	 */
19316 	ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
19317 	bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
19318 	if (bssidx == WL_INVALID) {
19319 		WL_DBG(("No discovery I/F available. Do nothing.\n"));
19320 		return;
19321 	}
19322 
19323 	for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
19324 		if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
19325 			bssidx, vndrie_flag[index], NULL, 0)) < 0) {
19326 			if (ret != BCME_NOTFOUND) {
19327 				WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret));
19328 			}
19329 		}
19330 	}
19331 #endif /* WL_CFG80211_P2P_DEV_IF */
19332 }
19333 
19334 s32
wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev)19335 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
19336 {
19337 	s32 index;
19338 	s32 ret;
19339 	struct net_info *netinfo;
19340 	s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
19341 		VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
19342 
19343 	netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
19344 	if (!netinfo || !netinfo->wdev) {
19345 		WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
19346 		return -1;
19347 	}
19348 
19349 	WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo->bssidx));
19350 	/* Clear the IEs set in the firmware so that host is in sync with firmware */
19351 	for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
19352 		if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
19353 			netinfo->bssidx, vndrie_flag[index], NULL, 0)) < 0)
19354 			if (ret != BCME_NOTFOUND) {
19355 				WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
19356 			}
19357 	}
19358 
19359 	return 0;
19360 }
19361 
19362 s32
wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 * cfg)19363 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
19364 {
19365 	struct net_info *iter, *next;
19366 
19367 	WL_DBG(("clear management vendor IEs \n"));
19368 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19369 	for_each_ndev(cfg, iter, next) {
19370 		GCC_DIAGNOSTIC_POP();
19371 		wl_cfg80211_clear_per_bss_ies(cfg, iter->wdev);
19372 	}
19373 	return 0;
19374 }
19375 
19376 static void
wl_print_fw_ie_data(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bssidx)19377 wl_print_fw_ie_data(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx)
19378 {
19379 	vndr_ie_buf_t *ies;
19380 	s32 ret;
19381 
19382 	ret  = wldev_iovar_getbuf_bsscfg(ndev, "vndr_ie", NULL,
19383 		0, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
19384 		bssidx, &cfg->ioctl_buf_sync);
19385 	if (ret == BCME_OK) {
19386 		ies = (vndr_ie_buf_t *)cfg->ioctl_buf;
19387 		WL_INFORM_MEM(("FW IE count:%d ", ies->iecount));
19388 #ifdef GET_FW_IE_DATA
19389 		if (wl_dbg_level & WL_DBG_DBG) {
19390 			int i = 0;
19391 			/* If debug enabled, print each IE */
19392 			for (i = 0; i < ies->iecount; i++) {
19393 				vndr_ie_info_t *info = &ies->vndr_ie_list[i];
19394 				WL_DBG_MEM(("pktflag:0x%x\n", info->pktflag));
19395 					prhex("IE:", (u8 *)&info->vndr_ie_data,
19396 						info->vndr_ie_data.len + TLV_HDR_LEN);
19397 			}
19398 		}
19399 #endif /* GET_FW_IE_DATA */
19400 	} else {
19401 		WL_ERR(("IE retrieval failed! ret:%d\n", ret));
19402 	}
19403 }
19404 
19405 #define WL_VNDR_IE_MAXLEN 2048
19406 static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
19407 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)19408 wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
19409 	s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
19410 {
19411 	struct net_device *ndev = NULL;
19412 	s32 ret = BCME_OK;
19413 	u8  *curr_ie_buf = NULL;
19414 	u8  *mgmt_ie_buf = NULL;
19415 	u32 mgmt_ie_buf_len = 0;
19416 	u32 *mgmt_ie_len = 0;
19417 	u32 del_add_ie_buf_len = 0;
19418 	u32 total_ie_buf_len = 0;
19419 	u32 parsed_ie_buf_len = 0;
19420 	struct parsed_vndr_ies old_vndr_ies;
19421 	struct parsed_vndr_ies new_vndr_ies;
19422 	s32 i;
19423 	u8 *ptr;
19424 	s32 remained_buf_len;
19425 	wl_bss_vndr_ies_t *ies = NULL;
19426 	struct net_info *netinfo;
19427 	struct wireless_dev *wdev;
19428 
19429 	if (!cfgdev) {
19430 		WL_ERR(("cfgdev is NULL\n"));
19431 		return -EINVAL;
19432 	}
19433 
19434 	ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
19435 	wdev = cfgdev_to_wdev(cfgdev);
19436 
19437 	if (bssidx > WL_MAX_IFS) {
19438 		WL_ERR(("bssidx > supported concurrent Ifaces \n"));
19439 		return -EINVAL;
19440 	}
19441 
19442 	netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
19443 	if (!netinfo) {
19444 		WL_ERR(("net_info ptr is NULL \n"));
19445 		return -EINVAL;
19446 	}
19447 
19448 	/* Clear the global buffer */
19449 	bzero(g_mgmt_ie_buf, sizeof(g_mgmt_ie_buf));
19450 	curr_ie_buf = g_mgmt_ie_buf;
19451 	ies = &netinfo->bss.ies;
19452 
19453 	WL_DBG_MEM(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d\n",
19454 		pktflag, bssidx, vndr_ie_len));
19455 
19456 	switch (pktflag) {
19457 		case VNDR_IE_PRBRSP_FLAG :
19458 			mgmt_ie_buf = ies->probe_res_ie;
19459 			mgmt_ie_len = &ies->probe_res_ie_len;
19460 			mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
19461 			break;
19462 		case VNDR_IE_ASSOCRSP_FLAG :
19463 			mgmt_ie_buf = ies->assoc_res_ie;
19464 			mgmt_ie_len = &ies->assoc_res_ie_len;
19465 			mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
19466 			break;
19467 		case VNDR_IE_BEACON_FLAG :
19468 			mgmt_ie_buf = ies->beacon_ie;
19469 			mgmt_ie_len = &ies->beacon_ie_len;
19470 			mgmt_ie_buf_len = sizeof(ies->beacon_ie);
19471 			break;
19472 		case VNDR_IE_PRBREQ_FLAG :
19473 			mgmt_ie_buf = ies->probe_req_ie;
19474 			mgmt_ie_len = &ies->probe_req_ie_len;
19475 			mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
19476 			break;
19477 		case VNDR_IE_ASSOCREQ_FLAG :
19478 			mgmt_ie_buf = ies->assoc_req_ie;
19479 			mgmt_ie_len = &ies->assoc_req_ie_len;
19480 			mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
19481 			break;
19482 		case VNDR_IE_DISASSOC_FLAG :
19483 			mgmt_ie_buf = ies->disassoc_ie;
19484 			mgmt_ie_len = &ies->disassoc_ie_len;
19485 			mgmt_ie_buf_len = sizeof(ies->disassoc_ie);
19486 			break;
19487 		default:
19488 			mgmt_ie_buf = NULL;
19489 			mgmt_ie_len = NULL;
19490 			WL_ERR(("not suitable packet type (%d)\n", pktflag));
19491 			return BCME_ERROR;
19492 	}
19493 
19494 	if (vndr_ie_len > mgmt_ie_buf_len) {
19495 		WL_ERR(("extra IE size too big\n"));
19496 		ret = -ENOMEM;
19497 	} else {
19498 		/* parse and save new vndr_ie in curr_ie_buff before comparing it */
19499 		if (vndr_ie && vndr_ie_len && curr_ie_buf) {
19500 			ptr = curr_ie_buf;
19501 
19502 			WL_DBG(("Incoming IEs len:%d\n", vndr_ie_len));
19503 			if ((ret = wl_cfg80211_parse_vndr_ies((const u8 *)vndr_ie,
19504 			                                      vndr_ie_len, &new_vndr_ies)) < 0) {
19505 				WL_ERR(("parse vndr ie failed \n"));
19506 				goto exit;
19507 			}
19508 
19509 			for (i = 0; i < new_vndr_ies.count; i++) {
19510 				struct parsed_vndr_ie_info *vndrie_info =
19511 					&new_vndr_ies.ie_info[i];
19512 
19513 				if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
19514 					WL_ERR(("IE size is too big (%d > %d)\n",
19515 						parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
19516 					ret = -EINVAL;
19517 					goto exit;
19518 				}
19519 
19520 				memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
19521 					vndrie_info->ie_len);
19522 				parsed_ie_buf_len += vndrie_info->ie_len;
19523 			}
19524 		}
19525 
19526 		if (mgmt_ie_buf != NULL) {
19527 			if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
19528 				(memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
19529 				WL_DBG_MEM(("No change in cached IEs for pkt:%d\n", pktflag));
19530 				goto exit;
19531 			}
19532 
19533 			/* parse old vndr_ie */
19534 			WL_DBG(("Cached IEs len:%d\n", *mgmt_ie_len));
19535 			if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
19536 				&old_vndr_ies)) < 0) {
19537 				WL_ERR(("parse vndr ie failed \n"));
19538 				goto exit;
19539 			}
19540 			/* make a command to delete old ie */
19541 			for (i = 0; i < old_vndr_ies.count; i++) {
19542 				struct parsed_vndr_ie_info *vndrie_info =
19543 				&old_vndr_ies.ie_info[i];
19544 
19545 				if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
19546 					WL_DBG_MEM(("DEL VENDOR EXTN ID :%d TYPE:%d Len:%d\n",
19547 						vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
19548 						vndrie_info->vndrie.len));
19549 				} else {
19550 					WL_DBG_MEM(("DEL ID :%d Len:%d OUI:"MACOUIDBG" TYPE:%d\n",
19551 						vndrie_info->vndrie.id, vndrie_info->vndrie.len,
19552 						MACOUI2STRDBG(vndrie_info->vndrie.oui),
19553 						vndrie_info->vndrie.data[0]));
19554 				}
19555 
19556 				del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
19557 					pktflag, vndrie_info->vndrie.oui,
19558 					vndrie_info->vndrie.id,
19559 					vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
19560 					vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
19561 					"del");
19562 
19563 				curr_ie_buf += del_add_ie_buf_len;
19564 				total_ie_buf_len += del_add_ie_buf_len;
19565 			}
19566 		}
19567 
19568 		*mgmt_ie_len = 0;
19569 		/* Add if there is any extra IE */
19570 		if (mgmt_ie_buf && parsed_ie_buf_len) {
19571 			ptr = mgmt_ie_buf;
19572 
19573 			remained_buf_len = mgmt_ie_buf_len;
19574 			/* make a command to add new ie */
19575 			for (i = 0; i < new_vndr_ies.count; i++) {
19576 				struct parsed_vndr_ie_info *vndrie_info =
19577 					&new_vndr_ies.ie_info[i];
19578 				if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
19579 					WL_DBG_MEM(("ADD VENDOR EXTN ID :%d TYPE:%d Len:%d\n",
19580 						vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
19581 						vndrie_info->vndrie.len));
19582 				} else {
19583 					WL_DBG_MEM(("ADD ID :%d Len:%d OUI:"MACOUIDBG" TYPE:%d\n",
19584 						vndrie_info->vndrie.id, vndrie_info->vndrie.len,
19585 						MACOUI2STRDBG(vndrie_info->vndrie.oui),
19586 						vndrie_info->vndrie.data[0]));
19587 				}
19588 
19589 				del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
19590 					pktflag, vndrie_info->vndrie.oui,
19591 					vndrie_info->vndrie.id,
19592 					vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
19593 					vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
19594 					"add");
19595 
19596 				/* verify remained buf size before copy data */
19597 				if (remained_buf_len >= vndrie_info->ie_len) {
19598 					remained_buf_len -= vndrie_info->ie_len;
19599 				} else {
19600 					WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
19601 					"found vndr ies # = %d(cur %d), remained len %d, "
19602 					"cur mgmt_ie_len %d, new ie len = %d\n",
19603 					pktflag, new_vndr_ies.count, i, remained_buf_len,
19604 					*mgmt_ie_len, vndrie_info->ie_len));
19605 					break;
19606 				}
19607 
19608 				/* save the parsed IE in cfg struct */
19609 				memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
19610 					vndrie_info->ie_len);
19611 				*mgmt_ie_len += vndrie_info->ie_len;
19612 				curr_ie_buf += del_add_ie_buf_len;
19613 				total_ie_buf_len += del_add_ie_buf_len;
19614 			}
19615 		}
19616 
19617 		if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
19618 			ret  = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
19619 				total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
19620 				bssidx, &cfg->ioctl_buf_sync);
19621 			if (ret) {
19622 				WL_ERR(("vndr_ie set error :%d\n", ret));
19623 				if (ret == BCME_NOTFOUND) {
19624 					/* retrieve and print IE data for debug */
19625 					wl_print_fw_ie_data(cfg, ndev, bssidx);
19626 				}
19627 			}
19628 		}
19629 	}
19630 exit:
19631 
19632 return ret;
19633 }
19634 
wl_cfg80211_clear_security(struct bcm_cfg80211 * cfg)19635 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
19636 {
19637 	struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
19638 	int err;
19639 
19640 	/* Clear the security settings on the primary Interface */
19641 	err = wldev_iovar_setint(dev, "wsec", 0);
19642 	if (unlikely(err)) {
19643 		WL_ERR(("wsec clear failed \n"));
19644 	}
19645 	err = wldev_iovar_setint(dev, "auth", 0);
19646 	if (unlikely(err)) {
19647 		WL_ERR(("auth clear failed \n"));
19648 	}
19649 	err = wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
19650 	if (unlikely(err)) {
19651 		WL_ERR(("wpa_auth clear failed \n"));
19652 	}
19653 }
19654 
19655 #ifdef WL_CFG80211_P2P_DEV_IF
wl_cfg80211_del_p2p_wdev(struct net_device * dev)19656 void wl_cfg80211_del_p2p_wdev(struct net_device *dev)
19657 {
19658 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19659 	struct wireless_dev *wdev = NULL;
19660 
19661 	WL_DBG(("Enter \n"));
19662 	if (!cfg) {
19663 		WL_ERR(("Invalid Ptr\n"));
19664 		return;
19665 	} else {
19666 		wdev = cfg->p2p_wdev;
19667 	}
19668 
19669 	if (wdev) {
19670 		wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
19671 	}
19672 }
19673 #endif /* WL_CFG80211_P2P_DEV_IF */
19674 
19675 #ifdef GTK_OFFLOAD_SUPPORT
19676 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
19677 static s32
wl_cfg80211_set_rekey_data(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_gtk_rekey_data * data)19678 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
19679 		struct cfg80211_gtk_rekey_data *data)
19680 {
19681 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
19682 	s32 err = 0;
19683 	gtk_keyinfo_t keyinfo;
19684 	bcol_gtk_para_t bcol_keyinfo;
19685 
19686 	WL_DBG(("Enter\n"));
19687 	if (data == NULL || cfg->p2p_net == dev) {
19688 		WL_ERR(("data is NULL or wrong net device\n"));
19689 		return -EINVAL;
19690 	}
19691 
19692 	prhex("kck", (const u8 *) (data->kck), RSN_KCK_LENGTH);
19693 	prhex("kek", (const u8 *) (data->kek), RSN_KEK_LENGTH);
19694 	prhex("replay_ctr", (const u8 *) (data->replay_ctr), RSN_REPLAY_LEN);
19695 	bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH);
19696 	bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH);
19697 	bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN);
19698 
19699 	memset(&bcol_keyinfo, 0, sizeof(bcol_keyinfo));
19700 	bcol_keyinfo.enable = 1;
19701 	bcol_keyinfo.ptk_len = 64;
19702 	memcpy(&bcol_keyinfo.ptk[0], data->kck, RSN_KCK_LENGTH);
19703 	memcpy(&bcol_keyinfo.ptk[RSN_KCK_LENGTH], data->kek, RSN_KEK_LENGTH);
19704 	err = wldev_iovar_setbuf(dev, "bcol_gtk_rekey_ptk", &bcol_keyinfo,
19705 		sizeof(bcol_keyinfo), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
19706 	if (!err) {
19707 		return err;
19708 	}
19709 
19710 	if ((err = wldev_iovar_setbuf(dev, "gtk_key_info", &keyinfo, sizeof(keyinfo),
19711 		cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync)) < 0) {
19712 		WL_ERR(("seting gtk_key_info failed code=%d\n", err));
19713 		return err;
19714 	}
19715 
19716 	WL_DBG(("Exit\n"));
19717 	return err;
19718 }
19719 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
19720 #endif /* GTK_OFFLOAD_SUPPORT */
19721 
19722 #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)19723 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
19724 	const struct cfg80211_pmk_conf *conf)
19725 {
19726 	int ret = 0;
19727 	wsec_pmk_t pmk;
19728 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
19729 	struct wl_security *sec;
19730 	s32 bssidx;
19731 
19732 	pmk.key_len = conf->pmk_len;
19733 	if (pmk.key_len > sizeof(pmk.key)) {
19734 		ret = -EINVAL;
19735 		return ret;
19736 	}
19737 	pmk.flags = 0;
19738 	ret = memcpy_s(&pmk.key, sizeof(pmk.key), conf->pmk, conf->pmk_len);
19739 	if (ret) {
19740 		ret = -EINVAL;
19741 		return ret;
19742 	}
19743 
19744 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
19745 		WL_ERR(("Find index failed\n"));
19746 		ret = -EINVAL;
19747 		return ret;
19748 	}
19749 
19750 	sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
19751 	if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
19752 		(sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
19753 		ret = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len,
19754 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
19755 		if (ret) {
19756 			/* could fail in case that 'okc' is not supported */
19757 			WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
19758 		}
19759 	}
19760 
19761 	ret = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
19762 	if (ret) {
19763 		WL_ERR(("wl_cfg80211_set_pmk error:%d", ret));
19764 		ret = -EINVAL;
19765 		return ret;
19766 	} else {
19767 		WL_DBG(("pmk added for mac:"MACDBG"\n", MAC2STRDBG(conf->aa)));
19768 	}
19769 	return 0;
19770 }
19771 
wl_cfg80211_del_pmk(struct wiphy * wiphy,struct net_device * dev,const u8 * aa)19772 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
19773 	const u8 *aa)
19774 {
19775 	int err = BCME_OK;
19776 	struct cfg80211_pmksa pmksa;
19777 
19778 	/* build up cfg80211_pmksa structure to use existing wl_cfg80211_update_pmksa API */
19779 	bzero(&pmksa, sizeof(pmksa));
19780 	pmksa.bssid = aa;
19781 
19782 	err = wl_cfg80211_update_pmksa(wiphy, dev, &pmksa, FALSE);
19783 	if (unlikely(err)) {
19784 		WL_ERR(("wl_cfg80211_update_pmksa err:%d\n", err));
19785 		err = -EINVAL;
19786 	} else {
19787 		WL_DBG(("pmk deleted for bssid:"MACDBG"\n", MAC2STRDBG(aa)));
19788 	}
19789 
19790 	return err;
19791 }
19792 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
19793 
19794 u64
wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 * cfg)19795 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
19796 {
19797 	u64 id = 0;
19798 	id = ++cfg->last_roc_id;
19799 #ifdef  P2P_LISTEN_OFFLOADING
19800 	if (id == P2PO_COOKIE) {
19801 		id = ++cfg->last_roc_id;
19802 	}
19803 #endif /* P2P_LISTEN_OFFLOADING */
19804 	if (id == 0)
19805 		id = ++cfg->last_roc_id;
19806 	return id;
19807 }
19808 
19809 struct net_device*
wl_get_netdev_by_name(struct bcm_cfg80211 * cfg,char * ifname)19810 wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname)
19811 {
19812 	struct net_info *iter, *next;
19813 	struct net_device *ndev = NULL;
19814 
19815 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19816 	for_each_ndev(cfg, iter, next) {
19817 		GCC_DIAGNOSTIC_POP();
19818 		if (iter->ndev) {
19819 			if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
19820 				ndev = iter->ndev;
19821 				break;
19822 			}
19823 		}
19824 	}
19825 
19826 	return ndev;
19827 }
19828 
19829 #ifdef WBTEXT
wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 * cfg,struct ether_addr * ea)19830 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
19831 {
19832 	wl_wbtext_bssid_t *bssid = NULL;
19833 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19834 	/* check duplicate */
19835 	list_for_each_entry(bssid, &cfg->wbtext_bssid_list, list) {
19836 		GCC_DIAGNOSTIC_POP();
19837 		if (!memcmp(bssid->ea.octet, ea, ETHER_ADDR_LEN)) {
19838 			return FALSE;
19839 		}
19840 	}
19841 
19842 	return TRUE;
19843 }
19844 
wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 * cfg,struct ether_addr * ea)19845 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
19846 {
19847 	wl_wbtext_bssid_t *bssid = NULL;
19848 	char eabuf[ETHER_ADDR_STR_LEN];
19849 
19850 	bssid = (wl_wbtext_bssid_t *)MALLOC(cfg->osh, sizeof(wl_wbtext_bssid_t));
19851 	if (bssid == NULL) {
19852 		WL_ERR(("alloc failed\n"));
19853 		return FALSE;
19854 	}
19855 
19856 	memcpy(bssid->ea.octet, ea, ETHER_ADDR_LEN);
19857 
19858 	INIT_LIST_HEAD(&bssid->list);
19859 	list_add_tail(&bssid->list, &cfg->wbtext_bssid_list);
19860 
19861 	WL_DBG(("add wbtext bssid : %s\n", bcm_ether_ntoa(ea, eabuf)));
19862 
19863 	return TRUE;
19864 }
19865 
wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 * cfg)19866 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg)
19867 {
19868 	wl_wbtext_bssid_t *bssid = NULL;
19869 	char eabuf[ETHER_ADDR_STR_LEN];
19870 
19871 	while (!list_empty(&cfg->wbtext_bssid_list)) {
19872 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19873 		bssid = list_entry(cfg->wbtext_bssid_list.next, wl_wbtext_bssid_t, list);
19874 		GCC_DIAGNOSTIC_POP();
19875 		if (bssid) {
19876 			WL_DBG(("clear wbtext bssid : %s\n", bcm_ether_ntoa(&bssid->ea, eabuf)));
19877 			list_del(&bssid->list);
19878 			MFREE(cfg->osh, bssid, sizeof(wl_wbtext_bssid_t));
19879 		}
19880 	}
19881 }
19882 
wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 * cfg,struct net_device * dev)19883 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev)
19884 {
19885 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
19886 	bcm_tlv_t * cap_ie = NULL;
19887 	bool req_sent = FALSE;
19888 	struct wl_profile *profile;
19889 
19890 	WL_DBG(("Enter\n"));
19891 
19892 	profile = wl_get_profile_by_netdev(cfg, dev);
19893 	if (!profile) {
19894 		WL_ERR(("no profile exists\n"));
19895 		return;
19896 	}
19897 
19898 	if (wl_cfg80211_wbtext_check_bssid_list(cfg,
19899 			(struct ether_addr *)&profile->bssid) == FALSE) {
19900 		WL_DBG(("already updated\n"));
19901 		return;
19902 	}
19903 
19904 	/* first, check NBR bit in RRM IE */
19905 	if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
19906 			DOT11_MNG_RRM_CAP_ID)) != NULL) {
19907 		if (isset(cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
19908 			WL_DBG(("sending neighbor report\n"));
19909 			req_sent = wl_cfg80211_wbtext_send_nbr_req(cfg, dev, profile);
19910 		}
19911 	}
19912 
19913 	/* if RRM nbr was not supported, check BTM bit in extend cap. IE */
19914 	if (!req_sent) {
19915 		if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
19916 				DOT11_MNG_EXT_CAP_ID)) != NULL) {
19917 			if (cap_ie->len >= DOT11_EXTCAP_LEN_BSSTRANS &&
19918 					isset(cap_ie->data, DOT11_EXT_CAP_BSSTRANS_MGMT)) {
19919 				WL_DBG(("sending btm query\n"));
19920 				wl_cfg80211_wbtext_send_btm_query(cfg, dev, profile);
19921 			}
19922 		}
19923 	}
19924 }
19925 
wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 * cfg,struct net_device * dev,struct wl_profile * profile)19926 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
19927 	struct wl_profile *profile)
19928 {
19929 	int error = -1;
19930 	char *smbuf = NULL;
19931 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
19932 	bcm_tlv_t * rrm_cap_ie = NULL;
19933 	wlc_ssid_t *ssid = NULL;
19934 	bool ret = FALSE;
19935 
19936 	WL_DBG(("Enter\n"));
19937 
19938 	/* check RRM nbr bit in extend cap. IE of assoc response */
19939 	if ((rrm_cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
19940 			DOT11_MNG_RRM_CAP_ID)) != NULL) {
19941 		if (!isset(rrm_cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
19942 			WL_DBG(("AP doesn't support neighbor report\n"));
19943 			return FALSE;
19944 		}
19945 	}
19946 
19947 	smbuf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
19948 	if (smbuf == NULL) {
19949 		WL_ERR(("failed to allocated memory\n"));
19950 		goto nbr_req_out;
19951 	}
19952 
19953 	ssid = (wlc_ssid_t *)MALLOCZ(cfg->osh, sizeof(wlc_ssid_t));
19954 	if (ssid == NULL) {
19955 		WL_ERR(("failed to allocated memory\n"));
19956 		goto nbr_req_out;
19957 	}
19958 
19959 	ssid->SSID_len = MIN(profile->ssid.SSID_len, DOT11_MAX_SSID_LEN);
19960 	memcpy(ssid->SSID, profile->ssid.SSID, ssid->SSID_len);
19961 
19962 	error = wldev_iovar_setbuf(dev, "rrm_nbr_req", ssid,
19963 		sizeof(wlc_ssid_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
19964 	if (error == BCME_OK) {
19965 		ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
19966 			(struct ether_addr *)&profile->bssid);
19967 	} else {
19968 		WL_ERR(("failed to send neighbor report request, error=%d\n", error));
19969 	}
19970 
19971 nbr_req_out:
19972 	if (ssid) {
19973 		MFREE(cfg->osh, ssid, sizeof(wlc_ssid_t));
19974 	}
19975 
19976 	if (smbuf) {
19977 		MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
19978 	}
19979 	return ret;
19980 }
19981 
wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 * cfg,struct net_device * dev,struct wl_profile * profile)19982 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
19983 	struct wl_profile *profile)
19984 
19985 {
19986 	int error = -1;
19987 	bool ret = FALSE;
19988 	wl_bsstrans_query_t btq;
19989 
19990 	WL_DBG(("Enter\n"));
19991 
19992 	bzero(&btq, sizeof(wl_bsstrans_query_t));
19993 
19994 	btq.version = WL_BSSTRANS_QUERY_VERSION_1;
19995 	error = wldev_iovar_setbuf(dev, "wnm_bsstrans_query", &btq,
19996 		sizeof(btq), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
19997 	if (error == BCME_OK) {
19998 		ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
19999 			(struct ether_addr *)&profile->bssid);
20000 	} else {
20001 		WL_ERR(("wl_cfg80211_wbtext_send_btm_query: failed to set BTM query,"
20002 			" error=%d\n", error));
20003 	}
20004 	return ret;
20005 }
20006 
wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 * cfg,struct net_device * dev)20007 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev)
20008 {
20009 	keepalives_max_idle_t keepalive = {0, 0, 0, 0};
20010 	s32 bssidx, error;
20011 	int wnm_maxidle = 0;
20012 	struct wl_connect_info *conn_info = wl_to_conn(cfg);
20013 
20014 	/* AP supports wnm max idle ? */
20015 	if (bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
20016 			DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID) != NULL) {
20017 		error = wldev_iovar_getint(dev, "wnm_maxidle", &wnm_maxidle);
20018 		if (error < 0) {
20019 			WL_ERR(("failed to get wnm max idle period : %d\n", error));
20020 		}
20021 	}
20022 
20023 	WL_DBG(("wnm max idle period : %d\n", wnm_maxidle));
20024 
20025 	/* if wnm maxidle has valid period, set it as keep alive */
20026 	if (wnm_maxidle > 0) {
20027 		keepalive.keepalive_count = 1;
20028 	}
20029 
20030 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) >= 0) {
20031 		error = wldev_iovar_setbuf_bsscfg(dev, "wnm_keepalives_max_idle", &keepalive,
20032 			sizeof(keepalives_max_idle_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
20033 			bssidx, &cfg->ioctl_buf_sync);
20034 		if (error < 0) {
20035 			if (error == BCME_BADARG) {
20036 				WL_ERR(("set wnm_keepalive with invalid arguments\n"));
20037 			} else {
20038 				WL_ERR(("set wnm_keepalives_max_idle failed : %d\n", error));
20039 			}
20040 		}
20041 	}
20042 }
20043 
20044 static int
wl_cfg80211_recv_nbr_resp(struct net_device * dev,uint8 * body,uint body_len)20045 wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len)
20046 {
20047 	dot11_rm_action_t *rm_rep;
20048 	bcm_tlv_t *tlvs;
20049 	uint tlv_len;
20050 	int i, error;
20051 	dot11_neighbor_rep_ie_t *nbr_rep_ie;
20052 	chanspec_t ch;
20053 	wl_roam_channel_list_t channel_list;
20054 	char iobuf[WLC_IOCTL_SMLEN];
20055 
20056 	if (body_len < DOT11_RM_ACTION_LEN) {
20057 		WL_ERR(("Received Neighbor Report frame with incorrect length %d\n",
20058 			body_len));
20059 		return BCME_ERROR;
20060 	}
20061 
20062 	rm_rep = (dot11_rm_action_t *)body;
20063 	WL_DBG(("received neighbor report (token = %d)\n", rm_rep->token));
20064 
20065 	tlvs = (bcm_tlv_t *)&rm_rep->data[0];
20066 
20067 	tlv_len = body_len - DOT11_RM_ACTION_LEN;
20068 
20069 	while (tlvs && tlvs->id == DOT11_MNG_NEIGHBOR_REP_ID) {
20070 		nbr_rep_ie = (dot11_neighbor_rep_ie_t *)tlvs;
20071 
20072 		if (nbr_rep_ie->len < DOT11_NEIGHBOR_REP_IE_FIXED_LEN) {
20073 			WL_ERR(("malformed Neighbor Report element with length %d\n",
20074 				nbr_rep_ie->len));
20075 			tlvs = bcm_next_tlv(tlvs, &tlv_len);
20076 			continue;
20077 		}
20078 
20079 		ch = CH20MHZ_CHSPEC(nbr_rep_ie->channel);
20080 		WL_DBG(("ch:%d, bssid:"MACDBG"\n",
20081 			ch, MAC2STRDBG(nbr_rep_ie->bssid.octet)));
20082 
20083 		/* get RCC list */
20084 		error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0,
20085 			(void *)&channel_list, sizeof(channel_list), NULL);
20086 		if (error) {
20087 			WL_ERR(("Failed to get roamscan channels, error = %d\n", error));
20088 			return BCME_ERROR;
20089 		}
20090 
20091 		/* update RCC */
20092 		if (channel_list.n < MAX_ROAM_CHANNEL) {
20093 			for (i = 0; i < channel_list.n; i++) {
20094 				if (channel_list.channels[i] == ch) {
20095 					break;
20096 				}
20097 			}
20098 			if (i == channel_list.n) {
20099 				channel_list.channels[channel_list.n] = ch;
20100 				channel_list.n++;
20101 			}
20102 		}
20103 
20104 		/* set RCC list */
20105 		error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list,
20106 			sizeof(channel_list), iobuf, sizeof(iobuf), NULL);
20107 		if (error) {
20108 			WL_DBG(("Failed to set roamscan channels, error = %d\n", error));
20109 		}
20110 
20111 		tlvs = bcm_next_tlv(tlvs, &tlv_len);
20112 	}
20113 
20114 	return BCME_OK;
20115 }
20116 #endif /* WBTEXT */
20117 #ifdef SUPPORT_SET_CAC
20118 void
wl_cfg80211_set_cac(struct bcm_cfg80211 * cfg,int enable)20119 wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable)
20120 {
20121 	int ret = 0;
20122 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20123 
20124 	WL_DBG(("cac enable %d\n", enable));
20125 	if (!dhd) {
20126 		WL_ERR(("dhd is NULL\n"));
20127 		return;
20128 	}
20129 	if ((ret = dhd_wl_ioctl_set_intiovar(dhd, "cac", enable,
20130 			WLC_SET_VAR, TRUE, 0)) < 0) {
20131 		WL_ERR(("Failed set CAC, ret=%d\n", ret));
20132 	} else {
20133 		WL_DBG(("CAC set successfully\n"));
20134 	}
20135 	return;
20136 }
20137 #endif /* SUPPORT_SET_CAC */
20138 
20139 #ifdef SUPPORT_RSSI_SUM_REPORT
20140 int
wl_get_rssi_per_ant(struct net_device * dev,char * ifname,char * peer_mac,void * param)20141 wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void *param)
20142 {
20143 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20144 	wl_rssi_ant_mimo_t *get_param = (wl_rssi_ant_mimo_t *)param;
20145 	rssi_ant_param_t *set_param = NULL;
20146 	struct net_device *ifdev = NULL;
20147 	char iobuf[WLC_IOCTL_SMLEN];
20148 	int err = BCME_OK;
20149 	int iftype = 0;
20150 
20151 	bzero(iobuf, WLC_IOCTL_SMLEN);
20152 
20153 	/* Check the interface type */
20154 	ifdev = wl_get_netdev_by_name(cfg, ifname);
20155 	if (ifdev == NULL) {
20156 		WL_ERR(("Could not find net_device for ifname:%s\n", ifname));
20157 		err = BCME_BADARG;
20158 		goto fail;
20159 	}
20160 
20161 	iftype = ifdev->ieee80211_ptr->iftype;
20162 	if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO) {
20163 		if (peer_mac) {
20164 			set_param = (rssi_ant_param_t *)MALLOCZ(cfg->osh, sizeof(rssi_ant_param_t));
20165 			err = wl_cfg80211_ether_atoe(peer_mac, &set_param->ea);
20166 			if (!err) {
20167 				WL_ERR(("Invalid Peer MAC format\n"));
20168 				err = BCME_BADARG;
20169 				goto fail;
20170 			}
20171 		} else {
20172 			WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype));
20173 			err = BCME_BADARG;
20174 			goto fail;
20175 		}
20176 	}
20177 
20178 	err = wldev_iovar_getbuf(ifdev, "phy_rssi_ant", peer_mac ?
20179 		(void *)&(set_param->ea) : NULL, peer_mac ? ETHER_ADDR_LEN : 0,
20180 		(void *)iobuf, sizeof(iobuf), NULL);
20181 	if (unlikely(err)) {
20182 		WL_ERR(("Failed to get rssi info, err=%d\n", err));
20183 	} else {
20184 		memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t));
20185 		if (get_param->count == 0) {
20186 			WL_ERR(("Not supported on this chip\n"));
20187 			err = BCME_UNSUPPORTED;
20188 		}
20189 	}
20190 
20191 fail:
20192 	if (set_param) {
20193 		MFREE(cfg->osh, set_param, sizeof(rssi_ant_param_t));
20194 	}
20195 
20196 	return err;
20197 }
20198 
20199 int
wl_get_rssi_logging(struct net_device * dev,void * param)20200 wl_get_rssi_logging(struct net_device *dev, void *param)
20201 {
20202 	rssilog_get_param_t *get_param = (rssilog_get_param_t *)param;
20203 	char iobuf[WLC_IOCTL_SMLEN];
20204 	int err = BCME_OK;
20205 
20206 	bzero(iobuf, WLC_IOCTL_SMLEN);
20207 	bzero(get_param, sizeof(*get_param));
20208 	err = wldev_iovar_getbuf(dev, "rssilog", NULL, 0, (void *)iobuf,
20209 		sizeof(iobuf), NULL);
20210 	if (err) {
20211 		WL_ERR(("Failed to get rssi logging info, err=%d\n", err));
20212 	} else {
20213 		memcpy(get_param, iobuf, sizeof(*get_param));
20214 	}
20215 
20216 	return err;
20217 }
20218 
20219 int
wl_set_rssi_logging(struct net_device * dev,void * param)20220 wl_set_rssi_logging(struct net_device *dev, void *param)
20221 {
20222 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20223 	rssilog_set_param_t *set_param = (rssilog_set_param_t *)param;
20224 	int err;
20225 
20226 	err = wldev_iovar_setbuf(dev, "rssilog", set_param,
20227 		sizeof(*set_param), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
20228 		&cfg->ioctl_buf_sync);
20229 	if (err) {
20230 		WL_ERR(("Failed to set rssi logging param, err=%d\n", err));
20231 	}
20232 
20233 	return err;
20234 }
20235 #endif /* SUPPORT_RSSI_SUM_REPORT */
20236 /* Function to flush the FW preserve buffer content
20237 * The buffer content is sent to host in form of events.
20238 */
20239 void
wl_flush_fw_log_buffer(struct net_device * dev,uint32 logset_mask)20240 wl_flush_fw_log_buffer(struct net_device *dev, uint32 logset_mask)
20241 {
20242 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20243 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20244 	int i;
20245 	int err = 0;
20246 	u8 buf[WLC_IOCTL_SMLEN] = {0};
20247 	wl_el_set_params_t set_param;
20248 
20249 	/* Set the size of data to retrieve */
20250 	memset(&set_param, 0, sizeof(set_param));
20251 	set_param.size = WLC_IOCTL_SMLEN;
20252 
20253 	for (i = 0; i < dhd->event_log_max_sets; i++)
20254 	{
20255 		if ((0x01u << i) & logset_mask) {
20256 			set_param.set = i;
20257 			err = wldev_iovar_setbuf(dev, "event_log_get", &set_param,
20258 				sizeof(struct wl_el_set_params_s), buf, WLC_IOCTL_SMLEN,
20259 				NULL);
20260 			if (err) {
20261 				WL_DBG(("Failed to get fw preserve logs, err=%d\n", err));
20262 			}
20263 		}
20264 	}
20265 }
20266 #ifdef USE_WFA_CERT_CONF
20267 extern int g_frameburst;
20268 #endif /* USE_WFA_CERT_CONF */
20269 
20270 int
wl_cfg80211_set_frameburst(struct bcm_cfg80211 * cfg,bool enable)20271 wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable)
20272 {
20273 	int ret = BCME_OK;
20274 	int val = enable ? 1 : 0;
20275 
20276 #ifdef USE_WFA_CERT_CONF
20277 	if (!g_frameburst) {
20278 		WL_DBG(("Skip setting frameburst\n"));
20279 		return 0;
20280 	}
20281 #endif /* USE_WFA_CERT_CONF */
20282 
20283 	WL_DBG(("Set frameburst %d\n", val));
20284 	ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg), WLC_SET_FAKEFRAG, &val, sizeof(val));
20285 	if (ret < 0) {
20286 		WL_ERR(("Failed set frameburst, ret=%d\n", ret));
20287 	} else {
20288 		WL_INFORM_MEM(("frameburst is %s\n", enable ? "enabled" : "disabled"));
20289 	}
20290 
20291 	return ret;
20292 }
20293 
20294 s32
wl_cfg80211_set_dbg_verbose(struct net_device * ndev,u32 level)20295 wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level)
20296 {
20297 	/* configure verbose level for debugging */
20298 	if (level) {
20299 		/* Enable increased verbose */
20300 		wl_dbg_level |= WL_DBG_DBG;
20301 	} else {
20302 		/* Disable */
20303 		wl_dbg_level &= ~WL_DBG_DBG;
20304 	}
20305 	WL_INFORM(("debug verbose set to %d\n", level));
20306 
20307 	return BCME_OK;
20308 }
20309 
20310 const u8 *
wl_find_attribute(const u8 * buf,u16 len,u16 element_id)20311 wl_find_attribute(const u8 *buf, u16 len, u16 element_id)
20312 {
20313 	const u8 *attrib;
20314 	u16 attrib_id;
20315 	u16 attrib_len;
20316 
20317 	if (!buf) {
20318 		WL_ERR(("buf null\n"));
20319 		return NULL;
20320 	}
20321 
20322 	attrib = buf;
20323 	while (len >= 4) {
20324 		/* attribute id */
20325 		attrib_id = *attrib++ << 8;
20326 		attrib_id |= *attrib++;
20327 		len -= 2;
20328 
20329 		/* 2-byte little endian */
20330 		attrib_len = *attrib++ << 8;
20331 		attrib_len |= *attrib++;
20332 
20333 		len -= 2;
20334 		if (attrib_id == element_id) {
20335 			/* This will point to start of subelement attrib after
20336 			 * attribute id & len
20337 			 */
20338 			return attrib;
20339 		}
20340 		if (len > attrib_len) {
20341 			len -= attrib_len;	/* for the remaining subelt fields */
20342 			WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n",
20343 				attrib_id, attrib_len, len));
20344 
20345 			/* Go to next subelement */
20346 			attrib += attrib_len;
20347 		} else {
20348 			WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n",
20349 				attrib_id, attrib_len));
20350 			return NULL;
20351 		}
20352 	}
20353 	return NULL;
20354 }
20355 
wl_cfg80211_get_bus_state(struct bcm_cfg80211 * cfg)20356 uint8 wl_cfg80211_get_bus_state(struct bcm_cfg80211 *cfg)
20357 {
20358 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20359 	WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
20360 			dhd->hang_was_sent, dhd->busstate));
20361 	return ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent);
20362 }
20363 
20364 #ifdef WL_WPS_SYNC
wl_wps_reauth_timeout(unsigned long data)20365 static void wl_wps_reauth_timeout(unsigned long data)
20366 {
20367 	struct net_device *ndev = (struct net_device *)data;
20368 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20369 	s32 inst;
20370 	unsigned long flags;
20371 
20372 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20373 	inst = wl_get_wps_inst_match(cfg, ndev);
20374 	if (inst >= 0) {
20375 		WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n",
20376 				ndev->name, inst, cfg->wps_session[inst].state));
20377 		if (cfg->wps_session[inst].state == WPS_STATE_REAUTH_WAIT) {
20378 			/* Session should get deleted from success (linkup) or
20379 			 * deauth case. Just in case, link reassoc failed, clear
20380 			 * state here.
20381 			 */
20382 			WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n",
20383 				ndev->name, inst));
20384 			cfg->wps_session[inst].state = WPS_STATE_IDLE;
20385 			cfg->wps_session[inst].in_use = false;
20386 		}
20387 	}
20388 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20389 }
20390 
wl_init_wps_reauth_sm(struct bcm_cfg80211 * cfg)20391 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg)
20392 {
20393 	/* Only two instances are supported as of now. one for
20394 	 * infra STA and other for infra STA/GC.
20395 	 */
20396 	int i = 0;
20397 	struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
20398 
20399 	spin_lock_init(&cfg->wps_sync);
20400 	for (i = 0; i < WPS_MAX_SESSIONS; i++) {
20401 		/* Init scan_timeout timer */
20402 		init_timer_compat(&cfg->wps_session[i].timer, wl_wps_reauth_timeout, pdev);
20403 		cfg->wps_session[i].in_use = false;
20404 		cfg->wps_session[i].state = WPS_STATE_IDLE;
20405 	}
20406 }
20407 
wl_deinit_wps_reauth_sm(struct bcm_cfg80211 * cfg)20408 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg)
20409 {
20410 	int i = 0;
20411 
20412 	for (i = 0; i < WPS_MAX_SESSIONS; i++) {
20413 		cfg->wps_session[i].in_use = false;
20414 		cfg->wps_session[i].state = WPS_STATE_IDLE;
20415 		del_timer_sync(&cfg->wps_session[i].timer);
20416 	}
20417 
20418 }
20419 
20420 static s32
wl_get_free_wps_inst(struct bcm_cfg80211 * cfg)20421 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg)
20422 {
20423 	int i;
20424 
20425 	for (i = 0; i < WPS_MAX_SESSIONS; i++) {
20426 		if (!cfg->wps_session[i].in_use) {
20427 			return i;
20428 		}
20429 	}
20430 	return BCME_ERROR;
20431 }
20432 
20433 static s32
wl_get_wps_inst_match(struct bcm_cfg80211 * cfg,struct net_device * ndev)20434 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev)
20435 {
20436 	int i;
20437 
20438 	for (i = 0; i < WPS_MAX_SESSIONS; i++) {
20439 		if ((cfg->wps_session[i].in_use) &&
20440 			(ndev == cfg->wps_session[i].ndev)) {
20441 			return i;
20442 		}
20443 	}
20444 
20445 	return BCME_ERROR;
20446 }
20447 
20448 static s32
wl_wps_session_add(struct net_device * ndev,u16 mode,u8 * mac_addr)20449 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *mac_addr)
20450 {
20451 	s32 inst;
20452 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20453 	unsigned long flags;
20454 
20455 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20456 	/* Fetch and initialize a wps instance */
20457 	inst = wl_get_free_wps_inst(cfg);
20458 	if (inst == BCME_ERROR) {
20459 		WL_ERR(("[WPS] No free insance\n"));
20460 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20461 		return BCME_ERROR;
20462 	}
20463 	cfg->wps_session[inst].in_use = true;
20464 	cfg->wps_session[inst].state = WPS_STATE_STARTED;
20465 	cfg->wps_session[inst].ndev = ndev;
20466 	cfg->wps_session[inst].mode = mode;
20467 	/* return check not required since both buffer lens are same */
20468 	(void)memcpy_s(cfg->wps_session[inst].peer_mac, ETH_ALEN, mac_addr, ETH_ALEN);
20469 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20470 
20471 	WL_INFORM_MEM(("[%s][WPS] session created.  Peer: " MACDBG "\n",
20472 		ndev->name, MAC2STRDBG(mac_addr)));
20473 	return BCME_OK;
20474 }
20475 
20476 static void
wl_wps_session_del(struct net_device * ndev)20477 wl_wps_session_del(struct net_device *ndev)
20478 {
20479 	s32 inst;
20480 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20481 	unsigned long flags;
20482 	u16 cur_state;
20483 
20484 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20485 
20486 	/* Get current instance for the given ndev */
20487 	inst = wl_get_wps_inst_match(cfg, ndev);
20488 	if (inst == BCME_ERROR) {
20489 		WL_DBG(("[WPS] instance match NOT found\n"));
20490 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20491 		return;
20492 	}
20493 
20494 	cur_state = cfg->wps_session[inst].state;
20495 	if (cur_state != WPS_STATE_DONE) {
20496 		WL_DBG(("[WPS] wrong state:%d\n", cur_state));
20497 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20498 		return;
20499 	}
20500 
20501 	/* Mark this as unused */
20502 	cfg->wps_session[inst].in_use = false;
20503 	cfg->wps_session[inst].state = WPS_STATE_IDLE;
20504 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20505 
20506 	/* Ensure this API is called from sleepable context. */
20507 	del_timer_sync(&cfg->wps_session[inst].timer);
20508 
20509 	WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev->name));
20510 }
20511 
20512 static void
wl_wps_handle_ifdel(struct net_device * ndev)20513 wl_wps_handle_ifdel(struct net_device *ndev)
20514 {
20515 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20516 	unsigned long flags;
20517 	u16 cur_state;
20518 	s32 inst;
20519 
20520 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20521 	inst = wl_get_wps_inst_match(cfg, ndev);
20522 	if (inst == BCME_ERROR) {
20523 		WL_DBG(("[WPS] instance match NOT found\n"));
20524 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20525 		return;
20526 	}
20527 	cur_state = cfg->wps_session[inst].state;
20528 	cfg->wps_session[inst].state = WPS_STATE_DONE;
20529 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20530 
20531 	WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev->name, cur_state));
20532 	if (cur_state > WPS_STATE_IDLE) {
20533 		wl_wps_session_del(ndev);
20534 	}
20535 }
20536 
20537 static s32
wl_wps_handle_sta_linkdown(struct net_device * ndev,u16 inst)20538 wl_wps_handle_sta_linkdown(struct net_device *ndev, u16 inst)
20539 {
20540 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20541 	unsigned long flags;
20542 	u16 cur_state;
20543 	bool wps_done = false;
20544 
20545 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20546 	cur_state = cfg->wps_session[inst].state;
20547 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
20548 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20549 		wl_clr_drv_status(cfg, CONNECTED, ndev);
20550 		wl_clr_drv_status(cfg, DISCONNECTING, ndev);
20551 		WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev->name));
20552 		/* Drop the link down event while we are waiting for reauth */
20553 		return BCME_UNSUPPORTED;
20554 	} else if (cur_state == WPS_STATE_STARTED) {
20555 		/* Link down before reaching EAP-FAIL. End WPS session */
20556 		cfg->wps_session[inst].state = WPS_STATE_DONE;
20557 		wps_done = true;
20558 		WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev->name));
20559 	} else {
20560 		WL_DBG(("[%s][WPS] link down in state:%d\n",
20561 			ndev->name, cur_state));
20562 	}
20563 
20564 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20565 
20566 	if (wps_done) {
20567 		wl_wps_session_del(ndev);
20568 	}
20569 	return BCME_OK;
20570 }
20571 
20572 static s32
wl_wps_handle_peersta_linkdown(struct net_device * ndev,u16 inst,const u8 * peer_mac)20573 wl_wps_handle_peersta_linkdown(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20574 {
20575 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20576 	unsigned long flags;
20577 	u16 cur_state;
20578 	s32 ret = BCME_OK;
20579 	bool wps_done = false;
20580 
20581 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20582 	cur_state = cfg->wps_session[inst].state;
20583 
20584 	if (!peer_mac) {
20585 		WL_ERR(("Invalid arg\n"));
20586 		ret = BCME_ERROR;
20587 		goto exit;
20588 	}
20589 
20590 	/* AP/GO can have multiple clients. so validate peer_mac addr
20591 	 * and ensure states are updated only for right peer.
20592 	 */
20593 	if (memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20594 		/* Mac addr not matching. Ignore. */
20595 		WL_DBG(("[%s][WPS] No active WPS session"
20596 			"for the peer:" MACDBG "\n", ndev->name, MAC2STRDBG(peer_mac)));
20597 		ret = BCME_OK;
20598 		goto exit;
20599 	}
20600 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
20601 		WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
20602 			" Peer: " MACDBG "\n",
20603 			ndev->name, MAC2STRDBG(peer_mac)));
20604 #ifdef NOT_YET
20605 		/* Link down during REAUTH state is expected. However,
20606 		 * if this is send up, hostapd statemachine issues a
20607 		 * deauth down and that may pre-empt WPS reauth state
20608 		 * at GC.
20609 		 */
20610 		WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore."
20611 			" for client:" MACDBG "\n",
20612 			ndev->name, MAC2STRDBG(peer_mac)));
20613 		ret = BCME_UNSUPPORTED;
20614 #endif
20615 	} else if (cur_state == WPS_STATE_STARTED) {
20616 		/* Link down before reaching REAUTH_WAIT state. WPS
20617 		 * session ended.
20618 		 */
20619 		cfg->wps_session[inst].state = WPS_STATE_DONE;
20620 		WL_INFORM_MEM(("[%s][WPS] link down after wps start"
20621 			" client:" MACDBG "\n",
20622 			ndev->name, MAC2STRDBG(peer_mac)));
20623 		wps_done = true;
20624 		/* since we have freed lock above, return from here */
20625 		ret = BCME_OK;
20626 	} else {
20627 		WL_ERR(("[%s][WPS] Unsupported state:%d",
20628 			ndev->name, cur_state));
20629 		ret = BCME_ERROR;
20630 	}
20631 exit:
20632 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20633 	if (wps_done) {
20634 		wl_wps_session_del(ndev);
20635 	}
20636 	return ret;
20637 }
20638 
20639 static s32
wl_wps_handle_sta_linkup(struct net_device * ndev,u16 inst)20640 wl_wps_handle_sta_linkup(struct net_device *ndev, u16 inst)
20641 {
20642 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20643 	unsigned long flags;
20644 	u16 cur_state;
20645 	s32 ret = BCME_OK;
20646 	bool wps_done = false;
20647 
20648 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20649 	cur_state = cfg->wps_session[inst].state;
20650 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
20651 		/* WPS session succeeded. del session. */
20652 		cfg->wps_session[inst].state = WPS_STATE_DONE;
20653 		wps_done = true;
20654 		WL_INFORM_MEM(("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev->name));
20655 		ret = BCME_OK;
20656 	} else {
20657 		WL_ERR(("[%s][WPS] unexpected link up in state:%d \n",
20658 			ndev->name, cur_state));
20659 		ret = BCME_ERROR;
20660 	}
20661 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20662 	if (wps_done) {
20663 		wl_wps_session_del(ndev);
20664 	}
20665 	return ret;
20666 }
20667 
20668 static s32
wl_wps_handle_peersta_linkup(struct net_device * ndev,u16 inst,const u8 * peer_mac)20669 wl_wps_handle_peersta_linkup(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20670 {
20671 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20672 	unsigned long flags;
20673 	u16 cur_state;
20674 	s32 ret = BCME_OK;
20675 
20676 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20677 	cur_state = cfg->wps_session[inst].state;
20678 
20679 	/* For AP case, check whether call came for right peer */
20680 	if (!peer_mac ||
20681 		memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20682 		WL_ERR(("[WPS] macaddr mismatch\n"));
20683 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20684 		/* Mac addr not matching. Ignore. */
20685 		return BCME_ERROR;
20686 	}
20687 
20688 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
20689 		WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev->name));
20690 		ret = BCME_OK;
20691 	} else {
20692 		WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
20693 			ndev->name, cur_state));
20694 		ret = BCME_ERROR;
20695 	}
20696 
20697 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20698 
20699 	return ret;
20700 }
20701 
20702 static s32
wl_wps_handle_authorize(struct net_device * ndev,u16 inst,const u8 * peer_mac)20703 wl_wps_handle_authorize(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20704 {
20705 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20706 	unsigned long flags;
20707 	u16 cur_state;
20708 	bool wps_done = false;
20709 	s32 ret = BCME_OK;
20710 
20711 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20712 	cur_state = cfg->wps_session[inst].state;
20713 
20714 	/* For AP case, check whether call came for right peer */
20715 	if (!peer_mac ||
20716 		memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20717 		WL_ERR(("[WPS] macaddr mismatch\n"));
20718 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20719 		/* Mac addr not matching. Ignore. */
20720 		return BCME_ERROR;
20721 	}
20722 
20723 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
20724 		/* WPS session succeeded. del session. */
20725 		cfg->wps_session[inst].state = WPS_STATE_DONE;
20726 		wps_done = true;
20727 		WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev->name));
20728 		ret = BCME_OK;
20729 	} else {
20730 		WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
20731 			ndev->name, cur_state));
20732 		ret = BCME_ERROR;
20733 	}
20734 
20735 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20736 	if (wps_done) {
20737 		wl_wps_session_del(ndev);
20738 	}
20739 	return ret;
20740 }
20741 
20742 static s32
wl_wps_handle_reauth(struct net_device * ndev,u16 inst,const u8 * peer_mac)20743 wl_wps_handle_reauth(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20744 {
20745 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20746 	unsigned long flags;
20747 	u16 cur_state;
20748 	u16 mode;
20749 	s32 ret = BCME_OK;
20750 
20751 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20752 	cur_state = cfg->wps_session[inst].state;
20753 	mode = cfg->wps_session[inst].mode;
20754 
20755 	if (((mode == WL_MODE_BSS) && (cur_state == WPS_STATE_STARTED)) ||
20756 		((mode == WL_MODE_AP) && (cur_state == WPS_STATE_M8_SENT))) {
20757 		/* Move to reauth wait */
20758 		cfg->wps_session[inst].state = WPS_STATE_REAUTH_WAIT;
20759 		/* Use ndev to find the wps instance which fired the timer */
20760 		timer_set_private(&cfg->wps_session[inst].timer, ndev);
20761 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20762 		mod_timer(&cfg->wps_session[inst].timer,
20763 			jiffies + msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT));
20764 		WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG "\n",
20765 			ndev->name, mode, MAC2STRDBG(peer_mac)));
20766 		return BCME_OK;
20767 	} else {
20768 		/* 802.1x cases */
20769 		WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev->name));
20770 	}
20771 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20772 	return ret;
20773 }
20774 
20775 static s32
wl_wps_handle_disconnect(struct net_device * ndev,u16 inst,const u8 * peer_mac)20776 wl_wps_handle_disconnect(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20777 {
20778 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20779 	unsigned long flags;
20780 	u16 cur_state;
20781 	s32 ret = BCME_OK;
20782 
20783 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20784 	cur_state = cfg->wps_session[inst].state;
20785 	/* If Disconnect command comes from  user space for STA/GC,
20786 	 * respond with event without waiting for event from fw as
20787 	 * it would be dropped by the WPS_SYNC code.
20788 	 */
20789 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
20790 		if (ETHER_ISBCAST(peer_mac)) {
20791 			WL_INFORM_MEM(("[WPS] Bcast peer. Do nothing.\n"));
20792 		} else {
20793 			/* Notify link down */
20794 			CFG80211_DISCONNECTED(ndev,
20795 				WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
20796 				true, GFP_ATOMIC);
20797 			WL_INFORM_MEM(("[WPS] Disconnect event notified\n"));
20798 		}
20799 	} else {
20800 		WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
20801 			ndev->name, cur_state));
20802 		ret = BCME_UNSUPPORTED;
20803 	}
20804 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20805 	return ret;
20806 }
20807 
20808 static s32
wl_wps_handle_disconnect_client(struct net_device * ndev,u16 inst,const u8 * peer_mac)20809 wl_wps_handle_disconnect_client(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20810 {
20811 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20812 	unsigned long flags;
20813 	u16 cur_state;
20814 	s32 ret = BCME_OK;
20815 	bool wps_done = false;
20816 
20817 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20818 	cur_state = cfg->wps_session[inst].state;
20819 	/* For GO/AP, ignore disconnect client during reauth state */
20820 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
20821 		if (ETHER_ISBCAST(peer_mac)) {
20822 			/* If there is broadcast deauth, then mark wps session as ended */
20823 			cfg->wps_session[inst].state = WPS_STATE_DONE;
20824 			wps_done = true;
20825 			WL_INFORM_MEM(("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev->name));
20826 			ret = BCME_OK;
20827 			goto exit;
20828 		} else if (!(memcmp(cfg->wps_session[inst].peer_mac,
20829 			peer_mac, ETH_ALEN))) {
20830 			WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev->name));
20831 			ret = BCME_UNSUPPORTED;
20832 		}
20833 	}
20834 
20835 exit:
20836 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20837 	if (wps_done) {
20838 		wl_wps_session_del(ndev);
20839 	}
20840 	return ret;
20841 }
20842 
20843 static s32
wl_wps_handle_connect_fail(struct net_device * ndev,u16 inst)20844 wl_wps_handle_connect_fail(struct net_device *ndev, u16 inst)
20845 {
20846 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20847 	unsigned long flags;
20848 	u16 cur_state;
20849 	bool wps_done = false;
20850 
20851 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20852 	cur_state = cfg->wps_session[inst].state;
20853 	if (cur_state == WPS_STATE_REAUTH_WAIT) {
20854 		cfg->wps_session[inst].state = WPS_STATE_DONE;
20855 		wps_done = true;
20856 		WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n",
20857 			ndev->name));
20858 	} else {
20859 		WL_ERR(("[%s][WPS] Connect fail. state:%d\n",
20860 			ndev->name, cur_state));
20861 	}
20862 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20863 	if (wps_done) {
20864 		wl_wps_session_del(ndev);
20865 	}
20866 	return BCME_OK;
20867 }
20868 
20869 static s32
wl_wps_handle_m8_sent(struct net_device * ndev,u16 inst,const u8 * peer_mac)20870 wl_wps_handle_m8_sent(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20871 {
20872 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20873 	unsigned long flags;
20874 	u16 cur_state;
20875 	s32 ret = BCME_OK;
20876 
20877 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20878 	cur_state = cfg->wps_session[inst].state;
20879 
20880 	if (cur_state == WPS_STATE_STARTED) {
20881 		/* Move to M8 sent state */
20882 		cfg->wps_session[inst].state = WPS_STATE_M8_SENT;
20883 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20884 		return BCME_OK;
20885 	} else {
20886 		/* 802.1x cases */
20887 		WL_DBG(("[%s][WPS] Not valid state to send M8\n", ndev->name));
20888 	}
20889 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20890 	return ret;
20891 }
20892 
20893 s32
wl_wps_session_update(struct net_device * ndev,u16 state,const u8 * peer_mac)20894 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac)
20895 {
20896 	s32 inst;
20897 	u16 mode;
20898 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20899 	s32 ret = BCME_ERROR;
20900 	unsigned long flags;
20901 
20902 	WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20903 	/* Get current instance for the given ndev */
20904 	inst = wl_get_wps_inst_match(cfg, ndev);
20905 	if (inst == BCME_ERROR) {
20906 		/* No active WPS session. Do Nothing. */
20907 		WL_DBG(("[%s][WPS] No matching instance.\n", ndev->name));
20908 		WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20909 		return BCME_NOTFOUND;
20910 	}
20911 	mode = cfg->wps_session[inst].mode;
20912 	WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20913 
20914 	WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG "\n",
20915 		ndev->name, state, mode, MAC2STRDBG(peer_mac)));
20916 
20917 	switch (state) {
20918 		case WPS_STATE_M8_RECVD:
20919 		{
20920 			/* Occasionally, due to race condition between ctrl
20921 			 * and data path, deauth ind is recvd before EAP-FAIL.
20922 			 * Ignore deauth ind before EAP-FAIL
20923 			 * So move to REAUTH WAIT on receiving M8 on GC and
20924 			 * ignore deauth ind before EAP-FAIL till 'x' timeout.
20925 			 * Kickoff a timer to monitor reauth status.
20926 			 */
20927 			if (mode == WL_MODE_BSS) {
20928 				ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
20929 			} else {
20930 				/* Nothing to be done for AP/GO mode */
20931 				ret = BCME_OK;
20932 			}
20933 			break;
20934 		}
20935 		case WPS_STATE_M8_SENT:
20936 		{
20937 			/* Mantain the M8 sent state to verify
20938 			 * EAP-FAIL sent is valid
20939 			 */
20940 			if (mode == WL_MODE_AP) {
20941 				ret = wl_wps_handle_m8_sent(ndev, inst, peer_mac);
20942 			} else {
20943 				/* Nothing to be done for STA/GC mode */
20944 				ret = BCME_OK;
20945 			}
20946 			break;
20947 		}
20948 		case WPS_STATE_EAP_FAIL:
20949 		{
20950 			/* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
20951 			 * Kickoff a timer to monitor reauth status
20952 			 */
20953 			if (mode == WL_MODE_AP) {
20954 				ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
20955 			} else {
20956 				/* Nothing to be done for STA/GC mode */
20957 				ret = BCME_OK;
20958 			}
20959 			break;
20960 		}
20961 		case WPS_STATE_LINKDOWN:
20962 		{
20963 			if (mode == WL_MODE_BSS) {
20964 				ret = wl_wps_handle_sta_linkdown(ndev, inst);
20965 			} else if (mode == WL_MODE_AP) {
20966 				/* Take action only for matching peer mac */
20967 				if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20968 					ret = wl_wps_handle_peersta_linkdown(ndev, inst, peer_mac);
20969 				}
20970 			}
20971 			break;
20972 		}
20973 		case WPS_STATE_LINKUP:
20974 		{
20975 			if (mode == WL_MODE_BSS) {
20976 				wl_wps_handle_sta_linkup(ndev, inst);
20977 			} else if (mode == WL_MODE_AP) {
20978 				/* Take action only for matching peer mac */
20979 				if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20980 					wl_wps_handle_peersta_linkup(ndev, inst, peer_mac);
20981 				}
20982 			}
20983 			break;
20984 		}
20985 		case WPS_STATE_DISCONNECT_CLIENT:
20986 		{
20987 			/* Disconnect STA/GC command from user space */
20988 			if (mode == WL_MODE_AP) {
20989 				ret = wl_wps_handle_disconnect_client(ndev, inst, peer_mac);
20990 			} else {
20991 				WL_ERR(("[WPS] Unsupported mode %d\n", mode));
20992 			}
20993 			break;
20994 		}
20995 		case WPS_STATE_DISCONNECT:
20996 		{
20997 			/* Disconnect command on STA/GC interface */
20998 			if (mode == WL_MODE_BSS) {
20999 				ret = wl_wps_handle_disconnect(ndev, inst, peer_mac);
21000 			}
21001 			break;
21002 		}
21003 		case WPS_STATE_CONNECT_FAIL:
21004 		{
21005 			if (mode == WL_MODE_BSS) {
21006 				ret = wl_wps_handle_connect_fail(ndev, inst);
21007 			} else {
21008 				WL_ERR(("[WPS] Unsupported mode %d\n", mode));
21009 			}
21010 			break;
21011 		}
21012 		case WPS_STATE_AUTHORIZE:
21013 		{
21014 			if (mode == WL_MODE_AP) {
21015 				/* Take action only for matching peer mac */
21016 				if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
21017 					wl_wps_handle_authorize(ndev, inst, peer_mac);
21018 				} else {
21019 					WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
21020 				}
21021 			}
21022 			break;
21023 		}
21024 
21025 	default:
21026 		WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state, mode));
21027 		ret = BCME_ERROR;
21028 	}
21029 
21030 	return ret;
21031 }
21032 
21033 #define EAP_EXP_ATTRIB_DATA_OFFSET 14
21034 void
wl_handle_wps_states(struct net_device * ndev,u8 * pkt,u16 len,bool direction)21035 wl_handle_wps_states(struct net_device *ndev, u8 *pkt, u16 len, bool direction)
21036 {
21037 	eapol_header_t *eapol_hdr;
21038 	bool tx_packet = direction;
21039 	u16 eapol_type;
21040 	u16 mode;
21041 	u8 *peer_mac;
21042 
21043 	if (!ndev || !pkt) {
21044 		WL_ERR(("[WPS] Invalid arg\n"));
21045 		return;
21046 	}
21047 
21048 	if (len < (ETHER_HDR_LEN + EAPOL_HDR_LEN)) {
21049 		WL_ERR(("[WPS] Invalid len\n"));
21050 		return;
21051 	}
21052 
21053 	eapol_hdr = (eapol_header_t *)pkt;
21054 	eapol_type = eapol_hdr->type;
21055 
21056 	peer_mac = tx_packet ? eapol_hdr->eth.ether_dhost :
21057 			eapol_hdr->eth.ether_shost;
21058 	/*
21059 	 * The implementation assumes only one WPS session would be active
21060 	 * per interface at a time. Even for hostap, the wps_pin session
21061 	 * is limited to one enrollee/client at a time. A session is marked
21062 	 * started on WSC_START and gets cleared from below contexts
21063 	 * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
21064 	 * b) Link up following EAP-FAIL. (success case)
21065 	 * c) Link up timeout after EAP-FAIL. (Fail case)
21066 	 */
21067 
21068 	if (eapol_type == EAP_PACKET) {
21069 		wl_eap_header_t *eap;
21070 
21071 		if (len > sizeof(*eap)) {
21072 			eap = (wl_eap_header_t *)(pkt + ETHER_HDR_LEN + EAPOL_HDR_LEN);
21073 			if (eap->type == EAP_EXPANDED_TYPE) {
21074 				wl_eap_exp_t *exp = (wl_eap_exp_t *)eap->data;
21075 				if (eap->length > EAP_EXP_HDR_MIN_LENGTH) {
21076 					/* opcode is at fixed offset */
21077 					u8 opcode = exp->opcode;
21078 					u16 eap_len = ntoh16(eap->length);
21079 
21080 					WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
21081 						ndev->name, opcode, eap_len));
21082 					if (opcode == EAP_WSC_MSG) {
21083 						const u8 *msg;
21084 						const u8* parse_buf = exp->data;
21085 						/* Check if recvd pkt is fragmented */
21086 						if ((!tx_packet) &&
21087 							(exp->flags &
21088 							EAP_EXP_FLAGS_FRAGMENTED_DATA)) {
21089 							if ((eap_len - EAP_EXP_ATTRIB_DATA_OFFSET)
21090 							> 2) {
21091 								parse_buf +=
21092 								EAP_EXP_FRAGMENT_LEN_OFFSET;
21093 								eap_len -=
21094 								EAP_EXP_FRAGMENT_LEN_OFFSET;
21095 								WL_DBG(("Rcvd EAP"
21096 								" fragmented pkt\n"));
21097 							} else {
21098 								/* If recvd pkt is fragmented
21099 								* and does not have
21100 								* length field drop the packet.
21101 								*/
21102 								return;
21103 							}
21104 						}
21105 
21106 						msg = wl_find_attribute(parse_buf,
21107 							(eap_len - EAP_EXP_ATTRIB_DATA_OFFSET),
21108 							EAP_ATTRIB_MSGTYPE);
21109 						if (unlikely(!msg)) {
21110 							WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
21111 						} else if ((*msg == EAP_WSC_MSG_M8) &&
21112 								!tx_packet) {
21113 							/* In certain cases M2 can also carry
21114 							 * credential. So add check for
21115 							 * cred in M8/M2 and start reauth timer.
21116 							 */
21117 							WL_INFORM_MEM(("[%s][WPS] M8\n",
21118 								ndev->name));
21119 							wl_wps_session_update(ndev,
21120 								WPS_STATE_M8_RECVD, peer_mac);
21121 						} else if ((*msg == EAP_WSC_MSG_M8) &&
21122 								tx_packet) {
21123 							WL_INFORM_MEM(("[%s][WPS] M8 Sent\n",
21124 								ndev->name));
21125 							wl_wps_session_update(ndev,
21126 								WPS_STATE_M8_SENT, peer_mac);
21127 						} else {
21128 							WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n",
21129 								ndev->name, *msg));
21130 						}
21131 					} else if (opcode == EAP_WSC_START) {
21132 						/* WSC session started. WSC_START - Tx from GO/AP.
21133 						 * Session will be deleted on successful link up or
21134 						 * on failure (deauth context)
21135 						 */
21136 						mode = tx_packet ? WL_MODE_AP : WL_MODE_BSS;
21137 						wl_wps_session_add(ndev, mode, peer_mac);
21138 						WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
21139 							ndev->name, mode));
21140 					} else if (opcode == EAP_WSC_DONE) {
21141 						/* WSC session done. TX on STA/GC. RX on GO/AP
21142 						 * On devices where config file save fails, it may
21143 						 * return WPS_NAK with config_error:0. But the
21144 						 * connection would still proceed. Hence don't let
21145 						 * state machine depend on WSC DONE.
21146 						 */
21147 						WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev->name));
21148 					}
21149 				}
21150 			}
21151 
21152 			if (eap->code == EAP_CODE_FAILURE) {
21153 				/* EAP_FAIL */
21154 				WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev->name));
21155 				wl_wps_session_update(ndev,
21156 					WPS_STATE_EAP_FAIL, peer_mac);
21157 			}
21158 		}
21159 	}
21160 }
21161 #endif /* WL_WPS_SYNC */
21162 
21163 s32
wl_cfg80211_sup_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * event,void * data)21164 wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21165 	const wl_event_msg_t *event, void *data)
21166 {
21167 	int err = BCME_OK;
21168 	u32 status = ntoh32(event->status);
21169 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
21170 	u32 reason = ntoh32(event->reason);
21171 
21172 	if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
21173 		/* Join attempt via non-cfg80211 interface.
21174 		 * Don't send resultant events to cfg80211
21175 		 * layer
21176 		 */
21177 		WL_INFORM_MEM(("Event received in non-cfg80211"
21178 			" connect state. Ignore\n"));
21179 		return BCME_OK;
21180 	}
21181 
21182 	if ((status == WLC_SUP_KEYED || status == WLC_SUP_KEYXCHANGE_WAIT_G1) &&
21183 	    reason == WLC_E_SUP_OTHER) {
21184 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
21185 		/* NL80211_CMD_PORT_AUTHORIZED supported above >= 4.15 */
21186 		cfg80211_port_authorized(ndev, (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID),
21187 			GFP_KERNEL);
21188 		WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
21189 #elif ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT))
21190 		err = wl_cfgvendor_send_async_event(bcmcfg_to_wiphy(cfg), ndev,
21191 			BRCM_VENDOR_EVENT_PORT_AUTHORIZED, NULL, 0);
21192 		WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
21193 #else
21194 		/* not supported in kernel <= 3,14,0 */
21195 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */
21196 		/* Post SCB authorize actions */
21197 		wl_cfg80211_post_scb_auth(cfg, ndev);
21198 	} else if (status < WLC_SUP_KEYXCHANGE_WAIT_G1 && (reason != WLC_E_SUP_OTHER &&
21199 		reason != WLC_E_SUP_PTK_UPDATE)) {
21200 		/* if any failure seen while 4way HS, should send NL80211_CMD_DISCONNECT */
21201 		WL_ERR(("4way HS error. status:%d, reason:%d\n", status, reason));
21202 		CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
21203 	}
21204 
21205 	return err;
21206 }
21207 
21208 #ifdef WL_BCNRECV
21209 static s32
wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21210 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21211 		const wl_event_msg_t *e, void *data)
21212 {
21213 	s32 status = ntoh32(e->status);
21214 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
21215 	/* Abort fakeapscan, when Roam is in progress */
21216 	if (status == WLC_E_STATUS_RXBCN_ABORT) {
21217 		wl_android_bcnrecv_stop(ndev, WL_BCNRECV_ROAMABORT);
21218 	} else {
21219 		WL_ERR(("UNKNOWN STATUS. status:%d\n", status));
21220 	}
21221 	return BCME_OK;
21222 }
21223 #endif /* WL_BCNRECV */
21224 
21225 #ifdef WL_MBO
21226 static s32
wl_mbo_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21227 wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21228 	const wl_event_msg_t *e, void *data)
21229 {
21230 	s32 err = 0;
21231 	wl_event_mbo_t *mbo_evt = (wl_event_mbo_t *)data;
21232 	wl_event_mbo_cell_nw_switch_t *cell_sw_evt = NULL;
21233 	wl_btm_event_type_data_t *evt_data = NULL;
21234 
21235 	WL_INFORM(("MBO: Evt %u\n", mbo_evt->type));
21236 
21237 	if (mbo_evt->type == WL_MBO_E_CELLULAR_NW_SWITCH) {
21238 		cell_sw_evt = (wl_event_mbo_cell_nw_switch_t *)mbo_evt->data;
21239 		BCM_REFERENCE(cell_sw_evt);
21240 		SUPP_EVENT(("CTRL-EVENT-CELLULAR-SWITCH", "reason %d cur_assoc_time_left %u "
21241 			"reassoc_delay %u\n", cell_sw_evt->reason,
21242 			cell_sw_evt->assoc_time_remain, cell_sw_evt->reassoc_delay));
21243 	} else if (mbo_evt->type == WL_MBO_E_BTM_RCVD) {
21244 		evt_data = (wl_btm_event_type_data_t *)mbo_evt->data;
21245 		if (evt_data->version != WL_BTM_EVENT_DATA_VER_1) {
21246 			WL_ERR(("version mismatch. rcvd %u expected %u\n",
21247 				evt_data->version, WL_BTM_EVENT_DATA_VER_1));
21248 				return -1;
21249 		}
21250 		SUPP_EVENT(("CTRL-EVENT-BRCM-BTM-REQ-RCVD", "reason=%u\n",
21251 			evt_data->transition_reason));
21252 	} else {
21253 		WL_INFORM(("UNKNOWN EVENT. type:%u\n", mbo_evt->type));
21254 	}
21255 	return err;
21256 }
21257 #endif /* WL_MBO */
21258 
21259 #ifdef WL_CAC_TS
21260 static s32
wl_cfg80211_cac_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21261 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21262 		const wl_event_msg_t *e, void *data)
21263 {
21264 	u32 event = ntoh32(e->event_type);
21265 	s32 status = ntoh32(e->status);
21266 	s32 reason = ntoh32(e->reason);
21267 
21268 	BCM_REFERENCE(reason);
21269 
21270 	if (event == WLC_E_ADDTS_IND) {
21271 		/* The supp log format of adding ts_delay in success case needs to be maintained */
21272 		if (status == WLC_E_STATUS_SUCCESS) {
21273 			uint *ts_delay = (uint *)data;
21274 			BCM_REFERENCE(ts_delay);
21275 			SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d ts_delay=%u\n",
21276 				status, reason, *ts_delay));
21277 		} else {
21278 			SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d\n",
21279 				status, reason));
21280 		}
21281 	} else if (event == WLC_E_DELTS_IND) {
21282 		SUPP_EVENT(("CTRL-EVENT-CAC-DELTS", "status=%d reason=%d\n", status, reason));
21283 	}
21284 
21285 	return BCME_OK;
21286 }
21287 #endif /* WL_CAC_TS */
21288 
21289 #if defined(WL_MBO) || defined(WL_OCE)
21290 static s32
wl_bssid_prune_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21291 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21292 	const wl_event_msg_t *e, void *data)
21293 {
21294 	s32 err = 0;
21295 	uint reason = 0;
21296 	wl_bssid_pruned_evt_info_t *evt_info = (wl_bssid_pruned_evt_info_t *)data;
21297 
21298 	if (evt_info->version == WL_BSSID_PRUNE_EVT_VER_1) {
21299 		if (evt_info->reason == WLC_E_PRUNE_ASSOC_RETRY_DELAY) {
21300 			/* MBO assoc retry delay */
21301 			reason = WIFI_PRUNE_ASSOC_RETRY_DELAY;
21302 			SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
21303 				" reason=%u timeout_val=%u(ms)\n", evt_info->SSID,
21304 				ETHER_TO_MACF(evt_info->BSSID),	reason, evt_info->time_remaining));
21305 		} else if (evt_info->reason == WLC_E_PRUNE_RSSI_ASSOC_REJ) {
21306 			/* OCE RSSI-based assoc rejection */
21307 			reason = WIFI_PRUNE_RSSI_ASSOC_REJ;
21308 			SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
21309 				" reason=%u timeout_val=%u(ms) rssi_threshold=%d(dBm)\n",
21310 				evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID),
21311 				reason, evt_info->time_remaining, evt_info->rssi_threshold));
21312 		} else {
21313 			/* Invalid other than the assoc retry delay/RSSI assoc rejection
21314 			 * in the current handler
21315 			 */
21316 			BCM_REFERENCE(reason);
21317 			WL_INFORM(("INVALID. reason:%u\n", evt_info->reason));
21318 		}
21319 	} else {
21320 		WL_INFORM(("version mismatch. rcvd %u expected %u\n", evt_info->version,
21321 			WL_BSSID_PRUNE_EVT_VER_1));
21322 	}
21323 	return err;
21324 }
21325 #endif /* WL_MBO || WL_OCE */
21326 #ifdef RTT_SUPPORT
21327 static s32
wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21328 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21329 		const wl_event_msg_t *e, void *data)
21330 {
21331 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
21332 	wl_event_msg_t event;
21333 
21334 	(void)memcpy_s(&event, sizeof(wl_event_msg_t),
21335 		e, sizeof(wl_event_msg_t));
21336 	return dhd_rtt_event_handler(dhdp, &event, data);
21337 }
21338 #endif /* RTT_SUPPORT */
21339 
21340 void
wl_print_verinfo(struct bcm_cfg80211 * cfg)21341 wl_print_verinfo(struct bcm_cfg80211 *cfg)
21342 {
21343 	char *ver_ptr;
21344 	uint32 alloc_len = MOD_PARAM_INFOLEN;
21345 
21346 	if (!cfg) {
21347 		WL_ERR(("cfg is NULL\n"));
21348 		return;
21349 	}
21350 
21351 	ver_ptr = (char *)MALLOCZ(cfg->osh, alloc_len);
21352 	if (!ver_ptr) {
21353 		WL_ERR(("Failed to alloc ver_ptr\n"));
21354 		return;
21355 	}
21356 
21357 	if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
21358 		TRUE, &ver_ptr, alloc_len)) {
21359 		WL_ERR(("DHD Version: %s\n", ver_ptr));
21360 	}
21361 
21362 	if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
21363 		FALSE, &ver_ptr, alloc_len)) {
21364 		WL_ERR(("F/W Version: %s\n", ver_ptr));
21365 	}
21366 
21367 	MFREE(cfg->osh, ver_ptr, alloc_len);
21368 }
21369 
21370 /* Get the concurrency mode */
wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 * cfg)21371 int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg)
21372 {
21373 	struct net_info *iter, *next;
21374 	uint cmode = CONCURRENCY_MODE_NONE;
21375 	u32 connected_cnt = 0;
21376 	u32 pre_channel = 0, channel = 0;
21377 	u32 pre_band = 0;
21378 	u32 chanspec = 0;
21379 	u32 band = 0;
21380 
21381 	connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
21382 	if (connected_cnt <= 1) {
21383 		return cmode;
21384 	}
21385 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21386 	for_each_ndev(cfg, iter, next) {
21387 		if (iter->ndev) {
21388 			if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
21389 				if (wldev_iovar_getint(iter->ndev, "chanspec",
21390 					(s32 *)&chanspec) == BCME_OK) {
21391 					channel = wf_chspec_ctlchan(
21392 						wl_chspec_driver_to_host(chanspec));
21393 					band = (channel <= CH_MAX_2G_CHANNEL) ?
21394 						IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
21395 				}
21396 				if ((!pre_channel && channel)) {
21397 					pre_band = band;
21398 					pre_channel = channel;
21399 				} else if (pre_channel) {
21400 					if ((pre_band == band) && (pre_channel == channel)) {
21401 						cmode = CONCURRENCY_SCC_MODE;
21402 						goto exit;
21403 					} else if ((pre_band == band) && (pre_channel != channel)) {
21404 						cmode = CONCURRENCY_VSDB_MODE;
21405 						goto exit;
21406 					} else if (pre_band != band) {
21407 						cmode = CONCURRENCY_RSDB_MODE;
21408 						goto exit;
21409 					}
21410 				}
21411 			}
21412 		}
21413 	}
21414 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
21415 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
21416 _Pragma("GCC diagnostic pop")
21417 #endif
21418 exit:
21419 	return cmode;
21420 }
21421 #ifdef WL_CHAN_UTIL
21422 static s32
wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21423 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21424 		const wl_event_msg_t *e, void *data)
21425 {
21426 	s32 err = BCME_OK;
21427 	struct sk_buff *skb = NULL;
21428 	s32 status = ntoh32(e->status);
21429 	u8 chan_use_percentage = 0;
21430 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
21431 		LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
21432 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
21433 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
21434 			/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
21435 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21436 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
21437 	uint len;
21438 	gfp_t kflags;
21439 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
21440 
21441 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21442 	len = CU_ATTR_HDR_LEN + sizeof(u8);
21443 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
21444 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
21445 
21446 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
21447 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
21448 	skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), len,
21449 		BRCM_VENDOR_EVENT_CU, kflags);
21450 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21451 	skb = cfg80211_vendor_event_alloc(wiphy, len, BRCM_VENDOR_EVENT_CU, kflags);
21452 #else
21453 	/* No support exist */
21454 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
21455 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
21456 	if (!skb) {
21457 		WL_ERR(("skb alloc failed"));
21458 		return -ENOMEM;
21459 	}
21460 
21461 	if ((status == WLC_E_STATUS_SUCCESS) && data) {
21462 		wl_bssload_t *bssload_report = (wl_bssload_t *)data;
21463 		chan_use_percentage = (bssload_report->chan_util * 100) / 255;
21464 		WL_DBG(("ChannelUtilization=%hhu\n", chan_use_percentage));
21465 		err = nla_put_u8(skb, CU_ATTR_PERCENTAGE, chan_use_percentage);
21466 		if (err < 0) {
21467 			WL_ERR(("Failed to put CU_ATTR_PERCENTAGE, err:%d\n", err));
21468 		}
21469 	}
21470 
21471 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21472 	cfg80211_vendor_event(skb, kflags);
21473 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
21474 
21475 	return err;
21476 }
21477 
21478 #define WL_CHAN_UTIL_DEFAULT_INTERVAL	3000
21479 #define WL_CHAN_UTIL_THRESH_MIN		15
21480 #define WL_CHAN_UTIL_THRESH_INTERVAL	10
21481 #ifndef CUSTOM_CU_INTERVAL
21482 #define CUSTOM_CU_INTERVAL WL_CHAN_UTIL_DEFAULT_INTERVAL
21483 #endif /* CUSTOM_CU_INTERVAL */
21484 
21485 static s32
wl_cfg80211_start_bssload_report(struct net_device * ndev)21486 wl_cfg80211_start_bssload_report(struct net_device *ndev)
21487 {
21488 	s32 err = BCME_OK;
21489 	wl_bssload_cfg_t blcfg;
21490 	u8 i;
21491 	struct bcm_cfg80211 *cfg;
21492 
21493 	if (!ndev) {
21494 		return -ENODEV;
21495 	}
21496 
21497 	cfg = wl_get_cfg(ndev);
21498 	if (!cfg) {
21499 		return -ENODEV;
21500 	}
21501 
21502 	/* Typecasting to void as the buffer size is same as the memset size */
21503 	(void)memset_s(&blcfg, sizeof(wl_bssload_cfg_t), 0, sizeof(wl_bssload_cfg_t));
21504 	/* Set default report interval 3 sec and 8 threshhold levels between 15 to 85% */
21505 	blcfg.rate_limit_msec = CUSTOM_CU_INTERVAL;
21506 	blcfg.num_util_levels = MAX_BSSLOAD_LEVELS;
21507 	for (i = 0; i < MAX_BSSLOAD_LEVELS; i++) {
21508 		blcfg.util_levels[i] = (((WL_CHAN_UTIL_THRESH_MIN +
21509 			(i * WL_CHAN_UTIL_THRESH_INTERVAL)) * 255) / 100);
21510 	}
21511 
21512 	err = wldev_iovar_setbuf(ndev, "bssload_report_event", &blcfg,
21513 		sizeof(wl_bssload_cfg_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
21514 	if (unlikely(err)) {
21515 		WL_ERR(("Set event_msgs error (%d)\n", err));
21516 	}
21517 
21518 	return err;
21519 }
21520 #endif /* WL_CHAN_UTIL */
21521 
21522 s32
wl_cfg80211_config_suspend_events(struct net_device * ndev,bool enable)21523 wl_cfg80211_config_suspend_events(struct net_device *ndev, bool enable)
21524 {
21525 	s32 err = 0;
21526 	struct bcm_cfg80211 *cfg;
21527 	s8 event_buf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE] = {0};
21528 	eventmsgs_ext_t *eventmask_msg = NULL;
21529 	/*  Room for "event_msgs_ext" + '\0' + bitvec  */
21530 	char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16];
21531 	s32 msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE;
21532 
21533 	if (!ndev) {
21534 		return -ENODEV;
21535 	}
21536 
21537 	cfg = wl_get_cfg(ndev);
21538 	if (!cfg) {
21539 		return -ENODEV;
21540 	}
21541 
21542 	mutex_lock(&cfg->event_sync);
21543 
21544 	eventmask_msg = (eventmsgs_ext_t *)event_buf;
21545 	eventmask_msg->ver = EVENTMSGS_VER;
21546 	eventmask_msg->command = EVENTMSGS_NONE;
21547 	eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
21548 	eventmask_msg->maxgetsize = WL_EVENTING_MASK_EXT_LEN;
21549 
21550 	/* Read event_msgs mask */
21551 	err = wldev_iovar_getbuf(ndev, "event_msgs_ext",
21552 		eventmask_msg, EVENTMSGS_EXT_STRUCT_SIZE,
21553 		iovbuf,
21554 		sizeof(iovbuf),
21555 		NULL);
21556 
21557 	if (unlikely(err)) {
21558 		WL_ERR(("Get event_msgs error (%d)\n", err));
21559 		goto eventmsg_out;
21560 	}
21561 
21562 	bcopy(iovbuf, eventmask_msg, msglen);
21563 
21564 	/* Add set/clear of event mask under feature specific flags */
21565 	if (enable) {
21566 		WL_DBG(("%s: Enabling events on resume\n", __FUNCTION__));
21567 #ifdef WL_CHAN_UTIL
21568 		setbit(eventmask_msg->mask, WLC_E_BSS_LOAD);
21569 #endif /* WL_CHAN_UTIL */
21570 	} else {
21571 		WL_DBG(("%s: Disabling events before suspend\n", __FUNCTION__));
21572 #ifdef WL_CHAN_UTIL
21573 		clrbit(eventmask_msg->mask, WLC_E_BSS_LOAD);
21574 #endif /* WL_CHAN_UTIL */
21575 	}
21576 
21577 	/* Write updated Event mask */
21578 	eventmask_msg->ver = EVENTMSGS_VER;
21579 	eventmask_msg->command = EVENTMSGS_SET_MASK;
21580 	eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
21581 
21582 	err = wldev_iovar_setbuf(ndev, "event_msgs_ext", eventmask_msg,
21583 		WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE,
21584 		iovbuf, sizeof(iovbuf), NULL);
21585 
21586 	if (unlikely(err)) {
21587 		WL_ERR(("Set event_msgs error (%d)\n", err));
21588 		goto eventmsg_out;
21589 	}
21590 
21591 eventmsg_out:
21592 	mutex_unlock(&cfg->event_sync);
21593 	return err;
21594 }
21595 
21596 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
21597 #ifdef WLFBT
21598 static int
wl_cfg80211_update_ft_ies(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_update_ft_ies_params * ftie)21599 wl_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
21600 	struct cfg80211_update_ft_ies_params *ftie)
21601 {
21602 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
21603 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
21604 
21605 	if (!FW_SUPPORTED(dhdp, fbtoverds) && !FW_SUPPORTED(dhdp, fbt_adpt)) {
21606 		WL_INFORM(("FW does not support FT roaming\n"));
21607 		return BCME_UNSUPPORTED;
21608 	}
21609 	return BCME_OK;
21610 }
21611 #endif /* WLFBT */
21612 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */
21613 
21614 #ifdef WL_WIPSEVT
21615 int
wl_cfg80211_wips_event_ext(wl_wips_event_info_t * wips_event)21616 wl_cfg80211_wips_event_ext(wl_wips_event_info_t *wips_event)
21617 {
21618 	s32 err = BCME_OK;
21619 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21620 	struct sk_buff *skb;
21621 	gfp_t kflags;
21622 	struct bcm_cfg80211 *cfg;
21623 	struct net_device *ndev;
21624 	struct wiphy *wiphy;
21625 
21626 	cfg = wl_cfg80211_get_bcmcfg();
21627 	if (!cfg || !cfg->wdev) {
21628 		WL_ERR(("WIPS evt invalid arg\n"));
21629 		return err;
21630 	}
21631 
21632 	ndev = bcmcfg_to_prmry_ndev(cfg);
21633 	wiphy = bcmcfg_to_wiphy(cfg);
21634 
21635 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
21636 	skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
21637 		BRCM_VENDOR_WIPS_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_WIPS, kflags);
21638 
21639 	if (!skb) {
21640 		WL_ERR(("skb alloc failed"));
21641 		return BCME_NOMEM;
21642 	}
21643 
21644 	err = nla_put_u16(skb, WIPS_ATTR_DEAUTH_CNT, wips_event->misdeauth);
21645 	if (unlikely(err)) {
21646 		WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_CNT failed\n"));
21647 		goto fail;
21648 	}
21649 	err = nla_put(skb, WIPS_ATTR_DEAUTH_BSSID, ETHER_ADDR_LEN, &wips_event->bssid);
21650 	if (unlikely(err)) {
21651 		WL_ERR(("nla_put WIPS_ATTR_DEAUTH_BSSID failed\n"));
21652 		goto fail;
21653 	}
21654 	err = nla_put_s16(skb, WIPS_ATTR_CURRENT_RSSI, wips_event->current_RSSI);
21655 	if (unlikely(err)) {
21656 		WL_ERR(("nla_put_u16 WIPS_ATTR_CURRENT_RSSI failed\n"));
21657 		goto fail;
21658 	}
21659 	err = nla_put_s16(skb, WIPS_ATTR_DEAUTH_RSSI, wips_event->deauth_RSSI);
21660 	if (unlikely(err)) {
21661 		WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_RSSI failed\n"));
21662 		goto fail;
21663 	}
21664 	cfg80211_vendor_event(skb, kflags);
21665 
21666 	return err;
21667 
21668 fail:
21669 	if (skb) {
21670 		nlmsg_free(skb);
21671 	}
21672 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
21673 	return err;
21674 }
21675 
21676 int
wl_cfg80211_wips_event(uint16 misdeauth,char * bssid)21677 wl_cfg80211_wips_event(uint16 misdeauth, char* bssid)
21678 {
21679 	s32 err = BCME_OK;
21680 	wl_wips_event_info_t wips_event;
21681 
21682 	wips_event.misdeauth = misdeauth;
21683 	memcpy(&wips_event.bssid, bssid, ETHER_ADDR_LEN);
21684 	wips_event.current_RSSI = 0;
21685 	wips_event.deauth_RSSI = 0;
21686 
21687 	err = wl_cfg80211_wips_event_ext(&wips_event);
21688 	return err;
21689 }
21690 #endif /* WL_WIPSEVT */
21691 
21692 #ifdef PCIE_INB_DW
21693 #define WL_DS(x)
21694 /*
21695  * This API checks whether its okay to enter DS.
21696  * If some transaction is in progress, return true
21697  * to skip DS.
21698  */
21699 #ifndef USECS_PER_MSEC
21700 #define USECS_PER_MSEC 1000UL
21701 #endif /* USECS_PER_MSEC */
wl_cfg80211_check_in_progress(struct net_device * dev)21702 bool wl_cfg80211_check_in_progress(struct net_device *dev)
21703 {
21704 	struct bcm_cfg80211 *cfg;
21705 	struct net_device *pri_dev;
21706 	u8 reason = WL_STATE_IDLE;
21707 	u64 timeout;
21708 	u64 start_time = 0;
21709 
21710 	cfg = wl_get_cfg(dev);
21711 	pri_dev = bcmcfg_to_prmry_ndev(cfg);
21712 
21713 	/* check states like scan in progress, four way handshake, etc
21714 	 * before entering Deep Sleep.
21715 	 */
21716 	if (wl_get_drv_status_all(cfg, SCANNING)) {
21717 		WL_DS(("scan in progress\n"));
21718 		reason = WL_STATE_SCANNING;
21719 		start_time = GET_TS(cfg, scan_start);
21720 	} else if (wl_get_drv_status_all(cfg, CONNECTING)) {
21721 		WL_DS(("connect in progress\n"));
21722 		reason = WL_STATE_CONNECTING;
21723 		start_time = GET_TS(cfg, conn_start);
21724 	} else if ((IS_STA_IFACE(ndev_to_wdev(dev))) &&
21725 		wl_get_drv_status(cfg, CONNECTED, pri_dev) &&
21726 		!wl_get_drv_status(cfg, AUTHORIZED, pri_dev)) {
21727 		WL_DS(("connect-authorization in progress\n"));
21728 		reason = WL_STATE_AUTHORIZING;
21729 		start_time = GET_TS(cfg, authorize_start);
21730 	}
21731 
21732 	if (reason) {
21733 		u64 curtime = OSL_LOCALTIME_NS();
21734 		if (unlikely(!start_time)) {
21735 			WL_ERR_RLMT(("state got cleared for reason:%d\n", reason));
21736 			return false;
21737 		}
21738 		/* check whether we are stuck in a state
21739 		 * for too long.
21740 		 */
21741 		timeout = (start_time + (WL_DS_SKIP_THRESHOLD_USECS * USECS_PER_MSEC));
21742 		if (time_after64(curtime, timeout)) {
21743 			/* state hasn't changed for WL_DS_SKIP_THRESHOLD_USECS */
21744 			WL_ERR(("DS skip threshold hit. reason:%d start_time:"
21745 					SEC_USEC_FMT" cur_time:"SEC_USEC_FMT"\n",
21746 					reason, GET_SEC_USEC(start_time), GET_SEC_USEC(curtime)));
21747 			ASSERT((0));
21748 		}
21749 		/* return true to skip suspend */
21750 		return true;
21751 	}
21752 
21753 	return false;
21754 }
21755 #endif
21756 
wl_cfg80211_is_dpp_frame(void * frame,u32 frame_len)21757 bool wl_cfg80211_is_dpp_frame(void *frame, u32 frame_len)
21758 {
21759 		/* check for DPP public action frames */
21760 	wl_dpp_pa_frame_t *pact_frm;
21761 
21762 	if (frame == NULL) {
21763 		return false;
21764 	}
21765 	pact_frm = (wl_dpp_pa_frame_t *)frame;
21766 	if (frame_len < sizeof(wl_dpp_pa_frame_t) -1) {
21767 		return false;
21768 	}
21769 
21770 	if ((pact_frm->category == WL_PUB_AF_CATEGORY) &&
21771 		(pact_frm->action == WL_PUB_AF_ACTION) &&
21772 		(pact_frm->oui_type == WL_PUB_AF_WFA_STYPE_DPP) &&
21773 		(memcmp(pact_frm->oui, WFA_OUI, sizeof(pact_frm->oui)) == 0)) {
21774 		return true;
21775 	}
21776 
21777 	return false;
21778 }
21779 
21780 const char *
get_dpp_pa_ftype(enum wl_dpp_ftype ftype)21781 get_dpp_pa_ftype(enum wl_dpp_ftype ftype)
21782 {
21783 	switch (ftype) {
21784 		case DPP_AUTH_REQ:
21785 			return "DPP_AUTH_REQ";
21786 		case DPP_AUTH_RESP:
21787 			return "DPP_AUTH_RESP";
21788 		case DPP_AUTH_CONF:
21789 			return "DPP_AUTH_CONF";
21790 		default:
21791 			return "Unkown DPP frame";
21792 	}
21793 }
21794 
21795 #define GAS_RESP_LEN        2
21796 #define DOUBLE_TLV_BODY_OFF 4
wl_cfg80211_find_gas_subtype(u8 subtype,u16 adv_id,u8 * data,u32 len)21797 bool wl_cfg80211_find_gas_subtype(u8 subtype, u16 adv_id, u8* data, u32 len)
21798 {
21799 	const bcm_tlv_t *ie = (bcm_tlv_t *)data;
21800 	const u8 *frame = NULL;
21801 	u16 id, flen;
21802 
21803 	/* Skipped first ANQP Element, if frame has anqp elemnt */
21804 	ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID);
21805 
21806 	if (ie == NULL)
21807 		return false;
21808 
21809 	frame = (const uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN;
21810 	id = ((u16) (((frame)[1] << 8) | (frame)[0]));
21811 	flen = ((u16) (((frame)[3] << 8) | (frame)[2]));
21812 
21813 	/* If the contents match the OUI and the type */
21814 	if ((flen >= WFA_OUI_LEN + 1) &&
21815 		(id == adv_id) &&
21816 		!bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) &&
21817 		subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) {
21818 		return true;
21819 	}
21820 
21821 	return false;
21822 }
21823 
wl_cfg80211_is_dpp_gas_action(void * frame,u32 frame_len)21824 bool wl_cfg80211_is_dpp_gas_action(void *frame, u32 frame_len)
21825 {
21826 	wl_dpp_gas_af_t *act_frm = (wl_dpp_gas_af_t *)frame;
21827 	u32 len;
21828 	const bcm_tlv_t *ie = NULL;
21829 
21830 	if ((frame_len < (sizeof(wl_dpp_gas_af_t) - 1)) ||
21831 			act_frm->category != WL_PUB_AF_CATEGORY) {
21832 		return false;
21833 	}
21834 
21835 	len = frame_len - (u32)(sizeof(wl_dpp_gas_af_t) - 1);
21836 	if (act_frm->action == WL_PUB_AF_GAS_IREQ) {
21837 		ie = (bcm_tlv_t *)act_frm->query_data;
21838 		/* We are interested only in MNG ADV ID. Skip any other id. */
21839 		ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID);
21840 	} else if (act_frm->action == WL_PUB_AF_GAS_IRESP) {
21841 		ie = (bcm_tlv_t *)&act_frm->query_data[WL_GAS_RESP_OFFSET];
21842 		/* We are interested only in MNG ADV ID. Skip any other id. */
21843 		ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID);
21844 	} else {
21845 		return false;
21846 	}
21847 
21848 	if (ie && (ie->len >= WL_GAS_MIN_LEN) &&
21849 		(memcmp(&ie->data[WL_GAS_WFA_OFFSET], WFA_OUI, 3) == 0) &&
21850 		(ie->data[WL_GAS_STYPE_OFFSET] == WL_GAS_WFA_STYPE_DPP)) {
21851 		WL_DBG(("DPP GAS FRAME. type:%d\n", act_frm->action));
21852 		return true;
21853 	}
21854 
21855 	/* Non DPP GAS frame */
21856 	return false;
21857 }
21858 
21859 #ifdef KEEP_ALIVE
21860 #define KA_TEMP_BUF_SIZE 512
21861 #define KA_FRAME_SIZE 300
21862 int
wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 * cfg,uint8 mkeep_alive_id,uint16 ether_type,uint8 * ip_pkt,uint16 ip_pkt_len,uint8 * src_mac,uint8 * dst_mac,uint32 period_msec)21863 wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id,
21864 	uint16 ether_type, uint8 *ip_pkt, uint16 ip_pkt_len,
21865 	uint8* src_mac, uint8* dst_mac, uint32 period_msec)
21866 {
21867 	const int ETHERTYPE_LEN = 2;
21868 	char *pbuf = NULL;
21869 	const char *str;
21870 	wl_mkeep_alive_pkt_t mkeep_alive_pkt;
21871 	wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL;
21872 	uint16 buf_len = 0;
21873 	u8 str_len = 0;
21874 	int res = BCME_ERROR;
21875 	uint16 len_bytes = 0;
21876 	int i = 0;
21877 	uint16 pmac_frame_len = KA_FRAME_SIZE;
21878 	uint16 pbuf_len = KA_TEMP_BUF_SIZE;
21879 
21880 	/* ether frame to have both max IP pkt (256 bytes) and ether header */
21881 	char *pmac_frame = NULL;
21882 	char *pmac_frame_begin = NULL;
21883 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
21884 	struct net_device *primary_ndev = NULL;
21885 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
21886 
21887 	/*
21888 	 * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
21889 	 * dongle shall reject a mkeep_alive request.
21890 	 */
21891 	if (!(dhd->op_mode & DHD_FLAG_STA_MODE))
21892 		return res;
21893 
21894 	WL_TRACE(("%s execution\n", __FUNCTION__));
21895 
21896 	if ((pbuf = MALLOCZ(cfg->osh, KA_TEMP_BUF_SIZE)) == NULL) {
21897 		WL_ERR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE));
21898 		res = BCME_NOMEM;
21899 		return res;
21900 	}
21901 
21902 	if ((pmac_frame = MALLOCZ(cfg->osh, pmac_frame_len)) == NULL) {
21903 		WL_ERR(("failed to allocate mac_frame with size %d\n", pmac_frame_len));
21904 		res = BCME_NOMEM;
21905 		goto exit;
21906 	}
21907 	pmac_frame_begin = pmac_frame;
21908 
21909 	/*
21910 	 * Get current mkeep-alive status.
21911 	 */
21912 	res = wldev_iovar_getbuf(primary_ndev, "mkeep_alive", &mkeep_alive_id,
21913 		sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync);
21914 	if (res < 0) {
21915 		WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res));
21916 		goto exit;
21917 	} else {
21918 		/* Check available ID whether it is occupied */
21919 		mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf;
21920 		if (dtoh32(mkeep_alive_pktp->period_msec != 0)) {
21921 			WL_ERR(("%s: Get mkeep_alive failed, ID %u is in use.\n",
21922 				__FUNCTION__, mkeep_alive_id));
21923 
21924 			/* Current occupied ID info */
21925 			WL_ERR(("%s: mkeep_alive\n", __FUNCTION__));
21926 			WL_ERR(("   Id    : %d\n"
21927 				"   Period: %d msec\n"
21928 				"   Length: %d\n"
21929 				"   Packet: 0x",
21930 				mkeep_alive_pktp->keep_alive_id,
21931 				dtoh32(mkeep_alive_pktp->period_msec),
21932 				dtoh16(mkeep_alive_pktp->len_bytes)));
21933 
21934 			for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) {
21935 				WL_ERR(("%02x", mkeep_alive_pktp->data[i]));
21936 			}
21937 			WL_ERR(("\n"));
21938 
21939 			res = BCME_NOTFOUND;
21940 			goto exit;
21941 		}
21942 	}
21943 
21944 	/* Request the specified ID */
21945 	bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
21946 	bzero(pbuf, KA_TEMP_BUF_SIZE);
21947 	str = "mkeep_alive";
21948 	str_len = strlen(str);
21949 	strlcpy(pbuf, str, KA_TEMP_BUF_SIZE);
21950 	buf_len = str_len + 1;
21951 	pbuf_len -= buf_len;
21952 
21953 	mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + buf_len);
21954 	mkeep_alive_pkt.period_msec = htod32(period_msec);
21955 	mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
21956 	mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
21957 	len_bytes = (ETHER_ADDR_LEN*2) + ETHERTYPE_LEN + ip_pkt_len;
21958 	mkeep_alive_pkt.len_bytes = htod16(len_bytes);
21959 
21960 	/* ID assigned */
21961 	mkeep_alive_pkt.keep_alive_id = mkeep_alive_id;
21962 
21963 	buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
21964 
21965 	/*
21966 	 * Build up Ethernet Frame
21967 	 */
21968 
21969 	/* Mapping dest mac addr */
21970 	res = memcpy_s(pmac_frame, pmac_frame_len, dst_mac, ETHER_ADDR_LEN);
21971 	if (res) {
21972 		goto exit;
21973 	}
21974 	pmac_frame += ETHER_ADDR_LEN;
21975 	pmac_frame_len -= ETHER_ADDR_LEN;
21976 
21977 	/* Mapping src mac addr */
21978 	res = memcpy_s(pmac_frame, pmac_frame_len, src_mac, ETHER_ADDR_LEN);
21979 	if (res) {
21980 		goto exit;
21981 	}
21982 	pmac_frame += ETHER_ADDR_LEN;
21983 	pmac_frame_len -= ETHER_ADDR_LEN;
21984 
21985 	/* Mapping Ethernet type */
21986 	ether_type = hton16(ether_type);
21987 	res = memcpy_s(pmac_frame, pmac_frame_len, &ether_type, ETHERTYPE_LEN);
21988 	if (res) {
21989 		goto exit;
21990 	}
21991 	pmac_frame += ETHERTYPE_LEN;
21992 	pmac_frame_len -= ETHERTYPE_LEN;
21993 
21994 	/* Mapping IP pkt */
21995 	res = memcpy_s(pmac_frame, pmac_frame_len, ip_pkt, ip_pkt_len);
21996 	if (res) {
21997 		goto exit;
21998 	}
21999 	pmac_frame += ip_pkt_len;
22000 	pmac_frame_len -= ip_pkt_len;
22001 
22002 	/*
22003 	 * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
22004 	 * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
22005 	 * guarantee that the buffer is properly aligned.
22006 	 */
22007 	res = memcpy_s((char *)mkeep_alive_pktp, pbuf_len,
22008 		&mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
22009 	if (res) {
22010 		goto exit;
22011 	}
22012 	pbuf_len -= WL_MKEEP_ALIVE_FIXED_LEN;
22013 
22014 	/*
22015 	 * Length of ether frame (assume to be all hexa bytes)
22016 	 *     = src mac + dst mac + ether type + ip pkt len
22017 	 */
22018 	res = memcpy_s(mkeep_alive_pktp->data, pbuf_len,
22019 		pmac_frame_begin, len_bytes);
22020 	if (res) {
22021 		goto exit;
22022 	}
22023 	buf_len += len_bytes;
22024 
22025 	res = wldev_ioctl_set(primary_ndev, WLC_SET_VAR, pbuf, buf_len);
22026 exit:
22027 	if (pmac_frame_begin) {
22028 		MFREE(cfg->osh, pmac_frame_begin, KA_FRAME_SIZE);
22029 	}
22030 	if (pbuf) {
22031 		MFREE(cfg->osh, pbuf, KA_TEMP_BUF_SIZE);
22032 	}
22033 	return res;
22034 }
22035 
22036 int
wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211 * cfg,uint8 mkeep_alive_id)22037 wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id)
22038 {
22039 	char *pbuf = NULL;
22040 	wl_mkeep_alive_pkt_t mkeep_alive_pkt;
22041 	wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL;
22042 	int	res = BCME_ERROR;
22043 	int	i = 0;
22044 	struct net_device *primary_ndev = NULL;
22045 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22046 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
22047 
22048 	/*
22049 	 * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
22050 	 * dongle shall reject a mkeep_alive request.
22051 	 */
22052 	if (!(dhd->op_mode & DHD_FLAG_STA_MODE))
22053 		return res;
22054 
22055 	WL_TRACE(("%s execution\n", __FUNCTION__));
22056 
22057 	/*
22058 	 * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt.
22059 	 */
22060 	if ((pbuf = MALLOCZ(cfg->osh, KA_TEMP_BUF_SIZE)) == NULL) {
22061 		WL_ERR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE));
22062 		res = BCME_NOMEM;
22063 		return res;
22064 	}
22065 
22066 	res = wldev_iovar_getbuf(primary_ndev, "mkeep_alive", &mkeep_alive_id,
22067 			sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync);
22068 	if (res < 0) {
22069 		WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res));
22070 		goto exit;
22071 	} else {
22072 		/* Check occupied ID */
22073 		mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf;
22074 		WL_DBG(("%s: mkeep_alive\n", __FUNCTION__));
22075 		WL_DBG(("   Id    : %d\n"
22076 			"   Period: %d msec\n"
22077 			"   Length: %d\n"
22078 			"   Packet: 0x",
22079 			mkeep_alive_pktp->keep_alive_id,
22080 			dtoh32(mkeep_alive_pktp->period_msec),
22081 			dtoh16(mkeep_alive_pktp->len_bytes)));
22082 
22083 		for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) {
22084 			WL_DBG(("%02x", mkeep_alive_pktp->data[i]));
22085 		}
22086 		WL_DBG(("\n"));
22087 	}
22088 
22089 	/* Make it stop if available */
22090 	if (dtoh32(mkeep_alive_pktp->period_msec != 0)) {
22091 		WL_INFORM_MEM(("stop mkeep_alive on ID %d\n", mkeep_alive_id));
22092 		bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
22093 
22094 		mkeep_alive_pkt.period_msec = 0;
22095 		mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
22096 		mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
22097 		mkeep_alive_pkt.keep_alive_id = mkeep_alive_id;
22098 
22099 		res = wldev_iovar_setbuf(primary_ndev, "mkeep_alive",
22100 			(char *)&mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN,
22101 			pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync);
22102 	} else {
22103 		WL_ERR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id));
22104 		res = BCME_NOTFOUND;
22105 	}
22106 exit:
22107 	if (pbuf) {
22108 		MFREE(cfg->osh, pbuf, KA_TEMP_BUF_SIZE);
22109 	}
22110 	return res;
22111 }
22112 #endif /* KEEP_ALIVE */
22113 
22114 s32
wl_cfg80211_handle_macaddr_change(struct net_device * dev,u8 * macaddr)22115 wl_cfg80211_handle_macaddr_change(struct net_device *dev, u8 *macaddr)
22116 {
22117 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22118 	uint8 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
22119 	u32 status = TRUE;
22120 
22121 	if (IS_STA_IFACE(dev->ieee80211_ptr) &&
22122 		wl_get_drv_status(cfg, CONNECTED, dev)) {
22123 		/* Macaddress change in connected state. The curent
22124 		 * connection will become invalid. Issue disconnect
22125 		 * to current AP to let the AP know about link down
22126 		 */
22127 		WL_INFORM_MEM(("macaddr change in connected state. Force disassoc.\n"));
22128 		wl_cfg80211_disassoc(dev, WLAN_REASON_DEAUTH_LEAVING);
22129 
22130 		while ((status = wl_get_drv_status(cfg, CONNECTED, dev)) && wait_cnt) {
22131 			WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
22132 			wait_cnt--;
22133 			OSL_SLEEP(50);
22134 		}
22135 	}
22136 	return BCME_OK;
22137 }
22138 
22139 int
wl_cfg80211_handle_hang_event(struct net_device * ndev,uint16 hang_reason,uint32 memdump_type)22140 wl_cfg80211_handle_hang_event(struct net_device *ndev, uint16 hang_reason, uint32 memdump_type)
22141 {
22142 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
22143 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22144 
22145 	WL_INFORM_MEM(("hang reason = %d, memdump_type =%d\n",
22146 		hang_reason, memdump_type));
22147 
22148 	/* check if pre-registered mac matches the mac from dongle via WLC_E_LINK */
22149 	if (wl_get_drv_status(cfg, READY, ndev)) {
22150 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
22151 		wl_copy_hang_info_if_falure(ndev,
22152 			hang_reason, BCME_NOTFOUND);
22153 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
22154 		SUPP_LOG(("Err. hang reason:%d, dump_type:%d\n", hang_reason, memdump_type));
22155 		wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
22156 		/* IF dongle is down due to previous hang or other conditions,
22157 		 * sending 0ne more hang notification is not needed.
22158 		 */
22159 
22160 		if (dhd_query_bus_erros(dhd)) {
22161 			return BCME_ERROR;
22162 		}
22163 		dhd->iface_op_failed = TRUE;
22164 #if defined(DHD_FW_COREDUMP)
22165 		if (dhd->memdump_enabled) {
22166 			dhd->memdump_type = memdump_type;
22167 			dhd_bus_mem_dump(dhd);
22168 		}
22169 #endif /* DHD_FW_COREDUMP */
22170 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
22171 		WL_ERR(("Notify hang event to upper layer \n"));
22172 		dhd->hang_reason = hang_reason;
22173 		net_os_send_hang_message(ndev);
22174 #endif /* BCMDONGLEHOST &&  OEM_ANDROID */
22175 	}
22176 
22177 	return BCME_OK;
22178 }
22179 
22180 static void
wl_cfg80211_spmk_pmkdb_change_pmk_type(struct bcm_cfg80211 * cfg,pmkid_list_v3_t * pmk_list)22181 wl_cfg80211_spmk_pmkdb_change_pmk_type(struct bcm_cfg80211 *cfg, pmkid_list_v3_t *pmk_list)
22182 {
22183 	int i;
22184 	pmkid_list_v3_t *spmk_list = NULL;
22185 
22186 	if (!cfg || !cfg->spmk_info_list || !cfg->spmk_info_list->pmkids.count) {
22187 		return;
22188 	}
22189 
22190 	spmk_list = &cfg->spmk_info_list->pmkids;
22191 	for (i = 0; i < spmk_list->count; i++) {
22192 		if (memcmp(&pmk_list->pmkid->bssid,
22193 			&spmk_list->pmkid[i].bssid, ETHER_ADDR_LEN)) {
22194 			continue; /* different MAC */
22195 		}
22196 		WL_INFORM_MEM(("SPMK replace idx:%d bssid: "MACF " to SSID: %d\n", i,
22197 			ETHER_TO_MACF(pmk_list->pmkid->bssid), spmk_list->pmkid[i].ssid_len));
22198 		bzero(&pmk_list->pmkid->bssid, ETHER_ADDR_LEN);
22199 		pmk_list->pmkid->ssid_len = spmk_list->pmkid[i].ssid_len;
22200 		(void)memcpy_s(pmk_list->pmkid->ssid, spmk_list->pmkid[i].ssid_len,
22201 			spmk_list->pmkid[i].ssid, spmk_list->pmkid[i].ssid_len);
22202 	}
22203 }
22204 
22205 static void
wl_cfg80211_spmk_pmkdb_del_spmk(struct bcm_cfg80211 * cfg,struct cfg80211_pmksa * pmksa)22206 wl_cfg80211_spmk_pmkdb_del_spmk(struct bcm_cfg80211 *cfg, struct cfg80211_pmksa *pmksa)
22207 {
22208 	pmkid_list_v3_t *spmk_list = NULL;
22209 	bool bFound = FALSE;
22210 	int i;
22211 
22212 	if (!cfg || !cfg->spmk_info_list || !cfg->spmk_info_list->pmkids.count) {
22213 		return;
22214 	}
22215 
22216 	spmk_list = &cfg->spmk_info_list->pmkids;
22217 	for (i = 0; i < spmk_list->count; i++) {
22218 		if (eacmp(&pmksa->bssid, &spmk_list->pmkid[i].bssid)) {
22219 			continue; /* different MAC */
22220 		}
22221 		bFound = TRUE;
22222 		break;
22223 	}
22224 	WL_INFORM_MEM(("wl_cfg80211_del_pmksa "MACDBG "found:%d(idx:%d)",
22225 		MAC2STRDBG(spmk_list->pmkid[i].bssid.octet), bFound, i));
22226 	if (!bFound) {
22227 		return;
22228 	}
22229 
22230 	for (; i < spmk_list->count - 1; i++) {
22231 		memcpy_s(&spmk_list->pmkid[i], sizeof(pmkid_v3_t),
22232 			&spmk_list->pmkid[i + 1], sizeof(pmkid_v3_t));
22233 	}
22234 	spmk_list->count--;
22235 }
22236 
22237 static void
wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as,const wl_event_msg_t * event,wl_assoc_state_t assoc_state)22238 wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as,
22239 		const wl_event_msg_t *event, wl_assoc_state_t assoc_state)
22240 {
22241 	if (as->status != WLC_E_STATUS_SUCCESS) {
22242 #ifdef CUSTOMER_HW6
22243 		/* Some older chips sends SET_SSID with fail status and it
22244 		 * still proceeds with join. Excempt it for the sake of
22245 		 * compatibility
22246 		 */
22247 		return;
22248 #endif /* CUSTOMER_HW6 */
22249 #ifdef DHD_ENABLE_BIGDATA_LOGGING
22250 		wl_get_connect_failed_status(cfg, event);
22251 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
22252 
22253 #ifdef SET_SSID_FAIL_CUSTOM_RC
22254 		if (as->status == WLC_E_STATUS_TIMEOUT) {
22255 			WL_INFORM_MEM(("overriding reason code %d to %d\n",
22256 					as->reason, SET_SSID_FAIL_CUSTOM_RC));
22257 			as->reason = SET_SSID_FAIL_CUSTOM_RC;
22258 		}
22259 #endif /* SET_SSID_FAIL_CUSTOM_RC */
22260 
22261 		/* Report connect failure */
22262 		as->link_action = wl_set_link_action(assoc_state, false);
22263 	}
22264 #ifdef WL_NAN
22265 	else if ((as->status == WLC_E_STATUS_SUCCESS) &&
22266 			wl_cfgnan_is_enabled(cfg) &&
22267 			wl_get_drv_status(cfg, CONNECTED, as->ndev)) {
22268 		u8 *curbssid = wl_read_prof(cfg, as->ndev, WL_PROF_BSSID);
22269 		u8 *conn_req_bssid =
22270 			wl_read_prof(cfg, as->ndev, WL_PROF_LATEST_BSSID);
22271 
22272 		if (memcmp(curbssid, conn_req_bssid, ETHER_ADDR_LEN) == 0) {
22273 			wl_cfgnan_get_stats(cfg);
22274 		}
22275 	}
22276 #endif /* WL_NAN */
22277 
22278 	return;
22279 }
22280 
22281 #ifdef  WL_TWT
22282 static s32
wl_notify_twt_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)22283 wl_notify_twt_event(struct bcm_cfg80211 *cfg,
22284 		bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
22285 {
22286 	uint32 type;
22287 	type = ntoh32(e->event_type);
22288 	WL_DBG(("TWT event type %d\n", type));
22289 	return BCME_OK;
22290 }
22291 #endif /* WL_TWT */
22292 
22293 #define CHECK_AND_INCR_LEN(ret, len, maxlen) \
22294 	{ \
22295 		if ((ret < 0) || ((ret + len) > maxlen)) \
22296 			return len; \
22297 		len += ret; \
22298 	}
22299 u32
wl_cfg80211_debug_data_dump(struct net_device * dev,u8 * buf,u32 buf_len)22300 wl_cfg80211_debug_data_dump(struct net_device *dev, u8 *buf, u32 buf_len)
22301 {
22302 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22303 	u32 len = 0;
22304 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
22305 	s32 ret = 0;
22306 
22307 	BCM_REFERENCE(dhdp);
22308 	if ((!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
22309 		WL_INFORM(("driver not up.\n"));
22310 		return 0;
22311 	}
22312 
22313 	ret = snprintf(buf, buf_len, "\n[BCMLINUX]\nlock info:\n");
22314 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22315 
22316 	ret = snprintf(buf+len, buf_len-len,
22317 			"rtnl:%d\n"
22318 			"scan_sync:%d\n"
22319 			"usr_sync:%d\n"
22320 			"if_sync:%d\n"
22321 			"event_sync:%d\n"
22322 			"ioctl_buf:%d\n",
22323 			rtnl_is_locked(),  mutex_is_locked(&cfg->scan_sync),
22324 			mutex_is_locked(&cfg->usr_sync), mutex_is_locked(&cfg->if_sync),
22325 			mutex_is_locked(&cfg->event_sync), mutex_is_locked(&cfg->ioctl_buf_sync));
22326 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22327 
22328 #ifdef WL_NAN
22329 	ret = snprintf(buf+len, buf_len-len, "nan:%d\n", mutex_is_locked(&cfg->nancfg->nan_sync));
22330 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22331 #endif /* WL_NAN */
22332 #ifdef RTT_SUPPORT
22333 	{
22334 		rtt_status_info_t *rtt_status = GET_RTTSTATE(dhdp);
22335 		ret = snprintf(buf+len, buf_len-len, "rtt:%d\n",
22336 				mutex_is_locked(&rtt_status->rtt_mutex));
22337 		CHECK_AND_INCR_LEN(ret, len, buf_len);
22338 		ret = snprintf(buf+len, buf_len-len, "geofence:%d\n",
22339 				mutex_is_locked(&(rtt_status)->geofence_mutex));
22340 		CHECK_AND_INCR_LEN(ret, len, buf_len);
22341 	}
22342 #endif /* RTT_SUPPORT */
22343 #ifdef WL_BCNRECV
22344 	ret = snprintf(buf+len, buf_len-len, "bcn_sync:%d\n", mutex_is_locked(&cfg->bcn_sync));
22345 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22346 #endif /* WL_BCNRECV */
22347 #ifdef WLTDLS
22348 	ret = snprintf(buf+len, buf_len-len, "tdls_sync:%d\n", mutex_is_locked(&cfg->tdls_sync));
22349 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22350 #endif /* WLTDLS */
22351 	ret = snprintf(buf+len, buf_len-len, "cfgdrv:%d\n", spin_is_locked(&cfg->cfgdrv_lock));
22352 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22353 
22354 	ret = snprintf(buf+len, buf_len-len, "vndr_oui:%d\n", spin_is_locked(&cfg->vndr_oui_sync));
22355 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22356 
22357 	ret = snprintf(buf+len, buf_len-len, "net_list:%d\n", spin_is_locked(&cfg->net_list_sync));
22358 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22359 
22360 	ret = snprintf(buf+len, buf_len-len, "eq_lock:%d\n", spin_is_locked(&cfg->eq_lock));
22361 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22362 
22363 #ifdef WL_WPS_SYNC
22364 	ret = snprintf(buf+len, buf_len-len, "wps:%d\n", spin_is_locked(&cfg->wps_sync));
22365 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22366 #endif /* WL_WPS_SYNC */
22367 	ret = snprintf(buf+len, buf_len-len, "eidx.in_progress:0x%x eidx.event:0x%x",
22368 			cfg->eidx.in_progress, cfg->eidx.event_type);
22369 	CHECK_AND_INCR_LEN(ret, len, buf_len);
22370 	return len;
22371 }
22372 
22373 #ifdef WL_CLIENT_SAE
22374 static bool
wl_is_pmkid_available(struct net_device * dev,const u8 * bssid)22375 wl_is_pmkid_available(struct net_device *dev, const u8 *bssid)
22376 {
22377 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22378 	int i;
22379 
22380 	/* check the bssid is null or not */
22381 	if (!bssid) return FALSE;
22382 
22383 	for (i = 0; i < cfg->pmk_list->pmkids.count; i++) {
22384 		if (!memcmp(bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
22385 			ETHER_ADDR_LEN)) {
22386 			return TRUE;
22387 		}
22388 	}
22389 	return FALSE;
22390 }
22391 
22392 #define WL_AUTH_START_EVT_V0 0
22393 static s32
wl_notify_start_auth(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)22394 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
22395 	bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
22396 {
22397 	struct cfg80211_external_auth_params ext_auth_param;
22398 	struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22399 	u32 datalen = be32_to_cpu(e->datalen);
22400 #ifdef WL_AUTH_START_EVT_V0
22401 	wl_ext_auth_evt_t *evt_v0_data = (wl_ext_auth_evt_t *)data;
22402 #else
22403 	wl_auth_start_evt_t *evt_v1_data = (wl_auth_start_evt_t *)data;
22404 #endif
22405 	wl_assoc_mgr_cmd_t cmd;
22406 	struct wireless_dev *wdev = ndev->ieee80211_ptr;
22407 	int err, retry = 3;
22408 
22409 	WL_DBG(("Enter\n"));
22410 
22411 	if (!datalen || !data) {
22412 		WL_ERR(("Invalid data for auth start event\n"));
22413 		return BCME_ERROR;
22414 	}
22415 
22416 	ext_auth_param.action = NL80211_EXTERNAL_AUTH_START;
22417 	ext_auth_param.key_mgmt_suite = ntoh32(WLAN_AKM_SUITE_SAE_SHA256);
22418 #ifdef WL_AUTH_START_EVT_V0
22419 	(void)memcpy_s(&ext_auth_param.bssid, ETHER_ADDR_LEN, &evt_v0_data->bssid, ETHER_ADDR_LEN);
22420 	ext_auth_param.ssid.ssid_len = MIN(evt_v0_data->ssid.SSID_len, DOT11_MAX_SSID_LEN);
22421 	if (ext_auth_param.ssid.ssid_len) {
22422 		(void)memcpy_s(&ext_auth_param.ssid.ssid, ext_auth_param.ssid.ssid_len,
22423 			evt_v0_data->ssid.SSID, ext_auth_param.ssid.ssid_len);
22424 	}
22425 	WL_MSG(ndev->name, "BSSID "MACDBG"\n", MAC2STRDBG(&evt_v0_data->bssid));
22426 #else
22427 	(void)memcpy_s(&ext_auth_param.bssid, ETHER_ADDR_LEN, &evt_v1_data->bssid, ETHER_ADDR_LEN);
22428 	ext_auth_param.ssid.ssid_len = MIN(evt_v1_data->ssid.SSID_len, DOT11_MAX_SSID_LEN);
22429 	if (ext_auth_param.ssid.ssid_len) {
22430 		(void)memcpy_s(&ext_auth_param.ssid.ssid, ext_auth_param.ssid.ssid_len,
22431 			evt_v1_data->ssid.SSID, ext_auth_param.ssid.ssid_len);
22432 	}
22433 	WL_MSG(ndev->name, "BSSID "MACDBG", version=%d\n",
22434 		MAC2STRDBG(&evt_v1_data->bssid), evt_v1_data->version);
22435 #endif
22436 
22437 	/* Wait for conn_owner_nlportid been assigned in nl80211_connect */
22438 	for (retry = 3; retry > 0; retry--) {
22439 		if (wdev->conn_owner_nlportid) {
22440 			break;
22441 		}
22442 
22443 		wl_delay(10);
22444 	}
22445 
22446 #ifdef WL_EXT_IAPSTA
22447 	err = wl_ext_in4way_sync(ndev, STA_START_AUTH_DELAY, WL_EXT_STATUS_CONNECTING, NULL);
22448 	if (err) {
22449 		WL_ERR(("Failed to notify external auth req(%d)\n", err));
22450 		return BCME_ERROR;
22451 	}
22452 #endif
22453 
22454 	err = cfg80211_external_auth_request(ndev, &ext_auth_param, GFP_KERNEL);
22455 	if (err) {
22456 		WL_ERR(("Send external auth request failed, ret %d\n", err));
22457 		return BCME_ERROR;
22458 	}
22459 
22460 	cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
22461 	cmd.length = sizeof(cmd);
22462 	cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
22463 	cmd.params = WL_ASSOC_MGR_PARAMS_PAUSE_EVENT_AUTH_RESP;
22464 	err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd), cfg->ioctl_buf,
22465 		WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
22466 	if (unlikely(err)) {
22467 		WL_ERR(("Failed to pause assoc(%d)\n", err));
22468 	}
22469 
22470 	return BCME_OK;
22471 }
22472 
22473 s32
wl_handle_auth_event(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)22474 wl_handle_auth_event(struct bcm_cfg80211 *cfg, struct net_device *ndev,
22475 	const wl_event_msg_t *e, void *data)
22476 {
22477 	bcm_struct_cfgdev *cfgdev = ndev_to_cfgdev(ndev);
22478 	u8 bsscfgidx = e->bsscfgidx;
22479 	u8 *mgmt_frame = NULL;
22480 	u8 *body = NULL;
22481 	u32 body_len = 0;
22482 	s32 chan;
22483 	chanspec_t chanspec;
22484 	s32 freq;
22485 	struct ether_addr da;
22486 	struct ether_addr bssid;
22487 	u32 len = ntoh32(e->datalen);
22488 	u32 status = ntoh32(e->status);
22489 	int err = BCME_OK;
22490 
22491 	if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
22492 		return WL_INVALID;
22493 	}
22494 
22495 	if (!len) {
22496 		WL_ERR(("WLC_E_AUTH has no payload. status %d reason %d\n",
22497 			status, ntoh32(e->reason)));
22498 #ifdef WL_EXT_IAPSTA
22499 		if (status != WLC_E_STATUS_SUCCESS)
22500 			wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
22501 				WL_EXT_STATUS_DISCONNECTED, NULL);
22502 #endif
22503 		return WL_INVALID;
22504 	}
22505 
22506 	body = (u8 *)MALLOCZ(cfg->osh, len);
22507 	if (body == NULL) {
22508 		WL_ERR(("Failed to allocate body\n"));
22509 		return WL_INVALID;
22510 	}
22511 	(void)memcpy_s(body, len, data, len);
22512 
22513 	err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
22514 		NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
22515 	if (unlikely(err)) {
22516 		MFREE(cfg->osh, body, len);
22517 		WL_ERR(("Could not get cur_etheraddr %d\n", err));
22518 		return err;
22519 	}
22520 	(void)memcpy_s(da.octet, ETHER_ADDR_LEN, cfg->ioctl_buf, ETHER_ADDR_LEN);
22521 
22522 	bzero(&bssid, sizeof(bssid));
22523 	err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
22524 	/* Use e->addr as bssid for Sta case , before association completed */
22525 	if (err == BCME_NOTASSOCIATED) {
22526 		(void)memcpy_s(&bssid, ETHER_ADDR_LEN, &e->addr, ETHER_ADDR_LEN);
22527 		err = BCME_OK;
22528 	}
22529 	if (unlikely(err)) {
22530 		MFREE(cfg->osh, body, len);
22531 		WL_ERR(("Could not get bssid %d\n", err));
22532 		return err;
22533 	}
22534 
22535 	err = wldev_iovar_getint(ndev, "chanspec", &chan);
22536 	if (unlikely(err)) {
22537 		MFREE(cfg->osh, body, len);
22538 		WL_ERR(("Could not get chanspec %d\n", err));
22539 		return err;
22540 	}
22541 
22542 	chanspec = wl_chspec_driver_to_host(chan);
22543 	freq = wl_channel_to_frequency(wf_chspec_ctlchan(chanspec), CHSPEC_BAND(chanspec));
22544 
22545 	body_len = len;
22546 	err = wl_frame_get_mgmt(cfg, FC_AUTH, &da, &e->addr, &bssid,
22547 		&mgmt_frame, &len, body);
22548 	if (!err) {
22549 #ifdef WL_EXT_IAPSTA
22550 		wl_ext_update_extsae_4way(ndev, (struct ieee80211_mgmt *)mgmt_frame, FALSE);
22551 #endif
22552 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
22553 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0);
22554 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
22555 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
22556 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
22557 		cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
22558 #else
22559 		cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
22560 #endif
22561 		MFREE(cfg->osh, mgmt_frame, len);
22562 	}
22563 
22564 	if (body) {
22565 		MFREE(cfg->osh, body, body_len);
22566 	}
22567 
22568 	return BCME_OK;
22569 }
22570 
22571 /** Called by the cfg80211 framework */
22572 static s32
wl_cfg80211_external_auth(struct wiphy * wiphy,struct net_device * ndev,struct cfg80211_external_auth_params * ext_auth_param)22573 wl_cfg80211_external_auth(struct wiphy *wiphy,
22574 	struct net_device *ndev, struct cfg80211_external_auth_params *ext_auth_param)
22575 {
22576 	int err = 0;
22577 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
22578 	wl_assoc_mgr_cmd_t cmd;
22579 
22580 	WL_DBG(("Enter\n"));
22581 
22582 	if (!ext_auth_param ||
22583 		ETHER_ISNULLADDR(ext_auth_param->bssid)) {
22584 		WL_ERR(("Invalid param\n"));
22585 		return -EINVAL;
22586 	}
22587 
22588 	cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
22589 	cmd.length = sizeof(cmd);
22590 	cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
22591 	cmd.params = WL_ASSOC_MGR_PARAMS_EVENT_NONE;
22592 	err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd),
22593 		cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
22594 	if (unlikely(err)) {
22595 		WL_ERR(("Failed to pause assoc(%d)\n", err));
22596 	}
22597 
22598 	return err;
22599 }
22600 
22601 static s32
wl_cfg80211_mgmt_auth_tx(struct net_device * dev,bcm_struct_cfgdev * cfgdev,struct bcm_cfg80211 * cfg,const u8 * buf,size_t len,s32 bssidx,u64 * cookie)22602 wl_cfg80211_mgmt_auth_tx(struct net_device *dev, bcm_struct_cfgdev *cfgdev,
22603 	struct bcm_cfg80211 *cfg, const u8 *buf, size_t len, s32 bssidx, u64 *cookie)
22604 {
22605 	int err = 0;
22606 	wl_assoc_mgr_cmd_t *cmd;
22607 	char *ambuf = NULL;
22608 	int param_len;
22609 	bool ack = true;
22610 
22611 	param_len = sizeof(wl_assoc_mgr_cmd_t) + len;
22612 	ambuf = MALLOCZ(cfg->osh, param_len);
22613 	if (ambuf == NULL) {
22614 		WL_ERR(("unable to allocate frame\n"));
22615 		return -ENOMEM;
22616 	}
22617 
22618 	cmd = (wl_assoc_mgr_cmd_t*)ambuf;
22619 	cmd->version = WL_ASSOC_MGR_CURRENT_VERSION;
22620 	cmd->length = len;
22621 	cmd->cmd = WL_ASSOC_MGR_CMD_SEND_AUTH;
22622 	err = memcpy_s(&cmd->params, len, buf, len);
22623 	if (err) {
22624 		WL_ERR(("Failed to copy cmd params(%d)\n", err));
22625 		ack = false;
22626 	} else {
22627 		err = wldev_iovar_setbuf(dev, "assoc_mgr_cmd", ambuf, param_len,
22628 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
22629 		if (unlikely(err)) {
22630 			WL_ERR(("Failed to send auth(%d)\n", err));
22631 			ack = false;
22632 		}
22633 #ifdef WL_EXT_IAPSTA
22634 		else {
22635 			const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *)buf;
22636 			wl_ext_update_extsae_4way(dev, mgmt, TRUE);
22637 		}
22638 #endif
22639 	}
22640 
22641 	MFREE(cfg->osh, ambuf, param_len);
22642 
22643 	cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
22644 	return BCME_OK;
22645 }
22646 #endif /* WL_CLIENT_SAE */
22647 
22648 s32
wl_cfg80211_autochannel(struct net_device * dev,char * command,int total_len)22649 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len)
22650 {
22651 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22652 	int ret = 0;
22653 	int bytes_written = -1;
22654 
22655 	sscanf(command, "%*s %d", &cfg->autochannel);
22656 
22657 	if (cfg->autochannel == 0) {
22658 		cfg->best_2g_ch = 0;
22659 		cfg->best_5g_ch = 0;
22660 	} else if (cfg->autochannel == 2) {
22661 		bytes_written = snprintf(command, total_len, "2g=%d 5g=%d",
22662 			cfg->best_2g_ch, cfg->best_5g_ch);
22663 		WL_TRACE(("command result is %s\n", command));
22664 		ret = bytes_written;
22665 	}
22666 
22667 	return ret;
22668 }
22669