1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * Linux cfg80211 driver
4 *
5 * Copyright (C) 1999-2019, Broadcom.
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 *
26 * <<Broadcom-WL-IPTag/Open:>>
27 *
28 * $Id: wl_cfg80211.c 826086 2019-06-18 19:23:59Z $
29 */
30 /* */
31 #include <typedefs.h>
32 #include <linuxver.h>
33 #include <linux/kernel.h>
34 #ifdef CONFIG_AP6XXX_WIFI6_HDF
35 #include "hdf_bdh_event.h"
36 #endif
37 #include <bcmutils.h>
38 #include <bcmstdlib_s.h>
39 #include <bcmwifi_channels.h>
40 #include <bcmendian.h>
41 #include <ethernet.h>
42 #ifdef WL_WPS_SYNC
43 #include <eapol.h>
44 #endif /* WL_WPS_SYNC */
45 #include <802.11.h>
46 #include <bcmiov.h>
47 #include <linux/if_arp.h>
48 #include <linux/uaccess.h>
49
50 #include <ethernet.h>
51 #include <linux/kernel.h>
52 #include <linux/kthread.h>
53 #include <linux/netdevice.h>
54 #include <linux/sched.h>
55 #include <linux/etherdevice.h>
56 #include <linux/wireless.h>
57 #include <linux/ieee80211.h>
58 #include <linux/wait.h>
59 #include <net/cfg80211.h>
60 #include <net/rtnetlink.h>
61
62 #include <wlioctl.h>
63 #include <bcmevent.h>
64 #include <wldev_common.h>
65 #include <wl_cfg80211.h>
66 #include <wl_cfgp2p.h>
67 #include <wl_cfgscan.h>
68 #include <bcmdevs.h>
69 #ifdef WL_FILS
70 #include <fils.h>
71 #include <frag.h>
72 #endif /* WL_FILS */
73 #include <wl_android.h>
74 #include <dngl_stats.h>
75 #include <dhd.h>
76 #include <dhd_linux.h>
77 #include <dhd_linux_pktdump.h>
78 #include <dhd_debug.h>
79 #include <dhdioctl.h>
80 #include <wlioctl.h>
81 #include <dhd_cfg80211.h>
82 #include <dhd_bus.h>
83 #ifdef PNO_SUPPORT
84 #include <dhd_pno.h>
85 #endif /* PNO_SUPPORT */
86 #include <wl_cfgvendor.h>
87
88 #if !defined(WL_VENDOR_EXT_SUPPORT)
89 #undef GSCAN_SUPPORT
90 #endif
91 #include <dhd_config.h>
92
93 #ifdef WL_NAN
94 #include <wl_cfgnan.h>
95 #endif /* WL_NAN */
96
97 #ifdef PROP_TXSTATUS
98 #include <dhd_wlfc.h>
99 #endif // endif
100
101 #ifdef BCMPCIE
102 #include <dhd_flowring.h>
103 #endif // endif
104 #ifdef RTT_SUPPORT
105 #include <dhd_rtt.h>
106 #endif /* RTT_SUPPORT */
107
108 #define BRCM_SAE_VENDOR_EVENT_BUF_LEN 500
109
110 #ifdef DNGL_AXI_ERROR_LOGGING
111 #include <bcmtlv.h>
112 #endif /* DNGL_AXI_ERROR_LOGGING */
113
114 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
115 #include <linux/dev_ril_bridge.h>
116 #include <linux/notifier.h>
117 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
118
119 #ifdef BCMWAPI_WPI
120 /* these items should evetually go into wireless.h of the linux system headfile dir */
121 #ifndef IW_ENCODE_ALG_SM4
122 #define IW_ENCODE_ALG_SM4 0x20
123 #endif // endif
124
125 #ifndef IW_AUTH_WAPI_ENABLED
126 #define IW_AUTH_WAPI_ENABLED 0x20
127 #endif // endif
128
129 #ifndef IW_AUTH_WAPI_VERSION_1
130 #define IW_AUTH_WAPI_VERSION_1 0x00000008
131 #endif // endif
132
133 #ifndef IW_AUTH_CIPHER_SMS4
134 #define IW_AUTH_CIPHER_SMS4 0x00000020
135 #endif // endif
136
137 #ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
138 #define IW_AUTH_KEY_MGMT_WAPI_PSK 4
139 #endif // endif
140
141 #ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
142 #define IW_AUTH_KEY_MGMT_WAPI_CERT 8
143 #endif // endif
144 #endif /* BCMWAPI_WPI */
145
146 #ifdef BCMWAPI_WPI
147 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
148 #else /* BCMWAPI_WPI */
149 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
150 #endif /* BCMWAPI_WPI */
151
152 #if (defined(WL_FW_OCE_AP_SELECT) || defined(BCMFW_ROAM_ENABLE) && ((LINUX_VERSION_CODE \
153 >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)))
154 uint fw_ap_select = true;
155 #else
156 uint fw_ap_select = false;
157 #endif /* WL_FW_OCE_AP_SELECT && (ROAM_ENABLE || BCMFW_ROAM_ENABLE) */
158 module_param(fw_ap_select, uint, 0660);
159
160 static struct device *cfg80211_parent_dev = NULL;
161 static struct bcm_cfg80211 *g_bcmcfg = NULL;
162 //u32 wl_dbg_level = 0xff;
163 u32 wl_dbg_level = WL_DBG_ERR; // | WL_DBG_P2P_ACTION | WL_DBG_INFO;
164
165 #define MAX_VIF_OFFSET 15
166 #define MAX_WAIT_TIME 1500
167 #ifdef WLAIBSS_MCHAN
168 #define IBSS_IF_NAME "ibss%d"
169 #endif /* WLAIBSS_MCHAN */
170
171 #ifdef VSDB
172 /* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
173 #define DEFAULT_SLEEP_TIME_VSDB 120
174 #define OFF_CHAN_TIME_THRESHOLD_MS 200
175 #define AF_RETRY_DELAY_TIME 40
176
177 /* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
178 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
179 do { \
180 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
181 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
182 OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
183 } \
184 } while (0)
185 #else /* VSDB */
186 /* if not VSDB, do nothing */
187 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
188 #endif /* VSDB */
189
190 #define DNGL_FUNC(func, parameters) func parameters
191 #define COEX_DHCP
192
193 #define WLAN_EID_SSID 0
194 #define CH_MIN_5G_CHANNEL 34
195
196 #ifdef WL_RELMCAST
197 enum rmc_event_type {
198 RMC_EVENT_NONE,
199 RMC_EVENT_LEADER_CHECK_FAIL
200 };
201 #endif /* WL_RELMCAST */
202
203 #ifdef CONFIG_AP6XXX_WIFI6_HDF
204 #include "hdf_wl_interface.h"
205 #include "net_device.h"
206 int32_t HdfWifiEventMgmtTxStatus(const struct NetDevice *netDev, const uint8_t *buf, size_t len, uint8_t ack);
207 int32_t HdfWifiEventRxMgmt(const struct NetDevice *netDev, int32_t freq, int32_t sigMbm, const uint8_t *buf, size_t len);
208 int32_t HdfWifiEventCsaChannelSwitch(const struct NetDevice *netDev, int32_t freq);
209 int32_t HdfWifiEventRemainOnChannel(const struct NetDevice *netDev, uint32_t freq, uint32_t duration);
210
211 struct NetDevice * GetHdfNetDeviceByLinuxInf(struct net_device *dev);
212
213 int ChangNewSta(struct net_device *dev, const uint8_t *macAddr, uint8_t addrLen,
214 const struct station_info *info);
215 int ChangDelSta(struct net_device *dev,const uint8_t *macAddr, uint8_t addrLen);
216 extern void HdfInformBssFrameEventCallback(struct net_device *ndev, const struct InnerBssInfo *innerBssInfo);
217 extern int32_t HdfConnectResultEventCallback(struct net_device *ndev, const struct InnerConnetResult *innerConnResult);
218
219 extern int g_event_ifidx;
220 extern struct hdf_inf_map g_hdf_infmap[HDF_INF_MAX];
221 struct NetDevice * get_hdf_netdev(int ifidx);
222 extern int g_mgmt_tx_event_ifidx;
223
224 #endif
225
226 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
227 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
228 * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
229 * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
230 * All the chnages in world regulatory domain are to be done here.
231 *
232 * this definition reuires disabling missing-field-initializer warning
233 * as the ieee80211_regdomain definition differs in plain linux and in Android
234 */
235 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
236 4 && __GNUC_MINOR__ >= 6))
237 _Pragma("GCC diagnostic push")
238 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
239 #endif // endif
240 static const struct ieee80211_regdomain brcm_regdom = {
241 .n_reg_rules = 4,
242 .alpha2 = "99",
243 .reg_rules = {
244 /* IEEE 802.11b/g, channels 1..11 */
245 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
246 /* If any */
247 /* IEEE 802.11 channel 14 - Only JP enables
248 * this and for 802.11b only
249 */
250 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
251 /* IEEE 802.11a, channel 36..64 */
252 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
253 /* IEEE 802.11a, channel 100..165 */
254 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
255 };
256
257 #ifdef CONFIG_AP6XXX_WIFI6_HDF
bdh6_get_regdomain(void)258 const struct ieee80211_regdomain * bdh6_get_regdomain(void)
259 {
260 return &brcm_regdom;
261 }
262 #endif
263
264 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
265 4 && __GNUC_MINOR__ >= 6))
266 _Pragma("GCC diagnostic pop")
267 #endif // endif
268
269 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
270 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
271 static const struct ieee80211_iface_limit common_if_limits[] = {
272 {
273 /*
274 * Driver can support up to 2 AP's
275 */
276 .max = 2,
277 .types = BIT(NL80211_IFTYPE_AP),
278 },
279 {
280 /*
281 * During P2P-GO removal, P2P-GO is first changed to STA and later only
282 * removed. So setting maximum possible number of STA interfaces according
283 * to kernel version.
284 *
285 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
286 * linux-3.8 and above - max:4
287 * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
288 * for NAN defined, registering it as STA type)
289 */
290 #ifdef WL_ENABLE_P2P_IF
291 .max = 5,
292 #else
293 .max = 4,
294 #endif /* WL_ENABLE_P2P_IF */
295 .types = BIT(NL80211_IFTYPE_STATION),
296 },
297 {
298 .max = 2,
299 .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
300 },
301 #if defined(WL_CFG80211_P2P_DEV_IF)
302 {
303 .max = 1,
304 .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
305 },
306 #endif /* WL_CFG80211_P2P_DEV_IF */
307 {
308 .max = 1,
309 .types = BIT(NL80211_IFTYPE_ADHOC),
310 },
311 };
312
313 #define NUM_DIFF_CHANNELS 2
314
315 static const struct ieee80211_iface_combination
316 common_iface_combinations[] = {
317 {
318 .num_different_channels = NUM_DIFF_CHANNELS,
319 /*
320 * At Max 5 network interfaces can be registered concurrently
321 */
322 .max_interfaces = IFACE_MAX_CNT,
323 .limits = common_if_limits,
324 .n_limits = ARRAY_SIZE(common_if_limits),
325 },
326 };
327 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
328
329 static const char *wl_if_state_strs[WL_IF_STATE_MAX + 1] = {
330 "WL_IF_CREATE_REQ",
331 "WL_IF_CREATE_DONE",
332 "WL_IF_DELETE_REQ",
333 "WL_IF_DELETE_DONE",
334 "WL_IF_CHANGE_REQ",
335 "WL_IF_CHANGE_DONE",
336 "WL_IF_STATE_MAX"
337 };
338
339 #ifdef BCMWAPI_WPI
340 #if defined(ANDROID_PLATFORM_VERSION) && (ANDROID_PLATFORM_VERSION >= 8)
341 /* WAPI define in ieee80211.h is used */
342 #else
343 #undef WLAN_AKM_SUITE_WAPI_PSK
344 #define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04
345
346 #undef WLAN_AKM_SUITE_WAPI_CERT
347 #define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12
348
349 #undef NL80211_WAPI_VERSION_1
350 #define NL80211_WAPI_VERSION_1 1 << 2
351 #endif /* ANDROID_PLATFORM_VERSION && ANDROID_PLATFORM_VERSION >= 8 */
352 #endif /* BCMWAPI_WPI */
353
354 /* Data Element Definitions */
355 #define WPS_ID_CONFIG_METHODS 0x1008
356 #define WPS_ID_REQ_TYPE 0x103A
357 #define WPS_ID_DEVICE_NAME 0x1011
358 #define WPS_ID_VERSION 0x104A
359 #define WPS_ID_DEVICE_PWD_ID 0x1012
360 #define WPS_ID_REQ_DEV_TYPE 0x106A
361 #define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
362 #define WPS_ID_PRIM_DEV_TYPE 0x1054
363
364 /* Device Password ID */
365 #define DEV_PW_DEFAULT 0x0000
366 #define DEV_PW_USER_SPECIFIED 0x0001,
367 #define DEV_PW_MACHINE_SPECIFIED 0x0002
368 #define DEV_PW_REKEY 0x0003
369 #define DEV_PW_PUSHBUTTON 0x0004
370 #define DEV_PW_REGISTRAR_SPECIFIED 0x0005
371
372 /* Config Methods */
373 #define WPS_CONFIG_USBA 0x0001
374 #define WPS_CONFIG_ETHERNET 0x0002
375 #define WPS_CONFIG_LABEL 0x0004
376 #define WPS_CONFIG_DISPLAY 0x0008
377 #define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
378 #define WPS_CONFIG_INT_NFC_TOKEN 0x0020
379 #define WPS_CONFIG_NFC_INTERFACE 0x0040
380 #define WPS_CONFIG_PUSHBUTTON 0x0080
381 #define WPS_CONFIG_KEYPAD 0x0100
382 #define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
383 #define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
384 #define WPS_CONFIG_VIRT_DISPLAY 0x2008
385 #define WPS_CONFIG_PHY_DISPLAY 0x4008
386
387 #define PM_BLOCK 1
388 #define PM_ENABLE 0
389
390 /* GCMP crypto supported above kernel v4.0 */
391 #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0))
392 #define WL_GCMP
393 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0) */
394
395 #ifndef IBSS_COALESCE_ALLOWED
396 #define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT
397 #endif // endif
398
399 #ifndef IBSS_INITIAL_SCAN_ALLOWED
400 #define IBSS_INITIAL_SCAN_ALLOWED IBSS_INITIAL_SCAN_ALLOWED_DEFAULT
401 #endif // endif
402
403 #define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
404 #define LONG_LISTEN_TIME 2000
405
406 #ifdef RTT_SUPPORT
407 static s32 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
408 const wl_event_msg_t *e, void *data);
409 #endif /* RTT_SUPPORT */
410 #ifdef WL_CHAN_UTIL
411 static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg,
412 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
413 static s32 wl_cfg80211_start_bssload_report(struct net_device *ndev);
414 #endif /* WL_CHAN_UTIL */
415
416 #ifdef SUPPORT_AP_RADIO_PWRSAVE
417 #define RADIO_PWRSAVE_PPS 10
418 #define RADIO_PWRSAVE_QUIET_TIME 10
419 #define RADIO_PWRSAVE_LEVEL 3
420 #define RADIO_PWRSAVE_STAS_ASSOC_CHECK 0
421
422 #define RADIO_PWRSAVE_LEVEL_MIN 1
423 #define RADIO_PWRSAVE_LEVEL_MAX 9
424 #define RADIO_PWRSAVE_PPS_MIN 1
425 #define RADIO_PWRSAVE_QUIETTIME_MIN 1
426 #define RADIO_PWRSAVE_ASSOCCHECK_MIN 0
427 #define RADIO_PWRSAVE_ASSOCCHECK_MAX 1
428
429 #define RADIO_PWRSAVE_MAJOR_VER 1
430 #define RADIO_PWRSAVE_MINOR_VER 1
431 #define RADIO_PWRSAVE_MAJOR_VER_SHIFT 8
432 #define RADIO_PWRSAVE_VERSION \
433 ((RADIO_PWRSAVE_MAJOR_VER << RADIO_PWRSAVE_MAJOR_VER_SHIFT)| RADIO_PWRSAVE_MINOR_VER)
434 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
435
436 /* SoftAP related parameters */
437 #define DEFAULT_2G_SOFTAP_CHANNEL 1
438 #define DEFAULT_5G_SOFTAP_CHANNEL 149
439 #define WL_MAX_NUM_CSA_COUNTERS 255
440
441 #define MAX_VNDR_OUI_STR_LEN 256u
442 #define VNDR_OUI_STR_LEN 10u
443 #define DOT11_DISCONNECT_RC 2u
444 static const uchar *exclude_vndr_oui_list[] = {
445 "\x00\x50\xf2", /* Microsoft */
446 "\x00\x00\xf0", /* Samsung Elec */
447 WFA_OUI, /* WFA */
448 NULL
449 };
450
451 typedef struct wl_vndr_oui_entry {
452 uchar oui[DOT11_OUI_LEN];
453 struct list_head list;
454 } wl_vndr_oui_entry_t;
455
456 #if defined(WL_DISABLE_HE_SOFTAP) || defined(WL_DISABLE_HE_P2P) || \
457 defined(SUPPORT_AP_BWCTRL)
458 #define WL_HE_FEATURES_HE_AP 0x8
459 #define WL_HE_FEATURES_HE_P2P 0x20
460 #endif // endif
461
462 static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
463 struct net_device *ndev, char *vndr_oui, u32 vndr_oui_len);
464 static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg);
465 static s32 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
466 struct parsed_vndr_ies *vndr_ies);
467
468 #if defined(WL_FW_OCE_AP_SELECT)
469 static bool
470 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
471
472 /* Check whether the given IE looks like WFA OCE IE. */
473 #define wl_cfgoce_is_oce_ie(ie, tlvs, len) wl_cfgoce_has_ie(ie, tlvs, len, \
474 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_MBO_OCE)
475
476 /* Is any of the tlvs the expected entry? If
477 * not update the tlvs buffer pointer/length.
478 */
479 static bool
wl_cfgoce_has_ie(const u8 * ie,const u8 ** tlvs,u32 * tlvs_len,const u8 * oui,u32 oui_len,u8 type)480 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
481 {
482 /* If the contents match the OUI and the type */
483 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
484 !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
485 type == ie[TLV_BODY_OFF + oui_len]) {
486 return TRUE;
487 }
488
489 return FALSE;
490 }
491 #endif /* WL_FW_OCE_AP_SELECT */
492
493 /*
494 * cfg80211_ops api/callback list
495 */
496 static s32 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
497 const struct ether_addr *da, const struct ether_addr *sa,
498 const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody);
499 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
500 #ifdef WLAIBSS_MCHAN
501 static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name);
502 static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
503 #endif /* WLAIBSS_MCHAN */
504 static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
505 struct cfg80211_ibss_params *params);
506 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
507 struct net_device *dev);
508 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
509 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
510 struct net_device *dev, const u8 *mac,
511 struct station_info *sinfo);
512 #else
513 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
514 struct net_device *dev, u8 *mac,
515 struct station_info *sinfo);
516 #endif // endif
517 static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
518 struct net_device *dev, bool enabled,
519 s32 timeout);
520 #ifndef CONFIG_AP6XXX_WIFI6_HDF
521 static
522 #endif
523 int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
524 struct cfg80211_connect_params *sme);
525 #if defined(WL_FILS)
526 static int wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
527 struct cfg80211_connect_params *sme, u32 changed);
528 #endif /* WL_FILS */
529 #ifndef CONFIG_AP6XXX_WIFI6_HDF
530 static
531 #endif
532 s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
533 u16 reason_code);
534 #if defined(WL_CFG80211_P2P_DEV_IF)
535 static s32
536 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
537 enum nl80211_tx_power_setting type, s32 mbm);
538 #else
539 static s32
540 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
541 enum nl80211_tx_power_setting type, s32 dbm);
542 #endif /* WL_CFG80211_P2P_DEV_IF */
543 #if defined(WL_CFG80211_P2P_DEV_IF)
544 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
545 struct wireless_dev *wdev, s32 *dbm);
546 #else
547 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
548 #endif /* WL_CFG80211_P2P_DEV_IF */
549 static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
550 struct net_device *dev,
551 u8 key_idx, bool unicast, bool multicast);
552 static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
553 u8 key_idx, bool pairwise, const u8 *mac_addr,
554 struct key_params *params);
555 static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
556 u8 key_idx, bool pairwise, const u8 *mac_addr);
557 static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
558 u8 key_idx, bool pairwise, const u8 *mac_addr,
559 void *cookie, void (*callback) (void *cookie,
560 struct key_params *params));
561 static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
562 struct net_device *dev, u8 key_idx);
563 static s32 wl_cfg80211_resume(struct wiphy *wiphy);
564 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
565 2, 0))
566 static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
567 bcm_struct_cfgdev *cfgdev, u64 cookie);
568 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
569 static s32 wl_cfg80211_del_station(
570 struct wiphy *wiphy, struct net_device *ndev,
571 struct station_del_parameters *params);
572 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
573 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
574 struct net_device *ndev, const u8* mac_addr);
575 #else
576 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
577 struct net_device *ndev, u8* mac_addr);
578 #endif // endif
579 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
580 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
581 struct net_device *dev, const u8 *mac, struct station_parameters *params);
582 #else
583 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
584 struct net_device *dev, u8 *mac, struct station_parameters *params);
585 #endif // endif
586 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
587 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
588 static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
589 #else
590 static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
591 #endif // endif
592 static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
593 struct cfg80211_pmksa *pmksa);
594 static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
595 struct cfg80211_pmksa *pmksa);
596 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
597 struct net_device *dev);
598 #ifdef WL_CLIENT_SAE
599 static bool wl_is_pmkid_available(struct net_device *dev, const u8 *bssid);
600 #endif /* WL_CLIENT_SAE */
601 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
602 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
603 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
604 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
605 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
606 u32 peer_capability, const u8 *buf, size_t len);
607 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
608 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
609 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
610 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
611 u32 peer_capability, const u8 *buf, size_t len);
612 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
613 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
614 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
615 u32 peer_capability, bool initiator, const u8 *buf, size_t len);
616 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
617 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
618 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
619 const u8 *buf, size_t len);
620 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
621 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
622 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
623 const u8 *peer, enum nl80211_tdls_operation oper);
624 #else
625 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
626 u8 *peer, enum nl80211_tdls_operation oper);
627 #endif // endif
628 #endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
629 static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg, struct net_device *dev);
630
631 struct wireless_dev *
632 wl_cfg80211_create_iface(struct wiphy *wiphy, wl_iftype_t
633 iface_type, u8 *mac_addr, const char *name);
634 s32
635 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
636
637 s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
638 struct net_device *ndev, s32 bsscfg_idx,
639 wl_iftype_t iftype, s32 del, u8 *addr);
640 s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
641 struct net_device *ndev, s32 bsscfg_idx,
642 wl_iftype_t brcm_iftype, s32 del, u8 *addr);
643 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
644 static s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev);
645 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */
646 #ifdef GTK_OFFLOAD_SUPPORT
647 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
648 static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
649 struct cfg80211_gtk_rekey_data *data);
650 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
651 #endif /* GTK_OFFLOAD_SUPPORT */
652 chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
653 chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
654 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev);
655 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
656 int wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
657 struct cfg80211_csa_settings *params);
658 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
659
660 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
661 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
662 const struct cfg80211_pmk_conf *conf);
663 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
664 const u8 *aa);
665 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
666
667 /*
668 * event & event Q handlers for cfg80211 interfaces
669 */
670 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
671 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
672 static void wl_event_handler(struct work_struct *work_data);
673 static void wl_init_eq(struct bcm_cfg80211 *cfg);
674 static void wl_flush_eq(struct bcm_cfg80211 *cfg);
675 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
676 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
677 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
678 static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
679 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
680 static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
681 const wl_event_msg_t *msg, void *data);
682 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e);
683 static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
684 const wl_event_msg_t *e, void *data);
685 static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
686 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
687 static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
688 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
689 static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
690 const wl_event_msg_t *e, void *data, bool completed);
691 static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
692 const wl_event_msg_t *e, void *data);
693 static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
694 const wl_event_msg_t *e, void *data);
695 #ifdef BT_WIFI_HANDOVER
696 static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
697 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
698 #endif /* BT_WIFI_HANDOVER */
699 #ifdef GSCAN_SUPPORT
700 static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
701 const wl_event_msg_t *e, void *data);
702 #endif /* GSCAN_SUPPORT */
703 #ifdef RSSI_MONITOR_SUPPORT
704 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
705 const wl_event_msg_t *e, void *data);
706 #endif /* RSSI_MONITOR_SUPPORT */
707 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
708 enum wl_status state, bool set);
709 #ifdef CUSTOM_EVENT_PM_WAKE
710 static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
711 const wl_event_msg_t *e, void *data);
712 #endif /* CUSTOM_EVENT_PM_WAKE */
713 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
714 static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
715 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
716 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
717 #ifdef DHD_LOSSLESS_ROAMING
718 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
719 #endif /* DHD_LOSSLESS_ROAMING */
720
721 #ifdef WL_MBO
722 static s32
723 wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
724 const wl_event_msg_t *e, void *data);
725 #endif /* WL_MBO */
726
727 #ifdef WL_CLIENT_SAE
728 static s32 wl_notify_connect_status_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
729 const wl_event_msg_t *e, void *data);
730 static s32 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
731 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
732 static s32 wl_cfg80211_external_auth(struct wiphy *wiphy,
733 struct net_device *dev, struct cfg80211_external_auth_params *ext_auth);
734 #endif /* WL_CLIENT_SAE */
735
736 /*
737 * register/deregister parent device
738 */
739 static void wl_cfg80211_clear_parent_dev(void);
740 /*
741 * ioctl utilites
742 */
743
744 /*
745 * cfg80211 set_wiphy_params utilities
746 */
747 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
748 static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
749 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
750
751 /*
752 * cfg profile utilities
753 */
754 static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
755 const wl_event_msg_t *e, const void *data, s32 item);
756 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
757
758 /*
759 * cfg80211 connect utilites
760 */
761 static s32 wl_set_wpa_version(struct net_device *dev,
762 struct cfg80211_connect_params *sme);
763 static s32 wl_set_auth_type(struct net_device *dev,
764 struct cfg80211_connect_params *sme);
765 static s32 wl_set_set_cipher(struct net_device *dev,
766 struct cfg80211_connect_params *sme);
767 static s32 wl_set_key_mgmt(struct net_device *dev,
768 struct cfg80211_connect_params *sme);
769 static s32 wl_set_set_sharedkey(struct net_device *dev,
770 struct cfg80211_connect_params *sme);
771 #ifdef WL_FILS
772 static s32 wl_set_fils_params(struct net_device *dev,
773 struct cfg80211_connect_params *sme);
774 #endif // endif
775 #ifdef BCMWAPI_WPI
776 static s32 wl_set_set_wapi_ie(struct net_device *dev,
777 struct cfg80211_connect_params *sme);
778 #endif // endif
779 #ifdef WL_GCMP
780 static s32 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask);
781 #endif /* WL_GCMP */
782 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
783 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch,
784 struct wl_join_params *join_params, size_t *join_params_size);
785 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
786
787 /*
788 * information element utilities
789 */
790 static void wl_rst_ie(struct bcm_cfg80211 *cfg);
791 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
792 static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 *ie_size,
793 bool update_ssid);
794 static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size);
795 static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size);
796 static u32 wl_get_ielen(struct bcm_cfg80211 *cfg);
797 #ifdef MFP
798 static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie, const u8** rsn_cap);
799 #endif // endif
800
801 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, dhd_pub_t *data);
802 static void wl_free_wdev(struct bcm_cfg80211 *cfg);
803 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
804 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
805 static int
806 #else
807 static void
808 #endif /* kernel version < 3.10.11 */
809 wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
810 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
811
812 static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool update_ssid);
813 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool update_ssid);
814 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
815 s32 wl_cfg80211_channel_to_freq(u32 channel);
816 static void wl_cfg80211_work_handler(struct work_struct *work);
817 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
818 u8 key_idx, const u8 *mac_addr,
819 struct key_params *params);
820 /*
821 * key indianess swap utilities
822 */
823 static void swap_key_from_BE(struct wl_wsec_key *key);
824 static void swap_key_to_BE(struct wl_wsec_key *key);
825
826 /*
827 * bcm_cfg80211 memory init/deinit utilities
828 */
829 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
830 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
831
832 static void wl_delay(u32 ms);
833
834 /*
835 * ibss mode utilities
836 */
837 static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev);
838 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
839
840 /*
841 * link up/down , default configuration utilities
842 */
843 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
844 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
845 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
846
847 static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
848 struct net_device *ndev);
849 static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
850 static void wl_link_up(struct bcm_cfg80211 *cfg);
851 static void wl_link_down(struct bcm_cfg80211 *cfg);
852 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype);
853 static void wl_init_conf(struct wl_conf *conf);
854 int wl_cfg80211_get_ioctl_version(void);
855
856 /*
857 * find most significant bit set
858 */
859 static __used u32 wl_find_msb(u16 bit16);
860
861 /*
862 * rfkill support
863 */
864 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
865 static int wl_rfkill_set(void *data, bool blocked);
866 #ifdef DEBUGFS_CFG80211
867 static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg);
868 static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg);
869 #endif // endif
870 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
871
872 #ifdef WL_CFG80211_ACL
873 /* ACL */
874 static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
875 const struct cfg80211_acl_data *acl);
876 #endif /* WL_CFG80211_ACL */
877
878 /*
879 * Some external functions, TODO: move them to dhd_linux.h
880 */
881 int dhd_add_monitor(const char *name, struct net_device **new_ndev);
882 int dhd_del_monitor(struct net_device *ndev);
883 int dhd_monitor_init(void *dhd_pub);
884 int dhd_monitor_uninit(void);
885 netdev_tx_t dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
886
887 #ifdef ESCAN_CHANNEL_CACHE
888 void reset_roam_cache(struct bcm_cfg80211 *cfg);
889 void add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi);
890 int get_roam_channel_list(int target_chan, chanspec_t *channels,
891 int n_channels, const wlc_ssid_t *ssid, int ioctl_ver);
892 void set_roam_band(int band);
893 #endif /* ESCAN_CHANNEL_CACHE */
894
895 #ifdef ROAM_CHANNEL_CACHE
896 int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
897 void print_roam_cache(struct bcm_cfg80211 *cfg);
898 void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
899 #endif /* ROAM_CHANNEL_CACHE */
900
901 #ifdef P2P_LISTEN_OFFLOADING
902 s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
903 #endif /* P2P_LISTEN_OFFLOADING */
904
905 #ifdef PKT_FILTER_SUPPORT
906 extern uint dhd_pkt_filter_enable;
907 extern uint dhd_master_mode;
908 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
909 #endif /* PKT_FILTER_SUPPORT */
910
911 #ifdef SUPPORT_SET_CAC
912 static void wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable);
913 #endif /* SUPPORT_SET_CAC */
914
915 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
916 const struct ether_addr *bssid);
917 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
918
919 #ifdef WL_WPS_SYNC
920 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg);
921 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg);
922 static void wl_wps_reauth_timeout(unsigned long data);
923 static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg);
924 static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev);
925 static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *peer_mac);
926 static void wl_wps_session_del(struct net_device *ndev);
927 static s32 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac);
928 static void wl_wps_handle_ifdel(struct net_device *ndev);
929 #endif /* WL_WPS_SYNC */
930
931 #if defined(WL_FW_OCE_AP_SELECT)
932 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint);
933 #endif /* WL_FW_OCE_AP_SELECT */
934
935 #ifdef WL_BCNRECV
936 static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
937 const wl_event_msg_t *e, void *data);
938 #endif /* WL_BCNRECV */
939
940 #ifdef WL_CAC_TS
941 static s32 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
942 const wl_event_msg_t *e, void *data);
943 #endif /* WL_CAC_TS */
944
945 #if defined(WL_MBO) || defined(WL_OCE)
946 static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
947 const wl_event_msg_t *e, void *data);
948 #endif /* WL_MBO || WL_OCE */
949
950 static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ,
951 WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ };
952
953 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || (defined(CONFIG_ARCH_MSM) && \
954 defined(CFG80211_DISCONNECTED_V2))
955 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
956 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
957 IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
958 #else
959 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
960 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
961 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
962 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
963
964 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
965 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
966 defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || defined(WL_FILS) || \
967 defined(CONFIG_CFG80211_FILS_BKPORT)
968 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
969 resp_ie_len, status, gfp) \
970 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
971 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
972 #else
973 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
974 resp_ie_len, status, gfp) \
975 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
976 resp_ie_len, status, gfp);
977 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
978 * (CFG80211_CONNECT_TIMEOUT_REASON_CODE) ||
979 * WL_FILS || CONFIG_CFG80211_FILS_BKPORT
980 */
981 #elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
982 /* There are customer kernels with backported changes for
983 * connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
984 * is available for kernels < 4.7 in such cases.
985 */
986 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
987 resp_ie_len, status, gfp) \
988 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
989 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
990 #else
991 /* Kernels < 4.7 doesn't support cfg80211_connect_bss */
992 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
993 resp_ie_len, status, gfp) \
994 cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
995 resp_ie_len, status, gfp);
996 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
997
998 #define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
999 (akm) == RSN_AKM_UNSPECIFIED || \
1000 (akm) == RSN_AKM_PSK)
1001
1002 extern int dhd_wait_pend8021x(struct net_device *dev);
1003 #ifdef PROP_TXSTATUS_VSDB
1004 extern int disable_proptx;
1005 #endif /* PROP_TXSTATUS_VSDB */
1006
1007 static s32
1008 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1009 const wl_event_msg_t *e, void *data);
1010 static s32
1011 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1012 const wl_event_msg_t *e, void *data);
1013 #ifdef SUPPORT_AP_BWCTRL
1014 static void
1015 wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg, struct net_device *ndev, chanspec_t chanspec);
1016 static void
1017 wl_restore_ap_bw(struct bcm_cfg80211 *cfg);
1018 #endif /* SUPPORT_AP_BWCTRL */
1019
1020 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \
1021 0)))
1022 struct chan_info {
1023 int freq;
1024 int chan_type;
1025 };
1026 #endif // endif
1027
1028 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
1029 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(wiphy, bss);
1030 #else
1031 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(bss);
1032 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
1033
1034 #define CHAN2G(_channel, _freq, _flags) { \
1035 .band = IEEE80211_BAND_2GHZ, \
1036 .center_freq = (_freq), \
1037 .hw_value = (_channel), \
1038 .flags = (_flags), \
1039 .max_antenna_gain = 0, \
1040 .max_power = 30, \
1041 }
1042
1043 #define CHAN5G(_channel, _flags) { \
1044 .band = IEEE80211_BAND_5GHZ, \
1045 .center_freq = 5000 + (5 * (_channel)), \
1046 .hw_value = (_channel), \
1047 .flags = (_flags), \
1048 .max_antenna_gain = 0, \
1049 .max_power = 30, \
1050 }
1051
1052 #define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
1053 #define RATETAB_ENT(_rateid, _flags) \
1054 { \
1055 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
1056 .hw_value = (_rateid), \
1057 .flags = (_flags), \
1058 }
1059
1060 static struct ieee80211_rate __wl_rates[] = {
1061 RATETAB_ENT(DOT11_RATE_1M, 0),
1062 RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
1063 RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
1064 RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
1065 RATETAB_ENT(DOT11_RATE_6M, 0),
1066 RATETAB_ENT(DOT11_RATE_9M, 0),
1067 RATETAB_ENT(DOT11_RATE_12M, 0),
1068 RATETAB_ENT(DOT11_RATE_18M, 0),
1069 RATETAB_ENT(DOT11_RATE_24M, 0),
1070 RATETAB_ENT(DOT11_RATE_36M, 0),
1071 RATETAB_ENT(DOT11_RATE_48M, 0),
1072 RATETAB_ENT(DOT11_RATE_54M, 0)
1073 };
1074
1075 #define wl_a_rates (__wl_rates + 4)
1076 #define wl_a_rates_size 8
1077 #define wl_g_rates (__wl_rates + 0)
1078 #define wl_g_rates_size 12
1079
1080 static struct ieee80211_channel __wl_2ghz_channels[] = {
1081 CHAN2G(1, 2412, 0),
1082 CHAN2G(2, 2417, 0),
1083 CHAN2G(3, 2422, 0),
1084 CHAN2G(4, 2427, 0),
1085 CHAN2G(5, 2432, 0),
1086 CHAN2G(6, 2437, 0),
1087 CHAN2G(7, 2442, 0),
1088 CHAN2G(8, 2447, 0),
1089 CHAN2G(9, 2452, 0),
1090 CHAN2G(10, 2457, 0),
1091 CHAN2G(11, 2462, 0),
1092 CHAN2G(12, 2467, 0),
1093 CHAN2G(13, 2472, 0),
1094 CHAN2G(14, 2484, 0)
1095 };
1096
1097 static struct ieee80211_channel __wl_5ghz_a_channels[] = {
1098 CHAN5G(34, 0), CHAN5G(36, 0),
1099 CHAN5G(38, 0), CHAN5G(40, 0),
1100 CHAN5G(42, 0), CHAN5G(44, 0),
1101 CHAN5G(46, 0), CHAN5G(48, 0),
1102 CHAN5G(52, 0), CHAN5G(56, 0),
1103 CHAN5G(60, 0), CHAN5G(64, 0),
1104 CHAN5G(100, 0), CHAN5G(104, 0),
1105 CHAN5G(108, 0), CHAN5G(112, 0),
1106 CHAN5G(116, 0), CHAN5G(120, 0),
1107 CHAN5G(124, 0), CHAN5G(128, 0),
1108 CHAN5G(132, 0), CHAN5G(136, 0),
1109 CHAN5G(140, 0), CHAN5G(144, 0),
1110 CHAN5G(149, 0), CHAN5G(153, 0),
1111 CHAN5G(157, 0), CHAN5G(161, 0),
1112 CHAN5G(165, 0)
1113 };
1114
1115 static struct ieee80211_supported_band __wl_band_2ghz = {
1116 .band = IEEE80211_BAND_2GHZ,
1117 .channels = __wl_2ghz_channels,
1118 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
1119 .bitrates = wl_g_rates,
1120 .n_bitrates = wl_g_rates_size
1121 };
1122
1123 static struct ieee80211_supported_band __wl_band_5ghz_a = {
1124 .band = IEEE80211_BAND_5GHZ,
1125 .channels = __wl_5ghz_a_channels,
1126 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
1127 .bitrates = wl_a_rates,
1128 .n_bitrates = wl_a_rates_size
1129 };
1130
1131 static const u32 __wl_cipher_suites[] = {
1132 WLAN_CIPHER_SUITE_WEP40,
1133 WLAN_CIPHER_SUITE_WEP104,
1134 WLAN_CIPHER_SUITE_TKIP,
1135 WLAN_CIPHER_SUITE_CCMP,
1136 #ifdef MFP
1137 /*
1138 * Advertising AES_CMAC cipher suite to userspace would imply that we
1139 * are supporting MFP. So advertise only when MFP support is enabled.
1140 */
1141 WLAN_CIPHER_SUITE_AES_CMAC,
1142 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1143 WLAN_CIPHER_SUITE_BIP_GMAC_256,
1144 WLAN_CIPHER_SUITE_BIP_GMAC_128,
1145 WLAN_CIPHER_SUITE_BIP_CMAC_256,
1146 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1147 #endif /* MFP */
1148
1149 #ifdef BCMWAPI_WPI
1150 WLAN_CIPHER_SUITE_SMS4,
1151 #endif // endif
1152 #if defined(WLAN_CIPHER_SUITE_PMK)
1153 WLAN_CIPHER_SUITE_PMK,
1154 #endif /* WLAN_CIPHER_SUITE_PMK */
1155 #ifdef WL_GCMP
1156 WLAN_CIPHER_SUITE_GCMP,
1157 WLAN_CIPHER_SUITE_GCMP_256,
1158 WLAN_CIPHER_SUITE_BIP_GMAC_128,
1159 WLAN_CIPHER_SUITE_BIP_GMAC_256,
1160 #endif /* WL_GCMP */
1161 };
1162
1163 #ifdef WL_SUPPORT_ACS
1164 /*
1165 * The firmware code required for this feature to work is currently under
1166 * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1167 * required firmware code out of the BCMINTERNAL flag.
1168 */
1169 struct wl_dump_survey {
1170 u32 obss;
1171 u32 ibss;
1172 u32 no_ctg;
1173 u32 no_pckt;
1174 u32 tx;
1175 u32 idle;
1176 };
1177 #endif /* WL_SUPPORT_ACS */
1178
1179 #ifdef WL_CFG80211_GON_COLLISION
1180 #define BLOCK_GON_REQ_MAX_NUM 5
1181 #endif /* WL_CFG80211_GON_COLLISION */
1182
1183 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1184 static int maxrxpktglom = 0;
1185 #endif // endif
1186
1187 /* IOCtl version read from targeted driver */
1188 int ioctl_version;
1189 #ifdef DEBUGFS_CFG80211
1190 #define SUBLOGLEVEL 20
1191 #define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1))
1192 static const struct {
1193 u32 log_level;
1194 char *sublogname;
1195 } sublogname_map[] = {
1196 {WL_DBG_ERR, "ERR"},
1197 {WL_DBG_INFO, "INFO"},
1198 {WL_DBG_DBG, "DBG"},
1199 {WL_DBG_SCAN, "SCAN"},
1200 {WL_DBG_TRACE, "TRACE"},
1201 {WL_DBG_P2P_ACTION, "P2PACTION"}
1202 };
1203 #endif // endif
1204
1205 typedef struct rsn_cipher_algo_entry {
1206 u32 cipher_suite;
1207 u32 wsec_algo;
1208 u32 wsec_key_algo;
1209 } rsn_cipher_algo_entry_t;
1210
1211 static const rsn_cipher_algo_entry_t rsn_cipher_algo_lookup_tbl[] = {
1212 {WLAN_CIPHER_SUITE_WEP40, WEP_ENABLED, CRYPTO_ALGO_WEP1},
1213 {WLAN_CIPHER_SUITE_WEP104, WEP_ENABLED, CRYPTO_ALGO_WEP128},
1214 {WLAN_CIPHER_SUITE_TKIP, TKIP_ENABLED, CRYPTO_ALGO_TKIP},
1215 {WLAN_CIPHER_SUITE_CCMP, AES_ENABLED, CRYPTO_ALGO_AES_CCM},
1216 {WLAN_CIPHER_SUITE_AES_CMAC, AES_ENABLED, CRYPTO_ALGO_BIP},
1217 #ifdef BCMWAPI_WPI
1218 {WLAN_CIPHER_SUITE_SMS4, SMS4_ENABLED, CRYPTO_ALGO_SMS4},
1219 #endif /* BCMWAPI_WPI */
1220 #ifdef WL_GCMP
1221 {WLAN_CIPHER_SUITE_GCMP, AES_ENABLED, CRYPTO_ALGO_AES_GCM},
1222 {WLAN_CIPHER_SUITE_GCMP_256, AES_ENABLED, CRYPTO_ALGO_AES_GCM256},
1223 {WLAN_CIPHER_SUITE_BIP_GMAC_128, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC},
1224 {WLAN_CIPHER_SUITE_BIP_GMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC256},
1225 #endif /* WL_GCMP */
1226 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1227 {WLAN_CIPHER_SUITE_BIP_CMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_CMAC256},
1228 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1229 };
1230
1231 typedef struct rsn_akm_wpa_auth_entry {
1232 u32 akm_suite;
1233 u32 wpa_auth;
1234 } rsn_akm_wpa_auth_entry_t;
1235
1236 static const rsn_akm_wpa_auth_entry_t rsn_akm_wpa_auth_lookup_tbl[] = {
1237 #ifdef WL_OWE
1238 {WLAN_AKM_SUITE_OWE, WPA3_AUTH_OWE},
1239 #endif /* WL_OWE */
1240 {WLAN_AKM_SUITE_8021X, WPA2_AUTH_UNSPECIFIED},
1241 {WL_AKM_SUITE_SHA256_1X, WPA2_AUTH_1X_SHA256},
1242 {WL_AKM_SUITE_SHA256_PSK, WPA2_AUTH_PSK_SHA256},
1243 {WLAN_AKM_SUITE_PSK, WPA2_AUTH_PSK},
1244 {WLAN_AKM_SUITE_FT_8021X, WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT},
1245 {WLAN_AKM_SUITE_FT_PSK, WPA2_AUTH_PSK | WPA2_AUTH_FT},
1246 {WLAN_AKM_SUITE_FILS_SHA256, WPA2_AUTH_FILS_SHA256},
1247 {WLAN_AKM_SUITE_FILS_SHA384, WPA2_AUTH_FILS_SHA384},
1248 {WLAN_AKM_SUITE_8021X_SUITE_B, WPA3_AUTH_1X_SUITE_B_SHA256},
1249 {WLAN_AKM_SUITE_8021X_SUITE_B_192, WPA3_AUTH_1X_SUITE_B_SHA384},
1250 #ifdef BCMWAPI_WPI
1251 {WLAN_AKM_SUITE_WAPI_CERT, WAPI_AUTH_UNSPECIFIED},
1252 {WLAN_AKM_SUITE_WAPI_PSK, WAPI_AUTH_PSK},
1253 #endif /* BCMWAPI_WPI */
1254 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
1255 {WLAN_AKM_SUITE_SAE, WPA3_AUTH_SAE_PSK},
1256 #endif /* WL_SAE || WL_CLIENT_SAE */
1257 {WLAN_AKM_SUITE_FT_8021X_SHA384, WPA3_AUTH_1X_SUITE_B_SHA384 | WPA2_AUTH_FT}
1258 };
1259
1260 #define BUFSZ 8
1261 #define BUFSZN BUFSZ + 1
1262
1263 #define _S(x) #x
1264 #define S(x) _S(x)
1265
1266 #define SOFT_AP_IF_NAME "swlan0"
1267
1268 /* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1269 uint32 fw_assoc_watchdog_ms = 0;
1270 bool fw_assoc_watchdog_started = 0;
1271 #define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1272
wl_add_remove_pm_enable_work(struct bcm_cfg80211 * cfg,enum wl_pm_workq_act_type type)1273 static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg,
1274 enum wl_pm_workq_act_type type)
1275 {
1276 u16 wq_duration = 0;
1277 dhd_pub_t *dhd = NULL;
1278
1279 if (cfg == NULL)
1280 return;
1281
1282 dhd = (dhd_pub_t *)(cfg->pub);
1283
1284 mutex_lock(&cfg->pm_sync);
1285 /*
1286 * Make cancel and schedule work part mutually exclusive
1287 * so that while cancelling, we are sure that there is no
1288 * work getting scheduled.
1289 */
1290 if (delayed_work_pending(&cfg->pm_enable_work)) {
1291 cancel_delayed_work(&cfg->pm_enable_work);
1292 DHD_PM_WAKE_UNLOCK(cfg->pub);
1293 }
1294
1295 if (type == WL_PM_WORKQ_SHORT) {
1296 wq_duration = WL_PM_ENABLE_TIMEOUT;
1297 } else if (type == WL_PM_WORKQ_LONG) {
1298 wq_duration = (WL_PM_ENABLE_TIMEOUT*2);
1299 }
1300
1301 /* It should schedule work item only if driver is up */
1302 if (wq_duration && dhd->up) {
1303 if (schedule_delayed_work(&cfg->pm_enable_work,
1304 msecs_to_jiffies((const unsigned int)wq_duration))) {
1305 DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub, wq_duration);
1306 } else {
1307 WL_ERR(("Can't schedule pm work handler\n"));
1308 }
1309 }
1310 mutex_unlock(&cfg->pm_sync);
1311 }
1312
1313 /* Return a new chanspec given a legacy chanspec
1314 * Returns INVCHANSPEC on error
1315 */
1316 chanspec_t
wl_chspec_from_legacy(chanspec_t legacy_chspec)1317 wl_chspec_from_legacy(chanspec_t legacy_chspec)
1318 {
1319 chanspec_t chspec;
1320
1321 /* get the channel number */
1322 chspec = LCHSPEC_CHANNEL(legacy_chspec);
1323
1324 /* convert the band */
1325 if (LCHSPEC_IS2G(legacy_chspec)) {
1326 chspec |= WL_CHANSPEC_BAND_2G;
1327 } else {
1328 chspec |= WL_CHANSPEC_BAND_5G;
1329 }
1330
1331 /* convert the bw and sideband */
1332 if (LCHSPEC_IS20(legacy_chspec)) {
1333 chspec |= WL_CHANSPEC_BW_20;
1334 } else {
1335 chspec |= WL_CHANSPEC_BW_40;
1336 if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
1337 chspec |= WL_CHANSPEC_CTL_SB_L;
1338 } else {
1339 chspec |= WL_CHANSPEC_CTL_SB_U;
1340 }
1341 }
1342
1343 if (wf_chspec_malformed(chspec)) {
1344 WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1345 chspec));
1346 return INVCHANSPEC;
1347 }
1348
1349 return chspec;
1350 }
1351
1352 /* Return a legacy chanspec given a new chanspec
1353 * Returns INVCHANSPEC on error
1354 */
1355 static chanspec_t
wl_chspec_to_legacy(chanspec_t chspec)1356 wl_chspec_to_legacy(chanspec_t chspec)
1357 {
1358 chanspec_t lchspec;
1359
1360 if (wf_chspec_malformed(chspec)) {
1361 WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1362 chspec));
1363 return INVCHANSPEC;
1364 }
1365
1366 /* get the channel number */
1367 lchspec = CHSPEC_CHANNEL(chspec);
1368
1369 /* convert the band */
1370 if (CHSPEC_IS2G(chspec)) {
1371 lchspec |= WL_LCHANSPEC_BAND_2G;
1372 } else {
1373 lchspec |= WL_LCHANSPEC_BAND_5G;
1374 }
1375
1376 /* convert the bw and sideband */
1377 if (CHSPEC_IS20(chspec)) {
1378 lchspec |= WL_LCHANSPEC_BW_20;
1379 lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
1380 } else if (CHSPEC_IS40(chspec)) {
1381 lchspec |= WL_LCHANSPEC_BW_40;
1382 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
1383 lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
1384 } else {
1385 lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
1386 }
1387 } else {
1388 /* cannot express the bandwidth */
1389 char chanbuf[CHANSPEC_STR_LEN];
1390 WL_ERR((
1391 "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1392 "to pre-11ac format\n",
1393 wf_chspec_ntoa(chspec, chanbuf), chspec));
1394 return INVCHANSPEC;
1395 }
1396
1397 return lchspec;
1398 }
1399
wl_cfg80211_is_hal_started(struct bcm_cfg80211 * cfg)1400 bool wl_cfg80211_is_hal_started(struct bcm_cfg80211 *cfg)
1401 {
1402 return cfg->hal_started;
1403 }
1404
1405 /* given a chanspec value, do the endian and chanspec version conversion to
1406 * a chanspec_t value
1407 * Returns INVCHANSPEC on error
1408 */
1409 chanspec_t
wl_chspec_host_to_driver(chanspec_t chanspec)1410 wl_chspec_host_to_driver(chanspec_t chanspec)
1411 {
1412 if (ioctl_version == 1) {
1413 chanspec = wl_chspec_to_legacy(chanspec);
1414 if (chanspec == INVCHANSPEC) {
1415 return chanspec;
1416 }
1417 }
1418 chanspec = htodchanspec(chanspec);
1419
1420 return chanspec;
1421 }
1422
1423 /* given a channel value, do the endian and chanspec version conversion to
1424 * a chanspec_t value
1425 * Returns INVCHANSPEC on error
1426 */
1427 chanspec_t
wl_ch_host_to_driver(u16 channel)1428 wl_ch_host_to_driver(u16 channel)
1429 {
1430 chanspec_t chanspec;
1431 chanspec_band_t band;
1432
1433 band = WL_CHANNEL_BAND(channel);
1434
1435 chanspec = wf_create_20MHz_chspec(channel, band);
1436 if (chanspec == INVCHANSPEC) {
1437 return chanspec;
1438 }
1439
1440 return wl_chspec_host_to_driver(chanspec);
1441 }
1442
1443 /* given a chanspec value from the driver, do the endian and chanspec version conversion to
1444 * a chanspec_t value
1445 * Returns INVCHANSPEC on error
1446 */
1447 chanspec_t
wl_chspec_driver_to_host(chanspec_t chanspec)1448 wl_chspec_driver_to_host(chanspec_t chanspec)
1449 {
1450 chanspec = dtohchanspec(chanspec);
1451 if (ioctl_version == 1) {
1452 chanspec = wl_chspec_from_legacy(chanspec);
1453 }
1454
1455 return chanspec;
1456 }
1457
1458 /*
1459 * convert ASCII string to MAC address (colon-delimited format)
1460 * eg: 00:11:22:33:44:55
1461 */
1462 int
wl_cfg80211_ether_atoe(const char * a,struct ether_addr * n)1463 wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
1464 {
1465 char *c = NULL;
1466 int count = 0;
1467
1468 bzero(n, ETHER_ADDR_LEN);
1469 for (;;) {
1470 n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
1471 if (!*c++ || count == ETHER_ADDR_LEN)
1472 break;
1473 a = c;
1474 }
1475 return (count == ETHER_ADDR_LEN);
1476 }
1477
1478 /* There isn't a lot of sense in it, but you can transmit anything you like */
1479 static const struct ieee80211_txrx_stypes
1480 wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1481 #ifdef WLMESH_CFG80211
1482 [NL80211_IFTYPE_MESH_POINT] = {
1483 .tx = 0xffff,
1484 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1485 BIT(IEEE80211_STYPE_AUTH >> 4)
1486 },
1487 #endif /* WLMESH_CFG80211 */
1488 [NL80211_IFTYPE_ADHOC] = {
1489 .tx = 0xffff,
1490 .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
1491 },
1492 [NL80211_IFTYPE_STATION] = {
1493 .tx = 0xffff,
1494 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1495 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1496 #ifdef WL_CLIENT_SAE
1497 | BIT(IEEE80211_STYPE_AUTH >> 4)
1498 #endif /* WL_CLIENT_SAE */
1499 },
1500 [NL80211_IFTYPE_AP] = {
1501 .tx = 0xffff,
1502 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1503 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1504 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1505 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1506 BIT(IEEE80211_STYPE_AUTH >> 4) |
1507 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1508 BIT(IEEE80211_STYPE_ACTION >> 4)
1509 },
1510 [NL80211_IFTYPE_AP_VLAN] = {
1511 /* copy AP */
1512 .tx = 0xffff,
1513 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1514 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1515 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1516 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1517 BIT(IEEE80211_STYPE_AUTH >> 4) |
1518 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1519 BIT(IEEE80211_STYPE_ACTION >> 4)
1520 },
1521 [NL80211_IFTYPE_P2P_CLIENT] = {
1522 .tx = 0xffff,
1523 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1524 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1525 },
1526 [NL80211_IFTYPE_P2P_GO] = {
1527 .tx = 0xffff,
1528 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1529 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1530 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1531 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1532 BIT(IEEE80211_STYPE_AUTH >> 4) |
1533 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1534 BIT(IEEE80211_STYPE_ACTION >> 4)
1535 },
1536 #if defined(WL_CFG80211_P2P_DEV_IF)
1537 [NL80211_IFTYPE_P2P_DEVICE] = {
1538 .tx = 0xffff,
1539 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1540 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1541 },
1542 #endif /* WL_CFG80211_P2P_DEV_IF */
1543 };
1544
swap_key_from_BE(struct wl_wsec_key * key)1545 static void swap_key_from_BE(struct wl_wsec_key *key)
1546 {
1547 key->index = htod32(key->index);
1548 key->len = htod32(key->len);
1549 key->algo = htod32(key->algo);
1550 key->flags = htod32(key->flags);
1551 key->rxiv.hi = htod32(key->rxiv.hi);
1552 key->rxiv.lo = htod16(key->rxiv.lo);
1553 key->iv_initialized = htod32(key->iv_initialized);
1554 }
1555
swap_key_to_BE(struct wl_wsec_key * key)1556 static void swap_key_to_BE(struct wl_wsec_key *key)
1557 {
1558 key->index = dtoh32(key->index);
1559 key->len = dtoh32(key->len);
1560 key->algo = dtoh32(key->algo);
1561 key->flags = dtoh32(key->flags);
1562 key->rxiv.hi = dtoh32(key->rxiv.hi);
1563 key->rxiv.lo = dtoh16(key->rxiv.lo);
1564 key->iv_initialized = dtoh32(key->iv_initialized);
1565 }
1566
1567 #if defined(WL_FW_OCE_AP_SELECT)
wl_cfg80211_is_oce_ap(struct wiphy * wiphy,const u8 * bssid_hint)1568 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint)
1569 {
1570 const u8 *parse = NULL;
1571 bcm_tlv_t *ie;
1572 const struct cfg80211_bss_ies *ies;
1573 u32 len;
1574 struct cfg80211_bss *bss;
1575
1576 bss = CFG80211_GET_BSS(wiphy, NULL, bssid_hint, 0, 0);
1577 if (!bss) {
1578 WL_ERR(("Unable to find AP in the cache"));
1579 return false;
1580 }
1581
1582 if (rcu_access_pointer(bss->ies)) {
1583 ies = rcu_access_pointer(bss->ies);
1584 parse = ies->data;
1585 len = ies->len;
1586 } else {
1587 WL_ERR(("ies is NULL"));
1588 return false;
1589 }
1590
1591 while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_VS_ID))) {
1592 if (wl_cfgoce_is_oce_ie((const uint8*)ie, (u8 const **)&parse, &len) == TRUE) {
1593 return true;
1594 } else {
1595 ie = bcm_next_tlv((const bcm_tlv_t*) ie, &len);
1596 if (!ie) {
1597 return false;
1598 }
1599 parse = (uint8 *)ie;
1600 WL_DBG(("NON OCE IE. next ie ptr:%p", parse));
1601 }
1602 }
1603 WL_DBG(("OCE IE NOT found"));
1604 return false;
1605 }
1606 #endif /* WL_FW_OCE_AP_SELECT */
1607
1608 /* Dump the contents of the encoded wps ie buffer and get pbc value */
1609 static void
wl_validate_wps_ie(const char * wps_ie,s32 wps_ie_len,bool * pbc)1610 wl_validate_wps_ie(const char *wps_ie, s32 wps_ie_len, bool *pbc)
1611 {
1612 #define WPS_IE_FIXED_LEN 6
1613 s16 len;
1614 const u8 *subel = NULL;
1615 u16 subelt_id;
1616 u16 subelt_len;
1617 u16 val;
1618 u8 *valptr = (uint8*) &val;
1619 if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
1620 WL_ERR(("invalid argument : NULL\n"));
1621 return;
1622 }
1623 len = (s16)wps_ie[TLV_LEN_OFF];
1624
1625 if (len > wps_ie_len) {
1626 WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
1627 return;
1628 }
1629 WL_DBG(("wps_ie len=%d\n", len));
1630 len -= 4; /* for the WPS IE's OUI, oui_type fields */
1631 subel = wps_ie + WPS_IE_FIXED_LEN;
1632 while (len >= 4) { /* must have attr id, attr len fields */
1633 valptr[0] = *subel++;
1634 valptr[1] = *subel++;
1635 subelt_id = HTON16(val);
1636
1637 valptr[0] = *subel++;
1638 valptr[1] = *subel++;
1639 subelt_len = HTON16(val);
1640
1641 len -= 4; /* for the attr id, attr len fields */
1642 len -= (s16)subelt_len; /* for the remaining fields in this attribute */
1643 if (len < 0) {
1644 break;
1645 }
1646 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
1647 subel, subelt_id, subelt_len));
1648
1649 if (subelt_id == WPS_ID_VERSION) {
1650 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
1651 } else if (subelt_id == WPS_ID_REQ_TYPE) {
1652 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
1653 } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
1654 valptr[0] = *subel;
1655 valptr[1] = *(subel + 1);
1656 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
1657 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
1658 char devname[33];
1659 int namelen = MIN(subelt_len, (sizeof(devname) - 1));
1660
1661 if (namelen) {
1662 memcpy(devname, subel, namelen);
1663 devname[namelen] = '\0';
1664 /* Printing len as rx'ed in the IE */
1665 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1666 devname, subelt_len));
1667 }
1668 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
1669 valptr[0] = *subel;
1670 valptr[1] = *(subel + 1);
1671 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
1672 *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
1673 } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
1674 valptr[0] = *subel;
1675 valptr[1] = *(subel + 1);
1676 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
1677 valptr[0] = *(subel + 6);
1678 valptr[1] = *(subel + 7);
1679 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
1680 } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
1681 valptr[0] = *subel;
1682 valptr[1] = *(subel + 1);
1683 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
1684 valptr[0] = *(subel + 6);
1685 valptr[1] = *(subel + 7);
1686 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
1687 } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
1688 valptr[0] = *subel;
1689 valptr[1] = *(subel + 1);
1690 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1691 ": cat=%u\n", HTON16(val)));
1692 } else {
1693 WL_DBG((" unknown attr 0x%x\n", subelt_id));
1694 }
1695
1696 subel += subelt_len;
1697 }
1698 }
1699
wl_set_tx_power(struct net_device * dev,enum nl80211_tx_power_setting type,s32 dbm)1700 s32 wl_set_tx_power(struct net_device *dev,
1701 enum nl80211_tx_power_setting type, s32 dbm)
1702 {
1703 s32 err = 0;
1704 s32 disable = 0;
1705 s32 txpwrqdbm;
1706 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1707
1708 /* Make sure radio is off or on as far as software is concerned */
1709 disable = WL_RADIO_SW_DISABLE << 16;
1710 disable = htod32(disable);
1711 err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable));
1712 if (unlikely(err)) {
1713 WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
1714 return err;
1715 }
1716
1717 if (dbm > 0xffff)
1718 dbm = 0xffff;
1719 txpwrqdbm = dbm * 4;
1720 #ifdef SUPPORT_WL_TXPOWER
1721 if (type == NL80211_TX_POWER_AUTOMATIC)
1722 txpwrqdbm = 127;
1723 else
1724 txpwrqdbm |= WL_TXPWR_OVERRIDE;
1725 #endif /* SUPPORT_WL_TXPOWER */
1726 err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
1727 sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
1728 &cfg->ioctl_buf_sync);
1729 if (unlikely(err))
1730 WL_ERR(("qtxpower error (%d)\n", err));
1731 else
1732 WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
1733
1734 return err;
1735 }
1736
wl_get_tx_power(struct net_device * dev,s32 * dbm)1737 s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
1738 {
1739 s32 err = 0;
1740 s32 txpwrdbm;
1741 char ioctl_buf[WLC_IOCTL_SMLEN];
1742
1743 err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
1744 NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
1745 if (unlikely(err)) {
1746 WL_ERR(("error (%d)\n", err));
1747 return err;
1748 }
1749
1750 memcpy(&txpwrdbm, ioctl_buf, sizeof(txpwrdbm));
1751 txpwrdbm = dtoh32(txpwrdbm);
1752 *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
1753
1754 WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
1755
1756 return err;
1757 }
1758
wl_cfg80211_get_shared_freq(struct wiphy * wiphy)1759 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
1760 {
1761 chanspec_t chspec;
1762 int cur_band, err = 0;
1763 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1764 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
1765 struct ether_addr bssid;
1766 wl_bss_info_t *bss = NULL;
1767 u16 channel = WL_P2P_TEMP_CHAN;
1768 char *buf;
1769
1770 bzero(&bssid, sizeof(bssid));
1771 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) {
1772 /* STA interface is not associated. So start the new interface on a temp
1773 * channel . Later proper channel will be applied by the above framework
1774 * via set_channel (cfg80211 API).
1775 */
1776 WL_DBG(("Not associated. Return a temp channel. \n"));
1777 cur_band = 0;
1778 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(int));
1779 if (unlikely(err)) {
1780 WL_ERR(("Get band failed\n"));
1781 } else if (cur_band == WLC_BAND_5G) {
1782 channel = WL_P2P_TEMP_CHAN_5G;
1783 }
1784 return wl_ch_host_to_driver(channel);
1785 }
1786
1787 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
1788 if (!buf) {
1789 WL_ERR(("buf alloc failed. use temp channel\n"));
1790 return wl_ch_host_to_driver(channel);
1791 }
1792
1793 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1794 if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf,
1795 WL_EXTRA_BUF_MAX))) {
1796 WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1797 chspec = wl_ch_host_to_driver(channel);
1798 }
1799 else {
1800 bss = (wl_bss_info_t *) (buf + 4);
1801 chspec = bss->chanspec;
1802
1803 WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
1804 }
1805
1806 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
1807 return chspec;
1808 }
1809
1810 static void
wl_wlfc_enable(struct bcm_cfg80211 * cfg,bool enable)1811 wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable)
1812 {
1813 #ifdef PROP_TXSTATUS_VSDB
1814 #if defined(BCMSDIO) || defined(BCMDBUS)
1815 bool wlfc_enabled = FALSE;
1816 s32 err;
1817 dhd_pub_t *dhd;
1818 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1819
1820 dhd = (dhd_pub_t *)(cfg->pub);
1821 if (!dhd) {
1822 return;
1823 }
1824
1825 if (enable) {
1826 if (!cfg->wlfc_on && !disable_proptx) {
1827 dhd_wlfc_get_enable(dhd, &wlfc_enabled);
1828 if (!wlfc_enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1829 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1830 dhd_wlfc_init(dhd);
1831 err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32));
1832 if (err < 0)
1833 WL_ERR(("WLC_UP return err:%d\n", err));
1834 }
1835 cfg->wlfc_on = true;
1836 WL_DBG(("wlfc_on:%d \n", cfg->wlfc_on));
1837 }
1838 } else if (dhd->conf->disable_proptx != 0){
1839 dhd_wlfc_deinit(dhd);
1840 cfg->wlfc_on = false;
1841 }
1842 #endif /* BCMSDIO || BCMDBUS */
1843 #endif /* PROP_TXSTATUS_VSDB */
1844 }
1845
1846 struct wireless_dev *
wl_cfg80211_p2p_if_add(struct bcm_cfg80211 * cfg,wl_iftype_t wl_iftype,char const * name,u8 * mac_addr,s32 * ret_err)1847 wl_cfg80211_p2p_if_add(struct bcm_cfg80211 *cfg,
1848 wl_iftype_t wl_iftype,
1849 char const *name, u8 *mac_addr, s32 *ret_err)
1850 {
1851 u16 chspec;
1852 s16 cfg_type;
1853 long timeout;
1854 s32 err;
1855 u16 p2p_iftype;
1856 int dhd_mode;
1857 struct net_device *new_ndev = NULL;
1858 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
1859 struct ether_addr *p2p_addr;
1860
1861 *ret_err = BCME_OK;
1862 if (!cfg->p2p) {
1863 WL_ERR(("p2p not initialized\n"));
1864 return NULL;
1865 }
1866
1867 printk(KERN_INFO"wl_cfg80211_p2p_if_add type=%d, name=%s\n", wl_iftype, name);
1868
1869 #if defined(WL_CFG80211_P2P_DEV_IF)
1870 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
1871 /* Handle Dedicated P2P discovery Interface */
1872 #ifdef CONFIG_AP6XXX_WIFI6_HDF
1873 // cache @mac_addr ...
1874 memcpy(g_hdf_infmap[HDF_INF_P2P0].macaddr, mac_addr, ETH_ALEN);
1875 #endif
1876 return wl_cfgp2p_add_p2p_disc_if(cfg);
1877 }
1878 #endif /* WL_CFG80211_P2P_DEV_IF */
1879
1880 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1881 p2p_iftype = WL_P2P_IF_GO;
1882 } else {
1883 p2p_iftype = WL_P2P_IF_CLIENT;
1884 }
1885
1886 /* Dual p2p doesn't support multiple P2PGO interfaces,
1887 * p2p_go_count is the counter for GO creation
1888 * requests.
1889 */
1890 if ((cfg->p2p->p2p_go_count > 0) && (wl_iftype == WL_IF_TYPE_P2P_GO)) {
1891 WL_ERR(("FW does not support multiple GO\n"));
1892 *ret_err = -ENOTSUPP;
1893 return NULL;
1894 }
1895 if (!cfg->p2p->on) {
1896 p2p_on(cfg) = true;
1897 wl_cfgp2p_set_firm_p2p(cfg);
1898 wl_cfgp2p_init_discovery(cfg);
1899 }
1900
1901 strlcpy(cfg->p2p->vir_ifname, name, sizeof(cfg->p2p->vir_ifname));
1902 /* In concurrency case, STA may be already associated in a particular channel.
1903 * so retrieve the current channel of primary interface and then start the virtual
1904 * interface on that.
1905 */
1906 chspec = wl_cfg80211_get_shared_freq(wiphy);
1907
1908 /* For P2P mode, use P2P-specific driver features to create the
1909 * bss: "cfg p2p_ifadd"
1910 */
1911 wl_set_p2p_status(cfg, IF_ADDING);
1912 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
1913 cfg_type = wl_cfgp2p_get_conn_idx(cfg);
1914 if (cfg_type == BCME_ERROR) {
1915 wl_clr_p2p_status(cfg, IF_ADDING);
1916 WL_ERR(("Failed to get connection idx for p2p interface\n"));
1917 return NULL;
1918 }
1919
1920 p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
1921 memcpy(p2p_addr->octet, mac_addr, ETH_ALEN);
1922
1923 err = wl_cfgp2p_ifadd(cfg, p2p_addr,
1924 htod32(p2p_iftype), chspec);
1925 if (unlikely(err)) {
1926 wl_clr_p2p_status(cfg, IF_ADDING);
1927 WL_ERR((" virtual iface add failed (%d) \n", err));
1928 return NULL;
1929 }
1930
1931 /* Wait for WLC_E_IF event with IF_ADD opcode */
1932 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1933 ((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
1934 (cfg->if_event_info.valid)),
1935 msecs_to_jiffies(MAX_WAIT_TIME));
1936 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
1937 wl_if_event_info *event = &cfg->if_event_info;
1938 new_ndev = wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg), event,
1939 event->mac, cfg->p2p->vir_ifname, false);
1940 if (unlikely(!new_ndev)) {
1941 goto fail;
1942 }
1943
1944 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1945 cfg->p2p->p2p_go_count++;
1946 }
1947 /* Fill p2p specific data */
1948 wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
1949 wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
1950
1951 WL_ERR((" virtual interface(%s) is "
1952 "created net attach done\n", cfg->p2p->vir_ifname));
1953 dhd_mode = (wl_iftype == WL_IF_TYPE_P2P_GC) ?
1954 DHD_FLAG_P2P_GC_MODE : DHD_FLAG_P2P_GO_MODE;
1955 DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
1956 /* reinitialize completion to clear previous count */
1957 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1958 INIT_COMPLETION(cfg->iface_disable);
1959 #else
1960 init_completion(&cfg->iface_disable);
1961 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
1962
1963 return new_ndev->ieee80211_ptr;
1964 }
1965
1966 fail:
1967 return NULL;
1968 }
1969
1970 bool
wl_cfg80211_check_vif_in_use(struct net_device * ndev)1971 wl_cfg80211_check_vif_in_use(struct net_device *ndev)
1972 {
1973 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1974 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
1975 bool nan_enabled = FALSE;
1976
1977 #ifdef WL_NAN
1978 nan_enabled = cfg->nan_enable;
1979 #endif /* WL_NAN */
1980
1981 if (nan_enabled || (wl_cfgp2p_vif_created(cfg)) ||
1982 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
1983 WL_MEM(("%s: Virtual interfaces in use. NAN %d P2P %d softAP %d\n",
1984 __FUNCTION__, nan_enabled, wl_cfgp2p_vif_created(cfg),
1985 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)));
1986 return TRUE;
1987 }
1988
1989 return FALSE;
1990 }
1991
1992 void
wl_cfg80211_iface_state_ops(struct wireless_dev * wdev,wl_interface_state_t state,wl_iftype_t wl_iftype,u16 wl_mode)1993 wl_cfg80211_iface_state_ops(struct wireless_dev *wdev,
1994 wl_interface_state_t state,
1995 wl_iftype_t wl_iftype, u16 wl_mode)
1996 {
1997 struct net_device *ndev;
1998 struct bcm_cfg80211 *cfg;
1999 dhd_pub_t *dhd;
2000 s32 bssidx;
2001
2002 WL_DBG(("state:%s wl_iftype:%d mode:%d\n",
2003 wl_if_state_strs[state], wl_iftype, wl_mode));
2004 if (!wdev) {
2005 WL_ERR(("wdev null\n"));
2006 return;
2007 }
2008
2009 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_NAN_NMI)) {
2010 /* P2P discovery is a netless device and uses a
2011 * hidden bsscfg interface in fw. Don't apply the
2012 * iface ops state changes for p2p discovery I/F.
2013 * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
2014 * Don't apply iface ops state changes for NMI I/F.
2015 */
2016 return;
2017 }
2018
2019 cfg = wiphy_priv(wdev->wiphy);
2020 ndev = wdev->netdev;
2021 dhd = (dhd_pub_t *)(cfg->pub);
2022
2023 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2024 if (!ndev || (bssidx < 0)) {
2025 WL_ERR(("ndev null. skip iface state ops\n"));
2026 return;
2027 }
2028
2029 switch (state) {
2030 case WL_IF_CREATE_REQ:
2031 #ifdef WL_BCNRECV
2032 /* check fakeapscan in progress then abort */
2033 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
2034 #endif /* WL_BCNRECV */
2035 wl_cfg80211_scan_abort(cfg);
2036 wl_wlfc_enable(cfg, true);
2037 #ifdef WLTDLS
2038 /* disable TDLS if number of connected interfaces is >= 1 */
2039 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_CREATE, false);
2040 #endif /* WLTDLS */
2041 break;
2042 case WL_IF_DELETE_REQ:
2043 #ifdef WL_WPS_SYNC
2044 wl_wps_handle_ifdel(ndev);
2045 #endif /* WPS_SYNC */
2046 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
2047 /* Send completion for any pending scans */
2048 wl_cfg80211_cancel_scan(cfg);
2049 }
2050
2051 #ifdef CUSTOM_SET_CPUCORE
2052 dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
2053 if (!(dhd->chan_isvht80)) {
2054 dhd_set_cpucore(dhd, FALSE);
2055 }
2056 #endif /* CUSTOM_SET_CPUCORE */
2057 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
2058 break;
2059 case WL_IF_CREATE_DONE:
2060 if (wl_mode == WL_MODE_BSS) {
2061 /* Common code for sta type interfaces - STA, GC */
2062 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2063 }
2064 if (wl_iftype == WL_IF_TYPE_P2P_GC) {
2065 /* Disable firmware roaming for P2P interface */
2066 wldev_iovar_setint(ndev, "roam_off", 1);
2067 wldev_iovar_setint(ndev, "bcn_timeout", dhd->conf->bcn_timeout);
2068 }
2069 if (wl_mode == WL_MODE_AP) {
2070 /* Common code for AP/GO */
2071 }
2072 break;
2073 case WL_IF_DELETE_DONE:
2074 #ifdef WLTDLS
2075 /* Enable back TDLS if connected interface is <= 1 */
2076 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2077 #endif /* WLTDLS */
2078 wl_wlfc_enable(cfg, false);
2079 break;
2080 case WL_IF_CHANGE_REQ:
2081 /* Flush existing IEs from firmware on role change */
2082 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
2083 break;
2084 case WL_IF_CHANGE_DONE:
2085 if (wl_mode == WL_MODE_BSS) {
2086 /* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2087 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2088 }
2089 break;
2090
2091 default:
2092 WL_ERR(("Unsupported state: %d\n", state));
2093 return;
2094 }
2095 }
2096
2097 static s32
wl_cfg80211_p2p_if_del(struct wiphy * wiphy,struct wireless_dev * wdev)2098 wl_cfg80211_p2p_if_del(struct wiphy *wiphy, struct wireless_dev *wdev)
2099 {
2100 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2101 s16 bssidx;
2102 s16 err;
2103 s32 cfg_type;
2104 struct net_device *ndev;
2105 long timeout;
2106
2107 if (unlikely(!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
2108 WL_INFORM_MEM(("device is not ready\n"));
2109 return BCME_NOTFOUND;
2110 }
2111 #ifdef WL_CFG80211_P2P_DEV_IF
2112 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2113 /* Handle dedicated P2P discovery interface. */
2114 return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
2115 }
2116 #endif /* WL_CFG80211_P2P_DEV_IF */
2117
2118 /* Handle P2P Group Interface */
2119 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2120 if (bssidx <= 0) {
2121 WL_ERR(("bssidx not found\n"));
2122 return BCME_NOTFOUND;
2123 }
2124 if (wl_cfgp2p_find_type(cfg, bssidx, &cfg_type) != BCME_OK) {
2125 /* Couldn't find matching iftype */
2126 WL_MEM(("non P2P interface\n"));
2127 return BCME_NOTFOUND;
2128 }
2129
2130 ndev = wdev->netdev;
2131 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2132 wl_clr_p2p_status(cfg, IF_ADDING);
2133
2134 /* for GO */
2135 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
2136 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
2137 cfg->p2p->p2p_go_count--;
2138 /* disable interface before bsscfg free */
2139 err = wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2140 /* if fw doesn't support "ifdis",
2141 do not wait for link down of ap mode
2142 */
2143 if (err == 0) {
2144 WL_ERR(("Wait for Link Down event for GO !!!\n"));
2145 wait_for_completion_timeout(&cfg->iface_disable,
2146 msecs_to_jiffies(500));
2147 } else if (err != BCME_UNSUPPORTED) {
2148 msleep(300);
2149 }
2150 } else {
2151 /* GC case */
2152 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
2153 WL_ERR(("Wait for Link Down event for GC !\n"));
2154 wait_for_completion_timeout
2155 (&cfg->iface_disable, msecs_to_jiffies(500));
2156 }
2157 }
2158
2159 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
2160 wl_set_p2p_status(cfg, IF_DELETING);
2161 DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
2162
2163 err = wl_cfgp2p_ifdel(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2164 if (unlikely(err)) {
2165 WL_ERR(("IFDEL operation failed, error code = %d\n", err));
2166 goto fail;
2167 } else {
2168 /* Wait for WLC_E_IF event */
2169 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2170 ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
2171 (cfg->if_event_info.valid)),
2172 msecs_to_jiffies(MAX_WAIT_TIME));
2173 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
2174 cfg->if_event_info.valid) {
2175 WL_ERR(("P2P IFDEL operation done\n"));
2176 err = BCME_OK;
2177 } else {
2178 WL_ERR(("IFDEL didn't complete properly\n"));
2179 err = -EINVAL;
2180 }
2181 }
2182
2183 fail:
2184 /* Even in failure case, attempt to remove the host data structure.
2185 * Firmware would be cleaned up via WiFi reset done by the
2186 * user space from hang event context (for android only).
2187 */
2188 bzero(cfg->p2p->vir_ifname, IFNAMSIZ);
2189 wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
2190 wl_to_p2p_bss_ndev(cfg, cfg_type) = NULL;
2191 wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, cfg_type));
2192 dhd_net_if_lock(ndev);
2193 if (cfg->if_event_info.ifidx) {
2194 /* Remove interface except for primary ifidx */
2195 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
2196 }
2197 dhd_net_if_unlock(ndev);
2198 return err;
2199 }
2200
2201 #ifdef WL_IFACE_MGMT_CONF
2202 #ifdef WL_IFACE_MGMT
2203 static s32
wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 * cfg)2204 wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 *cfg)
2205 {
2206 s32 ret = BCME_OK;
2207 wl_iftype_t active_sec_iface = WL_IFACE_NOT_PRESENT;
2208 bool p2p_disc_on = false;
2209 bool sta_assoc_state = false;
2210
2211 mutex_lock(&cfg->if_sync);
2212
2213 sta_assoc_state = (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) ||
2214 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg)));
2215 active_sec_iface = wl_cfg80211_get_sec_iface(cfg);
2216 p2p_disc_on = wl_get_p2p_status(cfg, SCANNING);
2217
2218 if ((sta_assoc_state == TRUE) || (p2p_disc_on == TRUE) ||
2219 (cfg->nan_init_state == TRUE) ||
2220 (active_sec_iface != WL_IFACE_NOT_PRESENT)) {
2221 WL_INFORM_MEM(("Active iface matrix: sta_assoc_state = %d,"
2222 " p2p_disc = %d, nan_disc = %d, active iface = %s\n",
2223 sta_assoc_state, p2p_disc_on, cfg->nan_init_state,
2224 wl_iftype_to_str(active_sec_iface)));
2225 ret = BCME_BUSY;
2226 }
2227 mutex_unlock(&cfg->if_sync);
2228 return ret;
2229 }
2230 #endif /* WL_IFACE_MGMT */
2231 #ifdef WL_NANP2P
2232 int
wl_cfg80211_set_iface_conc_disc(struct net_device * ndev,uint8 arg_val)2233 wl_cfg80211_set_iface_conc_disc(struct net_device *ndev,
2234 uint8 arg_val)
2235 {
2236 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2237 if (!cfg) {
2238 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2239 return BCME_ERROR;
2240 }
2241
2242 if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
2243 WL_ERR(("Cant allow iface management modifications\n"));
2244 return BCME_BUSY;
2245 }
2246
2247 if (arg_val) {
2248 cfg->conc_disc |= arg_val;
2249 } else {
2250 cfg->conc_disc &= ~arg_val;
2251 }
2252 return BCME_OK;
2253 }
2254
2255 uint8
wl_cfg80211_get_iface_conc_disc(struct net_device * ndev)2256 wl_cfg80211_get_iface_conc_disc(struct net_device *ndev)
2257 {
2258 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2259 if (!cfg) {
2260 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2261 return BCME_ERROR;
2262 }
2263 return cfg->conc_disc;
2264 }
2265 #endif /* WL_NANP2P */
2266 #ifdef WL_IFACE_MGMT
2267 int
wl_cfg80211_set_iface_policy(struct net_device * ndev,char * arg,int len)2268 wl_cfg80211_set_iface_policy(struct net_device *ndev,
2269 char *arg, int len)
2270 {
2271 int ret = BCME_OK;
2272 uint8 i = 0;
2273 iface_mgmt_data_t *iface_data = NULL;
2274
2275 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2276 if (!cfg) {
2277 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2278 return BCME_ERROR;
2279 }
2280
2281 if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
2282 WL_ERR(("Cant allow iface management modifications\n"));
2283 return BCME_BUSY;
2284 }
2285
2286 if (!arg || len <= 0 || len > sizeof(iface_mgmt_data_t)) {
2287 return BCME_BADARG;
2288 }
2289
2290 iface_data = (iface_mgmt_data_t *)arg;
2291 if (iface_data->policy >= WL_IF_POLICY_INVALID) {
2292 WL_ERR(("Unexpected value of policy = %d\n",
2293 iface_data->policy));
2294 return BCME_BADARG;
2295 }
2296
2297 bzero(&cfg->iface_data, sizeof(iface_mgmt_data_t));
2298 ret = memcpy_s(&cfg->iface_data, sizeof(iface_mgmt_data_t), arg, len);
2299 if (ret != BCME_OK) {
2300 WL_ERR(("Failed to copy iface data, src len = %d\n", len));
2301 return ret;
2302 }
2303
2304 if (cfg->iface_data.policy == WL_IF_POLICY_ROLE_PRIORITY) {
2305 for (i = 0; i < WL_IF_TYPE_MAX; i++) {
2306 WL_DBG(("iface = %s, priority[i] = %d\n",
2307 wl_iftype_to_str(i), cfg->iface_data.priority[i]));
2308 }
2309 }
2310
2311 return ret;
2312 }
2313
2314 uint8
wl_cfg80211_get_iface_policy(struct net_device * ndev)2315 wl_cfg80211_get_iface_policy(struct net_device *ndev)
2316
2317 {
2318 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2319 if (!cfg) {
2320 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2321 return BCME_ERROR;
2322 }
2323
2324 return cfg->iface_data.policy;
2325 }
2326 #endif /* WL_IFACE_MGMT */
2327 #endif /* WL_IFACE_MGMT_CONF */
2328
2329 #ifdef WL_IFACE_MGMT
2330 /* Get active secondary data iface type */
2331 wl_iftype_t
wl_cfg80211_get_sec_iface(struct bcm_cfg80211 * cfg)2332 wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg)
2333 {
2334 #ifndef WL_STATIC_IF
2335 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2336 #endif /* !WL_STATIC_IF */
2337 struct net_device *p2p_ndev = NULL;
2338
2339 p2p_ndev = wl_to_p2p_bss_ndev(cfg,
2340 P2PAPI_BSSCFG_CONNECTION1);
2341
2342 #ifdef WL_STATIC_IF
2343 if (IS_CFG80211_STATIC_IF_ACTIVE(cfg)) {
2344 if (IS_AP_IFACE(cfg->static_ndev->ieee80211_ptr)) {
2345 return WL_IF_TYPE_AP;
2346 }
2347 }
2348 #else
2349 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
2350 return WL_IF_TYPE_AP;
2351 }
2352 #endif /* WL_STATIC_IF */
2353
2354 if (p2p_ndev && p2p_ndev->ieee80211_ptr) {
2355 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
2356 return WL_IF_TYPE_P2P_GO;
2357 }
2358
2359 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
2360 return WL_IF_TYPE_P2P_GC;
2361 }
2362 }
2363
2364 #ifdef WL_NAN
2365 if (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg))) {
2366 return WL_IF_TYPE_NAN;
2367 }
2368 #endif /* WL_NAN */
2369 return WL_IFACE_NOT_PRESENT;
2370 }
2371
2372 /*
2373 * Handle incoming data interface request based on policy.
2374 * If there is any conflicting interface, that will be
2375 * deleted.
2376 */
2377 s32
wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2378 wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 *cfg,
2379 wl_iftype_t new_wl_iftype)
2380 {
2381 s32 ret = BCME_OK;
2382 bool del_iface = false;
2383 wl_iftype_t sec_wl_if_type = wl_cfg80211_get_sec_iface(cfg);
2384
2385 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2386 new_wl_iftype == WL_IF_TYPE_NAN) {
2387 /* Multi NDP is allowed irrespective of Policy */
2388 return BCME_OK;
2389 }
2390
2391 if (sec_wl_if_type == WL_IFACE_NOT_PRESENT) {
2392 /*
2393 * If there is no active secondary I/F, there
2394 * is no interface conflict. Do nothing.
2395 */
2396 return BCME_OK;
2397 }
2398
2399 /* Handle secondary data link case */
2400 switch (cfg->iface_data.policy) {
2401 case WL_IF_POLICY_CUSTOM:
2402 case WL_IF_POLICY_DEFAULT: {
2403 if (sec_wl_if_type == WL_IF_TYPE_NAN) {
2404 /* NAN has the lowest priority */
2405 del_iface = true;
2406 } else {
2407 /* Active iface is present, returning error */
2408 ret = BCME_ERROR;
2409 }
2410 break;
2411 }
2412 case WL_IF_POLICY_FCFS: {
2413 WL_INFORM_MEM(("Found active iface = %s, can't support new iface = %s\n",
2414 wl_iftype_to_str(sec_wl_if_type), wl_iftype_to_str(new_wl_iftype)));
2415 ret = BCME_ERROR;
2416 break;
2417 }
2418 case WL_IF_POLICY_LP: {
2419 WL_INFORM_MEM(("Remove active sec data interface, allow incoming iface\n"));
2420 /* Delete existing data iface and allow incoming sec iface */
2421 del_iface = true;
2422 break;
2423 }
2424 case WL_IF_POLICY_ROLE_PRIORITY: {
2425 WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2426 wl_iftype_to_str(sec_wl_if_type),
2427 cfg->iface_data.priority[sec_wl_if_type],
2428 wl_iftype_to_str(new_wl_iftype),
2429 cfg->iface_data.priority[new_wl_iftype]));
2430 if (cfg->iface_data.priority[new_wl_iftype] >
2431 cfg->iface_data.priority[sec_wl_if_type]) {
2432 del_iface = true;
2433 } else {
2434 WL_ERR(("Can't support new iface = %s\n",
2435 wl_iftype_to_str(new_wl_iftype)));
2436 ret = BCME_ERROR;
2437 }
2438 break;
2439 }
2440 default: {
2441 WL_ERR(("Unsupported interface policy = %d\n",
2442 cfg->iface_data.policy));
2443 return BCME_ERROR;
2444 }
2445 }
2446 if (del_iface) {
2447 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2448 }
2449 return ret;
2450 }
2451
2452 /* Handle discovery ifaces based on policy */
2453 s32
wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype,bool * disable_nan,bool * disable_p2p)2454 wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 *cfg,
2455 wl_iftype_t new_wl_iftype, bool *disable_nan, bool *disable_p2p)
2456 {
2457 s32 ret = BCME_OK;
2458 wl_iftype_t sec_wl_if_type =
2459 wl_cfg80211_get_sec_iface(cfg);
2460 *disable_p2p = false;
2461 *disable_nan = false;
2462
2463 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2464 new_wl_iftype == WL_IF_TYPE_NAN) {
2465 /* Multi NDP is allowed irrespective of Policy */
2466 return BCME_OK;
2467 }
2468
2469 /*
2470 * Check for any policy conflicts with active secondary
2471 * interface for incoming discovery iface
2472 */
2473 if ((sec_wl_if_type != WL_IFACE_NOT_PRESENT) &&
2474 (is_discovery_iface(new_wl_iftype))) {
2475 switch (cfg->iface_data.policy) {
2476 case WL_IF_POLICY_CUSTOM: {
2477 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2478 new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2479 WL_INFORM_MEM(("Allow P2P Discovery with active NDP\n"));
2480 /* No further checks are required. */
2481 return BCME_OK;
2482 }
2483 /*
2484 * Intentional fall through to default policy
2485 * as for AP and associated ifaces, both are same
2486 */
2487 }
2488 case WL_IF_POLICY_DEFAULT: {
2489 if (sec_wl_if_type == WL_IF_TYPE_AP) {
2490 WL_INFORM_MEM(("AP is active, cant support new iface\n"));
2491 ret = BCME_ERROR;
2492 } else if (sec_wl_if_type == WL_IF_TYPE_P2P_GC ||
2493 sec_wl_if_type == WL_IF_TYPE_P2P_GO) {
2494 if (new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2495 /*
2496 * Associated discovery case,
2497 * Fall through
2498 */
2499 } else {
2500 /* Active iface is present, returning error */
2501 WL_INFORM_MEM(("P2P group is active,"
2502 " cant support new iface\n"));
2503 ret = BCME_ERROR;
2504 }
2505 } else if (sec_wl_if_type == WL_IF_TYPE_NAN) {
2506 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2507 }
2508 break;
2509 }
2510 case WL_IF_POLICY_FCFS: {
2511 WL_INFORM_MEM(("Can't support new iface = %s\n",
2512 wl_iftype_to_str(new_wl_iftype)));
2513 ret = BCME_ERROR;
2514 break;
2515 }
2516 case WL_IF_POLICY_LP: {
2517 /* Delete existing data iface n allow incoming sec iface */
2518 WL_INFORM_MEM(("Remove active sec data interface = %s\n",
2519 wl_iftype_to_str(sec_wl_if_type)));
2520 ret = wl_cfg80211_delete_iface(cfg,
2521 sec_wl_if_type);
2522 break;
2523 }
2524 case WL_IF_POLICY_ROLE_PRIORITY: {
2525 WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2526 wl_iftype_to_str(sec_wl_if_type),
2527 cfg->iface_data.priority[sec_wl_if_type],
2528 wl_iftype_to_str(new_wl_iftype),
2529 cfg->iface_data.priority[new_wl_iftype]));
2530 if (cfg->iface_data.priority[new_wl_iftype] >
2531 cfg->iface_data.priority[sec_wl_if_type]) {
2532 WL_INFORM_MEM(("Remove active sec data iface\n"));
2533 ret = wl_cfg80211_delete_iface(cfg,
2534 sec_wl_if_type);
2535 } else {
2536 WL_ERR(("Can't support new iface = %s"
2537 " due to low priority\n",
2538 wl_iftype_to_str(new_wl_iftype)));
2539 ret = BCME_ERROR;
2540 }
2541 break;
2542 }
2543 default: {
2544 WL_ERR(("Unsupported policy\n"));
2545 return BCME_ERROR;
2546 }
2547 }
2548 } else {
2549 /*
2550 * Handle incoming new secondary iface request,
2551 * irrespective of existing discovery ifaces
2552 */
2553 if ((cfg->iface_data.policy == WL_IF_POLICY_CUSTOM) &&
2554 (new_wl_iftype == WL_IF_TYPE_NAN)) {
2555 WL_INFORM_MEM(("Allow NAN Data Path\n"));
2556 /* No further checks are required. */
2557 return BCME_OK;
2558 }
2559 }
2560
2561 /* Check for any conflicting discovery iface */
2562 switch (new_wl_iftype) {
2563 case WL_IF_TYPE_P2P_DISC:
2564 case WL_IF_TYPE_P2P_GO:
2565 case WL_IF_TYPE_P2P_GC: {
2566 *disable_nan = true;
2567 break;
2568 }
2569 case WL_IF_TYPE_NAN_NMI:
2570 case WL_IF_TYPE_NAN: {
2571 *disable_p2p = true;
2572 break;
2573 }
2574 case WL_IF_TYPE_STA:
2575 case WL_IF_TYPE_AP: {
2576 *disable_nan = true;
2577 *disable_p2p = true;
2578 break;
2579 }
2580 default: {
2581 WL_ERR(("Unsupported\n"));
2582 return BCME_ERROR;
2583 }
2584 }
2585 return ret;
2586 }
2587
2588 bool
wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2589 wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 *cfg,
2590 wl_iftype_t new_wl_iftype)
2591 {
2592 struct net_device *p2p_ndev = NULL;
2593 p2p_ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
2594
2595 if (new_wl_iftype == WL_IF_TYPE_P2P_DISC && p2p_ndev &&
2596 p2p_ndev->ieee80211_ptr &&
2597 is_p2p_group_iface(p2p_ndev->ieee80211_ptr)) {
2598 return true;
2599 }
2600 #ifdef WL_NAN
2601 else if ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) &&
2602 (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg)))) {
2603 return true;
2604 }
2605 #endif /* WL_NAN */
2606 return false;
2607 }
2608
2609 /* Handle incoming discovery iface request */
2610 s32
wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2611 wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 *cfg,
2612 wl_iftype_t new_wl_iftype)
2613 {
2614 s32 ret = BCME_OK;
2615 bool disable_p2p = false;
2616 bool disable_nan = false;
2617
2618 wl_iftype_t active_sec_iface =
2619 wl_cfg80211_get_sec_iface(cfg);
2620
2621 if (is_discovery_iface(new_wl_iftype) &&
2622 (active_sec_iface != WL_IFACE_NOT_PRESENT)) {
2623 if (wl_cfg80211_is_associated_discovery(cfg,
2624 new_wl_iftype) == TRUE) {
2625 WL_DBG(("Associate iface request is allowed= %s\n",
2626 wl_iftype_to_str(new_wl_iftype)));
2627 return ret;
2628 }
2629 }
2630
2631 ret = wl_cfg80211_disc_if_mgmt(cfg, new_wl_iftype,
2632 &disable_nan, &disable_p2p);
2633 if (ret != BCME_OK) {
2634 WL_ERR(("Failed at disc iface mgmt, ret = %d\n", ret));
2635 return ret;
2636 }
2637 #ifdef WL_NANP2P
2638 if (((new_wl_iftype == WL_IF_TYPE_P2P_DISC) && disable_nan) ||
2639 ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) && disable_p2p)) {
2640 if ((cfg->nan_p2p_supported == TRUE) &&
2641 (cfg->conc_disc == WL_NANP2P_CONC_SUPPORT)) {
2642 WL_INFORM_MEM(("P2P + NAN conc is supported\n"));
2643 disable_p2p = false;
2644 disable_nan = false;
2645 }
2646 }
2647 #endif /* WL_NANP2P */
2648
2649 if (disable_nan) {
2650 #ifdef WL_NAN
2651 /* Disable nan */
2652 cfg->nancfg.disable_reason = NAN_CONCURRENCY_CONFLICT;
2653 ret = wl_cfgnan_disable(cfg);
2654 if (ret != BCME_OK) {
2655 WL_ERR(("failed to disable nan, error[%d]\n", ret));
2656 return ret;
2657 }
2658 #endif /* WL_NAN */
2659 }
2660
2661 if (disable_p2p) {
2662 /* Disable p2p discovery */
2663 ret = wl_cfg80211_deinit_p2p_discovery(cfg);
2664 if (ret != BCME_OK) {
2665 WL_ERR(("Failed to disable p2p_disc for allowing nan\n"));
2666 return ret;
2667 }
2668 }
2669 return ret;
2670 }
2671
2672 /*
2673 * Check for any conflicting iface before adding iface.
2674 * Based on policy, either conflicting iface is removed
2675 * or new iface add request is blocked.
2676 */
2677 s32
wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2678 wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg,
2679 wl_iftype_t new_wl_iftype)
2680 {
2681 s32 ret = BCME_OK;
2682
2683 WL_INFORM_MEM(("Incoming iface = %s\n", wl_iftype_to_str(new_wl_iftype)));
2684
2685 if (!is_discovery_iface(new_wl_iftype)) {
2686 /* Incoming data interface request */
2687 if (wl_cfg80211_get_sec_iface(cfg) != WL_IFACE_NOT_PRESENT) {
2688 /* active interface present - Apply interface data policy */
2689 ret = wl_cfg80211_data_if_mgmt(cfg, new_wl_iftype);
2690 if (ret != BCME_OK) {
2691 WL_ERR(("if_mgmt fail:%d\n", ret));
2692 return ret;
2693 }
2694 }
2695 }
2696 /* Apply discovery config */
2697 ret = wl_cfg80211_handle_discovery_config(cfg, new_wl_iftype);
2698 return ret;
2699 }
2700 #endif /* WL_IFACE_MGMT */
2701
2702 static struct wireless_dev *
wl_cfg80211_add_monitor_if(struct wiphy * wiphy,const char * name)2703 wl_cfg80211_add_monitor_if(struct wiphy *wiphy, const char *name)
2704 {
2705 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
2706 WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2707 return ERR_PTR(-EOPNOTSUPP);
2708 #else
2709 struct wireless_dev *wdev;
2710 struct net_device* ndev = NULL;
2711
2712 dhd_add_monitor(name, &ndev);
2713
2714 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2715 if (!wdev) {
2716 WL_ERR(("wireless_dev alloc failed! \n"));
2717 goto fail;
2718 }
2719
2720 wdev->wiphy = wiphy;
2721 wdev->iftype = NL80211_IFTYPE_MONITOR;
2722 ndev->ieee80211_ptr = wdev;
2723 SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
2724
2725 WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
2726 return ndev->ieee80211_ptr;
2727 fail:
2728 return ERR_PTR(-EOPNOTSUPP);
2729 #endif // endif
2730 }
2731
2732 static struct wireless_dev *
wl_cfg80211_add_ibss(struct wiphy * wiphy,u16 wl_iftype,char const * name)2733 wl_cfg80211_add_ibss(struct wiphy *wiphy, u16 wl_iftype, char const *name)
2734 {
2735 #ifdef WLAIBSS_MCHAN
2736 /* AIBSS */
2737 return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
2738 #else
2739 /* Normal IBSS */
2740 WL_ERR(("IBSS not supported on Virtual iface\n"));
2741 return NULL;
2742 #endif // endif
2743 }
2744
2745 s32
wl_release_vif_macaddr(struct bcm_cfg80211 * cfg,u8 * mac_addr,u16 wl_iftype)2746 wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype)
2747 {
2748 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2749 u16 org_toggle_bytes;
2750 u16 cur_toggle_bytes;
2751 u16 toggled_bit;
2752
2753 if (!ndev || !mac_addr || ETHER_ISNULLADDR(mac_addr)) {
2754 return -EINVAL;
2755 }
2756 WL_DBG(("%s:Mac addr" MACDBG "\n",
2757 __FUNCTION__, MAC2STRDBG(mac_addr)));
2758
2759 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_AP) ||
2760 (wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2761 /* Avoid invoking release mac addr code for interfaces using
2762 * fixed mac addr.
2763 */
2764 return BCME_OK;
2765 }
2766
2767 /* Fetch last two bytes of mac address */
2768 org_toggle_bytes = ntoh16(*((u16 *)&ndev->dev_addr[4]));
2769 cur_toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
2770
2771 toggled_bit = (org_toggle_bytes ^ cur_toggle_bytes);
2772 WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n",
2773 org_toggle_bytes, cur_toggle_bytes));
2774 if (toggled_bit & cfg->vif_macaddr_mask) {
2775 /* This toggled_bit is marked in the used mac addr
2776 * mask. Clear it.
2777 */
2778 cfg->vif_macaddr_mask &= ~toggled_bit;
2779 WL_INFORM(("MAC address - " MACDBG " released. toggled_bit:%04X vif_mask:%04X\n",
2780 MAC2STRDBG(mac_addr), toggled_bit, cfg->vif_macaddr_mask));
2781 } else {
2782 WL_ERR(("MAC address - " MACDBG " not found in the used list."
2783 " toggled_bit:%04x vif_mask:%04x\n", MAC2STRDBG(mac_addr),
2784 toggled_bit, cfg->vif_macaddr_mask));
2785 return -EINVAL;
2786 }
2787
2788 return BCME_OK;
2789 }
2790
2791 s32
wl_get_vif_macaddr(struct bcm_cfg80211 * cfg,u16 wl_iftype,u8 * mac_addr)2792 wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr)
2793 {
2794 #ifdef WL_P2P_USE_RANDMAC
2795 struct ether_addr *p2p_dev_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE);
2796 #endif // endif
2797 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2798 u16 toggle_mask;
2799 u16 toggle_bit;
2800 u16 toggle_bytes;
2801 u16 used;
2802 u32 offset = 0;
2803 /* Toggle mask starts from MSB of second last byte */
2804 u16 mask = 0x8000;
2805 if (!mac_addr) {
2806 return -EINVAL;
2807 }
2808 #ifdef WL_P2P_USE_RANDMAC
2809 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
2810 memcpy_s(mac_addr, ETH_ALEN, p2p_dev_addr->octet, ETH_ALEN);
2811 return 0;
2812 }
2813 #endif // endif
2814 memcpy(mac_addr, ndev->dev_addr, ETH_ALEN);
2815 /*
2816 * VIF MAC address managment
2817 * P2P Device addres: Primary MAC with locally admin. bit set
2818 * P2P Group address/NAN NMI/Softap/NAN DPI: Primary MAC addr
2819 * with local admin bit set and one additional bit toggled.
2820 * cfg->vif_macaddr_mask will hold the info regarding the mac address
2821 * released. Ensure to call wl_release_vif_macaddress to free up
2822 * the mac address.
2823 */
2824 #if defined(SPECIFIC_MAC_GEN_SCHEME)
2825 if (wl_iftype == WL_IF_TYPE_P2P_DISC || wl_iftype == WL_IF_TYPE_AP) {
2826 mac_addr[0] |= 0x02;
2827 } else if ((wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2828 mac_addr[0] |= 0x02;
2829 mac_addr[4] ^= 0x80;
2830 }
2831 #else
2832 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
2833 mac_addr[0] |= 0x02;
2834 }
2835 #endif /* SEPCIFIC_MAC_GEN_SCHEME */
2836 else {
2837 /* For locally administered mac addresses, we keep the
2838 * OUI part constant and just work on the last two bytes.
2839 */
2840 mac_addr[0] |= 0x02;
2841 toggle_mask = cfg->vif_macaddr_mask;
2842 toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
2843 do {
2844 used = toggle_mask & mask;
2845 if (!used) {
2846 /* Use this bit position */
2847 toggle_bit = mask >> offset;
2848 toggle_bytes ^= toggle_bit;
2849 cfg->vif_macaddr_mask |= toggle_bit;
2850 WL_DBG(("toggle_bit:%04X toggle_bytes:%04X toggle_mask:%04X\n",
2851 toggle_bit, toggle_bytes, cfg->vif_macaddr_mask));
2852 /* Macaddress are stored in network order */
2853 mac_addr[5] = *((u8 *)&toggle_bytes);
2854 mac_addr[4] = *(((u8 *)&toggle_bytes + 1));
2855 break;
2856 }
2857
2858 /* Shift by one */
2859 toggle_mask = toggle_mask << 0x1;
2860 offset++;
2861 if (offset > MAX_VIF_OFFSET) {
2862 /* We have used up all macaddresses. Something wrong! */
2863 WL_ERR(("Entire range of macaddress used up.\n"));
2864 ASSERT(0);
2865 break;
2866 }
2867 } while (true);
2868 }
2869 WL_INFORM_MEM(("Get virtual I/F mac addr: "MACDBG"\n", MAC2STRDBG(mac_addr)));
2870 return 0;
2871 }
2872 #ifdef DNGL_AXI_ERROR_LOGGING
2873 static s32
_wl_cfg80211_check_axi_error(struct bcm_cfg80211 * cfg)2874 _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg)
2875 {
2876 s32 ret = BCME_OK;
2877 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2878 hnd_ext_trap_hdr_t *hdr;
2879 int axi_host_error_size;
2880 uint8 *new_dst;
2881 uint32 *ext_data = dhd->extended_trap_data;
2882 struct file *fp = NULL;
2883 char *filename = DHD_COMMON_DUMP_PATH
2884 DHD_DUMP_AXI_ERROR_FILENAME
2885 DHD_DUMP_HAL_FILENAME_SUFFIX;
2886
2887 WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename));
2888
2889 fp = filp_open(filename, O_RDONLY, 0);
2890
2891 if (IS_ERR(fp) || (fp == NULL)) {
2892 WL_ERR(("%s: Couldn't read the file, err %ld,File [%s] No previous axi error \n",
2893 __FUNCTION__, PTR_ERR(fp), filename));
2894 return ret;
2895 }
2896
2897 kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t));
2898 filp_close(fp, NULL);
2899
2900 /* Delete axi error info file */
2901 if (dhd_file_delete(filename) < 0) {
2902 WL_ERR(("%s(): Failed to delete file: %s\n", __FUNCTION__, filename));
2903 return ret;
2904 }
2905 WL_ERR(("%s(): Success to delete file: %s\n", __FUNCTION__, filename));
2906
2907 if (dhd->axi_err_dump->etd_axi_error_v1.signature != HND_EXT_TRAP_AXIERROR_SIGNATURE) {
2908 WL_ERR(("%s: Invalid AXI signature: 0x%x\n",
2909 __FUNCTION__, dhd->axi_err_dump->etd_axi_error_v1.signature));
2910 }
2911
2912 /* First word is original trap_data */
2913 ext_data++;
2914
2915 /* Followed by the extended trap data header */
2916 hdr = (hnd_ext_trap_hdr_t *)ext_data;
2917 new_dst = hdr->data;
2918
2919 axi_host_error_size = sizeof(dhd->axi_err_dump->axid)
2920 + sizeof(dhd->axi_err_dump->fault_address);
2921
2922 /* TAG_TRAP_AXI_HOST_INFO tlv : host's axid, fault address */
2923 new_dst = bcm_write_tlv(TAG_TRAP_AXI_HOST_INFO,
2924 (const void *)dhd->axi_err_dump,
2925 axi_host_error_size, new_dst);
2926
2927 /* TAG_TRAP_AXI_ERROR tlv */
2928 new_dst = bcm_write_tlv(TAG_TRAP_AXI_ERROR,
2929 (const void *)&dhd->axi_err_dump->etd_axi_error_v1,
2930 sizeof(dhd->axi_err_dump->etd_axi_error_v1), new_dst);
2931 hdr->len = new_dst - hdr->data;
2932
2933 dhd->dongle_trap_occured = TRUE;
2934 memset(dhd->axi_err_dump, 0, sizeof(dhd_axi_error_dump_t));
2935
2936 dhd->hang_reason = HANG_REASON_DONGLE_TRAP;
2937 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2938 ret = BCME_ERROR;
2939 return ret;
2940 }
2941 #endif /* DNGL_AXI_ERROR_LOGGING */
2942
2943 /* All Android/Linux private/Vendor Interface calls should make
2944 * use of below API for interface creation.
2945 */
2946 struct wireless_dev *
wl_cfg80211_add_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,wl_iftype_t wl_iftype,const char * name,u8 * mac)2947 wl_cfg80211_add_if(struct bcm_cfg80211 *cfg,
2948 struct net_device *primary_ndev,
2949 wl_iftype_t wl_iftype, const char *name, u8 *mac)
2950 {
2951 u8 mac_addr[ETH_ALEN];
2952 s32 err = -ENODEV;
2953 struct wireless_dev *wdev = NULL;
2954 struct wiphy *wiphy;
2955 s32 wl_mode;
2956 dhd_pub_t *dhd;
2957 wl_iftype_t macaddr_iftype = wl_iftype;
2958
2959 printk(KERN_INFO"%s if name: %s, wl_iftype:%d \n", __func__,
2960 name ? name : "NULL", wl_iftype);
2961 if (!cfg || !primary_ndev || !name) {
2962 WL_ERR(("cfg/ndev/name ptr null\n"));
2963 return NULL;
2964 }
2965 if (wl_cfg80211_get_wdev_from_ifname(cfg, name)) {
2966 WL_ERR(("Interface name %s exists!\n", name));
2967 return NULL;
2968 }
2969
2970 wiphy = bcmcfg_to_wiphy(cfg);
2971 dhd = (dhd_pub_t *)(cfg->pub);
2972 if (!dhd) {
2973 return NULL;
2974 }
2975
2976 if ((wl_mode = wl_iftype_to_mode(wl_iftype)) < 0) {
2977 return NULL;
2978 }
2979 mutex_lock(&cfg->if_sync);
2980 #ifdef WL_NAN
2981 if (wl_iftype == WL_IF_TYPE_NAN) {
2982 /*
2983 * Bypass the role conflict check for NDI and handle it
2984 * from dp req and dp resp context
2985 * because in aware comms, ndi gets created soon after nan enable.
2986 */
2987 } else
2988 #endif /* WL_NAN */
2989 #ifdef WL_IFACE_MGMT
2990 if ((err = wl_cfg80211_handle_if_role_conflict(cfg, wl_iftype)) < 0) {
2991 mutex_unlock(&cfg->if_sync);
2992 return NULL;
2993 }
2994 #endif /* WL_IFACE_MGMT */
2995 #ifdef DNGL_AXI_ERROR_LOGGING
2996 /* Check the previous smmu fault error */
2997 if ((err = _wl_cfg80211_check_axi_error(cfg)) < 0) {
2998 mutex_unlock(&cfg->if_sync);
2999 return NULL;
3000 }
3001 #endif /* DNGL_AXI_ERROR_LOGGING */
3002 /* Protect the interace op context */
3003 /* Do pre-create ops */
3004 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CREATE_REQ,
3005 wl_iftype, wl_mode);
3006
3007 if (strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)) == 0) {
3008 macaddr_iftype = WL_IF_TYPE_AP;
3009 }
3010
3011 if (mac) {
3012 /* If mac address is provided, use that */
3013 memcpy(mac_addr, mac, ETH_ALEN);
3014 } else if ((wl_get_vif_macaddr(cfg, macaddr_iftype, mac_addr) != BCME_OK)) {
3015 /* Fetch the mac address to be used for virtual interface */
3016 err = -EINVAL;
3017 goto fail;
3018 }
3019
3020 switch (wl_iftype) {
3021 case WL_IF_TYPE_IBSS:
3022 wdev = wl_cfg80211_add_ibss(wiphy, wl_iftype, name);
3023 break;
3024 case WL_IF_TYPE_MONITOR:
3025 wdev = wl_cfg80211_add_monitor_if(wiphy, name);
3026 break;
3027 case WL_IF_TYPE_STA:
3028 case WL_IF_TYPE_AP:
3029 case WL_IF_TYPE_NAN:
3030 if (cfg->iface_cnt >= (IFACE_MAX_CNT - 1)) {
3031 WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
3032 cfg->iface_cnt));
3033 err = -ENOTSUPP;
3034 goto fail;
3035 }
3036 wdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
3037 wl_iftype, mac_addr, name);
3038 break;
3039 case WL_IF_TYPE_P2P_DISC:
3040 case WL_IF_TYPE_P2P_GO:
3041 /* Intentional fall through */
3042 case WL_IF_TYPE_P2P_GC:
3043 if (cfg->p2p_supported) {
3044 wdev = wl_cfg80211_p2p_if_add(cfg, wl_iftype,
3045 name, mac_addr, &err);
3046 break;
3047 }
3048 /* Intentionally fall through for unsupported interface
3049 * handling when firmware doesn't support p2p
3050 */
3051 default:
3052 WL_ERR(("Unsupported interface type\n"));
3053 err = -ENOTSUPP;
3054 goto fail;
3055 }
3056
3057 if (!wdev) {
3058 WL_ERR(("vif create failed. err:%d\n", err));
3059 if (err != -ENOTSUPP) {
3060 err = -ENODEV;
3061 }
3062 goto fail;
3063 }
3064
3065 /* Ensure decrementing in case of failure */
3066 cfg->vif_count++;
3067
3068 wl_cfg80211_iface_state_ops(wdev,
3069 WL_IF_CREATE_DONE, wl_iftype, wl_mode);
3070
3071 WL_INFORM_MEM(("Vif created. dev->ifindex:%d"
3072 " cfg_iftype:%d, vif_count:%d\n",
3073 (wdev->netdev ? wdev->netdev->ifindex : 0xff),
3074 wdev->iftype, cfg->vif_count));
3075 mutex_unlock(&cfg->if_sync);
3076 return wdev;
3077
3078 fail:
3079 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3080 WL_IF_DELETE_REQ, wl_iftype, wl_mode);
3081
3082 if (err != -ENOTSUPP) {
3083 /* For non-supported interfaces, just return error and
3084 * skip below recovery steps.
3085 */
3086 SUPP_LOG(("IF_ADD fail. err:%d\n", err));
3087 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3088 if (dhd_query_bus_erros(dhd)) {
3089 goto exit;
3090 }
3091 dhd->iface_op_failed = TRUE;
3092 #if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
3093 if (dhd->memdump_enabled) {
3094 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3095 dhd_bus_mem_dump(dhd);
3096 }
3097 #endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
3098 dhd->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
3099 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3100 }
3101 exit:
3102 mutex_unlock(&cfg->if_sync);
3103 return NULL;
3104 }
3105
3106 static bcm_struct_cfgdev *
wl_cfg80211_add_virtual_iface(struct wiphy * wiphy,const char * name,unsigned char name_assign_type,enum nl80211_iftype type,u32 * flags,struct vif_params * params)3107 wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
3108 #if defined(WL_CFG80211_P2P_DEV_IF)
3109 const char *name,
3110 #else
3111 char *name,
3112 #endif /* WL_CFG80211_P2P_DEV_IF */
3113 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
3114 unsigned char name_assign_type,
3115 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
3116 enum nl80211_iftype type,
3117 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3118 u32 *flags,
3119 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3120 struct vif_params *params)
3121 {
3122 u16 wl_iftype;
3123 u16 wl_mode;
3124 struct net_device *primary_ndev;
3125 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3126 struct wireless_dev *wdev;
3127
3128 WL_DBG(("Enter iftype: %d\n", type));
3129 if (!cfg) {
3130 return ERR_PTR(-EINVAL);
3131 }
3132
3133 /* Use primary I/F for sending cmds down to firmware */
3134 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3135 if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
3136 WL_ERR(("device is not ready\n"));
3137 return ERR_PTR(-ENODEV);
3138 }
3139
3140 if (!name) {
3141 WL_ERR(("Interface name not provided \n"));
3142 return ERR_PTR(-EINVAL);
3143 }
3144
3145 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3146 return ERR_PTR(-EINVAL);
3147 }
3148
3149 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, name, NULL);
3150 WL_INFORM_MEM(("add inf ifname=%s, type=%d, primary ifname=%s, wdev=%p, %p\n", name, type, primary_ndev->name, wdev, wdev?wdev->netdev:NULL));
3151 if (unlikely(!wdev)) {
3152 return ERR_PTR(-ENODEV);
3153 }
3154 return wdev_to_cfgdev(wdev);
3155 }
3156
3157 static s32
wl_cfg80211_del_ibss(struct wiphy * wiphy,struct wireless_dev * wdev)3158 wl_cfg80211_del_ibss(struct wiphy *wiphy, struct wireless_dev *wdev)
3159 {
3160 WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev));
3161 #ifdef WLAIBSS_MCHAN
3162 /* AIBSS */
3163 return bcm_cfg80211_del_ibss_if(wiphy, wdev);
3164 #else
3165 /* Normal IBSS */
3166 return wl_cfg80211_del_iface(wiphy, wdev);
3167 #endif // endif
3168 }
3169
3170 s32
wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)3171 wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
3172 struct wireless_dev *wdev, char *ifname)
3173 {
3174 int ret = BCME_OK;
3175 mutex_lock(&cfg->if_sync);
3176 ret = _wl_cfg80211_del_if(cfg, primary_ndev, wdev, ifname);
3177 mutex_unlock(&cfg->if_sync);
3178 return ret;
3179 }
3180
3181 s32
_wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)3182 _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
3183 struct wireless_dev *wdev, char *ifname)
3184 {
3185 int ret = BCME_OK;
3186 s32 bssidx;
3187 struct wiphy *wiphy;
3188 u16 wl_mode;
3189 u16 wl_iftype;
3190 struct net_info *netinfo;
3191 dhd_pub_t *dhd;
3192 BCM_REFERENCE(dhd);
3193
3194 if (!cfg) {
3195 return -EINVAL;
3196 }
3197
3198 dhd = (dhd_pub_t *)(cfg->pub);
3199
3200 if (!wdev && ifname) {
3201 /* If only ifname is provided, fetch corresponding wdev ptr from our
3202 * internal data structure
3203 */
3204 wdev = wl_cfg80211_get_wdev_from_ifname(cfg, ifname);
3205 }
3206
3207 /* Check whether we have a valid wdev ptr */
3208 if (unlikely(!wdev)) {
3209 WL_ERR(("wdev not found. '%s' does not exists\n", ifname));
3210 return -ENODEV;
3211 }
3212
3213 WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev->iftype));
3214
3215 wiphy = wdev->wiphy;
3216 #ifdef WL_CFG80211_P2P_DEV_IF
3217 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
3218 /* p2p discovery would be de-initialized in stop p2p
3219 * device context/from other virtual i/f creation context
3220 * so netinfo list may not have any node corresponding to
3221 * discovery I/F. Handle it before bssidx check.
3222 */
3223 ret = wl_cfg80211_p2p_if_del(wiphy, wdev);
3224 if (unlikely(ret)) {
3225 goto exit;
3226 } else {
3227 /* success case. return from here */
3228 if (cfg->vif_count) {
3229 cfg->vif_count--;
3230 }
3231 return BCME_OK;
3232 }
3233 }
3234 #endif /* WL_CFG80211_P2P_DEV_IF */
3235
3236 if ((netinfo = wl_get_netinfo_by_wdev(cfg, wdev)) == NULL) {
3237 WL_ERR(("Find netinfo from wdev %p failed\n", wdev));
3238 ret = -ENODEV;
3239 goto exit;
3240 }
3241
3242 if (!wdev->netdev) {
3243 WL_ERR(("ndev null! \n"));
3244 } else {
3245 /* Disable tx before del */
3246 netif_tx_disable(wdev->netdev);
3247 }
3248
3249 wl_iftype = netinfo->iftype;
3250 wl_mode = wl_iftype_to_mode(wl_iftype);
3251 bssidx = netinfo->bssidx;
3252 WL_INFORM_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
3253 wdev->iftype, wl_iftype, wl_mode, bssidx));
3254
3255 /* Do pre-interface del ops */
3256 wl_cfg80211_iface_state_ops(wdev, WL_IF_DELETE_REQ, wl_iftype, wl_mode);
3257
3258 switch (wl_iftype) {
3259 case WL_IF_TYPE_P2P_GO:
3260 case WL_IF_TYPE_P2P_GC:
3261 case WL_IF_TYPE_AP:
3262 case WL_IF_TYPE_STA:
3263 case WL_IF_TYPE_NAN:
3264 ret = wl_cfg80211_del_iface(wiphy, wdev);
3265 break;
3266 case WL_IF_TYPE_IBSS:
3267 ret = wl_cfg80211_del_ibss(wiphy, wdev);
3268 break;
3269
3270 default:
3271 WL_ERR(("Unsupported interface type\n"));
3272 ret = BCME_ERROR;
3273 }
3274
3275 exit:
3276 if (ret == BCME_OK) {
3277 /* Successful case */
3278 if (cfg->vif_count) {
3279 cfg->vif_count--;
3280 }
3281 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3282 WL_IF_DELETE_DONE, wl_iftype, wl_mode);
3283 #ifdef WL_NAN
3284 if (!((cfg->nancfg.mac_rand) && (wl_iftype == WL_IF_TYPE_NAN)))
3285 #endif /* WL_NAN */
3286 {
3287 wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype);
3288 }
3289 WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg->vif_count));
3290 } else {
3291 if (!wdev->netdev) {
3292 WL_ERR(("ndev null! \n"));
3293 } else {
3294 /* IF del failed. revert back tx queue status */
3295 netif_tx_start_all_queues(wdev->netdev);
3296 }
3297
3298 /* Skip generating log files and sending HANG event
3299 * if driver state is not READY
3300 */
3301 if (wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg))) {
3302 SUPP_LOG(("IF_DEL fail. err:%d\n", ret));
3303 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3304 /* IF dongle is down due to previous hang or other conditions, sending
3305 * one more hang notification is not needed.
3306 */
3307 if (dhd_query_bus_erros(dhd) || (ret == BCME_DONGLE_DOWN)) {
3308 goto end;
3309 }
3310 dhd->iface_op_failed = TRUE;
3311 #if defined(DHD_FW_COREDUMP)
3312 if (dhd->memdump_enabled && (ret != -EBADTYPE)) {
3313 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3314 dhd_bus_mem_dump(dhd);
3315 }
3316 #endif /* DHD_FW_COREDUMP */
3317 WL_ERR(("Notify hang event to upper layer \n"));
3318 dhd->hang_reason = HANG_REASON_IFACE_DEL_FAILURE;
3319 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3320 }
3321 }
3322 end:
3323 return ret;
3324 }
3325
3326 static s32
wl_cfg80211_del_virtual_iface(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev)3327 wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
3328 {
3329 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3330 struct wireless_dev *wdev = cfgdev_to_wdev(cfgdev);
3331 int ret = BCME_OK;
3332 u16 wl_iftype;
3333 u16 wl_mode;
3334 struct net_device *primary_ndev;
3335
3336 if (!cfg) {
3337 return -EINVAL;
3338 }
3339
3340 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3341 wdev = cfgdev_to_wdev(cfgdev);
3342 if (!wdev) {
3343 WL_ERR(("wdev null"));
3344 return -ENODEV;
3345 }
3346
3347 WL_DBG(("Enter wdev:%p iftype: %d\n", wdev, wdev->iftype));
3348 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
3349 WL_ERR(("Wrong iftype: %d\n", wdev->iftype));
3350 return -ENODEV;
3351 }
3352
3353 if ((ret = wl_cfg80211_del_if(cfg, primary_ndev,
3354 wdev, NULL)) < 0) {
3355 WL_ERR(("IF del failed\n"));
3356 }
3357
3358 return ret;
3359 }
3360
3361 static s32
wl_cfg80211_change_p2prole(struct wiphy * wiphy,struct net_device * ndev,enum nl80211_iftype type)3362 wl_cfg80211_change_p2prole(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type)
3363 {
3364 s32 wlif_type;
3365 s32 mode = 0;
3366 s32 index;
3367 s32 err;
3368 s32 conn_idx = -1;
3369 chanspec_t chspec;
3370 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3371 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3372
3373 WL_INFORM_MEM(("Enter. current_role:%d new_role:%d \n", ndev->ieee80211_ptr->iftype, type));
3374
3375 if (!cfg->p2p || !wl_cfgp2p_vif_created(cfg)) {
3376 WL_ERR(("P2P not initialized \n"));
3377 return -EINVAL;
3378 }
3379
3380 if (!is_p2p_group_iface(ndev->ieee80211_ptr)) {
3381 WL_ERR(("Wrong if type \n"));
3382 return -EINVAL;
3383 }
3384
3385 /* Abort any on-going scans to avoid race condition issues */
3386 wl_cfg80211_cancel_scan(cfg);
3387
3388 index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
3389 if (index < 0) {
3390 WL_ERR(("Find bsscfg index from ndev(%p) failed\n", ndev));
3391 return BCME_ERROR;
3392 }
3393 if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK) {
3394 return BCME_ERROR;
3395 }
3396
3397 /* In concurrency case, STA may be already associated in a particular
3398 * channel. so retrieve the current channel of primary interface and
3399 * then start the virtual interface on that.
3400 */
3401 chspec = wl_cfg80211_get_shared_freq(wiphy);
3402 if (type == NL80211_IFTYPE_P2P_GO) {
3403 /* Dual p2p doesn't support multiple P2PGO interfaces,
3404 * p2p_go_count is the counter for GO creation
3405 * requests.
3406 */
3407 if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
3408 WL_ERR(("FW does not support multiple GO\n"));
3409 return BCME_ERROR;
3410 }
3411 mode = WL_MODE_AP;
3412 wlif_type = WL_P2P_IF_GO;
3413 dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
3414 dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
3415 } else {
3416 wlif_type = WL_P2P_IF_CLIENT;
3417 /* for GO */
3418 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
3419 WL_INFORM_MEM(("Downgrading P2P GO to cfg_iftype:%d \n", type));
3420 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
3421 cfg->p2p->p2p_go_count--;
3422 /* disable interface before bsscfg free */
3423 err = wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx));
3424 /* if fw doesn't support "ifdis",
3425 * do not wait for link down of ap mode
3426 */
3427 if (err == 0) {
3428 WL_DBG(("Wait for Link Down event for GO !!!\n"));
3429 wait_for_completion_timeout(&cfg->iface_disable,
3430 msecs_to_jiffies(500));
3431 } else if (err != BCME_UNSUPPORTED) {
3432 msleep(300);
3433 }
3434 }
3435 }
3436
3437 wl_set_p2p_status(cfg, IF_CHANGING);
3438 wl_clr_p2p_status(cfg, IF_CHANGED);
3439 wl_cfgp2p_ifchange(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx),
3440 htod32(wlif_type), chspec, conn_idx);
3441 wait_event_interruptible_timeout(cfg->netif_change_event,
3442 (wl_get_p2p_status(cfg, IF_CHANGED) == true),
3443 msecs_to_jiffies(MAX_WAIT_TIME));
3444
3445 wl_clr_p2p_status(cfg, IF_CHANGING);
3446 wl_clr_p2p_status(cfg, IF_CHANGED);
3447
3448 if (mode == WL_MODE_AP) {
3449 wl_set_drv_status(cfg, CONNECTED, ndev);
3450 }
3451
3452 return BCME_OK;
3453 }
3454
3455 static s32
wl_cfg80211_change_virtual_iface(struct wiphy * wiphy,struct net_device * ndev,enum nl80211_iftype type,u32 * flags,struct vif_params * params)3456 wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
3457 enum nl80211_iftype type,
3458 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3459 u32 *flags,
3460 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3461 struct vif_params *params)
3462 {
3463 s32 infra = 1;
3464 s32 err = BCME_OK;
3465 u16 wl_iftype;
3466 u16 wl_mode;
3467 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3468 struct net_info *netinfo = NULL;
3469 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3470 struct net_device *primary_ndev;
3471
3472 if (!dhd)
3473 return -EINVAL;
3474
3475 printk(KERN_INFO"[%s] Enter. current cfg_iftype:%d new cfg_iftype:%d \n",
3476 ndev->name, ndev->ieee80211_ptr->iftype, type);
3477 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3478
3479 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3480 WL_ERR(("Unknown role \n"));
3481 return -EINVAL;
3482 }
3483
3484 mutex_lock(&cfg->if_sync);
3485 netinfo = wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
3486 if (unlikely(!netinfo)) {
3487 #ifdef WL_STATIC_IF
3488 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
3489 /* Incase of static interfaces, the netinfo will be
3490 * allocated only when FW interface is initialized. So
3491 * store the value and use it during initialization.
3492 */
3493 WL_INFORM_MEM(("skip change vif for static if\n"));
3494 ndev->ieee80211_ptr->iftype = type;
3495 err = BCME_OK;
3496 } else
3497 #endif /* WL_STATIC_IF */
3498 {
3499 WL_ERR(("netinfo not found \n"));
3500 err = -ENODEV;
3501 }
3502 goto fail;
3503 }
3504
3505 /* perform pre-if-change tasks */
3506 wl_cfg80211_iface_state_ops(ndev->ieee80211_ptr,
3507 WL_IF_CHANGE_REQ, wl_iftype, wl_mode);
3508
3509 switch (type) {
3510 case NL80211_IFTYPE_ADHOC:
3511 infra = 0;
3512 break;
3513 case NL80211_IFTYPE_STATION:
3514 /* Supplicant sets iftype to STATION while removing p2p GO */
3515 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
3516 /* Downgrading P2P GO */
3517 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3518 if (unlikely(err)) {
3519 WL_ERR(("P2P downgrade failed \n"));
3520 }
3521 } else if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
3522 /* Downgrade role from AP to STA */
3523 if ((err = wl_cfg80211_add_del_bss(cfg, ndev,
3524 netinfo->bssidx, wl_iftype, 0, NULL)) < 0) {
3525 WL_ERR(("AP-STA Downgrade failed \n"));
3526 goto fail;
3527 }
3528 }
3529 break;
3530 case NL80211_IFTYPE_AP:
3531 /* intentional fall through */
3532 case NL80211_IFTYPE_AP_VLAN:
3533 {
3534 if (!wl_get_drv_status(cfg, AP_CREATED, ndev) &&
3535 wl_get_drv_status(cfg, READY, ndev)) {
3536 err = wl_cfg80211_set_ap_role(cfg, ndev);
3537 if (unlikely(err)) {
3538 WL_ERR(("set ap role failed!\n"));
3539 goto fail;
3540 }
3541 } else {
3542 WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
3543 }
3544 break;
3545 }
3546 case NL80211_IFTYPE_P2P_GO:
3547 /* Intentional fall through */
3548 case NL80211_IFTYPE_P2P_CLIENT:
3549 infra = 1;
3550 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3551 break;
3552 case NL80211_IFTYPE_MONITOR:
3553 case NL80211_IFTYPE_WDS:
3554 case NL80211_IFTYPE_MESH_POINT:
3555 /* Intentional fall through */
3556 default:
3557 WL_ERR(("Unsupported type:%d \n", type));
3558 err = -EINVAL;
3559 goto fail;
3560 }
3561
3562 if (wl_get_drv_status(cfg, READY, ndev)) {
3563 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(s32));
3564 if (err < 0) {
3565 WL_ERR(("SET INFRA/IBSS error %d\n", err));
3566 goto fail;
3567 }
3568 }
3569
3570 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3571 WL_IF_CHANGE_DONE, wl_iftype, wl_mode);
3572
3573 /* Update new iftype in relevant structures */
3574 ndev->ieee80211_ptr->iftype = type;
3575 netinfo->iftype = wl_iftype;
3576 WL_INFORM_MEM(("[%s] cfg_iftype changed to %d\n", ndev->name, type));
3577 #ifdef WL_EXT_IAPSTA
3578 wl_ext_iapsta_update_iftype(ndev, netinfo->ifidx, wl_iftype);
3579 #endif
3580
3581 fail:
3582 if (err) {
3583 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
3584 }
3585 mutex_unlock(&cfg->if_sync);
3586 return err;
3587 }
3588
3589 s32
wl_cfg80211_notify_ifadd(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx,uint8 role)3590 wl_cfg80211_notify_ifadd(struct net_device *dev,
3591 int ifidx, char *name, uint8 *mac, uint8 bssidx, uint8 role)
3592 {
3593 bool ifadd_expected = FALSE;
3594 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3595 bool bss_pending_op = TRUE;
3596
3597 /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
3598 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
3599 */
3600 if (wl_get_p2p_status(cfg, IF_CHANGING))
3601 return wl_cfg80211_notify_ifchange(dev, ifidx, name, mac, bssidx);
3602
3603 /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
3604 if (wl_get_p2p_status(cfg, IF_ADDING)) {
3605 ifadd_expected = TRUE;
3606 wl_clr_p2p_status(cfg, IF_ADDING);
3607 } else if (cfg->bss_pending_op) {
3608 ifadd_expected = TRUE;
3609 bss_pending_op = FALSE;
3610 }
3611
3612 if (ifadd_expected) {
3613 wl_if_event_info *if_event_info = &cfg->if_event_info;
3614
3615 if_event_info->valid = TRUE;
3616 if_event_info->ifidx = ifidx;
3617 if_event_info->bssidx = bssidx;
3618 if_event_info->role = role;
3619 strlcpy(if_event_info->name, name, sizeof(if_event_info->name));
3620 if_event_info->name[IFNAMSIZ - 1] = '\0';
3621 if (mac)
3622 memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
3623
3624 /* Update bss pendig operation status */
3625 if (!bss_pending_op) {
3626 cfg->bss_pending_op = FALSE;
3627 }
3628 WL_INFORM_MEM(("IF_ADD ifidx:%d bssidx:%d role:%d\n",
3629 ifidx, bssidx, role));
3630 OSL_SMP_WMB();
3631 wake_up_interruptible(&cfg->netif_change_event);
3632 return BCME_OK;
3633 }
3634
3635 return BCME_ERROR;
3636 }
3637
3638 s32
wl_cfg80211_notify_ifdel(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)3639 wl_cfg80211_notify_ifdel(struct net_device *dev, int ifidx, char *name, uint8 *mac, uint8 bssidx)
3640 {
3641 bool ifdel_expected = FALSE;
3642 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3643 wl_if_event_info *if_event_info = &cfg->if_event_info;
3644 bool bss_pending_op = TRUE;
3645
3646 if (wl_get_p2p_status(cfg, IF_DELETING)) {
3647 ifdel_expected = TRUE;
3648 wl_clr_p2p_status(cfg, IF_DELETING);
3649 } else if (cfg->bss_pending_op) {
3650 ifdel_expected = TRUE;
3651 bss_pending_op = FALSE;
3652 }
3653
3654 if (ifdel_expected) {
3655 if_event_info->valid = TRUE;
3656 if_event_info->ifidx = ifidx;
3657 if_event_info->bssidx = bssidx;
3658 /* Update bss pendig operation status */
3659 if (!bss_pending_op) {
3660 cfg->bss_pending_op = FALSE;
3661 }
3662 WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx, bssidx));
3663 OSL_SMP_WMB();
3664 wake_up_interruptible(&cfg->netif_change_event);
3665 return BCME_OK;
3666 }
3667
3668 return BCME_ERROR;
3669 }
3670
3671 s32
wl_cfg80211_notify_ifchange(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)3672 wl_cfg80211_notify_ifchange(struct net_device * dev, int ifidx, char *name, uint8 *mac,
3673 uint8 bssidx)
3674 {
3675 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3676
3677 if (wl_get_p2p_status(cfg, IF_CHANGING)) {
3678 wl_set_p2p_status(cfg, IF_CHANGED);
3679 OSL_SMP_WMB();
3680 wake_up_interruptible(&cfg->netif_change_event);
3681 return BCME_OK;
3682 }
3683
3684 return BCME_ERROR;
3685 }
3686
wl_set_rts(struct net_device * dev,u32 rts_threshold)3687 static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
3688 {
3689 s32 err = 0;
3690
3691 err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
3692 if (unlikely(err)) {
3693 WL_ERR(("Error (%d)\n", err));
3694 return err;
3695 }
3696 return err;
3697 }
3698
wl_set_frag(struct net_device * dev,u32 frag_threshold)3699 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
3700 {
3701 s32 err = 0;
3702
3703 err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
3704 if (unlikely(err)) {
3705 WL_ERR(("Error (%d)\n", err));
3706 return err;
3707 }
3708 return err;
3709 }
3710
wl_set_retry(struct net_device * dev,u32 retry,bool l)3711 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
3712 {
3713 s32 err = 0;
3714 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
3715
3716 #ifdef CUSTOM_LONG_RETRY_LIMIT
3717 if ((cmd == WLC_SET_LRL) &&
3718 (retry != CUSTOM_LONG_RETRY_LIMIT)) {
3719 WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
3720 return err;
3721 }
3722 #endif /* CUSTOM_LONG_RETRY_LIMIT */
3723
3724 retry = htod32(retry);
3725 err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry));
3726 if (unlikely(err)) {
3727 WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
3728 return err;
3729 }
3730 return err;
3731 }
3732
wl_cfg80211_set_wiphy_params(struct wiphy * wiphy,u32 changed)3733 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
3734 {
3735 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
3736 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
3737 s32 err = 0;
3738
3739 RETURN_EIO_IF_NOT_UP(cfg);
3740 WL_DBG(("Enter\n"));
3741 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
3742 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
3743 cfg->conf->rts_threshold = wiphy->rts_threshold;
3744 err = wl_set_rts(ndev, cfg->conf->rts_threshold);
3745 if (err != BCME_OK)
3746 return err;
3747 }
3748 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
3749 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
3750 cfg->conf->frag_threshold = wiphy->frag_threshold;
3751 err = wl_set_frag(ndev, cfg->conf->frag_threshold);
3752 if (err != BCME_OK)
3753 return err;
3754 }
3755 if (changed & WIPHY_PARAM_RETRY_LONG &&
3756 (cfg->conf->retry_long != wiphy->retry_long)) {
3757 cfg->conf->retry_long = wiphy->retry_long;
3758 err = wl_set_retry(ndev, cfg->conf->retry_long, true);
3759 if (err != BCME_OK)
3760 return err;
3761 }
3762 if (changed & WIPHY_PARAM_RETRY_SHORT &&
3763 (cfg->conf->retry_short != wiphy->retry_short)) {
3764 cfg->conf->retry_short = wiphy->retry_short;
3765 err = wl_set_retry(ndev, cfg->conf->retry_short, false);
3766 if (err != BCME_OK) {
3767 return err;
3768 }
3769 }
3770
3771 return err;
3772 }
3773 static chanspec_t
channel_to_chanspec(struct wiphy * wiphy,struct net_device * dev,u32 channel,u32 bw_cap)3774 channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap)
3775 {
3776 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3777 u8 *buf = NULL;
3778 wl_uint32_list_t *list;
3779 int err = BCME_OK;
3780 chanspec_t c = 0, ret_c = 0;
3781 int bw = 0, tmp_bw = 0;
3782 int i;
3783 u32 tmp_c;
3784
3785 #define LOCAL_BUF_SIZE 1024
3786 buf = (u8 *)MALLOC(cfg->osh, LOCAL_BUF_SIZE);
3787 if (!buf) {
3788 WL_ERR(("buf memory alloc failed\n"));
3789 goto exit;
3790 }
3791
3792 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
3793 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync);
3794 if (err != BCME_OK) {
3795 WL_ERR(("get chanspecs failed with %d\n", err));
3796 goto exit;
3797 }
3798
3799 list = (wl_uint32_list_t *)(void *)buf;
3800 for (i = 0; i < dtoh32(list->count); i++) {
3801 c = dtoh32(list->element[i]);
3802 if (channel <= CH_MAX_2G_CHANNEL) {
3803 if (!CHSPEC_IS20(c))
3804 continue;
3805 if (channel == CHSPEC_CHANNEL(c)) {
3806 ret_c = c;
3807 bw = 20;
3808 goto exit;
3809 }
3810 }
3811 tmp_c = wf_chspec_ctlchan(c);
3812 tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT];
3813 if (tmp_c != channel)
3814 continue;
3815
3816 if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) {
3817 bw = tmp_bw;
3818 ret_c = c;
3819 if (bw == bw_cap)
3820 goto exit;
3821 }
3822 }
3823 exit:
3824 if (buf) {
3825 MFREE(cfg->osh, buf, LOCAL_BUF_SIZE);
3826 }
3827 #undef LOCAL_BUF_SIZE
3828 WL_DBG(("return chanspec %x %d\n", ret_c, bw));
3829 return ret_c;
3830 }
3831
3832 void
wl_cfg80211_ibss_vsie_set_buffer(struct net_device * dev,vndr_ie_setbuf_t * ibss_vsie,int ibss_vsie_len)3833 wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev, vndr_ie_setbuf_t *ibss_vsie,
3834 int ibss_vsie_len)
3835 {
3836 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3837
3838 if (cfg != NULL && ibss_vsie != NULL) {
3839 if (cfg->ibss_vsie != NULL) {
3840 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3841 }
3842 cfg->ibss_vsie = ibss_vsie;
3843 cfg->ibss_vsie_len = ibss_vsie_len;
3844 }
3845 }
3846
3847 static void
wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 * cfg)3848 wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
3849 {
3850 /* free & initiralize VSIE (Vendor Specific IE) */
3851 if (cfg->ibss_vsie != NULL) {
3852 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3853 cfg->ibss_vsie_len = 0;
3854 }
3855 }
3856
3857 s32
wl_cfg80211_ibss_vsie_delete(struct net_device * dev)3858 wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
3859 {
3860 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3861 char *ioctl_buf = NULL;
3862 s32 ret = BCME_OK, bssidx;
3863
3864 if (cfg != NULL && cfg->ibss_vsie != NULL) {
3865 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
3866 if (!ioctl_buf) {
3867 WL_ERR(("ioctl memory alloc failed\n"));
3868 return -ENOMEM;
3869 }
3870 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3871 WL_ERR(("Find index failed\n"));
3872 ret = BCME_ERROR;
3873 goto end;
3874 }
3875 /* change the command from "add" to "del" */
3876 strlcpy(cfg->ibss_vsie->cmd, "del", sizeof(cfg->ibss_vsie->cmd));
3877
3878 ret = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie",
3879 cfg->ibss_vsie, cfg->ibss_vsie_len,
3880 ioctl_buf, WLC_IOCTL_MEDLEN, bssidx, NULL);
3881 WL_ERR(("ret=%d\n", ret));
3882
3883 if (ret == BCME_OK) {
3884 /* Free & initialize VSIE */
3885 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3886 cfg->ibss_vsie_len = 0;
3887 }
3888 end:
3889 if (ioctl_buf) {
3890 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3891 }
3892 }
3893
3894 return ret;
3895 }
3896
3897 #ifdef WLAIBSS_MCHAN
3898 static bcm_struct_cfgdev*
bcm_cfg80211_add_ibss_if(struct wiphy * wiphy,char * name)3899 bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name)
3900 {
3901 int err = 0;
3902 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3903 struct wireless_dev* wdev = NULL;
3904 struct net_device *new_ndev = NULL;
3905 struct net_device *primary_ndev = NULL;
3906 long timeout;
3907 wl_aibss_if_t aibss_if;
3908 wl_if_event_info *event = NULL;
3909
3910 if (cfg->ibss_cfgdev != NULL) {
3911 WL_ERR(("IBSS interface %s already exists\n", name));
3912 return NULL;
3913 }
3914
3915 WL_ERR(("Try to create IBSS interface %s\n", name));
3916 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3917 /* generate a new MAC address for the IBSS interface */
3918 get_primary_mac(cfg, &cfg->ibss_if_addr);
3919 cfg->ibss_if_addr.octet[4] ^= 0x40;
3920 bzero(&aibss_if, sizeof(aibss_if));
3921 memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
3922 aibss_if.chspec = 0;
3923 aibss_if.len = sizeof(aibss_if);
3924
3925 cfg->bss_pending_op = TRUE;
3926 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3927 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
3928 sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3929 if (err) {
3930 WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
3931 goto fail;
3932 }
3933 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3934 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
3935 if (timeout <= 0 || cfg->bss_pending_op)
3936 goto fail;
3937
3938 event = &cfg->if_event_info;
3939 /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
3940 * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
3941 * and will be freed by dhd_detach unless it gets unregistered before that. The
3942 * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
3943 * be freed by wl_dealloc_netinfo
3944 */
3945 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name,
3946 event->mac, event->bssidx, event->name);
3947 if (new_ndev == NULL)
3948 goto fail;
3949 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
3950 if (wdev == NULL)
3951 goto fail;
3952 wdev->wiphy = wiphy;
3953 wdev->iftype = NL80211_IFTYPE_ADHOC;
3954 wdev->netdev = new_ndev;
3955 new_ndev->ieee80211_ptr = wdev;
3956 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
3957
3958 /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
3959 * needs to be modified to take one parameter (bool need_rtnl_lock)
3960 */
3961 ASSERT_RTNL();
3962 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, FALSE) != BCME_OK)
3963 goto fail;
3964
3965 wl_alloc_netinfo(cfg, new_ndev, wdev, WL_IF_TYPE_IBSS,
3966 PM_ENABLE, event->bssidx, event->ifidx);
3967 cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
3968 WL_ERR(("IBSS interface %s created\n", new_ndev->name));
3969 return cfg->ibss_cfgdev;
3970
3971 fail:
3972 WL_ERR(("failed to create IBSS interface %s \n", name));
3973 cfg->bss_pending_op = FALSE;
3974 if (new_ndev)
3975 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
3976 if (wdev) {
3977 MFREE(cfg->osh, wdev, sizeof(*wdev));
3978 }
3979 return NULL;
3980 }
3981
3982 static s32
bcm_cfg80211_del_ibss_if(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev)3983 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
3984 {
3985 int err = 0;
3986 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3987 struct net_device *ndev = NULL;
3988 struct net_device *primary_ndev = NULL;
3989 long timeout;
3990
3991 if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet))
3992 return -EINVAL;
3993 ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev);
3994 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3995
3996 cfg->bss_pending_op = TRUE;
3997 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3998 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
3999 sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4000 if (err) {
4001 WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
4002 goto fail;
4003 }
4004 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4005 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4006 if (timeout <= 0 || cfg->bss_pending_op) {
4007 WL_ERR(("timeout in waiting IF_DEL event\n"));
4008 goto fail;
4009 }
4010
4011 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
4012 cfg->ibss_cfgdev = NULL;
4013 return 0;
4014
4015 fail:
4016 cfg->bss_pending_op = FALSE;
4017 return -1;
4018 }
4019 #endif /* WLAIBSS_MCHAN */
4020
4021 s32
wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)4022 wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)
4023 {
4024 s32 ret = BCME_ERROR;
4025
4026 switch (iftype) {
4027 case WL_IF_TYPE_AP:
4028 ret = WL_INTERFACE_TYPE_AP;
4029 break;
4030 case WL_IF_TYPE_STA:
4031 ret = WL_INTERFACE_TYPE_STA;
4032 break;
4033 case WL_IF_TYPE_NAN_NMI:
4034 case WL_IF_TYPE_NAN:
4035 ret = WL_INTERFACE_TYPE_NAN;
4036 break;
4037 case WL_IF_TYPE_P2P_DISC:
4038 ret = WL_INTERFACE_TYPE_P2P_DISC;
4039 break;
4040 case WL_IF_TYPE_P2P_GO:
4041 ret = WL_INTERFACE_TYPE_P2P_GO;
4042 break;
4043 case WL_IF_TYPE_P2P_GC:
4044 ret = WL_INTERFACE_TYPE_P2P_GC;
4045 break;
4046
4047 default:
4048 WL_ERR(("Unsupported type:%d \n", iftype));
4049 ret = -EINVAL;
4050 break;
4051 }
4052 return ret;
4053 }
4054
4055 s32
wl_cfg80211_interface_ops(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,wl_iftype_t cfg_iftype,s32 del,u8 * addr)4056 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
4057 struct net_device *ndev, s32 bsscfg_idx,
4058 wl_iftype_t cfg_iftype, s32 del, u8 *addr)
4059 {
4060 s32 ret;
4061 struct wl_interface_create_v2 iface;
4062 wl_interface_create_v3_t iface_v3;
4063 wl_interface_create_t iface_v0;
4064 struct wl_interface_info_v1 *info;
4065 wl_interface_info_v2_t *info_v2;
4066 wl_interface_info_t *info_v0;
4067 uint32 ifflags = 0;
4068 bool use_iface_info_v2 = false;
4069 u8 ioctl_buf[WLC_IOCTL_SMLEN];
4070 s32 iftype;
4071
4072 if (del) {
4073 ret = wldev_iovar_setbuf(ndev, "interface_remove",
4074 NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL);
4075 if (unlikely(ret))
4076 WL_ERR(("Interface remove failed!! ret %d\n", ret));
4077 return ret;
4078 }
4079
4080 /* Interface create */
4081 bzero(&iface, sizeof(iface));
4082 /*
4083 * flags field is still used along with iftype inorder to support the old version of the
4084 * FW work with the latest app changes.
4085 */
4086
4087 iftype = wl_cfg80211_to_fw_iftype(cfg_iftype);
4088 if (iftype < 0) {
4089 return -ENOTSUPP;
4090 }
4091
4092 if (addr) {
4093 ifflags |= WL_INTERFACE_MAC_USE;
4094 }
4095
4096 /* Pass ver = 0 for fetching the interface_create iovar version */
4097 if (wl_legacy_chip_check(ndev)) {
4098 bzero(&iface_v0, sizeof(iface_v0));
4099 iface_v0.ver = WL_INTERFACE_CREATE_VER;
4100 iface_v0.flags = iftype | ifflags;
4101 if (addr) {
4102 memcpy(&iface_v0.mac_addr.octet, addr, ETH_ALEN);
4103 }
4104 ret = wldev_iovar_getbuf(ndev, "interface_create",
4105 &iface_v0, sizeof(struct wl_interface_create),
4106 ioctl_buf, sizeof(ioctl_buf), NULL);
4107 if (ret == 0) {
4108 info_v0 = (wl_interface_info_t *)ioctl_buf;
4109 ret = info_v0->bsscfgidx;
4110 goto exit;
4111 }
4112 } else {
4113 ret = wldev_iovar_getbuf(ndev, "interface_create",
4114 &iface, sizeof(struct wl_interface_create_v2),
4115 ioctl_buf, sizeof(ioctl_buf), NULL);
4116 }
4117 if (ret == BCME_UNSUPPORTED) {
4118 WL_ERR(("interface_create iovar not supported\n"));
4119 return ret;
4120 } else if ((ret == 0) && *((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3) {
4121 WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags));
4122 use_iface_info_v2 = true;
4123 bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
4124 iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
4125 iface_v3.iftype = iftype;
4126 iface_v3.flags = ifflags;
4127 if (addr) {
4128 memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
4129 }
4130 ret = wldev_iovar_getbuf(ndev, "interface_create",
4131 &iface_v3, sizeof(wl_interface_create_v3_t),
4132 ioctl_buf, sizeof(ioctl_buf), NULL);
4133 } else {
4134 /* On any other error, attempt with iovar version 2 */
4135 WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n", ret, ifflags));
4136 iface.ver = WL_INTERFACE_CREATE_VER_2;
4137 iface.iftype = iftype;
4138 iface.flags = ifflags;
4139 if (addr) {
4140 memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
4141 }
4142 ret = wldev_iovar_getbuf(ndev, "interface_create",
4143 &iface, sizeof(struct wl_interface_create_v2),
4144 ioctl_buf, sizeof(ioctl_buf), NULL);
4145 }
4146
4147 if (unlikely(ret)) {
4148 WL_ERR(("Interface create failed!! ret %d\n", ret));
4149 return ret;
4150 }
4151
4152 /* success case */
4153 if (use_iface_info_v2 == true) {
4154 info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
4155 ret = info_v2->bsscfgidx;
4156 } else {
4157 /* Use v1 struct */
4158 info = (struct wl_interface_info_v1 *)ioctl_buf;
4159 ret = info->bsscfgidx;
4160 }
4161
4162 exit:
4163 WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
4164 return ret;
4165 }
4166
4167 s32
wl_cfg80211_add_del_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,wl_iftype_t brcm_iftype,s32 del,u8 * addr)4168 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
4169 struct net_device *ndev, s32 bsscfg_idx,
4170 wl_iftype_t brcm_iftype, s32 del, u8 *addr)
4171 {
4172 s32 ret = BCME_OK;
4173 s32 val = 0;
4174
4175 struct {
4176 s32 cfg;
4177 s32 val;
4178 struct ether_addr ea;
4179 } bss_setbuf;
4180
4181 WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype, del));
4182
4183 bzero(&bss_setbuf, sizeof(bss_setbuf));
4184
4185 /* AP=2, STA=3, up=1, down=0, val=-1 */
4186 if (del) {
4187 val = WLC_AP_IOV_OP_DELETE;
4188 } else if (brcm_iftype == WL_IF_TYPE_AP) {
4189 /* Add/role change to AP Interface */
4190 WL_DBG(("Adding AP Interface \n"));
4191 val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
4192 } else if (brcm_iftype == WL_IF_TYPE_STA) {
4193 /* Add/role change to STA Interface */
4194 WL_DBG(("Adding STA Interface \n"));
4195 val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
4196 } else {
4197 WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype));
4198 return -EINVAL;
4199 }
4200
4201 if (!del) {
4202 wl_ext_bss_iovar_war(ndev, &val);
4203 }
4204
4205 bss_setbuf.cfg = htod32(bsscfg_idx);
4206 bss_setbuf.val = htod32(val);
4207
4208 if (addr) {
4209 memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
4210 }
4211
4212 WL_MSG(ndev->name, "wl bss %d bssidx:%d\n", val, bsscfg_idx);
4213 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4214 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4215 if (ret != 0)
4216 WL_ERR(("'bss %d' failed with %d\n", val, ret));
4217
4218 return ret;
4219 }
4220
4221 s32
wl_cfg80211_bss_up(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,s32 bss_up)4222 wl_cfg80211_bss_up(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 bss_up)
4223 {
4224 s32 ret = BCME_OK;
4225 s32 val = bss_up ? 1 : 0;
4226
4227 struct {
4228 s32 cfg;
4229 s32 val;
4230 } bss_setbuf;
4231
4232 bss_setbuf.cfg = htod32(bsscfg_idx);
4233 bss_setbuf.val = htod32(val);
4234
4235 WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx, bss_up ? "up" : "down"));
4236 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4237 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4238
4239 if (ret != 0) {
4240 WL_ERR(("'bss %d' failed with %d\n", bss_up, ret));
4241 }
4242
4243 return ret;
4244 }
4245
4246 bool
wl_cfg80211_bss_isup(struct net_device * ndev,int bsscfg_idx)4247 wl_cfg80211_bss_isup(struct net_device *ndev, int bsscfg_idx)
4248 {
4249 s32 result, val;
4250 bool isup = false;
4251 s8 getbuf[64];
4252
4253 /* Check if the BSS is up */
4254 *(int*)getbuf = -1;
4255 result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
4256 sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
4257 if (result != 0) {
4258 WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
4259 WL_ERR(("NOTE: this ioctl error is normal "
4260 "when the BSS has not been created yet.\n"));
4261 } else {
4262 val = *(int*)getbuf;
4263 val = dtoh32(val);
4264 WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx, val));
4265 isup = (val ? TRUE : FALSE);
4266 }
4267 return isup;
4268 }
4269
4270 s32
wl_iftype_to_mode(wl_iftype_t iftype)4271 wl_iftype_to_mode(wl_iftype_t iftype)
4272 {
4273 s32 mode = BCME_ERROR;
4274
4275 switch (iftype) {
4276 case WL_IF_TYPE_STA:
4277 case WL_IF_TYPE_P2P_GC:
4278 case WL_IF_TYPE_P2P_DISC:
4279 mode = WL_MODE_BSS;
4280 break;
4281 case WL_IF_TYPE_AP:
4282 case WL_IF_TYPE_P2P_GO:
4283 mode = WL_MODE_AP;
4284 break;
4285 case WL_IF_TYPE_NAN:
4286 mode = WL_MODE_NAN;
4287 break;
4288 case WL_IF_TYPE_AIBSS:
4289 /* Intentional fall through */
4290 case WL_IF_TYPE_IBSS:
4291 mode = WL_MODE_IBSS;
4292 break;
4293 #ifdef WLMESH_CFG80211
4294 case WL_IF_TYPE_MESH:
4295 mode = WL_MODE_MESH;
4296 break;
4297 #endif /* WLMESH_CFG80211 */
4298 default:
4299 WL_ERR(("Unsupported type:%d\n", iftype));
4300 break;
4301 }
4302 return mode;
4303 }
4304
4305 s32
cfg80211_to_wl_iftype(uint16 type,uint16 * role,uint16 * mode)4306 cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode)
4307 {
4308 switch (type) {
4309 case NL80211_IFTYPE_STATION:
4310 *role = WL_IF_TYPE_STA;
4311 *mode = WL_MODE_BSS;
4312 break;
4313 case NL80211_IFTYPE_AP:
4314 *role = WL_IF_TYPE_AP;
4315 *mode = WL_MODE_AP;
4316 break;
4317 #ifdef WL_CFG80211_P2P_DEV_IF
4318 case NL80211_IFTYPE_P2P_DEVICE:
4319 *role = WL_IF_TYPE_P2P_DISC;
4320 *mode = WL_MODE_BSS;
4321 break;
4322 #endif /* WL_CFG80211_P2P_DEV_IF */
4323 case NL80211_IFTYPE_P2P_GO:
4324 *role = WL_IF_TYPE_P2P_GO;
4325 *mode = WL_MODE_AP;
4326 break;
4327 case NL80211_IFTYPE_P2P_CLIENT:
4328 *role = WL_IF_TYPE_P2P_GC;
4329 *mode = WL_MODE_BSS;
4330 break;
4331 case NL80211_IFTYPE_MONITOR:
4332 WL_ERR(("Unsupported mode \n"));
4333 return BCME_UNSUPPORTED;
4334 case NL80211_IFTYPE_ADHOC:
4335 *role = WL_IF_TYPE_IBSS;
4336 *mode = WL_MODE_IBSS;
4337 break;
4338 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
4339 case NL80211_IFTYPE_NAN:
4340 *role = WL_IF_TYPE_NAN;
4341 *mode = WL_MODE_NAN;
4342 break;
4343 #endif // endif
4344 #ifdef WLMESH_CFG80211
4345 case NL80211_IFTYPE_MESH_POINT:
4346 *role = WLC_E_IF_ROLE_AP;
4347 *mode = WL_MODE_MESH;
4348 break;
4349 #endif /* WLMESH_CFG80211 */
4350 default:
4351 WL_ERR(("Unknown interface type:0x%x\n", type));
4352 return BCME_ERROR;
4353 }
4354 return BCME_OK;
4355 }
4356
4357 static s32
wl_role_to_cfg80211_type(uint16 role,uint16 * wl_iftype,uint16 * mode)4358 wl_role_to_cfg80211_type(uint16 role, uint16 *wl_iftype, uint16 *mode)
4359 {
4360 switch (role) {
4361 case WLC_E_IF_ROLE_STA:
4362 *wl_iftype = WL_IF_TYPE_STA;
4363 *mode = WL_MODE_BSS;
4364 return NL80211_IFTYPE_STATION;
4365 case WLC_E_IF_ROLE_AP:
4366 *wl_iftype = WL_IF_TYPE_AP;
4367 *mode = WL_MODE_AP;
4368 return NL80211_IFTYPE_AP;
4369 case WLC_E_IF_ROLE_P2P_GO:
4370 *wl_iftype = WL_IF_TYPE_P2P_GO;
4371 *mode = WL_MODE_AP;
4372 return NL80211_IFTYPE_P2P_GO;
4373 case WLC_E_IF_ROLE_P2P_CLIENT:
4374 *wl_iftype = WL_IF_TYPE_P2P_GC;
4375 *mode = WL_MODE_BSS;
4376 return NL80211_IFTYPE_P2P_CLIENT;
4377 case WLC_E_IF_ROLE_IBSS:
4378 *wl_iftype = WL_IF_TYPE_IBSS;
4379 *mode = WL_MODE_IBSS;
4380 return NL80211_IFTYPE_ADHOC;
4381 case WLC_E_IF_ROLE_NAN:
4382 *wl_iftype = WL_IF_TYPE_NAN;
4383 *mode = WL_MODE_NAN;
4384 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
4385 /* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
4386 * For Vendor HAL based NAN implementation, continue advertising
4387 * as a STA interface
4388 */
4389 return NL80211_IFTYPE_NAN;
4390 #else
4391 return NL80211_IFTYPE_STATION;
4392 #endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
4393 #ifdef WLDWDS
4394 case WLC_E_IF_ROLE_WDS:
4395 *wl_iftype = WL_IF_TYPE_AP;
4396 *mode = WL_MODE_AP;
4397 return NL80211_IFTYPE_AP;
4398 #endif
4399 #ifdef WLMESH_CFG80211
4400 case WLC_E_IF_ROLE_MESH:
4401 *wl_iftype = WL_IF_TYPE_MESH;
4402 *mode = WL_MODE_MESH;
4403 return NL80211_IFTYPE_MESH_POINT;
4404 #endif /* WLMESH_CFG80211 */
4405
4406 default:
4407 WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role));
4408 return BCME_ERROR;
4409 }
4410 }
4411
4412 struct net_device *
wl_cfg80211_post_ifcreate(struct net_device * ndev,wl_if_event_info * event,u8 * addr,const char * name,bool rtnl_lock_reqd)4413 wl_cfg80211_post_ifcreate(struct net_device *ndev,
4414 wl_if_event_info *event, u8 *addr,
4415 const char *name, bool rtnl_lock_reqd)
4416 {
4417 struct bcm_cfg80211 *cfg;
4418 struct net_device *primary_ndev;
4419 struct net_device *new_ndev = NULL;
4420 struct wireless_dev *wdev = NULL;
4421 s32 iface_type;
4422 s32 ret = BCME_OK;
4423 u16 mode;
4424 u8 mac_addr[ETH_ALEN];
4425 u16 wl_iftype;
4426
4427 if (!ndev || !event) {
4428 WL_ERR(("Wrong arg\n"));
4429 return NULL;
4430 }
4431
4432 cfg = wl_get_cfg(ndev);
4433 if (!cfg) {
4434 WL_ERR(("cfg null\n"));
4435 return NULL;
4436 }
4437
4438 WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
4439 event->role, event->ifidx, event->bssidx));
4440 if (!event->ifidx || !event->bssidx) {
4441 /* Fw returned primary idx (0) for virtual interface */
4442 WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
4443 event->ifidx, event->bssidx));
4444 return NULL;
4445 }
4446
4447 #if defined(WLMESH_CFG80211) && defined(WL_EXT_IAPSTA)
4448 if (wl_ext_iapsta_mesh_creating(ndev)) {
4449 event->role = WLC_E_IF_ROLE_MESH;
4450 WL_MSG(ndev->name, "change role to WLC_E_IF_ROLE_MESH\n");
4451 }
4452 #endif /* WLMESH_CFG80211 && WL_EXT_IAPSTA */
4453
4454 iface_type = wl_role_to_cfg80211_type(event->role, &wl_iftype, &mode);
4455 if (iface_type < 0) {
4456 /* Unknown iface type */
4457 WL_ERR(("Wrong iface type \n"));
4458 return NULL;
4459 }
4460
4461 WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG "\n",
4462 addr, name, event->role, iface_type, MAC2STRDBG(event->mac)));
4463 if (!name) {
4464 /* If iface name is not provided, use dongle ifname */
4465 name = event->name;
4466 }
4467
4468 if (!addr) {
4469 /* If mac address is not set, use primary mac with locally administered
4470 * bit set.
4471 */
4472 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4473 memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
4474 /* For customer6 builds, use primary mac address for virtual interface */
4475 mac_addr[0] |= 0x02;
4476 addr = mac_addr;
4477 }
4478
4479 #ifdef WL_STATIC_IF
4480 if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
4481 new_ndev = wl_cfg80211_post_static_ifcreate(cfg, event, addr, iface_type);
4482 if (!new_ndev) {
4483 WL_ERR(("failed to get I/F pointer\n"));
4484 return NULL;
4485 }
4486 wdev = new_ndev->ieee80211_ptr;
4487 } else
4488 #endif /* WL_STATIC_IF */
4489 {
4490 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
4491 name, addr, event->bssidx, event->name);
4492 if (!new_ndev) {
4493 WL_ERR(("I/F allocation failed! \n"));
4494 return NULL;
4495 } else {
4496 WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
4497 event->ifidx, event->bssidx));
4498 }
4499
4500 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
4501 if (!wdev) {
4502 WL_ERR(("wireless_dev alloc failed! \n"));
4503 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4504 return NULL;
4505 }
4506
4507 wdev->wiphy = bcmcfg_to_wiphy(cfg);
4508 wdev->iftype = iface_type;
4509
4510 new_ndev->ieee80211_ptr = wdev;
4511 #ifdef WLDWDS
4512 /* set wds0.x to 4addr interface here */
4513 if (event->role == WLC_E_IF_ROLE_WDS) {
4514 printf("\n\n\n event->role == WLC_E_IF_ROLE_WDS, set vwdev 4addr to %s\n", event->name);
4515 wdev->use_4addr = true;
4516 }
4517 #endif /* WLDWDS */
4518 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4519
4520 memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
4521 #ifdef WL_EXT_IAPSTA
4522 wl_ext_iapsta_ifadding(new_ndev, event->ifidx);
4523 #endif /* WL_EXT_IAPSTA */
4524 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd)
4525 != BCME_OK) {
4526 WL_ERR(("IFACE register failed \n"));
4527 /* Post interface registration, wdev would be freed from the netdev
4528 * destructor path. For other cases, handle it here.
4529 */
4530 MFREE(cfg->osh, wdev, sizeof(*wdev));
4531 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4532 return NULL;
4533 }
4534 }
4535
4536 /* Initialize with the station mode params */
4537 ret = wl_alloc_netinfo(cfg, new_ndev, wdev, wl_iftype,
4538 PM_ENABLE, event->bssidx, event->ifidx);
4539 if (unlikely(ret)) {
4540 WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret));
4541 goto fail;
4542 }
4543
4544 /* Apply the mode & infra setting based on iftype */
4545 if ((ret = wl_config_infra(cfg, new_ndev, wl_iftype)) < 0) {
4546 WL_ERR(("config ifmode failure (%d)\n", ret));
4547 goto fail;
4548 }
4549
4550 if (mode == WL_MODE_AP) {
4551 wl_set_drv_status(cfg, AP_CREATING, new_ndev);
4552 }
4553 #ifdef WL_EXT_IAPSTA
4554 wl_ext_iapsta_update_iftype(new_ndev, event->ifidx, wl_iftype);
4555 #endif
4556
4557 WL_INFORM_MEM(("Network Interface (%s) registered with host."
4558 " cfg_iftype:%d wl_role:%d " MACDBG "\n",
4559 new_ndev->name, iface_type, event->role, MAC2STRDBG(new_ndev->dev_addr)));
4560
4561 #ifdef SUPPORT_SET_CAC
4562 wl_cfg80211_set_cac(cfg, 0);
4563 #endif /* SUPPORT_SET_CAC */
4564
4565 return new_ndev;
4566
4567 fail:
4568 #ifdef WL_STATIC_IF
4569 /* remove static if from iflist */
4570 if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
4571 cfg->static_ndev_state = NDEV_STATE_FW_IF_FAILED;
4572 wl_cfg80211_update_iflist_info(cfg, new_ndev, WL_STATIC_IFIDX, addr,
4573 event->bssidx, event->name, NDEV_STATE_FW_IF_FAILED);
4574 }
4575 #endif /* WL_STATIC_IF */
4576 if (new_ndev) {
4577 /* wdev would be freed from netdev destructor call back */
4578 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4579 }
4580
4581 return NULL;
4582 }
4583
4584 s32
wl_cfg80211_delete_iface(struct bcm_cfg80211 * cfg,wl_iftype_t sec_data_if_type)4585 wl_cfg80211_delete_iface(struct bcm_cfg80211 *cfg,
4586 wl_iftype_t sec_data_if_type)
4587 {
4588 struct net_info *iter, *next;
4589 struct net_device *primary_ndev;
4590 s32 ret = BCME_OK;
4591 uint8 i = 0;
4592
4593 BCM_REFERENCE(i);
4594 BCM_REFERENCE(ret);
4595
4596 /* Note: This function will clean up only the network interface and host
4597 * data structures. The firmware interface clean up will happen in the
4598 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4599 * context for the module case).
4600 */
4601 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4602 WL_DBG(("Enter, deleting iftype %s\n",
4603 wl_iftype_to_str(sec_data_if_type)));
4604 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4605 for_each_ndev(cfg, iter, next) {
4606 GCC_DIAGNOSTIC_POP();
4607 if (iter->ndev && (iter->ndev != primary_ndev)) {
4608 if (iter->iftype != sec_data_if_type) {
4609 continue;
4610 }
4611 switch (sec_data_if_type) {
4612 case WL_IF_TYPE_P2P_GO:
4613 case WL_IF_TYPE_P2P_GC: {
4614 ret = _wl_cfg80211_del_if(cfg,
4615 iter->ndev, NULL, iter->ndev->name);
4616 break;
4617 }
4618 #ifdef WL_NAN
4619 case WL_IF_TYPE_NAN: {
4620 if (cfg->nan_enable == false) {
4621 WL_INFORM_MEM(("Nan is not active,"
4622 " ignore NDI delete\n"));
4623 } else {
4624 ret = wl_cfgnan_delete_ndp(cfg, iter->ndev);
4625 }
4626 break;
4627 }
4628 #endif /* WL_NAN */
4629 case WL_IF_TYPE_AP: {
4630 /* Cleanup AP */
4631 #ifdef WL_STATIC_IF
4632 /* handle static ap */
4633 if (IS_CFG80211_STATIC_IF(cfg, iter->ndev)) {
4634 dev_close(iter->ndev);
4635 } else
4636 #endif /* WL_STATIC_IF */
4637 {
4638 /* handle virtual created AP */
4639 ret = _wl_cfg80211_del_if(cfg, iter->ndev,
4640 NULL, iter->ndev->name);
4641 }
4642 break;
4643 }
4644 default: {
4645 WL_ERR(("Unsupported interface type\n"));
4646 ret = -ENOTSUPP;
4647 goto fail;
4648 }
4649 }
4650 }
4651 }
4652 fail:
4653 return ret;
4654 }
4655
4656 void
wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 * cfg,bool rtnl_lock_reqd)4657 wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 *cfg, bool rtnl_lock_reqd)
4658 {
4659 struct net_info *iter, *next;
4660 struct net_device *primary_ndev;
4661
4662 /* Note: This function will clean up only the network interface and host
4663 * data structures. The firmware interface clean up will happen in the
4664 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4665 * context for the module case).
4666 */
4667 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4668 WL_DBG(("Enter\n"));
4669 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4670 for_each_ndev(cfg, iter, next) {
4671 GCC_DIAGNOSTIC_POP();
4672 if (iter->ndev && (iter->ndev != primary_ndev)) {
4673 /* Ensure interfaces are down before deleting */
4674 #ifdef WL_STATIC_IF
4675 /* Avoiding cleaning static ifaces */
4676 if (!IS_CFG80211_STATIC_IF(cfg, iter->ndev))
4677 #endif /* WL_STATIC_IF */
4678 {
4679 dev_close(iter->ndev);
4680 WL_DBG(("Cleaning up iface:%s \n", iter->ndev->name));
4681 wl_cfg80211_post_ifdel(iter->ndev, rtnl_lock_reqd, 0);
4682 }
4683 }
4684 }
4685 }
4686
4687 s32
wl_cfg80211_post_ifdel(struct net_device * ndev,bool rtnl_lock_reqd,s32 ifidx)4688 wl_cfg80211_post_ifdel(struct net_device *ndev, bool rtnl_lock_reqd, s32 ifidx)
4689 {
4690 s32 ret = BCME_OK;
4691 struct bcm_cfg80211 *cfg;
4692 struct net_info *netinfo = NULL;
4693
4694 if (!ndev || !ndev->ieee80211_ptr) {
4695 /* No wireless dev done for this interface */
4696 ret = -EINVAL;
4697 goto exit;
4698 }
4699
4700 cfg = wl_get_cfg(ndev);
4701 if (!cfg) {
4702 WL_ERR(("cfg null\n"));
4703 ret = BCME_ERROR;
4704 goto exit;
4705 }
4706
4707 if (ifidx <= 0) {
4708 WL_ERR(("Invalid IF idx for iface:%s\n", ndev->name));
4709 ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
4710 BCM_REFERENCE(ifidx);
4711 if (ifidx <= 0) {
4712 ASSERT(0);
4713 ret = BCME_ERROR;
4714 goto exit;
4715 }
4716 }
4717
4718 if ((netinfo = wl_get_netinfo_by_wdev(cfg, ndev_to_wdev(ndev))) == NULL) {
4719 WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev)));
4720 ret = -ENODEV;
4721 goto exit;
4722 }
4723
4724 #ifdef WL_STATIC_IF
4725 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
4726 ret = wl_cfg80211_post_static_ifdel(cfg, ndev);
4727 } else
4728 #endif /* WL_STATIC_IF */
4729 {
4730 WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
4731 ndev->name, ifidx, cfg->vif_count));
4732 wl_cfg80211_remove_if(cfg, ifidx, ndev, rtnl_lock_reqd);
4733 cfg->bss_pending_op = FALSE;
4734 }
4735
4736 #ifdef SUPPORT_SET_CAC
4737 wl_cfg80211_set_cac(cfg, 1);
4738 #endif /* SUPPORT_SET_CAC */
4739 exit:
4740 return ret;
4741 }
4742
4743 int
wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 * cfg)4744 wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 *cfg)
4745 {
4746 s32 ret = BCME_OK;
4747 bcm_struct_cfgdev *cfgdev;
4748
4749 if (cfg->p2p) {
4750 /* De-initialize the p2p discovery interface, if operational */
4751 WL_ERR(("Disabling P2P Discovery Interface \n"));
4752 #ifdef WL_CFG80211_P2P_DEV_IF
4753 cfgdev = bcmcfg_to_p2p_wdev(cfg);
4754 #else
4755 cfgdev = cfg->p2p_net;
4756 #endif // endif
4757 if (cfgdev) {
4758 ret = wl_cfg80211_scan_stop(cfg, cfgdev);
4759 if (unlikely(ret < 0)) {
4760 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
4761 }
4762 }
4763
4764 wl_cfgp2p_disable_discovery(cfg);
4765 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
4766 p2p_on(cfg) = false;
4767 }
4768 return ret;
4769 }
4770
4771 /* Create a Generic Network Interface and initialize it depending up on
4772 * the interface type
4773 */
4774 struct wireless_dev *
wl_cfg80211_create_iface(struct wiphy * wiphy,wl_iftype_t wl_iftype,u8 * mac_addr,const char * name)4775 wl_cfg80211_create_iface(struct wiphy *wiphy,
4776 wl_iftype_t wl_iftype,
4777 u8 *mac_addr, const char *name)
4778 {
4779 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4780 struct net_device *new_ndev = NULL;
4781 struct net_device *primary_ndev = NULL;
4782 s32 ret = BCME_OK;
4783 s32 bsscfg_idx = 0;
4784 long timeout;
4785 wl_if_event_info *event = NULL;
4786 u8 addr[ETH_ALEN];
4787 struct net_info *iter, *next;
4788
4789 WL_DBG(("Enter\n"));
4790 if (!name) {
4791 WL_ERR(("Interface name not provided\n"));
4792 return NULL;
4793 }
4794 else {
4795 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4796 for_each_ndev(cfg, iter, next) {
4797 GCC_DIAGNOSTIC_POP();
4798 if (iter->ndev) {
4799 if (strncmp(iter->ndev->name, name, strlen(name)) == 0) {
4800 WL_ERR(("Interface name,%s exists!\n", iter->ndev->name));
4801 return NULL;
4802 }
4803 }
4804 }
4805 }
4806 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4807 if (likely(!mac_addr)) {
4808 /* Use primary MAC with the locally administered bit for the
4809 * Secondary STA I/F
4810 */
4811 memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
4812 addr[0] |= 0x02;
4813 } else {
4814 /* Use the application provided mac address (if any) */
4815 memcpy(addr, mac_addr, ETH_ALEN);
4816 }
4817
4818 cfg->bss_pending_op = TRUE;
4819 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
4820
4821 /*
4822 * Intialize the firmware I/F.
4823 */
4824 {
4825 ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
4826 wl_iftype, 0, addr);
4827 }
4828 if (ret == BCME_UNSUPPORTED) {
4829 /* Use bssidx 1 by default */
4830 bsscfg_idx = 1;
4831 if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
4832 bsscfg_idx, wl_iftype, 0, addr)) < 0) {
4833 goto exit;
4834 }
4835 } else if (ret < 0) {
4836 WL_ERR(("Interface create failed!! ret:%d \n", ret));
4837 goto exit;
4838 } else {
4839 /* Success */
4840 bsscfg_idx = ret;
4841 }
4842
4843 WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
4844 /*
4845 * Wait till the firmware send a confirmation event back.
4846 */
4847 WL_DBG(("Wait for the FW I/F Event\n"));
4848 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4849 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4850 if (timeout <= 0 || cfg->bss_pending_op) {
4851 WL_ERR(("ADD_IF event, didn't come. Return. timeout:%lu bss_pending_op:%d\n",
4852 timeout, cfg->bss_pending_op));
4853 if (timeout == -ERESTARTSYS) {
4854 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
4855 }
4856 goto exit;
4857 }
4858
4859 event = &cfg->if_event_info;
4860 /*
4861 * Since FW operation is successful,we can go ahead with the
4862 * the host interface creation.
4863 */
4864 new_ndev = wl_cfg80211_post_ifcreate(primary_ndev,
4865 event, addr, name, false);
4866
4867 if (new_ndev) {
4868 /* Iface post ops successful. Return ndev/wdev ptr */
4869 return new_ndev->ieee80211_ptr;
4870 }
4871
4872 exit:
4873 cfg->bss_pending_op = FALSE;
4874 return NULL;
4875 }
4876
4877 s32
wl_cfg80211_del_iface(struct wiphy * wiphy,struct wireless_dev * wdev)4878 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
4879 {
4880 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4881 struct net_device *ndev = NULL;
4882 s32 ret = BCME_OK;
4883 s32 bsscfg_idx = 1;
4884 long timeout;
4885 u16 wl_iftype;
4886 u16 wl_mode;
4887
4888 WL_DBG(("Enter\n"));
4889
4890 /* If any scan is going on, abort it */
4891 if (wl_get_drv_status_all(cfg, SCANNING)) {
4892 WL_DBG(("Scan in progress. Aborting the scan!\n"));
4893 wl_cfg80211_cancel_scan(cfg);
4894 }
4895
4896 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, wdev);
4897 if (bsscfg_idx <= 0) {
4898 /* validate bsscfgidx */
4899 WL_ERR(("Wrong bssidx! \n"));
4900 return -EINVAL;
4901 }
4902
4903 /* Handle p2p iface */
4904 if ((ret = wl_cfg80211_p2p_if_del(wiphy, wdev)) != BCME_NOTFOUND) {
4905 WL_DBG(("P2P iface del handled \n"));
4906 #ifdef SUPPORT_SET_CAC
4907 wl_cfg80211_set_cac(cfg, 1);
4908 #endif /* SUPPORT_SET_CAC */
4909 return ret;
4910 }
4911
4912 ndev = wdev->netdev;
4913 if (unlikely(!ndev)) {
4914 WL_ERR(("ndev null! \n"));
4915 return -EINVAL;
4916 }
4917
4918 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4919
4920 if (cfg80211_to_wl_iftype(ndev->ieee80211_ptr->iftype,
4921 &wl_iftype, &wl_mode) < 0) {
4922 return -EINVAL;
4923 }
4924
4925 WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d",
4926 bsscfg_idx, ndev->ieee80211_ptr->iftype, wl_iftype));
4927 /* Delete the firmware interface. "interface_remove" command
4928 * should go on the interface to be deleted
4929 */
4930 if (wl_cfg80211_get_bus_state(cfg)) {
4931 WL_ERR(("Bus state is down: %d\n", __LINE__));
4932 ret = BCME_DONGLE_DOWN;
4933 goto exit;
4934 }
4935
4936 cfg->bss_pending_op = true;
4937 ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx,
4938 wl_iftype, 1, NULL);
4939 if (ret == BCME_UNSUPPORTED) {
4940 if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
4941 bsscfg_idx, wl_iftype, true, NULL)) < 0) {
4942 WL_ERR(("DEL bss failed ret:%d \n", ret));
4943 goto exit;
4944 }
4945 } else if ((ret == BCME_NOTAP) || (ret == BCME_NOTSTA)) {
4946 /* De-init sequence involving role downgrade not happened.
4947 * Do nothing and return error. The del command should be
4948 * retried.
4949 */
4950 WL_ERR(("ifdel role mismatch:%d\n", ret));
4951 ret = -EBADTYPE;
4952 goto exit;
4953 } else if (ret < 0) {
4954 WL_ERR(("Interface DEL failed ret:%d \n", ret));
4955 goto exit;
4956 }
4957
4958 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4959 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4960 if (timeout <= 0 || cfg->bss_pending_op) {
4961 WL_ERR(("timeout in waiting IF_DEL event\n"));
4962 /* The interface unregister will happen from wifi reset context */
4963 ret = -ETIMEDOUT;
4964 /* fall through */
4965 }
4966
4967 exit:
4968 if (ret < 0) {
4969 WL_ERR(("iface del failed:%d\n", ret));
4970 #ifdef WL_STATIC_IF
4971 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
4972 /*
4973 * For static interface, clean up the host data,
4974 * irrespective of fw status. For dynamic
4975 * interfaces it gets cleaned from dhd_stop context
4976 */
4977 wl_cfg80211_post_static_ifdel(cfg, ndev);
4978 }
4979 #endif /* WL_STATIC_IF */
4980 } else {
4981 ret = wl_cfg80211_post_ifdel(ndev, false, cfg->if_event_info.ifidx);
4982 if (unlikely(ret)) {
4983 WL_ERR(("post_ifdel failed\n"));
4984 }
4985 }
4986
4987 cfg->bss_pending_op = false;
4988 return ret;
4989 }
4990
4991 static s32
wl_cfg80211_join_ibss(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ibss_params * params)4992 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
4993 struct cfg80211_ibss_params *params)
4994 {
4995 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4996 struct cfg80211_bss *bss;
4997 struct ieee80211_channel *chan;
4998 struct wl_join_params join_params;
4999 int scan_suppress;
5000 struct cfg80211_ssid ssid;
5001 s32 scan_retry = 0;
5002 s32 err = 0;
5003 size_t join_params_size;
5004 chanspec_t chanspec = 0;
5005 u32 param[2] = {0, 0};
5006 u32 bw_cap = 0;
5007
5008 WL_TRACE(("In\n"));
5009 RETURN_EIO_IF_NOT_UP(cfg);
5010 WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
5011 if (!params->ssid || params->ssid_len <= 0 ||
5012 params->ssid_len > DOT11_MAX_SSID_LEN) {
5013 WL_ERR(("Invalid parameter\n"));
5014 return -EINVAL;
5015 }
5016 #if defined(WL_CFG80211_P2P_DEV_IF)
5017 chan = params->chandef.chan;
5018 #else
5019 chan = params->channel;
5020 #endif /* WL_CFG80211_P2P_DEV_IF */
5021 if (chan)
5022 cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
5023 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
5024 struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
5025 u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
5026 u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
5027 if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
5028 (memcmp(params->ssid, lssid->SSID, lssid->SSID_len) == 0) &&
5029 (*channel == cfg->channel))) {
5030 WL_ERR(("Connection already existed to " MACDBG "\n",
5031 MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
5032 return -EISCONN;
5033 }
5034 WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n",
5035 lssid->SSID, MAC2STRDBG(bssid)));
5036 }
5037
5038 /* remove the VSIE */
5039 wl_cfg80211_ibss_vsie_delete(dev);
5040
5041 bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
5042 if (!bss) {
5043 if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
5044 memcpy(ssid.ssid, params->ssid, params->ssid_len);
5045 ssid.ssid_len = params->ssid_len;
5046 do {
5047 if (unlikely
5048 (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
5049 -EBUSY)) {
5050 wl_delay(150);
5051 } else {
5052 break;
5053 }
5054 } while (++scan_retry < WL_SCAN_RETRY_MAX);
5055
5056 /* rtnl lock code is removed here. don't see why rtnl lock
5057 * needs to be released.
5058 */
5059
5060 /* wait 4 secons till scan done.... */
5061 schedule_timeout_interruptible(msecs_to_jiffies(4000));
5062
5063 bss = cfg80211_get_ibss(wiphy, NULL,
5064 params->ssid, params->ssid_len);
5065 }
5066 }
5067 if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
5068 ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
5069 !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
5070 cfg->ibss_starter = false;
5071 WL_DBG(("Found IBSS\n"));
5072 } else {
5073 cfg->ibss_starter = true;
5074 }
5075
5076 if (bss) {
5077 CFG80211_PUT_BSS(wiphy, bss);
5078 }
5079
5080 if (chan) {
5081 if (chan->band == IEEE80211_BAND_5GHZ)
5082 param[0] = WLC_BAND_5G;
5083 else if (chan->band == IEEE80211_BAND_2GHZ)
5084 param[0] = WLC_BAND_2G;
5085 err = wldev_iovar_getint(dev, "bw_cap", param);
5086 if (unlikely(err)) {
5087 WL_ERR(("Get bw_cap Failed (%d)\n", err));
5088 return err;
5089 }
5090 bw_cap = param[0];
5091 chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap);
5092 }
5093 /*
5094 * Join with specific BSSID and cached SSID
5095 * If SSID is zero join based on BSSID only
5096 */
5097 bzero(&join_params, sizeof(join_params));
5098 memcpy((void *)join_params.ssid.SSID, (const void *)params->ssid,
5099 params->ssid_len);
5100 join_params.ssid.SSID_len = htod32(params->ssid_len);
5101 if (params->bssid) {
5102 memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
5103 err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
5104 ETHER_ADDR_LEN);
5105 if (unlikely(err)) {
5106 WL_ERR(("Error (%d)\n", err));
5107 return err;
5108 }
5109 } else
5110 bzero(&join_params.params.bssid, ETHER_ADDR_LEN);
5111
5112 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5113 scan_suppress = TRUE;
5114 /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
5115 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5116 &scan_suppress, sizeof(int));
5117 if (unlikely(err)) {
5118 WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
5119 return err;
5120 }
5121 }
5122
5123 join_params.params.chanspec_list[0] = chanspec;
5124 join_params.params.chanspec_num = 1;
5125 wldev_iovar_setint(dev, "chanspec", chanspec);
5126 join_params_size = sizeof(join_params);
5127
5128 /* Disable Authentication, IBSS will add key if it required */
5129 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
5130 wldev_iovar_setint(dev, "wsec", 0);
5131
5132 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
5133 join_params_size);
5134 if (unlikely(err)) {
5135 WL_ERR(("IBSS set_ssid Error (%d)\n", err));
5136 return err;
5137 }
5138
5139 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5140 scan_suppress = FALSE;
5141 /* Reset the SCAN SUPPRESS Flag */
5142 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5143 &scan_suppress, sizeof(int));
5144 if (unlikely(err)) {
5145 WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
5146 return err;
5147 }
5148 }
5149 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
5150 wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
5151 #ifdef WL_RELMCAST
5152 cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
5153 #endif /* WL_RELMCAST */
5154 return err;
5155 }
5156
wl_cfg80211_leave_ibss(struct wiphy * wiphy,struct net_device * dev)5157 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
5158 {
5159 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5160 s32 err = 0;
5161 scb_val_t scbval;
5162 u8 *curbssid;
5163
5164 RETURN_EIO_IF_NOT_UP(cfg);
5165 wl_link_down(cfg);
5166
5167 WL_INFORM_MEM(("Leave IBSS\n"));
5168 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
5169 wl_set_drv_status(cfg, DISCONNECTING, dev);
5170 scbval.val = 0;
5171 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
5172 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
5173 sizeof(scb_val_t));
5174 if (unlikely(err)) {
5175 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5176 WL_ERR(("error(%d)\n", err));
5177 return err;
5178 }
5179
5180 /* remove the VSIE */
5181 wl_cfg80211_ibss_vsie_delete(dev);
5182
5183 return err;
5184 }
5185
5186 #ifdef MFP
5187 static
wl_cfg80211_get_rsn_capa(const bcm_tlv_t * wpa2ie,const u8 ** rsn_cap)5188 int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie,
5189 const u8** rsn_cap)
5190 {
5191 u16 suite_count;
5192 const wpa_suite_mcast_t *mcast;
5193 const wpa_suite_ucast_t *ucast;
5194 int len;
5195 const wpa_suite_auth_key_mgmt_t *mgmt;
5196
5197 if (!wpa2ie)
5198 return BCME_BADARG;
5199
5200 len = wpa2ie->len;
5201
5202 /* check for Multicast cipher suite */
5203 if ((len -= (WPA_SUITE_LEN + WPA2_VERSION_LEN)) <= 0) {
5204 return BCME_NOTFOUND;
5205 }
5206
5207 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
5208
5209 /* Check for the unicast suite(s) */
5210 if (len < WPA_IE_SUITE_COUNT_LEN) {
5211 return BCME_NOTFOUND;
5212 }
5213
5214 ucast = (const wpa_suite_ucast_t *)&mcast[1];
5215 suite_count = ltoh16_ua(&ucast->count);
5216 if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
5217 (len -= (WPA_IE_SUITE_COUNT_LEN +
5218 (WPA_SUITE_LEN * suite_count))) <= 0)
5219 return BCME_BADLEN;
5220
5221 /* Check for AUTH key management suite(s) */
5222 if (len < WPA_IE_SUITE_COUNT_LEN) {
5223 return BCME_NOTFOUND;
5224 }
5225
5226 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
5227 suite_count = ltoh16_ua(&mgmt->count);
5228
5229 if ((suite_count <= NL80211_MAX_NR_CIPHER_SUITES) &&
5230 (len -= (WPA_IE_SUITE_COUNT_LEN +
5231 (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
5232 rsn_cap[0] = (const u8 *)&mgmt->list[suite_count];
5233 } else {
5234 return BCME_BADLEN;
5235 }
5236
5237 return BCME_OK;
5238 }
5239 #endif /* MFP */
5240
5241 static s32
wl_set_wpa_version(struct net_device * dev,struct cfg80211_connect_params * sme)5242 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
5243 {
5244 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5245 struct wl_security *sec;
5246 s32 val = 0;
5247 s32 err = 0;
5248 s32 bssidx;
5249
5250 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5251 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5252 return BCME_ERROR;
5253 }
5254
5255 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
5256 val = WPA_AUTH_PSK |
5257 WPA_AUTH_UNSPECIFIED;
5258 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
5259 val = WPA2_AUTH_PSK|
5260 WPA2_AUTH_UNSPECIFIED;
5261 else
5262 val = WPA_AUTH_DISABLED;
5263
5264 if (is_wps_conn(sme))
5265 val = WPA_AUTH_DISABLED;
5266
5267 #ifdef BCMWAPI_WPI
5268 if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) {
5269 WL_DBG((" * wl_set_wpa_version, set wpa_auth"
5270 " to WPA_AUTH_WAPI 0x400"));
5271 val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5272 }
5273 #endif // endif
5274 WL_INFORM_MEM(("[%s] wl wpa_auth 0x%0x\n", dev->name, val));
5275 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
5276 if (unlikely(err)) {
5277 WL_ERR(("set wpa_auth failed (%d)\n", err));
5278 return err;
5279 }
5280 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5281 sec->wpa_versions = sme->crypto.wpa_versions;
5282 return err;
5283 }
5284
5285 #ifdef BCMWAPI_WPI
5286 static s32
wl_set_set_wapi_ie(struct net_device * dev,struct cfg80211_connect_params * sme)5287 wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme)
5288 {
5289 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5290 s32 err = 0;
5291 s32 bssidx;
5292
5293 WL_DBG((" wl_set_set_wapi_ie\n"));
5294 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5295 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5296 return BCME_ERROR;
5297 }
5298
5299 err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", (const void *)sme->ie, sme->ie_len,
5300 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5301 if (unlikely(err)) {
5302 WL_ERR(("set_wapi_ie Error (%d)\n", err));
5303 return err;
5304 }
5305 WL_INFORM_MEM(("wapi_ie successfully (%s)\n", dev->name));
5306 return err;
5307 }
5308 #endif /* BCMWAPI_WPI */
5309
5310 static s32
wl_set_auth_type(struct net_device * dev,struct cfg80211_connect_params * sme)5311 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
5312 {
5313 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5314 struct wl_security *sec;
5315 s32 val = 0;
5316 s32 err = 0;
5317 s32 bssidx;
5318
5319 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5320 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5321 return BCME_ERROR;
5322 }
5323
5324 switch (sme->auth_type) {
5325 case NL80211_AUTHTYPE_OPEN_SYSTEM:
5326 val = WL_AUTH_OPEN_SYSTEM;
5327 WL_DBG(("open system\n"));
5328 break;
5329 case NL80211_AUTHTYPE_SHARED_KEY:
5330 val = WL_AUTH_SHARED_KEY;
5331 WL_DBG(("shared key\n"));
5332 break;
5333 case NL80211_AUTHTYPE_AUTOMATIC:
5334 val = WL_AUTH_OPEN_SHARED;
5335 WL_DBG(("automatic\n"));
5336 break;
5337 #ifdef WL_FILS
5338 case NL80211_AUTHTYPE_FILS_SK:
5339 WL_DBG(("fils shared key\n"));
5340 val = WL_AUTH_FILS_SHARED;
5341 break;
5342 case NL80211_AUTHTYPE_FILS_SK_PFS:
5343 val = WL_AUTH_FILS_SHARED_PFS;
5344 WL_DBG(("fils shared key with pfs\n"));
5345 break;
5346 case NL80211_AUTHTYPE_FILS_PK:
5347 WL_DBG(("fils public key\n"));
5348 val = WL_AUTH_FILS_PUBLIC;
5349 break;
5350 #endif /* WL_FILS */
5351 #ifdef WL_CLIENT_SAE
5352 case NL80211_AUTHTYPE_SAE:
5353 if (!wl_is_pmkid_available(dev, sme->bssid)) {
5354 val = WL_AUTH_SAE_KEY;
5355 } else {
5356 /* Fw will choose right auth type
5357 * dynamically based on PMKID availability
5358 */
5359 val = WL_AUTH_OPEN_SHARED;
5360 }
5361 WL_DBG(("sae auth type %d\n", val));
5362 break;
5363 #endif /* WL_CLIENT_SAE */
5364 default:
5365 val = 2;
5366 WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
5367 break;
5368 }
5369
5370 WL_INFORM_MEM(("[%s] wl auth 0x%0x \n", dev->name, val));
5371 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
5372 if (unlikely(err)) {
5373 WL_ERR(("set auth failed (%d)\n", err));
5374 return err;
5375 }
5376 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5377 sec->auth_type = sme->auth_type;
5378 return err;
5379 }
5380
5381 #ifdef WL_CLIENT_SAE
5382 static bool
wl_is_pmkid_available(struct net_device * dev,const u8 * bssid)5383 wl_is_pmkid_available(struct net_device *dev, const u8 *bssid)
5384 {
5385 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5386 int i;
5387 int npmkids = (cfg->pmk_list->pmkids.length - sizeof(uint16)*2) / sizeof(pmkid_v2_t);
5388
5389 /* check the bssid is null or not */
5390 if (!bssid) return FALSE;
5391
5392 for (i = 0; i < npmkids; i++) {
5393 if (!memcmp(bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid, ETHER_ADDR_LEN)) {
5394 WL_DBG(("FOUND PMKID\n"));
5395 return TRUE;
5396 }
5397 }
5398 WL_ERR(("PMKID NOT FOUND\n"));
5399 return FALSE;
5400 }
5401 #endif /* WL_CLIENT_SAE */
5402
5403 static u32
wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)5404 wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)
5405 {
5406 uint i;
5407
5408 for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5409 if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5410 return rsn_cipher_algo_lookup_tbl[i].wsec_algo;
5411 }
5412 }
5413 return WSEC_NONE;
5414 }
5415
5416 static u32
wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)5417 wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)
5418 {
5419 uint i;
5420
5421 for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5422 if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5423 return rsn_cipher_algo_lookup_tbl[i].wsec_key_algo;
5424 }
5425 }
5426 return CRYPTO_ALGO_OFF;
5427 }
5428
5429 static u32
wl_rsn_akm_wpa_auth_lookup(uint32 akm)5430 wl_rsn_akm_wpa_auth_lookup(uint32 akm)
5431 {
5432 uint i;
5433
5434 for (i = 0; i < ARRAYSIZE(rsn_akm_wpa_auth_lookup_tbl); i++) {
5435 if (akm == rsn_akm_wpa_auth_lookup_tbl[i].akm_suite) {
5436 return rsn_akm_wpa_auth_lookup_tbl[i].wpa_auth;
5437 }
5438 }
5439 return WPA_AUTH_DISABLED;
5440 }
5441
5442 static s32
wl_set_set_cipher(struct net_device * dev,struct cfg80211_connect_params * sme)5443 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
5444 {
5445 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5446 struct wl_security *sec;
5447 s32 pval = 0;
5448 s32 gval = 0;
5449 s32 err = 0;
5450 s32 wsec_val = 0;
5451 #ifdef BCMWAPI_WPI
5452 s32 wapi_val = 0;
5453 s32 val = 0;
5454 #endif // endif
5455 s32 bssidx;
5456 #ifdef WL_GCMP
5457 uint32 algos = 0, mask = 0;
5458 #endif /* WL_GCMP */
5459
5460 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5461 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5462 return BCME_ERROR;
5463 }
5464
5465 if (sme->crypto.n_ciphers_pairwise) {
5466 pval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.ciphers_pairwise[0]);
5467 if (pval == WSEC_NONE) {
5468 WL_ERR(("invalid cipher pairwise (%d)\n", sme->crypto.ciphers_pairwise[0]));
5469 return BCME_BADARG;
5470 }
5471 switch (sme->crypto.ciphers_pairwise[0]) {
5472 #ifdef BCMWAPI_WPI
5473 case WLAN_CIPHER_SUITE_SMS4:
5474 val = pval;
5475 err = wl_set_set_wapi_ie(dev, sme);
5476 if (unlikely(err)) {
5477 WL_DBG(("Set wapi ie failed \n"));
5478 return err;
5479 } else {
5480 WL_DBG(("Set wapi ie succeded\n"));
5481 }
5482 wapi_val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5483 WL_INFORM_MEM(("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val, dev->name));
5484 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wapi_val, bssidx);
5485 if (unlikely(err)) {
5486 WL_ERR(("set wpa_auth failed (%d)\n", err));
5487 return err;
5488 }
5489 break;
5490 #endif /* BCMWAPI_WPI */
5491 #ifdef WL_GCMP
5492 case WLAN_CIPHER_SUITE_GCMP:
5493 case WLAN_CIPHER_SUITE_GCMP_256:
5494 algos = KEY_ALGO_MASK(wl_rsn_cipher_wsec_key_algo_lookup(
5495 sme->crypto.ciphers_pairwise[0]));
5496 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
5497 break;
5498 #endif /* WL_GCMP */
5499 default: /* No post processing required */
5500 break;
5501 }
5502 }
5503 #if defined(BCMSUP_4WAY_HANDSHAKE)
5504 /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
5505 * handshake.
5506 * Note that the FW feature flag only exists on kernels that support the
5507 * FT-EAP AKM suite.
5508 */
5509 if (cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) {
5510 err = wldev_iovar_setint_bsscfg(dev, "sup_wpa", 1, bssidx);
5511 if (err) {
5512 WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err));
5513 return err;
5514 } else {
5515 WL_INFORM_MEM(("idsup enabled.\n"));
5516 }
5517 }
5518 #endif /* BCMSUP_4WAY_HANDSHAKE */
5519 if (sme->crypto.cipher_group) {
5520 gval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.cipher_group);
5521 if (gval == WSEC_NONE) {
5522 WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group));
5523 return BCME_BADARG;
5524 }
5525 switch (sme->crypto.cipher_group) {
5526 #ifdef BCMWAPI_WPI
5527 case WLAN_CIPHER_SUITE_SMS4:
5528 val = gval;
5529 break;
5530 #endif // endif
5531 #ifdef WL_GCMP
5532 case WLAN_CIPHER_SUITE_GCMP:
5533 case WLAN_CIPHER_SUITE_GCMP_256:
5534 algos = KEY_ALGO_MASK(
5535 wl_rsn_cipher_wsec_key_algo_lookup(sme->crypto.cipher_group));
5536 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
5537 break;
5538 #endif /* WL_GCMP */
5539 default: /* No post processing required */
5540 break;
5541 }
5542 }
5543
5544 WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
5545 #ifdef WL_GCMP
5546 WL_DBG(("algos:%x, mask:%x", algos, mask));
5547 #endif /* WL_GCMP */
5548
5549 if (is_wps_conn(sme)) {
5550 if (sme->privacy) {
5551 wsec_val = 4;
5552 } else {
5553 /* WPS-2.0 allows no security */
5554 wsec_val = 0;
5555 }
5556 } else {
5557 #ifdef BCMWAPI_WPI
5558 if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) {
5559 WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
5560 wsec_val = val;
5561 } else
5562 #endif // endif
5563 {
5564 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
5565 wsec_val = pval | gval;
5566 }
5567 }
5568
5569 WL_INFORM_MEM(("[%s] wl wsec 0x%x\n", dev->name, wsec_val));
5570 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec_val, bssidx);
5571 if (unlikely(err)) {
5572 WL_ERR(("error (%d)\n", err));
5573 return err;
5574 }
5575 #ifdef WL_GCMP
5576 wl_set_wsec_info_algos(dev, algos, mask);
5577 #endif /* WL_GCMP */
5578 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5579 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
5580 sec->cipher_group = sme->crypto.cipher_group;
5581 return err;
5582 }
5583 #ifdef WL_GCMP
5584 static s32
wl_set_wsec_info_algos(struct net_device * dev,uint32 algos,uint32 mask)5585 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask)
5586 {
5587 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5588 s32 bssidx;
5589 s32 err = 0;
5590 wl_wsec_info_t *wsec_info;
5591 bcm_xtlv_t *wsec_info_tlv;
5592 uint16 tlv_data_len;
5593 uint8 tlv_data[8];
5594 uint32 param_len;
5595 uint8 * buf;
5596
5597 WL_DBG(("enter.\n"));
5598 if (!cfg) {
5599 return BCME_ERROR;
5600 }
5601 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5602 WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
5603 return BCME_ERROR;
5604 }
5605
5606 buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5607 if (!buf) {
5608 WL_ERR(("No memory"));
5609 return BCME_NOMEM;
5610 }
5611 wsec_info = (wl_wsec_info_t *)buf;
5612 wsec_info->version = WL_WSEC_INFO_VERSION;
5613 wsec_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
5614
5615 wsec_info->num_tlvs++;
5616 tlv_data_len = sizeof(tlv_data);
5617 err = memcpy_s(tlv_data, sizeof(tlv_data), &algos, sizeof(algos));
5618 if (err) {
5619 WL_ERR(("memcpy_s algos error (%d)\n", err));
5620 goto exit;
5621 }
5622 err = memcpy_s(tlv_data + sizeof(algos), sizeof(mask), &mask, sizeof(mask));
5623 if (err) {
5624 WL_ERR(("memcpy_s mask error (%d)\n", err));
5625 goto exit;
5626 }
5627 bcm_xtlv_pack_xtlv(wsec_info_tlv, WL_WSEC_INFO_BSS_ALGOS, tlv_data_len, tlv_data, 0);
5628 param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN + tlv_data_len;
5629
5630 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
5631 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5632 if (unlikely(err) && (err != BCME_UNSUPPORTED))
5633 WL_ERR(("wsec_info error (%d)\n", err));
5634 exit:
5635 MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5636 return err;
5637 }
5638 #endif /* WL_GCMP */
5639 #ifdef MFP
5640 static s32
wl_cfg80211_set_mfp(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme)5641 wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
5642 struct net_device *dev,
5643 struct cfg80211_connect_params *sme)
5644 {
5645 s32 mfp = WL_MFP_NONE;
5646 s32 current_mfp = WL_MFP_NONE;
5647 const bcm_tlv_t *wpa2_ie;
5648 const u8* rsn_cap = NULL;
5649 bool fw_support = false;
5650 int err, count = 0;
5651 const u8 *eptr = NULL, *ptr = NULL;
5652 const u8* group_mgmt_cs = NULL;
5653 const wpa_pmkid_list_t* pmkid = NULL;
5654
5655 if (!sme) {
5656 /* No connection params from userspace, Do nothing. */
5657 return 0;
5658 }
5659
5660 /* Check fw support and retreive current mfp val */
5661 err = wldev_iovar_getint(dev, "mfp", ¤t_mfp);
5662 if (!err) {
5663 fw_support = true;
5664 }
5665
5666 /* Parse the wpa2ie to decode the MFP capablity */
5667 if (((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
5668 DOT11_MNG_RSN_ID)) != NULL) &&
5669 (wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) {
5670 WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap[0], rsn_cap[1]));
5671 /* Check for MFP cap in the RSN capability field */
5672 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
5673 if (sme->mfp)
5674 #endif // endif
5675 {
5676 if (rsn_cap[0] & RSN_CAP_MFPR) {
5677 mfp = WL_MFP_REQUIRED;
5678 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
5679 mfp = WL_MFP_CAPABLE;
5680 }
5681 }
5682 /*
5683 * eptr --> end/last byte addr of wpa2_ie
5684 * ptr --> to keep track of current/required byte addr
5685 */
5686 eptr = (const u8*)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN);
5687 /* pointing ptr to the next byte after rns_cap */
5688 ptr = (const u8*)rsn_cap + RSN_CAP_LEN;
5689 if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) {
5690 /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
5691 pmkid = (const wpa_pmkid_list_t*)ptr;
5692 count = pmkid->count.low | (pmkid->count.high << 8);
5693 /* ptr now to point to last byte addr of pmkid */
5694 ptr = (const u8*)pmkid + (count * WPA2_PMKID_LEN
5695 + WPA2_PMKID_COUNT_LEN);
5696 if ((eptr - ptr) >= WPA_SUITE_LEN) {
5697 /* group_mgmt_cs now to point to first byte addr of bip */
5698 group_mgmt_cs = ptr;
5699 }
5700 }
5701 }
5702
5703 WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n",
5704 mfp, wpa2_ie, fw_support));
5705
5706 if (fw_support == false) {
5707 if (mfp == WL_MFP_REQUIRED) {
5708 /* if mfp > 0, mfp capability set in wpa ie, but
5709 * FW indicated error for mfp. Propagate the error up.
5710 */
5711 WL_ERR(("mfp capability found in wpaie. But fw doesn't "
5712 "seem to support MFP\n"));
5713 err = -EINVAL;
5714 goto exit;
5715 } else {
5716 /* Firmware doesn't support mfp. But since connection request
5717 * is for non-mfp case, don't bother.
5718 */
5719 err = BCME_OK;
5720 goto exit;
5721 }
5722 } else if (mfp != current_mfp) {
5723 err = wldev_iovar_setint(dev, "mfp", mfp);
5724 if (unlikely(err)) {
5725 WL_ERR(("mfp (%d) set failed ret:%d \n", mfp, err));
5726 goto exit;
5727 }
5728 WL_INFORM_MEM(("[%s] wl mfp 0x%x\n", dev->name, mfp));
5729 }
5730
5731 if (group_mgmt_cs && bcmp((const uint8 *)WPA2_OUI,
5732 group_mgmt_cs, (WPA_SUITE_LEN - 1)) == 0) {
5733 WL_DBG(("BIP is found\n"));
5734 err = wldev_iovar_setbuf(dev, "bip",
5735 group_mgmt_cs, WPA_SUITE_LEN, cfg->ioctl_buf,
5736 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5737 /*
5738 * Dont return failure for unsupported cases
5739 * of bip iovar for backward compatibility
5740 */
5741 if (err != BCME_UNSUPPORTED && err < 0) {
5742 WL_ERR(("bip set error (%d)\n", err));
5743 {
5744 goto exit;
5745 }
5746 } else {
5747 WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n",
5748 dev->name, group_mgmt_cs[0], group_mgmt_cs[1],
5749 group_mgmt_cs[2]));
5750 }
5751 }
5752 exit:
5753 if (err) {
5754 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
5755 FW_LOGSET_MASK_ALL);
5756 }
5757
5758 return 0;
5759 }
5760 #endif /* MFP */
5761
5762 #ifdef WL_FILS
5763 bool
wl_is_fils_supported(struct net_device * ndev)5764 wl_is_fils_supported(struct net_device *ndev)
5765 {
5766 s32 err;
5767 u8 ioctl_buf[WLC_IOCTL_SMLEN] = {0};
5768 bcm_iov_buf_t *iov_buf = (bcm_iov_buf_t *)ioctl_buf;
5769
5770 iov_buf->version = WL_FILS_IOV_VERSION;
5771 err = wldev_iovar_getbuf(ndev, "fils", (uint8*)iov_buf, sizeof(bcm_iov_buf_t),
5772 iov_buf, WLC_IOCTL_SMLEN, NULL);
5773 if (err == BCME_UNSUPPORTED) {
5774 WL_DBG(("FILS NOT supported\n"));
5775 return false;
5776 }
5777
5778 WL_INFORM(("FILS supported\n"));
5779 return true;
5780 }
5781
5782 #define WL_NUM_OF_TLV_IN_SET_FILS_PARAMS 4u
5783 static s32
wl_set_fils_params(struct net_device * dev,struct cfg80211_connect_params * sme)5784 wl_set_fils_params(struct net_device *dev, struct cfg80211_connect_params *sme)
5785 {
5786 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5787 bcm_iov_buf_t *iov_buf = NULL;
5788 bcm_xtlvbuf_t tbuf;
5789 s32 err = BCME_OK;
5790 uint32 buf_size;
5791
5792 if ((sme->auth_type != NL80211_AUTHTYPE_FILS_SK) &&
5793 (sme->auth_type != NL80211_AUTHTYPE_FILS_SK_PFS) &&
5794 (sme->auth_type != NL80211_AUTHTYPE_FILS_PK)) {
5795 return BCME_OK;
5796 }
5797 if (sme->fils_erp_rrk_len > WL_MAX_FILS_KEY_LEN) {
5798 WL_ERR(("%s: FILS rRK exceed allowed size\n", __FUNCTION__));
5799 err = BCME_BADARG;
5800 goto exit;
5801 }
5802 /* Check incoming buffer length */
5803 buf_size = sme->fils_erp_username_len + sme->fils_erp_realm_len + sme->fils_erp_rrk_len +
5804 sizeof(sme->fils_erp_next_seq_num) +
5805 WL_NUM_OF_TLV_IN_SET_FILS_PARAMS * BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32) +
5806 sizeof(bcm_iov_buf_t) - 1u;
5807
5808 if (buf_size > WLC_IOCTL_SMLEN) {
5809 WL_ERR(("%s: FILS connect params arguments exceed allowed size\n", __FUNCTION__));
5810 err = BCME_BADARG;
5811 goto exit;
5812 }
5813 iov_buf = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
5814 if (!iov_buf) {
5815 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, WLC_IOCTL_SMLEN));
5816 err = BCME_NOMEM;
5817 goto exit;
5818 }
5819 iov_buf->version = WL_FILS_IOV_VERSION;
5820 iov_buf->id = WL_FILS_CMD_ADD_CONNECT_PARAMS;
5821 /* check if this should be len w/o headers */
5822 err = bcm_xtlv_buf_init(&tbuf, (uint8*)&iov_buf->data[0],
5823 WLC_IOCTL_SMLEN - sizeof(bcm_iov_buf_t) + sizeof(uint16),
5824 BCM_XTLV_OPTION_ALIGN32);
5825 if (err != BCME_OK) {
5826 WL_ERR(("%s: xtlv_context initialization failed\n", __FUNCTION__));
5827 goto exit;
5828 }
5829 if (sme->fils_erp_username_len && sme->fils_erp_username != NULL) {
5830 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_USERNAME,
5831 sme->fils_erp_username, sme->fils_erp_username_len);
5832 if (err != BCME_OK) {
5833 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5834 goto exit;
5835 }
5836 }
5837 if (sme->fils_erp_realm_len && sme->fils_erp_realm != NULL) {
5838 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_REALM,
5839 sme->fils_erp_realm, sme->fils_erp_realm_len);
5840 if (err != BCME_OK) {
5841 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5842 goto exit;
5843 }
5844 }
5845 if (sme->fils_erp_rrk_len && sme->fils_erp_rrk != NULL) {
5846 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_RRK,
5847 sme->fils_erp_rrk, sme->fils_erp_rrk_len);
5848 if (err != BCME_OK) {
5849 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5850 goto exit;
5851 }
5852 }
5853 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM,
5854 (u8 *)&sme->fils_erp_next_seq_num, sizeof(sme->fils_erp_next_seq_num));
5855 if (err != BCME_OK) {
5856 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5857 goto exit;
5858 }
5859 iov_buf->len = bcm_xtlv_buf_len(&tbuf);
5860 err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf->len + sizeof(bcm_iov_buf_t) -
5861 sizeof(uint16), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5862 if (unlikely(err)) {
5863 WL_ERR(("set fils params ioctl error (%d)\n", err));
5864 goto exit;
5865 }
5866
5867 exit:
5868 if (err != BCME_OK) {
5869 WL_ERR(("set FILS params error %d\n", err));
5870 }
5871 else {
5872 WL_INFORM_MEM(("FILS parameters succesfully applied\n"));
5873 }
5874 if (iov_buf) {
5875 MFREE(cfg->osh, iov_buf, WLC_IOCTL_SMLEN);
5876 }
5877 return err;
5878 }
5879
5880 #if !defined(WL_FILS_ROAM_OFFLD) && defined(WL_FILS)
5881 static s32
wl_get_bcn_timeout(struct net_device * dev,u32 * bcn_timeout)5882 wl_get_bcn_timeout(struct net_device *dev, u32 *bcn_timeout)
5883 {
5884 s32 err = 0;
5885
5886 err = wldev_iovar_getint(dev, "bcn_timeout", bcn_timeout);
5887 if (unlikely(err)) {
5888 WL_ERR(("could not get bcn_timeout (%d)\n", err));
5889 }
5890 return err;
5891 }
5892
5893 #define WL_ROAM_ENABLE 0
5894 #define WL_ROAM_DISABLE 1
5895 /* Beacon Timeout beacon loss in case FILS roaming offload is not supported by fw */
5896 #define WL_BCN_TIMEOUT 3
5897
5898 static s32
wl_fils_toggle_roaming(struct net_device * dev,u32 auth_type)5899 wl_fils_toggle_roaming(struct net_device *dev, u32 auth_type)
5900 {
5901 s32 err = 0;
5902 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5903
5904 if (WPA2_AUTH_IS_FILS(auth_type) && !cfg->fils_info.fils_roam_disabled) {
5905 err = wl_get_bcn_timeout(dev, &cfg->fils_info.fils_bcn_timeout_cache);
5906 if (unlikely(err)) {
5907 return err;
5908 }
5909 wl_dongle_roam(dev, WL_ROAM_DISABLE, WL_BCN_TIMEOUT);
5910 cfg->fils_info.fils_roam_disabled = true;
5911 WL_INFORM_MEM(("fw roam disabled for FILS akm\n"));
5912 } else if (cfg->fils_info.fils_roam_disabled) {
5913 /* Enable roaming back for other auth types */
5914 wl_dongle_roam(dev, WL_ROAM_ENABLE, cfg->fils_info.fils_bcn_timeout_cache);
5915 cfg->fils_info.fils_roam_disabled = false;
5916 WL_INFORM_MEM(("fw roam enabled\n"));
5917 }
5918 return err;
5919 }
5920 #endif /* !WL_FILS_ROAM_OFFLD && WL_FILS */
5921 #endif /* WL_FILS */
5922
5923 static s32
wl_set_key_mgmt(struct net_device * dev,struct cfg80211_connect_params * sme)5924 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
5925 {
5926 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5927 struct wl_security *sec;
5928 s32 val = 0;
5929 s32 err = 0;
5930 s32 bssidx;
5931
5932 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5933 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5934 return BCME_ERROR;
5935 }
5936
5937 if (sme->crypto.n_akm_suites) {
5938 err = wldev_iovar_getint(dev, "wpa_auth", &val);
5939 if (unlikely(err)) {
5940 WL_ERR(("could not get wpa_auth (%d)\n", err));
5941 return err;
5942 }
5943 if (val & (WPA_AUTH_PSK |
5944 WPA_AUTH_UNSPECIFIED)) {
5945 switch (sme->crypto.akm_suites[0]) {
5946 case WLAN_AKM_SUITE_8021X:
5947 val = WPA_AUTH_UNSPECIFIED;
5948 break;
5949 case WLAN_AKM_SUITE_PSK:
5950 val = WPA_AUTH_PSK;
5951 break;
5952 default:
5953 WL_ERR(("invalid akm suite (0x%x)\n",
5954 sme->crypto.akm_suites[0]));
5955 return -EINVAL;
5956 }
5957 } else if (val & (WPA2_AUTH_PSK |
5958 WPA2_AUTH_UNSPECIFIED)) {
5959 switch (sme->crypto.akm_suites[0]) {
5960 #ifdef MFP
5961 case WL_AKM_SUITE_SHA256_1X:
5962 val = WPA2_AUTH_1X_SHA256;
5963 break;
5964 case WL_AKM_SUITE_SHA256_PSK:
5965 val = WPA2_AUTH_PSK_SHA256;
5966 break;
5967 #endif /* MFP */
5968 case WLAN_AKM_SUITE_8021X:
5969 case WLAN_AKM_SUITE_PSK:
5970 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
5971 case WLAN_AKM_SUITE_FT_8021X:
5972 #endif // endif
5973 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
5974 case WLAN_AKM_SUITE_FT_PSK:
5975 #endif // endif
5976 case WLAN_AKM_SUITE_FILS_SHA256:
5977 case WLAN_AKM_SUITE_FILS_SHA384:
5978 case WLAN_AKM_SUITE_8021X_SUITE_B:
5979 case WLAN_AKM_SUITE_8021X_SUITE_B_192:
5980 #ifdef WL_OWE
5981 case WLAN_AKM_SUITE_OWE:
5982 #endif /* WL_OWE */
5983 case WLAN_AKM_SUITE_FT_8021X_SHA384:
5984 val = wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[0]);
5985 break;
5986 case WLAN_AKM_SUITE_FT_FILS_SHA256:
5987 val = WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT;
5988 break;
5989 case WLAN_AKM_SUITE_FT_FILS_SHA384:
5990 val = WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT;
5991 break;
5992 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
5993 case WLAN_AKM_SUITE_SAE:
5994 val = WPA3_AUTH_SAE_PSK;
5995 break;
5996 #endif /* WL_SAE || WL_CLIENT_SAE */
5997 default:
5998 WL_ERR(("invalid akm suite (0x%x)\n",
5999 sme->crypto.akm_suites[0]));
6000 return -EINVAL;
6001 }
6002 }
6003 #ifdef BCMWAPI_WPI
6004 else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) {
6005 switch (sme->crypto.akm_suites[0]) {
6006 case WLAN_AKM_SUITE_WAPI_CERT:
6007 val = WAPI_AUTH_UNSPECIFIED;
6008 break;
6009 case WLAN_AKM_SUITE_WAPI_PSK:
6010 val = WAPI_AUTH_PSK;
6011 break;
6012 default:
6013 WL_ERR(("invalid akm suite (0x%x)\n",
6014 sme->crypto.akm_suites[0]));
6015 return -EINVAL;
6016 }
6017 }
6018 #endif // endif
6019
6020 #ifdef WL_FILS
6021 #if !defined(WL_FILS_ROAM_OFFLD)
6022 err = wl_fils_toggle_roaming(dev, val);
6023 if (unlikely(err)) {
6024 return err;
6025 }
6026 #endif /* !WL_FILS_ROAM_OFFLD */
6027 #endif /* !WL_FILS */
6028
6029 #ifdef MFP
6030 if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) {
6031 WL_ERR(("MFP set failed err:%d\n", err));
6032 return -EINVAL;
6033 }
6034 #endif /* MFP */
6035
6036 WL_INFORM_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val));
6037 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
6038 if (unlikely(err)) {
6039 WL_ERR(("could not set wpa_auth (0x%x)\n", err));
6040 return err;
6041 }
6042 }
6043 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6044 sec->wpa_auth = sme->crypto.akm_suites[0];
6045
6046 return err;
6047 }
6048
6049 static s32
wl_set_set_sharedkey(struct net_device * dev,struct cfg80211_connect_params * sme)6050 wl_set_set_sharedkey(struct net_device *dev,
6051 struct cfg80211_connect_params *sme)
6052 {
6053 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6054 struct wl_security *sec;
6055 struct wl_wsec_key key;
6056 s32 val;
6057 s32 err = 0;
6058 s32 bssidx;
6059
6060 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6061 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6062 return BCME_ERROR;
6063 }
6064
6065 WL_DBG(("key len (%d)\n", sme->key_len));
6066 if (sme->key_len) {
6067 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6068 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
6069 sec->wpa_versions, sec->cipher_pairwise));
6070 if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
6071 NL80211_WPA_VERSION_2)) &&
6072 #ifdef BCMWAPI_WPI
6073 !is_wapi(sec->cipher_pairwise) &&
6074 #endif // endif
6075 (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
6076 WLAN_CIPHER_SUITE_WEP104)))
6077 {
6078 bzero(&key, sizeof(key));
6079 key.len = (u32) sme->key_len;
6080 key.index = (u32) sme->key_idx;
6081 if (unlikely(key.len > sizeof(key.data))) {
6082 WL_ERR(("Too long key length (%u)\n", key.len));
6083 return -EINVAL;
6084 }
6085 memcpy(key.data, sme->key, key.len);
6086 key.flags = WL_PRIMARY_KEY;
6087 if ((sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP40) ||
6088 (sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP104)) {
6089 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(sec->cipher_pairwise);
6090 } else {
6091 WL_ERR(("Invalid algorithm (%d)\n",
6092 sme->crypto.ciphers_pairwise[0]));
6093 return -EINVAL;
6094 }
6095 /* Set the new key/index */
6096 WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
6097 key.len, key.index, key.algo));
6098 WL_DBG(("key \"%s\"\n", key.data));
6099 swap_key_from_BE(&key);
6100 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6101 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6102 if (unlikely(err)) {
6103 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6104 return err;
6105 }
6106 WL_INFORM_MEM(("key applied to fw\n"));
6107 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
6108 WL_DBG(("set auth_type to shared key\n"));
6109 val = WL_AUTH_SHARED_KEY; /* shared key */
6110 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
6111 if (unlikely(err)) {
6112 WL_ERR(("set auth failed (%d)\n", err));
6113 return err;
6114 }
6115 }
6116 }
6117 }
6118 return err;
6119 }
6120
6121 #if defined(ESCAN_RESULT_PATCH)
6122 static u8 connect_req_bssid[6];
6123 static u8 broad_bssid[6];
6124 #endif /* ESCAN_RESULT_PATCH */
6125
6126 #if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
wl_get_chan_isvht80(struct net_device * net,dhd_pub_t * dhd)6127 static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
6128 {
6129 u32 chanspec = 0;
6130 bool isvht80 = 0;
6131
6132 if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK)
6133 chanspec = wl_chspec_driver_to_host(chanspec);
6134
6135 isvht80 = chanspec & WL_CHANSPEC_BW_80;
6136 WL_DBG(("wl_get_chan_isvht80: chanspec(%x:%d)\n", chanspec, isvht80));
6137
6138 return isvht80;
6139 }
6140 #endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
6141
wl_cfg80211_cleanup_mismatch_status(struct net_device * dev,struct bcm_cfg80211 * cfg,bool disassociate)6142 int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80211 *cfg,
6143 bool disassociate)
6144 {
6145 scb_val_t scbval;
6146 int err = TRUE;
6147 int wait_cnt;
6148
6149 if (disassociate) {
6150 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6151 BCM_REFERENCE(dhdp);
6152 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
6153 dhd_net2idx(dhdp->info, dev), DOT11_RC_DISASSOC_LEAVING);
6154 WL_ERR(("Disassociate previous connection!\n"));
6155 wl_set_drv_status(cfg, DISCONNECTING, dev);
6156 scbval.val = DOT11_RC_DISASSOC_LEAVING;
6157 scbval.val = htod32(scbval.val);
6158
6159 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6160 sizeof(scb_val_t));
6161 if (unlikely(err)) {
6162 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6163 WL_ERR(("error (%d)\n", err));
6164 return err;
6165 }
6166 wait_cnt = 500/10;
6167 } else {
6168 wait_cnt = 200/10;
6169 WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
6170 if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6171 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6172 }
6173 }
6174
6175 while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
6176 WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
6177 wait_cnt));
6178 wait_cnt--;
6179 OSL_SLEEP(10);
6180 }
6181
6182 if (wait_cnt == 0) {
6183 WL_ERR(("DISCONNECING clean up failed!\n"));
6184 /* Clear DISCONNECTING driver status as we have made sufficient attempts
6185 * for driver clean up.
6186 */
6187 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6188 wl_clr_drv_status(cfg, CONNECTED, dev);
6189 return BCME_NOTREADY;
6190 }
6191 return BCME_OK;
6192 }
6193
6194 #ifdef WL_FILS
6195 static int
wl_fils_add_hlp_container(struct bcm_cfg80211 * cfg,struct net_device * dev,const uint8 * ie_buf,uint16 ie_len)6196 wl_fils_add_hlp_container(struct bcm_cfg80211 *cfg, struct net_device *dev,
6197 const uint8* ie_buf, uint16 ie_len)
6198 {
6199 const bcm_tlv_ext_t *hlp_ie;
6200
6201 if ((hlp_ie = (const bcm_tlv_ext_t*)bcm_parse_tlvs_dot11((const uint8 *)ie_buf, ie_len,
6202 FILS_HLP_CONTAINER_EXT_ID, TRUE))) {
6203 u16 hlp_len = hlp_ie->len;
6204 u16 left_len = (ie_len - ((const uint8*)hlp_ie - ie_buf));
6205 bcm_iov_buf_t *iov_buf = 0;
6206 uint8* pxtlv;
6207 int err;
6208 size_t iov_buf_len;
6209 bcm_tlv_dot11_frag_tot_len(ie_buf, ie_len, FILS_HLP_CONTAINER_EXT_ID,
6210 TRUE, (uint*)&hlp_len);
6211
6212 hlp_len += BCM_TLV_EXT_HDR_SIZE;
6213
6214 if ((hlp_len > DOT11_MAX_MPDU_BODY_LEN) || (hlp_len > left_len)) {
6215 WL_ERR(("bad HLP length %d\n", hlp_len));
6216 return EFAULT;
6217 }
6218 iov_buf_len = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) - 1 + hlp_len;
6219 iov_buf = MALLOCZ(cfg->osh, iov_buf_len);
6220 if (iov_buf == NULL) {
6221 WL_ERR(("failed to allocated iov_buf\n"));
6222 return ENOMEM;
6223 }
6224
6225 prhex("HLP, HLP", (const uchar *)hlp_ie, hlp_len);
6226
6227 pxtlv = (uint8 *)&iov_buf->data[0];
6228 ((bcm_xtlv_t*)pxtlv)->id = WL_FILS_XTLV_HLP_IE;
6229 ((bcm_xtlv_t*)pxtlv)->len = hlp_len;
6230
6231 memcpy(((bcm_xtlv_t*)pxtlv)->data, hlp_ie, ((bcm_xtlv_t*)pxtlv)->len);
6232
6233 iov_buf->version = WL_FILS_IOV_VERSION;
6234 iov_buf->id = WL_FILS_CMD_ADD_HLP_IE;
6235 iov_buf->len = ((sizeof(bcm_xtlv_t)-1) + ((bcm_xtlv_t*)pxtlv)->len);
6236
6237 err = wldev_iovar_setbuf(dev, "fils", iov_buf,
6238 sizeof(bcm_iov_buf_t) + iov_buf->len,
6239 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6240 if (unlikely(err)) {
6241 WL_ERR(("fils wldev_iovar_setbuf error (%d)\n", err));
6242 }
6243 else {
6244 WL_INFORM_MEM(("FILS HLP Packet succesfully updated\n"));
6245 }
6246 MFREE(cfg->osh, iov_buf, iov_buf_len);
6247 }
6248 return BCME_OK;
6249 }
6250 #endif /* WL_FILS */
6251
6252 #if defined(WL_FILS)
6253 #ifndef UPDATE_FILS_ERP_INFO
6254 #define UPDATE_FILS_ERP_INFO BIT(1)
6255 #define UPDATE_AUTH_TYPE BIT(2)
6256 #endif // endif
6257
6258 static int
wl_cfg80211_update_connect_params(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme,u32 changed)6259 wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
6260 struct cfg80211_connect_params *sme, u32 changed)
6261 {
6262 s32 err = BCME_OK;
6263 if (changed & UPDATE_FILS_ERP_INFO) {
6264 err = wl_set_fils_params(dev, sme);
6265
6266 if (unlikely(err)) {
6267 WL_ERR(("Invalid FILS params\n"));
6268 goto exit;
6269 }
6270 }
6271 if (changed & UPDATE_AUTH_TYPE) {
6272 err = wl_set_auth_type(dev, sme);
6273 if (unlikely(err)) {
6274 WL_ERR(("Invalid auth type\n"));
6275 goto exit;
6276 }
6277 }
6278 if ((changed & UPDATE_FILS_ERP_INFO) && !(changed & UPDATE_AUTH_TYPE)) {
6279 WL_DBG(("Warning: FILS ERP params are set, but authentication type - not\n"));
6280 }
6281 exit:
6282 return err;
6283
6284 }
6285 #endif /* WL_FILS */
6286
6287 #define MAX_SCAN_ABORT_WAIT_CNT 20
6288 #define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
6289
6290 #ifndef CONFIG_AP6XXX_WIFI6_HDF
6291 static
6292 #endif
6293 s32
wl_cfg80211_connect(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme)6294 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
6295 struct cfg80211_connect_params *sme)
6296 {
6297 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6298 struct ieee80211_channel *chan = sme->channel;
6299 wl_extjoin_params_t *ext_join_params;
6300 struct wl_join_params join_params;
6301 size_t join_params_size;
6302 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6303 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6304 s32 roam_trigger[2] = {0, 0};
6305 #endif /* ROAM_AP_ENV_DETECTION */
6306 s32 err = 0;
6307 const wpa_ie_fixed_t *wpa_ie;
6308 const bcm_tlv_t *wpa2_ie;
6309 const u8* wpaie = 0;
6310 u32 wpaie_len = 0;
6311 u32 chan_cnt = 0;
6312 struct ether_addr bssid;
6313 s32 bssidx = -1;
6314 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6315 bool skip_hints = fw_ap_select;
6316 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6317 #ifdef ESCAN_CHANNEL_CACHE
6318 chanspec_t chanspec_list[MAX_ROAM_CHANNEL];
6319 #endif /* ESCAN_CHANNEL_CACHE */
6320 int wait_cnt;
6321 char sec[32];
6322
6323 WL_DBG(("In %s\n", dev->name));
6324 if (!dev) {
6325 WL_ERR(("dev is null\n"));
6326 return -EINVAL;
6327 }
6328 BCM_REFERENCE(dhdp);
6329 DHD_STATLOG_CTRL(dhdp, ST(ASSOC_START), dhd_net2idx(dhdp->info, dev), 0);
6330
6331 #ifdef ESCAN_CHANNEL_CACHE
6332 memset(chanspec_list, 0, (sizeof(chanspec_t) * MAX_ROAM_CHANNEL));
6333 #endif /* ESCAN_CHANNEL_CACHE */
6334
6335 /* Connection attempted via linux-wireless */
6336 wl_set_drv_status(cfg, CFG80211_CONNECT, dev);
6337 #ifdef DHDTCPSYNC_FLOOD_BLK
6338 dhd_reset_tcpsync_info_by_dev(dev);
6339 #endif /* DHDTCPSYNC_FLOOD_BLK */
6340
6341 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6342 #ifdef WL_SKIP_CONNECT_HINTS
6343 skip_hints = true;
6344 #elif defined(WL_FW_OCE_AP_SELECT)
6345 /* override bssid_hint for oce networks */
6346 skip_hints = (fw_ap_select && wl_cfg80211_is_oce_ap(wiphy, sme->bssid_hint));
6347 #endif // endif
6348 if (skip_hints) {
6349 /* Let fw choose the best AP */
6350 WL_INFORM(("skipping bssid & channel hint\n"));
6351 } else {
6352 if (sme->channel_hint) {
6353 chan = sme->channel_hint;
6354 WL_INFORM_MEM(("channel_hint (%d), channel_hint center_freq (%d)\n",
6355 ieee80211_frequency_to_channel(sme->channel_hint->center_freq),
6356 sme->channel_hint->center_freq));
6357 }
6358 if (sme->bssid_hint) {
6359 sme->bssid = sme->bssid_hint;
6360 WL_INFORM_MEM(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
6361 }
6362 }
6363 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6364
6365 if (unlikely(!sme->ssid)) {
6366 WL_ERR(("Invalid ssid\n"));
6367 return -EOPNOTSUPP;
6368 }
6369
6370 if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) {
6371 WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n",
6372 sme->ssid, sme->ssid_len));
6373 return -EINVAL;
6374 }
6375
6376 WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
6377 if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
6378 prhex(NULL, sme->ie, sme->ie_len);
6379 }
6380
6381 RETURN_EIO_IF_NOT_UP(cfg);
6382 /*
6383 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
6384 */
6385 if (cfg->scan_request) {
6386 WL_TRACE_HW4(("Aborting the scan! \n"));
6387 wl_cfg80211_scan_abort(cfg);
6388 wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
6389 while (wl_get_drv_status(cfg, SCANNING, dev) && wait_cnt) {
6390 WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
6391 wait_cnt--;
6392 OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
6393 }
6394 if (wl_get_drv_status(cfg, SCANNING, dev)) {
6395 wl_cfg80211_cancel_scan(cfg);
6396 }
6397 }
6398 #ifdef WL_SCHED_SCAN
6399 /* Locks are taken in wl_cfg80211_sched_scan_stop()
6400 * A start scan occuring during connect is unlikely
6401 */
6402 if (cfg->sched_scan_req) {
6403 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
6404 wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg),
6405 cfg->sched_scan_req->reqid);
6406 #else
6407 wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg));
6408 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
6409 }
6410 #endif /* WL_SCHED_SCAN */
6411 #ifdef WL_CFG80211_GON_COLLISION
6412 /* init block gon req count */
6413 cfg->block_gon_req_tx_count = 0;
6414 cfg->block_gon_req_rx_count = 0;
6415 #endif /* WL_CFG80211_GON_COLLISION */
6416 #if defined(ESCAN_RESULT_PATCH)
6417 if (sme->bssid)
6418 memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN);
6419 else
6420 bzero(connect_req_bssid, ETHER_ADDR_LEN);
6421 bzero(broad_bssid, ETHER_ADDR_LEN);
6422 #endif // endif
6423 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
6424 maxrxpktglom = 0;
6425 #endif // endif
6426 if (wl_get_drv_status(cfg, CONNECTING, dev) || wl_get_drv_status(cfg, CONNECTED, dev)) {
6427 /* set nested connect bit to identify the context */
6428 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6429 /* DHD prev status is CONNECTING/CONNECTED */
6430 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
6431 } else if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6432 /* DHD prev status is DISCONNECTING */
6433 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, false);
6434 } else if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6435 /* DHD previous status is not connected and FW connected */
6436 if (wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) == 0) {
6437 /* set nested connect bit to identify the context */
6438 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6439 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, true);
6440 }
6441 }
6442 wl_ext_in4way_sync(dev, STA_WAIT_DISCONNECTED, WL_EXT_STATUS_CONNECTING, NULL);
6443
6444 if (sme->bssid) {
6445 wl_update_prof(cfg, dev, NULL, sme->bssid, WL_PROF_LATEST_BSSID);
6446 } else {
6447 wl_update_prof(cfg, dev, NULL, ðer_bcast, WL_PROF_LATEST_BSSID);
6448 }
6449 #ifdef SUPPORT_AP_BWCTRL
6450 if (dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
6451 wl_restore_ap_bw(cfg);
6452 }
6453 #endif /* SUPPORT_AP_BWCTRL */
6454 /* 'connect' request received */
6455 wl_set_drv_status(cfg, CONNECTING, dev);
6456 /* clear nested connect bit on proceeding for connection */
6457 wl_clr_drv_status(cfg, NESTED_CONNECT, dev);
6458
6459 /* Clean BSSID */
6460 bzero(&bssid, sizeof(bssid));
6461 if (!wl_get_drv_status(cfg, DISCONNECTING, dev))
6462 wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
6463
6464 if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) {
6465 /* we only allow to connect using virtual interface in case of P2P */
6466 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6467 WL_ERR(("Find p2p index from wdev(%p) failed\n",
6468 dev->ieee80211_ptr));
6469 err = BCME_ERROR;
6470 goto exit;
6471 }
6472 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6473 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
6474 } else if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6475 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6476 WL_ERR(("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr));
6477 err = BCME_ERROR;
6478 goto exit;
6479 }
6480
6481 /* find the RSN_IE */
6482 if ((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
6483 DOT11_MNG_RSN_ID)) != NULL) {
6484 WL_DBG((" WPA2 IE is found\n"));
6485 }
6486 /* find the WPA_IE */
6487 if ((wpa_ie = wl_cfgp2p_find_wpaie(sme->ie,
6488 sme->ie_len)) != NULL) {
6489 WL_DBG((" WPA IE is found\n"));
6490 }
6491 if (wpa_ie != NULL || wpa2_ie != NULL) {
6492 wpaie = (wpa_ie != NULL) ? (const u8 *)wpa_ie : (const u8 *)wpa2_ie;
6493 wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
6494 wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
6495 err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
6496 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6497 if (unlikely(err)) {
6498 WL_ERR(("wpaie set error (%d)\n", err));
6499 goto exit;
6500 }
6501 } else {
6502 err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
6503 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6504 if (unlikely(err)) {
6505 WL_ERR(("wpaie set error (%d)\n", err));
6506 goto exit;
6507 }
6508 }
6509 err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6510 VNDR_IE_ASSOCREQ_FLAG, (const u8 *)sme->ie, sme->ie_len);
6511 if (unlikely(err)) {
6512 goto exit;
6513 }
6514 }
6515 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6516 if (dhdp->roam_env_detection) {
6517 bool is_roamtrig_reset = TRUE;
6518 bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection",
6519 AP_ENV_DETECT_NOT_USED) == BCME_OK);
6520 #ifdef SKIP_ROAM_TRIGGER_RESET
6521 roam_trigger[1] = WLC_BAND_2G;
6522 is_roamtrig_reset =
6523 (wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
6524 sizeof(roam_trigger)) == BCME_OK) &&
6525 (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER-10);
6526 #endif /* SKIP_ROAM_TRIGGER_RESET */
6527 if (is_roamtrig_reset && is_roam_env_ok) {
6528 roam_trigger[0] = WL_AUTO_ROAM_TRIGGER;
6529 roam_trigger[1] = WLC_BAND_ALL;
6530 err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
6531 sizeof(roam_trigger));
6532 if (unlikely(err)) {
6533 WL_ERR((" failed to restore roam_trigger for auto env"
6534 " detection\n"));
6535 }
6536 }
6537 }
6538 #endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
6539 if (chan) {
6540 cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
6541 chan_cnt = 1;
6542 WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel,
6543 chan->center_freq, chan_cnt));
6544 } else {
6545 WL_DBG(("No channel info from user space\n"));
6546 cfg->channel = 0;
6547 }
6548 #ifdef ESCAN_CHANNEL_CACHE
6549 /*
6550 * No channel information from user space. if ECC is enabled, the ECC
6551 * would prepare the channel list, else no channel would be provided
6552 * and firmware would need to do a full channel scan.
6553 *
6554 * Use cached channels. This might take slightly longer time compared
6555 * to using a single channel based join. But ECC would help choose
6556 * a better AP for a given ssid. For a given SSID there might multiple
6557 * APs on different channels and ECC would scan all those channels
6558 * before deciding up on the AP. This accounts for the additional delay.
6559 */
6560 if (cfg->rcc_enabled || cfg->channel == 0)
6561 {
6562 wlc_ssid_t ssid;
6563 int band;
6564
6565 err = wldev_get_band(dev, &band);
6566 if (!err) {
6567 set_roam_band(band);
6568 }
6569
6570 memcpy(ssid.SSID, sme->ssid, sme->ssid_len);
6571 ssid.SSID_len = (uint32)sme->ssid_len;
6572 chan_cnt = get_roam_channel_list(cfg->channel, chanspec_list,
6573 MAX_ROAM_CHANNEL, &ssid, ioctl_version);
6574 WL_DBG(("RCC channel count:%d \n", chan_cnt));
6575 }
6576 #endif /* ESCAN_CHANNEL_CACHE */
6577 WL_DBG(("3. set wpa version \n"));
6578
6579 err = wl_set_wpa_version(dev, sme);
6580 if (unlikely(err)) {
6581 WL_ERR(("Invalid wpa_version\n"));
6582 goto exit;
6583 }
6584 #ifdef BCMWAPI_WPI
6585 if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1)
6586 WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n"));
6587 else {
6588 WL_DBG(("4. wl_set_auth_type\n"));
6589 #endif // endif
6590 err = wl_set_auth_type(dev, sme);
6591 if (unlikely(err)) {
6592 WL_ERR(("Invalid auth type\n"));
6593 goto exit;
6594 }
6595 #ifdef BCMWAPI_WPI
6596 }
6597 #endif // endif
6598 #ifdef WL_FILS
6599 if (sme->ie && sme->ie_len) {
6600 err = wl_fils_add_hlp_container(cfg, dev, sme->ie, sme->ie_len);
6601 if (unlikely(err)) {
6602 WL_ERR(("FILS sending HLP failed\n"));
6603 goto exit;
6604 }
6605 }
6606 #endif /* WL_FILS */
6607 err = wl_set_set_cipher(dev, sme);
6608 if (unlikely(err)) {
6609 WL_ERR(("Invalid ciper\n"));
6610 goto exit;
6611 }
6612
6613 err = wl_set_key_mgmt(dev, sme);
6614 if (unlikely(err)) {
6615 WL_ERR(("Invalid key mgmt\n"));
6616 goto exit;
6617 }
6618
6619 err = wl_set_set_sharedkey(dev, sme);
6620 if (unlikely(err)) {
6621 WL_ERR(("Invalid shared key\n"));
6622 goto exit;
6623 }
6624 #ifdef WL_FILS
6625 err = wl_set_fils_params(dev, sme);
6626 if (unlikely(err)) {
6627 WL_ERR(("Invalid FILS params\n"));
6628 goto exit;
6629 }
6630 #endif /* WL_FILS */
6631
6632 /*
6633 * Join with specific BSSID and cached SSID
6634 * If SSID is zero join based on BSSID only
6635 */
6636 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
6637 chan_cnt * sizeof(chanspec_t);
6638 ext_join_params = (wl_extjoin_params_t *)MALLOCZ(cfg->osh, join_params_size);
6639 if (ext_join_params == NULL) {
6640 err = -ENOMEM;
6641 wl_clr_drv_status(cfg, CONNECTING, dev);
6642 goto exit;
6643 }
6644 ext_join_params->ssid.SSID_len =
6645 (uint32)min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
6646 memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
6647 wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
6648 ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
6649 /* increate dwell time to receive probe response or detect Beacon
6650 * from target AP at a noisy air only during connect command
6651 */
6652 ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
6653 ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
6654 /* Set up join scan parameters */
6655 ext_join_params->scan.scan_type = -1;
6656 ext_join_params->scan.nprobes = chan_cnt ?
6657 (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
6658 ext_join_params->scan.home_time = -1;
6659
6660 if (sme->bssid)
6661 memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
6662 else
6663 memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN);
6664 ext_join_params->assoc.chanspec_num = chan_cnt;
6665
6666 if (chan_cnt && !cfg->rcc_enabled) {
6667 if (cfg->channel) {
6668 /*
6669 * Use the channel provided by userspace
6670 */
6671 u16 channel, band, bw, ctl_sb;
6672 chanspec_t chspec;
6673 channel = cfg->channel;
6674 band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
6675 : WL_CHANSPEC_BAND_5G;
6676
6677 /* Get min_bw set for the interface */
6678 bw = WL_CHANSPEC_BW_20;
6679 if (bw == INVCHANSPEC) {
6680 WL_ERR(("Invalid chanspec \n"));
6681 MFREE(cfg->osh, ext_join_params, join_params_size);
6682 err = BCME_ERROR;
6683 goto exit;
6684 }
6685
6686 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
6687 chspec = (channel | band | bw | ctl_sb);
6688 ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
6689 ext_join_params->assoc.chanspec_list[0] |= chspec;
6690 ext_join_params->assoc.chanspec_list[0] =
6691 wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]);
6692 }
6693 }
6694 #ifdef ESCAN_CHANNEL_CACHE
6695 else {
6696 memcpy(ext_join_params->assoc.chanspec_list, chanspec_list,
6697 sizeof(chanspec_t) * chan_cnt);
6698 }
6699 #endif /* ESCAN_CHANNEL_CACHE */
6700 ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
6701 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
6702 WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
6703 ext_join_params->ssid.SSID_len));
6704 }
6705
6706 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6707 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6708 MFREE(cfg->osh, ext_join_params, join_params_size);
6709 err = BCME_ERROR;
6710 goto exit;
6711 }
6712 #ifdef WLTDLS
6713 /* disable TDLS if number of connected interfaces is >= 1 */
6714 wl_cfg80211_tdls_config(cfg, TDLS_STATE_CONNECT, false);
6715 #endif /* WLTDLS */
6716 #ifdef WL_EXT_IAPSTA
6717 wl_ext_iapsta_update_channel(dhdp, dev, cfg->channel);
6718 #endif
6719
6720 wl_ext_get_sec(dev, 0, sec, sizeof(sec));
6721 if (cfg->rcc_enabled) {
6722 WL_MSG(dev->name, "Connecting with " MACDBG " ssid \"%s\", len (%d), "
6723 "sec=%s, with rcc channels. chan_cnt:%d \n\n",
6724 MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
6725 ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, sec, chan_cnt);
6726 } else {
6727 WL_MSG(dev->name, "Connecting with " MACDBG " ssid \"%s\", len (%d), "
6728 "sec=%s, channel=%d\n\n",
6729 MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
6730 ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, sec,
6731 cfg->channel);
6732 }
6733 SUPP_LOG(("[%s] Connecting with " MACDBG " ssid \"%s\","
6734 "channel:%d rcc:%d\n",
6735 dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
6736 ext_join_params->ssid.SSID, cfg->channel, cfg->rcc_enabled));
6737 err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
6738 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6739 MFREE(cfg->osh, ext_join_params, join_params_size);
6740 if (err) {
6741 wl_clr_drv_status(cfg, CONNECTING, dev);
6742 if (err == BCME_UNSUPPORTED) {
6743 WL_DBG(("join iovar is not supported\n"));
6744 goto set_ssid;
6745 } else {
6746 WL_ERR(("join iovar error (%d)\n", err));
6747 goto exit;
6748 }
6749 } else
6750 goto exit;
6751
6752 set_ssid:
6753 #if defined(ROAMEXP_SUPPORT)
6754 /* Clear Blacklist bssid and Whitelist ssid list before join issue
6755 * This is temporary fix since currently firmware roaming is not
6756 * disabled by android framework before SSID join from framework
6757 */
6758 /* Flush blacklist bssid content */
6759 dhd_dev_set_blacklist_bssid(dev, NULL, 0, true);
6760 /* Flush whitelist ssid content */
6761 dhd_dev_set_whitelist_ssid(dev, NULL, 0, true);
6762 #endif /* ROAMEXP_SUPPORT */
6763 bzero(&join_params, sizeof(join_params));
6764 join_params_size = sizeof(join_params.ssid);
6765
6766 join_params.ssid.SSID_len = (uint32)min(sizeof(join_params.ssid.SSID), sme->ssid_len);
6767 memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
6768 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
6769 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
6770 if (sme->bssid)
6771 memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
6772 else
6773 memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN);
6774
6775 if (wl_ch_to_chanspec(dev, cfg->channel, &join_params, &join_params_size) < 0) {
6776 WL_ERR(("Invalid chanspec\n"));
6777 return -EINVAL;
6778 }
6779
6780 WL_DBG(("join_param_size %zu\n", join_params_size));
6781
6782 if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
6783 WL_MSG(dev->name, "ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
6784 join_params.ssid.SSID_len);
6785 }
6786 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, join_params_size);
6787 exit:
6788 if (err) {
6789 WL_ERR(("error (%d)\n", err));
6790 wl_clr_drv_status(cfg, CONNECTING, dev);
6791 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
6792 #ifdef WLTDLS
6793 /* If connect fails, check whether we can enable back TDLS */
6794 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
6795 #endif /* WLTDLS */
6796 }
6797 if (!err)
6798 wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY,
6799 WL_EXT_STATUS_CONNECTING, NULL);
6800 #ifdef DBG_PKT_MON
6801 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && !err) {
6802 DHD_DBG_PKT_MON_START(dhdp);
6803 }
6804 #endif /* DBG_PKT_MON */
6805 return err;
6806 }
6807
wl_cfg80211_disconnect_state_sync(struct bcm_cfg80211 * cfg,struct net_device * dev)6808 static void wl_cfg80211_disconnect_state_sync(struct bcm_cfg80211 *cfg, struct net_device *dev)
6809 {
6810 struct wireless_dev *wdev;
6811 uint8 wait_cnt;
6812
6813 if (!dev || !dev->ieee80211_ptr) {
6814 WL_ERR(("wrong ndev\n"));
6815 return;
6816 }
6817
6818 wdev = dev->ieee80211_ptr;
6819 wait_cnt = WAIT_FOR_DISCONNECT_STATE_SYNC;
6820 while ((wdev->current_bss) && wait_cnt) {
6821 WL_DBG(("Waiting for disconnect sync, wait_cnt: %d\n", wait_cnt));
6822 wait_cnt--;
6823 OSL_SLEEP(50);
6824 }
6825
6826 if (wait_cnt == 0) {
6827 /* state didn't get cleared within given timeout */
6828 WL_INFORM_MEM(("cfg80211 state. wdev->current_bss non null\n"));
6829 } else {
6830 WL_MEM(("cfg80211 disconnect state sync done\n"));
6831 }
6832
6833 }
6834
wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 * cfg,struct net_device * dev)6835 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev)
6836 {
6837 uint8 wait_cnt;
6838 u32 status = 0;
6839
6840 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
6841 while ((status = wl_get_drv_status(cfg, DISCONNECTING, dev)) && wait_cnt) {
6842 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
6843 wait_cnt--;
6844 OSL_SLEEP(50);
6845 }
6846
6847 WL_INFORM_MEM(("Wait for disconnection done. status:%d wait_cnt:%d\n", status, wait_cnt));
6848 if (!wait_cnt && wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6849 /* No response from firmware. Indicate connect result
6850 * to clear cfg80211 state machine
6851 */
6852 WL_INFORM_MEM(("force send connect result\n"));
6853 CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
6854 WLAN_STATUS_UNSPECIFIED_FAILURE,
6855 GFP_KERNEL);
6856 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6857 }
6858 return;
6859 }
6860
6861 #ifndef CONFIG_AP6XXX_WIFI6_HDF
6862 static
6863 #endif
6864 s32
wl_cfg80211_disconnect(struct wiphy * wiphy,struct net_device * dev,u16 reason_code)6865 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
6866 u16 reason_code)
6867 {
6868 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6869 scb_val_t scbval;
6870 bool act = false;
6871 s32 err = 0;
6872 u8 *curbssid = NULL;
6873 u8 null_bssid[ETHER_ADDR_LEN];
6874 s32 bssidx = 0;
6875 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6876
6877 RETURN_EIO_IF_NOT_UP(cfg);
6878 act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
6879 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
6880 WL_MSG(dev->name, "Reason %d, act %d\n", reason_code, act);
6881
6882 BCM_REFERENCE(dhdp);
6883 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_START),
6884 dhd_net2idx(dhdp->info, dev), reason_code);
6885 #ifdef DHD_4WAYM4_FAIL_DISCONNECT
6886 dhd_cleanup_m4_state_work(dhdp, dhd_net2idx(dhdp->info, dev));
6887 #endif /* DHD_4WAYM4_FAIL_DISCONNECT */
6888
6889 #ifdef ESCAN_RESULT_PATCH
6890 if (wl_get_drv_status(cfg, CONNECTING, dev)) {
6891 if (curbssid) {
6892 WL_ERR(("Disconnecting while CONNECTING status"
6893 " connecting device: " MACDBG "\n", MAC2STRDBG(curbssid)));
6894 } else {
6895 WL_ERR(("Disconnecting while CONNECTING status \n"));
6896 }
6897 act = true;
6898 }
6899 #endif /* ESCAN_RESULT_PATCH */
6900
6901 if (!curbssid) {
6902 WL_ERR(("Disconnecting while CONNECTING status %d\n", (int)sizeof(null_bssid)));
6903 bzero(null_bssid, sizeof(null_bssid));
6904 curbssid = null_bssid;
6905 }
6906
6907 if (act) {
6908 #ifdef DBG_PKT_MON
6909 /* Stop packet monitor */
6910 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6911 DHD_DBG_PKT_MON_STOP(dhdp);
6912 }
6913 #endif /* DBG_PKT_MON */
6914 /*
6915 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
6916 */
6917 /* Let scan aborted by F/W */
6918 if (cfg->scan_request) {
6919 WL_TRACE_HW4(("Aborting the scan! \n"));
6920 wl_cfg80211_cancel_scan(cfg);
6921 }
6922 /* Set DISCONNECTING state. We are clearing this state in all exit paths */
6923 wl_set_drv_status(cfg, DISCONNECTING, dev);
6924 if (wl_get_drv_status(cfg, CONNECTING, dev) ||
6925 wl_get_drv_status(cfg, CONNECTED, dev)) {
6926 scbval.val = reason_code;
6927 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
6928 scbval.val = htod32(scbval.val);
6929 WL_INFORM_MEM(("[%s] wl disassoc\n", dev->name));
6930 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6931 sizeof(scb_val_t));
6932 if (unlikely(err)) {
6933 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6934 WL_ERR(("error (%d)\n", err));
6935 goto exit;
6936 }
6937 wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
6938 WL_EXT_STATUS_DISCONNECTING, NULL);
6939 }
6940 #ifdef WL_WPS_SYNC
6941 /* If are in WPS reauth state, then we would be
6942 * dropping the link down events. Ensure that
6943 * Event is sent up for the disconnect Req
6944 */
6945 if (wl_wps_session_update(dev,
6946 WPS_STATE_DISCONNECT, curbssid) == BCME_OK) {
6947 WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
6948 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6949 }
6950 #endif /* WPS_SYNC */
6951 wl_cfg80211_wait_for_disconnection(cfg, dev);
6952 } else {
6953 /* Not in connecting or connected state. However since disconnect came
6954 * from upper layer, indicate connect fail to clear any state mismatch
6955 */
6956 WL_INFORM_MEM(("act is false. report connect result fail.\n"));
6957 CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
6958 WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
6959 }
6960 #ifdef CUSTOM_SET_CPUCORE
6961 /* set default cpucore */
6962 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6963 dhdp->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
6964 if (!(dhdp->chan_isvht80))
6965 dhd_set_cpucore(dhdp, FALSE);
6966 }
6967 #endif /* CUSTOM_SET_CPUCORE */
6968
6969 cfg->rssi = 0; /* reset backup of rssi */
6970
6971 exit:
6972 /* Clear IEs for disaasoc */
6973 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6974 WL_ERR(("Find index failed\n"));
6975 err = -EINVAL;
6976 return err;
6977 }
6978 WL_ERR(("Clearing disconnect IEs \n"));
6979 err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
6980 ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, NULL, 0);
6981
6982 return err;
6983 }
6984
6985 static s32
6986 #if defined(WL_CFG80211_P2P_DEV_IF)
wl_cfg80211_set_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,s32 mbm)6987 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
6988 enum nl80211_tx_power_setting type, s32 mbm)
6989 #else
6990 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
6991 enum nl80211_tx_power_setting type, s32 dbm)
6992 #endif /* WL_CFG80211_P2P_DEV_IF */
6993 {
6994
6995 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6996 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6997 s32 err = 0;
6998 #if defined(WL_CFG80211_P2P_DEV_IF)
6999 s32 dbm = MBM_TO_DBM(mbm);
7000 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
7001 defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
7002 dbm = MBM_TO_DBM(dbm);
7003 #endif /* WL_CFG80211_P2P_DEV_IF */
7004
7005 RETURN_EIO_IF_NOT_UP(cfg);
7006 switch (type) {
7007 case NL80211_TX_POWER_AUTOMATIC:
7008 break;
7009 case NL80211_TX_POWER_LIMITED:
7010 if (dbm < 0) {
7011 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
7012 return -EINVAL;
7013 }
7014 break;
7015 case NL80211_TX_POWER_FIXED:
7016 if (dbm < 0) {
7017 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
7018 return -EINVAL;
7019 }
7020 break;
7021 }
7022
7023 err = wl_set_tx_power(ndev, type, dbm);
7024 if (unlikely(err)) {
7025 WL_ERR(("error (%d)\n", err));
7026 return err;
7027 }
7028
7029 cfg->conf->tx_power = dbm;
7030
7031 return err;
7032 }
7033
7034 static s32
7035 #if defined(WL_CFG80211_P2P_DEV_IF)
wl_cfg80211_get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,s32 * dbm)7036 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
7037 struct wireless_dev *wdev, s32 *dbm)
7038 #else
7039 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
7040 #endif /* WL_CFG80211_P2P_DEV_IF */
7041 {
7042 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7043 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7044 s32 err = 0;
7045
7046 RETURN_EIO_IF_NOT_UP(cfg);
7047 err = wl_get_tx_power(ndev, dbm);
7048 if (unlikely(err))
7049 WL_ERR(("error (%d)\n", err));
7050
7051 return err;
7052 }
7053
7054 static s32
wl_cfg80211_config_default_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool unicast,bool multicast)7055 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
7056 u8 key_idx, bool unicast, bool multicast)
7057 {
7058 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7059 u32 index;
7060 s32 wsec;
7061 s32 err = 0;
7062 s32 bssidx;
7063
7064 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7065 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
7066 return BCME_ERROR;
7067 }
7068
7069 WL_DBG(("key index (%d)\n", key_idx));
7070 RETURN_EIO_IF_NOT_UP(cfg);
7071 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7072 if (unlikely(err)) {
7073 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7074 return err;
7075 }
7076 if (wsec == WEP_ENABLED) {
7077 /* Just select a new current key */
7078 index = (u32) key_idx;
7079 index = htod32(index);
7080 err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index,
7081 sizeof(index));
7082 if (unlikely(err)) {
7083 WL_ERR(("error (%d)\n", err));
7084 }
7085 }
7086 return err;
7087 }
7088
7089 static s32
wl_add_keyext(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,const u8 * mac_addr,struct key_params * params)7090 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
7091 u8 key_idx, const u8 *mac_addr, struct key_params *params)
7092 {
7093 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7094 struct wl_wsec_key key;
7095 s32 err = 0;
7096 s32 bssidx;
7097 s32 mode = wl_get_mode_by_netdev(cfg, dev);
7098
7099 WL_MSG(dev->name, "key index (%d)\n", key_idx);
7100 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7101 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7102 return BCME_ERROR;
7103 }
7104 bzero(&key, sizeof(key));
7105 key.index = (u32) key_idx;
7106
7107 if (!ETHER_ISMULTI(mac_addr))
7108 memcpy((char *)&key.ea, (const void *)mac_addr, ETHER_ADDR_LEN);
7109 key.len = (u32) params->key_len;
7110
7111 /* check for key index change */
7112 if (key.len == 0) {
7113 /* key delete */
7114 swap_key_from_BE(&key);
7115 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7116 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7117 if (unlikely(err)) {
7118 WL_ERR(("key delete error (%d)\n", err));
7119 return err;
7120 }
7121 } else {
7122 if (key.len > sizeof(key.data)) {
7123 WL_ERR(("Invalid key length (%d)\n", key.len));
7124 return -EINVAL;
7125 }
7126 WL_DBG(("Setting the key index %d\n", key.index));
7127 memcpy(key.data, params->key, key.len);
7128
7129 if ((mode == WL_MODE_BSS) &&
7130 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
7131 u8 keybuf[8];
7132 memcpy(keybuf, &key.data[24], sizeof(keybuf));
7133 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
7134 memcpy(&key.data[16], keybuf, sizeof(keybuf));
7135 }
7136
7137 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
7138 if (params->seq && params->seq_len == 6) {
7139 /* rx iv */
7140 const u8 *ivptr;
7141 ivptr = (const u8 *) params->seq;
7142 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
7143 (ivptr[3] << 8) | ivptr[2];
7144 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
7145 key.iv_initialized = true;
7146 }
7147 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7148 if (key.algo == CRYPTO_ALGO_OFF) { //not found.
7149 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7150 return -EINVAL;
7151 }
7152 swap_key_from_BE(&key);
7153 /* need to guarantee EAPOL 4/4 send out before set key */
7154 dhd_wait_pend8021x(dev);
7155 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7156 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7157 if (unlikely(err)) {
7158 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7159 return err;
7160 }
7161 WL_INFORM_MEM(("[%s] wsec key set\n", dev->name));
7162 }
7163 return err;
7164 }
7165
7166 int
wl_cfg80211_enable_roam_offload(struct net_device * dev,int enable)7167 wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
7168 {
7169 int err;
7170 wl_eventmsg_buf_t ev_buf;
7171 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7172
7173 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7174 /* roam offload is only for the primary device */
7175 return -1;
7176 }
7177
7178 WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev->name, enable));
7179 err = wldev_iovar_setint(dev, "roam_offload", enable);
7180 if (err)
7181 return err;
7182
7183 bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
7184 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
7185 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
7186 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
7187 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
7188 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
7189 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
7190 err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
7191 if (!err) {
7192 cfg->roam_offload = enable;
7193 }
7194 return err;
7195 }
7196
7197 struct wireless_dev *
wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 * cfg,const char * name)7198 wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 *cfg, const char *name)
7199 {
7200 struct net_info *iter, *next;
7201
7202 if (name == NULL) {
7203 WL_ERR(("Iface name is not provided\n"));
7204 return NULL;
7205 }
7206
7207 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7208 for_each_ndev(cfg, iter, next) {
7209 GCC_DIAGNOSTIC_POP();
7210 if (iter->ndev) {
7211 if (strcmp(iter->ndev->name, name) == 0) {
7212 return iter->ndev->ieee80211_ptr;
7213 }
7214 }
7215 }
7216
7217 WL_DBG(("Iface %s not found\n", name));
7218 return NULL;
7219 }
7220
7221 #if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
7222 void
wl_cfg80211_block_arp(struct net_device * dev,int enable)7223 wl_cfg80211_block_arp(struct net_device *dev, int enable)
7224 {
7225 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7226 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7227
7228 WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev->name, enable));
7229 if (!dhd_pkt_filter_enable) {
7230 WL_DBG(("Packet filter isn't enabled\n"));
7231 return;
7232 }
7233
7234 /* Block/Unblock ARP frames only if STA is connected to
7235 * the upstream AP in case of STA+SoftAP Concurrenct mode
7236 */
7237 if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
7238 WL_DBG(("STA not connected to upstream AP\n"));
7239 return;
7240 }
7241
7242 if (enable) {
7243 WL_DBG(("Enable ARP Filter\n"));
7244 /* Add ARP filter */
7245 dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
7246
7247 /* Enable ARP packet filter - blacklist */
7248 dhd_master_mode = FALSE;
7249 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7250 TRUE, dhd_master_mode);
7251 } else {
7252 WL_DBG(("Disable ARP Filter\n"));
7253 /* Disable ARP packet filter */
7254 dhd_master_mode = TRUE;
7255 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7256 FALSE, dhd_master_mode);
7257
7258 /* Delete ARP filter */
7259 dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
7260 }
7261 }
7262 #endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
7263
7264 static s32
wl_cfg80211_add_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr,struct key_params * params)7265 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
7266 u8 key_idx, bool pairwise, const u8 *mac_addr,
7267 struct key_params *params)
7268 {
7269 struct wl_wsec_key key;
7270 s32 val = 0;
7271 s32 wsec = 0;
7272 s32 err = 0;
7273 u8 keybuf[8];
7274 s32 bssidx = 0;
7275 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7276 s32 mode = wl_get_mode_by_netdev(cfg, dev);
7277 #ifdef WL_GCMP
7278 uint32 algos = 0, mask = 0;
7279 #endif /* WL_GCMP */
7280 #if defined(WLAN_CIPHER_SUITE_PMK)
7281 int j;
7282 wsec_pmk_t pmk;
7283 char keystring[WSEC_MAX_PSK_LEN + 1];
7284 char* charptr = keystring;
7285 u16 len;
7286 struct wl_security *sec;
7287 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7288 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7289
7290 WL_INFORM_MEM(("key index (%d) (0x%x)\n", key_idx, params->cipher));
7291 RETURN_EIO_IF_NOT_UP(cfg);
7292
7293 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7294 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
7295 return BCME_ERROR;
7296 }
7297
7298 if (mac_addr &&
7299 ((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
7300 (params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
7301 wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
7302 goto exit;
7303 }
7304
7305 BCM_REFERENCE(dhdp);
7306 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_KEY), dhd_net2idx(dhdp->info, dev), 0);
7307
7308 bzero(&key, sizeof(key));
7309 /* Clear any buffered wep key */
7310 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
7311
7312 key.len = (u32) params->key_len;
7313 key.index = (u32) key_idx;
7314
7315 if (unlikely(key.len > sizeof(key.data))) {
7316 WL_ERR(("Too long key length (%u)\n", key.len));
7317 return -EINVAL;
7318 }
7319 memcpy(key.data, params->key, key.len);
7320
7321 key.flags = WL_PRIMARY_KEY;
7322
7323 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7324 val = wl_rsn_cipher_wsec_algo_lookup(params->cipher);
7325 if (val == WSEC_NONE) {
7326 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7327 #if defined(WLAN_CIPHER_SUITE_PMK)
7328 /* WLAN_CIPHER_SUITE_PMK is not NL80211 standard ,but BRCM proprietary cipher suite.
7329 * so it doesn't have right algo type too. Just for now, bypass this check for
7330 * backward compatibility.
7331 * TODO: deprecate this proprietary way and replace to nl80211 set_pmk API.
7332 */
7333 if (params->cipher != WLAN_CIPHER_SUITE_PMK)
7334 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7335 return -EINVAL;
7336 }
7337 switch (params->cipher) {
7338 case WLAN_CIPHER_SUITE_TKIP:
7339 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
7340 if (mode == WL_MODE_BSS) {
7341 bcopy(&key.data[24], keybuf, sizeof(keybuf));
7342 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
7343 bcopy(keybuf, &key.data[16], sizeof(keybuf));
7344 }
7345 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7346 break;
7347 #if defined(WLAN_CIPHER_SUITE_PMK)
7348 case WLAN_CIPHER_SUITE_PMK:
7349 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7350
7351 WL_MEM(("set_pmk: wpa_auth:%x akm:%x\n", sec->wpa_auth, params->cipher));
7352 /* Avoid pmk set for SAE and OWE for external supplicant case. */
7353 if (IS_AKM_SAE(sec->wpa_auth) || IS_AKM_OWE(sec->wpa_auth)) {
7354 WL_INFORM_MEM(("skip pmk set for akm:%x\n", sec->wpa_auth));
7355 break;
7356 }
7357
7358 if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
7359 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
7360 err = wldev_iovar_setbuf(dev, "okc_info_pmk", (const void *)params->key,
7361 WSEC_MAX_PSK_LEN / 2, keystring, sizeof(keystring), NULL);
7362 if (err) {
7363 /* could fail in case that 'okc' is not supported */
7364 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err));
7365 }
7366 }
7367 /* copy the raw hex key to the appropriate format */
7368 for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) {
7369 charptr += snprintf(charptr, sizeof(keystring), "%02x", params->key[j]);
7370 }
7371 len = (u16)strlen(keystring);
7372 pmk.key_len = htod16(len);
7373 bcopy(keystring, pmk.key, len);
7374 pmk.flags = htod16(WSEC_PASSPHRASE);
7375
7376 err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
7377 if (err) {
7378 return err;
7379 }
7380 /* Clear key length to delete key */
7381 key.len = 0;
7382 break;
7383 #endif /* WLAN_CIPHER_SUITE_PMK */
7384 #ifdef WL_GCMP
7385 case WLAN_CIPHER_SUITE_GCMP:
7386 case WLAN_CIPHER_SUITE_GCMP_256:
7387 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
7388 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
7389 algos = KEY_ALGO_MASK(key.algo);
7390 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
7391 break;
7392 #endif /* WL_GCMP */
7393 default: /* No post processing required */
7394 WL_DBG(("no post processing required (0x%x)\n", params->cipher));
7395 break;
7396 }
7397
7398 /* Set the new key/index */
7399 if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
7400 WL_ERR(("IBSS KEY setted\n"));
7401 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
7402 }
7403 swap_key_from_BE(&key);
7404 if ((params->cipher == WLAN_CIPHER_SUITE_WEP40) ||
7405 (params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
7406 /*
7407 * For AP role, since we are doing a wl down before bringing up AP,
7408 * the plumbed keys will be lost. So for AP once we bring up AP, we
7409 * need to plumb keys again. So buffer the keys for future use. This
7410 * is more like a WAR. If firmware later has the capability to do
7411 * interface upgrade without doing a "wl down" and "wl apsta 0", then
7412 * this will not be required.
7413 */
7414 WL_DBG(("Buffering WEP Keys \n"));
7415 memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key));
7416 }
7417 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7418 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7419 if (unlikely(err)) {
7420 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7421 return err;
7422 }
7423
7424 exit:
7425 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7426 if (unlikely(err)) {
7427 WL_ERR(("get wsec error (%d)\n", err));
7428 return err;
7429 }
7430
7431 wsec |= val;
7432 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
7433 if (unlikely(err)) {
7434 WL_ERR(("set wsec error (%d)\n", err));
7435 return err;
7436 }
7437 #ifdef WL_GCMP
7438 wl_set_wsec_info_algos(dev, algos, mask);
7439 #endif /* WL_GCMP */
7440 wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY,
7441 WL_EXT_STATUS_ADD_KEY, NULL);
7442 return err;
7443 }
7444
7445 static s32
wl_cfg80211_del_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr)7446 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
7447 u8 key_idx, bool pairwise, const u8 *mac_addr)
7448 {
7449 struct wl_wsec_key key;
7450 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7451 s32 err = 0;
7452 s32 bssidx;
7453 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7454
7455 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7456 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7457 return BCME_ERROR;
7458 }
7459 WL_DBG(("Enter\n"));
7460
7461 #ifndef MFP
7462 if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
7463 return -EINVAL;
7464 #endif // endif
7465
7466 RETURN_EIO_IF_NOT_UP(cfg);
7467 BCM_REFERENCE(dhdp);
7468 DHD_STATLOG_CTRL(dhdp, ST(DELETE_KEY), dhd_net2idx(dhdp->info, dev), 0);
7469 bzero(&key, sizeof(key));
7470
7471 key.flags = WL_PRIMARY_KEY;
7472 key.algo = CRYPTO_ALGO_OFF;
7473 key.index = (u32) key_idx;
7474
7475 WL_DBG(("key index (%d)\n", key_idx));
7476 /* Set the new key/index */
7477 swap_key_from_BE(&key);
7478 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7479 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7480 if (unlikely(err)) {
7481 if (err == -EINVAL) {
7482 if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
7483 /* we ignore this key index in this case */
7484 WL_DBG(("invalid key index (%d)\n", key_idx));
7485 }
7486 } else {
7487 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7488 }
7489 return err;
7490 }
7491 return err;
7492 }
7493
7494 /* NOTE : this function cannot work as is and is never called */
7495 static s32
wl_cfg80211_get_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr,void * cookie,void (* callback)(void * cookie,struct key_params * params))7496 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
7497 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
7498 void (*callback) (void *cookie, struct key_params * params))
7499 {
7500 struct key_params params;
7501 struct wl_wsec_key key;
7502 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7503 struct wl_security *sec;
7504 s32 wsec;
7505 s32 err = 0;
7506 s32 bssidx;
7507
7508 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7509 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7510 return BCME_ERROR;
7511 }
7512 WL_DBG(("key index (%d)\n", key_idx));
7513 RETURN_EIO_IF_NOT_UP(cfg);
7514 bzero(&key, sizeof(key));
7515 key.index = key_idx;
7516 swap_key_to_BE(&key);
7517 bzero(¶ms, sizeof(params));
7518 params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
7519 params.key = key.data;
7520
7521 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7522 if (unlikely(err)) {
7523 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7524 return err;
7525 }
7526 switch (WSEC_ENABLED(wsec)) {
7527 case WEP_ENABLED:
7528 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7529 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
7530 params.cipher = WLAN_CIPHER_SUITE_WEP40;
7531 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7532 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
7533 params.cipher = WLAN_CIPHER_SUITE_WEP104;
7534 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7535 }
7536 break;
7537 case TKIP_ENABLED:
7538 params.cipher = WLAN_CIPHER_SUITE_TKIP;
7539 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7540 break;
7541 case AES_ENABLED:
7542 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7543 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7544 break;
7545 #ifdef BCMWAPI_WPI
7546 case SMS4_ENABLED:
7547 params.cipher = WLAN_CIPHER_SUITE_SMS4;
7548 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7549 break;
7550 #endif // endif
7551 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
7552 /* to connect to mixed mode AP */
7553 case (AES_ENABLED | TKIP_ENABLED): /* TKIP CCMP */
7554 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7555 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7556 break;
7557 #endif // endif
7558 default:
7559 WL_ERR(("Invalid algo (0x%x)\n", wsec));
7560 return -EINVAL;
7561 }
7562
7563 callback(cookie, ¶ms);
7564 return err;
7565 }
7566
7567 static s32
wl_cfg80211_config_default_mgmt_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx)7568 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
7569 struct net_device *dev, u8 key_idx)
7570 {
7571 #ifdef MFP
7572 return 0;
7573 #else
7574 WL_INFORM_MEM(("Not supported\n"));
7575 return -EOPNOTSUPP;
7576 #endif /* MFP */
7577 }
7578
7579 static bool
wl_check_assoc_state(struct bcm_cfg80211 * cfg,struct net_device * dev)7580 wl_check_assoc_state(struct bcm_cfg80211 *cfg, struct net_device *dev)
7581 {
7582 wl_assoc_info_t asinfo;
7583 uint32 state = 0;
7584 int err;
7585
7586 err = wldev_iovar_getbuf_bsscfg(dev, "assoc_info",
7587 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
7588 if (unlikely(err)) {
7589 WL_ERR(("failed to get assoc_info : err=%d\n", err));
7590 return FALSE;
7591 } else {
7592 memcpy(&asinfo, cfg->ioctl_buf, sizeof(wl_assoc_info_t));
7593 state = dtoh32(asinfo.state);
7594 WL_DBG(("assoc state=%d\n", state));
7595 }
7596
7597 return (state > 0)? TRUE:FALSE;
7598 }
7599
7600 static s32
wl_cfg80211_get_rssi(struct net_device * dev,struct bcm_cfg80211 * cfg,s32 * rssi)7601 wl_cfg80211_get_rssi(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 *rssi)
7602 {
7603 s32 err = BCME_OK;
7604 scb_val_t scb_val;
7605 #ifdef SUPPORT_RSSI_SUM_REPORT
7606 wl_rssi_ant_mimo_t rssi_ant_mimo;
7607 #endif /* SUPPORT_RSSI_SUM_REPORT */
7608
7609 if (dev == NULL || cfg == NULL) {
7610 return BCME_ERROR;
7611 }
7612
7613 /* initialize rssi */
7614 *rssi = 0;
7615
7616 #ifdef SUPPORT_RSSI_SUM_REPORT
7617 /* Query RSSI sum across antennas */
7618 bzero(&rssi_ant_mimo, sizeof(rssi_ant_mimo));
7619 err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
7620 if (err) {
7621 WL_ERR(("Could not get rssi sum (%d)\n", err));
7622 /* set rssi to zero and do not return error,
7623 * because iovar phy_rssi_ant could return BCME_UNSUPPORTED
7624 * when bssid was null during roaming
7625 */
7626 err = BCME_OK;
7627 } else {
7628 cfg->rssi_sum_report = TRUE;
7629 if ((*rssi = rssi_ant_mimo.rssi_sum) >= 0) {
7630 *rssi = 0;
7631 }
7632 }
7633 #endif /* SUPPORT_RSSI_SUM_REPORT */
7634
7635 /* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore */
7636 if (cfg->rssi_sum_report == FALSE) {
7637 bzero(&scb_val, sizeof(scb_val));
7638 scb_val.val = 0;
7639 err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val,
7640 sizeof(scb_val_t));
7641 if (err) {
7642 WL_ERR(("Could not get rssi (%d)\n", err));
7643 return err;
7644 }
7645 #if defined(RSSIOFFSET)
7646 *rssi = wl_update_rssi_offset(dev, dtoh32(scb_val.val));
7647 #else
7648 *rssi = dtoh32(scb_val.val);
7649 #endif
7650 }
7651
7652 if (*rssi >= 0) {
7653 /* check assoc status including roaming */
7654 DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub));
7655 if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_check_assoc_state(cfg, dev)) {
7656 *rssi = cfg->rssi; /* use previous RSSI */
7657 WL_DBG(("use previous RSSI %d dBm\n", cfg->rssi));
7658 } else {
7659 *rssi = 0;
7660 }
7661 DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
7662 } else {
7663 /* backup the current rssi */
7664 cfg->rssi = *rssi;
7665 }
7666
7667 return err;
7668 }
7669
7670 static int
wl_cfg80211_ifstats_counters_cb(void * ctx,const uint8 * data,uint16 type,uint16 len)7671 wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data, uint16 type, uint16 len)
7672 {
7673 switch (type) {
7674 case WL_IFSTATS_XTLV_IF_INDEX:
7675 WL_DBG(("Stats received on interface index: %d\n", *data));
7676 break;
7677 case WL_IFSTATS_XTLV_GENERIC: {
7678 if (len > sizeof(wl_if_stats_t)) {
7679 WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n",
7680 type, len, (int)sizeof(wl_if_stats_t)));
7681 }
7682 memcpy(ctx, data, sizeof(wl_if_stats_t));
7683 break;
7684 }
7685 default:
7686 WL_DBG(("Unsupported counter type 0x%x\n", type));
7687 break;
7688 }
7689
7690 return BCME_OK;
7691 }
7692
7693 /* Parameters to if_counters iovar need to be converted to XTLV format
7694 * before sending to FW. The length of the top level XTLV container
7695 * containing parameters should not exceed 228 bytes
7696 */
7697 #define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228
7698
7699 int
wl_cfg80211_ifstats_counters(struct net_device * dev,wl_if_stats_t * if_stats)7700 wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats)
7701 {
7702 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7703 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7704 uint8 *pbuf = NULL;
7705 bcm_xtlvbuf_t xtlvbuf, local_xtlvbuf;
7706 bcm_xtlv_t *xtlv;
7707 uint16 expected_resp_len;
7708 wl_stats_report_t *request = NULL, *response = NULL;
7709 int bsscfg_idx;
7710 int ret = BCME_OK;
7711
7712 pbuf = (uint8 *)MALLOCZ(dhdp->osh, WLC_IOCTL_MEDLEN);
7713 if (!pbuf) {
7714 WL_ERR(("Failed to allocate local pbuf\n"));
7715 return BCME_NOMEM;
7716 }
7717
7718 /* top level container length cannot exceed 228 bytes.
7719 * This is because the output buffer is 1535 bytes long.
7720 * Allow 1300 bytes for reporting stats coming in XTLV format
7721 */
7722 request = (wl_stats_report_t *)
7723 MALLOCZ(dhdp->osh, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7724 if (!request) {
7725 WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
7726 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX));
7727 ret = BCME_NOMEM;
7728 goto fail;
7729 }
7730
7731 request->version = WL_STATS_REPORT_REQUEST_VERSION_V2;
7732
7733 /* Top level container... we will create it ourselves */
7734 /* Leave space for report version, length, and top level XTLV
7735 * WL_IFSTATS_XTLV_IF.
7736 */
7737 ret = bcm_xtlv_buf_init(&local_xtlvbuf,
7738 (uint8*)(request->data) + BCM_XTLV_HDR_SIZE,
7739 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7740 offsetof(wl_stats_report_t, data) - BCM_XTLV_HDR_SIZE,
7741 BCM_XTLV_OPTION_ALIGN32);
7742
7743 if (ret) {
7744 goto fail;
7745 }
7746
7747 /* Populate requests using this the local_xtlvbuf context. The xtlvbuf
7748 * is used to fill the container containing the XTLVs populated using
7749 * local_xtlvbuf.
7750 */
7751 ret = bcm_xtlv_buf_init(&xtlvbuf,
7752 (uint8*)(request->data),
7753 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7754 offsetof(wl_stats_report_t, data),
7755 BCM_XTLV_OPTION_ALIGN32);
7756
7757 if (ret) {
7758 goto fail;
7759 }
7760
7761 /* Request generic stats */
7762 ret = bcm_xtlv_put_data(&local_xtlvbuf,
7763 WL_IFSTATS_XTLV_GENERIC, NULL, 0);
7764 if (ret) {
7765 goto fail;
7766 }
7767
7768 /* Complete the outer container with type and length
7769 * only.
7770 */
7771 ret = bcm_xtlv_put_data(&xtlvbuf,
7772 WL_IFSTATS_XTLV_IF,
7773 NULL, bcm_xtlv_buf_len(&local_xtlvbuf));
7774
7775 if (ret) {
7776 goto fail;
7777 }
7778
7779 request->length = bcm_xtlv_buf_len(&xtlvbuf) +
7780 offsetof(wl_stats_report_t, data);
7781 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
7782
7783 /* send the command over to the device and get teh output */
7784 ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request,
7785 request->length, pbuf, WLC_IOCTL_MEDLEN, bsscfg_idx,
7786 &cfg->ioctl_buf_sync);
7787 if (ret < 0) {
7788 WL_ERR(("if_counters not supported ret=%d\n", ret));
7789 goto fail;
7790 }
7791
7792 /* Reuse request to process response */
7793 response = (wl_stats_report_t *)pbuf;
7794
7795 /* version check */
7796 if (response->version != WL_STATS_REPORT_REQUEST_VERSION_V2) {
7797 ret = BCME_VERSION;
7798 goto fail;
7799 }
7800
7801 xtlv = (bcm_xtlv_t *)(response->data);
7802
7803 expected_resp_len =
7804 (BCM_XTLV_LEN(xtlv) + OFFSETOF(wl_stats_report_t, data));
7805
7806 /* Check if the received length is as expected */
7807 if ((response->length > WLC_IOCTL_MEDLEN) ||
7808 (response->length < expected_resp_len)) {
7809 ret = BCME_ERROR;
7810 WL_ERR(("Illegal response length received. Got: %d"
7811 " Expected: %d. Expected len must be <= %u\n",
7812 response->length, expected_resp_len, WLC_IOCTL_MEDLEN));
7813 goto fail;
7814 }
7815
7816 /* check the type. The return data will be in
7817 * WL_IFSTATS_XTLV_IF container. So check if that container is
7818 * present
7819 */
7820 if (BCM_XTLV_ID(xtlv) != WL_IFSTATS_XTLV_IF) {
7821 ret = BCME_ERROR;
7822 WL_ERR(("unexpected type received: %d Expected: %d\n",
7823 BCM_XTLV_ID(xtlv), WL_IFSTATS_XTLV_IF));
7824 goto fail;
7825 }
7826
7827 /* Process XTLVs within WL_IFSTATS_XTLV_IF container */
7828 ret = bcm_unpack_xtlv_buf(if_stats,
7829 (uint8*)response->data + BCM_XTLV_HDR_SIZE,
7830 BCM_XTLV_LEN(xtlv), /* total length of all TLVs in container */
7831 BCM_XTLV_OPTION_ALIGN32, wl_cfg80211_ifstats_counters_cb);
7832 if (ret) {
7833 WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret));
7834 }
7835
7836 fail:
7837 if (pbuf) {
7838 MFREE(dhdp->osh, pbuf, WLC_IOCTL_MEDLEN);
7839 }
7840
7841 if (request) {
7842 MFREE(dhdp->osh, request, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7843 }
7844 return ret;
7845 }
7846 #undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
7847
7848 static s32
7849 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
wl_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_info * sinfo)7850 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7851 const u8 *mac, struct station_info *sinfo)
7852 #else
7853 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7854 u8 *mac, struct station_info *sinfo)
7855 #endif // endif
7856 {
7857 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7858 s32 rssi = 0;
7859 s32 rate = 0;
7860 s32 err = 0;
7861 u16 wl_iftype = 0;
7862 u16 wl_mode = 0;
7863 get_pktcnt_t pktcnt;
7864 wl_if_stats_t *if_stats = NULL;
7865 sta_info_v4_t *sta = NULL;
7866 u8 *curmacp = NULL;
7867 s8 eabuf[ETHER_ADDR_STR_LEN];
7868 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
7869 bool fw_assoc_state = FALSE;
7870 u32 dhd_assoc_state = 0;
7871 void *buf;
7872
7873 RETURN_EIO_IF_NOT_UP(cfg);
7874
7875 if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype, &wl_iftype, &wl_mode) < 0) {
7876 return -EINVAL;
7877 }
7878
7879 buf = MALLOC(cfg->osh, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
7880 if (buf == NULL) {
7881 WL_ERR(("wl_cfg80211_get_station: MALLOC failed\n"));
7882 goto error;
7883 }
7884
7885 switch (wl_iftype) {
7886 case WL_IF_TYPE_STA:
7887 case WL_IF_TYPE_IBSS:
7888 if (cfg->roam_offload) {
7889 struct ether_addr bssid;
7890 bzero(&bssid, sizeof(bssid));
7891 err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
7892 if (err) {
7893 WL_ERR(("Failed to get current BSSID\n"));
7894 } else {
7895 if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
7896 /* roaming is detected */
7897 err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
7898 if (err)
7899 WL_ERR(("Failed to handle the delayed"
7900 " roam, err=%d", err));
7901 mac = (u8 *)bssid.octet;
7902 }
7903 }
7904 }
7905 dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
7906 DHD_OS_WAKE_LOCK(dhd);
7907 fw_assoc_state = dhd_is_associated(dhd, 0, &err);
7908 if (dhd_assoc_state && !fw_assoc_state) {
7909 /* check roam (join) status */
7910 if (wl_check_assoc_state(cfg, dev)) {
7911 fw_assoc_state = TRUE;
7912 WL_DBG(("roam status\n"));
7913 }
7914 }
7915 DHD_OS_WAKE_UNLOCK(dhd);
7916 if (!dhd_assoc_state || !fw_assoc_state) {
7917 WL_ERR(("NOT assoc\n"));
7918 if (err == -ENODATA)
7919 goto error;
7920 if (!dhd_assoc_state) {
7921 WL_TRACE_HW4(("drv state is not connected \n"));
7922 }
7923 if (!fw_assoc_state) {
7924 WL_TRACE_HW4(("fw state is not associated \n"));
7925 }
7926 /* Disconnect due to fw is not associated for
7927 * FW_ASSOC_WATCHDOG_TIME ms.
7928 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
7929 * means that BSSID is null.
7930 */
7931 if (dhd_assoc_state && !fw_assoc_state && !err) {
7932 if (!fw_assoc_watchdog_started) {
7933 fw_assoc_watchdog_ms = OSL_SYSUPTIME();
7934 fw_assoc_watchdog_started = TRUE;
7935 WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
7936 } else if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
7937 FW_ASSOC_WATCHDOG_TIME) {
7938 fw_assoc_watchdog_started = FALSE;
7939 err = -ENODEV;
7940 WL_TRACE_HW4(("fw is not associated for %d ms \n",
7941 (OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
7942 goto get_station_err;
7943 }
7944 }
7945 err = -ENODEV;
7946 goto error;
7947 }
7948 if (dhd_is_associated(dhd, 0, NULL)) {
7949 fw_assoc_watchdog_started = FALSE;
7950 }
7951 curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
7952 if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
7953 WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
7954 MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
7955 }
7956 /* go through to get another information */
7957 case WL_IF_TYPE_P2P_GC:
7958 case WL_IF_TYPE_P2P_DISC:
7959 if ((err = wl_cfg80211_get_rssi(dev, cfg, &rssi)) != BCME_OK) {
7960 goto get_station_err;
7961 }
7962 #if defined(RSSIAVG)
7963 err = wl_update_connected_rssi_cache(dev, &cfg->g_connected_rssi_cache_ctrl, &rssi);
7964 if (err) {
7965 WL_ERR(("Could not get rssi (%d)\n", err));
7966 goto get_station_err;
7967 }
7968 wl_delete_dirty_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
7969 wl_reset_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
7970 #endif
7971 #if defined(RSSIOFFSET)
7972 rssi = wl_update_rssi_offset(dev, rssi);
7973 #endif
7974 #if !defined(RSSIAVG) && !defined(RSSIOFFSET)
7975 // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
7976 rssi = MIN(rssi, RSSI_MAXVAL);
7977 #endif
7978 sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
7979 sinfo->signal = rssi;
7980 WL_DBG(("RSSI %d dBm\n", rssi));
7981 /* go through to get another information */
7982 case WL_IF_TYPE_P2P_GO:
7983 /* Report the current tx rate */
7984 rate = 0;
7985 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
7986 if (err) {
7987 WL_ERR(("Could not get rate (%d)\n", err));
7988 } else {
7989 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7990 int rxpktglom;
7991 #endif // endif
7992 rate = dtoh32(rate);
7993 sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
7994 sinfo->txrate.legacy = rate * 5;
7995 WL_DBG(("Rate %d Mbps\n", (rate / 2)));
7996 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7997 rxpktglom = ((rate/2) > 150) ? 20 : 10;
7998
7999 if (maxrxpktglom != rxpktglom) {
8000 maxrxpktglom = rxpktglom;
8001 WL_DBG(("Rate %d Mbps, update bus:"
8002 "maxtxpktglom=%d\n", (rate/2), maxrxpktglom));
8003 err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
8004 (char*)&maxrxpktglom, 4, cfg->ioctl_buf,
8005 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8006 if (err < 0) {
8007 WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
8008 }
8009 }
8010 #endif // endif
8011 }
8012 if_stats = (wl_if_stats_t *)buf;
8013 bzero(if_stats, sizeof(*if_stats));
8014 if (FW_SUPPORTED(dhd, ifst)) {
8015 err = wl_cfg80211_ifstats_counters(dev, if_stats);
8016 } else
8017 {
8018 err = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
8019 (char *)if_stats, sizeof(*if_stats), NULL);
8020 }
8021
8022 if (err) {
8023 // WL_ERR(("if_counters not supported ret=%d\n", err));
8024 bzero(&pktcnt, sizeof(pktcnt));
8025 err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt,
8026 sizeof(pktcnt));
8027 if (!err) {
8028 sinfo->rx_packets = pktcnt.rx_good_pkt;
8029 sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
8030 sinfo->tx_packets = pktcnt.tx_good_pkt;
8031 sinfo->tx_failed = pktcnt.tx_bad_pkt;
8032 }
8033 } else {
8034 sinfo->rx_packets = (uint32)dtoh64(if_stats->rxframe);
8035 sinfo->rx_dropped_misc = 0;
8036 sinfo->tx_packets = (uint32)dtoh64(if_stats->txfrmsnt);
8037 sinfo->tx_failed = (uint32)dtoh64(if_stats->txnobuf) +
8038 (uint32)dtoh64(if_stats->txrunt) +
8039 (uint32)dtoh64(if_stats->txfail);
8040 }
8041
8042 sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
8043 STA_INFO_BIT(INFO_RX_DROP_MISC) |
8044 STA_INFO_BIT(INFO_TX_PACKETS) |
8045 STA_INFO_BIT(INFO_TX_FAILED));
8046 get_station_err:
8047 if (err && (err != -ENODATA)) {
8048 /* Disconnect due to zero BSSID or error to get RSSI */
8049 scb_val_t scbval;
8050 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
8051 dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
8052 scbval.val = htod32(DOT11_RC_DISASSOC_LEAVING);
8053 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
8054 sizeof(scb_val_t));
8055 if (unlikely(err)) {
8056 WL_ERR(("disassoc error (%d)\n", err));
8057 }
8058
8059 WL_ERR(("force cfg80211_disconnected: %d\n", err));
8060 wl_clr_drv_status(cfg, CONNECTED, dev);
8061 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_DONE),
8062 dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
8063 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
8064 wl_link_down(cfg);
8065 }
8066 break;
8067 case WL_IF_TYPE_AP:
8068 err = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac,
8069 ETHER_ADDR_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8070 if (err < 0) {
8071 WL_ERR(("GET STA INFO failed, %d\n", err));
8072 goto error;
8073 }
8074 sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
8075 sta = (sta_info_v4_t *)buf;
8076 if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
8077 WL_ERR(("GET STA INFO version mismatch, %d\n", err));
8078 return BCME_VERSION;
8079 }
8080 sta->len = dtoh16(sta->len);
8081 sta->cap = dtoh16(sta->cap);
8082 sta->flags = dtoh32(sta->flags);
8083 sta->idle = dtoh32(sta->idle);
8084 sta->in = dtoh32(sta->in);
8085 sinfo->inactive_time = sta->idle * 1000;
8086 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
8087 if (sta->flags & WL_STA_ASSOC) {
8088 sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
8089 sinfo->connected_time = sta->in;
8090 }
8091 #endif // endif
8092 WL_INFORM_MEM(("STA %s, flags 0x%x, idle time %ds, connected time %ds\n",
8093 bcm_ether_ntoa((const struct ether_addr *)mac, eabuf),
8094 sta->flags, sta->idle, sta->in));
8095 break;
8096 default :
8097 WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
8098 }
8099 error:
8100 if (buf) {
8101 MFREE(cfg->osh, buf, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
8102 }
8103
8104 return err;
8105 }
8106
8107 static s32
wl_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool enabled,s32 timeout)8108 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
8109 bool enabled, s32 timeout)
8110 {
8111 s32 pm;
8112 s32 err = 0;
8113 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8114 struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
8115 s32 mode;
8116 #ifdef RTT_SUPPORT
8117 rtt_status_info_t *rtt_status;
8118 #endif /* RTT_SUPPORT */
8119 dhd_pub_t *dhd = cfg->pub;
8120 RETURN_EIO_IF_NOT_UP(cfg);
8121
8122 WL_DBG(("Enter %s enable=%d, timeout=%u\n", dev->name, enabled, timeout));
8123 mode = wl_get_mode_by_netdev(cfg, dev);
8124 if (cfg->p2p_net == dev || _net_info == NULL ||
8125 !wl_get_drv_status(cfg, CONNECTED, dev) ||
8126 ((mode != WL_MODE_BSS) &&
8127 (mode != WL_MODE_IBSS))) {
8128 return err;
8129 }
8130
8131 /* Enlarge pm_enable_work */
8132 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
8133
8134 pm = enabled ? PM_FAST : PM_OFF;
8135 if (_net_info->pm_block) {
8136 WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
8137 dev->name, _net_info->pm_block));
8138 pm = PM_OFF;
8139 }
8140 if (enabled && dhd_conf_get_pm(dhd) >= 0)
8141 pm = dhd_conf_get_pm(dhd);
8142 pm = htod32(pm);
8143 WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
8144 #ifdef RTT_SUPPORT
8145 rtt_status = GET_RTTSTATE(dhd);
8146 if (rtt_status->status != RTT_ENABLED) {
8147 #endif /* RTT_SUPPORT */
8148 err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
8149 if (unlikely(err)) {
8150 if (err == -ENODEV)
8151 WL_DBG(("net_device is not ready yet\n"));
8152 else
8153 WL_ERR(("error (%d)\n", err));
8154 return err;
8155 }
8156 #ifdef RTT_SUPPORT
8157 }
8158 #endif /* RTT_SUPPORT */
8159 wl_cfg80211_update_power_mode(dev);
8160 return err;
8161 }
8162
wl_cfg80211_update_power_mode(struct net_device * dev)8163 void wl_cfg80211_update_power_mode(struct net_device *dev)
8164 {
8165 int err, pm = -1;
8166
8167 err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
8168 if (err)
8169 WL_ERR(("error (%d)\n", err));
8170 else if (pm != -1 && dev->ieee80211_ptr)
8171 dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
8172 }
8173
wl_find_msb(u16 bit16)8174 static __used u32 wl_find_msb(u16 bit16)
8175 {
8176 u32 ret = 0;
8177
8178 if (bit16 & 0xff00) {
8179 ret += 8;
8180 bit16 >>= 8;
8181 }
8182
8183 if (bit16 & 0xf0) {
8184 ret += 4;
8185 bit16 >>= 4;
8186 }
8187
8188 if (bit16 & 0xc) {
8189 ret += 2;
8190 bit16 >>= 2;
8191 }
8192
8193 if (bit16 & 2)
8194 ret += bit16 & 2;
8195 else if (bit16)
8196 ret += bit16;
8197
8198 return ret;
8199 }
8200
wl_cfg80211_resume(struct wiphy * wiphy)8201 static s32 wl_cfg80211_resume(struct wiphy *wiphy)
8202 {
8203 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8204 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8205 s32 err = BCME_OK;
8206
8207 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8208 WL_INFORM_MEM(("device is not ready\n"));
8209 return err;
8210 }
8211
8212 return err;
8213 }
8214
8215 static s32
8216 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
wl_cfg80211_suspend(struct wiphy * wiphy,struct cfg80211_wowlan * wow)8217 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
8218 #else
8219 wl_cfg80211_suspend(struct wiphy *wiphy)
8220 #endif // endif
8221 {
8222 s32 err = BCME_OK;
8223 #ifdef DHD_CLEAR_ON_SUSPEND
8224 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8225 struct net_info *iter, *next;
8226 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8227 unsigned long flags;
8228
8229 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8230 WL_INFORM_MEM(("device is not ready : status (%d)\n",
8231 (int)cfg->status));
8232 return err;
8233 }
8234 for_each_ndev(cfg, iter, next) {
8235 /* p2p discovery iface doesn't have a ndev associated with it (for kernel > 3.8) */
8236 if (iter->ndev)
8237 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8238 }
8239 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
8240 if (cfg->scan_request) {
8241 wl_notify_scan_done(cfg, true);
8242 cfg->scan_request = NULL;
8243 }
8244 for_each_ndev(cfg, iter, next) {
8245 if (iter->ndev) {
8246 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
8247 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8248 }
8249 }
8250 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
8251 for_each_ndev(cfg, iter, next) {
8252 if (iter->ndev) {
8253 if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
8254 wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false);
8255 }
8256 }
8257 }
8258 #endif /* DHD_CLEAR_ON_SUSPEND */
8259
8260 return err;
8261 }
8262
8263 static s32
wl_update_pmklist(struct net_device * dev,struct wl_pmk_list * pmk_list,s32 err)8264 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
8265 s32 err)
8266 {
8267 int i, j;
8268 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8269 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
8270 int npmkids = cfg->pmk_list->pmkids.count;
8271
8272 ASSERT(cfg->pmk_list->pmkids.length >= (sizeof(u16)*2));
8273 if (!pmk_list) {
8274 WL_ERR(("pmk_list is NULL\n"));
8275 return -EINVAL;
8276 }
8277 /* pmk list is supported only for STA interface i.e. primary interface
8278 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
8279 */
8280 if (primary_dev != dev) {
8281 WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
8282 " interfaces than primary interface\n"));
8283 return err;
8284 }
8285
8286 WL_DBG(("No of elements %d\n", npmkids));
8287 for (i = 0; i < npmkids; i++) {
8288 WL_DBG(("PMKID[%d]: %pM =\n", i,
8289 &pmk_list->pmkids.pmkid[i].bssid));
8290 for (j = 0; j < WPA2_PMKID_LEN; j++) {
8291 WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].pmkid[j]));
8292 }
8293 }
8294 if (cfg->wlc_ver.wlc_ver_major >= MIN_PMKID_LIST_V3_FW_MAJOR) {
8295 pmk_list->pmkids.version = PMKID_LIST_VER_3;
8296 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8297 sizeof(*pmk_list), cfg->ioctl_buf,
8298 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8299 }
8300 else if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V2_FW_MAJOR) {
8301 u32 v2_list_size = (u32)(sizeof(pmkid_list_v2_t) + npmkids*sizeof(pmkid_v2_t));
8302 pmkid_list_v2_t *pmkid_v2_list = (pmkid_list_v2_t *)MALLOCZ(cfg->osh, v2_list_size);
8303
8304 if (pmkid_v2_list == NULL) {
8305 WL_ERR(("failed to allocate pmkid list\n"));
8306 return BCME_NOMEM;
8307 }
8308
8309 pmkid_v2_list->version = PMKID_LIST_VER_2;
8310 /* Account for version, length and pmkid_v2_t fields */
8311 pmkid_v2_list->length = (npmkids * sizeof(pmkid_v2_t)) + (2 * sizeof(u16));
8312
8313 for (i = 0; i < npmkids; i++) {
8314 /* memcpy_s return checks not needed as buffers are of same size */
8315 (void)memcpy_s(&pmkid_v2_list->pmkid[i].BSSID,
8316 ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8317 ETHER_ADDR_LEN);
8318
8319 /* copy pmkid if available */
8320 if (pmk_list->pmkids.pmkid[i].pmkid_len) {
8321 (void)memcpy_s(pmkid_v2_list->pmkid[i].PMKID,
8322 WPA2_PMKID_LEN,
8323 pmk_list->pmkids.pmkid[i].pmkid,
8324 pmk_list->pmkids.pmkid[i].pmkid_len);
8325 }
8326
8327 if (pmk_list->pmkids.pmkid[i].pmk_len) {
8328 (void)memcpy_s(pmkid_v2_list->pmkid[i].pmk,
8329 pmk_list->pmkids.pmkid[i].pmk_len,
8330 pmk_list->pmkids.pmkid[i].pmk,
8331 pmk_list->pmkids.pmkid[i].pmk_len);
8332 pmkid_v2_list->pmkid[i].pmk_len = pmk_list->pmkids.pmkid[i].pmk_len;
8333 }
8334
8335 if (pmk_list->pmkids.pmkid[i].ssid_len) {
8336 (void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
8337 pmk_list->pmkids.pmkid[i].ssid_len,
8338 pmk_list->pmkids.pmkid[i].ssid,
8339 pmk_list->pmkids.pmkid[i].ssid_len);
8340 pmkid_v2_list->pmkid[i].ssid.ssid_len
8341 = pmk_list->pmkids.pmkid[i].ssid_len;
8342 }
8343
8344 (void)memcpy_s(pmkid_v2_list->pmkid[i].fils_cache_id,
8345 FILS_CACHE_ID_LEN, &pmk_list->pmkids.pmkid[i].fils_cache_id,
8346 FILS_CACHE_ID_LEN);
8347 pmkid_v2_list->pmkid[i].length = PMKID_ELEM_V2_LENGTH;
8348 }
8349 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v2_list,
8350 v2_list_size, cfg->ioctl_buf,
8351 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8352 if (unlikely(err)) {
8353 WL_ERR(("pmkid_info failed (%d)\n", err));
8354 }
8355
8356 MFREE(cfg->osh, pmkid_v2_list, v2_list_size);
8357 }
8358 else {
8359 u32 v1_list_size = (u32)(sizeof(pmkid_list_v1_t) + npmkids*sizeof(pmkid_v1_t));
8360 pmkid_list_v1_t *pmkid_v1_list = (pmkid_list_v1_t *)MALLOCZ(cfg->osh, v1_list_size);
8361 if (pmkid_v1_list == NULL) {
8362 WL_ERR(("failed to allocate pmkid list\n"));
8363 return BCME_NOMEM;
8364 }
8365 for (i = 0; i < npmkids; i++) {
8366 /* memcpy_s return checks not needed as buffers are of same size */
8367 (void)memcpy_s(&pmkid_v1_list->pmkid[i].BSSID,
8368 ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8369 ETHER_ADDR_LEN);
8370 (void)memcpy_s(pmkid_v1_list->pmkid[i].PMKID,
8371 WPA2_PMKID_LEN, pmk_list->pmkids.pmkid[i].pmkid,
8372 WPA2_PMKID_LEN);
8373 pmkid_v1_list->npmkid++;
8374 }
8375 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v1_list,
8376 v1_list_size, cfg->ioctl_buf,
8377 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8378 if (unlikely(err)) {
8379 WL_ERR(("pmkid_info failed (%d)\n", err));
8380 }
8381
8382 MFREE(cfg->osh, pmkid_v1_list, v1_list_size);
8383 }
8384 return err;
8385 }
8386
8387 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8388 * entry operation.
8389 */
8390 static s32
wl_cfg80211_set_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8391 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
8392 struct cfg80211_pmksa *pmksa)
8393 {
8394 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8395 s32 err = 0;
8396 int i;
8397 int npmkids = cfg->pmk_list->pmkids.count;
8398 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
8399
8400 RETURN_EIO_IF_NOT_UP(cfg);
8401 BCM_REFERENCE(dhdp);
8402 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_PMKSA), dhd_net2idx(dhdp->info, dev), 0);
8403
8404 for (i = 0; i < npmkids; i++) {
8405 if (pmksa->bssid != NULL) {
8406 if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8407 ETHER_ADDR_LEN))
8408 break;
8409 }
8410 #ifdef WL_FILS
8411 else if (pmksa->ssid != NULL) {
8412 if (!memcmp(pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8413 pmksa->ssid_len))
8414 break;
8415 }
8416 #endif /* WL_FILS */
8417 }
8418 if (i < WL_NUM_PMKIDS_MAX) {
8419 if (pmksa->bssid != NULL) {
8420 memcpy(&cfg->pmk_list->pmkids.pmkid[i].bssid, pmksa->bssid,
8421 ETHER_ADDR_LEN);
8422 }
8423 #ifdef WL_FILS
8424 else if (pmksa->ssid != NULL) {
8425 cfg->pmk_list->pmkids.pmkid[i].ssid_len = pmksa->ssid_len;
8426 memcpy(&cfg->pmk_list->pmkids.pmkid[i].ssid, pmksa->ssid,
8427 pmksa->ssid_len);
8428 memcpy(&cfg->pmk_list->pmkids.pmkid[i].fils_cache_id, pmksa->cache_id,
8429 FILS_CACHE_ID_LEN);
8430 }
8431 #endif /* WL_FILS */
8432 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS))
8433 if (pmksa->pmk_len) {
8434 if (memcpy_s(&cfg->pmk_list->pmkids.pmkid[i].pmk, PMK_LEN_MAX, pmksa->pmk,
8435 pmksa->pmk_len)) {
8436 WL_ERR(("invalid pmk len = %zu", pmksa->pmk_len));
8437 } else {
8438 cfg->pmk_list->pmkids.pmkid[i].pmk_len = pmksa->pmk_len;
8439 }
8440 }
8441 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS) */
8442 /* return check not required as buffer lengths are same */
8443 (void)memcpy_s(cfg->pmk_list->pmkids.pmkid[i].pmkid, WPA2_PMKID_LEN, pmksa->pmkid,
8444 WPA2_PMKID_LEN);
8445 cfg->pmk_list->pmkids.pmkid[i].pmkid_len = WPA2_PMKID_LEN;
8446
8447 /* set lifetime not to expire in firmware by default.
8448 * Currently, wpa_supplicant control PMKID lifetime on his end. e.g) set 12 hours
8449 * when it expired, wpa_supplicant should call set_pmksa/del_pmksa to update
8450 * corresponding entry.
8451 */
8452 cfg->pmk_list->pmkids.pmkid[i].time_left = KEY_PERM_PMK;
8453 if (i == npmkids) {
8454 cfg->pmk_list->pmkids.length += sizeof(pmkid_v3_t);
8455 cfg->pmk_list->pmkids.count++;
8456 }
8457 } else {
8458 err = -EINVAL;
8459 }
8460
8461 #if (WL_DBG_LEVEL > 0)
8462 if (pmksa->bssid != NULL) {
8463 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
8464 &cfg->pmk_list->pmkids.pmkid[npmkids - 1].bssid));
8465 }
8466 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8467 WL_DBG(("%02x\n",
8468 cfg->pmk_list->pmkids.pmkid[npmkids - 1].
8469 pmkid[i]));
8470 }
8471 #endif /* (WL_DBG_LEVEL > 0) */
8472
8473 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8474
8475 return err;
8476 }
8477
8478 /* sending pmkid_info IOVAR to manipulate PMKID(PMKSA) list in firmware.
8479 * input @pmksa: host given single pmksa info.
8480 * if it's NULL, assume whole list manipulated. e.g) flush all PMKIDs in firmware.
8481 * input @set: TRUE means adding PMKSA operation. FALSE means deleting.
8482 * return: log internal BCME_XXX error, and convert it to -EINVAL to linux generic error code.
8483 */
wl_cfg80211_update_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa,bool set)8484 static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
8485 struct cfg80211_pmksa *pmksa, bool set) {
8486
8487 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8488 s32 err = 0;
8489 pmkid_list_v3_t *pmk_list;
8490 uint32 alloc_len;
8491
8492 RETURN_EIO_IF_NOT_UP(cfg);
8493
8494 if (cfg->wlc_ver.wlc_ver_major < MIN_PMKID_LIST_V3_FW_MAJOR) {
8495 WL_ERR(("wlc_ver_major not supported:%d\n", cfg->wlc_ver.wlc_ver_major));
8496 return BCME_VERSION;
8497 }
8498
8499 alloc_len = (uint32) OFFSETOF(pmkid_list_v3_t, pmkid) + ((pmksa) ? sizeof(pmkid_v3_t) : 0);
8500 pmk_list = (pmkid_list_v3_t *)MALLOCZ(cfg->osh, alloc_len);
8501
8502 if (pmk_list == NULL) {
8503 return BCME_NOMEM;
8504 }
8505
8506 pmk_list->version = PMKID_LIST_VER_3;
8507 pmk_list->length = alloc_len;
8508 pmk_list->count = (pmksa) ? 1 : 0; // 1 means single entry operation, 0 means whole list.
8509
8510 /* controll set/del action by lifetime parameter accordingly.
8511 * if set == TRUE, it's set PMKID action with lifetime permanent.
8512 * if set == FALSE, it's del PMKID action with lifetime zero.
8513 */
8514 pmk_list->pmkid->time_left = (set) ? KEY_PERM_PMK : 0;
8515
8516 if (pmksa) {
8517 if (pmksa->bssid) {
8518 err = memcpy_s(&pmk_list->pmkid->bssid, sizeof(pmk_list->pmkid->bssid),
8519 pmksa->bssid, ETHER_ADDR_LEN);
8520 if (err) {
8521 goto exit;
8522 }
8523 }
8524 if (pmksa->pmkid) {
8525 err = memcpy_s(&pmk_list->pmkid->pmkid, sizeof(pmk_list->pmkid->pmkid),
8526 pmksa->pmkid, WPA2_PMKID_LEN);
8527 if (err) {
8528 goto exit;
8529 }
8530 }
8531 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
8532 if (pmksa->pmk) {
8533 err = memcpy_s(&pmk_list->pmkid->pmk, sizeof(pmk_list->pmkid->pmk),
8534 pmksa->pmk, pmksa->pmk_len);
8535 if (err) {
8536 goto exit;
8537 }
8538 pmk_list->pmkid->pmk_len = pmksa->pmk_len;
8539 }
8540 if (pmksa->ssid) {
8541 err = memcpy_s(&pmk_list->pmkid->ssid, sizeof(pmk_list->pmkid->ssid),
8542 pmksa->ssid, pmksa->ssid_len);
8543 if (err) {
8544 goto exit;
8545 }
8546 pmk_list->pmkid->ssid_len = pmksa->ssid_len;
8547 }
8548 if (pmksa->cache_id) {
8549 pmk_list->pmkid->fils_cache_id = *(uint16 *)pmksa->cache_id;
8550 }
8551 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
8552 }
8553 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8554 alloc_len, cfg->ioctl_buf,
8555 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8556
8557 exit:
8558 if (pmk_list) {
8559 MFREE(cfg->osh, pmk_list, alloc_len);
8560 }
8561 return err;
8562 }
8563
8564 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8565 * entry operation.
8566 */
8567 static s32
wl_cfg80211_del_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8568 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
8569 struct cfg80211_pmksa *pmksa)
8570 {
8571 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8572 s32 err = 0;
8573 int i;
8574 int npmkids = cfg->pmk_list->pmkids.count;
8575 RETURN_EIO_IF_NOT_UP(cfg);
8576
8577 if (!pmksa) {
8578 WL_ERR(("pmksa is not initialized\n"));
8579 return BCME_ERROR;
8580 }
8581 if (!npmkids) {
8582 /* nmpkids = 0, nothing to delete */
8583 WL_DBG(("npmkids=0. Skip del\n"));
8584 return BCME_OK;
8585 }
8586
8587 #if (WL_DBG_LEVEL > 0)
8588 if (pmksa->bssid) {
8589 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
8590 pmksa->bssid));
8591 }
8592 #ifdef WL_FILS
8593 else if (pmksa->ssid) {
8594 WL_DBG(("FILS: del_pmksa for ssid: "));
8595 for (i = 0; i < pmksa->ssid_len; i++) {
8596 WL_DBG(("%c", pmksa->ssid[i]));
8597 }
8598 WL_DBG(("\n"));
8599 }
8600 #endif /* WL_FILS */
8601 if (pmksa->pmkid) {
8602 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8603 WL_DBG(("%02x\n", pmksa->pmkid[i]));
8604 }
8605 }
8606 #endif /* (WL_DBG_LEVEL > 0) */
8607
8608 for (i = 0; i < npmkids; i++) {
8609 if (pmksa->bssid) {
8610 if (!memcmp
8611 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8612 ETHER_ADDR_LEN)) {
8613 break;
8614 }
8615 }
8616 #ifdef WL_FILS
8617 else if (pmksa->ssid) {
8618 if (!memcmp
8619 (pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8620 pmksa->ssid_len)) {
8621 break;
8622 }
8623 }
8624 #endif /* WL_FILS */
8625 }
8626 if ((npmkids > 0) && (i < npmkids)) {
8627 bzero(&cfg->pmk_list->pmkids.pmkid[i], sizeof(pmkid_v3_t));
8628 for (; i < (npmkids - 1); i++) {
8629 (void)memcpy_s(&cfg->pmk_list->pmkids.pmkid[i],
8630 sizeof(pmkid_v3_t),
8631 &cfg->pmk_list->pmkids.pmkid[i + 1],
8632 sizeof(pmkid_v3_t));
8633 }
8634 npmkids--;
8635 cfg->pmk_list->pmkids.length -= sizeof(pmkid_v3_t);
8636 cfg->pmk_list->pmkids.count--;
8637
8638 } else {
8639 err = -EINVAL;
8640 }
8641
8642 /* current wl_update_pmklist() doesn't delete corresponding PMKID entry.
8643 * inside firmware. So we need to issue delete action explicitely through
8644 * this function.
8645 */
8646 err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
8647 /* intentional fall through even on error.
8648 * it should work above MIN_PMKID_LIST_V3_FW_MAJOR, otherwise let ignore it.
8649 */
8650
8651 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8652
8653 return err;
8654
8655 }
8656
8657 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8658 * entry operation.
8659 */
8660 static s32
wl_cfg80211_flush_pmksa(struct wiphy * wiphy,struct net_device * dev)8661 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
8662 {
8663 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8664 s32 err = 0;
8665 RETURN_EIO_IF_NOT_UP(cfg);
8666 bzero(cfg->pmk_list, sizeof(*cfg->pmk_list));
8667 cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
8668 cfg->pmk_list->pmkids.count = 0;
8669 cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
8670 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8671 return err;
8672 }
8673
8674 static s32
wl_cfg80211_remain_on_channel(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,struct ieee80211_channel * channel,enum nl80211_channel_type channel_type,unsigned int duration,u64 * cookie)8675 wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
8676 struct ieee80211_channel *channel,
8677 #if !defined(WL_CFG80211_P2P_DEV_IF)
8678 enum nl80211_channel_type channel_type,
8679 #endif /* WL_CFG80211_P2P_DEV_IF */
8680 unsigned int duration, u64 *cookie)
8681 {
8682 s32 target_channel;
8683 u32 id;
8684 s32 err = BCME_OK;
8685 struct ether_addr primary_mac;
8686 struct net_device *ndev = NULL;
8687 #ifdef CONFIG_AP6XXX_WIFI6_HDF
8688 NetDevice *netdev = NULL;
8689 int ret = 0;
8690 #endif
8691 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8692
8693 RETURN_EIO_IF_NOT_UP(cfg);
8694 #ifdef DHD_IFDEBUG
8695 PRINT_WDEV_INFO(cfgdev);
8696 #endif /* DHD_IFDEBUG */
8697
8698 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
8699
8700 mutex_lock(&cfg->usr_sync);
8701 WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
8702 ieee80211_frequency_to_channel(channel->center_freq),
8703 duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO"));
8704
8705 if (!cfg->p2p) {
8706 WL_ERR(("cfg->p2p is not initialized\n"));
8707 err = BCME_ERROR;
8708 goto exit;
8709 }
8710
8711 #ifdef P2P_LISTEN_OFFLOADING
8712 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8713 WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
8714 err = -EAGAIN;
8715 goto exit;
8716 }
8717 #endif /* P2P_LISTEN_OFFLOADING */
8718
8719 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8720 if (wl_get_drv_status_all(cfg, SCANNING)) {
8721 wl_cfg80211_cancel_scan(cfg);
8722 }
8723 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8724
8725 target_channel = ieee80211_frequency_to_channel(channel->center_freq);
8726 memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel));
8727 #if defined(WL_ENABLE_P2P_IF)
8728 cfg->remain_on_chan_type = channel_type;
8729 #endif /* WL_ENABLE_P2P_IF */
8730 id = ++cfg->last_roc_id;
8731 if (id == 0)
8732 id = ++cfg->last_roc_id;
8733 *cookie = id;
8734
8735 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8736 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
8737 timer_list_compat_t *_timer;
8738 WL_DBG(("scan is running. go to fake listen state\n"));
8739
8740 if (duration > LONG_LISTEN_TIME) {
8741 wl_cfg80211_scan_abort(cfg);
8742 } else {
8743 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8744
8745 if (timer_pending(&cfg->p2p->listen_timer)) {
8746 WL_DBG(("cancel current listen timer \n"));
8747 del_timer_sync(&cfg->p2p->listen_timer);
8748 }
8749
8750 _timer = &cfg->p2p->listen_timer;
8751 wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
8752
8753 INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0);
8754
8755 err = BCME_OK;
8756 goto exit;
8757 }
8758 }
8759 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8760
8761 #ifdef WL_BCNRECV
8762 /* check fakeapscan in progress then abort */
8763 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_LISTENBUSY);
8764 #endif /* WL_BCNRECV */
8765 #ifdef WL_CFG80211_SYNC_GON
8766 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
8767 /* do not enter listen mode again if we are in listen mode already for next af.
8768 * remain on channel completion will be returned by waiting next af completion.
8769 */
8770 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8771 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8772 #else
8773 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8774 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8775 goto exit;
8776 }
8777 #endif /* WL_CFG80211_SYNC_GON */
8778 if (cfg->p2p && !cfg->p2p->on) {
8779 /* In case of p2p_listen command, supplicant send remain_on_channel
8780 * without turning on P2P
8781 */
8782 get_primary_mac(cfg, &primary_mac);
8783 #ifndef WL_P2P_USE_RANDMAC
8784 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
8785 #endif /* WL_P2P_USE_RANDMAC */
8786 p2p_on(cfg) = true;
8787 }
8788
8789 if (p2p_is_on(cfg)) {
8790 err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
8791 if (unlikely(err)) {
8792 goto exit;
8793 }
8794 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8795 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8796 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8797 err = wl_cfgp2p_discover_listen(cfg, target_channel, duration);
8798
8799 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8800 if (err == BCME_OK) {
8801 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8802 } else {
8803 /* if failed, firmware may be internal scanning state.
8804 * so other scan request shall not abort it
8805 */
8806 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8807 }
8808 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8809
8810 if (err) {
8811 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
8812 }
8813
8814 /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant
8815 * and expire timer will send a completion to the upper layer
8816 */
8817 err = BCME_OK;
8818 }
8819
8820 exit:
8821 if (err == BCME_OK) {
8822 WL_DBG(("Success\n"));
8823 #if defined(WL_CFG80211_P2P_DEV_IF)
8824 #ifdef CONFIG_AP6XXX_WIFI6_HDF
8825 netdev = get_hdf_netdev(HDF_INF_P2P0);
8826 ret = HdfWifiEventRemainOnChannel(netdev, channel->center_freq, duration);
8827 printk(KERN_INFO"call HdfWifiEventRemainOnChannel cookie=%llu, ret=%d\n", *cookie, ret);
8828 #else
8829 cfg80211_ready_on_channel(cfgdev, *cookie, channel,
8830 duration, GFP_KERNEL);
8831 #endif
8832 #else
8833 cfg80211_ready_on_channel(cfgdev, *cookie, channel,
8834 channel_type, duration, GFP_KERNEL);
8835 #endif /* WL_CFG80211_P2P_DEV_IF */
8836 } else {
8837 WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie));
8838 }
8839 mutex_unlock(&cfg->usr_sync);
8840 return err;
8841 }
8842
8843 static s32
wl_cfg80211_cancel_remain_on_channel(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u64 cookie)8844 wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
8845 bcm_struct_cfgdev *cfgdev, u64 cookie)
8846 {
8847 s32 err = 0;
8848
8849 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8850
8851 #ifdef P2PLISTEN_AP_SAMECHN
8852 struct net_device *dev;
8853 #endif /* P2PLISTEN_AP_SAMECHN */
8854
8855 RETURN_EIO_IF_NOT_UP(cfg);
8856
8857 #ifdef DHD_IFDEBUG
8858 PRINT_WDEV_INFO(cfgdev);
8859 #endif /* DHD_IFDEBUG */
8860
8861 #if defined(WL_CFG80211_P2P_DEV_IF)
8862 if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
8863 WL_DBG((" enter ) on P2P dedicated discover interface\n"));
8864 }
8865 #else
8866 WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex));
8867 #endif /* WL_CFG80211_P2P_DEV_IF */
8868
8869 #ifdef P2PLISTEN_AP_SAMECHN
8870 if (cfg && cfg->p2p_resp_apchn_status) {
8871 dev = bcmcfg_to_prmry_ndev(cfg);
8872 wl_cfg80211_set_p2p_resp_ap_chn(dev, 0);
8873 cfg->p2p_resp_apchn_status = false;
8874 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
8875 }
8876 #endif /* P2PLISTEN_AP_SAMECHN */
8877
8878 if (cfg->last_roc_id == cookie) {
8879 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
8880 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
8881 } else {
8882 WL_ERR(("wl_cfg80211_cancel_remain_on_channel: ignore, request cookie(%llu)"
8883 " is not matched. (cur : %llu)\n",
8884 cookie, cfg->last_roc_id));
8885 }
8886
8887 return err;
8888 }
8889
8890 static void
wl_cfg80211_afx_handler(struct work_struct * work)8891 wl_cfg80211_afx_handler(struct work_struct *work)
8892 {
8893 struct afx_hdl *afx_instance;
8894 struct bcm_cfg80211 *cfg;
8895 s32 ret = BCME_OK;
8896
8897 BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
8898 if (afx_instance) {
8899 cfg = wl_get_cfg(afx_instance->dev);
8900 if (cfg != NULL && cfg->afx_hdl->is_active) {
8901 if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
8902 ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
8903 (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
8904 } else {
8905 ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
8906 cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
8907 NULL);
8908 }
8909 if (unlikely(ret != BCME_OK)) {
8910 WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
8911 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
8912 complete(&cfg->act_frm_scan);
8913 }
8914 }
8915 }
8916 }
8917
8918 static s32
wl_cfg80211_af_searching_channel(struct bcm_cfg80211 * cfg,struct net_device * dev)8919 wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
8920 {
8921 u32 max_retry = WL_CHANNEL_SYNC_RETRY;
8922 bool is_p2p_gas = false;
8923
8924 if (dev == NULL)
8925 return -1;
8926
8927 WL_DBG((" enter ) \n"));
8928
8929 wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8930 cfg->afx_hdl->is_active = TRUE;
8931
8932 if (cfg->afx_hdl->pending_tx_act_frm) {
8933 wl_action_frame_t *action_frame;
8934 action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
8935 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len))
8936 is_p2p_gas = true;
8937 }
8938
8939 /* Loop to wait until we find a peer's channel or the
8940 * pending action frame tx is cancelled.
8941 */
8942 while ((cfg->afx_hdl->retry < max_retry) &&
8943 (cfg->afx_hdl->peer_chan == WL_INVALID)) {
8944 cfg->afx_hdl->is_listen = FALSE;
8945 wl_set_drv_status(cfg, SCANNING, dev);
8946 WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
8947 cfg->afx_hdl->retry));
8948 /* search peer on peer's listen channel */
8949 schedule_work(&cfg->afx_hdl->work);
8950 wait_for_completion_timeout(&cfg->act_frm_scan,
8951 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8952
8953 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8954 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8955 break;
8956
8957 if (is_p2p_gas)
8958 break;
8959
8960 if (cfg->afx_hdl->my_listen_chan) {
8961 WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
8962 cfg->afx_hdl->my_listen_chan));
8963 /* listen on my listen channel */
8964 cfg->afx_hdl->is_listen = TRUE;
8965 schedule_work(&cfg->afx_hdl->work);
8966 wait_for_completion_timeout(&cfg->act_frm_scan,
8967 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8968 }
8969 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8970 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8971 break;
8972
8973 cfg->afx_hdl->retry++;
8974
8975 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
8976 }
8977
8978 cfg->afx_hdl->is_active = FALSE;
8979
8980 wl_clr_drv_status(cfg, SCANNING, dev);
8981 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8982
8983 return (cfg->afx_hdl->peer_chan);
8984 }
8985
8986 struct p2p_config_af_params {
8987 s32 max_tx_retry; /* max tx retry count if tx no ack */
8988 #ifdef WL_CFG80211_GON_COLLISION
8989 /* drop tx go nego request if go nego collision occurs */
8990 bool drop_tx_req;
8991 #endif // endif
8992 #ifdef WL_CFG80211_SYNC_GON
8993 bool extra_listen;
8994 #endif // endif
8995 bool search_channel; /* 1: search peer's channel to send af */
8996 };
8997
8998 #ifdef WL_DISABLE_HE_P2P
8999 static s32
wl_cfg80211_he_p2p_disable(struct wiphy * wiphy,struct ether_addr peer_mac)9000 wl_cfg80211_he_p2p_disable(struct wiphy *wiphy, struct ether_addr peer_mac)
9001 {
9002 struct cfg80211_bss *bss;
9003 u8 *ie = NULL;
9004 u32 ie_len = 0;
9005 struct net_device *ndev = NULL;
9006 s32 bssidx = 0;
9007 s32 err = BCME_OK;
9008 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9009
9010 bss = CFG80211_GET_BSS(wiphy, NULL, peer_mac.octet, NULL, 0);
9011 if (!bss) {
9012 WL_ERR(("Could not find the Peer device\n"));
9013 return BCME_ERROR;
9014 } else {
9015 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
9016 #if defined(WL_CFG80211_P2P_DEV_IF)
9017 ie = (u8 *)bss->ies->data;
9018 ie_len = bss->ies->len;
9019 #else
9020 ie = bss->information_elements;
9021 ie_len = bss->len_information_elements;
9022 #endif /* WL_CFG80211_P2P_DEV_IF */
9023 GCC_DIAGNOSTIC_POP();
9024 }
9025 if (ie) {
9026 if ((bcm_parse_tlvs_dot11(ie, ie_len,
9027 EXT_MNG_HE_CAP_ID, TRUE)) == NULL) {
9028 WL_DBG(("Peer does not support HE capability\n"));
9029 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
9030 if (ndev && (bssidx =
9031 wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
9032 WL_ERR(("Find index failed\n"));
9033 err = BCME_ERROR;
9034 } else {
9035 WL_DBG(("Disabling HE for P2P\n"));
9036 err = wl_cfg80211_set_he_mode(ndev, cfg, bssidx,
9037 WL_IF_TYPE_P2P_DISC, FALSE);
9038 if (err < 0) {
9039 WL_ERR(("failed to set he features, error=%d\n", err));
9040 }
9041 }
9042 } else {
9043 WL_DBG(("Peer supports HE capability\n"));
9044 }
9045 }
9046 CFG80211_PUT_BSS(wiphy, bss);
9047
9048 return err;
9049 }
9050 #endif /* WL_DISABLE_HE_P2P */
9051
9052 static s32
wl_cfg80211_config_p2p_pub_af_tx(struct wiphy * wiphy,wl_action_frame_t * action_frame,wl_af_params_t * af_params,struct p2p_config_af_params * config_af_params)9053 wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
9054 wl_action_frame_t *action_frame, wl_af_params_t *af_params,
9055 struct p2p_config_af_params *config_af_params)
9056 {
9057 s32 err = BCME_OK;
9058 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9059 wifi_p2p_pub_act_frame_t *act_frm =
9060 (wifi_p2p_pub_act_frame_t *) (action_frame->data);
9061
9062 /* initialize default value */
9063 #ifdef WL_CFG80211_GON_COLLISION
9064 config_af_params->drop_tx_req = false;
9065 #endif // endif
9066 #ifdef WL_CFG80211_SYNC_GON
9067 config_af_params->extra_listen = true;
9068 #endif // endif
9069 config_af_params->search_channel = false;
9070 config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
9071 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
9072
9073 switch (act_frm->subtype) {
9074 case P2P_PAF_GON_REQ: {
9075 /* Disable he if peer does not support before starting GONEG */
9076 #ifdef WL_DISABLE_HE_P2P
9077 wl_cfg80211_he_p2p_disable(wiphy, action_frame->da);
9078 #endif /* WL_DISABLE_HE_P2P */
9079 WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
9080 wl_set_p2p_status(cfg, GO_NEG_PHASE);
9081
9082 config_af_params->search_channel = true;
9083 cfg->next_af_subtype = act_frm->subtype + 1;
9084
9085 /* increase dwell time to wait for RESP frame */
9086 af_params->dwell_time = WL_MED_DWELL_TIME;
9087
9088 #ifdef WL_CFG80211_GON_COLLISION
9089 config_af_params->drop_tx_req = true;
9090 #endif /* WL_CFG80211_GON_COLLISION */
9091 break;
9092 }
9093 case P2P_PAF_GON_RSP: {
9094 cfg->next_af_subtype = act_frm->subtype + 1;
9095 /* increase dwell time to wait for CONF frame */
9096 af_params->dwell_time = WL_MED_DWELL_TIME + 100;
9097 break;
9098 }
9099 case P2P_PAF_GON_CONF: {
9100 /* If we reached till GO Neg confirmation reset the filter */
9101 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
9102 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
9103
9104 /* minimize dwell time */
9105 af_params->dwell_time = WL_MIN_DWELL_TIME;
9106
9107 #ifdef WL_CFG80211_GON_COLLISION
9108 /* if go nego formation done, clear it */
9109 cfg->block_gon_req_tx_count = 0;
9110 cfg->block_gon_req_rx_count = 0;
9111 #endif /* WL_CFG80211_GON_COLLISION */
9112 #ifdef WL_CFG80211_SYNC_GON
9113 config_af_params->extra_listen = false;
9114 #endif /* WL_CFG80211_SYNC_GON */
9115 break;
9116 }
9117 case P2P_PAF_INVITE_REQ: {
9118 config_af_params->search_channel = true;
9119 cfg->next_af_subtype = act_frm->subtype + 1;
9120
9121 /* increase dwell time */
9122 af_params->dwell_time = WL_MED_DWELL_TIME;
9123 break;
9124 }
9125 case P2P_PAF_INVITE_RSP:
9126 /* minimize dwell time */
9127 af_params->dwell_time = WL_MIN_DWELL_TIME;
9128 #ifdef WL_CFG80211_SYNC_GON
9129 config_af_params->extra_listen = false;
9130 #endif /* WL_CFG80211_SYNC_GON */
9131 break;
9132 case P2P_PAF_DEVDIS_REQ: {
9133 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
9134 action_frame->len)) {
9135 config_af_params->search_channel = true;
9136 }
9137
9138 cfg->next_af_subtype = act_frm->subtype + 1;
9139 /* maximize dwell time to wait for RESP frame */
9140 af_params->dwell_time = WL_LONG_DWELL_TIME;
9141 break;
9142 }
9143 case P2P_PAF_DEVDIS_RSP:
9144 /* minimize dwell time */
9145 af_params->dwell_time = WL_MIN_DWELL_TIME;
9146 #ifdef WL_CFG80211_SYNC_GON
9147 config_af_params->extra_listen = false;
9148 #endif /* WL_CFG80211_SYNC_GON */
9149 break;
9150 case P2P_PAF_PROVDIS_REQ: {
9151 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
9152 action_frame->len)) {
9153 config_af_params->search_channel = true;
9154 }
9155
9156 cfg->next_af_subtype = act_frm->subtype + 1;
9157 /* increase dwell time to wait for RESP frame */
9158 af_params->dwell_time = WL_MED_DWELL_TIME;
9159 break;
9160 }
9161 case P2P_PAF_PROVDIS_RSP: {
9162 cfg->next_af_subtype = P2P_PAF_GON_REQ;
9163 af_params->dwell_time = WL_MED_DWELL_TIME;
9164 #ifdef WL_CFG80211_SYNC_GON
9165 config_af_params->extra_listen = false;
9166 #endif /* WL_CFG80211_SYNC_GON */
9167 break;
9168 }
9169 default:
9170 WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
9171 act_frm->subtype));
9172 err = BCME_BADARG;
9173 }
9174 return err;
9175 }
9176
9177 #ifdef WL11U
9178 static bool
wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 * cfg,wl_af_params_t * af_params,void * frame,u16 frame_len)9179 wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params,
9180 void *frame, u16 frame_len)
9181 {
9182 struct wl_scan_results *bss_list;
9183 wl_bss_info_t *bi = NULL;
9184 bool result = false;
9185 s32 i;
9186 chanspec_t chanspec;
9187
9188 /* If DFS channel is 52~148, check to block it or not */
9189 if (af_params &&
9190 (af_params->channel >= 52 && af_params->channel <= 148)) {
9191 if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
9192 bss_list = cfg->bss_list;
9193 bi = next_bss(bss_list, bi);
9194 for_each_bss(bss_list, bi, i) {
9195 chanspec = wl_chspec_driver_to_host(bi->chanspec);
9196 if (CHSPEC_IS5G(chanspec) &&
9197 ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec))
9198 == af_params->channel)) {
9199 result = true; /* do not block the action frame */
9200 break;
9201 }
9202 }
9203 }
9204 }
9205 else {
9206 result = true;
9207 }
9208
9209 WL_DBG(("result=%s", result?"true":"false"));
9210 return result;
9211 }
9212 #endif /* WL11U */
9213 static bool
wl_cfg80211_check_dwell_overflow(int32 requested_dwell,ulong dwell_jiffies)9214 wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies)
9215 {
9216 if ((requested_dwell & CUSTOM_RETRY_MASK) &&
9217 (jiffies_to_msecs(jiffies - dwell_jiffies) >
9218 (requested_dwell & ~CUSTOM_RETRY_MASK))) {
9219 WL_ERR(("Action frame TX retry time over dwell time!\n"));
9220 return true;
9221 }
9222 return false;
9223 }
9224
9225 static bool
wl_cfg80211_send_action_frame(struct wiphy * wiphy,struct net_device * dev,bcm_struct_cfgdev * cfgdev,wl_af_params_t * af_params,wl_action_frame_t * action_frame,u16 action_frame_len,s32 bssidx)9226 wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
9227 bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
9228 wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
9229 {
9230 #ifdef WL11U
9231 struct net_device *ndev = NULL;
9232 #endif /* WL11U */
9233 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9234 bool ack = false;
9235 u8 category, action;
9236 s32 tx_retry;
9237 struct p2p_config_af_params config_af_params;
9238 struct net_info *netinfo;
9239 #ifdef VSDB
9240 ulong off_chan_started_jiffies = 0;
9241 #endif // endif
9242 ulong dwell_jiffies = 0;
9243 bool dwell_overflow = false;
9244 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
9245
9246 int32 requested_dwell = af_params->dwell_time;
9247
9248 /* Add the default dwell time
9249 * Dwell time to stay off-channel to wait for a response action frame
9250 * after transmitting an GO Negotiation action frame
9251 */
9252 af_params->dwell_time = WL_DWELL_TIME;
9253
9254 #ifdef WL11U
9255 #if defined(WL_CFG80211_P2P_DEV_IF)
9256 ndev = dev;
9257 #else
9258 ndev = ndev_to_cfgdev(cfgdev);
9259 #endif /* WL_CFG80211_P2P_DEV_IF */
9260 #endif /* WL11U */
9261
9262 category = action_frame->data[DOT11_ACTION_CAT_OFF];
9263 action = action_frame->data[DOT11_ACTION_ACT_OFF];
9264
9265 /* initialize variables */
9266 tx_retry = 0;
9267 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
9268 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
9269 config_af_params.search_channel = false;
9270 #ifdef WL_CFG80211_GON_COLLISION
9271 config_af_params.drop_tx_req = false;
9272 #endif // endif
9273 #ifdef WL_CFG80211_SYNC_GON
9274 config_af_params.extra_listen = false;
9275 #endif // endif
9276
9277 /* config parameters */
9278 /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
9279 if (category == DOT11_ACTION_CAT_PUBLIC) {
9280 if ((action == P2P_PUB_AF_ACTION) &&
9281 (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
9282 /* p2p public action frame process */
9283 if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy,
9284 action_frame, af_params, &config_af_params)) {
9285 WL_DBG(("Unknown subtype.\n"));
9286 }
9287
9288 #ifdef WL_CFG80211_GON_COLLISION
9289 if (config_af_params.drop_tx_req) {
9290 if (cfg->block_gon_req_tx_count) {
9291 /* drop gon req tx action frame */
9292 WL_DBG(("Drop gon req tx action frame: count %d\n",
9293 cfg->block_gon_req_tx_count));
9294 goto exit;
9295 }
9296 }
9297 #endif /* WL_CFG80211_GON_COLLISION */
9298 } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
9299 /* service discovery process */
9300 if (action == P2PSD_ACTION_ID_GAS_IREQ ||
9301 action == P2PSD_ACTION_ID_GAS_CREQ) {
9302 /* configure service discovery query frame */
9303
9304 config_af_params.search_channel = true;
9305
9306 /* save next af suptype to cancel remained dwell time */
9307 cfg->next_af_subtype = action + 1;
9308
9309 af_params->dwell_time = WL_MED_DWELL_TIME;
9310 if (requested_dwell & CUSTOM_RETRY_MASK) {
9311 config_af_params.max_tx_retry =
9312 (requested_dwell & CUSTOM_RETRY_MASK) >> 24;
9313 af_params->dwell_time =
9314 (requested_dwell & ~CUSTOM_RETRY_MASK);
9315 WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
9316 config_af_params.max_tx_retry,
9317 af_params->dwell_time));
9318 }
9319 } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
9320 action == P2PSD_ACTION_ID_GAS_CRESP) {
9321 /* configure service discovery response frame */
9322 af_params->dwell_time = WL_MIN_DWELL_TIME;
9323 } else {
9324 WL_DBG(("Unknown action type: %d\n", action));
9325 }
9326 } else {
9327 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
9328 category, action, action_frame_len));
9329 }
9330 } else if (category == P2P_AF_CATEGORY) {
9331 /* do not configure anything. it will be sent with a default configuration */
9332 } else {
9333 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
9334 category, action));
9335 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
9336 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9337 return false;
9338 }
9339 }
9340
9341 netinfo = wl_get_netinfo_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
9342 /* validate channel and p2p ies */
9343 if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) &&
9344 netinfo && netinfo->bss.ies.probe_req_ie_len) {
9345 config_af_params.search_channel = true;
9346 } else {
9347 config_af_params.search_channel = false;
9348 }
9349 #ifdef WL11U
9350 if (ndev == bcmcfg_to_prmry_ndev(cfg))
9351 config_af_params.search_channel = false;
9352 #endif /* WL11U */
9353
9354 #ifdef VSDB
9355 /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
9356 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
9357 OSL_SLEEP(50);
9358 }
9359 #endif // endif
9360
9361 /* if scan is ongoing, abort current scan. */
9362 if (wl_get_drv_status_all(cfg, SCANNING)) {
9363 wl_cfg80211_cancel_scan(cfg);
9364 }
9365
9366 /* Abort P2P listen */
9367 if (discover_cfgdev(cfgdev, cfg)) {
9368 if (cfg->p2p_supported && cfg->p2p) {
9369 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
9370 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
9371 }
9372 }
9373
9374 #ifdef WL11U
9375 /* handling DFS channel exceptions */
9376 if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) {
9377 return false; /* the action frame was blocked */
9378 }
9379 #endif /* WL11U */
9380
9381 /* set status and destination address before sending af */
9382 if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
9383 /* set this status to cancel the remained dwell time in rx process */
9384 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9385 }
9386 wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
9387 memcpy(cfg->afx_hdl->tx_dst_addr.octet,
9388 af_params->action_frame.da.octet,
9389 sizeof(cfg->afx_hdl->tx_dst_addr.octet));
9390
9391 /* save af_params for rx process */
9392 cfg->afx_hdl->pending_tx_act_frm = af_params;
9393
9394 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
9395 WL_DBG(("Set GAS action frame config.\n"));
9396 config_af_params.search_channel = false;
9397 config_af_params.max_tx_retry = 1;
9398 }
9399
9400 /* search peer's channel */
9401 if (config_af_params.search_channel) {
9402 /* initialize afx_hdl */
9403 if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
9404 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
9405 goto exit;
9406 }
9407 cfg->afx_hdl->dev = dev;
9408 cfg->afx_hdl->retry = 0;
9409 cfg->afx_hdl->peer_chan = WL_INVALID;
9410
9411 if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
9412 WL_ERR(("couldn't find peer's channel.\n"));
9413 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
9414 af_params->channel);
9415 /* Even if we couldn't find peer channel, try to send the frame
9416 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
9417 * respond to probe request (Ideally it has to be in listen and
9418 * responsd to probe request). However if we send Go neg req, the
9419 * peer is sending GO-neg resp. So instead of giving up here, just
9420 * proceed and attempt sending out the action frame.
9421 */
9422 }
9423
9424 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
9425 /*
9426 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
9427 * but after the check of piggyback algorithm.
9428 * To take care of current piggback algo, lets abort the scan here itself.
9429 */
9430 wl_cfg80211_cancel_scan(cfg);
9431 /* Suspend P2P discovery's search-listen to prevent it from
9432 * starting a scan or changing the channel.
9433 */
9434 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9435 WL_ERR(("Can not disable discovery mode\n"));
9436 goto exit;
9437 }
9438
9439 /* update channel */
9440 if (cfg->afx_hdl->peer_chan != WL_INVALID) {
9441 af_params->channel = cfg->afx_hdl->peer_chan;
9442 WL_ERR(("Attempt tx on peer listen channel:%d ",
9443 cfg->afx_hdl->peer_chan));
9444 } else {
9445 WL_ERR(("Attempt tx with the channel provided by userspace."
9446 "Channel: %d\n", af_params->channel));
9447 }
9448 }
9449
9450 #ifdef VSDB
9451 off_chan_started_jiffies = jiffies;
9452 #endif /* VSDB */
9453
9454 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel);
9455
9456 wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
9457
9458 dwell_jiffies = jiffies;
9459 /* Now send a tx action frame */
9460 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
9461 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9462
9463 /* if failed, retry it. tx_retry_max value is configure by .... */
9464 while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry) &&
9465 !dwell_overflow) {
9466 #ifdef VSDB
9467 if (af_params->channel) {
9468 if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
9469 OFF_CHAN_TIME_THRESHOLD_MS) {
9470 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
9471 off_chan_started_jiffies = jiffies;
9472 } else
9473 OSL_SLEEP(AF_RETRY_DELAY_TIME);
9474 }
9475 #endif /* VSDB */
9476 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
9477 false : true;
9478 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9479 }
9480
9481 if (ack == false) {
9482 WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
9483 }
9484 WL_DBG(("Complete to send action frame\n"));
9485 exit:
9486 /* Clear SENDING_ACT_FRM after all sending af is done */
9487 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9488
9489 #ifdef WL_CFG80211_SYNC_GON
9490 /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
9491 * if we coundn't get the next action response frame and dongle does not keep
9492 * the dwell time, go to listen state again to get next action response frame.
9493 */
9494 if (ack && config_af_params.extra_listen &&
9495 #ifdef WL_CFG80211_GON_COLLISION
9496 !cfg->block_gon_req_tx_count &&
9497 #endif /* WL_CFG80211_GON_COLLISION */
9498 wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
9499 cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
9500 s32 extar_listen_time;
9501
9502 extar_listen_time = af_params->dwell_time -
9503 jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
9504
9505 if (extar_listen_time > 50) {
9506 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9507 WL_DBG(("Wait more time! actual af time:%d,"
9508 "calculated extar listen:%d\n",
9509 af_params->dwell_time, extar_listen_time));
9510 if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
9511 extar_listen_time + 100) == BCME_OK) {
9512 wait_for_completion_timeout(&cfg->wait_next_af,
9513 msecs_to_jiffies(extar_listen_time + 100 + 300));
9514 }
9515 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9516 }
9517 }
9518 #endif /* WL_CFG80211_SYNC_GON */
9519 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9520
9521 cfg->afx_hdl->pending_tx_act_frm = NULL;
9522
9523 if (ack) {
9524 WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
9525 cfg->afx_hdl->my_listen_chan));
9526 } else {
9527 WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
9528 cfg->afx_hdl->my_listen_chan));
9529 }
9530
9531 #ifdef WL_CFG80211_GON_COLLISION
9532 if (cfg->block_gon_req_tx_count) {
9533 cfg->block_gon_req_tx_count--;
9534 /* if ack is ture, supplicant will wait more time(100ms).
9535 * so we will return it as a success to get more time .
9536 */
9537 ack = true;
9538 }
9539 #endif /* WL_CFG80211_GON_COLLISION */
9540 return ack;
9541 }
9542
9543 #define MAX_NUM_OF_ASSOCIATED_DEV 64
9544 static s32
9545 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
wl_cfg80211_mgmt_tx(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,struct cfg80211_mgmt_tx_params * params,u64 * cookie)9546 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9547 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
9548 #else
9549 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9550 struct ieee80211_channel *channel, bool offchan,
9551 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
9552 enum nl80211_channel_type channel_type,
9553 bool channel_type_valid,
9554 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
9555 unsigned int wait, const u8* buf, size_t len,
9556 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
9557 bool no_cck,
9558 #endif // endif
9559 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
9560 bool dont_wait_for_ack,
9561 #endif // endif
9562 u64 *cookie)
9563 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9564 {
9565 wl_action_frame_t *action_frame;
9566 wl_af_params_t *af_params;
9567 scb_val_t scb_val;
9568 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9569 struct ieee80211_channel *channel = params->chan;
9570 const u8 *buf = params->buf;
9571 size_t len = params->len;
9572 #endif // endif
9573 const struct ieee80211_mgmt *mgmt;
9574 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9575 struct net_device *dev = NULL;
9576 s32 err = BCME_OK;
9577 s32 bssidx = 0;
9578 u32 id;
9579 bool ack = false;
9580 s8 eabuf[ETHER_ADDR_STR_LEN];
9581
9582 WL_DBG(("Enter \n"));
9583
9584 if (len > ACTION_FRAME_SIZE) {
9585 WL_ERR(("bad length:%zu\n", len));
9586 return BCME_BADLEN;
9587 }
9588 #ifdef DHD_IFDEBUG
9589 PRINT_WDEV_INFO(cfgdev);
9590 #endif /* DHD_IFDEBUG */
9591
9592 dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
9593
9594 if (!dev) {
9595 WL_ERR(("dev is NULL\n"));
9596 return -EINVAL;
9597 }
9598
9599 /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
9600 if (discover_cfgdev(cfgdev, cfg)) {
9601 if (!cfg->p2p_supported || !cfg->p2p) {
9602 WL_ERR(("P2P doesn't setup completed yet\n"));
9603 return -EINVAL;
9604 }
9605 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9606 }
9607 else {
9608 if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
9609 WL_ERR(("Find p2p index failed\n"));
9610 return BCME_ERROR;
9611 }
9612 }
9613
9614 WL_DBG(("TX target bssidx=%d, wdev iftype=%d, center_freq=%u\n", bssidx, cfgdev->iftype, params->chan->center_freq));
9615
9616 if (p2p_is_on(cfg)) {
9617 /* Suspend P2P discovery search-listen to prevent it from changing the
9618 * channel.
9619 */
9620 if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9621 WL_ERR(("Can not disable discovery mode\n"));
9622 return -EFAULT;
9623 }
9624 }
9625 *cookie = 0;
9626 id = cfg->send_action_id++;
9627 if (id == 0)
9628 id = cfg->send_action_id++;
9629 *cookie = id;
9630 mgmt = (const struct ieee80211_mgmt *)buf;
9631 if (ieee80211_is_mgmt(mgmt->frame_control)) {
9632 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
9633 s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
9634 s32 ie_len = len - ie_offset;
9635 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9636 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9637 }
9638 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
9639 VNDR_IE_PRBRSP_FLAG, (const u8 *)(buf + ie_offset), ie_len);
9640 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9641 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9642 HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf, len, true);
9643 #endif
9644 #if defined(P2P_IE_MISSING_FIX)
9645 if (!cfg->p2p_prb_noti) {
9646 cfg->p2p_prb_noti = true;
9647 WL_DBG(("wl_cfg80211_mgmt_tx: TX 802_1X Probe"
9648 " Response first time.\n"));
9649 }
9650 #endif // endif
9651 goto exit;
9652 } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
9653 ieee80211_is_deauth(mgmt->frame_control)) {
9654 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
9655 sizeof(struct ether_addr) + sizeof(uint)] = {0};
9656 int num_associated = 0;
9657 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9658 if (!bcmp((const uint8 *)BSSID_BROADCAST,
9659 (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
9660 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9661 err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST,
9662 assoc_maclist, sizeof(mac_buf));
9663 if (err < 0)
9664 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9665 else
9666 num_associated = assoc_maclist->count;
9667 }
9668 memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
9669 scb_val.val = mgmt->u.disassoc.reason_code;
9670 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
9671 sizeof(scb_val_t));
9672 if (err < 0)
9673 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
9674 WL_ERR(("Disconnect STA : " MACDBG " scb_val.val %d\n",
9675 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mgmt->da,
9676 eabuf)), scb_val.val));
9677
9678 if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
9679 wl_delay(400);
9680
9681 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9682 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9683 HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf, len, true);
9684 #endif
9685 goto exit;
9686
9687 } else if (ieee80211_is_action(mgmt->frame_control)) {
9688 /* Abort the dwell time of any previous off-channel
9689 * action frame that may be still in effect. Sending
9690 * off-channel action frames relies on the driver's
9691 * scan engine. If a previous off-channel action frame
9692 * tx is still in progress (including the dwell time),
9693 * then this new action frame will not be sent out.
9694 */
9695 /* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
9696 * And previous off-channel action frame must be ended before new af tx.
9697 */
9698 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9699 wl_cfg80211_cancel_scan(cfg);
9700 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9701 }
9702 #ifdef WL_CLIENT_SAE
9703 else if (ieee80211_is_auth(mgmt->frame_control)) {
9704 int err = 0;
9705 wl_assoc_mgr_cmd_t *cmd;
9706 char *ambuf = NULL;
9707 int param_len;
9708
9709 ack = true;
9710 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9711 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9712 }
9713 param_len = sizeof(wl_assoc_mgr_cmd_t) + len;
9714 ambuf = MALLOCZ(cfg->osh, param_len);
9715 if (ambuf == NULL) {
9716 WL_ERR(("unable to allocate frame\n"));
9717 return -ENOMEM;
9718 }
9719 cmd = (wl_assoc_mgr_cmd_t*)ambuf;
9720 cmd->version = WL_ASSOC_MGR_CURRENT_VERSION;
9721 cmd->length = len;
9722 cmd->cmd = WL_ASSOC_MGR_CMD_SEND_AUTH;
9723 memcpy(&cmd->params, buf, len);
9724 err = wldev_iovar_setbuf(dev, "assoc_mgr_cmd", ambuf, param_len,
9725 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
9726 if (unlikely(err)) {
9727 WL_ERR(("Failed to send auth(%d)\n", err));
9728 ack = false;
9729 }
9730 MFREE(cfg->osh, ambuf, param_len);
9731 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9732 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9733 HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf, len, ack);
9734 #endif
9735 goto exit;
9736 }
9737 #endif /* WL_CLIENT_SAE */
9738 } else {
9739 WL_ERR(("Driver only allows MGMT packet type\n"));
9740 goto exit;
9741 }
9742
9743 af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
9744
9745 if (af_params == NULL)
9746 {
9747 WL_ERR(("unable to allocate frame\n"));
9748 return -ENOMEM;
9749 }
9750
9751 action_frame = &af_params->action_frame;
9752
9753 /* Add the packet Id */
9754 action_frame->packetId = *cookie;
9755 WL_DBG(("action frame %d\n", action_frame->packetId));
9756 /* Add BSSID */
9757 memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
9758 memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
9759
9760 /* Add the length exepted for 802.11 header */
9761 action_frame->len = len - DOT11_MGMT_HDR_LEN;
9762 WL_DBG(("action_frame->len: %d\n", action_frame->len));
9763
9764 /* Add the channel */
9765 af_params->channel =
9766 ieee80211_frequency_to_channel(channel->center_freq);
9767 /* Save listen_chan for searching common channel */
9768 cfg->afx_hdl->peer_listen_chan = af_params->channel;
9769 WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
9770
9771 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9772 af_params->dwell_time = params->wait;
9773 #else
9774 af_params->dwell_time = wait;
9775 #endif // endif
9776
9777 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
9778
9779 ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params,
9780 action_frame, action_frame->len, bssidx);
9781 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9782 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9783 HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf, len, ack);
9784 #endif
9785
9786 MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
9787 exit:
9788 return err;
9789 }
9790
9791 static void
wl_cfg80211_mgmt_frame_register(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u16 frame,bool reg)9792 wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9793 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9794 u16 frame, bool reg)
9795 #else
9796 struct mgmt_frame_regs *upd)
9797 #endif
9798 {
9799
9800 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9801 WL_DBG(("frame_type: %x, reg: %d\n", frame, reg));
9802
9803 if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
9804 return;
9805 #endif
9806
9807 return;
9808 }
9809
9810 static s32
wl_cfg80211_change_bss(struct wiphy * wiphy,struct net_device * dev,struct bss_parameters * params)9811 wl_cfg80211_change_bss(struct wiphy *wiphy,
9812 struct net_device *dev,
9813 struct bss_parameters *params)
9814 {
9815 s32 err = 0;
9816 s32 ap_isolate = 0;
9817 #ifdef PCIE_FULL_DONGLE
9818 s32 ifidx = DHD_BAD_IF;
9819 #endif // endif
9820 #if defined(PCIE_FULL_DONGLE)
9821 dhd_pub_t *dhd;
9822 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9823 dhd = (dhd_pub_t *)(cfg->pub);
9824 #if defined(WL_ENABLE_P2P_IF)
9825 if (cfg->p2p_net == dev)
9826 dev = bcmcfg_to_prmry_ndev(cfg);
9827 #endif
9828 #endif // endif
9829
9830 if (params->use_cts_prot >= 0) {
9831 }
9832
9833 if (params->use_short_preamble >= 0) {
9834 }
9835
9836 if (params->use_short_slot_time >= 0) {
9837 }
9838
9839 if (params->basic_rates) {
9840 }
9841
9842 if (params->ap_isolate >= 0) {
9843 ap_isolate = params->ap_isolate;
9844 #ifdef PCIE_FULL_DONGLE
9845 ifidx = dhd_net2idx(dhd->info, dev);
9846
9847 if (ifidx != DHD_BAD_IF) {
9848 err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate);
9849 } else {
9850 WL_ERR(("Failed to set ap_isolate\n"));
9851 }
9852 #else
9853 err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
9854 if (unlikely(err))
9855 {
9856 WL_ERR(("set ap_isolate Error (%d)\n", err));
9857 }
9858 #endif /* PCIE_FULL_DONGLE */
9859 }
9860
9861 if (params->ht_opmode >= 0) {
9862 }
9863
9864 return err;
9865 }
9866
9867 static int
wl_get_bandwidth_cap(struct net_device * ndev,uint32 band,uint32 * bandwidth)9868 wl_get_bandwidth_cap(struct net_device *ndev, uint32 band, uint32 *bandwidth)
9869 {
9870 u32 bw = WL_CHANSPEC_BW_20;
9871 s32 err = BCME_OK;
9872 s32 bw_cap = 0;
9873 struct {
9874 u32 band;
9875 u32 bw_cap;
9876 } param = {0, 0};
9877 u8 ioctl_buf[WLC_IOCTL_SMLEN];
9878
9879 if (band == IEEE80211_BAND_5GHZ) {
9880 param.band = WLC_BAND_5G;
9881 err = wldev_iovar_getbuf(ndev, "bw_cap", ¶m, sizeof(param),
9882 ioctl_buf, sizeof(ioctl_buf), NULL);
9883 if (err) {
9884 if (err != BCME_UNSUPPORTED) {
9885 WL_ERR(("bw_cap failed, %d\n", err));
9886 return err;
9887 } else {
9888 err = wldev_iovar_getint(ndev, "mimo_bw_cap", &bw_cap);
9889 if (err) {
9890 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
9891 }
9892 if (bw_cap != WLC_N_BW_20ALL) {
9893 bw = WL_CHANSPEC_BW_40;
9894 }
9895 }
9896 } else {
9897 if (WL_BW_CAP_80MHZ(ioctl_buf[0])) {
9898 bw = WL_CHANSPEC_BW_80;
9899 } else if (WL_BW_CAP_40MHZ(ioctl_buf[0])) {
9900 bw = WL_CHANSPEC_BW_40;
9901 } else {
9902 bw = WL_CHANSPEC_BW_20;
9903 }
9904 }
9905 } else if (band == IEEE80211_BAND_2GHZ) {
9906 bw = WL_CHANSPEC_BW_20;
9907 }
9908
9909 *bandwidth = bw;
9910
9911 return err;
9912 }
9913
9914 static s32
wl_cfg80211_set_channel(struct wiphy * wiphy,struct net_device * dev,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type)9915 wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
9916 struct ieee80211_channel *chan,
9917 enum nl80211_channel_type channel_type)
9918 {
9919 s32 _chan;
9920 chanspec_t chspec = 0;
9921 chanspec_t fw_chspec = 0;
9922 u32 bw = WL_CHANSPEC_BW_20;
9923 s32 err = BCME_OK;
9924 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9925 #if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL) || defined(WL_EXT_IAPSTA)
9926 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
9927 #endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
9928
9929 dev = ndev_to_wlc_ndev(dev, cfg);
9930 _chan = ieee80211_frequency_to_channel(chan->center_freq);
9931 #ifdef WL_EXT_IAPSTA
9932 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
9933 wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev), WL_IF_TYPE_AP);
9934 _chan = wl_ext_iapsta_update_channel(dhd, dev, _chan);
9935 }
9936 #endif
9937 WL_MSG(dev->name, "netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
9938 dev->ifindex, channel_type, _chan);
9939
9940 #ifdef NOT_YET
9941 switch (channel_type) {
9942 case NL80211_CHAN_HT40MINUS:
9943 /* secondary channel is below the control channel */
9944 chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_UPPER);
9945 break;
9946 case NL80211_CHAN_HT40PLUS:
9947 /* secondary channel is above the control channel */
9948 chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_LOWER);
9949 break;
9950 default:
9951 chspec = CH20MHZ_CHSPEC(channel);
9952
9953 }
9954 #endif /* NOT_YET */
9955
9956 #if defined(APSTA_RESTRICTED_CHANNEL)
9957 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
9958 DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
9959 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
9960 u32 *sta_chan = (u32 *)wl_read_prof(cfg,
9961 bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN);
9962 u32 sta_band = (*sta_chan > CH_MAX_2G_CHANNEL) ?
9963 IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
9964 if (chan->band == sta_band) {
9965 /* Do not try SCC in 5GHz if channel is not CH149 */
9966 _chan = (sta_band == IEEE80211_BAND_5GHZ &&
9967 *sta_chan != DEFAULT_5G_SOFTAP_CHANNEL) ?
9968 DEFAULT_2G_SOFTAP_CHANNEL : *sta_chan;
9969 WL_ERR(("target channel will be changed to %d\n", _chan));
9970 if (_chan <= CH_MAX_2G_CHANNEL) {
9971 bw = WL_CHANSPEC_BW_20;
9972 goto set_channel;
9973 }
9974 }
9975 }
9976 #endif /* APSTA_RESTRICTED_CHANNEL */
9977
9978 err = wl_get_bandwidth_cap(dev, chan->band, &bw);
9979 if (err < 0) {
9980 WL_ERR(("Failed to get bandwidth information, err=%d\n", err));
9981 return err;
9982 }
9983
9984 set_channel:
9985 chspec = wf_channel2chspec(_chan, bw);
9986 if (wf_chspec_valid(chspec)) {
9987 fw_chspec = wl_chspec_host_to_driver(chspec);
9988 if (fw_chspec != INVCHANSPEC) {
9989 if ((err = wldev_iovar_setint(dev, "chanspec",
9990 fw_chspec)) == BCME_BADCHAN) {
9991 if (bw == WL_CHANSPEC_BW_80)
9992 goto change_bw;
9993 err = wldev_ioctl_set(dev, WLC_SET_CHANNEL,
9994 &_chan, sizeof(_chan));
9995 if (err < 0) {
9996 WL_ERR(("WLC_SET_CHANNEL error %d"
9997 "chip may not be supporting this channel\n", err));
9998 }
9999 } else if (err) {
10000 WL_ERR(("failed to set chanspec error %d\n", err));
10001 }
10002 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
10003 else {
10004 /* Disable Frameburst only for stand-alone 2GHz SoftAP */
10005 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
10006 DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
10007 (_chan <= CH_MAX_2G_CHANNEL) &&
10008 !wl_get_drv_status(cfg, CONNECTED,
10009 bcmcfg_to_prmry_ndev(cfg))) {
10010 WL_DBG(("Disabling frameburst on "
10011 "stand-alone 2GHz SoftAP\n"));
10012 wl_cfg80211_set_frameburst(cfg, FALSE);
10013 }
10014 }
10015 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
10016 } else {
10017 WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
10018 err = BCME_ERROR;
10019 }
10020 } else {
10021 change_bw:
10022 if (bw == WL_CHANSPEC_BW_80)
10023 bw = WL_CHANSPEC_BW_40;
10024 else if (bw == WL_CHANSPEC_BW_40)
10025 bw = WL_CHANSPEC_BW_20;
10026 else
10027 bw = 0;
10028 if (bw)
10029 goto set_channel;
10030 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
10031 err = BCME_ERROR;
10032 }
10033 #ifdef CUSTOM_SET_CPUCORE
10034 if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
10035 WL_DBG(("SoftAP mode do not need to set cpucore\n"));
10036 } else if (chspec & WL_CHANSPEC_BW_80) {
10037 /* SoftAp only mode do not need to set cpucore */
10038 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
10039 dev != bcmcfg_to_prmry_ndev(cfg)) {
10040 /* Soft AP on virtual Iface (AP+STA case) */
10041 dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
10042 dhd_set_cpucore(dhd, TRUE);
10043 } else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
10044 /* If P2P IF is vht80 */
10045 dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
10046 dhd_set_cpucore(dhd, TRUE);
10047 }
10048 }
10049 #endif /* CUSTOM_SET_CPUCORE */
10050 if (!err && (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
10051 /* Update AP/GO operating channel */
10052 cfg->ap_oper_channel = ieee80211_frequency_to_channel(chan->center_freq);
10053 }
10054 if (err) {
10055 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
10056 FW_LOGSET_MASK_ALL);
10057 }
10058 return err;
10059 }
10060
10061 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
10062 struct net_device *
wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 * cfg)10063 wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
10064 {
10065 struct net_info *_net_info, *next;
10066 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
10067 list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
10068 GCC_DIAGNOSTIC_POP();
10069 if (_net_info->ndev &&
10070 test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
10071 return _net_info->ndev;
10072 }
10073
10074 return NULL;
10075 }
10076 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
10077
10078 static s32
wl_validate_opensecurity(struct net_device * dev,s32 bssidx,bool privacy)10079 wl_validate_opensecurity(struct net_device *dev, s32 bssidx, bool privacy)
10080 {
10081 s32 err = BCME_OK;
10082 u32 wpa_val;
10083 s32 wsec = 0;
10084
10085 /* set auth */
10086 err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
10087 if (err < 0) {
10088 WL_ERR(("auth error %d\n", err));
10089 return BCME_ERROR;
10090 }
10091
10092 if (privacy) {
10093 /* If privacy bit is set in open mode, then WEP would be enabled */
10094 wsec = WEP_ENABLED;
10095 WL_DBG(("Setting wsec to %d for WEP \n", wsec));
10096 }
10097
10098 /* set wsec */
10099 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10100 if (err < 0) {
10101 WL_ERR(("wsec error %d\n", err));
10102 return BCME_ERROR;
10103 }
10104
10105 /* set upper-layer auth */
10106 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC)
10107 wpa_val = WPA_AUTH_NONE;
10108 else
10109 wpa_val = WPA_AUTH_DISABLED;
10110 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_val, bssidx);
10111 if (err < 0) {
10112 WL_ERR(("wpa_auth error %d\n", err));
10113 return BCME_ERROR;
10114 }
10115
10116 return 0;
10117 }
10118
10119 #define MAX_FILS_IND_IE_LEN 1024u
10120 static s32
wl_validate_fils_ind_ie(struct net_device * dev,const bcm_tlv_t * filsindie,s32 bssidx)10121 wl_validate_fils_ind_ie(struct net_device *dev, const bcm_tlv_t *filsindie, s32 bssidx)
10122 {
10123 s32 err = BCME_OK;
10124 struct bcm_cfg80211 *cfg = NULL;
10125 bcm_iov_buf_t *iov_buf = NULL;
10126 bcm_xtlv_t* pxtlv;
10127 int iov_buf_size = 0;
10128
10129 if (!dev || !filsindie) {
10130 WL_ERR(("%s: dev/filsidie is null\n", __FUNCTION__));
10131 goto exit;
10132 }
10133
10134 cfg = wl_get_cfg(dev);
10135 if (!cfg) {
10136 WL_ERR(("%s: cfg is null\n", __FUNCTION__));
10137 goto exit;
10138 }
10139
10140 iov_buf_size = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) + filsindie->len - 1;
10141 iov_buf = MALLOCZ(cfg->osh, iov_buf_size);
10142 if (!iov_buf) {
10143 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, iov_buf_size));
10144 err = BCME_NOMEM;
10145 goto exit;
10146 }
10147 iov_buf->version = WL_FILS_IOV_VERSION;
10148 iov_buf->id = WL_FILS_CMD_ADD_IND_IE;
10149 iov_buf->len = sizeof(bcm_xtlv_t) + filsindie->len - 1;
10150 pxtlv = (bcm_xtlv_t*)&iov_buf->data[0];
10151 pxtlv->id = WL_FILS_XTLV_IND_IE;
10152 pxtlv->len = filsindie->len;
10153 /* memcpy_s return check not required as buffer is allocated based on ie
10154 * len
10155 */
10156 (void)memcpy_s(pxtlv->data, filsindie->len, filsindie->data, filsindie->len);
10157
10158 err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf_size,
10159 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
10160 if (unlikely(err)) {
10161 WL_ERR(("fils indication ioctl error (%d)\n", err));
10162 goto exit;
10163 }
10164
10165 exit:
10166 if (err < 0) {
10167 WL_ERR(("FILS Ind setting error %d\n", err));
10168 }
10169
10170 if (iov_buf) {
10171 MFREE(cfg->osh, iov_buf, iov_buf_size);
10172 }
10173 return err;
10174 }
10175
10176 static s32
wl_validate_wpa2ie(struct net_device * dev,const bcm_tlv_t * wpa2ie,s32 bssidx)10177 wl_validate_wpa2ie(struct net_device *dev, const bcm_tlv_t *wpa2ie, s32 bssidx)
10178 {
10179 s32 len = 0;
10180 s32 err = BCME_OK;
10181 u16 auth = 0; /* d11 open authentication */
10182 u32 wsec;
10183 u32 pval = 0;
10184 u32 gval = 0;
10185 u32 wpa_auth = 0;
10186 const wpa_suite_mcast_t *mcast;
10187 const wpa_suite_ucast_t *ucast;
10188 const wpa_suite_auth_key_mgmt_t *mgmt;
10189 const wpa_pmkid_list_t *pmkid;
10190 int cnt = 0;
10191 #ifdef MFP
10192 int mfp = 0;
10193 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10194 #endif /* MFP */
10195
10196 u16 suite_count;
10197 u8 rsn_cap[2];
10198 u32 wme_bss_disable;
10199
10200 if (wpa2ie == NULL)
10201 goto exit;
10202
10203 WL_DBG(("Enter \n"));
10204 len = wpa2ie->len - WPA2_VERSION_LEN;
10205 /* check the mcast cipher */
10206 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10207 switch (mcast->type) {
10208 case WPA_CIPHER_NONE:
10209 gval = 0;
10210 break;
10211 case WPA_CIPHER_WEP_40:
10212 case WPA_CIPHER_WEP_104:
10213 gval = WEP_ENABLED;
10214 break;
10215 case WPA_CIPHER_TKIP:
10216 gval = TKIP_ENABLED;
10217 break;
10218 case WPA_CIPHER_AES_CCM:
10219 gval = AES_ENABLED;
10220 break;
10221 #ifdef BCMWAPI_WPI
10222 case WAPI_CIPHER_SMS4:
10223 gval = SMS4_ENABLED;
10224 break;
10225 #endif // endif
10226 default:
10227 WL_ERR(("No Security Info\n"));
10228 break;
10229 }
10230 if ((len -= WPA_SUITE_LEN) <= 0)
10231 return BCME_BADLEN;
10232
10233 /* check the unicast cipher */
10234 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10235 suite_count = ltoh16_ua(&ucast->count);
10236 switch (ucast->list[0].type) {
10237 case WPA_CIPHER_NONE:
10238 pval = 0;
10239 break;
10240 case WPA_CIPHER_WEP_40:
10241 case WPA_CIPHER_WEP_104:
10242 pval = WEP_ENABLED;
10243 break;
10244 case WPA_CIPHER_TKIP:
10245 pval = TKIP_ENABLED;
10246 break;
10247 case WPA_CIPHER_AES_CCM:
10248 pval = AES_ENABLED;
10249 break;
10250 #ifdef BCMWAPI_WPI
10251 case WAPI_CIPHER_SMS4:
10252 pval = SMS4_ENABLED;
10253 break;
10254 #endif // endif
10255 default:
10256 WL_ERR(("No Security Info\n"));
10257 }
10258 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
10259 return BCME_BADLEN;
10260
10261 /* FOR WPS , set SEC_OW_ENABLED */
10262 wsec = (pval | gval | SES_OW_ENABLED);
10263 /* check the AKM */
10264 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
10265 suite_count = cnt = ltoh16_ua(&mgmt->count);
10266 while (cnt--) {
10267 switch (mgmt->list[cnt].type) {
10268 case RSN_AKM_NONE:
10269 wpa_auth |= WPA_AUTH_NONE;
10270 break;
10271 case RSN_AKM_UNSPECIFIED:
10272 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
10273 break;
10274 case RSN_AKM_PSK:
10275 wpa_auth |= WPA2_AUTH_PSK;
10276 break;
10277 #ifdef MFP
10278 case RSN_AKM_MFP_PSK:
10279 wpa_auth |= WPA2_AUTH_PSK_SHA256;
10280 break;
10281 case RSN_AKM_MFP_1X:
10282 wpa_auth |= WPA2_AUTH_1X_SHA256;
10283 break;
10284 case RSN_AKM_FILS_SHA256:
10285 wpa_auth |= WPA2_AUTH_FILS_SHA256;
10286 break;
10287 case RSN_AKM_FILS_SHA384:
10288 wpa_auth |= WPA2_AUTH_FILS_SHA384;
10289 break;
10290 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
10291 case RSN_AKM_SAE_PSK:
10292 wpa_auth |= WPA3_AUTH_SAE_PSK;
10293 break;
10294 #endif /* WL_SAE || WL_CLIENT_SAE */
10295 #endif /* MFP */
10296 default:
10297 WL_ERR(("No Key Mgmt Info\n"));
10298 }
10299 }
10300
10301 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
10302 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
10303 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
10304
10305 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
10306 wme_bss_disable = 0;
10307 } else {
10308 wme_bss_disable = 1;
10309 }
10310
10311 #ifdef MFP
10312 if (rsn_cap[0] & RSN_CAP_MFPR) {
10313 WL_DBG(("MFP Required \n"));
10314 mfp = WL_MFP_REQUIRED;
10315 /* Our firmware has requirement that WPA2_AUTH_PSK/WPA2_AUTH_UNSPECIFIED
10316 * be set, if SHA256 OUI is to be included in the rsn ie.
10317 */
10318 if (wpa_auth & WPA2_AUTH_PSK_SHA256) {
10319 wpa_auth |= WPA2_AUTH_PSK;
10320 } else if (wpa_auth & WPA2_AUTH_1X_SHA256) {
10321 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
10322 }
10323 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
10324 WL_DBG(("MFP Capable \n"));
10325 mfp = WL_MFP_CAPABLE;
10326 }
10327 #endif /* MFP */
10328
10329 /* set wme_bss_disable to sync RSN Capabilities */
10330 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
10331 if (err < 0) {
10332 WL_ERR(("wme_bss_disable error %d\n", err));
10333 return BCME_ERROR;
10334 }
10335 } else {
10336 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
10337 }
10338
10339 len -= RSN_CAP_LEN;
10340 if (len >= WPA2_PMKID_COUNT_LEN) {
10341 pmkid = (const wpa_pmkid_list_t *)
10342 ((const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
10343 cnt = ltoh16_ua(&pmkid->count);
10344 if (cnt != 0) {
10345 WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
10346 return BCME_ERROR;
10347 }
10348 /* since PMKID cnt is known to be 0 for AP, */
10349 /* so don't bother to send down this info to firmware */
10350 }
10351
10352 #ifdef MFP
10353 len -= WPA2_PMKID_COUNT_LEN;
10354 if (len >= WPA_SUITE_LEN) {
10355 cfg->bip_pos =
10356 (const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN;
10357 } else {
10358 cfg->bip_pos = NULL;
10359 }
10360 #endif // endif
10361
10362 /* set auth */
10363 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10364 if (err < 0) {
10365 WL_ERR(("auth error %d\n", err));
10366 return BCME_ERROR;
10367 }
10368
10369 /* set wsec */
10370 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10371 if (err < 0) {
10372 WL_ERR(("wsec error %d\n", err));
10373 return BCME_ERROR;
10374 }
10375
10376 #ifdef MFP
10377 cfg->mfp_mode = mfp;
10378 #endif /* MFP */
10379
10380 /* set upper-layer auth */
10381 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10382 if (err < 0) {
10383 WL_ERR(("wpa_auth error %d\n", err));
10384 return BCME_ERROR;
10385 }
10386 exit:
10387 return 0;
10388 }
10389
10390 static s32
wl_validate_wpaie(struct net_device * dev,const wpa_ie_fixed_t * wpaie,s32 bssidx)10391 wl_validate_wpaie(struct net_device *dev, const wpa_ie_fixed_t *wpaie, s32 bssidx)
10392 {
10393 const wpa_suite_mcast_t *mcast;
10394 const wpa_suite_ucast_t *ucast;
10395 const wpa_suite_auth_key_mgmt_t *mgmt;
10396 u16 auth = 0; /* d11 open authentication */
10397 u16 count;
10398 s32 err = BCME_OK;
10399 s32 len = 0;
10400 u32 i;
10401 u32 wsec;
10402 u32 pval = 0;
10403 u32 gval = 0;
10404 u32 wpa_auth = 0;
10405 u32 tmp = 0;
10406
10407 if (wpaie == NULL)
10408 goto exit;
10409 WL_DBG(("Enter \n"));
10410 len = wpaie->length; /* value length */
10411 len -= WPA_IE_TAG_FIXED_LEN;
10412 /* check for multicast cipher suite */
10413 if (len < WPA_SUITE_LEN) {
10414 WL_INFORM_MEM(("no multicast cipher suite\n"));
10415 goto exit;
10416 }
10417
10418 /* pick up multicast cipher */
10419 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
10420 len -= WPA_SUITE_LEN;
10421 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
10422 if (IS_WPA_CIPHER(mcast->type)) {
10423 tmp = 0;
10424 switch (mcast->type) {
10425 case WPA_CIPHER_NONE:
10426 tmp = 0;
10427 break;
10428 case WPA_CIPHER_WEP_40:
10429 case WPA_CIPHER_WEP_104:
10430 tmp = WEP_ENABLED;
10431 break;
10432 case WPA_CIPHER_TKIP:
10433 tmp = TKIP_ENABLED;
10434 break;
10435 case WPA_CIPHER_AES_CCM:
10436 tmp = AES_ENABLED;
10437 break;
10438 default:
10439 WL_ERR(("No Security Info\n"));
10440 }
10441 gval |= tmp;
10442 }
10443 }
10444 /* Check for unicast suite(s) */
10445 if (len < WPA_IE_SUITE_COUNT_LEN) {
10446 WL_INFORM_MEM(("no unicast suite\n"));
10447 goto exit;
10448 }
10449 /* walk thru unicast cipher list and pick up what we recognize */
10450 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10451 count = ltoh16_ua(&ucast->count);
10452 len -= WPA_IE_SUITE_COUNT_LEN;
10453 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10454 i++, len -= WPA_SUITE_LEN) {
10455 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10456 if (IS_WPA_CIPHER(ucast->list[i].type)) {
10457 tmp = 0;
10458 switch (ucast->list[i].type) {
10459 case WPA_CIPHER_NONE:
10460 tmp = 0;
10461 break;
10462 case WPA_CIPHER_WEP_40:
10463 case WPA_CIPHER_WEP_104:
10464 tmp = WEP_ENABLED;
10465 break;
10466 case WPA_CIPHER_TKIP:
10467 tmp = TKIP_ENABLED;
10468 break;
10469 case WPA_CIPHER_AES_CCM:
10470 tmp = AES_ENABLED;
10471 break;
10472 default:
10473 WL_ERR(("No Security Info\n"));
10474 }
10475 pval |= tmp;
10476 }
10477 }
10478 }
10479 len -= (count - i) * WPA_SUITE_LEN;
10480 /* Check for auth key management suite(s) */
10481 if (len < WPA_IE_SUITE_COUNT_LEN) {
10482 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10483 goto exit;
10484 }
10485 /* walk thru auth management suite list and pick up what we recognize */
10486 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
10487 count = ltoh16_ua(&mgmt->count);
10488 len -= WPA_IE_SUITE_COUNT_LEN;
10489 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10490 i++, len -= WPA_SUITE_LEN) {
10491 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10492 if (IS_WPA_AKM(mgmt->list[i].type)) {
10493 tmp = 0;
10494 switch (mgmt->list[i].type) {
10495 case RSN_AKM_NONE:
10496 tmp = WPA_AUTH_NONE;
10497 break;
10498 case RSN_AKM_UNSPECIFIED:
10499 tmp = WPA_AUTH_UNSPECIFIED;
10500 break;
10501 case RSN_AKM_PSK:
10502 tmp = WPA_AUTH_PSK;
10503 break;
10504 default:
10505 WL_ERR(("No Key Mgmt Info\n"));
10506 }
10507 wpa_auth |= tmp;
10508 }
10509 }
10510
10511 }
10512 /* FOR WPS , set SEC_OW_ENABLED */
10513 wsec = (pval | gval | SES_OW_ENABLED);
10514 /* set auth */
10515 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10516 if (err < 0) {
10517 WL_ERR(("auth error %d\n", err));
10518 return BCME_ERROR;
10519 }
10520 /* set wsec */
10521 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10522 if (err < 0) {
10523 WL_ERR(("wsec error %d\n", err));
10524 return BCME_ERROR;
10525 }
10526 /* set upper-layer auth */
10527 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10528 if (err < 0) {
10529 WL_ERR(("wpa_auth error %d\n", err));
10530 return BCME_ERROR;
10531 }
10532 exit:
10533 return 0;
10534 }
10535
10536 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
wl_get_cipher_type(uint8 type)10537 static u32 wl_get_cipher_type(uint8 type)
10538 {
10539 u32 ret = 0;
10540 switch (type) {
10541 case WPA_CIPHER_NONE:
10542 ret = 0;
10543 break;
10544 case WPA_CIPHER_WEP_40:
10545 case WPA_CIPHER_WEP_104:
10546 ret = WEP_ENABLED;
10547 break;
10548 case WPA_CIPHER_TKIP:
10549 ret = TKIP_ENABLED;
10550 break;
10551 case WPA_CIPHER_AES_CCM:
10552 ret = AES_ENABLED;
10553 break;
10554 #ifdef BCMWAPI_WPI
10555 case WAPI_CIPHER_SMS4:
10556 ret = SMS4_ENABLED;
10557 break;
10558 #endif // endif
10559 default:
10560 WL_ERR(("No Security Info\n"));
10561 }
10562 return ret;
10563 }
10564
wl_get_suite_auth_key_mgmt_type(uint8 type,const wpa_suite_mcast_t * mcast)10565 static u32 wl_get_suite_auth_key_mgmt_type(uint8 type, const wpa_suite_mcast_t *mcast)
10566 {
10567 u32 ret = 0;
10568 u32 is_wpa2 = 0;
10569
10570 if (!bcmp(mcast->oui, WPA2_OUI, WPA2_OUI_LEN)) {
10571 is_wpa2 = 1;
10572 }
10573
10574 WL_INFORM_MEM(("%s, type = %d\n", is_wpa2 ? "WPA2":"WPA", type));
10575 switch (type) {
10576 case RSN_AKM_NONE:
10577 /* For WPA and WPA2, AUTH_NONE is common */
10578 ret = WPA_AUTH_NONE;
10579 break;
10580 case RSN_AKM_UNSPECIFIED:
10581 if (is_wpa2) {
10582 ret = WPA2_AUTH_UNSPECIFIED;
10583 } else {
10584 ret = WPA_AUTH_UNSPECIFIED;
10585 }
10586 break;
10587 case RSN_AKM_PSK:
10588 if (is_wpa2) {
10589 ret = WPA2_AUTH_PSK;
10590 } else {
10591 ret = WPA_AUTH_PSK;
10592 }
10593 break;
10594 #ifdef WL_SAE
10595 case RSN_AKM_SAE_PSK:
10596 ret = WPA3_AUTH_SAE_PSK;
10597 break;
10598 #endif /* WL_SAE */
10599 default:
10600 WL_ERR(("No Key Mgmt Info\n"));
10601 }
10602
10603 return ret;
10604 }
10605
10606 static s32
wl_validate_wpaie_wpa2ie(struct net_device * dev,const wpa_ie_fixed_t * wpaie,const bcm_tlv_t * wpa2ie,s32 bssidx)10607 wl_validate_wpaie_wpa2ie(struct net_device *dev, const wpa_ie_fixed_t *wpaie,
10608 const bcm_tlv_t *wpa2ie, s32 bssidx)
10609 {
10610 const wpa_suite_mcast_t *mcast;
10611 const wpa_suite_ucast_t *ucast;
10612 const wpa_suite_auth_key_mgmt_t *mgmt;
10613 u16 auth = 0; /* d11 open authentication */
10614 u16 count;
10615 s32 err = BCME_OK;
10616 u32 wme_bss_disable;
10617 u16 suite_count;
10618 u8 rsn_cap[2];
10619 s32 len = 0;
10620 u32 i;
10621 u32 wsec1, wsec2, wsec;
10622 u32 pval = 0;
10623 u32 gval = 0;
10624 u32 wpa_auth = 0;
10625 u32 wpa_auth1 = 0;
10626 u32 wpa_auth2 = 0;
10627
10628 if (wpaie == NULL || wpa2ie == NULL)
10629 goto exit;
10630
10631 WL_DBG(("Enter \n"));
10632 len = wpaie->length; /* value length */
10633 len -= WPA_IE_TAG_FIXED_LEN;
10634 /* check for multicast cipher suite */
10635 if (len < WPA_SUITE_LEN) {
10636 WL_INFORM_MEM(("no multicast cipher suite\n"));
10637 goto exit;
10638 }
10639
10640 /* pick up multicast cipher */
10641 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
10642 len -= WPA_SUITE_LEN;
10643 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
10644 if (IS_WPA_CIPHER(mcast->type)) {
10645 gval |= wl_get_cipher_type(mcast->type);
10646 }
10647 }
10648 WL_DBG(("\nwpa ie validate\n"));
10649 WL_DBG(("wpa ie mcast cipher = 0x%X\n", gval));
10650
10651 /* Check for unicast suite(s) */
10652 if (len < WPA_IE_SUITE_COUNT_LEN) {
10653 WL_INFORM_MEM(("no unicast suite\n"));
10654 goto exit;
10655 }
10656
10657 /* walk thru unicast cipher list and pick up what we recognize */
10658 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10659 count = ltoh16_ua(&ucast->count);
10660 len -= WPA_IE_SUITE_COUNT_LEN;
10661 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10662 i++, len -= WPA_SUITE_LEN) {
10663 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10664 if (IS_WPA_CIPHER(ucast->list[i].type)) {
10665 pval |= wl_get_cipher_type(ucast->list[i].type);
10666 }
10667 }
10668 }
10669 WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count, pval));
10670
10671 /* FOR WPS , set SEC_OW_ENABLED */
10672 wsec1 = (pval | gval | SES_OW_ENABLED);
10673 WL_ERR(("wpa ie wsec = 0x%X\n", wsec1));
10674
10675 len -= (count - i) * WPA_SUITE_LEN;
10676 /* Check for auth key management suite(s) */
10677 if (len < WPA_IE_SUITE_COUNT_LEN) {
10678 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10679 goto exit;
10680 }
10681 /* walk thru auth management suite list and pick up what we recognize */
10682 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
10683 count = ltoh16_ua(&mgmt->count);
10684 len -= WPA_IE_SUITE_COUNT_LEN;
10685 for (i = 0; i < count && len >= WPA_SUITE_LEN;
10686 i++, len -= WPA_SUITE_LEN) {
10687 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10688 if (IS_WPA_AKM(mgmt->list[i].type)) {
10689 wpa_auth1 |=
10690 wl_get_suite_auth_key_mgmt_type(mgmt->list[i].type, mcast);
10691 }
10692 }
10693
10694 }
10695 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth1));
10696 WL_ERR(("\nwpa2 ie validate\n"));
10697
10698 pval = 0;
10699 gval = 0;
10700 len = wpa2ie->len;
10701 /* check the mcast cipher */
10702 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10703 gval = wl_get_cipher_type(mcast->type);
10704
10705 WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval));
10706 if ((len -= WPA_SUITE_LEN) <= 0)
10707 {
10708 WL_ERR(("P:wpa2 ie len[%d]", len));
10709 return BCME_BADLEN;
10710 }
10711
10712 /* check the unicast cipher */
10713 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10714 suite_count = ltoh16_ua(&ucast->count);
10715 WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count));
10716 pval |= wl_get_cipher_type(ucast->list[0].type);
10717
10718 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
10719 return BCME_BADLEN;
10720
10721 WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval));
10722
10723 /* FOR WPS , set SEC_OW_ENABLED */
10724 wsec2 = (pval | gval | SES_OW_ENABLED);
10725 WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2));
10726
10727 /* check the AKM */
10728 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
10729 suite_count = ltoh16_ua(&mgmt->count);
10730 wpa_auth2 = wl_get_suite_auth_key_mgmt_type(mgmt->list[0].type, mcast);
10731 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth2));
10732
10733 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
10734 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
10735 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
10736 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
10737 wme_bss_disable = 0;
10738 } else {
10739 wme_bss_disable = 1;
10740 }
10741 WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap[0], wme_bss_disable));
10742
10743 /* set wme_bss_disable to sync RSN Capabilities */
10744 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
10745 if (err < 0) {
10746 WL_ERR(("wme_bss_disable error %d\n", err));
10747 return BCME_ERROR;
10748 }
10749 } else {
10750 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
10751 }
10752
10753 wsec = (wsec1 | wsec2);
10754 wpa_auth = (wpa_auth1 | wpa_auth2);
10755 WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec, wpa_auth));
10756
10757 /* set auth */
10758 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10759 if (err < 0) {
10760 WL_ERR(("auth error %d\n", err));
10761 return BCME_ERROR;
10762 }
10763 /* set wsec */
10764 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10765 if (err < 0) {
10766 WL_ERR(("wsec error %d\n", err));
10767 return BCME_ERROR;
10768 }
10769 /* set upper-layer auth */
10770 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10771 if (err < 0) {
10772 WL_ERR(("wpa_auth error %d\n", err));
10773 return BCME_ERROR;
10774 }
10775 exit:
10776 return 0;
10777 }
10778 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10779
10780 static s32
wl_cfg80211_bcn_validate_sec(struct net_device * dev,struct parsed_ies * ies,u32 dev_role,s32 bssidx,bool privacy)10781 wl_cfg80211_bcn_validate_sec(
10782 struct net_device *dev,
10783 struct parsed_ies *ies,
10784 u32 dev_role,
10785 s32 bssidx,
10786 bool privacy)
10787 {
10788 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10789 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
10790
10791 if (!bss) {
10792 WL_ERR(("cfgbss is NULL \n"));
10793 return BCME_ERROR;
10794 }
10795
10796 if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
10797 /* For P2P GO, the sec type is WPA2-PSK */
10798 WL_DBG(("P2P GO: validating wpa2_ie"));
10799 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0)
10800 return BCME_ERROR;
10801
10802 } else if (dev_role == NL80211_IFTYPE_AP) {
10803
10804 WL_DBG(("SoftAP: validating security"));
10805 /* If wpa2_ie or wpa_ie is present validate it */
10806
10807 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10808 if ((ies->wpa_ie != NULL && ies->wpa2_ie != NULL)) {
10809 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie, ies->wpa2_ie, bssidx) < 0) {
10810 bss->security_mode = false;
10811 return BCME_ERROR;
10812 }
10813 }
10814 else {
10815 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10816 if ((ies->wpa2_ie || ies->wpa_ie) &&
10817 ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
10818 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
10819 bss->security_mode = false;
10820 return BCME_ERROR;
10821 }
10822
10823 if (ies->fils_ind_ie &&
10824 (wl_validate_fils_ind_ie(dev, ies->fils_ind_ie, bssidx) < 0)) {
10825 bss->security_mode = false;
10826 return BCME_ERROR;
10827 }
10828
10829 bss->security_mode = true;
10830 if (bss->rsn_ie) {
10831 MFREE(cfg->osh, bss->rsn_ie, bss->rsn_ie[1]
10832 + WPA_RSN_IE_TAG_FIXED_LEN);
10833 bss->rsn_ie = NULL;
10834 }
10835 if (bss->wpa_ie) {
10836 MFREE(cfg->osh, bss->wpa_ie, bss->wpa_ie[1]
10837 + WPA_RSN_IE_TAG_FIXED_LEN);
10838 bss->wpa_ie = NULL;
10839 }
10840 if (bss->wps_ie) {
10841 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
10842 bss->wps_ie = NULL;
10843 }
10844 if (bss->fils_ind_ie) {
10845 MFREE(cfg->osh, bss->fils_ind_ie, bss->fils_ind_ie[1]
10846 + FILS_INDICATION_IE_TAG_FIXED_LEN);
10847 bss->fils_ind_ie = NULL;
10848 }
10849 if (ies->wpa_ie != NULL) {
10850 /* WPAIE */
10851 bss->rsn_ie = NULL;
10852 bss->wpa_ie = MALLOCZ(cfg->osh,
10853 ies->wpa_ie->length
10854 + WPA_RSN_IE_TAG_FIXED_LEN);
10855 if (bss->wpa_ie) {
10856 memcpy(bss->wpa_ie, ies->wpa_ie,
10857 ies->wpa_ie->length
10858 + WPA_RSN_IE_TAG_FIXED_LEN);
10859 }
10860 } else if (ies->wpa2_ie != NULL) {
10861 /* RSNIE */
10862 bss->wpa_ie = NULL;
10863 bss->rsn_ie = MALLOCZ(cfg->osh,
10864 ies->wpa2_ie->len
10865 + WPA_RSN_IE_TAG_FIXED_LEN);
10866 if (bss->rsn_ie) {
10867 memcpy(bss->rsn_ie, ies->wpa2_ie,
10868 ies->wpa2_ie->len
10869 + WPA_RSN_IE_TAG_FIXED_LEN);
10870 }
10871 }
10872 #ifdef WL_FILS
10873 if (ies->fils_ind_ie) {
10874 bss->fils_ind_ie = MALLOCZ(cfg->osh,
10875 ies->fils_ind_ie->len
10876 + FILS_INDICATION_IE_TAG_FIXED_LEN);
10877 if (bss->fils_ind_ie) {
10878 memcpy(bss->fils_ind_ie, ies->fils_ind_ie,
10879 ies->fils_ind_ie->len
10880 + FILS_INDICATION_IE_TAG_FIXED_LEN);
10881 }
10882 }
10883 #endif /* WL_FILS */
10884 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
10885 }
10886 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10887 if (!ies->wpa2_ie && !ies->wpa_ie) {
10888 wl_validate_opensecurity(dev, bssidx, privacy);
10889 bss->security_mode = false;
10890 }
10891
10892 if (ies->wps_ie) {
10893 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
10894 if (bss->wps_ie) {
10895 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
10896 }
10897 }
10898 }
10899
10900 return 0;
10901
10902 }
10903
10904 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
wl_cfg80211_bcn_set_params(struct cfg80211_ap_settings * info,struct net_device * dev,u32 dev_role,s32 bssidx)10905 static s32 wl_cfg80211_bcn_set_params(
10906 struct cfg80211_ap_settings *info,
10907 struct net_device *dev,
10908 u32 dev_role, s32 bssidx)
10909 {
10910 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10911 s32 err = BCME_OK;
10912
10913 WL_DBG(("interval (%d) \ndtim_period (%d) \n",
10914 info->beacon_interval, info->dtim_period));
10915
10916 if (info->beacon_interval) {
10917 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
10918 &info->beacon_interval, sizeof(s32))) < 0) {
10919 WL_ERR(("Beacon Interval Set Error, %d\n", err));
10920 return err;
10921 }
10922 }
10923
10924 if (info->dtim_period) {
10925 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
10926 &info->dtim_period, sizeof(s32))) < 0) {
10927 WL_ERR(("DTIM Interval Set Error, %d\n", err));
10928 return err;
10929 }
10930 }
10931
10932 if ((info->ssid) && (info->ssid_len > 0) &&
10933 (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
10934 WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
10935 if (dev_role == NL80211_IFTYPE_AP) {
10936 /* Store the hostapd SSID */
10937 bzero(cfg->hostapd_ssid.SSID, DOT11_MAX_SSID_LEN);
10938 memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
10939 cfg->hostapd_ssid.SSID_len = (uint32)info->ssid_len;
10940 } else {
10941 /* P2P GO */
10942 bzero(cfg->p2p->ssid.SSID, DOT11_MAX_SSID_LEN);
10943 memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
10944 cfg->p2p->ssid.SSID_len = (uint32)info->ssid_len;
10945 }
10946 }
10947
10948 return err;
10949 }
10950 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
10951
10952 static s32
wl_cfg80211_parse_ies(const u8 * ptr,u32 len,struct parsed_ies * ies)10953 wl_cfg80211_parse_ies(const u8 *ptr, u32 len, struct parsed_ies *ies)
10954 {
10955 s32 err = BCME_OK;
10956
10957 bzero(ies, sizeof(struct parsed_ies));
10958
10959 /* find the WPSIE */
10960 if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
10961 WL_DBG(("WPSIE in beacon \n"));
10962 ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
10963 } else {
10964 WL_DBG(("No WPSIE in beacon \n"));
10965 }
10966
10967 /* find the RSN_IE */
10968 if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len,
10969 DOT11_MNG_RSN_ID)) != NULL) {
10970 WL_DBG((" WPA2 IE found\n"));
10971 ies->wpa2_ie_len = ies->wpa2_ie->len;
10972 }
10973
10974 /* find the FILS_IND_IE */
10975 if ((ies->fils_ind_ie = bcm_parse_tlvs(ptr, len,
10976 DOT11_MNG_FILS_IND_ID)) != NULL) {
10977 WL_DBG((" FILS IND IE found\n"));
10978 ies->fils_ind_ie_len = ies->fils_ind_ie->len;
10979 }
10980
10981 /* find the WPA_IE */
10982 if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
10983 WL_DBG((" WPA found\n"));
10984 ies->wpa_ie_len = ies->wpa_ie->length;
10985 }
10986
10987 return err;
10988
10989 }
10990
10991 static s32
wl_cfg80211_set_ap_role(struct bcm_cfg80211 * cfg,struct net_device * dev)10992 wl_cfg80211_set_ap_role(
10993 struct bcm_cfg80211 *cfg,
10994 struct net_device *dev)
10995 {
10996 s32 err = BCME_OK;
10997 s32 infra = 1;
10998 s32 ap = 0;
10999 s32 pm;
11000 s32 bssidx;
11001 s32 apsta = 0;
11002 bool new_chip;
11003
11004 new_chip = wl_new_chip_check(dev);
11005
11006 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11007 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11008 return -EINVAL;
11009 }
11010
11011 WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n", dev->name, bssidx));
11012
11013 if (bssidx != 0 || new_chip) {
11014 if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
11015 WL_IF_TYPE_AP, 0, NULL)) < 0) {
11016 WL_ERR(("wl add_del_bss returned error:%d\n", err));
11017 return err;
11018 }
11019 }
11020
11021 /*
11022 * For older chips, "bss" iovar does not support
11023 * bsscfg role change/upgradation, and still
11024 * return BCME_OK on attempt
11025 * Hence, below traditional way to handle the same
11026 */
11027
11028 if ((err = wldev_ioctl_get(dev,
11029 WLC_GET_AP, &ap, sizeof(s32))) < 0) {
11030 WL_ERR(("Getting AP mode failed %d \n", err));
11031 return err;
11032 }
11033
11034 if (!ap) {
11035 /* AP mode switch not supported. Try setting up AP explicitly */
11036 err = wldev_iovar_getint(dev, "apsta", (s32 *)&apsta);
11037 if (unlikely(err)) {
11038 WL_ERR(("Could not get apsta %d\n", err));
11039 return err;
11040 }
11041 if (apsta == 0) {
11042 /* If apsta is not set, set it */
11043
11044 /* Check for any connected interfaces before wl down */
11045 if (wl_get_drv_status_all(cfg, CONNECTED) > 0) {
11046 WL_ERR(("Concurrent i/f operational. can't do wl down"));
11047 return BCME_ERROR;
11048 }
11049 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11050 if (err < 0) {
11051 WL_ERR(("WLC_DOWN error %d\n", err));
11052 return err;
11053 }
11054 err = wldev_iovar_setint(dev, "apsta", 0);
11055 if (err < 0) {
11056 WL_ERR(("wl apsta 0 error %d\n", err));
11057 return err;
11058 }
11059 ap = 1;
11060 if ((err = wldev_ioctl_set(dev,
11061 WLC_SET_AP, &ap, sizeof(s32))) < 0) {
11062 WL_ERR(("setting AP mode failed %d \n", err));
11063 return err;
11064 }
11065 }
11066 }
11067 else if (bssidx == 0 && !new_chip && !wl_ext_iapsta_other_if_enabled(dev)) {
11068 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11069 if (err < 0) {
11070 WL_ERR(("WLC_DOWN error %d\n", err));
11071 return err;
11072 }
11073 err = wldev_iovar_setint(dev, "apsta", 0);
11074 if (err < 0) {
11075 WL_ERR(("wl apsta 0 error %d\n", err));
11076 return err;
11077 }
11078 ap = 1;
11079 if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) < 0) {
11080 WL_ERR(("setting AP mode failed %d \n", err));
11081 return err;
11082 }
11083 }
11084
11085 if (bssidx == 0) {
11086 pm = 0;
11087 if ((err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm))) != 0) {
11088 WL_ERR(("wl PM 0 returned error:%d\n", err));
11089 /* Ignore error, if any */
11090 err = BCME_OK;
11091 }
11092 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11093 if (err < 0) {
11094 WL_ERR(("SET INFRA error %d\n", err));
11095 return err;
11096 }
11097 }
11098
11099 /* On success, mark AP creation in progress. */
11100 wl_set_drv_status(cfg, AP_CREATING, dev);
11101 return 0;
11102 }
11103
11104 /* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
11105 #define MAX_AP_LINK_WAIT_TIME 10000
11106 static s32
wl_cfg80211_bcn_bringup_ap(struct net_device * dev,struct parsed_ies * ies,u32 dev_role,s32 bssidx)11107 wl_cfg80211_bcn_bringup_ap(
11108 struct net_device *dev,
11109 struct parsed_ies *ies,
11110 u32 dev_role, s32 bssidx)
11111 {
11112 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11113 struct wl_join_params join_params;
11114 bool is_bssup = false;
11115 s32 infra = 1;
11116 s32 join_params_size = 0;
11117 s32 ap = 1;
11118 s32 wsec;
11119 #ifdef DISABLE_11H_SOFTAP
11120 s32 spect = 0;
11121 #endif /* DISABLE_11H_SOFTAP */
11122 #ifdef SOFTAP_UAPSD_OFF
11123 uint32 wme_apsd = 0;
11124 #endif /* SOFTAP_UAPSD_OFF */
11125 s32 err = BCME_OK;
11126 s32 is_rsdb_supported = BCME_ERROR;
11127 long timeout;
11128 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11129 char sec[32];
11130
11131 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
11132 if (is_rsdb_supported < 0)
11133 return (-ENODEV);
11134
11135 WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role, bssidx, dev->name));
11136
11137 /* Common code for SoftAP and P2P GO */
11138 wl_clr_drv_status(cfg, AP_CREATED, dev);
11139
11140 /* Make sure INFRA is set for AP/GO */
11141 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11142 if (err < 0) {
11143 WL_ERR(("SET INFRA error %d\n", err));
11144 goto exit;
11145 }
11146
11147 /* Do abort scan before creating GO */
11148 wl_cfg80211_scan_abort(cfg);
11149
11150 if (dev_role == NL80211_IFTYPE_P2P_GO) {
11151 wl_ext_get_sec(dev, 0, sec, sizeof(sec));
11152 WL_MSG(dev->name, "Creating GO with sec=%s\n", sec);
11153 is_bssup = wl_cfg80211_bss_isup(dev, bssidx);
11154 if (!is_bssup && (ies->wpa2_ie != NULL)) {
11155
11156 err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid,
11157 sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
11158 bssidx, &cfg->ioctl_buf_sync);
11159 if (err < 0) {
11160 WL_ERR(("GO SSID setting error %d\n", err));
11161 goto exit;
11162 }
11163
11164 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
11165 WL_ERR(("GO Bring up error %d\n", err));
11166 goto exit;
11167 }
11168 } else
11169 WL_DBG(("Bss is already up\n"));
11170 } else if (dev_role == NL80211_IFTYPE_AP) {
11171
11172 // if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
11173 /* Make sure fw is in proper state */
11174 err = wl_cfg80211_set_ap_role(cfg, dev);
11175 if (unlikely(err)) {
11176 WL_ERR(("set ap role failed!\n"));
11177 goto exit;
11178 }
11179 // }
11180
11181 /* Device role SoftAP */
11182 WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
11183 /* Clear the status bit after use */
11184 wl_clr_drv_status(cfg, AP_CREATING, dev);
11185
11186 #ifdef DISABLE_11H_SOFTAP
11187 if (is_rsdb_supported == 0) {
11188 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11189 if (err < 0) {
11190 WL_ERR(("WLC_DOWN error %d\n", err));
11191 goto exit;
11192 }
11193 }
11194 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT,
11195 &spect, sizeof(s32));
11196 if (err < 0) {
11197 WL_ERR(("SET SPECT_MANAGMENT error %d\n", err));
11198 goto exit;
11199 }
11200 #endif /* DISABLE_11H_SOFTAP */
11201
11202 #ifdef WL_DISABLE_HE_SOFTAP
11203 err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, FALSE);
11204 if (err < 0) {
11205 WL_ERR(("failed to set he features, error=%d\n", err));
11206 }
11207 #endif /* WL_DISABLE_HE_SOFTAP */
11208
11209 #ifdef SOFTAP_UAPSD_OFF
11210 err = wldev_iovar_setbuf_bsscfg(dev, "wme_apsd", &wme_apsd, sizeof(wme_apsd),
11211 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11212 if (err < 0) {
11213 WL_ERR(("failed to disable uapsd, error=%d\n", err));
11214 }
11215 #endif /* SOFTAP_UAPSD_OFF */
11216
11217 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
11218 if (unlikely(err)) {
11219 WL_ERR(("WLC_UP error (%d)\n", err));
11220 goto exit;
11221 }
11222
11223 #ifdef MFP
11224 if (cfg->bip_pos) {
11225 err = wldev_iovar_setbuf_bsscfg(dev, "bip",
11226 (const void *)(cfg->bip_pos), WPA_SUITE_LEN, cfg->ioctl_buf,
11227 WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11228 if (err < 0) {
11229 WL_ERR(("bip set error %d\n", err));
11230 {
11231 goto exit;
11232 }
11233 }
11234 }
11235 #endif /* MFP */
11236
11237 err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec);
11238 if (unlikely(err)) {
11239 WL_ERR(("Could not get wsec %d\n", err));
11240 goto exit;
11241 }
11242 if (dhdp->conf->chip == BCM43430_CHIP_ID && bssidx > 0 &&
11243 (wsec & (TKIP_ENABLED|AES_ENABLED))) {
11244 wsec |= WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround
11245 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
11246 if (err < 0) {
11247 WL_ERR(("wsec error %d\n", err));
11248 goto exit;
11249 }
11250 }
11251 if ((wsec == WEP_ENABLED) && cfg->wep_key.len) {
11252 WL_DBG(("Applying buffered WEP KEY \n"));
11253 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &cfg->wep_key,
11254 sizeof(struct wl_wsec_key), cfg->ioctl_buf,
11255 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
11256 /* clear the key after use */
11257 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
11258 if (unlikely(err)) {
11259 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
11260 goto exit;
11261 }
11262 }
11263
11264 #ifdef MFP
11265 if (cfg->mfp_mode) {
11266 /* This needs to go after wsec otherwise the wsec command will
11267 * overwrite the values set by MFP
11268 */
11269 err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx);
11270 if (err < 0) {
11271 WL_ERR(("MFP Setting failed. ret = %d \n", err));
11272 /* If fw doesn't support mfp, Ignore the error */
11273 if (err != BCME_UNSUPPORTED) {
11274 goto exit;
11275 }
11276 }
11277 }
11278 #endif /* MFP */
11279
11280 bzero(&join_params, sizeof(join_params));
11281 /* join parameters starts with ssid */
11282 join_params_size = sizeof(join_params.ssid);
11283 join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
11284 (uint32)DOT11_MAX_SSID_LEN);
11285 memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
11286 join_params.ssid.SSID_len);
11287 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
11288
11289 wl_ext_get_sec(dev, 0, sec, sizeof(sec));
11290 WL_MSG(dev->name, "Creating AP with sec=%s\n", sec);
11291 /* create softap */
11292 if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
11293 join_params_size)) != 0) {
11294 WL_ERR(("SoftAP/GO set ssid failed! \n"));
11295 goto exit;
11296 } else {
11297 WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
11298 }
11299
11300 if (bssidx != 0) {
11301 /* AP on Virtual Interface */
11302 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
11303 WL_ERR(("AP Bring up error %d\n", err));
11304 goto exit;
11305 }
11306 }
11307
11308 } else {
11309 WL_ERR(("Wrong interface type %d\n", dev_role));
11310 goto exit;
11311 }
11312
11313 /* Wait for Linkup event to mark successful AP/GO bring up */
11314 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
11315 wl_get_drv_status(cfg, AP_CREATED, dev), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
11316 if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) {
11317 WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
11318 if (timeout == -ERESTARTSYS) {
11319 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
11320 err = -ERESTARTSYS;
11321 goto exit;
11322 }
11323 if (dhd_query_bus_erros(dhdp)) {
11324 err = -ENODEV;
11325 goto exit;
11326 }
11327 dhdp->iface_op_failed = TRUE;
11328 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
11329 if (dhdp->memdump_enabled) {
11330 dhdp->memdump_type = DUMP_TYPE_AP_LINKUP_FAILURE;
11331 dhd_bus_mem_dump(dhdp);
11332 }
11333 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
11334 err = -ENODEV;
11335 goto exit;
11336 }
11337 SUPP_LOG(("AP/GO Link up\n"));
11338
11339 exit:
11340 if (cfg->wep_key.len) {
11341 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
11342 }
11343
11344 #ifdef MFP
11345 if (cfg->mfp_mode) {
11346 cfg->mfp_mode = 0;
11347 }
11348
11349 if (cfg->bip_pos) {
11350 cfg->bip_pos = NULL;
11351 }
11352 #endif /* MFP */
11353
11354 if (err) {
11355 SUPP_LOG(("AP/GO bring up fail. err:%d\n", err));
11356 }
11357 return err;
11358 }
11359
11360 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11361 s32
wl_cfg80211_parse_ap_ies(struct net_device * dev,struct cfg80211_beacon_data * info,struct parsed_ies * ies)11362 wl_cfg80211_parse_ap_ies(
11363 struct net_device *dev,
11364 struct cfg80211_beacon_data *info,
11365 struct parsed_ies *ies)
11366 {
11367 struct parsed_ies prb_ies;
11368 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11369 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11370 const u8 *vndr = NULL;
11371 u32 vndr_ie_len = 0;
11372 s32 err = BCME_OK;
11373
11374 /* Parse Beacon IEs */
11375 if (wl_cfg80211_parse_ies((const u8 *)info->tail,
11376 info->tail_len, ies) < 0) {
11377 WL_ERR(("Beacon get IEs failed \n"));
11378 err = -EINVAL;
11379 goto fail;
11380 }
11381
11382 vndr = (const u8 *)info->proberesp_ies;
11383 vndr_ie_len = (uint32)info->proberesp_ies_len;
11384
11385 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
11386 /* SoftAP mode */
11387 const struct ieee80211_mgmt *mgmt;
11388 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
11389 if (mgmt != NULL) {
11390 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
11391 vndr_ie_len = (uint32)(info->probe_resp_len -
11392 offsetof(const struct ieee80211_mgmt, u.probe_resp.variable));
11393 }
11394 }
11395 /* Parse Probe Response IEs */
11396 if (wl_cfg80211_parse_ies((const u8 *)vndr, vndr_ie_len, &prb_ies) < 0) {
11397 WL_ERR(("PROBE RESP get IEs failed \n"));
11398 err = -EINVAL;
11399 }
11400 fail:
11401
11402 return err;
11403 }
11404
11405 s32
wl_cfg80211_set_ies(struct net_device * dev,struct cfg80211_beacon_data * info,s32 bssidx)11406 wl_cfg80211_set_ies(
11407 struct net_device *dev,
11408 struct cfg80211_beacon_data *info,
11409 s32 bssidx)
11410 {
11411 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11412 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11413 const u8 *vndr = NULL;
11414 u32 vndr_ie_len = 0;
11415 s32 err = BCME_OK;
11416
11417 /* Set Beacon IEs to FW */
11418 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
11419 VNDR_IE_BEACON_FLAG, (const u8 *)info->tail,
11420 info->tail_len)) < 0) {
11421 WL_ERR(("Set Beacon IE Failed \n"));
11422 } else {
11423 WL_DBG(("Applied Vndr IEs for Beacon \n"));
11424 }
11425
11426 vndr = (const u8 *)info->proberesp_ies;
11427 vndr_ie_len = (uint32)info->proberesp_ies_len;
11428
11429 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
11430 /* SoftAP mode */
11431 const struct ieee80211_mgmt *mgmt;
11432 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
11433 if (mgmt != NULL) {
11434 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
11435 vndr_ie_len = (uint32)(info->probe_resp_len -
11436 offsetof(struct ieee80211_mgmt, u.probe_resp.variable));
11437 }
11438 }
11439
11440 /* Set Probe Response IEs to FW */
11441 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
11442 VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
11443 WL_ERR(("Set Probe Resp IE Failed \n"));
11444 } else {
11445 WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
11446 }
11447
11448 return err;
11449 }
11450 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11451
wl_cfg80211_hostapd_sec(struct net_device * dev,struct parsed_ies * ies,s32 bssidx)11452 static s32 wl_cfg80211_hostapd_sec(
11453 struct net_device *dev,
11454 struct parsed_ies *ies,
11455 s32 bssidx)
11456 {
11457 bool update_bss = 0;
11458 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11459 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
11460
11461 if (!bss) {
11462 WL_ERR(("cfgbss is NULL \n"));
11463 return -EINVAL;
11464 }
11465
11466 if (ies->wps_ie) {
11467 if (bss->wps_ie &&
11468 memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
11469 WL_DBG((" WPS IE is changed\n"));
11470 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
11471 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11472 if (bss->wps_ie) {
11473 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11474 }
11475 } else if (bss->wps_ie == NULL) {
11476 WL_DBG((" WPS IE is added\n"));
11477 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11478 if (bss->wps_ie) {
11479 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11480 }
11481 }
11482
11483 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11484 if (ies->wpa_ie != NULL && ies->wpa2_ie != NULL) {
11485 WL_ERR(("update bss - wpa_ie and wpa2_ie is not null\n"));
11486 if (!bss->security_mode) {
11487 /* change from open mode to security mode */
11488 update_bss = true;
11489 bss->wpa_ie = MALLOCZ(cfg->osh,
11490 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11491 if (bss->wpa_ie) {
11492 memcpy(bss->wpa_ie, ies->wpa_ie,
11493 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11494 }
11495 bss->rsn_ie = MALLOCZ(cfg->osh,
11496 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11497 if (bss->rsn_ie) {
11498 memcpy(bss->rsn_ie, ies->wpa2_ie,
11499 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11500 }
11501 } else {
11502 /* change from (WPA or WPA2 or WPA/WPA2) to WPA/WPA2 mixed mode */
11503 if (bss->wpa_ie) {
11504 if (memcmp(bss->wpa_ie,
11505 ies->wpa_ie, ies->wpa_ie->length +
11506 WPA_RSN_IE_TAG_FIXED_LEN)) {
11507 MFREE(cfg->osh, bss->wpa_ie,
11508 bss->wpa_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11509 update_bss = true;
11510 bss->wpa_ie = MALLOCZ(cfg->osh,
11511 ies->wpa_ie->length
11512 + WPA_RSN_IE_TAG_FIXED_LEN);
11513 if (bss->wpa_ie) {
11514 memcpy(bss->wpa_ie, ies->wpa_ie,
11515 ies->wpa_ie->length
11516 + WPA_RSN_IE_TAG_FIXED_LEN);
11517 }
11518 }
11519 }
11520 else {
11521 update_bss = true;
11522 bss->wpa_ie = MALLOCZ(cfg->osh,
11523 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11524 if (bss->wpa_ie) {
11525 memcpy(bss->wpa_ie, ies->wpa_ie,
11526 ies->wpa_ie->length
11527 + WPA_RSN_IE_TAG_FIXED_LEN);
11528 }
11529 }
11530 if (bss->rsn_ie) {
11531 if (memcmp(bss->rsn_ie,
11532 ies->wpa2_ie,
11533 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
11534 update_bss = true;
11535 MFREE(cfg->osh, bss->rsn_ie,
11536 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11537 bss->rsn_ie = MALLOCZ(cfg->osh,
11538 ies->wpa2_ie->len
11539 + WPA_RSN_IE_TAG_FIXED_LEN);
11540 if (bss->rsn_ie) {
11541 memcpy(bss->rsn_ie, ies->wpa2_ie,
11542 ies->wpa2_ie->len
11543 + WPA_RSN_IE_TAG_FIXED_LEN);
11544 }
11545 }
11546 }
11547 else {
11548 update_bss = true;
11549 bss->rsn_ie = MALLOCZ(cfg->osh,
11550 ies->wpa2_ie->len
11551 + WPA_RSN_IE_TAG_FIXED_LEN);
11552 if (bss->rsn_ie) {
11553 memcpy(bss->rsn_ie, ies->wpa2_ie,
11554 ies->wpa2_ie->len
11555 + WPA_RSN_IE_TAG_FIXED_LEN);
11556 }
11557 }
11558 }
11559 WL_ERR(("update_bss=%d\n", update_bss));
11560 if (update_bss) {
11561 bss->security_mode = true;
11562 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11563 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie,
11564 ies->wpa2_ie, bssidx) < 0) {
11565 return BCME_ERROR;
11566 }
11567 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11568 }
11569
11570 }
11571 else
11572 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11573 if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
11574 if (!bss->security_mode) {
11575 /* change from open mode to security mode */
11576 update_bss = true;
11577 if (ies->wpa_ie != NULL) {
11578 bss->wpa_ie = MALLOCZ(cfg->osh,
11579 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11580 if (bss->wpa_ie) {
11581 memcpy(bss->wpa_ie,
11582 ies->wpa_ie,
11583 ies->wpa_ie->length
11584 + WPA_RSN_IE_TAG_FIXED_LEN);
11585 }
11586 } else {
11587 bss->rsn_ie = MALLOCZ(cfg->osh,
11588 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11589 if (bss->rsn_ie) {
11590 memcpy(bss->rsn_ie,
11591 ies->wpa2_ie,
11592 ies->wpa2_ie->len
11593 + WPA_RSN_IE_TAG_FIXED_LEN);
11594 }
11595 }
11596 } else if (bss->wpa_ie) {
11597 /* change from WPA2 mode to WPA mode */
11598 if (ies->wpa_ie != NULL) {
11599 update_bss = true;
11600 MFREE(cfg->osh, bss->rsn_ie,
11601 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11602 bss->rsn_ie = NULL;
11603 bss->wpa_ie = MALLOCZ(cfg->osh,
11604 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11605 if (bss->wpa_ie) {
11606 memcpy(bss->wpa_ie,
11607 ies->wpa_ie,
11608 ies->wpa_ie->length
11609 + WPA_RSN_IE_TAG_FIXED_LEN);
11610 }
11611 } else if (memcmp(bss->rsn_ie,
11612 ies->wpa2_ie, ies->wpa2_ie->len
11613 + WPA_RSN_IE_TAG_FIXED_LEN)) {
11614 update_bss = true;
11615 MFREE(cfg->osh, bss->rsn_ie,
11616 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11617 bss->rsn_ie = MALLOCZ(cfg->osh,
11618 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11619 if (bss->rsn_ie) {
11620 memcpy(bss->rsn_ie,
11621 ies->wpa2_ie,
11622 ies->wpa2_ie->len
11623 + WPA_RSN_IE_TAG_FIXED_LEN);
11624 }
11625 bss->wpa_ie = NULL;
11626 }
11627 }
11628 if (update_bss) {
11629 bss->security_mode = true;
11630 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11631 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
11632 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
11633 return BCME_ERROR;
11634 }
11635 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11636 }
11637 }
11638 } else {
11639 WL_ERR(("No WPSIE in beacon \n"));
11640 }
11641 return 0;
11642 }
11643
11644 static s32
11645 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
11646 2, 0))
11647 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
wl_cfg80211_del_station(struct wiphy * wiphy,struct net_device * ndev,struct station_del_parameters * params)11648 wl_cfg80211_del_station(
11649 struct wiphy *wiphy, struct net_device *ndev,
11650 struct station_del_parameters *params)
11651 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
11652 wl_cfg80211_del_station(
11653 struct wiphy *wiphy,
11654 struct net_device *ndev,
11655 const u8* mac_addr)
11656 #else
11657 wl_cfg80211_del_station(
11658 struct wiphy *wiphy,
11659 struct net_device *ndev,
11660 u8* mac_addr)
11661 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11662 {
11663 struct net_device *dev;
11664 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11665 scb_val_t scb_val;
11666 int err;
11667 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
11668 sizeof(struct ether_addr) + sizeof(uint)] = {0};
11669 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
11670 int num_associated = 0;
11671
11672 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11673 const u8 *mac_addr = params->mac;
11674 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11675 u16 rc = params->reason_code;
11676 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11677 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11678
11679 WL_DBG(("Entry\n"));
11680 if (mac_addr == NULL) {
11681 WL_DBG(("mac_addr is NULL ignore it\n"));
11682 return 0;
11683 }
11684
11685 dev = ndev_to_wlc_ndev(ndev, cfg);
11686
11687 if (p2p_is_on(cfg)) {
11688 /* Suspend P2P discovery search-listen to prevent it from changing the
11689 * channel.
11690 */
11691 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
11692 WL_ERR(("Can not disable discovery mode\n"));
11693 return -EFAULT;
11694 }
11695 }
11696 err = wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
11697 WL_EXT_STATUS_DELETE_STA, (void *)mac_addr);
11698 if (err) {
11699 return 0;
11700 }
11701
11702 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
11703 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
11704 assoc_maclist, sizeof(mac_buf));
11705 if (err < 0)
11706 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
11707 else
11708 num_associated = assoc_maclist->count;
11709
11710 memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
11711 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11712 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11713 if (rc == DOT11_RC_8021X_AUTH_FAIL) {
11714 WL_ERR(("deauth will be sent at F/W\n"));
11715 scb_val.val = DOT11_RC_8021X_AUTH_FAIL;
11716 } else {
11717 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11718 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11719
11720 #ifdef WL_WPS_SYNC
11721 if (wl_wps_session_update(ndev,
11722 WPS_STATE_DISCONNECT_CLIENT, mac_addr) == BCME_UNSUPPORTED) {
11723 /* Ignore disconnect command from upper layer */
11724 WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
11725 } else
11726 #endif /* WL_WPS_SYNC */
11727 {
11728 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
11729 WL_MSG(dev->name, "Disconnect STA : %pM scb_val.val %d\n",
11730 mac_addr, scb_val.val);
11731 /* need to guarantee EAP-Failure send out before deauth */
11732 dhd_wait_pend8021x(dev);
11733 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
11734 sizeof(scb_val_t));
11735 if (err < 0) {
11736 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
11737 }
11738 }
11739 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11740 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11741 }
11742 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11743 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11744
11745 if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
11746 wl_delay(400);
11747
11748 return 0;
11749 }
11750
11751 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
11752 static s32
wl_cfg80211_change_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)11753 wl_cfg80211_change_station(
11754 struct wiphy *wiphy,
11755 struct net_device *dev,
11756 const u8 *mac,
11757 struct station_parameters *params)
11758 #else
11759 static s32
11760 wl_cfg80211_change_station(
11761 struct wiphy *wiphy,
11762 struct net_device *dev,
11763 u8 *mac,
11764 struct station_parameters *params)
11765 #endif // endif
11766 {
11767 int err = BCME_OK;
11768 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11769 struct net_device *ndev = ndev_to_wlc_ndev(dev, cfg);
11770
11771 WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x "
11772 "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac),
11773 params->sta_flags_mask, params->sta_flags_set, ndev->name));
11774
11775 if ((wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS) &&
11776 !(wl_get_drv_status(cfg, CONNECTED, dev))) {
11777 /* Return error indicating not in connected state */
11778 WL_ERR(("Ignore SCB_AUTHORIZE/DEAUTHORIZE in non connected state\n"));
11779 return -ENOTSUPP;
11780 }
11781
11782 /* Processing only authorize/de-authorize flag for now */
11783 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
11784 WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
11785 return -ENOTSUPP;
11786 }
11787
11788 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
11789 err = wldev_ioctl_set(ndev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN);
11790 if (unlikely(err)) {
11791 WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
11792 } else {
11793 WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG "\n",
11794 ndev->name, MAC2STRDBG(mac)));
11795 }
11796 return err;
11797 }
11798
11799 err = wldev_ioctl_set(ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN);
11800 if (unlikely(err)) {
11801 WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
11802 } else {
11803 WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG "\n",
11804 ndev->name, MAC2STRDBG(mac)));
11805 #ifdef WL_WPS_SYNC
11806 wl_wps_session_update(ndev, WPS_STATE_AUTHORIZE, mac);
11807 #endif /* WL_WPS_SYNC */
11808 }
11809 #ifdef DHD_LOSSLESS_ROAMING
11810 wl_del_roam_timeout(cfg);
11811 #endif // endif
11812
11813 return err;
11814 }
11815 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
11816
11817 static s32
wl_cfg80211_set_scb_timings(struct bcm_cfg80211 * cfg,struct net_device * dev)11818 wl_cfg80211_set_scb_timings(
11819 struct bcm_cfg80211 *cfg,
11820 struct net_device *dev)
11821 {
11822 int err;
11823 u32 ps_pretend;
11824 wl_scb_probe_t scb_probe;
11825 u32 ps_pretend_retries;
11826
11827 bzero(&scb_probe, sizeof(wl_scb_probe_t));
11828 scb_probe.scb_timeout = WL_SCB_TIMEOUT;
11829 scb_probe.scb_activity_time = WL_SCB_ACTIVITY_TIME;
11830 scb_probe.scb_max_probe = WL_SCB_MAX_PROBE;
11831 err = wldev_iovar_setbuf(dev, "scb_probe", (void *)&scb_probe,
11832 sizeof(wl_scb_probe_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
11833 &cfg->ioctl_buf_sync);
11834 if (unlikely(err)) {
11835 WL_ERR(("set 'scb_probe' failed, error = %d\n", err));
11836 return err;
11837 }
11838
11839 ps_pretend_retries = WL_PSPRETEND_RETRY_LIMIT;
11840 err = wldev_iovar_setint(dev, "pspretend_retry_limit", ps_pretend_retries);
11841 if (unlikely(err)) {
11842 if (err == BCME_UNSUPPORTED) {
11843 /* Ignore error if fw doesn't support the iovar */
11844 WL_DBG(("set 'pspretend_retry_limit %d' failed, error = %d\n",
11845 ps_pretend_retries, err));
11846 } else {
11847 WL_ERR(("set 'pspretend_retry_limit %d' failed, error = %d\n",
11848 ps_pretend_retries, err));
11849 return err;
11850 }
11851 }
11852
11853 ps_pretend = MAX(WL_SCB_MAX_PROBE / 2, WL_MIN_PSPRETEND_THRESHOLD);
11854 err = wldev_iovar_setint(dev, "pspretend_threshold", ps_pretend);
11855 if (unlikely(err)) {
11856 if (err == BCME_UNSUPPORTED) {
11857 /* Ignore error if fw doesn't support the iovar */
11858 WL_DBG(("wl pspretend_threshold %d set error %d\n",
11859 ps_pretend, err));
11860 } else {
11861 WL_ERR(("wl pspretend_threshold %d set error %d\n",
11862 ps_pretend, err));
11863 return err;
11864 }
11865 }
11866
11867 return 0;
11868 }
11869
11870 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
11871 static s32
wl_cfg80211_start_ap(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ap_settings * info)11872 wl_cfg80211_start_ap(
11873 struct wiphy *wiphy,
11874 struct net_device *dev,
11875 struct cfg80211_ap_settings *info)
11876 {
11877 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11878 s32 err = BCME_OK;
11879 struct parsed_ies ies;
11880 s32 bssidx = 0;
11881 u32 dev_role = 0;
11882 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11883
11884 WL_DBG(("Enter \n"));
11885
11886 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11887 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11888 return BCME_ERROR;
11889 }
11890
11891 if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
11892 dev_role = NL80211_IFTYPE_P2P_GO;
11893 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
11894 dev_role = NL80211_IFTYPE_AP;
11895 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
11896 err = dhd_ndo_enable(dhd, FALSE);
11897 WL_DBG(("Disabling NDO on Hostapd mode %d\n", err));
11898 if (err) {
11899 WL_ERR(("Disabling NDO Failed %d\n", err));
11900 }
11901 #ifdef WL_EXT_IAPSTA
11902 wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev), WL_IF_TYPE_AP);
11903 #endif /* WL_EXT_IAPSTA */
11904 #ifdef PKT_FILTER_SUPPORT
11905 /* Disable packet filter */
11906 if (dhd->early_suspended) {
11907 WL_ERR(("Disable pkt_filter\n"));
11908 dhd_enable_packet_filter(0, dhd);
11909 #ifdef APF
11910 dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd));
11911 #endif /* APF */
11912 }
11913 #endif /* PKT_FILTER_SUPPORT */
11914 #ifdef ARP_OFFLOAD_SUPPORT
11915 /* IF SoftAP is enabled, disable arpoe */
11916 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
11917 dhd_arp_offload_set(dhd, 0);
11918 dhd_arp_offload_enable(dhd, FALSE);
11919 }
11920 #endif /* ARP_OFFLOAD_SUPPORT */
11921 } else {
11922 /* only AP or GO role need to be handled here. */
11923 err = -EINVAL;
11924 goto fail;
11925 }
11926
11927 /* disable TDLS */
11928 #ifdef WLTDLS
11929 if (bssidx == 0) {
11930 /* Disable TDLS for primary Iface. For virtual interface,
11931 * tdls disable will happen from interface create context
11932 */
11933 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_CREATE, false);
11934 }
11935 #endif /* WLTDLS */
11936
11937 if (!check_dev_role_integrity(cfg, dev_role)) {
11938 err = -EINVAL;
11939 goto fail;
11940 }
11941
11942 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
11943 if (!dev->ieee80211_ptr->preset_chandef.chan) {
11944 WL_ERR(("chan is NULL\n"));
11945 err = -EINVAL;
11946 goto fail;
11947 }
11948 if ((err = wl_cfg80211_set_channel(wiphy, dev,
11949 dev->ieee80211_ptr->preset_chandef.chan,
11950 NL80211_CHAN_HT20) < 0)) {
11951 WL_ERR(("Set channel failed \n"));
11952 goto fail;
11953 }
11954 #endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
11955
11956 if ((err = wl_cfg80211_bcn_set_params(info, dev,
11957 dev_role, bssidx)) < 0) {
11958 WL_ERR(("Beacon params set failed \n"));
11959 goto fail;
11960 }
11961
11962 /* Parse IEs */
11963 if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) {
11964 WL_ERR(("Set IEs failed \n"));
11965 goto fail;
11966 }
11967
11968 if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies,
11969 dev_role, bssidx, info->privacy)) < 0)
11970 {
11971 WL_ERR(("Beacon set security failed \n"));
11972 goto fail;
11973 }
11974
11975 if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies,
11976 dev_role, bssidx)) < 0) {
11977 WL_ERR(("Beacon bring up AP/GO failed \n"));
11978 goto fail;
11979 }
11980
11981 /* Set GC/STA SCB expiry timings. */
11982 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
11983 WL_ERR(("scb setting failed \n"));
11984 // goto fail;
11985 }
11986
11987 wl_set_drv_status(cfg, CONNECTED, dev);
11988 WL_DBG(("** AP/GO Created **\n"));
11989
11990 #ifdef WL_CFG80211_ACL
11991 /* Enfoce Admission Control. */
11992 if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
11993 WL_ERR(("Set ACL failed\n"));
11994 }
11995 #endif /* WL_CFG80211_ACL */
11996
11997 /* Set IEs to FW */
11998 if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
11999 WL_ERR(("Set IEs failed \n"));
12000
12001 #ifdef WLDWDS
12002 if (dev->ieee80211_ptr->use_4addr) {
12003 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12004 VNDR_IE_ASSOCRSP_FLAG, (const u8 *)info->beacon.assocresp_ies,
12005 info->beacon.assocresp_ies_len)) < 0) {
12006 WL_ERR(("Set ASSOC RESP IE Failed\n"));
12007 }
12008 }
12009 #endif /* WLDWDS */
12010
12011 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12012 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
12013 bool pbc = 0;
12014 wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12015 if (pbc) {
12016 WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
12017 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12018 }
12019 }
12020
12021 /* Configure hidden SSID */
12022 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) {
12023 if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
12024 WL_ERR(("failed to set hidden : %d\n", err));
12025 WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
12026 }
12027
12028 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12029 if (dev_role == NL80211_IFTYPE_AP) {
12030 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
12031 wl_cfg80211_init_ap_rps(cfg);
12032 } else {
12033 WL_ERR(("Set rpsnoa failed \n"));
12034 }
12035 }
12036 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12037 fail:
12038 if (err) {
12039 WL_ERR(("ADD/SET beacon failed\n"));
12040 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12041 wl_cfg80211_stop_ap(wiphy, dev);
12042 if (dev_role == NL80211_IFTYPE_AP) {
12043 #ifdef WL_EXT_IAPSTA
12044 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12045 #endif /* WL_EXT_IAPSTA */
12046 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12047 #ifdef PKT_FILTER_SUPPORT
12048 /* Enable packet filter */
12049 if (dhd->early_suspended) {
12050 WL_ERR(("Enable pkt_filter\n"));
12051 dhd_enable_packet_filter(1, dhd);
12052 #ifdef APF
12053 dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd));
12054 #endif /* APF */
12055 }
12056 #endif /* PKT_FILTER_SUPPORT */
12057 #ifdef ARP_OFFLOAD_SUPPORT
12058 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
12059 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12060 dhd_arp_offload_set(dhd, dhd_arp_mode);
12061 dhd_arp_offload_enable(dhd, TRUE);
12062 }
12063 #endif /* ARP_OFFLOAD_SUPPORT */
12064 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12065 wl_cfg80211_set_frameburst(cfg, TRUE);
12066 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12067 #ifdef WL_EXT_IAPSTA
12068 }
12069 #endif /* WL_EXT_IAPSTA */
12070 }
12071 #ifdef WLTDLS
12072 if (bssidx == 0) {
12073 /* Since AP creation failed, re-enable TDLS */
12074 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
12075 }
12076 #endif /* WLTDLS */
12077
12078 }
12079
12080 return err;
12081 }
12082
12083 static s32
wl_cfg80211_stop_ap(struct wiphy * wiphy,struct net_device * dev)12084 wl_cfg80211_stop_ap(
12085 struct wiphy *wiphy,
12086 struct net_device *dev)
12087 {
12088 int err = 0;
12089 u32 dev_role = 0;
12090 int ap = 0;
12091 s32 bssidx = 0;
12092 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12093 s32 is_rsdb_supported = BCME_ERROR;
12094 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12095
12096 WL_DBG(("Enter \n"));
12097
12098 if (wl_cfg80211_get_bus_state(cfg)) {
12099 /* since bus is down, iovar will fail. recovery path will bringup the bus. */
12100 WL_ERR(("bus is not ready\n"));
12101 return BCME_OK;
12102 }
12103 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
12104 if (is_rsdb_supported < 0)
12105 return (-ENODEV);
12106
12107 wl_clr_drv_status(cfg, AP_CREATING, dev);
12108 wl_clr_drv_status(cfg, AP_CREATED, dev);
12109 cfg->ap_oper_channel = 0;
12110
12111 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12112 dev_role = NL80211_IFTYPE_AP;
12113 WL_DBG(("stopping AP operation\n"));
12114 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12115 dev_role = NL80211_IFTYPE_P2P_GO;
12116 WL_DBG(("stopping P2P GO operation\n"));
12117 } else {
12118 WL_ERR(("no AP/P2P GO interface is operational.\n"));
12119 return -EINVAL;
12120 }
12121
12122 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12123 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12124 return BCME_ERROR;
12125 }
12126
12127 if (!check_dev_role_integrity(cfg, dev_role)) {
12128 WL_ERR(("role integrity check failed \n"));
12129 err = -EINVAL;
12130 goto exit;
12131 }
12132
12133 /* Free up resources */
12134 wl_cfg80211_cleanup_if(dev);
12135
12136 /* Clear AP/GO connected status */
12137 wl_clr_drv_status(cfg, CONNECTED, dev);
12138 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
12139 WL_ERR(("bss down error %d\n", err));
12140 }
12141
12142 if (dev_role == NL80211_IFTYPE_AP) {
12143 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12144 wl_cfg80211_set_frameburst(cfg, TRUE);
12145 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12146 #ifdef PKT_FILTER_SUPPORT
12147 /* Enable packet filter */
12148 if (dhd->early_suspended) {
12149 WL_ERR(("Enable pkt_filter\n"));
12150 dhd_enable_packet_filter(1, dhd);
12151 #ifdef APF
12152 dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd));
12153 #endif /* APF */
12154 }
12155 #endif /* PKT_FILTER_SUPPORT */
12156 #ifdef ARP_OFFLOAD_SUPPORT
12157 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
12158 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12159 dhd_arp_offload_set(dhd, dhd_arp_mode);
12160 dhd_arp_offload_enable(dhd, TRUE);
12161 }
12162 #endif /* ARP_OFFLOAD_SUPPORT */
12163
12164 if (is_rsdb_supported == 0) {
12165 /* For non-rsdb chips, we use stand alone AP. Do wl down on stop AP */
12166 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
12167 if (unlikely(err)) {
12168 WL_ERR(("WLC_UP error (%d)\n", err));
12169 err = -EINVAL;
12170 goto exit;
12171 }
12172 }
12173
12174 #ifdef WL_DISABLE_HE_SOFTAP
12175 if (wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, TRUE) != BCME_OK) {
12176 WL_ERR(("failed to set he features\n"));
12177 }
12178 #endif /* WL_DISABLE_HE_SOFTAP */
12179
12180 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
12181 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12182 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
12183 wl_cfg80211_init_ap_rps(cfg);
12184 } else {
12185 WL_ERR(("Set rpsnoa failed \n"));
12186 }
12187 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12188 } else {
12189 WL_DBG(("Stopping P2P GO \n"));
12190 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
12191 DHD_EVENT_TIMEOUT_MS*3);
12192 DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub));
12193 }
12194
12195 SUPP_LOG(("AP/GO Link down\n"));
12196 exit:
12197 if (err) {
12198 /* In case of failure, flush fw logs */
12199 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12200 SUPP_LOG(("AP/GO Link down fail. err:%d\n", err));
12201 }
12202 #ifdef WLTDLS
12203 if (bssidx == 0) {
12204 /* re-enable TDLS if the number of connected interfaces is less than 2 */
12205 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
12206 }
12207 #endif /* WLTDLS */
12208
12209 if (dev_role == NL80211_IFTYPE_AP) {
12210 #ifdef WL_EXT_IAPSTA
12211 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12212 #endif /* WL_EXT_IAPSTA */
12213 /* clear the AP mode */
12214 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12215 #ifdef WL_EXT_IAPSTA
12216 }
12217 #endif /* WL_EXT_IAPSTA */
12218 }
12219 return err;
12220 }
12221
12222 static s32
wl_cfg80211_change_beacon(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_beacon_data * info)12223 wl_cfg80211_change_beacon(
12224 struct wiphy *wiphy,
12225 struct net_device *dev,
12226 struct cfg80211_beacon_data *info)
12227 {
12228 s32 err = BCME_OK;
12229 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12230 struct parsed_ies ies;
12231 u32 dev_role = 0;
12232 s32 bssidx = 0;
12233 bool pbc = 0;
12234
12235 WL_DBG(("Enter \n"));
12236
12237 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12238 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12239 return BCME_ERROR;
12240 }
12241
12242 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12243 dev_role = NL80211_IFTYPE_P2P_GO;
12244 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12245 dev_role = NL80211_IFTYPE_AP;
12246 } else {
12247 err = -EINVAL;
12248 goto fail;
12249 }
12250
12251 if (!check_dev_role_integrity(cfg, dev_role)) {
12252 err = -EINVAL;
12253 goto fail;
12254 }
12255
12256 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
12257 WL_ERR(("P2P already down status!\n"));
12258 err = BCME_ERROR;
12259 goto fail;
12260 }
12261
12262 /* Parse IEs */
12263 if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) {
12264 WL_ERR(("Parse IEs failed \n"));
12265 goto fail;
12266 }
12267
12268 /* Set IEs to FW */
12269 if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
12270 WL_ERR(("Set IEs failed \n"));
12271 goto fail;
12272 }
12273
12274 if (dev_role == NL80211_IFTYPE_AP) {
12275 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
12276 WL_ERR(("Hostapd update sec failed \n"));
12277 err = -EINVAL;
12278 goto fail;
12279 }
12280 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12281 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
12282 wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12283 WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
12284 if (pbc)
12285 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12286 else
12287 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
12288 }
12289 }
12290
12291 fail:
12292 if (err) {
12293 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12294 }
12295 return err;
12296 }
12297 #else
12298 static s32
wl_cfg80211_add_set_beacon(struct wiphy * wiphy,struct net_device * dev,struct beacon_parameters * info)12299 wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
12300 struct beacon_parameters *info)
12301 {
12302 s32 err = BCME_OK;
12303 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12304 s32 ie_offset = 0;
12305 s32 bssidx = 0;
12306 u32 dev_role = NL80211_IFTYPE_AP;
12307 struct parsed_ies ies;
12308 bcm_tlv_t *ssid_ie;
12309 bool pbc = 0;
12310 bool privacy;
12311 bool is_bss_up = 0;
12312 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12313
12314 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
12315 info->interval, info->dtim_period, info->head_len, info->tail_len));
12316
12317 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
12318 dev_role = NL80211_IFTYPE_AP;
12319 }
12320 #if defined(WL_ENABLE_P2P_IF)
12321 else if (dev == cfg->p2p_net) {
12322 /* Group Add request on p2p0 */
12323 dev = bcmcfg_to_prmry_ndev(cfg);
12324 dev_role = NL80211_IFTYPE_P2P_GO;
12325 }
12326 #endif /* WL_ENABLE_P2P_IF */
12327
12328 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12329 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12330 return BCME_ERROR;
12331 }
12332
12333 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12334 dev_role = NL80211_IFTYPE_P2P_GO;
12335 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12336 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
12337 }
12338
12339 if (!check_dev_role_integrity(cfg, dev_role)) {
12340 err = -ENODEV;
12341 goto fail;
12342 }
12343
12344 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
12345 WL_ERR(("P2P already down status!\n"));
12346 err = BCME_ERROR;
12347 goto fail;
12348 }
12349
12350 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
12351 /* find the SSID */
12352 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
12353 info->head_len - ie_offset,
12354 DOT11_MNG_SSID_ID)) != NULL) {
12355 if (dev_role == NL80211_IFTYPE_AP) {
12356 /* Store the hostapd SSID */
12357 bzero(&cfg->hostapd_ssid.SSID[0], DOT11_MAX_SSID_LEN);
12358 cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
12359 memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
12360 cfg->hostapd_ssid.SSID_len);
12361 } else {
12362 /* P2P GO */
12363 bzero(&cfg->p2p->ssid.SSID[0], DOT11_MAX_SSID_LEN);
12364 cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
12365 memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
12366 cfg->p2p->ssid.SSID_len);
12367 }
12368 }
12369
12370 if (wl_cfg80211_parse_ies((u8 *)info->tail,
12371 info->tail_len, &ies) < 0) {
12372 WL_ERR(("Beacon get IEs failed \n"));
12373 err = -EINVAL;
12374 goto fail;
12375 }
12376
12377 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12378 VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
12379 info->tail_len)) < 0) {
12380 WL_ERR(("Beacon set IEs failed \n"));
12381 goto fail;
12382 } else {
12383 WL_DBG(("Applied Vndr IEs for Beacon \n"));
12384 }
12385
12386 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12387 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12388 VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies,
12389 info->proberesp_ies_len)) < 0) {
12390 WL_ERR(("ProbeRsp set IEs failed \n"));
12391 goto fail;
12392 } else {
12393 WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
12394 }
12395 #endif // endif
12396
12397 is_bss_up = wl_cfg80211_bss_isup(dev, bssidx);
12398
12399 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12400 privacy = info->privacy;
12401 #else
12402 privacy = 0;
12403 #endif // endif
12404 if (!is_bss_up &&
12405 (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx, privacy) < 0))
12406 {
12407 WL_ERR(("Beacon set security failed \n"));
12408 err = -EINVAL;
12409 goto fail;
12410 }
12411
12412 /* Set BI and DTIM period */
12413 if (info->interval) {
12414 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
12415 &info->interval, sizeof(s32))) < 0) {
12416 WL_ERR(("Beacon Interval Set Error, %d\n", err));
12417 return err;
12418 }
12419 }
12420 if (info->dtim_period) {
12421 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
12422 &info->dtim_period, sizeof(s32))) < 0) {
12423 WL_ERR(("DTIM Interval Set Error, %d\n", err));
12424 return err;
12425 }
12426 }
12427
12428 /* If bss is already up, skip bring up */
12429 if (!is_bss_up &&
12430 (err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0)
12431 {
12432 WL_ERR(("Beacon bring up AP/GO failed \n"));
12433 goto fail;
12434 }
12435
12436 /* Set GC/STA SCB expiry timings. */
12437 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
12438 WL_ERR(("scb setting failed \n"));
12439 if (err == BCME_UNSUPPORTED)
12440 err = 0;
12441 // goto fail;
12442 }
12443
12444 if (wl_get_drv_status(cfg, AP_CREATED, dev)) {
12445 /* Soft AP already running. Update changed params */
12446 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
12447 WL_ERR(("Hostapd update sec failed \n"));
12448 err = -EINVAL;
12449 goto fail;
12450 }
12451 }
12452
12453 /* Enable Probe Req filter */
12454 if (((dev_role == NL80211_IFTYPE_P2P_GO) ||
12455 (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) {
12456 wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12457 if (pbc)
12458 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12459 }
12460
12461 WL_DBG(("** ADD/SET beacon done **\n"));
12462 wl_set_drv_status(cfg, CONNECTED, dev);
12463
12464 fail:
12465 if (err) {
12466 WL_ERR(("ADD/SET beacon failed\n"));
12467 if (dev_role == NL80211_IFTYPE_AP) {
12468 #ifdef WL_EXT_IAPSTA
12469 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12470 #endif /* WL_EXT_IAPSTA */
12471 /* clear the AP mode */
12472 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12473 #ifdef WL_EXT_IAPSTA
12474 }
12475 #endif /* WL_EXT_IAPSTA */
12476 }
12477 }
12478 return err;
12479
12480 }
12481
12482 static s32
wl_cfg80211_del_beacon(struct wiphy * wiphy,struct net_device * dev)12483 wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
12484 {
12485 int err = 0;
12486 s32 bssidx = 0;
12487 int infra = 0;
12488 struct wireless_dev *wdev = dev->ieee80211_ptr;
12489 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12490 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12491
12492 WL_DBG(("Enter. \n"));
12493
12494 if (!wdev) {
12495 WL_ERR(("wdev null \n"));
12496 return -EINVAL;
12497 }
12498
12499 if ((wdev->iftype != NL80211_IFTYPE_P2P_GO) && (wdev->iftype != NL80211_IFTYPE_AP)) {
12500 WL_ERR(("Unspported iface type iftype:%d \n", wdev->iftype));
12501 }
12502
12503 wl_clr_drv_status(cfg, AP_CREATING, dev);
12504 wl_clr_drv_status(cfg, AP_CREATED, dev);
12505
12506 /* Clear AP/GO connected status */
12507 wl_clr_drv_status(cfg, CONNECTED, dev);
12508
12509 cfg->ap_oper_channel = 0;
12510
12511 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12512 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12513 return BCME_ERROR;
12514 }
12515
12516 /* Do bss down */
12517 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
12518 WL_ERR(("bss down error %d\n", err));
12519 }
12520
12521 /* fall through is intentional */
12522 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
12523 if (err < 0) {
12524 WL_ERR(("SET INFRA error %d\n", err));
12525 }
12526 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
12527
12528 if (wdev->iftype == NL80211_IFTYPE_AP) {
12529 #ifdef WL_EXT_IAPSTA
12530 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12531 #endif /* WL_EXT_IAPSTA */
12532 /* clear the AP mode */
12533 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12534 #ifdef WL_EXT_IAPSTA
12535 }
12536 #endif /* WL_EXT_IAPSTA */
12537 }
12538
12539 return 0;
12540 }
12541 #endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
12542
12543 #ifdef WL_SUPPORT_ACS
12544 /*
12545 * Currently the dump_obss IOVAR is returning string as output so we need to
12546 * parse the output buffer in an unoptimized way. Going forward if we get the
12547 * IOVAR output in binary format this method can be optimized
12548 */
wl_parse_dump_obss(char * buf,struct wl_dump_survey * survey)12549 static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
12550 {
12551 int i;
12552 char *token;
12553 char delim[] = " \n";
12554
12555 token = strsep(&buf, delim);
12556 while (token != NULL) {
12557 if (!strcmp(token, "OBSS")) {
12558 for (i = 0; i < OBSS_TOKEN_IDX; i++)
12559 token = strsep(&buf, delim);
12560 survey->obss = simple_strtoul(token, NULL, 10);
12561 }
12562
12563 if (!strcmp(token, "IBSS")) {
12564 for (i = 0; i < IBSS_TOKEN_IDX; i++)
12565 token = strsep(&buf, delim);
12566 survey->ibss = simple_strtoul(token, NULL, 10);
12567 }
12568
12569 if (!strcmp(token, "TXDur")) {
12570 for (i = 0; i < TX_TOKEN_IDX; i++)
12571 token = strsep(&buf, delim);
12572 survey->tx = simple_strtoul(token, NULL, 10);
12573 }
12574
12575 if (!strcmp(token, "Category")) {
12576 for (i = 0; i < CTG_TOKEN_IDX; i++)
12577 token = strsep(&buf, delim);
12578 survey->no_ctg = simple_strtoul(token, NULL, 10);
12579 }
12580
12581 if (!strcmp(token, "Packet")) {
12582 for (i = 0; i < PKT_TOKEN_IDX; i++)
12583 token = strsep(&buf, delim);
12584 survey->no_pckt = simple_strtoul(token, NULL, 10);
12585 }
12586
12587 if (!strcmp(token, "Opp(time):")) {
12588 for (i = 0; i < IDLE_TOKEN_IDX; i++)
12589 token = strsep(&buf, delim);
12590 survey->idle = simple_strtoul(token, NULL, 10);
12591 }
12592
12593 token = strsep(&buf, delim);
12594 }
12595
12596 return 0;
12597 }
12598
wl_dump_obss(struct net_device * ndev,cca_msrmnt_query req,struct wl_dump_survey * survey)12599 static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
12600 struct wl_dump_survey *survey)
12601 {
12602 cca_stats_n_flags *results;
12603 char *buf;
12604 int retry, err;
12605 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
12606
12607 buf = (char *)MALLOCZ(cfg->osh, sizeof(char) * WLC_IOCTL_MAXLEN);
12608 if (unlikely(!buf)) {
12609 WL_ERR(("%s: buf alloc failed\n", __func__));
12610 return -ENOMEM;
12611 }
12612
12613 retry = IOCTL_RETRY_COUNT;
12614 while (retry--) {
12615 err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req),
12616 buf, WLC_IOCTL_MAXLEN, NULL);
12617 if (err >= 0) {
12618 break;
12619 }
12620 WL_DBG(("attempt = %d, err = %d, \n",
12621 (IOCTL_RETRY_COUNT - retry), err));
12622 }
12623
12624 if (retry <= 0) {
12625 WL_ERR(("failure, dump_obss IOVAR failed\n"));
12626 err = -EINVAL;
12627 goto exit;
12628 }
12629
12630 results = (cca_stats_n_flags *)(buf);
12631 wl_parse_dump_obss(results->buf, survey);
12632 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
12633
12634 return 0;
12635 exit:
12636 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
12637 return err;
12638 }
12639
wl_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * ndev,int idx,struct survey_info * info)12640 static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
12641 int idx, struct survey_info *info)
12642 {
12643 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12644 struct wl_dump_survey *survey;
12645 struct ieee80211_supported_band *band;
12646 struct ieee80211_channel*chan;
12647 cca_msrmnt_query req;
12648 int val, err, noise, retry;
12649
12650 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12651 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
12652 return -ENOENT;
12653 }
12654 band = wiphy->bands[IEEE80211_BAND_2GHZ];
12655 if (band && idx >= band->n_channels) {
12656 idx -= band->n_channels;
12657 band = NULL;
12658 }
12659
12660 if (!band || idx >= band->n_channels) {
12661 /* Move to 5G band */
12662 band = wiphy->bands[IEEE80211_BAND_5GHZ];
12663 if (idx >= band->n_channels) {
12664 return -ENOENT;
12665 }
12666 }
12667
12668 chan = &band->channels[idx];
12669 /* Setting current channel to the requested channel */
12670 if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan,
12671 NL80211_CHAN_HT20) < 0)) {
12672 WL_ERR(("Set channel failed \n"));
12673 }
12674
12675 if (!idx) {
12676 /* Set interface up, explicitly. */
12677 val = 1;
12678 err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
12679 if (err < 0) {
12680 WL_ERR(("set interface up failed, error = %d\n", err));
12681 }
12682 }
12683
12684 /* Get noise value */
12685 retry = IOCTL_RETRY_COUNT;
12686 while (retry--) {
12687 noise = 0;
12688 err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise,
12689 sizeof(noise));
12690 if (err >= 0) {
12691 break;
12692 }
12693 WL_DBG(("attempt = %d, err = %d, \n",
12694 (IOCTL_RETRY_COUNT - retry), err));
12695 }
12696
12697 if (retry <= 0) {
12698 WL_ERR(("Get Phy Noise failed, error = %d\n", err));
12699 noise = CHAN_NOISE_DUMMY;
12700 }
12701
12702 survey = (struct wl_dump_survey *)MALLOCZ(cfg->osh,
12703 sizeof(struct wl_dump_survey));
12704 if (unlikely(!survey)) {
12705 WL_ERR(("%s: alloc failed\n", __func__));
12706 return -ENOMEM;
12707 }
12708
12709 /* Start Measurement for obss stats on current channel */
12710 req.msrmnt_query = 0;
12711 req.time_req = ACS_MSRMNT_DELAY;
12712 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
12713 goto exit;
12714 }
12715
12716 /*
12717 * Wait for the meaurement to complete, adding a buffer value of 10 to take
12718 * into consideration any delay in IOVAR completion
12719 */
12720 msleep(ACS_MSRMNT_DELAY + 10);
12721
12722 /* Issue IOVAR to collect measurement results */
12723 req.msrmnt_query = 1;
12724 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
12725 goto exit;
12726 }
12727
12728 info->channel = chan;
12729 info->noise = noise;
12730 info->channel_time = ACS_MSRMNT_DELAY;
12731 info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
12732 info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg +
12733 survey->no_pckt;
12734 info->channel_time_tx = survey->tx;
12735 info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
12736 SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
12737 SURVEY_INFO_CHANNEL_TIME_TX;
12738 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
12739
12740 return 0;
12741 exit:
12742 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
12743 return err;
12744 }
12745 #endif /* WL_SUPPORT_ACS */
12746
12747 #ifndef CONFIG_AP6XXX_WIFI6_HDF
12748 static
12749 #endif
12750 struct cfg80211_ops wl_cfg80211_ops = {
12751 .add_virtual_intf = wl_cfg80211_add_virtual_iface,
12752 .del_virtual_intf = wl_cfg80211_del_virtual_iface,
12753 .change_virtual_intf = wl_cfg80211_change_virtual_iface,
12754 #if defined(WL_CFG80211_P2P_DEV_IF)
12755 .start_p2p_device = wl_cfgp2p_start_p2p_device,
12756 .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
12757 #endif /* WL_CFG80211_P2P_DEV_IF */
12758 .scan = wl_cfg80211_scan,
12759 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
12760 .abort_scan = wl_cfg80211_abort_scan,
12761 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
12762 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
12763 .join_ibss = wl_cfg80211_join_ibss,
12764 .leave_ibss = wl_cfg80211_leave_ibss,
12765 .get_station = wl_cfg80211_get_station,
12766 .set_tx_power = wl_cfg80211_set_tx_power,
12767 .get_tx_power = wl_cfg80211_get_tx_power,
12768 .add_key = wl_cfg80211_add_key,
12769 .del_key = wl_cfg80211_del_key,
12770 .get_key = wl_cfg80211_get_key,
12771 .set_default_key = wl_cfg80211_config_default_key,
12772 .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
12773 .set_power_mgmt = wl_cfg80211_set_power_mgmt,
12774 .connect = wl_cfg80211_connect,
12775 .disconnect = wl_cfg80211_disconnect,
12776 .suspend = wl_cfg80211_suspend,
12777 .resume = wl_cfg80211_resume,
12778 .set_pmksa = wl_cfg80211_set_pmksa,
12779 .del_pmksa = wl_cfg80211_del_pmksa,
12780 .flush_pmksa = wl_cfg80211_flush_pmksa,
12781 .remain_on_channel = wl_cfg80211_remain_on_channel,
12782 .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
12783 .mgmt_tx = wl_cfg80211_mgmt_tx,
12784 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
12785 .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
12786 #else
12787 .update_mgmt_frame_registrations = wl_cfg80211_mgmt_frame_register,
12788 #endif
12789 .change_bss = wl_cfg80211_change_bss,
12790 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS)
12791 .set_channel = wl_cfg80211_set_channel,
12792 #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
12793 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS)
12794 .set_beacon = wl_cfg80211_add_set_beacon,
12795 .add_beacon = wl_cfg80211_add_set_beacon,
12796 .del_beacon = wl_cfg80211_del_beacon,
12797 #else
12798 .change_beacon = wl_cfg80211_change_beacon,
12799 .start_ap = wl_cfg80211_start_ap,
12800 .stop_ap = wl_cfg80211_stop_ap,
12801 #endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
12802 #ifdef WL_SCHED_SCAN
12803 .sched_scan_start = wl_cfg80211_sched_scan_start,
12804 .sched_scan_stop = wl_cfg80211_sched_scan_stop,
12805 #endif /* WL_SCHED_SCAN */
12806 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
12807 2, 0))
12808 .del_station = wl_cfg80211_del_station,
12809 .change_station = wl_cfg80211_change_station,
12810 .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
12811 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
12812 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
12813 .tdls_mgmt = wl_cfg80211_tdls_mgmt,
12814 .tdls_oper = wl_cfg80211_tdls_oper,
12815 #endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
12816 #ifdef WL_SUPPORT_ACS
12817 .dump_survey = wl_cfg80211_dump_survey,
12818 #endif /* WL_SUPPORT_ACS */
12819 #ifdef WL_CFG80211_ACL
12820 .set_mac_acl = wl_cfg80211_set_mac_acl,
12821 #endif /* WL_CFG80211_ACL */
12822 #ifdef GTK_OFFLOAD_SUPPORT
12823 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
12824 .set_rekey_data = wl_cfg80211_set_rekey_data,
12825 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
12826 #endif /* GTK_OFFLOAD_SUPPORT */
12827 #if defined(WL_FILS)
12828 /* This should be enabled from kernel version which supports this */
12829 .update_connect_params = wl_cfg80211_update_connect_params,
12830 #endif /* WL_FILS */
12831 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
12832 .set_pmk = wl_cfg80211_set_pmk,
12833 .del_pmk = wl_cfg80211_del_pmk,
12834 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
12835 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
12836 .channel_switch = wl_cfg80211_channel_switch,
12837 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
12838 #ifdef WL_CLIENT_SAE
12839 .external_auth = wl_cfg80211_external_auth,
12840 #endif /* WL_CLIENT_SAE */
12841 };
12842
wl_mode_to_nl80211_iftype(s32 mode)12843 s32 wl_mode_to_nl80211_iftype(s32 mode)
12844 {
12845 s32 err = 0;
12846
12847 switch (mode) {
12848 case WL_MODE_BSS:
12849 return NL80211_IFTYPE_STATION;
12850 case WL_MODE_IBSS:
12851 return NL80211_IFTYPE_ADHOC;
12852 case WL_MODE_AP:
12853 return NL80211_IFTYPE_AP;
12854 #ifdef WLMESH_CFG80211
12855 case WL_MODE_MESH:
12856 return NL80211_IFTYPE_MESH_POINT;
12857 #endif /* WLMESH_CFG80211 */
12858 default:
12859 return NL80211_IFTYPE_UNSPECIFIED;
12860 }
12861
12862 return err;
12863 }
12864
12865 s32
wl_cfg80211_set_country_code(struct net_device * net,char * country_code,bool notify,bool user_enforced,int revinfo)12866 wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
12867 bool notify, bool user_enforced, int revinfo)
12868 {
12869 s32 ret = BCME_OK;
12870 #ifdef WL_NAN
12871 struct wireless_dev *wdev = ndev_to_wdev(net);
12872 struct wiphy *wiphy = wdev->wiphy;
12873 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12874 if (cfg->nan_enable) {
12875 mutex_lock(&cfg->if_sync);
12876 cfg->nancfg.disable_reason = NAN_COUNTRY_CODE_CHANGE;
12877 ret = wl_cfgnan_disable(cfg);
12878 mutex_unlock(&cfg->if_sync);
12879 if (ret != BCME_OK) {
12880 WL_ERR(("failed to disable nan, error[%d]\n", ret));
12881 return ret;
12882 }
12883 }
12884 #endif /* WL_NAN */
12885 ret = wldev_set_country(net, country_code,
12886 notify, user_enforced, revinfo);
12887 if (ret < 0) {
12888 WL_ERR(("set country Failed :%d\n", ret));
12889 }
12890 return ret;
12891 }
12892
12893 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
12894 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
12895 #define WL_CFG80211_REG_NOTIFIER() static int wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
12896 #else
12897 #define WL_CFG80211_REG_NOTIFIER() static void wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
12898 #endif /* kernel version < 3.9.0 */
12899 #endif
12900
12901 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
WL_CFG80211_REG_NOTIFIER()12902 WL_CFG80211_REG_NOTIFIER()
12903 {
12904 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
12905 int ret = 0;
12906 int revinfo = -1;
12907
12908 if (!request || !cfg) {
12909 WL_ERR(("Invalid arg\n"));
12910 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
12911 return -EINVAL;
12912 #else
12913 return;
12914 #endif /* kernel version < 3.10.11 */
12915 }
12916
12917 WL_DBG(("ccode: %c%c Initiator: %d\n",
12918 request->alpha2[0], request->alpha2[1], request->initiator));
12919
12920 /* We support only REGDOM_SET_BY_USER as of now */
12921 if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
12922 (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
12923 WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
12924 request->initiator));
12925 /* in case of no supported country by regdb
12926 lets driver setup platform default Locale
12927 */
12928 }
12929
12930 WL_ERR(("Set country code %c%c from %s\n",
12931 request->alpha2[0], request->alpha2[1],
12932 ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User")));
12933
12934 if ((ret = wldev_set_country(bcmcfg_to_prmry_ndev(cfg), request->alpha2,
12935 false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false),
12936 revinfo)) < 0) {
12937 WL_ERR(("set country Failed :%d\n", ret));
12938 }
12939
12940 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
12941 return ret;
12942 #else
12943 return;
12944 #endif /* kernel version < 3.10.11 */
12945 }
12946 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
12947
12948 #ifdef CONFIG_PM
12949 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
12950 static const struct wiphy_wowlan_support brcm_wowlan_support = {
12951 .flags = WIPHY_WOWLAN_ANY,
12952 .n_patterns = WL_WOWLAN_MAX_PATTERNS,
12953 .pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
12954 .pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
12955 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
12956 .max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
12957 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
12958 };
12959 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
12960 #endif /* CONFIG_PM */
12961
wl_features_set(u8 * array,uint8 len,u32 ftidx)12962 int wl_features_set(u8 *array, uint8 len, u32 ftidx)
12963 {
12964 u8* ft_byte;
12965
12966 if ((ftidx / 8u) >= len)
12967 return BCME_BADARG;
12968
12969 ft_byte = &array[ftidx / 8u];
12970 *ft_byte |= BIT(ftidx % 8u);
12971 return BCME_OK;
12972 }
12973
wl_setup_wiphy(struct wireless_dev * wdev,struct device * sdiofunc_dev,dhd_pub_t * context)12974 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, dhd_pub_t *context)
12975 {
12976 s32 err = 0;
12977 #ifdef CONFIG_PM
12978 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
12979 struct cfg80211_wowlan *brcm_wowlan_config = NULL;
12980 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
12981 #endif /* CONFIG_PM */
12982
12983 //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
12984 dhd_pub_t *dhd = (dhd_pub_t *)context;
12985 BCM_REFERENCE(dhd);
12986
12987 if (!dhd) {
12988 WL_ERR(("DHD is NULL!!"));
12989 err = -ENODEV;
12990 return err;
12991 }
12992 //#endif // endif
12993
12994 wdev->wiphy =
12995 wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
12996 if (unlikely(!wdev->wiphy)) {
12997 WL_ERR(("Couldn not allocate wiphy device\n"));
12998 err = -ENOMEM;
12999 return err;
13000 }
13001 set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
13002 wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
13003 /* Report how many SSIDs Driver can support per Scan request */
13004 wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
13005 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
13006 #ifdef WL_SCHED_SCAN
13007 wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
13008 wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
13009 wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
13010 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
13011 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
13012 #endif /* LINUX_VER < 4.12 */
13013 #endif /* WL_SCHED_SCAN */
13014 #ifdef WLMESH_CFG80211
13015 wdev->wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
13016 #endif /* WLMESH_CFG80211 */
13017 wdev->wiphy->interface_modes =
13018 BIT(NL80211_IFTYPE_STATION)
13019 | BIT(NL80211_IFTYPE_ADHOC)
13020 #if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
13021 | BIT(NL80211_IFTYPE_MONITOR)
13022 #endif // endif
13023 #if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
13024 | BIT(NL80211_IFTYPE_P2P_CLIENT)
13025 | BIT(NL80211_IFTYPE_P2P_GO)
13026 #endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
13027 #if defined(WL_CFG80211_P2P_DEV_IF)
13028 | BIT(NL80211_IFTYPE_P2P_DEVICE)
13029 #endif /* WL_CFG80211_P2P_DEV_IF */
13030 #ifdef WLMESH_CFG80211
13031 | BIT(NL80211_IFTYPE_MESH_POINT)
13032 #endif /* WLMESH_CFG80211 */
13033 | BIT(NL80211_IFTYPE_AP);
13034
13035 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
13036 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
13037 WL_DBG(("Setting interface combinations for common mode\n"));
13038 wdev->wiphy->iface_combinations = common_iface_combinations;
13039 wdev->wiphy->n_iface_combinations =
13040 ARRAY_SIZE(common_iface_combinations);
13041 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
13042
13043 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
13044
13045 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
13046 wdev->wiphy->cipher_suites = __wl_cipher_suites;
13047 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
13048 wdev->wiphy->max_remain_on_channel_duration = 5000;
13049 wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
13050 #ifndef WL_POWERSAVE_DISABLED
13051 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
13052 #else
13053 wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
13054 #endif /* !WL_POWERSAVE_DISABLED */
13055 wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
13056 WIPHY_FLAG_4ADDR_AP |
13057 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS)
13058 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
13059 #endif // endif
13060 WIPHY_FLAG_4ADDR_STATION;
13061 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
13062 /*
13063 * If FW ROAM flag is advertised, upper layer doesn't provide the
13064 * bssid & freq in the connect command. However, kernel ver >= 3.15,
13065 * provides bssid_hint & freq_hint which can be used by the firmware.
13066 * fw_ap_select variable determines whether FW selects the AP or the
13067 * user space selects the target AP within the given ESS.
13068 */
13069 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
13070 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13071 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
13072 wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
13073 WIPHY_FLAG_OFFCHAN_TX;
13074 #endif // endif
13075 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
13076 4, 0))
13077 /* From 3.4 kernel ownards AP_SME flag can be advertised
13078 * to remove the patch from supplicant
13079 */
13080 wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
13081
13082 #ifdef WL_CFG80211_ACL
13083 /* Configure ACL capabilities. */
13084 wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
13085 #endif // endif
13086
13087 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
13088 /* Supplicant distinguish between the SoftAP mode and other
13089 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
13090 * response frame from Supplicant MR1 and Kernel 3.4.0 or
13091 * later version. To add Vendor specific IE into the
13092 * probe response frame in case of SoftAP mode,
13093 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
13094 */
13095 if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
13096 wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
13097 wdev->wiphy->probe_resp_offload = 0;
13098 }
13099 #endif // endif
13100 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
13101
13102 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
13103 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
13104 #endif // endif
13105
13106 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13107 /*
13108 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
13109 * disconnection of connected network before suspend. So a dummy wowlan
13110 * filter is configured for kernels linux-3.8 and above.
13111 */
13112
13113 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13114 wdev->wiphy->wowlan = &brcm_wowlan_support;
13115 /* If this is not provided cfg stack will get disconnect
13116 * during suspend.
13117 * Note: wiphy->wowlan_config is freed by cfg80211 layer.
13118 * so use malloc instead of MALLOC(osh) to avoid false alarm.
13119 */
13120 brcm_wowlan_config = kmalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL);
13121 if (brcm_wowlan_config) {
13122 brcm_wowlan_config->disconnect = true;
13123 brcm_wowlan_config->gtk_rekey_failure = true;
13124 brcm_wowlan_config->eap_identity_req = true;
13125 brcm_wowlan_config->four_way_handshake = true;
13126 brcm_wowlan_config->patterns = NULL;
13127 brcm_wowlan_config->n_patterns = 0;
13128 brcm_wowlan_config->tcp = NULL;
13129 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13130 brcm_wowlan_config->nd_config = NULL;
13131 #endif // endif
13132 } else {
13133 WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
13134 " So wiphy->wowlan_config is set to NULL\n"));
13135 }
13136 wdev->wiphy->wowlan_config = brcm_wowlan_config;
13137 #else
13138 wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
13139 wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
13140 wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
13141 wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
13142 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
13143 wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
13144 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
13145 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13146 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13147
13148 WL_DBG(("Registering custom regulatory)\n"));
13149 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
13150 wdev->wiphy->regulatory_flags |=
13151 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13152 REGULATORY_IGNORE_STALE_KICKOFF |
13153 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
13154 REGULATORY_CUSTOM_REG;
13155 #else
13156 wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
13157 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
13158 wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
13159
13160 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13161 WL_INFORM_MEM(("Registering Vendor80211\n"));
13162 err = wl_cfgvendor_attach(wdev->wiphy, dhd);
13163 if (unlikely(err < 0)) {
13164 WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
13165 }
13166 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
13167 #ifdef WL_FILS
13168 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
13169 #endif /* WL_FILS */
13170
13171 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
13172 wdev->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
13173 wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS;
13174 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */
13175
13176 /* Now we can register wiphy with cfg80211 module */
13177 err = wiphy_register(wdev->wiphy);
13178 if (unlikely(err < 0)) {
13179 WL_ERR(("Couldn not register wiphy device (%d)\n", err));
13180 wiphy_free(wdev->wiphy);
13181 }
13182
13183 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
13184 KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
13185 wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
13186 #endif // endif
13187
13188 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
13189 if (wl_extsae_chip(dhd))
13190 wdev->wiphy->features |= NL80211_FEATURE_SAE;
13191 #endif /* WL_SAE || WL_CLIENT_SAE */
13192 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE)
13193 if (FW_SUPPORTED(dhd, idsup)) {
13194 err = wiphy_ext_feature_set(wdev->wiphy,
13195 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
13196 if (err) {
13197 return err;
13198 }
13199 err = wiphy_ext_feature_set(wdev->wiphy,
13200 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
13201 if (err) {
13202 return err;
13203 }
13204 }
13205 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) && defined(BCMSUP_4WAY_HANDSHAKE) */
13206 #ifdef WL_SCAN_TYPE
13207 /* These scan types will be mapped to default scan on non-supported chipset */
13208 /* Advertise scan type capability. */
13209 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_SPAN_SCAN);
13210 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_POWER_SCAN);
13211 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
13212 wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN;
13213 #endif /* WL_SCAN_TYPE */
13214
13215 return err;
13216 }
13217
wl_free_wdev(struct bcm_cfg80211 * cfg)13218 static void wl_free_wdev(struct bcm_cfg80211 *cfg)
13219 {
13220 struct wireless_dev *wdev = cfg->wdev;
13221 struct wiphy *wiphy = NULL;
13222 if (!wdev) {
13223 WL_ERR(("wdev is invalid\n"));
13224 return;
13225 }
13226 if (wdev->wiphy) {
13227 wiphy = wdev->wiphy;
13228
13229 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13230 wl_cfgvendor_detach(wdev->wiphy);
13231 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
13232 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13233 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13234 /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
13235 WL_DBG(("clear wowlan\n"));
13236 wdev->wiphy->wowlan = NULL;
13237 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13238 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13239 wiphy_unregister(wdev->wiphy);
13240 wdev->wiphy->dev.parent = NULL;
13241 wdev->wiphy = NULL;
13242 }
13243
13244 wl_delete_all_netinfo(cfg);
13245 if (wiphy) {
13246 if (wdev->netdev)
13247 wdev->netdev->ieee80211_ptr = NULL;
13248 wdev->netdev = NULL;
13249 MFREE(cfg->osh, wdev, sizeof(*wdev));
13250 cfg->wdev = NULL;
13251 wiphy_free(wiphy);
13252 }
13253
13254 /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
13255 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
13256 */
13257 }
13258
13259 #if defined(BSSCACHE) || defined(RSSIAVG)
wl_cfg80211_update_bss_cache(struct bcm_cfg80211 * cfg)13260 void wl_cfg80211_update_bss_cache(struct bcm_cfg80211 *cfg)
13261 {
13262 #if defined(RSSIAVG)
13263 int rssi;
13264 #endif
13265 struct wl_scan_results *bss_list = cfg->bss_list;
13266
13267 /* Free cache in p2p scanning*/
13268 if (p2p_is_on(cfg) && p2p_scan(cfg)) {
13269 #if defined(RSSIAVG)
13270 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
13271 #endif
13272 #if defined(BSSCACHE)
13273 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
13274 #endif
13275 }
13276
13277 /* Update cache */
13278 #if defined(RSSIAVG)
13279 wl_update_rssi_cache(&cfg->g_rssi_cache_ctrl, bss_list);
13280 if (!in_atomic())
13281 wl_update_connected_rssi_cache(ndev, &cfg->g_rssi_cache_ctrl, &rssi);
13282 #endif
13283 #if defined(BSSCACHE)
13284 wl_update_bss_cache(&cfg->g_bss_cache_ctrl,
13285 #if defined(RSSIAVG)
13286 &cfg->g_rssi_cache_ctrl,
13287 #endif
13288 bss_list);
13289 #endif
13290
13291 /* delete dirty cache */
13292 #if defined(RSSIAVG)
13293 wl_delete_dirty_rssi_cache(&cfg->g_rssi_cache_ctrl);
13294 wl_reset_rssi_cache(&cfg->g_rssi_cache_ctrl);
13295 #endif
13296 #if defined(BSSCACHE)
13297 wl_delete_dirty_bss_cache(&cfg->g_bss_cache_ctrl);
13298 wl_reset_bss_cache(&cfg->g_bss_cache_ctrl);
13299 #endif
13300
13301 }
13302 #endif
13303
13304 #if defined(BSSCACHE)
wl_inform_bss_cache(struct bcm_cfg80211 * cfg)13305 s32 wl_inform_bss_cache(struct bcm_cfg80211 *cfg)
13306 {
13307 struct wl_scan_results *bss_list = cfg->bss_list;
13308 wl_bss_info_t *bi = NULL; /* must be initialized */
13309 s32 err = 0;
13310 s32 i;
13311 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13312 #if defined(BSSCACHE)
13313 wl_bss_cache_t *node;
13314 #endif
13315
13316 WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
13317 node = cfg->g_bss_cache_ctrl.m_cache_head;
13318 for (i=0; node && i<WL_AP_MAX; i++) {
13319 bi = node->results.bss_info;
13320 err = wl_inform_single_bss(cfg, bi, false);
13321 node = node->next;
13322 }
13323 if (cfg->autochannel)
13324 wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, ioctl_version,
13325 &cfg->best_2g_ch, &cfg->best_5g_ch);
13326
13327 return err;
13328 }
13329 #endif
13330
wl_inform_bss(struct bcm_cfg80211 * cfg)13331 s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
13332 {
13333 #if !defined(BSSCACHE)
13334 struct wl_scan_results *bss_list;
13335 wl_bss_info_t *bi = NULL; /* must be initialized */
13336 s32 i;
13337 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13338 #endif
13339 s32 err = 0;
13340
13341 #if defined(BSSCACHE) || defined(RSSIAVG)
13342 wl_cfg80211_update_bss_cache(cfg);
13343 #endif
13344
13345 #if defined(BSSCACHE)
13346 err = wl_inform_bss_cache(cfg);
13347 #else
13348 bss_list = cfg->bss_list;
13349 WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
13350 #ifdef ESCAN_CHANNEL_CACHE
13351 reset_roam_cache(cfg);
13352 #endif /* ESCAN_CHANNEL_CACHE */
13353 preempt_disable();
13354 bi = next_bss(bss_list, bi);
13355 for_each_bss(bss_list, bi, i) {
13356 #ifdef ESCAN_CHANNEL_CACHE
13357 add_roam_cache(cfg, bi);
13358 #endif /* ESCAN_CHANNEL_CACHE */
13359 err = wl_inform_single_bss(cfg, bi, false);
13360 if (unlikely(err)) {
13361 WL_ERR(("bss inform failed\n"));
13362 }
13363 }
13364 preempt_enable();
13365 if (cfg->autochannel)
13366 wl_ext_get_best_channel(ndev, bss_list, ioctl_version,
13367 &cfg->best_2g_ch, &cfg->best_5g_ch);
13368 #endif
13369
13370 WL_MEM(("cfg80211 scan cache updated\n"));
13371 #ifdef ROAM_CHANNEL_CACHE
13372 /* print_roam_cache(); */
13373 update_roam_cache(cfg, ioctl_version);
13374 #endif /* ROAM_CHANNEL_CACHE */
13375 return err;
13376 }
13377
wl_inform_single_bss(struct bcm_cfg80211 * cfg,wl_bss_info_t * bi,bool update_ssid)13378 static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool update_ssid)
13379 {
13380 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13381 struct ieee80211_mgmt *mgmt;
13382 struct ieee80211_channel *channel;
13383 struct ieee80211_supported_band *band;
13384 struct wl_cfg80211_bss_info *notif_bss_info;
13385 struct wl_scan_req *sr = wl_to_sr(cfg);
13386 struct beacon_proberesp *beacon_proberesp;
13387 struct cfg80211_bss *cbss = NULL;
13388 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
13389 log_conn_event_t *event_data = NULL;
13390 tlv_log *tlv_data = NULL;
13391 u32 alloc_len, tlv_len;
13392 u32 payload_len;
13393 s32 mgmt_type;
13394 s32 signal;
13395 u32 freq;
13396 s32 err = 0;
13397 gfp_t aflags;
13398 u8 tmp_buf[IEEE80211_MAX_SSID_LEN + 1];
13399 chanspec_t chanspec;
13400 #ifdef CONFIG_AP6XXX_WIFI6_HDF
13401 struct InnerBssInfo innerBssInfo;
13402 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13403 #endif
13404 if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
13405 WL_DBG(("Beacon is larger than buffer. Discarding\n"));
13406 return err;
13407 }
13408
13409 if (bi->SSID_len > IEEE80211_MAX_SSID_LEN) {
13410 WL_ERR(("wrong SSID len:%d\n", bi->SSID_len));
13411 return -EINVAL;
13412 }
13413
13414 aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
13415 notif_bss_info = (struct wl_cfg80211_bss_info *)MALLOCZ(cfg->osh,
13416 sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13417 if (unlikely(!notif_bss_info)) {
13418 WL_ERR(("notif_bss_info alloc failed\n"));
13419 return -ENOMEM;
13420 }
13421 mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
13422 chanspec = wl_chspec_driver_to_host(bi->chanspec);
13423 notif_bss_info->channel = wf_chspec_ctlchan(chanspec);
13424
13425 if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
13426 band = wiphy->bands[IEEE80211_BAND_2GHZ];
13427 else
13428 band = wiphy->bands[IEEE80211_BAND_5GHZ];
13429 if (!band) {
13430 WL_ERR(("No valid band\n"));
13431 MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
13432 + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13433 return -EINVAL;
13434 }
13435 notif_bss_info->rssi = dtoh16(bi->RSSI);
13436 #if defined(RSSIAVG)
13437 notif_bss_info->rssi = wl_get_avg_rssi(&cfg->g_rssi_cache_ctrl, &bi->BSSID);
13438 if (notif_bss_info->rssi == RSSI_MINVAL)
13439 notif_bss_info->rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
13440 #endif
13441 #if defined(RSSIOFFSET)
13442 notif_bss_info->rssi = wl_update_rssi_offset(bcmcfg_to_prmry_ndev(cfg), notif_bss_info->rssi);
13443 #endif
13444 #if !defined(RSSIAVG) && !defined(RSSIOFFSET)
13445 // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
13446 notif_bss_info->rssi = MIN(notif_bss_info->rssi, RSSI_MAXVAL);
13447 #endif
13448 memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
13449 mgmt_type = cfg->active_scan ?
13450 IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
13451 if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
13452 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type);
13453 }
13454 beacon_proberesp = cfg->active_scan ?
13455 (struct beacon_proberesp *)&mgmt->u.probe_resp :
13456 (struct beacon_proberesp *)&mgmt->u.beacon;
13457 beacon_proberesp->timestamp = 0;
13458 beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
13459 beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
13460 wl_rst_ie(cfg);
13461 wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, update_ssid);
13462 wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
13463 wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX -
13464 offsetof(struct wl_cfg80211_bss_info, frame_buf));
13465 notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
13466 u.beacon.variable) + wl_get_ielen(cfg);
13467 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
13468 freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
13469 (void)band->band;
13470 #else
13471 freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
13472 #endif // endif
13473 if (freq == 0) {
13474 WL_ERR(("Invalid channel, fail to change channel to freq\n"));
13475 MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
13476 + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13477 return -EINVAL;
13478 }
13479 channel = ieee80211_get_channel(wiphy, freq);
13480 memcpy(tmp_buf, bi->SSID, bi->SSID_len);
13481 tmp_buf[bi->SSID_len] = '\0';
13482 WL_SCAN(("###0331###BSSID %pM, channel %3d(%3d %3sMHz), rssi %3d, capa 0x%-4x, mgmt_type %d, "
13483 "frame_len %3d, SSID \"%s\"\n",
13484 &bi->BSSID, notif_bss_info->channel, CHSPEC_CHANNEL(chanspec),
13485 CHSPEC_IS20(chanspec)?"20":
13486 CHSPEC_IS40(chanspec)?"40":
13487 CHSPEC_IS80(chanspec)?"80":
13488 CHSPEC_IS160(chanspec)?"160":"??",
13489 notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type,
13490 notif_bss_info->frame_len, tmp_buf));
13491 if (unlikely(!channel)) {
13492 WL_ERR(("ieee80211_get_channel error, freq=%d, channel=%d\n",
13493 freq, notif_bss_info->channel));
13494 MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
13495 + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13496 return -EINVAL;
13497 }
13498
13499 signal = notif_bss_info->rssi*100;
13500 if (!mgmt->u.probe_resp.timestamp) {
13501 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13502 struct osl_timespec ts;
13503 osl_get_monotonic_boottime(&ts);
13504 mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000)
13505 + ts.tv_nsec / 1000;
13506 #else
13507 struct osl_timespec tv;
13508 osl_do_gettimeofday(&tv);
13509 mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000)
13510 + tv.tv_usec;
13511 #endif // endif
13512 }
13513
13514 cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
13515 le16_to_cpu(notif_bss_info->frame_len), signal, aflags);
13516 if (unlikely(!cbss)) {
13517 WL_ERR(("cfg80211_inform_bss_frame error bssid " MACDBG " channel %d \n",
13518 MAC2STRDBG((u8*)(&bi->BSSID)), notif_bss_info->channel));
13519 err = -EINVAL;
13520 goto out_err;
13521 }
13522
13523 CFG80211_PUT_BSS(wiphy, cbss);
13524 #ifdef CONFIG_AP6XXX_WIFI6_HDF
13525 innerBssInfo.channel = channel;
13526 innerBssInfo.signal = signal;
13527 innerBssInfo.freq = freq;
13528 innerBssInfo.mgmt = mgmt;
13529 innerBssInfo.mgmtLen = notif_bss_info->frame_len;
13530 HdfInformBssFrameEventCallback(ndev, &innerBssInfo);
13531 #endif
13532 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID) &&
13533 (cfg->sched_scan_req && !cfg->scan_request)) {
13534 alloc_len = sizeof(log_conn_event_t) + IEEE80211_MAX_SSID_LEN + sizeof(uint16) +
13535 sizeof(int16);
13536 event_data = (log_conn_event_t *)MALLOCZ(dhdp->osh, alloc_len);
13537 if (!event_data) {
13538 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
13539 "length(%d)\n", __func__, alloc_len));
13540 goto out_err;
13541 }
13542 tlv_len = 3 * sizeof(tlv_log);
13543 event_data->tlvs = (tlv_log *)MALLOCZ(cfg->osh, tlv_len);
13544 if (!event_data->tlvs) {
13545 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
13546 "length(%d)\n", __func__, tlv_len));
13547 goto free_evt_data;
13548 }
13549
13550 payload_len = sizeof(log_conn_event_t);
13551 event_data->event = WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND;
13552 tlv_data = event_data->tlvs;
13553
13554 /* ssid */
13555 tlv_data->tag = WIFI_TAG_SSID;
13556 tlv_data->len = bi->SSID_len;
13557 memcpy(tlv_data->value, bi->SSID, bi->SSID_len);
13558 payload_len += TLV_LOG_SIZE(tlv_data);
13559 tlv_data = TLV_LOG_NEXT(tlv_data);
13560
13561 /* channel */
13562 tlv_data->tag = WIFI_TAG_CHANNEL;
13563 tlv_data->len = sizeof(uint16);
13564 memcpy(tlv_data->value, ¬if_bss_info->channel, sizeof(uint16));
13565 payload_len += TLV_LOG_SIZE(tlv_data);
13566 tlv_data = TLV_LOG_NEXT(tlv_data);
13567
13568 /* rssi */
13569 tlv_data->tag = WIFI_TAG_RSSI;
13570 tlv_data->len = sizeof(int16);
13571 memcpy(tlv_data->value, ¬if_bss_info->rssi, sizeof(int16));
13572 payload_len += TLV_LOG_SIZE(tlv_data);
13573 tlv_data = TLV_LOG_NEXT(tlv_data);
13574
13575 dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
13576 event_data, payload_len);
13577 MFREE(dhdp->osh, event_data->tlvs, tlv_len);
13578 free_evt_data:
13579 MFREE(dhdp->osh, event_data, alloc_len);
13580 }
13581
13582 out_err:
13583 MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
13584 + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13585 return err;
13586 }
13587
wl_is_linkup(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e,struct net_device * ndev)13588 static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev)
13589 {
13590 u32 event = ntoh32(e->event_type);
13591 u32 status = ntoh32(e->status);
13592 u16 flags = ntoh16(e->flags);
13593 #if defined(CUSTOM_SET_ANTNPM)
13594 dhd_pub_t *dhd;
13595 dhd = (dhd_pub_t *)(cfg->pub);
13596 #endif // endif
13597
13598 WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
13599 if (event == WLC_E_SET_SSID) {
13600 if (status == WLC_E_STATUS_SUCCESS) {
13601 #ifdef CUSTOM_SET_ANTNPM
13602 if (dhd->mimo_ant_set) {
13603 int err = 0;
13604
13605 WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhd->mimo_ant_set));
13606 err = wldev_iovar_setint(ndev, "txchain", dhd->mimo_ant_set);
13607 if (err != 0) {
13608 WL_ERR(("[WIFI_SEC] Fail set txchain\n"));
13609 }
13610 err = wldev_iovar_setint(ndev, "rxchain", dhd->mimo_ant_set);
13611 if (err != 0) {
13612 WL_ERR(("[WIFI_SEC] Fail set rxchain\n"));
13613 }
13614 }
13615 #endif /* CUSTOM_SET_ANTNPM */
13616 if (!wl_is_ibssmode(cfg, ndev))
13617 return true;
13618 }
13619 } else if (event == WLC_E_LINK) {
13620 if (flags & WLC_EVENT_MSG_LINK)
13621 return true;
13622 }
13623
13624 WL_DBG(("wl_is_linkup false\n"));
13625 return false;
13626 }
13627
wl_is_linkdown(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)13628 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13629 {
13630 u32 event = ntoh32(e->event_type);
13631 u16 flags = ntoh16(e->flags);
13632
13633 if (event == WLC_E_DEAUTH_IND ||
13634 event == WLC_E_DISASSOC_IND ||
13635 event == WLC_E_DISASSOC ||
13636 event == WLC_E_DEAUTH) {
13637 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
13638 return true;
13639 } else if (event == WLC_E_LINK) {
13640 if (!(flags & WLC_EVENT_MSG_LINK)) {
13641 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
13642 return true;
13643 }
13644 }
13645
13646 return false;
13647 }
13648
wl_is_nonetwork(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)13649 static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13650 {
13651 u32 event = ntoh32(e->event_type);
13652 u32 status = ntoh32(e->status);
13653
13654 if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS)
13655 return true;
13656 if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
13657 return true;
13658 if (event == WLC_E_ASSOC_RESP_IE && status != WLC_E_STATUS_SUCCESS)
13659 return true;
13660
13661 return false;
13662 }
13663
13664 #ifdef WL_SAE
13665 static s32
wl_cfg80211_event_sae_key(struct bcm_cfg80211 * cfg,struct net_device * ndev,wl_sae_key_info_t * sae_key)13666 wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13667 wl_sae_key_info_t *sae_key)
13668 {
13669 struct sk_buff *skb;
13670 gfp_t kflags;
13671 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13672 int err = BCME_OK;
13673
13674 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
13675 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
13676 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
13677 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), BRCM_SAE_VENDOR_EVENT_BUF_LEN,
13678 BRCM_VENDOR_EVENT_SAE_KEY, kflags);
13679 #else
13680 skb = cfg80211_vendor_event_alloc(wiphy, BRCM_SAE_VENDOR_EVENT_BUF_LEN,
13681 BRCM_VENDOR_EVENT_SAE_KEY, kflags);
13682 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
13683 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
13684 if (!skb) {
13685 WL_ERR(("skb alloc failed"));
13686 err = BCME_NOMEM;
13687 goto done;
13688 }
13689
13690 WL_INFORM_MEM(("Received Sae Key event for "MACDBG" key length %x %x",
13691 MAC2STRDBG(sae_key->peer_mac), sae_key->pmk_len, sae_key->pmkid_len));
13692 nla_put(skb, BRCM_SAE_KEY_ATTR_PEER_MAC, ETHER_ADDR_LEN, sae_key->peer_mac);
13693 nla_put(skb, BRCM_SAE_KEY_ATTR_PMK, sae_key->pmk_len, sae_key->pmk);
13694 nla_put(skb, BRCM_SAE_KEY_ATTR_PMKID, sae_key->pmkid_len, sae_key->pmkid);
13695 cfg80211_vendor_event(skb, kflags);
13696
13697 done:
13698 return err;
13699 }
13700
13701 static s32
wl_bss_handle_sae_auth(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * event,void * data)13702 wl_bss_handle_sae_auth(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13703 const wl_event_msg_t *event, void *data)
13704 {
13705 int err = BCME_OK;
13706 uint status = ntoh32(event->status);
13707 wl_auth_event_t *auth_data;
13708 wl_sae_key_info_t sae_key;
13709 uint16 tlv_buf_len;
13710
13711 if (status == WLC_E_STATUS_SUCCESS) {
13712 auth_data = (wl_auth_event_t *)data;
13713 if (auth_data->version != WL_AUTH_EVENT_DATA_V1) {
13714 WL_ERR(("unknown auth event data version %x\n",
13715 auth_data->version));
13716 err = BCME_VERSION;
13717 goto done;
13718 }
13719
13720 tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V1;
13721
13722 /* check if PMK info present */
13723 sae_key.pmk = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13724 WL_AUTH_PMK_TLV_ID, &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
13725 if (!sae_key.pmk || !sae_key.pmk_len) {
13726 WL_ERR(("Mandatory PMK info not present"));
13727 err = BCME_NOTFOUND;
13728 goto done;
13729 }
13730 /* check if PMKID info present */
13731 sae_key.pmkid = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
13732 WL_AUTH_PMKID_TLV_ID, &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
13733 if (!sae_key.pmkid || !sae_key.pmkid_len) {
13734 WL_ERR(("Mandatory PMKID info not present\n"));
13735 err = BCME_NOTFOUND;
13736 goto done;
13737 }
13738 memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet, ETHER_ADDR_LEN);
13739 err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
13740 if (err) {
13741 WL_ERR(("Failed to event sae key info\n"));
13742 }
13743 } else {
13744 WL_ERR(("sae auth status failure:%d\n", status));
13745 }
13746 done:
13747 return err;
13748 }
13749 #endif /* WL_SAE */
13750
13751 static s32
wl_get_auth_assoc_status(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)13752 wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13753 const wl_event_msg_t *e, void *data)
13754 {
13755 u32 reason = ntoh32(e->reason);
13756 u32 event = ntoh32(e->event_type);
13757 #ifdef WL_SAE
13758 uint auth_type = ntoh32(e->auth_type);
13759 #endif /* WL_SAE */
13760 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13761 WL_DBG(("event type : %d, reason : %d\n", event, reason));
13762
13763 if (sec) {
13764 switch (event) {
13765 case WLC_E_ASSOC:
13766 case WLC_E_AUTH:
13767 case WLC_E_AUTH_IND:
13768 sec->auth_assoc_res_status = reason;
13769 #ifdef WL_SAE
13770 if ((event == WLC_E_AUTH || event == WLC_E_AUTH_IND) &&
13771 auth_type == DOT11_SAE) {
13772 wl_bss_handle_sae_auth(cfg, ndev, e, data);
13773 }
13774 #endif /* WL_SAE */
13775 break;
13776 default:
13777 break;
13778 }
13779 } else {
13780 WL_ERR(("sec is NULL\n"));
13781 }
13782 return 0;
13783 }
13784
13785 #ifdef WL_CLIENT_SAE
13786 static s32
wl_notify_connect_status_ap_auth(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)13787 wl_notify_connect_status_ap_auth(struct bcm_cfg80211 *cfg,
13788 struct net_device *ndev, const wl_event_msg_t *e, void *data)
13789 {
13790 bcm_struct_cfgdev *cfgdev = ndev_to_cfgdev(ndev);
13791 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13792 u8 bsscfgidx = e->bsscfgidx;
13793 u8 *mgmt_frame = NULL;
13794 u8 *body = NULL;
13795 u32 body_len = 0;
13796 s32 chan;
13797 u16 channel;
13798 struct ieee80211_supported_band *band;
13799 chanspec_t chanspec;
13800 s32 freq;
13801 struct ether_addr da;
13802 struct ether_addr bssid;
13803 u32 event = ntoh32(e->event_type);
13804 u32 reason = ntoh32(e->reason);
13805 u32 len = ntoh32(e->datalen);
13806 s32 err = 0;
13807
13808 if (!len) {
13809 WL_ERR(("event %s(%d) has no payload. status %d reason %d\n",
13810 bcmevent_get_name(event), event, ntoh32(e->status), reason));
13811 return 0;
13812 }
13813
13814 body = (u8 *)MALLOCZ(cfg->osh, len);
13815 if (body == NULL) {
13816 WL_ERR(("Failed to allocate body\n"));
13817 return WL_INVALID;
13818 }
13819 (void)memcpy_s(body, len, data, len);
13820
13821 err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
13822 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
13823 if (unlikely(err)) {
13824 WL_ERR(("Could not get cur_etheraddr %d\n", err));
13825 goto exit;
13826 }
13827 (void)memcpy_s(da.octet, ETHER_ADDR_LEN, cfg->ioctl_buf, ETHER_ADDR_LEN);
13828
13829 bzero(&bssid, sizeof(bssid));
13830 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
13831 if (unlikely(err)) {
13832 WL_ERR(("Could not get bssid %d\n", err));
13833 goto exit;
13834 }
13835
13836 err = wldev_iovar_getint(ndev, "chanspec", &chan);
13837 if (unlikely(err)) {
13838 WL_ERR(("Could not get chanspec %d\n", err));
13839 goto exit;
13840 }
13841 chanspec = wl_chspec_driver_to_host(chan);
13842 channel = wf_chspec_ctlchan(chanspec);
13843
13844 if (channel <= CH_MAX_2G_CHANNEL)
13845 band = wiphy->bands[IEEE80211_BAND_2GHZ];
13846 else
13847 band = wiphy->bands[IEEE80211_BAND_5GHZ];
13848 if (!band) {
13849 WL_ERR(("No valid band\n"));
13850 goto exit;
13851 }
13852
13853 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
13854 freq = ieee80211_channel_to_frequency(channel);
13855 #else
13856 freq = ieee80211_channel_to_frequency(channel, band->band);
13857 #endif
13858
13859 body_len = len;
13860 err = wl_frame_get_mgmt(cfg, FC_AUTH, &da, &e->addr, &bssid,
13861 &mgmt_frame, &len, body);
13862 if (!err) {
13863 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
13864 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0);
13865 #ifdef CONFIG_AP6XXX_WIFI6_HDF
13866 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame, len);
13867 #endif
13868 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
13869 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
13870 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
13871 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
13872 #else
13873 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
13874 #endif
13875 MFREE(cfg->osh, mgmt_frame, len);
13876 }
13877
13878 exit:
13879 if (body) {
13880 MFREE(cfg->osh, body, body_len);
13881 }
13882
13883 return err;
13884 }
13885 #endif /* WL_CLIENT_SAE */
13886
13887
13888 /* The mainline kernel >= 3.2.0 has support for indicating new/del station
13889 * to AP/P2P GO via events. If this change is backported to kernel for which
13890 * this driver is being built, then define WL_CFG80211_STA_EVENT. You
13891 * should use this new/del sta event mechanism for BRCM supplicant >= 22.
13892 */
13893 static s32
wl_notify_connect_status_ap(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)13894 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13895 const wl_event_msg_t *e, void *data)
13896 {
13897 s32 err = 0;
13898 u32 event = ntoh32(e->event_type);
13899 u32 reason = ntoh32(e->reason);
13900 u32 len = ntoh32(e->datalen);
13901 u32 status = ntoh32(e->status);
13902
13903 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
13904 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
13905 bool isfree = false;
13906 u8 *mgmt_frame;
13907 u8 bsscfgidx = e->bsscfgidx;
13908 s32 freq;
13909 s32 channel;
13910 u8 *body = NULL;
13911 u16 fc = 0;
13912 u32 body_len = 0;
13913
13914 struct ieee80211_supported_band *band;
13915 struct ether_addr da;
13916 struct ether_addr bssid;
13917 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13918 channel_info_t ci;
13919 u8 ioctl_buf[WLC_IOCTL_SMLEN];
13920 #else
13921 struct station_info sinfo;
13922 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
13923
13924 WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n",
13925 ndev->name, event, ntoh32(e->status), reason));
13926
13927 if (event == WLC_E_AUTH_IND) {
13928 wl_get_auth_assoc_status(cfg, ndev, e, data);
13929 return 0;
13930 }
13931 /* if link down, bsscfg is disabled. */
13932 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
13933 wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
13934 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
13935 WL_MSG(ndev->name, "AP mode link down !! \n");
13936 complete(&cfg->iface_disable);
13937 return 0;
13938 }
13939
13940 if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
13941 (reason == WLC_E_REASON_INITIAL_ASSOC) &&
13942 (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
13943 if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
13944 /* AP/GO brought up successfull in firmware */
13945 WL_MSG(ndev->name, "AP/GO Link up\n");
13946 wl_set_drv_status(cfg, AP_CREATED, ndev);
13947 OSL_SMP_WMB();
13948 wake_up_interruptible(&cfg->netif_change_event);
13949 #ifdef WL_BCNRECV
13950 /* check fakeapscan is in progress, if progress then abort */
13951 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
13952 #endif /* WL_BCNRECV */
13953 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_AP_ENABLED, NULL);
13954 return 0;
13955 }
13956 }
13957
13958 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
13959 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
13960 "event %s(%d) status %d reason %d\n",
13961 bcmevent_get_name(event), event, ntoh32(e->status), reason);
13962 }
13963
13964 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
13965 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
13966 WL_DBG(("Enter \n"));
13967 if (!len && (event == WLC_E_DEAUTH)) {
13968 len = 2; /* reason code field */
13969 data = &reason;
13970 }
13971 if (len) {
13972 body = (u8 *)MALLOCZ(cfg->osh, len);
13973 if (body == NULL) {
13974 WL_ERR(("Failed to allocate body\n"));
13975 return WL_INVALID;
13976 }
13977 }
13978 bzero(&bssid, ETHER_ADDR_LEN);
13979 WL_DBG(("Enter event %d ndev %p\n", event, ndev));
13980 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
13981 MFREE(cfg->osh, body, len);
13982 return WL_INVALID;
13983 }
13984 if (len)
13985 memcpy(body, data, len);
13986
13987 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
13988 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, NULL);
13989 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
13990 bzero(&bssid, sizeof(bssid));
13991 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
13992 switch (event) {
13993 case WLC_E_ASSOC_IND:
13994 fc = FC_ASSOC_REQ;
13995 break;
13996 case WLC_E_REASSOC_IND:
13997 fc = FC_REASSOC_REQ;
13998 break;
13999 case WLC_E_DISASSOC_IND:
14000 fc = FC_DISASSOC;
14001 break;
14002 case WLC_E_DEAUTH_IND:
14003 fc = FC_DISASSOC;
14004 break;
14005 case WLC_E_DEAUTH:
14006 fc = FC_DISASSOC;
14007 break;
14008 default:
14009 fc = 0;
14010 goto exit;
14011 }
14012 bzero(&ci, sizeof(ci));
14013 if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
14014 MFREE(cfg->osh, body, len);
14015 return err;
14016 }
14017
14018 channel = dtoh32(ci.hw_channel);
14019 if (channel <= CH_MAX_2G_CHANNEL)
14020 band = wiphy->bands[IEEE80211_BAND_2GHZ];
14021 else
14022 band = wiphy->bands[IEEE80211_BAND_5GHZ];
14023 if (!band) {
14024 WL_ERR(("No valid band\n"));
14025 if (body) {
14026 MFREE(cfg->osh, body, len);
14027 }
14028 return -EINVAL;
14029 }
14030 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
14031 freq = ieee80211_channel_to_frequency(channel);
14032 (void)band->band;
14033 #else
14034 freq = ieee80211_channel_to_frequency(channel, band->band);
14035 #endif // endif
14036 body_len = len;
14037 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
14038 &mgmt_frame, &len, body);
14039 if (err < 0)
14040 goto exit;
14041 isfree = true;
14042
14043 if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
14044 (event == WLC_E_DISASSOC_IND) ||
14045 ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
14046 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14047 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
14048 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14049 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame, len);
14050 #endif
14051 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14052 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14053 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14054 defined(WL_COMPAT_WIRELESS)
14055 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14056 #else
14057 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14058 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
14059 }
14060
14061 exit:
14062 if (isfree) {
14063 MFREE(cfg->osh, mgmt_frame, len);
14064 }
14065 if (body) {
14066 MFREE(cfg->osh, body, body_len);
14067 }
14068 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14069 memset(&sinfo, 0, sizeof(struct station_info));
14070 sinfo.filled = 0;
14071 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
14072 reason == DOT11_SC_SUCCESS) {
14073 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
14074 * STATION_INFO_ASSOC_REQ_IES flag
14075 */
14076 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
14077 sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
14078 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
14079 if (!data) {
14080 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
14081 return -EINVAL;
14082 }
14083 sinfo.assoc_req_ies = data;
14084 sinfo.assoc_req_ies_len = len;
14085 WL_MSG(ndev->name, "new sta event for "MACDBG "\n",
14086 MAC2STRDBG(e->addr.octet));
14087 wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
14088 WL_EXT_STATUS_STA_CONNECTED, (void *)&e->addr);
14089 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
14090 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14091 ChangNewSta(ndev,e->addr.octet,6,&sinfo);
14092 #endif
14093 #ifdef WL_WPS_SYNC
14094 wl_wps_session_update(ndev, WPS_STATE_LINKUP, e->addr.octet);
14095 #endif /* WL_WPS_SYNC */
14096 } else if ((event == WLC_E_DEAUTH_IND) ||
14097 ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
14098 (event == WLC_E_DISASSOC_IND)) {
14099 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14100 "del sta event for "MACDBG "\n", MAC2STRDBG(e->addr.octet));
14101 wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
14102 WL_EXT_STATUS_STA_DISCONNECTED, (void *)&e->addr);
14103 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
14104 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14105 ChangDelSta(ndev,e->addr.octet,6);
14106 #endif
14107 #ifdef WL_WPS_SYNC
14108 wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet);
14109 #endif /* WL_WPS_SYNC */
14110 }
14111 #ifdef WL_CLIENT_SAE
14112 else if (event == WLC_E_AUTH) {
14113 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14114 "add sta auth event for "MACDBG "\n", MAC2STRDBG(e->addr.octet));
14115 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14116 WL_ERR(("invalid mode\n"));
14117 return WL_INVALID;
14118 }
14119 err = wl_notify_connect_status_ap_auth(cfg, ndev, e, data);
14120 }
14121 #endif /* WL_CLIENT_SAE */
14122 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14123 return err;
14124 }
14125
14126 #ifdef WL_CLIENT_SAE
14127 static s32
wl_notify_start_auth(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)14128 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
14129 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
14130 {
14131 struct cfg80211_external_auth_params ext_auth_param;
14132 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14133 u32 datalen = be32_to_cpu(e->datalen);
14134 wl_ext_auth_evt_t *evt_data = (wl_ext_auth_evt_t *)data;
14135 wl_assoc_mgr_cmd_t cmd;
14136 int err;
14137
14138 WL_DBG(("Enter\n"));
14139
14140 if (!datalen || !data)
14141 return BCME_ERROR;
14142
14143 ext_auth_param.ssid.ssid_len = MIN(evt_data->ssid.SSID_len, DOT11_MAX_SSID_LEN);
14144 if (ext_auth_param.ssid.ssid_len)
14145 memcpy(&ext_auth_param.ssid.ssid, evt_data->ssid.SSID,
14146 ext_auth_param.ssid.ssid_len);
14147
14148 memcpy(&ext_auth_param.bssid, &evt_data->bssid, ETHER_ADDR_LEN);
14149 ext_auth_param.action = NL80211_EXTERNAL_AUTH_START;
14150 ext_auth_param.key_mgmt_suite = ntoh32(WLAN_AKM_SUITE_SAE_SHA256);
14151
14152 WL_MSG(ndev->name, "BSSID: "MACDBG"\n", MAC2STRDBG(&evt_data->bssid));
14153
14154 err = cfg80211_external_auth_request(ndev, &ext_auth_param, GFP_KERNEL);
14155 if (unlikely(err)) {
14156 WL_ERR(("Failed to notify external auth req(%d)\n", err));
14157 }
14158
14159 cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
14160 cmd.length = sizeof(cmd);
14161 cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
14162 cmd.params = WL_ASSOC_MGR_PARAMS_PAUSE_EVENT_AUTH_RESP;
14163 err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd),
14164 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
14165 if (unlikely(err)) {
14166 WL_ERR(("Failed to pause assoc(%d)\n", err));
14167 }
14168
14169 return BCME_OK;
14170 }
14171
14172 static s32
wl_notify_connect_status_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14173 wl_notify_connect_status_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14174 const wl_event_msg_t *e, void *data)
14175 {
14176 s32 err = 0;
14177 u32 event = ntoh32(e->event_type);
14178 u32 reason = ntoh32(e->reason);
14179 u32 len = ntoh32(e->datalen);
14180 u32 status = ntoh32(e->status);
14181
14182 bool isfree = false;
14183 u8 *mgmt_frame;
14184 u8 bsscfgidx = e->bsscfgidx;
14185 s32 freq;
14186 s32 channel;
14187 u8 *body = NULL;
14188 u16 fc = 0, rssi = 0;
14189 bcm_struct_cfgdev *cfgdev = ndev_to_cfgdev(ndev);
14190
14191 struct ieee80211_supported_band *band;
14192 struct ether_addr da;
14193 struct ether_addr bssid;
14194 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14195 channel_info_t ci;
14196
14197 WL_DBG(("event %d status %d reason %d\n", event, status, reason));
14198
14199 if (event == WLC_E_AUTH) {
14200 struct wl_security *sec;
14201 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14202
14203 if (!(sec->auth_type == NL80211_AUTHTYPE_SAE)) {
14204 WL_DBG(("Abort AUTH processing due to NOT SAE\n"));
14205 return 0;
14206 } else {
14207 if (status != WLC_E_STATUS_SUCCESS && !len) {
14208 WL_ERR(("SAE AUTH FAIL EVENT\n"));
14209 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
14210 WL_EXT_STATUS_DISCONNECTED, NULL);
14211 return 0;
14212 }
14213 }
14214 }
14215
14216 if (!len && (event == WLC_E_DEAUTH)) {
14217 len = 2; /* reason code field */
14218 data = &reason;
14219 }
14220
14221 if (len) {
14222 body = kzalloc(len, GFP_KERNEL);
14223 if (body == NULL) {
14224 WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
14225 return WL_INVALID;
14226 }
14227 }
14228
14229 memset(&bssid, 0, ETHER_ADDR_LEN);
14230 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14231 kfree(body);
14232 return WL_INVALID;
14233 }
14234 if (len)
14235 memcpy(body, data, len);
14236
14237 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
14238 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
14239 memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
14240 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14241 /* Use e->addr as bssid for Sta case , before association completed */
14242 if (err == BCME_NOTASSOCIATED)
14243 memcpy(&bssid, &e->addr, ETHER_ADDR_LEN);
14244
14245 switch (event) {
14246 case WLC_E_ASSOC_IND:
14247 fc = FC_ASSOC_REQ;
14248 break;
14249 case WLC_E_REASSOC_IND:
14250 fc = FC_REASSOC_REQ;
14251 break;
14252 case WLC_E_DISASSOC_IND:
14253 fc = FC_DISASSOC;
14254 break;
14255 case WLC_E_DEAUTH_IND:
14256 fc = FC_DISASSOC;
14257 break;
14258 case WLC_E_DEAUTH:
14259 fc = FC_DISASSOC;
14260 break;
14261 case WLC_E_AUTH:
14262 fc = FC_AUTH;
14263 break;
14264 default:
14265 fc = 0;
14266 goto exit;
14267 }
14268 if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
14269 kfree(body);
14270 return err;
14271 }
14272
14273 channel = dtoh32(ci.hw_channel);
14274 if (channel <= CH_MAX_2G_CHANNEL)
14275 band = wiphy->bands[IEEE80211_BAND_2GHZ];
14276 else
14277 band = wiphy->bands[IEEE80211_BAND_5GHZ];
14278 if (!band) {
14279 WL_ERR(("No valid band\n"));
14280 if (body)
14281 kfree(body);
14282 return -EINVAL;
14283 }
14284 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
14285 freq = ieee80211_channel_to_frequency(channel);
14286 (void)band->band;
14287 #else
14288 freq = ieee80211_channel_to_frequency(channel, band->band);
14289 #endif
14290
14291 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
14292 &mgmt_frame, &len, body);
14293 if (err < 0) {
14294 goto exit;
14295 }
14296 isfree = true;
14297
14298 if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
14299 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14300 cfg80211_rx_mgmt(cfgdev, freq, rssi, mgmt_frame, len, 0);
14301 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14302 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, rssi, mgmt_frame, len);
14303 #endif
14304 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14305 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14306 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14307 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14308 #else
14309 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14310 #endif
14311 } else if (event == WLC_E_DISASSOC_IND) {
14312 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14313 cfg80211_rx_mgmt(cfgdev, freq, rssi, mgmt_frame, len, 0);
14314 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14315 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, rssi, mgmt_frame, len);
14316 #endif
14317 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14318 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14319 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14320 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14321 #else
14322 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14323 #endif
14324 } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
14325 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14326 cfg80211_rx_mgmt(cfgdev, freq, rssi, mgmt_frame, len, 0);
14327 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14328 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, rssi, mgmt_frame, len);
14329 #endif
14330 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14331 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14332 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14333 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14334 #else
14335 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14336 #endif
14337 } else if (event == WLC_E_AUTH) {
14338 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14339 cfg80211_rx_mgmt(cfgdev, freq, rssi, mgmt_frame, len, 0);
14340 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14341 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, rssi, mgmt_frame, len);
14342 #endif
14343 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14344 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14345 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
14346 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14347 #else
14348 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14349 #endif
14350 }
14351 exit:
14352 if (isfree)
14353 kfree(mgmt_frame);
14354 if (body)
14355 kfree(body);
14356 return err;
14357 }
14358 #endif /* WL_CLIENT_SAE */
14359
14360 static s32
wl_notify_connect_status_ibss(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14361 wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14362 const wl_event_msg_t *e, void *data)
14363 {
14364 s32 err = 0;
14365 u32 event = ntoh32(e->event_type);
14366 u16 flags = ntoh16(e->flags);
14367 u32 status = ntoh32(e->status);
14368 bool active;
14369 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14370 struct ieee80211_channel *channel = NULL;
14371 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14372 u32 chanspec, chan;
14373 u32 freq, band;
14374 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14375
14376 if (event == WLC_E_JOIN) {
14377 WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev->name));
14378 }
14379 if (event == WLC_E_START) {
14380 WL_INFORM_MEM(("[%s] started IBSS network\n", ndev->name));
14381 }
14382 if (event == WLC_E_JOIN || event == WLC_E_START ||
14383 (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
14384 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14385 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
14386 if (unlikely(err)) {
14387 WL_ERR(("Could not get chanspec %d\n", err));
14388 return err;
14389 }
14390 chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
14391 band = (chan <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
14392 freq = ieee80211_channel_to_frequency(chan, band);
14393 channel = ieee80211_get_channel(wiphy, freq);
14394 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14395 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
14396 /* ROAM or Redundant */
14397 u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14398 if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
14399 WL_DBG(("IBSS connected event from same BSSID("
14400 MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
14401 return err;
14402 }
14403 WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
14404 ndev->name, MAC2STRDBG(cur_bssid),
14405 MAC2STRDBG((const u8 *)&e->addr)));
14406 wl_get_assoc_ies(cfg, ndev);
14407 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14408 wl_update_bss_info(cfg, ndev, false);
14409 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14410 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
14411 #else
14412 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
14413 #endif // endif
14414 }
14415 else {
14416 /* New connection */
14417 WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG "\n",
14418 ndev->name, MAC2STRDBG((const u8 *)&e->addr)));
14419 wl_link_up(cfg);
14420 wl_get_assoc_ies(cfg, ndev);
14421 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14422 wl_update_bss_info(cfg, ndev, false);
14423 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14424 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
14425 #else
14426 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
14427 #endif // endif
14428 wl_set_drv_status(cfg, CONNECTED, ndev);
14429 active = true;
14430 wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
14431 }
14432 } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
14433 event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
14434 wl_clr_drv_status(cfg, CONNECTED, ndev);
14435 wl_link_down(cfg);
14436 wl_init_prof(cfg, ndev);
14437 }
14438 else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
14439 WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
14440 }
14441 else {
14442 WL_DBG(("no action (IBSS mode)\n"));
14443 }
14444 return err;
14445 }
14446
wl_cfg80211_disassoc(struct net_device * ndev,uint32 reason)14447 void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason)
14448 {
14449 scb_val_t scbval;
14450 s32 err;
14451 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14452 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14453
14454 BCM_REFERENCE(cfg);
14455 BCM_REFERENCE(dhdp);
14456 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
14457 dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
14458
14459 memset_s(&scbval, sizeof(scb_val_t), 0x0, sizeof(scb_val_t));
14460 scbval.val = htod32(reason);
14461 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
14462 if (err < 0) {
14463 WL_ERR(("WLC_DISASSOC error %d\n", err));
14464 }
14465 }
wl_cfg80211_del_all_sta(struct net_device * ndev,uint32 reason)14466 void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason)
14467 {
14468 struct net_device *dev;
14469 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14470 scb_val_t scb_val;
14471 int err;
14472 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
14473 sizeof(struct ether_addr) + sizeof(uint)] = {0};
14474 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
14475 int num_associated = 0;
14476
14477 dev = ndev_to_wlc_ndev(ndev, cfg);
14478
14479 if (p2p_is_on(cfg)) {
14480 /* Suspend P2P discovery search-listen to prevent it from changing the
14481 * channel.
14482 */
14483 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
14484 WL_ERR(("Can not disable discovery mode\n"));
14485 return;
14486 }
14487 }
14488
14489 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
14490 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
14491 assoc_maclist, sizeof(mac_buf));
14492 if (err < 0)
14493 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
14494 else
14495 num_associated = assoc_maclist->count;
14496
14497 memset(scb_val.ea.octet, 0xff, ETHER_ADDR_LEN);
14498 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
14499 scb_val.val = htod32(reason);
14500 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
14501 sizeof(scb_val_t));
14502 if (err < 0) {
14503 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
14504 }
14505
14506 if (num_associated > 0)
14507 wl_delay(400);
14508
14509 return;
14510 }
14511 /* API to handle the Deauth from the AP.
14512 * For now we are deleting the PMKID cache in DHD/FW
14513 * in case of current connection is using SAE authnetication
14514 */
14515 static s32
wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14516 wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14517 const wl_event_msg_t *e, void *data)
14518 {
14519 int err = BCME_OK;
14520 #ifdef WL_SAE
14521 uint8 bssid[ETHER_ADDR_LEN];
14522 struct cfg80211_pmksa pmksa;
14523 s32 val = 0;
14524
14525 err = wldev_iovar_getint(ndev, "wpa_auth", &val);
14526 if (unlikely(err)) {
14527 WL_ERR(("could not get wpa_auth (%d)\n", err));
14528 goto done;
14529 }
14530 if (val == WPA3_AUTH_SAE_PSK) {
14531 (void)memcpy_s(bssid, ETHER_ADDR_LEN,
14532 (const uint8*)&e->addr, ETHER_ADDR_LEN);
14533 memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
14534 pmksa.bssid = bssid;
14535 WL_INFORM_MEM(("Deleting the PMKSA for SAE AP "MACDBG,
14536 MAC2STRDBG(e->addr.octet)));
14537 wl_cfg80211_del_pmksa(cfg->wdev->wiphy, ndev, &pmksa);
14538 }
14539 done:
14540 #endif /* WL_SAE */
14541 return err;
14542 }
14543
14544 static void
wl_cache_assoc_resp_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14545 wl_cache_assoc_resp_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14546 const wl_event_msg_t *e, void *data)
14547 {
14548 struct wl_connect_info *conn_info = wl_to_conn(cfg);
14549 u32 datalen = ntoh32(e->datalen);
14550 u32 event_type = ntoh32(e->event_type);
14551
14552 if (datalen > VNDR_IE_MIN_LEN &&
14553 datalen < VNDR_IE_MAX_LEN &&
14554 data) {
14555 conn_info->resp_ie_len = datalen;
14556 WL_DBG((" assoc resp IES len = %d\n", conn_info->resp_ie_len));
14557 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
14558 (void)memcpy_s(conn_info->resp_ie, sizeof(conn_info->resp_ie),
14559 data, datalen);
14560
14561 WL_INFORM_MEM(("[%s] copied assoc resp ies, sent to upper layer:"
14562 "event %d reason=%d ie_len=%d from " MACDBG "\n",
14563 ndev->name, event_type, ntoh32(e->reason), datalen,
14564 MAC2STRDBG((const u8*)(&e->addr))));
14565 }
14566 }
14567
14568 #ifdef WLMESH_CFG80211
14569 static s32
wl_notify_connect_status_mesh(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14570 wl_notify_connect_status_mesh(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14571 const wl_event_msg_t *e, void *data)
14572 {
14573 s32 err = 0;
14574 u32 event = ntoh32(e->event_type);
14575 u32 reason = ntoh32(e->reason);
14576 u32 len = ntoh32(e->datalen);
14577 u32 status = ntoh32(e->status);
14578
14579 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14580 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14581 bool isfree = false;
14582 u8 *mgmt_frame;
14583 u8 bsscfgidx = e->bsscfgidx;
14584 s32 freq;
14585 s32 channel;
14586 u8 *body = NULL;
14587 u16 fc = 0;
14588 u32 body_len = 0;
14589
14590 struct ieee80211_supported_band *band;
14591 struct ether_addr da;
14592 struct ether_addr bssid;
14593 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14594 channel_info_t ci;
14595 u8 ioctl_buf[WLC_IOCTL_SMLEN];
14596 #else
14597 struct station_info sinfo;
14598 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14599
14600 WL_INFORM_MEM(("[%s] Mode Mesh. Event:%d status:%d reason:%d\n",
14601 ndev->name, event, ntoh32(e->status), reason));
14602
14603 /* if link down, bsscfg is disabled. */
14604 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
14605 (ndev != bcmcfg_to_prmry_ndev(cfg))) {
14606 WL_MSG(ndev->name, "Mesh mode link down !! \n");
14607 return 0;
14608 }
14609
14610 if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
14611 (reason == WLC_E_REASON_INITIAL_ASSOC)) {
14612 /* AP/GO brought up successfull in firmware */
14613 WL_MSG(ndev->name, "Mesh Link up\n");
14614 return 0;
14615 }
14616
14617 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
14618 WL_MSG(ndev->name, "event %s(%d) status %d reason %d\n",
14619 bcmevent_get_name(event), event, ntoh32(e->status), reason);
14620 }
14621
14622 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14623 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14624 WL_DBG(("Enter \n"));
14625 if (!len && (event == WLC_E_DEAUTH)) {
14626 len = 2; /* reason code field */
14627 data = &reason;
14628 }
14629 if (len) {
14630 body = (u8 *)MALLOCZ(cfg->osh, len);
14631 if (body == NULL) {
14632 WL_ERR(("Failed to allocate body\n"));
14633 return WL_INVALID;
14634 }
14635 }
14636 bzero(&bssid, ETHER_ADDR_LEN);
14637 WL_DBG(("Enter event %d ndev %p\n", event, ndev));
14638 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14639 MFREE(cfg->osh, body, len);
14640 return WL_INVALID;
14641 }
14642 if (len)
14643 memcpy(body, data, len);
14644
14645 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
14646 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx, NULL);
14647 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
14648 bzero(&bssid, sizeof(bssid));
14649 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14650 switch (event) {
14651 case WLC_E_ASSOC_IND:
14652 fc = FC_ASSOC_REQ;
14653 break;
14654 case WLC_E_REASSOC_IND:
14655 fc = FC_REASSOC_REQ;
14656 break;
14657 case WLC_E_DISASSOC_IND:
14658 fc = FC_DISASSOC;
14659 break;
14660 case WLC_E_DEAUTH_IND:
14661 fc = FC_DISASSOC;
14662 break;
14663 case WLC_E_DEAUTH:
14664 fc = FC_DISASSOC;
14665 break;
14666 default:
14667 fc = 0;
14668 goto exit;
14669 }
14670 bzero(&ci, sizeof(ci));
14671 if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
14672 MFREE(cfg->osh, body, len);
14673 return err;
14674 }
14675
14676 channel = dtoh32(ci.hw_channel);
14677 if (channel <= CH_MAX_2G_CHANNEL)
14678 band = wiphy->bands[IEEE80211_BAND_2GHZ];
14679 else
14680 band = wiphy->bands[IEEE80211_BAND_5GHZ];
14681 if (!band) {
14682 WL_ERR(("No valid band\n"));
14683 if (body) {
14684 MFREE(cfg->osh, body, len);
14685 }
14686 return -EINVAL;
14687 }
14688 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
14689 freq = ieee80211_channel_to_frequency(channel);
14690 (void)band->band;
14691 #else
14692 freq = ieee80211_channel_to_frequency(channel, band->band);
14693 #endif // endif
14694 body_len = len;
14695 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
14696 &mgmt_frame, &len, body);
14697 if (err < 0)
14698 goto exit;
14699 isfree = true;
14700
14701 if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
14702 (event == WLC_E_DISASSOC_IND) ||
14703 ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
14704 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14705 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
14706 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14707 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame, len);
14708 #endif
14709 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14710 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14711 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14712 defined(WL_COMPAT_WIRELESS)
14713 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14714 #else
14715 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14716 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
14717 }
14718
14719 exit:
14720 if (isfree) {
14721 MFREE(cfg->osh, mgmt_frame, len);
14722 }
14723 if (body) {
14724 MFREE(cfg->osh, body, body_len);
14725 }
14726 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14727 memset(&sinfo, 0, sizeof(struct station_info));
14728 sinfo.filled = 0;
14729 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
14730 reason == DOT11_SC_SUCCESS) {
14731 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
14732 * STATION_INFO_ASSOC_REQ_IES flag
14733 */
14734 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
14735 sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
14736 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
14737 if (!data) {
14738 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
14739 return -EINVAL;
14740 }
14741 sinfo.assoc_req_ies = data;
14742 sinfo.assoc_req_ies_len = len;
14743 WL_MSG(ndev->name, "new sta event for "MACDBG "\n",
14744 MAC2STRDBG(e->addr.octet));
14745 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
14746 } else if ((event == WLC_E_DEAUTH_IND) ||
14747 ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
14748 (event == WLC_E_DISASSOC_IND)) {
14749 WL_MSG(ndev->name, "del sta event for "MACDBG "\n",
14750 MAC2STRDBG(e->addr.octet));
14751 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
14752 }
14753 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14754 return err;
14755 }
14756 #endif /* WLMESH_CFG80211 */
14757
14758 #ifdef CONFIG_AP6XXX_WIFI6_HDF
wl_notify_connect_sta_status(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data,bool completed,struct cfg80211_bss * bss)14759 static s32 wl_notify_connect_sta_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14760 const wl_event_msg_t *e, void *data, bool completed, struct cfg80211_bss *bss)
14761 {
14762 uint8_t *curbssid = NULL;
14763 uint16_t connectStatus = 0;
14764 uint16_t freq = 0;
14765 struct wl_connect_info *conn_info = NULL;
14766 struct InnerConnetResult innerConnResult;
14767 conn_info = wl_to_conn(cfg);
14768 curbssid = (uint8_t *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14769
14770 if(completed) {
14771 connectStatus = 0;
14772 } else {
14773 connectStatus = 1;
14774 }
14775
14776 if(bss != NULL) {
14777 if(bss->channel != NULL) {
14778 freq = bss->channel->center_freq;
14779 }
14780 }
14781
14782 innerConnResult.bssid = curbssid;
14783 innerConnResult.reqIe = conn_info->req_ie;
14784 innerConnResult.rspIe = conn_info->resp_ie;
14785 innerConnResult.reqIeLen = conn_info->req_ie_len;
14786 innerConnResult.rspIeLen = conn_info->resp_ie_len;
14787 innerConnResult.freq = freq;
14788 innerConnResult.statusCode = connectStatus;
14789 innerConnResult.connectStatus = connectStatus;
14790 HdfConnectResultEventCallback(ndev, &innerConnResult);
14791
14792 return 0;
14793 }
14794 #endif
14795
14796 static s32
wl_notify_connect_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)14797 wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14798 const wl_event_msg_t *e, void *data)
14799 {
14800 bool act;
14801 struct net_device *ndev = NULL;
14802 s32 err = 0;
14803 u32 event = ntoh32(e->event_type);
14804 u32 datalen = ntoh32(e->datalen);
14805 struct wiphy *wiphy = NULL;
14806 struct cfg80211_bss *bss = NULL;
14807 struct wlc_ssid *ssid = NULL;
14808 u8 *bssid = 0;
14809 s32 bssidx = 0;
14810 u8 *ie_ptr = NULL;
14811 uint32 ie_len = 0;
14812 #ifdef WL_ANALYTICS
14813 struct parsed_vndr_ies disco_vndr_ie;
14814 struct parsed_vndr_ie_info *vndrie_info = NULL;
14815 uint32 i = 0;
14816 #endif /* WL_ANALYTICS */
14817
14818 dhd_pub_t *dhdp;
14819 u32 mode;
14820 int vndr_oui_num = 0;
14821 char vndr_oui[MAX_VNDR_OUI_STR_LEN] = {0, };
14822 bool loc_gen = false;
14823 #ifdef DHD_LOSSLESS_ROAMING
14824 struct wl_security *sec;
14825 #endif /* DHD_LOSSLESS_ROAMING */
14826
14827 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14828 #ifdef DHD_LOSSLESS_ROAMING
14829 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14830 #endif /* DHD_LOSSLESS_ROAMING */
14831 dhdp = (dhd_pub_t *)(cfg->pub);
14832 BCM_REFERENCE(dhdp);
14833
14834 mode = wl_get_mode_by_netdev(cfg, ndev);
14835 /* Push link events to upper layer log */
14836 SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n",
14837 ndev->name, mode, ntoh32(e->event_type),
14838 ntoh32(e->status), ntoh32(e->reason)));
14839 if (mode == WL_MODE_AP) {
14840 err = wl_notify_connect_status_ap(cfg, ndev, e, data);
14841 #ifdef WLMESH_CFG80211
14842 } else if (mode == WL_MODE_MESH) {
14843 err = wl_notify_connect_status_mesh(cfg, ndev, e, data);
14844 #endif /* WLMESH_CFG80211 */
14845 } else if (mode == WL_MODE_IBSS) {
14846 err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
14847 } else if (mode == WL_MODE_BSS) {
14848 WL_INFORM_MEM(("[%s] Mode BSS. event:%d status:%d reason:%d\n",
14849 ndev->name, ntoh32(e->event_type),
14850 ntoh32(e->status), ntoh32(e->reason)));
14851
14852 if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
14853 /* Join attempt via non-cfg80211 interface.
14854 * Don't send resultant events to cfg80211
14855 * layer
14856 */
14857 WL_INFORM_MEM(("Event received in non-cfg80211"
14858 " connect state. Ignore\n"));
14859 return BCME_OK;
14860 }
14861 #ifdef WL_CLIENT_SAE
14862 if (event == WLC_E_AUTH)
14863 wl_notify_connect_status_bss(cfg, ndev, e, data);
14864 #endif /* WL_CLIENT_SAE */
14865
14866 if (event == WLC_E_ASSOC || event == WLC_E_AUTH) {
14867 wl_get_auth_assoc_status(cfg, ndev, e, data);
14868 return 0;
14869 }
14870 if (event == WLC_E_ASSOC_RESP_IE) {
14871 if (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) {
14872 wl_cache_assoc_resp_ies(cfg, ndev, e, data);
14873 }
14874 return 0;
14875 }
14876
14877 DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
14878 if (wl_is_linkup(cfg, e, ndev)) {
14879 wl_link_up(cfg);
14880 act = true;
14881 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
14882 WL_INFORM_MEM(("[%s] link up for bssid " MACDBG "\n",
14883 ndev->name, MAC2STRDBG((const u8*)(&e->addr))));
14884 if ((event == WLC_E_LINK) &&
14885 (ntoh16(e->flags) & WLC_EVENT_MSG_LINK) &&
14886 !wl_get_drv_status(cfg, CONNECTED, ndev) &&
14887 !wl_get_drv_status(cfg, CONNECTING, ndev)) {
14888 WL_INFORM_MEM(("link up in non-connected/"
14889 "non-connecting state\n"));
14890 wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
14891 return BCME_OK;
14892 }
14893
14894 #ifdef WL_WPS_SYNC
14895 /* Avoid invocation for Roam cases */
14896 if ((event == WLC_E_LINK) &&
14897 !wl_get_drv_status(cfg, CONNECTED, ndev)) {
14898 wl_wps_session_update(ndev,
14899 WPS_STATE_LINKUP, e->addr.octet);
14900 }
14901 #endif /* WL_WPS_SYNC */
14902
14903 if (event == WLC_E_LINK &&
14904 #ifdef DHD_LOSSLESS_ROAMING
14905 !cfg->roam_offload &&
14906 !IS_AKM_SUITE_FT(sec) &&
14907 #endif /* DHD_LOSSLESS_ROAMING */
14908 wl_get_drv_status(cfg, CONNECTED, ndev)) {
14909 wl_bss_roaming_done(cfg, ndev, e, data);
14910 /* Arm pkt logging timer */
14911 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
14912 } else {
14913 /* Initial Association */
14914 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
14915 wl_bss_connect_done(cfg, ndev, e, data, true);
14916 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
14917 vndr_oui_num = wl_vndr_ies_get_vendor_oui(cfg,
14918 ndev, vndr_oui, ARRAY_SIZE(vndr_oui));
14919 if (vndr_oui_num > 0) {
14920 WL_INFORM_MEM(("[%s] vendor oui: %s\n",
14921 ndev->name, vndr_oui));
14922 }
14923 }
14924 if (event == WLC_E_LINK) {
14925 /* Arm pkt logging timer */
14926 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_CONNECT);
14927 }
14928 WL_DBG(("joined in BSS network \"%s\"\n",
14929 ((struct wlc_ssid *)wl_read_prof(cfg, ndev,
14930 WL_PROF_SSID))->SSID));
14931 }
14932 }
14933 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
14934 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
14935 } else if (wl_is_linkdown(cfg, e) ||
14936 ((event == WLC_E_SET_SSID) &&
14937 (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) &&
14938 (wl_get_drv_status(cfg, CONNECTED, ndev)))) {
14939 if (wl_is_linkdown(cfg, e)) {
14940 /* Clear IEs for disaasoc */
14941 if ((bssidx = wl_get_bssidx_by_wdev(cfg,
14942 ndev->ieee80211_ptr)) < 0) {
14943 WL_ERR(("Find index failed\n"));
14944 } else {
14945 WL_ERR(("link down--clearing disconnect IEs\n"));
14946 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
14947 ndev_to_cfgdev(ndev), bssidx, VNDR_IE_DISASSOC_FLAG,
14948 NULL, 0)) != BCME_OK) {
14949 WL_ERR(("Failed to clear ies err = %d\n", err));
14950 }
14951 }
14952 }
14953
14954 WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n",
14955 wl_get_drv_status(cfg, CONNECTING, ndev),
14956 wl_get_drv_status(cfg, CONNECTED, ndev),
14957 wl_get_drv_status(cfg, DISCONNECTING, ndev),
14958 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
14959
14960 #ifdef WL_WPS_SYNC
14961 {
14962 u8 wps_state;
14963 if ((event == WLC_E_SET_SSID) &&
14964 (ntoh32(e->status) != WLC_E_STATUS_SUCCESS)) {
14965 /* connect fail */
14966 wps_state = WPS_STATE_CONNECT_FAIL;
14967 } else {
14968 wps_state = WPS_STATE_LINKDOWN;
14969 }
14970 if (wl_wps_session_update(ndev,
14971 wps_state, e->addr.octet) == BCME_UNSUPPORTED) {
14972 /* Unexpected event. Ignore it. */
14973 return 0;
14974 }
14975 }
14976 #endif /* WL_WPS_SYNC */
14977
14978 if (wl_get_drv_status(cfg, DISCONNECTING, ndev) &&
14979 (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) ||
14980 wl_get_drv_status(cfg, CONNECTING, ndev))) {
14981 /* wl_cfg80211_connect was called before 'DISCONNECTING' was
14982 * cleared. Deauth/Link down event is caused by WLC_DISASSOC
14983 * command issued from the wl_cfg80211_connect context. Ignore
14984 * the event to avoid pre-empting the current connection
14985 */
14986 WL_DBG(("Nested connection case. Drop event. \n"));
14987 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
14988 WL_EXT_STATUS_DISCONNECTED, NULL);
14989 wl_ext_iapsta_restart_master(ndev);
14990 wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
14991 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
14992 /* Not in 'CONNECTED' state, clear it */
14993 wl_clr_drv_status(cfg, CONNECTED, ndev);
14994 return 0;
14995 }
14996
14997 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
14998 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
14999 FW_LOGSET_MASK_ALL);
15000 }
15001 #ifdef DHD_LOSSLESS_ROAMING
15002 wl_del_roam_timeout(cfg);
15003 #endif // endif
15004 #ifdef P2PLISTEN_AP_SAMECHN
15005 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15006 wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0);
15007 cfg->p2p_resp_apchn_status = false;
15008 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
15009 }
15010 #endif /* P2PLISTEN_AP_SAMECHN */
15011 wl_cfg80211_cancel_scan(cfg);
15012
15013 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15014 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15015 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
15016 bool fw_assoc_state = TRUE;
15017 dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
15018 fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
15019 if (!fw_assoc_state) {
15020 WL_ERR(("Event sends up even different BSSID"
15021 " cur: " MACDBG " event: " MACDBG"\n",
15022 MAC2STRDBG(curbssid),
15023 MAC2STRDBG((const u8*)(&e->addr))));
15024 } else {
15025 WL_ERR(("BSSID of event is not the connected BSSID"
15026 "(ignore it) cur: " MACDBG
15027 " event: " MACDBG"\n",
15028 MAC2STRDBG(curbssid),
15029 MAC2STRDBG((const u8*)(&e->addr))));
15030 return 0;
15031 }
15032 }
15033 }
15034 /* Explicitly calling unlink to remove BSS in CFG */
15035 wiphy = bcmcfg_to_wiphy(cfg);
15036 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
15037 bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15038 if (ssid && bssid) {
15039 bss = CFG80211_GET_BSS(wiphy, NULL, bssid,
15040 ssid->SSID, ssid->SSID_len);
15041 if (bss) {
15042 cfg80211_unlink_bss(wiphy, bss);
15043 CFG80211_PUT_BSS(wiphy, bss);
15044 }
15045 }
15046
15047 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15048 scb_val_t scbval;
15049 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15050 uint32 reason = 0;
15051 struct ether_addr bssid_dongle = {{0, 0, 0, 0, 0, 0}};
15052 struct ether_addr bssid_null = {{0, 0, 0, 0, 0, 0}};
15053
15054 if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
15055 reason = ntoh32(e->reason);
15056 if (reason > WLC_E_DEAUTH_MAX_REASON) {
15057 WL_ERR(("Event %d original reason is %d, "
15058 "changed 0xFF\n", event, reason));
15059 reason = WLC_E_DEAUTH_MAX_REASON;
15060 }
15061 wl_cfg80211_handle_deauth_ind(cfg, ndev, e, data);
15062 }
15063 wl_ext_iapsta_restart_master(ndev);
15064 #ifdef SET_SSID_FAIL_CUSTOM_RC
15065 if ((event == WLC_E_SET_SSID) &&
15066 (ntoh32(e->status) == WLC_E_STATUS_TIMEOUT)) {
15067 reason = SET_SSID_FAIL_CUSTOM_RC;
15068 }
15069 #endif /* SET_SSID_FAIL_CUSTOM_RC */
15070
15071 /* roam offload does not sync BSSID always, get it from dongle */
15072 if (cfg->roam_offload) {
15073 bzero(&bssid_dongle, sizeof(bssid_dongle));
15074 if (wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid_dongle,
15075 sizeof(bssid_dongle)) == BCME_OK) {
15076 /* if not roam case, it would return null bssid */
15077 if (memcmp(&bssid_dongle, &bssid_null,
15078 ETHER_ADDR_LEN) != 0) {
15079 curbssid = (u8 *)&bssid_dongle;
15080 }
15081 }
15082 }
15083 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
15084 bool fw_assoc_state = TRUE;
15085 dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
15086 fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
15087 if (!fw_assoc_state) {
15088 WL_ERR(("Event sends up even different BSSID"
15089 " cur: " MACDBG " event: " MACDBG"\n",
15090 MAC2STRDBG(curbssid),
15091 MAC2STRDBG((const u8*)(&e->addr))));
15092 } else {
15093 WL_ERR(("BSSID of event is not the connected BSSID"
15094 "(ignore it) cur: " MACDBG
15095 " event: " MACDBG"\n",
15096 MAC2STRDBG(curbssid),
15097 MAC2STRDBG((const u8*)(&e->addr))));
15098 return 0;
15099 }
15100 }
15101 #ifdef DBG_PKT_MON
15102 /* Stop packet monitor */
15103 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15104 DHD_DBG_PKT_MON_STOP(dhdp);
15105 }
15106 #endif /* DBG_PKT_MON */
15107 /* clear RSSI monitor, framework will set new cfg */
15108 #ifdef RSSI_MONITOR_SUPPORT
15109 dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
15110 FALSE, 0, 0);
15111 #endif /* RSSI_MONITOR_SUPPORT */
15112 wl_clr_drv_status(cfg, CONNECTED, ndev);
15113
15114 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15115 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15116 dhd_net2idx(dhdp->info, ndev),
15117 WLAN_REASON_DEAUTH_LEAVING);
15118 /* To make sure disconnect, explictly send dissassoc
15119 * for BSSID 00:00:00:00:00:00 issue
15120 */
15121 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
15122 WL_INFORM_MEM(("clear fw state\n"));
15123 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
15124 scbval.val = htod32(scbval.val);
15125 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
15126 sizeof(scb_val_t));
15127 if (err < 0) {
15128 WL_ERR(("WLC_DISASSOC error %d\n", err));
15129 err = 0;
15130 }
15131 }
15132 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15133 loc_gen = true;
15134 }
15135 WL_INFORM_MEM(("[%s] Indicate disconnect event to upper layer. "
15136 "event: %d reason=%d from " MACDBG "\n",
15137 ndev->name, event, ntoh32(e->reason),
15138 MAC2STRDBG((const u8*)(&e->addr))));
15139
15140 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_DONE),
15141 dhd_net2idx(dhdp->info, ndev), reason);
15142 /* Send up deauth and clear states */
15143
15144 /*
15145 * FW sends body and body len as a part of deauth
15146 * and disassoc events (WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND)
15147 * The VIEs sits after reason code in the body. Reason code is
15148 * 2 bytes long.
15149 */
15150 WL_DBG(("recv disconnect ies ie_len = %d\n", ie_len));
15151 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND) {
15152 if ((datalen > DOT11_DISCONNECT_RC) &&
15153 datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
15154 data) {
15155 ie_ptr = (uchar*)data + DOT11_DISCONNECT_RC;
15156 ie_len = datalen - DOT11_DISCONNECT_RC;
15157 }
15158 } else if (event == WLC_E_LINK &&
15159 ntoh32(e->reason) == WLC_E_LINK_BCN_LOSS) {
15160 #ifdef WL_ANALYTICS
15161 /*
15162 * In case of linkdown, FW sends prb rsp IEs. Disco VIE
15163 * are appended with prb rsp ies. Remove prb rsp IES and
15164 * send disco vie to upper layer.
15165 * Disco VIE has fixed len of 11 octets.
15166 * As per SS spec.(2 octet header + 9 octet VIE)
15167 */
15168 if (datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
15169 datalen >= DOT11_DISCONNECT_RC &&
15170 ((err = wl_cfg80211_parse_vndr_ies(
15171 (const u8 *)data, datalen,
15172 &disco_vndr_ie)) == BCME_OK)) {
15173 for (i = 0; i < disco_vndr_ie.count; i++) {
15174 vndrie_info = &disco_vndr_ie.ie_info[i];
15175 if ((vndrie_info->vndrie.id ==
15176 0xDD) && (!memcmp(
15177 vndrie_info->vndrie.oui,
15178 SSE_OUI, DOT11_OUI_LEN)) &&
15179 (vndrie_info->vndrie.data[0] ==
15180 VENDOR_ENTERPRISE_STA_OUI_TYPE)) {
15181 ie_ptr = (u8 *)vndrie_info->ie_ptr;
15182 ie_len = vndrie_info->ie_len;
15183 }
15184 }
15185 }
15186 #endif /* WL_ANALYTICS */
15187 }
15188
15189 #ifdef CONFIG_AP6XXX_WIFI6_HDF
15190 HdfDisconnectedEventCallback(ndev, reason, ie_ptr, ie_len);
15191 #endif
15192 CFG80211_DISCONNECTED(ndev, reason, ie_ptr, ie_len,
15193 loc_gen, GFP_KERNEL);
15194 WL_INFORM_MEM(("[%s] Disconnect event sent to upper layer"
15195 "event:%d reason=%d ie_len=%d from " MACDBG "\n",
15196 ndev->name, event, ntoh32(e->reason), ie_len,
15197 MAC2STRDBG((const u8*)(&e->addr))));
15198
15199 /* Wait for status to be cleared to prevent race condition
15200 * issues with connect context
15201 */
15202 wl_cfg80211_disconnect_state_sync(cfg, ndev);
15203 wl_link_down(cfg);
15204 wl_init_prof(cfg, ndev);
15205 }
15206 else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
15207 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15208 dhd_net2idx(dhdp->info, ndev), 0);
15209 WL_INFORM_MEM(("link down, during connecting\n"));
15210 /* Issue WLC_DISASSOC to prevent FW roam attempts.
15211 * Do not issue WLC_DISASSOC again if the linkdown is
15212 * generated due to local disassoc, to avoid connect-disconnect
15213 * loop.
15214 */
15215 if (!((event == WLC_E_LINK) &&
15216 (ntoh32(e->reason) == WLC_E_LINK_DISASSOC) &&
15217 (ntoh32(e->status) == WLC_E_STATUS_SUCCESS))) {
15218 err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
15219 if (err < 0) {
15220 WL_ERR(("CONNECTING state,"
15221 " WLC_DISASSOC error %d\n",
15222 err));
15223 err = 0;
15224 }
15225 #ifdef ESCAN_RESULT_PATCH
15226 if ((memcmp(connect_req_bssid, broad_bssid,
15227 ETHER_ADDR_LEN) == 0) ||
15228 (memcmp(&e->addr, broad_bssid,
15229 ETHER_ADDR_LEN) == 0) ||
15230 (memcmp(&e->addr, connect_req_bssid,
15231 ETHER_ADDR_LEN) == 0))
15232 /* In case this event comes while associating
15233 * another AP
15234 */
15235 #endif /* ESCAN_RESULT_PATCH */
15236 wl_bss_connect_done(cfg, ndev, e, data, false);
15237 }
15238 }
15239 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15240 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
15241 WL_EXT_STATUS_DISCONNECTED, NULL);
15242
15243 /* if link down, bsscfg is diabled */
15244 if (ndev != bcmcfg_to_prmry_ndev(cfg))
15245 complete(&cfg->iface_disable);
15246 #ifdef WLTDLS
15247 /* re-enable TDLS if the number of connected interfaces
15248 * is less than 2.
15249 */
15250 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
15251 #endif /* WLTDLS */
15252 } else if (wl_is_nonetwork(cfg, e)) {
15253 WL_ERR(("connect failed event=%d e->status %d e->reason %d \n",
15254 event, (int)ntoh32(e->status), (int)ntoh32(e->reason)));
15255 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
15256 WL_EXT_STATUS_DISCONNECTED, NULL);
15257 wl_ext_iapsta_enable_master_if(ndev, FALSE);
15258 #ifdef WL_WPS_SYNC
15259 if (wl_wps_session_update(ndev,
15260 WPS_STATE_CONNECT_FAIL, e->addr.octet) == BCME_UNSUPPORTED) {
15261 /* Unexpected event. Ignore it. */
15262 return 0;
15263 }
15264 #endif /* WL_WPS_SYNC */
15265 /* Dump FW preserve buffer content */
15266 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
15267
15268 /* Clean up any pending scan request */
15269 wl_cfg80211_cancel_scan(cfg);
15270
15271 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
15272 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15273 WL_INFORM_MEM(("wl dissassoc\n"));
15274 err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
15275 if (err < 0) {
15276 WL_ERR(("WLC_DISASSOC error %d\n", err));
15277 err = 0;
15278 }
15279 } else {
15280 WL_DBG(("connect fail. clear disconnecting bit\n"));
15281 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15282 }
15283 wl_bss_connect_done(cfg, ndev, e, data, false);
15284 wl_clr_drv_status(cfg, CONNECTING, ndev);
15285 WL_INFORM_MEM(("connect fail reported\n"));
15286 }
15287 } else {
15288 WL_DBG(("%s nothing\n", __FUNCTION__));
15289 }
15290 DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
15291 } else {
15292 WL_MSG(ndev->name, "Invalid mode %d event %d status %d\n",
15293 wl_get_mode_by_netdev(cfg, ndev), ntoh32(e->event_type),
15294 ntoh32(e->status));
15295 }
15296 return err;
15297 }
15298
15299 #ifdef WL_RELMCAST
wl_cfg80211_set_rmc_pid(struct net_device * dev,int pid)15300 void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
15301 {
15302 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
15303 if (pid > 0)
15304 cfg->rmc_event_pid = pid;
15305 WL_DBG(("set pid for rmc event : pid=%d\n", pid));
15306 }
15307 #endif /* WL_RELMCAST */
15308
15309 #ifdef WL_RELMCAST
15310 static s32
wl_notify_rmc_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15311 wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15312 const wl_event_msg_t *e, void *data)
15313 {
15314 u32 evt = ntoh32(e->event_type);
15315 u32 reason = ntoh32(e->reason);
15316 int ret = -1;
15317
15318 switch (reason) {
15319 case WLC_E_REASON_RMC_AR_LOST:
15320 case WLC_E_REASON_RMC_AR_NO_ACK:
15321 if (cfg->rmc_event_pid != 0) {
15322 ret = wl_netlink_send_msg(cfg->rmc_event_pid,
15323 RMC_EVENT_LEADER_CHECK_FAIL,
15324 cfg->rmc_event_seq++, NULL, 0);
15325 }
15326 break;
15327 default:
15328 break;
15329 }
15330 WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
15331 return ret;
15332 }
15333 #endif /* WL_RELMCAST */
15334
15335 #ifdef GSCAN_SUPPORT
15336 static s32
wl_handle_roam_exp_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15337 wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15338 const wl_event_msg_t *e, void *data)
15339 {
15340 struct net_device *ndev = NULL;
15341 u32 datalen = be32_to_cpu(e->datalen);
15342
15343 if (datalen) {
15344 wl_roam_exp_event_t *evt_data = (wl_roam_exp_event_t *)data;
15345 if (evt_data->version == ROAM_EXP_EVENT_VERSION) {
15346 wlc_ssid_t *ssid = &evt_data->cur_ssid;
15347 struct wireless_dev *wdev;
15348 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15349 if (ndev) {
15350 wdev = ndev->ieee80211_ptr;
15351 wdev->ssid_len = min(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN);
15352 memcpy(wdev->ssid, ssid->SSID, wdev->ssid_len);
15353 WL_ERR(("SSID is %s\n", ssid->SSID));
15354 wl_update_prof(cfg, ndev, NULL, ssid, WL_PROF_SSID);
15355 } else {
15356 WL_ERR(("NULL ndev!\n"));
15357 }
15358 } else {
15359 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
15360 ROAM_EXP_EVENT_VERSION));
15361 }
15362 }
15363 return BCME_OK;
15364 }
15365 #endif /* GSCAN_SUPPORT */
15366
15367 #ifdef RSSI_MONITOR_SUPPORT
wl_handle_rssi_monitor_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15368 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15369 const wl_event_msg_t *e, void *data)
15370 {
15371
15372 #if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
15373 u32 datalen = be32_to_cpu(e->datalen);
15374 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15375 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15376
15377 if (datalen) {
15378 wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data;
15379 if (evt_data->version == RSSI_MONITOR_VERSION) {
15380 dhd_rssi_monitor_evt_t monitor_data;
15381 monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION;
15382 monitor_data.cur_rssi = evt_data->cur_rssi;
15383 memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN);
15384 wl_cfgvendor_send_async_event(wiphy, ndev,
15385 GOOGLE_RSSI_MONITOR_EVENT,
15386 &monitor_data, sizeof(monitor_data));
15387 } else {
15388 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
15389 RSSI_MONITOR_VERSION));
15390 }
15391 }
15392 #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
15393 return BCME_OK;
15394 }
15395 #endif /* RSSI_MONITOR_SUPPORT */
15396
15397 static s32
wl_notify_roaming_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15398 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15399 const wl_event_msg_t *e, void *data)
15400 {
15401 bool act;
15402 struct net_device *ndev = NULL;
15403 s32 err = 0;
15404 u32 event = be32_to_cpu(e->event_type);
15405 u32 status = be32_to_cpu(e->status);
15406 #ifdef DHD_LOSSLESS_ROAMING
15407 struct wl_security *sec;
15408 #endif // endif
15409 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15410 WL_DBG(("Enter \n"));
15411
15412 BCM_REFERENCE(dhdp);
15413 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15414
15415 if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
15416 wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
15417 cfg->disable_roam_event = TRUE;
15418 }
15419
15420 if ((cfg->disable_roam_event) && (event == WLC_E_ROAM))
15421 return err;
15422
15423 if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
15424 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15425 #ifdef DHD_LOSSLESS_ROAMING
15426 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15427 /* In order to reduce roaming delay, wl_bss_roaming_done is
15428 * early called with WLC_E_LINK event. It is called from
15429 * here only if WLC_E_LINK event is blocked for specific
15430 * security type.
15431 */
15432 if (IS_AKM_SUITE_FT(sec)) {
15433 wl_bss_roaming_done(cfg, ndev, e, data);
15434 /* Arm pkt logging timer */
15435 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
15436 }
15437 /* Roam timer is deleted mostly from wl_cfg80211_change_station
15438 * after roaming is finished successfully. We need to delete
15439 * the timer from here only for some security types that aren't
15440 * using wl_cfg80211_change_station to authorize SCB
15441 */
15442 if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
15443 wl_del_roam_timeout(cfg);
15444 }
15445 #else
15446 #if !defined(DHD_NONFT_ROAMING)
15447 wl_bss_roaming_done(cfg, ndev, e, data);
15448 #endif /* !DHD_NONFT_ROAMING */
15449 #endif /* DHD_LOSSLESS_ROAMING */
15450 } else {
15451 wl_bss_connect_done(cfg, ndev, e, data, true);
15452 }
15453 act = true;
15454 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
15455 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
15456
15457 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15458 wl_vndr_ies_get_vendor_oui(cfg, ndev, NULL, 0);
15459 }
15460 }
15461 #ifdef DHD_LOSSLESS_ROAMING
15462 else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) {
15463 wl_del_roam_timeout(cfg);
15464 }
15465 #endif // endif
15466 return err;
15467 }
15468
15469 #ifdef CUSTOM_EVENT_PM_WAKE
15470 uint32 last_dpm_upd_time = 0; /* ms */
15471 #define DPM_UPD_LMT_TIME ((CUSTOM_EVENT_PM_WAKE + (5)) * (1000) * (4)) /* ms */
15472 #define DPM_UPD_LMT_RSSI -85 /* dbm */
15473
15474 static s32
wl_check_pmstatus(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15475 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15476 const wl_event_msg_t *e, void *data)
15477 {
15478 s32 err = BCME_OK;
15479 struct net_device *ndev = NULL;
15480 u8 *pbuf = NULL;
15481 uint32 cur_dpm_upd_time = 0;
15482 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
15483 s32 rssi;
15484 #ifdef SUPPORT_RSSI_SUM_REPORT
15485 wl_rssi_ant_mimo_t rssi_ant_mimo;
15486 #endif /* SUPPORT_RSSI_SUM_REPORT */
15487 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15488
15489 pbuf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
15490 if (pbuf == NULL) {
15491 WL_ERR(("failed to allocate local pbuf\n"));
15492 return -ENOMEM;
15493 }
15494
15495 err = wldev_iovar_getbuf_bsscfg(ndev, "dump",
15496 "pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN,
15497 0, &cfg->ioctl_buf_sync);
15498
15499 if (err) {
15500 WL_ERR(("dump ioctl err = %d", err));
15501 } else {
15502 WL_ERR(("PM status : %s\n", pbuf));
15503 }
15504
15505 if (pbuf) {
15506 MFREE(cfg->osh, pbuf, WLC_IOCTL_MEDLEN);
15507 }
15508
15509 if (dhd->early_suspended) {
15510 /* LCD off */
15511 #ifdef SUPPORT_RSSI_SUM_REPORT
15512 /* Query RSSI sum across antennas */
15513 memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
15514 err = wl_get_rssi_per_ant(ndev, ndev->name, NULL, &rssi_ant_mimo);
15515 if (err) {
15516 WL_ERR(("Could not get rssi sum (%d)\n", err));
15517 }
15518 rssi = rssi_ant_mimo.rssi_sum;
15519 if (rssi == 0)
15520 #endif /* SUPPORT_RSSI_SUM_REPORT */
15521 {
15522 scb_val_t scb_val;
15523 memset(&scb_val, 0, sizeof(scb_val_t));
15524 scb_val.val = 0;
15525 err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
15526 if (err) {
15527 WL_ERR(("Could not get rssi (%d)\n", err));
15528 }
15529 #if defined(RSSIOFFSET)
15530 rssi = wl_update_rssi_offset(ndev, dtoh32(scb_val.val));
15531 #else
15532 rssi = dtoh32(scb_val.val);
15533 #endif
15534 }
15535 WL_ERR(("RSSI %d dBm\n", rssi));
15536 if (rssi > DPM_UPD_LMT_RSSI) {
15537 return err;
15538 }
15539 } else {
15540 /* LCD on */
15541 return err;
15542 }
15543
15544 if (last_dpm_upd_time == 0) {
15545 last_dpm_upd_time = OSL_SYSUPTIME();
15546 } else {
15547 cur_dpm_upd_time = OSL_SYSUPTIME();
15548 if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) {
15549 scb_val_t scbval;
15550 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
15551 dhd_net2idx(dhd->info, ndev), 0);
15552 bzero(&scbval, sizeof(scb_val_t));
15553
15554 err = wldev_ioctl_set(ndev, WLC_DISASSOC,
15555 &scbval, sizeof(scb_val_t));
15556 if (err < 0) {
15557 WL_ERR(("Disassoc error %d\n", err));
15558 return err;
15559 }
15560 WL_ERR(("Force Disassoc due to updated DPM event.\n"));
15561
15562 last_dpm_upd_time = 0;
15563 } else {
15564 last_dpm_upd_time = cur_dpm_upd_time;
15565 }
15566 }
15567
15568 return err;
15569 }
15570 #endif /* CUSTOM_EVENT_PM_WAKE */
15571
15572 #ifdef QOS_MAP_SET
15573 /* get user priority table */
15574 uint8 *
wl_get_up_table(dhd_pub_t * dhdp,int idx)15575 wl_get_up_table(dhd_pub_t * dhdp, int idx)
15576 {
15577 struct net_device *ndev;
15578 struct bcm_cfg80211 *cfg;
15579
15580 ndev = dhd_idx2net(dhdp, idx);
15581 if (ndev) {
15582 cfg = wl_get_cfg(ndev);
15583 if (cfg)
15584 return (uint8 *)(cfg->up_table);
15585 }
15586
15587 return NULL;
15588 }
15589 #endif /* QOS_MAP_SET */
15590
15591 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
15592 static s32
wl_notify_roam_prep_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15593 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15594 const wl_event_msg_t *e, void *data)
15595 {
15596 struct wl_security *sec;
15597 struct net_device *ndev;
15598 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15599 u32 status = ntoh32(e->status);
15600 u32 reason = ntoh32(e->reason);
15601
15602 BCM_REFERENCE(sec);
15603
15604 if (status == WLC_E_STATUS_SUCCESS && reason != WLC_E_REASON_INITIAL_ASSOC) {
15605 WL_ERR(("Attempting roam with reason code : %d\n", reason));
15606 }
15607
15608 #ifdef CONFIG_SILENT_ROAM
15609 if (dhdp->in_suspend && reason == WLC_E_REASON_SILENT_ROAM) {
15610 dhdp->sroamed = TRUE;
15611 }
15612 #endif /* CONFIG_SILENT_ROAM */
15613
15614 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15615
15616 #ifdef DBG_PKT_MON
15617 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15618 DHD_DBG_PKT_MON_STOP(dhdp);
15619 DHD_DBG_PKT_MON_START(dhdp);
15620 }
15621 #endif /* DBG_PKT_MON */
15622 #ifdef DHD_LOSSLESS_ROAMING
15623 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15624 /* Disable Lossless Roaming for specific AKM suite
15625 * Any other AKM suite can be added below if transition time
15626 * is delayed because of Lossless Roaming
15627 * and it causes any certication failure
15628 */
15629 if (IS_AKM_SUITE_FT(sec)) {
15630 return BCME_OK;
15631 }
15632
15633 dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC;
15634 /* Restore flow control */
15635 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
15636
15637 mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
15638 #endif /* DHD_LOSSLESS_ROAMING */
15639
15640 return BCME_OK;
15641 }
15642 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
15643
15644 static s32
wl_notify_roam_start_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15645 wl_notify_roam_start_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15646 const wl_event_msg_t *e, void *data)
15647 {
15648 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
15649 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15650 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15651 int event_type;
15652
15653 event_type = WIFI_EVENT_ROAM_SCAN_STARTED;
15654 wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_ROAM_EVENT_START,
15655 &event_type, sizeof(int));
15656 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || (WL_VENDOR_EXT_SUPPORT) */
15657
15658 return BCME_OK;
15659 }
15660
wl_get_assoc_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev)15661 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
15662 {
15663 wl_assoc_info_t assoc_info;
15664 struct wl_connect_info *conn_info = wl_to_conn(cfg);
15665 s32 err = 0;
15666 #ifdef QOS_MAP_SET
15667 bcm_tlv_t * qos_map_ie = NULL;
15668 #endif /* QOS_MAP_SET */
15669
15670 WL_DBG(("Enter \n"));
15671 err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
15672 WL_ASSOC_INFO_MAX, NULL);
15673 if (unlikely(err)) {
15674 WL_ERR(("could not get assoc info (%d)\n", err));
15675 return err;
15676 }
15677 memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
15678 assoc_info.req_len = htod32(assoc_info.req_len);
15679 assoc_info.resp_len = htod32(assoc_info.resp_len);
15680 assoc_info.flags = htod32(assoc_info.flags);
15681 if (conn_info->req_ie_len) {
15682 conn_info->req_ie_len = 0;
15683 bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
15684 }
15685 if (conn_info->resp_ie_len) {
15686 conn_info->resp_ie_len = 0;
15687 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
15688 }
15689
15690 if (assoc_info.req_len) {
15691 err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
15692 assoc_info.req_len, NULL);
15693 if (unlikely(err)) {
15694 WL_ERR(("could not get assoc req (%d)\n", err));
15695 return err;
15696 }
15697 if (assoc_info.req_len < sizeof(struct dot11_assoc_req)) {
15698 WL_ERR(("req_len %d lessthan %d \n", assoc_info.req_len,
15699 (int)sizeof(struct dot11_assoc_req)));
15700 return BCME_BADLEN;
15701 }
15702 conn_info->req_ie_len = (uint32)(assoc_info.req_len
15703 - sizeof(struct dot11_assoc_req));
15704 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
15705 conn_info->req_ie_len -= ETHER_ADDR_LEN;
15706 }
15707 if (conn_info->req_ie_len <= MAX_REQ_LINE)
15708 memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
15709 else {
15710 WL_ERR(("IE size %d above max %d size \n",
15711 conn_info->req_ie_len, MAX_REQ_LINE));
15712 return err;
15713 }
15714 } else {
15715 conn_info->req_ie_len = 0;
15716 }
15717
15718 if (assoc_info.resp_len) {
15719 err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
15720 assoc_info.resp_len, NULL);
15721 if (unlikely(err)) {
15722 WL_ERR(("could not get assoc resp (%d)\n", err));
15723 return err;
15724 }
15725 if (assoc_info.resp_len < sizeof(struct dot11_assoc_resp)) {
15726 WL_ERR(("resp_len %d is lessthan %d \n", assoc_info.resp_len,
15727 (int)sizeof(struct dot11_assoc_resp)));
15728 return BCME_BADLEN;
15729 }
15730 conn_info->resp_ie_len = assoc_info.resp_len -
15731 (uint32)sizeof(struct dot11_assoc_resp);
15732 if (conn_info->resp_ie_len <= MAX_REQ_LINE) {
15733 memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
15734 } else {
15735 WL_ERR(("IE size %d above max %d size \n",
15736 conn_info->resp_ie_len, MAX_REQ_LINE));
15737 return err;
15738 }
15739
15740 #ifdef QOS_MAP_SET
15741 /* find qos map set ie */
15742 if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
15743 DOT11_MNG_QOS_MAP_ID)) != NULL) {
15744 WL_DBG((" QoS map set IE found in assoc response\n"));
15745 if (!cfg->up_table) {
15746 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
15747 }
15748 wl_set_up_table(cfg->up_table, qos_map_ie);
15749 } else {
15750 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
15751 }
15752 #endif /* QOS_MAP_SET */
15753 } else {
15754 conn_info->resp_ie_len = 0;
15755 }
15756 WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
15757 conn_info->resp_ie_len));
15758
15759 return err;
15760 }
15761
wl_ch_to_chanspec(struct net_device * dev,int ch,struct wl_join_params * join_params,size_t * join_params_size)15762 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch, struct wl_join_params *join_params,
15763 size_t *join_params_size)
15764 {
15765 chanspec_t chanspec = 0, chspec;
15766 struct bcm_cfg80211 *cfg =
15767 (struct bcm_cfg80211 *)wiphy_priv(dev->ieee80211_ptr->wiphy);
15768
15769 if ((ch != 0) && (cfg && !cfg->rcc_enabled)) {
15770 join_params->params.chanspec_num = 1;
15771 join_params->params.chanspec_list[0] = ch;
15772
15773 if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
15774 chanspec |= WL_CHANSPEC_BAND_2G;
15775 else
15776 chanspec |= WL_CHANSPEC_BAND_5G;
15777
15778 /* Get the min_bw set for the interface */
15779 chspec = WL_CHANSPEC_BW_20;
15780 if (chspec == INVCHANSPEC) {
15781 WL_ERR(("Invalid chanspec \n"));
15782 return -EINVAL;
15783 }
15784 chanspec |= chspec;
15785 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
15786
15787 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
15788 join_params->params.chanspec_num * sizeof(chanspec_t);
15789
15790 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
15791 join_params->params.chanspec_list[0] |= chanspec;
15792 join_params->params.chanspec_list[0] =
15793 wl_chspec_host_to_driver(join_params->params.chanspec_list[0]);
15794
15795 join_params->params.chanspec_num =
15796 htod32(join_params->params.chanspec_num);
15797 }
15798 #ifdef ESCAN_CHANNEL_CACHE
15799 else {
15800 /* If channel is not present and ESCAN_CHANNEL_CACHE is enabled,
15801 * use the cached channel list
15802 */
15803 int n_channels;
15804 n_channels = get_roam_channel_list(ch, join_params->params.chanspec_list,
15805 MAX_ROAM_CHANNEL, &join_params->ssid, ioctl_version);
15806 join_params->params.chanspec_num = htod32(n_channels);
15807 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
15808 join_params->params.chanspec_num * sizeof(chanspec_t);
15809 }
15810 #endif /* ESCAN_CHANNEL_CACHE */
15811
15812 WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
15813 join_params->params.chanspec_list[0],
15814 join_params->params.chanspec_num));
15815 return 0;
15816 }
15817
wl_update_bss_info(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool update_ssid)15818 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15819 bool update_ssid)
15820 {
15821 struct cfg80211_bss *bss;
15822 wl_bss_info_t *bi;
15823 struct wlc_ssid *ssid;
15824 const struct bcm_tlv *tim;
15825 s32 beacon_interval;
15826 s32 dtim_period;
15827 size_t ie_len;
15828 const u8 *ie;
15829 u8 *curbssid;
15830 s32 err = 0;
15831 struct wiphy *wiphy;
15832 u32 channel;
15833 char *buf;
15834 u32 freq, band;
15835
15836 wiphy = bcmcfg_to_wiphy(cfg);
15837
15838 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
15839 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15840 bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
15841 ssid->SSID, ssid->SSID_len);
15842 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
15843 if (!buf) {
15844 WL_ERR(("buffer alloc failed.\n"));
15845 return BCME_NOMEM;
15846 }
15847 mutex_lock(&cfg->usr_sync);
15848 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
15849 err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX);
15850 if (unlikely(err)) {
15851 WL_ERR(("Could not get bss info %d\n", err));
15852 goto update_bss_info_out;
15853 }
15854 bi = (wl_bss_info_t *)(buf + 4);
15855 channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
15856 wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN);
15857
15858 if (!bss) {
15859 WL_DBG(("Could not find the AP\n"));
15860 if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
15861 WL_ERR(("Bssid doesn't match\n"));
15862 err = -EIO;
15863 goto update_bss_info_out;
15864 }
15865 err = wl_inform_single_bss(cfg, bi, update_ssid);
15866 if (unlikely(err))
15867 goto update_bss_info_out;
15868
15869 ie = ((u8 *)bi) + bi->ie_offset;
15870 ie_len = bi->ie_length;
15871 beacon_interval = cpu_to_le16(bi->beacon_period);
15872 } else {
15873 WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
15874 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
15875 freq = ieee80211_channel_to_frequency(channel);
15876 #else
15877 band = (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
15878 freq = ieee80211_channel_to_frequency(channel, band);
15879 #endif // endif
15880 bss->channel = ieee80211_get_channel(wiphy, freq);
15881 #if defined(WL_CFG80211_P2P_DEV_IF)
15882 ie = (const u8 *)bss->ies->data;
15883 ie_len = bss->ies->len;
15884 #else
15885 ie = bss->information_elements;
15886 ie_len = bss->len_information_elements;
15887 #endif /* WL_CFG80211_P2P_DEV_IF */
15888 beacon_interval = bss->beacon_interval;
15889
15890 CFG80211_PUT_BSS(wiphy, bss);
15891 }
15892
15893 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
15894 if (tim) {
15895 dtim_period = tim->data[1];
15896 } else {
15897 /*
15898 * active scan was done so we could not get dtim
15899 * information out of probe response.
15900 * so we speficially query dtim information.
15901 */
15902 dtim_period = 0;
15903 err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD,
15904 &dtim_period, sizeof(dtim_period));
15905 if (unlikely(err)) {
15906 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
15907 goto update_bss_info_out;
15908 }
15909 }
15910
15911 wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
15912 wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
15913
15914 update_bss_info_out:
15915 if (unlikely(err)) {
15916 WL_ERR(("Failed with error %d\n", err));
15917 }
15918
15919 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
15920 mutex_unlock(&cfg->usr_sync);
15921 return err;
15922 }
15923
15924 static s32
wl_bss_roaming_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)15925 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15926 const wl_event_msg_t *e, void *data)
15927 {
15928 struct wl_connect_info *conn_info = wl_to_conn(cfg);
15929 s32 err = 0;
15930 u8 *curbssid;
15931 u32 *channel;
15932 scb_val_t scbval;
15933 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15934 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15935 struct ieee80211_supported_band *band;
15936 struct ieee80211_channel *notify_channel = NULL;
15937 u32 freq;
15938 struct channel_info ci;
15939 u32 cur_channel;
15940 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
15941 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
15942 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
15943 defined(CFG80211_ROAM_API_GE_4_12)
15944 struct cfg80211_roam_info roam_info;
15945 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
15946 #if defined(WL_FILS_ROAM_OFFLD)
15947 struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
15948 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15949 #endif // endif
15950 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15951 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
15952 dhd_if_t *ifp = NULL;
15953 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
15954 #ifdef WLFBT
15955 uint32 data_len = 0;
15956 if (data)
15957 data_len = ntoh32(e->datalen);
15958 #endif /* WLFBT */
15959
15960 BCM_REFERENCE(dhdp);
15961 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15962 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
15963 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
15964 /* Skip calling cfg80211_roamed If the channels are same and
15965 * the current bssid & the new bssid are same
15966 * Also clear timer roam_timeout.
15967 * Only used on BCM4359 devices.
15968 */
15969 bzero(&ci, sizeof(ci));
15970 if ((wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci,
15971 sizeof(ci))) < 0) {
15972 WL_ERR(("Failed to get current channel !"));
15973 err = BCME_ERROR;
15974 goto fail;
15975 }
15976 cur_channel = dtoh32(ci.hw_channel);
15977 if ((*channel == cur_channel) && ((memcmp(curbssid, &e->addr,
15978 ETHER_ADDR_LEN) == 0) || (memcmp(&cfg->last_roamed_addr,
15979 &e->addr, ETHER_ADDR_LEN) == 0))) {
15980 WL_DBG(("BSS already present, Skipping roamed event to"
15981 " upper layer\n"));
15982 goto fail;
15983 }
15984 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
15985
15986 if ((err = wl_get_assoc_ies(cfg, ndev)) != BCME_OK) {
15987 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15988 dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
15989 WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
15990 " upper layer\n"));
15991 /* To make sure disconnect, and fw sync, explictly send dissassoc
15992 * for BSSID 00:00:00:00:00:00 issue
15993 */
15994 bzero(&scbval, sizeof(scb_val_t));
15995 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
15996 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
15997 scbval.val = htod32(scbval.val);
15998 if (wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
15999 sizeof(scb_val_t)) < 0) {
16000 WL_ERR(("WLC_DISASSOC error\n"));
16001 }
16002 goto fail;
16003 }
16004
16005 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID);
16006 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16007 if ((err = wl_update_bss_info(cfg, ndev, true)) != BCME_OK) {
16008 WL_ERR(("failed to update bss info, err=%d\n", err));
16009 goto fail;
16010 }
16011 wl_update_pmklist(ndev, cfg->pmk_list, err);
16012
16013 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
16014 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16015 /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
16016 if (*channel <= CH_MAX_2G_CHANNEL)
16017 band = wiphy->bands[IEEE80211_BAND_2GHZ];
16018 else
16019 band = wiphy->bands[IEEE80211_BAND_5GHZ];
16020 freq = ieee80211_channel_to_frequency(*channel, band->band);
16021 notify_channel = ieee80211_get_channel(wiphy, freq);
16022 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16023 #ifdef WLFBT
16024 /* back up the given FBT key for the further supplicant request,
16025 * currently not checking the FBT is enabled for current BSS in DHD,
16026 * because the supplicant decides to take it or not.
16027 */
16028 if (data && (data_len == FBT_KEYLEN)) {
16029 memcpy(cfg->fbt_key, data, FBT_KEYLEN);
16030 }
16031 #endif /* WLFBT */
16032 #ifdef CUSTOM_LONG_RETRY_LIMIT
16033 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
16034 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
16035 }
16036 #endif /* CUSTOM_LONG_RETRY_LIMIT */
16037 DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM),
16038 dhd_net2idx(dhdp->info, ndev), 0);
16039 WL_ERR(("Report roam event to upper layer. " MACDBG " (ch:%d)\n",
16040 MAC2STRDBG((const u8*)(&e->addr)), *channel));
16041 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
16042
16043 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16044 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
16045 defined(CFG80211_ROAM_API_GE_4_12)
16046 memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
16047 roam_info.channel = notify_channel;
16048 roam_info.bssid = curbssid;
16049 roam_info.req_ie = conn_info->req_ie;
16050 roam_info.req_ie_len = conn_info->req_ie_len;
16051 roam_info.resp_ie = conn_info->resp_ie;
16052 roam_info.resp_ie_len = conn_info->resp_ie_len;
16053 #if defined(WL_FILS_ROAM_OFFLD)
16054 if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
16055 roam_info.fils.kek = fils_info->fils_kek;
16056 roam_info.fils.kek_len = fils_info->fils_kek_len;
16057 roam_info.fils.update_erp_next_seq_num = true;
16058 roam_info.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
16059 roam_info.fils.pmk = fils_info->fils_pmk;
16060 roam_info.fils.pmk_len = fils_info->fils_kek_len;
16061 roam_info.fils.pmkid = fils_info->fils_pmkid;
16062 }
16063 #endif // endif
16064 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
16065 #else
16066 cfg80211_roamed(ndev,
16067 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16068 notify_channel,
16069 #endif // endif
16070 curbssid,
16071 conn_info->req_ie, conn_info->req_ie_len,
16072 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
16073 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
16074
16075 memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
16076 wl_set_drv_status(cfg, CONNECTED, ndev);
16077
16078 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16079 ifp = dhd_get_ifp(dhdp, e->ifidx);
16080 if (ifp) {
16081 ifp->post_roam_evt = TRUE;
16082 }
16083 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
16084
16085 return err;
16086
16087 fail:
16088 #ifdef DHD_LOSSLESS_ROAMING
16089 wl_del_roam_timeout(cfg);
16090 #endif /* DHD_LOSSLESS_ROAMING */
16091 return err;
16092 }
16093
16094 static bool
wl_cfg80211_verify_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,struct cfg80211_bss ** bss)16095 wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16096 struct cfg80211_bss **bss)
16097 {
16098 struct wiphy *wiphy;
16099 struct wlc_ssid *ssid;
16100 uint8 *curbssid;
16101 int count = 0;
16102 int ret = false;
16103 u8 cur_ssid[DOT11_MAX_SSID_LEN + 1];
16104
16105 wiphy = bcmcfg_to_wiphy(cfg);
16106 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
16107 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16108 if (!ssid) {
16109 WL_ERR(("No SSID found in the saved profile \n"));
16110 return false;
16111 }
16112
16113 do {
16114 *bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
16115 ssid->SSID, ssid->SSID_len);
16116 if (*bss || (count > 5)) {
16117 break;
16118 }
16119
16120 count++;
16121 msleep(100);
16122 } while (*bss == NULL);
16123
16124 WL_DBG(("cfg80211 bss_ptr:%p loop_cnt:%d\n", *bss, count));
16125 if (*bss) {
16126 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
16127 /* Update the reference count after use. In case of kernel version >= 4.7
16128 * the cfg802_put_bss is called in cfg80211_connect_bss context
16129 */
16130 CFG80211_PUT_BSS(wiphy, *bss);
16131 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
16132 ret = true;
16133 } else {
16134 memset(cur_ssid, 0, DOT11_MAX_SSID_LEN);
16135 strncpy(cur_ssid, ssid->SSID,
16136 MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN));
16137 WL_ERR(("No bss entry for ssid:%s bssid:"MACDBG"\n",
16138 cur_ssid, MAC2STRDBG(curbssid)));
16139 }
16140
16141 return ret;
16142 }
16143
16144 #ifdef WL_FILS
16145 static s32
wl_get_fils_connect_params(struct bcm_cfg80211 * cfg,struct net_device * ndev)16146 wl_get_fils_connect_params(struct bcm_cfg80211 *cfg, struct net_device *ndev)
16147 {
16148 const bcm_xtlv_t* pxtlv_out;
16149 struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
16150 int err = BCME_OK;
16151 bcm_iov_buf_t *iov_buf_in = NULL;
16152 bcm_iov_buf_t iov_buf_out = {0};
16153 u16 len;
16154 u16 type;
16155 const u8 *data;
16156 iov_buf_in = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
16157 if (!iov_buf_in) {
16158 WL_ERR(("buf memory alloc failed\n"));
16159 err = BCME_NOMEM;
16160 goto exit;
16161 }
16162 iov_buf_out.version = WL_FILS_IOV_VERSION;
16163 iov_buf_out.id = WL_FILS_CMD_GET_CONNECT_PARAMS;
16164 err = wldev_iovar_getbuf(ndev, "fils", (uint8*)&iov_buf_out, sizeof(bcm_iov_buf_t),
16165 iov_buf_in, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
16166 if (unlikely(err)) {
16167 WL_ERR(("Get FILS Params Error (%d)\n", err));
16168 goto exit;
16169 }
16170 pxtlv_out = (bcm_xtlv_t*)((bcm_iov_buf_t*)iov_buf_in)->data;
16171 len = iov_buf_in->len;
16172 do {
16173 if (!bcm_valid_xtlv(pxtlv_out, iov_buf_in->len, BCM_XTLV_OPTION_ALIGN32)) {
16174 WL_ERR(("%s: XTLV is not valid\n", __func__));
16175 err = BCME_BADARG;
16176 goto exit;
16177 }
16178 bcm_xtlv_unpack_xtlv(pxtlv_out, &type, &len, &data, BCM_XTLV_OPTION_ALIGN32);
16179 switch (type) {
16180 case WL_FILS_XTLV_ERP_NEXT_SEQ_NUM:
16181 fils_info->fils_erp_next_seq_num = *(const u16 *)data;
16182 break;
16183 case WL_FILS_XTLV_KEK:
16184 if (memcpy_s(fils_info->fils_kek,
16185 WL_MAX_FILS_KEY_LEN, data, len) < 0) {
16186 err = BCME_BADARG;
16187 goto exit;
16188 }
16189 fils_info->fils_kek_len = len;
16190 break;
16191 case WL_FILS_XTLV_PMK:
16192 if (memcpy_s(fils_info->fils_pmk,
16193 WL_MAX_FILS_KEY_LEN, data, len) < 0) {
16194 err = BCME_BADARG;
16195 goto exit;
16196 }
16197 fils_info->fils_pmk_len = len;
16198 break;
16199 case WL_FILS_XTLV_PMKID:
16200 if (memcpy_s(fils_info->fils_pmkid,
16201 WL_MAX_FILS_KEY_LEN, data, len) < 0) {
16202 err = BCME_BADARG;
16203 goto exit;
16204 }
16205 break;
16206 default:
16207 WL_ERR(("%s: wrong XTLV code\n", __func__));
16208 break;
16209
16210 }
16211 } while ((pxtlv_out = bcm_next_xtlv(pxtlv_out, (int *)&iov_buf_in->len,
16212 BCM_XTLV_OPTION_ALIGN32)) && iov_buf_in->len);
16213 exit:
16214 if (iov_buf_in) {
16215 MFREE(cfg->osh, iov_buf_in, WLC_IOCTL_SMLEN);
16216 }
16217 return err;
16218 }
16219 #endif /* WL_FILS */
16220 static s32
wl_bss_connect_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data,bool completed)16221 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16222 const wl_event_msg_t *e, void *data, bool completed)
16223 {
16224 struct wl_connect_info *conn_info = wl_to_conn(cfg);
16225 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16226 s32 err = 0;
16227 #ifdef WL_FILS
16228 struct cfg80211_connect_resp_params resp_params = {0};
16229 struct wl_fils_info *fils_info = NULL;
16230 struct wlc_ssid *ssid = NULL;
16231 struct wiphy *wiphy = NULL;
16232
16233 #endif /* WL_FILS */
16234 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16235 u32 event_type = ntoh32(e->event_type);
16236 struct cfg80211_bss *bss = NULL;
16237 dhd_pub_t *dhdp;
16238 dhdp = (dhd_pub_t *)(cfg->pub);
16239 BCM_REFERENCE(dhdp);
16240
16241 if (!sec) {
16242 WL_ERR(("sec is NULL\n"));
16243 return -ENODEV;
16244 }
16245 WL_DBG((" enter\n"));
16246 #ifdef ESCAN_RESULT_PATCH
16247 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
16248 if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) {
16249 WL_INFORM_MEM((" Connected event of connected device "
16250 "e=%d s=%d, ignore it\n",
16251 ntoh32(e->event_type), ntoh32(e->status)));
16252 return err;
16253 }
16254 }
16255 if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 &&
16256 memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) {
16257 WL_DBG(("copy bssid\n"));
16258 memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN);
16259 }
16260 #else
16261 if (cfg->scan_request) {
16262 wl_cfg80211_cancel_scan(cfg);
16263 }
16264 #endif /* ESCAN_RESULT_PATCH */
16265 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
16266 wl_cfg80211_scan_abort(cfg);
16267 if (completed) {
16268 wl_get_assoc_ies(cfg, ndev);
16269 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
16270 WL_PROF_BSSID);
16271 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16272 /*
16273 * CFG layer relies on cached IEs (from probe/beacon) to fetch matching bss.
16274 * For cases, there is no match available,
16275 * need to update the cache based on bss info from fw.
16276 */
16277 wl_update_bss_info(cfg, ndev, true);
16278 wl_update_pmklist(ndev, cfg->pmk_list, err);
16279 wl_set_drv_status(cfg, CONNECTED, ndev);
16280 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
16281 if (dhdp->roam_env_detection)
16282 wldev_iovar_setint(ndev, "roam_env_detection",
16283 AP_ENV_INDETERMINATE);
16284 #endif /* ROAM_AP_ENV_DETECTION */
16285 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
16286 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
16287 init_completion(&cfg->iface_disable);
16288 #else
16289 /* reinitialize completion to clear previous count */
16290 INIT_COMPLETION(cfg->iface_disable);
16291 #endif // endif
16292 }
16293 #ifdef CUSTOM_SET_CPUCORE
16294 if (wl_get_chan_isvht80(ndev, dhdp)) {
16295 if (ndev == bcmcfg_to_prmry_ndev(cfg))
16296 dhdp->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
16297 else if (is_p2p_group_iface(ndev->ieee80211_ptr))
16298 dhdp->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
16299 dhd_set_cpucore(dhdp, TRUE);
16300 }
16301 #endif /* CUSTOM_SET_CPUCORE */
16302 #ifdef CUSTOM_LONG_RETRY_LIMIT
16303 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
16304 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
16305 }
16306 #endif /* CUSTOM_LONG_RETRY_LIMIT */
16307 bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
16308 }
16309 wl_clr_drv_status(cfg, CONNECTING, ndev);
16310
16311 if (completed && (wl_cfg80211_verify_bss(cfg, ndev, &bss) != true)) {
16312 /* If bss entry is not available in the cfg80211 bss cache
16313 * the wireless stack will complain and won't populate
16314 * wdev->current_bss ptr
16315 */
16316 WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
16317 completed = false;
16318 sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
16319 }
16320 if (completed) {
16321 WL_MSG(ndev->name, "Report connect result - connection succeeded\n");
16322 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
16323 wl_ext_iapsta_enable_master_if(ndev, TRUE);
16324 } else {
16325 WL_MSG(ndev->name, "Report connect result - connection failed\n");
16326 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
16327 WL_EXT_STATUS_DISCONNECTED, NULL);
16328 }
16329 #ifdef WL_FILS
16330 if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
16331 wl_get_fils_connect_params(cfg, ndev);
16332 fils_info = wl_to_fils_info(cfg);
16333 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
16334 wiphy = bcmcfg_to_wiphy(cfg);
16335 resp_params.status = completed ? WLAN_STATUS_SUCCESS :
16336 (sec->auth_assoc_res_status) ?
16337 sec->auth_assoc_res_status :
16338 WLAN_STATUS_UNSPECIFIED_FAILURE;
16339 resp_params.bssid = curbssid;
16340 resp_params.bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
16341 ssid->SSID, ssid->SSID_len);
16342 resp_params.req_ie = conn_info->req_ie;
16343 resp_params.req_ie_len = conn_info->req_ie_len;
16344 resp_params.resp_ie = conn_info->resp_ie;
16345 resp_params.resp_ie_len = conn_info->resp_ie_len;
16346 #if defined(WL_FILS_ROAM_OFFLD) || (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0))
16347 resp_params.fils.kek = fils_info->fils_kek;
16348 resp_params.fils.kek_len = fils_info->fils_kek_len;
16349 resp_params.fils.update_erp_next_seq_num = true;
16350 resp_params.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
16351 resp_params.fils.pmk = fils_info->fils_pmk;
16352 resp_params.fils.pmk_len = fils_info->fils_kek_len;
16353 resp_params.fils.pmkid = fils_info->fils_pmkid;
16354 #else
16355 resp_params.fils_kek = fils_info->fils_kek;
16356 resp_params.fils_kek_len = fils_info->fils_kek_len;
16357 resp_params.update_erp_next_seq_num = true;
16358 resp_params.fils_erp_next_seq_num = fils_info->fils_erp_next_seq_num;
16359 resp_params.pmk = fils_info->fils_pmk;
16360 resp_params.pmk_len = fils_info->fils_kek_len;
16361 resp_params.pmkid = fils_info->fils_pmkid;
16362 #endif /* WL_FILS_ROAM_OFFLD */
16363 cfg80211_connect_done(ndev, &resp_params, GFP_KERNEL);
16364 }
16365 else
16366 #endif /* WL_FILS */
16367 {
16368 CFG80211_CONNECT_RESULT(ndev,
16369 curbssid,
16370 bss,
16371 conn_info->req_ie,
16372 conn_info->req_ie_len,
16373 conn_info->resp_ie,
16374 conn_info->resp_ie_len,
16375 completed ? WLAN_STATUS_SUCCESS :
16376 (sec->auth_assoc_res_status) ?
16377 sec->auth_assoc_res_status :
16378 WLAN_STATUS_UNSPECIFIED_FAILURE,
16379 GFP_KERNEL);
16380
16381 #ifdef CONFIG_AP6XXX_WIFI6_HDF
16382 wl_notify_connect_sta_status(cfg, ndev, e, data, completed, bss);
16383 #endif
16384 }
16385 } else {
16386 WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
16387 " connecting:%x. connected:%d\n",
16388 ndev->name, event_type, wl_get_drv_status(cfg, CONNECTING, ndev),
16389 wl_get_drv_status(cfg, CONNECTED, ndev)));
16390 }
16391 #ifdef CONFIG_TCPACK_FASTTX
16392 if (wl_get_chan_isvht80(ndev, dhdp))
16393 wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
16394 else
16395 wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
16396 #endif /* CONFIG_TCPACK_FASTTX */
16397
16398 return err;
16399 }
16400
16401 static s32
wl_notify_mic_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)16402 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16403 const wl_event_msg_t *e, void *data)
16404 {
16405 struct net_device *ndev = NULL;
16406 u16 flags = ntoh16(e->flags);
16407 enum nl80211_key_type key_type;
16408
16409 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16410
16411 WL_INFORM_MEM(("[%s] mic fail event - " MACDBG " \n",
16412 ndev->name, MAC2STRDBG(e->addr.octet)));
16413 mutex_lock(&cfg->usr_sync);
16414 if (flags & WLC_EVENT_MSG_GROUP)
16415 key_type = NL80211_KEYTYPE_GROUP;
16416 else
16417 key_type = NL80211_KEYTYPE_PAIRWISE;
16418
16419 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
16420 cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1,
16421 NULL, GFP_KERNEL);
16422 mutex_unlock(&cfg->usr_sync);
16423
16424 return 0;
16425 }
16426
16427 #ifdef BT_WIFI_HANDOVER
16428 static s32
wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)16429 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16430 const wl_event_msg_t *e, void *data)
16431 {
16432 struct net_device *ndev = NULL;
16433 u32 event = ntoh32(e->event_type);
16434 u32 datalen = ntoh32(e->datalen);
16435 s32 err;
16436
16437 WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen));
16438 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16439 err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0);
16440
16441 return err;
16442 }
16443 #endif /* BT_WIFI_HANDOVER */
16444
16445 static s32
wl_frame_get_mgmt(struct bcm_cfg80211 * cfg,u16 fc,const struct ether_addr * da,const struct ether_addr * sa,const struct ether_addr * bssid,u8 ** pheader,u32 * body_len,u8 * pbody)16446 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
16447 const struct ether_addr *da, const struct ether_addr *sa,
16448 const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody)
16449 {
16450 struct dot11_management_header *hdr;
16451 u32 totlen = 0;
16452 s32 err = 0;
16453 u8 *offset;
16454 u32 prebody_len = *body_len;
16455 switch (fc) {
16456 case FC_ASSOC_REQ:
16457 /* capability , listen interval */
16458 totlen = DOT11_ASSOC_REQ_FIXED_LEN;
16459 *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
16460 break;
16461
16462 case FC_REASSOC_REQ:
16463 /* capability, listen inteval, ap address */
16464 totlen = DOT11_REASSOC_REQ_FIXED_LEN;
16465 *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
16466 break;
16467 }
16468 totlen += DOT11_MGMT_HDR_LEN + prebody_len;
16469 *pheader = (u8 *)MALLOCZ(cfg->osh, totlen);
16470 if (*pheader == NULL) {
16471 WL_ERR(("memory alloc failed \n"));
16472 return -ENOMEM;
16473 }
16474 hdr = (struct dot11_management_header *) (*pheader);
16475 hdr->fc = htol16(fc);
16476 hdr->durid = 0;
16477 hdr->seq = 0;
16478 offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
16479 bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
16480 bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
16481 bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
16482 if ((pbody != NULL) && prebody_len)
16483 bcopy((const char*)pbody, offset, prebody_len);
16484 *body_len = totlen;
16485 return err;
16486 }
16487
16488 #ifdef WL_CFG80211_GON_COLLISION
16489 static void
wl_gon_req_collision(struct bcm_cfg80211 * cfg,wl_action_frame_t * tx_act_frm,wifi_p2p_pub_act_frame_t * rx_act_frm,struct net_device * ndev,struct ether_addr sa,struct ether_addr da)16490 wl_gon_req_collision(struct bcm_cfg80211 *cfg, wl_action_frame_t *tx_act_frm,
16491 wifi_p2p_pub_act_frame_t *rx_act_frm, struct net_device *ndev,
16492 struct ether_addr sa, struct ether_addr da)
16493 {
16494 if (cfg->afx_hdl->pending_tx_act_frm == NULL)
16495 return;
16496
16497 if (tx_act_frm &&
16498 wl_cfgp2p_is_pub_action(tx_act_frm->data, tx_act_frm->len)) {
16499 wifi_p2p_pub_act_frame_t *pact_frm;
16500
16501 pact_frm = (wifi_p2p_pub_act_frame_t *)tx_act_frm->data;
16502
16503 if (!(pact_frm->subtype == P2P_PAF_GON_REQ &&
16504 rx_act_frm->subtype == P2P_PAF_GON_REQ)) {
16505 return;
16506 }
16507 }
16508
16509 WL_ERR((" GO NEGO Request COLLISION !!! \n"));
16510
16511 /* if sa(peer) addr is less than da(my) addr,
16512 * my device will process peer's gon request and block to send my gon req.
16513 *
16514 * if not (sa addr > da addr),
16515 * my device will process gon request and drop gon req of peer.
16516 */
16517 if (memcmp(sa.octet, da.octet, ETHER_ADDR_LEN) < 0) {
16518 /* block to send tx gon request */
16519 cfg->block_gon_req_tx_count = BLOCK_GON_REQ_MAX_NUM;
16520 WL_ERR((" block to send gon req tx !!!\n"));
16521
16522 /* if we are finding a common channel for sending af,
16523 * do not scan more to block to send current gon req
16524 */
16525 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
16526 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, ndev);
16527 complete(&cfg->act_frm_scan);
16528 }
16529 } else {
16530 /* drop gon request of peer to process gon request by my device. */
16531 WL_ERR((" drop to receive gon req rx !!! \n"));
16532 cfg->block_gon_req_rx_count = BLOCK_GON_REQ_MAX_NUM;
16533 }
16534
16535 return;
16536 }
16537 #endif /* WL_CFG80211_GON_COLLISION */
16538
16539 void
wl_stop_wait_next_action_frame(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 bsscfgidx)16540 wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 bsscfgidx)
16541 {
16542 s32 err = 0;
16543
16544 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
16545 if (timer_pending(&cfg->p2p->listen_timer)) {
16546 del_timer_sync(&cfg->p2p->listen_timer);
16547 }
16548 if (cfg->afx_hdl != NULL) {
16549 if (cfg->afx_hdl->dev != NULL) {
16550 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
16551 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev);
16552 }
16553 cfg->afx_hdl->peer_chan = WL_INVALID;
16554 }
16555 complete(&cfg->act_frm_scan);
16556 WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
16557 } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
16558 if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
16559 wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
16560 wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
16561
16562 WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx));
16563 /* Scan engine is not used for sending action frames in the latest driver
16564 * branches. actframe_abort is used in the latest driver branches
16565 * instead of scan abort.
16566 * If actframe_abort iovar succeeds, don't execute scan abort.
16567 * If actframe_abort fails with unsupported error,
16568 * execute scan abort (for backward copmatibility).
16569 */
16570 if (cfg->af_sent_channel) {
16571 err = wldev_iovar_setint_bsscfg(ndev, "actframe_abort", 1, bsscfgidx);
16572 if (err < 0) {
16573 if (err == BCME_UNSUPPORTED) {
16574 wl_cfg80211_scan_abort(cfg);
16575 } else {
16576 WL_ERR(("actframe_abort failed. ret:%d\n", err));
16577 }
16578 }
16579 }
16580 }
16581 #ifdef WL_CFG80211_SYNC_GON
16582 else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
16583 WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
16584 /* So abort scan to cancel listen */
16585 wl_cfg80211_scan_abort(cfg);
16586 }
16587 #endif /* WL_CFG80211_SYNC_GON */
16588 }
16589
16590 #if defined(WLTDLS)
wl_cfg80211_is_tdls_tunneled_frame(void * frame,u32 frame_len)16591 bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len)
16592 {
16593 unsigned char *data;
16594
16595 if (frame == NULL) {
16596 WL_ERR(("Invalid frame \n"));
16597 return false;
16598 }
16599
16600 if (frame_len < 5) {
16601 WL_ERR(("Invalid frame length [%d] \n", frame_len));
16602 return false;
16603 }
16604
16605 data = frame;
16606
16607 if (!memcmp(data, TDLS_TUNNELED_PRB_REQ, 5) ||
16608 !memcmp(data, TDLS_TUNNELED_PRB_RESP, 5)) {
16609 WL_DBG(("TDLS Vendor Specific Received type\n"));
16610 return true;
16611 }
16612
16613 return false;
16614 }
16615 #endif /* WLTDLS */
16616
wl_cfg80211_get_ioctl_version(void)16617 int wl_cfg80211_get_ioctl_version(void)
16618 {
16619 return ioctl_version;
16620 }
16621
16622 static s32
wl_notify_rx_mgmt_frame(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)16623 wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16624 const wl_event_msg_t *e, void *data)
16625 {
16626 struct ieee80211_supported_band *band;
16627 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
16628 //#ifdef CONFIG_AP6XXX_WIFI6_HDF
16629 // struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
16630 //#endif
16631 struct ether_addr da;
16632 struct ether_addr bssid;
16633 bool isfree = false;
16634 s32 err = 0;
16635 s32 freq;
16636 struct net_device *ndev = NULL;
16637 wifi_p2p_pub_act_frame_t *act_frm = NULL;
16638 wifi_p2p_action_frame_t *p2p_act_frm = NULL;
16639 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
16640 wl_event_rx_frame_data_t *rxframe;
16641 u32 event;
16642 u8 *mgmt_frame;
16643 u8 bsscfgidx;
16644 u32 mgmt_frame_len;
16645 u16 channel;
16646 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
16647 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16648 #endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
16649 if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) {
16650 WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen)));
16651 return -EINVAL;
16652 }
16653 mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_t);
16654 event = ntoh32(e->event_type);
16655 bsscfgidx = e->bsscfgidx;
16656 rxframe = (wl_event_rx_frame_data_t *)data;
16657 if (!rxframe) {
16658 WL_ERR(("rxframe: NULL\n"));
16659 return -EINVAL;
16660 }
16661 channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK);
16662 bzero(&bssid, ETHER_ADDR_LEN);
16663 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16664 if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) &&
16665 (event == WLC_E_PROBREQ_MSG)) {
16666 struct net_info *iter, *next;
16667 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
16668 for_each_ndev(cfg, iter, next) {
16669 GCC_DIAGNOSTIC_POP();
16670 if (iter->ndev && iter->wdev &&
16671 iter->wdev->iftype == NL80211_IFTYPE_AP) {
16672 ndev = iter->ndev;
16673 cfgdev = ndev_to_cfgdev(ndev);
16674 break;
16675 }
16676 }
16677 }
16678
16679 if (channel <= CH_MAX_2G_CHANNEL)
16680 band = wiphy->bands[IEEE80211_BAND_2GHZ];
16681 else
16682 band = wiphy->bands[IEEE80211_BAND_5GHZ];
16683 if (!band) {
16684 WL_ERR(("No valid band\n"));
16685 return -EINVAL;
16686 }
16687 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
16688 freq = ieee80211_channel_to_frequency(channel);
16689 (void)band->band;
16690 #else
16691 freq = ieee80211_channel_to_frequency(channel, band->band);
16692 #endif // endif
16693 if (event == WLC_E_ACTION_FRAME_RX) {
16694 u8 ioctl_buf[WLC_IOCTL_SMLEN];
16695
16696 if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
16697 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx,
16698 NULL)) != BCME_OK) {
16699 WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
16700 goto exit;
16701 }
16702
16703 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
16704 if (err < 0)
16705 WL_ERR(("WLC_GET_BSSID error %d\n", err));
16706 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
16707 err = wl_frame_get_mgmt(cfg, FC_ACTION, &da, &e->addr, &bssid,
16708 &mgmt_frame, &mgmt_frame_len,
16709 (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
16710 if (err < 0) {
16711 WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
16712 mgmt_frame_len, channel, freq));
16713 goto exit;
16714 }
16715 isfree = true;
16716 if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16717 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
16718 act_frm = (wifi_p2p_pub_act_frame_t *)
16719 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
16720 } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16721 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
16722 p2p_act_frm = (wifi_p2p_action_frame_t *)
16723 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
16724 (void) p2p_act_frm;
16725 } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16726 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
16727
16728 sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
16729 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
16730 if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
16731 if (cfg->next_af_subtype == sd_act_frm->action) {
16732 WL_DBG(("We got a right next frame of SD!(%d)\n",
16733 sd_act_frm->action));
16734 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16735
16736 /* Stop waiting for next AF. */
16737 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16738 }
16739 }
16740 (void) sd_act_frm;
16741 #ifdef WLTDLS
16742 } else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
16743 (wl_cfg80211_is_tdls_tunneled_frame(
16744 &mgmt_frame[DOT11_MGMT_HDR_LEN],
16745 mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
16746 if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
16747 WL_ERR((" TDLS Action Frame Received type = %d \n",
16748 mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
16749 }
16750 #ifdef TDLS_MSG_ONLY_WFD
16751 if (!dhdp->tdls_mode) {
16752 WL_DBG((" TDLS Frame filtered \n"));
16753 goto exit;
16754 }
16755 #else
16756 if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
16757 cfg->tdls_mgmt_frame = mgmt_frame;
16758 cfg->tdls_mgmt_frame_len = mgmt_frame_len;
16759 cfg->tdls_mgmt_freq = freq;
16760 return 0;
16761 }
16762 #endif /* TDLS_MSG_ONLY_WFD */
16763 #endif /* WLTDLS */
16764 #ifdef QOS_MAP_SET
16765 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
16766 /* update QoS map set table */
16767 bcm_tlv_t * qos_map_ie = NULL;
16768 if ((qos_map_ie = bcm_parse_tlvs(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16769 mgmt_frame_len - DOT11_MGMT_HDR_LEN,
16770 DOT11_MNG_QOS_MAP_ID)) != NULL) {
16771 WL_DBG((" QoS map set IE found in QoS action frame\n"));
16772 if (!cfg->up_table) {
16773 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
16774 }
16775 wl_set_up_table(cfg->up_table, qos_map_ie);
16776 } else {
16777 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
16778 }
16779 #endif /* QOS_MAP_SET */
16780 } else {
16781 /*
16782 * if we got normal action frame and ndev is p2p0,
16783 * we have to change ndev from p2p0 to wlan0
16784 */
16785
16786 if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
16787 u8 action = 0;
16788 if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16789 mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) {
16790 WL_DBG(("Recived action is not public action frame\n"));
16791 } else if (cfg->next_af_subtype == action) {
16792 WL_DBG(("Recived action is the waiting action(%d)\n",
16793 action));
16794 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16795
16796 /* Stop waiting for next AF. */
16797 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16798 }
16799 }
16800 }
16801
16802 if (act_frm) {
16803 #ifdef WL_CFG80211_GON_COLLISION
16804 if (act_frm->subtype == P2P_PAF_GON_REQ) {
16805 wl_gon_req_collision(cfg,
16806 &cfg->afx_hdl->pending_tx_act_frm->action_frame,
16807 act_frm, ndev, e->addr, da);
16808
16809 if (cfg->block_gon_req_rx_count) {
16810 WL_ERR(("drop frame GON Req Rx : count (%d)\n",
16811 cfg->block_gon_req_rx_count));
16812 cfg->block_gon_req_rx_count--;
16813 goto exit;
16814 }
16815 } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
16816 /* if go formation done, clear it */
16817 cfg->block_gon_req_tx_count = 0;
16818 cfg->block_gon_req_rx_count = 0;
16819 }
16820 #endif /* WL_CFG80211_GON_COLLISION */
16821
16822 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
16823 if (cfg->next_af_subtype == act_frm->subtype) {
16824 WL_DBG(("We got a right next frame!(%d)\n",
16825 act_frm->subtype));
16826 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16827
16828 if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
16829 OSL_SLEEP(20);
16830 }
16831
16832 /* Stop waiting for next AF. */
16833 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16834 } else if ((cfg->next_af_subtype == P2P_PAF_GON_RSP) &&
16835 (act_frm->subtype == P2P_PAF_GON_REQ)) {
16836 /* If current received frame is GO NEG REQ and next
16837 * expected frame is GO NEG RESP, do not send it up.
16838 */
16839 WL_ERR(("GO Neg req received while waiting for RESP."
16840 "Discard incoming frame\n"));
16841 goto exit;
16842 }
16843 }
16844 }
16845
16846 wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
16847 mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel);
16848 if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
16849 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
16850 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
16851 }
16852 } else if (event == WLC_E_PROBREQ_MSG) {
16853
16854 /* Handle probe reqs frame
16855 * WPS-AP certification 4.2.13
16856 */
16857 struct parsed_ies prbreq_ies;
16858 u32 prbreq_ie_len = 0;
16859 bool pbc = 0;
16860
16861 WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
16862 mgmt_frame = (u8 *)(data);
16863 mgmt_frame_len = ntoh32(e->datalen);
16864 if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) {
16865 WL_ERR(("wrong datalen:%d\n", mgmt_frame_len));
16866 return -EINVAL;
16867 }
16868 prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
16869
16870 /* Parse prob_req IEs */
16871 if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16872 prbreq_ie_len, &prbreq_ies) < 0) {
16873 WL_ERR(("Prob req get IEs failed\n"));
16874 return 0;
16875 }
16876 if (prbreq_ies.wps_ie != NULL) {
16877 wl_validate_wps_ie(
16878 (const char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
16879 WL_DBG((" wps_ie exist pbc = %d\n", pbc));
16880 /* if pbc method, send prob_req mgmt frame to upper layer */
16881 if (!pbc)
16882 return 0;
16883 } else
16884 return 0;
16885 } else {
16886 mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
16887
16888 /* wpa supplicant use probe request event for restarting another GON Req.
16889 * but it makes GON Req repetition.
16890 * so if src addr of prb req is same as my target device,
16891 * do not send probe request event during sending action frame.
16892 */
16893 if (event == WLC_E_P2P_PROBREQ_MSG) {
16894 WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
16895 "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
16896
16897 #ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
16898 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) &&
16899 !memcmp(cfg->afx_hdl->tx_dst_addr.octet, e->addr.octet,
16900 ETHER_ADDR_LEN)) {
16901 if (cfg->afx_hdl->pending_tx_act_frm &&
16902 wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
16903 s32 channel = CHSPEC_CHANNEL(hton16(rxframe->channel));
16904 WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
16905 channel));
16906 cfg->afx_hdl->peer_chan = channel;
16907 complete(&cfg->act_frm_scan);
16908 }
16909 }
16910 #endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
16911
16912 /* Filter any P2P probe reqs arriving during the
16913 * GO-NEG Phase
16914 */
16915 if (cfg->p2p &&
16916 #if defined(P2P_IE_MISSING_FIX)
16917 cfg->p2p_prb_noti &&
16918 #endif // endif
16919 wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
16920 WL_DBG(("Filtering P2P probe_req while "
16921 "being in GO-Neg state\n"));
16922 return 0;
16923 }
16924 }
16925 }
16926
16927 if (discover_cfgdev(cfgdev, cfg))
16928 WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
16929 else
16930 WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
16931 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
16932 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
16933 #ifdef CONFIG_AP6XXX_WIFI6_HDF
16934 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame, mgmt_frame_len);
16935 #endif
16936 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
16937 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
16938 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
16939 defined(WL_COMPAT_WIRELESS)
16940 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
16941 #else
16942 cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
16943 #endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
16944
16945 WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
16946 mgmt_frame_len, ntoh32(e->datalen), channel, freq));
16947 exit:
16948 if (isfree) {
16949 MFREE(cfg->osh, mgmt_frame, mgmt_frame_len);
16950 }
16951 return err;
16952 }
16953
wl_init_conf(struct wl_conf * conf)16954 static void wl_init_conf(struct wl_conf *conf)
16955 {
16956 WL_DBG(("Enter \n"));
16957 conf->frag_threshold = (u32)-1;
16958 conf->rts_threshold = (u32)-1;
16959 conf->retry_short = (u32)-1;
16960 conf->retry_long = (u32)-1;
16961 conf->tx_power = -1;
16962 }
16963
wl_init_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev)16964 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
16965 {
16966 unsigned long flags;
16967 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
16968
16969 if (!profile) {
16970 WL_ERR(("profile null\n"));
16971 return;
16972 }
16973
16974 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
16975 bzero(profile, sizeof(struct wl_profile));
16976 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
16977 }
16978
wl_init_event_handler(struct bcm_cfg80211 * cfg)16979 static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
16980 {
16981 bzero(cfg->evt_handler, sizeof(cfg->evt_handler));
16982
16983 cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
16984 cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
16985 cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
16986 cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
16987 cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
16988 cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
16989 cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
16990 cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
16991 cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
16992 cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
16993 cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
16994 cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
16995 cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
16996 cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
16997 cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
16998 cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
16999 cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
17000 cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
17001 cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
17002 cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
17003 cfg->evt_handler[WLC_E_AUTH_IND] = wl_notify_connect_status;
17004 cfg->evt_handler[WLC_E_ASSOC_RESP_IE] = wl_notify_connect_status;
17005 #ifdef PNO_SUPPORT
17006 cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
17007 #endif /* PNO_SUPPORT */
17008 #ifdef GSCAN_SUPPORT
17009 cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
17010 cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
17011 cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
17012 cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
17013 cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
17014 cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
17015 cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
17016 cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
17017 #endif /* GSCAN_SUPPORT */
17018 #ifdef RSSI_MONITOR_SUPPORT
17019 cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
17020 #endif /* RSSI_MONITOR_SUPPORT */
17021 #ifdef WLTDLS
17022 cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
17023 #endif /* WLTDLS */
17024 cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
17025 #ifdef WL_RELMCAST
17026 cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
17027 #endif /* WL_RELMCAST */
17028 #ifdef BT_WIFI_HANDOVER
17029 cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
17030 #endif // endif
17031 #ifdef WL_NAN
17032 cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status;
17033 cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status;
17034 #endif /* WL_NAN */
17035 cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
17036 cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
17037 #ifdef CUSTOM_EVENT_PM_WAKE
17038 cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
17039 #endif /* CUSTOM_EVENT_PM_WAKE */
17040 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
17041 cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
17042 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
17043 cfg->evt_handler[WLC_E_ROAM_START] = wl_notify_roam_start_status;
17044 cfg->evt_handler[WLC_E_PSK_SUP] = wl_cfg80211_sup_event_handler;
17045 #ifdef WL_BCNRECV
17046 cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
17047 #endif /* WL_BCNRECV */
17048 #ifdef WL_MBO
17049 cfg->evt_handler[WLC_E_MBO] = wl_mbo_event_handler;
17050 #endif /* WL_MBO */
17051 #ifdef WL_CAC_TS
17052 cfg->evt_handler[WLC_E_ADDTS_IND] = wl_cfg80211_cac_event_handler;
17053 cfg->evt_handler[WLC_E_DELTS_IND] = wl_cfg80211_cac_event_handler;
17054 #endif /* WL_CAC_TS */
17055 #if defined(WL_MBO) || defined(WL_OCE)
17056 cfg->evt_handler[WLC_E_PRUNE] = wl_bssid_prune_event_handler;
17057 #endif /* WL_MBO || WL_OCE */
17058 #ifdef RTT_SUPPORT
17059 cfg->evt_handler[WLC_E_PROXD] = wl_cfg80211_rtt_event_handler;
17060 #endif // endif
17061 #ifdef WL_CHAN_UTIL
17062 cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler;
17063 #endif /* WL_CHAN_UTIL */
17064 #ifdef WL_CLIENT_SAE
17065 cfg->evt_handler[WLC_E_JOIN_START] = wl_notify_start_auth;
17066 #endif /* WL_CLIENT_SAE */
17067 }
17068
17069 #ifdef WL_CLIENT_SAE
17070 /** Called by the cfg80211 framework */
17071 static s32
wl_cfg80211_external_auth(struct wiphy * wiphy,struct net_device * ndev,struct cfg80211_external_auth_params * ext_auth_param)17072 wl_cfg80211_external_auth(struct wiphy *wiphy,
17073 struct net_device *ndev, struct cfg80211_external_auth_params *ext_auth_param)
17074 {
17075 int err = 0;
17076 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
17077 wl_assoc_mgr_cmd_t cmd;
17078
17079 WL_DBG(("Enter\n"));
17080
17081 if (!ext_auth_param ||
17082 ETHER_ISNULLADDR(ext_auth_param->bssid)) {
17083 WL_ERR(("Invalid wl_cfg80211_external_auth param\n"));
17084 return -EINVAL;
17085 }
17086
17087 cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
17088 cmd.length = sizeof(cmd);
17089 cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
17090 cmd.params = WL_ASSOC_MGR_PARAMS_EVENT_NONE;
17091 err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd), cfg->ioctl_buf,
17092 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
17093 if (unlikely(err)) {
17094 WL_ERR(("Failed to pause assoc(%d)\n", err));
17095 }
17096
17097 return err;
17098 }
17099 #endif /* WL_CLIENT_SAE */
17100
17101 #if defined(STATIC_WL_PRIV_STRUCT)
17102 static int
wl_init_escan_result_buf(struct bcm_cfg80211 * cfg)17103 wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
17104 {
17105 #ifdef DUAL_ESCAN_RESULT_BUFFER
17106 cfg->escan_info.escan_buf[0] = DHD_OS_PREALLOC(cfg->pub,
17107 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
17108 if (cfg->escan_info.escan_buf[0] == NULL) {
17109 WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
17110 return -ENOMEM;
17111 }
17112
17113 cfg->escan_info.escan_buf[1] = DHD_OS_PREALLOC(cfg->pub,
17114 DHD_PREALLOC_WIPHY_ESCAN1, ESCAN_BUF_SIZE);
17115 if (cfg->escan_info.escan_buf[1] == NULL) {
17116 WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
17117 return -ENOMEM;
17118 }
17119
17120 bzero(cfg->escan_info.escan_buf[0], ESCAN_BUF_SIZE);
17121 bzero(cfg->escan_info.escan_buf[1], ESCAN_BUF_SIZE);
17122 cfg->escan_info.escan_type[0] = 0;
17123 cfg->escan_info.escan_type[1] = 0;
17124 #else
17125 cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
17126 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
17127 if (cfg->escan_info.escan_buf == NULL) {
17128 WL_ERR(("Failed to alloc ESCAN_BUF\n"));
17129 return -ENOMEM;
17130 }
17131 bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
17132 #endif /* DUAL_ESCAN_RESULT_BUFFER */
17133
17134 return 0;
17135 }
17136
17137 static void
wl_deinit_escan_result_buf(struct bcm_cfg80211 * cfg)17138 wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
17139 {
17140 #ifdef DUAL_ESCAN_RESULT_BUFFER
17141 if (cfg->escan_info.escan_buf[0] != NULL) {
17142 cfg->escan_info.escan_buf[0] = NULL;
17143 cfg->escan_info.escan_type[0] = 0;
17144 }
17145
17146 if (cfg->escan_info.escan_buf[1] != NULL) {
17147 cfg->escan_info.escan_buf[1] = NULL;
17148 cfg->escan_info.escan_type[1] = 0;
17149 }
17150 #else
17151 if (cfg->escan_info.escan_buf != NULL) {
17152 cfg->escan_info.escan_buf = NULL;
17153 }
17154 #endif /* DUAL_ESCAN_RESULT_BUFFER */
17155 }
17156 #endif /* STATIC_WL_PRIV_STRUCT */
17157
wl_init_priv_mem(struct bcm_cfg80211 * cfg)17158 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
17159 {
17160 WL_DBG(("Enter \n"));
17161
17162 cfg->scan_results = (struct wl_scan_results *)MALLOCZ(cfg->osh,
17163 WL_SCAN_BUF_MAX);
17164 if (unlikely(!cfg->scan_results)) {
17165 WL_ERR(("Scan results alloc failed\n"));
17166 goto init_priv_mem_out;
17167 }
17168 cfg->conf = (struct wl_conf *)MALLOCZ(cfg->osh, sizeof(*cfg->conf));
17169 if (unlikely(!cfg->conf)) {
17170 WL_ERR(("wl_conf alloc failed\n"));
17171 goto init_priv_mem_out;
17172 }
17173 cfg->scan_req_int = (void *)MALLOCZ(cfg->osh,
17174 sizeof(*cfg->scan_req_int));
17175 if (unlikely(!cfg->scan_req_int)) {
17176 WL_ERR(("Scan req alloc failed\n"));
17177 goto init_priv_mem_out;
17178 }
17179 cfg->ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
17180 if (unlikely(!cfg->ioctl_buf)) {
17181 WL_ERR(("Ioctl buf alloc failed\n"));
17182 goto init_priv_mem_out;
17183 }
17184 cfg->escan_ioctl_buf = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
17185 if (unlikely(!cfg->escan_ioctl_buf)) {
17186 WL_ERR(("Ioctl buf alloc failed\n"));
17187 goto init_priv_mem_out;
17188 }
17189 cfg->extra_buf = (void *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
17190 if (unlikely(!cfg->extra_buf)) {
17191 WL_ERR(("Extra buf alloc failed\n"));
17192 goto init_priv_mem_out;
17193 }
17194 cfg->pmk_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->pmk_list));
17195 if (unlikely(!cfg->pmk_list)) {
17196 WL_ERR(("pmk list alloc failed\n"));
17197 goto init_priv_mem_out;
17198 }
17199 #if defined(STATIC_WL_PRIV_STRUCT)
17200 cfg->conn_info = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->conn_info));
17201 if (unlikely(!cfg->conn_info)) {
17202 WL_ERR(("cfg->conn_info alloc failed\n"));
17203 goto init_priv_mem_out;
17204 }
17205 cfg->ie = (void *)MALLOC(cfg->osh, sizeof(*cfg->ie));
17206 if (unlikely(!cfg->ie)) {
17207 WL_ERR(("cfg->ie alloc failed\n"));
17208 goto init_priv_mem_out;
17209 }
17210 if (unlikely(wl_init_escan_result_buf(cfg))) {
17211 WL_ERR(("Failed to init escan resul buf\n"));
17212 goto init_priv_mem_out;
17213 }
17214 #endif /* STATIC_WL_PRIV_STRUCT */
17215 cfg->afx_hdl = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->afx_hdl));
17216 if (unlikely(!cfg->afx_hdl)) {
17217 WL_ERR(("afx hdl alloc failed\n"));
17218 goto init_priv_mem_out;
17219 } else {
17220 init_completion(&cfg->act_frm_scan);
17221 init_completion(&cfg->wait_next_af);
17222
17223 INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
17224 }
17225 #ifdef WLTDLS
17226 if (cfg->tdls_mgmt_frame) {
17227 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
17228 cfg->tdls_mgmt_frame = NULL;
17229 cfg->tdls_mgmt_frame_len = 0;
17230 }
17231 #endif /* WLTDLS */
17232 return 0;
17233
17234 init_priv_mem_out:
17235 wl_deinit_priv_mem(cfg);
17236
17237 return -ENOMEM;
17238 }
17239
wl_deinit_priv_mem(struct bcm_cfg80211 * cfg)17240 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
17241 {
17242 MFREE(cfg->osh, cfg->scan_results, WL_SCAN_BUF_MAX);
17243 MFREE(cfg->osh, cfg->conf, sizeof(*cfg->conf));
17244 MFREE(cfg->osh, cfg->scan_req_int, sizeof(*cfg->scan_req_int));
17245 MFREE(cfg->osh, cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
17246 MFREE(cfg->osh, cfg->escan_ioctl_buf, WLC_IOCTL_MAXLEN);
17247 MFREE(cfg->osh, cfg->extra_buf, WL_EXTRA_BUF_MAX);
17248 MFREE(cfg->osh, cfg->pmk_list, sizeof(*cfg->pmk_list));
17249 #if defined(STATIC_WL_PRIV_STRUCT)
17250 MFREE(cfg->osh, cfg->conn_info, sizeof(*cfg->conn_info));
17251 MFREE(cfg->osh, cfg->ie, sizeof(*cfg->ie));
17252 wl_deinit_escan_result_buf(cfg);
17253 #endif /* STATIC_WL_PRIV_STRUCT */
17254 if (cfg->afx_hdl) {
17255 cancel_work_sync(&cfg->afx_hdl->work);
17256 MFREE(cfg->osh, cfg->afx_hdl, sizeof(*cfg->afx_hdl));
17257 }
17258
17259 }
17260
wl_create_event_handler(struct bcm_cfg80211 * cfg)17261 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
17262 {
17263 int ret = 0;
17264 WL_DBG(("Enter \n"));
17265
17266 /* Allocate workqueue for event */
17267 if (!cfg->event_workq) {
17268 cfg->event_workq = alloc_workqueue("dhd_eventd",
17269 WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 1);
17270 }
17271
17272 if (!cfg->event_workq) {
17273 WL_ERR(("event_workq alloc_workqueue failed\n"));
17274 ret = -ENOMEM;
17275 } else {
17276 INIT_WORK(&cfg->event_work, wl_event_handler);
17277 }
17278 return ret;
17279 }
17280
wl_destroy_event_handler(struct bcm_cfg80211 * cfg)17281 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
17282 {
17283 if (cfg && cfg->event_workq) {
17284 cancel_work_sync(&cfg->event_work);
17285 destroy_workqueue(cfg->event_workq);
17286 cfg->event_workq = NULL;
17287 }
17288 }
17289
wl_terminate_event_handler(struct net_device * dev)17290 void wl_terminate_event_handler(struct net_device *dev)
17291 {
17292 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17293
17294 if (cfg) {
17295 wl_destroy_event_handler(cfg);
17296 wl_flush_eq(cfg);
17297 }
17298 }
17299
17300 #ifdef DHD_LOSSLESS_ROAMING
wl_del_roam_timeout(struct bcm_cfg80211 * cfg)17301 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
17302 {
17303 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
17304
17305 /* restore prec_map to ALLPRIO */
17306 dhdp->dequeue_prec_map = ALLPRIO;
17307 if (timer_pending(&cfg->roam_timeout)) {
17308 del_timer_sync(&cfg->roam_timeout);
17309 }
17310
17311 }
17312
wl_roam_timeout(unsigned long data)17313 static void wl_roam_timeout(unsigned long data)
17314 {
17315 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
17316 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
17317
17318 WL_ERR(("roam timer expired\n"));
17319
17320 /* restore prec_map to ALLPRIO */
17321 dhdp->dequeue_prec_map = ALLPRIO;
17322 }
17323
17324 #endif /* DHD_LOSSLESS_ROAMING */
17325
17326 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
17327 #define CP_CHAN_INFO_RAT_MODE_LTE 3
17328 #define CP_CHAN_INFO_RAT_MODE_NR5G 7
17329 int g_mhs_chan_for_cpcoex = 0;
17330
17331 struct __packed cam_cp_noti_info {
17332 u8 rat;
17333 u32 band;
17334 u32 channel;
17335 };
17336
17337 int
wl_cfg80211_send_msg_to_ril()17338 wl_cfg80211_send_msg_to_ril()
17339 {
17340 int id, buf = 1;
17341
17342 id = IPC_SYSTEM_CP_CHANNEL_INFO;
17343 dev_ril_bridge_send_msg(id, sizeof(int), &buf);
17344 WL_ERR(("[BeyondX] send message to ril.\n"));
17345
17346 OSL_SLEEP(500);
17347 return 0;
17348 }
17349
17350 int
wl_cfg80211_ril_bridge_notifier_call(struct notifier_block * nb,unsigned long size,void * buf)17351 wl_cfg80211_ril_bridge_notifier_call(struct notifier_block *nb,
17352 unsigned long size, void *buf)
17353 {
17354 struct dev_ril_bridge_msg *msg;
17355 struct cam_cp_noti_info *cp_noti_info;
17356 static int mhs_channel_for_4g, mhs_channel_for_5g;
17357 static int recv_msg_4g, recv_msg_5g;
17358
17359 WL_ERR(("[BeyondX] receive message from ril.\n"));
17360 msg = (struct dev_ril_bridge_msg *)buf;
17361
17362 if (msg->dev_id == IPC_SYSTEM_CP_CHANNEL_INFO &&
17363 msg->data_len <= sizeof(struct cam_cp_noti_info)) {
17364 u8 rat;
17365 u32 band;
17366 u32 channel;
17367
17368 cp_noti_info = (struct cam_cp_noti_info *)msg->data;
17369 rat = cp_noti_info->rat;
17370 band = cp_noti_info->band;
17371 channel = cp_noti_info->channel;
17372
17373 /* LTE/5G Band/Freq information => Mobile Hotspot channel mapping.
17374 * LTE/B40: 38650~39649 => Ch.11
17375 * LTE/B41: 39650~41589 => Ch.1
17376 * 5G/N41: 499200~537999 => Ch.1
17377 */
17378 if (rat == CP_CHAN_INFO_RAT_MODE_LTE) {
17379 recv_msg_4g = 1;
17380 if (channel >= 38650 && channel <= 39649) {
17381 mhs_channel_for_4g = 11;
17382 } else if (channel >= 39650 && channel <= 41589) {
17383 mhs_channel_for_4g = 1;
17384 }
17385 }
17386 if (rat == CP_CHAN_INFO_RAT_MODE_NR5G) {
17387 recv_msg_5g = 1;
17388 if (channel >= 499200 && channel <= 537999) {
17389 mhs_channel_for_5g = 1;
17390 }
17391 }
17392
17393 WL_DBG(("[BeyondX] rat: %u, band: %u, channel: %u, mhs_channel_for_4g: %u, "
17394 "mhs_channel_for_5g: %u\n", rat, band, channel,
17395 mhs_channel_for_4g, mhs_channel_for_5g));
17396
17397 if (recv_msg_4g && recv_msg_5g) {
17398 if (mhs_channel_for_4g && mhs_channel_for_5g) {
17399 /* if 4G/B40 + 5G/N41, select channel 6 for MHS */
17400 if (mhs_channel_for_4g == 11 && mhs_channel_for_5g == 1) {
17401 g_mhs_chan_for_cpcoex = 6;
17402 /* if 4G(except for B40) + 5G/N41, select channel 1 for MHS */
17403 } else {
17404 g_mhs_chan_for_cpcoex = 1;
17405 }
17406 } else {
17407 g_mhs_chan_for_cpcoex = mhs_channel_for_4g ? mhs_channel_for_4g :
17408 mhs_channel_for_5g ? mhs_channel_for_5g : 0;
17409 }
17410 mhs_channel_for_4g = mhs_channel_for_5g = 0;
17411 recv_msg_4g = recv_msg_5g = 0;
17412 }
17413 }
17414
17415 return 0;
17416 }
17417
17418 static struct notifier_block wl_cfg80211_ril_bridge_notifier = {
17419 .notifier_call = wl_cfg80211_ril_bridge_notifier_call,
17420 };
17421
17422 static bool wl_cfg80211_ril_bridge_notifier_registered = FALSE;
17423 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
17424
17425 static s32
wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,unsigned long state,void * ptr)17426 wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
17427 unsigned long state, void *ptr)
17428 {
17429 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
17430 struct net_device *dev = ptr;
17431 #else
17432 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
17433 #endif /* LINUX_VERSION < VERSION(3, 11, 0) */
17434 struct wireless_dev *wdev = NULL;
17435 struct bcm_cfg80211 *cfg = NULL;
17436
17437 WL_DBG(("Enter state:%lu ndev%p \n", state, dev));
17438 if (!dev) {
17439 WL_ERR(("dev null\n"));
17440 return NOTIFY_DONE;
17441 }
17442
17443 wdev = ndev_to_wdev(dev);
17444 if (!wdev) {
17445 WL_ERR(("wdev null. Do nothing\n"));
17446 return NOTIFY_DONE;
17447 }
17448
17449 cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
17450 if (!cfg || (cfg != wl_cfg80211_get_bcmcfg())) {
17451 /* If cfg80211 priv is null or doesn't match return */
17452 WL_ERR(("wrong cfg ptr (%p)\n", cfg));
17453 return NOTIFY_DONE;
17454 }
17455
17456 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
17457 /* Nothing to be done for primary I/F */
17458 return NOTIFY_DONE;
17459 }
17460
17461 switch (state) {
17462 case NETDEV_DOWN:
17463 {
17464 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
17465 int max_wait_timeout = 2;
17466 int max_wait_count = 100;
17467 int refcnt = 0;
17468 unsigned long limit = jiffies + max_wait_timeout * HZ;
17469 while (work_pending(&wdev->cleanup_work)) {
17470 if (refcnt%5 == 0) {
17471 WL_ERR(("[NETDEV_DOWN] wait for "
17472 "complete of cleanup_work"
17473 " (%d th)\n", refcnt));
17474 }
17475 if (!time_before(jiffies, limit)) {
17476 WL_ERR(("[NETDEV_DOWN] cleanup_work"
17477 " of CFG80211 is not"
17478 " completed in %d sec\n",
17479 max_wait_timeout));
17480 break;
17481 }
17482 if (refcnt >= max_wait_count) {
17483 WL_ERR(("[NETDEV_DOWN] cleanup_work"
17484 " of CFG80211 is not"
17485 " completed in %d loop\n",
17486 max_wait_count));
17487 break;
17488 }
17489 set_current_state(TASK_INTERRUPTIBLE);
17490 (void)schedule_timeout(100);
17491 set_current_state(TASK_RUNNING);
17492 refcnt++;
17493 }
17494 #endif /* LINUX_VERSION < VERSION(3, 14, 0) */
17495 break;
17496 }
17497 case NETDEV_UNREGISTER:
17498 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
17499 /* after calling list_del_rcu(&wdev->list) */
17500 wl_dealloc_netinfo_by_wdev(cfg, wdev);
17501 break;
17502 case NETDEV_GOING_DOWN:
17503 /*
17504 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
17505 * In front of door, the function checks whether current scan
17506 * is working or not. If the scanning is still working,
17507 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
17508 */
17509 if (wl_get_drv_status(cfg, SCANNING, dev))
17510 wl_cfg80211_cancel_scan(cfg);
17511 break;
17512 }
17513 return NOTIFY_DONE;
17514 }
17515
17516 static struct notifier_block wl_cfg80211_netdev_notifier = {
17517 .notifier_call = wl_cfg80211_netdev_notifier_call,
17518 };
17519
17520 /*
17521 * to make sure we won't register the same notifier twice, otherwise a loop is likely to be
17522 * created in kernel notifier link list (with 'next' pointing to itself)
17523 */
17524 static bool wl_cfg80211_netdev_notifier_registered = FALSE;
17525
wl_cfg80211_concurrent_roam(struct bcm_cfg80211 * cfg,int enable)17526 static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
17527 {
17528 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
17529 bool p2p_connected = wl_cfgp2p_vif_created(cfg);
17530 struct net_info *iter, *next;
17531
17532 if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT))
17533 return;
17534
17535 WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
17536 enable, p2p_connected, connected_cnt));
17537 /* Disable FW roam when we have a concurrent P2P connection */
17538 if (enable && p2p_connected && connected_cnt > 1) {
17539
17540 /* Mark it as to be reverted */
17541 cfg->roam_flags |= WL_ROAM_REVERT_STATUS;
17542 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17543 for_each_ndev(cfg, iter, next) {
17544 GCC_DIAGNOSTIC_POP();
17545 if (iter->ndev && iter->wdev &&
17546 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
17547 if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE)
17548 == BCME_OK) {
17549 iter->roam_off = TRUE;
17550 }
17551 else {
17552 WL_ERR(("error to enable roam_off\n"));
17553 }
17554 }
17555 }
17556 }
17557 else if (!enable && (cfg->roam_flags & WL_ROAM_REVERT_STATUS)) {
17558 cfg->roam_flags &= ~WL_ROAM_REVERT_STATUS;
17559 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17560 for_each_ndev(cfg, iter, next) {
17561 GCC_DIAGNOSTIC_POP();
17562 if (iter->ndev && iter->wdev &&
17563 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
17564 if (iter->roam_off != WL_INVALID) {
17565 if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE)
17566 == BCME_OK) {
17567 iter->roam_off = FALSE;
17568 }
17569 else {
17570 WL_ERR(("error to disable roam_off\n"));
17571 }
17572 }
17573 }
17574 }
17575 }
17576
17577 return;
17578 }
17579
wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 * cfg)17580 static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
17581 {
17582 struct net_info *iter, *next;
17583 u32 ctl_chan = 0;
17584 u32 chanspec = 0;
17585 u32 pre_ctl_chan = 0;
17586 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
17587 cfg->vsdb_mode = false;
17588
17589 if (connected_cnt <= 1) {
17590 return;
17591 }
17592 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17593 for_each_ndev(cfg, iter, next) {
17594 GCC_DIAGNOSTIC_POP();
17595 /* p2p discovery iface ndev could be null */
17596 if (iter->ndev) {
17597 chanspec = 0;
17598 ctl_chan = 0;
17599 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
17600 if (wldev_iovar_getint(iter->ndev, "chanspec",
17601 (s32 *)&chanspec) == BCME_OK) {
17602 chanspec = wl_chspec_driver_to_host(chanspec);
17603 ctl_chan = wf_chspec_ctlchan(chanspec);
17604 wl_update_prof(cfg, iter->ndev, NULL,
17605 &ctl_chan, WL_PROF_CHAN);
17606 }
17607 if (!cfg->vsdb_mode) {
17608 if (!pre_ctl_chan && ctl_chan)
17609 pre_ctl_chan = ctl_chan;
17610 else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) {
17611 cfg->vsdb_mode = true;
17612 }
17613 }
17614 }
17615 }
17616 }
17617 WL_MSG("wlan", "%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel");
17618 return;
17619 }
17620
17621 int
wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211 * cfg)17622 wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211 *cfg)
17623 {
17624 struct net_info *iter, *next;
17625 u32 chanspec = 0;
17626 u32 band = 0;
17627 u32 pre_band = 0;
17628 bool is_rsdb_supported = FALSE;
17629 bool rsdb_mode = FALSE;
17630
17631 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
17632
17633 if (!is_rsdb_supported) {
17634 return 0;
17635 }
17636
17637 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17638 for_each_ndev(cfg, iter, next) {
17639 GCC_DIAGNOSTIC_POP();
17640 /* p2p discovery iface ndev could be null */
17641 if (iter->ndev) {
17642 chanspec = 0;
17643 band = 0;
17644 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
17645 if (wldev_iovar_getint(iter->ndev, "chanspec",
17646 (s32 *)&chanspec) == BCME_OK) {
17647 chanspec = wl_chspec_driver_to_host(chanspec);
17648 band = CHSPEC_BAND(chanspec);
17649 }
17650
17651 if (!pre_band && band) {
17652 pre_band = band;
17653 } else if (pre_band && (pre_band != band)) {
17654 rsdb_mode = TRUE;
17655 }
17656 }
17657 }
17658 }
17659 WL_DBG(("RSDB mode is %s\n", rsdb_mode ? "enabled" : "disabled"));
17660
17661 return rsdb_mode;
17662 }
17663
wl_notifier_change_state(struct bcm_cfg80211 * cfg,struct net_info * _net_info,enum wl_status state,bool set)17664 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
17665 enum wl_status state, bool set)
17666 {
17667 s32 pm = PM_FAST;
17668 s32 err = BCME_OK;
17669 u32 mode;
17670 u32 chan = 0;
17671 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
17672 dhd_pub_t *dhd = cfg->pub;
17673 #ifdef RTT_SUPPORT
17674 rtt_status_info_t *rtt_status;
17675 #endif /* RTT_SUPPORT */
17676 if (dhd->busstate == DHD_BUS_DOWN) {
17677 WL_ERR(("busstate is DHD_BUS_DOWN!\n"));
17678 return 0;
17679 }
17680 WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
17681 state, set, _net_info->pm_restore, _net_info->ndev->name));
17682
17683 if (state != WL_STATUS_CONNECTED)
17684 return 0;
17685 mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
17686 if (set) {
17687 wl_cfg80211_concurrent_roam(cfg, 1);
17688 wl_cfg80211_determine_vsdb_mode(cfg);
17689 if (mode == WL_MODE_AP) {
17690 if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
17691 WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
17692 }
17693 pm = PM_OFF;
17694 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
17695 sizeof(pm))) != 0) {
17696 if (err == -ENODEV)
17697 WL_DBG(("%s:netdev not ready\n",
17698 _net_info->ndev->name));
17699 else
17700 WL_ERR(("%s:error (%d)\n",
17701 _net_info->ndev->name, err));
17702
17703 wl_cfg80211_update_power_mode(_net_info->ndev);
17704 }
17705 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
17706 #if defined(WLTDLS)
17707 if (wl_cfg80211_is_concurrent_mode(primary_dev)) {
17708 err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
17709 }
17710 #endif /* defined(WLTDLS) */
17711
17712 #ifdef DISABLE_FRAMEBURST_VSDB
17713 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
17714 wl_cfg80211_is_concurrent_mode(primary_dev) &&
17715 !wl_cfg80211_determine_p2p_rsdb_mode(cfg)) {
17716 wl_cfg80211_set_frameburst(cfg, FALSE);
17717 }
17718 #endif /* DISABLE_FRAMEBURST_VSDB */
17719 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
17720 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
17721 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
17722 /* Enable frameburst for
17723 * STA/SoftAP concurrent mode
17724 */
17725 wl_cfg80211_set_frameburst(cfg, TRUE);
17726 }
17727 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
17728 } else { /* clear */
17729 chan = 0;
17730 /* clear chan information when the net device is disconnected */
17731 wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
17732 wl_cfg80211_determine_vsdb_mode(cfg);
17733 if (primary_dev == _net_info->ndev) {
17734 pm = PM_FAST;
17735 #ifdef RTT_SUPPORT
17736 rtt_status = GET_RTTSTATE(dhd);
17737 if (rtt_status->status != RTT_ENABLED) {
17738 #endif /* RTT_SUPPORT */
17739 if (dhd_conf_get_pm(dhd) >= 0)
17740 pm = dhd_conf_get_pm(dhd);
17741 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
17742 sizeof(pm))) != 0) {
17743 if (err == -ENODEV)
17744 WL_DBG(("%s:netdev not ready\n",
17745 _net_info->ndev->name));
17746 else
17747 WL_ERR(("%s:error (%d)\n",
17748 _net_info->ndev->name, err));
17749
17750 wl_cfg80211_update_power_mode(_net_info->ndev);
17751 }
17752 #ifdef RTT_SUPPORT
17753 }
17754 #endif /* RTT_SUPPORT */
17755 }
17756 wl_cfg80211_concurrent_roam(cfg, 0);
17757 #if defined(WLTDLS)
17758 if (!wl_cfg80211_is_concurrent_mode(primary_dev)) {
17759 err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
17760 }
17761 #endif /* defined(WLTDLS) */
17762
17763 #if defined(DISABLE_FRAMEBURST_VSDB)
17764 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE)) {
17765 wl_cfg80211_set_frameburst(cfg, TRUE);
17766 }
17767 #endif /* DISABLE_FRAMEBURST_VSDB */
17768 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
17769 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
17770 (cfg->ap_oper_channel <= CH_MAX_2G_CHANNEL)) {
17771 /* Disable frameburst for stand-alone 2GHz SoftAP */
17772 wl_cfg80211_set_frameburst(cfg, FALSE);
17773 }
17774 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
17775 }
17776 return err;
17777 }
17778
17779 #ifdef DHD_LOSSLESS_ROAMING
wl_init_roam_timeout(struct bcm_cfg80211 * cfg)17780 static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
17781 {
17782 int err = 0;
17783
17784 /* Init roam timer */
17785 init_timer_compat(&cfg->roam_timeout, wl_roam_timeout, cfg);
17786
17787 return err;
17788 }
17789 #endif /* DHD_LOSSLESS_ROAMING */
17790
wl_init_priv(struct bcm_cfg80211 * cfg)17791 static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
17792 {
17793 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
17794 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
17795 s32 err = 0;
17796
17797 cfg->scan_request = NULL;
17798 cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
17799 #ifdef DISABLE_BUILTIN_ROAM
17800 cfg->roam_on = false;
17801 #else
17802 cfg->roam_on = true;
17803 #endif /* DISABLE_BUILTIN_ROAM */
17804 cfg->active_scan = true;
17805 cfg->rf_blocked = false;
17806 cfg->vsdb_mode = false;
17807 #if defined(BCMSDIO) || defined(BCMDBUS)
17808 cfg->wlfc_on = false;
17809 #endif /* BCMSDIO || BCMDBUS */
17810 cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
17811 cfg->disable_roam_event = false;
17812 /* register interested state */
17813 set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
17814 spin_lock_init(&cfg->cfgdrv_lock);
17815 mutex_init(&cfg->ioctl_buf_sync);
17816 init_waitqueue_head(&cfg->netif_change_event);
17817 init_completion(&cfg->send_af_done);
17818 init_completion(&cfg->iface_disable);
17819 mutex_init(&cfg->usr_sync);
17820 mutex_init(&cfg->event_sync);
17821 mutex_init(&cfg->if_sync);
17822 mutex_init(&cfg->scan_sync);
17823 mutex_init(&cfg->pm_sync);
17824 #ifdef WLTDLS
17825 mutex_init(&cfg->tdls_sync);
17826 #endif /* WLTDLS */
17827 #ifdef WL_BCNRECV
17828 mutex_init(&cfg->bcn_sync);
17829 #endif /* WL_BCNRECV */
17830 #ifdef WL_WPS_SYNC
17831 wl_init_wps_reauth_sm(cfg);
17832 #endif /* WL_WPS_SYNC */
17833 wl_init_eq(cfg);
17834 err = wl_init_priv_mem(cfg);
17835 if (err)
17836 return err;
17837 if (wl_create_event_handler(cfg))
17838 return -ENOMEM;
17839 wl_init_event_handler(cfg);
17840 err = wl_init_scan(cfg);
17841 if (err)
17842 return err;
17843 #ifdef DHD_LOSSLESS_ROAMING
17844 err = wl_init_roam_timeout(cfg);
17845 if (err) {
17846 return err;
17847 }
17848 #endif /* DHD_LOSSLESS_ROAMING */
17849 wl_init_conf(cfg->conf);
17850 wl_init_prof(cfg, ndev);
17851 wl_link_down(cfg);
17852 DNGL_FUNC(dhd_cfg80211_init, (cfg));
17853 #ifdef WL_NAN
17854 cfg->nan_dp_state = NAN_DP_STATE_DISABLED;
17855 init_waitqueue_head(&cfg->ndp_if_change_event);
17856 mutex_init(&cfg->nancfg.nan_sync);
17857 init_waitqueue_head(&cfg->nancfg.nan_event_wait);
17858 #endif /* WL_NAN */
17859 cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
17860 cfg->pmk_list->pmkids.count = 0;
17861 cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
17862 return err;
17863 }
17864
wl_deinit_priv(struct bcm_cfg80211 * cfg)17865 static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
17866 {
17867 DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
17868 wl_destroy_event_handler(cfg);
17869 wl_flush_eq(cfg);
17870 wl_link_down(cfg);
17871 del_timer_sync(&cfg->scan_timeout);
17872 #ifdef DHD_LOSSLESS_ROAMING
17873 del_timer_sync(&cfg->roam_timeout);
17874 #endif // endif
17875 wl_deinit_priv_mem(cfg);
17876 if (wl_cfg80211_netdev_notifier_registered) {
17877 wl_cfg80211_netdev_notifier_registered = FALSE;
17878 unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
17879 }
17880 }
17881
17882 #if defined(WL_ENABLE_P2P_IF)
wl_cfg80211_attach_p2p(struct bcm_cfg80211 * cfg)17883 static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
17884 {
17885 WL_TRACE(("Enter \n"));
17886
17887 if (wl_cfgp2p_register_ndev(cfg) < 0) {
17888 WL_ERR(("P2P attach failed. \n"));
17889 return -ENODEV;
17890 }
17891
17892 return 0;
17893 }
17894
wl_cfg80211_detach_p2p(struct bcm_cfg80211 * cfg)17895 static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
17896 {
17897 struct wireless_dev *wdev;
17898
17899 WL_DBG(("Enter \n"));
17900 if (!cfg) {
17901 WL_ERR(("Invalid Ptr\n"));
17902 return -EINVAL;
17903 }
17904 else {
17905 wdev = cfg->p2p_wdev;
17906 if (!wdev) {
17907 WL_ERR(("Invalid Ptr\n"));
17908 return -EINVAL;
17909 }
17910 }
17911
17912 wl_cfgp2p_unregister_ndev(cfg);
17913
17914 cfg->p2p_wdev = NULL;
17915 cfg->p2p_net = NULL;
17916 WL_DBG(("Freeing 0x%p \n", wdev));
17917 kfree(wdev);
17918
17919 return 0;
17920 }
17921 #endif
17922
wl_cfg80211_attach_post(struct net_device * ndev)17923 static s32 wl_cfg80211_attach_post(struct net_device *ndev)
17924 {
17925 struct bcm_cfg80211 * cfg;
17926 s32 err = 0;
17927 s32 ret = 0;
17928 WL_TRACE(("In\n"));
17929 if (unlikely(!ndev)) {
17930 WL_ERR(("ndev is invaild\n"));
17931 return -ENODEV;
17932 }
17933 cfg = wl_get_cfg(ndev);
17934 if (unlikely(!cfg)) {
17935 WL_ERR(("cfg is invaild\n"));
17936 return -EINVAL;
17937 }
17938 if (!wl_get_drv_status(cfg, READY, ndev)) {
17939 if (cfg->wdev) {
17940 ret = wl_cfgp2p_supported(cfg, ndev);
17941 if (ret > 0) {
17942 #if !defined(WL_ENABLE_P2P_IF)
17943 cfg->wdev->wiphy->interface_modes |=
17944 (BIT(NL80211_IFTYPE_P2P_CLIENT)|
17945 BIT(NL80211_IFTYPE_P2P_GO));
17946 #endif /* !WL_ENABLE_P2P_IF */
17947 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
17948 goto fail;
17949
17950 #if defined(WL_ENABLE_P2P_IF)
17951 if (cfg->p2p_net) {
17952 /* Update MAC addr for p2p0 interface here. */
17953 memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
17954 cfg->p2p_net->dev_addr[0] |= 0x02;
17955 WL_MSG(cfg->p2p_net->name, "p2p_dev_addr="MACDBG "\n",
17956 MAC2STRDBG(cfg->p2p_net->dev_addr));
17957 } else {
17958 WL_ERR(("p2p_net not yet populated."
17959 " Couldn't update the MAC Address for p2p0 \n"));
17960 return -ENODEV;
17961 }
17962 #endif /* WL_ENABLE_P2P_IF */
17963 cfg->p2p_supported = true;
17964 } else if (ret == 0) {
17965 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
17966 goto fail;
17967 } else {
17968 /* SDIO bus timeout */
17969 err = -ENODEV;
17970 goto fail;
17971 }
17972 }
17973 }
17974 wl_set_drv_status(cfg, READY, ndev);
17975 fail:
17976 return err;
17977 }
17978
wl_get_cfg(struct net_device * ndev)17979 struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev)
17980 {
17981 struct wireless_dev *wdev = ndev->ieee80211_ptr;
17982
17983 if (!wdev || !wdev->wiphy)
17984 return NULL;
17985
17986 return wiphy_priv(wdev->wiphy);
17987 }
17988
17989 s32
wl_cfg80211_net_attach(struct net_device * primary_ndev)17990 wl_cfg80211_net_attach(struct net_device *primary_ndev)
17991 {
17992 struct bcm_cfg80211 *cfg = wl_get_cfg(primary_ndev);
17993
17994 if (!cfg) {
17995 WL_ERR(("cfg null\n"));
17996 return BCME_ERROR;
17997 }
17998 #ifdef WL_STATIC_IF
17999 /* Register dummy n/w iface. FW init will happen only from dev_open */
18000 if (wl_cfg80211_register_static_if(cfg, NL80211_IFTYPE_STATION,
18001 WL_STATIC_IFNAME_PREFIX) == NULL) {
18002 WL_ERR(("static i/f registration failed!\n"));
18003 return BCME_ERROR;
18004 }
18005 #endif /* WL_STATIC_IF */
18006 return BCME_OK;
18007 }
18008
18009 #ifdef CONFIG_AP6XXX_WIFI6_HDF
18010 void set_krn_wiphy(void *pwiphy);
18011 #endif
18012
wl_cfg80211_attach(struct net_device * ndev,void * context)18013 s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
18014 {
18015 struct wireless_dev *wdev;
18016 struct bcm_cfg80211 *cfg;
18017 s32 err = 0;
18018 struct device *dev;
18019 u16 bssidx = 0;
18020 u16 ifidx = 0;
18021 dhd_pub_t *dhd = (struct dhd_pub *)(context);
18022
18023 WL_TRACE(("In\n"));
18024 if (!ndev) {
18025 WL_ERR(("ndev is invaild\n"));
18026 return -ENODEV;
18027 }
18028 WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
18029 dev = wl_cfg80211_get_parent_dev();
18030
18031 wdev = (struct wireless_dev *)MALLOCZ(dhd->osh, sizeof(*wdev));
18032 if (unlikely(!wdev)) {
18033 WL_ERR(("Could not allocate wireless device\n"));
18034 return -ENOMEM;
18035 }
18036 err = wl_setup_wiphy(wdev, dev, context);
18037 if (unlikely(err)) {
18038 MFREE(dhd->osh, wdev, sizeof(*wdev));
18039 return -ENOMEM;
18040 }
18041 #ifdef WLMESH_CFG80211
18042 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_MESH);
18043 #else
18044 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
18045 #endif
18046 cfg = wiphy_priv(wdev->wiphy);
18047 cfg->wdev = wdev;
18048 cfg->pub = context;
18049 cfg->osh = dhd->osh;
18050 INIT_LIST_HEAD(&cfg->net_list);
18051 INIT_LIST_HEAD(&cfg->vndr_oui_list);
18052 spin_lock_init(&cfg->vndr_oui_sync);
18053 spin_lock_init(&cfg->net_list_sync);
18054 ndev->ieee80211_ptr = wdev;
18055 #ifdef CONFIG_AP6XXX_WIFI6_HDF
18056 set_krn_wiphy(wdev->wiphy);
18057 #endif
18058 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
18059 wdev->netdev = ndev;
18060 cfg->state_notifier = wl_notifier_change_state;
18061 err = wl_alloc_netinfo(cfg, ndev, wdev, WL_IF_TYPE_STA, PM_ENABLE, bssidx, ifidx);
18062 if (err) {
18063 WL_ERR(("Failed to alloc net_info (%d)\n", err));
18064 goto cfg80211_attach_out;
18065 }
18066 err = wl_init_priv(cfg);
18067 if (err) {
18068 WL_ERR(("Failed to init iwm_priv (%d)\n", err));
18069 goto cfg80211_attach_out;
18070 }
18071
18072 err = wl_setup_rfkill(cfg, TRUE);
18073 if (err) {
18074 WL_ERR(("Failed to setup rfkill %d\n", err));
18075 goto cfg80211_attach_out;
18076 }
18077 #ifdef DEBUGFS_CFG80211
18078 err = wl_setup_debugfs(cfg);
18079 if (err) {
18080 WL_ERR(("Failed to setup debugfs %d\n", err));
18081 goto cfg80211_attach_out;
18082 }
18083 #endif // endif
18084 if (!wl_cfg80211_netdev_notifier_registered) {
18085 wl_cfg80211_netdev_notifier_registered = TRUE;
18086 err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
18087 if (err) {
18088 wl_cfg80211_netdev_notifier_registered = FALSE;
18089 WL_ERR(("Failed to register notifierl %d\n", err));
18090 goto cfg80211_attach_out;
18091 }
18092 }
18093 #if defined(COEX_DHCP)
18094 cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
18095 if (!cfg->btcoex_info)
18096 goto cfg80211_attach_out;
18097 #endif // endif
18098
18099 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
18100 wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
18101 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
18102
18103 #if defined(WL_ENABLE_P2P_IF)
18104 err = wl_cfg80211_attach_p2p(cfg);
18105 if (err)
18106 goto cfg80211_attach_out;
18107 #endif
18108
18109 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
18110 #ifdef WL_NAN
18111 WL_DBG(("NAN: Armed wl_cfgnan_delayed_disable work\n"));
18112 INIT_DELAYED_WORK(&cfg->nan_disable, wl_cfgnan_delayed_disable);
18113 #endif /* WL_NAN */
18114 cfg->rssi_sum_report = FALSE;
18115 return err;
18116
18117 cfg80211_attach_out:
18118 wl_cfg80211_detach(cfg);
18119 return err;
18120 }
18121
wl_cfg80211_detach(struct bcm_cfg80211 * cfg)18122 void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
18123 {
18124 WL_DBG(("Enter\n"));
18125 if (!cfg) {
18126 return;
18127 }
18128 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
18129
18130 #if defined(COEX_DHCP)
18131 wl_cfg80211_btcoex_deinit();
18132 cfg->btcoex_info = NULL;
18133 #endif // endif
18134
18135 wl_setup_rfkill(cfg, FALSE);
18136 #ifdef DEBUGFS_CFG80211
18137 wl_free_debugfs(cfg);
18138 #endif // endif
18139 if (cfg->p2p_supported) {
18140 if (timer_pending(&cfg->p2p->listen_timer))
18141 del_timer_sync(&cfg->p2p->listen_timer);
18142 wl_cfgp2p_deinit_priv(cfg);
18143 }
18144
18145 #ifdef WL_WPS_SYNC
18146 wl_deinit_wps_reauth_sm(cfg);
18147 #endif /* WL_WPS_SYNC */
18148
18149 if (timer_pending(&cfg->scan_timeout))
18150 del_timer_sync(&cfg->scan_timeout);
18151 #ifdef DHD_LOSSLESS_ROAMING
18152 if (timer_pending(&cfg->roam_timeout)) {
18153 del_timer_sync(&cfg->roam_timeout);
18154 }
18155 #endif /* DHD_LOSSLESS_ROAMING */
18156
18157 #ifdef WL_STATIC_IF
18158 wl_cfg80211_unregister_static_if(cfg);
18159 #endif /* WL_STATIC_IF */
18160 #if defined(WL_CFG80211_P2P_DEV_IF)
18161 if (cfg->p2p_wdev)
18162 wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
18163 #endif /* WL_CFG80211_P2P_DEV_IF */
18164 #if defined(WL_ENABLE_P2P_IF)
18165 wl_cfg80211_detach_p2p(cfg);
18166 #endif
18167 wl_cfg80211_ibss_vsie_free(cfg);
18168 wl_dealloc_netinfo_by_wdev(cfg, cfg->wdev);
18169 wl_cfg80211_set_bcmcfg(NULL);
18170 wl_deinit_priv(cfg);
18171 wl_cfg80211_clear_parent_dev();
18172 #if defined(RSSIAVG)
18173 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
18174 wl_free_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
18175 #endif
18176 #if defined(BSSCACHE)
18177 wl_release_bss_cache_ctrl(&cfg->g_bss_cache_ctrl);
18178 #endif
18179 wl_free_wdev(cfg);
18180 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
18181 * structure "cfg", which is the private part of wiphy, has been freed in
18182 * wl_free_wdev !!!!!!!!!!!
18183 */
18184 WL_DBG(("Exit\n"));
18185 }
18186
18187 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
wl_cfg80211_register_dev_ril_bridge_event_notifier()18188 void wl_cfg80211_register_dev_ril_bridge_event_notifier()
18189 {
18190 WL_DBG(("Enter\n"));
18191 if (!wl_cfg80211_ril_bridge_notifier_registered) {
18192 s32 err = 0;
18193 wl_cfg80211_ril_bridge_notifier_registered = TRUE;
18194 err = register_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
18195 if (err) {
18196 wl_cfg80211_ril_bridge_notifier_registered = FALSE;
18197 WL_ERR(("Failed to register ril_notifier! %d\n", err));
18198 }
18199 }
18200 }
18201
wl_cfg80211_unregister_dev_ril_bridge_event_notifier()18202 void wl_cfg80211_unregister_dev_ril_bridge_event_notifier()
18203 {
18204 WL_DBG(("Enter\n"));
18205 if (wl_cfg80211_ril_bridge_notifier_registered) {
18206 wl_cfg80211_ril_bridge_notifier_registered = FALSE;
18207 unregister_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
18208 }
18209 }
18210 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
18211
wl_print_event_data(struct bcm_cfg80211 * cfg,uint32 event_type,const wl_event_msg_t * e)18212 static void wl_print_event_data(struct bcm_cfg80211 *cfg,
18213 uint32 event_type, const wl_event_msg_t *e)
18214 {
18215 s32 status = ntoh32(e->status);
18216 s32 reason = ntoh32(e->reason);
18217 s32 ifidx = ntoh32(e->ifidx);
18218 s32 bssidx = ntoh32(e->bsscfgidx);
18219
18220 switch (event_type) {
18221 case WLC_E_ESCAN_RESULT:
18222 if ((status == WLC_E_STATUS_SUCCESS) ||
18223 (status == WLC_E_STATUS_ABORT)) {
18224 WL_INFORM_MEM(("event_type (%d), ifidx: %d"
18225 " bssidx: %d scan_type:%d\n",
18226 event_type, ifidx, bssidx, status));
18227 }
18228 break;
18229 case WLC_E_LINK:
18230 case WLC_E_DISASSOC:
18231 case WLC_E_DISASSOC_IND:
18232 case WLC_E_DEAUTH:
18233 case WLC_E_DEAUTH_IND:
18234 WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
18235 " status:%d reason:%d\n",
18236 event_type, ifidx, bssidx, status, reason));
18237 break;
18238
18239 default:
18240 /* Print only when DBG verbose is enabled */
18241 WL_DBG(("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
18242 event_type, ifidx, bssidx, status, reason));
18243 }
18244 }
18245
wl_event_handler(struct work_struct * work_data)18246 static void wl_event_handler(struct work_struct *work_data)
18247 {
18248 struct bcm_cfg80211 *cfg = NULL;
18249 struct wl_event_q *e;
18250 struct wireless_dev *wdev = NULL;
18251
18252 WL_DBG(("Enter \n"));
18253 BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
18254 cfg->wl_evt_hdlr_entry_time = OSL_LOCALTIME_NS();
18255 DHD_EVENT_WAKE_LOCK(cfg->pub);
18256 while ((e = wl_deq_event(cfg))) {
18257 s32 status = ntoh32(e->emsg.status);
18258 u32 event_type = ntoh32(e->emsg.event_type);
18259 bool scan_cmplt_evt = (event_type == WLC_E_ESCAN_RESULT) &&
18260 ((status == WLC_E_STATUS_SUCCESS) || (status == WLC_E_STATUS_ABORT));
18261
18262 cfg->wl_evt_deq_time = OSL_LOCALTIME_NS();
18263 if (scan_cmplt_evt) {
18264 cfg->scan_deq_time = OSL_LOCALTIME_NS();
18265 }
18266 /* Print only critical events to avoid too many prints */
18267 wl_print_event_data(cfg, e->etype, &e->emsg);
18268
18269 if (e->emsg.ifidx > WL_MAX_IFS) {
18270 WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
18271 goto fail;
18272 }
18273
18274 /* Make sure iface operations, don't creat race conditions */
18275 mutex_lock(&cfg->if_sync);
18276 if (!(wdev = wl_get_wdev_by_fw_idx(cfg,
18277 e->emsg.bsscfgidx, e->emsg.ifidx))) {
18278 /* For WLC_E_IF would be handled by wl_host_event */
18279 if (e->etype != WLC_E_IF)
18280 WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
18281 " Ignoring event.\n", e->emsg.bsscfgidx));
18282 } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
18283 dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
18284 if (dhd->busstate == DHD_BUS_DOWN) {
18285 WL_ERR((": BUS is DOWN.\n"));
18286 } else
18287 {
18288 WL_DBG(("event_type %d event_sub %d\n",
18289 ntoh32(e->emsg.event_type),
18290 ntoh32(e->emsg.reason)));
18291 cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
18292 &e->emsg, e->edata);
18293 if (scan_cmplt_evt) {
18294 cfg->scan_hdlr_cmplt_time = OSL_LOCALTIME_NS();
18295 }
18296 }
18297 } else {
18298 WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
18299 }
18300 mutex_unlock(&cfg->if_sync);
18301 fail:
18302 wl_put_event(cfg, e);
18303 if (scan_cmplt_evt) {
18304 cfg->scan_cmplt_time = OSL_LOCALTIME_NS();
18305 }
18306 cfg->wl_evt_hdlr_exit_time = OSL_LOCALTIME_NS();
18307 }
18308 DHD_EVENT_WAKE_UNLOCK(cfg->pub);
18309 }
18310
18311 /*
18312 * Generic API to handle critical events which doesnt need
18313 * cfg enquening and sleepable API calls.
18314 */
18315 s32
wl_cfg80211_handle_critical_events(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)18316 wl_cfg80211_handle_critical_events(struct bcm_cfg80211 *cfg,
18317 const wl_event_msg_t * e)
18318 {
18319 s32 ret = BCME_ERROR;
18320 u32 event_type = ntoh32(e->event_type);
18321
18322 if (event_type >= WLC_E_LAST) {
18323 return BCME_ERROR;
18324 }
18325
18326 switch (event_type) {
18327 case WLC_E_NAN_CRITICAL: {
18328 #ifdef WL_NAN
18329 if (ntoh32(e->reason) == WL_NAN_EVENT_STOP) {
18330 ret =
18331 wl_cfgvendor_nan_send_async_disable_resp(cfg->static_ndev->ieee80211_ptr);
18332 }
18333 #endif /* WL_NAN */
18334 break;
18335 }
18336 default:
18337 ret = BCME_ERROR;
18338 }
18339 return ret;
18340 }
18341
18342 void
wl_cfg80211_event(struct net_device * ndev,const wl_event_msg_t * e,void * data)18343 wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
18344 {
18345 s32 status = ntoh32(e->status);
18346 u32 event_type = ntoh32(e->event_type);
18347 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18348 struct net_info *netinfo;
18349
18350 WL_DBG(("event_type (%d): reason (%d): %s\n", event_type, ntoh32(e->reason),
18351 bcmevent_get_name(event_type)));
18352 if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
18353 WL_ERR(("Stale event ignored\n"));
18354 return;
18355 }
18356
18357 if (cfg->event_workq == NULL) {
18358 WL_ERR(("Event handler is not created\n"));
18359 return;
18360 }
18361
18362 if (event_type == WLC_E_IF) {
18363 /* Don't process WLC_E_IF events in wl_cfg80211 layer */
18364 return;
18365 }
18366
18367 netinfo = wl_get_netinfo_by_fw_idx(cfg, e->bsscfgidx, e->ifidx);
18368 if (!netinfo) {
18369 /* Since the netinfo entry is not there, the netdev entry is not
18370 * created via cfg80211 interface. so the event is not of interest
18371 * to the cfg80211 layer.
18372 */
18373 WL_TRACE(("ignore event %d, not interested\n", event_type));
18374 return;
18375 }
18376
18377 /* Handle wl_cfg80211_critical_events */
18378 if (wl_cfg80211_handle_critical_events(cfg, e) == BCME_OK) {
18379 return;
18380 }
18381
18382 if (event_type == WLC_E_PFN_NET_FOUND) {
18383 WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
18384 }
18385 else if (event_type == WLC_E_PFN_NET_LOST) {
18386 WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
18387 }
18388
18389 if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
18390 queue_work(cfg->event_workq, &cfg->event_work);
18391 }
18392 /* Mark timeout value for thread sched */
18393 if ((event_type == WLC_E_ESCAN_RESULT) &&
18394 ((status == WLC_E_STATUS_SUCCESS) ||
18395 (status == WLC_E_STATUS_ABORT))) {
18396 cfg->scan_enq_time = OSL_LOCALTIME_NS();
18397 WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
18398 status, work_busy(&cfg->event_work)));
18399 }
18400 }
18401
wl_init_eq(struct bcm_cfg80211 * cfg)18402 static void wl_init_eq(struct bcm_cfg80211 *cfg)
18403 {
18404 wl_init_eq_lock(cfg);
18405 INIT_LIST_HEAD(&cfg->eq_list);
18406 }
18407
wl_flush_eq(struct bcm_cfg80211 * cfg)18408 static void wl_flush_eq(struct bcm_cfg80211 *cfg)
18409 {
18410 struct wl_event_q *e;
18411 unsigned long flags;
18412
18413 flags = wl_lock_eq(cfg);
18414 while (!list_empty_careful(&cfg->eq_list)) {
18415 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
18416 list_del(&e->eq_list);
18417 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
18418 }
18419 wl_unlock_eq(cfg, flags);
18420 }
18421
18422 /*
18423 * retrieve first queued event from head
18424 */
18425
wl_deq_event(struct bcm_cfg80211 * cfg)18426 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
18427 {
18428 struct wl_event_q *e = NULL;
18429 unsigned long flags;
18430
18431 flags = wl_lock_eq(cfg);
18432 if (likely(!list_empty(&cfg->eq_list))) {
18433 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
18434 list_del(&e->eq_list);
18435 }
18436 wl_unlock_eq(cfg, flags);
18437
18438 return e;
18439 }
18440
18441 /*
18442 * push event to tail of the queue
18443 */
18444
18445 static s32
wl_enq_event(struct bcm_cfg80211 * cfg,struct net_device * ndev,u32 event,const wl_event_msg_t * msg,void * data)18446 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event,
18447 const wl_event_msg_t *msg, void *data)
18448 {
18449 struct wl_event_q *e;
18450 s32 err = 0;
18451 uint32 evtq_size;
18452 uint32 data_len;
18453 unsigned long flags;
18454
18455 data_len = 0;
18456 if (data)
18457 data_len = ntoh32(msg->datalen);
18458 evtq_size = (uint32)(sizeof(struct wl_event_q) + data_len);
18459 e = (struct wl_event_q *)MALLOCZ(cfg->osh, evtq_size);
18460 if (unlikely(!e)) {
18461 WL_ERR(("event alloc failed\n"));
18462 return -ENOMEM;
18463 }
18464 e->etype = event;
18465 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
18466 if (data)
18467 memcpy(e->edata, data, data_len);
18468 e->datalen = data_len;
18469 flags = wl_lock_eq(cfg);
18470 list_add_tail(&e->eq_list, &cfg->eq_list);
18471 wl_unlock_eq(cfg, flags);
18472
18473 return err;
18474 }
18475
wl_put_event(struct bcm_cfg80211 * cfg,struct wl_event_q * e)18476 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e)
18477 {
18478 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
18479 }
18480
wl_config_infra(struct bcm_cfg80211 * cfg,struct net_device * ndev,u16 iftype)18481 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype)
18482 {
18483 s32 infra = 0;
18484 s32 err = 0;
18485 bool skip_infra = false;
18486
18487 switch (iftype) {
18488 case WL_IF_TYPE_IBSS:
18489 case WL_IF_TYPE_AIBSS:
18490 infra = 0;
18491 break;
18492 case WL_IF_TYPE_AP:
18493 case WL_IF_TYPE_STA:
18494 case WL_IF_TYPE_P2P_GO:
18495 case WL_IF_TYPE_P2P_GC:
18496 /* Intentional fall through */
18497 infra = 1;
18498 break;
18499 #ifdef WLMESH_CFG80211
18500 case NL80211_IFTYPE_MESH_POINT:
18501 infra = WL_BSSTYPE_MESH;
18502 break;
18503 #endif /* WLMESH_CFG80211 */
18504 case WL_IF_TYPE_MONITOR:
18505 case WL_IF_TYPE_NAN:
18506 /* Intentionall fall through */
18507 default:
18508 skip_infra = true;
18509 WL_ERR(("Skipping infra setting for type:%d\n", iftype));
18510 break;
18511 }
18512
18513 if (!skip_infra) {
18514 infra = htod32(infra);
18515 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
18516 if (unlikely(err)) {
18517 WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
18518 return err;
18519 }
18520 }
18521 return 0;
18522 }
18523
wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf * ev,u16 event,bool set)18524 void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set)
18525 {
18526 if (!ev || (event > WLC_E_LAST))
18527 return;
18528
18529 if (ev->num < MAX_EVENT_BUF_NUM) {
18530 ev->event[ev->num].type = event;
18531 ev->event[ev->num].set = set;
18532 ev->num++;
18533 } else {
18534 WL_ERR(("evenbuffer doesn't support > %u events. Update"
18535 " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
18536 ASSERT(0);
18537 }
18538 }
18539
wl_cfg80211_apply_eventbuffer(struct net_device * ndev,struct bcm_cfg80211 * cfg,wl_eventmsg_buf_t * ev)18540 s32 wl_cfg80211_apply_eventbuffer(
18541 struct net_device *ndev,
18542 struct bcm_cfg80211 *cfg,
18543 wl_eventmsg_buf_t *ev)
18544 {
18545 char eventmask[WL_EVENTING_MASK_LEN];
18546 int i, ret = 0;
18547 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
18548
18549 if (!ev || (!ev->num))
18550 return -EINVAL;
18551
18552 mutex_lock(&cfg->event_sync);
18553
18554 /* Read event_msgs mask */
18555 ret = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
18556 if (unlikely(ret)) {
18557 WL_ERR(("Get event_msgs error (%d)\n", ret));
18558 goto exit;
18559 }
18560 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
18561
18562 /* apply the set bits */
18563 for (i = 0; i < ev->num; i++) {
18564 if (ev->event[i].set)
18565 setbit(eventmask, ev->event[i].type);
18566 else
18567 clrbit(eventmask, ev->event[i].type);
18568 }
18569
18570 /* Write updated Event mask */
18571 ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf,
18572 sizeof(iovbuf), NULL);
18573 if (unlikely(ret)) {
18574 WL_ERR(("Set event_msgs error (%d)\n", ret));
18575 }
18576
18577 exit:
18578 mutex_unlock(&cfg->event_sync);
18579 return ret;
18580 }
18581
wl_add_remove_eventmsg(struct net_device * ndev,u16 event,bool add)18582 s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
18583 {
18584 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
18585 s8 eventmask[WL_EVENTING_MASK_LEN];
18586 s32 err = 0;
18587 struct bcm_cfg80211 *cfg;
18588
18589 if (!ndev)
18590 return -ENODEV;
18591
18592 cfg = wl_get_cfg(ndev);
18593 if (!cfg)
18594 return -ENODEV;
18595
18596 mutex_lock(&cfg->event_sync);
18597
18598 /* Setup event_msgs */
18599 err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
18600 if (unlikely(err)) {
18601 WL_ERR(("Get event_msgs error (%d)\n", err));
18602 goto eventmsg_out;
18603 }
18604 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
18605 if (add) {
18606 setbit(eventmask, event);
18607 } else {
18608 clrbit(eventmask, event);
18609 }
18610 err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
18611 sizeof(iovbuf), NULL);
18612 if (unlikely(err)) {
18613 WL_ERR(("Set event_msgs error (%d)\n", err));
18614 goto eventmsg_out;
18615 }
18616
18617 eventmsg_out:
18618 mutex_unlock(&cfg->event_sync);
18619 return err;
18620 }
18621
wl_construct_reginfo(struct bcm_cfg80211 * cfg,s32 bw_cap)18622 static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
18623 {
18624 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
18625 struct ieee80211_channel *band_chan_arr = NULL;
18626 wl_uint32_list_t *list;
18627 u32 i, j, index, n_2g, n_5g, band, channel, array_size;
18628 u32 *n_cnt = NULL;
18629 chanspec_t c = 0;
18630 s32 err = BCME_OK;
18631 bool update;
18632 bool ht40_allowed;
18633 u8 *pbuf = NULL;
18634 bool dfs_radar_disabled = FALSE;
18635
18636 #define LOCAL_BUF_LEN 2048
18637 pbuf = (u8 *)MALLOCZ(cfg->osh, LOCAL_BUF_LEN);
18638 if (pbuf == NULL) {
18639 WL_ERR(("failed to allocate local buf\n"));
18640 return -ENOMEM;
18641 }
18642
18643 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
18644 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
18645 if (err != 0) {
18646 WL_ERR(("get chanspecs failed with %d\n", err));
18647 MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
18648 return err;
18649 }
18650
18651 list = (wl_uint32_list_t *)(void *)pbuf;
18652 band = array_size = n_2g = n_5g = 0;
18653 for (i = 0; i < dtoh32(list->count); i++) {
18654 index = 0;
18655 update = false;
18656 ht40_allowed = false;
18657 c = (chanspec_t)dtoh32(list->element[i]);
18658 c = wl_chspec_driver_to_host(c);
18659 channel = wf_chspec_ctlchan(c);
18660
18661 if (!CHSPEC_IS40(c) && ! CHSPEC_IS20(c)) {
18662 WL_DBG(("HT80/160/80p80 center channel : %d\n", channel));
18663 continue;
18664 }
18665 if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
18666 (channel <= CH_MAX_2G_CHANNEL)) {
18667 band_chan_arr = __wl_2ghz_channels;
18668 array_size = ARRAYSIZE(__wl_2ghz_channels);
18669 n_cnt = &n_2g;
18670 band = IEEE80211_BAND_2GHZ;
18671 ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false;
18672 } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
18673 band_chan_arr = __wl_5ghz_a_channels;
18674 array_size = ARRAYSIZE(__wl_5ghz_a_channels);
18675 n_cnt = &n_5g;
18676 band = IEEE80211_BAND_5GHZ;
18677 ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true;
18678 } else {
18679 WL_ERR(("Invalid channel Sepc. 0x%x.\n", c));
18680 continue;
18681 }
18682 if (!ht40_allowed && CHSPEC_IS40(c))
18683 continue;
18684 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
18685 if (band_chan_arr[j].hw_value == channel) {
18686 update = true;
18687 break;
18688 }
18689 }
18690 if (update)
18691 index = j;
18692 else
18693 index = *n_cnt;
18694 if (!dhd_conf_match_channel(cfg->pub, channel))
18695 continue;
18696 if (index < array_size) {
18697 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
18698 band_chan_arr[index].center_freq =
18699 ieee80211_channel_to_frequency(channel);
18700 #else
18701 band_chan_arr[index].center_freq =
18702 ieee80211_channel_to_frequency(channel, band);
18703 #endif // endif
18704 band_chan_arr[index].hw_value = channel;
18705 band_chan_arr[index].beacon_found = false;
18706
18707 if (CHSPEC_IS40(c) && ht40_allowed) {
18708 /* assuming the order is HT20, HT40 Upper,
18709 * HT40 lower from chanspecs
18710 */
18711 u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
18712 if (CHSPEC_SB_UPPER(c)) {
18713 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
18714 band_chan_arr[index].flags &=
18715 ~IEEE80211_CHAN_NO_HT40;
18716 band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
18717 } else {
18718 /* It should be one of
18719 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
18720 */
18721 band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
18722 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
18723 band_chan_arr[index].flags |=
18724 IEEE80211_CHAN_NO_HT40MINUS;
18725 }
18726 } else {
18727 band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
18728 if (!dfs_radar_disabled) {
18729 if (band == IEEE80211_BAND_2GHZ)
18730 channel |= WL_CHANSPEC_BAND_2G;
18731 else
18732 channel |= WL_CHANSPEC_BAND_5G;
18733 channel |= WL_CHANSPEC_BW_20;
18734 channel = wl_chspec_host_to_driver(channel);
18735 err = wldev_iovar_getint(dev, "per_chan_info", &channel);
18736 if (!err) {
18737 if (channel & WL_CHAN_RADAR) {
18738 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
18739 band_chan_arr[index].flags |=
18740 (IEEE80211_CHAN_RADAR
18741 | IEEE80211_CHAN_NO_IBSS);
18742 #else
18743 band_chan_arr[index].flags |=
18744 IEEE80211_CHAN_RADAR;
18745 #endif // endif
18746 }
18747
18748 if (channel & WL_CHAN_PASSIVE)
18749 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
18750 band_chan_arr[index].flags |=
18751 IEEE80211_CHAN_PASSIVE_SCAN;
18752 #else
18753 band_chan_arr[index].flags |=
18754 IEEE80211_CHAN_NO_IR;
18755 #endif // endif
18756 } else if (err == BCME_UNSUPPORTED) {
18757 dfs_radar_disabled = TRUE;
18758 WL_ERR(("does not support per_chan_info\n"));
18759 }
18760 }
18761 }
18762 if (!update)
18763 (*n_cnt)++;
18764 }
18765
18766 }
18767 __wl_band_2ghz.n_channels = n_2g;
18768 __wl_band_5ghz_a.n_channels = n_5g;
18769 MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
18770 #undef LOCAL_BUF_LEN
18771
18772 return err;
18773 }
18774
__wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)18775 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
18776 {
18777 struct wiphy *wiphy;
18778 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
18779 u32 bandlist[3];
18780 u32 nband = 0;
18781 u32 i = 0;
18782 s32 err = 0;
18783 s32 index = 0;
18784 s32 nmode = 0;
18785 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18786 u32 j = 0;
18787 s32 vhtmode = 0;
18788 s32 txstreams = 0;
18789 s32 rxstreams = 0;
18790 s32 ldpc_cap = 0;
18791 s32 stbc_rx = 0;
18792 s32 stbc_tx = 0;
18793 s32 txbf_bfe_cap = 0;
18794 s32 txbf_bfr_cap = 0;
18795 #endif // endif
18796 s32 bw_cap = 0;
18797 s32 cur_band = -1;
18798 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, };
18799
18800 bzero(bandlist, sizeof(bandlist));
18801 err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist,
18802 sizeof(bandlist));
18803 if (unlikely(err)) {
18804 WL_ERR(("error read bandlist (%d)\n", err));
18805 return err;
18806 }
18807 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band,
18808 sizeof(s32));
18809 if (unlikely(err)) {
18810 WL_ERR(("error (%d)\n", err));
18811 return err;
18812 }
18813
18814 err = wldev_iovar_getint(dev, "nmode", &nmode);
18815 if (unlikely(err)) {
18816 WL_ERR(("error reading nmode (%d)\n", err));
18817 }
18818
18819 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18820 err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
18821 if (unlikely(err)) {
18822 WL_ERR(("error reading vhtmode (%d)\n", err));
18823 }
18824
18825 if (vhtmode) {
18826 err = wldev_iovar_getint(dev, "txstreams", &txstreams);
18827 if (unlikely(err)) {
18828 WL_ERR(("error reading txstreams (%d)\n", err));
18829 }
18830
18831 err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
18832 if (unlikely(err)) {
18833 WL_ERR(("error reading rxstreams (%d)\n", err));
18834 }
18835
18836 err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
18837 if (unlikely(err)) {
18838 WL_ERR(("error reading ldpc_cap (%d)\n", err));
18839 }
18840
18841 err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
18842 if (unlikely(err)) {
18843 WL_ERR(("error reading stbc_rx (%d)\n", err));
18844 }
18845
18846 err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
18847 if (unlikely(err)) {
18848 WL_ERR(("error reading stbc_tx (%d)\n", err));
18849 }
18850
18851 err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
18852 if (unlikely(err)) {
18853 WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
18854 }
18855
18856 err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
18857 if (unlikely(err)) {
18858 WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
18859 }
18860 }
18861 #endif // endif
18862
18863 /* For nmode and vhtmode check bw cap */
18864 if (nmode ||
18865 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18866 vhtmode ||
18867 #endif // endif
18868 0) {
18869 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
18870 if (unlikely(err)) {
18871 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
18872 }
18873 }
18874
18875 err = wl_construct_reginfo(cfg, bw_cap);
18876 if (err) {
18877 WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
18878 if (err != BCME_UNSUPPORTED)
18879 return err;
18880 }
18881
18882 wiphy = bcmcfg_to_wiphy(cfg);
18883 nband = bandlist[0];
18884
18885 for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
18886 index = -1;
18887 if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
18888 bands[IEEE80211_BAND_5GHZ] =
18889 &__wl_band_5ghz_a;
18890 index = IEEE80211_BAND_5GHZ;
18891 if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
18892 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
18893
18894 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18895 /* VHT capabilities. */
18896 if (vhtmode) {
18897 /* Supported */
18898 bands[index]->vht_cap.vht_supported = TRUE;
18899
18900 for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
18901 /* TX stream rates. */
18902 if (j <= txstreams) {
18903 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
18904 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
18905 } else {
18906 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
18907 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
18908 }
18909
18910 /* RX stream rates. */
18911 if (j <= rxstreams) {
18912 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
18913 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
18914 } else {
18915 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
18916 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
18917 }
18918 }
18919
18920 /* Capabilities */
18921 /* 80 MHz is mandatory */
18922 bands[index]->vht_cap.cap |=
18923 IEEE80211_VHT_CAP_SHORT_GI_80;
18924
18925 if (WL_BW_CAP_160MHZ(bw_cap)) {
18926 bands[index]->vht_cap.cap |=
18927 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
18928 bands[index]->vht_cap.cap |=
18929 IEEE80211_VHT_CAP_SHORT_GI_160;
18930 }
18931
18932 bands[index]->vht_cap.cap |=
18933 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
18934
18935 if (ldpc_cap)
18936 bands[index]->vht_cap.cap |=
18937 IEEE80211_VHT_CAP_RXLDPC;
18938
18939 if (stbc_tx)
18940 bands[index]->vht_cap.cap |=
18941 IEEE80211_VHT_CAP_TXSTBC;
18942
18943 if (stbc_rx)
18944 bands[index]->vht_cap.cap |=
18945 (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
18946
18947 if (txbf_bfe_cap)
18948 bands[index]->vht_cap.cap |=
18949 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
18950
18951 if (txbf_bfr_cap) {
18952 bands[index]->vht_cap.cap |=
18953 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
18954 }
18955
18956 if (txbf_bfe_cap || txbf_bfr_cap) {
18957 bands[index]->vht_cap.cap |=
18958 (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
18959 bands[index]->vht_cap.cap |=
18960 ((txstreams - 1) <<
18961 VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
18962 bands[index]->vht_cap.cap |=
18963 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
18964 }
18965
18966 /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
18967 bands[index]->vht_cap.cap |=
18968 (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
18969 WL_DBG(("__wl_update_wiphybands band[%d] vht_enab=%d vht_cap=%08x "
18970 "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
18971 index,
18972 bands[index]->vht_cap.vht_supported,
18973 bands[index]->vht_cap.cap,
18974 bands[index]->vht_cap.vht_mcs.rx_mcs_map,
18975 bands[index]->vht_cap.vht_mcs.tx_mcs_map));
18976 }
18977 #endif // endif
18978 }
18979 else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
18980 bands[IEEE80211_BAND_2GHZ] =
18981 &__wl_band_2ghz;
18982 index = IEEE80211_BAND_2GHZ;
18983 if (bw_cap == WLC_N_BW_40ALL)
18984 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
18985 }
18986
18987 if ((index >= 0) && nmode) {
18988 bands[index]->ht_cap.cap |=
18989 (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
18990 bands[index]->ht_cap.ht_supported = TRUE;
18991 bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
18992 bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
18993 /* An HT shall support all EQM rates for one spatial stream */
18994 bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
18995 }
18996
18997 }
18998
18999 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
19000 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
19001
19002 /* check if any bands populated otherwise makes 2Ghz as default */
19003 if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL &&
19004 wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) {
19005 /* Setup 2Ghz band as default */
19006 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
19007 }
19008
19009 if (notify)
19010 wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
19011
19012 return 0;
19013 }
19014
wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)19015 s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
19016 {
19017 s32 err;
19018
19019 mutex_lock(&cfg->usr_sync);
19020 err = __wl_update_wiphybands(cfg, notify);
19021 mutex_unlock(&cfg->usr_sync);
19022
19023 return err;
19024 }
19025
__wl_cfg80211_up(struct bcm_cfg80211 * cfg)19026 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
19027 {
19028 s32 err = 0;
19029 s32 ret = 0;
19030 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
19031 struct wireless_dev *wdev = ndev->ieee80211_ptr;
19032 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
19033 #ifdef WLTDLS
19034 u32 tdls;
19035 #endif /* WLTDLS */
19036 u16 wl_iftype = 0;
19037 u16 wl_mode = 0;
19038 u8 ioctl_buf[WLC_IOCTL_SMLEN];
19039
19040 WL_DBG(("In\n"));
19041
19042 if (!dhd_download_fw_on_driverload) {
19043 err = wl_create_event_handler(cfg);
19044 if (err) {
19045 WL_ERR(("wl_create_event_handler failed\n"));
19046 return err;
19047 }
19048 wl_init_event_handler(cfg);
19049 }
19050 /* Reserve 0x8000 toggle bit for P2P GO/GC */
19051 cfg->vif_macaddr_mask = 0x8000;
19052
19053 err = dhd_config_dongle(cfg);
19054 if (unlikely(err))
19055 return err;
19056
19057 #if 0
19058 /* terence 20180108: this patch will cause to kernel panic with below
19059 * steps in Android 4.4 with kernel 3.4
19060 * insmod bcmdhd.ko; hostapd /data/misc/wifi/hostapd.conf
19061 */
19062 /* Always bring up interface in STA mode.
19063 * Did observe , if previous SofAP Bringup/cleanup
19064 * is not done properly, iftype is stuck with AP mode.
19065 * So during next wlan0 up, forcing the type to STA
19066 */
19067 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
19068 if (!netinfo) {
19069 WL_ERR(("there is no netinfo\n"));
19070 return -ENODEV;
19071 }
19072 ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
19073 netinfo->iftype = WL_IF_TYPE_STA;
19074 #endif
19075
19076 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
19077 return -EINVAL;
19078 }
19079 err = wl_config_infra(cfg, ndev, wl_iftype);
19080 if (unlikely(err && err != -EINPROGRESS)) {
19081 WL_ERR(("wl_config_infra failed\n"));
19082 if (err == -1) {
19083 WL_ERR(("return error %d\n", err));
19084 return err;
19085 }
19086 }
19087
19088 err = wl_init_scan(cfg);
19089 if (err) {
19090 WL_ERR(("wl_init_scan failed\n"));
19091 return err;
19092 }
19093 err = __wl_update_wiphybands(cfg, true);
19094 if (unlikely(err)) {
19095 WL_ERR(("wl_update_wiphybands failed\n"));
19096 if (err == -1) {
19097 WL_ERR(("return error %d\n", err));
19098 return err;
19099 }
19100 }
19101
19102 /* Update wlc version in cfg struct already queried as part of DHD initialization */
19103 cfg->wlc_ver.wlc_ver_major = dhd->wlc_ver_major;
19104 cfg->wlc_ver.wlc_ver_minor = dhd->wlc_ver_minor;
19105
19106 if ((ret = wldev_iovar_getbuf(ndev, "scan_ver", NULL, 0,
19107 ioctl_buf, sizeof(ioctl_buf), NULL)) == BCME_OK) {
19108 WL_INFORM_MEM(("scan_params v2\n"));
19109 /* use scan_params ver2 */
19110 cfg->scan_params_v2 = true;
19111 } else {
19112 if (ret == BCME_UNSUPPORTED) {
19113 WL_INFORM(("scan_ver, UNSUPPORTED\n"));
19114 ret = BCME_OK;
19115 } else {
19116 WL_ERR(("get scan_ver err(%d)\n", ret));
19117 }
19118 }
19119 #ifdef DHD_LOSSLESS_ROAMING
19120 if (timer_pending(&cfg->roam_timeout)) {
19121 del_timer_sync(&cfg->roam_timeout);
19122 }
19123 #endif /* DHD_LOSSLESS_ROAMING */
19124
19125 err = dhd_monitor_init(cfg->pub);
19126
19127 #ifdef WL_HOST_BAND_MGMT
19128 /* By default the curr_band is initialized to BAND_AUTO */
19129 if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) {
19130 if (ret == BCME_UNSUPPORTED) {
19131 /* Don't fail the initialization, lets just
19132 * fall back to the original method
19133 */
19134 WL_ERR(("WL_HOST_BAND_MGMT defined, "
19135 "but roam_band iovar not supported \n"));
19136 } else {
19137 WL_ERR(("roam_band failed. ret=%d", ret));
19138 err = -1;
19139 }
19140 }
19141 #endif /* WL_HOST_BAND_MGMT */
19142 #ifdef WLTDLS
19143 if (wldev_iovar_getint(ndev, "tdls_enable", &tdls) == 0) {
19144 WL_DBG(("TDLS supported in fw\n"));
19145 cfg->tdls_supported = true;
19146 }
19147 #endif /* WLTDLS */
19148 #ifdef WL_IFACE_MGMT
19149 #ifdef CUSTOM_IF_MGMT_POLICY
19150 cfg->iface_data.policy = CUSTOM_IF_MGMT_POLICY;
19151 #else
19152 cfg->iface_data.policy = WL_IF_POLICY_DEFAULT;
19153 #endif /* CUSTOM_IF_MGMT_POLICY */
19154 #endif /* WL_IFACE_MGMT */
19155 #ifdef WL_NAN
19156 #ifdef WL_NANP2P
19157 if (FW_SUPPORTED(dhd, nanp2p)) {
19158 /* Enable NANP2P concurrent support */
19159 cfg->conc_disc = WL_NANP2P_CONC_SUPPORT;
19160 WL_INFORM_MEM(("nan + p2p conc discovery is supported\n"));
19161 cfg->nan_p2p_supported = true;
19162 }
19163 #endif /* WL_NANP2P */
19164 #endif /* WL_NAN */
19165
19166 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
19167 wl_set_drv_status(cfg, READY, ndev);
19168 return err;
19169 }
19170
__wl_cfg80211_down(struct bcm_cfg80211 * cfg)19171 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
19172 {
19173 s32 err = 0;
19174 struct net_info *iter, *next;
19175 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
19176 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
19177 defined(WL_NEW_CFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
19178 struct net_device *p2p_net = cfg->p2p_net;
19179 #endif
19180
19181 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
19182 WL_INFORM_MEM(("cfg80211 down\n"));
19183
19184 /* Check if cfg80211 interface is already down */
19185 if (!wl_get_drv_status(cfg, READY, ndev)) {
19186 WL_DBG(("cfg80211 interface is already down\n"));
19187 return err; /* it is even not ready */
19188 }
19189
19190 #ifdef SHOW_LOGTRACE
19191 /* Stop the event logging */
19192 wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
19193 #endif /* SHOW_LOGTRACE */
19194
19195 /* clear vendor OUI list */
19196 wl_vndr_ies_clear_vendor_oui_list(cfg);
19197
19198 /* Delete pm_enable_work */
19199 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
19200
19201 if (cfg->p2p_supported) {
19202 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
19203 #ifdef PROP_TXSTATUS_VSDB
19204 #if defined(BCMSDIO) || defined(BCMDBUS)
19205 if (wl_cfgp2p_vif_created(cfg)) {
19206 bool enabled = false;
19207 dhd_wlfc_get_enable(dhd, &enabled);
19208 if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
19209 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
19210 dhd_wlfc_deinit(dhd);
19211 cfg->wlfc_on = false;
19212 }
19213 }
19214 #endif /* BCMSDIO || BCMDBUS */
19215 #endif /* PROP_TXSTATUS_VSDB */
19216 }
19217
19218 #ifdef WL_NAN
19219 mutex_lock(&cfg->if_sync);
19220 /* Cancel pending nan disable work if any */
19221 if (delayed_work_pending(&cfg->nan_disable)) {
19222 WL_DBG(("Unarm the nan_disable work\n"));
19223 cancel_delayed_work_sync(&cfg->nan_disable);
19224 }
19225 cfg->nancfg.disable_reason = NAN_BUS_IS_DOWN;
19226 wl_cfgnan_disable(cfg);
19227 mutex_unlock(&cfg->if_sync);
19228 #endif /* WL_NAN */
19229
19230 if (!dhd_download_fw_on_driverload) {
19231 /* For built-in drivers/other drivers that do reset on
19232 * "ifconfig <primary_iface> down", cleanup any left
19233 * over interfaces
19234 */
19235 wl_cfg80211_cleanup_virtual_ifaces(cfg, false);
19236 }
19237 /* Clear used mac addr mask */
19238 cfg->vif_macaddr_mask = 0;
19239
19240 if (dhd->up)
19241 {
19242 /* If primary BSS is operational (for e.g SoftAP), bring it down */
19243 if (wl_cfg80211_bss_isup(ndev, 0)) {
19244 if (wl_cfg80211_bss_up(cfg, ndev, 0, 0) < 0)
19245 WL_ERR(("BSS down failed \n"));
19246 }
19247
19248 /* clear all the security setting on primary Interface */
19249 wl_cfg80211_clear_security(cfg);
19250 }
19251
19252 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19253 for_each_ndev(cfg, iter, next) {
19254 GCC_DIAGNOSTIC_POP();
19255 if (iter->ndev) /* p2p discovery iface is null */
19256 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
19257 }
19258
19259 #ifdef P2P_LISTEN_OFFLOADING
19260 wl_cfg80211_p2plo_deinit(cfg);
19261 #endif /* P2P_LISTEN_OFFLOADING */
19262
19263 /* cancel and notify scan complete, if scan request is pending */
19264 wl_cfg80211_cancel_scan(cfg);
19265 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19266 for_each_ndev(cfg, iter, next) {
19267 GCC_DIAGNOSTIC_POP();
19268 /* p2p discovery iface ndev ptr could be null */
19269 if (iter->ndev == NULL)
19270 continue;
19271 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19272 WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
19273 wl_get_drv_status(cfg, CONNECTING, ndev),
19274 wl_get_drv_status(cfg, CONNECTED, ndev),
19275 wl_get_drv_status(cfg, DISCONNECTING, ndev),
19276 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
19277
19278 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
19279 CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
19280 }
19281
19282 if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
19283 wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
19284
19285 u8 *latest_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
19286 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
19287 struct wireless_dev *wdev = ndev->ieee80211_ptr;
19288 struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid,
19289 wdev->ssid, wdev->ssid_len);
19290
19291 BCM_REFERENCE(bss);
19292
19293 CFG80211_CONNECT_RESULT(ndev,
19294 latest_bssid, bss, NULL, 0, NULL, 0,
19295 WLAN_STATUS_UNSPECIFIED_FAILURE,
19296 GFP_KERNEL);
19297 }
19298 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19299 wl_clr_drv_status(cfg, READY, iter->ndev);
19300 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
19301 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
19302 wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
19303 wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
19304 wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
19305 wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
19306 wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
19307 wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev);
19308 wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev);
19309 }
19310 bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
19311 NL80211_IFTYPE_STATION;
19312 #if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
19313 defined(WL_NEW_CFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
19314 if (p2p_net)
19315 dev_close(p2p_net);
19316 #endif
19317
19318 /* Avoid deadlock from wl_cfg80211_down */
19319 if (!dhd_download_fw_on_driverload) {
19320 mutex_unlock(&cfg->usr_sync);
19321 wl_destroy_event_handler(cfg);
19322 mutex_lock(&cfg->usr_sync);
19323 }
19324
19325 wl_flush_eq(cfg);
19326 wl_link_down(cfg);
19327 if (cfg->p2p_supported) {
19328 if (timer_pending(&cfg->p2p->listen_timer))
19329 del_timer_sync(&cfg->p2p->listen_timer);
19330 wl_cfgp2p_down(cfg);
19331 }
19332
19333 if (timer_pending(&cfg->scan_timeout)) {
19334 del_timer_sync(&cfg->scan_timeout);
19335 }
19336
19337 wl_cfg80211_clear_mgmt_vndr_ies(cfg);
19338 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
19339
19340 dhd_monitor_uninit();
19341 #ifdef WLAIBSS_MCHAN
19342 bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
19343 #endif /* WLAIBSS_MCHAN */
19344
19345 #ifdef WL11U
19346 /* Clear interworking element. */
19347 if (cfg->wl11u) {
19348 cfg->wl11u = FALSE;
19349 }
19350 #endif /* WL11U */
19351
19352 cfg->disable_roam_event = false;
19353 cfg->scan_params_v2 = false;
19354
19355 DNGL_FUNC(dhd_cfg80211_down, (cfg));
19356
19357 #ifdef DHD_IFDEBUG
19358 /* Printout all netinfo entries */
19359 wl_probe_wdev_all(cfg);
19360 #endif /* DHD_IFDEBUG */
19361
19362 return err;
19363 }
19364
wl_cfg80211_up(struct net_device * net)19365 s32 wl_cfg80211_up(struct net_device *net)
19366 {
19367 struct bcm_cfg80211 *cfg;
19368 s32 err = 0;
19369 int val = 1;
19370 dhd_pub_t *dhd;
19371 #ifdef DISABLE_PM_BCNRX
19372 s32 interr = 0;
19373 uint param = 0;
19374 s8 iovbuf[WLC_IOCTL_SMLEN];
19375 #endif /* DISABLE_PM_BCNRX */
19376
19377 WL_DBG(("In\n"));
19378 cfg = wl_get_cfg(net);
19379
19380 if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
19381 sizeof(int)) < 0)) {
19382 WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
19383 return err;
19384 }
19385 val = dtoh32(val);
19386 if (val != WLC_IOCTL_VERSION && val != 1) {
19387 WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
19388 val, WLC_IOCTL_VERSION));
19389 return BCME_VERSION;
19390 }
19391 ioctl_version = val;
19392 WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
19393 wl_ext_in4way_sync(net, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
19394 WL_EXT_STATUS_DISCONNECTED, NULL);
19395
19396 mutex_lock(&cfg->usr_sync);
19397 dhd = (dhd_pub_t *)(cfg->pub);
19398 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
19399 err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
19400 if (unlikely(err)) {
19401 mutex_unlock(&cfg->usr_sync);
19402 return err;
19403 }
19404 }
19405 #ifdef WLMESH_CFG80211
19406 cfg->wdev->wiphy->features |= NL80211_FEATURE_USERSPACE_MPM;
19407 #endif /* WLMESH_CFG80211 */
19408 #if defined(BCMSUP_4WAY_HANDSHAKE)
19409 if (dhd->fw_4way_handshake) {
19410 /* This is a hacky method to indicate fw 4WHS support and
19411 * is used only for kernels (kernels < 3.14). For newer
19412 * kernels, we would be using vendor extn. path to advertise
19413 * FW based 4-way handshake feature support.
19414 */
19415 cfg->wdev->wiphy->features |= NL80211_FEATURE_FW_4WAY_HANDSHAKE;
19416 }
19417 #endif /* BCMSUP_4WAY_HANDSHAKE */
19418 err = __wl_cfg80211_up(cfg);
19419 if (unlikely(err))
19420 WL_ERR(("__wl_cfg80211_up failed\n"));
19421
19422 #ifdef ROAM_CHANNEL_CACHE
19423 if (init_roam_cache(cfg, ioctl_version) == 0) {
19424 /* Enable support for Roam cache */
19425 cfg->rcc_enabled = true;
19426 WL_ERR(("Roam channel cache enabled\n"));
19427 } else {
19428 WL_ERR(("Failed to enable RCC.\n"));
19429 }
19430 #endif /* ROAM_CHANNEL_CACHE */
19431
19432 /* IOVAR configurations with 'up' condition */
19433 #ifdef DISABLE_PM_BCNRX
19434 interr = wldev_iovar_setbuf(net, "pm_bcnrx", (char *)¶m, sizeof(param), iovbuf,
19435 sizeof(iovbuf), &cfg->ioctl_buf_sync);
19436
19437 if (unlikely(interr)) {
19438 WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
19439 }
19440 #endif /* DISABLE_PM_BCNRX */
19441 #ifdef WL_CHAN_UTIL
19442 interr = wl_cfg80211_start_bssload_report(net);
19443 if (unlikely(interr)) {
19444 WL_ERR(("%s: Failed to start bssload_report eventing, err=%d\n",
19445 __FUNCTION__, interr));
19446 }
19447 #endif /* WL_CHAN_UTIL */
19448
19449 mutex_unlock(&cfg->usr_sync);
19450
19451 #ifdef WLAIBSS_MCHAN
19452 bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
19453 #endif /* WLAIBSS_MCHAN */
19454 return err;
19455 }
19456
19457 /* Private Event to Supplicant with indication that chip hangs */
wl_cfg80211_hang(struct net_device * dev,u16 reason)19458 int wl_cfg80211_hang(struct net_device *dev, u16 reason)
19459 {
19460 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19461 dhd_pub_t *dhd;
19462 if (!cfg) {
19463 return BCME_ERROR;
19464 }
19465
19466 RETURN_EIO_IF_NOT_UP(cfg);
19467
19468 dhd = (dhd_pub_t *)(cfg->pub);
19469 if ((dhd->hang_reason <= HANG_REASON_MASK) || (dhd->hang_reason >= HANG_REASON_MAX)) {
19470 WL_ERR(("wl_cfg80211_hang, Invalid hang reason 0x%x\n",
19471 dhd->hang_reason));
19472 dhd->hang_reason = HANG_REASON_UNKNOWN;
19473 }
19474 WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32)(dhd->hang_reason)));
19475
19476 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
19477 {
19478 if (dhd->up == TRUE) {
19479 CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
19480 }
19481 }
19482 #if defined(RSSIAVG)
19483 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
19484 #endif
19485 #if defined(BSSCACHE)
19486 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
19487 #endif
19488 if (cfg != NULL) {
19489 wl_link_down(cfg);
19490 }
19491 return 0;
19492 }
19493
wl_cfg80211_down(struct net_device * dev)19494 s32 wl_cfg80211_down(struct net_device *dev)
19495 {
19496 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19497 s32 err = BCME_ERROR;
19498
19499 WL_DBG(("In\n"));
19500
19501 if (cfg && (cfg == wl_cfg80211_get_bcmcfg())) {
19502 mutex_lock(&cfg->usr_sync);
19503 #if defined(RSSIAVG)
19504 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
19505 #endif
19506 #if defined(BSSCACHE)
19507 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
19508 #endif
19509 err = __wl_cfg80211_down(cfg);
19510 mutex_unlock(&cfg->usr_sync);
19511 }
19512
19513 return err;
19514 }
19515
19516 void
wl_cfg80211_sta_ifdown(struct net_device * dev)19517 wl_cfg80211_sta_ifdown(struct net_device *dev)
19518 {
19519 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19520
19521 WL_DBG(("In\n"));
19522
19523 if (cfg) {
19524 /* cancel scan if anything pending */
19525 wl_cfg80211_cancel_scan(cfg);
19526 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19527 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
19528 wl_get_drv_status(cfg, CONNECTED, dev)) {
19529 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
19530 }
19531 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19532 }
19533 }
19534
wl_read_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 item)19535 void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
19536 {
19537 unsigned long flags;
19538 void *rptr = NULL;
19539 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
19540
19541 if (!profile)
19542 return NULL;
19543 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
19544 switch (item) {
19545 case WL_PROF_SEC:
19546 rptr = &profile->sec;
19547 break;
19548 case WL_PROF_ACT:
19549 rptr = &profile->active;
19550 break;
19551 case WL_PROF_BSSID:
19552 rptr = profile->bssid;
19553 break;
19554 case WL_PROF_SSID:
19555 rptr = &profile->ssid;
19556 break;
19557 case WL_PROF_CHAN:
19558 rptr = &profile->channel;
19559 break;
19560 case WL_PROF_LATEST_BSSID:
19561 rptr = profile->latest_bssid;
19562 break;
19563 }
19564 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
19565 if (!rptr)
19566 WL_ERR(("invalid item (%d)\n", item));
19567 return rptr;
19568 }
19569
19570 static s32
wl_update_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,const void * data,s32 item)19571 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
19572 const wl_event_msg_t *e, const void *data, s32 item)
19573 {
19574 s32 err = 0;
19575 const struct wlc_ssid *ssid;
19576 unsigned long flags;
19577 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
19578
19579 if (!profile)
19580 return WL_INVALID;
19581 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
19582 switch (item) {
19583 case WL_PROF_SSID:
19584 ssid = (const wlc_ssid_t *) data;
19585 bzero(profile->ssid.SSID,
19586 sizeof(profile->ssid.SSID));
19587 profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
19588 memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
19589 break;
19590 case WL_PROF_BSSID:
19591 if (data)
19592 memcpy(profile->bssid, data, ETHER_ADDR_LEN);
19593 else
19594 bzero(profile->bssid, ETHER_ADDR_LEN);
19595 break;
19596 case WL_PROF_SEC:
19597 memcpy(&profile->sec, data, sizeof(profile->sec));
19598 break;
19599 case WL_PROF_ACT:
19600 profile->active = *(const bool *)data;
19601 break;
19602 case WL_PROF_BEACONINT:
19603 profile->beacon_interval = *(const u16 *)data;
19604 break;
19605 case WL_PROF_DTIMPERIOD:
19606 profile->dtim_period = *(const u8 *)data;
19607 break;
19608 case WL_PROF_CHAN:
19609 profile->channel = *(const u32*)data;
19610 break;
19611 case WL_PROF_LATEST_BSSID:
19612 if (data) {
19613 memcpy_s(profile->latest_bssid, sizeof(profile->latest_bssid),
19614 data, ETHER_ADDR_LEN);
19615 } else {
19616 memset_s(profile->latest_bssid, sizeof(profile->latest_bssid),
19617 0, ETHER_ADDR_LEN);
19618 }
19619 break;
19620 default:
19621 err = -EOPNOTSUPP;
19622 break;
19623 }
19624 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
19625
19626 if (err == -EOPNOTSUPP)
19627 WL_ERR(("unsupported item (%d)\n", item));
19628
19629 return err;
19630 }
19631
wl_cfg80211_dbg_level(u32 level)19632 void wl_cfg80211_dbg_level(u32 level)
19633 {
19634 /*
19635 * prohibit to change debug level
19636 * by insmod parameter.
19637 * eventually debug level will be configured
19638 * in compile time by using CONFIG_XXX
19639 */
19640 /* wl_dbg_level = level; */
19641 }
19642
wl_is_ibssmode(struct bcm_cfg80211 * cfg,struct net_device * ndev)19643 static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev)
19644 {
19645 return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS;
19646 }
19647
wl_is_ibssstarter(struct bcm_cfg80211 * cfg)19648 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
19649 {
19650 return cfg->ibss_starter;
19651 }
19652
wl_rst_ie(struct bcm_cfg80211 * cfg)19653 static void wl_rst_ie(struct bcm_cfg80211 *cfg)
19654 {
19655 struct wl_ie *ie = wl_to_ie(cfg);
19656
19657 ie->offset = 0;
19658 bzero(ie->buf, sizeof(ie->buf));
19659 }
19660
wl_add_ie(struct bcm_cfg80211 * cfg,u8 t,u8 l,u8 * v)19661 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
19662 {
19663 struct wl_ie *ie = wl_to_ie(cfg);
19664 s32 err = 0;
19665
19666 if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
19667 WL_ERR(("ei crosses buffer boundary\n"));
19668 return -ENOSPC;
19669 }
19670 ie->buf[ie->offset] = t;
19671 ie->buf[ie->offset + 1] = l;
19672 memcpy(&ie->buf[ie->offset + 2], v, l);
19673 ie->offset += l + 2;
19674
19675 return err;
19676 }
19677
wl_update_hidden_ap_ie(wl_bss_info_t * bi,const u8 * ie_stream,u32 * ie_size,bool update_ssid)19678 static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 *ie_size,
19679 bool update_ssid)
19680 {
19681 u8 *ssidie;
19682 int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN);
19683 int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len;
19684 /* cfg80211_find_ie defined in kernel returning const u8 */
19685
19686 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19687 ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
19688 GCC_DIAGNOSTIC_POP();
19689
19690 /* ERROR out if
19691 * 1. No ssid IE is FOUND or
19692 * 2. New ssid length is > what was allocated for existing ssid (as
19693 * we do not want to overwrite the rest of the IEs) or
19694 * 3. If in case of erroneous buffer input where ssid length doesnt match the space
19695 * allocated to it.
19696 */
19697 if (!ssidie) {
19698 return;
19699 }
19700 available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream);
19701 remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
19702 unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size);
19703 if (ssidie[1] > available_buffer_len) {
19704 WL_ERR_MEM(("wl_update_hidden_ap_ie: skip wl_update_hidden_ap_ie : overflow\n"));
19705 return;
19706 }
19707
19708 if (ssidie[1] != ssid_len) {
19709 if (ssidie[1]) {
19710 WL_ERR_RLMT(("wl_update_hidden_ap_ie: Wrong SSID len: %d != %d\n",
19711 ssidie[1], bi->SSID_len));
19712 }
19713 /*
19714 * The bss info in firmware gets updated from beacon and probe resp.
19715 * In case of hidden network, the bss_info that got updated by beacon,
19716 * will not carry SSID and this can result in cfg80211_get_bss not finding a match.
19717 * so include the SSID element.
19718 */
19719 if ((update_ssid && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) {
19720 WL_INFORM_MEM(("Changing the SSID Info.\n"));
19721 memmove(ssidie + ssid_len + 2,
19722 (ssidie + 2) + ssidie[1],
19723 remaining_ie_buf_len);
19724 memcpy(ssidie + 2, bi->SSID, ssid_len);
19725 *ie_size = *ie_size + ssid_len - ssidie[1];
19726 ssidie[1] = ssid_len;
19727 } else if (ssid_len < ssidie[1]) {
19728 WL_ERR_MEM(("wl_update_hidden_ap_ie: Invalid SSID len: %d < %d\n",
19729 bi->SSID_len, ssidie[1]));
19730 }
19731 return;
19732 }
19733 if (*(ssidie + 2) == '\0')
19734 memcpy(ssidie + 2, bi->SSID, ssid_len);
19735 return;
19736 }
19737
wl_mrg_ie(struct bcm_cfg80211 * cfg,u8 * ie_stream,u16 ie_size)19738 static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size)
19739 {
19740 struct wl_ie *ie = wl_to_ie(cfg);
19741 s32 err = 0;
19742
19743 if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
19744 WL_ERR(("ei_stream crosses buffer boundary\n"));
19745 return -ENOSPC;
19746 }
19747 memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
19748 ie->offset += ie_size;
19749
19750 return err;
19751 }
19752
wl_cp_ie(struct bcm_cfg80211 * cfg,u8 * dst,u16 dst_size)19753 static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size)
19754 {
19755 struct wl_ie *ie = wl_to_ie(cfg);
19756 s32 err = 0;
19757
19758 if (unlikely(ie->offset > dst_size)) {
19759 WL_ERR(("dst_size is not enough\n"));
19760 return -ENOSPC;
19761 }
19762 memcpy(dst, &ie->buf[0], ie->offset);
19763
19764 return err;
19765 }
19766
wl_get_ielen(struct bcm_cfg80211 * cfg)19767 static u32 wl_get_ielen(struct bcm_cfg80211 *cfg)
19768 {
19769 struct wl_ie *ie = wl_to_ie(cfg);
19770
19771 return ie->offset;
19772 }
19773
wl_link_up(struct bcm_cfg80211 * cfg)19774 static void wl_link_up(struct bcm_cfg80211 *cfg)
19775 {
19776 cfg->link_up = true;
19777 }
19778
wl_link_down(struct bcm_cfg80211 * cfg)19779 static void wl_link_down(struct bcm_cfg80211 *cfg)
19780 {
19781 struct wl_connect_info *conn_info = wl_to_conn(cfg);
19782
19783 WL_DBG(("In\n"));
19784 cfg->link_up = false;
19785 if (conn_info) {
19786 conn_info->req_ie_len = 0;
19787 conn_info->resp_ie_len = 0;
19788 }
19789 }
19790
wl_lock_eq(struct bcm_cfg80211 * cfg)19791 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
19792 {
19793 unsigned long flags;
19794
19795 WL_CFG_EQ_LOCK(&cfg->eq_lock, flags);
19796 return flags;
19797 }
19798
wl_unlock_eq(struct bcm_cfg80211 * cfg,unsigned long flags)19799 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
19800 {
19801 WL_CFG_EQ_UNLOCK(&cfg->eq_lock, flags);
19802 }
19803
wl_init_eq_lock(struct bcm_cfg80211 * cfg)19804 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
19805 {
19806 spin_lock_init(&cfg->eq_lock);
19807 }
19808
wl_delay(u32 ms)19809 static void wl_delay(u32 ms)
19810 {
19811 if (in_atomic() || (ms < jiffies_to_msecs(1))) {
19812 OSL_DELAY(ms*1000);
19813 } else {
19814 OSL_SLEEP(ms);
19815 }
19816 }
19817
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)19818 s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
19819 {
19820 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19821 struct ether_addr primary_mac;
19822 if (!cfg->p2p)
19823 return -1;
19824 if (!p2p_is_on(cfg)) {
19825 get_primary_mac(cfg, &primary_mac);
19826 #ifndef WL_P2P_USE_RANDMAC
19827 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
19828 #endif /* WL_P2P_USE_RANDMAC */
19829 memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN);
19830 } else {
19831 memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
19832 ETHER_ADDR_LEN);
19833 }
19834
19835 return 0;
19836 }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)19837 s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
19838 {
19839 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19840
19841 return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
19842 }
19843
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)19844 s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
19845 {
19846 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19847
19848 return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
19849 }
19850
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)19851 s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
19852 {
19853 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19854
19855 return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
19856 }
19857
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)19858 s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
19859 {
19860 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19861
19862 return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
19863 }
19864
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)19865 s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
19866 {
19867 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19868
19869 return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
19870 }
19871
19872 #ifdef P2PLISTEN_AP_SAMECHN
wl_cfg80211_set_p2p_resp_ap_chn(struct net_device * net,s32 enable)19873 s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
19874 {
19875 s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
19876
19877 if ((ret == 0) && enable) {
19878 /* disable PM for p2p responding on infra AP channel */
19879 s32 pm = PM_OFF;
19880
19881 ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm));
19882 }
19883
19884 return ret;
19885 }
19886 #endif /* P2PLISTEN_AP_SAMECHN */
19887
wl_cfg80211_channel_to_freq(u32 channel)19888 s32 wl_cfg80211_channel_to_freq(u32 channel)
19889 {
19890 int freq = 0;
19891
19892 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
19893 freq = ieee80211_channel_to_frequency(channel);
19894 #else
19895 {
19896 u16 band = 0;
19897 if (channel <= CH_MAX_2G_CHANNEL)
19898 band = IEEE80211_BAND_2GHZ;
19899 else
19900 band = IEEE80211_BAND_5GHZ;
19901 freq = ieee80211_channel_to_frequency(channel, band);
19902 }
19903 #endif // endif
19904 return freq;
19905 }
19906
19907 #ifdef WLTDLS
19908 s32
wl_tdls_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)19909 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
19910 const wl_event_msg_t *e, void *data) {
19911
19912 struct net_device *ndev = NULL;
19913 u32 reason = ntoh32(e->reason);
19914 s8 *msg = NULL;
19915
19916 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
19917
19918 switch (reason) {
19919 case WLC_E_TDLS_PEER_DISCOVERED :
19920 msg = " TDLS PEER DISCOVERD ";
19921 break;
19922 case WLC_E_TDLS_PEER_CONNECTED :
19923 if (cfg->tdls_mgmt_frame) {
19924 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
19925 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
19926 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0);
19927 #ifdef CONFIG_AP6XXX_WIFI6_HDF
19928 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), cfg->tdls_mgmt_freq, 0,
19929 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
19930 #endif
19931 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
19932 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
19933 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0,
19934 GFP_ATOMIC);
19935 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
19936 defined(WL_COMPAT_WIRELESS)
19937 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
19938 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
19939 GFP_ATOMIC);
19940 #else
19941 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
19942 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, GFP_ATOMIC);
19943
19944 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
19945 }
19946 msg = " TDLS PEER CONNECTED ";
19947 #ifdef SUPPORT_SET_CAC
19948 /* TDLS connect reset CAC */
19949 wl_cfg80211_set_cac(cfg, 0);
19950 #endif /* SUPPORT_SET_CAC */
19951 break;
19952 case WLC_E_TDLS_PEER_DISCONNECTED :
19953 if (cfg->tdls_mgmt_frame) {
19954 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
19955 cfg->tdls_mgmt_frame_len = 0;
19956 cfg->tdls_mgmt_freq = 0;
19957 }
19958 msg = "TDLS PEER DISCONNECTED ";
19959 #ifdef SUPPORT_SET_CAC
19960 /* TDLS disconnec, set CAC */
19961 wl_cfg80211_set_cac(cfg, 1);
19962 #endif /* SUPPORT_SET_CAC */
19963 break;
19964 }
19965 if (msg) {
19966 WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((const u8*)(&e->addr)),
19967 (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
19968 }
19969 return 0;
19970
19971 }
19972 #endif /* WLTDLS */
19973
19974 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
19975 static s32
19976 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
19977 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
wl_cfg80211_tdls_mgmt(struct wiphy * wiphy,struct net_device * dev,u8 * peer,u8 action_code,u8 dialog_token,u16 status_code,u32 peer_capability,const u8 * buf,size_t len)19978 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
19979 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
19980 u32 peer_capability, const u8 *buf, size_t len)
19981 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
19982 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
19983 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
19984 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
19985 u32 peer_capability, const u8 *buf, size_t len)
19986 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
19987 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
19988 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
19989 u32 peer_capability, bool initiator, const u8 *buf, size_t len)
19990 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
19991 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
19992 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
19993 const u8 *buf, size_t len)
19994 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
19995 {
19996 s32 ret = 0;
19997 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
19998 struct bcm_cfg80211 *cfg;
19999 tdls_wfd_ie_iovar_t info;
20000 bzero(&info, sizeof(info));
20001 cfg = wl_get_cfg(dev);
20002
20003 #if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
20004 /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
20005 * and that cuases build error
20006 */
20007 BCM_REFERENCE(peer_capability);
20008 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20009
20010 switch (action_code) {
20011 /* We need to set TDLS Wifi Display IE to firmware
20012 * using tdls_wfd_ie iovar
20013 */
20014 case WLAN_TDLS_SET_PROBE_WFD_IE:
20015 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_PROBE_WFD_IE\n"));
20016 info.mode = TDLS_WFD_PROBE_IE_TX;
20017
20018 if (len > sizeof(info.data)) {
20019 return -EINVAL;
20020 }
20021 memcpy(&info.data, buf, len);
20022 info.length = len;
20023 break;
20024 case WLAN_TDLS_SET_SETUP_WFD_IE:
20025 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_SETUP_WFD_IE\n"));
20026 info.mode = TDLS_WFD_IE_TX;
20027
20028 if (len > sizeof(info.data)) {
20029 return -EINVAL;
20030 }
20031 memcpy(&info.data, buf, len);
20032 info.length = len;
20033 break;
20034 case WLAN_TDLS_SET_WFD_ENABLED:
20035 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_ENABLED\n"));
20036 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
20037 goto out;
20038 case WLAN_TDLS_SET_WFD_DISABLED:
20039 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_DISABLED\n"));
20040 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
20041 goto out;
20042 default:
20043 WL_ERR(("Unsupported action code : %d\n", action_code));
20044 goto out;
20045 }
20046 ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
20047 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
20048
20049 if (ret) {
20050 WL_ERR(("tdls_wfd_ie error %d\n", ret));
20051 }
20052
20053 out:
20054 #endif /* TDLS_MSG_ONLY_WFD && WLTDLS */
20055 return ret;
20056 }
20057
20058 static s32
20059 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
wl_cfg80211_tdls_oper(struct wiphy * wiphy,struct net_device * dev,const u8 * peer,enum nl80211_tdls_operation oper)20060 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
20061 const u8 *peer, enum nl80211_tdls_operation oper)
20062 #else
20063 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
20064 u8 *peer, enum nl80211_tdls_operation oper)
20065 #endif // endif
20066 {
20067 s32 ret = 0;
20068 #ifdef WLTDLS
20069 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20070 tdls_iovar_t info;
20071 dhd_pub_t *dhdp;
20072 bool tdls_auto_mode = false;
20073 dhdp = (dhd_pub_t *)(cfg->pub);
20074 bzero(&info, sizeof(tdls_iovar_t));
20075 if (peer) {
20076 memcpy(&info.ea, peer, ETHER_ADDR_LEN);
20077 } else {
20078 return -1;
20079 }
20080 switch (oper) {
20081 case NL80211_TDLS_DISCOVERY_REQ:
20082 /* If the discovery request is broadcast then we need to set
20083 * info.mode to Tunneled Probe Request
20084 */
20085 if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
20086 info.mode = TDLS_MANUAL_EP_WFD_TPQ;
20087 WL_ERR(("wl_cfg80211_tdls_oper: TDLS TUNNELED PRBOBE REQUEST\n"));
20088 } else {
20089 info.mode = TDLS_MANUAL_EP_DISCOVERY;
20090 }
20091 break;
20092 case NL80211_TDLS_SETUP:
20093 if (dhdp->tdls_mode == true) {
20094 info.mode = TDLS_MANUAL_EP_CREATE;
20095 tdls_auto_mode = false;
20096 /* Do tear down and create a fresh one */
20097 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_TEARDOWN, tdls_auto_mode);
20098 if (ret < 0) {
20099 return ret;
20100 }
20101 } else {
20102 tdls_auto_mode = true;
20103 }
20104 break;
20105 case NL80211_TDLS_TEARDOWN:
20106 info.mode = TDLS_MANUAL_EP_DELETE;
20107 break;
20108 default:
20109 WL_ERR(("Unsupported operation : %d\n", oper));
20110 goto out;
20111 }
20112 /* turn on TDLS */
20113 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_SETUP, tdls_auto_mode);
20114 if (ret < 0) {
20115 return ret;
20116 }
20117 if (info.mode) {
20118 ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
20119 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
20120 if (ret) {
20121 WL_ERR(("tdls_endpoint error %d\n", ret));
20122 }
20123 }
20124 out:
20125 if (ret) {
20126 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
20127 return -ENOTSUPP;
20128 }
20129 #endif /* WLTDLS */
20130 return ret;
20131 }
20132 #endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
20133
wl_cfg80211_set_wps_p2p_ie(struct net_device * ndev,char * buf,int len,enum wl_management_type type)20134 s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
20135 enum wl_management_type type)
20136 {
20137 struct bcm_cfg80211 *cfg;
20138 s32 ret = 0;
20139 struct ether_addr primary_mac;
20140 s32 bssidx = 0;
20141 s32 pktflag = 0;
20142 cfg = wl_get_cfg(ndev);
20143
20144 if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
20145 /* Vendor IEs should be set to FW
20146 * after SoftAP interface is brought up
20147 */
20148 WL_DBG(("Skipping set IE since AP is not up \n"));
20149 goto exit;
20150 } else if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
20151 /* Either stand alone AP case or P2P discovery */
20152 if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
20153 /* Stand alone AP case on primary interface */
20154 WL_DBG(("Apply IEs for Primary AP Interface \n"));
20155 bssidx = 0;
20156 } else {
20157 if (!cfg->p2p) {
20158 /* If p2p not initialized, return failure */
20159 WL_ERR(("P2P not initialized \n"));
20160 goto exit;
20161 }
20162 /* P2P Discovery case (p2p listen) */
20163 if (!cfg->p2p->on) {
20164 /* Turn on Discovery interface */
20165 get_primary_mac(cfg, &primary_mac);
20166 #ifndef WL_P2P_USE_RANDMAC
20167 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
20168 #endif /* WL_P2P_USE_RANDMAC */
20169 p2p_on(cfg) = true;
20170 ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
20171 if (unlikely(ret)) {
20172 WL_ERR(("Enable discovery failed \n"));
20173 goto exit;
20174 }
20175 }
20176 WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
20177 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
20178 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
20179 }
20180 } else {
20181 /* Virtual AP/ P2P Group Interface */
20182 WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
20183 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
20184 }
20185
20186 if (ndev != NULL) {
20187 switch (type) {
20188 case WL_BEACON:
20189 pktflag = VNDR_IE_BEACON_FLAG;
20190 break;
20191 case WL_PROBE_RESP:
20192 pktflag = VNDR_IE_PRBRSP_FLAG;
20193 break;
20194 case WL_ASSOC_RESP:
20195 pktflag = VNDR_IE_ASSOCRSP_FLAG;
20196 break;
20197 }
20198 if (pktflag) {
20199 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
20200 ndev_to_cfgdev(ndev), bssidx, pktflag, buf, len);
20201 }
20202 }
20203 exit:
20204 return ret;
20205 }
20206
20207 #ifdef WL_SUPPORT_AUTO_CHANNEL
20208 static s32
wl_cfg80211_set_auto_channel_scan_state(struct net_device * ndev)20209 wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev)
20210 {
20211 u32 val = 0;
20212 s32 ret = BCME_ERROR;
20213 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20214 /* Set interface up, explicitly. */
20215 val = 1;
20216
20217 ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
20218 if (ret < 0) {
20219 WL_ERR(("set interface up failed, error = %d\n", ret));
20220 goto done;
20221 }
20222
20223 /* Stop all scan explicitly, till auto channel selection complete. */
20224 wl_set_drv_status(cfg, SCANNING, ndev);
20225 if (cfg->escan_info.ndev == NULL) {
20226 ret = BCME_OK;
20227 goto done;
20228 }
20229
20230 wl_cfg80211_cancel_scan(cfg);
20231
20232 done:
20233 return ret;
20234 }
20235
20236 static bool
wl_cfg80211_valid_channel_p2p(int channel)20237 wl_cfg80211_valid_channel_p2p(int channel)
20238 {
20239 bool valid = false;
20240
20241 /* channel 1 to 14 */
20242 if ((channel >= 1) && (channel <= 14)) {
20243 valid = true;
20244 }
20245 /* channel 36 to 48 */
20246 else if ((channel >= 36) && (channel <= 48)) {
20247 valid = true;
20248 }
20249 /* channel 149 to 161 */
20250 else if ((channel >= 149) && (channel <= 161)) {
20251 valid = true;
20252 }
20253 else {
20254 valid = false;
20255 WL_INFORM(("invalid P2P chanspec, channel = %d\n", channel));
20256 }
20257
20258 return valid;
20259 }
20260
20261 s32
wl_cfg80211_get_chanspecs_2g(struct net_device * ndev,void * buf,s32 buflen)20262 wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
20263 {
20264 s32 ret = BCME_ERROR;
20265 struct bcm_cfg80211 *cfg = NULL;
20266 chanspec_t chanspec = 0;
20267
20268 cfg = wl_get_cfg(ndev);
20269
20270 /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
20271 chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 |
20272 WL_CHANSPEC_CTL_SB_NONE);
20273 chanspec = wl_chspec_host_to_driver(chanspec);
20274
20275 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
20276 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
20277 if (ret < 0) {
20278 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
20279 }
20280
20281 return ret;
20282 }
20283
20284 s32
wl_cfg80211_get_chanspecs_5g(struct net_device * ndev,void * buf,s32 buflen)20285 wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
20286 {
20287 u32 channel = 0;
20288 s32 ret = BCME_ERROR;
20289 s32 i = 0;
20290 s32 j = 0;
20291 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20292 wl_uint32_list_t *list = NULL;
20293 chanspec_t chanspec = 0;
20294
20295 /* Restrict channels to 5GHz, 20MHz BW, no SB. */
20296 chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 |
20297 WL_CHANSPEC_CTL_SB_NONE);
20298 chanspec = wl_chspec_host_to_driver(chanspec);
20299
20300 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
20301 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
20302 if (ret < 0) {
20303 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
20304 goto done;
20305 }
20306
20307 list = (wl_uint32_list_t *)buf;
20308 /* Skip DFS and inavlid P2P channel. */
20309 for (i = 0, j = 0; i < dtoh32(list->count); i++) {
20310 chanspec = (chanspec_t) dtoh32(list->element[i]);
20311 channel = CHSPEC_CHANNEL(chanspec);
20312
20313 ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
20314 if (ret < 0) {
20315 WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret));
20316 goto done;
20317 }
20318
20319 if (CHANNEL_IS_RADAR(channel) ||
20320 !(wl_cfg80211_valid_channel_p2p(CHSPEC_CHANNEL(chanspec)))) {
20321 continue;
20322 } else {
20323 list->element[j] = list->element[i];
20324 }
20325
20326 j++;
20327 }
20328
20329 list->count = j;
20330
20331 done:
20332 return ret;
20333 }
20334
20335 static s32
wl_cfg80211_get_best_channel(struct net_device * ndev,void * buf,int buflen,int * channel)20336 wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen,
20337 int *channel)
20338 {
20339 s32 ret = BCME_ERROR;
20340 int chosen = 0;
20341 int retry = 0;
20342 uint chip;
20343
20344 /* Start auto channel selection scan. */
20345 ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, buf, buflen);
20346 if (ret < 0) {
20347 WL_ERR(("can't start auto channel scan, error = %d\n", ret));
20348 *channel = 0;
20349 goto done;
20350 }
20351
20352 /* Wait for auto channel selection, worst case possible delay is 5250ms. */
20353 retry = CHAN_SEL_RETRY_COUNT;
20354
20355 while (retry--) {
20356 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
20357 chosen = 0;
20358 ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
20359 if ((ret == 0) && (dtoh32(chosen) != 0)) {
20360 chip = dhd_conf_get_chip(dhd_get_pub(ndev));
20361 if (chip != BCM43362_CHIP_ID && chip != BCM4330_CHIP_ID &&
20362 chip != BCM43143_CHIP_ID) {
20363 u32 chanspec = 0;
20364 int ctl_chan;
20365 chanspec = wl_chspec_driver_to_host(chosen);
20366 WL_INFORM(("selected chanspec = 0x%x\n", chanspec));
20367 ctl_chan = wf_chspec_ctlchan(chanspec);
20368 WL_INFORM(("selected ctl_chan = %d\n", ctl_chan));
20369 *channel = (u16)(ctl_chan & 0x00FF);
20370 } else
20371 *channel = (u16)(chosen & 0x00FF);
20372 WL_INFORM(("selected channel = %d\n", *channel));
20373 break;
20374 }
20375 WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n",
20376 (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
20377 }
20378
20379 if (retry <= 0) {
20380 WL_ERR(("failure, auto channel selection timed out\n"));
20381 *channel = 0;
20382 ret = BCME_ERROR;
20383 }
20384 WL_INFORM(("selected channel = %d\n", *channel));
20385
20386 done:
20387 return ret;
20388 }
20389
20390 static s32
wl_cfg80211_restore_auto_channel_scan_state(struct net_device * ndev)20391 wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev)
20392 {
20393 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20394 /* Clear scan stop driver status. */
20395 wl_clr_drv_status(cfg, SCANNING, ndev);
20396
20397 return BCME_OK;
20398 }
20399
20400 s32
wl_cfg80211_get_best_channels(struct net_device * dev,char * cmd,int total_len)20401 wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len)
20402 {
20403 int channel = 0, band, band_cur;
20404 s32 ret = BCME_ERROR;
20405 u8 *buf = NULL;
20406 char *pos = cmd;
20407 struct bcm_cfg80211 *cfg = NULL;
20408 struct net_device *ndev = NULL;
20409
20410 bzero(cmd, total_len);
20411 cfg = wl_get_cfg(dev);
20412
20413 buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
20414 if (buf == NULL) {
20415 WL_ERR(("failed to allocate chanspec buffer\n"));
20416 return -ENOMEM;
20417 }
20418
20419 /*
20420 * Always use primary interface, irrespective of interface on which
20421 * command came.
20422 */
20423 ndev = bcmcfg_to_prmry_ndev(cfg);
20424
20425 /*
20426 * Make sure that FW and driver are in right state to do auto channel
20427 * selection scan.
20428 */
20429 ret = wl_cfg80211_set_auto_channel_scan_state(ndev);
20430 if (ret < 0) {
20431 WL_ERR(("can't set auto channel scan state, error = %d\n", ret));
20432 goto done;
20433 }
20434
20435 ret = wldev_ioctl(dev, WLC_GET_BAND, &band_cur, sizeof(band_cur), false);
20436 if (band_cur != WLC_BAND_5G) {
20437 /* Best channel selection in 2.4GHz band. */
20438 ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
20439 if (ret < 0) {
20440 WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
20441 goto done;
20442 }
20443
20444 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
20445 &channel);
20446 if (ret < 0) {
20447 WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
20448 goto done;
20449 }
20450
20451 if (CHANNEL_IS_2G(channel)) {
20452 // channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
20453 } else {
20454 WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel));
20455 channel = 0;
20456 }
20457 pos += snprintf(pos, total_len, "2g=%d ", channel);
20458 }
20459
20460 if (band_cur != WLC_BAND_2G) {
20461 // terence 20140120: fix for some chipsets only return 2.4GHz channel (4330b2/43341b0/4339a0)
20462 band = band_cur==WLC_BAND_2G ? band_cur : WLC_BAND_5G;
20463 ret = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true);
20464 if (ret < 0) {
20465 WL_ERR(("WLC_SET_BAND error %d\n", ret));
20466 goto done;
20467 }
20468
20469 /* Best channel selection in 5GHz band. */
20470 ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
20471 if (ret < 0) {
20472 WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret));
20473 goto done;
20474 }
20475
20476 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
20477 &channel);
20478 if (ret < 0) {
20479 WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret));
20480 goto done;
20481 }
20482
20483 if (CHANNEL_IS_5G(channel)) {
20484 // channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
20485 } else {
20486 WL_ERR(("invalid 5GHz channel, channel = %d\n", channel));
20487 channel = 0;
20488 }
20489
20490 ret = wldev_ioctl(dev, WLC_SET_BAND, &band_cur, sizeof(band_cur), true);
20491 if (ret < 0)
20492 WL_ERR(("WLC_SET_BAND error %d\n", ret));
20493 pos += snprintf(pos, total_len, "5g=%d ", channel);
20494 }
20495
20496 done:
20497 if (NULL != buf) {
20498 MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
20499 }
20500
20501 /* Restore FW and driver back to normal state. */
20502 ret = wl_cfg80211_restore_auto_channel_scan_state(ndev);
20503 if (ret < 0) {
20504 WL_ERR(("can't restore auto channel scan state, error = %d\n", ret));
20505 }
20506
20507 WL_MSG(ndev->name, "%s\n", cmd);
20508
20509 return (pos - cmd);
20510 }
20511 #endif /* WL_SUPPORT_AUTO_CHANNEL */
20512
20513 static const struct rfkill_ops wl_rfkill_ops = {
20514 .set_block = wl_rfkill_set
20515 };
20516
wl_rfkill_set(void * data,bool blocked)20517 static int wl_rfkill_set(void *data, bool blocked)
20518 {
20519 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
20520
20521 WL_DBG(("Enter \n"));
20522 WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
20523
20524 if (!cfg)
20525 return -EINVAL;
20526
20527 cfg->rf_blocked = blocked;
20528
20529 return 0;
20530 }
20531
wl_setup_rfkill(struct bcm_cfg80211 * cfg,bool setup)20532 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
20533 {
20534 s32 err = 0;
20535
20536 WL_DBG(("Enter \n"));
20537 if (!cfg)
20538 return -EINVAL;
20539 if (setup) {
20540 cfg->rfkill = rfkill_alloc("brcmfmac-wifi",
20541 wl_cfg80211_get_parent_dev(),
20542 RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
20543
20544 if (!cfg->rfkill) {
20545 err = -ENOMEM;
20546 goto err_out;
20547 }
20548
20549 err = rfkill_register(cfg->rfkill);
20550
20551 if (err)
20552 rfkill_destroy(cfg->rfkill);
20553 } else {
20554 if (!cfg->rfkill) {
20555 err = -ENOMEM;
20556 goto err_out;
20557 }
20558
20559 rfkill_unregister(cfg->rfkill);
20560 rfkill_destroy(cfg->rfkill);
20561 }
20562
20563 err_out:
20564 return err;
20565 }
20566
20567 #ifdef DEBUGFS_CFG80211
20568 /**
20569 * Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
20570 * to turn on SCAN and DBG log.
20571 * To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
20572 * To see current setting of debug level,
20573 * cat /sys/kernel/debug/dhd/debug_level
20574 */
20575 static ssize_t
wl_debuglevel_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)20576 wl_debuglevel_write(struct file *file, const char __user *userbuf,
20577 size_t count, loff_t *ppos)
20578 {
20579 char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)], sublog[SUBLOGLEVELZ];
20580 char *params, *token, *colon;
20581 uint i, tokens, log_on = 0;
20582 size_t minsize = min_t(size_t, (sizeof(tbuf) - 1), count);
20583
20584 bzero(tbuf, sizeof(tbuf));
20585 bzero(sublog, sizeof(sublog));
20586 if (copy_from_user(&tbuf, userbuf, minsize)) {
20587 return -EFAULT;
20588 }
20589
20590 tbuf[minsize] = '\0';
20591 params = &tbuf[0];
20592 colon = strchr(params, '\n');
20593 if (colon != NULL)
20594 *colon = '\0';
20595 while ((token = strsep(¶ms, " ")) != NULL) {
20596 bzero(sublog, sizeof(sublog));
20597 if (token == NULL || !*token)
20598 break;
20599 if (*token == '\0')
20600 continue;
20601 colon = strchr(token, ':');
20602 if (colon != NULL) {
20603 *colon = ' ';
20604 }
20605 tokens = sscanf(token, "%"S(SUBLOGLEVEL)"s %u", sublog, &log_on);
20606 if (colon != NULL)
20607 *colon = ':';
20608
20609 if (tokens == 2) {
20610 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
20611 if (!strncmp(sublog, sublogname_map[i].sublogname,
20612 strlen(sublogname_map[i].sublogname))) {
20613 if (log_on)
20614 wl_dbg_level |=
20615 (sublogname_map[i].log_level);
20616 else
20617 wl_dbg_level &=
20618 ~(sublogname_map[i].log_level);
20619 }
20620 }
20621 } else
20622 WL_ERR(("%s: can't parse '%s' as a "
20623 "SUBMODULE:LEVEL (%d tokens)\n",
20624 tbuf, token, tokens));
20625
20626 }
20627 return count;
20628 }
20629
20630 static ssize_t
wl_debuglevel_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)20631 wl_debuglevel_read(struct file *file, char __user *user_buf,
20632 size_t count, loff_t *ppos)
20633 {
20634 char *param;
20635 char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)];
20636 uint i;
20637 bzero(tbuf, sizeof(tbuf));
20638 param = &tbuf[0];
20639 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
20640 param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
20641 sublogname_map[i].sublogname,
20642 (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0);
20643 }
20644 *param = '\n';
20645 return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0]));
20646
20647 }
20648 static const struct file_operations fops_debuglevel = {
20649 .open = NULL,
20650 .write = wl_debuglevel_write,
20651 .read = wl_debuglevel_read,
20652 .owner = THIS_MODULE,
20653 .llseek = NULL,
20654 };
20655
wl_setup_debugfs(struct bcm_cfg80211 * cfg)20656 static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg)
20657 {
20658 s32 err = 0;
20659 struct dentry *_dentry;
20660 if (!cfg)
20661 return -EINVAL;
20662 cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
20663 if (!cfg->debugfs || IS_ERR(cfg->debugfs)) {
20664 if (cfg->debugfs == ERR_PTR(-ENODEV))
20665 WL_ERR(("Debugfs is not enabled on this kernel\n"));
20666 else
20667 WL_ERR(("Can not create debugfs directory\n"));
20668 cfg->debugfs = NULL;
20669 goto exit;
20670
20671 }
20672 _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR,
20673 cfg->debugfs, cfg, &fops_debuglevel);
20674 if (!_dentry || IS_ERR(_dentry)) {
20675 WL_ERR(("failed to create debug_level debug file\n"));
20676 wl_free_debugfs(cfg);
20677 }
20678 exit:
20679 return err;
20680 }
wl_free_debugfs(struct bcm_cfg80211 * cfg)20681 static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg)
20682 {
20683 if (!cfg)
20684 return -EINVAL;
20685 if (cfg->debugfs)
20686 debugfs_remove_recursive(cfg->debugfs);
20687 cfg->debugfs = NULL;
20688 return 0;
20689 }
20690 #endif /* DEBUGFS_CFG80211 */
20691
wl_cfg80211_get_bcmcfg(void)20692 struct bcm_cfg80211 *wl_cfg80211_get_bcmcfg(void)
20693 {
20694 return g_bcmcfg;
20695 }
20696
wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 * cfg)20697 void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 *cfg)
20698 {
20699 g_bcmcfg = cfg;
20700 }
20701
wl_cfg80211_get_parent_dev(void)20702 struct device *wl_cfg80211_get_parent_dev(void)
20703 {
20704 return cfg80211_parent_dev;
20705 }
20706
wl_cfg80211_set_parent_dev(void * dev)20707 void wl_cfg80211_set_parent_dev(void *dev)
20708 {
20709 cfg80211_parent_dev = dev;
20710 }
20711
wl_cfg80211_clear_parent_dev(void)20712 static void wl_cfg80211_clear_parent_dev(void)
20713 {
20714 cfg80211_parent_dev = NULL;
20715 }
20716
get_primary_mac(struct bcm_cfg80211 * cfg,struct ether_addr * mac)20717 void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
20718 {
20719 u8 ioctl_buf[WLC_IOCTL_SMLEN];
20720
20721 if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
20722 "cur_etheraddr", NULL, 0, ioctl_buf, sizeof(ioctl_buf),
20723 0, NULL) == BCME_OK) {
20724 memcpy(mac->octet, ioctl_buf, ETHER_ADDR_LEN);
20725 } else {
20726 bzero(mac->octet, ETHER_ADDR_LEN);
20727 }
20728 }
check_dev_role_integrity(struct bcm_cfg80211 * cfg,u32 dev_role)20729 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
20730 {
20731 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20732 if (((dev_role == NL80211_IFTYPE_AP) &&
20733 !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
20734 ((dev_role == NL80211_IFTYPE_P2P_GO) &&
20735 !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
20736 {
20737 WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
20738 return false;
20739 }
20740 return true;
20741 }
20742
wl_cfg80211_do_driver_init(struct net_device * net)20743 int wl_cfg80211_do_driver_init(struct net_device *net)
20744 {
20745 struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
20746
20747 if (!cfg || !cfg->wdev)
20748 return -EINVAL;
20749
20750 if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
20751 return -1;
20752
20753 return 0;
20754 }
20755
wl_cfg80211_enable_trace(u32 level)20756 void wl_cfg80211_enable_trace(u32 level)
20757 {
20758 wl_dbg_level = level;
20759 WL_MSG("wlan", "wl_dbg_level = 0x%x\n", wl_dbg_level);
20760 }
20761
20762 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
20763 2, 0))
20764 static s32
wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u64 cookie)20765 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
20766 bcm_struct_cfgdev *cfgdev, u64 cookie)
20767 {
20768 /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
20769 * is passed with CMD_FRAME. This callback is supposed to cancel
20770 * the OFFCHANNEL Wait. Since we are already taking care of that
20771 * with the tx_mgmt logic, do nothing here.
20772 */
20773
20774 return 0;
20775 }
20776 #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
20777
20778 #ifdef WL_HOST_BAND_MGMT
20779 s32
wl_cfg80211_set_band(struct net_device * ndev,int band)20780 wl_cfg80211_set_band(struct net_device *ndev, int band)
20781 {
20782 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20783 int ret = 0;
20784 char ioctl_buf[50];
20785
20786 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
20787 WL_ERR(("Invalid band\n"));
20788 return -EINVAL;
20789 }
20790
20791 if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band,
20792 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
20793 WL_ERR(("seting roam_band failed code=%d\n", ret));
20794 return ret;
20795 }
20796
20797 WL_DBG(("Setting band to %d\n", band));
20798 cfg->curr_band = band;
20799
20800 return 0;
20801 }
20802 #endif /* WL_HOST_BAND_MGMT */
20803
20804 s32
wl_cfg80211_set_if_band(struct net_device * ndev,int band)20805 wl_cfg80211_set_if_band(struct net_device *ndev, int band)
20806 {
20807 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20808 int ret = 0, wait_cnt;
20809 char ioctl_buf[32];
20810
20811 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
20812 WL_ERR(("Invalid band\n"));
20813 return -EINVAL;
20814 }
20815 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
20816 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
20817 BCM_REFERENCE(dhdp);
20818 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
20819 dhd_net2idx(dhdp->info, ndev), 0);
20820 ret = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
20821 if (ret < 0) {
20822 WL_ERR(("WLC_DISASSOC error %d\n", ret));
20823 /* continue to set 'if_band' */
20824 }
20825 else {
20826 /* This is to ensure that 'if_band' iovar is issued only after
20827 * disconnection is completed
20828 */
20829 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
20830 while (wl_get_drv_status(cfg, CONNECTED, ndev) && wait_cnt) {
20831 WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt));
20832 wait_cnt--;
20833 OSL_SLEEP(50);
20834 }
20835 }
20836 }
20837 if ((ret = wldev_iovar_setbuf(ndev, "if_band", &band,
20838 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
20839 WL_ERR(("seting if_band failed ret=%d\n", ret));
20840 /* issue 'WLC_SET_BAND' if if_band is not supported */
20841 if (ret == BCME_UNSUPPORTED) {
20842 ret = wldev_set_band(ndev, band);
20843 if (ret < 0) {
20844 WL_ERR(("seting band failed ret=%d\n", ret));
20845 }
20846 }
20847 }
20848 return ret;
20849 }
20850
20851 s32
wl_cfg80211_dfs_ap_move(struct net_device * ndev,char * data,char * command,int total_len)20852 wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int total_len)
20853 {
20854 char ioctl_buf[WLC_IOCTL_SMLEN];
20855 int err = 0;
20856 uint32 val = 0;
20857 chanspec_t chanspec = 0;
20858 int abort;
20859 int bytes_written = 0;
20860 struct wl_dfs_ap_move_status_v2 *status;
20861 char chanbuf[CHANSPEC_STR_LEN];
20862 const char *dfs_state_str[DFS_SCAN_S_MAX] = {
20863 "Radar Free On Channel",
20864 "Radar Found On Channel",
20865 "Radar Scan In Progress",
20866 "Radar Scan Aborted",
20867 "RSDB Mode switch in Progress For Scan"
20868 };
20869 if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
20870 bytes_written = snprintf(command, total_len, "AP is not up\n");
20871 return bytes_written;
20872 }
20873 if (!*data) {
20874 if ((err = wldev_iovar_getbuf(ndev, "dfs_ap_move", NULL, 0,
20875 ioctl_buf, sizeof(ioctl_buf), NULL))) {
20876 WL_ERR(("setting dfs_ap_move failed with err=%d \n", err));
20877 return err;
20878 }
20879 status = (struct wl_dfs_ap_move_status_v2 *)ioctl_buf;
20880
20881 if (status->version != WL_DFS_AP_MOVE_VERSION) {
20882 err = BCME_UNSUPPORTED;
20883 WL_ERR(("err=%d version=%d\n", err, status->version));
20884 return err;
20885 }
20886
20887 if (status->move_status != (int8) DFS_SCAN_S_IDLE) {
20888 chanspec = wl_chspec_driver_to_host(status->chanspec);
20889 if (chanspec != 0 && chanspec != INVCHANSPEC) {
20890 wf_chspec_ntoa(chanspec, chanbuf);
20891 bytes_written = snprintf(command, total_len,
20892 "AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
20893 }
20894 bytes_written += snprintf(command + bytes_written,
20895 total_len - bytes_written,
20896 "%s\n", dfs_state_str[status->move_status]);
20897 return bytes_written;
20898 } else {
20899 bytes_written = snprintf(command, total_len, "dfs AP move in IDLE state\n");
20900 return bytes_written;
20901 }
20902 }
20903
20904 abort = bcm_atoi(data);
20905 if (abort == -1) {
20906 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &abort,
20907 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
20908 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
20909 return err;
20910 }
20911 } else {
20912 chanspec = wf_chspec_aton(data);
20913 if (chanspec != 0) {
20914 val = wl_chspec_host_to_driver(chanspec);
20915 if (val != INVCHANSPEC) {
20916 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &val,
20917 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
20918 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
20919 return err;
20920 }
20921 WL_DBG((" set dfs_ap_move successfull"));
20922 } else {
20923 err = BCME_USAGE_ERROR;
20924 }
20925 }
20926 }
20927 return err;
20928 }
20929
wl_cfg80211_is_concurrent_mode(struct net_device * dev)20930 bool wl_cfg80211_is_concurrent_mode(struct net_device *dev)
20931 {
20932 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20933 if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
20934 return true;
20935 } else {
20936 return false;
20937 }
20938 }
20939
wl_cfg80211_get_dhdp(struct net_device * dev)20940 void* wl_cfg80211_get_dhdp(struct net_device *dev)
20941 {
20942 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20943
20944 return cfg->pub;
20945 }
20946
wl_cfg80211_is_p2p_active(struct net_device * dev)20947 bool wl_cfg80211_is_p2p_active(struct net_device *dev)
20948 {
20949 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20950 return (cfg && cfg->p2p);
20951 }
20952
wl_cfg80211_is_roam_offload(struct net_device * dev)20953 bool wl_cfg80211_is_roam_offload(struct net_device * dev)
20954 {
20955 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20956 return (cfg && cfg->roam_offload);
20957 }
20958
wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev,const wl_event_msg_t * e,int ifidx)20959 bool wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev, const wl_event_msg_t *e,
20960 int ifidx)
20961 {
20962 u8 *curbssid = NULL;
20963 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20964
20965 if (!cfg) {
20966 /* When interface is created using wl
20967 * ndev->ieee80211_ptr will be NULL.
20968 */
20969 return NULL;
20970 }
20971 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
20972
20973 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
20974 return true;
20975 }
20976 return false;
20977 }
20978
wl_cfg80211_work_handler(struct work_struct * work)20979 static void wl_cfg80211_work_handler(struct work_struct * work)
20980 {
20981 struct bcm_cfg80211 *cfg = NULL;
20982 struct net_info *iter, *next;
20983 s32 err = BCME_OK;
20984 s32 pm = PM_FAST;
20985 dhd_pub_t *dhd;
20986 BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
20987 WL_DBG(("Enter \n"));
20988 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
20989 for_each_ndev(cfg, iter, next) {
20990 GCC_DIAGNOSTIC_POP();
20991 /* p2p discovery iface ndev could be null */
20992 if (iter->ndev) {
20993 if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
20994 (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
20995 wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
20996 continue;
20997 if (iter->ndev) {
20998 dhd = (dhd_pub_t *)(cfg->pub);
20999 if (dhd_conf_get_pm(dhd) >= 0)
21000 pm = dhd_conf_get_pm(dhd);
21001 if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM,
21002 &pm, sizeof(pm))) != 0) {
21003 if (err == -ENODEV)
21004 WL_DBG(("%s:netdev not ready\n",
21005 iter->ndev->name));
21006 else
21007 WL_ERR(("%s:error (%d)\n",
21008 iter->ndev->name, err));
21009 } else
21010 wl_cfg80211_update_power_mode(iter->ndev);
21011 }
21012 }
21013 }
21014 DHD_PM_WAKE_UNLOCK(cfg->pub);
21015 }
21016
21017 u8
wl_get_action_category(void * frame,u32 frame_len)21018 wl_get_action_category(void *frame, u32 frame_len)
21019 {
21020 u8 category;
21021 u8 *ptr = (u8 *)frame;
21022 if (frame == NULL)
21023 return DOT11_ACTION_CAT_ERR_MASK;
21024 if (frame_len < DOT11_ACTION_HDR_LEN)
21025 return DOT11_ACTION_CAT_ERR_MASK;
21026 category = ptr[DOT11_ACTION_CAT_OFF];
21027 WL_DBG(("Action Category: %d\n", category));
21028 return category;
21029 }
21030
21031 int
wl_get_public_action(void * frame,u32 frame_len,u8 * ret_action)21032 wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
21033 {
21034 u8 *ptr = (u8 *)frame;
21035 if (frame == NULL || ret_action == NULL)
21036 return BCME_ERROR;
21037 if (frame_len < DOT11_ACTION_HDR_LEN)
21038 return BCME_ERROR;
21039 if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
21040 return BCME_ERROR;
21041 *ret_action = ptr[DOT11_ACTION_ACT_OFF];
21042 WL_DBG(("Public Action : %d\n", *ret_action));
21043 return BCME_OK;
21044 }
21045
21046 #ifdef WLFBT
21047 int
wl_cfg80211_get_fbt_key(struct net_device * dev,uint8 * key,int total_len)21048 wl_cfg80211_get_fbt_key(struct net_device *dev, uint8 *key, int total_len)
21049 {
21050 struct bcm_cfg80211 * cfg = wl_get_cfg(dev);
21051 int bytes_written = -1;
21052
21053 if (total_len < FBT_KEYLEN) {
21054 WL_ERR(("wl_cfg80211_get_fbt_key: Insufficient buffer \n"));
21055 goto end;
21056 }
21057 if (cfg) {
21058 memcpy(key, cfg->fbt_key, FBT_KEYLEN);
21059 bytes_written = FBT_KEYLEN;
21060 } else {
21061 bzero(key, FBT_KEYLEN);
21062 WL_ERR(("wl_cfg80211_get_fbt_key: Failed to copy KCK and KEK \n"));
21063 }
21064 prhex("KCK, KEK", (uchar *)key, FBT_KEYLEN);
21065 end:
21066 return bytes_written;
21067 }
21068 #endif /* WLFBT */
21069
21070 static int
wl_cfg80211_delayed_roam(struct bcm_cfg80211 * cfg,struct net_device * ndev,const struct ether_addr * bssid)21071 wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
21072 const struct ether_addr *bssid)
21073 {
21074 s32 err;
21075 wl_event_msg_t e;
21076
21077 bzero(&e, sizeof(e));
21078 e.event_type = cpu_to_be32(WLC_E_ROAM);
21079 memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
21080 /* trigger the roam event handler */
21081 err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
21082
21083 return err;
21084 }
21085
21086 static s32
wl_cfg80211_parse_vndr_ies(const u8 * parse,u32 len,struct parsed_vndr_ies * vndr_ies)21087 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
21088 struct parsed_vndr_ies *vndr_ies)
21089 {
21090 s32 err = BCME_OK;
21091 const vndr_ie_t *vndrie;
21092 const bcm_tlv_t *ie;
21093 struct parsed_vndr_ie_info *parsed_info;
21094 u32 count = 0;
21095 u32 remained_len;
21096
21097 remained_len = len;
21098 bzero(vndr_ies, sizeof(*vndr_ies));
21099
21100 WL_DBG(("---> len %d\n", len));
21101 ie = (const bcm_tlv_t *) parse;
21102 if (!bcm_valid_tlv(ie, remained_len))
21103 ie = NULL;
21104 while (ie) {
21105 if (count >= MAX_VNDR_IE_NUMBER)
21106 break;
21107 if (ie->id == DOT11_MNG_VS_ID || (ie->id == DOT11_MNG_ID_EXT_ID)) {
21108 vndrie = (const vndr_ie_t *) ie;
21109 if (ie->id == DOT11_MNG_ID_EXT_ID) {
21110 /* len should be bigger than sizeof ID extn field at least */
21111 if (vndrie->len < MIN_VENDOR_EXTN_IE_LEN) {
21112 WL_ERR(("%s: invalid vndr extn ie."
21113 " length %d\n",
21114 __FUNCTION__, vndrie->len));
21115 goto end;
21116 }
21117 } else {
21118 /* len should be bigger than OUI length +
21119 * one data length at least
21120 */
21121 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
21122 WL_ERR(("wl_cfg80211_parse_vndr_ies:"
21123 " invalid vndr ie. length is too small %d\n",
21124 vndrie->len));
21125 goto end;
21126 }
21127
21128 /* if wpa or wme ie, do not add ie */
21129 if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
21130 ((vndrie->data[0] == WPA_OUI_TYPE) ||
21131 (vndrie->data[0] == WME_OUI_TYPE))) {
21132 CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
21133 goto end;
21134 }
21135 }
21136
21137 parsed_info = &vndr_ies->ie_info[count++];
21138
21139 /* save vndr ie information */
21140 parsed_info->ie_ptr = (const char *)vndrie;
21141 parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
21142 memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
21143 vndr_ies->count = count;
21144 if (ie->id == DOT11_MNG_ID_EXT_ID) {
21145 WL_DBG(("\t ** Vendor Extension ie id: 0x%02x, len:%d\n",
21146 ie->id, parsed_info->ie_len));
21147 } else {
21148 WL_DBG(("\t ** OUI "MACOUIDBG", type 0x%02x len:%d\n",
21149 MACOUI2STRDBG(parsed_info->vndrie.oui),
21150 parsed_info->vndrie.data[0], parsed_info->ie_len));
21151 }
21152 }
21153 end:
21154 ie = bcm_next_tlv(ie, &remained_len);
21155 }
21156 return err;
21157 }
21158
21159 static bool
wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info * vndr_info)21160 wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info *vndr_info)
21161 {
21162 int i = 0;
21163
21164 while (exclude_vndr_oui_list[i]) {
21165 if (!memcmp(vndr_info->vndrie.oui,
21166 exclude_vndr_oui_list[i],
21167 DOT11_OUI_LEN)) {
21168 return TRUE;
21169 }
21170 i++;
21171 }
21172
21173 return FALSE;
21174 }
21175
21176 static bool
wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)21177 wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 *cfg,
21178 struct parsed_vndr_ie_info *vndr_info)
21179 {
21180 wl_vndr_oui_entry_t *oui_entry = NULL;
21181 unsigned long flags;
21182
21183 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21184 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21185 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
21186 GCC_DIAGNOSTIC_POP();
21187 if (!memcmp(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN)) {
21188 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21189 return TRUE;
21190 }
21191 }
21192 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21193 return FALSE;
21194 }
21195
21196 static bool
wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)21197 wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 *cfg,
21198 struct parsed_vndr_ie_info *vndr_info)
21199 {
21200 wl_vndr_oui_entry_t *oui_entry = NULL;
21201 unsigned long flags;
21202
21203 oui_entry = kmalloc(sizeof(*oui_entry), GFP_KERNEL);
21204 if (oui_entry == NULL) {
21205 WL_ERR(("alloc failed\n"));
21206 return FALSE;
21207 }
21208
21209 memcpy(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN);
21210
21211 INIT_LIST_HEAD(&oui_entry->list);
21212 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21213 list_add_tail(&oui_entry->list, &cfg->vndr_oui_list);
21214 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21215
21216 return TRUE;
21217 }
21218
21219 static void
wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 * cfg)21220 wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg)
21221 {
21222 wl_vndr_oui_entry_t *oui_entry = NULL;
21223 unsigned long flags;
21224
21225 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21226 while (!list_empty(&cfg->vndr_oui_list)) {
21227 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21228 oui_entry = list_entry(cfg->vndr_oui_list.next, wl_vndr_oui_entry_t, list);
21229 GCC_DIAGNOSTIC_POP();
21230 if (oui_entry) {
21231 list_del(&oui_entry->list);
21232 kfree(oui_entry);
21233 }
21234 }
21235 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21236 }
21237
21238 static int
wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * vndr_oui,u32 vndr_oui_len)21239 wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
21240 char *vndr_oui, u32 vndr_oui_len)
21241 {
21242 int i;
21243 int vndr_oui_num = 0;
21244
21245 struct wl_connect_info *conn_info = wl_to_conn(cfg);
21246 wl_vndr_oui_entry_t *oui_entry = NULL;
21247 struct parsed_vndr_ie_info *vndr_info;
21248 struct parsed_vndr_ies vndr_ies;
21249
21250 char *pos = vndr_oui;
21251 u32 remained_buf_len = vndr_oui_len;
21252 unsigned long flags;
21253
21254 if (!conn_info->resp_ie_len) {
21255 return BCME_ERROR;
21256 }
21257
21258 wl_vndr_ies_clear_vendor_oui_list(cfg);
21259
21260 if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
21261 conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
21262 for (i = 0; i < vndr_ies.count; i++) {
21263 vndr_info = &vndr_ies.ie_info[i];
21264 if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
21265 continue;
21266 }
21267
21268 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
21269 continue;
21270 }
21271
21272 wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
21273 vndr_oui_num++;
21274 }
21275 }
21276
21277 if (vndr_oui) {
21278 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21279 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21280 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
21281 GCC_DIAGNOSTIC_POP();
21282 if (remained_buf_len < VNDR_OUI_STR_LEN) {
21283 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21284 return BCME_ERROR;
21285 }
21286 pos += snprintf(pos, VNDR_OUI_STR_LEN, "%02X-%02X-%02X ",
21287 oui_entry->oui[0], oui_entry->oui[1], oui_entry->oui[2]);
21288 remained_buf_len -= VNDR_OUI_STR_LEN;
21289 }
21290 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21291 }
21292
21293 return vndr_oui_num;
21294 }
21295
21296 void
wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 * cfg)21297 wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 *cfg)
21298 {
21299 /* Legacy P2P used to store it in primary dev cache */
21300 s32 index;
21301 struct net_device *ndev;
21302 s32 bssidx;
21303 s32 ret;
21304 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
21305 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
21306
21307 WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
21308 /* certain vendors uses p2p0 interface in addition to
21309 * the dedicated p2p interface supported by the linux
21310 * kernel.
21311 */
21312 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
21313 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
21314 if (bssidx == WL_INVALID) {
21315 WL_DBG(("No discovery I/F available. Do nothing.\n"));
21316 return;
21317 }
21318
21319 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
21320 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
21321 bssidx, vndrie_flag[index], NULL, 0)) < 0) {
21322 if (ret != BCME_NOTFOUND) {
21323 WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret));
21324 }
21325 }
21326 }
21327
21328 if (cfg->p2p_wdev && (ndev->ieee80211_ptr != cfg->p2p_wdev)) {
21329 /* clear IEs for dedicated p2p interface */
21330 wl_cfg80211_clear_per_bss_ies(cfg, cfg->p2p_wdev);
21331 }
21332 }
21333
21334 s32
wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev)21335 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
21336 {
21337 s32 index;
21338 s32 ret;
21339 struct net_info *netinfo;
21340 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
21341 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
21342
21343 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
21344 if (!netinfo || !netinfo->wdev) {
21345 WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
21346 return -1;
21347 }
21348
21349 WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo->bssidx));
21350 /* Clear the IEs set in the firmware so that host is in sync with firmware */
21351 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
21352 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
21353 netinfo->bssidx, vndrie_flag[index], NULL, 0)) < 0)
21354 if (ret != BCME_NOTFOUND) {
21355 WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
21356 }
21357 }
21358
21359 return 0;
21360 }
21361
21362 s32
wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 * cfg)21363 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
21364 {
21365 struct net_info *iter, *next;
21366
21367 WL_DBG(("clear management vendor IEs \n"));
21368 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21369 for_each_ndev(cfg, iter, next) {
21370 GCC_DIAGNOSTIC_POP();
21371 wl_cfg80211_clear_per_bss_ies(cfg, iter->wdev);
21372 }
21373 return 0;
21374 }
21375
21376 #define WL_VNDR_IE_MAXLEN 2048
21377 static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
21378 int
wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,s32 bssidx,s32 pktflag,const u8 * vndr_ie,u32 vndr_ie_len)21379 wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21380 s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
21381 {
21382 struct net_device *ndev = NULL;
21383 s32 ret = BCME_OK;
21384 u8 *curr_ie_buf = NULL;
21385 u8 *mgmt_ie_buf = NULL;
21386 u32 mgmt_ie_buf_len = 0;
21387 u32 *mgmt_ie_len = 0;
21388 u32 del_add_ie_buf_len = 0;
21389 u32 total_ie_buf_len = 0;
21390 u32 parsed_ie_buf_len = 0;
21391 struct parsed_vndr_ies old_vndr_ies;
21392 struct parsed_vndr_ies new_vndr_ies;
21393 s32 i;
21394 u8 *ptr;
21395 s32 remained_buf_len;
21396 wl_bss_vndr_ies_t *ies = NULL;
21397 struct net_info *netinfo;
21398 struct wireless_dev *wdev;
21399
21400 if (!cfgdev) {
21401 WL_ERR(("cfgdev is NULL\n"));
21402 return -EINVAL;
21403 }
21404
21405 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
21406 wdev = cfgdev_to_wdev(cfgdev);
21407
21408 if (bssidx > WL_MAX_IFS) {
21409 WL_ERR(("bssidx > supported concurrent Ifaces \n"));
21410 return -EINVAL;
21411 }
21412
21413 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
21414 if (!netinfo) {
21415 WL_ERR(("net_info ptr is NULL \n"));
21416 return -EINVAL;
21417 }
21418
21419 /* Clear the global buffer */
21420 bzero(g_mgmt_ie_buf, sizeof(g_mgmt_ie_buf));
21421 curr_ie_buf = g_mgmt_ie_buf;
21422 ies = &netinfo->bss.ies;
21423
21424 WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d wdev:%p\n",
21425 pktflag, bssidx, vndr_ie_len, wdev));
21426
21427 switch (pktflag) {
21428 case VNDR_IE_PRBRSP_FLAG :
21429 mgmt_ie_buf = ies->probe_res_ie;
21430 mgmt_ie_len = &ies->probe_res_ie_len;
21431 mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
21432 break;
21433 case VNDR_IE_ASSOCRSP_FLAG :
21434 mgmt_ie_buf = ies->assoc_res_ie;
21435 mgmt_ie_len = &ies->assoc_res_ie_len;
21436 mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
21437 break;
21438 case VNDR_IE_BEACON_FLAG :
21439 mgmt_ie_buf = ies->beacon_ie;
21440 mgmt_ie_len = &ies->beacon_ie_len;
21441 mgmt_ie_buf_len = sizeof(ies->beacon_ie);
21442 break;
21443 case VNDR_IE_PRBREQ_FLAG :
21444 mgmt_ie_buf = ies->probe_req_ie;
21445 mgmt_ie_len = &ies->probe_req_ie_len;
21446 mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
21447 break;
21448 case VNDR_IE_ASSOCREQ_FLAG :
21449 mgmt_ie_buf = ies->assoc_req_ie;
21450 mgmt_ie_len = &ies->assoc_req_ie_len;
21451 mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
21452 break;
21453 case VNDR_IE_DISASSOC_FLAG :
21454 mgmt_ie_buf = ies->disassoc_ie;
21455 mgmt_ie_len = &ies->disassoc_ie_len;
21456 mgmt_ie_buf_len = sizeof(ies->disassoc_ie);
21457 break;
21458 default:
21459 mgmt_ie_buf = NULL;
21460 mgmt_ie_len = NULL;
21461 WL_ERR(("not suitable packet type (%d)\n", pktflag));
21462 return BCME_ERROR;
21463 }
21464
21465 if (vndr_ie_len > mgmt_ie_buf_len) {
21466 WL_ERR(("extra IE size too big\n"));
21467 ret = -ENOMEM;
21468 } else {
21469 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
21470 if (vndr_ie && vndr_ie_len && curr_ie_buf) {
21471 ptr = curr_ie_buf;
21472
21473 if ((ret = wl_cfg80211_parse_vndr_ies((const u8 *)vndr_ie,
21474 vndr_ie_len, &new_vndr_ies)) < 0) {
21475 WL_ERR(("parse vndr ie failed \n"));
21476 goto exit;
21477 }
21478
21479 for (i = 0; i < new_vndr_ies.count; i++) {
21480 struct parsed_vndr_ie_info *vndrie_info =
21481 &new_vndr_ies.ie_info[i];
21482
21483 if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
21484 WL_ERR(("IE size is too big (%d > %d)\n",
21485 parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
21486 ret = -EINVAL;
21487 goto exit;
21488 }
21489
21490 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
21491 vndrie_info->ie_len);
21492 parsed_ie_buf_len += vndrie_info->ie_len;
21493 }
21494 }
21495
21496 if (mgmt_ie_buf != NULL) {
21497 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
21498 (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
21499 WL_DBG(("Previous mgmt IE is equals to current IE"));
21500 goto exit;
21501 }
21502
21503 /* parse old vndr_ie */
21504 if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
21505 &old_vndr_ies)) < 0) {
21506 WL_ERR(("parse vndr ie failed \n"));
21507 goto exit;
21508 }
21509 /* make a command to delete old ie */
21510 for (i = 0; i < old_vndr_ies.count; i++) {
21511 struct parsed_vndr_ie_info *vndrie_info =
21512 &old_vndr_ies.ie_info[i];
21513 #if defined(WL_MBO) || defined(WL_OCE)
21514 {
21515 if ((vndrie_info->vndrie.id == 0xDD) &&
21516 (!memcmp(vndrie_info->vndrie.oui, WFA_OUI, WFA_OUI_LEN)) &&
21517 (vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
21518 WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
21519 ", type: %0x\n",
21520 vndrie_info->vndrie.id,
21521 vndrie_info->vndrie.len,
21522 MACOUI2STRDBG(vndrie_info->vndrie.oui),
21523 vndrie_info->vndrie.data[0]));
21524 continue;
21525 }
21526 }
21527 #endif /* WL_MBO || WL_OCE */
21528
21529 if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
21530 WL_DBG(("DELETED VENDOR EXTN ID : %d, TYPE: %d Len: %d\n",
21531 vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
21532 vndrie_info->vndrie.len));
21533 } else {
21534 WL_DBG(("DELETED ID : %d, Len: %d , OUI:"MACOUIDBG"\n",
21535 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
21536 MACOUI2STRDBG(vndrie_info->vndrie.oui)));
21537 }
21538
21539 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
21540 pktflag, vndrie_info->vndrie.oui,
21541 vndrie_info->vndrie.id,
21542 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
21543 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
21544 "del");
21545
21546 curr_ie_buf += del_add_ie_buf_len;
21547 total_ie_buf_len += del_add_ie_buf_len;
21548 }
21549 }
21550
21551 *mgmt_ie_len = 0;
21552 /* Add if there is any extra IE */
21553 if (mgmt_ie_buf && parsed_ie_buf_len) {
21554 ptr = mgmt_ie_buf;
21555
21556 remained_buf_len = mgmt_ie_buf_len;
21557
21558 /* make a command to add new ie */
21559 for (i = 0; i < new_vndr_ies.count; i++) {
21560 struct parsed_vndr_ie_info *vndrie_info =
21561 &new_vndr_ies.ie_info[i];
21562 #if defined(WL_MBO) || defined(WL_OCE)
21563 {
21564 if ((vndrie_info->vndrie.id == 0xDD) &&
21565 (!memcmp(vndrie_info->vndrie.oui, WFA_OUI, WFA_OUI_LEN)) &&
21566 (vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
21567 WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
21568 ",type :%0x\n",
21569 vndrie_info->vndrie.id,
21570 vndrie_info->vndrie.len,
21571 MACOUI2STRDBG(vndrie_info->vndrie.oui),
21572 vndrie_info->vndrie.data[0]));
21573 continue;
21574 }
21575 }
21576 #endif /* WL_MBO || WL_OCE */
21577 if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
21578 WL_DBG(("ADDED VENDOR EXTN ID : %d, TYPE = %d, Len: %d\n",
21579 vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
21580 vndrie_info->vndrie.len));
21581 } else {
21582 WL_DBG(("ADDED ID : %d, Len: %d(%d), OUI:"MACOUIDBG"\n",
21583 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
21584 vndrie_info->ie_len - 2,
21585 MACOUI2STRDBG(vndrie_info->vndrie.oui)));
21586 }
21587
21588 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
21589 pktflag, vndrie_info->vndrie.oui,
21590 vndrie_info->vndrie.id,
21591 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
21592 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
21593 "add");
21594
21595 /* verify remained buf size before copy data */
21596 if (remained_buf_len >= vndrie_info->ie_len) {
21597 remained_buf_len -= vndrie_info->ie_len;
21598 } else {
21599 WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
21600 "found vndr ies # = %d(cur %d), remained len %d, "
21601 "cur mgmt_ie_len %d, new ie len = %d\n",
21602 pktflag, new_vndr_ies.count, i, remained_buf_len,
21603 *mgmt_ie_len, vndrie_info->ie_len));
21604 break;
21605 }
21606
21607 /* save the parsed IE in cfg struct */
21608 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
21609 vndrie_info->ie_len);
21610 *mgmt_ie_len += vndrie_info->ie_len;
21611 curr_ie_buf += del_add_ie_buf_len;
21612 total_ie_buf_len += del_add_ie_buf_len;
21613 }
21614 }
21615
21616 if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
21617 ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
21618 total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
21619 bssidx, &cfg->ioctl_buf_sync);
21620 if (ret)
21621 WL_ERR(("vndr ie set error : %d\n", ret));
21622 }
21623 }
21624 exit:
21625
21626 return ret;
21627 }
21628
21629 #ifdef WL_CFG80211_ACL
21630 static int
wl_cfg80211_set_mac_acl(struct wiphy * wiphy,struct net_device * cfgdev,const struct cfg80211_acl_data * acl)21631 wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
21632 const struct cfg80211_acl_data *acl)
21633 {
21634 int i;
21635 int ret = 0;
21636 int macnum = 0;
21637 int macmode = MACLIST_MODE_DISABLED;
21638 struct maclist *list;
21639 struct bcm_cfg80211 *cfg = wl_get_cfg(cfgdev);
21640
21641 /* get the MAC filter mode */
21642 if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
21643 macmode = MACLIST_MODE_ALLOW;
21644 } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
21645 acl->n_acl_entries) {
21646 macmode = MACLIST_MODE_DENY;
21647 }
21648
21649 /* if acl == NULL, macmode is still disabled.. */
21650 if (macmode == MACLIST_MODE_DISABLED) {
21651 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0)
21652 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list"
21653 " failed error=%d\n", ret));
21654
21655 return ret;
21656 }
21657
21658 macnum = acl->n_acl_entries;
21659 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
21660 WL_ERR(("wl_cfg80211_set_mac_acl: invalid number of MAC address entries %d\n",
21661 macnum));
21662 return -1;
21663 }
21664
21665 /* allocate memory for the MAC list */
21666 list = (struct maclist *)MALLOC(cfg->osh, sizeof(int) +
21667 sizeof(struct ether_addr) * macnum);
21668 if (!list) {
21669 WL_ERR(("wl_cfg80211_set_mac_acl: failed to allocate memory\n"));
21670 return -1;
21671 }
21672
21673 /* prepare the MAC list */
21674 list->count = htod32(macnum);
21675 for (i = 0; i < macnum; i++) {
21676 memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN);
21677 }
21678 /* set the list */
21679 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0)
21680 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list failed error=%d\n", ret));
21681
21682 MFREE(cfg->osh, list, sizeof(int) +
21683 sizeof(struct ether_addr) * macnum);
21684
21685 return ret;
21686 }
21687 #endif /* WL_CFG80211_ACL */
21688
21689 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
wl_chspec_chandef(chanspec_t chanspec,struct cfg80211_chan_def * chandef,struct wiphy * wiphy)21690 int wl_chspec_chandef(chanspec_t chanspec,
21691 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
21692 struct cfg80211_chan_def *chandef,
21693 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
21694 struct chan_info *chaninfo,
21695 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
21696 struct wiphy *wiphy)
21697 {
21698 uint16 freq = 0;
21699 int chan_type = 0;
21700 int channel = 0;
21701 struct ieee80211_channel *chan;
21702
21703 if (!chandef) {
21704 return -1;
21705 }
21706 channel = CHSPEC_CHANNEL(chanspec);
21707
21708 switch (CHSPEC_BW(chanspec)) {
21709 case WL_CHANSPEC_BW_20:
21710 chan_type = NL80211_CHAN_HT20;
21711 break;
21712 case WL_CHANSPEC_BW_40:
21713 {
21714 if (CHSPEC_SB_UPPER(chanspec)) {
21715 channel += CH_10MHZ_APART;
21716 } else {
21717 channel -= CH_10MHZ_APART;
21718 }
21719 }
21720 chan_type = NL80211_CHAN_HT40PLUS;
21721 break;
21722
21723 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21724 case WL_CHANSPEC_BW_80:
21725 case WL_CHANSPEC_BW_8080:
21726 {
21727 uint16 sb = CHSPEC_CTL_SB(chanspec);
21728
21729 if (sb == WL_CHANSPEC_CTL_SB_LL) {
21730 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
21731 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
21732 channel -= CH_10MHZ_APART;
21733 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
21734 channel += CH_10MHZ_APART;
21735 } else {
21736 /* WL_CHANSPEC_CTL_SB_UU */
21737 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
21738 }
21739
21740 if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_LU)
21741 chan_type = NL80211_CHAN_HT40MINUS;
21742 else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU)
21743 chan_type = NL80211_CHAN_HT40PLUS;
21744 }
21745 break;
21746 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21747 default:
21748 chan_type = NL80211_CHAN_HT20;
21749 break;
21750
21751 }
21752
21753 if (CHSPEC_IS5G(chanspec))
21754 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
21755 else
21756 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
21757
21758 chan = ieee80211_get_channel(wiphy, freq);
21759 WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
21760 channel, freq, chan_type, chan));
21761
21762 if (unlikely(!chan)) {
21763 /* fw and cfg80211 channel lists are not in sync */
21764 WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
21765 ASSERT(0);
21766 return -EINVAL;
21767 }
21768
21769 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21770 cfg80211_chandef_create(chandef, chan, chan_type);
21771 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
21772 \
21773 0)))
21774 chaninfo->freq = freq;
21775 chaninfo->chan_type = chan_type;
21776 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21777 return 0;
21778 }
21779
21780 void
wl_cfg80211_ch_switch_notify(struct net_device * dev,uint16 chanspec,struct wiphy * wiphy)21781 wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy)
21782 {
21783 u32 freq;
21784 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21785 struct cfg80211_chan_def chandef;
21786 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
21787 struct chan_info chaninfo;
21788 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21789
21790 if (!wiphy) {
21791 WL_ERR(("wiphy is null\n"));
21792 return;
21793 }
21794 #if (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0))
21795 /* Channel switch support is only for AP/GO/ADHOC/MESH */
21796 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
21797 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
21798 WL_ERR(("No channel switch notify support for STA/GC\n"));
21799 return;
21800 }
21801 #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
21802
21803 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21804 if (wl_chspec_chandef(chanspec, &chandef, wiphy))
21805 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
21806 if (wl_chspec_chandef(chanspec, &chaninfo, wiphy))
21807 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21808 {
21809 WL_ERR(("chspec_chandef failed\n"));
21810 return;
21811 }
21812 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
21813 freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1;
21814 cfg80211_ch_switch_notify(dev, &chandef);
21815 #ifdef CONFIG_AP6XXX_WIFI6_HDF
21816 HdfWifiEventCsaChannelSwitch(get_hdf_netdev(HDF_INF_P2P0), freq);
21817 #endif
21818 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, 0)))
21819 freq = chan_info.freq;
21820 cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type);
21821 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21822
21823 WL_MSG(dev->name, "Channel switch notification for freq: %d chanspec: 0x%x\n",
21824 freq, chanspec);
21825 return;
21826 }
21827 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
21828
21829 static void
wl_ap_channel_ind(struct bcm_cfg80211 * cfg,struct net_device * ndev,chanspec_t chanspec)21830 wl_ap_channel_ind(struct bcm_cfg80211 *cfg,
21831 struct net_device *ndev,
21832 chanspec_t chanspec)
21833 {
21834 u32 channel = LCHSPEC_CHANNEL(chanspec);
21835
21836 WL_INFORM_MEM(("(%s) AP channel:%d chspec:0x%x \n",
21837 ndev->name, channel, chanspec));
21838
21839 #ifdef SUPPORT_AP_BWCTRL
21840 wl_update_apchan_bwcap(cfg, ndev, chanspec);
21841 #endif /* SUPPORT_AP_BWCTRL */
21842
21843 if (cfg->ap_oper_channel && (cfg->ap_oper_channel != channel)) {
21844 /*
21845 * If cached channel is different from the channel indicated
21846 * by the event, notify user space about the channel switch.
21847 */
21848 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
21849 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
21850 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
21851 cfg->ap_oper_channel = channel;
21852 }
21853 }
21854
21855 static s32
wl_ap_start_ind(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21856 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21857 const wl_event_msg_t *e, void *data)
21858 {
21859 struct net_device *ndev = NULL;
21860 chanspec_t chanspec;
21861
21862 WL_DBG(("Enter\n"));
21863 if (unlikely(e->status)) {
21864 WL_ERR(("status:0x%x \n", e->status));
21865 return -1;
21866 }
21867
21868 if (!data) {
21869 return -EINVAL;
21870 }
21871
21872 if (likely(cfgdev)) {
21873 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
21874 chanspec = *((chanspec_t *)data);
21875
21876 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
21877 /* For AP/GO role */
21878 wl_ap_channel_ind(cfg, ndev, chanspec);
21879 }
21880 }
21881
21882 return 0;
21883 }
21884
21885 static s32
wl_csa_complete_ind(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21886 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21887 const wl_event_msg_t *e, void *data)
21888 {
21889 int error = 0;
21890 u32 chanspec = 0;
21891 struct net_device *ndev = NULL;
21892 struct ether_addr bssid;
21893
21894 WL_DBG(("Enter\n"));
21895 if (unlikely(e->status)) {
21896 WL_ERR(("status:0x%x \n", e->status));
21897 return -1;
21898 }
21899
21900 if (likely(cfgdev)) {
21901 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
21902 /* Get association state if not AP and then query chanspec */
21903 if (!((wl_get_mode_by_netdev(cfg, ndev)) == WL_MODE_AP)) {
21904 error = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
21905 if (error) {
21906 WL_ERR(("CSA on %s. Not associated. error=%d\n",
21907 ndev->name, error));
21908 return BCME_ERROR;
21909 }
21910 }
21911
21912 error = wldev_iovar_getint(ndev, "chanspec", &chanspec);
21913 if (unlikely(error)) {
21914 WL_ERR(("Get chanspec error: %d \n", error));
21915 return -1;
21916 }
21917
21918 WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev->name, chanspec));
21919 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
21920 /* For AP/GO role */
21921 wl_ap_channel_ind(cfg, ndev, chanspec);
21922 } else {
21923 /* STA/GC roles */
21924 if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
21925 WL_ERR(("CSA on %s. Not associated.\n", ndev->name));
21926 return BCME_ERROR;
21927 }
21928 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
21929 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
21930 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
21931 }
21932
21933 }
21934
21935 return 0;
21936 }
21937
wl_cfg80211_clear_security(struct bcm_cfg80211 * cfg)21938 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
21939 {
21940 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
21941 int err;
21942
21943 /* Clear the security settings on the primary Interface */
21944 err = wldev_iovar_setint(dev, "wsec", 0);
21945 if (unlikely(err)) {
21946 WL_ERR(("wsec clear failed \n"));
21947 }
21948 err = wldev_iovar_setint(dev, "auth", 0);
21949 if (unlikely(err)) {
21950 WL_ERR(("auth clear failed \n"));
21951 }
21952 err = wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
21953 if (unlikely(err)) {
21954 WL_ERR(("wpa_auth clear failed \n"));
21955 }
21956 }
21957
21958 #ifdef WL_CFG80211_P2P_DEV_IF
wl_cfg80211_del_p2p_wdev(struct net_device * dev)21959 void wl_cfg80211_del_p2p_wdev(struct net_device *dev)
21960 {
21961 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21962 struct wireless_dev *wdev = NULL;
21963
21964 WL_DBG(("Enter \n"));
21965 if (!cfg) {
21966 WL_ERR(("Invalid Ptr\n"));
21967 return;
21968 } else {
21969 wdev = cfg->p2p_wdev;
21970 }
21971
21972 if (wdev) {
21973 wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
21974 }
21975 }
21976 #endif /* WL_CFG80211_P2P_DEV_IF */
21977
21978 #ifdef GTK_OFFLOAD_SUPPORT
21979 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
21980 static s32
wl_cfg80211_set_rekey_data(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_gtk_rekey_data * data)21981 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
21982 struct cfg80211_gtk_rekey_data *data)
21983 {
21984 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
21985 s32 err = 0;
21986 gtk_keyinfo_t keyinfo;
21987 bcol_gtk_para_t bcol_keyinfo;
21988
21989 WL_DBG(("Enter\n"));
21990 if (data == NULL || cfg->p2p_net == dev) {
21991 WL_ERR(("data is NULL or wrong net device\n"));
21992 return -EINVAL;
21993 }
21994
21995 prhex("kck", (const u8 *) (data->kck), RSN_KCK_LENGTH);
21996 prhex("kek", (const u8 *) (data->kek), RSN_KEK_LENGTH);
21997 prhex("replay_ctr", (const u8 *) (data->replay_ctr), RSN_REPLAY_LEN);
21998 bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH);
21999 bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH);
22000 bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN);
22001
22002 memset(&bcol_keyinfo, 0, sizeof(bcol_keyinfo));
22003 bcol_keyinfo.enable = 1;
22004 bcol_keyinfo.ptk_len = 64;
22005 memcpy(&bcol_keyinfo.ptk[0], data->kck, RSN_KCK_LENGTH);
22006 memcpy(&bcol_keyinfo.ptk[RSN_KCK_LENGTH], data->kek, RSN_KEK_LENGTH);
22007 err = wldev_iovar_setbuf(dev, "bcol_gtk_rekey_ptk", &bcol_keyinfo,
22008 sizeof(bcol_keyinfo), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
22009 if (!err) {
22010 return err;
22011 }
22012
22013 if ((err = wldev_iovar_setbuf(dev, "gtk_key_info", &keyinfo, sizeof(keyinfo),
22014 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync)) < 0) {
22015 WL_ERR(("seting gtk_key_info failed code=%d\n", err));
22016 return err;
22017 }
22018
22019 WL_DBG(("Exit\n"));
22020 return err;
22021 }
22022 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
22023 #endif /* GTK_OFFLOAD_SUPPORT */
22024
22025 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
wl_cfg80211_set_pmk(struct wiphy * wiphy,struct net_device * dev,const struct cfg80211_pmk_conf * conf)22026 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
22027 const struct cfg80211_pmk_conf *conf)
22028 {
22029 int ret = 0;
22030 wsec_pmk_t pmk;
22031 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
22032 struct wl_security *sec;
22033 s32 bssidx;
22034
22035 pmk.key_len = conf->pmk_len;
22036 if (pmk.key_len > sizeof(pmk.key)) {
22037 ret = -EINVAL;
22038 return ret;
22039 }
22040 pmk.flags = 0;
22041 ret = memcpy_s(&pmk.key, sizeof(pmk.key), conf->pmk, conf->pmk_len);
22042 if (ret) {
22043 ret = -EINVAL;
22044 return ret;
22045 }
22046
22047 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
22048 WL_ERR(("Find index failed\n"));
22049 ret = -EINVAL;
22050 return ret;
22051 }
22052
22053 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
22054 if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
22055 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
22056 ret = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len,
22057 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
22058 if (ret) {
22059 /* could fail in case that 'okc' is not supported */
22060 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
22061 }
22062 }
22063
22064 ret = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
22065 if (ret) {
22066 WL_ERR(("wl_cfg80211_set_pmk error:%d", ret));
22067 ret = -EINVAL;
22068 return ret;
22069 }
22070 return 0;
22071 }
22072
wl_cfg80211_del_pmk(struct wiphy * wiphy,struct net_device * dev,const u8 * aa)22073 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
22074 const u8 *aa)
22075 {
22076 int err = BCME_OK;
22077 struct cfg80211_pmksa pmksa;
22078
22079 /* build up cfg80211_pmksa structure to use existing wl_cfg80211_update_pmksa API */
22080 bzero(&pmksa, sizeof(pmksa));
22081 pmksa.bssid = aa;
22082
22083 err = wl_cfg80211_update_pmksa(wiphy, dev, &pmksa, FALSE);
22084
22085 if (err) {
22086 WL_ERR(("wl_cfg80211_update_pmksa err:%d\n", err));
22087 err = -EINVAL;
22088 }
22089
22090 return err;
22091 }
22092 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
22093
22094 #if defined(WL_SUPPORT_AUTO_CHANNEL)
22095 int
wl_cfg80211_set_spect(struct net_device * dev,int spect)22096 wl_cfg80211_set_spect(struct net_device *dev, int spect)
22097 {
22098 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22099 int wlc_down = 1;
22100 int wlc_up = 1;
22101 int err = BCME_OK;
22102
22103 if (!wl_get_drv_status_all(cfg, CONNECTED)) {
22104 err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
22105 if (err) {
22106 WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
22107 return err;
22108 }
22109
22110 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
22111 if (err) {
22112 WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
22113 return err;
22114 }
22115
22116 err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
22117 if (err) {
22118 WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
22119 return err;
22120 }
22121 }
22122 return err;
22123 }
22124
22125 int
wl_cfg80211_get_sta_channel(struct bcm_cfg80211 * cfg)22126 wl_cfg80211_get_sta_channel(struct bcm_cfg80211 *cfg)
22127 {
22128 int channel = 0;
22129
22130 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
22131 channel = cfg->channel;
22132 }
22133 return channel;
22134 }
22135 #endif /* WL_SUPPORT_AUTO_CHANNEL */
22136
22137 u64
wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 * cfg)22138 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
22139 {
22140 u64 id = 0;
22141 id = ++cfg->last_roc_id;
22142 #ifdef P2P_LISTEN_OFFLOADING
22143 if (id == P2PO_COOKIE) {
22144 id = ++cfg->last_roc_id;
22145 }
22146 #endif /* P2P_LISTEN_OFFLOADING */
22147 if (id == 0)
22148 id = ++cfg->last_roc_id;
22149 return id;
22150 }
22151
22152 #ifdef WLTDLS
22153 s32
wl_cfg80211_tdls_config(struct bcm_cfg80211 * cfg,enum wl_tdls_config state,bool auto_mode)22154 wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg, enum wl_tdls_config state, bool auto_mode)
22155 {
22156 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
22157 int err = 0;
22158 struct net_info *iter, *next;
22159 int update_reqd = 0;
22160 int enable = 0;
22161 dhd_pub_t *dhdp;
22162 dhdp = (dhd_pub_t *)(cfg->pub);
22163
22164 /*
22165 * TDLS need to be enabled only if we have a single STA/GC
22166 * connection.
22167 */
22168
22169 WL_DBG(("Enter state:%d\n", state));
22170 if (!cfg->tdls_supported) {
22171 /* FW doesn't support tdls. Do nothing */
22172 return -ENODEV;
22173 }
22174
22175 /* Protect tdls config session */
22176 mutex_lock(&cfg->tdls_sync);
22177
22178 if (state == TDLS_STATE_TEARDOWN) {
22179 /* Host initiated TDLS tear down */
22180 err = dhd_tdls_enable(ndev, false, auto_mode, NULL);
22181 goto exit;
22182 } else if ((state == TDLS_STATE_AP_CREATE) ||
22183 (state == TDLS_STATE_NMI_CREATE)) {
22184 /* We don't support tdls while AP/GO/NAN is operational */
22185 update_reqd = true;
22186 enable = false;
22187 } else if ((state == TDLS_STATE_CONNECT) || (state == TDLS_STATE_IF_CREATE)) {
22188 if (wl_get_drv_status_all(cfg,
22189 CONNECTED) >= TDLS_MAX_IFACE_FOR_ENABLE) {
22190 /* For STA/GC connect command request, disable
22191 * tdls if we have any concurrent interfaces
22192 * operational.
22193 */
22194 WL_DBG(("Interface limit restriction. disable tdls.\n"));
22195 update_reqd = true;
22196 enable = false;
22197 }
22198 } else if ((state == TDLS_STATE_DISCONNECT) ||
22199 (state == TDLS_STATE_AP_DELETE) ||
22200 (state == TDLS_STATE_SETUP) ||
22201 (state == TDLS_STATE_IF_DELETE)) {
22202 /* Enable back the tdls connection only if we have less than
22203 * or equal to a single STA/GC connection.
22204 */
22205 if (wl_get_drv_status_all(cfg,
22206 CONNECTED) == 0) {
22207 /* If there are no interfaces connected, enable tdls */
22208 update_reqd = true;
22209 enable = true;
22210 } else if (wl_get_drv_status_all(cfg,
22211 CONNECTED) == TDLS_MAX_IFACE_FOR_ENABLE) {
22212 /* We have one interface in CONNECTED state.
22213 * Verify whether its a STA interface before
22214 * we enable back tdls.
22215 */
22216 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22217 for_each_ndev(cfg, iter, next) {
22218 GCC_DIAGNOSTIC_POP();
22219 if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, ndev)) &&
22220 (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)) {
22221 WL_DBG(("Non STA iface operational. cfg_iftype:%d"
22222 " Can't enable tdls.\n",
22223 ndev->ieee80211_ptr->iftype));
22224 err = -ENOTSUPP;
22225 goto exit;
22226 }
22227 }
22228 /* No AP/GO found. Enable back tdls */
22229 update_reqd = true;
22230 enable = true;
22231 } else {
22232 WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
22233 err = -ENOTSUPP;
22234 goto exit;
22235 }
22236 } else {
22237 WL_ERR(("Unknown tdls state:%d \n", state));
22238 err = -EINVAL;
22239 goto exit;
22240 }
22241
22242 if (update_reqd == true) {
22243 if (dhdp->tdls_enable == enable) {
22244 WL_DBG(("No change in tdls state. Do nothing."
22245 " tdls_enable:%d\n", enable));
22246 goto exit;
22247 }
22248 err = wldev_iovar_setint(ndev, "tdls_enable", enable);
22249 if (unlikely(err)) {
22250 WL_ERR(("tdls_enable setting failed. err:%d\n", err));
22251 goto exit;
22252 } else {
22253 WL_INFORM_MEM(("tdls_enable %d state:%d\n", enable, state));
22254 /* Update the dhd state variable to be in sync */
22255 dhdp->tdls_enable = enable;
22256 if (state == TDLS_STATE_SETUP) {
22257 /* For host initiated setup, apply TDLS params
22258 * Don't propagate errors up for param config
22259 * failures
22260 */
22261 dhd_tdls_enable(ndev, true, auto_mode, NULL);
22262
22263 }
22264 }
22265 } else {
22266 WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
22267 "current_status:%d \n",
22268 state, update_reqd, dhdp->tdls_enable));
22269 }
22270
22271 exit:
22272 if (err) {
22273 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
22274 }
22275 mutex_unlock(&cfg->tdls_sync);
22276 return err;
22277 }
22278 #endif /* WLTDLS */
22279
wl_get_ap_netdev(struct bcm_cfg80211 * cfg,char * ifname)22280 struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname)
22281 {
22282 struct net_info *iter, *next;
22283 struct net_device *ndev = NULL;
22284
22285 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22286 for_each_ndev(cfg, iter, next) {
22287 GCC_DIAGNOSTIC_POP();
22288 if (iter->ndev) {
22289 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
22290 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
22291 ndev = iter->ndev;
22292 break;
22293 }
22294 }
22295 }
22296 }
22297
22298 return ndev;
22299 }
22300
22301 struct net_device*
wl_get_netdev_by_name(struct bcm_cfg80211 * cfg,char * ifname)22302 wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname)
22303 {
22304 struct net_info *iter, *next;
22305 struct net_device *ndev = NULL;
22306
22307 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22308 for_each_ndev(cfg, iter, next) {
22309 GCC_DIAGNOSTIC_POP();
22310 if (iter->ndev) {
22311 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
22312 ndev = iter->ndev;
22313 break;
22314 }
22315 }
22316 }
22317
22318 return ndev;
22319 }
22320
22321 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
22322 #define WLC_RATE_FLAG 0x80
22323 #define RATE_MASK 0x7f
22324
wl_set_ap_beacon_rate(struct net_device * dev,int val,char * ifname)22325 int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname)
22326 {
22327 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22328 dhd_pub_t *dhdp;
22329 wl_rateset_args_t rs;
22330 int error = BCME_ERROR, i;
22331 struct net_device *ndev = NULL;
22332
22333 dhdp = (dhd_pub_t *)(cfg->pub);
22334
22335 if (dhdp && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22336 WL_ERR(("Not Hostapd mode\n"));
22337 return BCME_NOTAP;
22338 }
22339
22340 ndev = wl_get_ap_netdev(cfg, ifname);
22341
22342 if (ndev == NULL) {
22343 WL_ERR(("No softAP interface named %s\n", ifname));
22344 return BCME_NOTAP;
22345 }
22346
22347 bzero(&rs, sizeof(wl_rateset_args_t));
22348 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
22349 &rs, sizeof(wl_rateset_args_t), NULL);
22350 if (error < 0) {
22351 WL_ERR(("get rateset failed = %d\n", error));
22352 return error;
22353 }
22354
22355 if (rs.count < 1) {
22356 WL_ERR(("Failed to get rate count\n"));
22357 return BCME_ERROR;
22358 }
22359
22360 /* Host delivers target rate in the unit of 500kbps */
22361 /* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic rate */
22362 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
22363 if (rs.rates[i] & WLC_RATE_FLAG)
22364 if ((rs.rates[i] & RATE_MASK) == val)
22365 break;
22366
22367 /* Valid rate has been delivered as an argument */
22368 if (i < rs.count && i < WL_NUMRATES) {
22369 error = wldev_iovar_setint(ndev, "force_bcn_rspec", val);
22370 if (error < 0) {
22371 WL_ERR(("set beacon rate failed = %d\n", error));
22372 return BCME_ERROR;
22373 }
22374 } else {
22375 WL_ERR(("Rate is invalid"));
22376 return BCME_BADARG;
22377 }
22378
22379 return BCME_OK;
22380 }
22381
22382 int
wl_get_ap_basic_rate(struct net_device * dev,char * command,char * ifname,int total_len)22383 wl_get_ap_basic_rate(struct net_device *dev, char* command, char *ifname, int total_len)
22384 {
22385 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22386 dhd_pub_t *dhdp;
22387 wl_rateset_args_t rs;
22388 int error = BCME_ERROR;
22389 int i, bytes_written = 0;
22390 struct net_device *ndev = NULL;
22391
22392 dhdp = (dhd_pub_t *)(cfg->pub);
22393
22394 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22395 WL_ERR(("Not Hostapd mode\n"));
22396 return BCME_NOTAP;
22397 }
22398
22399 ndev = wl_get_ap_netdev(cfg, ifname);
22400
22401 if (ndev == NULL) {
22402 WL_ERR(("No softAP interface named %s\n", ifname));
22403 return BCME_NOTAP;
22404 }
22405
22406 bzero(&rs, sizeof(wl_rateset_args_t));
22407 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
22408 &rs, sizeof(wl_rateset_args_t), NULL);
22409 if (error < 0) {
22410 WL_ERR(("get rateset failed = %d\n", error));
22411 return error;
22412 }
22413
22414 if (rs.count < 1) {
22415 WL_ERR(("Failed to get rate count\n"));
22416 return BCME_ERROR;
22417 }
22418
22419 /* Delivers basic rate in the unit of 500kbps to host */
22420 for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
22421 if (rs.rates[i] & WLC_RATE_FLAG)
22422 bytes_written += snprintf(command + bytes_written, total_len,
22423 "%d ", rs.rates[i] & RATE_MASK);
22424
22425 /* Remove last space in the command buffer */
22426 if (bytes_written && (bytes_written < total_len)) {
22427 command[bytes_written - 1] = '\0';
22428 bytes_written--;
22429 }
22430
22431 return bytes_written;
22432
22433 }
22434 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
22435
22436 #ifdef SUPPORT_AP_RADIO_PWRSAVE
22437 #define MSEC_PER_MIN (60000L)
22438
22439 static int
_wl_update_ap_rps_params(struct net_device * dev)22440 _wl_update_ap_rps_params(struct net_device *dev)
22441 {
22442 struct bcm_cfg80211 *cfg = NULL;
22443 rpsnoa_iovar_params_t iovar;
22444 u8 smbuf[WLC_IOCTL_SMLEN];
22445
22446 if (!dev)
22447 return BCME_BADARG;
22448
22449 cfg = wl_get_cfg(dev);
22450
22451 bzero(&iovar, sizeof(iovar));
22452 bzero(smbuf, sizeof(smbuf));
22453
22454 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
22455 iovar.hdr.subcmd = WL_RPSNOA_CMD_PARAMS;
22456 iovar.hdr.len = sizeof(iovar);
22457 iovar.param->band = WLC_BAND_ALL;
22458 iovar.param->level = cfg->ap_rps_info.level;
22459 iovar.param->stas_assoc_check = cfg->ap_rps_info.sta_assoc_check;
22460 iovar.param->pps = cfg->ap_rps_info.pps;
22461 iovar.param->quiet_time = cfg->ap_rps_info.quiet_time;
22462
22463 if (wldev_iovar_setbuf(dev, "rpsnoa", &iovar, sizeof(iovar),
22464 smbuf, sizeof(smbuf), NULL)) {
22465 WL_ERR(("Failed to set rpsnoa params"));
22466 return BCME_ERROR;
22467 }
22468
22469 return BCME_OK;
22470 }
22471
22472 int
wl_get_ap_rps(struct net_device * dev,char * command,char * ifname,int total_len)22473 wl_get_ap_rps(struct net_device *dev, char* command, char *ifname, int total_len)
22474 {
22475 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22476 dhd_pub_t *dhdp;
22477 int error = BCME_ERROR;
22478 int bytes_written = 0;
22479 struct net_device *ndev = NULL;
22480 rpsnoa_iovar_status_t iovar;
22481 u8 smbuf[WLC_IOCTL_SMLEN];
22482 u32 chanspec = 0;
22483 u8 idx = 0;
22484 u16 state;
22485 u32 sleep;
22486 u32 time_since_enable;
22487
22488 dhdp = (dhd_pub_t *)(cfg->pub);
22489
22490 if (!dhdp) {
22491 error = BCME_NOTUP;
22492 goto fail;
22493 }
22494
22495 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22496 WL_ERR(("Not Hostapd mode\n"));
22497 error = BCME_NOTAP;
22498 goto fail;
22499 }
22500
22501 ndev = wl_get_ap_netdev(cfg, ifname);
22502
22503 if (ndev == NULL) {
22504 WL_ERR(("No softAP interface named %s\n", ifname));
22505 error = BCME_NOTAP;
22506 goto fail;
22507 }
22508
22509 bzero(&iovar, sizeof(iovar));
22510 bzero(smbuf, sizeof(smbuf));
22511
22512 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
22513 iovar.hdr.subcmd = WL_RPSNOA_CMD_STATUS;
22514 iovar.hdr.len = sizeof(iovar);
22515 iovar.stats->band = WLC_BAND_ALL;
22516
22517 error = wldev_iovar_getbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
22518 smbuf, sizeof(smbuf), NULL);
22519 if (error < 0) {
22520 WL_ERR(("get ap radio pwrsave failed = %d\n", error));
22521 goto fail;
22522 }
22523
22524 /* RSDB event doesn't seem to be handled correctly.
22525 * So check chanspec of AP directly from the firmware
22526 */
22527 error = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
22528 if (error < 0) {
22529 WL_ERR(("get chanspec from AP failed = %d\n", error));
22530 goto fail;
22531 }
22532
22533 chanspec = wl_chspec_driver_to_host(chanspec);
22534 if (CHSPEC_IS2G(chanspec))
22535 idx = 0;
22536 else if (CHSPEC_IS5G(chanspec))
22537 idx = 1;
22538 else {
22539 error = BCME_BADCHAN;
22540 goto fail;
22541 }
22542
22543 state = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].state;
22544 sleep = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_dur;
22545 time_since_enable = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_avail_dur;
22546
22547 /* Conver ms to minute, round down only */
22548 sleep = DIV_U64_BY_U32(sleep, MSEC_PER_MIN);
22549 time_since_enable = DIV_U64_BY_U32(time_since_enable, MSEC_PER_MIN);
22550
22551 bytes_written += snprintf(command + bytes_written, total_len,
22552 "state=%d sleep=%d time_since_enable=%d", state, sleep, time_since_enable);
22553 error = bytes_written;
22554
22555 fail:
22556 return error;
22557 }
22558
22559 int
wl_set_ap_rps(struct net_device * dev,bool enable,char * ifname)22560 wl_set_ap_rps(struct net_device *dev, bool enable, char *ifname)
22561 {
22562 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22563 dhd_pub_t *dhdp;
22564 struct net_device *ndev = NULL;
22565 rpsnoa_iovar_t iovar;
22566 u8 smbuf[WLC_IOCTL_SMLEN];
22567 int ret = BCME_OK;
22568
22569 dhdp = (dhd_pub_t *)(cfg->pub);
22570
22571 if (!dhdp) {
22572 ret = BCME_NOTUP;
22573 goto exit;
22574 }
22575
22576 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22577 WL_ERR(("Not Hostapd mode\n"));
22578 ret = BCME_NOTAP;
22579 goto exit;
22580 }
22581
22582 ndev = wl_get_ap_netdev(cfg, ifname);
22583
22584 if (ndev == NULL) {
22585 WL_ERR(("No softAP interface named %s\n", ifname));
22586 ret = BCME_NOTAP;
22587 goto exit;
22588 }
22589
22590 if (cfg->ap_rps_info.enable != enable) {
22591 cfg->ap_rps_info.enable = enable;
22592 if (enable) {
22593 ret = _wl_update_ap_rps_params(ndev);
22594 if (ret) {
22595 WL_ERR(("Filed to update rpsnoa params\n"));
22596 goto exit;
22597 }
22598 }
22599 bzero(&iovar, sizeof(iovar));
22600 bzero(smbuf, sizeof(smbuf));
22601
22602 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
22603 iovar.hdr.subcmd = WL_RPSNOA_CMD_ENABLE;
22604 iovar.hdr.len = sizeof(iovar);
22605 iovar.data->band = WLC_BAND_ALL;
22606 iovar.data->value = (int16)enable;
22607
22608 ret = wldev_iovar_setbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
22609 smbuf, sizeof(smbuf), NULL);
22610 if (ret) {
22611 WL_ERR(("Failed to enable AP radio power save"));
22612 goto exit;
22613 }
22614 cfg->ap_rps_info.enable = enable;
22615 }
22616 exit:
22617 return ret;
22618 }
22619
22620 int
wl_update_ap_rps_params(struct net_device * dev,ap_rps_info_t * rps,char * ifname)22621 wl_update_ap_rps_params(struct net_device *dev, ap_rps_info_t* rps, char *ifname)
22622 {
22623 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22624 dhd_pub_t *dhdp;
22625 struct net_device *ndev = NULL;
22626
22627 dhdp = (dhd_pub_t *)(cfg->pub);
22628
22629 if (!dhdp)
22630 return BCME_NOTUP;
22631
22632 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22633 WL_ERR(("Not Hostapd mode\n"));
22634 return BCME_NOTAP;
22635 }
22636
22637 ndev = wl_get_ap_netdev(cfg, ifname);
22638
22639 if (ndev == NULL) {
22640 WL_ERR(("No softAP interface named %s\n", ifname));
22641 return BCME_NOTAP;
22642 }
22643
22644 if (!rps)
22645 return BCME_BADARG;
22646
22647 if (rps->pps < RADIO_PWRSAVE_PPS_MIN)
22648 return BCME_BADARG;
22649
22650 if (rps->level < RADIO_PWRSAVE_LEVEL_MIN ||
22651 rps->level > RADIO_PWRSAVE_LEVEL_MAX)
22652 return BCME_BADARG;
22653
22654 if (rps->quiet_time < RADIO_PWRSAVE_QUIETTIME_MIN)
22655 return BCME_BADARG;
22656
22657 if (rps->sta_assoc_check > RADIO_PWRSAVE_ASSOCCHECK_MAX ||
22658 rps->sta_assoc_check < RADIO_PWRSAVE_ASSOCCHECK_MIN)
22659 return BCME_BADARG;
22660
22661 cfg->ap_rps_info.pps = rps->pps;
22662 cfg->ap_rps_info.level = rps->level;
22663 cfg->ap_rps_info.quiet_time = rps->quiet_time;
22664 cfg->ap_rps_info.sta_assoc_check = rps->sta_assoc_check;
22665
22666 if (cfg->ap_rps_info.enable) {
22667 if (_wl_update_ap_rps_params(ndev)) {
22668 WL_ERR(("Failed to update rpsnoa params"));
22669 return BCME_ERROR;
22670 }
22671 }
22672
22673 return BCME_OK;
22674 }
22675
22676 void
wl_cfg80211_init_ap_rps(struct bcm_cfg80211 * cfg)22677 wl_cfg80211_init_ap_rps(struct bcm_cfg80211 *cfg)
22678 {
22679 cfg->ap_rps_info.enable = FALSE;
22680 cfg->ap_rps_info.sta_assoc_check = RADIO_PWRSAVE_STAS_ASSOC_CHECK;
22681 cfg->ap_rps_info.pps = RADIO_PWRSAVE_PPS;
22682 cfg->ap_rps_info.quiet_time = RADIO_PWRSAVE_QUIET_TIME;
22683 cfg->ap_rps_info.level = RADIO_PWRSAVE_LEVEL;
22684 }
22685 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
22686
22687 int
wl_cfg80211_iface_count(struct net_device * dev)22688 wl_cfg80211_iface_count(struct net_device *dev)
22689 {
22690 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22691 struct net_info *iter, *next;
22692 int iface_count = 0;
22693
22694 /* Return the count of network interfaces (skip netless p2p discovery
22695 * interface)
22696 */
22697 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22698 for_each_ndev(cfg, iter, next) {
22699 GCC_DIAGNOSTIC_POP();
22700 if (iter->ndev) {
22701 iface_count++;
22702 }
22703 }
22704 return iface_count;
22705 }
22706
22707 #ifdef SUPPORT_SET_CAC
22708 static void
wl_cfg80211_set_cac(struct bcm_cfg80211 * cfg,int enable)22709 wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable)
22710 {
22711 int ret = 0;
22712 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22713
22714 WL_DBG(("cac enable %d\n", enable));
22715 if (!dhd) {
22716 WL_ERR(("dhd is NULL\n"));
22717 return;
22718 }
22719 if ((ret = dhd_wl_ioctl_set_intiovar(dhd, "cac", enable,
22720 WLC_SET_VAR, TRUE, 0)) < 0) {
22721 WL_ERR(("Failed set CAC, ret=%d\n", ret));
22722 } else {
22723 WL_DBG(("CAC set successfully\n"));
22724 }
22725 return;
22726 }
22727 #endif /* SUPPORT_SET_CAC */
22728
22729 #ifdef SUPPORT_RSSI_SUM_REPORT
22730 int
wl_get_rssi_per_ant(struct net_device * dev,char * ifname,char * peer_mac,void * param)22731 wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void *param)
22732 {
22733 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22734 wl_rssi_ant_mimo_t *get_param = (wl_rssi_ant_mimo_t *)param;
22735 rssi_ant_param_t *set_param = NULL;
22736 struct net_device *ifdev = NULL;
22737 char iobuf[WLC_IOCTL_SMLEN];
22738 int err = BCME_OK;
22739 int iftype = 0;
22740
22741 bzero(iobuf, WLC_IOCTL_SMLEN);
22742
22743 /* Check the interface type */
22744 ifdev = wl_get_netdev_by_name(cfg, ifname);
22745 if (ifdev == NULL) {
22746 WL_ERR(("Could not find net_device for ifname:%s\n", ifname));
22747 err = BCME_BADARG;
22748 goto fail;
22749 }
22750
22751 iftype = ifdev->ieee80211_ptr->iftype;
22752 if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO) {
22753 if (peer_mac) {
22754 set_param = (rssi_ant_param_t *)MALLOCZ(cfg->osh, sizeof(rssi_ant_param_t));
22755 err = wl_cfg80211_ether_atoe(peer_mac, &set_param->ea);
22756 if (!err) {
22757 WL_ERR(("Invalid Peer MAC format\n"));
22758 err = BCME_BADARG;
22759 goto fail;
22760 }
22761 } else {
22762 WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype));
22763 err = BCME_BADARG;
22764 goto fail;
22765 }
22766 }
22767
22768 err = wldev_iovar_getbuf(ifdev, "phy_rssi_ant", peer_mac ?
22769 (void *)&(set_param->ea) : NULL, peer_mac ? ETHER_ADDR_LEN : 0,
22770 (void *)iobuf, sizeof(iobuf), NULL);
22771 if (unlikely(err)) {
22772 WL_ERR(("Failed to get rssi info, err=%d\n", err));
22773 } else {
22774 memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t));
22775 if (get_param->count == 0) {
22776 WL_ERR(("Not supported on this chip\n"));
22777 err = BCME_UNSUPPORTED;
22778 }
22779 }
22780
22781 fail:
22782 if (set_param) {
22783 MFREE(cfg->osh, set_param, sizeof(rssi_ant_param_t));
22784 }
22785
22786 return err;
22787 }
22788
22789 int
wl_get_rssi_logging(struct net_device * dev,void * param)22790 wl_get_rssi_logging(struct net_device *dev, void *param)
22791 {
22792 rssilog_get_param_t *get_param = (rssilog_get_param_t *)param;
22793 char iobuf[WLC_IOCTL_SMLEN];
22794 int err = BCME_OK;
22795
22796 bzero(iobuf, WLC_IOCTL_SMLEN);
22797 bzero(get_param, sizeof(*get_param));
22798 err = wldev_iovar_getbuf(dev, "rssilog", NULL, 0, (void *)iobuf,
22799 sizeof(iobuf), NULL);
22800 if (err) {
22801 WL_ERR(("Failed to get rssi logging info, err=%d\n", err));
22802 } else {
22803 memcpy(get_param, iobuf, sizeof(*get_param));
22804 }
22805
22806 return err;
22807 }
22808
22809 int
wl_set_rssi_logging(struct net_device * dev,void * param)22810 wl_set_rssi_logging(struct net_device *dev, void *param)
22811 {
22812 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22813 rssilog_set_param_t *set_param = (rssilog_set_param_t *)param;
22814 int err;
22815
22816 err = wldev_iovar_setbuf(dev, "rssilog", set_param,
22817 sizeof(*set_param), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
22818 &cfg->ioctl_buf_sync);
22819 if (err) {
22820 WL_ERR(("Failed to set rssi logging param, err=%d\n", err));
22821 }
22822
22823 return err;
22824 }
22825 #endif /* SUPPORT_RSSI_SUM_REPORT */
22826 /* Function to flush the FW preserve buffer content
22827 * The buffer content is sent to host in form of events.
22828 */
22829 void
wl_flush_fw_log_buffer(struct net_device * dev,uint32 logset_mask)22830 wl_flush_fw_log_buffer(struct net_device *dev, uint32 logset_mask)
22831 {
22832 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22833 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22834 int i;
22835 int err = 0;
22836 u8 buf[WLC_IOCTL_SMLEN] = {0};
22837 wl_el_set_params_t set_param;
22838
22839 /* Set the size of data to retrieve */
22840 memset(&set_param, 0, sizeof(set_param));
22841 set_param.size = WLC_IOCTL_SMLEN;
22842
22843 for (i = 0; i < dhd->event_log_max_sets; i++)
22844 {
22845 if ((0x01u << i) & logset_mask) {
22846 set_param.set = i;
22847 err = wldev_iovar_setbuf(dev, "event_log_get", &set_param,
22848 sizeof(struct wl_el_set_params_s), buf, WLC_IOCTL_SMLEN,
22849 NULL);
22850 if (err) {
22851 WL_DBG(("Failed to get fw preserve logs, err=%d\n", err));
22852 }
22853 }
22854 }
22855 }
22856 #ifdef USE_WFA_CERT_CONF
22857 extern int g_frameburst;
22858 #endif /* USE_WFA_CERT_CONF */
22859
22860 int
wl_cfg80211_set_frameburst(struct bcm_cfg80211 * cfg,bool enable)22861 wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable)
22862 {
22863 int ret = BCME_OK;
22864 int val = enable ? 1 : 0;
22865
22866 #ifdef USE_WFA_CERT_CONF
22867 if (!g_frameburst) {
22868 WL_DBG(("Skip setting frameburst\n"));
22869 return 0;
22870 }
22871 #endif /* USE_WFA_CERT_CONF */
22872
22873 WL_DBG(("Set frameburst %d\n", val));
22874 ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg), WLC_SET_FAKEFRAG, &val, sizeof(val));
22875 if (ret < 0) {
22876 WL_ERR(("Failed set frameburst, ret=%d\n", ret));
22877 } else {
22878 WL_INFORM_MEM(("frameburst is %s\n", enable ? "enabled" : "disabled"));
22879 }
22880
22881 return ret;
22882 }
22883
22884 s32
wl_cfg80211_set_dbg_verbose(struct net_device * ndev,u32 level)22885 wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level)
22886 {
22887 /* configure verbose level for debugging */
22888 if (level) {
22889 /* Enable increased verbose */
22890 wl_dbg_level |= WL_DBG_DBG;
22891 } else {
22892 /* Disable */
22893 wl_dbg_level &= ~WL_DBG_DBG;
22894 }
22895 WL_INFORM(("debug verbose set to %d\n", level));
22896
22897 return BCME_OK;
22898 }
22899
22900 const u8 *
wl_find_attribute(const u8 * buf,u16 len,u16 element_id)22901 wl_find_attribute(const u8 *buf, u16 len, u16 element_id)
22902 {
22903 const u8 *attrib;
22904 u16 attrib_id;
22905 u16 attrib_len;
22906
22907 if (!buf) {
22908 WL_ERR(("buf null\n"));
22909 return NULL;
22910 }
22911
22912 attrib = buf;
22913 while (len >= 4) {
22914 /* attribute id */
22915 attrib_id = *attrib++ << 8;
22916 attrib_id |= *attrib++;
22917 len -= 2;
22918
22919 /* 2-byte little endian */
22920 attrib_len = *attrib++ << 8;
22921 attrib_len |= *attrib++;
22922
22923 len -= 2;
22924 if (attrib_id == element_id) {
22925 /* This will point to start of subelement attrib after
22926 * attribute id & len
22927 */
22928 return attrib;
22929 }
22930 if (len > attrib_len) {
22931 len -= attrib_len; /* for the remaining subelt fields */
22932 WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n",
22933 attrib_id, attrib_len, len));
22934
22935 /* Go to next subelement */
22936 attrib += attrib_len;
22937 } else {
22938 WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n",
22939 attrib_id, attrib_len));
22940 return NULL;
22941 }
22942 }
22943 return NULL;
22944 }
22945
wl_cfg80211_get_bus_state(struct bcm_cfg80211 * cfg)22946 uint8 wl_cfg80211_get_bus_state(struct bcm_cfg80211 *cfg)
22947 {
22948 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22949 WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
22950 dhd->hang_was_sent, dhd->busstate));
22951 return ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent);
22952 }
22953
22954 #ifdef WL_WPS_SYNC
wl_wps_reauth_timeout(unsigned long data)22955 static void wl_wps_reauth_timeout(unsigned long data)
22956 {
22957 struct net_device *ndev = (struct net_device *)data;
22958 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
22959 s32 inst;
22960 unsigned long flags;
22961
22962 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
22963 inst = wl_get_wps_inst_match(cfg, ndev);
22964 if (inst >= 0) {
22965 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n",
22966 ndev->name, inst, cfg->wps_session[inst].state));
22967 if (cfg->wps_session[inst].state == WPS_STATE_REAUTH_WAIT) {
22968 /* Session should get deleted from success (linkup) or
22969 * deauth case. Just in case, link reassoc failed, clear
22970 * state here.
22971 */
22972 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n",
22973 ndev->name, inst));
22974 cfg->wps_session[inst].state = WPS_STATE_IDLE;
22975 cfg->wps_session[inst].in_use = false;
22976 }
22977 }
22978 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
22979 }
22980
wl_init_wps_reauth_sm(struct bcm_cfg80211 * cfg)22981 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg)
22982 {
22983 /* Only two instances are supported as of now. one for
22984 * infra STA and other for infra STA/GC.
22985 */
22986 int i = 0;
22987 struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
22988
22989 spin_lock_init(&cfg->wps_sync);
22990 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
22991 /* Init scan_timeout timer */
22992 init_timer_compat(&cfg->wps_session[i].timer, wl_wps_reauth_timeout, pdev);
22993 cfg->wps_session[i].in_use = false;
22994 cfg->wps_session[i].state = WPS_STATE_IDLE;
22995 }
22996 }
22997
wl_deinit_wps_reauth_sm(struct bcm_cfg80211 * cfg)22998 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg)
22999 {
23000 int i = 0;
23001
23002 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23003 cfg->wps_session[i].in_use = false;
23004 cfg->wps_session[i].state = WPS_STATE_IDLE;
23005 if (timer_pending(&cfg->wps_session[i].timer)) {
23006 del_timer_sync(&cfg->wps_session[i].timer);
23007 }
23008 }
23009
23010 }
23011
23012 static s32
wl_get_free_wps_inst(struct bcm_cfg80211 * cfg)23013 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg)
23014 {
23015 int i;
23016
23017 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23018 if (!cfg->wps_session[i].in_use) {
23019 return i;
23020 }
23021 }
23022 return BCME_ERROR;
23023 }
23024
23025 static s32
wl_get_wps_inst_match(struct bcm_cfg80211 * cfg,struct net_device * ndev)23026 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev)
23027 {
23028 int i;
23029
23030 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23031 if ((cfg->wps_session[i].in_use) &&
23032 (ndev == cfg->wps_session[i].ndev)) {
23033 return i;
23034 }
23035 }
23036
23037 return BCME_ERROR;
23038 }
23039
23040 static s32
wl_wps_session_add(struct net_device * ndev,u16 mode,u8 * mac_addr)23041 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *mac_addr)
23042 {
23043 s32 inst;
23044 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23045 unsigned long flags;
23046
23047 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23048 /* Fetch and initialize a wps instance */
23049 inst = wl_get_free_wps_inst(cfg);
23050 if (inst == BCME_ERROR) {
23051 WL_ERR(("[WPS] No free insance\n"));
23052 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23053 return BCME_ERROR;
23054 }
23055 cfg->wps_session[inst].in_use = true;
23056 cfg->wps_session[inst].state = WPS_STATE_STARTED;
23057 cfg->wps_session[inst].ndev = ndev;
23058 cfg->wps_session[inst].mode = mode;
23059 /* return check not required since both buffer lens are same */
23060 (void)memcpy_s(cfg->wps_session[inst].peer_mac, ETH_ALEN, mac_addr, ETH_ALEN);
23061 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23062
23063 WL_INFORM_MEM(("[%s][WPS] session created. Peer: " MACDBG "\n",
23064 ndev->name, MAC2STRDBG(mac_addr)));
23065 return BCME_OK;
23066 }
23067
23068 static void
wl_wps_session_del(struct net_device * ndev)23069 wl_wps_session_del(struct net_device *ndev)
23070 {
23071 s32 inst;
23072 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23073 unsigned long flags;
23074 u16 cur_state;
23075
23076 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23077
23078 /* Get current instance for the given ndev */
23079 inst = wl_get_wps_inst_match(cfg, ndev);
23080 if (inst == BCME_ERROR) {
23081 WL_DBG(("[WPS] instance match NOT found\n"));
23082 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23083 return;
23084 }
23085
23086 cur_state = cfg->wps_session[inst].state;
23087 if (cur_state != WPS_STATE_DONE) {
23088 WL_DBG(("[WPS] wrong state:%d\n", cur_state));
23089 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23090 return;
23091 }
23092
23093 /* Mark this as unused */
23094 cfg->wps_session[inst].in_use = false;
23095 cfg->wps_session[inst].state = WPS_STATE_IDLE;
23096 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23097
23098 /* Ensure this API is called from sleepable context. */
23099 if (timer_pending(&cfg->wps_session[inst].timer)) {
23100 del_timer_sync(&cfg->wps_session[inst].timer);
23101 }
23102
23103 WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev->name));
23104 }
23105
23106 static void
wl_wps_handle_ifdel(struct net_device * ndev)23107 wl_wps_handle_ifdel(struct net_device *ndev)
23108 {
23109 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23110 unsigned long flags;
23111 u16 cur_state;
23112 s32 inst;
23113
23114 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23115 inst = wl_get_wps_inst_match(cfg, ndev);
23116 if (inst == BCME_ERROR) {
23117 WL_DBG(("[WPS] instance match NOT found\n"));
23118 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23119 return;
23120 }
23121 cur_state = cfg->wps_session[inst].state;
23122 cfg->wps_session[inst].state = WPS_STATE_DONE;
23123 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23124
23125 WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev->name, cur_state));
23126 if (cur_state > WPS_STATE_IDLE) {
23127 wl_wps_session_del(ndev);
23128 }
23129 }
23130
23131 static s32
wl_wps_handle_sta_linkdown(struct net_device * ndev,u16 inst)23132 wl_wps_handle_sta_linkdown(struct net_device *ndev, u16 inst)
23133 {
23134 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23135 unsigned long flags;
23136 u16 cur_state;
23137 bool wps_done = false;
23138
23139 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23140 cur_state = cfg->wps_session[inst].state;
23141 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23142 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23143 wl_clr_drv_status(cfg, CONNECTED, ndev);
23144 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
23145 WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev->name));
23146 /* Drop the link down event while we are waiting for reauth */
23147 return BCME_UNSUPPORTED;
23148 } else if (cur_state == WPS_STATE_STARTED) {
23149 /* Link down before reaching EAP-FAIL. End WPS session */
23150 cfg->wps_session[inst].state = WPS_STATE_DONE;
23151 wps_done = true;
23152 WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev->name));
23153 } else {
23154 WL_DBG(("[%s][WPS] link down in state:%d\n",
23155 ndev->name, cur_state));
23156 }
23157
23158 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23159
23160 if (wps_done) {
23161 wl_wps_session_del(ndev);
23162 }
23163 return BCME_OK;
23164 }
23165
23166 static s32
wl_wps_handle_peersta_linkdown(struct net_device * ndev,u16 inst,const u8 * peer_mac)23167 wl_wps_handle_peersta_linkdown(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23168 {
23169 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23170 unsigned long flags;
23171 u16 cur_state;
23172 s32 ret = BCME_OK;
23173 bool wps_done = false;
23174
23175 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23176 cur_state = cfg->wps_session[inst].state;
23177
23178 if (!peer_mac) {
23179 WL_ERR(("Invalid arg\n"));
23180 ret = BCME_ERROR;
23181 goto exit;
23182 }
23183
23184 /* AP/GO can have multiple clients. so validate peer_mac addr
23185 * and ensure states are updated only for right peer.
23186 */
23187 if (memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23188 /* Mac addr not matching. Ignore. */
23189 WL_DBG(("[%s][WPS] No active WPS session"
23190 "for the peer:" MACDBG "\n", ndev->name, MAC2STRDBG(peer_mac)));
23191 ret = BCME_OK;
23192 goto exit;
23193 }
23194 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23195 WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
23196 " Peer: " MACDBG "\n",
23197 ndev->name, MAC2STRDBG(peer_mac)));
23198 #ifdef NOT_YET
23199 /* Link down during REAUTH state is expected. However,
23200 * if this is send up, hostapd statemachine issues a
23201 * deauth down and that may pre-empt WPS reauth state
23202 * at GC.
23203 */
23204 WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore."
23205 " for client:" MACDBG "\n",
23206 ndev->name, MAC2STRDBG(peer_mac)));
23207 ret = BCME_UNSUPPORTED;
23208 #endif // endif
23209 } else if (cur_state == WPS_STATE_STARTED) {
23210 /* Link down before reaching REAUTH_WAIT state. WPS
23211 * session ended.
23212 */
23213 cfg->wps_session[inst].state = WPS_STATE_DONE;
23214 WL_INFORM_MEM(("[%s][WPS] link down after wps start"
23215 " client:" MACDBG "\n",
23216 ndev->name, MAC2STRDBG(peer_mac)));
23217 wps_done = true;
23218 /* since we have freed lock above, return from here */
23219 ret = BCME_OK;
23220 } else {
23221 WL_ERR(("[%s][WPS] Unsupported state:%d",
23222 ndev->name, cur_state));
23223 ret = BCME_ERROR;
23224 }
23225 exit:
23226 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23227 if (wps_done) {
23228 wl_wps_session_del(ndev);
23229 }
23230 return ret;
23231 }
23232
23233 static s32
wl_wps_handle_sta_linkup(struct net_device * ndev,u16 inst)23234 wl_wps_handle_sta_linkup(struct net_device *ndev, u16 inst)
23235 {
23236 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23237 unsigned long flags;
23238 u16 cur_state;
23239 s32 ret = BCME_OK;
23240 bool wps_done = false;
23241
23242 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23243 cur_state = cfg->wps_session[inst].state;
23244 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23245 /* WPS session succeeded. del session. */
23246 cfg->wps_session[inst].state = WPS_STATE_DONE;
23247 wps_done = true;
23248 WL_INFORM_MEM(("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev->name));
23249 ret = BCME_OK;
23250 } else {
23251 WL_ERR(("[%s][WPS] unexpected link up in state:%d \n",
23252 ndev->name, cur_state));
23253 ret = BCME_ERROR;
23254 }
23255 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23256 if (wps_done) {
23257 wl_wps_session_del(ndev);
23258 }
23259 return ret;
23260 }
23261
23262 static s32
wl_wps_handle_peersta_linkup(struct net_device * ndev,u16 inst,const u8 * peer_mac)23263 wl_wps_handle_peersta_linkup(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23264 {
23265 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23266 unsigned long flags;
23267 u16 cur_state;
23268 s32 ret = BCME_OK;
23269
23270 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23271 cur_state = cfg->wps_session[inst].state;
23272
23273 /* For AP case, check whether call came for right peer */
23274 if (!peer_mac ||
23275 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23276 WL_ERR(("[WPS] macaddr mismatch\n"));
23277 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23278 /* Mac addr not matching. Ignore. */
23279 return BCME_ERROR;
23280 }
23281
23282 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23283 WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev->name));
23284 ret = BCME_OK;
23285 } else {
23286 WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
23287 ndev->name, cur_state));
23288 ret = BCME_ERROR;
23289 }
23290
23291 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23292
23293 return ret;
23294 }
23295
23296 static s32
wl_wps_handle_authorize(struct net_device * ndev,u16 inst,const u8 * peer_mac)23297 wl_wps_handle_authorize(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23298 {
23299 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23300 unsigned long flags;
23301 u16 cur_state;
23302 bool wps_done = false;
23303 s32 ret = BCME_OK;
23304
23305 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23306 cur_state = cfg->wps_session[inst].state;
23307
23308 /* For AP case, check whether call came for right peer */
23309 if (!peer_mac ||
23310 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23311 WL_ERR(("[WPS] macaddr mismatch\n"));
23312 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23313 /* Mac addr not matching. Ignore. */
23314 return BCME_ERROR;
23315 }
23316
23317 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23318 /* WPS session succeeded. del session. */
23319 cfg->wps_session[inst].state = WPS_STATE_DONE;
23320 wps_done = true;
23321 WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev->name));
23322 ret = BCME_OK;
23323 } else {
23324 WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
23325 ndev->name, cur_state));
23326 ret = BCME_ERROR;
23327 }
23328
23329 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23330 if (wps_done) {
23331 wl_wps_session_del(ndev);
23332 }
23333 return ret;
23334 }
23335
23336 static s32
wl_wps_handle_reauth(struct net_device * ndev,u16 inst,const u8 * peer_mac)23337 wl_wps_handle_reauth(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23338 {
23339 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23340 unsigned long flags;
23341 u16 cur_state;
23342 u16 mode;
23343 s32 ret = BCME_OK;
23344
23345 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23346 cur_state = cfg->wps_session[inst].state;
23347 mode = cfg->wps_session[inst].mode;
23348
23349 if (((mode == WL_MODE_BSS) && (cur_state == WPS_STATE_STARTED)) ||
23350 ((mode == WL_MODE_AP) && (cur_state == WPS_STATE_M8_SENT))) {
23351 /* Move to reauth wait */
23352 cfg->wps_session[inst].state = WPS_STATE_REAUTH_WAIT;
23353 /* Use ndev to find the wps instance which fired the timer */
23354 timer_set_private(&cfg->wps_session[inst].timer, ndev);
23355 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23356 mod_timer(&cfg->wps_session[inst].timer,
23357 jiffies + msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT));
23358 WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG "\n",
23359 ndev->name, mode, MAC2STRDBG(peer_mac)));
23360 return BCME_OK;
23361 } else {
23362 /* 802.1x cases */
23363 WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev->name));
23364 }
23365 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23366 return ret;
23367 }
23368
23369 static s32
wl_wps_handle_disconnect(struct net_device * ndev,u16 inst,const u8 * peer_mac)23370 wl_wps_handle_disconnect(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23371 {
23372 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23373 unsigned long flags;
23374 u16 cur_state;
23375 s32 ret = BCME_OK;
23376
23377 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23378 cur_state = cfg->wps_session[inst].state;
23379 /* If Disconnect command comes from user space for STA/GC,
23380 * respond with event without waiting for event from fw as
23381 * it would be dropped by the WPS_SYNC code.
23382 */
23383 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23384 if (ETHER_ISBCAST(peer_mac)) {
23385 WL_DBG(("[WPS] Bcast peer. Do nothing.\n"));
23386 } else {
23387 /* Notify link down */
23388 CFG80211_DISCONNECTED(ndev,
23389 WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
23390 true, GFP_ATOMIC);
23391 }
23392 } else {
23393 WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
23394 ndev->name, cur_state));
23395 ret = BCME_UNSUPPORTED;
23396 }
23397 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23398 return ret;
23399 }
23400
23401 static s32
wl_wps_handle_disconnect_client(struct net_device * ndev,u16 inst,const u8 * peer_mac)23402 wl_wps_handle_disconnect_client(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23403 {
23404 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23405 unsigned long flags;
23406 u16 cur_state;
23407 s32 ret = BCME_OK;
23408 bool wps_done = false;
23409
23410 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23411 cur_state = cfg->wps_session[inst].state;
23412 /* For GO/AP, ignore disconnect client during reauth state */
23413 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23414 if (ETHER_ISBCAST(peer_mac)) {
23415 /* If there is broadcast deauth, then mark wps session as ended */
23416 cfg->wps_session[inst].state = WPS_STATE_DONE;
23417 wps_done = true;
23418 WL_INFORM_MEM(("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev->name));
23419 ret = BCME_OK;
23420 goto exit;
23421 } else if (!(memcmp(cfg->wps_session[inst].peer_mac,
23422 peer_mac, ETH_ALEN))) {
23423 WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev->name));
23424 ret = BCME_UNSUPPORTED;
23425 }
23426 }
23427
23428 exit:
23429 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23430 if (wps_done) {
23431 wl_wps_session_del(ndev);
23432 }
23433 return ret;
23434 }
23435
23436 static s32
wl_wps_handle_connect_fail(struct net_device * ndev,u16 inst)23437 wl_wps_handle_connect_fail(struct net_device *ndev, u16 inst)
23438 {
23439 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23440 unsigned long flags;
23441 u16 cur_state;
23442 bool wps_done = false;
23443
23444 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23445 cur_state = cfg->wps_session[inst].state;
23446 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23447 cfg->wps_session[inst].state = WPS_STATE_DONE;
23448 wps_done = true;
23449 WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n",
23450 ndev->name));
23451 } else {
23452 WL_ERR(("[%s][WPS] Connect fail. state:%d\n",
23453 ndev->name, cur_state));
23454 }
23455 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23456 if (wps_done) {
23457 wl_wps_session_del(ndev);
23458 }
23459 return BCME_OK;
23460 }
23461
23462 static s32
wl_wps_handle_m8_sent(struct net_device * ndev,u16 inst,const u8 * peer_mac)23463 wl_wps_handle_m8_sent(struct net_device *ndev, u16 inst, const u8 *peer_mac)
23464 {
23465 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23466 unsigned long flags;
23467 u16 cur_state;
23468 s32 ret = BCME_OK;
23469
23470 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23471 cur_state = cfg->wps_session[inst].state;
23472
23473 if (cur_state == WPS_STATE_STARTED) {
23474 /* Move to M8 sent state */
23475 cfg->wps_session[inst].state = WPS_STATE_M8_SENT;
23476 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23477 return BCME_OK;
23478 } else {
23479 /* 802.1x cases */
23480 WL_DBG(("[%s][WPS] Not valid state to send M8\n", ndev->name));
23481 }
23482 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23483 return ret;
23484 }
23485
23486 static s32
wl_wps_session_update(struct net_device * ndev,u16 state,const u8 * peer_mac)23487 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac)
23488 {
23489 s32 inst;
23490 u16 mode;
23491 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23492 s32 ret = BCME_ERROR;
23493 unsigned long flags;
23494
23495 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23496 /* Get current instance for the given ndev */
23497 inst = wl_get_wps_inst_match(cfg, ndev);
23498 if (inst == BCME_ERROR) {
23499 /* No active WPS session. Do Nothing. */
23500 WL_DBG(("[%s][WPS] No matching instance.\n", ndev->name));
23501 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23502 return BCME_NOTFOUND;
23503 }
23504 mode = cfg->wps_session[inst].mode;
23505 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23506
23507 WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG "\n",
23508 ndev->name, state, mode, MAC2STRDBG(peer_mac)));
23509
23510 switch (state) {
23511 case WPS_STATE_M8_RECVD:
23512 {
23513 /* Occasionally, due to race condition between ctrl
23514 * and data path, deauth ind is recvd before EAP-FAIL.
23515 * Ignore deauth ind before EAP-FAIL
23516 * So move to REAUTH WAIT on receiving M8 on GC and
23517 * ignore deauth ind before EAP-FAIL till 'x' timeout.
23518 * Kickoff a timer to monitor reauth status.
23519 */
23520 if (mode == WL_MODE_BSS) {
23521 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
23522 } else {
23523 /* Nothing to be done for AP/GO mode */
23524 ret = BCME_OK;
23525 }
23526 break;
23527 }
23528 case WPS_STATE_M8_SENT:
23529 {
23530 /* Mantain the M8 sent state to verify
23531 * EAP-FAIL sent is valid
23532 */
23533 if (mode == WL_MODE_AP) {
23534 ret = wl_wps_handle_m8_sent(ndev, inst, peer_mac);
23535 } else {
23536 /* Nothing to be done for STA/GC mode */
23537 ret = BCME_OK;
23538 }
23539 break;
23540 }
23541 case WPS_STATE_EAP_FAIL:
23542 {
23543 /* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
23544 * Kickoff a timer to monitor reauth status
23545 */
23546 if (mode == WL_MODE_AP) {
23547 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
23548 } else {
23549 /* Nothing to be done for STA/GC mode */
23550 ret = BCME_OK;
23551 }
23552 break;
23553 }
23554 case WPS_STATE_LINKDOWN:
23555 {
23556 if (mode == WL_MODE_BSS) {
23557 ret = wl_wps_handle_sta_linkdown(ndev, inst);
23558 } else if (mode == WL_MODE_AP) {
23559 /* Take action only for matching peer mac */
23560 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23561 ret = wl_wps_handle_peersta_linkdown(ndev, inst, peer_mac);
23562 }
23563 }
23564 break;
23565 }
23566 case WPS_STATE_LINKUP:
23567 {
23568 if (mode == WL_MODE_BSS) {
23569 wl_wps_handle_sta_linkup(ndev, inst);
23570 } else if (mode == WL_MODE_AP) {
23571 /* Take action only for matching peer mac */
23572 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23573 wl_wps_handle_peersta_linkup(ndev, inst, peer_mac);
23574 }
23575 }
23576 break;
23577 }
23578 case WPS_STATE_DISCONNECT_CLIENT:
23579 {
23580 /* Disconnect STA/GC command from user space */
23581 if (mode == WL_MODE_AP) {
23582 ret = wl_wps_handle_disconnect_client(ndev, inst, peer_mac);
23583 } else {
23584 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
23585 }
23586 break;
23587 }
23588 case WPS_STATE_DISCONNECT:
23589 {
23590 /* Disconnect command on STA/GC interface */
23591 if (mode == WL_MODE_BSS) {
23592 ret = wl_wps_handle_disconnect(ndev, inst, peer_mac);
23593 }
23594 break;
23595 }
23596 case WPS_STATE_CONNECT_FAIL:
23597 {
23598 if (mode == WL_MODE_BSS) {
23599 ret = wl_wps_handle_connect_fail(ndev, inst);
23600 } else {
23601 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
23602 }
23603 break;
23604 }
23605 case WPS_STATE_AUTHORIZE:
23606 {
23607 if (mode == WL_MODE_AP) {
23608 /* Take action only for matching peer mac */
23609 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23610 wl_wps_handle_authorize(ndev, inst, peer_mac);
23611 } else {
23612 WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
23613 }
23614 }
23615 break;
23616 }
23617
23618 default:
23619 WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state, mode));
23620 ret = BCME_ERROR;
23621 }
23622
23623 return ret;
23624 }
23625
23626 #define EAP_EXP_ATTRIB_DATA_OFFSET 14
23627 void
wl_handle_wps_states(struct net_device * ndev,u8 * pkt,u16 len,bool direction)23628 wl_handle_wps_states(struct net_device *ndev, u8 *pkt, u16 len, bool direction)
23629 {
23630 eapol_header_t *eapol_hdr;
23631 bool tx_packet = direction;
23632 u16 eapol_type;
23633 u16 mode;
23634 u8 *peer_mac;
23635
23636 if (!ndev || !pkt) {
23637 WL_ERR(("[WPS] Invalid arg\n"));
23638 return;
23639 }
23640
23641 if (len < (ETHER_HDR_LEN + EAPOL_HDR_LEN)) {
23642 WL_ERR(("[WPS] Invalid len\n"));
23643 return;
23644 }
23645
23646 eapol_hdr = (eapol_header_t *)pkt;
23647 eapol_type = eapol_hdr->type;
23648
23649 peer_mac = tx_packet ? eapol_hdr->eth.ether_dhost :
23650 eapol_hdr->eth.ether_shost;
23651 /*
23652 * The implementation assumes only one WPS session would be active
23653 * per interface at a time. Even for hostap, the wps_pin session
23654 * is limited to one enrollee/client at a time. A session is marked
23655 * started on WSC_START and gets cleared from below contexts
23656 * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
23657 * b) Link up following EAP-FAIL. (success case)
23658 * c) Link up timeout after EAP-FAIL. (Fail case)
23659 */
23660
23661 if (eapol_type == EAP_PACKET) {
23662 wl_eap_header_t *eap;
23663
23664 if (len > sizeof(*eap)) {
23665 eap = (wl_eap_header_t *)(pkt + ETHER_HDR_LEN + EAPOL_HDR_LEN);
23666 if (eap->type == EAP_EXPANDED_TYPE) {
23667 wl_eap_exp_t *exp = (wl_eap_exp_t *)eap->data;
23668 if (eap->length > EAP_EXP_HDR_MIN_LENGTH) {
23669 /* opcode is at fixed offset */
23670 u8 opcode = exp->opcode;
23671 u16 eap_len = ntoh16(eap->length);
23672
23673 WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
23674 ndev->name, opcode, eap_len));
23675 if (opcode == EAP_WSC_MSG) {
23676 const u8 *msg;
23677 const u8* parse_buf = exp->data;
23678 /* Check if recvd pkt is fragmented */
23679 if ((!tx_packet) &&
23680 (exp->flags &
23681 EAP_EXP_FLAGS_FRAGMENTED_DATA)) {
23682 if ((eap_len - EAP_EXP_ATTRIB_DATA_OFFSET)
23683 > 2) {
23684 parse_buf +=
23685 EAP_EXP_FRAGMENT_LEN_OFFSET;
23686 eap_len -=
23687 EAP_EXP_FRAGMENT_LEN_OFFSET;
23688 WL_DBG(("Rcvd EAP"
23689 " fragmented pkt\n"));
23690 } else {
23691 /* If recvd pkt is fragmented
23692 * and does not have
23693 * length field drop the packet.
23694 */
23695 return;
23696 }
23697 }
23698
23699 msg = wl_find_attribute(parse_buf,
23700 (eap_len - EAP_EXP_ATTRIB_DATA_OFFSET),
23701 EAP_ATTRIB_MSGTYPE);
23702 if (unlikely(!msg)) {
23703 WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
23704 } else if ((*msg == EAP_WSC_MSG_M8) &&
23705 !tx_packet) {
23706 WL_INFORM_MEM(("[%s][WPS] M8\n",
23707 ndev->name));
23708 wl_wps_session_update(ndev,
23709 WPS_STATE_M8_RECVD, peer_mac);
23710 } else if ((*msg == EAP_WSC_MSG_M8) &&
23711 tx_packet) {
23712 WL_INFORM_MEM(("[%s][WPS] M8 Sent\n",
23713 ndev->name));
23714 wl_wps_session_update(ndev,
23715 WPS_STATE_M8_SENT, peer_mac);
23716 } else {
23717 WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n",
23718 ndev->name, *msg));
23719 }
23720 } else if (opcode == EAP_WSC_START) {
23721 /* WSC session started. WSC_START - Tx from GO/AP.
23722 * Session will be deleted on successful link up or
23723 * on failure (deauth context)
23724 */
23725 mode = tx_packet ? WL_MODE_AP : WL_MODE_BSS;
23726 wl_wps_session_add(ndev, mode, peer_mac);
23727 WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
23728 ndev->name, mode));
23729 } else if (opcode == EAP_WSC_DONE) {
23730 /* WSC session done. TX on STA/GC. RX on GO/AP
23731 * On devices where config file save fails, it may
23732 * return WPS_NAK with config_error:0. But the
23733 * connection would still proceed. Hence don't let
23734 * state machine depend on WSC DONE.
23735 */
23736 WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev->name));
23737 }
23738 }
23739 }
23740
23741 if (eap->code == EAP_CODE_FAILURE) {
23742 /* EAP_FAIL */
23743 WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev->name));
23744 wl_wps_session_update(ndev,
23745 WPS_STATE_EAP_FAIL, peer_mac);
23746 }
23747 }
23748 }
23749 }
23750 #endif /* WL_WPS_SYNC */
23751
23752 s32
wl_cfg80211_sup_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * event,void * data)23753 wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23754 const wl_event_msg_t *event, void *data)
23755 {
23756 int err = BCME_OK;
23757 u32 status = ntoh32(event->status);
23758 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
23759 u32 reason = ntoh32(event->reason);
23760
23761 if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
23762 /* Join attempt via non-cfg80211 interface.
23763 * Don't send resultant events to cfg80211
23764 * layer
23765 */
23766 WL_INFORM_MEM(("Event received in non-cfg80211"
23767 " connect state. Ignore\n"));
23768 return BCME_OK;
23769 }
23770
23771 if ((status == WLC_SUP_KEYED || status == WLC_SUP_KEYXCHANGE_WAIT_G1) &&
23772 reason == WLC_E_SUP_OTHER) {
23773 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
23774 /* NL80211_CMD_PORT_AUTHORIZED supported above >= 4.15 */
23775 cfg80211_port_authorized(ndev, (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID),
23776 GFP_KERNEL);
23777 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
23778 #elif ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
23779 defined(WL_VENDOR_EXT_SUPPORT))
23780 err = wl_cfgvendor_send_async_event(bcmcfg_to_wiphy(cfg), ndev,
23781 BRCM_VENDOR_EVENT_PORT_AUTHORIZED, NULL, 0);
23782 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
23783 #else
23784 /* not supported in kernel <= 3,14,0 */
23785 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */
23786 } else if (status < WLC_SUP_KEYXCHANGE_WAIT_G1 && (reason != WLC_E_SUP_OTHER &&
23787 reason != WLC_E_SUP_PTK_UPDATE)) {
23788 /* if any failure seen while 4way HS, should send NL80211_CMD_DISCONNECT */
23789 WL_ERR(("4way HS error. status:%d, reason:%d\n", status, reason));
23790 CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
23791 }
23792
23793 return err;
23794 }
23795
23796 #ifdef WL_BCNRECV
23797 static s32
wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23798 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23799 const wl_event_msg_t *e, void *data)
23800 {
23801 s32 status = ntoh32(e->status);
23802 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
23803 /* Abort fakeapscan, when Roam is in progress */
23804 if (status == WLC_E_STATUS_RXBCN_ABORT) {
23805 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_ROAMABORT);
23806 } else {
23807 WL_ERR(("UNKNOWN STATUS. status:%d\n", status));
23808 }
23809 return BCME_OK;
23810 }
23811 #endif /* WL_BCNRECV */
23812
23813 #ifdef WL_MBO
23814 static s32
wl_mbo_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23815 wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23816 const wl_event_msg_t *e, void *data)
23817 {
23818 s32 err = 0;
23819 wl_event_mbo_t *mbo_evt = (wl_event_mbo_t *)data;
23820 wl_event_mbo_cell_nw_switch_t *cell_sw_evt = NULL;
23821 wl_btm_event_type_data_t *evt_data = NULL;
23822
23823 WL_INFORM(("MBO: Evt %u\n", mbo_evt->type));
23824
23825 if (mbo_evt->type == WL_MBO_E_CELLULAR_NW_SWITCH) {
23826 cell_sw_evt = (wl_event_mbo_cell_nw_switch_t *)mbo_evt->data;
23827 BCM_REFERENCE(cell_sw_evt);
23828 SUPP_EVENT(("CTRL-EVENT-CELLULAR-SWITCH", "reason %d cur_assoc_time_left %u "
23829 "reassoc_delay %u\n", cell_sw_evt->reason,
23830 cell_sw_evt->assoc_time_remain, cell_sw_evt->reassoc_delay));
23831 } else if (mbo_evt->type == WL_MBO_E_BTM_RCVD) {
23832 evt_data = (wl_btm_event_type_data_t *)mbo_evt->data;
23833 if (evt_data->version != WL_BTM_EVENT_DATA_VER_1) {
23834 WL_ERR(("version mismatch. rcvd %u expected %u\n",
23835 evt_data->version, WL_BTM_EVENT_DATA_VER_1));
23836 return -1;
23837 }
23838 SUPP_EVENT(("CTRL-EVENT-BRCM-BTM-REQ-RCVD", "reason=%u\n",
23839 evt_data->transition_reason));
23840 } else {
23841 WL_INFORM(("UNKNOWN EVENT. type:%u\n", mbo_evt->type));
23842 }
23843 return err;
23844 }
23845 #endif /* WL_MBO */
23846
23847 #ifdef WL_CAC_TS
23848 static s32
wl_cfg80211_cac_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23849 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23850 const wl_event_msg_t *e, void *data)
23851 {
23852 u32 event = ntoh32(e->event_type);
23853 s32 status = ntoh32(e->status);
23854 s32 reason = ntoh32(e->reason);
23855
23856 BCM_REFERENCE(reason);
23857
23858 if (event == WLC_E_ADDTS_IND) {
23859 /* The supp log format of adding ts_delay in success case needs to be maintained */
23860 if (status == WLC_E_STATUS_SUCCESS) {
23861 uint *ts_delay = (uint *)data;
23862 BCM_REFERENCE(ts_delay);
23863 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d ts_delay=%u\n",
23864 status, reason, *ts_delay));
23865 } else {
23866 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d\n",
23867 status, reason));
23868 }
23869 } else if (event == WLC_E_DELTS_IND) {
23870 SUPP_EVENT(("CTRL-EVENT-CAC-DELTS", "status=%d reason=%d\n", status, reason));
23871 }
23872
23873 return BCME_OK;
23874 }
23875 #endif /* WL_CAC_TS */
23876
23877 #if defined(WL_MBO) || defined(WL_OCE)
23878 static s32
wl_bssid_prune_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23879 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23880 const wl_event_msg_t *e, void *data)
23881 {
23882 s32 err = 0;
23883 uint reason = 0;
23884 wl_bssid_pruned_evt_info_t *evt_info = (wl_bssid_pruned_evt_info_t *)data;
23885
23886 if (evt_info->version == WL_BSSID_PRUNE_EVT_VER_1) {
23887 if (evt_info->reason == WLC_E_PRUNE_ASSOC_RETRY_DELAY) {
23888 /* MBO assoc retry delay */
23889 reason = WIFI_PRUNE_ASSOC_RETRY_DELAY;
23890 SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
23891 " reason=%u timeout_val=%u(ms)\n", evt_info->SSID,
23892 ETHER_TO_MACF(evt_info->BSSID), reason, evt_info->time_remaining));
23893 } else if (evt_info->reason == WLC_E_PRUNE_RSSI_ASSOC_REJ) {
23894 /* OCE RSSI-based assoc rejection */
23895 reason = WIFI_PRUNE_RSSI_ASSOC_REJ;
23896 SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
23897 " reason=%u timeout_val=%u(ms) rssi_threshold=%d(dBm)\n",
23898 evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID),
23899 reason, evt_info->time_remaining, evt_info->rssi_threshold));
23900 } else {
23901 /* Invalid other than the assoc retry delay/RSSI assoc rejection
23902 * in the current handler
23903 */
23904 BCM_REFERENCE(reason);
23905 WL_INFORM(("INVALID. reason:%u\n", evt_info->reason));
23906 }
23907 } else {
23908 WL_INFORM(("version mismatch. rcvd %u expected %u\n", evt_info->version,
23909 WL_BSSID_PRUNE_EVT_VER_1));
23910 }
23911 return err;
23912 }
23913 #endif /* WL_MBO || WL_OCE */
23914 #ifdef RTT_SUPPORT
23915 static s32
wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23916 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23917 const wl_event_msg_t *e, void *data)
23918 {
23919 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
23920 wl_event_msg_t event;
23921
23922 (void)memcpy_s(&event, sizeof(wl_event_msg_t),
23923 e, sizeof(wl_event_msg_t));
23924 return dhd_rtt_event_handler(dhdp, &event, data);
23925 }
23926 #endif /* RTT_SUPPORT */
23927
23928 void
wl_print_verinfo(struct bcm_cfg80211 * cfg)23929 wl_print_verinfo(struct bcm_cfg80211 *cfg)
23930 {
23931 char *ver_ptr;
23932 uint32 alloc_len = MOD_PARAM_INFOLEN;
23933
23934 if (!cfg) {
23935 WL_ERR(("cfg is NULL\n"));
23936 return;
23937 }
23938
23939 ver_ptr = (char *)MALLOCZ(cfg->osh, alloc_len);
23940 if (!ver_ptr) {
23941 WL_ERR(("Failed to alloc ver_ptr\n"));
23942 return;
23943 }
23944
23945 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
23946 TRUE, &ver_ptr, alloc_len)) {
23947 WL_ERR(("DHD Version: %s\n", ver_ptr));
23948 }
23949
23950 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
23951 FALSE, &ver_ptr, alloc_len)) {
23952 WL_ERR(("F/W Version: %s\n", ver_ptr));
23953 }
23954
23955 MFREE(cfg->osh, ver_ptr, alloc_len);
23956 }
23957 #if defined(WL_DISABLE_HE_SOFTAP) || defined(WL_DISABLE_HE_P2P)
23958 typedef struct {
23959 uint16 id;
23960 uint16 len;
23961 uint32 val;
23962 } he_xtlv_v32;
23963
23964 static bool
wl_he_get_uint_cb(void * ctx,uint16 * id,uint16 * len)23965 wl_he_get_uint_cb(void *ctx, uint16 *id, uint16 *len)
23966 {
23967 he_xtlv_v32 *v32 = ctx;
23968
23969 *id = v32->id;
23970 *len = v32->len;
23971
23972 return FALSE;
23973 }
23974
23975 static void
wl_he_pack_uint_cb(void * ctx,uint16 id,uint16 len,uint8 * buf)23976 wl_he_pack_uint_cb(void *ctx, uint16 id, uint16 len, uint8 *buf)
23977 {
23978 he_xtlv_v32 *v32 = ctx;
23979
23980 BCM_REFERENCE(id);
23981 BCM_REFERENCE(len);
23982
23983 v32->val = htod32(v32->val);
23984
23985 switch (v32->len) {
23986 case sizeof(uint8):
23987 *buf = (uint8)v32->val;
23988 break;
23989 case sizeof(uint16):
23990 store16_ua(buf, (uint16)v32->val);
23991 break;
23992 case sizeof(uint32):
23993 store32_ua(buf, v32->val);
23994 break;
23995 default:
23996 /* ASSERT(0); */
23997 break;
23998 }
23999 }
24000
wl_cfg80211_set_he_mode(struct net_device * dev,struct bcm_cfg80211 * cfg,s32 bssidx,u32 interface_type,bool set)24001 int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg,
24002 s32 bssidx, u32 interface_type, bool set)
24003 {
24004 bcm_xtlv_t read_he_xtlv;
24005 uint8 se_he_xtlv[32];
24006 int se_he_xtlv_len = sizeof(se_he_xtlv);
24007 he_xtlv_v32 v32;
24008 u32 he_feature = 0;
24009 s32 err = 0;
24010 u32 he_interface = 0;
24011
24012 read_he_xtlv.id = WL_HE_CMD_FEATURES;
24013 read_he_xtlv.len = 0;
24014 err = wldev_iovar_getbuf_bsscfg(dev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
24015 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, NULL);
24016 if (err < 0) {
24017 if (err == BCME_UNSUPPORTED) {
24018 /* HE not supported. Do nothing. */
24019 return BCME_OK;
24020 }
24021 WL_ERR(("HE get failed. error=%d\n", err));
24022 } else {
24023 he_feature = *(int*)cfg->ioctl_buf;
24024 he_feature = dtoh32(he_feature);
24025 }
24026
24027 v32.id = WL_HE_CMD_FEATURES;
24028 v32.len = sizeof(s32);
24029 if (interface_type == WL_IF_TYPE_P2P_DISC) {
24030 he_interface = WL_HE_FEATURES_HE_P2P;
24031 } else if (interface_type == WL_IF_TYPE_AP) {
24032 he_interface = WL_HE_FEATURES_HE_AP;
24033 } else {
24034 WL_ERR(("HE request for Invalid interface type"));
24035 err = BCME_BADARG;
24036 return err;
24037 }
24038
24039 if (set) {
24040 v32.val = (he_feature | he_interface);
24041 } else {
24042 v32.val = (he_feature & ~he_interface);
24043 }
24044
24045 err = bcm_pack_xtlv_buf((void *)&v32, se_he_xtlv, sizeof(se_he_xtlv),
24046 BCM_XTLV_OPTION_ALIGN32, wl_he_get_uint_cb, wl_he_pack_uint_cb,
24047 &se_he_xtlv_len);
24048 if (err != BCME_OK) {
24049 WL_ERR(("failed to pack he settvl=%d\n", err));
24050 }
24051
24052 err = wldev_iovar_setbuf_bsscfg(dev, "he", &se_he_xtlv, sizeof(se_he_xtlv),
24053 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
24054 if (err < 0) {
24055 WL_ERR(("failed to set he features, error=%d\n", err));
24056 }
24057 WL_INFORM(("Set HE[%d] done\n", set));
24058
24059 return err;
24060 }
24061 #endif /* WL_DISABLE_HE_SOFTAP || WL_DISABLE_HE_P2P */
24062
24063 /* Get the concurrency mode */
wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 * cfg)24064 int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg)
24065 {
24066 struct net_info *iter, *next;
24067 uint cmode = CONCURRENCY_MODE_NONE;
24068 u32 connected_cnt = 0;
24069 u32 pre_channel = 0, channel = 0;
24070 u32 pre_band = 0;
24071 u32 chanspec = 0;
24072 u32 band = 0;
24073
24074 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
24075 if (connected_cnt <= 1) {
24076 return cmode;
24077 }
24078 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
24079 for_each_ndev(cfg, iter, next) {
24080 if (iter->ndev) {
24081 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
24082 if (wldev_iovar_getint(iter->ndev, "chanspec",
24083 (s32 *)&chanspec) == BCME_OK) {
24084 channel = wf_chspec_ctlchan(
24085 wl_chspec_driver_to_host(chanspec));
24086 band = (channel <= CH_MAX_2G_CHANNEL) ?
24087 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
24088 }
24089 if ((!pre_channel && channel)) {
24090 pre_band = band;
24091 pre_channel = channel;
24092 } else if (pre_channel) {
24093 if ((pre_band == band) && (pre_channel == channel)) {
24094 cmode = CONCURRENCY_SCC_MODE;
24095 goto exit;
24096 } else if ((pre_band == band) && (pre_channel != channel)) {
24097 cmode = CONCURRENCY_VSDB_MODE;
24098 goto exit;
24099 } else if (pre_band != band) {
24100 cmode = CONCURRENCY_RSDB_MODE;
24101 goto exit;
24102 }
24103 }
24104 }
24105 }
24106 }
24107 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
24108 4 && __GNUC_MINOR__ >= 6))
24109 _Pragma("GCC diagnostic pop")
24110 #endif // endif
24111 exit:
24112 return cmode;
24113 }
24114 #ifdef WL_CHAN_UTIL
24115 static s32
wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)24116 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
24117 const wl_event_msg_t *e, void *data)
24118 {
24119 s32 err = BCME_OK;
24120 struct sk_buff *skb = NULL;
24121 s32 status = ntoh32(e->status);
24122 u8 chan_use_percentage = 0;
24123 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
24124 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
24125 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
24126 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
24127 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
24128 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24129 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
24130 uint len;
24131 gfp_t kflags;
24132 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24133
24134 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24135 len = CU_ATTR_HDR_LEN + sizeof(u8);
24136 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
24137 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24138
24139 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
24140 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
24141 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), len,
24142 BRCM_VENDOR_EVENT_CU, kflags);
24143 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24144 skb = cfg80211_vendor_event_alloc(wiphy, len, BRCM_VENDOR_EVENT_CU, kflags);
24145 #else
24146 /* No support exist */
24147 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
24148 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
24149 if (!skb) {
24150 WL_ERR(("skb alloc failed"));
24151 return -ENOMEM;
24152 }
24153
24154 if ((status == WLC_E_STATUS_SUCCESS) && data) {
24155 wl_bssload_t *bssload_report = (wl_bssload_t *)data;
24156 chan_use_percentage = (bssload_report->chan_util * 100) / 255;
24157 WL_DBG(("ChannelUtilization=%hhu\n", chan_use_percentage));
24158 err = nla_put_u8(skb, CU_ATTR_PERCENTAGE, chan_use_percentage);
24159 if (err < 0) {
24160 WL_ERR(("Failed to put CU_ATTR_PERCENTAGE, err:%d\n", err));
24161 }
24162 }
24163
24164 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24165 cfg80211_vendor_event(skb, kflags);
24166 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24167
24168 return err;
24169 }
24170
24171 #define WL_CHAN_UTIL_DEFAULT_INTERVAL 3000
24172 #define WL_CHAN_UTIL_THRESH_MIN 15
24173 #define WL_CHAN_UTIL_THRESH_INTERVAL 10
24174 #ifndef CUSTOM_CU_INTERVAL
24175 #define CUSTOM_CU_INTERVAL WL_CHAN_UTIL_DEFAULT_INTERVAL
24176 #endif /* CUSTOM_CU_INTERVAL */
24177
24178 static s32
wl_cfg80211_start_bssload_report(struct net_device * ndev)24179 wl_cfg80211_start_bssload_report(struct net_device *ndev)
24180 {
24181 s32 err = BCME_OK;
24182 wl_bssload_cfg_t blcfg;
24183 u8 i;
24184 struct bcm_cfg80211 *cfg;
24185
24186 if (!ndev) {
24187 return -ENODEV;
24188 }
24189
24190 cfg = wl_get_cfg(ndev);
24191 if (!cfg) {
24192 return -ENODEV;
24193 }
24194
24195 /* Typecasting to void as the buffer size is same as the memset size */
24196 (void)memset_s(&blcfg, sizeof(wl_bssload_cfg_t), 0, sizeof(wl_bssload_cfg_t));
24197 /* Set default report interval 3 sec and 8 threshhold levels between 15 to 85% */
24198 blcfg.rate_limit_msec = CUSTOM_CU_INTERVAL;
24199 blcfg.num_util_levels = MAX_BSSLOAD_LEVELS;
24200 for (i = 0; i < MAX_BSSLOAD_LEVELS; i++) {
24201 blcfg.util_levels[i] = (((WL_CHAN_UTIL_THRESH_MIN +
24202 (i * WL_CHAN_UTIL_THRESH_INTERVAL)) * 255) / 100);
24203 }
24204
24205 err = wldev_iovar_setbuf(ndev, "bssload_report_event", &blcfg,
24206 sizeof(wl_bssload_cfg_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
24207 if (unlikely(err)) {
24208 WL_ERR(("Set event_msgs error (%d)\n", err));
24209 }
24210
24211 return err;
24212 }
24213 #endif /* WL_CHAN_UTIL */
24214
24215 s32
wl_cfg80211_config_suspend_events(struct net_device * ndev,bool enable)24216 wl_cfg80211_config_suspend_events(struct net_device *ndev, bool enable)
24217 {
24218 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
24219 s8 eventmask[WL_EVENTING_MASK_LEN];
24220 s32 err = 0;
24221 struct bcm_cfg80211 *cfg;
24222
24223 if (!ndev) {
24224 return -ENODEV;
24225 }
24226
24227 cfg = wl_get_cfg(ndev);
24228 if (!cfg) {
24229 return -ENODEV;
24230 }
24231
24232 mutex_lock(&cfg->event_sync);
24233 err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
24234 if (unlikely(err)) {
24235 WL_ERR(("Get event_msgs error (%d)\n", err));
24236 goto eventmsg_out;
24237 }
24238
24239 (void)memcpy_s(eventmask, WL_EVENTING_MASK_LEN, iovbuf, WL_EVENTING_MASK_LEN);
24240 /* Add set/clear of event mask under feature specific flags */
24241 if (enable) {
24242 WL_DBG(("%s: Enabling events on resume\n", __FUNCTION__));
24243 #ifdef WL_CHAN_UTIL
24244 setbit(eventmask, WLC_E_BSS_LOAD);
24245 #endif /* WL_CHAN_UTIL */
24246 } else {
24247 WL_DBG(("%s: Disabling events before suspend\n", __FUNCTION__));
24248 #ifdef WL_CHAN_UTIL
24249 clrbit(eventmask, WLC_E_BSS_LOAD);
24250 #endif /* WL_CHAN_UTIL */
24251 }
24252
24253 err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
24254 sizeof(iovbuf), NULL);
24255 if (unlikely(err)) {
24256 WL_ERR(("Set event_msgs error (%d)\n", err));
24257 goto eventmsg_out;
24258 }
24259
24260 eventmsg_out:
24261 mutex_unlock(&cfg->event_sync);
24262 return err;
24263 }
24264
24265 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
24266 int
wl_cfg80211_channel_switch(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_csa_settings * params)24267 wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
24268 struct cfg80211_csa_settings *params)
24269 {
24270 s32 err = BCME_OK;
24271 s32 chan = 0;
24272 u32 band = 0;
24273 u32 bw = WL_CHANSPEC_BW_20;
24274 chanspec_t chspec = 0;
24275 wl_chan_switch_t csa_arg;
24276 struct cfg80211_chan_def *chandef = ¶ms->chandef;
24277 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
24278 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
24279
24280 dev = ndev_to_wlc_ndev(dev, cfg);
24281 chan = ieee80211_frequency_to_channel(chandef->chan->center_freq);
24282 band = chandef->chan->band;
24283
24284 WL_ERR(("netdev_ifidx(%d), target channel(%d) target bandwidth(%d),"
24285 " mode(%d), count(%d)\n", dev->ifindex, chan, chandef->width,
24286 params->block_tx, params->count));
24287
24288 if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) {
24289 WL_ERR(("Channel Switch doesn't support on "
24290 "the non-SoftAP mode\n"));
24291 return -EINVAL;
24292 }
24293
24294 /* Check if STA is trying to associate with an AP */
24295 if (wl_get_drv_status(cfg, CONNECTING, primary_dev)) {
24296 WL_ERR(("Connecting is in progress\n"));
24297 return BCME_BUSY;
24298 }
24299
24300 if (chan == cfg->ap_oper_channel) {
24301 WL_ERR(("Channel %d is same as current operating channel,"
24302 " so skip\n", chan));
24303 return BCME_OK;
24304 }
24305
24306 if (band == IEEE80211_BAND_5GHZ) {
24307 #ifdef APSTA_RESTRICTED_CHANNEL
24308 if (chan != DEFAULT_5G_SOFTAP_CHANNEL) {
24309 WL_ERR(("Invalid 5G Channel, chan=%d\n", chan));
24310 return -EINVAL;
24311 }
24312 #endif /* APSTA_RESTRICTED_CHANNEL */
24313 err = wl_get_bandwidth_cap(primary_dev, band, &bw);
24314 if (err < 0) {
24315 WL_ERR(("Failed to get bandwidth information,"
24316 " err=%d\n", err));
24317 return err;
24318 }
24319 } else if (band == IEEE80211_BAND_2GHZ) {
24320 #ifdef APSTA_RESTRICTED_CHANNEL
24321 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24322 u32 *sta_chan = (u32 *)wl_read_prof(cfg,
24323 primary_dev, WL_PROF_CHAN);
24324
24325 /* In 2GHz STA/SoftAP concurrent mode, the operating channel
24326 * of STA and SoftAP should be confgiured to the same 2GHz
24327 * channel. Otherwise, it is an invalid configuration.
24328 */
24329 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
24330 wl_get_drv_status(cfg, CONNECTED, primary_dev) &&
24331 sta_chan && (*sta_chan != chan)) {
24332 WL_ERR(("Invalid 2G Channel in case of STA/SoftAP"
24333 " concurrent mode, sta_chan=%d, chan=%d\n",
24334 *sta_chan, chan));
24335 return -EINVAL;
24336 }
24337 #endif /* APSTA_RESTRICTED_CHANNEL */
24338 bw = WL_CHANSPEC_BW_20;
24339 } else {
24340 WL_ERR(("invalid band (%d)\n", band));
24341 return -EINVAL;
24342 }
24343
24344 chspec = wf_channel2chspec(chan, bw);
24345 if (!wf_chspec_valid(chspec)) {
24346 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
24347 return -EINVAL;
24348 }
24349
24350 /* Send CSA to associated STAs */
24351 memset(&csa_arg, 0, sizeof(wl_chan_switch_t));
24352 csa_arg.mode = params->block_tx;
24353 csa_arg.count = params->count;
24354 csa_arg.chspec = chspec;
24355 csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME;
24356 csa_arg.reg = 0;
24357
24358 err = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(wl_chan_switch_t),
24359 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
24360 if (err < 0) {
24361 WL_ERR(("Failed to switch channel, err=%d\n", err));
24362 }
24363
24364 return err;
24365 }
24366 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
24367
24368 #ifdef WL_WIPSEVT
24369 int
wl_cfg80211_wips_event_ext(wl_wips_event_info_t * wips_event)24370 wl_cfg80211_wips_event_ext(wl_wips_event_info_t *wips_event)
24371 {
24372 s32 err = BCME_OK;
24373 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24374 struct sk_buff *skb;
24375 gfp_t kflags;
24376 struct bcm_cfg80211 *cfg;
24377 struct net_device *ndev;
24378 struct wiphy *wiphy;
24379
24380 cfg = wl_cfg80211_get_bcmcfg();
24381 if (!cfg || !cfg->wdev) {
24382 WL_ERR(("WIPS evt invalid arg\n"));
24383 return err;
24384 }
24385
24386 ndev = bcmcfg_to_prmry_ndev(cfg);
24387 wiphy = bcmcfg_to_wiphy(cfg);
24388
24389 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
24390 skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
24391 BRCM_VENDOR_WIPS_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_WIPS, kflags);
24392
24393 if (!skb) {
24394 WL_ERR(("skb alloc failed"));
24395 return BCME_NOMEM;
24396 }
24397
24398 err = nla_put_u16(skb, WIPS_ATTR_DEAUTH_CNT, wips_event->misdeauth);
24399 if (unlikely(err)) {
24400 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_CNT failed\n"));
24401 goto fail;
24402 }
24403 err = nla_put(skb, WIPS_ATTR_DEAUTH_BSSID, ETHER_ADDR_LEN, &wips_event->bssid);
24404 if (unlikely(err)) {
24405 WL_ERR(("nla_put WIPS_ATTR_DEAUTH_BSSID failed\n"));
24406 goto fail;
24407 }
24408 err = nla_put_s16(skb, WIPS_ATTR_CURRENT_RSSI, wips_event->current_RSSI);
24409 if (unlikely(err)) {
24410 WL_ERR(("nla_put_u16 WIPS_ATTR_CURRENT_RSSI failed\n"));
24411 goto fail;
24412 }
24413 err = nla_put_s16(skb, WIPS_ATTR_DEAUTH_RSSI, wips_event->deauth_RSSI);
24414 if (unlikely(err)) {
24415 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_RSSI failed\n"));
24416 goto fail;
24417 }
24418 cfg80211_vendor_event(skb, kflags);
24419
24420 return err;
24421
24422 fail:
24423 if (skb) {
24424 nlmsg_free(skb);
24425 }
24426 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24427 return err;
24428 }
24429
24430 int
wl_cfg80211_wips_event(uint16 misdeauth,char * bssid)24431 wl_cfg80211_wips_event(uint16 misdeauth, char* bssid)
24432 {
24433 s32 err = BCME_OK;
24434 wl_wips_event_info_t wips_event;
24435
24436 wips_event.misdeauth = misdeauth;
24437 memcpy(&wips_event.bssid, bssid, ETHER_ADDR_LEN);
24438 wips_event.current_RSSI = 0;
24439 wips_event.deauth_RSSI = 0;
24440
24441 err = wl_cfg80211_wips_event_ext(&wips_event);
24442 return err;
24443 }
24444 #endif /* WL_WIPSEVT */
24445
wl_cfg80211_check_in_progress(struct net_device * dev)24446 bool wl_cfg80211_check_in_progress(struct net_device *dev)
24447 {
24448 /* TODO: Check for cfg status like scan in progress,
24449 * four way handshake, etc before entering Deep Sleep.
24450 */
24451 return TRUE;
24452 }
24453
24454 #ifdef SUPPORT_AP_SUSPEND
24455 void
wl_set_ap_suspend_error_handler(struct net_device * ndev,bool suspend)24456 wl_set_ap_suspend_error_handler(struct net_device *ndev, bool suspend)
24457 {
24458 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24459 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24460
24461 if (wl_get_drv_status(cfg, READY, ndev)) {
24462 /* IF dongle is down due to previous hang or other conditions, sending
24463 * one more hang notification is not needed.
24464 */
24465 if (dhd_query_bus_erros(dhdp)) {
24466 return;
24467 }
24468 dhdp->iface_op_failed = TRUE;
24469 #if defined(DHD_FW_COREDUMP)
24470 if (dhdp->memdump_enabled) {
24471 dhdp->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
24472 dhd_bus_mem_dump(dhdp);
24473 }
24474 #endif /* DHD_FW_COREDUMP */
24475 WL_ERR(("Notify hang event to upper layer \n"));
24476 dhdp->hang_reason = suspend ?
24477 HANG_REASON_BSS_DOWN_FAILURE : HANG_REASON_BSS_UP_FAILURE;
24478 net_os_send_hang_message(ndev);
24479 }
24480 }
24481
24482 #define MAX_AP_RESUME_TIME 5000
24483 int
wl_set_ap_suspend(struct net_device * dev,bool suspend,char * ifname)24484 wl_set_ap_suspend(struct net_device *dev, bool suspend, char *ifname)
24485 {
24486 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24487 dhd_pub_t *dhdp;
24488 struct net_device *ndev = NULL;
24489 int ret = BCME_OK;
24490 bool is_bssup = FALSE;
24491 int bssidx;
24492 unsigned long start_j;
24493 int time_to_sleep = MAX_AP_RESUME_TIME;
24494
24495 dhdp = (dhd_pub_t *)(cfg->pub);
24496
24497 if (!dhdp) {
24498 return BCME_NOTUP;
24499 }
24500
24501 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
24502 WL_ERR(("Not Hostapd mode\n"));
24503 return BCME_NOTAP;
24504 }
24505
24506 ndev = wl_get_ap_netdev(cfg, ifname);
24507
24508 if (ndev == NULL) {
24509 WL_ERR(("No softAP interface named %s\n", ifname));
24510 return BCME_NOTAP;
24511 }
24512
24513 if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
24514 WL_ERR(("Find p2p index from wdev(%p) failed\n", ndev->ieee80211_ptr));
24515 return BCME_NOTFOUND;
24516 }
24517
24518 is_bssup = wl_cfg80211_bss_isup(ndev, bssidx);
24519 if (is_bssup && suspend) {
24520 wl_clr_drv_status(cfg, AP_CREATED, ndev);
24521 wl_clr_drv_status(cfg, CONNECTED, ndev);
24522
24523 if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 0)) < 0) {
24524 WL_ERR(("AP suspend error %d, suspend %d\n", ret, suspend));
24525 ret = BCME_NOTDOWN;
24526 goto exit;
24527 }
24528 } else if (!is_bssup && !suspend) {
24529 /* Abort scan before starting AP again */
24530 wl_cfg80211_scan_abort(cfg);
24531
24532 if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 1)) < 0) {
24533 WL_ERR(("AP resume error %d, suspend %d\n", ret, suspend));
24534 ret = BCME_NOTUP;
24535 goto exit;
24536 }
24537
24538 while (TRUE) {
24539 start_j = get_jiffies_64();
24540 /* Wait for Linkup event to mark successful AP bring up */
24541 ret = wait_event_interruptible_timeout(cfg->netif_change_event,
24542 wl_get_drv_status(cfg, AP_CREATED, ndev),
24543 msecs_to_jiffies(time_to_sleep));
24544 if (ret == -ERESTARTSYS) {
24545 WL_ERR(("waitqueue was interrupted by a signal\n"));
24546 time_to_sleep -= jiffies_to_msecs(get_jiffies_64() - start_j);
24547 if (time_to_sleep <= 0) {
24548 WL_ERR(("time to sleep hits 0\n"));
24549 ret = BCME_NOTUP;
24550 goto exit;
24551 }
24552 } else if (ret == 0 || !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
24553 WL_ERR(("AP resume failed!\n"));
24554 ret = BCME_NOTUP;
24555 goto exit;
24556 } else {
24557 wl_set_drv_status(cfg, CONNECTED, ndev);
24558 ret = BCME_OK;
24559 break;
24560 }
24561 }
24562 } else {
24563 /* bssup + resume or bssdown + suspend,
24564 * So, returns OK
24565 */
24566 ret = BCME_OK;
24567 }
24568 exit:
24569 if (ret != BCME_OK)
24570 wl_set_ap_suspend_error_handler(bcmcfg_to_prmry_ndev(cfg), suspend);
24571
24572 return ret;
24573 }
24574 #endif /* SUPPORT_AP_SUSPEND */
24575
24576 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
wl_set_softap_elna_bypass(struct net_device * dev,char * ifname,int enable)24577 int wl_set_softap_elna_bypass(struct net_device *dev, char *ifname, int enable)
24578 {
24579 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24580 struct net_device *ifdev = NULL;
24581 char iobuf[WLC_IOCTL_SMLEN];
24582 int err = BCME_OK;
24583 int iftype = 0;
24584
24585 memset(iobuf, 0, WLC_IOCTL_SMLEN);
24586
24587 /* Check the interface type */
24588 ifdev = wl_get_netdev_by_name(cfg, ifname);
24589 if (ifdev == NULL) {
24590 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__, ifname));
24591 err = BCME_BADARG;
24592 goto fail;
24593 }
24594
24595 iftype = ifdev->ieee80211_ptr->iftype;
24596 if (iftype == NL80211_IFTYPE_AP) {
24597 err = wldev_iovar_setint(ifdev, "softap_elnabypass", enable);
24598 if (unlikely(err)) {
24599 WL_ERR(("%s: Failed to set softap_elnabypass, err=%d\n",
24600 __FUNCTION__, err));
24601 }
24602 } else {
24603 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
24604 __FUNCTION__));
24605 err = BCME_BADARG;
24606 }
24607 fail:
24608 return err;
24609 }
wl_get_softap_elna_bypass(struct net_device * dev,char * ifname,void * param)24610 int wl_get_softap_elna_bypass(struct net_device *dev, char *ifname, void *param)
24611 {
24612 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24613 int *enable = (int*)param;
24614 struct net_device *ifdev = NULL;
24615 char iobuf[WLC_IOCTL_SMLEN];
24616 int err = BCME_OK;
24617 int iftype = 0;
24618
24619 memset(iobuf, 0, WLC_IOCTL_SMLEN);
24620
24621 /* Check the interface type */
24622 ifdev = wl_get_netdev_by_name(cfg, ifname);
24623 if (ifdev == NULL) {
24624 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__, ifname));
24625 err = BCME_BADARG;
24626 goto fail;
24627 }
24628
24629 iftype = ifdev->ieee80211_ptr->iftype;
24630 if (iftype == NL80211_IFTYPE_AP) {
24631 err = wldev_iovar_getint(ifdev, "softap_elnabypass", enable);
24632 if (unlikely(err)) {
24633 WL_ERR(("%s: Failed to get softap_elnabypass, err=%d\n",
24634 __FUNCTION__, err));
24635 }
24636 } else {
24637 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
24638 __FUNCTION__));
24639 err = BCME_BADARG;
24640 }
24641 fail:
24642 return err;
24643
24644 }
24645 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
24646
24647 #ifdef SUPPORT_AP_BWCTRL
24648 #define OPER_MODE_ENABLE (1 << 8)
24649 static int op2bw[] = {20, 40, 80, 160};
24650
24651 static int
wl_get_ap_he_mode(struct net_device * ndev,struct bcm_cfg80211 * cfg,bool * he)24652 wl_get_ap_he_mode(struct net_device *ndev, struct bcm_cfg80211 *cfg, bool *he)
24653 {
24654 bcm_xtlv_t read_he_xtlv;
24655 int ret = 0;
24656 u8 he_enab = 0;
24657 u32 he_feature = 0;
24658 *he = FALSE;
24659
24660 /* Check he enab first */
24661 read_he_xtlv.id = WL_HE_CMD_ENAB;
24662 read_he_xtlv.len = 0;
24663
24664 ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
24665 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
24666 if (ret < 0) {
24667 if (ret == BCME_UNSUPPORTED) {
24668 /* HE not supported */
24669 ret = BCME_OK;
24670 } else {
24671 WL_ERR(("HE ENAB get failed. ret=%d\n", ret));
24672 }
24673 goto exit;
24674 } else {
24675 he_enab = *(u8*)cfg->ioctl_buf;
24676 }
24677
24678 if (!he_enab) {
24679 goto exit;
24680 }
24681
24682 /* Then check BIT3 of he features */
24683 read_he_xtlv.id = WL_HE_CMD_FEATURES;
24684 read_he_xtlv.len = 0;
24685
24686 ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
24687 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
24688 if (ret < 0) {
24689 WL_ERR(("HE FEATURE get failed. error=%d\n", ret));
24690 goto exit;
24691 } else {
24692 he_feature = *(int*)cfg->ioctl_buf;
24693 he_feature = dtoh32(he_feature);
24694 }
24695
24696 if (he_feature & WL_HE_FEATURES_HE_AP) {
24697 WL_DBG(("HE is enabled in AP\n"));
24698 *he = TRUE;
24699 }
24700 exit:
24701 return ret;
24702 }
24703
24704 static void
wl_update_apchan_bwcap(struct bcm_cfg80211 * cfg,struct net_device * ndev,chanspec_t chanspec)24705 wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg, struct net_device *ndev, chanspec_t chanspec)
24706 {
24707 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
24708 struct wireless_dev *wdev = ndev_to_wdev(dev);
24709 struct wiphy *wiphy = wdev->wiphy;
24710 int ret = BCME_OK;
24711 u32 bw_cap;
24712 u32 ctl_chan;
24713 chanspec_t chanbw = WL_CHANSPEC_BW_20;
24714
24715 /* Update channel in profile */
24716 ctl_chan = wf_chspec_ctlchan(chanspec);
24717 wl_update_prof(cfg, ndev, NULL, &ctl_chan, WL_PROF_CHAN);
24718
24719 /* BW cap is only updated in 5GHz */
24720 if (ctl_chan <= CH_MAX_2G_CHANNEL)
24721 return;
24722
24723 /* Get WL BW CAP */
24724 ret = wl_get_bandwidth_cap(bcmcfg_to_prmry_ndev(cfg),
24725 IEEE80211_BAND_5GHZ, &bw_cap);
24726 if (ret < 0) {
24727 WL_ERR(("get bw_cap failed = %d\n", ret));
24728 goto exit;
24729 }
24730
24731 chanbw = CHSPEC_BW(channel_to_chanspec(wiphy,
24732 ndev, wf_chspec_ctlchan(chanspec), bw_cap));
24733
24734 exit:
24735 cfg->bw_cap_5g = bw2cap[chanbw >> WL_CHANSPEC_BW_SHIFT];
24736 WL_INFORM_MEM(("supported bw cap is:0x%x\n", cfg->bw_cap_5g));
24737
24738 }
24739
24740 int
wl_rxchain_to_opmode_nss(int rxchain)24741 wl_rxchain_to_opmode_nss(int rxchain)
24742 {
24743 /*
24744 * Nss 1 -> 0, Nss 2 -> 1
24745 * This is from operating mode field
24746 * in 8.4.1.50 of 802.11ac-2013
24747 */
24748 /* TODO : Nss 3 ? */
24749 if (rxchain == 3)
24750 return (1 << 4);
24751 else
24752 return 0;
24753 }
24754
24755 int
wl_update_opmode(struct net_device * ndev,u32 bw)24756 wl_update_opmode(struct net_device *ndev, u32 bw)
24757 {
24758 int ret = BCME_OK;
24759 int oper_mode;
24760 int rxchain;
24761
24762 ret = wldev_iovar_getint(ndev, "rxchain", (s32 *)&rxchain);
24763 if (ret < 0) {
24764 WL_ERR(("get rxchain failed = %d\n", ret));
24765 goto exit;
24766 }
24767
24768 oper_mode = bw;
24769 oper_mode |= wl_rxchain_to_opmode_nss(rxchain);
24770 /* Enable flag */
24771 oper_mode |= OPER_MODE_ENABLE;
24772
24773 ret = wldev_iovar_setint(ndev, "oper_mode", oper_mode);
24774 if (ret < 0) {
24775 WL_ERR(("set oper_mode failed = %d\n", ret));
24776 goto exit;
24777 }
24778
24779 exit:
24780 return ret;
24781 }
24782
24783 int
wl_set_ap_bw(struct net_device * dev,u32 bw,char * ifname)24784 wl_set_ap_bw(struct net_device *dev, u32 bw, char *ifname)
24785 {
24786 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24787 dhd_pub_t *dhdp;
24788 struct net_device *ndev = NULL;
24789 int ret = BCME_OK;
24790 u32 *channel;
24791 bool he;
24792
24793 dhdp = (dhd_pub_t *)(cfg->pub);
24794
24795 if (!dhdp) {
24796 return BCME_NOTUP;
24797 }
24798
24799 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
24800 WL_ERR(("Not Hostapd mode\n"));
24801 return BCME_NOTAP;
24802 }
24803
24804 ndev = wl_get_ap_netdev(cfg, ifname);
24805
24806 if (ndev == NULL) {
24807 WL_ERR(("No softAP interface named %s\n", ifname));
24808 return BCME_NOTAP;
24809 }
24810
24811 if (bw > DOT11_OPER_MODE_160MHZ) {
24812 WL_ERR(("BW is too big %d\n", bw));
24813 return BCME_BADARG;
24814 }
24815
24816 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
24817 if (*channel <= CH_MAX_2G_CHANNEL) {
24818 WL_ERR(("current channel is %d, not supported\n", *channel));
24819 ret = BCME_BADCHAN;
24820 goto exit;
24821 }
24822
24823 if ((DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
24824 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) ||
24825 cfg->nan_enable) {
24826 WL_ERR(("BW control in concurrent mode is not supported\n"));
24827 return BCME_BUSY;
24828 }
24829
24830 /* When SCAN is on going either in STA or in AP, return BUSY */
24831 if (wl_get_drv_status_all(cfg, SCANNING)) {
24832 WL_ERR(("STA is SCANNING, not support BW control\n"));
24833 return BCME_BUSY;
24834 }
24835
24836 /* When SCANABORT is on going either in STA or in AP, return BUSY */
24837 if (wl_get_drv_status_all(cfg, SCAN_ABORTING)) {
24838 WL_ERR(("STA is SCAN_ABORTING, not support BW control\n"));
24839 return BCME_BUSY;
24840 }
24841
24842 /* When CONNECTION is on going in STA, return BUSY */
24843 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
24844 WL_ERR(("STA is CONNECTING, not support BW control\n"));
24845 return BCME_BUSY;
24846 }
24847
24848 /* BW control in AX mode needs more verification */
24849 ret = wl_get_ap_he_mode(ndev, cfg, &he);
24850 if (ret == BCME_OK && he) {
24851 WL_ERR(("BW control in HE mode is not supported\n"));
24852 return BCME_UNSUPPORTED;
24853 }
24854 if (ret < 0) {
24855 WL_ERR(("Check AX mode is failed\n"));
24856 goto exit;
24857 }
24858
24859 if ((!WL_BW_CAP_160MHZ(cfg->bw_cap_5g) && (bw == DOT11_OPER_MODE_160MHZ)) ||
24860 (!WL_BW_CAP_80MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_80MHZ)) ||
24861 (!WL_BW_CAP_40MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_40MHZ)) ||
24862 (!WL_BW_CAP_20MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_20MHZ))) {
24863 WL_ERR(("bw_cap %x does not support bw = %d\n", cfg->bw_cap_5g, bw));
24864 ret = BCME_BADARG;
24865 goto exit;
24866 }
24867
24868 WL_DBG(("Updating AP BW to %d\n", op2bw[bw]));
24869
24870 ret = wl_update_opmode(ndev, bw);
24871 if (ret < 0) {
24872 WL_ERR(("opmode set failed = %d\n", ret));
24873 goto exit;
24874 }
24875
24876 exit:
24877 return ret;
24878 }
24879
24880 int
wl_get_ap_bw(struct net_device * dev,char * command,char * ifname,int total_len)24881 wl_get_ap_bw(struct net_device *dev, char* command, char *ifname, int total_len)
24882 {
24883 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24884 dhd_pub_t *dhdp;
24885 struct net_device *ndev = NULL;
24886 int ret = BCME_OK;
24887 u32 chanspec = 0;
24888 u32 bw = DOT11_OPER_MODE_20MHZ;
24889 int bytes_written = 0;
24890
24891 dhdp = (dhd_pub_t *)(cfg->pub);
24892
24893 if (!dhdp) {
24894 return BCME_NOTUP;
24895 }
24896
24897 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
24898 WL_ERR(("Not Hostapd mode\n"));
24899 return BCME_NOTAP;
24900 }
24901
24902 ndev = wl_get_ap_netdev(cfg, ifname);
24903
24904 if (ndev == NULL) {
24905 WL_ERR(("No softAP interface named %s\n", ifname));
24906 return BCME_NOTAP;
24907 }
24908
24909 ret = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
24910 if (ret < 0) {
24911 WL_ERR(("get chanspec from AP failed = %d\n", ret));
24912 goto exit;
24913 }
24914
24915 chanspec = wl_chspec_driver_to_host(chanspec);
24916
24917 if (CHSPEC_IS20(chanspec)) {
24918 bw = DOT11_OPER_MODE_20MHZ;
24919 } else if (CHSPEC_IS40(chanspec)) {
24920 bw = DOT11_OPER_MODE_40MHZ;
24921 } else if (CHSPEC_IS80(chanspec)) {
24922 bw = DOT11_OPER_MODE_80MHZ;
24923 } else if (CHSPEC_IS_BW_160_WIDE(chanspec)) {
24924 bw = DOT11_OPER_MODE_160MHZ;
24925 } else {
24926 WL_ERR(("chanspec error %x\n", chanspec));
24927 ret = BCME_BADCHAN;
24928 goto exit;
24929 }
24930
24931 bytes_written += snprintf(command + bytes_written, total_len,
24932 "bw=%d", bw);
24933 ret = bytes_written;
24934 exit:
24935 return ret;
24936 }
24937
24938 static void
wl_restore_ap_bw(struct bcm_cfg80211 * cfg)24939 wl_restore_ap_bw(struct bcm_cfg80211 *cfg)
24940 {
24941 int ret = BCME_OK;
24942 u32 bw;
24943 bool he = FALSE;
24944 struct net_info *iter, *next;
24945 struct net_device *ndev = NULL;
24946 u32 *channel;
24947
24948 if (!cfg) {
24949 return;
24950 }
24951
24952 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
24953 for_each_ndev(cfg, iter, next) {
24954 GCC_DIAGNOSTIC_POP();
24955 if (iter->ndev) {
24956 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
24957 channel = (u32 *)wl_read_prof(cfg, iter->ndev, WL_PROF_CHAN);
24958 if (*channel > CH_MAX_2G_CHANNEL) {
24959 ndev = iter->ndev;
24960 break;
24961 }
24962 }
24963 }
24964 }
24965
24966 if (!ndev) {
24967 return;
24968 }
24969
24970 /* BW control in AX mode not allowed */
24971 ret = wl_get_ap_he_mode(bcmcfg_to_prmry_ndev(cfg), cfg, &he);
24972 if (ret == BCME_OK && he) {
24973 return;
24974 }
24975 if (ret < 0) {
24976 WL_ERR(("Check AX mode is failed\n"));
24977 return;
24978 }
24979
24980 if (WL_BW_CAP_160MHZ(cfg->bw_cap_5g)) {
24981 bw = DOT11_OPER_MODE_160MHZ;
24982 } else if (WL_BW_CAP_80MHZ(cfg->bw_cap_5g)) {
24983 bw = DOT11_OPER_MODE_80MHZ;
24984 } else if (WL_BW_CAP_40MHZ(cfg->bw_cap_5g)) {
24985 bw = DOT11_OPER_MODE_40MHZ;
24986 } else {
24987 return;
24988 }
24989
24990 WL_DBG(("Restoring AP BW to %d\n", op2bw[bw]));
24991
24992 ret = wl_update_opmode(ndev, bw);
24993 if (ret < 0) {
24994 WL_ERR(("bw restore failed = %d\n", ret));
24995 return;
24996 }
24997 }
24998 #endif /* SUPPORT_AP_BWCTRL */
24999
25000 s32
wl_cfg80211_autochannel(struct net_device * dev,char * command,int total_len)25001 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len)
25002 {
25003 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
25004 int ret = 0;
25005 int bytes_written = -1;
25006
25007 sscanf(command, "%*s %d", &cfg->autochannel);
25008
25009 if (cfg->autochannel == 0) {
25010 cfg->best_2g_ch = 0;
25011 cfg->best_5g_ch = 0;
25012 } else if (cfg->autochannel == 2) {
25013 bytes_written = snprintf(command, total_len, "2g=%d 5g=%d",
25014 cfg->best_2g_ch, cfg->best_5g_ch);
25015 WL_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
25016 ret = bytes_written;
25017 }
25018
25019 return ret;
25020 }
25021