1 /*
2 * Linux cfg80211 driver
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Dual:>>
22 */
23 /* */
24 #include <typedefs.h>
25 #include <linuxver.h>
26 #include <linux/kernel.h>
27
28 #include <bcmutils.h>
29 #include <bcmstdlib_s.h>
30 #include <bcmwifi_channels.h>
31 #include <bcmendian.h>
32 #include <ethernet.h>
33 #ifdef WL_WPS_SYNC
34 #include <eapol.h>
35 #endif /* WL_WPS_SYNC */
36 #include <802.11.h>
37 #include <bcmiov.h>
38 #include <linux/if_arp.h>
39 #include <asm/uaccess.h>
40
41 #include <ethernet.h>
42 #include <linux/kernel.h>
43 #include <linux/kthread.h>
44 #include <linux/netdevice.h>
45 #include <linux/sched.h>
46 #include <linux/etherdevice.h>
47 #include <linux/wireless.h>
48 #include <linux/ieee80211.h>
49 #include <linux/wait.h>
50 #if defined(CONFIG_TIZEN)
51 #include <linux/net_stat_tizen.h>
52 #endif /* CONFIG_TIZEN */
53 #include <net/cfg80211.h>
54 #include <net/rtnetlink.h>
55
56 #include <wlioctl.h>
57 #include <bcmevent.h>
58 #include <wldev_common.h>
59 #include <wl_cfg80211.h>
60 #include <wl_cfgp2p.h>
61 #include <wl_cfgscan.h>
62 #include <wl_cfgvif.h>
63 #include <bcmdevs.h>
64 #include <bcmdevs_legacy.h>
65 #ifdef WL_FILS
66 #include <fils.h>
67 #include <frag.h>
68 #endif /* WL_FILS */
69
70 #ifdef OEM_ANDROID
71 #include <wl_android.h>
72 #endif
73
74 #if defined(BCMDONGLEHOST)
75 #include <dngl_stats.h>
76 #include <dhd.h>
77 #include <dhd_linux.h>
78 #include <dhd_linux_pktdump.h>
79 #include <dhd_debug.h>
80 #include <dhdioctl.h>
81 #include <wlioctl.h>
82 #include <dhd_cfg80211.h>
83 #include <dhd_bus.h>
84 #ifdef PNO_SUPPORT
85 #include <dhd_pno.h>
86 #endif /* PNO_SUPPORT */
87 #include <wl_cfgvendor.h>
88 #endif /* defined(BCMDONGLEHOST) */
89
90 #ifdef CONFIG_SLEEP_MONITOR
91 #include <linux/power/sleep_monitor.h>
92 #endif
93
94 #if !defined(WL_VENDOR_EXT_SUPPORT)
95 #undef GSCAN_SUPPORT
96 #endif
97 #include <dhd_config.h>
98
99 #ifdef WL_NAN
100 #include <wl_cfgnan.h>
101 #endif /* WL_NAN */
102
103 #ifdef PROP_TXSTATUS
104 #include <dhd_wlfc.h>
105 #endif
106
107 #ifdef BCMPCIE
108 #include <dhd_flowring.h>
109 #endif
110 #ifdef RTT_SUPPORT
111 #include <dhd_rtt.h>
112 #endif /* RTT_SUPPORT */
113
114 #if defined(BIGDATA_SOFTAP) || defined(DHD_ENABLE_BIGDATA_LOGGING)
115 #include <wl_bigdata.h>
116 #endif /* BIGDATA_SOFTAP || DHD_ENABLE_BIGDATA_LOGGING */
117
118 #ifdef DHD_EVENT_LOG_FILTER
119 #include <dhd_event_log_filter.h>
120 #endif /* DHD_EVENT_LOG_FILTER */
121 #define BRCM_SAE_VENDOR_EVENT_BUF_LEN 500
122
123 #ifdef DNGL_AXI_ERROR_LOGGING
124 #include <bcmtlv.h>
125 #endif /* DNGL_AXI_ERROR_LOGGING */
126
127 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
128 #include <linux/dev_ril_bridge.h>
129 #include <linux/notifier.h>
130 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
131
132 #if (defined(WL_FW_OCE_AP_SELECT) || defined(BCMFW_ROAM_ENABLE)) && \
133 ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS))
134 uint fw_ap_select = true;
135 #else
136 uint fw_ap_select = false;
137 #endif /* WL_FW_OCE_AP_SELECT && (ROAM_ENABLE || BCMFW_ROAM_ENABLE) */
138 module_param(fw_ap_select, uint, 0660);
139
140 #if defined(WL_REASSOC)
141 uint wl_reassoc_support = true;
142 #else
143 uint wl_reassoc_support = false;
144 #endif /* WL_REASSOC */
145 module_param(wl_reassoc_support, uint, 0660);
146
147 static struct device *cfg80211_parent_dev = NULL;
148 static struct bcm_cfg80211 *g_bcmcfg = NULL;
149 u32 wl_dbg_level = WL_DBG_ERR;
150
151 #define MAX_WAIT_TIME 1500
152 #ifdef WLAIBSS_MCHAN
153 #define IBSS_IF_NAME "ibss%d"
154 #endif /* WLAIBSS_MCHAN */
155
156 #ifdef VSDB
157 /* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
158 #define DEFAULT_SLEEP_TIME_VSDB 120
159 #define OFF_CHAN_TIME_THRESHOLD_MS 200
160 #define AF_RETRY_DELAY_TIME 40
161
162 /* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
163 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
164 do { \
165 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
166 wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
167 OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
168 } \
169 } while (0)
170 #else /* VSDB */
171 /* if not VSDB, do nothing */
172 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
173 #endif /* VSDB */
174
175 #if !defined(BCMDONGLEHOST)
176 #ifdef ntoh32
177 #undef ntoh32
178 #endif
179 #ifdef ntoh16
180 #undef ntoh16
181 #endif
182 #ifdef htod32
183 #undef htod32
184 #endif
185 #ifdef htod16
186 #undef htod16
187 #endif
188 #define ntoh32(i) (i)
189 #define ntoh16(i) (i)
190 #define htod32(i) (i)
191 #define htod16(i) (i)
192 #define DNGL_FUNC(func, parameters)
193 #else
194 #define DNGL_FUNC(func, parameters) func parameters
195 #define COEX_DHCP
196
197 #endif /* defined(BCMDONGLEHOST) */
198
199 #define WLAN_EID_SSID 0
200 #define CH_MIN_5G_CHANNEL 34
201 #ifdef WLAIBSS
202 enum abiss_event_type {
203 AIBSS_EVENT_TXFAIL
204 };
205 #endif
206
207 #ifdef WL_RELMCAST
208 enum rmc_event_type {
209 RMC_EVENT_NONE,
210 RMC_EVENT_LEADER_CHECK_FAIL
211 };
212 #endif /* WL_RELMCAST */
213
214 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
215 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
216 * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
217 * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
218 * All the chnages in world regulatory domain are to be done here.
219 *
220 * this definition reuires disabling missing-field-initializer warning
221 * as the ieee80211_regdomain definition differs in plain linux and in Android
222 */
223 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
224 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
225 _Pragma("GCC diagnostic push")
226 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
227 #endif
228 static const struct ieee80211_regdomain brcm_regdom = {
229 #ifdef WL_6G_BAND
230 .n_reg_rules = 8,
231 #else
232 .n_reg_rules = 4,
233 #endif
234 .alpha2 = "99",
235 .reg_rules = {
236 /* IEEE 802.11b/g, channels 1..11 */
237 REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
238 /* If any */
239 /* IEEE 802.11 channel 14 - Only JP enables
240 * this and for 802.11b only
241 */
242 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
243 /* IEEE 802.11a, channel 36..64 */
244 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
245 /* IEEE 802.11a, channel 100..165 */
246 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0),
247 #ifdef WL_6G_BAND
248 REG_RULE(6025-80, 6985+80, 160, 6, 20, 0),
249 REG_RULE(5935-10, 7115+10, 20, 6, 20, 0),
250 REG_RULE(5965-20, 7085+20, 40, 6, 20, 0),
251 REG_RULE(5985-40, 7025+40, 80, 6, 20, 0),
252 #endif /* WL_6G_BAND */
253 }
254 };
255 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
256 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
257 _Pragma("GCC diagnostic pop")
258 #endif
259
260 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
261 (defined(WL_IFACE_COMB_NUM_CHANNELS) || \
262 defined(WL_CFG80211_P2P_DEV_IF))
263 static const struct ieee80211_iface_limit common_if_limits[] = {
264 {
265 /*
266 * Driver can support up to 2 AP's
267 */
268 .max = 2,
269 .types = BIT(NL80211_IFTYPE_AP),
270 },
271 {
272 /*
273 * During P2P-GO removal, P2P-GO is first changed to STA and later only
274 * removed. So setting maximum possible number of STA interfaces according
275 * to kernel version.
276 *
277 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
278 * linux-3.8 and above - max:4
279 * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
280 * for NAN defined, registering it as STA type)
281 */
282 #ifdef WL_ENABLE_P2P_IF
283 .max = 5,
284 #else
285 .max = 4,
286 #endif /* WL_ENABLE_P2P_IF */
287 .types = BIT(NL80211_IFTYPE_STATION),
288 },
289 {
290 .max = 2,
291 .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
292 },
293 #if defined(WL_CFG80211_P2P_DEV_IF)
294 {
295 .max = 1,
296 .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
297 },
298 #endif /* WL_CFG80211_P2P_DEV_IF */
299 {
300 .max = 1,
301 .types = BIT(NL80211_IFTYPE_ADHOC),
302 },
303 };
304
305 #define NUM_DIFF_CHANNELS 2
306
307 static const struct ieee80211_iface_combination
308 common_iface_combinations[] = {
309 {
310 .num_different_channels = NUM_DIFF_CHANNELS,
311 /*
312 * At Max 5 network interfaces can be registered concurrently
313 */
314 .max_interfaces = IFACE_MAX_CNT,
315 .limits = common_if_limits,
316 .n_limits = ARRAY_SIZE(common_if_limits),
317 },
318 };
319 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
320
321 static const char *wl_if_state_strs[WL_IF_STATE_MAX + 1] = {
322 "WL_IF_CREATE_REQ",
323 "WL_IF_CREATE_DONE",
324 "WL_IF_DELETE_REQ",
325 "WL_IF_DELETE_DONE",
326 "WL_IF_CHANGE_REQ",
327 "WL_IF_CHANGE_DONE",
328 "WL_IF_STATE_MAX"
329 };
330
331 #ifdef WBTEXT
332 typedef struct wl_wbtext_bssid {
333 struct ether_addr ea;
334 struct list_head list;
335 } wl_wbtext_bssid_t;
336
337 static void wl_cfg80211_wbtext_reset_conf(struct bcm_cfg80211 *cfg, struct net_device *ndev);
338 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev);
339 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
340 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
341 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg);
342 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
343 struct wl_profile *profile);
344 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
345 struct wl_profile *profile);
346 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev);
347 static int wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len);
348 #endif /* WBTEXT */
349
350 #ifdef RTT_SUPPORT
351 static s32 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
352 const wl_event_msg_t *e, void *data);
353 #endif /* RTT_SUPPORT */
354 #ifdef WL_CHAN_UTIL
355 static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg,
356 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
357 static s32 wl_cfg80211_start_bssload_report(struct net_device *ndev);
358 #endif /* WL_CHAN_UTIL */
359
360 /* SoftAP related parameters */
361 #define DEFAULT_2G_SOFTAP_CHANNEL 1
362 #define DEFAULT_2G_SOFTAP_CHANSPEC 0x1006
363 #define DEFAULT_5G_SOFTAP_CHANNEL 149
364 #define WL_MAX_NUM_CSA_COUNTERS 255
365
366 #define MAX_VNDR_OUI_STR_LEN 256u
367 #define VNDR_OUI_STR_LEN 10u
368 #define DOT11_DISCONNECT_RC 2u
369 static const uchar *exclude_vndr_oui_list[] = {
370 "\x00\x50\xf2", /* Microsoft */
371 "\x00\x00\xf0", /* Samsung Elec */
372 WFA_OUI, /* WFA */
373 NULL
374 };
375
376 typedef struct wl_vndr_oui_entry {
377 uchar oui[DOT11_OUI_LEN];
378 struct list_head list;
379 } wl_vndr_oui_entry_t;
380
381 #ifdef WL_ANALYTICS
382 static const uchar disco_bcnloss_vsie[] = {
383 0xdd, /* Vendor specific */
384 0x09, /* Length */
385 0x00, 0x00, 0xF0, /* OUI */
386 0x22, /* VENDOR_ENTERPRISE_STA_OUI_TYPE */
387 0x03, /* Sub type for additional rc */
388 0x01, /* Version */
389 0x02, /* Length */
390 0x07, 0x00 /* Reason code for BCN loss */
391 };
392 #endif /* WL_ANALYTICS */
393
394 static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
395 struct net_device *ndev, char *vndr_oui, u32 vndr_oui_len);
396 static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg);
397 #ifdef WL_ANALYTICS
398 static bool wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211 *cfg,
399 struct net_device *ndev, const char *vndr_oui);
400 #endif
401 static s32 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
402 struct parsed_vndr_ies *vndr_ies);
403 static bool wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t *vndrie);
404 #if defined(WL_FW_OCE_AP_SELECT)
405 static bool
406 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
407
408 /* Check whether the given IE looks like WFA OCE IE. */
409 #define wl_cfgoce_is_oce_ie(ie, tlvs, len) wl_cfgoce_has_ie(ie, tlvs, len, \
410 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_MBO_OCE)
411
412 /* Is any of the tlvs the expected entry? If
413 * not update the tlvs buffer pointer/length.
414 */
415 static bool
wl_cfgoce_has_ie(const u8 * ie,const u8 ** tlvs,u32 * tlvs_len,const u8 * oui,u32 oui_len,u8 type)416 wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
417 {
418 /* If the contents match the OUI and the type */
419 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
420 !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
421 type == ie[TLV_BODY_OFF + oui_len]) {
422 return TRUE;
423 }
424
425 return FALSE;
426 }
427 #endif /* WL_FW_OCE_AP_SELECT */
428
429 /*
430 * cfg80211_ops api/callback list
431 */
432 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
433 #ifdef WLAIBSS_MCHAN
434 static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name);
435 static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
436 #endif /* WLAIBSS_MCHAN */
437 static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
438 struct cfg80211_ibss_params *params);
439 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
440 struct net_device *dev);
441 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
442 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
443 struct net_device *dev, const u8 *mac,
444 struct station_info *sinfo);
445 #else
446 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
447 struct net_device *dev, u8 *mac,
448 struct station_info *sinfo);
449 #endif
450 static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
451 struct net_device *dev, bool enabled,
452 s32 timeout);
453 static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
454 struct cfg80211_connect_params *sme);
455 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
456 static int wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
457 struct cfg80211_connect_params *sme, u32 changed);
458 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
459 static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
460 u16 reason_code);
461 #if defined(WL_CFG80211_P2P_DEV_IF)
462 static s32
463 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
464 enum nl80211_tx_power_setting type, s32 mbm);
465 #else
466 static s32
467 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
468 enum nl80211_tx_power_setting type, s32 dbm);
469 #endif /* WL_CFG80211_P2P_DEV_IF */
470 #if defined(WL_CFG80211_P2P_DEV_IF)
471 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
472 struct wireless_dev *wdev, s32 *dbm);
473 #else
474 static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
475 #endif /* WL_CFG80211_P2P_DEV_IF */
476 static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
477 struct net_device *dev,
478 u8 key_idx, bool unicast, bool multicast);
479 static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
480 u8 key_idx, bool pairwise, const u8 *mac_addr,
481 struct key_params *params);
482 static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
483 u8 key_idx, bool pairwise, const u8 *mac_addr);
484 static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
485 u8 key_idx, bool pairwise, const u8 *mac_addr,
486 void *cookie, void (*callback) (void *cookie,
487 struct key_params *params));
488 static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
489 struct net_device *dev, u8 key_idx);
490 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
491 static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
492 bcm_struct_cfgdev *cfgdev, u64 cookie);
493 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
494 static s32 wl_cfg80211_del_station(
495 struct wiphy *wiphy, struct net_device *ndev,
496 struct station_del_parameters *params);
497 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
498 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
499 struct net_device *ndev, const u8* mac_addr);
500 #else
501 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
502 struct net_device *ndev, u8* mac_addr);
503 #endif
504 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
505 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
506 struct net_device *dev, const u8 *mac, struct station_parameters *params);
507 #else
508 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
509 struct net_device *dev, u8 *mac, struct station_parameters *params);
510 #endif
511 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
512 static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
513 struct cfg80211_pmksa *pmksa);
514 static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
515 struct cfg80211_pmksa *pmksa);
516 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
517 struct net_device *dev);
518 static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
519 struct cfg80211_pmksa *pmksa, bool set);
520 static void wl_cfg80211_spmk_pmkdb_change_pmk_type(struct bcm_cfg80211 *cfg,
521 pmkid_list_v3_t *pmk_list);
522 static void wl_cfg80211_spmk_pmkdb_del_spmk(struct bcm_cfg80211 *cfg,
523 struct cfg80211_pmksa *pmksa);
524
525 struct wireless_dev *
526 wl_cfg80211_create_iface(struct wiphy *wiphy, wl_iftype_t
527 iface_type, u8 *mac_addr, const char *name);
528 s32
529 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
530
531 s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
532 struct net_device *ndev, s32 bsscfg_idx,
533 wl_iftype_t iftype, s32 del, u8 *addr);
534 s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
535 struct net_device *ndev, s32 bsscfg_idx,
536 wl_iftype_t brcm_iftype, s32 del, u8 *addr);
537 #ifdef GTK_OFFLOAD_SUPPORT
538 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
539 static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
540 struct cfg80211_gtk_rekey_data *data);
541 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
542 #endif /* GTK_OFFLOAD_SUPPORT */
543 chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
544 chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
545 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev);
546 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
547 #ifdef WLFBT
548 static int wl_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
549 struct cfg80211_update_ft_ies_params *ftie);
550 #endif /* WLFBT */
551 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */
552
553 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
554 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
555 const struct cfg80211_pmk_conf *conf);
556 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
557 const u8 *aa);
558 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
559
560 /*
561 * event & event Q handlers for cfg80211 interfaces
562 */
563 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
564 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
565 static void wl_event_handler(struct work_struct *work_data);
566 static void wl_init_eq(struct bcm_cfg80211 *cfg);
567 static void wl_flush_eq(struct bcm_cfg80211 *cfg);
568 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
569 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
570 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
571 static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
572 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
573 static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
574 const wl_event_msg_t *msg, void *data);
575 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e);
576 static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
577 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
578 static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
579 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
580 static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
581 const wl_event_msg_t *e, void *data, bool completed);
582 #ifdef DHD_LOSSLESS_ROAMING
583 static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
584 const wl_event_msg_t *e, void *data);
585 #endif /* DHD_LOSSLESS_ROAMING */
586 static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
587 const wl_event_msg_t *e, void *data);
588 #ifdef BT_WIFI_HANDOVER
589 static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
590 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
591 #endif /* BT_WIFI_HANDOVER */
592 #ifdef GSCAN_SUPPORT
593 static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
594 const wl_event_msg_t *e, void *data);
595 #endif /* GSCAN_SUPPORT */
596 #ifdef RSSI_MONITOR_SUPPORT
597 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
598 const wl_event_msg_t *e, void *data);
599 #endif /* RSSI_MONITOR_SUPPORT */
600 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
601 enum wl_status state, bool set);
602 #ifdef CUSTOM_EVENT_PM_WAKE
603 static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
604 const wl_event_msg_t *e, void *data);
605 #endif /* CUSTOM_EVENT_PM_WAKE */
606 #if defined(DHD_LOSSLESS_ROAMING) || defined (DBG_PKT_MON)
607 static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
608 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
609 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
610 #ifdef DHD_LOSSLESS_ROAMING
611 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
612 #endif /* DHD_LOSSLESS_ROAMING */
613 #ifdef WL_SDO
614 static s32 wl_svc_resp_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
615 const wl_event_msg_t *e, void *data);
616 static s32 wl_notify_device_discovery(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
617 const wl_event_msg_t *e, void *data);
618 #endif
619
620 #ifdef WL_MBO
621 static s32
622 wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
623 const wl_event_msg_t *e, void *data);
624 #endif /* WL_MBO */
625
626 #ifdef WL_TWT
627 static s32
628 wl_notify_twt_event(struct bcm_cfg80211 *cfg,
629 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
630 #endif /* WL_TWT */
631
632 #ifdef WL_CLIENT_SAE
633 static bool wl_is_pmkid_available(struct net_device *dev, const u8 *bssid);
634 static s32 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
635 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
636 static s32 wl_cfg80211_external_auth(struct wiphy *wiphy,
637 struct net_device *dev, struct cfg80211_external_auth_params *ext_auth);
638 static s32
639 wl_cfg80211_mgmt_auth_tx(struct net_device *dev, bcm_struct_cfgdev *cfgdev,
640 struct bcm_cfg80211 *cfg, const u8 *buf, size_t len, s32 bssidx, u64 *cookie);
641 #endif /* WL_CLIENT_SAE */
642
643 /*
644 * register/deregister parent device
645 */
646 static void wl_cfg80211_clear_parent_dev(void);
647 /*
648 * ioctl utilites
649 */
650
651 /*
652 * cfg80211 set_wiphy_params utilities
653 */
654 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
655 static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
656 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
657
658 /*
659 * cfg profile utilities
660 */
661 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
662
663 /*
664 * cfg80211 connect utilites
665 */
666 static s32 wl_set_wpa_version(struct net_device *dev,
667 struct cfg80211_connect_params *sme);
668 static s32 wl_set_auth_type(struct net_device *dev,
669 struct cfg80211_connect_params *sme);
670 static s32 wl_set_set_cipher(struct net_device *dev,
671 struct cfg80211_connect_params *sme);
672 static s32 wl_set_key_mgmt(struct net_device *dev,
673 struct cfg80211_connect_params *sme);
674 static s32 wl_set_set_sharedkey(struct net_device *dev,
675 struct cfg80211_connect_params *sme);
676 #ifdef WL_FILS
677 static s32 wl_set_fils_params(struct net_device *dev,
678 struct cfg80211_connect_params *sme);
679 #endif
680
681 #ifdef BCMWAPI_WPI
682 static s32 wl_set_set_wapi_ie(struct net_device *dev,
683 struct cfg80211_connect_params *sme);
684 #endif
685
686 #ifdef WL_GCMP
687 static s32 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask);
688 #endif /* WL_GCMP */
689 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
690 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
691
692 /*
693 * information element utilities
694 */
695 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
696
697 #ifdef MFP
698 static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie, const u8** rsn_cap);
699 #endif
700
701 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, dhd_pub_t *data);
702 static void wl_free_wdev(struct bcm_cfg80211 *cfg);
703 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
704 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
705 static int
706 #else
707 static void
708 #endif /* kernel version < 3.10.11 */
709 wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
710 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
711
712 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool update_ssid);
713 static void wl_cfg80211_work_handler(struct work_struct *work);
714 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
715 u8 key_idx, const u8 *mac_addr,
716 struct key_params *params);
717 /*
718 * key indianess swap utilities
719 */
720 static void swap_key_from_BE(struct wl_wsec_key *key);
721 static void swap_key_to_BE(struct wl_wsec_key *key);
722
723 /*
724 * bcm_cfg80211 memory init/deinit utilities
725 */
726 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
727 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
728
729 static void wl_delay(u32 ms);
730
731 /*
732 * ibss mode utilities
733 */
734 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
735
736 /*
737 * link up/down , default configuration utilities
738 */
739 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
740 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
741
742 static void wl_link_up(struct bcm_cfg80211 *cfg);
743 static s32 wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as);
744 static s32 wl_post_linkup_ops(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as);
745 static void wl_link_down(struct bcm_cfg80211 *cfg);
746 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype);
747 static void wl_init_conf(struct wl_conf *conf);
748 int wl_cfg80211_get_ioctl_version(void);
749
750 /*
751 * find most significant bit set
752 */
753 static __used u32 wl_find_msb(u16 bit16);
754
755 /*
756 * rfkill support
757 */
758 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
759 static int wl_rfkill_set(void *data, bool blocked);
760
761 /*
762 * Some external functions, TODO: move them to dhd_linux.h
763 */
764 int dhd_add_monitor(const char *name, struct net_device **new_ndev);
765 int dhd_del_monitor(struct net_device *ndev);
766 int dhd_monitor_init(void *dhd_pub);
767 int dhd_monitor_uninit(void);
768 netdev_tx_t dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
769
770 #ifdef ROAM_CHANNEL_CACHE
771 int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
772 #endif /* ROAM_CHANNEL_CACHE */
773
774 #ifdef P2P_LISTEN_OFFLOADING
775 s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
776 #endif /* P2P_LISTEN_OFFLOADING */
777
778 #ifdef CUSTOMER_HW4_DEBUG
779 extern bool wl_scan_timeout_dbg_enabled;
780 #endif /* CUSTOMER_HW4_DEBUG */
781 #ifdef PKT_FILTER_SUPPORT
782 extern uint dhd_pkt_filter_enable;
783 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
784 #endif /* PKT_FILTER_SUPPORT */
785
786 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
787 const struct ether_addr *bssid);
788 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
789
790 #ifdef WL_SDO
791 s32 wl_cfg80211_sdo_init(struct bcm_cfg80211 *cfg);
792 s32 wl_cfg80211_sdo_deinit(struct bcm_cfg80211 *cfg);
793 #define MAX_SDO_PROTO 5
794 wl_sdo_proto_t wl_sdo_protos [] = {
795 { "all", SVC_RPOTYPE_ALL },
796 { "upnp", SVC_RPOTYPE_UPNP },
797 { "bonjour", SVC_RPOTYPE_BONJOUR },
798 { "wsd", SVC_RPOTYPE_WSD },
799 { "vendor", SVC_RPOTYPE_VENDOR },
800 };
801 #endif
802
803 #ifdef WL_WPS_SYNC
804 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg);
805 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg);
806 static void wl_wps_reauth_timeout(unsigned long data);
807 static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg);
808 static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev);
809 static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *peer_mac);
810 static void wl_wps_session_del(struct net_device *ndev);
811 s32 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac);
812 static void wl_wps_handle_ifdel(struct net_device *ndev);
813 #endif /* WL_WPS_SYNC */
814
815 #if defined(WL_FW_OCE_AP_SELECT)
816 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint);
817 #endif /* WL_FW_OCE_AP_SELECT */
818
819 #ifdef WL_BCNRECV
820 static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
821 const wl_event_msg_t *e, void *data);
822 #endif /* WL_BCNRECV */
823
824 #ifdef WL_CAC_TS
825 static s32 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
826 const wl_event_msg_t *e, void *data);
827 #endif /* WL_CAC_TS */
828
829 #if defined(WL_MBO) || defined(WL_OCE)
830 static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
831 const wl_event_msg_t *e, void *data);
832 #endif /* WL_MBO || WL_OCE */
833 static void wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as,
834 const wl_event_msg_t *event, wl_assoc_state_t assoc_state);
835
836 #if !defined(BCMDONGLEHOST)
837 /* Wake lock are used in Android only, which is dongle based as of now */
838 #define DHD_OS_WAKE_LOCK(pub)
839 #define DHD_OS_WAKE_UNLOCK(pub)
840 #define DHD_EVENT_WAKE_LOCK(pub)
841 #define DHD_EVENT_WAKE_UNLOCK(pub)
842 #define DHD_OS_WAKE_LOCK_TIMEOUT(pub)
843 #endif /* defined(BCMDONGLEHOST) */
844
845 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || \
846 (defined(CONFIG_ARCH_MSM) && defined(CFG80211_DISCONNECTED_V2))
847 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
848 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
849 IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
850 #else
851 #define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
852 cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
853 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
854 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
855
856 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
857 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
858 defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || \
859 defined(WL_FILS) || defined(CONFIG_CFG80211_FILS_BKPORT)
860 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
861 resp_ie_len, status, gfp) \
862 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
863 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
864 #else
865 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
866 resp_ie_len, status, gfp) \
867 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
868 resp_ie_len, status, gfp);
869 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
870 * (CFG80211_CONNECT_TIMEOUT_REASON_CODE) ||
871 * WL_FILS || CONFIG_CFG80211_FILS_BKPORT
872 */
873 #elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
874 /* There are customer kernels with backported changes for
875 * connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
876 * is available for kernels < 4.7 in such cases.
877 */
878 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
879 resp_ie_len, status, gfp) \
880 cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
881 resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
882 #else
883 /* Kernels < 4.7 doesn't support cfg80211_connect_bss */
884 #define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
885 resp_ie_len, status, gfp) \
886 cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
887 resp_ie_len, status, gfp);
888 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
889
890 #define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
891 (akm) == RSN_AKM_UNSPECIFIED || \
892 (akm) == RSN_AKM_PSK)
893
894 #define WL_EIDX_INVALID 0xffff
895 #define WL_SET_EIDX_IN_PROGRESS(cfg, id, type) \
896 { cfg->eidx.in_progress = id; \
897 cfg->eidx.event_type = type; }
898 #define WL_CLR_EIDX_STATES(cfg) \
899 cfg->eidx.in_progress = WL_EIDX_INVALID;
900 extern int dhd_wait_pend8021x(struct net_device *dev);
901 #ifdef PROP_TXSTATUS_VSDB
902 extern int disable_proptx;
903 #endif /* PROP_TXSTATUS_VSDB */
904
905 /* WAR: disable pm_bcnrx , scan_ps for BCM4354 WISOL module.
906 * WISOL module have ANT_1 Rx sensitivity issue.
907 */
908 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
909 extern void dhd_force_disable_singlcore_scan(dhd_pub_t *dhd);
910 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
911
912 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, 0)))
913 struct chan_info {
914 int freq;
915 int chan_type;
916 };
917 #endif
918
919 #define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
920 #define RATETAB_ENT(_rateid, _flags) \
921 { \
922 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
923 .hw_value = (_rateid), \
924 .flags = (_flags), \
925 }
926
927 static struct ieee80211_rate __wl_rates[] = {
928 RATETAB_ENT(DOT11_RATE_1M, 0),
929 RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
930 RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
931 RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
932 RATETAB_ENT(DOT11_RATE_6M, 0),
933 RATETAB_ENT(DOT11_RATE_9M, 0),
934 RATETAB_ENT(DOT11_RATE_12M, 0),
935 RATETAB_ENT(DOT11_RATE_18M, 0),
936 RATETAB_ENT(DOT11_RATE_24M, 0),
937 RATETAB_ENT(DOT11_RATE_36M, 0),
938 RATETAB_ENT(DOT11_RATE_48M, 0),
939 RATETAB_ENT(DOT11_RATE_54M, 0)
940 };
941
942 #define wl_a_rates (__wl_rates + 4)
943 #define wl_a_rates_size 8
944 #define wl_g_rates (__wl_rates + 0)
945 #define wl_g_rates_size 12
946
947 static struct ieee80211_channel __wl_2ghz_channels[] = {
948 CHAN2G(1, 2412, 0),
949 CHAN2G(2, 2417, 0),
950 CHAN2G(3, 2422, 0),
951 CHAN2G(4, 2427, 0),
952 CHAN2G(5, 2432, 0),
953 CHAN2G(6, 2437, 0),
954 CHAN2G(7, 2442, 0),
955 CHAN2G(8, 2447, 0),
956 CHAN2G(9, 2452, 0),
957 CHAN2G(10, 2457, 0),
958 CHAN2G(11, 2462, 0),
959 CHAN2G(12, 2467, 0),
960 CHAN2G(13, 2472, 0),
961 CHAN2G(14, 2484, 0)
962 };
963
964 static struct ieee80211_channel __wl_5ghz_a_channels[] = {
965 CHAN5G(34, 0), CHAN5G(36, 0),
966 CHAN5G(38, 0), CHAN5G(40, 0),
967 CHAN5G(42, 0), CHAN5G(44, 0),
968 CHAN5G(46, 0), CHAN5G(48, 0),
969 CHAN5G(52, 0), CHAN5G(56, 0),
970 CHAN5G(60, 0), CHAN5G(64, 0),
971 CHAN5G(100, 0), CHAN5G(104, 0),
972 CHAN5G(108, 0), CHAN5G(112, 0),
973 CHAN5G(116, 0), CHAN5G(120, 0),
974 CHAN5G(124, 0), CHAN5G(128, 0),
975 CHAN5G(132, 0), CHAN5G(136, 0),
976 CHAN5G(140, 0), CHAN5G(144, 0),
977 CHAN5G(149, 0), CHAN5G(153, 0),
978 CHAN5G(157, 0), CHAN5G(161, 0),
979 CHAN5G(165, 0),
980
981 #if defined(WL_6G_BAND) && !defined(CFG80211_6G_SUPPORT)
982 /* 6GHz frequency starting 5935 */
983 CHAN6G_CHAN2(0), CHAN6G(1, 0),
984 CHAN6G(5, 0), CHAN6G(9, 0),
985 CHAN6G(13, 0), CHAN6G(17, 0),
986 CHAN6G(21, 0), CHAN6G(25, 0),
987 CHAN6G(29, 0), CHAN6G(33, 0),
988 CHAN6G(37, 0), CHAN6G(41, 0),
989 CHAN6G(45, 0), CHAN6G(49, 0),
990 CHAN6G(53, 0), CHAN6G(57, 0),
991 CHAN6G(61, 0), CHAN6G(65, 0),
992 CHAN6G(69, 0), CHAN6G(73, 0),
993 CHAN6G(77, 0), CHAN6G(81, 0),
994 CHAN6G(85, 0), CHAN6G(89, 0),
995 CHAN6G(93, 0), CHAN6G(97, 0),
996 CHAN6G(101, 0), CHAN6G(105, 0),
997 CHAN6G(109, 0), CHAN6G(113, 0),
998 CHAN6G(117, 0), CHAN6G(121, 0),
999 CHAN6G(125, 0), CHAN6G(129, 0),
1000 CHAN6G(133, 0), CHAN6G(137, 0),
1001 CHAN6G(141, 0), CHAN6G(145, 0),
1002 CHAN6G(149, 0), CHAN6G(153, 0),
1003 CHAN6G(157, 0), CHAN6G(161, 0),
1004 CHAN6G(165, 0), CHAN6G(169, 0),
1005 CHAN6G(173, 0), CHAN6G(177, 0),
1006 CHAN6G(181, 0), CHAN6G(185, 0),
1007 CHAN6G(189, 0), CHAN6G(193, 0),
1008 CHAN6G(197, 0), CHAN6G(201, 0),
1009 CHAN6G(205, 0), CHAN6G(209, 0),
1010 CHAN6G(213, 0), CHAN6G(217, 0),
1011 CHAN6G(221, 0), CHAN6G(225, 0),
1012 CHAN6G(229, 0), CHAN6G(233, 0),
1013
1014 CHAN6G(3, 0), CHAN6G(11, 0),
1015 CHAN6G(19, 0), CHAN6G(27, 0),
1016 CHAN6G(35, 0), CHAN6G(43, 0),
1017 CHAN6G(51, 0), CHAN6G(59, 0),
1018 CHAN6G(67, 0), CHAN6G(75, 0),
1019 CHAN6G(83, 0), CHAN6G(91, 0),
1020 CHAN6G(99, 0), CHAN6G(107, 0),
1021 CHAN6G(115, 0), CHAN6G(123, 0),
1022 CHAN6G(131, 0), CHAN6G(139, 0),
1023 CHAN6G(147, 0), CHAN6G(155, 0),
1024 CHAN6G(163, 0), CHAN6G(171, 0),
1025 CHAN6G(179, 0), CHAN6G(187, 0),
1026 CHAN6G(195, 0), CHAN6G(203, 0),
1027 CHAN6G(211, 0), CHAN6G(219, 0), CHAN6G(227, 0),
1028
1029 CHAN6G(7, 0), CHAN6G(23, 0),
1030 CHAN6G(39, 0), CHAN6G(55, 0),
1031 CHAN6G(71, 0), CHAN6G(87, 0),
1032 CHAN6G(103, 0), CHAN6G(119, 0),
1033 CHAN6G(135, 0), CHAN6G(151, 0),
1034 CHAN6G(167, 0), CHAN6G(183, 0),
1035 CHAN6G(199, 0), CHAN6G(215, 0),
1036
1037 CHAN6G(15, 0), CHAN6G(47, 0),
1038 CHAN6G(79, 0), CHAN6G(111, 0),
1039 CHAN6G(143, 0), CHAN6G(175, 0), CHAN6G(207, 0),
1040 #endif /* WL_6G_BAND && !CFG80211_6G_SUPPORT */
1041 };
1042
1043 #ifdef CFG80211_6G_SUPPORT
1044 static struct ieee80211_channel __wl_6ghz_channels[] = {
1045 CHAN6G_CHAN2(0), CHAN6G(1, 0),
1046 CHAN6G(5, 0), CHAN6G(9, 0),
1047 CHAN6G(13, 0), CHAN6G(17, 0),
1048 CHAN6G(21, 0), CHAN6G(25, 0),
1049 CHAN6G(29, 0), CHAN6G(33, 0),
1050 CHAN6G(37, 0), CHAN6G(41, 0),
1051 CHAN6G(45, 0), CHAN6G(49, 0),
1052 CHAN6G(53, 0), CHAN6G(57, 0),
1053 CHAN6G(61, 0), CHAN6G(65, 0),
1054 CHAN6G(69, 0), CHAN6G(73, 0),
1055 CHAN6G(77, 0), CHAN6G(81, 0),
1056 CHAN6G(85, 0), CHAN6G(89, 0),
1057 CHAN6G(93, 0), CHAN6G(97, 0),
1058 CHAN6G(101, 0), CHAN6G(105, 0),
1059 CHAN6G(109, 0), CHAN6G(113, 0),
1060 CHAN6G(117, 0), CHAN6G(121, 0),
1061 CHAN6G(125, 0), CHAN6G(129, 0),
1062 CHAN6G(133, 0), CHAN6G(137, 0),
1063 CHAN6G(141, 0), CHAN6G(145, 0),
1064 CHAN6G(149, 0), CHAN6G(153, 0),
1065 CHAN6G(157, 0), CHAN6G(161, 0),
1066 CHAN6G(165, 0), CHAN6G(169, 0),
1067 CHAN6G(173, 0), CHAN6G(177, 0),
1068 CHAN6G(181, 0), CHAN6G(185, 0),
1069 CHAN6G(189, 0), CHAN6G(193, 0),
1070 CHAN6G(197, 0), CHAN6G(201, 0),
1071 CHAN6G(205, 0), CHAN6G(209, 0),
1072 CHAN6G(213, 0), CHAN6G(217, 0),
1073 CHAN6G(221, 0), CHAN6G(225, 0),
1074 CHAN6G(229, 0), CHAN6G(233, 0),
1075 };
1076 #endif /* CFG80211_6G_SUPPORT */
1077
1078 static struct ieee80211_supported_band __wl_band_2ghz = {
1079 .band = IEEE80211_BAND_2GHZ,
1080 .channels = __wl_2ghz_channels,
1081 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
1082 .bitrates = wl_g_rates,
1083 .n_bitrates = wl_g_rates_size
1084 };
1085
1086 static struct ieee80211_supported_band __wl_band_5ghz_a = {
1087 .band = IEEE80211_BAND_5GHZ,
1088 .channels = __wl_5ghz_a_channels,
1089 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
1090 .bitrates = wl_a_rates,
1091 .n_bitrates = wl_a_rates_size
1092 };
1093
1094 #ifdef CFG80211_6G_SUPPORT
1095 static struct ieee80211_supported_band __wl_band_6ghz = {
1096 .band = IEEE80211_BAND_6GHZ,
1097 .channels = __wl_6ghz_channels,
1098 .n_channels = ARRAY_SIZE(__wl_6ghz_channels),
1099 .bitrates = wl_a_rates,
1100 .n_bitrates = wl_a_rates_size
1101 };
1102 #endif /* CFG80211_6G_SUPPORT */
1103
1104 static const u32 __wl_cipher_suites[] = {
1105 WLAN_CIPHER_SUITE_WEP40,
1106 WLAN_CIPHER_SUITE_WEP104,
1107 WLAN_CIPHER_SUITE_TKIP,
1108 WLAN_CIPHER_SUITE_CCMP,
1109 #ifdef MFP
1110 /*
1111 * Advertising AES_CMAC cipher suite to userspace would imply that we
1112 * are supporting MFP. So advertise only when MFP support is enabled.
1113 */
1114 WLAN_CIPHER_SUITE_AES_CMAC,
1115 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1116 WLAN_CIPHER_SUITE_BIP_GMAC_256,
1117 WLAN_CIPHER_SUITE_BIP_GMAC_128,
1118 WLAN_CIPHER_SUITE_BIP_CMAC_256,
1119 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1120 #endif /* MFP */
1121
1122 #ifdef BCMWAPI_WPI
1123 WLAN_CIPHER_SUITE_SMS4,
1124 #endif
1125
1126 #if defined(WLAN_CIPHER_SUITE_PMK)
1127 WLAN_CIPHER_SUITE_PMK,
1128 #endif /* WLAN_CIPHER_SUITE_PMK */
1129 #ifdef WL_GCMP
1130 WLAN_CIPHER_SUITE_GCMP,
1131 WLAN_CIPHER_SUITE_GCMP_256,
1132 WLAN_CIPHER_SUITE_BIP_GMAC_128,
1133 WLAN_CIPHER_SUITE_BIP_GMAC_256,
1134 #endif /* WL_GCMP */
1135 };
1136
1137 #ifdef WL_SUPPORT_ACS
1138 /*
1139 * The firmware code required for this feature to work is currently under
1140 * BCMINTERNAL flag. In future if this is to enabled we need to bring the
1141 * required firmware code out of the BCMINTERNAL flag.
1142 */
1143 struct wl_dump_survey {
1144 u32 obss;
1145 u32 ibss;
1146 u32 no_ctg;
1147 u32 no_pckt;
1148 u32 tx;
1149 u32 idle;
1150 };
1151 #endif /* WL_SUPPORT_ACS */
1152
1153 #ifdef WL_CFG80211_GON_COLLISION
1154 #define BLOCK_GON_REQ_MAX_NUM 5
1155 #endif /* WL_CFG80211_GON_COLLISION */
1156
1157 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
1158 static int maxrxpktglom = 0;
1159 #endif
1160
1161 /* IOCtl version read from targeted driver */
1162 int ioctl_version;
1163
1164 typedef struct rsn_cipher_algo_entry {
1165 u32 cipher_suite;
1166 u32 wsec_algo;
1167 u32 wsec_key_algo;
1168 } rsn_cipher_algo_entry_t;
1169
1170 static const rsn_cipher_algo_entry_t rsn_cipher_algo_lookup_tbl[] = {
1171 {WLAN_CIPHER_SUITE_WEP40, WEP_ENABLED, CRYPTO_ALGO_WEP1},
1172 {WLAN_CIPHER_SUITE_WEP104, WEP_ENABLED, CRYPTO_ALGO_WEP128},
1173 {WLAN_CIPHER_SUITE_TKIP, TKIP_ENABLED, CRYPTO_ALGO_TKIP},
1174 {WLAN_CIPHER_SUITE_CCMP, AES_ENABLED, CRYPTO_ALGO_AES_CCM},
1175 {WLAN_CIPHER_SUITE_AES_CMAC, AES_ENABLED, CRYPTO_ALGO_BIP},
1176
1177 #ifdef BCMWAPI_WPI
1178 {WLAN_CIPHER_SUITE_SMS4, SMS4_ENABLED, CRYPTO_ALGO_SMS4},
1179 #endif /* BCMWAPI_WPI */
1180
1181 #ifdef WL_GCMP
1182 {WLAN_CIPHER_SUITE_GCMP, AES_ENABLED, CRYPTO_ALGO_AES_GCM},
1183 {WLAN_CIPHER_SUITE_GCMP_256, AES_ENABLED, CRYPTO_ALGO_AES_GCM256},
1184 {WLAN_CIPHER_SUITE_BIP_GMAC_128, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC},
1185 {WLAN_CIPHER_SUITE_BIP_GMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC256},
1186 #endif /* WL_GCMP */
1187 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1188 {WLAN_CIPHER_SUITE_BIP_CMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_CMAC256},
1189 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1190 };
1191
1192 typedef struct rsn_akm_wpa_auth_entry {
1193 u32 akm_suite;
1194 u32 wpa_auth;
1195 } rsn_akm_wpa_auth_entry_t;
1196
1197 static const rsn_akm_wpa_auth_entry_t rsn_akm_wpa_auth_lookup_tbl[] = {
1198 #ifdef WL_OWE
1199 {WLAN_AKM_SUITE_OWE, WPA3_AUTH_OWE},
1200 #endif /* WL_OWE */
1201 {WLAN_AKM_SUITE_8021X, WPA2_AUTH_UNSPECIFIED},
1202 {WL_AKM_SUITE_SHA256_1X, WPA2_AUTH_1X_SHA256},
1203 {WL_AKM_SUITE_SHA256_PSK, WPA2_AUTH_PSK_SHA256},
1204 {WLAN_AKM_SUITE_PSK, WPA2_AUTH_PSK},
1205 {WLAN_AKM_SUITE_FT_8021X, WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT},
1206 {WLAN_AKM_SUITE_FT_PSK, WPA2_AUTH_PSK | WPA2_AUTH_FT},
1207 {WLAN_AKM_SUITE_FILS_SHA256, WPA2_AUTH_FILS_SHA256},
1208 {WLAN_AKM_SUITE_FILS_SHA384, WPA2_AUTH_FILS_SHA384},
1209 {WLAN_AKM_SUITE_8021X_SUITE_B, WPA3_AUTH_1X_SUITE_B_SHA256},
1210 {WLAN_AKM_SUITE_8021X_SUITE_B_192, WPA3_AUTH_1X_SUITE_B_SHA384},
1211
1212 #ifdef BCMWAPI_WPI
1213 {WLAN_AKM_SUITE_WAPI_CERT, WAPI_AUTH_UNSPECIFIED},
1214 {WLAN_AKM_SUITE_WAPI_PSK, WAPI_AUTH_PSK},
1215 #endif /* BCMWAPI_WPI */
1216
1217 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
1218 {WLAN_AKM_SUITE_SAE, WPA3_AUTH_SAE_PSK},
1219 #endif /* WL_SAE || WL_CLIENT_SAE */
1220 #ifdef WL_SAE_FT
1221 {WLAN_AKM_SUITE_FT_OVER_SAE, WPA3_AUTH_SAE_PSK | WPA2_AUTH_FT},
1222 #endif /* WL_SAE_FT */
1223 {WLAN_AKM_SUITE_DPP, WPA3_AUTH_DPP_AKM},
1224 {WLAN_AKM_SUITE_FT_8021X_SHA384, WPA3_AUTH_1X_SUITE_B_SHA384 | WPA2_AUTH_FT}
1225 };
1226
1227 #define BUFSZ 8
1228 #define BUFSZN BUFSZ + 1
1229
1230 #define _S(x) #x
1231 #define S(x) _S(x)
1232
1233 #define SOFT_AP_IF_NAME "swlan0"
1234
1235 /* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1236 uint32 fw_assoc_watchdog_ms = 0;
1237 bool fw_assoc_watchdog_started = 0;
1238 #define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1239
wl_channel_to_frequency(u32 chan,chanspec_band_t band)1240 int wl_channel_to_frequency(u32 chan, chanspec_band_t band)
1241 {
1242 if (chan == 0) {
1243 return 0; /* not supported */
1244 }
1245 switch (band) {
1246 case WL_CHANSPEC_BAND_2G:
1247 if (chan == 14)
1248 return 2484;
1249 else if (chan < 14)
1250 return 2407 + chan * 5;
1251 break;
1252 case WL_CHANSPEC_BAND_5G:
1253 if (chan >= 182 && chan <= 196)
1254 return 4000 + chan * 5;
1255 else
1256 return 5000 + chan * 5;
1257 break;
1258 #ifdef WL_6G_BAND
1259 case WL_CHANSPEC_BAND_6G:
1260 if (chan == 2) {
1261 /* Specific handling for channel 2 in 6G */
1262 return 5935;
1263 }
1264 return 5950 + chan * 5;
1265 break;
1266 #endif /* WL_6G_BAND */
1267 default:
1268 WL_ERR(("Invalid Frequency Band\n"));
1269 }
1270 return 0; /* not supported */
1271 }
1272
wl_add_remove_pm_enable_work(struct bcm_cfg80211 * cfg,enum wl_pm_workq_act_type type)1273 static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg,
1274 enum wl_pm_workq_act_type type)
1275 {
1276 u16 wq_duration = 0;
1277
1278 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1279 dhd_pub_t *dhd = NULL;
1280 #endif /* BCMDONGLEHOST && OEM_ANDROID */
1281
1282 if (cfg == NULL)
1283 return;
1284
1285 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1286 dhd = (dhd_pub_t *)(cfg->pub);
1287 #endif /* BCMDONGLEHOST && OEM_ANDROID */
1288
1289 mutex_lock(&cfg->pm_sync);
1290 /*
1291 * Make cancel and schedule work part mutually exclusive
1292 * so that while cancelling, we are sure that there is no
1293 * work getting scheduled.
1294 */
1295 if (delayed_work_pending(&cfg->pm_enable_work)) {
1296 cancel_delayed_work(&cfg->pm_enable_work);
1297
1298 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1299 DHD_PM_WAKE_UNLOCK(cfg->pub);
1300 #endif /* BCMDONGLEHOST && OEM_ANDROID */
1301
1302 }
1303
1304 if (type == WL_PM_WORKQ_SHORT) {
1305 wq_duration = WL_PM_ENABLE_TIMEOUT;
1306 } else if (type == WL_PM_WORKQ_LONG) {
1307 wq_duration = (WL_PM_ENABLE_TIMEOUT*2);
1308 }
1309
1310 /* It should schedule work item only if driver is up */
1311 if (wq_duration) {
1312 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1313 if (dhd->up)
1314 #endif /* defined(BCMDONGLEHOST) && defined(OEM_ANDROID) */
1315 {
1316 if (schedule_delayed_work(&cfg->pm_enable_work,
1317 msecs_to_jiffies((const unsigned int)wq_duration))) {
1318
1319 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
1320 DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub, wq_duration);
1321 #endif /* BCMDONGLEHOST && OEM_ANDROID */
1322 } else {
1323 WL_ERR(("Can't schedule pm work handler\n"));
1324 }
1325 }
1326 }
1327 mutex_unlock(&cfg->pm_sync);
1328 }
1329
1330 /* Return a new chanspec given a legacy chanspec
1331 * Returns INVCHANSPEC on error
1332 */
1333 chanspec_t
wl_chspec_from_legacy(chanspec_t legacy_chspec)1334 wl_chspec_from_legacy(chanspec_t legacy_chspec)
1335 {
1336 chanspec_t chspec;
1337
1338 /* get the channel number */
1339 chspec = LCHSPEC_CHANNEL(legacy_chspec);
1340
1341 /* convert the band */
1342 if (LCHSPEC_IS2G(legacy_chspec)) {
1343 chspec |= WL_CHANSPEC_BAND_2G;
1344 } else {
1345 chspec |= WL_CHANSPEC_BAND_5G;
1346 }
1347
1348 /* convert the bw and sideband */
1349 if (LCHSPEC_IS20(legacy_chspec)) {
1350 chspec |= WL_CHANSPEC_BW_20;
1351 } else {
1352 chspec |= WL_CHANSPEC_BW_40;
1353 if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
1354 chspec |= WL_CHANSPEC_CTL_SB_L;
1355 } else {
1356 chspec |= WL_CHANSPEC_CTL_SB_U;
1357 }
1358 }
1359
1360 if (wf_chspec_malformed(chspec)) {
1361 WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1362 chspec));
1363 return INVCHANSPEC;
1364 }
1365
1366 return chspec;
1367 }
1368
1369 /* Return a legacy chanspec given a new chanspec
1370 * Returns INVCHANSPEC on error
1371 */
1372 static chanspec_t
wl_chspec_to_legacy(chanspec_t chspec)1373 wl_chspec_to_legacy(chanspec_t chspec)
1374 {
1375 chanspec_t lchspec;
1376
1377 if (wf_chspec_malformed(chspec)) {
1378 WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1379 chspec));
1380 return INVCHANSPEC;
1381 }
1382
1383 /* get the channel number */
1384 lchspec = CHSPEC_CHANNEL(chspec);
1385
1386 /* convert the band */
1387 if (CHSPEC_IS2G(chspec)) {
1388 lchspec |= WL_LCHANSPEC_BAND_2G;
1389 } else {
1390 lchspec |= WL_LCHANSPEC_BAND_5G;
1391 }
1392
1393 /* convert the bw and sideband */
1394 if (CHSPEC_IS20(chspec)) {
1395 lchspec |= WL_LCHANSPEC_BW_20;
1396 lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
1397 } else if (CHSPEC_IS40(chspec)) {
1398 lchspec |= WL_LCHANSPEC_BW_40;
1399 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
1400 lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
1401 } else {
1402 lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
1403 }
1404 } else {
1405 /* cannot express the bandwidth */
1406 char chanbuf[CHANSPEC_STR_LEN];
1407 WL_ERR((
1408 "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1409 "to pre-11ac format\n",
1410 wf_chspec_ntoa(chspec, chanbuf), chspec));
1411 return INVCHANSPEC;
1412 }
1413
1414 return lchspec;
1415 }
1416
wl_cfg80211_is_hal_started(struct bcm_cfg80211 * cfg)1417 bool wl_cfg80211_is_hal_started(struct bcm_cfg80211 *cfg)
1418 {
1419 return cfg->hal_started;
1420 }
1421
1422 /* given a chanspec value, do the endian and chanspec version conversion to
1423 * a chanspec_t value
1424 * Returns INVCHANSPEC on error
1425 */
1426 chanspec_t
wl_chspec_host_to_driver(chanspec_t chanspec)1427 wl_chspec_host_to_driver(chanspec_t chanspec)
1428 {
1429 if (ioctl_version == 1) {
1430 chanspec = wl_chspec_to_legacy(chanspec);
1431 if (chanspec == INVCHANSPEC) {
1432 return chanspec;
1433 }
1434 }
1435 chanspec = htodchanspec(chanspec);
1436
1437 return chanspec;
1438 }
1439
1440 /* given a channel value, do the endian and chanspec version conversion to
1441 * a chanspec_t value
1442 * Returns INVCHANSPEC on error
1443 */
1444 chanspec_t
wl_ch_host_to_driver(u16 channel)1445 wl_ch_host_to_driver(u16 channel)
1446 {
1447 chanspec_t chanspec;
1448 chanspec_band_t band;
1449
1450 band = WL_CHANNEL_BAND(channel);
1451
1452 chanspec = wf_create_20MHz_chspec(channel, band);
1453 if (chanspec == INVCHANSPEC) {
1454 return chanspec;
1455 }
1456
1457 return wl_chspec_host_to_driver(chanspec);
1458 }
1459
1460 /* given a chanspec value from the driver, do the endian and chanspec version conversion to
1461 * a chanspec_t value
1462 * Returns INVCHANSPEC on error
1463 */
1464 chanspec_t
wl_chspec_driver_to_host(chanspec_t chanspec)1465 wl_chspec_driver_to_host(chanspec_t chanspec)
1466 {
1467 chanspec = dtohchanspec(chanspec);
1468 if (ioctl_version == 1) {
1469 chanspec = wl_chspec_from_legacy(chanspec);
1470 }
1471
1472 return chanspec;
1473 }
1474
1475 /*
1476 * convert ASCII string to MAC address (colon-delimited format)
1477 * eg: 00:11:22:33:44:55
1478 */
1479 int
wl_cfg80211_ether_atoe(const char * a,struct ether_addr * n)1480 wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
1481 {
1482 char *c = NULL;
1483 int count = 0;
1484
1485 bzero(n, ETHER_ADDR_LEN);
1486 for (;;) {
1487 n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
1488 if (!*c++ || count == ETHER_ADDR_LEN)
1489 break;
1490 a = c;
1491 }
1492 return (count == ETHER_ADDR_LEN);
1493 }
1494
1495 /* There isn't a lot of sense in it, but you can transmit anything you like */
1496 static const struct ieee80211_txrx_stypes
1497 wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
1498 #ifdef WLMESH_CFG80211
1499 [NL80211_IFTYPE_MESH_POINT] = {
1500 .tx = 0xffff,
1501 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1502 BIT(IEEE80211_STYPE_AUTH >> 4)
1503 },
1504 #endif /* WLMESH_CFG80211 */
1505 [NL80211_IFTYPE_ADHOC] = {
1506 .tx = 0xffff,
1507 .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
1508 },
1509 [NL80211_IFTYPE_STATION] = {
1510 .tx = 0xffff,
1511 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1512 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1513 #ifdef WL_CLIENT_SAE
1514 | BIT(IEEE80211_STYPE_AUTH >> 4)
1515 #endif /* WL_CLIENT_SAE */
1516 },
1517 [NL80211_IFTYPE_AP] = {
1518 .tx = 0xffff,
1519 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1520 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1521 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1522 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1523 BIT(IEEE80211_STYPE_AUTH >> 4) |
1524 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1525 BIT(IEEE80211_STYPE_ACTION >> 4)
1526 },
1527 [NL80211_IFTYPE_AP_VLAN] = {
1528 /* copy AP */
1529 .tx = 0xffff,
1530 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1531 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1532 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1533 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1534 BIT(IEEE80211_STYPE_AUTH >> 4) |
1535 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1536 BIT(IEEE80211_STYPE_ACTION >> 4)
1537 },
1538 [NL80211_IFTYPE_P2P_CLIENT] = {
1539 .tx = 0xffff,
1540 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1541 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1542 },
1543 [NL80211_IFTYPE_P2P_GO] = {
1544 .tx = 0xffff,
1545 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
1546 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
1547 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
1548 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
1549 BIT(IEEE80211_STYPE_AUTH >> 4) |
1550 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
1551 BIT(IEEE80211_STYPE_ACTION >> 4)
1552 },
1553 #if defined(WL_CFG80211_P2P_DEV_IF)
1554 [NL80211_IFTYPE_P2P_DEVICE] = {
1555 .tx = 0xffff,
1556 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1557 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
1558 },
1559 #endif /* WL_CFG80211_P2P_DEV_IF */
1560 };
1561
swap_key_from_BE(struct wl_wsec_key * key)1562 static void swap_key_from_BE(struct wl_wsec_key *key)
1563 {
1564 key->index = htod32(key->index);
1565 key->len = htod32(key->len);
1566 key->algo = htod32(key->algo);
1567 key->flags = htod32(key->flags);
1568 key->rxiv.hi = htod32(key->rxiv.hi);
1569 key->rxiv.lo = htod16(key->rxiv.lo);
1570 key->iv_initialized = htod32(key->iv_initialized);
1571 }
1572
swap_key_to_BE(struct wl_wsec_key * key)1573 static void swap_key_to_BE(struct wl_wsec_key *key)
1574 {
1575 key->index = dtoh32(key->index);
1576 key->len = dtoh32(key->len);
1577 key->algo = dtoh32(key->algo);
1578 key->flags = dtoh32(key->flags);
1579 key->rxiv.hi = dtoh32(key->rxiv.hi);
1580 key->rxiv.lo = dtoh16(key->rxiv.lo);
1581 key->iv_initialized = dtoh32(key->iv_initialized);
1582 }
1583
1584 #if defined(WL_FW_OCE_AP_SELECT)
wl_cfg80211_is_oce_ap(struct wiphy * wiphy,const u8 * bssid_hint)1585 bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint)
1586 {
1587 const u8 *parse = NULL;
1588 bcm_tlv_t *ie;
1589 const struct cfg80211_bss_ies *ies;
1590 u32 len;
1591 struct cfg80211_bss *bss;
1592
1593 bss = CFG80211_GET_BSS(wiphy, NULL, bssid_hint, 0, 0);
1594 if (!bss) {
1595 WL_ERR(("Unable to find AP in the cache"));
1596 return false;
1597 }
1598
1599 if (rcu_access_pointer(bss->ies)) {
1600 ies = rcu_access_pointer(bss->ies);
1601 parse = ies->data;
1602 len = ies->len;
1603 } else {
1604 WL_ERR(("ies is NULL"));
1605 return false;
1606 }
1607
1608 while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_VS_ID))) {
1609 if (wl_cfgoce_is_oce_ie((const uint8*)ie, (u8 const **)&parse, &len) == TRUE) {
1610 return true;
1611 } else {
1612 ie = bcm_next_tlv((const bcm_tlv_t*) ie, &len);
1613 if (!ie) {
1614 return false;
1615 }
1616 parse = (uint8 *)ie;
1617 WL_DBG(("NON OCE IE. next ie ptr:%p", parse));
1618 }
1619 }
1620 WL_DBG(("OCE IE NOT found"));
1621 return false;
1622 }
1623 #endif /* WL_FW_OCE_AP_SELECT */
1624
1625 /* Dump the contents of the encoded wps ie buffer and get pbc value */
1626 static void
wl_validate_wps_ie(const char * wps_ie,s32 wps_ie_len,bool * pbc)1627 wl_validate_wps_ie(const char *wps_ie, s32 wps_ie_len, bool *pbc)
1628 {
1629 #define WPS_IE_FIXED_LEN 6
1630 s16 len;
1631 const u8 *subel = NULL;
1632 u16 subelt_id;
1633 u16 subelt_len;
1634 u16 val;
1635 u8 *valptr = (uint8*) &val;
1636 if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
1637 WL_ERR(("invalid argument : NULL\n"));
1638 return;
1639 }
1640 len = (s16)wps_ie[TLV_LEN_OFF];
1641
1642 if (len > wps_ie_len) {
1643 WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
1644 return;
1645 }
1646 WL_DBG(("wps_ie len=%d\n", len));
1647 len -= 4; /* for the WPS IE's OUI, oui_type fields */
1648 subel = wps_ie + WPS_IE_FIXED_LEN;
1649 while (len >= 4) { /* must have attr id, attr len fields */
1650 valptr[0] = *subel++;
1651 valptr[1] = *subel++;
1652 subelt_id = HTON16(val);
1653
1654 valptr[0] = *subel++;
1655 valptr[1] = *subel++;
1656 subelt_len = HTON16(val);
1657
1658 len -= 4; /* for the attr id, attr len fields */
1659 len -= (s16)subelt_len; /* for the remaining fields in this attribute */
1660 if (len < 0) {
1661 break;
1662 }
1663 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
1664 subel, subelt_id, subelt_len));
1665
1666 if (subelt_id == WPS_ID_VERSION) {
1667 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
1668 } else if (subelt_id == WPS_ID_REQ_TYPE) {
1669 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
1670 } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
1671 valptr[0] = *subel;
1672 valptr[1] = *(subel + 1);
1673 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
1674 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
1675 char devname[33];
1676 int namelen = MIN(subelt_len, (sizeof(devname) - 1));
1677
1678 if (namelen) {
1679 memcpy(devname, subel, namelen);
1680 devname[namelen] = '\0';
1681 /* Printing len as rx'ed in the IE */
1682 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1683 devname, subelt_len));
1684 }
1685 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
1686 valptr[0] = *subel;
1687 valptr[1] = *(subel + 1);
1688 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
1689 *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
1690 } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
1691 valptr[0] = *subel;
1692 valptr[1] = *(subel + 1);
1693 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
1694 valptr[0] = *(subel + 6);
1695 valptr[1] = *(subel + 7);
1696 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
1697 } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
1698 valptr[0] = *subel;
1699 valptr[1] = *(subel + 1);
1700 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
1701 valptr[0] = *(subel + 6);
1702 valptr[1] = *(subel + 7);
1703 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
1704 } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
1705 valptr[0] = *subel;
1706 valptr[1] = *(subel + 1);
1707 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
1708 ": cat=%u\n", HTON16(val)));
1709 } else {
1710 WL_DBG((" unknown attr 0x%x\n", subelt_id));
1711 }
1712
1713 subel += subelt_len;
1714 }
1715 }
1716
wl_set_tx_power(struct net_device * dev,enum nl80211_tx_power_setting type,s32 dbm)1717 s32 wl_set_tx_power(struct net_device *dev,
1718 enum nl80211_tx_power_setting type, s32 dbm)
1719 {
1720 s32 err = 0;
1721 s32 disable = 0;
1722 s32 txpwrqdbm;
1723 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1724
1725 /* Make sure radio is off or on as far as software is concerned */
1726 disable = WL_RADIO_SW_DISABLE << 16;
1727 disable = htod32(disable);
1728 err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable));
1729 if (unlikely(err)) {
1730 WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
1731 return err;
1732 }
1733
1734 if (dbm > 0xffff)
1735 dbm = 0xffff;
1736 txpwrqdbm = dbm * 4;
1737 #ifdef SUPPORT_WL_TXPOWER
1738 if (type == NL80211_TX_POWER_AUTOMATIC)
1739 txpwrqdbm = 127;
1740 else
1741 txpwrqdbm |= WL_TXPWR_OVERRIDE;
1742 #endif /* SUPPORT_WL_TXPOWER */
1743 err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
1744 sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
1745 &cfg->ioctl_buf_sync);
1746 if (unlikely(err))
1747 WL_ERR(("qtxpower error (%d)\n", err));
1748 else
1749 WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
1750
1751 return err;
1752 }
1753
wl_get_tx_power(struct net_device * dev,s32 * dbm)1754 s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
1755 {
1756 s32 err = 0;
1757 s32 txpwrdbm;
1758 char ioctl_buf[WLC_IOCTL_SMLEN];
1759
1760 err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
1761 NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
1762 if (unlikely(err)) {
1763 WL_ERR(("error (%d)\n", err));
1764 return err;
1765 }
1766
1767 memcpy(&txpwrdbm, ioctl_buf, sizeof(txpwrdbm));
1768 txpwrdbm = dtoh32(txpwrdbm);
1769 *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
1770
1771 WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
1772
1773 return err;
1774 }
1775
wl_cfg80211_get_shared_freq(struct wiphy * wiphy)1776 chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
1777 {
1778 chanspec_t chspec;
1779 int cur_band, err = 0;
1780 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1781 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
1782 struct ether_addr bssid;
1783 wl_bss_info_t *bss = NULL;
1784 u16 channel = WL_P2P_TEMP_CHAN;
1785 char *buf;
1786
1787 bzero(&bssid, sizeof(bssid));
1788 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) {
1789 /* STA interface is not associated. So start the new interface on a temp
1790 * channel . Later proper channel will be applied by the above framework
1791 * via set_channel (cfg80211 API).
1792 */
1793 WL_DBG(("Not associated. Return a temp channel. \n"));
1794 cur_band = 0;
1795 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(int));
1796 if (unlikely(err)) {
1797 WL_ERR(("Get band failed\n"));
1798 } else if (cur_band == WLC_BAND_5G || cur_band == WLC_BAND_6G) {
1799 channel = WL_P2P_TEMP_CHAN_5G;
1800 }
1801 return wl_ch_host_to_driver(channel);
1802 }
1803
1804 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
1805 if (!buf) {
1806 WL_ERR(("buf alloc failed. use temp channel\n"));
1807 return wl_ch_host_to_driver(channel);
1808 }
1809
1810 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1811 if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf,
1812 WL_EXTRA_BUF_MAX))) {
1813 WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1814 chspec = wl_ch_host_to_driver(channel);
1815 }
1816 else {
1817 bss = (wl_bss_info_t *) (buf + 4);
1818 chspec = bss->chanspec;
1819 #ifdef WL_6G_BAND
1820 /* Avoid p2p bring up in 6G based on bssinfo */
1821 if (CHSPEC_IS6G(chspec)) {
1822 channel = WL_P2P_TEMP_CHAN_5G;
1823 chspec = wl_ch_host_to_driver(channel);
1824 }
1825 #endif /* WL_6G_BAND */
1826 WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
1827 }
1828
1829 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
1830 return chspec;
1831 }
1832
1833 static void
wl_wlfc_enable(struct bcm_cfg80211 * cfg,bool enable)1834 wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable)
1835 {
1836 #ifdef PROP_TXSTATUS_VSDB
1837 #if defined(BCMSDIO) || defined(BCMDBUS)
1838 bool wlfc_enabled = FALSE;
1839 s32 err, up =1;
1840 dhd_pub_t *dhd;
1841 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1842
1843 dhd = (dhd_pub_t *)(cfg->pub);
1844 if (!dhd) {
1845 return;
1846 }
1847
1848 if (enable) {
1849 if (!cfg->wlfc_on && !disable_proptx) {
1850 dhd_wlfc_get_enable(dhd, &wlfc_enabled);
1851 if (!wlfc_enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1852 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1853 dhd_wlfc_init(dhd);
1854 err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32));
1855 if (err < 0)
1856 WL_ERR(("WLC_UP return err:%d\n", err));
1857 }
1858 cfg->wlfc_on = true;
1859 WL_DBG(("wlfc_on:%d \n", cfg->wlfc_on));
1860 }
1861 } else if (dhd->conf->disable_proptx != 0){
1862 dhd_wlfc_deinit(dhd);
1863 cfg->wlfc_on = false;
1864 }
1865 #endif /* BCMSDIO || BCMDBUS */
1866 #endif /* PROP_TXSTATUS_VSDB */
1867 }
1868
1869 struct wireless_dev *
wl_cfg80211_p2p_if_add(struct bcm_cfg80211 * cfg,wl_iftype_t wl_iftype,char const * name,u8 * mac_addr,s32 * ret_err)1870 wl_cfg80211_p2p_if_add(struct bcm_cfg80211 *cfg,
1871 wl_iftype_t wl_iftype,
1872 char const *name, u8 *mac_addr, s32 *ret_err)
1873 {
1874 u16 chspec;
1875 s16 cfg_type;
1876 long timeout;
1877 s32 err;
1878 u16 p2p_iftype;
1879 int dhd_mode;
1880 struct net_device *new_ndev = NULL;
1881 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
1882 struct ether_addr *p2p_addr;
1883
1884 *ret_err = BCME_OK;
1885 if (!cfg->p2p) {
1886 WL_ERR(("p2p not initialized\n"));
1887 return NULL;
1888 }
1889
1890 #if defined(WL_CFG80211_P2P_DEV_IF)
1891 if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
1892 /* Handle Dedicated P2P discovery Interface */
1893 return wl_cfgp2p_add_p2p_disc_if(cfg);
1894 }
1895 #endif /* WL_CFG80211_P2P_DEV_IF */
1896
1897 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1898 p2p_iftype = WL_P2P_IF_GO;
1899 } else {
1900 p2p_iftype = WL_P2P_IF_CLIENT;
1901 }
1902
1903 /* Dual p2p doesn't support multiple P2PGO interfaces,
1904 * p2p_go_count is the counter for GO creation
1905 * requests.
1906 */
1907 if ((cfg->p2p->p2p_go_count > 0) && (wl_iftype == WL_IF_TYPE_P2P_GO)) {
1908 WL_ERR(("FW does not support multiple GO\n"));
1909 *ret_err = -ENOTSUPP;
1910 return NULL;
1911 }
1912 if (!cfg->p2p->on) {
1913 p2p_on(cfg) = true;
1914 wl_cfgp2p_set_firm_p2p(cfg);
1915 wl_cfgp2p_init_discovery(cfg);
1916 }
1917
1918 strlcpy(cfg->p2p->vir_ifname, name, sizeof(cfg->p2p->vir_ifname));
1919 /* In concurrency case, STA may be already associated in a particular channel.
1920 * so retrieve the current channel of primary interface and then start the virtual
1921 * interface on that.
1922 */
1923 chspec = wl_cfg80211_get_shared_freq(wiphy);
1924
1925 /* For P2P mode, use P2P-specific driver features to create the
1926 * bss: "cfg p2p_ifadd"
1927 */
1928 wl_set_p2p_status(cfg, IF_ADDING);
1929 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
1930 cfg_type = wl_cfgp2p_get_conn_idx(cfg);
1931 if (cfg_type < BCME_OK) {
1932 wl_clr_p2p_status(cfg, IF_ADDING);
1933 WL_ERR(("Failed to get connection idx for p2p interface"
1934 ", error code = %d\n", cfg_type));
1935 return NULL;
1936 }
1937
1938 p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
1939 memcpy(p2p_addr->octet, mac_addr, ETH_ALEN);
1940
1941 err = wl_cfgp2p_ifadd(cfg, p2p_addr,
1942 htod32(p2p_iftype), chspec);
1943 if (unlikely(err)) {
1944 wl_clr_p2p_status(cfg, IF_ADDING);
1945 WL_ERR((" virtual iface add failed (%d) \n", err));
1946 return NULL;
1947 }
1948
1949 /* Wait for WLC_E_IF event with IF_ADD opcode */
1950 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1951 ((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
1952 (cfg->if_event_info.valid)),
1953 msecs_to_jiffies(MAX_WAIT_TIME));
1954 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
1955 wl_if_event_info *event = &cfg->if_event_info;
1956 new_ndev = wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg), event,
1957 event->mac, cfg->p2p->vir_ifname, false);
1958 if (unlikely(!new_ndev)) {
1959 goto fail;
1960 }
1961
1962 if (wl_iftype == WL_IF_TYPE_P2P_GO) {
1963 cfg->p2p->p2p_go_count++;
1964 }
1965 /* Fill p2p specific data */
1966 wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
1967 wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
1968
1969 WL_ERR((" virtual interface(%s) is "
1970 "created net attach done\n", cfg->p2p->vir_ifname));
1971 #if defined(BCMDONGLEHOST)
1972 dhd_mode = (wl_iftype == WL_IF_TYPE_P2P_GC) ?
1973 DHD_FLAG_P2P_GC_MODE : DHD_FLAG_P2P_GO_MODE;
1974 DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
1975 #endif /* defined(BCMDONGLEHOST) */
1976 /* reinitialize completion to clear previous count */
1977 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1978 INIT_COMPLETION(cfg->iface_disable);
1979 #else
1980 init_completion(&cfg->iface_disable);
1981 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
1982
1983 return new_ndev->ieee80211_ptr;
1984 }
1985
1986 fail:
1987 return NULL;
1988 }
1989
1990 void
wl_cfg80211_iface_state_ops(struct wireless_dev * wdev,wl_interface_state_t state,wl_iftype_t wl_iftype,u16 wl_mode)1991 wl_cfg80211_iface_state_ops(struct wireless_dev *wdev,
1992 wl_interface_state_t state,
1993 wl_iftype_t wl_iftype, u16 wl_mode)
1994 {
1995 struct net_device *ndev;
1996 struct bcm_cfg80211 *cfg;
1997 dhd_pub_t *dhd;
1998 s32 bssidx;
1999
2000 WL_DBG(("state:%s wl_iftype:%d mode:%d\n",
2001 wl_if_state_strs[state], wl_iftype, wl_mode));
2002 if (!wdev) {
2003 WL_ERR(("wdev null\n"));
2004 return;
2005 }
2006
2007 if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_NAN_NMI)) {
2008 /* P2P discovery is a netless device and uses a
2009 * hidden bsscfg interface in fw. Don't apply the
2010 * iface ops state changes for p2p discovery I/F.
2011 * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
2012 * Don't apply iface ops state changes for NMI I/F.
2013 */
2014 return;
2015 }
2016
2017 cfg = wiphy_priv(wdev->wiphy);
2018 ndev = wdev->netdev;
2019 dhd = (dhd_pub_t *)(cfg->pub);
2020
2021 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2022 if (!ndev || (bssidx < 0)) {
2023 WL_ERR(("ndev null. skip iface state ops\n"));
2024 return;
2025 }
2026
2027 switch (state) {
2028 case WL_IF_CREATE_REQ:
2029 #ifdef WL_BCNRECV
2030 /* check fakeapscan in progress then abort */
2031 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
2032 #endif /* WL_BCNRECV */
2033 wl_cfgscan_cancel_scan(cfg);
2034 wl_wlfc_enable(cfg, true);
2035 #ifdef WLTDLS
2036 /* disable TDLS if number of connected interfaces is >= 1 */
2037 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_CREATE, false);
2038 #endif /* WLTDLS */
2039 break;
2040 case WL_IF_DELETE_REQ:
2041 #ifdef WL_WPS_SYNC
2042 wl_wps_handle_ifdel(ndev);
2043 #endif /* WPS_SYNC */
2044 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
2045 /* Send completion for any pending scans */
2046 wl_cfgscan_cancel_scan(cfg);
2047 }
2048
2049 #ifdef CUSTOM_SET_CPUCORE
2050 dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
2051 if (!(dhd->chan_isvht80)) {
2052 dhd_set_cpucore(dhd, FALSE);
2053 }
2054 #endif /* CUSTOM_SET_CPUCORE */
2055 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
2056 break;
2057 case WL_IF_CREATE_DONE:
2058 if (wl_mode == WL_MODE_BSS) {
2059 /* Common code for sta type interfaces - STA, GC */
2060 /* Enable firmware key buffering before sent 4-way M4 */
2061 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2062 }
2063 if (wl_iftype == WL_IF_TYPE_P2P_GC) {
2064 /* Disable firmware roaming for P2P interface */
2065 wldev_iovar_setint(ndev, "roam_off", 1);
2066 wldev_iovar_setint(ndev, "bcn_timeout", dhd->conf->bcn_timeout);
2067 {
2068 int assoc_retry = 3;
2069 #if defined(CUSTOM_ASSOC_RETRY_MAX)
2070 assoc_retry = CUSTOM_ASSOC_RETRY_MAX;
2071 #endif /* CUSTOM_ASSOC_RETRY_MAX */
2072 /* set retry_max to CUSTOM_ASSOC_RETRY_MAX(3) */
2073 wldev_iovar_setint(ndev, "assoc_retry_max", assoc_retry);
2074 }
2075 }
2076 if (wl_mode == WL_MODE_AP) {
2077 /* Common code for AP/GO */
2078 #if defined(SUPPORT_AP_POWERSAVE) && defined(BCMDONGLEHOST)
2079 dhd_set_ap_powersave(dhd, 0, TRUE);
2080 #endif /* SUPPORT_AP_POWERSAVE && BCMDONGLEHOST */
2081 }
2082 break;
2083 case WL_IF_DELETE_DONE:
2084 #ifdef WLTDLS
2085 /* Enable back TDLS if connected interface is <= 1 */
2086 wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2087 #endif /* WLTDLS */
2088 wl_wlfc_enable(cfg, false);
2089 break;
2090 case WL_IF_CHANGE_REQ:
2091 /* Flush existing IEs from firmware on role change */
2092 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
2093 break;
2094 case WL_IF_CHANGE_DONE:
2095 if (wl_mode == WL_MODE_BSS) {
2096 #ifdef SUPPORT_AP_POWERSAVE
2097 dhd_set_ap_powersave(dhd, 0, FALSE);
2098 #endif /* SUPPORT_AP_POWERSAVE */
2099 /* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2100 wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2101 }
2102 break;
2103
2104 default:
2105 WL_ERR(("Unsupported state: %d\n", state));
2106 return;
2107 }
2108 }
2109
2110 static s32
wl_cfg80211_p2p_if_del(struct wiphy * wiphy,struct wireless_dev * wdev)2111 wl_cfg80211_p2p_if_del(struct wiphy *wiphy, struct wireless_dev *wdev)
2112 {
2113 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2114 s16 bssidx;
2115 s16 err;
2116 s32 cfg_type;
2117 struct net_device *ndev;
2118 long timeout;
2119 struct ether_addr p2p_dev_addr = {{0}};
2120
2121 if (unlikely(!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
2122 WL_INFORM_MEM(("device is not ready\n"));
2123 return BCME_NOTFOUND;
2124 }
2125
2126 #ifdef WL_CFG80211_P2P_DEV_IF
2127 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2128 /* Handle dedicated P2P discovery interface. */
2129 return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
2130 }
2131 #endif /* WL_CFG80211_P2P_DEV_IF */
2132
2133 /* Handle P2P Group Interface */
2134 bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2135 if (bssidx <= 0) {
2136 WL_ERR(("bssidx not found\n"));
2137 return BCME_NOTFOUND;
2138 }
2139 if (wl_cfgp2p_find_type(cfg, bssidx, &cfg_type) != BCME_OK) {
2140 /* Couldn't find matching iftype */
2141 WL_MEM(("non P2P interface\n"));
2142 return BCME_NOTFOUND;
2143 }
2144
2145 ndev = wdev->netdev;
2146 (void)memcpy_s(p2p_dev_addr.octet, ETHER_ADDR_LEN,
2147 ndev->dev_addr, ETHER_ADDR_LEN);
2148
2149 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2150 wl_clr_p2p_status(cfg, IF_ADDING);
2151
2152 /* for GO */
2153 if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
2154 wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
2155 cfg->p2p->p2p_go_count--;
2156 /* disable interface before bsscfg free */
2157 err = wl_cfgp2p_ifdisable(cfg, &p2p_dev_addr);
2158 /* if fw doesn't support "ifdis",
2159 do not wait for link down of ap mode
2160 */
2161 if (err == 0) {
2162 WL_ERR(("Wait for Link Down event for GO !!!\n"));
2163 wait_for_completion_timeout(&cfg->iface_disable,
2164 msecs_to_jiffies(500));
2165 } else if (err != BCME_UNSUPPORTED) {
2166 msleep(300);
2167 }
2168 } else {
2169 /* GC case */
2170 if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
2171 WL_ERR(("Wait for Link Down event for GC !\n"));
2172 wait_for_completion_timeout
2173 (&cfg->iface_disable, msecs_to_jiffies(500));
2174 }
2175
2176 /* Force P2P disconnect in iface down context */
2177 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
2178 WL_INFORM_MEM(("force send disconnect event\n"));
2179 CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
2180 wl_clr_drv_status(cfg, AUTHORIZED, ndev);
2181 }
2182 }
2183
2184 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
2185 wl_set_p2p_status(cfg, IF_DELETING);
2186 DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
2187
2188 err = wl_cfgp2p_ifdel(cfg, &p2p_dev_addr);
2189 if (unlikely(err)) {
2190 WL_ERR(("P2P IFDEL operation failed, error code = %d\n", err));
2191 err = BCME_ERROR;
2192 goto fail;
2193 } else {
2194 /* Wait for WLC_E_IF event */
2195 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2196 ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
2197 (cfg->if_event_info.valid)),
2198 msecs_to_jiffies(MAX_WAIT_TIME));
2199 if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
2200 cfg->if_event_info.valid) {
2201 WL_ERR(("P2P IFDEL operation done\n"));
2202 err = BCME_OK;
2203 } else {
2204 WL_ERR(("IFDEL didn't complete properly\n"));
2205 err = -EINVAL;
2206 }
2207 }
2208
2209 fail:
2210 /* Even in failure case, attempt to remove the host data structure.
2211 * Firmware would be cleaned up via WiFi reset done by the
2212 * user space from hang event context (for android only).
2213 */
2214 bzero(cfg->p2p->vir_ifname, IFNAMSIZ);
2215 wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
2216 wl_to_p2p_bss_ndev(cfg, cfg_type) = NULL;
2217 wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, cfg_type));
2218
2219 /* Clear our saved WPS and P2P IEs for the discovery BSS */
2220 wl_cfg80211_clear_p2p_disc_ies(cfg);
2221 #ifdef BCMDONGLEHOST
2222 dhd_net_if_lock(ndev);
2223 #endif /* BCMDONGLEHOST */
2224 if (cfg->if_event_info.ifidx) {
2225 /* Remove interface except for primary ifidx */
2226 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
2227 }
2228 #ifdef BCMDONGLEHOST
2229 dhd_net_if_unlock(ndev);
2230 #endif /* BCMDONGLEHOST */
2231 return err;
2232 }
2233
2234 static struct wireless_dev *
wl_cfg80211_add_monitor_if(struct wiphy * wiphy,const char * name)2235 wl_cfg80211_add_monitor_if(struct wiphy *wiphy, const char *name)
2236 {
2237 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
2238 WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2239 return ERR_PTR(-EOPNOTSUPP);
2240 #else
2241 struct wireless_dev *wdev;
2242 struct net_device* ndev = NULL;
2243
2244 dhd_add_monitor(name, &ndev);
2245
2246 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2247 if (!wdev) {
2248 WL_ERR(("wireless_dev alloc failed! \n"));
2249 goto fail;
2250 }
2251
2252 wdev->wiphy = wiphy;
2253 wdev->iftype = NL80211_IFTYPE_MONITOR;
2254 ndev->ieee80211_ptr = wdev;
2255 SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
2256
2257 WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
2258 return ndev->ieee80211_ptr;
2259 fail:
2260 return ERR_PTR(-EOPNOTSUPP);
2261 #endif // endif
2262 }
2263
2264 static struct wireless_dev *
wl_cfg80211_add_ibss(struct wiphy * wiphy,u16 wl_iftype,char const * name)2265 wl_cfg80211_add_ibss(struct wiphy *wiphy, u16 wl_iftype, char const *name)
2266 {
2267 #ifdef WLAIBSS_MCHAN
2268 /* AIBSS */
2269 return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
2270 #else
2271 /* Normal IBSS */
2272 WL_ERR(("IBSS not supported on Virtual iface\n"));
2273 return NULL;
2274 #endif
2275 }
2276
2277 #ifdef DNGL_AXI_ERROR_LOGGING
2278 static s32
_wl_cfg80211_check_axi_error(struct bcm_cfg80211 * cfg)2279 _wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg)
2280 {
2281 s32 ret = BCME_OK;
2282 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2283 hnd_ext_trap_hdr_t *hdr;
2284 int axi_host_error_size;
2285 uint8 *new_dst;
2286 uint32 *ext_data = dhd->extended_trap_data;
2287 struct file *fp = NULL;
2288 char *filename = DHD_COMMON_DUMP_PATH
2289 DHD_DUMP_AXI_ERROR_FILENAME
2290 DHD_DUMP_HAL_FILENAME_SUFFIX;
2291
2292 WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename));
2293
2294 fp = filp_open(filename, O_RDONLY, 0);
2295
2296 if (IS_ERR(fp) || (fp == NULL)) {
2297 WL_ERR(("%s: Couldn't read the file, err %ld,File [%s] No previous axi error \n",
2298 __FUNCTION__, PTR_ERR(fp), filename));
2299 return ret;
2300 }
2301
2302 kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t));
2303 filp_close(fp, NULL);
2304
2305 /* Delete axi error info file */
2306 if (dhd_file_delete(filename) < 0) {
2307 WL_ERR(("%s(): Failed to delete file: %s\n", __FUNCTION__, filename));
2308 return ret;
2309 }
2310 WL_ERR(("%s(): Success to delete file: %s\n", __FUNCTION__, filename));
2311
2312 if (dhd->axi_err_dump->etd_axi_error_v1.signature != HND_EXT_TRAP_AXIERROR_SIGNATURE) {
2313 WL_ERR(("%s: Invalid AXI signature: 0x%x\n",
2314 __FUNCTION__, dhd->axi_err_dump->etd_axi_error_v1.signature));
2315 }
2316
2317 /* First word is original trap_data */
2318 ext_data++;
2319
2320 /* Followed by the extended trap data header */
2321 hdr = (hnd_ext_trap_hdr_t *)ext_data;
2322 new_dst = hdr->data;
2323
2324 axi_host_error_size = sizeof(dhd->axi_err_dump->axid)
2325 + sizeof(dhd->axi_err_dump->fault_address);
2326
2327 /* TAG_TRAP_AXI_HOST_INFO tlv : host's axid, fault address */
2328 new_dst = bcm_write_tlv(TAG_TRAP_AXI_HOST_INFO,
2329 (const void *)dhd->axi_err_dump,
2330 axi_host_error_size, new_dst);
2331
2332 /* TAG_TRAP_AXI_ERROR tlv */
2333 new_dst = bcm_write_tlv(TAG_TRAP_AXI_ERROR,
2334 (const void *)&dhd->axi_err_dump->etd_axi_error_v1,
2335 sizeof(dhd->axi_err_dump->etd_axi_error_v1), new_dst);
2336 hdr->len = new_dst - hdr->data;
2337
2338 dhd->dongle_trap_occured = TRUE;
2339 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2340 copy_hang_info_trap(dhd);
2341 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2342 memset(dhd->axi_err_dump, 0, sizeof(dhd_axi_error_dump_t));
2343
2344 dhd->hang_reason = HANG_REASON_DONGLE_TRAP;
2345 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2346 ret = BCME_ERROR;
2347 return ret;
2348 }
2349 #endif /* DNGL_AXI_ERROR_LOGGING */
2350
2351 /* All Android/Linux private/Vendor Interface calls should make
2352 * use of below API for interface creation.
2353 */
2354 struct wireless_dev *
wl_cfg80211_add_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,wl_iftype_t wl_iftype,const char * name,u8 * mac)2355 wl_cfg80211_add_if(struct bcm_cfg80211 *cfg,
2356 struct net_device *primary_ndev,
2357 wl_iftype_t wl_iftype, const char *name, u8 *mac)
2358 {
2359 u8 mac_addr[ETH_ALEN];
2360 s32 err = -ENODEV;
2361 struct wireless_dev *wdev = NULL;
2362 struct wiphy *wiphy;
2363 s32 wl_mode;
2364 #if defined(BCMDONGLEHOST)
2365 dhd_pub_t *dhd;
2366 #endif /* BCMDONGLEHOST */
2367 wl_iftype_t macaddr_iftype = wl_iftype;
2368
2369 WL_INFORM_MEM(("if name: %s, wl_iftype:%d \n",
2370 name ? name : "NULL", wl_iftype));
2371 if (!cfg || !primary_ndev || !name) {
2372 WL_ERR(("cfg/ndev/name ptr null\n"));
2373 return NULL;
2374 }
2375 if (wl_cfg80211_get_wdev_from_ifname(cfg, name)) {
2376 WL_ERR(("Interface name %s exists!\n", name));
2377 return NULL;
2378 }
2379
2380 wiphy = bcmcfg_to_wiphy(cfg);
2381 #if defined(BCMDONGLEHOST)
2382 dhd = (dhd_pub_t *)(cfg->pub);
2383 if (!dhd) {
2384 return NULL;
2385 }
2386 #endif /* BCMDONGLEHOST */
2387
2388 if ((wl_mode = wl_iftype_to_mode(wl_iftype)) < 0) {
2389 return NULL;
2390 }
2391 mutex_lock(&cfg->if_sync);
2392 #ifdef WL_NAN
2393 if (wl_iftype == WL_IF_TYPE_NAN) {
2394 /*
2395 * Bypass the role conflict check for NDI and handle it
2396 * from dp req and dp resp context
2397 * because in aware comms, ndi gets created soon after nan enable.
2398 */
2399 } else
2400 #endif /* WL_NAN */
2401 #ifdef WL_IFACE_MGMT
2402 /* Allow wdev interface creation for p2p discovery to avoid failures
2403 * in user supplicant initialization. The role conflict rules will be
2404 * applied from discovery context if userspace tries to use discovery.
2405 */
2406 if ((wl_iftype != WL_IF_TYPE_P2P_DISC) &&
2407 (err = wl_cfg80211_handle_if_role_conflict(cfg, wl_iftype)) < 0) {
2408 mutex_unlock(&cfg->if_sync);
2409 return NULL;
2410 }
2411 #endif /* WL_IFACE_MGMT */
2412 #ifdef DNGL_AXI_ERROR_LOGGING
2413 /* Check the previous smmu fault error */
2414 if ((err = _wl_cfg80211_check_axi_error(cfg)) < 0) {
2415 mutex_unlock(&cfg->if_sync);
2416 return NULL;
2417 }
2418 #endif /* DNGL_AXI_ERROR_LOGGING */
2419 /* Protect the interace op context */
2420 /* Do pre-create ops */
2421 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CREATE_REQ,
2422 wl_iftype, wl_mode);
2423
2424 if (strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)) == 0) {
2425 macaddr_iftype = WL_IF_TYPE_AP;
2426 }
2427
2428 if (mac) {
2429 /* If mac address is provided, use that */
2430 memcpy(mac_addr, mac, ETH_ALEN);
2431 } else if ((wl_get_vif_macaddr(cfg, macaddr_iftype, mac_addr) != BCME_OK)) {
2432 /* Fetch the mac address to be used for virtual interface */
2433 err = -EINVAL;
2434 goto fail;
2435 }
2436
2437 switch (wl_iftype) {
2438 case WL_IF_TYPE_IBSS:
2439 wdev = wl_cfg80211_add_ibss(wiphy, wl_iftype, name);
2440 break;
2441 case WL_IF_TYPE_MONITOR:
2442 wdev = wl_cfg80211_add_monitor_if(wiphy, name);
2443 break;
2444 case WL_IF_TYPE_STA:
2445 case WL_IF_TYPE_AP:
2446 case WL_IF_TYPE_NAN:
2447 if (cfg->iface_cnt >= (IFACE_MAX_CNT - 1)) {
2448 WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
2449 cfg->iface_cnt));
2450 err = -ENOTSUPP;
2451 goto fail;
2452 }
2453 wdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
2454 wl_iftype, mac_addr, name);
2455 break;
2456 case WL_IF_TYPE_P2P_DISC:
2457 case WL_IF_TYPE_P2P_GO:
2458 /* Intentional fall through */
2459 case WL_IF_TYPE_P2P_GC:
2460 if (cfg->p2p_supported) {
2461 wdev = wl_cfg80211_p2p_if_add(cfg, wl_iftype,
2462 name, mac_addr, &err);
2463 break;
2464 }
2465 /* Intentionally fall through for unsupported interface
2466 * handling when firmware doesn't support p2p
2467 */
2468 default:
2469 WL_ERR(("Unsupported interface type\n"));
2470 err = -ENOTSUPP;
2471 goto fail;
2472 }
2473
2474 if (!wdev) {
2475 WL_ERR(("vif create failed. err:%d\n", err));
2476 if (err != -ENOTSUPP) {
2477 err = -ENODEV;
2478 }
2479 goto fail;
2480 }
2481
2482 /* Ensure decrementing in case of failure */
2483 cfg->vif_count++;
2484
2485 wl_cfg80211_iface_state_ops(wdev,
2486 WL_IF_CREATE_DONE, wl_iftype, wl_mode);
2487
2488 WL_INFORM_MEM(("Vif created. dev->ifindex:%d"
2489 " cfg_iftype:%d, vif_count:%d\n",
2490 (wdev->netdev ? wdev->netdev->ifindex : 0xff),
2491 wdev->iftype, cfg->vif_count));
2492 mutex_unlock(&cfg->if_sync);
2493 return wdev;
2494
2495 fail:
2496 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
2497 WL_IF_DELETE_REQ, wl_iftype, wl_mode);
2498
2499 if (err != -ENOTSUPP) {
2500 /* For non-supported interfaces, just return error and
2501 * skip below recovery steps.
2502 */
2503 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2504 wl_copy_hang_info_if_falure(primary_ndev, HANG_REASON_IFACE_DEL_FAILURE, err);
2505 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2506 SUPP_LOG(("IF_ADD fail. err:%d\n", err));
2507 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
2508 #if defined(BCMDONGLEHOST)
2509 if (dhd_query_bus_erros(dhd)) {
2510 goto exit;
2511 }
2512 dhd->iface_op_failed = TRUE;
2513 #endif /* BCMDONGLEHOST */
2514 #if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
2515 if (dhd->memdump_enabled) {
2516 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
2517 dhd_bus_mem_dump(dhd);
2518 }
2519 #endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
2520
2521 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
2522 /* If reached here, something wrong with DHD or firmware.
2523 * There could be a chance that firmware is in bad state.
2524 * Request the upper layer to do a Wi-Fi reset.
2525 */
2526 dhd->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
2527 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2528 #endif /* BCMDONGLEHOST && OEM_ANDROID */
2529
2530 }
2531 exit:
2532 mutex_unlock(&cfg->if_sync);
2533 return NULL;
2534 }
2535
2536 static s32
wl_cfg80211_del_ibss(struct wiphy * wiphy,struct wireless_dev * wdev)2537 wl_cfg80211_del_ibss(struct wiphy *wiphy, struct wireless_dev *wdev)
2538 {
2539 WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev));
2540 #ifdef WLAIBSS_MCHAN
2541 /* AIBSS */
2542 return bcm_cfg80211_del_ibss_if(wiphy, wdev);
2543 #else
2544 /* Normal IBSS */
2545 return wl_cfg80211_del_iface(wiphy, wdev);
2546 #endif
2547 }
2548
2549 s32
wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)2550 wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
2551 struct wireless_dev *wdev, char *ifname)
2552 {
2553 int ret = BCME_OK;
2554 mutex_lock(&cfg->if_sync);
2555 ret = _wl_cfg80211_del_if(cfg, primary_ndev, wdev, ifname);
2556 mutex_unlock(&cfg->if_sync);
2557 return ret;
2558 }
2559
2560 s32
_wl_cfg80211_del_if(struct bcm_cfg80211 * cfg,struct net_device * primary_ndev,struct wireless_dev * wdev,char * ifname)2561 _wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
2562 struct wireless_dev *wdev, char *ifname)
2563 {
2564 int ret = BCME_OK;
2565 s32 bssidx;
2566 struct wiphy *wiphy;
2567 u16 wl_mode;
2568 u16 wl_iftype;
2569 struct net_info *netinfo;
2570 #if defined(BCMDONGLEHOST)
2571 dhd_pub_t *dhd;
2572 BCM_REFERENCE(dhd);
2573 #endif /* BCMDONGLEHOST */
2574
2575 if (!cfg) {
2576 return -EINVAL;
2577 }
2578
2579 #if defined(BCMDONGLEHOST)
2580 dhd = (dhd_pub_t *)(cfg->pub);
2581 #endif /* BCMDONGLEHOST */
2582
2583 if (!wdev && ifname) {
2584 /* If only ifname is provided, fetch corresponding wdev ptr from our
2585 * internal data structure
2586 */
2587 wdev = wl_cfg80211_get_wdev_from_ifname(cfg, ifname);
2588 }
2589
2590 /* Check whether we have a valid wdev ptr */
2591 if (unlikely(!wdev)) {
2592 WL_ERR(("wdev not found. '%s' does not exists\n", ifname));
2593 return -ENODEV;
2594 }
2595
2596 WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev->iftype));
2597
2598 wiphy = wdev->wiphy;
2599 #ifdef WL_CFG80211_P2P_DEV_IF
2600 if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2601 /* p2p discovery would be de-initialized in stop p2p
2602 * device context/from other virtual i/f creation context
2603 * so netinfo list may not have any node corresponding to
2604 * discovery I/F. Handle it before bssidx check.
2605 */
2606 ret = wl_cfg80211_p2p_if_del(wiphy, wdev);
2607 if (unlikely(ret)) {
2608 goto exit;
2609 } else {
2610 /* success case. return from here */
2611 if (cfg->vif_count) {
2612 cfg->vif_count--;
2613 }
2614 return BCME_OK;
2615 }
2616 }
2617 #endif /* WL_CFG80211_P2P_DEV_IF */
2618
2619 if ((netinfo = wl_get_netinfo_by_wdev(cfg, wdev)) == NULL) {
2620 WL_ERR(("Find netinfo from wdev %p failed\n", wdev));
2621 ret = -ENODEV;
2622 goto exit;
2623 }
2624
2625 if (!wdev->netdev) {
2626 WL_ERR(("ndev null! \n"));
2627 } else {
2628 /* Disable tx before del */
2629 netif_tx_disable(wdev->netdev);
2630 }
2631
2632 wl_iftype = netinfo->iftype;
2633 wl_mode = wl_iftype_to_mode(wl_iftype);
2634 bssidx = netinfo->bssidx;
2635 WL_DBG_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
2636 wdev->iftype, wl_iftype, wl_mode, bssidx));
2637
2638 /* Do pre-interface del ops */
2639 wl_cfg80211_iface_state_ops(wdev, WL_IF_DELETE_REQ, wl_iftype, wl_mode);
2640
2641 #ifdef PCIE_FULL_DONGLE
2642 /* clean up sta info & clean up flowrings correspondign to the iface */
2643 dhd_net_del_flowrings_sta(dhd, wdev->netdev);
2644 #endif /* PCIE_FULL_DONGLE */
2645
2646 switch (wl_iftype) {
2647 case WL_IF_TYPE_P2P_GO:
2648 case WL_IF_TYPE_P2P_GC:
2649 case WL_IF_TYPE_AP:
2650 case WL_IF_TYPE_STA:
2651 case WL_IF_TYPE_NAN:
2652 ret = wl_cfg80211_del_iface(wiphy, wdev);
2653 break;
2654 case WL_IF_TYPE_IBSS:
2655 ret = wl_cfg80211_del_ibss(wiphy, wdev);
2656 break;
2657
2658 default:
2659 WL_ERR(("Unsupported interface type\n"));
2660 ret = BCME_ERROR;
2661 }
2662
2663 exit:
2664 if (ret == BCME_OK) {
2665 /* Successful case */
2666 if (cfg->vif_count) {
2667 cfg->vif_count--;
2668 }
2669 wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
2670 WL_IF_DELETE_DONE, wl_iftype, wl_mode);
2671 #ifdef WL_NAN
2672 if (!((cfg->nancfg->mac_rand) && (wl_iftype == WL_IF_TYPE_NAN)))
2673 #endif /* WL_NAN */
2674 {
2675 wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype);
2676 }
2677 WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg->vif_count));
2678 } else {
2679 if (!wdev->netdev) {
2680 WL_ERR(("ndev null! \n"));
2681 } else {
2682 /* IF del failed. revert back tx queue status */
2683 netif_tx_start_all_queues(wdev->netdev);
2684 }
2685
2686 /* Skip generating log files and sending HANG event
2687 * if driver state is not READY
2688 */
2689 if (wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg))) {
2690 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
2691 wl_copy_hang_info_if_falure(primary_ndev,
2692 HANG_REASON_IFACE_DEL_FAILURE, ret);
2693 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
2694 SUPP_LOG(("IF_DEL fail. err:%d\n", ret));
2695 wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
2696 #if defined(BCMDONGLEHOST)
2697 /* IF dongle is down due to previous hang or other conditions, sending
2698 * one more hang notification is not needed.
2699 */
2700 if (dhd_query_bus_erros(dhd) || (ret == BCME_DONGLE_DOWN)) {
2701 goto end;
2702 }
2703 dhd->iface_op_failed = TRUE;
2704 #if defined(DHD_FW_COREDUMP)
2705 if (dhd->memdump_enabled && (ret != -EBADTYPE)) {
2706 dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
2707 dhd_bus_mem_dump(dhd);
2708 }
2709 #endif /* DHD_FW_COREDUMP */
2710 #endif /* BCMDONGLEHOST */
2711
2712 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
2713 WL_ERR(("Notify hang event to upper layer \n"));
2714 dhd->hang_reason = HANG_REASON_IFACE_DEL_FAILURE;
2715 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2716 #endif /* BCMDONGLEHOST && OEM_ANDROID */
2717
2718 }
2719 }
2720 end:
2721 return ret;
2722 }
2723
2724 s32
wl_cfg80211_notify_ifadd(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx,uint8 role)2725 wl_cfg80211_notify_ifadd(struct net_device *dev,
2726 int ifidx, char *name, uint8 *mac, uint8 bssidx, uint8 role)
2727 {
2728 bool ifadd_expected = FALSE;
2729 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2730 bool bss_pending_op = TRUE;
2731
2732 /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
2733 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
2734 */
2735 if (wl_get_p2p_status(cfg, IF_CHANGING))
2736 return wl_cfg80211_notify_ifchange(dev, ifidx, name, mac, bssidx);
2737
2738 /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
2739 if (wl_get_p2p_status(cfg, IF_ADDING)) {
2740 ifadd_expected = TRUE;
2741 wl_clr_p2p_status(cfg, IF_ADDING);
2742 } else if (cfg->bss_pending_op) {
2743 ifadd_expected = TRUE;
2744 bss_pending_op = FALSE;
2745 }
2746
2747 if (ifadd_expected) {
2748 wl_if_event_info *if_event_info = &cfg->if_event_info;
2749
2750 if_event_info->ifidx = ifidx;
2751 if_event_info->bssidx = bssidx;
2752 if_event_info->role = role;
2753 strlcpy(if_event_info->name, name, sizeof(if_event_info->name));
2754 if_event_info->name[IFNAMSIZ - 1] = '\0';
2755 if (mac)
2756 memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
2757
2758 /* Update bss pendig operation status */
2759 if (!bss_pending_op) {
2760 cfg->bss_pending_op = FALSE;
2761 }
2762 WL_INFORM_MEM(("IF_ADD ifidx:%d bssidx:%d role:%d\n",
2763 ifidx, bssidx, role));
2764 OSL_SMP_WMB();
2765 if_event_info->valid = TRUE;
2766 wake_up_interruptible(&cfg->netif_change_event);
2767 return BCME_OK;
2768 }
2769
2770 return BCME_ERROR;
2771 }
2772
2773 s32
wl_cfg80211_notify_ifdel(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)2774 wl_cfg80211_notify_ifdel(struct net_device *dev, int ifidx, char *name, uint8 *mac, uint8 bssidx)
2775 {
2776 bool ifdel_expected = FALSE;
2777 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2778 wl_if_event_info *if_event_info = &cfg->if_event_info;
2779 bool bss_pending_op = TRUE;
2780
2781 if (wl_get_p2p_status(cfg, IF_DELETING)) {
2782 ifdel_expected = TRUE;
2783 wl_clr_p2p_status(cfg, IF_DELETING);
2784 } else if (cfg->bss_pending_op) {
2785 ifdel_expected = TRUE;
2786 bss_pending_op = FALSE;
2787 }
2788
2789 if (ifdel_expected) {
2790 if_event_info->ifidx = ifidx;
2791 if_event_info->bssidx = bssidx;
2792 /* Update bss pendig operation status */
2793 if (!bss_pending_op) {
2794 cfg->bss_pending_op = FALSE;
2795 }
2796 WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx, bssidx));
2797 OSL_SMP_WMB();
2798 if_event_info->valid = TRUE;
2799 wake_up_interruptible(&cfg->netif_change_event);
2800 return BCME_OK;
2801 }
2802
2803 return BCME_ERROR;
2804 }
2805
2806 s32
wl_cfg80211_notify_ifchange(struct net_device * dev,int ifidx,char * name,uint8 * mac,uint8 bssidx)2807 wl_cfg80211_notify_ifchange(struct net_device * dev, int ifidx, char *name, uint8 *mac,
2808 uint8 bssidx)
2809 {
2810 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2811
2812 if (wl_get_p2p_status(cfg, IF_CHANGING)) {
2813 wl_set_p2p_status(cfg, IF_CHANGED);
2814 OSL_SMP_WMB();
2815 wake_up_interruptible(&cfg->netif_change_event);
2816 return BCME_OK;
2817 }
2818
2819 return BCME_ERROR;
2820 }
2821
wl_set_rts(struct net_device * dev,u32 rts_threshold)2822 static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
2823 {
2824 s32 err = 0;
2825
2826 err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
2827 if (unlikely(err)) {
2828 WL_ERR(("Error (%d)\n", err));
2829 return err;
2830 }
2831 return err;
2832 }
2833
wl_set_frag(struct net_device * dev,u32 frag_threshold)2834 static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
2835 {
2836 s32 err = 0;
2837
2838 err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
2839 if (unlikely(err)) {
2840 WL_ERR(("Error (%d)\n", err));
2841 return err;
2842 }
2843 return err;
2844 }
2845
wl_set_retry(struct net_device * dev,u32 retry,bool l)2846 static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
2847 {
2848 s32 err = 0;
2849 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
2850
2851 #ifdef CUSTOM_LONG_RETRY_LIMIT
2852 if ((cmd == WLC_SET_LRL) &&
2853 (retry != CUSTOM_LONG_RETRY_LIMIT)) {
2854 WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
2855 return err;
2856 }
2857 #endif /* CUSTOM_LONG_RETRY_LIMIT */
2858
2859 retry = htod32(retry);
2860 err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry));
2861 if (unlikely(err)) {
2862 WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
2863 return err;
2864 }
2865 return err;
2866 }
2867
wl_cfg80211_set_wiphy_params(struct wiphy * wiphy,u32 changed)2868 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
2869 {
2870 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
2871 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2872 s32 err = 0;
2873
2874 RETURN_EIO_IF_NOT_UP(cfg);
2875 WL_DBG(("Enter\n"));
2876 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
2877 (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
2878 cfg->conf->rts_threshold = wiphy->rts_threshold;
2879 err = wl_set_rts(ndev, cfg->conf->rts_threshold);
2880 if (err != BCME_OK)
2881 return err;
2882 }
2883 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
2884 (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
2885 cfg->conf->frag_threshold = wiphy->frag_threshold;
2886 err = wl_set_frag(ndev, cfg->conf->frag_threshold);
2887 if (err != BCME_OK)
2888 return err;
2889 }
2890 if (changed & WIPHY_PARAM_RETRY_LONG &&
2891 (cfg->conf->retry_long != wiphy->retry_long)) {
2892 cfg->conf->retry_long = wiphy->retry_long;
2893 err = wl_set_retry(ndev, cfg->conf->retry_long, true);
2894 if (err != BCME_OK)
2895 return err;
2896 }
2897 if (changed & WIPHY_PARAM_RETRY_SHORT &&
2898 (cfg->conf->retry_short != wiphy->retry_short)) {
2899 cfg->conf->retry_short = wiphy->retry_short;
2900 err = wl_set_retry(ndev, cfg->conf->retry_short, false);
2901 if (err != BCME_OK) {
2902 return err;
2903 }
2904 }
2905
2906 return err;
2907 }
2908
2909 void
wl_cfg80211_ibss_vsie_set_buffer(struct net_device * dev,vndr_ie_setbuf_t * ibss_vsie,int ibss_vsie_len)2910 wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev, vndr_ie_setbuf_t *ibss_vsie,
2911 int ibss_vsie_len)
2912 {
2913 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2914
2915 if (cfg != NULL && ibss_vsie != NULL) {
2916 if (cfg->ibss_vsie != NULL) {
2917 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
2918 }
2919 cfg->ibss_vsie = ibss_vsie;
2920 cfg->ibss_vsie_len = ibss_vsie_len;
2921 }
2922 }
2923
2924 static void
wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 * cfg)2925 wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
2926 {
2927 /* free & initiralize VSIE (Vendor Specific IE) */
2928 if (cfg->ibss_vsie != NULL) {
2929 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
2930 cfg->ibss_vsie_len = 0;
2931 }
2932 }
2933
2934 s32
wl_cfg80211_ibss_vsie_delete(struct net_device * dev)2935 wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
2936 {
2937 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2938 char *ioctl_buf = NULL;
2939 s32 ret = BCME_OK, bssidx;
2940
2941 if (cfg != NULL && cfg->ibss_vsie != NULL) {
2942 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
2943 if (!ioctl_buf) {
2944 WL_ERR(("ioctl memory alloc failed\n"));
2945 return -ENOMEM;
2946 }
2947 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
2948 WL_ERR(("Find index failed\n"));
2949 ret = BCME_ERROR;
2950 goto end;
2951 }
2952 /* change the command from "add" to "del" */
2953 strlcpy(cfg->ibss_vsie->cmd, "del", sizeof(cfg->ibss_vsie->cmd));
2954
2955 ret = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie",
2956 cfg->ibss_vsie, cfg->ibss_vsie_len,
2957 ioctl_buf, WLC_IOCTL_MEDLEN, bssidx, NULL);
2958 WL_ERR(("ret=%d\n", ret));
2959
2960 if (ret == BCME_OK) {
2961 /* Free & initialize VSIE */
2962 MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
2963 cfg->ibss_vsie_len = 0;
2964 }
2965 end:
2966 if (ioctl_buf) {
2967 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
2968 }
2969 }
2970
2971 return ret;
2972 }
2973
2974 #ifdef WLAIBSS_MCHAN
2975 static bcm_struct_cfgdev*
bcm_cfg80211_add_ibss_if(struct wiphy * wiphy,char * name)2976 bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name)
2977 {
2978 int err = 0;
2979 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2980 struct wireless_dev* wdev = NULL;
2981 struct net_device *new_ndev = NULL;
2982 struct net_device *primary_ndev = NULL;
2983 long timeout;
2984 wl_aibss_if_t aibss_if;
2985 wl_if_event_info *event = NULL;
2986
2987 if (cfg->ibss_cfgdev != NULL) {
2988 WL_ERR(("IBSS interface %s already exists\n", name));
2989 return NULL;
2990 }
2991
2992 WL_ERR(("Try to create IBSS interface %s\n", name));
2993 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
2994 /* generate a new MAC address for the IBSS interface */
2995 get_primary_mac(cfg, &cfg->ibss_if_addr);
2996 cfg->ibss_if_addr.octet[4] ^= 0x40;
2997 bzero(&aibss_if, sizeof(aibss_if));
2998 memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
2999 aibss_if.chspec = 0;
3000 aibss_if.len = sizeof(aibss_if);
3001
3002 cfg->bss_pending_op = TRUE;
3003 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3004 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
3005 sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3006 if (err) {
3007 WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
3008 goto fail;
3009 }
3010 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3011 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
3012 if (timeout <= 0 || cfg->bss_pending_op)
3013 goto fail;
3014
3015 event = &cfg->if_event_info;
3016 /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
3017 * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
3018 * and will be freed by dhd_detach unless it gets unregistered before that. The
3019 * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
3020 * be freed by wl_dealloc_netinfo
3021 */
3022 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name,
3023 event->mac, event->bssidx, event->name);
3024 if (new_ndev == NULL)
3025 goto fail;
3026 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
3027 if (wdev == NULL)
3028 goto fail;
3029 wdev->wiphy = wiphy;
3030 wdev->iftype = NL80211_IFTYPE_ADHOC;
3031 wdev->netdev = new_ndev;
3032 new_ndev->ieee80211_ptr = wdev;
3033 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
3034
3035 /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
3036 * needs to be modified to take one parameter (bool need_rtnl_lock)
3037 */
3038 ASSERT_RTNL();
3039 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, FALSE) != BCME_OK)
3040 goto fail;
3041
3042 wl_alloc_netinfo(cfg, new_ndev, wdev, WL_IF_TYPE_IBSS,
3043 PM_ENABLE, event->bssidx, event->ifidx);
3044 cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
3045 WL_ERR(("IBSS interface %s created\n", new_ndev->name));
3046 return cfg->ibss_cfgdev;
3047
3048 fail:
3049 WL_ERR(("failed to create IBSS interface %s \n", name));
3050 cfg->bss_pending_op = FALSE;
3051 if (new_ndev)
3052 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
3053 if (wdev) {
3054 MFREE(cfg->osh, wdev, sizeof(*wdev));
3055 }
3056 return NULL;
3057 }
3058
3059 static s32
bcm_cfg80211_del_ibss_if(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev)3060 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
3061 {
3062 int err = 0;
3063 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3064 struct net_device *ndev = NULL;
3065 struct net_device *primary_ndev = NULL;
3066 long timeout;
3067
3068 if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet))
3069 return -EINVAL;
3070 ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev);
3071 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3072
3073 cfg->bss_pending_op = TRUE;
3074 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3075 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
3076 sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3077 if (err) {
3078 WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
3079 goto fail;
3080 }
3081 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
3082 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
3083 if (timeout <= 0 || cfg->bss_pending_op) {
3084 WL_ERR(("timeout in waiting IF_DEL event\n"));
3085 goto fail;
3086 }
3087
3088 wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
3089 cfg->ibss_cfgdev = NULL;
3090 return 0;
3091
3092 fail:
3093 cfg->bss_pending_op = FALSE;
3094 return -1;
3095 }
3096 #endif /* WLAIBSS_MCHAN */
3097
3098 s32
wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)3099 wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)
3100 {
3101 s32 ret = BCME_ERROR;
3102
3103 switch (iftype) {
3104 case WL_IF_TYPE_AP:
3105 ret = WL_INTERFACE_TYPE_AP;
3106 break;
3107 case WL_IF_TYPE_STA:
3108 ret = WL_INTERFACE_TYPE_STA;
3109 break;
3110 case WL_IF_TYPE_NAN_NMI:
3111 case WL_IF_TYPE_NAN:
3112 ret = WL_INTERFACE_TYPE_NAN;
3113 break;
3114 case WL_IF_TYPE_P2P_DISC:
3115 ret = WL_INTERFACE_TYPE_P2P_DISC;
3116 break;
3117 case WL_IF_TYPE_P2P_GO:
3118 ret = WL_INTERFACE_TYPE_P2P_GO;
3119 break;
3120 case WL_IF_TYPE_P2P_GC:
3121 ret = WL_INTERFACE_TYPE_P2P_GC;
3122 break;
3123
3124 #ifdef WLAWDL
3125 case WL_IF_TYPE_AWDL:
3126 ret = WL_INTERFACE_TYPE_AWDL;
3127 break;
3128 #endif /* WLAWDL */
3129
3130 default:
3131 WL_ERR(("Unsupported type:%d \n", iftype));
3132 ret = -EINVAL;
3133 break;
3134 }
3135 return ret;
3136 }
3137
3138 s32
wl_cfg80211_interface_ops(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,wl_iftype_t cfg_iftype,s32 del,u8 * addr)3139 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
3140 struct net_device *ndev, s32 bsscfg_idx,
3141 wl_iftype_t cfg_iftype, s32 del, u8 *addr)
3142 {
3143 s32 ret;
3144 struct wl_interface_create_v2 iface;
3145 wl_interface_create_v3_t iface_v3;
3146 wl_interface_create_v0_t iface_v0;
3147 struct wl_interface_info_v1 *info;
3148 wl_interface_info_v2_t *info_v2;
3149 wl_interface_info_v0_t *info_v0;
3150 uint32 ifflags = 0;
3151 bool use_iface_info_v2 = false;
3152 u8 ioctl_buf[WLC_IOCTL_SMLEN];
3153 s32 iftype;
3154 #ifdef WLEASYMESH
3155 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3156 #endif /* WLEASYMESH */
3157
3158 if (del) {
3159 ret = wldev_iovar_setbuf(ndev, "interface_remove",
3160 NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL);
3161 if (unlikely(ret))
3162 WL_ERR(("Interface remove failed!! ret %d\n", ret));
3163 return ret;
3164 }
3165
3166 /* Interface create */
3167 bzero(&iface, sizeof(iface));
3168 /*
3169 * flags field is still used along with iftype inorder to support the old version of the
3170 * FW work with the latest app changes.
3171 */
3172
3173 iftype = wl_cfg80211_to_fw_iftype(cfg_iftype);
3174 if (iftype < 0) {
3175 return -ENOTSUPP;
3176 }
3177
3178 if (addr) {
3179 ifflags |= WL_INTERFACE_MAC_USE;
3180 if (wl_legacy_chip_check(ndev)) {
3181 iface.flags = ifflags;
3182 memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
3183 }
3184 }
3185 #ifdef WLEASYMESH
3186 if (dhd->conf->fw_type == FW_TYPE_EZMESH && iftype == WL_INTERFACE_TYPE_AP) {
3187 // this can be removed for 4359
3188 ifflags |= WL_INTERFACE_TYPE_AP;
3189 }
3190 #endif /* WLEASYMESH */
3191
3192 /* Pass ver = 0 for fetching the interface_create iovar version */
3193 if (wl_legacy_chip_check(ndev)) {
3194 bzero(&iface_v0, sizeof(iface_v0));
3195 iface_v0.ver = WL_INTERFACE_CREATE_VER_0;
3196 iface_v0.flags = iftype | ifflags;
3197 if (addr) {
3198 memcpy(&iface_v0.mac_addr.octet, addr, ETH_ALEN);
3199 }
3200 ret = wldev_iovar_getbuf(ndev, "interface_create",
3201 &iface_v0, sizeof(struct wl_interface_create),
3202 ioctl_buf, sizeof(ioctl_buf), NULL);
3203 if (ret == 0) {
3204 info_v0 = (wl_interface_info_v0_t *)ioctl_buf;
3205 ret = info_v0->bsscfgidx;
3206 goto exit;
3207 }
3208 } else {
3209 ret = wldev_iovar_getbuf(ndev, "interface_create",
3210 &iface, sizeof(struct wl_interface_create_v2),
3211 ioctl_buf, sizeof(ioctl_buf), NULL);
3212 }
3213 if (ret == BCME_UNSUPPORTED) {
3214 WL_ERR(("interface_create iovar not supported\n"));
3215 return ret;
3216 } else if ((ret == 0) && *((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3) {
3217 WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags));
3218 use_iface_info_v2 = true;
3219 bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
3220 iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
3221 iface_v3.iftype = iftype;
3222 iface_v3.flags = ifflags;
3223 if (addr) {
3224 memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
3225 }
3226 ret = wldev_iovar_getbuf(ndev, "interface_create",
3227 &iface_v3, sizeof(wl_interface_create_v3_t),
3228 ioctl_buf, sizeof(ioctl_buf), NULL);
3229 } else if ((ret == 0) &&
3230 ((*((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_2) ||
3231 (*((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_1))) {
3232 /* Legacy firmware could invoke iovar and reply data
3233 * directly. Do not try if return ver is not expected.
3234 * On any other error, attempt with iovar version 2 */
3235 WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n", ret, ifflags));
3236 iface.ver = WL_INTERFACE_CREATE_VER_2;
3237 iface.iftype = iftype;
3238 iface.flags = ifflags;
3239 if (addr) {
3240 memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
3241 }
3242 ret = wldev_iovar_getbuf(ndev, "interface_create",
3243 &iface, sizeof(struct wl_interface_create_v2),
3244 ioctl_buf, sizeof(ioctl_buf), NULL);
3245 } else {
3246 /* inteface_create version 0, need to add chipnum in bcmdevs_legacy.h
3247 * and add new chip check at wl_legacy_chip_check function */
3248 WL_DBG(("interface_create version 0. get_ver:%d ifflags:0x%x\n", ret, ifflags));
3249 }
3250
3251 if (unlikely(ret)) {
3252 WL_ERR(("Interface create failed!! ret %d\n", ret));
3253 return ret;
3254 }
3255
3256 /* success case */
3257 if (use_iface_info_v2 == true) {
3258 info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
3259 ret = info_v2->bsscfgidx;
3260 } else {
3261 /* Use v1 struct */
3262 info = (struct wl_interface_info_v1 *)ioctl_buf;
3263 ret = info->bsscfgidx;
3264 }
3265
3266 exit:
3267 #ifdef WLEASYMESH
3268 //Give fw more time to process interface_create
3269 if (dhd->conf->fw_type == FW_TYPE_EZMESH) {
3270 wl_delay(500);
3271 }
3272 #endif /* WLEASYMESH */
3273 WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
3274 return ret;
3275 }
3276
3277 #ifdef CUSTOMER_HW6
3278 #define BCM4355_REV_C1 0x0c
3279 bool
wl_customer6_legacy_chip_check(struct bcm_cfg80211 * cfg,struct net_device * ndev)3280 wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg,
3281 struct net_device *ndev)
3282 {
3283 u32 chipnum;
3284 wlc_rev_info_t revinfo;
3285 int ret;
3286
3287 /* Get the device rev info */
3288 bzero(&revinfo, sizeof(revinfo));
3289 ret = wldev_ioctl_get(ndev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
3290 if (ret < 0) {
3291 WL_ERR(("wl_customer6_legacy_chip_check: GET revinfo FAILED. ret:%d\n", ret));
3292 ASSERT(0);
3293 return false;
3294 }
3295
3296 chipnum = revinfo.chipnum;
3297 WL_DBG(("wl_customer6_legacy_chip_check: GET_REVINFO device 0x%x, vendor 0x%x,"
3298 " chipnum 0x%x\n",
3299 dtoh32(revinfo.deviceid), dtoh32(revinfo.vendorid), dtoh32(chipnum)));
3300 if (
3301 #ifdef BCM4350_CHIP_ID
3302 (chipnum == BCM4350_CHIP_ID) ||
3303 #endif /* BCM4350_CHIP_ID */
3304 #ifdef BCM4355_CHIP_ID
3305 ((chipnum == BCM4355_CHIP_ID) && (revinfo.chiprev < BCM4355_REV_C1)) ||
3306 #endif /* BCM4355_CHIP_ID */
3307 #ifdef BCM4345_CHIP_ID
3308 (chipnum == BCM4345_CHIP_ID) ||
3309 #endif /* BCM4345_CHIP_ID */
3310 false) {
3311 /* WAR required */
3312 WL_DBG(("%s: Customer6 legacy chip identified\n", __FUNCTION__));
3313 return true;
3314 }
3315
3316 return false;
3317 }
3318 #endif /* CUSTOMER_HW6 */
3319
3320 s32
wl_cfg80211_add_del_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,wl_iftype_t brcm_iftype,s32 del,u8 * addr)3321 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
3322 struct net_device *ndev, s32 bsscfg_idx,
3323 wl_iftype_t brcm_iftype, s32 del, u8 *addr)
3324 {
3325 s32 ret = BCME_OK;
3326 s32 val = 0;
3327
3328 struct {
3329 s32 cfg;
3330 s32 val;
3331 struct ether_addr ea;
3332 } bss_setbuf;
3333
3334 WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype, del));
3335
3336 bzero(&bss_setbuf, sizeof(bss_setbuf));
3337
3338 /* AP=2, STA=3, up=1, down=0, val=-1 */
3339 if (del) {
3340 val = WLC_AP_IOV_OP_DELETE;
3341 } else if (brcm_iftype == WL_IF_TYPE_AP) {
3342 /* Add/role change to AP Interface */
3343 WL_DBG(("Adding AP Interface \n"));
3344 val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
3345 } else if (brcm_iftype == WL_IF_TYPE_STA) {
3346 /* Add/role change to STA Interface */
3347 WL_DBG(("Adding STA Interface \n"));
3348 val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
3349 } else {
3350 WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype));
3351 return -EINVAL;
3352 }
3353
3354 if (!del) {
3355 wl_ext_bss_iovar_war(ndev, &val);
3356 }
3357
3358 bss_setbuf.cfg = htod32(bsscfg_idx);
3359 bss_setbuf.val = htod32(val);
3360
3361 if (addr) {
3362 memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
3363 }
3364
3365 WL_MSG(ndev->name, "wl bss %d bssidx:%d\n", val, bsscfg_idx);
3366 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3367 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3368 if (ret != 0)
3369 WL_ERR(("'bss %d' failed with %d\n", val, ret));
3370
3371 return ret;
3372 }
3373
3374 s32
wl_cfg80211_bss_up(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bsscfg_idx,s32 bss_up)3375 wl_cfg80211_bss_up(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 bss_up)
3376 {
3377 s32 ret = BCME_OK;
3378 s32 val = bss_up ? 1 : 0;
3379
3380 struct {
3381 s32 cfg;
3382 s32 val;
3383 } bss_setbuf;
3384
3385 bss_setbuf.cfg = htod32(bsscfg_idx);
3386 bss_setbuf.val = htod32(val);
3387
3388 WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx, bss_up ? "up" : "down"));
3389 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3390 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3391
3392 if (ret != 0) {
3393 WL_ERR(("'bss %d' failed with %d\n", bss_up, ret));
3394 }
3395
3396 return ret;
3397 }
3398
3399 bool
wl_cfg80211_bss_isup(struct net_device * ndev,int bsscfg_idx)3400 wl_cfg80211_bss_isup(struct net_device *ndev, int bsscfg_idx)
3401 {
3402 s32 result, val;
3403 bool isup = false;
3404 s8 getbuf[64];
3405
3406 /* Check if the BSS is up */
3407 *(int*)getbuf = -1;
3408 result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
3409 sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
3410 if (result != 0) {
3411 WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
3412 WL_ERR(("NOTE: this ioctl error is normal "
3413 "when the BSS has not been created yet.\n"));
3414 } else {
3415 val = *(int*)getbuf;
3416 val = dtoh32(val);
3417 WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx, val));
3418 isup = (val ? TRUE : FALSE);
3419 }
3420 return isup;
3421 }
3422
3423 s32
wl_iftype_to_mode(wl_iftype_t iftype)3424 wl_iftype_to_mode(wl_iftype_t iftype)
3425 {
3426 s32 mode = BCME_ERROR;
3427
3428 switch (iftype) {
3429 case WL_IF_TYPE_STA:
3430 case WL_IF_TYPE_P2P_GC:
3431 case WL_IF_TYPE_P2P_DISC:
3432 mode = WL_MODE_BSS;
3433 break;
3434 case WL_IF_TYPE_AP:
3435 case WL_IF_TYPE_P2P_GO:
3436 mode = WL_MODE_AP;
3437 break;
3438 case WL_IF_TYPE_NAN:
3439 mode = WL_MODE_NAN;
3440 break;
3441
3442 #ifdef WLAWDL
3443 case WL_IF_TYPE_AWDL:
3444 mode = WL_MODE_AWDL;
3445 break;
3446 #endif /* WLAWDL */
3447
3448 case WL_IF_TYPE_AIBSS:
3449 /* Intentional fall through */
3450 case WL_IF_TYPE_IBSS:
3451 mode = WL_MODE_IBSS;
3452 break;
3453 #ifdef WLMESH_CFG80211
3454 case WL_IF_TYPE_MESH:
3455 mode = WL_MODE_MESH;
3456 break;
3457 #endif /* WLMESH_CFG80211 */
3458 default:
3459 WL_ERR(("Unsupported type:%d\n", iftype));
3460 break;
3461 }
3462 return mode;
3463 }
3464
3465 s32
cfg80211_to_wl_iftype(uint16 type,uint16 * role,uint16 * mode)3466 cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode)
3467 {
3468 switch (type) {
3469 case NL80211_IFTYPE_STATION:
3470 *role = WL_IF_TYPE_STA;
3471 *mode = WL_MODE_BSS;
3472 break;
3473 case NL80211_IFTYPE_AP:
3474 *role = WL_IF_TYPE_AP;
3475 *mode = WL_MODE_AP;
3476 break;
3477 #ifdef WL_CFG80211_P2P_DEV_IF
3478 case NL80211_IFTYPE_P2P_DEVICE:
3479 *role = WL_IF_TYPE_P2P_DISC;
3480 *mode = WL_MODE_BSS;
3481 break;
3482 #endif /* WL_CFG80211_P2P_DEV_IF */
3483 case NL80211_IFTYPE_P2P_GO:
3484 *role = WL_IF_TYPE_P2P_GO;
3485 *mode = WL_MODE_AP;
3486 break;
3487 case NL80211_IFTYPE_P2P_CLIENT:
3488 *role = WL_IF_TYPE_P2P_GC;
3489 *mode = WL_MODE_BSS;
3490 break;
3491 case NL80211_IFTYPE_MONITOR:
3492 WL_ERR(("Unsupported mode \n"));
3493 return BCME_UNSUPPORTED;
3494 case NL80211_IFTYPE_ADHOC:
3495 *role = WL_IF_TYPE_IBSS;
3496 *mode = WL_MODE_IBSS;
3497 break;
3498 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
3499 case NL80211_IFTYPE_NAN:
3500 *role = WL_IF_TYPE_NAN;
3501 *mode = WL_MODE_NAN;
3502 break;
3503 #endif
3504 #ifdef WLMESH_CFG80211
3505 case NL80211_IFTYPE_MESH_POINT:
3506 *role = WLC_E_IF_ROLE_AP;
3507 *mode = WL_MODE_MESH;
3508 break;
3509 #endif /* WLMESH_CFG80211 */
3510 default:
3511 WL_ERR(("Unknown interface type:0x%x\n", type));
3512 return BCME_ERROR;
3513 }
3514 return BCME_OK;
3515 }
3516
3517 static s32
wl_role_to_cfg80211_type(uint16 role,uint16 * wl_iftype,uint16 * mode)3518 wl_role_to_cfg80211_type(uint16 role, uint16 *wl_iftype, uint16 *mode)
3519 {
3520 switch (role) {
3521
3522 #ifdef WLAWDL
3523 case WLC_E_IF_ROLE_AWDL:
3524 /* Intentional fall through - Since there is no
3525 * corresponding iftype in cfg80211 stack, map
3526 * iftype to station.
3527 */
3528 *wl_iftype = WL_IF_TYPE_AWDL;
3529 *mode = WL_MODE_AWDL;
3530 return NL80211_IFTYPE_STATION;
3531 #endif /* WLAWDL */
3532
3533 case WLC_E_IF_ROLE_STA:
3534 *wl_iftype = WL_IF_TYPE_STA;
3535 *mode = WL_MODE_BSS;
3536 return NL80211_IFTYPE_STATION;
3537 case WLC_E_IF_ROLE_AP:
3538 *wl_iftype = WL_IF_TYPE_AP;
3539 *mode = WL_MODE_AP;
3540 return NL80211_IFTYPE_AP;
3541 case WLC_E_IF_ROLE_P2P_GO:
3542 *wl_iftype = WL_IF_TYPE_P2P_GO;
3543 *mode = WL_MODE_AP;
3544 return NL80211_IFTYPE_P2P_GO;
3545 case WLC_E_IF_ROLE_P2P_CLIENT:
3546 *wl_iftype = WL_IF_TYPE_P2P_GC;
3547 *mode = WL_MODE_BSS;
3548 return NL80211_IFTYPE_P2P_CLIENT;
3549 case WLC_E_IF_ROLE_IBSS:
3550 *wl_iftype = WL_IF_TYPE_IBSS;
3551 *mode = WL_MODE_IBSS;
3552 return NL80211_IFTYPE_ADHOC;
3553 case WLC_E_IF_ROLE_NAN:
3554 *wl_iftype = WL_IF_TYPE_NAN;
3555 *mode = WL_MODE_NAN;
3556 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
3557 /* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
3558 * For Vendor HAL based NAN implementation, continue advertising
3559 * as a STA interface
3560 */
3561 return NL80211_IFTYPE_NAN;
3562 #else
3563 return NL80211_IFTYPE_STATION;
3564 #endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
3565 #ifdef WLDWDS
3566 case WLC_E_IF_ROLE_WDS:
3567 *wl_iftype = WL_IF_TYPE_AP;
3568 *mode = WL_MODE_AP;
3569 return NL80211_IFTYPE_AP;
3570 #endif
3571 #ifdef WLMESH_CFG80211
3572 case WLC_E_IF_ROLE_MESH:
3573 *wl_iftype = WL_IF_TYPE_MESH;
3574 *mode = WL_MODE_MESH;
3575 return NL80211_IFTYPE_MESH_POINT;
3576 #endif /* WLMESH_CFG80211 */
3577
3578 default:
3579 WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role));
3580 return BCME_ERROR;
3581 }
3582 }
3583
3584 struct net_device *
wl_cfg80211_post_ifcreate(struct net_device * ndev,wl_if_event_info * event,u8 * addr,const char * name,bool rtnl_lock_reqd)3585 wl_cfg80211_post_ifcreate(struct net_device *ndev,
3586 wl_if_event_info *event, u8 *addr,
3587 const char *name, bool rtnl_lock_reqd)
3588 {
3589 struct bcm_cfg80211 *cfg;
3590 struct net_device *primary_ndev;
3591 struct net_device *new_ndev = NULL;
3592 struct wireless_dev *wdev = NULL;
3593 s32 iface_type;
3594 s32 ret = BCME_OK;
3595 u16 mode;
3596 u8 mac_addr[ETH_ALEN];
3597 u16 wl_iftype;
3598
3599 if (!ndev || !event) {
3600 WL_ERR(("Wrong arg\n"));
3601 return NULL;
3602 }
3603
3604 cfg = wl_get_cfg(ndev);
3605 if (!cfg) {
3606 WL_ERR(("cfg null\n"));
3607 return NULL;
3608 }
3609
3610 WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
3611 event->role, event->ifidx, event->bssidx));
3612 if (!event->ifidx || !event->bssidx) {
3613 /* Fw returned primary idx (0) for virtual interface */
3614 WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
3615 event->ifidx, event->bssidx));
3616 return NULL;
3617 }
3618
3619 #if defined(WLMESH_CFG80211) && defined(WL_EXT_IAPSTA)
3620 if (wl_ext_iapsta_mesh_creating(ndev)) {
3621 event->role = WLC_E_IF_ROLE_MESH;
3622 WL_MSG(ndev->name, "change role to WLC_E_IF_ROLE_MESH\n");
3623 }
3624 #endif /* WLMESH_CFG80211 && WL_EXT_IAPSTA */
3625
3626 iface_type = wl_role_to_cfg80211_type(event->role, &wl_iftype, &mode);
3627 if (iface_type < 0) {
3628 /* Unknown iface type */
3629 WL_ERR(("Wrong iface type \n"));
3630 return NULL;
3631 }
3632
3633 WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG "\n",
3634 addr, name, event->role, iface_type, MAC2STRDBG(event->mac)));
3635 if (!name) {
3636 /* If iface name is not provided, use dongle ifname */
3637 name = event->name;
3638 }
3639
3640 if (!addr) {
3641 /* If mac address is not set, use primary mac with locally administered
3642 * bit set.
3643 */
3644 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3645 memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
3646 #ifndef CUSTOMER_HW6
3647 /* For customer6 builds, use primary mac address for virtual interface */
3648 mac_addr[0] |= 0x02;
3649 #endif /* CUSTOMER_HW6 */
3650 addr = mac_addr;
3651 }
3652
3653 if (iface_type == NL80211_IFTYPE_P2P_CLIENT) {
3654 struct ether_addr *p2p_addr;
3655 s16 cfg_type = wl_cfgp2p_get_conn_idx(cfg);
3656 if (cfg_type < BCME_OK) {
3657 WL_ERR(("Failed to get connection idx for p2p interface"
3658 ", error code = %d", cfg_type));
3659 goto fail;
3660 }
3661 p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
3662
3663 /* check if pre-registered mac matches the mac from dongle via WLC_E_LINK */
3664 if (memcmp(p2p_addr->octet, addr, ETH_ALEN)) {
3665 WL_INFORM_MEM(("p2p pre-regsitered mac:" MACDBG
3666 " , mac from dongle:" MACDBG "\n",
3667 MAC2STRDBG(p2p_addr->octet), MAC2STRDBG(addr)));
3668
3669 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3670
3671 wl_cfg80211_handle_hang_event(primary_ndev,
3672 HANG_REASON_IFACE_ADD_FAILURE, DUMP_TYPE_IFACE_OP_FAILURE);
3673 goto fail;
3674 }
3675 }
3676
3677 #ifdef WL_STATIC_IF
3678 if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
3679 new_ndev = wl_cfg80211_post_static_ifcreate(cfg, event, addr, iface_type);
3680 if (!new_ndev) {
3681 WL_ERR(("failed to get I/F pointer\n"));
3682 return NULL;
3683 }
3684 wdev = new_ndev->ieee80211_ptr;
3685 } else
3686 #endif /* WL_STATIC_IF */
3687 {
3688 new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
3689 name, addr, event->bssidx, event->name);
3690 if (!new_ndev) {
3691 WL_ERR(("I/F allocation failed! \n"));
3692 return NULL;
3693 } else {
3694 WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
3695 event->ifidx, event->bssidx));
3696 }
3697
3698 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
3699 if (!wdev) {
3700 WL_ERR(("wireless_dev alloc failed! \n"));
3701 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
3702 return NULL;
3703 }
3704
3705 wdev->wiphy = bcmcfg_to_wiphy(cfg);
3706 wdev->iftype = iface_type;
3707
3708 new_ndev->ieee80211_ptr = wdev;
3709 #ifdef WLDWDS
3710 /* set wds0.x to 4addr interface here */
3711 if (event->role == WLC_E_IF_ROLE_WDS) {
3712 WL_MSG(ndev->name, "set vwdev 4addr to %s\n", event->name);
3713 wdev->use_4addr = true;
3714 }
3715 #endif /* WLDWDS */
3716 SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
3717
3718 memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
3719 #ifdef WL_EXT_IAPSTA
3720 wl_ext_iapsta_ifadding(new_ndev, event->ifidx);
3721 #endif /* WL_EXT_IAPSTA */
3722 if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd)
3723 != BCME_OK) {
3724 WL_ERR(("IFACE register failed \n"));
3725 /* Post interface registration, wdev would be freed from the netdev
3726 * destructor path. For other cases, handle it here.
3727 */
3728 MFREE(cfg->osh, wdev, sizeof(*wdev));
3729 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
3730 return NULL;
3731 }
3732 }
3733
3734 /* Initialize with the station mode params */
3735 ret = wl_alloc_netinfo(cfg, new_ndev, wdev, wl_iftype,
3736 PM_ENABLE, event->bssidx, event->ifidx);
3737 if (unlikely(ret)) {
3738 WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret));
3739 goto fail;
3740 }
3741
3742 /* Apply the mode & infra setting based on iftype */
3743 if ((ret = wl_config_infra(cfg, new_ndev, wl_iftype)) < 0) {
3744 WL_ERR(("config ifmode failure (%d)\n", ret));
3745 goto fail;
3746 }
3747
3748 if (mode == WL_MODE_AP) {
3749 wl_set_drv_status(cfg, AP_CREATING, new_ndev);
3750 }
3751 #ifdef WL_EXT_IAPSTA
3752 wl_ext_iapsta_update_iftype(new_ndev, event->ifidx, wl_iftype);
3753 #endif
3754
3755 WL_INFORM_MEM(("Network Interface (%s) registered with host."
3756 " cfg_iftype:%d wl_role:%d " MACDBG "\n",
3757 new_ndev->name, iface_type, event->role, MAC2STRDBG(new_ndev->dev_addr)));
3758
3759 #ifdef SUPPORT_SET_CAC
3760 wl_cfg80211_set_cac(cfg, 0);
3761 #endif /* SUPPORT_SET_CAC */
3762
3763 return new_ndev;
3764
3765 fail:
3766 #ifdef WL_STATIC_IF
3767 /* remove static if from iflist */
3768 if (IS_CFG80211_STATIC_IF_NAME(cfg, name)) {
3769 cfg->static_ndev_state = NDEV_STATE_FW_IF_FAILED;
3770 wl_cfg80211_update_iflist_info(cfg, new_ndev, WL_STATIC_IFIDX, addr,
3771 event->bssidx, event->name, NDEV_STATE_FW_IF_FAILED);
3772 }
3773 #endif /* WL_STATIC_IF */
3774 if (new_ndev) {
3775 /* wdev would be freed from netdev destructor call back */
3776 wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
3777 }
3778
3779 return NULL;
3780 }
3781
3782 s32
wl_cfg80211_delete_iface(struct bcm_cfg80211 * cfg,wl_iftype_t sec_data_if_type)3783 wl_cfg80211_delete_iface(struct bcm_cfg80211 *cfg,
3784 wl_iftype_t sec_data_if_type)
3785 {
3786 struct net_info *iter, *next;
3787 struct net_device *primary_ndev;
3788 s32 ret = BCME_OK;
3789 uint8 i = 0;
3790
3791 BCM_REFERENCE(i);
3792 BCM_REFERENCE(ret);
3793
3794 /* Note: This function will clean up only the network interface and host
3795 * data structures. The firmware interface clean up will happen in the
3796 * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
3797 * context for the module case).
3798 */
3799 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3800 WL_DBG(("Enter, deleting iftype %s\n",
3801 wl_iftype_to_str(sec_data_if_type)));
3802 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3803 for_each_ndev(cfg, iter, next) {
3804 GCC_DIAGNOSTIC_POP();
3805 if (iter->ndev && (iter->ndev != primary_ndev)) {
3806 if (iter->iftype != sec_data_if_type) {
3807 continue;
3808 }
3809 switch (sec_data_if_type) {
3810 case WL_IF_TYPE_P2P_GO:
3811 case WL_IF_TYPE_P2P_GC: {
3812 ret = _wl_cfg80211_del_if(cfg,
3813 iter->ndev, NULL, iter->ndev->name);
3814 break;
3815 }
3816 #ifdef WL_NAN
3817 case WL_IF_TYPE_NAN: {
3818 if (wl_cfgnan_is_enabled(cfg) == false) {
3819 WL_INFORM_MEM(("Nan is not active,"
3820 " ignore NDI delete\n"));
3821 } else {
3822 ret = wl_cfgnan_delete_ndp(cfg, iter->ndev);
3823 }
3824 break;
3825 }
3826 #endif /* WL_NAN */
3827 case WL_IF_TYPE_AP: {
3828 /* Cleanup AP */
3829 #ifdef WL_STATIC_IF
3830 /* handle static ap */
3831 if (IS_CFG80211_STATIC_IF(cfg, iter->ndev)) {
3832 dev_close(iter->ndev);
3833 } else
3834 #endif /* WL_STATIC_IF */
3835 {
3836 /* handle virtual created AP */
3837 ret = _wl_cfg80211_del_if(cfg, iter->ndev,
3838 NULL, iter->ndev->name);
3839 }
3840 break;
3841 }
3842 default: {
3843 WL_ERR(("Unsupported interface type\n"));
3844 ret = -ENOTSUPP;
3845 goto fail;
3846 }
3847 }
3848 }
3849 }
3850 fail:
3851 return ret;
3852 }
3853
3854 s32
wl_cfg80211_post_ifdel(struct net_device * ndev,bool rtnl_lock_reqd,s32 ifidx)3855 wl_cfg80211_post_ifdel(struct net_device *ndev, bool rtnl_lock_reqd, s32 ifidx)
3856 {
3857 s32 ret = BCME_OK;
3858 struct bcm_cfg80211 *cfg;
3859 struct net_info *netinfo = NULL;
3860
3861 if (!ndev || !ndev->ieee80211_ptr) {
3862 /* No wireless dev done for this interface */
3863 ret = -EINVAL;
3864 goto exit;
3865 }
3866
3867 cfg = wl_get_cfg(ndev);
3868 if (!cfg) {
3869 WL_ERR(("cfg null\n"));
3870 ret = BCME_ERROR;
3871 goto exit;
3872 }
3873
3874 if (ifidx <= 0) {
3875 WL_ERR(("Invalid IF idx for iface:%s\n", ndev->name));
3876 #if defined(BCMDONGLEHOST)
3877 ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
3878 BCM_REFERENCE(ifidx);
3879 #endif
3880 if (ifidx <= 0) {
3881 ASSERT(0);
3882 ret = BCME_ERROR;
3883 goto exit;
3884 }
3885 }
3886
3887 if ((netinfo = wl_get_netinfo_by_wdev(cfg, ndev_to_wdev(ndev))) == NULL) {
3888 WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev)));
3889 ret = -ENODEV;
3890 goto exit;
3891 }
3892
3893 #ifdef WL_STATIC_IF
3894 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
3895 ret = wl_cfg80211_post_static_ifdel(cfg, ndev);
3896 } else
3897 #endif /* WL_STATIC_IF */
3898 {
3899 WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
3900 ndev->name, ifidx, cfg->vif_count));
3901 wl_cfg80211_remove_if(cfg, ifidx, ndev, rtnl_lock_reqd);
3902 cfg->bss_pending_op = FALSE;
3903 }
3904
3905 #ifdef SUPPORT_SET_CAC
3906 wl_cfg80211_set_cac(cfg, 1);
3907 #endif /* SUPPORT_SET_CAC */
3908 exit:
3909 return ret;
3910 }
3911
3912 int
wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 * cfg)3913 wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 *cfg)
3914 {
3915 s32 ret = BCME_OK;
3916 bcm_struct_cfgdev *cfgdev;
3917
3918 if (cfg->p2p) {
3919 /* De-initialize the p2p discovery interface, if operational */
3920 WL_ERR(("Disabling P2P Discovery Interface \n"));
3921 #ifdef WL_CFG80211_P2P_DEV_IF
3922 cfgdev = bcmcfg_to_p2p_wdev(cfg);
3923 #else
3924 cfgdev = cfg->p2p_net;
3925 #endif
3926 if (cfgdev) {
3927 ret = wl_cfg80211_scan_stop(cfg, cfgdev);
3928 if (unlikely(ret < 0)) {
3929 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
3930 }
3931 }
3932
3933 wl_cfgp2p_disable_discovery(cfg);
3934 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
3935 p2p_on(cfg) = false;
3936 }
3937 return ret;
3938 }
3939
3940 /* Create a Generic Network Interface and initialize it depending up on
3941 * the interface type
3942 */
3943 struct wireless_dev *
wl_cfg80211_create_iface(struct wiphy * wiphy,wl_iftype_t wl_iftype,u8 * mac_addr,const char * name)3944 wl_cfg80211_create_iface(struct wiphy *wiphy,
3945 wl_iftype_t wl_iftype,
3946 u8 *mac_addr, const char *name)
3947 {
3948 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3949 struct net_device *new_ndev = NULL;
3950 struct net_device *primary_ndev = NULL;
3951 s32 ret = BCME_OK;
3952 s32 bsscfg_idx = 0;
3953 long timeout;
3954 wl_if_event_info *event = NULL;
3955 u8 addr[ETH_ALEN];
3956 struct net_info *iter, *next;
3957
3958 WL_DBG(("Enter\n"));
3959 if (!name) {
3960 WL_ERR(("Interface name not provided\n"));
3961 return NULL;
3962 }
3963 else {
3964 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
3965 for_each_ndev(cfg, iter, next) {
3966 GCC_DIAGNOSTIC_POP();
3967 if (iter->ndev) {
3968 if (strncmp(iter->ndev->name, name, strlen(name)) == 0) {
3969 WL_ERR(("Interface name,%s exists!\n", iter->ndev->name));
3970 return NULL;
3971 }
3972 }
3973 }
3974 }
3975 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3976 if (likely(!mac_addr)) {
3977 /* Use primary MAC with the locally administered bit for the
3978 * Secondary STA I/F
3979 */
3980 memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
3981 addr[0] |= 0x02;
3982 } else {
3983 /* Use the application provided mac address (if any) */
3984 memcpy(addr, mac_addr, ETH_ALEN);
3985 }
3986
3987 cfg->bss_pending_op = TRUE;
3988 bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
3989
3990 /*
3991 * Intialize the firmware I/F.
3992 */
3993
3994 #ifdef CUSTOMER_HW6
3995 if (wl_customer6_legacy_chip_check(cfg, primary_ndev)) {
3996 /* Use bss iovar instead of interface_create iovar */
3997 ret = BCME_UNSUPPORTED;
3998 } else
3999 #endif /* CUSTOMER_HW6 */
4000
4001 {
4002 ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
4003 wl_iftype, 0, addr);
4004 }
4005 if (ret == BCME_UNSUPPORTED) {
4006 /* Use bssidx 1 by default */
4007 bsscfg_idx = 1;
4008 if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
4009 bsscfg_idx, wl_iftype, 0, addr)) < 0) {
4010 goto exit;
4011 }
4012 } else if (ret < 0) {
4013 WL_ERR(("Interface create failed!! ret:%d \n", ret));
4014 goto exit;
4015 } else {
4016 /* Success */
4017 bsscfg_idx = ret;
4018 }
4019
4020 WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
4021 /*
4022 * Wait till the firmware send a confirmation event back.
4023 */
4024 WL_DBG(("Wait for the FW I/F Event\n"));
4025 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4026 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4027 if (timeout <= 0 || cfg->bss_pending_op) {
4028 WL_ERR(("ADD_IF event, didn't come. Return. timeout:%lu bss_pending_op:%d\n",
4029 timeout, cfg->bss_pending_op));
4030 if (timeout == -ERESTARTSYS) {
4031 WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
4032 }
4033 goto exit;
4034 }
4035
4036 event = &cfg->if_event_info;
4037 /*
4038 * Since FW operation is successful,we can go ahead with the
4039 * the host interface creation.
4040 */
4041 new_ndev = wl_cfg80211_post_ifcreate(primary_ndev,
4042 event, addr, name, false);
4043
4044 if (new_ndev) {
4045 /* Iface post ops successful. Return ndev/wdev ptr */
4046 return new_ndev->ieee80211_ptr;
4047 }
4048
4049 exit:
4050 cfg->bss_pending_op = FALSE;
4051 return NULL;
4052 }
4053
4054 s32
wl_cfg80211_del_iface(struct wiphy * wiphy,struct wireless_dev * wdev)4055 wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
4056 {
4057 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4058 struct net_device *ndev = NULL;
4059 s32 ret = BCME_OK;
4060 s32 bsscfg_idx = 1;
4061 long timeout;
4062 u16 wl_iftype;
4063 u16 wl_mode;
4064
4065 WL_DBG(("Enter\n"));
4066
4067 /* If any scan is going on, abort it */
4068 if (wl_get_drv_status_all(cfg, SCANNING)) {
4069 WL_DBG(("Scan in progress. Aborting the scan!\n"));
4070 wl_cfgscan_cancel_scan(cfg);
4071 }
4072
4073 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, wdev);
4074 if (bsscfg_idx <= 0) {
4075 /* validate bsscfgidx */
4076 WL_ERR(("Wrong bssidx! \n"));
4077 return -EINVAL;
4078 }
4079
4080 /* Handle p2p iface */
4081 if ((ret = wl_cfg80211_p2p_if_del(wiphy, wdev)) != BCME_NOTFOUND) {
4082 WL_DBG(("P2P iface del handled \n"));
4083 #ifdef SUPPORT_SET_CAC
4084 wl_cfg80211_set_cac(cfg, 1);
4085 #endif /* SUPPORT_SET_CAC */
4086 return ret;
4087 }
4088
4089 ndev = wdev->netdev;
4090 if (unlikely(!ndev)) {
4091 WL_ERR(("ndev null! \n"));
4092 return -EINVAL;
4093 }
4094
4095 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4096
4097 if (cfg80211_to_wl_iftype(ndev->ieee80211_ptr->iftype,
4098 &wl_iftype, &wl_mode) < 0) {
4099 return -EINVAL;
4100 }
4101
4102 WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d",
4103 bsscfg_idx, ndev->ieee80211_ptr->iftype, wl_iftype));
4104 /* Delete the firmware interface. "interface_remove" command
4105 * should go on the interface to be deleted
4106 */
4107 if (wl_cfg80211_get_bus_state(cfg)) {
4108 WL_ERR(("Bus state is down: %d\n", __LINE__));
4109 ret = BCME_DONGLE_DOWN;
4110 goto exit;
4111 }
4112
4113 cfg->bss_pending_op = true;
4114 ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx,
4115 wl_iftype, 1, NULL);
4116 if (ret == BCME_UNSUPPORTED) {
4117 if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
4118 bsscfg_idx, wl_iftype, true, NULL)) < 0) {
4119 WL_ERR(("DEL bss failed ret:%d \n", ret));
4120 goto exit;
4121 }
4122 } else if ((ret == BCME_NOTAP) || (ret == BCME_NOTSTA)) {
4123 /* De-init sequence involving role downgrade not happened.
4124 * Do nothing and return error. The del command should be
4125 * retried.
4126 */
4127 WL_ERR(("ifdel role mismatch:%d\n", ret));
4128 ret = -EBADTYPE;
4129 goto exit;
4130 } else if (ret < 0) {
4131 WL_ERR(("Interface DEL failed ret:%d \n", ret));
4132 goto exit;
4133 }
4134
4135 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
4136 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
4137 if (timeout <= 0 || cfg->bss_pending_op) {
4138 WL_ERR(("timeout in waiting IF_DEL event\n"));
4139 /* The interface unregister will happen from wifi reset context */
4140 ret = -ETIMEDOUT;
4141 /* fall through */
4142 }
4143
4144 exit:
4145 if (ret < 0) {
4146 WL_ERR(("iface del failed:%d\n", ret));
4147 #ifdef WL_STATIC_IF
4148 if (IS_CFG80211_STATIC_IF(cfg, ndev)) {
4149 /*
4150 * For static interface, clean up the host data,
4151 * irrespective of fw status. For dynamic
4152 * interfaces it gets cleaned from dhd_stop context
4153 */
4154 wl_cfg80211_post_static_ifdel(cfg, ndev);
4155 }
4156 #endif /* WL_STATIC_IF */
4157 } else {
4158 ret = wl_cfg80211_post_ifdel(ndev, false, cfg->if_event_info.ifidx);
4159 if (unlikely(ret)) {
4160 WL_ERR(("post_ifdel failed\n"));
4161 }
4162 }
4163
4164 cfg->bss_pending_op = false;
4165 return ret;
4166 }
4167
4168 static s32
wl_cfg80211_join_ibss(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ibss_params * params)4169 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
4170 struct cfg80211_ibss_params *params)
4171 {
4172 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4173 struct cfg80211_bss *bss;
4174 struct ieee80211_channel *chan;
4175 struct wl_join_params join_params;
4176 int scan_suppress;
4177 struct cfg80211_ssid ssid;
4178 s32 scan_retry = 0;
4179 s32 err = 0;
4180 size_t join_params_size;
4181 chanspec_t chanspec = 0;
4182
4183 WL_TRACE(("In\n"));
4184 RETURN_EIO_IF_NOT_UP(cfg);
4185 WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
4186 if (!params->ssid || params->ssid_len <= 0 ||
4187 params->ssid_len > DOT11_MAX_SSID_LEN) {
4188 WL_ERR(("Invalid parameter\n"));
4189 return -EINVAL;
4190 }
4191 #if defined(WL_CFG80211_P2P_DEV_IF)
4192 chan = params->chandef.chan;
4193 #else
4194 chan = params->channel;
4195 #endif /* WL_CFG80211_P2P_DEV_IF */
4196 if (chan) {
4197 cfg->channel = wl_freq_to_chanspec(chan->center_freq);
4198 }
4199 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
4200 struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
4201 u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
4202 u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
4203 if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
4204 (memcmp(params->ssid, lssid->SSID, lssid->SSID_len) == 0) &&
4205 (*channel == cfg->channel))) {
4206 WL_ERR(("Connection already existed to " MACDBG "\n",
4207 MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
4208 return -EISCONN;
4209 }
4210 WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n",
4211 lssid->SSID, MAC2STRDBG(bssid)));
4212 }
4213
4214 /* remove the VSIE */
4215 wl_cfg80211_ibss_vsie_delete(dev);
4216
4217 bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
4218 if (!bss) {
4219 if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
4220 memcpy(ssid.ssid, params->ssid, params->ssid_len);
4221 ssid.ssid_len = params->ssid_len;
4222 do {
4223 if (unlikely
4224 (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
4225 -EBUSY)) {
4226 wl_delay(150);
4227 } else {
4228 break;
4229 }
4230 } while (++scan_retry < WL_SCAN_RETRY_MAX);
4231
4232 /* rtnl lock code is removed here. don't see why rtnl lock
4233 * needs to be released.
4234 */
4235
4236 /* wait 4 secons till scan done.... */
4237 schedule_timeout_interruptible(msecs_to_jiffies(4000));
4238
4239 bss = cfg80211_get_ibss(wiphy, NULL,
4240 params->ssid, params->ssid_len);
4241 }
4242 }
4243 if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
4244 ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
4245 !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
4246 cfg->ibss_starter = false;
4247 WL_DBG(("Found IBSS\n"));
4248 } else {
4249 cfg->ibss_starter = true;
4250 }
4251
4252 if (bss) {
4253 CFG80211_PUT_BSS(wiphy, bss);
4254 }
4255
4256 if (chan) {
4257 u32 bw_cap = 0;
4258 err = wl_get_bandwidth_cap(dev, CHSPEC_BAND(cfg->channel), &bw_cap);
4259 if (unlikely(err)) {
4260 WL_ERR(("Failed to get bandwidth capability (%d)\n", err));
4261 return err;
4262 }
4263 chanspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(cfg->channel),
4264 bw_cap, CHSPEC_BAND(cfg->channel));
4265 }
4266
4267 /*
4268 * Join with specific BSSID and cached SSID
4269 * If SSID is zero join based on BSSID only
4270 */
4271 bzero(&join_params, sizeof(join_params));
4272 memcpy((void *)join_params.ssid.SSID, (const void *)params->ssid,
4273 params->ssid_len);
4274 join_params.ssid.SSID_len = htod32(params->ssid_len);
4275 if (params->bssid) {
4276 memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
4277 err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
4278 ETHER_ADDR_LEN);
4279 if (unlikely(err)) {
4280 WL_ERR(("Error (%d)\n", err));
4281 return err;
4282 }
4283 } else
4284 bzero(&join_params.params.bssid, ETHER_ADDR_LEN);
4285
4286 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
4287 scan_suppress = TRUE;
4288 /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
4289 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
4290 &scan_suppress, sizeof(int));
4291 if (unlikely(err)) {
4292 WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
4293 return err;
4294 }
4295 }
4296
4297 join_params.params.chanspec_list[0] = chanspec;
4298 join_params.params.chanspec_num = 1;
4299 wldev_iovar_setint(dev, "chanspec", chanspec);
4300 join_params_size = sizeof(join_params);
4301
4302 /* Disable Authentication, IBSS will add key if it required */
4303 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
4304 wldev_iovar_setint(dev, "wsec", 0);
4305
4306 err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
4307 join_params_size);
4308 if (unlikely(err)) {
4309 WL_ERR(("IBSS set_ssid Error (%d)\n", err));
4310 return err;
4311 }
4312
4313 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
4314 scan_suppress = FALSE;
4315 /* Reset the SCAN SUPPRESS Flag */
4316 err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
4317 &scan_suppress, sizeof(int));
4318 if (unlikely(err)) {
4319 WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
4320 return err;
4321 }
4322 }
4323 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
4324 wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
4325 #ifdef WLAIBSS
4326 cfg->aibss_txfail_seq = 0; /* initialize the sequence */
4327 #endif /* WLAIBSS */
4328 #ifdef WL_RELMCAST
4329 cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
4330 #endif /* WL_RELMCAST */
4331 return err;
4332 }
4333
wl_cfg80211_leave_ibss(struct wiphy * wiphy,struct net_device * dev)4334 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
4335 {
4336 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4337 s32 err = 0;
4338 scb_val_t scbval;
4339 u8 *curbssid;
4340
4341 RETURN_EIO_IF_NOT_UP(cfg);
4342 wl_link_down(cfg);
4343
4344 WL_INFORM_MEM(("Leave IBSS\n"));
4345 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
4346 wl_set_drv_status(cfg, DISCONNECTING, dev);
4347 scbval.val = 0;
4348 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
4349 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
4350 sizeof(scb_val_t));
4351 if (unlikely(err)) {
4352 wl_clr_drv_status(cfg, DISCONNECTING, dev);
4353 WL_ERR(("error(%d)\n", err));
4354 return err;
4355 }
4356
4357 /* remove the VSIE */
4358 wl_cfg80211_ibss_vsie_delete(dev);
4359
4360 return err;
4361 }
4362
4363 #ifdef MFP
4364 static
wl_cfg80211_get_rsn_capa(const bcm_tlv_t * wpa2ie,const u8 ** rsn_cap)4365 int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie,
4366 const u8** rsn_cap)
4367 {
4368 u16 suite_count;
4369 const wpa_suite_mcast_t *mcast;
4370 const wpa_suite_ucast_t *ucast;
4371 int len;
4372 const wpa_suite_auth_key_mgmt_t *mgmt;
4373
4374 if (!wpa2ie)
4375 return BCME_BADARG;
4376
4377 len = wpa2ie->len;
4378
4379 /* check for Multicast cipher suite */
4380 if ((len -= (WPA_SUITE_LEN + WPA2_VERSION_LEN)) <= 0) {
4381 return BCME_NOTFOUND;
4382 }
4383
4384 mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
4385
4386 /* Check for the unicast suite(s) */
4387 if (len < WPA_IE_SUITE_COUNT_LEN) {
4388 return BCME_NOTFOUND;
4389 }
4390
4391 ucast = (const wpa_suite_ucast_t *)&mcast[1];
4392 suite_count = ltoh16_ua(&ucast->count);
4393 if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
4394 (len -= (WPA_IE_SUITE_COUNT_LEN +
4395 (WPA_SUITE_LEN * suite_count))) <= 0)
4396 return BCME_BADLEN;
4397
4398 /* Check for AUTH key management suite(s) */
4399 if (len < WPA_IE_SUITE_COUNT_LEN) {
4400 return BCME_NOTFOUND;
4401 }
4402
4403 mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
4404 suite_count = ltoh16_ua(&mgmt->count);
4405
4406 if ((suite_count <= NL80211_MAX_NR_CIPHER_SUITES) &&
4407 (len -= (WPA_IE_SUITE_COUNT_LEN +
4408 (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
4409 rsn_cap[0] = (const u8 *)&mgmt->list[suite_count];
4410 } else {
4411 return BCME_BADLEN;
4412 }
4413
4414 return BCME_OK;
4415 }
4416 #endif /* MFP */
4417
4418 static s32
wl_set_wpa_version(struct net_device * dev,struct cfg80211_connect_params * sme)4419 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
4420 {
4421 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4422 struct wl_security *sec;
4423 s32 val = 0;
4424 s32 err = 0;
4425 s32 bssidx;
4426
4427 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4428 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4429 return BCME_ERROR;
4430 }
4431
4432 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
4433 val = WPA_AUTH_PSK |
4434 WPA_AUTH_UNSPECIFIED;
4435 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
4436 val = WPA2_AUTH_PSK|
4437 WPA2_AUTH_UNSPECIFIED;
4438 else
4439 val = WPA_AUTH_DISABLED;
4440
4441 if (is_wps_conn(sme))
4442 val = WPA_AUTH_DISABLED;
4443
4444 WL_DBG_MEM(("[%s] wl wpa_auth 0x%0x\n", dev->name, val));
4445 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
4446 if (unlikely(err)) {
4447 WL_ERR(("set wpa_auth failed (%d)\n", err));
4448 return err;
4449 }
4450 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4451 sec->wpa_versions = sme->crypto.wpa_versions;
4452 return err;
4453 }
4454
4455 #ifdef BCMWAPI_WPI
4456 static s32
wl_set_set_wapi_ie(struct net_device * dev,struct cfg80211_connect_params * sme)4457 wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme)
4458 {
4459 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4460 s32 err = 0;
4461 s32 bssidx;
4462
4463 WL_DBG((" wl_set_set_wapi_ie\n"));
4464 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4465 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4466 return BCME_ERROR;
4467 }
4468
4469 err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", (const void *)sme->ie, sme->ie_len,
4470 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
4471 if (unlikely(err)) {
4472 WL_ERR(("set_wapi_ie Error (%d)\n", err));
4473 return err;
4474 }
4475 WL_DBG_MEM(("wapi_ie successfully (%s)\n", dev->name));
4476 return err;
4477 }
4478 #endif /* BCMWAPI_WPI */
4479
4480 static s32
wl_set_auth_type(struct net_device * dev,struct cfg80211_connect_params * sme)4481 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
4482 {
4483 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4484 struct wl_security *sec;
4485 s32 val = 0;
4486 s32 err = 0;
4487 s32 bssidx;
4488
4489 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4490 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4491 return BCME_ERROR;
4492 }
4493
4494 switch (sme->auth_type) {
4495 case NL80211_AUTHTYPE_OPEN_SYSTEM:
4496 val = WL_AUTH_OPEN_SYSTEM;
4497 WL_DBG(("open system\n"));
4498 break;
4499 case NL80211_AUTHTYPE_SHARED_KEY:
4500 val = WL_AUTH_SHARED_KEY;
4501 WL_DBG(("shared key\n"));
4502 break;
4503 case NL80211_AUTHTYPE_AUTOMATIC:
4504 val = WL_AUTH_OPEN_SHARED;
4505 WL_DBG(("automatic\n"));
4506 break;
4507 #ifdef WL_FILS
4508 case NL80211_AUTHTYPE_FILS_SK:
4509 WL_DBG(("fils shared key\n"));
4510 val = WL_AUTH_FILS_SHARED;
4511 break;
4512 case NL80211_AUTHTYPE_FILS_SK_PFS:
4513 val = WL_AUTH_FILS_SHARED_PFS;
4514 WL_DBG(("fils shared key with pfs\n"));
4515 break;
4516 case NL80211_AUTHTYPE_FILS_PK:
4517 WL_DBG(("fils public key\n"));
4518 val = WL_AUTH_FILS_PUBLIC;
4519 break;
4520 #endif /* WL_FILS */
4521 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
4522 case NL80211_AUTHTYPE_SAE:
4523 #ifdef WL_CLIENT_SAE
4524 if (!wl_is_pmkid_available(dev, sme->bssid))
4525 val = DOT11_SAE;
4526 else
4527 #endif /* WL_CLIENT_SAE */
4528 {
4529 /* Fw will choose right auth type
4530 * dynamically based on PMKID availability
4531 */
4532 val = WL_AUTH_OPEN_SHARED;
4533 }
4534
4535 WL_DBG(("sae auth type\n"));
4536 break;
4537 #endif /* WL_SAE || WL_CLIENT_SAE */
4538 default:
4539 val = 2;
4540 WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
4541 break;
4542 }
4543
4544 WL_DBG_MEM(("[%s] wl auth 0x%0x \n", dev->name, val));
4545 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
4546 if (unlikely(err)) {
4547 WL_ERR(("set auth failed (%d)\n", err));
4548 return err;
4549 }
4550 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4551 sec->auth_type = sme->auth_type;
4552 sec->fw_auth = val;
4553 return err;
4554 }
4555
4556 static u32
wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)4557 wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)
4558 {
4559 uint i;
4560
4561 for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
4562 if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
4563 return rsn_cipher_algo_lookup_tbl[i].wsec_algo;
4564 }
4565 }
4566 return WSEC_NONE;
4567 }
4568
4569 static u32
wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)4570 wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)
4571 {
4572 uint i;
4573
4574 for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
4575 if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
4576 return rsn_cipher_algo_lookup_tbl[i].wsec_key_algo;
4577 }
4578 }
4579 return CRYPTO_ALGO_OFF;
4580 }
4581
4582 static u32
wl_rsn_akm_wpa_auth_lookup(uint32 akm)4583 wl_rsn_akm_wpa_auth_lookup(uint32 akm)
4584 {
4585 uint i;
4586
4587 for (i = 0; i < ARRAYSIZE(rsn_akm_wpa_auth_lookup_tbl); i++) {
4588 if (akm == rsn_akm_wpa_auth_lookup_tbl[i].akm_suite) {
4589 return rsn_akm_wpa_auth_lookup_tbl[i].wpa_auth;
4590 }
4591 }
4592 return WPA_AUTH_DISABLED;
4593 }
4594
4595 static s32
wl_set_set_cipher(struct net_device * dev,struct cfg80211_connect_params * sme)4596 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
4597 {
4598 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4599 struct wl_security *sec;
4600 s32 pval = 0;
4601 s32 gval = 0;
4602 s32 err = 0;
4603 s32 wsec_val = 0;
4604
4605 #ifdef BCMWAPI_WPI
4606 s32 wapi_val = 0;
4607 s32 val = 0;
4608 #endif
4609
4610 s32 bssidx;
4611 #ifdef WL_GCMP
4612 uint32 algos = 0, mask = 0;
4613 #endif /* WL_GCMP */
4614
4615 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4616 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4617 return BCME_ERROR;
4618 }
4619
4620 if (sme->crypto.n_ciphers_pairwise) {
4621 pval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.ciphers_pairwise[0]);
4622 if (pval == WSEC_NONE) {
4623 WL_ERR(("Invalid cipher (0x%x)\n",
4624 sme->crypto.ciphers_pairwise[0]));
4625 return BCME_BADARG;
4626 }
4627 switch (sme->crypto.ciphers_pairwise[0]) {
4628
4629 #ifdef BCMWAPI_WPI
4630 case WLAN_CIPHER_SUITE_SMS4:
4631 #ifndef CUSTOMER_HW6
4632 if (!IS_WAPI_VER(sme->crypto.wpa_versions)) {
4633 WL_ERR(("Invalid WAPI version %d\n", sme->crypto.wpa_versions));
4634 return BCME_BADARG;
4635 }
4636 #endif /* !CUSTOMER_HW6 */
4637 val = pval;
4638 err = wl_set_set_wapi_ie(dev, sme);
4639 if (unlikely(err)) {
4640 WL_DBG(("Set wapi ie failed \n"));
4641 return err;
4642 } else {
4643 WL_DBG(("Set wapi ie succeded\n"));
4644 }
4645 wapi_val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
4646 WL_DBG_MEM(("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val, dev->name));
4647 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wapi_val, bssidx);
4648 if (unlikely(err)) {
4649 WL_ERR(("set wpa_auth failed (%d)\n", err));
4650 return err;
4651 }
4652 break;
4653 #endif /* BCMWAPI_WPI */
4654
4655 #ifdef WL_GCMP
4656 case WLAN_CIPHER_SUITE_GCMP:
4657 case WLAN_CIPHER_SUITE_GCMP_256:
4658 algos = KEY_ALGO_MASK(wl_rsn_cipher_wsec_key_algo_lookup(
4659 sme->crypto.ciphers_pairwise[0]));
4660 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
4661 break;
4662 #endif /* WL_GCMP */
4663 default: /* No post processing required */
4664 break;
4665 }
4666 }
4667 #if defined(BCMSUP_4WAY_HANDSHAKE)
4668 /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
4669 * handshake.
4670 * Note that the FW feature flag only exists on kernels that support the
4671 * FT-EAP AKM suite.
4672 */
4673 if (cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) {
4674 err = wldev_iovar_setint_bsscfg(dev, "sup_wpa", 1, bssidx);
4675 if (err) {
4676 WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err));
4677 return err;
4678 } else {
4679 WL_INFORM_MEM(("idsup enabled.\n"));
4680 }
4681 }
4682 #endif /* BCMSUP_4WAY_HANDSHAKE */
4683 if (sme->crypto.cipher_group) {
4684 gval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.cipher_group);
4685 if (gval == WSEC_NONE) {
4686 WL_ERR(("invalid cipher group (0x%x)\n", sme->crypto.cipher_group));
4687 return BCME_BADARG;
4688 }
4689 switch (sme->crypto.cipher_group) {
4690
4691 #ifdef BCMWAPI_WPI
4692 case WLAN_CIPHER_SUITE_SMS4:
4693 val = gval;
4694 break;
4695 #endif
4696
4697 #ifdef WL_GCMP
4698 case WLAN_CIPHER_SUITE_GCMP:
4699 case WLAN_CIPHER_SUITE_GCMP_256:
4700 algos = KEY_ALGO_MASK(
4701 wl_rsn_cipher_wsec_key_algo_lookup(sme->crypto.cipher_group));
4702 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
4703 break;
4704 #endif /* WL_GCMP */
4705 default: /* No post processing required */
4706 break;
4707 }
4708 }
4709
4710 WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
4711 #ifdef WL_GCMP
4712 WL_DBG(("algos:%x, mask:%x", algos, mask));
4713 #endif /* WL_GCMP */
4714
4715 if (is_wps_conn(sme)) {
4716 if (sme->privacy) {
4717 wsec_val = 4;
4718 } else {
4719 /* WPS-2.0 allows no security */
4720 wsec_val = 0;
4721 }
4722 } else {
4723
4724 #ifdef BCMWAPI_WPI
4725 if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) {
4726 WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
4727 wsec_val = val;
4728 } else
4729 #endif
4730
4731 {
4732 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
4733 wsec_val = pval | gval;
4734 }
4735 }
4736
4737 WL_DBG_MEM(("[%s] wl wsec 0x%x\n", dev->name, wsec_val));
4738 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec_val, bssidx);
4739 if (unlikely(err)) {
4740 WL_ERR(("error (%d)\n", err));
4741 return err;
4742 }
4743 #ifdef WL_GCMP
4744 if (wl_set_wsec_info_algos(dev, algos, mask)) {
4745 WL_ERR(("set wsec_info error (%d)\n", err));
4746 }
4747 #endif /* WL_GCMP */
4748 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4749 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
4750 sec->cipher_group = sme->crypto.cipher_group;
4751 sec->fw_wsec = wsec_val;
4752 return err;
4753 }
4754 #ifdef WL_GCMP
4755 static s32
wl_set_wsec_info_algos(struct net_device * dev,uint32 algos,uint32 mask)4756 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask)
4757 {
4758 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4759 s32 bssidx;
4760 s32 err = 0;
4761 wl_wsec_info_t *wsec_info;
4762 bcm_xtlv_t *wsec_info_tlv;
4763 uint16 tlv_data_len;
4764 uint32 tlv_data[2];
4765 uint32 param_len;
4766 uint8 * buf;
4767
4768 WL_DBG(("enter.\n"));
4769 if (!cfg) {
4770 return BCME_ERROR;
4771 }
4772 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4773 WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
4774 return BCME_ERROR;
4775 }
4776
4777 buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
4778 if (!buf) {
4779 WL_ERR(("No memory"));
4780 return BCME_NOMEM;
4781 }
4782 wsec_info = (wl_wsec_info_t *)buf;
4783 wsec_info->version = WL_WSEC_INFO_VERSION;
4784 wsec_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
4785
4786 wsec_info->num_tlvs++;
4787 tlv_data_len = sizeof(tlv_data);
4788 tlv_data[0] = algos;
4789 tlv_data[1] = mask;
4790
4791 bcm_xtlv_pack_xtlv(wsec_info_tlv, WL_WSEC_INFO_BSS_ALGOS, tlv_data_len,
4792 (const uint8 *)tlv_data, 0);
4793 param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN + tlv_data_len;
4794
4795 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
4796 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
4797
4798 MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
4799 return err;
4800 }
4801 #endif /* WL_GCMP */
4802
4803 #ifdef WL_SAE
4804 s32
wl_cfg80211_set_wsec_info(struct net_device * dev,uint32 * data,uint16 data_len,int tag)4805 wl_cfg80211_set_wsec_info(struct net_device *dev, uint32 *data,
4806 uint16 data_len, int tag)
4807 {
4808 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4809 s32 bssidx;
4810 s32 err = 0;
4811 wl_wsec_info_t *wsec_info;
4812 bcm_xtlv_t *bcm_info_tlv;
4813 uint32 param_len;
4814 uint8 *buf = NULL;
4815
4816 if (!cfg) {
4817 return BCME_ERROR;
4818 }
4819
4820 if (data_len > WLC_IOCTL_SMLEN) {
4821 err = BCME_BADLEN;
4822 goto exit;
4823 }
4824
4825 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4826 WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
4827 err = BCME_ERROR;
4828 goto exit;
4829 }
4830
4831 buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + data_len);
4832 if (!buf) {
4833 WL_ERR(("No memory"));
4834 err = BCME_NOMEM;
4835 goto exit;
4836 }
4837
4838 wsec_info = (wl_wsec_info_t *)buf;
4839 bzero(wsec_info, sizeof(wl_wsec_info_t) + data_len);
4840 wsec_info->version = WL_WSEC_INFO_VERSION;
4841 bcm_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
4842
4843 wsec_info->num_tlvs++;
4844
4845 bcm_xtlv_pack_xtlv(bcm_info_tlv, tag, data_len, (const u8*)data, 0);
4846 param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN + data_len;
4847
4848 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
4849 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
4850 if (unlikely(err) && (err != BCME_UNSUPPORTED)) {
4851 WL_ERR(("set wsec_info error (%d)\n", err));
4852 }
4853
4854 exit:
4855 if (buf)
4856 MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + data_len);
4857 return err;
4858 }
4859 #endif /* SAE */
4860
4861 #ifdef MFP
4862 static s32
wl_cfg80211_set_mfp(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme)4863 wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
4864 struct net_device *dev,
4865 struct cfg80211_connect_params *sme)
4866 {
4867 s32 mfp = WL_MFP_NONE;
4868 s32 current_mfp = WL_MFP_NONE;
4869 const bcm_tlv_t *wpa2_ie;
4870 const u8* rsn_cap = NULL;
4871 bool fw_support = false;
4872 int err, count = 0;
4873 const u8 *eptr = NULL, *ptr = NULL;
4874 const u8* group_mgmt_cs = NULL;
4875 const wpa_pmkid_list_t* pmkid = NULL;
4876 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4877
4878 if (!sme) {
4879 /* No connection params from userspace, Do nothing. */
4880 return 0;
4881 }
4882
4883 /* Check fw support and retreive current mfp val */
4884 err = wldev_iovar_getint(dev, "mfp", ¤t_mfp);
4885 if (!err) {
4886 fw_support = true;
4887 }
4888
4889 /* Parse the wpa2ie to decode the MFP capablity */
4890 if (((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
4891 DOT11_MNG_RSN_ID)) != NULL) &&
4892 (wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) {
4893 WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap[0], rsn_cap[1]));
4894 /* Check for MFP cap in the RSN capability field */
4895 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
4896 if (sme->mfp)
4897 #endif
4898 {
4899 if (rsn_cap[0] & RSN_CAP_MFPR) {
4900 mfp = WL_MFP_REQUIRED;
4901 } else if (rsn_cap[0] & RSN_CAP_MFPC) {
4902 mfp = WL_MFP_CAPABLE;
4903 }
4904 }
4905 /*
4906 * eptr --> end/last byte addr of wpa2_ie
4907 * ptr --> to keep track of current/required byte addr
4908 */
4909 eptr = (const u8*)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN);
4910 /* pointing ptr to the next byte after rns_cap */
4911 ptr = (const u8*)rsn_cap + RSN_CAP_LEN;
4912 if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) {
4913 /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
4914 pmkid = (const wpa_pmkid_list_t*)ptr;
4915 count = pmkid->count.low | (pmkid->count.high << 8);
4916 /* ptr now to point to last byte addr of pmkid */
4917 ptr = (const u8*)pmkid + (count * WPA2_PMKID_LEN
4918 + WPA2_PMKID_COUNT_LEN);
4919 if ((eptr - ptr) >= WPA_SUITE_LEN) {
4920 /* group_mgmt_cs now to point to first byte addr of bip */
4921 group_mgmt_cs = ptr;
4922 }
4923 }
4924 }
4925
4926 WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n",
4927 mfp, wpa2_ie, fw_support));
4928
4929 if (fw_support == false) {
4930 if (mfp == WL_MFP_REQUIRED) {
4931 /* if mfp > 0, mfp capability set in wpa ie, but
4932 * FW indicated error for mfp. Propagate the error up.
4933 */
4934 WL_ERR(("mfp capability found in wpaie. But fw doesn't "
4935 "seem to support MFP\n"));
4936 err = -EINVAL;
4937 goto exit;
4938 } else {
4939 /* Firmware doesn't support mfp. But since connection request
4940 * is for non-mfp case, don't bother.
4941 */
4942 err = BCME_OK;
4943 goto exit;
4944 }
4945 } else if (mfp != current_mfp) {
4946 /* Some FW brances report error (-5) during MFP set if the BSS
4947 * is up (roam case). Typically in roaming cases, the MFP
4948 * configuration doesn't change. So in roam/reassoc cases, there is
4949 * no need to update the fw state. If we still hit corner cases
4950 * throwing (-5) error, we need to pull in RB:59117.
4951 */
4952 err = wldev_iovar_setint(dev, "mfp", mfp);
4953 if (unlikely(err)) {
4954 WL_ERR(("mfp (%d) set failed ret:%d \n", mfp, err));
4955 goto exit;
4956 }
4957 WL_DBG_MEM(("[%s] wl mfp 0x%x\n", dev->name, mfp));
4958 }
4959
4960 if (sec) {
4961 sec->fw_mfp = mfp;
4962 }
4963
4964 if (group_mgmt_cs && bcmp((const uint8 *)WPA2_OUI,
4965 group_mgmt_cs, (WPA_SUITE_LEN - 1)) == 0) {
4966 WL_DBG(("BIP is found\n"));
4967 err = wldev_iovar_setbuf(dev, "bip",
4968 group_mgmt_cs, WPA_SUITE_LEN, cfg->ioctl_buf,
4969 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
4970 /*
4971 * Dont return failure for unsupported cases
4972 * of bip iovar for backward compatibility
4973 */
4974 if (err != BCME_UNSUPPORTED && err < 0) {
4975 WL_ERR(("bip set error (%d)\n", err));
4976
4977 #ifdef CUSTOMER_HW6
4978 if (wl_customer6_legacy_chip_check(cfg,
4979 bcmcfg_to_prmry_ndev(cfg))) {
4980 /* Ignore bip error: Some older firmwares doesn't
4981 * support bip iovar/ return BCME_NOTUP while trying
4982 * to set bip from connect context. These firmares
4983 * include bip in RSNIE by default. So its okay to
4984 * ignore the error.
4985 */
4986 err = BCME_OK;
4987 goto exit;
4988 } else
4989 #endif /* CUSTOMER_HW6 */
4990
4991 {
4992 goto exit;
4993 }
4994 } else {
4995 WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n",
4996 dev->name, group_mgmt_cs[0], group_mgmt_cs[1],
4997 group_mgmt_cs[2]));
4998 }
4999 }
5000 exit:
5001 if (err) {
5002 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
5003 FW_LOGSET_MASK_ALL);
5004 }
5005
5006 return 0;
5007 }
5008 #endif /* MFP */
5009
5010 #ifdef WL_FILS
5011 bool
wl_is_fils_supported(struct net_device * ndev)5012 wl_is_fils_supported(struct net_device *ndev)
5013 {
5014 s32 err;
5015 u8 ioctl_buf[WLC_IOCTL_SMLEN] = {0};
5016 bcm_iov_buf_t *iov_buf = (bcm_iov_buf_t *)ioctl_buf;
5017
5018 iov_buf->version = WL_FILS_IOV_VERSION;
5019 err = wldev_iovar_getbuf(ndev, "fils", (uint8*)iov_buf, sizeof(bcm_iov_buf_t),
5020 iov_buf, WLC_IOCTL_SMLEN, NULL);
5021 if (err == BCME_UNSUPPORTED) {
5022 WL_DBG(("FILS NOT supported\n"));
5023 return false;
5024 }
5025
5026 WL_INFORM(("FILS supported\n"));
5027 return true;
5028 }
5029
5030 #define WL_NUM_OF_TLV_IN_SET_FILS_PARAMS 4u
5031 static s32
wl_set_fils_params(struct net_device * dev,struct cfg80211_connect_params * sme)5032 wl_set_fils_params(struct net_device *dev, struct cfg80211_connect_params *sme)
5033 {
5034 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5035 bcm_iov_buf_t *iov_buf = NULL;
5036 bcm_xtlvbuf_t tbuf;
5037 s32 err = BCME_OK;
5038 uint32 buf_size;
5039
5040 if ((sme->auth_type != NL80211_AUTHTYPE_FILS_SK) &&
5041 (sme->auth_type != NL80211_AUTHTYPE_FILS_SK_PFS) &&
5042 (sme->auth_type != NL80211_AUTHTYPE_FILS_PK)) {
5043 return BCME_OK;
5044 }
5045 if (sme->fils_erp_rrk_len > WL_MAX_FILS_KEY_LEN) {
5046 WL_ERR(("%s: FILS rRK exceed allowed size\n", __FUNCTION__));
5047 err = BCME_BADARG;
5048 goto exit;
5049 }
5050 /* Check incoming buffer length */
5051 buf_size = sme->fils_erp_username_len + sme->fils_erp_realm_len + sme->fils_erp_rrk_len +
5052 sizeof(sme->fils_erp_next_seq_num) +
5053 WL_NUM_OF_TLV_IN_SET_FILS_PARAMS * BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32) +
5054 sizeof(bcm_iov_buf_t) - 1u;
5055
5056 if (buf_size > WLC_IOCTL_SMLEN) {
5057 WL_ERR(("%s: FILS connect params arguments exceed allowed size\n", __FUNCTION__));
5058 err = BCME_BADARG;
5059 goto exit;
5060 }
5061 iov_buf = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
5062 if (!iov_buf) {
5063 WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, WLC_IOCTL_SMLEN));
5064 err = BCME_NOMEM;
5065 goto exit;
5066 }
5067 iov_buf->version = WL_FILS_IOV_VERSION;
5068 iov_buf->id = WL_FILS_CMD_ADD_CONNECT_PARAMS;
5069 /* check if this should be len w/o headers */
5070 err = bcm_xtlv_buf_init(&tbuf, (uint8*)&iov_buf->data[0],
5071 WLC_IOCTL_SMLEN - sizeof(bcm_iov_buf_t) + sizeof(uint16),
5072 BCM_XTLV_OPTION_ALIGN32);
5073 if (err != BCME_OK) {
5074 WL_ERR(("%s: xtlv_context initialization failed\n", __FUNCTION__));
5075 goto exit;
5076 }
5077 if (sme->fils_erp_username_len && sme->fils_erp_username != NULL) {
5078 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_USERNAME,
5079 sme->fils_erp_username, sme->fils_erp_username_len);
5080 if (err != BCME_OK) {
5081 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5082 goto exit;
5083 }
5084 }
5085 if (sme->fils_erp_realm_len && sme->fils_erp_realm != NULL) {
5086 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_REALM,
5087 sme->fils_erp_realm, sme->fils_erp_realm_len);
5088 if (err != BCME_OK) {
5089 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5090 goto exit;
5091 }
5092 }
5093 if (sme->fils_erp_rrk_len && sme->fils_erp_rrk != NULL) {
5094 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_RRK,
5095 sme->fils_erp_rrk, sme->fils_erp_rrk_len);
5096 if (err != BCME_OK) {
5097 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5098 goto exit;
5099 }
5100 }
5101 err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM,
5102 (u8 *)&sme->fils_erp_next_seq_num, sizeof(sme->fils_erp_next_seq_num));
5103 if (err != BCME_OK) {
5104 WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
5105 goto exit;
5106 }
5107 iov_buf->len = bcm_xtlv_buf_len(&tbuf);
5108 err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf->len + sizeof(bcm_iov_buf_t) -
5109 sizeof(uint16), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5110 if (unlikely(err)) {
5111 WL_ERR(("set fils params ioctl error (%d)\n", err));
5112 goto exit;
5113 }
5114
5115 exit:
5116 if (err != BCME_OK) {
5117 WL_ERR(("set FILS params error %d\n", err));
5118 }
5119 else {
5120 WL_DBG_MEM(("FILS parameters succesfully applied\n"));
5121 }
5122 if (iov_buf) {
5123 MFREE(cfg->osh, iov_buf, WLC_IOCTL_SMLEN);
5124 }
5125 return err;
5126 }
5127
5128 #if !defined(WL_FILS_ROAM_OFFLD) && defined(WL_FILS)
5129 static s32
wl_get_bcn_timeout(struct net_device * dev,u32 * bcn_timeout)5130 wl_get_bcn_timeout(struct net_device *dev, u32 *bcn_timeout)
5131 {
5132 s32 err = 0;
5133
5134 err = wldev_iovar_getint(dev, "bcn_timeout", bcn_timeout);
5135 if (unlikely(err)) {
5136 WL_ERR(("could not get bcn_timeout (%d)\n", err));
5137 }
5138 return err;
5139 }
5140
5141 #define WL_ROAM_ENABLE 0
5142 #define WL_ROAM_DISABLE 1
5143 /* Beacon Timeout beacon loss in case FILS roaming offload is not supported by fw */
5144 #define WL_BCN_TIMEOUT 3
5145
5146 static s32
wl_fils_toggle_roaming(struct net_device * dev,u32 auth_type)5147 wl_fils_toggle_roaming(struct net_device *dev, u32 auth_type)
5148 {
5149 s32 err = 0;
5150 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5151
5152 if (WPA2_AUTH_IS_FILS(auth_type) && !cfg->fils_info.fils_roam_disabled) {
5153 err = wl_get_bcn_timeout(dev, &cfg->fils_info.fils_bcn_timeout_cache);
5154 if (unlikely(err)) {
5155 return err;
5156 }
5157 wl_dongle_roam(dev, WL_ROAM_DISABLE, WL_BCN_TIMEOUT);
5158 cfg->fils_info.fils_roam_disabled = true;
5159 WL_DBG_MEM(("fw roam disabled for FILS akm\n"));
5160 } else if (cfg->fils_info.fils_roam_disabled) {
5161 /* Enable roaming back for other auth types */
5162 wl_dongle_roam(dev, WL_ROAM_ENABLE, cfg->fils_info.fils_bcn_timeout_cache);
5163 cfg->fils_info.fils_roam_disabled = false;
5164 WL_DBG_MEM(("fw roam enabled\n"));
5165 }
5166 return err;
5167 }
5168 #endif /* !WL_FILS_ROAM_OFFLD && WL_FILS */
5169 #endif /* WL_FILS */
5170
5171 static s32
wl_set_key_mgmt(struct net_device * dev,struct cfg80211_connect_params * sme)5172 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
5173 {
5174 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5175 struct wl_security *sec;
5176 s32 val = 0;
5177 s32 err = 0;
5178 s32 bssidx;
5179
5180 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5181 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5182 return BCME_ERROR;
5183 }
5184
5185 if (sme->crypto.n_akm_suites) {
5186 err = wldev_iovar_getint(dev, "wpa_auth", &val);
5187 if (unlikely(err)) {
5188 WL_ERR(("could not get wpa_auth (%d)\n", err));
5189 return err;
5190 }
5191 if (val & (WPA_AUTH_PSK |
5192 WPA_AUTH_UNSPECIFIED)) {
5193 switch (sme->crypto.akm_suites[0]) {
5194 case WLAN_AKM_SUITE_8021X:
5195 val = WPA_AUTH_UNSPECIFIED;
5196 break;
5197 case WLAN_AKM_SUITE_PSK:
5198 val = WPA_AUTH_PSK;
5199 break;
5200 default:
5201 WL_ERR(("invalid akm suite (0x%x)\n",
5202 sme->crypto.akm_suites[0]));
5203 return -EINVAL;
5204 }
5205 } else if (val & (WPA2_AUTH_PSK |
5206 WPA2_AUTH_UNSPECIFIED)) {
5207 switch (sme->crypto.akm_suites[0]) {
5208 #ifdef MFP
5209
5210 #ifdef CUSTOMER_HW6
5211 case WL_AKM_SUITE_SHA256_1X:
5212 if (wl_customer6_legacy_chip_check(cfg, dev)) {
5213 val = WPA2_AUTH_UNSPECIFIED;
5214 } else {
5215 val = WPA2_AUTH_1X_SHA256;
5216 }
5217 break;
5218 case WL_AKM_SUITE_SHA256_PSK:
5219 if (wl_customer6_legacy_chip_check(cfg, dev)) {
5220 val = WPA2_AUTH_PSK;
5221 } else {
5222 val = WPA2_AUTH_PSK_SHA256;
5223 }
5224 break;
5225 #endif /* CUSTOMER_HW6 */
5226
5227 #ifndef CUSTOMER_HW6
5228 case WL_AKM_SUITE_SHA256_1X:
5229 val = WPA2_AUTH_1X_SHA256;
5230 break;
5231 case WL_AKM_SUITE_SHA256_PSK:
5232 val = WPA2_AUTH_PSK_SHA256;
5233 break;
5234 #endif /* CUSTOMER_HW6 */
5235 #endif /* MFP */
5236 case WLAN_AKM_SUITE_8021X:
5237 case WLAN_AKM_SUITE_PSK:
5238 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
5239 case WLAN_AKM_SUITE_FT_8021X:
5240 #endif
5241 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
5242 case WLAN_AKM_SUITE_FT_PSK:
5243 #endif
5244 case WLAN_AKM_SUITE_FILS_SHA256:
5245 case WLAN_AKM_SUITE_FILS_SHA384:
5246 case WLAN_AKM_SUITE_8021X_SUITE_B:
5247 case WLAN_AKM_SUITE_8021X_SUITE_B_192:
5248 #ifdef WL_OWE
5249 case WLAN_AKM_SUITE_OWE:
5250 #endif /* WL_OWE */
5251 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
5252 case WLAN_AKM_SUITE_SAE:
5253 #endif /* WL_SAE || WL_CLIENT_SAE */
5254 #ifdef WL_SAE_FT
5255 case WLAN_AKM_SUITE_FT_OVER_SAE:
5256 #endif /* WL_SAE_FT */
5257 case WLAN_AKM_SUITE_DPP:
5258 case WLAN_AKM_SUITE_FT_8021X_SHA384:
5259 val = wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[0]);
5260 break;
5261 case WLAN_AKM_SUITE_FT_FILS_SHA256:
5262 val = WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT;
5263 break;
5264 case WLAN_AKM_SUITE_FT_FILS_SHA384:
5265 val = WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT;
5266 break;
5267 default:
5268 WL_ERR(("invalid akm suite (0x%x)\n",
5269 sme->crypto.akm_suites[0]));
5270 return -EINVAL;
5271 }
5272 }
5273
5274 #ifdef BCMWAPI_WPI
5275 else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) {
5276 switch (sme->crypto.akm_suites[0]) {
5277 case WLAN_AKM_SUITE_WAPI_CERT:
5278 val = WAPI_AUTH_UNSPECIFIED;
5279 break;
5280 case WLAN_AKM_SUITE_WAPI_PSK:
5281 val = WAPI_AUTH_PSK;
5282 break;
5283 default:
5284 WL_ERR(("invalid akm suite (0x%x)\n",
5285 sme->crypto.akm_suites[0]));
5286 return -EINVAL;
5287 }
5288 }
5289 #endif
5290
5291 #ifdef WL_FILS
5292 #if !defined(WL_FILS_ROAM_OFFLD)
5293 err = wl_fils_toggle_roaming(dev, val);
5294 if (unlikely(err)) {
5295 return err;
5296 }
5297 #endif /* !WL_FILS_ROAM_OFFLD */
5298 #endif /* !WL_FILS */
5299
5300 #ifdef MFP
5301 if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) {
5302 WL_ERR(("MFP set failed err:%d\n", err));
5303 return -EINVAL;
5304 }
5305 #endif /* MFP */
5306
5307 WL_DBG_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val));
5308 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
5309 if (unlikely(err)) {
5310 WL_ERR(("could not set wpa_auth (0x%x)\n", err));
5311 return err;
5312 }
5313 }
5314 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5315 sec->wpa_auth = sme->crypto.akm_suites[0];
5316 sec->fw_wpa_auth = val;
5317
5318 return err;
5319 }
5320
5321 static s32
wl_set_set_sharedkey(struct net_device * dev,struct cfg80211_connect_params * sme)5322 wl_set_set_sharedkey(struct net_device *dev,
5323 struct cfg80211_connect_params *sme)
5324 {
5325 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5326 struct wl_security *sec;
5327 struct wl_wsec_key key;
5328 s32 val;
5329 s32 err = 0;
5330 s32 bssidx;
5331
5332 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5333 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5334 return BCME_ERROR;
5335 }
5336
5337 WL_DBG(("key len (%d)\n", sme->key_len));
5338 if (sme->key_len) {
5339 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
5340 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
5341 sec->wpa_versions, sec->cipher_pairwise));
5342 if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
5343 NL80211_WPA_VERSION_2)) &&
5344
5345 #ifdef BCMWAPI_WPI
5346 !is_wapi(sec->cipher_pairwise) &&
5347 #endif
5348
5349 (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
5350 WLAN_CIPHER_SUITE_WEP104)))
5351 {
5352 bzero(&key, sizeof(key));
5353 key.len = (u32) sme->key_len;
5354 key.index = (u32) sme->key_idx;
5355 if (unlikely(key.len > sizeof(key.data))) {
5356 WL_ERR(("Too long key length (%u)\n", key.len));
5357 return -EINVAL;
5358 }
5359 memcpy(key.data, sme->key, key.len);
5360 key.flags = WL_PRIMARY_KEY;
5361 if ((sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP40) ||
5362 (sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP104)) {
5363 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(sec->cipher_pairwise);
5364 } else {
5365 WL_ERR(("Invalid algorithm (%d)\n",
5366 sme->crypto.ciphers_pairwise[0]));
5367 return -EINVAL;
5368 }
5369 /* Set the new key/index */
5370 WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
5371 key.len, key.index, key.algo));
5372 WL_DBG(("key \"%s\"\n", key.data));
5373 swap_key_from_BE(&key);
5374 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
5375 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5376 if (unlikely(err)) {
5377 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
5378 return err;
5379 }
5380 WL_INFORM_MEM(("key applied to fw\n"));
5381 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
5382 WL_DBG(("set auth_type to shared key\n"));
5383 val = WL_AUTH_SHARED_KEY; /* shared key */
5384 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
5385 if (unlikely(err)) {
5386 WL_ERR(("set auth failed (%d)\n", err));
5387 return err;
5388 }
5389 }
5390 }
5391 }
5392 return err;
5393 }
5394
5395 #if defined (CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
wl_get_chan_isvht80(struct net_device * net,dhd_pub_t * dhd)5396 static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
5397 {
5398 u32 chanspec = 0;
5399 bool isvht80 = 0;
5400
5401 if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK)
5402 chanspec = wl_chspec_driver_to_host(chanspec);
5403
5404 isvht80 = chanspec & WL_CHANSPEC_BW_80;
5405 WL_DBG(("wl_get_chan_isvht80: chanspec(%x:%d)\n", chanspec, isvht80));
5406
5407 return isvht80;
5408 }
5409 #endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
5410
wl_cfg80211_cleanup_mismatch_status(struct net_device * dev,struct bcm_cfg80211 * cfg,bool disassociate)5411 int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80211 *cfg,
5412 bool disassociate)
5413 {
5414 scb_val_t scbval;
5415 int err = TRUE;
5416 int wait_cnt;
5417
5418 if (disassociate) {
5419 #ifdef BCMDONGLEHOST
5420 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
5421 BCM_REFERENCE(dhdp);
5422 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
5423 dhd_net2idx(dhdp->info, dev), DOT11_RC_DISASSOC_LEAVING);
5424 #endif /* BCMDONGLEHOST */
5425 WL_ERR(("Disassociate previous connection!\n"));
5426 wl_set_drv_status(cfg, DISCONNECTING, dev);
5427 scbval.val = DOT11_RC_DISASSOC_LEAVING;
5428 scbval.val = htod32(scbval.val);
5429
5430 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
5431 sizeof(scb_val_t));
5432 if (unlikely(err)) {
5433 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5434 WL_ERR(("error (%d)\n", err));
5435 return err;
5436 }
5437 wait_cnt = 500/10;
5438 } else {
5439 wait_cnt = 200/10;
5440 WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
5441 if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
5442 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5443 }
5444 }
5445
5446 while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
5447 WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
5448 wait_cnt));
5449 wait_cnt--;
5450 OSL_SLEEP(10);
5451 }
5452
5453 if (wait_cnt == 0) {
5454 WL_ERR(("DISCONNECING clean up failed!\n"));
5455 /* Clear DISCONNECTING driver status as we have made sufficient attempts
5456 * for driver clean up.
5457 */
5458 wl_clr_drv_status(cfg, DISCONNECTING, dev);
5459 wl_clr_drv_status(cfg, CONNECTED, dev);
5460 return BCME_NOTREADY;
5461 }
5462 return BCME_OK;
5463 }
5464
5465 #ifdef WL_FILS
5466 static int
wl_fils_add_hlp_container(struct bcm_cfg80211 * cfg,struct net_device * dev,const uint8 * ie_buf,uint16 ie_len)5467 wl_fils_add_hlp_container(struct bcm_cfg80211 *cfg, struct net_device *dev,
5468 const uint8* ie_buf, uint16 ie_len)
5469 {
5470 const bcm_tlv_ext_t *hlp_ie;
5471
5472 if ((hlp_ie = (const bcm_tlv_ext_t*)bcm_parse_tlvs_dot11((const uint8 *)ie_buf, ie_len,
5473 FILS_HLP_CONTAINER_EXT_ID, TRUE))) {
5474 u16 hlp_len = hlp_ie->len;
5475 u16 left_len = (ie_len - ((const uint8*)hlp_ie - ie_buf));
5476 bcm_iov_buf_t *iov_buf = 0;
5477 uint8* pxtlv;
5478 int err;
5479 size_t iov_buf_len;
5480 bcm_tlv_dot11_frag_tot_len(ie_buf, ie_len, FILS_HLP_CONTAINER_EXT_ID,
5481 TRUE, (uint*)&hlp_len);
5482
5483 hlp_len += BCM_TLV_EXT_HDR_SIZE;
5484
5485 if ((hlp_len > DOT11_MAX_MPDU_BODY_LEN) || (hlp_len > left_len)) {
5486 WL_ERR(("bad HLP length %d\n", hlp_len));
5487 return EFAULT;
5488 }
5489 iov_buf_len = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) - 1 + hlp_len;
5490 iov_buf = MALLOCZ(cfg->osh, iov_buf_len);
5491 if (iov_buf == NULL) {
5492 WL_ERR(("failed to allocated iov_buf\n"));
5493 return ENOMEM;
5494 }
5495
5496 prhex("HLP, HLP", (const uchar *)hlp_ie, hlp_len);
5497
5498 pxtlv = (uint8 *)&iov_buf->data[0];
5499 ((bcm_xtlv_t*)pxtlv)->id = WL_FILS_XTLV_HLP_IE;
5500 ((bcm_xtlv_t*)pxtlv)->len = hlp_len;
5501
5502 memcpy(((bcm_xtlv_t*)pxtlv)->data, hlp_ie, ((bcm_xtlv_t*)pxtlv)->len);
5503
5504 iov_buf->version = WL_FILS_IOV_VERSION;
5505 iov_buf->id = WL_FILS_CMD_ADD_HLP_IE;
5506 iov_buf->len = ((sizeof(bcm_xtlv_t)-1) + ((bcm_xtlv_t*)pxtlv)->len);
5507
5508 err = wldev_iovar_setbuf(dev, "fils", iov_buf,
5509 sizeof(bcm_iov_buf_t) + iov_buf->len,
5510 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
5511 if (unlikely(err)) {
5512 WL_ERR(("fils wldev_iovar_setbuf error (%d)\n", err));
5513 }
5514 else {
5515 WL_DBG_MEM(("FILS HLP Packet succesfully updated\n"));
5516 }
5517 MFREE(cfg->osh, iov_buf, iov_buf_len);
5518 }
5519 return BCME_OK;
5520 }
5521 #endif /* WL_FILS */
5522
5523 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
5524 #define UPDATE_ASSOC_IES BIT(0)
5525 #ifndef UPDATE_FILS_ERP_INFO
5526 #define UPDATE_FILS_ERP_INFO BIT(1)
5527 #define UPDATE_AUTH_TYPE BIT(2)
5528 #endif
5529
5530 static int
wl_cfg80211_update_connect_params(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme,u32 changed)5531 wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
5532 struct cfg80211_connect_params *sme, u32 changed)
5533 {
5534 s32 err = BCME_OK;
5535 #if defined(WL_FILS)
5536 if (changed & UPDATE_FILS_ERP_INFO) {
5537 err = wl_set_fils_params(dev, sme);
5538 if (unlikely(err)) {
5539 WL_ERR(("Invalid FILS params\n"));
5540 goto exit;
5541 }
5542 if (!(changed & UPDATE_AUTH_TYPE)) {
5543 WL_DBG(("Warning: FILS ERP params are set,"
5544 "but authentication type - not\n"));
5545 }
5546 }
5547 if (changed & UPDATE_AUTH_TYPE) {
5548 err = wl_set_auth_type(dev, sme);
5549 if (unlikely(err)) {
5550 WL_ERR(("Invalid auth type\n"));
5551 goto exit;
5552 }
5553 }
5554 #endif /* WL_FILS */
5555 if (changed & UPDATE_ASSOC_IES) {
5556 WL_DBG(("update assoc ies\n"));
5557 err = wl_cfg80211_set_mgmt_vndr_ies(wl_get_cfg(dev), ndev_to_cfgdev(dev),
5558 wl_get_bssidx_by_wdev(wl_get_cfg(dev), dev->ieee80211_ptr),
5559 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
5560 if (err) {
5561 WL_ERR(("error updating vndr ies\n"));
5562 goto exit;
5563 }
5564 }
5565 exit:
5566 return err;
5567 }
5568 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
5569
5570 #if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
5571 static s32
wl_config_roam_env_detection(struct bcm_cfg80211 * cfg,struct net_device * dev)5572 wl_config_roam_env_detection(struct bcm_cfg80211 *cfg, struct net_device *dev)
5573 {
5574 #if defined(BCMDONGLEHOST)
5575 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
5576 #endif /* BCMDONGLEHOST */
5577 s32 roam_trigger[2] = {0, 0};
5578 s32 err = BCME_OK;
5579
5580 if (dhdp->roam_env_detection && (dev == bcmcfg_to_prmry_ndev(cfg))) {
5581 bool is_roamtrig_reset = TRUE;
5582 bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection",
5583 AP_ENV_DETECT_NOT_USED) == BCME_OK);
5584 #ifdef SKIP_ROAM_TRIGGER_RESET
5585 roam_trigger[1] = WLC_BAND_2G;
5586 is_roamtrig_reset =
5587 (wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
5588 sizeof(roam_trigger)) == BCME_OK) &&
5589 (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER-10);
5590 #endif /* SKIP_ROAM_TRIGGER_RESET */
5591 if (is_roamtrig_reset && is_roam_env_ok) {
5592 roam_trigger[0] = WL_AUTO_ROAM_TRIGGER;
5593 roam_trigger[1] = WLC_BAND_ALL;
5594 err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
5595 sizeof(roam_trigger));
5596 if (unlikely(err)) {
5597 WL_ERR((" failed to restore roam_trigger for auto env"
5598 " detection. err:%d\n", err));
5599 }
5600 }
5601 }
5602 return err;
5603 }
5604 #endif /* ROAM_ENABLE && ROAMENV_DETECTION */
5605
5606 s32
wl_do_preassoc_ops(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme)5607 wl_do_preassoc_ops(struct bcm_cfg80211 *cfg,
5608 struct net_device *dev, struct cfg80211_connect_params *sme)
5609 {
5610 #if defined(BCMDONGLEHOST)
5611 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
5612 #endif /* BCMDONGLEHOST */
5613
5614 #ifdef BCMDONGLEHOST
5615 BCM_REFERENCE(dhdp);
5616 DHD_STATLOG_CTRL(dhdp, ST(ASSOC_START), dhd_net2idx(dhdp->info, dev), 0);
5617 #endif /* BCMDONGLEHOST */
5618
5619 #ifdef DHDTCPSYNC_FLOOD_BLK
5620 dhd_reset_tcpsync_info_by_dev(dev);
5621 #endif /* DHDTCPSYNC_FLOOD_BLK */
5622
5623 if (wl_get_drv_status(cfg, SCANNING, dev)) {
5624 wl_cfgscan_cancel_scan(cfg);
5625 }
5626
5627 #ifdef WL_SCHED_SCAN
5628 /* Locks are taken in wl_cfg80211_sched_scan_stop()
5629 * A start scan occuring during connect is unlikely
5630 */
5631 if (cfg->sched_scan_req) {
5632 struct wireless_dev *wdev = dev->ieee80211_ptr;
5633 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
5634 wl_cfg80211_sched_scan_stop(wdev->wiphy, bcmcfg_to_prmry_ndev(cfg),
5635 cfg->sched_scan_req->reqid);
5636 #else
5637 wl_cfg80211_sched_scan_stop(wdev->wiphy, bcmcfg_to_prmry_ndev(cfg));
5638 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) */
5639 }
5640 #endif /* WL_SCHED_SCAN */
5641 #ifdef WL_CFG80211_GON_COLLISION
5642 /* init block gon req count */
5643 cfg->block_gon_req_tx_count = 0;
5644 cfg->block_gon_req_rx_count = 0;
5645 #endif /* WL_CFG80211_GON_COLLISION */
5646
5647 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
5648 maxrxpktglom = 0;
5649 #endif
5650
5651 #if defined (ROAM_ENABLE) && defined (ROAM_AP_ENV_DETECTION)
5652 if (wl_config_roam_env_detection(cfg, dev) != BCME_OK) {
5653 return BCME_ERROR;
5654 }
5655 #endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
5656
5657 #ifdef WLTDLS
5658 /* disable TDLS if number of connected interfaces is >= 1 */
5659 wl_cfg80211_tdls_config(cfg, TDLS_STATE_CONNECT, false);
5660 #endif /* WLTDLS */
5661
5662 #ifdef SUPPORT_AP_BWCTRL
5663 if (dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
5664 wl_restore_ap_bw(cfg);
5665 }
5666 #endif /* SUPPORT_AP_BWCTRL */
5667 #if defined(ROAMEXP_SUPPORT)
5668 /* Clear Blacklist bssid and Whitelist ssid list before join issue
5669 * This is temporary fix since currently firmware roaming is not
5670 * disabled by android framework before SSID join from framework
5671 */
5672 /* Flush blacklist bssid content */
5673 dhd_dev_set_blacklist_bssid(dev, NULL, 0, true);
5674 /* Flush whitelist ssid content */
5675 dhd_dev_set_whitelist_ssid(dev, NULL, 0, true);
5676 #endif /* ROAMEXP_SUPPORT */
5677
5678 WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
5679 if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
5680 prhex(NULL, sme->ie, sme->ie_len);
5681 }
5682 /* Connection attempted via linux-wireless */
5683 wl_set_drv_status(cfg, CFG80211_CONNECT, dev);
5684 return BCME_OK;
5685 }
5686
5687 static s32
wl_config_assoc_security(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme)5688 wl_config_assoc_security(struct bcm_cfg80211 *cfg,
5689 struct net_device *dev, struct cfg80211_connect_params *sme)
5690 {
5691 s32 err = BCME_OK;
5692
5693 err = wl_set_wpa_version(dev, sme);
5694 if (unlikely(err)) {
5695 WL_ERR(("Invalid wpa_version\n"));
5696 goto exit;
5697 }
5698
5699 err = wl_set_auth_type(dev, sme);
5700 if (unlikely(err)) {
5701 WL_ERR(("Invalid auth type\n"));
5702 goto exit;
5703 }
5704
5705 #ifdef WL_FILS
5706 if (sme->ie && sme->ie_len) {
5707 err = wl_fils_add_hlp_container(cfg, dev, sme->ie, sme->ie_len);
5708 if (unlikely(err)) {
5709 WL_ERR(("FILS sending HLP failed\n"));
5710 goto exit;
5711 }
5712 }
5713 #endif /* WL_FILS */
5714
5715 err = wl_set_set_cipher(dev, sme);
5716 if (unlikely(err)) {
5717 WL_ERR(("Invalid ciper\n"));
5718 goto exit;
5719 }
5720
5721 err = wl_set_key_mgmt(dev, sme);
5722 if (unlikely(err)) {
5723 WL_ERR(("Invalid key mgmt\n"));
5724 goto exit;
5725 }
5726
5727 err = wl_set_set_sharedkey(dev, sme);
5728 if (unlikely(err)) {
5729 WL_ERR(("Invalid shared key\n"));
5730 goto exit;
5731 }
5732
5733 #ifdef WL_FILS
5734 err = wl_set_fils_params(dev, sme);
5735 if (unlikely(err)) {
5736 WL_ERR(("Invalid FILS params\n"));
5737 goto exit;
5738 }
5739 #endif /* WL_FILS */
5740
5741 exit:
5742 return err;
5743 }
5744
5745 static s32
wl_config_assoc_ies(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme,wlcfg_assoc_info_t * info)5746 wl_config_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *dev,
5747 struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *info)
5748 {
5749 const wpa_ie_fixed_t *wpa_ie;
5750 const bcm_tlv_t *wpa2_ie;
5751 const u8* wpaie = 0;
5752 u32 wpaie_len;
5753 s32 err;
5754 s32 bssidx = info->bssidx;
5755
5756 /* configure all vendor and extended vendor IEs */
5757 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
5758 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
5759
5760 /* Find the RSNXE_IE and plumb */
5761 if ((err = wl_cfg80211_config_rsnxe_ie(cfg, dev,
5762 (const u8*)sme->ie, sme->ie_len)) < 0) {
5763 WL_ERR(("Failed to configure rsnxe ie: %d\n", err));
5764 return err;
5765 }
5766
5767 /* find the RSN_IE */
5768 if ((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
5769 DOT11_MNG_RSN_ID)) != NULL) {
5770 WL_DBG((" RSN IE is found\n"));
5771 }
5772
5773 /* find the WPA_IE */
5774 if ((wpa_ie = wl_cfgp2p_find_wpaie(sme->ie,
5775 sme->ie_len)) != NULL) {
5776 WL_DBG((" WPA IE is found\n"));
5777 }
5778
5779 if (wpa_ie != NULL || wpa2_ie != NULL) {
5780 wpaie = (wpa_ie != NULL) ? (const u8 *)wpa_ie : (const u8 *)wpa2_ie;
5781 wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
5782 wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
5783 } else {
5784 wpaie = NULL;
5785 wpaie_len = 0;
5786 }
5787
5788 err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
5789 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
5790 if (unlikely(err)) {
5791 WL_ERR(("wpaie set error (%d)\n", err));
5792 }
5793
5794 return err;
5795 }
5796
5797 s32
wl_cfg80211_config_rsnxe_ie(struct bcm_cfg80211 * cfg,struct net_device * dev,const u8 * parse,u32 len)5798 wl_cfg80211_config_rsnxe_ie(struct bcm_cfg80211 *cfg, struct net_device *dev,
5799 const u8 *parse, u32 len)
5800 {
5801 bcm_tlv_t *ie = NULL;
5802 s32 err = 0;
5803 u8 ie_len = 0;
5804 char smbuf[WLC_IOCTL_SMLEN];
5805
5806 while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_RSNXE_ID))) {
5807 WL_DBG(("Found RSNXE ie\n"));
5808 break;
5809 }
5810
5811 ie_len = (ie != NULL) ? (ie->len + BCM_TLV_HDR_SIZE): 0;
5812
5813 err = wldev_iovar_setbuf(dev, "rsnxe", ie, ie_len,
5814 smbuf, sizeof(smbuf), NULL);
5815 if (!err) {
5816 WL_DBG(("Configured RSNXE IE\n"));
5817 } else if (err == BCME_UNSUPPORTED) {
5818 WL_DBG(("FW does not support rsnxe iovar\n"));
5819 err = BCME_OK;
5820 } else {
5821 WL_ERR(("rsnxe set error (%d)\n", err));
5822 }
5823 return err;
5824 }
5825
5826 static s32
wl_fillup_assoc_params_v1(struct bcm_cfg80211 * cfg,struct net_device * dev,void * params,u32 buf_len,wlcfg_assoc_info_t * info)5827 wl_fillup_assoc_params_v1(struct bcm_cfg80211 *cfg, struct net_device *dev,
5828 void *params, u32 buf_len, wlcfg_assoc_info_t *info)
5829 {
5830 chanspec_t *chanspecs = info->chanspecs;
5831 u32 chan_cnt = info->chan_cnt;
5832 u32 join_scan_active_time = 0;
5833 wl_extjoin_params_v1_t *ext_join_params = (wl_extjoin_params_v1_t *)params;
5834
5835 if (buf_len < (sizeof(ext_join_params->ssid.SSID) +
5836 (sizeof(chanspec_t) * chan_cnt))) {
5837 WL_ERR(("buf too short\n"));
5838 return -EINVAL;
5839 }
5840
5841 if (info->bssid_hint) {
5842 /* Set bssid hint flag */
5843 WL_DBG_MEM(("ASSOC_HINT_BSSID_PRESENT. channels:%d\n", chan_cnt));
5844 ext_join_params->assoc.flags |= ASSOC_HINT_BSSID_PRESENT;
5845 }
5846
5847 /* ssid length check is already done above */
5848 if (memcpy_s(ext_join_params->ssid.SSID, sizeof(ext_join_params->ssid.SSID),
5849 info->ssid, info->ssid_len) != BCME_OK) {
5850 WL_ERR(("ssid cpy failed info_len:%d\n", info->ssid_len));
5851 return -EINVAL;
5852 }
5853
5854 ext_join_params->ssid.SSID_len = info->ssid_len;
5855 wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
5856 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
5857 WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
5858 ext_join_params->ssid.SSID_len));
5859 }
5860 ext_join_params->ssid.SSID_len = htod32(info->ssid_len);
5861
5862 /* Use increased dwell for targeted join case to take care of noisy env */
5863 join_scan_active_time = info->targeted_join ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS :
5864 WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS;
5865 ext_join_params->scan.active_time = chan_cnt ? join_scan_active_time : -1;
5866 ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
5867 /* Set up join scan parameters */
5868 ext_join_params->scan.scan_type = -1;
5869 /* WAR to sync with presence period of VSDB GO.
5870 * send probe request more frequently
5871 * probe request will be stopped when it gets probe response from target AP/GO.
5872 */
5873 ext_join_params->scan.nprobes = chan_cnt ?
5874 (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
5875 ext_join_params->scan.home_time = -1;
5876
5877 (void)memcpy_s(&ext_join_params->assoc.bssid, ETH_ALEN, info->bssid, ETH_ALEN);
5878
5879 ext_join_params->assoc.chanspec_num = chan_cnt;
5880 /* source and target lens are same */
5881 (void)memcpy_s(ext_join_params->assoc.chanspec_list, (sizeof(chanspec_t) * chan_cnt),
5882 chanspecs, sizeof(chanspec_t) * chan_cnt);
5883
5884 ext_join_params->assoc.chanspec_num = htod32(chan_cnt);
5885 return BCME_OK;
5886 }
5887
5888 static s32
wl_fillup_assoc_params_v0(struct bcm_cfg80211 * cfg,struct net_device * dev,void * params,u32 buf_len,wlcfg_assoc_info_t * info)5889 wl_fillup_assoc_params_v0(struct bcm_cfg80211 *cfg, struct net_device *dev,
5890 void *params, u32 buf_len, wlcfg_assoc_info_t *info)
5891 {
5892 chanspec_t *chanspecs = info->chanspecs;
5893 u32 chan_cnt = info->chan_cnt;
5894 u32 join_scan_active_time = 0;
5895 wl_extjoin_params_t *ext_join_params = (wl_extjoin_params_t *)params;
5896
5897 if (buf_len < (sizeof(ext_join_params->ssid.SSID) +
5898 (sizeof(chanspec_t) * chan_cnt))) {
5899 WL_ERR(("buf too short\n"));
5900 return -EINVAL;
5901 }
5902
5903 /* ssid length check is already done above */
5904 if (memcpy_s(ext_join_params->ssid.SSID, sizeof(ext_join_params->ssid.SSID),
5905 info->ssid, info->ssid_len) != BCME_OK) {
5906 WL_ERR(("ssid cpy failed info_len:%d\n", info->ssid_len));
5907 return -EINVAL;
5908 }
5909
5910 ext_join_params->ssid.SSID_len = info->ssid_len;
5911 wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
5912 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
5913 WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
5914 ext_join_params->ssid.SSID_len));
5915 }
5916 ext_join_params->ssid.SSID_len = htod32(info->ssid_len);
5917
5918 /* Use increased dwell for targeted join case to take care of noisy env */
5919 join_scan_active_time = info->targeted_join ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS :
5920 WL_BCAST_SCAN_JOIN_ACTIVE_DWELL_TIME_MS;
5921 ext_join_params->scan.active_time = chan_cnt ? join_scan_active_time : -1;
5922 ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
5923 /* Set up join scan parameters */
5924 ext_join_params->scan.scan_type = -1;
5925 /* WAR to sync with presence period of VSDB GO.
5926 * send probe request more frequently
5927 * probe request will be stopped when it gets probe response from target AP/GO.
5928 */
5929 ext_join_params->scan.nprobes = chan_cnt ?
5930 (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
5931 ext_join_params->scan.home_time = -1;
5932
5933 (void)memcpy_s(&ext_join_params->assoc.bssid, ETH_ALEN, info->bssid, ETH_ALEN);
5934
5935 ext_join_params->assoc.chanspec_num = chan_cnt;
5936 /* source and target lens are same */
5937 (void)memcpy_s(ext_join_params->assoc.chanspec_list, (sizeof(chanspec_t) * chan_cnt),
5938 chanspecs, sizeof(chanspec_t) * chan_cnt);
5939
5940 ext_join_params->assoc.chanspec_num = htod32(chan_cnt);
5941 return BCME_OK;
5942 }
5943
5944 static s32
wl_config_assoc_params(struct bcm_cfg80211 * cfg,struct net_device * dev,void * params,u32 buf_len,wlcfg_assoc_info_t * info)5945 wl_config_assoc_params(struct bcm_cfg80211 *cfg, struct net_device *dev,
5946 void *params, u32 buf_len, wlcfg_assoc_info_t *info)
5947 {
5948 s32 ret;
5949
5950 if (!cfg->join_iovar_ver) {
5951 ret = wl_fillup_assoc_params_v0(cfg, dev, params, buf_len, info);
5952 } else {
5953 ret = wl_fillup_assoc_params_v1(cfg, dev, params, buf_len, info);
5954 }
5955 return ret;
5956 }
5957
5958 static s32
wl_handle_assoc_hints(struct bcm_cfg80211 * cfg,struct net_device * dev,struct cfg80211_connect_params * sme,wlcfg_assoc_info_t * info)5959 wl_handle_assoc_hints(struct bcm_cfg80211 *cfg, struct net_device *dev,
5960 struct cfg80211_connect_params *sme, wlcfg_assoc_info_t *info)
5961 {
5962 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
5963 bool skip_hints = false;
5964 #endif /* KERNEL >= 3.15 */
5965 chanspec_t chspec;
5966
5967 if (!sme || !info) {
5968 WL_ERR(("wrong args\n"));
5969 return -EINVAL;
5970 }
5971
5972 if (unlikely(!sme->ssid) || (sme->ssid_len > DOT11_MAX_SSID_LEN)) {
5973 WL_ERR(("Invalid ssid %p. len:%zu\n", sme->ssid, sme->ssid_len));
5974 return -EINVAL;
5975 }
5976
5977 /* Copy SSID detail */
5978 info->ssid_len = sme->ssid_len;
5979 if (memcpy_s(info->ssid, sizeof(info->ssid),
5980 sme->ssid, info->ssid_len) != BCME_OK) {
5981 WL_ERR(("ssid cpy failed\n"));
5982 return -EINVAL;
5983 }
5984
5985 /* Handle incoming BSSID and Channel info */
5986 if (sme->bssid && !ETHER_ISBCAST(sme->bssid)) {
5987 /* Use user space requested BSSID and channel */
5988 info->targeted_join = true;
5989 (void)memcpy_s(info->bssid, ETH_ALEN, sme->bssid, ETH_ALEN);
5990 if (sme->channel && ((chspec =
5991 wl_freq_to_chanspec(sme->channel->center_freq)) != INVCHANSPEC)) {
5992 info->chan_cnt = 1;
5993 info->chanspecs[0] = chspec;
5994 /* Skip p2p connection on 6G */
5995 #ifdef WL_P2P_6G
5996 if (!(cfg->p2p_6g_enabled)) {
5997 #endif /* WL_P2P_6G */
5998 if (IS_P2P_GC(dev->ieee80211_ptr) && (CHSPEC_IS6G(chspec))) {
5999 WL_ERR(("P2P connection not allowed on 6G\n"));
6000 return -ENOTSUPP;
6001 }
6002 #ifdef WL_P2P_6G
6003 }
6004 #endif /* WL_P2P_6G */
6005 }
6006 }
6007 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6008 else {
6009 #ifdef WL_SKIP_CONNECT_HINTS
6010 skip_hints = true;
6011 WL_DBG(("force skip connect hints\n"));
6012 #else /* WL_SKIP_CONNECT_HINTS */
6013 /* override bssid_hint if overridden via module param */
6014 skip_hints = fw_ap_select;
6015 #if defined(WL_FW_OCE_AP_SELECT)
6016 /* If fw select needs to be specifically done for OCE */
6017 skip_hints = fw_ap_select &&
6018 wl_cfg80211_is_oce_ap(wiphy, sme->bssid_hint);
6019 #endif /* WL_FW_OCE_AP_SELECT */
6020 WL_DBG(("fw_ap_select:%d skip_hints:%d\n", fw_ap_select, skip_hints));
6021 #endif /* WL_SKIP_CONNECT_HINTS */
6022
6023 /* Use bssid_hint if hints are allowed and if its unicast addr */
6024 if (!skip_hints && sme->bssid_hint && !ETHER_ISBCAST(sme->bssid_hint)) {
6025 WL_INFORM_MEM(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
6026 info->targeted_join = true;
6027 if (cfg->join_iovar_ver) {
6028 /* Firmware supports bssid_hint feature */
6029 info->bssid_hint = true;
6030 }
6031 (void)memcpy_s(info->bssid, ETH_ALEN, sme->bssid_hint, ETH_ALEN);
6032 #ifndef WL_FORCE_RCC_LIST
6033 /* Use channel hint only for target bssid join case. In other
6034 * cases, use RCC or full scan to find better APs.
6035 */
6036 if (sme->channel_hint && ((chspec = wl_freq_to_chanspec(
6037 sme->channel_hint->center_freq)) != INVCHANSPEC)) {
6038 info->chan_cnt = 1;
6039 info->chanspecs[0] = chspec;
6040 WL_INFORM_MEM(("channel_hint: chspec(%x)\n", chspec));
6041 }
6042 #endif /* !WL_FORCE_RCC_LIST */
6043 }
6044 }
6045 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6046
6047 if (info->targeted_join != true) {
6048 /* For non targeted join, use bcast address */
6049 (void)memcpy_s(&info->bssid, ETH_ALEN, ðer_bcast, ETH_ALEN);
6050 }
6051 WL_DBG(("targeted_join:%d chan_cnt:%d\n",
6052 info->targeted_join, info->chan_cnt));
6053 return 0;
6054 }
6055
6056 static s32
wl_sync_fw_assoc_states(struct bcm_cfg80211 * cfg,struct net_device * dev,wlcfg_assoc_info_t * info)6057 wl_sync_fw_assoc_states(struct bcm_cfg80211 *cfg,
6058 struct net_device *dev, wlcfg_assoc_info_t *info)
6059 {
6060 s32 err = BCME_OK;
6061 u8 bssid[ETH_ALEN];
6062
6063 if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_reassoc_support) {
6064 /* ROAM case */
6065 info->reassoc = true;
6066 } else {
6067 /* store the bssid for the connect req */
6068 wl_update_prof(cfg, dev, NULL, info->bssid, WL_PROF_LATEST_BSSID);
6069
6070 /* following scenarios are possible
6071 * In case of wrong request/abnormal status,
6072 * trigger DISASSOC to clean up status.
6073 * 1. DHD prev status is CONNECTING
6074 * => 1.1 Wrong request
6075 * 2. DHD previous status is CONNECTED
6076 * - FW connected
6077 * => Wrong request
6078 * - FW not connected
6079 * => Abnormal status
6080 * 3. DHD previous status is DISCONNECTING
6081 * => Waiting for disconnecting
6082 * 4. DHD previous status is not connected
6083 * - FW not connected
6084 * => Normal status
6085 * - FW connected
6086 * => Abnormal status
6087 */
6088 if (wl_get_drv_status(cfg, CONNECTING, dev) ||
6089 wl_get_drv_status(cfg, CONNECTED, dev)) {
6090 /* set nested connect bit to identify the context */
6091 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6092 /* DHD prev status is CONNECTING/CONNECTED */
6093 wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
6094 } else if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6095 /* DHD prev status is DISCONNECTING */
6096 wl_cfg80211_cleanup_mismatch_status(dev, cfg, false);
6097 } else if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6098 /* DHD previous status is not connected and FW connected */
6099 if (wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) == 0) {
6100 /* set nested connect bit to identify the context */
6101 wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6102 wl_cfg80211_cleanup_mismatch_status(dev, cfg, true);
6103 }
6104 }
6105 #ifdef WL_EXT_IAPSTA
6106 wl_ext_in4way_sync(dev, STA_WAIT_DISCONNECTED, WL_EXT_STATUS_CONNECTING, NULL);
6107 #endif
6108 }
6109
6110 /* Clear BSSID if disconnecting state is not in progress */
6111 bzero(&bssid, sizeof(bssid));
6112 if (!wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6113 wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
6114 }
6115
6116 LOG_TS(cfg, conn_start);
6117 CLR_TS(cfg, authorize_start);
6118 /* clear nested connect bit on proceeding for connection */
6119 wl_clr_drv_status(cfg, NESTED_CONNECT, dev);
6120
6121 if (!info->reassoc) {
6122 /* 'connect' request received */
6123 wl_set_drv_status(cfg, CONNECTING, dev);
6124 }
6125
6126 return err;
6127 }
6128
6129 #if defined(DBG_PKT_MON) && defined(BCMDONGLEHOST)
6130 void
wl_pkt_mon_start(struct bcm_cfg80211 * cfg,struct net_device * dev)6131 wl_pkt_mon_start(struct bcm_cfg80211 *cfg, struct net_device *dev)
6132 {
6133 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6134 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6135 DHD_DBG_PKT_MON_START(dhdp);
6136 }
6137 }
6138 #endif /* DBG_PKT_MON && BCMDONGLEHOST */
6139
6140 static s32
wl_ext_get_rssi(struct bcm_cfg80211 * cfg,u8 * bssid)6141 wl_ext_get_rssi(struct bcm_cfg80211 *cfg, u8 *bssid)
6142 {
6143 wl_scan_results_t *bss_list;
6144 wl_bss_info_t *bi = NULL;
6145 s32 i, rssi = 0;
6146
6147 mutex_lock(&cfg->scan_sync);
6148 bss_list = cfg->bss_list;
6149 bi = next_bss(bss_list, bi);
6150 for_each_bss(bss_list, bi, i) {
6151 if (!memcmp(&bi->BSSID, bssid, ETHER_ADDR_LEN))
6152 rssi = dtoh32(bi->RSSI);
6153 }
6154 mutex_unlock(&cfg->scan_sync);
6155
6156 return rssi;
6157 }
6158
6159 void
wl_conn_debug_info(struct bcm_cfg80211 * cfg,struct net_device * dev,wlcfg_assoc_info_t * info)6160 wl_conn_debug_info(struct bcm_cfg80211 *cfg, struct net_device *dev, wlcfg_assoc_info_t *info)
6161 {
6162 struct wl_security *sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6163 char sec_info[32];
6164 u32 chanspec = info->chanspecs[0];
6165 s32 rssi = 0;
6166
6167 if (!sec) {
6168 WL_ERR(("no sec?\n"));
6169 return;
6170 }
6171
6172 rssi = wl_ext_get_rssi(cfg, info->bssid);
6173 wl_ext_get_sec(dev, 0, sec_info, sizeof(sec_info), TRUE);
6174 WL_MSG(dev->name, "Connecting with " MACDBG " ssid \"%s\", len (%d), "
6175 "channel=%d, sec=%s, rssi=%d\n", MAC2STRDBG((u8*)(&info->bssid)),
6176 info->ssid, info->ssid_len, wf_chspec_ctlchan(chanspec), sec_info, rssi);
6177 if (wl_dbg_level & WL_DBG_DBG) {
6178 WL_MSG(dev->name, "akm:0x%x auth:0x%x wpaver:0x%x pwise:0x%x gwise:0x%x\n",
6179 sec->wpa_auth, sec->auth_type, sec->wpa_versions,
6180 sec->cipher_pairwise, sec->cipher_group);
6181 WL_MSG(dev->name, "wpa_auth:0x%x auth:0x%x wsec:0x%x mfp:0x%x\n",
6182 sec->fw_wpa_auth, sec->fw_auth, sec->fw_wsec, sec->fw_mfp);
6183 /* print channels for assoc */
6184 prhex("chanspecs", (const u8 *)info->chanspecs,
6185 (info->chan_cnt * sizeof(chanspec_t)));
6186 }
6187 SUPP_LOG(("[%s] Connecting with " MACDBG " ssid \"%s\",chan_cnt:%d\n",
6188 dev->name, MAC2STRDBG((u8*)(&info->bssid)),
6189 info->ssid, info->chan_cnt));
6190 }
6191
6192 static s32
wl_handle_join(struct bcm_cfg80211 * cfg,struct net_device * dev,wlcfg_assoc_info_t * assoc_info)6193 wl_handle_join(struct bcm_cfg80211 *cfg,
6194 struct net_device *dev, wlcfg_assoc_info_t *assoc_info)
6195 {
6196 s32 err = 0;
6197 size_t join_params_size;
6198 void *join_params = NULL;
6199
6200 if (!cfg->join_iovar_ver) {
6201 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
6202 assoc_info->chan_cnt * sizeof(chanspec_t);
6203 } else if (cfg->join_iovar_ver == WL_EXTJOIN_VERSION_V1) {
6204 /* Use version join struct */
6205 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE_V1 +
6206 assoc_info->chan_cnt * sizeof(chanspec_t);
6207 } else {
6208 WL_ERR(("Unsupported join iovar version\n"));
6209 return -EINVAL;
6210 }
6211
6212 join_params = MALLOCZ(cfg->osh, join_params_size);
6213 if (join_params == NULL) {
6214 err = -ENOMEM;
6215 WL_ERR(("Mem alloc for join_params failed\n"));
6216 goto fail;
6217 }
6218
6219 /* Fill up the join params */
6220 err = wl_config_assoc_params(cfg, dev, join_params, join_params_size,
6221 assoc_info);
6222 if (unlikely(err)) {
6223 WL_ERR(("config assoc ies failed\n"));
6224 goto fail;
6225 }
6226
6227 err = wldev_iovar_setbuf_bsscfg(dev, "join", join_params, join_params_size,
6228 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, assoc_info->bssidx, &cfg->ioctl_buf_sync);
6229 if (err) {
6230 WL_ERR(("join iovar failed. err:%d\n", err));
6231 }
6232
6233 fail:
6234 if (join_params) {
6235 MFREE(cfg->osh, join_params, join_params_size);
6236 }
6237 return err;
6238 }
6239
6240 static s32
wl_handle_reassoc(struct bcm_cfg80211 * cfg,struct net_device * dev,wlcfg_assoc_info_t * info)6241 wl_handle_reassoc(struct bcm_cfg80211 *cfg, struct net_device *dev,
6242 wlcfg_assoc_info_t *info)
6243 {
6244 wl_reassoc_params_t reassoc_params;
6245 s32 err;
6246 char sec_info[32];
6247
6248 bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE);
6249 (void)memcpy_s(&reassoc_params.bssid.octet, ETH_ALEN, info->bssid, ETH_ALEN);
6250 wl_ext_get_sec(dev, 0, sec_info, sizeof(sec_info), TRUE);
6251 WL_MSG(dev->name, "Reconnecting with " MACDBG " sec=%s\n",
6252 MAC2STRDBG((u8*)(&reassoc_params.bssid)), sec_info);
6253 err = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, sizeof(wl_reassoc_params_t));
6254 if (unlikely(err)) {
6255 WL_ERR(("reassoc failed, error=%d\n", err));
6256 return err;
6257 } else {
6258 WL_INFORM_MEM(("wl reassoc "MACDBG"\n", MAC2STRDBG(info->bssid)));
6259 }
6260
6261 return BCME_OK;
6262 }
6263
6264 static s32
wl_cfg80211_connect(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme)6265 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
6266 struct cfg80211_connect_params *sme)
6267 {
6268 s32 err = BCME_OK;
6269 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6270 wlcfg_assoc_info_t assoc_info;
6271 #ifdef WL_EXT_IAPSTA
6272 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6273 #endif
6274
6275 WL_DBG(("Enter len=%zu\n", sme->ie_len));
6276 RETURN_EIO_IF_NOT_UP(cfg);
6277
6278 /* syncronize the connect states */
6279 mutex_lock(&cfg->connect_sync);
6280
6281 bzero(&assoc_info, sizeof(wlcfg_assoc_info_t));
6282 if ((assoc_info.bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6283 WL_ERR(("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr));
6284 goto fail;
6285 }
6286
6287 err = wl_do_preassoc_ops(cfg, dev, sme);
6288 if (unlikely(err)) {
6289 WL_ERR(("config assoc channel failed\n"));
6290 goto fail;
6291 }
6292
6293 err = wl_handle_assoc_hints(cfg, dev, sme, &assoc_info);
6294 if (unlikely(err)) {
6295 WL_ERR(("assoc hint processing failed\n"));
6296 goto fail;
6297 }
6298
6299 if (wl_sync_fw_assoc_states(cfg, dev, &assoc_info) != BCME_OK) {
6300 /* attempt best effort */
6301 WL_ERR(("fw assoc sync failed\n"));
6302 }
6303
6304 if (assoc_info.reassoc) {
6305 // terence 20200530, should call wl_ext_iapsta_update_channel() to move AP channel?
6306 /* Handle roam to same ESS */
6307 if ((err = wl_handle_reassoc(cfg, dev, &assoc_info)) != BCME_OK) {
6308 goto fail;
6309 }
6310 } else {
6311 err = wl_config_assoc_security(cfg, dev, sme);
6312 if (unlikely(err)) {
6313 WL_ERR(("config assoc security failed\n"));
6314 goto fail;
6315 }
6316
6317 err = wl_get_assoc_channels(cfg, dev, &assoc_info);
6318 if (unlikely(err)) {
6319 WL_ERR(("get assoc channels failed\n"));
6320 goto fail;
6321 }
6322
6323 err = wl_config_assoc_ies(cfg, dev, sme, &assoc_info);
6324 if (unlikely(err)) {
6325 WL_ERR(("config assoc ies failed\n"));
6326 goto fail;
6327 }
6328
6329 /* print relevant info for debug purpose */
6330 #ifdef WL_EXT_IAPSTA
6331 wl_ext_iapsta_update_channel(dhdp, dev, CHSPEC_CHANNEL(assoc_info.chanspecs[0]));
6332 #endif
6333 wl_conn_debug_info(cfg, dev, &assoc_info);
6334 if ((err = wl_handle_join(cfg, dev, &assoc_info)) != BCME_OK) {
6335 goto fail;
6336 }
6337 }
6338 /* Store the minium idx expected */
6339 cfg->eidx.min_connect_idx = cfg->eidx.enqd;
6340
6341 fail:
6342 if (unlikely(err)) {
6343 WL_ERR(("connect error (%d)\n", err));
6344 wl_clr_drv_status(cfg, CONNECTING, dev);
6345 CLR_TS(cfg, conn_start);
6346 /* Flush fw logs */
6347 wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
6348 #ifdef WLTDLS
6349 /* If connect fails, check whether we can enable back TDLS */
6350 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
6351 #endif /* WLTDLS */
6352 } else {
6353 #ifdef DBG_PKT_MON
6354 /* start packet log in adv to ensure that EAPOL msgs aren't missed */
6355 wl_pkt_mon_start(cfg, dev);
6356 #endif /* DBG_PKT_MON */
6357 }
6358 #ifdef WL_EXT_IAPSTA
6359 if (!err)
6360 wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY,
6361 WL_EXT_STATUS_CONNECTING, NULL);
6362 #endif
6363
6364 mutex_unlock(&cfg->connect_sync);
6365 return err;
6366 }
6367
wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 * cfg,struct net_device * dev)6368 static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev)
6369 {
6370 uint8 wait_cnt;
6371 u32 status = 0;
6372
6373 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
6374 while ((status = wl_get_drv_status(cfg, DISCONNECTING, dev)) && wait_cnt) {
6375 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
6376 wait_cnt--;
6377 OSL_SLEEP(50);
6378 }
6379
6380 WL_INFORM_MEM(("Wait for disconnection done. status:%d wait_cnt:%d\n", status, wait_cnt));
6381 if (!wait_cnt && wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6382 /* No response from firmware. Indicate connect result
6383 * to clear cfg80211 state machine
6384 */
6385 if (wl_get_drv_status(cfg, CONNECTING, dev)) {
6386 WL_INFORM_MEM(("force send connect result\n"));
6387 CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
6388 WLAN_STATUS_UNSPECIFIED_FAILURE,
6389 GFP_KERNEL);
6390 } else {
6391 WL_INFORM_MEM(("force send disconnect event\n"));
6392 CFG80211_DISCONNECTED(dev, WLAN_REASON_DEAUTH_LEAVING,
6393 NULL, 0, false, GFP_KERNEL);
6394 }
6395 CLR_TS(cfg, conn_start);
6396 CLR_TS(cfg, authorize_start);
6397 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6398 }
6399 return;
6400 }
6401
6402 static s32
wl_cfg80211_disconnect(struct wiphy * wiphy,struct net_device * dev,u16 reason_code)6403 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
6404 u16 reason_code)
6405 {
6406 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6407 scb_val_t scbval;
6408 bool act = false;
6409 s32 err = 0;
6410 u8 *curbssid = NULL;
6411 u8 null_bssid[ETHER_ADDR_LEN];
6412 s32 bssidx = 0;
6413 bool connected;
6414 bool conn_in_progress;
6415 struct wireless_dev *wdev = dev->ieee80211_ptr;
6416 #ifdef BCMDONGLEHOST
6417 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6418 #endif /* BCMDONGLEHOST */
6419
6420 RETURN_EIO_IF_NOT_UP(cfg);
6421 WL_MSG(dev->name, "Reason %d, act %d\n", reason_code, act);
6422
6423 #ifdef BCMDONGLEHOST
6424 BCM_REFERENCE(dhdp);
6425 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_START),
6426 dhd_net2idx(dhdp->info, dev), reason_code);
6427 #ifdef DHD_4WAYM4_FAIL_DISCONNECT
6428 dhd_cleanup_m4_state_work(dhdp, dhd_net2idx(dhdp->info, dev));
6429 #endif /* DHD_4WAYM4_FAIL_DISCONNECT */
6430 #endif /* BCMDONGLEHOST */
6431
6432 connected = wl_get_drv_status(cfg, CONNECTED, dev);
6433 conn_in_progress = wl_get_drv_status(cfg, CONNECTING, dev);
6434 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
6435 act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
6436 WL_INFORM_MEM(("disconnect in connect state [%d:%d:%d]. reason:%d\n",
6437 connected, conn_in_progress, act, reason_code));
6438 if (connected || conn_in_progress) {
6439 if (curbssid) {
6440 WL_DBG_MEM(("curbssid:" MACDBG "\n", MAC2STRDBG(curbssid)));
6441 }
6442 act = true;
6443 }
6444
6445 if (!curbssid) {
6446 WL_ERR(("Disconnecting while CONNECTING status %d\n", (int)sizeof(null_bssid)));
6447 bzero(null_bssid, sizeof(null_bssid));
6448 curbssid = null_bssid;
6449 }
6450
6451 if (act) {
6452 #ifdef DBG_PKT_MON
6453 /* Stop packet monitor */
6454 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6455 DHD_DBG_PKT_MON_STOP(dhdp);
6456 }
6457 #endif /* DBG_PKT_MON */
6458 /*
6459 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
6460 */
6461 /* Let scan aborted by F/W */
6462 if (cfg->scan_request) {
6463 WL_TRACE_HW4(("Aborting the scan! \n"));
6464 wl_cfgscan_cancel_scan(cfg);
6465 }
6466 if (conn_in_progress || connected || wdev->ssid_len) {
6467 scbval.val = reason_code;
6468 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
6469 scbval.val = htod32(scbval.val);
6470 WL_INFORM_MEM(("[%s] wl disassoc\n", dev->name));
6471 /* Set DISCONNECTING state. We are clearing this state
6472 in all exit paths
6473 */
6474 wl_set_drv_status(cfg, DISCONNECTING, dev);
6475 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6476 sizeof(scb_val_t));
6477 if (unlikely(err)) {
6478 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6479 WL_ERR(("error (%d)\n", err));
6480 goto exit;
6481 }
6482 #ifdef WL_EXT_IAPSTA
6483 wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
6484 WL_EXT_STATUS_DISCONNECTING, NULL);
6485 #endif
6486 }
6487 #ifdef WL_WPS_SYNC
6488 /* If are in WPS reauth state, then we would be
6489 * dropping the link down events. Ensure that
6490 * Event is sent up for the disconnect Req
6491 */
6492 if (wl_wps_session_update(dev,
6493 WPS_STATE_DISCONNECT, curbssid) == BCME_OK) {
6494 WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
6495 wl_clr_drv_status(cfg, DISCONNECTING, dev);
6496 if (connected) {
6497 /* Avoid further wl disassoc iovars */
6498 wl_clr_drv_status(cfg, CONNECTED, dev);
6499 }
6500 goto exit;
6501
6502 }
6503 #endif /* WPS_SYNC */
6504 wl_cfg80211_wait_for_disconnection(cfg, dev);
6505 } else {
6506 /* Not in connected or connection in progres states. Still receiving
6507 * disassoc indicates state mismatch with upper layer. Check for state
6508 * and issue disconnect indication if required.
6509 */
6510
6511 if (wdev->current_bss || wdev->ssid_len) {
6512 WL_INFORM_MEM(("report disconnect event\n"));
6513 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
6514 }
6515 }
6516
6517 #ifdef CUSTOM_SET_CPUCORE
6518 /* set default cpucore */
6519 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6520 dhdp->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
6521 if (!(dhdp->chan_isvht80))
6522 dhd_set_cpucore(dhdp, FALSE);
6523 }
6524 #endif /* CUSTOM_SET_CPUCORE */
6525
6526 cfg->rssi = 0; /* reset backup of rssi */
6527
6528 exit:
6529 CLR_TS(cfg, conn_start);
6530 CLR_TS(cfg, authorize_start);
6531
6532 /* Clear IEs for disaasoc */
6533 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) >= 0) {
6534 WL_INFORM_MEM(("Clearing disconnect IEs \n"));
6535 err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
6536 ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, NULL, 0);
6537 } else {
6538 WL_ERR(("Find index failed\n"));
6539 err = -EINVAL;
6540 }
6541
6542 return err;
6543 }
6544
6545 static s32
6546 #if defined(WL_CFG80211_P2P_DEV_IF)
wl_cfg80211_set_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,enum nl80211_tx_power_setting type,s32 mbm)6547 wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
6548 enum nl80211_tx_power_setting type, s32 mbm)
6549 #else
6550 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
6551 enum nl80211_tx_power_setting type, s32 dbm)
6552 #endif /* WL_CFG80211_P2P_DEV_IF */
6553 {
6554
6555 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6556 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6557 s32 err = 0;
6558 #if defined(WL_CFG80211_P2P_DEV_IF)
6559 s32 dbm = MBM_TO_DBM(mbm);
6560 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
6561 defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
6562 dbm = MBM_TO_DBM(dbm);
6563 #endif /* WL_CFG80211_P2P_DEV_IF */
6564
6565 RETURN_EIO_IF_NOT_UP(cfg);
6566 switch (type) {
6567 case NL80211_TX_POWER_AUTOMATIC:
6568 break;
6569 case NL80211_TX_POWER_LIMITED:
6570 if (dbm < 0) {
6571 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
6572 return -EINVAL;
6573 }
6574 break;
6575 case NL80211_TX_POWER_FIXED:
6576 if (dbm < 0) {
6577 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
6578 return -EINVAL;
6579 }
6580 break;
6581 }
6582
6583 err = wl_set_tx_power(ndev, type, dbm);
6584 if (unlikely(err)) {
6585 WL_ERR(("error (%d)\n", err));
6586 return err;
6587 }
6588
6589 cfg->conf->tx_power = dbm;
6590
6591 return err;
6592 }
6593
6594 static s32
6595 #if defined(WL_CFG80211_P2P_DEV_IF)
wl_cfg80211_get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,s32 * dbm)6596 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
6597 struct wireless_dev *wdev, s32 *dbm)
6598 #else
6599 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
6600 #endif /* WL_CFG80211_P2P_DEV_IF */
6601 {
6602 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6603 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
6604 s32 err = 0;
6605
6606 RETURN_EIO_IF_NOT_UP(cfg);
6607 err = wl_get_tx_power(ndev, dbm);
6608 if (unlikely(err))
6609 WL_ERR(("error (%d)\n", err));
6610
6611 return err;
6612 }
6613
6614 static s32
wl_cfg80211_config_default_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool unicast,bool multicast)6615 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
6616 u8 key_idx, bool unicast, bool multicast)
6617 {
6618 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6619 u32 index;
6620 s32 wsec;
6621 s32 err = 0;
6622 s32 bssidx;
6623
6624 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6625 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
6626 return BCME_ERROR;
6627 }
6628
6629 WL_DBG(("key index (%d)\n", key_idx));
6630 RETURN_EIO_IF_NOT_UP(cfg);
6631 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
6632 if (unlikely(err)) {
6633 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
6634 return err;
6635 }
6636 /* Fix IOT issue with Apple Airport */
6637 if (wsec == WEP_ENABLED) {
6638 /* Just select a new current key */
6639 index = (u32) key_idx;
6640 index = htod32(index);
6641 err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index,
6642 sizeof(index));
6643 if (unlikely(err)) {
6644 WL_ERR(("error (%d)\n", err));
6645 }
6646 }
6647 return err;
6648 }
6649
6650 static s32
wl_add_keyext(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,const u8 * mac_addr,struct key_params * params)6651 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
6652 u8 key_idx, const u8 *mac_addr, struct key_params *params)
6653 {
6654 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6655 struct wl_wsec_key key;
6656 s32 err = 0;
6657 s32 bssidx;
6658 s32 mode = wl_get_mode_by_netdev(cfg, dev);
6659
6660 WL_MSG(dev->name, "key index (%d)\n", key_idx);
6661 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6662 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
6663 return BCME_ERROR;
6664 }
6665 bzero(&key, sizeof(key));
6666 key.index = (u32) key_idx;
6667
6668 if (!ETHER_ISMULTI(mac_addr))
6669 memcpy((char *)&key.ea, (const void *)mac_addr, ETHER_ADDR_LEN);
6670 key.len = (u32) params->key_len;
6671
6672 /* check for key index change */
6673 if (key.len == 0) {
6674 /* key delete */
6675 swap_key_from_BE(&key);
6676 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6677 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6678 if (unlikely(err)) {
6679 WL_ERR(("key delete error (%d)\n", err));
6680 return err;
6681 }
6682 } else {
6683 if (key.len > sizeof(key.data)) {
6684 WL_ERR(("Invalid key length (%d)\n", key.len));
6685 return -EINVAL;
6686 }
6687 WL_DBG(("Setting the key index %d\n", key.index));
6688 memcpy(key.data, params->key, key.len);
6689
6690 if ((mode == WL_MODE_BSS) &&
6691 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
6692 u8 keybuf[8];
6693 memcpy(keybuf, &key.data[24], sizeof(keybuf));
6694 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
6695 memcpy(&key.data[16], keybuf, sizeof(keybuf));
6696 }
6697
6698 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
6699 if (params->seq && params->seq_len == 6) {
6700 /* rx iv */
6701 const u8 *ivptr;
6702 ivptr = (const u8 *) params->seq;
6703 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
6704 (ivptr[3] << 8) | ivptr[2];
6705 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
6706 key.iv_initialized = true;
6707 }
6708 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
6709 if (key.algo == CRYPTO_ALGO_OFF) { //not found.
6710 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
6711 return -EINVAL;
6712 }
6713 swap_key_from_BE(&key);
6714 #if defined(BCMDONGLEHOST) && !defined(CUSTOMER_HW4)
6715 /* need to guarantee EAPOL 4/4 send out before set key */
6716 dhd_wait_pend8021x(dev);
6717 #endif /* BCMDONGLEHOST && !CUSTOMER_HW4 */
6718 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
6719 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6720 if (unlikely(err)) {
6721 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6722 return err;
6723 }
6724 WL_INFORM_MEM(("[%s] wsec key set\n", dev->name));
6725 }
6726 return err;
6727 }
6728
6729 int
wl_cfg80211_enable_roam_offload(struct net_device * dev,int enable)6730 wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
6731 {
6732 int err;
6733 wl_eventmsg_buf_t ev_buf;
6734 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6735
6736 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
6737 /* roam offload is only for the primary device */
6738 return -1;
6739 }
6740
6741 WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev->name, enable));
6742 err = wldev_iovar_setint(dev, "roam_offload", enable);
6743 if (err)
6744 return err;
6745
6746 bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
6747 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
6748 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
6749 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
6750 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
6751 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
6752 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
6753 err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
6754 if (!err) {
6755 cfg->roam_offload = enable;
6756 }
6757 return err;
6758 }
6759
6760 struct wireless_dev *
wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 * cfg,const char * name)6761 wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 *cfg, const char *name)
6762 {
6763 struct net_info *iter, *next;
6764
6765 if (name == NULL) {
6766 WL_ERR(("Iface name is not provided\n"));
6767 return NULL;
6768 }
6769
6770 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
6771 for_each_ndev(cfg, iter, next) {
6772 GCC_DIAGNOSTIC_POP();
6773 if (iter->ndev) {
6774 if (strcmp(iter->ndev->name, name) == 0) {
6775 return iter->ndev->ieee80211_ptr;
6776 }
6777 }
6778 }
6779
6780 WL_DBG(("Iface %s not found\n", name));
6781 return NULL;
6782 }
6783
6784 #if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
6785 void
wl_cfg80211_block_arp(struct net_device * dev,int enable)6786 wl_cfg80211_block_arp(struct net_device *dev, int enable)
6787 {
6788 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6789 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6790
6791 WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev->name, enable));
6792 if (!dhd_pkt_filter_enable) {
6793 WL_DBG(("Packet filter isn't enabled\n"));
6794 return;
6795 }
6796
6797 /* Block/Unblock ARP frames only if STA is connected to
6798 * the upstream AP in case of STA+SoftAP Concurrenct mode
6799 */
6800 if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6801 WL_DBG(("STA not connected to upstream AP\n"));
6802 return;
6803 }
6804
6805 if (enable) {
6806 WL_DBG(("Enable ARP Filter\n"));
6807 /* Add ARP filter */
6808 dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
6809
6810 /* Enable ARP packet filter - blacklist */
6811 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
6812 TRUE, FALSE);
6813 } else {
6814 WL_DBG(("Disable ARP Filter\n"));
6815 /* Disable ARP packet filter */
6816 dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
6817 FALSE, TRUE);
6818
6819 /* Delete ARP filter */
6820 dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
6821 }
6822 }
6823 #endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
6824
6825 static s32
wl_cfg80211_add_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr,struct key_params * params)6826 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
6827 u8 key_idx, bool pairwise, const u8 *mac_addr,
6828 struct key_params *params)
6829 {
6830 struct wl_wsec_key key;
6831 s32 val = 0;
6832 s32 wsec = 0;
6833 s32 err = 0;
6834 u8 keybuf[8];
6835 s32 bssidx = 0;
6836 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6837 s32 mode = wl_get_mode_by_netdev(cfg, dev);
6838 #ifdef WL_GCMP
6839 uint32 algos = 0, mask = 0;
6840 #endif /* WL_GCMP */
6841 #if defined(WLAN_CIPHER_SUITE_PMK)
6842 wsec_pmk_t pmk;
6843 struct wl_security *sec;
6844 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
6845 #ifdef BCMDONGLEHOST
6846 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6847 #endif /* BCMDONGLEHOST */
6848
6849 #if defined (BCMDONGLEHOST)
6850 if (dhd_query_bus_erros(dhdp)) {
6851 /* If we are hit with bus error, return success so that
6852 * don't repeatedly call del station till we recover.
6853 */
6854 return 0;
6855 }
6856 #endif /* BCMDONGLEHOST */
6857
6858 WL_INFORM_MEM(("key index (%d) (0x%x)\n", key_idx, params->cipher));
6859 RETURN_EIO_IF_NOT_UP(cfg);
6860
6861 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6862 WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
6863 return BCME_ERROR;
6864 }
6865
6866 if (mac_addr &&
6867 ((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
6868 (params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
6869 wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
6870 goto exit;
6871 }
6872
6873 #ifdef BCMDONGLEHOST
6874 BCM_REFERENCE(dhdp);
6875 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_KEY), dhd_net2idx(dhdp->info, dev), 0);
6876 #endif /* BCMDONGLEHOST */
6877
6878 bzero(&key, sizeof(key));
6879 /* Clear any buffered wep key */
6880 bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
6881
6882 key.len = (u32) params->key_len;
6883 key.index = (u32) key_idx;
6884
6885 if (unlikely(key.len > sizeof(key.data))) {
6886 WL_ERR(("Too long key length (%u)\n", key.len));
6887 return -EINVAL;
6888 }
6889 memcpy(key.data, params->key, key.len);
6890
6891 key.flags = WL_PRIMARY_KEY;
6892
6893 key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
6894 val = wl_rsn_cipher_wsec_algo_lookup(params->cipher);
6895 if (val == WSEC_NONE) {
6896 WL_ERR(("Invalid cipher (0x%x), key.len = %d\n", params->cipher, key.len));
6897 #if defined(WLAN_CIPHER_SUITE_PMK)
6898 /* WLAN_CIPHER_SUITE_PMK is not NL80211 standard ,but BRCM proprietary cipher suite.
6899 * so it doesn't have right algo type. Just for now, bypass this check for
6900 * backward compatibility.
6901 * TODO: deprecate this proprietary way and replace to nl80211 set_pmk API.
6902 */
6903 if (params->cipher != WLAN_CIPHER_SUITE_PMK)
6904 #endif /* defined(WLAN_CIPHER_SUITE_PMK) */
6905 return -EINVAL;
6906 }
6907 switch (params->cipher) {
6908 case WLAN_CIPHER_SUITE_TKIP:
6909 if (params->key_len != TKIP_KEY_SIZE) {
6910 WL_ERR(("wrong TKIP Key length:%d", params->key_len));
6911 return -EINVAL;
6912 }
6913 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
6914 if (mode == WL_MODE_BSS) {
6915 bcopy(&key.data[24], keybuf, sizeof(keybuf));
6916 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
6917 bcopy(keybuf, &key.data[16], sizeof(keybuf));
6918 }
6919 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
6920 break;
6921 #if defined(WLAN_CIPHER_SUITE_PMK)
6922 case WLAN_CIPHER_SUITE_PMK:
6923 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
6924
6925 WL_MEM(("set_pmk: wpa_auth:%x akm:%x\n", sec->wpa_auth, params->cipher));
6926 /* Avoid pmk set for SAE and OWE for external supplicant case. */
6927 if (IS_AKM_SAE(sec->wpa_auth) || IS_AKM_OWE(sec->wpa_auth)) {
6928 WL_INFORM_MEM(("skip pmk set for akm:%x\n", sec->wpa_auth));
6929 break;
6930 }
6931
6932 if (params->key_len > sizeof(pmk.key)) {
6933 WL_ERR(("Worng PMK key length:%d", params->key_len));
6934 return -EINVAL;
6935 }
6936 bzero(&pmk, sizeof(pmk));
6937 bcopy(params->key, &pmk.key, params->key_len);
6938 pmk.key_len = params->key_len;
6939 pmk.flags = 0; /* 0:PMK, WSEC_PASSPHRASE:PSK, WSEC_SAE_PASSPHRASE:SAE_PSK */
6940
6941 if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
6942 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
6943 err = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len,
6944 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
6945 if (err) {
6946 /* could fail in case that 'okc' is not supported */
6947 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err));
6948 }
6949 }
6950
6951 err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
6952 if (err) {
6953 WL_ERR(("pmk failed, err=%d (ignore)\n", err));
6954 return err;
6955 } else {
6956 WL_DBG(("pmk set. flags:0x%x\n", pmk.flags));
6957 }
6958 /* Clear key length to delete key */
6959 key.len = 0;
6960 break;
6961 #endif /* WLAN_CIPHER_SUITE_PMK */
6962 #ifdef WL_GCMP
6963 case WLAN_CIPHER_SUITE_GCMP:
6964 case WLAN_CIPHER_SUITE_GCMP_256:
6965 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
6966 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
6967 algos = KEY_ALGO_MASK(key.algo);
6968 mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
6969 break;
6970 #endif /* WL_GCMP */
6971 default: /* No post processing required */
6972 WL_DBG(("no post processing required (0x%x)\n", params->cipher));
6973 break;
6974 }
6975
6976 /* Set the new key/index */
6977 if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
6978 WL_ERR(("IBSS KEY setted\n"));
6979 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
6980 }
6981 swap_key_from_BE(&key);
6982 if ((params->cipher == WLAN_CIPHER_SUITE_WEP40) ||
6983 (params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
6984 /*
6985 * For AP role, since we are doing a wl down before bringing up AP,
6986 * the plumbed keys will be lost. So for AP once we bring up AP, we
6987 * need to plumb keys again. So buffer the keys for future use. This
6988 * is more like a WAR. If firmware later has the capability to do
6989 * interface upgrade without doing a "wl down" and "wl apsta 0", then
6990 * this will not be required.
6991 */
6992 WL_DBG(("Buffering WEP Keys \n"));
6993 memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key));
6994 }
6995 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
6996 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
6997 if (unlikely(err)) {
6998 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
6999 return err;
7000 }
7001
7002 exit:
7003 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7004 if (unlikely(err)) {
7005 WL_ERR(("get wsec error (%d)\n", err));
7006 return err;
7007 }
7008
7009 wsec |= val;
7010 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
7011 if (unlikely(err)) {
7012 WL_ERR(("set wsec error (%d)\n", err));
7013 return err;
7014 }
7015 #ifdef WL_GCMP
7016 wl_set_wsec_info_algos(dev, algos, mask);
7017 #endif /* WL_GCMP */
7018 #ifdef WL_EXT_IAPSTA
7019 wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY,
7020 WL_EXT_STATUS_ADD_KEY, NULL);
7021 #endif
7022 return err;
7023 }
7024
7025 static s32
wl_cfg80211_del_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr)7026 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
7027 u8 key_idx, bool pairwise, const u8 *mac_addr)
7028 {
7029 struct wl_wsec_key key;
7030 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7031 s32 err = 0;
7032 s32 bssidx;
7033 #ifdef BCMDONGLEHOST
7034 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7035 #endif /* BCMDONGLEHOST */
7036
7037 #if defined (BCMDONGLEHOST)
7038 if (dhd_query_bus_erros(dhdp)) {
7039 /* If we are hit with bus error, return success so that
7040 * don't repeatedly call del station till we recover.
7041 */
7042 return 0;
7043 }
7044 #endif /* BCMDONGLEHOST */
7045
7046 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7047 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7048 return BCME_ERROR;
7049 }
7050 WL_DBG(("Enter\n"));
7051
7052 #ifndef MFP
7053 if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
7054 return -EINVAL;
7055 #endif
7056
7057 RETURN_EIO_IF_NOT_UP(cfg);
7058 #ifdef BCMDONGLEHOST
7059 BCM_REFERENCE(dhdp);
7060 DHD_STATLOG_CTRL(dhdp, ST(DELETE_KEY), dhd_net2idx(dhdp->info, dev), 0);
7061 #endif /* BCMDONGLEHOST */
7062 bzero(&key, sizeof(key));
7063
7064 key.flags = WL_PRIMARY_KEY;
7065 key.algo = CRYPTO_ALGO_OFF;
7066 key.index = (u32) key_idx;
7067
7068 WL_DBG(("key index (%d)\n", key_idx));
7069 /* Set the new key/index */
7070 swap_key_from_BE(&key);
7071 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
7072 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
7073 if (unlikely(err)) {
7074 if (err == -EINVAL) {
7075 if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
7076 /* we ignore this key index in this case */
7077 WL_DBG(("invalid key index (%d)\n", key_idx));
7078 }
7079 } else {
7080 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
7081 }
7082 return err;
7083 }
7084 return err;
7085 }
7086
7087 /* NOTE : this function cannot work as is and is never called */
7088 static s32
wl_cfg80211_get_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx,bool pairwise,const u8 * mac_addr,void * cookie,void (* callback)(void * cookie,struct key_params * params))7089 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
7090 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
7091 void (*callback) (void *cookie, struct key_params * params))
7092 {
7093 struct key_params params;
7094 struct wl_wsec_key key;
7095 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7096 struct wl_security *sec;
7097 s32 wsec;
7098 s32 err = 0;
7099 s32 bssidx;
7100
7101 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7102 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
7103 return BCME_ERROR;
7104 }
7105 WL_DBG(("key index (%d)\n", key_idx));
7106 RETURN_EIO_IF_NOT_UP(cfg);
7107 bzero(&key, sizeof(key));
7108 key.index = key_idx;
7109 swap_key_to_BE(&key);
7110 bzero(¶ms, sizeof(params));
7111 params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
7112 params.key = key.data;
7113
7114 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
7115 if (unlikely(err)) {
7116 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
7117 return err;
7118 }
7119 switch (WSEC_ENABLED(wsec)) {
7120 case WEP_ENABLED:
7121 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
7122 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
7123 params.cipher = WLAN_CIPHER_SUITE_WEP40;
7124 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
7125 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
7126 params.cipher = WLAN_CIPHER_SUITE_WEP104;
7127 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
7128 }
7129 break;
7130 case TKIP_ENABLED:
7131 params.cipher = WLAN_CIPHER_SUITE_TKIP;
7132 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7133 break;
7134 case AES_ENABLED:
7135 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7136 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
7137 break;
7138
7139 #ifdef BCMWAPI_WPI
7140 case SMS4_ENABLED:
7141 params.cipher = WLAN_CIPHER_SUITE_SMS4;
7142 WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
7143 break;
7144 #endif
7145
7146 #if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
7147 /* to connect to mixed mode AP */
7148 case (AES_ENABLED | TKIP_ENABLED): /* TKIP CCMP */
7149 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
7150 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
7151 break;
7152 #endif
7153 default:
7154 WL_ERR(("Invalid algo (0x%x)\n", wsec));
7155 return -EINVAL;
7156 }
7157
7158 callback(cookie, ¶ms);
7159 return err;
7160 }
7161
7162 static s32
wl_cfg80211_config_default_mgmt_key(struct wiphy * wiphy,struct net_device * dev,u8 key_idx)7163 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
7164 struct net_device *dev, u8 key_idx)
7165 {
7166 #ifdef MFP
7167 /* Firmware seems to use hard coded index for Group Mgmt Key.
7168 * TODO/Need to check whether something else needs to be
7169 * taken here
7170 */
7171 return 0;
7172 #else
7173 WL_INFORM_MEM(("Not supported\n"));
7174 return -EOPNOTSUPP;
7175 #endif /* MFP */
7176 }
7177
7178 static bool
wl_check_assoc_state(struct bcm_cfg80211 * cfg,struct net_device * dev)7179 wl_check_assoc_state(struct bcm_cfg80211 *cfg, struct net_device *dev)
7180 {
7181 wl_assoc_info_t asinfo;
7182 uint32 state = 0;
7183 int err;
7184
7185 err = wldev_iovar_getbuf_bsscfg(dev, "assoc_info",
7186 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
7187 if (unlikely(err)) {
7188 WL_ERR(("failed to get assoc_info : err=%d\n", err));
7189 return FALSE;
7190 } else {
7191 memcpy(&asinfo, cfg->ioctl_buf, sizeof(wl_assoc_info_t));
7192 state = dtoh32(asinfo.state);
7193 WL_DBG(("assoc state=%d\n", state));
7194 }
7195
7196 return (state > 0)? TRUE:FALSE;
7197 }
7198
7199 static s32
wl_cfg80211_get_rssi(struct net_device * dev,struct bcm_cfg80211 * cfg,s32 * rssi)7200 wl_cfg80211_get_rssi(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 *rssi)
7201 {
7202 s32 err = BCME_OK;
7203 scb_val_t scb_val;
7204 #ifdef SUPPORT_RSSI_SUM_REPORT
7205 wl_rssi_ant_mimo_t rssi_ant_mimo;
7206 #endif /* SUPPORT_RSSI_SUM_REPORT */
7207
7208 if (dev == NULL || cfg == NULL) {
7209 return BCME_ERROR;
7210 }
7211
7212 /* initialize rssi */
7213 *rssi = 0;
7214
7215 #ifdef SUPPORT_RSSI_SUM_REPORT
7216 /* Query RSSI sum across antennas */
7217 bzero(&rssi_ant_mimo, sizeof(rssi_ant_mimo));
7218 err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
7219 if (err) {
7220 WL_ERR(("Could not get rssi sum (%d)\n", err));
7221 /* set rssi to zero and do not return error,
7222 * because iovar phy_rssi_ant could return BCME_UNSUPPORTED
7223 * when bssid was null during roaming
7224 */
7225 err = BCME_OK;
7226 } else {
7227 cfg->rssi_sum_report = TRUE;
7228 if ((*rssi = rssi_ant_mimo.rssi_sum) >= 0) {
7229 *rssi = 0;
7230 }
7231 }
7232 #endif /* SUPPORT_RSSI_SUM_REPORT */
7233
7234 /* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore */
7235 if (cfg->rssi_sum_report == FALSE) {
7236 bzero(&scb_val, sizeof(scb_val));
7237 scb_val.val = 0;
7238 err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val,
7239 sizeof(scb_val_t));
7240 if (err) {
7241 WL_ERR(("Could not get rssi (%d)\n", err));
7242 return err;
7243 }
7244 #if defined(RSSIOFFSET)
7245 *rssi = wl_update_rssi_offset(dev, dtoh32(scb_val.val));
7246 #else
7247 *rssi = dtoh32(scb_val.val);
7248 #endif
7249 }
7250
7251 if (*rssi >= 0) {
7252 /* check assoc status including roaming */
7253 DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub));
7254 if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_check_assoc_state(cfg, dev)) {
7255 *rssi = cfg->rssi; /* use previous RSSI */
7256 WL_DBG(("use previous RSSI %d dBm\n", cfg->rssi));
7257 } else {
7258 *rssi = 0;
7259 }
7260 DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
7261 } else {
7262 /* backup the current rssi */
7263 cfg->rssi = *rssi;
7264 }
7265
7266 return err;
7267 }
7268
7269 static int
wl_cfg80211_ifstats_counters_cb(void * ctx,const uint8 * data,uint16 type,uint16 len)7270 wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data, uint16 type, uint16 len)
7271 {
7272 switch (type) {
7273 case WL_IFSTATS_XTLV_IF_INDEX:
7274 WL_DBG(("Stats received on interface index: %d\n", *data));
7275 break;
7276 case WL_IFSTATS_XTLV_GENERIC: {
7277 if (len > sizeof(wl_if_stats_t)) {
7278 WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n",
7279 type, len, (int)sizeof(wl_if_stats_t)));
7280 }
7281 memcpy(ctx, data, sizeof(wl_if_stats_t));
7282 break;
7283 }
7284 default:
7285 WL_DBG(("Unsupported counter type 0x%x\n", type));
7286 break;
7287 }
7288
7289 return BCME_OK;
7290 }
7291
7292 /* Parameters to if_counters iovar need to be converted to XTLV format
7293 * before sending to FW. The length of the top level XTLV container
7294 * containing parameters should not exceed 228 bytes
7295 */
7296 #define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228
7297
7298 int
wl_cfg80211_ifstats_counters(struct net_device * dev,wl_if_stats_t * if_stats)7299 wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats)
7300 {
7301 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7302 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7303 uint8 *pbuf = NULL;
7304 bcm_xtlvbuf_t xtlvbuf, local_xtlvbuf;
7305 bcm_xtlv_t *xtlv;
7306 uint16 expected_resp_len;
7307 wl_stats_report_t *request = NULL, *response = NULL;
7308 int bsscfg_idx;
7309 int ret = BCME_OK;
7310
7311 pbuf = (uint8 *)MALLOCZ(dhdp->osh, WLC_IOCTL_MEDLEN);
7312 if (!pbuf) {
7313 WL_ERR(("Failed to allocate local pbuf\n"));
7314 return BCME_NOMEM;
7315 }
7316
7317 /* top level container length cannot exceed 228 bytes.
7318 * This is because the output buffer is 1535 bytes long.
7319 * Allow 1300 bytes for reporting stats coming in XTLV format
7320 */
7321 request = (wl_stats_report_t *)
7322 MALLOCZ(dhdp->osh, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7323 if (!request) {
7324 WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
7325 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX));
7326 ret = BCME_NOMEM;
7327 goto fail;
7328 }
7329
7330 request->version = WL_STATS_REPORT_REQUEST_VERSION_V2;
7331
7332 /* Top level container... we will create it ourselves */
7333 /* Leave space for report version, length, and top level XTLV
7334 * WL_IFSTATS_XTLV_IF.
7335 */
7336 ret = bcm_xtlv_buf_init(&local_xtlvbuf,
7337 (uint8*)(request->data) + BCM_XTLV_HDR_SIZE,
7338 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7339 offsetof(wl_stats_report_t, data) - BCM_XTLV_HDR_SIZE,
7340 BCM_XTLV_OPTION_ALIGN32);
7341
7342 if (ret) {
7343 goto fail;
7344 }
7345
7346 /* Populate requests using this the local_xtlvbuf context. The xtlvbuf
7347 * is used to fill the container containing the XTLVs populated using
7348 * local_xtlvbuf.
7349 */
7350 ret = bcm_xtlv_buf_init(&xtlvbuf,
7351 (uint8*)(request->data),
7352 IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
7353 offsetof(wl_stats_report_t, data),
7354 BCM_XTLV_OPTION_ALIGN32);
7355
7356 if (ret) {
7357 goto fail;
7358 }
7359
7360 /* Request generic stats */
7361 ret = bcm_xtlv_put_data(&local_xtlvbuf,
7362 WL_IFSTATS_XTLV_GENERIC, NULL, 0);
7363 if (ret) {
7364 goto fail;
7365 }
7366
7367 /* Complete the outer container with type and length
7368 * only.
7369 */
7370 ret = bcm_xtlv_put_data(&xtlvbuf,
7371 WL_IFSTATS_XTLV_IF,
7372 NULL, bcm_xtlv_buf_len(&local_xtlvbuf));
7373
7374 if (ret) {
7375 goto fail;
7376 }
7377
7378 request->length = bcm_xtlv_buf_len(&xtlvbuf) +
7379 offsetof(wl_stats_report_t, data);
7380 bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
7381
7382 /* send the command over to the device and get teh output */
7383 ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request,
7384 request->length, pbuf, WLC_IOCTL_MEDLEN, bsscfg_idx,
7385 &cfg->ioctl_buf_sync);
7386 if (ret < 0) {
7387 WL_ERR(("if_counters not supported ret=%d\n", ret));
7388 goto fail;
7389 }
7390
7391 /* Reuse request to process response */
7392 response = (wl_stats_report_t *)pbuf;
7393
7394 /* version check */
7395 if (response->version != WL_STATS_REPORT_REQUEST_VERSION_V2) {
7396 ret = BCME_VERSION;
7397 goto fail;
7398 }
7399
7400 xtlv = (bcm_xtlv_t *)(response->data);
7401
7402 expected_resp_len =
7403 (BCM_XTLV_LEN(xtlv) + OFFSETOF(wl_stats_report_t, data));
7404
7405 /* Check if the received length is as expected */
7406 if ((response->length > WLC_IOCTL_MEDLEN) ||
7407 (response->length < expected_resp_len)) {
7408 ret = BCME_ERROR;
7409 WL_ERR(("Illegal response length received. Got: %d"
7410 " Expected: %d. Expected len must be <= %u\n",
7411 response->length, expected_resp_len, WLC_IOCTL_MEDLEN));
7412 goto fail;
7413 }
7414
7415 /* check the type. The return data will be in
7416 * WL_IFSTATS_XTLV_IF container. So check if that container is
7417 * present
7418 */
7419 if (BCM_XTLV_ID(xtlv) != WL_IFSTATS_XTLV_IF) {
7420 ret = BCME_ERROR;
7421 WL_ERR(("unexpected type received: %d Expected: %d\n",
7422 BCM_XTLV_ID(xtlv), WL_IFSTATS_XTLV_IF));
7423 goto fail;
7424 }
7425
7426 /* Process XTLVs within WL_IFSTATS_XTLV_IF container */
7427 ret = bcm_unpack_xtlv_buf(if_stats,
7428 (uint8*)response->data + BCM_XTLV_HDR_SIZE,
7429 BCM_XTLV_LEN(xtlv), /* total length of all TLVs in container */
7430 BCM_XTLV_OPTION_ALIGN32, wl_cfg80211_ifstats_counters_cb);
7431 if (ret) {
7432 WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret));
7433 }
7434
7435 fail:
7436 if (pbuf) {
7437 MFREE(dhdp->osh, pbuf, WLC_IOCTL_MEDLEN);
7438 }
7439
7440 if (request) {
7441 MFREE(dhdp->osh, request, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
7442 }
7443 return ret;
7444 }
7445 #undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
7446
7447 static s32
7448 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
wl_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_info * sinfo)7449 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7450 const u8 *mac, struct station_info *sinfo)
7451 #else
7452 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
7453 u8 *mac, struct station_info *sinfo)
7454 #endif
7455 {
7456 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7457 s32 rssi = 0;
7458 #if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
7459 wl_rssi_ant_mimo_t rssi_ant_mimo;
7460 int cnt, chains;
7461 #endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
7462 s32 rate = 0;
7463 s32 err = 0;
7464 u16 wl_iftype = 0;
7465 u16 wl_mode = 0;
7466 get_pktcnt_t pktcnt;
7467 wl_if_stats_t *if_stats = NULL;
7468 sta_info_v4_t *sta = NULL;
7469 #ifdef WL_RATE_INFO
7470 wl_rate_info_t *rates = NULL;
7471 #endif /* WL_RATE_INFO */
7472 u8 *curmacp = NULL;
7473 s8 eabuf[ETHER_ADDR_STR_LEN];
7474 #if defined(BCMDONGLEHOST)
7475 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
7476 bool fw_assoc_state = FALSE;
7477 u32 dhd_assoc_state = 0;
7478 #endif
7479 void *buf;
7480
7481 RETURN_EIO_IF_NOT_UP(cfg);
7482
7483 if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype, &wl_iftype, &wl_mode) < 0) {
7484 return -EINVAL;
7485 }
7486
7487 buf = MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
7488 if (buf == NULL) {
7489 WL_ERR(("wl_cfg80211_get_station: MALLOC failed\n"));
7490 goto error;
7491 }
7492
7493 switch (wl_iftype) {
7494 case WL_IF_TYPE_STA:
7495 case WL_IF_TYPE_IBSS:
7496 if (cfg->roam_offload) {
7497 struct ether_addr bssid;
7498 bzero(&bssid, sizeof(bssid));
7499 err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
7500 if (err) {
7501 WL_ERR(("Failed to get current BSSID\n"));
7502 } else {
7503 if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
7504 /* roaming is detected */
7505 err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
7506 if (err)
7507 WL_ERR(("Failed to handle the delayed"
7508 " roam, err=%d", err));
7509 mac = (u8 *)bssid.octet;
7510 }
7511 }
7512 }
7513 #if defined(BCMDONGLEHOST)
7514 dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
7515 DHD_OS_WAKE_LOCK(dhd);
7516 fw_assoc_state = dhd_is_associated(dhd, 0, &err);
7517 if (dhd_assoc_state && !fw_assoc_state) {
7518 /* check roam (join) status */
7519 if (wl_check_assoc_state(cfg, dev)) {
7520 fw_assoc_state = TRUE;
7521 WL_DBG(("roam status\n"));
7522 }
7523 }
7524 DHD_OS_WAKE_UNLOCK(dhd);
7525 #endif
7526 #if defined(BCMDONGLEHOST)
7527 if (!dhd_assoc_state || !fw_assoc_state)
7528 #else
7529 if (!wl_get_drv_status(cfg, CONNECTED, dev))
7530 #endif /* defined(BCMDONGLEHOST) */
7531 {
7532 WL_ERR(("NOT assoc\n"));
7533 if (err == -ENODATA)
7534 goto error;
7535 #if defined(BCMDONGLEHOST)
7536 if (!dhd_assoc_state) {
7537 WL_TRACE_HW4(("drv state is not connected \n"));
7538 }
7539 if (!fw_assoc_state) {
7540 WL_TRACE_HW4(("fw state is not associated \n"));
7541 }
7542 /* Disconnect due to fw is not associated for
7543 * FW_ASSOC_WATCHDOG_TIME ms.
7544 * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
7545 * means that BSSID is null.
7546 */
7547 if (dhd_assoc_state && !fw_assoc_state && !err) {
7548 if (!fw_assoc_watchdog_started) {
7549 fw_assoc_watchdog_ms = OSL_SYSUPTIME();
7550 fw_assoc_watchdog_started = TRUE;
7551 WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
7552 } else if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
7553 FW_ASSOC_WATCHDOG_TIME) {
7554 fw_assoc_watchdog_started = FALSE;
7555 err = -ENODEV;
7556 WL_TRACE_HW4(("fw is not associated for %d ms \n",
7557 (OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
7558 goto get_station_err;
7559 }
7560 }
7561 #endif /* defined(BCMDONGLEHOST) */
7562 err = -ENODEV;
7563 goto error;
7564 }
7565 #if defined(BCMDONGLEHOST)
7566 if (dhd_is_associated(dhd, 0, NULL)) {
7567 fw_assoc_watchdog_started = FALSE;
7568 }
7569 #endif /* defined(BCMDONGLEHOST) */
7570 curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
7571 if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
7572 WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
7573 MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
7574 }
7575 sta = (sta_info_v4_t *)buf;
7576 bzero(sta, WLC_IOCTL_MEDLEN);
7577 err = wldev_iovar_getbuf(dev, "sta_info", (const void*)curmacp,
7578 ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL);
7579 if (err < 0) {
7580 WL_ERR(("GET STA INFO failed, %d\n", err));
7581 goto error;
7582 }
7583 if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
7584 WL_ERR(("GET STA INFO version mismatch, %d\n", err));
7585 return BCME_VERSION;
7586 }
7587 sta->rx_rate = dtoh32(sta->rx_rate);
7588 if (sta->rx_rate != 0) {
7589 sinfo->filled |= STA_INFO_BIT(INFO_RX_BITRATE);
7590 sinfo->rxrate.legacy = sta->rx_rate / 100;
7591 WL_DBG(("RX Rate %d Mbps\n", (sta->rx_rate / 1000)));
7592 }
7593 /* go through to get another information */
7594 case WL_IF_TYPE_P2P_GC:
7595 case WL_IF_TYPE_P2P_DISC:
7596 if ((err = wl_cfg80211_get_rssi(dev, cfg, &rssi)) != BCME_OK) {
7597 goto get_station_err;
7598 }
7599 #if defined(RSSIAVG)
7600 err = wl_update_connected_rssi_cache(dev, &cfg->g_connected_rssi_cache_ctrl, &rssi);
7601 if (err) {
7602 WL_ERR(("Could not get rssi (%d)\n", err));
7603 goto get_station_err;
7604 }
7605 wl_delete_dirty_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
7606 wl_reset_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
7607 #endif
7608 #if defined(RSSIOFFSET)
7609 rssi = wl_update_rssi_offset(dev, rssi);
7610 #endif
7611 #if !defined(RSSIAVG) && !defined(RSSIOFFSET)
7612 // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
7613 rssi = MIN(rssi, RSSI_MAXVAL);
7614 #endif
7615 sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
7616 sinfo->signal = rssi;
7617 WL_DBG(("RSSI %d dBm\n", rssi));
7618 #if defined(SUPPORT_RSSI_SUM_REPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
7619 /* Query RSSI sum across antennas */
7620 (void)memset_s(&rssi_ant_mimo,
7621 sizeof(rssi_ant_mimo), 0, sizeof(rssi_ant_mimo));
7622 err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
7623 if (err) {
7624 WL_ERR(("Could not get rssi sum (%d)\n", err));
7625 } else {
7626 chains = 0;
7627 for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
7628 sinfo->chain_signal[cnt] = rssi_ant_mimo.rssi_ant[cnt];
7629 chains |= (1 << cnt);
7630 WL_DBG(("RSSI[%d]: %d dBm\n",
7631 cnt, rssi_ant_mimo.rssi_ant[cnt]));
7632 }
7633 sinfo->chains = chains;
7634 sinfo->filled |= STA_INFO_BIT(INFO_CHAIN_SIGNAL);
7635 }
7636 #endif /* SUPPORT_RSSI_SUM_REPORT && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
7637 /* go through to get another information */
7638 case WL_IF_TYPE_P2P_GO:
7639 #ifdef WL_RATE_INFO
7640 /* Get the current tx/rx rate */
7641 err = wldev_iovar_getbuf(dev, "rate_info", NULL, 0,
7642 buf, WLC_IOCTL_SMLEN, NULL);
7643 #else
7644 /* Get the current tx rate */
7645 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
7646 #endif /* WL_RATE_INFO */
7647 if (err) {
7648 WL_ERR(("Could not get rate (%d)\n", err));
7649 goto error;
7650 } else {
7651 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7652 int rxpktglom;
7653 #endif
7654 #ifdef WL_RATE_INFO
7655 rates = (wl_rate_info_t *)buf;
7656 rates->version = dtoh32(rates->version);
7657 rates->length = dtoh32(rates->length);
7658 if (rates->version != WL_RATE_INFO_VERSION) {
7659 WL_ERR(("RATE_INFO version mismatch\n"));
7660 err = BCME_VERSION;
7661 goto error;
7662 }
7663 if (rates->length != (uint16)sizeof(wl_rate_info_t)) {
7664 WL_ERR(("RATE_INFO length mismatch\n"));
7665 err = BCME_BADLEN;
7666 goto error;
7667 }
7668 /* Report the current tx rate */
7669 rate = dtoh32(rates->mode_tx_rate);
7670 #else
7671 /* Report the current tx rate */
7672 rate = dtoh32(rate);
7673 #endif /* WL_RATE_INFO */
7674 sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
7675 sinfo->txrate.legacy = rate * 5;
7676 WL_DBG(("Tx rate %d Mbps\n", (rate / 2)));
7677 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
7678 rxpktglom = ((rate/2) > 150) ? 20 : 10;
7679
7680 if (maxrxpktglom != rxpktglom) {
7681 maxrxpktglom = rxpktglom;
7682 WL_DBG(("Rate %d Mbps, update bus:"
7683 "maxtxpktglom=%d\n", (rate/2), maxrxpktglom));
7684 err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
7685 (char*)&maxrxpktglom, 4, cfg->ioctl_buf,
7686 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
7687 if (err < 0) {
7688 WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
7689 }
7690 }
7691 #endif
7692 #ifdef WL_RATE_INFO
7693 /* Report the current rx rate */
7694 rate = dtoh32(rates->mode_rx_rate);
7695 sinfo->filled |= STA_INFO_BIT(INFO_RX_BITRATE);
7696 sinfo->rxrate.legacy = rate * 5;
7697 WL_DBG(("Rx rate %d Mbps\n", (rate / 2)));
7698 #endif /* WL_RATE_INFO */
7699 }
7700 if_stats = (wl_if_stats_t *)buf;
7701 bzero(if_stats, WLC_IOCTL_MEDLEN);
7702 #ifdef BCMDONGLEHOST
7703 if (FW_SUPPORTED(dhd, ifst)) {
7704 err = wl_cfg80211_ifstats_counters(dev, if_stats);
7705 } else
7706 #endif /* BCMDONGLEHOST */
7707 {
7708 err = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
7709 (char *)if_stats, WLC_IOCTL_MEDLEN, NULL);
7710 }
7711
7712 if (err) {
7713 // WL_ERR(("if_counters not supported ret=%d\n", err));
7714 bzero(&pktcnt, sizeof(pktcnt));
7715 err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt,
7716 sizeof(pktcnt));
7717 if (!err) {
7718 sinfo->rx_packets = pktcnt.rx_good_pkt;
7719 sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
7720 sinfo->tx_packets = pktcnt.tx_good_pkt;
7721 sinfo->tx_failed = pktcnt.tx_bad_pkt;
7722 }
7723 } else {
7724 sinfo->rx_packets = (uint32)dtoh64(if_stats->rxframe);
7725 /* In this case, if_stats->rxerror is invalid.
7726 * So, force to assign '0'.
7727 */
7728 sinfo->rx_dropped_misc = 0;
7729 sinfo->tx_packets = (uint32)dtoh64(if_stats->txfrmsnt);
7730 sinfo->tx_failed = (uint32)dtoh64(if_stats->txnobuf) +
7731 (uint32)dtoh64(if_stats->txrunt) +
7732 (uint32)dtoh64(if_stats->txfail);
7733 sinfo->rx_bytes = dtoh64(if_stats->rxbyte);
7734 sinfo->tx_bytes = dtoh64(if_stats->txbyte);
7735 sinfo->tx_retries = (uint32)dtoh64(if_stats->txretry);
7736 sinfo->filled |= (STA_INFO_BIT(INFO_RX_BYTES) |
7737 STA_INFO_BIT(INFO_TX_BYTES) |
7738 STA_INFO_BIT(INFO_TX_RETRIES));
7739 }
7740
7741 sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
7742 STA_INFO_BIT(INFO_RX_DROP_MISC) |
7743 STA_INFO_BIT(INFO_TX_PACKETS) |
7744 STA_INFO_BIT(INFO_TX_FAILED));
7745 get_station_err:
7746 if (err && (err != -ENODATA)) {
7747 /* Disconnect due to zero BSSID or error to get RSSI */
7748 scb_val_t scbval;
7749 #ifdef BCMDONGLEHOST
7750 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
7751 dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
7752 #endif /* BCMDONGLEHOST */
7753 scbval.val = htod32(DOT11_RC_DISASSOC_LEAVING);
7754 err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
7755 sizeof(scb_val_t));
7756 if (unlikely(err)) {
7757 WL_ERR(("disassoc error (%d)\n", err));
7758 }
7759
7760 WL_ERR(("force cfg80211_disconnected: %d\n", err));
7761 wl_clr_drv_status(cfg, CONNECTED, dev);
7762 #ifdef BCMDONGLEHOST
7763 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_DONE),
7764 dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
7765 #endif /* BCMDONGLEHOST */
7766 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
7767 wl_link_down(cfg);
7768 }
7769 break;
7770 case WL_IF_TYPE_AP:
7771 sta = (sta_info_v4_t *)buf;
7772 bzero(sta, WLC_IOCTL_MEDLEN);
7773 err = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac,
7774 ETHER_ADDR_LEN, buf, WLC_IOCTL_MEDLEN, NULL);
7775 if (err < 0) {
7776 WL_ERR(("GET STA INFO failed, %d\n", err));
7777 goto error;
7778 }
7779 if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
7780 WL_ERR(("GET STA INFO version mismatch, %d\n", err));
7781 return BCME_VERSION;
7782 }
7783 sta->len = dtoh16(sta->len);
7784 sta->cap = dtoh16(sta->cap);
7785 sta->flags = dtoh32(sta->flags);
7786 sta->idle = dtoh32(sta->idle);
7787 sta->in = dtoh32(sta->in);
7788 sinfo->filled |= STA_INFO_BIT(INFO_INACTIVE_TIME);
7789 sinfo->inactive_time = sta->idle * 1000;
7790 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || \
7791 defined(WL_COMPAT_WIRELESS)
7792 if (sta->flags & WL_STA_ASSOC) {
7793 sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
7794 sinfo->connected_time = sta->in;
7795 }
7796 #endif
7797 WL_INFORM_MEM(("STA %s, flags 0x%x, idle time %ds, connected time %ds\n",
7798 bcm_ether_ntoa((const struct ether_addr *)mac, eabuf),
7799 sta->flags, sta->idle, sta->in));
7800 break;
7801 default :
7802 WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
7803 }
7804 error:
7805 if (buf) {
7806 MFREE(cfg->osh, buf, WLC_IOCTL_MEDLEN);
7807 }
7808
7809 return err;
7810 }
7811
7812 static int
wl_cfg80211_dump_station(struct wiphy * wiphy,struct net_device * ndev,int idx,u8 * mac,struct station_info * sinfo)7813 wl_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
7814 int idx, u8 *mac, struct station_info *sinfo)
7815 {
7816 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7817 struct maclist *assoc_maclist = (struct maclist *)&(cfg->assoclist);
7818 int err;
7819
7820 WL_DBG(("%s: enter, idx=%d\n", __FUNCTION__, idx));
7821
7822 if (idx == 0) {
7823 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
7824 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
7825 assoc_maclist, sizeof(cfg->assoclist));
7826 if (err < 0) {
7827 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
7828 cfg->assoclist.count = 0;
7829 return -EOPNOTSUPP;
7830 }
7831 }
7832
7833 if (idx < le32_to_cpu(cfg->assoclist.count)) {
7834 (void)memcpy_s(mac, ETH_ALEN, cfg->assoclist.mac[idx], ETH_ALEN);
7835 return wl_cfg80211_get_station(wiphy, ndev, mac, sinfo);
7836 }
7837
7838 return -ENOENT;
7839 }
7840
7841 static s32
wl_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool enabled,s32 timeout)7842 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
7843 bool enabled, s32 timeout)
7844 {
7845 s32 pm;
7846 s32 err = 0;
7847 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7848 struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
7849 s32 mode;
7850 #ifdef RTT_SUPPORT
7851 rtt_status_info_t *rtt_status;
7852 #endif /* RTT_SUPPORT */
7853 dhd_pub_t *dhd = cfg->pub;
7854 RETURN_EIO_IF_NOT_UP(cfg);
7855
7856 WL_DBG(("Enter\n"));
7857 mode = wl_get_mode_by_netdev(cfg, dev);
7858 if (cfg->p2p_net == dev || _net_info == NULL ||
7859 !wl_get_drv_status(cfg, CONNECTED, dev) ||
7860 ((mode != WL_MODE_BSS) &&
7861 (mode != WL_MODE_IBSS))) {
7862 return err;
7863 }
7864
7865 /* Enlarge pm_enable_work */
7866 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
7867
7868 pm = enabled ? PM_FAST : PM_OFF;
7869 if (_net_info->pm_block) {
7870 WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
7871 dev->name, _net_info->pm_block));
7872 pm = PM_OFF;
7873 }
7874 if (enabled && dhd_conf_get_pm(dhd) >= 0)
7875 pm = dhd_conf_get_pm(dhd);
7876 pm = htod32(pm);
7877 WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
7878 #ifdef RTT_SUPPORT
7879 rtt_status = GET_RTTSTATE(dhd);
7880 if (rtt_status->status != RTT_ENABLED) {
7881 #endif /* RTT_SUPPORT */
7882 err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
7883 if (unlikely(err)) {
7884 if (err == -ENODEV)
7885 WL_DBG(("net_device is not ready yet\n"));
7886 else
7887 WL_ERR(("error (%d)\n", err));
7888 return err;
7889 }
7890 #ifdef RTT_SUPPORT
7891 }
7892 #endif /* RTT_SUPPORT */
7893 wl_cfg80211_update_power_mode(dev);
7894 return err;
7895 }
7896
7897 /* force update cfg80211 to keep power save mode in sync. BUT this is NOT
7898 * a good solution since there is no protection while changing wdev->os. Best
7899 * way of changing power saving mode is doing it through
7900 * NL80211_CMD_SET_POWER_SAVE
7901 */
wl_cfg80211_update_power_mode(struct net_device * dev)7902 void wl_cfg80211_update_power_mode(struct net_device *dev)
7903 {
7904 int err, pm = -1;
7905
7906 err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
7907 if (err)
7908 WL_ERR(("error (%d)\n", err));
7909 else if (pm != -1 && dev->ieee80211_ptr)
7910 dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
7911 }
7912
wl_find_msb(u16 bit16)7913 static __used u32 wl_find_msb(u16 bit16)
7914 {
7915 u32 ret = 0;
7916
7917 if (bit16 & 0xff00) {
7918 ret += 8;
7919 bit16 >>= 8;
7920 }
7921
7922 if (bit16 & 0xf0) {
7923 ret += 4;
7924 bit16 >>= 4;
7925 }
7926
7927 if (bit16 & 0xc) {
7928 ret += 2;
7929 bit16 >>= 2;
7930 }
7931
7932 if (bit16 & 2)
7933 ret += bit16 & 2;
7934 else if (bit16)
7935 ret += bit16;
7936
7937 return ret;
7938 }
7939
7940 #ifndef OEM_ANDROID
7941 /*
7942 * API invoked from driver .resume context
7943 */
7944 s32
wl_cfg80211_resume(struct bcm_cfg80211 * cfg)7945 wl_cfg80211_resume(struct bcm_cfg80211 *cfg)
7946 {
7947 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7948 s32 err = BCME_OK;
7949 int pkt_filter_id = WL_WOWLAN_PKT_FILTER_ID_FIRST;
7950
7951 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
7952 WL_INFORM_MEM(("device is not ready\n"));
7953 return err;
7954 }
7955
7956 while (pkt_filter_id <= WL_WOWLAN_PKT_FILTER_ID_LAST) {
7957 /* delete wowlan pkt filter if any */
7958 err = wldev_iovar_setbuf(ndev, "pkt_filter_delete", &pkt_filter_id,
7959 sizeof(pkt_filter_id), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
7960 &cfg->ioctl_buf_sync);
7961 /* pkt_filter_delete would return BCME_BADARG when pkt filter id
7962 * does not exist in filter list of firmware, ignore it.
7963 */
7964 if (BCME_BADARG == err)
7965 err = BCME_OK;
7966
7967 if (BCME_OK != err) {
7968 WL_ERR(("pkt_filter_delete failed, id=%d, err=%d\n",
7969 pkt_filter_id, err));
7970 }
7971 pkt_filter_id++;
7972 }
7973
7974 return err;
7975 }
7976 #endif /* !OEM_ANDROID */
7977
7978 #if !defined(OEM_ANDROID)
7979 #ifdef CONFIG_PM
7980 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
wl_wowlan_config(struct wiphy * wiphy,struct cfg80211_wowlan * wow)7981 static s32 wl_wowlan_config(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
7982 {
7983 s32 err = BCME_OK;
7984 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7985 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
7986
7987 u32 i = 0, j = 0;
7988 u32 buf_len = 0, pattern_size = 0;
7989 wl_pkt_filter_t *pkt_filterp = NULL;
7990 wl_pkt_filter_enable_t pkt_filter_enable;
7991 u8 mask_bytes_len = 0, mask_byte_idx = 0, mask_bit_idx = 0;
7992 const u32 max_buf_size = WL_PKT_FILTER_FIXED_LEN +
7993 WL_PKT_FILTER_PATTERN_FIXED_LEN + (2 * WL_WOWLAN_MAX_PATTERN_LEN);
7994
7995 WL_DBG(("Enter\n"));
7996
7997 if (wow == NULL) {
7998 WL_DBG(("wow config is null\n"));
7999 return err;
8000 }
8001
8002 /* configure wowlan pattern filters */
8003 if (0 < wow->n_patterns) {
8004 pkt_filterp = (wl_pkt_filter_t *)MALLOCZ(cfg->osh, max_buf_size);
8005 if (pkt_filterp == NULL) {
8006 WL_ERR(("Error allocating buffer for pkt filters\n"));
8007 return -ENOMEM;
8008 }
8009
8010 WL_DBG(("Pattern count=%d\n", wow->n_patterns));
8011 while (i < wow->n_patterns) {
8012
8013 /* reset buffers */
8014 buf_len = 0;
8015 bzero(pkt_filterp, max_buf_size);
8016
8017 /* copy filter id */
8018 store32_ua(&pkt_filterp->id, (WL_WOWLAN_PKT_FILTER_ID_FIRST + i));
8019
8020 /* copy filter type */
8021 store32_ua(&pkt_filterp->type, WL_PKT_FILTER_TYPE_PATTERN_MATCH);
8022
8023 /* copy size */
8024 pattern_size = htod32(wow->patterns[i].pattern_len);
8025 store32_ua(&pkt_filterp->u.pattern.size_bytes, pattern_size);
8026
8027 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
8028 /* copy offset */
8029 store32_ua(&pkt_filterp->u.pattern.offset, wow->patterns[i].pkt_offset);
8030 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
8031
8032 /* convert mask from bit to byte format */
8033 j = 0;
8034 mask_bit_idx = 0;
8035 mask_byte_idx = 0;
8036 mask_bytes_len = DIV_ROUND_UP(pattern_size, 8);
8037 while ((mask_byte_idx < mask_bytes_len) &&
8038 (mask_bit_idx < pattern_size)) {
8039
8040 if (isbitset(wow->patterns[i].mask[mask_byte_idx], mask_bit_idx++))
8041 pkt_filterp->u.pattern.mask_and_pattern[j] = 0xFF;
8042 j++;
8043 if (mask_bit_idx >= 8) {
8044 /* move to next mask byte */
8045 mask_bit_idx = 0;
8046 mask_byte_idx++;
8047 }
8048 }
8049
8050 /* copy pattern to be matched */
8051 memcpy(&pkt_filterp->u.pattern.mask_and_pattern[pattern_size],
8052 wow->patterns[i].pattern, pattern_size);
8053
8054 /* calculate filter buffer len */
8055 buf_len += WL_PKT_FILTER_FIXED_LEN;
8056 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + (2 * pattern_size));
8057
8058 /* add pkt filter */
8059 err = wldev_iovar_setbuf(ndev, "pkt_filter_add", pkt_filterp, buf_len,
8060 cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync);
8061 if (BCME_OK != err) {
8062 WL_ERR(("pkt_filter_add failed, id=%d, err=%d\n",
8063 pkt_filterp->id, err));
8064 goto exit;
8065 }
8066
8067 /* enable pkt filter id */
8068 pkt_filter_enable.id = pkt_filterp->id;
8069 pkt_filter_enable.enable = TRUE;
8070 err = wldev_iovar_setbuf(ndev, "pkt_filter_enable", &pkt_filter_enable,
8071 sizeof(pkt_filter_enable),
8072 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
8073 if (BCME_OK != err) {
8074 WL_ERR(("pkt_filter_enable failed, id=%d, err=%d\n",
8075 pkt_filterp->id, err));
8076 goto exit;
8077 }
8078 i++; /* move to next pattern */
8079 }
8080 } else
8081 WL_DBG(("wowlan filters not found\n"));
8082
8083 exit:
8084 if (pkt_filterp) {
8085 MFREE(cfg->osh, pkt_filterp, max_buf_size);
8086 }
8087
8088 return err;
8089 }
8090 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
8091 #endif /* CONFIG_PM */
8092 #endif /* !OEM_ANDROID */
8093
8094 #ifndef OEM_ANDROID
8095 /*
8096 * API invoked from driver .suspend context
8097 */
8098 s32
wl_cfg80211_suspend(struct bcm_cfg80211 * cfg)8099 wl_cfg80211_suspend(struct bcm_cfg80211 *cfg)
8100 {
8101 s32 err = BCME_OK;
8102 #ifdef CONFIG_PM
8103 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
8104 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
8105 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
8106 #endif /* CONFIG_PM */
8107 #ifdef DHD_CLEAR_ON_SUSPEND
8108 struct net_info *iter, *next;
8109 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
8110 unsigned long flags;
8111
8112 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
8113 WL_INFORM_MEM(("device is not ready : status (%d)\n",
8114 (int)cfg->status));
8115 return err;
8116 }
8117 for_each_ndev(cfg, iter, next) {
8118 /* p2p discovery iface doesn't have a ndev associated with it (for kernel > 3.8) */
8119 if (iter->ndev)
8120 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8121 }
8122 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
8123 if (cfg->scan_request) {
8124 cfg80211_scan_done(cfg->scan_request, true);
8125 cfg->scan_request = NULL;
8126 }
8127 for_each_ndev(cfg, iter, next) {
8128 if (iter->ndev) {
8129 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
8130 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
8131 }
8132 }
8133 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
8134 for_each_ndev(cfg, iter, next) {
8135 if (iter->ndev) {
8136 if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
8137 wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false);
8138 }
8139 }
8140 }
8141 #endif /* DHD_CLEAR_ON_SUSPEND */
8142 #ifdef CONFIG_PM
8143 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
8144 err = wl_wowlan_config(wiphy, wiphy->wowlan_config);
8145 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
8146 #endif /* CONFIG_PM */
8147
8148 return err;
8149 }
8150 #endif /* !OEM_ANDROID */
8151
8152 static s32
wl_update_pmklist(struct net_device * dev,struct wl_pmk_list * pmk_list,s32 err)8153 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
8154 s32 err)
8155 {
8156 int i, j;
8157 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8158 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
8159 int npmkids = cfg->pmk_list->pmkids.count;
8160
8161 ASSERT(cfg->pmk_list->pmkids.length >= (sizeof(u16)*2));
8162 if (!pmk_list) {
8163 WL_ERR(("pmk_list is NULL\n"));
8164 return -EINVAL;
8165 }
8166 /* pmk list is supported only for STA interface i.e. primary interface
8167 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
8168 */
8169 if (primary_dev != dev) {
8170 WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
8171 " interfaces than primary interface\n"));
8172 return err;
8173 }
8174
8175 WL_DBG(("No of elements %d\n", npmkids));
8176 for (i = 0; i < npmkids; i++) {
8177 WL_DBG(("PMKID[%d]: %pM =\n", i,
8178 &pmk_list->pmkids.pmkid[i].bssid));
8179 for (j = 0; j < WPA2_PMKID_LEN; j++) {
8180 WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].pmkid[j]));
8181 }
8182 }
8183 if (cfg->wlc_ver.wlc_ver_major >= MIN_PMKID_LIST_V3_FW_MAJOR) {
8184 pmk_list->pmkids.version = PMKID_LIST_VER_3;
8185 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8186 sizeof(*pmk_list), cfg->ioctl_buf,
8187 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8188 }
8189 else if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V2_FW_MAJOR) {
8190 u32 v2_list_size = (u32)(sizeof(pmkid_list_v2_t) + npmkids*sizeof(pmkid_v2_t));
8191 pmkid_list_v2_t *pmkid_v2_list = (pmkid_list_v2_t *)MALLOCZ(cfg->osh, v2_list_size);
8192 pmkid_list_v3_t *spmk_list = &cfg->spmk_info_list->pmkids;
8193
8194 if (pmkid_v2_list == NULL) {
8195 WL_ERR(("failed to allocate pmkid list\n"));
8196 return BCME_NOMEM;
8197 }
8198
8199 pmkid_v2_list->version = PMKID_LIST_VER_2;
8200 /* Account for version, length and pmkid_v2_t fields */
8201 pmkid_v2_list->length = (npmkids * sizeof(pmkid_v2_t)) + (2 * sizeof(u16));
8202
8203 for (i = 0; i < npmkids; i++) {
8204 /* memcpy_s return checks not needed as buffers are of same size */
8205 (void)memcpy_s(&pmkid_v2_list->pmkid[i].BSSID,
8206 ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8207 ETHER_ADDR_LEN);
8208
8209 /* copy pmkid if available */
8210 if (pmk_list->pmkids.pmkid[i].pmkid_len) {
8211 (void)memcpy_s(pmkid_v2_list->pmkid[i].PMKID,
8212 WPA2_PMKID_LEN,
8213 pmk_list->pmkids.pmkid[i].pmkid,
8214 pmk_list->pmkids.pmkid[i].pmkid_len);
8215 }
8216
8217 if (pmk_list->pmkids.pmkid[i].pmk_len) {
8218 (void)memcpy_s(pmkid_v2_list->pmkid[i].pmk,
8219 pmk_list->pmkids.pmkid[i].pmk_len,
8220 pmk_list->pmkids.pmkid[i].pmk,
8221 pmk_list->pmkids.pmkid[i].pmk_len);
8222 pmkid_v2_list->pmkid[i].pmk_len = pmk_list->pmkids.pmkid[i].pmk_len;
8223 }
8224
8225 if (pmk_list->pmkids.pmkid[i].ssid_len) {
8226 (void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
8227 pmk_list->pmkids.pmkid[i].ssid_len,
8228 pmk_list->pmkids.pmkid[i].ssid,
8229 pmk_list->pmkids.pmkid[i].ssid_len);
8230 pmkid_v2_list->pmkid[i].ssid.ssid_len
8231 = pmk_list->pmkids.pmkid[i].ssid_len;
8232 }
8233
8234 (void)memcpy_s(pmkid_v2_list->pmkid[i].fils_cache_id,
8235 FILS_CACHE_ID_LEN, &pmk_list->pmkids.pmkid[i].fils_cache_id,
8236 FILS_CACHE_ID_LEN);
8237 for (j = 0; j < spmk_list->count; j++) {
8238 if (memcmp(&pmkid_v2_list->pmkid[i].BSSID,
8239 &spmk_list->pmkid[j].bssid, ETHER_ADDR_LEN)) {
8240 continue; /* different MAC */
8241 }
8242 WL_DBG(("SPMK replace idx:%d bssid: "MACF " to SSID: %d\n", i,
8243 ETHER_TO_MACF(pmkid_v2_list->pmkid[i].BSSID),
8244 spmk_list->pmkid[j].ssid_len));
8245 bzero(&pmkid_v2_list->pmkid[i].BSSID, ETHER_ADDR_LEN);
8246 pmkid_v2_list->pmkid[i].ssid.ssid_len =
8247 spmk_list->pmkid[j].ssid_len;
8248 (void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
8249 spmk_list->pmkid[j].ssid_len,
8250 spmk_list->pmkid[j].ssid,
8251 spmk_list->pmkid[j].ssid_len);
8252 }
8253 pmkid_v2_list->pmkid[i].length = PMKID_ELEM_V2_LENGTH;
8254 }
8255
8256 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v2_list,
8257 v2_list_size, cfg->ioctl_buf,
8258 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8259 if (unlikely(err)) {
8260 WL_ERR(("pmkid_info failed (%d)\n", err));
8261 }
8262
8263 MFREE(cfg->osh, pmkid_v2_list, v2_list_size);
8264 }
8265 else {
8266 u32 v1_list_size = (u32)(sizeof(pmkid_list_v1_t) + npmkids*sizeof(pmkid_v1_t));
8267 pmkid_list_v1_t *pmkid_v1_list = (pmkid_list_v1_t *)MALLOCZ(cfg->osh, v1_list_size);
8268 if (pmkid_v1_list == NULL) {
8269 WL_ERR(("failed to allocate pmkid list\n"));
8270 return BCME_NOMEM;
8271 }
8272 for (i = 0; i < npmkids; i++) {
8273 /* memcpy_s return checks not needed as buffers are of same size */
8274 (void)memcpy_s(&pmkid_v1_list->pmkid[i].BSSID,
8275 ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8276 ETHER_ADDR_LEN);
8277 (void)memcpy_s(pmkid_v1_list->pmkid[i].PMKID,
8278 WPA2_PMKID_LEN, pmk_list->pmkids.pmkid[i].pmkid,
8279 WPA2_PMKID_LEN);
8280 pmkid_v1_list->npmkid++;
8281 }
8282 err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v1_list,
8283 v1_list_size, cfg->ioctl_buf,
8284 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8285 if (unlikely(err)) {
8286 WL_ERR(("pmkid_info failed (%d)\n", err));
8287 }
8288
8289 MFREE(cfg->osh, pmkid_v1_list, v1_list_size);
8290 }
8291 return err;
8292 }
8293
8294 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8295 * entry operation.
8296 */
8297 static s32
wl_cfg80211_set_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8298 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
8299 struct cfg80211_pmksa *pmksa)
8300 {
8301 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8302 s32 err = 0;
8303 int i;
8304 int npmkids = cfg->pmk_list->pmkids.count;
8305 #ifdef BCMDONGLEHOST
8306 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
8307 #endif /* BCMDONGLEHOST */
8308
8309 if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) {
8310 err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, TRUE);
8311 if (err != BCME_OK) {
8312 WL_ERR(("wl_cfg80211_set_pmksa err:%d\n", err));
8313 }
8314 return err;
8315 }
8316
8317 RETURN_EIO_IF_NOT_UP(cfg);
8318 #ifdef BCMDONGLEHOST
8319 BCM_REFERENCE(dhdp);
8320 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_PMKSA), dhd_net2idx(dhdp->info, dev), 0);
8321 #endif /* BCMDONGLEHOST */
8322
8323 for (i = 0; i < npmkids; i++) {
8324 if (pmksa->bssid != NULL) {
8325 if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8326 ETHER_ADDR_LEN))
8327 break;
8328 }
8329 #ifdef WL_FILS
8330 else if (pmksa->ssid != NULL) {
8331 if (!memcmp(pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8332 pmksa->ssid_len))
8333 break;
8334 }
8335 #endif /* WL_FILS */
8336 }
8337 if (i < WL_NUM_PMKIDS_MAX) {
8338 if (pmksa->bssid != NULL) {
8339 memcpy(&cfg->pmk_list->pmkids.pmkid[i].bssid, pmksa->bssid,
8340 ETHER_ADDR_LEN);
8341 }
8342 #ifdef WL_FILS
8343 else if (pmksa->ssid != NULL) {
8344 cfg->pmk_list->pmkids.pmkid[i].ssid_len = pmksa->ssid_len;
8345 memcpy(&cfg->pmk_list->pmkids.pmkid[i].ssid, pmksa->ssid,
8346 pmksa->ssid_len);
8347 memcpy(&cfg->pmk_list->pmkids.pmkid[i].fils_cache_id, pmksa->cache_id,
8348 FILS_CACHE_ID_LEN);
8349 }
8350 #endif /* WL_FILS */
8351 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || \
8352 defined(WL_FILS))
8353 if (pmksa->pmk_len) {
8354 if (memcpy_s(&cfg->pmk_list->pmkids.pmkid[i].pmk, PMK_LEN_MAX, pmksa->pmk,
8355 pmksa->pmk_len)) {
8356 WL_ERR(("invalid pmk len = %zu", pmksa->pmk_len));
8357 } else {
8358 cfg->pmk_list->pmkids.pmkid[i].pmk_len = pmksa->pmk_len;
8359 }
8360 }
8361 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS) */
8362 /* return check not required as buffer lengths are same */
8363 (void)memcpy_s(cfg->pmk_list->pmkids.pmkid[i].pmkid, WPA2_PMKID_LEN, pmksa->pmkid,
8364 WPA2_PMKID_LEN);
8365 cfg->pmk_list->pmkids.pmkid[i].pmkid_len = WPA2_PMKID_LEN;
8366
8367 /* set lifetime not to expire in firmware by default.
8368 * Currently, wpa_supplicant control PMKID lifetime on his end. e.g) set 12 hours
8369 * when it expired, wpa_supplicant should call set_pmksa/del_pmksa to update
8370 * corresponding entry.
8371 */
8372 cfg->pmk_list->pmkids.pmkid[i].time_left = KEY_PERM_PMK;
8373 if (i == npmkids) {
8374 cfg->pmk_list->pmkids.length += sizeof(pmkid_v3_t);
8375 cfg->pmk_list->pmkids.count++;
8376 }
8377 } else {
8378 err = -EINVAL;
8379 }
8380
8381 #if (WL_DBG_LEVEL > 0)
8382 if (pmksa->bssid != NULL) {
8383 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
8384 &cfg->pmk_list->pmkids.pmkid[npmkids - 1].bssid));
8385 }
8386 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8387 WL_DBG(("%02x\n",
8388 cfg->pmk_list->pmkids.pmkid[npmkids - 1].
8389 pmkid[i]));
8390 }
8391 #endif /* (WL_DBG_LEVEL > 0) */
8392
8393 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8394
8395 return err;
8396 }
8397
8398 /* sending pmkid_info IOVAR to manipulate PMKID(PMKSA) list in firmware.
8399 * input @pmksa: host given single pmksa info.
8400 * if it's NULL, assume whole list manipulated. e.g) flush all PMKIDs in firmware.
8401 * input @set: TRUE means adding PMKSA operation. FALSE means deleting.
8402 * return: log internal BCME_XXX error, and convert it to -EINVAL to linux generic error code.
8403 */
wl_cfg80211_update_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa,bool set)8404 static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
8405 struct cfg80211_pmksa *pmksa, bool set) {
8406
8407 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8408 s32 err = 0;
8409 pmkid_list_v3_t *pmk_list;
8410 uint32 alloc_len;
8411
8412 RETURN_EIO_IF_NOT_UP(cfg);
8413
8414 if (cfg->wlc_ver.wlc_ver_major < MIN_PMKID_LIST_V3_FW_MAJOR) {
8415 WL_DBG(("wlc_ver_major not supported:%d\n", cfg->wlc_ver.wlc_ver_major));
8416 return BCME_VERSION;
8417 }
8418
8419 alloc_len = (uint32)(OFFSETOF(pmkid_list_v3_t, pmkid) + ((pmksa) ? sizeof(pmkid_v3_t) : 0));
8420 pmk_list = (pmkid_list_v3_t *)MALLOCZ(cfg->osh, alloc_len);
8421
8422 if (pmk_list == NULL) {
8423 return BCME_NOMEM;
8424 }
8425
8426 pmk_list->version = PMKID_LIST_VER_3;
8427 pmk_list->length = alloc_len;
8428 pmk_list->count = (pmksa) ? 1 : 0; // 1 means single entry operation, 0 means whole list.
8429 pmk_list->flag = (set) ? PMKDB_SET_IOVAR : PMKDB_CLEAR_IOVAR;
8430
8431 if (pmksa) {
8432 /* controll set/del action by lifetime parameter accordingly.
8433 * if set == TRUE, it's set PMKID action with lifetime permanent.
8434 * if set == FALSE, it's del PMKID action with lifetime zero.
8435 */
8436 pmk_list->pmkid->time_left = (set) ? KEY_PERM_PMK : 0;
8437 if (pmksa->bssid) {
8438 eacopy(pmksa->bssid, &pmk_list->pmkid->bssid);
8439 }
8440 if (pmksa->pmkid) {
8441 err = memcpy_s(&pmk_list->pmkid->pmkid, sizeof(pmk_list->pmkid->pmkid),
8442 pmksa->pmkid, WPA2_PMKID_LEN);
8443 if (err) {
8444 goto exit;
8445 }
8446 pmk_list->pmkid->pmkid_len = WPA2_PMKID_LEN;
8447 }
8448 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
8449 if (pmksa->pmk) {
8450 err = memcpy_s(&pmk_list->pmkid->pmk, sizeof(pmk_list->pmkid->pmk),
8451 pmksa->pmk, pmksa->pmk_len);
8452 if (err) {
8453 goto exit;
8454 }
8455 pmk_list->pmkid->pmk_len = pmksa->pmk_len;
8456 }
8457 if (pmksa->ssid) {
8458 err = memcpy_s(&pmk_list->pmkid->ssid, sizeof(pmk_list->pmkid->ssid),
8459 pmksa->ssid, pmksa->ssid_len);
8460 if (err) {
8461 goto exit;
8462 }
8463 pmk_list->pmkid->ssid_len = pmksa->ssid_len;
8464 }
8465 if (pmksa->cache_id) {
8466 /* supplicant passes data received on air as is(network order).
8467 * convert it before using.
8468 */
8469 pmk_list->pmkid->fils_cache_id = ntoh16(*(const uint16 *)pmksa->cache_id);
8470 }
8471 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
8472 wl_cfg80211_spmk_pmkdb_change_pmk_type(cfg, pmk_list);
8473 }
8474
8475 if (wl_dbg_level & WL_DBG_DBG) {
8476 prhex("pmklist_data", (char *)pmk_list, alloc_len);
8477 }
8478
8479 err = wldev_iovar_setbuf(dev, "pmkdb", (char *)pmk_list,
8480 alloc_len, cfg->ioctl_buf,
8481 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8482 if (unlikely(err)) {
8483 WL_ERR(("pmkdb set failed. err:%d\n", err));
8484 }
8485 exit:
8486 if (pmk_list) {
8487 MFREE(cfg->osh, pmk_list, alloc_len);
8488 }
8489 return err;
8490 }
8491
8492 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8493 * entry operation.
8494 */
8495 static s32
wl_cfg80211_del_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)8496 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
8497 struct cfg80211_pmksa *pmksa)
8498 {
8499 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8500 s32 err = 0;
8501 int i;
8502 int npmkids = cfg->pmk_list->pmkids.count;
8503 RETURN_EIO_IF_NOT_UP(cfg);
8504
8505 if (!pmksa) {
8506 WL_ERR(("pmksa is not initialized\n"));
8507 return BCME_ERROR;
8508 }
8509 if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) {
8510 err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
8511 if (err != BCME_OK) {
8512 WL_ERR(("wl_cfg80211_del_pmksa err:%d\n", err));
8513 }
8514 wl_cfg80211_spmk_pmkdb_del_spmk(cfg, pmksa);
8515 return err;
8516 }
8517
8518 if (!npmkids) {
8519 /* nmpkids = 0, nothing to delete */
8520 WL_DBG(("npmkids=0. Skip del\n"));
8521 return BCME_OK;
8522 }
8523
8524 #if (WL_DBG_LEVEL > 0)
8525 if (pmksa->bssid) {
8526 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
8527 pmksa->bssid));
8528 }
8529 #ifdef WL_FILS
8530 else if (pmksa->ssid) {
8531 WL_DBG(("FILS: del_pmksa for ssid: "));
8532 for (i = 0; i < pmksa->ssid_len; i++) {
8533 WL_DBG(("%c", pmksa->ssid[i]));
8534 }
8535 WL_DBG(("\n"));
8536 }
8537 #endif /* WL_FILS */
8538 if (pmksa->pmkid) {
8539 for (i = 0; i < WPA2_PMKID_LEN; i++) {
8540 WL_DBG(("%02x\n", pmksa->pmkid[i]));
8541 }
8542 }
8543 #endif /* (WL_DBG_LEVEL > 0) */
8544
8545 for (i = 0; i < npmkids; i++) {
8546 if (pmksa->bssid) {
8547 if (!memcmp
8548 (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
8549 ETHER_ADDR_LEN)) {
8550 break;
8551 }
8552 }
8553 #ifdef WL_FILS
8554 else if (pmksa->ssid) {
8555 if (!memcmp
8556 (pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
8557 pmksa->ssid_len)) {
8558 break;
8559 }
8560 }
8561 #endif /* WL_FILS */
8562 }
8563 if ((npmkids > 0) && (i < npmkids)) {
8564 bzero(&cfg->pmk_list->pmkids.pmkid[i], sizeof(pmkid_v3_t));
8565 for (; i < (npmkids - 1); i++) {
8566 (void)memcpy_s(&cfg->pmk_list->pmkids.pmkid[i],
8567 sizeof(pmkid_v3_t),
8568 &cfg->pmk_list->pmkids.pmkid[i + 1],
8569 sizeof(pmkid_v3_t));
8570 }
8571 npmkids--;
8572 cfg->pmk_list->pmkids.length -= sizeof(pmkid_v3_t);
8573 cfg->pmk_list->pmkids.count--;
8574
8575 } else {
8576 err = -EINVAL;
8577 }
8578
8579 /* current wl_update_pmklist() doesn't delete corresponding PMKID entry.
8580 * inside firmware. So we need to issue delete action explicitely through
8581 * this function.
8582 */
8583 err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
8584 /* intentional fall through even on error.
8585 * it should work above MIN_PMKID_LIST_V3_FW_MAJOR, otherwise let ignore it.
8586 */
8587
8588 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8589
8590 return err;
8591
8592 }
8593
8594 /* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
8595 * entry operation.
8596 */
8597 static s32
wl_cfg80211_flush_pmksa(struct wiphy * wiphy,struct net_device * dev)8598 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
8599 {
8600 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8601 s32 err = 0;
8602 RETURN_EIO_IF_NOT_UP(cfg);
8603 if (cfg->wlc_ver.wlc_ver_major >= PMKDB_WLC_VER) {
8604 /* NULL pmksa means delete whole PMKSA list */
8605 err = wl_cfg80211_update_pmksa(wiphy, dev, NULL, FALSE);
8606 if (err != BCME_OK) {
8607 WL_ERR(("wl_cfg80211_flush_pmksa err:%d\n", err));
8608 }
8609 return err;
8610 }
8611 bzero(cfg->pmk_list, sizeof(*cfg->pmk_list));
8612 cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
8613 cfg->pmk_list->pmkids.count = 0;
8614 cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
8615 err = wl_update_pmklist(dev, cfg->pmk_list, err);
8616 return err;
8617 }
8618
8619 static void
wl_cfg80211_afx_handler(struct work_struct * work)8620 wl_cfg80211_afx_handler(struct work_struct *work)
8621 {
8622 struct afx_hdl *afx_instance;
8623 struct bcm_cfg80211 *cfg;
8624 s32 ret = BCME_OK;
8625
8626 BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
8627 if (afx_instance) {
8628 cfg = wl_get_cfg(afx_instance->dev);
8629 if (cfg != NULL && cfg->afx_hdl->is_active) {
8630 if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
8631 ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
8632 (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
8633 } else {
8634 ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
8635 cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
8636 NULL);
8637 }
8638 if (unlikely(ret != BCME_OK)) {
8639 WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
8640 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
8641 complete(&cfg->act_frm_scan);
8642 }
8643 }
8644 }
8645 }
8646
8647 static s32
wl_cfg80211_af_searching_channel(struct bcm_cfg80211 * cfg,struct net_device * dev)8648 wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
8649 {
8650 u32 max_retry = WL_CHANNEL_SYNC_RETRY;
8651 bool is_p2p_gas = false;
8652
8653 if (dev == NULL)
8654 return -1;
8655
8656 WL_DBG((" enter ) \n"));
8657
8658 wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8659 cfg->afx_hdl->is_active = TRUE;
8660
8661 if (cfg->afx_hdl->pending_tx_act_frm) {
8662 wl_action_frame_t *action_frame;
8663 action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
8664 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len))
8665 is_p2p_gas = true;
8666 }
8667
8668 /* Loop to wait until we find a peer's channel or the
8669 * pending action frame tx is cancelled.
8670 */
8671 while ((cfg->afx_hdl->retry < max_retry) &&
8672 (cfg->afx_hdl->peer_chan == WL_INVALID)) {
8673 cfg->afx_hdl->is_listen = FALSE;
8674 wl_set_drv_status(cfg, SCANNING, dev);
8675 WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
8676 cfg->afx_hdl->retry));
8677 /* search peer on peer's listen channel */
8678 schedule_work(&cfg->afx_hdl->work);
8679 wait_for_completion_timeout(&cfg->act_frm_scan,
8680 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8681
8682 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8683 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8684 break;
8685
8686 if (is_p2p_gas)
8687 break;
8688
8689 if (cfg->afx_hdl->my_listen_chan) {
8690 WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
8691 cfg->afx_hdl->my_listen_chan));
8692 /* listen on my listen channel */
8693 cfg->afx_hdl->is_listen = TRUE;
8694 schedule_work(&cfg->afx_hdl->work);
8695 wait_for_completion_timeout(&cfg->act_frm_scan,
8696 msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
8697 }
8698 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
8699 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
8700 break;
8701
8702 cfg->afx_hdl->retry++;
8703
8704 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
8705 }
8706
8707 cfg->afx_hdl->is_active = FALSE;
8708
8709 wl_clr_drv_status(cfg, SCANNING, dev);
8710 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
8711
8712 return (cfg->afx_hdl->peer_chan);
8713 }
8714
8715 struct p2p_config_af_params {
8716 s32 max_tx_retry; /* max tx retry count if tx no ack */
8717 #ifdef WL_CFG80211_GON_COLLISION
8718 /* drop tx go nego request if go nego collision occurs */
8719 bool drop_tx_req;
8720 #endif
8721 #ifdef WL_CFG80211_SYNC_GON
8722 /* WAR: dongle does not keep the dwell time of 'actframe' sometime.
8723 * if extra_listen is set, keep the dwell time to get af response frame
8724 */
8725 bool extra_listen;
8726 #endif
8727 bool search_channel; /* 1: search peer's channel to send af */
8728 };
8729
8730 static s32
wl_cfg80211_config_p2p_pub_af_tx(struct wiphy * wiphy,wl_action_frame_t * action_frame,wl_af_params_t * af_params,struct p2p_config_af_params * config_af_params)8731 wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
8732 wl_action_frame_t *action_frame, wl_af_params_t *af_params,
8733 struct p2p_config_af_params *config_af_params)
8734 {
8735 s32 err = BCME_OK;
8736 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8737 wifi_p2p_pub_act_frame_t *act_frm =
8738 (wifi_p2p_pub_act_frame_t *) (action_frame->data);
8739
8740 /* initialize default value */
8741 #ifdef WL_CFG80211_GON_COLLISION
8742 config_af_params->drop_tx_req = false;
8743 #endif
8744 #ifdef WL_CFG80211_SYNC_GON
8745 config_af_params->extra_listen = true;
8746 #endif
8747 config_af_params->search_channel = false;
8748 config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
8749 cfg->next_af_subtype = WL_PUB_AF_STYPE_INVALID;
8750
8751 switch (act_frm->subtype) {
8752 case P2P_PAF_GON_REQ: {
8753 /* Disable he if peer does not support before starting GONEG */
8754 WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
8755 wl_set_p2p_status(cfg, GO_NEG_PHASE);
8756
8757 config_af_params->search_channel = true;
8758 cfg->next_af_subtype = act_frm->subtype + 1;
8759
8760 /* increase dwell time to wait for RESP frame */
8761 af_params->dwell_time = WL_MED_DWELL_TIME;
8762
8763 #ifdef WL_CFG80211_GON_COLLISION
8764 config_af_params->drop_tx_req = true;
8765 #endif /* WL_CFG80211_GON_COLLISION */
8766 break;
8767 }
8768 case P2P_PAF_GON_RSP: {
8769 cfg->next_af_subtype = act_frm->subtype + 1;
8770 /* increase dwell time to wait for CONF frame */
8771 /* WAR : 100ms is added because kernel spent more time in some case.
8772 * Kernel should be fixed.
8773 */
8774 af_params->dwell_time = WL_MED_DWELL_TIME + 100;
8775 break;
8776 }
8777 case P2P_PAF_GON_CONF: {
8778 /* If we reached till GO Neg confirmation reset the filter */
8779 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
8780 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
8781
8782 /* minimize dwell time */
8783 af_params->dwell_time = WL_MIN_DWELL_TIME;
8784
8785 #ifdef WL_CFG80211_GON_COLLISION
8786 /* if go nego formation done, clear it */
8787 cfg->block_gon_req_tx_count = 0;
8788 cfg->block_gon_req_rx_count = 0;
8789 #endif /* WL_CFG80211_GON_COLLISION */
8790 #ifdef WL_CFG80211_SYNC_GON
8791 config_af_params->extra_listen = false;
8792 #endif /* WL_CFG80211_SYNC_GON */
8793 break;
8794 }
8795 case P2P_PAF_INVITE_REQ: {
8796 config_af_params->search_channel = true;
8797 cfg->next_af_subtype = act_frm->subtype + 1;
8798
8799 /* increase dwell time */
8800 af_params->dwell_time = WL_MED_DWELL_TIME;
8801 break;
8802 }
8803 case P2P_PAF_INVITE_RSP:
8804 /* minimize dwell time */
8805 af_params->dwell_time = WL_MIN_DWELL_TIME;
8806 #ifdef WL_CFG80211_SYNC_GON
8807 config_af_params->extra_listen = false;
8808 #endif /* WL_CFG80211_SYNC_GON */
8809 break;
8810 case P2P_PAF_DEVDIS_REQ: {
8811 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
8812 action_frame->len)) {
8813 config_af_params->search_channel = true;
8814 }
8815
8816 cfg->next_af_subtype = act_frm->subtype + 1;
8817 /* maximize dwell time to wait for RESP frame */
8818 af_params->dwell_time = WL_LONG_DWELL_TIME;
8819 break;
8820 }
8821 case P2P_PAF_DEVDIS_RSP:
8822 /* minimize dwell time */
8823 af_params->dwell_time = WL_MIN_DWELL_TIME;
8824 #ifdef WL_CFG80211_SYNC_GON
8825 config_af_params->extra_listen = false;
8826 #endif /* WL_CFG80211_SYNC_GON */
8827 break;
8828 case P2P_PAF_PROVDIS_REQ: {
8829 if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
8830 action_frame->len)) {
8831 config_af_params->search_channel = true;
8832 }
8833
8834 cfg->next_af_subtype = act_frm->subtype + 1;
8835 /* increase dwell time to wait for RESP frame */
8836 af_params->dwell_time = WL_MED_DWELL_TIME;
8837 break;
8838 }
8839 case P2P_PAF_PROVDIS_RSP: {
8840 /* wpa_supplicant send go nego req right after prov disc */
8841 cfg->next_af_subtype = P2P_PAF_GON_REQ;
8842 af_params->dwell_time = WL_MED_DWELL_TIME;
8843 #ifdef WL_CFG80211_SYNC_GON
8844 config_af_params->extra_listen = false;
8845 #endif /* WL_CFG80211_SYNC_GON */
8846 break;
8847 }
8848 default:
8849 WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
8850 act_frm->subtype));
8851 err = BCME_BADARG;
8852 }
8853 return err;
8854 }
8855
8856 #if defined(WL11U) && defined(WL_HOST_AF_DFS_CHECK)
8857 static bool
wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 * cfg,wl_af_params_t * af_params,void * frame,u16 frame_len)8858 wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params,
8859 void *frame, u16 frame_len)
8860 {
8861 wl_scan_results *bss_list;
8862 wl_bss_info_t *bi = NULL;
8863 bool result = false;
8864 s32 i;
8865 chanspec_t chanspec;
8866
8867 /* If DFS channel is 52~148, check to block it or not */
8868 if (af_params &&
8869 (af_params->channel >= 52 && af_params->channel <= 148)) {
8870 if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
8871 bss_list = cfg->bss_list;
8872 bi = next_bss(bss_list, bi);
8873 for_each_bss(bss_list, bi, i) {
8874 chanspec = wl_chspec_driver_to_host(bi->chanspec);
8875 if (CHSPEC_IS5G(chanspec) &&
8876 ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec))
8877 == af_params->channel)) {
8878 result = true; /* do not block the action frame */
8879 break;
8880 }
8881 }
8882 }
8883 }
8884 else {
8885 result = true;
8886 }
8887
8888 WL_DBG(("result=%s", result?"true":"false"));
8889 return result;
8890 }
8891 #endif /* WL11U && WL_HOST_AF_DFS_CHECK */
8892 static bool
wl_cfg80211_check_dwell_overflow(int32 requested_dwell,ulong dwell_jiffies)8893 wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies)
8894 {
8895 if ((requested_dwell & CUSTOM_RETRY_MASK) &&
8896 (jiffies_to_msecs(jiffies - dwell_jiffies) >
8897 (requested_dwell & ~CUSTOM_RETRY_MASK))) {
8898 WL_ERR(("Action frame TX retry time over dwell time!\n"));
8899 return true;
8900 }
8901 return false;
8902 }
8903
8904 static bool
wl_cfg80211_send_action_frame(struct wiphy * wiphy,struct net_device * dev,bcm_struct_cfgdev * cfgdev,wl_af_params_t * af_params,wl_action_frame_t * action_frame,u16 action_frame_len,s32 bssidx)8905 wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
8906 bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
8907 wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
8908 {
8909 #ifdef WL11U
8910 struct net_device *ndev = NULL;
8911 #endif /* WL11U */
8912 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8913 bool ack = false;
8914 u8 category, action;
8915 s32 tx_retry;
8916 struct p2p_config_af_params config_af_params;
8917 struct net_info *netinfo;
8918 #ifdef VSDB
8919 ulong off_chan_started_jiffies = 0;
8920 #endif
8921 ulong dwell_jiffies = 0;
8922 bool dwell_overflow = false;
8923 #ifdef BCMDONGLEHOST
8924 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
8925 #endif /* BCMDONGLEHOST */
8926
8927 int32 requested_dwell = af_params->dwell_time;
8928
8929 /* Add the default dwell time
8930 * Dwell time to stay off-channel to wait for a response action frame
8931 * after transmitting an GO Negotiation action frame
8932 */
8933 af_params->dwell_time = WL_DEFAULT_DWELL_TIME;
8934
8935 #ifdef WL11U
8936 #if defined(WL_CFG80211_P2P_DEV_IF)
8937 ndev = dev;
8938 #else
8939 ndev = ndev_to_cfgdev(cfgdev);
8940 #endif /* WL_CFG80211_P2P_DEV_IF */
8941 #endif /* WL11U */
8942
8943 category = action_frame->data[DOT11_ACTION_CAT_OFF];
8944 action = action_frame->data[DOT11_ACTION_ACT_OFF];
8945
8946 /* initialize variables */
8947 tx_retry = 0;
8948 cfg->next_af_subtype = WL_PUB_AF_STYPE_INVALID;
8949 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
8950 config_af_params.search_channel = false;
8951 #ifdef WL_CFG80211_GON_COLLISION
8952 config_af_params.drop_tx_req = false;
8953 #endif
8954 #ifdef WL_CFG80211_SYNC_GON
8955 config_af_params.extra_listen = false;
8956 #endif
8957
8958 /* config parameters */
8959 /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
8960 if (category == DOT11_ACTION_CAT_PUBLIC) {
8961 if (wl_cfg80211_is_dpp_frame((void *)action_frame->data, action_frame->len)) {
8962 wl_dpp_pa_frame_t *pa = (wl_dpp_pa_frame_t *)action_frame->data;
8963 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
8964 af_params->dwell_time = WL_MED_DWELL_TIME;
8965 cfg->need_wait_afrx = true;
8966 /* once matching frame is found in rx, abort dwell (upper layer
8967 * doesn't do that).
8968 */
8969 if (pa->ftype == DPP_AUTH_REQ) {
8970 cfg->next_af_subtype = DPP_AUTH_RESP;
8971 } else if (pa->ftype == DPP_AUTH_RESP) {
8972 cfg->next_af_subtype = DPP_AUTH_CONF;
8973 } else {
8974 cfg->next_af_subtype = WL_PUB_AF_STYPE_INVALID;
8975 cfg->need_wait_afrx = false;
8976 }
8977 } else if (wl_cfg80211_is_dpp_gas_action(
8978 (void *)action_frame->data, action_frame->len)) {
8979 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
8980 af_params->dwell_time = WL_MED_DWELL_TIME;
8981 cfg->need_wait_afrx = true;
8982 config_af_params.search_channel = false;
8983
8984 if (requested_dwell == 0) {
8985 /* Use minimal dwell to take care of Ack */
8986 af_params->dwell_time = WL_MIN_DWELL_TIME;
8987 }
8988 } else if ((action == P2P_PUB_AF_ACTION) &&
8989 (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
8990 /* p2p public action frame process */
8991 if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy,
8992 action_frame, af_params, &config_af_params)) {
8993 /* just send unknown subtype frame with default parameters. */
8994 WL_DBG(("Unknown subtype.\n"));
8995 }
8996
8997 #ifdef WL_CFG80211_GON_COLLISION
8998 if (config_af_params.drop_tx_req) {
8999 if (cfg->block_gon_req_tx_count) {
9000 /* drop gon req tx action frame */
9001 WL_DBG(("Drop gon req tx action frame: count %d\n",
9002 cfg->block_gon_req_tx_count));
9003 goto exit;
9004 }
9005 }
9006 #endif /* WL_CFG80211_GON_COLLISION */
9007 } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
9008 /* service discovery process */
9009 if (action == P2PSD_ACTION_ID_GAS_IREQ ||
9010 action == P2PSD_ACTION_ID_GAS_CREQ) {
9011 /* configure service discovery query frame */
9012 config_af_params.search_channel = true;
9013
9014 /* save next af suptype to cancel remained dwell time */
9015 cfg->next_af_subtype = action + 1;
9016
9017 af_params->dwell_time = WL_MED_DWELL_TIME;
9018 if (requested_dwell & CUSTOM_RETRY_MASK) {
9019 config_af_params.max_tx_retry =
9020 (requested_dwell & CUSTOM_RETRY_MASK) >> 24;
9021 af_params->dwell_time =
9022 (requested_dwell & ~CUSTOM_RETRY_MASK);
9023 WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
9024 config_af_params.max_tx_retry,
9025 af_params->dwell_time));
9026 }
9027 } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
9028 action == P2PSD_ACTION_ID_GAS_CRESP) {
9029 /* configure service discovery response frame */
9030 af_params->dwell_time = WL_MIN_DWELL_TIME;
9031 } else {
9032 WL_DBG(("Unknown action type: %d\n", action));
9033 }
9034 } else {
9035 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
9036 category, action, action_frame_len));
9037 }
9038 } else if (category == P2P_AF_CATEGORY) {
9039 /* do not configure anything. it will be sent with a default configuration */
9040 } else {
9041 WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
9042 category, action));
9043 #ifdef BCMDONGLEHOST
9044 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
9045 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9046 return false;
9047 }
9048 #endif /* BCMDONGLEHOST */
9049 }
9050
9051 netinfo = wl_get_netinfo_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
9052 /* validate channel and p2p ies */
9053 if (config_af_params.search_channel &&
9054 IS_P2P_SOCIAL(CHSPEC_CHANNEL(af_params->channel)) &&
9055 netinfo && netinfo->bss.ies.probe_req_ie_len) {
9056 config_af_params.search_channel = true;
9057 } else {
9058 config_af_params.search_channel = false;
9059 }
9060 #ifdef WL11U
9061 if (ndev == bcmcfg_to_prmry_ndev(cfg))
9062 config_af_params.search_channel = false;
9063 #endif /* WL11U */
9064
9065 #ifdef VSDB
9066 /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
9067 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
9068 OSL_SLEEP(50);
9069 }
9070 #endif
9071
9072 /* if scan is ongoing, abort current scan. */
9073 if (wl_get_drv_status_all(cfg, SCANNING)) {
9074 wl_cfgscan_cancel_scan(cfg);
9075 }
9076
9077 /* Abort P2P listen */
9078 if (discover_cfgdev(cfgdev, cfg)) {
9079 if (cfg->p2p_supported && cfg->p2p) {
9080 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
9081 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
9082 }
9083 }
9084
9085 #if defined(WL11U) && defined(WL_HOST_AF_DFS_CHECK)
9086 /* handling DFS channel exceptions */
9087 if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) {
9088 return false; /* the action frame was blocked */
9089 }
9090 #endif /* WL11U && WL_HOST_AF_DFS_CHECK */
9091
9092 /* set status and destination address before sending af */
9093 if (cfg->next_af_subtype != WL_PUB_AF_STYPE_INVALID) {
9094 /* set this status to cancel the remained dwell time in rx process */
9095 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9096 }
9097 wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
9098 memcpy(cfg->afx_hdl->tx_dst_addr.octet,
9099 af_params->action_frame.da.octet,
9100 sizeof(cfg->afx_hdl->tx_dst_addr.octet));
9101
9102 /* save af_params for rx process */
9103 cfg->afx_hdl->pending_tx_act_frm = af_params;
9104
9105 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
9106 WL_DBG(("Set GAS action frame config.\n"));
9107 config_af_params.search_channel = false;
9108 config_af_params.max_tx_retry = 1;
9109 }
9110
9111 /* search peer's channel */
9112 if (config_af_params.search_channel) {
9113 /* initialize afx_hdl */
9114 if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
9115 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
9116 goto exit;
9117 }
9118 cfg->afx_hdl->dev = dev;
9119 cfg->afx_hdl->retry = 0;
9120 cfg->afx_hdl->peer_chan = WL_INVALID;
9121
9122 if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
9123 WL_ERR(("couldn't find peer's channel.\n"));
9124 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
9125 af_params->channel);
9126 /* Even if we couldn't find peer channel, try to send the frame
9127 * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
9128 * respond to probe request (Ideally it has to be in listen and
9129 * responsd to probe request). However if we send Go neg req, the
9130 * peer is sending GO-neg resp. So instead of giving up here, just
9131 * proceed and attempt sending out the action frame.
9132 */
9133 }
9134
9135 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
9136 /*
9137 * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
9138 * but after the check of piggyback algorithm.
9139 * To take care of current piggback algo, lets abort the scan here itself.
9140 */
9141 wl_cfgscan_cancel_scan(cfg);
9142 /* Suspend P2P discovery's search-listen to prevent it from
9143 * starting a scan or changing the channel.
9144 */
9145 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9146 WL_ERR(("Can not disable discovery mode\n"));
9147 goto exit;
9148 }
9149
9150 /* update channel */
9151 if (cfg->afx_hdl->peer_chan != WL_INVALID) {
9152 af_params->channel = cfg->afx_hdl->peer_chan;
9153 WL_ERR(("Attempt tx on peer listen channel:%d\n",
9154 cfg->afx_hdl->peer_chan));
9155 } else {
9156 WL_ERR(("Attempt tx with the channel provided by userspace."
9157 "Channel: %d\n", CHSPEC_CHANNEL(af_params->channel)));
9158 }
9159 }
9160
9161 #ifdef VSDB
9162 off_chan_started_jiffies = jiffies;
9163 #endif /* VSDB */
9164
9165 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel);
9166
9167 wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
9168
9169 dwell_jiffies = jiffies;
9170 /* Now send a tx action frame */
9171 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
9172 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9173
9174 /* if failed, retry it. tx_retry_max value is configure by .... */
9175 while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry) &&
9176 !dwell_overflow) {
9177 #ifdef VSDB
9178 if (af_params->channel) {
9179 if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
9180 OFF_CHAN_TIME_THRESHOLD_MS) {
9181 WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
9182 off_chan_started_jiffies = jiffies;
9183 } else
9184 OSL_SLEEP(AF_RETRY_DELAY_TIME);
9185 }
9186 #endif /* VSDB */
9187 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
9188 false : true;
9189 dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
9190 }
9191
9192 if (ack == false) {
9193 WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
9194 }
9195 WL_DBG(("Complete to send action frame\n"));
9196 exit:
9197 /* Clear SENDING_ACT_FRM after all sending af is done */
9198 wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
9199
9200 #ifdef WL_CFG80211_SYNC_GON
9201 /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
9202 * if we coundn't get the next action response frame and dongle does not keep
9203 * the dwell time, go to listen state again to get next action response frame.
9204 */
9205 if (ack && config_af_params.extra_listen &&
9206 #ifdef WL_CFG80211_GON_COLLISION
9207 !cfg->block_gon_req_tx_count &&
9208 #endif /* WL_CFG80211_GON_COLLISION */
9209 wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
9210 cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
9211 s32 extar_listen_time;
9212
9213 extar_listen_time = af_params->dwell_time -
9214 jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
9215
9216 if (extar_listen_time > 50) {
9217 wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9218 WL_DBG(("Wait more time! actual af time:%d,"
9219 "calculated extar listen:%d\n",
9220 af_params->dwell_time, extar_listen_time));
9221 if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
9222 extar_listen_time + 100) == BCME_OK) {
9223 wait_for_completion_timeout(&cfg->wait_next_af,
9224 msecs_to_jiffies(extar_listen_time + 100 + 300));
9225 }
9226 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
9227 }
9228 }
9229 #endif /* WL_CFG80211_SYNC_GON */
9230 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
9231
9232 cfg->afx_hdl->pending_tx_act_frm = NULL;
9233
9234 if (ack) {
9235 WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
9236 cfg->afx_hdl->my_listen_chan));
9237 } else {
9238 WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
9239 cfg->afx_hdl->my_listen_chan));
9240 }
9241
9242 #ifdef WL_CFG80211_GON_COLLISION
9243 if (cfg->block_gon_req_tx_count) {
9244 cfg->block_gon_req_tx_count--;
9245 /* if ack is ture, supplicant will wait more time(100ms).
9246 * so we will return it as a success to get more time .
9247 */
9248 ack = true;
9249 }
9250 #endif /* WL_CFG80211_GON_COLLISION */
9251 return ack;
9252 }
9253
9254 #define MAX_NUM_OF_ASSOCIATED_DEV 64
9255 static s32
9256 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
wl_cfg80211_mgmt_tx(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,struct cfg80211_mgmt_tx_params * params,u64 * cookie)9257 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9258 struct cfg80211_mgmt_tx_params *params, u64 *cookie)
9259 #else
9260 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9261 struct ieee80211_channel *channel, bool offchan,
9262 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
9263 enum nl80211_channel_type channel_type,
9264 bool channel_type_valid,
9265 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
9266 unsigned int wait, const u8* buf, size_t len,
9267 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || \
9268 defined(WL_COMPAT_WIRELESS)
9269 bool no_cck,
9270 #endif
9271 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
9272 defined(WL_COMPAT_WIRELESS)
9273 bool dont_wait_for_ack,
9274 #endif
9275 u64 *cookie)
9276 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9277 {
9278 wl_action_frame_t *action_frame;
9279 wl_af_params_t *af_params;
9280 scb_val_t scb_val;
9281 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9282 struct ieee80211_channel *channel = params->chan;
9283 const u8 *buf = params->buf;
9284 size_t len = params->len;
9285 #endif
9286 const struct ieee80211_mgmt *mgmt;
9287 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9288 struct net_device *dev = NULL;
9289 s32 err = BCME_OK;
9290 s32 bssidx = 0;
9291 u32 id;
9292 bool ack = false;
9293 s8 eabuf[ETHER_ADDR_STR_LEN];
9294
9295 WL_DBG(("Enter \n"));
9296
9297 if (len > ACTION_FRAME_SIZE) {
9298 WL_ERR(("bad length:%zu\n", len));
9299 return BCME_BADLEN;
9300 }
9301
9302 #ifdef DHD_IFDEBUG
9303 PRINT_WDEV_INFO(cfgdev);
9304 #endif /* DHD_IFDEBUG */
9305
9306 dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
9307
9308 if (!dev) {
9309 WL_ERR(("dev is NULL\n"));
9310 return -EINVAL;
9311 }
9312
9313 /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
9314 if (discover_cfgdev(cfgdev, cfg)) {
9315 if (!cfg->p2p_supported || !cfg->p2p) {
9316 WL_ERR(("P2P doesn't setup completed yet\n"));
9317 return -EINVAL;
9318 }
9319 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9320 }
9321 else {
9322 if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
9323 WL_ERR(("Failed to find bssidx\n"));
9324 return BCME_ERROR;
9325 }
9326 }
9327
9328 WL_DBG(("TX target bssidx=%d\n", bssidx));
9329
9330 if (p2p_is_on(cfg)) {
9331 /* Suspend P2P discovery search-listen to prevent it from changing the
9332 * channel.
9333 */
9334 if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9335 WL_ERR(("Can not disable discovery mode\n"));
9336 return -EFAULT;
9337 }
9338 }
9339 *cookie = 0;
9340 id = cfg->send_action_id++;
9341 if (id == 0)
9342 id = cfg->send_action_id++;
9343 *cookie = id;
9344 mgmt = (const struct ieee80211_mgmt *)buf;
9345 if (ieee80211_is_mgmt(mgmt->frame_control)) {
9346 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
9347 s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
9348 s32 ie_len = len - ie_offset;
9349 if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
9350 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
9351 }
9352 wl_cfg80211_set_mgmt_vndr_ies(cfg, cfgdev, bssidx,
9353 VNDR_IE_PRBRSP_FLAG, (const u8 *)(buf + ie_offset), ie_len);
9354 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9355 #if defined(P2P_IE_MISSING_FIX)
9356 if (!cfg->p2p_prb_noti) {
9357 cfg->p2p_prb_noti = true;
9358 WL_DBG(("wl_cfg80211_mgmt_tx: TX 802_1X Probe"
9359 " Response first time.\n"));
9360 }
9361 #endif
9362 goto exit;
9363 } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
9364 ieee80211_is_deauth(mgmt->frame_control)) {
9365 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
9366 sizeof(struct ether_addr) + sizeof(uint)] = {0};
9367 int num_associated = 0;
9368 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9369 if (!bcmp((const uint8 *)BSSID_BROADCAST,
9370 (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
9371 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9372 err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST,
9373 assoc_maclist, sizeof(mac_buf));
9374 if (err < 0)
9375 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9376 else
9377 num_associated = assoc_maclist->count;
9378 }
9379 memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
9380 scb_val.val = mgmt->u.disassoc.reason_code;
9381 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
9382 sizeof(scb_val_t));
9383 if (err < 0)
9384 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
9385 WL_ERR(("Disconnect STA : " MACDBG " scb_val.val %d\n",
9386 MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mgmt->da,
9387 eabuf)), scb_val.val));
9388
9389 /* WAR Wait for the deauth event to come,
9390 * supplicant will do the delete iface immediately
9391 * and we will have problem in sending
9392 * deauth frame if we delete the bss in firmware.
9393 * But we do not need additional delays for this WAR
9394 * during P2P connection.
9395 *
9396 * Supplicant call this function with BCAST after
9397 * delete all GC stations with each addr.
9398 * So, 400 ms delay can be called only once when GO disconnect all GC
9399 */
9400 if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
9401 wl_delay(400);
9402
9403 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
9404 goto exit;
9405
9406 } else if (ieee80211_is_action(mgmt->frame_control)) {
9407 /* Abort the dwell time of any previous off-channel
9408 * action frame that may be still in effect. Sending
9409 * off-channel action frames relies on the driver's
9410 * scan engine. If a previous off-channel action frame
9411 * tx is still in progress (including the dwell time),
9412 * then this new action frame will not be sent out.
9413 */
9414 /* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
9415 * And previous off-channel action frame must be ended before new af tx.
9416 */
9417 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9418 wl_cfgscan_cancel_scan(cfg);
9419 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9420 }
9421 #ifdef WL_CLIENT_SAE
9422 else if (ieee80211_is_auth(mgmt->frame_control)) {
9423 err = wl_cfg80211_mgmt_auth_tx(dev, cfgdev, cfg, buf, len,
9424 bssidx, cookie);
9425 goto exit;
9426 }
9427 #endif /* WL_CLIENT_SAE */
9428
9429 } else {
9430 WL_ERR(("Driver only allows MGMT packet type\n"));
9431 goto exit;
9432 }
9433
9434 af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
9435
9436 if (af_params == NULL)
9437 {
9438 WL_ERR(("unable to allocate frame\n"));
9439 return -ENOMEM;
9440 }
9441
9442 action_frame = &af_params->action_frame;
9443
9444 /* Add the packet Id */
9445 action_frame->packetId = *cookie;
9446 WL_DBG(("action frame %d\n", action_frame->packetId));
9447 /* Add BSSID */
9448 memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
9449 memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
9450
9451 /* Add the length exepted for 802.11 header */
9452 action_frame->len = len - DOT11_MGMT_HDR_LEN;
9453 WL_DBG(("action_frame->len: %d\n", action_frame->len));
9454
9455 if (channel) {
9456 /* Add the channel */
9457 af_params->channel =
9458 wl_freq_to_chanspec(channel->center_freq);
9459 } else {
9460 af_params->channel = 0;
9461 }
9462
9463 /* Save listen_chan for searching common channel */
9464 cfg->afx_hdl->peer_listen_chan = af_params->channel;
9465 WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
9466
9467 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9468 af_params->dwell_time = params->wait;
9469 #else
9470 af_params->dwell_time = wait;
9471 #endif
9472
9473 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
9474
9475 ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params,
9476 action_frame, action_frame->len, bssidx);
9477 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
9478 WL_DBG(("txstatus notified for cookie:%llu. ack:%d\n", *cookie, ack));
9479
9480 MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
9481 exit:
9482 return err;
9483 }
9484
9485 static void
wl_cfg80211_mgmt_frame_register(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u16 frame,bool reg)9486 wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
9487 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9488 u16 frame, bool reg)
9489 #else
9490 struct mgmt_frame_regs *upd)
9491 #endif
9492 {
9493
9494 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
9495 WL_DBG(("frame_type: %x, reg: %d\n", frame, reg));
9496
9497 if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
9498 return;
9499 #endif
9500
9501 return;
9502 }
9503
9504 static s32
wl_cfg80211_change_bss(struct wiphy * wiphy,struct net_device * dev,struct bss_parameters * params)9505 wl_cfg80211_change_bss(struct wiphy *wiphy,
9506 struct net_device *dev,
9507 struct bss_parameters *params)
9508 {
9509 s32 err = 0;
9510 s32 ap_isolate = 0;
9511 #ifdef PCIE_FULL_DONGLE
9512 s32 ifidx = DHD_BAD_IF;
9513 #endif
9514 #if defined(SUPPORT_HOSTAPD_BGN_MODE)
9515 s32 gmode = -1, nmode = -1;
9516 s32 gmode_prev = -1, nmode_prev = -1;
9517 #endif /* SUPPORT_HOSTAPD_BGN_MODE */
9518 #if defined(PCIE_FULL_DONGLE) || defined(SUPPORT_HOSTAPD_BGN_MODE)
9519 dhd_pub_t *dhd;
9520 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9521 dhd = (dhd_pub_t *)(cfg->pub);
9522 #if defined(WL_ENABLE_P2P_IF)
9523 if (cfg->p2p_net == dev)
9524 dev = bcmcfg_to_prmry_ndev(cfg);
9525 #endif
9526 #endif /* PCIE_FULL_DONGLE || SUPPORT_HOSTAPD_BGN_MODE */
9527
9528 if (params->use_cts_prot >= 0) {
9529 }
9530
9531 if (params->use_short_preamble >= 0) {
9532 }
9533
9534 if (params->use_short_slot_time >= 0) {
9535 }
9536
9537 if (params->basic_rates) {
9538 #if defined(SUPPORT_HOSTAPD_BGN_MODE)
9539 switch ((int)(params->basic_rates[params->basic_rates_len -1])) {
9540 case 22: /* B only , rate 11 */
9541 gmode = 0;
9542 nmode = 0;
9543 break;
9544 case 108: /* G only , rate 54 */
9545 gmode = 2;
9546 nmode = 0;
9547 break;
9548 default:
9549 gmode = -1;
9550 nmode = -1;
9551 break;
9552 }
9553 #endif /* SUPPORT_HOSTAPD_BGN_MODE */
9554 }
9555
9556 if (params->ap_isolate >= 0) {
9557 ap_isolate = params->ap_isolate;
9558 #ifdef PCIE_FULL_DONGLE
9559 ifidx = dhd_net2idx(dhd->info, dev);
9560
9561 if (ifidx != DHD_BAD_IF) {
9562 err = dhd_set_ap_isolate(dhd, ifidx, ap_isolate);
9563 } else {
9564 WL_ERR(("Failed to set ap_isolate\n"));
9565 }
9566 #else
9567 err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
9568 if (unlikely(err))
9569 {
9570 WL_ERR(("set ap_isolate Error (%d)\n", err));
9571 }
9572 #endif /* PCIE_FULL_DONGLE */
9573 }
9574
9575 if (params->ht_opmode >= 0) {
9576 #if defined(SUPPORT_HOSTAPD_BGN_MODE)
9577 nmode = 1;
9578 gmode = 1;
9579 } else {
9580 nmode = 0;
9581 #endif /* SUPPORT_HOSTAPD_BGN_MODE */
9582 }
9583
9584 #if defined(SUPPORT_HOSTAPD_BGN_MODE)
9585 err = wldev_iovar_getint(dev, "nmode", &nmode_prev);
9586 if (unlikely(err)) {
9587 WL_ERR(("error reading nmode (%d)\n", err));
9588 }
9589 if (nmode == nmode_prev) {
9590 nmode = -1;
9591 }
9592 err = wldev_ioctl_get(dev, WLC_GET_GMODE, &gmode_prev, sizeof(gmode_prev));
9593 if (unlikely(err)) {
9594 WL_ERR(("error reading gmode (%d)\n", err));
9595 }
9596 if (gmode == gmode_prev) {
9597 gmode = -1;
9598 }
9599
9600 if (((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) == DHD_FLAG_HOSTAP_MODE) &&
9601 ((gmode > -1) || (nmode > -1))) {
9602 s32 val = 0;
9603
9604 err = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
9605 if (unlikely(err))
9606 WL_ERR(("WLC_DOWN command failed:[%d]\n", err));
9607
9608 if (nmode > -1) {
9609 err = wldev_iovar_setint(dev, "nmode", nmode);
9610 if (unlikely(err))
9611 WL_ERR(("nmode command failed:mode[%d]:err[%d]\n", nmode, err));
9612 }
9613
9614 if (gmode > -1) {
9615 err = wldev_ioctl_set(dev, WLC_SET_GMODE, &gmode, sizeof(s32));
9616 if (unlikely(err))
9617 WL_ERR(("WLC_SET_GMODE command failed:mode[%d]:err[%d]\n",
9618 gmode, err));
9619 }
9620
9621 val = 0;
9622 err = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
9623 if (unlikely(err))
9624 WL_ERR(("WLC_UP command failed:err[%d]\n", err));
9625
9626 }
9627 #endif /* SUPPORT_HOSTAPD_BGN_MODE */
9628
9629 return err;
9630 }
9631
9632 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
9633 struct net_device *
wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 * cfg)9634 wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
9635 {
9636 struct net_info *_net_info, *next;
9637 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
9638 list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
9639 GCC_DIAGNOSTIC_POP();
9640 if (_net_info->ndev &&
9641 test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
9642 return _net_info->ndev;
9643 }
9644
9645 return NULL;
9646 }
9647 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9648
9649 bool
wl_cfg80211_macaddr_sync_reqd(struct net_device * dev)9650 wl_cfg80211_macaddr_sync_reqd(struct net_device *dev)
9651 {
9652 struct wireless_dev *wdev = dev->ieee80211_ptr;
9653 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
9654
9655 WL_DBG(("enter \n"));
9656 if (!wdev) {
9657 WL_ERR(("no wdev present\n"));
9658 return false;
9659 }
9660
9661 BCM_REFERENCE(cfg);
9662
9663 #if defined(WL_STATIC_IF)
9664 /* In soft case too role upgrade happens
9665 * from STA to AP in some cases.These
9666 * cases will have iftype as STATION.
9667 */
9668 if (IS_CFG80211_STATIC_IF(cfg, dev)) {
9669 WL_INFORM_MEM(("STATIC interface\n"));
9670 return true;
9671 }
9672 #endif /* WL_STATIC_IF && WL_SOFTAP_RAND */
9673
9674 switch (wdev->iftype) {
9675 #ifdef WL_P2P_RAND
9676 case NL80211_IFTYPE_P2P_GO:
9677 case NL80211_IFTYPE_P2P_CLIENT:
9678 WL_INFORM_MEM(("P2P GO/GC interface\n"));
9679 return true;
9680 #endif /* WL_P2P_RAND */
9681 #if defined(WL_STA_ASSOC_RAND)
9682 case NL80211_IFTYPE_STATION:
9683 WL_INFORM_MEM(("STA interface\n"));
9684 return true;
9685 #endif /* WL_STA_ASSOC_RAND */
9686 #ifdef WL_SOFTAP_RAND
9687 case NL80211_IFTYPE_AP:
9688 WL_INFORM_MEM(("SOFTAP interface\n"));
9689 return true;
9690 #endif /* WL_SOFTAP_RAND */
9691 default:
9692 WL_ERR(("no macthing if type\n"));
9693 }
9694 return false;
9695 }
9696
9697 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
9698 static s32
9699 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
wl_cfg80211_del_station(struct wiphy * wiphy,struct net_device * ndev,struct station_del_parameters * params)9700 wl_cfg80211_del_station(
9701 struct wiphy *wiphy, struct net_device *ndev,
9702 struct station_del_parameters *params)
9703 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
9704 wl_cfg80211_del_station(
9705 struct wiphy *wiphy,
9706 struct net_device *ndev,
9707 const u8* mac_addr)
9708 #else
9709 wl_cfg80211_del_station(
9710 struct wiphy *wiphy,
9711 struct net_device *ndev,
9712 u8* mac_addr)
9713 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9714 {
9715 struct net_device *dev;
9716 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9717 scb_val_t scb_val;
9718 int err;
9719 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
9720 sizeof(struct ether_addr) + sizeof(uint)] = {0};
9721 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
9722 int num_associated = 0;
9723
9724 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9725 const u8 *mac_addr = params->mac;
9726 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
9727 u16 rc = params->reason_code;
9728 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
9729 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9730
9731 WL_DBG(("Entry\n"));
9732 if (mac_addr == NULL) {
9733 WL_DBG(("mac_addr is NULL ignore it\n"));
9734 return 0;
9735 }
9736
9737 dev = ndev_to_wlc_ndev(ndev, cfg);
9738
9739 if (p2p_is_on(cfg)) {
9740 /* Suspend P2P discovery search-listen to prevent it from changing the
9741 * channel.
9742 */
9743 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
9744 WL_ERR(("Can not disable discovery mode\n"));
9745 return -EFAULT;
9746 }
9747 }
9748 #ifdef WL_EXT_IAPSTA
9749 err = wl_ext_in4way_sync(ndev, AP_WAIT_STA_RECONNECT,
9750 WL_EXT_STATUS_DELETE_STA, (void *)mac_addr);
9751 if (err) {
9752 return 0;
9753 }
9754 #endif
9755
9756 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
9757 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
9758 assoc_maclist, sizeof(mac_buf));
9759 if (err < 0)
9760 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
9761 else
9762 num_associated = assoc_maclist->count;
9763
9764 memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
9765 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
9766 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9767 if (rc == DOT11_RC_8021X_AUTH_FAIL) {
9768 WL_ERR(("deauth will be sent at F/W\n"));
9769 scb_val.val = DOT11_RC_8021X_AUTH_FAIL;
9770 } else {
9771 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9772 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
9773
9774 #ifdef WL_WPS_SYNC
9775 if (wl_wps_session_update(ndev,
9776 WPS_STATE_DISCONNECT_CLIENT, mac_addr) == BCME_UNSUPPORTED) {
9777 /* Ignore disconnect command from upper layer */
9778 WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
9779 } else
9780 #endif /* WL_WPS_SYNC */
9781 {
9782 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
9783 WL_MSG(dev->name, "Disconnect STA : %pM scb_val.val %d\n",
9784 mac_addr, scb_val.val);
9785 #if defined(BCMDONGLEHOST)
9786 /* need to guarantee EAP-Failure send out before deauth */
9787 dhd_wait_pend8021x(dev);
9788 #endif
9789 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
9790 sizeof(scb_val_t));
9791 if (err < 0) {
9792 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
9793 }
9794 }
9795 #ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
9796 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
9797 }
9798 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
9799 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
9800
9801 /* WAR Wait for the deauth event to come, supplicant will do the
9802 * delete iface immediately and we will have problem in sending
9803 * deauth frame if we delete the bss in firmware
9804 * But we do not need additional delays for this WAR
9805 * during P2P connection.
9806 *
9807 * Supplicant call this function with BCAST after doing
9808 * wl_cfg80211_del_station() all GC stations with each addr.
9809 * So, 400 ms delay can be called only once when GO disconnect all GC
9810 */
9811 if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
9812 wl_delay(400);
9813
9814 return 0;
9815 }
9816
9817 /* Implementation for post SCB authorize */
9818 static void
wl_cfg80211_post_scb_auth(struct bcm_cfg80211 * cfg,struct net_device * dev)9819 wl_cfg80211_post_scb_auth(struct bcm_cfg80211 *cfg, struct net_device *dev)
9820 {
9821 #ifdef WBTEXT
9822 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
9823 #endif /* WBTEXT */
9824
9825 LOG_TS(cfg, authorize_cmplt);
9826 CLR_TS(cfg, authorize_start);
9827 wl_set_drv_status(cfg, AUTHORIZED, dev);
9828 #ifdef DHD_LOSSLESS_ROAMING
9829 wl_del_roam_timeout(cfg);
9830 #endif
9831 #ifdef WBTEXT
9832 /* send nbr request or BTM query to update RCC
9833 * after 4-way handshake is completed
9834 */
9835 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
9836 dhdp->wbtext_support) {
9837 wl_cfg80211_wbtext_update_rcc(cfg, dev);
9838 }
9839 #endif /* WBTEXT */
9840 }
9841
9842 /* Currently adding support only for authorize/de-authorize flag
9843 * Need to be extended in future
9844 */
9845 static s32
9846 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
wl_cfg80211_change_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)9847 wl_cfg80211_change_station(
9848 struct wiphy *wiphy,
9849 struct net_device *dev,
9850 const u8 *mac,
9851 struct station_parameters *params)
9852 #else
9853 wl_cfg80211_change_station(
9854 struct wiphy *wiphy,
9855 struct net_device *dev,
9856 u8 *mac,
9857 struct station_parameters *params)
9858 #endif
9859 {
9860 int err = BCME_OK;
9861 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9862 #ifdef BCMSUP_4WAY_HANDSHAKE
9863 struct wl_security *sec;
9864 #endif /* BCMSUP_4WAY_HANDSHAKE */
9865 struct net_device *ndev = ndev_to_wlc_ndev(dev, cfg);
9866
9867 WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x "
9868 "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac),
9869 params->sta_flags_mask, params->sta_flags_set, ndev->name));
9870
9871 if ((wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS) &&
9872 !(wl_get_drv_status(cfg, CONNECTED, dev))) {
9873 /* Return error indicating not in connected state */
9874 WL_ERR(("Ignore SCB_AUTHORIZE/DEAUTHORIZE in non connected state\n"));
9875 return -ENOTSUPP;
9876 }
9877
9878 /* Processing only authorize/de-authorize flag for now */
9879 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
9880 WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
9881 return -ENOTSUPP;
9882 }
9883
9884 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
9885 err = wldev_ioctl_set(ndev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN);
9886 if (unlikely(err)) {
9887 WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
9888 } else {
9889 WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG "\n",
9890 ndev->name, MAC2STRDBG(mac)));
9891 }
9892 wl_clr_drv_status(cfg, AUTHORIZED, dev);
9893 CLR_TS(cfg, authorize_start);
9894 CLR_TS(cfg, conn_start);
9895 return err;
9896 }
9897 /* In case of 4way HS offloaded to FW and key_mgmt being 8021x, even the SCB
9898 * authorization is also offloaded to FW. So on reception of SCB authorize in the above
9899 * cases we avoid explicit call to ioctl WLC_SCB_AUTHORIZE. The post SCB authorize
9900 * actions are done from context of WLC_E_PSK_SUP event handler
9901 */
9902 #ifdef BCMSUP_4WAY_HANDSHAKE
9903 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
9904 if (
9905 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
9906 (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X)) &&
9907 #else
9908 (cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) &&
9909 #endif
9910 ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
9911 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X))) {
9912 return BCME_OK;
9913 }
9914 #endif /* BCMSUP_4WAY_HANDSHAKE */
9915 err = wldev_ioctl_set(ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN);
9916 if (unlikely(err)) {
9917 WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
9918 } else {
9919 WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG "\n",
9920 ndev->name, MAC2STRDBG(mac)));
9921 #ifdef WL_WPS_SYNC
9922 wl_wps_session_update(ndev, WPS_STATE_AUTHORIZE, mac);
9923 #endif /* WL_WPS_SYNC */
9924 }
9925
9926 /* Post SCB authorize actions */
9927 wl_cfg80211_post_scb_auth(cfg, ndev);
9928
9929 return err;
9930 }
9931 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
9932
9933 #ifdef WL_SUPPORT_ACS
9934 /*
9935 * Currently the dump_obss IOVAR is returning string as output so we need to
9936 * parse the output buffer in an unoptimized way. Going forward if we get the
9937 * IOVAR output in binary format this method can be optimized
9938 */
wl_parse_dump_obss(char * buf,struct wl_dump_survey * survey)9939 static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
9940 {
9941 int i;
9942 char *token;
9943 char delim[] = " \n";
9944
9945 token = strsep(&buf, delim);
9946 while (token != NULL) {
9947 if (!strcmp(token, "OBSS")) {
9948 for (i = 0; i < OBSS_TOKEN_IDX; i++)
9949 token = strsep(&buf, delim);
9950 survey->obss = simple_strtoul(token, NULL, 10);
9951 }
9952
9953 if (!strcmp(token, "IBSS")) {
9954 for (i = 0; i < IBSS_TOKEN_IDX; i++)
9955 token = strsep(&buf, delim);
9956 survey->ibss = simple_strtoul(token, NULL, 10);
9957 }
9958
9959 if (!strcmp(token, "TXDur")) {
9960 for (i = 0; i < TX_TOKEN_IDX; i++)
9961 token = strsep(&buf, delim);
9962 survey->tx = simple_strtoul(token, NULL, 10);
9963 }
9964
9965 if (!strcmp(token, "Category")) {
9966 for (i = 0; i < CTG_TOKEN_IDX; i++)
9967 token = strsep(&buf, delim);
9968 survey->no_ctg = simple_strtoul(token, NULL, 10);
9969 }
9970
9971 if (!strcmp(token, "Packet")) {
9972 for (i = 0; i < PKT_TOKEN_IDX; i++)
9973 token = strsep(&buf, delim);
9974 survey->no_pckt = simple_strtoul(token, NULL, 10);
9975 }
9976
9977 if (!strcmp(token, "Opp(time):")) {
9978 for (i = 0; i < IDLE_TOKEN_IDX; i++)
9979 token = strsep(&buf, delim);
9980 survey->idle = simple_strtoul(token, NULL, 10);
9981 }
9982
9983 token = strsep(&buf, delim);
9984 }
9985
9986 return 0;
9987 }
9988
wl_dump_obss(struct net_device * ndev,cca_msrmnt_query req,struct wl_dump_survey * survey)9989 static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
9990 struct wl_dump_survey *survey)
9991 {
9992 cca_stats_n_flags *results;
9993 char *buf;
9994 int retry, err;
9995 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
9996
9997 buf = (char *)MALLOCZ(cfg->osh, sizeof(char) * WLC_IOCTL_MAXLEN);
9998 if (unlikely(!buf)) {
9999 WL_ERR(("%s: buf alloc failed\n", __func__));
10000 return -ENOMEM;
10001 }
10002
10003 retry = IOCTL_RETRY_COUNT;
10004 while (retry--) {
10005 err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req),
10006 buf, WLC_IOCTL_MAXLEN, NULL);
10007 if (err >= 0) {
10008 break;
10009 }
10010 WL_DBG(("attempt = %d, err = %d, \n",
10011 (IOCTL_RETRY_COUNT - retry), err));
10012 }
10013
10014 if (retry <= 0) {
10015 WL_ERR(("failure, dump_obss IOVAR failed\n"));
10016 err = -EINVAL;
10017 goto exit;
10018 }
10019
10020 results = (cca_stats_n_flags *)(buf);
10021 wl_parse_dump_obss(results->buf, survey);
10022 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
10023
10024 return 0;
10025 exit:
10026 MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
10027 return err;
10028 }
10029
wl_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * ndev,int idx,struct survey_info * info)10030 static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
10031 int idx, struct survey_info *info)
10032 {
10033 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10034 struct wl_dump_survey *survey;
10035 struct ieee80211_supported_band *band;
10036 struct ieee80211_channel*chan;
10037 cca_msrmnt_query req;
10038 int val, err, noise, retry;
10039
10040 #ifdef BCMDONGLEHOST
10041 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10042 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
10043 return -ENOENT;
10044 }
10045 #endif
10046 band = wiphy->bands[IEEE80211_BAND_2GHZ];
10047 if (band && idx >= band->n_channels) {
10048 idx -= band->n_channels;
10049 band = NULL;
10050 }
10051
10052 if (!band || idx >= band->n_channels) {
10053 /* Move to 5G band */
10054 band = wiphy->bands[IEEE80211_BAND_5GHZ];
10055 if (idx >= band->n_channels) {
10056 return -ENOENT;
10057 }
10058 }
10059
10060 chan = &band->channels[idx];
10061 /* Setting current channel to the requested channel */
10062 if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan,
10063 NL80211_CHAN_HT20) < 0)) {
10064 /*
10065 * FIXME:
10066 *
10067 * Mostly set channel should not fail. because we are
10068 * traversing through Valid channel list. In case it fails,
10069 * right now we are passing the stats for previous channel.
10070 */
10071 WL_ERR(("Set channel failed \n"));
10072 }
10073
10074 if (!idx) {
10075 /* Set interface up, explicitly. */
10076 val = 1;
10077 err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
10078 if (err < 0) {
10079 WL_ERR(("set interface up failed, error = %d\n", err));
10080 }
10081 }
10082
10083 /* Get noise value */
10084 retry = IOCTL_RETRY_COUNT;
10085 while (retry--) {
10086 noise = 0;
10087 err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise,
10088 sizeof(noise));
10089 if (err >= 0) {
10090 break;
10091 }
10092 WL_DBG(("attempt = %d, err = %d, \n",
10093 (IOCTL_RETRY_COUNT - retry), err));
10094 }
10095
10096 if (retry <= 0) {
10097 WL_ERR(("Get Phy Noise failed, error = %d\n", err));
10098 noise = CHAN_NOISE_DUMMY;
10099 }
10100
10101 survey = (struct wl_dump_survey *)MALLOCZ(cfg->osh,
10102 sizeof(struct wl_dump_survey));
10103 if (unlikely(!survey)) {
10104 WL_ERR(("%s: alloc failed\n", __func__));
10105 return -ENOMEM;
10106 }
10107
10108 /* Start Measurement for obss stats on current channel */
10109 req.msrmnt_query = 0;
10110 req.time_req = ACS_MSRMNT_DELAY;
10111 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
10112 goto exit;
10113 }
10114
10115 /*
10116 * Wait for the meaurement to complete, adding a buffer value of 10 to take
10117 * into consideration any delay in IOVAR completion
10118 */
10119 msleep(ACS_MSRMNT_DELAY + 10);
10120
10121 /* Issue IOVAR to collect measurement results */
10122 req.msrmnt_query = 1;
10123 if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
10124 goto exit;
10125 }
10126
10127 info->channel = chan;
10128 info->noise = noise;
10129 info->channel_time = ACS_MSRMNT_DELAY;
10130 info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
10131 info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg +
10132 survey->no_pckt;
10133 info->channel_time_tx = survey->tx;
10134 info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
10135 SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
10136 SURVEY_INFO_CHANNEL_TIME_TX;
10137 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
10138
10139 return 0;
10140 exit:
10141 MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
10142 return err;
10143 }
10144 #endif /* WL_SUPPORT_ACS */
10145
10146 static struct cfg80211_ops wl_cfg80211_ops = {
10147 .add_virtual_intf = wl_cfg80211_add_virtual_iface,
10148 .del_virtual_intf = wl_cfg80211_del_virtual_iface,
10149 .change_virtual_intf = wl_cfg80211_change_virtual_iface,
10150 #if defined(WL_CFG80211_P2P_DEV_IF)
10151 .start_p2p_device = wl_cfgp2p_start_p2p_device,
10152 .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
10153 #endif /* WL_CFG80211_P2P_DEV_IF */
10154 .scan = wl_cfg80211_scan,
10155 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
10156 .abort_scan = wl_cfg80211_abort_scan,
10157 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
10158 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
10159 .join_ibss = wl_cfg80211_join_ibss,
10160 .leave_ibss = wl_cfg80211_leave_ibss,
10161 .get_station = wl_cfg80211_get_station,
10162 .dump_station = wl_cfg80211_dump_station,
10163 .set_tx_power = wl_cfg80211_set_tx_power,
10164 .get_tx_power = wl_cfg80211_get_tx_power,
10165 .add_key = wl_cfg80211_add_key,
10166 .del_key = wl_cfg80211_del_key,
10167 .get_key = wl_cfg80211_get_key,
10168 .set_default_key = wl_cfg80211_config_default_key,
10169 .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
10170 .set_power_mgmt = wl_cfg80211_set_power_mgmt,
10171 .connect = wl_cfg80211_connect,
10172 .disconnect = wl_cfg80211_disconnect,
10173 .set_pmksa = wl_cfg80211_set_pmksa,
10174 .del_pmksa = wl_cfg80211_del_pmksa,
10175 .flush_pmksa = wl_cfg80211_flush_pmksa,
10176 .remain_on_channel = wl_cfgscan_remain_on_channel,
10177 .cancel_remain_on_channel = wl_cfgscan_cancel_remain_on_channel,
10178 .mgmt_tx = wl_cfg80211_mgmt_tx,
10179 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0))
10180 .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
10181 #else
10182 .update_mgmt_frame_registrations = wl_cfg80211_mgmt_frame_register,
10183 #endif
10184 .change_bss = wl_cfg80211_change_bss,
10185 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || \
10186 defined(WL_COMPAT_WIRELESS)
10187 .set_channel = wl_cfg80211_set_channel,
10188 #endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
10189 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && \
10190 !defined(WL_COMPAT_WIRELESS)
10191 .set_beacon = wl_cfg80211_add_set_beacon,
10192 .add_beacon = wl_cfg80211_add_set_beacon,
10193 .del_beacon = wl_cfg80211_del_beacon,
10194 #else
10195 .change_beacon = wl_cfg80211_change_beacon,
10196 .start_ap = wl_cfg80211_start_ap,
10197 .stop_ap = wl_cfg80211_stop_ap,
10198 #endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
10199 #ifdef WL_SCHED_SCAN
10200 .sched_scan_start = wl_cfg80211_sched_scan_start,
10201 .sched_scan_stop = wl_cfg80211_sched_scan_stop,
10202 #endif /* WL_SCHED_SCAN */
10203 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
10204 .del_station = wl_cfg80211_del_station,
10205 .change_station = wl_cfg80211_change_station,
10206 .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
10207 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
10208 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \
10209 defined(WL_COMPAT_WIRELESS)
10210 .tdls_mgmt = wl_cfg80211_tdls_mgmt,
10211 .tdls_oper = wl_cfg80211_tdls_oper,
10212 #endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
10213 #ifdef WL_SUPPORT_ACS
10214 .dump_survey = wl_cfg80211_dump_survey,
10215 #endif /* WL_SUPPORT_ACS */
10216 #ifdef WL_CFG80211_ACL
10217 .set_mac_acl = wl_cfg80211_set_mac_acl,
10218 #endif /* WL_CFG80211_ACL */
10219 #ifdef GTK_OFFLOAD_SUPPORT
10220 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
10221 .set_rekey_data = wl_cfg80211_set_rekey_data,
10222 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
10223 #endif /* GTK_OFFLOAD_SUPPORT */
10224 #ifdef WL_CLIENT_SAE
10225 .external_auth = wl_cfg80211_external_auth,
10226 #endif /* WL_CLIENT_SAE */
10227 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
10228 /* This should be enabled from kernel version which supports this */
10229 .update_connect_params = wl_cfg80211_update_connect_params,
10230 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
10231 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
10232 .set_pmk = wl_cfg80211_set_pmk,
10233 .del_pmk = wl_cfg80211_del_pmk,
10234 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
10235 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
10236 .channel_switch = wl_cfg80211_channel_switch,
10237 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
10238 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
10239 #ifdef WLFBT
10240 .update_ft_ies = wl_cfg80211_update_ft_ies,
10241 #endif /* WLFBT */
10242 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */
10243 };
10244
wl_mode_to_nl80211_iftype(s32 mode)10245 s32 wl_mode_to_nl80211_iftype(s32 mode)
10246 {
10247 s32 err = 0;
10248
10249 switch (mode) {
10250 case WL_MODE_BSS:
10251 return NL80211_IFTYPE_STATION;
10252 case WL_MODE_IBSS:
10253 return NL80211_IFTYPE_ADHOC;
10254 case WL_MODE_AP:
10255 return NL80211_IFTYPE_AP;
10256 #ifdef WLMESH_CFG80211
10257 case WL_MODE_MESH:
10258 return NL80211_IFTYPE_MESH_POINT;
10259 #endif /* WLMESH_CFG80211 */
10260 default:
10261 return NL80211_IFTYPE_UNSPECIFIED;
10262 }
10263
10264 return err;
10265 }
10266
10267 static bool
wl_is_ccode_change_required(struct net_device * net,char * country_code,int revinfo)10268 wl_is_ccode_change_required(struct net_device *net,
10269 char *country_code, int revinfo)
10270 {
10271 s32 ret = BCME_OK;
10272 wl_country_t cspec = {{0}, 0, {0}};
10273 wl_country_t cur_cspec = {{0}, 0, {0}};
10274
10275 ret = wldev_iovar_getbuf(net, "country", NULL, 0, &cur_cspec,
10276 sizeof(cur_cspec), NULL);
10277 if (ret < 0) {
10278 WL_ERR(("get country code failed = %d\n", ret));
10279 return true;
10280 }
10281 /* If translation table is available, update cspec */
10282 cspec.rev = revinfo;
10283 strlcpy(cspec.country_abbrev, country_code, WL_CCODE_LEN + 1);
10284 strlcpy(cspec.ccode, country_code, WL_CCODE_LEN + 1);
10285 dhd_get_customized_country_code(net, cspec.country_abbrev, &cspec);
10286 if ((cur_cspec.rev == cspec.rev) &&
10287 (strncmp(cur_cspec.ccode, cspec.ccode, WL_CCODE_LEN) == 0) &&
10288 (strncmp(cur_cspec.country_abbrev, cspec.country_abbrev, WL_CCODE_LEN) == 0)) {
10289 WL_INFORM_MEM(("country code = %s/%d is already configured\n",
10290 country_code, revinfo));
10291 return false;
10292 }
10293 return true;
10294 }
10295
10296 void
wl_cfg80211_cleanup_connection(struct net_device * net,bool user_enforced)10297 wl_cfg80211_cleanup_connection(struct net_device *net, bool user_enforced)
10298 {
10299 s32 ret = BCME_OK;
10300 struct wireless_dev *wdev = ndev_to_wdev(net);
10301 struct wiphy *wiphy = wdev->wiphy;
10302 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10303 struct net_info *iter, *next;
10304 scb_val_t scbval;
10305
10306 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
10307 for_each_ndev(cfg, iter, next) {
10308 GCC_DIAGNOSTIC_POP();
10309 if (iter->ndev) {
10310 if (wl_get_drv_status(cfg, AP_CREATED, iter->ndev)) {
10311 memset(scbval.ea.octet, 0xff, ETHER_ADDR_LEN);
10312 scbval.val = DOT11_RC_DEAUTH_LEAVING;
10313 if ((ret = wldev_ioctl_set(iter->ndev,
10314 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
10315 &scbval, sizeof(scb_val_t))) != 0) {
10316 WL_ERR(("Failed to disconnect STAs %d\n", ret));
10317 }
10318
10319 } else if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
10320 if ((iter->ndev == net) && !user_enforced)
10321 continue;
10322 wl_cfg80211_disassoc(iter->ndev, WLAN_REASON_DEAUTH_LEAVING);
10323 } else {
10324 WL_INFORM(("Disconnected state. Interface clean "
10325 "up skipped for ifname:%s\n", iter->ndev->name));
10326 }
10327 }
10328 }
10329
10330 wl_cfgscan_cancel_scan(cfg);
10331
10332 /* Clean up NAN connection */
10333 #ifdef WL_NAN
10334 if (wl_cfgnan_is_enabled(cfg)) {
10335 mutex_lock(&cfg->if_sync);
10336 ret = wl_cfgnan_check_nan_disable_pending(cfg, true, true);
10337 mutex_unlock(&cfg->if_sync);
10338 if (ret != BCME_OK) {
10339 WL_ERR(("failed to disable nan, error[%d]\n", ret));
10340 }
10341 }
10342 #endif /* WL_NAN */
10343 }
10344
10345 s32
wl_cfg80211_set_country_code(struct net_device * net,char * country_code,bool notify,bool user_enforced,int revinfo)10346 wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
10347 bool notify, bool user_enforced, int revinfo)
10348 {
10349 s32 ret = BCME_OK;
10350 struct wireless_dev *wdev = ndev_to_wdev(net);
10351 struct wiphy *wiphy = wdev->wiphy;
10352 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10353 BCM_REFERENCE(cfg);
10354
10355 if (revinfo < 0) {
10356 WL_ERR(("country revinfo wrong : %d\n", revinfo));
10357 ret = BCME_BADARG;
10358 goto exit;
10359 }
10360
10361 if ((wl_is_ccode_change_required(net, country_code, revinfo) == false) &&
10362 !dhd_force_country_change(net)) {
10363 goto exit;
10364 }
10365
10366 wl_cfg80211_cleanup_connection(net, user_enforced);
10367
10368 ret = wldev_set_country(net, country_code,
10369 notify, revinfo);
10370 if (ret < 0) {
10371 WL_ERR(("set country Failed :%d\n", ret));
10372 goto exit;
10373 }
10374
10375 /* send up the hint so that upper layer apps
10376 * can refresh the channel
10377 * list
10378 */
10379 if (!IS_REGDOM_SELF_MANAGED(wiphy)) {
10380 regulatory_hint(wiphy, country_code);
10381 }
10382
10383 exit:
10384 return ret;
10385 }
10386
10387 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
10388 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
10389 #define WL_CFG80211_REG_NOTIFIER() static int wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
10390 #else
10391 #define WL_CFG80211_REG_NOTIFIER() static void wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
10392 #endif /* kernel version < 3.9.0 */
10393 #endif
10394
10395 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
WL_CFG80211_REG_NOTIFIER()10396 WL_CFG80211_REG_NOTIFIER()
10397 {
10398 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
10399 int ret = 0;
10400 int revinfo = -1;
10401
10402 if (!request || !cfg) {
10403 WL_ERR(("Invalid arg\n"));
10404 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
10405 return -EINVAL;
10406 #else
10407 return;
10408 #endif /* kernel version < 3.10.11 */
10409 }
10410
10411 WL_DBG(("ccode: %c%c Initiator: %d\n",
10412 request->alpha2[0], request->alpha2[1], request->initiator));
10413
10414 /* We support only REGDOM_SET_BY_USER as of now */
10415 if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
10416 (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
10417 WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
10418 request->initiator));
10419 /* in case of no supported country by regdb
10420 lets driver setup platform default Locale
10421 */
10422 }
10423
10424 WL_ERR(("Set country code %c%c from %s\n",
10425 request->alpha2[0], request->alpha2[1],
10426 ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User")));
10427 ret = wl_cfg80211_set_country_code(bcmcfg_to_prmry_ndev(cfg), request->alpha2, false,
10428 (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false),
10429 revinfo);
10430 if (ret < 0) {
10431 WL_ERR(("Set country failed ret:%d\n", ret));
10432 }
10433
10434 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 11))
10435 return ret;
10436 #else
10437 return;
10438 #endif /* kernel version < 3.10.11 */
10439 }
10440 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
10441
10442 #ifdef CONFIG_PM
10443 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
10444 static const struct wiphy_wowlan_support brcm_wowlan_support = {
10445 .flags = WIPHY_WOWLAN_ANY,
10446 .n_patterns = WL_WOWLAN_MAX_PATTERNS,
10447 .pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
10448 .pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
10449 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
10450 .max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
10451 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
10452 };
10453 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
10454 #endif /* CONFIG_PM */
10455
wl_features_set(u8 * array,uint8 len,u32 ftidx)10456 int wl_features_set(u8 *array, uint8 len, u32 ftidx)
10457 {
10458 u8* ft_byte;
10459
10460 if ((ftidx / 8u) >= len)
10461 return BCME_BADARG;
10462
10463 ft_byte = &array[ftidx / 8u];
10464 *ft_byte |= BIT(ftidx % 8u);
10465 return BCME_OK;
10466 }
10467
10468 static
wl_config_custom_regulatory(struct wiphy * wiphy)10469 void wl_config_custom_regulatory(struct wiphy *wiphy)
10470 {
10471
10472 #if defined(WL_SELF_MANAGED_REGDOM) && \
10473 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
10474 /* Use self managed regulatory domain */
10475 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED |
10476 REGULATORY_IGNORE_STALE_KICKOFF;
10477 wiphy->regd = &brcm_regdom;
10478 WL_DBG(("Self managed regdom\n"));
10479 return;
10480 #else /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
10481
10482 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
10483 wiphy->regulatory_flags |=
10484 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
10485 REGULATORY_IGNORE_STALE_KICKOFF |
10486 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) */
10487 REGULATORY_CUSTOM_REG;
10488 #else /* KERNEL VER >= 3.14 */
10489 wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
10490 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
10491 wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
10492 WL_DBG(("apply custom regulatory\n"));
10493 #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
10494 }
10495
wl_setup_wiphy(struct wireless_dev * wdev,struct device * sdiofunc_dev,dhd_pub_t * context)10496 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, dhd_pub_t *context)
10497 {
10498 s32 err = 0;
10499 #ifdef CONFIG_PM
10500 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
10501 struct cfg80211_wowlan *brcm_wowlan_config = NULL;
10502 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
10503 #endif /* CONFIG_PM */
10504
10505 //#if defined(BCMDONGLEHOST) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
10506 dhd_pub_t *dhd = (dhd_pub_t *)context;
10507 BCM_REFERENCE(dhd);
10508
10509 if (!dhd) {
10510 WL_ERR(("DHD is NULL!!"));
10511 err = -ENODEV;
10512 return err;
10513 }
10514 //#endif /* defined(BCMDONGLEHOST) && KERNEL >= 3, 4, 0 || defined(WL_COMPAT_WIRELESS)) */
10515
10516 wdev->wiphy =
10517 wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
10518 if (unlikely(!wdev->wiphy)) {
10519 WL_ERR(("Couldn not allocate wiphy device\n"));
10520 err = -ENOMEM;
10521 return err;
10522 }
10523 set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
10524 wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
10525 /* Report how many SSIDs Driver can support per Scan request */
10526 wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
10527 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
10528 #ifdef WL_SCHED_SCAN
10529 wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
10530 wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
10531 wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
10532 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
10533 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
10534 #else
10535 wdev->wiphy->max_sched_scan_reqs = 1;
10536 #endif /* LINUX_VER < 4.12 */
10537 #endif /* WL_SCHED_SCAN */
10538 #ifdef WLMESH_CFG80211
10539 wdev->wiphy->flags |= WIPHY_FLAG_MESH_AUTH;
10540 #endif /* WLMESH_CFG80211 */
10541 wdev->wiphy->interface_modes =
10542 BIT(NL80211_IFTYPE_STATION)
10543 | BIT(NL80211_IFTYPE_ADHOC)
10544 #if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
10545 /*
10546 * This monitor mode support creates an issue in registering
10547 * Action frame for P2P-GO, this was leading an error in receiving
10548 * action frames to GO interface.Keeping the code here because
10549 * monitor mode code has kept as it is in other modules,
10550 * though we are not supporting this mode.
10551 */
10552 | BIT(NL80211_IFTYPE_MONITOR)
10553 #endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
10554 #if defined(WL_IFACE_COMB_NUM_CHANNELS) || \
10555 defined(WL_CFG80211_P2P_DEV_IF)
10556 | BIT(NL80211_IFTYPE_P2P_CLIENT)
10557 | BIT(NL80211_IFTYPE_P2P_GO)
10558 #endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
10559 #if defined(WL_CFG80211_P2P_DEV_IF)
10560 | BIT(NL80211_IFTYPE_P2P_DEVICE)
10561 #endif /* WL_CFG80211_P2P_DEV_IF */
10562 #ifdef WLMESH_CFG80211
10563 | BIT(NL80211_IFTYPE_MESH_POINT)
10564 #endif /* WLMESH_CFG80211 */
10565 | BIT(NL80211_IFTYPE_AP);
10566
10567 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
10568 (defined(WL_IFACE_COMB_NUM_CHANNELS) || \
10569 defined(WL_CFG80211_P2P_DEV_IF))
10570 WL_DBG(("Setting interface combinations for common mode\n"));
10571 wdev->wiphy->iface_combinations = common_iface_combinations;
10572 wdev->wiphy->n_iface_combinations =
10573 ARRAY_SIZE(common_iface_combinations);
10574 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
10575
10576 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
10577
10578 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
10579 wdev->wiphy->cipher_suites = __wl_cipher_suites;
10580 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
10581 wdev->wiphy->max_remain_on_channel_duration = 5000;
10582 wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
10583 #ifndef WL_POWERSAVE_DISABLED
10584 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
10585 #else
10586 wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
10587 #endif /* !WL_POWERSAVE_DISABLED */
10588 wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
10589 WIPHY_FLAG_4ADDR_AP |
10590 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && \
10591 !defined(WL_COMPAT_WIRELESS)
10592 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
10593 #endif
10594 WIPHY_FLAG_4ADDR_STATION;
10595 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
10596 /*
10597 * If FW ROAM flag is advertised, upper layer doesn't provide the
10598 * bssid & freq in the connect command. However, kernel ver >= 3.15,
10599 * provides bssid_hint & freq_hint which can be used by the firmware.
10600 * fw_ap_select variable determines whether FW selects the AP or the
10601 * user space selects the target AP within the given ESS.
10602 */
10603 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
10604 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
10605 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
10606 defined(WL_COMPAT_WIRELESS)
10607 /* this flag should be added to support wpa_supplicant 1.0+ */
10608 wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
10609 WIPHY_FLAG_OFFCHAN_TX;
10610 #endif
10611 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
10612 /* From 3.4 kernel ownards AP_SME flag can be advertised
10613 * to remove the patch from supplicant
10614 */
10615 wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
10616
10617 #ifdef WL_CFG80211_ACL
10618 /* Configure ACL capabilities. */
10619 wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
10620 #endif
10621
10622 #if defined(BCMDONGLEHOST) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || \
10623 defined(WL_COMPAT_WIRELESS))
10624 /* Supplicant distinguish between the SoftAP mode and other
10625 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
10626 * response frame from Supplicant MR1 and Kernel 3.4.0 or
10627 * later version. To add Vendor specific IE into the
10628 * probe response frame in case of SoftAP mode,
10629 * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
10630 */
10631 if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
10632 wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
10633 wdev->wiphy->probe_resp_offload = 0;
10634 }
10635 #endif /* defined(BCMDONGLEHOST) && KERNEL >= 3, 4, 0 || defined(WL_COMPAT_WIRELESS)) */
10636 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
10637
10638 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || \
10639 defined(WL_COMPAT_WIRELESS)
10640 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
10641 #endif
10642
10643 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
10644 /*
10645 * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
10646 * disconnection of connected network before suspend. So a dummy wowlan
10647 * filter is configured for kernels linux-3.8 and above.
10648 */
10649
10650 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
10651 wdev->wiphy->wowlan = &brcm_wowlan_support;
10652 /* If this is not provided cfg stack will get disconnect
10653 * during suspend.
10654 * Note: wiphy->wowlan_config is freed by cfg80211 layer.
10655 * so use malloc instead of MALLOC(osh) to avoid false alarm.
10656 */
10657 brcm_wowlan_config = kmalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL);
10658 if (brcm_wowlan_config) {
10659 brcm_wowlan_config->disconnect = true;
10660 brcm_wowlan_config->gtk_rekey_failure = true;
10661 brcm_wowlan_config->eap_identity_req = true;
10662 brcm_wowlan_config->four_way_handshake = true;
10663 brcm_wowlan_config->patterns = NULL;
10664 brcm_wowlan_config->n_patterns = 0;
10665 brcm_wowlan_config->tcp = NULL;
10666 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
10667 brcm_wowlan_config->nd_config = NULL;
10668 #endif
10669 } else {
10670 WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
10671 " So wiphy->wowlan_config is set to NULL\n"));
10672 }
10673 wdev->wiphy->wowlan_config = brcm_wowlan_config;
10674 #else
10675 wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
10676 wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
10677 wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
10678 wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
10679 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
10680 wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
10681 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
10682 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
10683 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
10684
10685 WL_DBG(("Registering custom regulatory)\n"));
10686 wl_config_custom_regulatory(wdev->wiphy);
10687
10688 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
10689 WL_INFORM_MEM(("Registering Vendor80211\n"));
10690 err = wl_cfgvendor_attach(wdev->wiphy, dhd);
10691 if (unlikely(err < 0)) {
10692 WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
10693 }
10694 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
10695 #ifdef WL_FILS
10696 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
10697 #endif /* WL_FILS */
10698
10699 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
10700 wdev->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
10701 wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS;
10702 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */
10703
10704 /* Now we can register wiphy with cfg80211 module */
10705 err = wiphy_register(wdev->wiphy);
10706 if (unlikely(err < 0)) {
10707 WL_ERR(("Couldn not register wiphy device (%d)\n", err));
10708 wiphy_free(wdev->wiphy);
10709 }
10710
10711 #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
10712 (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
10713 /* Workaround for a cfg80211 bug */
10714 wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
10715 #endif
10716
10717 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN)
10718 wdev->wiphy->features |= (NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
10719 NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR);
10720 wdev->wiphy->max_sched_scan_plans = 1; /* multiple plans not supported */
10721 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) */
10722
10723 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
10724 if (wl_extsae_chip(dhd))
10725 wdev->wiphy->features |= NL80211_FEATURE_SAE;
10726 #endif /* WL_SAE || WL_CLIENT_SAE */
10727 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE)
10728 if (FW_SUPPORTED(dhd, idsup)) {
10729 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
10730 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
10731 }
10732 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) && defined(BCMSUP_4WAY_HANDSHAKE) */
10733 #ifdef WL_SCAN_TYPE
10734 /* These scan types will be mapped to default scan on non-supported chipset */
10735 /* Advertise scan type capability. */
10736 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_SPAN_SCAN);
10737 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_POWER_SCAN);
10738 wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
10739 wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN;
10740 #endif /* WL_SCAN_TYPE */
10741
10742 return err;
10743 }
10744
wl_free_wdev(struct bcm_cfg80211 * cfg)10745 static void wl_free_wdev(struct bcm_cfg80211 *cfg)
10746 {
10747 struct wireless_dev *wdev = cfg->wdev;
10748 struct wiphy *wiphy = NULL;
10749 if (!wdev) {
10750 WL_ERR(("wdev is invalid\n"));
10751 return;
10752 }
10753 if (wdev->wiphy) {
10754 wiphy = wdev->wiphy;
10755
10756 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
10757 wl_cfgvendor_detach(wdev->wiphy);
10758 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
10759 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
10760 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
10761 /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
10762 WL_DBG(("clear wowlan\n"));
10763 wdev->wiphy->wowlan = NULL;
10764 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
10765 #endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
10766 #if defined(WL_SELF_MANAGED_REGDOM) && \
10767 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
10768 /* Making regd ptr NULL, to avoid reference/freeing by regulatory unregister */
10769 wiphy->regd = NULL;
10770 #endif /* WL_SELF_MANAGED_REGDOM && KERNEL >= 4.0 */
10771 wiphy_unregister(wdev->wiphy);
10772 wdev->wiphy->dev.parent = NULL;
10773 wdev->wiphy = NULL;
10774 }
10775
10776 wl_delete_all_netinfo(cfg);
10777 if (wiphy) {
10778 if (wdev->netdev)
10779 wdev->netdev->ieee80211_ptr = NULL;
10780 wdev->netdev = NULL;
10781 MFREE(cfg->osh, wdev, sizeof(*wdev));
10782 cfg->wdev = NULL;
10783 wiphy_free(wiphy);
10784 }
10785
10786 /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
10787 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
10788 */
10789 }
10790
10791 static s32
wl_post_linkup_ops(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)10792 wl_post_linkup_ops(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
10793 {
10794 s32 ret = BCME_OK;
10795 int vndr_oui_num = 0;
10796 struct net_device *ndev = as->ndev;
10797 char vndr_oui[MAX_VNDR_OUI_STR_LEN] = {0, };
10798 #ifdef BCMDONGLEHOST
10799 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
10800 #endif /* BCMDONGLEHOST */
10801
10802 #ifdef WL_WPS_SYNC
10803 wl_wps_session_update(ndev, WPS_STATE_LINKUP, as->addr);
10804 #endif /** WL_WPS_SYNC */
10805
10806 if (IS_PRIMARY_NDEV(cfg, ndev)) {
10807 vndr_oui_num = wl_vndr_ies_get_vendor_oui(cfg,
10808 ndev, vndr_oui, ARRAY_SIZE(vndr_oui));
10809 if (vndr_oui_num > 0) {
10810 WL_INFORM_MEM(("[%s] vendor oui: %s\n",
10811 ndev->name, vndr_oui));
10812 }
10813 }
10814
10815 #ifdef ESCAN_CHANNEL_CACHE
10816 /* Update RCC list. FW clears RCC from join iovar context */
10817 update_roam_cache(cfg, ioctl_version);
10818 #endif /* ESCAN_CHANNEL_CACHE */
10819
10820 #ifdef BCMDONGLEHOST
10821 if (as->event_type == WLC_E_LINK) {
10822 /* Arm pkt logging timer */
10823 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_CONNECT);
10824 }
10825 #endif /* BCMDONGLEHOST */
10826 #ifdef WBTEXT
10827 if ((ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
10828 dhdp->wbtext_support && (as->event_type == WLC_E_SET_SSID)) {
10829 /* set wnm_keepalives_max_idle after association */
10830 wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
10831 }
10832 #endif /* WBTEXT */
10833
10834 #ifdef DHD_EVENT_LOG_FILTER
10835 dhd_event_log_filter_notify_connect_done(dhdp,
10836 as->addr, false);
10837 #endif /* DHD_EVENT_LOG_FILTER */
10838
10839 #ifdef CUSTOM_SET_OCLOFF
10840 if (dhdp->ocl_off) {
10841 int err = 0;
10842 int ocl_enable = 0;
10843 err = wldev_iovar_setint(ndev, "ocl_enable", ocl_enable);
10844 if (err != 0) {
10845 WL_ERR(("[WIFI_SEC] Set ocl_enable %d"
10846 " failed %d\n",
10847 ocl_enable, err));
10848 } else {
10849 WL_ERR(("[WIFI_SEC] Set ocl_enable %d"
10850 " succeeded %d\n",
10851 ocl_enable, err));
10852 }
10853 }
10854 #endif /* CUSTOM_SET_OCLOFF */
10855 #ifdef CUSTOM_SET_ANTNPM
10856 if (dhdp->mimo_ant_set) {
10857 int err = 0;
10858
10859 WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhdp->mimo_ant_set));
10860 err = wldev_iovar_setint(ndev, "txchain", dhdp->mimo_ant_set);
10861 if (err != 0) {
10862 WL_ERR(("[WIFI_SEC] Fail set txchain. err:%d\n", err));
10863 }
10864 err = wldev_iovar_setint(ndev, "rxchain", dhdp->mimo_ant_set);
10865 if (err != 0) {
10866 WL_ERR(("[WIFI_SEC] Fail set rxchain. err:%d\n", err));
10867 }
10868 }
10869 #endif /* CUSTOM_SET_ANTNPM */
10870
10871 #if defined (ROAM_ENABLE) && defined (ROAM_AP_ENV_DETECTION)
10872 if (dhdp->roam_env_detection) {
10873 wldev_iovar_setint(ndev, "roam_env_detection",
10874 AP_ENV_INDETERMINATE);
10875 }
10876 #endif /* ROAM_AP_ENV_DETECTION */
10877
10878 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
10879 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
10880 init_completion(&cfg->iface_disable);
10881 #else
10882 /* reinitialize completion to clear previous count */
10883 INIT_COMPLETION(cfg->iface_disable);
10884 #endif
10885 }
10886
10887 #ifdef CUSTOM_SET_CPUCORE
10888 if (wl_get_chan_isvht80(ndev, dhdp)) {
10889 if (ndev == bcmcfg_to_prmry_ndev(cfg))
10890 dhdp->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
10891 else if (is_p2p_group_iface(ndev->ieee80211_ptr))
10892 dhdp->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
10893 dhd_set_cpucore(dhdp, TRUE);
10894 }
10895 #endif /* CUSTOM_SET_CPUCORE */
10896
10897 #ifdef CUSTOM_LONG_RETRY_LIMIT
10898 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
10899 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
10900 }
10901 #endif /* CUSTOM_LONG_RETRY_LIMIT */
10902
10903 #if defined(CONFIG_TIZEN)
10904 net_stat_tizen_update_wifi(ndev, WIFISTAT_CONNECTION);
10905 #endif /* CONFIG_TIZEN */
10906
10907 #ifdef WL_BAM
10908 {
10909 struct ether_addr eth = {{0}};
10910 (void)memcpy_s(ð.octet, ETH_ALEN, as->addr, ETH_ALEN);
10911 if (wl_adps_bad_ap_check(cfg, ð)) {
10912 if (wl_adps_enabled(cfg, ndev)) {
10913 wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
10914 }
10915 }
10916 }
10917 #endif /* WL_BAM */
10918
10919 #ifdef CONFIG_TCPACK_FASTTX
10920 if (wl_get_chan_isvht80(ndev, dhdp))
10921 wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
10922 else
10923 wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
10924 #endif /* CONFIG_TCPACK_FASTTX */
10925 return ret;
10926 }
10927
10928 #ifdef WL_SAE
10929 static s32
wl_cfg80211_event_sae_key(struct bcm_cfg80211 * cfg,struct net_device * ndev,wl_sae_key_info_t * sae_key)10930 wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg, struct net_device *ndev,
10931 wl_sae_key_info_t *sae_key)
10932 {
10933 struct sk_buff *skb;
10934 gfp_t kflags;
10935 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
10936 int err = BCME_OK;
10937 struct cfg80211_pmksa pmksa;
10938
10939 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
10940 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
10941 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
10942 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), BRCM_SAE_VENDOR_EVENT_BUF_LEN,
10943 BRCM_VENDOR_EVENT_SAE_KEY, kflags);
10944 #else
10945 skb = cfg80211_vendor_event_alloc(wiphy, BRCM_SAE_VENDOR_EVENT_BUF_LEN,
10946 BRCM_VENDOR_EVENT_SAE_KEY, kflags);
10947 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
10948 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
10949 if (!skb) {
10950 WL_ERR(("skb alloc failed"));
10951 err = BCME_NOMEM;
10952 goto done;
10953 }
10954
10955 WL_INFORM_MEM(("Received Sae Key event for "MACDBG" key length %x %x",
10956 MAC2STRDBG(sae_key->peer_mac), sae_key->pmk_len, sae_key->pmkid_len));
10957 nla_put(skb, BRCM_SAE_KEY_ATTR_PEER_MAC, ETHER_ADDR_LEN, sae_key->peer_mac);
10958 nla_put(skb, BRCM_SAE_KEY_ATTR_PMK, sae_key->pmk_len, sae_key->pmk);
10959 nla_put(skb, BRCM_SAE_KEY_ATTR_PMKID, sae_key->pmkid_len, sae_key->pmkid);
10960 cfg80211_vendor_event(skb, kflags);
10961 /* wpa_supplicant will manage the PMK and PMKID from here on..
10962 * Delete the PMK cache in firmware, if wlc_ver equals to MIN_PMKID_LIST_V3_FW_MAJOR
10963 * else ignore.
10964 * MIN_PMKID_LIST_V3_FW_MAJOR has two IOVAR's(pmklist_info and PMKDB).
10965 */
10966 if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V3_FW_MAJOR) {
10967 WL_INFORM_MEM(("Deleting the SAE PMK cache Info from firmware \n"));
10968 memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
10969 pmksa.bssid = sae_key->peer_mac;
10970 pmksa.pmkid = sae_key->pmkid;
10971 err = wl_cfg80211_update_pmksa(wiphy, ndev, &pmksa, FALSE);
10972 if (err != BCME_OK) {
10973 WL_ERR(("Failed to delete the SAE PMK cache Info from firmware %d\n", err));
10974 }
10975 }
10976 done:
10977 return err;
10978 }
10979
10980 static s32
wl_bss_handle_sae_auth_v1(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * event,void * data)10981 wl_bss_handle_sae_auth_v1(struct bcm_cfg80211 *cfg, struct net_device *ndev,
10982 const wl_event_msg_t *event, void *data)
10983 {
10984 int err = BCME_OK;
10985 wl_auth_event_t *auth_data;
10986 wl_sae_key_info_t sae_key;
10987 uint16 tlv_buf_len;
10988 auth_data = (wl_auth_event_t *)data;
10989
10990 tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V1;
10991
10992 /* check if PMK info present */
10993 sae_key.pmk = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
10994 WL_AUTH_PMK_TLV_ID, &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
10995 if (!sae_key.pmk || !sae_key.pmk_len) {
10996 WL_ERR(("Mandatory PMK info not present"));
10997 err = BCME_NOTFOUND;
10998 goto done;
10999 }
11000 /* check if PMKID info present */
11001 sae_key.pmkid = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11002 WL_AUTH_PMKID_TLV_ID, &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
11003 if (!sae_key.pmkid || !sae_key.pmkid_len) {
11004 WL_ERR(("Mandatory PMKID info not present\n"));
11005 err = BCME_NOTFOUND;
11006 goto done;
11007 }
11008 memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet, ETHER_ADDR_LEN);
11009 err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
11010 if (err) {
11011 WL_ERR(("Failed to event sae key info\n"));
11012 }
11013 done:
11014 return err;
11015 }
11016
11017 static s32
wl_bss_handle_sae_auth_v2(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * event,void * data)11018 wl_bss_handle_sae_auth_v2(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11019 const wl_event_msg_t *event, void *data)
11020 {
11021 int err = BCME_OK;
11022 wl_auth_event_t *auth_data;
11023 wl_sae_key_info_t sae_key;
11024 uint16 tlv_buf_len;
11025 uint8 ssid[DOT11_MAX_SSID_LEN];
11026 const uint8 *tmp_buf;
11027 uint16 ssid_len;
11028 uint16 type_len;
11029 uint32 type;
11030 pmkid_v3_t *t_pmkid = NULL;
11031
11032 auth_data = (wl_auth_event_t *)data;
11033
11034 tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V2;
11035
11036 /* check if PMK info present */
11037 sae_key.pmk = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11038 WL_AUTH_PMK_TLV_ID, &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
11039 if (!sae_key.pmk || !sae_key.pmk_len) {
11040 WL_ERR(("Mandatory PMK info not present"));
11041 err = BCME_NOTFOUND;
11042 goto done;
11043 }
11044 /* check if PMKID info present */
11045 sae_key.pmkid = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11046 WL_AUTH_PMKID_TLV_ID, &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
11047 if (!sae_key.pmkid || !sae_key.pmkid_len) {
11048 WL_ERR(("Mandatory PMKID info not present\n"));
11049 err = BCME_NOTFOUND;
11050 goto done;
11051 }
11052 (void)memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet, ETHER_ADDR_LEN);
11053
11054 tmp_buf = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11055 WL_AUTH_PMKID_TYPE_TLV_ID, &type_len, BCM_XTLV_OPTION_ALIGN32);
11056
11057 memcpy(&type, tmp_buf, MIN(type_len, sizeof(type)));
11058 if (type == WL_AUTH_PMKID_TYPE_SSID) {
11059 int idx;
11060 int idx2;
11061 pmkid_list_v3_t *spmk_list = &cfg->spmk_info_list->pmkids;
11062
11063 tmp_buf = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
11064 WL_AUTH_SSID_TLV_ID, &ssid_len, BCM_XTLV_OPTION_ALIGN32);
11065 if (tmp_buf == NULL) {
11066 return BCME_ERROR;
11067 }
11068 bzero(ssid, sizeof(ssid));
11069 (void)memcpy_s(ssid, sizeof(ssid), tmp_buf, MIN(sizeof(ssid), ssid_len));
11070 for (idx = 0; idx < spmk_list->count; idx++) {
11071 t_pmkid = &spmk_list->pmkid[idx];
11072 if (ssid_len == t_pmkid->ssid_len &&
11073 !memcmp(ssid, t_pmkid->ssid, MIN(sizeof(ssid), ssid_len))) {
11074 break;
11075 }
11076 }
11077 if (idx >= spmk_list->count) {
11078 if (spmk_list->count == MAXPMKID) {
11079 /* remove oldest PMK info */
11080 for (idx2 = 0; idx2 < spmk_list->count - 1; idx2++) {
11081 (void)memcpy_s(&spmk_list->pmkid[idx2], sizeof(pmkid_v3_t),
11082 &spmk_list->pmkid[idx2 + 1], sizeof(pmkid_v3_t));
11083 }
11084 t_pmkid = &spmk_list->pmkid[spmk_list->count - 1];
11085 } else {
11086 t_pmkid = &spmk_list->pmkid[spmk_list->count++];
11087 }
11088 }
11089 if (!t_pmkid) {
11090 WL_ERR(("SPMK TPMKID is null\n"));
11091 return BCME_NOTFOUND;
11092 }
11093 bzero(t_pmkid, sizeof(pmkid_v3_t));
11094 memcpy(&t_pmkid->bssid, event->addr.octet, 6);
11095 t_pmkid->ssid_len = ssid_len;
11096 err = memcpy_s(t_pmkid->ssid, sizeof(t_pmkid->ssid), ssid, ssid_len);
11097 if (err != BCME_OK) {
11098 goto done;
11099 }
11100 /* COPY but not used */
11101 t_pmkid->pmkid_len = sae_key.pmkid_len;
11102 memcpy(t_pmkid->pmkid, sae_key.pmkid, sae_key.pmkid_len);
11103 t_pmkid->pmk_len = sae_key.pmk_len;
11104 memcpy(t_pmkid->pmk, sae_key.pmk, sae_key.pmk_len);
11105 }
11106
11107 err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
11108 if (err) {
11109 WL_ERR(("Failed to event sae key info\n"));
11110 }
11111 done:
11112 return err;
11113 }
11114
11115 s32
wl_bss_handle_sae_auth(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * event,void * data)11116 wl_bss_handle_sae_auth(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11117 const wl_event_msg_t *event, void *data)
11118 {
11119 int err = BCME_OK;
11120 uint status = ntoh32(event->status);
11121 wl_auth_event_t *auth_data;
11122
11123 if (status == WLC_E_STATUS_SUCCESS) {
11124 auth_data = (wl_auth_event_t *)data;
11125 if (auth_data->version == WL_AUTH_EVENT_DATA_V1) {
11126 err = wl_bss_handle_sae_auth_v1(cfg, ndev, event, data);
11127 } else if (auth_data->version == WL_AUTH_EVENT_DATA_V2) {
11128 err = wl_bss_handle_sae_auth_v2(cfg, ndev, event, data);
11129 } else {
11130 WL_ERR(("unknown auth event data version %x\n",
11131 auth_data->version));
11132 err = BCME_VERSION;
11133 }
11134 }
11135 WL_INFORM_MEM(("SAE AUTH status:%d ret: %d\n", status, err));
11136 return err;
11137 }
11138 #endif /* WL_SAE */
11139
11140 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
11141 enum {
11142 BIGDATA_ASSOC_REJECT_NO_ACK = 1,
11143 BIGDATA_ASSOC_REJECT_FAIL = 2,
11144 BIGDATA_ASSOC_REJECT_UNSOLICITED = 3,
11145 BIGDATA_ASSOC_REJECT_TIMEOUT = 4,
11146 BIGDATA_ASSOC_REJECT_ABORT = 5,
11147 BIGDATA_ASSOC_REJECT_NO_NETWWORKS = 6,
11148 BIGDATA_ASSOC_REJECT_MAX = 50
11149 };
11150
wl_get_connect_failed_status(struct bcm_cfg80211 * cfg,const wl_event_msg_t * e)11151 int wl_get_connect_failed_status(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
11152 {
11153 u32 status = ntoh32(e->status);
11154
11155 cfg->assoc_reject_status = 0;
11156
11157 if (status != WLC_E_STATUS_SUCCESS) {
11158 WL_INFORM(("auth assoc status event=%d e->status %d e->reason %d \n",
11159 ntoh32(cfg->event_auth_assoc.event_type),
11160 (int)ntoh32(cfg->event_auth_assoc.status),
11161 (int)ntoh32(cfg->event_auth_assoc.reason)));
11162
11163 /* Populate status based on cached auth/assoc status value */
11164 switch ((int)ntoh32(cfg->event_auth_assoc.status)) {
11165 case WLC_E_STATUS_NO_ACK:
11166 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_NO_ACK;
11167 break;
11168 case WLC_E_STATUS_FAIL:
11169 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_FAIL;
11170 break;
11171 case WLC_E_STATUS_UNSOLICITED:
11172 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_UNSOLICITED;
11173 break;
11174 case WLC_E_STATUS_TIMEOUT:
11175 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_TIMEOUT;
11176 break;
11177 case WLC_E_STATUS_ABORT:
11178 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_ABORT;
11179 break;
11180 case WLC_E_STATUS_SUCCESS:
11181 if (status == WLC_E_STATUS_NO_NETWORKS) {
11182 cfg->assoc_reject_status =
11183 BIGDATA_ASSOC_REJECT_NO_NETWWORKS;
11184 break;
11185 }
11186 default:
11187 cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_MAX;
11188 break;
11189 }
11190 if (cfg->assoc_reject_status) {
11191 if (ntoh32(cfg->event_auth_assoc.event_type) == WLC_E_ASSOC) {
11192 cfg->assoc_reject_status += BIGDATA_ASSOC_REJECT_MAX;
11193 }
11194 }
11195 }
11196
11197 WL_INFORM_MEM(("assoc_reject_status %d \n", cfg->assoc_reject_status));
11198
11199 return 0;
11200 }
11201
wl_cfg80211_get_connect_failed_status(struct net_device * dev,char * cmd,int total_len)11202 s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len)
11203 {
11204 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11205 int bytes_written = 0;
11206
11207 if (cfg == NULL) {
11208 return -1;
11209 }
11210 bytes_written = snprintf(cmd, total_len, "assoc_reject.status %d",
11211 cfg->assoc_reject_status);
11212 WL_ERR(("cmd: %s \n", cmd));
11213 return bytes_written;
11214 }
11215 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
11216
11217 static s32
wl_notify_connect_status_ibss(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)11218 wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11219 const wl_event_msg_t *e, void *data)
11220 {
11221 s32 err = 0;
11222 u32 event = ntoh32(e->event_type);
11223 u16 flags = ntoh16(e->flags);
11224 u32 status = ntoh32(e->status);
11225 bool active;
11226 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11227 struct ieee80211_channel *channel = NULL;
11228 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
11229 chanspec_t chanspec;
11230 u32 freq;
11231 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
11232
11233 if (event == WLC_E_JOIN) {
11234 WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev->name));
11235 }
11236 if (event == WLC_E_START) {
11237 WL_INFORM_MEM(("[%s] started IBSS network\n", ndev->name));
11238 }
11239 if (event == WLC_E_JOIN || event == WLC_E_START ||
11240 (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
11241 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11242 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
11243 if (unlikely(err)) {
11244 WL_ERR(("Could not get chanspec %d\n", err));
11245 return err;
11246 }
11247 chanspec = wl_chspec_driver_to_host(chanspec);
11248 freq = wl_channel_to_frequency(wf_chspec_ctlchan(chanspec), CHSPEC_BAND(chanspec));
11249 channel = ieee80211_get_channel(wiphy, freq);
11250 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
11251 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
11252 /* ROAM or Redundant */
11253 u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
11254 if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
11255 WL_DBG(("IBSS connected event from same BSSID("
11256 MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
11257 return err;
11258 }
11259 WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
11260 ndev->name, MAC2STRDBG(cur_bssid),
11261 MAC2STRDBG((const u8 *)&e->addr)));
11262 wl_get_assoc_ies(cfg, ndev);
11263 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
11264 wl_update_bss_info(cfg, ndev, false);
11265 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11266 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
11267 #else
11268 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
11269 #endif
11270 }
11271 else {
11272 /* New connection */
11273 WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG "\n",
11274 ndev->name, MAC2STRDBG((const u8 *)&e->addr)));
11275 wl_link_up(cfg);
11276 wl_get_assoc_ies(cfg, ndev);
11277 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
11278 wl_update_bss_info(cfg, ndev, false);
11279 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
11280 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
11281 #else
11282 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
11283 #endif
11284 wl_set_drv_status(cfg, CONNECTED, ndev);
11285 active = true;
11286 wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
11287 }
11288 } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
11289 event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
11290 wl_clr_drv_status(cfg, CONNECTED, ndev);
11291 wl_link_down(cfg);
11292 wl_init_prof(cfg, ndev);
11293 }
11294 else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
11295 WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
11296 }
11297 else {
11298 WL_DBG(("no action (IBSS mode)\n"));
11299 }
11300 return err;
11301 }
11302
11303 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
11304 #define WiFiALL_OUI "\x50\x6F\x9A" /* Wi-FiAll OUI */
11305 #define WiFiALL_OUI_LEN 3
11306 #define WiFiALL_OUI_TYPE 16
11307
11308 /* 11kv feature flag for big data */
11309 #define WL_BIGDATA_11KV_QBSSLOAD 0x00000001
11310 #define WL_BIGDATA_11KV_PROXYARP 0x00000002
11311 #define WL_BIGDATA_11KV_TFS 0x00000004
11312 #define WL_BIGDATA_11KV_SLEEP 0x00000008
11313 #define WL_BIGDATA_11KV_TIMBC 0x00000010
11314 #define WL_BIGDATA_11KV_BSSTRANS 0x00000020
11315 #define WL_BIGDATA_11KV_DMS 0x00000040
11316 #define WL_BIGDATA_11KV_LINK_MEA 0x00000080
11317 #define WL_BIGDATA_11KV_NBRREP 0x00000100
11318 #define WL_BIGDATA_11KV_BCNPASSIVE 0x00000200
11319 #define WL_BIGDATA_11KV_BCNACTIVE 0x00000400
11320 #define WL_BIGDATA_11KV_BCNTABLE 0x00000800
11321 #define WL_BIGDATA_11KV_BSSAAD 0x00001000
11322 #define WL_BIGDATA_11KV_MAX 0x00002000
11323
11324 #define WL_BIGDATA_SUPPORT_11K 0x00000001
11325 #define WL_BIGDATA_SUPPORT_11V 0x00000002
11326
11327 typedef struct {
11328 uint8 bitmap;
11329 uint8 octet_len;
11330 uint32 flag;
11331 } bigdata_11kv_t;
11332
11333 bigdata_11kv_t bigdata_11k_info[] = {
11334 {DOT11_RRM_CAP_LINK, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_LINK_MEA},
11335 {DOT11_RRM_CAP_NEIGHBOR_REPORT, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_NBRREP},
11336 {DOT11_RRM_CAP_BCN_PASSIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNPASSIVE},
11337 {DOT11_RRM_CAP_BCN_ACTIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNACTIVE},
11338 {DOT11_RRM_CAP_BCN_TABLE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNTABLE},
11339 {DOT11_RRM_CAP_BSSAAD, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BSSAAD},
11340 };
11341
11342 bigdata_11kv_t bigdata_11v_info[] = {
11343 {DOT11_EXT_CAP_PROXY_ARP, DOT11_EXTCAP_LEN_PROXY_ARP, WL_BIGDATA_11KV_PROXYARP},
11344 {DOT11_EXT_CAP_TFS, DOT11_EXTCAP_LEN_TFS, WL_BIGDATA_11KV_TFS},
11345 {DOT11_EXT_CAP_WNM_SLEEP, DOT11_EXTCAP_LEN_WNM_SLEEP, WL_BIGDATA_11KV_SLEEP},
11346 {DOT11_EXT_CAP_TIMBC, DOT11_EXTCAP_LEN_TIMBC, WL_BIGDATA_11KV_TIMBC},
11347 {DOT11_EXT_CAP_BSSTRANS_MGMT, DOT11_EXTCAP_LEN_BSSTRANS, WL_BIGDATA_11KV_BSSTRANS},
11348 {DOT11_EXT_CAP_DMS, DOT11_EXTCAP_LEN_DMS, WL_BIGDATA_11KV_DMS}
11349 };
11350
11351 static void
wl_get_11kv_info(u8 * ie,u32 ie_len,uint8 * support_11kv,uint32 * flag_11kv)11352 wl_get_11kv_info(u8 *ie, u32 ie_len, uint8 *support_11kv, uint32 *flag_11kv)
11353 {
11354 bcm_tlv_t *ie_11kv = NULL;
11355 uint32 flag_11k = 0, flag_11v = 0;
11356 int i;
11357
11358 /* parsing QBSS load ie */
11359 if ((bcm_parse_tlvs(ie, (u32)ie_len,
11360 DOT11_MNG_QBSS_LOAD_ID)) != NULL) {
11361 flag_11k |= WL_BIGDATA_11KV_QBSSLOAD;
11362 }
11363
11364 /* parsing RM IE for 11k */
11365 if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
11366 DOT11_MNG_RRM_CAP_ID)) != NULL) {
11367 for (i = 0; i < ARRAYSIZE(bigdata_11k_info); i++) {
11368 if ((ie_11kv->len >= bigdata_11k_info[i].octet_len) &&
11369 isset(ie_11kv->data, bigdata_11k_info[i].bitmap)) {
11370 flag_11k |= bigdata_11k_info[i].flag;
11371 }
11372 }
11373 }
11374
11375 /* parsing extended cap. IE for 11v */
11376 if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
11377 DOT11_MNG_EXT_CAP_ID)) != NULL) {
11378 for (i = 0; i < ARRAYSIZE(bigdata_11v_info); i++) {
11379 if ((ie_11kv->len >= bigdata_11v_info[i].octet_len) &&
11380 isset(ie_11kv->data, bigdata_11v_info[i].bitmap)) {
11381 flag_11v |= bigdata_11v_info[i].flag;
11382 }
11383 }
11384 }
11385
11386 if (flag_11k > 0) {
11387 *support_11kv |= WL_BIGDATA_SUPPORT_11K;
11388 }
11389
11390 if (flag_11v > 0) {
11391 *support_11kv |= WL_BIGDATA_SUPPORT_11V;
11392 }
11393
11394 *flag_11kv = flag_11k | flag_11v;
11395 }
11396
wl_get_bss_info(struct bcm_cfg80211 * cfg,struct net_device * dev,const u8 * mac)11397 int wl_get_bss_info(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *mac)
11398 {
11399 s32 err = 0;
11400 wl_bss_info_v109_1_t *bi;
11401 uint8 eabuf[ETHER_ADDR_LEN];
11402 u32 rate, channel, freq, supported_rate, nss = 0, mcs_map, mode_80211 = 0;
11403 char rate_str[4];
11404 u8 *ie = NULL;
11405 u32 ie_len;
11406 struct wiphy *wiphy;
11407 struct cfg80211_bss *bss;
11408 bcm_tlv_t *interworking_ie = NULL;
11409 bcm_tlv_t *tlv_ie = NULL;
11410 bcm_tlv_t *vht_ie = NULL;
11411 vndr_ie_t *vndrie;
11412 int16 ie_11u_rel_num = -1, ie_mu_mimo_cap = -1;
11413 u32 i, remained_len, count = 0;
11414 char roam_count_str[4], akm_str[4];
11415 s32 val = 0;
11416 uint8 support_11kv = 0;
11417 uint32 flag_11kv = 0; /* bit flags of 11kv big data */
11418 int cfg_bss_info_len = 0;
11419
11420 /* get BSS information */
11421
11422 strlcpy(cfg->bss_info, "x x x x x x x x x x x x x x x x x", sizeof(cfg->bss_info));
11423
11424 *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
11425
11426 err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, cfg->extra_buf, WL_EXTRA_BUF_MAX);
11427 if (unlikely(err)) {
11428 WL_ERR(("Could not get bss info %d\n", err));
11429 cfg->roam_count = 0;
11430 return -1;
11431 }
11432
11433 if (!mac) {
11434 WL_ERR(("mac is null \n"));
11435 cfg->roam_count = 0;
11436 return -1;
11437 }
11438
11439 memcpy(eabuf, mac, ETHER_ADDR_LEN);
11440
11441 bi = (wl_bss_info_v109_1_t *)(cfg->extra_buf + 4);
11442 channel = wf_chspec_ctlchan(bi->chanspec);
11443 freq = wl_channel_to_frequency(channel, CHSPEC_BAND(bi->chanspec));
11444 rate = 0;
11445 err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
11446 if (err) {
11447 WL_ERR(("Could not get rate (%d)\n", err));
11448 snprintf(rate_str, sizeof(rate_str), "x"); /* Unknown */
11449
11450 } else {
11451 rate = dtoh32(rate);
11452 snprintf(rate_str, sizeof(rate_str), "%d", (rate/2));
11453 }
11454
11455 /* supported maximum rate */
11456 supported_rate = (bi->rateset.rates[bi->rateset.count - 1] & 0x7f) / 2;
11457
11458 if (supported_rate < 12) {
11459 mode_80211 = BIGDATA_DOT11_11B_MODE; /* 11b maximum rate is 11Mbps. 11b mode */
11460 } else {
11461 /* It's not HT Capable case. */
11462 if (channel > 14) {
11463 mode_80211 = BIGDATA_DOT11_11A_MODE; /* 11a mode */
11464 } else {
11465 mode_80211 = BIGDATA_DOT11_11G_MODE; /* 11g mode */
11466 }
11467 }
11468
11469 if (bi->n_cap) {
11470 /* check Rx MCS Map for HT */
11471 nss = 0;
11472 mode_80211 = BIGDATA_DOT11_11N_MODE;
11473 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
11474 int8 bitmap = DOT11_HT_MCS_RATE_MASK;
11475 if (i == MAX_STREAMS_SUPPORTED-1) {
11476 bitmap = DOT11_RATE_MASK;
11477 }
11478 if (bi->basic_mcs[i] & bitmap) {
11479 nss++;
11480 }
11481 }
11482 }
11483
11484 if (bi->vht_cap) {
11485 nss = 0;
11486 mode_80211 = BIGDATA_DOT11_11AC_MODE;
11487 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
11488 mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
11489 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
11490 nss++;
11491 }
11492 }
11493 }
11494
11495 #if defined(WL11AX)
11496 if (bi->he_cap) {
11497 nss = 0;
11498 mode_80211 = BIGDATA_DOT11_11AX_MODE;
11499 for (i = 1; i <= HE_MCS_MAP_NSS_MAX; i++) {
11500 mcs_map = HE_MCS_NSS_GET_MCS(i, dtoh32(bi->he_rxmcsmap));
11501 if (mcs_map != HE_MCS_CODE_NONE) {
11502 nss++;
11503 }
11504 }
11505 }
11506 #endif /* WL11AX */
11507
11508 if (nss) {
11509 nss = nss - 1;
11510 }
11511
11512 wiphy = bcmcfg_to_wiphy(cfg);
11513 bss = CFG80211_GET_BSS(wiphy, NULL, eabuf, bi->SSID, bi->SSID_len);
11514 if (!bss) {
11515 WL_ERR(("Could not find the AP\n"));
11516 } else {
11517 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
11518 #if defined(WL_CFG80211_P2P_DEV_IF)
11519 ie = (u8 *)bss->ies->data;
11520 ie_len = bss->ies->len;
11521 #else
11522 ie = bss->information_elements;
11523 ie_len = bss->len_information_elements;
11524 #endif /* WL_CFG80211_P2P_DEV_IF */
11525 GCC_DIAGNOSTIC_POP();
11526 }
11527
11528 if (ie) {
11529 ie_mu_mimo_cap = 0;
11530 ie_11u_rel_num = 0;
11531
11532 if (bi->vht_cap) {
11533 if ((vht_ie = bcm_parse_tlvs(ie, ie_len,
11534 DOT11_MNG_VHT_CAP_ID)) != NULL) {
11535 if (vht_ie->len >= VHT_CAP_IE_LEN) {
11536 ie_mu_mimo_cap = (vht_ie->data[2] & 0x08) >> 3;
11537 }
11538 }
11539 }
11540
11541 if ((interworking_ie = bcm_parse_tlvs(ie, ie_len,
11542 DOT11_MNG_INTERWORKING_ID)) != NULL) {
11543 if ((tlv_ie = bcm_parse_tlvs(ie, ie_len, DOT11_MNG_VS_ID)) != NULL) {
11544 remained_len = ie_len;
11545
11546 while (tlv_ie) {
11547 if (count > MAX_VNDR_IE_NUMBER)
11548 break;
11549
11550 if (tlv_ie->id == DOT11_MNG_VS_ID) {
11551 vndrie = (vndr_ie_t *) tlv_ie;
11552
11553 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
11554 WL_ERR(("wl_get_bss_info: invalid vndr ie."
11555 "length is too small %d\n",
11556 vndrie->len));
11557 break;
11558 }
11559
11560 if (!bcmp(vndrie->oui,
11561 (u8*)WiFiALL_OUI, WiFiALL_OUI_LEN) &&
11562 (vndrie->data[0] == WiFiALL_OUI_TYPE))
11563 {
11564 WL_ERR(("Found Wi-FiAll OUI oui.\n"));
11565 ie_11u_rel_num = vndrie->data[1];
11566 ie_11u_rel_num = (ie_11u_rel_num & 0xf0)>>4;
11567 ie_11u_rel_num += 1;
11568
11569 break;
11570 }
11571 }
11572 count++;
11573 tlv_ie = bcm_next_tlv(tlv_ie, &remained_len);
11574 }
11575 }
11576 }
11577
11578 /* get 11kv information from ie of current bss */
11579 wl_get_11kv_info(ie, ie_len, &support_11kv, &flag_11kv);
11580 }
11581
11582 for (i = 0; i < bi->SSID_len; i++) {
11583 if (bi->SSID[i] == ' ') {
11584 bi->SSID[i] = '_';
11585 }
11586 }
11587
11588 /* 0 : None, 1 : OKC, 2 : FT, 3 : CCKM */
11589 err = wldev_iovar_getint(dev, "wpa_auth", &val);
11590 if (unlikely(err)) {
11591 WL_ERR(("could not get wpa_auth (%d)\n", err));
11592 snprintf(akm_str, sizeof(akm_str), "x"); /* Unknown */
11593 } else {
11594 WL_ERR(("wpa_auth val %d \n", val));
11595 if (val & WPA2_AUTH_FT) {
11596 snprintf(akm_str, sizeof(akm_str), "2");
11597 } else if (val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) {
11598 snprintf(akm_str, sizeof(akm_str), "1");
11599 } else {
11600 snprintf(akm_str, sizeof(akm_str), "0");
11601 }
11602 }
11603
11604 if (cfg->roam_offload) {
11605 snprintf(roam_count_str, sizeof(roam_count_str), "x"); /* Unknown */
11606 } else {
11607 snprintf(roam_count_str, sizeof(roam_count_str), "%d", cfg->roam_count);
11608 }
11609 cfg->roam_count = 0;
11610
11611 WL_ERR(("BSSID:" MACDBG " SSID %s \n", MAC2STRDBG(eabuf), "*****"));
11612 WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d,"
11613 "MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n"
11614 "akm:%s, roam:%s, 11kv:%d/%d \n",
11615 freq, wf_chspec_to_bw_str(bi->chanspec),
11616 dtoh32(bi->RSSI), (rate / 2), mode_80211, nss,
11617 ie_mu_mimo_cap, ie_11u_rel_num, bi->SNR, bi->phy_noise,
11618 akm_str, roam_count_str, support_11kv, flag_11kv));
11619
11620 if (ie) {
11621 snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
11622 MACOUI" %d %s %d %s %d %d %d %d %d %d %s %s %d %d",
11623 MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
11624 dtoh32(bi->RSSI), rate_str, mode_80211, nss, ie_mu_mimo_cap,
11625 ie_11u_rel_num, bi->SNR, bi->phy_noise, akm_str, roam_count_str,
11626 support_11kv, flag_11kv);
11627 } else {
11628 /* ie_mu_mimo_cap and ie_11u_rel_num is unknow. */
11629 snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
11630 MACOUI" %d %s %d %s %d %d x x %d %d %s %s x x",
11631 MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
11632 dtoh32(bi->RSSI), rate_str, mode_80211, nss, bi->SNR,
11633 bi->phy_noise, akm_str, roam_count_str);
11634 }
11635
11636 cfg_bss_info_len = strlen(cfg->bss_info);
11637 if (GET_BSS_INFO_LEN > cfg_bss_info_len) {
11638 uint16 full_cnt = 0, partial_cnt = 0;
11639 bool cnt_valid = FALSE;
11640
11641 #if defined(DHD_PUB_ROAM_EVT)
11642 wl_roam_stats_v1_t *roam_elem =
11643 (wl_roam_stats_v1_t *)dhd_get_roam_evt((dhd_pub_t *)cfg->pub);
11644
11645 if (roam_elem && roam_elem->version == WL_ROAM_STATS_VER_1) {
11646 wl_roam_stats_v1_t *roam_elem_v1;
11647 roam_elem_v1 = (wl_roam_stats_v1_t *)(uintptr_t)roam_elem;
11648
11649 cnt_valid = TRUE;
11650 full_cnt = roam_elem_v1->full_roam_scan_cnt;
11651 partial_cnt = roam_elem_v1->partial_roam_scan_cnt;
11652 }
11653 #endif /* DHD_PUB_ROAM_EVT */
11654 if (cnt_valid) {
11655 WL_ERR(("GET_BSS: full roam scan count:%d partial roam scan count:%d\n",
11656 full_cnt, partial_cnt));
11657 snprintf(&cfg->bss_info[cfg_bss_info_len],
11658 GET_BSS_INFO_LEN - cfg_bss_info_len, " %d %d",
11659 full_cnt, partial_cnt);
11660 } else {
11661 WL_ERR(("GET_BSS: roam scan count invalid\n"));
11662 snprintf(&cfg->bss_info[cfg_bss_info_len],
11663 GET_BSS_INFO_LEN - cfg_bss_info_len, " x x");
11664 }
11665 } else {
11666 WL_ERR(("Buffer to short to save roam info\n"));
11667 }
11668
11669 CFG80211_PUT_BSS(wiphy, bss);
11670
11671 return 0;
11672 }
11673
wl_cfg80211_get_bss_info(struct net_device * dev,char * cmd,int total_len)11674 s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len)
11675 {
11676 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11677
11678 if (cfg == NULL) {
11679 return -1;
11680 }
11681
11682 if (total_len < GET_BSS_INFO_LEN) {
11683 WL_ERR(("wl_cfg80211_get_bss_info: Buffer insuffient %d\n", total_len));
11684 return -1;
11685 }
11686
11687 bzero(cmd, total_len);
11688 memcpy(cmd, cfg->bss_info, GET_BSS_INFO_LEN);
11689
11690 WL_ERR_KERN(("cmd: %s \n", cmd));
11691
11692 return GET_BSS_INFO_LEN;
11693 }
11694 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
11695
wl_cfg80211_disassoc(struct net_device * ndev,uint32 reason)11696 void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason)
11697 {
11698 scb_val_t scbval;
11699 s32 err;
11700 #ifdef BCMDONGLEHOST
11701 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
11702 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11703
11704 BCM_REFERENCE(cfg);
11705 BCM_REFERENCE(dhdp);
11706 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
11707 dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
11708 #endif /* BCMDONGLEHOST */
11709
11710 memset_s(&scbval, sizeof(scb_val_t), 0x0, sizeof(scb_val_t));
11711 scbval.val = htod32(reason);
11712 err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
11713 if (err < 0) {
11714 WL_ERR(("WLC_DISASSOC error %d\n", err));
11715 } else {
11716 WL_INFORM_MEM(("wl disassoc. reason:%d\n", reason));
11717 }
11718 }
wl_cfg80211_del_all_sta(struct net_device * ndev,uint32 reason)11719 void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason)
11720 {
11721 struct net_device *dev;
11722 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
11723 scb_val_t scb_val;
11724 int err;
11725 char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
11726 sizeof(struct ether_addr) + sizeof(uint)] = {0};
11727 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
11728 int num_associated = 0;
11729
11730 dev = ndev_to_wlc_ndev(ndev, cfg);
11731
11732 if (p2p_is_on(cfg)) {
11733 /* Suspend P2P discovery search-listen to prevent it from changing the
11734 * channel.
11735 */
11736 if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
11737 WL_ERR(("Can not disable discovery mode\n"));
11738 return;
11739 }
11740 }
11741
11742 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
11743 err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
11744 assoc_maclist, sizeof(mac_buf));
11745 if (err < 0)
11746 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
11747 else
11748 num_associated = assoc_maclist->count;
11749
11750 memset(scb_val.ea.octet, 0xff, ETHER_ADDR_LEN);
11751 scb_val.val = DOT11_RC_DEAUTH_LEAVING;
11752 scb_val.val = htod32(reason);
11753 err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
11754 sizeof(scb_val_t));
11755 if (err < 0) {
11756 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
11757 }
11758
11759 /* WAR Wait for the deauth event to come, supplicant will do the
11760 * delete iface immediately and we will have problem in sending
11761 * deauth frame if we delete the bss in firmware
11762 * But we do not need additional delays for this WAR
11763 * during P2P connection.
11764 *
11765 * Supplicant call this function with BCAST after doing
11766 * wl_cfg80211_del_station() all GC stations with each addr.
11767 * So, 400 ms delay can be called only once when GO disconnect all GC
11768 */
11769 if (num_associated > 0)
11770 wl_delay(400);
11771
11772 return;
11773 }
11774 /* API to handle the Deauth from the AP.
11775 * For now we are deleting the PMKID cache in DHD/FW
11776 * in case of current connection is using SAE authnetication
11777 */
11778 static s32
wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)11779 wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
11780 {
11781 int err = BCME_OK;
11782 #ifdef WL_SAE
11783 struct net_device *ndev = as->ndev;
11784 const wl_event_msg_t *e = as->event_msg;
11785 uint8 bssid[ETHER_ADDR_LEN];
11786 struct cfg80211_pmksa pmksa;
11787 s32 val = 0;
11788 struct wlc_ssid *curssid;
11789 pmkid_list_v3_t *spmk_list = &cfg->spmk_info_list->pmkids;
11790 pmkid_v3_t *t_pmkid = NULL;
11791 int idx;
11792 bool bFound = FALSE;
11793 #endif /* WL_SAE */
11794
11795 if (as->reason > WLC_E_DEAUTH_MAX_REASON) {
11796 /* Specific AP send deauth by invalid reason.
11797 * If reason over 0x8XXX, framework trigger recovery.
11798 * Framework check HANG_REASON_MASK(0x8000) with reason.
11799 */
11800 WL_ERR(("Event %d original reason is %d, "
11801 "changed 0xFF\n", as->event_type, as->reason));
11802 as->reason = WLC_E_DEAUTH_MAX_REASON;
11803 }
11804 #ifdef WL_SAE
11805 err = wldev_iovar_getint(ndev, "wpa_auth", &val);
11806 if (unlikely(err)) {
11807 WL_ERR(("could not get wpa_auth (%d)\n", err));
11808 goto done;
11809 }
11810 if (val == WPA3_AUTH_SAE_PSK) {
11811 (void)memcpy_s(bssid, ETHER_ADDR_LEN,
11812 (const uint8*)&e->addr, ETHER_ADDR_LEN);
11813 memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
11814 pmksa.bssid = bssid;
11815 WL_INFORM_MEM(("Deleting the PMKSA for SAE AP "MACDBG,
11816 MAC2STRDBG(e->addr.octet)));
11817 wl_cfg80211_del_pmksa(cfg->wdev->wiphy, ndev, &pmksa);
11818 curssid = wl_read_prof(cfg, ndev, WL_PROF_SSID);
11819 for (idx = 0; idx < spmk_list->count; idx++) {
11820 t_pmkid = &spmk_list->pmkid[idx];
11821 if (curssid->SSID_len == t_pmkid->ssid_len &&
11822 !memcmp(curssid->SSID, t_pmkid->ssid, curssid->SSID_len)) {
11823 bFound = TRUE;
11824 break;
11825 }
11826 }
11827 if (!bFound) {
11828 goto done;
11829 }
11830 for (; idx < spmk_list->count - 1; idx++) {
11831 memcpy_s(&spmk_list->pmkid[idx], sizeof(pmkid_v3_t),
11832 &spmk_list->pmkid[idx + 1], sizeof(pmkid_v3_t));
11833 }
11834 spmk_list->count--;
11835 }
11836 done:
11837 #endif /* WL_SAE */
11838 return err;
11839 }
11840
11841 static void
wl_cache_assoc_resp_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)11842 wl_cache_assoc_resp_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev,
11843 const wl_event_msg_t *e, void *data)
11844 {
11845 struct wl_connect_info *conn_info = wl_to_conn(cfg);
11846 u32 datalen = ntoh32(e->datalen);
11847 u32 event_type = ntoh32(e->event_type);
11848
11849 if (data && datalen <= sizeof(conn_info->resp_ie)) {
11850 conn_info->resp_ie_len = datalen;
11851 WL_DBG((" assoc resp IES len = %d\n", conn_info->resp_ie_len));
11852 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
11853 (void)memcpy_s(conn_info->resp_ie, sizeof(conn_info->resp_ie),
11854 data, datalen);
11855
11856 WL_INFORM_MEM(("[%s] cached assoc resp ies"
11857 "event %d reason=%d ie_len=%d from " MACDBG "\n",
11858 ndev->name, event_type, ntoh32(e->reason), datalen,
11859 MAC2STRDBG((const u8*)(&e->addr))));
11860 }
11861 }
11862
11863 char *
wl_get_link_action_str(u16 link_action)11864 wl_get_link_action_str(u16 link_action)
11865 {
11866 switch (link_action) {
11867 case WL_LINK_NONE:
11868 return "LINK_NONE";
11869 case WL_LINK_ASSOC_FAIL:
11870 return "ASSOC_FAIL";
11871 case WL_LINK_ASSOC_DONE:
11872 return "ASSOC_DONE";
11873 case WL_LINK_DOWN:
11874 return "LINK_DOWN";
11875 case WL_LINK_ROAM_DONE:
11876 return "ROAM_DONE";
11877 case WL_LINK_FORCE_DEAUTH:
11878 return "SEND_DEAUTH";
11879 default:
11880 return "UNKOWN_STATE";
11881 }
11882 }
11883
11884 char *
wl_get_assoc_state_str(u16 assoc_state)11885 wl_get_assoc_state_str(u16 assoc_state)
11886 {
11887 switch (assoc_state) {
11888 case WL_STATE_ASSOC_IDLE:
11889 return "ASSOC_IDLE";
11890 case WL_STATE_ASSOCIATING:
11891 return "ASSOCIATING";
11892 case WL_STATE_ASSOCIATED:
11893 return "ASSOCIATED";
11894 default:
11895 return "UNKOWN_STATE";
11896 }
11897 }
11898
11899 static u32
wl_set_link_action(wl_assoc_state_t assoc_state,bool link_up)11900 wl_set_link_action(wl_assoc_state_t assoc_state, bool link_up)
11901 {
11902 wl_link_action_t action = WL_LINK_NONE;
11903
11904 switch (assoc_state) {
11905 case WL_STATE_ASSOCIATING:
11906 if (link_up) {
11907 action = WL_LINK_ASSOC_DONE;
11908 } else {
11909 action = WL_LINK_ASSOC_FAIL;
11910 }
11911 break;
11912 case WL_STATE_ASSOCIATED:
11913 if (link_up) {
11914 action = WL_LINK_ROAM_DONE;
11915 } else {
11916 action = WL_LINK_DOWN;
11917 }
11918 break;
11919 case WL_STATE_ASSOC_IDLE:
11920 if (link_up) {
11921 /* link up while cfg80211 state is not in
11922 * 'ASSOCIATING/ASSOCIATED. Sync up the fw
11923 * by disconnecting.
11924 */
11925 WL_ERR(("Unexpected link up\n"));
11926 action = WL_LINK_FORCE_DEAUTH;
11927 }
11928 break;
11929 default:
11930 WL_ERR(("unknown state:%d\n", assoc_state));
11931 action = WL_LINK_NONE;
11932 }
11933
11934 return action;
11935 }
11936
11937 static void
wl_cfg8021_unlink_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 * bssid)11938 wl_cfg8021_unlink_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 *bssid)
11939 {
11940 struct cfg80211_bss *bss;
11941 wlc_ssid_t *ssid;
11942 struct wireless_dev *wdev = ndev->ieee80211_ptr;
11943
11944 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
11945 if (ssid && bssid) {
11946 bss = CFG80211_GET_BSS(wdev->wiphy, NULL, bssid, ssid->SSID, ssid->SSID_len);
11947 if (bss) {
11948 cfg80211_unlink_bss(wdev->wiphy, bss);
11949 CFG80211_PUT_BSS(wdev->wiphy, bss);
11950 WL_INFORM_MEM(("bss unlinked"));
11951 }
11952 }
11953 }
11954
11955 static s32
wl_post_linkdown_ops(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as,struct net_device * ndev)11956 wl_post_linkdown_ops(struct bcm_cfg80211 *cfg,
11957 wl_assoc_status_t *as, struct net_device *ndev)
11958 {
11959 s32 ret = BCME_OK;
11960 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11961
11962 /* Common Code for connect failure & link down */
11963 BCM_REFERENCE(dhdp);
11964
11965 WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n",
11966 wl_get_drv_status(cfg, CONNECTING, ndev),
11967 wl_get_drv_status(cfg, CONNECTED, ndev),
11968 wl_get_drv_status(cfg, DISCONNECTING, ndev),
11969 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
11970
11971 /* clear timestamps on disconnect */
11972 CLR_TS(cfg, conn_start);
11973 CLR_TS(cfg, conn_cmplt);
11974 CLR_TS(cfg, authorize_start);
11975 CLR_TS(cfg, authorize_cmplt);
11976
11977 wl_link_down(cfg);
11978 wl_clr_drv_status(cfg, AUTHORIZED, ndev);
11979 wl_clr_drv_status(cfg, CONNECTED, ndev);
11980 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
11981
11982 #ifdef DBG_PKT_MON
11983 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
11984 /* Stop packet monitor */
11985 DHD_DBG_PKT_MON_STOP(dhdp);
11986 }
11987 #endif /* DHD_PKT_MON */
11988
11989 /* Flush preserve logs */
11990 wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
11991 FW_LOGSET_MASK_ALL);
11992
11993 #ifdef WL_GET_RCC
11994 wl_android_get_roam_scan_chanlist(cfg);
11995 #endif /* WL_GET_RCC */
11996
11997 #ifdef WES_SUPPORT
11998 if (cfg->ncho_mode) {
11999 /* Turn off NCHO mode */
12000 wl_android_set_ncho_mode(ndev, FALSE);
12001 }
12002 #endif /* WES_SUPPORT */
12003
12004 #ifdef WLTDLS
12005 wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
12006 #endif /* WLTDLS */
12007
12008 /* clear RSSI monitor, framework will set new cfg */
12009 #ifdef RSSI_MONITOR_SUPPORT
12010 dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
12011 FALSE, 0, 0);
12012 #endif /* RSSI_MONITOR_SUPPORT */
12013
12014 #ifdef WBTEXT
12015 wl_cfg80211_wbtext_reset_conf(cfg, as->ndev);
12016 #endif /* WBTEXT */
12017
12018 #ifdef P2PLISTEN_AP_SAMECHN
12019 if (as->ndev == bcmcfg_to_prmry_ndev(cfg)) {
12020 wl_cfg80211_set_p2p_resp_ap_chn(as->ndev, 0);
12021 cfg->p2p_resp_apchn_status = false;
12022 WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
12023 }
12024 #endif /* P2PLISTEN_AP_SAMECHN */
12025
12026 #ifdef WL_NAN
12027 if (wl_cfgnan_is_enabled(cfg)) {
12028 wl_cfgnan_get_stats(cfg);
12029 }
12030 #endif /* WL_NAN */
12031
12032 return ret;
12033 }
12034
12035 static s32
wl_handle_assoc_fail(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as,bool completed)12036 wl_handle_assoc_fail(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as, bool completed)
12037 {
12038 s32 ret = BCME_OK;
12039 struct net_device *ndev = as->ndev;
12040 u8 *connect_req_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
12041 #ifdef BCMDONGLEHOST
12042 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12043 #endif /* BCMDONGLEHOST */
12044
12045 #ifdef BCMDONGLEHOST
12046 BCM_REFERENCE(dhdp);
12047 #endif /* BCMDONGLEHOST */
12048 WL_INFORM_MEM(("event: %s\n", bcmevent_get_name(as->event_type)));
12049
12050 if (connect_req_bssid && !ETHER_ISNULLADDR(as->addr) &&
12051 memcmp(&as->addr, connect_req_bssid, ETH_ALEN) != 0) {
12052 WL_ERR(("Event:%d Wrong bssid:" MACDBG "\n", as->event_type, MAC2STRDBG(as->addr)));
12053 return BCME_OK;
12054 }
12055 #ifdef WL_EXT_IAPSTA
12056 wl_ext_iapsta_enable_master_if(ndev, FALSE);
12057 #endif
12058
12059 /* A connect request in Connected/Connecting will have the
12060 * NESTED_CONNECT state set.
12061 */
12062 if (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) &&
12063 wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
12064 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
12065 wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
12066 WL_INFORM_MEM(("Disconnect from nested connect context\n"));
12067 #ifdef WL_EXT_IAPSTA
12068 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
12069 WL_EXT_STATUS_DISCONNECTED, NULL);
12070 #endif
12071 return BCME_OK;
12072 }
12073
12074 #ifdef WL_WPS_SYNC
12075 if (wl_wps_session_update(ndev,
12076 WPS_STATE_CONNECT_FAIL, as->addr) == BCME_UNSUPPORTED) {
12077 /* Skip the event handling */
12078 return BCME_OK;
12079 }
12080 #endif /* WL_WPS_SYNC */
12081
12082 #ifdef BCMDONGLEHOST
12083 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
12084 dhd_net2idx(dhdp->info, ndev), 0);
12085 #endif /* BCMDONGLEHOST */
12086
12087 #if defined(CONFIG_TIZEN)
12088 net_stat_tizen_update_wifi(ndev, WIFISTAT_CONNECTION_FAIL);
12089 #endif /* CONFIG_TIZEN */
12090
12091 /* if link down, bsscfg is disabled */
12092 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
12093 complete(&cfg->iface_disable);
12094 }
12095
12096 /* Report connect result to upper layer */
12097 ret = wl_bss_connect_done(cfg, ndev, as->event_msg, as->data, false);
12098 if (unlikely(ret)) {
12099 WL_ERR(("connect result reporting failed.\n"));
12100 }
12101
12102 /* Issue WLC_DISASSOC to prevent FW roam attempts. Do not issue
12103 * WLC_DISASSOC again if the linkdown is generated due to local
12104 * disassoc, to avoid connect-disconnect loop.
12105 */
12106 if (!((as->event_type == WLC_E_LINK) && (as->reason == WLC_E_LINK_DISASSOC))) {
12107 wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
12108 }
12109
12110 /* Common handler for assoc fail/link down */
12111 wl_post_linkdown_ops(cfg, as, as->ndev);
12112
12113 return ret;
12114 }
12115
12116 s32
wl_get_connected_bssid(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 * mac_addr)12117 wl_get_connected_bssid(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 *mac_addr)
12118 {
12119 u8 bssid_dongle[ETH_ALEN] = {0};
12120 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
12121
12122 if (!mac_addr) {
12123 return -EINVAL;
12124 }
12125
12126 /* roam offload does not sync BSSID always, get it from dongle */
12127 if (cfg->roam_offload) {
12128 if (wldev_ioctl_get(ndev, WLC_GET_BSSID, bssid_dongle,
12129 sizeof(bssid_dongle)) == BCME_OK) {
12130 /* if not roam case, it would return null bssid */
12131 if (!ETHER_ISNULLADDR(bssid_dongle)) {
12132 curbssid = (u8 *)&bssid_dongle;
12133 }
12134 }
12135 }
12136
12137 if (curbssid) {
12138 (void)memcpy_s(mac_addr, ETH_ALEN, curbssid, ETH_ALEN);
12139 }
12140 return BCME_OK;
12141 }
12142
12143 #ifdef WBTEXT
12144 static void
wl_cfg80211_wbtext_reset_conf(struct bcm_cfg80211 * cfg,struct net_device * ndev)12145 wl_cfg80211_wbtext_reset_conf(struct bcm_cfg80211 *cfg, struct net_device *ndev)
12146 {
12147 #ifdef BCMDONGLEHOST
12148 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12149 s32 err;
12150
12151 /* when STA was disconnected, clear join pref and set wbtext */
12152 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
12153 dhdp->wbtext_policy
12154 == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) {
12155 char smbuf[WLC_IOCTL_SMLEN];
12156 if ((err = wldev_iovar_setbuf(ndev, "join_pref",
12157 NULL, 0, smbuf, sizeof(smbuf), NULL)) == BCME_OK) {
12158 if ((err = wldev_iovar_setint(ndev, "wnm_bsstrans_resp",
12159 dhdp->wbtext_policy)) == BCME_OK) {
12160 wl_cfg80211_wbtext_set_default(ndev);
12161 } else {
12162 WL_ERR(("Failed to set wbtext = %d\n", err));
12163 }
12164 } else {
12165 WL_ERR(("Failed to clear join pref = %d\n", err));
12166 }
12167 wl_cfg80211_wbtext_clear_bssid_list(cfg);
12168 } else {
12169 WL_ERR(("wbtext not applicable\n"));
12170 }
12171 #endif /* BCMDONGLEHOST */
12172 }
12173 #endif /* WBTEXT */
12174
12175 static s32
wl_handle_link_down(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)12176 wl_handle_link_down(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
12177 {
12178 s32 ret = BCME_OK;
12179 #if defined(BCMDONGLEHOST)
12180 dhd_pub_t *dhdp = (dhd_pub_t *)cfg->pub;
12181 #endif /* BCMDONGLEHOST */
12182 struct net_device *ndev = as->ndev;
12183 u32 datalen = as->data_len;
12184 u32 event = as->event_type;
12185 u8 *data = as->data;
12186 u8 *ie_ptr = NULL;
12187 u16 ie_len = 0;
12188 bool loc_gen = 0;
12189 u16 reason = as->reason;
12190
12191 #ifdef BCMDONGLEHOST
12192 BCM_REFERENCE(dhdp);
12193 #endif /* BCMDONGLEHOST */
12194 WL_MSG(ndev->name, "Link down Reason: %s\n", bcmevent_get_name(as->event_type));
12195 if ((BCME_OK != wl_get_connected_bssid(cfg, ndev, as->curbssid))) {
12196 WL_ERR(("bssid not found\n"));
12197 return -1;
12198 }
12199
12200 if (memcmp(as->curbssid, as->addr, ETHER_ADDR_LEN) != 0) {
12201 WL_ERR(("BSSID of event is not the connected BSSID"
12202 "(ignore it) cur: " MACDBG
12203 " event: " MACDBG"\n",
12204 MAC2STRDBG(as->curbssid),
12205 MAC2STRDBG((const u8*)(&as->addr))));
12206 return 0;
12207 }
12208
12209 /* A connect request in Connected/Connecting will have the
12210 * NESTED_CONNECT state set.
12211 */
12212 if (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) &&
12213 wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
12214 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
12215 wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
12216 WL_INFORM_MEM(("Disconnect from nested connect context\n"));
12217 #ifdef WL_EXT_IAPSTA
12218 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
12219 WL_EXT_STATUS_DISCONNECTED, NULL);
12220 wl_ext_iapsta_restart_master(ndev);
12221 #endif
12222 return 0;
12223 }
12224
12225 #ifdef WL_WPS_SYNC
12226 if (wl_wps_session_update(ndev,
12227 WPS_STATE_LINKDOWN, as->addr) == BCME_UNSUPPORTED) {
12228 /* Skip event handling */
12229 return 0;
12230 }
12231 #endif /* WL_WPS_SYNC */
12232
12233 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
12234 #ifdef BCMDONGLEHOST
12235 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
12236 dhd_net2idx(dhdp->info, ndev),
12237 WLAN_REASON_DEAUTH_LEAVING);
12238 #endif /* BCMDONGLEHOST */
12239 wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
12240 }
12241
12242 #ifdef BCMDONGLEHOST
12243 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_DONE),
12244 dhd_net2idx(dhdp->info, ndev), as->reason);
12245 #endif /* BCMDONGLEHOST */
12246
12247 #if defined(CONFIG_TIZEN)
12248 net_stat_tizen_update_wifi(ndev, WIFISTAT_CONNECTION_FAIL);
12249 #endif /* CONFIG_TIZEN */
12250
12251 #ifdef DHD_LOSSLESS_ROAMING
12252 wl_del_roam_timeout(cfg);
12253 #endif /* DHD_LOSSLESS_ROAMING */
12254 /*
12255 * FW sends body and body len as a part of deauth
12256 * and disassoc events (WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND)
12257 * The VIEs sits after reason code in the body. Reason code is
12258 * 2 bytes long.
12259 */
12260 WL_DBG(("recv disconnect ies ie_len = %d\n", ie_len));
12261 if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND) {
12262 if ((datalen > DOT11_DISCONNECT_RC) &&
12263 datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
12264 data) {
12265 ie_ptr = (uchar*)data + DOT11_DISCONNECT_RC;
12266 ie_len = datalen - DOT11_DISCONNECT_RC;
12267 }
12268 }
12269 #ifdef WL_ANALYTICS
12270 else if ((event == WLC_E_LINK) &&
12271 (reason == WLC_E_LINK_BCN_LOSS)) {
12272 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
12273 if (wl_vndr_ies_find_vendor_oui(cfg, ndev,
12274 CISCO_AIRONET_OUI)) {
12275 WL_INFORM_MEM(("Analytics Beacon loss\n"));
12276 ie_ptr = (uchar*)disco_bcnloss_vsie;
12277 ie_len = sizeof(disco_bcnloss_vsie);
12278 }
12279 }
12280 }
12281 #endif /* WL_ANALYTICS */
12282
12283 #ifdef BCMDONGLEHOST
12284 #if defined(DHDTCPSYNC_FLOOD_BLK) && defined(CUSTOMER_TCPSYNC_FLOOD_DIS_RC)
12285 {
12286 u32 ifidx = ntoh32(as->event_msg->ifidx);
12287 struct dhd_if *ifp = dhd_get_ifp(dhdp, ifidx);
12288 if (ifp && ifp->disconnect_tsync_flood) {
12289 reason = CUSTOMER_TCPSYNC_FLOOD_DIS_RC;
12290 }
12291 }
12292 #endif /* DHDTCPSYNC_FLOOD_BLK && CUSTOMER_TCPSYNC_FLOOD_DIS_RC */
12293 #endif /* BCMDONGLEHOST */
12294
12295 #ifdef DHD_ENABLE_BIGDATA_LOGGING
12296 wl_get_bss_info(cfg, ndev, as->addr);
12297 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
12298
12299 /* unlink from bss list - to force fresh add from next scan/connect */
12300 wl_cfg8021_unlink_bss(cfg, ndev, as->addr);
12301
12302 /* clear profile before reporting link down */
12303 wl_init_prof(cfg, ndev);
12304 #ifdef WL_EXT_IAPSTA
12305 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
12306 WL_EXT_STATUS_DISCONNECTED, NULL);
12307 wl_ext_iapsta_restart_master(ndev);
12308 #endif
12309
12310 CFG80211_DISCONNECTED(ndev, reason, ie_ptr, ie_len,
12311 loc_gen, GFP_KERNEL);
12312 WL_MSG(ndev->name, "Disconnect event sent to upper layer"
12313 "event:%d e->reason=%d reason=%d ie_len=%d "
12314 "from " MACDBG "\n",
12315 event, ntoh32(as->reason), reason, ie_len,
12316 MAC2STRDBG((const u8*)(&as->addr)));
12317
12318 /* clear connected state */
12319 wl_clr_drv_status(cfg, CONNECTED, ndev);
12320
12321 /* Common handler for assoc fail/link down */
12322 wl_post_linkdown_ops(cfg, as, as->ndev);
12323
12324 return ret;
12325 }
12326
12327 static s32
wl_handle_assoc_done(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)12328 wl_handle_assoc_done(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
12329 {
12330 s32 ret = BCME_OK;
12331 bool act = true;
12332 struct net_device *ndev = as->ndev;
12333
12334 wl_update_prof(cfg, ndev, as->event_msg, &act, WL_PROF_ACT);
12335
12336 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12337 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
12338 u8 *conn_req_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
12339 if (memcmp(curbssid, conn_req_bssid, ETHER_ADDR_LEN) == 0) {
12340 /* connected bssid and outstanding connect req bssid are same */
12341 WL_INFORM_MEM((" Connected event of connected device "
12342 "e=%d s=%d, ignore it\n",
12343 as->event_type, as->status));
12344 return ret;
12345 }
12346 }
12347
12348 /* Report connect result to cfg80211 layer */
12349 ret = wl_bss_connect_done(cfg, ndev, as->event_msg, as->data, true);
12350 if (unlikely(ret)) {
12351 WL_ERR(("Connect report failed!\n"));
12352 /* Sync with fw */
12353 wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
12354 ret = BCME_ERROR;
12355 goto exit;
12356 }
12357
12358 WL_DBG(("joined in BSS network \"%s\"\n",
12359 ((struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID));
12360 wl_update_prof(cfg, ndev, NULL, (const void *)&as->addr, WL_PROF_BSSID);
12361
12362 wl_link_up(cfg);
12363
12364 /* Handle feature specific handling on linkup event */
12365 ret = wl_post_linkup_ops(cfg, as);
12366
12367 exit:
12368 return ret;
12369 }
12370
12371 static s32
wl_handle_roam_done(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)12372 wl_handle_roam_done(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
12373 {
12374 s32 ret = BCME_OK;
12375 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12376
12377 if (cfg->roam_offload) {
12378 /* roam offload enabled, avoid roam events to wake up host */
12379 WL_ERR(("roamoffload enabled. Ignore event\n"));
12380 return ret;
12381 }
12382
12383 #ifdef DHD_EVENT_LOG_FILTER
12384 dhd_event_log_filter_notify_connect_done(dhdp,
12385 as->addr, true);
12386 #endif /* DHD_EVENT_LOG_FILTER */
12387
12388 #ifdef DHD_LOSSLESS_ROAMING
12389 {
12390 struct wl_security *sec = wl_read_prof(cfg,
12391 as->ndev, WL_PROF_SEC);
12392 if (!IS_AKM_SUITE_FT(sec)) {
12393 wl_bss_roaming_done(cfg, as->ndev, as->event_msg, as->data);
12394 }
12395 }
12396 #endif /* DHD_LOSSLESS_ROAMING */
12397
12398 /* Arm pkt logging timer */
12399 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
12400
12401 return ret;
12402 }
12403
12404 static s32
wl_handle_sta_link_action(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as)12405 wl_handle_sta_link_action(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as)
12406 {
12407 s32 ret = BCME_OK;
12408
12409 WL_INFORM_MEM(("assoc_state:%s link action:%s\n",
12410 wl_get_assoc_state_str(as->assoc_state),
12411 wl_get_link_action_str(as->link_action)));
12412
12413 switch (as->link_action) {
12414 case WL_LINK_ASSOC_DONE:
12415 ret = wl_handle_assoc_done(cfg, as);
12416 break;
12417 case WL_LINK_ASSOC_FAIL:
12418 ret = wl_handle_assoc_fail(cfg, as, FALSE);
12419 break;
12420 case WL_LINK_DOWN:
12421 ret = wl_handle_link_down(cfg, as);
12422 break;
12423 case WL_LINK_ROAM_DONE:
12424 ret = wl_handle_roam_done(cfg, as);
12425 break;
12426 case WL_LINK_FORCE_DEAUTH:
12427 wl_cfg80211_disassoc(as->ndev, WLAN_REASON_DEAUTH_LEAVING);
12428 break;
12429 default:
12430 WL_ERR(("Unsupported link state:%d\n", as->link_action));
12431 ret = -ENOTSUPP;
12432 }
12433
12434 if (unlikely(ret)) {
12435 WL_ERR(("link_action:%d handling failed\n", as->link_action));
12436 }
12437
12438 return ret;
12439 }
12440
12441 static s32
wl_handle_assoc_events(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const wl_event_msg_t * e,void * data,wl_assoc_state_t assoc_state)12442 wl_handle_assoc_events(struct bcm_cfg80211 *cfg,
12443 struct wireless_dev *wdev, const wl_event_msg_t *e,
12444 void *data, wl_assoc_state_t assoc_state)
12445 {
12446 s32 err = BCME_OK;
12447 wl_assoc_status_t as;
12448
12449 if (!wdev || !e) {
12450 WL_ERR(("wrong input\n"));
12451 return -EINVAL;
12452 }
12453
12454 bzero(&as, sizeof(wl_assoc_status_t));
12455 as.event_type = ntoh32(e->event_type);
12456 as.status = ntoh32(e->status);
12457 as.reason = ntoh32(e->reason);
12458 as.flags = ntoh16(e->flags);
12459 as.ndev = wdev->netdev;
12460 as.data = data;
12461 as.data_len = ntoh32(e->datalen);
12462 as.event_msg = e;
12463 (void)memcpy_s(as.addr, ETH_ALEN, e->addr.octet, ETH_ALEN);
12464
12465 WL_INFORM_MEM(("[%s] Mode BSS. assoc_state:%d event:%d "
12466 "status:%d reason:%d e_idx:%d " MACDBG "\n",
12467 as.ndev->name, as.assoc_state, as.event_type, as.status, as.reason,
12468 cfg->eidx.in_progress, MAC2STRDBG((const u8*)(&e->addr))));
12469
12470 /* Handle FW events */
12471 switch (as.event_type) {
12472 case WLC_E_AUTH:
12473 if (ntoh32(e->auth_type) == DOT11_SAE) {
12474 #ifdef WL_SAE
12475 wl_bss_handle_sae_auth(cfg, as.ndev, e, data);
12476 #endif /* WL_SAE */
12477
12478 #ifdef WL_CLIENT_SAE
12479 wl_handle_auth_event(cfg, as.ndev, e, data);
12480 #endif /* WL_CLIENT_SAE */
12481 }
12482
12483 /* Intentional fall through */
12484 case WLC_E_ASSOC:
12485 wl_get_auth_assoc_status(cfg, as.ndev, e, data);
12486 break;
12487 case WLC_E_ASSOC_RESP_IE:
12488 if (as.status != WLC_E_STATUS_SUCCESS) {
12489 wl_cache_assoc_resp_ies(cfg, as.ndev, e, data);
12490 }
12491 break;
12492 case WLC_E_SET_SSID:
12493 wl_cfg80211_handle_set_ssid_complete(cfg, &as, e, assoc_state);
12494 break;
12495 case WLC_E_DEAUTH_IND:
12496 case WLC_E_DISASSOC_IND:
12497 wl_cfg80211_handle_deauth_ind(cfg, &as);
12498 /* intentional fall through */
12499 case WLC_E_DISASSOC:
12500 case WLC_E_DEAUTH:
12501 as.link_action = wl_set_link_action(assoc_state, false);
12502 break;
12503 case WLC_E_LINK:
12504 if (as.flags & WLC_EVENT_MSG_LINK) {
12505 as.link_action = wl_set_link_action(assoc_state, true);
12506 } else {
12507 as.link_action = wl_set_link_action(assoc_state, false);
12508 }
12509 break;
12510 default:
12511 WL_DBG(("Ignore event:%d\n", as.event_type));
12512 as.link_action = 0;
12513 }
12514
12515 if (as.link_action) {
12516 /* Handle change in link state (if any) */
12517 err = wl_handle_sta_link_action(cfg, &as);
12518 }
12519
12520 return err;
12521 }
12522
12523 #define IS_OBSOLETE_EVENT(cur_idx, marker_idx) ((s32)(cur_idx - marker_idx) < 0)
12524 static s32
wl_notify_connect_status_sta(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const wl_event_msg_t * e,void * data)12525 wl_notify_connect_status_sta(struct bcm_cfg80211 *cfg,
12526 struct wireless_dev *wdev, const wl_event_msg_t *e, void *data)
12527 {
12528 u32 event_type;
12529 wl_assoc_state_t assoc_state;
12530 struct net_device *ndev;
12531 s32 ret = BCME_OK;
12532 wl_event_idx_t *idx = &cfg->eidx;
12533
12534 if (!wdev || !e) {
12535 WL_ERR(("wrong input\n"));
12536 return -EINVAL;
12537 }
12538
12539 event_type = ntoh32(e->event_type);
12540 if (IS_OBSOLETE_EVENT(idx->in_progress, idx->min_connect_idx)) {
12541 /* If this event is enqd before the connect req, discard */
12542 WL_ERR(("discard obsolete event:%d. cur_idx:%d min_idx:%d\n",
12543 event_type, idx->in_progress, idx->min_connect_idx));
12544 return -EINVAL;
12545 }
12546
12547 ndev = wdev->netdev;
12548 if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
12549 /* Join attempt via non-cfg80211 interface.
12550 * Don't send events to cfg80211 layer
12551 */
12552 WL_INFORM_MEM(("Event received in non-cfg80211"
12553 " connect state. Ignore\n"));
12554 goto exit;
12555 }
12556
12557 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
12558 assoc_state = WL_STATE_ASSOCIATING;
12559 } else if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12560 assoc_state = WL_STATE_ASSOCIATED;
12561 } else {
12562 WL_ERR(("Unexpected event:%d in assoc idle state\n", event_type));
12563 assoc_state = WL_STATE_ASSOC_IDLE;
12564 }
12565
12566 ret = wl_handle_assoc_events(cfg, wdev, e, data, assoc_state);
12567 exit:
12568 return ret;
12569 }
12570
12571 static s32
wl_notify_connect_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12572 wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12573 const wl_event_msg_t *e, void *data)
12574 {
12575 struct net_device *ndev = NULL;
12576 s32 err = 0;
12577 u32 mode;
12578
12579 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
12580 DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
12581 #endif /* BCMDONGLEHOST && OEM_ANDROID */
12582
12583 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12584 mode = wl_get_mode_by_netdev(cfg, ndev);
12585
12586 /* Push link events to upper layer log */
12587 SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n",
12588 ndev->name, mode, ntoh32(e->event_type),
12589 ntoh32(e->status), ntoh32(e->reason)));
12590
12591 if (mode == WL_MODE_AP) {
12592 /* AP/P2O GO cases */
12593 err = wl_notify_connect_status_ap(cfg, ndev, e, data);
12594 } else if (mode == WL_MODE_IBSS) {
12595 err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
12596 } else if (mode == WL_MODE_BSS) {
12597 /* STA/GC cases */
12598 err = wl_notify_connect_status_sta(cfg, ndev->ieee80211_ptr, e, data);
12599 } else {
12600 WL_ERR(("Unexpected event:%d for mode:%d\n", e->event_type, mode));
12601 }
12602
12603 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
12604 DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
12605 #endif /* BCMDONGLEHOST && OEM_ANDROID */
12606 return err;
12607 }
12608
12609 #ifdef WL_RELMCAST
wl_cfg80211_set_rmc_pid(struct net_device * dev,int pid)12610 void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
12611 {
12612 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
12613 if (pid > 0)
12614 cfg->rmc_event_pid = pid;
12615 WL_DBG(("set pid for rmc event : pid=%d\n", pid));
12616 }
12617 #endif /* WL_RELMCAST */
12618
12619 #ifdef WLAIBSS
wl_cfg80211_set_txfail_pid(struct net_device * dev,int pid)12620 void wl_cfg80211_set_txfail_pid(struct net_device *dev, int pid)
12621 {
12622 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
12623 if (pid > 0)
12624 cfg->aibss_txfail_pid = pid;
12625 WL_DBG(("set pid for aibss fail event : pid=%d\n", pid));
12626 }
12627
12628 static s32
wl_notify_aibss_txfail(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12629 wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12630 const wl_event_msg_t *e, void *data)
12631 {
12632 u32 evt = ntoh32(e->event_type);
12633 int ret = -1;
12634 #ifdef PCIE_FULL_DONGLE
12635 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12636 u32 reason = ntoh32(e->reason);
12637 #endif
12638 if (cfg->aibss_txfail_pid != 0) {
12639 #ifdef PCIE_FULL_DONGLE
12640 if (reason == AIBSS_PEER_FREE) {
12641 uint8 ifindex;
12642 wl_event_msg_t event;
12643
12644 bzero(&event, sizeof(wl_event_msg_t));
12645 memcpy(&event, e, sizeof(wl_event_msg_t));
12646
12647 ifindex = (uint8)dhd_ifname2idx(dhd->info, event.ifname);
12648 WL_INFORM_MEM(("Peer freed. Flow rings delete for peer.\n"));
12649 dhd_flow_rings_delete_for_peer(dhd, ifindex,
12650 (void *)&event.addr.octet[0]);
12651 return 0;
12652 }
12653 #endif
12654 ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL,
12655 cfg->aibss_txfail_seq++, &e->addr, ETHER_ADDR_LEN);
12656 }
12657
12658 WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n",
12659 evt, cfg->aibss_txfail_pid, ret, CONST_ETHERP_TO_MACF(&e->addr)));
12660 return ret;
12661 }
12662 #endif /* WLAIBSS */
12663 #ifdef WL_RELMCAST
12664 static s32
wl_notify_rmc_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12665 wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12666 const wl_event_msg_t *e, void *data)
12667 {
12668 u32 evt = ntoh32(e->event_type);
12669 u32 reason = ntoh32(e->reason);
12670 int ret = -1;
12671
12672 switch (reason) {
12673 case WLC_E_REASON_RMC_AR_LOST:
12674 case WLC_E_REASON_RMC_AR_NO_ACK:
12675 if (cfg->rmc_event_pid != 0) {
12676 ret = wl_netlink_send_msg(cfg->rmc_event_pid,
12677 RMC_EVENT_LEADER_CHECK_FAIL,
12678 cfg->rmc_event_seq++, NULL, 0);
12679 }
12680 break;
12681 default:
12682 break;
12683 }
12684 WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
12685 return ret;
12686 }
12687 #endif /* WL_RELMCAST */
12688
12689 #ifdef GSCAN_SUPPORT
12690 static s32
wl_handle_roam_exp_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12691 wl_handle_roam_exp_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12692 const wl_event_msg_t *e, void *data)
12693 {
12694 struct net_device *ndev = NULL;
12695 u32 datalen = be32_to_cpu(e->datalen);
12696
12697 if (datalen) {
12698 wl_roam_exp_event_t *evt_data = (wl_roam_exp_event_t *)data;
12699 if (evt_data->version == ROAM_EXP_EVENT_VERSION) {
12700 wlc_ssid_t *ssid = &evt_data->cur_ssid;
12701 struct wireless_dev *wdev;
12702 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12703 if (ndev) {
12704 wdev = ndev->ieee80211_ptr;
12705 wdev->ssid_len = min(ssid->SSID_len, (uint32)DOT11_MAX_SSID_LEN);
12706 memcpy(wdev->ssid, ssid->SSID, wdev->ssid_len);
12707 WL_ERR(("SSID is %s\n", ssid->SSID));
12708 wl_update_prof(cfg, ndev, NULL, ssid, WL_PROF_SSID);
12709 } else {
12710 WL_ERR(("NULL ndev!\n"));
12711 }
12712 } else {
12713 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
12714 ROAM_EXP_EVENT_VERSION));
12715 }
12716 }
12717 return BCME_OK;
12718 }
12719 #endif /* GSCAN_SUPPORT */
12720
12721 #ifdef RSSI_MONITOR_SUPPORT
wl_handle_rssi_monitor_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12722 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12723 const wl_event_msg_t *e, void *data)
12724 {
12725
12726 #if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
12727 u32 datalen = be32_to_cpu(e->datalen);
12728 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12729 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
12730
12731 if (datalen) {
12732 wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data;
12733 if (evt_data->version == RSSI_MONITOR_VERSION) {
12734 dhd_rssi_monitor_evt_t monitor_data;
12735 monitor_data.version = DHD_RSSI_MONITOR_EVT_VERSION;
12736 monitor_data.cur_rssi = evt_data->cur_rssi;
12737 memcpy(&monitor_data.BSSID, &e->addr, ETHER_ADDR_LEN);
12738 wl_cfgvendor_send_async_event(wiphy, ndev,
12739 GOOGLE_RSSI_MONITOR_EVENT,
12740 &monitor_data, sizeof(monitor_data));
12741 } else {
12742 WL_ERR(("Version mismatch %d, expected %d", evt_data->version,
12743 RSSI_MONITOR_VERSION));
12744 }
12745 }
12746 #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
12747 return BCME_OK;
12748 }
12749 #endif /* RSSI_MONITOR_SUPPORT */
12750
12751 static s32
wl_notify_roaming_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12752 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12753 const wl_event_msg_t *e, void *data)
12754 {
12755 bool act;
12756 struct net_device *ndev = NULL;
12757 s32 err = 0;
12758 u32 event = be32_to_cpu(e->event_type);
12759 u32 status = be32_to_cpu(e->status);
12760 #ifdef DHD_LOSSLESS_ROAMING
12761 struct wl_security *sec;
12762 #endif
12763 #ifdef BCMDONGLEHOST
12764 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12765 #endif /* BCMDONGLEHOST */
12766 WL_DBG(("Enter \n"));
12767
12768 #ifdef BCMDONGLEHOST
12769 BCM_REFERENCE(dhdp);
12770 #endif /* BCMDONGLEHOST */
12771 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12772
12773 if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
12774
12775 #ifdef OEM_ANDROID
12776 wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
12777 #endif /* OEM_ANDROID */
12778
12779 cfg->disable_roam_event = TRUE;
12780 }
12781
12782 if ((cfg->disable_roam_event) && (event == WLC_E_ROAM))
12783 return err;
12784
12785 if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
12786 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
12787 #ifdef DHD_LOSSLESS_ROAMING
12788 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
12789 /* In order to reduce roaming delay, wl_bss_roaming_done is
12790 * early called with WLC_E_LINK event. It is called from
12791 * here only if WLC_E_LINK event is blocked for specific
12792 * security type.
12793 */
12794 if (IS_AKM_SUITE_FT(sec)) {
12795 wl_bss_roaming_done(cfg, ndev, e, data);
12796 #ifdef BCMDONGLEHOST
12797 /* Arm pkt logging timer */
12798 dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
12799 #endif /* BCMDONGLEHOST */
12800 }
12801 /* Roam timer is deleted mostly from wl_cfg80211_change_station
12802 * after roaming is finished successfully. We need to delete
12803 * the timer from here only for some security types that aren't
12804 * using wl_cfg80211_change_station to authorize SCB
12805 */
12806 if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
12807 wl_del_roam_timeout(cfg);
12808 }
12809 #else
12810 #if !defined(DHD_NONFT_ROAMING)
12811 wl_bss_roaming_done(cfg, ndev, e, data);
12812 #endif /* !DHD_NONFT_ROAMING */
12813 #endif /* DHD_LOSSLESS_ROAMING */
12814 #ifdef WBTEXT
12815 if (dhdp->wbtext_support) {
12816 /* set wnm_keepalives_max_idle after association */
12817 wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
12818
12819 /* Mostly nbr request of BTM query will be handled
12820 * from wl_cfg80211_change_station
12821 * after key negotiation is finished.
12822 * This part is only for some specific security
12823 * types (FT, CCKM) that don't call
12824 * wl_cfg80211_change_station after roaming
12825 */
12826 if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
12827 /* send nbr request or BTM query to update RCC
12828 * after roaming completed
12829 */
12830 wl_cfg80211_wbtext_update_rcc(cfg, ndev);
12831 }
12832 }
12833 #endif /* WBTEXT */
12834 } else {
12835 wl_bss_connect_done(cfg, ndev, e, data, true);
12836 }
12837 act = true;
12838 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
12839 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
12840
12841 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
12842 wl_vndr_ies_get_vendor_oui(cfg, ndev, NULL, 0);
12843 }
12844 }
12845 #ifdef DHD_LOSSLESS_ROAMING
12846 else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) {
12847 wl_del_roam_timeout(cfg);
12848 }
12849 #endif
12850 return err;
12851 }
12852
12853 #ifdef CUSTOM_EVENT_PM_WAKE
12854 uint32 last_dpm_upd_time = 0; /* ms */
12855 #define DPM_UPD_LMT_TIME ((CUSTOM_EVENT_PM_WAKE + (5)) * (1000) * (4)) /* ms */
12856 #define DPM_UPD_LMT_RSSI -85 /* dbm */
12857
12858 static s32
wl_check_pmstatus(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12859 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12860 const wl_event_msg_t *e, void *data)
12861 {
12862 s32 err = BCME_OK;
12863 struct net_device *ndev = NULL;
12864 u8 *pbuf = NULL;
12865 uint32 cur_dpm_upd_time = 0;
12866 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12867 s32 rssi;
12868 #ifdef SUPPORT_RSSI_SUM_REPORT
12869 wl_rssi_ant_mimo_t rssi_ant_mimo;
12870 #endif /* SUPPORT_RSSI_SUM_REPORT */
12871 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12872
12873 pbuf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
12874 if (pbuf == NULL) {
12875 WL_ERR(("failed to allocate local pbuf\n"));
12876 return -ENOMEM;
12877 }
12878
12879 err = wldev_iovar_getbuf_bsscfg(ndev, "dump",
12880 "pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN,
12881 0, &cfg->ioctl_buf_sync);
12882
12883 if (err) {
12884 WL_ERR(("dump ioctl err = %d", err));
12885 } else {
12886 WL_ERR(("PM status : %s\n", pbuf));
12887 }
12888
12889 if (pbuf) {
12890 MFREE(cfg->osh, pbuf, WLC_IOCTL_MEDLEN);
12891 }
12892
12893 if (dhd->early_suspended) {
12894 /* LCD off */
12895 #ifdef SUPPORT_RSSI_SUM_REPORT
12896 /* Query RSSI sum across antennas */
12897 memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
12898 err = wl_get_rssi_per_ant(ndev, ndev->name, NULL, &rssi_ant_mimo);
12899 if (err) {
12900 WL_ERR(("Could not get rssi sum (%d)\n", err));
12901 }
12902 rssi = rssi_ant_mimo.rssi_sum;
12903 if (rssi == 0)
12904 #endif /* SUPPORT_RSSI_SUM_REPORT */
12905 {
12906 scb_val_t scb_val;
12907 memset(&scb_val, 0, sizeof(scb_val_t));
12908 scb_val.val = 0;
12909 err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
12910 if (err) {
12911 WL_ERR(("Could not get rssi (%d)\n", err));
12912 }
12913 rssi = wl_rssi_offset(dtoh32(scb_val.val));
12914 }
12915 WL_ERR(("RSSI %d dBm\n", rssi));
12916 if (rssi > DPM_UPD_LMT_RSSI) {
12917 return err;
12918 }
12919 } else {
12920 /* LCD on */
12921 return err;
12922 }
12923
12924 if (last_dpm_upd_time == 0) {
12925 last_dpm_upd_time = OSL_SYSUPTIME();
12926 } else {
12927 cur_dpm_upd_time = OSL_SYSUPTIME();
12928 if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) {
12929 scb_val_t scbval;
12930 DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
12931 dhd_net2idx(dhd->info, ndev), 0);
12932 bzero(&scbval, sizeof(scb_val_t));
12933
12934 err = wldev_ioctl_set(ndev, WLC_DISASSOC,
12935 &scbval, sizeof(scb_val_t));
12936 if (err < 0) {
12937 WL_ERR(("Disassoc error %d\n", err));
12938 return err;
12939 }
12940 WL_ERR(("Force Disassoc due to updated DPM event.\n"));
12941
12942 last_dpm_upd_time = 0;
12943 } else {
12944 last_dpm_upd_time = cur_dpm_upd_time;
12945 }
12946 }
12947
12948 return err;
12949 }
12950 #endif /* CUSTOM_EVENT_PM_WAKE */
12951
12952 #ifdef QOS_MAP_SET
12953 /* get user priority table */
12954 uint8 *
wl_get_up_table(dhd_pub_t * dhdp,int idx)12955 wl_get_up_table(dhd_pub_t * dhdp, int idx)
12956 {
12957 struct net_device *ndev;
12958 struct bcm_cfg80211 *cfg;
12959
12960 ndev = dhd_idx2net(dhdp, idx);
12961 if (ndev) {
12962 cfg = wl_get_cfg(ndev);
12963 if (cfg)
12964 return (uint8 *)(cfg->up_table);
12965 }
12966
12967 return NULL;
12968 }
12969 #endif /* QOS_MAP_SET */
12970
12971 #if defined(DHD_LOSSLESS_ROAMING) || defined (DBG_PKT_MON)
12972 /*
12973 * start packet logging in advance to make sure that EAPOL
12974 * messages are not missed during roaming
12975 */
12976 static s32
wl_notify_roam_prep_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)12977 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
12978 const wl_event_msg_t *e, void *data)
12979 {
12980 struct wl_security *sec;
12981 struct net_device *ndev;
12982 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12983 u32 status = ntoh32(e->status);
12984 u32 reason = ntoh32(e->reason);
12985
12986 BCM_REFERENCE(sec);
12987
12988 if (status == WLC_E_STATUS_SUCCESS && reason != WLC_E_REASON_INITIAL_ASSOC) {
12989 WL_ERR(("Attempting roam with reason code : %d\n", reason));
12990 }
12991
12992 #ifdef CONFIG_SILENT_ROAM
12993 if (dhdp->in_suspend && reason == WLC_E_REASON_SILENT_ROAM) {
12994 dhdp->sroamed = TRUE;
12995 }
12996 #endif /* CONFIG_SILENT_ROAM */
12997
12998 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
12999
13000 #ifdef DBG_PKT_MON
13001 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
13002 DHD_DBG_PKT_MON_STOP(dhdp);
13003 DHD_DBG_PKT_MON_START(dhdp);
13004 }
13005 #endif /* DBG_PKT_MON */
13006 #ifdef DHD_LOSSLESS_ROAMING
13007 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13008 /* Disable Lossless Roaming for specific AKM suite
13009 * Any other AKM suite can be added below if transition time
13010 * is delayed because of Lossless Roaming
13011 * and it causes any certication failure
13012 */
13013 if (IS_AKM_SUITE_FT(sec) || IS_AKM_OWE(sec->wpa_auth)) {
13014 return BCME_OK;
13015 }
13016
13017 dhdp->dequeue_prec_map = 1 << dhdp->flow_prio_map[PRIO_8021D_NC];
13018 /* Restore flow control */
13019 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
13020
13021 mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
13022 #endif /* DHD_LOSSLESS_ROAMING */
13023
13024 return BCME_OK;
13025 }
13026 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
13027
13028 static s32
wl_notify_roam_start_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)13029 wl_notify_roam_start_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13030 const wl_event_msg_t *e, void *data)
13031 {
13032 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13033 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13034 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13035 int event_type;
13036
13037 event_type = WIFI_EVENT_ROAM_SCAN_STARTED;
13038 wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_ROAM_EVENT_START,
13039 &event_type, sizeof(int));
13040 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || (WL_VENDOR_EXT_SUPPORT) */
13041
13042 return BCME_OK;
13043 }
13044
wl_get_assoc_ies(struct bcm_cfg80211 * cfg,struct net_device * ndev)13045 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13046 {
13047 wl_assoc_info_t assoc_info;
13048 struct wl_connect_info *conn_info = wl_to_conn(cfg);
13049 s32 err = 0;
13050 #ifdef QOS_MAP_SET
13051 bcm_tlv_t * qos_map_ie = NULL;
13052 #endif /* QOS_MAP_SET */
13053
13054 WL_DBG(("Enter \n"));
13055
13056 bzero(&assoc_info, sizeof(wl_assoc_info_t));
13057 err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
13058 WL_ASSOC_INFO_MAX, NULL);
13059 if (unlikely(err)) {
13060 WL_ERR(("could not get assoc info (%d)\n", err));
13061 return err;
13062 }
13063 memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
13064 assoc_info.req_len = htod32(assoc_info.req_len);
13065 assoc_info.resp_len = htod32(assoc_info.resp_len);
13066 assoc_info.flags = htod32(assoc_info.flags);
13067 if (conn_info->req_ie_len) {
13068 conn_info->req_ie_len = 0;
13069 bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
13070 }
13071 if (conn_info->resp_ie_len) {
13072 conn_info->resp_ie_len = 0;
13073 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
13074 }
13075
13076 if (assoc_info.req_len) {
13077 err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
13078 assoc_info.req_len, NULL);
13079 if (unlikely(err)) {
13080 WL_ERR(("could not get assoc req (%d)\n", err));
13081 return err;
13082 }
13083 if (assoc_info.req_len < sizeof(struct dot11_assoc_req)) {
13084 WL_ERR(("req_len %d lessthan %d \n", assoc_info.req_len,
13085 (int)sizeof(struct dot11_assoc_req)));
13086 return BCME_BADLEN;
13087 }
13088 conn_info->req_ie_len = (uint32)(assoc_info.req_len
13089 - sizeof(struct dot11_assoc_req));
13090 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
13091 conn_info->req_ie_len -= ETHER_ADDR_LEN;
13092 }
13093 if (conn_info->req_ie_len <= MAX_REQ_LINE)
13094 memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
13095 else {
13096 WL_ERR(("IE size %d above max %d size \n",
13097 conn_info->req_ie_len, MAX_REQ_LINE));
13098 return err;
13099 }
13100 } else {
13101 conn_info->req_ie_len = 0;
13102 }
13103
13104 if (assoc_info.resp_len) {
13105 err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
13106 assoc_info.resp_len, NULL);
13107 if (unlikely(err)) {
13108 WL_ERR(("could not get assoc resp (%d)\n", err));
13109 return err;
13110 }
13111 if (assoc_info.resp_len < sizeof(struct dot11_assoc_resp)) {
13112 WL_ERR(("resp_len %d is lessthan %d \n", assoc_info.resp_len,
13113 (int)sizeof(struct dot11_assoc_resp)));
13114 return BCME_BADLEN;
13115 }
13116 conn_info->resp_ie_len = assoc_info.resp_len -
13117 (uint32)sizeof(struct dot11_assoc_resp);
13118 if (conn_info->resp_ie_len <= MAX_REQ_LINE) {
13119 memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
13120 } else {
13121 WL_ERR(("IE size %d above max %d size \n",
13122 conn_info->resp_ie_len, MAX_REQ_LINE));
13123 return err;
13124 }
13125
13126 #ifdef QOS_MAP_SET
13127 /* find qos map set ie */
13128 if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
13129 DOT11_MNG_QOS_MAP_ID)) != NULL) {
13130 WL_DBG((" QoS map set IE found in assoc response\n"));
13131 if (!cfg->up_table) {
13132 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
13133 }
13134 wl_set_up_table(cfg->up_table, qos_map_ie);
13135 } else {
13136 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
13137 }
13138 #endif /* QOS_MAP_SET */
13139 } else {
13140 conn_info->resp_ie_len = 0;
13141 }
13142 WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
13143 conn_info->resp_ie_len));
13144
13145 return err;
13146 }
13147
wl_update_bss_info(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool update_ssid)13148 static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13149 bool update_ssid)
13150 {
13151 struct cfg80211_bss *bss;
13152 wl_bss_info_t *bi;
13153 struct wlc_ssid *ssid;
13154 const struct bcm_tlv *tim;
13155 s32 beacon_interval;
13156 s32 dtim_period;
13157 size_t ie_len;
13158 const u8 *ie;
13159 u8 *curbssid;
13160 s32 err = 0;
13161 struct wiphy *wiphy;
13162 char *buf;
13163 u32 freq;
13164 chanspec_t chspec = INVCHANSPEC;
13165
13166 wiphy = bcmcfg_to_wiphy(cfg);
13167
13168 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
13169 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13170 bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
13171 ssid->SSID, ssid->SSID_len);
13172 buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
13173 if (!buf) {
13174 WL_ERR(("buffer alloc failed.\n"));
13175 return BCME_NOMEM;
13176 }
13177 mutex_lock(&cfg->usr_sync);
13178 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
13179 err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX);
13180 if (unlikely(err)) {
13181 WL_ERR(("Could not get bss info %d\n", err));
13182 goto update_bss_info_out;
13183 }
13184 bi = (wl_bss_info_t *)(buf + 4);
13185 chspec = wl_chspec_driver_to_host(bi->chanspec);
13186 wl_update_prof(cfg, ndev, NULL, &chspec, WL_PROF_CHAN);
13187
13188 if (!bss) {
13189 if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
13190 WL_ERR(("Bssid doesn't match\n"));
13191 err = -EIO;
13192 goto update_bss_info_out;
13193 }
13194 err = wl_inform_single_bss(cfg, bi, update_ssid);
13195 if (unlikely(err)) {
13196 WL_ERR(("Could not update the AP detail in cache\n"));
13197 goto update_bss_info_out;
13198 }
13199
13200 WL_INFORM_MEM(("Updated the AP %pM detail in cache\n", curbssid));
13201 ie = ((u8 *)bi) + bi->ie_offset;
13202 ie_len = bi->ie_length;
13203 beacon_interval = cpu_to_le16(bi->beacon_period);
13204 } else {
13205 u16 channel;
13206 WL_INFORM_MEM(("Found AP in the cache - BSSID %pM\n", bss->bssid));
13207 channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
13208 freq = wl_channel_to_frequency(channel, CHSPEC_BAND(bi->chanspec));
13209 bss->channel = ieee80211_get_channel(wiphy, freq);
13210 #if defined(WL_CFG80211_P2P_DEV_IF)
13211 ie = (const u8 *)bss->ies->data;
13212 ie_len = bss->ies->len;
13213 #else
13214 ie = bss->information_elements;
13215 ie_len = bss->len_information_elements;
13216 #endif /* WL_CFG80211_P2P_DEV_IF */
13217 beacon_interval = bss->beacon_interval;
13218
13219 CFG80211_PUT_BSS(wiphy, bss);
13220 }
13221
13222 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
13223 if (tim) {
13224 dtim_period = tim->data[1];
13225 } else {
13226 /*
13227 * active scan was done so we could not get dtim
13228 * information out of probe response.
13229 * so we speficially query dtim information.
13230 */
13231 dtim_period = 0;
13232 err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD,
13233 &dtim_period, sizeof(dtim_period));
13234 if (unlikely(err)) {
13235 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
13236 goto update_bss_info_out;
13237 }
13238 }
13239
13240 wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
13241 wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
13242
13243 update_bss_info_out:
13244 if (unlikely(err)) {
13245 WL_ERR(("Failed with error %d\n", err));
13246 }
13247
13248 MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
13249 mutex_unlock(&cfg->usr_sync);
13250 return err;
13251 }
13252
13253 #ifdef DHD_LOSSLESS_ROAMING
13254 static s32
wl_bss_roaming_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)13255 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13256 const wl_event_msg_t *e, void *data)
13257 {
13258 struct wl_connect_info *conn_info = wl_to_conn(cfg);
13259 s32 err = 0;
13260 u8 *curbssid;
13261 chanspec_t *chanspec;
13262 scb_val_t scbval;
13263 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
13264 defined(WL_COMPAT_WIRELESS)
13265 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
13266 struct ieee80211_channel *notify_channel = NULL;
13267 u32 freq;
13268 u32 cur_channel, cur_chanspec, orig_channel;
13269 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
13270 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
13271 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \
13272 defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12)
13273 struct cfg80211_roam_info roam_info;
13274 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
13275 #if defined(WL_FILS_ROAM_OFFLD)
13276 struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
13277 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13278 #endif
13279 #ifdef BCMDONGLEHOST
13280 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
13281 #endif /* BCMDONGLEHOST */
13282 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
13283 dhd_if_t *ifp = NULL;
13284 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
13285 #ifdef WLFBT
13286 uint32 data_len = 0;
13287 if (data)
13288 data_len = ntoh32(e->datalen);
13289 #endif /* WLFBT */
13290
13291 BCM_REFERENCE(dhdp);
13292 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13293 chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
13294 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
13295 defined(WL_COMPAT_WIRELESS)
13296 /* Skip calling cfg80211_roamed If the channels are same and
13297 * the current bssid & the new bssid are same
13298 * Also clear timer roam_timeout.
13299 * Only used on BCM4359 devices.
13300 */
13301 err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&cur_chanspec);
13302 if (unlikely(err)) {
13303 return err;
13304 }
13305 cur_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(cur_chanspec));
13306 orig_channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(*chanspec));
13307 if ((orig_channel == cur_channel) &&
13308 ((memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) ||
13309 (memcmp(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN) == 0))) {
13310 WL_DBG(("BSS already present, Skipping roamed event to"
13311 " upper layer\n"));
13312 goto fail;
13313 }
13314 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
13315
13316 if ((err = wl_get_assoc_ies(cfg, ndev)) != BCME_OK) {
13317 #ifdef BCMDONGLEHOST
13318 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
13319 dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
13320 #endif /* BCMDONGLEHOST */
13321 WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
13322 " upper layer\n"));
13323 /* To make sure disconnect, and fw sync, explictly send dissassoc
13324 * for BSSID 00:00:00:00:00:00 issue
13325 */
13326 bzero(&scbval, sizeof(scb_val_t));
13327 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
13328 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
13329 scbval.val = htod32(scbval.val);
13330 if (wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
13331 sizeof(scb_val_t)) < 0) {
13332 WL_ERR(("WLC_DISASSOC error\n"));
13333 }
13334 goto fail;
13335 }
13336
13337 WL_MSG(ndev->name, "%pM(ch:%3d/%sMHz) => %pM(ch:%3d/%sMHz)\n",
13338 curbssid, orig_channel,
13339 CHSPEC_IS20(*chanspec)?"20":
13340 CHSPEC_IS40(*chanspec)?"40":
13341 CHSPEC_IS80(*chanspec)?"80":
13342 CHSPEC_IS160(*chanspec)?"160":"??",
13343 (const u8*)(&e->addr), cur_channel,
13344 CHSPEC_IS20(cur_chanspec)?"20":
13345 CHSPEC_IS40(cur_chanspec)?"40":
13346 CHSPEC_IS80(cur_chanspec)?"80":
13347 CHSPEC_IS160(cur_chanspec)?"160":"??");
13348
13349 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID);
13350 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13351 if ((err = wl_update_bss_info(cfg, ndev, true)) != BCME_OK) {
13352 WL_ERR(("failed to update bss info, err=%d\n", err));
13353 goto fail;
13354 }
13355 if (cfg->wlc_ver.wlc_ver_major < PMKDB_WLC_VER) {
13356 wl_update_pmklist(ndev, cfg->pmk_list, err);
13357 }
13358
13359 chanspec = (chanspec_t *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
13360 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
13361 defined(WL_COMPAT_WIRELESS)
13362 /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
13363 freq = wl_channel_to_frequency(wf_chspec_ctlchan(*chanspec), CHSPEC_BAND(*chanspec));
13364 notify_channel = ieee80211_get_channel(wiphy, freq);
13365 #endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
13366 #ifdef WLFBT
13367 /* back up the given FBT key for the further supplicant request,
13368 * currently not checking the FBT is enabled for current BSS in DHD,
13369 * because the supplicant decides to take it or not.
13370 */
13371 if (data && (data_len == FBT_KEYLEN)) {
13372 memcpy(cfg->fbt_key, data, FBT_KEYLEN);
13373 }
13374 #endif /* WLFBT */
13375 #ifdef CUSTOM_LONG_RETRY_LIMIT
13376 if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
13377 WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
13378 }
13379 #endif /* CUSTOM_LONG_RETRY_LIMIT */
13380 DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM),
13381 dhd_net2idx(dhdp->info, ndev), 0);
13382 #ifdef WL_EXT_IAPSTA
13383 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
13384 #endif
13385
13386 #if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
13387 (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || \
13388 defined(WL_FILS_ROAM_OFFLD) || defined(CFG80211_ROAM_API_GE_4_12)
13389 memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
13390 roam_info.channel = notify_channel;
13391 roam_info.bssid = curbssid;
13392 roam_info.req_ie = conn_info->req_ie;
13393 roam_info.req_ie_len = conn_info->req_ie_len;
13394 roam_info.resp_ie = conn_info->resp_ie;
13395 roam_info.resp_ie_len = conn_info->resp_ie_len;
13396 #if defined(WL_FILS_ROAM_OFFLD)
13397 if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
13398 roam_info.fils.kek = fils_info->fils_kek;
13399 roam_info.fils.kek_len = fils_info->fils_kek_len;
13400 roam_info.fils.update_erp_next_seq_num = true;
13401 roam_info.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
13402 roam_info.fils.pmk = fils_info->fils_pmk;
13403 roam_info.fils.pmk_len = fils_info->fils_kek_len;
13404 roam_info.fils.pmkid = fils_info->fils_pmkid;
13405 }
13406 #endif
13407 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
13408 #else
13409 cfg80211_roamed(ndev,
13410 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || \
13411 defined(WL_COMPAT_WIRELESS)
13412 notify_channel,
13413 #endif
13414 curbssid,
13415 conn_info->req_ie, conn_info->req_ie_len,
13416 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
13417 #endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
13418
13419 memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
13420 wl_set_drv_status(cfg, CONNECTED, ndev);
13421
13422 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
13423 cfg->roam_count++;
13424 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
13425 #ifdef WL_BAM
13426 if (wl_adps_bad_ap_check(cfg, &e->addr)) {
13427 if (wl_adps_enabled(cfg, ndev)) {
13428 wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
13429 }
13430 }
13431 #endif /* WL_BAM */
13432
13433 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
13434 ifp = dhd_get_ifp(dhdp, e->ifidx);
13435 if (ifp) {
13436 ifp->post_roam_evt = TRUE;
13437 }
13438 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
13439
13440 return err;
13441
13442 fail:
13443 #ifdef DHD_LOSSLESS_ROAMING
13444 wl_del_roam_timeout(cfg);
13445 #endif /* DHD_LOSSLESS_ROAMING */
13446 return err;
13447 }
13448 #endif /* DHD_LOSSLESS_ROAMING */
13449
13450 static bool
wl_cfg80211_verify_bss(struct bcm_cfg80211 * cfg,struct net_device * ndev,struct cfg80211_bss ** bss)13451 wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13452 struct cfg80211_bss **bss)
13453 {
13454 struct wiphy *wiphy;
13455 struct wlc_ssid *ssid;
13456 uint8 *curbssid;
13457 bool ret = false;
13458
13459 wiphy = bcmcfg_to_wiphy(cfg);
13460 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
13461 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13462 if (!ssid || !curbssid) {
13463 WL_ERR(("No SSID/bssid found in the saved profile \n"));
13464 return false;
13465 }
13466
13467 *bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
13468 ssid->SSID, ssid->SSID_len);
13469 if (*bss) {
13470 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
13471 /* Update the reference count after use. In case of kernel version >= 4.7
13472 * the cfg802_put_bss is called in cfg80211_connect_bss context
13473 */
13474 CFG80211_PUT_BSS(wiphy, *bss);
13475 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
13476 ret = true;
13477 } else {
13478 WL_ERR(("No bss entry for bssid:"MACDBG" ssid_len:%d\n",
13479 MAC2STRDBG(curbssid), ssid->SSID_len));
13480 }
13481
13482 return ret;
13483 }
13484
13485 #ifdef WL_FILS
13486 static s32
wl_get_fils_connect_params(struct bcm_cfg80211 * cfg,struct net_device * ndev)13487 wl_get_fils_connect_params(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13488 {
13489 const bcm_xtlv_t* pxtlv_out;
13490 struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
13491 int err = BCME_OK;
13492 bcm_iov_buf_t *iov_buf_in = NULL;
13493 bcm_iov_buf_t iov_buf_out = {0};
13494 u16 len;
13495 u16 type;
13496 const u8 *data;
13497 iov_buf_in = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13498 if (!iov_buf_in) {
13499 WL_ERR(("buf memory alloc failed\n"));
13500 err = BCME_NOMEM;
13501 goto exit;
13502 }
13503 iov_buf_out.version = WL_FILS_IOV_VERSION;
13504 iov_buf_out.id = WL_FILS_CMD_GET_CONNECT_PARAMS;
13505 err = wldev_iovar_getbuf(ndev, "fils", (uint8*)&iov_buf_out, sizeof(bcm_iov_buf_t),
13506 iov_buf_in, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
13507 if (unlikely(err)) {
13508 WL_ERR(("Get FILS Params Error (%d)\n", err));
13509 goto exit;
13510 }
13511 pxtlv_out = (bcm_xtlv_t*)((bcm_iov_buf_t*)iov_buf_in)->data;
13512 len = iov_buf_in->len;
13513 do {
13514 if (!bcm_valid_xtlv(pxtlv_out, iov_buf_in->len, BCM_XTLV_OPTION_ALIGN32)) {
13515 WL_ERR(("%s: XTLV is not valid\n", __func__));
13516 err = BCME_BADARG;
13517 goto exit;
13518 }
13519 bcm_xtlv_unpack_xtlv(pxtlv_out, &type, &len, &data, BCM_XTLV_OPTION_ALIGN32);
13520 switch (type) {
13521 case WL_FILS_XTLV_ERP_NEXT_SEQ_NUM:
13522 fils_info->fils_erp_next_seq_num = *(const u16 *)data;
13523 break;
13524 case WL_FILS_XTLV_KEK:
13525 if (memcpy_s(fils_info->fils_kek,
13526 WL_MAX_FILS_KEY_LEN, data, len) < 0) {
13527 err = BCME_BADARG;
13528 goto exit;
13529 }
13530 fils_info->fils_kek_len = len;
13531 break;
13532 case WL_FILS_XTLV_PMK:
13533 if (memcpy_s(fils_info->fils_pmk,
13534 WL_MAX_FILS_KEY_LEN, data, len) < 0) {
13535 err = BCME_BADARG;
13536 goto exit;
13537 }
13538 fils_info->fils_pmk_len = len;
13539 break;
13540 case WL_FILS_XTLV_PMKID:
13541 if (memcpy_s(fils_info->fils_pmkid,
13542 WL_MAX_FILS_KEY_LEN, data, len) < 0) {
13543 err = BCME_BADARG;
13544 goto exit;
13545 }
13546 break;
13547 default:
13548 WL_ERR(("%s: wrong XTLV code\n", __func__));
13549 break;
13550
13551 }
13552 } while ((pxtlv_out = bcm_next_xtlv(pxtlv_out, (int *)&iov_buf_in->len,
13553 BCM_XTLV_OPTION_ALIGN32)) && iov_buf_in->len);
13554 exit:
13555 if (iov_buf_in) {
13556 MFREE(cfg->osh, iov_buf_in, WLC_IOCTL_SMLEN);
13557 }
13558 return err;
13559 }
13560 #endif /* WL_FILS */
13561
13562 #ifdef WL_FILS
13563 static s32
wl_fillup_resp_params(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 * curbssid,void * params,u32 status)13564 wl_fillup_resp_params(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13565 u8 *curbssid, void *params, u32 status)
13566 {
13567 struct wl_connect_info *conn_info = wl_to_conn(cfg);
13568 struct cfg80211_connect_resp_params *resp_params;
13569 struct wl_fils_info *fils_info = NULL;
13570 struct wlc_ssid *ssid = NULL;
13571 struct wiphy *wiphy = NULL;
13572 s32 ret = BCME_OK;
13573
13574 fils_info = wl_to_fils_info(cfg);
13575 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
13576 wiphy = bcmcfg_to_wiphy(cfg);
13577 if (!ssid) {
13578 WL_ERR(("ssid profile not found\n"));
13579 return BCME_ERROR;
13580 }
13581
13582 resp_params = (struct cfg80211_connect_resp_params *)params;
13583 resp_params->status = status;
13584 resp_params->bssid = curbssid;
13585 resp_params->bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
13586 ssid->SSID, ssid->SSID_len);
13587 if (!resp_params->bss) {
13588 WL_ERR(("null bss\n"));
13589 return BCME_ERROR;
13590 }
13591
13592 resp_params->req_ie = conn_info->req_ie;
13593 resp_params->req_ie_len = conn_info->req_ie_len;
13594 resp_params->resp_ie = conn_info->resp_ie;
13595 resp_params->resp_ie_len = conn_info->resp_ie_len;
13596 #ifdef WL_FILS_ROAM_OFFLD
13597 /* Kernel >= 4.17 has introduced FILS data struct inside resp params */
13598 resp_params->fils.kek = fils_info->fils_kek;
13599 resp_params->fils.kek_len = fils_info->fils_kek_len;
13600 resp_params->fils.update_erp_next_seq_num = true;
13601 resp_params->fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
13602 resp_params->fils.pmk = fils_info->fils_pmk;
13603 resp_params->fils.pmk_len = fils_info->fils_kek_len;
13604 resp_params->fils.pmkid = fils_info->fils_pmkid;
13605 #else
13606 resp_params->fils_kek = fils_info->fils_kek;
13607 resp_params->fils_kek_len = fils_info->fils_kek_len;
13608 resp_params->update_erp_next_seq_num = true;
13609 resp_params->fils_erp_next_seq_num = fils_info->fils_erp_next_seq_num;
13610 resp_params->pmk = fils_info->fils_pmk;
13611 resp_params->pmk_len = fils_info->fils_kek_len;
13612 resp_params->pmkid = fils_info->fils_pmkid;
13613 #endif /* WL_FILS_ROAM_OFFLD */
13614
13615 return ret;
13616 }
13617 #endif /* WL_FILS */
13618
13619 static s32
wl_bss_connect_done(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data,bool completed)13620 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
13621 const wl_event_msg_t *e, void *data, bool completed)
13622 {
13623 struct wl_connect_info *conn_info = wl_to_conn(cfg);
13624 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
13625 s32 err = 0;
13626 u8 *conn_req_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
13627 u32 status;
13628 #ifdef WL_FILS
13629 struct cfg80211_connect_resp_params resp_params = {0};
13630 #endif /* WL_FILS */
13631
13632 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13633 u32 event_type = ntoh32(e->event_type);
13634 struct cfg80211_bss *bss = NULL;
13635 #ifdef BCMDONGLEHOST
13636 dhd_pub_t *dhdp;
13637 dhdp = (dhd_pub_t *)(cfg->pub);
13638 BCM_REFERENCE(dhdp);
13639 #endif /* BCMDONGLEHOST */
13640
13641 WL_DBG((" enter\n"));
13642 if (!sec) {
13643 WL_ERR(("sec is NULL\n"));
13644 err = -ENODEV;
13645 goto exit;
13646 }
13647
13648 if (!wl_get_drv_status(cfg, CONNECTING, ndev)) {
13649 WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
13650 " connecting:%x. connected:%d\n",
13651 ndev->name, event_type, wl_get_drv_status(cfg, CONNECTING, ndev),
13652 wl_get_drv_status(cfg, CONNECTED, ndev)));
13653 err = BCME_OK;
13654 goto exit;
13655 }
13656
13657 if (!conn_req_bssid) {
13658 WL_ERR(("conn_req bssid is null\n"));
13659 err = -EINVAL;
13660 goto exit;
13661 }
13662
13663 if (ETHER_ISNULLADDR(curbssid) &&
13664 !ETHER_ISNULLADDR(conn_req_bssid)) {
13665 WL_DBG(("copy bssid\n"));
13666 memcpy(curbssid, conn_req_bssid, ETHER_ADDR_LEN);
13667 }
13668
13669 wl_cfgscan_cancel_scan(cfg);
13670 bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
13671
13672 if (completed) {
13673 wl_get_assoc_ies(cfg, ndev);
13674 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
13675 WL_PROF_BSSID);
13676 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
13677 /*
13678 * CFG layer relies on cached IEs (from probe/beacon) to fetch matching bss.
13679 * For cases, there is no match available,
13680 * need to update the cache based on bss info from fw.
13681 */
13682 wl_update_bss_info(cfg, ndev, true);
13683 if (cfg->wlc_ver.wlc_ver_major < PMKDB_WLC_VER) {
13684 wl_update_pmklist(ndev, cfg->pmk_list, err);
13685 }
13686 wl_set_drv_status(cfg, CONNECTED, ndev);
13687
13688 if (wl_cfg80211_verify_bss(cfg, ndev, &bss) != true) {
13689 /* If bss entry is not available in the cfg80211 bss cache
13690 * the wireless stack will complain and won't populate
13691 * wdev->current_bss ptr
13692 */
13693 WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
13694 completed = false;
13695 sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
13696 }
13697 if (!ndev->ieee80211_ptr->ssid_len) {
13698 /* In certain cases, the delayed cfg80211 work from
13699 * disconnect context will induce race conditions in
13700 * which the ssid_len will be cleared, but dhd is in
13701 * connecting state. Return connect failure to avoid
13702 * getting locked in connected state.
13703 */
13704 WL_ERR(("ssid_len=0. Indicate assoc event failure\n"));
13705 completed = false;
13706 sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
13707 }
13708 }
13709
13710 /* Clear status after updating CONNECTED status */
13711 wl_clr_drv_status(cfg, CONNECTING, ndev);
13712
13713 /* update status field */
13714 if (completed) {
13715 status = WLAN_STATUS_SUCCESS;
13716 } else if (sec->auth_assoc_res_status) {
13717 status = sec->auth_assoc_res_status;
13718 } else {
13719 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
13720 }
13721
13722 if (completed) {
13723 WL_MSG(ndev->name, "Report connect result - connection succeeded\n");
13724 #ifdef WL_EXT_IAPSTA
13725 wl_ext_in4way_sync(ndev, 0, WL_EXT_STATUS_CONNECTED, NULL);
13726 wl_ext_iapsta_enable_master_if(ndev, TRUE);
13727 #endif
13728 } else {
13729 WL_MSG(ndev->name, "Report connect result - connection failed\n");
13730 #ifdef WL_EXT_IAPSTA
13731 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
13732 WL_EXT_STATUS_DISCONNECTED, NULL);
13733 #endif
13734 }
13735
13736 #ifdef WL_FILS
13737 if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
13738 if ((err = wl_get_fils_connect_params(cfg, ndev)) != BCME_OK) {
13739 WL_ERR(("FILS params fetch failed.\n"));
13740 goto exit;
13741 }
13742
13743 if (wl_fillup_resp_params(cfg, ndev, curbssid, &resp_params, status) != BCME_OK) {
13744 WL_ERR(("connect resp_params failure\n"));
13745 err = BCME_ERROR;
13746 goto exit;
13747 }
13748 cfg80211_connect_done(ndev, &resp_params, GFP_KERNEL);
13749 }
13750 else
13751 #endif /* WL_FILS */
13752 {
13753 CFG80211_CONNECT_RESULT(ndev, curbssid, bss,
13754 conn_info->req_ie, conn_info->req_ie_len,
13755 conn_info->resp_ie, conn_info->resp_ie_len,
13756 status, GFP_KERNEL);
13757 }
13758
13759 if (completed) {
13760 LOG_TS(cfg, conn_cmplt);
13761 LOG_TS(cfg, authorize_start);
13762 WL_INFORM_MEM(("[%s] Report connect result - "
13763 "connection succeeded\n", ndev->name));
13764
13765 #ifdef BCMWAPI_WPI
13766 if (sec->cipher_group == WLAN_CIPHER_SUITE_SMS4) {
13767 /* In WAPI case, there is no seperate authorized call
13768 * from upper layer. so set the state from connect done.
13769 */
13770 wl_set_drv_status(cfg, AUTHORIZED, ndev);
13771 CLR_TS(cfg, authorize_start);
13772 LOG_TS(cfg, authorize_cmplt);
13773 }
13774 #endif /* WAPI */
13775 }
13776
13777 exit:
13778 CLR_TS(cfg, conn_start);
13779 return err;
13780 }
13781
13782 static s32
wl_notify_mic_status(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)13783 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13784 const wl_event_msg_t *e, void *data)
13785 {
13786 struct net_device *ndev = NULL;
13787 u16 flags = ntoh16(e->flags);
13788 enum nl80211_key_type key_type;
13789
13790 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13791
13792 WL_INFORM_MEM(("[%s] mic fail event - " MACDBG " \n",
13793 ndev->name, MAC2STRDBG(e->addr.octet)));
13794 mutex_lock(&cfg->usr_sync);
13795 if (flags & WLC_EVENT_MSG_GROUP)
13796 key_type = NL80211_KEYTYPE_GROUP;
13797 else
13798 key_type = NL80211_KEYTYPE_PAIRWISE;
13799
13800 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
13801 cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1,
13802 NULL, GFP_KERNEL);
13803 mutex_unlock(&cfg->usr_sync);
13804
13805 return 0;
13806 }
13807
13808 #ifdef BT_WIFI_HANDOVER
13809 static s32
wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)13810 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13811 const wl_event_msg_t *e, void *data)
13812 {
13813 struct net_device *ndev = NULL;
13814 u32 event = ntoh32(e->event_type);
13815 u32 datalen = ntoh32(e->datalen);
13816 s32 err;
13817
13818 WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen));
13819 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
13820 err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0);
13821
13822 return err;
13823 }
13824 #endif /* BT_WIFI_HANDOVER */
13825
13826 #ifdef WL_CFG80211_GON_COLLISION
13827 static void
wl_gon_req_collision(struct bcm_cfg80211 * cfg,wl_action_frame_t * tx_act_frm,wifi_p2p_pub_act_frame_t * rx_act_frm,struct net_device * ndev,struct ether_addr sa,struct ether_addr da)13828 wl_gon_req_collision(struct bcm_cfg80211 *cfg, wl_action_frame_t *tx_act_frm,
13829 wifi_p2p_pub_act_frame_t *rx_act_frm, struct net_device *ndev,
13830 struct ether_addr sa, struct ether_addr da)
13831 {
13832 if (cfg->afx_hdl->pending_tx_act_frm == NULL)
13833 return;
13834
13835 if (tx_act_frm &&
13836 wl_cfgp2p_is_pub_action(tx_act_frm->data, tx_act_frm->len)) {
13837 wifi_p2p_pub_act_frame_t *pact_frm;
13838
13839 pact_frm = (wifi_p2p_pub_act_frame_t *)tx_act_frm->data;
13840
13841 if (!(pact_frm->subtype == P2P_PAF_GON_REQ &&
13842 rx_act_frm->subtype == P2P_PAF_GON_REQ)) {
13843 return;
13844 }
13845 }
13846
13847 WL_ERR((" GO NEGO Request COLLISION !!! \n"));
13848
13849 /* if sa(peer) addr is less than da(my) addr,
13850 * my device will process peer's gon request and block to send my gon req.
13851 *
13852 * if not (sa addr > da addr),
13853 * my device will process gon request and drop gon req of peer.
13854 */
13855 if (memcmp(sa.octet, da.octet, ETHER_ADDR_LEN) < 0) {
13856 /* block to send tx gon request */
13857 cfg->block_gon_req_tx_count = BLOCK_GON_REQ_MAX_NUM;
13858 WL_ERR((" block to send gon req tx !!!\n"));
13859
13860 /* if we are finding a common channel for sending af,
13861 * do not scan more to block to send current gon req
13862 */
13863 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
13864 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, ndev);
13865 complete(&cfg->act_frm_scan);
13866 }
13867 } else {
13868 /* drop gon request of peer to process gon request by my device. */
13869 WL_ERR((" drop to receive gon req rx !!! \n"));
13870 cfg->block_gon_req_rx_count = BLOCK_GON_REQ_MAX_NUM;
13871 }
13872
13873 return;
13874 }
13875 #endif /* WL_CFG80211_GON_COLLISION */
13876
13877 void
wl_stop_wait_next_action_frame(struct bcm_cfg80211 * cfg,struct net_device * ndev,u8 bsscfgidx)13878 wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 bsscfgidx)
13879 {
13880 s32 err = 0;
13881
13882 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
13883 del_timer_sync(&cfg->p2p->listen_timer);
13884 if (cfg->afx_hdl != NULL) {
13885 if (cfg->afx_hdl->dev != NULL) {
13886 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
13887 wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev);
13888 }
13889 cfg->afx_hdl->peer_chan = WL_INVALID;
13890 }
13891 complete(&cfg->act_frm_scan);
13892 WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
13893 } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
13894 if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
13895 wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
13896 wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
13897
13898 WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx));
13899 /* Scan engine is not used for sending action frames in the latest driver
13900 * branches. actframe_abort is used in the latest driver branches
13901 * instead of scan abort.
13902 * If actframe_abort iovar succeeds, don't execute scan abort.
13903 * If actframe_abort fails with unsupported error,
13904 * execute scan abort (for backward copmatibility).
13905 */
13906 if (cfg->af_sent_channel) {
13907 err = wldev_iovar_setint_bsscfg(ndev, "actframe_abort", 1, bsscfgidx);
13908 if (err < 0) {
13909 if (err == BCME_UNSUPPORTED) {
13910 mutex_lock(&cfg->scan_sync);
13911 wl_cfgscan_scan_abort(cfg);
13912 mutex_unlock(&cfg->scan_sync);
13913 } else {
13914 WL_ERR(("actframe_abort failed. ret:%d\n", err));
13915 }
13916 }
13917 }
13918 }
13919 #ifdef WL_CFG80211_SYNC_GON
13920 else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
13921 WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
13922 /* So abort scan to cancel listen */
13923 wl_cfgscan_cancel_scan(cfg);
13924 }
13925 #endif /* WL_CFG80211_SYNC_GON */
13926 }
13927
13928 #if defined(WES_SUPPORT)
wl_cfg80211_set_wes_mode(struct net_device * dev,int mode)13929 int wl_cfg80211_set_wes_mode(struct net_device *dev, int mode)
13930 {
13931 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13932 cfg->wes_mode = mode;
13933 return 0;
13934 }
13935
wl_cfg80211_get_wes_mode(struct net_device * dev)13936 int wl_cfg80211_get_wes_mode(struct net_device *dev)
13937 {
13938 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13939 return cfg->wes_mode;
13940 }
13941
wl_cfg80211_is_wes(void * frame,u32 frame_len)13942 bool wl_cfg80211_is_wes(void *frame, u32 frame_len)
13943 {
13944 unsigned char *data;
13945
13946 if (frame == NULL) {
13947 WL_ERR(("Invalid frame \n"));
13948 return false;
13949 }
13950
13951 if (frame_len < 4) {
13952 WL_ERR(("Invalid frame length [%d] \n", frame_len));
13953 return false;
13954 }
13955
13956 data = frame;
13957
13958 if (memcmp(data, "\x7f\x00\x00\xf0", 4) == 0) {
13959 WL_DBG(("Receive WES VS Action Frame \n"));
13960 return true;
13961 }
13962
13963 return false;
13964 }
13965
13966 int
wl_cfg80211_set_ncho_mode(struct net_device * dev,int mode)13967 wl_cfg80211_set_ncho_mode(struct net_device *dev, int mode)
13968 {
13969 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13970 cfg->ncho_mode = mode;
13971 return BCME_OK;
13972 }
13973
13974 int
wl_cfg80211_get_ncho_mode(struct net_device * dev)13975 wl_cfg80211_get_ncho_mode(struct net_device *dev)
13976 {
13977 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13978 return cfg->ncho_mode;
13979 }
13980 #endif /* WES_SUPPORT */
13981
wl_cfg80211_get_ioctl_version(void)13982 int wl_cfg80211_get_ioctl_version(void)
13983 {
13984 return ioctl_version;
13985 }
13986
13987 static s32
wl_notify_rx_mgmt_frame(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)13988 wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
13989 const wl_event_msg_t *e, void *data)
13990 {
13991 struct ether_addr da;
13992 struct ether_addr bssid;
13993 bool isfree = false;
13994 s32 err = 0;
13995 s32 freq;
13996 struct net_device *ndev = NULL;
13997 wifi_p2p_pub_act_frame_t *act_frm = NULL;
13998 wifi_p2p_action_frame_t *p2p_act_frm = NULL;
13999 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
14000 wl_event_rx_frame_data_t *rxframe;
14001 u32 event;
14002 u8 *mgmt_frame;
14003 u8 bsscfgidx;
14004 u32 mgmt_frame_len;
14005 chanspec_t chspec;
14006 #if defined(BCMDONGLEHOST) && defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
14007 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14008 #endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
14009 if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) {
14010 WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen)));
14011 return -EINVAL;
14012 }
14013 mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_t);
14014 event = ntoh32(e->event_type);
14015 bsscfgidx = e->bsscfgidx;
14016 rxframe = (wl_event_rx_frame_data_t *)data;
14017 if (!rxframe) {
14018 WL_ERR(("rxframe: NULL\n"));
14019 return -EINVAL;
14020 }
14021 chspec = ntoh16(rxframe->channel);
14022 bzero(&bssid, ETHER_ADDR_LEN);
14023 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
14024 if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) &&
14025 (event == WLC_E_PROBREQ_MSG)) {
14026 /* Probe req event comes on wlan0 interface even though
14027 * the frame have been received on correct interface(AP)
14028 * in firmware. Find the right interface to pass it up.
14029 * Required for WPS-AP certification 4.2.13.
14030 * TODO/Need a better fix. Current fix doesn't take
14031 * care of dual AP/GO scenarios.
14032 */
14033 struct net_info *iter, *next;
14034 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
14035 for_each_ndev(cfg, iter, next) {
14036 GCC_DIAGNOSTIC_POP();
14037 if (iter->ndev && iter->wdev &&
14038 iter->wdev->iftype == NL80211_IFTYPE_AP) {
14039 ndev = iter->ndev;
14040 cfgdev = ndev_to_cfgdev(ndev);
14041 break;
14042 }
14043 }
14044 }
14045
14046 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
14047 freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chspec));
14048 #else
14049 freq = wl_channel_to_frequency(wf_chspec_ctlchan(chspec), CHSPEC_BAND(chspec));
14050 #endif
14051 if (event == WLC_E_ACTION_FRAME_RX) {
14052 u8 ioctl_buf[WLC_IOCTL_SMLEN];
14053 if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
14054 NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx,
14055 NULL)) != BCME_OK) {
14056 WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
14057 goto exit;
14058 }
14059
14060 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
14061 if (err < 0)
14062 WL_ERR(("WLC_GET_BSSID error %d\n", err));
14063 memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
14064 err = wl_frame_get_mgmt(cfg, FC_ACTION, &da, &e->addr, &bssid,
14065 &mgmt_frame, &mgmt_frame_len,
14066 (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
14067 if (err < 0) {
14068 WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
14069 mgmt_frame_len, CHSPEC_CHANNEL(chspec), freq));
14070 goto exit;
14071 }
14072 isfree = true;
14073
14074 wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
14075 mgmt_frame_len - DOT11_MGMT_HDR_LEN, CHSPEC_CHANNEL(chspec));
14076
14077 if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14078 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14079 act_frm = (wifi_p2p_pub_act_frame_t *)
14080 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
14081 } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14082 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14083 p2p_act_frm = (wifi_p2p_action_frame_t *)
14084 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
14085 (void) p2p_act_frm;
14086 } else if (wl_cfg80211_is_dpp_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14087 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14088 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14089
14090 /* Stop waiting for next AF. */
14091 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14092 } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14093 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14094 #ifdef WL_SDO
14095 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
14096 WL_ERR(("SD offload is in progress. Don't report the"
14097 "frame via rx_mgmt path\n"));
14098 goto exit;
14099 }
14100 #endif
14101 sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
14102 (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
14103 if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
14104 if (cfg->next_af_subtype == sd_act_frm->action) {
14105 WL_DBG(("We got a right next frame of SD!(%d)\n",
14106 sd_act_frm->action));
14107 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14108
14109 /* Stop waiting for next AF. */
14110 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14111 }
14112 }
14113 (void) sd_act_frm;
14114 #ifdef WLTDLS
14115 } else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
14116 (wl_cfg80211_is_tdls_tunneled_frame(
14117 &mgmt_frame[DOT11_MGMT_HDR_LEN],
14118 mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
14119 if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
14120 WL_ERR((" TDLS Action Frame Received type = %d \n",
14121 mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
14122 }
14123 #ifdef TDLS_MSG_ONLY_WFD
14124 #ifdef BCMDONGLEHOST
14125 if (!dhdp->tdls_mode) {
14126 WL_DBG((" TDLS Frame filtered \n"));
14127 goto exit;
14128 }
14129 #endif /* BCMDONGLEHOST */
14130 #else
14131 if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
14132 cfg->tdls_mgmt_frame = mgmt_frame;
14133 cfg->tdls_mgmt_frame_len = mgmt_frame_len;
14134 cfg->tdls_mgmt_freq = freq;
14135 return 0;
14136 }
14137 #endif /* TDLS_MSG_ONLY_WFD */
14138 #endif /* WLTDLS */
14139 #ifdef QOS_MAP_SET
14140 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
14141 /* update QoS map set table */
14142 bcm_tlv_t * qos_map_ie = NULL;
14143 uint8 offset = DOT11_MGMT_HDR_LEN + DOT11_ACTION_FRMHDR_LEN;
14144 if ((qos_map_ie = bcm_parse_tlvs(&mgmt_frame[offset],
14145 mgmt_frame_len - offset, DOT11_MNG_QOS_MAP_ID)) != NULL) {
14146 WL_DBG((" QoS map set IE found in QoS action frame\n"));
14147 if (!cfg->up_table) {
14148 cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
14149 }
14150 wl_set_up_table(cfg->up_table, qos_map_ie);
14151 } else {
14152 MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
14153 }
14154 #endif /* QOS_MAP_SET */
14155 #ifdef WBTEXT
14156 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_RRM) {
14157 /* radio measurement category */
14158 switch (mgmt_frame[DOT11_MGMT_HDR_LEN+1]) {
14159 case DOT11_RM_ACTION_NR_REP:
14160 if (wl_cfg80211_recv_nbr_resp(ndev,
14161 &mgmt_frame[DOT11_MGMT_HDR_LEN],
14162 mgmt_frame_len - DOT11_MGMT_HDR_LEN)
14163 == BCME_OK) {
14164 WL_DBG(("RCC updated by nbr response\n"));
14165 }
14166 break;
14167 default:
14168 break;
14169 }
14170 #endif /* WBTEXT */
14171 } else {
14172 /* WAR : There is no way to identify DA of action frame as of now.
14173 * We have to modify firmware code to include DA and SA of Act frame
14174 * as event data
14175 */
14176 /*
14177 * if we got normal action frame and ndev is p2p0,
14178 * we have to change ndev from p2p0 to wlan0
14179 */
14180 #if defined(WES_SUPPORT)
14181 if (wl_cfg80211_is_wes(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14182 mgmt_frame_len - DOT11_MGMT_HDR_LEN) && cfg->wes_mode == 0) {
14183 /* Ignore WES VS Action frame */
14184 goto exit;
14185 }
14186 #endif /* WES_SUPPORT */
14187
14188 /* We need to check proper action frame is received */
14189 if (cfg->next_af_subtype != WL_PUB_AF_STYPE_INVALID) {
14190 u8 action = 0;
14191 if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14192 mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) {
14193 WL_DBG(("Recived action is not public action frame\n"));
14194 } else if (cfg->next_af_subtype == action) {
14195 WL_DBG(("Recived action is the waiting action(%d)\n",
14196 action));
14197 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14198
14199 /* Stop waiting for next AF. */
14200 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14201 }
14202 }
14203 }
14204
14205 if (act_frm) {
14206 #ifdef WL_CFG80211_GON_COLLISION
14207 if (act_frm->subtype == P2P_PAF_GON_REQ) {
14208 wl_gon_req_collision(cfg,
14209 &cfg->afx_hdl->pending_tx_act_frm->action_frame,
14210 act_frm, ndev, e->addr, da);
14211
14212 if (cfg->block_gon_req_rx_count) {
14213 WL_ERR(("drop frame GON Req Rx : count (%d)\n",
14214 cfg->block_gon_req_rx_count));
14215 cfg->block_gon_req_rx_count--;
14216 goto exit;
14217 }
14218 } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
14219 /* if go formation done, clear it */
14220 cfg->block_gon_req_tx_count = 0;
14221 cfg->block_gon_req_rx_count = 0;
14222 }
14223 #endif /* WL_CFG80211_GON_COLLISION */
14224
14225 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
14226 if (cfg->next_af_subtype == act_frm->subtype) {
14227 WL_DBG(("We got a right next frame!(%d)\n",
14228 act_frm->subtype));
14229 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14230
14231 if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
14232 OSL_SLEEP(20);
14233 }
14234
14235 /* Stop waiting for next AF. */
14236 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14237 } else if ((cfg->next_af_subtype == P2P_PAF_GON_RSP) &&
14238 (act_frm->subtype == P2P_PAF_GON_REQ)) {
14239 /* If current received frame is GO NEG REQ and next
14240 * expected frame is GO NEG RESP, do not send it up.
14241 */
14242 WL_ERR(("GO Neg req received while waiting for RESP."
14243 "Discard incoming frame\n"));
14244 goto exit;
14245 }
14246 }
14247 }
14248
14249 if (wl_cfg80211_is_dpp_frame(
14250 (void *)&mgmt_frame[DOT11_MGMT_HDR_LEN],
14251 mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
14252 wl_dpp_pa_frame_t *pa =
14253 (wl_dpp_pa_frame_t *)&mgmt_frame[DOT11_MGMT_HDR_LEN];
14254 if (cfg->next_af_subtype == pa->ftype) {
14255 WL_DBG(("matching dpp frm (%d) found. abort dwell\n", pa->ftype));
14256 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
14257
14258 /* Stop waiting for next AF. */
14259 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
14260 }
14261 }
14262 if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
14263 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
14264 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
14265 }
14266 } else if (event == WLC_E_PROBREQ_MSG) {
14267
14268 /* Handle probe reqs frame
14269 * WPS-AP certification 4.2.13
14270 */
14271 struct parsed_ies prbreq_ies;
14272 u32 prbreq_ie_len = 0;
14273 bool pbc = 0;
14274
14275 WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
14276 mgmt_frame = (u8 *)(data);
14277 mgmt_frame_len = ntoh32(e->datalen);
14278 if (mgmt_frame_len < DOT11_MGMT_HDR_LEN) {
14279 WL_ERR(("wrong datalen:%d\n", mgmt_frame_len));
14280 return -EINVAL;
14281 }
14282 prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
14283
14284 /* Parse prob_req IEs */
14285 if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
14286 prbreq_ie_len, &prbreq_ies) < 0) {
14287 WL_ERR(("Prob req get IEs failed\n"));
14288 return 0;
14289 }
14290
14291 if (prbreq_ies.wps_ie != NULL) {
14292 wl_validate_wps_ie(
14293 (const char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
14294 WL_DBG((" wps_ie exist pbc = %d\n", pbc));
14295 /* if pbc method, send prob_req mgmt frame to upper layer */
14296 if (!pbc)
14297 return 0;
14298 } else
14299 return 0;
14300 } else {
14301 mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
14302
14303 /* wpa supplicant use probe request event for restarting another GON Req.
14304 * but it makes GON Req repetition.
14305 * so if src addr of prb req is same as my target device,
14306 * do not send probe request event during sending action frame.
14307 */
14308 if (event == WLC_E_P2P_PROBREQ_MSG) {
14309 WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
14310 "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
14311
14312 #ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
14313 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) &&
14314 !memcmp(cfg->afx_hdl->tx_dst_addr.octet, e->addr.octet,
14315 ETHER_ADDR_LEN)) {
14316 if (cfg->afx_hdl->pending_tx_act_frm &&
14317 wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
14318 chanspec_t channel = hton16(rxframe->channel);
14319 WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
14320 channel));
14321 cfg->afx_hdl->peer_chan = channel;
14322 complete(&cfg->act_frm_scan);
14323 }
14324 }
14325 #endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
14326
14327 /* Filter any P2P probe reqs arriving during the
14328 * GO-NEG Phase
14329 */
14330 if (cfg->p2p &&
14331 #if defined(P2P_IE_MISSING_FIX)
14332 cfg->p2p_prb_noti &&
14333 #endif
14334 wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
14335 WL_DBG(("Filtering P2P probe_req while "
14336 "being in GO-Neg state\n"));
14337 return 0;
14338 }
14339 }
14340 }
14341
14342 if (discover_cfgdev(cfgdev, cfg))
14343 WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
14344 else
14345 WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
14346 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
14347 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
14348 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
14349 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
14350 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14351 defined(WL_COMPAT_WIRELESS)
14352 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
14353 #else
14354 cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
14355 #endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
14356
14357 WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
14358 mgmt_frame_len, ntoh32(e->datalen), CHSPEC_CHANNEL(chspec), freq));
14359 exit:
14360 if (isfree) {
14361 MFREE(cfg->osh, mgmt_frame, mgmt_frame_len);
14362 }
14363 return err;
14364 }
14365
14366 #ifdef CUSTOMER_HW6
14367 static s32
wl_cfg80211_ccode_evt_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * event,void * data)14368 wl_cfg80211_ccode_evt_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
14369 const wl_event_msg_t *event, void *data)
14370 {
14371 s32 err = 0;
14372 /* Indicate to upper layer for regdom change */
14373 WL_INFORM_MEM(("Received country code change event\n"));
14374 err = wl_update_wiphybands(cfg, true);
14375
14376 return err;
14377 }
14378 #endif /* CUSTOMER_HW6 */
14379
wl_init_conf(struct wl_conf * conf)14380 static void wl_init_conf(struct wl_conf *conf)
14381 {
14382 WL_DBG(("Enter \n"));
14383 conf->frag_threshold = (u32)-1;
14384 conf->rts_threshold = (u32)-1;
14385 conf->retry_short = (u32)-1;
14386 conf->retry_long = (u32)-1;
14387 conf->tx_power = -1;
14388 }
14389
wl_init_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev)14390 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
14391 {
14392 unsigned long flags;
14393 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
14394
14395 if (!profile) {
14396 WL_ERR(("profile null\n"));
14397 return;
14398 }
14399
14400 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
14401 bzero(profile, sizeof(struct wl_profile));
14402 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
14403 }
14404
wl_init_event_handler(struct bcm_cfg80211 * cfg)14405 static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
14406 {
14407 bzero(cfg->evt_handler, sizeof(cfg->evt_handler));
14408
14409 cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
14410 cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
14411 cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
14412 cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
14413 cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
14414 cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
14415 cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
14416 cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
14417 cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
14418 cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
14419 cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
14420 cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
14421 cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
14422 cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
14423 cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
14424 cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
14425 cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
14426 cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
14427 cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
14428 cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
14429 cfg->evt_handler[WLC_E_AUTH_IND] = wl_notify_connect_status;
14430 cfg->evt_handler[WLC_E_ASSOC_RESP_IE] = wl_notify_connect_status;
14431 #ifdef PNO_SUPPORT
14432 cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
14433 #endif /* PNO_SUPPORT */
14434 #ifdef GSCAN_SUPPORT
14435 cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
14436 cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
14437 cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
14438 cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
14439 cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
14440 cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
14441 cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
14442 cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
14443 #endif /* GSCAN_SUPPORT */
14444 #ifdef RSSI_MONITOR_SUPPORT
14445 cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
14446 #endif /* RSSI_MONITOR_SUPPORT */
14447 #ifdef WL_SDO
14448 cfg->evt_handler[WLC_E_SERVICE_FOUND] = wl_svc_resp_handler;
14449 cfg->evt_handler[WLC_E_P2PO_ADD_DEVICE] = wl_notify_device_discovery;
14450 cfg->evt_handler[WLC_E_P2PO_DEL_DEVICE] = wl_notify_device_discovery;
14451 #endif
14452 #ifdef WLTDLS
14453 cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
14454 #endif /* WLTDLS */
14455 cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
14456 #ifdef WLAIBSS
14457 cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail;
14458 #endif /* WLAIBSS */
14459 #ifdef WL_RELMCAST
14460 cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
14461 #endif /* WL_RELMCAST */
14462 #ifdef BT_WIFI_HANDOVER
14463 cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
14464 #endif
14465 #ifdef WL_NAN
14466 cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status;
14467 cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status;
14468 #endif /* WL_NAN */
14469 cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
14470 cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
14471 #ifdef CUSTOM_EVENT_PM_WAKE
14472 cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
14473 #endif /* CUSTOM_EVENT_PM_WAKE */
14474 #if defined(DHD_LOSSLESS_ROAMING) || defined (DBG_PKT_MON)
14475 cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
14476 #endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
14477 cfg->evt_handler[WLC_E_ROAM_START] = wl_notify_roam_start_status;
14478 #ifdef WL_BAM
14479 cfg->evt_handler[WLC_E_ADPS] = wl_adps_event_handler;
14480 #endif /* WL_BAM */
14481 cfg->evt_handler[WLC_E_PSK_SUP] = wl_cfg80211_sup_event_handler;
14482 #ifdef CUSTOMER_HW6
14483 cfg->evt_handler[WLC_E_COUNTRY_CODE_CHANGED] = wl_cfg80211_ccode_evt_handler;
14484 #endif /* CUSTOMER_HW6 */
14485 #ifdef WL_BCNRECV
14486 cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
14487 #endif /* WL_BCNRECV */
14488 #ifdef WL_MBO
14489 cfg->evt_handler[WLC_E_MBO] = wl_mbo_event_handler;
14490 #endif /* WL_MBO */
14491 #ifdef WL_CAC_TS
14492 cfg->evt_handler[WLC_E_ADDTS_IND] = wl_cfg80211_cac_event_handler;
14493 cfg->evt_handler[WLC_E_DELTS_IND] = wl_cfg80211_cac_event_handler;
14494 #endif /* WL_CAC_TS */
14495 #if defined(WL_MBO) || defined(WL_OCE)
14496 cfg->evt_handler[WLC_E_PRUNE] = wl_bssid_prune_event_handler;
14497 #endif /* WL_MBO || WL_OCE */
14498 #ifdef RTT_SUPPORT
14499 cfg->evt_handler[WLC_E_PROXD] = wl_cfg80211_rtt_event_handler;
14500 #endif
14501 #ifdef WL_CHAN_UTIL
14502 cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler;
14503 #endif /* WL_CHAN_UTIL */
14504 #ifdef WL_TWT
14505 cfg->evt_handler[WLC_E_TWT_SETUP] = wl_notify_twt_event;
14506 cfg->evt_handler[WLC_E_TWT_TEARDOWN] = wl_notify_twt_event;
14507 cfg->evt_handler[WLC_E_TWT_INFO_FRM] = wl_notify_twt_event;
14508 #endif /* WL_TWT */
14509 #ifdef WL_CLIENT_SAE
14510 cfg->evt_handler[WLC_E_JOIN_START] = wl_notify_start_auth;
14511 #endif /* WL_CLIENT_SAE */
14512 }
14513
14514 #if defined(STATIC_WL_PRIV_STRUCT)
14515 static int
wl_init_escan_result_buf(struct bcm_cfg80211 * cfg)14516 wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
14517 {
14518 #ifdef DUAL_ESCAN_RESULT_BUFFER
14519 cfg->escan_info.escan_buf[0] = DHD_OS_PREALLOC(cfg->pub,
14520 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
14521 if (cfg->escan_info.escan_buf[0] == NULL) {
14522 WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
14523 return -ENOMEM;
14524 }
14525
14526 cfg->escan_info.escan_buf[1] = DHD_OS_PREALLOC(cfg->pub,
14527 DHD_PREALLOC_WIPHY_ESCAN1, ESCAN_BUF_SIZE);
14528 if (cfg->escan_info.escan_buf[1] == NULL) {
14529 WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
14530 return -ENOMEM;
14531 }
14532
14533 bzero(cfg->escan_info.escan_buf[0], ESCAN_BUF_SIZE);
14534 bzero(cfg->escan_info.escan_buf[1], ESCAN_BUF_SIZE);
14535 cfg->escan_info.escan_type[0] = 0;
14536 cfg->escan_info.escan_type[1] = 0;
14537 #else
14538 cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
14539 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
14540 if (cfg->escan_info.escan_buf == NULL) {
14541 WL_ERR(("Failed to alloc ESCAN_BUF\n"));
14542 return -ENOMEM;
14543 }
14544 bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
14545 #endif /* DUAL_ESCAN_RESULT_BUFFER */
14546
14547 return 0;
14548 }
14549
14550 static void
wl_deinit_escan_result_buf(struct bcm_cfg80211 * cfg)14551 wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
14552 {
14553 #ifdef DUAL_ESCAN_RESULT_BUFFER
14554 if (cfg->escan_info.escan_buf[0] != NULL) {
14555 cfg->escan_info.escan_buf[0] = NULL;
14556 cfg->escan_info.escan_type[0] = 0;
14557 }
14558
14559 if (cfg->escan_info.escan_buf[1] != NULL) {
14560 cfg->escan_info.escan_buf[1] = NULL;
14561 cfg->escan_info.escan_type[1] = 0;
14562 }
14563 #else
14564 if (cfg->escan_info.escan_buf != NULL) {
14565 cfg->escan_info.escan_buf = NULL;
14566 }
14567 #endif /* DUAL_ESCAN_RESULT_BUFFER */
14568 }
14569 #endif /* STATIC_WL_PRIV_STRUCT */
14570
wl_init_priv_mem(struct bcm_cfg80211 * cfg)14571 static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
14572 {
14573 WL_DBG(("Enter \n"));
14574
14575 cfg->scan_results = (wl_scan_results_t *)MALLOCZ(cfg->osh,
14576 WL_SCAN_BUF_MAX);
14577 if (unlikely(!cfg->scan_results)) {
14578 WL_ERR(("Scan results alloc failed\n"));
14579 goto init_priv_mem_out;
14580 }
14581 cfg->conf = (struct wl_conf *)MALLOCZ(cfg->osh, sizeof(*cfg->conf));
14582 if (unlikely(!cfg->conf)) {
14583 WL_ERR(("wl_conf alloc failed\n"));
14584 goto init_priv_mem_out;
14585 }
14586 cfg->scan_req_int = (void *)MALLOCZ(cfg->osh,
14587 sizeof(*cfg->scan_req_int));
14588 if (unlikely(!cfg->scan_req_int)) {
14589 WL_ERR(("Scan req alloc failed\n"));
14590 goto init_priv_mem_out;
14591 }
14592 cfg->ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
14593 if (unlikely(!cfg->ioctl_buf)) {
14594 WL_ERR(("Ioctl buf alloc failed\n"));
14595 goto init_priv_mem_out;
14596 }
14597 cfg->escan_ioctl_buf = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
14598 if (unlikely(!cfg->escan_ioctl_buf)) {
14599 WL_ERR(("Ioctl buf alloc failed\n"));
14600 goto init_priv_mem_out;
14601 }
14602 cfg->extra_buf = (void *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
14603 if (unlikely(!cfg->extra_buf)) {
14604 WL_ERR(("Extra buf alloc failed\n"));
14605 goto init_priv_mem_out;
14606 }
14607 cfg->pmk_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->pmk_list));
14608 if (unlikely(!cfg->pmk_list)) {
14609 WL_ERR(("pmk list alloc failed\n"));
14610 goto init_priv_mem_out;
14611 }
14612 #if defined(STATIC_WL_PRIV_STRUCT)
14613 cfg->conn_info = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->conn_info));
14614 if (unlikely(!cfg->conn_info)) {
14615 WL_ERR(("cfg->conn_info alloc failed\n"));
14616 goto init_priv_mem_out;
14617 }
14618 cfg->ie = (void *)MALLOC(cfg->osh, sizeof(*cfg->ie));
14619 if (unlikely(!cfg->ie)) {
14620 WL_ERR(("cfg->ie alloc failed\n"));
14621 goto init_priv_mem_out;
14622 }
14623 if (unlikely(wl_init_escan_result_buf(cfg))) {
14624 WL_ERR(("Failed to init escan resul buf\n"));
14625 goto init_priv_mem_out;
14626 }
14627 #endif /* STATIC_WL_PRIV_STRUCT */
14628 cfg->afx_hdl = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->afx_hdl));
14629 if (unlikely(!cfg->afx_hdl)) {
14630 WL_ERR(("afx hdl alloc failed\n"));
14631 goto init_priv_mem_out;
14632 } else {
14633 init_completion(&cfg->act_frm_scan);
14634 init_completion(&cfg->wait_next_af);
14635
14636 INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
14637 }
14638 #ifdef WLTDLS
14639 if (cfg->tdls_mgmt_frame) {
14640 MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
14641 cfg->tdls_mgmt_frame = NULL;
14642 cfg->tdls_mgmt_frame_len = 0;
14643 }
14644 #endif /* WLTDLS */
14645 cfg->spmk_info_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->spmk_info_list));
14646 if (unlikely(!cfg->spmk_info_list)) {
14647 WL_ERR(("Single PMK info list allocation falure\n"));
14648 goto init_priv_mem_out;
14649 }
14650
14651 return 0;
14652
14653 init_priv_mem_out:
14654 wl_deinit_priv_mem(cfg);
14655
14656 return -ENOMEM;
14657 }
14658
wl_deinit_priv_mem(struct bcm_cfg80211 * cfg)14659 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
14660 {
14661 MFREE(cfg->osh, cfg->scan_results, WL_SCAN_BUF_MAX);
14662 MFREE(cfg->osh, cfg->conf, sizeof(*cfg->conf));
14663 MFREE(cfg->osh, cfg->scan_req_int, sizeof(*cfg->scan_req_int));
14664 MFREE(cfg->osh, cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
14665 MFREE(cfg->osh, cfg->escan_ioctl_buf, WLC_IOCTL_MAXLEN);
14666 MFREE(cfg->osh, cfg->extra_buf, WL_EXTRA_BUF_MAX);
14667 MFREE(cfg->osh, cfg->pmk_list, sizeof(*cfg->pmk_list));
14668 #if defined(STATIC_WL_PRIV_STRUCT)
14669 MFREE(cfg->osh, cfg->conn_info, sizeof(*cfg->conn_info));
14670 MFREE(cfg->osh, cfg->ie, sizeof(*cfg->ie));
14671 wl_deinit_escan_result_buf(cfg);
14672 #endif /* STATIC_WL_PRIV_STRUCT */
14673 if (cfg->afx_hdl) {
14674 #if defined(BCMDONGLEHOST)
14675 cancel_work_sync(&cfg->afx_hdl->work);
14676 #endif
14677 MFREE(cfg->osh, cfg->afx_hdl, sizeof(*cfg->afx_hdl));
14678 }
14679 MFREE(cfg->osh, cfg->spmk_info_list, sizeof(*cfg->spmk_info_list));
14680
14681 }
14682
wl_create_event_handler(struct bcm_cfg80211 * cfg)14683 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
14684 {
14685 int ret = 0;
14686 WL_DBG(("Enter \n"));
14687
14688 /* making separate work queue needs GPL license,
14689 * but some drivers are not in GPL license, so, making seperate queue Android only
14690 */
14691
14692 #ifdef OEM_ANDROID
14693 /* Allocate workqueue for event */
14694 if (!cfg->event_workq) {
14695 cfg->event_workq = alloc_workqueue("dhd_eventd",
14696 WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 1);
14697 }
14698
14699 if (!cfg->event_workq) {
14700 WL_ERR(("event_workq alloc_workqueue failed\n"));
14701 ret = -ENOMEM;
14702 } else {
14703 INIT_WORK(&cfg->event_work, wl_event_handler);
14704 }
14705 #endif /* OEM_ANDROID */
14706
14707 #ifndef OEM_ANDROID
14708 INIT_WORK(&cfg->event_work, wl_event_handler);
14709 cfg->event_workq_init = true;
14710 #endif /* OEM_ANDROID */
14711 return ret;
14712 }
14713
wl_destroy_event_handler(struct bcm_cfg80211 * cfg)14714 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
14715 {
14716
14717 #ifdef OEM_ANDROID
14718 if (cfg && cfg->event_workq) {
14719 cancel_work_sync(&cfg->event_work);
14720 destroy_workqueue(cfg->event_workq);
14721 cfg->event_workq = NULL;
14722 }
14723 #endif /* OEM_ANDROID */
14724
14725 #ifndef OEM_ANDROID
14726 if (cfg && cfg->event_workq_init) {
14727 #ifdef BCMDONGLEHOST
14728 cancel_work_sync(&cfg->event_work);
14729 #endif /* BCMDONGLEHOST */
14730 cfg->event_workq_init = false;
14731 }
14732 #endif /* OEM_ANDROID */
14733 }
14734
wl_terminate_event_handler(struct net_device * dev)14735 void wl_terminate_event_handler(struct net_device *dev)
14736 {
14737 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
14738
14739 if (cfg) {
14740 wl_destroy_event_handler(cfg);
14741 wl_flush_eq(cfg);
14742 }
14743 }
14744
14745 #ifdef DHD_LOSSLESS_ROAMING
wl_del_roam_timeout(struct bcm_cfg80211 * cfg)14746 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
14747 {
14748 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14749
14750 /* restore prec_map to ALLPRIO */
14751 dhdp->dequeue_prec_map = ALLPRIO;
14752 del_timer_sync(&cfg->roam_timeout);
14753 }
14754
wl_roam_timeout(unsigned long data)14755 static void wl_roam_timeout(unsigned long data)
14756 {
14757 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
14758 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14759
14760 WL_ERR(("roam timer expired\n"));
14761
14762 /* restore prec_map to ALLPRIO */
14763 dhdp->dequeue_prec_map = ALLPRIO;
14764 }
14765
14766 #endif /* DHD_LOSSLESS_ROAMING */
14767
14768 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
14769 #define CP_CHAN_INFO_RAT_MODE_LTE 3
14770 #define CP_CHAN_INFO_RAT_MODE_NR5G 7
14771 int g_mhs_chan_for_cpcoex = 0;
14772
14773 struct __packed cam_cp_noti_info {
14774 u8 rat;
14775 u32 band;
14776 u32 channel;
14777 };
14778
14779 int
wl_cfg80211_send_msg_to_ril()14780 wl_cfg80211_send_msg_to_ril()
14781 {
14782 int id, buf = 1;
14783
14784 id = IPC_SYSTEM_CP_CHANNEL_INFO;
14785 dev_ril_bridge_send_msg(id, sizeof(int), &buf);
14786 WL_ERR(("[BeyondX] send message to ril.\n"));
14787
14788 OSL_SLEEP(500);
14789 return 0;
14790 }
14791
14792 int
wl_cfg80211_ril_bridge_notifier_call(struct notifier_block * nb,unsigned long size,void * buf)14793 wl_cfg80211_ril_bridge_notifier_call(struct notifier_block *nb,
14794 unsigned long size, void *buf)
14795 {
14796 struct dev_ril_bridge_msg *msg;
14797 struct cam_cp_noti_info *cp_noti_info;
14798 static int mhs_channel_for_4g, mhs_channel_for_5g;
14799 static int recv_msg_4g, recv_msg_5g;
14800
14801 WL_ERR(("[BeyondX] receive message from ril.\n"));
14802 msg = (struct dev_ril_bridge_msg *)buf;
14803
14804 if (msg->dev_id == IPC_SYSTEM_CP_CHANNEL_INFO &&
14805 msg->data_len <= sizeof(struct cam_cp_noti_info)) {
14806 u8 rat;
14807 u32 band;
14808 u32 channel;
14809
14810 cp_noti_info = (struct cam_cp_noti_info *)msg->data;
14811 rat = cp_noti_info->rat;
14812 band = cp_noti_info->band;
14813 channel = cp_noti_info->channel;
14814
14815 /* LTE/5G Band/Freq information => Mobile Hotspot channel mapping.
14816 * LTE/B40: 38650~39649 => Ch.11
14817 * LTE/B41: 39650~41589 => Ch.1
14818 * 5G/N41: 499200~537999 => Ch.1
14819 */
14820 if (rat == CP_CHAN_INFO_RAT_MODE_LTE) {
14821 recv_msg_4g = 1;
14822 if (channel >= 38650 && channel <= 39649) {
14823 mhs_channel_for_4g = 11;
14824 } else if (channel >= 39650 && channel <= 41589) {
14825 mhs_channel_for_4g = 1;
14826 }
14827 }
14828 if (rat == CP_CHAN_INFO_RAT_MODE_NR5G) {
14829 recv_msg_5g = 1;
14830 if (channel >= 499200 && channel <= 537999) {
14831 mhs_channel_for_5g = 1;
14832 }
14833 }
14834
14835 WL_DBG(("[BeyondX] rat: %u, band: %u, channel: %u, mhs_channel_for_4g: %u, "
14836 "mhs_channel_for_5g: %u\n", rat, band, channel,
14837 mhs_channel_for_4g, mhs_channel_for_5g));
14838
14839 if (recv_msg_4g && recv_msg_5g) {
14840 if (mhs_channel_for_4g && mhs_channel_for_5g) {
14841 /* if 4G/B40 + 5G/N41, select channel 6 for MHS */
14842 if (mhs_channel_for_4g == 11 && mhs_channel_for_5g == 1) {
14843 g_mhs_chan_for_cpcoex = 6;
14844 /* if 4G(except for B40) + 5G/N41, select channel 1 for MHS */
14845 } else {
14846 g_mhs_chan_for_cpcoex = 1;
14847 }
14848 } else {
14849 g_mhs_chan_for_cpcoex = mhs_channel_for_4g ? mhs_channel_for_4g :
14850 mhs_channel_for_5g ? mhs_channel_for_5g : 0;
14851 }
14852 mhs_channel_for_4g = mhs_channel_for_5g = 0;
14853 recv_msg_4g = recv_msg_5g = 0;
14854 }
14855 }
14856
14857 return 0;
14858 }
14859
14860 static struct notifier_block wl_cfg80211_ril_bridge_notifier = {
14861 .notifier_call = wl_cfg80211_ril_bridge_notifier_call,
14862 };
14863
14864 static bool wl_cfg80211_ril_bridge_notifier_registered = FALSE;
14865 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
14866
14867 static s32
wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,unsigned long state,void * ptr)14868 wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
14869 unsigned long state, void *ptr)
14870 {
14871 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
14872 struct net_device *dev = ptr;
14873 #else
14874 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
14875 #endif /* LINUX_VERSION < VERSION(3, 11, 0) */
14876 struct wireless_dev *wdev = NULL;
14877 struct bcm_cfg80211 *cfg = NULL;
14878
14879 WL_DBG(("Enter state:%lu ndev%p \n", state, dev));
14880 if (!dev) {
14881 WL_ERR(("dev null\n"));
14882 return NOTIFY_DONE;
14883 }
14884
14885 wdev = ndev_to_wdev(dev);
14886 if (!wdev) {
14887 WL_ERR(("wdev null. Do nothing\n"));
14888 return NOTIFY_DONE;
14889 }
14890
14891 cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
14892 if (!cfg || (cfg != wl_cfg80211_get_bcmcfg())) {
14893 /* If cfg80211 priv is null or doesn't match return */
14894 WL_ERR(("wrong cfg ptr (%p)\n", cfg));
14895 return NOTIFY_DONE;
14896 }
14897
14898 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
14899 /* Nothing to be done for primary I/F */
14900 return NOTIFY_DONE;
14901 }
14902
14903 switch (state) {
14904 case NETDEV_DOWN:
14905 {
14906 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
14907 int max_wait_timeout = 2;
14908 int max_wait_count = 100;
14909 int refcnt = 0;
14910 unsigned long limit = jiffies + max_wait_timeout * HZ;
14911 while (work_pending(&wdev->cleanup_work)) {
14912 if (refcnt%5 == 0) {
14913 WL_ERR(("[NETDEV_DOWN] wait for "
14914 "complete of cleanup_work"
14915 " (%d th)\n", refcnt));
14916 }
14917 if (!time_before(jiffies, limit)) {
14918 WL_ERR(("[NETDEV_DOWN] cleanup_work"
14919 " of CFG80211 is not"
14920 " completed in %d sec\n",
14921 max_wait_timeout));
14922 break;
14923 }
14924 if (refcnt >= max_wait_count) {
14925 WL_ERR(("[NETDEV_DOWN] cleanup_work"
14926 " of CFG80211 is not"
14927 " completed in %d loop\n",
14928 max_wait_count));
14929 break;
14930 }
14931 set_current_state(TASK_INTERRUPTIBLE);
14932 (void)schedule_timeout(100);
14933 set_current_state(TASK_RUNNING);
14934 refcnt++;
14935 }
14936 #endif /* LINUX_VERSION < VERSION(3, 14, 0) */
14937 break;
14938 }
14939 case NETDEV_UNREGISTER:
14940 wl_cfg80211_clear_per_bss_ies(cfg, wdev);
14941 /* after calling list_del_rcu(&wdev->list) */
14942 wl_dealloc_netinfo_by_wdev(cfg, wdev);
14943 break;
14944 case NETDEV_GOING_DOWN:
14945 /*
14946 * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
14947 * In front of door, the function checks whether current scan
14948 * is working or not. If the scanning is still working,
14949 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
14950 */
14951 if (wl_get_drv_status(cfg, SCANNING, dev))
14952 wl_cfgscan_cancel_scan(cfg);
14953 break;
14954 }
14955 return NOTIFY_DONE;
14956 }
14957
14958 static struct notifier_block wl_cfg80211_netdev_notifier = {
14959 .notifier_call = wl_cfg80211_netdev_notifier_call,
14960 };
14961
14962 /*
14963 * to make sure we won't register the same notifier twice, otherwise a loop is likely to be
14964 * created in kernel notifier link list (with 'next' pointing to itself)
14965 */
14966 static bool wl_cfg80211_netdev_notifier_registered = FALSE;
14967
wl_cfg80211_concurrent_roam(struct bcm_cfg80211 * cfg,int enable)14968 void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
14969 {
14970 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
14971 bool p2p_connected = wl_cfgp2p_vif_created(cfg);
14972 #ifdef WL_NAN
14973 bool nan_connected = wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg));
14974 #endif /* WL_NAN */
14975 struct net_info *iter, *next;
14976
14977 if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT))
14978 return;
14979
14980 WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
14981 enable, p2p_connected, connected_cnt));
14982 /* Disable FW roam when we have a concurrent P2P connection */
14983 if (enable &&
14984 ((p2p_connected && connected_cnt > 1) ||
14985 #ifdef WL_NAN
14986 nan_connected ||
14987 #endif /* WL_NAN */
14988 FALSE)) {
14989
14990 /* Mark it as to be reverted */
14991 cfg->roam_flags |= WL_ROAM_REVERT_STATUS;
14992 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
14993 for_each_ndev(cfg, iter, next) {
14994 GCC_DIAGNOSTIC_POP();
14995 if (iter->ndev && iter->wdev &&
14996 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
14997 if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE)
14998 == BCME_OK) {
14999 iter->roam_off = TRUE;
15000 }
15001 else {
15002 WL_ERR(("error to enable roam_off\n"));
15003 }
15004 }
15005 }
15006 }
15007 else if (!enable && (cfg->roam_flags & WL_ROAM_REVERT_STATUS)) {
15008 cfg->roam_flags &= ~WL_ROAM_REVERT_STATUS;
15009 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
15010 for_each_ndev(cfg, iter, next) {
15011 GCC_DIAGNOSTIC_POP();
15012 if (iter->ndev && iter->wdev &&
15013 iter->wdev->iftype == NL80211_IFTYPE_STATION) {
15014 if (iter->roam_off != WL_INVALID) {
15015 if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE)
15016 == BCME_OK) {
15017 iter->roam_off = FALSE;
15018 }
15019 else {
15020 WL_ERR(("error to disable roam_off\n"));
15021 }
15022 }
15023 }
15024 }
15025 }
15026
15027 return;
15028 }
15029
wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 * cfg)15030 static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
15031 {
15032 struct net_info *iter, *next;
15033 #ifdef WLEASYMESH
15034 struct net_device *primary_dev;
15035 dhd_pub_t *dhd = cfg->pub;
15036 #endif /* WLEASYMESH */
15037 u32 ctl_chan = 0;
15038 u32 chanspec = 0;
15039 u32 pre_ctl_chan = 0;
15040 u32 band = 0;
15041 u32 pre_band = 0;
15042 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
15043 cfg->vsdb_mode = false;
15044
15045 if (connected_cnt <= 1) {
15046 return;
15047 }
15048 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
15049 for_each_ndev(cfg, iter, next) {
15050 GCC_DIAGNOSTIC_POP();
15051 /* p2p discovery iface ndev could be null */
15052 if (iter->ndev) {
15053 chanspec = 0;
15054 ctl_chan = 0;
15055 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
15056 if (wldev_iovar_getint(iter->ndev, "chanspec",
15057 (s32 *)&chanspec) == BCME_OK) {
15058 chanspec = wl_chspec_driver_to_host(chanspec);
15059 ctl_chan = wf_chspec_ctlchan(chanspec);
15060 band = CHSPEC_BAND(chanspec);
15061 wl_update_prof(cfg, iter->ndev, NULL,
15062 &chanspec, WL_PROF_CHAN);
15063 }
15064 if (!cfg->vsdb_mode) {
15065 if (!pre_ctl_chan && ctl_chan) {
15066 pre_ctl_chan = ctl_chan;
15067 pre_band = band;
15068 } else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan) &&
15069 (band == pre_band)) {
15070 cfg->vsdb_mode = true;
15071 }
15072 }
15073 }
15074 }
15075 }
15076 #ifdef WLEASYMESH
15077 if(dhd->conf->fw_type == FW_TYPE_EZMESH && cfg->vsdb_mode) {
15078 primary_dev = bcmcfg_to_prmry_ndev(cfg);
15079 WL_MSG("wlan", "check primary chanspec\n");
15080 if (wldev_iovar_getint(primary_dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
15081 //chanspec = wl_chspec_driver_to_host(chanspec);
15082 WL_MSG("wlan", "set primary chanspec to 0x%d\n", chanspec);
15083 wldev_iovar_setint(primary_dev, "chanspec", chanspec);
15084 }
15085 cfg->vsdb_mode = false;
15086 }
15087 #endif /* WLEASYMESH*/
15088 WL_MSG("wlan", "%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel");
15089 return;
15090 }
15091
15092 int
wl_cfg80211_determine_p2p_rsdb_scc_mode(struct bcm_cfg80211 * cfg)15093 wl_cfg80211_determine_p2p_rsdb_scc_mode(struct bcm_cfg80211 *cfg)
15094 {
15095 struct net_info *iter, *next;
15096 u32 chanspec = 0;
15097 u32 pre_chanspec = 0;
15098 u32 band = 0;
15099 u32 pre_band = INVCHANSPEC;
15100 bool is_rsdb_supported = FALSE;
15101 bool rsdb_or_scc_mode = FALSE;
15102
15103 #ifdef BCMDONGLEHOST
15104 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
15105 #endif /* BCMDONGLEHOST */
15106
15107 if (!is_rsdb_supported) {
15108 return 0;
15109 }
15110
15111 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
15112 for_each_ndev(cfg, iter, next) {
15113 GCC_DIAGNOSTIC_POP();
15114 /* p2p discovery iface ndev could be null */
15115 if (iter->ndev) {
15116 chanspec = 0;
15117 band = 0;
15118 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
15119 if (wldev_iovar_getint(iter->ndev, "chanspec",
15120 (s32 *)&chanspec) == BCME_OK) {
15121 chanspec = wl_chspec_driver_to_host(chanspec);
15122 band = CHSPEC_BAND(chanspec);
15123 }
15124
15125 if (pre_band == INVCHANSPEC && chanspec) {
15126 pre_band = band;
15127 pre_chanspec = chanspec;
15128 } else {
15129 if ((pre_band == band) && (pre_chanspec != chanspec)) {
15130 /* VSDB case */
15131 rsdb_or_scc_mode = FALSE;
15132 } else {
15133 /* RSDB/SCC case */
15134 rsdb_or_scc_mode = TRUE;
15135 }
15136 }
15137 }
15138 }
15139 }
15140 WL_DBG(("RSDB or SCC mode is %s\n", rsdb_or_scc_mode ? "enabled" : "disabled"));
15141
15142 return rsdb_or_scc_mode;
15143 }
15144
wl_notifier_change_state(struct bcm_cfg80211 * cfg,struct net_info * _net_info,enum wl_status state,bool set)15145 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
15146 enum wl_status state, bool set)
15147 {
15148 s32 pm = PM_FAST;
15149 s32 err = BCME_OK;
15150 u32 mode;
15151 chanspec_t chspec = 0;
15152 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
15153 #ifdef BCMDONGLEHOST
15154 dhd_pub_t *dhd = cfg->pub;
15155 #endif /* BCMDONGLEHOST */
15156 #ifdef RTT_SUPPORT
15157 rtt_status_info_t *rtt_status;
15158 #endif /* RTT_SUPPORT */
15159 #ifdef DISABLE_FRAMEBURST_VSDB
15160 bool rsdb_scc_flag = FALSE;
15161 #endif /* DISABLE_FRAMEBURST_VSDB */
15162 #ifdef BCMDONGLEHOST
15163 if (dhd->busstate == DHD_BUS_DOWN) {
15164 WL_ERR(("busstate is DHD_BUS_DOWN!\n"));
15165 return 0;
15166 }
15167 #endif /* BCMDONGLEHOST */
15168 WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
15169 state, set, _net_info->pm_restore, _net_info->ndev->name));
15170
15171 if (state != WL_STATUS_CONNECTED)
15172 return 0;
15173 mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
15174 if (set) {
15175 wl_cfg80211_concurrent_roam(cfg, 1);
15176 wl_cfg80211_determine_vsdb_mode(cfg);
15177 if (mode == WL_MODE_AP) {
15178 if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
15179 WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
15180 }
15181 pm = PM_OFF;
15182 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
15183 sizeof(pm))) != 0) {
15184 if (err == -ENODEV)
15185 WL_DBG(("%s:netdev not ready\n",
15186 _net_info->ndev->name));
15187 else
15188 WL_ERR(("%s:error (%d)\n",
15189 _net_info->ndev->name, err));
15190
15191 wl_cfg80211_update_power_mode(_net_info->ndev);
15192 }
15193 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
15194 #if defined(WLTDLS)
15195 if (wl_cfg80211_is_concurrent_mode(primary_dev)) {
15196 err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
15197 }
15198 #endif /* defined(WLTDLS) */
15199
15200 #ifdef BCMDONGLEHOST
15201 #ifdef DISABLE_FRAMEBURST_VSDB
15202 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
15203 wl_cfg80211_is_concurrent_mode(primary_dev)) {
15204 rsdb_scc_flag = wl_cfg80211_determine_p2p_rsdb_scc_mode(cfg);
15205 wl_cfg80211_set_frameburst(cfg, rsdb_scc_flag);
15206 }
15207 #endif /* DISABLE_FRAMEBURST_VSDB */
15208 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
15209 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
15210 wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
15211 /* Enable frameburst for
15212 * STA/SoftAP concurrent mode
15213 */
15214 wl_cfg80211_set_frameburst(cfg, TRUE);
15215 }
15216 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
15217 #endif /* BCMDONGLEHOST */
15218 } else { /* clear */
15219 chspec = INVCHANSPEC;
15220 /* clear chan information when the net device is disconnected */
15221 wl_update_prof(cfg, _net_info->ndev, NULL, &chspec, WL_PROF_CHAN);
15222 wl_cfg80211_determine_vsdb_mode(cfg);
15223 if (primary_dev == _net_info->ndev) {
15224 pm = PM_FAST;
15225 #ifdef RTT_SUPPORT
15226 rtt_status = GET_RTTSTATE(dhd);
15227 if (rtt_status->status != RTT_ENABLED) {
15228 #endif /* RTT_SUPPORT */
15229 if (dhd_conf_get_pm(dhd) >= 0)
15230 pm = dhd_conf_get_pm(dhd);
15231 if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
15232 sizeof(pm))) != 0) {
15233 if (err == -ENODEV)
15234 WL_DBG(("%s:netdev not ready\n",
15235 _net_info->ndev->name));
15236 else
15237 WL_ERR(("%s:error (%d)\n",
15238 _net_info->ndev->name, err));
15239
15240 wl_cfg80211_update_power_mode(_net_info->ndev);
15241 }
15242 #ifdef RTT_SUPPORT
15243 }
15244 #endif /* RTT_SUPPORT */
15245 }
15246 wl_cfg80211_concurrent_roam(cfg, 0);
15247 #if defined(WLTDLS)
15248 if (!wl_cfg80211_is_concurrent_mode(primary_dev)) {
15249 err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
15250 }
15251 #endif /* defined(WLTDLS) */
15252
15253 #ifdef BCMDONGLEHOST
15254 #if defined(DISABLE_FRAMEBURST_VSDB)
15255 if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE)) {
15256 wl_cfg80211_set_frameburst(cfg, TRUE);
15257 }
15258 #endif /* DISABLE_FRAMEBURST_VSDB */
15259 #ifdef DISABLE_WL_FRAMEBURST_SOFTAP
15260 if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
15261 CHSPEC_IS2G(cfg->ap_oper_channel)) {
15262 /* Disable frameburst for stand-alone 2GHz SoftAP */
15263 wl_cfg80211_set_frameburst(cfg, FALSE);
15264 }
15265 #endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
15266 #endif /* BCMDONGLEHOST */
15267 }
15268 return err;
15269 }
15270
15271 #ifdef DHD_LOSSLESS_ROAMING
wl_init_roam_timeout(struct bcm_cfg80211 * cfg)15272 static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
15273 {
15274 int err = 0;
15275
15276 /* Init roam timer */
15277 init_timer_compat(&cfg->roam_timeout, wl_roam_timeout, cfg);
15278
15279 return err;
15280 }
15281 #endif /* DHD_LOSSLESS_ROAMING */
15282
15283 #ifdef CONFIG_SLEEP_MONITOR
15284 extern long long temp_raw;
15285
wlan_get_sleep_monitor64_cb(void * priv,long long * raw_val,int check_level,int caller_type)15286 int wlan_get_sleep_monitor64_cb(void *priv, long long *raw_val,
15287 int check_level, int caller_type)
15288 {
15289 struct bcm_cfg80211 *cfg = priv;
15290 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15291 int state = DEVICE_UNKNOWN;
15292
15293 if (!dhdp->up)
15294 state = DEVICE_POWER_OFF;
15295 else {
15296 state = DEVICE_ON_ACTIVE1;
15297 if (wl_get_drv_status_all(cfg, CONNECTED))
15298 state = DEVICE_ON_ACTIVE2;
15299
15300 if (caller_type == SLEEP_MONITOR_CALL_SUSPEND) {
15301 *raw_val = temp_raw;
15302 temp_raw = 0;
15303 }
15304 }
15305
15306 return state;
15307 }
15308
15309 static struct sleep_monitor_ops wlan_sleep_monitor_ops = {
15310 .read64_cb_func = wlan_get_sleep_monitor64_cb,
15311 };
15312 #endif /* CONFIG_SLEEP_MONITOR */
15313
wl_init_priv(struct bcm_cfg80211 * cfg)15314 static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
15315 {
15316 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
15317 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
15318 s32 err = 0;
15319
15320 cfg->scan_request = NULL;
15321 cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
15322 #ifdef DISABLE_BUILTIN_ROAM
15323 cfg->roam_on = false;
15324 #else
15325 cfg->roam_on = true;
15326 #endif /* DISABLE_BUILTIN_ROAM */
15327 cfg->active_scan = true;
15328 cfg->rf_blocked = false;
15329 cfg->vsdb_mode = false;
15330 #if defined(BCMSDIO) || defined(BCMDBUS)
15331 cfg->wlfc_on = false;
15332 #endif /* BCMSDIO || BCMDBUS */
15333 cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
15334 cfg->disable_roam_event = false;
15335 /* register interested state */
15336 set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
15337 spin_lock_init(&cfg->cfgdrv_lock);
15338 mutex_init(&cfg->ioctl_buf_sync);
15339 init_waitqueue_head(&cfg->netif_change_event);
15340 init_completion(&cfg->send_af_done);
15341 init_completion(&cfg->iface_disable);
15342 mutex_init(&cfg->usr_sync);
15343 mutex_init(&cfg->event_sync);
15344 mutex_init(&cfg->if_sync);
15345 mutex_init(&cfg->scan_sync);
15346 mutex_init(&cfg->connect_sync);
15347 mutex_init(&cfg->pm_sync);
15348 #ifdef WLTDLS
15349 mutex_init(&cfg->tdls_sync);
15350 #endif /* WLTDLS */
15351 #ifdef WL_BCNRECV
15352 mutex_init(&cfg->bcn_sync);
15353 #endif /* WL_BCNRECV */
15354 #ifdef WL_WPS_SYNC
15355 wl_init_wps_reauth_sm(cfg);
15356 #endif /* WL_WPS_SYNC */
15357 wl_init_eq(cfg);
15358 err = wl_init_priv_mem(cfg);
15359 if (err)
15360 return err;
15361 if (wl_create_event_handler(cfg))
15362 return -ENOMEM;
15363 wl_init_event_handler(cfg);
15364 err = wl_init_scan(cfg);
15365 if (err)
15366 return err;
15367 #ifdef DHD_LOSSLESS_ROAMING
15368 err = wl_init_roam_timeout(cfg);
15369 if (err) {
15370 return err;
15371 }
15372 #endif /* DHD_LOSSLESS_ROAMING */
15373 wl_init_conf(cfg->conf);
15374 wl_init_prof(cfg, ndev);
15375 wl_link_down(cfg);
15376 DNGL_FUNC(dhd_cfg80211_init, (cfg));
15377 cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
15378 cfg->pmk_list->pmkids.count = 0;
15379 cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
15380
15381 #ifdef CONFIG_SLEEP_MONITOR
15382 sleep_monitor_register_ops(cfg, &wlan_sleep_monitor_ops,
15383 SLEEP_MONITOR_WIFI);
15384 #endif /* CONFIG_SLEEP_MONITOR */
15385 return err;
15386 }
15387
wl_deinit_priv(struct bcm_cfg80211 * cfg)15388 static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
15389 {
15390 DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
15391 wl_destroy_event_handler(cfg);
15392 wl_flush_eq(cfg);
15393 wl_link_down(cfg);
15394 del_timer_sync(&cfg->scan_timeout);
15395 #ifdef DHD_LOSSLESS_ROAMING
15396 del_timer_sync(&cfg->roam_timeout);
15397 #endif
15398 wl_deinit_priv_mem(cfg);
15399 if (wl_cfg80211_netdev_notifier_registered) {
15400 wl_cfg80211_netdev_notifier_registered = FALSE;
15401 unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
15402 }
15403
15404 #ifdef CONFIG_SLEEP_MONITOR
15405 sleep_monitor_unregister_ops(SLEEP_MONITOR_WIFI);
15406 #endif /* CONFIG_SLEEP_MONITOR */
15407 }
15408
15409 #if defined(WL_ENABLE_P2P_IF) || defined (WL_NEWCFG_PRIVCMD_SUPPORT)
wl_cfg80211_attach_p2p(struct bcm_cfg80211 * cfg)15410 static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
15411 {
15412 WL_TRACE(("Enter \n"));
15413
15414 if (wl_cfgp2p_register_ndev(cfg) < 0) {
15415 WL_ERR(("P2P attach failed. \n"));
15416 return -ENODEV;
15417 }
15418
15419 return 0;
15420 }
15421
wl_cfg80211_detach_p2p(struct bcm_cfg80211 * cfg)15422 static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
15423 {
15424 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
15425 struct wireless_dev *wdev;
15426 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
15427
15428 WL_DBG(("Enter \n"));
15429 if (!cfg) {
15430 WL_ERR(("Invalid Ptr\n"));
15431 return -EINVAL;
15432 }
15433 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
15434 else {
15435 wdev = cfg->p2p_wdev;
15436 if (!wdev) {
15437 WL_ERR(("Invalid Ptr\n"));
15438 return -EINVAL;
15439 }
15440 }
15441 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
15442
15443 wl_cfgp2p_unregister_ndev(cfg);
15444
15445 cfg->p2p_wdev = NULL;
15446 cfg->p2p_net = NULL;
15447 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
15448 WL_DBG(("Freeing 0x%p \n", wdev));
15449 MFREE(cfg->osh, wdev, sizeof(*wdev));
15450 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
15451
15452 return 0;
15453 }
15454 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
15455
15456 #if defined(BCMDONGLEHOST)
wl_cfg80211_attach_post(struct net_device * ndev)15457 static s32 wl_cfg80211_attach_post(struct net_device *ndev)
15458 {
15459 struct bcm_cfg80211 * cfg;
15460 s32 err = 0;
15461 s32 ret = 0;
15462 WL_TRACE(("In\n"));
15463 if (unlikely(!ndev)) {
15464 WL_ERR(("ndev is invaild\n"));
15465 return -ENODEV;
15466 }
15467 cfg = wl_get_cfg(ndev);
15468 if (unlikely(!cfg)) {
15469 WL_ERR(("cfg is invaild\n"));
15470 return -EINVAL;
15471 }
15472 if (!wl_get_drv_status(cfg, READY, ndev)) {
15473 if (cfg->wdev) {
15474 ret = wl_cfgp2p_supported(cfg, ndev);
15475 if (ret > 0) {
15476 #if !defined(WL_ENABLE_P2P_IF)
15477 cfg->wdev->wiphy->interface_modes |=
15478 (BIT(NL80211_IFTYPE_P2P_CLIENT)|
15479 BIT(NL80211_IFTYPE_P2P_GO));
15480 #endif /* !WL_ENABLE_P2P_IF */
15481 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
15482 goto fail;
15483
15484 #if defined(WL_ENABLE_P2P_IF)
15485 if (cfg->p2p_net) {
15486 /* Update MAC addr for p2p0 interface here. */
15487 memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
15488 cfg->p2p_net->dev_addr[0] |= 0x02;
15489 WL_MSG(cfg->p2p_net->name, "p2p_dev_addr="MACDBG "\n",
15490 MAC2STRDBG(cfg->p2p_net->dev_addr));
15491 } else {
15492 WL_ERR(("p2p_net not yet populated."
15493 " Couldn't update the MAC Address for p2p0 \n"));
15494 return -ENODEV;
15495 }
15496 #endif /* WL_ENABLE_P2P_IF */
15497 cfg->p2p_supported = true;
15498 } else if (ret == 0) {
15499 if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
15500 goto fail;
15501 } else {
15502 /* SDIO bus timeout */
15503 err = -ENODEV;
15504 goto fail;
15505 }
15506 }
15507 }
15508 wl_set_drv_status(cfg, READY, ndev);
15509 fail:
15510 return err;
15511 }
15512 #endif /* BCMDONGLEHOST */
15513
wl_get_cfg(struct net_device * ndev)15514 struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev)
15515 {
15516 struct wireless_dev *wdev = ndev->ieee80211_ptr;
15517
15518 if (!wdev || !wdev->wiphy)
15519 return NULL;
15520
15521 return wiphy_priv(wdev->wiphy);
15522 }
15523
15524 s32
wl_cfg80211_net_attach(struct net_device * primary_ndev)15525 wl_cfg80211_net_attach(struct net_device *primary_ndev)
15526 {
15527 struct bcm_cfg80211 *cfg = wl_get_cfg(primary_ndev);
15528 #ifdef WL_STATIC_IF
15529 enum nl80211_iftype ntype;
15530 #endif
15531
15532 if (!cfg) {
15533 WL_ERR(("cfg null\n"));
15534 return BCME_ERROR;
15535 }
15536 #ifdef WL_STATIC_IF
15537 /* Register dummy n/w iface. FW init will happen only from dev_open */
15538 #ifdef WLEASYMESH
15539 ntype = NL80211_IFTYPE_AP;
15540 #else
15541 ntype = NL80211_IFTYPE_STATION;
15542 #endif
15543 if (wl_cfg80211_register_static_if(cfg, ntype,
15544 WL_STATIC_IFNAME_PREFIX) == NULL) {
15545 WL_ERR(("static i/f registration failed!\n"));
15546 return BCME_ERROR;
15547 }
15548 #endif /* WL_STATIC_IF */
15549 return BCME_OK;
15550 }
15551
wl_cfg80211_attach(struct net_device * ndev,void * context)15552 s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
15553 {
15554 struct wireless_dev *wdev;
15555 struct bcm_cfg80211 *cfg;
15556 s32 err = 0;
15557 struct device *dev;
15558 u16 bssidx = 0;
15559 u16 ifidx = 0;
15560 dhd_pub_t *dhd = (struct dhd_pub *)(context);
15561
15562 WL_TRACE(("In\n"));
15563 if (!ndev) {
15564 WL_ERR(("ndev is invaild\n"));
15565 return -ENODEV;
15566 }
15567 WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
15568 #if !defined(BCMDONGLEHOST)
15569 wl_cfg80211_set_parent_dev(context);
15570 #endif
15571 dev = wl_cfg80211_get_parent_dev();
15572
15573 wdev = (struct wireless_dev *)MALLOCZ(dhd->osh, sizeof(*wdev));
15574 if (unlikely(!wdev)) {
15575 WL_ERR(("Could not allocate wireless device\n"));
15576 return -ENOMEM;
15577 }
15578 err = wl_setup_wiphy(wdev, dev, context);
15579 if (unlikely(err)) {
15580 MFREE(dhd->osh, wdev, sizeof(*wdev));
15581 return -ENOMEM;
15582 }
15583 #ifdef WLMESH_CFG80211
15584 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_MESH);
15585 #else
15586 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
15587 #endif
15588 cfg = wiphy_priv(wdev->wiphy);
15589 cfg->wdev = wdev;
15590 cfg->pub = context;
15591 cfg->osh = dhd->osh;
15592 INIT_LIST_HEAD(&cfg->net_list);
15593 #ifdef WBTEXT
15594 INIT_LIST_HEAD(&cfg->wbtext_bssid_list);
15595 #endif /* WBTEXT */
15596 INIT_LIST_HEAD(&cfg->vndr_oui_list);
15597 spin_lock_init(&cfg->vndr_oui_sync);
15598 spin_lock_init(&cfg->net_list_sync);
15599 ndev->ieee80211_ptr = wdev;
15600 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
15601 wdev->netdev = ndev;
15602 cfg->state_notifier = wl_notifier_change_state;
15603 err = wl_alloc_netinfo(cfg, ndev, wdev, WL_IF_TYPE_STA, PM_ENABLE, bssidx, ifidx);
15604 if (err) {
15605 WL_ERR(("Failed to alloc net_info (%d)\n", err));
15606 goto cfg80211_attach_out;
15607 }
15608 err = wl_init_priv(cfg);
15609 if (err) {
15610 WL_ERR(("Failed to init iwm_priv (%d)\n", err));
15611 goto cfg80211_attach_out;
15612 }
15613
15614 err = wl_setup_rfkill(cfg, TRUE);
15615 if (err) {
15616 WL_ERR(("Failed to setup rfkill %d\n", err));
15617 goto cfg80211_attach_out;
15618 }
15619
15620 if (!wl_cfg80211_netdev_notifier_registered) {
15621 wl_cfg80211_netdev_notifier_registered = TRUE;
15622 err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
15623 if (err) {
15624 wl_cfg80211_netdev_notifier_registered = FALSE;
15625 WL_ERR(("Failed to register notifierl %d\n", err));
15626 goto cfg80211_attach_out;
15627 }
15628 }
15629
15630 #if defined(OEM_ANDROID) && defined(COEX_DHCP)
15631 cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
15632 if (!cfg->btcoex_info)
15633 goto cfg80211_attach_out;
15634 #endif /* defined(OEM_ANDROID) && defined(COEX_DHCP) */
15635
15636 #if defined(SUPPORT_RANDOM_MAC_SCAN)
15637 cfg->random_mac_enabled = FALSE;
15638 #endif /* SUPPORT_RANDOM_MAC_SCAN */
15639
15640 #ifdef CONFIG_CFG80211_INTERNAL_REGDB
15641 wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
15642 #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
15643
15644 #if defined(WL_ENABLE_P2P_IF) || defined (WL_NEWCFG_PRIVCMD_SUPPORT)
15645 err = wl_cfg80211_attach_p2p(cfg);
15646 if (err)
15647 goto cfg80211_attach_out;
15648 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
15649
15650 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
15651 /* wlan scan_supp timer and work thread info */
15652 init_timer_compat(&cfg->scan_supp_timer, wl_cfg80211_scan_supp_timerfunc, cfg);
15653 INIT_WORK(&cfg->wlan_work, wl_cfg80211_work_handler);
15654 #endif /* DHCP_SCAN_SUPPRESS */
15655
15656 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
15657 INIT_DELAYED_WORK(&cfg->loc.work, wl_cfgscan_listen_complete_work);
15658 INIT_DELAYED_WORK(&cfg->ap_work, wl_cfg80211_ap_timeout_work);
15659 mutex_init(&cfg->pm_sync);
15660 #ifdef WL_NAN
15661 err = wl_cfgnan_attach(cfg);
15662 if (err) {
15663 WL_ERR(("Failed to attach nan module %d\n", err));
15664 goto cfg80211_attach_out;
15665 }
15666 #endif /* WL_NAN */
15667 cfg->rssi_sum_report = FALSE;
15668 #ifdef WL_BAM
15669 wl_bad_ap_mngr_init(cfg);
15670 #endif /* WL_BAM */
15671
15672 #ifdef BIGDATA_SOFTAP
15673 wl_attach_ap_stainfo(cfg);
15674 #endif /* BIGDATA_SOFTAP */
15675
15676 return err;
15677
15678 cfg80211_attach_out:
15679 wl_cfg80211_detach(cfg);
15680 return err;
15681 }
15682
wl_cfg80211_detach(struct bcm_cfg80211 * cfg)15683 void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
15684 {
15685 WL_DBG(("Enter\n"));
15686 if (!cfg) {
15687 return;
15688 }
15689 /* clean up pm_enable work item. Remove this once deinit is properly
15690 * clean up and wl_cfg8021_down is called while removing the module
15691 */
15692 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
15693
15694 #if defined(OEM_ANDROID) && defined(COEX_DHCP)
15695 wl_cfg80211_btcoex_deinit();
15696 cfg->btcoex_info = NULL;
15697 #endif /* defined(OEM_ANDROID) && defined(COEX_DHCP) */
15698
15699 wl_setup_rfkill(cfg, FALSE);
15700
15701 #ifdef WL_WPS_SYNC
15702 wl_deinit_wps_reauth_sm(cfg);
15703 #endif /* WL_WPS_SYNC */
15704
15705 del_timer_sync(&cfg->scan_timeout);
15706 #ifdef DHD_LOSSLESS_ROAMING
15707 del_timer_sync(&cfg->roam_timeout);
15708 #endif /* DHD_LOSSLESS_ROAMING */
15709
15710 #ifdef WL_STATIC_IF
15711 wl_cfg80211_unregister_static_if(cfg);
15712 #endif /* WL_STATIC_IF */
15713 #if defined(WL_ENABLE_P2P_IF) || defined (WL_NEWCFG_PRIVCMD_SUPPORT)
15714 wl_cfg80211_detach_p2p(cfg);
15715 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
15716 #ifdef WL_BAM
15717 wl_bad_ap_mngr_deinit(cfg);
15718 #endif /* WL_BAM */
15719
15720 #ifdef BIGDATA_SOFTAP
15721 wl_detach_ap_stainfo(cfg);
15722 #endif /* BIGDATA_SOFTAP */
15723
15724 #ifdef WL_NAN
15725 wl_cfgnan_detach(cfg);
15726 #endif /* WL_NAN */
15727 wl_cfg80211_ibss_vsie_free(cfg);
15728 wl_dealloc_netinfo_by_wdev(cfg, cfg->wdev);
15729 wl_cfg80211_set_bcmcfg(NULL);
15730 wl_deinit_priv(cfg);
15731 wl_cfg80211_clear_parent_dev();
15732 #if defined(RSSIAVG)
15733 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
15734 wl_free_rssi_cache(&cfg->g_connected_rssi_cache_ctrl);
15735 #endif
15736 #if defined(BSSCACHE)
15737 wl_release_bss_cache_ctrl(&cfg->g_bss_cache_ctrl);
15738 #endif
15739 wl_free_wdev(cfg);
15740 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
15741 * structure "cfg", which is the private part of wiphy, has been freed in
15742 * wl_free_wdev !!!!!!!!!!!
15743 */
15744 WL_DBG(("Exit\n"));
15745 }
15746
15747 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
wl_cfg80211_register_dev_ril_bridge_event_notifier()15748 void wl_cfg80211_register_dev_ril_bridge_event_notifier()
15749 {
15750 WL_DBG(("Enter\n"));
15751 if (!wl_cfg80211_ril_bridge_notifier_registered) {
15752 s32 err = 0;
15753 wl_cfg80211_ril_bridge_notifier_registered = TRUE;
15754 err = register_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
15755 if (err) {
15756 wl_cfg80211_ril_bridge_notifier_registered = FALSE;
15757 WL_ERR(("Failed to register ril_notifier! %d\n", err));
15758 }
15759 }
15760 }
15761
wl_cfg80211_unregister_dev_ril_bridge_event_notifier()15762 void wl_cfg80211_unregister_dev_ril_bridge_event_notifier()
15763 {
15764 WL_DBG(("Enter\n"));
15765 if (wl_cfg80211_ril_bridge_notifier_registered) {
15766 wl_cfg80211_ril_bridge_notifier_registered = FALSE;
15767 unregister_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
15768 }
15769 }
15770 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
15771
wl_print_event_data(struct bcm_cfg80211 * cfg,uint32 event_type,const wl_event_msg_t * e)15772 static void wl_print_event_data(struct bcm_cfg80211 *cfg,
15773 uint32 event_type, const wl_event_msg_t *e)
15774 {
15775 s32 status = ntoh32(e->status);
15776 s32 reason = ntoh32(e->reason);
15777 s32 ifidx = ntoh32(e->ifidx);
15778 s32 bssidx = ntoh32(e->bsscfgidx);
15779
15780 switch (event_type) {
15781 case WLC_E_ESCAN_RESULT:
15782 if ((status == WLC_E_STATUS_SUCCESS) ||
15783 (status == WLC_E_STATUS_ABORT)) {
15784 WL_INFORM_MEM(("event_type (%d), ifidx: %d"
15785 " bssidx: %d scan_type:%d\n",
15786 event_type, ifidx, bssidx, status));
15787 }
15788 break;
15789 case WLC_E_LINK:
15790 case WLC_E_DISASSOC:
15791 case WLC_E_DISASSOC_IND:
15792 case WLC_E_DEAUTH:
15793 case WLC_E_DEAUTH_IND:
15794 WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
15795 " status:%d reason:%d\n",
15796 event_type, ifidx, bssidx, status, reason));
15797 break;
15798
15799 default:
15800 /* Print only when DBG verbose is enabled */
15801 WL_DBG(("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
15802 event_type, ifidx, bssidx, status, reason));
15803 }
15804 }
15805
wl_event_handler(struct work_struct * work_data)15806 static void wl_event_handler(struct work_struct *work_data)
15807 {
15808 struct bcm_cfg80211 *cfg = NULL;
15809 struct wl_event_q *e;
15810 struct wireless_dev *wdev = NULL;
15811
15812 WL_DBG(("Enter \n"));
15813 BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
15814 LOG_TS(cfg, wl_evt_hdlr_entry);
15815 DHD_EVENT_WAKE_LOCK(cfg->pub);
15816 while ((e = wl_deq_event(cfg))) {
15817 s32 status = ntoh32(e->emsg.status);
15818 u32 event_type = ntoh32(e->emsg.event_type);
15819 bool scan_cmplt_evt = (event_type == WLC_E_ESCAN_RESULT) &&
15820 ((status == WLC_E_STATUS_SUCCESS) || (status == WLC_E_STATUS_ABORT));
15821
15822 LOG_TS(cfg, wl_evt_deq);
15823 if (scan_cmplt_evt) {
15824 LOG_TS(cfg, scan_deq);
15825 }
15826 /* Print only critical events to avoid too many prints */
15827 wl_print_event_data(cfg, e->etype, &e->emsg);
15828
15829 if (e->emsg.ifidx > WL_MAX_IFS) {
15830 WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
15831 goto fail;
15832 }
15833
15834 /* Make sure iface operations, don't creat race conditions */
15835 mutex_lock(&cfg->if_sync);
15836 if (!(wdev = wl_get_wdev_by_fw_idx(cfg,
15837 e->emsg.bsscfgidx, e->emsg.ifidx))) {
15838 /* For WLC_E_IF would be handled by wl_host_event */
15839 if (e->etype != WLC_E_IF)
15840 WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
15841 " Ignoring event.\n", e->emsg.bsscfgidx));
15842 } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
15843 #if defined(BCMDONGLEHOST)
15844 dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
15845 if (dhd->busstate == DHD_BUS_DOWN) {
15846 WL_ERR((": BUS is DOWN.\n"));
15847 } else
15848 #endif /* defined(BCMDONGLEHOST) */
15849 {
15850 WL_DBG(("event_type %d event_sub %d\n",
15851 ntoh32(e->emsg.event_type),
15852 ntoh32(e->emsg.reason)));
15853 WL_SET_EIDX_IN_PROGRESS(cfg, e->id, e->etype);
15854 cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
15855 &e->emsg, e->edata);
15856 WL_CLR_EIDX_STATES(cfg);
15857 if (scan_cmplt_evt) {
15858 LOG_TS(cfg, scan_hdlr_cmplt);
15859 }
15860 }
15861 } else {
15862 WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
15863 }
15864 mutex_unlock(&cfg->if_sync);
15865 fail:
15866 wl_put_event(cfg, e);
15867 if (scan_cmplt_evt) {
15868 LOG_TS(cfg, scan_cmplt);
15869 }
15870 LOG_TS(cfg, wl_evt_hdlr_exit);
15871 }
15872 DHD_EVENT_WAKE_UNLOCK(cfg->pub);
15873 }
15874
15875 /*
15876 * Generic API to handle critical events which doesnt need
15877 * cfg enquening and sleepable API calls.
15878 */
15879 s32
wl_cfg80211_handle_critical_events(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const wl_event_msg_t * e)15880 wl_cfg80211_handle_critical_events(struct bcm_cfg80211 *cfg,
15881 struct wireless_dev *wdev, const wl_event_msg_t * e)
15882 {
15883 s32 ret = BCME_ERROR;
15884 u32 event_type = ntoh32(e->event_type);
15885
15886 if (event_type >= WLC_E_LAST) {
15887 return BCME_ERROR;
15888 }
15889
15890 switch (event_type) {
15891 case WLC_E_NAN_CRITICAL: {
15892 #ifdef WL_NAN
15893 if (ntoh32(e->reason) == WL_NAN_EVENT_STOP) {
15894 WL_DBG(("Received WL_NAN_EVENT_STOP\n"));
15895 }
15896 #endif /* WL_NAN */
15897 break;
15898 }
15899 default:
15900 ret = BCME_ERROR;
15901 }
15902 return ret;
15903 }
15904
15905 void
wl_cfg80211_event(struct net_device * ndev,const wl_event_msg_t * e,void * data)15906 wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
15907 {
15908 s32 status = ntoh32(e->status);
15909 u32 event_type = ntoh32(e->event_type);
15910 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
15911 struct net_info *netinfo;
15912
15913 WL_DBG(("event_type (%d): reason (%d): %s\n", event_type, ntoh32(e->reason),
15914 bcmevent_get_name(event_type)));
15915 if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
15916 WL_ERR(("Stale event ignored\n"));
15917 return;
15918 }
15919
15920 #ifdef OEM_ANDROID
15921 if (cfg->event_workq == NULL) {
15922 WL_ERR(("Event handler is not created\n"));
15923 return;
15924 }
15925 #endif /* OEM_ANDROID */
15926
15927 #ifndef OEM_ANDROID
15928 if (!cfg->event_workq_init) {
15929 WL_ERR(("Event handler is not created\n"));
15930 return;
15931 }
15932 #endif /* OEM_ANDROID */
15933
15934 if (event_type == WLC_E_IF) {
15935 /* Don't process WLC_E_IF events in wl_cfg80211 layer */
15936 return;
15937 }
15938
15939 netinfo = wl_get_netinfo_by_fw_idx(cfg, e->bsscfgidx, e->ifidx);
15940 if (!netinfo) {
15941 /* Since the netinfo entry is not there, the netdev entry is not
15942 * created via cfg80211 interface. so the event is not of interest
15943 * to the cfg80211 layer.
15944 */
15945 WL_TRACE(("ignore event %d, not interested\n", event_type));
15946 return;
15947 }
15948
15949 /* Handle wl_cfg80211_critical_events */
15950 if (wl_cfg80211_handle_critical_events(cfg, netinfo->wdev, e) == BCME_OK) {
15951 return;
15952 }
15953
15954 if (event_type == WLC_E_PFN_NET_FOUND) {
15955 WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
15956 }
15957 else if (event_type == WLC_E_PFN_NET_LOST) {
15958 WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
15959 }
15960
15961 if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
15962
15963 #ifdef OEM_ANDROID
15964 queue_work(cfg->event_workq, &cfg->event_work);
15965 #endif /* OEM_ANDROID */
15966
15967 #ifndef OEM_ANDROID
15968 schedule_work(&cfg->event_work);
15969 #endif /* OEM_ANDROID */
15970 }
15971 /* Mark timeout value for thread sched */
15972 if ((event_type == WLC_E_ESCAN_RESULT) &&
15973 ((status == WLC_E_STATUS_SUCCESS) ||
15974 (status == WLC_E_STATUS_ABORT))) {
15975 LOG_TS(cfg, scan_enq);
15976 WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
15977 status, work_busy(&cfg->event_work)));
15978 }
15979 }
15980
wl_init_eq(struct bcm_cfg80211 * cfg)15981 static void wl_init_eq(struct bcm_cfg80211 *cfg)
15982 {
15983 wl_init_eq_lock(cfg);
15984 INIT_LIST_HEAD(&cfg->eq_list);
15985 }
15986
wl_flush_eq(struct bcm_cfg80211 * cfg)15987 static void wl_flush_eq(struct bcm_cfg80211 *cfg)
15988 {
15989 struct wl_event_q *e;
15990 unsigned long flags;
15991
15992 flags = wl_lock_eq(cfg);
15993 while (!list_empty_careful(&cfg->eq_list)) {
15994 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
15995 list_del(&e->eq_list);
15996 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
15997 }
15998 wl_unlock_eq(cfg, flags);
15999 }
16000
16001 /*
16002 * retrieve first queued event from head
16003 */
16004
wl_deq_event(struct bcm_cfg80211 * cfg)16005 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
16006 {
16007 struct wl_event_q *e = NULL;
16008 unsigned long flags;
16009
16010 flags = wl_lock_eq(cfg);
16011 if (likely(!list_empty(&cfg->eq_list))) {
16012 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
16013 list_del(&e->eq_list);
16014 }
16015 wl_unlock_eq(cfg, flags);
16016
16017 return e;
16018 }
16019
16020 /*
16021 * push event to tail of the queue
16022 */
16023
16024 static s32
wl_enq_event(struct bcm_cfg80211 * cfg,struct net_device * ndev,u32 event,const wl_event_msg_t * msg,void * data)16025 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event,
16026 const wl_event_msg_t *msg, void *data)
16027 {
16028 struct wl_event_q *e;
16029 s32 err = 0;
16030 uint32 evtq_size;
16031 uint32 data_len;
16032 unsigned long flags;
16033
16034 data_len = 0;
16035 if (data)
16036 data_len = ntoh32(msg->datalen);
16037 evtq_size = (uint32)(sizeof(struct wl_event_q) + data_len);
16038 e = (struct wl_event_q *)MALLOCZ(cfg->osh, evtq_size);
16039 if (unlikely(!e)) {
16040 WL_ERR(("event alloc failed\n"));
16041 return -ENOMEM;
16042 }
16043 e->etype = event;
16044 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
16045 if (data)
16046 memcpy(e->edata, data, data_len);
16047 e->datalen = data_len;
16048 e->id = cfg->eidx.enqd++;
16049 flags = wl_lock_eq(cfg);
16050 list_add_tail(&e->eq_list, &cfg->eq_list);
16051 wl_unlock_eq(cfg, flags);
16052
16053 return err;
16054 }
16055
wl_put_event(struct bcm_cfg80211 * cfg,struct wl_event_q * e)16056 static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e)
16057 {
16058 MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
16059 }
16060
wl_config_infra(struct bcm_cfg80211 * cfg,struct net_device * ndev,u16 iftype)16061 static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype)
16062 {
16063 s32 infra = 0;
16064 s32 err = 0;
16065 bool skip_infra = false;
16066
16067 switch (iftype) {
16068 case WL_IF_TYPE_IBSS:
16069 case WL_IF_TYPE_AIBSS:
16070 infra = 0;
16071 break;
16072 case WL_IF_TYPE_AP:
16073 case WL_IF_TYPE_STA:
16074 case WL_IF_TYPE_P2P_GO:
16075 case WL_IF_TYPE_P2P_GC:
16076 /* Intentional fall through */
16077 infra = 1;
16078 break;
16079 #ifdef WLMESH_CFG80211
16080 case NL80211_IFTYPE_MESH_POINT:
16081 infra = WL_BSSTYPE_MESH;
16082 break;
16083 #endif /* WLMESH_CFG80211 */
16084 case WL_IF_TYPE_MONITOR:
16085
16086 #ifdef WLAWDL
16087 case WL_IF_TYPE_AWDL:
16088 #endif /* WLAWDL */
16089
16090 case WL_IF_TYPE_NAN:
16091 /* Intentionall fall through */
16092 default:
16093 skip_infra = true;
16094 WL_ERR(("Skipping infra setting for type:%d\n", iftype));
16095 break;
16096 }
16097
16098 /* /TODO Infra iovar is stored in default bss first and
16099 * then applied to the next upcoming bss. so if there is
16100 * some other concurrent bss coming up in parallel, it
16101 * can cause problem. Ideally this iovar should get directly
16102 * applied on the target bsscfg.
16103 */
16104 if (!skip_infra) {
16105 infra = htod32(infra);
16106 err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
16107 if (unlikely(err)) {
16108 WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
16109 return err;
16110 }
16111 }
16112 return 0;
16113 }
16114
wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf * ev,u16 event,bool set)16115 void wl_cfg80211_add_to_eventbuffer(struct wl_eventmsg_buf *ev, u16 event, bool set)
16116 {
16117 if (!ev || (event > WLC_E_LAST))
16118 return;
16119
16120 if (ev->num < MAX_EVENT_BUF_NUM) {
16121 ev->event[ev->num].type = event;
16122 ev->event[ev->num].set = set;
16123 ev->num++;
16124 } else {
16125 WL_ERR(("evenbuffer doesn't support > %u events. Update"
16126 " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
16127 ASSERT(0);
16128 }
16129 }
16130
wl_cfg80211_apply_eventbuffer(struct net_device * ndev,struct bcm_cfg80211 * cfg,wl_eventmsg_buf_t * ev)16131 s32 wl_cfg80211_apply_eventbuffer(
16132 struct net_device *ndev,
16133 struct bcm_cfg80211 *cfg,
16134 wl_eventmsg_buf_t *ev)
16135 {
16136 int i, ret = BCME_OK;
16137 s8 event_buf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE] = {0};
16138 /* Room for "event_msgs_ext" + '\0' + bitvec */
16139 char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16];
16140 eventmsgs_ext_t *eventmask_msg;
16141 s32 msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE;
16142
16143 if (!ev || (!ev->num)) {
16144 return -EINVAL;
16145 }
16146
16147 mutex_lock(&cfg->event_sync);
16148
16149 eventmask_msg = (eventmsgs_ext_t *)event_buf;
16150 eventmask_msg->ver = EVENTMSGS_VER;
16151 eventmask_msg->command = EVENTMSGS_NONE;
16152 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
16153 eventmask_msg->maxgetsize = WL_EVENTING_MASK_EXT_LEN;
16154
16155 /* Read event_msgs mask */
16156 ret = wldev_iovar_getbuf(ndev, "event_msgs_ext",
16157 eventmask_msg, EVENTMSGS_EXT_STRUCT_SIZE,
16158 iovbuf,
16159 sizeof(iovbuf),
16160 NULL);
16161
16162 if (unlikely(ret)) {
16163 WL_ERR(("Get event_msgs error (%d)\n", ret));
16164 goto exit;
16165 }
16166
16167 bcopy(iovbuf, eventmask_msg, msglen);
16168
16169 /* apply the set bits */
16170 for (i = 0; i < ev->num; i++) {
16171 if (ev->event[i].set)
16172 setbit(eventmask_msg->mask, ev->event[i].type);
16173 else
16174 clrbit(eventmask_msg->mask, ev->event[i].type);
16175 }
16176
16177 /* Write updated Event mask */
16178 eventmask_msg->ver = EVENTMSGS_VER;
16179 eventmask_msg->command = EVENTMSGS_SET_MASK;
16180 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
16181
16182 /* Write updated Event mask */
16183 ret = wldev_iovar_setbuf(ndev, "event_msgs_ext", eventmask_msg,
16184 WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE,
16185 iovbuf, sizeof(iovbuf), NULL);
16186
16187 if (unlikely(ret)) {
16188 WL_ERR(("Set event_msgs error (%d)\n", ret));
16189 }
16190
16191 exit:
16192 mutex_unlock(&cfg->event_sync);
16193 return ret;
16194 }
16195
wl_add_remove_eventmsg(struct net_device * ndev,u16 event,bool add)16196 s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
16197 {
16198 s32 err = 0;
16199 s8 event_buf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE] = {0};
16200 eventmsgs_ext_t *eventmask_msg = NULL;
16201 struct bcm_cfg80211 *cfg;
16202 /* Room for "event_msgs_ext" + '\0' + bitvec */
16203 char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16];
16204 s32 msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE;
16205
16206 if (!ndev)
16207 return -ENODEV;
16208
16209 cfg = wl_get_cfg(ndev);
16210 if (!cfg)
16211 return -ENODEV;
16212
16213 mutex_lock(&cfg->event_sync);
16214
16215 eventmask_msg = (eventmsgs_ext_t *)event_buf;
16216 eventmask_msg->ver = EVENTMSGS_VER;
16217 eventmask_msg->command = EVENTMSGS_NONE;
16218 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
16219 eventmask_msg->maxgetsize = WL_EVENTING_MASK_EXT_LEN;
16220
16221 /* Read event_msgs mask */
16222 err = wldev_iovar_getbuf(ndev, "event_msgs_ext",
16223 eventmask_msg, EVENTMSGS_EXT_STRUCT_SIZE,
16224 iovbuf,
16225 sizeof(iovbuf),
16226 NULL);
16227
16228 if (unlikely(err)) {
16229 WL_ERR(("Get event_msgs error (%d)\n", err));
16230 goto eventmsg_out;
16231 }
16232
16233 bcopy(iovbuf, eventmask_msg, msglen);
16234
16235 if (add) {
16236 setbit(eventmask_msg->mask, event);
16237 } else {
16238 clrbit(eventmask_msg->mask, event);
16239 }
16240
16241 /* Write updated Event mask */
16242 eventmask_msg->ver = EVENTMSGS_VER;
16243 eventmask_msg->command = EVENTMSGS_SET_MASK;
16244 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
16245
16246 err = wldev_iovar_setbuf(ndev, "event_msgs_ext", eventmask_msg,
16247 WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE,
16248 iovbuf, sizeof(iovbuf), NULL);
16249
16250 if (unlikely(err)) {
16251 WL_ERR(("Set event_msgs error (%d)\n", err));
16252 goto eventmsg_out;
16253 }
16254
16255 eventmsg_out:
16256 mutex_unlock(&cfg->event_sync);
16257 return err;
16258 }
16259
16260 void
wl_cfg80211_generate_mac_addr(struct ether_addr * ea_addr)16261 wl_cfg80211_generate_mac_addr(struct ether_addr *ea_addr)
16262 {
16263 RANDOM_BYTES(ea_addr->octet, ETHER_ADDR_LEN);
16264 /* restore mcast and local admin bits to 0 and 1 */
16265 ETHER_SET_UNICAST(ea_addr->octet);
16266 ETHER_SET_LOCALADDR(ea_addr->octet);
16267 WL_ERR(("%s:generated new MAC="MACDBG" \n",
16268 __FUNCTION__, MAC2STRDBG(ea_addr->octet)));
16269 return;
16270 }
16271
wl_update_chan_param(struct net_device * dev,u32 cur_chan,struct ieee80211_channel * band_chan,bool * dfs_radar_disabled,bool legacy_chan_info)16272 static s32 wl_update_chan_param(struct net_device *dev, u32 cur_chan,
16273 struct ieee80211_channel *band_chan, bool *dfs_radar_disabled, bool legacy_chan_info)
16274 {
16275 s32 err = BCME_OK;
16276 u32 channel = cur_chan;
16277
16278 if (!(*dfs_radar_disabled)) {
16279 if (legacy_chan_info) {
16280 channel |= WL_CHANSPEC_BW_20;
16281 channel = wl_chspec_host_to_driver(channel);
16282 err = wldev_iovar_getint(dev, "per_chan_info", &channel);
16283 }
16284 if (!err) {
16285 if (channel & WL_CHAN_RADAR) {
16286 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
16287 band_chan->flags |= (IEEE80211_CHAN_RADAR |
16288 IEEE80211_CHAN_NO_IBSS);
16289 #else
16290 band_chan->flags |= IEEE80211_CHAN_RADAR;
16291 #endif
16292 }
16293 if (channel & WL_CHAN_PASSIVE) {
16294 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
16295 band_chan->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
16296 #else
16297 band_chan->flags |= IEEE80211_CHAN_NO_IR;
16298 #endif
16299 }
16300 } else if (err == BCME_UNSUPPORTED) {
16301 *dfs_radar_disabled = TRUE;
16302 WL_ERR(("does not support per_chan_info\n"));
16303 }
16304 }
16305
16306 return err;
16307 }
16308
wl_construct_reginfo(struct bcm_cfg80211 * cfg,s32 bw_cap)16309 static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
16310 {
16311 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
16312 struct ieee80211_channel *band_chan_arr = NULL;
16313 void *list;
16314 u32 i, j, index, channel, array_size = 0;
16315 chanspec_t chspec = 0;
16316 s32 err = BCME_OK;
16317 bool ht40_allowed;
16318 bool dfs_radar_disabled = FALSE;
16319 bool legacy_chan_info = FALSE;
16320 u16 list_count;
16321
16322 #define LOCAL_BUF_LEN 4096
16323 list = MALLOCZ(cfg->osh, LOCAL_BUF_LEN);
16324 if (list == NULL) {
16325 WL_ERR(("failed to allocate local buf\n"));
16326 return -ENOMEM;
16327 }
16328
16329 err = wldev_iovar_getbuf_bsscfg(dev, "chan_info_list", NULL,
16330 0, list, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
16331 if (err == BCME_UNSUPPORTED) {
16332 WL_INFORM(("get chan_info_list, UNSUPPORTED\n"));
16333 err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
16334 0, list, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
16335 if (err != BCME_OK) {
16336 WL_ERR(("get chanspecs err(%d)\n", err));
16337 MFREE(cfg->osh, list, LOCAL_BUF_LEN);
16338 return err;
16339 }
16340 /* Update indicating legacy chan info usage */
16341 legacy_chan_info = TRUE;
16342 } else if (err != BCME_OK) {
16343 WL_ERR(("get chan_info_list err(%d)\n", err));
16344 MFREE(cfg->osh, list, LOCAL_BUF_LEN);
16345 return err;
16346 }
16347
16348 WL_CHANNEL_ARRAY_INIT(__wl_2ghz_channels);
16349 WL_CHANNEL_ARRAY_INIT(__wl_5ghz_a_channels);
16350 #ifdef CFG80211_6G_SUPPORT
16351 WL_CHANNEL_ARRAY_INIT(__wl_6ghz_channels);
16352 #endif /* CFG80211_6G_SUPPORT */
16353
16354 list_count = legacy_chan_info ? ((wl_uint32_list_t *)list)->count :
16355 ((wl_chanspec_list_v1_t *)list)->count;
16356 for (i = 0; i < dtoh32(list_count); i++) {
16357 index = 0;
16358 ht40_allowed = false;
16359 if (legacy_chan_info) {
16360 chspec = (chanspec_t)dtoh32(((wl_uint32_list_t *)list)->element[i]);
16361 } else {
16362 chspec = (chanspec_t)dtoh32
16363 (((wl_chanspec_list_v1_t *)list)->chspecs[i].chanspec);
16364 }
16365 chspec = wl_chspec_driver_to_host(chspec);
16366 channel = wf_chspec_ctlchan(chspec);
16367
16368 if (!CHSPEC_IS40(chspec) &&
16369 !CHSPEC_IS20(chspec)) {
16370 WL_DBG(("HT80/160/80p80 center channel : %d\n", channel));
16371 continue;
16372 }
16373 if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) &&
16374 (channel <= CH_MAX_2G_CHANNEL)) {
16375 band_chan_arr = __wl_2ghz_channels;
16376 array_size = ARRAYSIZE(__wl_2ghz_channels);
16377 ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false;
16378 }
16379 #ifdef CFG80211_6G_SUPPORT
16380 else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) &&
16381 (channel <= CH_MAX_6G_CHANNEL)) {
16382 band_chan_arr = __wl_6ghz_channels;
16383 array_size = ARRAYSIZE(__wl_6ghz_channels);
16384 ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true;
16385 }
16386 #endif /* CFG80211_6G_SUPPORT */
16387 else if (
16388 #ifdef WL_6G_BAND
16389 /* Currently due to lack of kernel support both 6GHz and 5GHz
16390 * channels are published under 5GHz band
16391 */
16392 (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) &&
16393 (channel <= CH_MAX_6G_CHANNEL)) ||
16394 #endif /* WL_6G_BAND */
16395 (CHSPEC_IS5G(chspec) && channel >= CH_MIN_5G_CHANNEL)) {
16396 band_chan_arr = __wl_5ghz_a_channels;
16397 array_size = ARRAYSIZE(__wl_5ghz_a_channels);
16398 ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true;
16399 } else {
16400 WL_ERR(("Invalid channel Sepc. 0x%x.\n", chspec));
16401 continue;
16402 }
16403 if (!ht40_allowed && CHSPEC_IS40(chspec))
16404 continue;
16405 for (j = 0; j < array_size; j++) {
16406 if (band_chan_arr[j].hw_value == chspec) {
16407 break;
16408 }
16409 }
16410 index = j;
16411 if (!dhd_conf_match_channel(cfg->pub, channel))
16412 continue;
16413 if (index < array_size) {
16414 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) && !defined(WL_COMPAT_WIRELESS)
16415 band_chan_arr[index].center_freq =
16416 ieee80211_channel_to_frequency(channel);
16417 #else
16418 band_chan_arr[index].center_freq =
16419 wl_channel_to_frequency(channel, CHSPEC_BAND(chspec));
16420 #endif
16421 band_chan_arr[index].hw_value = chspec;
16422 band_chan_arr[index].beacon_found = false;
16423 band_chan_arr[index].flags &= ~IEEE80211_CHAN_DISABLED;
16424
16425 if (CHSPEC_IS40(chspec) && ht40_allowed) {
16426 /* assuming the order is HT20, HT40 Upper,
16427 * HT40 lower from chanspecs
16428 */
16429 u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
16430 if (CHSPEC_SB_UPPER(chspec)) {
16431 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
16432 band_chan_arr[index].flags &=
16433 ~IEEE80211_CHAN_NO_HT40;
16434 band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
16435 } else {
16436 /* It should be one of
16437 * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
16438 */
16439 band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
16440 if (ht40_flag == IEEE80211_CHAN_NO_HT40)
16441 band_chan_arr[index].flags |=
16442 IEEE80211_CHAN_NO_HT40MINUS;
16443 }
16444 } else {
16445 band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
16446 if (!legacy_chan_info) {
16447 channel = dtoh32
16448 (((wl_chanspec_list_v1_t *)list)->chspecs[i].chaninfo);
16449 } else {
16450 channel |= CHSPEC_BAND(chspec);
16451 }
16452 /* Update channel for radar/passive support */
16453 err = wl_update_chan_param(dev, channel,
16454 &band_chan_arr[index], &dfs_radar_disabled, legacy_chan_info);
16455 }
16456 }
16457
16458 }
16459
16460 __wl_band_2ghz.n_channels = ARRAYSIZE(__wl_2ghz_channels);
16461 __wl_band_5ghz_a.n_channels = ARRAYSIZE(__wl_5ghz_a_channels);
16462 #ifdef CFG80211_6G_SUPPORT
16463 __wl_band_6ghz.n_channels = ARRAYSIZE(__wl_6ghz_channels);
16464 #endif /* CFG80211_6G_SUPPORT */
16465
16466 MFREE(cfg->osh, list, LOCAL_BUF_LEN);
16467 #undef LOCAL_BUF_LEN
16468 return err;
16469 }
16470
16471 #ifdef WL_6G_BAND
wl_is_6g_supported(struct bcm_cfg80211 * cfg,u32 * bandlist,u8 nbands)16472 static void wl_is_6g_supported(struct bcm_cfg80211 *cfg, u32 *bandlist, u8 nbands)
16473 {
16474 u32 i = 0;
16475
16476 if (nbands > WL_MAX_BAND_SUPPORT) {
16477 return;
16478 }
16479 /* Check for 6GHz band support */
16480 for (i = 1; i <= nbands; i++) {
16481 if (bandlist[i] == WLC_BAND_6G) {
16482 cfg->band_6g_supported = true;
16483 }
16484 }
16485 }
16486 #endif /* WL_6G_BAND */
16487
__wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)16488 static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
16489 {
16490 struct wiphy *wiphy;
16491 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
16492 u32 bandlist[WL_MAX_BAND_SUPPORT+1];
16493 u32 nband = 0;
16494 u32 i = 0;
16495 s32 err = 0;
16496 s32 index = 0;
16497 s32 nmode = 0;
16498 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5)
16499 u32 j = 0;
16500 s32 vhtmode = 0;
16501 s32 txstreams = 0;
16502 s32 rxstreams = 0;
16503 s32 ldpc_cap = 0;
16504 s32 stbc_rx = 0;
16505 s32 stbc_tx = 0;
16506 s32 txbf_bfe_cap = 0;
16507 s32 txbf_bfr_cap = 0;
16508 #endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */
16509 s32 bw_cap = 0;
16510 s32 cur_band = -1;
16511 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, };
16512
16513 bzero(bandlist, sizeof(bandlist));
16514 err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist,
16515 sizeof(bandlist));
16516 if (unlikely(err)) {
16517 WL_ERR(("error read bandlist (%d)\n", err));
16518 return err;
16519 }
16520 err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band,
16521 sizeof(s32));
16522 if (unlikely(err)) {
16523 WL_ERR(("error (%d)\n", err));
16524 return err;
16525 }
16526
16527 err = wldev_iovar_getint(dev, "nmode", &nmode);
16528 if (unlikely(err)) {
16529 WL_ERR(("error reading nmode (%d)\n", err));
16530 }
16531
16532 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5)
16533 err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
16534 if (unlikely(err)) {
16535 WL_ERR(("error reading vhtmode (%d)\n", err));
16536 }
16537
16538 if (vhtmode) {
16539 err = wldev_iovar_getint(dev, "txstreams", &txstreams);
16540 if (unlikely(err)) {
16541 WL_ERR(("error reading txstreams (%d)\n", err));
16542 }
16543
16544 err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
16545 if (unlikely(err)) {
16546 WL_ERR(("error reading rxstreams (%d)\n", err));
16547 }
16548
16549 err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
16550 if (unlikely(err)) {
16551 WL_ERR(("error reading ldpc_cap (%d)\n", err));
16552 }
16553
16554 err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
16555 if (unlikely(err)) {
16556 WL_ERR(("error reading stbc_rx (%d)\n", err));
16557 }
16558
16559 err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
16560 if (unlikely(err)) {
16561 WL_ERR(("error reading stbc_tx (%d)\n", err));
16562 }
16563
16564 err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
16565 if (unlikely(err)) {
16566 WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
16567 }
16568
16569 err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
16570 if (unlikely(err)) {
16571 WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
16572 }
16573 }
16574 #endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */
16575
16576 /* For nmode and vhtmode check bw cap */
16577 if (nmode ||
16578 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5)
16579 vhtmode ||
16580 #endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */
16581 0) {
16582 err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
16583 if (unlikely(err)) {
16584 WL_ERR(("error get mimo_bw_cap (%d)\n", err));
16585 }
16586 }
16587
16588 #ifdef WL_6G_BAND
16589 wl_is_6g_supported(cfg, bandlist, bandlist[0]);
16590 #endif /* WL_6G_BAND */
16591
16592 err = wl_construct_reginfo(cfg, bw_cap);
16593 if (err) {
16594 WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
16595 if (err != BCME_UNSUPPORTED)
16596 return err;
16597 }
16598
16599 wiphy = bcmcfg_to_wiphy(cfg);
16600 nband = bandlist[0];
16601
16602 for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
16603 index = -1;
16604
16605 if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
16606 bands[IEEE80211_BAND_2GHZ] =
16607 &__wl_band_2ghz;
16608 index = IEEE80211_BAND_2GHZ;
16609 if (bw_cap == WLC_N_BW_40ALL)
16610 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
16611 } else {
16612 if (bandlist[i] == WLC_BAND_6G) {
16613 #ifdef CFG80211_6G_SUPPORT
16614 if (__wl_band_6ghz.n_channels > 0) {
16615 bands[IEEE80211_BAND_6GHZ] = &__wl_band_6ghz;
16616 index = IEEE80211_BAND_6GHZ;
16617 } else {
16618 WL_ERR(("6GHz channels not listed\n"));
16619 continue;
16620 }
16621 #else /* CFG80211_6G_SUPPORT */
16622 /* Both 6G/5G channels will be under 5G band list */
16623 if (__wl_band_5ghz_a.n_channels > 0)
16624 {
16625 bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
16626 index = IEEE80211_BAND_5GHZ;
16627 } else {
16628 WL_ERR(("5GHz channels not listed\n"));
16629 continue;
16630 }
16631 #endif /* CFG80211_6G_SUPPORT */
16632 } else if ((bandlist[i] == WLC_BAND_5G) &&
16633 (__wl_band_5ghz_a.n_channels > 0)) {
16634 bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
16635 index = IEEE80211_BAND_5GHZ;
16636 } else {
16637 WL_ERR(("Invalid band\n"));
16638 continue;
16639 }
16640
16641 if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
16642 bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
16643
16644 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) || defined(CUSTOMER_HW5)
16645 /* VHT capabilities. */
16646 if (vhtmode) {
16647 /* Supported */
16648 bands[index]->vht_cap.vht_supported = TRUE;
16649
16650 for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
16651 /* TX stream rates. */
16652 if (j <= txstreams) {
16653 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
16654 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
16655 } else {
16656 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
16657 bands[index]->vht_cap.vht_mcs.tx_mcs_map);
16658 }
16659
16660 /* RX stream rates. */
16661 if (j <= rxstreams) {
16662 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
16663 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
16664 } else {
16665 VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
16666 bands[index]->vht_cap.vht_mcs.rx_mcs_map);
16667 }
16668 }
16669
16670 /* Capabilities */
16671 /* 80 MHz is mandatory */
16672 bands[index]->vht_cap.cap |=
16673 IEEE80211_VHT_CAP_SHORT_GI_80;
16674
16675 if (WL_BW_CAP_160MHZ(bw_cap)) {
16676 bands[index]->vht_cap.cap |=
16677 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
16678 bands[index]->vht_cap.cap |=
16679 IEEE80211_VHT_CAP_SHORT_GI_160;
16680 }
16681
16682 bands[index]->vht_cap.cap |=
16683 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
16684
16685 if (ldpc_cap)
16686 bands[index]->vht_cap.cap |=
16687 IEEE80211_VHT_CAP_RXLDPC;
16688
16689 if (stbc_tx)
16690 bands[index]->vht_cap.cap |=
16691 IEEE80211_VHT_CAP_TXSTBC;
16692
16693 if (stbc_rx)
16694 bands[index]->vht_cap.cap |=
16695 (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
16696
16697 if (txbf_bfe_cap)
16698 bands[index]->vht_cap.cap |=
16699 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
16700
16701 if (txbf_bfr_cap) {
16702 bands[index]->vht_cap.cap |=
16703 IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
16704 }
16705
16706 if (txbf_bfe_cap || txbf_bfr_cap) {
16707 bands[index]->vht_cap.cap |=
16708 (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
16709 bands[index]->vht_cap.cap |=
16710 ((txstreams - 1) <<
16711 VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
16712 bands[index]->vht_cap.cap |=
16713 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
16714 }
16715
16716 /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
16717 bands[index]->vht_cap.cap |=
16718 (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
16719 WL_DBG(("__wl_update_wiphybands band[%d] vht_enab=%d vht_cap=%08x "
16720 "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
16721 index,
16722 bands[index]->vht_cap.vht_supported,
16723 bands[index]->vht_cap.cap,
16724 bands[index]->vht_cap.vht_mcs.rx_mcs_map,
16725 bands[index]->vht_cap.vht_mcs.tx_mcs_map));
16726 }
16727 #endif /* KERNEL >= 3.6 || CUSTOMER_HW5 */
16728 }
16729
16730 if ((index >= 0) && nmode) {
16731 bands[index]->ht_cap.cap |=
16732 (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
16733 bands[index]->ht_cap.ht_supported = TRUE;
16734 bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
16735 bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
16736 /* An HT shall support all EQM rates for one spatial stream */
16737 bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
16738 }
16739
16740 }
16741
16742 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
16743 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
16744 #ifdef CFG80211_6G_SUPPORT
16745 wiphy->bands[IEEE80211_BAND_6GHZ] = bands[IEEE80211_BAND_6GHZ];
16746 #endif /* CFG80211_6G_SUPPORT */
16747
16748 /* check if any bands populated otherwise makes 2Ghz as default */
16749 if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL &&
16750 #ifdef CFG80211_6G_SUPPORT
16751 wiphy->bands[IEEE80211_BAND_6GHZ] == NULL &&
16752 #endif /* CFG80211_6G_SUPPORT */
16753 wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) {
16754 /* Setup 2Ghz band as default */
16755 wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
16756 }
16757
16758 if (notify) {
16759 if (!IS_REGDOM_SELF_MANAGED(wiphy)) {
16760 WL_UPDATE_CUSTOM_REGULATORY(wiphy);
16761 wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
16762 }
16763 }
16764
16765 return 0;
16766 }
16767
wl_update_wiphybands(struct bcm_cfg80211 * cfg,bool notify)16768 s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
16769 {
16770 s32 err;
16771
16772 mutex_lock(&cfg->usr_sync);
16773 err = __wl_update_wiphybands(cfg, notify);
16774 mutex_unlock(&cfg->usr_sync);
16775
16776 return err;
16777 }
16778
__wl_cfg80211_up(struct bcm_cfg80211 * cfg)16779 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
16780 {
16781 s32 err = 0;
16782 s32 ret = 0;
16783
16784 struct net_info *netinfo = NULL;
16785 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
16786 struct wireless_dev *wdev = ndev->ieee80211_ptr;
16787 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
16788 #ifdef WLTDLS
16789 u32 tdls;
16790 #endif /* WLTDLS */
16791 u16 wl_iftype = 0;
16792 u16 wl_mode = 0;
16793 u8 ioctl_buf[WLC_IOCTL_SMLEN];
16794
16795 WL_DBG(("In\n"));
16796
16797 #if defined(__linux__)
16798 if (!dhd_download_fw_on_driverload) {
16799 #endif
16800 err = wl_create_event_handler(cfg);
16801 if (err) {
16802 WL_ERR(("wl_create_event_handler failed\n"));
16803 return err;
16804 }
16805 wl_init_event_handler(cfg);
16806 #if defined(__linux__)
16807 }
16808 #endif
16809 /* Reserve 0x8000 toggle bit for P2P GO/GC */
16810 cfg->vif_macaddr_mask = 0x8000;
16811
16812 #if defined(BCMDONGLEHOST)
16813 err = dhd_config_dongle(cfg);
16814 if (unlikely(err))
16815 return err;
16816 #endif /* defined(BCMDONGLEHOST) */
16817
16818 #ifdef SHOW_LOGTRACE
16819 /* Start the event logging */
16820 wl_add_remove_eventmsg(ndev, WLC_E_TRACE, TRUE);
16821 #endif /* SHOW_LOGTRACE */
16822
16823 (void)memcpy_s(wdev->wiphy->perm_addr, ETHER_ADDR_LEN,
16824 bcmcfg_to_prmry_ndev(cfg)->perm_addr, ETHER_ADDR_LEN);
16825 /* Always bring up interface in STA mode.
16826 * Did observe , if previous SofAP Bringup/cleanup
16827 * is not done properly, iftype is stuck with AP mode.
16828 * So during next wlan0 up, forcing the type to STA
16829 */
16830 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
16831 if (!netinfo) {
16832 WL_ERR(("there is no netinfo\n"));
16833 return -ENODEV;
16834 }
16835
16836 if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
16837 /* AP on primary interface case: Supplicant will
16838 * set mode first and then do dev_open. so in this
16839 * case, the type will already be set.
16840 */
16841 netinfo->iftype = WL_IF_TYPE_AP;
16842 } else {
16843 ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
16844 netinfo->iftype = WL_IF_TYPE_STA;
16845 }
16846
16847 if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
16848 return -EINVAL;
16849 }
16850 if (!dhd->fw_preinit) {
16851 err = wl_config_infra(cfg, ndev, wl_iftype);
16852 if (unlikely(err && err != -EINPROGRESS)) {
16853 WL_ERR(("wl_config_infra failed\n"));
16854 if (err == -1) {
16855 WL_ERR(("return error %d\n", err));
16856 return err;
16857 }
16858 }
16859 }
16860
16861 err = wl_init_scan(cfg);
16862 if (err) {
16863 WL_ERR(("wl_init_scan failed\n"));
16864 return err;
16865 }
16866 err = __wl_update_wiphybands(cfg, true);
16867 if (unlikely(err)) {
16868 WL_ERR(("wl_update_wiphybands failed\n"));
16869 if (err == -1) {
16870 WL_ERR(("return error %d\n", err));
16871 return err;
16872 }
16873 }
16874
16875 /* Update wlc version in cfg struct already queried as part of DHD initialization */
16876 cfg->wlc_ver.wlc_ver_major = dhd->wlc_ver_major;
16877 cfg->wlc_ver.wlc_ver_minor = dhd->wlc_ver_minor;
16878
16879 if ((ret = wldev_iovar_getbuf(ndev, "scan_ver", NULL, 0,
16880 ioctl_buf, sizeof(ioctl_buf), NULL)) == BCME_OK) {
16881 WL_INFORM_MEM(("scan_params v2\n"));
16882 /* use scan_params ver2 */
16883 cfg->scan_params_v2 = true;
16884 } else {
16885 if (ret == BCME_UNSUPPORTED) {
16886 WL_INFORM(("scan_ver, UNSUPPORTED\n"));
16887 ret = BCME_OK;
16888 } else {
16889 WL_INFORM(("get scan_ver err(%d)\n", ret));
16890 }
16891 }
16892
16893 if (((cfg->wlc_ver.wlc_ver_major == MIN_JOINEXT_V1_BR1_FW_MAJOR) &&
16894 (cfg->wlc_ver.wlc_ver_minor == MIN_JOINEXT_V1_BR1_FW_MINOR)) ||
16895 ((cfg->wlc_ver.wlc_ver_major == MIN_JOINEXT_V1_BR2_FW_MAJOR) &&
16896 (cfg->wlc_ver.wlc_ver_minor >= MIN_JOINEXT_V1_BR2_FW_MINOR)) ||
16897 (cfg->wlc_ver.wlc_ver_major >= MIN_JOINEXT_V1_FW_MAJOR)) {
16898 cfg->join_iovar_ver = WL_EXTJOIN_VERSION_V1;
16899 WL_INFORM_MEM(("join_ver:%d\n", cfg->join_iovar_ver));
16900 }
16901
16902 #ifdef DHD_LOSSLESS_ROAMING
16903 del_timer_sync(&cfg->roam_timeout);
16904 #endif /* DHD_LOSSLESS_ROAMING */
16905
16906 err = dhd_monitor_init(cfg->pub);
16907
16908 #ifdef WL_HOST_BAND_MGMT
16909 /* By default the curr_band is initialized to BAND_AUTO */
16910 if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) {
16911 if (ret == BCME_UNSUPPORTED) {
16912 /* Don't fail the initialization, lets just
16913 * fall back to the original method
16914 */
16915 WL_ERR(("WL_HOST_BAND_MGMT defined, "
16916 "but roam_band iovar not supported \n"));
16917 } else {
16918 WL_ERR(("roam_band failed. ret=%d", ret));
16919 err = -1;
16920 }
16921 }
16922 #endif /* WL_HOST_BAND_MGMT */
16923 /* Reset WES mode to 0 */
16924 cfg->wes_mode = OFF;
16925 cfg->ncho_mode = OFF;
16926 cfg->ncho_band = WLC_BAND_AUTO;
16927 #ifdef WBTEXT
16928 /* when wifi up, set roam_prof to default value */
16929 if (dhd->wbtext_support) {
16930 if (dhd->op_mode & DHD_FLAG_STA_MODE) {
16931 if (!dhd->fw_preinit) {
16932 wl_cfg80211_wbtext_set_default(ndev);
16933 }
16934 wl_cfg80211_wbtext_clear_bssid_list(cfg);
16935 }
16936 }
16937 #endif /* WBTEXT */
16938 #ifdef WLTDLS
16939 if (wldev_iovar_getint(ndev, "tdls_enable", &tdls) == 0) {
16940 WL_DBG(("TDLS supported in fw\n"));
16941 cfg->tdls_supported = true;
16942 }
16943 #endif /* WLTDLS */
16944 #ifdef WL_IFACE_MGMT
16945 #ifdef CUSTOM_IF_MGMT_POLICY
16946 cfg->iface_data.policy = CUSTOM_IF_MGMT_POLICY;
16947 #else
16948 cfg->iface_data.policy = WL_IF_POLICY_DEFAULT;
16949 #endif /* CUSTOM_IF_MGMT_POLICY */
16950 #endif /* WL_IFACE_MGMT */
16951 #ifdef WL_NAN
16952 #ifdef WL_NANP2P
16953 if (FW_SUPPORTED(dhd, nanp2p)) {
16954 /* Enable NANP2P concurrent support */
16955 cfg->conc_disc = WL_NANP2P_CONC_SUPPORT;
16956 WL_INFORM_MEM(("nan + p2p conc discovery is supported\n"));
16957 cfg->nan_p2p_supported = true;
16958 }
16959 #endif /* WL_NANP2P */
16960 #endif /* WL_NAN */
16961
16962 #ifdef WL_SAR_TX_POWER
16963 cfg->wifi_tx_power_mode = WIFI_POWER_SCENARIO_INVALID;
16964 #endif /* WL_SAR_TX_POWER */
16965
16966 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
16967 /* wlan scan_supp timer and work thread info */
16968 init_timer_compat(&cfg->scan_supp_timer, wl_cfg80211_scan_supp_timerfunc, cfg);
16969 INIT_WORK(&cfg->wlan_work, wl_cfg80211_work_handler);
16970 #endif /* DHCP_SCAN_SUPPRESS */
16971
16972 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
16973 wl_set_drv_status(cfg, READY, ndev);
16974
16975 return err;
16976 }
16977
__wl_cfg80211_down(struct bcm_cfg80211 * cfg)16978 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
16979 {
16980 s32 err = 0;
16981 struct net_info *iter, *next;
16982 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
16983 #if defined(WL_CFG80211) && \
16984 (defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && \
16985 !defined(PLATFORM_SLP)
16986 struct net_device *p2p_net = cfg->p2p_net;
16987 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) && !PLATFORM_SLP */
16988 #ifdef BCMDONGLEHOST
16989 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
16990 #endif /* BCMDONGLEHOST */
16991 WL_INFORM_MEM(("cfg80211 down\n"));
16992
16993 /* Check if cfg80211 interface is already down */
16994 if (!wl_get_drv_status(cfg, READY, ndev)) {
16995 WL_DBG(("cfg80211 interface is already down\n"));
16996 return err; /* it is even not ready */
16997 }
16998
16999 #ifdef SHOW_LOGTRACE
17000 /* Stop the event logging */
17001 wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
17002 #endif /* SHOW_LOGTRACE */
17003
17004 /* clear vendor OUI list */
17005 wl_vndr_ies_clear_vendor_oui_list(cfg);
17006
17007 /* clear timestamps */
17008 CLR_TS(cfg, scan_start);
17009 CLR_TS(cfg, scan_cmplt);
17010 CLR_TS(cfg, conn_start);
17011 CLR_TS(cfg, conn_cmplt);
17012 CLR_TS(cfg, authorize_start);
17013 CLR_TS(cfg, authorize_cmplt);
17014
17015 /* Delete pm_enable_work */
17016 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
17017
17018 if (cfg->loc.in_progress) {
17019 /* Listen in progress */
17020 if (delayed_work_pending(&cfg->loc.work)) {
17021 cancel_delayed_work_sync(&cfg->loc.work);
17022 }
17023 wl_cfgscan_notify_listen_complete(cfg);
17024 }
17025
17026 if (delayed_work_pending(&cfg->ap_work)) {
17027 cancel_delayed_work_sync(&cfg->ap_work);
17028 }
17029
17030 if (cfg->p2p_supported) {
17031 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
17032 #ifdef PROP_TXSTATUS_VSDB
17033 #if defined(BCMSDIO) || defined(BCMDBUS)
17034 if (wl_cfgp2p_vif_created(cfg)) {
17035 bool enabled = false;
17036 dhd_wlfc_get_enable(dhd, &enabled);
17037 /* WLFC should be turned off
17038 * while unloading dhd driver in IBSS or SoftAP mode
17039 */
17040 if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
17041 dhd->op_mode != DHD_FLAG_IBSS_MODE) {
17042 dhd_wlfc_deinit(dhd);
17043 cfg->wlfc_on = false;
17044 }
17045 }
17046 #endif /* BCMSDIO || BCMDBUS */
17047 #endif /* PROP_TXSTATUS_VSDB */
17048 }
17049
17050 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
17051 /* Force clear of scan_suppress */
17052 if (cfg->scan_suppressed)
17053 wl_cfg80211_scan_suppress(ndev, 0);
17054 del_timer_sync(&cfg->scan_supp_timer);
17055 cancel_work_sync(&cfg->wlan_work);
17056 #endif /* DHCP_SCAN_SUPPRESS */
17057
17058 #ifdef WL_SAR_TX_POWER
17059 cfg->wifi_tx_power_mode = WIFI_POWER_SCENARIO_INVALID;
17060 #endif /* WL_SAR_TX_POWER */
17061 if (!dhd_download_fw_on_driverload) {
17062 /* For built-in drivers/other drivers that do reset on
17063 * "ifconfig <primary_iface> down", cleanup any left
17064 * over interfaces
17065 */
17066 wl_cfg80211_cleanup_virtual_ifaces(cfg, false);
17067 }
17068 /* Clear used mac addr mask */
17069 cfg->vif_macaddr_mask = 0;
17070
17071 #ifdef BCMDONGLEHOST
17072 if (dhd->up)
17073 #endif /* BCMDONGLEHOST */
17074 {
17075 /* If primary BSS is operational (for e.g SoftAP), bring it down */
17076 if (wl_cfg80211_bss_isup(ndev, 0)) {
17077 if (wl_cfg80211_bss_up(cfg, ndev, 0, 0) < 0)
17078 WL_ERR(("BSS down failed \n"));
17079 }
17080
17081 /* clear all the security setting on primary Interface */
17082 wl_cfg80211_clear_security(cfg);
17083 }
17084
17085 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17086 for_each_ndev(cfg, iter, next) {
17087 GCC_DIAGNOSTIC_POP();
17088 if (iter->ndev) /* p2p discovery iface is null */
17089 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
17090 }
17091 #ifdef WL_SDO
17092 wl_cfg80211_sdo_deinit(cfg);
17093 #endif
17094
17095 #ifdef P2P_LISTEN_OFFLOADING
17096 wl_cfg80211_p2plo_deinit(cfg);
17097 #endif /* P2P_LISTEN_OFFLOADING */
17098
17099 /* cancel and notify scan complete, if scan request is pending */
17100 wl_cfgscan_cancel_scan(cfg);
17101 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17102 for_each_ndev(cfg, iter, next) {
17103 GCC_DIAGNOSTIC_POP();
17104 /* p2p discovery iface ndev ptr could be null */
17105 if (iter->ndev == NULL)
17106 continue;
17107 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
17108 WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]\n",
17109 wl_get_drv_status(cfg, CONNECTING, ndev),
17110 wl_get_drv_status(cfg, CONNECTED, ndev),
17111 wl_get_drv_status(cfg, DISCONNECTING, ndev),
17112 wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
17113
17114 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
17115 CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
17116 wl_clr_drv_status(cfg, AUTHORIZED, iter->ndev);
17117 }
17118
17119 if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
17120 wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
17121
17122 u8 *latest_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
17123 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
17124 struct wireless_dev *wdev = ndev->ieee80211_ptr;
17125 struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid,
17126 wdev->ssid, wdev->ssid_len);
17127
17128 BCM_REFERENCE(bss);
17129
17130 CFG80211_CONNECT_RESULT(ndev,
17131 latest_bssid, bss, NULL, 0, NULL, 0,
17132 WLAN_STATUS_UNSPECIFIED_FAILURE,
17133 GFP_KERNEL);
17134 }
17135 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
17136 wl_clr_drv_status(cfg, READY, iter->ndev);
17137 wl_clr_drv_status(cfg, SCANNING, iter->ndev);
17138 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
17139 wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
17140 wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
17141 wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
17142 wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
17143 wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
17144 wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev);
17145 wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev);
17146 }
17147 bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
17148 NL80211_IFTYPE_STATION;
17149 #if defined(WL_CFG80211) && \
17150 (defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && \
17151 !defined(PLATFORM_SLP)
17152 #ifdef SUPPORT_DEEP_SLEEP
17153 if (!trigger_deep_sleep)
17154 #endif /* SUPPORT_DEEP_SLEEP */
17155 if (p2p_net)
17156 dev_close(p2p_net);
17157 #endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT)&& !PLATFORM_SLP */
17158
17159 /* Avoid deadlock from wl_cfg80211_down */
17160 #if defined(BCMDONGLEHOST) && defined(__linux__)
17161 if (!dhd_download_fw_on_driverload) {
17162 #endif
17163 mutex_unlock(&cfg->usr_sync);
17164 wl_destroy_event_handler(cfg);
17165 mutex_lock(&cfg->usr_sync);
17166 #if defined(BCMDONGLEHOST) && defined(__linux__)
17167 }
17168 #endif
17169
17170 wl_flush_eq(cfg);
17171 wl_link_down(cfg);
17172 if (cfg->p2p_supported) {
17173 if (timer_pending(&cfg->p2p->listen_timer))
17174 del_timer_sync(&cfg->p2p->listen_timer);
17175 wl_cfgp2p_down(cfg);
17176 }
17177
17178 del_timer_sync(&cfg->scan_timeout);
17179
17180 wl_cfg80211_clear_mgmt_vndr_ies(cfg);
17181
17182 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
17183 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
17184 #endif
17185
17186 dhd_monitor_uninit();
17187 #ifdef WLAIBSS_MCHAN
17188 bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
17189 #endif /* WLAIBSS_MCHAN */
17190
17191 #ifdef WL11U
17192 /* Clear interworking element. */
17193 if (cfg->wl11u) {
17194 cfg->wl11u = FALSE;
17195 }
17196 #endif /* WL11U */
17197
17198 #ifdef CUSTOMER_HW4_DEBUG
17199 if (wl_scan_timeout_dbg_enabled) {
17200 wl_scan_timeout_dbg_clear();
17201 }
17202 #endif /* CUSTOMER_HW4_DEBUG */
17203
17204 cfg->disable_roam_event = false;
17205 cfg->scan_params_v2 = false;
17206
17207 DNGL_FUNC(dhd_cfg80211_down, (cfg));
17208
17209 #ifdef DHD_IFDEBUG
17210 /* Printout all netinfo entries */
17211 wl_probe_wdev_all(cfg);
17212 #endif /* DHD_IFDEBUG */
17213
17214 return err;
17215 }
17216
wl_cfg80211_up(struct net_device * net)17217 s32 wl_cfg80211_up(struct net_device *net)
17218 {
17219 struct bcm_cfg80211 *cfg;
17220 s32 err = 0;
17221 int val = 1;
17222 #ifdef BCMDONGLEHOST
17223 dhd_pub_t *dhd;
17224 #endif /* BCMDONGLEHOST */
17225 #ifdef DISABLE_PM_BCNRX
17226 s32 interr = 0;
17227 uint param = 0;
17228 s8 iovbuf[WLC_IOCTL_SMLEN];
17229 #endif /* DISABLE_PM_BCNRX */
17230 #ifdef WL_USE_RANDOMIZED_SCAN
17231 uint8 random_addr[ETHER_ADDR_LEN] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
17232 #endif /* WL_USE_RANDOMIZED_SCAN */
17233 WL_DBG(("In\n"));
17234 cfg = wl_get_cfg(net);
17235
17236 if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
17237 sizeof(int)) < 0)) {
17238 WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
17239 return err;
17240 }
17241 val = dtoh32(val);
17242 if (val != WLC_IOCTL_VERSION && val != 1) {
17243 WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
17244 val, WLC_IOCTL_VERSION));
17245 return BCME_VERSION;
17246 }
17247 ioctl_version = val;
17248 WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
17249 #ifdef WL_EXT_IAPSTA
17250 wl_ext_in4way_sync(net, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
17251 WL_EXT_STATUS_DISCONNECTED, NULL);
17252 #endif
17253
17254 mutex_lock(&cfg->usr_sync);
17255 #if defined(BCMDONGLEHOST)
17256 dhd = (dhd_pub_t *)(cfg->pub);
17257 if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
17258 err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
17259 if (unlikely(err)) {
17260 mutex_unlock(&cfg->usr_sync);
17261 return err;
17262 }
17263 }
17264 #ifdef WLMESH_CFG80211
17265 cfg->wdev->wiphy->features |= NL80211_FEATURE_USERSPACE_MPM;
17266 #endif /* WLMESH_CFG80211 */
17267 #if defined(BCMSUP_4WAY_HANDSHAKE)
17268 if (dhd->fw_4way_handshake) {
17269 /* This is a hacky method to indicate fw 4WHS support and
17270 * is used only for kernels (kernels < 3.14). For newer
17271 * kernels, we would be using vendor extn. path to advertise
17272 * FW based 4-way handshake feature support.
17273 */
17274 cfg->wdev->wiphy->features |= NL80211_FEATURE_FW_4WAY_HANDSHAKE;
17275 }
17276 #endif /* BCMSUP_4WAY_HANDSHAKE */
17277 #endif /* defined(BCMDONGLEHOST) */
17278 err = __wl_cfg80211_up(cfg);
17279 if (unlikely(err))
17280 WL_ERR(("__wl_cfg80211_up failed\n"));
17281
17282 #ifdef ROAM_CHANNEL_CACHE
17283 if (init_roam_cache(cfg, ioctl_version) == 0) {
17284 /* Enable support for Roam cache */
17285 cfg->rcc_enabled = true;
17286 WL_ERR(("Roam channel cache enabled\n"));
17287 } else {
17288 WL_ERR(("Failed to enable RCC.\n"));
17289 }
17290 #endif /* ROAM_CHANNEL_CACHE */
17291 #ifdef WL_USE_RANDOMIZED_SCAN
17292 /* Call scanmac only for valid configuration */
17293 if (wl_cfg80211_scan_mac_enable(net)) {
17294 WL_ERR(("%s : randmac enable failed\n", __FUNCTION__));
17295 } else {
17296 /* scanmac enabled. apply configuration */
17297 if (wl_cfg80211_scan_mac_config(net, random_addr, NULL)) {
17298 WL_ERR(("%s : failed to set randmac config for scan\n", __FUNCTION__));
17299 /* if config fails, disable scan mac */
17300 wl_cfg80211_scan_mac_disable(net);
17301 }
17302 }
17303 #endif /* WL_USE_RANDOMIZED_SCAN */
17304 /* WAR: disable pm_bcnrx , scan_ps for BCM4354 WISOL module.
17305 * WISOL module have ANT_1 Rx sensitivity issue.
17306 */
17307 #if defined(FORCE_DISABLE_SINGLECORE_SCAN)
17308 dhd_force_disable_singlcore_scan(dhd);
17309 #endif /* FORCE_DISABLE_SINGLECORE_SCAN */
17310
17311 /* IOVAR configurations with 'up' condition */
17312 #ifdef DISABLE_PM_BCNRX
17313 interr = wldev_iovar_setbuf(net, "pm_bcnrx", (char *)¶m, sizeof(param), iovbuf,
17314 sizeof(iovbuf), &cfg->ioctl_buf_sync);
17315
17316 if (unlikely(interr)) {
17317 WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
17318 }
17319 #endif /* DISABLE_PM_BCNRX */
17320 #ifdef WL_CHAN_UTIL
17321 interr = wl_cfg80211_start_bssload_report(net);
17322 if (unlikely(interr)) {
17323 WL_ERR(("%s: Failed to start bssload_report eventing, err=%d\n",
17324 __FUNCTION__, interr));
17325 }
17326 #endif /* WL_CHAN_UTIL */
17327
17328 mutex_unlock(&cfg->usr_sync);
17329
17330 #ifdef WLAIBSS_MCHAN
17331 bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
17332 #endif /* WLAIBSS_MCHAN */
17333 cfg->spmk_info_list->pmkids.count = 0;
17334 return err;
17335 }
17336
17337 /* Private Event to Supplicant with indication that chip hangs */
wl_cfg80211_hang(struct net_device * dev,u16 reason)17338 int wl_cfg80211_hang(struct net_device *dev, u16 reason)
17339 {
17340 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17341 #ifdef BCMDONGLEHOST
17342 dhd_pub_t *dhd;
17343 #if defined(SOFTAP_SEND_HANGEVT)
17344 /* specifc mac address used for hang event */
17345 uint8 hang_mac[ETHER_ADDR_LEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
17346 #endif /* SOFTAP_SEND_HANGEVT */
17347 #endif /* BCMDONGLEHOST */
17348 if (!cfg) {
17349 return BCME_ERROR;
17350 }
17351
17352 RETURN_EIO_IF_NOT_UP(cfg);
17353
17354 #ifdef BCMDONGLEHOST
17355 dhd = (dhd_pub_t *)(cfg->pub);
17356 #if defined(DHD_HANG_SEND_UP_TEST)
17357 if (dhd->req_hang_type) {
17358 WL_ERR(("wl_cfg80211_hang, Clear HANG test request 0x%x\n",
17359 dhd->req_hang_type));
17360 dhd->req_hang_type = 0;
17361 }
17362 #endif /* DHD_HANG_SEND_UP_TEST */
17363 if ((dhd->hang_reason <= HANG_REASON_MASK) || (dhd->hang_reason >= HANG_REASON_MAX)) {
17364 WL_ERR(("wl_cfg80211_hang, Invalid hang reason 0x%x\n",
17365 dhd->hang_reason));
17366 dhd->hang_reason = HANG_REASON_UNKNOWN;
17367 }
17368 #ifdef DHD_USE_EXTENDED_HANG_REASON
17369 /* The proper dhd->hang_reason handling codes should be implemented
17370 * in the WPA Supplicant/Hostapd or Android framework.
17371 * If not, HANG event may not be sent to Android framework and
17372 * driver cannot be reloaded.
17373 * Please do not enable DHD_USE_EXTENDED_HANG_REASON if your Android platform
17374 * cannot handle the dhd->hang_reason value.
17375 */
17376 if (dhd->hang_reason != 0) {
17377 reason = dhd->hang_reason;
17378 }
17379 #endif /* DHD_USE_EXTENDED_HANG_REASON */
17380 WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32)(dhd->hang_reason)));
17381 #else
17382 WL_ERR(("In : chip crash eventing\n"));
17383 #endif /* BCMDONGLEHOST */
17384
17385 wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
17386 #ifdef BCMDONGLEHOST
17387 #ifdef SOFTAP_SEND_HANGEVT
17388 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
17389 cfg80211_del_sta(dev, hang_mac, GFP_ATOMIC);
17390 } else
17391 #endif /* SOFTAP_SEND_HANGEVT */
17392 #endif /* BCMDONGLEHOST */
17393 {
17394 if (dhd->up == TRUE) {
17395 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
17396 #ifdef CUSOMER_HW4
17397 wl_cfgvendor_send_hang_event(dev, reason,
17398 dhd->hang_info, dhd->hang_info_cnt);
17399 #else
17400 wl_cfgvendor_simple_hang_event(dev, reason);
17401 #endif
17402 #else
17403 CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
17404 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
17405 }
17406 }
17407 #if defined(RSSIAVG)
17408 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
17409 #endif
17410 #if defined(BSSCACHE)
17411 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
17412 #endif
17413 if (cfg != NULL) {
17414 /* Do we need to call wl_cfg80211_down here ? */
17415 wl_link_down(cfg);
17416 }
17417 return 0;
17418 }
17419
wl_cfg80211_down(struct net_device * dev)17420 s32 wl_cfg80211_down(struct net_device *dev)
17421 {
17422 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17423 #ifdef RTT_SUPPORT
17424 dhd_pub_t *dhdp;
17425 #endif /* RTT_SUPPORT */
17426
17427 s32 err = BCME_ERROR;
17428
17429 WL_DBG(("In\n"));
17430
17431 if (cfg && (cfg == wl_cfg80211_get_bcmcfg())) {
17432 #ifdef WL_NAN
17433 mutex_lock(&cfg->if_sync);
17434 wl_cfgnan_check_nan_disable_pending(cfg, true, false);
17435 mutex_unlock(&cfg->if_sync);
17436 #endif /* WL_NAN */
17437
17438 #ifdef RTT_SUPPORT
17439 dhdp = (dhd_pub_t *)(cfg->pub);
17440 if (dhdp->rtt_state) {
17441 dhd_rtt_deinit(dhdp);
17442 }
17443 #endif /* RTT_SUPPORT */
17444 mutex_lock(&cfg->usr_sync);
17445 #if defined(RSSIAVG)
17446 wl_free_rssi_cache(&cfg->g_rssi_cache_ctrl);
17447 #endif
17448 #if defined(BSSCACHE)
17449 wl_free_bss_cache(&cfg->g_bss_cache_ctrl);
17450 #endif
17451 err = __wl_cfg80211_down(cfg);
17452 mutex_unlock(&cfg->usr_sync);
17453 }
17454
17455 return err;
17456 }
17457
17458 void
wl_cfg80211_sta_ifdown(struct net_device * dev)17459 wl_cfg80211_sta_ifdown(struct net_device *dev)
17460 {
17461 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
17462
17463 WL_DBG(("In\n"));
17464
17465 if (cfg) {
17466 /* cancel scan if anything pending */
17467 wl_cfgscan_cancel_scan(cfg);
17468 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
17469 if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
17470 wl_get_drv_status(cfg, CONNECTED, dev)) {
17471 CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
17472 }
17473 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
17474 }
17475 }
17476
wl_read_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 item)17477 void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
17478 {
17479 unsigned long flags;
17480 void *rptr = NULL;
17481 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
17482
17483 if (!profile)
17484 return NULL;
17485 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
17486 switch (item) {
17487 case WL_PROF_SEC:
17488 rptr = &profile->sec;
17489 break;
17490 case WL_PROF_ACT:
17491 rptr = &profile->active;
17492 break;
17493 case WL_PROF_BSSID:
17494 rptr = profile->bssid;
17495 break;
17496 case WL_PROF_SSID:
17497 rptr = &profile->ssid;
17498 break;
17499 case WL_PROF_CHAN:
17500 rptr = &profile->channel;
17501 break;
17502 case WL_PROF_LATEST_BSSID:
17503 rptr = profile->latest_bssid;
17504 break;
17505 }
17506 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
17507 if (!rptr)
17508 WL_ERR(("invalid item (%d)\n", item));
17509 return rptr;
17510 }
17511
17512 s32
wl_update_prof(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,const void * data,s32 item)17513 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
17514 const wl_event_msg_t *e, const void *data, s32 item)
17515 {
17516 s32 err = 0;
17517 const struct wlc_ssid *ssid;
17518 unsigned long flags;
17519 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
17520
17521 if (!profile)
17522 return WL_INVALID;
17523 WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
17524 switch (item) {
17525 case WL_PROF_SSID:
17526 ssid = (const wlc_ssid_t *) data;
17527 bzero(profile->ssid.SSID,
17528 sizeof(profile->ssid.SSID));
17529 profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
17530 memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
17531 break;
17532 case WL_PROF_BSSID:
17533 if (data)
17534 memcpy(profile->bssid, data, ETHER_ADDR_LEN);
17535 else
17536 bzero(profile->bssid, ETHER_ADDR_LEN);
17537 break;
17538 case WL_PROF_SEC:
17539 memcpy(&profile->sec, data, sizeof(profile->sec));
17540 break;
17541 case WL_PROF_ACT:
17542 profile->active = *(const bool *)data;
17543 break;
17544 case WL_PROF_BEACONINT:
17545 profile->beacon_interval = *(const u16 *)data;
17546 break;
17547 case WL_PROF_DTIMPERIOD:
17548 profile->dtim_period = *(const u8 *)data;
17549 break;
17550 case WL_PROF_CHAN:
17551 profile->channel = *(const chanspec_t *)data;
17552 break;
17553 case WL_PROF_LATEST_BSSID:
17554 if (data) {
17555 memcpy_s(profile->latest_bssid, sizeof(profile->latest_bssid),
17556 data, ETHER_ADDR_LEN);
17557 } else {
17558 memset_s(profile->latest_bssid, sizeof(profile->latest_bssid),
17559 0, ETHER_ADDR_LEN);
17560 }
17561 break;
17562 default:
17563 err = -EOPNOTSUPP;
17564 break;
17565 }
17566 WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
17567
17568 if (err == -EOPNOTSUPP)
17569 WL_ERR(("unsupported item (%d)\n", item));
17570
17571 return err;
17572 }
17573
wl_cfg80211_dbg_level(u32 level)17574 void wl_cfg80211_dbg_level(u32 level)
17575 {
17576 /*
17577 * prohibit to change debug level
17578 * by insmod parameter.
17579 * eventually debug level will be configured
17580 * in compile time by using CONFIG_XXX
17581 */
17582 /* wl_dbg_level = level; */
17583 }
17584
wl_is_ibssstarter(struct bcm_cfg80211 * cfg)17585 static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
17586 {
17587 return cfg->ibss_starter;
17588 }
17589
wl_add_ie(struct bcm_cfg80211 * cfg,u8 t,u8 l,u8 * v)17590 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
17591 {
17592 struct wl_ie *ie = wl_to_ie(cfg);
17593 s32 err = 0;
17594
17595 if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
17596 WL_ERR(("ei crosses buffer boundary\n"));
17597 return -ENOSPC;
17598 }
17599 ie->buf[ie->offset] = t;
17600 ie->buf[ie->offset + 1] = l;
17601 memcpy(&ie->buf[ie->offset + 2], v, l);
17602 ie->offset += l + 2;
17603
17604 return err;
17605 }
17606
wl_link_up(struct bcm_cfg80211 * cfg)17607 static void wl_link_up(struct bcm_cfg80211 *cfg)
17608 {
17609 cfg->link_up = true;
17610 }
17611
wl_link_down(struct bcm_cfg80211 * cfg)17612 static void wl_link_down(struct bcm_cfg80211 *cfg)
17613 {
17614 struct wl_connect_info *conn_info = wl_to_conn(cfg);
17615
17616 WL_DBG(("In\n"));
17617 cfg->link_up = false;
17618 if (conn_info) {
17619 conn_info->req_ie_len = 0;
17620 conn_info->resp_ie_len = 0;
17621 }
17622 }
17623
wl_lock_eq(struct bcm_cfg80211 * cfg)17624 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
17625 {
17626 unsigned long flags;
17627
17628 WL_CFG_EQ_LOCK(&cfg->eq_lock, flags);
17629 return flags;
17630 }
17631
wl_unlock_eq(struct bcm_cfg80211 * cfg,unsigned long flags)17632 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
17633 {
17634 WL_CFG_EQ_UNLOCK(&cfg->eq_lock, flags);
17635 }
17636
wl_init_eq_lock(struct bcm_cfg80211 * cfg)17637 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
17638 {
17639 spin_lock_init(&cfg->eq_lock);
17640 }
17641
wl_delay(u32 ms)17642 static void wl_delay(u32 ms)
17643 {
17644 if (in_atomic() || (ms < jiffies_to_msecs(1))) {
17645 OSL_DELAY(ms*1000);
17646 } else {
17647 OSL_SLEEP(ms);
17648 }
17649 }
17650
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)17651 s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
17652 {
17653 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17654 struct ether_addr primary_mac;
17655 if (!cfg->p2p)
17656 return -1;
17657 if (!p2p_is_on(cfg)) {
17658 get_primary_mac(cfg, &primary_mac);
17659 memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN);
17660 } else {
17661 memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
17662 ETHER_ADDR_LEN);
17663 }
17664
17665 return 0;
17666 }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)17667 s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
17668 {
17669 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17670
17671 return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
17672 }
17673
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)17674 s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
17675 {
17676 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17677
17678 return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
17679 }
17680
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)17681 s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
17682 {
17683 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17684
17685 return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
17686 }
17687
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)17688 s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
17689 {
17690 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17691
17692 return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
17693 }
17694
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)17695 s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
17696 {
17697 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
17698
17699 return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
17700 }
17701
17702 #ifdef P2PLISTEN_AP_SAMECHN
wl_cfg80211_set_p2p_resp_ap_chn(struct net_device * net,s32 enable)17703 s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
17704 {
17705 s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
17706
17707 if ((ret == 0) && enable) {
17708 /* disable PM for p2p responding on infra AP channel */
17709 s32 pm = PM_OFF;
17710
17711 ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm));
17712 }
17713
17714 return ret;
17715 }
17716 #endif /* P2PLISTEN_AP_SAMECHN */
17717
17718 #ifdef WL_SDO
17719 #define MAX_QR_LEN NLMSG_GOODSIZE
17720
17721 typedef struct wl_cfg80211_dev_info {
17722 u16 band;
17723 u16 freq;
17724 s16 rssi;
17725 u16 ie_len;
17726 u8 bssid[ETH_ALEN];
17727 } wl_cfg80211_dev_info_t;
17728
17729 static s32
wl_notify_device_discovery(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)17730 wl_notify_device_discovery(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17731 const wl_event_msg_t *e, void *data)
17732 {
17733 int err = 0;
17734 u32 event = ntoh32(e->event_type);
17735 wl_cfg80211_dev_info_t info;
17736 wl_bss_info_t *bi = NULL;
17737 struct net_device *ndev = NULL;
17738 u8 *buf = NULL;
17739 u32 buflen = 0;
17740 u16 channel = 0;
17741 wl_escan_result_t *escan_result;
17742 chanspec_t chspec = INVCHANSPEC;
17743
17744 WL_SD(("Enter. type:%d \n", event));
17745
17746 if ((event != WLC_E_P2PO_ADD_DEVICE) && (event != WLC_E_P2PO_DEL_DEVICE)) {
17747 WL_ERR(("Unknown Event\n"));
17748 return -EINVAL;
17749 }
17750
17751 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17752
17753 mutex_lock(&cfg->usr_sync);
17754 if (event == WLC_E_P2PO_DEL_DEVICE) {
17755 WL_SD(("DEV_LOST MAC:"MACDBG" \n", MAC2STRDBG(e->addr.octet)));
17756 err = wl_genl_send_msg(ndev, event, (const u8 *)e->addr.octet, ETH_ALEN, 0, 0);
17757 } else {
17758
17759 escan_result = (wl_escan_result_t *) data;
17760
17761 if (dtoh16(escan_result->bss_count) != 1) {
17762 WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
17763 err = -EINVAL;
17764 goto exit;
17765 }
17766
17767 bi = escan_result->bss_info;
17768 buflen = dtoh32(bi->length);
17769 if (unlikely(buflen > WL_BSS_INFO_MAX)) {
17770 WL_DBG(("Beacon is larger than buffer. Discarding\n"));
17771 err = -EINVAL;
17772 goto exit;
17773 }
17774
17775 /* Update sub-header */
17776 bzero(&info, sizeof(wl_cfg80211_dev_info_t));
17777 chspec = wl_chspec_driver_to_host(bi->chanspec);
17778 channel = wf_chspec_ctlchan(chspec);
17779 info.freq = wl_channel_to_frequency(channel, CHSPEC_BAND(chspec));
17780 info.rssi = wl_rssi_offset(dtoh16(bi->RSSI));
17781 memcpy(info.bssid, &bi->BSSID, ETH_ALEN);
17782 info.ie_len = buflen;
17783
17784 WL_SD(("DEV_FOUND band:%x Freq:%d rssi:%x "MACDBG" \n",
17785 info.band, info.freq, info.rssi, MAC2STRDBG(info.bssid)));
17786
17787 buf = ((u8 *) bi) + bi->ie_offset;
17788 err = wl_genl_send_msg(ndev, event, buf,
17789 buflen, (u8 *)&info, sizeof(wl_cfg80211_dev_info_t));
17790 }
17791 exit:
17792 mutex_unlock(&cfg->usr_sync);
17793 return err;
17794 }
17795
17796 s32
wl_cfg80211_sdo_init(struct bcm_cfg80211 * cfg)17797 wl_cfg80211_sdo_init(struct bcm_cfg80211 *cfg)
17798 {
17799 if (cfg->sdo) {
17800 WL_SD(("SDO already initialized\n"));
17801 return 0;
17802 }
17803
17804 cfg->sdo = (sd_offload_t *)MALLOCZ(cfg->osh, sizeof(sd_offload_t));
17805 if (!cfg->sdo) {
17806 WL_ERR(("MALLOCZ failed for SDO \n"));
17807 return -ENOMEM;
17808 }
17809
17810 return 0;
17811 }
17812
17813 s32
wl_cfg80211_sdo_deinit(struct bcm_cfg80211 * cfg)17814 wl_cfg80211_sdo_deinit(struct bcm_cfg80211 *cfg)
17815 {
17816 s32 bssidx;
17817 int ret = 0;
17818 int sdo_pause = 0;
17819 if (!cfg || !cfg->p2p) {
17820 WL_ERR(("Wl %p or cfg->p2p %p is null\n",
17821 cfg, cfg ? cfg->p2p : 0));
17822 return 0;
17823 }
17824
17825 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
17826 if (!cfg->sdo) {
17827 WL_DBG(("SDO Not Initialized. Do nothing. \n"));
17828 return 0;
17829 }
17830 if (cfg->sdo->dd_state &&
17831 (ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
17832 "p2po_stop", (void*)&sdo_pause, sizeof(sdo_pause),
17833 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) {
17834 WL_ERR(("p2po_stop Failed :%d\n", ret));
17835 }
17836 MFREE(cfg->osh, cfg->sdo, sizeof(sd_offload_t));
17837
17838 WL_SD(("SDO Deinit Done \n"));
17839
17840 return 0;
17841 }
17842
17843 s32
wl_cfg80211_resume_sdo(struct net_device * dev,struct bcm_cfg80211 * cfg)17844 wl_cfg80211_resume_sdo(struct net_device *dev, struct bcm_cfg80211 *cfg)
17845 {
17846 wl_sd_listen_t sd_listen;
17847 int ret = 0;
17848 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
17849
17850 WL_DBG(("Enter\n"));
17851
17852 if (!cfg->sdo) {
17853 return -EINVAL;
17854 }
17855
17856 if (dev == NULL)
17857 dev = bcmcfg_to_prmry_ndev(cfg);
17858
17859 /* Disable back the ESCAN events for the offload */
17860 wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, false);
17861
17862 /* Resume according to the saved state */
17863 if (cfg->sdo->dd_state == WL_DD_STATE_SEARCH) {
17864 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_find", NULL, 0,
17865 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) {
17866 WL_ERR(("p2po_find Failed :%d\n", ret));
17867 }
17868 } else if (cfg->sdo->dd_state == WL_DD_STATE_LISTEN) {
17869 /* Need to save the listen params in the set context
17870 * so that those values can be restored in the resume context
17871 */
17872 sd_listen.interval = cfg->sdo->sd_listen.interval;
17873 sd_listen.period = cfg->sdo->sd_listen.period;
17874
17875 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&sd_listen,
17876 sizeof(wl_sd_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
17877 bssidx, &cfg->ioctl_buf_sync)) < 0) {
17878 WL_ERR(("p2po_listen Failed :%d\n", ret));
17879 }
17880
17881 }
17882
17883 /* p2po_stop clears of the eventmask for GAS. Set it back */
17884 wl_add_remove_eventmsg(dev, WLC_E_SERVICE_FOUND, true);
17885 wl_add_remove_eventmsg(dev, WLC_E_GAS_FRAGMENT_RX, true);
17886 wl_add_remove_eventmsg(dev, WLC_E_GAS_COMPLETE, true);
17887
17888 WL_SD(("SDO Resumed \n"));
17889
17890 return ret;
17891 }
17892
wl_cfg80211_pause_sdo(struct net_device * dev,struct bcm_cfg80211 * cfg)17893 s32 wl_cfg80211_pause_sdo(struct net_device *dev, struct bcm_cfg80211 *cfg)
17894 {
17895
17896 int ret = 0;
17897 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
17898 int sdo_pause = 1;
17899
17900 WL_DBG(("Enter \n"));
17901
17902 if (!cfg->sdo) {
17903 WL_ERR(("SDO not initialized \n"));
17904 return -EINVAL;
17905 }
17906
17907 if (dev == NULL)
17908 dev = bcmcfg_to_prmry_ndev(cfg);
17909
17910 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop",
17911 (void*)&sdo_pause, sizeof(sdo_pause),
17912 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) {
17913 WL_ERR(("p2po_stop Failed :%d\n", ret));
17914 }
17915
17916 /* Enable back the ESCAN events for the SCAN */
17917 wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, true);
17918
17919 WL_SD(("SDO Paused \n"));
17920
17921 return ret;
17922 }
17923
17924 static s32
wl_svc_resp_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)17925 wl_svc_resp_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
17926 const wl_event_msg_t *e, void *data)
17927 {
17928 u32 event = ntoh32(e->event_type);
17929 struct net_device *ndev = NULL;
17930 const u8 *dst_mac = (const u8 *)e->addr.octet;
17931 int ret = 0;
17932 wl_event_sd_t *gas = NULL;
17933 int status = ntoh32(e->status);
17934 sdo_event_t sdo_hdr;
17935 u32 data_len = ntoh32(e->datalen);
17936 u8 *data_ptr = NULL;
17937 u32 tot_len = 0;
17938
17939 WL_SD(("Enter event_type:%d status:%d\n", event, status));
17940
17941 if (!cfg->sdo) {
17942 WL_ERR(("SDO Not initialized \n"));
17943 return -EINVAL;
17944 }
17945
17946 if (!(cfg->sdo->sd_state & WL_SD_SEARCH_SVC)) {
17947 /* We are not searching for any service. Drop
17948 * any bogus Event
17949 */
17950 WL_ERR(("Bogus SDO Event. Do nothing.. \n"));
17951 return -1;
17952 }
17953
17954 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17955
17956 mutex_lock(&cfg->usr_sync);
17957 if (event == WLC_E_SERVICE_FOUND) {
17958
17959 if ((status != WLC_E_STATUS_SUCCESS) && (status != WLC_E_STATUS_PARTIAL)) {
17960 WL_ERR(("WLC_E_SERVICE_FOUND: unknown status \n"));
17961 goto exit;
17962 }
17963
17964 gas = (wl_event_sd_t *)data;
17965 if (!gas) {
17966 ret = -EINVAL;
17967 goto exit;
17968 }
17969
17970 bzero(&sdo_hdr, sizeof(sdo_event_t));
17971 sdo_hdr.freq = wl_channel_to_frequency(gas->channel, WL_CHANSPEC_BAND_2G);
17972 sdo_hdr.count = gas->count;
17973 memcpy(sdo_hdr.addr, dst_mac, ETH_ALEN);
17974 data_ptr = (char *)gas->tlv;
17975 tot_len = data_len - (sizeof(wl_event_sd_t) - sizeof(wl_sd_tlv_t));
17976
17977 WL_SD(("WLC_E_SERVICE_FOUND "MACDBG" data_len:%d tlv_count:%d \n",
17978 MAC2STRDBG(dst_mac), data_len, sdo_hdr.count));
17979
17980 if (tot_len > NLMSG_DEFAULT_SIZE) {
17981 WL_ERR(("size(%u) > %lu not supported \n", tot_len, NLMSG_DEFAULT_SIZE));
17982 ret = -ENOMEM;
17983 goto exit;
17984 }
17985
17986 if (wl_genl_send_msg(ndev, event, data_ptr,
17987 tot_len, (u8 *)&sdo_hdr, sizeof(sdo_event_t)) < 0)
17988 WL_ERR(("Couldn't send up the NETLINK Event \n"));
17989 else
17990 WL_SD(("GAS event sent up \n"));
17991 } else {
17992 WL_ERR(("Unsupported Event: %d \n", event));
17993 }
17994
17995 exit:
17996 mutex_unlock(&cfg->usr_sync);
17997 return ret;
17998 }
17999
wl_cfg80211_DsdOffloadParseProto(char * proto_str,u8 * proto)18000 s32 wl_cfg80211_DsdOffloadParseProto(char* proto_str, u8* proto)
18001 {
18002 s32 len = -1;
18003 int i = 0;
18004
18005 for (i = 0; i < MAX_SDO_PROTO; i++) {
18006 if (strncmp(proto_str, wl_sdo_protos[i].str, strlen(wl_sdo_protos[i].str)) == 0) {
18007 WL_SD(("Matching proto (%d) found \n", wl_sdo_protos[i].val));
18008 *proto = wl_sdo_protos[i].val;
18009 len = strlen(wl_sdo_protos[i].str);
18010 break;
18011 }
18012 }
18013 return len;
18014 }
18015
18016 /*
18017 * register to search for a UPnP service
18018 * ./DRIVER P2P_SD_REQ upnp 0x10urn:schemas-upnporg:device:InternetGatewayDevice:1
18019 *
18020 * Enable discovery
18021 * ./cfg p2po_find
18022 */
18023 #define UPNP_QUERY_VER_OFFSET 3
wl_sd_handle_sd_req(struct net_device * dev,u8 * buf,int len)18024 s32 wl_sd_handle_sd_req(
18025 struct net_device *dev,
18026 u8 * buf,
18027 int len)
18028 {
18029 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18030 s32 bssidx = 0;
18031 wl_sd_qr_t *sdreq;
18032 u8 proto = 0;
18033 s32 ret = 0;
18034 u32 tot_len = len + sizeof(wl_sd_qr_t);
18035 u16 version = 0;
18036
18037 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
18038 WL_ERR(("find_idx failed\n"));
18039 return -EINVAL;
18040 }
18041 /* Check for the least arg length expected */
18042 if (!buf || (len < strlen("all"))) {
18043 WL_ERR(("Wrong Arg\n"));
18044 return -EINVAL;
18045 }
18046
18047 if (tot_len > WLC_IOCTL_MAXLEN) {
18048 WL_ERR(("Length > %lu not supported \n", MAX_QR_LEN));
18049 return -EINVAL;
18050 }
18051
18052 sdreq = (wl_sd_qr_t *)MALLOCZ(cfg->osh, tot_len);
18053 if (!sdreq) {
18054 WL_ERR(("MALLOCZ failed\n"));
18055 return -ENOMEM;
18056 }
18057
18058 WL_SD(("%s Len: %d\n", buf, len));
18059 if ((ret = wl_cfg80211_DsdOffloadParseProto(buf, &proto)) < 0) {
18060 WL_ERR(("Unknown proto \n"));
18061 goto exit;
18062 }
18063
18064 sdreq->protocol = proto;
18065 buf += ret;
18066 buf++; /* skip the space */
18067 sdreq->transaction_id = simple_strtoul(buf, NULL, 16);
18068 WL_SD(("transaction_id:%d\n", sdreq->transaction_id));
18069 buf += sizeof(sdreq->transaction_id);
18070
18071 if (*buf == '\0') {
18072 WL_SD(("No Query present. Proto:%d \n", proto));
18073 sdreq->query_len = 0;
18074 } else {
18075 buf++; /* skip the space */
18076 /* UPNP version needs to put as binary val */
18077 if (sdreq->protocol == SVC_RPOTYPE_UPNP) {
18078 /* Extract UPNP version */
18079 version = simple_strtoul(buf, NULL, 16);
18080 buf = buf + UPNP_QUERY_VER_OFFSET;
18081 buf[0] = version;
18082 WL_SD(("Upnp version: 0x%x \n", version));
18083 }
18084
18085 len = strlen(buf);
18086 WL_SD(("Len after stripping proto: %d Query: %s\n", len, buf));
18087 /* copy the query part */
18088 memcpy(sdreq->qrbuf, buf, len);
18089 sdreq->query_len = len;
18090 }
18091
18092 /* Enable discovery */
18093 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
18094 WL_ERR(("cfgp2p_enable discovery failed"));
18095 goto exit;
18096 }
18097
18098 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_sd_req_resp", (void*)sdreq,
18099 tot_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
18100 bssidx, &cfg->ioctl_buf_sync)) < 0) {
18101 WL_ERR(("Find SVC Failed \n"));
18102 goto exit;
18103 }
18104
18105 cfg->sdo->sd_state |= WL_SD_SEARCH_SVC;
18106
18107 exit:
18108 MFREE(cfg->osh, sdreq, tot_len);
18109 return ret;
18110 }
18111
wl_sd_handle_sd_cancel_req(struct net_device * dev,u8 * buf)18112 s32 wl_sd_handle_sd_cancel_req(
18113 struct net_device *dev,
18114 u8 *buf)
18115 {
18116 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18117 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18118
18119 if (wldev_iovar_setbuf_bsscfg(dev, "p2po_sd_cancel", NULL,
18120 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18121 bssidx, &cfg->ioctl_buf_sync) < 0) {
18122 WL_ERR(("Cancel SD Failed \n"));
18123 return -EINVAL;
18124 }
18125
18126 cfg->sdo->sd_state &= ~WL_SD_SEARCH_SVC;
18127
18128 return 0;
18129 }
18130
18131 /*
18132 * register a UPnP service to be discovered
18133 * ./cfg P2P_SD_SVC_ADD upnp 0x10urn:schemas-upnporg:device:InternetGatewayDevice:1 0x10uu
18134 * id:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnporg:device:InternetGate
18135 * wayDevice:1
18136 */
wl_sd_handle_sd_add_svc(struct net_device * dev,u8 * buf,int len)18137 s32 wl_sd_handle_sd_add_svc(
18138 struct net_device *dev,
18139 u8 * buf,
18140 int len)
18141 {
18142 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18143 s32 bssidx = 0;
18144 wl_sd_qr_t *sdreq;
18145 u8 proto = 0;
18146 u16 version = 0;
18147 s32 ret = 0;
18148 u8 *resp = NULL;
18149 u8 *query = NULL;
18150 u32 tot_len = len + sizeof(wl_sd_qr_t);
18151
18152 if (!buf || !len)
18153 return -EINVAL;
18154
18155 WL_SD(("%s Len: %d\n", buf, len));
18156 if (tot_len > WLC_IOCTL_MAXLEN) {
18157 WL_ERR(("Query-Resp length > %d not supported \n", WLC_IOCTL_MAXLEN));
18158 return -ENOMEM;
18159 }
18160
18161 sdreq = (wl_sd_qr_t *)MALLOCZ(cfg->osh, tot_len);
18162 if (!sdreq) {
18163 WL_ERR(("malloc failed\n"));
18164 return -ENOMEM;
18165 }
18166
18167 if ((ret = wl_cfg80211_DsdOffloadParseProto(buf, &proto)) < 0) {
18168 WL_ERR(("Unknown Proto \n"));
18169 goto exit;
18170 }
18171
18172 sdreq->protocol = proto;
18173 buf += ret;
18174
18175 if (*buf == '\0') {
18176 WL_ERR(("No Query Resp pair present \n"));
18177 ret = -EINVAL;
18178 goto exit;
18179 }
18180
18181 buf++; /* Skip the space */
18182 len = strlen(buf);
18183 query = strsep((char **)&buf, " ");
18184 if (!query || !buf) {
18185 WL_ERR(("No Query RESP Present\n"));
18186 ret = -EINVAL;
18187 goto exit;
18188 }
18189 resp = buf;
18190
18191 if (sdreq->protocol == SVC_RPOTYPE_UPNP) {
18192 /* Extract UPNP version */
18193 version = simple_strtoul(query, NULL, 16);
18194 query = query + UPNP_QUERY_VER_OFFSET;
18195 resp = resp + UPNP_QUERY_VER_OFFSET;
18196 query[0] = version;
18197 resp[0] = version;
18198 WL_SD(("Upnp version: 0x%x \n", version));
18199 }
18200
18201 sdreq->query_len = strlen(query);
18202 sdreq->response_len = strlen(buf);
18203 WL_SD(("query:%s len:%u \n", query, sdreq->query_len));
18204 WL_SD(("resp:%s len:%u \n", buf, sdreq->response_len));
18205
18206 memcpy(sdreq->qrbuf, query, sdreq->query_len);
18207 memcpy((sdreq->qrbuf + sdreq->query_len), resp, sdreq->response_len);
18208
18209 /* Enable discovery */
18210 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
18211 WL_ERR(("cfgp2p_enable discovery failed"));
18212 goto exit;
18213 }
18214
18215 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_addsvc", (void*)sdreq,
18216 tot_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
18217 bssidx, &cfg->ioctl_buf_sync)) < 0) {
18218 WL_ERR(("FW Failed in doing p2po_addsvc. RET:%d \n", ret));
18219 goto exit;
18220 }
18221
18222 cfg->sdo->sd_state |= WL_SD_ADV_SVC;
18223
18224 exit:
18225 MFREE(cfg->osh, sdreq, tot_len);
18226 return ret;
18227 }
18228
wl_sd_handle_sd_del_svc(struct net_device * dev,u8 * buf,int len)18229 s32 wl_sd_handle_sd_del_svc(
18230 struct net_device *dev,
18231 u8 * buf,
18232 int len)
18233 {
18234 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18235 s32 bssidx = 0;
18236 wl_sd_qr_t *sdreq;
18237 u8 proto = 0;
18238 s32 ret = 0;
18239 u32 tot_len = len + sizeof(wl_sd_qr_t);
18240 u16 version = 0;
18241
18242 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
18243 WL_ERR(("find_idx failed\n"));
18244 return -EINVAL;
18245 }
18246
18247 sdreq = (wl_sd_qr_t *)MALLOCZ(cfg->osh, tot_len);
18248 if (!sdreq) {
18249 WL_ERR(("malloc failed\n"));
18250 ret = -ENOMEM;
18251 goto exit;
18252 }
18253
18254 /* Check for the least arg length expected */
18255 if (buf && len >= strlen("all")) {
18256 WL_DBG(("%s Len: %d\n", buf, len));
18257 if ((ret = wl_cfg80211_DsdOffloadParseProto(buf, &proto)) < 0) {
18258 WL_ERR(("Unknown Proto \n"));
18259 goto exit;
18260 }
18261 sdreq->protocol = proto;
18262 buf += ret;
18263
18264 if (*buf == ' ') {
18265 /* Query present */
18266 buf++; /* Skip the space */
18267 /* UPNP version needs to put as binary val */
18268 if (sdreq->protocol == SVC_RPOTYPE_UPNP) {
18269 /* Extract UPNP version */
18270 version = simple_strtoul(buf, NULL, 16);
18271 buf = buf + UPNP_QUERY_VER_OFFSET;
18272 buf[0] = version;
18273 WL_SD(("Upnp version: 0x%x \n", version));
18274 }
18275 memcpy(sdreq->qrbuf, buf, strlen(buf));
18276 sdreq->query_len = strlen(buf);
18277 WL_SD(("Query to be deleted:%s len:%d\n", buf, sdreq->query_len));
18278 }
18279 } else {
18280 /* ALL */
18281 proto = 0;
18282 }
18283
18284 sdreq->protocol = proto;
18285 WL_SD(("Proto: %d \n", proto));
18286
18287 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_delsvc", (void*)sdreq,
18288 tot_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
18289 bssidx, &cfg->ioctl_buf_sync)) < 0) {
18290 WL_ERR(("FW Failed in doing sd_delsvc. ret=%d \n", ret));
18291 goto exit;
18292 }
18293
18294 cfg->sdo->sd_state &= ~WL_SD_ADV_SVC;
18295
18296 exit:
18297 if (sdreq) {
18298 MFREE(cfg->osh, sdreq, tot_len);
18299 }
18300
18301 return ret;
18302 }
18303
wl_sd_handle_sd_stop_discovery(struct net_device * dev,u8 * buf,int len)18304 s32 wl_sd_handle_sd_stop_discovery(
18305 struct net_device *dev,
18306 u8 * buf,
18307 int len)
18308 {
18309 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18310 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18311 int ret = 0;
18312 int sdo_pause = 0;
18313
18314 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", (void*)&sdo_pause,
18315 sizeof(sdo_pause), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18316 bssidx, &cfg->ioctl_buf_sync)) < 0) {
18317 WL_ERR(("p2po_stop Failed :%d\n", ret));
18318 return -1;
18319 }
18320
18321 /* clear the states */
18322 cfg->sdo->dd_state = WL_DD_STATE_IDLE;
18323 wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
18324
18325 bzero(&cfg->sdo->sd_listen, sizeof(wl_sd_listen_t));
18326
18327 /* Remove ESCAN from waking up the host if ofind/olisten is enabled */
18328 wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, true);
18329
18330 return ret;
18331 }
18332
wl_sd_handle_sd_find(struct net_device * dev,u8 * buf,int len)18333 s32 wl_sd_handle_sd_find(
18334 struct net_device *dev,
18335 u8 * buf,
18336 int len)
18337 {
18338 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18339 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18340 int ret = 0;
18341 s32 disc_bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18342 vndr_ie_setbuf_t *ie_setbuf;
18343 vndr_ie_t *vndrie;
18344 vndr_ie_buf_t *vndriebuf;
18345 int tot_len = 0;
18346 uint channel = 0;
18347
18348 u8 p2pie_buf[] = {
18349 0x09, 0x02, 0x02, 0x00, 0x27, 0x0c, 0x06, 0x05, 0x00,
18350 0x55, 0x53, 0x04, 0x51, 0x0b, 0x11, 0x05, 0x00, 0x55,
18351 0x53, 0x04, 0x51, 0x0b
18352 };
18353
18354 /* Enable discovery */
18355 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
18356 WL_ERR(("cfgp2p_enable discovery failed"));
18357 return -1;
18358 }
18359
18360 if (buf && strncmp(buf, "chan=", strlen("chan=")) == 0) {
18361 buf += strlen("chan=");
18362 channel = simple_strtol(buf, NULL, 10);
18363 WL_SD(("listen_chan to be set:%d\n", channel));
18364 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
18365 sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18366 bssidx, &cfg->ioctl_buf_sync)) < 0) {
18367 WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
18368 return -1;
18369 }
18370 }
18371
18372 tot_len = sizeof(vndr_ie_setbuf_t) + sizeof(p2pie_buf);
18373 ie_setbuf = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
18374 if (!ie_setbuf) {
18375 WL_ERR(("IE memory alloc failed\n"));
18376 return -ENOMEM;
18377 }
18378
18379 /* Apply the p2p_ie for p2po_find */
18380 strlcpy(ie_setbuf->cmd, "add", sizeof(ie_setbuf->cmd));
18381
18382 vndriebuf = &ie_setbuf->vndr_ie_buffer;
18383 vndriebuf->iecount = htod32(1);
18384 vndriebuf->vndr_ie_list[0].pktflag = htod32(16);
18385
18386 vndrie = &vndriebuf->vndr_ie_list[0].vndr_ie_data;
18387
18388 vndrie->id = (uchar) DOT11_MNG_PROPR_ID;
18389 vndrie->len = sizeof(p2pie_buf);
18390 memcpy(vndrie->oui, WFA_OUI, WFA_OUI_LEN);
18391 memcpy(vndrie->data, p2pie_buf, sizeof(p2pie_buf));
18392
18393 /* Remove ESCAN from waking up the host if SDO is enabled */
18394 wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, false);
18395
18396 if (wldev_iovar_setbuf_bsscfg(dev, "ie", (void*)ie_setbuf,
18397 tot_len, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18398 disc_bssidx, &cfg->ioctl_buf_sync) < 0) {
18399 WL_ERR(("p2p add_ie failed \n"));
18400 ret = -EINVAL;
18401 goto exit;
18402 } else
18403 WL_SD(("p2p add_ie applied successfully len:%d \n", tot_len));
18404
18405 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_find", NULL, 0,
18406 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync)) < 0) {
18407 WL_ERR(("p2po_find Failed :%d\n", ret));
18408 ret = -1;
18409 goto exit;
18410 }
18411
18412 /* set the states */
18413 cfg->sdo->dd_state = WL_DD_STATE_SEARCH;
18414 wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
18415
18416 exit:
18417 if (ie_setbuf) {
18418 MFREE(cfg->osh, ie_setbuf, tot_len);
18419 }
18420
18421 /* Incase of failure enable back the ESCAN event */
18422 if (ret)
18423 wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, true);
18424
18425 return ret;
18426 }
18427
wl_sd_handle_sd_listen(struct net_device * dev,u8 * buf,int len)18428 s32 wl_sd_handle_sd_listen(
18429 struct net_device *dev,
18430 u8 *buf,
18431 int len)
18432 {
18433 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18434 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18435 wl_sd_listen_t sd_listen;
18436 int ret = 0;
18437 u8 * ptr = NULL;
18438 uint channel = 0;
18439
18440 /* Just in case if it is not enabled */
18441 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
18442 WL_ERR(("cfgp2p_enable discovery failed"));
18443 return -1;
18444 }
18445 bzero(&sd_listen, sizeof(wl_sd_listen_t));
18446 if (len) {
18447 ptr = strsep((char **)&buf, " ");
18448 if (ptr == NULL) {
18449 /* period and duration given wrongly */
18450 WL_ERR(("Arguments in wrong format \n"));
18451 return -EINVAL;
18452 }
18453 else if (strncmp(ptr, "chan=", strlen("chan=")) == 0) {
18454 sd_listen.interval = 65535;
18455 sd_listen.period = 65535;
18456 ptr += strlen("chan=");
18457 channel = simple_strtol(ptr, NULL, 10);
18458 }
18459 else {
18460 sd_listen.period = simple_strtol(ptr, NULL, 10);
18461 ptr = strsep((char **)&buf, " ");
18462 if (ptr == NULL) {
18463 WL_ERR(("Arguments in wrong format \n"));
18464 return -EINVAL;
18465 }
18466 sd_listen.interval = simple_strtol(ptr, NULL, 10);
18467 if (buf && strncmp(buf, "chan=", strlen("chan=")) == 0) {
18468 buf += strlen("chan=");
18469 channel = simple_strtol(buf, NULL, 10);
18470 }
18471 }
18472 WL_SD(("listen_period:%d, listen_interval:%d and listen_channel:%d\n",
18473 sd_listen.period, sd_listen.interval, channel));
18474 }
18475 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
18476 sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18477 bssidx, &cfg->ioctl_buf_sync)) < 0) {
18478 WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
18479 return -1;
18480 }
18481
18482 WL_SD(("p2po_listen period:%d interval:%d \n",
18483 sd_listen.period, sd_listen.interval));
18484 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&sd_listen,
18485 sizeof(wl_sd_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
18486 bssidx, &cfg->ioctl_buf_sync)) < 0) {
18487 WL_ERR(("p2po_listen Failed :%d\n", ret));
18488 return -1;
18489 }
18490
18491 /* Remove ESCAN from waking up the host if ofind/olisten is enabled */
18492 wl_add_remove_eventmsg(dev, WLC_E_ESCAN_RESULT, false);
18493
18494 /* Store the extended listen values for use in sdo_resume */
18495 cfg->sdo->sd_listen.interval = sd_listen.interval;
18496 cfg->sdo->sd_listen.period = sd_listen.period;
18497
18498 /* set the states */
18499 cfg->sdo->dd_state = WL_DD_STATE_LISTEN;
18500 wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
18501
18502 return 0;
18503 }
18504
wl_cfg80211_sd_offload(struct net_device * dev,char * cmd,char * buf,int len)18505 s32 wl_cfg80211_sd_offload(struct net_device *dev, char *cmd, char* buf, int len)
18506 {
18507 int ret = 0;
18508 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18509
18510 WL_SD(("Entry cmd:%s arg_len:%d \n", cmd, len));
18511
18512 if (!cfg->sdo) {
18513 WL_SD(("Initializing SDO \n"));
18514 if ((ret = wl_cfg80211_sdo_init(cfg)) < 0)
18515 goto exit;
18516 }
18517
18518 if (strncmp(cmd, "P2P_SD_REQ", strlen("P2P_SD_REQ")) == 0) {
18519 ret = wl_sd_handle_sd_req(dev, buf, len);
18520 } else if (strncmp(cmd, "P2P_SD_CANCEL_REQ", strlen("P2P_SD_CANCEL_REQ")) == 0) {
18521 ret = wl_sd_handle_sd_cancel_req(dev, buf);
18522 } else if (strncmp(cmd, "P2P_SD_SVC_ADD", strlen("P2P_SD_SVC_ADD")) == 0) {
18523 ret = wl_sd_handle_sd_add_svc(dev, buf, len);
18524 } else if (strncmp(cmd, "P2P_SD_SVC_DEL", strlen("P2P_SD_SVC_DEL")) == 0) {
18525 ret = wl_sd_handle_sd_del_svc(dev, buf, len);
18526 } else if (strncmp(cmd, "P2P_SD_FIND", strlen("P2P_SD_FIND")) == 0) {
18527 ret = wl_sd_handle_sd_find(dev, buf, len);
18528 } else if (strncmp(cmd, "P2P_SD_LISTEN", strlen("P2P_SD_LISTEN")) == 0) {
18529 ret = wl_sd_handle_sd_listen(dev, buf, len);
18530 } else if (strncmp(cmd, "P2P_SD_STOP", strlen("P2P_STOP")) == 0) {
18531 ret = wl_sd_handle_sd_stop_discovery(dev, buf, len);
18532 } else {
18533 WL_ERR(("Request for Unsupported CMD:%s \n", buf));
18534 ret = -EINVAL;
18535 }
18536
18537 exit:
18538 return ret;
18539 }
18540 #endif /* WL_SDO */
18541
wl_cfg80211_set_wps_p2p_ie(struct net_device * ndev,char * buf,int len,enum wl_management_type type)18542 s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
18543 enum wl_management_type type)
18544 {
18545 struct bcm_cfg80211 *cfg;
18546 s32 ret = 0;
18547 s32 bssidx = 0;
18548 s32 pktflag = 0;
18549 struct wireless_dev *wdev = ndev->ieee80211_ptr;
18550
18551 cfg = wl_get_cfg(ndev);
18552 if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
18553 /* Vendor IEs should be set to FW
18554 * after SoftAP interface is brought up
18555 */
18556 WL_DBG(("Skipping set IE since AP is not up \n"));
18557 goto exit;
18558 } else if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
18559 /* Either stand alone AP case or P2P discovery */
18560 if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
18561 /* Stand alone AP case on primary interface */
18562 WL_DBG(("Apply IEs for Primary AP Interface \n"));
18563 bssidx = 0;
18564 } else {
18565 if (!cfg->p2p) {
18566 /* If p2p not initialized, return failure */
18567 WL_ERR(("P2P not initialized \n"));
18568 goto exit;
18569 }
18570 /* P2P Discovery case (p2p listen) */
18571 if (!cfg->p2p->on) {
18572 /* Turn on Discovery interface */
18573 p2p_on(cfg) = true;
18574 ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
18575 if (unlikely(ret)) {
18576 WL_ERR(("Enable discovery failed \n"));
18577 goto exit;
18578 }
18579 }
18580 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
18581 if (!cfg->p2p_wdev) {
18582 WL_ERR(("p2p_wdev not present\n"));
18583 goto exit;
18584 }
18585 wdev = cfg->p2p_wdev;
18586 WL_DBG(("Apply IEs for P2P Discovery Iface wdev:%p\n", wdev));
18587 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
18588 }
18589 } else {
18590 /* Virtual AP/ P2P Group Interface */
18591 WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
18592 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
18593 }
18594
18595 if (wdev != NULL) {
18596 switch (type) {
18597 case WL_BEACON:
18598 pktflag = VNDR_IE_BEACON_FLAG;
18599 break;
18600 case WL_PROBE_RESP:
18601 pktflag = VNDR_IE_PRBRSP_FLAG;
18602 break;
18603 case WL_ASSOC_RESP:
18604 pktflag = VNDR_IE_ASSOCRSP_FLAG;
18605 break;
18606 }
18607 if (pktflag) {
18608 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
18609 wdev_to_cfgdev(wdev), bssidx, pktflag, buf, len);
18610 }
18611 }
18612 exit:
18613 return ret;
18614 }
18615
18616 static const struct rfkill_ops wl_rfkill_ops = {
18617 .set_block = wl_rfkill_set
18618 };
18619
wl_rfkill_set(void * data,bool blocked)18620 static int wl_rfkill_set(void *data, bool blocked)
18621 {
18622 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
18623
18624 WL_DBG(("Enter \n"));
18625 WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
18626
18627 if (!cfg)
18628 return -EINVAL;
18629
18630 cfg->rf_blocked = blocked;
18631
18632 return 0;
18633 }
18634
wl_setup_rfkill(struct bcm_cfg80211 * cfg,bool setup)18635 static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
18636 {
18637 s32 err = 0;
18638
18639 WL_DBG(("Enter \n"));
18640 if (!cfg)
18641 return -EINVAL;
18642 if (setup) {
18643 cfg->rfkill = rfkill_alloc("brcmfmac-wifi",
18644 wl_cfg80211_get_parent_dev(),
18645 RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
18646
18647 if (!cfg->rfkill) {
18648 err = -ENOMEM;
18649 goto err_out;
18650 }
18651
18652 err = rfkill_register(cfg->rfkill);
18653
18654 if (err)
18655 rfkill_destroy(cfg->rfkill);
18656 } else {
18657 if (!cfg->rfkill) {
18658 err = -ENOMEM;
18659 goto err_out;
18660 }
18661
18662 rfkill_unregister(cfg->rfkill);
18663 rfkill_destroy(cfg->rfkill);
18664 }
18665
18666 err_out:
18667 return err;
18668 }
18669
wl_cfg80211_get_bcmcfg(void)18670 struct bcm_cfg80211 *wl_cfg80211_get_bcmcfg(void)
18671 {
18672 return g_bcmcfg;
18673 }
18674
wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 * cfg)18675 void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 *cfg)
18676 {
18677 g_bcmcfg = cfg;
18678 }
18679
wl_cfg80211_get_parent_dev(void)18680 struct device *wl_cfg80211_get_parent_dev(void)
18681 {
18682 return cfg80211_parent_dev;
18683 }
18684
wl_cfg80211_set_parent_dev(void * dev)18685 void wl_cfg80211_set_parent_dev(void *dev)
18686 {
18687 cfg80211_parent_dev = dev;
18688 }
18689
wl_cfg80211_clear_parent_dev(void)18690 static void wl_cfg80211_clear_parent_dev(void)
18691 {
18692 cfg80211_parent_dev = NULL;
18693 }
18694
get_primary_mac(struct bcm_cfg80211 * cfg,struct ether_addr * mac)18695 void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
18696 {
18697 u8 ioctl_buf[WLC_IOCTL_SMLEN];
18698
18699 if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
18700 "cur_etheraddr", NULL, 0, ioctl_buf, sizeof(ioctl_buf),
18701 0, NULL) == BCME_OK) {
18702 memcpy(mac->octet, ioctl_buf, ETHER_ADDR_LEN);
18703 } else {
18704 bzero(mac->octet, ETHER_ADDR_LEN);
18705 }
18706 }
18707
wl_cfg80211_do_driver_init(struct net_device * net)18708 int wl_cfg80211_do_driver_init(struct net_device *net)
18709 {
18710 struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
18711
18712 if (!cfg || !cfg->wdev)
18713 return -EINVAL;
18714
18715 #if defined(BCMDONGLEHOST)
18716 if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
18717 return -1;
18718 #endif /* BCMDONGLEHOST */
18719
18720 return 0;
18721 }
18722
wl_cfg80211_enable_trace(u32 level)18723 void wl_cfg80211_enable_trace(u32 level)
18724 {
18725 wl_dbg_level = level;
18726 WL_MSG("wlan", "wl_dbg_level = 0x%x\n", wl_dbg_level);
18727 }
18728
18729 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
18730 static s32
wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy * wiphy,bcm_struct_cfgdev * cfgdev,u64 cookie)18731 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
18732 bcm_struct_cfgdev *cfgdev, u64 cookie)
18733 {
18734 /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
18735 * is passed with CMD_FRAME. This callback is supposed to cancel
18736 * the OFFCHANNEL Wait. Since we are already taking care of that
18737 * with the tx_mgmt logic, do nothing here.
18738 */
18739
18740 return 0;
18741 }
18742 #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
18743
18744 #ifdef WL_HOST_BAND_MGMT
18745 s32
wl_cfg80211_set_band(struct net_device * ndev,int band)18746 wl_cfg80211_set_band(struct net_device *ndev, int band)
18747 {
18748 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18749 int ret = 0;
18750 char ioctl_buf[50];
18751
18752 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
18753 WL_ERR(("Invalid band\n"));
18754 return -EINVAL;
18755 }
18756
18757 if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band,
18758 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
18759 WL_ERR(("seting roam_band failed code=%d\n", ret));
18760 return ret;
18761 }
18762
18763 WL_DBG(("Setting band to %d\n", band));
18764 cfg->curr_band = band;
18765
18766 return 0;
18767 }
18768 #endif /* WL_HOST_BAND_MGMT */
18769
18770 s32
wl_cfg80211_set_if_band(struct net_device * ndev,int band)18771 wl_cfg80211_set_if_band(struct net_device *ndev, int band)
18772 {
18773 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
18774 int ret = BCME_OK, wait_cnt;
18775 char ioctl_buf[32];
18776
18777 if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
18778 WL_ERR(("Invalid band\n"));
18779 return -EINVAL;
18780 }
18781
18782 if (cfg->ncho_band == band) {
18783 WL_ERR(("Same to Current band %d\n", cfg->ncho_band));
18784 return ret;
18785 }
18786
18787 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
18788 #ifdef BCMDONGLEHOST
18789 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
18790 BCM_REFERENCE(dhdp);
18791 DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
18792 dhd_net2idx(dhdp->info, ndev), 0);
18793 #endif /* BCMDONGLEHOST */
18794 ret = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
18795 if (ret < 0) {
18796 WL_ERR(("WLC_DISASSOC error %d\n", ret));
18797 /* continue to set 'if_band' */
18798 }
18799 else {
18800 /* This is to ensure that 'if_band' iovar is issued only after
18801 * disconnection is completed
18802 */
18803 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
18804 while (wl_get_drv_status(cfg, CONNECTED, ndev) && wait_cnt) {
18805 WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt));
18806 wait_cnt--;
18807 OSL_SLEEP(50);
18808 }
18809 }
18810 }
18811 if ((ret = wldev_iovar_setbuf(ndev, "if_band", &band,
18812 sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
18813 WL_ERR(("seting if_band failed ret=%d\n", ret));
18814 /* issue 'WLC_SET_BAND' if if_band is not supported */
18815 if (ret == BCME_UNSUPPORTED) {
18816 ret = wldev_set_band(ndev, band);
18817 if (ret < 0) {
18818 WL_ERR(("seting band failed ret=%d\n", ret));
18819 }
18820 }
18821 }
18822
18823 if (ret == BCME_OK) {
18824 cfg->ncho_band = band;
18825 }
18826 return ret;
18827 }
18828
wl_cfg80211_is_concurrent_mode(struct net_device * dev)18829 bool wl_cfg80211_is_concurrent_mode(struct net_device *dev)
18830 {
18831 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18832 if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
18833 return true;
18834 } else {
18835 return false;
18836 }
18837 }
18838
18839 /*
18840 * This is to support existing btcoex implementation
18841 * btcoex clean up may help removing this function
18842 */
wl_cfg80211_get_dhdp(struct net_device * dev)18843 void* wl_cfg80211_get_dhdp(struct net_device *dev)
18844 {
18845 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18846
18847 return cfg->pub;
18848 }
18849
wl_cfg80211_is_p2p_active(struct net_device * dev)18850 bool wl_cfg80211_is_p2p_active(struct net_device *dev)
18851 {
18852 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18853 return (cfg && cfg->p2p);
18854 }
18855
wl_cfg80211_is_roam_offload(struct net_device * dev)18856 bool wl_cfg80211_is_roam_offload(struct net_device * dev)
18857 {
18858 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18859 return (cfg && cfg->roam_offload);
18860 }
18861
wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev,const wl_event_msg_t * e,int ifidx)18862 bool wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev, const wl_event_msg_t *e,
18863 int ifidx)
18864 {
18865 #ifdef BCMDONGLEHOST
18866 u8 *curbssid = NULL;
18867 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
18868
18869 if (!cfg) {
18870 /* When interface is created using wl
18871 * ndev->ieee80211_ptr will be NULL.
18872 */
18873 return NULL;
18874 }
18875 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
18876
18877 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
18878 return true;
18879 }
18880 #endif /* BCMDONGLEHOST */
18881 return false;
18882 }
18883
wl_cfg80211_work_handler(struct work_struct * work)18884 static void wl_cfg80211_work_handler(struct work_struct * work)
18885 {
18886 struct bcm_cfg80211 *cfg = NULL;
18887 struct net_info *iter, *next;
18888 s32 err = BCME_OK;
18889 s32 pm = PM_FAST;
18890 dhd_pub_t *dhd;
18891 BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
18892 WL_DBG(("Enter \n"));
18893 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18894 for_each_ndev(cfg, iter, next) {
18895 GCC_DIAGNOSTIC_POP();
18896 /* p2p discovery iface ndev could be null */
18897 if (iter->ndev) {
18898 if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
18899 (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
18900 wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
18901 continue;
18902 if (iter->ndev) {
18903 dhd = (dhd_pub_t *)(cfg->pub);
18904 if (dhd_conf_get_pm(dhd) >= 0)
18905 pm = dhd_conf_get_pm(dhd);
18906 if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM,
18907 &pm, sizeof(pm))) != 0) {
18908 if (err == -ENODEV)
18909 WL_DBG(("%s:netdev not ready\n",
18910 iter->ndev->name));
18911 else
18912 WL_ERR(("%s:error (%d)\n",
18913 iter->ndev->name, err));
18914 } else
18915 wl_cfg80211_update_power_mode(iter->ndev);
18916 }
18917 }
18918 }
18919
18920 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
18921 DHD_PM_WAKE_UNLOCK(cfg->pub);
18922 #endif /* BCMDONGLEHOST && OEM_ANDROID */
18923
18924 #if defined(OEM_ANDROID) && defined(DHCP_SCAN_SUPPRESS)
18925 if (cfg->scan_suppressed) {
18926 /* There is pending scan_suppress. Clean it */
18927 WL_ERR(("Clean up from timer after %d msec\n", WL_SCAN_SUPPRESS_TIMEOUT));
18928 wl_cfg80211_scan_suppress(bcmcfg_to_prmry_ndev(cfg), 0);
18929 }
18930 #endif /* DHCP_SCAN_SUPPRESS */
18931
18932 }
18933
18934 u8
wl_get_action_category(void * frame,u32 frame_len)18935 wl_get_action_category(void *frame, u32 frame_len)
18936 {
18937 u8 category;
18938 u8 *ptr = (u8 *)frame;
18939 if (frame == NULL)
18940 return DOT11_ACTION_CAT_ERR_MASK;
18941 if (frame_len < DOT11_ACTION_HDR_LEN)
18942 return DOT11_ACTION_CAT_ERR_MASK;
18943 category = ptr[DOT11_ACTION_CAT_OFF];
18944 WL_DBG(("Action Category: %d\n", category));
18945 return category;
18946 }
18947
18948 int
wl_get_public_action(void * frame,u32 frame_len,u8 * ret_action)18949 wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
18950 {
18951 u8 *ptr = (u8 *)frame;
18952 if (frame == NULL || ret_action == NULL)
18953 return BCME_ERROR;
18954 if (frame_len < DOT11_ACTION_HDR_LEN)
18955 return BCME_ERROR;
18956 if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
18957 return BCME_ERROR;
18958 *ret_action = ptr[DOT11_ACTION_ACT_OFF];
18959 WL_DBG(("Public Action : %d\n", *ret_action));
18960 return BCME_OK;
18961 }
18962
18963 #ifdef WLFBT
18964 int
wl_cfg80211_get_fbt_key(struct net_device * dev,uint8 * key,int total_len)18965 wl_cfg80211_get_fbt_key(struct net_device *dev, uint8 *key, int total_len)
18966 {
18967 struct bcm_cfg80211 * cfg = wl_get_cfg(dev);
18968 int bytes_written = -1;
18969
18970 if (total_len < FBT_KEYLEN) {
18971 WL_ERR(("wl_cfg80211_get_fbt_key: Insufficient buffer \n"));
18972 goto end;
18973 }
18974 if (cfg) {
18975 memcpy(key, cfg->fbt_key, FBT_KEYLEN);
18976 bytes_written = FBT_KEYLEN;
18977 } else {
18978 bzero(key, FBT_KEYLEN);
18979 WL_ERR(("wl_cfg80211_get_fbt_key: Failed to copy KCK and KEK \n"));
18980 }
18981 prhex("KCK, KEK", (uchar *)key, FBT_KEYLEN);
18982 end:
18983 return bytes_written;
18984 }
18985 #endif /* WLFBT */
18986
18987 static int
wl_cfg80211_delayed_roam(struct bcm_cfg80211 * cfg,struct net_device * ndev,const struct ether_addr * bssid)18988 wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
18989 const struct ether_addr *bssid)
18990 {
18991 s32 err;
18992 wl_event_msg_t e;
18993
18994 bzero(&e, sizeof(e));
18995 e.event_type = cpu_to_be32(WLC_E_ROAM);
18996 memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
18997 /* trigger the roam event handler */
18998 err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
18999
19000 return err;
19001 }
19002
19003 static bool
wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t * vndrie)19004 wl_cfg80211_filter_vndr_ext_id(const vndr_ie_t *vndrie)
19005 {
19006 if (vndrie->oui[0] == FILS_EXTID_MNG_HLP_CONTAINER_ID) {
19007 /* Skip adding fils HLP IE, its already done using
19008 * "WL_FILS_CMD_ADD_HLP_IE" subcmd.
19009 */
19010 WL_DBG(("%s:SKIP ADDING FILS HLP EXTN ID\n", __func__));
19011 return true;
19012 }
19013 return false;
19014 }
19015
19016 static s32
wl_cfg80211_parse_vndr_ies(const u8 * parse,u32 len,struct parsed_vndr_ies * vndr_ies)19017 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
19018 struct parsed_vndr_ies *vndr_ies)
19019 {
19020 s32 err = BCME_OK;
19021 const vndr_ie_t *vndrie;
19022 const bcm_tlv_t *ie;
19023 struct parsed_vndr_ie_info *parsed_info;
19024 u32 count = 0;
19025 u32 remained_len;
19026
19027 remained_len = len;
19028 bzero(vndr_ies, sizeof(*vndr_ies));
19029
19030 ie = (const bcm_tlv_t *) parse;
19031 if (!bcm_valid_tlv(ie, remained_len))
19032 ie = NULL;
19033 while (ie) {
19034 if (count >= MAX_VNDR_IE_NUMBER)
19035 break;
19036 if (ie->id == DOT11_MNG_VS_ID || (ie->id == DOT11_MNG_ID_EXT_ID)) {
19037 vndrie = (const vndr_ie_t *) ie;
19038 if (ie->id == DOT11_MNG_ID_EXT_ID) {
19039 /* len should be bigger than sizeof ID extn field at least */
19040 if (vndrie->len < MIN_VENDOR_EXTN_IE_LEN) {
19041 WL_ERR(("%s: invalid vndr extn ie."
19042 " length %d\n",
19043 __FUNCTION__, vndrie->len));
19044 goto end;
19045 }
19046 if (wl_cfg80211_filter_vndr_ext_id(vndrie)) {
19047 goto end;
19048 }
19049 } else {
19050 /* len should be bigger than OUI length +
19051 * one data length at least
19052 */
19053 if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
19054 WL_ERR(("wl_cfg80211_parse_vndr_ies:"
19055 " invalid vndr ie. length is too small %d\n",
19056 vndrie->len));
19057 goto end;
19058 }
19059
19060 /* if wpa or wme ie, do not add ie */
19061 if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
19062 ((vndrie->data[0] == WPA_OUI_TYPE) ||
19063 (vndrie->data[0] == WME_OUI_TYPE))) {
19064 CFGP2P_DBG(("SKIP WPA/WME oui \n"));
19065 goto end;
19066 }
19067 #if defined(WL_MBO) || defined(WL_OCE)
19068 if ((!memcmp(vndrie->oui, (u8 *)WFA_OUI, WFA_OUI_LEN)) &&
19069 (vndrie->data[0] == WFA_OUI_TYPE_MBO_OCE)) {
19070 WL_DBG(("SKIP ID : %d Len: %d OUI:"MACOUIDBG
19071 " TYPE:%0x\n", vndrie->id, vndrie->len,
19072 MACOUI2STRDBG(vndrie->oui), vndrie->data[0]));
19073 goto end;
19074 }
19075 #endif /* WL_MBO || WL_OCE */
19076 }
19077
19078 parsed_info = &vndr_ies->ie_info[count++];
19079
19080 /* save vndr ie information */
19081 parsed_info->ie_ptr = (const char *)vndrie;
19082 parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
19083 memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
19084 vndr_ies->count = count;
19085 if (ie->id == DOT11_MNG_ID_EXT_ID) {
19086 WL_DBG(("** Vendor Extension ie id: 0x%02x, len:%d\n",
19087 ie->id, vndrie->len));
19088 } else {
19089 WL_DBG(("** OUI "MACOUIDBG", type 0x%02x len:%d\n",
19090 MACOUI2STRDBG(parsed_info->vndrie.oui),
19091 parsed_info->vndrie.data[0], vndrie->len));
19092 }
19093 }
19094 end:
19095 ie = bcm_next_tlv(ie, &remained_len);
19096 }
19097 return err;
19098 }
19099
19100 static bool
wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info * vndr_info)19101 wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info *vndr_info)
19102 {
19103 int i = 0;
19104
19105 while (exclude_vndr_oui_list[i]) {
19106 if (!memcmp(vndr_info->vndrie.oui,
19107 exclude_vndr_oui_list[i],
19108 DOT11_OUI_LEN)) {
19109 return TRUE;
19110 }
19111 i++;
19112 }
19113
19114 return FALSE;
19115 }
19116
19117 static bool
wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)19118 wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 *cfg,
19119 struct parsed_vndr_ie_info *vndr_info)
19120 {
19121 wl_vndr_oui_entry_t *oui_entry = NULL;
19122 unsigned long flags;
19123
19124 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19125 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19126 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
19127 GCC_DIAGNOSTIC_POP();
19128 if (!memcmp(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN)) {
19129 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19130 return TRUE;
19131 }
19132 }
19133 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19134 return FALSE;
19135 }
19136
19137 static bool
wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 * cfg,struct parsed_vndr_ie_info * vndr_info)19138 wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 *cfg,
19139 struct parsed_vndr_ie_info *vndr_info)
19140 {
19141 wl_vndr_oui_entry_t *oui_entry = NULL;
19142 unsigned long flags;
19143
19144 oui_entry = kmalloc(sizeof(*oui_entry), GFP_KERNEL);
19145 if (oui_entry == NULL) {
19146 WL_ERR(("alloc failed\n"));
19147 return FALSE;
19148 }
19149
19150 memcpy(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN);
19151
19152 INIT_LIST_HEAD(&oui_entry->list);
19153 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19154 list_add_tail(&oui_entry->list, &cfg->vndr_oui_list);
19155 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19156
19157 return TRUE;
19158 }
19159
19160 static void
wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 * cfg)19161 wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg)
19162 {
19163 wl_vndr_oui_entry_t *oui_entry = NULL;
19164 unsigned long flags;
19165
19166 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19167 while (!list_empty(&cfg->vndr_oui_list)) {
19168 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19169 oui_entry = list_entry(cfg->vndr_oui_list.next, wl_vndr_oui_entry_t, list);
19170 GCC_DIAGNOSTIC_POP();
19171 if (oui_entry) {
19172 list_del(&oui_entry->list);
19173 kfree(oui_entry);
19174 }
19175 }
19176 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19177 }
19178
19179 static int
wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * vndr_oui,u32 vndr_oui_len)19180 wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
19181 char *vndr_oui, u32 vndr_oui_len)
19182 {
19183 int i;
19184 int vndr_oui_num = 0;
19185
19186 struct wl_connect_info *conn_info = wl_to_conn(cfg);
19187 wl_vndr_oui_entry_t *oui_entry = NULL;
19188 struct parsed_vndr_ie_info *vndr_info;
19189 struct parsed_vndr_ies vndr_ies;
19190
19191 char *pos = vndr_oui;
19192 u32 remained_buf_len = vndr_oui_len;
19193 unsigned long flags;
19194
19195 if (!conn_info->resp_ie_len) {
19196 return BCME_ERROR;
19197 }
19198
19199 wl_vndr_ies_clear_vendor_oui_list(cfg);
19200
19201 if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
19202 conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
19203 for (i = 0; i < vndr_ies.count; i++) {
19204 vndr_info = &vndr_ies.ie_info[i];
19205 if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
19206 continue;
19207 }
19208
19209 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
19210 continue;
19211 }
19212
19213 wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
19214 vndr_oui_num++;
19215 }
19216 }
19217
19218 if (vndr_oui) {
19219 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19220 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19221 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
19222 GCC_DIAGNOSTIC_POP();
19223 if (remained_buf_len < VNDR_OUI_STR_LEN) {
19224 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19225 return BCME_ERROR;
19226 }
19227 pos += snprintf(pos, VNDR_OUI_STR_LEN, "%02X-%02X-%02X ",
19228 oui_entry->oui[0], oui_entry->oui[1], oui_entry->oui[2]);
19229 remained_buf_len -= VNDR_OUI_STR_LEN;
19230 }
19231 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19232 }
19233
19234 return vndr_oui_num;
19235 }
19236
19237 #ifdef WL_ANALYTICS
19238 static bool
wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211 * cfg,struct net_device * ndev,const char * vndr_oui)19239 wl_vndr_ies_find_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
19240 const char *vndr_oui)
19241 {
19242 int i;
19243 int vndr_oui_num = 0;
19244
19245 struct wl_connect_info *conn_info = wl_to_conn(cfg);
19246 wl_vndr_oui_entry_t *oui_entry = NULL;
19247 struct parsed_vndr_ie_info *vndr_info;
19248 struct parsed_vndr_ies vndr_ies;
19249
19250 unsigned long flags;
19251 bool found = FALSE;
19252
19253 if (!conn_info->resp_ie_len) {
19254 return FALSE;
19255 }
19256
19257 wl_vndr_ies_clear_vendor_oui_list(cfg);
19258
19259 if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
19260 conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
19261 for (i = 0; i < vndr_ies.count; i++) {
19262 vndr_info = &vndr_ies.ie_info[i];
19263 if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
19264 continue;
19265 }
19266
19267 if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
19268 continue;
19269 }
19270
19271 wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
19272 vndr_oui_num++;
19273 }
19274 }
19275
19276 if (vndr_oui && vndr_oui_num) {
19277 WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
19278 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19279 list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
19280 GCC_DIAGNOSTIC_POP();
19281 if (!memcmp(vndr_oui, oui_entry->oui, DOT11_OUI_LEN)) {
19282 found = TRUE;
19283 break;
19284 }
19285 }
19286 WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
19287 }
19288
19289 return found;
19290 }
19291 #endif /* WL_ANALYTICS */
19292
19293 void
wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 * cfg)19294 wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 *cfg)
19295 {
19296 #ifdef WL_CFG80211_P2P_DEV_IF
19297 if (cfg->p2p_wdev) {
19298 /* clear IEs for dedicated p2p interface */
19299 WL_DBG_MEM(("Clear IEs for P2P Discovery Iface\n"));
19300 wl_cfg80211_clear_per_bss_ies(cfg, cfg->p2p_wdev);
19301 }
19302 #else
19303 /* Legacy P2P used to store it in primary dev cache */
19304 s32 index;
19305 struct net_device *ndev;
19306 s32 bssidx;
19307 s32 ret;
19308 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
19309 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
19310
19311 WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
19312 /* certain vendors uses p2p0 interface in addition to
19313 * the dedicated p2p interface supported by the linux
19314 * kernel.
19315 */
19316 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
19317 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
19318 if (bssidx == WL_INVALID) {
19319 WL_DBG(("No discovery I/F available. Do nothing.\n"));
19320 return;
19321 }
19322
19323 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
19324 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
19325 bssidx, vndrie_flag[index], NULL, 0)) < 0) {
19326 if (ret != BCME_NOTFOUND) {
19327 WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret));
19328 }
19329 }
19330 }
19331 #endif /* WL_CFG80211_P2P_DEV_IF */
19332 }
19333
19334 s32
wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev)19335 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
19336 {
19337 s32 index;
19338 s32 ret;
19339 struct net_info *netinfo;
19340 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
19341 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
19342
19343 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
19344 if (!netinfo || !netinfo->wdev) {
19345 WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
19346 return -1;
19347 }
19348
19349 WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo->bssidx));
19350 /* Clear the IEs set in the firmware so that host is in sync with firmware */
19351 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
19352 if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
19353 netinfo->bssidx, vndrie_flag[index], NULL, 0)) < 0)
19354 if (ret != BCME_NOTFOUND) {
19355 WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
19356 }
19357 }
19358
19359 return 0;
19360 }
19361
19362 s32
wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 * cfg)19363 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
19364 {
19365 struct net_info *iter, *next;
19366
19367 WL_DBG(("clear management vendor IEs \n"));
19368 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19369 for_each_ndev(cfg, iter, next) {
19370 GCC_DIAGNOSTIC_POP();
19371 wl_cfg80211_clear_per_bss_ies(cfg, iter->wdev);
19372 }
19373 return 0;
19374 }
19375
19376 static void
wl_print_fw_ie_data(struct bcm_cfg80211 * cfg,struct net_device * ndev,s32 bssidx)19377 wl_print_fw_ie_data(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx)
19378 {
19379 vndr_ie_buf_t *ies;
19380 s32 ret;
19381
19382 ret = wldev_iovar_getbuf_bsscfg(ndev, "vndr_ie", NULL,
19383 0, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
19384 bssidx, &cfg->ioctl_buf_sync);
19385 if (ret == BCME_OK) {
19386 ies = (vndr_ie_buf_t *)cfg->ioctl_buf;
19387 WL_INFORM_MEM(("FW IE count:%d ", ies->iecount));
19388 #ifdef GET_FW_IE_DATA
19389 if (wl_dbg_level & WL_DBG_DBG) {
19390 int i = 0;
19391 /* If debug enabled, print each IE */
19392 for (i = 0; i < ies->iecount; i++) {
19393 vndr_ie_info_t *info = &ies->vndr_ie_list[i];
19394 WL_DBG_MEM(("pktflag:0x%x\n", info->pktflag));
19395 prhex("IE:", (u8 *)&info->vndr_ie_data,
19396 info->vndr_ie_data.len + TLV_HDR_LEN);
19397 }
19398 }
19399 #endif /* GET_FW_IE_DATA */
19400 } else {
19401 WL_ERR(("IE retrieval failed! ret:%d\n", ret));
19402 }
19403 }
19404
19405 #define WL_VNDR_IE_MAXLEN 2048
19406 static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
19407 int
wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,s32 bssidx,s32 pktflag,const u8 * vndr_ie,u32 vndr_ie_len)19408 wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
19409 s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
19410 {
19411 struct net_device *ndev = NULL;
19412 s32 ret = BCME_OK;
19413 u8 *curr_ie_buf = NULL;
19414 u8 *mgmt_ie_buf = NULL;
19415 u32 mgmt_ie_buf_len = 0;
19416 u32 *mgmt_ie_len = 0;
19417 u32 del_add_ie_buf_len = 0;
19418 u32 total_ie_buf_len = 0;
19419 u32 parsed_ie_buf_len = 0;
19420 struct parsed_vndr_ies old_vndr_ies;
19421 struct parsed_vndr_ies new_vndr_ies;
19422 s32 i;
19423 u8 *ptr;
19424 s32 remained_buf_len;
19425 wl_bss_vndr_ies_t *ies = NULL;
19426 struct net_info *netinfo;
19427 struct wireless_dev *wdev;
19428
19429 if (!cfgdev) {
19430 WL_ERR(("cfgdev is NULL\n"));
19431 return -EINVAL;
19432 }
19433
19434 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
19435 wdev = cfgdev_to_wdev(cfgdev);
19436
19437 if (bssidx > WL_MAX_IFS) {
19438 WL_ERR(("bssidx > supported concurrent Ifaces \n"));
19439 return -EINVAL;
19440 }
19441
19442 netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
19443 if (!netinfo) {
19444 WL_ERR(("net_info ptr is NULL \n"));
19445 return -EINVAL;
19446 }
19447
19448 /* Clear the global buffer */
19449 bzero(g_mgmt_ie_buf, sizeof(g_mgmt_ie_buf));
19450 curr_ie_buf = g_mgmt_ie_buf;
19451 ies = &netinfo->bss.ies;
19452
19453 WL_DBG_MEM(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d\n",
19454 pktflag, bssidx, vndr_ie_len));
19455
19456 switch (pktflag) {
19457 case VNDR_IE_PRBRSP_FLAG :
19458 mgmt_ie_buf = ies->probe_res_ie;
19459 mgmt_ie_len = &ies->probe_res_ie_len;
19460 mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
19461 break;
19462 case VNDR_IE_ASSOCRSP_FLAG :
19463 mgmt_ie_buf = ies->assoc_res_ie;
19464 mgmt_ie_len = &ies->assoc_res_ie_len;
19465 mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
19466 break;
19467 case VNDR_IE_BEACON_FLAG :
19468 mgmt_ie_buf = ies->beacon_ie;
19469 mgmt_ie_len = &ies->beacon_ie_len;
19470 mgmt_ie_buf_len = sizeof(ies->beacon_ie);
19471 break;
19472 case VNDR_IE_PRBREQ_FLAG :
19473 mgmt_ie_buf = ies->probe_req_ie;
19474 mgmt_ie_len = &ies->probe_req_ie_len;
19475 mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
19476 break;
19477 case VNDR_IE_ASSOCREQ_FLAG :
19478 mgmt_ie_buf = ies->assoc_req_ie;
19479 mgmt_ie_len = &ies->assoc_req_ie_len;
19480 mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
19481 break;
19482 case VNDR_IE_DISASSOC_FLAG :
19483 mgmt_ie_buf = ies->disassoc_ie;
19484 mgmt_ie_len = &ies->disassoc_ie_len;
19485 mgmt_ie_buf_len = sizeof(ies->disassoc_ie);
19486 break;
19487 default:
19488 mgmt_ie_buf = NULL;
19489 mgmt_ie_len = NULL;
19490 WL_ERR(("not suitable packet type (%d)\n", pktflag));
19491 return BCME_ERROR;
19492 }
19493
19494 if (vndr_ie_len > mgmt_ie_buf_len) {
19495 WL_ERR(("extra IE size too big\n"));
19496 ret = -ENOMEM;
19497 } else {
19498 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
19499 if (vndr_ie && vndr_ie_len && curr_ie_buf) {
19500 ptr = curr_ie_buf;
19501
19502 WL_DBG(("Incoming IEs len:%d\n", vndr_ie_len));
19503 if ((ret = wl_cfg80211_parse_vndr_ies((const u8 *)vndr_ie,
19504 vndr_ie_len, &new_vndr_ies)) < 0) {
19505 WL_ERR(("parse vndr ie failed \n"));
19506 goto exit;
19507 }
19508
19509 for (i = 0; i < new_vndr_ies.count; i++) {
19510 struct parsed_vndr_ie_info *vndrie_info =
19511 &new_vndr_ies.ie_info[i];
19512
19513 if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
19514 WL_ERR(("IE size is too big (%d > %d)\n",
19515 parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
19516 ret = -EINVAL;
19517 goto exit;
19518 }
19519
19520 memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
19521 vndrie_info->ie_len);
19522 parsed_ie_buf_len += vndrie_info->ie_len;
19523 }
19524 }
19525
19526 if (mgmt_ie_buf != NULL) {
19527 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
19528 (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
19529 WL_DBG_MEM(("No change in cached IEs for pkt:%d\n", pktflag));
19530 goto exit;
19531 }
19532
19533 /* parse old vndr_ie */
19534 WL_DBG(("Cached IEs len:%d\n", *mgmt_ie_len));
19535 if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
19536 &old_vndr_ies)) < 0) {
19537 WL_ERR(("parse vndr ie failed \n"));
19538 goto exit;
19539 }
19540 /* make a command to delete old ie */
19541 for (i = 0; i < old_vndr_ies.count; i++) {
19542 struct parsed_vndr_ie_info *vndrie_info =
19543 &old_vndr_ies.ie_info[i];
19544
19545 if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
19546 WL_DBG_MEM(("DEL VENDOR EXTN ID :%d TYPE:%d Len:%d\n",
19547 vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
19548 vndrie_info->vndrie.len));
19549 } else {
19550 WL_DBG_MEM(("DEL ID :%d Len:%d OUI:"MACOUIDBG" TYPE:%d\n",
19551 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
19552 MACOUI2STRDBG(vndrie_info->vndrie.oui),
19553 vndrie_info->vndrie.data[0]));
19554 }
19555
19556 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
19557 pktflag, vndrie_info->vndrie.oui,
19558 vndrie_info->vndrie.id,
19559 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
19560 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
19561 "del");
19562
19563 curr_ie_buf += del_add_ie_buf_len;
19564 total_ie_buf_len += del_add_ie_buf_len;
19565 }
19566 }
19567
19568 *mgmt_ie_len = 0;
19569 /* Add if there is any extra IE */
19570 if (mgmt_ie_buf && parsed_ie_buf_len) {
19571 ptr = mgmt_ie_buf;
19572
19573 remained_buf_len = mgmt_ie_buf_len;
19574 /* make a command to add new ie */
19575 for (i = 0; i < new_vndr_ies.count; i++) {
19576 struct parsed_vndr_ie_info *vndrie_info =
19577 &new_vndr_ies.ie_info[i];
19578 if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
19579 WL_DBG_MEM(("ADD VENDOR EXTN ID :%d TYPE:%d Len:%d\n",
19580 vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
19581 vndrie_info->vndrie.len));
19582 } else {
19583 WL_DBG_MEM(("ADD ID :%d Len:%d OUI:"MACOUIDBG" TYPE:%d\n",
19584 vndrie_info->vndrie.id, vndrie_info->vndrie.len,
19585 MACOUI2STRDBG(vndrie_info->vndrie.oui),
19586 vndrie_info->vndrie.data[0]));
19587 }
19588
19589 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
19590 pktflag, vndrie_info->vndrie.oui,
19591 vndrie_info->vndrie.id,
19592 vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
19593 vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
19594 "add");
19595
19596 /* verify remained buf size before copy data */
19597 if (remained_buf_len >= vndrie_info->ie_len) {
19598 remained_buf_len -= vndrie_info->ie_len;
19599 } else {
19600 WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
19601 "found vndr ies # = %d(cur %d), remained len %d, "
19602 "cur mgmt_ie_len %d, new ie len = %d\n",
19603 pktflag, new_vndr_ies.count, i, remained_buf_len,
19604 *mgmt_ie_len, vndrie_info->ie_len));
19605 break;
19606 }
19607
19608 /* save the parsed IE in cfg struct */
19609 memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
19610 vndrie_info->ie_len);
19611 *mgmt_ie_len += vndrie_info->ie_len;
19612 curr_ie_buf += del_add_ie_buf_len;
19613 total_ie_buf_len += del_add_ie_buf_len;
19614 }
19615 }
19616
19617 if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
19618 ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
19619 total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
19620 bssidx, &cfg->ioctl_buf_sync);
19621 if (ret) {
19622 WL_ERR(("vndr_ie set error :%d\n", ret));
19623 if (ret == BCME_NOTFOUND) {
19624 /* retrieve and print IE data for debug */
19625 wl_print_fw_ie_data(cfg, ndev, bssidx);
19626 }
19627 }
19628 }
19629 }
19630 exit:
19631
19632 return ret;
19633 }
19634
wl_cfg80211_clear_security(struct bcm_cfg80211 * cfg)19635 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
19636 {
19637 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
19638 int err;
19639
19640 /* Clear the security settings on the primary Interface */
19641 err = wldev_iovar_setint(dev, "wsec", 0);
19642 if (unlikely(err)) {
19643 WL_ERR(("wsec clear failed \n"));
19644 }
19645 err = wldev_iovar_setint(dev, "auth", 0);
19646 if (unlikely(err)) {
19647 WL_ERR(("auth clear failed \n"));
19648 }
19649 err = wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
19650 if (unlikely(err)) {
19651 WL_ERR(("wpa_auth clear failed \n"));
19652 }
19653 }
19654
19655 #ifdef WL_CFG80211_P2P_DEV_IF
wl_cfg80211_del_p2p_wdev(struct net_device * dev)19656 void wl_cfg80211_del_p2p_wdev(struct net_device *dev)
19657 {
19658 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
19659 struct wireless_dev *wdev = NULL;
19660
19661 WL_DBG(("Enter \n"));
19662 if (!cfg) {
19663 WL_ERR(("Invalid Ptr\n"));
19664 return;
19665 } else {
19666 wdev = cfg->p2p_wdev;
19667 }
19668
19669 if (wdev) {
19670 wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
19671 }
19672 }
19673 #endif /* WL_CFG80211_P2P_DEV_IF */
19674
19675 #ifdef GTK_OFFLOAD_SUPPORT
19676 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
19677 static s32
wl_cfg80211_set_rekey_data(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_gtk_rekey_data * data)19678 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
19679 struct cfg80211_gtk_rekey_data *data)
19680 {
19681 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
19682 s32 err = 0;
19683 gtk_keyinfo_t keyinfo;
19684 bcol_gtk_para_t bcol_keyinfo;
19685
19686 WL_DBG(("Enter\n"));
19687 if (data == NULL || cfg->p2p_net == dev) {
19688 WL_ERR(("data is NULL or wrong net device\n"));
19689 return -EINVAL;
19690 }
19691
19692 prhex("kck", (const u8 *) (data->kck), RSN_KCK_LENGTH);
19693 prhex("kek", (const u8 *) (data->kek), RSN_KEK_LENGTH);
19694 prhex("replay_ctr", (const u8 *) (data->replay_ctr), RSN_REPLAY_LEN);
19695 bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH);
19696 bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH);
19697 bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN);
19698
19699 memset(&bcol_keyinfo, 0, sizeof(bcol_keyinfo));
19700 bcol_keyinfo.enable = 1;
19701 bcol_keyinfo.ptk_len = 64;
19702 memcpy(&bcol_keyinfo.ptk[0], data->kck, RSN_KCK_LENGTH);
19703 memcpy(&bcol_keyinfo.ptk[RSN_KCK_LENGTH], data->kek, RSN_KEK_LENGTH);
19704 err = wldev_iovar_setbuf(dev, "bcol_gtk_rekey_ptk", &bcol_keyinfo,
19705 sizeof(bcol_keyinfo), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
19706 if (!err) {
19707 return err;
19708 }
19709
19710 if ((err = wldev_iovar_setbuf(dev, "gtk_key_info", &keyinfo, sizeof(keyinfo),
19711 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync)) < 0) {
19712 WL_ERR(("seting gtk_key_info failed code=%d\n", err));
19713 return err;
19714 }
19715
19716 WL_DBG(("Exit\n"));
19717 return err;
19718 }
19719 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
19720 #endif /* GTK_OFFLOAD_SUPPORT */
19721
19722 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
wl_cfg80211_set_pmk(struct wiphy * wiphy,struct net_device * dev,const struct cfg80211_pmk_conf * conf)19723 static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
19724 const struct cfg80211_pmk_conf *conf)
19725 {
19726 int ret = 0;
19727 wsec_pmk_t pmk;
19728 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
19729 struct wl_security *sec;
19730 s32 bssidx;
19731
19732 pmk.key_len = conf->pmk_len;
19733 if (pmk.key_len > sizeof(pmk.key)) {
19734 ret = -EINVAL;
19735 return ret;
19736 }
19737 pmk.flags = 0;
19738 ret = memcpy_s(&pmk.key, sizeof(pmk.key), conf->pmk, conf->pmk_len);
19739 if (ret) {
19740 ret = -EINVAL;
19741 return ret;
19742 }
19743
19744 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
19745 WL_ERR(("Find index failed\n"));
19746 ret = -EINVAL;
19747 return ret;
19748 }
19749
19750 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
19751 if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
19752 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
19753 ret = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len,
19754 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
19755 if (ret) {
19756 /* could fail in case that 'okc' is not supported */
19757 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
19758 }
19759 }
19760
19761 ret = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
19762 if (ret) {
19763 WL_ERR(("wl_cfg80211_set_pmk error:%d", ret));
19764 ret = -EINVAL;
19765 return ret;
19766 } else {
19767 WL_DBG(("pmk added for mac:"MACDBG"\n", MAC2STRDBG(conf->aa)));
19768 }
19769 return 0;
19770 }
19771
wl_cfg80211_del_pmk(struct wiphy * wiphy,struct net_device * dev,const u8 * aa)19772 static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
19773 const u8 *aa)
19774 {
19775 int err = BCME_OK;
19776 struct cfg80211_pmksa pmksa;
19777
19778 /* build up cfg80211_pmksa structure to use existing wl_cfg80211_update_pmksa API */
19779 bzero(&pmksa, sizeof(pmksa));
19780 pmksa.bssid = aa;
19781
19782 err = wl_cfg80211_update_pmksa(wiphy, dev, &pmksa, FALSE);
19783 if (unlikely(err)) {
19784 WL_ERR(("wl_cfg80211_update_pmksa err:%d\n", err));
19785 err = -EINVAL;
19786 } else {
19787 WL_DBG(("pmk deleted for bssid:"MACDBG"\n", MAC2STRDBG(aa)));
19788 }
19789
19790 return err;
19791 }
19792 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
19793
19794 u64
wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 * cfg)19795 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
19796 {
19797 u64 id = 0;
19798 id = ++cfg->last_roc_id;
19799 #ifdef P2P_LISTEN_OFFLOADING
19800 if (id == P2PO_COOKIE) {
19801 id = ++cfg->last_roc_id;
19802 }
19803 #endif /* P2P_LISTEN_OFFLOADING */
19804 if (id == 0)
19805 id = ++cfg->last_roc_id;
19806 return id;
19807 }
19808
19809 struct net_device*
wl_get_netdev_by_name(struct bcm_cfg80211 * cfg,char * ifname)19810 wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname)
19811 {
19812 struct net_info *iter, *next;
19813 struct net_device *ndev = NULL;
19814
19815 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19816 for_each_ndev(cfg, iter, next) {
19817 GCC_DIAGNOSTIC_POP();
19818 if (iter->ndev) {
19819 if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
19820 ndev = iter->ndev;
19821 break;
19822 }
19823 }
19824 }
19825
19826 return ndev;
19827 }
19828
19829 #ifdef WBTEXT
wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 * cfg,struct ether_addr * ea)19830 static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
19831 {
19832 wl_wbtext_bssid_t *bssid = NULL;
19833 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19834 /* check duplicate */
19835 list_for_each_entry(bssid, &cfg->wbtext_bssid_list, list) {
19836 GCC_DIAGNOSTIC_POP();
19837 if (!memcmp(bssid->ea.octet, ea, ETHER_ADDR_LEN)) {
19838 return FALSE;
19839 }
19840 }
19841
19842 return TRUE;
19843 }
19844
wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 * cfg,struct ether_addr * ea)19845 static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
19846 {
19847 wl_wbtext_bssid_t *bssid = NULL;
19848 char eabuf[ETHER_ADDR_STR_LEN];
19849
19850 bssid = (wl_wbtext_bssid_t *)MALLOC(cfg->osh, sizeof(wl_wbtext_bssid_t));
19851 if (bssid == NULL) {
19852 WL_ERR(("alloc failed\n"));
19853 return FALSE;
19854 }
19855
19856 memcpy(bssid->ea.octet, ea, ETHER_ADDR_LEN);
19857
19858 INIT_LIST_HEAD(&bssid->list);
19859 list_add_tail(&bssid->list, &cfg->wbtext_bssid_list);
19860
19861 WL_DBG(("add wbtext bssid : %s\n", bcm_ether_ntoa(ea, eabuf)));
19862
19863 return TRUE;
19864 }
19865
wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 * cfg)19866 static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg)
19867 {
19868 wl_wbtext_bssid_t *bssid = NULL;
19869 char eabuf[ETHER_ADDR_STR_LEN];
19870
19871 while (!list_empty(&cfg->wbtext_bssid_list)) {
19872 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
19873 bssid = list_entry(cfg->wbtext_bssid_list.next, wl_wbtext_bssid_t, list);
19874 GCC_DIAGNOSTIC_POP();
19875 if (bssid) {
19876 WL_DBG(("clear wbtext bssid : %s\n", bcm_ether_ntoa(&bssid->ea, eabuf)));
19877 list_del(&bssid->list);
19878 MFREE(cfg->osh, bssid, sizeof(wl_wbtext_bssid_t));
19879 }
19880 }
19881 }
19882
wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 * cfg,struct net_device * dev)19883 static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev)
19884 {
19885 struct wl_connect_info *conn_info = wl_to_conn(cfg);
19886 bcm_tlv_t * cap_ie = NULL;
19887 bool req_sent = FALSE;
19888 struct wl_profile *profile;
19889
19890 WL_DBG(("Enter\n"));
19891
19892 profile = wl_get_profile_by_netdev(cfg, dev);
19893 if (!profile) {
19894 WL_ERR(("no profile exists\n"));
19895 return;
19896 }
19897
19898 if (wl_cfg80211_wbtext_check_bssid_list(cfg,
19899 (struct ether_addr *)&profile->bssid) == FALSE) {
19900 WL_DBG(("already updated\n"));
19901 return;
19902 }
19903
19904 /* first, check NBR bit in RRM IE */
19905 if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
19906 DOT11_MNG_RRM_CAP_ID)) != NULL) {
19907 if (isset(cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
19908 WL_DBG(("sending neighbor report\n"));
19909 req_sent = wl_cfg80211_wbtext_send_nbr_req(cfg, dev, profile);
19910 }
19911 }
19912
19913 /* if RRM nbr was not supported, check BTM bit in extend cap. IE */
19914 if (!req_sent) {
19915 if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
19916 DOT11_MNG_EXT_CAP_ID)) != NULL) {
19917 if (cap_ie->len >= DOT11_EXTCAP_LEN_BSSTRANS &&
19918 isset(cap_ie->data, DOT11_EXT_CAP_BSSTRANS_MGMT)) {
19919 WL_DBG(("sending btm query\n"));
19920 wl_cfg80211_wbtext_send_btm_query(cfg, dev, profile);
19921 }
19922 }
19923 }
19924 }
19925
wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 * cfg,struct net_device * dev,struct wl_profile * profile)19926 static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
19927 struct wl_profile *profile)
19928 {
19929 int error = -1;
19930 char *smbuf = NULL;
19931 struct wl_connect_info *conn_info = wl_to_conn(cfg);
19932 bcm_tlv_t * rrm_cap_ie = NULL;
19933 wlc_ssid_t *ssid = NULL;
19934 bool ret = FALSE;
19935
19936 WL_DBG(("Enter\n"));
19937
19938 /* check RRM nbr bit in extend cap. IE of assoc response */
19939 if ((rrm_cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
19940 DOT11_MNG_RRM_CAP_ID)) != NULL) {
19941 if (!isset(rrm_cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
19942 WL_DBG(("AP doesn't support neighbor report\n"));
19943 return FALSE;
19944 }
19945 }
19946
19947 smbuf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
19948 if (smbuf == NULL) {
19949 WL_ERR(("failed to allocated memory\n"));
19950 goto nbr_req_out;
19951 }
19952
19953 ssid = (wlc_ssid_t *)MALLOCZ(cfg->osh, sizeof(wlc_ssid_t));
19954 if (ssid == NULL) {
19955 WL_ERR(("failed to allocated memory\n"));
19956 goto nbr_req_out;
19957 }
19958
19959 ssid->SSID_len = MIN(profile->ssid.SSID_len, DOT11_MAX_SSID_LEN);
19960 memcpy(ssid->SSID, profile->ssid.SSID, ssid->SSID_len);
19961
19962 error = wldev_iovar_setbuf(dev, "rrm_nbr_req", ssid,
19963 sizeof(wlc_ssid_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
19964 if (error == BCME_OK) {
19965 ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
19966 (struct ether_addr *)&profile->bssid);
19967 } else {
19968 WL_ERR(("failed to send neighbor report request, error=%d\n", error));
19969 }
19970
19971 nbr_req_out:
19972 if (ssid) {
19973 MFREE(cfg->osh, ssid, sizeof(wlc_ssid_t));
19974 }
19975
19976 if (smbuf) {
19977 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
19978 }
19979 return ret;
19980 }
19981
wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 * cfg,struct net_device * dev,struct wl_profile * profile)19982 static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
19983 struct wl_profile *profile)
19984
19985 {
19986 int error = -1;
19987 bool ret = FALSE;
19988 wl_bsstrans_query_t btq;
19989
19990 WL_DBG(("Enter\n"));
19991
19992 bzero(&btq, sizeof(wl_bsstrans_query_t));
19993
19994 btq.version = WL_BSSTRANS_QUERY_VERSION_1;
19995 error = wldev_iovar_setbuf(dev, "wnm_bsstrans_query", &btq,
19996 sizeof(btq), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
19997 if (error == BCME_OK) {
19998 ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
19999 (struct ether_addr *)&profile->bssid);
20000 } else {
20001 WL_ERR(("wl_cfg80211_wbtext_send_btm_query: failed to set BTM query,"
20002 " error=%d\n", error));
20003 }
20004 return ret;
20005 }
20006
wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 * cfg,struct net_device * dev)20007 static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev)
20008 {
20009 keepalives_max_idle_t keepalive = {0, 0, 0, 0};
20010 s32 bssidx, error;
20011 int wnm_maxidle = 0;
20012 struct wl_connect_info *conn_info = wl_to_conn(cfg);
20013
20014 /* AP supports wnm max idle ? */
20015 if (bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
20016 DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID) != NULL) {
20017 error = wldev_iovar_getint(dev, "wnm_maxidle", &wnm_maxidle);
20018 if (error < 0) {
20019 WL_ERR(("failed to get wnm max idle period : %d\n", error));
20020 }
20021 }
20022
20023 WL_DBG(("wnm max idle period : %d\n", wnm_maxidle));
20024
20025 /* if wnm maxidle has valid period, set it as keep alive */
20026 if (wnm_maxidle > 0) {
20027 keepalive.keepalive_count = 1;
20028 }
20029
20030 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) >= 0) {
20031 error = wldev_iovar_setbuf_bsscfg(dev, "wnm_keepalives_max_idle", &keepalive,
20032 sizeof(keepalives_max_idle_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
20033 bssidx, &cfg->ioctl_buf_sync);
20034 if (error < 0) {
20035 if (error == BCME_BADARG) {
20036 WL_ERR(("set wnm_keepalive with invalid arguments\n"));
20037 } else {
20038 WL_ERR(("set wnm_keepalives_max_idle failed : %d\n", error));
20039 }
20040 }
20041 }
20042 }
20043
20044 static int
wl_cfg80211_recv_nbr_resp(struct net_device * dev,uint8 * body,uint body_len)20045 wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len)
20046 {
20047 dot11_rm_action_t *rm_rep;
20048 bcm_tlv_t *tlvs;
20049 uint tlv_len;
20050 int i, error;
20051 dot11_neighbor_rep_ie_t *nbr_rep_ie;
20052 chanspec_t ch;
20053 wl_roam_channel_list_t channel_list;
20054 char iobuf[WLC_IOCTL_SMLEN];
20055
20056 if (body_len < DOT11_RM_ACTION_LEN) {
20057 WL_ERR(("Received Neighbor Report frame with incorrect length %d\n",
20058 body_len));
20059 return BCME_ERROR;
20060 }
20061
20062 rm_rep = (dot11_rm_action_t *)body;
20063 WL_DBG(("received neighbor report (token = %d)\n", rm_rep->token));
20064
20065 tlvs = (bcm_tlv_t *)&rm_rep->data[0];
20066
20067 tlv_len = body_len - DOT11_RM_ACTION_LEN;
20068
20069 while (tlvs && tlvs->id == DOT11_MNG_NEIGHBOR_REP_ID) {
20070 nbr_rep_ie = (dot11_neighbor_rep_ie_t *)tlvs;
20071
20072 if (nbr_rep_ie->len < DOT11_NEIGHBOR_REP_IE_FIXED_LEN) {
20073 WL_ERR(("malformed Neighbor Report element with length %d\n",
20074 nbr_rep_ie->len));
20075 tlvs = bcm_next_tlv(tlvs, &tlv_len);
20076 continue;
20077 }
20078
20079 ch = CH20MHZ_CHSPEC(nbr_rep_ie->channel);
20080 WL_DBG(("ch:%d, bssid:"MACDBG"\n",
20081 ch, MAC2STRDBG(nbr_rep_ie->bssid.octet)));
20082
20083 /* get RCC list */
20084 error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0,
20085 (void *)&channel_list, sizeof(channel_list), NULL);
20086 if (error) {
20087 WL_ERR(("Failed to get roamscan channels, error = %d\n", error));
20088 return BCME_ERROR;
20089 }
20090
20091 /* update RCC */
20092 if (channel_list.n < MAX_ROAM_CHANNEL) {
20093 for (i = 0; i < channel_list.n; i++) {
20094 if (channel_list.channels[i] == ch) {
20095 break;
20096 }
20097 }
20098 if (i == channel_list.n) {
20099 channel_list.channels[channel_list.n] = ch;
20100 channel_list.n++;
20101 }
20102 }
20103
20104 /* set RCC list */
20105 error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list,
20106 sizeof(channel_list), iobuf, sizeof(iobuf), NULL);
20107 if (error) {
20108 WL_DBG(("Failed to set roamscan channels, error = %d\n", error));
20109 }
20110
20111 tlvs = bcm_next_tlv(tlvs, &tlv_len);
20112 }
20113
20114 return BCME_OK;
20115 }
20116 #endif /* WBTEXT */
20117 #ifdef SUPPORT_SET_CAC
20118 void
wl_cfg80211_set_cac(struct bcm_cfg80211 * cfg,int enable)20119 wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable)
20120 {
20121 int ret = 0;
20122 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20123
20124 WL_DBG(("cac enable %d\n", enable));
20125 if (!dhd) {
20126 WL_ERR(("dhd is NULL\n"));
20127 return;
20128 }
20129 if ((ret = dhd_wl_ioctl_set_intiovar(dhd, "cac", enable,
20130 WLC_SET_VAR, TRUE, 0)) < 0) {
20131 WL_ERR(("Failed set CAC, ret=%d\n", ret));
20132 } else {
20133 WL_DBG(("CAC set successfully\n"));
20134 }
20135 return;
20136 }
20137 #endif /* SUPPORT_SET_CAC */
20138
20139 #ifdef SUPPORT_RSSI_SUM_REPORT
20140 int
wl_get_rssi_per_ant(struct net_device * dev,char * ifname,char * peer_mac,void * param)20141 wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void *param)
20142 {
20143 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20144 wl_rssi_ant_mimo_t *get_param = (wl_rssi_ant_mimo_t *)param;
20145 rssi_ant_param_t *set_param = NULL;
20146 struct net_device *ifdev = NULL;
20147 char iobuf[WLC_IOCTL_SMLEN];
20148 int err = BCME_OK;
20149 int iftype = 0;
20150
20151 bzero(iobuf, WLC_IOCTL_SMLEN);
20152
20153 /* Check the interface type */
20154 ifdev = wl_get_netdev_by_name(cfg, ifname);
20155 if (ifdev == NULL) {
20156 WL_ERR(("Could not find net_device for ifname:%s\n", ifname));
20157 err = BCME_BADARG;
20158 goto fail;
20159 }
20160
20161 iftype = ifdev->ieee80211_ptr->iftype;
20162 if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO) {
20163 if (peer_mac) {
20164 set_param = (rssi_ant_param_t *)MALLOCZ(cfg->osh, sizeof(rssi_ant_param_t));
20165 err = wl_cfg80211_ether_atoe(peer_mac, &set_param->ea);
20166 if (!err) {
20167 WL_ERR(("Invalid Peer MAC format\n"));
20168 err = BCME_BADARG;
20169 goto fail;
20170 }
20171 } else {
20172 WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype));
20173 err = BCME_BADARG;
20174 goto fail;
20175 }
20176 }
20177
20178 err = wldev_iovar_getbuf(ifdev, "phy_rssi_ant", peer_mac ?
20179 (void *)&(set_param->ea) : NULL, peer_mac ? ETHER_ADDR_LEN : 0,
20180 (void *)iobuf, sizeof(iobuf), NULL);
20181 if (unlikely(err)) {
20182 WL_ERR(("Failed to get rssi info, err=%d\n", err));
20183 } else {
20184 memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t));
20185 if (get_param->count == 0) {
20186 WL_ERR(("Not supported on this chip\n"));
20187 err = BCME_UNSUPPORTED;
20188 }
20189 }
20190
20191 fail:
20192 if (set_param) {
20193 MFREE(cfg->osh, set_param, sizeof(rssi_ant_param_t));
20194 }
20195
20196 return err;
20197 }
20198
20199 int
wl_get_rssi_logging(struct net_device * dev,void * param)20200 wl_get_rssi_logging(struct net_device *dev, void *param)
20201 {
20202 rssilog_get_param_t *get_param = (rssilog_get_param_t *)param;
20203 char iobuf[WLC_IOCTL_SMLEN];
20204 int err = BCME_OK;
20205
20206 bzero(iobuf, WLC_IOCTL_SMLEN);
20207 bzero(get_param, sizeof(*get_param));
20208 err = wldev_iovar_getbuf(dev, "rssilog", NULL, 0, (void *)iobuf,
20209 sizeof(iobuf), NULL);
20210 if (err) {
20211 WL_ERR(("Failed to get rssi logging info, err=%d\n", err));
20212 } else {
20213 memcpy(get_param, iobuf, sizeof(*get_param));
20214 }
20215
20216 return err;
20217 }
20218
20219 int
wl_set_rssi_logging(struct net_device * dev,void * param)20220 wl_set_rssi_logging(struct net_device *dev, void *param)
20221 {
20222 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20223 rssilog_set_param_t *set_param = (rssilog_set_param_t *)param;
20224 int err;
20225
20226 err = wldev_iovar_setbuf(dev, "rssilog", set_param,
20227 sizeof(*set_param), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
20228 &cfg->ioctl_buf_sync);
20229 if (err) {
20230 WL_ERR(("Failed to set rssi logging param, err=%d\n", err));
20231 }
20232
20233 return err;
20234 }
20235 #endif /* SUPPORT_RSSI_SUM_REPORT */
20236 /* Function to flush the FW preserve buffer content
20237 * The buffer content is sent to host in form of events.
20238 */
20239 void
wl_flush_fw_log_buffer(struct net_device * dev,uint32 logset_mask)20240 wl_flush_fw_log_buffer(struct net_device *dev, uint32 logset_mask)
20241 {
20242 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20243 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20244 int i;
20245 int err = 0;
20246 u8 buf[WLC_IOCTL_SMLEN] = {0};
20247 wl_el_set_params_t set_param;
20248
20249 /* Set the size of data to retrieve */
20250 memset(&set_param, 0, sizeof(set_param));
20251 set_param.size = WLC_IOCTL_SMLEN;
20252
20253 for (i = 0; i < dhd->event_log_max_sets; i++)
20254 {
20255 if ((0x01u << i) & logset_mask) {
20256 set_param.set = i;
20257 err = wldev_iovar_setbuf(dev, "event_log_get", &set_param,
20258 sizeof(struct wl_el_set_params_s), buf, WLC_IOCTL_SMLEN,
20259 NULL);
20260 if (err) {
20261 WL_DBG(("Failed to get fw preserve logs, err=%d\n", err));
20262 }
20263 }
20264 }
20265 }
20266 #ifdef USE_WFA_CERT_CONF
20267 extern int g_frameburst;
20268 #endif /* USE_WFA_CERT_CONF */
20269
20270 int
wl_cfg80211_set_frameburst(struct bcm_cfg80211 * cfg,bool enable)20271 wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable)
20272 {
20273 int ret = BCME_OK;
20274 int val = enable ? 1 : 0;
20275
20276 #ifdef USE_WFA_CERT_CONF
20277 if (!g_frameburst) {
20278 WL_DBG(("Skip setting frameburst\n"));
20279 return 0;
20280 }
20281 #endif /* USE_WFA_CERT_CONF */
20282
20283 WL_DBG(("Set frameburst %d\n", val));
20284 ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg), WLC_SET_FAKEFRAG, &val, sizeof(val));
20285 if (ret < 0) {
20286 WL_ERR(("Failed set frameburst, ret=%d\n", ret));
20287 } else {
20288 WL_INFORM_MEM(("frameburst is %s\n", enable ? "enabled" : "disabled"));
20289 }
20290
20291 return ret;
20292 }
20293
20294 s32
wl_cfg80211_set_dbg_verbose(struct net_device * ndev,u32 level)20295 wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level)
20296 {
20297 /* configure verbose level for debugging */
20298 if (level) {
20299 /* Enable increased verbose */
20300 wl_dbg_level |= WL_DBG_DBG;
20301 } else {
20302 /* Disable */
20303 wl_dbg_level &= ~WL_DBG_DBG;
20304 }
20305 WL_INFORM(("debug verbose set to %d\n", level));
20306
20307 return BCME_OK;
20308 }
20309
20310 const u8 *
wl_find_attribute(const u8 * buf,u16 len,u16 element_id)20311 wl_find_attribute(const u8 *buf, u16 len, u16 element_id)
20312 {
20313 const u8 *attrib;
20314 u16 attrib_id;
20315 u16 attrib_len;
20316
20317 if (!buf) {
20318 WL_ERR(("buf null\n"));
20319 return NULL;
20320 }
20321
20322 attrib = buf;
20323 while (len >= 4) {
20324 /* attribute id */
20325 attrib_id = *attrib++ << 8;
20326 attrib_id |= *attrib++;
20327 len -= 2;
20328
20329 /* 2-byte little endian */
20330 attrib_len = *attrib++ << 8;
20331 attrib_len |= *attrib++;
20332
20333 len -= 2;
20334 if (attrib_id == element_id) {
20335 /* This will point to start of subelement attrib after
20336 * attribute id & len
20337 */
20338 return attrib;
20339 }
20340 if (len > attrib_len) {
20341 len -= attrib_len; /* for the remaining subelt fields */
20342 WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n",
20343 attrib_id, attrib_len, len));
20344
20345 /* Go to next subelement */
20346 attrib += attrib_len;
20347 } else {
20348 WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n",
20349 attrib_id, attrib_len));
20350 return NULL;
20351 }
20352 }
20353 return NULL;
20354 }
20355
wl_cfg80211_get_bus_state(struct bcm_cfg80211 * cfg)20356 uint8 wl_cfg80211_get_bus_state(struct bcm_cfg80211 *cfg)
20357 {
20358 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20359 WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
20360 dhd->hang_was_sent, dhd->busstate));
20361 return ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent);
20362 }
20363
20364 #ifdef WL_WPS_SYNC
wl_wps_reauth_timeout(unsigned long data)20365 static void wl_wps_reauth_timeout(unsigned long data)
20366 {
20367 struct net_device *ndev = (struct net_device *)data;
20368 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20369 s32 inst;
20370 unsigned long flags;
20371
20372 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20373 inst = wl_get_wps_inst_match(cfg, ndev);
20374 if (inst >= 0) {
20375 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n",
20376 ndev->name, inst, cfg->wps_session[inst].state));
20377 if (cfg->wps_session[inst].state == WPS_STATE_REAUTH_WAIT) {
20378 /* Session should get deleted from success (linkup) or
20379 * deauth case. Just in case, link reassoc failed, clear
20380 * state here.
20381 */
20382 WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n",
20383 ndev->name, inst));
20384 cfg->wps_session[inst].state = WPS_STATE_IDLE;
20385 cfg->wps_session[inst].in_use = false;
20386 }
20387 }
20388 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20389 }
20390
wl_init_wps_reauth_sm(struct bcm_cfg80211 * cfg)20391 static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg)
20392 {
20393 /* Only two instances are supported as of now. one for
20394 * infra STA and other for infra STA/GC.
20395 */
20396 int i = 0;
20397 struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
20398
20399 spin_lock_init(&cfg->wps_sync);
20400 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
20401 /* Init scan_timeout timer */
20402 init_timer_compat(&cfg->wps_session[i].timer, wl_wps_reauth_timeout, pdev);
20403 cfg->wps_session[i].in_use = false;
20404 cfg->wps_session[i].state = WPS_STATE_IDLE;
20405 }
20406 }
20407
wl_deinit_wps_reauth_sm(struct bcm_cfg80211 * cfg)20408 static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg)
20409 {
20410 int i = 0;
20411
20412 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
20413 cfg->wps_session[i].in_use = false;
20414 cfg->wps_session[i].state = WPS_STATE_IDLE;
20415 del_timer_sync(&cfg->wps_session[i].timer);
20416 }
20417
20418 }
20419
20420 static s32
wl_get_free_wps_inst(struct bcm_cfg80211 * cfg)20421 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg)
20422 {
20423 int i;
20424
20425 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
20426 if (!cfg->wps_session[i].in_use) {
20427 return i;
20428 }
20429 }
20430 return BCME_ERROR;
20431 }
20432
20433 static s32
wl_get_wps_inst_match(struct bcm_cfg80211 * cfg,struct net_device * ndev)20434 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev)
20435 {
20436 int i;
20437
20438 for (i = 0; i < WPS_MAX_SESSIONS; i++) {
20439 if ((cfg->wps_session[i].in_use) &&
20440 (ndev == cfg->wps_session[i].ndev)) {
20441 return i;
20442 }
20443 }
20444
20445 return BCME_ERROR;
20446 }
20447
20448 static s32
wl_wps_session_add(struct net_device * ndev,u16 mode,u8 * mac_addr)20449 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *mac_addr)
20450 {
20451 s32 inst;
20452 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20453 unsigned long flags;
20454
20455 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20456 /* Fetch and initialize a wps instance */
20457 inst = wl_get_free_wps_inst(cfg);
20458 if (inst == BCME_ERROR) {
20459 WL_ERR(("[WPS] No free insance\n"));
20460 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20461 return BCME_ERROR;
20462 }
20463 cfg->wps_session[inst].in_use = true;
20464 cfg->wps_session[inst].state = WPS_STATE_STARTED;
20465 cfg->wps_session[inst].ndev = ndev;
20466 cfg->wps_session[inst].mode = mode;
20467 /* return check not required since both buffer lens are same */
20468 (void)memcpy_s(cfg->wps_session[inst].peer_mac, ETH_ALEN, mac_addr, ETH_ALEN);
20469 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20470
20471 WL_INFORM_MEM(("[%s][WPS] session created. Peer: " MACDBG "\n",
20472 ndev->name, MAC2STRDBG(mac_addr)));
20473 return BCME_OK;
20474 }
20475
20476 static void
wl_wps_session_del(struct net_device * ndev)20477 wl_wps_session_del(struct net_device *ndev)
20478 {
20479 s32 inst;
20480 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20481 unsigned long flags;
20482 u16 cur_state;
20483
20484 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20485
20486 /* Get current instance for the given ndev */
20487 inst = wl_get_wps_inst_match(cfg, ndev);
20488 if (inst == BCME_ERROR) {
20489 WL_DBG(("[WPS] instance match NOT found\n"));
20490 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20491 return;
20492 }
20493
20494 cur_state = cfg->wps_session[inst].state;
20495 if (cur_state != WPS_STATE_DONE) {
20496 WL_DBG(("[WPS] wrong state:%d\n", cur_state));
20497 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20498 return;
20499 }
20500
20501 /* Mark this as unused */
20502 cfg->wps_session[inst].in_use = false;
20503 cfg->wps_session[inst].state = WPS_STATE_IDLE;
20504 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20505
20506 /* Ensure this API is called from sleepable context. */
20507 del_timer_sync(&cfg->wps_session[inst].timer);
20508
20509 WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev->name));
20510 }
20511
20512 static void
wl_wps_handle_ifdel(struct net_device * ndev)20513 wl_wps_handle_ifdel(struct net_device *ndev)
20514 {
20515 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20516 unsigned long flags;
20517 u16 cur_state;
20518 s32 inst;
20519
20520 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20521 inst = wl_get_wps_inst_match(cfg, ndev);
20522 if (inst == BCME_ERROR) {
20523 WL_DBG(("[WPS] instance match NOT found\n"));
20524 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20525 return;
20526 }
20527 cur_state = cfg->wps_session[inst].state;
20528 cfg->wps_session[inst].state = WPS_STATE_DONE;
20529 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20530
20531 WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev->name, cur_state));
20532 if (cur_state > WPS_STATE_IDLE) {
20533 wl_wps_session_del(ndev);
20534 }
20535 }
20536
20537 static s32
wl_wps_handle_sta_linkdown(struct net_device * ndev,u16 inst)20538 wl_wps_handle_sta_linkdown(struct net_device *ndev, u16 inst)
20539 {
20540 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20541 unsigned long flags;
20542 u16 cur_state;
20543 bool wps_done = false;
20544
20545 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20546 cur_state = cfg->wps_session[inst].state;
20547 if (cur_state == WPS_STATE_REAUTH_WAIT) {
20548 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20549 wl_clr_drv_status(cfg, CONNECTED, ndev);
20550 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
20551 WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev->name));
20552 /* Drop the link down event while we are waiting for reauth */
20553 return BCME_UNSUPPORTED;
20554 } else if (cur_state == WPS_STATE_STARTED) {
20555 /* Link down before reaching EAP-FAIL. End WPS session */
20556 cfg->wps_session[inst].state = WPS_STATE_DONE;
20557 wps_done = true;
20558 WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev->name));
20559 } else {
20560 WL_DBG(("[%s][WPS] link down in state:%d\n",
20561 ndev->name, cur_state));
20562 }
20563
20564 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20565
20566 if (wps_done) {
20567 wl_wps_session_del(ndev);
20568 }
20569 return BCME_OK;
20570 }
20571
20572 static s32
wl_wps_handle_peersta_linkdown(struct net_device * ndev,u16 inst,const u8 * peer_mac)20573 wl_wps_handle_peersta_linkdown(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20574 {
20575 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20576 unsigned long flags;
20577 u16 cur_state;
20578 s32 ret = BCME_OK;
20579 bool wps_done = false;
20580
20581 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20582 cur_state = cfg->wps_session[inst].state;
20583
20584 if (!peer_mac) {
20585 WL_ERR(("Invalid arg\n"));
20586 ret = BCME_ERROR;
20587 goto exit;
20588 }
20589
20590 /* AP/GO can have multiple clients. so validate peer_mac addr
20591 * and ensure states are updated only for right peer.
20592 */
20593 if (memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20594 /* Mac addr not matching. Ignore. */
20595 WL_DBG(("[%s][WPS] No active WPS session"
20596 "for the peer:" MACDBG "\n", ndev->name, MAC2STRDBG(peer_mac)));
20597 ret = BCME_OK;
20598 goto exit;
20599 }
20600 if (cur_state == WPS_STATE_REAUTH_WAIT) {
20601 WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
20602 " Peer: " MACDBG "\n",
20603 ndev->name, MAC2STRDBG(peer_mac)));
20604 #ifdef NOT_YET
20605 /* Link down during REAUTH state is expected. However,
20606 * if this is send up, hostapd statemachine issues a
20607 * deauth down and that may pre-empt WPS reauth state
20608 * at GC.
20609 */
20610 WL_INFORM_MEM(("[%s][WPS] REAUTH link down. Ignore."
20611 " for client:" MACDBG "\n",
20612 ndev->name, MAC2STRDBG(peer_mac)));
20613 ret = BCME_UNSUPPORTED;
20614 #endif
20615 } else if (cur_state == WPS_STATE_STARTED) {
20616 /* Link down before reaching REAUTH_WAIT state. WPS
20617 * session ended.
20618 */
20619 cfg->wps_session[inst].state = WPS_STATE_DONE;
20620 WL_INFORM_MEM(("[%s][WPS] link down after wps start"
20621 " client:" MACDBG "\n",
20622 ndev->name, MAC2STRDBG(peer_mac)));
20623 wps_done = true;
20624 /* since we have freed lock above, return from here */
20625 ret = BCME_OK;
20626 } else {
20627 WL_ERR(("[%s][WPS] Unsupported state:%d",
20628 ndev->name, cur_state));
20629 ret = BCME_ERROR;
20630 }
20631 exit:
20632 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20633 if (wps_done) {
20634 wl_wps_session_del(ndev);
20635 }
20636 return ret;
20637 }
20638
20639 static s32
wl_wps_handle_sta_linkup(struct net_device * ndev,u16 inst)20640 wl_wps_handle_sta_linkup(struct net_device *ndev, u16 inst)
20641 {
20642 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20643 unsigned long flags;
20644 u16 cur_state;
20645 s32 ret = BCME_OK;
20646 bool wps_done = false;
20647
20648 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20649 cur_state = cfg->wps_session[inst].state;
20650 if (cur_state == WPS_STATE_REAUTH_WAIT) {
20651 /* WPS session succeeded. del session. */
20652 cfg->wps_session[inst].state = WPS_STATE_DONE;
20653 wps_done = true;
20654 WL_INFORM_MEM(("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev->name));
20655 ret = BCME_OK;
20656 } else {
20657 WL_ERR(("[%s][WPS] unexpected link up in state:%d \n",
20658 ndev->name, cur_state));
20659 ret = BCME_ERROR;
20660 }
20661 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20662 if (wps_done) {
20663 wl_wps_session_del(ndev);
20664 }
20665 return ret;
20666 }
20667
20668 static s32
wl_wps_handle_peersta_linkup(struct net_device * ndev,u16 inst,const u8 * peer_mac)20669 wl_wps_handle_peersta_linkup(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20670 {
20671 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20672 unsigned long flags;
20673 u16 cur_state;
20674 s32 ret = BCME_OK;
20675
20676 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20677 cur_state = cfg->wps_session[inst].state;
20678
20679 /* For AP case, check whether call came for right peer */
20680 if (!peer_mac ||
20681 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20682 WL_ERR(("[WPS] macaddr mismatch\n"));
20683 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20684 /* Mac addr not matching. Ignore. */
20685 return BCME_ERROR;
20686 }
20687
20688 if (cur_state == WPS_STATE_REAUTH_WAIT) {
20689 WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev->name));
20690 ret = BCME_OK;
20691 } else {
20692 WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
20693 ndev->name, cur_state));
20694 ret = BCME_ERROR;
20695 }
20696
20697 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20698
20699 return ret;
20700 }
20701
20702 static s32
wl_wps_handle_authorize(struct net_device * ndev,u16 inst,const u8 * peer_mac)20703 wl_wps_handle_authorize(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20704 {
20705 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20706 unsigned long flags;
20707 u16 cur_state;
20708 bool wps_done = false;
20709 s32 ret = BCME_OK;
20710
20711 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20712 cur_state = cfg->wps_session[inst].state;
20713
20714 /* For AP case, check whether call came for right peer */
20715 if (!peer_mac ||
20716 memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20717 WL_ERR(("[WPS] macaddr mismatch\n"));
20718 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20719 /* Mac addr not matching. Ignore. */
20720 return BCME_ERROR;
20721 }
20722
20723 if (cur_state == WPS_STATE_REAUTH_WAIT) {
20724 /* WPS session succeeded. del session. */
20725 cfg->wps_session[inst].state = WPS_STATE_DONE;
20726 wps_done = true;
20727 WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev->name));
20728 ret = BCME_OK;
20729 } else {
20730 WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
20731 ndev->name, cur_state));
20732 ret = BCME_ERROR;
20733 }
20734
20735 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20736 if (wps_done) {
20737 wl_wps_session_del(ndev);
20738 }
20739 return ret;
20740 }
20741
20742 static s32
wl_wps_handle_reauth(struct net_device * ndev,u16 inst,const u8 * peer_mac)20743 wl_wps_handle_reauth(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20744 {
20745 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20746 unsigned long flags;
20747 u16 cur_state;
20748 u16 mode;
20749 s32 ret = BCME_OK;
20750
20751 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20752 cur_state = cfg->wps_session[inst].state;
20753 mode = cfg->wps_session[inst].mode;
20754
20755 if (((mode == WL_MODE_BSS) && (cur_state == WPS_STATE_STARTED)) ||
20756 ((mode == WL_MODE_AP) && (cur_state == WPS_STATE_M8_SENT))) {
20757 /* Move to reauth wait */
20758 cfg->wps_session[inst].state = WPS_STATE_REAUTH_WAIT;
20759 /* Use ndev to find the wps instance which fired the timer */
20760 timer_set_private(&cfg->wps_session[inst].timer, ndev);
20761 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20762 mod_timer(&cfg->wps_session[inst].timer,
20763 jiffies + msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT));
20764 WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG "\n",
20765 ndev->name, mode, MAC2STRDBG(peer_mac)));
20766 return BCME_OK;
20767 } else {
20768 /* 802.1x cases */
20769 WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev->name));
20770 }
20771 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20772 return ret;
20773 }
20774
20775 static s32
wl_wps_handle_disconnect(struct net_device * ndev,u16 inst,const u8 * peer_mac)20776 wl_wps_handle_disconnect(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20777 {
20778 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20779 unsigned long flags;
20780 u16 cur_state;
20781 s32 ret = BCME_OK;
20782
20783 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20784 cur_state = cfg->wps_session[inst].state;
20785 /* If Disconnect command comes from user space for STA/GC,
20786 * respond with event without waiting for event from fw as
20787 * it would be dropped by the WPS_SYNC code.
20788 */
20789 if (cur_state == WPS_STATE_REAUTH_WAIT) {
20790 if (ETHER_ISBCAST(peer_mac)) {
20791 WL_INFORM_MEM(("[WPS] Bcast peer. Do nothing.\n"));
20792 } else {
20793 /* Notify link down */
20794 CFG80211_DISCONNECTED(ndev,
20795 WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
20796 true, GFP_ATOMIC);
20797 WL_INFORM_MEM(("[WPS] Disconnect event notified\n"));
20798 }
20799 } else {
20800 WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
20801 ndev->name, cur_state));
20802 ret = BCME_UNSUPPORTED;
20803 }
20804 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20805 return ret;
20806 }
20807
20808 static s32
wl_wps_handle_disconnect_client(struct net_device * ndev,u16 inst,const u8 * peer_mac)20809 wl_wps_handle_disconnect_client(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20810 {
20811 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20812 unsigned long flags;
20813 u16 cur_state;
20814 s32 ret = BCME_OK;
20815 bool wps_done = false;
20816
20817 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20818 cur_state = cfg->wps_session[inst].state;
20819 /* For GO/AP, ignore disconnect client during reauth state */
20820 if (cur_state == WPS_STATE_REAUTH_WAIT) {
20821 if (ETHER_ISBCAST(peer_mac)) {
20822 /* If there is broadcast deauth, then mark wps session as ended */
20823 cfg->wps_session[inst].state = WPS_STATE_DONE;
20824 wps_done = true;
20825 WL_INFORM_MEM(("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev->name));
20826 ret = BCME_OK;
20827 goto exit;
20828 } else if (!(memcmp(cfg->wps_session[inst].peer_mac,
20829 peer_mac, ETH_ALEN))) {
20830 WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev->name));
20831 ret = BCME_UNSUPPORTED;
20832 }
20833 }
20834
20835 exit:
20836 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20837 if (wps_done) {
20838 wl_wps_session_del(ndev);
20839 }
20840 return ret;
20841 }
20842
20843 static s32
wl_wps_handle_connect_fail(struct net_device * ndev,u16 inst)20844 wl_wps_handle_connect_fail(struct net_device *ndev, u16 inst)
20845 {
20846 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20847 unsigned long flags;
20848 u16 cur_state;
20849 bool wps_done = false;
20850
20851 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20852 cur_state = cfg->wps_session[inst].state;
20853 if (cur_state == WPS_STATE_REAUTH_WAIT) {
20854 cfg->wps_session[inst].state = WPS_STATE_DONE;
20855 wps_done = true;
20856 WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n",
20857 ndev->name));
20858 } else {
20859 WL_ERR(("[%s][WPS] Connect fail. state:%d\n",
20860 ndev->name, cur_state));
20861 }
20862 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20863 if (wps_done) {
20864 wl_wps_session_del(ndev);
20865 }
20866 return BCME_OK;
20867 }
20868
20869 static s32
wl_wps_handle_m8_sent(struct net_device * ndev,u16 inst,const u8 * peer_mac)20870 wl_wps_handle_m8_sent(struct net_device *ndev, u16 inst, const u8 *peer_mac)
20871 {
20872 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20873 unsigned long flags;
20874 u16 cur_state;
20875 s32 ret = BCME_OK;
20876
20877 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20878 cur_state = cfg->wps_session[inst].state;
20879
20880 if (cur_state == WPS_STATE_STARTED) {
20881 /* Move to M8 sent state */
20882 cfg->wps_session[inst].state = WPS_STATE_M8_SENT;
20883 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20884 return BCME_OK;
20885 } else {
20886 /* 802.1x cases */
20887 WL_DBG(("[%s][WPS] Not valid state to send M8\n", ndev->name));
20888 }
20889 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20890 return ret;
20891 }
20892
20893 s32
wl_wps_session_update(struct net_device * ndev,u16 state,const u8 * peer_mac)20894 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac)
20895 {
20896 s32 inst;
20897 u16 mode;
20898 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
20899 s32 ret = BCME_ERROR;
20900 unsigned long flags;
20901
20902 WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
20903 /* Get current instance for the given ndev */
20904 inst = wl_get_wps_inst_match(cfg, ndev);
20905 if (inst == BCME_ERROR) {
20906 /* No active WPS session. Do Nothing. */
20907 WL_DBG(("[%s][WPS] No matching instance.\n", ndev->name));
20908 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20909 return BCME_NOTFOUND;
20910 }
20911 mode = cfg->wps_session[inst].mode;
20912 WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
20913
20914 WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG "\n",
20915 ndev->name, state, mode, MAC2STRDBG(peer_mac)));
20916
20917 switch (state) {
20918 case WPS_STATE_M8_RECVD:
20919 {
20920 /* Occasionally, due to race condition between ctrl
20921 * and data path, deauth ind is recvd before EAP-FAIL.
20922 * Ignore deauth ind before EAP-FAIL
20923 * So move to REAUTH WAIT on receiving M8 on GC and
20924 * ignore deauth ind before EAP-FAIL till 'x' timeout.
20925 * Kickoff a timer to monitor reauth status.
20926 */
20927 if (mode == WL_MODE_BSS) {
20928 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
20929 } else {
20930 /* Nothing to be done for AP/GO mode */
20931 ret = BCME_OK;
20932 }
20933 break;
20934 }
20935 case WPS_STATE_M8_SENT:
20936 {
20937 /* Mantain the M8 sent state to verify
20938 * EAP-FAIL sent is valid
20939 */
20940 if (mode == WL_MODE_AP) {
20941 ret = wl_wps_handle_m8_sent(ndev, inst, peer_mac);
20942 } else {
20943 /* Nothing to be done for STA/GC mode */
20944 ret = BCME_OK;
20945 }
20946 break;
20947 }
20948 case WPS_STATE_EAP_FAIL:
20949 {
20950 /* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
20951 * Kickoff a timer to monitor reauth status
20952 */
20953 if (mode == WL_MODE_AP) {
20954 ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
20955 } else {
20956 /* Nothing to be done for STA/GC mode */
20957 ret = BCME_OK;
20958 }
20959 break;
20960 }
20961 case WPS_STATE_LINKDOWN:
20962 {
20963 if (mode == WL_MODE_BSS) {
20964 ret = wl_wps_handle_sta_linkdown(ndev, inst);
20965 } else if (mode == WL_MODE_AP) {
20966 /* Take action only for matching peer mac */
20967 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20968 ret = wl_wps_handle_peersta_linkdown(ndev, inst, peer_mac);
20969 }
20970 }
20971 break;
20972 }
20973 case WPS_STATE_LINKUP:
20974 {
20975 if (mode == WL_MODE_BSS) {
20976 wl_wps_handle_sta_linkup(ndev, inst);
20977 } else if (mode == WL_MODE_AP) {
20978 /* Take action only for matching peer mac */
20979 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
20980 wl_wps_handle_peersta_linkup(ndev, inst, peer_mac);
20981 }
20982 }
20983 break;
20984 }
20985 case WPS_STATE_DISCONNECT_CLIENT:
20986 {
20987 /* Disconnect STA/GC command from user space */
20988 if (mode == WL_MODE_AP) {
20989 ret = wl_wps_handle_disconnect_client(ndev, inst, peer_mac);
20990 } else {
20991 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
20992 }
20993 break;
20994 }
20995 case WPS_STATE_DISCONNECT:
20996 {
20997 /* Disconnect command on STA/GC interface */
20998 if (mode == WL_MODE_BSS) {
20999 ret = wl_wps_handle_disconnect(ndev, inst, peer_mac);
21000 }
21001 break;
21002 }
21003 case WPS_STATE_CONNECT_FAIL:
21004 {
21005 if (mode == WL_MODE_BSS) {
21006 ret = wl_wps_handle_connect_fail(ndev, inst);
21007 } else {
21008 WL_ERR(("[WPS] Unsupported mode %d\n", mode));
21009 }
21010 break;
21011 }
21012 case WPS_STATE_AUTHORIZE:
21013 {
21014 if (mode == WL_MODE_AP) {
21015 /* Take action only for matching peer mac */
21016 if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
21017 wl_wps_handle_authorize(ndev, inst, peer_mac);
21018 } else {
21019 WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
21020 }
21021 }
21022 break;
21023 }
21024
21025 default:
21026 WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state, mode));
21027 ret = BCME_ERROR;
21028 }
21029
21030 return ret;
21031 }
21032
21033 #define EAP_EXP_ATTRIB_DATA_OFFSET 14
21034 void
wl_handle_wps_states(struct net_device * ndev,u8 * pkt,u16 len,bool direction)21035 wl_handle_wps_states(struct net_device *ndev, u8 *pkt, u16 len, bool direction)
21036 {
21037 eapol_header_t *eapol_hdr;
21038 bool tx_packet = direction;
21039 u16 eapol_type;
21040 u16 mode;
21041 u8 *peer_mac;
21042
21043 if (!ndev || !pkt) {
21044 WL_ERR(("[WPS] Invalid arg\n"));
21045 return;
21046 }
21047
21048 if (len < (ETHER_HDR_LEN + EAPOL_HDR_LEN)) {
21049 WL_ERR(("[WPS] Invalid len\n"));
21050 return;
21051 }
21052
21053 eapol_hdr = (eapol_header_t *)pkt;
21054 eapol_type = eapol_hdr->type;
21055
21056 peer_mac = tx_packet ? eapol_hdr->eth.ether_dhost :
21057 eapol_hdr->eth.ether_shost;
21058 /*
21059 * The implementation assumes only one WPS session would be active
21060 * per interface at a time. Even for hostap, the wps_pin session
21061 * is limited to one enrollee/client at a time. A session is marked
21062 * started on WSC_START and gets cleared from below contexts
21063 * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
21064 * b) Link up following EAP-FAIL. (success case)
21065 * c) Link up timeout after EAP-FAIL. (Fail case)
21066 */
21067
21068 if (eapol_type == EAP_PACKET) {
21069 wl_eap_header_t *eap;
21070
21071 if (len > sizeof(*eap)) {
21072 eap = (wl_eap_header_t *)(pkt + ETHER_HDR_LEN + EAPOL_HDR_LEN);
21073 if (eap->type == EAP_EXPANDED_TYPE) {
21074 wl_eap_exp_t *exp = (wl_eap_exp_t *)eap->data;
21075 if (eap->length > EAP_EXP_HDR_MIN_LENGTH) {
21076 /* opcode is at fixed offset */
21077 u8 opcode = exp->opcode;
21078 u16 eap_len = ntoh16(eap->length);
21079
21080 WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
21081 ndev->name, opcode, eap_len));
21082 if (opcode == EAP_WSC_MSG) {
21083 const u8 *msg;
21084 const u8* parse_buf = exp->data;
21085 /* Check if recvd pkt is fragmented */
21086 if ((!tx_packet) &&
21087 (exp->flags &
21088 EAP_EXP_FLAGS_FRAGMENTED_DATA)) {
21089 if ((eap_len - EAP_EXP_ATTRIB_DATA_OFFSET)
21090 > 2) {
21091 parse_buf +=
21092 EAP_EXP_FRAGMENT_LEN_OFFSET;
21093 eap_len -=
21094 EAP_EXP_FRAGMENT_LEN_OFFSET;
21095 WL_DBG(("Rcvd EAP"
21096 " fragmented pkt\n"));
21097 } else {
21098 /* If recvd pkt is fragmented
21099 * and does not have
21100 * length field drop the packet.
21101 */
21102 return;
21103 }
21104 }
21105
21106 msg = wl_find_attribute(parse_buf,
21107 (eap_len - EAP_EXP_ATTRIB_DATA_OFFSET),
21108 EAP_ATTRIB_MSGTYPE);
21109 if (unlikely(!msg)) {
21110 WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
21111 } else if ((*msg == EAP_WSC_MSG_M8) &&
21112 !tx_packet) {
21113 /* In certain cases M2 can also carry
21114 * credential. So add check for
21115 * cred in M8/M2 and start reauth timer.
21116 */
21117 WL_INFORM_MEM(("[%s][WPS] M8\n",
21118 ndev->name));
21119 wl_wps_session_update(ndev,
21120 WPS_STATE_M8_RECVD, peer_mac);
21121 } else if ((*msg == EAP_WSC_MSG_M8) &&
21122 tx_packet) {
21123 WL_INFORM_MEM(("[%s][WPS] M8 Sent\n",
21124 ndev->name));
21125 wl_wps_session_update(ndev,
21126 WPS_STATE_M8_SENT, peer_mac);
21127 } else {
21128 WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n",
21129 ndev->name, *msg));
21130 }
21131 } else if (opcode == EAP_WSC_START) {
21132 /* WSC session started. WSC_START - Tx from GO/AP.
21133 * Session will be deleted on successful link up or
21134 * on failure (deauth context)
21135 */
21136 mode = tx_packet ? WL_MODE_AP : WL_MODE_BSS;
21137 wl_wps_session_add(ndev, mode, peer_mac);
21138 WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
21139 ndev->name, mode));
21140 } else if (opcode == EAP_WSC_DONE) {
21141 /* WSC session done. TX on STA/GC. RX on GO/AP
21142 * On devices where config file save fails, it may
21143 * return WPS_NAK with config_error:0. But the
21144 * connection would still proceed. Hence don't let
21145 * state machine depend on WSC DONE.
21146 */
21147 WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev->name));
21148 }
21149 }
21150 }
21151
21152 if (eap->code == EAP_CODE_FAILURE) {
21153 /* EAP_FAIL */
21154 WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev->name));
21155 wl_wps_session_update(ndev,
21156 WPS_STATE_EAP_FAIL, peer_mac);
21157 }
21158 }
21159 }
21160 }
21161 #endif /* WL_WPS_SYNC */
21162
21163 s32
wl_cfg80211_sup_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * event,void * data)21164 wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21165 const wl_event_msg_t *event, void *data)
21166 {
21167 int err = BCME_OK;
21168 u32 status = ntoh32(event->status);
21169 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
21170 u32 reason = ntoh32(event->reason);
21171
21172 if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
21173 /* Join attempt via non-cfg80211 interface.
21174 * Don't send resultant events to cfg80211
21175 * layer
21176 */
21177 WL_INFORM_MEM(("Event received in non-cfg80211"
21178 " connect state. Ignore\n"));
21179 return BCME_OK;
21180 }
21181
21182 if ((status == WLC_SUP_KEYED || status == WLC_SUP_KEYXCHANGE_WAIT_G1) &&
21183 reason == WLC_E_SUP_OTHER) {
21184 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
21185 /* NL80211_CMD_PORT_AUTHORIZED supported above >= 4.15 */
21186 cfg80211_port_authorized(ndev, (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID),
21187 GFP_KERNEL);
21188 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
21189 #elif ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT))
21190 err = wl_cfgvendor_send_async_event(bcmcfg_to_wiphy(cfg), ndev,
21191 BRCM_VENDOR_EVENT_PORT_AUTHORIZED, NULL, 0);
21192 WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
21193 #else
21194 /* not supported in kernel <= 3,14,0 */
21195 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */
21196 /* Post SCB authorize actions */
21197 wl_cfg80211_post_scb_auth(cfg, ndev);
21198 } else if (status < WLC_SUP_KEYXCHANGE_WAIT_G1 && (reason != WLC_E_SUP_OTHER &&
21199 reason != WLC_E_SUP_PTK_UPDATE)) {
21200 /* if any failure seen while 4way HS, should send NL80211_CMD_DISCONNECT */
21201 WL_ERR(("4way HS error. status:%d, reason:%d\n", status, reason));
21202 CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
21203 }
21204
21205 return err;
21206 }
21207
21208 #ifdef WL_BCNRECV
21209 static s32
wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21210 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21211 const wl_event_msg_t *e, void *data)
21212 {
21213 s32 status = ntoh32(e->status);
21214 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
21215 /* Abort fakeapscan, when Roam is in progress */
21216 if (status == WLC_E_STATUS_RXBCN_ABORT) {
21217 wl_android_bcnrecv_stop(ndev, WL_BCNRECV_ROAMABORT);
21218 } else {
21219 WL_ERR(("UNKNOWN STATUS. status:%d\n", status));
21220 }
21221 return BCME_OK;
21222 }
21223 #endif /* WL_BCNRECV */
21224
21225 #ifdef WL_MBO
21226 static s32
wl_mbo_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21227 wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21228 const wl_event_msg_t *e, void *data)
21229 {
21230 s32 err = 0;
21231 wl_event_mbo_t *mbo_evt = (wl_event_mbo_t *)data;
21232 wl_event_mbo_cell_nw_switch_t *cell_sw_evt = NULL;
21233 wl_btm_event_type_data_t *evt_data = NULL;
21234
21235 WL_INFORM(("MBO: Evt %u\n", mbo_evt->type));
21236
21237 if (mbo_evt->type == WL_MBO_E_CELLULAR_NW_SWITCH) {
21238 cell_sw_evt = (wl_event_mbo_cell_nw_switch_t *)mbo_evt->data;
21239 BCM_REFERENCE(cell_sw_evt);
21240 SUPP_EVENT(("CTRL-EVENT-CELLULAR-SWITCH", "reason %d cur_assoc_time_left %u "
21241 "reassoc_delay %u\n", cell_sw_evt->reason,
21242 cell_sw_evt->assoc_time_remain, cell_sw_evt->reassoc_delay));
21243 } else if (mbo_evt->type == WL_MBO_E_BTM_RCVD) {
21244 evt_data = (wl_btm_event_type_data_t *)mbo_evt->data;
21245 if (evt_data->version != WL_BTM_EVENT_DATA_VER_1) {
21246 WL_ERR(("version mismatch. rcvd %u expected %u\n",
21247 evt_data->version, WL_BTM_EVENT_DATA_VER_1));
21248 return -1;
21249 }
21250 SUPP_EVENT(("CTRL-EVENT-BRCM-BTM-REQ-RCVD", "reason=%u\n",
21251 evt_data->transition_reason));
21252 } else {
21253 WL_INFORM(("UNKNOWN EVENT. type:%u\n", mbo_evt->type));
21254 }
21255 return err;
21256 }
21257 #endif /* WL_MBO */
21258
21259 #ifdef WL_CAC_TS
21260 static s32
wl_cfg80211_cac_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21261 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21262 const wl_event_msg_t *e, void *data)
21263 {
21264 u32 event = ntoh32(e->event_type);
21265 s32 status = ntoh32(e->status);
21266 s32 reason = ntoh32(e->reason);
21267
21268 BCM_REFERENCE(reason);
21269
21270 if (event == WLC_E_ADDTS_IND) {
21271 /* The supp log format of adding ts_delay in success case needs to be maintained */
21272 if (status == WLC_E_STATUS_SUCCESS) {
21273 uint *ts_delay = (uint *)data;
21274 BCM_REFERENCE(ts_delay);
21275 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d ts_delay=%u\n",
21276 status, reason, *ts_delay));
21277 } else {
21278 SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d\n",
21279 status, reason));
21280 }
21281 } else if (event == WLC_E_DELTS_IND) {
21282 SUPP_EVENT(("CTRL-EVENT-CAC-DELTS", "status=%d reason=%d\n", status, reason));
21283 }
21284
21285 return BCME_OK;
21286 }
21287 #endif /* WL_CAC_TS */
21288
21289 #if defined(WL_MBO) || defined(WL_OCE)
21290 static s32
wl_bssid_prune_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21291 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21292 const wl_event_msg_t *e, void *data)
21293 {
21294 s32 err = 0;
21295 uint reason = 0;
21296 wl_bssid_pruned_evt_info_t *evt_info = (wl_bssid_pruned_evt_info_t *)data;
21297
21298 if (evt_info->version == WL_BSSID_PRUNE_EVT_VER_1) {
21299 if (evt_info->reason == WLC_E_PRUNE_ASSOC_RETRY_DELAY) {
21300 /* MBO assoc retry delay */
21301 reason = WIFI_PRUNE_ASSOC_RETRY_DELAY;
21302 SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
21303 " reason=%u timeout_val=%u(ms)\n", evt_info->SSID,
21304 ETHER_TO_MACF(evt_info->BSSID), reason, evt_info->time_remaining));
21305 } else if (evt_info->reason == WLC_E_PRUNE_RSSI_ASSOC_REJ) {
21306 /* OCE RSSI-based assoc rejection */
21307 reason = WIFI_PRUNE_RSSI_ASSOC_REJ;
21308 SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
21309 " reason=%u timeout_val=%u(ms) rssi_threshold=%d(dBm)\n",
21310 evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID),
21311 reason, evt_info->time_remaining, evt_info->rssi_threshold));
21312 } else {
21313 /* Invalid other than the assoc retry delay/RSSI assoc rejection
21314 * in the current handler
21315 */
21316 BCM_REFERENCE(reason);
21317 WL_INFORM(("INVALID. reason:%u\n", evt_info->reason));
21318 }
21319 } else {
21320 WL_INFORM(("version mismatch. rcvd %u expected %u\n", evt_info->version,
21321 WL_BSSID_PRUNE_EVT_VER_1));
21322 }
21323 return err;
21324 }
21325 #endif /* WL_MBO || WL_OCE */
21326 #ifdef RTT_SUPPORT
21327 static s32
wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21328 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21329 const wl_event_msg_t *e, void *data)
21330 {
21331 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
21332 wl_event_msg_t event;
21333
21334 (void)memcpy_s(&event, sizeof(wl_event_msg_t),
21335 e, sizeof(wl_event_msg_t));
21336 return dhd_rtt_event_handler(dhdp, &event, data);
21337 }
21338 #endif /* RTT_SUPPORT */
21339
21340 void
wl_print_verinfo(struct bcm_cfg80211 * cfg)21341 wl_print_verinfo(struct bcm_cfg80211 *cfg)
21342 {
21343 char *ver_ptr;
21344 uint32 alloc_len = MOD_PARAM_INFOLEN;
21345
21346 if (!cfg) {
21347 WL_ERR(("cfg is NULL\n"));
21348 return;
21349 }
21350
21351 ver_ptr = (char *)MALLOCZ(cfg->osh, alloc_len);
21352 if (!ver_ptr) {
21353 WL_ERR(("Failed to alloc ver_ptr\n"));
21354 return;
21355 }
21356
21357 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
21358 TRUE, &ver_ptr, alloc_len)) {
21359 WL_ERR(("DHD Version: %s\n", ver_ptr));
21360 }
21361
21362 if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
21363 FALSE, &ver_ptr, alloc_len)) {
21364 WL_ERR(("F/W Version: %s\n", ver_ptr));
21365 }
21366
21367 MFREE(cfg->osh, ver_ptr, alloc_len);
21368 }
21369
21370 /* Get the concurrency mode */
wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 * cfg)21371 int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg)
21372 {
21373 struct net_info *iter, *next;
21374 uint cmode = CONCURRENCY_MODE_NONE;
21375 u32 connected_cnt = 0;
21376 u32 pre_channel = 0, channel = 0;
21377 u32 pre_band = 0;
21378 u32 chanspec = 0;
21379 u32 band = 0;
21380
21381 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
21382 if (connected_cnt <= 1) {
21383 return cmode;
21384 }
21385 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
21386 for_each_ndev(cfg, iter, next) {
21387 if (iter->ndev) {
21388 if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
21389 if (wldev_iovar_getint(iter->ndev, "chanspec",
21390 (s32 *)&chanspec) == BCME_OK) {
21391 channel = wf_chspec_ctlchan(
21392 wl_chspec_driver_to_host(chanspec));
21393 band = (channel <= CH_MAX_2G_CHANNEL) ?
21394 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
21395 }
21396 if ((!pre_channel && channel)) {
21397 pre_band = band;
21398 pre_channel = channel;
21399 } else if (pre_channel) {
21400 if ((pre_band == band) && (pre_channel == channel)) {
21401 cmode = CONCURRENCY_SCC_MODE;
21402 goto exit;
21403 } else if ((pre_band == band) && (pre_channel != channel)) {
21404 cmode = CONCURRENCY_VSDB_MODE;
21405 goto exit;
21406 } else if (pre_band != band) {
21407 cmode = CONCURRENCY_RSDB_MODE;
21408 goto exit;
21409 }
21410 }
21411 }
21412 }
21413 }
21414 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && \
21415 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
21416 _Pragma("GCC diagnostic pop")
21417 #endif
21418 exit:
21419 return cmode;
21420 }
21421 #ifdef WL_CHAN_UTIL
21422 static s32
wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)21423 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
21424 const wl_event_msg_t *e, void *data)
21425 {
21426 s32 err = BCME_OK;
21427 struct sk_buff *skb = NULL;
21428 s32 status = ntoh32(e->status);
21429 u8 chan_use_percentage = 0;
21430 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
21431 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
21432 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
21433 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
21434 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
21435 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21436 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
21437 uint len;
21438 gfp_t kflags;
21439 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
21440
21441 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21442 len = CU_ATTR_HDR_LEN + sizeof(u8);
21443 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
21444 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
21445
21446 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
21447 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
21448 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), len,
21449 BRCM_VENDOR_EVENT_CU, kflags);
21450 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21451 skb = cfg80211_vendor_event_alloc(wiphy, len, BRCM_VENDOR_EVENT_CU, kflags);
21452 #else
21453 /* No support exist */
21454 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
21455 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
21456 if (!skb) {
21457 WL_ERR(("skb alloc failed"));
21458 return -ENOMEM;
21459 }
21460
21461 if ((status == WLC_E_STATUS_SUCCESS) && data) {
21462 wl_bssload_t *bssload_report = (wl_bssload_t *)data;
21463 chan_use_percentage = (bssload_report->chan_util * 100) / 255;
21464 WL_DBG(("ChannelUtilization=%hhu\n", chan_use_percentage));
21465 err = nla_put_u8(skb, CU_ATTR_PERCENTAGE, chan_use_percentage);
21466 if (err < 0) {
21467 WL_ERR(("Failed to put CU_ATTR_PERCENTAGE, err:%d\n", err));
21468 }
21469 }
21470
21471 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21472 cfg80211_vendor_event(skb, kflags);
21473 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
21474
21475 return err;
21476 }
21477
21478 #define WL_CHAN_UTIL_DEFAULT_INTERVAL 3000
21479 #define WL_CHAN_UTIL_THRESH_MIN 15
21480 #define WL_CHAN_UTIL_THRESH_INTERVAL 10
21481 #ifndef CUSTOM_CU_INTERVAL
21482 #define CUSTOM_CU_INTERVAL WL_CHAN_UTIL_DEFAULT_INTERVAL
21483 #endif /* CUSTOM_CU_INTERVAL */
21484
21485 static s32
wl_cfg80211_start_bssload_report(struct net_device * ndev)21486 wl_cfg80211_start_bssload_report(struct net_device *ndev)
21487 {
21488 s32 err = BCME_OK;
21489 wl_bssload_cfg_t blcfg;
21490 u8 i;
21491 struct bcm_cfg80211 *cfg;
21492
21493 if (!ndev) {
21494 return -ENODEV;
21495 }
21496
21497 cfg = wl_get_cfg(ndev);
21498 if (!cfg) {
21499 return -ENODEV;
21500 }
21501
21502 /* Typecasting to void as the buffer size is same as the memset size */
21503 (void)memset_s(&blcfg, sizeof(wl_bssload_cfg_t), 0, sizeof(wl_bssload_cfg_t));
21504 /* Set default report interval 3 sec and 8 threshhold levels between 15 to 85% */
21505 blcfg.rate_limit_msec = CUSTOM_CU_INTERVAL;
21506 blcfg.num_util_levels = MAX_BSSLOAD_LEVELS;
21507 for (i = 0; i < MAX_BSSLOAD_LEVELS; i++) {
21508 blcfg.util_levels[i] = (((WL_CHAN_UTIL_THRESH_MIN +
21509 (i * WL_CHAN_UTIL_THRESH_INTERVAL)) * 255) / 100);
21510 }
21511
21512 err = wldev_iovar_setbuf(ndev, "bssload_report_event", &blcfg,
21513 sizeof(wl_bssload_cfg_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
21514 if (unlikely(err)) {
21515 WL_ERR(("Set event_msgs error (%d)\n", err));
21516 }
21517
21518 return err;
21519 }
21520 #endif /* WL_CHAN_UTIL */
21521
21522 s32
wl_cfg80211_config_suspend_events(struct net_device * ndev,bool enable)21523 wl_cfg80211_config_suspend_events(struct net_device *ndev, bool enable)
21524 {
21525 s32 err = 0;
21526 struct bcm_cfg80211 *cfg;
21527 s8 event_buf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE] = {0};
21528 eventmsgs_ext_t *eventmask_msg = NULL;
21529 /* Room for "event_msgs_ext" + '\0' + bitvec */
21530 char iovbuf[WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE + 16];
21531 s32 msglen = WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE;
21532
21533 if (!ndev) {
21534 return -ENODEV;
21535 }
21536
21537 cfg = wl_get_cfg(ndev);
21538 if (!cfg) {
21539 return -ENODEV;
21540 }
21541
21542 mutex_lock(&cfg->event_sync);
21543
21544 eventmask_msg = (eventmsgs_ext_t *)event_buf;
21545 eventmask_msg->ver = EVENTMSGS_VER;
21546 eventmask_msg->command = EVENTMSGS_NONE;
21547 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
21548 eventmask_msg->maxgetsize = WL_EVENTING_MASK_EXT_LEN;
21549
21550 /* Read event_msgs mask */
21551 err = wldev_iovar_getbuf(ndev, "event_msgs_ext",
21552 eventmask_msg, EVENTMSGS_EXT_STRUCT_SIZE,
21553 iovbuf,
21554 sizeof(iovbuf),
21555 NULL);
21556
21557 if (unlikely(err)) {
21558 WL_ERR(("Get event_msgs error (%d)\n", err));
21559 goto eventmsg_out;
21560 }
21561
21562 bcopy(iovbuf, eventmask_msg, msglen);
21563
21564 /* Add set/clear of event mask under feature specific flags */
21565 if (enable) {
21566 WL_DBG(("%s: Enabling events on resume\n", __FUNCTION__));
21567 #ifdef WL_CHAN_UTIL
21568 setbit(eventmask_msg->mask, WLC_E_BSS_LOAD);
21569 #endif /* WL_CHAN_UTIL */
21570 } else {
21571 WL_DBG(("%s: Disabling events before suspend\n", __FUNCTION__));
21572 #ifdef WL_CHAN_UTIL
21573 clrbit(eventmask_msg->mask, WLC_E_BSS_LOAD);
21574 #endif /* WL_CHAN_UTIL */
21575 }
21576
21577 /* Write updated Event mask */
21578 eventmask_msg->ver = EVENTMSGS_VER;
21579 eventmask_msg->command = EVENTMSGS_SET_MASK;
21580 eventmask_msg->len = WL_EVENTING_MASK_EXT_LEN;
21581
21582 err = wldev_iovar_setbuf(ndev, "event_msgs_ext", eventmask_msg,
21583 WL_EVENTING_MASK_EXT_LEN + EVENTMSGS_EXT_STRUCT_SIZE,
21584 iovbuf, sizeof(iovbuf), NULL);
21585
21586 if (unlikely(err)) {
21587 WL_ERR(("Set event_msgs error (%d)\n", err));
21588 goto eventmsg_out;
21589 }
21590
21591 eventmsg_out:
21592 mutex_unlock(&cfg->event_sync);
21593 return err;
21594 }
21595
21596 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
21597 #ifdef WLFBT
21598 static int
wl_cfg80211_update_ft_ies(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_update_ft_ies_params * ftie)21599 wl_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
21600 struct cfg80211_update_ft_ies_params *ftie)
21601 {
21602 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
21603 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
21604
21605 if (!FW_SUPPORTED(dhdp, fbtoverds) && !FW_SUPPORTED(dhdp, fbt_adpt)) {
21606 WL_INFORM(("FW does not support FT roaming\n"));
21607 return BCME_UNSUPPORTED;
21608 }
21609 return BCME_OK;
21610 }
21611 #endif /* WLFBT */
21612 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) */
21613
21614 #ifdef WL_WIPSEVT
21615 int
wl_cfg80211_wips_event_ext(wl_wips_event_info_t * wips_event)21616 wl_cfg80211_wips_event_ext(wl_wips_event_info_t *wips_event)
21617 {
21618 s32 err = BCME_OK;
21619 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
21620 struct sk_buff *skb;
21621 gfp_t kflags;
21622 struct bcm_cfg80211 *cfg;
21623 struct net_device *ndev;
21624 struct wiphy *wiphy;
21625
21626 cfg = wl_cfg80211_get_bcmcfg();
21627 if (!cfg || !cfg->wdev) {
21628 WL_ERR(("WIPS evt invalid arg\n"));
21629 return err;
21630 }
21631
21632 ndev = bcmcfg_to_prmry_ndev(cfg);
21633 wiphy = bcmcfg_to_wiphy(cfg);
21634
21635 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
21636 skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
21637 BRCM_VENDOR_WIPS_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_WIPS, kflags);
21638
21639 if (!skb) {
21640 WL_ERR(("skb alloc failed"));
21641 return BCME_NOMEM;
21642 }
21643
21644 err = nla_put_u16(skb, WIPS_ATTR_DEAUTH_CNT, wips_event->misdeauth);
21645 if (unlikely(err)) {
21646 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_CNT failed\n"));
21647 goto fail;
21648 }
21649 err = nla_put(skb, WIPS_ATTR_DEAUTH_BSSID, ETHER_ADDR_LEN, &wips_event->bssid);
21650 if (unlikely(err)) {
21651 WL_ERR(("nla_put WIPS_ATTR_DEAUTH_BSSID failed\n"));
21652 goto fail;
21653 }
21654 err = nla_put_s16(skb, WIPS_ATTR_CURRENT_RSSI, wips_event->current_RSSI);
21655 if (unlikely(err)) {
21656 WL_ERR(("nla_put_u16 WIPS_ATTR_CURRENT_RSSI failed\n"));
21657 goto fail;
21658 }
21659 err = nla_put_s16(skb, WIPS_ATTR_DEAUTH_RSSI, wips_event->deauth_RSSI);
21660 if (unlikely(err)) {
21661 WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_RSSI failed\n"));
21662 goto fail;
21663 }
21664 cfg80211_vendor_event(skb, kflags);
21665
21666 return err;
21667
21668 fail:
21669 if (skb) {
21670 nlmsg_free(skb);
21671 }
21672 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
21673 return err;
21674 }
21675
21676 int
wl_cfg80211_wips_event(uint16 misdeauth,char * bssid)21677 wl_cfg80211_wips_event(uint16 misdeauth, char* bssid)
21678 {
21679 s32 err = BCME_OK;
21680 wl_wips_event_info_t wips_event;
21681
21682 wips_event.misdeauth = misdeauth;
21683 memcpy(&wips_event.bssid, bssid, ETHER_ADDR_LEN);
21684 wips_event.current_RSSI = 0;
21685 wips_event.deauth_RSSI = 0;
21686
21687 err = wl_cfg80211_wips_event_ext(&wips_event);
21688 return err;
21689 }
21690 #endif /* WL_WIPSEVT */
21691
21692 #ifdef PCIE_INB_DW
21693 #define WL_DS(x)
21694 /*
21695 * This API checks whether its okay to enter DS.
21696 * If some transaction is in progress, return true
21697 * to skip DS.
21698 */
21699 #ifndef USECS_PER_MSEC
21700 #define USECS_PER_MSEC 1000UL
21701 #endif /* USECS_PER_MSEC */
wl_cfg80211_check_in_progress(struct net_device * dev)21702 bool wl_cfg80211_check_in_progress(struct net_device *dev)
21703 {
21704 struct bcm_cfg80211 *cfg;
21705 struct net_device *pri_dev;
21706 u8 reason = WL_STATE_IDLE;
21707 u64 timeout;
21708 u64 start_time = 0;
21709
21710 cfg = wl_get_cfg(dev);
21711 pri_dev = bcmcfg_to_prmry_ndev(cfg);
21712
21713 /* check states like scan in progress, four way handshake, etc
21714 * before entering Deep Sleep.
21715 */
21716 if (wl_get_drv_status_all(cfg, SCANNING)) {
21717 WL_DS(("scan in progress\n"));
21718 reason = WL_STATE_SCANNING;
21719 start_time = GET_TS(cfg, scan_start);
21720 } else if (wl_get_drv_status_all(cfg, CONNECTING)) {
21721 WL_DS(("connect in progress\n"));
21722 reason = WL_STATE_CONNECTING;
21723 start_time = GET_TS(cfg, conn_start);
21724 } else if ((IS_STA_IFACE(ndev_to_wdev(dev))) &&
21725 wl_get_drv_status(cfg, CONNECTED, pri_dev) &&
21726 !wl_get_drv_status(cfg, AUTHORIZED, pri_dev)) {
21727 WL_DS(("connect-authorization in progress\n"));
21728 reason = WL_STATE_AUTHORIZING;
21729 start_time = GET_TS(cfg, authorize_start);
21730 }
21731
21732 if (reason) {
21733 u64 curtime = OSL_LOCALTIME_NS();
21734 if (unlikely(!start_time)) {
21735 WL_ERR_RLMT(("state got cleared for reason:%d\n", reason));
21736 return false;
21737 }
21738 /* check whether we are stuck in a state
21739 * for too long.
21740 */
21741 timeout = (start_time + (WL_DS_SKIP_THRESHOLD_USECS * USECS_PER_MSEC));
21742 if (time_after64(curtime, timeout)) {
21743 /* state hasn't changed for WL_DS_SKIP_THRESHOLD_USECS */
21744 WL_ERR(("DS skip threshold hit. reason:%d start_time:"
21745 SEC_USEC_FMT" cur_time:"SEC_USEC_FMT"\n",
21746 reason, GET_SEC_USEC(start_time), GET_SEC_USEC(curtime)));
21747 ASSERT((0));
21748 }
21749 /* return true to skip suspend */
21750 return true;
21751 }
21752
21753 return false;
21754 }
21755 #endif
21756
wl_cfg80211_is_dpp_frame(void * frame,u32 frame_len)21757 bool wl_cfg80211_is_dpp_frame(void *frame, u32 frame_len)
21758 {
21759 /* check for DPP public action frames */
21760 wl_dpp_pa_frame_t *pact_frm;
21761
21762 if (frame == NULL) {
21763 return false;
21764 }
21765 pact_frm = (wl_dpp_pa_frame_t *)frame;
21766 if (frame_len < sizeof(wl_dpp_pa_frame_t) -1) {
21767 return false;
21768 }
21769
21770 if ((pact_frm->category == WL_PUB_AF_CATEGORY) &&
21771 (pact_frm->action == WL_PUB_AF_ACTION) &&
21772 (pact_frm->oui_type == WL_PUB_AF_WFA_STYPE_DPP) &&
21773 (memcmp(pact_frm->oui, WFA_OUI, sizeof(pact_frm->oui)) == 0)) {
21774 return true;
21775 }
21776
21777 return false;
21778 }
21779
21780 const char *
get_dpp_pa_ftype(enum wl_dpp_ftype ftype)21781 get_dpp_pa_ftype(enum wl_dpp_ftype ftype)
21782 {
21783 switch (ftype) {
21784 case DPP_AUTH_REQ:
21785 return "DPP_AUTH_REQ";
21786 case DPP_AUTH_RESP:
21787 return "DPP_AUTH_RESP";
21788 case DPP_AUTH_CONF:
21789 return "DPP_AUTH_CONF";
21790 default:
21791 return "Unkown DPP frame";
21792 }
21793 }
21794
21795 #define GAS_RESP_LEN 2
21796 #define DOUBLE_TLV_BODY_OFF 4
wl_cfg80211_find_gas_subtype(u8 subtype,u16 adv_id,u8 * data,u32 len)21797 bool wl_cfg80211_find_gas_subtype(u8 subtype, u16 adv_id, u8* data, u32 len)
21798 {
21799 const bcm_tlv_t *ie = (bcm_tlv_t *)data;
21800 const u8 *frame = NULL;
21801 u16 id, flen;
21802
21803 /* Skipped first ANQP Element, if frame has anqp elemnt */
21804 ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID);
21805
21806 if (ie == NULL)
21807 return false;
21808
21809 frame = (const uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN;
21810 id = ((u16) (((frame)[1] << 8) | (frame)[0]));
21811 flen = ((u16) (((frame)[3] << 8) | (frame)[2]));
21812
21813 /* If the contents match the OUI and the type */
21814 if ((flen >= WFA_OUI_LEN + 1) &&
21815 (id == adv_id) &&
21816 !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) &&
21817 subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) {
21818 return true;
21819 }
21820
21821 return false;
21822 }
21823
wl_cfg80211_is_dpp_gas_action(void * frame,u32 frame_len)21824 bool wl_cfg80211_is_dpp_gas_action(void *frame, u32 frame_len)
21825 {
21826 wl_dpp_gas_af_t *act_frm = (wl_dpp_gas_af_t *)frame;
21827 u32 len;
21828 const bcm_tlv_t *ie = NULL;
21829
21830 if ((frame_len < (sizeof(wl_dpp_gas_af_t) - 1)) ||
21831 act_frm->category != WL_PUB_AF_CATEGORY) {
21832 return false;
21833 }
21834
21835 len = frame_len - (u32)(sizeof(wl_dpp_gas_af_t) - 1);
21836 if (act_frm->action == WL_PUB_AF_GAS_IREQ) {
21837 ie = (bcm_tlv_t *)act_frm->query_data;
21838 /* We are interested only in MNG ADV ID. Skip any other id. */
21839 ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID);
21840 } else if (act_frm->action == WL_PUB_AF_GAS_IRESP) {
21841 ie = (bcm_tlv_t *)&act_frm->query_data[WL_GAS_RESP_OFFSET];
21842 /* We are interested only in MNG ADV ID. Skip any other id. */
21843 ie = bcm_parse_tlvs(ie, len, DOT11_MNG_ADVERTISEMENT_ID);
21844 } else {
21845 return false;
21846 }
21847
21848 if (ie && (ie->len >= WL_GAS_MIN_LEN) &&
21849 (memcmp(&ie->data[WL_GAS_WFA_OFFSET], WFA_OUI, 3) == 0) &&
21850 (ie->data[WL_GAS_STYPE_OFFSET] == WL_GAS_WFA_STYPE_DPP)) {
21851 WL_DBG(("DPP GAS FRAME. type:%d\n", act_frm->action));
21852 return true;
21853 }
21854
21855 /* Non DPP GAS frame */
21856 return false;
21857 }
21858
21859 #ifdef KEEP_ALIVE
21860 #define KA_TEMP_BUF_SIZE 512
21861 #define KA_FRAME_SIZE 300
21862 int
wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 * cfg,uint8 mkeep_alive_id,uint16 ether_type,uint8 * ip_pkt,uint16 ip_pkt_len,uint8 * src_mac,uint8 * dst_mac,uint32 period_msec)21863 wl_cfg80211_start_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id,
21864 uint16 ether_type, uint8 *ip_pkt, uint16 ip_pkt_len,
21865 uint8* src_mac, uint8* dst_mac, uint32 period_msec)
21866 {
21867 const int ETHERTYPE_LEN = 2;
21868 char *pbuf = NULL;
21869 const char *str;
21870 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
21871 wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL;
21872 uint16 buf_len = 0;
21873 u8 str_len = 0;
21874 int res = BCME_ERROR;
21875 uint16 len_bytes = 0;
21876 int i = 0;
21877 uint16 pmac_frame_len = KA_FRAME_SIZE;
21878 uint16 pbuf_len = KA_TEMP_BUF_SIZE;
21879
21880 /* ether frame to have both max IP pkt (256 bytes) and ether header */
21881 char *pmac_frame = NULL;
21882 char *pmac_frame_begin = NULL;
21883 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
21884 struct net_device *primary_ndev = NULL;
21885 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
21886
21887 /*
21888 * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
21889 * dongle shall reject a mkeep_alive request.
21890 */
21891 if (!(dhd->op_mode & DHD_FLAG_STA_MODE))
21892 return res;
21893
21894 WL_TRACE(("%s execution\n", __FUNCTION__));
21895
21896 if ((pbuf = MALLOCZ(cfg->osh, KA_TEMP_BUF_SIZE)) == NULL) {
21897 WL_ERR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE));
21898 res = BCME_NOMEM;
21899 return res;
21900 }
21901
21902 if ((pmac_frame = MALLOCZ(cfg->osh, pmac_frame_len)) == NULL) {
21903 WL_ERR(("failed to allocate mac_frame with size %d\n", pmac_frame_len));
21904 res = BCME_NOMEM;
21905 goto exit;
21906 }
21907 pmac_frame_begin = pmac_frame;
21908
21909 /*
21910 * Get current mkeep-alive status.
21911 */
21912 res = wldev_iovar_getbuf(primary_ndev, "mkeep_alive", &mkeep_alive_id,
21913 sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync);
21914 if (res < 0) {
21915 WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res));
21916 goto exit;
21917 } else {
21918 /* Check available ID whether it is occupied */
21919 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf;
21920 if (dtoh32(mkeep_alive_pktp->period_msec != 0)) {
21921 WL_ERR(("%s: Get mkeep_alive failed, ID %u is in use.\n",
21922 __FUNCTION__, mkeep_alive_id));
21923
21924 /* Current occupied ID info */
21925 WL_ERR(("%s: mkeep_alive\n", __FUNCTION__));
21926 WL_ERR((" Id : %d\n"
21927 " Period: %d msec\n"
21928 " Length: %d\n"
21929 " Packet: 0x",
21930 mkeep_alive_pktp->keep_alive_id,
21931 dtoh32(mkeep_alive_pktp->period_msec),
21932 dtoh16(mkeep_alive_pktp->len_bytes)));
21933
21934 for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) {
21935 WL_ERR(("%02x", mkeep_alive_pktp->data[i]));
21936 }
21937 WL_ERR(("\n"));
21938
21939 res = BCME_NOTFOUND;
21940 goto exit;
21941 }
21942 }
21943
21944 /* Request the specified ID */
21945 bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
21946 bzero(pbuf, KA_TEMP_BUF_SIZE);
21947 str = "mkeep_alive";
21948 str_len = strlen(str);
21949 strlcpy(pbuf, str, KA_TEMP_BUF_SIZE);
21950 buf_len = str_len + 1;
21951 pbuf_len -= buf_len;
21952
21953 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + buf_len);
21954 mkeep_alive_pkt.period_msec = htod32(period_msec);
21955 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
21956 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
21957 len_bytes = (ETHER_ADDR_LEN*2) + ETHERTYPE_LEN + ip_pkt_len;
21958 mkeep_alive_pkt.len_bytes = htod16(len_bytes);
21959
21960 /* ID assigned */
21961 mkeep_alive_pkt.keep_alive_id = mkeep_alive_id;
21962
21963 buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
21964
21965 /*
21966 * Build up Ethernet Frame
21967 */
21968
21969 /* Mapping dest mac addr */
21970 res = memcpy_s(pmac_frame, pmac_frame_len, dst_mac, ETHER_ADDR_LEN);
21971 if (res) {
21972 goto exit;
21973 }
21974 pmac_frame += ETHER_ADDR_LEN;
21975 pmac_frame_len -= ETHER_ADDR_LEN;
21976
21977 /* Mapping src mac addr */
21978 res = memcpy_s(pmac_frame, pmac_frame_len, src_mac, ETHER_ADDR_LEN);
21979 if (res) {
21980 goto exit;
21981 }
21982 pmac_frame += ETHER_ADDR_LEN;
21983 pmac_frame_len -= ETHER_ADDR_LEN;
21984
21985 /* Mapping Ethernet type */
21986 ether_type = hton16(ether_type);
21987 res = memcpy_s(pmac_frame, pmac_frame_len, ðer_type, ETHERTYPE_LEN);
21988 if (res) {
21989 goto exit;
21990 }
21991 pmac_frame += ETHERTYPE_LEN;
21992 pmac_frame_len -= ETHERTYPE_LEN;
21993
21994 /* Mapping IP pkt */
21995 res = memcpy_s(pmac_frame, pmac_frame_len, ip_pkt, ip_pkt_len);
21996 if (res) {
21997 goto exit;
21998 }
21999 pmac_frame += ip_pkt_len;
22000 pmac_frame_len -= ip_pkt_len;
22001
22002 /*
22003 * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
22004 * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
22005 * guarantee that the buffer is properly aligned.
22006 */
22007 res = memcpy_s((char *)mkeep_alive_pktp, pbuf_len,
22008 &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
22009 if (res) {
22010 goto exit;
22011 }
22012 pbuf_len -= WL_MKEEP_ALIVE_FIXED_LEN;
22013
22014 /*
22015 * Length of ether frame (assume to be all hexa bytes)
22016 * = src mac + dst mac + ether type + ip pkt len
22017 */
22018 res = memcpy_s(mkeep_alive_pktp->data, pbuf_len,
22019 pmac_frame_begin, len_bytes);
22020 if (res) {
22021 goto exit;
22022 }
22023 buf_len += len_bytes;
22024
22025 res = wldev_ioctl_set(primary_ndev, WLC_SET_VAR, pbuf, buf_len);
22026 exit:
22027 if (pmac_frame_begin) {
22028 MFREE(cfg->osh, pmac_frame_begin, KA_FRAME_SIZE);
22029 }
22030 if (pbuf) {
22031 MFREE(cfg->osh, pbuf, KA_TEMP_BUF_SIZE);
22032 }
22033 return res;
22034 }
22035
22036 int
wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211 * cfg,uint8 mkeep_alive_id)22037 wl_cfg80211_stop_mkeep_alive(struct bcm_cfg80211 *cfg, uint8 mkeep_alive_id)
22038 {
22039 char *pbuf = NULL;
22040 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
22041 wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL;
22042 int res = BCME_ERROR;
22043 int i = 0;
22044 struct net_device *primary_ndev = NULL;
22045 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22046 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
22047
22048 /*
22049 * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
22050 * dongle shall reject a mkeep_alive request.
22051 */
22052 if (!(dhd->op_mode & DHD_FLAG_STA_MODE))
22053 return res;
22054
22055 WL_TRACE(("%s execution\n", __FUNCTION__));
22056
22057 /*
22058 * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt.
22059 */
22060 if ((pbuf = MALLOCZ(cfg->osh, KA_TEMP_BUF_SIZE)) == NULL) {
22061 WL_ERR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE));
22062 res = BCME_NOMEM;
22063 return res;
22064 }
22065
22066 res = wldev_iovar_getbuf(primary_ndev, "mkeep_alive", &mkeep_alive_id,
22067 sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync);
22068 if (res < 0) {
22069 WL_ERR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res));
22070 goto exit;
22071 } else {
22072 /* Check occupied ID */
22073 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf;
22074 WL_DBG(("%s: mkeep_alive\n", __FUNCTION__));
22075 WL_DBG((" Id : %d\n"
22076 " Period: %d msec\n"
22077 " Length: %d\n"
22078 " Packet: 0x",
22079 mkeep_alive_pktp->keep_alive_id,
22080 dtoh32(mkeep_alive_pktp->period_msec),
22081 dtoh16(mkeep_alive_pktp->len_bytes)));
22082
22083 for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) {
22084 WL_DBG(("%02x", mkeep_alive_pktp->data[i]));
22085 }
22086 WL_DBG(("\n"));
22087 }
22088
22089 /* Make it stop if available */
22090 if (dtoh32(mkeep_alive_pktp->period_msec != 0)) {
22091 WL_INFORM_MEM(("stop mkeep_alive on ID %d\n", mkeep_alive_id));
22092 bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
22093
22094 mkeep_alive_pkt.period_msec = 0;
22095 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
22096 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
22097 mkeep_alive_pkt.keep_alive_id = mkeep_alive_id;
22098
22099 res = wldev_iovar_setbuf(primary_ndev, "mkeep_alive",
22100 (char *)&mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN,
22101 pbuf, KA_TEMP_BUF_SIZE, &cfg->ioctl_buf_sync);
22102 } else {
22103 WL_ERR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id));
22104 res = BCME_NOTFOUND;
22105 }
22106 exit:
22107 if (pbuf) {
22108 MFREE(cfg->osh, pbuf, KA_TEMP_BUF_SIZE);
22109 }
22110 return res;
22111 }
22112 #endif /* KEEP_ALIVE */
22113
22114 s32
wl_cfg80211_handle_macaddr_change(struct net_device * dev,u8 * macaddr)22115 wl_cfg80211_handle_macaddr_change(struct net_device *dev, u8 *macaddr)
22116 {
22117 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22118 uint8 wait_cnt = WAIT_FOR_DISCONNECT_MAX;
22119 u32 status = TRUE;
22120
22121 if (IS_STA_IFACE(dev->ieee80211_ptr) &&
22122 wl_get_drv_status(cfg, CONNECTED, dev)) {
22123 /* Macaddress change in connected state. The curent
22124 * connection will become invalid. Issue disconnect
22125 * to current AP to let the AP know about link down
22126 */
22127 WL_INFORM_MEM(("macaddr change in connected state. Force disassoc.\n"));
22128 wl_cfg80211_disassoc(dev, WLAN_REASON_DEAUTH_LEAVING);
22129
22130 while ((status = wl_get_drv_status(cfg, CONNECTED, dev)) && wait_cnt) {
22131 WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
22132 wait_cnt--;
22133 OSL_SLEEP(50);
22134 }
22135 }
22136 return BCME_OK;
22137 }
22138
22139 int
wl_cfg80211_handle_hang_event(struct net_device * ndev,uint16 hang_reason,uint32 memdump_type)22140 wl_cfg80211_handle_hang_event(struct net_device *ndev, uint16 hang_reason, uint32 memdump_type)
22141 {
22142 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
22143 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
22144
22145 WL_INFORM_MEM(("hang reason = %d, memdump_type =%d\n",
22146 hang_reason, memdump_type));
22147
22148 /* check if pre-registered mac matches the mac from dongle via WLC_E_LINK */
22149 if (wl_get_drv_status(cfg, READY, ndev)) {
22150 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
22151 wl_copy_hang_info_if_falure(ndev,
22152 hang_reason, BCME_NOTFOUND);
22153 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
22154 SUPP_LOG(("Err. hang reason:%d, dump_type:%d\n", hang_reason, memdump_type));
22155 wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
22156 /* IF dongle is down due to previous hang or other conditions,
22157 * sending 0ne more hang notification is not needed.
22158 */
22159
22160 if (dhd_query_bus_erros(dhd)) {
22161 return BCME_ERROR;
22162 }
22163 dhd->iface_op_failed = TRUE;
22164 #if defined(DHD_FW_COREDUMP)
22165 if (dhd->memdump_enabled) {
22166 dhd->memdump_type = memdump_type;
22167 dhd_bus_mem_dump(dhd);
22168 }
22169 #endif /* DHD_FW_COREDUMP */
22170 #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
22171 WL_ERR(("Notify hang event to upper layer \n"));
22172 dhd->hang_reason = hang_reason;
22173 net_os_send_hang_message(ndev);
22174 #endif /* BCMDONGLEHOST && OEM_ANDROID */
22175 }
22176
22177 return BCME_OK;
22178 }
22179
22180 static void
wl_cfg80211_spmk_pmkdb_change_pmk_type(struct bcm_cfg80211 * cfg,pmkid_list_v3_t * pmk_list)22181 wl_cfg80211_spmk_pmkdb_change_pmk_type(struct bcm_cfg80211 *cfg, pmkid_list_v3_t *pmk_list)
22182 {
22183 int i;
22184 pmkid_list_v3_t *spmk_list = NULL;
22185
22186 if (!cfg || !cfg->spmk_info_list || !cfg->spmk_info_list->pmkids.count) {
22187 return;
22188 }
22189
22190 spmk_list = &cfg->spmk_info_list->pmkids;
22191 for (i = 0; i < spmk_list->count; i++) {
22192 if (memcmp(&pmk_list->pmkid->bssid,
22193 &spmk_list->pmkid[i].bssid, ETHER_ADDR_LEN)) {
22194 continue; /* different MAC */
22195 }
22196 WL_INFORM_MEM(("SPMK replace idx:%d bssid: "MACF " to SSID: %d\n", i,
22197 ETHER_TO_MACF(pmk_list->pmkid->bssid), spmk_list->pmkid[i].ssid_len));
22198 bzero(&pmk_list->pmkid->bssid, ETHER_ADDR_LEN);
22199 pmk_list->pmkid->ssid_len = spmk_list->pmkid[i].ssid_len;
22200 (void)memcpy_s(pmk_list->pmkid->ssid, spmk_list->pmkid[i].ssid_len,
22201 spmk_list->pmkid[i].ssid, spmk_list->pmkid[i].ssid_len);
22202 }
22203 }
22204
22205 static void
wl_cfg80211_spmk_pmkdb_del_spmk(struct bcm_cfg80211 * cfg,struct cfg80211_pmksa * pmksa)22206 wl_cfg80211_spmk_pmkdb_del_spmk(struct bcm_cfg80211 *cfg, struct cfg80211_pmksa *pmksa)
22207 {
22208 pmkid_list_v3_t *spmk_list = NULL;
22209 bool bFound = FALSE;
22210 int i;
22211
22212 if (!cfg || !cfg->spmk_info_list || !cfg->spmk_info_list->pmkids.count) {
22213 return;
22214 }
22215
22216 spmk_list = &cfg->spmk_info_list->pmkids;
22217 for (i = 0; i < spmk_list->count; i++) {
22218 if (eacmp(&pmksa->bssid, &spmk_list->pmkid[i].bssid)) {
22219 continue; /* different MAC */
22220 }
22221 bFound = TRUE;
22222 break;
22223 }
22224 WL_INFORM_MEM(("wl_cfg80211_del_pmksa "MACDBG "found:%d(idx:%d)",
22225 MAC2STRDBG(spmk_list->pmkid[i].bssid.octet), bFound, i));
22226 if (!bFound) {
22227 return;
22228 }
22229
22230 for (; i < spmk_list->count - 1; i++) {
22231 memcpy_s(&spmk_list->pmkid[i], sizeof(pmkid_v3_t),
22232 &spmk_list->pmkid[i + 1], sizeof(pmkid_v3_t));
22233 }
22234 spmk_list->count--;
22235 }
22236
22237 static void
wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 * cfg,wl_assoc_status_t * as,const wl_event_msg_t * event,wl_assoc_state_t assoc_state)22238 wl_cfg80211_handle_set_ssid_complete(struct bcm_cfg80211 *cfg, wl_assoc_status_t *as,
22239 const wl_event_msg_t *event, wl_assoc_state_t assoc_state)
22240 {
22241 if (as->status != WLC_E_STATUS_SUCCESS) {
22242 #ifdef CUSTOMER_HW6
22243 /* Some older chips sends SET_SSID with fail status and it
22244 * still proceeds with join. Excempt it for the sake of
22245 * compatibility
22246 */
22247 return;
22248 #endif /* CUSTOMER_HW6 */
22249 #ifdef DHD_ENABLE_BIGDATA_LOGGING
22250 wl_get_connect_failed_status(cfg, event);
22251 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
22252
22253 #ifdef SET_SSID_FAIL_CUSTOM_RC
22254 if (as->status == WLC_E_STATUS_TIMEOUT) {
22255 WL_INFORM_MEM(("overriding reason code %d to %d\n",
22256 as->reason, SET_SSID_FAIL_CUSTOM_RC));
22257 as->reason = SET_SSID_FAIL_CUSTOM_RC;
22258 }
22259 #endif /* SET_SSID_FAIL_CUSTOM_RC */
22260
22261 /* Report connect failure */
22262 as->link_action = wl_set_link_action(assoc_state, false);
22263 }
22264 #ifdef WL_NAN
22265 else if ((as->status == WLC_E_STATUS_SUCCESS) &&
22266 wl_cfgnan_is_enabled(cfg) &&
22267 wl_get_drv_status(cfg, CONNECTED, as->ndev)) {
22268 u8 *curbssid = wl_read_prof(cfg, as->ndev, WL_PROF_BSSID);
22269 u8 *conn_req_bssid =
22270 wl_read_prof(cfg, as->ndev, WL_PROF_LATEST_BSSID);
22271
22272 if (memcmp(curbssid, conn_req_bssid, ETHER_ADDR_LEN) == 0) {
22273 wl_cfgnan_get_stats(cfg);
22274 }
22275 }
22276 #endif /* WL_NAN */
22277
22278 return;
22279 }
22280
22281 #ifdef WL_TWT
22282 static s32
wl_notify_twt_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)22283 wl_notify_twt_event(struct bcm_cfg80211 *cfg,
22284 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
22285 {
22286 uint32 type;
22287 type = ntoh32(e->event_type);
22288 WL_DBG(("TWT event type %d\n", type));
22289 return BCME_OK;
22290 }
22291 #endif /* WL_TWT */
22292
22293 #define CHECK_AND_INCR_LEN(ret, len, maxlen) \
22294 { \
22295 if ((ret < 0) || ((ret + len) > maxlen)) \
22296 return len; \
22297 len += ret; \
22298 }
22299 u32
wl_cfg80211_debug_data_dump(struct net_device * dev,u8 * buf,u32 buf_len)22300 wl_cfg80211_debug_data_dump(struct net_device *dev, u8 *buf, u32 buf_len)
22301 {
22302 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22303 u32 len = 0;
22304 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
22305 s32 ret = 0;
22306
22307 BCM_REFERENCE(dhdp);
22308 if ((!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
22309 WL_INFORM(("driver not up.\n"));
22310 return 0;
22311 }
22312
22313 ret = snprintf(buf, buf_len, "\n[BCMLINUX]\nlock info:\n");
22314 CHECK_AND_INCR_LEN(ret, len, buf_len);
22315
22316 ret = snprintf(buf+len, buf_len-len,
22317 "rtnl:%d\n"
22318 "scan_sync:%d\n"
22319 "usr_sync:%d\n"
22320 "if_sync:%d\n"
22321 "event_sync:%d\n"
22322 "ioctl_buf:%d\n",
22323 rtnl_is_locked(), mutex_is_locked(&cfg->scan_sync),
22324 mutex_is_locked(&cfg->usr_sync), mutex_is_locked(&cfg->if_sync),
22325 mutex_is_locked(&cfg->event_sync), mutex_is_locked(&cfg->ioctl_buf_sync));
22326 CHECK_AND_INCR_LEN(ret, len, buf_len);
22327
22328 #ifdef WL_NAN
22329 ret = snprintf(buf+len, buf_len-len, "nan:%d\n", mutex_is_locked(&cfg->nancfg->nan_sync));
22330 CHECK_AND_INCR_LEN(ret, len, buf_len);
22331 #endif /* WL_NAN */
22332 #ifdef RTT_SUPPORT
22333 {
22334 rtt_status_info_t *rtt_status = GET_RTTSTATE(dhdp);
22335 ret = snprintf(buf+len, buf_len-len, "rtt:%d\n",
22336 mutex_is_locked(&rtt_status->rtt_mutex));
22337 CHECK_AND_INCR_LEN(ret, len, buf_len);
22338 ret = snprintf(buf+len, buf_len-len, "geofence:%d\n",
22339 mutex_is_locked(&(rtt_status)->geofence_mutex));
22340 CHECK_AND_INCR_LEN(ret, len, buf_len);
22341 }
22342 #endif /* RTT_SUPPORT */
22343 #ifdef WL_BCNRECV
22344 ret = snprintf(buf+len, buf_len-len, "bcn_sync:%d\n", mutex_is_locked(&cfg->bcn_sync));
22345 CHECK_AND_INCR_LEN(ret, len, buf_len);
22346 #endif /* WL_BCNRECV */
22347 #ifdef WLTDLS
22348 ret = snprintf(buf+len, buf_len-len, "tdls_sync:%d\n", mutex_is_locked(&cfg->tdls_sync));
22349 CHECK_AND_INCR_LEN(ret, len, buf_len);
22350 #endif /* WLTDLS */
22351 ret = snprintf(buf+len, buf_len-len, "cfgdrv:%d\n", spin_is_locked(&cfg->cfgdrv_lock));
22352 CHECK_AND_INCR_LEN(ret, len, buf_len);
22353
22354 ret = snprintf(buf+len, buf_len-len, "vndr_oui:%d\n", spin_is_locked(&cfg->vndr_oui_sync));
22355 CHECK_AND_INCR_LEN(ret, len, buf_len);
22356
22357 ret = snprintf(buf+len, buf_len-len, "net_list:%d\n", spin_is_locked(&cfg->net_list_sync));
22358 CHECK_AND_INCR_LEN(ret, len, buf_len);
22359
22360 ret = snprintf(buf+len, buf_len-len, "eq_lock:%d\n", spin_is_locked(&cfg->eq_lock));
22361 CHECK_AND_INCR_LEN(ret, len, buf_len);
22362
22363 #ifdef WL_WPS_SYNC
22364 ret = snprintf(buf+len, buf_len-len, "wps:%d\n", spin_is_locked(&cfg->wps_sync));
22365 CHECK_AND_INCR_LEN(ret, len, buf_len);
22366 #endif /* WL_WPS_SYNC */
22367 ret = snprintf(buf+len, buf_len-len, "eidx.in_progress:0x%x eidx.event:0x%x",
22368 cfg->eidx.in_progress, cfg->eidx.event_type);
22369 CHECK_AND_INCR_LEN(ret, len, buf_len);
22370 return len;
22371 }
22372
22373 #ifdef WL_CLIENT_SAE
22374 static bool
wl_is_pmkid_available(struct net_device * dev,const u8 * bssid)22375 wl_is_pmkid_available(struct net_device *dev, const u8 *bssid)
22376 {
22377 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22378 int i;
22379
22380 /* check the bssid is null or not */
22381 if (!bssid) return FALSE;
22382
22383 for (i = 0; i < cfg->pmk_list->pmkids.count; i++) {
22384 if (!memcmp(bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
22385 ETHER_ADDR_LEN)) {
22386 return TRUE;
22387 }
22388 }
22389 return FALSE;
22390 }
22391
22392 #define WL_AUTH_START_EVT_V0 0
22393 static s32
wl_notify_start_auth(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)22394 wl_notify_start_auth(struct bcm_cfg80211 *cfg,
22395 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
22396 {
22397 struct cfg80211_external_auth_params ext_auth_param;
22398 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22399 u32 datalen = be32_to_cpu(e->datalen);
22400 #ifdef WL_AUTH_START_EVT_V0
22401 wl_ext_auth_evt_t *evt_v0_data = (wl_ext_auth_evt_t *)data;
22402 #else
22403 wl_auth_start_evt_t *evt_v1_data = (wl_auth_start_evt_t *)data;
22404 #endif
22405 wl_assoc_mgr_cmd_t cmd;
22406 struct wireless_dev *wdev = ndev->ieee80211_ptr;
22407 int err, retry = 3;
22408
22409 WL_DBG(("Enter\n"));
22410
22411 if (!datalen || !data) {
22412 WL_ERR(("Invalid data for auth start event\n"));
22413 return BCME_ERROR;
22414 }
22415
22416 ext_auth_param.action = NL80211_EXTERNAL_AUTH_START;
22417 ext_auth_param.key_mgmt_suite = ntoh32(WLAN_AKM_SUITE_SAE_SHA256);
22418 #ifdef WL_AUTH_START_EVT_V0
22419 (void)memcpy_s(&ext_auth_param.bssid, ETHER_ADDR_LEN, &evt_v0_data->bssid, ETHER_ADDR_LEN);
22420 ext_auth_param.ssid.ssid_len = MIN(evt_v0_data->ssid.SSID_len, DOT11_MAX_SSID_LEN);
22421 if (ext_auth_param.ssid.ssid_len) {
22422 (void)memcpy_s(&ext_auth_param.ssid.ssid, ext_auth_param.ssid.ssid_len,
22423 evt_v0_data->ssid.SSID, ext_auth_param.ssid.ssid_len);
22424 }
22425 WL_MSG(ndev->name, "BSSID "MACDBG"\n", MAC2STRDBG(&evt_v0_data->bssid));
22426 #else
22427 (void)memcpy_s(&ext_auth_param.bssid, ETHER_ADDR_LEN, &evt_v1_data->bssid, ETHER_ADDR_LEN);
22428 ext_auth_param.ssid.ssid_len = MIN(evt_v1_data->ssid.SSID_len, DOT11_MAX_SSID_LEN);
22429 if (ext_auth_param.ssid.ssid_len) {
22430 (void)memcpy_s(&ext_auth_param.ssid.ssid, ext_auth_param.ssid.ssid_len,
22431 evt_v1_data->ssid.SSID, ext_auth_param.ssid.ssid_len);
22432 }
22433 WL_MSG(ndev->name, "BSSID "MACDBG", version=%d\n",
22434 MAC2STRDBG(&evt_v1_data->bssid), evt_v1_data->version);
22435 #endif
22436
22437 /* Wait for conn_owner_nlportid been assigned in nl80211_connect */
22438 for (retry = 3; retry > 0; retry--) {
22439 if (wdev->conn_owner_nlportid) {
22440 break;
22441 }
22442
22443 wl_delay(10);
22444 }
22445
22446 #ifdef WL_EXT_IAPSTA
22447 err = wl_ext_in4way_sync(ndev, STA_START_AUTH_DELAY, WL_EXT_STATUS_CONNECTING, NULL);
22448 if (err) {
22449 WL_ERR(("Failed to notify external auth req(%d)\n", err));
22450 return BCME_ERROR;
22451 }
22452 #endif
22453
22454 err = cfg80211_external_auth_request(ndev, &ext_auth_param, GFP_KERNEL);
22455 if (err) {
22456 WL_ERR(("Send external auth request failed, ret %d\n", err));
22457 return BCME_ERROR;
22458 }
22459
22460 cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
22461 cmd.length = sizeof(cmd);
22462 cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
22463 cmd.params = WL_ASSOC_MGR_PARAMS_PAUSE_EVENT_AUTH_RESP;
22464 err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd), cfg->ioctl_buf,
22465 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
22466 if (unlikely(err)) {
22467 WL_ERR(("Failed to pause assoc(%d)\n", err));
22468 }
22469
22470 return BCME_OK;
22471 }
22472
22473 s32
wl_handle_auth_event(struct bcm_cfg80211 * cfg,struct net_device * ndev,const wl_event_msg_t * e,void * data)22474 wl_handle_auth_event(struct bcm_cfg80211 *cfg, struct net_device *ndev,
22475 const wl_event_msg_t *e, void *data)
22476 {
22477 bcm_struct_cfgdev *cfgdev = ndev_to_cfgdev(ndev);
22478 u8 bsscfgidx = e->bsscfgidx;
22479 u8 *mgmt_frame = NULL;
22480 u8 *body = NULL;
22481 u32 body_len = 0;
22482 s32 chan;
22483 chanspec_t chanspec;
22484 s32 freq;
22485 struct ether_addr da;
22486 struct ether_addr bssid;
22487 u32 len = ntoh32(e->datalen);
22488 u32 status = ntoh32(e->status);
22489 int err = BCME_OK;
22490
22491 if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
22492 return WL_INVALID;
22493 }
22494
22495 if (!len) {
22496 WL_ERR(("WLC_E_AUTH has no payload. status %d reason %d\n",
22497 status, ntoh32(e->reason)));
22498 #ifdef WL_EXT_IAPSTA
22499 if (status != WLC_E_STATUS_SUCCESS)
22500 wl_ext_in4way_sync(ndev, STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY|STA_WAIT_DISCONNECTED,
22501 WL_EXT_STATUS_DISCONNECTED, NULL);
22502 #endif
22503 return WL_INVALID;
22504 }
22505
22506 body = (u8 *)MALLOCZ(cfg->osh, len);
22507 if (body == NULL) {
22508 WL_ERR(("Failed to allocate body\n"));
22509 return WL_INVALID;
22510 }
22511 (void)memcpy_s(body, len, data, len);
22512
22513 err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
22514 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
22515 if (unlikely(err)) {
22516 MFREE(cfg->osh, body, len);
22517 WL_ERR(("Could not get cur_etheraddr %d\n", err));
22518 return err;
22519 }
22520 (void)memcpy_s(da.octet, ETHER_ADDR_LEN, cfg->ioctl_buf, ETHER_ADDR_LEN);
22521
22522 bzero(&bssid, sizeof(bssid));
22523 err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
22524 /* Use e->addr as bssid for Sta case , before association completed */
22525 if (err == BCME_NOTASSOCIATED) {
22526 (void)memcpy_s(&bssid, ETHER_ADDR_LEN, &e->addr, ETHER_ADDR_LEN);
22527 err = BCME_OK;
22528 }
22529 if (unlikely(err)) {
22530 MFREE(cfg->osh, body, len);
22531 WL_ERR(("Could not get bssid %d\n", err));
22532 return err;
22533 }
22534
22535 err = wldev_iovar_getint(ndev, "chanspec", &chan);
22536 if (unlikely(err)) {
22537 MFREE(cfg->osh, body, len);
22538 WL_ERR(("Could not get chanspec %d\n", err));
22539 return err;
22540 }
22541
22542 chanspec = wl_chspec_driver_to_host(chan);
22543 freq = wl_channel_to_frequency(wf_chspec_ctlchan(chanspec), CHSPEC_BAND(chanspec));
22544
22545 body_len = len;
22546 err = wl_frame_get_mgmt(cfg, FC_AUTH, &da, &e->addr, &bssid,
22547 &mgmt_frame, &len, body);
22548 if (!err) {
22549 #ifdef WL_EXT_IAPSTA
22550 wl_ext_update_extsae_4way(ndev, (struct ieee80211_mgmt *)mgmt_frame, FALSE);
22551 #endif
22552 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
22553 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0);
22554 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
22555 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
22556 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
22557 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
22558 #else
22559 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
22560 #endif
22561 MFREE(cfg->osh, mgmt_frame, len);
22562 }
22563
22564 if (body) {
22565 MFREE(cfg->osh, body, body_len);
22566 }
22567
22568 return BCME_OK;
22569 }
22570
22571 /** Called by the cfg80211 framework */
22572 static s32
wl_cfg80211_external_auth(struct wiphy * wiphy,struct net_device * ndev,struct cfg80211_external_auth_params * ext_auth_param)22573 wl_cfg80211_external_auth(struct wiphy *wiphy,
22574 struct net_device *ndev, struct cfg80211_external_auth_params *ext_auth_param)
22575 {
22576 int err = 0;
22577 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
22578 wl_assoc_mgr_cmd_t cmd;
22579
22580 WL_DBG(("Enter\n"));
22581
22582 if (!ext_auth_param ||
22583 ETHER_ISNULLADDR(ext_auth_param->bssid)) {
22584 WL_ERR(("Invalid param\n"));
22585 return -EINVAL;
22586 }
22587
22588 cmd.version = WL_ASSOC_MGR_CURRENT_VERSION;
22589 cmd.length = sizeof(cmd);
22590 cmd.cmd = WL_ASSOC_MGR_CMD_PAUSE_ON_EVT;
22591 cmd.params = WL_ASSOC_MGR_PARAMS_EVENT_NONE;
22592 err = wldev_iovar_setbuf(ndev, "assoc_mgr_cmd", (void *)&cmd, sizeof(cmd),
22593 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
22594 if (unlikely(err)) {
22595 WL_ERR(("Failed to pause assoc(%d)\n", err));
22596 }
22597
22598 return err;
22599 }
22600
22601 static s32
wl_cfg80211_mgmt_auth_tx(struct net_device * dev,bcm_struct_cfgdev * cfgdev,struct bcm_cfg80211 * cfg,const u8 * buf,size_t len,s32 bssidx,u64 * cookie)22602 wl_cfg80211_mgmt_auth_tx(struct net_device *dev, bcm_struct_cfgdev *cfgdev,
22603 struct bcm_cfg80211 *cfg, const u8 *buf, size_t len, s32 bssidx, u64 *cookie)
22604 {
22605 int err = 0;
22606 wl_assoc_mgr_cmd_t *cmd;
22607 char *ambuf = NULL;
22608 int param_len;
22609 bool ack = true;
22610
22611 param_len = sizeof(wl_assoc_mgr_cmd_t) + len;
22612 ambuf = MALLOCZ(cfg->osh, param_len);
22613 if (ambuf == NULL) {
22614 WL_ERR(("unable to allocate frame\n"));
22615 return -ENOMEM;
22616 }
22617
22618 cmd = (wl_assoc_mgr_cmd_t*)ambuf;
22619 cmd->version = WL_ASSOC_MGR_CURRENT_VERSION;
22620 cmd->length = len;
22621 cmd->cmd = WL_ASSOC_MGR_CMD_SEND_AUTH;
22622 err = memcpy_s(&cmd->params, len, buf, len);
22623 if (err) {
22624 WL_ERR(("Failed to copy cmd params(%d)\n", err));
22625 ack = false;
22626 } else {
22627 err = wldev_iovar_setbuf(dev, "assoc_mgr_cmd", ambuf, param_len,
22628 cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
22629 if (unlikely(err)) {
22630 WL_ERR(("Failed to send auth(%d)\n", err));
22631 ack = false;
22632 }
22633 #ifdef WL_EXT_IAPSTA
22634 else {
22635 const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *)buf;
22636 wl_ext_update_extsae_4way(dev, mgmt, TRUE);
22637 }
22638 #endif
22639 }
22640
22641 MFREE(cfg->osh, ambuf, param_len);
22642
22643 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
22644 return BCME_OK;
22645 }
22646 #endif /* WL_CLIENT_SAE */
22647
22648 s32
wl_cfg80211_autochannel(struct net_device * dev,char * command,int total_len)22649 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len)
22650 {
22651 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22652 int ret = 0;
22653 int bytes_written = -1;
22654
22655 sscanf(command, "%*s %d", &cfg->autochannel);
22656
22657 if (cfg->autochannel == 0) {
22658 cfg->best_2g_ch = 0;
22659 cfg->best_5g_ch = 0;
22660 } else if (cfg->autochannel == 2) {
22661 bytes_written = snprintf(command, total_len, "2g=%d 5g=%d",
22662 cfg->best_2g_ch, cfg->best_5g_ch);
22663 WL_TRACE(("command result is %s\n", command));
22664 ret = bytes_written;
22665 }
22666
22667 return ret;
22668 }
22669