• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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", &current_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, &ether_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, &ether_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, &ether_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(&params, 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, &params);
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", &param, 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, &notif_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, &notif_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 *)&param, 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(&params, " ")) != 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 = &params->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