1 /*
2 * Linux cfg80211 driver
3 *
4 * Copyright (C) 1999-2019, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions
16 * of the license of that module. An independent module is a module which is
17 * not derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: wl_cfg80211.c 826086 2019-06-18 19:23:59Z $
28 */
29 /* */
30 #include <typedefs.h>
31 #include <linuxver.h>
32 #include <linux/kernel.h>
33 #ifdef CONFIG_AP6XXX_WIFI6_HDF
34 #include "hdf_mac80211_sta_event.h"
35 #endif
36 #include <bcmutils.h>
37 #include <bcmstdlib_s.h>
38 #include <bcmwifi_channels.h>
39 #include <bcmendian.h>
40 #include <ethernet.h>
41 #ifdef WL_WPS_SYNC
42 #include <dhd_eapol.h>
43 #endif /* WL_WPS_SYNC */
44 #include <802.11.h>
45 #include <bcmiov.h>
46 #include <linux/if_arp.h>
47 #include <asm/uaccess.h>
48
49 #include <ethernet.h>
50 #include <linux/kernel.h>
51 #include <linux/kthread.h>
52 #include <linux/netdevice.h>
53 #include <linux/sched.h>
54 #include <linux/etherdevice.h>
55 #include <linux/wireless.h>
56 #include <linux/ieee80211.h>
57 #include <linux/wait.h>
58 #include <net/cfg80211.h>
59 #include <net/rtnetlink.h>
60
61 #include <wlioctl.h>
62 #include <bcmevent.h>
63 #include <wldev_common.h>
64 #include <wl_cfg80211.h>
65 #include <wl_cfgp2p.h>
66 #include <wl_cfgscan.h>
67 #include <bcmdevs.h>
68 #ifdef WL_FILS
69 #include <fils.h>
70 #include <frag.h>
71 #endif /* WL_FILS */
72 #include <wl_android.h>
73 #include <dngl_stats.h>
74 #include <dhd.h>
75 #include <dhd_linux.h>
76 #include <dhd_linux_pktdump.h>
77 #include <dhd_debug.h>
78 #include <dhdioctl.h>
79 #include <wlioctl.h>
80 #include <dhd_cfg80211.h>
81 #include <dhd_bus.h>
82 #ifdef PNO_SUPPORT
83 #include <dhd_pno.h>
84 #endif /* PNO_SUPPORT */
85 #include <wl_cfgvendor.h>
86
87 #if !defined(WL_VENDOR_EXT_SUPPORT)
88 #undef GSCAN_SUPPORT
89 #endif
90 #include <dhd_config.h>
91
92 #ifdef WL_NAN
93 #include <wl_cfgnan.h>
94 #endif /* WL_NAN */
95
96 #ifdef PROP_TXSTATUS
97 #include <dhd_wlfc.h>
98 #endif // endif
99
100 #ifdef BCMPCIE
101 #include <dhd_flowring.h>
102 #endif // endif
103 #ifdef RTT_SUPPORT
104 #include <dhd_rtt.h>
105 #endif /* RTT_SUPPORT */
106
107 #define BRCM_SAE_VENDOR_EVENT_BUF_LEN 500
108
109 #ifdef DNGL_AXI_ERROR_LOGGING
110 #include <bcmtlv.h>
111 #endif /* DNGL_AXI_ERROR_LOGGING */
112
113 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
114 #include <linux/dev_ril_bridge.h>
115 #include <linux/notifier.h>
116 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
117
118 #ifdef BCMWAPI_WPI
119 /* these items should evetually go into wireless.h of the linux system headfile
120 * 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) \
148 ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
149 #else /* BCMWAPI_WPI */
150 #define IW_WSEC_ENABLED(wsec) \
151 ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
152 #endif /* BCMWAPI_WPI */
153
154 #if (defined(WL_FW_OCE_AP_SELECT) || \
155 defined(BCMFW_ROAM_ENABLE) && \
156 ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || \
157 defined(WL_COMPAT_WIRELESS)))
158 uint fw_ap_select = true;
159 #else
160 uint fw_ap_select = false;
161 #endif /* WL_FW_OCE_AP_SELECT && (ROAM_ENABLE || BCMFW_ROAM_ENABLE) */
162 module_param(fw_ap_select, uint, 0660);
163
164 static struct device *cfg80211_parent_dev = NULL;
165 static struct bcm_cfg80211 *g_bcmcfg = NULL;
166 u32 wl_dbg_level = 0xff;
167 // u32 wl_dbg_level = WL_DBG_ERR; // | WL_DBG_P2P_ACTION | WL_DBG_INFO;
168
169 #define MAX_VIF_OFFSET 15
170 #define MAX_WAIT_TIME 1500
171 #ifdef WLAIBSS_MCHAN
172 #define IBSS_IF_NAME "ibss%d"
173 #endif /* WLAIBSS_MCHAN */
174
175 #ifdef VSDB
176 /* sleep time to keep STA's connecting or connection for continuous af tx or
177 * finding a peer */
178 #define DEFAULT_SLEEP_TIME_VSDB 120
179 #define OFF_CHAN_TIME_THRESHOLD_MS 200
180 #define AF_RETRY_DELAY_TIME 40
181
182 /* if sta is connected or connecting, sleep for a while before retry af tx or
183 * finding a peer */
184 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
185 do { \
186 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
187 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
188 OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
189 } \
190 } while (0)
191 #else /* VSDB */
192 /* if not VSDB, do nothing */
193 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
194 #endif /* VSDB */
195
196 #define DNGL_FUNC(func, parameters) func parameters
197 #define COEX_DHCP
198
199 #define WLAN_EID_SSID 0
200 #define CH_MIN_5G_CHANNEL 34
201
202 #ifdef WL_RELMCAST
203 enum rmc_event_type { RMC_EVENT_NONE, RMC_EVENT_LEADER_CHECK_FAIL };
204 #endif /* WL_RELMCAST */
205
206 #ifdef CONFIG_AP6XXX_WIFI6_HDF
207 #include "hdf_wl_interface.h"
208 #include "net_device.h"
209 int32_t HdfWifiEventMgmtTxStatus(const struct NetDevice *netDev,
210 const uint8_t *buf, size_t len, uint8_t ack);
211 int32_t HdfWifiEventRxMgmt(const struct NetDevice *netDev, int32_t freq,
212 int32_t sigMbm, const uint8_t *buf, size_t len);
213 int32_t HdfWifiEventCsaChannelSwitch(const struct NetDevice *netDev,
214 int32_t freq);
215 int32_t HdfWifiEventRemainOnChannel(const struct NetDevice *netDev,
216 uint32_t freq, uint32_t duration);
217
218 struct NetDevice *GetHdfNetDeviceByLinuxInf(struct net_device *dev);
219
220 int ChangNewSta(struct net_device *dev, const uint8_t *macAddr, uint8_t addrLen,
221 const struct station_info *info);
222 int ChangDelSta(struct net_device *dev, const uint8_t *macAddr,
223 uint8_t addrLen);
224 extern void HdfInformBssFrameEventCallback(struct net_device *ndev,
225 struct ieee80211_channel *channel,
226 int32_t signal, int16_t freq,
227 struct ieee80211_mgmt *mgmt,
228 uint32_t mgmtLen);
229 extern int32_t HdfConnectResultEventCallback(struct net_device *ndev,
230 uint8_t *bssid, uint8_t *reqIe,
231 uint8_t *rspIe, uint32_t reqIeLen,
232 uint32_t rspIeLen,
233 uint16_t connectStatus,
234 uint16_t freq);
235
236 extern int g_event_ifidx;
237 extern struct hdf_inf_map g_hdf_infmap[HDF_INF_MAX];
238 struct NetDevice *get_hdf_netdev(int ifidx);
239
240 extern int g_mgmt_tx_event_ifidx;
241
242 #endif
243
244 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
245 * By default world regulatory domain defined in reg.c puts the flags
246 * NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels
247 * (for 36..48 and 149..165). With respect to these flags, wpa_supplicant
248 * doesn't start p2p operations on 5GHz channels. All the chnages in world
249 * regulatory domain are to be done here.
250 *
251 * this definition reuires disabling missing-field-initializer warning
252 * as the ieee80211_regdomain definition differs in plain linux and in Android
253 */
254 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
255 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0x6))
256 _Pragma("GCC diagnostic push")
257 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
258 #endif // endif
259 static const struct ieee80211_regdomain brcm_regdom = {
260 .n_reg_rules = 4,
261 .alpha2 = "99",
262 .reg_rules = {
263 /* IEEE 802.11b/g, channels 1..11 */
264 REG_RULE(2412 - 0xA, 2472 + 0xA, 40, 6, 20, 0),
265 /* If any */
266 /* IEEE 802.11 channel 14 - Only JP enables
267 * this and for 802.11b only
268 */
269 REG_RULE(2484 - 0xA, 2484 + 0xA, 20, 6, 20, 0),
270 /* IEEE 802.11a, channel 36..64 */
271 REG_RULE(5150 - 0xA, 5350 + 0xA, 40, 6, 20, 0),
272 /* IEEE 802.11a, channel 100..165 */
273 REG_RULE(5470 - 0xA, 5850 + 0xA, 40, 6, 20, 0),
274 }};
275
276 #ifdef CONFIG_AP6XXX_WIFI6_HDF
bdh6_get_regdomain(void)277 const struct ieee80211_regdomain *bdh6_get_regdomain(void)
278 {
279 return &brcm_regdom;
280 }
281 #endif
282
283 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
284 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0x6))
285 _Pragma("GCC diagnostic pop")
286 #endif // endif
287
288 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
289 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
290 static const struct ieee80211_iface_limit common_if_limits[] = {
291 {
292 /*
293 * Driver can support up to 2 AP's
294 */
295 .max = 2,
296 .types = BIT(NL80211_IFTYPE_AP),
297 },
298 {
299 /*
300 * During P2P-GO removal, P2P-GO is first changed to STA and later only
301 * removed. So setting maximum possible number of STA interfaces according
302 * to kernel version.
303 *
304 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
305 * linux-3.8 and above - max:4
306 * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
307 * for NAN defined, registering it as STA type)
308 */
309 #ifdef WL_ENABLE_P2P_IF
310 .max = 5,
311 #else
312 .max = 4,
313 #endif /* WL_ENABLE_P2P_IF */
314 .types = BIT(NL80211_IFTYPE_STATION),
315 },
316 {
317 .max = 2,
318 .types = BIT(NL80211_IFTYPE_P2P_GO) |
319 BIT(NL80211_IFTYPE_P2P_CLIENT),
320 },
321 #if defined(WL_CFG80211_P2P_DEV_IF)
322 {
323 .max = 1,
324 .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
325 },
326 #endif /* WL_CFG80211_P2P_DEV_IF */
327 {
328 .max = 1,
329 .types = BIT(NL80211_IFTYPE_ADHOC),
330 },
331 };
332
333 #define NUM_DIFF_CHANNELS 2
334
335 static const struct ieee80211_iface_combination common_iface_combinations[] = {
336 {
337 .num_different_channels = NUM_DIFF_CHANNELS,
338 /*
339 * At Max 5 network interfaces can be registered concurrently
340 */
341 .max_interfaces = IFACE_MAX_CNT,
342 .limits = common_if_limits,
343 .n_limits = ARRAY_SIZE(common_if_limits),
344 },
345 };
346 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || \
347 WL_CFG80211_P2P_DEV_IF) */
348
349 static const char *wl_if_state_strs[WL_IF_STATE_MAX + 1] = {
350 "WL_IF_CREATE_REQ", "WL_IF_CREATE_DONE", "WL_IF_DELETE_REQ",
351 "WL_IF_DELETE_DONE", "WL_IF_CHANGE_REQ", "WL_IF_CHANGE_DONE",
352 "WL_IF_STATE_MAX"};
353
354 #ifdef BCMWAPI_WPI
355 #if defined(ANDROID_PLATFORM_VERSION) && (ANDROID_PLATFORM_VERSION >= 8)
356 /* WAPI define in ieee80211.h is used */
357 #else
358 #undef WLAN_AKM_SUITE_WAPI_PSK
359 #define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04
360
361 #undef WLAN_AKM_SUITE_WAPI_CERT
362 #define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12
363
364 #undef NL80211_WAPI_VERSION_1
365 #define NL80211_WAPI_VERSION_1 1 << 2
366 #endif /* ANDROID_PLATFORM_VERSION && ANDROID_PLATFORM_VERSION >= 8 */
367 #endif /* BCMWAPI_WPI */
368
369 /* Data Element Definitions */
370 #define WPS_ID_CONFIG_METHODS 0x1008
371 #define WPS_ID_REQ_TYPE 0x103A
372 #define WPS_ID_DEVICE_NAME 0x1011
373 #define WPS_ID_VERSION 0x104A
374 #define WPS_ID_DEVICE_PWD_ID 0x1012
375 #define WPS_ID_REQ_DEV_TYPE 0x106A
376 #define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
377 #define WPS_ID_PRIM_DEV_TYPE 0x1054
378
379 /* Device Password ID */
380 #define DEV_PW_DEFAULT 0x0000
381 #define DEV_PW_USER_SPECIFIED 0x0001,
382 #define DEV_PW_MACHINE_SPECIFIED 0x0002
383 #define DEV_PW_REKEY 0x0003
384 #define DEV_PW_PUSHBUTTON 0x0004
385 #define DEV_PW_REGISTRAR_SPECIFIED 0x0005
386
387 /* Config Methods */
388 #define WPS_CONFIG_USBA 0x0001
389 #define WPS_CONFIG_ETHERNET 0x0002
390 #define WPS_CONFIG_LABEL 0x0004
391 #define WPS_CONFIG_DISPLAY 0x0008
392 #define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
393 #define WPS_CONFIG_INT_NFC_TOKEN 0x0020
394 #define WPS_CONFIG_NFC_INTERFACE 0x0040
395 #define WPS_CONFIG_PUSHBUTTON 0x0080
396 #define WPS_CONFIG_KEYPAD 0x0100
397 #define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
398 #define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
399 #define WPS_CONFIG_VIRT_DISPLAY 0x2008
400 #define WPS_CONFIG_PHY_DISPLAY 0x4008
401
402 #define PM_BLOCK 1
403 #define PM_ENABLE 0
404
405 /* GCMP crypto supported above kernel v4.0 */
406 #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0))
407 #define WL_GCMP
408 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0) */
409
410 #ifndef IBSS_COALESCE_ALLOWED
411 #define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT
412 #endif // endif
413
414 #ifndef IBSS_INITIAL_SCAN_ALLOWED
415 #define IBSS_INITIAL_SCAN_ALLOWED IBSS_INITIAL_SCAN_ALLOWED_DEFAULT
416 #endif // endif
417
418 #define CUSTOM_RETRY_MASK \
419 0xff000000 /* Mask for retry counter of custom dwell time */
420 #define LONG_LISTEN_TIME 2000
421
422 #ifdef RTT_SUPPORT
423 static s32 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg,
424 bcm_struct_cfgdev *cfgdev,
425 const wl_event_msg_t *e, void *data);
426 #endif /* RTT_SUPPORT */
427 #ifdef WL_CHAN_UTIL
428 static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg,
429 bcm_struct_cfgdev *cfgdev,
430 const wl_event_msg_t *e,
431 void *data);
432 static s32 wl_cfg80211_start_bssload_report(struct net_device *ndev);
433 #endif /* WL_CHAN_UTIL */
434
435 #ifdef SUPPORT_AP_RADIO_PWRSAVE
436 #define RADIO_PWRSAVE_PPS 10
437 #define RADIO_PWRSAVE_QUIET_TIME 10
438 #define RADIO_PWRSAVE_LEVEL 3
439 #define RADIO_PWRSAVE_STAS_ASSOC_CHECK 0
440
441 #define RADIO_PWRSAVE_LEVEL_MIN 1
442 #define RADIO_PWRSAVE_LEVEL_MAX 9
443 #define RADIO_PWRSAVE_PPS_MIN 1
444 #define RADIO_PWRSAVE_QUIETTIME_MIN 1
445 #define RADIO_PWRSAVE_ASSOCCHECK_MIN 0
446 #define RADIO_PWRSAVE_ASSOCCHECK_MAX 1
447
448 #define RADIO_PWRSAVE_MAJOR_VER 1
449 #define RADIO_PWRSAVE_MINOR_VER 1
450 #define RADIO_PWRSAVE_MAJOR_VER_SHIFT 8
451 #define RADIO_PWRSAVE_VERSION \
452 ((RADIO_PWRSAVE_MAJOR_VER << RADIO_PWRSAVE_MAJOR_VER_SHIFT) | \
453 RADIO_PWRSAVE_MINOR_VER)
454 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
455
456 /* SoftAP related parameters */
457 #define DEFAULT_2G_SOFTAP_CHANNEL 1
458 #define DEFAULT_5G_SOFTAP_CHANNEL 149
459 #define WL_MAX_NUM_CSA_COUNTERS 255
460
461 #define MAX_VNDR_OUI_STR_LEN 256u
462 #define VNDR_OUI_STR_LEN 10u
463 #define DOT11_DISCONNECT_RC 2u
464 static const uchar *exclude_vndr_oui_list[] = {
465 "\x00\x50\xf2", /* Microsoft */
466 "\x00\x00\xf0", /* Samsung Elec */
467 WFA_OUI, /* WFA */
468 NULL};
469
470 typedef struct wl_vndr_oui_entry {
471 uchar oui[DOT11_OUI_LEN];
472 struct list_head list;
473 } wl_vndr_oui_entry_t;
474
475 #if defined(WL_DISABLE_HE_SOFTAP) || defined(WL_DISABLE_HE_P2P) || \
476 defined(SUPPORT_AP_BWCTRL)
477 #define WL_HE_FEATURES_HE_AP 0x8
478 #define WL_HE_FEATURES_HE_P2P 0x20
479 #endif // endif
480
481 static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
482 struct net_device *ndev, char *vndr_oui,
483 u32 vndr_oui_len);
484 static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg);
485 static s32 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
486 struct parsed_vndr_ies *vndr_ies);
487
488 #if defined(WL_FW_OCE_AP_SELECT)
489 static bool wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
490 const u8 *oui, u32 oui_len, u8 type);
491
492 /* Check whether the given IE looks like WFA OCE IE. */
493 #define wl_cfgoce_is_oce_ie(ie, tlvs, len) \
494 wl_cfgoce_has_ie(ie, tlvs, len, (const uint8 *)WFA_OUI, WFA_OUI_LEN, \
495 WFA_OUI_TYPE_MBO_OCE)
496
497 /* Is any of the tlvs the expected entry? If
498 * not update the tlvs buffer pointer/length.
499 */
wl_cfgoce_has_ie(const u8 * ie,const u8 ** tlvs,u32 * tlvs_len,const u8 * oui,u32 oui_len,u8 type)500 static bool wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
501 const u8 *oui, u32 oui_len, u8 type)
502 {
503 /* If the contents match the OUI and the type */
504 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
505 !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
506 type == ie[TLV_BODY_OFF + oui_len]) {
507 return TRUE;
508 }
509
510 return FALSE;
511 }
512 #endif /* WL_FW_OCE_AP_SELECT */
513
514 /*
515 * cfg80211_ops api/callback list
516 */
517 static s32 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
518 const struct ether_addr *da,
519 const struct ether_addr *sa,
520 const struct ether_addr *bssid, u8 **pheader,
521 u32 *body_len, u8 *pbody);
522 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
523 #ifdef WLAIBSS_MCHAN
524 static bcm_struct_cfgdev *bcm_cfg80211_add_ibss_if(struct wiphy *wiphy,
525 char *name);
526 static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy,
527 bcm_struct_cfgdev *cfgdev);
528 #endif /* WLAIBSS_MCHAN */
529 static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
530 struct cfg80211_ibss_params *params);
531 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
532 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
533 static s32 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
534 const u8 *mac, struct station_info *sinfo);
535 #else
536 static s32 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
537 u8 *mac, struct station_info *sinfo);
538 #endif // endif
539 static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
540 struct net_device *dev, bool enabled,
541 s32 timeout);
542 #ifndef CONFIG_AP6XXX_WIFI6_HDF
543 static
544 #endif
545 int
546 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
547 struct cfg80211_connect_params *sme);
548 #if defined(WL_FILS)
549 static int
550 wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
551 struct cfg80211_connect_params *sme,
552 u32 changed);
553 #endif /* WL_FILS */
554 #ifndef CONFIG_AP6XXX_WIFI6_HDF
555 static
556 #endif
557 s32
558 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
559 u16 reason_code);
560 #if defined(WL_CFG80211_P2P_DEV_IF)
561 static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
562 struct wireless_dev *wdev,
563 enum nl80211_tx_power_setting type,
564 s32 mbm);
565 #else
566 static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
567 enum nl80211_tx_power_setting type,
568 s32 dbm);
569 #endif /* WL_CFG80211_P2P_DEV_IF */
570 #if defined(WL_CFG80211_P2P_DEV_IF)
571 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
572 struct wireless_dev *wdev, s32 *dbm);
573 #else
574 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
575 #endif /* WL_CFG80211_P2P_DEV_IF */
576 static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
577 struct net_device *dev, u8 key_idx,
578 bool unicast, bool multicast);
579 static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
580 u8 key_idx, bool pairwise, const u8 *mac_addr,
581 struct key_params *params);
582 static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
583 u8 key_idx, bool pairwise, const u8 *mac_addr);
584 static s32
585 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx,
586 bool pairwise, const u8 *mac_addr, void *cookie,
587 void (*callback)(void *cookie, struct key_params *params));
588 static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
589 struct net_device *dev,
590 u8 key_idx);
591 static s32 wl_cfg80211_resume(struct wiphy *wiphy);
592 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || \
593 (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
594 static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
595 bcm_struct_cfgdev *cfgdev,
596 u64 cookie);
597 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
598 static s32 wl_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
599 struct station_del_parameters *params);
600 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
601 static s32 wl_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
602 const u8 *mac_addr);
603 #else
604 static s32 wl_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
605 u8 *mac_addr);
606 #endif // endif
607 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
608 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
609 struct net_device *dev, const u8 *mac,
610 struct station_parameters *params);
611 #else
612 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
613 struct net_device *dev, u8 *mac,
614 struct station_parameters *params);
615 #endif // endif
616 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, \
617 0)) */
618 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
619 defined(WL_COMPAT_WIRELESS)
620 static s32 wl_cfg80211_suspend(struct wiphy *wiphy,
621 struct cfg80211_wowlan *wow);
622 #else
623 static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
624 #endif // endif
625 static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
626 struct cfg80211_pmksa *pmksa);
627 static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
628 struct cfg80211_pmksa *pmksa);
629 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev);
630 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \
631 defined(WL_COMPAT_WIRELESS)
632 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || \
633 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) && \
634 LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
635 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
636 u8 *peer, u8 action_code, u8 dialog_token,
637 u16 status_code, u32 peer_capability,
638 const u8 *buf, size_t len);
639 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
640 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
641 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
642 const u8 *peer, u8 action_code,
643 u8 dialog_token, u16 status_code,
644 u32 peer_capability, const u8 *buf,
645 size_t len);
646 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
647 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
648 const u8 *peer, u8 action_code,
649 u8 dialog_token, u16 status_code,
650 u32 peer_capability, bool initiator,
651 const u8 *buf, size_t len);
652 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
653 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
654 u8 *peer, u8 action_code, u8 dialog_token,
655 u16 status_code, const u8 *buf, size_t len);
656 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
657 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
658 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
659 const u8 *peer,
660 enum nl80211_tdls_operation oper);
661 #else
662 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
663 u8 *peer, enum nl80211_tdls_operation oper);
664 #endif // endif
665 #endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
666 static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg,
667 struct net_device *dev);
668
669 struct wireless_dev *wl_cfg80211_create_iface(struct wiphy *wiphy,
670 wl_iftype_t iface_type,
671 u8 *mac_addr, const char *name);
672 s32 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
673
674 s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, struct net_device *ndev,
675 s32 bsscfg_idx, wl_iftype_t iftype, s32 del,
676 u8 *addr);
677 s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
678 s32 bsscfg_idx, wl_iftype_t brcm_iftype, s32 del,
679 u8 *addr);
680 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
681 defined(WL_COMPAT_WIRELESS)
682 static s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev);
683 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */
684 #ifdef GTK_OFFLOAD_SUPPORT
685 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
686 static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy,
687 struct net_device *dev,
688 struct cfg80211_gtk_rekey_data *data);
689 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
690 #endif /* GTK_OFFLOAD_SUPPORT */
691 chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
692 chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
693 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg,
694 struct net_device *dev);
695 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
696 int wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
697 struct cfg80211_csa_settings *params);
698 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
699
700 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
701 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
702 const struct cfg80211_pmk_conf *conf);
703 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
704 const u8 *aa);
705 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
706
707 /*
708 * event & event Q handlers for cfg80211 interfaces
709 */
710 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
711 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
712 static void wl_event_handler(struct work_struct *work_data);
713 static void wl_init_eq(struct bcm_cfg80211 *cfg);
714 static void wl_flush_eq(struct bcm_cfg80211 *cfg);
715 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
716 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
717 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
718 static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
719 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
720 static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev,
721 u32 type, const wl_event_msg_t *msg, void *data);
722 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e);
723 static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg,
724 struct net_device *ndev,
725 const wl_event_msg_t *e, void *data);
726 static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
727 bcm_struct_cfgdev *cfgdev,
728 const wl_event_msg_t *e, void *data);
729 static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
730 bcm_struct_cfgdev *cfgdev,
731 const wl_event_msg_t *e, void *data);
732 static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg,
733 struct net_device *ndev, const wl_event_msg_t *e,
734 void *data, bool completed);
735 static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg,
736 struct net_device *ndev, const wl_event_msg_t *e,
737 void *data);
738 static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg,
739 bcm_struct_cfgdev *cfgdev,
740 const wl_event_msg_t *e, void *data);
741 #ifdef BT_WIFI_HANDOVER
742 static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
743 bcm_struct_cfgdev *cfgdev,
744 const wl_event_msg_t *e, void *data);
745 #endif /* BT_WIFI_HANDOVER */
746 #ifdef GSCAN_SUPPORT
747 static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl,
748 bcm_struct_cfgdev *cfgdev,
749 const wl_event_msg_t *e, void *data);
750 #endif /* GSCAN_SUPPORT */
751 #ifdef RSSI_MONITOR_SUPPORT
752 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl,
753 bcm_struct_cfgdev *cfgdev,
754 const wl_event_msg_t *e, void *data);
755 #endif /* RSSI_MONITOR_SUPPORT */
756 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg,
757 struct net_info *_net_info,
758 enum wl_status state, bool set);
759 #ifdef CUSTOM_EVENT_PM_WAKE
760 static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg,
761 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e,
762 void *data);
763 #endif /* CUSTOM_EVENT_PM_WAKE */
764 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
765 static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
766 bcm_struct_cfgdev *cfgdev,
767 const wl_event_msg_t *e, void *data);
768 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
769 #ifdef DHD_LOSSLESS_ROAMING
770 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
771 #endif /* DHD_LOSSLESS_ROAMING */
772
773 #ifdef WL_MBO
774 static s32 wl_mbo_event_handler(struct bcm_cfg80211 *cfg,
775 bcm_struct_cfgdev *cfgdev,
776 const wl_event_msg_t *e, void *data);
777 #endif /* WL_MBO */
778
779 #ifdef WL_CLIENT_SAE
780 static bool wl_is_pmkid_available(struct net_device *dev, const u8 *bssid);
781 static s32 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
782 bcm_struct_cfgdev *cfgdev,
783 const wl_event_msg_t *e, void *data);
784 static s32 wl_handle_auth_event(struct bcm_cfg80211 *cfg,
785 struct net_device *ndev,
786 const wl_event_msg_t *e, void *data);
787 static s32
788 wl_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *dev,
789 struct cfg80211_external_auth_params *ext_auth);
790 static s32 wl_cfg80211_mgmt_auth_tx(struct net_device *dev,
791 bcm_struct_cfgdev *cfgdev,
792 struct bcm_cfg80211 *cfg, const u8 *buf,
793 size_t len, s32 bssidx, u64 *cookie);
794 #endif /* WL_CLIENT_SAE */
795 static s32 wl_cfg80211_config_rsnxe_ie(struct net_device *dev, const u8 *parse,
796 u32 len);
797
798 /*
799 * register/deregister parent device
800 */
801 static void wl_cfg80211_clear_parent_dev(void);
802 /*
803 * ioctl utilites
804 */
805
806 /*
807 * cfg80211 set_wiphy_params utilities
808 */
809 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
810 static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
811 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
812
813 /*
814 * cfg profile utilities
815 */
816 static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
817 const wl_event_msg_t *e, const void *data, s32 item);
818 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
819
820 /*
821 * cfg80211 connect utilites
822 */
823 static s32 wl_set_wpa_version(struct net_device *dev,
824 struct cfg80211_connect_params *sme);
825 static s32 wl_set_auth_type(struct net_device *dev,
826 struct cfg80211_connect_params *sme);
827 static s32 wl_set_set_cipher(struct net_device *dev,
828 struct cfg80211_connect_params *sme);
829 static s32 wl_set_key_mgmt(struct net_device *dev,
830 struct cfg80211_connect_params *sme);
831 static s32 wl_set_set_sharedkey(struct net_device *dev,
832 struct cfg80211_connect_params *sme);
833 #ifdef WL_FILS
834 static s32 wl_set_fils_params(struct net_device *dev,
835 struct cfg80211_connect_params *sme);
836 #endif // endif
837 #ifdef BCMWAPI_WPI
838 static s32 wl_set_set_wapi_ie(struct net_device *dev,
839 struct cfg80211_connect_params *sme);
840 #endif // endif
841 #ifdef WL_GCMP
842 static s32 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos,
843 uint32 mask);
844 #endif /* WL_GCMP */
845 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
846 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch,
847 struct wl_join_params *join_params,
848 size_t *join_params_size);
849 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
850
851 /*
852 * information element utilities
853 */
854 static void wl_rst_ie(struct bcm_cfg80211 *cfg);
855 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
856 static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream,
857 u32 *ie_size, bool update_ssid);
858 static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size);
859 static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size);
860 static u32 wl_get_ielen(struct bcm_cfg80211 *cfg);
861 #ifdef MFP
862 static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie,
863 const u8 **rsn_cap);
864 #endif // endif
865
866 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev,
867 dhd_pub_t *data);
868 static void wl_free_wdev(struct bcm_cfg80211 *cfg);
869 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
870 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
871 static int
872 #else
873 static void
874 #endif /* kernel version < 3.10.11 */
875 wl_cfg80211_reg_notifier(struct wiphy *wiphy,
876 struct regulatory_request *request);
877 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
878
879 static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi,
880 bool update_ssid);
881 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
882 bool update_ssid);
883 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
884 s32 wl_cfg80211_channel_to_freq(u32 channel);
885 static void wl_cfg80211_work_handler(struct work_struct *work);
886 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
887 u8 key_idx, const u8 *mac_addr,
888 struct key_params *params);
889 /*
890 * key indianess swap utilities
891 */
892 static void swap_key_from_BE(struct wl_wsec_key *key);
893 static void swap_key_to_BE(struct wl_wsec_key *key);
894
895 /*
896 * bcm_cfg80211 memory init/deinit utilities
897 */
898 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
899 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
900
901 static void wl_delay(u32 ms);
902
903 /*
904 * ibss mode utilities
905 */
906 static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev);
907 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
908
909 /*
910 * link up/down , default configuration utilities
911 */
912 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
913 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
914 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
915
916 static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
917 struct net_device *ndev);
918 static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
919 static void wl_link_up(struct bcm_cfg80211 *cfg);
920 static void wl_link_down(struct bcm_cfg80211 *cfg);
921 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev,
922 u16 iftype);
923 static void wl_init_conf(struct wl_conf *conf);
924 int wl_cfg80211_get_ioctl_version(void);
925
926 /*
927 * find most significant bit set
928 */
929 static __used u32 wl_find_msb(u16 bit16);
930
931 /*
932 * rfkill support
933 */
934 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
935 static int wl_rfkill_set(void *data, bool blocked);
936 #ifdef DEBUGFS_CFG80211
937 static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg);
938 static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg);
939 #endif // endif
940 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
941
942 #ifdef WL_CFG80211_ACL
943 /* ACL */
944 static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy,
945 struct net_device *cfgdev,
946 const struct cfg80211_acl_data *acl);
947 #endif /* WL_CFG80211_ACL */
948
949 /*
950 * Some external functions, move them to dhd_linux.h
951 */
952 int dhd_add_monitor(const char *name, struct net_device **new_ndev);
953 int dhd_del_monitor(struct net_device *ndev);
954 int dhd_monitor_init(void *dhd_pub);
955 int dhd_monitor_uninit(void);
956 netdev_tx_t dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
957
958 #ifdef ESCAN_CHANNEL_CACHE
959 void reset_roam_cache(struct bcm_cfg80211 *cfg);
960 void add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi);
961 int get_roam_channel_list(int target_chan, chanspec_t *channels, int n_channels,
962 const wlc_ssid_t *ssid, int ioctl_ver);
963 void set_roam_band(int band);
964 #endif /* ESCAN_CHANNEL_CACHE */
965
966 #ifdef ROAM_CHANNEL_CACHE
967 int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
968 void print_roam_cache(struct bcm_cfg80211 *cfg);
969 void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
970 #endif /* ROAM_CHANNEL_CACHE */
971
972 #ifdef P2P_LISTEN_OFFLOADING
973 s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
974 #endif /* P2P_LISTEN_OFFLOADING */
975
976 #ifdef PKT_FILTER_SUPPORT
977 extern uint dhd_pkt_filter_enable;
978 extern uint dhd_master_mode;
979 extern void dhd_pktfilter_offload_enable(dhd_pub_t *dhd, char *arg, int enable,
980 int master_mode);
981 #endif /* PKT_FILTER_SUPPORT */
982
983 #ifdef SUPPORT_SET_CAC
984 static void wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable);
985 #endif /* SUPPORT_SET_CAC */
986
987 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg,
988 struct net_device *ndev,
989 const struct ether_addr *bssid);
990 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
991
992 #ifdef WL_WPS_SYNC
993 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg);
994 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg);
995 static void wl_wps_reauth_timeout(unsigned long data);
996 static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg);
997 static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg,
998 struct net_device *ndev);
999 static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *peer_mac);
1000 static void wl_wps_session_del(struct net_device *ndev);
1001 static s32 wl_wps_session_update(struct net_device *ndev, u16 state,
1002 const u8 *peer_mac);
1003 static void wl_wps_handle_ifdel(struct net_device *ndev);
1004 #endif /* WL_WPS_SYNC */
1005
1006 #if defined(WL_FW_OCE_AP_SELECT)
1007 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint);
1008 #endif /* WL_FW_OCE_AP_SELECT */
1009
1010 #ifdef WL_BCNRECV
1011 static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg,
1012 bcm_struct_cfgdev *cfgdev,
1013 const wl_event_msg_t *e,
1014 void *data);
1015 #endif /* WL_BCNRECV */
1016
1017 #ifdef WL_CAC_TS
1018 static s32 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg,
1019 bcm_struct_cfgdev *cfgdev,
1020 const wl_event_msg_t *e, void *data);
1021 #endif /* WL_CAC_TS */
1022
1023 #if defined(WL_MBO) || defined(WL_OCE)
1024 static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg,
1025 bcm_struct_cfgdev *cfgdev,
1026 const wl_event_msg_t *e, void *data);
1027 #endif /* WL_MBO || WL_OCE */
1028
1029 static int bw2cap[] = {0,
1030 0,
1031 WLC_BW_CAP_20MHZ,
1032 WLC_BW_CAP_40MHZ,
1033 WLC_BW_CAP_80MHZ,
1034 WLC_BW_CAP_160MHZ,
1035 WLC_BW_CAP_160MHZ};
1036
1037 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || \
1038 (defined(CONFIG_ARCH_MSM) && defined(CFG80211_DISCONNECTED_V2))
1039 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
1040 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
1041 IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
1042 #else
1043 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
1044 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
1045 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
1046 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
1047
1048 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
1049 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
1050 defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || defined(WL_FILS) || \
1051 defined(CONFIG_CFG80211_FILS_BKPORT)
1052 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1053 resp_ie_len, status, gfp) \
1054 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1055 resp_ie_len, status, gfp, \
1056 NL80211_TIMEOUT_UNSPECIFIED);
1057 #else
1058 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1059 resp_ie_len, status, gfp) \
1060 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1061 resp_ie_len, status, gfp);
1062 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
1063 * (CFG80211_CONNECT_TIMEOUT_REASON_CODE) || \
1064 * WL_FILS || CONFIG_CFG80211_FILS_BKPORT \
1065 */
1066 #elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
1067 /* There are customer kernels with backported changes for
1068 * connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
1069 * is available for kernels < 4.7 in such cases.
1070 */
1071 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1072 resp_ie_len, status, gfp) \
1073 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1074 resp_ie_len, status, gfp, \
1075 NL80211_TIMEOUT_UNSPECIFIED);
1076 #else
1077 /* Kernels < 4.7 doesn't support cfg80211_connect_bss */
1078 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1079 resp_ie_len, status, gfp) \
1080 cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
1081 resp_ie_len, status, gfp);
1082 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
1083
1084 #define IS_WPA_AKM(akm) \
1085 ((akm) == RSN_AKM_NONE || (akm) == RSN_AKM_UNSPECIFIED || \
1086 (akm) == RSN_AKM_PSK)
1087
1088 extern int dhd_wait_pend8021x(struct net_device *dev);
1089 #ifdef PROP_TXSTATUS_VSDB
1090 extern int disable_proptx;
1091 #endif /* PROP_TXSTATUS_VSDB */
1092
1093 static s32 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1094 const wl_event_msg_t *e, void *data);
1095 static s32 wl_csa_complete_ind(struct bcm_cfg80211 *cfg,
1096 bcm_struct_cfgdev *cfgdev,
1097 const wl_event_msg_t *e, void *data);
1098 #ifdef SUPPORT_AP_BWCTRL
1099 static void wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg,
1100 struct net_device *ndev,
1101 chanspec_t chanspec);
1102 static void wl_restore_ap_bw(struct bcm_cfg80211 *cfg);
1103 #endif /* SUPPORT_AP_BWCTRL */
1104
1105 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) && \
1106 (LINUX_VERSION_CODE <= (3, 7, 0)))
1107 struct chan_info {
1108 int freq;
1109 int chan_type;
1110 };
1111 #endif // endif
1112
1113 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
1114 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(wiphy, bss);
1115 #else
1116 #define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(bss);
1117 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
1118
1119 #define CHAN2G(_channel, _freq, _flags) \
1120 { \
1121 .band = IEEE80211_BAND_2GHZ, .center_freq = (_freq), \
1122 .hw_value = (_channel), .flags = (_flags), .max_antenna_gain = 0, \
1123 .max_power = 30, \
1124 }
1125
1126 #define CHAN5G(_channel, _flags) \
1127 { \
1128 .band = IEEE80211_BAND_5GHZ, .center_freq = 0x1388 + (5 * (_channel)), \
1129 .hw_value = (_channel), .flags = (_flags), .max_antenna_gain = 0, \
1130 .max_power = 30, \
1131 }
1132
1133 #define RATE_TO_BASE100KBPS(rate) (((rate) * 0xA) / 0x2)
1134 #define RATETAB_ENT(_rateid, _flags) \
1135 { \
1136 .bitrate = RATE_TO_BASE100KBPS(_rateid), .hw_value = (_rateid), \
1137 .flags = (_flags), \
1138 }
1139
1140 static struct ieee80211_rate __wl_rates[] = {
1141 RATETAB_ENT(DOT11_RATE_1M, 0),
1142 RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
1143 RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
1144 RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
1145 RATETAB_ENT(DOT11_RATE_6M, 0),
1146 RATETAB_ENT(DOT11_RATE_9M, 0),
1147 RATETAB_ENT(DOT11_RATE_12M, 0),
1148 RATETAB_ENT(DOT11_RATE_18M, 0),
1149 RATETAB_ENT(DOT11_RATE_24M, 0),
1150 RATETAB_ENT(DOT11_RATE_36M, 0),
1151 RATETAB_ENT(DOT11_RATE_48M, 0),
1152 RATETAB_ENT(DOT11_RATE_54M, 0)};
1153
1154 #define wl_a_rates (__wl_rates + 4)
1155 #define wl_a_rates_size 8
1156 #define wl_g_rates (__wl_rates + 0)
1157 #define wl_g_rates_size 12
1158
1159 static struct ieee80211_channel __wl_2ghz_channels[] = {
1160 CHAN2G(1, 2412, 0), CHAN2G(2, 2417, 0), CHAN2G(3, 2422, 0),
1161 CHAN2G(4, 2427, 0), CHAN2G(5, 2432, 0), CHAN2G(6, 2437, 0),
1162 CHAN2G(7, 2442, 0), CHAN2G(8, 2447, 0), CHAN2G(9, 2452, 0),
1163 CHAN2G(10, 2457, 0), CHAN2G(11, 2462, 0), CHAN2G(12, 2467, 0),
1164 CHAN2G(13, 2472, 0), CHAN2G(14, 2484, 0)};
1165
1166 static struct ieee80211_channel __wl_5ghz_a_channels[] = {
1167 CHAN5G(34, 0), CHAN5G(36, 0), CHAN5G(38, 0), CHAN5G(40, 0),
1168 CHAN5G(42, 0), CHAN5G(44, 0), CHAN5G(46, 0), CHAN5G(48, 0),
1169 CHAN5G(52, 0), CHAN5G(56, 0), CHAN5G(60, 0), CHAN5G(64, 0),
1170 CHAN5G(100, 0), CHAN5G(104, 0), CHAN5G(108, 0), CHAN5G(112, 0),
1171 CHAN5G(116, 0), CHAN5G(120, 0), CHAN5G(124, 0), CHAN5G(128, 0),
1172 CHAN5G(132, 0), CHAN5G(136, 0), CHAN5G(140, 0), CHAN5G(144, 0),
1173 CHAN5G(149, 0), CHAN5G(153, 0), CHAN5G(157, 0), CHAN5G(161, 0),
1174 CHAN5G(165, 0)};
1175
1176 static struct ieee80211_supported_band __wl_band_2ghz = {
1177 .band = IEEE80211_BAND_2GHZ,
1178 .channels = __wl_2ghz_channels,
1179 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
1180 .bitrates = wl_g_rates,
1181 .n_bitrates = wl_g_rates_size};
1182
1183 static struct ieee80211_supported_band __wl_band_5ghz_a = {
1184 .band = IEEE80211_BAND_5GHZ,
1185 .channels = __wl_5ghz_a_channels,
1186 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
1187 .bitrates = wl_a_rates,
1188 .n_bitrates = wl_a_rates_size};
1189
1190 static const u32 __wl_cipher_suites[] = {
1191 WLAN_CIPHER_SUITE_WEP40,
1192 WLAN_CIPHER_SUITE_WEP104,
1193 WLAN_CIPHER_SUITE_TKIP,
1194 WLAN_CIPHER_SUITE_CCMP,
1195 #ifdef MFP
1196 /*
1197 * Advertising AES_CMAC cipher suite to userspace would imply that we
1198 * are supporting MFP. So advertise only when MFP support is enabled.
1199 */
1200 WLAN_CIPHER_SUITE_AES_CMAC,
1201 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1202 WLAN_CIPHER_SUITE_BIP_GMAC_256,
1203 WLAN_CIPHER_SUITE_BIP_GMAC_128,
1204 WLAN_CIPHER_SUITE_BIP_CMAC_256,
1205 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1206 #endif /* MFP */
1207
1208 #ifdef BCMWAPI_WPI
1209 WLAN_CIPHER_SUITE_SMS4,
1210 #endif // endif
1211 #if defined(WLAN_CIPHER_SUITE_PMK)
1212 WLAN_CIPHER_SUITE_PMK,
1213 #endif /* WLAN_CIPHER_SUITE_PMK */
1214 #ifdef WL_GCMP
1215 WLAN_CIPHER_SUITE_GCMP,
1216 WLAN_CIPHER_SUITE_GCMP_256,
1217 WLAN_CIPHER_SUITE_BIP_GMAC_128,
1218 WLAN_CIPHER_SUITE_BIP_GMAC_256,
1219 #endif /* WL_GCMP */
1220 };
1221
1222 #ifdef WL_SUPPORT_ACS
1223 /*
1224 * The firmware code required for this feature to work is currently under
1225 * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1226 * required firmware code out of the BCMINTERNAL flag.
1227 */
1228 struct wl_dump_survey {
1229 u32 obss;
1230 u32 ibss;
1231 u32 no_ctg;
1232 u32 no_pckt;
1233 u32 tx;
1234 u32 idle;
1235 };
1236 #endif /* WL_SUPPORT_ACS */
1237
1238 #ifdef WL_CFG80211_GON_COLLISION
1239 #define BLOCK_GON_REQ_MAX_NUM 5
1240 #endif /* WL_CFG80211_GON_COLLISION */
1241
1242 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1243 static int maxrxpktglom = 0;
1244 #endif // endif
1245
1246 /* IOCtl version read from targeted driver */
1247 int ioctl_version;
1248 #ifdef DEBUGFS_CFG80211
1249 #define SUBLOGLEVEL 20
1250 #define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1))
1251 static const struct {
1252 u32 log_level;
1253 char *sublogname;
1254 } sublogname_map[] = {
1255 {WL_DBG_ERR, "ERR"}, {WL_DBG_INFO, "INFO"},
1256 {WL_DBG_DBG, "DBG"}, {WL_DBG_SCAN, "SCAN"},
1257 {WL_DBG_TRACE, "TRACE"}, {WL_DBG_P2P_ACTION, "P2PACTION"}};
1258 #endif // endif
1259
1260 typedef struct rsn_cipher_algo_entry {
1261 u32 cipher_suite;
1262 u32 wsec_algo;
1263 u32 wsec_key_algo;
1264 } rsn_cipher_algo_entry_t;
1265
1266 static const rsn_cipher_algo_entry_t rsn_cipher_algo_lookup_tbl[] = {
1267 {WLAN_CIPHER_SUITE_WEP40, WEP_ENABLED, CRYPTO_ALGO_WEP1},
1268 {WLAN_CIPHER_SUITE_WEP104, WEP_ENABLED, CRYPTO_ALGO_WEP128},
1269 {WLAN_CIPHER_SUITE_TKIP, TKIP_ENABLED, CRYPTO_ALGO_TKIP},
1270 {WLAN_CIPHER_SUITE_CCMP, AES_ENABLED, CRYPTO_ALGO_AES_CCM},
1271 {WLAN_CIPHER_SUITE_AES_CMAC, AES_ENABLED, CRYPTO_ALGO_BIP},
1272 #ifdef BCMWAPI_WPI
1273 {WLAN_CIPHER_SUITE_SMS4, SMS4_ENABLED, CRYPTO_ALGO_SMS4},
1274 #endif /* BCMWAPI_WPI */
1275 #ifdef WL_GCMP
1276 {WLAN_CIPHER_SUITE_GCMP, AES_ENABLED, CRYPTO_ALGO_AES_GCM},
1277 {WLAN_CIPHER_SUITE_GCMP_256, AES_ENABLED, CRYPTO_ALGO_AES_GCM256},
1278 {WLAN_CIPHER_SUITE_BIP_GMAC_128, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC},
1279 {WLAN_CIPHER_SUITE_BIP_GMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC256},
1280 #endif /* WL_GCMP */
1281 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1282 {WLAN_CIPHER_SUITE_BIP_CMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_CMAC256},
1283 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1284 };
1285
1286 typedef struct rsn_akm_wpa_auth_entry {
1287 u32 akm_suite;
1288 u32 wpa_auth;
1289 } rsn_akm_wpa_auth_entry_t;
1290
1291 static const rsn_akm_wpa_auth_entry_t rsn_akm_wpa_auth_lookup_tbl[] = {
1292 #ifdef WL_OWE
1293 {WLAN_AKM_SUITE_OWE, WPA3_AUTH_OWE},
1294 #endif /* WL_OWE */
1295 {WLAN_AKM_SUITE_8021X, WPA2_AUTH_UNSPECIFIED},
1296 {WL_AKM_SUITE_SHA256_1X, WPA2_AUTH_1X_SHA256},
1297 {WL_AKM_SUITE_SHA256_PSK, WPA2_AUTH_PSK_SHA256},
1298 {WLAN_AKM_SUITE_PSK, WPA2_AUTH_PSK},
1299 {WLAN_AKM_SUITE_FT_8021X, WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT},
1300 {WLAN_AKM_SUITE_FT_PSK, WPA2_AUTH_PSK | WPA2_AUTH_FT},
1301 {WLAN_AKM_SUITE_FILS_SHA256, WPA2_AUTH_FILS_SHA256},
1302 {WLAN_AKM_SUITE_FILS_SHA384, WPA2_AUTH_FILS_SHA384},
1303 {WLAN_AKM_SUITE_8021X_SUITE_B, WPA3_AUTH_1X_SUITE_B_SHA256},
1304 {WLAN_AKM_SUITE_8021X_SUITE_B_192, WPA3_AUTH_1X_SUITE_B_SHA384},
1305 #ifdef BCMWAPI_WPI
1306 {WLAN_AKM_SUITE_WAPI_CERT, WAPI_AUTH_UNSPECIFIED},
1307 {WLAN_AKM_SUITE_WAPI_PSK, WAPI_AUTH_PSK},
1308 #endif /* BCMWAPI_WPI */
1309 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
1310 {WLAN_AKM_SUITE_SAE, WPA3_AUTH_SAE_PSK},
1311 #endif /* WL_SAE || WL_CLIENT_SAE */
1312 {WLAN_AKM_SUITE_FT_8021X_SHA384,
1313 WPA3_AUTH_1X_SUITE_B_SHA384 | WPA2_AUTH_FT}};
1314
1315 #define BUFSZ 8
1316 #define BUFSZN BUFSZ + 1
1317
1318 #define _S(x) #x
1319 #define S(x) _S(x)
1320
1321 #define SOFT_AP_IF_NAME "swlan0"
1322
1323 /* watchdog timer for disconnecting when fw is not associated for
1324 * FW_ASSOC_WATCHDOG_TIME ms */
1325 uint32 fw_assoc_watchdog_ms = 0;
1326 bool fw_assoc_watchdog_started = 0;
1327 #define FW_ASSOC_WATCHDOG_TIME 0xA * 1000 /* msec */
1328
wl_add_remove_pm_enable_work(struct bcm_cfg80211 * cfg,enum wl_pm_workq_act_type type)1329 static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg,
1330 enum wl_pm_workq_act_type type)
1331 {
1332 u16 wq_duration = 0;
1333 dhd_pub_t *dhd = NULL;
1334
1335 if (cfg == NULL) {
1336 return;
1337 }
1338
1339 dhd = (dhd_pub_t *)(cfg->pub);
1340
1341 mutex_lock(&cfg->pm_sync);
1342 /*
1343 * Make cancel and schedule work part mutually exclusive
1344 * so that while cancelling, we are sure that there is no
1345 * work getting scheduled.
1346 */
1347 if (delayed_work_pending(&cfg->pm_enable_work)) {
1348 cancel_delayed_work(&cfg->pm_enable_work);
1349 DHD_PM_WAKE_UNLOCK(cfg->pub);
1350 }
1351
1352 if (type == WL_PM_WORKQ_SHORT) {
1353 wq_duration = WL_PM_ENABLE_TIMEOUT;
1354 } else if (type == WL_PM_WORKQ_LONG) {
1355 wq_duration = (WL_PM_ENABLE_TIMEOUT * 0x2);
1356 }
1357
1358 /* It should schedule work item only if driver is up */
1359 if (wq_duration && dhd->up) {
1360 if (schedule_delayed_work(
1361 &cfg->pm_enable_work,
1362 msecs_to_jiffies((const unsigned int)wq_duration))) {
1363 DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub, wq_duration);
1364 } else {
1365 WL_ERR(("Can't schedule pm work handler\n"));
1366 }
1367 }
1368 mutex_unlock(&cfg->pm_sync);
1369 }
1370
1371 /* Return a new chanspec given a legacy chanspec
1372 * Returns INVCHANSPEC on error
1373 */
wl_chspec_from_legacy(chanspec_t legacy_chspec)1374 chanspec_t wl_chspec_from_legacy(chanspec_t legacy_chspec)
1375 {
1376 chanspec_t chspec;
1377
1378 /* get the channel number */
1379 chspec = LCHSPEC_CHANNEL(legacy_chspec);
1380
1381 /* convert the band */
1382 if (LCHSPEC_IS2G(legacy_chspec)) {
1383 chspec |= WL_CHANSPEC_BAND_2G;
1384 } else {
1385 chspec |= WL_CHANSPEC_BAND_5G;
1386 }
1387
1388 /* convert the bw and sideband */
1389 if (LCHSPEC_IS20(legacy_chspec)) {
1390 chspec |= WL_CHANSPEC_BW_20;
1391 } else {
1392 chspec |= WL_CHANSPEC_BW_40;
1393 if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
1394 chspec |= WL_CHANSPEC_CTL_SB_L;
1395 } else {
1396 chspec |= WL_CHANSPEC_CTL_SB_U;
1397 }
1398 }
1399
1400 if (wf_chspec_malformed(chspec)) {
1401 WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1402 chspec));
1403 return INVCHANSPEC;
1404 }
1405
1406 return chspec;
1407 }
1408
1409 /* Return a legacy chanspec given a new chanspec
1410 * Returns INVCHANSPEC on error
1411 */
wl_chspec_to_legacy(chanspec_t chspec)1412 static chanspec_t wl_chspec_to_legacy(chanspec_t chspec)
1413 {
1414 chanspec_t lchspec;
1415
1416 if (wf_chspec_malformed(chspec)) {
1417 WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1418 chspec));
1419 return INVCHANSPEC;
1420 }
1421
1422 /* get the channel number */
1423 lchspec = CHSPEC_CHANNEL(chspec);
1424
1425 /* convert the band */
1426 if (CHSPEC_IS2G(chspec)) {
1427 lchspec |= WL_LCHANSPEC_BAND_2G;
1428 } else {
1429 lchspec |= WL_LCHANSPEC_BAND_5G;
1430 }
1431
1432 /* convert the bw and sideband */
1433 if (CHSPEC_IS20(chspec)) {
1434 lchspec |= WL_LCHANSPEC_BW_20;
1435 lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
1436 } else if (CHSPEC_IS40(chspec)) {
1437 lchspec |= WL_LCHANSPEC_BW_40;
1438 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
1439 lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
1440 } else {
1441 lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
1442 }
1443 } else {
1444 /* cannot express the bandwidth */
1445 char chanbuf[CHANSPEC_STR_LEN];
1446 WL_ERR(("wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1447 "to pre-11ac format\n",
1448 wf_chspec_ntoa(chspec, chanbuf), chspec));
1449 return INVCHANSPEC;
1450 }
1451
1452 return lchspec;
1453 }
1454
wl_cfg80211_is_hal_started(struct bcm_cfg80211 * cfg)1455 bool wl_cfg80211_is_hal_started(struct bcm_cfg80211 *cfg)
1456 {
1457 return cfg->hal_started;
1458 }
1459
1460 /* given a chanspec value, do the endian and chanspec version conversion to
1461 * a chanspec_t value
1462 * Returns INVCHANSPEC on error
1463 */
wl_chspec_host_to_driver(chanspec_t chanspec)1464 chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec)
1465 {
1466 if (ioctl_version == 1) {
1467 chanspec = wl_chspec_to_legacy(chanspec);
1468 if (chanspec == INVCHANSPEC) {
1469 return chanspec;
1470 }
1471 }
1472 chanspec = htodchanspec(chanspec);
1473
1474 return chanspec;
1475 }
1476
1477 /* given a channel value, do the endian and chanspec version conversion to
1478 * a chanspec_t value
1479 * Returns INVCHANSPEC on error
1480 */
wl_ch_host_to_driver(u16 channel)1481 chanspec_t wl_ch_host_to_driver(u16 channel)
1482 {
1483 chanspec_t chanspec;
1484 chanspec_band_t band;
1485
1486 band = WL_CHANNEL_BAND(channel);
1487
1488 chanspec = wf_create_20MHz_chspec(channel, band);
1489 if (chanspec == INVCHANSPEC) {
1490 return chanspec;
1491 }
1492
1493 return wl_chspec_host_to_driver(chanspec);
1494 }
1495
1496 /* given a chanspec value from the driver, do the endian and chanspec version
1497 * conversion to a chanspec_t value Returns INVCHANSPEC on error
1498 */
wl_chspec_driver_to_host(chanspec_t chanspec)1499 chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec)
1500 {
1501 chanspec = dtohchanspec(chanspec);
1502 if (ioctl_version == 1) {
1503 chanspec = wl_chspec_from_legacy(chanspec);
1504 }
1505
1506 return chanspec;
1507 }
1508
1509 /*
1510 * convert ASCII string to MAC address (colon-delimited format)
1511 * eg: 00:11:22:33:44:55
1512 */
wl_cfg80211_ether_atoe(const char * a,struct ether_addr * n)1513 int wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
1514 {
1515 char *c = NULL;
1516 int count = 0;
1517
1518 bzero(n, ETHER_ADDR_LEN);
1519 for (;;) {
1520 n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
1521 if (!*c++ || count == ETHER_ADDR_LEN) {
1522 break;
1523 }
1524 a = c;
1525 }
1526 return (count == ETHER_ADDR_LEN);
1527 }
1528
1529 /* There isn't a lot of sense in it, but you can transmit anything you like */
1530 static const struct ieee80211_txrx_stypes
1531 wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1532 #ifdef WLMESH_CFG80211
1533 [NL80211_IFTYPE_MESH_POINT] = {.tx = 0xffff,
1534 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1535 BIT(IEEE80211_STYPE_AUTH >> 4)},
1536 #endif /* WLMESH_CFG80211 */
1537 [NL80211_IFTYPE_ADHOC] = {.tx = 0xffff,
1538 .rx = BIT(IEEE80211_STYPE_ACTION >> 4)},
1539 [NL80211_IFTYPE_STATION] = {.tx = 0xffff,
1540 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1541 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1542 #ifdef WL_CLIENT_SAE
1543 | BIT(IEEE80211_STYPE_AUTH >> 4)
1544 #endif /* WL_CLIENT_SAE */
1545 },
1546 [NL80211_IFTYPE_AP] = {.tx = 0xffff,
1547 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1548 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1549 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1550 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1551 BIT(IEEE80211_STYPE_AUTH >> 4) |
1552 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1553 BIT(IEEE80211_STYPE_ACTION >> 4)},
1554 [NL80211_IFTYPE_AP_VLAN] =
1555 {
1556 .tx = 0xffff,
1557 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1558 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1559 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1560 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1561 BIT(IEEE80211_STYPE_AUTH >> 4) |
1562 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1563 BIT(IEEE80211_STYPE_ACTION >> 4)},
1564 [NL80211_IFTYPE_P2P_CLIENT] = {.tx = 0xffff,
1565 .rx =
1566 BIT(IEEE80211_STYPE_ACTION >> 4) |
1567 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)},
1568 [NL80211_IFTYPE_P2P_GO] = {.tx = 0xffff,
1569 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1570 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1571 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1572 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1573 BIT(IEEE80211_STYPE_AUTH >> 4) |
1574 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1575 BIT(IEEE80211_STYPE_ACTION >> 4)},
1576 #if defined(WL_CFG80211_P2P_DEV_IF)
1577 [NL80211_IFTYPE_P2P_DEVICE] = {.tx = 0xffff,
1578 .rx =
1579 BIT(IEEE80211_STYPE_ACTION >> 4) |
1580 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)},
1581 #endif /* WL_CFG80211_P2P_DEV_IF */
1582 };
1583
swap_key_from_BE(struct wl_wsec_key * key)1584 static void swap_key_from_BE(struct wl_wsec_key *key)
1585 {
1586 key->index = htod32(key->index);
1587 key->len = htod32(key->len);
1588 key->algo = htod32(key->algo);
1589 key->flags = htod32(key->flags);
1590 key->rxiv.hi = htod32(key->rxiv.hi);
1591 key->rxiv.lo = htod16(key->rxiv.lo);
1592 key->iv_initialized = htod32(key->iv_initialized);
1593 }
1594
swap_key_to_BE(struct wl_wsec_key * key)1595 static void swap_key_to_BE(struct wl_wsec_key *key)
1596 {
1597 key->index = dtoh32(key->index);
1598 key->len = dtoh32(key->len);
1599 key->algo = dtoh32(key->algo);
1600 key->flags = dtoh32(key->flags);
1601 key->rxiv.hi = dtoh32(key->rxiv.hi);
1602 key->rxiv.lo = dtoh16(key->rxiv.lo);
1603 key->iv_initialized = dtoh32(key->iv_initialized);
1604 }
1605
1606 #if defined(WL_FW_OCE_AP_SELECT)
wl_cfg80211_is_oce_ap(struct wiphy * wiphy,const u8 * bssid_hint)1607 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint)
1608 {
1609 const u8 *parse = NULL;
1610 bcm_tlv_t *ie;
1611 const struct cfg80211_bss_ies *ies;
1612 u32 len;
1613 struct cfg80211_bss *bss;
1614
1615 bss = CFG80211_GET_BSS(wiphy, NULL, bssid_hint, 0, 0);
1616 if (!bss) {
1617 WL_ERR(("Unable to find AP in the cache"));
1618 return false;
1619 }
1620
1621 if (rcu_access_pointer(bss->ies)) {
1622 ies = rcu_access_pointer(bss->ies);
1623 parse = ies->data;
1624 len = ies->len;
1625 } else {
1626 WL_ERR(("ies is NULL"));
1627 return false;
1628 }
1629
1630 while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_VS_ID))) {
1631 if (wl_cfgoce_is_oce_ie((const uint8 *)ie, (u8 const **)&parse, &len) ==
1632 TRUE) {
1633 return true;
1634 } else {
1635 ie = bcm_next_tlv((const bcm_tlv_t *)ie, &len);
1636 if (!ie) {
1637 return false;
1638 }
1639 parse = (uint8 *)ie;
1640 WL_DBG(("NON OCE IE. next ie ptr:%p", parse));
1641 }
1642 }
1643 WL_DBG(("OCE IE NOT found"));
1644 return false;
1645 }
1646 #endif /* WL_FW_OCE_AP_SELECT */
1647
1648 /* Dump the contents of the encoded wps ie buffer and get pbc value */
wl_validate_wps_ie(const char * wps_ie,s32 wps_ie_len,bool * pbc)1649 static void wl_validate_wps_ie(const char *wps_ie, s32 wps_ie_len, bool *pbc)
1650 {
1651 #define WPS_IE_FIXED_LEN 6
1652 s16 len;
1653 const u8 *subel = NULL;
1654 u16 subelt_id;
1655 u16 subelt_len;
1656 u16 val;
1657 u8 *valptr = (uint8 *)&val;
1658 if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
1659 WL_ERR(("invalid argument : NULL\n"));
1660 return;
1661 }
1662 len = (s16)wps_ie[TLV_LEN_OFF];
1663
1664 if (len > wps_ie_len) {
1665 WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
1666 return;
1667 }
1668 WL_DBG(("wps_ie len=%d\n", len));
1669 len -= 0x4; /* for the WPS IE's OUI, oui_type fields */
1670 subel = wps_ie + WPS_IE_FIXED_LEN;
1671 while (len >= 0x4) { /* must have attr id, attr len fields */
1672 valptr[0] = *subel++;
1673 valptr[1] = *subel++;
1674 subelt_id = HTON16(val);
1675
1676 valptr[0] = *subel++;
1677 valptr[1] = *subel++;
1678 subelt_len = HTON16(val);
1679
1680 len -= 0x4; /* for the attr id, attr len fields */
1681 len -= (s16)subelt_len; /* for the remaining fields in this attribute */
1682 if (len < 0) {
1683 break;
1684 }
1685 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n", subel, subelt_id,
1686 subelt_len));
1687
1688 if (subelt_id == WPS_ID_VERSION) {
1689 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
1690 } else if (subelt_id == WPS_ID_REQ_TYPE) {
1691 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
1692 } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
1693 valptr[0] = *subel;
1694 valptr[1] = *(subel + 1);
1695 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
1696 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
1697 char devname[33];
1698 int namelen = MIN(subelt_len, (sizeof(devname) - 1));
1699 if (namelen) {
1700 memcpy(devname, subel, namelen);
1701 devname[namelen] = '\0';
1702 /* Printing len as rx'ed in the IE */
1703 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n", devname,
1704 subelt_len));
1705 }
1706 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
1707 valptr[0] = *subel;
1708 valptr[1] = *(subel + 1);
1709 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
1710 *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
1711 } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
1712 valptr[0] = *subel;
1713 valptr[1] = *(subel + 1);
1714 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
1715 valptr[0] = *(subel + 0x6);
1716 valptr[1] = *(subel + 0x7);
1717 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
1718 } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
1719 valptr[0] = *subel;
1720 valptr[1] = *(subel + 1);
1721 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
1722 valptr[0] = *(subel + 0x6);
1723 valptr[1] = *(subel + 0x7);
1724 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
1725 } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
1726 valptr[0] = *subel;
1727 valptr[1] = *(subel + 1);
1728 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1729 ": cat=%u\n",
1730 HTON16(val)));
1731 } else {
1732 WL_DBG((" unknown attr 0x%x\n", subelt_id));
1733 }
1734
1735 subel += subelt_len;
1736 }
1737 }
1738
wl_set_tx_power(struct net_device * dev,enum nl80211_tx_power_setting type,s32 dbm)1739 s32 wl_set_tx_power(struct net_device *dev, enum nl80211_tx_power_setting type,
1740 s32 dbm)
1741 {
1742 s32 err = 0;
1743 s32 disable = 0;
1744 s32 txpwrqdbm;
1745 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1746
1747 /* Make sure radio is off or on as far as software is concerned */
1748 disable = WL_RADIO_SW_DISABLE << 0x10;
1749 disable = htod32(disable);
1750 err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable));
1751 if (unlikely(err)) {
1752 WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
1753 return err;
1754 }
1755
1756 if (dbm > 0xffff) {
1757 dbm = 0xffff;
1758 }
1759 txpwrqdbm = dbm * 0x4;
1760 #ifdef SUPPORT_WL_TXPOWER
1761 if (type == NL80211_TX_POWER_AUTOMATIC) {
1762 txpwrqdbm = 0x7F;
1763 } else {
1764 txpwrqdbm |= WL_TXPWR_OVERRIDE;
1765 }
1766 #endif /* SUPPORT_WL_TXPOWER */
1767 err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
1768 sizeof(txpwrqdbm), cfg->ioctl_buf,
1769 WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
1770 if (unlikely(err)) {
1771 WL_ERR(("qtxpower error (%d)\n", err));
1772 } else {
1773 WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
1774 }
1775
1776 return err;
1777 }
1778
wl_get_tx_power(struct net_device * dev,s32 * dbm)1779 s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
1780 {
1781 s32 err = 0;
1782 s32 txpwrdbm;
1783 char ioctl_buf[WLC_IOCTL_SMLEN];
1784
1785 err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower", NULL, 0, ioctl_buf,
1786 WLC_IOCTL_SMLEN, 0, NULL);
1787 if (unlikely(err)) {
1788 WL_ERR(("error (%d)\n", err));
1789 return err;
1790 }
1791
1792 memcpy(&txpwrdbm, ioctl_buf, sizeof(txpwrdbm));
1793 txpwrdbm = dtoh32(txpwrdbm);
1794 *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 0x4;
1795
1796 WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
1797
1798 return err;
1799 }
1800
wl_cfg80211_get_shared_freq(struct wiphy * wiphy)1801 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
1802 {
1803 chanspec_t chspec;
1804 int cur_band, err = 0;
1805 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1806 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
1807 struct ether_addr bssid;
1808 wl_bss_info_t *bss = NULL;
1809 u16 channel = WL_P2P_TEMP_CHAN;
1810 char *buf;
1811
1812 bzero(&bssid, sizeof(bssid));
1813 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) {
1814 /* STA interface is not associated. So start the new interface on a temp
1815 * channel . Later proper channel will be applied by the above framework
1816 * via set_channel (cfg80211 API).
1817 */
1818 WL_DBG(("Not associated. Return a temp channel. \n"));
1819 cur_band = 0;
1820 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(int));
1821 if (unlikely(err)) {
1822 WL_ERR(("Get band failed\n"));
1823 } else if (cur_band == WLC_BAND_5G) {
1824 channel = WL_P2P_TEMP_CHAN_5G;
1825 }
1826 return wl_ch_host_to_driver(channel);
1827 }
1828
1829 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
1830 if (!buf) {
1831 WL_ERR(("buf alloc failed. use temp channel\n"));
1832 return wl_ch_host_to_driver(channel);
1833 }
1834
1835 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1836 if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX))) {
1837 WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1838 chspec = wl_ch_host_to_driver(channel);
1839 } else {
1840 bss = (wl_bss_info_t *)(buf + 0x4);
1841 chspec = bss->chanspec;
1842
1843 WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
1844 }
1845
1846 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
1847 return chspec;
1848 }
1849
wl_wlfc_enable(struct bcm_cfg80211 * cfg,bool enable)1850 static void wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable)
1851 {
1852 #ifdef PROP_TXSTATUS_VSDB
1853 #if defined(BCMSDIO) || defined(BCMDBUS)
1854 bool wlfc_enabled = FALSE;
1855 s32 err;
1856 dhd_pub_t *dhd;
1857 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1858
1859 dhd = (dhd_pub_t *)(cfg->pub);
1860 if (!dhd) {
1861 return;
1862 }
1863
1864 if (enable) {
1865 if (!cfg->wlfc_on && !disable_proptx) {
1866 dhd_wlfc_get_enable(dhd, &wlfc_enabled);
1867 if (!wlfc_enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1868 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1869 dhd_wlfc_init(dhd);
1870 err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32));
1871 if (err < 0) {
1872 WL_ERR(("WLC_UP return err:%d\n", err));
1873 }
1874 }
1875 cfg->wlfc_on = true;
1876 WL_DBG(("wlfc_on:%d \n", cfg->wlfc_on));
1877 }
1878 } else if (dhd->conf->disable_proptx != 0) {
1879 dhd_wlfc_deinit(dhd);
1880 cfg->wlfc_on = false;
1881 }
1882 #endif /* BCMSDIO || BCMDBUS */
1883 #endif /* PROP_TXSTATUS_VSDB */
1884 }
1885
wl_cfg80211_p2p_if_add(struct bcm_cfg80211 * cfg,wl_iftype_t wl_iftype,char const * name,u8 * mac_addr,s32 * ret_err)1886 struct wireless_dev *wl_cfg80211_p2p_if_add(struct bcm_cfg80211 *cfg,
1887 wl_iftype_t wl_iftype,
1888 char const *name, u8 *mac_addr,
1889 s32 *ret_err)
1890 {
1891 u16 chspec;
1892 s16 cfg_type;
1893 long timeout;
1894 s32 err;
1895 u16 p2p_iftype;
1896 int dhd_mode;
1897 struct net_device *new_ndev = NULL;
1898 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
1899 struct ether_addr *p2p_addr;
1900
1901 *ret_err = BCME_OK;
1902 if (!cfg->p2p) {
1903 WL_ERR(("p2p not initialized\n"));
1904 return NULL;
1905 }
1906
1907 #if defined(WL_CFG80211_P2P_DEV_IF)
1908 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
1909 /* Handle Dedicated P2P discovery Interface */
1910 #ifdef CONFIG_AP6XXX_WIFI6_HDF
1911 // cache @mac_addr ...
1912 memcpy(g_hdf_infmap[HDF_INF_P2P0].macaddr, mac_addr, ETH_ALEN);
1913 #endif
1914 return wl_cfgp2p_add_p2p_disc_if(cfg);
1915 }
1916 #endif /* WL_CFG80211_P2P_DEV_IF */
1917
1918 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1919 p2p_iftype = WL_P2P_IF_GO;
1920 } else {
1921 p2p_iftype = WL_P2P_IF_CLIENT;
1922 }
1923
1924 /* Dual p2p doesn't support multiple P2PGO interfaces,
1925 * p2p_go_count is the counter for GO creation
1926 * requests.
1927 */
1928 if ((cfg->p2p->p2p_go_count > 0) && (wl_iftype == WL_IF_TYPE_P2P_GO)) {
1929 WL_ERR(("FW does not support multiple GO\n"));
1930 *ret_err = -ENOTSUPP;
1931 return NULL;
1932 }
1933 if (!cfg->p2p->on) {
1934 p2p_on(cfg) = true;
1935 wl_cfgp2p_set_firm_p2p(cfg);
1936 wl_cfgp2p_init_discovery(cfg);
1937 }
1938
1939 strlcpy(cfg->p2p->vir_ifname, name, sizeof(cfg->p2p->vir_ifname));
1940 /* In concurrency case, STA may be already associated in a particular
1941 * channel. so retrieve the current channel of primary interface and then
1942 * start the virtual interface on that.
1943 */
1944 chspec = wl_cfg80211_get_shared_freq(wiphy);
1945
1946 /* For P2P mode, use P2P-specific driver features to create the
1947 * bss: "cfg p2p_ifadd"
1948 */
1949 wl_set_p2p_status(cfg, IF_ADDING);
1950 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
1951 cfg_type = wl_cfgp2p_get_conn_idx(cfg);
1952 if (cfg_type == BCME_ERROR) {
1953 wl_clr_p2p_status(cfg, IF_ADDING);
1954 WL_ERR(("Failed to get connection idx for p2p interface\n"));
1955 return NULL;
1956 }
1957
1958 p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
1959 memcpy(p2p_addr->octet, mac_addr, ETH_ALEN);
1960
1961 err = wl_cfgp2p_ifadd(cfg, p2p_addr, htod32(p2p_iftype), chspec);
1962 if (unlikely(err)) {
1963 wl_clr_p2p_status(cfg, IF_ADDING);
1964 WL_ERR((" virtual iface add failed (%d) \n", err));
1965 return NULL;
1966 }
1967
1968 /* Wait for WLC_E_IF event with IF_ADD opcode */
1969 timeout = wait_event_interruptible_timeout(
1970 cfg->netif_change_event,
1971 ((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
1972 (cfg->if_event_info.valid)),
1973 msecs_to_jiffies(MAX_WAIT_TIME));
1974 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) &&
1975 cfg->if_event_info.valid) {
1976 wl_if_event_info *event = &cfg->if_event_info;
1977 new_ndev =
1978 wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg), event,
1979 event->mac, cfg->p2p->vir_ifname, false);
1980 if (unlikely(!new_ndev)) {
1981 goto fail;
1982 }
1983
1984 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1985 cfg->p2p->p2p_go_count++;
1986 }
1987 /* Fill p2p specific data */
1988 wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
1989 wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
1990
1991 WL_ERR((" virtual interface(%s) is "
1992 "created net attach done\n",
1993 cfg->p2p->vir_ifname));
1994 dhd_mode = (wl_iftype == WL_IF_TYPE_P2P_GC) ? DHD_FLAG_P2P_GC_MODE
1995 : DHD_FLAG_P2P_GO_MODE;
1996 DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
1997 /* reinitialize completion to clear previous count */
1998 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1999 INIT_COMPLETION(cfg->iface_disable);
2000 #else
2001 init_completion(&cfg->iface_disable);
2002 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
2003
2004 return new_ndev->ieee80211_ptr;
2005 }
2006
2007 fail:
2008 return NULL;
2009 }
2010
wl_cfg80211_check_vif_in_use(struct net_device * ndev)2011 bool wl_cfg80211_check_vif_in_use(struct net_device *ndev)
2012 {
2013 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2014 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2015 bool nan_enabled = FALSE;
2016
2017 #ifdef WL_NAN
2018 nan_enabled = cfg->nan_enable;
2019 #endif /* WL_NAN */
2020
2021 if (nan_enabled || (wl_cfgp2p_vif_created(cfg)) ||
2022 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
2023 WL_MEM(("%s: Virtual interfaces in use. NAN %d P2P %d softAP %d\n",
2024 __FUNCTION__, nan_enabled, wl_cfgp2p_vif_created(cfg),
2025 (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)));
2026 return TRUE;
2027 }
2028
2029 return FALSE;
2030 }
2031
wl_cfg80211_iface_state_ops(struct wireless_dev * wdev,wl_interface_state_t state,wl_iftype_t wl_iftype,u16 wl_mode)2032 void wl_cfg80211_iface_state_ops(struct wireless_dev *wdev,
2033 wl_interface_state_t state,
2034 wl_iftype_t wl_iftype, u16 wl_mode)
2035 {
2036 struct net_device *ndev;
2037 struct bcm_cfg80211 *cfg;
2038 dhd_pub_t *dhd;
2039 s32 bssidx;
2040
2041 WL_DBG(("state:%s wl_iftype:%d mode:%d\n", wl_if_state_strs[state],
2042 wl_iftype, wl_mode));
2043 if (!wdev) {
2044 WL_ERR(("wdev null\n"));
2045 return;
2046 }
2047
2048 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) ||
2049 (wl_iftype == WL_IF_TYPE_NAN_NMI)) {
2050 /* P2P discovery is a netless device and uses a
2051 * hidden bsscfg interface in fw. Don't apply the
2052 * iface ops state changes for p2p discovery I/F.
2053 * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
2054 * Don't apply iface ops state changes for NMI I/F.
2055 */
2056 return;
2057 }
2058
2059 cfg = wiphy_priv(wdev->wiphy);
2060 ndev = wdev->netdev;
2061 dhd = (dhd_pub_t *)(cfg->pub);
2062
2063 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2064 if (!ndev || (bssidx < 0)) {
2065 WL_ERR(("ndev null. skip iface state ops\n"));
2066 return;
2067 }
2068
2069 switch (state) {
2070 case WL_IF_CREATE_REQ:
2071 #ifdef WL_BCNRECV
2072 /* check fakeapscan in progress then abort */
2073 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
2074 #endif /* WL_BCNRECV */
2075 wl_cfg80211_scan_abort(cfg);
2076 wl_wlfc_enable(cfg, true);
2077 #ifdef WLTDLS
2078 /* disable TDLS if number of connected interfaces is >= 1 */
2079 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_CREATE, false);
2080 #endif /* WLTDLS */
2081 break;
2082 case WL_IF_DELETE_REQ:
2083 #ifdef WL_WPS_SYNC
2084 wl_wps_handle_ifdel(ndev);
2085 #endif /* WPS_SYNC */
2086 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
2087 /* Send completion for any pending scans */
2088 wl_cfg80211_cancel_scan(cfg);
2089 }
2090
2091 #ifdef CUSTOM_SET_CPUCORE
2092 dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
2093 if (!(dhd->chan_isvht80)) {
2094 dhd_set_cpucore(dhd, FALSE);
2095 }
2096 #endif /* CUSTOM_SET_CPUCORE */
2097 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
2098 break;
2099 case WL_IF_CREATE_DONE:
2100 if (wl_mode == WL_MODE_BSS) {
2101 /* Common code for sta type interfaces - STA, GC */
2102 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2103 }
2104 if (wl_iftype == WL_IF_TYPE_P2P_GC) {
2105 /* Disable firmware roaming for P2P interface */
2106 wldev_iovar_setint(ndev, "roam_off", 1);
2107 wldev_iovar_setint(ndev, "bcn_timeout", dhd->conf->bcn_timeout);
2108 }
2109 if (wl_mode == WL_MODE_AP) {
2110 /* Common code for AP/GO */
2111 }
2112 break;
2113 case WL_IF_DELETE_DONE:
2114 #ifdef WLTDLS
2115 /* Enable back TDLS if connected interface is <= 1 */
2116 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2117 #endif /* WLTDLS */
2118 wl_wlfc_enable(cfg, false);
2119 break;
2120 case WL_IF_CHANGE_REQ:
2121 /* Flush existing IEs from firmware on role change */
2122 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
2123 break;
2124 case WL_IF_CHANGE_DONE:
2125 if (wl_mode == WL_MODE_BSS) {
2126 /* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2127 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2128 }
2129 break;
2130
2131 default:
2132 WL_ERR(("Unsupported state: %d\n", state));
2133 return;
2134 }
2135 }
2136
wl_cfg80211_p2p_if_del(struct wiphy * wiphy,struct wireless_dev * wdev)2137 static s32 wl_cfg80211_p2p_if_del(struct wiphy *wiphy,
2138 struct wireless_dev *wdev)
2139 {
2140 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2141 s16 bssidx;
2142 s16 err;
2143 s32 cfg_type;
2144 struct net_device *ndev;
2145 long timeout;
2146
2147 if (unlikely(!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
2148 WL_INFORM_MEM(("device is not ready\n"));
2149 return BCME_NOTFOUND;
2150 }
2151 #ifdef WL_CFG80211_P2P_DEV_IF
2152 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2153 /* Handle dedicated P2P discovery interface. */
2154 return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
2155 }
2156 #endif /* WL_CFG80211_P2P_DEV_IF */
2157
2158 /* Handle P2P Group Interface */
2159 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2160 if (bssidx <= 0) {
2161 WL_ERR(("bssidx not found\n"));
2162 return BCME_NOTFOUND;
2163 }
2164 if (wl_cfgp2p_find_type(cfg, bssidx, &cfg_type) != BCME_OK) {
2165 /* Couldn't find matching iftype */
2166 WL_MEM(("non P2P interface\n"));
2167 return BCME_NOTFOUND;
2168 }
2169
2170 ndev = wdev->netdev;
2171 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2172 wl_clr_p2p_status(cfg, IF_ADDING);
2173
2174 /* for GO */
2175 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
2176 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
2177 cfg->p2p->p2p_go_count--;
2178 /* disable interface before bsscfg free */
2179 err = wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2180 /* if fw doesn't support "ifdis",
2181 do not wait for link down of ap mode
2182 */
2183 if (err == 0) {
2184 WL_ERR(("Wait for Link Down event for GO !!!\n"));
2185 wait_for_completion_timeout(&cfg->iface_disable,
2186 msecs_to_jiffies(0x1F4));
2187 } else if (err != BCME_UNSUPPORTED) {
2188 msleep(0x12C);
2189 }
2190 } else {
2191 /* GC case */
2192 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
2193 WL_ERR(("Wait for Link Down event for GC !\n"));
2194 wait_for_completion_timeout(&cfg->iface_disable,
2195 msecs_to_jiffies(0x1F4));
2196 }
2197 }
2198
2199 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
2200 wl_set_p2p_status(cfg, IF_DELETING);
2201 DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
2202
2203 err = wl_cfgp2p_ifdel(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2204 if (unlikely(err)) {
2205 WL_ERR(("IFDEL operation failed, error code = %d\n", err));
2206 goto fail;
2207 } else {
2208 /* Wait for WLC_E_IF event */
2209 timeout = wait_event_interruptible_timeout(
2210 cfg->netif_change_event,
2211 ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
2212 (cfg->if_event_info.valid)),
2213 msecs_to_jiffies(MAX_WAIT_TIME));
2214 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
2215 cfg->if_event_info.valid) {
2216 WL_ERR(("P2P IFDEL operation done\n"));
2217 err = BCME_OK;
2218 } else {
2219 WL_ERR(("IFDEL didn't complete properly\n"));
2220 err = -EINVAL;
2221 }
2222 }
2223
2224 fail:
2225 /* Even in failure case, attempt to remove the host data structure.
2226 * Firmware would be cleaned up via WiFi reset done by the
2227 * user space from hang event context (for android only).
2228 */
2229 bzero(cfg->p2p->vir_ifname, IFNAMSIZ);
2230 wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
2231 wl_to_p2p_bss_ndev(cfg, cfg_type) = NULL;
2232 wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, cfg_type));
2233 dhd_net_if_lock(ndev);
2234 if (cfg->if_event_info.ifidx) {
2235 /* Remove interface except for primary ifidx */
2236 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
2237 }
2238 dhd_net_if_unlock(ndev);
2239 return err;
2240 }
2241
2242 #ifdef WL_IFACE_MGMT_CONF
2243 #ifdef WL_IFACE_MGMT
wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 * cfg)2244 static s32 wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 *cfg)
2245 {
2246 s32 ret = BCME_OK;
2247 wl_iftype_t active_sec_iface = WL_IFACE_NOT_PRESENT;
2248 bool p2p_disc_on = false;
2249 bool sta_assoc_state = false;
2250
2251 mutex_lock(&cfg->if_sync);
2252
2253 sta_assoc_state =
2254 (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) ||
2255 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg)));
2256 active_sec_iface = wl_cfg80211_get_sec_iface(cfg);
2257 p2p_disc_on = wl_get_p2p_status(cfg, SCANNING);
2258 if ((sta_assoc_state == TRUE) || (p2p_disc_on == TRUE) ||
2259 (cfg->nan_init_state == TRUE) ||
2260 (active_sec_iface != WL_IFACE_NOT_PRESENT)) {
2261 WL_INFORM_MEM(("Active iface matrix: sta_assoc_state = %d,"
2262 " p2p_disc = %d, nan_disc = %d, active iface = %s\n",
2263 sta_assoc_state, p2p_disc_on, cfg->nan_init_state,
2264 wl_iftype_to_str(active_sec_iface)));
2265 ret = BCME_BUSY;
2266 }
2267 mutex_unlock(&cfg->if_sync);
2268 return ret;
2269 }
2270 #endif /* WL_IFACE_MGMT */
2271 #ifdef WL_NANP2P
wl_cfg80211_set_iface_conc_disc(struct net_device * ndev,uint8 arg_val)2272 int wl_cfg80211_set_iface_conc_disc(struct net_device *ndev, uint8 arg_val)
2273 {
2274 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2275 if (!cfg) {
2276 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2277 return BCME_ERROR;
2278 }
2279
2280 if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
2281 WL_ERR(("Cant allow iface management modifications\n"));
2282 return BCME_BUSY;
2283 }
2284
2285 if (arg_val) {
2286 cfg->conc_disc |= arg_val;
2287 } else {
2288 cfg->conc_disc &= ~arg_val;
2289 }
2290 return BCME_OK;
2291 }
2292
wl_cfg80211_get_iface_conc_disc(struct net_device * ndev)2293 uint8 wl_cfg80211_get_iface_conc_disc(struct net_device *ndev)
2294 {
2295 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2296 if (!cfg) {
2297 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2298 return BCME_ERROR;
2299 }
2300 return cfg->conc_disc;
2301 }
2302 #endif /* WL_NANP2P */
2303 #ifdef WL_IFACE_MGMT
wl_cfg80211_set_iface_policy(struct net_device * ndev,char * arg,int len)2304 int wl_cfg80211_set_iface_policy(struct net_device *ndev, char *arg, int len)
2305 {
2306 int ret = BCME_OK;
2307 uint8 i = 0;
2308 iface_mgmt_data_t *iface_data = NULL;
2309
2310 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2311 if (!cfg) {
2312 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2313 return BCME_ERROR;
2314 }
2315
2316 if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
2317 WL_ERR(("Cant allow iface management modifications\n"));
2318 return BCME_BUSY;
2319 }
2320
2321 if (!arg || len <= 0 || len > sizeof(iface_mgmt_data_t)) {
2322 return BCME_BADARG;
2323 }
2324
2325 iface_data = (iface_mgmt_data_t *)arg;
2326 if (iface_data->policy >= WL_IF_POLICY_INVALID) {
2327 WL_ERR(("Unexpected value of policy = %d\n", iface_data->policy));
2328 return BCME_BADARG;
2329 }
2330
2331 bzero(&cfg->iface_data, sizeof(iface_mgmt_data_t));
2332 ret = memcpy_s(&cfg->iface_data, sizeof(iface_mgmt_data_t), arg, len);
2333 if (ret != BCME_OK) {
2334 WL_ERR(("Failed to copy iface data, src len = %d\n", len));
2335 return ret;
2336 }
2337
2338 if (cfg->iface_data.policy == WL_IF_POLICY_ROLE_PRIORITY) {
2339 for (i = 0; i < WL_IF_TYPE_MAX; i++) {
2340 WL_DBG(("iface = %s, priority[i] = %d\n", wl_iftype_to_str(i),
2341 cfg->iface_data.priority[i]));
2342 }
2343 }
2344
2345 return ret;
2346 }
2347
wl_cfg80211_get_iface_policy(struct net_device * ndev)2348 uint8 wl_cfg80211_get_iface_policy(struct net_device *ndev)
2349
2350 {
2351 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2352 if (!cfg) {
2353 WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2354 return BCME_ERROR;
2355 }
2356
2357 return cfg->iface_data.policy;
2358 }
2359 #endif /* WL_IFACE_MGMT */
2360 #endif /* WL_IFACE_MGMT_CONF */
2361
2362 #ifdef WL_IFACE_MGMT
2363 /* Get active secondary data iface type */
wl_cfg80211_get_sec_iface(struct bcm_cfg80211 * cfg)2364 wl_iftype_t wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg)
2365 {
2366 #ifdef WL_STATIC_IF
2367 struct net_device *static_if_ndev;
2368 #else
2369 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2370 #endif /* WL_STATIC_IF */
2371 struct net_device *p2p_ndev = NULL;
2372
2373 p2p_ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
2374
2375 #ifdef WL_STATIC_IF
2376 static_if_ndev = wl_cfg80211_static_if_active(cfg);
2377 if (static_if_ndev) {
2378 if (IS_AP_IFACE(static_if_ndev->ieee80211_ptr)) {
2379 return WL_IF_TYPE_AP;
2380 }
2381 }
2382 #else
2383 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
2384 return WL_IF_TYPE_AP;
2385 }
2386 #endif /* WL_STATIC_IF */
2387
2388 if (p2p_ndev && p2p_ndev->ieee80211_ptr) {
2389 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
2390 return WL_IF_TYPE_P2P_GO;
2391 }
2392
2393 if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
2394 return WL_IF_TYPE_P2P_GC;
2395 }
2396 }
2397
2398 #ifdef WL_NAN
2399 if (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg))) {
2400 return WL_IF_TYPE_NAN;
2401 }
2402 #endif /* WL_NAN */
2403 return WL_IFACE_NOT_PRESENT;
2404 }
2405
2406 /*
2407 * Handle incoming data interface request based on policy.
2408 * If there is any conflicting interface, that will be
2409 * deleted.
2410 */
wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2411 s32 wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 *cfg,
2412 wl_iftype_t new_wl_iftype)
2413 {
2414 s32 ret = BCME_OK;
2415 bool del_iface = false;
2416 wl_iftype_t sec_wl_if_type = wl_cfg80211_get_sec_iface(cfg);
2417 if (sec_wl_if_type == WL_IF_TYPE_NAN && new_wl_iftype == WL_IF_TYPE_NAN) {
2418 /* Multi NDP is allowed irrespective of Policy */
2419 return BCME_OK;
2420 }
2421
2422 if (sec_wl_if_type == WL_IFACE_NOT_PRESENT) {
2423 /*
2424 * If there is no active secondary I/F, there
2425 * is no interface conflict. Do nothing.
2426 */
2427 return BCME_OK;
2428 }
2429
2430 /* Handle secondary data link case */
2431 switch (cfg->iface_data.policy) {
2432 case WL_IF_POLICY_CUSTOM:
2433 case WL_IF_POLICY_DEFAULT: {
2434 if (sec_wl_if_type == WL_IF_TYPE_NAN) {
2435 /* NAN has the lowest priority */
2436 del_iface = true;
2437 } else {
2438 /* Active iface is present, returning error */
2439 ret = BCME_ERROR;
2440 }
2441 break;
2442 }
2443 case WL_IF_POLICY_FCFS: {
2444 WL_INFORM_MEM(
2445 ("Found active iface = %s, can't support new iface = %s\n",
2446 wl_iftype_to_str(sec_wl_if_type),
2447 wl_iftype_to_str(new_wl_iftype)));
2448 ret = BCME_ERROR;
2449 break;
2450 }
2451 case WL_IF_POLICY_LP: {
2452 WL_INFORM_MEM(
2453 ("Remove active sec data interface, allow incoming iface\n"));
2454 /* Delete existing data iface and allow incoming sec iface */
2455 del_iface = true;
2456 break;
2457 }
2458 case WL_IF_POLICY_ROLE_PRIORITY: {
2459 WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2460 wl_iftype_to_str(sec_wl_if_type),
2461 cfg->iface_data.priority[sec_wl_if_type],
2462 wl_iftype_to_str(new_wl_iftype),
2463 cfg->iface_data.priority[new_wl_iftype]));
2464 if (cfg->iface_data.priority[new_wl_iftype] >
2465 cfg->iface_data.priority[sec_wl_if_type]) {
2466 del_iface = true;
2467 } else {
2468 WL_ERR(("Can't support new iface = %s\n",
2469 wl_iftype_to_str(new_wl_iftype)));
2470 ret = BCME_ERROR;
2471 }
2472 break;
2473 }
2474 default: {
2475 WL_ERR(("Unsupported interface policy = %d\n",
2476 cfg->iface_data.policy));
2477 return BCME_ERROR;
2478 }
2479 }
2480 if (del_iface) {
2481 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2482 }
2483 return ret;
2484 }
2485
2486 /* Handle discovery ifaces based on policy */
wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype,bool * disable_nan,bool * disable_p2p)2487 s32 wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 *cfg,
2488 wl_iftype_t new_wl_iftype, bool *disable_nan,
2489 bool *disable_p2p)
2490 {
2491 s32 ret = BCME_OK;
2492 wl_iftype_t sec_wl_if_type = wl_cfg80211_get_sec_iface(cfg);
2493 *disable_p2p = false;
2494 *disable_nan = false;
2495
2496 if (sec_wl_if_type == WL_IF_TYPE_NAN && new_wl_iftype == WL_IF_TYPE_NAN) {
2497 /* Multi NDP is allowed irrespective of Policy */
2498 return BCME_OK;
2499 }
2500
2501 /*
2502 * Check for any policy conflicts with active secondary
2503 * interface for incoming discovery iface
2504 */
2505 if ((sec_wl_if_type != WL_IFACE_NOT_PRESENT) &&
2506 (is_discovery_iface(new_wl_iftype))) {
2507 switch (cfg->iface_data.policy) {
2508 case WL_IF_POLICY_CUSTOM: {
2509 if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2510 new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2511 WL_INFORM_MEM(("Allow P2P Discovery with active NDP\n"));
2512 /* No further checks are required. */
2513 return BCME_OK;
2514 }
2515 /*
2516 * Intentional fall through to default policy
2517 * as for AP and associated ifaces, both are same
2518 */
2519 }
2520 case WL_IF_POLICY_DEFAULT: {
2521 if (sec_wl_if_type == WL_IF_TYPE_AP) {
2522 WL_INFORM_MEM(("AP is active, cant support new iface\n"));
2523 ret = BCME_ERROR;
2524 } else if (sec_wl_if_type == WL_IF_TYPE_P2P_GC ||
2525 sec_wl_if_type == WL_IF_TYPE_P2P_GO) {
2526 if (new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2527 /*
2528 * Associated discovery case,
2529 * Fall through
2530 */
2531 } else {
2532 /* Active iface is present, returning error */
2533 WL_INFORM_MEM(("P2P group is active,"
2534 " cant support new iface\n"));
2535 ret = BCME_ERROR;
2536 }
2537 } else if (sec_wl_if_type == WL_IF_TYPE_NAN) {
2538 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2539 }
2540 break;
2541 }
2542 case WL_IF_POLICY_FCFS: {
2543 WL_INFORM_MEM(("Can't support new iface = %s\n",
2544 wl_iftype_to_str(new_wl_iftype)));
2545 ret = BCME_ERROR;
2546 break;
2547 }
2548 case WL_IF_POLICY_LP: {
2549 /* Delete existing data iface n allow incoming sec iface */
2550 WL_INFORM_MEM(("Remove active sec data interface = %s\n",
2551 wl_iftype_to_str(sec_wl_if_type)));
2552 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2553 break;
2554 }
2555 case WL_IF_POLICY_ROLE_PRIORITY: {
2556 WL_INFORM_MEM(
2557 ("Existing iface = %s (%d) and new iface = %s (%d)\n",
2558 wl_iftype_to_str(sec_wl_if_type),
2559 cfg->iface_data.priority[sec_wl_if_type],
2560 wl_iftype_to_str(new_wl_iftype),
2561 cfg->iface_data.priority[new_wl_iftype]));
2562 if (cfg->iface_data.priority[new_wl_iftype] >
2563 cfg->iface_data.priority[sec_wl_if_type]) {
2564 WL_INFORM_MEM(("Remove active sec data iface\n"));
2565 ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2566 } else {
2567 WL_ERR(("Can't support new iface = %s"
2568 " due to low priority\n",
2569 wl_iftype_to_str(new_wl_iftype)));
2570 ret = BCME_ERROR;
2571 }
2572 break;
2573 }
2574 default: {
2575 WL_ERR(("Unsupported policy\n"));
2576 return BCME_ERROR;
2577 }
2578 }
2579 } else {
2580 /*
2581 * Handle incoming new secondary iface request,
2582 * irrespective of existing discovery ifaces
2583 */
2584 if ((cfg->iface_data.policy == WL_IF_POLICY_CUSTOM) &&
2585 (new_wl_iftype == WL_IF_TYPE_NAN)) {
2586 WL_INFORM_MEM(("Allow NAN Data Path\n"));
2587 /* No further checks are required. */
2588 return BCME_OK;
2589 }
2590 }
2591
2592 /* Check for any conflicting discovery iface */
2593 switch (new_wl_iftype) {
2594 case WL_IF_TYPE_P2P_DISC:
2595 case WL_IF_TYPE_P2P_GO:
2596 case WL_IF_TYPE_P2P_GC: {
2597 *disable_nan = true;
2598 break;
2599 }
2600 case WL_IF_TYPE_NAN_NMI:
2601 case WL_IF_TYPE_NAN: {
2602 *disable_p2p = true;
2603 break;
2604 }
2605 case WL_IF_TYPE_STA:
2606 case WL_IF_TYPE_AP: {
2607 *disable_nan = true;
2608 *disable_p2p = true;
2609 break;
2610 }
2611 default: {
2612 WL_ERR(("Unsupported\n"));
2613 return BCME_ERROR;
2614 }
2615 }
2616 return ret;
2617 }
2618
wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2619 bool wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 *cfg,
2620 wl_iftype_t new_wl_iftype)
2621 {
2622 struct net_device *p2p_ndev = NULL;
2623 p2p_ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
2624 if (new_wl_iftype == WL_IF_TYPE_P2P_DISC && p2p_ndev &&
2625 p2p_ndev->ieee80211_ptr &&
2626 is_p2p_group_iface(p2p_ndev->ieee80211_ptr)) {
2627 return true;
2628 }
2629 #ifdef WL_NAN
2630 else if ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) &&
2631 (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg)))) {
2632 return true;
2633 }
2634 #endif /* WL_NAN */
2635 return false;
2636 }
2637
2638 /* Handle incoming discovery iface request */
wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2639 s32 wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 *cfg,
2640 wl_iftype_t new_wl_iftype)
2641 {
2642 s32 ret = BCME_OK;
2643 bool disable_p2p = false;
2644 bool disable_nan = false;
2645
2646 wl_iftype_t active_sec_iface = wl_cfg80211_get_sec_iface(cfg);
2647 if (is_discovery_iface(new_wl_iftype) &&
2648 (active_sec_iface != WL_IFACE_NOT_PRESENT)) {
2649 if (wl_cfg80211_is_associated_discovery(cfg, new_wl_iftype) == TRUE) {
2650 WL_DBG(("Associate iface request is allowed= %s\n",
2651 wl_iftype_to_str(new_wl_iftype)));
2652 return ret;
2653 }
2654 }
2655
2656 ret = wl_cfg80211_disc_if_mgmt(cfg, new_wl_iftype, &disable_nan,
2657 &disable_p2p);
2658 if (ret != BCME_OK) {
2659 WL_ERR(("Failed at disc iface mgmt, ret = %d\n", ret));
2660 return ret;
2661 }
2662 #ifdef WL_NANP2P
2663 if (((new_wl_iftype == WL_IF_TYPE_P2P_DISC) && disable_nan) ||
2664 ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) && disable_p2p)) {
2665 if ((cfg->nan_p2p_supported == TRUE) &&
2666 (cfg->conc_disc == WL_NANP2P_CONC_SUPPORT)) {
2667 WL_INFORM_MEM(("P2P + NAN conc is supported\n"));
2668 disable_p2p = false;
2669 disable_nan = false;
2670 }
2671 }
2672 #endif /* WL_NANP2P */
2673
2674 if (disable_nan) {
2675 #ifdef WL_NAN
2676 /* Disable nan */
2677 cfg->nancfg.disable_reason = NAN_CONCURRENCY_CONFLICT;
2678 ret = wl_cfgnan_disable(cfg);
2679 if (ret != BCME_OK) {
2680 WL_ERR(("failed to disable nan, error[%d]\n", ret));
2681 return ret;
2682 }
2683 #endif /* WL_NAN */
2684 }
2685
2686 if (disable_p2p) {
2687 /* Disable p2p discovery */
2688 ret = wl_cfg80211_deinit_p2p_discovery(cfg);
2689 if (ret != BCME_OK) {
2690 WL_ERR(("Failed to disable p2p_disc for allowing nan\n"));
2691 return ret;
2692 }
2693 }
2694 return ret;
2695 }
2696
2697 /*
2698 * Check for any conflicting iface before adding iface.
2699 * Based on policy, either conflicting iface is removed
2700 * or new iface add request is blocked.
2701 */
wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 * cfg,wl_iftype_t new_wl_iftype)2702 s32 wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg,
2703 wl_iftype_t new_wl_iftype)
2704 {
2705 s32 ret = BCME_OK;
2706 #ifdef P2P_AP_CONCURRENT
2707 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2708 #endif
2709
2710 WL_INFORM_MEM(("Incoming iface = %s\n", wl_iftype_to_str(new_wl_iftype)));
2711
2712 #ifdef P2P_AP_CONCURRENT
2713 if (dhd->conf->war & P2P_AP_MAC_CONFLICT) {
2714 return ret;
2715 } else
2716 #endif
2717 #ifdef WL_STATIC_IF
2718 if (wl_cfg80211_get_sec_iface(cfg) == WL_IF_TYPE_AP &&
2719 new_wl_iftype == WL_IF_TYPE_AP) {
2720 } else
2721 #endif /* WL_STATIC_IF */
2722 if (!is_discovery_iface(new_wl_iftype)) {
2723 /* Incoming data interface request */
2724 if (wl_cfg80211_get_sec_iface(cfg) != WL_IFACE_NOT_PRESENT) {
2725 /* active interface present - Apply interface data policy */
2726 ret = wl_cfg80211_data_if_mgmt(cfg, new_wl_iftype);
2727 if (ret != BCME_OK) {
2728 WL_ERR(("if_mgmt fail:%d\n", ret));
2729 return ret;
2730 }
2731 }
2732 }
2733 /* Apply discovery config */
2734 ret = wl_cfg80211_handle_discovery_config(cfg, new_wl_iftype);
2735 return ret;
2736 }
2737 #endif /* WL_IFACE_MGMT */
2738
wl_cfg80211_add_monitor_if(struct wiphy * wiphy,const char * name)2739 static struct wireless_dev *wl_cfg80211_add_monitor_if(struct wiphy *wiphy,
2740 const char *name)
2741 {
2742 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
2743 WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2744 return ERR_PTR(-EOPNOTSUPP);
2745 #else
2746 struct wireless_dev *wdev;
2747 struct net_device *ndev = NULL;
2748
2749 dhd_add_monitor(name, &ndev);
2750
2751 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2752 if (!wdev) {
2753 WL_ERR(("wireless_dev alloc failed! \n"));
2754 goto fail;
2755 }
2756
2757 wdev->wiphy = wiphy;
2758 wdev->iftype = NL80211_IFTYPE_MONITOR;
2759 ndev->ieee80211_ptr = wdev;
2760 SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
2761
2762 WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
2763 return ndev->ieee80211_ptr;
2764 fail:
2765 return ERR_PTR(-EOPNOTSUPP);
2766 #endif // endif
2767 }
2768
2769 static struct wireless_dev *
wl_cfg80211_add_ibss(struct wiphy * wiphy,u16 wl_iftype,char const * name)2770 wl_cfg80211_add_ibss(struct wiphy *wiphy, u16 wl_iftype, char const *name)
2771 {
2772 #ifdef WLAIBSS_MCHAN
2773 /* AIBSS */
2774 return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
2775 #else
2776 /* Normal IBSS */
2777 WL_ERR(("IBSS not supported on Virtual iface\n"));
2778 return NULL;
2779 #endif // endif
2780 }
2781
wl_release_vif_macaddr(struct bcm_cfg80211 * cfg,u8 * mac_addr,u16 wl_iftype)2782 s32 wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr,
2783 u16 wl_iftype)
2784 {
2785 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2786 u16 org_toggle_bytes;
2787 u16 cur_toggle_bytes;
2788 u16 toggled_bit;
2789
2790 if (!ndev || !mac_addr || ETHER_ISNULLADDR(mac_addr)) {
2791 return -EINVAL;
2792 }
2793 WL_DBG(("%s:Mac addr" MACDBG "\n", __FUNCTION__, MAC2STRDBG(mac_addr)));
2794
2795 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_AP) ||
2796 (wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2797 /* Avoid invoking release mac addr code for interfaces using
2798 * fixed mac addr.
2799 */
2800 return BCME_OK;
2801 }
2802
2803 /* Fetch last two bytes of mac address */
2804 org_toggle_bytes = ntoh16(*((u16 *)&ndev->dev_addr[0x4]));
2805 cur_toggle_bytes = ntoh16(*((u16 *)&mac_addr[0x4]));
2806
2807 toggled_bit = (org_toggle_bytes ^ cur_toggle_bytes);
2808 WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n", org_toggle_bytes,
2809 cur_toggle_bytes));
2810 if (toggled_bit & cfg->vif_macaddr_mask) {
2811 /* This toggled_bit is marked in the used mac addr
2812 * mask. Clear it.
2813 */
2814 cfg->vif_macaddr_mask &= ~toggled_bit;
2815 WL_INFORM(("MAC address - " MACDBG
2816 " released. toggled_bit:%04X vif_mask:%04X\n",
2817 MAC2STRDBG(mac_addr), toggled_bit, cfg->vif_macaddr_mask));
2818 } else {
2819 WL_ERR(("MAC address - " MACDBG " not found in the used list."
2820 " toggled_bit:%04x vif_mask:%04x\n",
2821 MAC2STRDBG(mac_addr), toggled_bit, cfg->vif_macaddr_mask));
2822 return -EINVAL;
2823 }
2824
2825 return BCME_OK;
2826 }
2827
wl_get_vif_macaddr(struct bcm_cfg80211 * cfg,u16 wl_iftype,u8 * mac_addr)2828 s32 wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr)
2829 {
2830 #ifdef WL_P2P_USE_RANDMAC
2831 struct ether_addr *p2p_dev_addr =
2832 wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE);
2833 #endif // endif
2834 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2835 u16 toggle_mask;
2836 u16 toggle_bit;
2837 u16 toggle_bytes;
2838 u16 used;
2839 u32 offset = 0;
2840 /* Toggle mask starts from MSB of second last byte */
2841 u16 mask = 0x8000;
2842 if (!mac_addr) {
2843 return -EINVAL;
2844 }
2845 #ifdef WL_P2P_USE_RANDMAC
2846 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
2847 memcpy_s(mac_addr, ETH_ALEN, p2p_dev_addr->octet, ETH_ALEN);
2848 return 0;
2849 }
2850 #endif // endif
2851 memcpy(mac_addr, ndev->dev_addr, ETH_ALEN);
2852 /*
2853 * VIF MAC address managment
2854 * P2P Device addres: Primary MAC with locally admin. bit set
2855 * P2P Group address/NAN NMI/Softap/NAN DPI: Primary MAC addr
2856 * with local admin bit set and one additional bit toggled.
2857 * cfg->vif_macaddr_mask will hold the info regarding the mac address
2858 * released. Ensure to call wl_release_vif_macaddress to free up
2859 * the mac address.
2860 */
2861 #if defined(SPECIFIC_MAC_GEN_SCHEME)
2862 if (wl_iftype == WL_IF_TYPE_P2P_DISC || wl_iftype == WL_IF_TYPE_AP) {
2863 mac_addr[0] |= 0x02;
2864 } else if ((wl_iftype == WL_IF_TYPE_P2P_GO) ||
2865 (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2866 mac_addr[0] |= 0x02;
2867 mac_addr[0x4] ^= 0x80;
2868 }
2869 #else
2870 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
2871 mac_addr[0] |= 0x02;
2872 }
2873 #endif /* SEPCIFIC_MAC_GEN_SCHEME */
2874 else {
2875 /* For locally administered mac addresses, we keep the
2876 * OUI part constant and just work on the last two bytes.
2877 */
2878 mac_addr[0] |= 0x02;
2879 toggle_mask = cfg->vif_macaddr_mask;
2880 toggle_bytes = ntoh16(*((u16 *)&mac_addr[0x4]));
2881 do {
2882 used = toggle_mask & mask;
2883 if (!used) {
2884 /* Use this bit position */
2885 toggle_bit = mask >> offset;
2886 toggle_bytes ^= toggle_bit;
2887 cfg->vif_macaddr_mask |= toggle_bit;
2888 WL_DBG(("toggle_bit:%04X toggle_bytes:%04X toggle_mask:%04X\n",
2889 toggle_bit, toggle_bytes, cfg->vif_macaddr_mask));
2890 /* Macaddress are stored in network order */
2891 mac_addr[0x5] = *((u8 *)&toggle_bytes);
2892 mac_addr[0x4] = *(((u8 *)&toggle_bytes + 1));
2893 break;
2894 }
2895
2896 /* Shift by one */
2897 toggle_mask = toggle_mask << 0x1;
2898 offset++;
2899 if (offset > MAX_VIF_OFFSET) {
2900 /* We have used up all macaddresses. Something wrong! */
2901 WL_ERR(("Entire range of macaddress used up.\n"));
2902 ASSERT(0);
2903 break;
2904 }
2905 } while (true);
2906 }
2907 WL_INFORM_MEM(
2908 ("Get virtual I/F mac addr: " MACDBG "\n", MAC2STRDBG(mac_addr)));
2909 return 0;
2910 }
2911 #ifdef DNGL_AXI_ERROR_LOGGING
_wl_cfg80211_check_axi_error(struct bcm_cfg80211 * cfg)2912 static s32 _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg)
2913 {
2914 s32 ret = BCME_OK;
2915 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2916 hnd_ext_trap_hdr_t *hdr;
2917 int axi_host_error_size;
2918 uint8 *new_dst;
2919 uint32 *ext_data = dhd->extended_trap_data;
2920 struct file *fp = NULL;
2921 char *filename = DHD_COMMON_DUMP_PATH DHD_DUMP_AXI_ERROR_FILENAME
2922 DHD_DUMP_HAL_FILENAME_SUFFIX;
2923
2924 WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename));
2925
2926 fp = filp_open(filename, O_RDONLY, 0);
2927 if (IS_ERR(fp) || (fp == NULL)) {
2928 WL_ERR(("%s: Couldn't read the file, err %ld,File [%s] No previous "
2929 "axi error \n",
2930 __FUNCTION__, PTR_ERR(fp), filename));
2931 return ret;
2932 }
2933
2934 kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump,
2935 sizeof(dhd_axi_error_dump_t));
2936 filp_close(fp, NULL);
2937
2938 /* Delete axi error info file */
2939 if (dhd_file_delete(filename) < 0) {
2940 WL_ERR(("%s(): Failed to delete file: %s\n", __FUNCTION__, filename));
2941 return ret;
2942 }
2943 WL_ERR(("%s(): Success to delete file: %s\n", __FUNCTION__, filename));
2944
2945 if (dhd->axi_err_dump->etd_axi_error_v1.signature !=
2946 HND_EXT_TRAP_AXIERROR_SIGNATURE) {
2947 WL_ERR(("%s: Invalid AXI signature: 0x%x\n", __FUNCTION__,
2948 dhd->axi_err_dump->etd_axi_error_v1.signature));
2949 }
2950
2951 /* First word is original trap_data */
2952 ext_data++;
2953
2954 /* Followed by the extended trap data header */
2955 hdr = (hnd_ext_trap_hdr_t *)ext_data;
2956 new_dst = hdr->data;
2957
2958 axi_host_error_size = sizeof(dhd->axi_err_dump->axid) +
2959 sizeof(dhd->axi_err_dump->fault_address);
2960
2961 /* TAG_TRAP_AXI_HOST_INFO tlv : host's axid, fault address */
2962 new_dst =
2963 bcm_write_tlv(TAG_TRAP_AXI_HOST_INFO, (const void *)dhd->axi_err_dump,
2964 axi_host_error_size, new_dst);
2965
2966 /* TAG_TRAP_AXI_ERROR tlv */
2967 new_dst = bcm_write_tlv(
2968 TAG_TRAP_AXI_ERROR, (const void *)&dhd->axi_err_dump->etd_axi_error_v1,
2969 sizeof(dhd->axi_err_dump->etd_axi_error_v1), new_dst);
2970 hdr->len = new_dst - hdr->data;
2971
2972 dhd->dongle_trap_occured = TRUE;
2973 memset(dhd->axi_err_dump, 0, sizeof(dhd_axi_error_dump_t));
2974
2975 dhd->hang_reason = HANG_REASON_DONGLE_TRAP;
2976 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2977 ret = BCME_ERROR;
2978 return ret;
2979 }
2980 #endif /* DNGL_AXI_ERROR_LOGGING */
2981
2982 /* All Android/Linux private/Vendor Interface calls should make
2983 * use of below API for interface creation.
2984 */
wl_cfg80211_add_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,wl_iftype_t wl_iftype,const char * name,u8 * mac)2985 struct wireless_dev *wl_cfg80211_add_if(struct bcm_cfg80211 *cfg,
2986 struct net_device *primary_ndev,
2987 wl_iftype_t wl_iftype, const char *name,
2988 u8 *mac)
2989 {
2990 u8 mac_addr[ETH_ALEN];
2991 s32 err = -ENODEV;
2992 struct wireless_dev *wdev = NULL;
2993 struct wiphy *wiphy;
2994 s32 wl_mode;
2995 dhd_pub_t *dhd;
2996 wl_iftype_t macaddr_iftype = wl_iftype;
2997
2998 WL_INFORM_MEM(
2999 ("if name: %s, wl_iftype:%d \n", name ? name : "NULL", wl_iftype));
3000 if (!cfg || !primary_ndev || !name) {
3001 WL_ERR(("cfg/ndev/name ptr null\n"));
3002 return NULL;
3003 }
3004 if (wl_cfg80211_get_wdev_from_ifname(cfg, name)) {
3005 WL_ERR(("Interface name %s exists!\n", name));
3006 return NULL;
3007 }
3008
3009 wiphy = bcmcfg_to_wiphy(cfg);
3010 dhd = (dhd_pub_t *)(cfg->pub);
3011 if (!dhd) {
3012 return NULL;
3013 }
3014
3015 if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
3016 WL_ERR(("Please check op_mode %d, name %s\n", dhd->op_mode, name));
3017 return NULL;
3018 }
3019
3020 if ((wl_mode = wl_iftype_to_mode(wl_iftype)) < 0) {
3021 return NULL;
3022 }
3023 mutex_lock(&cfg->if_sync);
3024 #ifdef WL_NAN
3025 if (wl_iftype == WL_IF_TYPE_NAN) {
3026 /*
3027 * Bypass the role conflict check for NDI and handle it
3028 * from dp req and dp resp context
3029 * because in aware comms, ndi gets created soon after nan enable.
3030 */
3031 } else
3032 #endif /* WL_NAN */
3033 #ifdef WL_IFACE_MGMT
3034 if ((err = wl_cfg80211_handle_if_role_conflict(cfg, wl_iftype)) < 0) {
3035 mutex_unlock(&cfg->if_sync);
3036 return NULL;
3037 }
3038 #endif /* WL_IFACE_MGMT */
3039 #ifdef DNGL_AXI_ERROR_LOGGING
3040 /* Check the previous smmu fault error */
3041 if ((err = _wl_cfg80211_check_axi_error(cfg)) < 0) {
3042 mutex_unlock(&cfg->if_sync);
3043 return NULL;
3044 }
3045 #endif /* DNGL_AXI_ERROR_LOGGING */
3046 /* Protect the interace op context */
3047 /* Do pre-create ops */
3048 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CREATE_REQ,
3049 wl_iftype, wl_mode);
3050
3051 if (strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)) == 0) {
3052 macaddr_iftype = WL_IF_TYPE_AP;
3053 }
3054
3055 if (mac) {
3056 /* If mac address is provided, use that */
3057 memcpy(mac_addr, mac, ETH_ALEN);
3058 } else if ((wl_get_vif_macaddr(cfg, macaddr_iftype, mac_addr) != BCME_OK)) {
3059 /* Fetch the mac address to be used for virtual interface */
3060 err = -EINVAL;
3061 goto fail;
3062 }
3063
3064 switch (wl_iftype) {
3065 case WL_IF_TYPE_IBSS:
3066 wdev = wl_cfg80211_add_ibss(wiphy, wl_iftype, name);
3067 break;
3068 case WL_IF_TYPE_MONITOR:
3069 wdev = wl_cfg80211_add_monitor_if(wiphy, name);
3070 break;
3071 case WL_IF_TYPE_STA:
3072 case WL_IF_TYPE_AP:
3073 case WL_IF_TYPE_NAN:
3074 if (cfg->iface_cnt >= (IFACE_MAX_CNT - 1)) {
3075 WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
3076 cfg->iface_cnt));
3077 err = -ENOTSUPP;
3078 goto fail;
3079 }
3080 wdev = wl_cfg80211_create_iface(cfg->wdev->wiphy, wl_iftype,
3081 mac_addr, name);
3082 break;
3083 case WL_IF_TYPE_P2P_DISC:
3084 case WL_IF_TYPE_P2P_GO:
3085 /* Intentional fall through */
3086 case WL_IF_TYPE_P2P_GC:
3087 if (cfg->p2p_supported) {
3088 wdev = wl_cfg80211_p2p_if_add(cfg, wl_iftype, name, mac_addr,
3089 &err);
3090 break;
3091 }
3092 /* Intentionally fall through for unsupported interface
3093 * handling when firmware doesn't support p2p
3094 */
3095 default:
3096 WL_ERR(("Unsupported interface type\n"));
3097 err = -ENOTSUPP;
3098 goto fail;
3099 }
3100
3101 if (!wdev) {
3102 WL_ERR(("vif create failed. err:%d\n", err));
3103 if (err != -ENOTSUPP) {
3104 err = -ENODEV;
3105 }
3106 goto fail;
3107 }
3108
3109 /* Ensure decrementing in case of failure */
3110 cfg->vif_count++;
3111
3112 wl_cfg80211_iface_state_ops(wdev, WL_IF_CREATE_DONE, wl_iftype, wl_mode);
3113
3114 WL_INFORM_MEM(("Vif created. dev->ifindex:%d"
3115 " cfg_iftype:%d, vif_count:%d\n",
3116 (wdev->netdev ? wdev->netdev->ifindex : 0xff), wdev->iftype,
3117 cfg->vif_count));
3118 mutex_unlock(&cfg->if_sync);
3119 return wdev;
3120
3121 fail:
3122 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_DELETE_REQ,
3123 wl_iftype, wl_mode);
3124
3125 if (err != -ENOTSUPP) {
3126 /* For non-supported interfaces, just return error and
3127 * skip below recovery steps.
3128 */
3129 SUPP_LOG(("IF_ADD fail. err:%d\n", err));
3130 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3131 if (dhd_query_bus_erros(dhd)) {
3132 goto exit;
3133 }
3134 dhd->iface_op_failed = TRUE;
3135 #if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
3136 if (dhd->memdump_enabled) {
3137 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3138 dhd_bus_mem_dump(dhd);
3139 }
3140 #endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
3141 dhd->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
3142 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3143 }
3144 exit:
3145 mutex_unlock(&cfg->if_sync);
3146 return NULL;
3147 }
3148
3149 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)3150 wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
3151 #if defined(WL_CFG80211_P2P_DEV_IF)
3152 const char *name,
3153 #else
3154 char *name,
3155 #endif /* WL_CFG80211_P2P_DEV_IF */
3156 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
3157 unsigned char name_assign_type,
3158 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
3159 enum nl80211_iftype type,
3160 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3161 u32 *flags,
3162 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3163 struct vif_params *params)
3164 {
3165 u16 wl_iftype;
3166 u16 wl_mode;
3167 struct net_device *primary_ndev;
3168 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3169 struct wireless_dev *wdev;
3170
3171 WL_DBG(("Enter iftype: %d\n", type));
3172 if (!cfg) {
3173 return ERR_PTR(-EINVAL);
3174 }
3175
3176 /* Use primary I/F for sending cmds down to firmware */
3177 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3178 if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
3179 WL_ERR(("device is not ready\n"));
3180 return ERR_PTR(-ENODEV);
3181 }
3182
3183 if (!name) {
3184 WL_ERR(("Interface name not provided \n"));
3185 return ERR_PTR(-EINVAL);
3186 }
3187
3188 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3189 return ERR_PTR(-EINVAL);
3190 }
3191
3192 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, name, NULL);
3193 if (unlikely(!wdev)) {
3194 return ERR_PTR(-ENODEV);
3195 }
3196 return wdev_to_cfgdev(wdev);
3197 }
3198
wl_cfg80211_del_ibss(struct wiphy * wiphy,struct wireless_dev * wdev)3199 static s32 wl_cfg80211_del_ibss(struct wiphy *wiphy, struct wireless_dev *wdev)
3200 {
3201 WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev));
3202 #ifdef WLAIBSS_MCHAN
3203 /* AIBSS */
3204 return bcm_cfg80211_del_ibss_if(wiphy, wdev);
3205 #else
3206 /* Normal IBSS */
3207 return wl_cfg80211_del_iface(wiphy, wdev);
3208 #endif // endif
3209 }
3210
wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)3211 s32 wl_cfg80211_del_if(struct bcm_cfg80211 *cfg,
3212 struct net_device *primary_ndev,
3213 struct wireless_dev *wdev, char *ifname)
3214 {
3215 int ret = BCME_OK;
3216 mutex_lock(&cfg->if_sync);
3217 ret = _wl_cfg80211_del_if(cfg, primary_ndev, wdev, ifname);
3218 mutex_unlock(&cfg->if_sync);
3219 return ret;
3220 }
3221
_wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)3222 s32 _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg,
3223 struct net_device *primary_ndev,
3224 struct wireless_dev *wdev, char *ifname)
3225 {
3226 int ret = BCME_OK;
3227 s32 bssidx;
3228 struct wiphy *wiphy;
3229 u16 wl_mode;
3230 u16 wl_iftype;
3231 struct net_info *netinfo;
3232 dhd_pub_t *dhd;
3233 BCM_REFERENCE(dhd);
3234
3235 if (!cfg) {
3236 return -EINVAL;
3237 }
3238
3239 dhd = (dhd_pub_t *)(cfg->pub);
3240
3241 if (!wdev && ifname) {
3242 /* If only ifname is provided, fetch corresponding wdev ptr from our
3243 * internal data structure
3244 */
3245 wdev = wl_cfg80211_get_wdev_from_ifname(cfg, ifname);
3246 }
3247
3248 /* Check whether we have a valid wdev ptr */
3249 if (unlikely(!wdev)) {
3250 WL_ERR(("wdev not found. '%s' does not exists\n", ifname));
3251 return -ENODEV;
3252 }
3253
3254 WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev->iftype));
3255
3256 wiphy = wdev->wiphy;
3257 #ifdef WL_CFG80211_P2P_DEV_IF
3258 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
3259 /* p2p discovery would be de-initialized in stop p2p
3260 * device context/from other virtual i/f creation context
3261 * so netinfo list may not have any node corresponding to
3262 * discovery I/F. Handle it before bssidx check.
3263 */
3264 ret = wl_cfg80211_p2p_if_del(wiphy, wdev);
3265 if (unlikely(ret)) {
3266 goto exit;
3267 } else {
3268 /* success case. return from here */
3269 if (cfg->vif_count) {
3270 cfg->vif_count--;
3271 }
3272 return BCME_OK;
3273 }
3274 }
3275 #endif /* WL_CFG80211_P2P_DEV_IF */
3276
3277 if ((netinfo = wl_get_netinfo_by_wdev(cfg, wdev)) == NULL) {
3278 WL_ERR(("Find netinfo from wdev %p failed\n", wdev));
3279 ret = -ENODEV;
3280 goto exit;
3281 }
3282
3283 if (!wdev->netdev) {
3284 WL_ERR(("ndev null! \n"));
3285 } else {
3286 /* Disable tx before del */
3287 netif_tx_disable(wdev->netdev);
3288 }
3289
3290 wl_iftype = netinfo->iftype;
3291 wl_mode = wl_iftype_to_mode(wl_iftype);
3292 bssidx = netinfo->bssidx;
3293 WL_INFORM_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
3294 wdev->iftype, wl_iftype, wl_mode, bssidx));
3295
3296 /* Do pre-interface del ops */
3297 wl_cfg80211_iface_state_ops(wdev, WL_IF_DELETE_REQ, wl_iftype, wl_mode);
3298
3299 switch (wl_iftype) {
3300 case WL_IF_TYPE_P2P_GO:
3301 case WL_IF_TYPE_P2P_GC:
3302 case WL_IF_TYPE_AP:
3303 case WL_IF_TYPE_STA:
3304 case WL_IF_TYPE_NAN:
3305 ret = wl_cfg80211_del_iface(wiphy, wdev);
3306 break;
3307 case WL_IF_TYPE_IBSS:
3308 ret = wl_cfg80211_del_ibss(wiphy, wdev);
3309 break;
3310
3311 default:
3312 WL_ERR(("Unsupported interface type\n"));
3313 ret = BCME_ERROR;
3314 }
3315
3316 exit:
3317 if (ret == BCME_OK) {
3318 /* Successful case */
3319 if (cfg->vif_count) {
3320 cfg->vif_count--;
3321 }
3322 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3323 WL_IF_DELETE_DONE, wl_iftype, wl_mode);
3324 #ifdef WL_NAN
3325 if (!((cfg->nancfg.mac_rand) && (wl_iftype == WL_IF_TYPE_NAN)))
3326 #endif /* WL_NAN */
3327 {
3328 wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype);
3329 }
3330 WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg->vif_count));
3331 } else {
3332 if (!wdev->netdev) {
3333 WL_ERR(("ndev null! \n"));
3334 } else {
3335 /* IF del failed. revert back tx queue status */
3336 netif_tx_start_all_queues(wdev->netdev);
3337 }
3338
3339 /* Skip generating log files and sending HANG event
3340 * if driver state is not READY
3341 */
3342 if (wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg))) {
3343 SUPP_LOG(("IF_DEL fail. err:%d\n", ret));
3344 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3345 /* IF dongle is down due to previous hang or other conditions,
3346 * sending one more hang notification is not needed.
3347 */
3348 if (dhd_query_bus_erros(dhd) || (ret == BCME_DONGLE_DOWN)) {
3349 goto end;
3350 }
3351 dhd->iface_op_failed = TRUE;
3352 #if defined(DHD_FW_COREDUMP)
3353 if (dhd->memdump_enabled && (ret != -EBADTYPE)) {
3354 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3355 dhd_bus_mem_dump(dhd);
3356 }
3357 #endif /* DHD_FW_COREDUMP */
3358 WL_ERR(("Notify hang event to upper layer \n"));
3359 dhd->hang_reason = HANG_REASON_IFACE_DEL_FAILURE;
3360 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3361 }
3362 }
3363 end:
3364 return ret;
3365 }
3366
wl_cfg80211_del_virtual_iface(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev)3367 static s32 wl_cfg80211_del_virtual_iface(struct wiphy *wiphy,
3368 bcm_struct_cfgdev *cfgdev)
3369 {
3370 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3371 struct wireless_dev *wdev = cfgdev_to_wdev(cfgdev);
3372 int ret = BCME_OK;
3373 u16 wl_iftype;
3374 u16 wl_mode;
3375 struct net_device *primary_ndev;
3376
3377 if (!cfg) {
3378 return -EINVAL;
3379 }
3380
3381 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3382 wdev = cfgdev_to_wdev(cfgdev);
3383 if (!wdev) {
3384 WL_ERR(("wdev null"));
3385 return -ENODEV;
3386 }
3387
3388 WL_DBG(("Enter wdev:%p iftype: %d\n", wdev, wdev->iftype));
3389 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
3390 WL_ERR(("Wrong iftype: %d\n", wdev->iftype));
3391 return -ENODEV;
3392 }
3393
3394 if ((ret = wl_cfg80211_del_if(cfg, primary_ndev, wdev, NULL)) < 0) {
3395 WL_ERR(("IF del failed\n"));
3396 }
3397
3398 return ret;
3399 }
3400
wl_cfg80211_change_p2prole(struct wiphy * wiphy,struct net_device * ndev,enum nl80211_iftype type)3401 static s32 wl_cfg80211_change_p2prole(struct wiphy *wiphy,
3402 struct net_device *ndev,
3403 enum nl80211_iftype type)
3404 {
3405 s32 wlif_type;
3406 s32 mode = 0;
3407 s32 index;
3408 s32 err;
3409 s32 conn_idx = -1;
3410 chanspec_t chspec;
3411 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3412 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3413
3414 WL_INFORM_MEM(("Enter. current_role:%d new_role:%d \n",
3415 ndev->ieee80211_ptr->iftype, type));
3416
3417 if (!cfg->p2p || !wl_cfgp2p_vif_created(cfg)) {
3418 WL_ERR(("P2P not initialized \n"));
3419 return -EINVAL;
3420 }
3421
3422 if (!is_p2p_group_iface(ndev->ieee80211_ptr)) {
3423 WL_ERR(("Wrong if type \n"));
3424 return -EINVAL;
3425 }
3426
3427 /* Abort any on-going scans to avoid race condition issues */
3428 wl_cfg80211_cancel_scan(cfg);
3429
3430 index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
3431 if (index < 0) {
3432 WL_ERR(("Find bsscfg index from ndev(%p) failed\n", ndev));
3433 return BCME_ERROR;
3434 }
3435 if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK) {
3436 return BCME_ERROR;
3437 }
3438
3439 /* In concurrency case, STA may be already associated in a particular
3440 * channel. so retrieve the current channel of primary interface and
3441 * then start the virtual interface on that.
3442 */
3443 chspec = wl_cfg80211_get_shared_freq(wiphy);
3444 if (type == NL80211_IFTYPE_P2P_GO) {
3445 /* Dual p2p doesn't support multiple P2PGO interfaces,
3446 * p2p_go_count is the counter for GO creation
3447 * requests.
3448 */
3449 if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
3450 WL_ERR(("FW does not support multiple GO\n"));
3451 return BCME_ERROR;
3452 }
3453 mode = WL_MODE_AP;
3454 wlif_type = WL_P2P_IF_GO;
3455 dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
3456 dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
3457 } else {
3458 wlif_type = WL_P2P_IF_CLIENT;
3459 /* for GO */
3460 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
3461 WL_INFORM_MEM(("Downgrading P2P GO to cfg_iftype:%d \n", type));
3462 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
3463 cfg->p2p->p2p_go_count--;
3464 /* disable interface before bsscfg free */
3465 err =
3466 wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx));
3467 /* if fw doesn't support "ifdis",
3468 * do not wait for link down of ap mode
3469 */
3470 if (err == 0) {
3471 WL_DBG(("Wait for Link Down event for GO !!!\n"));
3472 wait_for_completion_timeout(&cfg->iface_disable,
3473 msecs_to_jiffies(500));
3474 } else if (err != BCME_UNSUPPORTED) {
3475 msleep(0x12C);
3476 }
3477 }
3478 }
3479
3480 wl_set_p2p_status(cfg, IF_CHANGING);
3481 wl_clr_p2p_status(cfg, IF_CHANGED);
3482 wl_cfgp2p_ifchange(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx),
3483 htod32(wlif_type), chspec, conn_idx);
3484 wait_event_interruptible_timeout(
3485 cfg->netif_change_event, (wl_get_p2p_status(cfg, IF_CHANGED) == true),
3486 msecs_to_jiffies(MAX_WAIT_TIME));
3487
3488 wl_clr_p2p_status(cfg, IF_CHANGING);
3489 wl_clr_p2p_status(cfg, IF_CHANGED);
3490
3491 if (mode == WL_MODE_AP) {
3492 wl_set_drv_status(cfg, CONNECTED, ndev);
3493 }
3494
3495 return BCME_OK;
3496 }
3497
wl_cfg80211_change_virtual_iface(struct wiphy * wiphy,struct net_device * ndev,enum nl80211_iftype type,u32 * flags,struct vif_params * params)3498 static s32 wl_cfg80211_change_virtual_iface(struct wiphy *wiphy,
3499 struct net_device *ndev,
3500 enum nl80211_iftype type,
3501 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3502 u32 *flags,
3503 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3504 struct vif_params *params)
3505 {
3506 s32 infra = 1;
3507 s32 err = BCME_OK;
3508 u16 wl_iftype;
3509 u16 wl_mode;
3510 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3511 struct net_info *netinfo = NULL;
3512 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3513 struct net_device *primary_ndev;
3514
3515 if (!dhd) {
3516 return -EINVAL;
3517 }
3518
3519 WL_INFORM_MEM(("[%s] Enter. current cfg_iftype:%d new cfg_iftype:%d \n",
3520 ndev->name, ndev->ieee80211_ptr->iftype, type));
3521 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3522
3523 if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3524 WL_ERR(("Unknown role \n"));
3525 return -EINVAL;
3526 }
3527
3528 mutex_lock(&cfg->if_sync);
3529 netinfo = wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
3530 if (unlikely(!netinfo)) {
3531 #ifdef WL_STATIC_IF
3532 if (wl_cfg80211_static_if(cfg, ndev)) {
3533 /* Incase of static interfaces, the netinfo will be
3534 * allocated only when FW interface is initialized. So
3535 * store the value and use it during initialization.
3536 */
3537 WL_INFORM_MEM(("skip change vif for static if\n"));
3538 ndev->ieee80211_ptr->iftype = type;
3539 err = BCME_OK;
3540 } else
3541 #endif /* WL_STATIC_IF */
3542 {
3543 WL_ERR(("netinfo not found \n"));
3544 err = -ENODEV;
3545 }
3546 goto fail;
3547 }
3548
3549 /* perform pre-if-change tasks */
3550 wl_cfg80211_iface_state_ops(ndev->ieee80211_ptr, WL_IF_CHANGE_REQ,
3551 wl_iftype, wl_mode);
3552
3553 switch (type) {
3554 case NL80211_IFTYPE_ADHOC:
3555 infra = 0;
3556 break;
3557 case NL80211_IFTYPE_STATION:
3558 /* Supplicant sets iftype to STATION while removing p2p GO */
3559 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
3560 /* Downgrading P2P GO */
3561 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3562 if (unlikely(err)) {
3563 WL_ERR(("P2P downgrade failed \n"));
3564 }
3565 } else if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
3566 /* Downgrade role from AP to STA */
3567 if ((err = wl_cfg80211_add_del_bss(cfg, ndev, netinfo->bssidx,
3568 wl_iftype, 0, NULL)) < 0) {
3569 WL_ERR(("AP-STA Downgrade failed \n"));
3570 goto fail;
3571 }
3572 }
3573 break;
3574 case NL80211_IFTYPE_AP:
3575 /* intentional fall through */
3576 case NL80211_IFTYPE_AP_VLAN: {
3577 if (!wl_get_drv_status(cfg, AP_CREATED, ndev) &&
3578 wl_get_drv_status(cfg, READY, ndev)) {
3579 err = wl_cfg80211_set_ap_role(cfg, ndev);
3580 if (unlikely(err)) {
3581 WL_ERR(("set ap role failed!\n"));
3582 goto fail;
3583 }
3584 } else {
3585 WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
3586 }
3587 break;
3588 }
3589 case NL80211_IFTYPE_P2P_GO:
3590 /* Intentional fall through */
3591 case NL80211_IFTYPE_P2P_CLIENT:
3592 infra = 1;
3593 err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3594 break;
3595 case NL80211_IFTYPE_MONITOR:
3596 case NL80211_IFTYPE_WDS:
3597 case NL80211_IFTYPE_MESH_POINT:
3598 /* Intentional fall through */
3599 default:
3600 WL_ERR(("Unsupported type:%d \n", type));
3601 err = -EINVAL;
3602 goto fail;
3603 }
3604
3605 if (wl_get_drv_status(cfg, READY, ndev)) {
3606 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(s32));
3607 if (err < 0) {
3608 WL_ERR(("SET INFRA/IBSS error %d\n", err));
3609 goto fail;
3610 }
3611 }
3612
3613 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CHANGE_DONE,
3614 wl_iftype, wl_mode);
3615
3616 /* Update new iftype in relevant structures */
3617 ndev->ieee80211_ptr->iftype = type;
3618 netinfo->iftype = wl_iftype;
3619 WL_INFORM_MEM(("[%s] cfg_iftype changed to %d\n", ndev->name, type));
3620 #ifdef WL_EXT_IAPSTA
3621 wl_ext_iapsta_update_iftype(ndev, netinfo->ifidx, wl_iftype);
3622 #endif
3623
3624 fail:
3625 if (err) {
3626 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
3627 }
3628 mutex_unlock(&cfg->if_sync);
3629 return err;
3630 }
3631
wl_cfg80211_notify_ifadd(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx,uint8 role)3632 s32 wl_cfg80211_notify_ifadd(struct net_device *dev, int ifidx, char *name,
3633 uint8 *mac, uint8 bssidx, uint8 role)
3634 {
3635 bool ifadd_expected = FALSE;
3636 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3637 bool bss_pending_op = TRUE;
3638
3639 /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating
3640 * ("p2p_ifupd") redirect the IF_ADD event to ifchange as it is not a real
3641 * "new" interface
3642 */
3643 if (wl_get_p2p_status(cfg, IF_CHANGING)) {
3644 return wl_cfg80211_notify_ifchange(dev, ifidx, name, mac, bssidx);
3645 }
3646
3647 /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
3648 if (wl_get_p2p_status(cfg, IF_ADDING)) {
3649 ifadd_expected = TRUE;
3650 wl_clr_p2p_status(cfg, IF_ADDING);
3651 } else if (cfg->bss_pending_op) {
3652 ifadd_expected = TRUE;
3653 bss_pending_op = FALSE;
3654 }
3655
3656 if (ifadd_expected) {
3657 wl_if_event_info *if_event_info = &cfg->if_event_info;
3658
3659 if_event_info->valid = TRUE;
3660 if_event_info->ifidx = ifidx;
3661 if_event_info->bssidx = bssidx;
3662 if_event_info->role = role;
3663 strlcpy(if_event_info->name, name, sizeof(if_event_info->name));
3664 if_event_info->name[IFNAMSIZ - 1] = '\0';
3665 if (mac) {
3666 memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
3667 }
3668
3669 /* Update bss pendig operation status */
3670 if (!bss_pending_op) {
3671 cfg->bss_pending_op = FALSE;
3672 }
3673 WL_INFORM_MEM(
3674 ("IF_ADD ifidx:%d bssidx:%d role:%d\n", ifidx, bssidx, role));
3675 OSL_SMP_WMB();
3676 wake_up_interruptible(&cfg->netif_change_event);
3677 return BCME_OK;
3678 }
3679
3680 return BCME_ERROR;
3681 }
3682
wl_cfg80211_notify_ifdel(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)3683 s32 wl_cfg80211_notify_ifdel(struct net_device *dev, int ifidx, char *name,
3684 uint8 *mac, uint8 bssidx)
3685 {
3686 bool ifdel_expected = FALSE;
3687 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3688 wl_if_event_info *if_event_info = &cfg->if_event_info;
3689 bool bss_pending_op = TRUE;
3690
3691 if (wl_get_p2p_status(cfg, IF_DELETING)) {
3692 ifdel_expected = TRUE;
3693 wl_clr_p2p_status(cfg, IF_DELETING);
3694 } else if (cfg->bss_pending_op) {
3695 ifdel_expected = TRUE;
3696 bss_pending_op = FALSE;
3697 }
3698
3699 if (ifdel_expected) {
3700 if_event_info->valid = TRUE;
3701 if_event_info->ifidx = ifidx;
3702 if_event_info->bssidx = bssidx;
3703 /* Update bss pendig operation status */
3704 if (!bss_pending_op) {
3705 cfg->bss_pending_op = FALSE;
3706 }
3707 WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx, bssidx));
3708 OSL_SMP_WMB();
3709 wake_up_interruptible(&cfg->netif_change_event);
3710 return BCME_OK;
3711 }
3712
3713 return BCME_ERROR;
3714 }
3715
wl_cfg80211_notify_ifchange(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)3716 s32 wl_cfg80211_notify_ifchange(struct net_device *dev, int ifidx, char *name,
3717 uint8 *mac, uint8 bssidx)
3718 {
3719 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3720
3721 if (wl_get_p2p_status(cfg, IF_CHANGING)) {
3722 wl_set_p2p_status(cfg, IF_CHANGED);
3723 OSL_SMP_WMB();
3724 wake_up_interruptible(&cfg->netif_change_event);
3725 return BCME_OK;
3726 }
3727
3728 return BCME_ERROR;
3729 }
3730
wl_set_rts(struct net_device * dev,u32 rts_threshold)3731 static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
3732 {
3733 s32 err = 0;
3734
3735 err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
3736 if (unlikely(err)) {
3737 WL_ERR(("Error (%d)\n", err));
3738 return err;
3739 }
3740 return err;
3741 }
3742
wl_set_frag(struct net_device * dev,u32 frag_threshold)3743 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
3744 {
3745 s32 err = 0;
3746
3747 err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
3748 if (unlikely(err)) {
3749 WL_ERR(("Error (%d)\n", err));
3750 return err;
3751 }
3752 return err;
3753 }
3754
wl_set_retry(struct net_device * dev,u32 retry,bool l)3755 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
3756 {
3757 s32 err = 0;
3758 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
3759
3760 #ifdef CUSTOM_LONG_RETRY_LIMIT
3761 if ((cmd == WLC_SET_LRL) && (retry != CUSTOM_LONG_RETRY_LIMIT)) {
3762 WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
3763 return err;
3764 }
3765 #endif /* CUSTOM_LONG_RETRY_LIMIT */
3766
3767 retry = htod32(retry);
3768 err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry));
3769 if (unlikely(err)) {
3770 WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
3771 return err;
3772 }
3773 return err;
3774 }
3775
wl_cfg80211_set_wiphy_params(struct wiphy * wiphy,u32 changed)3776 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
3777 {
3778 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
3779 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
3780 s32 err = 0;
3781
3782 RETURN_EIO_IF_NOT_UP(cfg);
3783 WL_DBG(("Enter\n"));
3784 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
3785 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
3786 cfg->conf->rts_threshold = wiphy->rts_threshold;
3787 err = wl_set_rts(ndev, cfg->conf->rts_threshold);
3788 if (err != BCME_OK) {
3789 return err;
3790 }
3791 }
3792 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
3793 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
3794 cfg->conf->frag_threshold = wiphy->frag_threshold;
3795 err = wl_set_frag(ndev, cfg->conf->frag_threshold);
3796 if (err != BCME_OK) {
3797 return err;
3798 }
3799 }
3800 if (changed & WIPHY_PARAM_RETRY_LONG &&
3801 (cfg->conf->retry_long != wiphy->retry_long)) {
3802 cfg->conf->retry_long = wiphy->retry_long;
3803 err = wl_set_retry(ndev, cfg->conf->retry_long, true);
3804 if (err != BCME_OK) {
3805 return err;
3806 }
3807 }
3808 if (changed & WIPHY_PARAM_RETRY_SHORT &&
3809 (cfg->conf->retry_short != wiphy->retry_short)) {
3810 cfg->conf->retry_short = wiphy->retry_short;
3811 err = wl_set_retry(ndev, cfg->conf->retry_short, false);
3812 if (err != BCME_OK) {
3813 return err;
3814 }
3815 }
3816
3817 return err;
3818 }
channel_to_chanspec(struct wiphy * wiphy,struct net_device * dev,u32 channel,u32 bw_cap)3819 static chanspec_t channel_to_chanspec(struct wiphy *wiphy,
3820 struct net_device *dev, u32 channel,
3821 u32 bw_cap)
3822 {
3823 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3824 u8 *buf = NULL;
3825 wl_uint32_list_t *list;
3826 int err = BCME_OK;
3827 chanspec_t c = 0, ret_c = 0;
3828 int bw = 0, tmp_bw = 0;
3829 int i;
3830 u32 tmp_c;
3831
3832 #define LOCAL_BUF_SIZE 1024
3833 buf = (u8 *)MALLOC(cfg->osh, LOCAL_BUF_SIZE);
3834 if (!buf) {
3835 WL_ERR(("buf memory alloc failed\n"));
3836 goto exit;
3837 }
3838
3839 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, 0, buf,
3840 LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync);
3841 if (err != BCME_OK) {
3842 WL_ERR(("get chanspecs failed with %d\n", err));
3843 goto exit;
3844 }
3845
3846 list = (wl_uint32_list_t *)(void *)buf;
3847 for (i = 0; i < dtoh32(list->count); i++) {
3848 c = dtoh32(list->element[i]);
3849 if (channel <= CH_MAX_2G_CHANNEL) {
3850 if (!CHSPEC_IS20(c)) {
3851 continue;
3852 }
3853 if (channel == CHSPEC_CHANNEL(c)) {
3854 ret_c = c;
3855 bw = 20;
3856 goto exit;
3857 }
3858 }
3859 tmp_c = wf_chspec_ctlchan(c);
3860 tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT];
3861 if (tmp_c != channel) {
3862 continue;
3863 }
3864
3865 if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) {
3866 bw = tmp_bw;
3867 ret_c = c;
3868 if (bw == bw_cap) {
3869 goto exit;
3870 }
3871 }
3872 }
3873 exit:
3874 if (buf) {
3875 MFREE(cfg->osh, buf, LOCAL_BUF_SIZE);
3876 }
3877 #undef LOCAL_BUF_SIZE
3878 WL_DBG(("return chanspec %x %d\n", ret_c, bw));
3879 return ret_c;
3880 }
3881
wl_cfg80211_ibss_vsie_set_buffer(struct net_device * dev,vndr_ie_setbuf_t * ibss_vsie,int ibss_vsie_len)3882 void wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev,
3883 vndr_ie_setbuf_t *ibss_vsie,
3884 int ibss_vsie_len)
3885 {
3886 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3887
3888 if (cfg != NULL && ibss_vsie != NULL) {
3889 if (cfg->ibss_vsie != NULL) {
3890 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3891 }
3892 cfg->ibss_vsie = ibss_vsie;
3893 cfg->ibss_vsie_len = ibss_vsie_len;
3894 }
3895 }
3896
wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 * cfg)3897 static void wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
3898 {
3899 /* free & initiralize VSIE (Vendor Specific IE) */
3900 if (cfg->ibss_vsie != NULL) {
3901 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3902 cfg->ibss_vsie_len = 0;
3903 }
3904 }
3905
wl_cfg80211_ibss_vsie_delete(struct net_device * dev)3906 s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
3907 {
3908 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3909 char *ioctl_buf = NULL;
3910 s32 ret = BCME_OK, bssidx;
3911
3912 if (cfg != NULL && cfg->ibss_vsie != NULL) {
3913 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
3914 if (!ioctl_buf) {
3915 WL_ERR(("ioctl memory alloc failed\n"));
3916 return -ENOMEM;
3917 }
3918 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3919 WL_ERR(("Find index failed\n"));
3920 ret = BCME_ERROR;
3921 goto end;
3922 }
3923 /* change the command from "add" to "del" */
3924 strlcpy(cfg->ibss_vsie->cmd, "del", sizeof(cfg->ibss_vsie->cmd));
3925
3926 ret = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", cfg->ibss_vsie,
3927 cfg->ibss_vsie_len, ioctl_buf,
3928 WLC_IOCTL_MEDLEN, bssidx, NULL);
3929 WL_ERR(("ret=%d\n", ret));
3930
3931 if (ret == BCME_OK) {
3932 /* Free & initialize VSIE */
3933 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
3934 cfg->ibss_vsie_len = 0;
3935 }
3936 end:
3937 if (ioctl_buf) {
3938 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
3939 }
3940 }
3941
3942 return ret;
3943 }
3944
3945 #ifdef WLAIBSS_MCHAN
bcm_cfg80211_add_ibss_if(struct wiphy * wiphy,char * name)3946 static bcm_struct_cfgdev *bcm_cfg80211_add_ibss_if(struct wiphy *wiphy,
3947 char *name)
3948 {
3949 int err = 0;
3950 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3951 struct wireless_dev *wdev = NULL;
3952 struct net_device *new_ndev = NULL;
3953 struct net_device *primary_ndev = NULL;
3954 long timeout;
3955 wl_aibss_if_t aibss_if;
3956 wl_if_event_info *event = NULL;
3957
3958 if (cfg->ibss_cfgdev != NULL) {
3959 WL_ERR(("IBSS interface %s already exists\n", name));
3960 return NULL;
3961 }
3962
3963 WL_ERR(("Try to create IBSS interface %s\n", name));
3964 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3965 /* generate a new MAC address for the IBSS interface */
3966 get_primary_mac(cfg, &cfg->ibss_if_addr);
3967 cfg->ibss_if_addr.octet[0x4] ^= 0x40;
3968 bzero(&aibss_if, sizeof(aibss_if));
3969 memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
3970 aibss_if.chspec = 0;
3971 aibss_if.len = sizeof(aibss_if);
3972
3973 cfg->bss_pending_op = TRUE;
3974 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3975 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
3976 sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
3977 &cfg->ioctl_buf_sync);
3978 if (err) {
3979 WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
3980 goto fail;
3981 }
3982 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3983 !cfg->bss_pending_op,
3984 msecs_to_jiffies(MAX_WAIT_TIME));
3985 if (timeout <= 0 || cfg->bss_pending_op) {
3986 goto fail;
3987 }
3988
3989 event = &cfg->if_event_info;
3990 /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give
3991 * the control over this net_device interface to dhd_linux, hence the
3992 * interface is managed by dhd_liux and will be freed by dhd_detach unless
3993 * it gets unregistered before that. The wireless_dev instance
3994 * new_ndev->ieee80211_ptr associated with this net_device will be freed by
3995 * wl_dealloc_netinfo
3996 */
3997 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name,
3998 event->mac, event->bssidx, event->name);
3999 if (new_ndev == NULL) {
4000 goto fail;
4001 }
4002 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
4003 if (wdev == NULL) {
4004 goto fail;
4005 }
4006 wdev->wiphy = wiphy;
4007 wdev->iftype = NL80211_IFTYPE_ADHOC;
4008 wdev->netdev = new_ndev;
4009 new_ndev->ieee80211_ptr = wdev;
4010 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4011
4012 /* rtnl lock must have been acquired, if this is not the case,
4013 * wl_cfg80211_register_if needs to be modified to take one parameter (bool
4014 * need_rtnl_lock)
4015 */
4016 ASSERT_RTNL();
4017 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, FALSE) !=
4018 BCME_OK) {
4019 goto fail;
4020 }
4021
4022 wl_alloc_netinfo(cfg, new_ndev, wdev, WL_IF_TYPE_IBSS, PM_ENABLE,
4023 event->bssidx, event->ifidx);
4024 cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
4025 WL_ERR(("IBSS interface %s created\n", new_ndev->name));
4026 return cfg->ibss_cfgdev;
4027
4028 fail:
4029 WL_ERR(("failed to create IBSS interface %s \n", name));
4030 cfg->bss_pending_op = FALSE;
4031 if (new_ndev) {
4032 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
4033 }
4034 if (wdev) {
4035 MFREE(cfg->osh, wdev, sizeof(*wdev));
4036 }
4037 return NULL;
4038 }
4039
bcm_cfg80211_del_ibss_if(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev)4040 static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy,
4041 bcm_struct_cfgdev *cfgdev)
4042 {
4043 int err = 0;
4044 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4045 struct net_device *ndev = NULL;
4046 struct net_device *primary_ndev = NULL;
4047 long timeout;
4048
4049 if (!cfgdev || cfg->ibss_cfgdev != cfgdev ||
4050 ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet)) {
4051 return -EINVAL;
4052 }
4053 ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev);
4054 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4055
4056 cfg->bss_pending_op = TRUE;
4057 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
4058 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
4059 sizeof(cfg->ibss_if_addr), cfg->ioctl_buf,
4060 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4061 if (err) {
4062 WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
4063 goto fail;
4064 }
4065 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4066 !cfg->bss_pending_op,
4067 msecs_to_jiffies(MAX_WAIT_TIME));
4068 if (timeout <= 0 || cfg->bss_pending_op) {
4069 WL_ERR(("timeout in waiting IF_DEL event\n"));
4070 goto fail;
4071 }
4072
4073 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
4074 cfg->ibss_cfgdev = NULL;
4075 return 0;
4076
4077 fail:
4078 cfg->bss_pending_op = FALSE;
4079 return -1;
4080 }
4081 #endif /* WLAIBSS_MCHAN */
4082
wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)4083 s32 wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)
4084 {
4085 s32 ret = BCME_ERROR;
4086
4087 switch (iftype) {
4088 case WL_IF_TYPE_AP:
4089 ret = WL_INTERFACE_TYPE_AP;
4090 break;
4091 case WL_IF_TYPE_STA:
4092 ret = WL_INTERFACE_TYPE_STA;
4093 break;
4094 case WL_IF_TYPE_NAN_NMI:
4095 case WL_IF_TYPE_NAN:
4096 ret = WL_INTERFACE_TYPE_NAN;
4097 break;
4098 case WL_IF_TYPE_P2P_DISC:
4099 ret = WL_INTERFACE_TYPE_P2P_DISC;
4100 break;
4101 case WL_IF_TYPE_P2P_GO:
4102 ret = WL_INTERFACE_TYPE_P2P_GO;
4103 break;
4104 case WL_IF_TYPE_P2P_GC:
4105 ret = WL_INTERFACE_TYPE_P2P_GC;
4106 break;
4107
4108 default:
4109 WL_ERR(("Unsupported type:%d \n", iftype));
4110 ret = -EINVAL;
4111 break;
4112 }
4113 return ret;
4114 }
4115
wl_cfg80211_interface_ops(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,wl_iftype_t cfg_iftype,s32 del,u8 * addr)4116 s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg, struct net_device *ndev,
4117 s32 bsscfg_idx, wl_iftype_t cfg_iftype, s32 del,
4118 u8 *addr)
4119 {
4120 s32 ret;
4121 struct wl_interface_create_v2 iface;
4122 wl_interface_create_v3_t iface_v3;
4123 wl_interface_create_t iface_v0;
4124 struct wl_interface_info_v1 *info;
4125 wl_interface_info_v2_t *info_v2;
4126 wl_interface_info_t *info_v0;
4127 uint32 ifflags = 0;
4128 bool use_iface_info_v2 = false;
4129 u8 ioctl_buf[WLC_IOCTL_SMLEN];
4130 s32 iftype;
4131 #ifdef WLEASYMESH
4132 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
4133 #endif /* WLEASYMESH */
4134
4135 if (del) {
4136 ret = wldev_iovar_setbuf(ndev, "interface_remove", NULL, 0, ioctl_buf,
4137 sizeof(ioctl_buf), NULL);
4138 if (unlikely(ret)) {
4139 WL_ERR(("Interface remove failed!! ret %d\n", ret));
4140 }
4141 return ret;
4142 }
4143
4144 /* Interface create */
4145 bzero(&iface, sizeof(iface));
4146 /*
4147 * flags field is still used along with iftype inorder to support the old
4148 * version of the FW work with the latest app changes.
4149 */
4150
4151 iftype = wl_cfg80211_to_fw_iftype(cfg_iftype);
4152 if (iftype < 0) {
4153 return -ENOTSUPP;
4154 }
4155
4156 if (addr) {
4157 ifflags |= WL_INTERFACE_MAC_USE;
4158 }
4159 #ifdef WLEASYMESH
4160 if (dhd->conf->fw_type == FW_TYPE_EZMESH &&
4161 iftype == WL_INTERFACE_TYPE_AP) {
4162 // this can be removed for 4359
4163 ifflags |= WL_INTERFACE_TYPE_AP;
4164 }
4165 #endif /* WLEASYMESH */
4166
4167 /* Pass ver = 0 for fetching the interface_create iovar version */
4168 if (wl_legacy_chip_check(ndev)) {
4169 bzero(&iface_v0, sizeof(iface_v0));
4170 iface_v0.ver = WL_INTERFACE_CREATE_VER;
4171 iface_v0.flags = iftype | ifflags;
4172 if (addr) {
4173 memcpy(&iface_v0.mac_addr.octet, addr, ETH_ALEN);
4174 }
4175 ret = wldev_iovar_getbuf(ndev, "interface_create", &iface_v0,
4176 sizeof(struct wl_interface_create), ioctl_buf,
4177 sizeof(ioctl_buf), NULL);
4178 if (ret == 0) {
4179 info_v0 = (wl_interface_info_t *)ioctl_buf;
4180 ret = info_v0->bsscfgidx;
4181 goto exit;
4182 }
4183 } else {
4184 ret = wldev_iovar_getbuf(ndev, "interface_create", &iface,
4185 sizeof(struct wl_interface_create_v2),
4186 ioctl_buf, sizeof(ioctl_buf), NULL);
4187 }
4188 if (ret == BCME_UNSUPPORTED) {
4189 WL_ERR(("interface_create iovar not supported\n"));
4190 return ret;
4191 } else if ((ret == 0) &&
4192 *((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3) {
4193 WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags));
4194 use_iface_info_v2 = true;
4195 bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
4196 iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
4197 iface_v3.iftype = iftype;
4198 iface_v3.flags = ifflags;
4199 if (addr) {
4200 memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
4201 }
4202 ret = wldev_iovar_getbuf(ndev, "interface_create", &iface_v3,
4203 sizeof(wl_interface_create_v3_t), ioctl_buf,
4204 sizeof(ioctl_buf), NULL);
4205 } else {
4206 /* On any other error, attempt with iovar version 2 */
4207 WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n", ret,
4208 ifflags));
4209 iface.ver = WL_INTERFACE_CREATE_VER_2;
4210 iface.iftype = iftype;
4211 iface.flags = ifflags;
4212 if (addr) {
4213 memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
4214 }
4215 ret = wldev_iovar_getbuf(ndev, "interface_create", &iface,
4216 sizeof(struct wl_interface_create_v2),
4217 ioctl_buf, sizeof(ioctl_buf), NULL);
4218 }
4219
4220 if (unlikely(ret)) {
4221 WL_ERR(("Interface create failed!! ret %d\n", ret));
4222 return ret;
4223 }
4224
4225 /* success case */
4226 if (use_iface_info_v2 == true) {
4227 info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
4228 ret = info_v2->bsscfgidx;
4229 } else {
4230 /* Use v1 struct */
4231 info = (struct wl_interface_info_v1 *)ioctl_buf;
4232 ret = info->bsscfgidx;
4233 }
4234
4235 exit:
4236 #ifdef WLEASYMESH
4237 // Give fw more time to process interface_create
4238 if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
4239 wl_delay(0x1F4);
4240 }
4241 #endif /* WLEASYMESH */
4242 WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
4243 return ret;
4244 }
4245
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)4246 s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
4247 s32 bsscfg_idx, wl_iftype_t brcm_iftype, s32 del,
4248 u8 *addr)
4249 {
4250 s32 ret = BCME_OK;
4251 s32 val = 0;
4252
4253 struct {
4254 s32 cfg;
4255 s32 val;
4256 struct ether_addr ea;
4257 } bss_setbuf;
4258
4259 WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype, del));
4260
4261 bzero(&bss_setbuf, sizeof(bss_setbuf));
4262
4263 /* AP=2, STA=3, up=1, down=0, val=-1 */
4264 if (del) {
4265 val = WLC_AP_IOV_OP_DELETE;
4266 } else if (brcm_iftype == WL_IF_TYPE_AP) {
4267 /* Add/role change to AP Interface */
4268 WL_DBG(("Adding AP Interface \n"));
4269 val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
4270 } else if (brcm_iftype == WL_IF_TYPE_STA) {
4271 /* Add/role change to STA Interface */
4272 WL_DBG(("Adding STA Interface \n"));
4273 val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
4274 } else {
4275 WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype));
4276 return -EINVAL;
4277 }
4278
4279 if (!del) {
4280 wl_ext_bss_iovar_war(ndev, &val);
4281 }
4282
4283 bss_setbuf.cfg = htod32(bsscfg_idx);
4284 bss_setbuf.val = htod32(val);
4285
4286 if (addr) {
4287 memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
4288 }
4289
4290 WL_MSG(ndev->name, "wl bss %d bssidx:%d\n", val, bsscfg_idx);
4291 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4292 cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
4293 &cfg->ioctl_buf_sync);
4294 if (ret != 0) {
4295 WL_ERR(("'bss %d' failed with %d\n", val, ret));
4296 }
4297
4298 return ret;
4299 }
4300
wl_cfg80211_bss_up(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,s32 bss_up)4301 s32 wl_cfg80211_bss_up(struct bcm_cfg80211 *cfg, struct net_device *ndev,
4302 s32 bsscfg_idx, s32 bss_up)
4303 {
4304 s32 ret = BCME_OK;
4305 s32 val = bss_up ? 1 : 0;
4306
4307 struct {
4308 s32 cfg;
4309 s32 val;
4310 } bss_setbuf;
4311
4312 bss_setbuf.cfg = htod32(bsscfg_idx);
4313 bss_setbuf.val = htod32(val);
4314
4315 WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx, bss_up ? "up" : "down"));
4316 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4317 cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
4318 &cfg->ioctl_buf_sync);
4319 if (ret != 0) {
4320 WL_ERR(("'bss %d' failed with %d\n", bss_up, ret));
4321 }
4322 return ret;
4323 }
4324
wl_cfg80211_bss_isup(struct net_device * ndev,int bsscfg_idx)4325 bool wl_cfg80211_bss_isup(struct net_device *ndev, int bsscfg_idx)
4326 {
4327 s32 result, val;
4328 bool isup = false;
4329 s8 getbuf[64];
4330
4331 /* Check if the BSS is up */
4332 *(int *)getbuf = -1;
4333 result =
4334 wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, sizeof(bsscfg_idx),
4335 getbuf, sizeof(getbuf), 0, NULL);
4336 if (result != 0) {
4337 WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
4338 WL_ERR(("NOTE: this ioctl error is normal "
4339 "when the BSS has not been created yet.\n"));
4340 } else {
4341 val = *(int *)getbuf;
4342 val = dtoh32(val);
4343 WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx, val));
4344 isup = (val ? TRUE : FALSE);
4345 }
4346 return isup;
4347 }
4348
wl_iftype_to_mode(wl_iftype_t iftype)4349 s32 wl_iftype_to_mode(wl_iftype_t iftype)
4350 {
4351 s32 mode = BCME_ERROR;
4352
4353 switch (iftype) {
4354 case WL_IF_TYPE_STA:
4355 case WL_IF_TYPE_P2P_GC:
4356 case WL_IF_TYPE_P2P_DISC:
4357 mode = WL_MODE_BSS;
4358 break;
4359 case WL_IF_TYPE_AP:
4360 case WL_IF_TYPE_P2P_GO:
4361 mode = WL_MODE_AP;
4362 break;
4363 case WL_IF_TYPE_NAN:
4364 mode = WL_MODE_NAN;
4365 break;
4366 case WL_IF_TYPE_AIBSS:
4367 /* Intentional fall through */
4368 case WL_IF_TYPE_IBSS:
4369 mode = WL_MODE_IBSS;
4370 break;
4371 #ifdef WLMESH_CFG80211
4372 case WL_IF_TYPE_MESH:
4373 mode = WL_MODE_MESH;
4374 break;
4375 #endif /* WLMESH_CFG80211 */
4376 default:
4377 WL_ERR(("Unsupported type:%d\n", iftype));
4378 break;
4379 }
4380 return mode;
4381 }
4382
cfg80211_to_wl_iftype(uint16 type,uint16 * role,uint16 * mode)4383 s32 cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode)
4384 {
4385 switch (type) {
4386 case NL80211_IFTYPE_STATION:
4387 *role = WL_IF_TYPE_STA;
4388 *mode = WL_MODE_BSS;
4389 break;
4390 case NL80211_IFTYPE_AP:
4391 *role = WL_IF_TYPE_AP;
4392 *mode = WL_MODE_AP;
4393 break;
4394 #ifdef WL_CFG80211_P2P_DEV_IF
4395 case NL80211_IFTYPE_P2P_DEVICE:
4396 *role = WL_IF_TYPE_P2P_DISC;
4397 *mode = WL_MODE_BSS;
4398 break;
4399 #endif /* WL_CFG80211_P2P_DEV_IF */
4400 case NL80211_IFTYPE_P2P_GO:
4401 *role = WL_IF_TYPE_P2P_GO;
4402 *mode = WL_MODE_AP;
4403 break;
4404 case NL80211_IFTYPE_P2P_CLIENT:
4405 *role = WL_IF_TYPE_P2P_GC;
4406 *mode = WL_MODE_BSS;
4407 break;
4408 case NL80211_IFTYPE_MONITOR:
4409 WL_ERR(("Unsupported mode \n"));
4410 return BCME_UNSUPPORTED;
4411 case NL80211_IFTYPE_ADHOC:
4412 *role = WL_IF_TYPE_IBSS;
4413 *mode = WL_MODE_IBSS;
4414 break;
4415 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
4416 case NL80211_IFTYPE_NAN:
4417 *role = WL_IF_TYPE_NAN;
4418 *mode = WL_MODE_NAN;
4419 break;
4420 #endif // endif
4421 #ifdef WLMESH_CFG80211
4422 case NL80211_IFTYPE_MESH_POINT:
4423 *role = WLC_E_IF_ROLE_AP;
4424 *mode = WL_MODE_MESH;
4425 break;
4426 #endif /* WLMESH_CFG80211 */
4427 default:
4428 WL_ERR(("Unknown interface type:0x%x\n", type));
4429 return BCME_ERROR;
4430 }
4431 return BCME_OK;
4432 }
4433
wl_role_to_cfg80211_type(uint16 role,uint16 * wl_iftype,uint16 * mode)4434 static s32 wl_role_to_cfg80211_type(uint16 role, uint16 *wl_iftype,
4435 uint16 *mode)
4436 {
4437 switch (role) {
4438 case WLC_E_IF_ROLE_STA:
4439 *wl_iftype = WL_IF_TYPE_STA;
4440 *mode = WL_MODE_BSS;
4441 return NL80211_IFTYPE_STATION;
4442 case WLC_E_IF_ROLE_AP:
4443 *wl_iftype = WL_IF_TYPE_AP;
4444 *mode = WL_MODE_AP;
4445 return NL80211_IFTYPE_AP;
4446 case WLC_E_IF_ROLE_P2P_GO:
4447 *wl_iftype = WL_IF_TYPE_P2P_GO;
4448 *mode = WL_MODE_AP;
4449 return NL80211_IFTYPE_P2P_GO;
4450 case WLC_E_IF_ROLE_P2P_CLIENT:
4451 *wl_iftype = WL_IF_TYPE_P2P_GC;
4452 *mode = WL_MODE_BSS;
4453 return NL80211_IFTYPE_P2P_CLIENT;
4454 case WLC_E_IF_ROLE_IBSS:
4455 *wl_iftype = WL_IF_TYPE_IBSS;
4456 *mode = WL_MODE_IBSS;
4457 return NL80211_IFTYPE_ADHOC;
4458 case WLC_E_IF_ROLE_NAN:
4459 *wl_iftype = WL_IF_TYPE_NAN;
4460 *mode = WL_MODE_NAN;
4461 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
4462 /* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
4463 * For Vendor HAL based NAN implementation, continue advertising
4464 * as a STA interface
4465 */
4466 return NL80211_IFTYPE_NAN;
4467 #else
4468 return NL80211_IFTYPE_STATION;
4469 #endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
4470 #ifdef WLDWDS
4471 case WLC_E_IF_ROLE_WDS:
4472 *wl_iftype = WL_IF_TYPE_AP;
4473 *mode = WL_MODE_AP;
4474 return NL80211_IFTYPE_AP;
4475 #endif
4476 #ifdef WLMESH_CFG80211
4477 case WLC_E_IF_ROLE_MESH:
4478 *wl_iftype = WL_IF_TYPE_MESH;
4479 *mode = WL_MODE_MESH;
4480 return NL80211_IFTYPE_MESH_POINT;
4481 #endif /* WLMESH_CFG80211 */
4482
4483 default:
4484 WL_ERR(
4485 ("Unknown interface role:0x%x. Forcing type station\n", role));
4486 return BCME_ERROR;
4487 }
4488 }
4489
wl_cfg80211_post_ifcreate(struct net_device * ndev,wl_if_event_info * event,u8 * addr,const char * name,bool rtnl_lock_reqd)4490 struct net_device *wl_cfg80211_post_ifcreate(struct net_device *ndev,
4491 wl_if_event_info *event, u8 *addr,
4492 const char *name,
4493 bool rtnl_lock_reqd)
4494 {
4495 struct bcm_cfg80211 *cfg;
4496 struct net_device *primary_ndev;
4497 struct net_device *new_ndev = NULL;
4498 struct wireless_dev *wdev = NULL;
4499 s32 iface_type;
4500 s32 ret = BCME_OK;
4501 u16 mode;
4502 u8 mac_addr[ETH_ALEN];
4503 u16 wl_iftype;
4504 #ifdef WL_STATIC_IF
4505 int static_ifidx;
4506 #endif
4507
4508 if (!ndev || !event) {
4509 WL_ERR(("Wrong arg\n"));
4510 return NULL;
4511 }
4512
4513 cfg = wl_get_cfg(ndev);
4514 if (!cfg) {
4515 WL_ERR(("cfg null\n"));
4516 return NULL;
4517 }
4518
4519 WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n", event->role, event->ifidx,
4520 event->bssidx));
4521 if (!event->ifidx || !event->bssidx) {
4522 /* Fw returned primary idx (0) for virtual interface */
4523 WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n", event->ifidx,
4524 event->bssidx));
4525 return NULL;
4526 }
4527
4528 #if defined(WLMESH_CFG80211) && defined(WL_EXT_IAPSTA)
4529 if (wl_ext_iapsta_mesh_creating(ndev)) {
4530 event->role = WLC_E_IF_ROLE_MESH;
4531 WL_MSG(ndev->name, "change role to WLC_E_IF_ROLE_MESH\n");
4532 }
4533 #endif /* WLMESH_CFG80211 && WL_EXT_IAPSTA */
4534
4535 iface_type = wl_role_to_cfg80211_type(event->role, &wl_iftype, &mode);
4536 if (iface_type < 0) {
4537 /* Unknown iface type */
4538 WL_ERR(("Wrong iface type \n"));
4539 return NULL;
4540 }
4541
4542 WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG "\n", addr,
4543 name, event->role, iface_type, MAC2STRDBG(event->mac)));
4544 if (!name) {
4545 /* If iface name is not provided, use dongle ifname */
4546 name = event->name;
4547 }
4548
4549 if (!addr) {
4550 /* If mac address is not set, use primary mac with locally administered
4551 * bit set.
4552 */
4553 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4554 memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
4555 /* For customer6 builds, use primary mac address for virtual interface
4556 */
4557 mac_addr[0] |= 0x02;
4558 addr = mac_addr;
4559 }
4560
4561 #ifdef WL_STATIC_IF
4562 static_ifidx = wl_cfg80211_static_if_name(cfg, name);
4563 if (static_ifidx >= 0) {
4564 new_ndev = wl_cfg80211_post_static_ifcreate(cfg, event, addr,
4565 iface_type, static_ifidx);
4566 if (!new_ndev) {
4567 WL_ERR(("failed to get I/F pointer\n"));
4568 return NULL;
4569 }
4570 wdev = new_ndev->ieee80211_ptr;
4571 } else
4572 #endif /* WL_STATIC_IF */
4573 {
4574 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, name, addr,
4575 event->bssidx, event->name);
4576 if (!new_ndev) {
4577 WL_ERR(("I/F allocation failed! \n"));
4578 return NULL;
4579 } else {
4580 WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
4581 event->ifidx, event->bssidx));
4582 }
4583
4584 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
4585 if (!wdev) {
4586 WL_ERR(("wireless_dev alloc failed! \n"));
4587 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4588 return NULL;
4589 }
4590
4591 wdev->wiphy = bcmcfg_to_wiphy(cfg);
4592 wdev->iftype = iface_type;
4593
4594 new_ndev->ieee80211_ptr = wdev;
4595 #ifdef WLDWDS
4596 /* set wds0.x to 4addr interface here */
4597 if (event->role == WLC_E_IF_ROLE_WDS) {
4598 WL_MSG(ndev->name, "set vwdev 4addr to %s\n", event->name);
4599 wdev->use_4addr = true;
4600 }
4601 #endif /* WLDWDS */
4602 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4603
4604 memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
4605 #ifdef WL_EXT_IAPSTA
4606 wl_ext_iapsta_ifadding(new_ndev, event->ifidx);
4607 #endif /* WL_EXT_IAPSTA */
4608 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev,
4609 rtnl_lock_reqd) != BCME_OK) {
4610 WL_ERR(("IFACE register failed \n"));
4611 /* Post interface registration, wdev would be freed from the netdev
4612 * destructor path. For other cases, handle it here.
4613 */
4614 MFREE(cfg->osh, wdev, sizeof(*wdev));
4615 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4616 return NULL;
4617 }
4618 }
4619
4620 /* Initialize with the station mode params */
4621 ret = wl_alloc_netinfo(cfg, new_ndev, wdev, wl_iftype, PM_ENABLE,
4622 event->bssidx, event->ifidx);
4623 if (unlikely(ret)) {
4624 WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret));
4625 goto fail;
4626 }
4627
4628 /* Apply the mode & infra setting based on iftype */
4629 if ((ret = wl_config_infra(cfg, new_ndev, wl_iftype)) < 0) {
4630 WL_ERR(("config ifmode failure (%d)\n", ret));
4631 goto fail;
4632 }
4633
4634 if (mode == WL_MODE_AP) {
4635 wl_set_drv_status(cfg, AP_CREATING, new_ndev);
4636 }
4637 #ifdef WL_EXT_IAPSTA
4638 wl_ext_iapsta_update_iftype(new_ndev, event->ifidx, wl_iftype);
4639 #endif
4640
4641 WL_INFORM_MEM(("Network Interface (%s) registered with host."
4642 " cfg_iftype:%d wl_role:%d " MACDBG "\n",
4643 new_ndev->name, iface_type, event->role,
4644 MAC2STRDBG(new_ndev->dev_addr)));
4645
4646 #ifdef SUPPORT_SET_CAC
4647 wl_cfg80211_set_cac(cfg, 0);
4648 #endif /* SUPPORT_SET_CAC */
4649
4650 return new_ndev;
4651
4652 fail:
4653 #ifdef WL_STATIC_IF
4654 /* remove static if from iflist */
4655 static_ifidx = wl_cfg80211_static_if_name(cfg, name);
4656 if (static_ifidx >= 0) {
4657 cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_FAILED;
4658 wl_cfg80211_update_iflist_info(
4659 cfg, new_ndev, WL_STATIC_IFIDX + static_ifidx, addr, event->bssidx,
4660 event->name, NDEV_STATE_FW_IF_FAILED);
4661 }
4662 #endif /* WL_STATIC_IF */
4663 if (new_ndev) {
4664 /* wdev would be freed from netdev destructor call back */
4665 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4666 }
4667
4668 return NULL;
4669 }
4670
wl_cfg80211_delete_iface(struct bcm_cfg80211 * cfg,wl_iftype_t sec_data_if_type)4671 s32 wl_cfg80211_delete_iface(struct bcm_cfg80211 *cfg,
4672 wl_iftype_t sec_data_if_type)
4673 {
4674 struct net_info *iter, *next;
4675 struct net_device *primary_ndev;
4676 s32 ret = BCME_OK;
4677 uint8 i = 0;
4678
4679 BCM_REFERENCE(i);
4680 BCM_REFERENCE(ret);
4681
4682 /* Note: This function will clean up only the network interface and host
4683 * data structures. The firmware interface clean up will happen in the
4684 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4685 * context for the module case).
4686 */
4687 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4688 WL_DBG(
4689 ("Enter, deleting iftype %s\n", wl_iftype_to_str(sec_data_if_type)));
4690 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4691 for_each_ndev(cfg, iter, next)
4692 {
4693 GCC_DIAGNOSTIC_POP();
4694 if (iter->ndev && (iter->ndev != primary_ndev)) {
4695 if (iter->iftype != sec_data_if_type) {
4696 continue;
4697 }
4698 switch (sec_data_if_type) {
4699 case WL_IF_TYPE_P2P_GO:
4700 case WL_IF_TYPE_P2P_GC: {
4701 ret = _wl_cfg80211_del_if(cfg, iter->ndev, NULL,
4702 iter->ndev->name);
4703 break;
4704 }
4705 #ifdef WL_NAN
4706 case WL_IF_TYPE_NAN: {
4707 if (cfg->nan_enable == false) {
4708 WL_INFORM_MEM(("Nan is not active,"
4709 " ignore NDI delete\n"));
4710 } else {
4711 ret = wl_cfgnan_delete_ndp(cfg, iter->ndev);
4712 }
4713 break;
4714 }
4715 #endif /* WL_NAN */
4716 case WL_IF_TYPE_AP: {
4717 /* Cleanup AP */
4718 #ifdef WL_STATIC_IF
4719 /* handle static ap */
4720 if (wl_cfg80211_static_if(cfg, iter->ndev)) {
4721 dev_close(iter->ndev);
4722 } else
4723 #endif /* WL_STATIC_IF */
4724 {
4725 /* handle virtual created AP */
4726 ret = _wl_cfg80211_del_if(cfg, iter->ndev, NULL,
4727 iter->ndev->name);
4728 }
4729 break;
4730 }
4731 default: {
4732 WL_ERR(("Unsupported interface type\n"));
4733 ret = -ENOTSUPP;
4734 goto fail;
4735 }
4736 }
4737 }
4738 }
4739 fail:
4740 return ret;
4741 }
4742
wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 * cfg,bool rtnl_lock_reqd)4743 void wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 *cfg,
4744 bool rtnl_lock_reqd)
4745 {
4746 struct net_info *iter, *next;
4747 struct net_device *primary_ndev;
4748
4749 /* Note: This function will clean up only the network interface and host
4750 * data structures. The firmware interface clean up will happen in the
4751 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4752 * context for the module case).
4753 */
4754 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4755 WL_DBG(("Enter\n"));
4756 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4757 for_each_ndev(cfg, iter, next)
4758 {
4759 GCC_DIAGNOSTIC_POP();
4760 if (iter->ndev && (iter->ndev != primary_ndev)) {
4761 /* Ensure interfaces are down before deleting */
4762 #ifdef WL_STATIC_IF
4763 /* Avoiding cleaning static ifaces */
4764 if (!wl_cfg80211_static_if(cfg, iter->ndev))
4765 #endif /* WL_STATIC_IF */
4766 {
4767 dev_close(iter->ndev);
4768 WL_DBG(("Cleaning up iface:%s \n", iter->ndev->name));
4769 wl_cfg80211_post_ifdel(iter->ndev, rtnl_lock_reqd, 0);
4770 }
4771 }
4772 }
4773 }
4774
wl_cfg80211_post_ifdel(struct net_device * ndev,bool rtnl_lock_reqd,s32 ifidx)4775 s32 wl_cfg80211_post_ifdel(struct net_device *ndev, bool rtnl_lock_reqd,
4776 s32 ifidx)
4777 {
4778 s32 ret = BCME_OK;
4779 struct bcm_cfg80211 *cfg;
4780 struct net_info *netinfo = NULL;
4781
4782 if (!ndev || !ndev->ieee80211_ptr) {
4783 /* No wireless dev done for this interface */
4784 ret = -EINVAL;
4785 goto exit;
4786 }
4787
4788 cfg = wl_get_cfg(ndev);
4789 if (!cfg) {
4790 WL_ERR(("cfg null\n"));
4791 ret = BCME_ERROR;
4792 goto exit;
4793 }
4794
4795 if (ifidx <= 0) {
4796 WL_ERR(("Invalid IF idx for iface:%s\n", ndev->name));
4797 ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
4798 BCM_REFERENCE(ifidx);
4799 if (ifidx <= 0) {
4800 ASSERT(0);
4801 ret = BCME_ERROR;
4802 goto exit;
4803 }
4804 }
4805
4806 if ((netinfo = wl_get_netinfo_by_wdev(cfg, ndev_to_wdev(ndev))) == NULL) {
4807 WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev)));
4808 ret = -ENODEV;
4809 goto exit;
4810 }
4811
4812 #ifdef WL_STATIC_IF
4813 if (wl_cfg80211_static_if(cfg, ndev)) {
4814 ret = wl_cfg80211_post_static_ifdel(cfg, ndev);
4815 } else
4816 #endif /* WL_STATIC_IF */
4817 {
4818 WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
4819 ndev->name, ifidx, cfg->vif_count));
4820 wl_cfg80211_remove_if(cfg, ifidx, ndev, rtnl_lock_reqd);
4821 cfg->bss_pending_op = FALSE;
4822 }
4823
4824 #ifdef SUPPORT_SET_CAC
4825 wl_cfg80211_set_cac(cfg, 1);
4826 #endif /* SUPPORT_SET_CAC */
4827 exit:
4828 return ret;
4829 }
4830
wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 * cfg)4831 int wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 *cfg)
4832 {
4833 s32 ret = BCME_OK;
4834 bcm_struct_cfgdev *cfgdev;
4835
4836 if (cfg->p2p) {
4837 /* De-initialize the p2p discovery interface, if operational */
4838 WL_ERR(("Disabling P2P Discovery Interface \n"));
4839 #ifdef WL_CFG80211_P2P_DEV_IF
4840 cfgdev = bcmcfg_to_p2p_wdev(cfg);
4841 #else
4842 cfgdev = cfg->p2p_net;
4843 #endif // endif
4844 if (cfgdev) {
4845 ret = wl_cfg80211_scan_stop(cfg, cfgdev);
4846 if (unlikely(ret < 0)) {
4847 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
4848 }
4849 }
4850
4851 wl_cfgp2p_disable_discovery(cfg);
4852 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
4853 p2p_on(cfg) = false;
4854 }
4855 return ret;
4856 }
4857
4858 /* Create a Generic Network Interface and initialize it depending up on
4859 * the interface type
4860 */
wl_cfg80211_create_iface(struct wiphy * wiphy,wl_iftype_t wl_iftype,u8 * mac_addr,const char * name)4861 struct wireless_dev *wl_cfg80211_create_iface(struct wiphy *wiphy,
4862 wl_iftype_t wl_iftype,
4863 u8 *mac_addr, const char *name)
4864 {
4865 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4866 struct net_device *new_ndev = NULL;
4867 struct net_device *primary_ndev = NULL;
4868 s32 ret = BCME_OK;
4869 s32 bsscfg_idx = 0;
4870 long timeout;
4871 wl_if_event_info *event = NULL;
4872 u8 addr[ETH_ALEN];
4873 struct net_info *iter, *next;
4874
4875 WL_DBG(("Enter\n"));
4876 if (!name) {
4877 WL_ERR(("Interface name not provided\n"));
4878 return NULL;
4879 } else {
4880 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4881 for_each_ndev(cfg, iter, next)
4882 {
4883 GCC_DIAGNOSTIC_POP();
4884 if (iter->ndev) {
4885 if (strncmp(iter->ndev->name, name, strlen(name)) == 0) {
4886 WL_ERR(("Interface name,%s exists!\n", iter->ndev->name));
4887 return NULL;
4888 }
4889 }
4890 }
4891 }
4892 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4893 if (likely(!mac_addr)) {
4894 /* Use primary MAC with the locally administered bit for the
4895 * Secondary STA I/F
4896 */
4897 memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
4898 addr[0] |= 0x02;
4899 } else {
4900 /* Use the application provided mac address (if any) */
4901 memcpy(addr, mac_addr, ETH_ALEN);
4902 }
4903
4904 cfg->bss_pending_op = TRUE;
4905 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
4906
4907 /*
4908 * Intialize the firmware I/F.
4909 */
4910 {
4911 ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
4912 wl_iftype, 0, addr);
4913 }
4914 if (ret == BCME_UNSUPPORTED) {
4915 /* Use bssidx 1 by default */
4916 bsscfg_idx = 1;
4917 if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev, bsscfg_idx,
4918 wl_iftype, 0, addr)) < 0) {
4919 goto exit;
4920 }
4921 } else if (ret < 0) {
4922 WL_ERR(("Interface create failed!! ret:%d \n", ret));
4923 goto exit;
4924 } else {
4925 /* Success */
4926 bsscfg_idx = ret;
4927 }
4928
4929 WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
4930 /*
4931 * Wait till the firmware send a confirmation event back.
4932 */
4933 WL_DBG(("Wait for the FW I/F Event\n"));
4934 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4935 !cfg->bss_pending_op,
4936 msecs_to_jiffies(MAX_WAIT_TIME));
4937 if (timeout <= 0 || cfg->bss_pending_op) {
4938 WL_ERR(("ADD_IF event, didn't come. Return. timeout:%lu "
4939 "bss_pending_op:%d\n",
4940 timeout, cfg->bss_pending_op));
4941 if (timeout == -ERESTARTSYS) {
4942 WL_ERR(("waitqueue was interrupted by a signal, returns "
4943 "-ERESTARTSYS\n"));
4944 }
4945 goto exit;
4946 }
4947
4948 event = &cfg->if_event_info;
4949 /*
4950 * Since FW operation is successful,we can go ahead with the
4951 * the host interface creation.
4952 */
4953 new_ndev =
4954 wl_cfg80211_post_ifcreate(primary_ndev, event, addr, name, false);
4955 if (new_ndev) {
4956 /* Iface post ops successful. Return ndev/wdev ptr */
4957 return new_ndev->ieee80211_ptr;
4958 }
4959
4960 exit:
4961 cfg->bss_pending_op = FALSE;
4962 return NULL;
4963 }
4964
wl_cfg80211_del_iface(struct wiphy * wiphy,struct wireless_dev * wdev)4965 s32 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
4966 {
4967 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4968 struct net_device *ndev = NULL;
4969 s32 ret = BCME_OK;
4970 s32 bsscfg_idx = 1;
4971 long timeout;
4972 u16 wl_iftype;
4973 u16 wl_mode;
4974
4975 WL_DBG(("Enter\n"));
4976
4977 /* If any scan is going on, abort it */
4978 if (wl_get_drv_status_all(cfg, SCANNING)) {
4979 WL_DBG(("Scan in progress. Aborting the scan!\n"));
4980 wl_cfg80211_cancel_scan(cfg);
4981 }
4982
4983 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, wdev);
4984 if (bsscfg_idx <= 0) {
4985 /* validate bsscfgidx */
4986 WL_ERR(("Wrong bssidx! \n"));
4987 return -EINVAL;
4988 }
4989
4990 /* Handle p2p iface */
4991 if ((ret = wl_cfg80211_p2p_if_del(wiphy, wdev)) != BCME_NOTFOUND) {
4992 WL_DBG(("P2P iface del handled \n"));
4993 #ifdef SUPPORT_SET_CAC
4994 wl_cfg80211_set_cac(cfg, 1);
4995 #endif /* SUPPORT_SET_CAC */
4996 return ret;
4997 }
4998
4999 ndev = wdev->netdev;
5000 if (unlikely(!ndev)) {
5001 WL_ERR(("ndev null! \n"));
5002 return -EINVAL;
5003 }
5004
5005 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
5006
5007 if (cfg80211_to_wl_iftype(ndev->ieee80211_ptr->iftype, &wl_iftype,
5008 &wl_mode) < 0) {
5009 return -EINVAL;
5010 }
5011
5012 WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d", bsscfg_idx,
5013 ndev->ieee80211_ptr->iftype, wl_iftype));
5014 /* Delete the firmware interface. "interface_remove" command
5015 * should go on the interface to be deleted
5016 */
5017 if (wl_cfg80211_get_bus_state(cfg)) {
5018 WL_ERR(("Bus state is down: %d\n", __LINE__));
5019 ret = BCME_DONGLE_DOWN;
5020 goto exit;
5021 }
5022
5023 cfg->bss_pending_op = true;
5024 ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx, wl_iftype, 1, NULL);
5025 if (ret == BCME_UNSUPPORTED) {
5026 if ((ret = wl_cfg80211_add_del_bss(cfg, ndev, bsscfg_idx, wl_iftype,
5027 true, NULL)) < 0) {
5028 WL_ERR(("DEL bss failed ret:%d \n", ret));
5029 goto exit;
5030 }
5031 } else if ((ret == BCME_NOTAP) || (ret == BCME_NOTSTA)) {
5032 /* De-init sequence involving role downgrade not happened.
5033 * Do nothing and return error. The del command should be
5034 * retried.
5035 */
5036 WL_ERR(("ifdel role mismatch:%d\n", ret));
5037 ret = -EBADTYPE;
5038 goto exit;
5039 } else if (ret < 0) {
5040 WL_ERR(("Interface DEL failed ret:%d \n", ret));
5041 goto exit;
5042 }
5043
5044 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
5045 !cfg->bss_pending_op,
5046 msecs_to_jiffies(MAX_WAIT_TIME));
5047 if (timeout <= 0 || cfg->bss_pending_op) {
5048 WL_ERR(("timeout in waiting IF_DEL event\n"));
5049 /* The interface unregister will happen from wifi reset context */
5050 ret = -ETIMEDOUT;
5051 /* fall through */
5052 }
5053
5054 exit:
5055 if (ret < 0) {
5056 WL_ERR(("iface del failed:%d\n", ret));
5057 #ifdef WL_STATIC_IF
5058 if (wl_cfg80211_static_if(cfg, ndev)) {
5059 /*
5060 * For static interface, clean up the host data,
5061 * irrespective of fw status. For dynamic
5062 * interfaces it gets cleaned from dhd_stop context
5063 */
5064 wl_cfg80211_post_static_ifdel(cfg, ndev);
5065 }
5066 #endif /* WL_STATIC_IF */
5067 } else {
5068 ret = wl_cfg80211_post_ifdel(ndev, false, cfg->if_event_info.ifidx);
5069 if (unlikely(ret)) {
5070 WL_ERR(("post_ifdel failed\n"));
5071 }
5072 }
5073
5074 cfg->bss_pending_op = false;
5075 return ret;
5076 }
5077
wl_cfg80211_join_ibss(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ibss_params * params)5078 static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
5079 struct cfg80211_ibss_params *params)
5080 {
5081 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5082 struct cfg80211_bss *bss;
5083 struct ieee80211_channel *chan;
5084 struct wl_join_params join_params;
5085 int scan_suppress;
5086 struct cfg80211_ssid ssid;
5087 s32 scan_retry = 0;
5088 s32 err = 0;
5089 size_t join_params_size;
5090 chanspec_t chanspec = 0;
5091 u32 param[0x2] = {0, 0};
5092 u32 bw_cap = 0;
5093
5094 WL_TRACE(("In\n"));
5095 RETURN_EIO_IF_NOT_UP(cfg);
5096 WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
5097 if (!params->ssid || params->ssid_len <= 0 ||
5098 params->ssid_len > DOT11_MAX_SSID_LEN) {
5099 WL_ERR(("Invalid parameter\n"));
5100 return -EINVAL;
5101 }
5102 #if defined(WL_CFG80211_P2P_DEV_IF)
5103 chan = params->chandef.chan;
5104 #else
5105 chan = params->channel;
5106 #endif /* WL_CFG80211_P2P_DEV_IF */
5107 if (chan) {
5108 cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
5109 }
5110 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
5111 struct wlc_ssid *lssid =
5112 (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
5113 u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
5114 u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
5115 if (!params->bssid ||
5116 ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
5117 (memcmp(params->ssid, lssid->SSID, lssid->SSID_len) == 0) &&
5118 (*channel == cfg->channel))) {
5119 WL_ERR(("Connection already existed to " MACDBG "\n",
5120 MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
5121 return -EISCONN;
5122 }
5123 WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n", lssid->SSID,
5124 MAC2STRDBG(bssid)));
5125 }
5126
5127 /* remove the VSIE */
5128 wl_cfg80211_ibss_vsie_delete(dev);
5129
5130 bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
5131 if (!bss) {
5132 if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
5133 memcpy(ssid.ssid, params->ssid, params->ssid_len);
5134 ssid.ssid_len = params->ssid_len;
5135 do {
5136 if (unlikely(__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
5137 -EBUSY)) {
5138 wl_delay(0x96);
5139 } else {
5140 break;
5141 }
5142 } while (++scan_retry < WL_SCAN_RETRY_MAX);
5143
5144 /* rtnl lock code is removed here. don't see why rtnl lock
5145 * needs to be released.
5146 */
5147
5148 /* wait 4 secons till scan done.... */
5149 schedule_timeout_interruptible(msecs_to_jiffies(0xFA0));
5150
5151 bss =
5152 cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
5153 }
5154 }
5155 if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
5156 ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
5157 !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
5158 cfg->ibss_starter = false;
5159 WL_DBG(("Found IBSS\n"));
5160 } else {
5161 cfg->ibss_starter = true;
5162 }
5163
5164 if (bss) {
5165 CFG80211_PUT_BSS(wiphy, bss);
5166 }
5167
5168 if (chan) {
5169 if (chan->band == IEEE80211_BAND_5GHZ) {
5170 param[0] = WLC_BAND_5G;
5171 } else if (chan->band == IEEE80211_BAND_2GHZ) {
5172 param[0] = WLC_BAND_2G;
5173 }
5174 err = wldev_iovar_getint(dev, "bw_cap", param);
5175 if (unlikely(err)) {
5176 WL_ERR(("Get bw_cap Failed (%d)\n", err));
5177 return err;
5178 }
5179 bw_cap = param[0];
5180 chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap);
5181 }
5182 /*
5183 * Join with specific BSSID and cached SSID
5184 * If SSID is zero join based on BSSID only
5185 */
5186 bzero(&join_params, sizeof(join_params));
5187 memcpy((void *)join_params.ssid.SSID, (const void *)params->ssid,
5188 params->ssid_len);
5189 join_params.ssid.SSID_len = htod32(params->ssid_len);
5190 if (params->bssid) {
5191 memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
5192 err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID,
5193 &join_params.params.bssid, ETHER_ADDR_LEN);
5194 if (unlikely(err)) {
5195 WL_ERR(("Error (%d)\n", err));
5196 return err;
5197 }
5198 } else {
5199 bzero(&join_params.params.bssid, ETHER_ADDR_LEN);
5200 }
5201
5202 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5203 scan_suppress = TRUE;
5204 /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
5205 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS, &scan_suppress,
5206 sizeof(int));
5207 if (unlikely(err)) {
5208 WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
5209 return err;
5210 }
5211 }
5212
5213 join_params.params.chanspec_list[0] = chanspec;
5214 join_params.params.chanspec_num = 1;
5215 wldev_iovar_setint(dev, "chanspec", chanspec);
5216 join_params_size = sizeof(join_params);
5217
5218 /* Disable Authentication, IBSS will add key if it required */
5219 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
5220 wldev_iovar_setint(dev, "wsec", 0);
5221
5222 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, join_params_size);
5223 if (unlikely(err)) {
5224 WL_ERR(("IBSS set_ssid Error (%d)\n", err));
5225 return err;
5226 }
5227
5228 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
5229 scan_suppress = FALSE;
5230 /* Reset the SCAN SUPPRESS Flag */
5231 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS, &scan_suppress,
5232 sizeof(int));
5233 if (unlikely(err)) {
5234 WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
5235 return err;
5236 }
5237 }
5238 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
5239 wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
5240 #ifdef WL_RELMCAST
5241 cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
5242 #endif /* WL_RELMCAST */
5243 return err;
5244 }
5245
wl_cfg80211_leave_ibss(struct wiphy * wiphy,struct net_device * dev)5246 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
5247 {
5248 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5249 s32 err = 0;
5250 scb_val_t scbval;
5251 u8 *curbssid;
5252
5253 RETURN_EIO_IF_NOT_UP(cfg);
5254 wl_link_down(cfg);
5255
5256 WL_INFORM_MEM(("Leave IBSS\n"));
5257 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
5258 wl_set_drv_status(cfg, DISCONNECTING, dev);
5259 scbval.val = 0;
5260 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
5261 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
5262 if (unlikely(err)) {
5263 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5264 WL_ERR(("error(%d)\n", err));
5265 return err;
5266 }
5267
5268 /* remove the VSIE */
5269 wl_cfg80211_ibss_vsie_delete(dev);
5270
5271 return err;
5272 }
5273
5274 #ifdef MFP
wl_cfg80211_get_rsn_capa(const bcm_tlv_t * wpa2ie,const u8 ** rsn_cap)5275 static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie, const u8 **rsn_cap)
5276 {
5277 u16 suite_count;
5278 const wpa_suite_mcast_t *mcast;
5279 const wpa_suite_ucast_t *ucast;
5280 int len;
5281 const wpa_suite_auth_key_mgmt_t *mgmt;
5282
5283 if (!wpa2ie) {
5284 return BCME_BADARG;
5285 }
5286
5287 len = wpa2ie->len;
5288
5289 /* check for Multicast cipher suite */
5290 if ((len -= (WPA_SUITE_LEN + WPA2_VERSION_LEN)) <= 0) {
5291 return BCME_NOTFOUND;
5292 }
5293
5294 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
5295
5296 /* Check for the unicast suite(s) */
5297 if (len < WPA_IE_SUITE_COUNT_LEN) {
5298 return BCME_NOTFOUND;
5299 }
5300
5301 ucast = (const wpa_suite_ucast_t *)&mcast[1];
5302 suite_count = ltoh16_ua(&ucast->count);
5303 if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
5304 (len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0) {
5305 return BCME_BADLEN;
5306 }
5307
5308 /* Check for AUTH key management suite(s) */
5309 if (len < WPA_IE_SUITE_COUNT_LEN) {
5310 return BCME_NOTFOUND;
5311 }
5312
5313 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
5314 suite_count = ltoh16_ua(&mgmt->count);
5315 if ((suite_count <= NL80211_MAX_NR_CIPHER_SUITES) &&
5316 (len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
5317 rsn_cap[0] = (const u8 *)&mgmt->list[suite_count];
5318 } else {
5319 return BCME_BADLEN;
5320 }
5321 return BCME_OK;
5322 }
5323 #endif /* MFP */
5324
wl_set_wpa_version(struct net_device * dev,struct cfg80211_connect_params * sme)5325 static s32 wl_set_wpa_version(struct net_device *dev,
5326 struct cfg80211_connect_params *sme)
5327 {
5328 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5329 struct wl_security *sec;
5330 s32 val = 0;
5331 s32 err = 0;
5332 s32 bssidx;
5333
5334 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5335 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5336 return BCME_ERROR;
5337 }
5338
5339 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) {
5340 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
5341 } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
5342 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
5343 } else {
5344 val = WPA_AUTH_DISABLED;
5345 }
5346
5347 if (is_wps_conn(sme)) {
5348 val = WPA_AUTH_DISABLED;
5349 }
5350
5351 #ifdef BCMWAPI_WPI
5352 if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) {
5353 WL_DBG((" * wl_set_wpa_version, set wpa_auth"
5354 " to WPA_AUTH_WAPI 0x400"));
5355 val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5356 }
5357 #endif // endif
5358 WL_INFORM_MEM(("[%s] wl wpa_auth 0x%0x\n", dev->name, val));
5359 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
5360 if (unlikely(err)) {
5361 WL_ERR(("set wpa_auth failed (%d)\n", err));
5362 return err;
5363 }
5364 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5365 sec->wpa_versions = sme->crypto.wpa_versions;
5366 return err;
5367 }
5368
5369 #ifdef BCMWAPI_WPI
wl_set_set_wapi_ie(struct net_device * dev,struct cfg80211_connect_params * sme)5370 static s32 wl_set_set_wapi_ie(struct net_device *dev,
5371 struct cfg80211_connect_params *sme)
5372 {
5373 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5374 s32 err = 0;
5375 s32 bssidx;
5376
5377 WL_DBG((" wl_set_set_wapi_ie\n"));
5378 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5379 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5380 return BCME_ERROR;
5381 }
5382
5383 err = wldev_iovar_setbuf_bsscfg(
5384 dev, "wapiie", (const void *)sme->ie, sme->ie_len, cfg->ioctl_buf,
5385 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5386 if (unlikely(err)) {
5387 WL_ERR(("set_wapi_ie Error (%d)\n", err));
5388 return err;
5389 }
5390 WL_INFORM_MEM(("wapi_ie successfully (%s)\n", dev->name));
5391 return err;
5392 }
5393 #endif /* BCMWAPI_WPI */
5394
wl_set_auth_type(struct net_device * dev,struct cfg80211_connect_params * sme)5395 static s32 wl_set_auth_type(struct net_device *dev,
5396 struct cfg80211_connect_params *sme)
5397 {
5398 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5399 struct wl_security *sec;
5400 s32 val = 0;
5401 s32 err = 0;
5402 s32 bssidx;
5403
5404 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5405 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5406 return BCME_ERROR;
5407 }
5408
5409 switch (sme->auth_type) {
5410 case NL80211_AUTHTYPE_OPEN_SYSTEM:
5411 val = WL_AUTH_OPEN_SYSTEM;
5412 WL_DBG(("open system\n"));
5413 break;
5414 case NL80211_AUTHTYPE_SHARED_KEY:
5415 val = WL_AUTH_SHARED_KEY;
5416 WL_DBG(("shared key\n"));
5417 break;
5418 case NL80211_AUTHTYPE_AUTOMATIC:
5419 val = WL_AUTH_OPEN_SHARED;
5420 WL_DBG(("automatic\n"));
5421 break;
5422 #ifdef WL_FILS
5423 case NL80211_AUTHTYPE_FILS_SK:
5424 WL_DBG(("fils shared key\n"));
5425 val = WL_AUTH_FILS_SHARED;
5426 break;
5427 case NL80211_AUTHTYPE_FILS_SK_PFS:
5428 val = WL_AUTH_FILS_SHARED_PFS;
5429 WL_DBG(("fils shared key with pfs\n"));
5430 break;
5431 case NL80211_AUTHTYPE_FILS_PK:
5432 WL_DBG(("fils public key\n"));
5433 val = WL_AUTH_FILS_PUBLIC;
5434 break;
5435 #endif /* WL_FILS */
5436 #ifdef WL_CLIENT_SAE
5437 case NL80211_AUTHTYPE_SAE:
5438 if (!wl_is_pmkid_available(dev, sme->bssid)) {
5439 val = WL_AUTH_SAE_KEY;
5440 } else {
5441 /* Fw will choose right auth type
5442 * dynamically based on PMKID availability
5443 */
5444 val = WL_AUTH_OPEN_SHARED;
5445 }
5446 WL_DBG(("sae auth type %d\n", val));
5447 break;
5448 #endif /* WL_CLIENT_SAE */
5449 default:
5450 val = 0x2;
5451 WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
5452 break;
5453 }
5454
5455 WL_INFORM_MEM(("[%s] wl auth 0x%0x \n", dev->name, val));
5456 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
5457 if (unlikely(err)) {
5458 WL_ERR(("set auth failed (%d)\n", err));
5459 return err;
5460 }
5461 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5462 sec->auth_type = sme->auth_type;
5463 return err;
5464 }
5465
wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)5466 static u32 wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)
5467 {
5468 uint i;
5469
5470 for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5471 if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5472 return rsn_cipher_algo_lookup_tbl[i].wsec_algo;
5473 }
5474 }
5475 return WSEC_NONE;
5476 }
5477
wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)5478 static u32 wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)
5479 {
5480 uint i;
5481
5482 for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5483 if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5484 return rsn_cipher_algo_lookup_tbl[i].wsec_key_algo;
5485 }
5486 }
5487 return CRYPTO_ALGO_OFF;
5488 }
5489
wl_rsn_akm_wpa_auth_lookup(uint32 akm)5490 static u32 wl_rsn_akm_wpa_auth_lookup(uint32 akm)
5491 {
5492 uint i;
5493
5494 for (i = 0; i < ARRAYSIZE(rsn_akm_wpa_auth_lookup_tbl); i++) {
5495 if (akm == rsn_akm_wpa_auth_lookup_tbl[i].akm_suite) {
5496 return rsn_akm_wpa_auth_lookup_tbl[i].wpa_auth;
5497 }
5498 }
5499 return WPA_AUTH_DISABLED;
5500 }
5501
wl_set_set_cipher(struct net_device * dev,struct cfg80211_connect_params * sme)5502 static s32 wl_set_set_cipher(struct net_device *dev,
5503 struct cfg80211_connect_params *sme)
5504 {
5505 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5506 struct wl_security *sec;
5507 s32 pval = 0;
5508 s32 gval = 0;
5509 s32 err = 0;
5510 s32 wsec_val = 0;
5511 #ifdef BCMWAPI_WPI
5512 s32 wapi_val = 0;
5513 s32 val = 0;
5514 #endif // endif
5515 s32 bssidx;
5516 #ifdef WL_GCMP
5517 uint32 algos = 0, mask = 0;
5518 #endif /* WL_GCMP */
5519
5520 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5521 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5522 return BCME_ERROR;
5523 }
5524
5525 if (sme->crypto.n_ciphers_pairwise) {
5526 pval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.ciphers_pairwise[0]);
5527 if (pval == WSEC_NONE) {
5528 WL_ERR(("invalid cipher pairwise (%d)\n",
5529 sme->crypto.ciphers_pairwise[0]));
5530 return BCME_BADARG;
5531 }
5532 switch (sme->crypto.ciphers_pairwise[0]) {
5533 #ifdef BCMWAPI_WPI
5534 case WLAN_CIPHER_SUITE_SMS4:
5535 val = pval;
5536 err = wl_set_set_wapi_ie(dev, sme);
5537 if (unlikely(err)) {
5538 WL_DBG(("Set wapi ie failed \n"));
5539 return err;
5540 } else {
5541 WL_DBG(("Set wapi ie succeded\n"));
5542 }
5543 wapi_val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5544 WL_INFORM_MEM(
5545 ("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val, dev->name));
5546 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wapi_val,
5547 bssidx);
5548 if (unlikely(err)) {
5549 WL_ERR(("set wpa_auth failed (%d)\n", err));
5550 return err;
5551 }
5552 break;
5553 #endif /* BCMWAPI_WPI */
5554 #ifdef WL_GCMP
5555 case WLAN_CIPHER_SUITE_GCMP:
5556 case WLAN_CIPHER_SUITE_GCMP_256:
5557 algos = KEY_ALGO_MASK(wl_rsn_cipher_wsec_key_algo_lookup(
5558 sme->crypto.ciphers_pairwise[0]));
5559 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
5560 break;
5561 #endif /* WL_GCMP */
5562 default: /* No post processing required */
5563 break;
5564 }
5565 }
5566 #if defined(BCMSUP_4WAY_HANDSHAKE)
5567 /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
5568 * handshake.
5569 * Note that the FW feature flag only exists on kernels that support the
5570 * FT-EAP AKM suite.
5571 */
5572 if (cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) {
5573 err = wldev_iovar_setint_bsscfg(dev, "sup_wpa", 1, bssidx);
5574 if (err) {
5575 WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err));
5576 return err;
5577 } else {
5578 WL_INFORM_MEM(("idsup enabled.\n"));
5579 }
5580 }
5581 #endif /* BCMSUP_4WAY_HANDSHAKE */
5582 if (sme->crypto.cipher_group) {
5583 gval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.cipher_group);
5584 if (gval == WSEC_NONE) {
5585 WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group));
5586 return BCME_BADARG;
5587 }
5588 switch (sme->crypto.cipher_group) {
5589 #ifdef BCMWAPI_WPI
5590 case WLAN_CIPHER_SUITE_SMS4:
5591 val = gval;
5592 break;
5593 #endif // endif
5594 #ifdef WL_GCMP
5595 case WLAN_CIPHER_SUITE_GCMP:
5596 case WLAN_CIPHER_SUITE_GCMP_256:
5597 algos = KEY_ALGO_MASK(wl_rsn_cipher_wsec_key_algo_lookup(
5598 sme->crypto.cipher_group));
5599 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
5600 break;
5601 #endif /* WL_GCMP */
5602 default: /* No post processing required */
5603 break;
5604 }
5605 }
5606
5607 WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
5608 #ifdef WL_GCMP
5609 WL_DBG(("algos:%x, mask:%x\n", algos, mask));
5610 #endif /* WL_GCMP */
5611
5612 if (is_wps_conn(sme)) {
5613 if (sme->privacy) {
5614 wsec_val = 0x4;
5615 } else {
5616 /* WPS-2.0 allows no security */
5617 wsec_val = 0;
5618 }
5619 } else {
5620 #ifdef BCMWAPI_WPI
5621 if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) {
5622 WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED\n"));
5623 wsec_val = val;
5624 } else
5625 #endif // endif
5626 {
5627 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC\n"));
5628 wsec_val = pval | gval;
5629 }
5630 }
5631
5632 WL_INFORM_MEM(("[%s] wl wsec 0x%x\n", dev->name, wsec_val));
5633 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec_val, bssidx);
5634 if (unlikely(err)) {
5635 WL_ERR(("error (%d)\n", err));
5636 return err;
5637 }
5638 #ifdef WL_GCMP
5639 wl_set_wsec_info_algos(dev, algos, mask);
5640 #endif /* WL_GCMP */
5641 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5642 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
5643 sec->cipher_group = sme->crypto.cipher_group;
5644 return err;
5645 }
5646 #ifdef WL_GCMP
wl_set_wsec_info_algos(struct net_device * dev,uint32 algos,uint32 mask)5647 static s32 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos,
5648 uint32 mask)
5649 {
5650 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5651 s32 bssidx;
5652 s32 err = 0;
5653 wl_wsec_info_t *wsec_info;
5654 bcm_xtlv_t *wsec_info_tlv;
5655 uint16 tlv_data_len;
5656 uint8 tlv_data[8];
5657 uint32 param_len;
5658 uint8 *buf;
5659
5660 WL_DBG(("enter.\n"));
5661 if (!cfg) {
5662 return BCME_ERROR;
5663 }
5664 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5665 WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
5666 return BCME_ERROR;
5667 }
5668
5669 buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5670 if (!buf) {
5671 WL_ERR(("No memory"));
5672 return BCME_NOMEM;
5673 }
5674 wsec_info = (wl_wsec_info_t *)buf;
5675 wsec_info->version = WL_WSEC_INFO_VERSION;
5676 wsec_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
5677
5678 wsec_info->num_tlvs++;
5679 tlv_data_len = sizeof(tlv_data);
5680 err = memcpy_s(tlv_data, sizeof(tlv_data), &algos, sizeof(algos));
5681 if (err) {
5682 WL_ERR(("memcpy_s algos error (%d)\n", err));
5683 goto exit;
5684 }
5685 err = memcpy_s(tlv_data + sizeof(algos), sizeof(mask), &mask, sizeof(mask));
5686 if (err) {
5687 WL_ERR(("memcpy_s mask error (%d)\n", err));
5688 goto exit;
5689 }
5690 bcm_xtlv_pack_xtlv(wsec_info_tlv, WL_WSEC_INFO_BSS_ALGOS, tlv_data_len,
5691 tlv_data, 0);
5692 param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN +
5693 tlv_data_len;
5694
5695 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
5696 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx,
5697 &cfg->ioctl_buf_sync);
5698 if (unlikely(err) && (err != BCME_UNSUPPORTED)) {
5699 WL_ERR(("wsec_info error (%d)\n", err));
5700 }
5701 exit:
5702 MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5703 return err;
5704 }
5705 #endif /* WL_GCMP */
5706 #ifdef MFP
wl_cfg80211_set_mfp(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme)5707 static s32 wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg, struct net_device *dev,
5708 struct cfg80211_connect_params *sme)
5709 {
5710 s32 mfp = WL_MFP_NONE;
5711 s32 current_mfp = WL_MFP_NONE;
5712 const bcm_tlv_t *wpa2_ie;
5713 const u8 *rsn_cap = NULL;
5714 bool fw_support = false;
5715 int err, count = 0;
5716 const u8 *eptr = NULL, *ptr = NULL;
5717 const u8 *group_mgmt_cs = NULL;
5718 const wpa_pmkid_list_t *pmkid = NULL;
5719
5720 if (!sme) {
5721 /* No connection params from userspace, Do nothing. */
5722 return 0;
5723 }
5724
5725 /* Check fw support and retreive current mfp val */
5726 err = wldev_iovar_getint(dev, "mfp", ¤t_mfp);
5727 if (!err) {
5728 fw_support = true;
5729 }
5730
5731 /* Parse the wpa2ie to decode the MFP capablity */
5732 if (((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
5733 DOT11_MNG_RSN_ID)) != NULL) &&
5734 (wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) {
5735 WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap[0], rsn_cap[1]));
5736 /* Check for MFP cap in the RSN capability field */
5737 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
5738 if (sme->mfp)
5739 #endif // endif
5740 {
5741 if (rsn_cap[0] & RSN_CAP_MFPR) {
5742 mfp = WL_MFP_REQUIRED;
5743 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
5744 mfp = WL_MFP_CAPABLE;
5745 }
5746 }
5747 /*
5748 * eptr --> end/last byte addr of wpa2_ie
5749 * ptr --> to keep track of current/required byte addr
5750 */
5751 eptr = (const u8 *)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN);
5752 /* pointing ptr to the next byte after rns_cap */
5753 ptr = (const u8 *)rsn_cap + RSN_CAP_LEN;
5754 if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) {
5755 /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
5756 pmkid = (const wpa_pmkid_list_t *)ptr;
5757 count = pmkid->count.low | (pmkid->count.high << 0x8);
5758 /* ptr now to point to last byte addr of pmkid */
5759 ptr = (const u8 *)pmkid +
5760 (count * WPA2_PMKID_LEN + WPA2_PMKID_COUNT_LEN);
5761 if ((eptr - ptr) >= WPA_SUITE_LEN) {
5762 /* group_mgmt_cs now to point to first byte addr of bip */
5763 group_mgmt_cs = ptr;
5764 }
5765 }
5766 }
5767
5768 WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n", mfp, wpa2_ie,
5769 fw_support));
5770
5771 if (fw_support == false) {
5772 if (mfp == WL_MFP_REQUIRED) {
5773 /* if mfp > 0, mfp capability set in wpa ie, but
5774 * FW indicated error for mfp. Propagate the error up.
5775 */
5776 WL_ERR(("mfp capability found in wpaie. But fw doesn't "
5777 "seem to support MFP\n"));
5778 err = -EINVAL;
5779 goto exit;
5780 } else {
5781 /* Firmware doesn't support mfp. But since connection request
5782 * is for non-mfp case, don't bother.
5783 */
5784 err = BCME_OK;
5785 goto exit;
5786 }
5787 } else if (mfp != current_mfp) {
5788 err = wldev_iovar_setint(dev, "mfp", mfp);
5789 if (unlikely(err)) {
5790 WL_ERR(("mfp (%d) set failed ret:%d \n", mfp, err));
5791 goto exit;
5792 }
5793 WL_INFORM_MEM(("[%s] wl mfp 0x%x\n", dev->name, mfp));
5794 }
5795
5796 if (group_mgmt_cs && bcmp((const uint8 *)WPA2_OUI, group_mgmt_cs,
5797 (WPA_SUITE_LEN - 1)) == 0) {
5798 WL_DBG(("BIP is found\n"));
5799 err = wldev_iovar_setbuf(dev, "bip", group_mgmt_cs, WPA_SUITE_LEN,
5800 cfg->ioctl_buf, WLC_IOCTL_SMLEN,
5801 &cfg->ioctl_buf_sync);
5802 /*
5803 * Dont return failure for unsupported cases
5804 * of bip iovar for backward compatibility
5805 */
5806 if (err != BCME_UNSUPPORTED && err < 0) {
5807 WL_ERR(("bip set error (%d)\n", err));
5808 {
5809 goto exit;
5810 }
5811 } else {
5812 WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n", dev->name,
5813 group_mgmt_cs[0], group_mgmt_cs[1],
5814 group_mgmt_cs[0x2]));
5815 }
5816 }
5817 exit:
5818 if (err) {
5819 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg), FW_LOGSET_MASK_ALL);
5820 }
5821
5822 return 0;
5823 }
5824 #endif /* MFP */
5825
5826 #ifdef WL_FILS
wl_is_fils_supported(struct net_device * ndev)5827 bool wl_is_fils_supported(struct net_device *ndev)
5828 {
5829 s32 err;
5830 u8 ioctl_buf[WLC_IOCTL_SMLEN] = {0};
5831 bcm_iov_buf_t *iov_buf = (bcm_iov_buf_t *)ioctl_buf;
5832
5833 iov_buf->version = WL_FILS_IOV_VERSION;
5834 err = wldev_iovar_getbuf(ndev, "fils", (uint8 *)iov_buf,
5835 sizeof(bcm_iov_buf_t), iov_buf, WLC_IOCTL_SMLEN,
5836 NULL);
5837 if (err == BCME_UNSUPPORTED) {
5838 WL_DBG(("FILS NOT supported\n"));
5839 return false;
5840 }
5841
5842 WL_INFORM(("FILS supported\n"));
5843 return true;
5844 }
5845
5846 #define WL_NUM_OF_TLV_IN_SET_FILS_PARAMS 4u
wl_set_fils_params(struct net_device * dev,struct cfg80211_connect_params * sme)5847 static s32 wl_set_fils_params(struct net_device *dev,
5848 struct cfg80211_connect_params *sme)
5849 {
5850 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5851 bcm_iov_buf_t *iov_buf = NULL;
5852 bcm_xtlvbuf_t tbuf;
5853 s32 err = BCME_OK;
5854 uint32 buf_size;
5855
5856 if ((sme->auth_type != NL80211_AUTHTYPE_FILS_SK) &&
5857 (sme->auth_type != NL80211_AUTHTYPE_FILS_SK_PFS) &&
5858 (sme->auth_type != NL80211_AUTHTYPE_FILS_PK)) {
5859 return BCME_OK;
5860 }
5861 if (sme->fils_erp_rrk_len > WL_MAX_FILS_KEY_LEN) {
5862 WL_ERR(("%s: FILS rRK exceed allowed size\n", __FUNCTION__));
5863 err = BCME_BADARG;
5864 goto exit;
5865 }
5866 /* Check incoming buffer length */
5867 buf_size = sme->fils_erp_username_len + sme->fils_erp_realm_len +
5868 sme->fils_erp_rrk_len + sizeof(sme->fils_erp_next_seq_num) +
5869 WL_NUM_OF_TLV_IN_SET_FILS_PARAMS *
5870 BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32) +
5871 sizeof(bcm_iov_buf_t) - 1u;
5872 if (buf_size > WLC_IOCTL_SMLEN) {
5873 WL_ERR(("%s: FILS connect params arguments exceed allowed size\n",
5874 __FUNCTION__));
5875 err = BCME_BADARG;
5876 goto exit;
5877 }
5878 iov_buf = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
5879 if (!iov_buf) {
5880 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__,
5881 WLC_IOCTL_SMLEN));
5882 err = BCME_NOMEM;
5883 goto exit;
5884 }
5885 iov_buf->version = WL_FILS_IOV_VERSION;
5886 iov_buf->id = WL_FILS_CMD_ADD_CONNECT_PARAMS;
5887 /* check if this should be len w/o headers */
5888 err = bcm_xtlv_buf_init(&tbuf, (uint8 *)&iov_buf->data[0],
5889 WLC_IOCTL_SMLEN - sizeof(bcm_iov_buf_t) +
5890 sizeof(uint16),
5891 BCM_XTLV_OPTION_ALIGN32);
5892 if (err != BCME_OK) {
5893 WL_ERR(("%s: xtlv_context initialization failed\n", __FUNCTION__));
5894 goto exit;
5895 }
5896 if (sme->fils_erp_username_len && sme->fils_erp_username != NULL) {
5897 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_USERNAME,
5898 sme->fils_erp_username,
5899 sme->fils_erp_username_len);
5900 if (err != BCME_OK) {
5901 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5902 goto exit;
5903 }
5904 }
5905 if (sme->fils_erp_realm_len && sme->fils_erp_realm != NULL) {
5906 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_REALM,
5907 sme->fils_erp_realm, sme->fils_erp_realm_len);
5908 if (err != BCME_OK) {
5909 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5910 goto exit;
5911 }
5912 }
5913 if (sme->fils_erp_rrk_len && sme->fils_erp_rrk != NULL) {
5914 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_RRK, sme->fils_erp_rrk,
5915 sme->fils_erp_rrk_len);
5916 if (err != BCME_OK) {
5917 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5918 goto exit;
5919 }
5920 }
5921 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM,
5922 (u8 *)&sme->fils_erp_next_seq_num,
5923 sizeof(sme->fils_erp_next_seq_num));
5924 if (err != BCME_OK) {
5925 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5926 goto exit;
5927 }
5928 iov_buf->len = bcm_xtlv_buf_len(&tbuf);
5929 err = wldev_iovar_setbuf(
5930 dev, "fils", iov_buf,
5931 iov_buf->len + sizeof(bcm_iov_buf_t) - sizeof(uint16), cfg->ioctl_buf,
5932 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5933 if (unlikely(err)) {
5934 WL_ERR(("set fils params ioctl error (%d)\n", err));
5935 goto exit;
5936 }
5937
5938 exit:
5939 if (err != BCME_OK) {
5940 WL_ERR(("set FILS params error %d\n", err));
5941 } else {
5942 WL_INFORM_MEM(("FILS parameters succesfully applied\n"));
5943 }
5944 if (iov_buf) {
5945 MFREE(cfg->osh, iov_buf, WLC_IOCTL_SMLEN);
5946 }
5947 return err;
5948 }
5949
5950 #if !defined(WL_FILS_ROAM_OFFLD) && defined(WL_FILS)
wl_get_bcn_timeout(struct net_device * dev,u32 * bcn_timeout)5951 static s32 wl_get_bcn_timeout(struct net_device *dev, u32 *bcn_timeout)
5952 {
5953 s32 err = 0;
5954
5955 err = wldev_iovar_getint(dev, "bcn_timeout", bcn_timeout);
5956 if (unlikely(err)) {
5957 WL_ERR(("could not get bcn_timeout (%d)\n", err));
5958 }
5959 return err;
5960 }
5961
5962 #define WL_ROAM_ENABLE 0
5963 #define WL_ROAM_DISABLE 1
5964 /* Beacon Timeout beacon loss in case FILS roaming offload is not supported by
5965 * fw */
5966 #define WL_BCN_TIMEOUT 3
5967
wl_fils_toggle_roaming(struct net_device * dev,u32 auth_type)5968 static s32 wl_fils_toggle_roaming(struct net_device *dev, u32 auth_type)
5969 {
5970 s32 err = 0;
5971 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5972
5973 if (WPA2_AUTH_IS_FILS(auth_type) && !cfg->fils_info.fils_roam_disabled) {
5974 err = wl_get_bcn_timeout(dev, &cfg->fils_info.fils_bcn_timeout_cache);
5975 if (unlikely(err)) {
5976 return err;
5977 }
5978 wl_dongle_roam(dev, WL_ROAM_DISABLE, WL_BCN_TIMEOUT);
5979 cfg->fils_info.fils_roam_disabled = true;
5980 WL_INFORM_MEM(("fw roam disabled for FILS akm\n"));
5981 } else if (cfg->fils_info.fils_roam_disabled) {
5982 /* Enable roaming back for other auth types */
5983 wl_dongle_roam(dev, WL_ROAM_ENABLE,
5984 cfg->fils_info.fils_bcn_timeout_cache);
5985 cfg->fils_info.fils_roam_disabled = false;
5986 WL_INFORM_MEM(("fw roam enabled\n"));
5987 }
5988 return err;
5989 }
5990 #endif /* !WL_FILS_ROAM_OFFLD && WL_FILS */
5991 #endif /* WL_FILS */
5992
wl_set_key_mgmt(struct net_device * dev,struct cfg80211_connect_params * sme)5993 static s32 wl_set_key_mgmt(struct net_device *dev,
5994 struct cfg80211_connect_params *sme)
5995 {
5996 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5997 struct wl_security *sec;
5998 s32 val = 0;
5999 s32 err = 0;
6000 s32 bssidx;
6001
6002 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6003 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6004 return BCME_ERROR;
6005 }
6006
6007 if (sme->crypto.n_akm_suites) {
6008 err = wldev_iovar_getint(dev, "wpa_auth", &val);
6009 if (unlikely(err)) {
6010 WL_ERR(("could not get wpa_auth (%d)\n", err));
6011 return err;
6012 }
6013 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
6014 switch (sme->crypto.akm_suites[0]) {
6015 case WLAN_AKM_SUITE_8021X:
6016 val = WPA_AUTH_UNSPECIFIED;
6017 break;
6018 case WLAN_AKM_SUITE_PSK:
6019 val = WPA_AUTH_PSK;
6020 break;
6021 default:
6022 WL_ERR(("invalid akm suite (0x%x)\n",
6023 sme->crypto.akm_suites[0]));
6024 return -EINVAL;
6025 }
6026 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
6027 switch (sme->crypto.akm_suites[0]) {
6028 #ifdef MFP
6029 case WL_AKM_SUITE_SHA256_1X:
6030 val = WPA2_AUTH_1X_SHA256;
6031 break;
6032 case WL_AKM_SUITE_SHA256_PSK:
6033 val = WPA2_AUTH_PSK_SHA256;
6034 break;
6035 #endif /* MFP */
6036 case WLAN_AKM_SUITE_8021X:
6037 case WLAN_AKM_SUITE_PSK:
6038 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
6039 case WLAN_AKM_SUITE_FT_8021X:
6040 #endif // endif
6041 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
6042 case WLAN_AKM_SUITE_FT_PSK:
6043 #endif // endif
6044 case WLAN_AKM_SUITE_FILS_SHA256:
6045 case WLAN_AKM_SUITE_FILS_SHA384:
6046 case WLAN_AKM_SUITE_8021X_SUITE_B:
6047 case WLAN_AKM_SUITE_8021X_SUITE_B_192:
6048 #ifdef WL_OWE
6049 case WLAN_AKM_SUITE_OWE:
6050 #endif /* WL_OWE */
6051 case WLAN_AKM_SUITE_FT_8021X_SHA384:
6052 val = wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[0]);
6053 break;
6054 case WLAN_AKM_SUITE_FT_FILS_SHA256:
6055 val = WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT;
6056 break;
6057 case WLAN_AKM_SUITE_FT_FILS_SHA384:
6058 val = WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT;
6059 break;
6060 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
6061 case WLAN_AKM_SUITE_SAE:
6062 val = WPA3_AUTH_SAE_PSK;
6063 break;
6064 #endif /* WL_SAE || WL_CLIENT_SAE */
6065 default:
6066 WL_ERR(("invalid akm suite (0x%x)\n",
6067 sme->crypto.akm_suites[0]));
6068 return -EINVAL;
6069 }
6070 }
6071 #ifdef BCMWAPI_WPI
6072 else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) {
6073 switch (sme->crypto.akm_suites[0]) {
6074 case WLAN_AKM_SUITE_WAPI_CERT:
6075 val = WAPI_AUTH_UNSPECIFIED;
6076 break;
6077 case WLAN_AKM_SUITE_WAPI_PSK:
6078 val = WAPI_AUTH_PSK;
6079 break;
6080 default:
6081 WL_ERR(("invalid akm suite (0x%x)\n",
6082 sme->crypto.akm_suites[0]));
6083 return -EINVAL;
6084 }
6085 }
6086 #endif // endif
6087
6088 #ifdef WL_FILS
6089 #if !defined(WL_FILS_ROAM_OFFLD)
6090 err = wl_fils_toggle_roaming(dev, val);
6091 if (unlikely(err)) {
6092 return err;
6093 }
6094 #endif /* !WL_FILS_ROAM_OFFLD */
6095 #endif /* !WL_FILS */
6096
6097 #ifdef MFP
6098 if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) {
6099 WL_ERR(("MFP set failed err:%d\n", err));
6100 return -EINVAL;
6101 }
6102 #endif /* MFP */
6103
6104 WL_INFORM_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val));
6105 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
6106 if (unlikely(err)) {
6107 WL_ERR(("could not set wpa_auth (0x%x)\n", err));
6108 return err;
6109 }
6110 }
6111 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6112 sec->wpa_auth = sme->crypto.akm_suites[0];
6113
6114 return err;
6115 }
6116
wl_set_set_sharedkey(struct net_device * dev,struct cfg80211_connect_params * sme)6117 static s32 wl_set_set_sharedkey(struct net_device *dev,
6118 struct cfg80211_connect_params *sme)
6119 {
6120 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6121 struct wl_security *sec;
6122 struct wl_wsec_key key;
6123 s32 val;
6124 s32 err = 0;
6125 s32 bssidx;
6126
6127 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6128 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6129 return BCME_ERROR;
6130 }
6131
6132 WL_DBG(("key len (%d)\n", sme->key_len));
6133 if (sme->key_len) {
6134 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6135 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", sec->wpa_versions,
6136 sec->cipher_pairwise));
6137 if (!(sec->wpa_versions &
6138 (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) &&
6139 #ifdef BCMWAPI_WPI
6140 !is_wapi(sec->cipher_pairwise) &&
6141 #endif // endif
6142 (sec->cipher_pairwise &
6143 (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104))) {
6144 bzero(&key, sizeof(key));
6145 key.len = (u32)sme->key_len;
6146 key.index = (u32)sme->key_idx;
6147 if (unlikely(key.len > sizeof(key.data))) {
6148 WL_ERR(("Too long key length (%u)\n", key.len));
6149 return -EINVAL;
6150 }
6151 memcpy(key.data, sme->key, key.len);
6152 key.flags = WL_PRIMARY_KEY;
6153 if ((sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP40) ||
6154 (sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP104)) {
6155 key.algo =
6156 wl_rsn_cipher_wsec_key_algo_lookup(sec->cipher_pairwise);
6157 } else {
6158 WL_ERR(("Invalid algorithm (%d)\n",
6159 sme->crypto.ciphers_pairwise[0]));
6160 return -EINVAL;
6161 }
6162 /* Set the new key/index */
6163 WL_DBG(("key length (%d) key index (%d) algo (%d)\n", key.len,
6164 key.index, key.algo));
6165 WL_DBG(("key \"%s\"\n", key.data));
6166 swap_key_from_BE(&key);
6167 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6168 cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
6169 bssidx, &cfg->ioctl_buf_sync);
6170 if (unlikely(err)) {
6171 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6172 return err;
6173 }
6174 WL_INFORM_MEM(("key applied to fw\n"));
6175 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
6176 WL_DBG(("set auth_type to shared key\n"));
6177 val = WL_AUTH_SHARED_KEY; /* shared key */
6178 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
6179 if (unlikely(err)) {
6180 WL_ERR(("set auth failed (%d)\n", err));
6181 return err;
6182 }
6183 }
6184 }
6185 }
6186 return err;
6187 }
6188
6189 #if defined(ESCAN_RESULT_PATCH)
6190 static u8 connect_req_bssid[0x6];
6191 static u8 broad_bssid[0x6];
6192 #endif /* ESCAN_RESULT_PATCH */
6193
6194 #if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
wl_get_chan_isvht80(struct net_device * net,dhd_pub_t * dhd)6195 static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
6196 {
6197 u32 chanspec = 0;
6198 bool isvht80 = 0;
6199
6200 if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK) {
6201 chanspec = wl_chspec_driver_to_host(chanspec);
6202 }
6203
6204 isvht80 = chanspec & WL_CHANSPEC_BW_80;
6205 WL_DBG(("wl_get_chan_isvht80: chanspec(%x:%d)\n", chanspec, isvht80));
6206
6207 return isvht80;
6208 }
6209 #endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
6210
wl_cfg80211_cleanup_mismatch_status(struct net_device * dev,struct bcm_cfg80211 * cfg,bool disassociate)6211 int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev,
6212 struct bcm_cfg80211 *cfg,
6213 bool disassociate)
6214 {
6215 scb_val_t scbval;
6216 int err = TRUE;
6217 int wait_cnt;
6218
6219 if (disassociate) {
6220 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6221 BCM_REFERENCE(dhdp);
6222 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
6223 dhd_net2idx(dhdp->info, dev),
6224 DOT11_RC_DISASSOC_LEAVING);
6225 WL_ERR(("Disassociate previous connection!\n"));
6226 wl_set_drv_status(cfg, DISCONNECTING, dev);
6227 scbval.val = DOT11_RC_DISASSOC_LEAVING;
6228 scbval.val = htod32(scbval.val);
6229
6230 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
6231 if (unlikely(err)) {
6232 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6233 WL_ERR(("error (%d)\n", err));
6234 return err;
6235 }
6236 wait_cnt = 0x1F4 / 0xA;
6237 } else {
6238 wait_cnt = 0xC8 / 0xA;
6239 WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
6240 if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6241 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6242 }
6243 }
6244
6245 while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
6246 WL_DBG(
6247 ("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt));
6248 wait_cnt--;
6249 OSL_SLEEP(0xA);
6250 }
6251
6252 if (wait_cnt == 0) {
6253 WL_ERR(("DISCONNECING clean up failed!\n"));
6254 /* Clear DISCONNECTING driver status as we have made sufficient attempts
6255 * for driver clean up.
6256 */
6257 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6258 wl_clr_drv_status(cfg, CONNECTED, dev);
6259 return BCME_NOTREADY;
6260 }
6261 return BCME_OK;
6262 }
6263
6264 #ifdef WL_FILS
wl_fils_add_hlp_container(struct bcm_cfg80211 * cfg,struct net_device * dev,const uint8 * ie_buf,uint16 ie_len)6265 static int wl_fils_add_hlp_container(struct bcm_cfg80211 *cfg,
6266 struct net_device *dev,
6267 const uint8 *ie_buf, uint16 ie_len)
6268 {
6269 const bcm_tlv_ext_t *hlp_ie;
6270
6271 if ((hlp_ie = (const bcm_tlv_ext_t *)bcm_parse_tlvs_dot11(
6272 (const uint8 *)ie_buf, ie_len, FILS_HLP_CONTAINER_EXT_ID, TRUE))) {
6273 u16 hlp_len = hlp_ie->len;
6274 u16 left_len = (ie_len - ((const uint8 *)hlp_ie - ie_buf));
6275 bcm_iov_buf_t *iov_buf = 0;
6276 uint8 *pxtlv;
6277 int err;
6278 size_t iov_buf_len;
6279 bcm_tlv_dot11_frag_tot_len(ie_buf, ie_len, FILS_HLP_CONTAINER_EXT_ID,
6280 TRUE, (uint *)&hlp_len);
6281
6282 hlp_len += BCM_TLV_EXT_HDR_SIZE;
6283
6284 if ((hlp_len > DOT11_MAX_MPDU_BODY_LEN) || (hlp_len > left_len)) {
6285 WL_ERR(("bad HLP length %d\n", hlp_len));
6286 return EFAULT;
6287 }
6288 iov_buf_len = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) - 1 + hlp_len;
6289 iov_buf = MALLOCZ(cfg->osh, iov_buf_len);
6290 if (iov_buf == NULL) {
6291 WL_ERR(("failed to allocated iov_buf\n"));
6292 return ENOMEM;
6293 }
6294
6295 prhex("HLP, HLP", (const uchar *)hlp_ie, hlp_len);
6296
6297 pxtlv = (uint8 *)&iov_buf->data[0];
6298 ((bcm_xtlv_t *)pxtlv)->id = WL_FILS_XTLV_HLP_IE;
6299 ((bcm_xtlv_t *)pxtlv)->len = hlp_len;
6300
6301 memcpy(((bcm_xtlv_t *)pxtlv)->data, hlp_ie, ((bcm_xtlv_t *)pxtlv)->len);
6302
6303 iov_buf->version = WL_FILS_IOV_VERSION;
6304 iov_buf->id = WL_FILS_CMD_ADD_HLP_IE;
6305 iov_buf->len = ((sizeof(bcm_xtlv_t) - 1) + ((bcm_xtlv_t *)pxtlv)->len);
6306
6307 err = wldev_iovar_setbuf(
6308 dev, "fils", iov_buf, sizeof(bcm_iov_buf_t) + iov_buf->len,
6309 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6310 if (unlikely(err)) {
6311 WL_ERR(("fils wldev_iovar_setbuf error (%d)\n", err));
6312 } else {
6313 WL_INFORM_MEM(("FILS HLP Packet succesfully updated\n"));
6314 }
6315 MFREE(cfg->osh, iov_buf, iov_buf_len);
6316 }
6317 return BCME_OK;
6318 }
6319 #endif /* WL_FILS */
6320
6321 #if defined(WL_FILS)
6322 #ifndef UPDATE_FILS_ERP_INFO
6323 #define UPDATE_FILS_ERP_INFO BIT(1)
6324 #define UPDATE_AUTH_TYPE BIT(2)
6325 #endif // endif
6326
6327 static int
wl_cfg80211_update_connect_params(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme,u32 changed)6328 wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
6329 struct cfg80211_connect_params *sme,
6330 u32 changed)
6331 {
6332 s32 err = BCME_OK;
6333 if (changed & UPDATE_FILS_ERP_INFO) {
6334 err = wl_set_fils_params(dev, sme);
6335 if (unlikely(err)) {
6336 WL_ERR(("Invalid FILS params\n"));
6337 goto exit;
6338 }
6339 }
6340 if (changed & UPDATE_AUTH_TYPE) {
6341 err = wl_set_auth_type(dev, sme);
6342 if (unlikely(err)) {
6343 WL_ERR(("Invalid auth type\n"));
6344 goto exit;
6345 }
6346 }
6347 if ((changed & UPDATE_FILS_ERP_INFO) && !(changed & UPDATE_AUTH_TYPE)) {
6348 WL_DBG(("Warning: FILS ERP params are set, but authentication type - "
6349 "not\n"));
6350 }
6351 exit:
6352 return err;
6353 }
6354 #endif /* WL_FILS */
6355
6356 #define MAX_SCAN_ABORT_WAIT_CNT 20
6357 #define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
6358
wl_ext_get_rssi(struct bcm_cfg80211 * cfg,u8 * bssid)6359 static s32 wl_ext_get_rssi(struct bcm_cfg80211 *cfg, u8 *bssid)
6360 {
6361 wl_scan_results_t *bss_list;
6362 wl_bss_info_t *bi = NULL;
6363 s32 i, rssi = 0;
6364
6365 mutex_lock(&cfg->scan_sync);
6366 bss_list = cfg->bss_list;
6367 bi = next_bss(bss_list, bi);
6368 for_each_bss(bss_list, bi, i)
6369 {
6370 if (!memcmp(&bi->BSSID, bssid, ETHER_ADDR_LEN)) {
6371 rssi = dtoh32(bi->RSSI);
6372 }
6373 }
6374 mutex_unlock(&cfg->scan_sync);
6375
6376 return rssi;
6377 }
6378
6379 #ifndef CONFIG_AP6XXX_WIFI6_HDF
6380 static
6381 #endif
6382 s32
wl_cfg80211_connect(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme)6383 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
6384 struct cfg80211_connect_params *sme)
6385 {
6386 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6387 struct ieee80211_channel *chan = sme->channel;
6388 wl_extjoin_params_t *ext_join_params;
6389 struct wl_join_params join_params;
6390 size_t join_params_size;
6391 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6392 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6393 s32 roam_trigger[0x2] = {0, 0};
6394 #endif /* ROAM_AP_ENV_DETECTION */
6395 s32 err = 0;
6396 const wpa_ie_fixed_t *wpa_ie;
6397 const bcm_tlv_t *wpa2_ie;
6398 const u8 *wpaie = 0;
6399 u32 wpaie_len = 0;
6400 u32 chan_cnt = 0;
6401 struct ether_addr bssid;
6402 s32 bssidx = -1;
6403 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6404 bool skip_hints = fw_ap_select;
6405 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6406 #ifdef ESCAN_CHANNEL_CACHE
6407 chanspec_t chanspec_list[MAX_ROAM_CHANNEL];
6408 #endif /* ESCAN_CHANNEL_CACHE */
6409 int wait_cnt;
6410 char sec[32];
6411 s32 rssi = 0;
6412
6413 WL_DBG(("In\n"));
6414 if (!dev) {
6415 WL_ERR(("dev is null\n"));
6416 return -EINVAL;
6417 }
6418 BCM_REFERENCE(dhdp);
6419 DHD_STATLOG_CTRL(dhdp, ST(ASSOC_START), dhd_net2idx(dhdp->info, dev), 0);
6420
6421 #ifdef ESCAN_CHANNEL_CACHE
6422 memset(chanspec_list, 0, (sizeof(chanspec_t) * MAX_ROAM_CHANNEL));
6423 #endif /* ESCAN_CHANNEL_CACHE */
6424
6425 /* Connection attempted via linux-wireless */
6426 wl_set_drv_status(cfg, CFG80211_CONNECT, dev);
6427 #ifdef DHDTCPSYNC_FLOOD_BLK
6428 dhd_reset_tcpsync_info_by_dev(dev);
6429 #endif /* DHDTCPSYNC_FLOOD_BLK */
6430
6431 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6432 #ifdef WL_SKIP_CONNECT_HINTS
6433 skip_hints = true;
6434 #elif defined(WL_FW_OCE_AP_SELECT)
6435 /* override bssid_hint for oce networks */
6436 skip_hints =
6437 (fw_ap_select && wl_cfg80211_is_oce_ap(wiphy, sme->bssid_hint));
6438 #endif // endif
6439 if (skip_hints) {
6440 /* Let fw choose the best AP */
6441 WL_INFORM(("skipping bssid & channel hint\n"));
6442 } else {
6443 if (sme->channel_hint) {
6444 chan = sme->channel_hint;
6445 WL_INFORM_MEM(
6446 ("channel_hint (%d), channel_hint center_freq (%d)\n",
6447 ieee80211_frequency_to_channel(sme->channel_hint->center_freq),
6448 sme->channel_hint->center_freq));
6449 }
6450 if (sme->bssid_hint) {
6451 sme->bssid = sme->bssid_hint;
6452 WL_INFORM_MEM(
6453 ("bssid_hint " MACDBG " \n", MAC2STRDBG(sme->bssid_hint)));
6454 }
6455 }
6456 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6457
6458 if (unlikely(!sme->ssid)) {
6459 WL_ERR(("Invalid ssid\n"));
6460 return -EOPNOTSUPP;
6461 }
6462
6463 if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) {
6464 WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n", sme->ssid,
6465 sme->ssid_len));
6466 return -EINVAL;
6467 }
6468
6469 WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
6470 if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
6471 prhex(NULL, sme->ie, sme->ie_len);
6472 }
6473
6474 RETURN_EIO_IF_NOT_UP(cfg);
6475 /*
6476 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
6477 */
6478 if (cfg->scan_request) {
6479 WL_TRACE_HW4(("Aborting the scan! \n"));
6480 wl_cfg80211_scan_abort(cfg);
6481 wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
6482 while (wl_get_drv_status(cfg, SCANNING, dev) && wait_cnt) {
6483 WL_DBG(
6484 ("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
6485 wait_cnt--;
6486 OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
6487 }
6488 if (wl_get_drv_status(cfg, SCANNING, dev)) {
6489 wl_cfg80211_cancel_scan(cfg);
6490 }
6491 }
6492 #ifdef WL_SCHED_SCAN
6493 /* Locks are taken in wl_cfg80211_sched_scan_stop()
6494 * A start scan occuring during connect is unlikely
6495 */
6496 if (cfg->sched_scan_req) {
6497 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
6498 wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg),
6499 cfg->sched_scan_req->reqid);
6500 #else
6501 wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg));
6502 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
6503 }
6504 #endif /* WL_SCHED_SCAN */
6505 #ifdef WL_CFG80211_GON_COLLISION
6506 /* init block gon req count */
6507 cfg->block_gon_req_tx_count = 0;
6508 cfg->block_gon_req_rx_count = 0;
6509 #endif /* WL_CFG80211_GON_COLLISION */
6510 #if defined(ESCAN_RESULT_PATCH)
6511 if (sme->bssid) {
6512 memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN);
6513 } else {
6514 bzero(connect_req_bssid, ETHER_ADDR_LEN);
6515 }
6516 bzero(broad_bssid, ETHER_ADDR_LEN);
6517 #endif // endif
6518 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
6519 maxrxpktglom = 0;
6520 #endif // endif
6521 if (wl_get_drv_status(cfg, CONNECTING, dev) ||
6522 wl_get_drv_status(cfg, CONNECTED, dev)) {
6523 /* set nested connect bit to identify the context */
6524 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6525 /* DHD prev status is CONNECTING/CONNECTED */
6526 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
6527 } else if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6528 /* DHD prev status is DISCONNECTING */
6529 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, false);
6530 } else if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6531 /* DHD previous status is not connected and FW connected */
6532 if (wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) == 0) {
6533 /* set nested connect bit to identify the context */
6534 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6535 err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, true);
6536 }
6537 }
6538 #ifdef WL_EXT_IAPSTA
6539 wl_ext_in4way_sync(dev, STA_WAIT_DISCONNECTED, WL_EXT_STATUS_DISCONNECTING,
6540 NULL);
6541 #endif
6542
6543 if (sme->bssid) {
6544 wl_update_prof(cfg, dev, NULL, sme->bssid, WL_PROF_LATEST_BSSID);
6545 } else {
6546 wl_update_prof(cfg, dev, NULL, ðer_bcast, WL_PROF_LATEST_BSSID);
6547 }
6548 #ifdef SUPPORT_AP_BWCTRL
6549 if (dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
6550 wl_restore_ap_bw(cfg);
6551 }
6552 #endif /* SUPPORT_AP_BWCTRL */
6553 /* 'connect' request received */
6554 wl_set_drv_status(cfg, CONNECTING, dev);
6555 /* clear nested connect bit on proceeding for connection */
6556 wl_clr_drv_status(cfg, NESTED_CONNECT, dev);
6557
6558 /* Clean BSSID */
6559 bzero(&bssid, sizeof(bssid));
6560 if (!wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6561 wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
6562 }
6563
6564 if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) {
6565 /* we only allow to connect using virtual interface in case of P2P */
6566 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6567 WL_ERR(
6568 ("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6569 err = BCME_ERROR;
6570 goto exit;
6571 }
6572 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6573 VNDR_IE_ASSOCREQ_FLAG, sme->ie,
6574 sme->ie_len);
6575 } else if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6576 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6577 WL_ERR(
6578 ("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr));
6579 err = BCME_ERROR;
6580 goto exit;
6581 }
6582
6583 /* find the RSN_IE */
6584 if ((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
6585 DOT11_MNG_RSN_ID)) != NULL) {
6586 WL_DBG((" WPA2 IE is found\n"));
6587 }
6588 /* find the WPA_IE */
6589 if ((wpa_ie = wl_cfgp2p_find_wpaie(sme->ie, sme->ie_len)) != NULL) {
6590 WL_DBG((" WPA IE is found\n"));
6591 }
6592 if (wpa_ie != NULL || wpa2_ie != NULL) {
6593 wpaie = (wpa_ie != NULL) ? (const u8 *)wpa_ie : (const u8 *)wpa2_ie;
6594 wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
6595 wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
6596 err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
6597 cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
6598 &cfg->ioctl_buf_sync);
6599 if (unlikely(err)) {
6600 WL_ERR(("wpaie set error (%d)\n", err));
6601 goto exit;
6602 }
6603 } else {
6604 err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0, cfg->ioctl_buf,
6605 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6606 if (unlikely(err)) {
6607 WL_ERR(("wpaie set error (%d)\n", err));
6608 goto exit;
6609 }
6610 }
6611 err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6612 VNDR_IE_ASSOCREQ_FLAG,
6613 (const u8 *)sme->ie, sme->ie_len);
6614 if (unlikely(err)) {
6615 goto exit;
6616 }
6617
6618 /* Find the RSNXE_IE and plumb */
6619 err =
6620 wl_cfg80211_config_rsnxe_ie(dev, (const u8 *)sme->ie, sme->ie_len);
6621 if (unlikely(err)) {
6622 goto exit;
6623 }
6624 }
6625 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6626 if (dhdp->roam_env_detection) {
6627 bool is_roamtrig_reset = TRUE;
6628 bool is_roam_env_ok =
6629 (wldev_iovar_setint(dev, "roam_env_detection",
6630 AP_ENV_DETECT_NOT_USED) == BCME_OK);
6631 #ifdef SKIP_ROAM_TRIGGER_RESET
6632 roam_trigger[1] = WLC_BAND_2G;
6633 is_roamtrig_reset =
6634 (wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
6635 sizeof(roam_trigger)) == BCME_OK) &&
6636 (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER - 0xA);
6637 #endif /* SKIP_ROAM_TRIGGER_RESET */
6638 if (is_roamtrig_reset && is_roam_env_ok) {
6639 roam_trigger[0] = WL_AUTO_ROAM_TRIGGER;
6640 roam_trigger[1] = WLC_BAND_ALL;
6641 err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
6642 sizeof(roam_trigger));
6643 if (unlikely(err)) {
6644 WL_ERR((" failed to restore roam_trigger for auto env"
6645 " detection\n"));
6646 }
6647 }
6648 }
6649 #endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
6650 if (chan) {
6651 cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
6652 chan_cnt = 1;
6653 WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel,
6654 chan->center_freq, chan_cnt));
6655 } else {
6656 WL_DBG(("No channel info from user space\n"));
6657 cfg->channel = 0;
6658 }
6659 #ifdef ESCAN_CHANNEL_CACHE
6660 /*
6661 * No channel information from user space. if ECC is enabled, the ECC
6662 * would prepare the channel list, else no channel would be provided
6663 * and firmware would need to do a full channel scan.
6664 *
6665 * Use cached channels. This might take slightly longer time compared
6666 * to using a single channel based join. But ECC would help choose
6667 * a better AP for a given ssid. For a given SSID there might multiple
6668 * APs on different channels and ECC would scan all those channels
6669 * before deciding up on the AP. This accounts for the additional delay.
6670 */
6671 if (cfg->rcc_enabled || cfg->channel == 0) {
6672 wlc_ssid_t ssid;
6673 int band;
6674
6675 err = wldev_get_band(dev, &band);
6676 if (!err) {
6677 set_roam_band(band);
6678 }
6679
6680 memcpy(ssid.SSID, sme->ssid, sme->ssid_len);
6681 ssid.SSID_len = (uint32)sme->ssid_len;
6682 chan_cnt =
6683 get_roam_channel_list(cfg->channel, chanspec_list, MAX_ROAM_CHANNEL,
6684 &ssid, ioctl_version);
6685 WL_DBG(("RCC channel count:%d \n", chan_cnt));
6686 }
6687 #endif /* ESCAN_CHANNEL_CACHE */
6688 WL_DBG(("3. set wpa version \n"));
6689
6690 err = wl_set_wpa_version(dev, sme);
6691 if (unlikely(err)) {
6692 WL_ERR(("Invalid wpa_version\n"));
6693 goto exit;
6694 }
6695 #ifdef BCMWAPI_WPI
6696 if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) {
6697 WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n"));
6698 } else {
6699 WL_DBG(("4. wl_set_auth_type\n"));
6700 #endif // endif
6701 err = wl_set_auth_type(dev, sme);
6702 if (unlikely(err)) {
6703 WL_ERR(("Invalid auth type\n"));
6704 goto exit;
6705 }
6706 #ifdef BCMWAPI_WPI
6707 }
6708 #endif // endif
6709 #ifdef WL_FILS
6710 if (sme->ie && sme->ie_len) {
6711 err = wl_fils_add_hlp_container(cfg, dev, sme->ie, sme->ie_len);
6712 if (unlikely(err)) {
6713 WL_ERR(("FILS sending HLP failed\n"));
6714 goto exit;
6715 }
6716 }
6717 #endif /* WL_FILS */
6718 err = wl_set_set_cipher(dev, sme);
6719 if (unlikely(err)) {
6720 WL_ERR(("Invalid ciper\n"));
6721 goto exit;
6722 }
6723
6724 err = wl_set_key_mgmt(dev, sme);
6725 if (unlikely(err)) {
6726 WL_ERR(("Invalid key mgmt\n"));
6727 goto exit;
6728 }
6729
6730 err = wl_set_set_sharedkey(dev, sme);
6731 if (unlikely(err)) {
6732 WL_ERR(("Invalid shared key\n"));
6733 goto exit;
6734 }
6735 #ifdef WL_FILS
6736 err = wl_set_fils_params(dev, sme);
6737 if (unlikely(err)) {
6738 WL_ERR(("Invalid FILS params\n"));
6739 goto exit;
6740 }
6741 #endif /* WL_FILS */
6742
6743 /*
6744 * Join with specific BSSID and cached SSID
6745 * If SSID is zero join based on BSSID only
6746 */
6747 join_params_size =
6748 WL_EXTJOIN_PARAMS_FIXED_SIZE + chan_cnt * sizeof(chanspec_t);
6749 ext_join_params =
6750 (wl_extjoin_params_t *)MALLOCZ(cfg->osh, join_params_size);
6751 if (ext_join_params == NULL) {
6752 err = -ENOMEM;
6753 wl_clr_drv_status(cfg, CONNECTING, dev);
6754 goto exit;
6755 }
6756 ext_join_params->ssid.SSID_len =
6757 (uint32)min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
6758 memcpy(&ext_join_params->ssid.SSID, sme->ssid,
6759 ext_join_params->ssid.SSID_len);
6760 wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
6761 ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
6762 /* increate dwell time to receive probe response or detect Beacon
6763 * from target AP at a noisy air only during connect command
6764 */
6765 ext_join_params->scan.active_time =
6766 chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
6767 ext_join_params->scan.passive_time =
6768 chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
6769 /* Set up join scan parameters */
6770 ext_join_params->scan.scan_type = -1;
6771 ext_join_params->scan.nprobes = chan_cnt
6772 ? (ext_join_params->scan.active_time /
6773 WL_SCAN_JOIN_PROBE_INTERVAL_MS)
6774 : -1;
6775 ext_join_params->scan.home_time = -1;
6776
6777 if (sme->bssid) {
6778 memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
6779 } else {
6780 memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN);
6781 }
6782 ext_join_params->assoc.chanspec_num = chan_cnt;
6783
6784 if (chan_cnt && !cfg->rcc_enabled) {
6785 if (cfg->channel) {
6786 /*
6787 * Use the channel provided by userspace
6788 */
6789 u16 channel, band, bw, ctl_sb;
6790 chanspec_t chspec;
6791 channel = cfg->channel;
6792 band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
6793 : WL_CHANSPEC_BAND_5G;
6794
6795 /* Get min_bw set for the interface */
6796 bw = WL_CHANSPEC_BW_20;
6797 if (bw == INVCHANSPEC) {
6798 WL_ERR(("Invalid chanspec \n"));
6799 MFREE(cfg->osh, ext_join_params, join_params_size);
6800 err = BCME_ERROR;
6801 goto exit;
6802 }
6803
6804 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
6805 chspec = (channel | band | bw | ctl_sb);
6806 ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
6807 ext_join_params->assoc.chanspec_list[0] |= chspec;
6808 ext_join_params->assoc.chanspec_list[0] = wl_chspec_host_to_driver(
6809 ext_join_params->assoc.chanspec_list[0]);
6810 }
6811 }
6812 #ifdef ESCAN_CHANNEL_CACHE
6813 else {
6814 memcpy(ext_join_params->assoc.chanspec_list, chanspec_list,
6815 sizeof(chanspec_t) * chan_cnt);
6816 }
6817 #endif /* ESCAN_CHANNEL_CACHE */
6818 ext_join_params->assoc.chanspec_num =
6819 htod32(ext_join_params->assoc.chanspec_num);
6820 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
6821 WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
6822 ext_join_params->ssid.SSID_len));
6823 }
6824
6825 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6826 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6827 MFREE(cfg->osh, ext_join_params, join_params_size);
6828 err = BCME_ERROR;
6829 goto exit;
6830 }
6831 #ifdef WLTDLS
6832 /* disable TDLS if number of connected interfaces is >= 1 */
6833 wl_cfg80211_tdls_config(cfg, TDLS_STATE_CONNECT, false);
6834 #endif /* WLTDLS */
6835 #ifdef WL_EXT_IAPSTA
6836 wl_ext_iapsta_update_channel(dhdp, dev, cfg->channel);
6837 #endif
6838
6839 rssi = wl_ext_get_rssi(cfg, (u8 *)(&ext_join_params->assoc.bssid));
6840 wl_ext_get_sec(dev, 0, sec, sizeof(sec), TRUE);
6841 if (cfg->rcc_enabled) {
6842 WL_MSG(dev->name,
6843 "Connecting with " MACDBG " ssid \"%s\", len (%d), "
6844 "sec=%s, rssi=%d, with rcc channels. chan_cnt:%d \n\n",
6845 MAC2STRDBG((u8 *)(&ext_join_params->assoc.bssid)),
6846 ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, sec,
6847 rssi, chan_cnt);
6848 } else {
6849 WL_MSG(dev->name,
6850 "Connecting with " MACDBG " ssid \"%s\", len (%d), "
6851 "sec=%s, channel=%d, rssi=%d\n\n",
6852 MAC2STRDBG((u8 *)(&ext_join_params->assoc.bssid)),
6853 ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, sec,
6854 cfg->channel, rssi);
6855 }
6856 SUPP_LOG(("[%s] Connecting with " MACDBG " ssid \"%s\","
6857 "channel:%d rcc:%d\n",
6858 dev->name, MAC2STRDBG((u8 *)(&ext_join_params->assoc.bssid)),
6859 ext_join_params->ssid.SSID, cfg->channel, cfg->rcc_enabled));
6860 err = wldev_iovar_setbuf_bsscfg(
6861 dev, "join", ext_join_params, join_params_size, cfg->ioctl_buf,
6862 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6863 MFREE(cfg->osh, ext_join_params, join_params_size);
6864 if (err) {
6865 wl_clr_drv_status(cfg, CONNECTING, dev);
6866 if (err == BCME_UNSUPPORTED) {
6867 WL_DBG(("join iovar is not supported\n"));
6868 goto set_ssid;
6869 } else {
6870 WL_ERR(("join iovar error (%d)\n", err));
6871 goto exit;
6872 }
6873 } else {
6874 goto exit;
6875 }
6876
6877 set_ssid:
6878 #if defined(ROAMEXP_SUPPORT)
6879 /* Clear Blacklist bssid and Whitelist ssid list before join issue
6880 * This is temporary fix since currently firmware roaming is not
6881 * disabled by android framework before SSID join from framework
6882 */
6883 /* Flush blacklist bssid content */
6884 dhd_dev_set_blacklist_bssid(dev, NULL, 0, true);
6885 /* Flush whitelist ssid content */
6886 dhd_dev_set_whitelist_ssid(dev, NULL, 0, true);
6887 #endif /* ROAMEXP_SUPPORT */
6888 bzero(&join_params, sizeof(join_params));
6889 join_params_size = sizeof(join_params.ssid);
6890
6891 join_params.ssid.SSID_len =
6892 (uint32)min(sizeof(join_params.ssid.SSID), sme->ssid_len);
6893 memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
6894 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
6895 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
6896 if (sme->bssid) {
6897 memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
6898 } else {
6899 memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN);
6900 }
6901
6902 if (wl_ch_to_chanspec(dev, cfg->channel, &join_params, &join_params_size) <
6903 0) {
6904 WL_ERR(("Invalid chanspec\n"));
6905 return -EINVAL;
6906 }
6907
6908 WL_DBG(("join_param_size %zu\n", join_params_size));
6909
6910 if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
6911 WL_MSG(dev->name, "ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
6912 join_params.ssid.SSID_len);
6913 }
6914 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, join_params_size);
6915 exit:
6916 if (err) {
6917 WL_ERR(("error (%d)\n", err));
6918 wl_clr_drv_status(cfg, CONNECTING, dev);
6919 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
6920 #ifdef WLTDLS
6921 /* If connect fails, check whether we can enable back TDLS */
6922 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
6923 #endif /* WLTDLS */
6924 }
6925 #ifdef WL_EXT_IAPSTA
6926 if (!err) {
6927 wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY | STA_NO_BTC_IN4WAY,
6928 WL_EXT_STATUS_CONNECTING, NULL);
6929 }
6930 #endif
6931 #ifdef DBG_PKT_MON
6932 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && !err) {
6933 DHD_DBG_PKT_MON_START(dhdp);
6934 }
6935 #endif /* DBG_PKT_MON */
6936 return err;
6937 }
6938
wl_cfg80211_disconnect_state_sync(struct bcm_cfg80211 * cfg,struct net_device * dev)6939 static void wl_cfg80211_disconnect_state_sync(struct bcm_cfg80211 *cfg,
6940 struct net_device *dev)
6941 {
6942 struct wireless_dev *wdev;
6943 uint8 wait_cnt;
6944
6945 if (!dev || !dev->ieee80211_ptr) {
6946 WL_ERR(("wrong ndev\n"));
6947 return;
6948 }
6949
6950 wdev = dev->ieee80211_ptr;
6951 wait_cnt = WAIT_FOR_DISCONNECT_STATE_SYNC;
6952 while ((wdev->current_bss) && wait_cnt) {
6953 WL_DBG(("Waiting for disconnect sync, wait_cnt: %d\n", wait_cnt));
6954 wait_cnt--;
6955 OSL_SLEEP(0x32);
6956 }
6957
6958 if (wait_cnt == 0) {
6959 /* state didn't get cleared within given timeout */
6960 WL_INFORM_MEM(("cfg80211 state. wdev->current_bss non null\n"));
6961 } else {
6962 WL_MEM(("cfg80211 disconnect state sync done\n"));
6963 }
6964 }
6965
wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 * cfg,struct net_device * dev)6966 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg,
6967 struct net_device *dev)
6968 {
6969 uint8 wait_cnt;
6970 u32 status = 0;
6971
6972 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
6973 while ((status = wl_get_drv_status(cfg, DISCONNECTING, dev)) && wait_cnt) {
6974 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
6975 wait_cnt--;
6976 OSL_SLEEP(0x32);
6977 }
6978
6979 WL_INFORM_MEM(("Wait for disconnection done. status:%d wait_cnt:%d\n",
6980 status, wait_cnt));
6981 if (!wait_cnt && wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6982 /* No response from firmware. Indicate connect result
6983 * to clear cfg80211 state machine
6984 */
6985 WL_INFORM_MEM(("force send connect result\n"));
6986 CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
6987 WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
6988 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6989 }
6990 return;
6991 }
6992
6993 #ifndef CONFIG_AP6XXX_WIFI6_HDF
6994 static
6995 #endif
6996 s32
wl_cfg80211_disconnect(struct wiphy * wiphy,struct net_device * dev,u16 reason_code)6997 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
6998 u16 reason_code)
6999 {
7000 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7001 scb_val_t scbval;
7002 bool act = false;
7003 s32 err = 0;
7004 u8 *curbssid = NULL;
7005 u8 null_bssid[ETHER_ADDR_LEN];
7006 s32 bssidx = 0;
7007 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7008
7009 RETURN_EIO_IF_NOT_UP(cfg);
7010 act = *(bool *)wl_read_prof(cfg, dev, WL_PROF_ACT);
7011 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
7012 WL_MSG(dev->name, "Reason %d, act %d\n", reason_code, act);
7013
7014 BCM_REFERENCE(dhdp);
7015 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_START), dhd_net2idx(dhdp->info, dev),
7016 reason_code);
7017 #ifdef DHD_4WAYM4_FAIL_DISCONNECT
7018 dhd_cleanup_m4_state_work(dhdp, dhd_net2idx(dhdp->info, dev));
7019 #endif /* DHD_4WAYM4_FAIL_DISCONNECT */
7020
7021 #ifdef ESCAN_RESULT_PATCH
7022 if (wl_get_drv_status(cfg, CONNECTING, dev)) {
7023 if (curbssid) {
7024 WL_ERR(("Disconnecting while CONNECTING status"
7025 " connecting device: " MACDBG "\n",
7026 MAC2STRDBG(curbssid)));
7027 } else {
7028 WL_ERR(("Disconnecting while CONNECTING status \n"));
7029 }
7030 act = true;
7031 }
7032 #endif /* ESCAN_RESULT_PATCH */
7033
7034 if (!curbssid) {
7035 WL_ERR(("Disconnecting while CONNECTING status %d\n",
7036 (int)sizeof(null_bssid)));
7037 bzero(null_bssid, sizeof(null_bssid));
7038 curbssid = null_bssid;
7039 }
7040
7041 if (act) {
7042 #ifdef DBG_PKT_MON
7043 /* Stop packet monitor */
7044 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
7045 DHD_DBG_PKT_MON_STOP(dhdp);
7046 }
7047 #endif /* DBG_PKT_MON */
7048 /*
7049 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
7050 */
7051 /* Let scan aborted by F/W */
7052 if (cfg->scan_request) {
7053 WL_TRACE_HW4(("Aborting the scan! \n"));
7054 wl_cfg80211_cancel_scan(cfg);
7055 }
7056 /* Set DISCONNECTING state. We are clearing this state in all exit paths
7057 */
7058 wl_set_drv_status(cfg, DISCONNECTING, dev);
7059 if (wl_get_drv_status(cfg, CONNECTING, dev) ||
7060 wl_get_drv_status(cfg, CONNECTED, dev)) {
7061 scbval.val = reason_code;
7062 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
7063 scbval.val = htod32(scbval.val);
7064 WL_INFORM_MEM(("[%s] wl disassoc\n", dev->name));
7065 err =
7066 wldev_ioctl_set(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
7067 if (unlikely(err)) {
7068 wl_clr_drv_status(cfg, DISCONNECTING, dev);
7069 WL_ERR(("error (%d)\n", err));
7070 goto exit;
7071 }
7072 #ifdef WL_EXT_IAPSTA
7073 wl_ext_in4way_sync(dev,
7074 STA_NO_SCAN_IN4WAY | STA_NO_BTC_IN4WAY |
7075 STA_WAIT_DISCONNECTED,
7076 WL_EXT_STATUS_DISCONNECTING, NULL);
7077 #endif
7078 }
7079 #ifdef WL_WPS_SYNC
7080 /* If are in WPS reauth state, then we would be
7081 * dropping the link down events. Ensure that
7082 * Event is sent up for the disconnect Req
7083 */
7084 if (wl_wps_session_update(dev, WPS_STATE_DISCONNECT, curbssid) ==
7085 BCME_OK) {
7086 WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
7087 wl_clr_drv_status(cfg, DISCONNECTING, dev);
7088 }
7089 #endif /* WPS_SYNC */
7090 wl_cfg80211_wait_for_disconnection(cfg, dev);
7091 } else {
7092 /* Not in connecting or connected state. However since disconnect came
7093 * from upper layer, indicate connect fail to clear any state mismatch
7094 */
7095 WL_INFORM_MEM(("act is false. report connect result fail.\n"));
7096 CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
7097 WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
7098 }
7099 #ifdef CUSTOM_SET_CPUCORE
7100 /* set default cpucore */
7101 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
7102 dhdp->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
7103 if (!(dhdp->chan_isvht80)) {
7104 dhd_set_cpucore(dhdp, FALSE);
7105 }
7106 }
7107 #endif /* CUSTOM_SET_CPUCORE */
7108
7109 cfg->rssi = 0; /* reset backup of rssi */
7110
7111 exit:
7112 /* Clear IEs for disaasoc */
7113 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7114 WL_ERR(("Find index failed\n"));
7115 err = -EINVAL;
7116 return err;
7117 }
7118 WL_ERR(("Clearing disconnect IEs \n"));
7119 err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
7120 VNDR_IE_DISASSOC_FLAG, NULL, 0);
7121
7122 return err;
7123 }
7124
7125 static s32
7126 #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)7127 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
7128 enum nl80211_tx_power_setting type, s32 mbm)
7129 #else
7130 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
7131 enum nl80211_tx_power_setting type, s32 dbm)
7132 #endif /* WL_CFG80211_P2P_DEV_IF */
7133 {
7134 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7135 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7136 s32 err = 0;
7137 #if defined(WL_CFG80211_P2P_DEV_IF)
7138 s32 dbm = MBM_TO_DBM(mbm);
7139 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
7140 defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
7141 dbm = MBM_TO_DBM(dbm);
7142 #endif /* WL_CFG80211_P2P_DEV_IF */
7143
7144 RETURN_EIO_IF_NOT_UP(cfg);
7145 switch (type) {
7146 case NL80211_TX_POWER_AUTOMATIC:
7147 break;
7148 case NL80211_TX_POWER_LIMITED:
7149 if (dbm < 0) {
7150 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
7151 return -EINVAL;
7152 }
7153 break;
7154 case NL80211_TX_POWER_FIXED:
7155 if (dbm < 0) {
7156 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
7157 return -EINVAL;
7158 }
7159 break;
7160 }
7161
7162 err = wl_set_tx_power(ndev, type, dbm);
7163 if (unlikely(err)) {
7164 WL_ERR(("error (%d)\n", err));
7165 return err;
7166 }
7167
7168 cfg->conf->tx_power = dbm;
7169
7170 return err;
7171 }
7172
7173 static s32
7174 #if defined(WL_CFG80211_P2P_DEV_IF)
wl_cfg80211_get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,s32 * dbm)7175 wl_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
7176 s32 *dbm)
7177 #else
7178 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
7179 #endif /* WL_CFG80211_P2P_DEV_IF */
7180 {
7181 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7182 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7183 s32 err = 0;
7184
7185 RETURN_EIO_IF_NOT_UP(cfg);
7186 err = wl_get_tx_power(ndev, dbm);
7187 if (unlikely(err)) {
7188 WL_ERR(("error (%d)\n", err));
7189 }
7190
7191 return err;
7192 }
7193
wl_cfg80211_config_default_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool unicast,bool multicast)7194 static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
7195 struct net_device *dev, u8 key_idx,
7196 bool unicast, bool multicast)
7197 {
7198 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7199 u32 index;
7200 s32 wsec;
7201 s32 err = 0;
7202 s32 bssidx;
7203
7204 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7205 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
7206 return BCME_ERROR;
7207 }
7208
7209 WL_DBG(("key index (%d)\n", key_idx));
7210 RETURN_EIO_IF_NOT_UP(cfg);
7211 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7212 if (unlikely(err)) {
7213 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7214 return err;
7215 }
7216 if (wsec == WEP_ENABLED) {
7217 /* Just select a new current key */
7218 index = (u32)key_idx;
7219 index = htod32(index);
7220 err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index, sizeof(index));
7221 if (unlikely(err)) {
7222 WL_ERR(("error (%d)\n", err));
7223 }
7224 }
7225 return err;
7226 }
7227
wl_add_keyext(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,const u8 * mac_addr,struct key_params * params)7228 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
7229 u8 key_idx, const u8 *mac_addr,
7230 struct key_params *params)
7231 {
7232 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7233 struct wl_wsec_key key;
7234 s32 err = 0;
7235 s32 bssidx;
7236 s32 mode = wl_get_mode_by_netdev(cfg, dev);
7237
7238 WL_MSG(dev->name, "key index (%d)\n", key_idx);
7239 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7240 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7241 return BCME_ERROR;
7242 }
7243 bzero(&key, sizeof(key));
7244 key.index = (u32)key_idx;
7245
7246 if (!ETHER_ISMULTI(mac_addr)) {
7247 memcpy((char *)&key.ea, (const void *)mac_addr, ETHER_ADDR_LEN);
7248 }
7249 key.len = (u32)params->key_len;
7250
7251 /* check for key index change */
7252 if (key.len == 0) {
7253 /* key delete */
7254 swap_key_from_BE(&key);
7255 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7256 cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
7257 bssidx, &cfg->ioctl_buf_sync);
7258 if (unlikely(err)) {
7259 WL_ERR(("key delete error (%d)\n", err));
7260 return err;
7261 }
7262 } else {
7263 if (key.len > sizeof(key.data)) {
7264 WL_ERR(("Invalid key length (%d)\n", key.len));
7265 return -EINVAL;
7266 }
7267 WL_DBG(("Setting the key index %d\n", key.index));
7268 memcpy(key.data, params->key, key.len);
7269
7270 if ((mode == WL_MODE_BSS) &&
7271 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
7272 u8 keybuf[8];
7273 memcpy(keybuf, &key.data[0x18], sizeof(keybuf));
7274 memcpy(&key.data[0x18], &key.data[16], sizeof(keybuf));
7275 memcpy(&key.data[16], keybuf, sizeof(keybuf));
7276 }
7277
7278 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
7279 if (params->seq && params->seq_len == 0x6) {
7280 /* rx iv */
7281 const u8 *ivptr;
7282 ivptr = (const u8 *)params->seq;
7283 key.rxiv.hi = (ivptr[5] << 0x18) | (ivptr[0x4] << 16) |
7284 (ivptr[3] << 8) | ivptr[0x2];
7285 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
7286 key.iv_initialized = true;
7287 }
7288 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7289 if (key.algo == CRYPTO_ALGO_OFF) { // not found.
7290 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7291 return -EINVAL;
7292 }
7293 swap_key_from_BE(&key);
7294 /* need to guarantee EAPOL 4/4 send out before set key */
7295 dhd_wait_pend8021x(dev);
7296 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7297 cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
7298 bssidx, &cfg->ioctl_buf_sync);
7299 if (unlikely(err)) {
7300 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7301 return err;
7302 }
7303 WL_INFORM_MEM(("[%s] wsec key set\n", dev->name));
7304 }
7305 return err;
7306 }
7307
wl_cfg80211_enable_roam_offload(struct net_device * dev,int enable)7308 int wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
7309 {
7310 int err;
7311 wl_eventmsg_buf_t ev_buf;
7312 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7313
7314 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7315 /* roam offload is only for the primary device */
7316 return -1;
7317 }
7318
7319 WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev->name, enable));
7320 err = wldev_iovar_setint(dev, "roam_offload", enable);
7321 if (err) {
7322 return err;
7323 }
7324
7325 bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
7326 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
7327 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
7328 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
7329 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
7330 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
7331 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
7332 err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
7333 if (!err) {
7334 cfg->roam_offload = enable;
7335 }
7336 return err;
7337 }
7338
wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 * cfg,const char * name)7339 struct wireless_dev *wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 *cfg,
7340 const char *name)
7341 {
7342 struct net_info *iter, *next;
7343
7344 if (name == NULL) {
7345 WL_ERR(("Iface name is not provided\n"));
7346 return NULL;
7347 }
7348
7349 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7350 for_each_ndev(cfg, iter, next)
7351 {
7352 GCC_DIAGNOSTIC_POP();
7353 if (iter->ndev) {
7354 if (strcmp(iter->ndev->name, name) == 0) {
7355 return iter->ndev->ieee80211_ptr;
7356 }
7357 }
7358 }
7359
7360 WL_DBG(("Iface %s not found\n", name));
7361 return NULL;
7362 }
7363
7364 #if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
wl_cfg80211_block_arp(struct net_device * dev,int enable)7365 void wl_cfg80211_block_arp(struct net_device *dev, int enable)
7366 {
7367 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7368 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7369
7370 WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev->name, enable));
7371 if (!dhd_pkt_filter_enable) {
7372 WL_DBG(("Packet filter isn't enabled\n"));
7373 return;
7374 }
7375
7376 /* Block/Unblock ARP frames only if STA is connected to
7377 * the upstream AP in case of STA+SoftAP Concurrenct mode
7378 */
7379 if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
7380 WL_DBG(("STA not connected to upstream AP\n"));
7381 return;
7382 }
7383
7384 if (enable) {
7385 WL_DBG(("Enable ARP Filter\n"));
7386 /* Add ARP filter */
7387 dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
7388
7389 /* Enable ARP packet filter - blacklist */
7390 dhd_master_mode = FALSE;
7391 dhd_pktfilter_offload_enable(
7392 dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM], TRUE,
7393 dhd_master_mode);
7394 } else {
7395 WL_DBG(("Disable ARP Filter\n"));
7396 /* Disable ARP packet filter */
7397 dhd_master_mode = TRUE;
7398 dhd_pktfilter_offload_enable(
7399 dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM], FALSE,
7400 dhd_master_mode);
7401
7402 /* Delete ARP filter */
7403 dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
7404 }
7405 }
7406 #endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
7407
wl_cfg80211_add_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr,struct key_params * params)7408 static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
7409 u8 key_idx, bool pairwise, const u8 *mac_addr,
7410 struct key_params *params)
7411 {
7412 struct wl_wsec_key key;
7413 s32 val = 0;
7414 s32 wsec = 0;
7415 s32 err = 0;
7416 u8 keybuf[8];
7417 s32 bssidx = 0;
7418 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7419 s32 mode = wl_get_mode_by_netdev(cfg, dev);
7420 #ifdef WL_GCMP
7421 uint32 algos = 0, mask = 0;
7422 #endif /* WL_GCMP */
7423 #if defined(WLAN_CIPHER_SUITE_PMK)
7424 int j;
7425 wsec_pmk_t pmk;
7426 char keystring[WSEC_MAX_PSK_LEN + 1];
7427 char *charptr = keystring;
7428 u16 len;
7429 struct wl_security *sec;
7430 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7431 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7432
7433 WL_INFORM_MEM(("key index (%d) (0x%x)\n", key_idx, params->cipher));
7434 RETURN_EIO_IF_NOT_UP(cfg);
7435
7436 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7437 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
7438 return BCME_ERROR;
7439 }
7440
7441 if (mac_addr && ((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
7442 (params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
7443 wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
7444 goto exit;
7445 }
7446
7447 BCM_REFERENCE(dhdp);
7448 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_KEY), dhd_net2idx(dhdp->info, dev), 0);
7449
7450 bzero(&key, sizeof(key));
7451 /* Clear any buffered wep key */
7452 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
7453
7454 key.len = (u32)params->key_len;
7455 key.index = (u32)key_idx;
7456
7457 if (unlikely(key.len > sizeof(key.data))) {
7458 WL_ERR(("Too long key length (%u)\n", key.len));
7459 return -EINVAL;
7460 }
7461 memcpy(key.data, params->key, key.len);
7462
7463 key.flags = WL_PRIMARY_KEY;
7464
7465 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7466 val = wl_rsn_cipher_wsec_algo_lookup(params->cipher);
7467 if (val == WSEC_NONE) {
7468 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7469 #if defined(WLAN_CIPHER_SUITE_PMK)
7470 /* WLAN_CIPHER_SUITE_PMK is not NL80211 standard ,but BRCM proprietary
7471 * cipher suite. so it doesn't have right algo type too. Just for now,
7472 * bypass this check for backward compatibility.
7473 * deprecate this proprietary way and replace to nl80211 set_pmk
7474 * API.
7475 */
7476 if (params->cipher != WLAN_CIPHER_SUITE_PMK)
7477 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7478 return -EINVAL;
7479 }
7480 switch (params->cipher) {
7481 case WLAN_CIPHER_SUITE_TKIP:
7482 /* wpa_supplicant switches the third and fourth quarters of the TKIP
7483 * key */
7484 if (mode == WL_MODE_BSS) {
7485 bcopy(&key.data[0x18], keybuf, sizeof(keybuf));
7486 bcopy(&key.data[16], &key.data[0x18], sizeof(keybuf));
7487 bcopy(keybuf, &key.data[16], sizeof(keybuf));
7488 }
7489 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7490 break;
7491 #if defined(WLAN_CIPHER_SUITE_PMK)
7492 case WLAN_CIPHER_SUITE_PMK:
7493 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7494
7495 WL_MEM(("set_pmk: wpa_auth:%x akm:%x\n", sec->wpa_auth,
7496 params->cipher));
7497 /* Avoid pmk set for SAE and OWE for external supplicant case. */
7498 if (IS_AKM_SAE(sec->wpa_auth) || IS_AKM_OWE(sec->wpa_auth)) {
7499 WL_INFORM_MEM(("skip pmk set for akm:%x\n", sec->wpa_auth));
7500 break;
7501 }
7502
7503 if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
7504 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
7505 err = wldev_iovar_setbuf(
7506 dev, "okc_info_pmk", (const void *)params->key,
7507 WSEC_MAX_PSK_LEN / 0x2, keystring, sizeof(keystring), NULL);
7508 if (err) {
7509 /* could fail in case that 'okc' is not supported */
7510 WL_INFORM_MEM(
7511 ("okc_info_pmk failed, err=%d (ignore)\n", err));
7512 }
7513 }
7514 /* copy the raw hex key to the appropriate format */
7515 for (j = 0; j < (WSEC_MAX_PSK_LEN / 0x2); j++) {
7516 charptr += snprintf(charptr, sizeof(keystring), "%02x",
7517 params->key[j]);
7518 }
7519 len = (u16)strlen(keystring);
7520 pmk.key_len = htod16(len);
7521 bcopy(keystring, pmk.key, len);
7522 pmk.flags = htod16(WSEC_PASSPHRASE);
7523
7524 err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
7525 if (err) {
7526 return err;
7527 }
7528 /* Clear key length to delete key */
7529 key.len = 0;
7530 break;
7531 #endif /* WLAN_CIPHER_SUITE_PMK */
7532 #ifdef WL_GCMP
7533 case WLAN_CIPHER_SUITE_GCMP:
7534 case WLAN_CIPHER_SUITE_GCMP_256:
7535 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
7536 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
7537 algos = KEY_ALGO_MASK(key.algo);
7538 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
7539 break;
7540 #endif /* WL_GCMP */
7541 default: /* No post processing required */
7542 WL_DBG(("no post processing required (0x%x)\n", params->cipher));
7543 break;
7544 }
7545
7546 /* Set the new key/index */
7547 if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
7548 WL_ERR(("IBSS KEY setted\n"));
7549 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
7550 }
7551 swap_key_from_BE(&key);
7552 if ((params->cipher == WLAN_CIPHER_SUITE_WEP40) ||
7553 (params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
7554 /*
7555 * For AP role, since we are doing a wl down before bringing up AP,
7556 * the plumbed keys will be lost. So for AP once we bring up AP, we
7557 * need to plumb keys again. So buffer the keys for future use. This
7558 * is more like a WAR. If firmware later has the capability to do
7559 * interface upgrade without doing a "wl down" and "wl apsta 0", then
7560 * this will not be required.
7561 */
7562 WL_DBG(("Buffering WEP Keys \n"));
7563 memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key));
7564 }
7565 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7566 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx,
7567 &cfg->ioctl_buf_sync);
7568 if (unlikely(err)) {
7569 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7570 return err;
7571 }
7572
7573 exit:
7574 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7575 if (unlikely(err)) {
7576 WL_ERR(("get wsec error (%d)\n", err));
7577 return err;
7578 }
7579
7580 wsec |= val;
7581 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
7582 if (unlikely(err)) {
7583 WL_ERR(("set wsec error (%d)\n", err));
7584 return err;
7585 }
7586 #ifdef WL_GCMP
7587 wl_set_wsec_info_algos(dev, algos, mask);
7588 #endif /* WL_GCMP */
7589 #ifdef WL_EXT_IAPSTA
7590 wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY | STA_NO_BTC_IN4WAY,
7591 WL_EXT_STATUS_ADD_KEY, NULL);
7592 #endif
7593 return err;
7594 }
7595
wl_cfg80211_del_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr)7596 static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
7597 u8 key_idx, bool pairwise, const u8 *mac_addr)
7598 {
7599 struct wl_wsec_key key;
7600 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7601 s32 err = 0;
7602 s32 bssidx;
7603 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7604
7605 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7606 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7607 return BCME_ERROR;
7608 }
7609 WL_DBG(("Enter\n"));
7610
7611 #ifndef MFP
7612 if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) &&
7613 (key_idx < DOT11_MAX_DEFAULT_KEYS + 0x2)) {
7614 return -EINVAL;
7615 }
7616 #endif // endif
7617
7618 RETURN_EIO_IF_NOT_UP(cfg);
7619 BCM_REFERENCE(dhdp);
7620 DHD_STATLOG_CTRL(dhdp, ST(DELETE_KEY), dhd_net2idx(dhdp->info, dev), 0);
7621 bzero(&key, sizeof(key));
7622
7623 key.flags = WL_PRIMARY_KEY;
7624 key.algo = CRYPTO_ALGO_OFF;
7625 key.index = (u32)key_idx;
7626
7627 WL_DBG(("key index (%d)\n", key_idx));
7628 /* Set the new key/index */
7629 swap_key_from_BE(&key);
7630 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
7631 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx,
7632 &cfg->ioctl_buf_sync);
7633 if (unlikely(err)) {
7634 if (err == -EINVAL) {
7635 if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
7636 /* we ignore this key index in this case */
7637 WL_DBG(("invalid key index (%d)\n", key_idx));
7638 }
7639 } else {
7640 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7641 }
7642 return err;
7643 }
7644 return err;
7645 }
7646
7647 /* NOTE : this function cannot work as is and is never called */
7648 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))7649 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx,
7650 bool pairwise, const u8 *mac_addr, void *cookie,
7651 void (*callback)(void *cookie, struct key_params *params))
7652 {
7653 struct key_params params;
7654 struct wl_wsec_key key;
7655 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7656 struct wl_security *sec;
7657 s32 wsec;
7658 s32 err = 0;
7659 s32 bssidx;
7660
7661 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7662 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7663 return BCME_ERROR;
7664 }
7665 WL_DBG(("key index (%d)\n", key_idx));
7666 RETURN_EIO_IF_NOT_UP(cfg);
7667 bzero(&key, sizeof(key));
7668 key.index = key_idx;
7669 swap_key_to_BE(&key);
7670 bzero(¶ms, sizeof(params));
7671 params.key_len = (u8)min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
7672 params.key = key.data;
7673
7674 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7675 if (unlikely(err)) {
7676 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7677 return err;
7678 }
7679 switch (WSEC_ENABLED(wsec)) {
7680 case WEP_ENABLED:
7681 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7682 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
7683 params.cipher = WLAN_CIPHER_SUITE_WEP40;
7684 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7685 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
7686 params.cipher = WLAN_CIPHER_SUITE_WEP104;
7687 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7688 }
7689 break;
7690 case TKIP_ENABLED:
7691 params.cipher = WLAN_CIPHER_SUITE_TKIP;
7692 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7693 break;
7694 case AES_ENABLED:
7695 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7696 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7697 break;
7698 #ifdef BCMWAPI_WPI
7699 case SMS4_ENABLED:
7700 params.cipher = WLAN_CIPHER_SUITE_SMS4;
7701 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7702 break;
7703 #endif // endif
7704 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
7705 /* to connect to mixed mode AP */
7706 case (AES_ENABLED | TKIP_ENABLED): /* TKIP CCMP */
7707 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7708 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7709 break;
7710 #endif // endif
7711 default:
7712 WL_ERR(("Invalid algo (0x%x)\n", wsec));
7713 return -EINVAL;
7714 }
7715
7716 callback(cookie, ¶ms);
7717 return err;
7718 }
7719
wl_cfg80211_config_default_mgmt_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx)7720 static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
7721 struct net_device *dev,
7722 u8 key_idx)
7723 {
7724 #ifdef MFP
7725 return 0;
7726 #else
7727 WL_INFORM_MEM(("Not supported\n"));
7728 return -EOPNOTSUPP;
7729 #endif /* MFP */
7730 }
7731
wl_check_assoc_state(struct bcm_cfg80211 * cfg,struct net_device * dev)7732 static bool wl_check_assoc_state(struct bcm_cfg80211 *cfg,
7733 struct net_device *dev)
7734 {
7735 wl_assoc_info_t asinfo;
7736 uint32 state = 0;
7737 int err;
7738
7739 err = wldev_iovar_getbuf_bsscfg(dev, "assoc_info", NULL, 0, cfg->ioctl_buf,
7740 WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
7741 if (unlikely(err)) {
7742 WL_ERR(("failed to get assoc_info : err=%d\n", err));
7743 return FALSE;
7744 } else {
7745 memcpy(&asinfo, cfg->ioctl_buf, sizeof(wl_assoc_info_t));
7746 state = dtoh32(asinfo.state);
7747 WL_DBG(("assoc state=%d\n", state));
7748 }
7749
7750 return (state > 0) ? TRUE : FALSE;
7751 }
7752
wl_cfg80211_get_rssi(struct net_device * dev,struct bcm_cfg80211 * cfg,s32 * rssi)7753 static s32 wl_cfg80211_get_rssi(struct net_device *dev,
7754 struct bcm_cfg80211 *cfg, s32 *rssi)
7755 {
7756 s32 err = BCME_OK;
7757 scb_val_t scb_val;
7758 #ifdef SUPPORT_RSSI_SUM_REPORT
7759 wl_rssi_ant_mimo_t rssi_ant_mimo;
7760 #endif /* SUPPORT_RSSI_SUM_REPORT */
7761
7762 if (dev == NULL || cfg == NULL) {
7763 return BCME_ERROR;
7764 }
7765
7766 /* initialize rssi */
7767 *rssi = 0;
7768
7769 #ifdef SUPPORT_RSSI_SUM_REPORT
7770 /* Query RSSI sum across antennas */
7771 bzero(&rssi_ant_mimo, sizeof(rssi_ant_mimo));
7772 err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
7773 if (err) {
7774 WL_ERR(("Could not get rssi sum (%d)\n", err));
7775 /* set rssi to zero and do not return error,
7776 * because iovar phy_rssi_ant could return BCME_UNSUPPORTED
7777 * when bssid was null during roaming
7778 */
7779 err = BCME_OK;
7780 } else {
7781 cfg->rssi_sum_report = TRUE;
7782 if ((*rssi = rssi_ant_mimo.rssi_sum) >= 0) {
7783 *rssi = 0;
7784 }
7785 }
7786 #endif /* SUPPORT_RSSI_SUM_REPORT */
7787
7788 /* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore
7789 */
7790 if (cfg->rssi_sum_report == FALSE) {
7791 bzero(&scb_val, sizeof(scb_val));
7792 scb_val.val = 0;
7793 err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
7794 if (err) {
7795 WL_ERR(("Could not get rssi (%d)\n", err));
7796 return err;
7797 }
7798 #if defined(RSSIOFFSET)
7799 *rssi = wl_update_rssi_offset(dev, dtoh32(scb_val.val));
7800 #else
7801 *rssi = dtoh32(scb_val.val);
7802 #endif
7803 }
7804
7805 if (*rssi >= 0) {
7806 /* check assoc status including roaming */
7807 DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub));
7808 if (wl_get_drv_status(cfg, CONNECTED, dev) &&
7809 wl_check_assoc_state(cfg, dev)) {
7810 *rssi = cfg->rssi; /* use previous RSSI */
7811 WL_DBG(("use previous RSSI %d dBm\n", cfg->rssi));
7812 } else {
7813 *rssi = 0;
7814 }
7815 DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
7816 } else {
7817 /* backup the current rssi */
7818 cfg->rssi = *rssi;
7819 }
7820
7821 return err;
7822 }
7823
wl_cfg80211_ifstats_counters_cb(void * ctx,const uint8 * data,uint16 type,uint16 len)7824 static int wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data,
7825 uint16 type, uint16 len)
7826 {
7827 switch (type) {
7828 case WL_IFSTATS_XTLV_IF_INDEX:
7829 WL_DBG(("Stats received on interface index: %d\n", *data));
7830 break;
7831 case WL_IFSTATS_XTLV_GENERIC: {
7832 if (len > sizeof(wl_if_stats_t)) {
7833 WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n", type,
7834 len, (int)sizeof(wl_if_stats_t)));
7835 }
7836 memcpy(ctx, data, sizeof(wl_if_stats_t));
7837 break;
7838 }
7839 default:
7840 WL_DBG(("Unsupported counter type 0x%x\n", type));
7841 break;
7842 }
7843
7844 return BCME_OK;
7845 }
7846
7847 /* Parameters to if_counters iovar need to be converted to XTLV format
7848 * before sending to FW. The length of the top level XTLV container
7849 * containing parameters should not exceed 228 bytes
7850 */
7851 #define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228
7852
wl_cfg80211_ifstats_counters(struct net_device * dev,wl_if_stats_t * if_stats)7853 int wl_cfg80211_ifstats_counters(struct net_device *dev,
7854 wl_if_stats_t *if_stats)
7855 {
7856 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7857 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7858 uint8 *pbuf = NULL;
7859 bcm_xtlvbuf_t xtlvbuf, local_xtlvbuf;
7860 bcm_xtlv_t *xtlv;
7861 uint16 expected_resp_len;
7862 wl_stats_report_t *request = NULL, *response = NULL;
7863 int bsscfg_idx;
7864 int ret = BCME_OK;
7865
7866 pbuf = (uint8 *)MALLOCZ(dhdp->osh, WLC_IOCTL_MEDLEN);
7867 if (!pbuf) {
7868 WL_ERR(("Failed to allocate local pbuf\n"));
7869 return BCME_NOMEM;
7870 }
7871
7872 /* top level container length cannot exceed 228 bytes.
7873 * This is because the output buffer is 1535 bytes long.
7874 * Allow 1300 bytes for reporting stats coming in XTLV format
7875 */
7876 request = (wl_stats_report_t *)MALLOCZ(dhdp->osh,
7877 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7878 if (!request) {
7879 WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
7880 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX));
7881 ret = BCME_NOMEM;
7882 goto fail;
7883 }
7884
7885 request->version = WL_STATS_REPORT_REQUEST_VERSION_V2;
7886
7887 /* Top level container... we will create it ourselves */
7888 /* Leave space for report version, length, and top level XTLV
7889 * WL_IFSTATS_XTLV_IF.
7890 */
7891 ret = bcm_xtlv_buf_init(
7892 &local_xtlvbuf, (uint8 *)(request->data) + BCM_XTLV_HDR_SIZE,
7893 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7894 offsetof(wl_stats_report_t, data) - BCM_XTLV_HDR_SIZE,
7895 BCM_XTLV_OPTION_ALIGN32);
7896 if (ret) {
7897 goto fail;
7898 }
7899
7900 /* Populate requests using this the local_xtlvbuf context. The xtlvbuf
7901 * is used to fill the container containing the XTLVs populated using
7902 * local_xtlvbuf.
7903 */
7904 ret = bcm_xtlv_buf_init(&xtlvbuf, (uint8 *)(request->data),
7905 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7906 offsetof(wl_stats_report_t, data),
7907 BCM_XTLV_OPTION_ALIGN32);
7908 if (ret) {
7909 goto fail;
7910 }
7911 /* Request generic stats */
7912 ret = bcm_xtlv_put_data(&local_xtlvbuf, WL_IFSTATS_XTLV_GENERIC, NULL, 0);
7913 if (ret) {
7914 goto fail;
7915 }
7916
7917 /* Complete the outer container with type and length
7918 * only.
7919 */
7920 ret = bcm_xtlv_put_data(&xtlvbuf, WL_IFSTATS_XTLV_IF, NULL,
7921 bcm_xtlv_buf_len(&local_xtlvbuf));
7922 if (ret) {
7923 goto fail;
7924 }
7925
7926 request->length =
7927 bcm_xtlv_buf_len(&xtlvbuf) + offsetof(wl_stats_report_t, data);
7928 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
7929
7930 /* send the command over to the device and get teh output */
7931 ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request,
7932 request->length, pbuf, WLC_IOCTL_MEDLEN,
7933 bsscfg_idx, &cfg->ioctl_buf_sync);
7934 if (ret < 0) {
7935 WL_ERR(("if_counters not supported ret=%d\n", ret));
7936 goto fail;
7937 }
7938
7939 /* Reuse request to process response */
7940 response = (wl_stats_report_t *)pbuf;
7941
7942 /* version check */
7943 if (response->version != WL_STATS_REPORT_REQUEST_VERSION_V2) {
7944 ret = BCME_VERSION;
7945 goto fail;
7946 }
7947
7948 xtlv = (bcm_xtlv_t *)(response->data);
7949
7950 expected_resp_len =
7951 (BCM_XTLV_LEN(xtlv) + OFFSETOF(wl_stats_report_t, data));
7952 /* Check if the received length is as expected */
7953 if ((response->length > WLC_IOCTL_MEDLEN) ||
7954 (response->length < expected_resp_len)) {
7955 ret = BCME_ERROR;
7956 WL_ERR(("Illegal response length received. Got: %d"
7957 " Expected: %d. Expected len must be <= %u\n",
7958 response->length, expected_resp_len, WLC_IOCTL_MEDLEN));
7959 goto fail;
7960 }
7961
7962 /* check the type. The return data will be in
7963 * WL_IFSTATS_XTLV_IF container. So check if that container is
7964 * present
7965 */
7966 if (BCM_XTLV_ID(xtlv) != WL_IFSTATS_XTLV_IF) {
7967 ret = BCME_ERROR;
7968 WL_ERR(("unexpected type received: %d Expected: %d\n",
7969 BCM_XTLV_ID(xtlv), WL_IFSTATS_XTLV_IF));
7970 goto fail;
7971 }
7972
7973 /* Process XTLVs within WL_IFSTATS_XTLV_IF container */
7974 ret = bcm_unpack_xtlv_buf(
7975 if_stats, (uint8 *)response->data + BCM_XTLV_HDR_SIZE,
7976 BCM_XTLV_LEN(xtlv), /* total length of all TLVs in container */
7977 BCM_XTLV_OPTION_ALIGN32, wl_cfg80211_ifstats_counters_cb);
7978 if (ret) {
7979 WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret));
7980 }
7981
7982 fail:
7983 if (pbuf) {
7984 MFREE(dhdp->osh, pbuf, WLC_IOCTL_MEDLEN);
7985 }
7986
7987 if (request) {
7988 MFREE(dhdp->osh, request, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7989 }
7990 return ret;
7991 }
7992 #undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
7993
7994 static s32
7995 #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)7996 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7997 const u8 *mac, struct station_info *sinfo)
7998 #else
7999 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac,
8000 struct station_info *sinfo)
8001 #endif // endif
8002 {
8003 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8004 s32 rssi = 0;
8005 s32 rate = 0;
8006 s32 err = 0;
8007 u16 wl_iftype = 0;
8008 u16 wl_mode = 0;
8009 get_pktcnt_t pktcnt;
8010 wl_if_stats_t *if_stats = NULL;
8011 sta_info_v4_t *sta = NULL;
8012 u8 *curmacp = NULL;
8013 s8 eabuf[ETHER_ADDR_STR_LEN];
8014 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
8015 bool fw_assoc_state = FALSE;
8016 u32 dhd_assoc_state = 0;
8017 void *buf;
8018
8019 RETURN_EIO_IF_NOT_UP(cfg);
8020
8021 if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype, &wl_iftype,
8022 &wl_mode) < 0) {
8023 return -EINVAL;
8024 }
8025
8026 buf = MALLOC(cfg->osh, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
8027 if (buf == NULL) {
8028 WL_ERR(("wl_cfg80211_get_station: MALLOC failed\n"));
8029 goto error;
8030 }
8031
8032 switch (wl_iftype) {
8033 case WL_IF_TYPE_STA:
8034 case WL_IF_TYPE_IBSS:
8035 if (cfg->roam_offload) {
8036 struct ether_addr bssid;
8037 bzero(&bssid, sizeof(bssid));
8038 err =
8039 wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
8040 if (err) {
8041 WL_ERR(("Failed to get current BSSID\n"));
8042 } else {
8043 if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
8044 /* roaming is detected */
8045 err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
8046 if (err) {
8047 WL_ERR(("Failed to handle the delayed"
8048 " roam, err=%d",
8049 err));
8050 }
8051 mac = (u8 *)bssid.octet;
8052 }
8053 }
8054 }
8055 dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
8056 DHD_OS_WAKE_LOCK(dhd);
8057 fw_assoc_state = dhd_is_associated(dhd, 0, &err);
8058 if (dhd_assoc_state && !fw_assoc_state) {
8059 /* check roam (join) status */
8060 if (wl_check_assoc_state(cfg, dev)) {
8061 fw_assoc_state = TRUE;
8062 WL_DBG(("roam status\n"));
8063 }
8064 }
8065 DHD_OS_WAKE_UNLOCK(dhd);
8066 if (!dhd_assoc_state || !fw_assoc_state) {
8067 WL_ERR(("NOT assoc\n"));
8068 if (err == -ENODATA) {
8069 goto error;
8070 }
8071 if (!dhd_assoc_state) {
8072 WL_TRACE_HW4(("drv state is not connected \n"));
8073 }
8074 if (!fw_assoc_state) {
8075 WL_TRACE_HW4(("fw state is not associated \n"));
8076 }
8077 /* Disconnect due to fw is not associated for
8078 * FW_ASSOC_WATCHDOG_TIME ms.
8079 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
8080 * means that BSSID is null.
8081 */
8082 if (dhd_assoc_state && !fw_assoc_state && !err) {
8083 if (!fw_assoc_watchdog_started) {
8084 fw_assoc_watchdog_ms = OSL_SYSUPTIME();
8085 fw_assoc_watchdog_started = TRUE;
8086 WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
8087 } else if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
8088 FW_ASSOC_WATCHDOG_TIME) {
8089 fw_assoc_watchdog_started = FALSE;
8090 err = -ENODEV;
8091 WL_TRACE_HW4(
8092 ("fw is not associated for %d ms \n",
8093 (OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
8094 goto get_station_err;
8095 }
8096 }
8097 err = -ENODEV;
8098 goto error;
8099 }
8100 if (dhd_is_associated(dhd, 0, NULL)) {
8101 fw_assoc_watchdog_started = FALSE;
8102 }
8103 curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
8104 if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
8105 WL_ERR(("Wrong Mac address: " MACDBG " != " MACDBG "\n",
8106 MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
8107 }
8108 /* go through to get another information */
8109 case WL_IF_TYPE_P2P_GC:
8110 case WL_IF_TYPE_P2P_DISC:
8111 if ((err = wl_cfg80211_get_rssi(dev, cfg, &rssi)) != BCME_OK) {
8112 goto get_station_err;
8113 }
8114 #if defined(RSSIAVG)
8115 err = wl_update_connected_rssi_cache(
8116 dev, &cfg->g_connected_rssi_cache_ctrl, &rssi);
8117 if (err) {
8118 WL_ERR(("Could not get rssi (%d)\n", err));
8119 goto get_station_err;
8120 }
8121 wl_delete_dirty_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
8122 wl_reset_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
8123 #endif
8124 #if defined(RSSIOFFSET)
8125 rssi = wl_update_rssi_offset(dev, rssi);
8126 #endif
8127 #if !defined(RSSIAVG) && !defined(RSSIOFFSET)
8128 // terence 20150419: limit the max. rssi to -2 or the bss will be
8129 // filtered out in android OS
8130 rssi = MIN(rssi, RSSI_MAXVAL);
8131 #endif
8132 sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
8133 sinfo->signal = rssi;
8134 WL_DBG(("RSSI %d dBm\n", rssi));
8135 /* go through to get another information */
8136 case WL_IF_TYPE_P2P_GO:
8137 /* Report the current tx rate */
8138 rate = 0;
8139 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
8140 if (err) {
8141 WL_ERR(("Could not get rate (%d)\n", err));
8142 } else {
8143 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
8144 int rxpktglom;
8145 #endif // endif
8146 rate = dtoh32(rate);
8147 sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
8148 sinfo->txrate.legacy = rate * 5;
8149 WL_DBG(("Rate %d Mbps\n", (rate / 0x2)));
8150 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
8151 rxpktglom = ((rate / 0x2) > 0x96) ? 20 : 0xA;
8152
8153 if (maxrxpktglom != rxpktglom) {
8154 maxrxpktglom = rxpktglom;
8155 WL_DBG(("Rate %d Mbps, update bus:"
8156 "maxtxpktglom=%d\n",
8157 (rate / 0x2), maxrxpktglom));
8158 err = wldev_iovar_setbuf(
8159 dev, "bus:maxtxpktglom", (char *)&maxrxpktglom, 4,
8160 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8161 if (err < 0) {
8162 WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
8163 }
8164 }
8165 #endif // endif
8166 }
8167 if_stats = (wl_if_stats_t *)buf;
8168 bzero(if_stats, sizeof(*if_stats));
8169 if (FW_SUPPORTED(dhd, ifst)) {
8170 err = wl_cfg80211_ifstats_counters(dev, if_stats);
8171 } else {
8172 err = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
8173 (char *)if_stats, sizeof(*if_stats),
8174 NULL);
8175 }
8176
8177 if (err) {
8178 bzero(&pktcnt, sizeof(pktcnt));
8179 err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt,
8180 sizeof(pktcnt));
8181 if (!err) {
8182 sinfo->rx_packets = pktcnt.rx_good_pkt;
8183 sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
8184 sinfo->tx_packets = pktcnt.tx_good_pkt;
8185 sinfo->tx_failed = pktcnt.tx_bad_pkt;
8186 }
8187 } else {
8188 sinfo->rx_packets = (uint32)dtoh64(if_stats->rxframe);
8189 sinfo->rx_dropped_misc = 0;
8190 sinfo->tx_packets = (uint32)dtoh64(if_stats->txfrmsnt);
8191 sinfo->tx_failed = (uint32)dtoh64(if_stats->txnobuf) +
8192 (uint32)dtoh64(if_stats->txrunt) +
8193 (uint32)dtoh64(if_stats->txfail);
8194 }
8195
8196 sinfo->filled |=
8197 (STA_INFO_BIT(INFO_RX_PACKETS) |
8198 STA_INFO_BIT(INFO_RX_DROP_MISC) |
8199 STA_INFO_BIT(INFO_TX_PACKETS) | STA_INFO_BIT(INFO_TX_FAILED));
8200 get_station_err:
8201 if (err && (err != -ENODATA)) {
8202 /* Disconnect due to zero BSSID or error to get RSSI */
8203 scb_val_t scbval;
8204 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
8205 dhd_net2idx(dhd->info, dev),
8206 DOT11_RC_DISASSOC_LEAVING);
8207 scbval.val = htod32(DOT11_RC_DISASSOC_LEAVING);
8208 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
8209 sizeof(scb_val_t));
8210 if (unlikely(err)) {
8211 WL_ERR(("disassoc error (%d)\n", err));
8212 }
8213
8214 WL_ERR(("force cfg80211_disconnected: %d\n", err));
8215 wl_clr_drv_status(cfg, CONNECTED, dev);
8216 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_DONE),
8217 dhd_net2idx(dhd->info, dev),
8218 DOT11_RC_DISASSOC_LEAVING);
8219 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
8220 wl_link_down(cfg);
8221 }
8222 break;
8223 case WL_IF_TYPE_AP:
8224 err =
8225 wldev_iovar_getbuf(dev, "sta_info", (const void *)mac,
8226 ETHER_ADDR_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8227 if (err < 0) {
8228 WL_ERR(("GET STA INFO failed, %d\n", err));
8229 goto error;
8230 }
8231 sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
8232 sta = (sta_info_v4_t *)buf;
8233 if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
8234 WL_ERR(("GET STA INFO version mismatch, %d\n", err));
8235 return BCME_VERSION;
8236 }
8237 sta->len = dtoh16(sta->len);
8238 sta->cap = dtoh16(sta->cap);
8239 sta->flags = dtoh32(sta->flags);
8240 sta->idle = dtoh32(sta->idle);
8241 sta->in = dtoh32(sta->in);
8242 sinfo->inactive_time = sta->idle * 1000;
8243 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || \
8244 defined(WL_COMPAT_WIRELESS)
8245 if (sta->flags & WL_STA_ASSOC) {
8246 sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
8247 sinfo->connected_time = sta->in;
8248 }
8249 #endif // endif
8250 WL_INFORM_MEM(
8251 ("STA %s, flags 0x%x, idle time %ds, connected time %ds\n",
8252 bcm_ether_ntoa((const struct ether_addr *)mac, eabuf),
8253 sta->flags, sta->idle, sta->in));
8254 break;
8255 default:
8256 WL_ERR(
8257 ("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
8258 }
8259 error:
8260 if (buf) {
8261 MFREE(cfg->osh, buf, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
8262 }
8263
8264 return err;
8265 }
8266
wl_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool enabled,s32 timeout)8267 static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
8268 struct net_device *dev, bool enabled,
8269 s32 timeout)
8270 {
8271 s32 pm;
8272 s32 err = 0;
8273 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8274 struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
8275 s32 mode;
8276 #ifdef RTT_SUPPORT
8277 rtt_status_info_t *rtt_status;
8278 #endif /* RTT_SUPPORT */
8279 dhd_pub_t *dhd = cfg->pub;
8280 RETURN_EIO_IF_NOT_UP(cfg);
8281
8282 WL_DBG(("Enter\n"));
8283 mode = wl_get_mode_by_netdev(cfg, dev);
8284 if (cfg->p2p_net == dev || _net_info == NULL ||
8285 !wl_get_drv_status(cfg, CONNECTED, dev) ||
8286 ((mode != WL_MODE_BSS) && (mode != WL_MODE_IBSS))) {
8287 return err;
8288 }
8289
8290 /* Enlarge pm_enable_work */
8291 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
8292
8293 pm = enabled ? PM_FAST : PM_OFF;
8294 if (_net_info->pm_block) {
8295 WL_ERR(("%s:Do not enable the power save for pm_block %d\n", dev->name,
8296 _net_info->pm_block));
8297 pm = PM_OFF;
8298 }
8299 if (enabled && dhd_conf_get_pm(dhd) >= 0) {
8300 pm = dhd_conf_get_pm(dhd);
8301 }
8302 pm = htod32(pm);
8303 WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
8304 #ifdef RTT_SUPPORT
8305 rtt_status = GET_RTTSTATE(dhd);
8306 if (rtt_status->status != RTT_ENABLED) {
8307 #endif /* RTT_SUPPORT */
8308 err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
8309 if (unlikely(err)) {
8310 if (err == -ENODEV) {
8311 WL_DBG(("net_device is not ready yet\n"));
8312 } else {
8313 WL_ERR(("error (%d)\n", err));
8314 }
8315 return err;
8316 }
8317 #ifdef RTT_SUPPORT
8318 }
8319 #endif /* RTT_SUPPORT */
8320 wl_cfg80211_update_power_mode(dev);
8321 return err;
8322 }
8323
wl_cfg80211_update_power_mode(struct net_device * dev)8324 void wl_cfg80211_update_power_mode(struct net_device *dev)
8325 {
8326 int err, pm = -1;
8327
8328 err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
8329 if (err) {
8330 WL_ERR(("error (%d)\n", err));
8331 } else if (pm != -1 && dev->ieee80211_ptr) {
8332 dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
8333 }
8334 }
8335
wl_find_msb(u16 bit16)8336 static __used u32 wl_find_msb(u16 bit16)
8337 {
8338 u32 ret = 0;
8339
8340 if (bit16 & 0xff00) {
8341 ret += 8;
8342 bit16 >>= 8;
8343 }
8344
8345 if (bit16 & 0xf0) {
8346 ret += 0x4;
8347 bit16 >>= 0x4;
8348 }
8349
8350 if (bit16 & 0xc) {
8351 ret += 0x2;
8352 bit16 >>= 0x2;
8353 }
8354
8355 if (bit16 & 0x2) {
8356 ret += bit16 & 0x2;
8357 } else if (bit16) {
8358 ret += bit16;
8359 }
8360
8361 return ret;
8362 }
8363
wl_cfg80211_resume(struct wiphy * wiphy)8364 static s32 wl_cfg80211_resume(struct wiphy *wiphy)
8365 {
8366 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8367 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8368 s32 err = BCME_OK;
8369
8370 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8371 WL_INFORM_MEM(("device is not ready\n"));
8372 return err;
8373 }
8374
8375 return err;
8376 }
8377
8378 static s32
8379 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
8380 defined(WL_COMPAT_WIRELESS)
wl_cfg80211_suspend(struct wiphy * wiphy,struct cfg80211_wowlan * wow)8381 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
8382 #else
8383 wl_cfg80211_suspend(struct wiphy *wiphy)
8384 #endif // endif
8385 {
8386 s32 err = BCME_OK;
8387 #ifdef DHD_CLEAR_ON_SUSPEND
8388 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8389 struct net_info *iter, *next;
8390 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8391 unsigned long flags;
8392
8393 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8394 WL_INFORM_MEM(
8395 ("device is not ready : status (%d)\n", (int)cfg->status));
8396 return err;
8397 }
8398 for_each_ndev(cfg, iter, next)
8399 {
8400 /* p2p discovery iface doesn't have a ndev associated with it (for
8401 * kernel > 3.8) */
8402 if (iter->ndev) {
8403 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8404 }
8405 }
8406 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
8407 if (cfg->scan_request) {
8408 wl_notify_scan_done(cfg, true);
8409 cfg->scan_request = NULL;
8410 }
8411 for_each_ndev(cfg, iter, next)
8412 {
8413 if (iter->ndev) {
8414 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
8415 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8416 }
8417 }
8418 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
8419 for_each_ndev(cfg, iter, next)
8420 {
8421 if (iter->ndev) {
8422 if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
8423 wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false);
8424 }
8425 }
8426 }
8427 #endif /* DHD_CLEAR_ON_SUSPEND */
8428
8429 return err;
8430 }
8431
wl_update_pmklist(struct net_device * dev,struct wl_pmk_list * pmk_list,s32 err)8432 static s32 wl_update_pmklist(struct net_device *dev,
8433 struct wl_pmk_list *pmk_list, s32 err)
8434 {
8435 int i, j;
8436 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8437 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
8438 int npmkids = cfg->pmk_list->pmkids.count;
8439
8440 ASSERT(cfg->pmk_list->pmkids.length >= (sizeof(u16) * 0x2));
8441 if (!pmk_list) {
8442 WL_ERR(("pmk_list is NULL\n"));
8443 return -EINVAL;
8444 }
8445 /* pmk list is supported only for STA interface i.e. primary interface
8446 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
8447 */
8448 if (primary_dev != dev) {
8449 WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
8450 " interfaces than primary interface\n"));
8451 return err;
8452 }
8453
8454 WL_DBG(("No of elements %d\n", npmkids));
8455 for (i = 0; i < npmkids; i++) {
8456 WL_DBG(("PMKID[%d]: %pM =\n", i, &pmk_list->pmkids.pmkid[i].bssid));
8457 for (j = 0; j < WPA2_PMKID_LEN; j++) {
8458 WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].pmkid[j]));
8459 }
8460 }
8461 if (cfg->wlc_ver.wlc_ver_major >= MIN_PMKID_LIST_V3_FW_MAJOR) {
8462 pmk_list->pmkids.version = PMKID_LIST_VER_3;
8463 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8464 sizeof(*pmk_list), cfg->ioctl_buf,
8465 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8466 } else if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V2_FW_MAJOR) {
8467 u32 v2_list_size =
8468 (u32)(sizeof(pmkid_list_v2_t) + npmkids * sizeof(pmkid_v2_t));
8469 pmkid_list_v2_t *pmkid_v2_list =
8470 (pmkid_list_v2_t *)MALLOCZ(cfg->osh, v2_list_size);
8471
8472 if (pmkid_v2_list == NULL) {
8473 WL_ERR(("failed to allocate pmkid list\n"));
8474 return BCME_NOMEM;
8475 }
8476
8477 pmkid_v2_list->version = PMKID_LIST_VER_2;
8478 /* Account for version, length and pmkid_v2_t fields */
8479 pmkid_v2_list->length =
8480 (npmkids * sizeof(pmkid_v2_t)) + (0x2 * sizeof(u16));
8481
8482 for (i = 0; i < npmkids; i++) {
8483 /* memcpy_s return checks not needed as buffers are of same size */
8484 (void)memcpy_s(&pmkid_v2_list->pmkid[i].BSSID, ETHER_ADDR_LEN,
8485 &pmk_list->pmkids.pmkid[i].bssid, ETHER_ADDR_LEN);
8486
8487 /* copy pmkid if available */
8488 if (pmk_list->pmkids.pmkid[i].pmkid_len) {
8489 (void)memcpy_s(pmkid_v2_list->pmkid[i].PMKID, WPA2_PMKID_LEN,
8490 pmk_list->pmkids.pmkid[i].pmkid,
8491 pmk_list->pmkids.pmkid[i].pmkid_len);
8492 }
8493
8494 if (pmk_list->pmkids.pmkid[i].pmk_len) {
8495 (void)memcpy_s(pmkid_v2_list->pmkid[i].pmk,
8496 pmk_list->pmkids.pmkid[i].pmk_len,
8497 pmk_list->pmkids.pmkid[i].pmk,
8498 pmk_list->pmkids.pmkid[i].pmk_len);
8499 pmkid_v2_list->pmkid[i].pmk_len =
8500 pmk_list->pmkids.pmkid[i].pmk_len;
8501 }
8502
8503 if (pmk_list->pmkids.pmkid[i].ssid_len) {
8504 (void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
8505 pmk_list->pmkids.pmkid[i].ssid_len,
8506 pmk_list->pmkids.pmkid[i].ssid,
8507 pmk_list->pmkids.pmkid[i].ssid_len);
8508 pmkid_v2_list->pmkid[i].ssid.ssid_len =
8509 pmk_list->pmkids.pmkid[i].ssid_len;
8510 }
8511
8512 (void)memcpy_s(
8513 pmkid_v2_list->pmkid[i].fils_cache_id, FILS_CACHE_ID_LEN,
8514 &pmk_list->pmkids.pmkid[i].fils_cache_id, FILS_CACHE_ID_LEN);
8515 pmkid_v2_list->pmkid[i].length = PMKID_ELEM_V2_LENGTH;
8516 }
8517 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v2_list,
8518 v2_list_size, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
8519 &cfg->ioctl_buf_sync);
8520 if (unlikely(err)) {
8521 WL_ERR(("pmkid_info failed (%d)\n", err));
8522 }
8523
8524 MFREE(cfg->osh, pmkid_v2_list, v2_list_size);
8525 } else {
8526 u32 v1_list_size =
8527 (u32)(sizeof(pmkid_list_v1_t) + npmkids * sizeof(pmkid_v1_t));
8528 pmkid_list_v1_t *pmkid_v1_list =
8529 (pmkid_list_v1_t *)MALLOCZ(cfg->osh, v1_list_size);
8530 if (pmkid_v1_list == NULL) {
8531 WL_ERR(("failed to allocate pmkid list\n"));
8532 return BCME_NOMEM;
8533 }
8534 for (i = 0; i < npmkids; i++) {
8535 /* memcpy_s return checks not needed as buffers are of same size */
8536 (void)memcpy_s(&pmkid_v1_list->pmkid[i].BSSID, ETHER_ADDR_LEN,
8537 &pmk_list->pmkids.pmkid[i].bssid, ETHER_ADDR_LEN);
8538 (void)memcpy_s(pmkid_v1_list->pmkid[i].PMKID, WPA2_PMKID_LEN,
8539 pmk_list->pmkids.pmkid[i].pmkid, WPA2_PMKID_LEN);
8540 pmkid_v1_list->npmkid++;
8541 }
8542 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v1_list,
8543 v1_list_size, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
8544 &cfg->ioctl_buf_sync);
8545 if (unlikely(err)) {
8546 WL_ERR(("pmkid_info failed (%d)\n", err));
8547 }
8548
8549 MFREE(cfg->osh, pmkid_v1_list, v1_list_size);
8550 }
8551 return err;
8552 }
8553
8554 /* remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa
8555 * for single entry operation.
8556 */
wl_cfg80211_set_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8557 static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
8558 struct cfg80211_pmksa *pmksa)
8559 {
8560 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8561 s32 err = 0;
8562 int i;
8563 int npmkids = cfg->pmk_list->pmkids.count;
8564 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
8565
8566 RETURN_EIO_IF_NOT_UP(cfg);
8567 BCM_REFERENCE(dhdp);
8568 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_PMKSA), dhd_net2idx(dhdp->info, dev), 0);
8569
8570 for (i = 0; i < npmkids; i++) {
8571 if (pmksa->bssid != NULL) {
8572 if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8573 ETHER_ADDR_LEN)) {
8574 break;
8575 }
8576 }
8577 #ifdef WL_FILS
8578 else if (pmksa->ssid != NULL) {
8579 if (!memcmp(pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8580 pmksa->ssid_len)) {
8581 break;
8582 }
8583 }
8584 #endif /* WL_FILS */
8585 }
8586 if (i < WL_NUM_PMKIDS_MAX) {
8587 if (pmksa->bssid != NULL) {
8588 memcpy(&cfg->pmk_list->pmkids.pmkid[i].bssid, pmksa->bssid,
8589 ETHER_ADDR_LEN);
8590 }
8591 #ifdef WL_FILS
8592 else if (pmksa->ssid != NULL) {
8593 cfg->pmk_list->pmkids.pmkid[i].ssid_len = pmksa->ssid_len;
8594 memcpy(&cfg->pmk_list->pmkids.pmkid[i].ssid, pmksa->ssid,
8595 pmksa->ssid_len);
8596 memcpy(&cfg->pmk_list->pmkids.pmkid[i].fils_cache_id,
8597 pmksa->cache_id, FILS_CACHE_ID_LEN);
8598 }
8599 #endif /* WL_FILS */
8600 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS))
8601 if (pmksa->pmk_len) {
8602 if (memcpy_s(&cfg->pmk_list->pmkids.pmkid[i].pmk, PMK_LEN_MAX,
8603 pmksa->pmk, pmksa->pmk_len)) {
8604 WL_ERR(("invalid pmk len = %zu", pmksa->pmk_len));
8605 } else {
8606 cfg->pmk_list->pmkids.pmkid[i].pmk_len = pmksa->pmk_len;
8607 }
8608 }
8609 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS) \
8610 */
8611 /* return check not required as buffer lengths are same */
8612 (void)memcpy_s(cfg->pmk_list->pmkids.pmkid[i].pmkid, WPA2_PMKID_LEN,
8613 pmksa->pmkid, WPA2_PMKID_LEN);
8614 cfg->pmk_list->pmkids.pmkid[i].pmkid_len = WPA2_PMKID_LEN;
8615
8616 /* set lifetime not to expire in firmware by default.
8617 * Currently, wpa_supplicant control PMKID lifetime on his end. e.g) set
8618 * 12 hours when it expired, wpa_supplicant should call
8619 * set_pmksa/del_pmksa to update corresponding entry.
8620 */
8621 cfg->pmk_list->pmkids.pmkid[i].time_left = KEY_PERM_PMK;
8622 if (i == npmkids) {
8623 cfg->pmk_list->pmkids.length += sizeof(pmkid_v3_t);
8624 cfg->pmk_list->pmkids.count++;
8625 }
8626 } else {
8627 err = -EINVAL;
8628 }
8629
8630 #if (WL_DBG_LEVEL > 0)
8631 if (pmksa->bssid != NULL) {
8632 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
8633 &cfg->pmk_list->pmkids.pmkid[npmkids - 1].bssid));
8634 }
8635 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8636 WL_DBG(("%02x\n", cfg->pmk_list->pmkids.pmkid[npmkids - 1].pmkid[i]));
8637 }
8638 #endif /* (WL_DBG_LEVEL > 0) */
8639
8640 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8641
8642 return err;
8643 }
8644
8645 /* sending pmkid_info IOVAR to manipulate PMKID(PMKSA) list in firmware.
8646 * input @pmksa: host given single pmksa info.
8647 * if it's NULL, assume whole list manipulated. e.g) flush all PMKIDs in
8648 * firmware. input @set: TRUE means adding PMKSA operation. FALSE means
8649 * deleting. return: log internal BCME_XXX error, and convert it to -EINVAL to
8650 * linux generic error code.
8651 */
wl_cfg80211_update_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa,bool set)8652 static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
8653 struct cfg80211_pmksa *pmksa, bool set)
8654 {
8655 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8656 s32 err = 0;
8657 pmkid_list_v3_t *pmk_list;
8658 uint32 alloc_len;
8659
8660 RETURN_EIO_IF_NOT_UP(cfg);
8661
8662 if (cfg->wlc_ver.wlc_ver_major < MIN_PMKID_LIST_V3_FW_MAJOR) {
8663 WL_ERR(
8664 ("wlc_ver_major not supported:%d\n", cfg->wlc_ver.wlc_ver_major));
8665 return BCME_VERSION;
8666 }
8667
8668 alloc_len = (uint32)OFFSETOF(pmkid_list_v3_t, pmkid) +
8669 ((pmksa) ? sizeof(pmkid_v3_t) : 0);
8670 pmk_list = (pmkid_list_v3_t *)MALLOCZ(cfg->osh, alloc_len);
8671 if (pmk_list == NULL) {
8672 return BCME_NOMEM;
8673 }
8674 pmk_list->version = PMKID_LIST_VER_3;
8675 pmk_list->length = alloc_len;
8676 pmk_list->count =
8677 (pmksa) ? 1 : 0; // 1 means single entry operation, 0 means whole list.
8678
8679 /* controll set/del action by lifetime parameter accordingly.
8680 * if set == TRUE, it's set PMKID action with lifetime permanent.
8681 * if set == FALSE, it's del PMKID action with lifetime zero.
8682 */
8683 pmk_list->pmkid->time_left = (set) ? KEY_PERM_PMK : 0;
8684
8685 if (pmksa) {
8686 if (pmksa->bssid) {
8687 err = memcpy_s(&pmk_list->pmkid->bssid,
8688 sizeof(pmk_list->pmkid->bssid), pmksa->bssid,
8689 ETHER_ADDR_LEN);
8690 if (err) {
8691 goto exit;
8692 }
8693 }
8694 if (pmksa->pmkid) {
8695 err = memcpy_s(&pmk_list->pmkid->pmkid,
8696 sizeof(pmk_list->pmkid->pmkid), pmksa->pmkid,
8697 WPA2_PMKID_LEN);
8698 if (err) {
8699 goto exit;
8700 }
8701 }
8702 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
8703 if (pmksa->pmk) {
8704 err = memcpy_s(&pmk_list->pmkid->pmk, sizeof(pmk_list->pmkid->pmk),
8705 pmksa->pmk, pmksa->pmk_len);
8706 if (err) {
8707 goto exit;
8708 }
8709 pmk_list->pmkid->pmk_len = pmksa->pmk_len;
8710 }
8711 if (pmksa->ssid) {
8712 err =
8713 memcpy_s(&pmk_list->pmkid->ssid, sizeof(pmk_list->pmkid->ssid),
8714 pmksa->ssid, pmksa->ssid_len);
8715 if (err) {
8716 goto exit;
8717 }
8718 pmk_list->pmkid->ssid_len = pmksa->ssid_len;
8719 }
8720 if (pmksa->cache_id) {
8721 pmk_list->pmkid->fils_cache_id = *(uint16 *)pmksa->cache_id;
8722 }
8723 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
8724 }
8725 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, alloc_len,
8726 cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
8727 &cfg->ioctl_buf_sync);
8728
8729 exit:
8730 if (pmk_list) {
8731 MFREE(cfg->osh, pmk_list, alloc_len);
8732 }
8733 return err;
8734 }
8735
8736 /* remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa
8737 * for single entry operation.
8738 */
wl_cfg80211_del_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8739 static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
8740 struct cfg80211_pmksa *pmksa)
8741 {
8742 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8743 s32 err = 0;
8744 int i;
8745 int npmkids = cfg->pmk_list->pmkids.count;
8746 RETURN_EIO_IF_NOT_UP(cfg);
8747
8748 if (!pmksa) {
8749 WL_ERR(("pmksa is not initialized\n"));
8750 return BCME_ERROR;
8751 }
8752 if (!npmkids) {
8753 /* nmpkids = 0, nothing to delete */
8754 WL_DBG(("npmkids=0. Skip del\n"));
8755 return BCME_OK;
8756 }
8757
8758 #if (WL_DBG_LEVEL > 0)
8759 if (pmksa->bssid) {
8760 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", pmksa->bssid));
8761 }
8762 #ifdef WL_FILS
8763 else if (pmksa->ssid) {
8764 WL_DBG(("FILS: del_pmksa for ssid: "));
8765 for (i = 0; i < pmksa->ssid_len; i++) {
8766 WL_DBG(("%c", pmksa->ssid[i]));
8767 }
8768 WL_DBG(("\n"));
8769 }
8770 #endif /* WL_FILS */
8771 if (pmksa->pmkid) {
8772 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8773 WL_DBG(("%02x\n", pmksa->pmkid[i]));
8774 }
8775 }
8776 #endif /* (WL_DBG_LEVEL > 0) */
8777
8778 for (i = 0; i < npmkids; i++) {
8779 if (pmksa->bssid) {
8780 if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8781 ETHER_ADDR_LEN)) {
8782 break;
8783 }
8784 }
8785 #ifdef WL_FILS
8786 else if (pmksa->ssid) {
8787 if (!memcmp(pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8788 pmksa->ssid_len)) {
8789 break;
8790 }
8791 }
8792 #endif /* WL_FILS */
8793 }
8794 if ((npmkids > 0) && (i < npmkids)) {
8795 bzero(&cfg->pmk_list->pmkids.pmkid[i], sizeof(pmkid_v3_t));
8796 for (; i < (npmkids - 1); i++) {
8797 (void)memcpy_s(&cfg->pmk_list->pmkids.pmkid[i], sizeof(pmkid_v3_t),
8798 &cfg->pmk_list->pmkids.pmkid[i + 1],
8799 sizeof(pmkid_v3_t));
8800 }
8801 npmkids--;
8802 cfg->pmk_list->pmkids.length -= sizeof(pmkid_v3_t);
8803 cfg->pmk_list->pmkids.count--;
8804 } else {
8805 err = -EINVAL;
8806 }
8807
8808 /* current wl_update_pmklist() doesn't delete corresponding PMKID entry.
8809 * inside firmware. So we need to issue delete action explicitely through
8810 * this function.
8811 */
8812 err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
8813 /* intentional fall through even on error.
8814 * it should work above MIN_PMKID_LIST_V3_FW_MAJOR, otherwise let ignore it.
8815 */
8816
8817 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8818 return err;
8819 }
8820
8821 /* remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa
8822 * for single entry operation.
8823 */
wl_cfg80211_flush_pmksa(struct wiphy * wiphy,struct net_device * dev)8824 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
8825 {
8826 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8827 s32 err = 0;
8828 RETURN_EIO_IF_NOT_UP(cfg);
8829 bzero(cfg->pmk_list, sizeof(*cfg->pmk_list));
8830 cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
8831 cfg->pmk_list->pmkids.count = 0;
8832 cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
8833 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8834 return err;
8835 }
8836
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)8837 static s32 wl_cfg80211_remain_on_channel(struct wiphy *wiphy,
8838 bcm_struct_cfgdev *cfgdev,
8839 struct ieee80211_channel *channel,
8840 #if !defined(WL_CFG80211_P2P_DEV_IF)
8841 enum nl80211_channel_type channel_type,
8842 #endif /* WL_CFG80211_P2P_DEV_IF */
8843 unsigned int duration, u64 *cookie)
8844 {
8845 s32 target_channel;
8846 u32 id;
8847 s32 err = BCME_OK;
8848 struct ether_addr primary_mac;
8849 struct net_device *ndev = NULL;
8850 #ifdef CONFIG_AP6XXX_WIFI6_HDF
8851 NetDevice *netdev = NULL;
8852 int ret = 0;
8853 #endif
8854 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8855
8856 RETURN_EIO_IF_NOT_UP(cfg);
8857 #ifdef DHD_IFDEBUG
8858 PRINT_WDEV_INFO(cfgdev);
8859 #endif /* DHD_IFDEBUG */
8860
8861 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
8862
8863 mutex_lock(&cfg->usr_sync);
8864 WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
8865 ieee80211_frequency_to_channel(channel->center_freq), duration,
8866 (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES" : "NO"));
8867
8868 if (!cfg->p2p) {
8869 WL_ERR(("cfg->p2p is not initialized\n"));
8870 err = BCME_ERROR;
8871 goto exit;
8872 }
8873
8874 #ifdef P2P_LISTEN_OFFLOADING
8875 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8876 WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
8877 err = -EAGAIN;
8878 goto exit;
8879 }
8880 #endif /* P2P_LISTEN_OFFLOADING */
8881
8882 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8883 if (wl_get_drv_status_all(cfg, SCANNING)) {
8884 wl_cfg80211_cancel_scan(cfg);
8885 }
8886 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8887
8888 target_channel = ieee80211_frequency_to_channel(channel->center_freq);
8889 memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel));
8890 #if defined(WL_ENABLE_P2P_IF)
8891 cfg->remain_on_chan_type = channel_type;
8892 #endif /* WL_ENABLE_P2P_IF */
8893 id = ++cfg->last_roc_id;
8894 if (id == 0) {
8895 id = ++cfg->last_roc_id;
8896 }
8897 *cookie = id;
8898
8899 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8900 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
8901 timer_list_compat_t *_timer;
8902 WL_DBG(("scan is running. go to fake listen state\n"));
8903
8904 if (duration > LONG_LISTEN_TIME) {
8905 wl_cfg80211_scan_abort(cfg);
8906 } else {
8907 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8908
8909 if (timer_pending(&cfg->p2p->listen_timer)) {
8910 WL_DBG(("cancel current listen timer \n"));
8911 del_timer_sync(&cfg->p2p->listen_timer);
8912 }
8913
8914 _timer = &cfg->p2p->listen_timer;
8915 wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
8916
8917 INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0);
8918
8919 err = BCME_OK;
8920 goto exit;
8921 }
8922 }
8923 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8924
8925 #ifdef WL_BCNRECV
8926 /* check fakeapscan in progress then abort */
8927 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_LISTENBUSY);
8928 #endif /* WL_BCNRECV */
8929 #ifdef WL_CFG80211_SYNC_GON
8930 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
8931 /* do not enter listen mode again if we are in listen mode already for
8932 * next af. remain on channel completion will be returned by waiting
8933 * next af completion.
8934 */
8935 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8936 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8937 #else
8938 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8939 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8940 goto exit;
8941 }
8942 #endif /* WL_CFG80211_SYNC_GON */
8943 if (cfg->p2p && !cfg->p2p->on) {
8944 /* In case of p2p_listen command, supplicant send remain_on_channel
8945 * without turning on P2P
8946 */
8947 get_primary_mac(cfg, &primary_mac);
8948 #ifndef WL_P2P_USE_RANDMAC
8949 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
8950 #endif /* WL_P2P_USE_RANDMAC */
8951 p2p_on(cfg) = true;
8952 }
8953
8954 if (p2p_is_on(cfg)) {
8955 err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
8956 if (unlikely(err)) {
8957 goto exit;
8958 }
8959 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8960 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8961 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8962 err = wl_cfgp2p_discover_listen(cfg, target_channel, duration);
8963 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
8964 if (err == BCME_OK) {
8965 wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
8966 } else {
8967 /* if failed, firmware may be internal scanning state.
8968 * so other scan request shall not abort it
8969 */
8970 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
8971 }
8972 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
8973 if (err) {
8974 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
8975 }
8976
8977 /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant
8978 * and expire timer will send a completion to the upper layer
8979 */
8980 err = BCME_OK;
8981 }
8982
8983 exit:
8984 if (err == BCME_OK) {
8985 WL_DBG(("Success\n"));
8986 #if defined(WL_CFG80211_P2P_DEV_IF)
8987 #ifdef CONFIG_AP6XXX_WIFI6_HDF
8988 netdev = get_hdf_netdev(HDF_INF_P2P0);
8989 ret =
8990 HdfWifiEventRemainOnChannel(netdev, channel->center_freq, duration);
8991 printk(KERN_INFO
8992 "call HdfWifiEventRemainOnChannel cookie=%llu, ret=%d\n",
8993 *cookie, ret);
8994 #else
8995 cfg80211_ready_on_channel(cfgdev, *cookie, channel, duration,
8996 GFP_KERNEL);
8997 #endif
8998 #else
8999 cfg80211_ready_on_channel(cfgdev, *cookie, channel, channel_type,
9000 duration, GFP_KERNEL);
9001 #endif /* WL_CFG80211_P2P_DEV_IF */
9002 } else {
9003 WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie));
9004 }
9005 mutex_unlock(&cfg->usr_sync);
9006 return err;
9007 }
9008
wl_cfg80211_cancel_remain_on_channel(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u64 cookie)9009 static s32 wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
9010 bcm_struct_cfgdev *cfgdev,
9011 u64 cookie)
9012 {
9013 s32 err = 0;
9014
9015 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9016
9017 #ifdef P2PLISTEN_AP_SAMECHN
9018 struct net_device *dev;
9019 #endif /* P2PLISTEN_AP_SAMECHN */
9020
9021 RETURN_EIO_IF_NOT_UP(cfg);
9022
9023 #ifdef DHD_IFDEBUG
9024 PRINT_WDEV_INFO(cfgdev);
9025 #endif /* DHD_IFDEBUG */
9026
9027 #if defined(WL_CFG80211_P2P_DEV_IF)
9028 if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
9029 WL_DBG((" enter ) on P2P dedicated discover interface\n"));
9030 }
9031 #else
9032 WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex));
9033 #endif /* WL_CFG80211_P2P_DEV_IF */
9034
9035 #ifdef P2PLISTEN_AP_SAMECHN
9036 if (cfg && cfg->p2p_resp_apchn_status) {
9037 dev = bcmcfg_to_prmry_ndev(cfg);
9038 wl_cfg80211_set_p2p_resp_ap_chn(dev, 0);
9039 cfg->p2p_resp_apchn_status = false;
9040 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
9041 }
9042 #endif /* P2PLISTEN_AP_SAMECHN */
9043
9044 if (cfg->last_roc_id == cookie) {
9045 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
9046 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
9047 } else {
9048 WL_ERR((
9049 "wl_cfg80211_cancel_remain_on_channel: ignore, request cookie(%llu)"
9050 " is not matched. (cur : %llu)\n",
9051 cookie, cfg->last_roc_id));
9052 }
9053
9054 return err;
9055 }
9056
wl_cfg80211_afx_handler(struct work_struct * work)9057 static void wl_cfg80211_afx_handler(struct work_struct *work)
9058 {
9059 struct afx_hdl *afx_instance;
9060 struct bcm_cfg80211 *cfg;
9061 s32 ret = BCME_OK;
9062
9063 BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
9064 if (afx_instance) {
9065 cfg = wl_get_cfg(afx_instance->dev);
9066 if (cfg != NULL && cfg->afx_hdl->is_active) {
9067 if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
9068 ret = wl_cfgp2p_discover_listen(
9069 cfg, cfg->afx_hdl->my_listen_chan,
9070 (0x64 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
9071 } else {
9072 ret = wl_cfgp2p_act_frm_search(
9073 cfg, cfg->afx_hdl->dev, cfg->afx_hdl->bssidx,
9074 cfg->afx_hdl->peer_listen_chan, NULL);
9075 }
9076 if (unlikely(ret != BCME_OK)) {
9077 WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
9078 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
9079 complete(&cfg->act_frm_scan);
9080 }
9081 }
9082 }
9083 }
9084 }
9085
wl_cfg80211_af_searching_channel(struct bcm_cfg80211 * cfg,struct net_device * dev)9086 static s32 wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg,
9087 struct net_device *dev)
9088 {
9089 u32 max_retry = WL_CHANNEL_SYNC_RETRY;
9090 bool is_p2p_gas = false;
9091
9092 if (dev == NULL) {
9093 return -1;
9094 }
9095
9096 WL_DBG((" enter ) \n"));
9097
9098 wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
9099 cfg->afx_hdl->is_active = TRUE;
9100
9101 if (cfg->afx_hdl->pending_tx_act_frm) {
9102 wl_action_frame_t *action_frame;
9103 action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
9104 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data,
9105 action_frame->len)) {
9106 is_p2p_gas = true;
9107 }
9108 }
9109
9110 /* Loop to wait until we find a peer's channel or the
9111 * pending action frame tx is cancelled.
9112 */
9113 while ((cfg->afx_hdl->retry < max_retry) &&
9114 (cfg->afx_hdl->peer_chan == WL_INVALID)) {
9115 cfg->afx_hdl->is_listen = FALSE;
9116 wl_set_drv_status(cfg, SCANNING, dev);
9117 WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
9118 cfg->afx_hdl->retry));
9119 /* search peer on peer's listen channel */
9120 schedule_work(&cfg->afx_hdl->work);
9121 wait_for_completion_timeout(&cfg->act_frm_scan,
9122 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
9123
9124 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
9125 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) {
9126 break;
9127 }
9128
9129 if (is_p2p_gas) {
9130 break;
9131 }
9132
9133 if (cfg->afx_hdl->my_listen_chan) {
9134 WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
9135 cfg->afx_hdl->my_listen_chan));
9136 /* listen on my listen channel */
9137 cfg->afx_hdl->is_listen = TRUE;
9138 schedule_work(&cfg->afx_hdl->work);
9139 wait_for_completion_timeout(
9140 &cfg->act_frm_scan, msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
9141 }
9142 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
9143 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev))) {
9144 break;
9145 }
9146
9147 cfg->afx_hdl->retry++;
9148
9149 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
9150 }
9151
9152 cfg->afx_hdl->is_active = FALSE;
9153
9154 wl_clr_drv_status(cfg, SCANNING, dev);
9155 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
9156
9157 return (cfg->afx_hdl->peer_chan);
9158 }
9159
9160 struct p2p_config_af_params {
9161 s32 max_tx_retry; /* max tx retry count if tx no ack */
9162 #ifdef WL_CFG80211_GON_COLLISION
9163 /* drop tx go nego request if go nego collision occurs */
9164 bool drop_tx_req;
9165 #endif // endif
9166 #ifdef WL_CFG80211_SYNC_GON
9167 bool extra_listen;
9168 #endif // endif
9169 bool search_channel; /* 1: search peer's channel to send af */
9170 };
9171
9172 #ifdef WL_DISABLE_HE_P2P
wl_cfg80211_he_p2p_disable(struct wiphy * wiphy,struct ether_addr peer_mac)9173 static s32 wl_cfg80211_he_p2p_disable(struct wiphy *wiphy,
9174 struct ether_addr peer_mac)
9175 {
9176 struct cfg80211_bss *bss;
9177 u8 *ie = NULL;
9178 u32 ie_len = 0;
9179 struct net_device *ndev = NULL;
9180 s32 bssidx = 0;
9181 s32 err = BCME_OK;
9182 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9183
9184 bss = CFG80211_GET_BSS(wiphy, NULL, peer_mac.octet, NULL, 0);
9185 if (!bss) {
9186 WL_ERR(("Could not find the Peer device\n"));
9187 return BCME_ERROR;
9188 } else {
9189 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
9190 #if defined(WL_CFG80211_P2P_DEV_IF)
9191 ie = (u8 *)bss->ies->data;
9192 ie_len = bss->ies->len;
9193 #else
9194 ie = bss->information_elements;
9195 ie_len = bss->len_information_elements;
9196 #endif /* WL_CFG80211_P2P_DEV_IF */
9197 GCC_DIAGNOSTIC_POP();
9198 }
9199 if (ie) {
9200 if ((bcm_parse_tlvs_dot11(ie, ie_len, EXT_MNG_HE_CAP_ID, TRUE)) ==
9201 NULL) {
9202 WL_DBG(("Peer does not support HE capability\n"));
9203 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
9204 if (ndev && (bssidx = wl_get_bssidx_by_wdev(
9205 cfg, ndev->ieee80211_ptr)) < 0) {
9206 WL_ERR(("Find index failed\n"));
9207 err = BCME_ERROR;
9208 } else {
9209 WL_DBG(("Disabling HE for P2P\n"));
9210 err = wl_cfg80211_set_he_mode(ndev, cfg, bssidx,
9211 WL_IF_TYPE_P2P_DISC, FALSE);
9212 if (err < 0) {
9213 WL_ERR(("failed to set he features, error=%d\n", err));
9214 }
9215 }
9216 } else {
9217 WL_DBG(("Peer supports HE capability\n"));
9218 }
9219 }
9220 CFG80211_PUT_BSS(wiphy, bss);
9221
9222 return err;
9223 }
9224 #endif /* WL_DISABLE_HE_P2P */
9225
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)9226 static s32 wl_cfg80211_config_p2p_pub_af_tx(
9227 struct wiphy *wiphy, wl_action_frame_t *action_frame,
9228 wl_af_params_t *af_params, struct p2p_config_af_params *config_af_params)
9229 {
9230 s32 err = BCME_OK;
9231 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9232 wifi_p2p_pub_act_frame_t *act_frm =
9233 (wifi_p2p_pub_act_frame_t *)(action_frame->data);
9234
9235 /* initialize default value */
9236 #ifdef WL_CFG80211_GON_COLLISION
9237 config_af_params->drop_tx_req = false;
9238 #endif // endif
9239 #ifdef WL_CFG80211_SYNC_GON
9240 config_af_params->extra_listen = true;
9241 #endif // endif
9242 config_af_params->search_channel = false;
9243 config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
9244 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
9245
9246 switch (act_frm->subtype) {
9247 case P2P_PAF_GON_REQ: {
9248 /* Disable he if peer does not support before starting GONEG */
9249 #ifdef WL_DISABLE_HE_P2P
9250 wl_cfg80211_he_p2p_disable(wiphy, action_frame->da);
9251 #endif /* WL_DISABLE_HE_P2P */
9252 WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
9253 wl_set_p2p_status(cfg, GO_NEG_PHASE);
9254
9255 cfg->next_af_subtype = act_frm->subtype + 1;
9256
9257 /* increase dwell time to wait for RESP frame */
9258 af_params->dwell_time = WL_MED_DWELL_TIME;
9259
9260 #ifdef WL_CFG80211_GON_COLLISION
9261 config_af_params->drop_tx_req = true;
9262 #endif /* WL_CFG80211_GON_COLLISION */
9263 break;
9264 }
9265 case P2P_PAF_GON_RSP: {
9266 cfg->next_af_subtype = act_frm->subtype + 1;
9267 /* increase dwell time to wait for CONF frame */
9268 af_params->dwell_time = WL_MED_DWELL_TIME + 0x64;
9269 break;
9270 }
9271 case P2P_PAF_GON_CONF: {
9272 /* If we reached till GO Neg confirmation reset the filter */
9273 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
9274 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
9275
9276 /* minimize dwell time */
9277 af_params->dwell_time = WL_MIN_DWELL_TIME;
9278
9279 #ifdef WL_CFG80211_GON_COLLISION
9280 /* if go nego formation done, clear it */
9281 cfg->block_gon_req_tx_count = 0;
9282 cfg->block_gon_req_rx_count = 0;
9283 #endif /* WL_CFG80211_GON_COLLISION */
9284 #ifdef WL_CFG80211_SYNC_GON
9285 config_af_params->extra_listen = false;
9286 #endif /* WL_CFG80211_SYNC_GON */
9287 break;
9288 }
9289 case P2P_PAF_INVITE_REQ: {
9290 config_af_params->search_channel = true;
9291 cfg->next_af_subtype = act_frm->subtype + 1;
9292
9293 /* increase dwell time */
9294 af_params->dwell_time = WL_MED_DWELL_TIME;
9295 break;
9296 }
9297 case P2P_PAF_INVITE_RSP:
9298 /* minimize dwell time */
9299 af_params->dwell_time = WL_MIN_DWELL_TIME;
9300 #ifdef WL_CFG80211_SYNC_GON
9301 config_af_params->extra_listen = false;
9302 #endif /* WL_CFG80211_SYNC_GON */
9303 break;
9304 case P2P_PAF_DEVDIS_REQ: {
9305 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
9306 action_frame->len)) {
9307 config_af_params->search_channel = true;
9308 }
9309
9310 cfg->next_af_subtype = act_frm->subtype + 1;
9311 /* maximize dwell time to wait for RESP frame */
9312 af_params->dwell_time = WL_LONG_DWELL_TIME;
9313 break;
9314 }
9315 case P2P_PAF_DEVDIS_RSP:
9316 /* minimize dwell time */
9317 af_params->dwell_time = WL_MIN_DWELL_TIME;
9318 #ifdef WL_CFG80211_SYNC_GON
9319 config_af_params->extra_listen = false;
9320 #endif /* WL_CFG80211_SYNC_GON */
9321 break;
9322 case P2P_PAF_PROVDIS_REQ: {
9323 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
9324 action_frame->len)) {
9325 config_af_params->search_channel = true;
9326 }
9327
9328 cfg->next_af_subtype = act_frm->subtype + 1;
9329 /* increase dwell time to wait for RESP frame */
9330 af_params->dwell_time = WL_MED_DWELL_TIME;
9331 break;
9332 }
9333 case P2P_PAF_PROVDIS_RSP: {
9334 cfg->next_af_subtype = P2P_PAF_GON_REQ;
9335 af_params->dwell_time = WL_MED_DWELL_TIME;
9336 #ifdef WL_CFG80211_SYNC_GON
9337 config_af_params->extra_listen = false;
9338 #endif /* WL_CFG80211_SYNC_GON */
9339 break;
9340 }
9341 default:
9342 WL_DBG(
9343 ("Unknown p2p pub act frame subtype: %d\n", act_frm->subtype));
9344 err = BCME_BADARG;
9345 }
9346 return err;
9347 }
9348
9349 #ifdef WL11U
wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 * cfg,wl_af_params_t * af_params,void * frame,u16 frame_len)9350 static bool wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg,
9351 wl_af_params_t *af_params,
9352 void *frame, u16 frame_len)
9353 {
9354 struct wl_scan_results *bss_list;
9355 wl_bss_info_t *bi = NULL;
9356 bool result = false;
9357 s32 i;
9358 chanspec_t chanspec;
9359
9360 /* If DFS channel is 52~148, check to block it or not */
9361 if (af_params && (af_params->channel >= 52 && af_params->channel <= 148)) {
9362 if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
9363 bss_list = cfg->bss_list;
9364 bi = next_bss(bss_list, bi);
9365 for_each_bss(bss_list, bi, i)
9366 {
9367 chanspec = wl_chspec_driver_to_host(bi->chanspec);
9368 if (CHSPEC_IS5G(chanspec) &&
9369 ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec)) ==
9370 af_params->channel)) {
9371 result = true; /* do not block the action frame */
9372 break;
9373 }
9374 }
9375 }
9376 } else {
9377 result = true;
9378 }
9379
9380 WL_DBG(("result=%s", result ? "true" : "false"));
9381 return result;
9382 }
9383 #endif /* WL11U */
wl_cfg80211_check_dwell_overflow(int32 requested_dwell,ulong dwell_jiffies)9384 static bool wl_cfg80211_check_dwell_overflow(int32 requested_dwell,
9385 ulong dwell_jiffies)
9386 {
9387 if ((requested_dwell >= 0x1F4) &&
9388 (jiffies_to_msecs(jiffies - dwell_jiffies) > requested_dwell)) {
9389 WL_ERR(("Action frame TX retry time over dwell time!\n"));
9390 return true;
9391 }
9392 return false;
9393 }
9394
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)9395 static bool wl_cfg80211_send_action_frame(struct wiphy *wiphy,
9396 struct net_device *dev,
9397 bcm_struct_cfgdev *cfgdev,
9398 wl_af_params_t *af_params,
9399 wl_action_frame_t *action_frame,
9400 u16 action_frame_len, s32 bssidx)
9401 {
9402 #ifdef WL11U
9403 struct net_device *ndev = NULL;
9404 #endif /* WL11U */
9405 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9406 bool ack = false;
9407 u8 category, action;
9408 s32 tx_retry;
9409 struct p2p_config_af_params config_af_params;
9410 struct net_info *netinfo;
9411 #ifdef VSDB
9412 ulong off_chan_started_jiffies = 0;
9413 #endif // endif
9414 ulong dwell_jiffies = 0;
9415 bool dwell_overflow = false;
9416 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
9417
9418 int32 requested_dwell = af_params->dwell_time;
9419
9420 /* Add the default dwell time
9421 * Dwell time to stay off-channel to wait for a response action frame
9422 * after transmitting an GO Negotiation action frame
9423 */
9424 af_params->dwell_time = WL_DWELL_TIME;
9425
9426 #ifdef WL11U
9427 #if defined(WL_CFG80211_P2P_DEV_IF)
9428 ndev = dev;
9429 #else
9430 ndev = ndev_to_cfgdev(cfgdev);
9431 #endif /* WL_CFG80211_P2P_DEV_IF */
9432 #endif /* WL11U */
9433
9434 category = action_frame->data[DOT11_ACTION_CAT_OFF];
9435 action = action_frame->data[DOT11_ACTION_ACT_OFF];
9436
9437 /* initialize variables */
9438 tx_retry = 0;
9439 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
9440 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
9441 config_af_params.search_channel = false;
9442 #ifdef WL_CFG80211_GON_COLLISION
9443 config_af_params.drop_tx_req = false;
9444 #endif // endif
9445 #ifdef WL_CFG80211_SYNC_GON
9446 config_af_params.extra_listen = false;
9447 #endif // endif
9448
9449 /* config parameters */
9450 /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
9451 if (category == DOT11_ACTION_CAT_PUBLIC) {
9452 if ((action == P2P_PUB_AF_ACTION) &&
9453 (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
9454 /* p2p public action frame process */
9455 if (BCME_OK !=
9456 wl_cfg80211_config_p2p_pub_af_tx(wiphy, action_frame, af_params,
9457 &config_af_params)) {
9458 WL_DBG(("Unknown subtype.\n"));
9459 }
9460
9461 #ifdef WL_CFG80211_GON_COLLISION
9462 if (config_af_params.drop_tx_req) {
9463 if (cfg->block_gon_req_tx_count) {
9464 /* drop gon req tx action frame */
9465 WL_DBG(("Drop gon req tx action frame: count %d\n",
9466 cfg->block_gon_req_tx_count));
9467 goto exit;
9468 }
9469 }
9470 #endif /* WL_CFG80211_GON_COLLISION */
9471 } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
9472 /* service discovery process */
9473 if (action == P2PSD_ACTION_ID_GAS_IREQ ||
9474 action == P2PSD_ACTION_ID_GAS_CREQ) {
9475 /* configure service discovery query frame */
9476
9477 config_af_params.search_channel = true;
9478
9479 /* save next af suptype to cancel remained dwell time */
9480 cfg->next_af_subtype = action + 1;
9481
9482 af_params->dwell_time = WL_MED_DWELL_TIME;
9483 if (requested_dwell & CUSTOM_RETRY_MASK) {
9484 config_af_params.max_tx_retry =
9485 (requested_dwell & CUSTOM_RETRY_MASK) >> 0x18;
9486 af_params->dwell_time =
9487 (requested_dwell & ~CUSTOM_RETRY_MASK);
9488 WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
9489 config_af_params.max_tx_retry,
9490 af_params->dwell_time));
9491 }
9492 } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
9493 action == P2PSD_ACTION_ID_GAS_CRESP) {
9494 /* configure service discovery response frame */
9495 af_params->dwell_time = WL_MIN_DWELL_TIME;
9496 } else {
9497 WL_DBG(("Unknown action type: %d\n", action));
9498 }
9499 } else {
9500 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
9501 category, action, action_frame_len));
9502 }
9503 } else if (category == P2P_AF_CATEGORY) {
9504 /* do not configure anything. it will be sent with a default
9505 * configuration */
9506 } else {
9507 WL_DBG(
9508 ("Unknown Frame: category 0x%x, action 0x%x\n", category, action));
9509 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
9510 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9511 return false;
9512 }
9513 }
9514
9515 netinfo = wl_get_netinfo_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
9516 /* validate channel and p2p ies */
9517 if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) &&
9518 netinfo && netinfo->bss.ies.probe_req_ie_len) {
9519 config_af_params.search_channel = true;
9520 } else {
9521 config_af_params.search_channel = false;
9522 }
9523 #ifdef WL11U
9524 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
9525 config_af_params.search_channel = false;
9526 }
9527 #endif /* WL11U */
9528
9529 #ifdef VSDB
9530 /* if connecting on primary iface, sleep for a while before sending af tx
9531 * for VSDB */
9532 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
9533 OSL_SLEEP(0x32);
9534 }
9535 #endif // endif
9536
9537 /* if scan is ongoing, abort current scan. */
9538 if (wl_get_drv_status_all(cfg, SCANNING)) {
9539 wl_cfg80211_cancel_scan(cfg);
9540 }
9541
9542 /* Abort P2P listen */
9543 if (discover_cfgdev(cfgdev, cfg)) {
9544 if (cfg->p2p_supported && cfg->p2p) {
9545 wl_cfgp2p_set_p2p_mode(
9546 cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
9547 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
9548 }
9549 }
9550
9551 #ifdef WL11U
9552 /* handling DFS channel exceptions */
9553 if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data,
9554 action_frame->len)) {
9555 return false; /* the action frame was blocked */
9556 }
9557 #endif /* WL11U */
9558
9559 /* set status and destination address before sending af */
9560 if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
9561 /* set this status to cancel the remained dwell time in rx process */
9562 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9563 }
9564 wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
9565 memcpy(cfg->afx_hdl->tx_dst_addr.octet, af_params->action_frame.da.octet,
9566 sizeof(cfg->afx_hdl->tx_dst_addr.octet));
9567
9568 /* save af_params for rx process */
9569 cfg->afx_hdl->pending_tx_act_frm = af_params;
9570
9571 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
9572 WL_DBG(("Set GAS action frame config.\n"));
9573 config_af_params.search_channel = false;
9574 config_af_params.max_tx_retry = 1;
9575 }
9576
9577 /* search peer's channel */
9578 if (config_af_params.search_channel) {
9579 /* initialize afx_hdl */
9580 if ((cfg->afx_hdl->bssidx =
9581 wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
9582 WL_ERR(
9583 ("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
9584 goto exit;
9585 }
9586 cfg->afx_hdl->dev = dev;
9587 cfg->afx_hdl->retry = 0;
9588 cfg->afx_hdl->peer_chan = WL_INVALID;
9589
9590 if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
9591 WL_ERR(("couldn't find peer's channel.\n"));
9592 wl_cfgp2p_print_actframe(true, action_frame->data,
9593 action_frame->len, af_params->channel);
9594 /* Even if we couldn't find peer channel, try to send the frame
9595 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
9596 * respond to probe request (Ideally it has to be in listen and
9597 * responsd to probe request). However if we send Go neg req, the
9598 * peer is sending GO-neg resp. So instead of giving up here, just
9599 * proceed and attempt sending out the action frame.
9600 */
9601 }
9602
9603 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
9604 /*
9605 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
9606 * but after the check of piggyback algorithm.
9607 * To take care of current piggback algo, lets abort the scan here
9608 * itself.
9609 */
9610 wl_cfg80211_cancel_scan(cfg);
9611 /* Suspend P2P discovery's search-listen to prevent it from
9612 * starting a scan or changing the channel.
9613 */
9614 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9615 WL_ERR(("Can not disable discovery mode\n"));
9616 goto exit;
9617 }
9618
9619 /* update channel */
9620 if (cfg->afx_hdl->peer_chan != WL_INVALID) {
9621 af_params->channel = cfg->afx_hdl->peer_chan;
9622 WL_ERR(("Attempt tx on peer listen channel:%d ",
9623 cfg->afx_hdl->peer_chan));
9624 } else {
9625 WL_ERR(("Attempt tx with the channel provided by userspace."
9626 "Channel: %d\n",
9627 af_params->channel));
9628 }
9629 }
9630
9631 #ifdef VSDB
9632 off_chan_started_jiffies = jiffies;
9633 #endif /* VSDB */
9634
9635 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
9636 af_params->channel);
9637
9638 wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len,
9639 true);
9640
9641 dwell_jiffies = jiffies;
9642 /* Now send a tx action frame */
9643 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
9644 dwell_overflow =
9645 wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9646
9647 if (requested_dwell < 0x1F4) {
9648 config_af_params.max_tx_retry = 0x5;
9649 }
9650 /* if failed, retry it. tx_retry_max value is configure by .... */
9651 while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry) &&
9652 !dwell_overflow) {
9653 #ifdef VSDB
9654 if (af_params->channel) {
9655 if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
9656 OFF_CHAN_TIME_THRESHOLD_MS) {
9657 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
9658 off_chan_started_jiffies = jiffies;
9659 } else {
9660 OSL_SLEEP(AF_RETRY_DELAY_TIME);
9661 }
9662 }
9663 #endif /* VSDB */
9664 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false
9665 : true;
9666 dwell_overflow =
9667 wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9668 WL_DBG(("ack:%d dwell_overflow:%d channel:%d requested_dwell:%d\n", ack,
9669 dwell_overflow, af_params->channel, requested_dwell));
9670 }
9671
9672 if (ack == false) {
9673 WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
9674 } else {
9675 WL_ERR(("success to send Action Frame(retry %d, channel:%d)\n",
9676 tx_retry, af_params->channel));
9677 }
9678 WL_DBG(("Complete to send action frame\n"));
9679 exit:
9680 /* Clear SENDING_ACT_FRM after all sending af is done */
9681 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9682
9683 #ifdef WL_CFG80211_SYNC_GON
9684 /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
9685 * if we coundn't get the next action response frame and dongle does not
9686 * keep the dwell time, go to listen state again to get next action response
9687 * frame.
9688 */
9689 if (ack && config_af_params.extra_listen &&
9690 #ifdef WL_CFG80211_GON_COLLISION
9691 !cfg->block_gon_req_tx_count &&
9692 #endif /* WL_CFG80211_GON_COLLISION */
9693 wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
9694 cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
9695 s32 extar_listen_time;
9696
9697 extar_listen_time = af_params->dwell_time -
9698 jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
9699 if (extar_listen_time > 0x32) {
9700 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9701 WL_DBG(("Wait more time! actual af time:%d,"
9702 "calculated extar listen:%d\n",
9703 af_params->dwell_time, extar_listen_time));
9704 if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
9705 extar_listen_time + 0x64) == BCME_OK) {
9706 wait_for_completion_timeout(
9707 &cfg->wait_next_af,
9708 msecs_to_jiffies(extar_listen_time + 0x64 + 0x12C));
9709 }
9710 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9711 }
9712 }
9713 #endif /* WL_CFG80211_SYNC_GON */
9714 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9715
9716 cfg->afx_hdl->pending_tx_act_frm = NULL;
9717
9718 if (ack) {
9719 WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
9720 cfg->afx_hdl->my_listen_chan));
9721 } else {
9722 WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
9723 cfg->afx_hdl->my_listen_chan));
9724 }
9725
9726 #ifdef WL_CFG80211_GON_COLLISION
9727 if (cfg->block_gon_req_tx_count) {
9728 cfg->block_gon_req_tx_count--;
9729 /* if ack is ture, supplicant will wait more time(100ms).
9730 * so we will return it as a success to get more time .
9731 */
9732 ack = true;
9733 }
9734 #endif /* WL_CFG80211_GON_COLLISION */
9735 return ack;
9736 }
9737
9738 #define MAX_NUM_OF_ASSOCIATED_DEV 64
9739 static s32
9740 #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)9741 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9742 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
9743 #else
9744 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9745 struct ieee80211_channel *channel, bool offchan,
9746 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
9747 enum nl80211_channel_type channel_type,
9748 bool channel_type_valid,
9749 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
9750 unsigned int wait, const u8 *buf, size_t len,
9751 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || \
9752 defined(WL_COMPAT_WIRELESS)
9753 bool no_cck,
9754 #endif // endif
9755 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
9756 defined(WL_COMPAT_WIRELESS)
9757 bool dont_wait_for_ack,
9758 #endif // endif
9759 u64 *cookie)
9760 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9761 {
9762 wl_action_frame_t *action_frame;
9763 wl_af_params_t *af_params;
9764 scb_val_t scb_val;
9765 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9766 struct ieee80211_channel *channel = params->chan;
9767 const u8 *buf = params->buf;
9768 size_t len = params->len;
9769 #endif // endif
9770 const struct ieee80211_mgmt *mgmt;
9771 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9772 struct net_device *dev = NULL;
9773 s32 err = BCME_OK;
9774 s32 bssidx = 0;
9775 u32 id;
9776 bool ack = false;
9777 s8 eabuf[ETHER_ADDR_STR_LEN];
9778
9779 WL_DBG(("Enter \n"));
9780
9781 if (len > ACTION_FRAME_SIZE) {
9782 WL_ERR(("bad length:%zu\n", len));
9783 return BCME_BADLEN;
9784 }
9785 #ifdef DHD_IFDEBUG
9786 PRINT_WDEV_INFO(cfgdev);
9787 #endif /* DHD_IFDEBUG */
9788
9789 dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
9790 if (!dev) {
9791 WL_ERR(("dev is NULL\n"));
9792 return -EINVAL;
9793 }
9794
9795 /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p:
9796 * P2PAPI_BSSCFG_DEVICE) */
9797 if (discover_cfgdev(cfgdev, cfg)) {
9798 if (!cfg->p2p_supported || !cfg->p2p) {
9799 WL_ERR(("P2P doesn't setup completed yet\n"));
9800 return -EINVAL;
9801 }
9802 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9803 } else {
9804 if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
9805 WL_ERR(("Find p2p index failed\n"));
9806 return BCME_ERROR;
9807 }
9808 }
9809
9810 WL_DBG(("TX target bssidx=%d\n", bssidx));
9811
9812 if (p2p_is_on(cfg)) {
9813 /* Suspend P2P discovery search-listen to prevent it from changing the
9814 * channel.
9815 */
9816 if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9817 WL_ERR(("Can not disable discovery mode\n"));
9818 return -EFAULT;
9819 }
9820 }
9821 *cookie = 0;
9822 id = cfg->send_action_id++;
9823 if (id == 0) {
9824 id = cfg->send_action_id++;
9825 }
9826 *cookie = id;
9827 mgmt = (const struct ieee80211_mgmt *)buf;
9828 if (ieee80211_is_mgmt(mgmt->frame_control)) {
9829 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
9830 s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
9831 s32 ie_len = len - ie_offset;
9832 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9833 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9834 }
9835 wl_cfg80211_set_mgmt_vndr_ies(
9836 cfg, ndev_to_cfgdev(dev), bssidx, VNDR_IE_PRBRSP_FLAG,
9837 (const u8 *)(buf + ie_offset), ie_len);
9838 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true,
9839 GFP_KERNEL);
9840 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9841 HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf,
9842 len, true);
9843 #endif
9844 #if defined(P2P_IE_MISSING_FIX)
9845 if (!cfg->p2p_prb_noti) {
9846 cfg->p2p_prb_noti = true;
9847 WL_DBG(("wl_cfg80211_mgmt_tx: TX 802_1X Probe"
9848 " Response first time.\n"));
9849 }
9850 #endif // endif
9851 goto exit;
9852 } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
9853 ieee80211_is_deauth(mgmt->frame_control)) {
9854 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * sizeof(struct ether_addr) +
9855 sizeof(uint)] = {0};
9856 int num_associated = 0;
9857 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9858 if (!bcmp((const uint8 *)BSSID_BROADCAST,
9859 (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
9860 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9861 err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
9862 sizeof(mac_buf));
9863 if (err < 0) {
9864 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9865 } else {
9866 num_associated = assoc_maclist->count;
9867 }
9868 }
9869 memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
9870 scb_val.val = mgmt->u.disassoc.reason_code;
9871 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
9872 &scb_val, sizeof(scb_val_t));
9873 if (err < 0) {
9874 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
9875 }
9876 WL_ERR(("Disconnect STA : " MACDBG " scb_val.val %d\n",
9877 MAC2STRDBG(bcm_ether_ntoa(
9878 (const struct ether_addr *)mgmt->da, eabuf)),
9879 scb_val.val));
9880
9881 if (num_associated > 0 && ETHER_ISBCAST(mgmt->da)) {
9882 wl_delay(400);
9883 }
9884
9885 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true,
9886 GFP_KERNEL);
9887 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9888 HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf,
9889 len, true);
9890 #endif
9891 goto exit;
9892 } else if (ieee80211_is_action(mgmt->frame_control)) {
9893 /* Abort the dwell time of any previous off-channel
9894 * action frame that may be still in effect. Sending
9895 * off-channel action frames relies on the driver's
9896 * scan engine. If a previous off-channel action frame
9897 * tx is still in progress (including the dwell time),
9898 * then this new action frame will not be sent out.
9899 */
9900 /* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
9901 * And previous off-channel action frame must be ended before new af tx.
9902 */
9903 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9904 wl_cfg80211_cancel_scan(cfg);
9905 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9906 }
9907 #ifdef WL_CLIENT_SAE
9908 else if (ieee80211_is_auth(mgmt->frame_control)) {
9909 err = wl_cfg80211_mgmt_auth_tx(dev, cfgdev, cfg, buf, len, bssidx,
9910 cookie);
9911 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9912 HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf,
9913 len, ack);
9914 #endif
9915 goto exit;
9916 }
9917 #endif /* WL_CLIENT_SAE */
9918 } else {
9919 WL_ERR(("Driver only allows MGMT packet type\n"));
9920 goto exit;
9921 }
9922
9923 af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
9924 if (af_params == NULL) {
9925 WL_ERR(("unable to allocate frame\n"));
9926 return -ENOMEM;
9927 }
9928 action_frame = &af_params->action_frame;
9929
9930 /* Add the packet Id */
9931 action_frame->packetId = *cookie;
9932 WL_DBG(("action frame %d\n", action_frame->packetId));
9933 /* Add BSSID */
9934 memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
9935 memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
9936
9937 /* Add the length exepted for 802.11 header */
9938 action_frame->len = len - DOT11_MGMT_HDR_LEN;
9939 WL_DBG(("action_frame->len: %d\n", action_frame->len));
9940
9941 /* Add the channel */
9942 af_params->channel = ieee80211_frequency_to_channel(channel->center_freq);
9943 /* Save listen_chan for searching common channel */
9944 cfg->afx_hdl->peer_listen_chan = af_params->channel;
9945 WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
9946
9947 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9948 af_params->dwell_time = params->wait;
9949 #else
9950 af_params->dwell_time = wait;
9951 #endif // endif
9952
9953 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
9954 printk(
9955 KERN_INFO
9956 "lijg123 send action: dst: %02x:%02x:%02x:%02x:%02x:%02x, src:%02x:%02x:%02x:%02x:%02x:%02x, \
9957 bssid:%02x:%02x:%02x:%02x:%02x:%02x\n",
9958 mgmt->da[0], mgmt->da[1], mgmt->da[0x2], mgmt->da[3], mgmt->da[0x4],
9959 mgmt->da[5], mgmt->sa[0], mgmt->sa[1], mgmt->sa[0x2], mgmt->sa[3],
9960 mgmt->sa[0x4], mgmt->sa[5], mgmt->bssid[0], mgmt->bssid[1],
9961 mgmt->bssid[0x2], mgmt->bssid[3], mgmt->bssid[0x4], mgmt->bssid[5]);
9962 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, true);
9963
9964 ack = wl_cfg80211_send_action_frame(
9965 wiphy, dev, cfgdev, af_params, action_frame, action_frame->len, bssidx);
9966 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9967 #ifdef CONFIG_AP6XXX_WIFI6_HDF
9968 HdfWifiEventMgmtTxStatus(get_hdf_netdev(g_mgmt_tx_event_ifidx), buf, len,
9969 ack);
9970 #endif
9971
9972 MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
9973 exit:
9974 return err;
9975 }
9976
wl_cfg80211_mgmt_frame_register(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u16 frame,bool reg)9977 static void wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
9978 bcm_struct_cfgdev *cfgdev,
9979 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9980 u16 frame, bool reg)
9981 #else
9982 struct mgmt_frame_regs *upd)
9983 #endif
9984 {
9985 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9986 WL_DBG(("frame_type: %x, reg: %d\n", frame, reg));
9987 if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) {
9988 return;
9989 }
9990 #endif
9991 return;
9992 }
9993
wl_cfg80211_change_bss(struct wiphy * wiphy,struct net_device * dev,struct bss_parameters * params)9994 static s32 wl_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev,
9995 struct bss_parameters *params)
9996 {
9997 s32 err = 0;
9998 s32 ap_isolate = 0;
9999 #ifdef PCIE_FULL_DONGLE
10000 s32 ifidx = DHD_BAD_IF;
10001 #endif // endif
10002 #if defined(PCIE_FULL_DONGLE)
10003 dhd_pub_t *dhd;
10004 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10005 dhd = (dhd_pub_t *)(cfg->pub);
10006 #if defined(WL_ENABLE_P2P_IF)
10007 if (cfg->p2p_net == dev) {
10008 dev = bcmcfg_to_prmry_ndev(cfg);
10009 }
10010 #endif
10011 #endif // endif
10012
10013 if (params->use_cts_prot >= 0) {
10014 }
10015
10016 if (params->use_short_preamble >= 0) {
10017 }
10018
10019 if (params->use_short_slot_time >= 0) {
10020 }
10021
10022 if (params->basic_rates) {
10023 }
10024
10025 if (params->ap_isolate >= 0) {
10026 ap_isolate = params->ap_isolate;
10027 #ifdef PCIE_FULL_DONGLE
10028 ifidx = dhd_net2idx(dhd->info, dev);
10029 if (ifidx != DHD_BAD_IF) {
10030 err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate);
10031 } else {
10032 WL_ERR(("Failed to set ap_isolate\n"));
10033 }
10034 #else
10035 err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
10036 if (unlikely(err)) {
10037 WL_ERR(("set ap_isolate Error (%d)\n", err));
10038 }
10039 #endif /* PCIE_FULL_DONGLE */
10040 }
10041
10042 if (params->ht_opmode >= 0) {
10043 }
10044
10045 return err;
10046 }
10047
wl_get_bandwidth_cap(struct net_device * ndev,uint32 band,uint32 * bandwidth)10048 static int wl_get_bandwidth_cap(struct net_device *ndev, uint32 band,
10049 uint32 *bandwidth)
10050 {
10051 u32 bw = WL_CHANSPEC_BW_20;
10052 s32 err = BCME_OK;
10053 s32 bw_cap = 0;
10054 struct {
10055 u32 band;
10056 u32 bw_cap;
10057 } param = {0, 0};
10058 u8 ioctl_buf[WLC_IOCTL_SMLEN];
10059
10060 if (band == IEEE80211_BAND_2GHZ) {
10061 param.band = WLC_BAND_2G;
10062 } else if (band == IEEE80211_BAND_5GHZ) {
10063 param.band = WLC_BAND_5G;
10064 }
10065
10066 if (band == IEEE80211_BAND_2GHZ || band == IEEE80211_BAND_5GHZ) {
10067 err = wldev_iovar_getbuf(ndev, "bw_cap", ¶m, sizeof(param),
10068 ioctl_buf, sizeof(ioctl_buf), NULL);
10069 if (err) {
10070 if (err != BCME_UNSUPPORTED) {
10071 WL_ERR(("bw_cap failed, %d\n", err));
10072 return err;
10073 } else {
10074 err = wldev_iovar_getint(ndev, "mimo_bw_cap", &bw_cap);
10075 if (err) {
10076 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
10077 }
10078 if (bw_cap != WLC_N_BW_20ALL) {
10079 bw = WL_CHANSPEC_BW_40;
10080 }
10081 }
10082 } else {
10083 if (WL_BW_CAP_80MHZ(ioctl_buf[0])) {
10084 bw = WL_CHANSPEC_BW_80;
10085 } else if (WL_BW_CAP_40MHZ(ioctl_buf[0])) {
10086 bw = WL_CHANSPEC_BW_40;
10087 } else {
10088 bw = WL_CHANSPEC_BW_20;
10089 }
10090 }
10091 } else if (band == IEEE80211_BAND_2GHZ) {
10092 bw = WL_CHANSPEC_BW_20;
10093 }
10094
10095 *bandwidth = bw;
10096
10097 return err;
10098 }
10099
wl_cfg80211_set_channel(struct wiphy * wiphy,struct net_device * dev,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type)10100 static s32 wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
10101 struct ieee80211_channel *chan,
10102 enum nl80211_channel_type channel_type)
10103 {
10104 s32 _chan;
10105 chanspec_t chspec = 0;
10106 chanspec_t fw_chspec = 0;
10107 u32 bw = WL_CHANSPEC_BW_20;
10108 s32 err = BCME_OK;
10109 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10110 #if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL) || \
10111 defined(WL_EXT_IAPSTA)
10112 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10113 #endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
10114
10115 dev = ndev_to_wlc_ndev(dev, cfg);
10116 _chan = ieee80211_frequency_to_channel(chan->center_freq);
10117 #ifdef WL_EXT_IAPSTA
10118 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
10119 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
10120 u16 wl_iftype = 0;
10121 u16 wl_mode = 0;
10122 if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype, &wl_iftype,
10123 &wl_mode) < 0) {
10124 WL_ERR(
10125 ("Unknown interface type:0x%x\n", dev->ieee80211_ptr->iftype));
10126 return -EINVAL;
10127 }
10128 wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev),
10129 wl_iftype);
10130 _chan = wl_ext_iapsta_update_channel(dhd, dev, _chan);
10131 }
10132 #endif
10133 WL_MSG(dev->name, "netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
10134 dev->ifindex, channel_type, _chan);
10135
10136 #ifdef NOT_YET
10137 switch (channel_type) {
10138 case NL80211_CHAN_HT40MINUS:
10139 /* secondary channel is below the control channel */
10140 chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_UPPER);
10141 break;
10142 case NL80211_CHAN_HT40PLUS:
10143 /* secondary channel is above the control channel */
10144 chspec = CH40MHZ_CHSPEC(channel, WL_CHANSPEC_CTL_SB_LOWER);
10145 break;
10146 default:
10147 chspec = CH20MHZ_CHSPEC(channel);
10148 }
10149 #endif /* NOT_YET */
10150
10151 #if defined(APSTA_RESTRICTED_CHANNEL)
10152 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
10153 DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
10154 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
10155 u32 *sta_chan =
10156 (u32 *)wl_read_prof(cfg, bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN);
10157 u32 sta_band = (*sta_chan > CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_5GHZ
10158 : IEEE80211_BAND_2GHZ;
10159 if (chan->band == sta_band) {
10160 /* Do not try SCC in 5GHz if channel is not CH149 */
10161 _chan = (sta_band == IEEE80211_BAND_5GHZ &&
10162 *sta_chan != DEFAULT_5G_SOFTAP_CHANNEL)
10163 ? DEFAULT_2G_SOFTAP_CHANNEL
10164 : *sta_chan;
10165 WL_ERR(("target channel will be changed to %d\n", _chan));
10166 if (_chan <= CH_MAX_2G_CHANNEL) {
10167 bw = WL_CHANSPEC_BW_20;
10168 goto set_channel;
10169 }
10170 }
10171 }
10172 #endif /* APSTA_RESTRICTED_CHANNEL */
10173
10174 err = wl_get_bandwidth_cap(dev, chan->band, &bw);
10175 if (err < 0) {
10176 WL_ERR(("Failed to get bandwidth information, err=%d\n", err));
10177 return err;
10178 }
10179
10180 set_channel:
10181 chspec = wf_channel2chspec(_chan, bw);
10182 if (wf_chspec_valid(chspec)) {
10183 fw_chspec = wl_chspec_host_to_driver(chspec);
10184 if (fw_chspec != INVCHANSPEC) {
10185 if ((err = wldev_iovar_setint(dev, "chanspec", fw_chspec)) ==
10186 BCME_BADCHAN) {
10187 if (bw == WL_CHANSPEC_BW_80) {
10188 goto change_bw;
10189 }
10190 err = wldev_ioctl_set(dev, WLC_SET_CHANNEL, &_chan,
10191 sizeof(_chan));
10192 if (err < 0) {
10193 WL_ERR(("WLC_SET_CHANNEL error %d"
10194 "chip may not be supporting this channel\n",
10195 err));
10196 }
10197 } else if (err) {
10198 WL_ERR(("failed to set chanspec error %d\n", err));
10199 }
10200 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
10201 else {
10202 /* Disable Frameburst only for stand-alone 2GHz SoftAP */
10203 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
10204 DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
10205 (_chan <= CH_MAX_2G_CHANNEL) &&
10206 !wl_get_drv_status(cfg, CONNECTED,
10207 bcmcfg_to_prmry_ndev(cfg))) {
10208 WL_DBG(("Disabling frameburst on "
10209 "stand-alone 2GHz SoftAP\n"));
10210 wl_cfg80211_set_frameburst(cfg, FALSE);
10211 }
10212 }
10213 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
10214 } else {
10215 WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
10216 err = BCME_ERROR;
10217 }
10218 } else {
10219 change_bw:
10220 if (bw == WL_CHANSPEC_BW_80) {
10221 bw = WL_CHANSPEC_BW_40;
10222 } else if (bw == WL_CHANSPEC_BW_40) {
10223 bw = WL_CHANSPEC_BW_20;
10224 } else {
10225 bw = 0;
10226 }
10227 if (bw) {
10228 goto set_channel;
10229 }
10230 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
10231 err = BCME_ERROR;
10232 }
10233 #ifdef CUSTOM_SET_CPUCORE
10234 if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
10235 WL_DBG(("SoftAP mode do not need to set cpucore\n"));
10236 } else if (chspec & WL_CHANSPEC_BW_80) {
10237 /* SoftAp only mode do not need to set cpucore */
10238 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
10239 dev != bcmcfg_to_prmry_ndev(cfg)) {
10240 /* Soft AP on virtual Iface (AP+STA case) */
10241 dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
10242 dhd_set_cpucore(dhd, TRUE);
10243 } else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
10244 /* If P2P IF is vht80 */
10245 dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
10246 dhd_set_cpucore(dhd, TRUE);
10247 }
10248 }
10249 #endif /* CUSTOM_SET_CPUCORE */
10250 if (!err && (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
10251 /* Update AP/GO operating channel */
10252 cfg->ap_oper_channel =
10253 ieee80211_frequency_to_channel(chan->center_freq);
10254 }
10255 if (err) {
10256 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg), FW_LOGSET_MASK_ALL);
10257 }
10258 return err;
10259 }
10260
10261 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
10262 struct net_device *
wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 * cfg)10263 wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
10264 {
10265 struct net_info *_net_info, *next;
10266 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
10267 list_for_each_entry_safe(_net_info, next, &cfg->net_list, list)
10268 {
10269 GCC_DIAGNOSTIC_POP();
10270 if (_net_info->ndev &&
10271 test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state)) {
10272 return _net_info->ndev;
10273 }
10274 }
10275
10276 return NULL;
10277 }
10278 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
10279
wl_validate_opensecurity(struct net_device * dev,s32 bssidx,bool privacy)10280 static s32 wl_validate_opensecurity(struct net_device *dev, s32 bssidx,
10281 bool privacy)
10282 {
10283 s32 err = BCME_OK;
10284 u32 wpa_val;
10285 s32 wsec = 0;
10286
10287 /* set auth */
10288 err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
10289 if (err < 0) {
10290 WL_ERR(("auth error %d\n", err));
10291 return BCME_ERROR;
10292 }
10293
10294 if (privacy) {
10295 /* If privacy bit is set in open mode, then WEP would be enabled */
10296 wsec = WEP_ENABLED;
10297 WL_DBG(("Setting wsec to %d for WEP \n", wsec));
10298 }
10299
10300 /* set wsec */
10301 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10302 if (err < 0) {
10303 WL_ERR(("wsec error %d\n", err));
10304 return BCME_ERROR;
10305 }
10306
10307 /* set upper-layer auth */
10308 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC) {
10309 wpa_val = WPA_AUTH_NONE;
10310 } else {
10311 wpa_val = WPA_AUTH_DISABLED;
10312 }
10313 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_val, bssidx);
10314 if (err < 0) {
10315 WL_ERR(("wpa_auth error %d\n", err));
10316 return BCME_ERROR;
10317 }
10318
10319 return 0;
10320 }
10321
10322 #define MAX_FILS_IND_IE_LEN 1024u
wl_validate_fils_ind_ie(struct net_device * dev,const bcm_tlv_t * filsindie,s32 bssidx)10323 static s32 wl_validate_fils_ind_ie(struct net_device *dev,
10324 const bcm_tlv_t *filsindie, s32 bssidx)
10325 {
10326 s32 err = BCME_OK;
10327 struct bcm_cfg80211 *cfg = NULL;
10328 bcm_iov_buf_t *iov_buf = NULL;
10329 bcm_xtlv_t *pxtlv;
10330 int iov_buf_size = 0;
10331
10332 if (!dev || !filsindie) {
10333 WL_ERR(("%s: dev/filsidie is null\n", __FUNCTION__));
10334 goto exit;
10335 }
10336
10337 cfg = wl_get_cfg(dev);
10338 if (!cfg) {
10339 WL_ERR(("%s: cfg is null\n", __FUNCTION__));
10340 goto exit;
10341 }
10342
10343 iov_buf_size =
10344 sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) + filsindie->len - 1;
10345 iov_buf = MALLOCZ(cfg->osh, iov_buf_size);
10346 if (!iov_buf) {
10347 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__,
10348 iov_buf_size));
10349 err = BCME_NOMEM;
10350 goto exit;
10351 }
10352 iov_buf->version = WL_FILS_IOV_VERSION;
10353 iov_buf->id = WL_FILS_CMD_ADD_IND_IE;
10354 iov_buf->len = sizeof(bcm_xtlv_t) + filsindie->len - 1;
10355 pxtlv = (bcm_xtlv_t *)&iov_buf->data[0];
10356 pxtlv->id = WL_FILS_XTLV_IND_IE;
10357 pxtlv->len = filsindie->len;
10358 /* memcpy_s return check not required as buffer is allocated based on ie
10359 * len
10360 */
10361 (void)memcpy_s(pxtlv->data, filsindie->len, filsindie->data,
10362 filsindie->len);
10363
10364 err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf_size, cfg->ioctl_buf,
10365 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
10366 if (unlikely(err)) {
10367 WL_ERR(("fils indication ioctl error (%d)\n", err));
10368 goto exit;
10369 }
10370
10371 exit:
10372 if (err < 0) {
10373 WL_ERR(("FILS Ind setting error %d\n", err));
10374 }
10375
10376 if (iov_buf) {
10377 MFREE(cfg->osh, iov_buf, iov_buf_size);
10378 }
10379 return err;
10380 }
10381
wl_validate_wpa2ie(struct net_device * dev,const bcm_tlv_t * wpa2ie,s32 bssidx)10382 static s32 wl_validate_wpa2ie(struct net_device *dev, const bcm_tlv_t *wpa2ie,
10383 s32 bssidx)
10384 {
10385 s32 len = 0;
10386 s32 err = BCME_OK;
10387 u16 auth = 0; /* d11 open authentication */
10388 u32 wsec;
10389 u32 pval = 0;
10390 u32 gval = 0;
10391 u32 wpa_auth = 0;
10392 const wpa_suite_mcast_t *mcast;
10393 const wpa_suite_ucast_t *ucast;
10394 const wpa_suite_auth_key_mgmt_t *mgmt;
10395 const wpa_pmkid_list_t *pmkid;
10396 int cnt = 0;
10397 #ifdef MFP
10398 int mfp = 0;
10399 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
10400 #endif /* MFP */
10401
10402 u16 suite_count;
10403 u8 rsn_cap[0x2];
10404 u32 wme_bss_disable;
10405
10406 if (wpa2ie == NULL) {
10407 goto exit;
10408 }
10409
10410 WL_DBG(("Enter \n"));
10411 len = wpa2ie->len - WPA2_VERSION_LEN;
10412 /* check the mcast cipher */
10413 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10414 switch (mcast->type) {
10415 case WPA_CIPHER_NONE:
10416 gval = 0;
10417 break;
10418 case WPA_CIPHER_WEP_40:
10419 case WPA_CIPHER_WEP_104:
10420 gval = WEP_ENABLED;
10421 break;
10422 case WPA_CIPHER_TKIP:
10423 gval = TKIP_ENABLED;
10424 break;
10425 case WPA_CIPHER_AES_CCM:
10426 gval = AES_ENABLED;
10427 break;
10428 #ifdef BCMWAPI_WPI
10429 case WAPI_CIPHER_SMS4:
10430 gval = SMS4_ENABLED;
10431 break;
10432 #endif // endif
10433 default:
10434 WL_ERR(("No Security Info\n"));
10435 break;
10436 }
10437 if ((len -= WPA_SUITE_LEN) <= 0) {
10438 return BCME_BADLEN;
10439 }
10440
10441 /* check the unicast cipher */
10442 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10443 suite_count = ltoh16_ua(&ucast->count);
10444 switch (ucast->list[0].type) {
10445 case WPA_CIPHER_NONE:
10446 pval = 0;
10447 break;
10448 case WPA_CIPHER_WEP_40:
10449 case WPA_CIPHER_WEP_104:
10450 pval = WEP_ENABLED;
10451 break;
10452 case WPA_CIPHER_TKIP:
10453 pval = TKIP_ENABLED;
10454 break;
10455 case WPA_CIPHER_AES_CCM:
10456 pval = AES_ENABLED;
10457 break;
10458 #ifdef BCMWAPI_WPI
10459 case WAPI_CIPHER_SMS4:
10460 pval = SMS4_ENABLED;
10461 break;
10462 #endif // endif
10463 default:
10464 WL_ERR(("No Security Info\n"));
10465 }
10466 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <=
10467 0) {
10468 return BCME_BADLEN;
10469 }
10470
10471 /* FOR WPS , set SEC_OW_ENABLED */
10472 wsec = (pval | gval | SES_OW_ENABLED);
10473 /* check the AKM */
10474 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
10475 suite_count = cnt = ltoh16_ua(&mgmt->count);
10476 while (cnt--) {
10477 switch (mgmt->list[cnt].type) {
10478 case RSN_AKM_NONE:
10479 wpa_auth |= WPA_AUTH_NONE;
10480 break;
10481 case RSN_AKM_UNSPECIFIED:
10482 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
10483 break;
10484 case RSN_AKM_PSK:
10485 wpa_auth |= WPA2_AUTH_PSK;
10486 break;
10487 #ifdef MFP
10488 case RSN_AKM_MFP_PSK:
10489 wpa_auth |= WPA2_AUTH_PSK_SHA256;
10490 break;
10491 case RSN_AKM_MFP_1X:
10492 wpa_auth |= WPA2_AUTH_1X_SHA256;
10493 break;
10494 case RSN_AKM_FILS_SHA256:
10495 wpa_auth |= WPA2_AUTH_FILS_SHA256;
10496 break;
10497 case RSN_AKM_FILS_SHA384:
10498 wpa_auth |= WPA2_AUTH_FILS_SHA384;
10499 break;
10500 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
10501 case RSN_AKM_SAE_PSK:
10502 wpa_auth |= WPA3_AUTH_SAE_PSK;
10503 break;
10504 #endif /* WL_SAE || WL_CLIENT_SAE */
10505 #endif /* MFP */
10506 default:
10507 WL_ERR(("No Key Mgmt Info\n"));
10508 }
10509 }
10510
10511 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >=
10512 RSN_CAP_LEN) {
10513 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
10514 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
10515
10516 if (rsn_cap[0] &
10517 (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
10518 wme_bss_disable = 0;
10519 } else {
10520 wme_bss_disable = 1;
10521 }
10522
10523 #ifdef MFP
10524 if (rsn_cap[0] & RSN_CAP_MFPR) {
10525 WL_DBG(("MFP Required \n"));
10526 mfp = WL_MFP_REQUIRED;
10527 /* Our firmware has requirement that
10528 * WPA2_AUTH_PSK/WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI is to
10529 * be included in the rsn ie.
10530 */
10531 if (wpa_auth & WPA2_AUTH_PSK_SHA256) {
10532 wpa_auth |= WPA2_AUTH_PSK;
10533 } else if (wpa_auth & WPA2_AUTH_1X_SHA256) {
10534 wpa_auth |= WPA2_AUTH_UNSPECIFIED;
10535 }
10536 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
10537 WL_DBG(("MFP Capable \n"));
10538 mfp = WL_MFP_CAPABLE;
10539 }
10540 #endif /* MFP */
10541
10542 /* set wme_bss_disable to sync RSN Capabilities */
10543 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable,
10544 bssidx);
10545 if (err < 0) {
10546 WL_ERR(("wme_bss_disable error %d\n", err));
10547 return BCME_ERROR;
10548 }
10549 } else {
10550 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
10551 }
10552
10553 len -= RSN_CAP_LEN;
10554 if (len >= WPA2_PMKID_COUNT_LEN) {
10555 pmkid =
10556 (const wpa_pmkid_list_t *)((const u8 *)&mgmt->list[suite_count] +
10557 RSN_CAP_LEN);
10558 cnt = ltoh16_ua(&pmkid->count);
10559 if (cnt != 0) {
10560 WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
10561 return BCME_ERROR;
10562 }
10563 /* since PMKID cnt is known to be 0 for AP, */
10564 /* so don't bother to send down this info to firmware */
10565 }
10566
10567 #ifdef MFP
10568 len -= WPA2_PMKID_COUNT_LEN;
10569 if (len >= WPA_SUITE_LEN) {
10570 cfg->bip_pos = (const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN +
10571 WPA2_PMKID_COUNT_LEN;
10572 } else {
10573 cfg->bip_pos = NULL;
10574 }
10575 #endif // endif
10576
10577 /* set auth */
10578 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10579 if (err < 0) {
10580 WL_ERR(("auth error %d\n", err));
10581 return BCME_ERROR;
10582 }
10583
10584 /* set wsec */
10585 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10586 if (err < 0) {
10587 WL_ERR(("wsec error %d\n", err));
10588 return BCME_ERROR;
10589 }
10590
10591 #ifdef MFP
10592 cfg->mfp_mode = mfp;
10593 #endif /* MFP */
10594
10595 /* set upper-layer auth */
10596 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10597 if (err < 0) {
10598 WL_ERR(("wpa_auth error %d\n", err));
10599 return BCME_ERROR;
10600 }
10601 exit:
10602 return 0;
10603 }
10604
wl_validate_wpaie(struct net_device * dev,const wpa_ie_fixed_t * wpaie,s32 bssidx)10605 static s32 wl_validate_wpaie(struct net_device *dev,
10606 const wpa_ie_fixed_t *wpaie, s32 bssidx)
10607 {
10608 const wpa_suite_mcast_t *mcast;
10609 const wpa_suite_ucast_t *ucast;
10610 const wpa_suite_auth_key_mgmt_t *mgmt;
10611 u16 auth = 0; /* d11 open authentication */
10612 u16 count;
10613 s32 err = BCME_OK;
10614 s32 len = 0;
10615 u32 i;
10616 u32 wsec;
10617 u32 pval = 0;
10618 u32 gval = 0;
10619 u32 wpa_auth = 0;
10620 u32 tmp = 0;
10621
10622 if (wpaie == NULL) {
10623 goto exit;
10624 }
10625 WL_DBG(("Enter \n"));
10626 len = wpaie->length; /* value length */
10627 len -= WPA_IE_TAG_FIXED_LEN;
10628 /* check for multicast cipher suite */
10629 if (len < WPA_SUITE_LEN) {
10630 WL_INFORM_MEM(("no multicast cipher suite\n"));
10631 goto exit;
10632 }
10633
10634 /* pick up multicast cipher */
10635 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
10636 len -= WPA_SUITE_LEN;
10637 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
10638 if (IS_WPA_CIPHER(mcast->type)) {
10639 tmp = 0;
10640 switch (mcast->type) {
10641 case WPA_CIPHER_NONE:
10642 tmp = 0;
10643 break;
10644 case WPA_CIPHER_WEP_40:
10645 case WPA_CIPHER_WEP_104:
10646 tmp = WEP_ENABLED;
10647 break;
10648 case WPA_CIPHER_TKIP:
10649 tmp = TKIP_ENABLED;
10650 break;
10651 case WPA_CIPHER_AES_CCM:
10652 tmp = AES_ENABLED;
10653 break;
10654 default:
10655 WL_ERR(("No Security Info\n"));
10656 }
10657 gval |= tmp;
10658 }
10659 }
10660 /* Check for unicast suite(s) */
10661 if (len < WPA_IE_SUITE_COUNT_LEN) {
10662 WL_INFORM_MEM(("no unicast suite\n"));
10663 goto exit;
10664 }
10665 /* walk thru unicast cipher list and pick up what we recognize */
10666 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10667 count = ltoh16_ua(&ucast->count);
10668 len -= WPA_IE_SUITE_COUNT_LEN;
10669 for (i = 0; i < count && len >= WPA_SUITE_LEN; i++, len -= WPA_SUITE_LEN) {
10670 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10671 if (IS_WPA_CIPHER(ucast->list[i].type)) {
10672 tmp = 0;
10673 switch (ucast->list[i].type) {
10674 case WPA_CIPHER_NONE:
10675 tmp = 0;
10676 break;
10677 case WPA_CIPHER_WEP_40:
10678 case WPA_CIPHER_WEP_104:
10679 tmp = WEP_ENABLED;
10680 break;
10681 case WPA_CIPHER_TKIP:
10682 tmp = TKIP_ENABLED;
10683 break;
10684 case WPA_CIPHER_AES_CCM:
10685 tmp = AES_ENABLED;
10686 break;
10687 default:
10688 WL_ERR(("No Security Info\n"));
10689 }
10690 pval |= tmp;
10691 }
10692 }
10693 }
10694 len -= (count - i) * WPA_SUITE_LEN;
10695 /* Check for auth key management suite(s) */
10696 if (len < WPA_IE_SUITE_COUNT_LEN) {
10697 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10698 goto exit;
10699 }
10700 /* walk thru auth management suite list and pick up what we recognize */
10701 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
10702 count = ltoh16_ua(&mgmt->count);
10703 len -= WPA_IE_SUITE_COUNT_LEN;
10704 for (i = 0; i < count && len >= WPA_SUITE_LEN; i++, len -= WPA_SUITE_LEN) {
10705 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10706 if (IS_WPA_AKM(mgmt->list[i].type)) {
10707 tmp = 0;
10708 switch (mgmt->list[i].type) {
10709 case RSN_AKM_NONE:
10710 tmp = WPA_AUTH_NONE;
10711 break;
10712 case RSN_AKM_UNSPECIFIED:
10713 tmp = WPA_AUTH_UNSPECIFIED;
10714 break;
10715 case RSN_AKM_PSK:
10716 tmp = WPA_AUTH_PSK;
10717 break;
10718 default:
10719 WL_ERR(("No Key Mgmt Info\n"));
10720 }
10721 wpa_auth |= tmp;
10722 }
10723 }
10724 }
10725 /* FOR WPS , set SEC_OW_ENABLED */
10726 wsec = (pval | gval | SES_OW_ENABLED);
10727 /* set auth */
10728 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10729 if (err < 0) {
10730 WL_ERR(("auth error %d\n", err));
10731 return BCME_ERROR;
10732 }
10733 /* set wsec */
10734 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10735 if (err < 0) {
10736 WL_ERR(("wsec error %d\n", err));
10737 return BCME_ERROR;
10738 }
10739 /* set upper-layer auth */
10740 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10741 if (err < 0) {
10742 WL_ERR(("wpa_auth error %d\n", err));
10743 return BCME_ERROR;
10744 }
10745 exit:
10746 return 0;
10747 }
10748
10749 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
wl_get_cipher_type(uint8 type)10750 static u32 wl_get_cipher_type(uint8 type)
10751 {
10752 u32 ret = 0;
10753 switch (type) {
10754 case WPA_CIPHER_NONE:
10755 ret = 0;
10756 break;
10757 case WPA_CIPHER_WEP_40:
10758 case WPA_CIPHER_WEP_104:
10759 ret = WEP_ENABLED;
10760 break;
10761 case WPA_CIPHER_TKIP:
10762 ret = TKIP_ENABLED;
10763 break;
10764 case WPA_CIPHER_AES_CCM:
10765 ret = AES_ENABLED;
10766 break;
10767 #ifdef BCMWAPI_WPI
10768 case WAPI_CIPHER_SMS4:
10769 ret = SMS4_ENABLED;
10770 break;
10771 #endif // endif
10772 default:
10773 WL_ERR(("No Security Info\n"));
10774 }
10775 return ret;
10776 }
10777
wl_get_suite_auth_key_mgmt_type(uint8 type,const wpa_suite_mcast_t * mcast)10778 static u32 wl_get_suite_auth_key_mgmt_type(uint8 type,
10779 const wpa_suite_mcast_t *mcast)
10780 {
10781 u32 ret = 0;
10782 u32 is_wpa2 = 0;
10783
10784 if (!bcmp(mcast->oui, WPA2_OUI, WPA2_OUI_LEN)) {
10785 is_wpa2 = 1;
10786 }
10787
10788 WL_INFORM_MEM(("%s, type = %d\n", is_wpa2 ? "WPA2" : "WPA", type));
10789 switch (type) {
10790 case RSN_AKM_NONE:
10791 /* For WPA and WPA2, AUTH_NONE is common */
10792 ret = WPA_AUTH_NONE;
10793 break;
10794 case RSN_AKM_UNSPECIFIED:
10795 if (is_wpa2) {
10796 ret = WPA2_AUTH_UNSPECIFIED;
10797 } else {
10798 ret = WPA_AUTH_UNSPECIFIED;
10799 }
10800 break;
10801 case RSN_AKM_PSK:
10802 if (is_wpa2) {
10803 ret = WPA2_AUTH_PSK;
10804 } else {
10805 ret = WPA_AUTH_PSK;
10806 }
10807 break;
10808 #ifdef WL_SAE
10809 case RSN_AKM_SAE_PSK:
10810 ret = WPA3_AUTH_SAE_PSK;
10811 break;
10812 #endif /* WL_SAE */
10813 default:
10814 WL_ERR(("No Key Mgmt Info\n"));
10815 }
10816
10817 return ret;
10818 }
10819
wl_validate_wpaie_wpa2ie(struct net_device * dev,const wpa_ie_fixed_t * wpaie,const bcm_tlv_t * wpa2ie,s32 bssidx)10820 static s32 wl_validate_wpaie_wpa2ie(struct net_device *dev,
10821 const wpa_ie_fixed_t *wpaie,
10822 const bcm_tlv_t *wpa2ie, s32 bssidx)
10823 {
10824 const wpa_suite_mcast_t *mcast;
10825 const wpa_suite_ucast_t *ucast;
10826 const wpa_suite_auth_key_mgmt_t *mgmt;
10827 u16 auth = 0; /* d11 open authentication */
10828 u16 count;
10829 s32 err = BCME_OK;
10830 u32 wme_bss_disable;
10831 u16 suite_count;
10832 u8 rsn_cap[0x2];
10833 s32 len = 0;
10834 u32 i;
10835 u32 wsec1, wsec2, wsec;
10836 u32 pval = 0;
10837 u32 gval = 0;
10838 u32 wpa_auth = 0;
10839 u32 wpa_auth1 = 0;
10840 u32 wpa_auth2 = 0;
10841
10842 if (wpaie == NULL || wpa2ie == NULL) {
10843 goto exit;
10844 }
10845
10846 WL_DBG(("Enter \n"));
10847 len = wpaie->length; /* value length */
10848 len -= WPA_IE_TAG_FIXED_LEN;
10849 /* check for multicast cipher suite */
10850 if (len < WPA_SUITE_LEN) {
10851 WL_INFORM_MEM(("no multicast cipher suite\n"));
10852 goto exit;
10853 }
10854
10855 /* pick up multicast cipher */
10856 mcast = (const wpa_suite_mcast_t *)&wpaie[1];
10857 len -= WPA_SUITE_LEN;
10858 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
10859 if (IS_WPA_CIPHER(mcast->type)) {
10860 gval |= wl_get_cipher_type(mcast->type);
10861 }
10862 }
10863 WL_DBG(("\nwpa ie validate\n"));
10864 WL_DBG(("wpa ie mcast cipher = 0x%X\n", gval));
10865
10866 /* Check for unicast suite(s) */
10867 if (len < WPA_IE_SUITE_COUNT_LEN) {
10868 WL_INFORM_MEM(("no unicast suite\n"));
10869 goto exit;
10870 }
10871
10872 /* walk thru unicast cipher list and pick up what we recognize */
10873 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10874 count = ltoh16_ua(&ucast->count);
10875 len -= WPA_IE_SUITE_COUNT_LEN;
10876 for (i = 0; i < count && len >= WPA_SUITE_LEN; i++, len -= WPA_SUITE_LEN) {
10877 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10878 if (IS_WPA_CIPHER(ucast->list[i].type)) {
10879 pval |= wl_get_cipher_type(ucast->list[i].type);
10880 }
10881 }
10882 }
10883 WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count, pval));
10884
10885 /* FOR WPS , set SEC_OW_ENABLED */
10886 wsec1 = (pval | gval | SES_OW_ENABLED);
10887 WL_ERR(("wpa ie wsec = 0x%X\n", wsec1));
10888
10889 len -= (count - i) * WPA_SUITE_LEN;
10890 /* Check for auth key management suite(s) */
10891 if (len < WPA_IE_SUITE_COUNT_LEN) {
10892 WL_INFORM_MEM((" no auth key mgmt suite\n"));
10893 goto exit;
10894 }
10895 /* walk thru auth management suite list and pick up what we recognize */
10896 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
10897 count = ltoh16_ua(&mgmt->count);
10898 len -= WPA_IE_SUITE_COUNT_LEN;
10899 for (i = 0; i < count && len >= WPA_SUITE_LEN; i++, len -= WPA_SUITE_LEN) {
10900 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
10901 if (IS_WPA_AKM(mgmt->list[i].type)) {
10902 wpa_auth1 |=
10903 wl_get_suite_auth_key_mgmt_type(mgmt->list[i].type, mcast);
10904 }
10905 }
10906 }
10907 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count,
10908 wpa_auth1));
10909 WL_ERR(("\nwpa2 ie validate\n"));
10910
10911 pval = 0;
10912 gval = 0;
10913 len = wpa2ie->len;
10914 /* check the mcast cipher */
10915 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10916 gval = wl_get_cipher_type(mcast->type);
10917
10918 WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval));
10919 if ((len -= WPA_SUITE_LEN) <= 0) {
10920 WL_ERR(("P:wpa2 ie len[%d]", len));
10921 return BCME_BADLEN;
10922 }
10923
10924 /* check the unicast cipher */
10925 ucast = (const wpa_suite_ucast_t *)&mcast[1];
10926 suite_count = ltoh16_ua(&ucast->count);
10927 WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count));
10928 pval |= wl_get_cipher_type(ucast->list[0].type);
10929
10930 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <=
10931 0) {
10932 return BCME_BADLEN;
10933 }
10934
10935 WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval));
10936
10937 /* FOR WPS , set SEC_OW_ENABLED */
10938 wsec2 = (pval | gval | SES_OW_ENABLED);
10939 WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2));
10940
10941 /* check the AKM */
10942 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
10943 suite_count = ltoh16_ua(&mgmt->count);
10944 wpa_auth2 = wl_get_suite_auth_key_mgmt_type(mgmt->list[0].type, mcast);
10945 WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count,
10946 wpa_auth2));
10947
10948 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >=
10949 RSN_CAP_LEN) {
10950 rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
10951 rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
10952 if (rsn_cap[0] &
10953 (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
10954 wme_bss_disable = 0;
10955 } else {
10956 wme_bss_disable = 1;
10957 }
10958 WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap[0],
10959 wme_bss_disable));
10960
10961 /* set wme_bss_disable to sync RSN Capabilities */
10962 err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable,
10963 bssidx);
10964 if (err < 0) {
10965 WL_ERR(("wme_bss_disable error %d\n", err));
10966 return BCME_ERROR;
10967 }
10968 } else {
10969 WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
10970 }
10971
10972 wsec = (wsec1 | wsec2);
10973 wpa_auth = (wpa_auth1 | wpa_auth2);
10974 WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec, wpa_auth));
10975
10976 /* set auth */
10977 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
10978 if (err < 0) {
10979 WL_ERR(("auth error %d\n", err));
10980 return BCME_ERROR;
10981 }
10982 /* set wsec */
10983 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
10984 if (err < 0) {
10985 WL_ERR(("wsec error %d\n", err));
10986 return BCME_ERROR;
10987 }
10988 /* set upper-layer auth */
10989 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
10990 if (err < 0) {
10991 WL_ERR(("wpa_auth error %d\n", err));
10992 return BCME_ERROR;
10993 }
10994 exit:
10995 return 0;
10996 }
10997 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
10998
wl_cfg80211_bcn_validate_sec(struct net_device * dev,struct parsed_ies * ies,u32 dev_role,s32 bssidx,bool privacy)10999 static s32 wl_cfg80211_bcn_validate_sec(struct net_device *dev,
11000 struct parsed_ies *ies, u32 dev_role,
11001 s32 bssidx, bool privacy)
11002 {
11003 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11004 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
11005
11006 if (!bss) {
11007 WL_ERR(("cfgbss is NULL \n"));
11008 return BCME_ERROR;
11009 }
11010
11011 if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
11012 /* For P2P GO, the sec type is WPA2-PSK */
11013 WL_DBG(("P2P GO: validating wpa2_ie"));
11014 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0) {
11015 return BCME_ERROR;
11016 }
11017 } else if (dev_role == NL80211_IFTYPE_AP) {
11018 WL_DBG(("SoftAP: validating security"));
11019 /* If wpa2_ie or wpa_ie is present validate it */
11020
11021 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11022 if ((ies->wpa_ie != NULL && ies->wpa2_ie != NULL)) {
11023 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie, ies->wpa2_ie,
11024 bssidx) < 0) {
11025 bss->security_mode = false;
11026 return BCME_ERROR;
11027 }
11028 } else {
11029 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11030 if ((ies->wpa2_ie || ies->wpa_ie) &&
11031 ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
11032 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
11033 bss->security_mode = false;
11034 return BCME_ERROR;
11035 }
11036
11037 if (ies->fils_ind_ie &&
11038 (wl_validate_fils_ind_ie(dev, ies->fils_ind_ie, bssidx) < 0)) {
11039 bss->security_mode = false;
11040 return BCME_ERROR;
11041 }
11042
11043 bss->security_mode = true;
11044 if (bss->rsn_ie) {
11045 MFREE(cfg->osh, bss->rsn_ie,
11046 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11047 bss->rsn_ie = NULL;
11048 }
11049 if (bss->wpa_ie) {
11050 MFREE(cfg->osh, bss->wpa_ie,
11051 bss->wpa_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11052 bss->wpa_ie = NULL;
11053 }
11054 if (bss->wps_ie) {
11055 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 0x2);
11056 bss->wps_ie = NULL;
11057 }
11058 if (bss->fils_ind_ie) {
11059 MFREE(cfg->osh, bss->fils_ind_ie,
11060 bss->fils_ind_ie[1] + FILS_INDICATION_IE_TAG_FIXED_LEN);
11061 bss->fils_ind_ie = NULL;
11062 }
11063 if (ies->wpa_ie != NULL) {
11064 /* WPAIE */
11065 bss->rsn_ie = NULL;
11066 bss->wpa_ie = MALLOCZ(cfg->osh, ies->wpa_ie->length +
11067 WPA_RSN_IE_TAG_FIXED_LEN);
11068 if (bss->wpa_ie) {
11069 memcpy(bss->wpa_ie, ies->wpa_ie,
11070 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11071 }
11072 } else if (ies->wpa2_ie != NULL) {
11073 /* RSNIE */
11074 bss->wpa_ie = NULL;
11075 bss->rsn_ie = MALLOCZ(cfg->osh, ies->wpa2_ie->len +
11076 WPA_RSN_IE_TAG_FIXED_LEN);
11077 if (bss->rsn_ie) {
11078 memcpy(bss->rsn_ie, ies->wpa2_ie,
11079 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11080 }
11081 }
11082 #ifdef WL_FILS
11083 if (ies->fils_ind_ie) {
11084 bss->fils_ind_ie =
11085 MALLOCZ(cfg->osh, ies->fils_ind_ie->len +
11086 FILS_INDICATION_IE_TAG_FIXED_LEN);
11087 if (bss->fils_ind_ie) {
11088 memcpy(bss->fils_ind_ie, ies->fils_ind_ie,
11089 ies->fils_ind_ie->len +
11090 FILS_INDICATION_IE_TAG_FIXED_LEN);
11091 }
11092 }
11093 #endif /* WL_FILS */
11094 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11095 }
11096 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11097 if (!ies->wpa2_ie && !ies->wpa_ie) {
11098 wl_validate_opensecurity(dev, bssidx, privacy);
11099 bss->security_mode = false;
11100 }
11101
11102 if (ies->wps_ie) {
11103 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11104 if (bss->wps_ie) {
11105 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11106 }
11107 }
11108 }
11109
11110 return 0;
11111 }
11112
11113 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
11114 defined(WL_COMPAT_WIRELESS)
wl_cfg80211_bcn_set_params(struct cfg80211_ap_settings * info,struct net_device * dev,u32 dev_role,s32 bssidx)11115 static s32 wl_cfg80211_bcn_set_params(struct cfg80211_ap_settings *info,
11116 struct net_device *dev, u32 dev_role,
11117 s32 bssidx)
11118 {
11119 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11120 s32 err = BCME_OK;
11121
11122 WL_DBG(("interval (%d) dtim_period (%d) \n", info->beacon_interval,
11123 info->dtim_period));
11124
11125 if (info->beacon_interval) {
11126 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD, &info->beacon_interval,
11127 sizeof(s32))) < 0) {
11128 WL_ERR(("Beacon Interval Set Error, %d\n", err));
11129 return err;
11130 }
11131 }
11132
11133 if (info->dtim_period) {
11134 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD, &info->dtim_period,
11135 sizeof(s32))) < 0) {
11136 WL_ERR(("DTIM Interval Set Error, %d\n", err));
11137 return err;
11138 }
11139 }
11140
11141 if ((info->ssid) && (info->ssid_len > 0) &&
11142 (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
11143 WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
11144 if (dev_role == NL80211_IFTYPE_AP) {
11145 /* Store the hostapd SSID */
11146 bzero(cfg->hostapd_ssid.SSID, DOT11_MAX_SSID_LEN);
11147 memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
11148 cfg->hostapd_ssid.SSID_len = (uint32)info->ssid_len;
11149 } else {
11150 /* P2P GO */
11151 bzero(cfg->p2p->ssid.SSID, DOT11_MAX_SSID_LEN);
11152 memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
11153 cfg->p2p->ssid.SSID_len = (uint32)info->ssid_len;
11154 }
11155 }
11156
11157 return err;
11158 }
11159 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11160
wl_cfg80211_parse_ies(const u8 * ptr,u32 len,struct parsed_ies * ies)11161 static s32 wl_cfg80211_parse_ies(const u8 *ptr, u32 len, struct parsed_ies *ies)
11162 {
11163 s32 err = BCME_OK;
11164
11165 bzero(ies, sizeof(struct parsed_ies));
11166
11167 /* find the WPSIE */
11168 if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
11169 WL_DBG(("WPSIE in beacon \n"));
11170 ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
11171 } else {
11172 WL_DBG(("No WPSIE in beacon \n"));
11173 }
11174
11175 /* find the RSN_IE */
11176 if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len, DOT11_MNG_RSN_ID)) != NULL) {
11177 WL_DBG((" WPA2 IE found\n"));
11178 ies->wpa2_ie_len = ies->wpa2_ie->len;
11179 }
11180
11181 /* find the FILS_IND_IE */
11182 if ((ies->fils_ind_ie = bcm_parse_tlvs(ptr, len, DOT11_MNG_FILS_IND_ID)) !=
11183 NULL) {
11184 WL_DBG((" FILS IND IE found\n"));
11185 ies->fils_ind_ie_len = ies->fils_ind_ie->len;
11186 }
11187
11188 /* find the WPA_IE */
11189 if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
11190 WL_DBG((" WPA found\n"));
11191 ies->wpa_ie_len = ies->wpa_ie->length;
11192 }
11193
11194 return err;
11195 }
11196
wl_cfg80211_set_ap_role(struct bcm_cfg80211 * cfg,struct net_device * dev)11197 static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg,
11198 struct net_device *dev)
11199 {
11200 s32 err = BCME_OK;
11201 s32 infra = 1;
11202 s32 ap = 0;
11203 s32 pm;
11204 s32 bssidx;
11205 s32 apsta = 0;
11206 bool new_chip;
11207 #ifdef WLEASYMESH
11208 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11209 #endif /* WLEASYMESH */
11210
11211 new_chip = wl_new_chip_check(dev);
11212
11213 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11214 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11215 return -EINVAL;
11216 }
11217
11218 WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n", dev->name, bssidx));
11219
11220 if (bssidx != 0 || new_chip) {
11221 if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx, WL_IF_TYPE_AP, 0,
11222 NULL)) < 0) {
11223 WL_ERR(("wl add_del_bss returned error:%d\n", err));
11224 return err;
11225 }
11226 }
11227
11228 /*
11229 * For older chips, "bss" iovar does not support
11230 * bsscfg role change/upgradation, and still
11231 * return BCME_OK on attempt
11232 * Hence, below traditional way to handle the same
11233 */
11234
11235 if ((err = wldev_ioctl_get(dev, WLC_GET_AP, &ap, sizeof(s32))) < 0) {
11236 WL_ERR(("Getting AP mode failed %d \n", err));
11237 return err;
11238 }
11239 #ifdef WLEASYMESH
11240 else if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
11241 WL_MSG(dev->name, "Getting AP mode ok, set map and dwds");
11242 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11243 if (err < 0) {
11244 WL_ERR(("WLC_DOWN error %d\n", err));
11245 return err;
11246 }
11247 // For FrontHaulAP
11248 err = wldev_iovar_setint(dev, "map", 0x2);
11249 if (err < 0) {
11250 WL_ERR(("wl map 2 error %d\n", err));
11251 return err;
11252 }
11253 err = wldev_iovar_setint(dev, "dwds", 1);
11254 if (err < 0) {
11255 WL_ERR(("wl dwds 1 error %d\n", err));
11256 return err;
11257 }
11258 WL_MSG(dev->name, "Get AP %d", (int)ap);
11259 }
11260 #endif /* WLEASYMESH */
11261
11262 if (!ap) {
11263 /* AP mode switch not supported. Try setting up AP explicitly */
11264 err = wldev_iovar_getint(dev, "apsta", (s32 *)&apsta);
11265 if (unlikely(err)) {
11266 WL_ERR(("Could not get apsta %d\n", err));
11267 return err;
11268 }
11269 if (apsta == 0) {
11270 /* If apsta is not set, set it */
11271
11272 /* Check for any connected interfaces before wl down */
11273 if (wl_get_drv_status_all(cfg, CONNECTED) > 0) {
11274 #ifdef WLEASYMESH
11275 if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
11276 WL_MSG(dev->name, "do wl down");
11277 } else {
11278 #endif /* WLEASYMESH */
11279 WL_ERR(("Concurrent i/f operational. can't do wl down"));
11280 return BCME_ERROR;
11281 #ifdef WLEASYMESH
11282 }
11283 #endif /* WLEASYMESH */
11284 }
11285 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11286 if (err < 0) {
11287 WL_ERR(("WLC_DOWN error %d\n", err));
11288 return err;
11289 }
11290 #ifdef WLEASYMESH
11291 if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
11292 err = wldev_iovar_setint(dev, "apsta", 1);
11293 } else
11294 #endif /* WLEASYMESH */
11295 err = wldev_iovar_setint(dev, "apsta", 0);
11296 if (err < 0) {
11297 WL_ERR(("wl apsta 0 error %d\n", err));
11298 return err;
11299 }
11300 ap = 1;
11301 if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) <
11302 0) {
11303 WL_ERR(("setting AP mode failed %d \n", err));
11304 return err;
11305 }
11306 #ifdef WLEASYMESH
11307 // For FrontHaulAP
11308 if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
11309 WL_MSG(dev->name, "wl map 2");
11310 err = wldev_iovar_setint(dev, "map", 2);
11311 if (err < 0) {
11312 WL_ERR(("wl map 2 error %d\n", err));
11313 return err;
11314 }
11315 err = wldev_iovar_setint(dev, "dwds", 1);
11316 if (err < 0) {
11317 WL_ERR(("wl dwds 1 error %d\n", err));
11318 return err;
11319 }
11320 }
11321 #endif /* WLEASYMESH */
11322 }
11323 } else if (bssidx == 0 && !new_chip
11324 #ifdef WL_EXT_IAPSTA
11325 && !wl_ext_iapsta_other_if_enabled(dev)
11326 #endif
11327 ) {
11328 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11329 if (err < 0) {
11330 WL_ERR(("WLC_DOWN error %d\n", err));
11331 return err;
11332 }
11333 err = wldev_iovar_setint(dev, "apsta", 0);
11334 if (err < 0) {
11335 WL_ERR(("wl apsta 0 error %d\n", err));
11336 return err;
11337 }
11338 ap = 1;
11339 if ((err = wldev_ioctl_set(dev, WLC_SET_AP, &ap, sizeof(s32))) < 0) {
11340 WL_ERR(("setting AP mode failed %d \n", err));
11341 return err;
11342 }
11343 }
11344
11345 if (bssidx == 0) {
11346 pm = 0;
11347 if ((err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm))) != 0) {
11348 WL_ERR(("wl PM 0 returned error:%d\n", err));
11349 /* Ignore error, if any */
11350 err = BCME_OK;
11351 }
11352 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11353 if (err < 0) {
11354 WL_ERR(("SET INFRA error %d\n", err));
11355 return err;
11356 }
11357 }
11358
11359 /* On success, mark AP creation in progress. */
11360 wl_set_drv_status(cfg, AP_CREATING, dev);
11361 return 0;
11362 }
11363
11364 /* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
11365 #define MAX_AP_LINK_WAIT_TIME 10000
wl_cfg80211_bcn_bringup_ap(struct net_device * dev,struct parsed_ies * ies,u32 dev_role,s32 bssidx)11366 static s32 wl_cfg80211_bcn_bringup_ap(struct net_device *dev,
11367 struct parsed_ies *ies, u32 dev_role,
11368 s32 bssidx)
11369 {
11370 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11371 struct wl_join_params join_params;
11372 bool is_bssup = false;
11373 s32 infra = 1;
11374 s32 join_params_size = 0;
11375 s32 ap = 1;
11376 s32 wsec;
11377 #ifdef DISABLE_11H_SOFTAP
11378 s32 spect = 0;
11379 #endif /* DISABLE_11H_SOFTAP */
11380 #ifdef SOFTAP_UAPSD_OFF
11381 uint32 wme_apsd = 0;
11382 #endif /* SOFTAP_UAPSD_OFF */
11383 s32 err = BCME_OK;
11384 s32 is_rsdb_supported = BCME_ERROR;
11385 long timeout;
11386 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11387 char sec[32];
11388
11389 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
11390 if (is_rsdb_supported < 0) {
11391 return (-ENODEV);
11392 }
11393
11394 WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role, bssidx,
11395 dev->name));
11396
11397 /* Common code for SoftAP and P2P GO */
11398 wl_clr_drv_status(cfg, AP_CREATED, dev);
11399
11400 /* Make sure INFRA is set for AP/GO */
11401 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11402 if (err < 0) {
11403 WL_ERR(("SET INFRA error %d\n", err));
11404 goto exit;
11405 }
11406
11407 /* Do abort scan before creating GO */
11408 wl_cfg80211_scan_abort(cfg);
11409
11410 if (dev_role == NL80211_IFTYPE_P2P_GO) {
11411 wl_ext_get_sec(dev, 0, sec, sizeof(sec), TRUE);
11412 WL_MSG(dev->name, "Creating GO with sec=%s\n", sec);
11413 is_bssup = wl_cfg80211_bss_isup(dev, bssidx);
11414 if (!is_bssup && (ies->wpa2_ie != NULL)) {
11415 err = wldev_iovar_setbuf_bsscfg(
11416 dev, "ssid", &cfg->p2p->ssid, sizeof(cfg->p2p->ssid),
11417 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
11418 if (err < 0) {
11419 WL_ERR(("GO SSID setting error %d\n", err));
11420 goto exit;
11421 }
11422
11423 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
11424 WL_ERR(("GO Bring up error %d\n", err));
11425 goto exit;
11426 }
11427 } else {
11428 WL_DBG(("Bss is already up\n"));
11429 }
11430 } else if (dev_role == NL80211_IFTYPE_AP) {
11431 /* Make sure fw is in proper state */
11432 err = wl_cfg80211_set_ap_role(cfg, dev);
11433 if (unlikely(err)) {
11434 WL_ERR(("set ap role failed!\n"));
11435 goto exit;
11436 }
11437 // }
11438
11439 /* Device role SoftAP */
11440 WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
11441 /* Clear the status bit after use */
11442 wl_clr_drv_status(cfg, AP_CREATING, dev);
11443
11444 #ifdef DISABLE_11H_SOFTAP
11445 if (is_rsdb_supported == 0) {
11446 err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11447 if (err < 0) {
11448 WL_ERR(("WLC_DOWN error %d\n", err));
11449 goto exit;
11450 }
11451 }
11452 err =
11453 wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(s32));
11454 if (err < 0) {
11455 WL_ERR(("SET SPECT_MANAGMENT error %d\n", err));
11456 goto exit;
11457 }
11458 #endif /* DISABLE_11H_SOFTAP */
11459
11460 #ifdef WL_DISABLE_HE_SOFTAP
11461 err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, FALSE);
11462 if (err < 0) {
11463 WL_ERR(("failed to set he features, error=%d\n", err));
11464 }
11465 #endif /* WL_DISABLE_HE_SOFTAP */
11466
11467 #ifdef SOFTAP_UAPSD_OFF
11468 err = wldev_iovar_setbuf_bsscfg(
11469 dev, "wme_apsd", &wme_apsd, sizeof(wme_apsd), cfg->ioctl_buf,
11470 WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11471 if (err < 0) {
11472 WL_ERR(("failed to disable uapsd, error=%d\n", err));
11473 }
11474 #endif /* SOFTAP_UAPSD_OFF */
11475
11476 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
11477 if (unlikely(err)) {
11478 WL_ERR(("WLC_UP error (%d)\n", err));
11479 goto exit;
11480 }
11481
11482 #ifdef MFP
11483 if (cfg->bip_pos) {
11484 err = wldev_iovar_setbuf_bsscfg(
11485 dev, "bip", (const void *)(cfg->bip_pos), WPA_SUITE_LEN,
11486 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11487 if (err < 0) {
11488 WL_ERR(("bip set error %d\n", err));
11489 {
11490 goto exit;
11491 }
11492 }
11493 }
11494 #endif /* MFP */
11495
11496 err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec);
11497 if (unlikely(err)) {
11498 WL_ERR(("Could not get wsec %d\n", err));
11499 goto exit;
11500 }
11501 if (dhdp->conf->chip == BCM43430_CHIP_ID && bssidx > 0 &&
11502 (wsec & (TKIP_ENABLED | AES_ENABLED))) {
11503 wsec |=
11504 WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround
11505 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
11506 if (err < 0) {
11507 WL_ERR(("wsec error %d\n", err));
11508 goto exit;
11509 }
11510 }
11511 if ((wsec == WEP_ENABLED) && cfg->wep_key.len) {
11512 WL_DBG(("Applying buffered WEP KEY \n"));
11513 err = wldev_iovar_setbuf_bsscfg(
11514 dev, "wsec_key", &cfg->wep_key, sizeof(struct wl_wsec_key),
11515 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
11516 /* clear the key after use */
11517 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
11518 if (unlikely(err)) {
11519 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
11520 goto exit;
11521 }
11522 }
11523
11524 #ifdef MFP
11525 if (cfg->mfp_mode) {
11526 /* This needs to go after wsec otherwise the wsec command will
11527 * overwrite the values set by MFP
11528 */
11529 err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx);
11530 if (err < 0) {
11531 WL_ERR(("MFP Setting failed. ret = %d \n", err));
11532 /* If fw doesn't support mfp, Ignore the error */
11533 if (err != BCME_UNSUPPORTED) {
11534 goto exit;
11535 }
11536 }
11537 }
11538 #endif /* MFP */
11539
11540 bzero(&join_params, sizeof(join_params));
11541 /* join parameters starts with ssid */
11542 join_params_size = sizeof(join_params.ssid);
11543 join_params.ssid.SSID_len =
11544 MIN(cfg->hostapd_ssid.SSID_len, (uint32)DOT11_MAX_SSID_LEN);
11545 memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
11546 join_params.ssid.SSID_len);
11547 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
11548
11549 wl_ext_get_sec(dev, 0, sec, sizeof(sec), TRUE);
11550 WL_MSG(dev->name, "Creating AP with sec=%s\n", sec);
11551 /* create softap */
11552 if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
11553 join_params_size)) != 0) {
11554 WL_ERR(("SoftAP/GO set ssid failed! \n"));
11555 goto exit;
11556 } else {
11557 WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
11558 }
11559
11560 if (bssidx != 0) {
11561 /* AP on Virtual Interface */
11562 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
11563 WL_ERR(("AP Bring up error %d\n", err));
11564 goto exit;
11565 }
11566 }
11567 } else {
11568 WL_ERR(("Wrong interface type %d\n", dev_role));
11569 goto exit;
11570 }
11571
11572 /* Wait for Linkup event to mark successful AP/GO bring up */
11573 timeout = wait_event_interruptible_timeout(
11574 cfg->netif_change_event, wl_get_drv_status(cfg, AP_CREATED, dev),
11575 msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
11576 if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) {
11577 WL_ERR((
11578 "Link up didn't come for AP interface. AP/GO creation failed! \n"));
11579 if (timeout == -ERESTARTSYS) {
11580 WL_ERR(("waitqueue was interrupted by a signal, returns "
11581 "-ERESTARTSYS\n"));
11582 err = -ERESTARTSYS;
11583 goto exit;
11584 }
11585 if (dhd_query_bus_erros(dhdp)) {
11586 err = -ENODEV;
11587 goto exit;
11588 }
11589 dhdp->iface_op_failed = TRUE;
11590 #if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
11591 if (dhdp->memdump_enabled) {
11592 dhdp->memdump_type = DUMP_TYPE_AP_LINKUP_FAILURE;
11593 dhd_bus_mem_dump(dhdp);
11594 }
11595 #endif /* DHD_DEBUG && DHD_FW_COREDUMP */
11596 err = -ENODEV;
11597 goto exit;
11598 }
11599 SUPP_LOG(("AP/GO Link up\n"));
11600
11601 exit:
11602 if (cfg->wep_key.len) {
11603 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
11604 }
11605
11606 #ifdef MFP
11607 if (cfg->mfp_mode) {
11608 cfg->mfp_mode = 0;
11609 }
11610
11611 if (cfg->bip_pos) {
11612 cfg->bip_pos = NULL;
11613 }
11614 #endif /* MFP */
11615
11616 if (err) {
11617 SUPP_LOG(("AP/GO bring up fail. err:%d\n", err));
11618 }
11619 return err;
11620 }
11621
11622 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
11623 defined(WL_COMPAT_WIRELESS)
wl_cfg80211_parse_ap_ies(struct net_device * dev,struct cfg80211_beacon_data * info,struct parsed_ies * ies)11624 s32 wl_cfg80211_parse_ap_ies(struct net_device *dev,
11625 struct cfg80211_beacon_data *info,
11626 struct parsed_ies *ies)
11627 {
11628 struct parsed_ies prb_ies;
11629 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11630 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11631 const u8 *vndr = NULL;
11632 u32 vndr_ie_len = 0;
11633 s32 err = BCME_OK;
11634
11635 /* Parse Beacon IEs */
11636 if (wl_cfg80211_parse_ies((const u8 *)info->tail, info->tail_len, ies) <
11637 0) {
11638 WL_ERR(("Beacon get IEs failed \n"));
11639 err = -EINVAL;
11640 goto fail;
11641 }
11642
11643 /* Find the RSNXE_IE and plumb */
11644 err = wl_cfg80211_config_rsnxe_ie(dev, (const u8 *)info->tail,
11645 info->tail_len);
11646 if (unlikely(err)) {
11647 goto fail;
11648 }
11649
11650 vndr = (const u8 *)info->proberesp_ies;
11651 vndr_ie_len = (uint32)info->proberesp_ies_len;
11652
11653 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
11654 /* SoftAP mode */
11655 const struct ieee80211_mgmt *mgmt;
11656 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
11657 if (mgmt != NULL) {
11658 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
11659 vndr_ie_len = (uint32)(info->probe_resp_len -
11660 offsetof(const struct ieee80211_mgmt,
11661 u.probe_resp.variable));
11662 }
11663 }
11664 /* Parse Probe Response IEs */
11665 if (wl_cfg80211_parse_ies((const u8 *)vndr, vndr_ie_len, &prb_ies) < 0) {
11666 WL_ERR(("PROBE RESP get IEs failed \n"));
11667 err = -EINVAL;
11668 }
11669 fail:
11670
11671 return err;
11672 }
11673
wl_cfg80211_set_ies(struct net_device * dev,struct cfg80211_beacon_data * info,s32 bssidx)11674 s32 wl_cfg80211_set_ies(struct net_device *dev,
11675 struct cfg80211_beacon_data *info, s32 bssidx)
11676 {
11677 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11678 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
11679 const u8 *vndr = NULL;
11680 u32 vndr_ie_len = 0;
11681 s32 err = BCME_OK;
11682
11683 /* Set Beacon IEs to FW */
11684 if ((err = wl_cfg80211_set_mgmt_vndr_ies(
11685 cfg, ndev_to_cfgdev(dev), bssidx, VNDR_IE_BEACON_FLAG,
11686 (const u8 *)info->tail, info->tail_len)) < 0) {
11687 WL_ERR(("Set Beacon IE Failed \n"));
11688 } else {
11689 WL_DBG(("Applied Vndr IEs for Beacon \n"));
11690 }
11691
11692 vndr = (const u8 *)info->proberesp_ies;
11693 vndr_ie_len = (uint32)info->proberesp_ies_len;
11694
11695 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
11696 /* SoftAP mode */
11697 const struct ieee80211_mgmt *mgmt;
11698 mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
11699 if (mgmt != NULL) {
11700 vndr = (const u8 *)&mgmt->u.probe_resp.variable;
11701 vndr_ie_len = (uint32)(info->probe_resp_len -
11702 offsetof(struct ieee80211_mgmt,
11703 u.probe_resp.variable));
11704 }
11705 }
11706
11707 /* Set Probe Response IEs to FW */
11708 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
11709 VNDR_IE_PRBRSP_FLAG, vndr,
11710 vndr_ie_len)) < 0) {
11711 WL_ERR(("Set Probe Resp IE Failed \n"));
11712 } else {
11713 WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
11714 }
11715
11716 return err;
11717 }
11718 #endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
11719
wl_cfg80211_hostapd_sec(struct net_device * dev,struct parsed_ies * ies,s32 bssidx)11720 static s32 wl_cfg80211_hostapd_sec(struct net_device *dev,
11721 struct parsed_ies *ies, s32 bssidx)
11722 {
11723 bool update_bss = 0;
11724 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11725 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
11726
11727 if (!bss) {
11728 WL_ERR(("cfgbss is NULL \n"));
11729 return -EINVAL;
11730 }
11731
11732 if (ies->wps_ie) {
11733 if (bss->wps_ie && memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
11734 WL_DBG((" WPS IE is changed\n"));
11735 MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 0x2);
11736 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11737 if (bss->wps_ie) {
11738 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11739 }
11740 } else if (bss->wps_ie == NULL) {
11741 WL_DBG((" WPS IE is added\n"));
11742 bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11743 if (bss->wps_ie) {
11744 memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11745 }
11746 }
11747
11748 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11749 if (ies->wpa_ie != NULL && ies->wpa2_ie != NULL) {
11750 WL_ERR(("update bss - wpa_ie and wpa2_ie is not null\n"));
11751 if (!bss->security_mode) {
11752 /* change from open mode to security mode */
11753 update_bss = true;
11754 bss->wpa_ie = MALLOCZ(cfg->osh, ies->wpa_ie->length +
11755 WPA_RSN_IE_TAG_FIXED_LEN);
11756 if (bss->wpa_ie) {
11757 memcpy(bss->wpa_ie, ies->wpa_ie,
11758 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11759 }
11760 bss->rsn_ie = MALLOCZ(cfg->osh, ies->wpa2_ie->len +
11761 WPA_RSN_IE_TAG_FIXED_LEN);
11762 if (bss->rsn_ie) {
11763 memcpy(bss->rsn_ie, ies->wpa2_ie,
11764 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11765 }
11766 } else {
11767 /* change from (WPA or WPA2 or WPA/WPA2) to WPA/WPA2 mixed mode
11768 */
11769 if (bss->wpa_ie) {
11770 if (memcmp(bss->wpa_ie, ies->wpa_ie,
11771 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN)) {
11772 MFREE(cfg->osh, bss->wpa_ie,
11773 bss->wpa_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11774 update_bss = true;
11775 bss->wpa_ie =
11776 MALLOCZ(cfg->osh, ies->wpa_ie->length +
11777 WPA_RSN_IE_TAG_FIXED_LEN);
11778 if (bss->wpa_ie) {
11779 memcpy(bss->wpa_ie, ies->wpa_ie,
11780 ies->wpa_ie->length +
11781 WPA_RSN_IE_TAG_FIXED_LEN);
11782 }
11783 }
11784 } else {
11785 update_bss = true;
11786 bss->wpa_ie =
11787 MALLOCZ(cfg->osh,
11788 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11789 if (bss->wpa_ie) {
11790 memcpy(bss->wpa_ie, ies->wpa_ie,
11791 ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
11792 }
11793 }
11794 if (bss->rsn_ie) {
11795 if (memcmp(bss->rsn_ie, ies->wpa2_ie,
11796 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
11797 update_bss = true;
11798 MFREE(cfg->osh, bss->rsn_ie,
11799 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11800 bss->rsn_ie =
11801 MALLOCZ(cfg->osh, ies->wpa2_ie->len +
11802 WPA_RSN_IE_TAG_FIXED_LEN);
11803 if (bss->rsn_ie) {
11804 memcpy(bss->rsn_ie, ies->wpa2_ie,
11805 ies->wpa2_ie->len +
11806 WPA_RSN_IE_TAG_FIXED_LEN);
11807 }
11808 }
11809 } else {
11810 update_bss = true;
11811 bss->rsn_ie = MALLOCZ(
11812 cfg->osh, ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11813 if (bss->rsn_ie) {
11814 memcpy(bss->rsn_ie, ies->wpa2_ie,
11815 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
11816 }
11817 }
11818 }
11819 WL_ERR(("update_bss=%d\n", update_bss));
11820 if (update_bss) {
11821 bss->security_mode = true;
11822 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11823 if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie, ies->wpa2_ie,
11824 bssidx) < 0) {
11825 return BCME_ERROR;
11826 }
11827 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11828 }
11829 } else
11830 #endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
11831 if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
11832 if (!bss->security_mode) {
11833 /* change from open mode to security mode */
11834 update_bss = true;
11835 if (ies->wpa_ie != NULL) {
11836 bss->wpa_ie =
11837 MALLOCZ(cfg->osh, ies->wpa_ie->length +
11838 WPA_RSN_IE_TAG_FIXED_LEN);
11839 if (bss->wpa_ie) {
11840 memcpy(bss->wpa_ie, ies->wpa_ie,
11841 ies->wpa_ie->length +
11842 WPA_RSN_IE_TAG_FIXED_LEN);
11843 }
11844 } else {
11845 bss->rsn_ie =
11846 MALLOCZ(cfg->osh, ies->wpa2_ie->len +
11847 WPA_RSN_IE_TAG_FIXED_LEN);
11848 if (bss->rsn_ie) {
11849 memcpy(bss->rsn_ie, ies->wpa2_ie,
11850 ies->wpa2_ie->len +
11851 WPA_RSN_IE_TAG_FIXED_LEN);
11852 }
11853 }
11854 } else if (bss->wpa_ie) {
11855 /* change from WPA2 mode to WPA mode */
11856 if (ies->wpa_ie != NULL) {
11857 update_bss = true;
11858 MFREE(cfg->osh, bss->rsn_ie,
11859 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11860 bss->rsn_ie = NULL;
11861 bss->wpa_ie =
11862 MALLOCZ(cfg->osh, ies->wpa_ie->length +
11863 WPA_RSN_IE_TAG_FIXED_LEN);
11864 if (bss->wpa_ie) {
11865 memcpy(bss->wpa_ie, ies->wpa_ie,
11866 ies->wpa_ie->length +
11867 WPA_RSN_IE_TAG_FIXED_LEN);
11868 }
11869 } else if (memcmp(bss->rsn_ie, ies->wpa2_ie,
11870 ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
11871 update_bss = true;
11872 MFREE(cfg->osh, bss->rsn_ie,
11873 bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
11874 bss->rsn_ie =
11875 MALLOCZ(cfg->osh, ies->wpa2_ie->len +
11876 WPA_RSN_IE_TAG_FIXED_LEN);
11877 if (bss->rsn_ie) {
11878 memcpy(bss->rsn_ie, ies->wpa2_ie,
11879 ies->wpa2_ie->len +
11880 WPA_RSN_IE_TAG_FIXED_LEN);
11881 }
11882 bss->wpa_ie = NULL;
11883 }
11884 }
11885 if (update_bss) {
11886 bss->security_mode = true;
11887 wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
11888 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
11889 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
11890 return BCME_ERROR;
11891 }
11892 wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
11893 }
11894 }
11895 } else {
11896 WL_ERR(("No WPSIE in beacon \n"));
11897 }
11898 return 0;
11899 }
11900
11901 static s32
11902 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || \
11903 (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
11904 #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)11905 wl_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
11906 struct station_del_parameters *params)
11907 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
11908 wl_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
11909 const u8 *mac_addr)
11910 #else
11911 wl_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
11912 u8 *mac_addr)
11913 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11914 {
11915 struct net_device *dev;
11916 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
11917 scb_val_t scb_val;
11918 int err;
11919 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * sizeof(struct ether_addr) +
11920 sizeof(uint)] = {0};
11921 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
11922 int num_associated = 0;
11923
11924 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11925 const u8 *mac_addr = params->mac;
11926 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11927 u16 rc = params->reason_code;
11928 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11929 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11930
11931 WL_DBG(("Entry\n"));
11932 if (mac_addr == NULL) {
11933 WL_DBG(("mac_addr is NULL ignore it\n"));
11934 return 0;
11935 }
11936
11937 dev = ndev_to_wlc_ndev(ndev, cfg);
11938
11939 if (p2p_is_on(cfg)) {
11940 /* Suspend P2P discovery search-listen to prevent it from changing the
11941 * channel.
11942 */
11943 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
11944 WL_ERR(("Can not disable discovery mode\n"));
11945 return -EFAULT;
11946 }
11947 }
11948 #ifdef WL_EXT_IAPSTA
11949 err = wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
11950 WL_EXT_STATUS_DELETE_STA, (void *)mac_addr);
11951 if (err) {
11952 return 0;
11953 }
11954 #endif
11955
11956 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
11957 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST, assoc_maclist,
11958 sizeof(mac_buf));
11959 if (err < 0) {
11960 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
11961 } else {
11962 num_associated = assoc_maclist->count;
11963 }
11964
11965 memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
11966 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11967 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11968 if (rc == DOT11_RC_8021X_AUTH_FAIL) {
11969 WL_ERR(("deauth will be sent at F/W\n"));
11970 scb_val.val = DOT11_RC_8021X_AUTH_FAIL;
11971 } else {
11972 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11973 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11974
11975 #ifdef WL_WPS_SYNC
11976 if (wl_wps_session_update(ndev, WPS_STATE_DISCONNECT_CLIENT,
11977 mac_addr) == BCME_UNSUPPORTED) {
11978 /* Ignore disconnect command from upper layer */
11979 WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
11980 } else
11981 #endif /* WL_WPS_SYNC */
11982 {
11983 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
11984 WL_MSG(dev->name, "Disconnect STA : %pM scb_val.val %d\n", mac_addr,
11985 scb_val.val);
11986 /* need to guarantee EAP-Failure send out before deauth */
11987 dhd_wait_pend8021x(dev);
11988 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
11989 &scb_val, sizeof(scb_val_t));
11990 if (err < 0) {
11991 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
11992 }
11993 }
11994 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
11995 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
11996 }
11997 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
11998 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
11999
12000 if (num_associated > 0 && ETHER_ISBCAST(mac_addr)) {
12001 wl_delay(400);
12002 }
12003
12004 return 0;
12005 }
12006
12007 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
wl_cfg80211_change_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)12008 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
12009 struct net_device *dev, const u8 *mac,
12010 struct station_parameters *params)
12011 #else
12012 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
12013 struct net_device *dev, u8 *mac,
12014 struct station_parameters *params)
12015 #endif // endif
12016 {
12017 int err = BCME_OK;
12018 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12019 struct net_device *ndev = ndev_to_wlc_ndev(dev, cfg);
12020
12021 WL_DBG(("SCB_AUTHORIZE mac_addr:" MACDBG " sta_flags_mask:0x%x "
12022 "sta_flags_set:0x%x iface:%s \n",
12023 MAC2STRDBG(mac), params->sta_flags_mask, params->sta_flags_set,
12024 ndev->name));
12025
12026 if ((wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS) &&
12027 !(wl_get_drv_status(cfg, CONNECTED, dev))) {
12028 /* Return error indicating not in connected state */
12029 WL_ERR(("Ignore SCB_AUTHORIZE/DEAUTHORIZE in non connected state\n"));
12030 return -ENOTSUPP;
12031 }
12032
12033 /* Processing only authorize/de-authorize flag for now */
12034 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
12035 WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
12036 return -ENOTSUPP;
12037 }
12038
12039 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
12040 err = wldev_ioctl_set(ndev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN);
12041 if (unlikely(err)) {
12042 WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
12043 } else {
12044 WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG "\n", ndev->name,
12045 MAC2STRDBG(mac)));
12046 }
12047 return err;
12048 }
12049
12050 err = wldev_ioctl_set(ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN);
12051 if (unlikely(err)) {
12052 WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
12053 } else {
12054 WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG "\n", ndev->name,
12055 MAC2STRDBG(mac)));
12056 #ifdef WL_WPS_SYNC
12057 wl_wps_session_update(ndev, WPS_STATE_AUTHORIZE, mac);
12058 #endif /* WL_WPS_SYNC */
12059 }
12060 #ifdef DHD_LOSSLESS_ROAMING
12061 wl_del_roam_timeout(cfg);
12062 #endif // endif
12063
12064 return err;
12065 }
12066 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, \
12067 0)) */
12068
wl_cfg80211_set_scb_timings(struct bcm_cfg80211 * cfg,struct net_device * dev)12069 static s32 wl_cfg80211_set_scb_timings(struct bcm_cfg80211 *cfg,
12070 struct net_device *dev)
12071 {
12072 int err;
12073 u32 ps_pretend;
12074 wl_scb_probe_t scb_probe;
12075 u32 ps_pretend_retries;
12076
12077 bzero(&scb_probe, sizeof(wl_scb_probe_t));
12078 scb_probe.scb_timeout = WL_SCB_TIMEOUT;
12079 scb_probe.scb_activity_time = WL_SCB_ACTIVITY_TIME;
12080 scb_probe.scb_max_probe = WL_SCB_MAX_PROBE;
12081 err = wldev_iovar_setbuf(dev, "scb_probe", (void *)&scb_probe,
12082 sizeof(wl_scb_probe_t), cfg->ioctl_buf,
12083 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
12084 if (unlikely(err)) {
12085 WL_ERR(("set 'scb_probe' failed, error = %d\n", err));
12086 return err;
12087 }
12088
12089 ps_pretend_retries = WL_PSPRETEND_RETRY_LIMIT;
12090 err = wldev_iovar_setint(dev, "pspretend_retry_limit", ps_pretend_retries);
12091 if (unlikely(err)) {
12092 if (err == BCME_UNSUPPORTED) {
12093 /* Ignore error if fw doesn't support the iovar */
12094 WL_DBG(("set 'pspretend_retry_limit %d' failed, error = %d\n",
12095 ps_pretend_retries, err));
12096 } else {
12097 WL_ERR(("set 'pspretend_retry_limit %d' failed, error = %d\n",
12098 ps_pretend_retries, err));
12099 return err;
12100 }
12101 }
12102
12103 ps_pretend = MAX(WL_SCB_MAX_PROBE / 0x2, WL_MIN_PSPRETEND_THRESHOLD);
12104 err = wldev_iovar_setint(dev, "pspretend_threshold", ps_pretend);
12105 if (unlikely(err)) {
12106 if (err == BCME_UNSUPPORTED) {
12107 /* Ignore error if fw doesn't support the iovar */
12108 WL_DBG(
12109 ("wl pspretend_threshold %d set error %d\n", ps_pretend, err));
12110 } else {
12111 WL_ERR(
12112 ("wl pspretend_threshold %d set error %d\n", ps_pretend, err));
12113 return err;
12114 }
12115 }
12116
12117 return 0;
12118 }
12119
12120 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
12121 defined(WL_COMPAT_WIRELESS)
wl_cfg80211_start_ap(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ap_settings * info)12122 static s32 wl_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
12123 struct cfg80211_ap_settings *info)
12124 {
12125 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12126 s32 err = BCME_OK;
12127 struct parsed_ies ies;
12128 s32 bssidx = 0;
12129 u32 dev_role = 0;
12130 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12131
12132 WL_DBG(("Enter \n"));
12133
12134 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12135 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12136 return BCME_ERROR;
12137 }
12138
12139 if (p2p_is_on(cfg) &&
12140 (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
12141 dev_role = NL80211_IFTYPE_P2P_GO;
12142 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12143 dev_role = NL80211_IFTYPE_AP;
12144 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
12145 err = dhd_ndo_enable(dhd, FALSE);
12146 WL_DBG(("Disabling NDO on Hostapd mode %d\n", err));
12147 if (err) {
12148 WL_ERR(("Disabling NDO Failed %d\n", err));
12149 }
12150 wl_wlfc_enable(cfg, TRUE);
12151 #ifdef WL_EXT_IAPSTA
12152 wl_ext_iapsta_update_iftype(dev, dhd_net2idx(dhd->info, dev),
12153 WL_IF_TYPE_AP);
12154 #endif /* WL_EXT_IAPSTA */
12155 #ifdef PKT_FILTER_SUPPORT
12156 /* Disable packet filter */
12157 if (dhd->early_suspended) {
12158 WL_ERR(("Disable pkt_filter\n"));
12159 dhd_enable_packet_filter(0, dhd);
12160 #ifdef APF
12161 dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd));
12162 #endif /* APF */
12163 }
12164 #endif /* PKT_FILTER_SUPPORT */
12165 #ifdef ARP_OFFLOAD_SUPPORT
12166 /* IF SoftAP is enabled, disable arpoe */
12167 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12168 dhd_arp_offload_set(dhd, 0);
12169 dhd_arp_offload_enable(dhd, FALSE);
12170 }
12171 #endif /* ARP_OFFLOAD_SUPPORT */
12172 } else {
12173 /* only AP or GO role need to be handled here. */
12174 err = -EINVAL;
12175 goto fail;
12176 }
12177
12178 /* disable TDLS */
12179 #ifdef WLTDLS
12180 if (bssidx == 0) {
12181 /* Disable TDLS for primary Iface. For virtual interface,
12182 * tdls disable will happen from interface create context
12183 */
12184 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_CREATE, false);
12185 }
12186 #endif /* WLTDLS */
12187
12188 if (!check_dev_role_integrity(cfg, dev_role)) {
12189 err = -EINVAL;
12190 goto fail;
12191 }
12192
12193 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && \
12194 !defined(WL_COMPAT_WIRELESS))
12195 if (!dev->ieee80211_ptr->preset_chandef.chan) {
12196 WL_ERR(("chan is NULL\n"));
12197 err = -EINVAL;
12198 goto fail;
12199 }
12200 if ((err = wl_cfg80211_set_channel(wiphy, dev,
12201 dev->ieee80211_ptr->preset_chandef.chan,
12202 NL80211_CHAN_HT20) < 0)) {
12203 WL_ERR(("Set channel failed \n"));
12204 goto fail;
12205 }
12206 #endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
12207
12208 if ((err = wl_cfg80211_bcn_set_params(info, dev, dev_role, bssidx)) < 0) {
12209 WL_ERR(("Beacon params set failed \n"));
12210 goto fail;
12211 }
12212
12213 /* Parse IEs */
12214 if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) {
12215 WL_ERR(("Set IEs failed \n"));
12216 goto fail;
12217 }
12218
12219 if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx,
12220 info->privacy)) < 0) {
12221 WL_ERR(("Beacon set security failed \n"));
12222 goto fail;
12223 }
12224
12225 if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0) {
12226 WL_ERR(("Beacon bring up AP/GO failed \n"));
12227 goto fail;
12228 }
12229
12230 /* Set GC/STA SCB expiry timings. */
12231 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
12232 WL_ERR(("scb setting failed \n"));
12233 }
12234
12235 wl_set_drv_status(cfg, CONNECTED, dev);
12236 WL_DBG(("** AP/GO Created **\n"));
12237
12238 #ifdef WL_CFG80211_ACL
12239 /* Enfoce Admission Control. */
12240 if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
12241 WL_ERR(("Set ACL failed\n"));
12242 }
12243 #endif /* WL_CFG80211_ACL */
12244
12245 /* Set IEs to FW */
12246 if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0) {
12247 WL_ERR(("Set IEs failed \n"));
12248 }
12249
12250 #ifdef WLDWDS
12251 if (dev->ieee80211_ptr->use_4addr) {
12252 if ((err = wl_cfg80211_set_mgmt_vndr_ies(
12253 cfg, ndev_to_cfgdev(dev), bssidx, VNDR_IE_ASSOCRSP_FLAG,
12254 (const u8 *)info->beacon.assocresp_ies,
12255 info->beacon.assocresp_ies_len)) < 0) {
12256 WL_ERR(("Set ASSOC RESP IE Failed\n"));
12257 }
12258 }
12259 #endif /* WLDWDS */
12260
12261 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12262 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
12263 bool pbc = 0;
12264 wl_validate_wps_ie((const char *)ies.wps_ie, ies.wps_ie_len, &pbc);
12265 if (pbc) {
12266 WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
12267 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12268 }
12269 }
12270
12271 /* Configure hidden SSID */
12272 if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) {
12273 if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0) {
12274 WL_ERR(("failed to set hidden : %d\n", err));
12275 }
12276 WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
12277 }
12278
12279 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12280 if (dev_role == NL80211_IFTYPE_AP) {
12281 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
12282 wl_cfg80211_init_ap_rps(cfg);
12283 } else {
12284 WL_ERR(("Set rpsnoa failed \n"));
12285 }
12286 }
12287 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12288 fail:
12289 if (err) {
12290 WL_ERR(("ADD/SET beacon failed\n"));
12291 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12292 wl_cfg80211_stop_ap(wiphy, dev);
12293 if (dev_role == NL80211_IFTYPE_AP) {
12294 #ifdef WL_EXT_IAPSTA
12295 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12296 #endif /* WL_EXT_IAPSTA */
12297 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12298 #ifdef PKT_FILTER_SUPPORT
12299 /* Enable packet filter */
12300 if (dhd->early_suspended) {
12301 WL_ERR(("Enable pkt_filter\n"));
12302 dhd_enable_packet_filter(1, dhd);
12303 #ifdef APF
12304 dhd_dev_apf_enable_filter(
12305 dhd_linux_get_primary_netdev(dhd));
12306 #endif /* APF */
12307 }
12308 #endif /* PKT_FILTER_SUPPORT */
12309 #ifdef ARP_OFFLOAD_SUPPORT
12310 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
12311 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12312 dhd_arp_offload_set(dhd, dhd_arp_mode);
12313 dhd_arp_offload_enable(dhd, TRUE);
12314 }
12315 #endif /* ARP_OFFLOAD_SUPPORT */
12316 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12317 wl_cfg80211_set_frameburst(cfg, TRUE);
12318 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12319 wl_wlfc_enable(cfg, FALSE);
12320 #ifdef WL_EXT_IAPSTA
12321 }
12322 #endif /* WL_EXT_IAPSTA */
12323 }
12324 #ifdef WLTDLS
12325 if (bssidx == 0) {
12326 /* Since AP creation failed, re-enable TDLS */
12327 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
12328 }
12329 #endif /* WLTDLS */
12330 }
12331
12332 return err;
12333 }
12334
wl_cfg80211_stop_ap(struct wiphy * wiphy,struct net_device * dev)12335 static s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
12336 {
12337 int err = 0;
12338 u32 dev_role = 0;
12339 int ap = 0;
12340 s32 bssidx = 0;
12341 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12342 s32 is_rsdb_supported = BCME_ERROR;
12343 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12344
12345 WL_DBG(("Enter \n"));
12346
12347 if (wl_cfg80211_get_bus_state(cfg)) {
12348 /* since bus is down, iovar will fail. recovery path will bringup the
12349 * bus. */
12350 WL_ERR(("bus is not ready\n"));
12351 return BCME_OK;
12352 }
12353 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
12354 if (is_rsdb_supported < 0) {
12355 return (-ENODEV);
12356 }
12357
12358 wl_clr_drv_status(cfg, AP_CREATING, dev);
12359 wl_clr_drv_status(cfg, AP_CREATED, dev);
12360 cfg->ap_oper_channel = 0;
12361
12362 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12363 dev_role = NL80211_IFTYPE_AP;
12364 WL_MSG(dev->name, "stopping AP operation\n");
12365 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12366 dev_role = NL80211_IFTYPE_P2P_GO;
12367 WL_MSG(dev->name, "stopping P2P GO operation\n");
12368 } else {
12369 WL_ERR(("no AP/P2P GO interface is operational.\n"));
12370 return -EINVAL;
12371 }
12372
12373 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12374 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12375 return BCME_ERROR;
12376 }
12377
12378 if (!check_dev_role_integrity(cfg, dev_role)) {
12379 WL_ERR(("role integrity check failed \n"));
12380 err = -EINVAL;
12381 goto exit;
12382 }
12383
12384 /* Free up resources */
12385 wl_cfg80211_cleanup_if(dev);
12386
12387 /* Clear AP/GO connected status */
12388 wl_clr_drv_status(cfg, CONNECTED, dev);
12389 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
12390 WL_ERR(("bss down error %d\n", err));
12391 }
12392
12393 if (dev_role == NL80211_IFTYPE_AP) {
12394 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12395 wl_cfg80211_set_frameburst(cfg, TRUE);
12396 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12397 #ifdef PKT_FILTER_SUPPORT
12398 /* Enable packet filter */
12399 if (dhd->early_suspended) {
12400 WL_ERR(("Enable pkt_filter\n"));
12401 dhd_enable_packet_filter(1, dhd);
12402 #ifdef APF
12403 dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd));
12404 #endif /* APF */
12405 }
12406 #endif /* PKT_FILTER_SUPPORT */
12407 #ifdef ARP_OFFLOAD_SUPPORT
12408 /* IF SoftAP is disabled, enable arpoe back for STA mode. */
12409 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12410 dhd_arp_offload_set(dhd, dhd_arp_mode);
12411 dhd_arp_offload_enable(dhd, TRUE);
12412 }
12413 #endif /* ARP_OFFLOAD_SUPPORT */
12414
12415 if (is_rsdb_supported == 0) {
12416 /* For non-rsdb chips, we use stand alone AP. Do wl down on stop AP
12417 */
12418 err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
12419 if (unlikely(err)) {
12420 WL_ERR(("WLC_UP error (%d)\n", err));
12421 err = -EINVAL;
12422 goto exit;
12423 }
12424 }
12425
12426 #ifdef WL_DISABLE_HE_SOFTAP
12427 if (wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, TRUE) !=
12428 BCME_OK) {
12429 WL_ERR(("failed to set he features\n"));
12430 }
12431 #endif /* WL_DISABLE_HE_SOFTAP */
12432
12433 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
12434 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12435 if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
12436 wl_cfg80211_init_ap_rps(cfg);
12437 } else {
12438 WL_ERR(("Set rpsnoa failed \n"));
12439 }
12440 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12441 } else {
12442 WL_DBG(("Stopping P2P GO \n"));
12443 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
12444 DHD_EVENT_TIMEOUT_MS * 3);
12445 DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub));
12446 }
12447
12448 SUPP_LOG(("AP/GO Link down\n"));
12449 exit:
12450 if (err) {
12451 /* In case of failure, flush fw logs */
12452 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12453 SUPP_LOG(("AP/GO Link down fail. err:%d\n", err));
12454 }
12455 #ifdef WLTDLS
12456 if (bssidx == 0) {
12457 /* re-enable TDLS if the number of connected interfaces is less than 2
12458 */
12459 wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
12460 }
12461 #endif /* WLTDLS */
12462
12463 if (dev_role == NL80211_IFTYPE_AP) {
12464 #ifdef WL_EXT_IAPSTA
12465 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12466 #endif /* WL_EXT_IAPSTA */
12467 /* clear the AP mode */
12468 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12469 wl_wlfc_enable(cfg, FALSE);
12470 #ifdef WL_EXT_IAPSTA
12471 }
12472 #endif /* WL_EXT_IAPSTA */
12473 }
12474 return err;
12475 }
12476
wl_cfg80211_change_beacon(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_beacon_data * info)12477 static s32 wl_cfg80211_change_beacon(struct wiphy *wiphy,
12478 struct net_device *dev,
12479 struct cfg80211_beacon_data *info)
12480 {
12481 s32 err = BCME_OK;
12482 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12483 struct parsed_ies ies;
12484 u32 dev_role = 0;
12485 s32 bssidx = 0;
12486 bool pbc = 0;
12487
12488 WL_DBG(("Enter \n"));
12489
12490 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12491 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12492 return BCME_ERROR;
12493 }
12494
12495 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12496 dev_role = NL80211_IFTYPE_P2P_GO;
12497 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12498 dev_role = NL80211_IFTYPE_AP;
12499 } else {
12500 err = -EINVAL;
12501 goto fail;
12502 }
12503
12504 if (!check_dev_role_integrity(cfg, dev_role)) {
12505 err = -EINVAL;
12506 goto fail;
12507 }
12508
12509 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
12510 WL_ERR(("P2P already down status!\n"));
12511 err = BCME_ERROR;
12512 goto fail;
12513 }
12514
12515 /* Parse IEs */
12516 if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) {
12517 WL_ERR(("Parse IEs failed \n"));
12518 goto fail;
12519 }
12520
12521 /* Set IEs to FW */
12522 if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
12523 WL_ERR(("Set IEs failed \n"));
12524 goto fail;
12525 }
12526
12527 if (dev_role == NL80211_IFTYPE_AP) {
12528 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
12529 WL_ERR(("Hostapd update sec failed \n"));
12530 err = -EINVAL;
12531 goto fail;
12532 }
12533 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
12534 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
12535 wl_validate_wps_ie((const char *)ies.wps_ie, ies.wps_ie_len, &pbc);
12536 WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
12537 if (pbc) {
12538 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12539 } else {
12540 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
12541 }
12542 }
12543 }
12544
12545 fail:
12546 if (err) {
12547 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12548 }
12549 return err;
12550 }
12551 #else
wl_cfg80211_add_set_beacon(struct wiphy * wiphy,struct net_device * dev,struct beacon_parameters * info)12552 static s32 wl_cfg80211_add_set_beacon(struct wiphy *wiphy,
12553 struct net_device *dev,
12554 struct beacon_parameters *info)
12555 {
12556 s32 err = BCME_OK;
12557 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12558 s32 ie_offset = 0;
12559 s32 bssidx = 0;
12560 u32 dev_role = NL80211_IFTYPE_AP;
12561 struct parsed_ies ies;
12562 bcm_tlv_t *ssid_ie;
12563 bool pbc = 0;
12564 bool privacy;
12565 bool is_bss_up = 0;
12566 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12567
12568 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
12569 info->interval, info->dtim_period, info->head_len, info->tail_len));
12570
12571 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
12572 dev_role = NL80211_IFTYPE_AP;
12573 }
12574 #if defined(WL_ENABLE_P2P_IF)
12575 else if (dev == cfg->p2p_net) {
12576 /* Group Add request on p2p0 */
12577 dev = bcmcfg_to_prmry_ndev(cfg);
12578 dev_role = NL80211_IFTYPE_P2P_GO;
12579 }
12580 #endif /* WL_ENABLE_P2P_IF */
12581
12582 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12583 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12584 return BCME_ERROR;
12585 }
12586
12587 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12588 dev_role = NL80211_IFTYPE_P2P_GO;
12589 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12590 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
12591 }
12592
12593 if (!check_dev_role_integrity(cfg, dev_role)) {
12594 err = -ENODEV;
12595 goto fail;
12596 }
12597
12598 if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
12599 WL_ERR(("P2P already down status!\n"));
12600 err = BCME_ERROR;
12601 goto fail;
12602 }
12603
12604 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
12605 /* find the SSID */
12606 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
12607 info->head_len - ie_offset,
12608 DOT11_MNG_SSID_ID)) != NULL) {
12609 if (dev_role == NL80211_IFTYPE_AP) {
12610 /* Store the hostapd SSID */
12611 bzero(&cfg->hostapd_ssid.SSID[0], DOT11_MAX_SSID_LEN);
12612 cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
12613 memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
12614 cfg->hostapd_ssid.SSID_len);
12615 } else {
12616 /* P2P GO */
12617 bzero(&cfg->p2p->ssid.SSID[0], DOT11_MAX_SSID_LEN);
12618 cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
12619 memcpy(cfg->p2p->ssid.SSID, ssid_ie->data, cfg->p2p->ssid.SSID_len);
12620 }
12621 }
12622
12623 if (wl_cfg80211_parse_ies((u8 *)info->tail, info->tail_len, &ies) < 0) {
12624 WL_ERR(("Beacon get IEs failed \n"));
12625 err = -EINVAL;
12626 goto fail;
12627 }
12628
12629 if ((err = wl_cfg80211_set_mgmt_vndr_ies(
12630 cfg, ndev_to_cfgdev(dev), bssidx, VNDR_IE_BEACON_FLAG,
12631 (u8 *)info->tail, info->tail_len)) < 0) {
12632 WL_ERR(("Beacon set IEs failed \n"));
12633 goto fail;
12634 } else {
12635 WL_DBG(("Applied Vndr IEs for Beacon \n"));
12636 }
12637
12638 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12639 if ((err = wl_cfg80211_set_mgmt_vndr_ies(
12640 cfg, ndev_to_cfgdev(dev), bssidx, VNDR_IE_PRBRSP_FLAG,
12641 (u8 *)info->proberesp_ies, info->proberesp_ies_len)) < 0) {
12642 WL_ERR(("ProbeRsp set IEs failed \n"));
12643 goto fail;
12644 } else {
12645 WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
12646 }
12647 #endif // endif
12648
12649 is_bss_up = wl_cfg80211_bss_isup(dev, bssidx);
12650
12651 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
12652 privacy = info->privacy;
12653 #else
12654 privacy = 0;
12655 #endif // endif
12656 if (!is_bss_up && (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx,
12657 privacy) < 0)) {
12658 WL_ERR(("Beacon set security failed \n"));
12659 err = -EINVAL;
12660 goto fail;
12661 }
12662
12663 /* Set BI and DTIM period */
12664 if (info->interval) {
12665 if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD, &info->interval,
12666 sizeof(s32))) < 0) {
12667 WL_ERR(("Beacon Interval Set Error, %d\n", err));
12668 return err;
12669 }
12670 }
12671 if (info->dtim_period) {
12672 if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD, &info->dtim_period,
12673 sizeof(s32))) < 0) {
12674 WL_ERR(("DTIM Interval Set Error, %d\n", err));
12675 return err;
12676 }
12677 }
12678
12679 /* If bss is already up, skip bring up */
12680 if (!is_bss_up &&
12681 (err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0) {
12682 WL_ERR(("Beacon bring up AP/GO failed \n"));
12683 goto fail;
12684 }
12685
12686 /* Set GC/STA SCB expiry timings. */
12687 if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
12688 WL_ERR(("scb setting failed \n"));
12689 if (err == BCME_UNSUPPORTED) {
12690 err = 0;
12691 }
12692 }
12693
12694 if (wl_get_drv_status(cfg, AP_CREATED, dev)) {
12695 /* Soft AP already running. Update changed params */
12696 if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
12697 WL_ERR(("Hostapd update sec failed \n"));
12698 err = -EINVAL;
12699 goto fail;
12700 }
12701 }
12702
12703 /* Enable Probe Req filter */
12704 if (((dev_role == NL80211_IFTYPE_P2P_GO) ||
12705 (dev_role == NL80211_IFTYPE_AP)) &&
12706 (ies.wps_ie != NULL)) {
12707 wl_validate_wps_ie((char *)ies.wps_ie, ies.wps_ie_len, &pbc);
12708 if (pbc) {
12709 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
12710 }
12711 }
12712
12713 WL_DBG(("** ADD/SET beacon done **\n"));
12714 wl_set_drv_status(cfg, CONNECTED, dev);
12715
12716 fail:
12717 if (err) {
12718 WL_ERR(("ADD/SET beacon failed\n"));
12719 if (dev_role == NL80211_IFTYPE_AP) {
12720 #ifdef WL_EXT_IAPSTA
12721 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12722 #endif /* WL_EXT_IAPSTA */
12723 /* clear the AP mode */
12724 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12725 #ifdef WL_EXT_IAPSTA
12726 }
12727 #endif /* WL_EXT_IAPSTA */
12728 }
12729 }
12730 return err;
12731 }
12732
wl_cfg80211_del_beacon(struct wiphy * wiphy,struct net_device * dev)12733 static s32 wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
12734 {
12735 int err = 0;
12736 s32 bssidx = 0;
12737 int infra = 0;
12738 struct wireless_dev *wdev = dev->ieee80211_ptr;
12739 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12740 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12741
12742 WL_DBG(("Enter. \n"));
12743
12744 if (!wdev) {
12745 WL_ERR(("wdev null \n"));
12746 return -EINVAL;
12747 }
12748
12749 if ((wdev->iftype != NL80211_IFTYPE_P2P_GO) &&
12750 (wdev->iftype != NL80211_IFTYPE_AP)) {
12751 WL_ERR(("Unspported iface type iftype:%d \n", wdev->iftype));
12752 }
12753
12754 wl_clr_drv_status(cfg, AP_CREATING, dev);
12755 wl_clr_drv_status(cfg, AP_CREATED, dev);
12756
12757 /* Clear AP/GO connected status */
12758 wl_clr_drv_status(cfg, CONNECTED, dev);
12759
12760 cfg->ap_oper_channel = 0;
12761
12762 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12763 WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
12764 return BCME_ERROR;
12765 }
12766
12767 /* Do bss down */
12768 if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
12769 WL_ERR(("bss down error %d\n", err));
12770 }
12771
12772 /* fall through is intentional */
12773 err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
12774 if (err < 0) {
12775 WL_ERR(("SET INFRA error %d\n", err));
12776 }
12777 wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
12778
12779 if (wdev->iftype == NL80211_IFTYPE_AP) {
12780 #ifdef WL_EXT_IAPSTA
12781 if (!wl_ext_iapsta_iftype_enabled(dev, WL_IF_TYPE_AP)) {
12782 #endif /* WL_EXT_IAPSTA */
12783 /* clear the AP mode */
12784 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12785 #ifdef WL_EXT_IAPSTA
12786 }
12787 #endif /* WL_EXT_IAPSTA */
12788 }
12789
12790 return 0;
12791 }
12792 #endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
12793
12794 #ifdef WL_SUPPORT_ACS
12795 /*
12796 * Currently the dump_obss IOVAR is returning string as output so we need to
12797 * parse the output buffer in an unoptimized way. Going forward if we get the
12798 * IOVAR output in binary format this method can be optimized
12799 */
wl_parse_dump_obss(char * buf,struct wl_dump_survey * survey)12800 static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
12801 {
12802 int i;
12803 char *token;
12804 char delim[] = " \n";
12805
12806 token = strsep(&buf, delim);
12807 while (token != NULL) {
12808 if (!strcmp(token, "OBSS")) {
12809 for (i = 0; i < OBSS_TOKEN_IDX; i++) {
12810 token = strsep(&buf, delim);
12811 }
12812 survey->obss = simple_strtoul(token, NULL, 10);
12813 }
12814
12815 if (!strcmp(token, "IBSS")) {
12816 for (i = 0; i < IBSS_TOKEN_IDX; i++) {
12817 token = strsep(&buf, delim);
12818 }
12819 survey->ibss = simple_strtoul(token, NULL, 10);
12820 }
12821
12822 if (!strcmp(token, "TXDur")) {
12823 for (i = 0; i < TX_TOKEN_IDX; i++) {
12824 token = strsep(&buf, delim);
12825 }
12826 survey->tx = simple_strtoul(token, NULL, 10);
12827 }
12828
12829 if (!strcmp(token, "Category")) {
12830 for (i = 0; i < CTG_TOKEN_IDX; i++) {
12831 token = strsep(&buf, delim);
12832 }
12833 survey->no_ctg = simple_strtoul(token, NULL, 10);
12834 }
12835
12836 if (!strcmp(token, "Packet")) {
12837 for (i = 0; i < PKT_TOKEN_IDX; i++) {
12838 token = strsep(&buf, delim);
12839 }
12840 survey->no_pckt = simple_strtoul(token, NULL, 10);
12841 }
12842
12843 if (!strcmp(token, "Opp(time):")) {
12844 for (i = 0; i < IDLE_TOKEN_IDX; i++) {
12845 token = strsep(&buf, delim);
12846 }
12847 survey->idle = simple_strtoul(token, NULL, 10);
12848 }
12849
12850 token = strsep(&buf, delim);
12851 }
12852
12853 return 0;
12854 }
12855
wl_dump_obss(struct net_device * ndev,cca_msrmnt_query req,struct wl_dump_survey * survey)12856 static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
12857 struct wl_dump_survey *survey)
12858 {
12859 cca_stats_n_flags *results;
12860 char *buf;
12861 int retry, err;
12862 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
12863
12864 buf = (char *)MALLOCZ(cfg->osh, sizeof(char) * WLC_IOCTL_MAXLEN);
12865 if (unlikely(!buf)) {
12866 WL_ERR(("%s: buf alloc failed\n", __func__));
12867 return -ENOMEM;
12868 }
12869
12870 retry = IOCTL_RETRY_COUNT;
12871 while (retry--) {
12872 err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req), buf,
12873 WLC_IOCTL_MAXLEN, NULL);
12874 if (err >= 0) {
12875 break;
12876 }
12877 WL_DBG(
12878 ("attempt = %d, err = %d, \n", (IOCTL_RETRY_COUNT - retry), err));
12879 }
12880
12881 if (retry <= 0) {
12882 WL_ERR(("failure, dump_obss IOVAR failed\n"));
12883 err = -EINVAL;
12884 goto exit;
12885 }
12886
12887 results = (cca_stats_n_flags *)(buf);
12888 wl_parse_dump_obss(results->buf, survey);
12889 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
12890
12891 return 0;
12892 exit:
12893 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
12894 return err;
12895 }
12896
wl_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * ndev,int idx,struct survey_info * info)12897 static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
12898 int idx, struct survey_info *info)
12899 {
12900 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
12901 struct wl_dump_survey *survey;
12902 struct ieee80211_supported_band *band;
12903 struct ieee80211_channel *chan;
12904 cca_msrmnt_query req;
12905 int val, err, noise, retry;
12906
12907 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12908 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
12909 return -ENOENT;
12910 }
12911 band = wiphy->bands[IEEE80211_BAND_2GHZ];
12912 if (band && idx >= band->n_channels) {
12913 idx -= band->n_channels;
12914 band = NULL;
12915 }
12916
12917 if (!band || idx >= band->n_channels) {
12918 /* Move to 5G band */
12919 band = wiphy->bands[IEEE80211_BAND_5GHZ];
12920 if (idx >= band->n_channels) {
12921 return -ENOENT;
12922 }
12923 }
12924
12925 chan = &band->channels[idx];
12926 /* Setting current channel to the requested channel */
12927 if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan, NL80211_CHAN_HT20) <
12928 0)) {
12929 WL_ERR(("Set channel failed \n"));
12930 }
12931
12932 if (!idx) {
12933 /* Set interface up, explicitly. */
12934 val = 1;
12935 err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
12936 if (err < 0) {
12937 WL_ERR(("set interface up failed, error = %d\n", err));
12938 }
12939 }
12940
12941 /* Get noise value */
12942 retry = IOCTL_RETRY_COUNT;
12943 while (retry--) {
12944 noise = 0;
12945 err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise, sizeof(noise));
12946 if (err >= 0) {
12947 break;
12948 }
12949 WL_DBG(
12950 ("attempt = %d, err = %d, \n", (IOCTL_RETRY_COUNT - retry), err));
12951 }
12952
12953 if (retry <= 0) {
12954 WL_ERR(("Get Phy Noise failed, error = %d\n", err));
12955 noise = CHAN_NOISE_DUMMY;
12956 }
12957
12958 survey = (struct wl_dump_survey *)MALLOCZ(cfg->osh,
12959 sizeof(struct wl_dump_survey));
12960 if (unlikely(!survey)) {
12961 WL_ERR(("%s: alloc failed\n", __func__));
12962 return -ENOMEM;
12963 }
12964
12965 /* Start Measurement for obss stats on current channel */
12966 req.msrmnt_query = 0;
12967 req.time_req = ACS_MSRMNT_DELAY;
12968 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
12969 goto exit;
12970 }
12971
12972 /*
12973 * Wait for the meaurement to complete, adding a buffer value of 10 to take
12974 * into consideration any delay in IOVAR completion
12975 */
12976 msleep(ACS_MSRMNT_DELAY + 0xA);
12977
12978 /* Issue IOVAR to collect measurement results */
12979 req.msrmnt_query = 1;
12980 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
12981 goto exit;
12982 }
12983
12984 info->channel = chan;
12985 info->noise = noise;
12986 info->channel_time = ACS_MSRMNT_DELAY;
12987 info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
12988 info->channel_time_rx =
12989 survey->obss + survey->ibss + survey->no_ctg + survey->no_pckt;
12990 info->channel_time_tx = survey->tx;
12991 info->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_CHANNEL_TIME |
12992 SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
12993 SURVEY_INFO_CHANNEL_TIME_TX;
12994 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
12995
12996 return 0;
12997 exit:
12998 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
12999 return err;
13000 }
13001 #endif /* WL_SUPPORT_ACS */
13002
13003 #ifndef CONFIG_AP6XXX_WIFI6_HDF
13004 static
13005 #endif
13006 struct cfg80211_ops wl_cfg80211_ops = {
13007 .add_virtual_intf = wl_cfg80211_add_virtual_iface,
13008 .del_virtual_intf = wl_cfg80211_del_virtual_iface,
13009 .change_virtual_intf = wl_cfg80211_change_virtual_iface,
13010 #if defined(WL_CFG80211_P2P_DEV_IF)
13011 .start_p2p_device = wl_cfgp2p_start_p2p_device,
13012 .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
13013 #endif /* WL_CFG80211_P2P_DEV_IF */
13014 .scan = wl_cfg80211_scan,
13015 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
13016 .abort_scan = wl_cfg80211_abort_scan,
13017 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
13018 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
13019 .join_ibss = wl_cfg80211_join_ibss,
13020 .leave_ibss = wl_cfg80211_leave_ibss,
13021 .get_station = wl_cfg80211_get_station,
13022 .set_tx_power = wl_cfg80211_set_tx_power,
13023 .get_tx_power = wl_cfg80211_get_tx_power,
13024 .add_key = wl_cfg80211_add_key,
13025 .del_key = wl_cfg80211_del_key,
13026 .get_key = wl_cfg80211_get_key,
13027 .set_default_key = wl_cfg80211_config_default_key,
13028 .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
13029 .set_power_mgmt = wl_cfg80211_set_power_mgmt,
13030 .connect = wl_cfg80211_connect,
13031 .disconnect = wl_cfg80211_disconnect,
13032 .suspend = wl_cfg80211_suspend,
13033 .resume = wl_cfg80211_resume,
13034 .set_pmksa = wl_cfg80211_set_pmksa,
13035 .del_pmksa = wl_cfg80211_del_pmksa,
13036 .flush_pmksa = wl_cfg80211_flush_pmksa,
13037 .remain_on_channel = wl_cfg80211_remain_on_channel,
13038 .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
13039 .mgmt_tx = wl_cfg80211_mgmt_tx,
13040 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
13041 .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
13042 #else
13043 .update_mgmt_frame_registrations = wl_cfg80211_mgmt_frame_register,
13044 #endif
13045 .change_bss = wl_cfg80211_change_bss,
13046 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || \
13047 defined(WL_COMPAT_WIRELESS)
13048 .set_channel = wl_cfg80211_set_channel,
13049 #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
13050 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && \
13051 !defined(WL_COMPAT_WIRELESS)
13052 .set_beacon = wl_cfg80211_add_set_beacon,
13053 .add_beacon = wl_cfg80211_add_set_beacon,
13054 .del_beacon = wl_cfg80211_del_beacon,
13055 #else
13056 .change_beacon = wl_cfg80211_change_beacon,
13057 .start_ap = wl_cfg80211_start_ap,
13058 .stop_ap = wl_cfg80211_stop_ap,
13059 #endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
13060 #ifdef WL_SCHED_SCAN
13061 .sched_scan_start = wl_cfg80211_sched_scan_start,
13062 .sched_scan_stop = wl_cfg80211_sched_scan_stop,
13063 #endif /* WL_SCHED_SCAN */
13064 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || \
13065 (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
13066 .del_station = wl_cfg80211_del_station,
13067 .change_station = wl_cfg80211_change_station,
13068 .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
13069 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
13070 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \
13071 defined(WL_COMPAT_WIRELESS)
13072 .tdls_mgmt = wl_cfg80211_tdls_mgmt,
13073 .tdls_oper = wl_cfg80211_tdls_oper,
13074 #endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
13075 #ifdef WL_SUPPORT_ACS
13076 .dump_survey = wl_cfg80211_dump_survey,
13077 #endif /* WL_SUPPORT_ACS */
13078 #ifdef WL_CFG80211_ACL
13079 .set_mac_acl = wl_cfg80211_set_mac_acl,
13080 #endif /* WL_CFG80211_ACL */
13081 #ifdef GTK_OFFLOAD_SUPPORT
13082 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
13083 .set_rekey_data = wl_cfg80211_set_rekey_data,
13084 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
13085 #endif /* GTK_OFFLOAD_SUPPORT */
13086 #if defined(WL_FILS)
13087 /* This should be enabled from kernel version which supports this */
13088 .update_connect_params = wl_cfg80211_update_connect_params,
13089 #endif /* WL_FILS */
13090 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
13091 .set_pmk = wl_cfg80211_set_pmk,
13092 .del_pmk = wl_cfg80211_del_pmk,
13093 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
13094 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
13095 .channel_switch = wl_cfg80211_channel_switch,
13096 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
13097 #ifdef WL_CLIENT_SAE
13098 .external_auth = wl_cfg80211_external_auth,
13099 #endif /* WL_CLIENT_SAE */
13100 };
13101
wl_mode_to_nl80211_iftype(s32 mode)13102 s32 wl_mode_to_nl80211_iftype(s32 mode)
13103 {
13104 s32 err = 0;
13105
13106 switch (mode) {
13107 case WL_MODE_BSS:
13108 return NL80211_IFTYPE_STATION;
13109 case WL_MODE_IBSS:
13110 return NL80211_IFTYPE_ADHOC;
13111 case WL_MODE_AP:
13112 return NL80211_IFTYPE_AP;
13113 #ifdef WLMESH_CFG80211
13114 case WL_MODE_MESH:
13115 return NL80211_IFTYPE_MESH_POINT;
13116 #endif /* WLMESH_CFG80211 */
13117 default:
13118 return NL80211_IFTYPE_UNSPECIFIED;
13119 }
13120
13121 return err;
13122 }
13123
wl_cfg80211_set_country_code(struct net_device * net,char * country_code,bool notify,bool user_enforced,int revinfo)13124 s32 wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
13125 bool notify, bool user_enforced, int revinfo)
13126 {
13127 s32 ret = BCME_OK;
13128 #ifdef WL_NAN
13129 struct wireless_dev *wdev = ndev_to_wdev(net);
13130 struct wiphy *wiphy = wdev->wiphy;
13131 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
13132 if (cfg->nan_enable) {
13133 mutex_lock(&cfg->if_sync);
13134 cfg->nancfg.disable_reason = NAN_COUNTRY_CODE_CHANGE;
13135 ret = wl_cfgnan_disable(cfg);
13136 mutex_unlock(&cfg->if_sync);
13137 if (ret != BCME_OK) {
13138 WL_ERR(("failed to disable nan, error[%d]\n", ret));
13139 return ret;
13140 }
13141 }
13142 #endif /* WL_NAN */
13143 ret = wldev_set_country(net, country_code, notify, user_enforced, revinfo);
13144 if (ret < 0) {
13145 WL_ERR(("set country Failed :%d\n", ret));
13146 }
13147 return ret;
13148 }
13149
13150 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
13151 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
13152 #define WL_CFG80211_REG_NOTIFIER() \
13153 static int wl_cfg80211_reg_notifier(struct wiphy *wiphy, \
13154 struct regulatory_request *request)
13155 #else
13156 #define WL_CFG80211_REG_NOTIFIER() \
13157 static void wl_cfg80211_reg_notifier(struct wiphy *wiphy, \
13158 struct regulatory_request *request)
13159 #endif /* kernel version < 3.9.0 */
13160 #endif
13161
13162 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
WL_CFG80211_REG_NOTIFIER()13163 WL_CFG80211_REG_NOTIFIER()
13164 {
13165 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
13166 int ret = 0;
13167 int revinfo = -1;
13168
13169 if (!request || !cfg) {
13170 WL_ERR(("Invalid arg\n"));
13171 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
13172 return -EINVAL;
13173 #else
13174 return;
13175 #endif /* kernel version < 3.10.11 */
13176 }
13177
13178 WL_DBG(("ccode: %c%c Initiator: %d\n", request->alpha2[0],
13179 request->alpha2[1], request->initiator));
13180
13181 /* We support only REGDOM_SET_BY_USER as of now */
13182 if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
13183 (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
13184 WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
13185 request->initiator));
13186 /* in case of no supported country by regdb
13187 lets driver setup platform default Locale
13188 */
13189 }
13190
13191 WL_ERR(
13192 ("Set country code %c%c from %s\n", request->alpha2[0],
13193 request->alpha2[1],
13194 ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP"
13195 : "User")));
13196
13197 if ((ret = wldev_set_country(
13198 bcmcfg_to_prmry_ndev(cfg), request->alpha2, false,
13199 (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false),
13200 revinfo)) < 0) {
13201 WL_ERR(("set country Failed :%d\n", ret));
13202 }
13203
13204 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
13205 return ret;
13206 #else
13207 return;
13208 #endif /* kernel version < 3.10.11 */
13209 }
13210 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
13211
13212 #ifdef CONFIG_PM
13213 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
13214 static const struct wiphy_wowlan_support brcm_wowlan_support = {
13215 .flags = WIPHY_WOWLAN_ANY,
13216 .n_patterns = WL_WOWLAN_MAX_PATTERNS,
13217 .pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
13218 .pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
13219 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
13220 .max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
13221 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
13222 };
13223 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
13224 #endif /* CONFIG_PM */
13225
wl_features_set(u8 * array,uint8 len,u32 ftidx)13226 int wl_features_set(u8 *array, uint8 len, u32 ftidx)
13227 {
13228 u8 *ft_byte;
13229
13230 if ((ftidx / 8u) >= len) {
13231 return BCME_BADARG;
13232 }
13233
13234 ft_byte = &array[ftidx / 8u];
13235 *ft_byte |= BIT(ftidx % 8u);
13236 return BCME_OK;
13237 }
13238
wl_setup_wiphy(struct wireless_dev * wdev,struct device * sdiofunc_dev,dhd_pub_t * context)13239 static s32 wl_setup_wiphy(struct wireless_dev *wdev,
13240 struct device *sdiofunc_dev, dhd_pub_t *context)
13241 {
13242 s32 err = 0;
13243 #ifdef CONFIG_PM
13244 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13245 struct cfg80211_wowlan *brcm_wowlan_config = NULL;
13246 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13247 #endif /* CONFIG_PM */
13248
13249 // #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) ||
13250 // defined(WL_COMPAT_WIRELESS))
13251 dhd_pub_t *dhd = (dhd_pub_t *)context;
13252 BCM_REFERENCE(dhd);
13253
13254 if (!dhd) {
13255 WL_ERR(("DHD is NULL!!"));
13256 err = -ENODEV;
13257 return err;
13258 }
13259 // #endif // endif
13260
13261 wdev->wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
13262 if (unlikely(!wdev->wiphy)) {
13263 WL_ERR(("Couldn not allocate wiphy device\n"));
13264 err = -ENOMEM;
13265 return err;
13266 }
13267 set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
13268 wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
13269 /* Report how many SSIDs Driver can support per Scan request */
13270 wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
13271 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
13272 #ifdef WL_SCHED_SCAN
13273 wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
13274 wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
13275 wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
13276 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
13277 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
13278 #endif /* LINUX_VER < 4.12 */
13279 #endif /* WL_SCHED_SCAN */
13280 #ifdef WLMESH_CFG80211
13281 wdev->wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
13282 #endif /* WLMESH_CFG80211 */
13283 wdev->wiphy->interface_modes =
13284 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC)
13285 #if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
13286 | BIT(NL80211_IFTYPE_MONITOR)
13287 #endif // endif
13288 #if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
13289 | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)
13290 #endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
13291 #if defined(WL_CFG80211_P2P_DEV_IF)
13292 | BIT(NL80211_IFTYPE_P2P_DEVICE)
13293 #endif /* WL_CFG80211_P2P_DEV_IF */
13294 #ifdef WLMESH_CFG80211
13295 | BIT(NL80211_IFTYPE_MESH_POINT)
13296 #endif /* WLMESH_CFG80211 */
13297 | BIT(NL80211_IFTYPE_AP);
13298
13299 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
13300 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
13301 WL_DBG(("Setting interface combinations for common mode\n"));
13302 wdev->wiphy->iface_combinations = common_iface_combinations;
13303 wdev->wiphy->n_iface_combinations = ARRAY_SIZE(common_iface_combinations);
13304 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || \
13305 WL_CFG80211_P2P_DEV_IF) */
13306
13307 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
13308
13309 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
13310 wdev->wiphy->cipher_suites = __wl_cipher_suites;
13311 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
13312 wdev->wiphy->max_remain_on_channel_duration = 0x1388;
13313 wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
13314 #ifndef WL_POWERSAVE_DISABLED
13315 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
13316 #else
13317 wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
13318 #endif /* !WL_POWERSAVE_DISABLED */
13319 wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | WIPHY_FLAG_4ADDR_AP |
13320 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && \
13321 !defined(WL_COMPAT_WIRELESS)
13322 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
13323 #endif // endif
13324 WIPHY_FLAG_4ADDR_STATION;
13325 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
13326 /*
13327 * If FW ROAM flag is advertised, upper layer doesn't provide the
13328 * bssid & freq in the connect command. However, kernel ver >= 3.15,
13329 * provides bssid_hint & freq_hint which can be used by the firmware.
13330 * fw_ap_select variable determines whether FW selects the AP or the
13331 * user space selects the target AP within the given ESS.
13332 */
13333 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
13334 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13335 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
13336 defined(WL_COMPAT_WIRELESS)
13337 wdev->wiphy->flags |=
13338 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_OFFCHAN_TX;
13339 #endif // endif
13340 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || \
13341 (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
13342 /* From 3.4 kernel ownards AP_SME flag can be advertised
13343 * to remove the patch from supplicant
13344 */
13345 wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
13346
13347 #ifdef WL_CFG80211_ACL
13348 /* Configure ACL capabilities. */
13349 wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
13350 #endif // endif
13351
13352 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || \
13353 defined(WL_COMPAT_WIRELESS))
13354 /* Supplicant distinguish between the SoftAP mode and other
13355 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
13356 * response frame from Supplicant MR1 and Kernel 3.4.0 or
13357 * later version. To add Vendor specific IE into the
13358 * probe response frame in case of SoftAP mode,
13359 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
13360 */
13361 if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
13362 wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
13363 wdev->wiphy->probe_resp_offload = 0;
13364 }
13365 #endif // endif
13366 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= \
13367 KERNEL_VERSION(3, 4, 0)) */
13368
13369 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \
13370 defined(WL_COMPAT_WIRELESS)
13371 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
13372 #endif // endif
13373
13374 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13375 /*
13376 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
13377 * disconnection of connected network before suspend. So a dummy wowlan
13378 * filter is configured for kernels linux-3.8 and above.
13379 */
13380
13381 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13382 wdev->wiphy->wowlan = &brcm_wowlan_support;
13383 /* If this is not provided cfg stack will get disconnect
13384 * during suspend.
13385 * Note: wiphy->wowlan_config is freed by cfg80211 layer.
13386 * so use malloc instead of MALLOC(osh) to avoid false alarm.
13387 */
13388 brcm_wowlan_config = kmalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL);
13389 if (brcm_wowlan_config) {
13390 brcm_wowlan_config->disconnect = true;
13391 brcm_wowlan_config->gtk_rekey_failure = true;
13392 brcm_wowlan_config->eap_identity_req = true;
13393 brcm_wowlan_config->four_way_handshake = true;
13394 brcm_wowlan_config->patterns = NULL;
13395 brcm_wowlan_config->n_patterns = 0;
13396 brcm_wowlan_config->tcp = NULL;
13397 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13398 brcm_wowlan_config->nd_config = NULL;
13399 #endif // endif
13400 } else {
13401 WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
13402 " So wiphy->wowlan_config is set to NULL\n"));
13403 }
13404 wdev->wiphy->wowlan_config = brcm_wowlan_config;
13405 #else
13406 wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
13407 wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
13408 wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
13409 wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
13410 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
13411 wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
13412 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
13413 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13414 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13415
13416 WL_DBG(("Registering custom regulatory)\n"));
13417 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
13418 wdev->wiphy->regulatory_flags |=
13419 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
13420 REGULATORY_IGNORE_STALE_KICKOFF |
13421 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
13422 REGULATORY_CUSTOM_REG;
13423 #else
13424 wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
13425 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
13426 wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
13427
13428 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
13429 defined(WL_VENDOR_EXT_SUPPORT)
13430 WL_INFORM_MEM(("Registering Vendor80211\n"));
13431 err = wl_cfgvendor_attach(wdev->wiphy, dhd);
13432 if (unlikely(err < 0)) {
13433 WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
13434 }
13435 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
13436 defined(WL_VENDOR_EXT_SUPPORT) */
13437 #ifdef WL_FILS
13438 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
13439 #endif /* WL_FILS */
13440
13441 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
13442 wdev->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
13443 wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS;
13444 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */
13445
13446 /* Now we can register wiphy with cfg80211 module */
13447 err = wiphy_register(wdev->wiphy);
13448 if (unlikely(err < 0)) {
13449 WL_ERR(("Couldn not register wiphy device (%d)\n", err));
13450 wiphy_free(wdev->wiphy);
13451 }
13452
13453 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
13454 (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 3, 0))) && \
13455 defined(WL_IFACE_COMB_NUM_CHANNELS)
13456 wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
13457 #endif // endif
13458
13459 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
13460 if (wl_extsae_chip(dhd)) {
13461 wdev->wiphy->features |= NL80211_FEATURE_SAE;
13462 }
13463 #endif /* WL_SAE || WL_CLIENT_SAE */
13464 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && \
13465 defined(BCMSUP_4WAY_HANDSHAKE)
13466 if (FW_SUPPORTED(dhd, idsup)) {
13467 err = wiphy_ext_feature_set(wdev->wiphy,
13468 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
13469 if (err) {
13470 return err;
13471 }
13472 err = wiphy_ext_feature_set(wdev->wiphy,
13473 NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
13474 if (err) {
13475 return err;
13476 }
13477 }
13478 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) && \
13479 defined(BCMSUP_4WAY_HANDSHAKE) */
13480 #ifdef WL_SCAN_TYPE
13481 /* These scan types will be mapped to default scan on non-supported chipset
13482 */
13483 /* Advertise scan type capability. */
13484 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_SPAN_SCAN);
13485 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_POWER_SCAN);
13486 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
13487 wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN;
13488 #endif /* WL_SCAN_TYPE */
13489
13490 return err;
13491 }
13492
wl_free_wdev(struct bcm_cfg80211 * cfg)13493 static void wl_free_wdev(struct bcm_cfg80211 *cfg)
13494 {
13495 struct wireless_dev *wdev = cfg->wdev;
13496 struct wiphy *wiphy = NULL;
13497 if (!wdev) {
13498 WL_ERR(("wdev is invalid\n"));
13499 return;
13500 }
13501 if (wdev->wiphy) {
13502 wiphy = wdev->wiphy;
13503
13504 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
13505 defined(WL_VENDOR_EXT_SUPPORT)
13506 wl_cfgvendor_detach(wdev->wiphy);
13507 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
13508 defined(WL_VENDOR_EXT_SUPPORT) */
13509 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
13510 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
13511 /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic
13512 */
13513 WL_DBG(("clear wowlan\n"));
13514 wdev->wiphy->wowlan = NULL;
13515 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
13516 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
13517 wiphy_unregister(wdev->wiphy);
13518 wdev->wiphy->dev.parent = NULL;
13519 wdev->wiphy = NULL;
13520 }
13521
13522 wl_delete_all_netinfo(cfg);
13523 if (wiphy) {
13524 if (wdev->netdev) {
13525 wdev->netdev->ieee80211_ptr = NULL;
13526 }
13527 wdev->netdev = NULL;
13528 MFREE(cfg->osh, wdev, sizeof(*wdev));
13529 cfg->wdev = NULL;
13530 wiphy_free(wiphy);
13531 }
13532
13533 /* PLEASE do NOT call any function after wiphy_free, the driver's private
13534 * structure "cfg", which is the private part of wiphy, has been freed in
13535 * wiphy_free !!!!!!!!!!!
13536 */
13537 }
13538
13539 #if defined(BSSCACHE) || defined(RSSIAVG)
wl_cfg80211_update_bss_cache(struct bcm_cfg80211 * cfg)13540 void wl_cfg80211_update_bss_cache(struct bcm_cfg80211 *cfg)
13541 {
13542 #if defined(RSSIAVG)
13543 int rssi;
13544 #endif
13545 struct wl_scan_results *bss_list = cfg->bss_list;
13546
13547 /* Free cache in p2p scanning */
13548 if (p2p_is_on(cfg) && p2p_scan(cfg)) {
13549 #if defined(RSSIAVG)
13550 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
13551 #endif
13552 #if defined(BSSCACHE)
13553 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
13554 #endif
13555 }
13556
13557 /* Update cache */
13558 #if defined(RSSIAVG)
13559 wl_update_rssi_cache(&cfg->g_rssi_cache_ctrl, bss_list);
13560 if (!in_atomic()) {
13561 wl_update_connected_rssi_cache(ndev, &cfg->g_rssi_cache_ctrl, &rssi);
13562 }
13563 #endif
13564 #if defined(BSSCACHE)
13565 wl_update_bss_cache(&cfg->g_bss_cache_ctrl,
13566 #if defined(RSSIAVG)
13567 &cfg->g_rssi_cache_ctrl,
13568 #endif
13569 bss_list);
13570 #endif
13571
13572 /* delete dirty cache */
13573 #if defined(RSSIAVG)
13574 wl_delete_dirty_rssi_cache(&cfg->g_rssi_cache_ctrl);
13575 wl_reset_rssi_cache(&cfg->g_rssi_cache_ctrl);
13576 #endif
13577 #if defined(BSSCACHE)
13578 wl_delete_dirty_bss_cache(&cfg->g_bss_cache_ctrl);
13579 wl_reset_bss_cache(&cfg->g_bss_cache_ctrl);
13580 #endif
13581 }
13582 #endif
13583
13584 #if defined(BSSCACHE)
wl_inform_bss_cache(struct bcm_cfg80211 * cfg)13585 s32 wl_inform_bss_cache(struct bcm_cfg80211 *cfg)
13586 {
13587 struct wl_scan_results *bss_list = cfg->bss_list;
13588 wl_bss_info_t *bi = NULL; /* must be initialized */
13589 s32 err = 0;
13590 s32 i, cnt;
13591 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13592 wl_bss_cache_t *node;
13593
13594 WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
13595 bss_list = cfg->bss_list;
13596 preempt_disable();
13597 bi = next_bss(bss_list, bi);
13598 for_each_bss(bss_list, bi, i)
13599 {
13600 err = wl_inform_single_bss(cfg, bi, false);
13601 if (unlikely(err)) {
13602 WL_ERR(("bss inform failed\n"));
13603 }
13604 }
13605
13606 cnt = i;
13607 node = cfg->g_bss_cache_ctrl.m_cache_head;
13608 WL_SCAN(
13609 ("cached AP count (%d)\n", wl_bss_cache_size(&cfg->g_bss_cache_ctrl)));
13610 for (i = cnt; node && i < WL_AP_MAX; i++) {
13611 if (node->dirty > 1) {
13612 bi = node->results.bss_info;
13613 err = wl_inform_single_bss(cfg, bi, false);
13614 }
13615 node = node->next;
13616 }
13617 preempt_enable();
13618 if (cfg->autochannel) {
13619 wl_ext_get_best_channel(ndev, &cfg->g_bss_cache_ctrl, ioctl_version,
13620 &cfg->best_2g_ch, &cfg->best_5g_ch);
13621 }
13622
13623 return err;
13624 }
13625 #endif
13626
wl_inform_bss(struct bcm_cfg80211 * cfg)13627 s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
13628 {
13629 #if !defined(BSSCACHE)
13630 struct wl_scan_results *bss_list;
13631 wl_bss_info_t *bi = NULL; /* must be initialized */
13632 s32 i;
13633 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13634 #endif
13635 s32 err = 0;
13636
13637 #ifdef WL_EXT_IAPSTA
13638 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_SCAN_COMPLETE, NULL);
13639 #endif
13640
13641 #if defined(BSSCACHE) || defined(RSSIAVG)
13642 wl_cfg80211_update_bss_cache(cfg);
13643 #endif
13644
13645 #if defined(BSSCACHE)
13646 err = wl_inform_bss_cache(cfg);
13647 #else
13648 bss_list = cfg->bss_list;
13649 WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
13650 #ifdef ESCAN_CHANNEL_CACHE
13651 reset_roam_cache(cfg);
13652 #endif /* ESCAN_CHANNEL_CACHE */
13653 preempt_disable();
13654 bi = next_bss(bss_list, bi);
13655 for_each_bss(bss_list, bi, i)
13656 {
13657 #ifdef ESCAN_CHANNEL_CACHE
13658 add_roam_cache(cfg, bi);
13659 #endif /* ESCAN_CHANNEL_CACHE */
13660 err = wl_inform_single_bss(cfg, bi, false);
13661 if (unlikely(err)) {
13662 WL_ERR(("bss inform failed\n"));
13663 }
13664 }
13665 preempt_enable();
13666 if (cfg->autochannel) {
13667 wl_ext_get_best_channel(ndev, bss_list, ioctl_version, &cfg->best_2g_ch,
13668 &cfg->best_5g_ch);
13669 }
13670 #endif
13671
13672 WL_MEM(("cfg80211 scan cache updated\n"));
13673 #ifdef ROAM_CHANNEL_CACHE
13674 update_roam_cache(cfg, ioctl_version);
13675 #endif /* ROAM_CHANNEL_CACHE */
13676 return err;
13677 }
13678
wl_inform_single_bss(struct bcm_cfg80211 * cfg,wl_bss_info_t * bi,bool update_ssid)13679 static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi,
13680 bool update_ssid)
13681 {
13682 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13683 struct ieee80211_mgmt *mgmt;
13684 struct ieee80211_channel *channel;
13685 struct ieee80211_supported_band *band;
13686 struct wl_cfg80211_bss_info *notif_bss_info;
13687 struct wl_scan_req *sr = wl_to_sr(cfg);
13688 struct beacon_proberesp *beacon_proberesp;
13689 struct cfg80211_bss *cbss = NULL;
13690 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
13691 log_conn_event_t *event_data = NULL;
13692 tlv_log *tlv_data = NULL;
13693 u32 alloc_len, tlv_len;
13694 u32 payload_len;
13695 s32 mgmt_type;
13696 s32 signal;
13697 u32 freq;
13698 s32 err = 0;
13699 gfp_t aflags;
13700 u8 tmp_buf[IEEE80211_MAX_SSID_LEN + 1];
13701 chanspec_t chanspec;
13702 #ifdef CONFIG_AP6XXX_WIFI6_HDF
13703 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13704 #endif
13705 if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
13706 WL_DBG(("Beacon is larger than buffer. Discarding\n"));
13707 return err;
13708 }
13709
13710 if (bi->SSID_len > IEEE80211_MAX_SSID_LEN) {
13711 WL_ERR(("wrong SSID len:%d\n", bi->SSID_len));
13712 return -EINVAL;
13713 }
13714
13715 aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
13716 notif_bss_info = (struct wl_cfg80211_bss_info *)MALLOCZ(
13717 cfg->osh,
13718 sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
13719 if (unlikely(!notif_bss_info)) {
13720 WL_ERR(("notif_bss_info alloc failed\n"));
13721 return -ENOMEM;
13722 }
13723 mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
13724 chanspec = wl_chspec_driver_to_host(bi->chanspec);
13725 notif_bss_info->channel = wf_chspec_ctlchan(chanspec);
13726
13727 if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL) {
13728 band = wiphy->bands[IEEE80211_BAND_2GHZ];
13729 } else {
13730 band = wiphy->bands[IEEE80211_BAND_5GHZ];
13731 }
13732 if (!band) {
13733 WL_ERR(("No valid band\n"));
13734 MFREE(cfg->osh, notif_bss_info,
13735 sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) +
13736 WL_BSS_INFO_MAX);
13737 return -EINVAL;
13738 }
13739 notif_bss_info->rssi = dtoh16(bi->RSSI);
13740 #if defined(RSSIAVG)
13741 notif_bss_info->rssi = wl_get_avg_rssi(&cfg->g_rssi_cache_ctrl, &bi->BSSID);
13742 if (notif_bss_info->rssi == RSSI_MINVAL) {
13743 notif_bss_info->rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
13744 }
13745 #endif
13746 #if defined(RSSIOFFSET)
13747 notif_bss_info->rssi =
13748 wl_update_rssi_offset(bcmcfg_to_prmry_ndev(cfg), notif_bss_info->rssi);
13749 #endif
13750 #if !defined(RSSIAVG) && !defined(RSSIOFFSET)
13751 // terence 20150419: limit the max. rssi to -2 or the bss will be filtered
13752 // out in android OS
13753 notif_bss_info->rssi = MIN(notif_bss_info->rssi, RSSI_MAXVAL);
13754 #endif
13755 memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
13756 mgmt_type =
13757 cfg->active_scan ? IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
13758 if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
13759 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type);
13760 }
13761 beacon_proberesp = cfg->active_scan
13762 ? (struct beacon_proberesp *)&mgmt->u.probe_resp
13763 : (struct beacon_proberesp *)&mgmt->u.beacon;
13764 beacon_proberesp->timestamp = 0;
13765 beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
13766 beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
13767 wl_rst_ie(cfg);
13768 wl_update_hidden_ap_ie(bi, ((u8 *)bi) + bi->ie_offset, &bi->ie_length,
13769 update_ssid);
13770 wl_mrg_ie(cfg, ((u8 *)bi) + bi->ie_offset, bi->ie_length);
13771 wl_cp_ie(cfg, beacon_proberesp->variable,
13772 WL_BSS_INFO_MAX -
13773 offsetof(struct wl_cfg80211_bss_info, frame_buf));
13774 notif_bss_info->frame_len =
13775 offsetof(struct ieee80211_mgmt, u.beacon.variable) + wl_get_ielen(cfg);
13776 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && \
13777 !defined(WL_COMPAT_WIRELESS)
13778 freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
13779 (void)band->band;
13780 #else
13781 freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
13782 #endif // endif
13783 if (freq == 0) {
13784 WL_ERR(("Invalid channel, fail to change channel to freq\n"));
13785 MFREE(cfg->osh, notif_bss_info,
13786 sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) +
13787 WL_BSS_INFO_MAX);
13788 return -EINVAL;
13789 }
13790 channel = ieee80211_get_channel(wiphy, freq);
13791 memcpy(tmp_buf, bi->SSID, bi->SSID_len);
13792 tmp_buf[bi->SSID_len] = '\0';
13793 WL_SCAN(("BSSID %pM, channel %3d(%3d %3sMHz), rssi %3d, capa 0x%-4x, "
13794 "mgmt_type %d, "
13795 "frame_len %3d, SSID \"%s\"\n",
13796 &bi->BSSID, notif_bss_info->channel, CHSPEC_CHANNEL(chanspec),
13797 CHSPEC_IS20(chanspec) ? "20"
13798 : CHSPEC_IS40(chanspec) ? "40"
13799 : CHSPEC_IS80(chanspec) ? "80"
13800 : CHSPEC_IS160(chanspec) ? "160"
13801 : "??",
13802 notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type,
13803 notif_bss_info->frame_len, tmp_buf));
13804 if (unlikely(!channel)) {
13805 WL_ERR(("ieee80211_get_channel error, freq=%d, channel=%d\n", freq,
13806 notif_bss_info->channel));
13807 MFREE(cfg->osh, notif_bss_info,
13808 sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) +
13809 WL_BSS_INFO_MAX);
13810 return -EINVAL;
13811 }
13812
13813 signal = notif_bss_info->rssi * 0x64;
13814 if (!mgmt->u.probe_resp.timestamp) {
13815 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13816 struct osl_timespec ts;
13817 osl_get_monotonic_boottime(&ts);
13818 mgmt->u.probe_resp.timestamp =
13819 ((u64)ts.tv_sec * 0xF4240) + ts.tv_nsec / 0x3E8;
13820 #else
13821 struct osl_timespec tv;
13822 osl_do_gettimeofday(&tv);
13823 mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec * 0xF4240) + tv.tv_usec;
13824 #endif // endif
13825 }
13826
13827 cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
13828 le16_to_cpu(notif_bss_info->frame_len),
13829 signal, aflags);
13830 if (unlikely(!cbss)) {
13831 WL_ERR(("cfg80211_inform_bss_frame error bssid " MACDBG
13832 " channel %d \n",
13833 MAC2STRDBG((u8 *)(&bi->BSSID)), notif_bss_info->channel));
13834 err = -EINVAL;
13835 goto out_err;
13836 }
13837
13838 CFG80211_PUT_BSS(wiphy, cbss);
13839 #ifdef CONFIG_AP6XXX_WIFI6_HDF
13840 HdfInformBssFrameEventCallback(ndev, channel, signal, freq, mgmt,
13841 notif_bss_info->frame_len);
13842 #endif
13843 if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID) &&
13844 (cfg->sched_scan_req && !cfg->scan_request)) {
13845 alloc_len = sizeof(log_conn_event_t) + IEEE80211_MAX_SSID_LEN +
13846 sizeof(uint16) + sizeof(int16);
13847 event_data = (log_conn_event_t *)MALLOCZ(dhdp->osh, alloc_len);
13848 if (!event_data) {
13849 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
13850 "length(%d)\n",
13851 __func__, alloc_len));
13852 goto out_err;
13853 }
13854 tlv_len = 0x3 * sizeof(tlv_log);
13855 event_data->tlvs = (tlv_log *)MALLOCZ(cfg->osh, tlv_len);
13856 if (!event_data->tlvs) {
13857 WL_ERR(("%s: failed to allocate the log_conn_event_t with "
13858 "length(%d)\n",
13859 __func__, tlv_len));
13860 goto free_evt_data;
13861 }
13862
13863 payload_len = sizeof(log_conn_event_t);
13864 event_data->event = WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND;
13865 tlv_data = event_data->tlvs;
13866
13867 /* ssid */
13868 tlv_data->tag = WIFI_TAG_SSID;
13869 tlv_data->len = bi->SSID_len;
13870 memcpy(tlv_data->value, bi->SSID, bi->SSID_len);
13871 payload_len += TLV_LOG_SIZE(tlv_data);
13872 tlv_data = TLV_LOG_NEXT(tlv_data);
13873
13874 /* channel */
13875 tlv_data->tag = WIFI_TAG_CHANNEL;
13876 tlv_data->len = sizeof(uint16);
13877 memcpy(tlv_data->value, ¬if_bss_info->channel, sizeof(uint16));
13878 payload_len += TLV_LOG_SIZE(tlv_data);
13879 tlv_data = TLV_LOG_NEXT(tlv_data);
13880
13881 /* rssi */
13882 tlv_data->tag = WIFI_TAG_RSSI;
13883 tlv_data->len = sizeof(int16);
13884 memcpy(tlv_data->value, ¬if_bss_info->rssi, sizeof(int16));
13885 payload_len += TLV_LOG_SIZE(tlv_data);
13886 tlv_data = TLV_LOG_NEXT(tlv_data);
13887
13888 dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID, event_data,
13889 payload_len);
13890 MFREE(dhdp->osh, event_data->tlvs, tlv_len);
13891 free_evt_data:
13892 MFREE(dhdp->osh, event_data, alloc_len);
13893 }
13894
13895 out_err:
13896 MFREE(cfg->osh, notif_bss_info,
13897 sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) +
13898 WL_BSS_INFO_MAX);
13899 return err;
13900 }
13901
wl_is_linkup(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e,struct net_device * ndev)13902 static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
13903 struct net_device *ndev)
13904 {
13905 u32 event = ntoh32(e->event_type);
13906 u32 status = ntoh32(e->status);
13907 u16 flags = ntoh16(e->flags);
13908 #if defined(CUSTOM_SET_ANTNPM)
13909 dhd_pub_t *dhd;
13910 dhd = (dhd_pub_t *)(cfg->pub);
13911 #endif // endif
13912
13913 WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
13914 if (event == WLC_E_SET_SSID) {
13915 if (status == WLC_E_STATUS_SUCCESS) {
13916 #ifdef CUSTOM_SET_ANTNPM
13917 if (dhd->mimo_ant_set) {
13918 int err = 0;
13919
13920 WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhd->mimo_ant_set));
13921 err = wldev_iovar_setint(ndev, "txchain", dhd->mimo_ant_set);
13922 if (err != 0) {
13923 WL_ERR(("[WIFI_SEC] Fail set txchain\n"));
13924 }
13925 err = wldev_iovar_setint(ndev, "rxchain", dhd->mimo_ant_set);
13926 if (err != 0) {
13927 WL_ERR(("[WIFI_SEC] Fail set rxchain\n"));
13928 }
13929 }
13930 #endif /* CUSTOM_SET_ANTNPM */
13931 if (!wl_is_ibssmode(cfg, ndev)) {
13932 return true;
13933 }
13934 }
13935 } else if (event == WLC_E_LINK) {
13936 if (flags & WLC_EVENT_MSG_LINK) {
13937 return true;
13938 }
13939 }
13940
13941 WL_DBG(("wl_is_linkup false\n"));
13942 return false;
13943 }
13944
wl_is_linkdown(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)13945 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13946 {
13947 u32 event = ntoh32(e->event_type);
13948 u16 flags = ntoh16(e->flags);
13949
13950 if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND ||
13951 event == WLC_E_DISASSOC || event == WLC_E_DEAUTH) {
13952 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
13953 return true;
13954 } else if (event == WLC_E_LINK) {
13955 if (!(flags & WLC_EVENT_MSG_LINK)) {
13956 WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
13957 return true;
13958 }
13959 }
13960
13961 return false;
13962 }
13963
wl_is_nonetwork(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)13964 static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
13965 {
13966 u32 event = ntoh32(e->event_type);
13967 u32 status = ntoh32(e->status);
13968 if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS) {
13969 return true;
13970 }
13971 if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) {
13972 return true;
13973 }
13974 if (event == WLC_E_ASSOC_RESP_IE && status != WLC_E_STATUS_SUCCESS) {
13975 return true;
13976 }
13977
13978 return false;
13979 }
13980
13981 #ifdef WL_SAE
wl_cfg80211_event_sae_key(struct bcm_cfg80211 * cfg,struct net_device * ndev,wl_sae_key_info_t * sae_key)13982 static s32 wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg,
13983 struct net_device *ndev,
13984 wl_sae_key_info_t *sae_key)
13985 {
13986 struct sk_buff *skb;
13987 gfp_t kflags;
13988 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13989 int err = BCME_OK;
13990
13991 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
13992 #if (defined(CONFIG_ARCH_MSM) && \
13993 defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
13994 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
13995 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev),
13996 BRCM_SAE_VENDOR_EVENT_BUF_LEN,
13997 BRCM_VENDOR_EVENT_SAE_KEY, kflags);
13998 #else
13999 skb = cfg80211_vendor_event_alloc(wiphy, BRCM_SAE_VENDOR_EVENT_BUF_LEN,
14000 BRCM_VENDOR_EVENT_SAE_KEY, kflags);
14001 #endif /* (defined(CONFIG_ARCH_MSM) && \
14002 defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
14003 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
14004 if (!skb) {
14005 WL_ERR(("skb alloc failed"));
14006 err = BCME_NOMEM;
14007 goto done;
14008 }
14009
14010 WL_INFORM_MEM(("Received Sae Key event for " MACDBG " key length %x %x",
14011 MAC2STRDBG(sae_key->peer_mac), sae_key->pmk_len,
14012 sae_key->pmkid_len));
14013 nla_put(skb, BRCM_SAE_KEY_ATTR_PEER_MAC, ETHER_ADDR_LEN, sae_key->peer_mac);
14014 nla_put(skb, BRCM_SAE_KEY_ATTR_PMK, sae_key->pmk_len, sae_key->pmk);
14015 nla_put(skb, BRCM_SAE_KEY_ATTR_PMKID, sae_key->pmkid_len, sae_key->pmkid);
14016 cfg80211_vendor_event(skb, kflags);
14017
14018 done:
14019 return err;
14020 }
14021
wl_bss_handle_sae_auth(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * event,void * data)14022 static s32 wl_bss_handle_sae_auth(struct bcm_cfg80211 *cfg,
14023 struct net_device *ndev,
14024 const wl_event_msg_t *event, void *data)
14025 {
14026 int err = BCME_OK;
14027 uint status = ntoh32(event->status);
14028 wl_auth_event_t *auth_data;
14029 wl_sae_key_info_t sae_key;
14030 uint16 tlv_buf_len;
14031
14032 if (status == WLC_E_STATUS_SUCCESS) {
14033 auth_data = (wl_auth_event_t *)data;
14034 if (auth_data->version != WL_AUTH_EVENT_DATA_V1) {
14035 WL_ERR(
14036 ("unknown auth event data version %x\n", auth_data->version));
14037 err = BCME_VERSION;
14038 goto done;
14039 }
14040
14041 tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V1;
14042
14043 /* check if PMK info present */
14044 sae_key.pmk = bcm_get_data_from_xtlv_buf(
14045 auth_data->xtlvs, tlv_buf_len, WL_AUTH_PMK_TLV_ID,
14046 &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
14047 if (!sae_key.pmk || !sae_key.pmk_len) {
14048 WL_ERR(("Mandatory PMK info not present"));
14049 err = BCME_NOTFOUND;
14050 goto done;
14051 }
14052 /* check if PMKID info present */
14053 sae_key.pmkid = bcm_get_data_from_xtlv_buf(
14054 auth_data->xtlvs, tlv_buf_len, WL_AUTH_PMKID_TLV_ID,
14055 &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
14056 if (!sae_key.pmkid || !sae_key.pmkid_len) {
14057 WL_ERR(("Mandatory PMKID info not present\n"));
14058 err = BCME_NOTFOUND;
14059 goto done;
14060 }
14061 memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet,
14062 ETHER_ADDR_LEN);
14063 err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
14064 if (err) {
14065 WL_ERR(("Failed to event sae key info\n"));
14066 }
14067 } else {
14068 WL_ERR(("sae auth status failure:%d\n", status));
14069 }
14070 done:
14071 return err;
14072 }
14073 #endif /* WL_SAE */
14074
wl_get_auth_assoc_status(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14075 static s32 wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg,
14076 struct net_device *ndev,
14077 const wl_event_msg_t *e, void *data)
14078 {
14079 u32 reason = ntoh32(e->reason);
14080 u32 event = ntoh32(e->event_type);
14081 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14082 WL_DBG(("event type : %d, reason : %d\n", event, reason));
14083
14084 if (sec) {
14085 switch (event) {
14086 case WLC_E_ASSOC:
14087 case WLC_E_AUTH:
14088 case WLC_E_AUTH_IND:
14089 sec->auth_assoc_res_status = reason;
14090 if (ntoh32(e->auth_type) == DOT11_SAE) {
14091 #ifdef WL_CLIENT_SAE
14092 if (event == WLC_E_AUTH) {
14093 wl_handle_auth_event(cfg, ndev, e, data);
14094 }
14095 #endif /* WL_CLIENT_SAE */
14096 #ifdef WL_SAE
14097 if (event == WLC_E_AUTH || event == WLC_E_AUTH_IND) {
14098 wl_bss_handle_sae_auth(cfg, ndev, e, data);
14099 }
14100 #endif /* WL_SAE */
14101 }
14102 break;
14103 default:
14104 break;
14105 }
14106 } else {
14107 WL_ERR(("sec is NULL\n"));
14108 }
14109 return 0;
14110 }
14111
14112 /* The mainline kernel >= 3.2.0 has support for indicating new/del station
14113 * to AP/P2P GO via events. If this change is backported to kernel for which
14114 * this driver is being built, then define WL_CFG80211_STA_EVENT. You
14115 * should use this new/del sta event mechanism for BRCM supplicant >= 22.
14116 */
wl_notify_connect_status_ap(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14117 static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg,
14118 struct net_device *ndev,
14119 const wl_event_msg_t *e, void *data)
14120 {
14121 s32 err = 0;
14122 u32 event = ntoh32(e->event_type);
14123 u32 reason = ntoh32(e->reason);
14124 u32 len = ntoh32(e->datalen);
14125 u32 status = ntoh32(e->status);
14126
14127 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14128 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14129 bool isfree = false;
14130 u8 *mgmt_frame;
14131 u8 bsscfgidx = e->bsscfgidx;
14132 s32 freq;
14133 s32 channel;
14134 u8 *body = NULL;
14135 u16 fc = 0;
14136 u32 body_len = 0;
14137
14138 struct ieee80211_supported_band *band;
14139 struct ether_addr da;
14140 struct ether_addr bssid;
14141 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14142 channel_info_t ci;
14143 u8 ioctl_buf[WLC_IOCTL_SMLEN];
14144 #else
14145 struct station_info sinfo;
14146 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && \
14147 !WL_COMPAT_WIRELESS */
14148
14149 WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n",
14150 ndev->name, event, ntoh32(e->status), reason));
14151
14152 if (event == WLC_E_AUTH_IND) {
14153 wl_get_auth_assoc_status(cfg, ndev, e, data);
14154 return 0;
14155 }
14156 /* if link down, bsscfg is disabled. */
14157 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
14158 wl_get_p2p_status(cfg, IF_DELETING) &&
14159 (ndev != bcmcfg_to_prmry_ndev(cfg))) {
14160 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
14161 WL_MSG(ndev->name, "AP mode link down !! \n");
14162 complete(&cfg->iface_disable);
14163 #ifdef WL_EXT_IAPSTA
14164 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_AP_DISABLED, NULL);
14165 #endif
14166 return 0;
14167 }
14168
14169 if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
14170 (reason == WLC_E_REASON_INITIAL_ASSOC) &&
14171 (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
14172 if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
14173 /* AP/GO brought up successfull in firmware */
14174 WL_MSG(ndev->name, "AP/GO Link up\n");
14175 wl_set_drv_status(cfg, AP_CREATED, ndev);
14176 OSL_SMP_WMB();
14177 wake_up_interruptible(&cfg->netif_change_event);
14178 #ifdef WL_BCNRECV
14179 /* check fakeapscan is in progress, if progress then abort */
14180 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
14181 #endif /* WL_BCNRECV */
14182 #ifdef WL_EXT_IAPSTA
14183 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_AP_ENABLED, NULL);
14184 #endif
14185 return 0;
14186 }
14187 }
14188
14189 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND ||
14190 event == WLC_E_DEAUTH) {
14191 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14192 "event %s(%d) status %d reason %d\n",
14193 bcmevent_get_name(event), event, ntoh32(e->status), reason);
14194 }
14195
14196 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14197 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14198 WL_DBG(("Enter \n"));
14199 if (!len && (event == WLC_E_DEAUTH)) {
14200 len = 0x2; /* reason code field */
14201 data = &reason;
14202 }
14203 if (len) {
14204 body = (u8 *)MALLOCZ(cfg->osh, len);
14205 if (body == NULL) {
14206 WL_ERR(("Failed to allocate body\n"));
14207 return WL_INVALID;
14208 }
14209 }
14210 bzero(&bssid, ETHER_ADDR_LEN);
14211 WL_DBG(("Enter event %d ndev %p\n", event, ndev));
14212 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14213 MFREE(cfg->osh, body, len);
14214 return WL_INVALID;
14215 }
14216 if (len) {
14217 memcpy(body, data, len);
14218 }
14219
14220 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", NULL, 0, ioctl_buf,
14221 sizeof(ioctl_buf), bsscfgidx, NULL);
14222 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
14223 bzero(&bssid, sizeof(bssid));
14224 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14225 switch (event) {
14226 case WLC_E_ASSOC_IND:
14227 fc = FC_ASSOC_REQ;
14228 break;
14229 case WLC_E_REASSOC_IND:
14230 fc = FC_REASSOC_REQ;
14231 break;
14232 case WLC_E_DISASSOC_IND:
14233 fc = FC_DISASSOC;
14234 break;
14235 case WLC_E_DEAUTH_IND:
14236 fc = FC_DISASSOC;
14237 break;
14238 case WLC_E_DEAUTH:
14239 fc = FC_DISASSOC;
14240 break;
14241 default:
14242 fc = 0;
14243 goto exit;
14244 }
14245 bzero(&ci, sizeof(ci));
14246 if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
14247 MFREE(cfg->osh, body, len);
14248 return err;
14249 }
14250
14251 channel = dtoh32(ci.hw_channel);
14252 if (channel <= CH_MAX_2G_CHANNEL) {
14253 band = wiphy->bands[IEEE80211_BAND_2GHZ];
14254 } else {
14255 band = wiphy->bands[IEEE80211_BAND_5GHZ];
14256 }
14257 if (!band) {
14258 WL_ERR(("No valid band\n"));
14259 if (body) {
14260 MFREE(cfg->osh, body, len);
14261 }
14262 return -EINVAL;
14263 }
14264 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && \
14265 !defined(WL_COMPAT_WIRELESS)
14266 freq = ieee80211_channel_to_frequency(channel);
14267 (void)band->band;
14268 #else
14269 freq = ieee80211_channel_to_frequency(channel, band->band);
14270 #endif // endif
14271 body_len = len;
14272 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid, &mgmt_frame, &len,
14273 body);
14274 if (err < 0) {
14275 goto exit;
14276 }
14277 isfree = true;
14278
14279 if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
14280 (event == WLC_E_DISASSOC_IND) ||
14281 ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
14282 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14283 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
14284 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14285 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame,
14286 len);
14287 #endif
14288 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14289 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14290 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14291 defined(WL_COMPAT_WIRELESS)
14292 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14293 #else
14294 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14295 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
14296 }
14297
14298 exit:
14299 if (isfree) {
14300 MFREE(cfg->osh, mgmt_frame, len);
14301 }
14302 if (body) {
14303 MFREE(cfg->osh, body, body_len);
14304 }
14305 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && \
14306 !WL_COMPAT_WIRELESS */
14307 memset(&sinfo, 0, sizeof(struct station_info));
14308 sinfo.filled = 0;
14309 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
14310 reason == DOT11_SC_SUCCESS) {
14311 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
14312 * STATION_INFO_ASSOC_REQ_IES flag
14313 */
14314 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
14315 sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
14316 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
14317 if (!data) {
14318 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
14319 return -EINVAL;
14320 }
14321 sinfo.assoc_req_ies = data;
14322 sinfo.assoc_req_ies_len = len;
14323 WL_MSG(ndev->name, "new sta event for " MACDBG "\n",
14324 MAC2STRDBG(e->addr.octet));
14325 #ifdef WL_EXT_IAPSTA
14326 wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
14327 WL_EXT_STATUS_STA_CONNECTED, (void *)&e->addr);
14328 #endif
14329 #ifdef STA_MGMT
14330 if (!wl_ext_add_sta_info(ndev, (u8 *)&e->addr)) {
14331 return -EINVAL;
14332 }
14333 #endif /* STA_MGMT */
14334 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
14335 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14336 ChangNewSta(ndev, e->addr.octet, 6, &sinfo);
14337 #endif
14338 #ifdef WL_WPS_SYNC
14339 wl_wps_session_update(ndev, WPS_STATE_LINKUP, e->addr.octet);
14340 #endif /* WL_WPS_SYNC */
14341 } else if ((event == WLC_E_DEAUTH_IND) ||
14342 ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
14343 (event == WLC_E_DISASSOC_IND)) {
14344 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14345 "del sta event for " MACDBG "\n",
14346 MAC2STRDBG(e->addr.octet));
14347 #ifdef WL_EXT_IAPSTA
14348 wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
14349 WL_EXT_STATUS_STA_DISCONNECTED, (void *)&e->addr);
14350 #endif
14351 #ifdef STA_MGMT
14352 if (!wl_ext_del_sta_info(ndev, (u8 *)&e->addr)) {
14353 return -EINVAL;
14354 }
14355 #endif /* STA_MGMT */
14356 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
14357 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14358 ChangDelSta(ndev, e->addr.octet, 6);
14359 #endif
14360 #ifdef WL_WPS_SYNC
14361 wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet);
14362 #endif /* WL_WPS_SYNC */
14363 }
14364 #ifdef WL_CLIENT_SAE
14365 else if (event == WLC_E_AUTH && ntoh32(e->auth_type) == DOT11_SAE) {
14366 WL_MSG_RLMT(ndev->name, &e->addr, ETHER_ADDR_LEN,
14367 "add sta auth event for " MACDBG "\n",
14368 MAC2STRDBG(e->addr.octet));
14369 err = wl_handle_auth_event(cfg, ndev, e, data);
14370 }
14371 #endif /* WL_CLIENT_SAE */
14372 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && \
14373 !WL_COMPAT_WIRELESS */
14374 return err;
14375 }
14376
wl_notify_connect_status_ibss(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14377 static s32 wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg,
14378 struct net_device *ndev,
14379 const wl_event_msg_t *e, void *data)
14380 {
14381 s32 err = 0;
14382 u32 event = ntoh32(e->event_type);
14383 u16 flags = ntoh16(e->flags);
14384 u32 status = ntoh32(e->status);
14385 bool active;
14386 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14387 struct ieee80211_channel *channel = NULL;
14388 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14389 u32 chanspec, chan;
14390 u32 freq, band;
14391 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14392
14393 if (event == WLC_E_JOIN) {
14394 WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev->name));
14395 }
14396 if (event == WLC_E_START) {
14397 WL_INFORM_MEM(("[%s] started IBSS network\n", ndev->name));
14398 }
14399 if (event == WLC_E_JOIN || event == WLC_E_START ||
14400 (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
14401 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14402 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
14403 if (unlikely(err)) {
14404 WL_ERR(("Could not get chanspec %d\n", err));
14405 return err;
14406 }
14407 chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
14408 band = (chan <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ
14409 : IEEE80211_BAND_5GHZ;
14410 freq = ieee80211_channel_to_frequency(chan, band);
14411 channel = ieee80211_get_channel(wiphy, freq);
14412 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
14413 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
14414 /* ROAM or Redundant */
14415 u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14416 if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
14417 WL_DBG(("IBSS connected event from same BSSID(" MACDBG
14418 "), ignore it\n",
14419 MAC2STRDBG(cur_bssid)));
14420 return err;
14421 }
14422 WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG
14423 " to " MACDBG "\n",
14424 ndev->name, MAC2STRDBG(cur_bssid),
14425 MAC2STRDBG((const u8 *)&e->addr)));
14426 wl_get_assoc_ies(cfg, ndev);
14427 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr,
14428 WL_PROF_BSSID);
14429 wl_update_bss_info(cfg, ndev, false);
14430 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14431 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel,
14432 GFP_KERNEL);
14433 #else
14434 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
14435 #endif // endif
14436 } else {
14437 /* New connection */
14438 WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG "\n", ndev->name,
14439 MAC2STRDBG((const u8 *)&e->addr)));
14440 wl_link_up(cfg);
14441 wl_get_assoc_ies(cfg, ndev);
14442 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr,
14443 WL_PROF_BSSID);
14444 wl_update_bss_info(cfg, ndev, false);
14445 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
14446 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel,
14447 GFP_KERNEL);
14448 #else
14449 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
14450 #endif // endif
14451 wl_set_drv_status(cfg, CONNECTED, ndev);
14452 active = true;
14453 wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
14454 }
14455 } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
14456 event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
14457 wl_clr_drv_status(cfg, CONNECTED, ndev);
14458 wl_link_down(cfg);
14459 wl_init_prof(cfg, ndev);
14460 } else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
14461 WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
14462 } else {
14463 WL_DBG(("no action (IBSS mode)\n"));
14464 }
14465 return err;
14466 }
14467
wl_cfg80211_disassoc(struct net_device * ndev,uint32 reason)14468 void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason)
14469 {
14470 scb_val_t scbval;
14471 s32 err;
14472 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14473 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14474
14475 BCM_REFERENCE(cfg);
14476 BCM_REFERENCE(dhdp);
14477 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
14478 dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
14479
14480 memset_s(&scbval, sizeof(scb_val_t), 0x0, sizeof(scb_val_t));
14481 scbval.val = htod32(reason);
14482 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
14483 if (err < 0) {
14484 WL_ERR(("WLC_DISASSOC error %d\n", err));
14485 }
14486 }
wl_cfg80211_del_all_sta(struct net_device * ndev,uint32 reason)14487 void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason)
14488 {
14489 struct net_device *dev;
14490 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14491 scb_val_t scb_val;
14492 int err;
14493 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV * sizeof(struct ether_addr) +
14494 sizeof(uint)] = {0};
14495 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
14496 int num_associated = 0;
14497
14498 dev = ndev_to_wlc_ndev(ndev, cfg);
14499
14500 if (p2p_is_on(cfg)) {
14501 /* Suspend P2P discovery search-listen to prevent it from changing the
14502 * channel.
14503 */
14504 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
14505 WL_ERR(("Can not disable discovery mode\n"));
14506 return;
14507 }
14508 }
14509
14510 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
14511 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST, assoc_maclist,
14512 sizeof(mac_buf));
14513 if (err < 0) {
14514 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
14515 } else {
14516 num_associated = assoc_maclist->count;
14517 }
14518
14519 memset(scb_val.ea.octet, 0xff, ETHER_ADDR_LEN);
14520 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
14521 scb_val.val = htod32(reason);
14522 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
14523 sizeof(scb_val_t));
14524 if (err < 0) {
14525 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
14526 }
14527
14528 if (num_associated > 0) {
14529 wl_delay(0x190);
14530 }
14531
14532 return;
14533 }
14534 /* API to handle the Deauth from the AP.
14535 * For now we are deleting the PMKID cache in DHD/FW
14536 * in case of current connection is using SAE authnetication
14537 */
wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14538 static s32 wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 *cfg,
14539 struct net_device *ndev,
14540 const wl_event_msg_t *e, void *data)
14541 {
14542 int err = BCME_OK;
14543 #ifdef WL_SAE
14544 uint8 bssid[ETHER_ADDR_LEN];
14545 struct cfg80211_pmksa pmksa;
14546 s32 val = 0;
14547
14548 err = wldev_iovar_getint(ndev, "wpa_auth", &val);
14549 if (unlikely(err)) {
14550 WL_ERR(("could not get wpa_auth (%d)\n", err));
14551 goto done;
14552 }
14553 if (val == WPA3_AUTH_SAE_PSK) {
14554 (void)memcpy_s(bssid, ETHER_ADDR_LEN, (const uint8 *)&e->addr,
14555 ETHER_ADDR_LEN);
14556 memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
14557 pmksa.bssid = bssid;
14558 WL_INFORM_MEM(("Deleting the PMKSA for SAE AP " MACDBG,
14559 MAC2STRDBG(e->addr.octet)));
14560 wl_cfg80211_del_pmksa(cfg->wdev->wiphy, ndev, &pmksa);
14561 }
14562 done:
14563 #endif /* WL_SAE */
14564 return err;
14565 }
14566
wl_cache_assoc_resp_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14567 static void wl_cache_assoc_resp_ies(struct bcm_cfg80211 *cfg,
14568 struct net_device *ndev,
14569 const wl_event_msg_t *e, void *data)
14570 {
14571 struct wl_connect_info *conn_info = wl_to_conn(cfg);
14572 u32 datalen = ntoh32(e->datalen);
14573 u32 event_type = ntoh32(e->event_type);
14574
14575 if (datalen > VNDR_IE_MIN_LEN && datalen < VNDR_IE_MAX_LEN && data) {
14576 conn_info->resp_ie_len = datalen;
14577 WL_DBG((" assoc resp IES len = %d\n", conn_info->resp_ie_len));
14578 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
14579 (void)memcpy_s(conn_info->resp_ie, sizeof(conn_info->resp_ie), data,
14580 datalen);
14581
14582 WL_INFORM_MEM(("[%s] copied assoc resp ies, sent to upper layer:"
14583 "event %d reason=%d ie_len=%d from " MACDBG "\n",
14584 ndev->name, event_type, ntoh32(e->reason), datalen,
14585 MAC2STRDBG((const u8 *)(&e->addr))));
14586 }
14587 }
14588
14589 #ifdef WLMESH_CFG80211
wl_notify_connect_status_mesh(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)14590 static s32 wl_notify_connect_status_mesh(struct bcm_cfg80211 *cfg,
14591 struct net_device *ndev,
14592 const wl_event_msg_t *e, void *data)
14593 {
14594 s32 err = 0;
14595 u32 event = ntoh32(e->event_type);
14596 u32 reason = ntoh32(e->reason);
14597 u32 len = ntoh32(e->datalen);
14598 u32 status = ntoh32(e->status);
14599
14600 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14601 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14602 bool isfree = false;
14603 u8 *mgmt_frame;
14604 u8 bsscfgidx = e->bsscfgidx;
14605 s32 freq;
14606 s32 channel;
14607 u8 *body = NULL;
14608 u16 fc = 0;
14609 u32 body_len = 0;
14610
14611 struct ieee80211_supported_band *band;
14612 struct ether_addr da;
14613 struct ether_addr bssid;
14614 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14615 channel_info_t ci;
14616 u8 ioctl_buf[WLC_IOCTL_SMLEN];
14617 #else
14618 struct station_info sinfo;
14619 #endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && \
14620 !WL_COMPAT_WIRELESS */
14621
14622 WL_INFORM_MEM(("[%s] Mode Mesh. Event:%d status:%d reason:%d\n", ndev->name,
14623 event, ntoh32(e->status), reason));
14624
14625 /* if link down, bsscfg is disabled. */
14626 if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
14627 (ndev != bcmcfg_to_prmry_ndev(cfg))) {
14628 WL_MSG(ndev->name, "Mesh mode link down !! \n");
14629 return 0;
14630 }
14631
14632 if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
14633 (reason == WLC_E_REASON_INITIAL_ASSOC)) {
14634 /* AP/GO brought up successfull in firmware */
14635 WL_MSG(ndev->name, "Mesh Link up\n");
14636 return 0;
14637 }
14638
14639 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND ||
14640 event == WLC_E_DEAUTH) {
14641 WL_MSG(ndev->name, "event %s(%d) status %d reason %d\n",
14642 bcmevent_get_name(event), event, ntoh32(e->status), reason);
14643 }
14644
14645 #if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14646 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14647 WL_DBG(("Enter \n"));
14648 if (!len && (event == WLC_E_DEAUTH)) {
14649 len = 0x2; /* reason code field */
14650 data = &reason;
14651 }
14652 if (len) {
14653 body = (u8 *)MALLOCZ(cfg->osh, len);
14654 if (body == NULL) {
14655 WL_ERR(("Failed to allocate body\n"));
14656 return WL_INVALID;
14657 }
14658 }
14659 bzero(&bssid, ETHER_ADDR_LEN);
14660 WL_DBG(("Enter event %d ndev %p\n", event, ndev));
14661 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
14662 MFREE(cfg->osh, body, len);
14663 return WL_INVALID;
14664 }
14665 if (len) {
14666 memcpy(body, data, len);
14667 }
14668
14669 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", NULL, 0, ioctl_buf,
14670 sizeof(ioctl_buf), bsscfgidx, NULL);
14671 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
14672 bzero(&bssid, sizeof(bssid));
14673 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14674 switch (event) {
14675 case WLC_E_ASSOC_IND:
14676 fc = FC_ASSOC_REQ;
14677 break;
14678 case WLC_E_REASSOC_IND:
14679 fc = FC_REASSOC_REQ;
14680 break;
14681 case WLC_E_DISASSOC_IND:
14682 fc = FC_DISASSOC;
14683 break;
14684 case WLC_E_DEAUTH_IND:
14685 fc = FC_DISASSOC;
14686 break;
14687 case WLC_E_DEAUTH:
14688 fc = FC_DISASSOC;
14689 break;
14690 default:
14691 fc = 0;
14692 goto exit;
14693 }
14694 bzero(&ci, sizeof(ci));
14695 if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
14696 MFREE(cfg->osh, body, len);
14697 return err;
14698 }
14699
14700 channel = dtoh32(ci.hw_channel);
14701 if (channel <= CH_MAX_2G_CHANNEL) {
14702 band = wiphy->bands[IEEE80211_BAND_2GHZ];
14703 } else {
14704 band = wiphy->bands[IEEE80211_BAND_5GHZ];
14705 }
14706 if (!band) {
14707 WL_ERR(("No valid band\n"));
14708 if (body) {
14709 MFREE(cfg->osh, body, len);
14710 }
14711 return -EINVAL;
14712 }
14713 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && \
14714 !defined(WL_COMPAT_WIRELESS)
14715 freq = ieee80211_channel_to_frequency(channel);
14716 (void)band->band;
14717 #else
14718 freq = ieee80211_channel_to_frequency(channel, band->band);
14719 #endif // endif
14720 body_len = len;
14721 err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid, &mgmt_frame, &len,
14722 body);
14723 if (err < 0) {
14724 goto exit;
14725 }
14726 isfree = true;
14727
14728 if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
14729 (event == WLC_E_DISASSOC_IND) ||
14730 ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
14731 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14732 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
14733 #ifdef CONFIG_AP6XXX_WIFI6_HDF
14734 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame,
14735 len);
14736 #endif
14737 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14738 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
14739 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14740 defined(WL_COMPAT_WIRELESS)
14741 cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
14742 #else
14743 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
14744 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
14745 }
14746
14747 exit:
14748 if (isfree) {
14749 MFREE(cfg->osh, mgmt_frame, len);
14750 }
14751 if (body) {
14752 MFREE(cfg->osh, body, body_len);
14753 }
14754 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && \
14755 !WL_COMPAT_WIRELESS */
14756 memset(&sinfo, 0, sizeof(struct station_info));
14757 sinfo.filled = 0;
14758 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
14759 reason == DOT11_SC_SUCCESS) {
14760 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
14761 * STATION_INFO_ASSOC_REQ_IES flag
14762 */
14763 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
14764 sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
14765 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
14766 if (!data) {
14767 WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
14768 return -EINVAL;
14769 }
14770 sinfo.assoc_req_ies = data;
14771 sinfo.assoc_req_ies_len = len;
14772 WL_MSG(ndev->name, "new sta event for " MACDBG "\n",
14773 MAC2STRDBG(e->addr.octet));
14774 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
14775 } else if ((event == WLC_E_DEAUTH_IND) ||
14776 ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
14777 (event == WLC_E_DISASSOC_IND)) {
14778 WL_MSG(ndev->name, "del sta event for " MACDBG "\n",
14779 MAC2STRDBG(e->addr.octet));
14780 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
14781 }
14782 #endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && \
14783 !WL_COMPAT_WIRELESS */
14784 return err;
14785 }
14786 #endif /* WLMESH_CFG80211 */
14787
14788 #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)14789 static s32 wl_notify_connect_sta_status(struct bcm_cfg80211 *cfg,
14790 struct net_device *ndev,
14791 const wl_event_msg_t *e, void *data,
14792 bool completed,
14793 struct cfg80211_bss *bss)
14794 {
14795 uint8_t *curbssid = NULL;
14796 uint16_t connectStatus = 0;
14797 uint16_t freq = 0;
14798 struct wl_connect_info *conn_info = NULL;
14799 conn_info = wl_to_conn(cfg);
14800 curbssid = (uint8_t *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
14801
14802 if (completed) {
14803 connectStatus = 0;
14804 } else {
14805 connectStatus = 1;
14806 }
14807
14808 if (bss != NULL) {
14809 if (bss->channel != NULL) {
14810 freq = bss->channel->center_freq;
14811 }
14812 }
14813
14814 HdfConnectResultEventCallback(ndev, curbssid, conn_info->req_ie,
14815 conn_info->resp_ie, conn_info->req_ie_len,
14816 conn_info->resp_ie_len, connectStatus, freq);
14817
14818 return 0;
14819 }
14820 #endif
14821
wl_notify_connect_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)14822 static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
14823 bcm_struct_cfgdev *cfgdev,
14824 const wl_event_msg_t *e, void *data)
14825 {
14826 bool act;
14827 struct net_device *ndev = NULL;
14828 s32 err = 0;
14829 u32 event = ntoh32(e->event_type);
14830 u32 datalen = ntoh32(e->datalen);
14831 struct wiphy *wiphy = NULL;
14832 struct cfg80211_bss *bss = NULL;
14833 struct wlc_ssid *ssid = NULL;
14834 u8 *bssid = 0;
14835 s32 bssidx = 0;
14836 u8 *ie_ptr = NULL;
14837 uint32 ie_len = 0;
14838 #ifdef WL_ANALYTICS
14839 struct parsed_vndr_ies disco_vndr_ie;
14840 struct parsed_vndr_ie_info *vndrie_info = NULL;
14841 uint32 i = 0;
14842 #endif /* WL_ANALYTICS */
14843
14844 dhd_pub_t *dhdp;
14845 u32 mode;
14846 int vndr_oui_num = 0;
14847 char vndr_oui[MAX_VNDR_OUI_STR_LEN] = {
14848 0,
14849 };
14850 bool loc_gen = false;
14851 #ifdef DHD_LOSSLESS_ROAMING
14852 struct wl_security *sec;
14853 #endif /* DHD_LOSSLESS_ROAMING */
14854
14855 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14856 #ifdef DHD_LOSSLESS_ROAMING
14857 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14858 #endif /* DHD_LOSSLESS_ROAMING */
14859 dhdp = (dhd_pub_t *)(cfg->pub);
14860 BCM_REFERENCE(dhdp);
14861
14862 mode = wl_get_mode_by_netdev(cfg, ndev);
14863 /* Push link events to upper layer log */
14864 SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n", ndev->name, mode,
14865 ntoh32(e->event_type), ntoh32(e->status), ntoh32(e->reason)));
14866 if (mode == WL_MODE_AP) {
14867 err = wl_notify_connect_status_ap(cfg, ndev, e, data);
14868 #ifdef WLMESH_CFG80211
14869 } else if (mode == WL_MODE_MESH) {
14870 err = wl_notify_connect_status_mesh(cfg, ndev, e, data);
14871 #endif /* WLMESH_CFG80211 */
14872 } else if (mode == WL_MODE_IBSS) {
14873 err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
14874 } else if (mode == WL_MODE_BSS) {
14875 WL_INFORM_MEM(("[%s] Mode BSS. event:%d status:%d reason:%d\n",
14876 ndev->name, ntoh32(e->event_type), ntoh32(e->status),
14877 ntoh32(e->reason)));
14878
14879 if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
14880 /* Join attempt via non-cfg80211 interface.
14881 * Don't send resultant events to cfg80211
14882 * layer
14883 */
14884 WL_INFORM_MEM(("Event received in non-cfg80211"
14885 " connect state. Ignore\n"));
14886 return BCME_OK;
14887 }
14888
14889 if (event == WLC_E_ASSOC || event == WLC_E_AUTH) {
14890 wl_get_auth_assoc_status(cfg, ndev, e, data);
14891 return 0;
14892 }
14893 if (event == WLC_E_ASSOC_RESP_IE) {
14894 if (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) {
14895 wl_cache_assoc_resp_ies(cfg, ndev, e, data);
14896 }
14897 return 0;
14898 }
14899
14900 DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
14901 if (wl_is_linkup(cfg, e, ndev)) {
14902 wl_link_up(cfg);
14903 act = true;
14904 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
14905 WL_INFORM_MEM(("[%s] link up for bssid " MACDBG "\n",
14906 ndev->name, MAC2STRDBG((const u8 *)(&e->addr))));
14907 if ((event == WLC_E_LINK) &&
14908 (ntoh16(e->flags) & WLC_EVENT_MSG_LINK) &&
14909 !wl_get_drv_status(cfg, CONNECTED, ndev) &&
14910 !wl_get_drv_status(cfg, CONNECTING, ndev)) {
14911 WL_INFORM_MEM(("link up in non-connected/"
14912 "non-connecting state\n"));
14913 wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
14914 return BCME_OK;
14915 }
14916
14917 #ifdef WL_WPS_SYNC
14918 /* Avoid invocation for Roam cases */
14919 if ((event == WLC_E_LINK) &&
14920 !wl_get_drv_status(cfg, CONNECTED, ndev)) {
14921 wl_wps_session_update(ndev, WPS_STATE_LINKUP,
14922 e->addr.octet);
14923 }
14924 #endif /* WL_WPS_SYNC */
14925
14926 if (event == WLC_E_LINK &&
14927 #ifdef DHD_LOSSLESS_ROAMING
14928 !cfg->roam_offload && !IS_AKM_SUITE_FT(sec) &&
14929 #endif /* DHD_LOSSLESS_ROAMING */
14930 wl_get_drv_status(cfg, CONNECTED, ndev)) {
14931 wl_bss_roaming_done(cfg, ndev, e, data);
14932 /* Arm pkt logging timer */
14933 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
14934 } else {
14935 /* Initial Association */
14936 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
14937 wl_bss_connect_done(cfg, ndev, e, data, true);
14938 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
14939 vndr_oui_num = wl_vndr_ies_get_vendor_oui(
14940 cfg, ndev, vndr_oui, ARRAY_SIZE(vndr_oui));
14941 if (vndr_oui_num > 0) {
14942 WL_INFORM_MEM(("[%s] vendor oui: %s\n", ndev->name,
14943 vndr_oui));
14944 }
14945 }
14946 if (event == WLC_E_LINK) {
14947 /* Arm pkt logging timer */
14948 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_CONNECT);
14949 }
14950 WL_DBG(("joined in BSS network \"%s\"\n",
14951 ((struct wlc_ssid *)wl_read_prof(cfg, ndev,
14952 WL_PROF_SSID))
14953 ->SSID));
14954 }
14955 }
14956 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
14957 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr,
14958 WL_PROF_BSSID);
14959 } else if (wl_is_linkdown(cfg, e) ||
14960 ((event == WLC_E_SET_SSID) &&
14961 (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) &&
14962 (wl_get_drv_status(cfg, CONNECTED, ndev)))) {
14963 if (wl_is_linkdown(cfg, e)) {
14964 /* Clear IEs for disaasoc */
14965 if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) <
14966 0) {
14967 WL_ERR(("Find index failed\n"));
14968 } else {
14969 WL_ERR(("link down--clearing disconnect IEs\n"));
14970 if ((err = wl_cfg80211_set_mgmt_vndr_ies(
14971 cfg, ndev_to_cfgdev(ndev), bssidx,
14972 VNDR_IE_DISASSOC_FLAG, NULL, 0)) != BCME_OK) {
14973 WL_ERR(("Failed to clear ies err = %d\n", err));
14974 }
14975 }
14976 }
14977
14978 WL_INFORM_MEM(
14979 ("link down. connection state bit status: [%u:%u:%u:%u]\n",
14980 wl_get_drv_status(cfg, CONNECTING, ndev),
14981 wl_get_drv_status(cfg, CONNECTED, ndev),
14982 wl_get_drv_status(cfg, DISCONNECTING, ndev),
14983 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
14984
14985 #ifdef WL_WPS_SYNC
14986 {
14987 u8 wps_state;
14988 if ((event == WLC_E_SET_SSID) &&
14989 (ntoh32(e->status) != WLC_E_STATUS_SUCCESS)) {
14990 /* connect fail */
14991 wps_state = WPS_STATE_CONNECT_FAIL;
14992 } else {
14993 wps_state = WPS_STATE_LINKDOWN;
14994 }
14995 if (wl_wps_session_update(ndev, wps_state, e->addr.octet) ==
14996 BCME_UNSUPPORTED) {
14997 /* Unexpected event. Ignore it. */
14998 return 0;
14999 }
15000 }
15001 #endif /* WL_WPS_SYNC */
15002
15003 if (wl_get_drv_status(cfg, DISCONNECTING, ndev) &&
15004 (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) ||
15005 wl_get_drv_status(cfg, CONNECTING, ndev))) {
15006 /* wl_cfg80211_connect was called before 'DISCONNECTING' was
15007 * cleared. Deauth/Link down event is caused by WLC_DISASSOC
15008 * command issued from the wl_cfg80211_connect context. Ignore
15009 * the event to avoid pre-empting the current connection
15010 */
15011 WL_DBG(("Nested connection case. Drop event. \n"));
15012 #if defined(BSSCACHE)
15013 wl_delete_disconnected_bss_cache(&cfg->g_bss_cache_ctrl,
15014 (u8 *)(&e->addr));
15015 #endif
15016 #ifdef WL_EXT_IAPSTA
15017 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY | STA_NO_BTC_IN4WAY,
15018 WL_EXT_STATUS_DISCONNECTED, NULL);
15019 wl_ext_iapsta_restart_master(ndev);
15020 #endif
15021 wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
15022 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15023 /* Not in 'CONNECTED' state, clear it */
15024 wl_clr_drv_status(cfg, CONNECTED, ndev);
15025 return 0;
15026 }
15027
15028 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15029 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
15030 FW_LOGSET_MASK_ALL);
15031 }
15032 #ifdef DHD_LOSSLESS_ROAMING
15033 wl_del_roam_timeout(cfg);
15034 #endif // endif
15035 #ifdef P2PLISTEN_AP_SAMECHN
15036 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15037 wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0);
15038 cfg->p2p_resp_apchn_status = false;
15039 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
15040 }
15041 #endif /* P2PLISTEN_AP_SAMECHN */
15042 wl_cfg80211_cancel_scan(cfg);
15043
15044 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15045 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15046 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
15047 bool fw_assoc_state = TRUE;
15048 dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
15049 fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
15050 if (!fw_assoc_state) {
15051 WL_ERR(("Event sends up even different BSSID"
15052 " cur: " MACDBG " event: " MACDBG "\n",
15053 MAC2STRDBG(curbssid),
15054 MAC2STRDBG((const u8 *)(&e->addr))));
15055 } else {
15056 WL_ERR(("BSSID of event is not the connected BSSID"
15057 "(ignore it) cur: " MACDBG " event: " MACDBG
15058 "\n",
15059 MAC2STRDBG(curbssid),
15060 MAC2STRDBG((const u8 *)(&e->addr))));
15061 return 0;
15062 }
15063 }
15064 }
15065 /* Explicitly calling unlink to remove BSS in CFG */
15066 wiphy = bcmcfg_to_wiphy(cfg);
15067 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
15068 bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15069 if (ssid && bssid) {
15070 bss = CFG80211_GET_BSS(wiphy, NULL, bssid, ssid->SSID,
15071 ssid->SSID_len);
15072 if (bss) {
15073 cfg80211_unlink_bss(wiphy, bss);
15074 CFG80211_PUT_BSS(wiphy, bss);
15075 }
15076 }
15077
15078 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15079 scb_val_t scbval;
15080 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15081 uint32 reason = 0;
15082 struct ether_addr bssid_dongle = {{0, 0, 0, 0, 0, 0}};
15083 struct ether_addr bssid_null = {{0, 0, 0, 0, 0, 0}};
15084
15085 if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
15086 reason = ntoh32(e->reason);
15087 if (reason > WLC_E_DEAUTH_MAX_REASON) {
15088 WL_ERR(("Event %d original reason is %d, "
15089 "changed 0xFF\n",
15090 event, reason));
15091 reason = WLC_E_DEAUTH_MAX_REASON;
15092 }
15093 wl_cfg80211_handle_deauth_ind(cfg, ndev, e, data);
15094 }
15095 #ifdef WL_EXT_IAPSTA
15096 wl_ext_iapsta_restart_master(ndev);
15097 #endif
15098 #ifdef SET_SSID_FAIL_CUSTOM_RC
15099 if ((event == WLC_E_SET_SSID) &&
15100 (ntoh32(e->status) == WLC_E_STATUS_TIMEOUT)) {
15101 reason = SET_SSID_FAIL_CUSTOM_RC;
15102 }
15103 #endif /* SET_SSID_FAIL_CUSTOM_RC */
15104
15105 /* roam offload does not sync BSSID always, get it from dongle
15106 */
15107 if (cfg->roam_offload) {
15108 bzero(&bssid_dongle, sizeof(bssid_dongle));
15109 if (wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid_dongle,
15110 sizeof(bssid_dongle)) == BCME_OK) {
15111 /* if not roam case, it would return null bssid */
15112 if (memcmp(&bssid_dongle, &bssid_null,
15113 ETHER_ADDR_LEN) != 0) {
15114 curbssid = (u8 *)&bssid_dongle;
15115 }
15116 }
15117 }
15118 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
15119 bool fw_assoc_state = TRUE;
15120 dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
15121 fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
15122 if (!fw_assoc_state) {
15123 WL_ERR(("Event sends up even different BSSID"
15124 " cur: " MACDBG " event: " MACDBG "\n",
15125 MAC2STRDBG(curbssid),
15126 MAC2STRDBG((const u8 *)(&e->addr))));
15127 } else {
15128 WL_ERR(("BSSID of event is not the connected BSSID"
15129 "(ignore it) cur: " MACDBG " event: " MACDBG
15130 "\n",
15131 MAC2STRDBG(curbssid),
15132 MAC2STRDBG((const u8 *)(&e->addr))));
15133 return 0;
15134 }
15135 }
15136 #ifdef DBG_PKT_MON
15137 /* Stop packet monitor */
15138 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15139 DHD_DBG_PKT_MON_STOP(dhdp);
15140 }
15141 #endif /* DBG_PKT_MON */
15142 /* clear RSSI monitor, framework will set new cfg */
15143 #ifdef RSSI_MONITOR_SUPPORT
15144 dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg), FALSE,
15145 0, 0);
15146 #endif /* RSSI_MONITOR_SUPPORT */
15147 wl_clr_drv_status(cfg, CONNECTED, ndev);
15148
15149 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15150 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15151 dhd_net2idx(dhdp->info, ndev),
15152 WLAN_REASON_DEAUTH_LEAVING);
15153 /* To make sure disconnect, explictly send dissassoc
15154 * for BSSID 00:00:00:00:00:00 issue
15155 */
15156 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
15157 WL_INFORM_MEM(("clear fw state\n"));
15158 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
15159 scbval.val = htod32(scbval.val);
15160 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
15161 sizeof(scb_val_t));
15162 if (err < 0) {
15163 WL_ERR(("WLC_DISASSOC error %d\n", err));
15164 err = 0;
15165 }
15166 }
15167 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15168 loc_gen = true;
15169 }
15170 WL_INFORM_MEM(("[%s] Indicate disconnect event to upper layer. "
15171 "event: %d reason=%d from " MACDBG "\n",
15172 ndev->name, event, ntoh32(e->reason),
15173 MAC2STRDBG((const u8 *)(&e->addr))));
15174
15175 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_DONE),
15176 dhd_net2idx(dhdp->info, ndev), reason);
15177 /* Send up deauth and clear states */
15178
15179 /*
15180 * FW sends body and body len as a part of deauth
15181 * and disassoc events (WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND)
15182 * The VIEs sits after reason code in the body. Reason code is
15183 * 2 bytes long.
15184 */
15185 WL_DBG(("recv disconnect ies ie_len = %d\n", ie_len));
15186 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND) {
15187 if ((datalen > DOT11_DISCONNECT_RC) &&
15188 datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
15189 data) {
15190 ie_ptr = (uchar *)data + DOT11_DISCONNECT_RC;
15191 ie_len = datalen - DOT11_DISCONNECT_RC;
15192 }
15193 } else if (event == WLC_E_LINK &&
15194 ntoh32(e->reason) == WLC_E_LINK_BCN_LOSS) {
15195 #ifdef WL_ANALYTICS
15196 /*
15197 * In case of linkdown, FW sends prb rsp IEs. Disco VIE
15198 * are appended with prb rsp ies. Remove prb rsp IES and
15199 * send disco vie to upper layer.
15200 * Disco VIE has fixed len of 11 octets.
15201 * As per SS spec.(2 octet header + 9 octet VIE)
15202 */
15203 if (datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
15204 datalen >= DOT11_DISCONNECT_RC &&
15205 ((err = wl_cfg80211_parse_vndr_ies(
15206 (const u8 *)data, datalen, &disco_vndr_ie)) == BCME_OK)) {
15207 for (i = 0; i < disco_vndr_ie.count; i++) {
15208 vndrie_info = &disco_vndr_ie.ie_info[i];
15209 if ((vndrie_info->vndrie.id == 0xDD) &&
15210 (!memcmp(vndrie_info->vndrie.oui, SSE_OUI,
15211 DOT11_OUI_LEN)) &&
15212 (vndrie_info->vndrie.data[0] ==
15213 VENDOR_ENTERPRISE_STA_OUI_TYPE)) {
15214 ie_ptr = (u8 *)vndrie_info->ie_ptr;
15215 ie_len = vndrie_info->ie_len;
15216 }
15217 }
15218 }
15219 #endif /* WL_ANALYTICS */
15220 }
15221
15222 #ifdef CONFIG_AP6XXX_WIFI6_HDF
15223 HdfDisconnectedEventCallback(ndev, reason, ie_ptr, ie_len);
15224 #endif
15225 CFG80211_DISCONNECTED(ndev, reason, ie_ptr, ie_len, loc_gen,
15226 GFP_KERNEL);
15227 WL_INFORM_MEM(("[%s] Disconnect event sent to upper layer"
15228 "event:%d reason=%d ie_len=%d from " MACDBG "\n",
15229 ndev->name, event, ntoh32(e->reason), ie_len,
15230 MAC2STRDBG((const u8 *)(&e->addr))));
15231
15232 /* Wait for status to be cleared to prevent race condition
15233 * issues with connect context
15234 */
15235 wl_cfg80211_disconnect_state_sync(cfg, ndev);
15236 wl_link_down(cfg);
15237 wl_init_prof(cfg, ndev);
15238 } else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
15239 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15240 dhd_net2idx(dhdp->info, ndev), 0);
15241 WL_INFORM_MEM(("link down, during connecting\n"));
15242 /* Issue WLC_DISASSOC to prevent FW roam attempts.
15243 * Do not issue WLC_DISASSOC again if the linkdown is
15244 * generated due to local disassoc, to avoid connect-disconnect
15245 * loop.
15246 */
15247 if (!((event == WLC_E_LINK) &&
15248 (ntoh32(e->reason) == WLC_E_LINK_DISASSOC) &&
15249 (ntoh32(e->status) == WLC_E_STATUS_SUCCESS))) {
15250 err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
15251 if (err < 0) {
15252 WL_ERR(("CONNECTING state,"
15253 " WLC_DISASSOC error %d\n",
15254 err));
15255 err = 0;
15256 }
15257 #ifdef ESCAN_RESULT_PATCH
15258 if ((memcmp(connect_req_bssid, broad_bssid,
15259 ETHER_ADDR_LEN) == 0) ||
15260 (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) ||
15261 (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) ==
15262 0))
15263 /* In case this event comes while associating
15264 * another AP
15265 */
15266 #endif /* ESCAN_RESULT_PATCH */
15267 wl_bss_connect_done(cfg, ndev, e, data, false);
15268 }
15269 }
15270 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15271 #if defined(BSSCACHE)
15272 wl_delete_disconnected_bss_cache(&cfg->g_bss_cache_ctrl,
15273 (u8 *)(&e->addr));
15274 #endif
15275 #ifdef WL_EXT_IAPSTA
15276 {
15277 wl_event_msg_t emsg;
15278 memcpy(&emsg, e, sizeof(wl_event_msg_t));
15279 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY | STA_NO_BTC_IN4WAY,
15280 WL_EXT_STATUS_DISCONNECTED, &emsg);
15281 }
15282 #endif
15283
15284 /* if link down, bsscfg is diabled */
15285 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
15286 complete(&cfg->iface_disable);
15287 }
15288 #ifdef WLTDLS
15289 /* re-enable TDLS if the number of connected interfaces
15290 * is less than 2.
15291 */
15292 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
15293 #endif /* WLTDLS */
15294 } else if (wl_is_nonetwork(cfg, e)) {
15295 WL_ERR(("connect failed event=%d e->status %d e->reason %d \n",
15296 event, (int)ntoh32(e->status), (int)ntoh32(e->reason)));
15297 #if defined(BSSCACHE)
15298 wl_delete_disconnected_bss_cache(&cfg->g_bss_cache_ctrl,
15299 (u8 *)(&e->addr));
15300 #endif
15301 #ifdef WL_EXT_IAPSTA
15302 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY | STA_NO_BTC_IN4WAY,
15303 WL_EXT_STATUS_DISCONNECTED, NULL);
15304 wl_ext_iapsta_enable_master_if(ndev, FALSE);
15305 #endif
15306 #ifdef WL_WPS_SYNC
15307 if (wl_wps_session_update(ndev, WPS_STATE_CONNECT_FAIL,
15308 e->addr.octet) == BCME_UNSUPPORTED) {
15309 /* Unexpected event. Ignore it. */
15310 return 0;
15311 }
15312 #endif /* WL_WPS_SYNC */
15313 /* Dump FW preserve buffer content */
15314 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
15315
15316 /* Clean up any pending scan request */
15317 wl_cfg80211_cancel_scan(cfg);
15318
15319 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
15320 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15321 WL_INFORM_MEM(("wl dissassoc\n"));
15322 err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
15323 if (err < 0) {
15324 WL_ERR(("WLC_DISASSOC error %d\n", err));
15325 err = 0;
15326 }
15327 } else {
15328 WL_DBG(("connect fail. clear disconnecting bit\n"));
15329 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15330 }
15331 wl_bss_connect_done(cfg, ndev, e, data, false);
15332 wl_clr_drv_status(cfg, CONNECTING, ndev);
15333 WL_INFORM_MEM(("connect fail reported\n"));
15334 }
15335 } else {
15336 WL_DBG(("%s nothing\n", __FUNCTION__));
15337 }
15338 DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
15339 } else {
15340 WL_MSG(ndev->name, "Invalid mode %d event %d status %d\n",
15341 wl_get_mode_by_netdev(cfg, ndev), ntoh32(e->event_type),
15342 ntoh32(e->status));
15343 }
15344 return err;
15345 }
15346
15347 #ifdef WL_RELMCAST
wl_cfg80211_set_rmc_pid(struct net_device * dev,int pid)15348 void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
15349 {
15350 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
15351 if (pid > 0) {
15352 cfg->rmc_event_pid = pid;
15353 }
15354 WL_DBG(("set pid for rmc event : pid=%d\n", pid));
15355 }
15356 #endif /* WL_RELMCAST */
15357
15358 #ifdef WL_RELMCAST
wl_notify_rmc_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15359 static s32 wl_notify_rmc_status(struct bcm_cfg80211 *cfg,
15360 bcm_struct_cfgdev *cfgdev,
15361 const wl_event_msg_t *e, void *data)
15362 {
15363 u32 evt = ntoh32(e->event_type);
15364 u32 reason = ntoh32(e->reason);
15365 int ret = -1;
15366
15367 switch (reason) {
15368 case WLC_E_REASON_RMC_AR_LOST:
15369 case WLC_E_REASON_RMC_AR_NO_ACK:
15370 if (cfg->rmc_event_pid != 0) {
15371 ret = wl_netlink_send_msg(cfg->rmc_event_pid,
15372 RMC_EVENT_LEADER_CHECK_FAIL,
15373 cfg->rmc_event_seq++, NULL, 0);
15374 }
15375 break;
15376 default:
15377 break;
15378 }
15379 WL_DBG(
15380 ("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
15381 return ret;
15382 }
15383 #endif /* WL_RELMCAST */
15384
15385 #ifdef GSCAN_SUPPORT
wl_handle_roam_exp_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15386 static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg,
15387 bcm_struct_cfgdev *cfgdev,
15388 const wl_event_msg_t *e, void *data)
15389 {
15390 struct net_device *ndev = NULL;
15391 u32 datalen = be32_to_cpu(e->datalen);
15392 if (datalen) {
15393 wl_roam_exp_event_t *evt_data = (wl_roam_exp_event_t *)data;
15394 if (evt_data->version == ROAM_EXP_EVENT_VERSION) {
15395 wlc_ssid_t *ssid = &evt_data->cur_ssid;
15396 struct wireless_dev *wdev;
15397 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15398 if (ndev) {
15399 wdev = ndev->ieee80211_ptr;
15400 wdev->ssid_len =
15401 min(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN);
15402 memcpy(wdev->ssid, ssid->SSID, wdev->ssid_len);
15403 WL_ERR(("SSID is %s\n", ssid->SSID));
15404 wl_update_prof(cfg, ndev, NULL, ssid, WL_PROF_SSID);
15405 } else {
15406 WL_ERR(("NULL ndev!\n"));
15407 }
15408 } else {
15409 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
15410 ROAM_EXP_EVENT_VERSION));
15411 }
15412 }
15413 return BCME_OK;
15414 }
15415 #endif /* GSCAN_SUPPORT */
15416
15417 #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)15418 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg,
15419 bcm_struct_cfgdev *cfgdev,
15420 const wl_event_msg_t *e, void *data)
15421 {
15422 #if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
15423 u32 datalen = be32_to_cpu(e->datalen);
15424 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15425 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15426 if (datalen) {
15427 wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data;
15428 if (evt_data->version == RSSI_MONITOR_VERSION) {
15429 dhd_rssi_monitor_evt_t monitor_data;
15430 monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION;
15431 monitor_data.cur_rssi = evt_data->cur_rssi;
15432 memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN);
15433 wl_cfgvendor_send_async_event(wiphy, ndev,
15434 GOOGLE_RSSI_MONITOR_EVENT,
15435 &monitor_data, sizeof(monitor_data));
15436 } else {
15437 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
15438 RSSI_MONITOR_VERSION));
15439 }
15440 }
15441 #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
15442 return BCME_OK;
15443 }
15444 #endif /* RSSI_MONITOR_SUPPORT */
15445
wl_notify_roaming_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15446 static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
15447 bcm_struct_cfgdev *cfgdev,
15448 const wl_event_msg_t *e, void *data)
15449 {
15450 bool act;
15451 struct net_device *ndev = NULL;
15452 s32 err = 0;
15453 u32 event = be32_to_cpu(e->event_type);
15454 u32 status = be32_to_cpu(e->status);
15455 #ifdef DHD_LOSSLESS_ROAMING
15456 struct wl_security *sec;
15457 #endif // endif
15458 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15459 WL_DBG(("Enter \n"));
15460
15461 BCM_REFERENCE(dhdp);
15462 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15463
15464 if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
15465 wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
15466 cfg->disable_roam_event = TRUE;
15467 }
15468
15469 if ((cfg->disable_roam_event) && (event == WLC_E_ROAM)) {
15470 return err;
15471 }
15472
15473 if ((event == WLC_E_ROAM || event == WLC_E_BSSID) &&
15474 status == WLC_E_STATUS_SUCCESS) {
15475 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15476 #ifdef DHD_LOSSLESS_ROAMING
15477 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15478 /* In order to reduce roaming delay, wl_bss_roaming_done is
15479 * early called with WLC_E_LINK event. It is called from
15480 * here only if WLC_E_LINK event is blocked for specific
15481 * security type.
15482 */
15483 if (IS_AKM_SUITE_FT(sec)) {
15484 wl_bss_roaming_done(cfg, ndev, e, data);
15485 /* Arm pkt logging timer */
15486 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
15487 }
15488 /* Roam timer is deleted mostly from wl_cfg80211_change_station
15489 * after roaming is finished successfully. We need to delete
15490 * the timer from here only for some security types that aren't
15491 * using wl_cfg80211_change_station to authorize SCB
15492 */
15493 if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
15494 wl_del_roam_timeout(cfg);
15495 }
15496 #else
15497 #if !defined(DHD_NONFT_ROAMING)
15498 wl_bss_roaming_done(cfg, ndev, e, data);
15499 #endif /* !DHD_NONFT_ROAMING */
15500 #endif /* DHD_LOSSLESS_ROAMING */
15501 } else {
15502 wl_bss_connect_done(cfg, ndev, e, data, true);
15503 }
15504 act = true;
15505 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
15506 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
15507
15508 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15509 wl_vndr_ies_get_vendor_oui(cfg, ndev, NULL, 0);
15510 }
15511 }
15512 #ifdef DHD_LOSSLESS_ROAMING
15513 else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) &&
15514 status != WLC_E_STATUS_SUCCESS) {
15515 wl_del_roam_timeout(cfg);
15516 }
15517 #endif // endif
15518 return err;
15519 }
15520
15521 #ifdef CUSTOM_EVENT_PM_WAKE
15522 uint32 last_dpm_upd_time = 0; /* ms */
15523 #define DPM_UPD_LMT_TIME ((CUSTOM_EVENT_PM_WAKE + (5)) * (1000) * (4)) /* ms \
15524 */
15525 #define DPM_UPD_LMT_RSSI -85 /* dbm */
15526
wl_check_pmstatus(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15527 static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg,
15528 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e,
15529 void *data)
15530 {
15531 s32 err = BCME_OK;
15532 struct net_device *ndev = NULL;
15533 u8 *pbuf = NULL;
15534 uint32 cur_dpm_upd_time = 0;
15535 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
15536 s32 rssi;
15537 #ifdef SUPPORT_RSSI_SUM_REPORT
15538 wl_rssi_ant_mimo_t rssi_ant_mimo;
15539 #endif /* SUPPORT_RSSI_SUM_REPORT */
15540 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15541
15542 pbuf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
15543 if (pbuf == NULL) {
15544 WL_ERR(("failed to allocate local pbuf\n"));
15545 return -ENOMEM;
15546 }
15547
15548 err = wldev_iovar_getbuf_bsscfg(ndev, "dump", "pm", strlen("pm"), pbuf,
15549 WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
15550 if (err) {
15551 WL_ERR(("dump ioctl err = %d", err));
15552 } else {
15553 WL_ERR(("PM status : %s\n", pbuf));
15554 }
15555 if (pbuf) {
15556 MFREE(cfg->osh, pbuf, WLC_IOCTL_MEDLEN);
15557 }
15558
15559 if (dhd->early_suspended) {
15560 /* LCD off */
15561 #ifdef SUPPORT_RSSI_SUM_REPORT
15562 /* Query RSSI sum across antennas */
15563 memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
15564 err = wl_get_rssi_per_ant(ndev, ndev->name, NULL, &rssi_ant_mimo);
15565 if (err) {
15566 WL_ERR(("Could not get rssi sum (%d)\n", err));
15567 }
15568 rssi = rssi_ant_mimo.rssi_sum;
15569 if (rssi == 0)
15570 #endif /* SUPPORT_RSSI_SUM_REPORT */
15571 {
15572 scb_val_t scb_val;
15573 memset(&scb_val, 0, sizeof(scb_val_t));
15574 scb_val.val = 0;
15575 err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val,
15576 sizeof(scb_val_t));
15577 if (err) {
15578 WL_ERR(("Could not get rssi (%d)\n", err));
15579 }
15580 #if defined(RSSIOFFSET)
15581 rssi = wl_update_rssi_offset(ndev, dtoh32(scb_val.val));
15582 #else
15583 rssi = dtoh32(scb_val.val);
15584 #endif
15585 }
15586 WL_ERR(("RSSI %d dBm\n", rssi));
15587 if (rssi > DPM_UPD_LMT_RSSI) {
15588 return err;
15589 }
15590 } else {
15591 /* LCD on */
15592 return err;
15593 }
15594
15595 if (last_dpm_upd_time == 0) {
15596 last_dpm_upd_time = OSL_SYSUPTIME();
15597 } else {
15598 cur_dpm_upd_time = OSL_SYSUPTIME();
15599 if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) {
15600 scb_val_t scbval;
15601 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
15602 dhd_net2idx(dhd->info, ndev), 0);
15603 bzero(&scbval, sizeof(scb_val_t));
15604
15605 err =
15606 wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
15607 if (err < 0) {
15608 WL_ERR(("Disassoc error %d\n", err));
15609 return err;
15610 }
15611 WL_ERR(("Force Disassoc due to updated DPM event.\n"));
15612
15613 last_dpm_upd_time = 0;
15614 } else {
15615 last_dpm_upd_time = cur_dpm_upd_time;
15616 }
15617 }
15618
15619 return err;
15620 }
15621 #endif /* CUSTOM_EVENT_PM_WAKE */
15622
15623 #ifdef QOS_MAP_SET
15624 /* get user priority table */
wl_get_up_table(dhd_pub_t * dhdp,int idx)15625 uint8 *wl_get_up_table(dhd_pub_t *dhdp, int idx)
15626 {
15627 struct net_device *ndev;
15628 struct bcm_cfg80211 *cfg;
15629
15630 ndev = dhd_idx2net(dhdp, idx);
15631 if (ndev) {
15632 cfg = wl_get_cfg(ndev);
15633 if (cfg) {
15634 return (uint8 *)(cfg->up_table);
15635 }
15636 }
15637
15638 return NULL;
15639 }
15640 #endif /* QOS_MAP_SET */
15641
15642 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
wl_notify_roam_prep_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15643 static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
15644 bcm_struct_cfgdev *cfgdev,
15645 const wl_event_msg_t *e, void *data)
15646 {
15647 struct wl_security *sec;
15648 struct net_device *ndev;
15649 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15650 u32 status = ntoh32(e->status);
15651 u32 reason = ntoh32(e->reason);
15652
15653 BCM_REFERENCE(sec);
15654
15655 if (status == WLC_E_STATUS_SUCCESS &&
15656 reason != WLC_E_REASON_INITIAL_ASSOC) {
15657 WL_ERR(("Attempting roam with reason code : %d\n", reason));
15658 }
15659
15660 #ifdef CONFIG_SILENT_ROAM
15661 if (dhdp->in_suspend && reason == WLC_E_REASON_SILENT_ROAM) {
15662 dhdp->sroamed = TRUE;
15663 }
15664 #endif /* CONFIG_SILENT_ROAM */
15665
15666 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15667 #ifdef DBG_PKT_MON
15668 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15669 DHD_DBG_PKT_MON_STOP(dhdp);
15670 DHD_DBG_PKT_MON_START(dhdp);
15671 }
15672 #endif /* DBG_PKT_MON */
15673 #ifdef DHD_LOSSLESS_ROAMING
15674 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15675 /* Disable Lossless Roaming for specific AKM suite
15676 * Any other AKM suite can be added below if transition time
15677 * is delayed because of Lossless Roaming
15678 * and it causes any certication failure
15679 */
15680 if (IS_AKM_SUITE_FT(sec)) {
15681 return BCME_OK;
15682 }
15683
15684 dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC;
15685 /* Restore flow control */
15686 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
15687
15688 mod_timer(&cfg->roam_timeout,
15689 jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
15690 #endif /* DHD_LOSSLESS_ROAMING */
15691
15692 return BCME_OK;
15693 }
15694 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
15695
wl_notify_roam_start_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)15696 static s32 wl_notify_roam_start_status(struct bcm_cfg80211 *cfg,
15697 bcm_struct_cfgdev *cfgdev,
15698 const wl_event_msg_t *e, void *data)
15699 {
15700 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || \
15701 defined(WL_VENDOR_EXT_SUPPORT)
15702 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15703 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15704 int event_type;
15705
15706 event_type = WIFI_EVENT_ROAM_SCAN_STARTED;
15707 wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_ROAM_EVENT_START,
15708 &event_type, sizeof(int));
15709 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || \
15710 (WL_VENDOR_EXT_SUPPORT) */
15711
15712 return BCME_OK;
15713 }
15714
wl_get_assoc_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev)15715 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
15716 {
15717 wl_assoc_info_t assoc_info;
15718 struct wl_connect_info *conn_info = wl_to_conn(cfg);
15719 s32 err = 0;
15720 #ifdef QOS_MAP_SET
15721 bcm_tlv_t *qos_map_ie = NULL;
15722 #endif /* QOS_MAP_SET */
15723
15724 WL_DBG(("Enter \n"));
15725 err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
15726 WL_ASSOC_INFO_MAX, NULL);
15727 if (unlikely(err)) {
15728 WL_ERR(("could not get assoc info (%d)\n", err));
15729 return err;
15730 }
15731 memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
15732 assoc_info.req_len = htod32(assoc_info.req_len);
15733 assoc_info.resp_len = htod32(assoc_info.resp_len);
15734 assoc_info.flags = htod32(assoc_info.flags);
15735 if (conn_info->req_ie_len) {
15736 conn_info->req_ie_len = 0;
15737 bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
15738 }
15739 if (conn_info->resp_ie_len) {
15740 conn_info->resp_ie_len = 0;
15741 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
15742 }
15743
15744 if (assoc_info.req_len) {
15745 err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
15746 assoc_info.req_len, NULL);
15747 if (unlikely(err)) {
15748 WL_ERR(("could not get assoc req (%d)\n", err));
15749 return err;
15750 }
15751 if (assoc_info.req_len < sizeof(struct dot11_assoc_req)) {
15752 WL_ERR(("req_len %d lessthan %d \n", assoc_info.req_len,
15753 (int)sizeof(struct dot11_assoc_req)));
15754 return BCME_BADLEN;
15755 }
15756 conn_info->req_ie_len =
15757 (uint32)(assoc_info.req_len - sizeof(struct dot11_assoc_req));
15758 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
15759 conn_info->req_ie_len -= ETHER_ADDR_LEN;
15760 }
15761 if (conn_info->req_ie_len <= MAX_REQ_LINE) {
15762 memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
15763 } else {
15764 WL_ERR(("IE size %d above max %d size \n", conn_info->req_ie_len,
15765 MAX_REQ_LINE));
15766 return err;
15767 }
15768 } else {
15769 conn_info->req_ie_len = 0;
15770 }
15771
15772 if (assoc_info.resp_len) {
15773 err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0,
15774 cfg->extra_buf, assoc_info.resp_len, NULL);
15775 if (unlikely(err)) {
15776 WL_ERR(("could not get assoc resp (%d)\n", err));
15777 return err;
15778 }
15779 if (assoc_info.resp_len < sizeof(struct dot11_assoc_resp)) {
15780 WL_ERR(("resp_len %d is lessthan %d \n", assoc_info.resp_len,
15781 (int)sizeof(struct dot11_assoc_resp)));
15782 return BCME_BADLEN;
15783 }
15784 conn_info->resp_ie_len =
15785 assoc_info.resp_len - (uint32)sizeof(struct dot11_assoc_resp);
15786 if (conn_info->resp_ie_len <= MAX_REQ_LINE) {
15787 memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
15788 } else {
15789 WL_ERR(("IE size %d above max %d size \n", conn_info->resp_ie_len,
15790 MAX_REQ_LINE));
15791 return err;
15792 }
15793
15794 #ifdef QOS_MAP_SET
15795 /* find qos map set ie */
15796 if ((qos_map_ie =
15797 bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
15798 DOT11_MNG_QOS_MAP_ID)) != NULL) {
15799 WL_DBG((" QoS map set IE found in assoc response\n"));
15800 if (!cfg->up_table) {
15801 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
15802 }
15803 wl_set_up_table(cfg->up_table, qos_map_ie);
15804 } else {
15805 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
15806 }
15807 #endif /* QOS_MAP_SET */
15808 } else {
15809 conn_info->resp_ie_len = 0;
15810 }
15811 WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
15812 conn_info->resp_ie_len));
15813
15814 return err;
15815 }
15816
wl_ch_to_chanspec(struct net_device * dev,int ch,struct wl_join_params * join_params,size_t * join_params_size)15817 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch,
15818 struct wl_join_params *join_params,
15819 size_t *join_params_size)
15820 {
15821 chanspec_t chanspec = 0, chspec;
15822 struct bcm_cfg80211 *cfg =
15823 (struct bcm_cfg80211 *)wiphy_priv(dev->ieee80211_ptr->wiphy);
15824
15825 if ((ch != 0) && (cfg && !cfg->rcc_enabled)) {
15826 join_params->params.chanspec_num = 1;
15827 join_params->params.chanspec_list[0] = ch;
15828
15829 if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL) {
15830 chanspec |= WL_CHANSPEC_BAND_2G;
15831 } else {
15832 chanspec |= WL_CHANSPEC_BAND_5G;
15833 }
15834
15835 /* Get the min_bw set for the interface */
15836 chspec = WL_CHANSPEC_BW_20;
15837 if (chspec == INVCHANSPEC) {
15838 WL_ERR(("Invalid chanspec \n"));
15839 return -EINVAL;
15840 }
15841 chanspec |= chspec;
15842 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
15843
15844 *join_params_size +=
15845 WL_ASSOC_PARAMS_FIXED_SIZE +
15846 join_params->params.chanspec_num * sizeof(chanspec_t);
15847
15848 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
15849 join_params->params.chanspec_list[0] |= chanspec;
15850 join_params->params.chanspec_list[0] =
15851 wl_chspec_host_to_driver(join_params->params.chanspec_list[0]);
15852
15853 join_params->params.chanspec_num =
15854 htod32(join_params->params.chanspec_num);
15855 }
15856 #ifdef ESCAN_CHANNEL_CACHE
15857 else {
15858 /* If channel is not present and ESCAN_CHANNEL_CACHE is enabled,
15859 * use the cached channel list
15860 */
15861 int n_channels;
15862 n_channels = get_roam_channel_list(
15863 ch, join_params->params.chanspec_list, MAX_ROAM_CHANNEL,
15864 &join_params->ssid, ioctl_version);
15865 join_params->params.chanspec_num = htod32(n_channels);
15866 *join_params_size +=
15867 WL_ASSOC_PARAMS_FIXED_SIZE +
15868 join_params->params.chanspec_num * sizeof(chanspec_t);
15869 }
15870 #endif /* ESCAN_CHANNEL_CACHE */
15871
15872 WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
15873 join_params->params.chanspec_list[0],
15874 join_params->params.chanspec_num));
15875 return 0;
15876 }
15877
wl_update_bss_info(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool update_ssid)15878 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15879 bool update_ssid)
15880 {
15881 struct cfg80211_bss *bss;
15882 wl_bss_info_t *bi;
15883 struct wlc_ssid *ssid;
15884 const struct bcm_tlv *tim;
15885 s32 beacon_interval;
15886 s32 dtim_period;
15887 size_t ie_len;
15888 const u8 *ie;
15889 u8 *curbssid;
15890 s32 err = 0;
15891 struct wiphy *wiphy;
15892 u32 channel;
15893 char *buf;
15894 u32 freq, band;
15895
15896 wiphy = bcmcfg_to_wiphy(cfg);
15897
15898 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
15899 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15900 bss = CFG80211_GET_BSS(wiphy, NULL, curbssid, ssid->SSID, ssid->SSID_len);
15901 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
15902 if (!buf) {
15903 WL_ERR(("buffer alloc failed.\n"));
15904 return BCME_NOMEM;
15905 }
15906 mutex_lock(&cfg->usr_sync);
15907 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
15908 err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX);
15909 if (unlikely(err)) {
15910 WL_ERR(("Could not get bss info %d\n", err));
15911 goto update_bss_info_out;
15912 }
15913 bi = (wl_bss_info_t *)(buf + 0x4);
15914 channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
15915 wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN);
15916
15917 if (!bss) {
15918 WL_DBG(("Could not find the AP\n"));
15919 if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
15920 WL_ERR(("Bssid doesn't match\n"));
15921 err = -EIO;
15922 goto update_bss_info_out;
15923 }
15924 err = wl_inform_single_bss(cfg, bi, update_ssid);
15925 if (unlikely(err)) {
15926 goto update_bss_info_out;
15927 }
15928
15929 ie = ((u8 *)bi) + bi->ie_offset;
15930 ie_len = bi->ie_length;
15931 beacon_interval = cpu_to_le16(bi->beacon_period);
15932 } else {
15933 WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
15934 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && \
15935 !defined(WL_COMPAT_WIRELESS)
15936 freq = ieee80211_channel_to_frequency(channel);
15937 #else
15938 band = (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ
15939 : IEEE80211_BAND_5GHZ;
15940 freq = ieee80211_channel_to_frequency(channel, band);
15941 #endif // endif
15942 bss->channel = ieee80211_get_channel(wiphy, freq);
15943 #if defined(WL_CFG80211_P2P_DEV_IF)
15944 ie = (const u8 *)bss->ies->data;
15945 ie_len = bss->ies->len;
15946 #else
15947 ie = bss->information_elements;
15948 ie_len = bss->len_information_elements;
15949 #endif /* WL_CFG80211_P2P_DEV_IF */
15950 beacon_interval = bss->beacon_interval;
15951
15952 CFG80211_PUT_BSS(wiphy, bss);
15953 }
15954
15955 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
15956 if (tim) {
15957 dtim_period = tim->data[1];
15958 } else {
15959 /*
15960 * active scan was done so we could not get dtim
15961 * information out of probe response.
15962 * so we speficially query dtim information.
15963 */
15964 dtim_period = 0;
15965 err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD, &dtim_period,
15966 sizeof(dtim_period));
15967 if (unlikely(err)) {
15968 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
15969 goto update_bss_info_out;
15970 }
15971 }
15972
15973 wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
15974 wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
15975
15976 update_bss_info_out:
15977 if (unlikely(err)) {
15978 WL_ERR(("Failed with error %d\n", err));
15979 }
15980
15981 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
15982 mutex_unlock(&cfg->usr_sync);
15983 return err;
15984 }
15985
wl_bss_roaming_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)15986 static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg,
15987 struct net_device *ndev, const wl_event_msg_t *e,
15988 void *data)
15989 {
15990 struct wl_connect_info *conn_info = wl_to_conn(cfg);
15991 s32 err = 0;
15992 u8 *curbssid;
15993 u32 *channel;
15994 scb_val_t scbval;
15995 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
15996 defined(WL_COMPAT_WIRELESS)
15997 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15998 struct ieee80211_supported_band *band;
15999 struct ieee80211_channel *notify_channel = NULL;
16000 u32 freq;
16001 u32 cur_channel, chanspec;
16002 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16003 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16004 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \
16005 defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12)
16006 struct cfg80211_roam_info roam_info;
16007 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION \
16008 >= 4.12.0 */
16009 #if defined(WL_FILS_ROAM_OFFLD)
16010 struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
16011 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16012 #endif // endif
16013 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16014 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16015 dhd_if_t *ifp = NULL;
16016 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
16017 #ifdef WLFBT
16018 uint32 data_len = 0;
16019 if (data) {
16020 data_len = ntoh32(e->datalen);
16021 }
16022 #endif /* WLFBT */
16023
16024 BCM_REFERENCE(dhdp);
16025 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16026 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
16027 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
16028 defined(WL_COMPAT_WIRELESS)
16029 /* Skip calling cfg80211_roamed If the channels are same and
16030 * the current bssid & the new bssid are same
16031 * Also clear timer roam_timeout.
16032 * Only used on BCM4359 devices.
16033 */
16034 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
16035 if (unlikely(err)) {
16036 return err;
16037 }
16038 cur_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
16039 if ((*channel == cur_channel) &&
16040 ((memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) ||
16041 (memcmp(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN) == 0))) {
16042 WL_DBG(("BSS already present, Skipping roamed event to"
16043 " upper layer\n"));
16044 goto fail;
16045 }
16046 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16047
16048 if ((err = wl_get_assoc_ies(cfg, ndev)) != BCME_OK) {
16049 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
16050 dhd_net2idx(dhdp->info, ndev),
16051 WLAN_REASON_DEAUTH_LEAVING);
16052 WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
16053 " upper layer\n"));
16054 /* To make sure disconnect, and fw sync, explictly send dissassoc
16055 * for BSSID 00:00:00:00:00:00 issue
16056 */
16057 bzero(&scbval, sizeof(scb_val_t));
16058 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
16059 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
16060 scbval.val = htod32(scbval.val);
16061 if (wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)) <
16062 0) {
16063 WL_ERR(("WLC_DISASSOC error\n"));
16064 }
16065 goto fail;
16066 }
16067
16068 WL_MSG(ndev->name, "%pM(ch:%3d) => %pM(ch:%3d/%sMHz)\n", curbssid, *channel,
16069 (const u8 *)(&e->addr), cur_channel,
16070 CHSPEC_IS20(chanspec) ? "20"
16071 : CHSPEC_IS40(chanspec) ? "40"
16072 : CHSPEC_IS80(chanspec) ? "80"
16073 : CHSPEC_IS160(chanspec) ? "160"
16074 : "??");
16075
16076 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
16077 WL_PROF_BSSID);
16078 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16079 if ((err = wl_update_bss_info(cfg, ndev, true)) != BCME_OK) {
16080 WL_ERR(("failed to update bss info, err=%d\n", err));
16081 goto fail;
16082 }
16083 wl_update_pmklist(ndev, cfg->pmk_list, err);
16084
16085 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
16086 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
16087 defined(WL_COMPAT_WIRELESS)
16088 /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
16089 if (*channel <= CH_MAX_2G_CHANNEL) {
16090 band = wiphy->bands[IEEE80211_BAND_2GHZ];
16091 } else {
16092 band = wiphy->bands[IEEE80211_BAND_5GHZ];
16093 }
16094 freq = ieee80211_channel_to_frequency(*channel, band->band);
16095 notify_channel = ieee80211_get_channel(wiphy, freq);
16096 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16097 #ifdef WLFBT
16098 /* back up the given FBT key for the further supplicant request,
16099 * currently not checking the FBT is enabled for current BSS in DHD,
16100 * because the supplicant decides to take it or not.
16101 */
16102 if (data && (data_len == FBT_KEYLEN)) {
16103 memcpy(cfg->fbt_key, data, FBT_KEYLEN);
16104 }
16105 #endif /* WLFBT */
16106 #ifdef CUSTOM_LONG_RETRY_LIMIT
16107 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
16108 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
16109 }
16110 #endif /* CUSTOM_LONG_RETRY_LIMIT */
16111 DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM), dhd_net2idx(dhdp->info, ndev),
16112 0);
16113 #ifdef WL_EXT_IAPSTA
16114 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
16115 #endif
16116
16117 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16118 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \
16119 defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12)
16120 memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
16121 roam_info.channel = notify_channel;
16122 roam_info.bssid = curbssid;
16123 roam_info.req_ie = conn_info->req_ie;
16124 roam_info.req_ie_len = conn_info->req_ie_len;
16125 roam_info.resp_ie = conn_info->resp_ie;
16126 roam_info.resp_ie_len = conn_info->resp_ie_len;
16127 #if defined(WL_FILS_ROAM_OFFLD)
16128 if ((sec->auth_type == DOT11_FILS_SKEY_PFS) ||
16129 (sec->auth_type == DOT11_FILS_SKEY)) {
16130 roam_info.fils.kek = fils_info->fils_kek;
16131 roam_info.fils.kek_len = fils_info->fils_kek_len;
16132 roam_info.fils.update_erp_next_seq_num = true;
16133 roam_info.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
16134 roam_info.fils.pmk = fils_info->fils_pmk;
16135 roam_info.fils.pmk_len = fils_info->fils_kek_len;
16136 roam_info.fils.pmkid = fils_info->fils_pmkid;
16137 }
16138 #endif // endif
16139 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
16140 #else
16141 cfg80211_roamed(ndev,
16142 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
16143 defined(WL_COMPAT_WIRELESS)
16144 notify_channel,
16145 #endif // endif
16146 curbssid, conn_info->req_ie, conn_info->req_ie_len,
16147 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
16148 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION \
16149 >= 4.12.0 */
16150
16151 memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
16152 wl_set_drv_status(cfg, CONNECTED, ndev);
16153
16154 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16155 ifp = dhd_get_ifp(dhdp, e->ifidx);
16156 if (ifp) {
16157 ifp->post_roam_evt = TRUE;
16158 }
16159 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
16160
16161 return err;
16162
16163 fail:
16164 #ifdef DHD_LOSSLESS_ROAMING
16165 wl_del_roam_timeout(cfg);
16166 #endif /* DHD_LOSSLESS_ROAMING */
16167 return err;
16168 }
16169
wl_cfg80211_verify_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,struct cfg80211_bss ** bss)16170 static bool wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg,
16171 struct net_device *ndev,
16172 struct cfg80211_bss **bss)
16173 {
16174 struct wiphy *wiphy;
16175 struct wlc_ssid *ssid;
16176 uint8 *curbssid;
16177 int count = 0;
16178 int ret = false;
16179 u8 cur_ssid[DOT11_MAX_SSID_LEN + 1];
16180
16181 wiphy = bcmcfg_to_wiphy(cfg);
16182 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
16183 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16184 if (!ssid) {
16185 WL_ERR(("No SSID found in the saved profile \n"));
16186 return false;
16187 }
16188
16189 do {
16190 *bss =
16191 CFG80211_GET_BSS(wiphy, NULL, curbssid, ssid->SSID, ssid->SSID_len);
16192 if (*bss || (count > 0x5)) {
16193 break;
16194 }
16195
16196 count++;
16197 msleep(0x64);
16198 } while (*bss == NULL);
16199
16200 WL_DBG(("cfg80211 bss_ptr:%p loop_cnt:%d\n", *bss, count));
16201 if (*bss) {
16202 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
16203 /* Update the reference count after use. In case of kernel version
16204 * >= 4.7 the cfg802_put_bss is called in cfg80211_connect_bss context
16205 */
16206 CFG80211_PUT_BSS(wiphy, *bss);
16207 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
16208 ret = true;
16209 } else {
16210 memset(cur_ssid, 0, DOT11_MAX_SSID_LEN);
16211 strncpy(cur_ssid, ssid->SSID, MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN));
16212 WL_ERR(("No bss entry for ssid:%s bssid:" MACDBG "\n", cur_ssid,
16213 MAC2STRDBG(curbssid)));
16214 }
16215
16216 return ret;
16217 }
16218
16219 #ifdef WL_FILS
wl_get_fils_connect_params(struct bcm_cfg80211 * cfg,struct net_device * ndev)16220 static s32 wl_get_fils_connect_params(struct bcm_cfg80211 *cfg,
16221 struct net_device *ndev)
16222 {
16223 const bcm_xtlv_t *pxtlv_out;
16224 struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
16225 int err = BCME_OK;
16226 bcm_iov_buf_t *iov_buf_in = NULL;
16227 bcm_iov_buf_t iov_buf_out = {0};
16228 u16 len;
16229 u16 type;
16230 const u8 *data;
16231 iov_buf_in = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
16232 if (!iov_buf_in) {
16233 WL_ERR(("buf memory alloc failed\n"));
16234 err = BCME_NOMEM;
16235 goto exit;
16236 }
16237 iov_buf_out.version = WL_FILS_IOV_VERSION;
16238 iov_buf_out.id = WL_FILS_CMD_GET_CONNECT_PARAMS;
16239 err = wldev_iovar_getbuf(ndev, "fils", (uint8 *)&iov_buf_out,
16240 sizeof(bcm_iov_buf_t), iov_buf_in, WLC_IOCTL_SMLEN,
16241 &cfg->ioctl_buf_sync);
16242 if (unlikely(err)) {
16243 WL_ERR(("Get FILS Params Error (%d)\n", err));
16244 goto exit;
16245 }
16246 pxtlv_out = (bcm_xtlv_t *)((bcm_iov_buf_t *)iov_buf_in)->data;
16247 len = iov_buf_in->len;
16248 do {
16249 if (!bcm_valid_xtlv(pxtlv_out, iov_buf_in->len,
16250 BCM_XTLV_OPTION_ALIGN32)) {
16251 WL_ERR(("%s: XTLV is not valid\n", __func__));
16252 err = BCME_BADARG;
16253 goto exit;
16254 }
16255 bcm_xtlv_unpack_xtlv(pxtlv_out, &type, &len, &data,
16256 BCM_XTLV_OPTION_ALIGN32);
16257 switch (type) {
16258 case WL_FILS_XTLV_ERP_NEXT_SEQ_NUM:
16259 fils_info->fils_erp_next_seq_num = *(const u16 *)data;
16260 break;
16261 case WL_FILS_XTLV_KEK:
16262 if (memcpy_s(fils_info->fils_kek, WL_MAX_FILS_KEY_LEN, data,
16263 len) < 0) {
16264 err = BCME_BADARG;
16265 goto exit;
16266 }
16267 fils_info->fils_kek_len = len;
16268 break;
16269 case WL_FILS_XTLV_PMK:
16270 if (memcpy_s(fils_info->fils_pmk, WL_MAX_FILS_KEY_LEN, data,
16271 len) < 0) {
16272 err = BCME_BADARG;
16273 goto exit;
16274 }
16275 fils_info->fils_pmk_len = len;
16276 break;
16277 case WL_FILS_XTLV_PMKID:
16278 if (memcpy_s(fils_info->fils_pmkid, WL_MAX_FILS_KEY_LEN, data,
16279 len) < 0) {
16280 err = BCME_BADARG;
16281 goto exit;
16282 }
16283 break;
16284 default:
16285 WL_ERR(("%s: wrong XTLV code\n", __func__));
16286 break;
16287 }
16288 } while ((pxtlv_out = bcm_next_xtlv(pxtlv_out, (int *)&iov_buf_in->len,
16289 BCM_XTLV_OPTION_ALIGN32)) &&
16290 iov_buf_in->len);
16291 exit:
16292 if (iov_buf_in) {
16293 MFREE(cfg->osh, iov_buf_in, WLC_IOCTL_SMLEN);
16294 }
16295 return err;
16296 }
16297 #endif /* WL_FILS */
wl_bss_connect_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data,bool completed)16298 static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg,
16299 struct net_device *ndev, const wl_event_msg_t *e,
16300 void *data, bool completed)
16301 {
16302 struct wl_connect_info *conn_info = wl_to_conn(cfg);
16303 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16304 s32 err = 0;
16305 #ifdef WL_FILS
16306 struct cfg80211_connect_resp_params resp_params = {0};
16307 struct wl_fils_info *fils_info = NULL;
16308 struct wlc_ssid *ssid = NULL;
16309 struct wiphy *wiphy = NULL;
16310
16311 #endif /* WL_FILS */
16312 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16313 u32 event_type = ntoh32(e->event_type);
16314 struct cfg80211_bss *bss = NULL;
16315 dhd_pub_t *dhdp;
16316 dhdp = (dhd_pub_t *)(cfg->pub);
16317 BCM_REFERENCE(dhdp);
16318
16319 if (!sec) {
16320 WL_ERR(("sec is NULL\n"));
16321 return -ENODEV;
16322 }
16323 WL_DBG((" enter\n"));
16324 #ifdef ESCAN_RESULT_PATCH
16325 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
16326 if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) {
16327 WL_INFORM_MEM((" Connected event of connected device "
16328 "e=%d s=%d, ignore it\n",
16329 ntoh32(e->event_type), ntoh32(e->status)));
16330 return err;
16331 }
16332 }
16333 if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 &&
16334 memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) {
16335 WL_DBG(("copy bssid\n"));
16336 memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN);
16337 }
16338 #else
16339 if (cfg->scan_request) {
16340 wl_cfg80211_cancel_scan(cfg);
16341 }
16342 #endif /* ESCAN_RESULT_PATCH */
16343 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
16344 wl_cfg80211_scan_abort(cfg);
16345 if (completed) {
16346 wl_get_assoc_ies(cfg, ndev);
16347 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
16348 WL_PROF_BSSID);
16349 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16350 /*
16351 * CFG layer relies on cached IEs (from probe/beacon) to fetch
16352 * matching bss. For cases, there is no match available, need to
16353 * update the cache based on bss info from fw.
16354 */
16355 wl_update_bss_info(cfg, ndev, true);
16356 wl_update_pmklist(ndev, cfg->pmk_list, err);
16357 wl_set_drv_status(cfg, CONNECTED, ndev);
16358 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
16359 if (dhdp->roam_env_detection) {
16360 wldev_iovar_setint(ndev, "roam_env_detection",
16361 AP_ENV_INDETERMINATE);
16362 }
16363 #endif /* ROAM_AP_ENV_DETECTION */
16364 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
16365 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
16366 init_completion(&cfg->iface_disable);
16367 #else
16368 /* reinitialize completion to clear previous count */
16369 INIT_COMPLETION(cfg->iface_disable);
16370 #endif // endif
16371 }
16372 #ifdef CUSTOM_SET_CPUCORE
16373 if (wl_get_chan_isvht80(ndev, dhdp)) {
16374 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
16375 dhdp->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
16376 } else if (is_p2p_group_iface(ndev->ieee80211_ptr)) {
16377 dhdp->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
16378 }
16379 dhd_set_cpucore(dhdp, TRUE);
16380 }
16381 #endif /* CUSTOM_SET_CPUCORE */
16382 #ifdef CUSTOM_LONG_RETRY_LIMIT
16383 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
16384 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
16385 }
16386 #endif /* CUSTOM_LONG_RETRY_LIMIT */
16387 bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
16388 }
16389 wl_clr_drv_status(cfg, CONNECTING, ndev);
16390
16391 if (completed && (wl_cfg80211_verify_bss(cfg, ndev, &bss) != true)) {
16392 /* If bss entry is not available in the cfg80211 bss cache
16393 * the wireless stack will complain and won't populate
16394 * wdev->current_bss ptr
16395 */
16396 WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
16397 completed = false;
16398 sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
16399 }
16400 if (completed) {
16401 WL_MSG(ndev->name,
16402 "Report connect result - connection succeeded\n");
16403 #ifdef WL_EXT_IAPSTA
16404 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
16405 wl_ext_iapsta_enable_master_if(ndev, TRUE);
16406 #endif
16407 } else {
16408 WL_MSG(ndev->name, "Report connect result - connection failed\n");
16409 #ifdef WL_EXT_IAPSTA
16410 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY | STA_NO_BTC_IN4WAY,
16411 WL_EXT_STATUS_DISCONNECTED, NULL);
16412 #endif
16413 }
16414 #ifdef WL_FILS
16415 if ((sec->auth_type == DOT11_FILS_SKEY_PFS) ||
16416 (sec->auth_type == DOT11_FILS_SKEY)) {
16417 wl_get_fils_connect_params(cfg, ndev);
16418 fils_info = wl_to_fils_info(cfg);
16419 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
16420 wiphy = bcmcfg_to_wiphy(cfg);
16421 resp_params.status = completed ? WLAN_STATUS_SUCCESS
16422 : (sec->auth_assoc_res_status)
16423 ? sec->auth_assoc_res_status
16424 : WLAN_STATUS_UNSPECIFIED_FAILURE;
16425 resp_params.bssid = curbssid;
16426 resp_params.bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
16427 ssid->SSID, ssid->SSID_len);
16428 resp_params.req_ie = conn_info->req_ie;
16429 resp_params.req_ie_len = conn_info->req_ie_len;
16430 resp_params.resp_ie = conn_info->resp_ie;
16431 resp_params.resp_ie_len = conn_info->resp_ie_len;
16432 #if defined(WL_FILS_ROAM_OFFLD) || \
16433 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0))
16434 resp_params.fils.kek = fils_info->fils_kek;
16435 resp_params.fils.kek_len = fils_info->fils_kek_len;
16436 resp_params.fils.update_erp_next_seq_num = true;
16437 resp_params.fils.erp_next_seq_num =
16438 fils_info->fils_erp_next_seq_num;
16439 resp_params.fils.pmk = fils_info->fils_pmk;
16440 resp_params.fils.pmk_len = fils_info->fils_kek_len;
16441 resp_params.fils.pmkid = fils_info->fils_pmkid;
16442 #else
16443 resp_params.fils_kek = fils_info->fils_kek;
16444 resp_params.fils_kek_len = fils_info->fils_kek_len;
16445 resp_params.update_erp_next_seq_num = true;
16446 resp_params.fils_erp_next_seq_num =
16447 fils_info->fils_erp_next_seq_num;
16448 resp_params.pmk = fils_info->fils_pmk;
16449 resp_params.pmk_len = fils_info->fils_kek_len;
16450 resp_params.pmkid = fils_info->fils_pmkid;
16451 #endif /* WL_FILS_ROAM_OFFLD */
16452 cfg80211_connect_done(ndev, &resp_params, GFP_KERNEL);
16453 } else
16454 #endif /* WL_FILS */
16455 {
16456 CFG80211_CONNECT_RESULT(ndev, curbssid, bss, conn_info->req_ie,
16457 conn_info->req_ie_len, conn_info->resp_ie,
16458 conn_info->resp_ie_len,
16459 completed ? WLAN_STATUS_SUCCESS
16460 : (sec->auth_assoc_res_status)
16461 ? sec->auth_assoc_res_status
16462 : WLAN_STATUS_UNSPECIFIED_FAILURE,
16463 GFP_KERNEL);
16464
16465 #ifdef CONFIG_AP6XXX_WIFI6_HDF
16466 wl_notify_connect_sta_status(cfg, ndev, e, data, completed, bss);
16467 #endif
16468 }
16469 } else {
16470 WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
16471 " connecting:%x. connected:%d\n",
16472 ndev->name, event_type,
16473 wl_get_drv_status(cfg, CONNECTING, ndev),
16474 wl_get_drv_status(cfg, CONNECTED, ndev)));
16475 }
16476 #ifdef CONFIG_TCPACK_FASTTX
16477 if (wl_get_chan_isvht80(ndev, dhdp)) {
16478 wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
16479 } else {
16480 wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
16481 }
16482 #endif /* CONFIG_TCPACK_FASTTX */
16483
16484 return err;
16485 }
16486
wl_notify_mic_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)16487 static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg,
16488 bcm_struct_cfgdev *cfgdev,
16489 const wl_event_msg_t *e, void *data)
16490 {
16491 struct net_device *ndev = NULL;
16492 u16 flags = ntoh16(e->flags);
16493 enum nl80211_key_type key_type;
16494
16495 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16496
16497 WL_INFORM_MEM(("[%s] mic fail event - " MACDBG " \n", ndev->name,
16498 MAC2STRDBG(e->addr.octet)));
16499 mutex_lock(&cfg->usr_sync);
16500 if (flags & WLC_EVENT_MSG_GROUP) {
16501 key_type = NL80211_KEYTYPE_GROUP;
16502 } else {
16503 key_type = NL80211_KEYTYPE_PAIRWISE;
16504 }
16505
16506 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
16507 cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1, NULL,
16508 GFP_KERNEL);
16509 mutex_unlock(&cfg->usr_sync);
16510
16511 return 0;
16512 }
16513
16514 #ifdef BT_WIFI_HANDOVER
wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)16515 static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
16516 bcm_struct_cfgdev *cfgdev,
16517 const wl_event_msg_t *e, void *data)
16518 {
16519 struct net_device *ndev = NULL;
16520 u32 event = ntoh32(e->event_type);
16521 u32 datalen = ntoh32(e->datalen);
16522 s32 err;
16523
16524 WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n",
16525 event, datalen));
16526 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16527 err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0);
16528
16529 return err;
16530 }
16531 #endif /* BT_WIFI_HANDOVER */
16532
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)16533 static s32 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
16534 const struct ether_addr *da,
16535 const struct ether_addr *sa,
16536 const struct ether_addr *bssid, u8 **pheader,
16537 u32 *body_len, u8 *pbody)
16538 {
16539 struct dot11_management_header *hdr;
16540 u32 totlen = 0;
16541 s32 err = 0;
16542 u8 *offset;
16543 u32 prebody_len = *body_len;
16544 switch (fc) {
16545 case FC_ASSOC_REQ:
16546 /* capability , listen interval */
16547 totlen = DOT11_ASSOC_REQ_FIXED_LEN;
16548 *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
16549 break;
16550
16551 case FC_REASSOC_REQ:
16552 /* capability, listen inteval, ap address */
16553 totlen = DOT11_REASSOC_REQ_FIXED_LEN;
16554 *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
16555 break;
16556 }
16557 totlen += DOT11_MGMT_HDR_LEN + prebody_len;
16558 *pheader = (u8 *)MALLOCZ(cfg->osh, totlen);
16559 if (*pheader == NULL) {
16560 WL_ERR(("memory alloc failed \n"));
16561 return -ENOMEM;
16562 }
16563 hdr = (struct dot11_management_header *)(*pheader);
16564 hdr->fc = htol16(fc);
16565 hdr->durid = 0;
16566 hdr->seq = 0;
16567 offset = (u8 *)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
16568 bcopy((const char *)da, (u8 *)&hdr->da, ETHER_ADDR_LEN);
16569 bcopy((const char *)sa, (u8 *)&hdr->sa, ETHER_ADDR_LEN);
16570 bcopy((const char *)bssid, (u8 *)&hdr->bssid, ETHER_ADDR_LEN);
16571 if ((pbody != NULL) && prebody_len) {
16572 bcopy((const char *)pbody, offset, prebody_len);
16573 }
16574 *body_len = totlen;
16575 return err;
16576 }
16577
16578 #ifdef WL_CFG80211_GON_COLLISION
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)16579 static void wl_gon_req_collision(struct bcm_cfg80211 *cfg,
16580 wl_action_frame_t *tx_act_frm,
16581 wifi_p2p_pub_act_frame_t *rx_act_frm,
16582 struct net_device *ndev, struct ether_addr sa,
16583 struct ether_addr da)
16584 {
16585 if (cfg->afx_hdl->pending_tx_act_frm == NULL) {
16586 return;
16587 }
16588
16589 if (tx_act_frm &&
16590 wl_cfgp2p_is_pub_action(tx_act_frm->data, tx_act_frm->len)) {
16591 wifi_p2p_pub_act_frame_t *pact_frm;
16592
16593 pact_frm = (wifi_p2p_pub_act_frame_t *)tx_act_frm->data;
16594
16595 if (!(pact_frm->subtype == P2P_PAF_GON_REQ &&
16596 rx_act_frm->subtype == P2P_PAF_GON_REQ)) {
16597 return;
16598 }
16599 }
16600
16601 WL_ERR((" GO NEGO Request COLLISION !!! \n"));
16602
16603 /* if sa(peer) addr is less than da(my) addr,
16604 * my device will process peer's gon request and block to send my gon req.
16605 *
16606 * if not (sa addr > da addr),
16607 * my device will process gon request and drop gon req of peer.
16608 */
16609 if (memcmp(sa.octet, da.octet, ETHER_ADDR_LEN) < 0) {
16610 /* block to send tx gon request */
16611 cfg->block_gon_req_tx_count = BLOCK_GON_REQ_MAX_NUM;
16612 WL_ERR((" block to send gon req tx !!!\n"));
16613
16614 /* if we are finding a common channel for sending af,
16615 * do not scan more to block to send current gon req
16616 */
16617 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
16618 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, ndev);
16619 complete(&cfg->act_frm_scan);
16620 }
16621 } else {
16622 /* drop gon request of peer to process gon request by my device. */
16623 WL_ERR((" drop to receive gon req rx !!! \n"));
16624 cfg->block_gon_req_rx_count = BLOCK_GON_REQ_MAX_NUM;
16625 }
16626
16627 return;
16628 }
16629 #endif /* WL_CFG80211_GON_COLLISION */
16630
wl_stop_wait_next_action_frame(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 bsscfgidx)16631 void wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg,
16632 struct net_device *ndev, u8 bsscfgidx)
16633 {
16634 s32 err = 0;
16635
16636 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
16637 if (timer_pending(&cfg->p2p->listen_timer)) {
16638 del_timer_sync(&cfg->p2p->listen_timer);
16639 }
16640 if (cfg->afx_hdl != NULL) {
16641 if (cfg->afx_hdl->dev != NULL) {
16642 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
16643 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL,
16644 cfg->afx_hdl->dev);
16645 }
16646 cfg->afx_hdl->peer_chan = WL_INVALID;
16647 }
16648 complete(&cfg->act_frm_scan);
16649 WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
16650 } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
16651 if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
16652 wl_get_p2p_status(cfg, ACTION_TX_NOACK))) {
16653 wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
16654 }
16655
16656 WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n",
16657 bsscfgidx));
16658 /* Scan engine is not used for sending action frames in the latest
16659 * driver branches. actframe_abort is used in the latest driver branches
16660 * instead of scan abort.
16661 * If actframe_abort iovar succeeds, don't execute scan abort.
16662 * If actframe_abort fails with unsupported error,
16663 * execute scan abort (for backward copmatibility).
16664 */
16665 if (cfg->af_sent_channel) {
16666 err =
16667 wldev_iovar_setint_bsscfg(ndev, "actframe_abort", 1, bsscfgidx);
16668 if (err < 0) {
16669 if (err == BCME_UNSUPPORTED) {
16670 wl_cfg80211_scan_abort(cfg);
16671 } else {
16672 WL_ERR(("actframe_abort failed. ret:%d\n", err));
16673 }
16674 }
16675 }
16676 }
16677 #ifdef WL_CFG80211_SYNC_GON
16678 else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
16679 WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
16680 /* So abort scan to cancel listen */
16681 wl_cfg80211_scan_abort(cfg);
16682 }
16683 #endif /* WL_CFG80211_SYNC_GON */
16684 }
16685
16686 #if defined(WLTDLS)
wl_cfg80211_is_tdls_tunneled_frame(void * frame,u32 frame_len)16687 bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len)
16688 {
16689 unsigned char *data;
16690
16691 if (frame == NULL) {
16692 WL_ERR(("Invalid frame \n"));
16693 return false;
16694 }
16695
16696 if (frame_len < 5) {
16697 WL_ERR(("Invalid frame length [%d] \n", frame_len));
16698 return false;
16699 }
16700
16701 data = frame;
16702
16703 if (!memcmp(data, TDLS_TUNNELED_PRB_REQ, 5) ||
16704 !memcmp(data, TDLS_TUNNELED_PRB_RESP, 5)) {
16705 WL_DBG(("TDLS Vendor Specific Received type\n"));
16706 return true;
16707 }
16708
16709 return false;
16710 }
16711 #endif /* WLTDLS */
16712
wl_cfg80211_get_ioctl_version(void)16713 int wl_cfg80211_get_ioctl_version(void)
16714 {
16715 return ioctl_version;
16716 }
16717
wl_notify_rx_mgmt_frame(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)16718 static s32 wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg,
16719 bcm_struct_cfgdev *cfgdev,
16720 const wl_event_msg_t *e, void *data)
16721 {
16722 struct ieee80211_supported_band *band;
16723 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
16724 struct ether_addr da;
16725 struct ether_addr bssid;
16726 bool isfree = false;
16727 s32 err = 0;
16728 s32 freq;
16729 struct net_device *ndev = NULL;
16730 wifi_p2p_pub_act_frame_t *act_frm = NULL;
16731 wifi_p2p_action_frame_t *p2p_act_frm = NULL;
16732 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
16733 wl_event_rx_frame_data_t *rxframe;
16734 u32 event;
16735 u8 *mgmt_frame;
16736 u8 bsscfgidx;
16737 u32 mgmt_frame_len;
16738 u16 channel;
16739 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
16740 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16741 #endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
16742 if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) {
16743 WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen)));
16744 return -EINVAL;
16745 }
16746 mgmt_frame_len =
16747 ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_t);
16748 event = ntoh32(e->event_type);
16749 bsscfgidx = e->bsscfgidx;
16750 rxframe = (wl_event_rx_frame_data_t *)data;
16751 if (!rxframe) {
16752 WL_ERR(("rxframe: NULL\n"));
16753 return -EINVAL;
16754 }
16755 channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK);
16756 bzero(&bssid, ETHER_ADDR_LEN);
16757 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16758 if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) &&
16759 (event == WLC_E_PROBREQ_MSG)) {
16760 struct net_info *iter, *next;
16761 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
16762 for_each_ndev(cfg, iter, next)
16763 {
16764 GCC_DIAGNOSTIC_POP();
16765 if (iter->ndev && iter->wdev &&
16766 iter->wdev->iftype == NL80211_IFTYPE_AP) {
16767 ndev = iter->ndev;
16768 cfgdev = ndev_to_cfgdev(ndev);
16769 break;
16770 }
16771 }
16772 }
16773
16774 if (channel <= CH_MAX_2G_CHANNEL) {
16775 band = wiphy->bands[IEEE80211_BAND_2GHZ];
16776 } else {
16777 band = wiphy->bands[IEEE80211_BAND_5GHZ];
16778 }
16779 if (!band) {
16780 WL_ERR(("No valid band\n"));
16781 return -EINVAL;
16782 }
16783 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && \
16784 !defined(WL_COMPAT_WIRELESS)
16785 freq = ieee80211_channel_to_frequency(channel);
16786 (void)band->band;
16787 #else
16788 freq = ieee80211_channel_to_frequency(channel, band->band);
16789 #endif // endif
16790 if (event == WLC_E_ACTION_FRAME_RX) {
16791 u8 ioctl_buf[WLC_IOCTL_SMLEN];
16792
16793 if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", NULL, 0,
16794 ioctl_buf, sizeof(ioctl_buf),
16795 bsscfgidx, NULL)) != BCME_OK) {
16796 WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
16797 goto exit;
16798 }
16799
16800 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
16801 if (err < 0) {
16802 WL_ERR(("WLC_GET_BSSID error %d\n", err));
16803 }
16804 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
16805 err = wl_frame_get_mgmt(
16806 cfg, FC_ACTION, &da, &e->addr, &bssid, &mgmt_frame, &mgmt_frame_len,
16807 (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
16808 if (err < 0) {
16809 WL_ERR(
16810 ("Error in receiving action frame len %d channel %d freq %d\n",
16811 mgmt_frame_len, channel, freq));
16812 goto exit;
16813 }
16814 isfree = true;
16815 if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16816 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
16817 act_frm =
16818 (wifi_p2p_pub_act_frame_t *)(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
16819 } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16820 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
16821 p2p_act_frm = (wifi_p2p_action_frame_t *)(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
16822 (void)p2p_act_frm;
16823 } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16824 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
16825 sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t
16826 *)(&mgmt_frame[DOT11_MGMT_HDR_LEN]);
16827 if (sd_act_frm &&
16828 wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
16829 if (cfg->next_af_subtype == sd_act_frm->action) {
16830 WL_DBG(("We got a right next frame of SD!(%d)\n",
16831 sd_act_frm->action));
16832 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16833
16834 /* Stop waiting for next AF. */
16835 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16836 }
16837 }
16838 (void)sd_act_frm;
16839 #ifdef WLTDLS
16840 } else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
16841 (wl_cfg80211_is_tdls_tunneled_frame(
16842 &mgmt_frame[DOT11_MGMT_HDR_LEN],
16843 mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
16844 if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
16845 WL_ERR((" TDLS Action Frame Received type = %d \n",
16846 mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
16847 }
16848 #ifdef TDLS_MSG_ONLY_WFD
16849 if (!dhdp->tdls_mode) {
16850 WL_DBG((" TDLS Frame filtered \n"));
16851 goto exit;
16852 }
16853 #else
16854 if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
16855 cfg->tdls_mgmt_frame = mgmt_frame;
16856 cfg->tdls_mgmt_frame_len = mgmt_frame_len;
16857 cfg->tdls_mgmt_freq = freq;
16858 return 0;
16859 }
16860 #endif /* TDLS_MSG_ONLY_WFD */
16861 #endif /* WLTDLS */
16862 #ifdef QOS_MAP_SET
16863 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
16864 /* update QoS map set table */
16865 bcm_tlv_t *qos_map_ie = NULL;
16866 if ((qos_map_ie =
16867 bcm_parse_tlvs(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16868 mgmt_frame_len - DOT11_MGMT_HDR_LEN,
16869 DOT11_MNG_QOS_MAP_ID)) != NULL) {
16870 WL_DBG((" QoS map set IE found in QoS action frame\n"));
16871 if (!cfg->up_table) {
16872 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
16873 }
16874 wl_set_up_table(cfg->up_table, qos_map_ie);
16875 } else {
16876 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
16877 }
16878 #endif /* QOS_MAP_SET */
16879 } else {
16880 /*
16881 * if we got normal action frame and ndev is p2p0,
16882 * we have to change ndev from p2p0 to wlan0
16883 */
16884
16885 if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
16886 u8 action = 0;
16887 if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16888 mgmt_frame_len - DOT11_MGMT_HDR_LEN,
16889 &action) != BCME_OK) {
16890 WL_DBG(("Recived action is not public action frame\n"));
16891 } else if (cfg->next_af_subtype == action) {
16892 WL_DBG(
16893 ("Recived action is the waiting action(%d)\n", action));
16894 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16895
16896 /* Stop waiting for next AF. */
16897 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16898 }
16899 }
16900 }
16901
16902 if (act_frm) {
16903 #ifdef WL_CFG80211_GON_COLLISION
16904 if (act_frm->subtype == P2P_PAF_GON_REQ) {
16905 wl_gon_req_collision(
16906 cfg, &cfg->afx_hdl->pending_tx_act_frm->action_frame,
16907 act_frm, ndev, e->addr, da);
16908
16909 if (cfg->block_gon_req_rx_count) {
16910 WL_ERR(("drop frame GON Req Rx : count (%d)\n",
16911 cfg->block_gon_req_rx_count));
16912 cfg->block_gon_req_rx_count--;
16913 goto exit;
16914 }
16915 } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
16916 /* if go formation done, clear it */
16917 cfg->block_gon_req_tx_count = 0;
16918 cfg->block_gon_req_rx_count = 0;
16919 }
16920 #endif /* WL_CFG80211_GON_COLLISION */
16921
16922 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
16923 if (cfg->next_af_subtype == act_frm->subtype) {
16924 WL_DBG(
16925 ("We got a right next frame!(%d)\n", act_frm->subtype));
16926 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
16927
16928 if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
16929 OSL_SLEEP(20);
16930 }
16931
16932 /* Stop waiting for next AF. */
16933 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
16934 } else if ((cfg->next_af_subtype == P2P_PAF_GON_RSP) &&
16935 (act_frm->subtype == P2P_PAF_GON_REQ)) {
16936 /* If current received frame is GO NEG REQ and next
16937 * expected frame is GO NEG RESP, do not send it up.
16938 */
16939 WL_ERR(("GO Neg req received while waiting for RESP."
16940 "Discard incoming frame\n"));
16941 goto exit;
16942 }
16943 }
16944 }
16945
16946 wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
16947 mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel);
16948 if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
16949 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
16950 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
16951 }
16952 } else if (event == WLC_E_PROBREQ_MSG) {
16953 /* Handle probe reqs frame
16954 * WPS-AP certification 4.2.13
16955 */
16956 struct parsed_ies prbreq_ies;
16957 u32 prbreq_ie_len = 0;
16958 bool pbc = 0;
16959
16960 WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
16961 mgmt_frame = (u8 *)(data);
16962 mgmt_frame_len = ntoh32(e->datalen);
16963 if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) {
16964 WL_ERR(("wrong datalen:%d\n", mgmt_frame_len));
16965 return -EINVAL;
16966 }
16967 prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
16968 /* Parse prob_req IEs */
16969 if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
16970 prbreq_ie_len, &prbreq_ies) < 0) {
16971 WL_ERR(("Prob req get IEs failed\n"));
16972 return 0;
16973 }
16974 if (prbreq_ies.wps_ie != NULL) {
16975 wl_validate_wps_ie((const char *)prbreq_ies.wps_ie,
16976 prbreq_ies.wps_ie_len, &pbc);
16977 WL_DBG((" wps_ie exist pbc = %d\n", pbc));
16978 /* if pbc method, send prob_req mgmt frame to upper layer */
16979 if (!pbc) {
16980 return 0;
16981 }
16982 } else {
16983 return 0;
16984 }
16985 } else {
16986 mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
16987
16988 /* wpa supplicant use probe request event for restarting another GON
16989 * Req. but it makes GON Req repetition. so if src addr of prb req is
16990 * same as my target device, do not send probe request event during
16991 * sending action frame.
16992 */
16993 if (event == WLC_E_P2P_PROBREQ_MSG) {
16994 WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG)
16995 ? "WLC_E_P2P_PROBREQ_MSG"
16996 : "WLC_E_PROBREQ_MSG"));
16997
16998 #ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
16999 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) &&
17000 !memcmp(cfg->afx_hdl->tx_dst_addr.octet, e->addr.octet,
17001 ETHER_ADDR_LEN)) {
17002 if (cfg->afx_hdl->pending_tx_act_frm &&
17003 wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17004 s32 channel = CHSPEC_CHANNEL(hton16(rxframe->channel));
17005 WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
17006 channel));
17007 cfg->afx_hdl->peer_chan = channel;
17008 complete(&cfg->act_frm_scan);
17009 }
17010 }
17011 #endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
17012
17013 /* Filter any P2P probe reqs arriving during the
17014 * GO-NEG Phase
17015 */
17016 if (cfg->p2p &&
17017 #if defined(P2P_IE_MISSING_FIX)
17018 cfg->p2p_prb_noti &&
17019 #endif // endif
17020 wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
17021 WL_DBG(("Filtering P2P probe_req while "
17022 "being in GO-Neg state\n"));
17023 return 0;
17024 }
17025 }
17026 }
17027
17028 if (discover_cfgdev(cfgdev, cfg)) {
17029 WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
17030 } else {
17031 WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
17032 }
17033 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
17034 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
17035 #ifdef CONFIG_AP6XXX_WIFI6_HDF
17036 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame,
17037 mgmt_frame_len);
17038 #endif
17039 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
17040 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0,
17041 GFP_ATOMIC);
17042 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
17043 defined(WL_COMPAT_WIRELESS)
17044 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
17045 #else
17046 cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
17047 #endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
17048
17049 WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
17050 mgmt_frame_len, ntoh32(e->datalen), channel, freq));
17051 exit:
17052 if (isfree) {
17053 MFREE(cfg->osh, mgmt_frame, mgmt_frame_len);
17054 }
17055 return err;
17056 }
17057
wl_init_conf(struct wl_conf * conf)17058 static void wl_init_conf(struct wl_conf *conf)
17059 {
17060 WL_DBG(("Enter \n"));
17061 conf->frag_threshold = (u32)-1;
17062 conf->rts_threshold = (u32)-1;
17063 conf->retry_short = (u32)-1;
17064 conf->retry_long = (u32)-1;
17065 conf->tx_power = -1;
17066 }
17067
wl_init_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev)17068 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
17069 {
17070 unsigned long flags;
17071 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
17072
17073 if (!profile) {
17074 WL_ERR(("profile null\n"));
17075 return;
17076 }
17077
17078 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
17079 bzero(profile, sizeof(struct wl_profile));
17080 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
17081 }
17082
wl_init_event_handler(struct bcm_cfg80211 * cfg)17083 static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
17084 {
17085 bzero(cfg->evt_handler, sizeof(cfg->evt_handler));
17086
17087 cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
17088 cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
17089 cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
17090 cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
17091 cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
17092 cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
17093 cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
17094 cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
17095 cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
17096 cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
17097 cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
17098 cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
17099 cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
17100 cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
17101 cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
17102 cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] =
17103 wl_cfgp2p_listen_complete;
17104 cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] =
17105 wl_cfgp2p_action_tx_complete;
17106 cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] =
17107 wl_cfgp2p_action_tx_complete;
17108 cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
17109 cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
17110 cfg->evt_handler[WLC_E_AUTH_IND] = wl_notify_connect_status;
17111 cfg->evt_handler[WLC_E_ASSOC_RESP_IE] = wl_notify_connect_status;
17112 #ifdef PNO_SUPPORT
17113 cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
17114 #endif /* PNO_SUPPORT */
17115 #ifdef GSCAN_SUPPORT
17116 cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
17117 cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
17118 cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
17119 cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
17120 cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
17121 cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
17122 cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
17123 cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
17124 #endif /* GSCAN_SUPPORT */
17125 #ifdef RSSI_MONITOR_SUPPORT
17126 cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
17127 #endif /* RSSI_MONITOR_SUPPORT */
17128 #ifdef WLTDLS
17129 cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
17130 #endif /* WLTDLS */
17131 cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
17132 #ifdef WL_RELMCAST
17133 cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
17134 #endif /* WL_RELMCAST */
17135 #ifdef BT_WIFI_HANDOVER
17136 cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] =
17137 wl_notify_bt_wifi_handover_req;
17138 #endif // endif
17139 #ifdef WL_NAN
17140 cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status;
17141 cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status;
17142 #endif /* WL_NAN */
17143 cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
17144 cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
17145 #ifdef CUSTOM_EVENT_PM_WAKE
17146 cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
17147 #endif /* CUSTOM_EVENT_PM_WAKE */
17148 #if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
17149 cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
17150 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
17151 cfg->evt_handler[WLC_E_ROAM_START] = wl_notify_roam_start_status;
17152 cfg->evt_handler[WLC_E_PSK_SUP] = wl_cfg80211_sup_event_handler;
17153 #ifdef WL_BCNRECV
17154 cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
17155 #endif /* WL_BCNRECV */
17156 #ifdef WL_MBO
17157 cfg->evt_handler[WLC_E_MBO] = wl_mbo_event_handler;
17158 #endif /* WL_MBO */
17159 #ifdef WL_CAC_TS
17160 cfg->evt_handler[WLC_E_ADDTS_IND] = wl_cfg80211_cac_event_handler;
17161 cfg->evt_handler[WLC_E_DELTS_IND] = wl_cfg80211_cac_event_handler;
17162 #endif /* WL_CAC_TS */
17163 #if defined(WL_MBO) || defined(WL_OCE)
17164 cfg->evt_handler[WLC_E_PRUNE] = wl_bssid_prune_event_handler;
17165 #endif /* WL_MBO || WL_OCE */
17166 #ifdef RTT_SUPPORT
17167 cfg->evt_handler[WLC_E_PROXD] = wl_cfg80211_rtt_event_handler;
17168 #endif // endif
17169 #ifdef WL_CHAN_UTIL
17170 cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler;
17171 #endif /* WL_CHAN_UTIL */
17172 #ifdef WL_CLIENT_SAE
17173 cfg->evt_handler[WLC_E_JOIN_START] = wl_notify_start_auth;
17174 #endif /* WL_CLIENT_SAE */
17175 }
17176
17177 #if defined(STATIC_WL_PRIV_STRUCT)
wl_init_escan_result_buf(struct bcm_cfg80211 * cfg)17178 static int wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
17179 {
17180 #ifdef DUAL_ESCAN_RESULT_BUFFER
17181 cfg->escan_info.escan_buf[0] =
17182 DHD_OS_PREALLOC(cfg->pub, DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
17183 if (cfg->escan_info.escan_buf[0] == NULL) {
17184 WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
17185 return -ENOMEM;
17186 }
17187
17188 cfg->escan_info.escan_buf[1] =
17189 DHD_OS_PREALLOC(cfg->pub, DHD_PREALLOC_WIPHY_ESCAN1, ESCAN_BUF_SIZE);
17190 if (cfg->escan_info.escan_buf[1] == NULL) {
17191 WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
17192 return -ENOMEM;
17193 }
17194
17195 bzero(cfg->escan_info.escan_buf[0], ESCAN_BUF_SIZE);
17196 bzero(cfg->escan_info.escan_buf[1], ESCAN_BUF_SIZE);
17197 cfg->escan_info.escan_type[0] = 0;
17198 cfg->escan_info.escan_type[1] = 0;
17199 #else
17200 cfg->escan_info.escan_buf =
17201 DHD_OS_PREALLOC(cfg->pub, DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
17202 if (cfg->escan_info.escan_buf == NULL) {
17203 WL_ERR(("Failed to alloc ESCAN_BUF\n"));
17204 return -ENOMEM;
17205 }
17206 bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
17207 #endif /* DUAL_ESCAN_RESULT_BUFFER */
17208
17209 return 0;
17210 }
17211
wl_deinit_escan_result_buf(struct bcm_cfg80211 * cfg)17212 static void wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
17213 {
17214 #ifdef DUAL_ESCAN_RESULT_BUFFER
17215 if (cfg->escan_info.escan_buf[0] != NULL) {
17216 cfg->escan_info.escan_buf[0] = NULL;
17217 cfg->escan_info.escan_type[0] = 0;
17218 }
17219
17220 if (cfg->escan_info.escan_buf[1] != NULL) {
17221 cfg->escan_info.escan_buf[1] = NULL;
17222 cfg->escan_info.escan_type[1] = 0;
17223 }
17224 #else
17225 if (cfg->escan_info.escan_buf != NULL) {
17226 cfg->escan_info.escan_buf = NULL;
17227 }
17228 #endif /* DUAL_ESCAN_RESULT_BUFFER */
17229 }
17230 #endif /* STATIC_WL_PRIV_STRUCT */
17231
wl_init_priv_mem(struct bcm_cfg80211 * cfg)17232 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
17233 {
17234 WL_DBG(("Enter \n"));
17235
17236 cfg->scan_results =
17237 (struct wl_scan_results *)MALLOCZ(cfg->osh, WL_SCAN_BUF_MAX);
17238 if (unlikely(!cfg->scan_results)) {
17239 WL_ERR(("Scan results alloc failed\n"));
17240 goto init_priv_mem_out;
17241 }
17242 cfg->conf = (struct wl_conf *)MALLOCZ(cfg->osh, sizeof(*cfg->conf));
17243 if (unlikely(!cfg->conf)) {
17244 WL_ERR(("wl_conf alloc failed\n"));
17245 goto init_priv_mem_out;
17246 }
17247 cfg->scan_req_int = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->scan_req_int));
17248 if (unlikely(!cfg->scan_req_int)) {
17249 WL_ERR(("Scan req alloc failed\n"));
17250 goto init_priv_mem_out;
17251 }
17252 cfg->ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
17253 if (unlikely(!cfg->ioctl_buf)) {
17254 WL_ERR(("Ioctl buf alloc failed\n"));
17255 goto init_priv_mem_out;
17256 }
17257 cfg->escan_ioctl_buf = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
17258 if (unlikely(!cfg->escan_ioctl_buf)) {
17259 WL_ERR(("Ioctl buf alloc failed\n"));
17260 goto init_priv_mem_out;
17261 }
17262 cfg->extra_buf = (void *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
17263 if (unlikely(!cfg->extra_buf)) {
17264 WL_ERR(("Extra buf alloc failed\n"));
17265 goto init_priv_mem_out;
17266 }
17267 cfg->pmk_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->pmk_list));
17268 if (unlikely(!cfg->pmk_list)) {
17269 WL_ERR(("pmk list alloc failed\n"));
17270 goto init_priv_mem_out;
17271 }
17272 #if defined(STATIC_WL_PRIV_STRUCT)
17273 cfg->conn_info = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->conn_info));
17274 if (unlikely(!cfg->conn_info)) {
17275 WL_ERR(("cfg->conn_info alloc failed\n"));
17276 goto init_priv_mem_out;
17277 }
17278 cfg->ie = (void *)MALLOC(cfg->osh, sizeof(*cfg->ie));
17279 if (unlikely(!cfg->ie)) {
17280 WL_ERR(("cfg->ie alloc failed\n"));
17281 goto init_priv_mem_out;
17282 }
17283 if (unlikely(wl_init_escan_result_buf(cfg))) {
17284 WL_ERR(("Failed to init escan resul buf\n"));
17285 goto init_priv_mem_out;
17286 }
17287 #endif /* STATIC_WL_PRIV_STRUCT */
17288 cfg->afx_hdl = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->afx_hdl));
17289 if (unlikely(!cfg->afx_hdl)) {
17290 WL_ERR(("afx hdl alloc failed\n"));
17291 goto init_priv_mem_out;
17292 } else {
17293 init_completion(&cfg->act_frm_scan);
17294 init_completion(&cfg->wait_next_af);
17295
17296 INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
17297 }
17298 #ifdef WLTDLS
17299 if (cfg->tdls_mgmt_frame) {
17300 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
17301 cfg->tdls_mgmt_frame = NULL;
17302 cfg->tdls_mgmt_frame_len = 0;
17303 }
17304 #endif /* WLTDLS */
17305 return 0;
17306
17307 init_priv_mem_out:
17308 wl_deinit_priv_mem(cfg);
17309
17310 return -ENOMEM;
17311 }
17312
wl_deinit_priv_mem(struct bcm_cfg80211 * cfg)17313 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
17314 {
17315 MFREE(cfg->osh, cfg->scan_results, WL_SCAN_BUF_MAX);
17316 MFREE(cfg->osh, cfg->conf, sizeof(*cfg->conf));
17317 MFREE(cfg->osh, cfg->scan_req_int, sizeof(*cfg->scan_req_int));
17318 MFREE(cfg->osh, cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
17319 MFREE(cfg->osh, cfg->escan_ioctl_buf, WLC_IOCTL_MAXLEN);
17320 MFREE(cfg->osh, cfg->extra_buf, WL_EXTRA_BUF_MAX);
17321 MFREE(cfg->osh, cfg->pmk_list, sizeof(*cfg->pmk_list));
17322 #if defined(STATIC_WL_PRIV_STRUCT)
17323 MFREE(cfg->osh, cfg->conn_info, sizeof(*cfg->conn_info));
17324 MFREE(cfg->osh, cfg->ie, sizeof(*cfg->ie));
17325 wl_deinit_escan_result_buf(cfg);
17326 #endif /* STATIC_WL_PRIV_STRUCT */
17327 if (cfg->afx_hdl) {
17328 cancel_work_sync(&cfg->afx_hdl->work);
17329 MFREE(cfg->osh, cfg->afx_hdl, sizeof(*cfg->afx_hdl));
17330 }
17331 }
17332
wl_create_event_handler(struct bcm_cfg80211 * cfg)17333 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
17334 {
17335 int ret = 0;
17336 WL_DBG(("Enter \n"));
17337
17338 /* Allocate workqueue for event */
17339 if (!cfg->event_workq) {
17340 cfg->event_workq = alloc_workqueue(
17341 "dhd_eventd", WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 1);
17342 }
17343
17344 if (!cfg->event_workq) {
17345 WL_ERR(("event_workq alloc_workqueue failed\n"));
17346 ret = -ENOMEM;
17347 } else {
17348 INIT_WORK(&cfg->event_work, wl_event_handler);
17349 }
17350 return ret;
17351 }
17352
wl_destroy_event_handler(struct bcm_cfg80211 * cfg)17353 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
17354 {
17355 if (cfg && cfg->event_workq) {
17356 cancel_work_sync(&cfg->event_work);
17357 destroy_workqueue(cfg->event_workq);
17358 cfg->event_workq = NULL;
17359 }
17360 }
17361
wl_terminate_event_handler(struct net_device * dev)17362 void wl_terminate_event_handler(struct net_device *dev)
17363 {
17364 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17365
17366 if (cfg) {
17367 wl_destroy_event_handler(cfg);
17368 wl_flush_eq(cfg);
17369 }
17370 }
17371
17372 #ifdef DHD_LOSSLESS_ROAMING
wl_del_roam_timeout(struct bcm_cfg80211 * cfg)17373 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
17374 {
17375 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
17376
17377 /* restore prec_map to ALLPRIO */
17378 dhdp->dequeue_prec_map = ALLPRIO;
17379 if (timer_pending(&cfg->roam_timeout)) {
17380 del_timer_sync(&cfg->roam_timeout);
17381 }
17382 }
17383
wl_roam_timeout(unsigned long data)17384 static void wl_roam_timeout(unsigned long data)
17385 {
17386 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
17387 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
17388
17389 WL_ERR(("roam timer expired\n"));
17390
17391 /* restore prec_map to ALLPRIO */
17392 dhdp->dequeue_prec_map = ALLPRIO;
17393 }
17394
17395 #endif /* DHD_LOSSLESS_ROAMING */
17396
17397 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
17398 #define CP_CHAN_INFO_RAT_MODE_LTE 3
17399 #define CP_CHAN_INFO_RAT_MODE_NR5G 7
17400 int g_mhs_chan_for_cpcoex = 0;
17401
17402 struct __packed cam_cp_noti_info {
17403 u8 rat;
17404 u32 band;
17405 u32 channel;
17406 };
17407
wl_cfg80211_send_msg_to_ril()17408 int wl_cfg80211_send_msg_to_ril()
17409 {
17410 int id, buf = 1;
17411
17412 id = IPC_SYSTEM_CP_CHANNEL_INFO;
17413 dev_ril_bridge_send_msg(id, sizeof(int), &buf);
17414 WL_ERR(("[BeyondX] send message to ril.\n"));
17415
17416 OSL_SLEEP(0x1F4);
17417 return 0;
17418 }
17419
wl_cfg80211_ril_bridge_notifier_call(struct notifier_block * nb,unsigned long size,void * buf)17420 int wl_cfg80211_ril_bridge_notifier_call(struct notifier_block *nb,
17421 unsigned long size, void *buf)
17422 {
17423 struct dev_ril_bridge_msg *msg;
17424 struct cam_cp_noti_info *cp_noti_info;
17425 static int mhs_channel_for_4g, mhs_channel_for_5g;
17426 static int recv_msg_4g, recv_msg_5g;
17427
17428 WL_ERR(("[BeyondX] receive message from ril.\n"));
17429 msg = (struct dev_ril_bridge_msg *)buf;
17430
17431 if (msg->dev_id == IPC_SYSTEM_CP_CHANNEL_INFO &&
17432 msg->data_len <= sizeof(struct cam_cp_noti_info)) {
17433 u8 rat;
17434 u32 band;
17435 u32 channel;
17436
17437 cp_noti_info = (struct cam_cp_noti_info *)msg->data;
17438 rat = cp_noti_info->rat;
17439 band = cp_noti_info->band;
17440 channel = cp_noti_info->channel;
17441
17442 /* LTE/5G Band/Freq information => Mobile Hotspot channel mapping.
17443 * LTE/B40: 38650~39649 => Ch.11
17444 * LTE/B41: 39650~41589 => Ch.1
17445 * 5G/N41: 499200~537999 => Ch.1
17446 */
17447 if (rat == CP_CHAN_INFO_RAT_MODE_LTE) {
17448 recv_msg_4g = 1;
17449 if (channel >= 0x96FA && channel <= 0x96FA) {
17450 mhs_channel_for_4g = 0xB;
17451 } else if (channel >= 0x96FA && channel <= 0xA275) {
17452 mhs_channel_for_4g = 1;
17453 }
17454 }
17455 if (rat == CP_CHAN_INFO_RAT_MODE_NR5G) {
17456 recv_msg_5g = 1;
17457 if (channel >= 0x79E00 && channel <= 0x8358F) {
17458 mhs_channel_for_5g = 1;
17459 }
17460 }
17461
17462 WL_DBG((
17463 "[BeyondX] rat: %u, band: %u, channel: %u, mhs_channel_for_4g: %u, "
17464 "mhs_channel_for_5g: %u\n",
17465 rat, band, channel, mhs_channel_for_4g, mhs_channel_for_5g));
17466
17467 if (recv_msg_4g && recv_msg_5g) {
17468 if (mhs_channel_for_4g && mhs_channel_for_5g) {
17469 /* if 4G/B40 + 5G/N41, select channel 6 for MHS */
17470 if (mhs_channel_for_4g == 0xB && mhs_channel_for_5g == 1) {
17471 g_mhs_chan_for_cpcoex = 0x6;
17472 /* if 4G(except for B40) + 5G/N41, select channel 1 for MHS
17473 */
17474 } else {
17475 g_mhs_chan_for_cpcoex = 1;
17476 }
17477 } else {
17478 g_mhs_chan_for_cpcoex = mhs_channel_for_4g ? mhs_channel_for_4g
17479 : mhs_channel_for_5g
17480 ? mhs_channel_for_5g
17481 : 0;
17482 }
17483 mhs_channel_for_4g = mhs_channel_for_5g = 0;
17484 recv_msg_4g = recv_msg_5g = 0;
17485 }
17486 }
17487
17488 return 0;
17489 }
17490
17491 static struct notifier_block wl_cfg80211_ril_bridge_notifier = {
17492 .notifier_call = wl_cfg80211_ril_bridge_notifier_call,
17493 };
17494
17495 static bool wl_cfg80211_ril_bridge_notifier_registered = FALSE;
17496 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
17497
wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,unsigned long state,void * ptr)17498 static s32 wl_cfg80211_netdev_notifier_call(struct notifier_block *nb,
17499 unsigned long state, void *ptr)
17500 {
17501 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
17502 struct net_device *dev = ptr;
17503 #else
17504 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
17505 #endif /* LINUX_VERSION < VERSION(3, 11, 0) */
17506 struct wireless_dev *wdev = NULL;
17507 struct bcm_cfg80211 *cfg = NULL;
17508
17509 WL_DBG(("Enter state:%lu ndev%p \n", state, dev));
17510 if (!dev) {
17511 WL_ERR(("dev null\n"));
17512 return NOTIFY_DONE;
17513 }
17514
17515 wdev = ndev_to_wdev(dev);
17516 if (!wdev) {
17517 WL_ERR(("wdev null. Do nothing\n"));
17518 return NOTIFY_DONE;
17519 }
17520
17521 cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
17522 if (!cfg || (cfg != wl_cfg80211_get_bcmcfg())) {
17523 /* If cfg80211 priv is null or doesn't match return */
17524 WL_ERR(("wrong cfg ptr (%p)\n", cfg));
17525 return NOTIFY_DONE;
17526 }
17527
17528 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
17529 /* Nothing to be done for primary I/F */
17530 return NOTIFY_DONE;
17531 }
17532
17533 switch (state) {
17534 case NETDEV_DOWN: {
17535 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
17536 int max_wait_timeout = 2;
17537 int max_wait_count = 0x64;
17538 int refcnt = 0;
17539 unsigned long limit = jiffies + max_wait_timeout * HZ;
17540 while (work_pending(&wdev->cleanup_work)) {
17541 if (refcnt % 0x5 == 0) {
17542 WL_ERR(("[NETDEV_DOWN] wait for "
17543 "complete of cleanup_work"
17544 " (%d th)\n",
17545 refcnt));
17546 }
17547 if (!time_before(jiffies, limit)) {
17548 WL_ERR(("[NETDEV_DOWN] cleanup_work"
17549 " of CFG80211 is not"
17550 " completed in %d sec\n",
17551 max_wait_timeout));
17552 break;
17553 }
17554 if (refcnt >= max_wait_count) {
17555 WL_ERR(("[NETDEV_DOWN] cleanup_work"
17556 " of CFG80211 is not"
17557 " completed in %d loop\n",
17558 max_wait_count));
17559 break;
17560 }
17561 set_current_state(TASK_INTERRUPTIBLE);
17562 (void)schedule_timeout(0x64);
17563 set_current_state(TASK_RUNNING);
17564 refcnt++;
17565 }
17566 #endif /* LINUX_VERSION < VERSION(3, 14, 0) */
17567 break;
17568 }
17569 case NETDEV_UNREGISTER:
17570 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
17571 /* after calling list_del_rcu(&wdev->list) */
17572 wl_dealloc_netinfo_by_wdev(cfg, wdev);
17573 break;
17574 case NETDEV_GOING_DOWN:
17575 /*
17576 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
17577 * In front of door, the function checks whether current scan
17578 * is working or not. If the scanning is still working,
17579 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
17580 */
17581 if (wl_get_drv_status(cfg, SCANNING, dev)) {
17582 wl_cfg80211_cancel_scan(cfg);
17583 }
17584 break;
17585 default:
17586 break;
17587 }
17588 return NOTIFY_DONE;
17589 }
17590
17591 static struct notifier_block wl_cfg80211_netdev_notifier = {
17592 .notifier_call = wl_cfg80211_netdev_notifier_call,
17593 };
17594
17595 /*
17596 * to make sure we won't register the same notifier twice, otherwise a loop is
17597 * likely to be created in kernel notifier link list (with 'next' pointing to
17598 * itself)
17599 */
17600 static bool wl_cfg80211_netdev_notifier_registered = FALSE;
17601
wl_cfg80211_concurrent_roam(struct bcm_cfg80211 * cfg,int enable)17602 static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
17603 {
17604 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
17605 bool p2p_connected = wl_cfgp2p_vif_created(cfg);
17606 struct net_info *iter, *next;
17607
17608 if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT)) {
17609 return;
17610 }
17611
17612 WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n", enable,
17613 p2p_connected, connected_cnt));
17614 /* Disable FW roam when we have a concurrent P2P connection */
17615 if (enable && p2p_connected && connected_cnt > 1) {
17616 /* Mark it as to be reverted */
17617 cfg->roam_flags |= WL_ROAM_REVERT_STATUS;
17618 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17619 for_each_ndev(cfg, iter, next)
17620 {
17621 GCC_DIAGNOSTIC_POP();
17622 if (iter->ndev && iter->wdev &&
17623 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
17624 if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE) ==
17625 BCME_OK) {
17626 iter->roam_off = TRUE;
17627 } else {
17628 WL_ERR(("error to enable roam_off\n"));
17629 }
17630 }
17631 }
17632 } else if (!enable && (cfg->roam_flags & WL_ROAM_REVERT_STATUS)) {
17633 cfg->roam_flags &= ~WL_ROAM_REVERT_STATUS;
17634 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17635 for_each_ndev(cfg, iter, next)
17636 {
17637 GCC_DIAGNOSTIC_POP();
17638 if (iter->ndev && iter->wdev &&
17639 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
17640 if (iter->roam_off != WL_INVALID) {
17641 if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE) ==
17642 BCME_OK) {
17643 iter->roam_off = FALSE;
17644 } else {
17645 WL_ERR(("error to disable roam_off\n"));
17646 }
17647 }
17648 }
17649 }
17650 }
17651
17652 return;
17653 }
17654
wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 * cfg)17655 static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
17656 {
17657 struct net_info *iter, *next;
17658 #ifdef WLEASYMESH
17659 struct net_device *primary_dev;
17660 dhd_pub_t *dhd = cfg->pub;
17661 #endif /* WLEASYMESH */
17662 u32 ctl_chan = 0;
17663 u32 chanspec = 0;
17664 u32 pre_ctl_chan = 0;
17665 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
17666 cfg->vsdb_mode = false;
17667
17668 if (connected_cnt <= 1) {
17669 return;
17670 }
17671 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17672 for_each_ndev(cfg, iter, next)
17673 {
17674 GCC_DIAGNOSTIC_POP();
17675 /* p2p discovery iface ndev could be null */
17676 if (iter->ndev) {
17677 chanspec = 0;
17678 ctl_chan = 0;
17679 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
17680 if (wldev_iovar_getint(iter->ndev, "chanspec",
17681 (s32 *)&chanspec) == BCME_OK) {
17682 chanspec = wl_chspec_driver_to_host(chanspec);
17683 ctl_chan = wf_chspec_ctlchan(chanspec);
17684 wl_update_prof(cfg, iter->ndev, NULL, &ctl_chan,
17685 WL_PROF_CHAN);
17686 }
17687 if (!cfg->vsdb_mode) {
17688 if (!pre_ctl_chan && ctl_chan) {
17689 pre_ctl_chan = ctl_chan;
17690 } else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) {
17691 cfg->vsdb_mode = true;
17692 }
17693 }
17694 }
17695 }
17696 }
17697 #ifdef WLEASYMESH
17698 if (dhd->conf->fw_type == FW_TYPE_EZMESH && cfg->vsdb_mode) {
17699 primary_dev = bcmcfg_to_prmry_ndev(cfg);
17700 WL_MSG("wlan", "check primary chanspec\n");
17701 if (wldev_iovar_getint(primary_dev, "chanspec", (s32 *)&chanspec) ==
17702 BCME_OK) {
17703 WL_MSG("wlan", "set primary chanspec to 0x%d\n", chanspec);
17704 wldev_iovar_setint(primary_dev, "chanspec", chanspec);
17705 }
17706 cfg->vsdb_mode = false;
17707 }
17708 #endif /* WLEASYMESH */
17709 WL_MSG("wlan", "%s concurrency is enabled\n",
17710 cfg->vsdb_mode ? "Multi Channel" : "Same Channel");
17711 return;
17712 }
17713
wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211 * cfg)17714 int wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211 *cfg)
17715 {
17716 struct net_info *iter, *next;
17717 u32 chanspec = 0;
17718 u32 band = 0;
17719 u32 pre_band = 0;
17720 bool is_rsdb_supported = FALSE;
17721 bool rsdb_mode = FALSE;
17722
17723 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
17724 if (!is_rsdb_supported) {
17725 return 0;
17726 }
17727 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17728 for_each_ndev(cfg, iter, next)
17729 {
17730 GCC_DIAGNOSTIC_POP();
17731 /* p2p discovery iface ndev could be null */
17732 if (iter->ndev) {
17733 chanspec = 0;
17734 band = 0;
17735 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
17736 if (wldev_iovar_getint(iter->ndev, "chanspec",
17737 (s32 *)&chanspec) == BCME_OK) {
17738 chanspec = wl_chspec_driver_to_host(chanspec);
17739 band = CHSPEC_BAND(chanspec);
17740 }
17741
17742 if (!pre_band && band) {
17743 pre_band = band;
17744 } else if (pre_band && (pre_band != band)) {
17745 rsdb_mode = TRUE;
17746 }
17747 }
17748 }
17749 }
17750 WL_DBG(("RSDB mode is %s\n", rsdb_mode ? "enabled" : "disabled"));
17751
17752 return rsdb_mode;
17753 }
17754
wl_notifier_change_state(struct bcm_cfg80211 * cfg,struct net_info * _net_info,enum wl_status state,bool set)17755 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg,
17756 struct net_info *_net_info,
17757 enum wl_status state, bool set)
17758 {
17759 s32 pm = PM_FAST;
17760 s32 err = BCME_OK;
17761 u32 mode;
17762 u32 chan = 0;
17763 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
17764 dhd_pub_t *dhd = cfg->pub;
17765 #ifdef RTT_SUPPORT
17766 rtt_status_info_t *rtt_status;
17767 #endif /* RTT_SUPPORT */
17768 if (dhd->busstate == DHD_BUS_DOWN) {
17769 WL_ERR(("busstate is DHD_BUS_DOWN!\n"));
17770 return 0;
17771 }
17772 WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n", state,
17773 set, _net_info->pm_restore, _net_info->ndev->name));
17774
17775 if (state != WL_STATUS_CONNECTED) {
17776 return 0;
17777 }
17778 mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
17779 if (set) {
17780 wl_cfg80211_concurrent_roam(cfg, 1);
17781 wl_cfg80211_determine_vsdb_mode(cfg);
17782 if (mode == WL_MODE_AP) {
17783 if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG,
17784 false)) {
17785 WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
17786 }
17787 }
17788 pm = PM_OFF;
17789 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
17790 sizeof(pm))) != 0) {
17791 if (err == -ENODEV) {
17792 WL_DBG(("%s:netdev not ready\n", _net_info->ndev->name));
17793 } else {
17794 WL_ERR(("%s:error (%d)\n", _net_info->ndev->name, err));
17795 }
17796
17797 wl_cfg80211_update_power_mode(_net_info->ndev);
17798 }
17799 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
17800 #if defined(WLTDLS)
17801 if (wl_cfg80211_is_concurrent_mode(primary_dev)) {
17802 err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
17803 }
17804 #endif /* defined(WLTDLS) */
17805
17806 #ifdef DISABLE_FRAMEBURST_VSDB
17807 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
17808 wl_cfg80211_is_concurrent_mode(primary_dev) &&
17809 !wl_cfg80211_determine_p2p_rsdb_mode(cfg)) {
17810 wl_cfg80211_set_frameburst(cfg, FALSE);
17811 }
17812 #endif /* DISABLE_FRAMEBURST_VSDB */
17813 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
17814 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
17815 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
17816 /* Enable frameburst for
17817 * STA/SoftAP concurrent mode
17818 */
17819 wl_cfg80211_set_frameburst(cfg, TRUE);
17820 }
17821 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
17822 } else { /* clear */
17823 chan = 0;
17824 /* clear chan information when the net device is disconnected */
17825 wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
17826 wl_cfg80211_determine_vsdb_mode(cfg);
17827 if (primary_dev == _net_info->ndev) {
17828 pm = PM_FAST;
17829 #ifdef RTT_SUPPORT
17830 rtt_status = GET_RTTSTATE(dhd);
17831 if (rtt_status->status != RTT_ENABLED) {
17832 #endif /* RTT_SUPPORT */
17833 if (dhd_conf_get_pm(dhd) >= 0) {
17834 pm = dhd_conf_get_pm(dhd);
17835 }
17836 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
17837 sizeof(pm))) != 0) {
17838 if (err == -ENODEV) {
17839 WL_DBG(
17840 ("%s:netdev not ready\n", _net_info->ndev->name));
17841 } else {
17842 WL_ERR(("%s:error (%d)\n", _net_info->ndev->name, err));
17843 }
17844
17845 wl_cfg80211_update_power_mode(_net_info->ndev);
17846 }
17847 #ifdef RTT_SUPPORT
17848 }
17849 #endif /* RTT_SUPPORT */
17850 }
17851 wl_cfg80211_concurrent_roam(cfg, 0);
17852 #if defined(WLTDLS)
17853 if (!wl_cfg80211_is_concurrent_mode(primary_dev)) {
17854 err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
17855 }
17856 #endif /* defined(WLTDLS) */
17857
17858 #if defined(DISABLE_FRAMEBURST_VSDB)
17859 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE)) {
17860 wl_cfg80211_set_frameburst(cfg, TRUE);
17861 }
17862 #endif /* DISABLE_FRAMEBURST_VSDB */
17863 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
17864 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
17865 (cfg->ap_oper_channel <= CH_MAX_2G_CHANNEL)) {
17866 /* Disable frameburst for stand-alone 2GHz SoftAP */
17867 wl_cfg80211_set_frameburst(cfg, FALSE);
17868 }
17869 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
17870 }
17871 return err;
17872 }
17873
17874 #ifdef DHD_LOSSLESS_ROAMING
wl_init_roam_timeout(struct bcm_cfg80211 * cfg)17875 static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
17876 {
17877 int err = 0;
17878
17879 /* Init roam timer */
17880 init_timer_compat(&cfg->roam_timeout, wl_roam_timeout, cfg);
17881
17882 return err;
17883 }
17884 #endif /* DHD_LOSSLESS_ROAMING */
17885
wl_init_priv(struct bcm_cfg80211 * cfg)17886 static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
17887 {
17888 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
17889 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
17890 s32 err = 0;
17891
17892 cfg->scan_request = NULL;
17893 cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
17894 #ifdef DISABLE_BUILTIN_ROAM
17895 cfg->roam_on = false;
17896 #else
17897 cfg->roam_on = true;
17898 #endif /* DISABLE_BUILTIN_ROAM */
17899 cfg->active_scan = true;
17900 cfg->rf_blocked = false;
17901 cfg->vsdb_mode = false;
17902 #if defined(BCMSDIO) || defined(BCMDBUS)
17903 cfg->wlfc_on = false;
17904 #endif /* BCMSDIO || BCMDBUS */
17905 cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
17906 cfg->disable_roam_event = false;
17907 /* register interested state */
17908 set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
17909 spin_lock_init(&cfg->cfgdrv_lock);
17910 mutex_init(&cfg->ioctl_buf_sync);
17911 init_waitqueue_head(&cfg->netif_change_event);
17912 init_completion(&cfg->send_af_done);
17913 init_completion(&cfg->iface_disable);
17914 mutex_init(&cfg->usr_sync);
17915 mutex_init(&cfg->event_sync);
17916 mutex_init(&cfg->if_sync);
17917 mutex_init(&cfg->scan_sync);
17918 mutex_init(&cfg->pm_sync);
17919 #ifdef WLTDLS
17920 mutex_init(&cfg->tdls_sync);
17921 #endif /* WLTDLS */
17922 #ifdef WL_BCNRECV
17923 mutex_init(&cfg->bcn_sync);
17924 #endif /* WL_BCNRECV */
17925 #ifdef WL_WPS_SYNC
17926 wl_init_wps_reauth_sm(cfg);
17927 #endif /* WL_WPS_SYNC */
17928 wl_init_eq(cfg);
17929 err = wl_init_priv_mem(cfg);
17930 if (err) {
17931 return err;
17932 }
17933 if (wl_create_event_handler(cfg)) {
17934 return -ENOMEM;
17935 }
17936 wl_init_event_handler(cfg);
17937 err = wl_init_scan(cfg);
17938 if (err) {
17939 return err;
17940 }
17941 #ifdef DHD_LOSSLESS_ROAMING
17942 err = wl_init_roam_timeout(cfg);
17943 if (err) {
17944 return err;
17945 }
17946 #endif /* DHD_LOSSLESS_ROAMING */
17947 wl_init_conf(cfg->conf);
17948 wl_init_prof(cfg, ndev);
17949 wl_link_down(cfg);
17950 DNGL_FUNC(dhd_cfg80211_init, (cfg));
17951 #ifdef WL_NAN
17952 cfg->nan_dp_state = NAN_DP_STATE_DISABLED;
17953 init_waitqueue_head(&cfg->ndp_if_change_event);
17954 mutex_init(&cfg->nancfg.nan_sync);
17955 init_waitqueue_head(&cfg->nancfg.nan_event_wait);
17956 #endif /* WL_NAN */
17957 cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
17958 cfg->pmk_list->pmkids.count = 0;
17959 cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
17960 return err;
17961 }
17962
wl_deinit_priv(struct bcm_cfg80211 * cfg)17963 static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
17964 {
17965 DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
17966 wl_destroy_event_handler(cfg);
17967 wl_flush_eq(cfg);
17968 wl_link_down(cfg);
17969 del_timer_sync(&cfg->scan_timeout);
17970 #ifdef DHD_LOSSLESS_ROAMING
17971 del_timer_sync(&cfg->roam_timeout);
17972 #endif // endif
17973 wl_deinit_priv_mem(cfg);
17974 if (wl_cfg80211_netdev_notifier_registered) {
17975 wl_cfg80211_netdev_notifier_registered = FALSE;
17976 unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
17977 }
17978 }
17979
17980 #if defined(WL_ENABLE_P2P_IF)
wl_cfg80211_attach_p2p(struct bcm_cfg80211 * cfg)17981 static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
17982 {
17983 WL_TRACE(("Enter \n"));
17984
17985 if (wl_cfgp2p_register_ndev(cfg) < 0) {
17986 WL_ERR(("P2P attach failed. \n"));
17987 return -ENODEV;
17988 }
17989
17990 return 0;
17991 }
17992
wl_cfg80211_detach_p2p(struct bcm_cfg80211 * cfg)17993 static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
17994 {
17995 struct wireless_dev *wdev;
17996
17997 WL_DBG(("Enter \n"));
17998 if (!cfg) {
17999 WL_ERR(("Invalid Ptr\n"));
18000 return -EINVAL;
18001 } else {
18002 wdev = cfg->p2p_wdev;
18003 if (!wdev) {
18004 WL_ERR(("Invalid Ptr\n"));
18005 return -EINVAL;
18006 }
18007 }
18008
18009 wl_cfgp2p_unregister_ndev(cfg);
18010
18011 cfg->p2p_wdev = NULL;
18012 cfg->p2p_net = NULL;
18013 WL_DBG(("Freeing 0x%p \n", wdev));
18014 kfree(wdev);
18015
18016 return 0;
18017 }
18018 #endif
18019
wl_cfg80211_attach_post(struct net_device * ndev)18020 static s32 wl_cfg80211_attach_post(struct net_device *ndev)
18021 {
18022 struct bcm_cfg80211 *cfg;
18023 s32 err = 0;
18024 s32 ret = 0;
18025 WL_TRACE(("In\n"));
18026 if (unlikely(!ndev)) {
18027 WL_ERR(("ndev is invaild\n"));
18028 return -ENODEV;
18029 }
18030 cfg = wl_get_cfg(ndev);
18031 if (unlikely(!cfg)) {
18032 WL_ERR(("cfg is invaild\n"));
18033 return -EINVAL;
18034 }
18035 if (!wl_get_drv_status(cfg, READY, ndev)) {
18036 if (cfg->wdev) {
18037 ret = wl_cfgp2p_supported(cfg, ndev);
18038 if (ret > 0) {
18039 #if !defined(WL_ENABLE_P2P_IF)
18040 cfg->wdev->wiphy->interface_modes |=
18041 (BIT(NL80211_IFTYPE_P2P_CLIENT) |
18042 BIT(NL80211_IFTYPE_P2P_GO));
18043 #endif /* !WL_ENABLE_P2P_IF */
18044 if ((err = wl_cfgp2p_init_priv(cfg)) != 0) {
18045 goto fail;
18046 }
18047
18048 #if defined(WL_ENABLE_P2P_IF)
18049 if (cfg->p2p_net) {
18050 /* Update MAC addr for p2p0 interface here. */
18051 memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
18052 cfg->p2p_net->dev_addr[0] |= 0x02;
18053 WL_MSG(cfg->p2p_net->name, "p2p_dev_addr=" MACDBG "\n",
18054 MAC2STRDBG(cfg->p2p_net->dev_addr));
18055 } else {
18056 WL_ERR(("p2p_net not yet populated."
18057 " Couldn't update the MAC Address for p2p0 \n"));
18058 return -ENODEV;
18059 }
18060 #endif /* WL_ENABLE_P2P_IF */
18061 cfg->p2p_supported = true;
18062 } else if (ret == 0) {
18063 if ((err = wl_cfgp2p_init_priv(cfg)) != 0) {
18064 goto fail;
18065 }
18066 } else {
18067 /* SDIO bus timeout */
18068 err = -ENODEV;
18069 goto fail;
18070 }
18071 }
18072 }
18073 wl_set_drv_status(cfg, READY, ndev);
18074 fail:
18075 return err;
18076 }
18077
wl_get_cfg(struct net_device * ndev)18078 struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev)
18079 {
18080 struct wireless_dev *wdev = ndev->ieee80211_ptr;
18081
18082 if (!wdev || !wdev->wiphy) {
18083 return NULL;
18084 }
18085
18086 return wiphy_priv(wdev->wiphy);
18087 }
18088
wl_cfg80211_net_attach(struct net_device * primary_ndev)18089 s32 wl_cfg80211_net_attach(struct net_device *primary_ndev)
18090 {
18091 struct bcm_cfg80211 *cfg = wl_get_cfg(primary_ndev);
18092 #ifdef WL_STATIC_IF
18093 enum nl80211_iftype ntype;
18094 int i;
18095 #endif
18096
18097 if (!cfg) {
18098 WL_ERR(("cfg null\n"));
18099 return BCME_ERROR;
18100 }
18101 #ifdef WL_STATIC_IF
18102 /* Register dummy n/w iface. FW init will happen only from dev_open */
18103 #ifdef WLEASYMESH
18104 ntype = NL80211_IFTYPE_AP;
18105 #else
18106 ntype = NL80211_IFTYPE_STATION;
18107 #endif
18108 for (i = 0; i < DHD_MAX_STATIC_IFS; i++) {
18109 if (wl_cfg80211_register_static_if(cfg, ntype, WL_STATIC_IFNAME_PREFIX,
18110 i) == NULL) {
18111 WL_ERR(("static i/f registration failed!\n"));
18112 wl_cfg80211_unregister_static_if(cfg);
18113 return BCME_ERROR;
18114 }
18115 }
18116 #endif /* WL_STATIC_IF */
18117 return BCME_OK;
18118 }
18119
wl_cfg80211_attach(struct net_device * ndev,void * context)18120 s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
18121 {
18122 struct wireless_dev *wdev;
18123 struct bcm_cfg80211 *cfg;
18124 s32 err = 0;
18125 struct device *dev;
18126 u16 bssidx = 0;
18127 u16 ifidx = 0;
18128 dhd_pub_t *dhd = (struct dhd_pub *)(context);
18129
18130 WL_TRACE(("In\n"));
18131 if (!ndev) {
18132 WL_ERR(("ndev is invaild\n"));
18133 return -ENODEV;
18134 }
18135 WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
18136 dev = wl_cfg80211_get_parent_dev();
18137
18138 wdev = (struct wireless_dev *)MALLOCZ(dhd->osh, sizeof(*wdev));
18139 if (unlikely(!wdev)) {
18140 WL_ERR(("Could not allocate wireless device\n"));
18141 return -ENOMEM;
18142 }
18143 err = wl_setup_wiphy(wdev, dev, context);
18144 if (unlikely(err)) {
18145 MFREE(dhd->osh, wdev, sizeof(*wdev));
18146 return -ENOMEM;
18147 }
18148 #ifdef WLMESH_CFG80211
18149 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_MESH);
18150 #else
18151 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
18152 #endif
18153 cfg = wiphy_priv(wdev->wiphy);
18154 cfg->wdev = wdev;
18155 cfg->pub = context;
18156 cfg->osh = dhd->osh;
18157 INIT_LIST_HEAD(&cfg->net_list);
18158 INIT_LIST_HEAD(&cfg->vndr_oui_list);
18159 spin_lock_init(&cfg->vndr_oui_sync);
18160 spin_lock_init(&cfg->net_list_sync);
18161 ndev->ieee80211_ptr = wdev;
18162 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
18163 wdev->netdev = ndev;
18164 cfg->state_notifier = wl_notifier_change_state;
18165 err = wl_alloc_netinfo(cfg, ndev, wdev, WL_IF_TYPE_STA, PM_ENABLE, bssidx,
18166 ifidx);
18167 if (err) {
18168 WL_ERR(("Failed to alloc net_info (%d)\n", err));
18169 goto cfg80211_attach_out;
18170 }
18171 err = wl_init_priv(cfg);
18172 if (err) {
18173 WL_ERR(("Failed to init iwm_priv (%d)\n", err));
18174 goto cfg80211_attach_out;
18175 }
18176
18177 err = wl_setup_rfkill(cfg, TRUE);
18178 if (err) {
18179 WL_ERR(("Failed to setup rfkill %d\n", err));
18180 goto cfg80211_attach_out;
18181 }
18182 #ifdef DEBUGFS_CFG80211
18183 err = wl_setup_debugfs(cfg);
18184 if (err) {
18185 WL_ERR(("Failed to setup debugfs %d\n", err));
18186 goto cfg80211_attach_out;
18187 }
18188 #endif // endif
18189 if (!wl_cfg80211_netdev_notifier_registered) {
18190 wl_cfg80211_netdev_notifier_registered = TRUE;
18191 err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
18192 if (err) {
18193 wl_cfg80211_netdev_notifier_registered = FALSE;
18194 WL_ERR(("Failed to register notifierl %d\n", err));
18195 goto cfg80211_attach_out;
18196 }
18197 }
18198 #if defined(COEX_DHCP)
18199 cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
18200 if (!cfg->btcoex_info) {
18201 goto cfg80211_attach_out;
18202 }
18203 #endif // endif
18204
18205 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
18206 wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
18207 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
18208
18209 #if defined(WL_ENABLE_P2P_IF)
18210 err = wl_cfg80211_attach_p2p(cfg);
18211 if (err) {
18212 goto cfg80211_attach_out;
18213 }
18214 #endif
18215
18216 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
18217 #ifdef WL_NAN
18218 WL_DBG(("NAN: Armed wl_cfgnan_delayed_disable work\n"));
18219 INIT_DELAYED_WORK(&cfg->nan_disable, wl_cfgnan_delayed_disable);
18220 #endif /* WL_NAN */
18221 cfg->rssi_sum_report = FALSE;
18222 return err;
18223
18224 cfg80211_attach_out:
18225 wl_cfg80211_detach(cfg);
18226 return err;
18227 }
18228
wl_cfg80211_detach(struct bcm_cfg80211 * cfg)18229 void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
18230 {
18231 WL_DBG(("Enter\n"));
18232 if (!cfg) {
18233 return;
18234 }
18235 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
18236
18237 #if defined(COEX_DHCP)
18238 wl_cfg80211_btcoex_deinit();
18239 cfg->btcoex_info = NULL;
18240 #endif // endif
18241
18242 wl_setup_rfkill(cfg, FALSE);
18243 #ifdef DEBUGFS_CFG80211
18244 wl_free_debugfs(cfg);
18245 #endif // endif
18246 if (cfg->p2p_supported) {
18247 if (timer_pending(&cfg->p2p->listen_timer)) {
18248 del_timer_sync(&cfg->p2p->listen_timer);
18249 }
18250 wl_cfgp2p_deinit_priv(cfg);
18251 }
18252
18253 #ifdef WL_WPS_SYNC
18254 wl_deinit_wps_reauth_sm(cfg);
18255 #endif /* WL_WPS_SYNC */
18256
18257 if (timer_pending(&cfg->scan_timeout)) {
18258 del_timer_sync(&cfg->scan_timeout);
18259 }
18260 #ifdef DHD_LOSSLESS_ROAMING
18261 if (timer_pending(&cfg->roam_timeout)) {
18262 del_timer_sync(&cfg->roam_timeout);
18263 }
18264 #endif /* DHD_LOSSLESS_ROAMING */
18265
18266 #ifdef WL_STATIC_IF
18267 wl_cfg80211_unregister_static_if(cfg);
18268 #endif /* WL_STATIC_IF */
18269 #if defined(WL_CFG80211_P2P_DEV_IF)
18270 if (cfg->p2p_wdev) {
18271 wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
18272 }
18273 #endif /* WL_CFG80211_P2P_DEV_IF */
18274 #if defined(WL_ENABLE_P2P_IF)
18275 wl_cfg80211_detach_p2p(cfg);
18276 #endif
18277 wl_cfg80211_ibss_vsie_free(cfg);
18278 wl_dealloc_netinfo_by_wdev(cfg, cfg->wdev);
18279 wl_cfg80211_set_bcmcfg(NULL);
18280 wl_deinit_priv(cfg);
18281 wl_cfg80211_clear_parent_dev();
18282 #if defined(RSSIAVG)
18283 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
18284 wl_free_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
18285 #endif
18286 #if defined(BSSCACHE)
18287 wl_release_bss_cache_ctrl(&cfg->g_bss_cache_ctrl);
18288 #endif
18289 wl_free_wdev(cfg);
18290 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
18291 * structure "cfg", which is the private part of wiphy, has been freed in
18292 * wl_free_wdev !!!!!!!!!!!
18293 */
18294 WL_DBG(("Exit\n"));
18295 }
18296
18297 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
wl_cfg80211_register_dev_ril_bridge_event_notifier()18298 void wl_cfg80211_register_dev_ril_bridge_event_notifier()
18299 {
18300 WL_DBG(("Enter\n"));
18301 if (!wl_cfg80211_ril_bridge_notifier_registered) {
18302 s32 err = 0;
18303 wl_cfg80211_ril_bridge_notifier_registered = TRUE;
18304 err = register_dev_ril_bridge_event_notifier(
18305 &wl_cfg80211_ril_bridge_notifier);
18306 if (err) {
18307 wl_cfg80211_ril_bridge_notifier_registered = FALSE;
18308 WL_ERR(("Failed to register ril_notifier! %d\n", err));
18309 }
18310 }
18311 }
18312
wl_cfg80211_unregister_dev_ril_bridge_event_notifier()18313 void wl_cfg80211_unregister_dev_ril_bridge_event_notifier()
18314 {
18315 WL_DBG(("Enter\n"));
18316 if (wl_cfg80211_ril_bridge_notifier_registered) {
18317 wl_cfg80211_ril_bridge_notifier_registered = FALSE;
18318 unregister_dev_ril_bridge_event_notifier(
18319 &wl_cfg80211_ril_bridge_notifier);
18320 }
18321 }
18322 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
18323
wl_print_event_data(struct bcm_cfg80211 * cfg,uint32 event_type,const wl_event_msg_t * e)18324 static void wl_print_event_data(struct bcm_cfg80211 *cfg, uint32 event_type,
18325 const wl_event_msg_t *e)
18326 {
18327 s32 status = ntoh32(e->status);
18328 s32 reason = ntoh32(e->reason);
18329 s32 ifidx = ntoh32(e->ifidx);
18330 s32 bssidx = ntoh32(e->bsscfgidx);
18331
18332 switch (event_type) {
18333 case WLC_E_ESCAN_RESULT:
18334 if ((status == WLC_E_STATUS_SUCCESS) ||
18335 (status == WLC_E_STATUS_ABORT)) {
18336 WL_INFORM_MEM(("event_type (%d), ifidx: %d"
18337 " bssidx: %d scan_type:%d\n",
18338 event_type, ifidx, bssidx, status));
18339 }
18340 break;
18341 case WLC_E_LINK:
18342 case WLC_E_DISASSOC:
18343 case WLC_E_DISASSOC_IND:
18344 case WLC_E_DEAUTH:
18345 case WLC_E_DEAUTH_IND:
18346 WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
18347 " status:%d reason:%d\n",
18348 event_type, ifidx, bssidx, status, reason));
18349 break;
18350
18351 default:
18352 /* Print only when DBG verbose is enabled */
18353 WL_DBG(
18354 ("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
18355 event_type, ifidx, bssidx, status, reason));
18356 }
18357 }
18358
wl_event_handler(struct work_struct * work_data)18359 static void wl_event_handler(struct work_struct *work_data)
18360 {
18361 struct bcm_cfg80211 *cfg = NULL;
18362 struct wl_event_q *e;
18363 struct wireless_dev *wdev = NULL;
18364
18365 WL_DBG(("Enter \n"));
18366 BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
18367 cfg->wl_evt_hdlr_entry_time = OSL_LOCALTIME_NS();
18368 DHD_EVENT_WAKE_LOCK(cfg->pub);
18369 while ((e = wl_deq_event(cfg))) {
18370 s32 status = ntoh32(e->emsg.status);
18371 u32 event_type = ntoh32(e->emsg.event_type);
18372 bool scan_cmplt_evt = (event_type == WLC_E_ESCAN_RESULT) &&
18373 ((status == WLC_E_STATUS_SUCCESS) ||
18374 (status == WLC_E_STATUS_ABORT));
18375
18376 cfg->wl_evt_deq_time = OSL_LOCALTIME_NS();
18377 if (scan_cmplt_evt) {
18378 cfg->scan_deq_time = OSL_LOCALTIME_NS();
18379 }
18380 /* Print only critical events to avoid too many prints */
18381 wl_print_event_data(cfg, e->etype, &e->emsg);
18382
18383 if (e->emsg.ifidx > WL_MAX_IFS) {
18384 WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
18385 goto fail;
18386 }
18387
18388 /* Make sure iface operations, don't creat race conditions */
18389 mutex_lock(&cfg->if_sync);
18390 if (!(wdev = wl_get_wdev_by_fw_idx(cfg, e->emsg.bsscfgidx,
18391 e->emsg.ifidx))) {
18392 /* For WLC_E_IF would be handled by wl_host_event */
18393 if (e->etype != WLC_E_IF) {
18394 WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
18395 " Ignoring event.\n",
18396 e->emsg.bsscfgidx));
18397 }
18398 } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
18399 dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
18400 if (dhd->busstate == DHD_BUS_DOWN) {
18401 WL_ERR((": BUS is DOWN.\n"));
18402 } else {
18403 WL_DBG(("event_type %d event_sub %d\n",
18404 ntoh32(e->emsg.event_type), ntoh32(e->emsg.reason)));
18405 cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev), &e->emsg,
18406 e->edata);
18407 if (scan_cmplt_evt) {
18408 cfg->scan_hdlr_cmplt_time = OSL_LOCALTIME_NS();
18409 }
18410 }
18411 } else {
18412 WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
18413 }
18414 mutex_unlock(&cfg->if_sync);
18415 fail:
18416 wl_put_event(cfg, e);
18417 if (scan_cmplt_evt) {
18418 cfg->scan_cmplt_time = OSL_LOCALTIME_NS();
18419 }
18420 cfg->wl_evt_hdlr_exit_time = OSL_LOCALTIME_NS();
18421 }
18422 DHD_EVENT_WAKE_UNLOCK(cfg->pub);
18423 }
18424
18425 /*
18426 * Generic API to handle critical events which doesnt need
18427 * cfg enquening and sleepable API calls.
18428 */
wl_cfg80211_handle_critical_events(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)18429 s32 wl_cfg80211_handle_critical_events(struct bcm_cfg80211 *cfg,
18430 const wl_event_msg_t *e)
18431 {
18432 s32 ret = BCME_ERROR;
18433 u32 event_type = ntoh32(e->event_type);
18434 if (event_type >= WLC_E_LAST) {
18435 return BCME_ERROR;
18436 }
18437 switch (event_type) {
18438 case WLC_E_NAN_CRITICAL: {
18439 #ifdef WL_NAN
18440 if (ntoh32(e->reason) == WL_NAN_EVENT_STOP) {
18441 ret = wl_cfgvendor_nan_send_async_disable_resp(
18442 cfg->static_ndev->ieee80211_ptr);
18443 }
18444 #endif /* WL_NAN */
18445 break;
18446 }
18447 default:
18448 ret = BCME_ERROR;
18449 }
18450 return ret;
18451 }
18452
wl_cfg80211_event(struct net_device * ndev,const wl_event_msg_t * e,void * data)18453 void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e,
18454 void *data)
18455 {
18456 s32 status = ntoh32(e->status);
18457 u32 event_type = ntoh32(e->event_type);
18458 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18459 struct net_info *netinfo;
18460
18461 WL_DBG(("event_type (%d): reason (%d): %s\n", event_type, ntoh32(e->reason),
18462 bcmevent_get_name(event_type)));
18463 if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
18464 WL_ERR(("Stale event ignored\n"));
18465 return;
18466 }
18467
18468 if (cfg->event_workq == NULL) {
18469 WL_ERR(("Event handler is not created\n"));
18470 return;
18471 }
18472
18473 if (event_type == WLC_E_IF) {
18474 /* Don't process WLC_E_IF events in wl_cfg80211 layer */
18475 return;
18476 }
18477
18478 netinfo = wl_get_netinfo_by_fw_idx(cfg, e->bsscfgidx, e->ifidx);
18479 if (!netinfo) {
18480 /* Since the netinfo entry is not there, the netdev entry is not
18481 * created via cfg80211 interface. so the event is not of interest
18482 * to the cfg80211 layer.
18483 */
18484 WL_TRACE(("ignore event %d, not interested\n", event_type));
18485 return;
18486 }
18487
18488 /* Handle wl_cfg80211_critical_events */
18489 if (wl_cfg80211_handle_critical_events(cfg, e) == BCME_OK) {
18490 return;
18491 }
18492
18493 if (event_type == WLC_E_PFN_NET_FOUND) {
18494 WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
18495 } else if (event_type == WLC_E_PFN_NET_LOST) {
18496 WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
18497 }
18498
18499 if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
18500 queue_work(cfg->event_workq, &cfg->event_work);
18501 }
18502 /* Mark timeout value for thread sched */
18503 if ((event_type == WLC_E_ESCAN_RESULT) &&
18504 ((status == WLC_E_STATUS_SUCCESS) || (status == WLC_E_STATUS_ABORT))) {
18505 cfg->scan_enq_time = OSL_LOCALTIME_NS();
18506 WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
18507 status, work_busy(&cfg->event_work)));
18508 }
18509 }
18510
wl_init_eq(struct bcm_cfg80211 * cfg)18511 static void wl_init_eq(struct bcm_cfg80211 *cfg)
18512 {
18513 wl_init_eq_lock(cfg);
18514 INIT_LIST_HEAD(&cfg->eq_list);
18515 }
18516
wl_flush_eq(struct bcm_cfg80211 * cfg)18517 static void wl_flush_eq(struct bcm_cfg80211 *cfg)
18518 {
18519 struct wl_event_q *e;
18520 unsigned long flags;
18521
18522 flags = wl_lock_eq(cfg);
18523 while (!list_empty_careful(&cfg->eq_list)) {
18524 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
18525 list_del(&e->eq_list);
18526 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
18527 }
18528 wl_unlock_eq(cfg, flags);
18529 }
18530
18531 /*
18532 * retrieve first queued event from head
18533 */
18534
wl_deq_event(struct bcm_cfg80211 * cfg)18535 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
18536 {
18537 struct wl_event_q *e = NULL;
18538 unsigned long flags;
18539
18540 flags = wl_lock_eq(cfg);
18541 if (likely(!list_empty(&cfg->eq_list))) {
18542 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
18543 list_del(&e->eq_list);
18544 }
18545 wl_unlock_eq(cfg, flags);
18546
18547 return e;
18548 }
18549
18550 /*
18551 * push event to tail of the queue
18552 */
18553
wl_enq_event(struct bcm_cfg80211 * cfg,struct net_device * ndev,u32 event,const wl_event_msg_t * msg,void * data)18554 static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev,
18555 u32 event, const wl_event_msg_t *msg, void *data)
18556 {
18557 struct wl_event_q *e;
18558 s32 err = 0;
18559 uint32 evtq_size;
18560 uint32 data_len;
18561 unsigned long flags;
18562
18563 data_len = 0;
18564 if (data) {
18565 data_len = ntoh32(msg->datalen);
18566 }
18567 evtq_size = (uint32)(sizeof(struct wl_event_q) + data_len);
18568 e = (struct wl_event_q *)MALLOCZ(cfg->osh, evtq_size);
18569 if (unlikely(!e)) {
18570 WL_ERR(("event alloc failed\n"));
18571 return -ENOMEM;
18572 }
18573 e->etype = event;
18574 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
18575 if (data) {
18576 memcpy(e->edata, data, data_len);
18577 }
18578 e->datalen = data_len;
18579 flags = wl_lock_eq(cfg);
18580 list_add_tail(&e->eq_list, &cfg->eq_list);
18581 wl_unlock_eq(cfg, flags);
18582
18583 return err;
18584 }
18585
wl_put_event(struct bcm_cfg80211 * cfg,struct wl_event_q * e)18586 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e)
18587 {
18588 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
18589 }
18590
wl_config_infra(struct bcm_cfg80211 * cfg,struct net_device * ndev,u16 iftype)18591 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev,
18592 u16 iftype)
18593 {
18594 s32 infra = 0;
18595 s32 err = 0;
18596 bool skip_infra = false;
18597
18598 switch (iftype) {
18599 case WL_IF_TYPE_IBSS:
18600 case WL_IF_TYPE_AIBSS:
18601 infra = 0;
18602 break;
18603 case WL_IF_TYPE_AP:
18604 case WL_IF_TYPE_STA:
18605 case WL_IF_TYPE_P2P_GO:
18606 case WL_IF_TYPE_P2P_GC:
18607 /* Intentional fall through */
18608 infra = 1;
18609 break;
18610 #ifdef WLMESH_CFG80211
18611 case NL80211_IFTYPE_MESH_POINT:
18612 infra = WL_BSSTYPE_MESH;
18613 break;
18614 #endif /* WLMESH_CFG80211 */
18615 case WL_IF_TYPE_MONITOR:
18616 case WL_IF_TYPE_NAN:
18617 /* Intentionall fall through */
18618 default:
18619 skip_infra = true;
18620 WL_ERR(("Skipping infra setting for type:%d\n", iftype));
18621 break;
18622 }
18623
18624 if (!skip_infra) {
18625 infra = htod32(infra);
18626 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
18627 if (unlikely(err)) {
18628 WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
18629 return err;
18630 }
18631 }
18632 return 0;
18633 }
18634
wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf * ev,u16 event,bool set)18635 void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event,
18636 bool set)
18637 {
18638 if (!ev || (event > WLC_E_LAST)) {
18639 return;
18640 }
18641
18642 if (ev->num < MAX_EVENT_BUF_NUM) {
18643 ev->event[ev->num].type = event;
18644 ev->event[ev->num].set = set;
18645 ev->num++;
18646 } else {
18647 WL_ERR(("evenbuffer doesn't support > %u events. Update"
18648 " the define MAX_EVENT_BUF_NUM \n",
18649 MAX_EVENT_BUF_NUM));
18650 ASSERT(0);
18651 }
18652 }
18653
wl_cfg80211_apply_eventbuffer(struct net_device * ndev,struct bcm_cfg80211 * cfg,wl_eventmsg_buf_t * ev)18654 s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev,
18655 struct bcm_cfg80211 *cfg,
18656 wl_eventmsg_buf_t *ev)
18657 {
18658 char eventmask[WL_EVENTING_MASK_LEN];
18659 int i, ret = 0;
18660 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
18661
18662 if (!ev || (!ev->num)) {
18663 return -EINVAL;
18664 }
18665
18666 mutex_lock(&cfg->event_sync);
18667
18668 /* Read event_msgs mask */
18669 ret = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf,
18670 sizeof(iovbuf), NULL);
18671 if (unlikely(ret)) {
18672 WL_ERR(("Get event_msgs error (%d)\n", ret));
18673 goto exit;
18674 }
18675 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
18676
18677 /* apply the set bits */
18678 for (i = 0; i < ev->num; i++) {
18679 if (ev->event[i].set) {
18680 setbit(eventmask, ev->event[i].type);
18681 } else {
18682 clrbit(eventmask, ev->event[i].type);
18683 }
18684 }
18685
18686 /* Write updated Event mask */
18687 ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask),
18688 iovbuf, sizeof(iovbuf), NULL);
18689 if (unlikely(ret)) {
18690 WL_ERR(("Set event_msgs error (%d)\n", ret));
18691 }
18692
18693 exit:
18694 mutex_unlock(&cfg->event_sync);
18695 return ret;
18696 }
18697
wl_add_remove_eventmsg(struct net_device * ndev,u16 event,bool add)18698 s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
18699 {
18700 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
18701 s8 eventmask[WL_EVENTING_MASK_LEN];
18702 s32 err = 0;
18703 struct bcm_cfg80211 *cfg;
18704
18705 if (!ndev) {
18706 return -ENODEV;
18707 }
18708
18709 cfg = wl_get_cfg(ndev);
18710 if (!cfg) {
18711 return -ENODEV;
18712 }
18713
18714 mutex_lock(&cfg->event_sync);
18715
18716 /* Setup event_msgs */
18717 err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf,
18718 sizeof(iovbuf), NULL);
18719 if (unlikely(err)) {
18720 WL_ERR(("Get event_msgs error (%d)\n", err));
18721 goto eventmsg_out;
18722 }
18723 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
18724 if (add) {
18725 setbit(eventmask, event);
18726 } else {
18727 clrbit(eventmask, event);
18728 }
18729 err =
18730 wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
18731 iovbuf, sizeof(iovbuf), NULL);
18732 if (unlikely(err)) {
18733 WL_ERR(("Set event_msgs error (%d)\n", err));
18734 goto eventmsg_out;
18735 }
18736
18737 eventmsg_out:
18738 mutex_unlock(&cfg->event_sync);
18739 return err;
18740 }
18741
wl_construct_reginfo(struct bcm_cfg80211 * cfg,s32 bw_cap)18742 static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
18743 {
18744 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
18745 struct ieee80211_channel *band_chan_arr = NULL;
18746 wl_uint32_list_t *list;
18747 u32 i, j, index, n_2g, n_5g, band, channel, array_size;
18748 u32 *n_cnt = NULL;
18749 chanspec_t c = 0;
18750 s32 err = BCME_OK;
18751 bool update;
18752 bool ht40_allowed;
18753 u8 *pbuf = NULL;
18754 bool dfs_radar_disabled = FALSE;
18755
18756 #define LOCAL_BUF_LEN 2048
18757 pbuf = (u8 *)MALLOCZ(cfg->osh, LOCAL_BUF_LEN);
18758 if (pbuf == NULL) {
18759 WL_ERR(("failed to allocate local buf\n"));
18760 return -ENOMEM;
18761 }
18762
18763 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL, 0, pbuf,
18764 LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
18765 if (err != 0) {
18766 WL_ERR(("get chanspecs failed with %d\n", err));
18767 MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
18768 return err;
18769 }
18770
18771 list = (wl_uint32_list_t *)(void *)pbuf;
18772 band = array_size = n_2g = n_5g = 0;
18773 for (i = 0; i < dtoh32(list->count); i++) {
18774 index = 0;
18775 update = false;
18776 ht40_allowed = false;
18777 c = (chanspec_t)dtoh32(list->element[i]);
18778 c = wl_chspec_driver_to_host(c);
18779 channel = wf_chspec_ctlchan(c);
18780
18781 if (!CHSPEC_IS40(c) && !CHSPEC_IS20(c)) {
18782 WL_DBG(("HT80/160/80p80 center channel : %d\n", channel));
18783 continue;
18784 }
18785 if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
18786 (channel <= CH_MAX_2G_CHANNEL)) {
18787 band_chan_arr = __wl_2ghz_channels;
18788 array_size = ARRAYSIZE(__wl_2ghz_channels);
18789 n_cnt = &n_2g;
18790 band = IEEE80211_BAND_2GHZ;
18791 ht40_allowed = (bw_cap == WLC_N_BW_40ALL) ? true : false;
18792 } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
18793 band_chan_arr = __wl_5ghz_a_channels;
18794 array_size = ARRAYSIZE(__wl_5ghz_a_channels);
18795 n_cnt = &n_5g;
18796 band = IEEE80211_BAND_5GHZ;
18797 ht40_allowed = (bw_cap == WLC_N_BW_20ALL) ? false : true;
18798 } else {
18799 WL_ERR(("Invalid channel Sepc. 0x%x.\n", c));
18800 continue;
18801 }
18802 if (!ht40_allowed && CHSPEC_IS40(c)) {
18803 continue;
18804 }
18805 for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
18806 if (band_chan_arr[j].hw_value == channel) {
18807 update = true;
18808 break;
18809 }
18810 }
18811 if (update) {
18812 index = j;
18813 } else {
18814 index = *n_cnt;
18815 }
18816 if (!dhd_conf_match_channel(cfg->pub, channel)) {
18817 continue;
18818 }
18819 if (index < array_size) {
18820 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && \
18821 !defined(WL_COMPAT_WIRELESS)
18822 band_chan_arr[index].center_freq =
18823 ieee80211_channel_to_frequency(channel);
18824 #else
18825 band_chan_arr[index].center_freq =
18826 ieee80211_channel_to_frequency(channel, band);
18827 #endif // endif
18828 band_chan_arr[index].hw_value = channel;
18829 band_chan_arr[index].beacon_found = false;
18830
18831 if (CHSPEC_IS40(c) && ht40_allowed) {
18832 /* assuming the order is HT20, HT40 Upper,
18833 * HT40 lower from chanspecs
18834 */
18835 u32 ht40_flag =
18836 band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
18837 if (CHSPEC_SB_UPPER(c)) {
18838 if (ht40_flag == IEEE80211_CHAN_NO_HT40) {
18839 band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
18840 }
18841 band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
18842 } else {
18843 /* It should be one of
18844 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
18845 */
18846 band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
18847 if (ht40_flag == IEEE80211_CHAN_NO_HT40) {
18848 band_chan_arr[index].flags |=
18849 IEEE80211_CHAN_NO_HT40MINUS;
18850 }
18851 }
18852 } else {
18853 band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
18854 if (!dfs_radar_disabled) {
18855 if (band == IEEE80211_BAND_2GHZ) {
18856 channel |= WL_CHANSPEC_BAND_2G;
18857 } else {
18858 channel |= WL_CHANSPEC_BAND_5G;
18859 }
18860 channel |= WL_CHANSPEC_BW_20;
18861 channel = wl_chspec_host_to_driver(channel);
18862 err = wldev_iovar_getint(dev, "per_chan_info", &channel);
18863 if (!err) {
18864 if (channel & WL_CHAN_RADAR) {
18865 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
18866 band_chan_arr[index].flags |=
18867 (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS);
18868 #else
18869 band_chan_arr[index].flags |= IEEE80211_CHAN_RADAR;
18870 #endif // endif
18871 }
18872
18873 if (channel & WL_CHAN_PASSIVE)
18874 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
18875 band_chan_arr[index].flags |=
18876 IEEE80211_CHAN_PASSIVE_SCAN;
18877 #else
18878 band_chan_arr[index].flags |= IEEE80211_CHAN_NO_IR;
18879 #endif // endif
18880 } else if (err == BCME_UNSUPPORTED) {
18881 dfs_radar_disabled = TRUE;
18882 WL_ERR(("does not support per_chan_info\n"));
18883 }
18884 }
18885 }
18886 if (!update) {
18887 (*n_cnt)++;
18888 }
18889 }
18890 }
18891 __wl_band_2ghz.n_channels = n_2g;
18892 __wl_band_5ghz_a.n_channels = n_5g;
18893 MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
18894 #undef LOCAL_BUF_LEN
18895
18896 return err;
18897 }
18898
__wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)18899 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
18900 {
18901 struct wiphy *wiphy;
18902 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
18903 u32 bandlist[3];
18904 u32 nband = 0;
18905 u32 i = 0;
18906 s32 err = 0;
18907 s32 index = 0;
18908 s32 nmode = 0;
18909 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18910 u32 j = 0;
18911 s32 vhtmode = 0;
18912 s32 txstreams = 0;
18913 s32 rxstreams = 0;
18914 s32 ldpc_cap = 0;
18915 s32 stbc_rx = 0;
18916 s32 stbc_tx = 0;
18917 s32 txbf_bfe_cap = 0;
18918 s32 txbf_bfr_cap = 0;
18919 #endif // endif
18920 s32 bw_cap = 0;
18921 s32 cur_band = -1;
18922 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {
18923 NULL,
18924 };
18925
18926 bzero(bandlist, sizeof(bandlist));
18927 err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist, sizeof(bandlist));
18928 if (unlikely(err)) {
18929 WL_ERR(("error read bandlist (%d)\n", err));
18930 return err;
18931 }
18932 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(s32));
18933 if (unlikely(err)) {
18934 WL_ERR(("error (%d)\n", err));
18935 return err;
18936 }
18937
18938 err = wldev_iovar_getint(dev, "nmode", &nmode);
18939 if (unlikely(err)) {
18940 WL_ERR(("error reading nmode (%d)\n", err));
18941 }
18942
18943 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18944 err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
18945 if (unlikely(err)) {
18946 WL_ERR(("error reading vhtmode (%d)\n", err));
18947 }
18948
18949 if (vhtmode) {
18950 err = wldev_iovar_getint(dev, "txstreams", &txstreams);
18951 if (unlikely(err)) {
18952 WL_ERR(("error reading txstreams (%d)\n", err));
18953 }
18954
18955 err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
18956 if (unlikely(err)) {
18957 WL_ERR(("error reading rxstreams (%d)\n", err));
18958 }
18959
18960 err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
18961 if (unlikely(err)) {
18962 WL_ERR(("error reading ldpc_cap (%d)\n", err));
18963 }
18964
18965 err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
18966 if (unlikely(err)) {
18967 WL_ERR(("error reading stbc_rx (%d)\n", err));
18968 }
18969
18970 err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
18971 if (unlikely(err)) {
18972 WL_ERR(("error reading stbc_tx (%d)\n", err));
18973 }
18974
18975 err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
18976 if (unlikely(err)) {
18977 WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
18978 }
18979
18980 err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
18981 if (unlikely(err)) {
18982 WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
18983 }
18984 }
18985 #endif // endif
18986
18987 /* For nmode and vhtmode check bw cap */
18988 if (nmode ||
18989 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
18990 vhtmode ||
18991 #endif // endif
18992 0) {
18993 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
18994 if (unlikely(err)) {
18995 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
18996 }
18997 }
18998
18999 err = wl_construct_reginfo(cfg, bw_cap);
19000 if (err) {
19001 WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
19002 if (err != BCME_UNSUPPORTED) {
19003 return err;
19004 }
19005 }
19006
19007 wiphy = bcmcfg_to_wiphy(cfg);
19008 nband = bandlist[0];
19009
19010 for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
19011 index = -1;
19012 if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
19013 bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
19014 index = IEEE80211_BAND_5GHZ;
19015 if (nmode && (bw_cap == WLC_N_BW_40ALL ||
19016 bw_cap == WLC_N_BW_20IN2G_40IN5G)) {
19017 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
19018 }
19019
19020 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19021 /* VHT capabilities. */
19022 if (vhtmode) {
19023 /* Supported */
19024 bands[index]->vht_cap.vht_supported = TRUE;
19025
19026 for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
19027 /* TX stream rates. */
19028 if (j <= txstreams) {
19029 VHT_MCS_MAP_SET_MCS_PER_SS(
19030 j, VHT_CAP_MCS_MAP_0_9,
19031 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
19032 } else {
19033 VHT_MCS_MAP_SET_MCS_PER_SS(
19034 j, VHT_CAP_MCS_MAP_NONE,
19035 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
19036 }
19037
19038 /* RX stream rates. */
19039 if (j <= rxstreams) {
19040 VHT_MCS_MAP_SET_MCS_PER_SS(
19041 j, VHT_CAP_MCS_MAP_0_9,
19042 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
19043 } else {
19044 VHT_MCS_MAP_SET_MCS_PER_SS(
19045 j, VHT_CAP_MCS_MAP_NONE,
19046 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
19047 }
19048 }
19049
19050 /* Capabilities */
19051 /* 80 MHz is mandatory */
19052 bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
19053
19054 if (WL_BW_CAP_160MHZ(bw_cap)) {
19055 bands[index]->vht_cap.cap |=
19056 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
19057 bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
19058 }
19059
19060 bands[index]->vht_cap.cap |=
19061 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
19062
19063 if (ldpc_cap) {
19064 bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC;
19065 }
19066
19067 if (stbc_tx) {
19068 bands[index]->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC;
19069 }
19070
19071 if (stbc_rx) {
19072 bands[index]->vht_cap.cap |=
19073 (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
19074 }
19075
19076 if (txbf_bfe_cap) {
19077 bands[index]->vht_cap.cap |=
19078 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
19079 }
19080
19081 if (txbf_bfr_cap) {
19082 bands[index]->vht_cap.cap |=
19083 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
19084 }
19085
19086 if (txbf_bfe_cap || txbf_bfr_cap) {
19087 bands[index]->vht_cap.cap |=
19088 (0x2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
19089 bands[index]->vht_cap.cap |=
19090 ((txstreams - 1)
19091 << VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
19092 bands[index]->vht_cap.cap |=
19093 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
19094 }
19095
19096 /* AMPDU length limit, support max 1MB (2 ^ (13 + 0x7)) */
19097 bands[index]->vht_cap.cap |=
19098 (0x7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
19099 WL_DBG(
19100 ("__wl_update_wiphybands band[%d] vht_enab=%d vht_cap=%08x "
19101 "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
19102 index, bands[index]->vht_cap.vht_supported,
19103 bands[index]->vht_cap.cap,
19104 bands[index]->vht_cap.vht_mcs.rx_mcs_map,
19105 bands[index]->vht_cap.vht_mcs.tx_mcs_map));
19106 }
19107 #endif // endif
19108 } else if (bandlist[i] == WLC_BAND_2G &&
19109 __wl_band_2ghz.n_channels > 0) {
19110 bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
19111 index = IEEE80211_BAND_2GHZ;
19112 if (bw_cap == WLC_N_BW_40ALL) {
19113 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
19114 }
19115 }
19116
19117 if ((index >= 0) && nmode) {
19118 bands[index]->ht_cap.cap |=
19119 (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
19120 bands[index]->ht_cap.ht_supported = TRUE;
19121 bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
19122 bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
19123 /* An HT shall support all EQM rates for one spatial stream */
19124 bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
19125 }
19126 }
19127
19128 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
19129 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
19130
19131 /* check if any bands populated otherwise makes 2Ghz as default */
19132 if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL &&
19133 wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) {
19134 /* Setup 2Ghz band as default */
19135 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
19136 }
19137
19138 if (notify) {
19139 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
19140 rtnl_unlock();
19141 #endif
19142 wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
19143 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0))
19144 rtnl_lock();
19145 #endif
19146 }
19147
19148 return 0;
19149 }
19150
wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)19151 s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
19152 {
19153 s32 err;
19154
19155 mutex_lock(&cfg->usr_sync);
19156 err = __wl_update_wiphybands(cfg, notify);
19157 mutex_unlock(&cfg->usr_sync);
19158
19159 return err;
19160 }
19161
__wl_cfg80211_up(struct bcm_cfg80211 * cfg)19162 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
19163 {
19164 s32 err = 0;
19165 s32 ret = 0;
19166 struct net_info *netinfo = NULL;
19167 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
19168 struct wireless_dev *wdev = ndev->ieee80211_ptr;
19169 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
19170 #ifdef WLTDLS
19171 u32 tdls;
19172 #endif /* WLTDLS */
19173 u16 wl_iftype = 0;
19174 u16 wl_mode = 0;
19175 u8 ioctl_buf[WLC_IOCTL_SMLEN];
19176
19177 WL_DBG(("In\n"));
19178
19179 if (!dhd_download_fw_on_driverload) {
19180 err = wl_create_event_handler(cfg);
19181 if (err) {
19182 WL_ERR(("wl_create_event_handler failed\n"));
19183 return err;
19184 }
19185 wl_init_event_handler(cfg);
19186 }
19187 /* Reserve 0x8000 toggle bit for P2P GO/GC */
19188 cfg->vif_macaddr_mask = 0x8000;
19189
19190 err = dhd_config_dongle(cfg);
19191 if (unlikely(err)) {
19192 return err;
19193 }
19194
19195 /* terence 20180108: this patch will cause to kernel panic with below
19196 * steps in Android 4.4 with kernel 3.4
19197 * insmod bcmdhd.ko; hostapd /data/misc/wifi/hostapd.conf
19198 */
19199 /* Always bring up interface in STA mode.
19200 * Did observe , if previous SofAP Bringup/cleanup
19201 * is not done properly, iftype is stuck with AP mode.
19202 * So during next wlan0 up, forcing the type to STA
19203 */
19204 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
19205 if (!netinfo) {
19206 WL_ERR(("there is no netinfo\n"));
19207 return -ENODEV;
19208 }
19209
19210 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
19211 /* AP on primary interface case: Supplicant will
19212 * set mode first and then do dev_open. so in this
19213 * case, the type will already be set.
19214 */
19215 netinfo->iftype = WL_IF_TYPE_AP;
19216 } else {
19217 ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
19218 netinfo->iftype = WL_IF_TYPE_STA;
19219 }
19220
19221 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
19222 return -EINVAL;
19223 }
19224 err = wl_config_infra(cfg, ndev, wl_iftype);
19225 if (unlikely(err && err != -EINPROGRESS)) {
19226 WL_ERR(("wl_config_infra failed\n"));
19227 if (err == -1) {
19228 WL_ERR(("return error %d\n", err));
19229 return err;
19230 }
19231 }
19232
19233 err = wl_init_scan(cfg);
19234 if (err) {
19235 WL_ERR(("wl_init_scan failed\n"));
19236 return err;
19237 }
19238 err = __wl_update_wiphybands(cfg, true);
19239 if (unlikely(err)) {
19240 WL_ERR(("wl_update_wiphybands failed\n"));
19241 if (err == -1) {
19242 WL_ERR(("return error %d\n", err));
19243 return err;
19244 }
19245 }
19246
19247 /* Update wlc version in cfg struct already queried as part of DHD
19248 * initialization */
19249 cfg->wlc_ver.wlc_ver_major = dhd->wlc_ver_major;
19250 cfg->wlc_ver.wlc_ver_minor = dhd->wlc_ver_minor;
19251
19252 if ((ret = wldev_iovar_getbuf(ndev, "scan_ver", NULL, 0, ioctl_buf,
19253 sizeof(ioctl_buf), NULL)) == BCME_OK) {
19254 WL_INFORM_MEM(("scan_params v2\n"));
19255 /* use scan_params ver2 */
19256 cfg->scan_params_v2 = true;
19257 } else {
19258 if (ret == BCME_UNSUPPORTED) {
19259 WL_INFORM(("scan_ver, UNSUPPORTED\n"));
19260 ret = BCME_OK;
19261 } else {
19262 WL_ERR(("get scan_ver err(%d)\n", ret));
19263 }
19264 }
19265 #ifdef DHD_LOSSLESS_ROAMING
19266 if (timer_pending(&cfg->roam_timeout)) {
19267 del_timer_sync(&cfg->roam_timeout);
19268 }
19269 #endif /* DHD_LOSSLESS_ROAMING */
19270
19271 err = dhd_monitor_init(cfg->pub);
19272
19273 #ifdef WL_HOST_BAND_MGMT
19274 /* By default the curr_band is initialized to BAND_AUTO */
19275 if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) {
19276 if (ret == BCME_UNSUPPORTED) {
19277 /* Don't fail the initialization, lets just
19278 * fall back to the original method
19279 */
19280 WL_ERR(("WL_HOST_BAND_MGMT defined, "
19281 "but roam_band iovar not supported \n"));
19282 } else {
19283 WL_ERR(("roam_band failed. ret=%d", ret));
19284 err = -1;
19285 }
19286 }
19287 #endif /* WL_HOST_BAND_MGMT */
19288 #ifdef WLTDLS
19289 if (wldev_iovar_getint(ndev, "tdls_enable", &tdls) == 0) {
19290 WL_DBG(("TDLS supported in fw\n"));
19291 cfg->tdls_supported = true;
19292 }
19293 #endif /* WLTDLS */
19294 #ifdef WL_IFACE_MGMT
19295 #ifdef CUSTOM_IF_MGMT_POLICY
19296 cfg->iface_data.policy = CUSTOM_IF_MGMT_POLICY;
19297 #else
19298 cfg->iface_data.policy = WL_IF_POLICY_DEFAULT;
19299 #endif /* CUSTOM_IF_MGMT_POLICY */
19300 #endif /* WL_IFACE_MGMT */
19301 #ifdef WL_NAN
19302 #ifdef WL_NANP2P
19303 if (FW_SUPPORTED(dhd, nanp2p)) {
19304 /* Enable NANP2P concurrent support */
19305 cfg->conc_disc = WL_NANP2P_CONC_SUPPORT;
19306 WL_INFORM_MEM(("nan + p2p conc discovery is supported\n"));
19307 cfg->nan_p2p_supported = true;
19308 }
19309 #endif /* WL_NANP2P */
19310 #endif /* WL_NAN */
19311
19312 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
19313 wl_set_drv_status(cfg, READY, ndev);
19314 return err;
19315 }
19316
__wl_cfg80211_down(struct bcm_cfg80211 * cfg)19317 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
19318 {
19319 s32 err = 0;
19320 struct net_info *iter, *next;
19321 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
19322 #if defined(WL_CFG80211) && \
19323 (defined(WL_ENABLE_P2P_IF) || defined(WL_NEW_CFG_PRIVCMD_SUPPORT)) && \
19324 !defined(PLATFORM_SLP)
19325 struct net_device *p2p_net = cfg->p2p_net;
19326 #endif
19327
19328 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
19329 WL_INFORM_MEM(("cfg80211 down\n"));
19330
19331 /* Check if cfg80211 interface is already down */
19332 if (!wl_get_drv_status(cfg, READY, ndev)) {
19333 WL_DBG(("cfg80211 interface is already down\n"));
19334 return err; /* it is even not ready */
19335 }
19336
19337 #ifdef SHOW_LOGTRACE
19338 /* Stop the event logging */
19339 wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
19340 #endif /* SHOW_LOGTRACE */
19341
19342 /* clear vendor OUI list */
19343 wl_vndr_ies_clear_vendor_oui_list(cfg);
19344
19345 /* Delete pm_enable_work */
19346 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
19347
19348 if (cfg->p2p_supported) {
19349 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
19350 #ifdef PROP_TXSTATUS_VSDB
19351 #if defined(BCMSDIO) || defined(BCMDBUS)
19352 if (wl_cfgp2p_vif_created(cfg)) {
19353 bool enabled = false;
19354 dhd_wlfc_get_enable(dhd, &enabled);
19355 if (enabled && cfg->wlfc_on &&
19356 dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
19357 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
19358 dhd_wlfc_deinit(dhd);
19359 cfg->wlfc_on = false;
19360 }
19361 }
19362 #endif /* BCMSDIO || BCMDBUS */
19363 #endif /* PROP_TXSTATUS_VSDB */
19364 }
19365
19366 #ifdef WL_NAN
19367 mutex_lock(&cfg->if_sync);
19368 /* Cancel pending nan disable work if any */
19369 if (delayed_work_pending(&cfg->nan_disable)) {
19370 WL_DBG(("Unarm the nan_disable work\n"));
19371 cancel_delayed_work_sync(&cfg->nan_disable);
19372 }
19373 cfg->nancfg.disable_reason = NAN_BUS_IS_DOWN;
19374 wl_cfgnan_disable(cfg);
19375 mutex_unlock(&cfg->if_sync);
19376 #endif /* WL_NAN */
19377
19378 if (!dhd_download_fw_on_driverload) {
19379 /* For built-in drivers/other drivers that do reset on
19380 * "ifconfig <primary_iface> down", cleanup any left
19381 * over interfaces
19382 */
19383 wl_cfg80211_cleanup_virtual_ifaces(cfg, false);
19384 }
19385 /* Clear used mac addr mask */
19386 cfg->vif_macaddr_mask = 0;
19387
19388 if (dhd->up) {
19389 /* If primary BSS is operational (for e.g SoftAP), bring it down */
19390 if (wl_cfg80211_bss_isup(ndev, 0)) {
19391 if (wl_cfg80211_bss_up(cfg, ndev, 0, 0) < 0) {
19392 WL_ERR(("BSS down failed \n"));
19393 }
19394 }
19395
19396 /* clear all the security setting on primary Interface */
19397 wl_cfg80211_clear_security(cfg);
19398 }
19399
19400 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19401 for_each_ndev(cfg, iter, next)
19402 {
19403 GCC_DIAGNOSTIC_POP();
19404 if (iter->ndev) { /* p2p discovery iface is null */
19405 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
19406 }
19407 }
19408
19409 #ifdef P2P_LISTEN_OFFLOADING
19410 wl_cfg80211_p2plo_deinit(cfg);
19411 #endif /* P2P_LISTEN_OFFLOADING */
19412
19413 /* cancel and notify scan complete, if scan request is pending */
19414 wl_cfg80211_cancel_scan(cfg);
19415 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19416 for_each_ndev(cfg, iter, next)
19417 {
19418 GCC_DIAGNOSTIC_POP();
19419 /* p2p discovery iface ndev ptr could be null */
19420 if (iter->ndev == NULL) {
19421 continue;
19422 }
19423 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19424 WL_INFORM_MEM(
19425 ("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
19426 wl_get_drv_status(cfg, CONNECTING, ndev),
19427 wl_get_drv_status(cfg, CONNECTED, ndev),
19428 wl_get_drv_status(cfg, DISCONNECTING, ndev),
19429 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
19430
19431 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
19432 CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
19433 }
19434
19435 if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
19436 wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
19437 u8 *latest_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
19438 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
19439 struct wireless_dev *wdev = ndev->ieee80211_ptr;
19440 struct cfg80211_bss *bss = CFG80211_GET_BSS(
19441 wiphy, NULL, latest_bssid, wdev->ssid, wdev->ssid_len);
19442 BCM_REFERENCE(bss);
19443 CFG80211_CONNECT_RESULT(ndev, latest_bssid, bss, NULL, 0, NULL, 0,
19444 WLAN_STATUS_UNSPECIFIED_FAILURE,
19445 GFP_KERNEL);
19446 }
19447 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19448 wl_clr_drv_status(cfg, READY, iter->ndev);
19449 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
19450 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
19451 wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
19452 wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
19453 wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
19454 wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
19455 wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
19456 wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev);
19457 wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev);
19458 }
19459 bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
19460 #if defined(WL_CFG80211) && \
19461 (defined(WL_ENABLE_P2P_IF) || defined(WL_NEW_CFG_PRIVCMD_SUPPORT)) && \
19462 !defined(PLATFORM_SLP)
19463 if (p2p_net) {
19464 dev_close(p2p_net);
19465 }
19466 #endif
19467
19468 /* Avoid deadlock from wl_cfg80211_down */
19469 if (!dhd_download_fw_on_driverload) {
19470 mutex_unlock(&cfg->usr_sync);
19471 wl_destroy_event_handler(cfg);
19472 mutex_lock(&cfg->usr_sync);
19473 }
19474
19475 wl_flush_eq(cfg);
19476 wl_link_down(cfg);
19477 if (cfg->p2p_supported) {
19478 if (timer_pending(&cfg->p2p->listen_timer)) {
19479 del_timer_sync(&cfg->p2p->listen_timer);
19480 }
19481 wl_cfgp2p_down(cfg);
19482 }
19483
19484 if (timer_pending(&cfg->scan_timeout)) {
19485 del_timer_sync(&cfg->scan_timeout);
19486 }
19487
19488 wl_cfg80211_clear_mgmt_vndr_ies(cfg);
19489 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
19490
19491 dhd_monitor_uninit();
19492 #ifdef WLAIBSS_MCHAN
19493 bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
19494 #endif /* WLAIBSS_MCHAN */
19495
19496 #ifdef WL11U
19497 /* Clear interworking element. */
19498 if (cfg->wl11u) {
19499 cfg->wl11u = FALSE;
19500 }
19501 #endif /* WL11U */
19502
19503 cfg->disable_roam_event = false;
19504 cfg->scan_params_v2 = false;
19505
19506 DNGL_FUNC(dhd_cfg80211_down, (cfg));
19507
19508 #ifdef DHD_IFDEBUG
19509 /* Printout all netinfo entries */
19510 wl_probe_wdev_all(cfg);
19511 #endif /* DHD_IFDEBUG */
19512
19513 return err;
19514 }
19515
wl_cfg80211_up(struct net_device * net)19516 s32 wl_cfg80211_up(struct net_device *net)
19517 {
19518 struct bcm_cfg80211 *cfg;
19519 s32 err = 0;
19520 int val = 1;
19521 dhd_pub_t *dhd;
19522 #ifdef DISABLE_PM_BCNRX
19523 s32 interr = 0;
19524 uint param = 0;
19525 s8 iovbuf[WLC_IOCTL_SMLEN];
19526 #endif /* DISABLE_PM_BCNRX */
19527
19528 WL_DBG(("In\n"));
19529 cfg = wl_get_cfg(net);
19530 if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
19531 sizeof(int)) < 0)) {
19532 WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
19533 return err;
19534 }
19535 val = dtoh32(val);
19536 if (val != WLC_IOCTL_VERSION && val != 1) {
19537 WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
19538 val, WLC_IOCTL_VERSION));
19539 return BCME_VERSION;
19540 }
19541 ioctl_version = val;
19542 WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
19543 #ifdef WL_EXT_IAPSTA
19544 wl_ext_in4way_sync(net, STA_NO_SCAN_IN4WAY | STA_NO_BTC_IN4WAY,
19545 WL_EXT_STATUS_DISCONNECTED, NULL);
19546 #endif
19547
19548 mutex_lock(&cfg->usr_sync);
19549 dhd = (dhd_pub_t *)(cfg->pub);
19550 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
19551 err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
19552 if (unlikely(err)) {
19553 mutex_unlock(&cfg->usr_sync);
19554 return err;
19555 }
19556 }
19557 #ifdef WLMESH_CFG80211
19558 cfg->wdev->wiphy->features |= NL80211_FEATURE_USERSPACE_MPM;
19559 #endif /* WLMESH_CFG80211 */
19560 #if defined(BCMSUP_4WAY_HANDSHAKE)
19561 if (dhd->fw_4way_handshake) {
19562 /* This is a hacky method to indicate fw 4WHS support and
19563 * is used only for kernels (kernels < 3.14). For newer
19564 * kernels, we would be using vendor extn. path to advertise
19565 * FW based 4-way handshake feature support.
19566 */
19567 cfg->wdev->wiphy->features |= NL80211_FEATURE_FW_4WAY_HANDSHAKE;
19568 }
19569 #endif /* BCMSUP_4WAY_HANDSHAKE */
19570 err = __wl_cfg80211_up(cfg);
19571 if (unlikely(err)) {
19572 WL_ERR(("__wl_cfg80211_up failed\n"));
19573 }
19574
19575 #ifdef ROAM_CHANNEL_CACHE
19576 if (init_roam_cache(cfg, ioctl_version) == 0) {
19577 /* Enable support for Roam cache */
19578 cfg->rcc_enabled = true;
19579 WL_ERR(("Roam channel cache enabled\n"));
19580 } else {
19581 WL_ERR(("Failed to enable RCC.\n"));
19582 }
19583 #endif /* ROAM_CHANNEL_CACHE */
19584
19585 /* IOVAR configurations with 'up' condition */
19586 #ifdef DISABLE_PM_BCNRX
19587 interr = wldev_iovar_setbuf(net, "pm_bcnrx", (char *)¶m, sizeof(param),
19588 iovbuf, sizeof(iovbuf), &cfg->ioctl_buf_sync);
19589 if (unlikely(interr)) {
19590 WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
19591 }
19592 #endif /* DISABLE_PM_BCNRX */
19593 #ifdef WL_CHAN_UTIL
19594 interr = wl_cfg80211_start_bssload_report(net);
19595 if (unlikely(interr)) {
19596 WL_ERR(("%s: Failed to start bssload_report eventing, err=%d\n",
19597 __FUNCTION__, interr));
19598 }
19599 #endif /* WL_CHAN_UTIL */
19600
19601 mutex_unlock(&cfg->usr_sync);
19602
19603 #ifdef WLAIBSS_MCHAN
19604 bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
19605 #endif /* WLAIBSS_MCHAN */
19606 return err;
19607 }
19608
19609 /* Private Event to Supplicant with indication that chip hangs */
wl_cfg80211_hang(struct net_device * dev,u16 reason)19610 int wl_cfg80211_hang(struct net_device *dev, u16 reason)
19611 {
19612 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19613 dhd_pub_t *dhd;
19614 if (!cfg) {
19615 return BCME_ERROR;
19616 }
19617
19618 RETURN_EIO_IF_NOT_UP(cfg);
19619
19620 dhd = (dhd_pub_t *)(cfg->pub);
19621 if ((dhd->hang_reason <= HANG_REASON_MASK) ||
19622 (dhd->hang_reason >= HANG_REASON_MAX)) {
19623 WL_ERR(
19624 ("wl_cfg80211_hang, Invalid hang reason 0x%x\n", dhd->hang_reason));
19625 dhd->hang_reason = HANG_REASON_UNKNOWN;
19626 }
19627 WL_ERR(("In : chip crash eventing, reason=0x%x\n",
19628 (uint32)(dhd->hang_reason)));
19629
19630 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
19631 {
19632 if (dhd->up == TRUE) {
19633 CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
19634 }
19635 }
19636 #if defined(RSSIAVG)
19637 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
19638 #endif
19639 #if defined(BSSCACHE)
19640 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
19641 #endif
19642 if (cfg != NULL) {
19643 wl_link_down(cfg);
19644 }
19645 return 0;
19646 }
19647
wl_cfg80211_down(struct net_device * dev)19648 s32 wl_cfg80211_down(struct net_device *dev)
19649 {
19650 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19651 s32 err = BCME_ERROR;
19652
19653 WL_DBG(("In\n"));
19654
19655 if (cfg && (cfg == wl_cfg80211_get_bcmcfg())) {
19656 mutex_lock(&cfg->usr_sync);
19657 #if defined(RSSIAVG)
19658 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
19659 #endif
19660 #if defined(BSSCACHE)
19661 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
19662 #endif
19663 err = __wl_cfg80211_down(cfg);
19664 mutex_unlock(&cfg->usr_sync);
19665 }
19666
19667 return err;
19668 }
19669
wl_cfg80211_sta_ifdown(struct net_device * dev)19670 void wl_cfg80211_sta_ifdown(struct net_device *dev)
19671 {
19672 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19673
19674 WL_DBG(("In\n"));
19675
19676 if (cfg) {
19677 /* cancel scan if anything pending */
19678 wl_cfg80211_cancel_scan(cfg);
19679 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
19680 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
19681 wl_get_drv_status(cfg, CONNECTED, dev)) {
19682 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
19683 }
19684 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
19685 }
19686 }
19687
wl_read_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 item)19688 void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
19689 {
19690 unsigned long flags;
19691 void *rptr = NULL;
19692 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
19693
19694 if (!profile) {
19695 return NULL;
19696 }
19697 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
19698 switch (item) {
19699 case WL_PROF_SEC:
19700 rptr = &profile->sec;
19701 break;
19702 case WL_PROF_ACT:
19703 rptr = &profile->active;
19704 break;
19705 case WL_PROF_BSSID:
19706 rptr = profile->bssid;
19707 break;
19708 case WL_PROF_SSID:
19709 rptr = &profile->ssid;
19710 break;
19711 case WL_PROF_CHAN:
19712 rptr = &profile->channel;
19713 break;
19714 case WL_PROF_LATEST_BSSID:
19715 rptr = profile->latest_bssid;
19716 break;
19717 }
19718 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
19719 if (!rptr) {
19720 WL_ERR(("invalid item (%d)\n", item));
19721 }
19722 return rptr;
19723 }
19724
wl_update_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,const void * data,s32 item)19725 static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
19726 const wl_event_msg_t *e, const void *data, s32 item)
19727 {
19728 s32 err = 0;
19729 const struct wlc_ssid *ssid;
19730 unsigned long flags;
19731 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
19732
19733 if (!profile) {
19734 return WL_INVALID;
19735 }
19736 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
19737 switch (item) {
19738 case WL_PROF_SSID:
19739 ssid = (const wlc_ssid_t *)data;
19740 bzero(profile->ssid.SSID, sizeof(profile->ssid.SSID));
19741 profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
19742 memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
19743 break;
19744 case WL_PROF_BSSID:
19745 if (data) {
19746 memcpy(profile->bssid, data, ETHER_ADDR_LEN);
19747 } else {
19748 bzero(profile->bssid, ETHER_ADDR_LEN);
19749 }
19750 break;
19751 case WL_PROF_SEC:
19752 memcpy(&profile->sec, data, sizeof(profile->sec));
19753 break;
19754 case WL_PROF_ACT:
19755 profile->active = *(const bool *)data;
19756 break;
19757 case WL_PROF_BEACONINT:
19758 profile->beacon_interval = *(const u16 *)data;
19759 break;
19760 case WL_PROF_DTIMPERIOD:
19761 profile->dtim_period = *(const u8 *)data;
19762 break;
19763 case WL_PROF_CHAN:
19764 profile->channel = *(const u32 *)data;
19765 break;
19766 case WL_PROF_LATEST_BSSID:
19767 if (data) {
19768 memcpy_s(profile->latest_bssid, sizeof(profile->latest_bssid),
19769 data, ETHER_ADDR_LEN);
19770 } else {
19771 memset_s(profile->latest_bssid, sizeof(profile->latest_bssid),
19772 0, ETHER_ADDR_LEN);
19773 }
19774 break;
19775 default:
19776 err = -EOPNOTSUPP;
19777 break;
19778 }
19779 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
19780
19781 if (err == -EOPNOTSUPP) {
19782 WL_ERR(("unsupported item (%d)\n", item));
19783 }
19784
19785 return err;
19786 }
19787
wl_cfg80211_dbg_level(u32 level)19788 void wl_cfg80211_dbg_level(u32 level)
19789 {
19790 /*
19791 * prohibit to change debug level
19792 * by insmod parameter.
19793 * eventually debug level will be configured
19794 * in compile time by using CONFIG_XXX
19795 */
19796 }
19797
wl_is_ibssmode(struct bcm_cfg80211 * cfg,struct net_device * ndev)19798 static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev)
19799 {
19800 return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS;
19801 }
19802
wl_is_ibssstarter(struct bcm_cfg80211 * cfg)19803 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
19804 {
19805 return cfg->ibss_starter;
19806 }
19807
wl_rst_ie(struct bcm_cfg80211 * cfg)19808 static void wl_rst_ie(struct bcm_cfg80211 *cfg)
19809 {
19810 struct wl_ie *ie = wl_to_ie(cfg);
19811
19812 ie->offset = 0;
19813 bzero(ie->buf, sizeof(ie->buf));
19814 }
19815
wl_add_ie(struct bcm_cfg80211 * cfg,u8 t,u8 l,u8 * v)19816 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
19817 {
19818 struct wl_ie *ie = wl_to_ie(cfg);
19819 s32 err = 0;
19820
19821 if (unlikely(ie->offset + l + 0x2 > WL_TLV_INFO_MAX)) {
19822 WL_ERR(("ei crosses buffer boundary\n"));
19823 return -ENOSPC;
19824 }
19825 ie->buf[ie->offset] = t;
19826 ie->buf[ie->offset + 1] = l;
19827 memcpy(&ie->buf[ie->offset + 0x2], v, l);
19828 ie->offset += l + 0x2;
19829
19830 return err;
19831 }
19832
wl_update_hidden_ap_ie(wl_bss_info_t * bi,const u8 * ie_stream,u32 * ie_size,bool update_ssid)19833 static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream,
19834 u32 *ie_size, bool update_ssid)
19835 {
19836 u8 *ssidie;
19837 int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN);
19838 int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len;
19839 /* cfg80211_find_ie defined in kernel returning const u8 */
19840
19841 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19842 ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
19843 GCC_DIAGNOSTIC_POP();
19844
19845 /* ERROR out if
19846 * 1. No ssid IE is FOUND or
19847 * 2. New ssid length is > what was allocated for existing ssid (as
19848 * we do not want to overwrite the rest of the IEs) or
19849 * 3. If in case of erroneous buffer input where ssid length doesnt match
19850 * the space allocated to it.
19851 */
19852 if (!ssidie) {
19853 return;
19854 }
19855 available_buffer_len = ((int)(*ie_size)) - (ssidie + 0x2 - ie_stream);
19856 remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
19857 unused_buf_len = WL_EXTRA_BUF_MAX - (0x4 + bi->length + *ie_size);
19858 if (ssidie[1] > available_buffer_len) {
19859 WL_ERR_MEM(("wl_update_hidden_ap_ie: skip wl_update_hidden_ap_ie : "
19860 "overflow\n"));
19861 return;
19862 }
19863
19864 if (ssidie[1] != ssid_len) {
19865 if (ssidie[1]) {
19866 WL_ERR_RLMT(("wl_update_hidden_ap_ie: Wrong SSID len: %d != %d\n",
19867 ssidie[1], bi->SSID_len));
19868 }
19869 /*
19870 * The bss info in firmware gets updated from beacon and probe resp.
19871 * In case of hidden network, the bss_info that got updated by beacon,
19872 * will not carry SSID and this can result in cfg80211_get_bss not
19873 * finding a match. so include the SSID element.
19874 */
19875 if ((update_ssid && (ssid_len > ssidie[1])) &&
19876 (unused_buf_len > ssid_len)) {
19877 WL_INFORM_MEM(("Changing the SSID Info.\n"));
19878 memmove(ssidie + ssid_len + 0x2, (ssidie + 0x2) + ssidie[1],
19879 remaining_ie_buf_len);
19880 memcpy(ssidie + 0x2, bi->SSID, ssid_len);
19881 *ie_size = *ie_size + ssid_len - ssidie[1];
19882 ssidie[1] = ssid_len;
19883 } else if (ssid_len < ssidie[1]) {
19884 WL_ERR_MEM(("wl_update_hidden_ap_ie: Invalid SSID len: %d < %d\n",
19885 bi->SSID_len, ssidie[1]));
19886 }
19887 return;
19888 }
19889 if (*(ssidie + 0x2) == '\0') {
19890 memcpy(ssidie + 0x2, bi->SSID, ssid_len);
19891 }
19892 return;
19893 }
19894
wl_mrg_ie(struct bcm_cfg80211 * cfg,u8 * ie_stream,u16 ie_size)19895 static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size)
19896 {
19897 struct wl_ie *ie = wl_to_ie(cfg);
19898 s32 err = 0;
19899
19900 if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
19901 WL_ERR(("ei_stream crosses buffer boundary\n"));
19902 return -ENOSPC;
19903 }
19904 memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
19905 ie->offset += ie_size;
19906
19907 return err;
19908 }
19909
wl_cp_ie(struct bcm_cfg80211 * cfg,u8 * dst,u16 dst_size)19910 static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size)
19911 {
19912 struct wl_ie *ie = wl_to_ie(cfg);
19913 s32 err = 0;
19914
19915 if (unlikely(ie->offset > dst_size)) {
19916 WL_ERR(("dst_size is not enough\n"));
19917 return -ENOSPC;
19918 }
19919 memcpy(dst, &ie->buf[0], ie->offset);
19920
19921 return err;
19922 }
19923
wl_get_ielen(struct bcm_cfg80211 * cfg)19924 static u32 wl_get_ielen(struct bcm_cfg80211 *cfg)
19925 {
19926 struct wl_ie *ie = wl_to_ie(cfg);
19927
19928 return ie->offset;
19929 }
19930
wl_link_up(struct bcm_cfg80211 * cfg)19931 static void wl_link_up(struct bcm_cfg80211 *cfg)
19932 {
19933 cfg->link_up = true;
19934 }
19935
wl_link_down(struct bcm_cfg80211 * cfg)19936 static void wl_link_down(struct bcm_cfg80211 *cfg)
19937 {
19938 struct wl_connect_info *conn_info = wl_to_conn(cfg);
19939
19940 WL_DBG(("In\n"));
19941 cfg->link_up = false;
19942 if (conn_info) {
19943 conn_info->req_ie_len = 0;
19944 conn_info->resp_ie_len = 0;
19945 }
19946 }
19947
wl_lock_eq(struct bcm_cfg80211 * cfg)19948 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
19949 {
19950 unsigned long flags;
19951
19952 WL_CFG_EQ_LOCK(&cfg->eq_lock, flags);
19953 return flags;
19954 }
19955
wl_unlock_eq(struct bcm_cfg80211 * cfg,unsigned long flags)19956 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
19957 {
19958 WL_CFG_EQ_UNLOCK(&cfg->eq_lock, flags);
19959 }
19960
wl_init_eq_lock(struct bcm_cfg80211 * cfg)19961 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
19962 {
19963 spin_lock_init(&cfg->eq_lock);
19964 }
19965
wl_delay(u32 ms)19966 static void wl_delay(u32 ms)
19967 {
19968 if (in_atomic() || (ms < jiffies_to_msecs(1))) {
19969 OSL_DELAY(ms * 0x3E8);
19970 } else {
19971 OSL_SLEEP(ms);
19972 }
19973 }
19974
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)19975 s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net,
19976 struct ether_addr *p2pdev_addr)
19977 {
19978 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
19979 struct ether_addr primary_mac;
19980 if (!cfg->p2p) {
19981 return -1;
19982 }
19983 if (!p2p_is_on(cfg)) {
19984 get_primary_mac(cfg, &primary_mac);
19985 #ifndef WL_P2P_USE_RANDMAC
19986 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
19987 #endif /* WL_P2P_USE_RANDMAC */
19988 memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN);
19989 } else {
19990 memcpy(p2pdev_addr->octet,
19991 wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
19992 ETHER_ADDR_LEN);
19993 }
19994
19995 return 0;
19996 }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)19997 s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char *buf, int len)
19998 {
19999 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20000
20001 return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
20002 }
20003
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)20004 s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char *buf, int len)
20005 {
20006 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20007
20008 return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
20009 }
20010
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)20011 s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char *buf, int len)
20012 {
20013 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20014
20015 return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
20016 }
20017
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)20018 s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char *buf, int len)
20019 {
20020 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20021
20022 return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
20023 }
20024
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)20025 s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char *buf, int len)
20026 {
20027 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
20028
20029 return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
20030 }
20031
20032 #ifdef P2PLISTEN_AP_SAMECHN
wl_cfg80211_set_p2p_resp_ap_chn(struct net_device * net,s32 enable)20033 s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
20034 {
20035 s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
20036 if ((ret == 0) && enable) {
20037 /* disable PM for p2p responding on infra AP channel */
20038 s32 pm = PM_OFF;
20039
20040 ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm));
20041 }
20042
20043 return ret;
20044 }
20045 #endif /* P2PLISTEN_AP_SAMECHN */
20046
wl_cfg80211_channel_to_freq(u32 channel)20047 s32 wl_cfg80211_channel_to_freq(u32 channel)
20048 {
20049 int freq = 0;
20050
20051 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && \
20052 !defined(WL_COMPAT_WIRELESS)
20053 freq = ieee80211_channel_to_frequency(channel);
20054 #else
20055 {
20056 u16 band = 0;
20057 if (channel <= CH_MAX_2G_CHANNEL) {
20058 band = IEEE80211_BAND_2GHZ;
20059 } else {
20060 band = IEEE80211_BAND_5GHZ;
20061 }
20062 freq = ieee80211_channel_to_frequency(channel, band);
20063 }
20064 #endif // endif
20065 return freq;
20066 }
20067
20068 #ifdef WLTDLS
wl_tdls_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)20069 s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
20070 const wl_event_msg_t *e, void *data)
20071 {
20072 struct net_device *ndev = NULL;
20073 u32 reason = ntoh32(e->reason);
20074 s8 *msg = NULL;
20075
20076 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
20077
20078 switch (reason) {
20079 case WLC_E_TDLS_PEER_DISCOVERED:
20080 msg = " TDLS PEER DISCOVERD ";
20081 break;
20082 case WLC_E_TDLS_PEER_CONNECTED:
20083 if (cfg->tdls_mgmt_frame) {
20084 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
20085 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
20086 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
20087 0);
20088 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
20089 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
20090 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
20091 0, GFP_ATOMIC);
20092 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
20093 defined(WL_COMPAT_WIRELESS)
20094 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
20095 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
20096 GFP_ATOMIC);
20097 #else
20098 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
20099 cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
20100 GFP_ATOMIC);
20101
20102 #endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
20103 }
20104 msg = " TDLS PEER CONNECTED ";
20105 #ifdef SUPPORT_SET_CAC
20106 /* TDLS connect reset CAC */
20107 wl_cfg80211_set_cac(cfg, 0);
20108 #endif /* SUPPORT_SET_CAC */
20109 break;
20110 case WLC_E_TDLS_PEER_DISCONNECTED:
20111 if (cfg->tdls_mgmt_frame) {
20112 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
20113 cfg->tdls_mgmt_frame_len = 0;
20114 cfg->tdls_mgmt_freq = 0;
20115 }
20116 msg = "TDLS PEER DISCONNECTED ";
20117 #ifdef SUPPORT_SET_CAC
20118 /* TDLS disconnec, set CAC */
20119 wl_cfg80211_set_cac(cfg, 1);
20120 #endif /* SUPPORT_SET_CAC */
20121 break;
20122 }
20123 if (msg) {
20124 WL_ERR(("%s: " MACDBG " on %s ndev\n", msg,
20125 MAC2STRDBG((const u8 *)(&e->addr)),
20126 (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
20127 }
20128 return 0;
20129 }
20130 #endif /* WLTDLS */
20131
20132 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \
20133 defined(WL_COMPAT_WIRELESS)
20134 static s32
20135 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || \
20136 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) && \
20137 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)20138 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, u8 *peer,
20139 u8 action_code, u8 dialog_token, u16 status_code,
20140 u32 peer_capability, const u8 *buf, size_t len)
20141 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
20142 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
20143 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
20144 const u8 *peer, u8 action_code, u8 dialog_token,
20145 u16 status_code, u32 peer_capability, const u8 *buf,
20146 size_t len)
20147 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
20148 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
20149 const u8 *peer, u8 action_code, u8 dialog_token,
20150 u16 status_code, u32 peer_capability, bool initiator,
20151 const u8 *buf, size_t len)
20152 #else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20153 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, u8 *peer,
20154 u8 action_code, u8 dialog_token, u16 status_code,
20155 const u8 *buf, size_t len)
20156 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20157 {
20158 s32 ret = 0;
20159 #if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
20160 struct bcm_cfg80211 *cfg;
20161 tdls_wfd_ie_iovar_t info;
20162 bzero(&info, sizeof(info));
20163 cfg = wl_get_cfg(dev);
20164
20165 #if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
20166 /* Some customer platform back ported this feature from kernel 3.15 to
20167 * kernel 3.10 and that cuases build error
20168 */
20169 BCM_REFERENCE(peer_capability);
20170 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
20171
20172 switch (action_code) {
20173 /* We need to set TDLS Wifi Display IE to firmware
20174 * using tdls_wfd_ie iovar
20175 */
20176 case WLAN_TDLS_SET_PROBE_WFD_IE:
20177 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_PROBE_WFD_IE\n"));
20178 info.mode = TDLS_WFD_PROBE_IE_TX;
20179
20180 if (len > sizeof(info.data)) {
20181 return -EINVAL;
20182 }
20183 memcpy(&info.data, buf, len);
20184 info.length = len;
20185 break;
20186 case WLAN_TDLS_SET_SETUP_WFD_IE:
20187 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_SETUP_WFD_IE\n"));
20188 info.mode = TDLS_WFD_IE_TX;
20189
20190 if (len > sizeof(info.data)) {
20191 return -EINVAL;
20192 }
20193 memcpy(&info.data, buf, len);
20194 info.length = len;
20195 break;
20196 case WLAN_TDLS_SET_WFD_ENABLED:
20197 WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_ENABLED\n"));
20198 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
20199 goto out;
20200 case WLAN_TDLS_SET_WFD_DISABLED:
20201 WL_ERR(
20202 ("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_DISABLED\n"));
20203 dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
20204 goto out;
20205 default:
20206 WL_ERR(("Unsupported action code : %d\n", action_code));
20207 goto out;
20208 }
20209 ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
20210 cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
20211 &cfg->ioctl_buf_sync);
20212 if (ret) {
20213 WL_ERR(("tdls_wfd_ie error %d\n", ret));
20214 }
20215 out:
20216 #endif /* TDLS_MSG_ONLY_WFD && WLTDLS */
20217 return ret;
20218 }
20219
20220 static s32
20221 #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)20222 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
20223 const u8 *peer, enum nl80211_tdls_operation oper)
20224 #else
20225 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, u8 *peer,
20226 enum nl80211_tdls_operation oper)
20227 #endif // endif
20228 {
20229 s32 ret = 0;
20230 #ifdef WLTDLS
20231 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20232 tdls_iovar_t info;
20233 dhd_pub_t *dhdp;
20234 bool tdls_auto_mode = false;
20235 dhdp = (dhd_pub_t *)(cfg->pub);
20236 bzero(&info, sizeof(tdls_iovar_t));
20237 if (peer) {
20238 memcpy(&info.ea, peer, ETHER_ADDR_LEN);
20239 } else {
20240 return -1;
20241 }
20242 switch (oper) {
20243 case NL80211_TDLS_DISCOVERY_REQ:
20244 /* If the discovery request is broadcast then we need to set
20245 * info.mode to Tunneled Probe Request
20246 */
20247 if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) ==
20248 0) {
20249 info.mode = TDLS_MANUAL_EP_WFD_TPQ;
20250 WL_ERR(
20251 ("wl_cfg80211_tdls_oper: TDLS TUNNELED PRBOBE REQUEST\n"));
20252 } else {
20253 info.mode = TDLS_MANUAL_EP_DISCOVERY;
20254 }
20255 break;
20256 case NL80211_TDLS_SETUP:
20257 if (dhdp->tdls_mode == true) {
20258 info.mode = TDLS_MANUAL_EP_CREATE;
20259 tdls_auto_mode = false;
20260 /* Do tear down and create a fresh one */
20261 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_TEARDOWN,
20262 tdls_auto_mode);
20263 if (ret < 0) {
20264 return ret;
20265 }
20266 } else {
20267 tdls_auto_mode = true;
20268 }
20269 break;
20270 case NL80211_TDLS_TEARDOWN:
20271 info.mode = TDLS_MANUAL_EP_DELETE;
20272 break;
20273 default:
20274 WL_ERR(("Unsupported operation : %d\n", oper));
20275 goto out;
20276 }
20277 /* turn on TDLS */
20278 ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_SETUP, tdls_auto_mode);
20279 if (ret < 0) {
20280 return ret;
20281 }
20282 if (info.mode) {
20283 ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
20284 cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
20285 &cfg->ioctl_buf_sync);
20286 if (ret) {
20287 WL_ERR(("tdls_endpoint error %d\n", ret));
20288 }
20289 }
20290 out:
20291 if (ret) {
20292 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
20293 return -ENOTSUPP;
20294 }
20295 #endif /* WLTDLS */
20296 return ret;
20297 }
20298 #endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
20299
wl_cfg80211_set_wps_p2p_ie(struct net_device * ndev,char * buf,int len,enum wl_management_type type)20300 s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
20301 enum wl_management_type type)
20302 {
20303 struct bcm_cfg80211 *cfg;
20304 s32 ret = 0;
20305 struct ether_addr primary_mac;
20306 s32 bssidx = 0;
20307 s32 pktflag = 0;
20308 cfg = wl_get_cfg(ndev);
20309 if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
20310 /* Vendor IEs should be set to FW
20311 * after SoftAP interface is brought up
20312 */
20313 WL_DBG(("Skipping set IE since AP is not up \n"));
20314 goto exit;
20315 } else if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
20316 /* Either stand alone AP case or P2P discovery */
20317 if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
20318 /* Stand alone AP case on primary interface */
20319 WL_DBG(("Apply IEs for Primary AP Interface \n"));
20320 bssidx = 0;
20321 } else {
20322 if (!cfg->p2p) {
20323 /* If p2p not initialized, return failure */
20324 WL_ERR(("P2P not initialized \n"));
20325 goto exit;
20326 }
20327 /* P2P Discovery case (p2p listen) */
20328 if (!cfg->p2p->on) {
20329 /* Turn on Discovery interface */
20330 get_primary_mac(cfg, &primary_mac);
20331 #ifndef WL_P2P_USE_RANDMAC
20332 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
20333 #endif /* WL_P2P_USE_RANDMAC */
20334 p2p_on(cfg) = true;
20335 ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
20336 if (unlikely(ret)) {
20337 WL_ERR(("Enable discovery failed \n"));
20338 goto exit;
20339 }
20340 }
20341 WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
20342 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
20343 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
20344 }
20345 } else {
20346 /* Virtual AP/ P2P Group Interface */
20347 WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
20348 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
20349 }
20350
20351 if (ndev != NULL) {
20352 switch (type) {
20353 case WL_BEACON:
20354 pktflag = VNDR_IE_BEACON_FLAG;
20355 break;
20356 case WL_PROBE_RESP:
20357 pktflag = VNDR_IE_PRBRSP_FLAG;
20358 break;
20359 case WL_ASSOC_RESP:
20360 pktflag = VNDR_IE_ASSOCRSP_FLAG;
20361 break;
20362 }
20363 if (pktflag) {
20364 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
20365 bssidx, pktflag, buf, len);
20366 }
20367 }
20368 exit:
20369 return ret;
20370 }
20371
20372 #ifdef WL_SUPPORT_AUTO_CHANNEL
wl_cfg80211_set_auto_channel_scan_state(struct net_device * ndev)20373 static s32 wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev)
20374 {
20375 u32 val = 0;
20376 s32 ret = BCME_ERROR;
20377 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20378 /* Set interface up, explicitly. */
20379 val = 1;
20380
20381 ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
20382 if (ret < 0) {
20383 WL_ERR(("set interface up failed, error = %d\n", ret));
20384 goto done;
20385 }
20386
20387 /* Stop all scan explicitly, till auto channel selection complete. */
20388 wl_set_drv_status(cfg, SCANNING, ndev);
20389 if (cfg->escan_info.ndev == NULL) {
20390 ret = BCME_OK;
20391 goto done;
20392 }
20393
20394 wl_cfg80211_cancel_scan(cfg);
20395
20396 done:
20397 return ret;
20398 }
20399
wl_cfg80211_valid_channel_p2p(int channel)20400 static bool wl_cfg80211_valid_channel_p2p(int channel)
20401 {
20402 bool valid = false;
20403
20404 /* channel 1 to 14 */
20405 if ((channel >= 1) && (channel <= 14)) {
20406 valid = true;
20407 } else if ((channel >= 36) && (channel <= 48)) {
20408 /* channel 36 to 48 */
20409 valid = true;
20410 } else if ((channel >= 149) && (channel <= 161)) {
20411 /* channel 149 to 161 */
20412 valid = true;
20413 } else {
20414 valid = false;
20415 WL_INFORM(("invalid P2P chanspec, channel = %d\n", channel));
20416 }
20417
20418 return valid;
20419 }
20420
wl_cfg80211_get_chanspecs_2g(struct net_device * ndev,void * buf,s32 buflen)20421 s32 wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
20422 {
20423 s32 ret = BCME_ERROR;
20424 struct bcm_cfg80211 *cfg = NULL;
20425 chanspec_t chanspec = 0;
20426
20427 cfg = wl_get_cfg(ndev);
20428
20429 /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
20430 chanspec |=
20431 (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE);
20432 chanspec = wl_chspec_host_to_driver(chanspec);
20433
20434 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
20435 sizeof(chanspec), buf, buflen, 0,
20436 &cfg->ioctl_buf_sync);
20437 if (ret < 0) {
20438 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
20439 }
20440
20441 return ret;
20442 }
20443
wl_cfg80211_get_chanspecs_5g(struct net_device * ndev,void * buf,s32 buflen)20444 s32 wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
20445 {
20446 u32 channel = 0;
20447 s32 ret = BCME_ERROR;
20448 s32 i = 0;
20449 s32 j = 0;
20450 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20451 wl_uint32_list_t *list = NULL;
20452 chanspec_t chanspec = 0;
20453
20454 /* Restrict channels to 5GHz, 20MHz BW, no SB. */
20455 chanspec |=
20456 (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE);
20457 chanspec = wl_chspec_host_to_driver(chanspec);
20458
20459 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
20460 sizeof(chanspec), buf, buflen, 0,
20461 &cfg->ioctl_buf_sync);
20462 if (ret < 0) {
20463 WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
20464 goto done;
20465 }
20466
20467 list = (wl_uint32_list_t *)buf;
20468 /* Skip DFS and inavlid P2P channel. */
20469 for (i = 0, j = 0; i < dtoh32(list->count); i++) {
20470 chanspec = (chanspec_t)dtoh32(list->element[i]);
20471 channel = CHSPEC_CHANNEL(chanspec);
20472
20473 ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
20474 if (ret < 0) {
20475 WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret));
20476 goto done;
20477 }
20478
20479 if (CHANNEL_IS_RADAR(channel) ||
20480 !(wl_cfg80211_valid_channel_p2p(CHSPEC_CHANNEL(chanspec)))) {
20481 continue;
20482 } else {
20483 list->element[j] = list->element[i];
20484 }
20485
20486 j++;
20487 }
20488
20489 list->count = j;
20490
20491 done:
20492 return ret;
20493 }
20494
wl_cfg80211_get_best_channel(struct net_device * ndev,void * buf,int buflen,int * channel)20495 static s32 wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf,
20496 int buflen, int *channel)
20497 {
20498 s32 ret = BCME_ERROR;
20499 int chosen = 0;
20500 int retry = 0;
20501 uint chip;
20502
20503 /* Start auto channel selection scan. */
20504 ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, buf, buflen);
20505 if (ret < 0) {
20506 WL_ERR(("can't start auto channel scan, error = %d\n", ret));
20507 *channel = 0;
20508 goto done;
20509 }
20510
20511 /* Wait for auto channel selection, worst case possible delay is 5250ms. */
20512 retry = CHAN_SEL_RETRY_COUNT;
20513
20514 while (retry--) {
20515 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
20516 chosen = 0;
20517 ret =
20518 wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
20519 if ((ret == 0) && (dtoh32(chosen) != 0)) {
20520 chip = dhd_conf_get_chip(dhd_get_pub(ndev));
20521 if (chip != BCM43362_CHIP_ID && chip != BCM4330_CHIP_ID &&
20522 chip != BCM43143_CHIP_ID) {
20523 u32 chanspec = 0;
20524 int ctl_chan;
20525 chanspec = wl_chspec_driver_to_host(chosen);
20526 WL_INFORM(("selected chanspec = 0x%x\n", chanspec));
20527 ctl_chan = wf_chspec_ctlchan(chanspec);
20528 WL_INFORM(("selected ctl_chan = %d\n", ctl_chan));
20529 *channel = (u16)(ctl_chan & 0x00FF);
20530 } else {
20531 *channel = (u16)(chosen & 0x00FF);
20532 }
20533 WL_INFORM(("selected channel = %d\n", *channel));
20534 break;
20535 }
20536 WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n",
20537 (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
20538 }
20539
20540 if (retry <= 0) {
20541 WL_ERR(("failure, auto channel selection timed out\n"));
20542 *channel = 0;
20543 ret = BCME_ERROR;
20544 }
20545 WL_INFORM(("selected channel = %d\n", *channel));
20546
20547 done:
20548 return ret;
20549 }
20550
wl_cfg80211_restore_auto_channel_scan_state(struct net_device * ndev)20551 static s32 wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev)
20552 {
20553 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20554 /* Clear scan stop driver status. */
20555 wl_clr_drv_status(cfg, SCANNING, ndev);
20556
20557 return BCME_OK;
20558 }
20559
wl_cfg80211_get_best_channels(struct net_device * dev,char * cmd,int total_len)20560 s32 wl_cfg80211_get_best_channels(struct net_device *dev, char *cmd,
20561 int total_len)
20562 {
20563 int channel = 0, band, band_cur;
20564 s32 ret = BCME_ERROR;
20565 u8 *buf = NULL;
20566 char *pos = cmd;
20567 struct bcm_cfg80211 *cfg = NULL;
20568 struct net_device *ndev = NULL;
20569
20570 bzero(cmd, total_len);
20571 cfg = wl_get_cfg(dev);
20572
20573 buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
20574 if (buf == NULL) {
20575 WL_ERR(("failed to allocate chanspec buffer\n"));
20576 return -ENOMEM;
20577 }
20578
20579 /*
20580 * Always use primary interface, irrespective of interface on which
20581 * command came.
20582 */
20583 ndev = bcmcfg_to_prmry_ndev(cfg);
20584
20585 /*
20586 * Make sure that FW and driver are in right state to do auto channel
20587 * selection scan.
20588 */
20589 ret = wl_cfg80211_set_auto_channel_scan_state(ndev);
20590 if (ret < 0) {
20591 WL_ERR(("can't set auto channel scan state, error = %d\n", ret));
20592 goto done;
20593 }
20594
20595 ret = wldev_ioctl(dev, WLC_GET_BAND, &band_cur, sizeof(band_cur), false);
20596 if (band_cur != WLC_BAND_5G) {
20597 /* Best channel selection in 2.4GHz band. */
20598 ret =
20599 wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
20600 if (ret < 0) {
20601 WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
20602 goto done;
20603 }
20604
20605 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
20606 &channel);
20607 if (ret < 0) {
20608 WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n",
20609 ret));
20610 goto done;
20611 }
20612
20613 if (CHANNEL_IS_2G(channel)) {
20614 } else {
20615 WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel));
20616 channel = 0;
20617 }
20618 pos += snprintf(pos, total_len, "2g=%d ", channel);
20619 }
20620
20621 if (band_cur != WLC_BAND_2G) {
20622 // terence 20140120: fix for some chipsets only return 2.4GHz channel
20623 // (4330b2/43341b0/4339a0)
20624 band = band_cur == WLC_BAND_2G ? band_cur : WLC_BAND_5G;
20625 ret = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true);
20626 if (ret < 0) {
20627 WL_ERR(("WLC_SET_BAND error %d\n", ret));
20628 goto done;
20629 }
20630
20631 /* Best channel selection in 5GHz band. */
20632 ret =
20633 wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
20634 if (ret < 0) {
20635 WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret));
20636 goto done;
20637 }
20638
20639 ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
20640 &channel);
20641 if (ret < 0) {
20642 WL_ERR(
20643 ("can't select best channel scan in 5GHz, error = %d\n", ret));
20644 goto done;
20645 }
20646
20647 if (CHANNEL_IS_5G(channel)) {
20648 } else {
20649 WL_ERR(("invalid 5GHz channel, channel = %d\n", channel));
20650 channel = 0;
20651 }
20652
20653 ret = wldev_ioctl(dev, WLC_SET_BAND, &band_cur, sizeof(band_cur), true);
20654 if (ret < 0) {
20655 WL_ERR(("WLC_SET_BAND error %d\n", ret));
20656 }
20657 pos += snprintf(pos, total_len, "5g=%d ", channel);
20658 }
20659
20660 done:
20661 if (buf != NULL) {
20662 MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
20663 }
20664
20665 /* Restore FW and driver back to normal state. */
20666 ret = wl_cfg80211_restore_auto_channel_scan_state(ndev);
20667 if (ret < 0) {
20668 WL_ERR(("can't restore auto channel scan state, error = %d\n", ret));
20669 }
20670
20671 WL_MSG(ndev->name, "%s\n", cmd);
20672
20673 return (pos - cmd);
20674 }
20675 #endif /* WL_SUPPORT_AUTO_CHANNEL */
20676
20677 static const struct rfkill_ops wl_rfkill_ops = {.set_block = wl_rfkill_set};
20678
wl_rfkill_set(void * data,bool blocked)20679 static int wl_rfkill_set(void *data, bool blocked)
20680 {
20681 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
20682
20683 WL_DBG(("Enter \n"));
20684 WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
20685
20686 if (!cfg) {
20687 return -EINVAL;
20688 }
20689
20690 cfg->rf_blocked = blocked;
20691
20692 return 0;
20693 }
20694
wl_setup_rfkill(struct bcm_cfg80211 * cfg,bool setup)20695 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
20696 {
20697 s32 err = 0;
20698
20699 WL_DBG(("Enter \n"));
20700 if (!cfg) {
20701 return -EINVAL;
20702 }
20703 if (setup) {
20704 cfg->rfkill =
20705 rfkill_alloc("brcmfmac-wifi", wl_cfg80211_get_parent_dev(),
20706 RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
20707
20708 if (!cfg->rfkill) {
20709 err = -ENOMEM;
20710 goto err_out;
20711 }
20712 err = rfkill_register(cfg->rfkill);
20713 if (err) {
20714 rfkill_destroy(cfg->rfkill);
20715 }
20716 } else {
20717 if (!cfg->rfkill) {
20718 err = -ENOMEM;
20719 goto err_out;
20720 }
20721
20722 rfkill_unregister(cfg->rfkill);
20723 rfkill_destroy(cfg->rfkill);
20724 }
20725
20726 err_out:
20727 return err;
20728 }
20729
20730 #ifdef DEBUGFS_CFG80211
20731 /**
20732 * Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
20733 * to turn on SCAN and DBG log.
20734 * To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
20735 * To see current setting of debug level,
20736 * cat /sys/kernel/debug/dhd/debug_level
20737 */
wl_debuglevel_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)20738 static ssize_t wl_debuglevel_write(struct file *file,
20739 const char __user *userbuf, size_t count,
20740 loff_t *ppos)
20741 {
20742 char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)], sublog[SUBLOGLEVELZ];
20743 char *params, *token, *colon;
20744 uint i, tokens, log_on = 0;
20745 size_t minsize = min_t(size_t, (sizeof(tbuf) - 1), count);
20746
20747 bzero(tbuf, sizeof(tbuf));
20748 bzero(sublog, sizeof(sublog));
20749 if (copy_from_user(&tbuf, userbuf, minsize)) {
20750 return -EFAULT;
20751 }
20752
20753 tbuf[minsize] = '\0';
20754 params = &tbuf[0];
20755 colon = strchr(params, '\n');
20756 if (colon != NULL) {
20757 *colon = '\0';
20758 }
20759 while ((token = strsep(¶ms, " ")) != NULL) {
20760 bzero(sublog, sizeof(sublog));
20761 if (token == NULL || !*token) {
20762 break;
20763 }
20764 if (*token == '\0') {
20765 continue;
20766 }
20767 colon = strchr(token, ':');
20768 if (colon != NULL) {
20769 *colon = ' ';
20770 }
20771 tokens = sscanf(token, "%" S(SUBLOGLEVEL) "s %u", sublog, &log_on);
20772 if (colon != NULL) {
20773 *colon = ':';
20774 }
20775
20776 if (tokens == 0x2) {
20777 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
20778 if (!strncmp(sublog, sublogname_map[i].sublogname,
20779 strlen(sublogname_map[i].sublogname))) {
20780 if (log_on) {
20781 wl_dbg_level |= (sublogname_map[i].log_level);
20782 } else {
20783 wl_dbg_level &= ~(sublogname_map[i].log_level);
20784 }
20785 }
20786 }
20787 } else {
20788 WL_ERR(("%s: can't parse '%s' as a "
20789 "SUBMODULE:LEVEL (%d tokens)\n",
20790 tbuf, token, tokens));
20791 }
20792 }
20793 return count;
20794 }
20795
wl_debuglevel_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)20796 static ssize_t wl_debuglevel_read(struct file *file, char __user *user_buf,
20797 size_t count, loff_t *ppos)
20798 {
20799 char *param;
20800 char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)];
20801 uint i;
20802 bzero(tbuf, sizeof(tbuf));
20803 param = &tbuf[0];
20804 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
20805 param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
20806 sublogname_map[i].sublogname,
20807 (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0);
20808 }
20809 *param = '\n';
20810 return simple_read_from_buffer(user_buf, count, ppos, tbuf,
20811 strlen(&tbuf[0]));
20812 }
20813 static const struct file_operations fops_debuglevel = {
20814 .open = NULL,
20815 .write = wl_debuglevel_write,
20816 .read = wl_debuglevel_read,
20817 .owner = THIS_MODULE,
20818 .llseek = NULL,
20819 };
20820
wl_setup_debugfs(struct bcm_cfg80211 * cfg)20821 static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg)
20822 {
20823 s32 err = 0;
20824 struct dentry *_dentry;
20825 if (!cfg) {
20826 return -EINVAL;
20827 }
20828 cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
20829 if (!cfg->debugfs || IS_ERR(cfg->debugfs)) {
20830 if (cfg->debugfs == ERR_PTR(-ENODEV)) {
20831 WL_ERR(("Debugfs is not enabled on this kernel\n"));
20832 } else {
20833 WL_ERR(("Can not create debugfs directory\n"));
20834 }
20835 cfg->debugfs = NULL;
20836 goto exit;
20837 }
20838 _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR,
20839 cfg->debugfs, cfg, &fops_debuglevel);
20840 if (!_dentry || IS_ERR(_dentry)) {
20841 WL_ERR(("failed to create debug_level debug file\n"));
20842 wl_free_debugfs(cfg);
20843 }
20844 exit:
20845 return err;
20846 }
wl_free_debugfs(struct bcm_cfg80211 * cfg)20847 static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg)
20848 {
20849 if (!cfg) {
20850 return -EINVAL;
20851 }
20852 if (cfg->debugfs) {
20853 debugfs_remove_recursive(cfg->debugfs);
20854 }
20855 cfg->debugfs = NULL;
20856 return 0;
20857 }
20858 #endif /* DEBUGFS_CFG80211 */
20859
wl_cfg80211_get_bcmcfg(void)20860 struct bcm_cfg80211 *wl_cfg80211_get_bcmcfg(void)
20861 {
20862 return g_bcmcfg;
20863 }
20864
wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 * cfg)20865 void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 *cfg)
20866 {
20867 g_bcmcfg = cfg;
20868 }
20869
wl_cfg80211_get_parent_dev(void)20870 struct device *wl_cfg80211_get_parent_dev(void)
20871 {
20872 return cfg80211_parent_dev;
20873 }
20874
wl_cfg80211_set_parent_dev(void * dev)20875 void wl_cfg80211_set_parent_dev(void *dev)
20876 {
20877 cfg80211_parent_dev = dev;
20878 }
20879
wl_cfg80211_clear_parent_dev(void)20880 static void wl_cfg80211_clear_parent_dev(void)
20881 {
20882 cfg80211_parent_dev = NULL;
20883 }
20884
get_primary_mac(struct bcm_cfg80211 * cfg,struct ether_addr * mac)20885 void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
20886 {
20887 u8 ioctl_buf[WLC_IOCTL_SMLEN];
20888
20889 if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr",
20890 NULL, 0, ioctl_buf, sizeof(ioctl_buf), 0,
20891 NULL) == BCME_OK) {
20892 memcpy(mac->octet, ioctl_buf, ETHER_ADDR_LEN);
20893 } else {
20894 bzero(mac->octet, ETHER_ADDR_LEN);
20895 }
20896 }
check_dev_role_integrity(struct bcm_cfg80211 * cfg,u32 dev_role)20897 static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
20898 {
20899 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20900 if (((dev_role == NL80211_IFTYPE_AP) &&
20901 !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
20902 ((dev_role == NL80211_IFTYPE_P2P_GO) &&
20903 !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE))) {
20904 WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role,
20905 dhd->op_mode));
20906 return false;
20907 }
20908 return true;
20909 }
20910
wl_cfg80211_do_driver_init(struct net_device * net)20911 int wl_cfg80211_do_driver_init(struct net_device *net)
20912 {
20913 struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
20914
20915 if (!cfg || !cfg->wdev) {
20916 return -EINVAL;
20917 }
20918
20919 if (dhd_do_driver_init(cfg->wdev->netdev) < 0) {
20920 return -1;
20921 }
20922
20923 return 0;
20924 }
20925
wl_cfg80211_enable_trace(u32 level)20926 void wl_cfg80211_enable_trace(u32 level)
20927 {
20928 wl_dbg_level = level;
20929 WL_MSG("wlan", "wl_dbg_level = 0x%x\n", wl_dbg_level);
20930 }
20931
20932 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || \
20933 (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u64 cookie)20934 static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
20935 bcm_struct_cfgdev *cfgdev,
20936 u64 cookie)
20937 {
20938 /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
20939 * is passed with CMD_FRAME. This callback is supposed to cancel
20940 * the OFFCHANNEL Wait. Since we are already taking care of that
20941 * with the tx_mgmt logic, do nothing here.
20942 */
20943
20944 return 0;
20945 }
20946 #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
20947
20948 #ifdef WL_HOST_BAND_MGMT
wl_cfg80211_set_band(struct net_device * ndev,int band)20949 s32 wl_cfg80211_set_band(struct net_device *ndev, int band)
20950 {
20951 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20952 int ret = 0;
20953 char ioctl_buf[0x32];
20954
20955 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
20956 WL_ERR(("Invalid band\n"));
20957 return -EINVAL;
20958 }
20959
20960 if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band, sizeof(int),
20961 ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
20962 WL_ERR(("seting roam_band failed code=%d\n", ret));
20963 return ret;
20964 }
20965
20966 WL_DBG(("Setting band to %d\n", band));
20967 cfg->curr_band = band;
20968
20969 return 0;
20970 }
20971 #endif /* WL_HOST_BAND_MGMT */
20972
wl_cfg80211_set_if_band(struct net_device * ndev,int band)20973 s32 wl_cfg80211_set_if_band(struct net_device *ndev, int band)
20974 {
20975 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20976 int ret = 0, wait_cnt;
20977 char ioctl_buf[32];
20978
20979 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
20980 WL_ERR(("Invalid band\n"));
20981 return -EINVAL;
20982 }
20983 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
20984 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
20985 BCM_REFERENCE(dhdp);
20986 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
20987 dhd_net2idx(dhdp->info, ndev), 0);
20988 ret = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
20989 if (ret < 0) {
20990 WL_ERR(("WLC_DISASSOC error %d\n", ret));
20991 /* continue to set 'if_band' */
20992 } else {
20993 /* This is to ensure that 'if_band' iovar is issued only after
20994 * disconnection is completed
20995 */
20996 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
20997 while (wl_get_drv_status(cfg, CONNECTED, ndev) && wait_cnt) {
20998 WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt));
20999 wait_cnt--;
21000 OSL_SLEEP(0x32);
21001 }
21002 }
21003 }
21004 if ((ret = wldev_iovar_setbuf(ndev, "if_band", &band, sizeof(int),
21005 ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
21006 WL_ERR(("seting if_band failed ret=%d\n", ret));
21007 /* issue 'WLC_SET_BAND' if if_band is not supported */
21008 if (ret == BCME_UNSUPPORTED) {
21009 ret = wldev_set_band(ndev, band);
21010 if (ret < 0) {
21011 WL_ERR(("seting band failed ret=%d\n", ret));
21012 }
21013 }
21014 }
21015 return ret;
21016 }
21017
wl_cfg80211_dfs_ap_move(struct net_device * ndev,char * data,char * command,int total_len)21018 s32 wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command,
21019 int total_len)
21020 {
21021 char ioctl_buf[WLC_IOCTL_SMLEN];
21022 int err = 0;
21023 uint32 val = 0;
21024 chanspec_t chanspec = 0;
21025 int abort;
21026 int bytes_written = 0;
21027 struct wl_dfs_ap_move_status_v2 *status;
21028 char chanbuf[CHANSPEC_STR_LEN];
21029 const char *dfs_state_str[DFS_SCAN_S_MAX] = {
21030 "Radar Free On Channel", "Radar Found On Channel",
21031 "Radar Scan In Progress", "Radar Scan Aborted",
21032 "RSDB Mode switch in Progress For Scan"};
21033 if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
21034 bytes_written = snprintf(command, total_len, "AP is not up\n");
21035 return bytes_written;
21036 }
21037 if (!*data) {
21038 if ((err = wldev_iovar_getbuf(ndev, "dfs_ap_move", NULL, 0, ioctl_buf,
21039 sizeof(ioctl_buf), NULL))) {
21040 WL_ERR(("setting dfs_ap_move failed with err=%d \n", err));
21041 return err;
21042 }
21043 status = (struct wl_dfs_ap_move_status_v2 *)ioctl_buf;
21044
21045 if (status->version != WL_DFS_AP_MOVE_VERSION) {
21046 err = BCME_UNSUPPORTED;
21047 WL_ERR(("err=%d version=%d\n", err, status->version));
21048 return err;
21049 }
21050
21051 if (status->move_status != (int8)DFS_SCAN_S_IDLE) {
21052 chanspec = wl_chspec_driver_to_host(status->chanspec);
21053 if (chanspec != 0 && chanspec != INVCHANSPEC) {
21054 wf_chspec_ntoa(chanspec, chanbuf);
21055 bytes_written = snprintf(command, total_len,
21056 "AP Target Chanspec %s (0x%x)\n",
21057 chanbuf, chanspec);
21058 }
21059 bytes_written +=
21060 snprintf(command + bytes_written, total_len - bytes_written,
21061 "%s\n", dfs_state_str[status->move_status]);
21062 return bytes_written;
21063 } else {
21064 bytes_written =
21065 snprintf(command, total_len, "dfs AP move in IDLE state\n");
21066 return bytes_written;
21067 }
21068 }
21069
21070 abort = bcm_atoi(data);
21071 if (abort == -1) {
21072 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &abort, sizeof(int),
21073 ioctl_buf, sizeof(ioctl_buf), NULL)) <
21074 0) {
21075 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
21076 return err;
21077 }
21078 } else {
21079 chanspec = wf_chspec_aton(data);
21080 if (chanspec != 0) {
21081 val = wl_chspec_host_to_driver(chanspec);
21082 if (val != INVCHANSPEC) {
21083 if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &val,
21084 sizeof(int), ioctl_buf,
21085 sizeof(ioctl_buf), NULL)) < 0) {
21086 WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
21087 return err;
21088 }
21089 WL_DBG((" set dfs_ap_move successfull"));
21090 } else {
21091 err = BCME_USAGE_ERROR;
21092 }
21093 }
21094 }
21095 return err;
21096 }
21097
wl_cfg80211_is_concurrent_mode(struct net_device * dev)21098 bool wl_cfg80211_is_concurrent_mode(struct net_device *dev)
21099 {
21100 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21101 if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
21102 return true;
21103 } else {
21104 return false;
21105 }
21106 }
21107
wl_cfg80211_get_dhdp(struct net_device * dev)21108 void *wl_cfg80211_get_dhdp(struct net_device *dev)
21109 {
21110 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21111
21112 return cfg->pub;
21113 }
21114
wl_cfg80211_is_p2p_active(struct net_device * dev)21115 bool wl_cfg80211_is_p2p_active(struct net_device *dev)
21116 {
21117 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21118 return (cfg && cfg->p2p);
21119 }
21120
wl_cfg80211_is_roam_offload(struct net_device * dev)21121 bool wl_cfg80211_is_roam_offload(struct net_device *dev)
21122 {
21123 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21124 return (cfg && cfg->roam_offload);
21125 }
21126
wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev,const wl_event_msg_t * e,int ifidx)21127 bool wl_cfg80211_is_event_from_connected_bssid(struct net_device *dev,
21128 const wl_event_msg_t *e,
21129 int ifidx)
21130 {
21131 u8 *curbssid = NULL;
21132 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21133
21134 if (!cfg) {
21135 /* When interface is created using wl
21136 * ndev->ieee80211_ptr will be NULL.
21137 */
21138 return NULL;
21139 }
21140 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
21141 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
21142 return true;
21143 }
21144 return false;
21145 }
21146
wl_cfg80211_work_handler(struct work_struct * work)21147 static void wl_cfg80211_work_handler(struct work_struct *work)
21148 {
21149 struct bcm_cfg80211 *cfg = NULL;
21150 struct net_info *iter, *next;
21151 s32 err = BCME_OK;
21152 s32 pm = PM_FAST;
21153 dhd_pub_t *dhd;
21154 BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
21155 WL_DBG(("Enter \n"));
21156 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21157 for_each_ndev(cfg, iter, next)
21158 {
21159 GCC_DIAGNOSTIC_POP();
21160 /* p2p discovery iface ndev could be null */
21161 if (iter->ndev) {
21162 if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
21163 (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
21164 wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS)) {
21165 continue;
21166 }
21167 if (iter->ndev) {
21168 dhd = (dhd_pub_t *)(cfg->pub);
21169 if (dhd_conf_get_pm(dhd) >= 0) {
21170 pm = dhd_conf_get_pm(dhd);
21171 }
21172 if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM, &pm,
21173 sizeof(pm))) != 0) {
21174 if (err == -ENODEV) {
21175 WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
21176 } else {
21177 WL_ERR(("%s:error (%d)\n", iter->ndev->name, err));
21178 }
21179 } else {
21180 wl_cfg80211_update_power_mode(iter->ndev);
21181 }
21182 }
21183 }
21184 }
21185 DHD_PM_WAKE_UNLOCK(cfg->pub);
21186 }
21187
wl_get_action_category(void * frame,u32 frame_len)21188 u8 wl_get_action_category(void *frame, u32 frame_len)
21189 {
21190 u8 category;
21191 u8 *ptr = (u8 *)frame;
21192 if (frame == NULL) {
21193 return DOT11_ACTION_CAT_ERR_MASK;
21194 }
21195 if (frame_len < DOT11_ACTION_HDR_LEN) {
21196 return DOT11_ACTION_CAT_ERR_MASK;
21197 }
21198 category = ptr[DOT11_ACTION_CAT_OFF];
21199 WL_DBG(("Action Category: %d\n", category));
21200 return category;
21201 }
21202
wl_get_public_action(void * frame,u32 frame_len,u8 * ret_action)21203 int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
21204 {
21205 u8 *ptr = (u8 *)frame;
21206 if (frame == NULL || ret_action == NULL) {
21207 return BCME_ERROR;
21208 }
21209 if (frame_len < DOT11_ACTION_HDR_LEN) {
21210 return BCME_ERROR;
21211 }
21212 if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len)) {
21213 return BCME_ERROR;
21214 }
21215 *ret_action = ptr[DOT11_ACTION_ACT_OFF];
21216 WL_DBG(("Public Action : %d\n", *ret_action));
21217 return BCME_OK;
21218 }
21219
21220 #ifdef WLFBT
wl_cfg80211_get_fbt_key(struct net_device * dev,uint8 * key,int total_len)21221 int wl_cfg80211_get_fbt_key(struct net_device *dev, uint8 *key, int total_len)
21222 {
21223 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21224 int bytes_written = -1;
21225
21226 if (total_len < FBT_KEYLEN) {
21227 WL_ERR(("wl_cfg80211_get_fbt_key: Insufficient buffer \n"));
21228 goto end;
21229 }
21230 if (cfg) {
21231 memcpy(key, cfg->fbt_key, FBT_KEYLEN);
21232 bytes_written = FBT_KEYLEN;
21233 } else {
21234 bzero(key, FBT_KEYLEN);
21235 WL_ERR(("wl_cfg80211_get_fbt_key: Failed to copy KCK and KEK \n"));
21236 }
21237 prhex("KCK, KEK", (uchar *)key, FBT_KEYLEN);
21238 end:
21239 return bytes_written;
21240 }
21241 #endif /* WLFBT */
21242
wl_cfg80211_delayed_roam(struct bcm_cfg80211 * cfg,struct net_device * ndev,const struct ether_addr * bssid)21243 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg,
21244 struct net_device *ndev,
21245 const struct ether_addr *bssid)
21246 {
21247 s32 err;
21248 wl_event_msg_t e;
21249
21250 bzero(&e, sizeof(e));
21251 e.event_type = cpu_to_be32(WLC_E_ROAM);
21252 memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
21253 /* trigger the roam event handler */
21254 err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
21255
21256 return err;
21257 }
21258
wl_cfg80211_parse_vndr_ies(const u8 * parse,u32 len,struct parsed_vndr_ies * vndr_ies)21259 static s32 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
21260 struct parsed_vndr_ies *vndr_ies)
21261 {
21262 s32 err = BCME_OK;
21263 const vndr_ie_t *vndrie;
21264 const bcm_tlv_t *ie;
21265 struct parsed_vndr_ie_info *parsed_info;
21266 u32 count = 0;
21267 u32 remained_len;
21268
21269 remained_len = len;
21270 bzero(vndr_ies, sizeof(*vndr_ies));
21271
21272 WL_DBG(("---> len %d\n", len));
21273 ie = (const bcm_tlv_t *)parse;
21274 if (!bcm_valid_tlv(ie, remained_len)) {
21275 ie = NULL;
21276 }
21277 while (ie) {
21278 if (count >= MAX_VNDR_IE_NUMBER) {
21279 break;
21280 }
21281 if (ie->id == DOT11_MNG_VS_ID || (ie->id == DOT11_MNG_ID_EXT_ID)) {
21282 vndrie = (const vndr_ie_t *)ie;
21283 if (ie->id == DOT11_MNG_ID_EXT_ID) {
21284 /* len should be bigger than sizeof ID extn field at least */
21285 if (vndrie->len < MIN_VENDOR_EXTN_IE_LEN) {
21286 WL_ERR(("%s: invalid vndr extn ie."
21287 " length %d\n",
21288 __FUNCTION__, vndrie->len));
21289 goto end;
21290 }
21291 } else {
21292 /* len should be bigger than OUI length +
21293 * one data length at least
21294 */
21295 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
21296 WL_ERR(("wl_cfg80211_parse_vndr_ies:"
21297 " invalid vndr ie. length is too small %d\n",
21298 vndrie->len));
21299 goto end;
21300 }
21301
21302 /* if wpa or wme ie, do not add ie */
21303 if (!bcmp(vndrie->oui, (u8 *)WPA_OUI, WPA_OUI_LEN) &&
21304 ((vndrie->data[0] == WPA_OUI_TYPE) ||
21305 (vndrie->data[0] == WME_OUI_TYPE))) {
21306 CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
21307 goto end;
21308 }
21309 }
21310
21311 parsed_info = &vndr_ies->ie_info[count++];
21312
21313 /* save vndr ie information */
21314 parsed_info->ie_ptr = (const char *)vndrie;
21315 parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
21316 memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
21317 vndr_ies->count = count;
21318 if (ie->id == DOT11_MNG_ID_EXT_ID) {
21319 WL_DBG(("\t ** Vendor Extension ie id: 0x%02x, len:%d\n",
21320 ie->id, parsed_info->ie_len));
21321 } else {
21322 WL_DBG(("\t ** OUI " MACOUIDBG ", type 0x%02x len:%d\n",
21323 MACOUI2STRDBG(parsed_info->vndrie.oui),
21324 parsed_info->vndrie.data[0], parsed_info->ie_len));
21325 }
21326 }
21327 end:
21328 ie = bcm_next_tlv(ie, &remained_len);
21329 }
21330 return err;
21331 }
21332
wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info * vndr_info)21333 static bool wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info *vndr_info)
21334 {
21335 int i = 0;
21336
21337 while (exclude_vndr_oui_list[i]) {
21338 if (!memcmp(vndr_info->vndrie.oui, exclude_vndr_oui_list[i],
21339 DOT11_OUI_LEN)) {
21340 return TRUE;
21341 }
21342 i++;
21343 }
21344
21345 return FALSE;
21346 }
21347
21348 static bool
wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)21349 wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 *cfg,
21350 struct parsed_vndr_ie_info *vndr_info)
21351 {
21352 wl_vndr_oui_entry_t *oui_entry = NULL;
21353 unsigned long flags;
21354
21355 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21356 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21357 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list)
21358 {
21359 GCC_DIAGNOSTIC_POP();
21360 if (!memcmp(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN)) {
21361 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21362 return TRUE;
21363 }
21364 }
21365 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21366 return FALSE;
21367 }
21368
21369 static bool
wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)21370 wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 *cfg,
21371 struct parsed_vndr_ie_info *vndr_info)
21372 {
21373 wl_vndr_oui_entry_t *oui_entry = NULL;
21374 unsigned long flags;
21375
21376 oui_entry = kmalloc(sizeof(*oui_entry), GFP_KERNEL);
21377 if (oui_entry == NULL) {
21378 WL_ERR(("alloc failed\n"));
21379 return FALSE;
21380 }
21381
21382 memcpy(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN);
21383
21384 INIT_LIST_HEAD(&oui_entry->list);
21385 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21386 list_add_tail(&oui_entry->list, &cfg->vndr_oui_list);
21387 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21388
21389 return TRUE;
21390 }
21391
wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 * cfg)21392 static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg)
21393 {
21394 wl_vndr_oui_entry_t *oui_entry = NULL;
21395 unsigned long flags;
21396
21397 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21398 while (!list_empty(&cfg->vndr_oui_list)) {
21399 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21400 oui_entry =
21401 list_entry(cfg->vndr_oui_list.next, wl_vndr_oui_entry_t, list);
21402 GCC_DIAGNOSTIC_POP();
21403 if (oui_entry) {
21404 list_del(&oui_entry->list);
21405 kfree(oui_entry);
21406 }
21407 }
21408 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21409 }
21410
wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * vndr_oui,u32 vndr_oui_len)21411 static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
21412 struct net_device *ndev, char *vndr_oui,
21413 u32 vndr_oui_len)
21414 {
21415 int i;
21416 int vndr_oui_num = 0;
21417
21418 struct wl_connect_info *conn_info = wl_to_conn(cfg);
21419 wl_vndr_oui_entry_t *oui_entry = NULL;
21420 struct parsed_vndr_ie_info *vndr_info;
21421 struct parsed_vndr_ies vndr_ies;
21422
21423 char *pos = vndr_oui;
21424 u32 remained_buf_len = vndr_oui_len;
21425 unsigned long flags;
21426
21427 if (!conn_info->resp_ie_len) {
21428 return BCME_ERROR;
21429 }
21430
21431 wl_vndr_ies_clear_vendor_oui_list(cfg);
21432
21433 if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
21434 conn_info->resp_ie_len, &vndr_ies)) ==
21435 BCME_OK) {
21436 for (i = 0; i < vndr_ies.count; i++) {
21437 vndr_info = &vndr_ies.ie_info[i];
21438 if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
21439 continue;
21440 }
21441
21442 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
21443 continue;
21444 }
21445
21446 wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
21447 vndr_oui_num++;
21448 }
21449 }
21450
21451 if (vndr_oui) {
21452 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
21453 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21454 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list)
21455 {
21456 GCC_DIAGNOSTIC_POP();
21457 if (remained_buf_len < VNDR_OUI_STR_LEN) {
21458 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21459 return BCME_ERROR;
21460 }
21461 pos += snprintf(pos, VNDR_OUI_STR_LEN, "%02X-%02X-%02X ",
21462 oui_entry->oui[0], oui_entry->oui[1],
21463 oui_entry->oui[0x2]);
21464 remained_buf_len -= VNDR_OUI_STR_LEN;
21465 }
21466 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
21467 }
21468
21469 return vndr_oui_num;
21470 }
21471
wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 * cfg)21472 void wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 *cfg)
21473 {
21474 /* Legacy P2P used to store it in primary dev cache */
21475 s32 index;
21476 struct net_device *ndev;
21477 s32 bssidx;
21478 s32 ret;
21479 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
21480 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG,
21481 VNDR_IE_ASSOCREQ_FLAG};
21482
21483 WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
21484 /* certain vendors uses p2p0 interface in addition to
21485 * the dedicated p2p interface supported by the linux
21486 * kernel.
21487 */
21488 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
21489 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
21490 if (bssidx == WL_INVALID) {
21491 WL_DBG(("No discovery I/F available. Do nothing.\n"));
21492 return;
21493 }
21494
21495 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
21496 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
21497 bssidx, vndrie_flag[index],
21498 NULL, 0)) < 0) {
21499 if (ret != BCME_NOTFOUND) {
21500 WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret));
21501 }
21502 }
21503 }
21504
21505 if (cfg->p2p_wdev && (ndev->ieee80211_ptr != cfg->p2p_wdev)) {
21506 /* clear IEs for dedicated p2p interface */
21507 wl_cfg80211_clear_per_bss_ies(cfg, cfg->p2p_wdev);
21508 }
21509 }
21510
wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev)21511 s32 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg,
21512 struct wireless_dev *wdev)
21513 {
21514 s32 index;
21515 s32 ret;
21516 struct net_info *netinfo;
21517 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
21518 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG,
21519 VNDR_IE_ASSOCREQ_FLAG};
21520
21521 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
21522 if (!netinfo || !netinfo->wdev) {
21523 WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
21524 return -1;
21525 }
21526
21527 WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo->bssidx));
21528 /* Clear the IEs set in the firmware so that host is in sync with firmware
21529 */
21530 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
21531 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(
21532 cfg, wdev_to_cfgdev(netinfo->wdev), netinfo->bssidx,
21533 vndrie_flag[index], NULL, 0)) < 0) {
21534 if (ret != BCME_NOTFOUND) {
21535 WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
21536 }
21537 }
21538 }
21539
21540 return 0;
21541 }
21542
wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 * cfg)21543 s32 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
21544 {
21545 struct net_info *iter, *next;
21546
21547 WL_DBG(("clear management vendor IEs \n"));
21548 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21549 for_each_ndev(cfg, iter, next)
21550 {
21551 GCC_DIAGNOSTIC_POP();
21552 wl_cfg80211_clear_per_bss_ies(cfg, iter->wdev);
21553 }
21554 return 0;
21555 }
21556
21557 #define WL_VNDR_IE_MAXLEN 2048
21558 static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
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)21559 int wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg,
21560 bcm_struct_cfgdev *cfgdev, s32 bssidx,
21561 s32 pktflag, const u8 *vndr_ie,
21562 u32 vndr_ie_len)
21563 {
21564 struct net_device *ndev = NULL;
21565 s32 ret = BCME_OK;
21566 u8 *curr_ie_buf = NULL;
21567 u8 *mgmt_ie_buf = NULL;
21568 u32 mgmt_ie_buf_len = 0;
21569 u32 *mgmt_ie_len = 0;
21570 u32 del_add_ie_buf_len = 0;
21571 u32 total_ie_buf_len = 0;
21572 u32 parsed_ie_buf_len = 0;
21573 struct parsed_vndr_ies old_vndr_ies;
21574 struct parsed_vndr_ies new_vndr_ies;
21575 s32 i;
21576 u8 *ptr;
21577 s32 remained_buf_len;
21578 wl_bss_vndr_ies_t *ies = NULL;
21579 struct net_info *netinfo;
21580 struct wireless_dev *wdev;
21581
21582 if (!cfgdev) {
21583 WL_ERR(("cfgdev is NULL\n"));
21584 return -EINVAL;
21585 }
21586
21587 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
21588 wdev = cfgdev_to_wdev(cfgdev);
21589
21590 if (bssidx > WL_MAX_IFS) {
21591 WL_ERR(("bssidx > supported concurrent Ifaces \n"));
21592 return -EINVAL;
21593 }
21594
21595 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
21596 if (!netinfo) {
21597 WL_ERR(("net_info ptr is NULL \n"));
21598 return -EINVAL;
21599 }
21600
21601 /* Clear the global buffer */
21602 bzero(g_mgmt_ie_buf, sizeof(g_mgmt_ie_buf));
21603 curr_ie_buf = g_mgmt_ie_buf;
21604 ies = &netinfo->bss.ies;
21605
21606 WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d wdev:%p\n", pktflag,
21607 bssidx, vndr_ie_len, wdev));
21608
21609 switch (pktflag) {
21610 case VNDR_IE_PRBRSP_FLAG:
21611 mgmt_ie_buf = ies->probe_res_ie;
21612 mgmt_ie_len = &ies->probe_res_ie_len;
21613 mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
21614 break;
21615 case VNDR_IE_ASSOCRSP_FLAG:
21616 mgmt_ie_buf = ies->assoc_res_ie;
21617 mgmt_ie_len = &ies->assoc_res_ie_len;
21618 mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
21619 break;
21620 case VNDR_IE_BEACON_FLAG:
21621 mgmt_ie_buf = ies->beacon_ie;
21622 mgmt_ie_len = &ies->beacon_ie_len;
21623 mgmt_ie_buf_len = sizeof(ies->beacon_ie);
21624 break;
21625 case VNDR_IE_PRBREQ_FLAG:
21626 mgmt_ie_buf = ies->probe_req_ie;
21627 mgmt_ie_len = &ies->probe_req_ie_len;
21628 mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
21629 break;
21630 case VNDR_IE_ASSOCREQ_FLAG:
21631 mgmt_ie_buf = ies->assoc_req_ie;
21632 mgmt_ie_len = &ies->assoc_req_ie_len;
21633 mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
21634 break;
21635 case VNDR_IE_DISASSOC_FLAG:
21636 mgmt_ie_buf = ies->disassoc_ie;
21637 mgmt_ie_len = &ies->disassoc_ie_len;
21638 mgmt_ie_buf_len = sizeof(ies->disassoc_ie);
21639 break;
21640 default:
21641 mgmt_ie_buf = NULL;
21642 mgmt_ie_len = NULL;
21643 WL_ERR(("not suitable packet type (%d)\n", pktflag));
21644 return BCME_ERROR;
21645 }
21646
21647 if (vndr_ie_len > mgmt_ie_buf_len) {
21648 WL_ERR(("extra IE size too big\n"));
21649 ret = -ENOMEM;
21650 } else {
21651 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
21652 if (vndr_ie && vndr_ie_len && curr_ie_buf) {
21653 ptr = curr_ie_buf;
21654
21655 if ((ret = wl_cfg80211_parse_vndr_ies(
21656 (const u8 *)vndr_ie, vndr_ie_len, &new_vndr_ies)) < 0) {
21657 WL_ERR(("parse vndr ie failed \n"));
21658 goto exit;
21659 }
21660
21661 for (i = 0; i < new_vndr_ies.count; i++) {
21662 struct parsed_vndr_ie_info *vndrie_info =
21663 &new_vndr_ies.ie_info[i];
21664
21665 if ((parsed_ie_buf_len + vndrie_info->ie_len) >
21666 WL_VNDR_IE_MAXLEN) {
21667 WL_ERR(("IE size is too big (%d > %d)\n", parsed_ie_buf_len,
21668 WL_VNDR_IE_MAXLEN));
21669 ret = -EINVAL;
21670 goto exit;
21671 }
21672
21673 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
21674 vndrie_info->ie_len);
21675 parsed_ie_buf_len += vndrie_info->ie_len;
21676 }
21677 }
21678
21679 if (mgmt_ie_buf != NULL) {
21680 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
21681 (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
21682 WL_DBG(("Previous mgmt IE is equals to current IE"));
21683 goto exit;
21684 }
21685
21686 /* parse old vndr_ie */
21687 if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
21688 &old_vndr_ies)) < 0) {
21689 WL_ERR(("parse vndr ie failed \n"));
21690 goto exit;
21691 }
21692 /* make a command to delete old ie */
21693 for (i = 0; i < old_vndr_ies.count; i++) {
21694 struct parsed_vndr_ie_info *vndrie_info =
21695 &old_vndr_ies.ie_info[i];
21696 #if defined(WL_MBO) || defined(WL_OCE)
21697 {
21698 if ((vndrie_info->vndrie.id == 0xDD) &&
21699 (!memcmp(vndrie_info->vndrie.oui, WFA_OUI,
21700 WFA_OUI_LEN)) &&
21701 (vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
21702 WL_DBG(("skipping ID : %d, Len: %d, OUI:" MACOUIDBG
21703 ", type: %0x\n",
21704 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
21705 MACOUI2STRDBG(vndrie_info->vndrie.oui),
21706 vndrie_info->vndrie.data[0]));
21707 continue;
21708 }
21709 }
21710 #endif /* WL_MBO || WL_OCE */
21711
21712 if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
21713 WL_DBG(("DELETED VENDOR EXTN ID : %d, TYPE: %d Len: %d\n",
21714 vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
21715 vndrie_info->vndrie.len));
21716 } else {
21717 WL_DBG(("DELETED ID : %d, Len: %d , OUI:" MACOUIDBG "\n",
21718 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
21719 MACOUI2STRDBG(vndrie_info->vndrie.oui)));
21720 }
21721
21722 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(
21723 cfg, curr_ie_buf, pktflag, vndrie_info->vndrie.oui,
21724 vndrie_info->vndrie.id,
21725 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
21726 vndrie_info->ie_len - VNDR_IE_FIXED_LEN, "del");
21727
21728 curr_ie_buf += del_add_ie_buf_len;
21729 total_ie_buf_len += del_add_ie_buf_len;
21730 }
21731 }
21732
21733 *mgmt_ie_len = 0;
21734 /* Add if there is any extra IE */
21735 if (mgmt_ie_buf && parsed_ie_buf_len) {
21736 ptr = mgmt_ie_buf;
21737
21738 remained_buf_len = mgmt_ie_buf_len;
21739
21740 /* make a command to add new ie */
21741 for (i = 0; i < new_vndr_ies.count; i++) {
21742 struct parsed_vndr_ie_info *vndrie_info =
21743 &new_vndr_ies.ie_info[i];
21744 #if defined(WL_MBO) || defined(WL_OCE)
21745 {
21746 if ((vndrie_info->vndrie.id == 0xDD) &&
21747 (!memcmp(vndrie_info->vndrie.oui, WFA_OUI,
21748 WFA_OUI_LEN)) &&
21749 (vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
21750 WL_DBG(("skipping ID : %d, Len: %d, OUI:" MACOUIDBG
21751 ",type :%0x\n",
21752 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
21753 MACOUI2STRDBG(vndrie_info->vndrie.oui),
21754 vndrie_info->vndrie.data[0]));
21755 continue;
21756 }
21757 }
21758 #endif /* WL_MBO || WL_OCE */
21759 if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
21760 WL_DBG(("ADDED VENDOR EXTN ID : %d, TYPE = %d, Len: %d\n",
21761 vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
21762 vndrie_info->vndrie.len));
21763 } else {
21764 WL_DBG(("ADDED ID : %d, Len: %d(%d), OUI:" MACOUIDBG "\n",
21765 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
21766 vndrie_info->ie_len - 0x2,
21767 MACOUI2STRDBG(vndrie_info->vndrie.oui)));
21768 }
21769
21770 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(
21771 cfg, curr_ie_buf, pktflag, vndrie_info->vndrie.oui,
21772 vndrie_info->vndrie.id,
21773 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
21774 vndrie_info->ie_len - VNDR_IE_FIXED_LEN, "add");
21775
21776 /* verify remained buf size before copy data */
21777 if (remained_buf_len >= vndrie_info->ie_len) {
21778 remained_buf_len -= vndrie_info->ie_len;
21779 } else {
21780 WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
21781 "found vndr ies # = %d(cur %d), remained len %d, "
21782 "cur mgmt_ie_len %d, new ie len = %d\n",
21783 pktflag, new_vndr_ies.count, i, remained_buf_len,
21784 *mgmt_ie_len, vndrie_info->ie_len));
21785 break;
21786 }
21787
21788 /* save the parsed IE in cfg struct */
21789 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
21790 vndrie_info->ie_len);
21791 *mgmt_ie_len += vndrie_info->ie_len;
21792 curr_ie_buf += del_add_ie_buf_len;
21793 total_ie_buf_len += del_add_ie_buf_len;
21794 }
21795 }
21796
21797 if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
21798 ret = wldev_iovar_setbuf_bsscfg(
21799 ndev, "vndr_ie", g_mgmt_ie_buf, total_ie_buf_len,
21800 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
21801 if (ret) {
21802 WL_ERR(("vndr ie set error : %d\n", ret));
21803 }
21804 }
21805 }
21806 exit:
21807
21808 return ret;
21809 }
21810
21811 #ifdef WL_CFG80211_ACL
wl_cfg80211_set_mac_acl(struct wiphy * wiphy,struct net_device * cfgdev,const struct cfg80211_acl_data * acl)21812 static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy,
21813 struct net_device *cfgdev,
21814 const struct cfg80211_acl_data *acl)
21815 {
21816 int i;
21817 int ret = 0;
21818 int macnum = 0;
21819 int macmode = MACLIST_MODE_DISABLED;
21820 struct maclist *list;
21821 struct bcm_cfg80211 *cfg = wl_get_cfg(cfgdev);
21822
21823 /* get the MAC filter mode */
21824 if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
21825 macmode = MACLIST_MODE_ALLOW;
21826 } else if (acl &&
21827 acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
21828 acl->n_acl_entries) {
21829 macmode = MACLIST_MODE_DENY;
21830 }
21831
21832 /* if acl == NULL, macmode is still disabled.. */
21833 if (macmode == MACLIST_MODE_DISABLED) {
21834 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0) {
21835 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list"
21836 " failed error=%d\n",
21837 ret));
21838 }
21839
21840 return ret;
21841 }
21842
21843 macnum = acl->n_acl_entries;
21844 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
21845 WL_ERR(("wl_cfg80211_set_mac_acl: invalid number of MAC address "
21846 "entries %d\n",
21847 macnum));
21848 return -1;
21849 }
21850
21851 /* allocate memory for the MAC list */
21852 list = (struct maclist *)MALLOC(
21853 cfg->osh, sizeof(int) + sizeof(struct ether_addr) * macnum);
21854 if (!list) {
21855 WL_ERR(("wl_cfg80211_set_mac_acl: failed to allocate memory\n"));
21856 return -1;
21857 }
21858
21859 /* prepare the MAC list */
21860 list->count = htod32(macnum);
21861 for (i = 0; i < macnum; i++) {
21862 memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN);
21863 }
21864 /* set the list */
21865 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0) {
21866 WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list failed error=%d\n",
21867 ret));
21868 }
21869
21870 MFREE(cfg->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
21871
21872 return ret;
21873 }
21874 #endif /* WL_CFG80211_ACL */
21875
21876 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
wl_chspec_chandef(chanspec_t chanspec,struct cfg80211_chan_def * chandef,struct wiphy * wiphy)21877 int wl_chspec_chandef(chanspec_t chanspec,
21878 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
21879 struct cfg80211_chan_def *chandef,
21880 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) && \
21881 (LINUX_VERSION_CODE <= (3, 7, 0)))
21882 struct chan_info *chaninfo,
21883 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
21884 struct wiphy *wiphy)
21885 {
21886 uint16 freq = 0;
21887 int chan_type = 0;
21888 int channel = 0;
21889 struct ieee80211_channel *chan;
21890
21891 if (!chandef) {
21892 return -1;
21893 }
21894 channel = CHSPEC_CHANNEL(chanspec);
21895
21896 switch (CHSPEC_BW(chanspec)) {
21897 case WL_CHANSPEC_BW_20:
21898 chan_type = NL80211_CHAN_HT20;
21899 break;
21900 case WL_CHANSPEC_BW_40: {
21901 if (CHSPEC_SB_UPPER(chanspec)) {
21902 channel += CH_10MHZ_APART;
21903 } else {
21904 channel -= CH_10MHZ_APART;
21905 }
21906 }
21907 chan_type = NL80211_CHAN_HT40PLUS;
21908 break;
21909
21910 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
21911 case WL_CHANSPEC_BW_80:
21912 case WL_CHANSPEC_BW_8080: {
21913 uint16 sb = CHSPEC_CTL_SB(chanspec);
21914 if (sb == WL_CHANSPEC_CTL_SB_LL) {
21915 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
21916 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
21917 channel -= CH_10MHZ_APART;
21918 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
21919 channel += CH_10MHZ_APART;
21920 } else {
21921 /* WL_CHANSPEC_CTL_SB_UU */
21922 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
21923 }
21924
21925 if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_LU) {
21926 chan_type = NL80211_CHAN_HT40MINUS;
21927 } else if (sb == WL_CHANSPEC_CTL_SB_UL ||
21928 sb == WL_CHANSPEC_CTL_SB_UU) {
21929 chan_type = NL80211_CHAN_HT40PLUS;
21930 }
21931 break;
21932 }
21933 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21934 default:
21935 chan_type = NL80211_CHAN_HT20;
21936 break;
21937 }
21938
21939 if (CHSPEC_IS5G(chanspec)) {
21940 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
21941 } else {
21942 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
21943 }
21944
21945 chan = ieee80211_get_channel(wiphy, freq);
21946 WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n", channel, freq,
21947 chan_type, chan));
21948
21949 if (unlikely(!chan)) {
21950 /* fw and cfg80211 channel lists are not in sync */
21951 WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
21952 ASSERT(0);
21953 return -EINVAL;
21954 }
21955
21956 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
21957 cfg80211_chandef_create(chandef, chan, chan_type);
21958 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) && \
21959 (LINUX_VERSION_CODE <= (3, 7, \
21960 \
21961 0)))
21962 chaninfo->freq = freq;
21963 chaninfo->chan_type = chan_type;
21964 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21965 return 0;
21966 }
21967
wl_cfg80211_ch_switch_notify(struct net_device * dev,uint16 chanspec,struct wiphy * wiphy)21968 void wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec,
21969 struct wiphy *wiphy)
21970 {
21971 u32 freq;
21972 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
21973 struct cfg80211_chan_def chandef;
21974 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) && \
21975 (LINUX_VERSION_CODE <= (3, 7, 0)))
21976 struct chan_info chaninfo;
21977 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21978
21979 if (!wiphy) {
21980 WL_ERR(("wiphy is null\n"));
21981 return;
21982 }
21983 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 18, 0))
21984 /* Channel switch support is only for AP/GO/ADHOC/MESH */
21985 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
21986 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
21987 WL_ERR(("No channel switch notify support for STA/GC\n"));
21988 return;
21989 }
21990 #endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
21991
21992 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
21993 if (wl_chspec_chandef(chanspec, &chandef, wiphy))
21994 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) && \
21995 (LINUX_VERSION_CODE <= (3, 7, 0)))
21996 if (wl_chspec_chandef(chanspec, &chaninfo, wiphy))
21997 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
21998 {
21999 WL_ERR(("chspec_chandef failed\n"));
22000 return;
22001 }
22002 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
22003 freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1;
22004 cfg80211_ch_switch_notify(dev, &chandef);
22005 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) && \
22006 (LINUX_VERSION_CODE <= (3, 7, 0)))
22007 freq = chan_info.freq;
22008 cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type);
22009 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
22010
22011 WL_MSG(dev->name,
22012 "Channel switch notification for freq: %d chanspec: 0x%x\n", freq,
22013 chanspec);
22014 #ifdef WL_EXT_IAPSTA
22015 wl_ext_war(dev);
22016 #endif
22017 return;
22018 }
22019 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
22020
wl_ap_channel_ind(struct bcm_cfg80211 * cfg,struct net_device * ndev,chanspec_t chanspec)22021 static void wl_ap_channel_ind(struct bcm_cfg80211 *cfg, struct net_device *ndev,
22022 chanspec_t chanspec)
22023 {
22024 u32 channel = LCHSPEC_CHANNEL(chanspec);
22025
22026 WL_INFORM_MEM(
22027 ("(%s) AP channel:%d chspec:0x%x \n", ndev->name, channel, chanspec));
22028
22029 #ifdef SUPPORT_AP_BWCTRL
22030 wl_update_apchan_bwcap(cfg, ndev, chanspec);
22031 #endif /* SUPPORT_AP_BWCTRL */
22032
22033 if (cfg->ap_oper_channel && (cfg->ap_oper_channel != channel)) {
22034 /*
22035 * If cached channel is different from the channel indicated
22036 * by the event, notify user space about the channel switch.
22037 */
22038 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22039 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
22040 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
22041 cfg->ap_oper_channel = channel;
22042 }
22043 }
22044
wl_ap_start_ind(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)22045 static s32 wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
22046 const wl_event_msg_t *e, void *data)
22047 {
22048 struct net_device *ndev = NULL;
22049 chanspec_t chanspec;
22050
22051 WL_DBG(("Enter\n"));
22052 if (unlikely(e->status)) {
22053 WL_ERR(("status:0x%x \n", e->status));
22054 return -1;
22055 }
22056
22057 if (!data) {
22058 return -EINVAL;
22059 }
22060
22061 if (likely(cfgdev)) {
22062 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22063 chanspec = *((chanspec_t *)data);
22064
22065 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
22066 /* For AP/GO role */
22067 wl_ap_channel_ind(cfg, ndev, chanspec);
22068 }
22069 }
22070
22071 return 0;
22072 }
22073
wl_csa_complete_ind(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)22074 static s32 wl_csa_complete_ind(struct bcm_cfg80211 *cfg,
22075 bcm_struct_cfgdev *cfgdev,
22076 const wl_event_msg_t *e, void *data)
22077 {
22078 int error = 0;
22079 u32 chanspec = 0;
22080 struct net_device *ndev = NULL;
22081 struct ether_addr bssid;
22082
22083 WL_DBG(("Enter\n"));
22084 if (unlikely(e->status)) {
22085 WL_ERR(("status:0x%x \n", e->status));
22086 return -1;
22087 }
22088
22089 if (likely(cfgdev)) {
22090 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22091 /* Get association state if not AP and then query chanspec */
22092 if (!((wl_get_mode_by_netdev(cfg, ndev)) == WL_MODE_AP)) {
22093 error =
22094 wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
22095 if (error) {
22096 WL_ERR(("CSA on %s. Not associated. error=%d\n", ndev->name,
22097 error));
22098 return BCME_ERROR;
22099 }
22100 }
22101
22102 error = wldev_iovar_getint(ndev, "chanspec", &chanspec);
22103 if (unlikely(error)) {
22104 WL_ERR(("Get chanspec error: %d \n", error));
22105 return -1;
22106 }
22107
22108 WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev->name, chanspec));
22109 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
22110 /* For AP/GO role */
22111 wl_ap_channel_ind(cfg, ndev, chanspec);
22112 } else {
22113 /* STA/GC roles */
22114 if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
22115 WL_ERR(("CSA on %s. Not associated.\n", ndev->name));
22116 return BCME_ERROR;
22117 }
22118 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
22119 wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
22120 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
22121 }
22122 }
22123
22124 return 0;
22125 }
22126
wl_cfg80211_clear_security(struct bcm_cfg80211 * cfg)22127 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
22128 {
22129 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
22130 int err;
22131
22132 /* Clear the security settings on the primary Interface */
22133 err = wldev_iovar_setint(dev, "wsec", 0);
22134 if (unlikely(err)) {
22135 WL_ERR(("wsec clear failed \n"));
22136 }
22137 err = wldev_iovar_setint(dev, "auth", 0);
22138 if (unlikely(err)) {
22139 WL_ERR(("auth clear failed \n"));
22140 }
22141 err = wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
22142 if (unlikely(err)) {
22143 WL_ERR(("wpa_auth clear failed \n"));
22144 }
22145 }
22146
22147 #ifdef WL_CFG80211_P2P_DEV_IF
wl_cfg80211_del_p2p_wdev(struct net_device * dev)22148 void wl_cfg80211_del_p2p_wdev(struct net_device *dev)
22149 {
22150 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22151 struct wireless_dev *wdev = NULL;
22152
22153 WL_DBG(("Enter \n"));
22154 if (!cfg) {
22155 WL_ERR(("Invalid Ptr\n"));
22156 return;
22157 } else {
22158 wdev = cfg->p2p_wdev;
22159 }
22160
22161 if (wdev) {
22162 wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
22163 }
22164 }
22165 #endif /* WL_CFG80211_P2P_DEV_IF */
22166
22167 #ifdef GTK_OFFLOAD_SUPPORT
22168 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
wl_cfg80211_set_rekey_data(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_gtk_rekey_data * data)22169 static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy,
22170 struct net_device *dev,
22171 struct cfg80211_gtk_rekey_data *data)
22172 {
22173 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
22174 s32 err = 0;
22175 gtk_keyinfo_t keyinfo;
22176 bcol_gtk_para_t bcol_keyinfo;
22177 dhd_pub_t *dhd = cfg->pub;
22178
22179 WL_DBG(("Enter\n"));
22180 if (data == NULL || cfg->p2p_net == dev) {
22181 WL_ERR(("data is NULL or wrong net device\n"));
22182 return -EINVAL;
22183 }
22184
22185 if (!dhd->conf->rekey_offload) {
22186 WL_TRACE(("rekey_offload disabled\n"));
22187 return BCME_UNSUPPORTED;
22188 }
22189
22190 memset(&bcol_keyinfo, 0, sizeof(bcol_keyinfo));
22191 bcol_keyinfo.enable = 1;
22192 bcol_keyinfo.ptk_len = 0x40;
22193 memcpy(&bcol_keyinfo.ptk[0], data->kck, RSN_KCK_LENGTH);
22194 memcpy(&bcol_keyinfo.ptk[RSN_KCK_LENGTH], data->kek, RSN_KEK_LENGTH);
22195 err = wldev_iovar_setbuf(dev, "bcol_gtk_rekey_ptk", &bcol_keyinfo,
22196 sizeof(bcol_keyinfo), cfg->ioctl_buf,
22197 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
22198 if (!err) {
22199 goto exit;
22200 }
22201
22202 bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH);
22203 bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH);
22204 bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN);
22205 if ((err = wldev_iovar_setbuf(dev, "gtk_key_info", &keyinfo,
22206 sizeof(keyinfo), cfg->ioctl_buf,
22207 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync)) < 0) {
22208 return err;
22209 }
22210
22211 exit:
22212 prhex("kck", (const u8 *)(data->kck), RSN_KCK_LENGTH);
22213 prhex("kek", (const u8 *)(data->kek), RSN_KEK_LENGTH);
22214 prhex("replay_ctr", (const u8 *)(data->replay_ctr), RSN_REPLAY_LEN);
22215 WL_DBG(("Exit\n"));
22216 return err;
22217 }
22218 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
22219 #endif /* GTK_OFFLOAD_SUPPORT */
22220
22221 #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)22222 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
22223 const struct cfg80211_pmk_conf *conf)
22224 {
22225 int ret = 0;
22226 wsec_pmk_t pmk;
22227 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
22228 struct wl_security *sec;
22229 s32 bssidx;
22230
22231 pmk.key_len = conf->pmk_len;
22232 if (pmk.key_len > sizeof(pmk.key)) {
22233 ret = -EINVAL;
22234 return ret;
22235 }
22236 pmk.flags = 0;
22237 ret = memcpy_s(&pmk.key, sizeof(pmk.key), conf->pmk, conf->pmk_len);
22238 if (ret) {
22239 ret = -EINVAL;
22240 return ret;
22241 }
22242
22243 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
22244 WL_ERR(("Find index failed\n"));
22245 ret = -EINVAL;
22246 return ret;
22247 }
22248
22249 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
22250 if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
22251 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
22252 ret = wldev_iovar_setbuf_bsscfg(
22253 dev, "okc_info_pmk", pmk.key, pmk.key_len, cfg->ioctl_buf,
22254 WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
22255 if (ret) {
22256 /* could fail in case that 'okc' is not supported */
22257 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
22258 }
22259 }
22260
22261 ret = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
22262 if (ret) {
22263 WL_ERR(("wl_cfg80211_set_pmk error:%d", ret));
22264 ret = -EINVAL;
22265 return ret;
22266 }
22267 return 0;
22268 }
22269
wl_cfg80211_del_pmk(struct wiphy * wiphy,struct net_device * dev,const u8 * aa)22270 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
22271 const u8 *aa)
22272 {
22273 int err = BCME_OK;
22274 struct cfg80211_pmksa pmksa;
22275
22276 /* build up cfg80211_pmksa structure to use existing
22277 * wl_cfg80211_update_pmksa API */
22278 bzero(&pmksa, sizeof(pmksa));
22279 pmksa.bssid = aa;
22280
22281 err = wl_cfg80211_update_pmksa(wiphy, dev, &pmksa, FALSE);
22282 if (err) {
22283 WL_ERR(("wl_cfg80211_update_pmksa err:%d\n", err));
22284 err = -EINVAL;
22285 }
22286
22287 return err;
22288 }
22289 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
22290
22291 #if defined(WL_SUPPORT_AUTO_CHANNEL)
wl_cfg80211_set_spect(struct net_device * dev,int spect)22292 int wl_cfg80211_set_spect(struct net_device *dev, int spect)
22293 {
22294 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22295 int wlc_down = 1;
22296 int wlc_up = 1;
22297 int err = BCME_OK;
22298
22299 if (!wl_get_drv_status_all(cfg, CONNECTED)) {
22300 err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
22301 if (err) {
22302 WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
22303 return err;
22304 }
22305
22306 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect,
22307 sizeof(spect));
22308 if (err) {
22309 WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
22310 return err;
22311 }
22312
22313 err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
22314 if (err) {
22315 WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
22316 return err;
22317 }
22318 }
22319 return err;
22320 }
22321
wl_cfg80211_get_sta_channel(struct bcm_cfg80211 * cfg)22322 int wl_cfg80211_get_sta_channel(struct bcm_cfg80211 *cfg)
22323 {
22324 int channel = 0;
22325
22326 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
22327 channel = cfg->channel;
22328 }
22329 return channel;
22330 }
22331 #endif /* WL_SUPPORT_AUTO_CHANNEL */
22332
wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 * cfg)22333 u64 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
22334 {
22335 u64 id = 0;
22336 id = ++cfg->last_roc_id;
22337 #ifdef P2P_LISTEN_OFFLOADING
22338 if (id == P2PO_COOKIE) {
22339 id = ++cfg->last_roc_id;
22340 }
22341 #endif /* P2P_LISTEN_OFFLOADING */
22342 if (id == 0) {
22343 id = ++cfg->last_roc_id;
22344 }
22345 return id;
22346 }
22347
22348 #ifdef WLTDLS
wl_cfg80211_tdls_config(struct bcm_cfg80211 * cfg,enum wl_tdls_config state,bool auto_mode)22349 s32 wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg, enum wl_tdls_config state,
22350 bool auto_mode)
22351 {
22352 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
22353 int err = 0;
22354 struct net_info *iter, *next;
22355 int update_reqd = 0;
22356 int enable = 0;
22357 dhd_pub_t *dhdp;
22358 dhdp = (dhd_pub_t *)(cfg->pub);
22359
22360 /*
22361 * TDLS need to be enabled only if we have a single STA/GC
22362 * connection.
22363 */
22364
22365 WL_DBG(("Enter state:%d\n", state));
22366 if (!cfg->tdls_supported) {
22367 /* FW doesn't support tdls. Do nothing */
22368 return -ENODEV;
22369 }
22370
22371 /* Protect tdls config session */
22372 mutex_lock(&cfg->tdls_sync);
22373
22374 if (state == TDLS_STATE_TEARDOWN) {
22375 /* Host initiated TDLS tear down */
22376 err = dhd_tdls_enable(ndev, false, auto_mode, NULL);
22377 goto exit;
22378 } else if ((state == TDLS_STATE_AP_CREATE) ||
22379 (state == TDLS_STATE_NMI_CREATE)) {
22380 /* We don't support tdls while AP/GO/NAN is operational */
22381 update_reqd = true;
22382 enable = false;
22383 } else if ((state == TDLS_STATE_CONNECT) ||
22384 (state == TDLS_STATE_IF_CREATE)) {
22385 if (wl_get_drv_status_all(cfg, CONNECTED) >=
22386 TDLS_MAX_IFACE_FOR_ENABLE) {
22387 /* For STA/GC connect command request, disable
22388 * tdls if we have any concurrent interfaces
22389 * operational.
22390 */
22391 WL_DBG(("Interface limit restriction. disable tdls.\n"));
22392 update_reqd = true;
22393 enable = false;
22394 }
22395 } else if ((state == TDLS_STATE_DISCONNECT) ||
22396 (state == TDLS_STATE_AP_DELETE) || (state == TDLS_STATE_SETUP) ||
22397 (state == TDLS_STATE_IF_DELETE)) {
22398 /* Enable back the tdls connection only if we have less than
22399 * or equal to a single STA/GC connection.
22400 */
22401 if (wl_get_drv_status_all(cfg, CONNECTED) == 0) {
22402 /* If there are no interfaces connected, enable tdls */
22403 update_reqd = true;
22404 enable = true;
22405 } else if (wl_get_drv_status_all(cfg, CONNECTED) ==
22406 TDLS_MAX_IFACE_FOR_ENABLE) {
22407 /* We have one interface in CONNECTED state.
22408 * Verify whether its a STA interface before
22409 * we enable back tdls.
22410 */
22411 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22412 for_each_ndev(cfg, iter, next)
22413 {
22414 GCC_DIAGNOSTIC_POP();
22415 if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, ndev)) &&
22416 (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)) {
22417 WL_DBG(("Non STA iface operational. cfg_iftype:%d"
22418 " Can't enable tdls.\n",
22419 ndev->ieee80211_ptr->iftype));
22420 err = -ENOTSUPP;
22421 goto exit;
22422 }
22423 }
22424 /* No AP/GO found. Enable back tdls */
22425 update_reqd = true;
22426 enable = true;
22427 } else {
22428 WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
22429 err = -ENOTSUPP;
22430 goto exit;
22431 }
22432 } else {
22433 WL_ERR(("Unknown tdls state:%d \n", state));
22434 err = -EINVAL;
22435 goto exit;
22436 }
22437
22438 if (update_reqd == true) {
22439 if (dhdp->tdls_enable == enable) {
22440 WL_DBG(("No change in tdls state. Do nothing."
22441 " tdls_enable:%d\n",
22442 enable));
22443 goto exit;
22444 }
22445 err = wldev_iovar_setint(ndev, "tdls_enable", enable);
22446 if (unlikely(err)) {
22447 WL_ERR(("tdls_enable setting failed. err:%d\n", err));
22448 goto exit;
22449 } else {
22450 WL_INFORM_MEM(("tdls_enable %d state:%d\n", enable, state));
22451 /* Update the dhd state variable to be in sync */
22452 dhdp->tdls_enable = enable;
22453 if (state == TDLS_STATE_SETUP) {
22454 /* For host initiated setup, apply TDLS params
22455 * Don't propagate errors up for param config
22456 * failures
22457 */
22458 dhd_tdls_enable(ndev, true, auto_mode, NULL);
22459 }
22460 }
22461 } else {
22462 WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
22463 "current_status:%d \n",
22464 state, update_reqd, dhdp->tdls_enable));
22465 }
22466
22467 exit:
22468 if (err) {
22469 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
22470 }
22471 mutex_unlock(&cfg->tdls_sync);
22472 return err;
22473 }
22474 #endif /* WLTDLS */
22475
wl_get_ap_netdev(struct bcm_cfg80211 * cfg,char * ifname)22476 struct net_device *wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname)
22477 {
22478 struct net_info *iter, *next;
22479 struct net_device *ndev = NULL;
22480
22481 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22482 for_each_ndev(cfg, iter, next)
22483 {
22484 GCC_DIAGNOSTIC_POP();
22485 if (iter->ndev) {
22486 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
22487 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
22488 ndev = iter->ndev;
22489 break;
22490 }
22491 }
22492 }
22493 }
22494
22495 return ndev;
22496 }
22497
wl_get_netdev_by_name(struct bcm_cfg80211 * cfg,char * ifname)22498 struct net_device *wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname)
22499 {
22500 struct net_info *iter, *next;
22501 struct net_device *ndev = NULL;
22502
22503 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22504 for_each_ndev(cfg, iter, next)
22505 {
22506 GCC_DIAGNOSTIC_POP();
22507 if (iter->ndev) {
22508 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
22509 ndev = iter->ndev;
22510 break;
22511 }
22512 }
22513 }
22514
22515 return ndev;
22516 }
22517
22518 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
22519 #define WLC_RATE_FLAG 0x80
22520 #define RATE_MASK 0x7f
22521
wl_set_ap_beacon_rate(struct net_device * dev,int val,char * ifname)22522 int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname)
22523 {
22524 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22525 dhd_pub_t *dhdp;
22526 wl_rateset_args_t rs;
22527 int error = BCME_ERROR, i;
22528 struct net_device *ndev = NULL;
22529
22530 dhdp = (dhd_pub_t *)(cfg->pub);
22531
22532 if (dhdp && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22533 WL_ERR(("Not Hostapd mode\n"));
22534 return BCME_NOTAP;
22535 }
22536
22537 ndev = wl_get_ap_netdev(cfg, ifname);
22538 if (ndev == NULL) {
22539 WL_ERR(("No softAP interface named %s\n", ifname));
22540 return BCME_NOTAP;
22541 }
22542
22543 bzero(&rs, sizeof(wl_rateset_args_t));
22544 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0, &rs,
22545 sizeof(wl_rateset_args_t), NULL);
22546 if (error < 0) {
22547 WL_ERR(("get rateset failed = %d\n", error));
22548 return error;
22549 }
22550
22551 if (rs.count < 1) {
22552 WL_ERR(("Failed to get rate count\n"));
22553 return BCME_ERROR;
22554 }
22555
22556 /* Host delivers target rate in the unit of 500kbps */
22557 /* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic
22558 * rate */
22559 for (i = 0; i < rs.count && i < WL_NUMRATES; i++) {
22560 if (rs.rates[i] & WLC_RATE_FLAG) {
22561 if ((rs.rates[i] & RATE_MASK) == val) {
22562 break;
22563 }
22564 }
22565 }
22566
22567 /* Valid rate has been delivered as an argument */
22568 if (i < rs.count && i < WL_NUMRATES) {
22569 error = wldev_iovar_setint(ndev, "force_bcn_rspec", val);
22570 if (error < 0) {
22571 WL_ERR(("set beacon rate failed = %d\n", error));
22572 return BCME_ERROR;
22573 }
22574 } else {
22575 WL_ERR(("Rate is invalid"));
22576 return BCME_BADARG;
22577 }
22578
22579 return BCME_OK;
22580 }
22581
wl_get_ap_basic_rate(struct net_device * dev,char * command,char * ifname,int total_len)22582 int wl_get_ap_basic_rate(struct net_device *dev, char *command, char *ifname,
22583 int total_len)
22584 {
22585 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22586 dhd_pub_t *dhdp;
22587 wl_rateset_args_t rs;
22588 int error = BCME_ERROR;
22589 int i, bytes_written = 0;
22590 struct net_device *ndev = NULL;
22591
22592 dhdp = (dhd_pub_t *)(cfg->pub);
22593
22594 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22595 WL_ERR(("Not Hostapd mode\n"));
22596 return BCME_NOTAP;
22597 }
22598
22599 ndev = wl_get_ap_netdev(cfg, ifname);
22600 if (ndev == NULL) {
22601 WL_ERR(("No softAP interface named %s\n", ifname));
22602 return BCME_NOTAP;
22603 }
22604
22605 bzero(&rs, sizeof(wl_rateset_args_t));
22606 error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0, &rs,
22607 sizeof(wl_rateset_args_t), NULL);
22608 if (error < 0) {
22609 WL_ERR(("get rateset failed = %d\n", error));
22610 return error;
22611 }
22612
22613 if (rs.count < 1) {
22614 WL_ERR(("Failed to get rate count\n"));
22615 return BCME_ERROR;
22616 }
22617
22618 /* Delivers basic rate in the unit of 500kbps to host */
22619 for (i = 0; i < rs.count && i < WL_NUMRATES; i++) {
22620 if (rs.rates[i] & WLC_RATE_FLAG) {
22621 bytes_written += snprintf(command + bytes_written, total_len, "%d ",
22622 rs.rates[i] & RATE_MASK);
22623 }
22624 }
22625
22626 /* Remove last space in the command buffer */
22627 if (bytes_written && (bytes_written < total_len)) {
22628 command[bytes_written - 1] = '\0';
22629 bytes_written--;
22630 }
22631
22632 return bytes_written;
22633 }
22634 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
22635
22636 #ifdef SUPPORT_AP_RADIO_PWRSAVE
22637 #define MSEC_PER_MIN (60000L)
22638
_wl_update_ap_rps_params(struct net_device * dev)22639 static int _wl_update_ap_rps_params(struct net_device *dev)
22640 {
22641 struct bcm_cfg80211 *cfg = NULL;
22642 rpsnoa_iovar_params_t iovar;
22643 u8 smbuf[WLC_IOCTL_SMLEN];
22644
22645 if (!dev) {
22646 return BCME_BADARG;
22647 }
22648
22649 cfg = wl_get_cfg(dev);
22650
22651 bzero(&iovar, sizeof(iovar));
22652 bzero(smbuf, sizeof(smbuf));
22653
22654 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
22655 iovar.hdr.subcmd = WL_RPSNOA_CMD_PARAMS;
22656 iovar.hdr.len = sizeof(iovar);
22657 iovar.param->band = WLC_BAND_ALL;
22658 iovar.param->level = cfg->ap_rps_info.level;
22659 iovar.param->stas_assoc_check = cfg->ap_rps_info.sta_assoc_check;
22660 iovar.param->pps = cfg->ap_rps_info.pps;
22661 iovar.param->quiet_time = cfg->ap_rps_info.quiet_time;
22662
22663 if (wldev_iovar_setbuf(dev, "rpsnoa", &iovar, sizeof(iovar), smbuf,
22664 sizeof(smbuf), NULL)) {
22665 WL_ERR(("Failed to set rpsnoa params"));
22666 return BCME_ERROR;
22667 }
22668
22669 return BCME_OK;
22670 }
22671
wl_get_ap_rps(struct net_device * dev,char * command,char * ifname,int total_len)22672 int wl_get_ap_rps(struct net_device *dev, char *command, char *ifname,
22673 int total_len)
22674 {
22675 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22676 dhd_pub_t *dhdp;
22677 int error = BCME_ERROR;
22678 int bytes_written = 0;
22679 struct net_device *ndev = NULL;
22680 rpsnoa_iovar_status_t iovar;
22681 u8 smbuf[WLC_IOCTL_SMLEN];
22682 u32 chanspec = 0;
22683 u8 idx = 0;
22684 u16 state;
22685 u32 sleep;
22686 u32 time_since_enable;
22687
22688 dhdp = (dhd_pub_t *)(cfg->pub);
22689
22690 if (!dhdp) {
22691 error = BCME_NOTUP;
22692 goto fail;
22693 }
22694
22695 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22696 WL_ERR(("Not Hostapd mode\n"));
22697 error = BCME_NOTAP;
22698 goto fail;
22699 }
22700
22701 ndev = wl_get_ap_netdev(cfg, ifname);
22702 if (ndev == NULL) {
22703 WL_ERR(("No softAP interface named %s\n", ifname));
22704 error = BCME_NOTAP;
22705 goto fail;
22706 }
22707
22708 bzero(&iovar, sizeof(iovar));
22709 bzero(smbuf, sizeof(smbuf));
22710
22711 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
22712 iovar.hdr.subcmd = WL_RPSNOA_CMD_STATUS;
22713 iovar.hdr.len = sizeof(iovar);
22714 iovar.stats->band = WLC_BAND_ALL;
22715
22716 error = wldev_iovar_getbuf(ndev, "rpsnoa", &iovar, sizeof(iovar), smbuf,
22717 sizeof(smbuf), NULL);
22718 if (error < 0) {
22719 WL_ERR(("get ap radio pwrsave failed = %d\n", error));
22720 goto fail;
22721 }
22722
22723 /* RSDB event doesn't seem to be handled correctly.
22724 * So check chanspec of AP directly from the firmware
22725 */
22726 error = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
22727 if (error < 0) {
22728 WL_ERR(("get chanspec from AP failed = %d\n", error));
22729 goto fail;
22730 }
22731
22732 chanspec = wl_chspec_driver_to_host(chanspec);
22733 if (CHSPEC_IS2G(chanspec)) {
22734 idx = 0;
22735 } else if (CHSPEC_IS5G(chanspec)) {
22736 idx = 1;
22737 } else {
22738 error = BCME_BADCHAN;
22739 goto fail;
22740 }
22741
22742 state = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].state;
22743 sleep = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_dur;
22744 time_since_enable =
22745 ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_avail_dur;
22746
22747 /* Conver ms to minute, round down only */
22748 sleep = DIV_U64_BY_U32(sleep, MSEC_PER_MIN);
22749 time_since_enable = DIV_U64_BY_U32(time_since_enable, MSEC_PER_MIN);
22750
22751 bytes_written += snprintf(command + bytes_written, total_len,
22752 "state=%d sleep=%d time_since_enable=%d", state,
22753 sleep, time_since_enable);
22754 error = bytes_written;
22755
22756 fail:
22757 return error;
22758 }
22759
wl_set_ap_rps(struct net_device * dev,bool enable,char * ifname)22760 int wl_set_ap_rps(struct net_device *dev, bool enable, char *ifname)
22761 {
22762 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22763 dhd_pub_t *dhdp;
22764 struct net_device *ndev = NULL;
22765 rpsnoa_iovar_t iovar;
22766 u8 smbuf[WLC_IOCTL_SMLEN];
22767 int ret = BCME_OK;
22768
22769 dhdp = (dhd_pub_t *)(cfg->pub);
22770
22771 if (!dhdp) {
22772 ret = BCME_NOTUP;
22773 goto exit;
22774 }
22775
22776 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22777 WL_ERR(("Not Hostapd mode\n"));
22778 ret = BCME_NOTAP;
22779 goto exit;
22780 }
22781
22782 ndev = wl_get_ap_netdev(cfg, ifname);
22783 if (ndev == NULL) {
22784 WL_ERR(("No softAP interface named %s\n", ifname));
22785 ret = BCME_NOTAP;
22786 goto exit;
22787 }
22788 if (cfg->ap_rps_info.enable != enable) {
22789 cfg->ap_rps_info.enable = enable;
22790 if (enable) {
22791 ret = _wl_update_ap_rps_params(ndev);
22792 if (ret) {
22793 WL_ERR(("Filed to update rpsnoa params\n"));
22794 goto exit;
22795 }
22796 }
22797 bzero(&iovar, sizeof(iovar));
22798 bzero(smbuf, sizeof(smbuf));
22799
22800 iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
22801 iovar.hdr.subcmd = WL_RPSNOA_CMD_ENABLE;
22802 iovar.hdr.len = sizeof(iovar);
22803 iovar.data->band = WLC_BAND_ALL;
22804 iovar.data->value = (int16)enable;
22805
22806 ret = wldev_iovar_setbuf(ndev, "rpsnoa", &iovar, sizeof(iovar), smbuf,
22807 sizeof(smbuf), NULL);
22808 if (ret) {
22809 WL_ERR(("Failed to enable AP radio power save"));
22810 goto exit;
22811 }
22812 cfg->ap_rps_info.enable = enable;
22813 }
22814 exit:
22815 return ret;
22816 }
22817
wl_update_ap_rps_params(struct net_device * dev,ap_rps_info_t * rps,char * ifname)22818 int wl_update_ap_rps_params(struct net_device *dev, ap_rps_info_t *rps,
22819 char *ifname)
22820 {
22821 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22822 dhd_pub_t *dhdp;
22823 struct net_device *ndev = NULL;
22824
22825 dhdp = (dhd_pub_t *)(cfg->pub);
22826
22827 if (!dhdp) {
22828 return BCME_NOTUP;
22829 }
22830
22831 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
22832 WL_ERR(("Not Hostapd mode\n"));
22833 return BCME_NOTAP;
22834 }
22835
22836 ndev = wl_get_ap_netdev(cfg, ifname);
22837 if (ndev == NULL) {
22838 WL_ERR(("No softAP interface named %s\n", ifname));
22839 return BCME_NOTAP;
22840 }
22841 if (!rps) {
22842 return BCME_BADARG;
22843 }
22844
22845 if (rps->pps < RADIO_PWRSAVE_PPS_MIN) {
22846 return BCME_BADARG;
22847 }
22848
22849 if (rps->level < RADIO_PWRSAVE_LEVEL_MIN ||
22850 rps->level > RADIO_PWRSAVE_LEVEL_MAX) {
22851 return BCME_BADARG;
22852 }
22853
22854 if (rps->quiet_time < RADIO_PWRSAVE_QUIETTIME_MIN) {
22855 return BCME_BADARG;
22856 }
22857
22858 if (rps->sta_assoc_check > RADIO_PWRSAVE_ASSOCCHECK_MAX ||
22859 rps->sta_assoc_check < RADIO_PWRSAVE_ASSOCCHECK_MIN) {
22860 return BCME_BADARG;
22861 }
22862
22863 cfg->ap_rps_info.pps = rps->pps;
22864 cfg->ap_rps_info.level = rps->level;
22865 cfg->ap_rps_info.quiet_time = rps->quiet_time;
22866 cfg->ap_rps_info.sta_assoc_check = rps->sta_assoc_check;
22867
22868 if (cfg->ap_rps_info.enable) {
22869 if (_wl_update_ap_rps_params(ndev)) {
22870 WL_ERR(("Failed to update rpsnoa params"));
22871 return BCME_ERROR;
22872 }
22873 }
22874
22875 return BCME_OK;
22876 }
22877
wl_cfg80211_init_ap_rps(struct bcm_cfg80211 * cfg)22878 void wl_cfg80211_init_ap_rps(struct bcm_cfg80211 *cfg)
22879 {
22880 cfg->ap_rps_info.enable = FALSE;
22881 cfg->ap_rps_info.sta_assoc_check = RADIO_PWRSAVE_STAS_ASSOC_CHECK;
22882 cfg->ap_rps_info.pps = RADIO_PWRSAVE_PPS;
22883 cfg->ap_rps_info.quiet_time = RADIO_PWRSAVE_QUIET_TIME;
22884 cfg->ap_rps_info.level = RADIO_PWRSAVE_LEVEL;
22885 }
22886 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
22887
wl_cfg80211_iface_count(struct net_device * dev)22888 int wl_cfg80211_iface_count(struct net_device *dev)
22889 {
22890 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22891 struct net_info *iter, *next;
22892 int iface_count = 0;
22893
22894 /* Return the count of network interfaces (skip netless p2p discovery
22895 * interface)
22896 */
22897 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22898 for_each_ndev(cfg, iter, next)
22899 {
22900 GCC_DIAGNOSTIC_POP();
22901 if (iter->ndev) {
22902 iface_count++;
22903 }
22904 }
22905 return iface_count;
22906 }
22907
22908 #ifdef SUPPORT_SET_CAC
wl_cfg80211_set_cac(struct bcm_cfg80211 * cfg,int enable)22909 static void wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable)
22910 {
22911 int ret = 0;
22912 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22913
22914 WL_DBG(("cac enable %d\n", enable));
22915 if (!dhd) {
22916 WL_ERR(("dhd is NULL\n"));
22917 return;
22918 }
22919 if ((ret = dhd_wl_ioctl_set_intiovar(dhd, "cac", enable, WLC_SET_VAR, TRUE,
22920 0)) < 0) {
22921 WL_ERR(("Failed set CAC, ret=%d\n", ret));
22922 } else {
22923 WL_DBG(("CAC set successfully\n"));
22924 }
22925 return;
22926 }
22927 #endif /* SUPPORT_SET_CAC */
22928
22929 #ifdef SUPPORT_RSSI_SUM_REPORT
wl_get_rssi_per_ant(struct net_device * dev,char * ifname,char * peer_mac,void * param)22930 int wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac,
22931 void *param)
22932 {
22933 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22934 wl_rssi_ant_mimo_t *get_param = (wl_rssi_ant_mimo_t *)param;
22935 rssi_ant_param_t *set_param = NULL;
22936 struct net_device *ifdev = NULL;
22937 char iobuf[WLC_IOCTL_SMLEN];
22938 int err = BCME_OK;
22939 int iftype = 0;
22940
22941 bzero(iobuf, WLC_IOCTL_SMLEN);
22942
22943 /* Check the interface type */
22944 ifdev = wl_get_netdev_by_name(cfg, ifname);
22945 if (ifdev == NULL) {
22946 WL_ERR(("Could not find net_device for ifname:%s\n", ifname));
22947 err = BCME_BADARG;
22948 goto fail;
22949 }
22950
22951 iftype = ifdev->ieee80211_ptr->iftype;
22952 if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO) {
22953 if (peer_mac) {
22954 set_param =
22955 (rssi_ant_param_t *)MALLOCZ(cfg->osh, sizeof(rssi_ant_param_t));
22956 err = wl_cfg80211_ether_atoe(peer_mac, &set_param->ea);
22957 if (!err) {
22958 WL_ERR(("Invalid Peer MAC format\n"));
22959 err = BCME_BADARG;
22960 goto fail;
22961 }
22962 } else {
22963 WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype));
22964 err = BCME_BADARG;
22965 goto fail;
22966 }
22967 }
22968
22969 err = wldev_iovar_getbuf(
22970 ifdev, "phy_rssi_ant", peer_mac ? (void *)&(set_param->ea) : NULL,
22971 peer_mac ? ETHER_ADDR_LEN : 0, (void *)iobuf, sizeof(iobuf), NULL);
22972 if (unlikely(err)) {
22973 WL_ERR(("Failed to get rssi info, err=%d\n", err));
22974 } else {
22975 memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t));
22976 if (get_param->count == 0) {
22977 WL_ERR(("Not supported on this chip\n"));
22978 err = BCME_UNSUPPORTED;
22979 }
22980 }
22981
22982 fail:
22983 if (set_param) {
22984 MFREE(cfg->osh, set_param, sizeof(rssi_ant_param_t));
22985 }
22986
22987 return err;
22988 }
22989
wl_get_rssi_logging(struct net_device * dev,void * param)22990 int wl_get_rssi_logging(struct net_device *dev, void *param)
22991 {
22992 rssilog_get_param_t *get_param = (rssilog_get_param_t *)param;
22993 char iobuf[WLC_IOCTL_SMLEN];
22994 int err = BCME_OK;
22995
22996 bzero(iobuf, WLC_IOCTL_SMLEN);
22997 bzero(get_param, sizeof(*get_param));
22998 err = wldev_iovar_getbuf(dev, "rssilog", NULL, 0, (void *)iobuf,
22999 sizeof(iobuf), NULL);
23000 if (err) {
23001 WL_ERR(("Failed to get rssi logging info, err=%d\n", err));
23002 } else {
23003 memcpy(get_param, iobuf, sizeof(*get_param));
23004 }
23005
23006 return err;
23007 }
23008
wl_set_rssi_logging(struct net_device * dev,void * param)23009 int wl_set_rssi_logging(struct net_device *dev, void *param)
23010 {
23011 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23012 rssilog_set_param_t *set_param = (rssilog_set_param_t *)param;
23013 int err;
23014
23015 err = wldev_iovar_setbuf(dev, "rssilog", set_param, sizeof(*set_param),
23016 cfg->ioctl_buf, WLC_IOCTL_SMLEN,
23017 &cfg->ioctl_buf_sync);
23018 if (err) {
23019 WL_ERR(("Failed to set rssi logging param, err=%d\n", err));
23020 }
23021
23022 return err;
23023 }
23024 #endif /* SUPPORT_RSSI_SUM_REPORT */
23025 /* Function to flush the FW preserve buffer content
23026 * The buffer content is sent to host in form of events.
23027 */
wl_flush_fw_log_buffer(struct net_device * dev,uint32 logset_mask)23028 void wl_flush_fw_log_buffer(struct net_device *dev, uint32 logset_mask)
23029 {
23030 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23031 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
23032 int i;
23033 int err = 0;
23034 u8 buf[WLC_IOCTL_SMLEN] = {0};
23035 wl_el_set_params_t set_param;
23036
23037 /* Set the size of data to retrieve */
23038 memset(&set_param, 0, sizeof(set_param));
23039 set_param.size = WLC_IOCTL_SMLEN;
23040
23041 for (i = 0; i < dhd->event_log_max_sets; i++) {
23042 if ((0x01u << i) & logset_mask) {
23043 set_param.set = i;
23044 err = wldev_iovar_setbuf(dev, "event_log_get", &set_param,
23045 sizeof(struct wl_el_set_params_s), buf,
23046 WLC_IOCTL_SMLEN, NULL);
23047 if (err) {
23048 WL_DBG(("Failed to get fw preserve logs, err=%d\n", err));
23049 }
23050 }
23051 }
23052 }
23053 #ifdef USE_WFA_CERT_CONF
23054 extern int g_frameburst;
23055 #endif /* USE_WFA_CERT_CONF */
23056
wl_cfg80211_set_frameburst(struct bcm_cfg80211 * cfg,bool enable)23057 int wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable)
23058 {
23059 int ret = BCME_OK;
23060 int val = enable ? 1 : 0;
23061
23062 #ifdef USE_WFA_CERT_CONF
23063 if (!g_frameburst) {
23064 WL_DBG(("Skip setting frameburst\n"));
23065 return 0;
23066 }
23067 #endif /* USE_WFA_CERT_CONF */
23068
23069 WL_DBG(("Set frameburst %d\n", val));
23070 ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg), WLC_SET_FAKEFRAG, &val,
23071 sizeof(val));
23072 if (ret < 0) {
23073 WL_ERR(("Failed set frameburst, ret=%d\n", ret));
23074 } else {
23075 WL_INFORM_MEM(("frameburst is %s\n", enable ? "enabled" : "disabled"));
23076 }
23077
23078 return ret;
23079 }
23080
wl_cfg80211_set_dbg_verbose(struct net_device * ndev,u32 level)23081 s32 wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level)
23082 {
23083 /* configure verbose level for debugging */
23084 if (level) {
23085 /* Enable increased verbose */
23086 wl_dbg_level |= WL_DBG_DBG;
23087 } else {
23088 /* Disable */
23089 wl_dbg_level &= ~WL_DBG_DBG;
23090 }
23091 WL_INFORM(("debug verbose set to %d\n", level));
23092
23093 return BCME_OK;
23094 }
23095
wl_find_attribute(const u8 * buf,u16 len,u16 element_id)23096 const u8 *wl_find_attribute(const u8 *buf, u16 len, u16 element_id)
23097 {
23098 const u8 *attrib;
23099 u16 attrib_id;
23100 u16 attrib_len;
23101
23102 if (!buf) {
23103 WL_ERR(("buf null\n"));
23104 return NULL;
23105 }
23106
23107 attrib = buf;
23108 while (len >= 0x4) {
23109 /* attribute id */
23110 attrib_id = *attrib++ << 0x8;
23111 attrib_id |= *attrib++;
23112 len -= 0x2;
23113
23114 /* 2-byte little endian */
23115 attrib_len = *attrib++ << 0x8;
23116 attrib_len |= *attrib++;
23117
23118 len -= 0x2;
23119 if (attrib_id == element_id) {
23120 /* This will point to start of subelement attrib after
23121 * attribute id & len
23122 */
23123 return attrib;
23124 }
23125 if (len > attrib_len) {
23126 len -= attrib_len; /* for the remaining subelt fields */
23127 WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n", attrib_id,
23128 attrib_len, len));
23129
23130 /* Go to next subelement */
23131 attrib += attrib_len;
23132 } else {
23133 WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n", attrib_id,
23134 attrib_len));
23135 return NULL;
23136 }
23137 }
23138 return NULL;
23139 }
23140
wl_cfg80211_get_bus_state(struct bcm_cfg80211 * cfg)23141 uint8 wl_cfg80211_get_bus_state(struct bcm_cfg80211 *cfg)
23142 {
23143 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
23144 WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
23145 dhd->hang_was_sent, dhd->busstate));
23146 return ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent);
23147 }
23148
23149 #ifdef WL_WPS_SYNC
wl_wps_reauth_timeout(unsigned long data)23150 static void wl_wps_reauth_timeout(unsigned long data)
23151 {
23152 struct net_device *ndev = (struct net_device *)data;
23153 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23154 s32 inst;
23155 unsigned long flags;
23156
23157 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23158 inst = wl_get_wps_inst_match(cfg, ndev);
23159 if (inst >= 0) {
23160 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n", ndev->name,
23161 inst, cfg->wps_session[inst].state));
23162 if (cfg->wps_session[inst].state == WPS_STATE_REAUTH_WAIT) {
23163 /* Session should get deleted from success (linkup) or
23164 * deauth case. Just in case, link reassoc failed, clear
23165 * state here.
23166 */
23167 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n", ndev->name, inst));
23168 cfg->wps_session[inst].state = WPS_STATE_IDLE;
23169 cfg->wps_session[inst].in_use = false;
23170 }
23171 }
23172 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23173 }
23174
wl_init_wps_reauth_sm(struct bcm_cfg80211 * cfg)23175 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg)
23176 {
23177 /* Only two instances are supported as of now. one for
23178 * infra STA and other for infra STA/GC.
23179 */
23180 int i = 0;
23181 struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
23182
23183 spin_lock_init(&cfg->wps_sync);
23184 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23185 /* Init scan_timeout timer */
23186 init_timer_compat(&cfg->wps_session[i].timer, wl_wps_reauth_timeout,
23187 pdev);
23188 cfg->wps_session[i].in_use = false;
23189 cfg->wps_session[i].state = WPS_STATE_IDLE;
23190 }
23191 }
23192
wl_deinit_wps_reauth_sm(struct bcm_cfg80211 * cfg)23193 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg)
23194 {
23195 int i = 0;
23196
23197 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23198 cfg->wps_session[i].in_use = false;
23199 cfg->wps_session[i].state = WPS_STATE_IDLE;
23200 if (timer_pending(&cfg->wps_session[i].timer)) {
23201 del_timer_sync(&cfg->wps_session[i].timer);
23202 }
23203 }
23204 }
23205
wl_get_free_wps_inst(struct bcm_cfg80211 * cfg)23206 static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg)
23207 {
23208 int i;
23209
23210 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23211 if (!cfg->wps_session[i].in_use) {
23212 return i;
23213 }
23214 }
23215 return BCME_ERROR;
23216 }
23217
wl_get_wps_inst_match(struct bcm_cfg80211 * cfg,struct net_device * ndev)23218 static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg,
23219 struct net_device *ndev)
23220 {
23221 int i;
23222
23223 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
23224 if ((cfg->wps_session[i].in_use) &&
23225 (ndev == cfg->wps_session[i].ndev)) {
23226 return i;
23227 }
23228 }
23229
23230 return BCME_ERROR;
23231 }
23232
wl_wps_session_add(struct net_device * ndev,u16 mode,u8 * mac_addr)23233 static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *mac_addr)
23234 {
23235 s32 inst;
23236 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23237 unsigned long flags;
23238
23239 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23240 /* Fetch and initialize a wps instance */
23241 inst = wl_get_free_wps_inst(cfg);
23242 if (inst == BCME_ERROR) {
23243 WL_ERR(("[WPS] No free insance\n"));
23244 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23245 return BCME_ERROR;
23246 }
23247 cfg->wps_session[inst].in_use = true;
23248 cfg->wps_session[inst].state = WPS_STATE_STARTED;
23249 cfg->wps_session[inst].ndev = ndev;
23250 cfg->wps_session[inst].mode = mode;
23251 /* return check not required since both buffer lens are same */
23252 (void)memcpy_s(cfg->wps_session[inst].peer_mac, ETH_ALEN, mac_addr,
23253 ETH_ALEN);
23254 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23255
23256 WL_INFORM_MEM(("[%s][WPS] session created. Peer: " MACDBG "\n", ndev->name,
23257 MAC2STRDBG(mac_addr)));
23258 return BCME_OK;
23259 }
23260
wl_wps_session_del(struct net_device * ndev)23261 static void wl_wps_session_del(struct net_device *ndev)
23262 {
23263 s32 inst;
23264 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23265 unsigned long flags;
23266 u16 cur_state;
23267
23268 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23269
23270 /* Get current instance for the given ndev */
23271 inst = wl_get_wps_inst_match(cfg, ndev);
23272 if (inst == BCME_ERROR) {
23273 WL_DBG(("[WPS] instance match NOT found\n"));
23274 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23275 return;
23276 }
23277
23278 cur_state = cfg->wps_session[inst].state;
23279 if (cur_state != WPS_STATE_DONE) {
23280 WL_DBG(("[WPS] wrong state:%d\n", cur_state));
23281 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23282 return;
23283 }
23284
23285 /* Mark this as unused */
23286 cfg->wps_session[inst].in_use = false;
23287 cfg->wps_session[inst].state = WPS_STATE_IDLE;
23288 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23289
23290 /* Ensure this API is called from sleepable context. */
23291 if (timer_pending(&cfg->wps_session[inst].timer)) {
23292 del_timer_sync(&cfg->wps_session[inst].timer);
23293 }
23294
23295 WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev->name));
23296 }
23297
wl_wps_handle_ifdel(struct net_device * ndev)23298 static void wl_wps_handle_ifdel(struct net_device *ndev)
23299 {
23300 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23301 unsigned long flags;
23302 u16 cur_state;
23303 s32 inst;
23304
23305 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23306 inst = wl_get_wps_inst_match(cfg, ndev);
23307 if (inst == BCME_ERROR) {
23308 WL_DBG(("[WPS] instance match NOT found\n"));
23309 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23310 return;
23311 }
23312 cur_state = cfg->wps_session[inst].state;
23313 cfg->wps_session[inst].state = WPS_STATE_DONE;
23314 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23315
23316 WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev->name, cur_state));
23317 if (cur_state > WPS_STATE_IDLE) {
23318 wl_wps_session_del(ndev);
23319 }
23320 }
23321
wl_wps_handle_sta_linkdown(struct net_device * ndev,u16 inst)23322 static s32 wl_wps_handle_sta_linkdown(struct net_device *ndev, u16 inst)
23323 {
23324 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23325 unsigned long flags;
23326 u16 cur_state;
23327 bool wps_done = false;
23328
23329 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23330 cur_state = cfg->wps_session[inst].state;
23331 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23332 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23333 wl_clr_drv_status(cfg, CONNECTED, ndev);
23334 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
23335 WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev->name));
23336 /* Drop the link down event while we are waiting for reauth */
23337 return BCME_UNSUPPORTED;
23338 } else if (cur_state == WPS_STATE_STARTED) {
23339 /* Link down before reaching EAP-FAIL. End WPS session */
23340 cfg->wps_session[inst].state = WPS_STATE_DONE;
23341 wps_done = true;
23342 WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev->name));
23343 } else {
23344 WL_DBG(("[%s][WPS] link down in state:%d\n", ndev->name, cur_state));
23345 }
23346
23347 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23348
23349 if (wps_done) {
23350 wl_wps_session_del(ndev);
23351 }
23352 return BCME_OK;
23353 }
23354
wl_wps_handle_peersta_linkdown(struct net_device * ndev,u16 inst,const u8 * peer_mac)23355 static s32 wl_wps_handle_peersta_linkdown(struct net_device *ndev, u16 inst,
23356 const u8 *peer_mac)
23357 {
23358 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23359 unsigned long flags;
23360 u16 cur_state;
23361 s32 ret = BCME_OK;
23362 bool wps_done = false;
23363
23364 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23365 cur_state = cfg->wps_session[inst].state;
23366
23367 if (!peer_mac) {
23368 WL_ERR(("Invalid arg\n"));
23369 ret = BCME_ERROR;
23370 goto exit;
23371 }
23372
23373 /* AP/GO can have multiple clients. so validate peer_mac addr
23374 * and ensure states are updated only for right peer.
23375 */
23376 if (memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23377 /* Mac addr not matching. Ignore. */
23378 WL_DBG(("[%s][WPS] No active WPS session"
23379 "for the peer:" MACDBG "\n",
23380 ndev->name, MAC2STRDBG(peer_mac)));
23381 ret = BCME_OK;
23382 goto exit;
23383 }
23384 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23385 WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
23386 " Peer: " MACDBG "\n",
23387 ndev->name, MAC2STRDBG(peer_mac)));
23388 #ifdef NOT_YET
23389 /* Link down during REAUTH state is expected. However,
23390 * if this is send up, hostapd statemachine issues a
23391 * deauth down and that may pre-empt WPS reauth state
23392 * at GC.
23393 */
23394 WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore."
23395 " for client:" MACDBG "\n",
23396 ndev->name, MAC2STRDBG(peer_mac)));
23397 ret = BCME_UNSUPPORTED;
23398 #endif // endif
23399 } else if (cur_state == WPS_STATE_STARTED) {
23400 /* Link down before reaching REAUTH_WAIT state. WPS
23401 * session ended.
23402 */
23403 cfg->wps_session[inst].state = WPS_STATE_DONE;
23404 WL_INFORM_MEM(("[%s][WPS] link down after wps start"
23405 " client:" MACDBG "\n",
23406 ndev->name, MAC2STRDBG(peer_mac)));
23407 wps_done = true;
23408 /* since we have freed lock above, return from here */
23409 ret = BCME_OK;
23410 } else {
23411 WL_ERR(("[%s][WPS] Unsupported state:%d", ndev->name, cur_state));
23412 ret = BCME_ERROR;
23413 }
23414 exit:
23415 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23416 if (wps_done) {
23417 wl_wps_session_del(ndev);
23418 }
23419 return ret;
23420 }
23421
wl_wps_handle_sta_linkup(struct net_device * ndev,u16 inst)23422 static s32 wl_wps_handle_sta_linkup(struct net_device *ndev, u16 inst)
23423 {
23424 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23425 unsigned long flags;
23426 u16 cur_state;
23427 s32 ret = BCME_OK;
23428 bool wps_done = false;
23429
23430 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23431 cur_state = cfg->wps_session[inst].state;
23432 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23433 /* WPS session succeeded. del session. */
23434 cfg->wps_session[inst].state = WPS_STATE_DONE;
23435 wps_done = true;
23436 WL_INFORM_MEM(
23437 ("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev->name));
23438 ret = BCME_OK;
23439 } else {
23440 WL_ERR(("[%s][WPS] unexpected link up in state:%d \n", ndev->name,
23441 cur_state));
23442 ret = BCME_ERROR;
23443 }
23444 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23445 if (wps_done) {
23446 wl_wps_session_del(ndev);
23447 }
23448 return ret;
23449 }
23450
wl_wps_handle_peersta_linkup(struct net_device * ndev,u16 inst,const u8 * peer_mac)23451 static s32 wl_wps_handle_peersta_linkup(struct net_device *ndev, u16 inst,
23452 const u8 *peer_mac)
23453 {
23454 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23455 unsigned long flags;
23456 u16 cur_state;
23457 s32 ret = BCME_OK;
23458
23459 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23460 cur_state = cfg->wps_session[inst].state;
23461
23462 /* For AP case, check whether call came for right peer */
23463 if (!peer_mac ||
23464 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23465 WL_ERR(("[WPS] macaddr mismatch\n"));
23466 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23467 /* Mac addr not matching. Ignore. */
23468 return BCME_ERROR;
23469 }
23470
23471 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23472 WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev->name));
23473 ret = BCME_OK;
23474 } else {
23475 WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
23476 ndev->name, cur_state));
23477 ret = BCME_ERROR;
23478 }
23479
23480 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23481
23482 return ret;
23483 }
23484
wl_wps_handle_authorize(struct net_device * ndev,u16 inst,const u8 * peer_mac)23485 static s32 wl_wps_handle_authorize(struct net_device *ndev, u16 inst,
23486 const u8 *peer_mac)
23487 {
23488 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23489 unsigned long flags;
23490 u16 cur_state;
23491 bool wps_done = false;
23492 s32 ret = BCME_OK;
23493
23494 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23495 cur_state = cfg->wps_session[inst].state;
23496
23497 /* For AP case, check whether call came for right peer */
23498 if (!peer_mac ||
23499 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
23500 WL_ERR(("[WPS] macaddr mismatch\n"));
23501 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23502 /* Mac addr not matching. Ignore. */
23503 return BCME_ERROR;
23504 }
23505
23506 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23507 /* WPS session succeeded. del session. */
23508 cfg->wps_session[inst].state = WPS_STATE_DONE;
23509 wps_done = true;
23510 WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev->name));
23511 ret = BCME_OK;
23512 } else {
23513 WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
23514 ndev->name, cur_state));
23515 ret = BCME_ERROR;
23516 }
23517
23518 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23519 if (wps_done) {
23520 wl_wps_session_del(ndev);
23521 }
23522 return ret;
23523 }
23524
wl_wps_handle_reauth(struct net_device * ndev,u16 inst,const u8 * peer_mac)23525 static s32 wl_wps_handle_reauth(struct net_device *ndev, u16 inst,
23526 const u8 *peer_mac)
23527 {
23528 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23529 unsigned long flags;
23530 u16 cur_state;
23531 u16 mode;
23532 s32 ret = BCME_OK;
23533
23534 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23535 cur_state = cfg->wps_session[inst].state;
23536 mode = cfg->wps_session[inst].mode;
23537
23538 if (((mode == WL_MODE_BSS) && (cur_state == WPS_STATE_STARTED)) ||
23539 ((mode == WL_MODE_AP) && (cur_state == WPS_STATE_M8_SENT))) {
23540 /* Move to reauth wait */
23541 cfg->wps_session[inst].state = WPS_STATE_REAUTH_WAIT;
23542 /* Use ndev to find the wps instance which fired the timer */
23543 timer_set_private(&cfg->wps_session[inst].timer, ndev);
23544 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23545 mod_timer(&cfg->wps_session[inst].timer,
23546 jiffies + msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT));
23547 WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG "\n",
23548 ndev->name, mode, MAC2STRDBG(peer_mac)));
23549 return BCME_OK;
23550 } else {
23551 /* 802.1x cases */
23552 WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev->name));
23553 }
23554 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23555 return ret;
23556 }
23557
wl_wps_handle_disconnect(struct net_device * ndev,u16 inst,const u8 * peer_mac)23558 static s32 wl_wps_handle_disconnect(struct net_device *ndev, u16 inst,
23559 const u8 *peer_mac)
23560 {
23561 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23562 unsigned long flags;
23563 u16 cur_state;
23564 s32 ret = BCME_OK;
23565
23566 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23567 cur_state = cfg->wps_session[inst].state;
23568 /* If Disconnect command comes from user space for STA/GC,
23569 * respond with event without waiting for event from fw as
23570 * it would be dropped by the WPS_SYNC code.
23571 */
23572 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23573 if (ETHER_ISBCAST(peer_mac)) {
23574 WL_DBG(("[WPS] Bcast peer. Do nothing.\n"));
23575 } else {
23576 /* Notify link down */
23577 CFG80211_DISCONNECTED(ndev, WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
23578 true, GFP_ATOMIC);
23579 }
23580 } else {
23581 WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
23582 ndev->name, cur_state));
23583 ret = BCME_UNSUPPORTED;
23584 }
23585 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23586 return ret;
23587 }
23588
wl_wps_handle_disconnect_client(struct net_device * ndev,u16 inst,const u8 * peer_mac)23589 static s32 wl_wps_handle_disconnect_client(struct net_device *ndev, u16 inst,
23590 const u8 *peer_mac)
23591 {
23592 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23593 unsigned long flags;
23594 u16 cur_state;
23595 s32 ret = BCME_OK;
23596 bool wps_done = false;
23597
23598 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23599 cur_state = cfg->wps_session[inst].state;
23600 /* For GO/AP, ignore disconnect client during reauth state */
23601 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23602 if (ETHER_ISBCAST(peer_mac)) {
23603 /* If there is broadcast deauth, then mark wps session as ended */
23604 cfg->wps_session[inst].state = WPS_STATE_DONE;
23605 wps_done = true;
23606 WL_INFORM_MEM(
23607 ("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev->name));
23608 ret = BCME_OK;
23609 goto exit;
23610 } else if (!(memcmp(cfg->wps_session[inst].peer_mac, peer_mac,
23611 ETH_ALEN))) {
23612 WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev->name));
23613 ret = BCME_UNSUPPORTED;
23614 }
23615 }
23616
23617 exit:
23618 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23619 if (wps_done) {
23620 wl_wps_session_del(ndev);
23621 }
23622 return ret;
23623 }
23624
wl_wps_handle_connect_fail(struct net_device * ndev,u16 inst)23625 static s32 wl_wps_handle_connect_fail(struct net_device *ndev, u16 inst)
23626 {
23627 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23628 unsigned long flags;
23629 u16 cur_state;
23630 bool wps_done = false;
23631
23632 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23633 cur_state = cfg->wps_session[inst].state;
23634 if (cur_state == WPS_STATE_REAUTH_WAIT) {
23635 cfg->wps_session[inst].state = WPS_STATE_DONE;
23636 wps_done = true;
23637 WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n", ndev->name));
23638 } else {
23639 WL_ERR(("[%s][WPS] Connect fail. state:%d\n", ndev->name, cur_state));
23640 }
23641 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23642 if (wps_done) {
23643 wl_wps_session_del(ndev);
23644 }
23645 return BCME_OK;
23646 }
23647
wl_wps_handle_m8_sent(struct net_device * ndev,u16 inst,const u8 * peer_mac)23648 static s32 wl_wps_handle_m8_sent(struct net_device *ndev, u16 inst,
23649 const u8 *peer_mac)
23650 {
23651 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23652 unsigned long flags;
23653 u16 cur_state;
23654 s32 ret = BCME_OK;
23655
23656 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23657 cur_state = cfg->wps_session[inst].state;
23658
23659 if (cur_state == WPS_STATE_STARTED) {
23660 /* Move to M8 sent state */
23661 cfg->wps_session[inst].state = WPS_STATE_M8_SENT;
23662 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23663 return BCME_OK;
23664 } else {
23665 /* 802.1x cases */
23666 WL_DBG(("[%s][WPS] Not valid state to send M8\n", ndev->name));
23667 }
23668 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23669 return ret;
23670 }
23671
wl_wps_session_update(struct net_device * ndev,u16 state,const u8 * peer_mac)23672 static s32 wl_wps_session_update(struct net_device *ndev, u16 state,
23673 const u8 *peer_mac)
23674 {
23675 s32 inst;
23676 u16 mode;
23677 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
23678 s32 ret = BCME_ERROR;
23679 unsigned long flags;
23680
23681 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
23682 /* Get current instance for the given ndev */
23683 inst = wl_get_wps_inst_match(cfg, ndev);
23684 if (inst == BCME_ERROR) {
23685 /* No active WPS session. Do Nothing. */
23686 WL_DBG(("[%s][WPS] No matching instance.\n", ndev->name));
23687 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23688 return BCME_NOTFOUND;
23689 }
23690 mode = cfg->wps_session[inst].mode;
23691 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
23692
23693 WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG "\n", ndev->name, state,
23694 mode, MAC2STRDBG(peer_mac)));
23695
23696 switch (state) {
23697 case WPS_STATE_M8_RECVD: {
23698 /* Occasionally, due to race condition between ctrl
23699 * and data path, deauth ind is recvd before EAP-FAIL.
23700 * Ignore deauth ind before EAP-FAIL
23701 * So move to REAUTH WAIT on receiving M8 on GC and
23702 * ignore deauth ind before EAP-FAIL till 'x' timeout.
23703 * Kickoff a timer to monitor reauth status.
23704 */
23705 if (mode == WL_MODE_BSS) {
23706 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
23707 } else {
23708 /* Nothing to be done for AP/GO mode */
23709 ret = BCME_OK;
23710 }
23711 break;
23712 }
23713 case WPS_STATE_M8_SENT: {
23714 /* Mantain the M8 sent state to verify
23715 * EAP-FAIL sent is valid
23716 */
23717 if (mode == WL_MODE_AP) {
23718 ret = wl_wps_handle_m8_sent(ndev, inst, peer_mac);
23719 } else {
23720 /* Nothing to be done for STA/GC mode */
23721 ret = BCME_OK;
23722 }
23723 break;
23724 }
23725 case WPS_STATE_EAP_FAIL: {
23726 /* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
23727 * Kickoff a timer to monitor reauth status
23728 */
23729 if (mode == WL_MODE_AP) {
23730 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
23731 } else {
23732 /* Nothing to be done for STA/GC mode */
23733 ret = BCME_OK;
23734 }
23735 break;
23736 }
23737 case WPS_STATE_LINKDOWN: {
23738 if (mode == WL_MODE_BSS) {
23739 ret = wl_wps_handle_sta_linkdown(ndev, inst);
23740 } else if (mode == WL_MODE_AP) {
23741 /* Take action only for matching peer mac */
23742 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac,
23743 ETH_ALEN)) {
23744 ret = wl_wps_handle_peersta_linkdown(ndev, inst, peer_mac);
23745 }
23746 }
23747 break;
23748 }
23749 case WPS_STATE_LINKUP: {
23750 if (mode == WL_MODE_BSS) {
23751 wl_wps_handle_sta_linkup(ndev, inst);
23752 } else if (mode == WL_MODE_AP) {
23753 /* Take action only for matching peer mac */
23754 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac,
23755 ETH_ALEN)) {
23756 wl_wps_handle_peersta_linkup(ndev, inst, peer_mac);
23757 }
23758 }
23759 break;
23760 }
23761 case WPS_STATE_DISCONNECT_CLIENT: {
23762 /* Disconnect STA/GC command from user space */
23763 if (mode == WL_MODE_AP) {
23764 ret = wl_wps_handle_disconnect_client(ndev, inst, peer_mac);
23765 } else {
23766 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
23767 }
23768 break;
23769 }
23770 case WPS_STATE_DISCONNECT: {
23771 /* Disconnect command on STA/GC interface */
23772 if (mode == WL_MODE_BSS) {
23773 ret = wl_wps_handle_disconnect(ndev, inst, peer_mac);
23774 }
23775 break;
23776 }
23777 case WPS_STATE_CONNECT_FAIL: {
23778 if (mode == WL_MODE_BSS) {
23779 ret = wl_wps_handle_connect_fail(ndev, inst);
23780 } else {
23781 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
23782 }
23783 break;
23784 }
23785 case WPS_STATE_AUTHORIZE: {
23786 if (mode == WL_MODE_AP) {
23787 /* Take action only for matching peer mac */
23788 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac,
23789 ETH_ALEN)) {
23790 wl_wps_handle_authorize(ndev, inst, peer_mac);
23791 } else {
23792 WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
23793 }
23794 }
23795 break;
23796 }
23797
23798 default:
23799 WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state, mode));
23800 ret = BCME_ERROR;
23801 }
23802
23803 return ret;
23804 }
23805
23806 #define EAP_EXP_ATTRIB_DATA_OFFSET 14
wl_handle_wps_states(struct net_device * ndev,u8 * pkt,u16 len,bool direction)23807 void wl_handle_wps_states(struct net_device *ndev, u8 *pkt, u16 len,
23808 bool direction)
23809 {
23810 eapol_header_t *eapol_hdr;
23811 bool tx_packet = direction;
23812 u16 eapol_type;
23813 u16 mode;
23814 u8 *peer_mac;
23815
23816 if (!ndev || !pkt) {
23817 WL_ERR(("[WPS] Invalid arg\n"));
23818 return;
23819 }
23820
23821 if (len < (ETHER_HDR_LEN + EAPOL_HDR_LEN)) {
23822 WL_ERR(("[WPS] Invalid len\n"));
23823 return;
23824 }
23825
23826 eapol_hdr = (eapol_header_t *)pkt;
23827 eapol_type = eapol_hdr->type;
23828
23829 peer_mac =
23830 tx_packet ? eapol_hdr->eth.ether_dhost : eapol_hdr->eth.ether_shost;
23831 /*
23832 * The implementation assumes only one WPS session would be active
23833 * per interface at a time. Even for hostap, the wps_pin session
23834 * is limited to one enrollee/client at a time. A session is marked
23835 * started on WSC_START and gets cleared from below contexts
23836 * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
23837 * b) Link up following EAP-FAIL. (success case)
23838 * c) Link up timeout after EAP-FAIL. (Fail case)
23839 */
23840
23841 if (eapol_type == EAP_PACKET) {
23842 wl_eap_header_t *eap;
23843
23844 if (len > sizeof(*eap)) {
23845 eap = (wl_eap_header_t *)(pkt + ETHER_HDR_LEN + EAPOL_HDR_LEN);
23846 if (eap->type == EAP_EXPANDED_TYPE) {
23847 wl_eap_exp_t *exp = (wl_eap_exp_t *)eap->data;
23848 if (eap->length > EAP_EXP_HDR_MIN_LENGTH) {
23849 /* opcode is at fixed offset */
23850 u8 opcode = exp->opcode;
23851 u16 eap_len = ntoh16(eap->length);
23852
23853 WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
23854 ndev->name, opcode, eap_len));
23855 if (opcode == EAP_WSC_MSG) {
23856 const u8 *msg;
23857 const u8 *parse_buf = exp->data;
23858 /* Check if recvd pkt is fragmented */
23859 if ((!tx_packet) &&
23860 (exp->flags & EAP_EXP_FLAGS_FRAGMENTED_DATA)) {
23861 if ((eap_len - EAP_EXP_ATTRIB_DATA_OFFSET) > 0x2) {
23862 parse_buf += EAP_EXP_FRAGMENT_LEN_OFFSET;
23863 eap_len -= EAP_EXP_FRAGMENT_LEN_OFFSET;
23864 WL_DBG(("Rcvd EAP"
23865 " fragmented pkt\n"));
23866 } else {
23867 /* If recvd pkt is fragmented
23868 * and does not have
23869 * length field drop the packet.
23870 */
23871 return;
23872 }
23873 }
23874
23875 msg = wl_find_attribute(
23876 parse_buf, (eap_len - EAP_EXP_ATTRIB_DATA_OFFSET),
23877 EAP_ATTRIB_MSGTYPE);
23878 if (unlikely(!msg)) {
23879 WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
23880 } else if ((*msg == EAP_WSC_MSG_M8) && !tx_packet) {
23881 WL_INFORM_MEM(("[%s][WPS] M8\n", ndev->name));
23882 wl_wps_session_update(ndev, WPS_STATE_M8_RECVD,
23883 peer_mac);
23884 } else if ((*msg == EAP_WSC_MSG_M8) && tx_packet) {
23885 WL_INFORM_MEM(("[%s][WPS] M8 Sent\n", ndev->name));
23886 wl_wps_session_update(ndev, WPS_STATE_M8_SENT,
23887 peer_mac);
23888 } else {
23889 WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n", ndev->name,
23890 *msg));
23891 }
23892 } else if (opcode == EAP_WSC_START) {
23893 /* WSC session started. WSC_START - Tx from GO/AP.
23894 * Session will be deleted on successful link up or
23895 * on failure (deauth context)
23896 */
23897 mode = tx_packet ? WL_MODE_AP : WL_MODE_BSS;
23898 wl_wps_session_add(ndev, mode, peer_mac);
23899 WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
23900 ndev->name, mode));
23901 } else if (opcode == EAP_WSC_DONE) {
23902 /* WSC session done. TX on STA/GC. RX on GO/AP
23903 * On devices where config file save fails, it may
23904 * return WPS_NAK with config_error:0. But the
23905 * connection would still proceed. Hence don't let
23906 * state machine depend on WSC DONE.
23907 */
23908 WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev->name));
23909 }
23910 }
23911 }
23912
23913 if (eap->code == EAP_CODE_FAILURE) {
23914 /* EAP_FAIL */
23915 WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev->name));
23916 wl_wps_session_update(ndev, WPS_STATE_EAP_FAIL, peer_mac);
23917 }
23918 }
23919 }
23920 }
23921 #endif /* WL_WPS_SYNC */
23922
wl_cfg80211_sup_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * event,void * data)23923 s32 wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg,
23924 bcm_struct_cfgdev *cfgdev,
23925 const wl_event_msg_t *event, void *data)
23926 {
23927 int err = BCME_OK;
23928 u32 status = ntoh32(event->status);
23929 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
23930 u32 reason = ntoh32(event->reason);
23931
23932 if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
23933 /* Join attempt via non-cfg80211 interface.
23934 * Don't send resultant events to cfg80211
23935 * layer
23936 */
23937 WL_INFORM_MEM(("Event received in non-cfg80211"
23938 " connect state. Ignore\n"));
23939 return BCME_OK;
23940 }
23941
23942 if ((status == WLC_SUP_KEYED || status == WLC_SUP_KEYXCHANGE_WAIT_G1) &&
23943 reason == WLC_E_SUP_OTHER) {
23944 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
23945 /* NL80211_CMD_PORT_AUTHORIZED supported above >= 4.15 */
23946 cfg80211_port_authorized(
23947 ndev, (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID), GFP_KERNEL);
23948 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
23949 #elif ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
23950 defined(WL_VENDOR_EXT_SUPPORT))
23951 err = wl_cfgvendor_send_async_event(bcmcfg_to_wiphy(cfg), ndev,
23952 BRCM_VENDOR_EVENT_PORT_AUTHORIZED,
23953 NULL, 0);
23954 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
23955 #else
23956 /* not supported in kernel <= 3,14,0 */
23957 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */
23958 } else if (status < WLC_SUP_KEYXCHANGE_WAIT_G1 &&
23959 (reason != WLC_E_SUP_OTHER && reason != WLC_E_SUP_PTK_UPDATE)) {
23960 /* if any failure seen while 4way HS, should send NL80211_CMD_DISCONNECT
23961 */
23962 WL_ERR(("4way HS error. status:%d, reason:%d\n", status, reason));
23963 CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
23964 }
23965
23966 return err;
23967 }
23968
23969 #ifdef WL_BCNRECV
wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23970 static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg,
23971 bcm_struct_cfgdev *cfgdev,
23972 const wl_event_msg_t *e, void *data)
23973 {
23974 s32 status = ntoh32(e->status);
23975 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
23976 /* Abort fakeapscan, when Roam is in progress */
23977 if (status == WLC_E_STATUS_RXBCN_ABORT) {
23978 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_ROAMABORT);
23979 } else {
23980 WL_ERR(("UNKNOWN STATUS. status:%d\n", status));
23981 }
23982 return BCME_OK;
23983 }
23984 #endif /* WL_BCNRECV */
23985
23986 #ifdef WL_MBO
wl_mbo_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)23987 static s32 wl_mbo_event_handler(struct bcm_cfg80211 *cfg,
23988 bcm_struct_cfgdev *cfgdev,
23989 const wl_event_msg_t *e, void *data)
23990 {
23991 s32 err = 0;
23992 wl_event_mbo_t *mbo_evt = (wl_event_mbo_t *)data;
23993 wl_event_mbo_cell_nw_switch_t *cell_sw_evt = NULL;
23994 wl_btm_event_type_data_t *evt_data = NULL;
23995
23996 WL_INFORM(("MBO: Evt %u\n", mbo_evt->type));
23997
23998 if (mbo_evt->type == WL_MBO_E_CELLULAR_NW_SWITCH) {
23999 cell_sw_evt = (wl_event_mbo_cell_nw_switch_t *)mbo_evt->data;
24000 BCM_REFERENCE(cell_sw_evt);
24001 SUPP_EVENT(("CTRL-EVENT-CELLULAR-SWITCH",
24002 "reason %d cur_assoc_time_left %u "
24003 "reassoc_delay %u\n",
24004 cell_sw_evt->reason, cell_sw_evt->assoc_time_remain,
24005 cell_sw_evt->reassoc_delay));
24006 } else if (mbo_evt->type == WL_MBO_E_BTM_RCVD) {
24007 evt_data = (wl_btm_event_type_data_t *)mbo_evt->data;
24008 if (evt_data->version != WL_BTM_EVENT_DATA_VER_1) {
24009 WL_ERR(("version mismatch. rcvd %u expected %u\n",
24010 evt_data->version, WL_BTM_EVENT_DATA_VER_1));
24011 return -1;
24012 }
24013 SUPP_EVENT(("CTRL-EVENT-BRCM-BTM-REQ-RCVD", "reason=%u\n",
24014 evt_data->transition_reason));
24015 } else {
24016 WL_INFORM(("UNKNOWN EVENT. type:%u\n", mbo_evt->type));
24017 }
24018 return err;
24019 }
24020 #endif /* WL_MBO */
24021
24022 #ifdef WL_CAC_TS
wl_cfg80211_cac_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)24023 static s32 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg,
24024 bcm_struct_cfgdev *cfgdev,
24025 const wl_event_msg_t *e, void *data)
24026 {
24027 u32 event = ntoh32(e->event_type);
24028 s32 status = ntoh32(e->status);
24029 s32 reason = ntoh32(e->reason);
24030
24031 BCM_REFERENCE(reason);
24032
24033 if (event == WLC_E_ADDTS_IND) {
24034 /* The supp log format of adding ts_delay in success case needs to be
24035 * maintained */
24036 if (status == WLC_E_STATUS_SUCCESS) {
24037 uint *ts_delay = (uint *)data;
24038 BCM_REFERENCE(ts_delay);
24039 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS",
24040 "status=%d reason=%d ts_delay=%u\n", status, reason,
24041 *ts_delay));
24042 } else {
24043 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d\n", status,
24044 reason));
24045 }
24046 } else if (event == WLC_E_DELTS_IND) {
24047 SUPP_EVENT(
24048 ("CTRL-EVENT-CAC-DELTS", "status=%d reason=%d\n", status, reason));
24049 }
24050
24051 return BCME_OK;
24052 }
24053 #endif /* WL_CAC_TS */
24054
24055 #if defined(WL_MBO) || defined(WL_OCE)
wl_bssid_prune_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)24056 static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg,
24057 bcm_struct_cfgdev *cfgdev,
24058 const wl_event_msg_t *e, void *data)
24059 {
24060 s32 err = 0;
24061 uint reason = 0;
24062 wl_bssid_pruned_evt_info_t *evt_info = (wl_bssid_pruned_evt_info_t *)data;
24063
24064 if (evt_info->version == WL_BSSID_PRUNE_EVT_VER_1) {
24065 if (evt_info->reason == WLC_E_PRUNE_ASSOC_RETRY_DELAY) {
24066 /* MBO assoc retry delay */
24067 reason = WIFI_PRUNE_ASSOC_RETRY_DELAY;
24068 SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED",
24069 "ssid=%s bssid=" MACF " reason=%u timeout_val=%u(ms)\n",
24070 evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID), reason,
24071 evt_info->time_remaining));
24072 } else if (evt_info->reason == WLC_E_PRUNE_RSSI_ASSOC_REJ) {
24073 /* OCE RSSI-based assoc rejection */
24074 reason = WIFI_PRUNE_RSSI_ASSOC_REJ;
24075 SUPP_EVENT(
24076 ("CTRL-EVENT-BRCM-BSSID-PRUNED",
24077 "ssid=%s bssid=" MACF
24078 " reason=%u timeout_val=%u(ms) rssi_threshold=%d(dBm)\n",
24079 evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID), reason,
24080 evt_info->time_remaining, evt_info->rssi_threshold));
24081 } else {
24082 /* Invalid other than the assoc retry delay/RSSI assoc rejection
24083 * in the current handler
24084 */
24085 BCM_REFERENCE(reason);
24086 WL_INFORM(("INVALID. reason:%u\n", evt_info->reason));
24087 }
24088 } else {
24089 WL_INFORM(("version mismatch. rcvd %u expected %u\n", evt_info->version,
24090 WL_BSSID_PRUNE_EVT_VER_1));
24091 }
24092 return err;
24093 }
24094 #endif /* WL_MBO || WL_OCE */
24095 #ifdef RTT_SUPPORT
wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)24096 static s32 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg,
24097 bcm_struct_cfgdev *cfgdev,
24098 const wl_event_msg_t *e, void *data)
24099 {
24100 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24101 wl_event_msg_t event;
24102
24103 (void)memcpy_s(&event, sizeof(wl_event_msg_t), e, sizeof(wl_event_msg_t));
24104 return dhd_rtt_event_handler(dhdp, &event, data);
24105 }
24106 #endif /* RTT_SUPPORT */
24107
wl_print_verinfo(struct bcm_cfg80211 * cfg)24108 void wl_print_verinfo(struct bcm_cfg80211 *cfg)
24109 {
24110 char *ver_ptr;
24111 uint32 alloc_len = MOD_PARAM_INFOLEN;
24112
24113 if (!cfg) {
24114 WL_ERR(("cfg is NULL\n"));
24115 return;
24116 }
24117
24118 ver_ptr = (char *)MALLOCZ(cfg->osh, alloc_len);
24119 if (!ver_ptr) {
24120 WL_ERR(("Failed to alloc ver_ptr\n"));
24121 return;
24122 }
24123
24124 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg), TRUE, &ver_ptr,
24125 alloc_len)) {
24126 WL_ERR(("DHD Version: %s\n", ver_ptr));
24127 }
24128
24129 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg), FALSE, &ver_ptr,
24130 alloc_len)) {
24131 WL_ERR(("F/W Version: %s\n", ver_ptr));
24132 }
24133
24134 MFREE(cfg->osh, ver_ptr, alloc_len);
24135 }
24136 #if defined(WL_DISABLE_HE_SOFTAP) || defined(WL_DISABLE_HE_P2P)
24137 typedef struct {
24138 uint16 id;
24139 uint16 len;
24140 uint32 val;
24141 } he_xtlv_v32;
24142
wl_he_get_uint_cb(void * ctx,uint16 * id,uint16 * len)24143 static bool wl_he_get_uint_cb(void *ctx, uint16 *id, uint16 *len)
24144 {
24145 he_xtlv_v32 *v32 = ctx;
24146
24147 *id = v32->id;
24148 *len = v32->len;
24149
24150 return FALSE;
24151 }
24152
wl_he_pack_uint_cb(void * ctx,uint16 id,uint16 len,uint8 * buf)24153 static void wl_he_pack_uint_cb(void *ctx, uint16 id, uint16 len, uint8 *buf)
24154 {
24155 he_xtlv_v32 *v32 = ctx;
24156
24157 BCM_REFERENCE(id);
24158 BCM_REFERENCE(len);
24159
24160 v32->val = htod32(v32->val);
24161
24162 switch (v32->len) {
24163 case sizeof(uint8):
24164 *buf = (uint8)v32->val;
24165 break;
24166 case sizeof(uint16):
24167 store16_ua(buf, (uint16)v32->val);
24168 break;
24169 case sizeof(uint32):
24170 store32_ua(buf, v32->val);
24171 break;
24172 default:
24173 break;
24174 }
24175 }
24176
wl_cfg80211_set_he_mode(struct net_device * dev,struct bcm_cfg80211 * cfg,s32 bssidx,u32 interface_type,bool set)24177 int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg,
24178 s32 bssidx, u32 interface_type, bool set)
24179 {
24180 bcm_xtlv_t read_he_xtlv;
24181 uint8 se_he_xtlv[32];
24182 int se_he_xtlv_len = sizeof(se_he_xtlv);
24183 he_xtlv_v32 v32;
24184 u32 he_feature = 0;
24185 s32 err = 0;
24186 u32 he_interface = 0;
24187
24188 read_he_xtlv.id = WL_HE_CMD_FEATURES;
24189 read_he_xtlv.len = 0;
24190 err = wldev_iovar_getbuf_bsscfg(dev, "he", &read_he_xtlv,
24191 sizeof(read_he_xtlv), cfg->ioctl_buf,
24192 WLC_IOCTL_SMLEN, bssidx, NULL);
24193 if (err < 0) {
24194 if (err == BCME_UNSUPPORTED) {
24195 /* HE not supported. Do nothing. */
24196 return BCME_OK;
24197 }
24198 WL_ERR(("HE get failed. error=%d\n", err));
24199 } else {
24200 he_feature = *(int *)cfg->ioctl_buf;
24201 he_feature = dtoh32(he_feature);
24202 }
24203
24204 v32.id = WL_HE_CMD_FEATURES;
24205 v32.len = sizeof(s32);
24206 if (interface_type == WL_IF_TYPE_P2P_DISC) {
24207 he_interface = WL_HE_FEATURES_HE_P2P;
24208 } else if (interface_type == WL_IF_TYPE_AP) {
24209 he_interface = WL_HE_FEATURES_HE_AP;
24210 } else {
24211 WL_ERR(("HE request for Invalid interface type"));
24212 err = BCME_BADARG;
24213 return err;
24214 }
24215
24216 if (set) {
24217 v32.val = (he_feature | he_interface);
24218 } else {
24219 v32.val = (he_feature & ~he_interface);
24220 }
24221
24222 err = bcm_pack_xtlv_buf((void *)&v32, se_he_xtlv, sizeof(se_he_xtlv),
24223 BCM_XTLV_OPTION_ALIGN32, wl_he_get_uint_cb,
24224 wl_he_pack_uint_cb, &se_he_xtlv_len);
24225 if (err != BCME_OK) {
24226 WL_ERR(("failed to pack he settvl=%d\n", err));
24227 }
24228
24229 err = wldev_iovar_setbuf_bsscfg(dev, "he", &se_he_xtlv, sizeof(se_he_xtlv),
24230 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx,
24231 &cfg->ioctl_buf_sync);
24232 if (err < 0) {
24233 WL_ERR(("failed to set he features, error=%d\n", err));
24234 }
24235 WL_INFORM(("Set HE[%d] done\n", set));
24236
24237 return err;
24238 }
24239 #endif /* WL_DISABLE_HE_SOFTAP || WL_DISABLE_HE_P2P */
24240
24241 /* Get the concurrency mode */
wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 * cfg)24242 int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg)
24243 {
24244 struct net_info *iter, *next;
24245 uint cmode = CONCURRENCY_MODE_NONE;
24246 u32 connected_cnt = 0;
24247 u32 pre_channel = 0, channel = 0;
24248 u32 pre_band = 0;
24249 u32 chanspec = 0;
24250 u32 band = 0;
24251
24252 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
24253 if (connected_cnt <= 1) {
24254 return cmode;
24255 }
24256 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
24257 for_each_ndev(cfg, iter, next)
24258 {
24259 if (iter->ndev) {
24260 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
24261 if (wldev_iovar_getint(iter->ndev, "chanspec",
24262 (s32 *)&chanspec) == BCME_OK) {
24263 channel =
24264 wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
24265 band = (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ
24266 : IEEE80211_BAND_5GHZ;
24267 }
24268 if ((!pre_channel && channel)) {
24269 pre_band = band;
24270 pre_channel = channel;
24271 } else if (pre_channel) {
24272 if ((pre_band == band) && (pre_channel == channel)) {
24273 cmode = CONCURRENCY_SCC_MODE;
24274 goto exit;
24275 } else if ((pre_band == band) && (pre_channel != channel)) {
24276 cmode = CONCURRENCY_VSDB_MODE;
24277 goto exit;
24278 } else if (pre_band != band) {
24279 cmode = CONCURRENCY_RSDB_MODE;
24280 goto exit;
24281 }
24282 }
24283 }
24284 }
24285 }
24286 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
24287 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 0x6))
24288 _Pragma("GCC diagnostic pop")
24289 #endif // endif
24290 exit : return cmode;
24291 }
24292 #ifdef WL_CHAN_UTIL
wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)24293 static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg,
24294 bcm_struct_cfgdev *cfgdev,
24295 const wl_event_msg_t *e,
24296 void *data)
24297 {
24298 s32 err = BCME_OK;
24299 struct sk_buff *skb = NULL;
24300 s32 status = ntoh32(e->status);
24301 u8 chan_use_percentage = 0;
24302 #if (defined(CONFIG_ARCH_MSM) && \
24303 defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
24304 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
24305 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
24306 #endif /* (defined(CONFIG_ARCH_MSM) && \
24307 defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
24308 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
24309 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24310 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
24311 uint len;
24312 gfp_t kflags;
24313 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24314
24315 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24316 len = CU_ATTR_HDR_LEN + sizeof(u8);
24317 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
24318 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24319
24320 #if (defined(CONFIG_ARCH_MSM) && \
24321 defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
24322 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
24323 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), len,
24324 BRCM_VENDOR_EVENT_CU, kflags);
24325 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24326 skb = cfg80211_vendor_event_alloc(wiphy, len, BRCM_VENDOR_EVENT_CU, kflags);
24327 #else
24328 /* No support exist */
24329 #endif /* (defined(CONFIG_ARCH_MSM) && \
24330 defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
24331 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
24332 if (!skb) {
24333 WL_ERR(("skb alloc failed"));
24334 return -ENOMEM;
24335 }
24336
24337 if ((status == WLC_E_STATUS_SUCCESS) && data) {
24338 wl_bssload_t *bssload_report = (wl_bssload_t *)data;
24339 chan_use_percentage = (bssload_report->chan_util * 0x64) / 0xFF;
24340 WL_DBG(("ChannelUtilization=%hhu\n", chan_use_percentage));
24341 err = nla_put_u8(skb, CU_ATTR_PERCENTAGE, chan_use_percentage);
24342 if (err < 0) {
24343 WL_ERR(("Failed to put CU_ATTR_PERCENTAGE, err:%d\n", err));
24344 }
24345 }
24346
24347 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24348 cfg80211_vendor_event(skb, kflags);
24349 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24350
24351 return err;
24352 }
24353
24354 #define WL_CHAN_UTIL_DEFAULT_INTERVAL 3000
24355 #define WL_CHAN_UTIL_THRESH_MIN 15
24356 #define WL_CHAN_UTIL_THRESH_INTERVAL 10
24357 #ifndef CUSTOM_CU_INTERVAL
24358 #define CUSTOM_CU_INTERVAL WL_CHAN_UTIL_DEFAULT_INTERVAL
24359 #endif /* CUSTOM_CU_INTERVAL */
24360
wl_cfg80211_start_bssload_report(struct net_device * ndev)24361 static s32 wl_cfg80211_start_bssload_report(struct net_device *ndev)
24362 {
24363 s32 err = BCME_OK;
24364 wl_bssload_cfg_t blcfg;
24365 u8 i;
24366 struct bcm_cfg80211 *cfg;
24367
24368 if (!ndev) {
24369 return -ENODEV;
24370 }
24371
24372 cfg = wl_get_cfg(ndev);
24373 if (!cfg) {
24374 return -ENODEV;
24375 }
24376
24377 /* Typecasting to void as the buffer size is same as the memset size */
24378 (void)memset_s(&blcfg, sizeof(wl_bssload_cfg_t), 0,
24379 sizeof(wl_bssload_cfg_t));
24380 /* Set default report interval 3 sec and 8 threshhold levels between 15 to
24381 * 85% */
24382 blcfg.rate_limit_msec = CUSTOM_CU_INTERVAL;
24383 blcfg.num_util_levels = MAX_BSSLOAD_LEVELS;
24384 for (i = 0; i < MAX_BSSLOAD_LEVELS; i++) {
24385 blcfg.util_levels[i] =
24386 (((WL_CHAN_UTIL_THRESH_MIN + (i * WL_CHAN_UTIL_THRESH_INTERVAL)) *
24387 0xFF) /
24388 0x64);
24389 }
24390
24391 err = wldev_iovar_setbuf(ndev, "bssload_report_event", &blcfg,
24392 sizeof(wl_bssload_cfg_t), cfg->ioctl_buf,
24393 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
24394 if (unlikely(err)) {
24395 WL_ERR(("Set event_msgs error (%d)\n", err));
24396 }
24397
24398 return err;
24399 }
24400 #endif /* WL_CHAN_UTIL */
24401
wl_cfg80211_config_suspend_events(struct net_device * ndev,bool enable)24402 s32 wl_cfg80211_config_suspend_events(struct net_device *ndev, bool enable)
24403 {
24404 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
24405 s8 eventmask[WL_EVENTING_MASK_LEN];
24406 s32 err = 0;
24407 struct bcm_cfg80211 *cfg;
24408
24409 if (!ndev) {
24410 return -ENODEV;
24411 }
24412
24413 cfg = wl_get_cfg(ndev);
24414 if (!cfg) {
24415 return -ENODEV;
24416 }
24417
24418 mutex_lock(&cfg->event_sync);
24419 err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf,
24420 sizeof(iovbuf), NULL);
24421 if (unlikely(err)) {
24422 WL_ERR(("Get event_msgs error (%d)\n", err));
24423 goto eventmsg_out;
24424 }
24425
24426 (void)memcpy_s(eventmask, WL_EVENTING_MASK_LEN, iovbuf,
24427 WL_EVENTING_MASK_LEN);
24428 /* Add set/clear of event mask under feature specific flags */
24429 if (enable) {
24430 WL_DBG(("%s: Enabling events on resume\n", __FUNCTION__));
24431 #ifdef WL_CHAN_UTIL
24432 setbit(eventmask, WLC_E_BSS_LOAD);
24433 #endif /* WL_CHAN_UTIL */
24434 } else {
24435 WL_DBG(("%s: Disabling events before suspend\n", __FUNCTION__));
24436 #ifdef WL_CHAN_UTIL
24437 clrbit(eventmask, WLC_E_BSS_LOAD);
24438 #endif /* WL_CHAN_UTIL */
24439 }
24440
24441 err =
24442 wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
24443 iovbuf, sizeof(iovbuf), NULL);
24444 if (unlikely(err)) {
24445 WL_ERR(("Set event_msgs error (%d)\n", err));
24446 goto eventmsg_out;
24447 }
24448
24449 eventmsg_out:
24450 mutex_unlock(&cfg->event_sync);
24451 return err;
24452 }
24453
24454 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
wl_cfg80211_channel_switch(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_csa_settings * params)24455 int wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
24456 struct cfg80211_csa_settings *params)
24457 {
24458 s32 err = BCME_OK;
24459 s32 chan = 0;
24460 u32 band = 0;
24461 u32 bw = WL_CHANSPEC_BW_20;
24462 chanspec_t chspec = 0;
24463 wl_chan_switch_t csa_arg;
24464 struct cfg80211_chan_def *chandef = ¶ms->chandef;
24465 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
24466 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
24467
24468 dev = ndev_to_wlc_ndev(dev, cfg);
24469 chan = ieee80211_frequency_to_channel(chandef->chan->center_freq);
24470 band = chandef->chan->band;
24471
24472 WL_ERR(("netdev_ifidx(%d), target channel(%d) target bandwidth(%d),"
24473 " mode(%d), count(%d)\n",
24474 dev->ifindex, chan, chandef->width, params->block_tx,
24475 params->count));
24476
24477 if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) {
24478 WL_ERR(("Channel Switch doesn't support on "
24479 "the non-SoftAP mode\n"));
24480 return -EINVAL;
24481 }
24482
24483 /* Check if STA is trying to associate with an AP */
24484 if (wl_get_drv_status(cfg, CONNECTING, primary_dev)) {
24485 WL_ERR(("Connecting is in progress\n"));
24486 return BCME_BUSY;
24487 }
24488
24489 if (chan == cfg->ap_oper_channel) {
24490 WL_ERR(("Channel %d is same as current operating channel,"
24491 " so skip\n",
24492 chan));
24493 return BCME_OK;
24494 }
24495
24496 if (band == IEEE80211_BAND_5GHZ) {
24497 #ifdef APSTA_RESTRICTED_CHANNEL
24498 if (chan != DEFAULT_5G_SOFTAP_CHANNEL) {
24499 WL_ERR(("Invalid 5G Channel, chan=%d\n", chan));
24500 return -EINVAL;
24501 }
24502 #endif /* APSTA_RESTRICTED_CHANNEL */
24503 err = wl_get_bandwidth_cap(primary_dev, band, &bw);
24504 if (err < 0) {
24505 WL_ERR(("Failed to get bandwidth information,"
24506 " err=%d\n",
24507 err));
24508 return err;
24509 }
24510 } else if (band == IEEE80211_BAND_2GHZ) {
24511 #ifdef APSTA_RESTRICTED_CHANNEL
24512 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24513 u32 *sta_chan = (u32 *)wl_read_prof(cfg, primary_dev, WL_PROF_CHAN);
24514
24515 /* In 2GHz STA/SoftAP concurrent mode, the operating channel
24516 * of STA and SoftAP should be confgiured to the same 2GHz
24517 * channel. Otherwise, it is an invalid configuration.
24518 */
24519 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
24520 wl_get_drv_status(cfg, CONNECTED, primary_dev) && sta_chan &&
24521 (*sta_chan != chan)) {
24522 WL_ERR(("Invalid 2G Channel in case of STA/SoftAP"
24523 " concurrent mode, sta_chan=%d, chan=%d\n",
24524 *sta_chan, chan));
24525 return -EINVAL;
24526 }
24527 #endif /* APSTA_RESTRICTED_CHANNEL */
24528 bw = WL_CHANSPEC_BW_20;
24529 } else {
24530 WL_ERR(("invalid band (%d)\n", band));
24531 return -EINVAL;
24532 }
24533
24534 chspec = wf_channel2chspec(chan, bw);
24535 if (!wf_chspec_valid(chspec)) {
24536 WL_ERR(("Invalid chanspec 0x%x\n", chspec));
24537 return -EINVAL;
24538 }
24539
24540 /* Send CSA to associated STAs */
24541 memset(&csa_arg, 0, sizeof(wl_chan_switch_t));
24542 csa_arg.mode = params->block_tx;
24543 csa_arg.count = params->count;
24544 csa_arg.chspec = chspec;
24545 csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME;
24546 csa_arg.reg = 0;
24547
24548 err = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(wl_chan_switch_t),
24549 cfg->ioctl_buf, WLC_IOCTL_SMLEN,
24550 &cfg->ioctl_buf_sync);
24551 if (err < 0) {
24552 WL_ERR(("Failed to switch channel, err=%d\n", err));
24553 }
24554
24555 return err;
24556 }
24557 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
24558
24559 #ifdef WL_WIPSEVT
wl_cfg80211_wips_event_ext(wl_wips_event_info_t * wips_event)24560 int wl_cfg80211_wips_event_ext(wl_wips_event_info_t *wips_event)
24561 {
24562 s32 err = BCME_OK;
24563 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
24564 struct sk_buff *skb;
24565 gfp_t kflags;
24566 struct bcm_cfg80211 *cfg;
24567 struct net_device *ndev;
24568 struct wiphy *wiphy;
24569
24570 cfg = wl_cfg80211_get_bcmcfg();
24571 if (!cfg || !cfg->wdev) {
24572 WL_ERR(("WIPS evt invalid arg\n"));
24573 return err;
24574 }
24575
24576 ndev = bcmcfg_to_prmry_ndev(cfg);
24577 wiphy = bcmcfg_to_wiphy(cfg);
24578
24579 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
24580 skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
24581 BRCM_VENDOR_WIPS_EVENT_BUF_LEN,
24582 BRCM_VENDOR_EVENT_WIPS, kflags);
24583 if (!skb) {
24584 WL_ERR(("skb alloc failed"));
24585 return BCME_NOMEM;
24586 }
24587 err = nla_put_u16(skb, WIPS_ATTR_DEAUTH_CNT, wips_event->misdeauth);
24588 if (unlikely(err)) {
24589 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_CNT failed\n"));
24590 goto fail;
24591 }
24592 err = nla_put(skb, WIPS_ATTR_DEAUTH_BSSID, ETHER_ADDR_LEN,
24593 &wips_event->bssid);
24594 if (unlikely(err)) {
24595 WL_ERR(("nla_put WIPS_ATTR_DEAUTH_BSSID failed\n"));
24596 goto fail;
24597 }
24598 err = nla_put_s16(skb, WIPS_ATTR_CURRENT_RSSI, wips_event->current_RSSI);
24599 if (unlikely(err)) {
24600 WL_ERR(("nla_put_u16 WIPS_ATTR_CURRENT_RSSI failed\n"));
24601 goto fail;
24602 }
24603 err = nla_put_s16(skb, WIPS_ATTR_DEAUTH_RSSI, wips_event->deauth_RSSI);
24604 if (unlikely(err)) {
24605 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_RSSI failed\n"));
24606 goto fail;
24607 }
24608 cfg80211_vendor_event(skb, kflags);
24609
24610 return err;
24611
24612 fail:
24613 if (skb) {
24614 nlmsg_free(skb);
24615 }
24616 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
24617 return err;
24618 }
24619
wl_cfg80211_wips_event(uint16 misdeauth,char * bssid)24620 int wl_cfg80211_wips_event(uint16 misdeauth, char *bssid)
24621 {
24622 s32 err = BCME_OK;
24623 wl_wips_event_info_t wips_event;
24624
24625 wips_event.misdeauth = misdeauth;
24626 memcpy(&wips_event.bssid, bssid, ETHER_ADDR_LEN);
24627 wips_event.current_RSSI = 0;
24628 wips_event.deauth_RSSI = 0;
24629
24630 err = wl_cfg80211_wips_event_ext(&wips_event);
24631 return err;
24632 }
24633 #endif /* WL_WIPSEVT */
24634
wl_cfg80211_check_in_progress(struct net_device * dev)24635 bool wl_cfg80211_check_in_progress(struct net_device *dev)
24636 {
24637 /* Check for cfg status like scan in progress,
24638 * four way handshake, etc before entering Deep Sleep.
24639 */
24640 return TRUE;
24641 }
24642
24643 #ifdef SUPPORT_AP_SUSPEND
wl_set_ap_suspend_error_handler(struct net_device * ndev,bool suspend)24644 void wl_set_ap_suspend_error_handler(struct net_device *ndev, bool suspend)
24645 {
24646 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24647 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
24648
24649 if (wl_get_drv_status(cfg, READY, ndev)) {
24650 /* IF dongle is down due to previous hang or other conditions, sending
24651 * one more hang notification is not needed.
24652 */
24653 if (dhd_query_bus_erros(dhdp)) {
24654 return;
24655 }
24656 dhdp->iface_op_failed = TRUE;
24657 #if defined(DHD_FW_COREDUMP)
24658 if (dhdp->memdump_enabled) {
24659 dhdp->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
24660 dhd_bus_mem_dump(dhdp);
24661 }
24662 #endif /* DHD_FW_COREDUMP */
24663 WL_ERR(("Notify hang event to upper layer \n"));
24664 dhdp->hang_reason =
24665 suspend ? HANG_REASON_BSS_DOWN_FAILURE : HANG_REASON_BSS_UP_FAILURE;
24666 net_os_send_hang_message(ndev);
24667 }
24668 }
24669
24670 #define MAX_AP_RESUME_TIME 5000
wl_set_ap_suspend(struct net_device * dev,bool suspend,char * ifname)24671 int wl_set_ap_suspend(struct net_device *dev, bool suspend, char *ifname)
24672 {
24673 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24674 dhd_pub_t *dhdp;
24675 struct net_device *ndev = NULL;
24676 int ret = BCME_OK;
24677 bool is_bssup = FALSE;
24678 int bssidx;
24679 unsigned long start_j;
24680 int time_to_sleep = MAX_AP_RESUME_TIME;
24681
24682 dhdp = (dhd_pub_t *)(cfg->pub);
24683
24684 if (!dhdp) {
24685 return BCME_NOTUP;
24686 }
24687
24688 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
24689 WL_ERR(("Not Hostapd mode\n"));
24690 return BCME_NOTAP;
24691 }
24692
24693 ndev = wl_get_ap_netdev(cfg, ifname);
24694 if (ndev == NULL) {
24695 WL_ERR(("No softAP interface named %s\n", ifname));
24696 return BCME_NOTAP;
24697 }
24698 if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
24699 WL_ERR(("Find p2p index from wdev(%p) failed\n", ndev->ieee80211_ptr));
24700 return BCME_NOTFOUND;
24701 }
24702 is_bssup = wl_cfg80211_bss_isup(ndev, bssidx);
24703 if (is_bssup && suspend) {
24704 wl_clr_drv_status(cfg, AP_CREATED, ndev);
24705 wl_clr_drv_status(cfg, CONNECTED, ndev);
24706
24707 if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 0)) < 0) {
24708 WL_ERR(("AP suspend error %d, suspend %d\n", ret, suspend));
24709 ret = BCME_NOTDOWN;
24710 goto exit;
24711 }
24712 } else if (!is_bssup && !suspend) {
24713 /* Abort scan before starting AP again */
24714 wl_cfg80211_scan_abort(cfg);
24715
24716 if ((ret = wl_cfg80211_bss_up(cfg, ndev, bssidx, 1)) < 0) {
24717 WL_ERR(("AP resume error %d, suspend %d\n", ret, suspend));
24718 ret = BCME_NOTUP;
24719 goto exit;
24720 }
24721
24722 while (TRUE) {
24723 start_j = get_jiffies_64();
24724 /* Wait for Linkup event to mark successful AP bring up */
24725 ret = wait_event_interruptible_timeout(
24726 cfg->netif_change_event,
24727 wl_get_drv_status(cfg, AP_CREATED, ndev),
24728 msecs_to_jiffies(time_to_sleep));
24729 if (ret == -ERESTARTSYS) {
24730 WL_ERR(("waitqueue was interrupted by a signal\n"));
24731 time_to_sleep -= jiffies_to_msecs(get_jiffies_64() - start_j);
24732 if (time_to_sleep <= 0) {
24733 WL_ERR(("time to sleep hits 0\n"));
24734 ret = BCME_NOTUP;
24735 goto exit;
24736 }
24737 } else if (ret == 0 || !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
24738 WL_ERR(("AP resume failed!\n"));
24739 ret = BCME_NOTUP;
24740 goto exit;
24741 } else {
24742 wl_set_drv_status(cfg, CONNECTED, ndev);
24743 ret = BCME_OK;
24744 break;
24745 }
24746 }
24747 } else {
24748 /* bssup + resume or bssdown + suspend,
24749 * So, returns OK
24750 */
24751 ret = BCME_OK;
24752 }
24753 exit:
24754 if (ret != BCME_OK) {
24755 wl_set_ap_suspend_error_handler(bcmcfg_to_prmry_ndev(cfg), suspend);
24756 }
24757
24758 return ret;
24759 }
24760 #endif /* SUPPORT_AP_SUSPEND */
24761
24762 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
wl_set_softap_elna_bypass(struct net_device * dev,char * ifname,int enable)24763 int wl_set_softap_elna_bypass(struct net_device *dev, char *ifname, int enable)
24764 {
24765 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24766 struct net_device *ifdev = NULL;
24767 char iobuf[WLC_IOCTL_SMLEN];
24768 int err = BCME_OK;
24769 int iftype = 0;
24770
24771 memset(iobuf, 0, WLC_IOCTL_SMLEN);
24772
24773 /* Check the interface type */
24774 ifdev = wl_get_netdev_by_name(cfg, ifname);
24775 if (ifdev == NULL) {
24776 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__,
24777 ifname));
24778 err = BCME_BADARG;
24779 goto fail;
24780 }
24781
24782 iftype = ifdev->ieee80211_ptr->iftype;
24783 if (iftype == NL80211_IFTYPE_AP) {
24784 err = wldev_iovar_setint(ifdev, "softap_elnabypass", enable);
24785 if (unlikely(err)) {
24786 WL_ERR(("%s: Failed to set softap_elnabypass, err=%d\n",
24787 __FUNCTION__, err));
24788 }
24789 } else {
24790 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
24791 __FUNCTION__));
24792 err = BCME_BADARG;
24793 }
24794 fail:
24795 return err;
24796 }
wl_get_softap_elna_bypass(struct net_device * dev,char * ifname,void * param)24797 int wl_get_softap_elna_bypass(struct net_device *dev, char *ifname, void *param)
24798 {
24799 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24800 int *enable = (int *)param;
24801 struct net_device *ifdev = NULL;
24802 char iobuf[WLC_IOCTL_SMLEN];
24803 int err = BCME_OK;
24804 int iftype = 0;
24805
24806 memset(iobuf, 0, WLC_IOCTL_SMLEN);
24807
24808 /* Check the interface type */
24809 ifdev = wl_get_netdev_by_name(cfg, ifname);
24810 if (ifdev == NULL) {
24811 WL_ERR(("%s: Could not find net_device for ifname:%s\n", __FUNCTION__,
24812 ifname));
24813 err = BCME_BADARG;
24814 goto fail;
24815 }
24816
24817 iftype = ifdev->ieee80211_ptr->iftype;
24818 if (iftype == NL80211_IFTYPE_AP) {
24819 err = wldev_iovar_getint(ifdev, "softap_elnabypass", enable);
24820 if (unlikely(err)) {
24821 WL_ERR(("%s: Failed to get softap_elnabypass, err=%d\n",
24822 __FUNCTION__, err));
24823 }
24824 } else {
24825 WL_ERR(("%s: softap_elnabypass should control in SoftAP mode only\n",
24826 __FUNCTION__));
24827 err = BCME_BADARG;
24828 }
24829 fail:
24830 return err;
24831 }
24832 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
24833
24834 #ifdef SUPPORT_AP_BWCTRL
24835 #define OPER_MODE_ENABLE (1 << 8)
24836 static int op2bw[] = {20, 40, 80, 160};
24837
wl_get_ap_he_mode(struct net_device * ndev,struct bcm_cfg80211 * cfg,bool * he)24838 static int wl_get_ap_he_mode(struct net_device *ndev, struct bcm_cfg80211 *cfg,
24839 bool *he)
24840 {
24841 bcm_xtlv_t read_he_xtlv;
24842 int ret = 0;
24843 u8 he_enab = 0;
24844 u32 he_feature = 0;
24845 *he = FALSE;
24846
24847 /* Check he enab first */
24848 read_he_xtlv.id = WL_HE_CMD_ENAB;
24849 read_he_xtlv.len = 0;
24850
24851 ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
24852 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
24853 if (ret < 0) {
24854 if (ret == BCME_UNSUPPORTED) {
24855 /* HE not supported */
24856 ret = BCME_OK;
24857 } else {
24858 WL_ERR(("HE ENAB get failed. ret=%d\n", ret));
24859 }
24860 goto exit;
24861 } else {
24862 he_enab = *(u8 *)cfg->ioctl_buf;
24863 }
24864
24865 if (!he_enab) {
24866 goto exit;
24867 }
24868
24869 /* Then check BIT3 of he features */
24870 read_he_xtlv.id = WL_HE_CMD_FEATURES;
24871 read_he_xtlv.len = 0;
24872
24873 ret = wldev_iovar_getbuf(ndev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
24874 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
24875 if (ret < 0) {
24876 WL_ERR(("HE FEATURE get failed. error=%d\n", ret));
24877 goto exit;
24878 } else {
24879 he_feature = *(int *)cfg->ioctl_buf;
24880 he_feature = dtoh32(he_feature);
24881 }
24882
24883 if (he_feature & WL_HE_FEATURES_HE_AP) {
24884 WL_DBG(("HE is enabled in AP\n"));
24885 *he = TRUE;
24886 }
24887 exit:
24888 return ret;
24889 }
24890
wl_update_apchan_bwcap(struct bcm_cfg80211 * cfg,struct net_device * ndev,chanspec_t chanspec)24891 static void wl_update_apchan_bwcap(struct bcm_cfg80211 *cfg,
24892 struct net_device *ndev, chanspec_t chanspec)
24893 {
24894 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
24895 struct wireless_dev *wdev = ndev_to_wdev(dev);
24896 struct wiphy *wiphy = wdev->wiphy;
24897 int ret = BCME_OK;
24898 u32 bw_cap;
24899 u32 ctl_chan;
24900 chanspec_t chanbw = WL_CHANSPEC_BW_20;
24901
24902 /* Update channel in profile */
24903 ctl_chan = wf_chspec_ctlchan(chanspec);
24904 wl_update_prof(cfg, ndev, NULL, &ctl_chan, WL_PROF_CHAN);
24905
24906 /* BW cap is only updated in 5GHz */
24907 if (ctl_chan <= CH_MAX_2G_CHANNEL) {
24908 return;
24909 }
24910
24911 /* Get WL BW CAP */
24912 ret = wl_get_bandwidth_cap(bcmcfg_to_prmry_ndev(cfg), IEEE80211_BAND_5GHZ,
24913 &bw_cap);
24914 if (ret < 0) {
24915 WL_ERR(("get bw_cap failed = %d\n", ret));
24916 goto exit;
24917 }
24918
24919 chanbw = CHSPEC_BW(
24920 channel_to_chanspec(wiphy, ndev, wf_chspec_ctlchan(chanspec), bw_cap));
24921
24922 exit:
24923 cfg->bw_cap_5g = bw2cap[chanbw >> WL_CHANSPEC_BW_SHIFT];
24924 WL_INFORM_MEM(("supported bw cap is:0x%x\n", cfg->bw_cap_5g));
24925 }
24926
wl_rxchain_to_opmode_nss(int rxchain)24927 int wl_rxchain_to_opmode_nss(int rxchain)
24928 {
24929 /*
24930 * Nss 1 -> 0, Nss 2 -> 1
24931 * This is from operating mode field
24932 * in 8.4.1.50 of 802.11ac-2013
24933 */
24934 /* Nss 3 ? */
24935 if (rxchain == 0x3) {
24936 return (1 << 0x4);
24937 } else {
24938 return 0;
24939 }
24940 }
24941
wl_update_opmode(struct net_device * ndev,u32 bw)24942 int wl_update_opmode(struct net_device *ndev, u32 bw)
24943 {
24944 int ret = BCME_OK;
24945 int oper_mode;
24946 int rxchain;
24947
24948 ret = wldev_iovar_getint(ndev, "rxchain", (s32 *)&rxchain);
24949 if (ret < 0) {
24950 WL_ERR(("get rxchain failed = %d\n", ret));
24951 goto exit;
24952 }
24953
24954 oper_mode = bw;
24955 oper_mode |= wl_rxchain_to_opmode_nss(rxchain);
24956 /* Enable flag */
24957 oper_mode |= OPER_MODE_ENABLE;
24958
24959 ret = wldev_iovar_setint(ndev, "oper_mode", oper_mode);
24960 if (ret < 0) {
24961 WL_ERR(("set oper_mode failed = %d\n", ret));
24962 goto exit;
24963 }
24964
24965 exit:
24966 return ret;
24967 }
24968
wl_set_ap_bw(struct net_device * dev,u32 bw,char * ifname)24969 int wl_set_ap_bw(struct net_device *dev, u32 bw, char *ifname)
24970 {
24971 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24972 dhd_pub_t *dhdp;
24973 struct net_device *ndev = NULL;
24974 int ret = BCME_OK;
24975 u32 *channel;
24976 bool he;
24977
24978 dhdp = (dhd_pub_t *)(cfg->pub);
24979
24980 if (!dhdp) {
24981 return BCME_NOTUP;
24982 }
24983
24984 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
24985 WL_ERR(("Not Hostapd mode\n"));
24986 return BCME_NOTAP;
24987 }
24988
24989 ndev = wl_get_ap_netdev(cfg, ifname);
24990 if (ndev == NULL) {
24991 WL_ERR(("No softAP interface named %s\n", ifname));
24992 return BCME_NOTAP;
24993 }
24994
24995 if (bw > DOT11_OPER_MODE_160MHZ) {
24996 WL_ERR(("BW is too big %d\n", bw));
24997 return BCME_BADARG;
24998 }
24999 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
25000 if (*channel <= CH_MAX_2G_CHANNEL) {
25001 WL_ERR(("current channel is %d, not supported\n", *channel));
25002 ret = BCME_BADCHAN;
25003 goto exit;
25004 }
25005
25006 if ((DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
25007 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) ||
25008 cfg->nan_enable) {
25009 WL_ERR(("BW control in concurrent mode is not supported\n"));
25010 return BCME_BUSY;
25011 }
25012
25013 /* When SCAN is on going either in STA or in AP, return BUSY */
25014 if (wl_get_drv_status_all(cfg, SCANNING)) {
25015 WL_ERR(("STA is SCANNING, not support BW control\n"));
25016 return BCME_BUSY;
25017 }
25018
25019 /* When SCANABORT is on going either in STA or in AP, return BUSY */
25020 if (wl_get_drv_status_all(cfg, SCAN_ABORTING)) {
25021 WL_ERR(("STA is SCAN_ABORTING, not support BW control\n"));
25022 return BCME_BUSY;
25023 }
25024
25025 /* When CONNECTION is on going in STA, return BUSY */
25026 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
25027 WL_ERR(("STA is CONNECTING, not support BW control\n"));
25028 return BCME_BUSY;
25029 }
25030
25031 /* BW control in AX mode needs more verification */
25032 ret = wl_get_ap_he_mode(ndev, cfg, &he);
25033 if (ret == BCME_OK && he) {
25034 WL_ERR(("BW control in HE mode is not supported\n"));
25035 return BCME_UNSUPPORTED;
25036 }
25037 if (ret < 0) {
25038 WL_ERR(("Check AX mode is failed\n"));
25039 goto exit;
25040 }
25041
25042 if ((!WL_BW_CAP_160MHZ(cfg->bw_cap_5g) && (bw == DOT11_OPER_MODE_160MHZ)) ||
25043 (!WL_BW_CAP_80MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_80MHZ)) ||
25044 (!WL_BW_CAP_40MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_40MHZ)) ||
25045 (!WL_BW_CAP_20MHZ(cfg->bw_cap_5g) && (bw >= DOT11_OPER_MODE_20MHZ))) {
25046 WL_ERR(("bw_cap %x does not support bw = %d\n", cfg->bw_cap_5g, bw));
25047 ret = BCME_BADARG;
25048 goto exit;
25049 }
25050
25051 WL_DBG(("Updating AP BW to %d\n", op2bw[bw]));
25052
25053 ret = wl_update_opmode(ndev, bw);
25054 if (ret < 0) {
25055 WL_ERR(("opmode set failed = %d\n", ret));
25056 goto exit;
25057 }
25058
25059 exit:
25060 return ret;
25061 }
25062
wl_get_ap_bw(struct net_device * dev,char * command,char * ifname,int total_len)25063 int wl_get_ap_bw(struct net_device *dev, char *command, char *ifname,
25064 int total_len)
25065 {
25066 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
25067 dhd_pub_t *dhdp;
25068 struct net_device *ndev = NULL;
25069 int ret = BCME_OK;
25070 u32 chanspec = 0;
25071 u32 bw = DOT11_OPER_MODE_20MHZ;
25072 int bytes_written = 0;
25073
25074 dhdp = (dhd_pub_t *)(cfg->pub);
25075
25076 if (!dhdp) {
25077 return BCME_NOTUP;
25078 }
25079
25080 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
25081 WL_ERR(("Not Hostapd mode\n"));
25082 return BCME_NOTAP;
25083 }
25084
25085 ndev = wl_get_ap_netdev(cfg, ifname);
25086 if (ndev == NULL) {
25087 WL_ERR(("No softAP interface named %s\n", ifname));
25088 return BCME_NOTAP;
25089 }
25090
25091 ret = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
25092 if (ret < 0) {
25093 WL_ERR(("get chanspec from AP failed = %d\n", ret));
25094 goto exit;
25095 }
25096
25097 chanspec = wl_chspec_driver_to_host(chanspec);
25098 if (CHSPEC_IS20(chanspec)) {
25099 bw = DOT11_OPER_MODE_20MHZ;
25100 } else if (CHSPEC_IS40(chanspec)) {
25101 bw = DOT11_OPER_MODE_40MHZ;
25102 } else if (CHSPEC_IS80(chanspec)) {
25103 bw = DOT11_OPER_MODE_80MHZ;
25104 } else if (CHSPEC_IS_BW_160_WIDE(chanspec)) {
25105 bw = DOT11_OPER_MODE_160MHZ;
25106 } else {
25107 WL_ERR(("chanspec error %x\n", chanspec));
25108 ret = BCME_BADCHAN;
25109 goto exit;
25110 }
25111
25112 bytes_written += snprintf(command + bytes_written, total_len, "bw=%d", bw);
25113 ret = bytes_written;
25114 exit:
25115 return ret;
25116 }
25117
wl_restore_ap_bw(struct bcm_cfg80211 * cfg)25118 static void wl_restore_ap_bw(struct bcm_cfg80211 *cfg)
25119 {
25120 int ret = BCME_OK;
25121 u32 bw;
25122 bool he = FALSE;
25123 struct net_info *iter, *next;
25124 struct net_device *ndev = NULL;
25125 u32 *channel;
25126
25127 if (!cfg) {
25128 return;
25129 }
25130
25131 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
25132 for_each_ndev(cfg, iter, next)
25133 {
25134 GCC_DIAGNOSTIC_POP();
25135 if (iter->ndev) {
25136 if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
25137 channel = (u32 *)wl_read_prof(cfg, iter->ndev, WL_PROF_CHAN);
25138 if (*channel > CH_MAX_2G_CHANNEL) {
25139 ndev = iter->ndev;
25140 break;
25141 }
25142 }
25143 }
25144 }
25145
25146 if (!ndev) {
25147 return;
25148 }
25149
25150 /* BW control in AX mode not allowed */
25151 ret = wl_get_ap_he_mode(bcmcfg_to_prmry_ndev(cfg), cfg, &he);
25152 if (ret == BCME_OK && he) {
25153 return;
25154 }
25155 if (ret < 0) {
25156 WL_ERR(("Check AX mode is failed\n"));
25157 return;
25158 }
25159
25160 if (WL_BW_CAP_160MHZ(cfg->bw_cap_5g)) {
25161 bw = DOT11_OPER_MODE_160MHZ;
25162 } else if (WL_BW_CAP_80MHZ(cfg->bw_cap_5g)) {
25163 bw = DOT11_OPER_MODE_80MHZ;
25164 } else if (WL_BW_CAP_40MHZ(cfg->bw_cap_5g)) {
25165 bw = DOT11_OPER_MODE_40MHZ;
25166 } else {
25167 return;
25168 }
25169
25170 WL_DBG(("Restoring AP BW to %d\n", op2bw[bw]));
25171
25172 ret = wl_update_opmode(ndev, bw);
25173 if (ret < 0) {
25174 WL_ERR(("bw restore failed = %d\n", ret));
25175 return;
25176 }
25177 }
25178 #endif /* SUPPORT_AP_BWCTRL */
25179
25180 #ifdef WL_CLIENT_SAE
wl_is_pmkid_available(struct net_device * dev,const u8 * bssid)25181 static bool wl_is_pmkid_available(struct net_device *dev, const u8 *bssid)
25182 {
25183 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
25184 int i;
25185 int npmkids = (cfg->pmk_list->pmkids.length - sizeof(uint16) * 0x2) /
25186 sizeof(pmkid_v2_t);
25187
25188 /* check the bssid is null or not */
25189 if (!bssid) {
25190 return FALSE;
25191 }
25192
25193 for (i = 0; i < npmkids; i++) {
25194 if (!memcmp(bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
25195 ETHER_ADDR_LEN)) {
25196 WL_DBG(("FOUND PMKID\n"));
25197 return TRUE;
25198 }
25199 }
25200 WL_ERR(("PMKID NOT FOUND\n"));
25201 return FALSE;
25202 }
25203
wl_notify_start_auth(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)25204 static s32 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
25205 bcm_struct_cfgdev *cfgdev,
25206 const wl_event_msg_t *e, void *data)
25207 {
25208 struct cfg80211_external_auth_params ext_auth_param;
25209 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
25210 u32 datalen = be32_to_cpu(e->datalen);
25211 wl_ext_auth_evt_t *evt_data = (wl_ext_auth_evt_t *)data;
25212 wl_assoc_mgr_cmd_t cmd;
25213 int err;
25214
25215 WL_DBG(("Enter\n"));
25216
25217 if (!datalen || !data) {
25218 WL_ERR(("Invalid data for auth start event\n"));
25219 return BCME_ERROR;
25220 }
25221
25222 ext_auth_param.action = NL80211_EXTERNAL_AUTH_START;
25223 ext_auth_param.key_mgmt_suite = ntoh32(WLAN_AKM_SUITE_SAE_SHA256);
25224 memcpy(&ext_auth_param.bssid, &evt_data->bssid, ETHER_ADDR_LEN);
25225 ext_auth_param.ssid.ssid_len =
25226 MIN(evt_data->ssid.SSID_len, DOT11_MAX_SSID_LEN);
25227 if (ext_auth_param.ssid.ssid_len) {
25228 memcpy(&ext_auth_param.ssid.ssid, evt_data->ssid.SSID,
25229 ext_auth_param.ssid.ssid_len);
25230 }
25231
25232 WL_MSG(ndev->name, "BSSID: %pM\n", &evt_data->bssid);
25233
25234 #ifdef WL_EXT_IAPSTA
25235 err = wl_ext_in4way_sync(ndev, STA_START_AUTH_DELAY,
25236 WL_EXT_STATUS_CONNECTING, NULL);
25237 if (err) {
25238 WL_ERR(("Failed to notify external auth req(%d)\n", err));
25239 return BCME_ERROR;
25240 }
25241 #endif
25242
25243 err = cfg80211_external_auth_request(ndev, &ext_auth_param, GFP_KERNEL);
25244 if (unlikely(err)) {
25245 WL_ERR(("Failed to notify external auth req(%d)\n", err));
25246 return BCME_ERROR;
25247 }
25248
25249 cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
25250 cmd.length = sizeof(cmd);
25251 cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
25252 cmd.params = WL_ASSOC_MGR_PARAMS_PAUSE_EVENT_AUTH_RESP;
25253 err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd),
25254 cfg->ioctl_buf, WLC_IOCTL_SMLEN,
25255 &cfg->ioctl_buf_sync);
25256 if (unlikely(err)) {
25257 WL_ERR(("Failed to pause assoc(%d)\n", err));
25258 }
25259
25260 return BCME_OK;
25261 }
25262
wl_handle_auth_event(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)25263 static s32 wl_handle_auth_event(struct bcm_cfg80211 *cfg,
25264 struct net_device *ndev,
25265 const wl_event_msg_t *e, void *data)
25266 {
25267 bcm_struct_cfgdev *cfgdev = ndev_to_cfgdev(ndev);
25268 u8 bsscfgidx = e->bsscfgidx;
25269 u8 *mgmt_frame = NULL;
25270 u8 *body = NULL;
25271 u32 body_len = 0;
25272 s32 chan;
25273 chanspec_t chanspec;
25274 s32 freq;
25275 struct ether_addr da;
25276 struct ether_addr bssid;
25277 u32 len = ntoh32(e->datalen);
25278 u32 status = ntoh32(e->status);
25279 int err = BCME_OK;
25280 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
25281 u16 channel;
25282 struct ieee80211_supported_band *band;
25283
25284 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
25285 return WL_INVALID;
25286 }
25287
25288 if (!len) {
25289 WL_ERR(("WLC_E_AUTH has no payload. status %d reason %d\n", status,
25290 ntoh32(e->reason)));
25291 #ifdef WL_EXT_IAPSTA
25292 if (status != WLC_E_STATUS_SUCCESS) {
25293 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY | STA_NO_BTC_IN4WAY,
25294 WL_EXT_STATUS_DISCONNECTED, NULL);
25295 }
25296 #endif
25297 return WL_INVALID;
25298 }
25299
25300 body = (u8 *)MALLOCZ(cfg->osh, len);
25301 if (body == NULL) {
25302 WL_ERR(("Failed to allocate body\n"));
25303 return WL_INVALID;
25304 }
25305 (void)memcpy_s(body, len, data, len);
25306
25307 err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", NULL, 0,
25308 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx,
25309 &cfg->ioctl_buf_sync);
25310 if (unlikely(err)) {
25311 WL_ERR(("Could not get cur_etheraddr %d\n", err));
25312 goto exit;
25313 }
25314 (void)memcpy_s(da.octet, ETHER_ADDR_LEN, cfg->ioctl_buf, ETHER_ADDR_LEN);
25315
25316 bzero(&bssid, sizeof(bssid));
25317 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
25318 /* Use e->addr as bssid for Sta case , before association completed */
25319 if (err == BCME_NOTASSOCIATED) {
25320 (void)memcpy_s(&bssid, ETHER_ADDR_LEN, &e->addr, ETHER_ADDR_LEN);
25321 err = BCME_OK;
25322 }
25323 if (unlikely(err)) {
25324 MFREE(cfg->osh, body, len);
25325 WL_ERR(("Could not get bssid %d\n", err));
25326 return err;
25327 }
25328
25329 err = wldev_iovar_getint(ndev, "chanspec", &chan);
25330 if (unlikely(err)) {
25331 WL_ERR(("Could not get chanspec %d\n", err));
25332 goto exit;
25333 }
25334
25335 chanspec = wl_chspec_driver_to_host(chan);
25336 channel = wf_chspec_ctlchan(chanspec);
25337 if (channel <= CH_MAX_2G_CHANNEL) {
25338 band = wiphy->bands[IEEE80211_BAND_2GHZ];
25339 } else {
25340 band = wiphy->bands[IEEE80211_BAND_5GHZ];
25341 }
25342 if (!band) {
25343 WL_ERR(("No valid band\n"));
25344 goto exit;
25345 }
25346
25347 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
25348 freq = ieee80211_channel_to_frequency(channel);
25349 #else
25350 freq = ieee80211_channel_to_frequency(channel, band->band);
25351 #endif
25352
25353 body_len = len;
25354 err = wl_frame_get_mgmt(cfg, FC_AUTH, &da, &e->addr, &bssid, &mgmt_frame,
25355 &len, body);
25356 if (!err) {
25357 #ifdef WL_EXT_IAPSTA
25358 wl_ext_update_extsae_4way(ndev, (struct ieee80211_mgmt *)mgmt_frame,
25359 FALSE);
25360 #endif
25361 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
25362 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0);
25363 #ifdef CONFIG_AP6XXX_WIFI6_HDF
25364 HdfWifiEventRxMgmt(get_hdf_netdev(g_event_ifidx), freq, 0, mgmt_frame,
25365 len);
25366 #endif
25367 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
25368 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
25369 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
25370 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
25371 #else
25372 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
25373 #endif
25374 MFREE(cfg->osh, mgmt_frame, len);
25375 }
25376
25377 exit:
25378 if (body) {
25379 MFREE(cfg->osh, body, body_len);
25380 }
25381
25382 return err;
25383 }
25384
25385 /** Called by the cfg80211 framework */
25386 static s32
wl_cfg80211_external_auth(struct wiphy * wiphy,struct net_device * ndev,struct cfg80211_external_auth_params * ext_auth_param)25387 wl_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *ndev,
25388 struct cfg80211_external_auth_params *ext_auth_param)
25389 {
25390 int err = 0;
25391 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
25392 wl_assoc_mgr_cmd_t cmd;
25393
25394 WL_DBG(("Enter\n"));
25395
25396 if (!ext_auth_param || ETHER_ISNULLADDR(ext_auth_param->bssid)) {
25397 WL_ERR(("Invalid param\n"));
25398 return -EINVAL;
25399 }
25400
25401 cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
25402 cmd.length = sizeof(cmd);
25403 cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
25404 cmd.params = WL_ASSOC_MGR_PARAMS_EVENT_NONE;
25405 err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd),
25406 cfg->ioctl_buf, WLC_IOCTL_SMLEN,
25407 &cfg->ioctl_buf_sync);
25408 if (unlikely(err)) {
25409 WL_ERR(("Failed to pause assoc(%d)\n", err));
25410 }
25411
25412 return err;
25413 }
25414
wl_cfg80211_mgmt_auth_tx(struct net_device * dev,bcm_struct_cfgdev * cfgdev,struct bcm_cfg80211 * cfg,const u8 * buf,size_t len,s32 bssidx,u64 * cookie)25415 static s32 wl_cfg80211_mgmt_auth_tx(struct net_device *dev,
25416 bcm_struct_cfgdev *cfgdev,
25417 struct bcm_cfg80211 *cfg, const u8 *buf,
25418 size_t len, s32 bssidx, u64 *cookie)
25419 {
25420 int err = 0;
25421 wl_assoc_mgr_cmd_t *cmd;
25422 char *ambuf = NULL;
25423 int param_len;
25424 bool ack = true;
25425
25426 param_len = sizeof(wl_assoc_mgr_cmd_t) + len;
25427 ambuf = MALLOCZ(cfg->osh, param_len);
25428 if (ambuf == NULL) {
25429 WL_ERR(("unable to allocate frame\n"));
25430 return -ENOMEM;
25431 }
25432
25433 cmd = (wl_assoc_mgr_cmd_t *)ambuf;
25434 cmd->version = WL_ASSOC_MGR_CURRENT_VERSION;
25435 cmd->length = len;
25436 cmd->cmd = WL_ASSOC_MGR_CMD_SEND_AUTH;
25437 err = memcpy_s(&cmd->params, len, buf, len);
25438 if (err) {
25439 WL_ERR(("Failed to copy cmd params(%d)\n", err));
25440 ack = false;
25441 } else {
25442 err = wldev_iovar_setbuf(dev, "assoc_mgr_cmd", ambuf, param_len,
25443 cfg->ioctl_buf, WLC_IOCTL_SMLEN,
25444 &cfg->ioctl_buf_sync);
25445 if (unlikely(err)) {
25446 WL_ERR(("Failed to send auth(%d)\n", err));
25447 ack = false;
25448 }
25449 #ifdef WL_EXT_IAPSTA
25450 else {
25451 const struct ieee80211_mgmt *mgmt =
25452 (const struct ieee80211_mgmt *)buf;
25453 wl_ext_update_extsae_4way(dev, mgmt, TRUE);
25454 }
25455 #endif
25456 }
25457
25458 MFREE(cfg->osh, ambuf, param_len);
25459
25460 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
25461 return BCME_OK;
25462 }
25463 #endif /* WL_CLIENT_SAE */
25464
wl_cfg80211_config_rsnxe_ie(struct net_device * dev,const u8 * parse,u32 len)25465 static s32 wl_cfg80211_config_rsnxe_ie(struct net_device *dev, const u8 *parse,
25466 u32 len)
25467 {
25468 bcm_tlv_t *ie = NULL;
25469 s32 err = 0;
25470 u8 ie_len = 0;
25471 char smbuf[WLC_IOCTL_SMLEN];
25472
25473 while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_RSNXE_ID))) {
25474 WL_DBG(("Found RSNXE ie\n"));
25475 break;
25476 }
25477
25478 ie_len = (ie != NULL) ? (ie->len + BCM_TLV_HDR_SIZE) : 0;
25479
25480 err = wldev_iovar_setbuf(dev, "rsnxe", ie, ie_len, smbuf, sizeof(smbuf),
25481 NULL);
25482 if (!err) {
25483 WL_DBG(("Configured RSNXE IE\n"));
25484 } else if (err == BCME_UNSUPPORTED) {
25485 WL_DBG(("FW does not support rsnxe iovar\n"));
25486 err = BCME_OK;
25487 } else {
25488 WL_ERR(("rsnxe set error (%d)\n", err));
25489 }
25490 return err;
25491 }
25492
wl_cfg80211_autochannel(struct net_device * dev,char * command,int total_len)25493 s32 wl_cfg80211_autochannel(struct net_device *dev, char *command,
25494 int total_len)
25495 {
25496 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
25497 int ret = 0;
25498 int bytes_written = -1;
25499
25500 sscanf(command, "%*s %d", &cfg->autochannel);
25501
25502 if (cfg->autochannel == 0) {
25503 cfg->best_2g_ch = 0;
25504 cfg->best_5g_ch = 0;
25505 } else if (cfg->autochannel == 0x2) {
25506 bytes_written = snprintf(command, total_len, "2g=%d 5g=%d",
25507 cfg->best_2g_ch, cfg->best_5g_ch);
25508 WL_TRACE(("command result is %s\n", command));
25509 ret = bytes_written;
25510 }
25511
25512 return ret;
25513 }
25514
25515 #ifdef WL_STATIC_IF
wl_cfg80211_static_if(struct bcm_cfg80211 * cfg,struct net_device * ndev)25516 bool wl_cfg80211_static_if(struct bcm_cfg80211 *cfg, struct net_device *ndev)
25517 {
25518 int i;
25519
25520 if (!cfg) {
25521 return FALSE;
25522 }
25523
25524 for (i = 0; i < DHD_MAX_STATIC_IFS; i++) {
25525 if (cfg->static_ndev[i] == ndev) {
25526 return TRUE;
25527 }
25528 }
25529
25530 return FALSE;
25531 }
25532
wl_cfg80211_static_ifidx(struct bcm_cfg80211 * cfg,struct net_device * ndev)25533 int wl_cfg80211_static_ifidx(struct bcm_cfg80211 *cfg, struct net_device *ndev)
25534 {
25535 int i;
25536
25537 if (!cfg) {
25538 return -1;
25539 }
25540
25541 for (i = 0; i < DHD_MAX_STATIC_IFS; i++) {
25542 if (cfg->static_ndev[i] == ndev) {
25543 return i;
25544 }
25545 }
25546
25547 return -1;
25548 }
25549
wl_cfg80211_static_if_active(struct bcm_cfg80211 * cfg)25550 struct net_device *wl_cfg80211_static_if_active(struct bcm_cfg80211 *cfg)
25551 {
25552 int i;
25553
25554 if (!cfg) {
25555 return NULL;
25556 }
25557
25558 for (i = 0; i < DHD_MAX_STATIC_IFS; i++) {
25559 if (cfg->static_ndev[i] &&
25560 (cfg->static_ndev_state[i] & NDEV_STATE_FW_IF_CREATED)) {
25561 return cfg->static_ndev[i];
25562 }
25563 }
25564
25565 return NULL;
25566 }
25567
wl_cfg80211_static_if_name(struct bcm_cfg80211 * cfg,const char * name)25568 int wl_cfg80211_static_if_name(struct bcm_cfg80211 *cfg, const char *name)
25569 {
25570 int i;
25571
25572 if (!cfg) {
25573 return -1;
25574 }
25575
25576 for (i = 0; i < DHD_MAX_STATIC_IFS; i++) {
25577 if (cfg->static_ndev[i] &&
25578 (!strncmp(cfg->static_ndev[i]->name, name, strlen(name)))) {
25579 return i;
25580 }
25581 }
25582
25583 return -1;
25584 }
25585
wl_cfg80211_static_if_dev_close(struct net_device * dev)25586 void wl_cfg80211_static_if_dev_close(struct net_device *dev)
25587 {
25588 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
25589 int i;
25590
25591 if (!cfg) {
25592 return;
25593 }
25594
25595 for (i = 0; i < DHD_MAX_STATIC_IFS; i++) {
25596 if (cfg->static_ndev[i] && (cfg->static_ndev[i]->flags & IFF_UP)) {
25597 dev_close(cfg->static_ndev[i]);
25598 }
25599 }
25600
25601 return;
25602 }
25603 #endif /* WL_STATIC_IF */
25604