forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-10 cde9070d9970eef1f7ec2360586c802a16230ad8
kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/wl_cfg80211.c
....@@ -1,15 +1,16 @@
1
-/* SPDX-License-Identifier: GPL-2.0 */
21 /*
32 * Linux cfg80211 driver
43 *
5
- * Copyright (C) 1999-2019, Broadcom Corporation
6
- *
4
+ * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation
5
+ *
6
+ * Copyright (C) 1999-2017, Broadcom Corporation
7
+ *
78 * Unless you and Broadcom execute a separate written software license
89 * agreement governing use of this software, this software is licensed to you
910 * under the terms of the GNU General Public License version 2 (the "GPL"),
1011 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
1112 * following added to such license:
12
- *
13
+ *
1314 * As a special exception, the copyright holders of this software give you
1415 * permission to link this software with independent modules, and to copy and
1516 * distribute the resulting executable under terms of your choice, provided that
....@@ -17,7 +18,7 @@
1718 * the license of that module. An independent module is a module which is not
1819 * derived from this software. The special exception does not apply to any
1920 * modifications of the software.
20
- *
21
+ *
2122 * Notwithstanding the above, under no circumstances may you combine this
2223 * software in any way with any other Broadcom software provided under a license
2324 * other than the GPL, without Broadcom's express prior written consent.
....@@ -25,23 +26,31 @@
2526 *
2627 * <<Broadcom-WL-IPTag/Open:>>
2728 *
28
- * $Id: wl_cfg80211.c 715966 2019-05-30 02:36:59Z $
29
+ * $Id: wl_cfg80211.c 814814 2019-04-15 03:31:10Z $
2930 */
3031 /* */
3132 #include <typedefs.h>
3233 #include <linuxver.h>
33
-#include <osl.h>
3434 #include <linux/kernel.h>
3535
3636 #include <bcmutils.h>
37
+#include <bcmstdlib_s.h>
3738 #include <bcmwifi_channels.h>
3839 #include <bcmendian.h>
39
-#include <proto/ethernet.h>
40
-#include <proto/802.11.h>
40
+#include <ethernet.h>
41
+#ifdef WL_WPS_SYNC
42
+#include <eapol.h>
43
+#endif /* WL_WPS_SYNC */
44
+#include <802.11.h>
45
+#ifdef WL_FILS
46
+#include <fils.h>
47
+#include <frag.h>
48
+#endif /* WL_FILS */
49
+#include <bcmiov.h>
4150 #include <linux/if_arp.h>
42
-#include <linux/uaccess.h>
51
+#include <asm/uaccess.h>
4352
44
-#include <proto/ethernet.h>
53
+#include <ethernet.h>
4554 #include <linux/kernel.h>
4655 #include <linux/kthread.h>
4756 #include <linux/netdevice.h>
....@@ -54,14 +63,19 @@
5463 #include <net/rtnetlink.h>
5564
5665 #include <wlioctl.h>
66
+#include <bcmevent.h>
5767 #include <wldev_common.h>
5868 #include <wl_cfg80211.h>
5969 #include <wl_cfgp2p.h>
60
-#include <wl_android.h>
70
+#include <wl_cfgscan.h>
6171 #include <bcmdevs.h>
72
+#ifdef OEM_ANDROID
73
+#include <wl_android.h>
74
+#endif // endif
6275 #include <dngl_stats.h>
6376 #include <dhd.h>
6477 #include <dhd_linux.h>
78
+#include <dhd_linux_pktdump.h>
6579 #include <dhd_debug.h>
6680 #include <dhdioctl.h>
6781 #include <wlioctl.h>
....@@ -70,38 +84,99 @@
7084 #ifdef PNO_SUPPORT
7185 #include <dhd_pno.h>
7286 #endif /* PNO_SUPPORT */
73
-
74
-#if defined(WL_VENDOR_EXT_SUPPORT)
7587 #include <wl_cfgvendor.h>
76
-#endif /* defined(WL_VENDOR_EXT_SUPPORT) */
7788
7889 #ifdef WL_NAN
7990 #include <wl_cfgnan.h>
8091 #endif /* WL_NAN */
92
+
8193 #ifdef PROP_TXSTATUS
8294 #include <dhd_wlfc.h>
83
-#endif
95
+#endif // endif
8496
8597 #ifdef BCMPCIE
8698 #include <dhd_flowring.h>
87
-#endif
99
+#endif // endif
100
+#ifdef RTT_SUPPORT
101
+#include <dhd_rtt.h>
102
+#endif /* RTT_SUPPORT */
88103
89
-#ifdef WL11U
90
-#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
91
-#error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \
92
- according to Kernel version and is supported only in Android-JB
93
-#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
94
-#endif /* WL11U */
104
+#if defined(BIGDATA_SOFTAP) || defined(DHD_ENABLE_BIGDATA_LOGGING)
105
+#include <wl_bigdata.h>
106
+#endif /* BIGDATA_SOFTAP || DHD_ENABLE_BIGDATA_LOGGING */
95107
96
-module_param(wl_dbg_level, uint, 0664);
108
+#ifdef DHD_EVENT_LOG_FILTER
109
+#include <dhd_event_log_filter.h>
110
+#endif /* DHD_EVENT_LOG_FILTER */
111
+#define BRCM_SAE_VENDOR_EVENT_BUF_LEN 500
97112
113
+#ifdef DNGL_AXI_ERROR_LOGGING
114
+#include <bcmtlv.h>
115
+#endif /* DNGL_AXI_ERROR_LOGGING */
116
+
117
+#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
118
+#include <linux/dev_ril_bridge.h>
119
+#include <linux/notifier.h>
120
+#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
121
+
122
+#ifdef DHD_BANDSTEER
123
+#include <dhd_bandsteer.h>
124
+#endif /* DHD_BANDSTEER */
125
+
126
+#ifdef BCMWAPI_WPI
127
+/* these items should evetually go into wireless.h of the linux system headfile dir */
128
+#ifndef IW_ENCODE_ALG_SM4
129
+#define IW_ENCODE_ALG_SM4 0x20
130
+#endif // endif
131
+
132
+#ifndef IW_AUTH_WAPI_ENABLED
133
+#define IW_AUTH_WAPI_ENABLED 0x20
134
+#endif // endif
135
+
136
+#ifndef IW_AUTH_WAPI_VERSION_1
137
+#define IW_AUTH_WAPI_VERSION_1 0x00000008
138
+#endif // endif
139
+
140
+#ifndef IW_AUTH_CIPHER_SMS4
141
+#define IW_AUTH_CIPHER_SMS4 0x00000020
142
+#endif // endif
143
+
144
+#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
145
+#define IW_AUTH_KEY_MGMT_WAPI_PSK 4
146
+#endif // endif
147
+
148
+#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
149
+#define IW_AUTH_KEY_MGMT_WAPI_CERT 8
150
+#endif // endif
151
+#endif /* BCMWAPI_WPI */
152
+
153
+#ifdef BCMWAPI_WPI
154
+#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
155
+#else /* BCMWAPI_WPI */
98156 #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
157
+#endif /* BCMWAPI_WPI */
158
+
159
+#ifdef WL_SAE
160
+#define MGMT_AUTH_FRAME_DWELL_TIME 4000
161
+#define MGMT_AUTH_FRAME_WAIT_TIME (MGMT_AUTH_FRAME_DWELL_TIME + 100)
162
+#endif /* WL_SAE */
163
+
164
+#if (defined(WL_FW_OCE_AP_SELECT) || defined(BCMFW_ROAM_ENABLE) && ((LINUX_VERSION_CODE \
165
+ >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)))
166
+uint fw_ap_select = true;
167
+#else
168
+uint fw_ap_select = false;
169
+#endif /* WL_FW_OCE_AP_SELECT && (ROAM_ENABLE || BCMFW_ROAM_ENABLE) */
170
+module_param(fw_ap_select, uint, 0660);
171
+/* this flag enable triggerrs bgscan method from supplicant */
172
+uint us_ap_select = false;
173
+module_param(us_ap_select, uint, 0660);
99174
100175 static struct device *cfg80211_parent_dev = NULL;
101
-/* g_bcm_cfg should be static. Do not change */
102
-static struct bcm_cfg80211 *g_bcm_cfg = NULL;
103
-u32 wl_dbg_level = WL_DBG_ERR;
176
+static struct bcm_cfg80211 *g_bcmcfg = NULL;
177
+u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_P2P_ACTION | WL_DBG_INFO;
104178
179
+#define MAX_VIF_OFFSET 15
105180 #define MAX_WAIT_TIME 1500
106181 #ifdef WLAIBSS_MCHAN
107182 #define IBSS_IF_NAME "ibss%d"
....@@ -126,36 +201,45 @@
126201 #define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
127202 #endif /* VSDB */
128203
129
-#ifdef WL_CFG80211_SYNC_GON
130
-#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) \
131
- (wl_get_drv_status_all(cfg, SENDING_ACT_FRM) || \
132
- wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN))
133
-#else
134
-#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) wl_get_drv_status_all(cfg, SENDING_ACT_FRM)
135
-#endif /* WL_CFG80211_SYNC_GON */
136
-
137204 #define DNGL_FUNC(func, parameters) func parameters
138205 #define COEX_DHCP
139206
140207 #define WLAN_EID_SSID 0
141208 #define CH_MIN_5G_CHANNEL 34
142
-#define CH_MIN_2G_CHANNEL 1
143
-#define ACTIVE_SCAN 1
144
-#define PASSIVE_SCAN 0
209
+#ifdef WLAIBSS
210
+enum abiss_event_type {
211
+ AIBSS_EVENT_TXFAIL
212
+};
213
+#endif // endif
214
+
215
+#ifdef WL_SAE
216
+/**
217
+ * enum mgmt_tx_status - mgmt frame tx status
218
+ *
219
+ * @MGMT_TX_ACK: mgmt frame acked
220
+ * @MGMT_TX_NOACK: mgmt frame not acked
221
+ * @MGMT_TX_OFF_CHAN_COMPLETED: off-channel complete
222
+ * @MGMT_TX_SEND_FRAME: mgmt frame tx is in progres
223
+ */
224
+enum mgmt_tx_status {
225
+ MGMT_TX_ACK,
226
+ MGMT_TX_NOACK,
227
+ MGMT_TX_OFF_CHAN_COMPLETED,
228
+ MGMT_TX_SEND_FRAME
229
+};
230
+#endif /* WL_SAE */
145231
146232 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
147233 4 && __GNUC_MINOR__ >= 6))
148234 #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
149
-_Pragma("GCC diagnostic push") \
150
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
235
+GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); \
151236 (entry) = list_first_entry((ptr), type, member); \
152
-_Pragma("GCC diagnostic pop") \
237
+GCC_DIAGNOSTIC_POP(); \
153238
154239 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
155
-_Pragma("GCC diagnostic push") \
156
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
240
+GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST(); \
157241 entry = container_of((ptr), type, member); \
158
-_Pragma("GCC diagnostic pop") \
242
+GCC_DIAGNOSTIC_POP(); \
159243
160244 #else
161245 #define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
....@@ -166,10 +250,17 @@
166250
167251 #endif /* STRICT_GCC_WARNINGS */
168252
253
+#ifdef WL_RELMCAST
169254 enum rmc_event_type {
170255 RMC_EVENT_NONE,
171256 RMC_EVENT_LEADER_CHECK_FAIL
172257 };
258
+#endif /* WL_RELMCAST */
259
+
260
+#ifdef DHD_SSW_SPECIFIC_REQ
261
+#define WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE 2
262
+#define WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE 3
263
+#endif /* DHD_SSW_SPECIFIC_REQ */
173264
174265 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
175266 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
....@@ -184,9 +275,13 @@
184275 4 && __GNUC_MINOR__ >= 6))
185276 _Pragma("GCC diagnostic push")
186277 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
187
-#endif
278
+#endif // endif
188279 static const struct ieee80211_regdomain brcm_regdom = {
280
+#ifdef WL_6E
281
+ .n_reg_rules = 5,
282
+#else
189283 .n_reg_rules = 4,
284
+#endif /* WL_6E */
190285 .alpha2 = "99",
191286 .reg_rules = {
192287 /* IEEE 802.11b/g, channels 1..11 */
....@@ -197,15 +292,19 @@
197292 */
198293 REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
199294 /* IEEE 802.11a, channel 36..64 */
200
- REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
295
+ REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
201296 /* IEEE 802.11a, channel 100..165 */
202
- REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
297
+ REG_RULE(5470-10, 5850+10, 80, 6, 20, 0),
298
+#ifdef WL_6E
299
+ /* IEEE 802.11ax, 6E */
300
+ REG_RULE(5935-10, 7115+10, 80, 6, 20, 0),
301
+#endif /* WL_6E */
302
+ }
203303 };
204304 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
205305 4 && __GNUC_MINOR__ >= 6))
206306 _Pragma("GCC diagnostic pop")
207
-#endif
208
-
307
+#endif // endif
209308
210309 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
211310 (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
....@@ -224,12 +323,14 @@
224323 * to kernel version.
225324 *
226325 * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
227
- * linux-3.8 and above - max:2 (wlan0 + group removal of p2p-wlan0-x)
326
+ * linux-3.8 and above - max:4
327
+ * sta + NAN NMI + NAN DPI open + NAN DPI sec (since there is no iface type
328
+ * for NAN defined, registering it as STA type)
228329 */
229330 #ifdef WL_ENABLE_P2P_IF
230331 .max = 3,
231332 #else
232
- .max = 2,
333
+ .max = 4,
233334 #endif /* WL_ENABLE_P2P_IF */
234335 .types = BIT(NL80211_IFTYPE_STATION),
235336 },
....@@ -248,29 +349,47 @@
248349 .types = BIT(NL80211_IFTYPE_ADHOC),
249350 },
250351 };
251
-#ifdef BCM4330_CHIP
252
-#define NUM_DIFF_CHANNELS 1
253
-#else
254
-#define NUM_DIFF_CHANNELS 2
255
-#endif
352
+
353
+#define NUM_DIFF_CHANNELS 3
354
+
256355 static const struct ieee80211_iface_combination
257356 common_iface_combinations[] = {
258357 {
259358 .num_different_channels = NUM_DIFF_CHANNELS,
260359 /*
261
- * max_interfaces = 4
262
- * The max no of interfaces will be used in dual p2p case.
263
- * {STA, P2P Device, P2P Group 1, P2P Group 2}. Though we
264
- * will not be using the STA functionality in this case, it
265
- * will remain registered as it is the primary interface.
360
+ * At Max 5 network interfaces can be registered concurrently
266361 */
267
- .max_interfaces = 4,
362
+ .max_interfaces = IFACE_MAX_CNT,
268363 .limits = common_if_limits,
269364 .n_limits = ARRAY_SIZE(common_if_limits),
270365 },
271366 };
272367 #endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
273368
369
+static const char *wl_if_state_strs[WL_IF_STATE_MAX + 1] = {
370
+ "WL_IF_CREATE_REQ",
371
+ "WL_IF_CREATE_DONE",
372
+ "WL_IF_DELETE_REQ",
373
+ "WL_IF_DELETE_DONE",
374
+ "WL_IF_CHANGE_REQ",
375
+ "WL_IF_CHANGE_DONE",
376
+ "WL_IF_STATE_MAX"
377
+};
378
+
379
+#ifdef BCMWAPI_WPI
380
+#if defined(ANDROID_PLATFORM_VERSION) && (ANDROID_PLATFORM_VERSION >= 8)
381
+/* WAPI define in ieee80211.h is used */
382
+#else
383
+#undef WLAN_AKM_SUITE_WAPI_PSK
384
+#define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04
385
+
386
+#undef WLAN_AKM_SUITE_WAPI_CERT
387
+#define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12
388
+
389
+#undef NL80211_WAPI_VERSION_1
390
+#define NL80211_WAPI_VERSION_1 1 << 3
391
+#endif /* ANDROID_PLATFORM_VERSION && ANDROID_PLATFORM_VERSION >= 8 */
392
+#endif /* BCMWAPI_WPI */
274393
275394 /* Data Element Definitions */
276395 #define WPS_ID_CONFIG_METHODS 0x1008
....@@ -308,38 +427,127 @@
308427 #define PM_BLOCK 1
309428 #define PM_ENABLE 0
310429
311
-
312
-#define WL_AKM_SUITE_SHA256_1X 0x000FAC05
313
-#define WL_AKM_SUITE_SHA256_PSK 0x000FAC06
430
+/* GCMP crypto supported above kernel v4.0 */
431
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0))
432
+#define WL_GCMP
433
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(4, 0, 0) */
314434
315435 #ifndef IBSS_COALESCE_ALLOWED
316
-#define IBSS_COALESCE_ALLOWED 0
317
-#endif
436
+#define IBSS_COALESCE_ALLOWED IBSS_COALESCE_DEFAULT
437
+#endif // endif
318438
319439 #ifndef IBSS_INITIAL_SCAN_ALLOWED
320
-#define IBSS_INITIAL_SCAN_ALLOWED 0
321
-#endif
322
-
440
+#define IBSS_INITIAL_SCAN_ALLOWED IBSS_INITIAL_SCAN_ALLOWED_DEFAULT
441
+#endif // endif
323442
324443 #define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
325444 #define LONG_LISTEN_TIME 2000
445
+
446
+#ifdef WBTEXT
447
+typedef struct wl_wbtext_bssid {
448
+ struct ether_addr ea;
449
+ struct list_head list;
450
+} wl_wbtext_bssid_t;
451
+
452
+static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev);
453
+static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
454
+static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea);
455
+static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg);
456
+static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
457
+ struct wl_profile *profile);
458
+static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
459
+ struct wl_profile *profile);
460
+static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev);
461
+static int wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len);
462
+#endif /* WBTEXT */
463
+
464
+#ifdef RTT_SUPPORT
465
+static s32 wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
466
+ const wl_event_msg_t *e, void *data);
467
+#endif /* RTT_SUPPORT */
468
+#ifdef WL_CHAN_UTIL
469
+static s32 wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg,
470
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
471
+static s32 wl_cfg80211_start_bssload_report(struct net_device *ndev);
472
+#endif /* WL_CHAN_UTIL */
473
+
474
+#ifdef SUPPORT_AP_RADIO_PWRSAVE
475
+#define RADIO_PWRSAVE_PPS 10
476
+#define RADIO_PWRSAVE_QUIET_TIME 10
477
+#define RADIO_PWRSAVE_LEVEL 3
478
+#define RADIO_PWRSAVE_STAS_ASSOC_CHECK 0
479
+
480
+#define RADIO_PWRSAVE_LEVEL_MIN 1
481
+#define RADIO_PWRSAVE_LEVEL_MAX 9
482
+#define RADIO_PWRSAVE_PPS_MIN 1
483
+#define RADIO_PWRSAVE_QUIETTIME_MIN 1
484
+#define RADIO_PWRSAVE_ASSOCCHECK_MIN 0
485
+#define RADIO_PWRSAVE_ASSOCCHECK_MAX 1
486
+
487
+#define RADIO_PWRSAVE_MAJOR_VER 1
488
+#define RADIO_PWRSAVE_MINOR_VER 1
489
+#define RADIO_PWRSAVE_MAJOR_VER_SHIFT 8
490
+#define RADIO_PWRSAVE_VERSION \
491
+ ((RADIO_PWRSAVE_MAJOR_VER << RADIO_PWRSAVE_MAJOR_VER_SHIFT)| RADIO_PWRSAVE_MINOR_VER)
492
+#endif /* SUPPORT_AP_RADIO_PWRSAVE */
493
+
494
+/* SoftAP related parameters */
495
+#define DEFAULT_2G_SOFTAP_CHANNEL 1
496
+#define DEFAULT_5G_SOFTAP_CHANNEL 149
497
+#define WL_MAX_NUM_CSA_COUNTERS 255
498
+
499
+#define MAX_VNDR_OUI_STR_LEN 256u
500
+#define VNDR_OUI_STR_LEN 10u
501
+#define DOT11_DISCONNECT_RC 2u
502
+static const uchar *exclude_vndr_oui_list[] = {
503
+ "\x00\x50\xf2", /* Microsoft */
504
+ "\x00\x00\xf0", /* Samsung Elec */
505
+ WFA_OUI, /* WFA */
506
+ NULL
507
+};
508
+
509
+typedef struct wl_vndr_oui_entry {
510
+ uchar oui[DOT11_OUI_LEN];
511
+ struct list_head list;
512
+} wl_vndr_oui_entry_t;
513
+
514
+static int wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg,
515
+ struct net_device *ndev, char *vndr_oui, u32 vndr_oui_len);
516
+static void wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg);
517
+static s32 wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
518
+ struct parsed_vndr_ies *vndr_ies);
519
+
520
+#if defined(WL_FW_OCE_AP_SELECT)
521
+static bool
522
+wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
523
+
524
+/* Check whether the given IE looks like WFA OCE IE. */
525
+#define wl_cfgoce_is_oce_ie(ie, tlvs, len) wl_cfgoce_has_ie(ie, tlvs, len, \
526
+ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_MBO_OCE)
527
+
528
+/* Is any of the tlvs the expected entry? If
529
+ * not update the tlvs buffer pointer/length.
530
+ */
531
+static bool
532
+wl_cfgoce_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
533
+{
534
+ /* If the contents match the OUI and the type */
535
+ if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
536
+ !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
537
+ type == ie[TLV_BODY_OFF + oui_len]) {
538
+ return TRUE;
539
+ }
540
+
541
+ return FALSE;
542
+}
543
+#endif /* WL_FW_OCE_AP_SELECT */
544
+
326545 /*
327546 * cfg80211_ops api/callback list
328547 */
329
-static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
330
- const struct ether_addr *sa, const struct ether_addr *bssid,
331
- u8 **pheader, u32 *body_len, u8 *pbody);
332
-static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
333
- struct cfg80211_scan_request *request,
334
- struct cfg80211_ssid *this_ssid);
335
-#if defined(WL_CFG80211_P2P_DEV_IF)
336
-static s32
337
-wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request);
338
-#else
339
-static s32
340
-wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
341
- struct cfg80211_scan_request *request);
342
-#endif /* WL_CFG80211_P2P_DEV_IF */
548
+static s32 wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
549
+ const struct ether_addr *da, const struct ether_addr *sa,
550
+ const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody);
343551 static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
344552 #ifdef WLAIBSS_MCHAN
345553 static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name);
....@@ -357,12 +565,15 @@
357565 static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
358566 struct net_device *dev, u8 *mac,
359567 struct station_info *sinfo);
360
-#endif
361
-static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
362
- struct net_device *dev, bool enabled,
363
- s32 timeout);
568
+#endif // endif
364569 static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
365570 struct cfg80211_connect_params *sme);
571
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
572
+#if defined(WL_FILS) || defined(WL_OWE)
573
+static int wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
574
+ struct cfg80211_connect_params *sme, u32 changed);
575
+#endif
576
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
366577 static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
367578 u16 reason_code);
368579 #if defined(WL_CFG80211_P2P_DEV_IF)
....@@ -409,49 +620,45 @@
409620 #else
410621 static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
411622 struct net_device *ndev, u8* mac_addr);
412
-#endif
623
+#endif // endif
413624 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
414625 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
415626 struct net_device *dev, const u8 *mac, struct station_parameters *params);
416627 #else
417628 static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
418629 struct net_device *dev, u8 *mac, struct station_parameters *params);
419
-#endif
630
+#endif // endif
420631 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
421
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
632
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
422633 static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
423634 #else
424635 static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
425
-#endif
636
+#endif // endif
426637 static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
427638 struct cfg80211_pmksa *pmksa);
428639 static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
429640 struct cfg80211_pmksa *pmksa);
430641 static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
431642 struct net_device *dev);
432
-static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
433
-static void wl_cfg80211_cancel_scan(struct bcm_cfg80211 *cfg);
434
-static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
435
- struct net_device *ndev, bool aborted, bool fw_abort);
436
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
643
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
437644 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
438645 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
439646 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
440647 u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
441
- u32 peer_capability, const u8 *data, size_t len);
648
+ u32 peer_capability, const u8 *buf, size_t len);
442649 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
443650 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
444651 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
445652 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
446
- u32 peer_capability, const u8 *data, size_t len);
653
+ u32 peer_capability, const u8 *buf, size_t len);
447654 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
448655 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
449
- const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
450
- u32 peer_capability, bool initiator, const u8 *data, size_t len);
451
-#else
656
+ const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
657
+ u32 peer_capability, bool initiator, const u8 *buf, size_t len);
658
+#else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
452659 static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
453
- u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data,
454
- size_t len);
660
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
661
+ const u8 *buf, size_t len);
455662 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
456663 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
457664 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
....@@ -459,51 +666,58 @@
459666 #else
460667 static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
461668 u8 *peer, enum nl80211_tdls_operation oper);
462
-#endif
463
-#endif
464
-#ifdef WL_SCHED_SCAN
465
-static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev);
466
-#endif
467
-#if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF)
468
-bcm_struct_cfgdev*
469
-wl_cfg80211_create_iface(struct wiphy *wiphy, enum nl80211_iftype
470
- iface_type, u8 *mac_addr, const char *name);
669
+#endif // endif
670
+#endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
671
+static s32 wl_cfg80211_set_ap_role(struct bcm_cfg80211 *cfg, struct net_device *dev);
672
+
673
+struct wireless_dev *
674
+wl_cfg80211_create_iface(struct wiphy *wiphy, wl_iftype_t
675
+ iface_type, u8 *mac_addr, const char *name);
471676 s32
472
-wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
473
-#endif /* defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) */
677
+wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev);
474678
475679 s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
476680 struct net_device *ndev, s32 bsscfg_idx,
477
- enum nl80211_iftype iface_type, s32 del, u8 *addr);
681
+ wl_iftype_t iftype, s32 del, u8 *addr);
478682 s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
479683 struct net_device *ndev, s32 bsscfg_idx,
480
- enum nl80211_iftype iface_type, s32 del, u8 *addr);
684
+ wl_iftype_t brcm_iftype, s32 del, u8 *addr);
685
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
686
+static s32 wl_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev);
687
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) */
481688 #ifdef GTK_OFFLOAD_SUPPORT
482689 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
483690 static s32 wl_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
484691 struct cfg80211_gtk_rekey_data *data);
485692 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
486
-#endif
693
+#endif /* GTK_OFFLOAD_SUPPORT */
487694 chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
488695 chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
489
-#ifdef WL11ULB
490
-static s32 wl_cfg80211_get_ulb_bw(struct wireless_dev *wdev);
491
-static chanspec_t wl_cfg80211_ulb_get_min_bw_chspec(struct wireless_dev *wdev, s32 bssidx);
492
-static s32 wl_cfg80211_ulbbw_to_ulbchspec(u32 ulb_bw);
493
-#else
494
-static inline chanspec_t wl_cfg80211_ulb_get_min_bw_chspec(
495
- struct wireless_dev *wdev, s32 bssidx)
496
-{
497
- return WL_CHANSPEC_BW_20;
498
-}
499
-#endif /* WL11ULB */
696
+static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev);
697
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
698
+int wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
699
+ struct cfg80211_csa_settings *params);
700
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
701
+
702
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
703
+static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
704
+ const struct cfg80211_pmk_conf *conf);
705
+static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
706
+ const u8 *aa);
707
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
708
+
709
+#ifdef WL_SAE
710
+static int
711
+wl_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *dev,
712
+ struct cfg80211_external_auth_params *params);
713
+#endif /* WL_SAE */
500714
501715 /*
502716 * event & event Q handlers for cfg80211 interfaces
503717 */
504718 static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
505719 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
506
-static s32 wl_event_handler(void *data);
720
+static void wl_event_handler(struct work_struct *work_data);
507721 static void wl_init_eq(struct bcm_cfg80211 *cfg);
508722 static void wl_flush_eq(struct bcm_cfg80211 *cfg);
509723 static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
....@@ -513,16 +727,13 @@
513727 static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
514728 static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
515729 const wl_event_msg_t *msg, void *data);
516
-static void wl_put_event(struct wl_event_q *e);
517
-static void wl_wakeup_event(struct bcm_cfg80211 *cfg);
730
+static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e);
518731 static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
519732 const wl_event_msg_t *e, void *data);
520733 static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
521734 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
522735 static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
523736 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
524
-static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
525
- const wl_event_msg_t *e, void *data);
526737 static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
527738 const wl_event_msg_t *e, void *data, bool completed);
528739 static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
....@@ -533,35 +744,54 @@
533744 static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
534745 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
535746 #endif /* BT_WIFI_HANDOVER */
536
-#ifdef WL_SCHED_SCAN
537
-static s32
538
-wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
539
- const wl_event_msg_t *e, void *data);
540
-#endif /* WL_SCHED_SCAN */
541
-#ifdef PNO_SUPPORT
542
-static s32 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
543
- const wl_event_msg_t *e, void *data);
544
-#endif /* PNO_SUPPORT */
545747 #ifdef GSCAN_SUPPORT
546
-static s32 wl_notify_gscan_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
547
- const wl_event_msg_t *e, void *data);
548748 static s32 wl_handle_roam_exp_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
549749 const wl_event_msg_t *e, void *data);
550750 #endif /* GSCAN_SUPPORT */
751
+#ifdef RSSI_MONITOR_SUPPORT
551752 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
552753 const wl_event_msg_t *e, void *data);
754
+#endif /* RSSI_MONITOR_SUPPORT */
553755 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
554756 enum wl_status state, bool set);
555
-#ifdef DHD_LOSSLESS_ROAMING
757
+#ifdef CUSTOM_EVENT_PM_WAKE
758
+static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
759
+ const wl_event_msg_t *e, void *data);
760
+#endif /* CUSTOM_EVENT_PM_WAKE */
761
+#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
556762 static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
557763 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
764
+#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
765
+#ifdef DHD_LOSSLESS_ROAMING
558766 static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
559767 #endif /* DHD_LOSSLESS_ROAMING */
768
+#if !defined(DISABLE_11H) && defined(DHD_NOSCAN_DURING_CSA)
769
+static void wl_del_csa_timeout(struct bcm_cfg80211 *cfg);
770
+#endif // endif
560771
561
-#ifdef WLTDLS
562
-static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
772
+#ifdef WL_MBO
773
+static s32
774
+wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
563775 const wl_event_msg_t *e, void *data);
564
-#endif /* WLTDLS */
776
+#endif /* WL_MBO */
777
+
778
+static s32
779
+wl_notify_dos_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
780
+ const wl_event_msg_t *e, void *data);
781
+#ifdef WL_SAE
782
+static s32
783
+wl_notify_extauth_req_event(struct bcm_cfg80211 *cfg,
784
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
785
+static s32
786
+wl_notify_mgmt_frame_tx_complete(struct bcm_cfg80211 *cfg,
787
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
788
+#endif /* WL_SAE */
789
+
790
+#ifdef ENABLE_HOGSQS
791
+static s32 wl_cfg80211_hogsqs_notify(struct bcm_cfg80211 *cfg,
792
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
793
+#endif /* ENABLE_HOGSQS */
794
+
565795 /*
566796 * register/deregister parent device
567797 */
....@@ -582,7 +812,6 @@
582812 */
583813 static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
584814 const wl_event_msg_t *e, const void *data, s32 item);
585
-static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item);
586815 static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
587816
588817 /*
....@@ -598,9 +827,21 @@
598827 struct cfg80211_connect_params *sme);
599828 static s32 wl_set_set_sharedkey(struct net_device *dev,
600829 struct cfg80211_connect_params *sme);
830
+#ifdef WL_FILS
831
+static s32 wl_set_fils_params(struct net_device *dev,
832
+ struct cfg80211_connect_params *sme);
833
+#endif // endif
834
+#ifdef BCMWAPI_WPI
835
+static s32 wl_set_set_wapi_ie(struct net_device *dev,
836
+ struct cfg80211_connect_params *sme);
837
+#endif // endif
838
+#ifdef WL_GCMP
839
+static s32 wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask);
840
+#endif /* WL_GCMP */
841
+
601842 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
602843 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch,
603
- struct wl_join_params *join_params, size_t *join_params_size);
844
+ struct wl_join_params *join_params, size_t *join_params_size, struct ieee80211_channel *chan);
604845 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
605846
606847 /*
....@@ -608,45 +849,31 @@
608849 */
609850 static void wl_rst_ie(struct bcm_cfg80211 *cfg);
610851 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
611
-static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, const u8 *ie_stream, u32 *ie_size,
612
- bool roam);
852
+static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 *ie_size,
853
+ bool update_ssid);
613854 static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size);
614855 static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size);
615856 static u32 wl_get_ielen(struct bcm_cfg80211 *cfg);
616857 #ifdef MFP
617
-static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa);
618
-#endif
619
-
620
-#ifdef WL11U
621
-bcm_tlv_t *
622
-wl_cfg80211_find_interworking_ie(u8 *parse, u32 len);
623
-static s32
624
-wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
625
- uint8 ie_id, uint8 *data, uint8 data_len);
626
-#endif /* WL11U */
858
+static int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie, const u8** rsn_cap);
859
+#endif // endif
627860
628861 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data);
629862 static void wl_free_wdev(struct bcm_cfg80211 *cfg);
630
-#ifdef CONFIG_CFG80211_INTERNAL_REGDB
631
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
632
-static int
633
-#else
634
-static void
635
-#endif /* kernel version < 3.10.11 */
636
-wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
637
-#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
638863
639
-static s32 wl_inform_bss(struct bcm_cfg80211 *cfg);
640
-static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam);
641
-static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam);
864
+static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool update_ssid);
865
+static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool update_ssid);
642866 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
643867 s32 wl_cfg80211_channel_to_freq(u32 channel);
644
-
645
-
646868 static void wl_cfg80211_work_handler(struct work_struct *work);
647869 static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
648870 u8 key_idx, const u8 *mac_addr,
649871 struct key_params *params);
872
+
873
+#ifdef ENABLE_HOGSQS
874
+static void wl_cfg80211_hogsqs_event_handler(struct work_struct *work);
875
+#endif // endif
876
+
650877 /*
651878 * key indianess swap utilities
652879 */
....@@ -673,16 +900,14 @@
673900 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
674901 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
675902 static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
903
+
676904 static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
677905 struct net_device *ndev);
678906 static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
679907 static void wl_link_up(struct bcm_cfg80211 *cfg);
680908 static void wl_link_down(struct bcm_cfg80211 *cfg);
681
-static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype);
909
+static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype);
682910 static void wl_init_conf(struct wl_conf *conf);
683
-static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info,
684
- struct net_device* ndev);
685
-
686911 int wl_cfg80211_get_ioctl_version(void);
687912
688913 /*
....@@ -698,11 +923,8 @@
698923 #ifdef DEBUGFS_CFG80211
699924 static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg);
700925 static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg);
701
-#endif
702
-
703
-static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel,
704
- int nprobes, int *out_params_size);
705
-static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
926
+#endif // endif
927
+static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, s32 mode, u32 dev_role);
706928
707929 #ifdef WL_CFG80211_ACL
708930 /* ACL */
....@@ -713,29 +935,153 @@
713935 /*
714936 * Some external functions, TODO: move them to dhd_linux.h
715937 */
716
-int dhd_add_monitor(char *name, struct net_device **new_ndev);
938
+#ifdef DHD_MONITOR_INTERFACE
939
+int dhd_add_monitor(const char *name, struct net_device **new_ndev);
717940 int dhd_del_monitor(struct net_device *ndev);
718941 int dhd_monitor_init(void *dhd_pub);
719942 int dhd_monitor_uninit(void);
720
-int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
721
-#ifdef BCMSDIO
722
-extern uint16 dhd_get_chipid(dhd_pub_t * dhd);
723
-#endif
943
+#ifdef CFI_CHECK
944
+netdev_tx_t
945
+#else
946
+int
947
+#endif /* CFI_CHECK */
948
+dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
949
+#endif /* DHD_MONITOR_INTERFACE */
724950
951
+#ifdef ESCAN_CHANNEL_CACHE
952
+void reset_roam_cache(struct bcm_cfg80211 *cfg);
953
+void add_roam_cache(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi);
954
+int get_roam_channel_list(int target_chan, chanspec_t *channels,
955
+ int n_channels, const wlc_ssid_t *ssid, int ioctl_ver, struct ieee80211_channel *chan);
956
+void set_roam_band(int band);
957
+#endif /* ESCAN_CHANNEL_CACHE */
958
+
959
+#ifdef ROAM_CHANNEL_CACHE
960
+int init_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
961
+void print_roam_cache(struct bcm_cfg80211 *cfg);
962
+void update_roam_cache(struct bcm_cfg80211 *cfg, int ioctl_ver);
963
+#endif /* ROAM_CHANNEL_CACHE */
964
+
965
+#ifdef P2P_LISTEN_OFFLOADING
966
+s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
967
+#endif /* P2P_LISTEN_OFFLOADING */
968
+
969
+#ifdef CUSTOMER_HW4_DEBUG
970
+extern bool wl_scan_timeout_dbg_enabled;
971
+#endif /* CUSTOMER_HW4_DEBUG */
972
+#ifdef PKT_FILTER_SUPPORT
973
+extern uint dhd_pkt_filter_enable;
974
+extern uint dhd_master_mode;
975
+extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
976
+#endif /* PKT_FILTER_SUPPORT */
977
+
978
+#ifdef SUPPORT_SET_CAC
979
+static void wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable);
980
+#endif /* SUPPORT_SET_CAC */
725981
726982 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
727983 const struct ether_addr *bssid);
984
+static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
985
+
986
+#ifdef WL_WPS_SYNC
987
+static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg);
988
+static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg);
989
+static void wl_wps_reauth_timeout(unsigned long data);
990
+static s32 wl_get_free_wps_inst(struct bcm_cfg80211 *cfg);
991
+static s32 wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev);
992
+static s32 wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *peer_mac);
993
+static void wl_wps_session_del(struct net_device *ndev);
994
+static s32 wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac);
995
+static void wl_wps_handle_ifdel(struct net_device *ndev);
996
+#endif /* WL_WPS_SYNC */
997
+
998
+#if defined(WL_FW_OCE_AP_SELECT)
999
+bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint);
1000
+#endif /* WL_FW_OCE_AP_SELECT */
1001
+
1002
+#ifdef WL_BCNRECV
1003
+static s32 wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1004
+ const wl_event_msg_t *e, void *data);
1005
+#endif /* WL_BCNRECV */
1006
+
1007
+#ifdef WL_CAC_TS
1008
+static s32 wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1009
+ const wl_event_msg_t *e, void *data);
1010
+#endif /* WL_CAC_TS */
1011
+
1012
+#if defined(WL_MBO) || defined(WL_OCE)
1013
+static s32 wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1014
+ const wl_event_msg_t *e, void *data);
1015
+#endif /* WL_MBO || WL_OCE */
7281016
7291017 static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ,
7301018 WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ };
7311019
732
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0))
733
-#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
734
- cfg80211_disconnected(dev, reason, ie, len, gfp);
735
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
736
-#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
737
- cfg80211_disconnected(dev, reason, ie, len, loc_gen, gfp);
738
-#endif
1020
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || (defined(CONFIG_ARCH_MSM) && \
1021
+ defined(CFG80211_DISCONNECTED_V2))
1022
+#define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
1023
+ cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
1024
+ IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
1025
+#else
1026
+#define CFG80211_GET_BSS(wiphy, channel, bssid, ssid, ssid_len) \
1027
+ cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, \
1028
+ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
1029
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
1030
+
1031
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
1032
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) || \
1033
+ defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE) || defined(WL_FILS) || \
1034
+ defined(CONFIG_CFG80211_FILS_BKPORT)
1035
+#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1036
+ resp_ie_len, status, gfp) \
1037
+ cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1038
+ resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
1039
+#else
1040
+#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1041
+ resp_ie_len, status, gfp) \
1042
+ cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1043
+ resp_ie_len, status, gfp);
1044
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) || \
1045
+ * (CFG80211_CONNECT_TIMEOUT_REASON_CODE) ||
1046
+ * WL_FILS || CONFIG_CFG80211_FILS_BKPORT
1047
+ */
1048
+#elif defined(CFG80211_CONNECT_TIMEOUT_REASON_CODE)
1049
+/* There are customer kernels with backported changes for
1050
+ * connect timeout. CFG80211_CONNECT_TIMEOUT_REASON_CODE define
1051
+ * is available for kernels < 4.7 in such cases.
1052
+ */
1053
+#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1054
+ resp_ie_len, status, gfp) \
1055
+ cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1056
+ resp_ie_len, status, gfp, NL80211_TIMEOUT_UNSPECIFIED);
1057
+#else
1058
+/* Kernels < 4.7 doesn't support cfg80211_connect_bss */
1059
+#define CFG80211_CONNECT_RESULT(dev, bssid, bss, req_ie, req_ie_len, resp_ie, \
1060
+ resp_ie_len, status, gfp) \
1061
+ cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, \
1062
+ resp_ie_len, status, gfp);
1063
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) */
1064
+
1065
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
1066
+#define CFG80211_RX_MGMT(ndev, freq, sig_dbm, buf, len, flags, gfp) \
1067
+ cfg80211_rx_mgmt(ndev_to_wdev(ndev), freq, sig_dbm, buf, len, flags)
1068
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) && \
1069
+ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
1070
+#define CFG80211_RX_MGMT(ndev, freq, sig_dbm, buf, len, flags, gfp) \
1071
+ cfg80211_rx_mgmt(ndev_to_wdev(ndev), freq, sig_dbm, buf, len, flags, gfp)
1072
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && \
1073
+ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)))
1074
+#define CFG80211_RX_MGMT(ndev, freq, sig_dbm, buf, len, flags, gfp) \
1075
+ cfg80211_rx_mgmt(ndev_to_wdev(ndev), freq, sig_dbm, buf, len, gfp)
1076
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) && \
1077
+ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))) || \
1078
+ defined(WL_COMPAT_WIRELESS)
1079
+#define CFG80211_RX_MGMT(ndev, freq, sig_dbm, buf, len, flags, gfp) \
1080
+ cfg80211_rx_mgmt(ndev, freq, sig_dbm, buf, len, gfp)
1081
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
1082
+#define CFG80211_RX_MGMT(ndev, freq, sig_dbm, buf, len, flags, gfp) \
1083
+ cfg80211_rx_mgmt(ndev, freq, buf, len, gfp)
1084
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) */
7391085
7401086 #ifdef RSSI_OFFSET
7411087 static s32 wl_rssi_offset(s32 rssi)
....@@ -747,21 +1093,20 @@
7471093 }
7481094 #else
7491095 #define wl_rssi_offset(x) x
750
-#endif
1096
+#endif // endif
7511097
752
-#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
753
- (akm) == RSN_AKM_UNSPECIFIED || \
1098
+#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
1099
+ (akm) == RSN_AKM_UNSPECIFIED || \
7541100 (akm) == RSN_AKM_PSK)
755
-
7561101
7571102 extern int dhd_wait_pend8021x(struct net_device *dev);
7581103 #ifdef PROP_TXSTATUS_VSDB
7591104 extern int disable_proptx;
7601105 #endif /* PROP_TXSTATUS_VSDB */
7611106
762
-
763
-extern int passive_channel_skip;
764
-
1107
+static s32
1108
+wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1109
+ const wl_event_msg_t *e, void *data);
7651110 static s32
7661111 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
7671112 const wl_event_msg_t *e, void *data);
....@@ -771,39 +1116,14 @@
7711116 int freq;
7721117 int chan_type;
7731118 };
774
-#endif
1119
+#endif // endif
7751120
1121
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
1122
+#define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(wiphy, bss);
1123
+#else
1124
+#define CFG80211_PUT_BSS(wiphy, bss) cfg80211_put_bss(bss);
1125
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
7761126
777
-#if (WL_DBG_LEVEL > 0)
778
-#define WL_DBG_ESTR_MAX 50
779
-static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = {
780
- "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND",
781
- "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC",
782
- "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END",
783
- "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM",
784
- "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH",
785
- "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND",
786
- "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND",
787
- "PFN_NET_LOST",
788
- "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START",
789
- "IBSS_ASSOC",
790
- "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT",
791
- "PROBREQ_MSG",
792
- "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED",
793
- "EXCEEDED_MEDIUM_TIME", "ICV_ERROR",
794
- "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE",
795
- "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE",
796
- "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG",
797
- "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND",
798
- "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED",
799
- "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT",
800
- "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE",
801
- "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP",
802
- "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE"
803
-};
804
-#endif /* WL_DBG_LEVEL */
805
-
806
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
8071127 #define CHAN2G(_channel, _freq, _flags) { \
8081128 .band = IEEE80211_BAND_2GHZ, \
8091129 .center_freq = (_freq), \
....@@ -821,25 +1141,17 @@
8211141 .max_antenna_gain = 0, \
8221142 .max_power = 30, \
8231143 }
824
-#else
825
-#define CHAN2G(_channel, _freq, _flags) { \
826
- .band = NL80211_BAND_2GHZ, \
827
- .center_freq = (_freq), \
828
- .hw_value = (_channel), \
829
- .flags = (_flags), \
830
- .max_antenna_gain = 0, \
831
- .max_power = 30, \
832
-}
8331144
834
-#define CHAN5G(_channel, _flags) { \
835
- .band = NL80211_BAND_5GHZ, \
836
- .center_freq = 5000 + (5 * (_channel)), \
1145
+#ifdef WL_6E
1146
+#define CHAN6G(_channel, _flags) { \
1147
+ .band = IEEE80211_BAND_6GHZ, \
1148
+ .center_freq = 5950 + (5 * (_channel)), \
8371149 .hw_value = (_channel), \
8381150 .flags = (_flags), \
8391151 .max_antenna_gain = 0, \
8401152 .max_power = 30, \
8411153 }
842
-#endif /* if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
1154
+#endif /* WL_6E */
8431155
8441156 #define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
8451157 #define RATETAB_ENT(_rateid, _flags) \
....@@ -904,20 +1216,98 @@
9041216 CHAN5G(165, 0)
9051217 };
9061218
907
-/* Global define the IEEE80211_BAND_XX to NL80211_BAND_xx here
908
- * to prevent the verbosely #if #else for KERNEL VERSION
909
- * Except the ones in CHAN2G()/CHAN5G which cannot be changed from here
910
- */
911
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 7, 0))
912
-#define IEEE80211_BAND_2GHZ NL80211_BAND_2GHZ
913
-#define IEEE80211_BAND_5GHZ NL80211_BAND_5GHZ
914
-#endif
1219
+#ifdef WL_6E
1220
+static struct ieee80211_channel __wl_6ghz_a_channels[] = {
1221
+ CHAN6G(1, 0), CHAN6G(5, 0), CHAN6G(9, 0), CHAN6G(13, 0),
1222
+ CHAN6G(17, 0), CHAN6G(21, 0), CHAN6G(25, 0), CHAN6G(29, 0),
1223
+ CHAN6G(33, 0), CHAN6G(37, 0), CHAN6G(41, 0), CHAN6G(45, 0),
1224
+ CHAN6G(49, 0), CHAN6G(53, 0), CHAN6G(57, 0), CHAN6G(61, 0),
1225
+ CHAN6G(65, 0), CHAN6G(69, 0), CHAN6G(73, 0), CHAN6G(77, 0),
1226
+ CHAN6G(81, 0), CHAN6G(85, 0), CHAN6G(89, 0), CHAN6G(93, 0),
1227
+ CHAN6G(97, 0), CHAN6G(101, 0), CHAN6G(105, 0), CHAN6G(109, 0),
1228
+ CHAN6G(113, 0), CHAN6G(117, 0), CHAN6G(121, 0), CHAN6G(125, 0),
1229
+ CHAN6G(129, 0), CHAN6G(133, 0), CHAN6G(137, 0), CHAN6G(141, 0),
1230
+ CHAN6G(145, 0), CHAN6G(149, 0), CHAN6G(153, 0), CHAN6G(157, 0),
1231
+ CHAN6G(161, 0), CHAN6G(165, 0), CHAN6G(169, 0), CHAN6G(173, 0),
1232
+ CHAN6G(177, 0), CHAN6G(181, 0), CHAN6G(185, 0), CHAN6G(189, 0),
1233
+ CHAN6G(193, 0), CHAN6G(197, 0), CHAN6G(201, 0), CHAN6G(205, 0),
1234
+ CHAN6G(209, 0), CHAN6G(213, 0), CHAN6G(217, 0), CHAN6G(221, 0),
1235
+ CHAN6G(225, 0), CHAN6G(229, 0), CHAN6G(233, 0)
1236
+};
1237
+#endif /* WL_6E */
1238
+
1239
+#ifdef WL11AX
1240
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 21))
1241
+static u32 he = 0;
1242
+struct ieee80211_sband_iftype_data sdata[IEEE80211_NUM_BANDS];
1243
+static int wl_update_he_cap(struct bcm_cfg80211 *cfg, struct ieee80211_sband_iftype_data *data, int band)
1244
+{
1245
+ int idx = 1;
1246
+ struct ieee80211_sta_he_cap *he_cap = &data->he_cap;
1247
+ struct ieee80211_he_cap_elem *he_cap_elem =
1248
+ &he_cap->he_cap_elem;
1249
+ struct ieee80211_he_mcs_nss_supp *he_mcs =
1250
+ &he_cap->he_mcs_nss_supp;
1251
+
1252
+ if(data == NULL) {
1253
+ WL_ERR(("failed to allco mem\n"));
1254
+ return 0;
1255
+ }
1256
+
1257
+ data->types_mask= BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP);
1258
+ he_cap->has_he = true;
1259
+ he_cap_elem->mac_cap_info[0] =
1260
+ IEEE80211_HE_MAC_CAP0_HTC_HE | IEEE80211_HE_MAC_CAP0_TWT_REQ;
1261
+
1262
+ he_cap_elem->mac_cap_info[2] =
1263
+ IEEE80211_HE_MAC_CAP2_BSR;
1264
+ if ((band == NL80211_BAND_5GHZ) || (band == NL80211_BAND_6GHZ))
1265
+ he_cap_elem->phy_cap_info[0] =
1266
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
1267
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
1268
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
1269
+ he_cap_elem->phy_cap_info[1] =
1270
+ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
1271
+ he_cap_elem->phy_cap_info[2] =
1272
+ IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US;
1273
+ he_cap_elem->phy_cap_info[3] =
1274
+ IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
1275
+ he_cap_elem->phy_cap_info[4] =
1276
+ IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
1277
+ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK |
1278
+ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
1279
+ he_cap_elem->phy_cap_info[5] =
1280
+ IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2;
1281
+ he_cap_elem->phy_cap_info[6] =
1282
+ IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
1283
+ IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
1284
+ IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
1285
+ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
1286
+ IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
1287
+ IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
1288
+ he_cap_elem->phy_cap_info[7] =
1289
+ IEEE80211_HE_PHY_CAP7_MAX_NC_1;
1290
+ he_cap_elem->phy_cap_info[8] =
1291
+ IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
1292
+ IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU;
1293
+ he_cap_elem->phy_cap_info[9] =
1294
+ IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
1295
+ IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
1296
+ he_mcs->rx_mcs_80 = cpu_to_le16(0xfffa);
1297
+ he_mcs->tx_mcs_80 = cpu_to_le16(0xfffa);
1298
+ he_mcs->rx_mcs_160 = cpu_to_le16((0xfffa));
1299
+ he_mcs->tx_mcs_160 = cpu_to_le16((0xfffa));
1300
+ return idx;
1301
+}
1302
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 21) */
1303
+#endif /* WL11AX */
1304
+
9151305 static struct ieee80211_supported_band __wl_band_2ghz = {
9161306 .band = IEEE80211_BAND_2GHZ,
9171307 .channels = __wl_2ghz_channels,
9181308 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
9191309 .bitrates = wl_g_rates,
920
- .n_bitrates = wl_g_rates_size
1310
+ .n_bitrates = wl_g_rates_size,
9211311 };
9221312
9231313 static struct ieee80211_supported_band __wl_band_5ghz_a = {
....@@ -925,26 +1315,49 @@
9251315 .channels = __wl_5ghz_a_channels,
9261316 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
9271317 .bitrates = wl_a_rates,
928
- .n_bitrates = wl_a_rates_size
1318
+ .n_bitrates = wl_a_rates_size,
9291319 };
9301320
931
-#if defined(WLFBT)
932
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
933
-#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03
934
-#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04
935
-#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) */
936
-#define WLAN_CIPHER_SUITE_PMK 0x00904C00
937
-#endif /* WLFBT */
1321
+#ifdef WL_6E
1322
+static struct ieee80211_supported_band __wl_band_6ghz = {
1323
+ .band = IEEE80211_BAND_6GHZ,
1324
+ .channels = __wl_6ghz_a_channels,
1325
+ .n_channels = ARRAY_SIZE(__wl_6ghz_a_channels),
1326
+ .bitrates = wl_a_rates,
1327
+ .n_bitrates = wl_a_rates_size,
1328
+};
1329
+#endif /* WL_6E */
9381330
9391331 static const u32 __wl_cipher_suites[] = {
9401332 WLAN_CIPHER_SUITE_WEP40,
9411333 WLAN_CIPHER_SUITE_WEP104,
9421334 WLAN_CIPHER_SUITE_TKIP,
9431335 WLAN_CIPHER_SUITE_CCMP,
1336
+#ifdef MFP
1337
+ /*
1338
+ * Advertising AES_CMAC cipher suite to userspace would imply that we
1339
+ * are supporting MFP. So advertise only when MFP support is enabled.
1340
+ */
9441341 WLAN_CIPHER_SUITE_AES_CMAC,
945
-#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK)
1342
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1343
+ WLAN_CIPHER_SUITE_BIP_GMAC_256,
1344
+ WLAN_CIPHER_SUITE_BIP_GMAC_128,
1345
+ WLAN_CIPHER_SUITE_BIP_CMAC_256,
1346
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1347
+#endif /* MFP */
1348
+
1349
+#ifdef BCMWAPI_WPI
1350
+ WLAN_CIPHER_SUITE_SMS4,
1351
+#endif // endif
1352
+#if defined(WLAN_CIPHER_SUITE_PMK)
9461353 WLAN_CIPHER_SUITE_PMK,
947
-#endif
1354
+#endif /* WLAN_CIPHER_SUITE_PMK */
1355
+#ifdef WL_GCMP
1356
+ WLAN_CIPHER_SUITE_GCMP,
1357
+ WLAN_CIPHER_SUITE_GCMP_256,
1358
+ WLAN_CIPHER_SUITE_BIP_GMAC_128,
1359
+ WLAN_CIPHER_SUITE_BIP_GMAC_256,
1360
+#endif /* WL_GCMP */
9481361 };
9491362
9501363 #ifdef WL_SUPPORT_ACS
....@@ -963,15 +1376,19 @@
9631376 };
9641377 #endif /* WL_SUPPORT_ACS */
9651378
1379
+#ifdef WL_CFG80211_GON_COLLISION
1380
+#define BLOCK_GON_REQ_MAX_NUM 5
1381
+#endif /* WL_CFG80211_GON_COLLISION */
9661382
9671383 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
9681384 static int maxrxpktglom = 0;
969
-#endif
1385
+#endif // endif
9701386
9711387 /* IOCtl version read from targeted driver */
972
-static int ioctl_version;
1388
+int ioctl_version;
9731389 #ifdef DEBUGFS_CFG80211
974
-#define S_SUBLOGLEVEL 20
1390
+#define SUBLOGLEVEL 20
1391
+#define SUBLOGLEVELZ ((SUBLOGLEVEL) + (1))
9751392 static const struct {
9761393 u32 log_level;
9771394 char *sublogname;
....@@ -983,44 +1400,133 @@
9831400 {WL_DBG_TRACE, "TRACE"},
9841401 {WL_DBG_P2P_ACTION, "P2PACTION"}
9851402 };
986
-#endif
1403
+#endif // endif
9871404
1405
+typedef struct rsn_cipher_algo_entry {
1406
+ u32 cipher_suite;
1407
+ u32 wsec_algo;
1408
+ u32 wsec_key_algo;
1409
+} rsn_cipher_algo_entry_t;
9881410
989
-static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg, bool add_remove,
990
- enum wl_handler_del_type type)
1411
+static const rsn_cipher_algo_entry_t rsn_cipher_algo_lookup_tbl[] = {
1412
+ {WLAN_CIPHER_SUITE_WEP40, WEP_ENABLED, CRYPTO_ALGO_WEP1},
1413
+ {WLAN_CIPHER_SUITE_WEP104, WEP_ENABLED, CRYPTO_ALGO_WEP128},
1414
+ {WLAN_CIPHER_SUITE_TKIP, TKIP_ENABLED, CRYPTO_ALGO_TKIP},
1415
+ {WLAN_CIPHER_SUITE_CCMP, AES_ENABLED, CRYPTO_ALGO_AES_CCM},
1416
+ {WLAN_CIPHER_SUITE_AES_CMAC, AES_ENABLED, CRYPTO_ALGO_BIP},
1417
+#ifdef BCMWAPI_WPI
1418
+ {WLAN_CIPHER_SUITE_SMS4, SMS4_ENABLED, CRYPTO_ALGO_SMS4},
1419
+#endif /* BCMWAPI_WPI */
1420
+#ifdef WL_GCMP
1421
+ {WLAN_CIPHER_SUITE_GCMP, AES_ENABLED, CRYPTO_ALGO_AES_GCM},
1422
+ {WLAN_CIPHER_SUITE_GCMP_256, AES_ENABLED, CRYPTO_ALGO_AES_GCM256},
1423
+ {WLAN_CIPHER_SUITE_BIP_GMAC_128, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC},
1424
+ {WLAN_CIPHER_SUITE_BIP_GMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_GMAC256},
1425
+#endif /* WL_GCMP */
1426
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
1427
+ {WLAN_CIPHER_SUITE_BIP_CMAC_256, AES_ENABLED, CRYPTO_ALGO_BIP_CMAC256},
1428
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
1429
+};
1430
+
1431
+typedef struct rsn_akm_wpa_auth_entry {
1432
+ u32 akm_suite;
1433
+ u32 wpa_auth;
1434
+} rsn_akm_wpa_auth_entry_t;
1435
+
1436
+static const rsn_akm_wpa_auth_entry_t rsn_akm_wpa_auth_lookup_tbl[] = {
1437
+#ifdef WL_OWE
1438
+ {WLAN_AKM_SUITE_OWE, WPA3_AUTH_OWE},
1439
+#endif /* WL_OWE */
1440
+ {WLAN_AKM_SUITE_8021X, WPA2_AUTH_UNSPECIFIED},
1441
+ {WL_AKM_SUITE_SHA256_1X, WPA2_AUTH_1X_SHA256},
1442
+ {WL_AKM_SUITE_SHA256_PSK, WPA2_AUTH_PSK_SHA256},
1443
+ {WLAN_AKM_SUITE_PSK, WPA2_AUTH_PSK},
1444
+ {WLAN_AKM_SUITE_FT_8021X, WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT},
1445
+ {WLAN_AKM_SUITE_FT_PSK, WPA2_AUTH_PSK | WPA2_AUTH_FT},
1446
+ {WLAN_AKM_SUITE_FILS_SHA256, WPA2_AUTH_FILS_SHA256},
1447
+ {WLAN_AKM_SUITE_FILS_SHA384, WPA2_AUTH_FILS_SHA384},
1448
+ {WLAN_AKM_SUITE_8021X_SUITE_B, WPA3_AUTH_1X_SUITE_B_SHA256},
1449
+ {WLAN_AKM_SUITE_8021X_SUITE_B_192, WPA3_AUTH_1X_SUITE_B_SHA384},
1450
+#ifdef BCMWAPI_WPI
1451
+ {WLAN_AKM_SUITE_WAPI_CERT, WAPI_AUTH_UNSPECIFIED},
1452
+ {WLAN_AKM_SUITE_WAPI_PSK, WAPI_AUTH_PSK},
1453
+#endif /* BCMWAPI_WPI */
1454
+#ifdef WL_SAE
1455
+ {WLAN_AKM_SUITE_SAE, WPA3_AUTH_SAE_PSK},
1456
+#endif /* WL_SAE */
1457
+ {WLAN_AKM_SUITE_FT_8021X_SHA384, WPA3_AUTH_1X_SHA384 | WPA2_AUTH_FT},
1458
+ {WLAN_AKM_SUITE_DPP, WPA2_WFA_AUTH_DPP}
1459
+};
1460
+
1461
+#define BUFSZ 8
1462
+#define BUFSZN BUFSZ + 1
1463
+
1464
+#define _S(x) #x
1465
+#define S(x) _S(x)
1466
+
1467
+#define SOFT_AP_IF_NAME "swlan0"
1468
+
1469
+/* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
1470
+uint32 fw_assoc_watchdog_ms = 0;
1471
+bool fw_assoc_watchdog_started = 0;
1472
+#define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
1473
+
1474
+static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg,
1475
+ enum wl_pm_workq_act_type type)
9911476 {
1477
+ u16 wq_duration = 0;
1478
+#if defined(OEM_ANDROID)
1479
+ dhd_pub_t *dhd = NULL;
1480
+#endif /* BCMDONGLEHOST && OEM_ANDROID */
1481
+
9921482 if (cfg == NULL)
9931483 return;
9941484
995
- if (cfg->pm_enable_work_on) {
996
- if (add_remove) {
997
- schedule_delayed_work(&cfg->pm_enable_work,
998
- msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT));
999
- } else {
1000
- cancel_delayed_work_sync(&cfg->pm_enable_work);
1485
+#if defined(OEM_ANDROID)
1486
+ dhd = (dhd_pub_t *)(cfg->pub);
1487
+#endif /* BCMDONGLEHOST && OEM_ANDROID */
10011488
1002
- switch (type) {
1003
- case WL_HANDLER_MAINTAIN:
1004
- schedule_delayed_work(&cfg->pm_enable_work,
1005
- msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT));
1006
- break;
1007
- case WL_HANDLER_PEND:
1008
- schedule_delayed_work(&cfg->pm_enable_work,
1009
- msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT*2));
1010
- break;
1011
- case WL_HANDLER_DEL:
1012
- default:
1013
- cfg->pm_enable_work_on = false;
1014
- break;
1015
- }
1489
+ mutex_lock(&cfg->pm_sync);
1490
+ /*
1491
+ * Make cancel and schedule work part mutually exclusive
1492
+ * so that while cancelling, we are sure that there is no
1493
+ * work getting scheduled.
1494
+ */
1495
+ if (delayed_work_pending(&cfg->pm_enable_work)) {
1496
+ cancel_delayed_work(&cfg->pm_enable_work);
1497
+#if defined(OEM_ANDROID)
1498
+ DHD_PM_WAKE_UNLOCK(cfg->pub);
1499
+#endif /* BCMDONGLEHOST && OEM_ANDROID */
1500
+ }
1501
+
1502
+ if (type == WL_PM_WORKQ_SHORT) {
1503
+ wq_duration = WL_PM_ENABLE_TIMEOUT;
1504
+ } else if (type == WL_PM_WORKQ_LONG) {
1505
+ wq_duration = (WL_PM_ENABLE_TIMEOUT*2);
1506
+ }
1507
+
1508
+ /* It should schedule work item only if driver is up */
1509
+#if defined(OEM_ANDROID)
1510
+ if (wq_duration && dhd->up) {
1511
+#else
1512
+ if (wq_duration) {
1513
+#endif /* BCMDONGLEHOST && OEM_ANDROID */
1514
+ if (schedule_delayed_work(&cfg->pm_enable_work,
1515
+ msecs_to_jiffies((const unsigned int)wq_duration))) {
1516
+#if defined(OEM_ANDROID)
1517
+ DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub, wq_duration);
1518
+#endif /* BCMDONGLEHOST && OEM_ANDROID */
1519
+ } else {
1520
+ WL_ERR(("Can't schedule pm work handler\n"));
10161521 }
10171522 }
1523
+ mutex_unlock(&cfg->pm_sync);
10181524 }
10191525
10201526 /* Return a new chanspec given a legacy chanspec
10211527 * Returns INVCHANSPEC on error
10221528 */
1023
-static chanspec_t
1529
+chanspec_t
10241530 wl_chspec_from_legacy(chanspec_t legacy_chspec)
10251531 {
10261532 chanspec_t chspec;
....@@ -1049,7 +1555,7 @@
10491555
10501556 if (wf_chspec_malformed(chspec)) {
10511557 WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
1052
- chspec));
1558
+ chspec));
10531559 return INVCHANSPEC;
10541560 }
10551561
....@@ -1066,7 +1572,7 @@
10661572
10671573 if (wf_chspec_malformed(chspec)) {
10681574 WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
1069
- chspec));
1575
+ chspec));
10701576 return INVCHANSPEC;
10711577 }
10721578
....@@ -1095,13 +1601,18 @@
10951601 /* cannot express the bandwidth */
10961602 char chanbuf[CHANSPEC_STR_LEN];
10971603 WL_ERR((
1098
- "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1099
- "to pre-11ac format\n",
1100
- wf_chspec_ntoa(chspec, chanbuf), chspec));
1604
+ "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
1605
+ "to pre-11ac format\n",
1606
+ wf_chspec_ntoa(chspec, chanbuf), chspec));
11011607 return INVCHANSPEC;
11021608 }
11031609
11041610 return lchspec;
1611
+}
1612
+
1613
+bool wl_cfg80211_is_hal_started(struct bcm_cfg80211 *cfg)
1614
+{
1615
+ return cfg->hal_started;
11051616 }
11061617
11071618 /* given a chanspec value, do the endian and chanspec version conversion to
....@@ -1127,20 +1638,17 @@
11271638 * Returns INVCHANSPEC on error
11281639 */
11291640 chanspec_t
1130
-wl_ch_host_to_driver(s32 bssidx, u16 channel)
1641
+wl_ch_host_to_driver(u16 channel)
11311642 {
11321643 chanspec_t chanspec;
1644
+ chanspec_band_t band;
11331645
1134
- chanspec = channel & WL_CHANSPEC_CHAN_MASK;
1646
+ band = WL_CHANNEL_BAND(channel);
11351647
1136
- if (channel <= CH_MAX_2G_CHANNEL)
1137
- chanspec |= WL_CHANSPEC_BAND_2G;
1138
- else
1139
- chanspec |= WL_CHANSPEC_BAND_5G;
1140
-
1141
- chanspec |= wl_cfg80211_ulb_get_min_bw_chspec(NULL, bssidx);
1142
-
1143
- chanspec |= WL_CHANSPEC_CTL_SB_NONE;
1648
+ chanspec = wf_create_20MHz_chspec(channel, band);
1649
+ if (chanspec == INVCHANSPEC) {
1650
+ return chanspec;
1651
+ }
11441652
11451653 return wl_chspec_host_to_driver(chanspec);
11461654 }
....@@ -1170,7 +1678,7 @@
11701678 char *c = NULL;
11711679 int count = 0;
11721680
1173
- memset(n, 0, ETHER_ADDR_LEN);
1681
+ bzero(n, ETHER_ADDR_LEN);
11741682 for (;;) {
11751683 n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
11761684 if (!*c++ || count == ETHER_ADDR_LEN)
....@@ -1190,6 +1698,9 @@
11901698 [NL80211_IFTYPE_STATION] = {
11911699 .tx = 0xffff,
11921700 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
1701
+#ifdef WL_SAE
1702
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
1703
+#endif /* WL_SAE */
11931704 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
11941705 },
11951706 [NL80211_IFTYPE_AP] = {
....@@ -1259,13 +1770,54 @@
12591770 key->iv_initialized = dtoh32(key->iv_initialized);
12601771 }
12611772
1773
+#if defined(WL_FW_OCE_AP_SELECT)
1774
+bool static wl_cfg80211_is_oce_ap(struct wiphy *wiphy, const u8 *bssid_hint)
1775
+{
1776
+ const u8 *parse = NULL;
1777
+ bcm_tlv_t *ie;
1778
+ const struct cfg80211_bss_ies *ies;
1779
+ u32 len;
1780
+ struct cfg80211_bss *bss;
1781
+
1782
+ bss = CFG80211_GET_BSS(wiphy, NULL, bssid_hint, 0, 0);
1783
+ if (!bss) {
1784
+ WL_ERR(("Unable to find AP in the cache"));
1785
+ return false;
1786
+ }
1787
+
1788
+ if (rcu_access_pointer(bss->ies)) {
1789
+ ies = rcu_access_pointer(bss->ies);
1790
+ parse = ies->data;
1791
+ len = ies->len;
1792
+ } else {
1793
+ WL_ERR(("ies is NULL"));
1794
+ return false;
1795
+ }
1796
+
1797
+ while ((ie = bcm_parse_tlvs(parse, len, DOT11_MNG_VS_ID))) {
1798
+ if (wl_cfgoce_is_oce_ie((const uint8*)ie, (u8 const **)&parse, &len) == TRUE) {
1799
+ return true;
1800
+ } else {
1801
+ ie = bcm_next_tlv((const bcm_tlv_t*) ie, &len);
1802
+ if (!ie) {
1803
+ return false;
1804
+ }
1805
+ parse = (uint8 *)ie;
1806
+ WL_DBG(("NON OCE IE. next ie ptr:%p", parse));
1807
+ }
1808
+ }
1809
+ WL_DBG(("OCE IE NOT found"));
1810
+ return false;
1811
+}
1812
+#endif /* WL_FW_OCE_AP_SELECT */
1813
+
12621814 /* Dump the contents of the encoded wps ie buffer and get pbc value */
12631815 static void
1264
-wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc)
1816
+wl_validate_wps_ie(const char *wps_ie, s32 wps_ie_len, bool *pbc)
12651817 {
12661818 #define WPS_IE_FIXED_LEN 6
1267
- u16 len;
1268
- u8 *subel = NULL;
1819
+ s16 len;
1820
+ const u8 *subel = NULL;
12691821 u16 subelt_id;
12701822 u16 subelt_len;
12711823 u16 val;
....@@ -1274,7 +1826,7 @@
12741826 WL_ERR(("invalid argument : NULL\n"));
12751827 return;
12761828 }
1277
- len = (u16)wps_ie[TLV_LEN_OFF];
1829
+ len = (s16)wps_ie[TLV_LEN_OFF];
12781830
12791831 if (len > wps_ie_len) {
12801832 WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
....@@ -1293,7 +1845,10 @@
12931845 subelt_len = HTON16(val);
12941846
12951847 len -= 4; /* for the attr id, attr len fields */
1296
- len -= subelt_len; /* for the remaining fields in this attribute */
1848
+ len -= (s16)subelt_len; /* for the remaining fields in this attribute */
1849
+ if (len < 0) {
1850
+ break;
1851
+ }
12971852 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
12981853 subel, subelt_id, subelt_len));
12991854
....@@ -1306,11 +1861,16 @@
13061861 valptr[1] = *(subel + 1);
13071862 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
13081863 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
1309
- char devname[100];
1310
- memcpy(devname, subel, subelt_len);
1311
- devname[subelt_len] = '\0';
1312
- WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1313
- devname, subelt_len));
1864
+ char devname[33];
1865
+ int namelen = MIN(subelt_len, (sizeof(devname) - 1));
1866
+
1867
+ if (namelen) {
1868
+ memcpy(devname, subel, namelen);
1869
+ devname[namelen] = '\0';
1870
+ /* Printing len as rx'ed in the IE */
1871
+ WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
1872
+ devname, subelt_len));
1873
+ }
13141874 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
13151875 valptr[0] = *subel;
13161876 valptr[1] = *(subel + 1);
....@@ -1349,12 +1909,12 @@
13491909 s32 err = 0;
13501910 s32 disable = 0;
13511911 s32 txpwrqdbm;
1352
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
1912
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
13531913
13541914 /* Make sure radio is off or on as far as software is concerned */
13551915 disable = WL_RADIO_SW_DISABLE << 16;
13561916 disable = htod32(disable);
1357
- err = wldev_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable), true);
1917
+ err = wldev_ioctl_set(dev, WLC_SET_RADIO, &disable, sizeof(disable));
13581918 if (unlikely(err)) {
13591919 WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
13601920 return err;
....@@ -1363,6 +1923,12 @@
13631923 if (dbm > 0xffff)
13641924 dbm = 0xffff;
13651925 txpwrqdbm = dbm * 4;
1926
+#ifdef SUPPORT_WL_TXPOWER
1927
+ if (type == NL80211_TX_POWER_AUTOMATIC)
1928
+ txpwrqdbm = 127;
1929
+ else
1930
+ txpwrqdbm |= WL_TXPWR_OVERRIDE;
1931
+#endif /* SUPPORT_WL_TXPOWER */
13661932 err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
13671933 sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
13681934 &cfg->ioctl_buf_sync);
....@@ -1378,20 +1944,20 @@
13781944 {
13791945 s32 err = 0;
13801946 s32 txpwrdbm;
1381
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
1947
+ char ioctl_buf[WLC_IOCTL_SMLEN];
13821948
13831949 err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
1384
- NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
1950
+ NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
13851951 if (unlikely(err)) {
13861952 WL_ERR(("error (%d)\n", err));
13871953 return err;
13881954 }
13891955
1390
- memcpy(&txpwrdbm, cfg->ioctl_buf, sizeof(txpwrdbm));
1956
+ memcpy(&txpwrdbm, ioctl_buf, sizeof(txpwrdbm));
13911957 txpwrdbm = dtoh32(txpwrdbm);
13921958 *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
13931959
1394
- WL_INFORM(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
1960
+ WL_DBG(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
13951961
13961962 return err;
13971963 }
....@@ -1399,65 +1965,1414 @@
13991965 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
14001966 {
14011967 chanspec_t chspec;
1402
- int err = 0;
1968
+ int cur_band, err = 0;
14031969 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
14041970 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
14051971 struct ether_addr bssid;
1406
- struct wl_bss_info *bss = NULL;
1407
- s32 bssidx = 0; /* Explicitly set to primary bssidx */
1972
+ wl_bss_info_t *bss = NULL;
1973
+ u16 channel = WL_P2P_TEMP_CHAN;
14081974 char *buf;
14091975
1410
- memset(&bssid, 0, sizeof(bssid));
1411
- if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) {
1976
+ bzero(&bssid, sizeof(bssid));
1977
+ if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, sizeof(bssid)))) {
14121978 /* STA interface is not associated. So start the new interface on a temp
14131979 * channel . Later proper channel will be applied by the above framework
14141980 * via set_channel (cfg80211 API).
14151981 */
1416
- WL_DBG(("Not associated. Return first channel from supported channel list. \n"));
1417
-
1418
- if (!wldev_iovar_getint(dev, "chanspec", (s32*) &chspec)) {
1419
- return chspec;
1420
- } else {
1421
- return wl_ch_host_to_driver(bssidx, WL_P2P_TEMP_CHAN);
1982
+ WL_DBG(("Not associated. Return a temp channel. \n"));
1983
+ cur_band = 0;
1984
+ err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band, sizeof(int));
1985
+ if (unlikely(err)) {
1986
+ WL_ERR(("Get band failed\n"));
1987
+ } else if (cur_band == WLC_BAND_5G) {
1988
+ channel = WL_P2P_TEMP_CHAN_5G;
14221989 }
1990
+ return wl_ch_host_to_driver(channel);
14231991 }
1424
-
1425
- buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
1992
+
1993
+ buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
14261994 if (!buf) {
14271995 WL_ERR(("buf alloc failed. use temp channel\n"));
1428
- return wl_ch_host_to_driver(bssidx, WL_P2P_TEMP_CHAN);
1996
+ return wl_ch_host_to_driver(channel);
14291997 }
14301998
14311999 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1432
- if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, buf,
1433
- WL_EXTRA_BUF_MAX, false))) {
2000
+ if ((err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, buf,
2001
+ WL_EXTRA_BUF_MAX))) {
14342002 WL_ERR(("Failed to get associated bss info, use temp channel \n"));
1435
- chspec = wl_ch_host_to_driver(bssidx, WL_P2P_TEMP_CHAN);
2003
+ chspec = wl_ch_host_to_driver(channel);
14362004 }
14372005 else {
1438
- bss = (struct wl_bss_info *) (buf + 4);
1439
- chspec = bss->chanspec;
2006
+ bss = (wl_bss_info_t *) (buf + 4);
2007
+ chspec = bss->chanspec;
2008
+#ifdef WL_6E
2009
+ /* Avoid p2p bring up in 6G based on bssinfo */
2010
+ if (CHSPEC_IS6G(chspec)) {
2011
+ channel = WL_P2P_TEMP_CHAN_5G;
2012
+ chspec = wl_ch_host_to_driver(channel);
2013
+ }
2014
+#endif /* WL_6E */
14402015
14412016 WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
14422017 }
14432018
1444
- kfree(buf);
2019
+ MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
14452020 return chspec;
14462021 }
14472022
1448
-static bcm_struct_cfgdev *
1449
-wl_cfg80211_add_monitor_if(char *name)
2023
+static void
2024
+wl_wlfc_enable(struct bcm_cfg80211 *cfg, bool enable)
2025
+{
2026
+#ifdef PROP_TXSTATUS_VSDB
2027
+#if defined(BCMSDIO)
2028
+ bool wlfc_enabled = FALSE;
2029
+ s32 err;
2030
+ dhd_pub_t *dhd;
2031
+ struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
2032
+
2033
+ dhd = (dhd_pub_t *)(cfg->pub);
2034
+ if (!dhd) {
2035
+ return;
2036
+ }
2037
+
2038
+ if (enable) {
2039
+ if (!cfg->wlfc_on && !disable_proptx) {
2040
+ dhd_wlfc_get_enable(dhd, &wlfc_enabled);
2041
+ if (!wlfc_enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
2042
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
2043
+ dhd_wlfc_init(dhd);
2044
+ err = wldev_ioctl_set(primary_ndev, WLC_UP, &up, sizeof(s32));
2045
+ if (err < 0)
2046
+ WL_ERR(("WLC_UP return err:%d\n", err));
2047
+ }
2048
+ cfg->wlfc_on = true;
2049
+ WL_DBG(("wlfc_on:%d \n", cfg->wlfc_on));
2050
+ }
2051
+ } else {
2052
+ dhd_wlfc_get_enable(dhd, &wlfc_enabled);
2053
+ if (wlfc_enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
2054
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
2055
+ cfg->wlfc_on = false;
2056
+ }
2057
+ }
2058
+#endif /* defined(BCMSDIO) */
2059
+#endif /* PROP_TXSTATUS_VSDB */
2060
+}
2061
+
2062
+struct wireless_dev *
2063
+wl_cfg80211_p2p_if_add(struct bcm_cfg80211 *cfg,
2064
+ wl_iftype_t wl_iftype,
2065
+ char const *name, u8 *mac_addr, s32 *ret_err)
2066
+{
2067
+ u16 chspec;
2068
+ s16 cfg_type;
2069
+ long timeout;
2070
+ s32 err;
2071
+ u16 p2p_iftype;
2072
+ int dhd_mode;
2073
+ struct net_device *new_ndev = NULL;
2074
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
2075
+ struct ether_addr *p2p_addr;
2076
+#if defined(WL_SUPPORT_MULTIP2P)
2077
+ s32 is_mp2p_supported = BCME_ERROR;
2078
+#endif // endif
2079
+
2080
+ *ret_err = BCME_OK;
2081
+ if (!cfg->p2p) {
2082
+ WL_ERR(("p2p not initialized\n"));
2083
+ return NULL;
2084
+ }
2085
+
2086
+#if defined(WL_CFG80211_P2P_DEV_IF)
2087
+ if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
2088
+ /* Handle Dedicated P2P discovery Interface */
2089
+ cfg->down_disc_if = FALSE;
2090
+ return wl_cfgp2p_add_p2p_disc_if(cfg);
2091
+ }
2092
+#endif /* WL_CFG80211_P2P_DEV_IF */
2093
+
2094
+#if defined(WL_SUPPORT_MULTIP2P)
2095
+ is_mp2p_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_MP2P_MODE);
2096
+#endif /* WL_SUPPORT_MULTIP2P */
2097
+ if (wl_iftype == WL_IF_TYPE_P2P_GO) {
2098
+ p2p_iftype = WL_P2P_IF_GO;
2099
+ } else {
2100
+ p2p_iftype = WL_P2P_IF_CLIENT;
2101
+ }
2102
+
2103
+ /* Dual p2p doesn't support multiple P2PGO interfaces,
2104
+ * p2p_go_count is the counter for GO creation
2105
+ * requests.
2106
+ */
2107
+ if (TRUE &&
2108
+#if defined(WL_SUPPORT_MULTIP2P)
2109
+ (is_mp2p_supported <= 0) &&
2110
+#endif // endif
2111
+ ((cfg->p2p->p2p_go_count > 0) && (wl_iftype == WL_IF_TYPE_P2P_GO))) {
2112
+ WL_ERR(("FW does not support multiple GO\n"));
2113
+ *ret_err = -ENOTSUPP;
2114
+ return NULL;
2115
+ }
2116
+ if (!cfg->p2p->on) {
2117
+ p2p_on(cfg) = true;
2118
+ wl_cfgp2p_set_firm_p2p(cfg);
2119
+ wl_cfgp2p_init_discovery(cfg);
2120
+ }
2121
+
2122
+ strlcpy(cfg->p2p->vir_ifname, name, sizeof(cfg->p2p->vir_ifname));
2123
+ /* In concurrency case, STA may be already associated in a particular channel.
2124
+ * so retrieve the current channel of primary interface and then start the virtual
2125
+ * interface on that.
2126
+ */
2127
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
2128
+
2129
+ /* For P2P mode, use P2P-specific driver features to create the
2130
+ * bss: "cfg p2p_ifadd"
2131
+ */
2132
+ wl_set_p2p_status(cfg, IF_ADDING);
2133
+ bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
2134
+ cfg_type = wl_cfgp2p_get_conn_idx(cfg);
2135
+ if (cfg_type == BCME_ERROR) {
2136
+ wl_clr_p2p_status(cfg, IF_ADDING);
2137
+ WL_ERR(("Failed to get connection idx for p2p interface"));
2138
+ return NULL;
2139
+ }
2140
+
2141
+ p2p_addr = wl_to_p2p_bss_macaddr(cfg, cfg_type);
2142
+ memcpy(p2p_addr->octet, mac_addr, ETH_ALEN);
2143
+
2144
+ err = wl_cfgp2p_ifadd(cfg, p2p_addr,
2145
+ htod32(p2p_iftype), chspec);
2146
+ if (unlikely(err)) {
2147
+ wl_clr_p2p_status(cfg, IF_ADDING);
2148
+ WL_ERR((" virtual iface add failed (%d) \n", err));
2149
+ return NULL;
2150
+ }
2151
+
2152
+ /* Wait for WLC_E_IF event with IF_ADD opcode */
2153
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2154
+ ((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
2155
+ (cfg->if_event_info.valid)),
2156
+ msecs_to_jiffies(MAX_WAIT_TIME));
2157
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
2158
+ wl_if_event_info *event = &cfg->if_event_info;
2159
+ new_ndev = wl_cfg80211_post_ifcreate(bcmcfg_to_prmry_ndev(cfg), event,
2160
+ event->mac, cfg->p2p->vir_ifname, false);
2161
+ if (unlikely(!new_ndev)) {
2162
+ goto fail;
2163
+ }
2164
+
2165
+ if (wl_iftype == WL_IF_TYPE_P2P_GO) {
2166
+ cfg->p2p->p2p_go_count++;
2167
+ }
2168
+ /* Fill p2p specific data */
2169
+ wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
2170
+ wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
2171
+
2172
+ WL_ERR((" virtual interface(%s) is "
2173
+ "created net attach done\n", cfg->p2p->vir_ifname));
2174
+ dhd_mode = (wl_iftype == WL_IF_TYPE_P2P_GC) ?
2175
+ DHD_FLAG_P2P_GC_MODE : DHD_FLAG_P2P_GO_MODE;
2176
+ DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
2177
+ /* reinitialize completion to clear previous count */
2178
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
2179
+ INIT_COMPLETION(cfg->iface_disable);
2180
+#else
2181
+ init_completion(&cfg->iface_disable);
2182
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
2183
+
2184
+ return new_ndev->ieee80211_ptr;
2185
+ }
2186
+
2187
+fail:
2188
+ return NULL;
2189
+}
2190
+
2191
+bool
2192
+wl_cfg80211_check_vif_in_use(struct net_device *ndev)
2193
+{
2194
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2195
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2196
+ bool nan_enabled = FALSE;
2197
+
2198
+#ifdef WL_NAN
2199
+ nan_enabled = cfg->nan_enable;
2200
+#endif /* WL_NAN */
2201
+
2202
+ if (nan_enabled || (wl_cfgp2p_vif_created(cfg)) ||
2203
+ (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
2204
+ WL_MEM(("%s: Virtual interfaces in use. NAN %d P2P %d softAP %d\n",
2205
+ __FUNCTION__, nan_enabled, wl_cfgp2p_vif_created(cfg),
2206
+ (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)));
2207
+ return TRUE;
2208
+ }
2209
+
2210
+ return FALSE;
2211
+}
2212
+
2213
+void
2214
+wl_cfg80211_iface_state_ops(struct wireless_dev *wdev,
2215
+ wl_interface_state_t state,
2216
+ wl_iftype_t wl_iftype, u16 wl_mode)
2217
+{
2218
+ struct net_device *ndev;
2219
+ struct bcm_cfg80211 *cfg;
2220
+#if defined(CUSTOM_SET_CPUCORE)
2221
+ dhd_pub_t *dhd;
2222
+#endif // endif
2223
+ s32 bssidx;
2224
+
2225
+ WL_DBG(("state:%s wl_iftype:%d mode:%d\n",
2226
+ wl_if_state_strs[state], wl_iftype, wl_mode));
2227
+ if (!wdev) {
2228
+ WL_ERR(("wdev null\n"));
2229
+ return;
2230
+ }
2231
+
2232
+ if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_NAN_NMI)) {
2233
+ /* P2P discovery is a netless device and uses a
2234
+ * hidden bsscfg interface in fw. Don't apply the
2235
+ * iface ops state changes for p2p discovery I/F.
2236
+ * NAN NMI is netless device and uses a hidden bsscfg interface in fw.
2237
+ * Don't apply iface ops state changes for NMI I/F.
2238
+ */
2239
+ return;
2240
+ }
2241
+
2242
+ cfg = wiphy_priv(wdev->wiphy);
2243
+ ndev = wdev->netdev;
2244
+#ifdef CUSTOM_SET_CPUCORE
2245
+ dhd = (dhd_pub_t *)(cfg->pub);
2246
+#endif /* CUSTOM_SET_CPUCORE */
2247
+
2248
+ bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2249
+ if (!ndev || (bssidx < 0)) {
2250
+ WL_ERR(("ndev null. skip iface state ops\n"));
2251
+ return;
2252
+ }
2253
+
2254
+ switch (state) {
2255
+ case WL_IF_CREATE_REQ:
2256
+#ifdef WL_BCNRECV
2257
+ /* check fakeapscan in progress then abort */
2258
+ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
2259
+#endif /* WL_BCNRECV */
2260
+ wl_cfg80211_scan_abort(cfg);
2261
+#ifdef WLTDLS
2262
+ /* disable TDLS if number of connected interfaces is >= 1 */
2263
+ wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_CREATE, false);
2264
+#endif /* WLTDLS */
2265
+ break;
2266
+ case WL_IF_DELETE_REQ:
2267
+#ifdef WL_WPS_SYNC
2268
+ wl_wps_handle_ifdel(ndev);
2269
+#endif /* WPS_SYNC */
2270
+ if (wl_get_drv_status(cfg, SCANNING, ndev)) {
2271
+ /* Send completion for any pending scans */
2272
+ wl_cfg80211_cancel_scan(cfg);
2273
+ }
2274
+
2275
+#ifdef CUSTOM_SET_CPUCORE
2276
+ dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
2277
+ if (!(dhd->chan_isvht80)) {
2278
+ dhd_set_cpucore(dhd, FALSE);
2279
+ }
2280
+#endif /* CUSTOM_SET_CPUCORE */
2281
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
2282
+ break;
2283
+ case WL_IF_CREATE_DONE:
2284
+ if (wl_mode == WL_MODE_BSS) {
2285
+ /* Common code for sta type interfaces - STA, GC */
2286
+ wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2287
+ }
2288
+ if (wl_iftype == WL_IF_TYPE_P2P_GC) {
2289
+ /* Disable firmware roaming for P2P interface */
2290
+ wldev_iovar_setint(ndev, "roam_off", 1);
2291
+ }
2292
+ if (wl_mode == WL_MODE_AP) {
2293
+ /* Common code for AP/GO */
2294
+ }
2295
+ break;
2296
+ case WL_IF_DELETE_DONE:
2297
+#ifdef WLTDLS
2298
+ /* Enable back TDLS if connected interface is <= 1 */
2299
+ wl_cfg80211_tdls_config(cfg, TDLS_STATE_IF_DELETE, false);
2300
+#endif /* WLTDLS */
2301
+ wl_wlfc_enable(cfg, false);
2302
+ break;
2303
+ case WL_IF_CHANGE_REQ:
2304
+ /* Flush existing IEs from firmware on role change */
2305
+ wl_cfg80211_clear_per_bss_ies(cfg, wdev);
2306
+ break;
2307
+ case WL_IF_CHANGE_DONE:
2308
+ wl_wlfc_enable(cfg, true);
2309
+ if (wl_mode == WL_MODE_BSS) {
2310
+ /* Enable buffering of PTK key till EAPOL 4/4 is sent out */
2311
+ wldev_iovar_setint(ndev, "buf_key_b4_m4", 1);
2312
+ }
2313
+ break;
2314
+
2315
+ default:
2316
+ WL_ERR(("Unsupported state: %d\n", state));
2317
+ return;
2318
+ }
2319
+}
2320
+
2321
+static s32
2322
+wl_cfg80211_p2p_if_del(struct wiphy *wiphy, struct wireless_dev *wdev)
2323
+{
2324
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2325
+ s16 bssidx;
2326
+ s16 err;
2327
+ s32 cfg_type;
2328
+ struct net_device *ndev;
2329
+ long timeout;
2330
+
2331
+ if (unlikely(!wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg)))) {
2332
+ WL_INFORM_MEM(("device is not ready\n"));
2333
+ return BCME_NOTFOUND;
2334
+ }
2335
+#ifdef WL_CFG80211_P2P_DEV_IF
2336
+ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
2337
+ /* Handle dedicated P2P discovery interface. */
2338
+ return wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
2339
+ }
2340
+#endif /* WL_CFG80211_P2P_DEV_IF */
2341
+
2342
+ /* Handle P2P Group Interface */
2343
+ bssidx = wl_get_bssidx_by_wdev(cfg, wdev);
2344
+ if (bssidx <= 0) {
2345
+ WL_ERR(("bssidx not found\n"));
2346
+ return BCME_NOTFOUND;
2347
+ }
2348
+ if (wl_cfgp2p_find_type(cfg, bssidx, &cfg_type) != BCME_OK) {
2349
+ /* Couldn't find matching iftype */
2350
+ WL_MEM(("non P2P interface\n"));
2351
+ return BCME_NOTFOUND;
2352
+ }
2353
+
2354
+ ndev = wdev->netdev;
2355
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2356
+ wl_clr_p2p_status(cfg, IF_ADDING);
2357
+
2358
+ /* for GO */
2359
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
2360
+ wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
2361
+ cfg->p2p->p2p_go_count--;
2362
+ /* disable interface before bsscfg free */
2363
+ err = wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2364
+ /* if fw doesn't support "ifdis",
2365
+ do not wait for link down of ap mode
2366
+ */
2367
+ if (err == 0) {
2368
+ WL_ERR(("Wait for Link Down event for GO !!!\n"));
2369
+ wait_for_completion_timeout(&cfg->iface_disable,
2370
+ msecs_to_jiffies(500));
2371
+ } else if (err != BCME_UNSUPPORTED) {
2372
+ msleep(300);
2373
+ }
2374
+ } else {
2375
+ /* GC case */
2376
+ if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
2377
+ WL_ERR(("Wait for Link Down event for GC !\n"));
2378
+ wait_for_completion_timeout
2379
+ (&cfg->iface_disable, msecs_to_jiffies(500));
2380
+ }
2381
+ }
2382
+
2383
+ bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
2384
+ wl_set_p2p_status(cfg, IF_DELETING);
2385
+ DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
2386
+
2387
+ err = wl_cfgp2p_ifdel(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
2388
+ if (unlikely(err)) {
2389
+ WL_ERR(("IFDEL operation failed, error code = %d\n", err));
2390
+ goto fail;
2391
+ } else {
2392
+ /* Wait for WLC_E_IF event */
2393
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
2394
+ ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
2395
+ (cfg->if_event_info.valid)),
2396
+ msecs_to_jiffies(MAX_WAIT_TIME));
2397
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
2398
+ cfg->if_event_info.valid) {
2399
+ WL_ERR(("P2P IFDEL operation done\n"));
2400
+ err = BCME_OK;
2401
+ } else {
2402
+ WL_ERR(("IFDEL didn't complete properly\n"));
2403
+ err = -EINVAL;
2404
+ }
2405
+ }
2406
+
2407
+fail:
2408
+ /* Even in failure case, attempt to remove the host data structure.
2409
+ * Firmware would be cleaned up via WiFi reset done by the
2410
+ * user space from hang event context (for android only).
2411
+ */
2412
+ bzero(cfg->p2p->vir_ifname, IFNAMSIZ);
2413
+ wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
2414
+ wl_to_p2p_bss_ndev(cfg, cfg_type) = NULL;
2415
+ wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, cfg_type));
2416
+ dhd_net_if_lock(ndev);
2417
+ if (cfg->if_event_info.ifidx) {
2418
+ /* Remove interface except for primary ifidx */
2419
+ wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
2420
+ }
2421
+ dhd_net_if_unlock(ndev);
2422
+ return err;
2423
+}
2424
+
2425
+#ifdef WL_IFACE_MGMT_CONF
2426
+#ifdef WL_IFACE_MGMT
2427
+static s32
2428
+wl_cfg80211_is_policy_config_allowed(struct bcm_cfg80211 *cfg)
2429
+{
2430
+ s32 ret = BCME_OK;
2431
+ wl_iftype_t active_sec_iface = WL_IFACE_NOT_PRESENT;
2432
+ bool p2p_disc_on = false;
2433
+ bool sta_assoc_state = false;
2434
+
2435
+ mutex_lock(&cfg->if_sync);
2436
+
2437
+ sta_assoc_state = (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) ||
2438
+ wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg)));
2439
+ active_sec_iface = wl_cfg80211_get_sec_iface(cfg);
2440
+ p2p_disc_on = wl_get_p2p_status(cfg, SCANNING);
2441
+
2442
+ if ((sta_assoc_state == TRUE) || (p2p_disc_on == TRUE) ||
2443
+ (cfg->nan_init_state == TRUE) ||
2444
+ (active_sec_iface != WL_IFACE_NOT_PRESENT)) {
2445
+ WL_INFORM_MEM(("Active iface matrix: sta_assoc_state = %d,"
2446
+ " p2p_disc = %d, nan_disc = %d, active iface = %s\n",
2447
+ sta_assoc_state, p2p_disc_on, cfg->nan_init_state,
2448
+ wl_iftype_to_str(active_sec_iface)));
2449
+ ret = BCME_BUSY;
2450
+ }
2451
+ mutex_unlock(&cfg->if_sync);
2452
+ return ret;
2453
+}
2454
+#endif /* WL_IFACE_MGMT */
2455
+#ifdef WL_NANP2P
2456
+int
2457
+wl_cfg80211_set_iface_conc_disc(struct net_device *ndev,
2458
+ uint8 arg_val)
2459
+{
2460
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2461
+ if (!cfg) {
2462
+ WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2463
+ return BCME_ERROR;
2464
+ }
2465
+
2466
+ if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
2467
+ WL_ERR(("Cant allow iface management modifications\n"));
2468
+ return BCME_BUSY;
2469
+ }
2470
+
2471
+ if (arg_val) {
2472
+ cfg->conc_disc |= arg_val;
2473
+ } else {
2474
+ cfg->conc_disc &= ~arg_val;
2475
+ }
2476
+ return BCME_OK;
2477
+}
2478
+
2479
+uint8
2480
+wl_cfg80211_get_iface_conc_disc(struct net_device *ndev)
2481
+{
2482
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2483
+ if (!cfg) {
2484
+ WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2485
+ return BCME_ERROR;
2486
+ }
2487
+ return cfg->conc_disc;
2488
+}
2489
+#endif /* WL_NANP2P */
2490
+#ifdef WL_IFACE_MGMT
2491
+int
2492
+wl_cfg80211_set_iface_policy(struct net_device *ndev,
2493
+ char *arg, int len)
2494
+{
2495
+ int ret = BCME_OK;
2496
+ uint8 i = 0;
2497
+ iface_mgmt_data_t *iface_data = NULL;
2498
+
2499
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2500
+ if (!cfg) {
2501
+ WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2502
+ return BCME_ERROR;
2503
+ }
2504
+
2505
+ if (wl_cfg80211_is_policy_config_allowed(cfg) != BCME_OK) {
2506
+ WL_ERR(("Cant allow iface management modifications\n"));
2507
+ return BCME_BUSY;
2508
+ }
2509
+
2510
+ if (!arg || len <= 0 || len > sizeof(iface_mgmt_data_t)) {
2511
+ return BCME_BADARG;
2512
+ }
2513
+
2514
+ iface_data = (iface_mgmt_data_t *)arg;
2515
+ if (iface_data->policy >= WL_IF_POLICY_INVALID) {
2516
+ WL_ERR(("Unexpected value of policy = %d\n",
2517
+ iface_data->policy));
2518
+ return BCME_BADARG;
2519
+ }
2520
+
2521
+ bzero(&cfg->iface_data, sizeof(iface_mgmt_data_t));
2522
+ ret = memcpy_s(&cfg->iface_data, sizeof(iface_mgmt_data_t), arg, len);
2523
+ if (ret != BCME_OK) {
2524
+ WL_ERR(("Failed to copy iface data, src len = %d\n", len));
2525
+ return ret;
2526
+ }
2527
+
2528
+ if (cfg->iface_data.policy == WL_IF_POLICY_ROLE_PRIORITY) {
2529
+ for (i = 0; i < WL_IF_TYPE_MAX; i++) {
2530
+ WL_DBG(("iface = %s, priority[i] = %d\n",
2531
+ wl_iftype_to_str(i), cfg->iface_data.priority[i]));
2532
+ }
2533
+ }
2534
+
2535
+ return ret;
2536
+}
2537
+
2538
+uint8
2539
+wl_cfg80211_get_iface_policy(struct net_device *ndev)
2540
+
2541
+{
2542
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
2543
+ if (!cfg) {
2544
+ WL_ERR(("%s: Cannot find cfg\n", __FUNCTION__));
2545
+ return BCME_ERROR;
2546
+ }
2547
+
2548
+ return cfg->iface_data.policy;
2549
+}
2550
+#endif /* WL_IFACE_MGMT */
2551
+#endif /* WL_IFACE_MGMT_CONF */
2552
+
2553
+#ifdef WL_IFACE_MGMT
2554
+/* Get active secondary data iface type */
2555
+wl_iftype_t
2556
+wl_cfg80211_get_sec_iface(struct bcm_cfg80211 *cfg)
2557
+{
2558
+#ifndef WL_STATIC_IF
2559
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2560
+#endif /* !WL_STATIC_IF */
2561
+ struct net_device *p2p_ndev = NULL;
2562
+
2563
+ p2p_ndev = wl_to_p2p_bss_ndev(cfg,
2564
+ P2PAPI_BSSCFG_CONNECTION1);
2565
+
2566
+#ifdef WL_STATIC_IF
2567
+ if (IS_CFG80211_STATIC_IF_ACTIVE(cfg)) {
2568
+ if (IS_AP_IFACE(cfg->static_ndev->ieee80211_ptr)) {
2569
+ return WL_IF_TYPE_AP;
2570
+ }
2571
+ }
2572
+#else
2573
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
2574
+ return WL_IF_TYPE_AP;
2575
+ }
2576
+#endif /* WL_STATIC_IF */
2577
+
2578
+ if (p2p_ndev && p2p_ndev->ieee80211_ptr) {
2579
+ if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
2580
+ return WL_IF_TYPE_P2P_GO;
2581
+ }
2582
+
2583
+ if (p2p_ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
2584
+ return WL_IF_TYPE_P2P_GC;
2585
+ }
2586
+ }
2587
+
2588
+#ifdef WL_NAN
2589
+ if (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg))) {
2590
+ return WL_IF_TYPE_NAN;
2591
+ }
2592
+#endif /* WL_NAN */
2593
+ return WL_IFACE_NOT_PRESENT;
2594
+}
2595
+
2596
+/*
2597
+* Handle incoming data interface request based on policy.
2598
+* If there is any conflicting interface, that will be
2599
+* deleted.
2600
+*/
2601
+s32
2602
+wl_cfg80211_data_if_mgmt(struct bcm_cfg80211 *cfg,
2603
+ wl_iftype_t new_wl_iftype)
2604
+{
2605
+ s32 ret = BCME_OK;
2606
+ bool del_iface = false;
2607
+ wl_iftype_t sec_wl_if_type = wl_cfg80211_get_sec_iface(cfg);
2608
+
2609
+ if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2610
+ new_wl_iftype == WL_IF_TYPE_NAN) {
2611
+ /* Multi NDP is allowed irrespective of Policy */
2612
+ return BCME_OK;
2613
+ }
2614
+
2615
+ if (sec_wl_if_type == WL_IFACE_NOT_PRESENT) {
2616
+ /*
2617
+ * If there is no active secondary I/F, there
2618
+ * is no interface conflict. Do nothing.
2619
+ */
2620
+ return BCME_OK;
2621
+ }
2622
+
2623
+ /* Handle secondary data link case */
2624
+ switch (cfg->iface_data.policy) {
2625
+ case WL_IF_POLICY_CUSTOM:
2626
+ case WL_IF_POLICY_DEFAULT: {
2627
+ if (sec_wl_if_type == WL_IF_TYPE_NAN) {
2628
+ /* NAN has the lowest priority */
2629
+ del_iface = true;
2630
+ } else {
2631
+ /* Active iface is present, returning error */
2632
+ ret = BCME_ERROR;
2633
+ }
2634
+ break;
2635
+ }
2636
+ case WL_IF_POLICY_FCFS: {
2637
+ WL_INFORM_MEM(("Found active iface = %s, can't support new iface = %s\n",
2638
+ wl_iftype_to_str(sec_wl_if_type), wl_iftype_to_str(new_wl_iftype)));
2639
+ ret = BCME_ERROR;
2640
+ break;
2641
+ }
2642
+ case WL_IF_POLICY_LP: {
2643
+ WL_INFORM_MEM(("Remove active sec data interface, allow incoming iface\n"));
2644
+ /* Delete existing data iface and allow incoming sec iface */
2645
+ del_iface = true;
2646
+ break;
2647
+ }
2648
+ case WL_IF_POLICY_ROLE_PRIORITY: {
2649
+ WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2650
+ wl_iftype_to_str(sec_wl_if_type),
2651
+ cfg->iface_data.priority[sec_wl_if_type],
2652
+ wl_iftype_to_str(new_wl_iftype),
2653
+ cfg->iface_data.priority[new_wl_iftype]));
2654
+ if (cfg->iface_data.priority[new_wl_iftype] >
2655
+ cfg->iface_data.priority[sec_wl_if_type]) {
2656
+ del_iface = true;
2657
+ } else {
2658
+ WL_ERR(("Can't support new iface = %s\n",
2659
+ wl_iftype_to_str(new_wl_iftype)));
2660
+ ret = BCME_ERROR;
2661
+ }
2662
+ break;
2663
+ }
2664
+ default: {
2665
+ WL_ERR(("Unsupported interface policy = %d\n",
2666
+ cfg->iface_data.policy));
2667
+ return BCME_ERROR;
2668
+ }
2669
+ }
2670
+ if (del_iface) {
2671
+ ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2672
+ }
2673
+ return ret;
2674
+}
2675
+
2676
+/* Handle discovery ifaces based on policy */
2677
+s32
2678
+wl_cfg80211_disc_if_mgmt(struct bcm_cfg80211 *cfg,
2679
+ wl_iftype_t new_wl_iftype, bool *disable_nan, bool *disable_p2p)
2680
+{
2681
+ s32 ret = BCME_OK;
2682
+ wl_iftype_t sec_wl_if_type =
2683
+ wl_cfg80211_get_sec_iface(cfg);
2684
+ *disable_p2p = false;
2685
+ *disable_nan = false;
2686
+
2687
+ if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2688
+ new_wl_iftype == WL_IF_TYPE_NAN) {
2689
+ /* Multi NDP is allowed irrespective of Policy */
2690
+ return BCME_OK;
2691
+ }
2692
+
2693
+ /*
2694
+ * Check for any policy conflicts with active secondary
2695
+ * interface for incoming discovery iface
2696
+ */
2697
+ if ((sec_wl_if_type != WL_IFACE_NOT_PRESENT) &&
2698
+ (is_discovery_iface(new_wl_iftype))) {
2699
+ switch (cfg->iface_data.policy) {
2700
+ case WL_IF_POLICY_CUSTOM: {
2701
+ if (sec_wl_if_type == WL_IF_TYPE_NAN &&
2702
+ new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2703
+ WL_INFORM_MEM(("Allow P2P Discovery with active NDP\n"));
2704
+ /* No further checks are required. */
2705
+ return BCME_OK;
2706
+ }
2707
+ /*
2708
+ * Intentional fall through to default policy
2709
+ * as for AP and associated ifaces, both are same
2710
+ */
2711
+ }
2712
+ /* fall through */
2713
+ case WL_IF_POLICY_DEFAULT: {
2714
+ if (sec_wl_if_type == WL_IF_TYPE_AP) {
2715
+ WL_INFORM_MEM(("AP is active, cant support new iface\n"));
2716
+ ret = BCME_ERROR;
2717
+ } else if (sec_wl_if_type == WL_IF_TYPE_P2P_GC ||
2718
+ sec_wl_if_type == WL_IF_TYPE_P2P_GO) {
2719
+ if (new_wl_iftype == WL_IF_TYPE_P2P_DISC) {
2720
+ /*
2721
+ * Associated discovery case,
2722
+ * Fall through
2723
+ */
2724
+ } else {
2725
+ /* Active iface is present, returning error */
2726
+ WL_INFORM_MEM(("P2P group is active,"
2727
+ " cant support new iface\n"));
2728
+ ret = BCME_ERROR;
2729
+ }
2730
+ } else if (sec_wl_if_type == WL_IF_TYPE_NAN) {
2731
+ ret = wl_cfg80211_delete_iface(cfg, sec_wl_if_type);
2732
+ }
2733
+ break;
2734
+ }
2735
+ case WL_IF_POLICY_FCFS: {
2736
+ WL_INFORM_MEM(("Can't support new iface = %s\n",
2737
+ wl_iftype_to_str(new_wl_iftype)));
2738
+ ret = BCME_ERROR;
2739
+ break;
2740
+ }
2741
+ case WL_IF_POLICY_LP: {
2742
+ /* Delete existing data iface n allow incoming sec iface */
2743
+ WL_INFORM_MEM(("Remove active sec data interface = %s\n",
2744
+ wl_iftype_to_str(sec_wl_if_type)));
2745
+ ret = wl_cfg80211_delete_iface(cfg,
2746
+ sec_wl_if_type);
2747
+ break;
2748
+ }
2749
+ case WL_IF_POLICY_ROLE_PRIORITY: {
2750
+ WL_INFORM_MEM(("Existing iface = %s (%d) and new iface = %s (%d)\n",
2751
+ wl_iftype_to_str(sec_wl_if_type),
2752
+ cfg->iface_data.priority[sec_wl_if_type],
2753
+ wl_iftype_to_str(new_wl_iftype),
2754
+ cfg->iface_data.priority[new_wl_iftype]));
2755
+ if (cfg->iface_data.priority[new_wl_iftype] >
2756
+ cfg->iface_data.priority[sec_wl_if_type]) {
2757
+ WL_INFORM_MEM(("Remove active sec data iface\n"));
2758
+ ret = wl_cfg80211_delete_iface(cfg,
2759
+ sec_wl_if_type);
2760
+ } else {
2761
+ WL_ERR(("Can't support new iface = %s"
2762
+ " due to low priority\n",
2763
+ wl_iftype_to_str(new_wl_iftype)));
2764
+ ret = BCME_ERROR;
2765
+ }
2766
+ break;
2767
+ }
2768
+ default: {
2769
+ WL_ERR(("Unsupported policy\n"));
2770
+ return BCME_ERROR;
2771
+ }
2772
+ }
2773
+ } else {
2774
+ /*
2775
+ * Handle incoming new secondary iface request,
2776
+ * irrespective of existing discovery ifaces
2777
+ */
2778
+ if ((cfg->iface_data.policy == WL_IF_POLICY_CUSTOM) &&
2779
+ (new_wl_iftype == WL_IF_TYPE_NAN)) {
2780
+ WL_INFORM_MEM(("Allow NAN Data Path\n"));
2781
+ /* No further checks are required. */
2782
+ return BCME_OK;
2783
+ }
2784
+ }
2785
+
2786
+ /* Check for any conflicting discovery iface */
2787
+ switch (new_wl_iftype) {
2788
+ case WL_IF_TYPE_P2P_DISC:
2789
+ case WL_IF_TYPE_P2P_GO:
2790
+ case WL_IF_TYPE_P2P_GC: {
2791
+ *disable_nan = true;
2792
+ break;
2793
+ }
2794
+ case WL_IF_TYPE_NAN_NMI:
2795
+ case WL_IF_TYPE_NAN: {
2796
+ *disable_p2p = true;
2797
+ break;
2798
+ }
2799
+ case WL_IF_TYPE_STA:
2800
+ case WL_IF_TYPE_AP: {
2801
+ *disable_nan = true;
2802
+ *disable_p2p = true;
2803
+ break;
2804
+ }
2805
+ default: {
2806
+ WL_ERR(("Unsupported\n"));
2807
+ return BCME_ERROR;
2808
+ }
2809
+ }
2810
+ return ret;
2811
+}
2812
+
2813
+bool
2814
+wl_cfg80211_is_associated_discovery(struct bcm_cfg80211 *cfg,
2815
+ wl_iftype_t new_wl_iftype)
2816
+{
2817
+ struct net_device *p2p_ndev = NULL;
2818
+ p2p_ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
2819
+
2820
+ if (new_wl_iftype == WL_IF_TYPE_P2P_DISC && p2p_ndev &&
2821
+ p2p_ndev->ieee80211_ptr &&
2822
+ is_p2p_group_iface(p2p_ndev->ieee80211_ptr)) {
2823
+ return true;
2824
+ }
2825
+#ifdef WL_NAN
2826
+ else if ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) &&
2827
+ (wl_cfgnan_is_dp_active(bcmcfg_to_prmry_ndev(cfg)))) {
2828
+ return true;
2829
+ }
2830
+#endif /* WL_NAN */
2831
+ return false;
2832
+}
2833
+
2834
+/* Handle incoming discovery iface request */
2835
+s32
2836
+wl_cfg80211_handle_discovery_config(struct bcm_cfg80211 *cfg,
2837
+ wl_iftype_t new_wl_iftype)
2838
+{
2839
+ s32 ret = BCME_OK;
2840
+ bool disable_p2p = false;
2841
+ bool disable_nan = false;
2842
+
2843
+ wl_iftype_t active_sec_iface =
2844
+ wl_cfg80211_get_sec_iface(cfg);
2845
+
2846
+ if (is_discovery_iface(new_wl_iftype) &&
2847
+ (active_sec_iface != WL_IFACE_NOT_PRESENT)) {
2848
+ if (wl_cfg80211_is_associated_discovery(cfg,
2849
+ new_wl_iftype) == TRUE) {
2850
+ WL_DBG(("Associate iface request is allowed= %s\n",
2851
+ wl_iftype_to_str(new_wl_iftype)));
2852
+ return ret;
2853
+ }
2854
+ }
2855
+
2856
+ ret = wl_cfg80211_disc_if_mgmt(cfg, new_wl_iftype,
2857
+ &disable_nan, &disable_p2p);
2858
+ if (ret != BCME_OK) {
2859
+ WL_ERR(("Failed at disc iface mgmt, ret = %d\n", ret));
2860
+ return ret;
2861
+ }
2862
+#ifdef WL_NANP2P
2863
+ if (((new_wl_iftype == WL_IF_TYPE_P2P_DISC) && disable_nan) ||
2864
+ ((new_wl_iftype == WL_IF_TYPE_NAN_NMI) && disable_p2p)) {
2865
+ if ((cfg->nan_p2p_supported == TRUE) &&
2866
+ (cfg->conc_disc == WL_NANP2P_CONC_SUPPORT)) {
2867
+ WL_INFORM_MEM(("P2P + NAN conc is supported\n"));
2868
+ disable_p2p = false;
2869
+ disable_nan = false;
2870
+ }
2871
+ }
2872
+#endif /* WL_NANP2P */
2873
+
2874
+ if (disable_nan) {
2875
+#ifdef WL_NAN
2876
+ /* Disable nan */
2877
+ ret = wl_cfgnan_disable(cfg, NAN_CONCURRENCY_CONFLICT);
2878
+ if (ret != BCME_OK) {
2879
+ WL_ERR(("failed to disable nan, error[%d]\n", ret));
2880
+ return ret;
2881
+ }
2882
+#endif /* WL_NAN */
2883
+ }
2884
+
2885
+ if (disable_p2p) {
2886
+ /* Disable p2p discovery */
2887
+ ret = wl_cfg80211_deinit_p2p_discovery(cfg);
2888
+ if (ret != BCME_OK) {
2889
+ WL_ERR(("Failed to disable p2p_disc for allowing nan\n"));
2890
+ return ret;
2891
+ }
2892
+ }
2893
+ return ret;
2894
+}
2895
+
2896
+/*
2897
+* Check for any conflicting iface before adding iface.
2898
+* Based on policy, either conflicting iface is removed
2899
+* or new iface add request is blocked.
2900
+*/
2901
+s32
2902
+wl_cfg80211_handle_if_role_conflict(struct bcm_cfg80211 *cfg,
2903
+ wl_iftype_t new_wl_iftype)
2904
+{
2905
+ s32 ret = BCME_OK;
2906
+
2907
+ WL_INFORM_MEM(("Incoming iface = %s\n", wl_iftype_to_str(new_wl_iftype)));
2908
+
2909
+ if (!is_discovery_iface(new_wl_iftype)) {
2910
+ /* Incoming data interface request */
2911
+ if (wl_cfg80211_get_sec_iface(cfg) != WL_IFACE_NOT_PRESENT) {
2912
+ /* active interface present - Apply interface data policy */
2913
+ ret = wl_cfg80211_data_if_mgmt(cfg, new_wl_iftype);
2914
+ if (ret != BCME_OK) {
2915
+ WL_ERR(("if_mgmt fail:%d\n", ret));
2916
+ return ret;
2917
+ }
2918
+ }
2919
+ }
2920
+ /* Apply discovery config */
2921
+ ret = wl_cfg80211_handle_discovery_config(cfg, new_wl_iftype);
2922
+ return ret;
2923
+}
2924
+#endif /* WL_IFACE_MGMT */
2925
+
2926
+#ifdef DHD_MONITOR_INTERFACE
2927
+static struct wireless_dev *
2928
+wl_cfg80211_add_monitor_if(struct wiphy *wiphy, const char *name)
14502929 {
14512930 #if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
1452
- WL_INFORM(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
2931
+ WL_ERR(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
14532932 return ERR_PTR(-EOPNOTSUPP);
14542933 #else
2934
+ struct wireless *wdev;
14552935 struct net_device* ndev = NULL;
14562936
14572937 dhd_add_monitor(name, &ndev);
1458
- WL_INFORM(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
1459
- return ndev_to_cfgdev(ndev);
2938
+
2939
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2940
+ if (!wdev) {
2941
+ WL_ERR(("wireless_dev alloc failed! \n"));
2942
+ goto fail;
2943
+ }
2944
+
2945
+ wdev->wiphy = wiphy;
2946
+ wdev->iftype = iface_type;
2947
+ ndev->ieee80211_ptr = wdev;
2948
+ SET_NETDEV_DEV(ndev, wiphy_dev(wiphy));
2949
+
2950
+ WL_DBG(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
2951
+ return ndev->ieee80211_ptr;
14602952 #endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */
2953
+}
2954
+#endif /* DHD_MONITOR_INTERFACE */
2955
+
2956
+static struct wireless_dev *
2957
+wl_cfg80211_add_ibss(struct wiphy *wiphy, u16 wl_iftype, char const *name)
2958
+{
2959
+#ifdef WLAIBSS_MCHAN
2960
+ /* AIBSS */
2961
+ return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
2962
+#else
2963
+ /* Normal IBSS */
2964
+ WL_ERR(("IBSS not supported on Virtual iface\n"));
2965
+ return NULL;
2966
+#endif // endif
2967
+}
2968
+
2969
+s32
2970
+wl_release_vif_macaddr(struct bcm_cfg80211 *cfg, u8 *mac_addr, u16 wl_iftype)
2971
+{
2972
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2973
+ u16 org_toggle_bytes;
2974
+ u16 cur_toggle_bytes;
2975
+ u16 toggled_bit;
2976
+
2977
+ if (!ndev || !mac_addr || ETHER_ISNULLADDR(mac_addr)) {
2978
+ return -EINVAL;
2979
+ }
2980
+ WL_DBG(("%s:Mac addr" MACDBG "\n",
2981
+ __FUNCTION__, MAC2STRDBG(mac_addr)));
2982
+
2983
+#if defined(SPECIFIC_MAC_GEN_SCHEME)
2984
+ if ((wl_iftype == WL_IF_TYPE_P2P_DISC) || (wl_iftype == WL_IF_TYPE_AP) ||
2985
+ (wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
2986
+ /* Avoid invoking release mac addr code for interfaces using
2987
+ * fixed mac addr.
2988
+ */
2989
+ return BCME_OK;
2990
+ }
2991
+#else /* SPECIFIC_MAC_GEN_SCHEME */
2992
+ if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
2993
+ return BCME_OK;
2994
+ }
2995
+#endif /* SPECIFIC_MAC_GEN_SCHEME */
2996
+
2997
+ /* Fetch last two bytes of mac address */
2998
+ org_toggle_bytes = ntoh16(*((u16 *)&ndev->dev_addr[4]));
2999
+ cur_toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
3000
+
3001
+ toggled_bit = (org_toggle_bytes ^ cur_toggle_bytes);
3002
+ WL_DBG(("org_toggle_bytes:%04X cur_toggle_bytes:%04X\n",
3003
+ org_toggle_bytes, cur_toggle_bytes));
3004
+ if (toggled_bit & cfg->vif_macaddr_mask) {
3005
+ /* This toggled_bit is marked in the used mac addr
3006
+ * mask. Clear it.
3007
+ */
3008
+ cfg->vif_macaddr_mask &= ~toggled_bit;
3009
+ WL_INFORM(("MAC address - " MACDBG " released. toggled_bit:%04X vif_mask:%04X\n",
3010
+ MAC2STRDBG(mac_addr), toggled_bit, cfg->vif_macaddr_mask));
3011
+ } else {
3012
+ WL_ERR(("MAC address - " MACDBG " not found in the used list."
3013
+ " toggled_bit:%04x vif_mask:%04x\n", MAC2STRDBG(mac_addr),
3014
+ toggled_bit, cfg->vif_macaddr_mask));
3015
+ return -EINVAL;
3016
+ }
3017
+
3018
+ return BCME_OK;
3019
+}
3020
+
3021
+s32
3022
+wl_get_vif_macaddr(struct bcm_cfg80211 *cfg, u16 wl_iftype, u8 *mac_addr)
3023
+{
3024
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
3025
+ u16 toggle_mask;
3026
+ u16 toggle_bit;
3027
+ u16 toggle_bytes;
3028
+ u16 used;
3029
+ u32 offset = 0;
3030
+ /* Toggle mask starts from MSB of second last byte */
3031
+ u16 mask = 0x8000;
3032
+
3033
+ if (!mac_addr) {
3034
+ return -EINVAL;
3035
+ }
3036
+
3037
+ memcpy(mac_addr, ndev->dev_addr, ETH_ALEN);
3038
+/*
3039
+ * VIF MAC address managment
3040
+ * P2P Device addres: Primary MAC with locally admin. bit set
3041
+ * P2P Group address/NAN NMI/Softap/NAN DPI: Primary MAC addr
3042
+ * with local admin bit set and one additional bit toggled.
3043
+ * cfg->vif_macaddr_mask will hold the info regarding the mac address
3044
+ * released. Ensure to call wl_release_vif_macaddress to free up
3045
+ * the mac address.
3046
+ */
3047
+#if defined(SPECIFIC_MAC_GEN_SCHEME)
3048
+ if (wl_iftype == WL_IF_TYPE_P2P_DISC || wl_iftype == WL_IF_TYPE_AP) {
3049
+ mac_addr[0] |= 0x02;
3050
+ } else if ((wl_iftype == WL_IF_TYPE_P2P_GO) || (wl_iftype == WL_IF_TYPE_P2P_GC)) {
3051
+ mac_addr[0] |= 0x02;
3052
+ mac_addr[4] ^= 0x80;
3053
+ }
3054
+#else
3055
+ if (wl_iftype == WL_IF_TYPE_P2P_DISC) {
3056
+ mac_addr[0] |= 0x02;
3057
+ }
3058
+#endif /* SEPCIFIC_MAC_GEN_SCHEME */
3059
+ else {
3060
+ /* For locally administered mac addresses, we keep the
3061
+ * OUI part constant and just work on the last two bytes.
3062
+ */
3063
+ mac_addr[0] |= 0x02;
3064
+ toggle_mask = cfg->vif_macaddr_mask;
3065
+ toggle_bytes = ntoh16(*((u16 *)&mac_addr[4]));
3066
+ do {
3067
+ used = toggle_mask & mask;
3068
+ if (!used) {
3069
+ /* Use this bit position */
3070
+ toggle_bit = mask >> offset;
3071
+ toggle_bytes ^= toggle_bit;
3072
+ cfg->vif_macaddr_mask |= toggle_bit;
3073
+ WL_DBG(("toggle_bit:%04X toggle_bytes:%04X toggle_mask:%04X\n",
3074
+ toggle_bit, toggle_bytes, cfg->vif_macaddr_mask));
3075
+ /* Macaddress are stored in network order */
3076
+ mac_addr[5] = *((u8 *)&toggle_bytes);
3077
+ mac_addr[4] = *(((u8 *)&toggle_bytes + 1));
3078
+ break;
3079
+ }
3080
+
3081
+ /* Shift by one */
3082
+ toggle_mask = toggle_mask << 0x1;
3083
+ offset++;
3084
+ if (offset > MAX_VIF_OFFSET) {
3085
+ /* We have used up all macaddresses. Something wrong! */
3086
+ WL_ERR(("Entire range of macaddress used up.\n"));
3087
+ ASSERT(0);
3088
+ break;
3089
+ }
3090
+ } while (true);
3091
+ }
3092
+ WL_INFORM_MEM(("Get virtual I/F mac addr: "MACDBG"\n", MAC2STRDBG(mac_addr)));
3093
+ return 0;
3094
+}
3095
+#ifdef DNGL_AXI_ERROR_LOGGING
3096
+static s32
3097
+_wl_cfg80211_check_axi_error(struct bcm_cfg80211 *cfg)
3098
+{
3099
+ s32 ret = BCME_OK;
3100
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3101
+ hnd_ext_trap_hdr_t *hdr;
3102
+ int axi_host_error_size;
3103
+ uint8 *new_dst;
3104
+ uint32 *ext_data = dhd->extended_trap_data;
3105
+ struct file *fp = NULL;
3106
+ char *filename = DHD_COMMON_DUMP_PATH
3107
+ DHD_DUMP_AXI_ERROR_FILENAME
3108
+ DHD_DUMP_HAL_FILENAME_SUFFIX;
3109
+
3110
+ WL_ERR(("%s: starts to read %s. Axi error \n", __FUNCTION__, filename));
3111
+
3112
+ fp = filp_open(filename, O_RDONLY, 0);
3113
+
3114
+ if (IS_ERR(fp) || (fp == NULL)) {
3115
+ WL_ERR(("%s: Couldn't read the file, err %ld,File [%s] No previous axi error \n",
3116
+ __FUNCTION__, PTR_ERR(fp), filename));
3117
+ return ret;
3118
+ }
3119
+
3120
+ kernel_read_compat(fp, fp->f_pos, (char *)dhd->axi_err_dump, sizeof(dhd_axi_error_dump_t));
3121
+ filp_close(fp, NULL);
3122
+
3123
+ /* Delete axi error info file */
3124
+ if (dhd_file_delete(filename) < 0) {
3125
+ WL_ERR(("%s(): Failed to delete file: %s\n", __FUNCTION__, filename));
3126
+ return ret;
3127
+ }
3128
+ WL_ERR(("%s(): Success to delete file: %s\n", __FUNCTION__, filename));
3129
+
3130
+ if (dhd->axi_err_dump->etd_axi_error_v1.signature != HND_EXT_TRAP_AXIERROR_SIGNATURE) {
3131
+ WL_ERR(("%s: Invalid AXI signature: 0x%x\n",
3132
+ __FUNCTION__, dhd->axi_err_dump->etd_axi_error_v1.signature));
3133
+ }
3134
+
3135
+ /* First word is original trap_data */
3136
+ ext_data++;
3137
+
3138
+ /* Followed by the extended trap data header */
3139
+ hdr = (hnd_ext_trap_hdr_t *)ext_data;
3140
+ new_dst = hdr->data;
3141
+
3142
+ axi_host_error_size = sizeof(dhd->axi_err_dump->axid)
3143
+ + sizeof(dhd->axi_err_dump->fault_address);
3144
+
3145
+ /* TAG_TRAP_AXI_HOST_INFO tlv : host's axid, fault address */
3146
+ new_dst = bcm_write_tlv(TAG_TRAP_AXI_HOST_INFO,
3147
+ (const void *)dhd->axi_err_dump,
3148
+ axi_host_error_size, new_dst);
3149
+
3150
+ /* TAG_TRAP_AXI_ERROR tlv */
3151
+ new_dst = bcm_write_tlv(TAG_TRAP_AXI_ERROR,
3152
+ (const void *)&dhd->axi_err_dump->etd_axi_error_v1,
3153
+ sizeof(dhd->axi_err_dump->etd_axi_error_v1), new_dst);
3154
+ hdr->len = new_dst - hdr->data;
3155
+
3156
+ dhd->dongle_trap_occured = TRUE;
3157
+#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
3158
+ copy_hang_info_trap(dhd);
3159
+#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
3160
+ memset(dhd->axi_err_dump, 0, sizeof(dhd_axi_error_dump_t));
3161
+
3162
+ dhd->hang_reason = HANG_REASON_DONGLE_TRAP;
3163
+ net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3164
+ ret = BCME_ERROR;
3165
+ return ret;
3166
+}
3167
+#endif /* DNGL_AXI_ERROR_LOGGING */
3168
+
3169
+/* All Android/Linux private/Vendor Interface calls should make
3170
+ * use of below API for interface creation.
3171
+ */
3172
+struct wireless_dev *
3173
+wl_cfg80211_add_if(struct bcm_cfg80211 *cfg,
3174
+ struct net_device *primary_ndev,
3175
+ wl_iftype_t wl_iftype, const char *name, u8 *mac)
3176
+{
3177
+ u8 mac_addr[ETH_ALEN];
3178
+ s32 err = -ENODEV;
3179
+ struct wireless_dev *wdev = NULL;
3180
+ struct wiphy *wiphy;
3181
+ s32 wl_mode;
3182
+ dhd_pub_t *dhd;
3183
+ wl_iftype_t macaddr_iftype = wl_iftype;
3184
+ char *tmp = NULL;
3185
+ char vif_name[IFNAMSIZ] = {0};
3186
+ u8 vif_mac_addr[ETH_ALEN] = {0};
3187
+
3188
+ WL_INFORM_MEM(("if name: %s, wl_iftype:%d \n",
3189
+ name ? name : "NULL", wl_iftype));
3190
+ if (!cfg || !primary_ndev || !name) {
3191
+ WL_ERR(("cfg/ndev/name ptr null\n"));
3192
+ return NULL;
3193
+ }
3194
+ if (wl_cfg80211_get_wdev_from_ifname(cfg, name)) {
3195
+ WL_ERR(("Interface name %s exists!\n", name));
3196
+ return NULL;
3197
+ }
3198
+
3199
+ wiphy = bcmcfg_to_wiphy(cfg);
3200
+ dhd = (dhd_pub_t *)(cfg->pub);
3201
+ if (!dhd) {
3202
+ return NULL;
3203
+ }
3204
+
3205
+ if ((wl_mode = wl_iftype_to_mode(wl_iftype)) < 0) {
3206
+ return NULL;
3207
+ }
3208
+ mutex_lock(&cfg->if_sync);
3209
+#ifdef WL_NAN
3210
+ if (wl_iftype == WL_IF_TYPE_NAN) {
3211
+ /*
3212
+ * Bypass the role conflict check for NDI and handle it
3213
+ * from dp req and dp resp context
3214
+ * because in aware comms, ndi gets created soon after nan enable.
3215
+ */
3216
+ } else
3217
+#endif /* WL_NAN */
3218
+#ifdef WL_IFACE_MGMT
3219
+ if ((err = wl_cfg80211_handle_if_role_conflict(cfg, wl_iftype)) < 0) {
3220
+ mutex_unlock(&cfg->if_sync);
3221
+ return NULL;
3222
+ }
3223
+#endif /* WL_IFACE_MGMT */
3224
+#ifdef DNGL_AXI_ERROR_LOGGING
3225
+ /* Check the previous smmu fault error */
3226
+ if ((err = _wl_cfg80211_check_axi_error(cfg)) < 0) {
3227
+ mutex_unlock(&cfg->if_sync);
3228
+ return NULL;
3229
+ }
3230
+#endif /* DNGL_AXI_ERROR_LOGGING */
3231
+ /* Protect the interace op context */
3232
+ /* Do pre-create ops */
3233
+ wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr, WL_IF_CREATE_REQ,
3234
+ wl_iftype, wl_mode);
3235
+
3236
+ if (strnicmp(name, SOFT_AP_IF_NAME, strlen(SOFT_AP_IF_NAME)) == 0) {
3237
+ macaddr_iftype = WL_IF_TYPE_AP;
3238
+ }
3239
+
3240
+ tmp = strchr(name, ' ');
3241
+
3242
+ /* For MBSS AP create_interface, command will be
3243
+ * create_interface <interface_name> <ap_mac_addr>
3244
+ * parsing the vif_name and vif_mac_addr from char name
3245
+ */
3246
+ if (tmp) {
3247
+ int i;
3248
+
3249
+ /* skip space from delim after finding char */
3250
+ tmp++;
3251
+ mac = tmp;
3252
+
3253
+ for (i = 0; i < ETH_ALEN; i++) {
3254
+ vif_mac_addr[i] = (hex_to_bin(mac[i * 3]) << 4)
3255
+ | hex_to_bin(mac[i * 3 + 1]);
3256
+ }
3257
+
3258
+ for (i = 0; i <= strlen(name); i++) {
3259
+ if (*(name + i) != ' ') {
3260
+ *(vif_name + i) = *(name + i);
3261
+ } else {
3262
+ *(vif_name + i) = '\0';
3263
+ break;
3264
+ }
3265
+ }
3266
+ }
3267
+
3268
+ if (mac) {
3269
+ /* If mac address is provided, use that */
3270
+ if (tmp != NULL)
3271
+ memcpy(mac_addr, vif_mac_addr, ETH_ALEN);
3272
+ else
3273
+ memcpy(mac_addr, mac, ETH_ALEN);
3274
+ } else if ((wl_get_vif_macaddr(cfg, macaddr_iftype, mac_addr) != BCME_OK)) {
3275
+ /* Fetch the mac address to be used for virtual interface */
3276
+ err = -EINVAL;
3277
+ goto fail;
3278
+ }
3279
+
3280
+ switch (wl_iftype) {
3281
+ case WL_IF_TYPE_IBSS:
3282
+ wdev = wl_cfg80211_add_ibss(wiphy, wl_iftype, name);
3283
+ break;
3284
+#ifdef DHD_MONITOR_INTERFACE
3285
+ case WL_IF_TYPE_MONITOR:
3286
+ wdev = wl_cfg80211_add_monitor_if(wiphy, name);
3287
+ break;
3288
+#endif /* DHD_MONITOR_INTERFACE */
3289
+ case WL_IF_TYPE_STA:
3290
+ case WL_IF_TYPE_AP:
3291
+ case WL_IF_TYPE_NAN:
3292
+ if (cfg->iface_cnt >= (IFACE_MAX_CNT - 1)) {
3293
+ WL_ERR(("iface_cnt exceeds max cnt. created iface_cnt: %d\n",
3294
+ cfg->iface_cnt));
3295
+ err = -ENOTSUPP;
3296
+ goto fail;
3297
+ }
3298
+ if (*vif_name)
3299
+ wdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
3300
+ wl_iftype, mac_addr, vif_name);
3301
+ else
3302
+ wdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
3303
+ wl_iftype, mac_addr, name);
3304
+ break;
3305
+ case WL_IF_TYPE_P2P_DISC:
3306
+ case WL_IF_TYPE_P2P_GO:
3307
+ /* Intentional fall through */
3308
+ case WL_IF_TYPE_P2P_GC:
3309
+ if (cfg->p2p_supported) {
3310
+ wdev = wl_cfg80211_p2p_if_add(cfg, wl_iftype,
3311
+ name, mac_addr, &err);
3312
+ break;
3313
+ }
3314
+ /* Intentionally fall through for unsupported interface
3315
+ * handling when firmware doesn't support p2p
3316
+ */
3317
+ /* Intentional fall through */
3318
+ default:
3319
+ WL_ERR(("Unsupported interface type\n"));
3320
+ err = -ENOTSUPP;
3321
+ goto fail;
3322
+ }
3323
+
3324
+ if (!wdev) {
3325
+ WL_ERR(("vif create failed. err:%d\n", err));
3326
+ if (err != -ENOTSUPP) {
3327
+ err = -ENODEV;
3328
+ }
3329
+ goto fail;
3330
+ }
3331
+
3332
+ /* Ensure decrementing in case of failure */
3333
+ cfg->vif_count++;
3334
+
3335
+ wl_cfg80211_iface_state_ops(wdev,
3336
+ WL_IF_CREATE_DONE, wl_iftype, wl_mode);
3337
+
3338
+ WL_INFORM_MEM(("Vif created. dev->ifindex:%d"
3339
+ " cfg_iftype:%d, vif_count:%d\n",
3340
+ (wdev->netdev ? wdev->netdev->ifindex : 0xff),
3341
+ wdev->iftype, cfg->vif_count));
3342
+ mutex_unlock(&cfg->if_sync);
3343
+ return wdev;
3344
+
3345
+fail:
3346
+ wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3347
+ WL_IF_DELETE_REQ, wl_iftype, wl_mode);
3348
+
3349
+ if (err != -ENOTSUPP) {
3350
+ /* For non-supported interfaces, just return error and
3351
+ * skip below recovery steps.
3352
+ */
3353
+#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
3354
+ wl_copy_hang_info_if_falure(primary_ndev, HANG_REASON_IFACE_DEL_FAILURE, err);
3355
+#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
3356
+ SUPP_LOG(("IF_ADD fail. err:%d\n", err));
3357
+ wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3358
+ if (dhd_query_bus_erros(dhd)) {
3359
+ goto exit;
3360
+ }
3361
+ dhd->iface_op_failed = TRUE;
3362
+#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
3363
+ if (dhd->memdump_enabled) {
3364
+ dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3365
+ dhd_bus_mem_dump(dhd);
3366
+ }
3367
+#endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
3368
+#if defined(OEM_ANDROID)
3369
+ dhd->hang_reason = HANG_REASON_IFACE_ADD_FAILURE;
3370
+ net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3371
+#endif /* BCMDONGLEHOST && OEM_ANDROID */
3372
+ }
3373
+exit:
3374
+ mutex_unlock(&cfg->if_sync);
3375
+ return NULL;
14613376 }
14623377
14633378 static bcm_struct_cfgdev *
....@@ -1470,623 +3385,503 @@
14703385 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
14713386 unsigned char name_assign_type,
14723387 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
1473
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
14743388 enum nl80211_iftype type,
1475
-#else
1476
- enum nl80211_iftype type, u32 *flags,
1477
-#endif
3389
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3390
+ u32 *flags,
3391
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
14783392 struct vif_params *params)
14793393 {
1480
- s32 err = -ENODEV;
1481
- s32 timeout = -1;
1482
- s32 wlif_type = -1;
1483
- s32 mode = 0;
1484
- s32 val = 0;
1485
- s32 cfg_type;
1486
- s32 dhd_mode = 0;
1487
- chanspec_t chspec;
1488
- struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3394
+ u16 wl_iftype;
3395
+ u16 wl_mode;
14893396 struct net_device *primary_ndev;
1490
- struct net_device *new_ndev;
1491
- struct ether_addr primary_mac;
1492
-#ifdef WL_VIRTUAL_APSTA
1493
- bcm_struct_cfgdev *new_cfgdev;
1494
-#endif /* WL_VIRTUAL_APSTA */
1495
-#ifdef PROP_TXSTATUS_VSDB
1496
-#if defined(BCMSDIO) || defined(BCMDBUS)
1497
- s32 up = 1;
1498
- dhd_pub_t *dhd;
1499
- bool enabled;
1500
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
1501
-#endif /* PROP_TXSTATUS_VSDB */
1502
-#if defined(SUPPORT_AP_POWERSAVE)
1503
- dhd_pub_t *dhd;
1504
-#endif /* SUPPORT_AP_POWERSAVE */
3397
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3398
+ struct wireless_dev *wdev;
15053399
1506
- if (!cfg)
3400
+ WL_DBG(("Enter iftype: %d\n", type));
3401
+ if (!cfg) {
15073402 return ERR_PTR(-EINVAL);
1508
-
1509
-#ifdef PROP_TXSTATUS_VSDB
1510
-#if defined(BCMSDIO) || defined(BCMDBUS)
1511
- dhd = (dhd_pub_t *)(cfg->pub);
1512
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
1513
-#endif /* PROP_TXSTATUS_VSDB */
1514
-#if defined(SUPPORT_AP_POWERSAVE)
1515
- dhd = (dhd_pub_t *)(cfg->pub);
1516
-#endif /* SUPPORT_AP_POWERSAVE */
3403
+ }
15173404
15183405 /* Use primary I/F for sending cmds down to firmware */
15193406 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
1520
-
15213407 if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
15223408 WL_ERR(("device is not ready\n"));
15233409 return ERR_PTR(-ENODEV);
15243410 }
15253411
1526
- WL_DBG(("if name: %s, type: %d\n", name, type));
1527
- switch (type) {
1528
- case NL80211_IFTYPE_ADHOC:
1529
-#ifdef WLAIBSS_MCHAN
1530
- return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
1531
-#endif /* WLAIBSS_MCHAN */
1532
- case NL80211_IFTYPE_AP_VLAN:
1533
- case NL80211_IFTYPE_WDS:
1534
- case NL80211_IFTYPE_MESH_POINT:
1535
- WL_ERR(("Unsupported interface type\n"));
1536
- mode = WL_MODE_IBSS;
1537
- return NULL;
1538
- case NL80211_IFTYPE_MONITOR:
1539
- return wl_cfg80211_add_monitor_if((char *)name);
1540
-#if defined(WL_CFG80211_P2P_DEV_IF)
1541
- case NL80211_IFTYPE_P2P_DEVICE:
1542
- return wl_cfgp2p_add_p2p_disc_if(cfg);
1543
-#endif /* WL_CFG80211_P2P_DEV_IF */
1544
- case NL80211_IFTYPE_STATION:
1545
-#ifdef WL_VIRTUAL_APSTA
1546
-#ifdef WLAIBSS_MCHAN
1547
- if (cfg->ibss_cfgdev) {
1548
- WL_ERR(("AIBSS is already operational. "
1549
- " AIBSS & DUALSTA can't be used together \n"));
1550
- return ERR_PTR(-ENOMEM);
1551
- }
1552
-#endif /* WLAIBSS_MCHAN */
1553
- if (!name) {
1554
- WL_ERR(("Interface name not provided \n"));
1555
- return ERR_PTR(-ENODEV);
1556
- }
1557
-
1558
- if (wl_cfgp2p_vif_created(cfg)) {
1559
- WL_ERR(("Could not create new iface."
1560
- "Already one p2p interface is running"));
1561
- return ERR_PTR(-ENODEV);
1562
- }
1563
- new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
1564
- NL80211_IFTYPE_STATION, NULL, name);
1565
- if (!new_cfgdev)
1566
- return ERR_PTR(-ENOMEM);
1567
- else
1568
- return new_cfgdev;
1569
-#endif /* WL_VIRTUAL_APSTA */
1570
- case NL80211_IFTYPE_P2P_CLIENT:
1571
- wlif_type = WL_P2P_IF_CLIENT;
1572
- mode = WL_MODE_BSS;
1573
- break;
1574
- case NL80211_IFTYPE_P2P_GO:
1575
- case NL80211_IFTYPE_AP:
1576
- wlif_type = WL_P2P_IF_GO;
1577
- mode = WL_MODE_AP;
1578
- break;
1579
- default:
1580
- WL_ERR(("Unsupported interface type\n"));
1581
- return ERR_PTR(-ENODEV);
1582
- break;
1583
- }
1584
-
15853412 if (!name) {
1586
- WL_ERR(("name is NULL\n"));
3413
+ WL_ERR(("Interface name not provided \n"));
3414
+ return ERR_PTR(-EINVAL);
3415
+ }
3416
+
3417
+ if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3418
+ return ERR_PTR(-EINVAL);
3419
+ }
3420
+
3421
+ wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, name, NULL);
3422
+ if (unlikely(!wdev)) {
15873423 return ERR_PTR(-ENODEV);
15883424 }
1589
- if (cfg->p2p_supported && (wlif_type != -1)) {
1590
- ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */
15913425
1592
-#ifdef PROP_TXSTATUS_VSDB
1593
-#if defined(BCMSDIO) || defined(BCMDBUS)
1594
- if (!dhd)
1595
- return ERR_PTR(-ENODEV);
1596
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
1597
-#endif /* PROP_TXSTATUS_VSDB */
1598
- if (!cfg->p2p)
1599
- return ERR_PTR(-ENODEV);
3426
+ return wdev_to_cfgdev(wdev);
3427
+}
16003428
1601
- if (cfg->cfgdev_bssidx != -1) {
1602
- WL_ERR(("Failed to start p2p, Maximum no of interface reached"));
1603
- return ERR_PTR(-ENODEV);
1604
- }
1605
-
1606
- if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
1607
- p2p_on(cfg) = true;
1608
- wl_cfgp2p_set_firm_p2p(cfg);
1609
- wl_cfgp2p_init_discovery(cfg);
1610
- get_primary_mac(cfg, &primary_mac);
1611
- wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
1612
- }
1613
-
1614
- strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1);
1615
- cfg->p2p->vir_ifname[IFNAMSIZ - 1] = '\0';
1616
-
1617
- wl_cfg80211_scan_abort(cfg);
1618
-#ifdef PROP_TXSTATUS_VSDB
1619
-#if defined(BCMSDIO) || defined(BCMDBUS)
1620
- if (!cfg->wlfc_on && !disable_proptx) {
1621
- dhd_wlfc_get_enable(dhd, &enabled);
1622
- if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1623
- dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1624
- dhd_wlfc_init(dhd);
1625
- err = wldev_ioctl(primary_ndev, WLC_UP, &up, sizeof(s32), true);
1626
- if (err < 0)
1627
- WL_ERR(("WLC_UP return err:%d\n", err));
1628
- }
1629
- cfg->wlfc_on = true;
1630
- }
1631
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
1632
-#endif /* PROP_TXSTATUS_VSDB */
1633
-
1634
- /* Dual p2p doesn't support multiple P2PGO interfaces,
1635
- * p2p_go_count is the counter for GO creation
1636
- * requests.
1637
- */
1638
- if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
1639
- WL_ERR(("Fw doesnot support multiple Go"));
1640
- return ERR_PTR(-ENOMEM);
1641
- }
1642
- /* In concurrency case, STA may be already associated in a particular channel.
1643
- * so retrieve the current channel of primary interface and then start the virtual
1644
- * interface on that.
1645
- */
1646
- chspec = wl_cfg80211_get_shared_freq(wiphy);
1647
-
1648
- /* For P2P mode, use P2P-specific driver features to create the
1649
- * bss: "cfg p2p_ifadd"
1650
- */
1651
- wl_set_p2p_status(cfg, IF_ADDING);
1652
- memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
1653
- if (wlif_type == WL_P2P_IF_GO)
1654
- wldev_iovar_setint(primary_ndev, "mpc", 0);
1655
- cfg_type = wl_cfgp2p_get_conn_idx(cfg);
1656
- if (cfg_type == BCME_ERROR) {
1657
- wl_clr_p2p_status(cfg, IF_ADDING);
1658
- WL_ERR(("Failed to get connection idx for p2p interface"));
1659
- goto fail;
1660
- }
1661
- err = wl_cfgp2p_ifadd(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type),
1662
- htod32(wlif_type), chspec);
1663
- if (unlikely(err)) {
1664
- wl_clr_p2p_status(cfg, IF_ADDING);
1665
- WL_ERR((" virtual iface add failed (%d) \n", err));
1666
- return ERR_PTR(-ENOMEM);
1667
- }
1668
-
1669
- timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1670
- ((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
1671
- (cfg->if_event_info.valid)), msecs_to_jiffies(MAX_WAIT_TIME));
1672
-
1673
- if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
1674
- struct wireless_dev *vwdev;
1675
- int pm_mode = PM_ENABLE;
1676
- wl_if_event_info *event = &cfg->if_event_info;
1677
- /* IF_ADD event has come back, we can proceed to to register
1678
- * the new interface now, use the interface name provided by caller (thus
1679
- * ignore the one from wlc)
1680
- */
1681
- new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname,
1682
- event->mac, event->bssidx, event->name);
1683
- if (new_ndev == NULL)
1684
- goto fail;
1685
-
1686
- wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
1687
- wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
1688
- vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
1689
- if (unlikely(!vwdev)) {
1690
- WL_ERR(("Could not allocate wireless device\n"));
1691
- err = -ENOMEM;
1692
- goto fail;
1693
- }
1694
- vwdev->wiphy = cfg->wdev->wiphy;
1695
- WL_INFORM(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname));
1696
- if (type == NL80211_IFTYPE_P2P_GO) {
1697
- cfg->p2p->p2p_go_count++;
1698
- }
1699
- vwdev->iftype = type;
1700
- vwdev->netdev = new_ndev;
1701
- new_ndev->ieee80211_ptr = vwdev;
1702
- SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy));
1703
- wl_set_drv_status(cfg, READY, new_ndev);
1704
- wl_set_mode_by_netdev(cfg, new_ndev, mode);
1705
-
1706
- if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
1707
- wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
1708
- err = -ENODEV;
1709
- goto fail;
1710
- }
1711
- err = wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode, event->bssidx);
1712
- if (unlikely(err != 0)) {
1713
- WL_ERR(("Allocation of netinfo failed (%d) \n", err));
1714
- goto fail;
1715
- }
1716
- val = 1;
1717
- /* Disable firmware roaming for P2P interface */
1718
- wldev_iovar_setint(new_ndev, "roam_off", val);
1719
-#ifdef WL11ULB
1720
- if (cfg->p2p_wdev && is_p2p_group_iface(new_ndev->ieee80211_ptr)) {
1721
- u32 ulb_bw = wl_cfg80211_get_ulb_bw(cfg->p2p_wdev);
1722
- if (ulb_bw) {
1723
- /* Apply ULB BW settings on the newly spawned interface */
1724
- WL_DBG(("[ULB] Applying ULB BW for the newly"
1725
- "created P2P interface \n"));
1726
- if (wl_cfg80211_set_ulb_bw(new_ndev,
1727
- ulb_bw, new_ndev->name) < 0) {
1728
- /*
1729
- * If ulb_bw set failed, fail the iface creation.
1730
- * wl_dealloc_netinfo_by_wdev will be called by the
1731
- * unregister notifier.
1732
- */
1733
- wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
1734
- err = -EINVAL;
1735
- goto fail;
1736
- }
1737
- }
1738
- }
1739
-#endif /* WL11ULB */
1740
-
1741
- if (mode != WL_MODE_AP)
1742
- wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1);
1743
-
1744
- WL_ERR((" virtual interface(%s) is "
1745
- "created net attach done\n", cfg->p2p->vir_ifname));
1746
-#ifdef SUPPORT_AP_POWERSAVE
1747
- if (mode == WL_MODE_AP) {
1748
- dhd_set_ap_powersave(dhd, 0, TRUE);
1749
- }
1750
-#endif /* SUPPORT_AP_POWERSAVE */
1751
- if (type == NL80211_IFTYPE_P2P_CLIENT)
1752
- dhd_mode = DHD_FLAG_P2P_GC_MODE;
1753
- else if (type == NL80211_IFTYPE_P2P_GO)
1754
- dhd_mode = DHD_FLAG_P2P_GO_MODE;
1755
- DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
1756
- /* reinitialize completion to clear previous count */
1757
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
1758
- INIT_COMPLETION(cfg->iface_disable);
3429
+static s32
3430
+wl_cfg80211_del_ibss(struct wiphy *wiphy, struct wireless_dev *wdev)
3431
+{
3432
+ WL_INFORM_MEM(("del ibss wdev_ptr:%p\n", wdev));
3433
+#ifdef WLAIBSS_MCHAN
3434
+ /* AIBSS */
3435
+ return bcm_cfg80211_del_ibss_if(wiphy, wdev);
17593436 #else
1760
- init_completion(&cfg->iface_disable);
1761
-#endif
1762
- return ndev_to_cfgdev(new_ndev);
3437
+ /* Normal IBSS */
3438
+ return wl_cfg80211_del_iface(wiphy, wdev);
3439
+#endif // endif
3440
+}
3441
+
3442
+s32
3443
+wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
3444
+ struct wireless_dev *wdev, char *ifname)
3445
+{
3446
+ int ret = BCME_OK;
3447
+ mutex_lock(&cfg->if_sync);
3448
+ ret = _wl_cfg80211_del_if(cfg, primary_ndev, wdev, ifname);
3449
+ mutex_unlock(&cfg->if_sync);
3450
+ return ret;
3451
+}
3452
+
3453
+s32
3454
+_wl_cfg80211_del_if(struct bcm_cfg80211 *cfg, struct net_device *primary_ndev,
3455
+ struct wireless_dev *wdev, char *ifname)
3456
+{
3457
+ int ret = BCME_OK;
3458
+ s32 bssidx;
3459
+ struct wiphy *wiphy;
3460
+ u16 wl_mode;
3461
+ u16 wl_iftype;
3462
+ struct net_info *netinfo;
3463
+ dhd_pub_t *dhd;
3464
+ BCM_REFERENCE(dhd);
3465
+
3466
+ if (!cfg) {
3467
+ return -EINVAL;
3468
+ }
3469
+
3470
+ dhd = (dhd_pub_t *)(cfg->pub);
3471
+
3472
+ if (!wdev && ifname) {
3473
+ /* If only ifname is provided, fetch corresponding wdev ptr from our
3474
+ * internal data structure
3475
+ */
3476
+ wdev = wl_cfg80211_get_wdev_from_ifname(cfg, ifname);
3477
+ }
3478
+
3479
+ /* Check whether we have a valid wdev ptr */
3480
+ if (unlikely(!wdev)) {
3481
+ WL_ERR(("wdev not found. '%s' does not exists\n", ifname));
3482
+ return -ENODEV;
3483
+ }
3484
+
3485
+ WL_INFORM_MEM(("del vif. wdev cfg_iftype:%d\n", wdev->iftype));
3486
+
3487
+ wiphy = wdev->wiphy;
3488
+#ifdef WL_CFG80211_P2P_DEV_IF
3489
+ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
3490
+ /* p2p discovery would be de-initialized in stop p2p
3491
+ * device context/from other virtual i/f creation context
3492
+ * so netinfo list may not have any node corresponding to
3493
+ * discovery I/F. Handle it before bssidx check.
3494
+ */
3495
+ ret = wl_cfg80211_p2p_if_del(wiphy, wdev);
3496
+ if (unlikely(ret)) {
3497
+ goto exit;
17633498 } else {
1764
- wl_clr_p2p_status(cfg, IF_ADDING);
1765
- WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname));
1766
-
1767
- WL_ERR(("left timeout : %d\n", timeout));
1768
- WL_ERR(("IF_ADDING status : %d\n", wl_get_p2p_status(cfg, IF_ADDING)));
1769
- WL_ERR(("event valid : %d\n", cfg->if_event_info.valid));
1770
-
1771
- wl_clr_p2p_status(cfg, GO_NEG_PHASE);
1772
- wl_set_p2p_status(cfg, IF_DELETING);
1773
-
1774
- err = wl_cfgp2p_ifdel(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
1775
- if (err == BCME_OK) {
1776
- timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1777
- ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
1778
- (cfg->if_event_info.valid)),
1779
- msecs_to_jiffies(MAX_WAIT_TIME));
1780
- if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
1781
- cfg->if_event_info.valid) {
1782
- WL_ERR(("IFDEL operation done\n"));
1783
- } else {
1784
- WL_ERR(("IFDEL didn't complete properly\n"));
1785
- err = BCME_ERROR;
1786
- }
3499
+ /* success case. return from here */
3500
+ if (cfg->vif_count) {
3501
+ cfg->vif_count--;
17873502 }
1788
- if (err != BCME_OK) {
1789
- struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
1790
-
1791
- WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n",
1792
- err, ndev->name));
1793
- net_os_send_hang_message(ndev);
1794
- }
1795
-
1796
- memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
1797
- wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
1798
-#ifdef PROP_TXSTATUS_VSDB
1799
-#if defined(BCMSDIO) || defined(BCMDBUS)
1800
- dhd_wlfc_get_enable(dhd, &enabled);
1801
- if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
1802
- dhd->op_mode != DHD_FLAG_IBSS_MODE) {
1803
- dhd_wlfc_deinit(dhd);
1804
- cfg->wlfc_on = false;
1805
- }
1806
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
1807
-#endif /* PROP_TXSTATUS_VSDB */
3503
+ return BCME_OK;
18083504 }
18093505 }
1810
-fail:
1811
- if (wlif_type == WL_P2P_IF_GO)
1812
- wldev_iovar_setint(primary_ndev, "mpc", 1);
1813
- return ERR_PTR(err);
3506
+#endif /* WL_CFG80211_P2P_DEV_IF */
3507
+
3508
+ if ((netinfo = wl_get_netinfo_by_wdev(cfg, wdev)) == NULL) {
3509
+ WL_ERR(("Find netinfo from wdev %p failed\n", wdev));
3510
+ ret = -ENODEV;
3511
+ goto exit;
3512
+ }
3513
+
3514
+ if (!wdev->netdev) {
3515
+ WL_ERR(("ndev null! \n"));
3516
+ } else {
3517
+ /* Disable tx before del */
3518
+ netif_tx_disable(wdev->netdev);
3519
+ }
3520
+
3521
+ wl_iftype = netinfo->iftype;
3522
+ wl_mode = wl_iftype_to_mode(wl_iftype);
3523
+ bssidx = netinfo->bssidx;
3524
+ WL_INFORM_MEM(("[IFDEL] cfg_iftype:%d wl_iftype:%d mode:%d bssidx:%d\n",
3525
+ wdev->iftype, wl_iftype, wl_mode, bssidx));
3526
+
3527
+ /* Do pre-interface del ops */
3528
+ wl_cfg80211_iface_state_ops(wdev, WL_IF_DELETE_REQ, wl_iftype, wl_mode);
3529
+
3530
+ switch (wl_iftype) {
3531
+ case WL_IF_TYPE_P2P_GO:
3532
+ case WL_IF_TYPE_P2P_GC:
3533
+ case WL_IF_TYPE_AP:
3534
+ case WL_IF_TYPE_STA:
3535
+ case WL_IF_TYPE_NAN:
3536
+ ret = wl_cfg80211_del_iface(wiphy, wdev);
3537
+ break;
3538
+ case WL_IF_TYPE_IBSS:
3539
+ ret = wl_cfg80211_del_ibss(wiphy, wdev);
3540
+ break;
3541
+
3542
+ default:
3543
+ WL_ERR(("Unsupported interface type\n"));
3544
+ ret = BCME_ERROR;
3545
+ }
3546
+
3547
+exit:
3548
+ if (ret == BCME_OK) {
3549
+ /* Successful case */
3550
+ if (cfg->vif_count) {
3551
+ cfg->vif_count--;
3552
+ }
3553
+ wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3554
+ WL_IF_DELETE_DONE, wl_iftype, wl_mode);
3555
+#ifdef WL_NAN
3556
+ if (!((cfg->nancfg.mac_rand) && (wl_iftype == WL_IF_TYPE_NAN)))
3557
+#endif /* WL_NAN */
3558
+ {
3559
+ wl_release_vif_macaddr(cfg, wdev->netdev->dev_addr, wl_iftype);
3560
+ }
3561
+ WL_INFORM_MEM(("vif deleted. vif_count:%d\n", cfg->vif_count));
3562
+ } else {
3563
+ if (!wdev->netdev) {
3564
+ WL_ERR(("ndev null! \n"));
3565
+ } else {
3566
+ /* IF del failed. revert back tx queue status */
3567
+ netif_tx_start_all_queues(wdev->netdev);
3568
+ }
3569
+
3570
+ /* Skip generating log files and sending HANG event
3571
+ * if driver state is not READY
3572
+ */
3573
+ if (wl_get_drv_status(cfg, READY, bcmcfg_to_prmry_ndev(cfg))) {
3574
+#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
3575
+ wl_copy_hang_info_if_falure(primary_ndev,
3576
+ HANG_REASON_IFACE_DEL_FAILURE, ret);
3577
+#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
3578
+ SUPP_LOG(("IF_DEL fail. err:%d\n", ret));
3579
+ wl_flush_fw_log_buffer(primary_ndev, FW_LOGSET_MASK_ALL);
3580
+ /* IF dongle is down due to previous hang or other conditions, sending
3581
+ * one more hang notification is not needed.
3582
+ */
3583
+ if (dhd_query_bus_erros(dhd) || (ret == BCME_DONGLE_DOWN)) {
3584
+ goto end;
3585
+ }
3586
+ dhd->iface_op_failed = TRUE;
3587
+#if defined(DHD_FW_COREDUMP)
3588
+ if (dhd->memdump_enabled && (ret != -EBADTYPE)) {
3589
+ dhd->memdump_type = DUMP_TYPE_IFACE_OP_FAILURE;
3590
+ dhd_bus_mem_dump(dhd);
3591
+ }
3592
+#endif /* DHD_FW_COREDUMP */
3593
+#if defined(OEM_ANDROID)
3594
+ WL_ERR(("Notify hang event to upper layer \n"));
3595
+ dhd->hang_reason = HANG_REASON_IFACE_DEL_FAILURE;
3596
+ net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
3597
+#endif /* BCMDONGLEHOST && OEM_ANDROID */
3598
+ }
3599
+ }
3600
+end:
3601
+ return ret;
18143602 }
18153603
18163604 static s32
18173605 wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
18183606 {
1819
- struct net_device *dev = NULL;
1820
- struct ether_addr p2p_mac;
18213607 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1822
- s32 timeout = -1;
1823
- s32 ret = 0;
1824
- s32 index = -1;
1825
- s32 type = -1;
1826
-#ifdef CUSTOM_SET_CPUCORE
1827
- dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
1828
-#endif /* CUSTOM_SET_CPUCORE */
1829
- WL_DBG(("Enter\n"));
3608
+ struct wireless_dev *wdev = cfgdev_to_wdev(cfgdev);
3609
+ int ret = BCME_OK;
3610
+ u16 wl_iftype;
3611
+ u16 wl_mode;
3612
+ struct net_device *primary_ndev;
18303613
1831
-#ifdef CUSTOM_SET_CPUCORE
1832
- dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
1833
- if (!(dhd->chan_isvht80))
1834
- dhd_set_cpucore(dhd, FALSE);
1835
-#endif /* CUSTOM_SET_CPUCORE */
1836
-#if defined(WL_CFG80211_P2P_DEV_IF)
1837
- if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
1838
- return wl_cfgp2p_del_p2p_disc_if(cfgdev, cfg);
3614
+ if (!cfg) {
3615
+ return -EINVAL;
18393616 }
1840
-#endif /* WL_CFG80211_P2P_DEV_IF */
1841
- dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
18423617
1843
-#ifdef WLAIBSS_MCHAN
1844
- if (cfgdev == cfg->ibss_cfgdev)
1845
- return bcm_cfg80211_del_ibss_if(wiphy, cfgdev);
1846
-#endif /* WLAIBSS_MCHAN */
1847
-
1848
-#ifdef WL_VIRTUAL_APSTA
1849
- if (cfgdev == cfg->bss_cfgdev)
1850
- return wl_cfg80211_del_iface(wiphy, cfgdev);
1851
-#endif /* WL_VIRTUAL_APSTA */
1852
- if ((index = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
1853
- WL_ERR(("Find p2p index from wdev failed\n"));
1854
- return BCME_ERROR;
3618
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3619
+ wdev = cfgdev_to_wdev(cfgdev);
3620
+ if (!wdev) {
3621
+ WL_ERR(("wdev null"));
3622
+ return -ENODEV;
18553623 }
1856
- if (cfg->p2p_supported) {
1857
- if (wl_cfgp2p_find_type(cfg, index, &type) != BCME_OK)
1858
- return BCME_ERROR;
1859
- memcpy(p2p_mac.octet, wl_to_p2p_bss_macaddr(cfg, type).octet, ETHER_ADDR_LEN);
18603624
1861
- /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases
1862
- */
1863
- WL_DBG(("P2P: GO_NEG_PHASE status cleared "));
1864
- wl_clr_p2p_status(cfg, GO_NEG_PHASE);
1865
- if (wl_cfgp2p_vif_created(cfg)) {
1866
- if (wl_get_drv_status(cfg, SCANNING, dev)) {
1867
- wl_notify_escan_complete(cfg, dev, true, true);
1868
- }
1869
- wldev_iovar_setint(dev, "mpc", 1);
1870
- /* Delete pm_enable_work */
1871
- wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
1872
-
1873
- /* for GC */
1874
- if (wl_get_drv_status(cfg, DISCONNECTING, dev) &&
1875
- (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)) {
1876
- WL_ERR(("Wait for Link Down event for GC !\n"));
1877
- wait_for_completion_timeout
1878
- (&cfg->iface_disable, msecs_to_jiffies(500));
1879
- }
1880
-
1881
- memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
1882
- wl_set_p2p_status(cfg, IF_DELETING);
1883
- DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
1884
-
1885
- /* for GO */
1886
- if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
1887
- wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
1888
- cfg->p2p->p2p_go_count--;
1889
- /* disable interface before bsscfg free */
1890
- ret = wl_cfgp2p_ifdisable(cfg, &p2p_mac);
1891
- /* if fw doesn't support "ifdis",
1892
- do not wait for link down of ap mode
1893
- */
1894
- if (ret == 0) {
1895
- WL_ERR(("Wait for Link Down event for GO !!!\n"));
1896
- wait_for_completion_timeout(&cfg->iface_disable,
1897
- msecs_to_jiffies(500));
1898
- } else if (ret != BCME_UNSUPPORTED) {
1899
- msleep(300);
1900
- }
1901
- }
1902
- wl_cfg80211_clear_per_bss_ies(cfg, index);
1903
-
1904
- if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)
1905
- wldev_iovar_setint(dev, "buf_key_b4_m4", 0);
1906
- memcpy(p2p_mac.octet, wl_to_p2p_bss_macaddr(cfg, type).octet,
1907
- ETHER_ADDR_LEN);
1908
- CFGP2P_INFO(("primary idx %d : cfg p2p_ifdis "MACDBG"\n",
1909
- dev->ifindex, MAC2STRDBG(p2p_mac.octet)));
1910
-
1911
- /* delete interface after link down */
1912
- ret = wl_cfgp2p_ifdel(cfg, &p2p_mac);
1913
- if (ret != BCME_OK) {
1914
- struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
1915
-
1916
- WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n",
1917
- ret, ndev->name));
1918
- net_os_send_hang_message(ndev);
1919
- } else {
1920
- /* Wait for IF_DEL operation to be finished */
1921
- timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
1922
- ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
1923
- (cfg->if_event_info.valid)),
1924
- msecs_to_jiffies(MAX_WAIT_TIME));
1925
- if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
1926
- cfg->if_event_info.valid) {
1927
-
1928
- WL_DBG(("IFDEL operation done\n"));
1929
- wl_cfg80211_handle_ifdel(cfg, &cfg->if_event_info, dev);
1930
- } else {
1931
- WL_ERR(("IFDEL didn't complete properly\n"));
1932
- }
1933
- }
1934
-
1935
- ret = dhd_del_monitor(dev);
1936
- if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
1937
- DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL((dhd_pub_t *)(cfg->pub));
1938
- }
1939
- }
3625
+ WL_DBG(("Enter wdev:%p iftype: %d\n", wdev, wdev->iftype));
3626
+ if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
3627
+ WL_ERR(("Wrong iftype: %d\n", wdev->iftype));
3628
+ return -ENODEV;
19403629 }
3630
+
3631
+ if ((ret = wl_cfg80211_del_if(cfg, primary_ndev,
3632
+ wdev, NULL)) < 0) {
3633
+ WL_ERR(("IF del failed\n"));
3634
+ }
3635
+
19413636 return ret;
19423637 }
19433638
19443639 static s32
1945
-wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
1946
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
1947
- enum nl80211_iftype type,
1948
-#else
1949
- enum nl80211_iftype type, u32 *flags,
1950
-#endif
1951
- struct vif_params *params)
3640
+wl_cfg80211_change_p2prole(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type)
19523641 {
1953
- s32 ap = 0;
1954
- s32 infra = 0;
1955
- s32 ibss = 0;
19563642 s32 wlif_type;
19573643 s32 mode = 0;
1958
- s32 err = BCME_OK;
19593644 s32 index;
3645
+ s32 err;
19603646 s32 conn_idx = -1;
19613647 chanspec_t chspec;
19623648 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1963
- struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
19643649 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3650
+#if defined(WL_SUPPORT_MULTIP2P)
3651
+ s32 is_mp2p_supported = BCME_ERROR;
3652
+#endif /* WL_SUPPORT_MULTIP2P */
19653653
1966
- WL_DBG(("Enter type %d\n", type));
3654
+ WL_INFORM_MEM(("Enter. current_role:%d new_role:%d \n", ndev->ieee80211_ptr->iftype, type));
3655
+
3656
+ if (!cfg->p2p || !wl_cfgp2p_vif_created(cfg)) {
3657
+ WL_ERR(("P2P not initialized \n"));
3658
+ return -EINVAL;
3659
+ }
3660
+
3661
+ if (!is_p2p_group_iface(ndev->ieee80211_ptr)) {
3662
+ WL_ERR(("Wrong if type \n"));
3663
+ return -EINVAL;
3664
+ }
3665
+
3666
+ /* Abort any on-going scans to avoid race condition issues */
3667
+ wl_cfg80211_cancel_scan(cfg);
3668
+
3669
+ index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
3670
+ if (index < 0) {
3671
+ WL_ERR(("Find bsscfg index from ndev(%p) failed\n", ndev));
3672
+ return BCME_ERROR;
3673
+ }
3674
+ if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK) {
3675
+ return BCME_ERROR;
3676
+ }
3677
+
3678
+#if defined(WL_SUPPORT_MULTIP2P)
3679
+ is_mp2p_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_MP2P_MODE);
3680
+#endif /* WL_SUPPORT_MULTIP2P */
3681
+ /* In concurrency case, STA may be already associated in a particular
3682
+ * channel. so retrieve the current channel of primary interface and
3683
+ * then start the virtual interface on that.
3684
+ */
3685
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
3686
+ if (type == NL80211_IFTYPE_P2P_GO) {
3687
+ /* Dual p2p doesn't support multiple P2PGO interfaces,
3688
+ * p2p_go_count is the counter for GO creation
3689
+ * requests.
3690
+ */
3691
+ if (TRUE &&
3692
+#if defined(WL_SUPPORT_MULTIP2P)
3693
+ (is_mp2p_supported <= 0) &&
3694
+#endif // endif
3695
+ (cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
3696
+ WL_ERR(("FW does not support multiple GO\n"));
3697
+ return BCME_ERROR;
3698
+ }
3699
+ mode = WL_MODE_AP;
3700
+ wlif_type = WL_P2P_IF_GO;
3701
+ dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
3702
+ dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
3703
+ } else {
3704
+ wlif_type = WL_P2P_IF_CLIENT;
3705
+ /* for GO */
3706
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
3707
+ WL_INFORM_MEM(("Downgrading P2P GO to cfg_iftype:%d \n", type));
3708
+ wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
3709
+ cfg->p2p->p2p_go_count--;
3710
+ /* disable interface before bsscfg free */
3711
+ err = wl_cfgp2p_ifdisable(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx));
3712
+ /* if fw doesn't support "ifdis",
3713
+ * do not wait for link down of ap mode
3714
+ */
3715
+ if (err == 0) {
3716
+ WL_DBG(("Wait for Link Down event for GO !!!\n"));
3717
+ wait_for_completion_timeout(&cfg->iface_disable,
3718
+ msecs_to_jiffies(500));
3719
+ } else if (err != BCME_UNSUPPORTED) {
3720
+ msleep(300);
3721
+ }
3722
+ }
3723
+ }
3724
+
3725
+ wl_set_p2p_status(cfg, IF_CHANGING);
3726
+ wl_clr_p2p_status(cfg, IF_CHANGED);
3727
+ wl_cfgp2p_ifchange(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx),
3728
+ htod32(wlif_type), chspec, conn_idx);
3729
+ wait_event_interruptible_timeout(cfg->netif_change_event,
3730
+ (wl_get_p2p_status(cfg, IF_CHANGED) == true),
3731
+ msecs_to_jiffies(MAX_WAIT_TIME));
3732
+
3733
+ wl_clr_p2p_status(cfg, IF_CHANGING);
3734
+ wl_clr_p2p_status(cfg, IF_CHANGED);
3735
+
3736
+ if (mode == WL_MODE_AP) {
3737
+ wl_set_drv_status(cfg, CONNECTED, ndev);
3738
+ }
3739
+
3740
+ return BCME_OK;
3741
+}
3742
+
3743
+static s32
3744
+wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
3745
+ enum nl80211_iftype type,
3746
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
3747
+ u32 *flags,
3748
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
3749
+ struct vif_params *params)
3750
+{
3751
+ s32 infra = 1;
3752
+ s32 err = BCME_OK;
3753
+ u16 wl_iftype;
3754
+ u16 wl_mode;
3755
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3756
+ struct net_info *netinfo = NULL;
3757
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
3758
+ struct net_device *primary_ndev;
3759
+
3760
+ if (!dhd)
3761
+ return -EINVAL;
3762
+
3763
+ WL_INFORM_MEM(("[%s] Enter. current cfg_iftype:%d new cfg_iftype:%d \n",
3764
+ ndev->name, ndev->ieee80211_ptr->iftype, type));
3765
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3766
+
3767
+ if (cfg80211_to_wl_iftype(type, &wl_iftype, &wl_mode) < 0) {
3768
+ WL_ERR(("Unknown role \n"));
3769
+ return -EINVAL;
3770
+ }
3771
+
3772
+ mutex_lock(&cfg->if_sync);
3773
+ netinfo = wl_get_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
3774
+ if (unlikely(!netinfo)) {
3775
+#ifdef WL_STATIC_IF
3776
+ if (is_static_iface(cfg, ndev)) {
3777
+ /* Incase of static interfaces, the netinfo will be
3778
+ * allocated only when FW interface is initialized. So
3779
+ * store the value and use it during initialization.
3780
+ */
3781
+ WL_INFORM_MEM(("skip change vif for static if\n"));
3782
+ ndev->ieee80211_ptr->iftype = type;
3783
+ err = BCME_OK;
3784
+ } else
3785
+#endif /* WL_STATIC_IF */
3786
+ {
3787
+ WL_ERR(("netinfo not found \n"));
3788
+ err = -ENODEV;
3789
+ }
3790
+ goto fail;
3791
+ }
3792
+
3793
+ /* perform pre-if-change tasks */
3794
+ wl_cfg80211_iface_state_ops(ndev->ieee80211_ptr,
3795
+ WL_IF_CHANGE_REQ, wl_iftype, wl_mode);
3796
+
19673797 switch (type) {
3798
+ case NL80211_IFTYPE_ADHOC:
3799
+ infra = 0;
3800
+ break;
3801
+ case NL80211_IFTYPE_STATION:
3802
+ /* Supplicant sets iftype to STATION while removing p2p GO */
3803
+ if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
3804
+ /* Downgrading P2P GO */
3805
+ err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3806
+ if (unlikely(err)) {
3807
+ WL_ERR(("P2P downgrade failed \n"));
3808
+ }
3809
+ } else if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
3810
+ /* Downgrade role from AP to STA */
3811
+ if ((err = wl_cfg80211_add_del_bss(cfg, ndev,
3812
+ netinfo->bssidx, wl_iftype, 0, NULL)) < 0) {
3813
+ WL_ERR(("AP-STA Downgrade failed \n"));
3814
+ goto fail;
3815
+ }
3816
+ }
3817
+ break;
3818
+ case NL80211_IFTYPE_AP:
3819
+ /* intentional fall through */
3820
+ case NL80211_IFTYPE_AP_VLAN:
3821
+ {
3822
+ if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
3823
+ dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
3824
+ err = wl_cfg80211_set_ap_role(cfg, ndev);
3825
+ if (unlikely(err)) {
3826
+ WL_ERR(("set ap role failed!\n"));
3827
+ goto fail;
3828
+ }
3829
+ } else {
3830
+ WL_INFORM_MEM(("AP_CREATED bit set. Skip role change\n"));
3831
+ }
3832
+ break;
3833
+ }
3834
+ case NL80211_IFTYPE_P2P_GO:
3835
+ /* Intentional fall through */
3836
+ case NL80211_IFTYPE_P2P_CLIENT:
3837
+ infra = 1;
3838
+ err = wl_cfg80211_change_p2prole(wiphy, ndev, type);
3839
+ break;
19683840 case NL80211_IFTYPE_MONITOR:
19693841 case NL80211_IFTYPE_WDS:
19703842 case NL80211_IFTYPE_MESH_POINT:
1971
- ap = 1;
1972
- WL_ERR(("type (%d) : currently we do not support this type\n",
1973
- type));
1974
- break;
1975
- case NL80211_IFTYPE_ADHOC:
1976
- mode = WL_MODE_IBSS;
1977
- ibss = 1;
1978
- break;
1979
- case NL80211_IFTYPE_STATION:
1980
- case NL80211_IFTYPE_P2P_CLIENT:
1981
- mode = WL_MODE_BSS;
1982
- infra = 1;
1983
- break;
1984
- case NL80211_IFTYPE_AP:
1985
- dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
1986
- /* intentional fall through */
1987
- case NL80211_IFTYPE_AP_VLAN:
1988
- case NL80211_IFTYPE_P2P_GO:
1989
- mode = WL_MODE_AP;
1990
- ap = 1;
1991
- break;
3843
+ /* Intentional fall through */
19923844 default:
1993
- return -EINVAL;
1994
- }
1995
- if (!dhd)
1996
- return -EINVAL;
1997
- if (ap) {
1998
- wl_set_mode_by_netdev(cfg, ndev, mode);
1999
- if (is_p2p_group_iface(ndev->ieee80211_ptr) &&
2000
- cfg->p2p && wl_cfgp2p_vif_created(cfg)) {
2001
- WL_DBG(("p2p_vif_created p2p_on (%d)\n", p2p_on(cfg)));
2002
- wldev_iovar_setint(ndev, "mpc", 0);
2003
- wl_notify_escan_complete(cfg, ndev, true, true);
2004
-
2005
- /* Dual p2p doesn't support multiple P2PGO interfaces,
2006
- * p2p_go_count is the counter for GO creation
2007
- * requests.
2008
- */
2009
- if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
2010
- wl_set_mode_by_netdev(cfg, ndev, WL_MODE_BSS);
2011
- WL_ERR(("Fw doesnot support multiple GO "));
2012
- return BCME_ERROR;
2013
- }
2014
- /* In concurrency case, STA may be already associated in a particular
2015
- * channel. so retrieve the current channel of primary interface and
2016
- * then start the virtual interface on that.
2017
- */
2018
- chspec = wl_cfg80211_get_shared_freq(wiphy);
2019
- index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
2020
- if (index < 0) {
2021
- WL_ERR(("Find p2p index from ndev(%p) failed\n", ndev));
2022
- return BCME_ERROR;
2023
- }
2024
- if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK)
2025
- return BCME_ERROR;
2026
-
2027
- wlif_type = WL_P2P_IF_GO;
2028
- WL_DBG(("%s : ap (%d), infra (%d), iftype (%d) conn_idx (%d)\n",
2029
- ndev->name, ap, infra, type, conn_idx));
2030
- wl_set_p2p_status(cfg, IF_CHANGING);
2031
- wl_clr_p2p_status(cfg, IF_CHANGED);
2032
- wl_cfgp2p_ifchange(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx),
2033
- htod32(wlif_type), chspec, conn_idx);
2034
- wait_event_interruptible_timeout(cfg->netif_change_event,
2035
- (wl_get_p2p_status(cfg, IF_CHANGED) == true),
2036
- msecs_to_jiffies(MAX_WAIT_TIME));
2037
- wl_set_mode_by_netdev(cfg, ndev, mode);
2038
- dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
2039
- dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
2040
- wl_clr_p2p_status(cfg, IF_CHANGING);
2041
- wl_clr_p2p_status(cfg, IF_CHANGED);
2042
-#ifdef SUPPORT_AP_POWERSAVE
2043
- dhd_set_ap_powersave(dhd, 0, TRUE);
2044
-#endif /* SUPPORT_AP_POWERSAVE */
2045
- } else if (((ndev == primary_ndev) ||
2046
- (ndev == ((struct net_device *)cfgdev_to_ndev(cfg->bss_cfgdev)))) &&
2047
- !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
2048
- wl_set_drv_status(cfg, AP_CREATING, ndev);
2049
- } else {
2050
- WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
2051
- return -EINVAL;
2052
- }
2053
- } else {
2054
- /* P2P GO interface deletion is handled on the basis of role type (AP).
2055
- * So avoid changing role for p2p type.
2056
- */
2057
- if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
2058
- wl_set_mode_by_netdev(cfg, ndev, mode);
2059
- WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA"));
2060
-#ifdef SUPPORT_AP_POWERSAVE
2061
- dhd_set_ap_powersave(dhd, 0, FALSE);
2062
-#endif /* SUPPORT_AP_POWERSAVE */
3845
+ WL_ERR(("Unsupported type:%d \n", type));
3846
+ err = -EINVAL;
3847
+ goto fail;
20633848 }
20643849
2065
- if (ibss) {
2066
- infra = 0;
2067
- wl_set_mode_by_netdev(cfg, ndev, mode);
2068
- err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true);
2069
- if (err < 0) {
2070
- WL_ERR(("SET Adhoc error %d\n", err));
2071
- return -EINVAL;
2072
- }
3850
+ err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(s32));
3851
+ if (err < 0) {
3852
+ WL_ERR(("SET INFRA/IBSS error %d\n", err));
3853
+ goto fail;
20733854 }
20743855
3856
+ wl_cfg80211_iface_state_ops(primary_ndev->ieee80211_ptr,
3857
+ WL_IF_CHANGE_DONE, wl_iftype, wl_mode);
3858
+
3859
+ /* Update new iftype in relevant structures */
20753860 ndev->ieee80211_ptr->iftype = type;
2076
- return 0;
3861
+ netinfo->iftype = wl_iftype;
3862
+ WL_INFORM_MEM(("[%s] cfg_iftype changed to %d\n", ndev->name, type));
3863
+
3864
+fail:
3865
+ if (err) {
3866
+ wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
3867
+ }
3868
+ mutex_unlock(&cfg->if_sync);
3869
+ return err;
20773870 }
20783871
20793872 s32
2080
-wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx)
3873
+wl_cfg80211_notify_ifadd(struct net_device *dev,
3874
+ int ifidx, char *name, uint8 *mac, uint8 bssidx, uint8 role)
20813875 {
20823876 bool ifadd_expected = FALSE;
2083
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
3877
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3878
+ bool bss_pending_op = TRUE;
20843879
20853880 /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
20863881 * redirect the IF_ADD event to ifchange as it is not a real "new" interface
20873882 */
20883883 if (wl_get_p2p_status(cfg, IF_CHANGING))
2089
- return wl_cfg80211_notify_ifchange(ifidx, name, mac, bssidx);
3884
+ return wl_cfg80211_notify_ifchange(dev, ifidx, name, mac, bssidx);
20903885
20913886 /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
20923887 if (wl_get_p2p_status(cfg, IF_ADDING)) {
....@@ -2094,7 +3889,7 @@
20943889 wl_clr_p2p_status(cfg, IF_ADDING);
20953890 } else if (cfg->bss_pending_op) {
20963891 ifadd_expected = TRUE;
2097
- cfg->bss_pending_op = FALSE;
3892
+ bss_pending_op = FALSE;
20983893 }
20993894
21003895 if (ifadd_expected) {
....@@ -2103,10 +3898,19 @@
21033898 if_event_info->valid = TRUE;
21043899 if_event_info->ifidx = ifidx;
21053900 if_event_info->bssidx = bssidx;
2106
- strncpy(if_event_info->name, name, IFNAMSIZ);
2107
- if_event_info->name[IFNAMSIZ] = '\0';
3901
+ if_event_info->role = role;
3902
+ strlcpy(if_event_info->name, name, sizeof(if_event_info->name));
3903
+ if_event_info->name[IFNAMSIZ - 1] = '\0';
21083904 if (mac)
21093905 memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
3906
+
3907
+ /* Update bss pendig operation status */
3908
+ if (!bss_pending_op) {
3909
+ cfg->bss_pending_op = FALSE;
3910
+ }
3911
+ WL_INFORM_MEM(("IF_ADD ifidx:%d bssidx:%d role:%d\n",
3912
+ ifidx, bssidx, role));
3913
+ OSL_SMP_WMB();
21103914 wake_up_interruptible(&cfg->netif_change_event);
21113915 return BCME_OK;
21123916 }
....@@ -2115,24 +3919,31 @@
21153919 }
21163920
21173921 s32
2118
-wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx)
3922
+wl_cfg80211_notify_ifdel(struct net_device *dev, int ifidx, char *name, uint8 *mac, uint8 bssidx)
21193923 {
21203924 bool ifdel_expected = FALSE;
2121
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
3925
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21223926 wl_if_event_info *if_event_info = &cfg->if_event_info;
3927
+ bool bss_pending_op = TRUE;
21233928
21243929 if (wl_get_p2p_status(cfg, IF_DELETING)) {
21253930 ifdel_expected = TRUE;
21263931 wl_clr_p2p_status(cfg, IF_DELETING);
21273932 } else if (cfg->bss_pending_op) {
21283933 ifdel_expected = TRUE;
2129
- cfg->bss_pending_op = FALSE;
3934
+ bss_pending_op = FALSE;
21303935 }
21313936
21323937 if (ifdel_expected) {
21333938 if_event_info->valid = TRUE;
21343939 if_event_info->ifidx = ifidx;
21353940 if_event_info->bssidx = bssidx;
3941
+ /* Update bss pendig operation status */
3942
+ if (!bss_pending_op) {
3943
+ cfg->bss_pending_op = FALSE;
3944
+ }
3945
+ WL_INFORM_MEM(("IF_DEL ifidx:%d bssidx:%d\n", ifidx, bssidx));
3946
+ OSL_SMP_WMB();
21363947 wake_up_interruptible(&cfg->netif_change_event);
21373948 return BCME_OK;
21383949 }
....@@ -2141,847 +3952,19 @@
21413952 }
21423953
21433954 s32
2144
-wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx)
3955
+wl_cfg80211_notify_ifchange(struct net_device * dev, int ifidx, char *name, uint8 *mac,
3956
+ uint8 bssidx)
21453957 {
2146
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
3958
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
21473959
21483960 if (wl_get_p2p_status(cfg, IF_CHANGING)) {
21493961 wl_set_p2p_status(cfg, IF_CHANGED);
3962
+ OSL_SMP_WMB();
21503963 wake_up_interruptible(&cfg->netif_change_event);
21513964 return BCME_OK;
21523965 }
21533966
21543967 return BCME_ERROR;
2155
-}
2156
-
2157
-static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info,
2158
- struct net_device* ndev)
2159
-{
2160
- s32 type = -1;
2161
- s32 bssidx = -1;
2162
-#ifdef PROP_TXSTATUS_VSDB
2163
-#if defined(BCMSDIO) || defined(BCMDBUS)
2164
- dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2165
- bool enabled;
2166
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
2167
-#endif /* PROP_TXSTATUS_VSDB */
2168
-
2169
- bssidx = if_event_info->bssidx;
2170
- if (bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION1) &&
2171
- bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION2)) {
2172
- WL_ERR(("got IF_DEL for if %d, not owned by cfg driver\n", bssidx));
2173
- return BCME_ERROR;
2174
- }
2175
-
2176
- if (p2p_is_on(cfg) && wl_cfgp2p_vif_created(cfg)) {
2177
- if (cfg->scan_request && (cfg->escan_info.ndev == ndev)) {
2178
- /* Abort any pending scan requests */
2179
- cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2180
- WL_DBG(("ESCAN COMPLETED\n"));
2181
- wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, false);
2182
- }
2183
-
2184
- memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
2185
- if (wl_cfgp2p_find_type(cfg, bssidx, &type) == BCME_OK) {
2186
- /* Update P2P data */
2187
- wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, type));
2188
- wl_to_p2p_bss_ndev(cfg, type) = NULL;
2189
- wl_to_p2p_bss_bssidx(cfg, type) = -1;
2190
- } else if (wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr) < 0) {
2191
- WL_ERR(("bssidx not known for the given ndev as per net_info data \n"));
2192
- return BCME_ERROR;
2193
- }
2194
-
2195
-#ifdef PROP_TXSTATUS_VSDB
2196
-#if defined(BCMSDIO) || defined(BCMDBUS)
2197
- dhd_wlfc_get_enable(dhd, &enabled);
2198
- if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
2199
- dhd->op_mode != DHD_FLAG_IBSS_MODE) {
2200
- dhd_wlfc_deinit(dhd);
2201
- cfg->wlfc_on = false;
2202
- }
2203
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
2204
-#endif /* PROP_TXSTATUS_VSDB */
2205
- }
2206
-
2207
- dhd_net_if_lock(ndev);
2208
- wl_cfg80211_remove_if(cfg, if_event_info->ifidx, ndev);
2209
- dhd_net_if_unlock(ndev);
2210
-
2211
- return BCME_OK;
2212
-}
2213
-
2214
-/* Find listen channel */
2215
-static s32 wl_find_listen_channel(struct bcm_cfg80211 *cfg,
2216
- const u8 *ie, u32 ie_len)
2217
-{
2218
- wifi_p2p_ie_t *p2p_ie;
2219
- u8 *end, *pos;
2220
- s32 listen_channel;
2221
-
2222
-/* unfortunately const cast required here - function is
2223
- * a callback so its signature must not be changed
2224
- * and cascade of changing wl_cfgp2p_find_p2pie
2225
- * causes need for const cast in other places
2226
- */
2227
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
2228
- 4 && __GNUC_MINOR__ >= 6))
2229
-_Pragma("GCC diagnostic push")
2230
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
2231
-#endif
2232
- pos = (u8 *)ie;
2233
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
2234
- 4 && __GNUC_MINOR__ >= 6))
2235
-_Pragma("GCC diagnostic pop")
2236
-#endif
2237
- p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len);
2238
-
2239
- if (p2p_ie == NULL)
2240
- return 0;
2241
-
2242
- pos = p2p_ie->subelts;
2243
- end = p2p_ie->subelts + (p2p_ie->len - 4);
2244
-
2245
- CFGP2P_DBG((" found p2p ie ! lenth %d \n",
2246
- p2p_ie->len));
2247
-
2248
- while (pos < end) {
2249
- uint16 attr_len;
2250
- if (pos + 2 >= end) {
2251
- CFGP2P_DBG((" -- Invalid P2P attribute"));
2252
- return 0;
2253
- }
2254
- attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0]));
2255
-
2256
- if (pos + 3 + attr_len > end) {
2257
- CFGP2P_DBG(("P2P: Attribute underflow "
2258
- "(len=%u left=%d)",
2259
- attr_len, (int) (end - pos - 3)));
2260
- return 0;
2261
- }
2262
-
2263
- /* if Listen Channel att id is 6 and the vailue is valid,
2264
- * return the listen channel
2265
- */
2266
- if (pos[0] == 6) {
2267
- /* listen channel subel length format
2268
- * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num)
2269
- */
2270
- listen_channel = pos[1 + 2 + 3 + 1];
2271
-
2272
- if (listen_channel == SOCIAL_CHAN_1 ||
2273
- listen_channel == SOCIAL_CHAN_2 ||
2274
- listen_channel == SOCIAL_CHAN_3) {
2275
- CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel));
2276
- return listen_channel;
2277
- }
2278
- }
2279
- pos += 3 + attr_len;
2280
- }
2281
- return 0;
2282
-}
2283
-
2284
-static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request)
2285
-{
2286
- u32 n_ssids;
2287
- u32 n_channels;
2288
- u16 channel;
2289
- chanspec_t chanspec;
2290
- s32 i = 0, j = 0, offset;
2291
- char *ptr;
2292
- wlc_ssid_t ssid;
2293
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
2294
- struct wireless_dev *wdev;
2295
-
2296
- memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
2297
- params->bss_type = DOT11_BSSTYPE_ANY;
2298
- params->scan_type = 0;
2299
- params->nprobes = -1;
2300
- params->active_time = -1;
2301
- params->passive_time = -1;
2302
- params->home_time = -1;
2303
- params->channel_num = 0;
2304
- memset(&params->ssid, 0, sizeof(wlc_ssid_t));
2305
-
2306
- WL_SCAN(("Preparing Scan request\n"));
2307
- WL_SCAN(("nprobes=%d\n", params->nprobes));
2308
- WL_SCAN(("active_time=%d\n", params->active_time));
2309
- WL_SCAN(("passive_time=%d\n", params->passive_time));
2310
- WL_SCAN(("home_time=%d\n", params->home_time));
2311
- WL_SCAN(("scan_type=%d\n", params->scan_type));
2312
-
2313
- params->nprobes = htod32(params->nprobes);
2314
- params->active_time = htod32(params->active_time);
2315
- params->passive_time = htod32(params->passive_time);
2316
- params->home_time = htod32(params->home_time);
2317
-
2318
- /* if request is null just exit so it will be all channel broadcast scan */
2319
- if (!request)
2320
- return;
2321
-
2322
- n_ssids = request->n_ssids;
2323
- n_channels = request->n_channels;
2324
-
2325
- /* Copy channel array if applicable */
2326
- WL_SCAN(("### List of channelspecs to scan ###\n"));
2327
- if (n_channels > 0) {
2328
- for (i = 0; i < n_channels; i++) {
2329
- chanspec = 0;
2330
- channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq);
2331
- /* SKIP DFS channels for Secondary interface */
2332
- if ((cfg->escan_info.ndev != bcmcfg_to_prmry_ndev(cfg)) &&
2333
- (request->channels[i]->flags &
2334
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
2335
- (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN)))
2336
-#else
2337
- (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)))
2338
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */
2339
- continue;
2340
-
2341
-#if defined(WL_CFG80211_P2P_DEV_IF)
2342
- wdev = request->wdev;
2343
-#else
2344
- wdev = request->dev->ieee80211_ptr;
2345
-#endif /* WL_CFG80211_P2P_DEV_IF */
2346
- chanspec = wl_cfg80211_ulb_get_min_bw_chspec(wdev, -1);
2347
- if (chanspec == INVCHANSPEC) {
2348
- WL_ERR(("Invalid chanspec! Skipping channel\n"));
2349
- continue;
2350
- }
2351
-
2352
- if (request->channels[i]->band == IEEE80211_BAND_2GHZ) {
2353
- chanspec |= WL_CHANSPEC_BAND_2G;
2354
- } else {
2355
- chanspec |= WL_CHANSPEC_BAND_5G;
2356
- }
2357
- params->channel_list[j] = channel;
2358
- params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK;
2359
- params->channel_list[j] |= chanspec;
2360
- WL_SCAN(("Chan : %d, Channel spec: %x \n",
2361
- channel, params->channel_list[j]));
2362
- params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]);
2363
- j++;
2364
- }
2365
- } else {
2366
- WL_SCAN(("Scanning all channels\n"));
2367
- }
2368
- n_channels = j;
2369
- /* Copy ssid array if applicable */
2370
- WL_SCAN(("### List of SSIDs to scan ###\n"));
2371
- if (n_ssids > 0) {
2372
- offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16);
2373
- offset = roundup(offset, sizeof(u32));
2374
- ptr = (char*)params + offset;
2375
- for (i = 0; i < n_ssids; i++) {
2376
- memset(&ssid, 0, sizeof(wlc_ssid_t));
2377
- ssid.SSID_len = request->ssids[i].ssid_len;
2378
- memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
2379
- if (!ssid.SSID_len)
2380
- WL_SCAN(("%d: Broadcast scan\n", i));
2381
- else
2382
- WL_SCAN(("%d: scan for %s size =%d\n", i,
2383
- ssid.SSID, ssid.SSID_len));
2384
- memcpy(ptr, &ssid, sizeof(wlc_ssid_t));
2385
- ptr += sizeof(wlc_ssid_t);
2386
- }
2387
- } else {
2388
- WL_SCAN(("Broadcast scan\n"));
2389
- }
2390
- /* Adding mask to channel numbers */
2391
- params->channel_num =
2392
- htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
2393
- (n_channels & WL_SCAN_PARAMS_COUNT_MASK));
2394
-
2395
- if (n_channels == 1) {
2396
- params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS);
2397
- params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS);
2398
- }
2399
-}
2400
-
2401
-static s32
2402
-wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size)
2403
-{
2404
- wl_uint32_list_t *list;
2405
- s32 err = BCME_OK;
2406
- if (valid_chan_list == NULL || size <= 0)
2407
- return -ENOMEM;
2408
-
2409
- memset(valid_chan_list, 0, size);
2410
- list = (wl_uint32_list_t *)(void *) valid_chan_list;
2411
- list->count = htod32(WL_NUMCHANNELS);
2412
- err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false);
2413
- if (err != 0) {
2414
- WL_ERR(("get channels failed with %d\n", err));
2415
- }
2416
-
2417
- return err;
2418
-}
2419
-
2420
-#if defined(USE_INITIAL_SHORT_DWELL_TIME)
2421
-#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40
2422
-bool g_first_broadcast_scan = TRUE;
2423
-#endif
2424
-
2425
-static s32
2426
-wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev,
2427
- struct cfg80211_scan_request *request, uint16 action)
2428
-{
2429
- s32 err = BCME_OK;
2430
- u32 n_channels;
2431
- u32 n_ssids;
2432
- s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
2433
- wl_escan_params_t *params = NULL;
2434
- u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
2435
- u32 num_chans = 0;
2436
- s32 channel;
2437
- u32 n_valid_chan;
2438
- s32 search_state = WL_P2P_DISC_ST_SCAN;
2439
- u32 i, j, n_nodfs = 0;
2440
- u16 *default_chan_list = NULL;
2441
- wl_uint32_list_t *list;
2442
- s32 bssidx = -1;
2443
- struct net_device *dev = NULL;
2444
-#if defined(USE_INITIAL_SHORT_DWELL_TIME)
2445
- bool is_first_init_2g_scan = false;
2446
-#endif
2447
- p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN;
2448
-
2449
- WL_DBG(("Enter \n"));
2450
-
2451
- /* scan request can come with empty request : perform all default scan */
2452
- if (!cfg) {
2453
- err = -EINVAL;
2454
- goto exit;
2455
- }
2456
- if (!cfg->p2p_supported || !p2p_scan(cfg)) {
2457
- /* LEGACY SCAN TRIGGER */
2458
- WL_SCAN((" LEGACY E-SCAN START\n"));
2459
-
2460
-#if defined(USE_INITIAL_SHORT_DWELL_TIME)
2461
- if (!request) {
2462
- err = -EINVAL;
2463
- goto exit;
2464
- }
2465
- if (ndev == bcmcfg_to_prmry_ndev(cfg) && g_first_broadcast_scan == true) {
2466
- is_first_init_2g_scan = true;
2467
- g_first_broadcast_scan = false;
2468
- }
2469
-#endif
2470
-
2471
- /* if scan request is not empty parse scan request paramters */
2472
- if (request != NULL) {
2473
- n_channels = request->n_channels;
2474
- n_ssids = request->n_ssids;
2475
- if (n_channels % 2)
2476
- /* If n_channels is odd, add a padd of u16 */
2477
- params_size += sizeof(u16) * (n_channels + 1);
2478
- else
2479
- params_size += sizeof(u16) * n_channels;
2480
-
2481
- /* Allocate space for populating ssids in wl_escan_params_t struct */
2482
- params_size += sizeof(struct wlc_ssid) * n_ssids;
2483
- }
2484
- params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
2485
- if (params == NULL) {
2486
- err = -ENOMEM;
2487
- goto exit;
2488
- }
2489
- wl_scan_prep(&params->params, request);
2490
-
2491
-#if defined(USE_INITIAL_SHORT_DWELL_TIME)
2492
- /* Override active_time to reduce scan time if it's first bradcast scan. */
2493
- if (is_first_init_2g_scan)
2494
- params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS;
2495
-#endif
2496
-
2497
- params->version = htod32(ESCAN_REQ_VERSION);
2498
- params->action = htod16(action);
2499
- wl_escan_set_sync_id(params->sync_id, cfg);
2500
- wl_escan_set_type(cfg, WL_SCANTYPE_LEGACY);
2501
- if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
2502
- WL_ERR(("ioctl buffer length not sufficient\n"));
2503
- kfree(params);
2504
- err = -ENOMEM;
2505
- goto exit;
2506
- }
2507
- if (cfg->active_scan == PASSIVE_SCAN) {
2508
- params->params.scan_type = DOT11_SCANTYPE_PASSIVE;
2509
- WL_DBG(("Passive scan_type %d \n", params->params.scan_type));
2510
- }
2511
-
2512
- bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
2513
-
2514
- err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
2515
- cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
2516
- WL_ERR(("LEGACY_SCAN sync ID: %d, bssidx: %d\n", params->sync_id, bssidx));
2517
- if (unlikely(err)) {
2518
- if (err == BCME_EPERM)
2519
- /* Scan Not permitted at this point of time */
2520
- WL_DBG((" Escan not permitted at this time (%d)\n", err));
2521
- else
2522
- WL_ERR((" Escan set error (%d)\n", err));
2523
- } else {
2524
- DBG_EVENT_LOG(cfg->pub, WIFI_EVENT_DRIVER_SCAN_REQUESTED);
2525
- }
2526
- kfree(params);
2527
- }
2528
- else if (p2p_is_on(cfg) && p2p_scan(cfg)) {
2529
- /* P2P SCAN TRIGGER */
2530
- s32 _freq = 0;
2531
- n_nodfs = 0;
2532
- if (request && request->n_channels) {
2533
- num_chans = request->n_channels;
2534
- WL_SCAN((" chann number : %d\n", num_chans));
2535
- default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list),
2536
- GFP_KERNEL);
2537
- if (default_chan_list == NULL) {
2538
- WL_ERR(("channel list allocation failed \n"));
2539
- err = -ENOMEM;
2540
- goto exit;
2541
- }
2542
- if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) {
2543
- list = (wl_uint32_list_t *) chan_buf;
2544
- n_valid_chan = dtoh32(list->count);
2545
- for (i = 0; i < num_chans; i++)
2546
- {
2547
- _freq = request->channels[i]->center_freq;
2548
- channel = ieee80211_frequency_to_channel(_freq);
2549
-
2550
- /* ignore DFS channels */
2551
- if (request->channels[i]->flags &
2552
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
2553
- (IEEE80211_CHAN_NO_IR
2554
- | IEEE80211_CHAN_RADAR))
2555
-#else
2556
- (IEEE80211_CHAN_RADAR
2557
- | IEEE80211_CHAN_PASSIVE_SCAN))
2558
-#endif
2559
- continue;
2560
-
2561
- for (j = 0; j < n_valid_chan; j++) {
2562
- /* allows only supported channel on
2563
- * current reguatory
2564
- */
2565
- if (channel == (dtoh32(list->element[j])))
2566
- default_chan_list[n_nodfs++] =
2567
- channel;
2568
- }
2569
-
2570
- }
2571
- }
2572
- if (num_chans == SOCIAL_CHAN_CNT && (
2573
- (default_chan_list[0] == SOCIAL_CHAN_1) &&
2574
- (default_chan_list[1] == SOCIAL_CHAN_2) &&
2575
- (default_chan_list[2] == SOCIAL_CHAN_3))) {
2576
- /* SOCIAL CHANNELS 1, 6, 11 */
2577
- search_state = WL_P2P_DISC_ST_SEARCH;
2578
- p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
2579
- WL_INFORM(("P2P SEARCH PHASE START \n"));
2580
- } else if (((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1)) &&
2581
- (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) ||
2582
- ((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION2)) &&
2583
- (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP))) {
2584
- /* If you are already a GO, then do SEARCH only */
2585
- WL_INFORM(("Already a GO. Do SEARCH Only"));
2586
- search_state = WL_P2P_DISC_ST_SEARCH;
2587
- num_chans = n_nodfs;
2588
- p2p_scan_purpose = P2P_SCAN_NORMAL;
2589
-
2590
- } else if (num_chans == 1) {
2591
- p2p_scan_purpose = P2P_SCAN_CONNECT_TRY;
2592
- } else if (num_chans == SOCIAL_CHAN_CNT + 1) {
2593
- /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by
2594
- * the supplicant
2595
- */
2596
- p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
2597
- } else {
2598
- WL_INFORM(("P2P SCAN STATE START \n"));
2599
- num_chans = n_nodfs;
2600
- p2p_scan_purpose = P2P_SCAN_NORMAL;
2601
- }
2602
- } else {
2603
- err = -EINVAL;
2604
- goto exit;
2605
- }
2606
- err = wl_cfgp2p_escan(cfg, ndev, ACTIVE_SCAN, num_chans, default_chan_list,
2607
- search_state, action,
2608
- wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE), NULL,
2609
- p2p_scan_purpose);
2610
-
2611
- if (!err)
2612
- cfg->p2p->search_state = search_state;
2613
-
2614
- kfree(default_chan_list);
2615
- }
2616
-exit:
2617
- if (unlikely(err)) {
2618
- /* Don't print Error incase of Scan suppress */
2619
- if ((err == BCME_EPERM) && cfg->scan_suppressed)
2620
- WL_DBG(("Escan failed: Scan Suppressed \n"));
2621
- else
2622
- WL_ERR(("error (%d)\n", err));
2623
- }
2624
- return err;
2625
-}
2626
-
2627
-
2628
-static s32
2629
-wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *ndev,
2630
- struct cfg80211_scan_request *request)
2631
-{
2632
- s32 err = BCME_OK;
2633
- s32 passive_scan;
2634
- s32 passive_scan_time;
2635
- s32 passive_scan_time_org;
2636
- wl_scan_results_t *results;
2637
- WL_SCAN(("Enter \n"));
2638
- mutex_lock(&cfg->usr_sync);
2639
-
2640
- results = wl_escan_get_buf(cfg, FALSE);
2641
- results->version = 0;
2642
- results->count = 0;
2643
- results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
2644
-
2645
- cfg->escan_info.ndev = ndev;
2646
- cfg->escan_info.wiphy = wiphy;
2647
- cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
2648
- passive_scan = cfg->active_scan ? 0 : 1;
2649
- err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
2650
- &passive_scan, sizeof(passive_scan), true);
2651
- if (unlikely(err)) {
2652
- WL_ERR(("error (%d)\n", err));
2653
- goto exit;
2654
- }
2655
-
2656
- if (passive_channel_skip) {
2657
-
2658
- err = wldev_ioctl(ndev, WLC_GET_SCAN_PASSIVE_TIME,
2659
- &passive_scan_time_org, sizeof(passive_scan_time_org), false);
2660
- if (unlikely(err)) {
2661
- WL_ERR(("== error (%d)\n", err));
2662
- goto exit;
2663
- }
2664
-
2665
- WL_SCAN(("PASSIVE SCAN time : %d \n", passive_scan_time_org));
2666
-
2667
- passive_scan_time = 0;
2668
- err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME,
2669
- &passive_scan_time, sizeof(passive_scan_time), true);
2670
- if (unlikely(err)) {
2671
- WL_ERR(("== error (%d)\n", err));
2672
- goto exit;
2673
- }
2674
-
2675
- WL_SCAN(("PASSIVE SCAN SKIPED!! (passive_channel_skip:%d) \n",
2676
- passive_channel_skip));
2677
- }
2678
-
2679
- err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START);
2680
-
2681
- if (passive_channel_skip) {
2682
- err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME,
2683
- &passive_scan_time_org, sizeof(passive_scan_time_org), true);
2684
- if (unlikely(err)) {
2685
- WL_ERR(("== error (%d)\n", err));
2686
- goto exit;
2687
- }
2688
-
2689
- WL_SCAN(("PASSIVE SCAN RECOVERED!! (passive_scan_time_org:%d) \n",
2690
- passive_scan_time_org));
2691
- }
2692
-
2693
-exit:
2694
- mutex_unlock(&cfg->usr_sync);
2695
- return err;
2696
-}
2697
-
2698
-static s32
2699
-__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
2700
- struct cfg80211_scan_request *request,
2701
- struct cfg80211_ssid *this_ssid)
2702
-{
2703
- struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2704
- struct cfg80211_ssid *ssids;
2705
- struct ether_addr primary_mac;
2706
- bool p2p_ssid;
2707
-#ifdef WL11U
2708
- bcm_tlv_t *interworking_ie;
2709
-#endif
2710
- s32 err = 0;
2711
- s32 bssidx = -1;
2712
- s32 i;
2713
-
2714
- unsigned long flags;
2715
- static s32 busy_count = 0;
2716
-#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
2717
- struct net_device *remain_on_channel_ndev = NULL;
2718
-#endif
2719
-
2720
- /*
2721
- * Hostapd triggers scan before starting automatic channel selection
2722
- * to collect channel characteristics. However firmware scan engine
2723
- * doesn't support any channel characteristics collection along with
2724
- * scan. Hence return scan success.
2725
- */
2726
- if (request && (scan_req_iftype(request) == NL80211_IFTYPE_AP)) {
2727
- WL_INFORM(("Scan Command on SoftAP Interface. Ignoring...\n"));
2728
- return 0;
2729
- }
2730
-
2731
- ndev = ndev_to_wlc_ndev(ndev, cfg);
2732
-
2733
- if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
2734
- WL_ERR(("Sending Action Frames. Try it again.\n"));
2735
- return -EAGAIN;
2736
- }
2737
-
2738
- WL_DBG(("Enter wiphy (%p)\n", wiphy));
2739
- if (wl_get_drv_status_all(cfg, SCANNING)) {
2740
- if (cfg->scan_request == NULL) {
2741
- wl_clr_drv_status_all(cfg, SCANNING);
2742
- WL_DBG(("<<<<<<<<<<<Force Clear Scanning Status>>>>>>>>>>>\n"));
2743
- } else {
2744
- WL_ERR(("Scanning already\n"));
2745
- return -EAGAIN;
2746
- }
2747
- }
2748
- if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) {
2749
- WL_ERR(("Scanning being aborted\n"));
2750
- return -EAGAIN;
2751
- }
2752
- if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
2753
- WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
2754
- return -EOPNOTSUPP;
2755
- }
2756
-#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
2757
- remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg);
2758
- if (remain_on_channel_ndev) {
2759
- WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n"));
2760
- wl_notify_escan_complete(cfg, remain_on_channel_ndev, true, true);
2761
- }
2762
-#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
2763
-
2764
-
2765
- /* Arm scan timeout timer */
2766
- mod_timer(&cfg->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS));
2767
- if (request) { /* scan bss */
2768
- ssids = request->ssids;
2769
- p2p_ssid = false;
2770
- for (i = 0; i < request->n_ssids; i++) {
2771
- if (ssids[i].ssid_len &&
2772
- IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) {
2773
- p2p_ssid = true;
2774
- break;
2775
- }
2776
- }
2777
- if (p2p_ssid) {
2778
- if (cfg->p2p_supported) {
2779
- /* p2p scan trigger */
2780
- if (p2p_on(cfg) == false) {
2781
- /* p2p on at the first time */
2782
- p2p_on(cfg) = true;
2783
- wl_cfgp2p_set_firm_p2p(cfg);
2784
- get_primary_mac(cfg, &primary_mac);
2785
- wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
2786
-#if defined(P2P_IE_MISSING_FIX)
2787
- cfg->p2p_prb_noti = false;
2788
-#endif
2789
- }
2790
- wl_clr_p2p_status(cfg, GO_NEG_PHASE);
2791
- WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
2792
- p2p_scan(cfg) = true;
2793
- }
2794
- } else {
2795
- /* legacy scan trigger
2796
- * So, we have to disable p2p discovery if p2p discovery is on
2797
- */
2798
- if (cfg->p2p_supported) {
2799
- p2p_scan(cfg) = false;
2800
- /* If Netdevice is not equals to primary and p2p is on
2801
- * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
2802
- */
2803
-
2804
- if (p2p_scan(cfg) == false) {
2805
- if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
2806
- err = wl_cfgp2p_discover_enable_search(cfg,
2807
- false);
2808
- if (unlikely(err)) {
2809
- goto scan_out;
2810
- }
2811
-
2812
- }
2813
- }
2814
- }
2815
- if (!cfg->p2p_supported || !p2p_scan(cfg)) {
2816
- if ((bssidx = wl_get_bssidx_by_wdev(cfg,
2817
- ndev->ieee80211_ptr)) < 0) {
2818
- WL_ERR(("Find p2p index from ndev(%p) failed\n",
2819
- ndev));
2820
- err = BCME_ERROR;
2821
- goto scan_out;
2822
- }
2823
-#ifdef WL11U
2824
- if ((interworking_ie = wl_cfg80211_find_interworking_ie(
2825
- (u8 *)request->ie, request->ie_len)) != NULL) {
2826
- err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx,
2827
- VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
2828
- interworking_ie->data, interworking_ie->len);
2829
-
2830
- if (unlikely(err)) {
2831
- goto scan_out;
2832
- }
2833
- } else if (cfg->iw_ie_len != 0) {
2834
- /* we have to clear IW IE and disable gratuitous APR */
2835
- wl_cfg80211_add_iw_ie(cfg, ndev, bssidx,
2836
- VNDR_IE_CUSTOM_FLAG,
2837
- DOT11_MNG_INTERWORKING_ID,
2838
- 0, 0);
2839
-
2840
- (void)wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0,
2841
- bssidx);
2842
- cfg->wl11u = FALSE;
2843
- cfg->iw_ie_len = 0;
2844
- memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN);
2845
- /* we don't care about error */
2846
- }
2847
-#endif /* WL11U */
2848
- err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
2849
- bssidx, VNDR_IE_PRBREQ_FLAG, request->ie,
2850
- request->ie_len);
2851
-
2852
- if (unlikely(err)) {
2853
- goto scan_out;
2854
- }
2855
-
2856
- }
2857
- }
2858
- } else { /* scan in ibss */
2859
- ssids = this_ssid;
2860
- }
2861
-
2862
- if (request && cfg->p2p_supported && !p2p_scan(cfg)) {
2863
- WL_TRACE_HW4(("START SCAN\n"));
2864
- DHD_OS_SCAN_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub),
2865
- SCAN_WAKE_LOCK_TIMEOUT);
2866
- }
2867
-
2868
- if (cfg->p2p_supported) {
2869
- if (p2p_on(cfg) && p2p_scan(cfg)) {
2870
-
2871
- /* find my listen channel */
2872
- cfg->afx_hdl->my_listen_chan =
2873
- wl_find_listen_channel(cfg, request->ie,
2874
- request->ie_len);
2875
- err = wl_cfgp2p_enable_discovery(cfg, ndev,
2876
- request->ie, request->ie_len);
2877
-
2878
- if (unlikely(err)) {
2879
- goto scan_out;
2880
- }
2881
- }
2882
- }
2883
- err = wl_do_escan(cfg, wiphy, ndev, request);
2884
- if (likely(!err))
2885
- goto scan_success;
2886
- else
2887
- goto scan_out;
2888
-
2889
-scan_success:
2890
- busy_count = 0;
2891
- cfg->scan_request = request;
2892
- wl_set_drv_status(cfg, SCANNING, ndev);
2893
-
2894
- return 0;
2895
-
2896
-scan_out:
2897
- if (err == BCME_BUSY || err == BCME_NOTREADY) {
2898
- WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY));
2899
- err = -EBUSY;
2900
- } else if ((err == BCME_EPERM) && cfg->scan_suppressed) {
2901
- WL_ERR(("Scan not permitted due to scan suppress\n"));
2902
- err = -EPERM;
2903
- } else {
2904
- /* For all other fw errors, use a generic error code as return
2905
- * value to cfg80211 stack
2906
- */
2907
- err = -EAGAIN;
2908
- }
2909
-
2910
-#define SCAN_EBUSY_RETRY_LIMIT 10
2911
- if (err == -EBUSY) {
2912
- if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) {
2913
- struct ether_addr bssid;
2914
- s32 ret = 0;
2915
- busy_count = 0;
2916
- WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n",
2917
- wl_get_drv_status(cfg, SCANNING, ndev),
2918
- wl_get_drv_status(cfg, SCAN_ABORTING, ndev),
2919
- wl_get_drv_status(cfg, CONNECTING, ndev),
2920
- wl_get_drv_status(cfg, CONNECTED, ndev),
2921
- wl_get_drv_status(cfg, DISCONNECTING, ndev),
2922
- wl_get_drv_status(cfg, AP_CREATING, ndev),
2923
- wl_get_drv_status(cfg, AP_CREATED, ndev),
2924
- wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev),
2925
- wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev)));
2926
-
2927
- bzero(&bssid, sizeof(bssid));
2928
- if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID,
2929
- &bssid, ETHER_ADDR_LEN, false)) == 0)
2930
- WL_ERR(("FW is connected with " MACDBG "/n",
2931
- MAC2STRDBG(bssid.octet)));
2932
- else
2933
- WL_ERR(("GET BSSID failed with %d\n", ret));
2934
-
2935
- wl_cfg80211_scan_abort(cfg);
2936
-
2937
- }
2938
- } else {
2939
- busy_count = 0;
2940
- }
2941
-
2942
- wl_clr_drv_status(cfg, SCANNING, ndev);
2943
- if (timer_pending(&cfg->scan_timeout))
2944
- del_timer_sync(&cfg->scan_timeout);
2945
- DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
2946
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
2947
- cfg->scan_request = NULL;
2948
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
2949
-
2950
- return err;
2951
-}
2952
-
2953
-#if defined(WL_CFG80211_P2P_DEV_IF)
2954
-static s32
2955
-wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
2956
-#else
2957
-static s32
2958
-wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
2959
- struct cfg80211_scan_request *request)
2960
-#endif /* WL_CFG80211_P2P_DEV_IF */
2961
-{
2962
- s32 err = 0;
2963
- struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2964
-#if defined(WL_CFG80211_P2P_DEV_IF)
2965
- struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg);
2966
-#endif /* WL_CFG80211_P2P_DEV_IF */
2967
-
2968
- WL_DBG(("Enter\n"));
2969
- RETURN_EIO_IF_NOT_UP(cfg);
2970
-
2971
- if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
2972
- if (wl_cfg_multip2p_operational(cfg)) {
2973
- WL_ERR(("wlan0 scan failed, p2p devices are operational"));
2974
- return -ENODEV;
2975
- }
2976
- }
2977
-
2978
- err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
2979
- if (unlikely(err)) {
2980
- WL_ERR(("scan error (%d)\n", err));
2981
- return err;
2982
- }
2983
-
2984
- return err;
29853968 }
29863969
29873970 static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
....@@ -3013,8 +3996,16 @@
30133996 s32 err = 0;
30143997 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
30153998
3999
+#ifdef CUSTOM_LONG_RETRY_LIMIT
4000
+ if ((cmd == WLC_SET_LRL) &&
4001
+ (retry != CUSTOM_LONG_RETRY_LIMIT)) {
4002
+ WL_DBG(("CUSTOM_LONG_RETRY_LIMIT is used.Ignore configuration"));
4003
+ return err;
4004
+ }
4005
+#endif /* CUSTOM_LONG_RETRY_LIMIT */
4006
+
30164007 retry = htod32(retry);
3017
- err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true);
4008
+ err = wldev_ioctl_set(dev, cmd, &retry, sizeof(retry));
30184009 if (unlikely(err)) {
30194010 WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
30204011 return err;
....@@ -3073,9 +4064,9 @@
30734064 int bw = 0, tmp_bw = 0;
30744065 int i;
30754066 u32 tmp_c;
3076
- u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
4067
+
30774068 #define LOCAL_BUF_SIZE 1024
3078
- buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags);
4069
+ buf = (u8 *)MALLOC(cfg->osh, LOCAL_BUF_SIZE);
30794070 if (!buf) {
30804071 WL_ERR(("buf memory alloc failed\n"));
30814072 goto exit;
....@@ -3113,21 +4104,23 @@
31134104 }
31144105 }
31154106 exit:
3116
- if (buf)
3117
- kfree(buf);
4107
+ if (buf) {
4108
+ MFREE(cfg->osh, buf, LOCAL_BUF_SIZE);
4109
+ }
31184110 #undef LOCAL_BUF_SIZE
3119
- WL_INFORM(("return chanspec %x %d\n", ret_c, bw));
4111
+ WL_DBG(("return chanspec %x %d\n", ret_c, bw));
31204112 return ret_c;
31214113 }
31224114
31234115 void
3124
-wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len)
4116
+wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev, vndr_ie_setbuf_t *ibss_vsie,
4117
+ int ibss_vsie_len)
31254118 {
3126
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
4119
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
31274120
31284121 if (cfg != NULL && ibss_vsie != NULL) {
31294122 if (cfg->ibss_vsie != NULL) {
3130
- kfree(cfg->ibss_vsie);
4123
+ MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
31314124 }
31324125 cfg->ibss_vsie = ibss_vsie;
31334126 cfg->ibss_vsie_len = ibss_vsie_len;
....@@ -3139,8 +4132,7 @@
31394132 {
31404133 /* free & initiralize VSIE (Vendor Specific IE) */
31414134 if (cfg->ibss_vsie != NULL) {
3142
- kfree(cfg->ibss_vsie);
3143
- cfg->ibss_vsie = NULL;
4135
+ MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
31444136 cfg->ibss_vsie_len = 0;
31454137 }
31464138 }
....@@ -3148,35 +4140,37 @@
31484140 s32
31494141 wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
31504142 {
3151
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
4143
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
31524144 char *ioctl_buf = NULL;
3153
- s32 ret = BCME_OK;
4145
+ s32 ret = BCME_OK, bssidx;
31544146
31554147 if (cfg != NULL && cfg->ibss_vsie != NULL) {
3156
- ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
4148
+ ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
31574149 if (!ioctl_buf) {
31584150 WL_ERR(("ioctl memory alloc failed\n"));
31594151 return -ENOMEM;
31604152 }
3161
-
4153
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4154
+ WL_ERR(("Find index failed\n"));
4155
+ ret = BCME_ERROR;
4156
+ goto end;
4157
+ }
31624158 /* change the command from "add" to "del" */
3163
- strncpy(cfg->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1);
3164
- cfg->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
4159
+ strlcpy(cfg->ibss_vsie->cmd, "del", sizeof(cfg->ibss_vsie->cmd));
31654160
3166
- ret = wldev_iovar_setbuf(dev, "ie",
3167
- cfg->ibss_vsie, cfg->ibss_vsie_len,
3168
- ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
4161
+ ret = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie",
4162
+ cfg->ibss_vsie, cfg->ibss_vsie_len,
4163
+ ioctl_buf, WLC_IOCTL_MEDLEN, bssidx, NULL);
31694164 WL_ERR(("ret=%d\n", ret));
31704165
31714166 if (ret == BCME_OK) {
3172
- /* free & initiralize VSIE */
3173
- kfree(cfg->ibss_vsie);
3174
- cfg->ibss_vsie = NULL;
4167
+ /* Free & initialize VSIE */
4168
+ MFREE(cfg->osh, cfg->ibss_vsie, cfg->ibss_vsie_len);
31754169 cfg->ibss_vsie_len = 0;
31764170 }
3177
-
4171
+end:
31784172 if (ioctl_buf) {
3179
- kfree(ioctl_buf);
4173
+ MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
31804174 }
31814175 }
31824176
....@@ -3192,7 +4186,7 @@
31924186 struct wireless_dev* wdev = NULL;
31934187 struct net_device *new_ndev = NULL;
31944188 struct net_device *primary_ndev = NULL;
3195
- s32 timeout;
4189
+ long timeout;
31964190 wl_aibss_if_t aibss_if;
31974191 wl_if_event_info *event = NULL;
31984192
....@@ -3206,15 +4200,15 @@
32064200 /* generate a new MAC address for the IBSS interface */
32074201 get_primary_mac(cfg, &cfg->ibss_if_addr);
32084202 cfg->ibss_if_addr.octet[4] ^= 0x40;
3209
- memset(&aibss_if, sizeof(aibss_if), 0);
4203
+ bzero(&aibss_if, sizeof(aibss_if));
32104204 memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
32114205 aibss_if.chspec = 0;
32124206 aibss_if.len = sizeof(aibss_if);
32134207
32144208 cfg->bss_pending_op = TRUE;
3215
- memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4209
+ bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
32164210 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
3217
- sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
4211
+ sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
32184212 if (err) {
32194213 WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
32204214 goto fail;
....@@ -3235,7 +4229,7 @@
32354229 event->mac, event->bssidx, event->name);
32364230 if (new_ndev == NULL)
32374231 goto fail;
3238
- wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
4232
+ wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
32394233 if (wdev == NULL)
32404234 goto fail;
32414235 wdev->wiphy = wiphy;
....@@ -3248,10 +4242,11 @@
32484242 * needs to be modified to take one parameter (bool need_rtnl_lock)
32494243 */
32504244 ASSERT_RTNL();
3251
- if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK)
4245
+ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, FALSE) != BCME_OK)
32524246 goto fail;
32534247
3254
- wl_alloc_netinfo(cfg, new_ndev, wdev, WL_MODE_IBSS, PM_ENABLE, event->bssidx);
4248
+ wl_alloc_netinfo(cfg, new_ndev, wdev, WL_IF_TYPE_IBSS,
4249
+ PM_ENABLE, event->bssidx, event->ifidx);
32554250 cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
32564251 WL_ERR(("IBSS interface %s created\n", new_ndev->name));
32574252 return cfg->ibss_cfgdev;
....@@ -3260,9 +4255,10 @@
32604255 WL_ERR(("failed to create IBSS interface %s \n", name));
32614256 cfg->bss_pending_op = FALSE;
32624257 if (new_ndev)
3263
- wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
3264
- if (wdev)
3265
- kfree(wdev);
4258
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, FALSE);
4259
+ if (wdev) {
4260
+ MFREE(cfg->osh, wdev, sizeof(*wdev));
4261
+ }
32664262 return NULL;
32674263 }
32684264
....@@ -3273,7 +4269,7 @@
32734269 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
32744270 struct net_device *ndev = NULL;
32754271 struct net_device *primary_ndev = NULL;
3276
- s32 timeout;
4272
+ long timeout;
32774273
32784274 if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet))
32794275 return -EINVAL;
....@@ -3281,9 +4277,9 @@
32814277 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
32824278
32834279 cfg->bss_pending_op = TRUE;
3284
- memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
4280
+ bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
32854281 err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
3286
- sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
4282
+ sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
32874283 if (err) {
32884284 WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
32894285 goto fail;
....@@ -3295,7 +4291,7 @@
32954291 goto fail;
32964292 }
32974293
3298
- wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev);
4294
+ wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev, FALSE);
32994295 cfg->ibss_cfgdev = NULL;
33004296 return 0;
33014297
....@@ -3306,55 +4302,206 @@
33064302 #endif /* WLAIBSS_MCHAN */
33074303
33084304 s32
3309
-wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
3310
- struct net_device *ndev, s32 bsscfg_idx,
3311
- enum nl80211_iftype iface_type, s32 del, u8 *addr)
4305
+wl_cfg80211_to_fw_iftype(wl_iftype_t iftype)
33124306 {
3313
- wl_interface_create_t iface;
3314
- s32 ret;
3315
- wl_interface_info_t *info;
4307
+ s32 ret = BCME_ERROR;
33164308
3317
- bzero(&iface, sizeof(wl_interface_create_t));
4309
+ switch (iftype) {
4310
+ case WL_IF_TYPE_AP:
4311
+ ret = WL_INTERFACE_TYPE_AP;
4312
+ break;
4313
+ case WL_IF_TYPE_STA:
4314
+ ret = WL_INTERFACE_TYPE_STA;
4315
+ break;
4316
+ case WL_IF_TYPE_NAN_NMI:
4317
+ case WL_IF_TYPE_NAN:
4318
+ ret = WL_INTERFACE_TYPE_NAN;
4319
+ break;
4320
+ case WL_IF_TYPE_P2P_DISC:
4321
+ ret = WL_INTERFACE_TYPE_P2P_DISC;
4322
+ break;
4323
+ case WL_IF_TYPE_P2P_GO:
4324
+ ret = WL_INTERFACE_TYPE_P2P_GO;
4325
+ break;
4326
+ case WL_IF_TYPE_P2P_GC:
4327
+ ret = WL_INTERFACE_TYPE_P2P_GC;
4328
+ break;
4329
+ case WL_IF_TYPE_AWDL:
4330
+ ret = WL_INTERFACE_TYPE_AWDL;
4331
+ break;
33184332
3319
- iface.ver = WL_INTERFACE_CREATE_VER;
3320
-
3321
- if (iface_type == NL80211_IFTYPE_AP)
3322
- iface.flags = WL_INTERFACE_CREATE_AP;
3323
- else
3324
- iface.flags = WL_INTERFACE_CREATE_STA;
3325
-
3326
- if (del) {
3327
- ret = wldev_iovar_setbuf(ndev, "interface_remove",
3328
- NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
3329
- } else {
3330
- if (addr) {
3331
- memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
3332
- iface.flags |= WL_INTERFACE_MAC_USE;
3333
- }
3334
- ret = wldev_iovar_getbuf(ndev, "interface_create",
3335
- &iface, sizeof(wl_interface_create_t),
3336
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
3337
- if (ret == 0) {
3338
- /* success */
3339
- info = (wl_interface_info_t *)cfg->ioctl_buf;
3340
- WL_DBG(("wl interface create success!! bssidx:%d \n",
3341
- info->bsscfgidx));
3342
- ret = info->bsscfgidx;
3343
- }
4333
+ default:
4334
+ WL_ERR(("Unsupported type:%d \n", iftype));
4335
+ ret = -EINVAL;
4336
+ break;
33444337 }
3345
-
3346
- if (ret < 0)
3347
- WL_ERR(("Interface %s failed!! ret %d\n",
3348
- del ? "remove" : "create", ret));
3349
-
33504338 return ret;
33514339 }
33524340
4341
+s32
4342
+wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
4343
+ struct net_device *ndev, s32 bsscfg_idx,
4344
+ wl_iftype_t cfg_iftype, s32 del, u8 *addr)
4345
+{
4346
+ s32 ret;
4347
+ struct wl_interface_create_v2 iface;
4348
+ wl_interface_create_v3_t iface_v3;
4349
+ struct wl_interface_info_v1 *info;
4350
+ wl_interface_info_v2_t *info_v2;
4351
+ uint32 ifflags = 0;
4352
+ bool use_iface_info_v2 = false;
4353
+ u8 ioctl_buf[WLC_IOCTL_SMLEN];
4354
+ s32 iftype;
4355
+
4356
+ if (del) {
4357
+ ret = wldev_iovar_setbuf(ndev, "interface_remove",
4358
+ NULL, 0, ioctl_buf, sizeof(ioctl_buf), NULL);
4359
+ if (unlikely(ret))
4360
+ WL_ERR(("Interface remove failed!! ret %d\n", ret));
4361
+ return ret;
4362
+ }
4363
+
4364
+ /* Interface create */
4365
+ bzero(&iface, sizeof(iface));
4366
+ /*
4367
+ * flags field is still used along with iftype inorder to support the old version of the
4368
+ * FW work with the latest app changes.
4369
+ */
4370
+
4371
+ iftype = wl_cfg80211_to_fw_iftype(cfg_iftype);
4372
+ if (iftype < 0) {
4373
+ return -ENOTSUPP;
4374
+ }
4375
+
4376
+ if (addr) {
4377
+ ifflags |= WL_INTERFACE_MAC_USE;
4378
+ }
4379
+
4380
+ /* Pass ver = 0 for fetching the interface_create iovar version */
4381
+ ret = wldev_iovar_getbuf(ndev, "interface_create",
4382
+ &iface, sizeof(struct wl_interface_create_v2),
4383
+ ioctl_buf, sizeof(ioctl_buf), NULL);
4384
+ if (ret == BCME_UNSUPPORTED) {
4385
+ WL_ERR(("interface_create iovar not supported\n"));
4386
+ return ret;
4387
+ } else if ((ret == 0) && *((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3) {
4388
+ WL_DBG(("interface_create version 3. flags:0x%x \n", ifflags));
4389
+ use_iface_info_v2 = true;
4390
+ bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
4391
+ iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
4392
+ iface_v3.iftype = iftype;
4393
+ iface_v3.flags = ifflags;
4394
+ if (addr) {
4395
+ memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
4396
+ }
4397
+ ret = wldev_iovar_getbuf(ndev, "interface_create",
4398
+ &iface_v3, sizeof(wl_interface_create_v3_t),
4399
+ ioctl_buf, sizeof(ioctl_buf), NULL);
4400
+ } else {
4401
+ /* On any other error, attempt with iovar version 2 */
4402
+ WL_DBG(("interface_create version 2. get_ver:%d ifflags:0x%x\n", ret, ifflags));
4403
+ iface.ver = WL_INTERFACE_CREATE_VER_2;
4404
+ iface.iftype = iftype;
4405
+ iface.flags = ifflags;
4406
+ if (addr) {
4407
+ memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
4408
+ }
4409
+ ret = wldev_iovar_getbuf(ndev, "interface_create",
4410
+ &iface, sizeof(struct wl_interface_create_v2),
4411
+ ioctl_buf, sizeof(ioctl_buf), NULL);
4412
+ }
4413
+
4414
+ if (unlikely(ret)) {
4415
+ WL_ERR(("Interface create failed!! ret %d\n", ret));
4416
+ return ret;
4417
+ }
4418
+
4419
+ /* success case */
4420
+ if (use_iface_info_v2 == true) {
4421
+ info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
4422
+ ret = info_v2->bsscfgidx;
4423
+ } else {
4424
+ /* Use v1 struct */
4425
+ info = (struct wl_interface_info_v1 *)ioctl_buf;
4426
+ ret = info->bsscfgidx;
4427
+ }
4428
+
4429
+ WL_DBG(("wl interface create success!! bssidx:%d \n", ret));
4430
+ return ret;
4431
+}
4432
+
4433
+#if defined(IGUANA_LEGACY_CHIPS)
4434
+#define BCM4355_REV_C1 0x0c
4435
+#define BCM4355_REV_D0 0x0d
4436
+bool
4437
+wl_customer6_legacy_chip_check(struct bcm_cfg80211 *cfg,
4438
+ struct net_device *ndev)
4439
+{
4440
+ u32 chipnum;
4441
+ wlc_rev_info_t revinfo;
4442
+ int ret;
4443
+
4444
+ /* Get the device rev info */
4445
+ bzero(&revinfo, sizeof(revinfo));
4446
+ ret = wldev_ioctl_get(ndev, WLC_GET_REVINFO, &revinfo, sizeof(revinfo));
4447
+ if (ret < 0) {
4448
+ WL_ERR(("wl_customer6_legacy_chip_check: GET revinfo FAILED. ret:%d\n", ret));
4449
+ ASSERT(0);
4450
+ return false;
4451
+ }
4452
+
4453
+ WL_DBG(("wl_customer6_legacy_chip_check: GET_REVINFO device 0x%x, vendor 0x%x,"
4454
+ " chipnum 0x%x\n",
4455
+ dtoh32(revinfo.deviceid), dtoh32(revinfo.vendorid), dtoh32(revinfo.chipnum)));
4456
+ chipnum = revinfo.chipnum;
4457
+ if (
4458
+#ifdef BCM4350_CHIP_ID
4459
+ (chipnum == BCM4350_CHIP_ID) ||
4460
+#endif /* BCM4350_CHIP_ID */
4461
+#ifdef BCM4355_CHIP_ID
4462
+ ((chipnum == BCM4355_CHIP_ID) && (revinfo.chiprev < BCM4355_REV_C1 ||
4463
+ revinfo.chiprev == BCM4355_REV_D0)) ||
4464
+#endif /* BCM4355_CHIP_ID */
4465
+#ifdef BCM4345_CHIP_ID
4466
+ (chipnum == BCM4345_CHIP_ID) ||
4467
+#endif /* BCM4345_CHIP_ID */
4468
+#ifdef BCM4373_CHIP_ID
4469
+ (chipnum == BCM4373_CHIP_ID) ||
4470
+#endif /* BCM4373_CHIP_ID */
4471
+ false) {
4472
+ /* WAR required */
4473
+ WL_DBG(("%s: Customer6 legacy chip identified\n", __FUNCTION__));
4474
+ return true;
4475
+ }
4476
+
4477
+ return false;
4478
+}
4479
+
4480
+void
4481
+wl_bss_iovar_war(struct bcm_cfg80211 *cfg,
4482
+ struct net_device *ndev, s32 *val)
4483
+{
4484
+ if (wl_customer6_legacy_chip_check(cfg, ndev)) {
4485
+ /* Few firmware branches have issues in bss iovar handling and
4486
+ * that can't be changed since they are in production.
4487
+ */
4488
+ if (*val == WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE) {
4489
+ *val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
4490
+ } else if (*val == WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE) {
4491
+ *val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
4492
+ } else {
4493
+ /* Ignore for other bss enums */
4494
+ return;
4495
+ }
4496
+ WL_ERR(("wl bss %d\n", *val));
4497
+ }
4498
+}
4499
+#endif // endif
33534500
33544501 s32
33554502 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
33564503 struct net_device *ndev, s32 bsscfg_idx,
3357
- enum nl80211_iftype iface_type, s32 del, u8 *addr)
4504
+ wl_iftype_t brcm_iftype, s32 del, u8 *addr)
33584505 {
33594506 s32 ret = BCME_OK;
33604507 s32 val = 0;
....@@ -3365,22 +4512,23 @@
33654512 struct ether_addr ea;
33664513 } bss_setbuf;
33674514
3368
- WL_INFORM(("iface_type:%d del:%d \n", iface_type, del));
4515
+ WL_DBG(("wl_iftype:%d del:%d \n", brcm_iftype, del));
33694516
33704517 bzero(&bss_setbuf, sizeof(bss_setbuf));
33714518
3372
- /* AP=3, STA=2, up=1, down=0, val=-1 */
4519
+ /* AP=2, STA=3, up=1, down=0, val=-1 */
33734520 if (del) {
3374
- val = -1;
3375
- } else if (iface_type == NL80211_IFTYPE_AP) {
3376
- /* AP Interface */
4521
+ val = WLC_AP_IOV_OP_DELETE;
4522
+ } else if (brcm_iftype == WL_IF_TYPE_AP) {
4523
+ /* Add/role change to AP Interface */
33774524 WL_DBG(("Adding AP Interface \n"));
3378
- val = 3;
3379
- } else if (iface_type == NL80211_IFTYPE_STATION) {
4525
+ val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
4526
+ } else if (brcm_iftype == WL_IF_TYPE_STA) {
4527
+ /* Add/role change to STA Interface */
33804528 WL_DBG(("Adding STA Interface \n"));
3381
- val = 2;
4529
+ val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
33824530 } else {
3383
- WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", iface_type));
4531
+ WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", brcm_iftype));
33844532 return -EINVAL;
33854533 }
33864534
....@@ -3391,6 +4539,7 @@
33914539 memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
33924540 }
33934541
4542
+ WL_INFORM_MEM(("wl bss %d bssidx:%d iface:%s \n", val, bsscfg_idx, ndev->name));
33944543 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
33954544 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
33964545 if (ret != 0)
....@@ -3399,13 +4548,524 @@
33994548 return ret;
34004549 }
34014550
3402
-#if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF)
4551
+s32
4552
+wl_cfg80211_bss_up(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 bss_up)
4553
+{
4554
+ s32 ret = BCME_OK;
4555
+ s32 val = bss_up ? 1 : 0;
4556
+
4557
+ struct {
4558
+ s32 cfg;
4559
+ s32 val;
4560
+ } bss_setbuf;
4561
+
4562
+ bss_setbuf.cfg = htod32(bsscfg_idx);
4563
+ bss_setbuf.val = htod32(val);
4564
+
4565
+ WL_INFORM_MEM(("wl bss -C %d %s\n", bsscfg_idx, bss_up ? "up" : "down"));
4566
+ ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
4567
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
4568
+
4569
+ if (ret != 0) {
4570
+ WL_ERR(("'bss %d' failed with %d\n", bss_up, ret));
4571
+ }
4572
+
4573
+ return ret;
4574
+}
4575
+
4576
+bool
4577
+wl_cfg80211_bss_isup(struct net_device *ndev, int bsscfg_idx)
4578
+{
4579
+ s32 result, val;
4580
+ bool isup = false;
4581
+ s8 getbuf[64];
4582
+
4583
+ /* Check if the BSS is up */
4584
+ *(int*)getbuf = -1;
4585
+ result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
4586
+ sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
4587
+ if (result != 0) {
4588
+ WL_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
4589
+ WL_ERR(("NOTE: this ioctl error is normal "
4590
+ "when the BSS has not been created yet.\n"));
4591
+ } else {
4592
+ val = *(int*)getbuf;
4593
+ val = dtoh32(val);
4594
+ WL_DBG(("wl bss -C %d = %d\n", bsscfg_idx, val));
4595
+ isup = (val ? TRUE : FALSE);
4596
+ }
4597
+ return isup;
4598
+}
4599
+
4600
+s32
4601
+wl_iftype_to_mode(wl_iftype_t iftype)
4602
+{
4603
+ s32 mode = BCME_ERROR;
4604
+
4605
+ switch (iftype) {
4606
+ case WL_IF_TYPE_STA:
4607
+ case WL_IF_TYPE_P2P_GC:
4608
+ case WL_IF_TYPE_P2P_DISC:
4609
+ mode = WL_MODE_BSS;
4610
+ break;
4611
+ case WL_IF_TYPE_AP:
4612
+ case WL_IF_TYPE_P2P_GO:
4613
+ mode = WL_MODE_AP;
4614
+ break;
4615
+ case WL_IF_TYPE_NAN:
4616
+ mode = WL_MODE_NAN;
4617
+ break;
4618
+ case WL_IF_TYPE_AWDL:
4619
+ mode = WL_MODE_AWDL;
4620
+ break;
4621
+ case WL_IF_TYPE_AIBSS:
4622
+ /* Intentional fall through */
4623
+ case WL_IF_TYPE_IBSS:
4624
+ mode = WL_MODE_IBSS;
4625
+ break;
4626
+ default:
4627
+ WL_ERR(("Unsupported type:%d\n", iftype));
4628
+ break;
4629
+ }
4630
+ return mode;
4631
+}
4632
+
4633
+s32
4634
+cfg80211_to_wl_iftype(uint16 type, uint16 *role, uint16 *mode)
4635
+{
4636
+ switch (type) {
4637
+ case NL80211_IFTYPE_STATION:
4638
+ *role = WL_IF_TYPE_STA;
4639
+ *mode = WL_MODE_BSS;
4640
+ break;
4641
+ case NL80211_IFTYPE_AP:
4642
+ *role = WL_IF_TYPE_AP;
4643
+ *mode = WL_MODE_AP;
4644
+ break;
4645
+#ifdef WL_CFG80211_P2P_DEV_IF
4646
+ case NL80211_IFTYPE_P2P_DEVICE:
4647
+ *role = WL_IF_TYPE_P2P_DISC;
4648
+ *mode = WL_MODE_BSS;
4649
+ break;
4650
+#endif /* WL_CFG80211_P2P_DEV_IF */
4651
+ case NL80211_IFTYPE_P2P_GO:
4652
+ *role = WL_IF_TYPE_P2P_GO;
4653
+ *mode = WL_MODE_AP;
4654
+ break;
4655
+ case NL80211_IFTYPE_P2P_CLIENT:
4656
+ *role = WL_IF_TYPE_P2P_GC;
4657
+ *mode = WL_MODE_BSS;
4658
+ break;
4659
+ case NL80211_IFTYPE_MONITOR:
4660
+ WL_ERR(("Unsupported mode \n"));
4661
+ return BCME_UNSUPPORTED;
4662
+ case NL80211_IFTYPE_ADHOC:
4663
+ *role = WL_IF_TYPE_IBSS;
4664
+ *mode = WL_MODE_IBSS;
4665
+ break;
4666
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
4667
+ case NL80211_IFTYPE_NAN:
4668
+ *role = WL_IF_TYPE_NAN;
4669
+ *mode = WL_MODE_NAN;
4670
+ break;
4671
+#endif // endif
4672
+ default:
4673
+ WL_ERR(("Unknown interface type:0x%x\n", type));
4674
+ return BCME_ERROR;
4675
+ }
4676
+ return BCME_OK;
4677
+}
4678
+
4679
+static s32
4680
+wl_role_to_cfg80211_type(uint16 role, uint16 *wl_iftype, uint16 *mode)
4681
+{
4682
+ switch (role) {
4683
+ case WLC_E_IF_ROLE_STA:
4684
+ *wl_iftype = WL_IF_TYPE_STA;
4685
+ *mode = WL_MODE_BSS;
4686
+ return NL80211_IFTYPE_STATION;
4687
+ case WLC_E_IF_ROLE_AP:
4688
+ *wl_iftype = WL_IF_TYPE_AP;
4689
+ *mode = WL_MODE_AP;
4690
+ return NL80211_IFTYPE_AP;
4691
+ case WLC_E_IF_ROLE_P2P_GO:
4692
+ *wl_iftype = WL_IF_TYPE_P2P_GO;
4693
+ *mode = WL_MODE_AP;
4694
+ return NL80211_IFTYPE_P2P_GO;
4695
+ case WLC_E_IF_ROLE_P2P_CLIENT:
4696
+ *wl_iftype = WL_IF_TYPE_P2P_GC;
4697
+ *mode = WL_MODE_BSS;
4698
+ return NL80211_IFTYPE_P2P_CLIENT;
4699
+ case WLC_E_IF_ROLE_IBSS:
4700
+ *wl_iftype = WL_IF_TYPE_IBSS;
4701
+ *mode = WL_MODE_IBSS;
4702
+ return NL80211_IFTYPE_ADHOC;
4703
+ case WLC_E_IF_ROLE_NAN:
4704
+ *wl_iftype = WL_IF_TYPE_NAN;
4705
+ *mode = WL_MODE_NAN;
4706
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) && defined(WL_CFG80211_NAN)
4707
+ /* NL80211_IFTYPE_NAN should only be used with CFG80211 NAN MGMT
4708
+ * For Vendor HAL based NAN implementation, continue advertising
4709
+ * as a STA interface
4710
+ */
4711
+ return NL80211_IFTYPE_NAN;
4712
+#else
4713
+ return NL80211_IFTYPE_STATION;
4714
+#endif /* ((LINUX_VER >= KERNEL_VERSION(4, 9, 0))) && WL_CFG80211_NAN */
4715
+
4716
+ default:
4717
+ WL_ERR(("Unknown interface role:0x%x. Forcing type station\n", role));
4718
+ return BCME_ERROR;
4719
+ }
4720
+}
4721
+
4722
+struct net_device *
4723
+wl_cfg80211_post_ifcreate(struct net_device *ndev,
4724
+ wl_if_event_info *event, u8 *addr,
4725
+ const char *name, bool rtnl_lock_reqd)
4726
+{
4727
+ struct bcm_cfg80211 *cfg;
4728
+ struct net_device *primary_ndev;
4729
+ struct net_device *new_ndev = NULL;
4730
+ struct wireless_dev *wdev = NULL;
4731
+#ifdef WL_STATIC_IF
4732
+ int iface_num = 0;
4733
+#endif /* WL_STATIC_IF */
4734
+ s32 iface_type;
4735
+ s32 ret = BCME_OK;
4736
+ u16 mode;
4737
+ u8 mac_addr[ETH_ALEN];
4738
+ u16 wl_iftype;
4739
+
4740
+ if (!ndev || !event) {
4741
+ WL_ERR(("Wrong arg\n"));
4742
+ return NULL;
4743
+ }
4744
+
4745
+ cfg = wl_get_cfg(ndev);
4746
+ if (!cfg) {
4747
+ WL_ERR(("cfg null\n"));
4748
+ return NULL;
4749
+ }
4750
+
4751
+ WL_DBG(("Enter. role:%d ifidx:%d bssidx:%d\n",
4752
+ event->role, event->ifidx, event->bssidx));
4753
+ if (!event->ifidx || !event->bssidx) {
4754
+ /* Fw returned primary idx (0) for virtual interface */
4755
+ WL_ERR(("Wrong index. ifidx:%d bssidx:%d \n",
4756
+ event->ifidx, event->bssidx));
4757
+ return NULL;
4758
+ }
4759
+
4760
+ iface_type = wl_role_to_cfg80211_type(event->role, &wl_iftype, &mode);
4761
+ if (iface_type < 0) {
4762
+ /* Unknown iface type */
4763
+ WL_ERR(("Wrong iface type \n"));
4764
+ return NULL;
4765
+ }
4766
+
4767
+ WL_DBG(("mac_ptr:%p name:%s role:%d nl80211_iftype:%d " MACDBG "\n",
4768
+ addr, name, event->role, iface_type, MAC2STRDBG(event->mac)));
4769
+ if (!name) {
4770
+ /* If iface name is not provided, use dongle ifname */
4771
+ name = event->name;
4772
+ }
4773
+
4774
+ if (!addr) {
4775
+ /* If mac address is not set, use primary mac with locally administered
4776
+ * bit set.
4777
+ */
4778
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4779
+ memcpy(mac_addr, primary_ndev->dev_addr, ETH_ALEN);
4780
+ /* For customer6 builds, use primary mac address for virtual interface */
4781
+ mac_addr[0] |= 0x02;
4782
+ addr = mac_addr;
4783
+ }
4784
+
4785
+#ifdef WL_STATIC_IF
4786
+ if (is_static_iface_name(name, cfg)) {
4787
+ new_ndev = wl_cfg80211_post_static_ifcreate(cfg, event, addr, iface_type, name);
4788
+ if (!new_ndev) {
4789
+ WL_ERR(("failed to get I/F pointer\n"));
4790
+ return NULL;
4791
+ }
4792
+ wdev = new_ndev->ieee80211_ptr;
4793
+ } else
4794
+#endif /* WL_STATIC_IF */
4795
+ {
4796
+ new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
4797
+ name, addr, event->bssidx, event->name);
4798
+ if (!new_ndev) {
4799
+ WL_ERR(("I/F allocation failed! \n"));
4800
+ return NULL;
4801
+ } else {
4802
+ WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
4803
+ event->ifidx, event->bssidx));
4804
+ }
4805
+
4806
+ wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
4807
+ if (!wdev) {
4808
+ WL_ERR(("wireless_dev alloc failed! \n"));
4809
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4810
+ return NULL;
4811
+ }
4812
+
4813
+ wdev->wiphy = bcmcfg_to_wiphy(cfg);
4814
+ wdev->iftype = iface_type;
4815
+
4816
+ new_ndev->ieee80211_ptr = wdev;
4817
+ SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
4818
+
4819
+ memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
4820
+ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd)
4821
+ != BCME_OK) {
4822
+ WL_ERR(("IFACE register failed \n"));
4823
+ /* Post interface registration, wdev would be freed from the netdev
4824
+ * destructor path. For other cases, handle it here.
4825
+ */
4826
+ MFREE(cfg->osh, wdev, sizeof(*wdev));
4827
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4828
+ return NULL;
4829
+ }
4830
+ }
4831
+
4832
+ /* Initialize with the station mode params */
4833
+ ret = wl_alloc_netinfo(cfg, new_ndev, wdev, wl_iftype,
4834
+ PM_ENABLE, event->bssidx, event->ifidx);
4835
+ if (unlikely(ret)) {
4836
+ WL_ERR(("wl_alloc_netinfo Error (%d)\n", ret));
4837
+ goto fail;
4838
+ }
4839
+
4840
+ /* Apply the mode & infra setting based on iftype */
4841
+ if ((ret = wl_config_infra(cfg, new_ndev, wl_iftype)) < 0) {
4842
+ WL_ERR(("config ifmode failure (%d)\n", ret));
4843
+ goto fail;
4844
+ }
4845
+
4846
+ if (mode == WL_MODE_AP) {
4847
+ wl_set_drv_status(cfg, AP_CREATING, new_ndev);
4848
+ }
4849
+
4850
+ WL_INFORM_MEM(("Network Interface (%s) registered with host."
4851
+ " cfg_iftype:%d wl_role:%d " MACDBG "\n",
4852
+ new_ndev->name, iface_type, event->role, MAC2STRDBG(new_ndev->dev_addr)));
4853
+
4854
+#ifdef SUPPORT_SET_CAC
4855
+ wl_cfg80211_set_cac(cfg, 0);
4856
+#endif /* SUPPORT_SET_CAC */
4857
+
4858
+ return new_ndev;
4859
+
4860
+fail:
4861
+#ifdef WL_STATIC_IF
4862
+ /* remove static if from iflist */
4863
+ if ((iface_num = get_iface_num(name, cfg)) >= 0) {
4864
+ cfg->static_ndev_state[iface_num] = NDEV_STATE_FW_IF_FAILED;
4865
+ wl_cfg80211_update_iflist_info(cfg, new_ndev, (DHD_MAX_IFS + iface_num), addr,
4866
+ event->bssidx, event->name, NDEV_STATE_FW_IF_FAILED);
4867
+ }
4868
+#endif /* WL_STATIC_IF */
4869
+ if (new_ndev) {
4870
+ /* wdev would be freed from netdev destructor call back */
4871
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev, rtnl_lock_reqd);
4872
+ }
4873
+
4874
+ return NULL;
4875
+}
4876
+
4877
+s32
4878
+wl_cfg80211_delete_iface(struct bcm_cfg80211 *cfg,
4879
+ wl_iftype_t sec_data_if_type)
4880
+{
4881
+ struct net_info *iter, *next;
4882
+ struct net_device *primary_ndev;
4883
+ s32 ret = BCME_OK;
4884
+ uint8 i = 0;
4885
+
4886
+ BCM_REFERENCE(i);
4887
+ BCM_REFERENCE(ret);
4888
+
4889
+ /* Note: This function will clean up only the network interface and host
4890
+ * data structures. The firmware interface clean up will happen in the
4891
+ * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4892
+ * context for the module case).
4893
+ */
4894
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4895
+ WL_DBG(("Enter, deleting iftype %s\n",
4896
+ wl_iftype_to_str(sec_data_if_type)));
4897
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4898
+ for_each_ndev(cfg, iter, next) {
4899
+ GCC_DIAGNOSTIC_POP();
4900
+ if (iter->ndev && (iter->ndev != primary_ndev)) {
4901
+ if (iter->iftype != sec_data_if_type) {
4902
+ continue;
4903
+ }
4904
+ switch (sec_data_if_type) {
4905
+ case WL_IF_TYPE_P2P_GO:
4906
+ case WL_IF_TYPE_P2P_GC: {
4907
+ ret = _wl_cfg80211_del_if(cfg,
4908
+ iter->ndev, NULL, iter->ndev->name);
4909
+ break;
4910
+ }
4911
+#ifdef WL_NAN
4912
+ case WL_IF_TYPE_NAN: {
4913
+ if (cfg->nan_enable == false) {
4914
+ WL_INFORM_MEM(("Nan is not active,"
4915
+ " ignore NDI delete\n"));
4916
+ } else {
4917
+ ret = wl_cfgnan_delete_ndp(cfg, iter->ndev);
4918
+ }
4919
+ break;
4920
+ }
4921
+#endif /* WL_NAN */
4922
+ case WL_IF_TYPE_AP: {
4923
+ /* Cleanup AP */
4924
+#ifdef WL_STATIC_IF
4925
+ /* handle static ap */
4926
+ if (is_static_iface(cfg, iter->ndev)) {
4927
+ dev_close(iter->ndev);
4928
+ } else
4929
+#endif /* WL_STATIC_IF */
4930
+ {
4931
+ /* handle virtual created AP */
4932
+ ret = _wl_cfg80211_del_if(cfg, iter->ndev,
4933
+ NULL, iter->ndev->name);
4934
+ }
4935
+ break;
4936
+ }
4937
+ default: {
4938
+ WL_ERR(("Unsupported interface type\n"));
4939
+ ret = -ENOTSUPP;
4940
+ goto fail;
4941
+ }
4942
+ }
4943
+ }
4944
+ }
4945
+fail:
4946
+ return ret;
4947
+}
4948
+
4949
+void
4950
+wl_cfg80211_cleanup_virtual_ifaces(struct bcm_cfg80211 *cfg, bool rtnl_lock_reqd)
4951
+{
4952
+ struct net_info *iter, *next;
4953
+ struct net_device *primary_ndev;
4954
+
4955
+ /* Note: This function will clean up only the network interface and host
4956
+ * data structures. The firmware interface clean up will happen in the
4957
+ * during chip reset (ifconfig wlan0 down for built-in drivers/rmmod
4958
+ * context for the module case).
4959
+ */
4960
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
4961
+ WL_DBG(("Enter\n"));
4962
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
4963
+ for_each_ndev(cfg, iter, next) {
4964
+ GCC_DIAGNOSTIC_POP();
4965
+ if (iter->ndev && (iter->ndev != primary_ndev)) {
4966
+ /* Ensure interfaces are down before deleting */
4967
+#ifdef WL_STATIC_IF
4968
+ /* Avoiding cleaning static ifaces */
4969
+ if (!is_static_iface(cfg, iter->ndev))
4970
+#endif /* WL_STATIC_IF */
4971
+ {
4972
+ dev_close(iter->ndev);
4973
+ WL_DBG(("Cleaning up iface:%s \n", iter->ndev->name));
4974
+ wl_cfg80211_post_ifdel(iter->ndev, rtnl_lock_reqd, 0);
4975
+ }
4976
+ }
4977
+ }
4978
+}
4979
+
4980
+s32
4981
+wl_cfg80211_post_ifdel(struct net_device *ndev, bool rtnl_lock_reqd, s32 ifidx)
4982
+{
4983
+ s32 ret = BCME_OK;
4984
+ struct bcm_cfg80211 *cfg;
4985
+ struct net_info *netinfo = NULL;
4986
+
4987
+ if (!ndev || !ndev->ieee80211_ptr) {
4988
+ /* No wireless dev done for this interface */
4989
+ ret = -EINVAL;
4990
+ goto exit;
4991
+ }
4992
+
4993
+ cfg = wl_get_cfg(ndev);
4994
+ if (!cfg) {
4995
+ WL_ERR(("cfg null\n"));
4996
+ ret = BCME_ERROR;
4997
+ goto exit;
4998
+ }
4999
+
5000
+ if (ifidx <= 0) {
5001
+ WL_ERR(("Invalid IF idx for iface:%s\n", ndev->name));
5002
+ ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
5003
+ BCM_REFERENCE(ifidx);
5004
+ if (ifidx <= 0) {
5005
+ ASSERT(0);
5006
+ ret = BCME_ERROR;
5007
+ goto exit;
5008
+ }
5009
+ }
5010
+
5011
+ if ((netinfo = wl_get_netinfo_by_wdev(cfg, ndev_to_wdev(ndev))) == NULL) {
5012
+ WL_ERR(("Find netinfo from wdev %p failed\n", ndev_to_wdev(ndev)));
5013
+ ret = -ENODEV;
5014
+ goto exit;
5015
+ }
5016
+
5017
+#ifdef WL_STATIC_IF
5018
+ if (is_static_iface(cfg, ndev)) {
5019
+ ret = wl_cfg80211_post_static_ifdel(cfg, ndev);
5020
+ } else
5021
+#endif /* WL_STATIC_IF */
5022
+ {
5023
+ WL_INFORM_MEM(("[%s] cfg80211_remove_if ifidx:%d, vif_count:%d\n",
5024
+ ndev->name, ifidx, cfg->vif_count));
5025
+ wl_cfg80211_remove_if(cfg, ifidx, ndev, rtnl_lock_reqd);
5026
+ cfg->bss_pending_op = FALSE;
5027
+ }
5028
+
5029
+#ifdef SUPPORT_SET_CAC
5030
+ wl_cfg80211_set_cac(cfg, 1);
5031
+#endif /* SUPPORT_SET_CAC */
5032
+exit:
5033
+ return ret;
5034
+}
5035
+
5036
+int
5037
+wl_cfg80211_deinit_p2p_discovery(struct bcm_cfg80211 *cfg)
5038
+{
5039
+ s32 ret = BCME_OK;
5040
+ bcm_struct_cfgdev *cfgdev;
5041
+
5042
+ if (cfg->p2p) {
5043
+ /* De-initialize the p2p discovery interface, if operational */
5044
+ WL_ERR(("Disabling P2P Discovery Interface \n"));
5045
+#ifdef WL_CFG80211_P2P_DEV_IF
5046
+ cfgdev = bcmcfg_to_p2p_wdev(cfg);
5047
+#else
5048
+ cfgdev = cfg->p2p_net;
5049
+#endif // endif
5050
+ if (cfgdev) {
5051
+ ret = wl_cfg80211_scan_stop(cfg, cfgdev);
5052
+ if (unlikely(ret < 0)) {
5053
+ CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
5054
+ }
5055
+ }
5056
+
5057
+ wl_cfgp2p_disable_discovery(cfg);
5058
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
5059
+ p2p_on(cfg) = false;
5060
+ }
5061
+ return ret;
5062
+}
34035063 /* Create a Generic Network Interface and initialize it depending up on
34045064 * the interface type
34055065 */
3406
-bcm_struct_cfgdev*
5066
+struct wireless_dev *
34075067 wl_cfg80211_create_iface(struct wiphy *wiphy,
3408
- enum nl80211_iftype iface_type,
5068
+ wl_iftype_t wl_iftype,
34095069 u8 *mac_addr, const char *name)
34105070 {
34115071 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
....@@ -3413,20 +5073,29 @@
34135073 struct net_device *primary_ndev = NULL;
34145074 s32 ret = BCME_OK;
34155075 s32 bsscfg_idx = 0;
3416
- u32 timeout;
5076
+ long timeout;
34175077 wl_if_event_info *event = NULL;
3418
- struct wireless_dev *wdev = NULL;
34195078 u8 addr[ETH_ALEN];
5079
+ struct net_info *iter, *next;
34205080
34215081 WL_DBG(("Enter\n"));
3422
-
34235082 if (!name) {
34245083 WL_ERR(("Interface name not provided\n"));
34255084 return NULL;
34265085 }
3427
-
5086
+ else {
5087
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
5088
+ for_each_ndev(cfg, iter, next) {
5089
+ GCC_DIAGNOSTIC_POP();
5090
+ if (iter->ndev) {
5091
+ if (strncmp(iter->ndev->name, name, strlen(name)) == 0) {
5092
+ WL_ERR(("Interface name,%s exists!\n", iter->ndev->name));
5093
+ return NULL;
5094
+ }
5095
+ }
5096
+ }
5097
+ }
34285098 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
3429
-
34305099 if (likely(!mac_addr)) {
34315100 /* Use primary MAC with the locally administered bit for the
34325101 * Secondary STA I/F
....@@ -3438,54 +5107,32 @@
34385107 memcpy(addr, mac_addr, ETH_ALEN);
34395108 }
34405109
3441
- if ((iface_type != NL80211_IFTYPE_STATION) && (iface_type != NL80211_IFTYPE_AP)) {
3442
- WL_ERR(("IFACE type:%d not supported. STA "
3443
- "or AP IFACE is only supported\n", iface_type));
3444
- return NULL;
3445
- }
3446
-
34475110 cfg->bss_pending_op = TRUE;
3448
- memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
3449
-
3450
- /* De-initialize the p2p discovery interface, if operational */
3451
- if (p2p_is_on(cfg)) {
3452
- WL_DBG(("Disabling P2P Discovery Interface \n"));
3453
-#ifdef WL_CFG80211_P2P_DEV_IF
3454
- ret = wl_cfg80211_scan_stop(bcmcfg_to_p2p_wdev(cfg));
3455
-#else
3456
- ret = wl_cfg80211_scan_stop(cfg->p2p_net);
3457
-#endif
3458
- if (unlikely(ret < 0)) {
3459
- CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
3460
- }
3461
-
3462
- wl_cfgp2p_disable_discovery(cfg);
3463
- wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
3464
- p2p_on(cfg) = false;
3465
- }
5111
+ bzero(&cfg->if_event_info, sizeof(cfg->if_event_info));
34665112
34675113 /*
34685114 * Intialize the firmware I/F.
34695115 */
3470
- ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
3471
- NL80211_IFTYPE_STATION, 0, addr);
5116
+ {
5117
+ ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
5118
+ wl_iftype, 0, addr);
5119
+ }
34725120 if (ret == BCME_UNSUPPORTED) {
34735121 /* Use bssidx 1 by default */
34745122 bsscfg_idx = 1;
34755123 if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
3476
- bsscfg_idx, iface_type, 0, addr)) < 0) {
3477
- return NULL;
5124
+ bsscfg_idx, wl_iftype, 0, addr)) < 0) {
5125
+ goto exit;
34785126 }
34795127 } else if (ret < 0) {
34805128 WL_ERR(("Interface create failed!! ret:%d \n", ret));
3481
- goto fail;
5129
+ goto exit;
34825130 } else {
34835131 /* Success */
34845132 bsscfg_idx = ret;
34855133 }
34865134
34875135 WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
3488
-
34895136 /*
34905137 * Wait till the firmware send a confirmation event back.
34915138 */
....@@ -3493,117 +5140,108 @@
34935140 timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
34945141 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
34955142 if (timeout <= 0 || cfg->bss_pending_op) {
3496
- WL_ERR(("ADD_IF event, didn't come. Return \n"));
3497
- goto fail;
5143
+ WL_ERR(("ADD_IF event, didn't come. Return. timeout:%lu bss_pending_op:%d\n",
5144
+ timeout, cfg->bss_pending_op));
5145
+ if (timeout == -ERESTARTSYS) {
5146
+ WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
5147
+ }
5148
+ goto exit;
34985149 }
34995150
5151
+ event = &cfg->if_event_info;
35005152 /*
35015153 * Since FW operation is successful,we can go ahead with the
35025154 * the host interface creation.
35035155 */
3504
- event = &cfg->if_event_info;
3505
- new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
3506
- (char*)name, addr, event->bssidx, event->name);
3507
- if (!new_ndev) {
3508
- WL_ERR(("I/F allocation failed! \n"));
3509
- goto fail;
3510
- } else
3511
- WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
3512
- event->ifidx, event->bssidx));
5156
+ new_ndev = wl_cfg80211_post_ifcreate(primary_ndev,
5157
+ event, addr, name, false);
35135158
3514
- wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
3515
- if (!wdev) {
3516
- WL_ERR(("wireless_dev alloc failed! \n"));
3517
- goto fail;
5159
+ if (new_ndev) {
5160
+ /* Iface post ops successful. Return ndev/wdev ptr */
5161
+ return new_ndev->ieee80211_ptr;
35185162 }
35195163
3520
- wdev->wiphy = wiphy;
3521
- wdev->iftype = iface_type;
3522
- new_ndev->ieee80211_ptr = wdev;
3523
- SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
3524
-
3525
- /* RTNL lock must have been acquired. */
3526
- ASSERT_RTNL();
3527
-
3528
- /* Set the locally administed mac addr, if not applied already */
3529
- if (memcmp(addr, event->mac, ETH_ALEN) != 0) {
3530
- ret = wldev_iovar_setbuf_bsscfg(primary_ndev, "cur_etheraddr",
3531
- addr, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
3532
- event->bssidx, &cfg->ioctl_buf_sync);
3533
- if (unlikely(ret)) {
3534
- WL_ERR(("set cur_etheraddr Error (%d)\n", ret));
3535
- goto fail;
3536
- }
3537
- memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
3538
- }
3539
-
3540
- if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
3541
- WL_ERR(("IFACE register failed \n"));
3542
- goto fail;
3543
- }
3544
-
3545
- /* Initialize with the station mode params */
3546
- wl_alloc_netinfo(cfg, new_ndev, wdev,
3547
- (iface_type == NL80211_IFTYPE_STATION) ?
3548
- WL_MODE_BSS : WL_MODE_AP, PM_ENABLE, event->bssidx);
3549
- cfg->bss_cfgdev = ndev_to_cfgdev(new_ndev);
3550
- cfg->cfgdev_bssidx = event->bssidx;
3551
-
3552
- WL_DBG(("Host Network Interface for Secondary I/F created"));
3553
-
3554
- return cfg->bss_cfgdev;
3555
-
3556
-fail:
5164
+exit:
35575165 cfg->bss_pending_op = FALSE;
3558
- cfg->cfgdev_bssidx = -1;
3559
- if (wdev)
3560
- kfree(wdev);
3561
- if (new_ndev)
3562
- wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
3563
-
35645166 return NULL;
35655167 }
35665168
35675169 s32
3568
-wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
5170
+wl_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
35695171 {
35705172 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
35715173 struct net_device *ndev = NULL;
3572
- struct net_device *primary_ndev = NULL;
35735174 s32 ret = BCME_OK;
35745175 s32 bsscfg_idx = 1;
3575
- u32 timeout;
3576
- u32 ifidx;
3577
- enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION;
5176
+ long timeout;
5177
+ u16 wl_iftype;
5178
+ u16 wl_mode;
35785179
35795180 WL_DBG(("Enter\n"));
3580
-
3581
- if (!cfg->bss_cfgdev)
3582
- return 0;
35835181
35845182 /* If any scan is going on, abort it */
35855183 if (wl_get_drv_status_all(cfg, SCANNING)) {
35865184 WL_DBG(("Scan in progress. Aborting the scan!\n"));
3587
- wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
5185
+ wl_cfg80211_cancel_scan(cfg);
35885186 }
35895187
3590
- ndev = (struct net_device *)cfgdev_to_ndev(cfg->bss_cfgdev);
3591
- primary_ndev = bcmcfg_to_prmry_ndev(cfg);
5188
+ bsscfg_idx = wl_get_bssidx_by_wdev(cfg, wdev);
5189
+ if (bsscfg_idx <= 0) {
5190
+ /* validate bsscfgidx */
5191
+ WL_ERR(("Wrong bssidx! \n"));
5192
+ return -EINVAL;
5193
+ }
35925194
3593
- cfg->bss_pending_op = TRUE;
5195
+ /* Handle p2p iface */
5196
+ if ((ret = wl_cfg80211_p2p_if_del(wiphy, wdev)) != BCME_NOTFOUND) {
5197
+ WL_DBG(("P2P iface del handled \n"));
5198
+#ifdef SUPPORT_SET_CAC
5199
+ wl_cfg80211_set_cac(cfg, 1);
5200
+#endif /* SUPPORT_SET_CAC */
5201
+ return ret;
5202
+ }
5203
+
5204
+ ndev = wdev->netdev;
5205
+ if (unlikely(!ndev)) {
5206
+ WL_ERR(("ndev null! \n"));
5207
+ return -EINVAL;
5208
+ }
5209
+
35945210 memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
35955211
5212
+ if (cfg80211_to_wl_iftype(ndev->ieee80211_ptr->iftype,
5213
+ &wl_iftype, &wl_mode) < 0) {
5214
+ return -EINVAL;
5215
+ }
5216
+
5217
+ WL_DBG(("del interface. bssidx:%d cfg_iftype:%d wl_iftype:%d",
5218
+ bsscfg_idx, ndev->ieee80211_ptr->iftype, wl_iftype));
35965219 /* Delete the firmware interface. "interface_remove" command
35975220 * should go on the interface to be deleted
35985221 */
3599
- ret = wl_cfg80211_interface_ops(cfg, ndev, cfg->cfgdev_bssidx,
3600
- NL80211_IFTYPE_STATION, 1, NULL);
5222
+ if (wl_cfg80211_get_bus_state(cfg)) {
5223
+ WL_ERR(("Bus state is down: %d\n", __LINE__));
5224
+ ret = BCME_DONGLE_DOWN;
5225
+ goto exit;
5226
+ }
5227
+
5228
+ cfg->bss_pending_op = true;
5229
+ ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx,
5230
+ wl_iftype, 1, NULL);
36015231 if (ret == BCME_UNSUPPORTED) {
36025232 if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
3603
- bsscfg_idx, iface_type, true, NULL)) < 0) {
5233
+ bsscfg_idx, wl_iftype, true, NULL)) < 0) {
36045234 WL_ERR(("DEL bss failed ret:%d \n", ret));
36055235 goto exit;
36065236 }
5237
+ } else if ((ret == BCME_NOTAP) || (ret == BCME_NOTSTA)) {
5238
+ /* De-init sequence involving role downgrade not happened.
5239
+ * Do nothing and return error. The del command should be
5240
+ * retried.
5241
+ */
5242
+ WL_ERR(("ifdel role mismatch:%d\n", ret));
5243
+ ret = -EBADTYPE;
5244
+ goto exit;
36075245 } else if (ret < 0) {
36085246 WL_ERR(("Interface DEL failed ret:%d \n", ret));
36095247 goto exit;
....@@ -3613,20 +5251,34 @@
36135251 !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
36145252 if (timeout <= 0 || cfg->bss_pending_op) {
36155253 WL_ERR(("timeout in waiting IF_DEL event\n"));
5254
+ /* The interface unregister will happen from wifi reset context */
5255
+ ret = -ETIMEDOUT;
5256
+ /* fall through */
36165257 }
36175258
36185259 exit:
3619
- ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
3620
- wl_cfg80211_remove_if(cfg, ifidx, ndev);
3621
- cfg->bss_cfgdev = NULL;
3622
- cfg->cfgdev_bssidx = -1;
3623
- cfg->bss_pending_op = FALSE;
5260
+ if (ret < 0) {
5261
+ WL_ERR(("iface del failed:%d\n", ret));
5262
+#ifdef WL_STATIC_IF
5263
+ if (is_static_iface(cfg, ndev)) {
5264
+ /*
5265
+ * For static interface, clean up the host data,
5266
+ * irrespective of fw status. For dynamic
5267
+ * interfaces it gets cleaned from dhd_stop context
5268
+ */
5269
+ wl_cfg80211_post_static_ifdel(cfg, ndev);
5270
+ }
5271
+#endif /* WL_STATIC_IF */
5272
+ } else {
5273
+ ret = wl_cfg80211_post_ifdel(ndev, false, cfg->if_event_info.ifidx);
5274
+ if (unlikely(ret)) {
5275
+ WL_ERR(("post_ifdel failed\n"));
5276
+ }
5277
+ }
36245278
3625
- WL_DBG(("IF_DEL Done.\n"));
3626
-
5279
+ cfg->bss_pending_op = false;
36275280 return ret;
36285281 }
3629
-#endif /* defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) */
36305282
36315283 static s32
36325284 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
....@@ -3647,8 +5299,9 @@
36475299
36485300 WL_TRACE(("In\n"));
36495301 RETURN_EIO_IF_NOT_UP(cfg);
3650
- WL_INFORM(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
3651
- if (!params->ssid || params->ssid_len <= 0) {
5302
+ WL_INFORM_MEM(("IBSS JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
5303
+ if (!params->ssid || params->ssid_len <= 0 ||
5304
+ params->ssid_len > DOT11_MAX_SSID_LEN) {
36525305 WL_ERR(("Invalid parameter\n"));
36535306 return -EINVAL;
36545307 }
....@@ -3711,6 +5364,11 @@
37115364 } else {
37125365 cfg->ibss_starter = true;
37135366 }
5367
+
5368
+ if (bss) {
5369
+ CFG80211_PUT_BSS(wiphy, bss);
5370
+ }
5371
+
37145372 if (chan) {
37155373 if (chan->band == IEEE80211_BAND_5GHZ)
37165374 param[0] = WLC_BAND_5G;
....@@ -3728,27 +5386,26 @@
37285386 * Join with specific BSSID and cached SSID
37295387 * If SSID is zero join based on BSSID only
37305388 */
3731
- memset(&join_params, 0, sizeof(join_params));
3732
- memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
5389
+ bzero(&join_params, sizeof(join_params));
5390
+ memcpy((void *)join_params.ssid.SSID, (const void *)params->ssid,
37335391 params->ssid_len);
37345392 join_params.ssid.SSID_len = htod32(params->ssid_len);
37355393 if (params->bssid) {
37365394 memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
3737
- err = wldev_ioctl(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
3738
- ETHER_ADDR_LEN, true);
5395
+ err = wldev_ioctl_set(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
5396
+ ETHER_ADDR_LEN);
37395397 if (unlikely(err)) {
37405398 WL_ERR(("Error (%d)\n", err));
37415399 return err;
37425400 }
37435401 } else
3744
- memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
3745
- wldev_iovar_setint(dev, "ibss_coalesce_allowed", IBSS_COALESCE_ALLOWED);
5402
+ bzero(&join_params.params.bssid, ETHER_ADDR_LEN);
37465403
37475404 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
37485405 scan_suppress = TRUE;
37495406 /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
3750
- err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS,
3751
- &scan_suppress, sizeof(int), true);
5407
+ err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5408
+ &scan_suppress, sizeof(int));
37525409 if (unlikely(err)) {
37535410 WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
37545411 return err;
....@@ -3764,19 +5421,18 @@
37645421 wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
37655422 wldev_iovar_setint(dev, "wsec", 0);
37665423
3767
-
3768
- err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
3769
- join_params_size, true);
5424
+ err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
5425
+ join_params_size);
37705426 if (unlikely(err)) {
3771
- WL_ERR(("Error (%d)\n", err));
5427
+ WL_ERR(("IBSS set_ssid Error (%d)\n", err));
37725428 return err;
37735429 }
37745430
37755431 if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
37765432 scan_suppress = FALSE;
37775433 /* Reset the SCAN SUPPRESS Flag */
3778
- err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS,
3779
- &scan_suppress, sizeof(int), true);
5434
+ err = wldev_ioctl_set(dev, WLC_SET_SCANSUPPRESS,
5435
+ &scan_suppress, sizeof(int));
37805436 if (unlikely(err)) {
37815437 WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
37825438 return err;
....@@ -3784,7 +5440,12 @@
37845440 }
37855441 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
37865442 wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
5443
+#ifdef WLAIBSS
5444
+ cfg->aibss_txfail_seq = 0; /* initialize the sequence */
5445
+#endif /* WLAIBSS */
5446
+#ifdef WL_RELMCAST
37875447 cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
5448
+#endif /* WL_RELMCAST */
37885449 return err;
37895450 }
37905451
....@@ -3798,13 +5459,13 @@
37985459 RETURN_EIO_IF_NOT_UP(cfg);
37995460 wl_link_down(cfg);
38005461
3801
- WL_ERR(("Leave IBSS\n"));
5462
+ WL_INFORM_MEM(("Leave IBSS\n"));
38025463 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
38035464 wl_set_drv_status(cfg, DISCONNECTING, dev);
38045465 scbval.val = 0;
38055466 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
3806
- err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
3807
- sizeof(scb_val_t), true);
5467
+ err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
5468
+ sizeof(scb_val_t));
38085469 if (unlikely(err)) {
38095470 wl_clr_drv_status(cfg, DISCONNECTING, dev);
38105471 WL_ERR(("error(%d)\n", err));
....@@ -3818,46 +5479,64 @@
38185479 }
38195480
38205481 #ifdef MFP
3821
-static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa)
5482
+static
5483
+int wl_cfg80211_get_rsn_capa(const bcm_tlv_t *wpa2ie,
5484
+ const u8** rsn_cap)
38225485 {
38235486 u16 suite_count;
3824
- wpa_suite_mcast_t *mcast;
3825
- wpa_suite_ucast_t *ucast;
3826
- u16 len;
3827
- wpa_suite_auth_key_mgmt_t *mgmt;
5487
+ const wpa_suite_mcast_t *mcast;
5488
+ const wpa_suite_ucast_t *ucast;
5489
+ int len;
5490
+ const wpa_suite_auth_key_mgmt_t *mgmt;
38285491
38295492 if (!wpa2ie)
3830
- return -1;
5493
+ return BCME_BADARG;
38315494
38325495 len = wpa2ie->len;
3833
- mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
3834
- if ((len -= WPA_SUITE_LEN) <= 0)
3835
- return BCME_BADLEN;
3836
- ucast = (wpa_suite_ucast_t *)&mcast[1];
5496
+
5497
+ /* check for Multicast cipher suite */
5498
+ if ((len -= (WPA_SUITE_LEN + WPA2_VERSION_LEN)) <= 0) {
5499
+ return BCME_NOTFOUND;
5500
+ }
5501
+
5502
+ mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
5503
+
5504
+ /* Check for the unicast suite(s) */
5505
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
5506
+ return BCME_NOTFOUND;
5507
+ }
5508
+
5509
+ ucast = (const wpa_suite_ucast_t *)&mcast[1];
38375510 suite_count = ltoh16_ua(&ucast->count);
38385511 if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
38395512 (len -= (WPA_IE_SUITE_COUNT_LEN +
38405513 (WPA_SUITE_LEN * suite_count))) <= 0)
38415514 return BCME_BADLEN;
3842
- mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
5515
+
5516
+ /* Check for AUTH key management suite(s) */
5517
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
5518
+ return BCME_NOTFOUND;
5519
+ }
5520
+
5521
+ mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
38435522 suite_count = ltoh16_ua(&mgmt->count);
38445523
3845
- if ((suite_count > NL80211_MAX_NR_CIPHER_SUITES) ||
3846
- (len -= (WPA_IE_SUITE_COUNT_LEN +
3847
- (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
3848
- capa[0] = *(u8 *)&mgmt->list[suite_count];
3849
- capa[1] = *((u8 *)&mgmt->list[suite_count] + 1);
3850
- } else
5524
+ if ((suite_count <= NL80211_MAX_NR_CIPHER_SUITES) &&
5525
+ (len -= (WPA_IE_SUITE_COUNT_LEN +
5526
+ (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
5527
+ rsn_cap[0] = (const u8 *)&mgmt->list[suite_count];
5528
+ } else {
38515529 return BCME_BADLEN;
5530
+ }
38525531
3853
- return 0;
5532
+ return BCME_OK;
38545533 }
38555534 #endif /* MFP */
38565535
38575536 static s32
38585537 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
38595538 {
3860
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
5539
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
38615540 struct wl_security *sec;
38625541 s32 val = 0;
38635542 s32 err = 0;
....@@ -3872,15 +5551,36 @@
38725551 val = WPA_AUTH_PSK |
38735552 WPA_AUTH_UNSPECIFIED;
38745553 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
3875
- val = WPA2_AUTH_PSK|
3876
- WPA2_AUTH_UNSPECIFIED;
5554
+#ifdef WL_SAE
5555
+ if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_SAE)
5556
+ val = WPA3_AUTH_SAE_PSK;
5557
+ else
5558
+#endif /* WL_SAE */
5559
+#ifdef WL_OWE
5560
+ if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_OWE)
5561
+ val = WPA3_AUTH_OWE;
5562
+ else
5563
+#endif /* WL_OWE */
5564
+ val = WPA2_AUTH_PSK |
5565
+ WPA2_AUTH_UNSPECIFIED;
5566
+#if defined(WL_SAE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
5567
+ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3)
5568
+ val = WPA3_AUTH_SAE_PSK;
5569
+#endif /* WL_SAE */
38775570 else
38785571 val = WPA_AUTH_DISABLED;
38795572
38805573 if (is_wps_conn(sme))
38815574 val = WPA_AUTH_DISABLED;
38825575
3883
- WL_DBG(("setting wpa_auth to 0x%0x\n", val));
5576
+#ifdef BCMWAPI_WPI
5577
+ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) {
5578
+ WL_DBG((" * wl_set_wpa_version, set wpa_auth"
5579
+ " to WPA_AUTH_WAPI 0x400"));
5580
+ val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5581
+ }
5582
+#endif // endif
5583
+ WL_INFORM_MEM(("[%s] wl wpa_auth 0x%0x\n", dev->name, val));
38845584 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
38855585 if (unlikely(err)) {
38865586 WL_ERR(("set wpa_auth failed (%d)\n", err));
....@@ -3891,11 +5591,35 @@
38915591 return err;
38925592 }
38935593
5594
+#ifdef BCMWAPI_WPI
5595
+static s32
5596
+wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme)
5597
+{
5598
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5599
+ s32 err = 0;
5600
+ s32 bssidx;
5601
+
5602
+ WL_DBG((" wl_set_set_wapi_ie\n"));
5603
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5604
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
5605
+ return BCME_ERROR;
5606
+ }
5607
+
5608
+ err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", (const void *)sme->ie, sme->ie_len,
5609
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5610
+ if (unlikely(err)) {
5611
+ WL_ERR(("set_wapi_ie Error (%d)\n", err));
5612
+ return err;
5613
+ }
5614
+ WL_INFORM_MEM(("wapi_ie successfully (%s)\n", dev->name));
5615
+ return err;
5616
+}
5617
+#endif /* BCMWAPI_WPI */
38945618
38955619 static s32
38965620 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
38975621 {
3898
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
5622
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
38995623 struct wl_security *sec;
39005624 s32 val = 0;
39015625 s32 err = 0;
....@@ -3919,12 +5643,33 @@
39195643 val = WL_AUTH_OPEN_SHARED;
39205644 WL_DBG(("automatic\n"));
39215645 break;
5646
+#ifdef WL_FILS
5647
+ case NL80211_AUTHTYPE_FILS_SK:
5648
+ WL_DBG(("fils shared key\n"));
5649
+ val = WL_AUTH_FILS_SHARED;
5650
+ break;
5651
+ case NL80211_AUTHTYPE_FILS_SK_PFS:
5652
+ val = WL_AUTH_FILS_SHARED_PFS;
5653
+ WL_DBG(("fils shared key with pfs\n"));
5654
+ break;
5655
+ case NL80211_AUTHTYPE_FILS_PK:
5656
+ WL_DBG(("fils public key\n"));
5657
+ val = WL_AUTH_FILS_PUBLIC;
5658
+ break;
5659
+#endif /* WL_FILS */
5660
+#ifdef WL_SAE
5661
+ case NL80211_AUTHTYPE_SAE:
5662
+ WL_DBG(("SAE authentication\n"));
5663
+ val = WL_AUTH_SAE;
5664
+ break;
5665
+#endif /* WL_SAE */
39225666 default:
39235667 val = 2;
39245668 WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
39255669 break;
39265670 }
39275671
5672
+ WL_INFORM_MEM(("[%s] wl auth 0x%0x \n", dev->name, val));
39285673 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
39295674 if (unlikely(err)) {
39305675 WL_ERR(("set auth failed (%d)\n", err));
....@@ -3935,17 +5680,62 @@
39355680 return err;
39365681 }
39375682
5683
+static u32
5684
+wl_rsn_cipher_wsec_algo_lookup(uint32 cipher)
5685
+{
5686
+ uint i;
5687
+
5688
+ for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5689
+ if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5690
+ return rsn_cipher_algo_lookup_tbl[i].wsec_algo;
5691
+ }
5692
+ }
5693
+ return WSEC_NONE;
5694
+}
5695
+
5696
+static u32
5697
+wl_rsn_cipher_wsec_key_algo_lookup(uint32 cipher)
5698
+{
5699
+ uint i;
5700
+
5701
+ for (i = 0; i < ARRAYSIZE(rsn_cipher_algo_lookup_tbl); i++) {
5702
+ if (cipher == rsn_cipher_algo_lookup_tbl[i].cipher_suite) {
5703
+ return rsn_cipher_algo_lookup_tbl[i].wsec_key_algo;
5704
+ }
5705
+ }
5706
+ return CRYPTO_ALGO_OFF;
5707
+}
5708
+
5709
+static u32
5710
+wl_rsn_akm_wpa_auth_lookup(uint32 akm)
5711
+{
5712
+ uint i;
5713
+
5714
+ for (i = 0; i < ARRAYSIZE(rsn_akm_wpa_auth_lookup_tbl); i++) {
5715
+ if (akm == rsn_akm_wpa_auth_lookup_tbl[i].akm_suite) {
5716
+ return rsn_akm_wpa_auth_lookup_tbl[i].wpa_auth;
5717
+ }
5718
+ }
5719
+ return WPA_AUTH_DISABLED;
5720
+}
5721
+
39385722 static s32
39395723 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
39405724 {
3941
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
5725
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
39425726 struct wl_security *sec;
39435727 s32 pval = 0;
39445728 s32 gval = 0;
39455729 s32 err = 0;
39465730 s32 wsec_val = 0;
3947
-
5731
+#ifdef BCMWAPI_WPI
5732
+ s32 wapi_val = 0;
5733
+ s32 val = 0;
5734
+#endif // endif
39485735 s32 bssidx;
5736
+#ifdef WL_GCMP
5737
+ uint32 algos = 0, mask = 0;
5738
+#endif /* WL_GCMP */
39495739
39505740 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
39515741 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
....@@ -3953,87 +5743,523 @@
39535743 }
39545744
39555745 if (sme->crypto.n_ciphers_pairwise) {
5746
+ pval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.ciphers_pairwise[0]);
5747
+ if (pval == WSEC_NONE) {
5748
+ WL_ERR(("invalid cipher pairwise (%d)\n", sme->crypto.ciphers_pairwise[0]));
5749
+ return BCME_BADARG;
5750
+ }
39565751 switch (sme->crypto.ciphers_pairwise[0]) {
3957
- case WLAN_CIPHER_SUITE_WEP40:
3958
- case WLAN_CIPHER_SUITE_WEP104:
3959
- pval = WEP_ENABLED;
5752
+#ifdef BCMWAPI_WPI
5753
+ case WLAN_CIPHER_SUITE_SMS4:
5754
+ val = pval;
5755
+ err = wl_set_set_wapi_ie(dev, sme);
5756
+ if (unlikely(err)) {
5757
+ WL_DBG(("Set wapi ie failed \n"));
5758
+ return err;
5759
+ } else {
5760
+ WL_DBG(("Set wapi ie succeded\n"));
5761
+ }
5762
+ wapi_val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
5763
+ WL_INFORM_MEM(("[WAPI] wl wpa_auth to 0x%0x (%s)\n", val, dev->name));
5764
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wapi_val, bssidx);
5765
+ if (unlikely(err)) {
5766
+ WL_ERR(("set wpa_auth failed (%d)\n", err));
5767
+ return err;
5768
+ }
39605769 break;
3961
- case WLAN_CIPHER_SUITE_TKIP:
3962
- pval = TKIP_ENABLED;
5770
+#endif /* BCMWAPI_WPI */
5771
+#ifdef WL_GCMP
5772
+ case WLAN_CIPHER_SUITE_GCMP:
5773
+ case WLAN_CIPHER_SUITE_GCMP_256:
5774
+ algos = KEY_ALGO_MASK(wl_rsn_cipher_wsec_key_algo_lookup(
5775
+ sme->crypto.ciphers_pairwise[0]));
5776
+ mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
39635777 break;
3964
- case WLAN_CIPHER_SUITE_CCMP:
3965
- case WLAN_CIPHER_SUITE_AES_CMAC:
3966
- pval = AES_ENABLED;
5778
+#endif /* WL_GCMP */
5779
+ default: /* No post processing required */
39675780 break;
3968
- default:
3969
- WL_ERR(("invalid cipher pairwise (%d)\n",
3970
- sme->crypto.ciphers_pairwise[0]));
3971
- return -EINVAL;
39725781 }
39735782 }
5783
+#if defined(BCMSUP_4WAY_HANDSHAKE)
5784
+ /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
5785
+ * handshake.
5786
+ * Note that the FW feature flag only exists on kernels that support the
5787
+ * FT-EAP AKM suite.
5788
+ */
5789
+ if ((cfg->wdev->wiphy->features & NL80211_FEATURE_FW_4WAY_HANDSHAKE) &&
5790
+ (FW_SUPPORTED(dhdp, idsup)))
5791
+ {
5792
+ err = wldev_iovar_setint_bsscfg(dev, "sup_wpa", 1, bssidx);
5793
+ if (err) {
5794
+ WL_ERR(("FBT: Error setting sup_wpa (%d)\n", err));
5795
+ return err;
5796
+ } else {
5797
+ WL_INFORM_MEM(("idsup enabled.\n"));
5798
+ }
5799
+ }
5800
+#endif /* BCMSUP_4WAY_HANDSHAKE */
39745801 if (sme->crypto.cipher_group) {
5802
+ gval = wl_rsn_cipher_wsec_algo_lookup(sme->crypto.cipher_group);
5803
+ if (gval == WSEC_NONE) {
5804
+ WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group));
5805
+ return BCME_BADARG;
5806
+ }
39755807 switch (sme->crypto.cipher_group) {
3976
- case WLAN_CIPHER_SUITE_WEP40:
3977
- case WLAN_CIPHER_SUITE_WEP104:
3978
- gval = WEP_ENABLED;
5808
+#ifdef BCMWAPI_WPI
5809
+ case WLAN_CIPHER_SUITE_SMS4:
5810
+ val = gval;
39795811 break;
3980
- case WLAN_CIPHER_SUITE_TKIP:
3981
- gval = TKIP_ENABLED;
5812
+#endif // endif
5813
+#ifdef WL_GCMP
5814
+ case WLAN_CIPHER_SUITE_GCMP:
5815
+ case WLAN_CIPHER_SUITE_GCMP_256:
5816
+ algos = KEY_ALGO_MASK(
5817
+ wl_rsn_cipher_wsec_key_algo_lookup(sme->crypto.cipher_group));
5818
+ mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
39825819 break;
3983
- case WLAN_CIPHER_SUITE_CCMP:
3984
- gval = AES_ENABLED;
5820
+#endif /* WL_GCMP */
5821
+ default: /* No post processing required */
39855822 break;
3986
- case WLAN_CIPHER_SUITE_AES_CMAC:
3987
- gval = AES_ENABLED;
3988
- break;
3989
- default:
3990
- WL_ERR(("invalid cipher group (%d)\n",
3991
- sme->crypto.cipher_group));
3992
- return -EINVAL;
39935823 }
39945824 }
39955825
39965826 WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
5827
+#ifdef WL_GCMP
5828
+ WL_DBG(("algos:%x, mask:%x", algos, mask));
5829
+#endif /* WL_GCMP */
39975830
39985831 if (is_wps_conn(sme)) {
3999
- if (sme->privacy)
4000
- err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
4001
- else
5832
+ if (sme->privacy) {
5833
+ wsec_val = 4;
5834
+ } else {
40025835 /* WPS-2.0 allows no security */
4003
- err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx);
5836
+ wsec_val = 0;
5837
+ }
40045838 } else {
5839
+#ifdef BCMWAPI_WPI
5840
+ if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) {
5841
+ WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
5842
+ wsec_val = val;
5843
+ } else
5844
+#endif // endif
5845
+ {
40055846 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
40065847 wsec_val = pval | gval;
4007
-
4008
- WL_DBG((" Set WSEC to fW 0x%x \n", wsec_val));
4009
- err = wldev_iovar_setint_bsscfg(dev, "wsec",
4010
- wsec_val, bssidx);
5848
+ }
40115849 }
5850
+
5851
+ WL_INFORM_MEM(("[%s] wl wsec 0x%x\n", dev->name, wsec_val));
5852
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec_val, bssidx);
40125853 if (unlikely(err)) {
40135854 WL_ERR(("error (%d)\n", err));
40145855 return err;
40155856 }
4016
-
5857
+#ifdef WL_GCMP
5858
+ if (wl_set_wsec_info_algos(dev, algos, mask)) {
5859
+ WL_ERR(("set wsec_info error (%d)\n", err));
5860
+ }
5861
+#endif /* WL_GCMP */
40175862 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
40185863 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
40195864 sec->cipher_group = sme->crypto.cipher_group;
5865
+ return err;
5866
+}
5867
+#ifdef WL_GCMP
5868
+static s32
5869
+wl_set_wsec_info_algos(struct net_device *dev, uint32 algos, uint32 mask)
5870
+{
5871
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5872
+ s32 bssidx;
5873
+ s32 err = 0;
5874
+ wl_wsec_info_t *wsec_info;
5875
+ bcm_xtlv_t *wsec_info_tlv;
5876
+ uint16 tlv_data_len;
5877
+ uint8 tlv_data[8];
5878
+ uint32 param_len;
5879
+ uint8 * buf;
5880
+
5881
+ WL_DBG(("enter.\n"));
5882
+ if (!cfg) {
5883
+ return BCME_ERROR;
5884
+ }
5885
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
5886
+ WL_ERR(("Find index from wdev(%p) failed\n", dev->ieee80211_ptr));
5887
+ return BCME_ERROR;
5888
+ }
5889
+
5890
+ buf = MALLOCZ(cfg->osh, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5891
+ if (!buf) {
5892
+ WL_ERR(("No memory"));
5893
+ return BCME_NOMEM;
5894
+ }
5895
+ wsec_info = (wl_wsec_info_t *)buf;
5896
+ wsec_info->version = WL_WSEC_INFO_VERSION;
5897
+ wsec_info_tlv = (bcm_xtlv_t *)(buf + OFFSETOF(wl_wsec_info_t, tlvs));
5898
+
5899
+ wsec_info->num_tlvs++;
5900
+ tlv_data_len = sizeof(tlv_data);
5901
+ err = memcpy_s(tlv_data, sizeof(tlv_data), &algos, sizeof(algos));
5902
+ if (err) {
5903
+ goto exit;
5904
+ }
5905
+ err = memcpy_s(tlv_data + sizeof(algos), sizeof(mask), &mask, sizeof(mask));
5906
+ if (err) {
5907
+ goto exit;
5908
+ }
5909
+ bcm_xtlv_pack_xtlv(wsec_info_tlv, WL_WSEC_INFO_BSS_ALGOS, tlv_data_len, tlv_data, 0);
5910
+ param_len = OFFSETOF(wl_wsec_info_t, tlvs) + WL_WSEC_INFO_TLV_HDR_LEN + tlv_data_len;
5911
+
5912
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_info", wsec_info, param_len,
5913
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
5914
+exit:
5915
+ MFREE(cfg->osh, buf, sizeof(wl_wsec_info_t) + sizeof(tlv_data));
5916
+ return err;
5917
+}
5918
+#endif /* WL_GCMP */
5919
+#ifdef MFP
5920
+static s32
5921
+wl_cfg80211_set_mfp(struct bcm_cfg80211 *cfg,
5922
+ struct net_device *dev,
5923
+ struct cfg80211_connect_params *sme)
5924
+{
5925
+ s32 mfp = WL_MFP_NONE;
5926
+ s32 current_mfp = WL_MFP_NONE;
5927
+ const bcm_tlv_t *wpa2_ie;
5928
+ const u8* rsn_cap = NULL;
5929
+ bool fw_support = false;
5930
+ int err, count = 0;
5931
+ const u8 *eptr = NULL, *ptr = NULL;
5932
+ const u8* group_mgmt_cs = NULL;
5933
+ const wpa_pmkid_list_t* pmkid = NULL;
5934
+
5935
+ if (!sme) {
5936
+ /* No connection params from userspace, Do nothing. */
5937
+ return 0;
5938
+ }
5939
+
5940
+ /* Check fw support and retreive current mfp val */
5941
+ err = wldev_iovar_getint(dev, "mfp", &current_mfp);
5942
+ if (!err) {
5943
+ fw_support = true;
5944
+ }
5945
+
5946
+ /* Parse the wpa2ie to decode the MFP capablity */
5947
+ if (((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
5948
+ DOT11_MNG_RSN_ID)) != NULL) &&
5949
+ (wl_cfg80211_get_rsn_capa(wpa2_ie, &rsn_cap) == 0) && rsn_cap) {
5950
+ WL_DBG(("rsn_cap 0x%x%x\n", rsn_cap[0], rsn_cap[1]));
5951
+ /* Check for MFP cap in the RSN capability field */
5952
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
5953
+ if (sme->mfp)
5954
+#endif // endif
5955
+ {
5956
+ if (rsn_cap[0] & RSN_CAP_MFPR) {
5957
+ mfp = WL_MFP_REQUIRED;
5958
+ } else if (rsn_cap[0] & RSN_CAP_MFPC) {
5959
+ mfp = WL_MFP_CAPABLE;
5960
+ }
5961
+ }
5962
+ /*
5963
+ * eptr --> end/last byte addr of wpa2_ie
5964
+ * ptr --> to keep track of current/required byte addr
5965
+ */
5966
+ eptr = (const u8*)wpa2_ie + (wpa2_ie->len + TLV_HDR_LEN);
5967
+ /* pointing ptr to the next byte after rns_cap */
5968
+ ptr = (const u8*)rsn_cap + RSN_CAP_LEN;
5969
+ if (mfp && (eptr - ptr) >= WPA2_PMKID_COUNT_LEN) {
5970
+ /* pmkid now to point to 1st byte addr of pmkid in wpa2_ie */
5971
+ pmkid = (const wpa_pmkid_list_t*)ptr;
5972
+ count = pmkid->count.low | (pmkid->count.high << 8);
5973
+ /* ptr now to point to last byte addr of pmkid */
5974
+ ptr = (const u8*)pmkid + (count * WPA2_PMKID_LEN
5975
+ + WPA2_PMKID_COUNT_LEN);
5976
+ if ((eptr - ptr) >= WPA_SUITE_LEN) {
5977
+ /* group_mgmt_cs now to point to first byte addr of bip */
5978
+ group_mgmt_cs = ptr;
5979
+ }
5980
+ }
5981
+ }
5982
+
5983
+ WL_DBG(("mfp:%d wpa2_ie ptr:%p mfp fw_support:%d\n",
5984
+ mfp, wpa2_ie, fw_support));
5985
+
5986
+ if (fw_support == false) {
5987
+ if (mfp) {
5988
+ /* if mfp > 0, mfp capability set in wpa ie, but
5989
+ * FW indicated error for mfp. Propagate the error up.
5990
+ */
5991
+ WL_ERR(("mfp capability found in wpaie. But fw doesn't"
5992
+ "seem to support MFP\n"));
5993
+ err = -EINVAL;
5994
+ goto exit;
5995
+ } else {
5996
+ /* Firmware doesn't support mfp. But since connection request
5997
+ * is for non-mfp case, don't bother.
5998
+ */
5999
+ err = BCME_OK;
6000
+ goto exit;
6001
+ }
6002
+ } else if (mfp != current_mfp) {
6003
+ err = wldev_iovar_setint(dev, "mfp", mfp);
6004
+ if (unlikely(err)) {
6005
+ WL_ERR(("mfp (%d) set failed ret:%d \n", mfp, err));
6006
+ goto exit;
6007
+ }
6008
+ WL_INFORM_MEM(("[%s] wl mfp 0x%x\n", dev->name, mfp));
6009
+ }
6010
+
6011
+ if (group_mgmt_cs && bcmp((const uint8 *)WPA2_OUI,
6012
+ group_mgmt_cs, (WPA_SUITE_LEN - 1)) == 0) {
6013
+ WL_DBG(("BIP is found\n"));
6014
+ err = wldev_iovar_setbuf(dev, "bip",
6015
+ group_mgmt_cs, WPA_SUITE_LEN, cfg->ioctl_buf,
6016
+ WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
6017
+ /*
6018
+ * Dont return failure for unsupported cases
6019
+ * of bip iovar for backward compatibility
6020
+ */
6021
+ if (err != BCME_UNSUPPORTED && err < 0) {
6022
+ WL_ERR(("bip set error (%d)\n", err));
6023
+#if defined(IGUANA_LEGACY_CHIPS)
6024
+ if (wl_customer6_legacy_chip_check(cfg,
6025
+ bcmcfg_to_prmry_ndev(cfg))) {
6026
+ /* Ignore bip error: Some older firmwares doesn't
6027
+ * support bip iovar/ return BCME_NOTUP while trying
6028
+ * to set bip from connect context. These firmares
6029
+ * include bip in RSNIE by default. So its okay to
6030
+ * ignore the error.
6031
+ */
6032
+ err = BCME_OK;
6033
+ goto exit;
6034
+ } else
6035
+#endif // endif
6036
+ {
6037
+ goto exit;
6038
+ }
6039
+ } else {
6040
+ WL_INFORM_MEM(("[%s] wl bip %02X:%02X:%02X\n",
6041
+ dev->name, group_mgmt_cs[0], group_mgmt_cs[1],
6042
+ group_mgmt_cs[2]));
6043
+ }
6044
+ }
6045
+exit:
6046
+ if (err) {
6047
+ wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
6048
+ FW_LOGSET_MASK_ALL);
6049
+ }
6050
+
6051
+ return 0;
6052
+}
6053
+#endif /* MFP */
6054
+
6055
+#ifdef WL_FILS
6056
+bool
6057
+wl_is_fils_supported(struct net_device *ndev)
6058
+{
6059
+ s32 err;
6060
+ u8 ioctl_buf[WLC_IOCTL_SMLEN] = {0};
6061
+ bcm_iov_buf_t *iov_buf = (bcm_iov_buf_t *)ioctl_buf;
6062
+
6063
+ iov_buf->version = WL_FILS_IOV_VERSION;
6064
+ err = wldev_iovar_getbuf(ndev, "fils", (uint8*)iov_buf, sizeof(bcm_iov_buf_t),
6065
+ iov_buf, WLC_IOCTL_SMLEN, NULL);
6066
+ if (err == BCME_UNSUPPORTED) {
6067
+ WL_DBG(("FILS NOT supported\n"));
6068
+ return false;
6069
+ }
6070
+
6071
+ WL_INFORM(("FILS supported\n"));
6072
+ return true;
6073
+}
6074
+
6075
+#define WL_NUM_OF_TLV_IN_SET_FILS_PARAMS 4u
6076
+static s32
6077
+wl_set_fils_params(struct net_device *dev, struct cfg80211_connect_params *sme)
6078
+{
6079
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6080
+ bcm_iov_buf_t *iov_buf = NULL;
6081
+ bcm_xtlvbuf_t tbuf;
6082
+ s32 err = BCME_OK;
6083
+ uint32 buf_size;
6084
+
6085
+ if ((sme->auth_type != NL80211_AUTHTYPE_FILS_SK) &&
6086
+ (sme->auth_type != NL80211_AUTHTYPE_FILS_SK_PFS) &&
6087
+ (sme->auth_type != NL80211_AUTHTYPE_FILS_PK)) {
6088
+ return BCME_OK;
6089
+ }
6090
+ if (sme->fils_erp_rrk_len > WL_MAX_FILS_KEY_LEN) {
6091
+ WL_ERR(("%s: FILS rRK exceed allowed size\n", __FUNCTION__));
6092
+ err = BCME_BADARG;
6093
+ goto exit;
6094
+ }
6095
+ /* Check incoming buffer length */
6096
+ buf_size = sme->fils_erp_username_len + sme->fils_erp_realm_len + sme->fils_erp_rrk_len +
6097
+ sizeof(sme->fils_erp_next_seq_num) +
6098
+ WL_NUM_OF_TLV_IN_SET_FILS_PARAMS * BCM_XTLV_HDR_SIZE_EX(BCM_XTLV_OPTION_ALIGN32) +
6099
+ sizeof(bcm_iov_buf_t) - 1u;
6100
+
6101
+ if (buf_size > WLC_IOCTL_SMLEN) {
6102
+ WL_ERR(("%s: FILS connect params arguments exceed allowed size\n", __FUNCTION__));
6103
+ err = BCME_BADARG;
6104
+ goto exit;
6105
+ }
6106
+ iov_buf = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
6107
+ if (!iov_buf) {
6108
+ WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, WLC_IOCTL_SMLEN));
6109
+ err = BCME_NOMEM;
6110
+ goto exit;
6111
+ }
6112
+ iov_buf->version = WL_FILS_IOV_VERSION;
6113
+ iov_buf->id = WL_FILS_CMD_ADD_CONNECT_PARAMS;
6114
+ /* check if this should be len w/o headers */
6115
+ err = bcm_xtlv_buf_init(&tbuf, (uint8*)&iov_buf->data[0],
6116
+ WLC_IOCTL_SMLEN - sizeof(bcm_iov_buf_t) + sizeof(uint16),
6117
+ BCM_XTLV_OPTION_ALIGN32);
6118
+ if (err != BCME_OK) {
6119
+ WL_ERR(("%s: xtlv_context initialization failed\n", __FUNCTION__));
6120
+ goto exit;
6121
+ }
6122
+ if (sme->fils_erp_username_len && sme->fils_erp_username != NULL) {
6123
+ err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_USERNAME,
6124
+ sme->fils_erp_username, sme->fils_erp_username_len);
6125
+ if (err != BCME_OK) {
6126
+ WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
6127
+ goto exit;
6128
+ }
6129
+ }
6130
+ if (sme->fils_erp_realm_len && sme->fils_erp_realm != NULL) {
6131
+ err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_REALM,
6132
+ sme->fils_erp_realm, sme->fils_erp_realm_len);
6133
+ if (err != BCME_OK) {
6134
+ WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
6135
+ goto exit;
6136
+ }
6137
+ }
6138
+ if (sme->fils_erp_rrk_len && sme->fils_erp_rrk != NULL) {
6139
+ err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_RRK,
6140
+ sme->fils_erp_rrk, sme->fils_erp_rrk_len);
6141
+ if (err != BCME_OK) {
6142
+ WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
6143
+ goto exit;
6144
+ }
6145
+ }
6146
+ err = bcm_xtlv_put_data(&tbuf, WL_FILS_XTLV_ERP_NEXT_SEQ_NUM,
6147
+ (u8 *)&sme->fils_erp_next_seq_num, sizeof(sme->fils_erp_next_seq_num));
6148
+ if (err != BCME_OK) {
6149
+ WL_ERR(("%s: write xtlv failed\n", __FUNCTION__));
6150
+ goto exit;
6151
+ }
6152
+ iov_buf->len = bcm_xtlv_buf_len(&tbuf);
6153
+ err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf->len + sizeof(bcm_iov_buf_t) -
6154
+ sizeof(uint16), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
6155
+ if (unlikely(err)) {
6156
+ WL_ERR(("set fils params ioctl error (%d)\n", err));
6157
+ goto exit;
6158
+ }
6159
+
6160
+exit:
6161
+ if (err != BCME_OK) {
6162
+ WL_ERR(("set FILS params error %d\n", err));
6163
+ }
6164
+ else {
6165
+ WL_INFORM_MEM(("FILS parameters succesfully applied\n"));
6166
+ }
6167
+ if (iov_buf) {
6168
+ MFREE(cfg->osh, iov_buf, WLC_IOCTL_SMLEN);
6169
+ }
6170
+ return err;
6171
+}
6172
+
6173
+#if !defined(WL_FILS_ROAM_OFFLD) && defined(WL_FILS)
6174
+static s32
6175
+wl_get_bcn_timeout(struct net_device *dev, u32 *bcn_timeout)
6176
+{
6177
+ s32 err = 0;
6178
+
6179
+ err = wldev_iovar_getint(dev, "bcn_timeout", bcn_timeout);
6180
+ if (unlikely(err)) {
6181
+ WL_ERR(("could not get bcn_timeout (%d)\n", err));
6182
+ }
6183
+ return err;
6184
+}
6185
+
6186
+#define WL_ROAM_ENABLE 0
6187
+#define WL_ROAM_DISABLE 1
6188
+/* Beacon Timeout beacon loss in case FILS roaming offload is not supported by fw */
6189
+#define WL_BCN_TIMEOUT 3
6190
+
6191
+static s32
6192
+wl_fils_toggle_roaming(struct net_device *dev, u32 auth_type)
6193
+{
6194
+ s32 err = 0;
6195
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6196
+
6197
+ if (WPA2_AUTH_IS_FILS(auth_type) && !cfg->fils_info.fils_roam_disabled) {
6198
+ err = wl_get_bcn_timeout(dev, &cfg->fils_info.fils_bcn_timeout_cache);
6199
+ if (unlikely(err)) {
6200
+ return err;
6201
+ }
6202
+ wl_dongle_roam(dev, WL_ROAM_DISABLE, WL_BCN_TIMEOUT);
6203
+ cfg->fils_info.fils_roam_disabled = true;
6204
+ WL_INFORM_MEM(("fw roam disabled for FILS akm\n"));
6205
+ } else if (cfg->fils_info.fils_roam_disabled) {
6206
+ /* Enable roaming back for other auth types */
6207
+ wl_dongle_roam(dev, WL_ROAM_ENABLE, cfg->fils_info.fils_bcn_timeout_cache);
6208
+ cfg->fils_info.fils_roam_disabled = false;
6209
+ WL_INFORM_MEM(("fw roam enabled\n"));
6210
+ }
6211
+ return err;
6212
+}
6213
+#endif /* !WL_FILS_ROAM_OFFLD && WL_FILS */
6214
+#endif /* WL_FILS */
6215
+
6216
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
6217
+#ifdef WL_SAE
6218
+static int
6219
+wl_set_sae_password(struct net_device *net, const u8 *pwd_data, u16 pwd_len)
6220
+{
6221
+ struct wl_wsec_sae_pwd_le sae_pwd;
6222
+ int err = 0;
6223
+ u8 ioctl_buf[WLC_IOCTL_SMLEN];
6224
+
6225
+ if (pwd_len < WL_WSEC_MIN_SAE_PASSWORD_LEN || pwd_len > WL_WSEC_MAX_SAE_PASSWORD_LEN) {
6226
+ WL_ERR(("len b/n >%d & <%d\n", WL_WSEC_MIN_SAE_PASSWORD_LEN,
6227
+ WL_WSEC_MAX_SAE_PASSWORD_LEN));
6228
+ return -EINVAL;
6229
+ }
6230
+ if (!pwd_data) {
6231
+ WL_ERR(("pswd cannot be null\n"));
6232
+ return -EINVAL;
6233
+ }
6234
+
6235
+ sae_pwd.key_len = htod16(pwd_len);
6236
+ memcpy(sae_pwd.key, pwd_data, pwd_len);
6237
+
6238
+ err = wldev_iovar_setbuf(net, "sae_password", &sae_pwd,
6239
+ sizeof(sae_pwd), ioctl_buf, WLC_IOCTL_SMLEN, NULL);
6240
+ if (err < 0)
6241
+ WL_ERR(("failed to set SAE password in firmware (len=%u)\n",
6242
+ pwd_len));
40206243
40216244 return err;
40226245 }
6246
+#endif /* WL_SAE */
6247
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) */
40236248
40246249 static s32
40256250 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
40266251 {
4027
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
6252
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6253
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
6254
+#ifdef WL_SAE
6255
+
6256
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
6257
+#endif /* WL_SAE */
6258
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) */
40286259 struct wl_security *sec;
40296260 s32 val = 0;
40306261 s32 err = 0;
40316262 s32 bssidx;
4032
-#ifdef MFP
4033
- s32 mfp = WL_MFP_NONE;
4034
- bcm_tlv_t *wpa2_ie;
4035
- u8 rsn_cap[2];
4036
-#endif /* MFP */
40376263
40386264 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
40396265 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
....@@ -4056,77 +6282,125 @@
40566282 val = WPA_AUTH_PSK;
40576283 break;
40586284 default:
4059
- WL_ERR(("invalid cipher group (%d)\n",
4060
- sme->crypto.cipher_group));
6285
+ WL_ERR(("invalid akm suite (0x%x)\n",
6286
+ sme->crypto.akm_suites[0]));
40616287 return -EINVAL;
40626288 }
40636289 } else if (val & (WPA2_AUTH_PSK |
40646290 WPA2_AUTH_UNSPECIFIED)) {
40656291 switch (sme->crypto.akm_suites[0]) {
4066
- case WLAN_AKM_SUITE_8021X:
4067
- val = WPA2_AUTH_UNSPECIFIED;
4068
- break;
40696292 #ifdef MFP
6293
+#if defined(IGUANA_LEGACY_CHIPS)
6294
+ case WL_AKM_SUITE_SHA256_1X:
6295
+ if (wl_customer6_legacy_chip_check(cfg, dev)) {
6296
+ val = WPA2_AUTH_UNSPECIFIED;
6297
+ } else {
6298
+ val = WPA2_AUTH_1X_SHA256;
6299
+ }
6300
+ break;
6301
+ case WL_AKM_SUITE_SHA256_PSK:
6302
+ if (wl_customer6_legacy_chip_check(cfg, dev)) {
6303
+ val = WPA2_AUTH_PSK;
6304
+ } else {
6305
+ val = WPA2_AUTH_PSK_SHA256;
6306
+ }
6307
+ break;
6308
+#else
40706309 case WL_AKM_SUITE_SHA256_1X:
40716310 val = WPA2_AUTH_1X_SHA256;
40726311 break;
40736312 case WL_AKM_SUITE_SHA256_PSK:
40746313 val = WPA2_AUTH_PSK_SHA256;
40756314 break;
6315
+#endif // endif
40766316 #endif /* MFP */
6317
+ case WLAN_AKM_SUITE_8021X:
40776318 case WLAN_AKM_SUITE_PSK:
4078
- val = WPA2_AUTH_PSK;
4079
- break;
40806319 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_8021X)
40816320 case WLAN_AKM_SUITE_FT_8021X:
4082
- val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT;
4083
- break;
4084
-#endif
6321
+#endif // endif
40856322 #if defined(WLFBT) && defined(WLAN_AKM_SUITE_FT_PSK)
40866323 case WLAN_AKM_SUITE_FT_PSK:
4087
- val = WPA2_AUTH_PSK | WPA2_AUTH_FT;
6324
+#endif // endif
6325
+ case WLAN_AKM_SUITE_FILS_SHA256:
6326
+ case WLAN_AKM_SUITE_FILS_SHA384:
6327
+ case WLAN_AKM_SUITE_8021X_SUITE_B:
6328
+ case WLAN_AKM_SUITE_8021X_SUITE_B_192:
6329
+#ifdef WL_OWE
6330
+ case WLAN_AKM_SUITE_OWE:
6331
+#endif /* WL_OWE */
6332
+#ifdef WL_SAE
6333
+ case WLAN_AKM_SUITE_SAE:
6334
+#endif /* WL_SAE */
6335
+ case WLAN_AKM_SUITE_DPP:
6336
+ case WLAN_AKM_SUITE_FT_8021X_SHA384:
6337
+ val = wl_rsn_akm_wpa_auth_lookup(sme->crypto.akm_suites[0]);
40886338 break;
4089
-#endif
6339
+ case WLAN_AKM_SUITE_FT_FILS_SHA256:
6340
+ val = WPA2_AUTH_FILS_SHA256 | WPA2_AUTH_FT;
6341
+ break;
6342
+ case WLAN_AKM_SUITE_FT_FILS_SHA384:
6343
+ val = WPA2_AUTH_FILS_SHA384 | WPA2_AUTH_FT;
6344
+ break;
40906345 default:
4091
- WL_ERR(("invalid cipher group (%d)\n",
4092
- sme->crypto.cipher_group));
6346
+ WL_ERR(("invalid akm suite (0x%x)\n",
6347
+ sme->crypto.akm_suites[0]));
40936348 return -EINVAL;
40946349 }
40956350 }
4096
-
4097
-#ifdef MFP
4098
- if (((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len,
4099
- DOT11_MNG_RSN_ID)) != NULL) &&
4100
- (wl_cfg80211_get_rsn_capa(wpa2_ie, rsn_cap) == 0)) {
4101
- /* Check for MFP cap in the RSN capability field */
4102
- if (rsn_cap[0] & RSN_CAP_MFPR) {
4103
- mfp = WL_MFP_REQUIRED;
4104
- } else if (rsn_cap[0] & RSN_CAP_MFPC) {
4105
- mfp = WL_MFP_CAPABLE;
4106
- }
6351
+#ifdef BCMWAPI_WPI
6352
+ else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) {
6353
+ switch (sme->crypto.akm_suites[0]) {
6354
+ case WLAN_AKM_SUITE_WAPI_CERT:
6355
+ val = WAPI_AUTH_UNSPECIFIED;
6356
+ break;
6357
+ case WLAN_AKM_SUITE_WAPI_PSK:
6358
+ val = WAPI_AUTH_PSK;
6359
+ break;
6360
+ default:
6361
+ WL_ERR(("invalid akm suite (0x%x)\n",
6362
+ sme->crypto.akm_suites[0]));
6363
+ return -EINVAL;
6364
+ }
41076365 }
4108
- err = wldev_iovar_setint(dev, "mfp", mfp);
4109
- if (unlikely(err)) {
4110
- if (!mfp && (err == BCME_UNSUPPORTED)) {
4111
- /* For non-mfp cases, if firmware doesn't support MFP
4112
- * ignore the failure and proceed ahead.
4113
- */
4114
- WL_DBG(("fw doesn't support mfp \n"));
4115
- err = 0;
4116
- } else {
4117
- WL_ERR(("mfp set failed ret:%d \n", err));
6366
+#endif // endif
6367
+
6368
+#ifdef WL_FILS
6369
+#if !defined(WL_FILS_ROAM_OFFLD)
6370
+ err = wl_fils_toggle_roaming(dev, val);
6371
+ if (unlikely(err)) {
6372
+ return err;
6373
+ }
6374
+#endif /* !WL_FILS_ROAM_OFFLD */
6375
+#endif /* !WL_FILS */
6376
+
6377
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
6378
+#ifdef WL_SAE
6379
+ if ((val & (WPA3_AUTH_SAE_PSK)) &&
6380
+ FW_SUPPORTED(dhd, sae)) {
6381
+ err = wl_set_sae_password(dev, sme->crypto.sae_pwd, sme->crypto.sae_pwd_len);
6382
+ if (!err && (FW_SUPPORTED(dhd, idsup))) {
6383
+ err = wldev_iovar_setint_bsscfg(dev, "sup_wpa", 1, bssidx);
6384
+ if (err) {
6385
+ WL_ERR(("Error setting sup_wpa (%d)\n", err));
41186386 return err;
41196387 }
4120
- } else {
4121
- WL_DBG(("mfp set to 0x%x \n", mfp));
6388
+ }
6389
+ }
6390
+#endif /* WL_SAE */
6391
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) */
6392
+
6393
+#ifdef MFP
6394
+ if ((err = wl_cfg80211_set_mfp(cfg, dev, sme)) < 0) {
6395
+ WL_ERR(("MFP set failed err:%d\n", err));
6396
+ return -EINVAL;
41226397 }
41236398 #endif /* MFP */
41246399
4125
- WL_DBG(("setting wpa_auth to 0x%x\n", val));
4126
-
6400
+ WL_INFORM_MEM(("[%s] wl wpa_auth to 0x%x\n", dev->name, val));
41276401 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
41286402 if (unlikely(err)) {
4129
- WL_ERR(("could not set wpa_auth (%d)\n", err));
6403
+ WL_ERR(("could not set wpa_auth (0x%x)\n", err));
41306404 return err;
41316405 }
41326406 }
....@@ -4140,7 +6414,7 @@
41406414 wl_set_set_sharedkey(struct net_device *dev,
41416415 struct cfg80211_connect_params *sme)
41426416 {
4143
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
6417
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
41446418 struct wl_security *sec;
41456419 struct wl_wsec_key key;
41466420 s32 val;
....@@ -4159,10 +6433,13 @@
41596433 sec->wpa_versions, sec->cipher_pairwise));
41606434 if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
41616435 NL80211_WPA_VERSION_2)) &&
6436
+#ifdef BCMWAPI_WPI
6437
+ !is_wapi(sec->cipher_pairwise) &&
6438
+#endif // endif
41626439 (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
41636440 WLAN_CIPHER_SUITE_WEP104)))
41646441 {
4165
- memset(&key, 0, sizeof(key));
6442
+ bzero(&key, sizeof(key));
41666443 key.len = (u32) sme->key_len;
41676444 key.index = (u32) sme->key_idx;
41686445 if (unlikely(key.len > sizeof(key.data))) {
....@@ -4171,14 +6448,10 @@
41716448 }
41726449 memcpy(key.data, sme->key, key.len);
41736450 key.flags = WL_PRIMARY_KEY;
4174
- switch (sec->cipher_pairwise) {
4175
- case WLAN_CIPHER_SUITE_WEP40:
4176
- key.algo = CRYPTO_ALGO_WEP1;
4177
- break;
4178
- case WLAN_CIPHER_SUITE_WEP104:
4179
- key.algo = CRYPTO_ALGO_WEP128;
4180
- break;
4181
- default:
6451
+ if ((sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP40) ||
6452
+ (sec->cipher_pairwise == WLAN_CIPHER_SUITE_WEP104)) {
6453
+ key.algo = wl_rsn_cipher_wsec_key_algo_lookup(sec->cipher_pairwise);
6454
+ } else {
41826455 WL_ERR(("Invalid algorithm (%d)\n",
41836456 sme->crypto.ciphers_pairwise[0]));
41846457 return -EINVAL;
....@@ -4194,6 +6467,7 @@
41946467 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
41956468 return err;
41966469 }
6470
+ WL_INFORM_MEM(("key applied to fw\n"));
41976471 if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
41986472 WL_DBG(("set auth_type to shared key\n"));
41996473 val = WL_AUTH_SHARED_KEY; /* shared key */
....@@ -4213,8 +6487,6 @@
42136487 static u8 broad_bssid[6];
42146488 #endif /* ESCAN_RESULT_PATCH */
42156489
4216
-
4217
-
42186490 #if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
42196491 static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
42206492 {
....@@ -4225,11 +6497,302 @@
42256497 chanspec = wl_chspec_driver_to_host(chanspec);
42266498
42276499 isvht80 = chanspec & WL_CHANSPEC_BW_80;
4228
- WL_INFO(("%s: chanspec(%x:%d)\n", __FUNCTION__, chanspec, isvht80));
6500
+ WL_DBG(("wl_get_chan_isvht80: chanspec(%x:%d)\n", chanspec, isvht80));
42296501
42306502 return isvht80;
42316503 }
42326504 #endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
6505
+
6506
+int wl_cfg80211_cleanup_mismatch_status(struct net_device *dev, struct bcm_cfg80211 *cfg,
6507
+ bool disassociate)
6508
+{
6509
+ scb_val_t scbval;
6510
+ int err = TRUE;
6511
+ int wait_cnt;
6512
+
6513
+ if (disassociate) {
6514
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6515
+ BCM_REFERENCE(dhdp);
6516
+ DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
6517
+ dhd_net2idx(dhdp->info, dev), DOT11_RC_DISASSOC_LEAVING);
6518
+ WL_ERR(("Disassociate previous connection!\n"));
6519
+ wl_set_drv_status(cfg, DISCONNECTING, dev);
6520
+ scbval.val = DOT11_RC_DISASSOC_LEAVING;
6521
+ scbval.val = htod32(scbval.val);
6522
+
6523
+ err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
6524
+ sizeof(scb_val_t));
6525
+ if (unlikely(err)) {
6526
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
6527
+ WL_ERR(("error (%d)\n", err));
6528
+ return err;
6529
+ }
6530
+ wait_cnt = 500/10;
6531
+ } else {
6532
+ wait_cnt = 200/10;
6533
+ WL_ERR(("Waiting for previous DISCONNECTING status!\n"));
6534
+ if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6535
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
6536
+ }
6537
+ }
6538
+
6539
+ while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
6540
+ WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
6541
+ wait_cnt));
6542
+ wait_cnt--;
6543
+ OSL_SLEEP(10);
6544
+ }
6545
+
6546
+ if (wait_cnt == 0) {
6547
+ WL_ERR(("DISCONNECING clean up failed!\n"));
6548
+ /* Clear DISCONNECTING driver status as we have made sufficient attempts
6549
+ * for driver clean up.
6550
+ */
6551
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
6552
+ return BCME_NOTREADY;
6553
+ }
6554
+ return BCME_OK;
6555
+}
6556
+
6557
+#ifdef WL_FILS
6558
+static int
6559
+wl_fils_add_hlp_container(struct bcm_cfg80211 *cfg, struct net_device *dev,
6560
+ const uint8* ie_buf, uint16 ie_len)
6561
+{
6562
+ const bcm_tlv_ext_t *hlp_ie;
6563
+
6564
+ if ((hlp_ie = (const bcm_tlv_ext_t*)bcm_parse_tlvs_dot11((const uint8 *)ie_buf, ie_len,
6565
+ FILS_HLP_CONTAINER_EXT_ID, TRUE))) {
6566
+ u16 hlp_len = hlp_ie->len;
6567
+ u16 left_len = (ie_len - ((const uint8*)hlp_ie - ie_buf));
6568
+ bcm_iov_buf_t *iov_buf = 0;
6569
+ uint8* pxtlv;
6570
+ int err;
6571
+ size_t iov_buf_len;
6572
+ bcm_tlv_dot11_frag_tot_len(ie_buf, ie_len, FILS_HLP_CONTAINER_EXT_ID,
6573
+ TRUE, (uint*)&hlp_len);
6574
+
6575
+ hlp_len += BCM_TLV_EXT_HDR_SIZE;
6576
+
6577
+ if ((hlp_len > DOT11_MAX_MPDU_BODY_LEN) || (hlp_len > left_len)) {
6578
+ WL_ERR(("bad HLP length %d\n", hlp_len));
6579
+ return EFAULT;
6580
+ }
6581
+ iov_buf_len = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) - 1 + hlp_len;
6582
+ iov_buf = MALLOCZ(cfg->osh, iov_buf_len);
6583
+ if (iov_buf == NULL) {
6584
+ WL_ERR(("failed to allocated iov_buf\n"));
6585
+ return ENOMEM;
6586
+ }
6587
+
6588
+ prhex("HLP, HLP", (const uchar *)hlp_ie, hlp_len);
6589
+
6590
+ pxtlv = (uint8 *)&iov_buf->data[0];
6591
+ ((bcm_xtlv_t*)pxtlv)->id = WL_FILS_XTLV_HLP_IE;
6592
+ ((bcm_xtlv_t*)pxtlv)->len = hlp_len;
6593
+
6594
+ memcpy(((bcm_xtlv_t*)pxtlv)->data, hlp_ie, ((bcm_xtlv_t*)pxtlv)->len);
6595
+
6596
+ iov_buf->version = WL_FILS_IOV_VERSION;
6597
+ iov_buf->id = WL_FILS_CMD_ADD_HLP_IE;
6598
+ iov_buf->len = ((sizeof(bcm_xtlv_t)-1) + ((bcm_xtlv_t*)pxtlv)->len);
6599
+
6600
+ err = wldev_iovar_setbuf(dev, "fils", iov_buf,
6601
+ sizeof(bcm_iov_buf_t) + iov_buf->len,
6602
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
6603
+ if (unlikely(err)) {
6604
+ WL_ERR(("fils wldev_iovar_setbuf error (%d)\n", err));
6605
+ }
6606
+ else {
6607
+ WL_INFORM_MEM(("FILS HLP Packet succesfully updated\n"));
6608
+ }
6609
+ MFREE(cfg->osh, iov_buf, iov_buf_len);
6610
+ }
6611
+ return BCME_OK;
6612
+}
6613
+#endif /* WL_FILS */
6614
+
6615
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
6616
+#define UPDATE_ASSOC_IES BIT(0)
6617
+#ifndef UPDATE_FILS_ERP_INFO
6618
+#define UPDATE_FILS_ERP_INFO BIT(1)
6619
+#define UPDATE_AUTH_TYPE BIT(2)
6620
+#endif // endif
6621
+#if defined(WL_FILS) || defined(WL_OWE)
6622
+static int
6623
+wl_cfg80211_update_connect_params(struct wiphy *wiphy, struct net_device *dev,
6624
+ struct cfg80211_connect_params *sme, u32 changed)
6625
+{
6626
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6627
+ s32 bssidx = -1;
6628
+ s32 err = BCME_OK;
6629
+
6630
+ if (changed & UPDATE_ASSOC_IES) {
6631
+ WL_DBG(("update assoc ies\n"));
6632
+ bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
6633
+
6634
+ err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
6635
+ VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
6636
+
6637
+ if (err) {
6638
+ WL_ERR(("error updating vndr ies\n"));
6639
+ goto exit;
6640
+ }
6641
+ }
6642
+#if defined(WL_FILS)
6643
+ if (changed & UPDATE_FILS_ERP_INFO) {
6644
+ err = wl_set_fils_params(dev, sme);
6645
+
6646
+ if (unlikely(err)) {
6647
+ WL_ERR(("Invalid FILS params\n"));
6648
+ goto exit;
6649
+ }
6650
+ }
6651
+ if (changed & UPDATE_AUTH_TYPE) {
6652
+ err = wl_set_auth_type(dev, sme);
6653
+ if (unlikely(err)) {
6654
+ WL_ERR(("Invalid auth type\n"));
6655
+ goto exit;
6656
+ }
6657
+ }
6658
+ if ((changed & UPDATE_FILS_ERP_INFO) && !(changed & UPDATE_AUTH_TYPE)) {
6659
+ WL_DBG(("Warning: FILS ERP params are set, but authentication type - not\n"));
6660
+ }
6661
+#endif // endif
6662
+exit:
6663
+ return err;
6664
+
6665
+}
6666
+#endif
6667
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
6668
+
6669
+#ifdef WL_SAE
6670
+static int
6671
+wl_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *dev,
6672
+ struct cfg80211_external_auth_params *params)
6673
+{
6674
+ int ret = 0;
6675
+ struct wl_auth_req_status auth_status;
6676
+ u8 ioctl_buf[WLC_IOCTL_SMLEN];
6677
+
6678
+ WL_DBG(("Enter\n"));
6679
+
6680
+ if (params->status == WLAN_STATUS_SUCCESS) {
6681
+ auth_status.flags = WL_EXTAUTH_SUCCESS;
6682
+ } else {
6683
+ WL_ERR(("External authentication failed with %d\n",
6684
+ params->status));
6685
+ auth_status.flags = WL_EXTAUTH_FAIL;
6686
+ }
6687
+ memcpy(auth_status.peer_mac.octet, params->bssid, ETH_ALEN);
6688
+ auth_status.ssid_len = min_t(u8, params->ssid.ssid_len,
6689
+ IEEE80211_MAX_SSID_LEN);
6690
+ memcpy(auth_status.ssid, params->ssid.ssid, auth_status.ssid_len);
6691
+ memset(auth_status.pmkid, 0, WLAN_PMKID_LEN);
6692
+ if (params->pmkid)
6693
+ memcpy(auth_status.pmkid, params->pmkid, WLAN_PMKID_LEN);
6694
+
6695
+ ret = wldev_iovar_setbuf(dev, "auth_status", &auth_status,
6696
+ sizeof(auth_status), ioctl_buf, WLC_IOCTL_SMLEN, NULL);
6697
+ if (ret < 0)
6698
+ WL_ERR(("auth_status iovar failed: ret=%d\n", ret));
6699
+
6700
+ return ret;
6701
+}
6702
+
6703
+/**
6704
+ * wl_notify_extauth_req_event() - host authentication request
6705
+ *
6706
+ * @cfg: object to handle cfg80211 interface
6707
+ * @cfgdev: represents ndev or wdev
6708
+ * @e: event message. Not used, to make it usable for fweh event dispatcher
6709
+ * @data: payload of message, containing auth frame data
6710
+ *
6711
+ */
6712
+static s32
6713
+wl_notify_extauth_req_event(struct bcm_cfg80211 *cfg,
6714
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
6715
+{
6716
+ struct cfg80211_external_auth_params params;
6717
+ struct wl_auth_req_status *auth_req = (struct wl_auth_req_status *)data;
6718
+ struct net_device *ndev = cfgdev_to_ndev(cfgdev);
6719
+ int err = 0;
6720
+
6721
+ WL_DBG(("EVENT: EXT_AUTH_REQ received\n"));
6722
+
6723
+ if (e->datalen < sizeof(*auth_req)) {
6724
+ WL_ERR(("Ext auth req event data too small. Ignoring event\n"));
6725
+ return -EINVAL;
6726
+ }
6727
+
6728
+ memset(&params, 0, sizeof(params));
6729
+ params.action = NL80211_EXTERNAL_AUTH_START;
6730
+ params.key_mgmt_suite = ntohl(WLAN_AKM_SUITE_SAE);
6731
+ params.status = WLAN_STATUS_SUCCESS;
6732
+ params.ssid.ssid_len = min_t(u32, IEEE80211_MAX_SSID_LEN, auth_req->ssid_len);
6733
+ memcpy(params.ssid.ssid, auth_req->ssid, params.ssid.ssid_len);
6734
+ memcpy(params.bssid, auth_req->peer_mac.octet, ETH_ALEN);
6735
+
6736
+ err = cfg80211_external_auth_request(ndev, &params, GFP_ATOMIC);
6737
+ if (err) {
6738
+ WL_ERR(("EXT_AUTH_REQ to supplicant failed\n"));
6739
+ }
6740
+ return err;
6741
+}
6742
+
6743
+/**
6744
+ * wl_notify_mgmt_frame_tx_complete() - transmit mgmt frame complete
6745
+ *
6746
+ * @cfg: object to handle cfg80211 interface
6747
+ * @cfgdev: represents ndev or wdev
6748
+ * @e: event message. Not used, to make it usable for fweh event dispatcher
6749
+ * @data: payload of message, containing auth frame data
6750
+ *
6751
+ */
6752
+static s32
6753
+wl_notify_mgmt_frame_tx_complete(struct bcm_cfg80211 *cfg,
6754
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
6755
+{
6756
+ u32 event_type = ntoh32(e->event_type);
6757
+ u32 status = ntoh32(e->status);
6758
+ struct net_device *ndev = NULL;
6759
+ u32 *packetid = (u32 *)data;
6760
+ struct net_info *_net_info;
6761
+
6762
+ WL_DBG((" Enter\n"));
6763
+
6764
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
6765
+ _net_info = wl_get_netinfo_by_netdev(cfg, ndev);
6766
+
6767
+ WL_DBG(("EVENT: mgmt tx status: event %s, status=%d\n",
6768
+ event_type == WLC_E_MGMT_FRAME_TXSTATUS ?
6769
+ "MGMT_FRAME_TXSTATUS" : "MGMT_FRAME_OFF_CHAN_COMPLETE", e->status));
6770
+
6771
+ if (!test_bit(MGMT_TX_SEND_FRAME, &_net_info->mgmt_txstatus) ||
6772
+ (*packetid != _net_info->mgmt_txid)) {
6773
+ return 0;
6774
+ }
6775
+
6776
+ if (event_type == WLC_E_MGMT_FRAME_TXSTATUS) {
6777
+ if (status == WLC_E_STATUS_SUCCESS) {
6778
+ set_bit(MGMT_TX_ACK,
6779
+ &_net_info->mgmt_txstatus);
6780
+ } else {
6781
+ set_bit(MGMT_TX_NOACK,
6782
+ &_net_info->mgmt_txstatus);
6783
+ }
6784
+ } else {
6785
+ set_bit(MGMT_TX_OFF_CHAN_COMPLETED,
6786
+ &_net_info->mgmt_txstatus);
6787
+ }
6788
+
6789
+ complete(&_net_info->mgmt_tx_cpl);
6790
+ return BCME_OK;
6791
+}
6792
+#endif /* WL_SAE */
6793
+
6794
+#define MAX_SCAN_ABORT_WAIT_CNT 20
6795
+#define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
42336796
42346797 static s32
42356798 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
....@@ -4240,29 +6803,73 @@
42406803 wl_extjoin_params_t *ext_join_params;
42416804 struct wl_join_params join_params;
42426805 size_t join_params_size;
6806
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6807
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
6808
+ s32 roam_trigger[2] = {0, 0};
6809
+#endif /* ROAM_AP_ENV_DETECTION */
42436810 s32 err = 0;
4244
- wpa_ie_fixed_t *wpa_ie;
4245
- bcm_tlv_t *wpa2_ie;
4246
- u8* wpaie = 0;
6811
+ const wpa_ie_fixed_t *wpa_ie;
6812
+ const bcm_tlv_t *wpa2_ie;
6813
+ const u8* wpaie = 0;
42476814 u32 wpaie_len = 0;
42486815 u32 chan_cnt = 0;
42496816 struct ether_addr bssid;
42506817 s32 bssidx = -1;
4251
- int ret;
6818
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
6819
+ bool skip_hints = fw_ap_select;
6820
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
6821
+#ifdef ESCAN_CHANNEL_CACHE
6822
+ chanspec_t chanspec_list[MAX_ROAM_CHANNEL];
6823
+#endif /* ESCAN_CHANNEL_CACHE */
42526824 int wait_cnt;
42536825
42546826 WL_DBG(("In\n"));
6827
+ if (!dev) {
6828
+ WL_ERR(("dev is null\n"));
6829
+ return -EINVAL;
6830
+ }
6831
+ BCM_REFERENCE(dhdp);
6832
+ DHD_STATLOG_CTRL(dhdp, ST(ASSOC_START), dhd_net2idx(dhdp->info, dev), 0);
6833
+
6834
+#ifdef ESCAN_CHANNEL_CACHE
6835
+ memset(chanspec_list, 0, (sizeof(chanspec_t) * MAX_ROAM_CHANNEL));
6836
+#endif /* ESCAN_CHANNEL_CACHE */
6837
+
6838
+ /* Connection attempted via linux-wireless */
6839
+ wl_set_drv_status(cfg, CFG80211_CONNECT, dev);
6840
+#ifdef DHDTCPSYNC_FLOOD_BLK
6841
+ dhd_reset_tcpsync_info_by_dev(dev);
6842
+#endif /* DHDTCPSYNC_FLOOD_BLK */
6843
+
6844
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
6845
+ /* Disable scanmac if enabled */
6846
+ if (cfg->scanmac_enabled) {
6847
+ wl_cfg80211_scan_mac_disable(dev);
6848
+ }
6849
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
42556850
42566851 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
4257
- if (sme->channel_hint) {
4258
- chan = sme->channel_hint;
4259
- WL_DBG(("channel_hint (%d), channel_hint center_freq (%d)\n",
4260
- ieee80211_frequency_to_channel(sme->channel_hint->center_freq),
4261
- sme->channel_hint->center_freq));
4262
- }
4263
- if (sme->bssid_hint) {
4264
- sme->bssid = sme->bssid_hint;
4265
- WL_DBG(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
6852
+#if defined(WL_FW_OCE_AP_SELECT)
6853
+ /* override bssid_hint for oce networks */
6854
+ skip_hints = (fw_ap_select && wl_cfg80211_is_oce_ap(wiphy, sme->bssid_hint));
6855
+#endif // endif
6856
+ if (skip_hints) {
6857
+ /* Let fw choose the best AP */
6858
+ WL_INFORM(("skipping bssid & channel hint\n"));
6859
+ /* sme->channel can point to an invalid address
6860
+ * which gets assigned to chan instead of NULL */
6861
+ chan = NULL;
6862
+ } else {
6863
+ if (sme->channel_hint) {
6864
+ chan = sme->channel_hint;
6865
+ WL_INFORM_MEM(("channel_hint (%d), channel_hint center_freq (%d)\n",
6866
+ ieee80211_frequency_to_channel(sme->channel_hint->center_freq),
6867
+ sme->channel_hint->center_freq));
6868
+ }
6869
+ if (sme->bssid_hint) {
6870
+ sme->bssid = sme->bssid_hint;
6871
+ WL_INFORM_MEM(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
6872
+ }
42666873 }
42676874 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
42686875
....@@ -4277,68 +6884,83 @@
42776884 return -EINVAL;
42786885 }
42796886
4280
- RETURN_EIO_IF_NOT_UP(cfg);
6887
+ WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
6888
+ if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
6889
+ prhex(NULL, sme->ie, sme->ie_len);
6890
+ }
42816891
6892
+ RETURN_EIO_IF_NOT_UP(cfg);
42826893 /*
42836894 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
42846895 */
4285
-#if !defined(ESCAN_RESULT_PATCH)
42866896 if (cfg->scan_request) {
4287
- wl_notify_escan_complete(cfg, dev, true, true);
6897
+ WL_TRACE_HW4(("Aborting the scan! \n"));
6898
+ wl_cfg80211_scan_abort(cfg);
6899
+ wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
6900
+ while (wl_get_drv_status(cfg, SCANNING, dev) && wait_cnt) {
6901
+ WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
6902
+ wait_cnt--;
6903
+ OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
6904
+ }
6905
+ if (wl_get_drv_status(cfg, SCANNING, dev)) {
6906
+ wl_cfg80211_cancel_scan(cfg);
6907
+ }
42886908 }
4289
-#endif
42906909 #ifdef WL_SCHED_SCAN
6910
+ /* Locks are taken in wl_cfg80211_sched_scan_stop()
6911
+ * A start scan occuring during connect is unlikely
6912
+ */
42916913 if (cfg->sched_scan_req) {
6914
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
6915
+ wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg),
6916
+ cfg->sched_scan_req->reqid);
6917
+#else
42926918 wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg));
6919
+#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(4, 11, 0) */
42936920 }
4294
-#endif
6921
+#endif /* WL_SCHED_SCAN */
6922
+#ifdef WL_CFG80211_GON_COLLISION
6923
+ /* init block gon req count */
6924
+ cfg->block_gon_req_tx_count = 0;
6925
+ cfg->block_gon_req_rx_count = 0;
6926
+#endif /* WL_CFG80211_GON_COLLISION */
42956927 #if defined(ESCAN_RESULT_PATCH)
42966928 if (sme->bssid)
42976929 memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN);
42986930 else
42996931 bzero(connect_req_bssid, ETHER_ADDR_LEN);
43006932 bzero(broad_bssid, ETHER_ADDR_LEN);
4301
-#endif
6933
+#endif // endif
43026934 #if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
43036935 maxrxpktglom = 0;
4304
-#endif
4305
- bzero(&bssid, sizeof(bssid));
4306
- if (!wl_get_drv_status(cfg, CONNECTED, dev)&&
4307
- (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) {
4308
- if (!ETHER_ISNULLADDR(&bssid)) {
4309
- scb_val_t scbval;
4310
- wl_set_drv_status(cfg, DISCONNECTING, dev);
4311
- scbval.val = DOT11_RC_DISASSOC_LEAVING;
4312
- memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN);
4313
- scbval.val = htod32(scbval.val);
4314
-
4315
- WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n",
4316
- MAC2STRDBG(bssid.octet)));
4317
- err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
4318
- sizeof(scb_val_t), true);
4319
- if (unlikely(err)) {
4320
- wl_clr_drv_status(cfg, DISCONNECTING, dev);
4321
- WL_ERR(("error (%d)\n", err));
4322
- return err;
4323
- }
4324
- wait_cnt = 500/10;
4325
- while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
4326
- WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
4327
- wait_cnt));
4328
- wait_cnt--;
4329
- OSL_SLEEP(10);
4330
- }
4331
- } else
4332
- WL_DBG(("Currently not associated!\n"));
4333
- } else {
4334
- /* if status is DISCONNECTING, wait for disconnection terminated max 500 ms */
4335
- wait_cnt = 500/10;
4336
- while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
4337
- WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt));
4338
- wait_cnt--;
4339
- OSL_SLEEP(10);
6936
+#endif // endif
6937
+ if (wl_get_drv_status(cfg, CONNECTING, dev) || wl_get_drv_status(cfg, CONNECTED, dev)) {
6938
+ /* set nested connect bit to identify the context */
6939
+ wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6940
+ /* DHD prev status is CONNECTING/CONNECTED */
6941
+ err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, TRUE);
6942
+ } else if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
6943
+ /* DHD prev status is DISCONNECTING */
6944
+ err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, false);
6945
+ } else if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
6946
+ /* DHD previous status is not connected and FW connected */
6947
+ if (wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN) == 0) {
6948
+ /* set nested connect bit to identify the context */
6949
+ wl_set_drv_status(cfg, NESTED_CONNECT, dev);
6950
+ err = wl_cfg80211_cleanup_mismatch_status(dev, cfg, true);
43406951 }
43416952 }
6953
+
6954
+ if (sme->bssid) {
6955
+ wl_update_prof(cfg, dev, NULL, sme->bssid, WL_PROF_LATEST_BSSID);
6956
+ } else {
6957
+ wl_update_prof(cfg, dev, NULL, &ether_bcast, WL_PROF_LATEST_BSSID);
6958
+ }
6959
+
6960
+ /* 'connect' request received */
6961
+ wl_set_drv_status(cfg, CONNECTING, dev);
6962
+ /* clear nested connect bit on proceeding for connection */
6963
+ wl_clr_drv_status(cfg, NESTED_CONNECT, dev);
43426964
43436965 /* Clean BSSID */
43446966 bzero(&bssid, sizeof(bssid));
....@@ -4350,94 +6972,180 @@
43506972 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
43516973 WL_ERR(("Find p2p index from wdev(%p) failed\n",
43526974 dev->ieee80211_ptr));
4353
- return BCME_ERROR;
6975
+ err = BCME_ERROR;
6976
+ goto exit;
43546977 }
43556978 wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
43566979 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
43576980 } else if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6981
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6982
+ WL_ERR(("Find wlan index from wdev(%p) failed\n", dev->ieee80211_ptr));
6983
+ err = BCME_ERROR;
6984
+ goto exit;
6985
+ }
6986
+
43586987 /* find the RSN_IE */
4359
- if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len,
6988
+ if ((wpa2_ie = bcm_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
43606989 DOT11_MNG_RSN_ID)) != NULL) {
43616990 WL_DBG((" WPA2 IE is found\n"));
43626991 }
43636992 /* find the WPA_IE */
4364
- if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie,
6993
+ if ((wpa_ie = wl_cfgp2p_find_wpaie(sme->ie,
43656994 sme->ie_len)) != NULL) {
43666995 WL_DBG((" WPA IE is found\n"));
43676996 }
4368
- if (wpa_ie != NULL || wpa2_ie != NULL) {
4369
- wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie;
6997
+#ifdef WL_SAE
6998
+ if (((wpa_ie != NULL) || (wpa2_ie != NULL))&&
6999
+ (!((FW_SUPPORTED(dhdp, sae)) && (FW_SUPPORTED(dhdp, idsup)) &&
7000
+ (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_SAE))))
7001
+#else
7002
+ if ((wpa_ie != NULL || wpa2_ie != NULL))
7003
+#endif // endif
7004
+ {
7005
+ wpaie = (wpa_ie != NULL) ? (const u8 *)wpa_ie : (const u8 *)wpa2_ie;
43707006 wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
43717007 wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
43727008 err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
4373
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
7009
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
43747010 if (unlikely(err)) {
43757011 WL_ERR(("wpaie set error (%d)\n", err));
4376
- return err;
7012
+ goto exit;
43777013 }
43787014 } else {
43797015 err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
4380
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
7016
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
43817017 if (unlikely(err)) {
43827018 WL_ERR(("wpaie set error (%d)\n", err));
4383
- return err;
7019
+ goto exit;
43847020 }
43857021 }
4386
-
4387
- if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
4388
- WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4389
- return BCME_ERROR;
4390
- }
43917022 err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
4392
- VNDR_IE_ASSOCREQ_FLAG, (const u8 *)sme->ie, sme->ie_len);
7023
+ VNDR_IE_ASSOCREQ_FLAG, (const u8 *)sme->ie, sme->ie_len);
43937024 if (unlikely(err)) {
4394
- return err;
7025
+ goto exit;
43957026 }
43967027 }
4397
- if (chan) {
4398
- /* If RCC is not enabled, use the channel provided by userspace */
4399
- cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
4400
- chan_cnt = 1;
4401
- WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel,
4402
- chan->center_freq, chan_cnt));
4403
- } else {
4404
- /*
4405
- * No channel information from user space. if RCC is enabled, the RCC
4406
- * would prepare the channel list, else no channel would be provided
4407
- * and firmware would need to do a full channel scan.
4408
- */
4409
- WL_DBG(("No channel info from user space\n"));
4410
- cfg->channel = 0;
7028
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
7029
+ if (dhdp->roam_env_detection) {
7030
+ bool is_roamtrig_reset = TRUE;
7031
+ bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection",
7032
+ AP_ENV_DETECT_NOT_USED) == BCME_OK);
7033
+#ifdef SKIP_ROAM_TRIGGER_RESET
7034
+ roam_trigger[1] = WLC_BAND_2G;
7035
+ is_roamtrig_reset =
7036
+ (wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
7037
+ sizeof(roam_trigger)) == BCME_OK) &&
7038
+ (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER-10);
7039
+#endif /* SKIP_ROAM_TRIGGER_RESET */
7040
+ if (is_roamtrig_reset && is_roam_env_ok) {
7041
+ roam_trigger[0] = WL_AUTO_ROAM_TRIGGER;
7042
+ roam_trigger[1] = WLC_BAND_ALL;
7043
+ err = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
7044
+ sizeof(roam_trigger));
7045
+ if (unlikely(err)) {
7046
+ WL_ERR((" failed to restore roam_trigger for auto env"
7047
+ " detection\n"));
7048
+ }
7049
+ }
44117050 }
4412
- WL_DBG(("3. set wapi version \n"));
7051
+#endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
7052
+ if (chan &&
7053
+#ifdef H2_BRING_UP
7054
+ FALSE &&
7055
+#endif /* H2_BRING_UP */
7056
+ TRUE) {
7057
+
7058
+ cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
7059
+ chan_cnt = 1;
7060
+ WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel,
7061
+ chan->center_freq, chan_cnt));
7062
+ } else {
7063
+ WL_DBG(("No channel info from user space\n"));
7064
+ cfg->channel = 0;
7065
+ }
7066
+#ifdef ESCAN_CHANNEL_CACHE
7067
+ /*
7068
+ * No channel information from user space. if ECC is enabled, the ECC
7069
+ * would prepare the channel list, else no channel would be provided
7070
+ * and firmware would need to do a full channel scan.
7071
+ *
7072
+ * Use cached channels. This might take slightly longer time compared
7073
+ * to using a single channel based join. But ECC would help choose
7074
+ * a better AP for a given ssid. For a given SSID there might multiple
7075
+ * APs on different channels and ECC would scan all those channels
7076
+ * before deciding up on the AP. This accounts for the additional delay.
7077
+ */
7078
+ if (cfg->rcc_enabled || cfg->channel == 0)
7079
+ {
7080
+ wlc_ssid_t ssid;
7081
+ int band;
7082
+
7083
+ err = wldev_get_band(dev, &band);
7084
+ if (!err) {
7085
+ set_roam_band(band);
7086
+ }
7087
+
7088
+ memcpy(ssid.SSID, sme->ssid, sme->ssid_len);
7089
+ ssid.SSID_len = (uint32)sme->ssid_len;
7090
+ chan_cnt = get_roam_channel_list(cfg->channel, chanspec_list,
7091
+ MAX_ROAM_CHANNEL, &ssid, ioctl_version, chan);
7092
+ WL_DBG(("RCC channel count:%d \n", chan_cnt));
7093
+ }
7094
+#endif /* ESCAN_CHANNEL_CACHE */
7095
+ WL_DBG(("3. set wpa version \n"));
7096
+
44137097 err = wl_set_wpa_version(dev, sme);
44147098 if (unlikely(err)) {
44157099 WL_ERR(("Invalid wpa_version\n"));
4416
- return err;
7100
+ goto exit;
44177101 }
7102
+#ifdef BCMWAPI_WPI
7103
+ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1)
7104
+ WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n"));
7105
+ else {
7106
+ WL_DBG(("4. wl_set_auth_type\n"));
7107
+#endif // endif
44187108 err = wl_set_auth_type(dev, sme);
44197109 if (unlikely(err)) {
44207110 WL_ERR(("Invalid auth type\n"));
4421
- return err;
7111
+ goto exit;
44227112 }
4423
-
7113
+#ifdef BCMWAPI_WPI
7114
+ }
7115
+#endif // endif
7116
+#ifdef WL_FILS
7117
+ if (sme->ie && sme->ie_len) {
7118
+ err = wl_fils_add_hlp_container(cfg, dev, sme->ie, sme->ie_len);
7119
+ if (unlikely(err)) {
7120
+ WL_ERR(("FILS sending HLP failed\n"));
7121
+ goto exit;
7122
+ }
7123
+ }
7124
+#endif /* WL_FILS */
44247125 err = wl_set_set_cipher(dev, sme);
44257126 if (unlikely(err)) {
44267127 WL_ERR(("Invalid ciper\n"));
4427
- return err;
7128
+ goto exit;
44287129 }
44297130
44307131 err = wl_set_key_mgmt(dev, sme);
44317132 if (unlikely(err)) {
44327133 WL_ERR(("Invalid key mgmt\n"));
4433
- return err;
7134
+ goto exit;
44347135 }
44357136
44367137 err = wl_set_set_sharedkey(dev, sme);
44377138 if (unlikely(err)) {
44387139 WL_ERR(("Invalid shared key\n"));
4439
- return err;
7140
+ goto exit;
44407141 }
7142
+#ifdef WL_FILS
7143
+ err = wl_set_fils_params(dev, sme);
7144
+ if (unlikely(err)) {
7145
+ WL_ERR(("Invalid FILS params\n"));
7146
+ goto exit;
7147
+ }
7148
+#endif /* WL_FILS */
44417149
44427150 /*
44437151 * Join with specific BSSID and cached SSID
....@@ -4445,21 +7153,38 @@
44457153 */
44467154 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
44477155 chan_cnt * sizeof(chanspec_t);
4448
- ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
7156
+ ext_join_params = (wl_extjoin_params_t *)MALLOCZ(cfg->osh, join_params_size);
44497157 if (ext_join_params == NULL) {
44507158 err = -ENOMEM;
44517159 wl_clr_drv_status(cfg, CONNECTING, dev);
44527160 goto exit;
44537161 }
4454
- ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
7162
+ ext_join_params->ssid.SSID_len =
7163
+ (uint32)min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
44557164 memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
44567165 wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
44577166 ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
44587167 /* increate dwell time to receive probe response or detect Beacon
44597168 * from target AP at a noisy air only during connect command
44607169 */
7170
+#ifdef WL_6E
7171
+ /* If chan is NULL in case of fw_ap_select=1
7172
+ * avoiding dereferencing chan->center_freq */
7173
+ if (chan && chan->center_freq > FREQ_START_6G_CHANNEL) {
7174
+ ext_join_params->scan.active_time = chan_cnt ?
7175
+ WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS_6E : -1;
7176
+ ext_join_params->scan.passive_time = chan_cnt ?
7177
+ WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS_6E : -1;
7178
+ } else {
7179
+ ext_join_params->scan.active_time = chan_cnt ?
7180
+ WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
7181
+ ext_join_params->scan.passive_time = chan_cnt ?
7182
+ WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
7183
+ }
7184
+#else
44617185 ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
44627186 ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
7187
+#endif /* WL_6E */
44637188 /* Set up join scan parameters */
44647189 ext_join_params->scan.scan_type = -1;
44657190 ext_join_params->scan.nprobes = chan_cnt ?
....@@ -4471,7 +7196,8 @@
44717196 else
44727197 memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
44737198 ext_join_params->assoc.chanspec_num = chan_cnt;
4474
- if (chan_cnt) {
7199
+
7200
+ if (chan_cnt && !cfg->rcc_enabled) {
44757201 if (cfg->channel) {
44767202 /*
44777203 * Use the channel provided by userspace
....@@ -4483,11 +7209,12 @@
44837209 : WL_CHANSPEC_BAND_5G;
44847210
44857211 /* Get min_bw set for the interface */
4486
- bw = wl_cfg80211_ulb_get_min_bw_chspec(dev->ieee80211_ptr, bssidx);
7212
+ bw = WL_CHANSPEC_BW_20;
44877213 if (bw == INVCHANSPEC) {
44887214 WL_ERR(("Invalid chanspec \n"));
4489
- kfree(ext_join_params);
4490
- return BCME_ERROR;
7215
+ MFREE(cfg->osh, ext_join_params, join_params_size);
7216
+ err = BCME_ERROR;
7217
+ goto exit;
44917218 }
44927219
44937220 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
....@@ -4498,49 +7225,88 @@
44987225 wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]);
44997226 }
45007227 }
7228
+#ifdef ESCAN_CHANNEL_CACHE
7229
+ else {
7230
+ memcpy(ext_join_params->assoc.chanspec_list, chanspec_list,
7231
+ sizeof(chanspec_t) * chan_cnt);
7232
+ }
7233
+#endif /* ESCAN_CHANNEL_CACHE */
45017234 ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
45027235 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
4503
- WL_INFORM(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
7236
+ WL_DBG(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
45047237 ext_join_params->ssid.SSID_len));
45057238 }
4506
- wl_set_drv_status(cfg, CONNECTING, dev);
45077239
45087240 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
45097241 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
4510
- kfree(ext_join_params);
4511
- return BCME_ERROR;
7242
+ MFREE(cfg->osh, ext_join_params, join_params_size);
7243
+ err = BCME_ERROR;
7244
+ goto exit;
45127245 }
7246
+#ifdef DHD_EVENT_LOG_FILTER
7247
+ if (dev == bcmcfg_to_prmry_ndev(cfg)) {
7248
+ /* inform only for STA Interface */
7249
+ dhd_event_log_filter_notify_connect_request(dhdp,
7250
+ (uint8 *)(&ext_join_params->assoc.bssid), cfg->channel);
7251
+ }
7252
+#endif /* DHD_EVENT_LOG_FILTER */
7253
+#ifdef WLTDLS
7254
+ /* disable TDLS if number of connected interfaces is >= 1 */
7255
+ wl_cfg80211_tdls_config(cfg, TDLS_STATE_CONNECT, false);
7256
+#endif /* WLTDLS */
45137257 err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
45147258 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
4515
-
45167259 if (cfg->rcc_enabled) {
4517
- WL_ERR(("Connecting with" MACDBG " ssid \"%s\", len (%d) with rcc channels \n\n",
4518
- MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
4519
- ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len));
7260
+ WL_ERR_KERN(("[%s] Connecting with " MACDBG " ssid \"%s\","
7261
+ " len (%d) with rcc channels. chan_cnt:%d \n\n",
7262
+ dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
7263
+ ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, chan_cnt));
7264
+ WL_INFORM_MEM(("[%s] Connecting with " MACDBG " ssid \"%s\","
7265
+ " len (%d) with rcc channels. chan_cnt:%d \n\n",
7266
+ dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
7267
+ "*****", ext_join_params->ssid.SSID_len, chan_cnt));
45207268 } else {
4521
- WL_ERR(("Connecting with" MACDBG " ssid \"%s\", len (%d) channel=%d\n\n",
4522
- MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
7269
+ WL_ERR_KERN(("[%s] Connecting with " MACDBG " ssid \"%s\","
7270
+ " len (%d) channels:%d \n\n",
7271
+ dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
45237272 ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, cfg->channel));
7273
+ WL_INFORM_MEM(("[%s] Connecting with " MACDBG " ssid \"%s\","
7274
+ " len (%d) channels:%d \n\n",
7275
+ dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
7276
+ "*****", ext_join_params->ssid.SSID_len, cfg->channel));
45247277 }
4525
-
4526
- kfree(ext_join_params);
7278
+ SUPP_LOG(("[%s] Connecting with " MACDBG " ssid \"%s\","
7279
+ "channel:%d rcc:%d\n",
7280
+ dev->name, MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
7281
+ ext_join_params->ssid.SSID, cfg->channel, cfg->rcc_enabled));
7282
+ MFREE(cfg->osh, ext_join_params, join_params_size);
45277283 if (err) {
45287284 wl_clr_drv_status(cfg, CONNECTING, dev);
45297285 if (err == BCME_UNSUPPORTED) {
45307286 WL_DBG(("join iovar is not supported\n"));
45317287 goto set_ssid;
45327288 } else {
4533
- WL_ERR(("error (%d)\n", err));
7289
+ WL_ERR(("join iovar error (%d)\n", err));
45347290 goto exit;
45357291 }
45367292 } else
45377293 goto exit;
45387294
45397295 set_ssid:
4540
- memset(&join_params, 0, sizeof(join_params));
7296
+#if defined(ROAMEXP_SUPPORT)
7297
+ /* Clear Blacklist bssid and Whitelist ssid list before join issue
7298
+ * This is temporary fix since currently firmware roaming is not
7299
+ * disabled by android framework before SSID join from framework
7300
+ */
7301
+ /* Flush blacklist bssid content */
7302
+ dhd_dev_set_blacklist_bssid(dev, NULL, 0, true);
7303
+ /* Flush whitelist ssid content */
7304
+ dhd_dev_set_whitelist_ssid(dev, NULL, 0, true);
7305
+#endif /* ROAMEXP_SUPPORT */
7306
+ bzero(&join_params, sizeof(join_params));
45417307 join_params_size = sizeof(join_params.ssid);
45427308
4543
- join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
7309
+ join_params.ssid.SSID_len = (uint32)min(sizeof(join_params.ssid.SSID), sme->ssid_len);
45447310 memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
45457311 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
45467312 wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
....@@ -4549,7 +7315,8 @@
45497315 else
45507316 memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
45517317
4552
- if (wl_ch_to_chanspec(dev, cfg->channel, &join_params, &join_params_size) < 0) {
7318
+ if (wl_ch_to_chanspec(dev, cfg->channel, &join_params, &join_params_size,
7319
+ chan) < 0) {
45537320 WL_ERR(("Invalid chanspec\n"));
45547321 return -EINVAL;
45557322 }
....@@ -4557,17 +7324,79 @@
45577324 WL_DBG(("join_param_size %zu\n", join_params_size));
45587325
45597326 if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
4560
- WL_INFORM(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
7327
+ WL_INFORM_MEM(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
45617328 join_params.ssid.SSID_len));
45627329 }
4563
- wl_set_drv_status(cfg, CONNECTING, dev);
4564
- err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
7330
+ err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params, join_params_size);
7331
+exit:
45657332 if (err) {
45667333 WL_ERR(("error (%d)\n", err));
45677334 wl_clr_drv_status(cfg, CONNECTING, dev);
7335
+ wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
7336
+#ifdef WLTDLS
7337
+ /* If connect fails, check whether we can enable back TDLS */
7338
+ wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
7339
+#endif /* WLTDLS */
45687340 }
4569
-exit:
7341
+#ifdef DBG_PKT_MON
7342
+ if ((dev == bcmcfg_to_prmry_ndev(cfg)) && !err) {
7343
+ DHD_DBG_PKT_MON_START(dhdp);
7344
+ }
7345
+#endif /* DBG_PKT_MON */
45707346 return err;
7347
+}
7348
+
7349
+static void wl_cfg80211_disconnect_state_sync(struct bcm_cfg80211 *cfg, struct net_device *dev)
7350
+{
7351
+ struct wireless_dev *wdev;
7352
+ uint8 wait_cnt;
7353
+
7354
+ if (!dev || !dev->ieee80211_ptr) {
7355
+ WL_ERR(("wrong ndev\n"));
7356
+ return;
7357
+ }
7358
+
7359
+ wdev = dev->ieee80211_ptr;
7360
+ wait_cnt = WAIT_FOR_DISCONNECT_STATE_SYNC;
7361
+ while ((wdev->current_bss) && wait_cnt) {
7362
+ WL_DBG(("Waiting for disconnect sync, wait_cnt: %d\n", wait_cnt));
7363
+ wait_cnt--;
7364
+ OSL_SLEEP(50);
7365
+ }
7366
+
7367
+ if (wait_cnt == 0) {
7368
+ /* state didn't get cleared within given timeout */
7369
+ WL_INFORM_MEM(("cfg80211 state. wdev->current_bss non null\n"));
7370
+ } else {
7371
+ WL_MEM(("cfg80211 disconnect state sync done\n"));
7372
+ }
7373
+
7374
+}
7375
+
7376
+static void wl_cfg80211_wait_for_disconnection(struct bcm_cfg80211 *cfg, struct net_device *dev)
7377
+{
7378
+ uint8 wait_cnt;
7379
+ u32 status = 0;
7380
+
7381
+ wait_cnt = WAIT_FOR_DISCONNECT_MAX;
7382
+ while ((status = wl_get_drv_status(cfg, DISCONNECTING, dev)) && wait_cnt) {
7383
+ WL_DBG(("Waiting for disconnection, wait_cnt: %d\n", wait_cnt));
7384
+ wait_cnt--;
7385
+ OSL_SLEEP(50);
7386
+ }
7387
+
7388
+ WL_INFORM_MEM(("Wait for disconnection done. status:%d wait_cnt:%d\n", status, wait_cnt));
7389
+ if (!wait_cnt && wl_get_drv_status(cfg, DISCONNECTING, dev)) {
7390
+ /* No response from firmware. Indicate connect result
7391
+ * to clear cfg80211 state machine
7392
+ */
7393
+ WL_INFORM_MEM(("force send connect result\n"));
7394
+ CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
7395
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
7396
+ GFP_KERNEL);
7397
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
7398
+ }
7399
+ return;
45717400 }
45727401
45737402 static s32
....@@ -4578,57 +7407,112 @@
45787407 scb_val_t scbval;
45797408 bool act = false;
45807409 s32 err = 0;
4581
- u8 *curbssid;
4582
-#ifdef CUSTOM_SET_CPUCORE
4583
- dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
4584
-#endif /* CUSTOM_SET_CPUCORE */
7410
+ u8 *curbssid = NULL;
7411
+ u8 null_bssid[ETHER_ADDR_LEN];
7412
+ s32 bssidx = 0;
7413
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
45857414 WL_ERR(("Reason %d\n", reason_code));
45867415 RETURN_EIO_IF_NOT_UP(cfg);
45877416 act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
45887417 curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
7418
+
7419
+ BCM_REFERENCE(dhdp);
7420
+ DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_START),
7421
+ dhd_net2idx(dhdp->info, dev), reason_code);
7422
+#ifdef DHD_4WAYM4_FAIL_DISCONNECT
7423
+ dhd_cleanup_m4_state_work(dhdp, dhd_net2idx(dhdp->info, dev));
7424
+#endif /* DHD_4WAYM4_FAIL_DISCONNECT */
7425
+
45897426 #ifdef ESCAN_RESULT_PATCH
4590
- if (wl_get_drv_status(cfg, CONNECTING, dev) && curbssid &&
4591
- (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0)) {
4592
- WL_ERR(("Disconnecting from connecting device: " MACDBG "\n",
4593
- MAC2STRDBG(curbssid)));
7427
+ if (wl_get_drv_status(cfg, CONNECTING, dev)) {
7428
+ if (curbssid) {
7429
+ WL_ERR(("Disconnecting while CONNECTING status"
7430
+ " connecting device: " MACDBG "\n", MAC2STRDBG(curbssid)));
7431
+ } else {
7432
+ WL_ERR(("Disconnecting while CONNECTING status \n"));
7433
+ }
45947434 act = true;
45957435 }
45967436 #endif /* ESCAN_RESULT_PATCH */
7437
+
7438
+ if (!curbssid) {
7439
+ WL_ERR(("Disconnecting while CONNECTING status %d\n", (int)sizeof(null_bssid)));
7440
+ bzero(null_bssid, sizeof(null_bssid));
7441
+ curbssid = null_bssid;
7442
+ }
7443
+
45977444 if (act) {
7445
+#ifdef DBG_PKT_MON
7446
+ /* Stop packet monitor */
7447
+ if (dev == bcmcfg_to_prmry_ndev(cfg)) {
7448
+ DHD_DBG_PKT_MON_STOP(dhdp);
7449
+ }
7450
+#endif /* DBG_PKT_MON */
45987451 /*
45997452 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
46007453 */
4601
-#if !defined(ESCAN_RESULT_PATCH)
46027454 /* Let scan aborted by F/W */
46037455 if (cfg->scan_request) {
4604
- wl_notify_escan_complete(cfg, dev, true, true);
7456
+ WL_TRACE_HW4(("Aborting the scan! \n"));
7457
+ wl_cfg80211_cancel_scan(cfg);
46057458 }
4606
-#endif /* ESCAN_RESULT_PATCH */
7459
+ /* Set DISCONNECTING state. We are clearing this state in all exit paths */
46077460 wl_set_drv_status(cfg, DISCONNECTING, dev);
4608
- scbval.val = reason_code;
4609
- memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
4610
- scbval.val = htod32(scbval.val);
4611
- err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
4612
- sizeof(scb_val_t), true);
4613
- if (unlikely(err)) {
4614
- wl_clr_drv_status(cfg, DISCONNECTING, dev);
4615
- WL_ERR(("error (%d)\n", err));
4616
- return err;
7461
+ if (wl_get_drv_status(cfg, CONNECTING, dev) ||
7462
+ wl_get_drv_status(cfg, CONNECTED, dev)) {
7463
+ scbval.val = reason_code;
7464
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
7465
+ scbval.val = htod32(scbval.val);
7466
+ WL_INFORM_MEM(("[%s] wl disassoc\n", dev->name));
7467
+ err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
7468
+ sizeof(scb_val_t));
7469
+ if (unlikely(err)) {
7470
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
7471
+ WL_ERR(("error (%d)\n", err));
7472
+ goto exit;
7473
+ }
46177474 }
7475
+#ifdef WL_WPS_SYNC
7476
+ /* If are in WPS reauth state, then we would be
7477
+ * dropping the link down events. Ensure that
7478
+ * Event is sent up for the disconnect Req
7479
+ */
7480
+ if (wl_wps_session_update(dev,
7481
+ WPS_STATE_DISCONNECT, curbssid) == BCME_OK) {
7482
+ WL_INFORM_MEM(("[WPS] Disconnect done.\n"));
7483
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
7484
+ }
7485
+#endif /* WPS_SYNC */
7486
+ wl_cfg80211_wait_for_disconnection(cfg, dev);
7487
+ } else {
7488
+ /* Not in connecting or connected state. However since disconnect came
7489
+ * from upper layer, indicate connect fail to clear any state mismatch
7490
+ */
7491
+ WL_INFORM_MEM(("act is false. report connect result fail.\n"));
7492
+ CFG80211_CONNECT_RESULT(dev, NULL, NULL, NULL, 0, NULL, 0,
7493
+ WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
46187494 }
46197495 #ifdef CUSTOM_SET_CPUCORE
46207496 /* set default cpucore */
46217497 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
4622
- dhd->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
4623
- if (!(dhd->chan_isvht80))
4624
- dhd_set_cpucore(dhd, FALSE);
7498
+ dhdp->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
7499
+ if (!(dhdp->chan_isvht80))
7500
+ dhd_set_cpucore(dhdp, FALSE);
46257501 }
46267502 #endif /* CUSTOM_SET_CPUCORE */
46277503
4628
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
4629
- /* cfg80211 expects disconnect event from DHD to release wdev->current_bss */
4630
- CFG80211_DISCONNECTED(dev, reason_code, NULL, 0, false, GFP_KERNEL);
4631
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
7504
+ cfg->rssi = 0; /* reset backup of rssi */
7505
+
7506
+exit:
7507
+ /* Clear IEs for disaasoc */
7508
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7509
+ WL_ERR(("Find index failed\n"));
7510
+ err = -EINVAL;
7511
+ return err;
7512
+ }
7513
+ WL_ERR(("Clearing disconnect IEs \n"));
7514
+ err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
7515
+ ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, NULL, 0);
46327516
46337517 return err;
46347518 }
....@@ -4728,8 +7612,8 @@
47287612 /* Just select a new current key */
47297613 index = (u32) key_idx;
47307614 index = htod32(index);
4731
- err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index,
4732
- sizeof(index), true);
7615
+ err = wldev_ioctl_set(dev, WLC_SET_KEY_PRIMARY, &index,
7616
+ sizeof(index));
47337617 if (unlikely(err)) {
47347618 WL_ERR(("error (%d)\n", err));
47357619 }
....@@ -4747,11 +7631,12 @@
47477631 s32 bssidx;
47487632 s32 mode = wl_get_mode_by_netdev(cfg, dev);
47497633
7634
+ WL_ERR(("key index (%d)\n", key_idx));
47507635 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
47517636 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
47527637 return BCME_ERROR;
47537638 }
4754
- memset(&key, 0, sizeof(key));
7639
+ bzero(&key, sizeof(key));
47557640 key.index = (u32) key_idx;
47567641
47577642 if (!ETHER_ISMULTI(mac_addr))
....@@ -4787,36 +7672,15 @@
47877672 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
47887673 if (params->seq && params->seq_len == 6) {
47897674 /* rx iv */
4790
- u8 *ivptr;
4791
- ivptr = (u8 *) params->seq;
7675
+ const u8 *ivptr;
7676
+ ivptr = (const u8 *) params->seq;
47927677 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
47937678 (ivptr[3] << 8) | ivptr[2];
47947679 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
47957680 key.iv_initialized = true;
47967681 }
4797
-
4798
- switch (params->cipher) {
4799
- case WLAN_CIPHER_SUITE_WEP40:
4800
- key.algo = CRYPTO_ALGO_WEP1;
4801
- WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
4802
- break;
4803
- case WLAN_CIPHER_SUITE_WEP104:
4804
- key.algo = CRYPTO_ALGO_WEP128;
4805
- WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
4806
- break;
4807
- case WLAN_CIPHER_SUITE_TKIP:
4808
- key.algo = CRYPTO_ALGO_TKIP;
4809
- WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
4810
- break;
4811
- case WLAN_CIPHER_SUITE_AES_CMAC:
4812
- key.algo = CRYPTO_ALGO_AES_CCM;
4813
- WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
4814
- break;
4815
- case WLAN_CIPHER_SUITE_CCMP:
4816
- key.algo = CRYPTO_ALGO_AES_CCM;
4817
- WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
4818
- break;
4819
- default:
7682
+ key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7683
+ if (key.algo == CRYPTO_ALGO_OFF) { //not found.
48207684 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
48217685 return -EINVAL;
48227686 }
....@@ -4829,6 +7693,7 @@
48297693 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
48307694 return err;
48317695 }
7696
+ WL_INFORM_MEM(("[%s] wsec key set\n", dev->name));
48327697 }
48337698 return err;
48347699 }
....@@ -4838,11 +7703,14 @@
48387703 {
48397704 int err;
48407705 wl_eventmsg_buf_t ev_buf;
7706
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
48417707
4842
- if (dev != bcmcfg_to_prmry_ndev(g_bcm_cfg)) {
7708
+ if (dev != bcmcfg_to_prmry_ndev(cfg)) {
48437709 /* roam offload is only for the primary device */
48447710 return -1;
48457711 }
7712
+
7713
+ WL_INFORM_MEM(("[%s] wl roam_offload %d\n", dev->name, enable));
48467714 err = wldev_iovar_setint(dev, "roam_offload", enable);
48477715 if (err)
48487716 return err;
....@@ -4854,56 +7722,79 @@
48547722 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
48557723 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
48567724 wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
4857
- err = wl_cfg80211_apply_eventbuffer(dev, g_bcm_cfg, &ev_buf);
7725
+ err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
48587726 if (!err) {
4859
- g_bcm_cfg->roam_offload = enable;
7727
+ cfg->roam_offload = enable;
48607728 }
48617729 return err;
48627730 }
48637731
4864
-#if defined(WL_VIRTUAL_APSTA)
4865
-int
4866
-wl_cfg80211_interface_create(struct net_device *dev, char *name)
7732
+struct wireless_dev *
7733
+wl_cfg80211_get_wdev_from_ifname(struct bcm_cfg80211 *cfg, const char *name)
48677734 {
4868
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
4869
- bcm_struct_cfgdev *new_cfgdev;
4870
-
4871
- new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
4872
- NL80211_IFTYPE_STATION, NULL, name);
4873
- if (!new_cfgdev) {
4874
- return BCME_ERROR;
4875
- }
4876
- else {
4877
- WL_DBG(("Iface %s created successfuly\n", name));
4878
- return BCME_OK;
4879
- }
4880
-}
4881
-
4882
-int
4883
-wl_cfg80211_interface_delete(struct net_device *dev, char *name)
4884
-{
4885
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
48867735 struct net_info *iter, *next;
4887
- int err = BCME_ERROR;
48887736
48897737 if (name == NULL) {
4890
- return BCME_ERROR;
7738
+ WL_ERR(("Iface name is not provided\n"));
7739
+ return NULL;
48917740 }
48927741
7742
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
48937743 for_each_ndev(cfg, iter, next) {
7744
+ GCC_DIAGNOSTIC_POP();
48947745 if (iter->ndev) {
48957746 if (strcmp(iter->ndev->name, name) == 0) {
4896
- err = wl_cfg80211_del_iface(cfg->wdev->wiphy, cfg->bss_cfgdev);
4897
- break;
7747
+ return iter->ndev->ieee80211_ptr;
48987748 }
48997749 }
49007750 }
4901
- if (!err) {
4902
- WL_DBG(("Iface %s deleted successfuly", name));
4903
- }
4904
- return err;
7751
+
7752
+ WL_DBG(("Iface %s not found\n", name));
7753
+ return NULL;
49057754 }
4906
-#endif /* defined (WL_VIRTUAL_APSTA) */
7755
+
7756
+#if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
7757
+void
7758
+wl_cfg80211_block_arp(struct net_device *dev, int enable)
7759
+{
7760
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7761
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7762
+
7763
+ WL_INFORM_MEM(("[%s] Enter. enable:%d\n", dev->name, enable));
7764
+ if (!dhd_pkt_filter_enable) {
7765
+ WL_DBG(("Packet filter isn't enabled\n"));
7766
+ return;
7767
+ }
7768
+
7769
+ /* Block/Unblock ARP frames only if STA is connected to
7770
+ * the upstream AP in case of STA+SoftAP Concurrenct mode
7771
+ */
7772
+ if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
7773
+ WL_DBG(("STA not connected to upstream AP\n"));
7774
+ return;
7775
+ }
7776
+
7777
+ if (enable) {
7778
+ WL_DBG(("Enable ARP Filter\n"));
7779
+ /* Add ARP filter */
7780
+ dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
7781
+
7782
+ /* Enable ARP packet filter - blacklist */
7783
+ dhd_master_mode = FALSE;
7784
+ dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7785
+ TRUE, dhd_master_mode);
7786
+ } else {
7787
+ WL_DBG(("Disable ARP Filter\n"));
7788
+ /* Disable ARP packet filter */
7789
+ dhd_master_mode = TRUE;
7790
+ dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
7791
+ FALSE, dhd_master_mode);
7792
+
7793
+ /* Delete ARP filter */
7794
+ dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
7795
+ }
7796
+}
7797
+#endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
49077798
49087799 static s32
49097800 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
....@@ -4918,7 +7809,20 @@
49187809 s32 bssidx = 0;
49197810 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
49207811 s32 mode = wl_get_mode_by_netdev(cfg, dev);
4921
- WL_DBG(("key index (%d)\n", key_idx));
7812
+#ifdef WL_GCMP
7813
+ uint32 algos = 0, mask = 0;
7814
+#endif /* WL_GCMP */
7815
+#if defined(WLAN_CIPHER_SUITE_PMK)
7816
+ int j;
7817
+ wsec_pmk_t pmk;
7818
+ char keystring[WSEC_MAX_PSK_LEN + 1];
7819
+ char* charptr = keystring;
7820
+ u16 len;
7821
+ struct wl_security *sec;
7822
+#endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7823
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7824
+
7825
+ WL_INFORM_MEM(("key index (%d) (0x%x)\n", key_idx, params->cipher));
49227826 RETURN_EIO_IF_NOT_UP(cfg);
49237827
49247828 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
....@@ -4932,9 +7836,13 @@
49327836 wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
49337837 goto exit;
49347838 }
4935
- memset(&key, 0, sizeof(key));
7839
+
7840
+ BCM_REFERENCE(dhdp);
7841
+ DHD_STATLOG_CTRL(dhdp, ST(INSTALL_KEY), dhd_net2idx(dhdp->info, dev), 0);
7842
+
7843
+ bzero(&key, sizeof(key));
49367844 /* Clear any buffered wep key */
4937
- memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
7845
+ bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
49387846
49397847 key.len = (u32) params->key_len;
49407848 key.index = (u32) key_idx;
....@@ -4946,20 +7854,23 @@
49467854 memcpy(key.data, params->key, key.len);
49477855
49487856 key.flags = WL_PRIMARY_KEY;
7857
+
7858
+ key.algo = wl_rsn_cipher_wsec_key_algo_lookup(params->cipher);
7859
+ val = wl_rsn_cipher_wsec_algo_lookup(params->cipher);
7860
+ if (val == WSEC_NONE) {
7861
+ WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
7862
+#if defined(WLAN_CIPHER_SUITE_PMK)
7863
+ /* WLAN_CIPHER_SUITE_PMK is not NL80211 standard ,but BRCM proprietary cipher suite.
7864
+ * so it doesn't have right algo type too. Just for now, bypass this check for
7865
+ * backward compatibility.
7866
+ * TODO: deprecate this proprietary way and replace to nl80211 set_pmk API.
7867
+ */
7868
+ if (params->cipher != WLAN_CIPHER_SUITE_PMK)
7869
+#endif /* defined(WLAN_CIPHER_SUITE_PMK) */
7870
+ return -EINVAL;
7871
+ }
49497872 switch (params->cipher) {
4950
- case WLAN_CIPHER_SUITE_WEP40:
4951
- key.algo = CRYPTO_ALGO_WEP1;
4952
- val = WEP_ENABLED;
4953
- WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
4954
- break;
4955
- case WLAN_CIPHER_SUITE_WEP104:
4956
- key.algo = CRYPTO_ALGO_WEP128;
4957
- val = WEP_ENABLED;
4958
- WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
4959
- break;
49607873 case WLAN_CIPHER_SUITE_TKIP:
4961
- key.algo = CRYPTO_ALGO_TKIP;
4962
- val = TKIP_ENABLED;
49637874 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
49647875 if (mode == WL_MODE_BSS) {
49657876 bcopy(&key.data[24], keybuf, sizeof(keybuf));
....@@ -4968,50 +7879,55 @@
49687879 }
49697880 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
49707881 break;
4971
- case WLAN_CIPHER_SUITE_AES_CMAC:
4972
- key.algo = CRYPTO_ALGO_AES_CCM;
4973
- val = AES_ENABLED;
4974
- WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
4975
- break;
4976
- case WLAN_CIPHER_SUITE_CCMP:
4977
- key.algo = CRYPTO_ALGO_AES_CCM;
4978
- val = AES_ENABLED;
4979
- WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
4980
- break;
4981
-#if defined(WLFBT) && defined(WLAN_CIPHER_SUITE_PMK)
4982
- case WLAN_CIPHER_SUITE_PMK: {
4983
- int j;
4984
- wsec_pmk_t pmk;
4985
- char keystring[WSEC_MAX_PSK_LEN + 1];
4986
- char* charptr = keystring;
4987
- uint len;
4988
- struct wl_security *sec;
4989
-
7882
+#if defined(WLAN_CIPHER_SUITE_PMK)
7883
+ case WLAN_CIPHER_SUITE_PMK:
49907884 sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
4991
- if (sec->wpa_auth == WLAN_AKM_SUITE_8021X) {
4992
- err = wldev_iovar_setbuf(dev, "okc_info_pmk", (void *)params->key,
7885
+
7886
+ WL_MEM(("set_pmk: wpa_auth:%x akm:%x\n", sec->wpa_auth, params->cipher));
7887
+ /* Avoid pmk set for SAE and OWE for external supplicant case. */
7888
+ if (IS_AKM_SAE(sec->wpa_auth) || IS_AKM_OWE(sec->wpa_auth)) {
7889
+ WL_INFORM_MEM(("skip pmk set for akm:%x\n", sec->wpa_auth));
7890
+ break;
7891
+ }
7892
+
7893
+ if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
7894
+ (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
7895
+ err = wldev_iovar_setbuf(dev, "okc_info_pmk", (const void *)params->key,
49937896 WSEC_MAX_PSK_LEN / 2, keystring, sizeof(keystring), NULL);
49947897 if (err) {
49957898 /* could fail in case that 'okc' is not supported */
4996
- WL_INFORM(("Setting 'okc_info_pmk' failed, err=%d\n", err));
7899
+ WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", err));
49977900 }
49987901 }
49997902 /* copy the raw hex key to the appropriate format */
50007903 for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) {
50017904 charptr += snprintf(charptr, sizeof(keystring), "%02x", params->key[j]);
50027905 }
5003
- len = strlen(keystring);
7906
+ len = (u16)strlen(keystring);
50047907 pmk.key_len = htod16(len);
50057908 bcopy(keystring, pmk.key, len);
50067909 pmk.flags = htod16(WSEC_PASSPHRASE);
5007
- err = wldev_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk), true);
5008
- if (err)
7910
+
7911
+ err = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
7912
+ if (err) {
50097913 return err;
5010
- } break;
5011
-#endif /* WLFBT && WLAN_CIPHER_SUITE_PMK */
5012
- default:
5013
- WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
5014
- return -EINVAL;
7914
+ }
7915
+ /* Clear key length to delete key */
7916
+ key.len = 0;
7917
+ break;
7918
+#endif /* WLAN_CIPHER_SUITE_PMK */
7919
+#ifdef WL_GCMP
7920
+ case WLAN_CIPHER_SUITE_GCMP:
7921
+ case WLAN_CIPHER_SUITE_GCMP_256:
7922
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
7923
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
7924
+ algos = KEY_ALGO_MASK(key.algo);
7925
+ mask = algos | KEY_ALGO_MASK(CRYPTO_ALGO_AES_CCM);
7926
+ break;
7927
+#endif /* WL_GCMP */
7928
+ default: /* No post processing required */
7929
+ WL_DBG(("no post processing required (0x%x)\n", params->cipher));
7930
+ break;
50157931 }
50167932
50177933 /* Set the new key/index */
....@@ -5053,7 +7969,11 @@
50537969 WL_ERR(("set wsec error (%d)\n", err));
50547970 return err;
50557971 }
5056
-
7972
+#ifdef WL_GCMP
7973
+ if (wl_set_wsec_info_algos(dev, algos, mask)) {
7974
+ WL_ERR(("set wsec_info error (%d)\n", err));
7975
+ }
7976
+#endif /* WL_GCMP */
50577977 return err;
50587978 }
50597979
....@@ -5065,6 +7985,7 @@
50657985 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
50667986 s32 err = 0;
50677987 s32 bssidx;
7988
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
50687989
50697990 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
50707991 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
....@@ -5075,10 +7996,12 @@
50757996 #ifndef MFP
50767997 if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
50777998 return -EINVAL;
5078
-#endif
7999
+#endif // endif
50798000
50808001 RETURN_EIO_IF_NOT_UP(cfg);
5081
- memset(&key, 0, sizeof(key));
8002
+ BCM_REFERENCE(dhdp);
8003
+ DHD_STATLOG_CTRL(dhdp, ST(DELETE_KEY), dhd_net2idx(dhdp->info, dev), 0);
8004
+ bzero(&key, sizeof(key));
50828005
50838006 key.flags = WL_PRIMARY_KEY;
50848007 key.algo = CRYPTO_ALGO_OFF;
....@@ -5103,6 +8026,7 @@
51038026 return err;
51048027 }
51058028
8029
+/* NOTE : this function cannot work as is and is never called */
51068030 static s32
51078031 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
51088032 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
....@@ -5122,12 +8046,12 @@
51228046 }
51238047 WL_DBG(("key index (%d)\n", key_idx));
51248048 RETURN_EIO_IF_NOT_UP(cfg);
5125
- memset(&key, 0, sizeof(key));
8049
+ bzero(&key, sizeof(key));
51268050 key.index = key_idx;
51278051 swap_key_to_BE(&key);
5128
- memset(&params, 0, sizeof(params));
8052
+ bzero(&params, sizeof(params));
51298053 params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
5130
- memcpy((void *)params.key, key.data, params.key_len);
8054
+ params.key = key.data;
51318055
51328056 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
51338057 if (unlikely(err)) {
....@@ -5153,6 +8077,19 @@
51538077 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
51548078 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
51558079 break;
8080
+#ifdef BCMWAPI_WPI
8081
+ case SMS4_ENABLED:
8082
+ params.cipher = WLAN_CIPHER_SUITE_SMS4;
8083
+ WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
8084
+ break;
8085
+#endif // endif
8086
+#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
8087
+ /* to connect to mixed mode AP */
8088
+ case (AES_ENABLED | TKIP_ENABLED): /* TKIP CCMP */
8089
+ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
8090
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
8091
+ break;
8092
+#endif // endif
51568093 default:
51578094 WL_ERR(("Invalid algo (0x%x)\n", wsec));
51588095 return -EINVAL;
....@@ -5169,165 +8106,529 @@
51698106 #ifdef MFP
51708107 return 0;
51718108 #else
5172
- WL_INFORM(("Not supported\n"));
8109
+ WL_INFORM_MEM(("Not supported\n"));
51738110 return -EOPNOTSUPP;
51748111 #endif /* MFP */
51758112 }
51768113
5177
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
5178
-static s32
5179
-wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
5180
- const u8 *mac, struct station_info *sinfo)
5181
-#else
5182
-static s32
5183
-wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
5184
- u8 *mac, struct station_info *sinfo)
5185
-#endif
8114
+static bool
8115
+wl_check_assoc_state(struct bcm_cfg80211 *cfg, struct net_device *dev)
51868116 {
5187
- struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8117
+ wl_assoc_info_t asinfo;
8118
+ uint32 state = 0;
8119
+ int err;
8120
+
8121
+ err = wldev_iovar_getbuf_bsscfg(dev, "assoc_info",
8122
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
8123
+ if (unlikely(err)) {
8124
+ WL_ERR(("failed to get assoc_info : err=%d\n", err));
8125
+ return FALSE;
8126
+ } else {
8127
+ memcpy(&asinfo, cfg->ioctl_buf, sizeof(wl_assoc_info_t));
8128
+ state = dtoh32(asinfo.state);
8129
+ WL_DBG(("assoc state=%d\n", state));
8130
+ }
8131
+
8132
+ return (state > 0)? TRUE:FALSE;
8133
+}
8134
+
8135
+static s32
8136
+wl_cfg80211_get_rssi(struct net_device *dev, struct bcm_cfg80211 *cfg, s32 *rssi)
8137
+{
8138
+ s32 err = BCME_OK;
51888139 scb_val_t scb_val;
5189
- s32 rssi;
5190
- s32 rate;
5191
- s32 err = 0;
5192
- sta_info_t *sta;
5193
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
5194
- s8 eabuf[ETHER_ADDR_STR_LEN];
5195
-#endif
5196
- dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
5197
- RETURN_EIO_IF_NOT_UP(cfg);
5198
- if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
5199
- err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
5200
- ETHER_ADDR_LEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
5201
- if (err < 0) {
5202
- WL_ERR(("GET STA INFO failed, %d\n", err));
5203
- return err;
5204
- }
5205
- sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
5206
- sta = (sta_info_t *)cfg->ioctl_buf;
5207
- sta->len = dtoh16(sta->len);
5208
- sta->cap = dtoh16(sta->cap);
5209
- sta->flags = dtoh32(sta->flags);
5210
- sta->idle = dtoh32(sta->idle);
5211
- sta->in = dtoh32(sta->in);
5212
- sinfo->inactive_time = sta->idle * 1000;
5213
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
5214
- if (sta->flags & WL_STA_ASSOC) {
5215
- sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
5216
- sinfo->connected_time = sta->in;
5217
- }
5218
- WL_INFORM(("STA %s : idle time : %d sec, connected time :%d ms\n",
5219
- bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
5220
- sta->idle * 1000));
5221
-#endif
5222
- } else if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS ||
5223
- wl_get_mode_by_netdev(cfg, dev) == WL_MODE_IBSS) {
5224
- get_pktcnt_t pktcnt;
5225
- u8 *curmacp;
8140
+#ifdef SUPPORT_RSSI_SUM_REPORT
8141
+ wl_rssi_ant_mimo_t rssi_ant_mimo;
8142
+#endif /* SUPPORT_RSSI_SUM_REPORT */
52268143
5227
- if (cfg->roam_offload) {
5228
- struct ether_addr bssid;
5229
- memset(&bssid, 0, sizeof(bssid));
5230
- err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
5231
- if (err) {
5232
- WL_ERR(("Failed to get current BSSID\n"));
5233
- } else {
5234
- if (!ETHER_ISNULLADDR(&bssid.octet) &&
5235
- memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
5236
- /* roaming is detected */
5237
- err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
5238
- if (err)
5239
- WL_ERR(("Failed to handle the delayed roam, "
5240
- "err=%d", err));
5241
- mac = (u8 *)bssid.octet;
5242
- }
5243
- }
5244
- }
5245
- if (!wl_get_drv_status(cfg, CONNECTED, dev) ||
5246
- (dhd_is_associated(dhd, NULL, &err) == FALSE)) {
5247
- WL_ERR(("NOT assoc\n"));
5248
- if (err == -ERESTARTSYS)
5249
- return err;
5250
- err = -ENODEV;
5251
- return err;
5252
- }
5253
- curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
5254
- if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
5255
- WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
5256
- MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
5257
- }
8144
+ if (dev == NULL || cfg == NULL) {
8145
+ return BCME_ERROR;
8146
+ }
52588147
5259
- /* Report the current tx rate */
5260
- rate = 0;
5261
- err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
5262
- if (err) {
5263
- WL_ERR(("Could not get rate (%d)\n", err));
5264
- } else {
5265
-#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
5266
- int rxpktglom;
5267
-#endif
5268
- rate = dtoh32(rate);
5269
- sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
5270
- sinfo->txrate.legacy = rate * 5;
5271
- WL_DBG(("Rate %d Mbps\n", (rate / 2)));
5272
-#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
5273
- rxpktglom = ((rate/2) > 150) ? 20 : 10;
8148
+ /* initialize rssi */
8149
+ *rssi = 0;
52748150
5275
- if (maxrxpktglom != rxpktglom) {
5276
- maxrxpktglom = rxpktglom;
5277
- WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2),
5278
- maxrxpktglom));
5279
- err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
5280
- (char*)&maxrxpktglom, 4, cfg->ioctl_buf,
5281
- WLC_IOCTL_MAXLEN, NULL);
5282
- if (err < 0) {
5283
- WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
5284
- }
5285
- }
5286
-#endif
5287
- }
5288
-
5289
- memset(&scb_val, 0, sizeof(scb_val));
5290
- scb_val.val = 0;
5291
- err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
5292
- sizeof(scb_val_t), false);
5293
- if (err) {
5294
- WL_ERR(("Could not get rssi (%d)\n", err));
5295
- goto get_station_err;
5296
- }
5297
- rssi = wl_rssi_offset(dtoh32(scb_val.val));
5298
- sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
5299
- sinfo->signal = rssi;
5300
- WL_DBG(("RSSI %d dBm\n", rssi));
5301
- memset(&pktcnt, 0, sizeof(pktcnt));
5302
- err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt,
5303
- sizeof(pktcnt), false);
5304
- if (!err) {
5305
- sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
5306
- STA_INFO_BIT(INFO_RX_DROP_MISC) |
5307
- STA_INFO_BIT(INFO_TX_PACKETS) |
5308
- STA_INFO_BIT(INFO_TX_FAILED));
5309
- sinfo->rx_packets = pktcnt.rx_good_pkt;
5310
- sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
5311
- sinfo->tx_packets = pktcnt.tx_good_pkt;
5312
- sinfo->tx_failed = pktcnt.tx_bad_pkt;
5313
- }
5314
-get_station_err:
5315
- if (err && (err != -ERESTARTSYS)) {
5316
- /* Disconnect due to zero BSSID or error to get RSSI */
5317
- WL_ERR(("force cfg80211_disconnected: %d\n", err));
5318
- wl_clr_drv_status(cfg, CONNECTED, dev);
5319
- CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
5320
- wl_link_down(cfg);
8151
+#ifdef SUPPORT_RSSI_SUM_REPORT
8152
+ /* Query RSSI sum across antennas */
8153
+ bzero(&rssi_ant_mimo, sizeof(rssi_ant_mimo));
8154
+ err = wl_get_rssi_per_ant(dev, dev->name, NULL, &rssi_ant_mimo);
8155
+ if (err) {
8156
+ WL_ERR(("Could not get rssi sum (%d)\n", err));
8157
+ /* set rssi to zero and do not return error,
8158
+ * because iovar phy_rssi_ant could return BCME_UNSUPPORTED
8159
+ * when bssid was null during roaming
8160
+ */
8161
+ err = BCME_OK;
8162
+ } else {
8163
+ cfg->rssi_sum_report = TRUE;
8164
+ if ((*rssi = rssi_ant_mimo.rssi_sum) >= 0) {
8165
+ *rssi = 0;
53218166 }
53228167 }
5323
- else {
5324
- WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
8168
+#endif /* SUPPORT_RSSI_SUM_REPORT */
8169
+
8170
+ /* if SUPPORT_RSSI_SUM_REPORT works once, do not use legacy method anymore */
8171
+ if (cfg->rssi_sum_report == FALSE) {
8172
+ bzero(&scb_val, sizeof(scb_val));
8173
+ scb_val.val = 0;
8174
+ err = wldev_ioctl_get(dev, WLC_GET_RSSI, &scb_val,
8175
+ sizeof(scb_val_t));
8176
+ if (err) {
8177
+ WL_ERR(("Could not get rssi (%d)\n", err));
8178
+ return err;
8179
+ }
8180
+ *rssi = wl_rssi_offset(dtoh32(scb_val.val));
8181
+ }
8182
+
8183
+ if (*rssi >= 0) {
8184
+ /* check assoc status including roaming */
8185
+ DHD_OS_WAKE_LOCK((dhd_pub_t *)(cfg->pub));
8186
+ if (wl_get_drv_status(cfg, CONNECTED, dev) && wl_check_assoc_state(cfg, dev)) {
8187
+ *rssi = cfg->rssi; /* use previous RSSI */
8188
+ WL_DBG(("use previous RSSI %d dBm\n", cfg->rssi));
8189
+ } else {
8190
+ *rssi = 0;
8191
+ }
8192
+ DHD_OS_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
8193
+ } else {
8194
+ /* backup the current rssi */
8195
+ cfg->rssi = *rssi;
53258196 }
53268197
53278198 return err;
53288199 }
53298200
8201
+static int
8202
+wl_cfg80211_ifstats_counters_cb(void *ctx, const uint8 *data, uint16 type, uint16 len)
8203
+{
8204
+ switch (type) {
8205
+ case WL_IFSTATS_XTLV_IF_INDEX:
8206
+ WL_DBG(("Stats received on interface index: %d\n", *data));
8207
+ break;
8208
+ case WL_IFSTATS_XTLV_GENERIC: {
8209
+ if (len > sizeof(wl_if_stats_t)) {
8210
+ WL_INFORM(("type 0x%x: cntbuf length too long! %d > %d\n",
8211
+ type, len, (int)sizeof(wl_if_stats_t)));
8212
+ }
8213
+ memcpy(ctx, data, sizeof(wl_if_stats_t));
8214
+ break;
8215
+ }
8216
+ default:
8217
+ WL_DBG(("Unsupported counter type 0x%x\n", type));
8218
+ break;
8219
+ }
8220
+
8221
+ return BCME_OK;
8222
+}
8223
+
8224
+/* Parameters to if_counters iovar need to be converted to XTLV format
8225
+ * before sending to FW. The length of the top level XTLV container
8226
+ * containing parameters should not exceed 228 bytes
8227
+ */
8228
+#define IF_COUNTERS_PARAM_CONTAINER_LEN_MAX 228
8229
+
8230
+int
8231
+wl_cfg80211_ifstats_counters(struct net_device *dev, wl_if_stats_t *if_stats)
8232
+{
8233
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8234
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
8235
+ uint8 *pbuf = NULL;
8236
+ bcm_xtlvbuf_t xtlvbuf, local_xtlvbuf;
8237
+ bcm_xtlv_t *xtlv;
8238
+ uint16 expected_resp_len;
8239
+ wl_stats_report_t *request = NULL, *response = NULL;
8240
+ int bsscfg_idx;
8241
+ int ret = BCME_OK;
8242
+
8243
+ pbuf = (uint8 *)MALLOCZ(dhdp->osh, WLC_IOCTL_MEDLEN);
8244
+ if (!pbuf) {
8245
+ WL_ERR(("Failed to allocate local pbuf\n"));
8246
+ return BCME_NOMEM;
8247
+ }
8248
+
8249
+ /* top level container length cannot exceed 228 bytes.
8250
+ * This is because the output buffer is 1535 bytes long.
8251
+ * Allow 1300 bytes for reporting stats coming in XTLV format
8252
+ */
8253
+ request = (wl_stats_report_t *)
8254
+ MALLOCZ(dhdp->osh, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
8255
+ if (!request) {
8256
+ WL_ERR(("Failed to allocate wl_stats_report_t with length (%d)\n",
8257
+ IF_COUNTERS_PARAM_CONTAINER_LEN_MAX));
8258
+ ret = BCME_NOMEM;
8259
+ goto fail;
8260
+ }
8261
+
8262
+ request->version = WL_STATS_REPORT_REQUEST_VERSION_V2;
8263
+
8264
+ /* Top level container... we will create it ourselves */
8265
+ /* Leave space for report version, length, and top level XTLV
8266
+ * WL_IFSTATS_XTLV_IF.
8267
+ */
8268
+ ret = bcm_xtlv_buf_init(&local_xtlvbuf,
8269
+ (uint8*)(request->data) + BCM_XTLV_HDR_SIZE,
8270
+ IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
8271
+ offsetof(wl_stats_report_t, data) - BCM_XTLV_HDR_SIZE,
8272
+ BCM_XTLV_OPTION_ALIGN32);
8273
+
8274
+ if (ret) {
8275
+ goto fail;
8276
+ }
8277
+
8278
+ /* Populate requests using this the local_xtlvbuf context. The xtlvbuf
8279
+ * is used to fill the container containing the XTLVs populated using
8280
+ * local_xtlvbuf.
8281
+ */
8282
+ ret = bcm_xtlv_buf_init(&xtlvbuf,
8283
+ (uint8*)(request->data),
8284
+ IF_COUNTERS_PARAM_CONTAINER_LEN_MAX -
8285
+ offsetof(wl_stats_report_t, data),
8286
+ BCM_XTLV_OPTION_ALIGN32);
8287
+
8288
+ if (ret) {
8289
+ goto fail;
8290
+ }
8291
+
8292
+ /* Request generic stats */
8293
+ ret = bcm_xtlv_put_data(&local_xtlvbuf,
8294
+ WL_IFSTATS_XTLV_GENERIC, NULL, 0);
8295
+ if (ret) {
8296
+ goto fail;
8297
+ }
8298
+
8299
+ /* Complete the outer container with type and length
8300
+ * only.
8301
+ */
8302
+ ret = bcm_xtlv_put_data(&xtlvbuf,
8303
+ WL_IFSTATS_XTLV_IF,
8304
+ NULL, bcm_xtlv_buf_len(&local_xtlvbuf));
8305
+
8306
+ if (ret) {
8307
+ goto fail;
8308
+ }
8309
+
8310
+ request->length = bcm_xtlv_buf_len(&xtlvbuf) +
8311
+ offsetof(wl_stats_report_t, data);
8312
+ bsscfg_idx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
8313
+
8314
+ /* send the command over to the device and get teh output */
8315
+ ret = wldev_iovar_getbuf_bsscfg(dev, "if_counters", (void *)request,
8316
+ request->length, pbuf, WLC_IOCTL_MEDLEN, bsscfg_idx,
8317
+ &cfg->ioctl_buf_sync);
8318
+ if (ret < 0) {
8319
+ WL_ERR(("if_counters not supported ret=%d\n", ret));
8320
+ goto fail;
8321
+ }
8322
+
8323
+ /* Reuse request to process response */
8324
+ response = (wl_stats_report_t *)pbuf;
8325
+
8326
+ /* version check */
8327
+ if (response->version != WL_STATS_REPORT_REQUEST_VERSION_V2) {
8328
+ ret = BCME_VERSION;
8329
+ goto fail;
8330
+ }
8331
+
8332
+ xtlv = (bcm_xtlv_t *)(response->data);
8333
+
8334
+ expected_resp_len =
8335
+ (BCM_XTLV_LEN(xtlv) + OFFSETOF(wl_stats_report_t, data));
8336
+
8337
+ /* Check if the received length is as expected */
8338
+ if ((response->length > WLC_IOCTL_MEDLEN) ||
8339
+ (response->length < expected_resp_len)) {
8340
+ ret = BCME_ERROR;
8341
+ WL_ERR(("Illegal response length received. Got: %d"
8342
+ " Expected: %d. Expected len must be <= %u\n",
8343
+ response->length, expected_resp_len, WLC_IOCTL_MEDLEN));
8344
+ goto fail;
8345
+ }
8346
+
8347
+ /* check the type. The return data will be in
8348
+ * WL_IFSTATS_XTLV_IF container. So check if that container is
8349
+ * present
8350
+ */
8351
+ if (BCM_XTLV_ID(xtlv) != WL_IFSTATS_XTLV_IF) {
8352
+ ret = BCME_ERROR;
8353
+ WL_ERR(("unexpected type received: %d Expected: %d\n",
8354
+ BCM_XTLV_ID(xtlv), WL_IFSTATS_XTLV_IF));
8355
+ goto fail;
8356
+ }
8357
+
8358
+ /* Process XTLVs within WL_IFSTATS_XTLV_IF container */
8359
+ ret = bcm_unpack_xtlv_buf(if_stats,
8360
+ (uint8*)response->data + BCM_XTLV_HDR_SIZE,
8361
+ BCM_XTLV_LEN(xtlv), /* total length of all TLVs in container */
8362
+ BCM_XTLV_OPTION_ALIGN32, wl_cfg80211_ifstats_counters_cb);
8363
+ if (ret) {
8364
+ WL_ERR(("Error unpacking XTLVs in wl_ifstats_counters: %d\n", ret));
8365
+ }
8366
+
8367
+fail:
8368
+ if (pbuf) {
8369
+ MFREE(dhdp->osh, pbuf, WLC_IOCTL_MEDLEN);
8370
+ }
8371
+
8372
+ if (request) {
8373
+ MFREE(dhdp->osh, request, IF_COUNTERS_PARAM_CONTAINER_LEN_MAX);
8374
+ }
8375
+ return ret;
8376
+}
8377
+#undef IF_COUNTERS_PARAM_CONTAINER_LEN_MAX
8378
+
8379
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
53308380 static s32
8381
+wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
8382
+ const u8 *mac, struct station_info *sinfo)
8383
+#else
8384
+static s32
8385
+wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
8386
+ u8 *mac, struct station_info *sinfo)
8387
+#endif // endif
8388
+{
8389
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8390
+ s32 rssi = 0;
8391
+ s32 rate = 0;
8392
+ s32 err = 0;
8393
+ u16 wl_iftype = 0;
8394
+ u16 wl_mode = 0;
8395
+ get_pktcnt_t pktcnt;
8396
+ wl_if_stats_t *if_stats = NULL;
8397
+ sta_info_v4_t *sta = NULL;
8398
+ u8 *curmacp = NULL;
8399
+
8400
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
8401
+ s8 eabuf[ETHER_ADDR_STR_LEN];
8402
+#endif // endif
8403
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
8404
+ bool fw_assoc_state = FALSE;
8405
+ u32 dhd_assoc_state = 0;
8406
+ void *buf;
8407
+
8408
+ RETURN_EIO_IF_NOT_UP(cfg);
8409
+
8410
+ if (cfg80211_to_wl_iftype(dev->ieee80211_ptr->iftype, &wl_iftype, &wl_mode) < 0) {
8411
+ return -EINVAL;
8412
+ }
8413
+
8414
+ buf = MALLOC(cfg->osh, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
8415
+ if (buf == NULL) {
8416
+ WL_ERR(("wl_cfg80211_get_station: MALLOC failed\n"));
8417
+ goto error;
8418
+ }
8419
+
8420
+ switch (wl_iftype) {
8421
+ case WL_IF_TYPE_STA:
8422
+ case WL_IF_TYPE_IBSS:
8423
+ if (cfg->roam_offload) {
8424
+ struct ether_addr bssid;
8425
+ bzero(&bssid, sizeof(bssid));
8426
+ err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
8427
+ if (err) {
8428
+ WL_ERR(("Failed to get current BSSID\n"));
8429
+ } else {
8430
+ if (memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
8431
+ /* roaming is detected */
8432
+ err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
8433
+ if (err)
8434
+ WL_ERR(("Failed to handle the delayed"
8435
+ " roam, err=%d", err));
8436
+ mac = (u8 *)bssid.octet;
8437
+ }
8438
+ }
8439
+ }
8440
+ dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
8441
+ DHD_OS_WAKE_LOCK(dhd);
8442
+ fw_assoc_state = dhd_is_associated(dhd, 0, &err);
8443
+ if (dhd_assoc_state && !fw_assoc_state) {
8444
+ /* check roam (join) status */
8445
+ if (wl_check_assoc_state(cfg, dev)) {
8446
+ fw_assoc_state = TRUE;
8447
+ WL_DBG(("roam status\n"));
8448
+ }
8449
+ }
8450
+ DHD_OS_WAKE_UNLOCK(dhd);
8451
+ if (!dhd_assoc_state || !fw_assoc_state) {
8452
+ WL_ERR(("NOT assoc\n"));
8453
+ if (err == -ENODATA)
8454
+ goto error;
8455
+ if (!dhd_assoc_state) {
8456
+ WL_TRACE_HW4(("drv state is not connected \n"));
8457
+ }
8458
+ if (!fw_assoc_state) {
8459
+ WL_TRACE_HW4(("fw state is not associated \n"));
8460
+ }
8461
+ /* Disconnect due to fw is not associated for
8462
+ * FW_ASSOC_WATCHDOG_TIME ms.
8463
+ * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
8464
+ * means that BSSID is null.
8465
+ */
8466
+ if (dhd_assoc_state && !fw_assoc_state && !err) {
8467
+ if (!fw_assoc_watchdog_started) {
8468
+ fw_assoc_watchdog_ms = OSL_SYSUPTIME();
8469
+ fw_assoc_watchdog_started = TRUE;
8470
+ WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
8471
+ } else if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
8472
+ FW_ASSOC_WATCHDOG_TIME) {
8473
+ fw_assoc_watchdog_started = FALSE;
8474
+ err = -ENODEV;
8475
+ WL_TRACE_HW4(("fw is not associated for %d ms \n",
8476
+ (OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
8477
+ goto get_station_err;
8478
+ }
8479
+ }
8480
+ err = -ENODEV;
8481
+ goto error;
8482
+ }
8483
+ if (dhd_is_associated(dhd, 0, NULL)) {
8484
+ fw_assoc_watchdog_started = FALSE;
8485
+ }
8486
+ curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
8487
+ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
8488
+ WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
8489
+ MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
8490
+ }
8491
+ /* go through to get another information */
8492
+ /* fall through */
8493
+ case WL_IF_TYPE_P2P_GC:
8494
+ case WL_IF_TYPE_P2P_DISC:
8495
+ if ((err = wl_cfg80211_get_rssi(dev, cfg, &rssi)) != BCME_OK) {
8496
+ goto get_station_err;
8497
+ }
8498
+ sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
8499
+ sinfo->signal = rssi;
8500
+ WL_DBG(("RSSI %d dBm\n", rssi));
8501
+ /* go through to get another information */
8502
+ /* fall through */
8503
+ case WL_IF_TYPE_P2P_GO:
8504
+ /* Report the current tx rate */
8505
+ rate = 0;
8506
+ err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
8507
+ if (err) {
8508
+ WL_ERR(("Could not get rate (%d)\n", err));
8509
+ } else {
8510
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
8511
+ int rxpktglom;
8512
+#endif // endif
8513
+ rate = dtoh32(rate);
8514
+ sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
8515
+ sinfo->txrate.legacy = rate * 5;
8516
+ WL_DBG(("Rate %d Mbps\n", (rate / 2)));
8517
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
8518
+ rxpktglom = ((rate/2) > 150) ? 20 : 10;
8519
+
8520
+ if (maxrxpktglom != rxpktglom) {
8521
+ maxrxpktglom = rxpktglom;
8522
+ WL_DBG(("Rate %d Mbps, update bus:"
8523
+ "maxtxpktglom=%d\n", (rate/2), maxrxpktglom));
8524
+ err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
8525
+ (char*)&maxrxpktglom, 4, cfg->ioctl_buf,
8526
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8527
+ if (err < 0) {
8528
+ WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
8529
+ }
8530
+ }
8531
+#endif // endif
8532
+ }
8533
+ if_stats = (wl_if_stats_t *)buf;
8534
+ bzero(if_stats, sizeof(*if_stats));
8535
+ if (FW_SUPPORTED(dhd, ifst)) {
8536
+ err = wl_cfg80211_ifstats_counters(dev, if_stats);
8537
+ } else
8538
+ {
8539
+ err = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
8540
+ (char *)if_stats, sizeof(*if_stats), NULL);
8541
+ }
8542
+
8543
+ if (err) {
8544
+ WL_ERR(("if_counters not supported ret=%d\n",
8545
+ err));
8546
+ bzero(&pktcnt, sizeof(pktcnt));
8547
+ err = wldev_ioctl_get(dev, WLC_GET_PKTCNTS, &pktcnt,
8548
+ sizeof(pktcnt));
8549
+ if (!err) {
8550
+ sinfo->rx_packets = pktcnt.rx_good_pkt;
8551
+ sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
8552
+ sinfo->tx_packets = pktcnt.tx_good_pkt;
8553
+ sinfo->tx_failed = pktcnt.tx_bad_pkt;
8554
+ }
8555
+ } else {
8556
+ sinfo->rx_packets = (uint32)dtoh64(if_stats->rxframe);
8557
+ sinfo->rx_dropped_misc = 0;
8558
+ sinfo->tx_packets = (uint32)dtoh64(if_stats->txfrmsnt);
8559
+ sinfo->tx_failed = (uint32)dtoh64(if_stats->txnobuf) +
8560
+ (uint32)dtoh64(if_stats->txrunt) +
8561
+ (uint32)dtoh64(if_stats->txfail);
8562
+ }
8563
+
8564
+ sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
8565
+ STA_INFO_BIT(INFO_RX_DROP_MISC) |
8566
+ STA_INFO_BIT(INFO_TX_PACKETS) |
8567
+ STA_INFO_BIT(INFO_TX_FAILED));
8568
+get_station_err:
8569
+ if (err && (err != -ENODATA)) {
8570
+ /* Disconnect due to zero BSSID or error to get RSSI */
8571
+ scb_val_t scbval;
8572
+ DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
8573
+ dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
8574
+ scbval.val = htod32(DOT11_RC_DISASSOC_LEAVING);
8575
+ err = wldev_ioctl_set(dev, WLC_DISASSOC, &scbval,
8576
+ sizeof(scb_val_t));
8577
+ if (unlikely(err)) {
8578
+ WL_ERR(("disassoc error (%d)\n", err));
8579
+ }
8580
+
8581
+ WL_ERR(("force cfg80211_disconnected: %d\n", err));
8582
+ wl_clr_drv_status(cfg, CONNECTED, dev);
8583
+ DHD_STATLOG_CTRL(dhd, ST(DISASSOC_DONE),
8584
+ dhd_net2idx(dhd->info, dev), DOT11_RC_DISASSOC_LEAVING);
8585
+ CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
8586
+ wl_link_down(cfg);
8587
+ }
8588
+ break;
8589
+ case WL_IF_TYPE_AP:
8590
+ err = wldev_iovar_getbuf(dev, "sta_info", (const void*)mac,
8591
+ ETHER_ADDR_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8592
+ if (err < 0) {
8593
+ WL_ERR(("GET STA INFO failed, %d\n", err));
8594
+ goto error;
8595
+ }
8596
+ sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
8597
+ sta = (sta_info_v4_t *)buf;
8598
+ if (sta->ver != WL_STA_VER_4 && sta->ver != WL_STA_VER_5) {
8599
+ WL_ERR(("GET STA INFO version mismatch, %d\n", err));
8600
+ return BCME_VERSION;
8601
+ }
8602
+ sta->len = dtoh16(sta->len);
8603
+ sta->cap = dtoh16(sta->cap);
8604
+ sta->flags = dtoh32(sta->flags);
8605
+ sta->idle = dtoh32(sta->idle);
8606
+ sta->in = dtoh32(sta->in);
8607
+ sinfo->inactive_time = sta->idle * 1000;
8608
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
8609
+ if (sta->flags & WL_STA_ASSOC) {
8610
+ sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
8611
+ sinfo->connected_time = sta->in;
8612
+ }
8613
+ WL_INFORM_MEM(("[%s] STA %s : idle time : %d sec,"
8614
+ " connected time :%d ms\n",
8615
+ dev->name,
8616
+ bcm_ether_ntoa((const struct ether_addr *)mac, eabuf),
8617
+ sinfo->inactive_time, sta->idle * 1000));
8618
+#endif // endif
8619
+ break;
8620
+ default :
8621
+ WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
8622
+ }
8623
+error:
8624
+ if (buf) {
8625
+ MFREE(cfg->osh, buf, MAX(sizeof(wl_if_stats_t), WLC_IOCTL_SMLEN));
8626
+ }
8627
+
8628
+ return err;
8629
+}
8630
+
8631
+s32
53318632 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
53328633 bool enabled, s32 timeout)
53338634 {
....@@ -5335,15 +8636,24 @@
53358636 s32 err = 0;
53368637 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
53378638 struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
5338
-
8639
+ s32 mode;
8640
+#ifdef RTT_SUPPORT
8641
+ dhd_pub_t *dhd = cfg->pub;
8642
+ rtt_status_info_t *rtt_status;
8643
+#endif /* RTT_SUPPORT */
53398644 RETURN_EIO_IF_NOT_UP(cfg);
8645
+
53408646 WL_DBG(("Enter\n"));
8647
+ mode = wl_get_mode_by_netdev(cfg, dev);
53418648 if (cfg->p2p_net == dev || _net_info == NULL ||
5342
- !wl_get_drv_status(cfg, CONNECTED, dev)) {
8649
+ !wl_get_drv_status(cfg, CONNECTED, dev) ||
8650
+ ((mode != WL_MODE_BSS) &&
8651
+ (mode != WL_MODE_IBSS))) {
53438652 return err;
53448653 }
5345
- /* Delete pm_enable_work */
5346
- wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_PEND);
8654
+
8655
+ /* Enlarge pm_enable_work */
8656
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
53478657
53488658 pm = enabled ? PM_FAST : PM_OFF;
53498659 if (_net_info->pm_block) {
....@@ -5353,14 +8663,21 @@
53538663 }
53548664 pm = htod32(pm);
53558665 WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
5356
- err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
5357
- if (unlikely(err)) {
5358
- if (err == -ENODEV)
5359
- WL_DBG(("net_device is not ready yet\n"));
5360
- else
5361
- WL_ERR(("error (%d)\n", err));
5362
- return err;
8666
+#ifdef RTT_SUPPORT
8667
+ rtt_status = GET_RTTSTATE(dhd);
8668
+ if (rtt_status->status != RTT_ENABLED) {
8669
+#endif /* RTT_SUPPORT */
8670
+ err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
8671
+ if (unlikely(err)) {
8672
+ if (err == -ENODEV)
8673
+ WL_DBG(("net_device is not ready yet\n"));
8674
+ else
8675
+ WL_ERR(("error (%d)\n", err));
8676
+ return err;
8677
+ }
8678
+#ifdef RTT_SUPPORT
53638679 }
8680
+#endif /* RTT_SUPPORT */
53648681 wl_cfg80211_update_power_mode(dev);
53658682 return err;
53668683 }
....@@ -5369,23 +8686,11 @@
53698686 {
53708687 int err, pm = -1;
53718688
5372
- err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), true);
8689
+ err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
53738690 if (err)
5374
- WL_ERR(("%s:error (%d)\n", __FUNCTION__, err));
8691
+ WL_ERR(("wl_cfg80211_update_power_mode: error (%d)\n", err));
53758692 else if (pm != -1 && dev->ieee80211_ptr)
53768693 dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
5377
-}
5378
-
5379
-void wl_cfg80211_set_passive_scan(struct net_device *dev, char *command)
5380
-{
5381
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
5382
-
5383
- if (strcmp(command, "SCAN-ACTIVE") == 0) {
5384
- cfg->active_scan = 1;
5385
- } else if (strcmp(command, "SCAN-PASSIVE") == 0) {
5386
- cfg->active_scan = 0;
5387
- } else
5388
- WL_ERR(("Unknown command \n"));
53898694 }
53908695
53918696 static __used u32 wl_find_msb(u16 bit16)
....@@ -5420,22 +8725,158 @@
54208725 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
54218726 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
54228727 s32 err = BCME_OK;
8728
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)) && \
8729
+ !defined(OEM_ANDROID)
8730
+ int pkt_filter_id = WL_WOWLAN_PKT_FILTER_ID_FIRST;
8731
+#endif /* (KERNEL_VERSION(2, 6, 39) || WL_COMPAT_WIRELES) && !OEM_ANDROID */
54238732
54248733 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
5425
- WL_INFORM(("device is not ready\n"));
8734
+ WL_INFORM_MEM(("device is not ready\n"));
54268735 return err;
54278736 }
54288737
8738
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)) && \
8739
+ !defined(OEM_ANDROID)
8740
+ while (pkt_filter_id <= WL_WOWLAN_PKT_FILTER_ID_LAST) {
8741
+ /* delete wowlan pkt filter if any */
8742
+ err = wldev_iovar_setbuf(ndev, "pkt_filter_delete", &pkt_filter_id,
8743
+ sizeof(pkt_filter_id), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8744
+ &cfg->ioctl_buf_sync);
8745
+ /* pkt_filter_delete would return BCME_BADARG when pkt filter id
8746
+ * does not exist in filter list of firmware, ignore it.
8747
+ */
8748
+ if (BCME_BADARG == err)
8749
+ err = BCME_OK;
8750
+
8751
+ if (BCME_OK != err) {
8752
+ WL_ERR(("pkt_filter_delete failed, id=%d, err=%d\n",
8753
+ pkt_filter_id, err));
8754
+ }
8755
+ pkt_filter_id++;
8756
+ }
8757
+#endif /* (KERNEL_VERSION(2, 6, 39) || WL_COMPAT_WIRELES) && !OEM_ANDROID */
54298758
54308759 return err;
54318760 }
54328761
8762
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)) && \
8763
+ !defined(OEM_ANDROID)
8764
+static s32 wl_wowlan_config(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
8765
+{
8766
+ s32 err = BCME_OK;
8767
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8768
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
54338769
5434
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
8770
+ u32 i = 0, j = 0;
8771
+ u32 buf_len = 0, pattern_size = 0;
8772
+ wl_pkt_filter_t *pkt_filterp = NULL;
8773
+ wl_pkt_filter_enable_t pkt_filter_enable;
8774
+ u8 mask_bytes_len = 0, mask_byte_idx = 0, mask_bit_idx = 0;
8775
+ const u32 max_buf_size = WL_PKT_FILTER_FIXED_LEN +
8776
+ WL_PKT_FILTER_PATTERN_FIXED_LEN + (2 * WL_WOWLAN_MAX_PATTERN_LEN);
8777
+
8778
+ WL_DBG(("Enter\n"));
8779
+
8780
+ if (wow == NULL) {
8781
+ WL_DBG(("wow config is null\n"));
8782
+ return err;
8783
+ }
8784
+
8785
+ /* configure wowlan pattern filters */
8786
+ if (0 < wow->n_patterns) {
8787
+ pkt_filterp = (wl_pkt_filter_t *)MALLOCZ(cfg->osh, max_buf_size);
8788
+ if (pkt_filterp == NULL) {
8789
+ WL_ERR(("Error allocating buffer for pkt filters\n"));
8790
+ return -ENOMEM;
8791
+ }
8792
+
8793
+ WL_DBG(("Pattern count=%d\n", wow->n_patterns));
8794
+ while (i < wow->n_patterns) {
8795
+
8796
+ /* reset buffers */
8797
+ buf_len = 0;
8798
+ bzero(pkt_filterp, max_buf_size);
8799
+
8800
+ /* copy filter id */
8801
+ store32_ua(&pkt_filterp->id, (WL_WOWLAN_PKT_FILTER_ID_FIRST + i));
8802
+
8803
+ /* copy filter type */
8804
+ store32_ua(&pkt_filterp->type, WL_PKT_FILTER_TYPE_PATTERN_MATCH);
8805
+
8806
+ /* copy size */
8807
+ pattern_size = htod32(wow->patterns[i].pattern_len);
8808
+ store32_ua(&pkt_filterp->u.pattern.size_bytes, pattern_size);
8809
+
8810
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
8811
+ /* copy offset */
8812
+ store32_ua(&pkt_filterp->u.pattern.offset, wow->patterns[i].pkt_offset);
8813
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
8814
+
8815
+ /* convert mask from bit to byte format */
8816
+ j = 0;
8817
+ mask_bit_idx = 0;
8818
+ mask_byte_idx = 0;
8819
+ mask_bytes_len = DIV_ROUND_UP(pattern_size, 8);
8820
+ while ((mask_byte_idx < mask_bytes_len) &&
8821
+ (mask_bit_idx < pattern_size)) {
8822
+
8823
+ if (isbitset(wow->patterns[i].mask[mask_byte_idx], mask_bit_idx++))
8824
+ pkt_filterp->u.pattern.mask_and_pattern[j] = 0xFF;
8825
+ j++;
8826
+ if (mask_bit_idx >= 8) {
8827
+ /* move to next mask byte */
8828
+ mask_bit_idx = 0;
8829
+ mask_byte_idx++;
8830
+ }
8831
+ }
8832
+
8833
+ /* copy pattern to be matched */
8834
+ memcpy(&pkt_filterp->u.pattern.mask_and_pattern[pattern_size],
8835
+ wow->patterns[i].pattern, pattern_size);
8836
+
8837
+ /* calculate filter buffer len */
8838
+ buf_len += WL_PKT_FILTER_FIXED_LEN;
8839
+ buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + (2 * pattern_size));
8840
+
8841
+ /* add pkt filter */
8842
+ err = wldev_iovar_setbuf(ndev, "pkt_filter_add", pkt_filterp, buf_len,
8843
+ cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync);
8844
+ if (BCME_OK != err) {
8845
+ WL_ERR(("pkt_filter_add failed, id=%d, err=%d\n",
8846
+ pkt_filterp->id, err));
8847
+ goto exit;
8848
+ }
8849
+
8850
+ /* enable pkt filter id */
8851
+ pkt_filter_enable.id = pkt_filterp->id;
8852
+ pkt_filter_enable.enable = TRUE;
8853
+ err = wldev_iovar_setbuf(ndev, "pkt_filter_enable", &pkt_filter_enable,
8854
+ sizeof(pkt_filter_enable),
8855
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
8856
+ if (BCME_OK != err) {
8857
+ WL_ERR(("pkt_filter_enable failed, id=%d, err=%d\n",
8858
+ pkt_filterp->id, err));
8859
+ goto exit;
8860
+ }
8861
+ i++; /* move to next pattern */
8862
+ }
8863
+ } else
8864
+ WL_DBG(("wowlan filters not found\n"));
8865
+
8866
+exit:
8867
+ if (pkt_filterp) {
8868
+ MFREE(cfg->osh, pkt_filterp, max_buf_size);
8869
+ }
8870
+
8871
+ return err;
8872
+}
8873
+#endif /* (KERNEL_VERSION(2, 6, 39) || WL_COMPAT_WIRELES) && !OEM_ANDROID */
8874
+
8875
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
54358876 static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
54368877 #else
54378878 static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
5438
-#endif
8879
+#endif // endif
54398880 {
54408881 s32 err = BCME_OK;
54418882 #ifdef DHD_CLEAR_ON_SUSPEND
....@@ -5444,7 +8885,7 @@
54448885 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
54458886 unsigned long flags;
54468887 if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
5447
- WL_INFORM(("device is not ready : status (%d)\n",
8888
+ WL_INFORM_MEM(("device is not ready : status (%d)\n",
54488889 (int)cfg->status));
54498890 return err;
54508891 }
....@@ -5453,14 +8894,9 @@
54538894 if (iter->ndev)
54548895 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
54558896 }
5456
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
8897
+ WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
54578898 if (cfg->scan_request) {
5458
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 8, 0))
5459
- struct cfg80211_scan_info info = { .aborted = true };
5460
- cfg80211_scan_done(cfg->scan_request, &info);
5461
-#else
54628899 cfg80211_scan_done(cfg->scan_request, true);
5463
-#endif
54648900 cfg->scan_request = NULL;
54658901 }
54668902 for_each_ndev(cfg, iter, next) {
....@@ -5469,7 +8905,7 @@
54698905 wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
54708906 }
54718907 }
5472
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
8908
+ WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
54738909 for_each_ndev(cfg, iter, next) {
54748910 if (iter->ndev) {
54758911 if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
....@@ -5479,32 +8915,10 @@
54798915 }
54808916 #endif /* DHD_CLEAR_ON_SUSPEND */
54818917
5482
-
5483
-#ifdef CUS_11321
5484
- {
5485
- struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5486
- struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
5487
- u8 gpiopol = 0; // 0:Set active high when wake up, 1:Set active low when wake up
5488
- char strclear[6] = "clear";
5489
- u32 wowl = WL_WOWL_DIS | WL_WOWL_BCN | WL_WOWL_GTK_FAILURE | WL_WOWL_RETR |
5490
- WL_WOWL_TCPKEEP_TIME | WL_WOWL_TCPKEEP_DATA;
5491
-
5492
- /* enable ARPOE */
5493
- wldev_iovar_setint(ndev, "arpoe", 1);
5494
- wldev_iovar_setint(ndev, "arp_ol", 0xf);
5495
- wldev_iovar_setint(ndev, "arp_peerage", 1000000);
5496
-
5497
- /* enable GTKOE */
5498
- wldev_iovar_setint(ndev, "wake_event_enable", 4);
5499
-
5500
- /* enable WOWL */
5501
- wldev_iovar_setint(ndev, "wowl_gpiopol", gpiopol);
5502
- wldev_iovar_setbuf(ndev, "wowl_wakeind", strclear, sizeof(strclear),
5503
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
5504
- wldev_iovar_setint(ndev, "wowl", wowl);
5505
- wldev_iovar_setint(ndev, "wowl_activate", 1);
5506
- }
5507
-#endif
8918
+#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)) && \
8919
+ !defined(OEM_ANDROID)
8920
+ err = wl_wowlan_config(wiphy, wow);
8921
+#endif /* (KERNEL_VERSION(2, 6, 39) || WL_COMPAT_WIRELES) && !OEM_ANDROID */
55088922
55098923 return err;
55108924 }
....@@ -5514,38 +8928,132 @@
55148928 s32 err)
55158929 {
55168930 int i, j;
5517
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
8931
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
55188932 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
8933
+ int npmkids = cfg->pmk_list->pmkids.count;
55198934
8935
+ ASSERT(cfg->pmk_list->pmkids.length >= (sizeof(u16)*2));
55208936 if (!pmk_list) {
5521
- printk("pmk_list is NULL\n");
8937
+ WL_INFORM_MEM(("pmk_list is NULL\n"));
55228938 return -EINVAL;
55238939 }
55248940 /* pmk list is supported only for STA interface i.e. primary interface
55258941 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
55268942 */
55278943 if (primary_dev != dev) {
5528
- WL_INFORM(("Not supporting Flushing pmklist on virtual"
8944
+ WL_INFORM_MEM(("Not supporting Flushing pmklist on virtual"
55298945 " interfaces than primary interface\n"));
55308946 return err;
55318947 }
55328948
5533
- WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
5534
- for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
8949
+ WL_DBG(("No of elements %d\n", npmkids));
8950
+ for (i = 0; i < npmkids; i++) {
55358951 WL_DBG(("PMKID[%d]: %pM =\n", i,
5536
- &pmk_list->pmkids.pmkid[i].BSSID));
8952
+ &pmk_list->pmkids.pmkid[i].bssid));
55378953 for (j = 0; j < WPA2_PMKID_LEN; j++) {
5538
- WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]));
8954
+ WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].pmkid[j]));
55398955 }
55408956 }
5541
- if (likely(!err)) {
5542
- err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
5543
- sizeof(*pmk_list), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
8957
+ if (cfg->wlc_ver.wlc_ver_major > MIN_PMKID_LIST_V3_FW_MAJOR) {
8958
+ pmk_list->pmkids.version = PMKID_LIST_VER_3;
8959
+ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
8960
+ sizeof(*pmk_list), cfg->ioctl_buf,
8961
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
55448962 }
8963
+ /* For wlc_ver_major 13 sending pmkid version as 2
8964
+ * as firmware has not implemented the pmkid list ver 3
8965
+ */
8966
+ else if (cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V2_FW_MAJOR ||
8967
+ cfg->wlc_ver.wlc_ver_major == MIN_PMKID_LIST_V3_FW_MAJOR) {
8968
+ u32 v2_list_size = (u32)(sizeof(pmkid_list_v2_t) + npmkids*sizeof(pmkid_v2_t));
8969
+ pmkid_list_v2_t *pmkid_v2_list = (pmkid_list_v2_t *)MALLOCZ(cfg->osh, v2_list_size);
55458970
8971
+ if (pmkid_v2_list == NULL) {
8972
+ WL_ERR(("failed to allocate pmkid list\n"));
8973
+ return BCME_NOMEM;
8974
+ }
8975
+
8976
+ pmkid_v2_list->version = PMKID_LIST_VER_2;
8977
+ /* Account for version, length and pmkid_v2_t fields */
8978
+ pmkid_v2_list->length = (npmkids * sizeof(pmkid_v2_t)) + (2 * sizeof(u16));
8979
+
8980
+ for (i = 0; i < npmkids; i++) {
8981
+ /* memcpy_s return checks not needed as buffers are of same size */
8982
+ (void)memcpy_s(&pmkid_v2_list->pmkid[i].BSSID,
8983
+ ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
8984
+ ETHER_ADDR_LEN);
8985
+
8986
+ /* copy pmkid if available */
8987
+ if (pmk_list->pmkids.pmkid[i].pmkid_len) {
8988
+ (void)memcpy_s(pmkid_v2_list->pmkid[i].PMKID,
8989
+ WPA2_PMKID_LEN,
8990
+ pmk_list->pmkids.pmkid[i].pmkid,
8991
+ pmk_list->pmkids.pmkid[i].pmkid_len);
8992
+ }
8993
+
8994
+ if (pmk_list->pmkids.pmkid[i].pmk_len) {
8995
+ (void)memcpy_s(pmkid_v2_list->pmkid[i].pmk,
8996
+ pmk_list->pmkids.pmkid[i].pmk_len,
8997
+ pmk_list->pmkids.pmkid[i].pmk,
8998
+ pmk_list->pmkids.pmkid[i].pmk_len);
8999
+ pmkid_v2_list->pmkid[i].pmk_len = pmk_list->pmkids.pmkid[i].pmk_len;
9000
+ }
9001
+
9002
+ if (pmk_list->pmkids.pmkid[i].ssid_len) {
9003
+ (void)memcpy_s(pmkid_v2_list->pmkid[i].ssid.ssid,
9004
+ pmk_list->pmkids.pmkid[i].ssid_len,
9005
+ pmk_list->pmkids.pmkid[i].ssid,
9006
+ pmk_list->pmkids.pmkid[i].ssid_len);
9007
+ pmkid_v2_list->pmkid[i].ssid.ssid_len
9008
+ = pmk_list->pmkids.pmkid[i].ssid_len;
9009
+ }
9010
+
9011
+ (void)memcpy_s(pmkid_v2_list->pmkid[i].fils_cache_id,
9012
+ FILS_CACHE_ID_LEN, &pmk_list->pmkids.pmkid[i].fils_cache_id,
9013
+ FILS_CACHE_ID_LEN);
9014
+ pmkid_v2_list->pmkid[i].length = PMKID_ELEM_V2_LENGTH;
9015
+ }
9016
+ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v2_list,
9017
+ v2_list_size, cfg->ioctl_buf,
9018
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
9019
+ if (unlikely(err)) {
9020
+ WL_ERR(("pmkid_info failed (%d)\n", err));
9021
+ }
9022
+
9023
+ MFREE(cfg->osh, pmkid_v2_list, v2_list_size);
9024
+ }
9025
+ else {
9026
+ u32 v1_list_size = (u32)(sizeof(pmkid_list_v1_t) + npmkids*sizeof(pmkid_v1_t));
9027
+ pmkid_list_v1_t *pmkid_v1_list = (pmkid_list_v1_t *)MALLOCZ(cfg->osh, v1_list_size);
9028
+ if (pmkid_v1_list == NULL) {
9029
+ WL_ERR(("failed to allocate pmkid list\n"));
9030
+ return BCME_NOMEM;
9031
+ }
9032
+ for (i = 0; i < npmkids; i++) {
9033
+ /* memcpy_s return checks not needed as buffers are of same size */
9034
+ (void)memcpy_s(&pmkid_v1_list->pmkid[i].BSSID,
9035
+ ETHER_ADDR_LEN, &pmk_list->pmkids.pmkid[i].bssid,
9036
+ ETHER_ADDR_LEN);
9037
+ (void)memcpy_s(pmkid_v1_list->pmkid[i].PMKID,
9038
+ WPA2_PMKID_LEN, pmk_list->pmkids.pmkid[i].pmkid,
9039
+ WPA2_PMKID_LEN);
9040
+ pmkid_v1_list->npmkid++;
9041
+ }
9042
+ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmkid_v1_list,
9043
+ v1_list_size, cfg->ioctl_buf,
9044
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
9045
+ if (unlikely(err)) {
9046
+ WL_ERR(("pmkid_info failed (%d)\n", err));
9047
+ }
9048
+
9049
+ MFREE(cfg->osh, pmkid_v1_list, v1_list_size);
9050
+ }
55469051 return err;
55479052 }
55489053
9054
+/* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
9055
+ * entry operation.
9056
+ */
55499057 static s32
55509058 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
55519059 struct cfg80211_pmksa *pmksa)
....@@ -5553,76 +9061,259 @@
55539061 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
55549062 s32 err = 0;
55559063 int i;
9064
+ int npmkids = cfg->pmk_list->pmkids.count;
9065
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
55569066
55579067 RETURN_EIO_IF_NOT_UP(cfg);
5558
- for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
5559
- if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5560
- ETHER_ADDR_LEN))
5561
- break;
9068
+ BCM_REFERENCE(dhdp);
9069
+ DHD_STATLOG_CTRL(dhdp, ST(INSTALL_PMKSA), dhd_net2idx(dhdp->info, dev), 0);
9070
+
9071
+ for (i = 0; i < npmkids; i++) {
9072
+ if (pmksa->bssid != NULL) {
9073
+ if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
9074
+ ETHER_ADDR_LEN))
9075
+ break;
9076
+ }
9077
+#ifdef WL_FILS
9078
+ else if (pmksa->ssid != NULL) {
9079
+ if (!memcmp(pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
9080
+ pmksa->ssid_len))
9081
+ break;
9082
+ }
9083
+#endif /* WL_FILS */
9084
+ }
55629085 if (i < WL_NUM_PMKIDS_MAX) {
5563
- memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid,
5564
- ETHER_ADDR_LEN);
5565
- memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid,
9086
+ if (pmksa->bssid != NULL) {
9087
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].bssid, pmksa->bssid,
9088
+ ETHER_ADDR_LEN);
9089
+ }
9090
+#ifdef WL_FILS
9091
+ else if (pmksa->ssid != NULL) {
9092
+ cfg->pmk_list->pmkids.pmkid[i].ssid_len = pmksa->ssid_len;
9093
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].ssid, pmksa->ssid,
9094
+ pmksa->ssid_len);
9095
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].fils_cache_id, pmksa->cache_id,
9096
+ FILS_CACHE_ID_LEN);
9097
+ }
9098
+#endif /* WL_FILS */
9099
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS))
9100
+ if (pmksa->pmk_len) {
9101
+ if (memcpy_s(&cfg->pmk_list->pmkids.pmkid[i].pmk, PMK_LEN_MAX, pmksa->pmk,
9102
+ pmksa->pmk_len)) {
9103
+ WL_ERR(("invalid pmk len = %lu", pmksa->pmk_len));
9104
+ } else {
9105
+ cfg->pmk_list->pmkids.pmkid[i].pmk_len = pmksa->pmk_len;
9106
+ }
9107
+ }
9108
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || defined(WL_FILS) */
9109
+ /* return check not required as buffer lengths are same */
9110
+ (void)memcpy_s(cfg->pmk_list->pmkids.pmkid[i].pmkid, WPA2_PMKID_LEN, pmksa->pmkid,
55669111 WPA2_PMKID_LEN);
5567
- if (i == cfg->pmk_list->pmkids.npmkid)
5568
- cfg->pmk_list->pmkids.npmkid++;
9112
+ cfg->pmk_list->pmkids.pmkid[i].pmkid_len = WPA2_PMKID_LEN;
9113
+
9114
+ /* set lifetime not to expire in firmware by default.
9115
+ * Currently, wpa_supplicant control PMKID lifetime on his end. e.g) set 12 hours
9116
+ * when it expired, wpa_supplicant should call set_pmksa/del_pmksa to update
9117
+ * corresponding entry.
9118
+ */
9119
+ cfg->pmk_list->pmkids.pmkid[i].time_left = KEY_PERM_PMK;
9120
+ if (i == npmkids) {
9121
+ cfg->pmk_list->pmkids.length += sizeof(pmkid_v3_t);
9122
+ cfg->pmk_list->pmkids.count++;
9123
+ }
55699124 } else {
55709125 err = -EINVAL;
55719126 }
5572
- WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
5573
- &cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].BSSID));
9127
+
9128
+#if (WL_DBG_LEVEL > 0)
9129
+ if (pmksa->bssid != NULL) {
9130
+ WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
9131
+ &cfg->pmk_list->pmkids.pmkid[npmkids - 1].bssid));
9132
+ }
55749133 for (i = 0; i < WPA2_PMKID_LEN; i++) {
55759134 WL_DBG(("%02x\n",
5576
- cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].
5577
- PMKID[i]));
9135
+ cfg->pmk_list->pmkids.pmkid[npmkids - 1].
9136
+ pmkid[i]));
55789137 }
9138
+#endif /* (WL_DBG_LEVEL > 0) */
55799139
55809140 err = wl_update_pmklist(dev, cfg->pmk_list, err);
55819141
55829142 return err;
55839143 }
55849144
9145
+/* sending pmkid_info IOVAR to manipulate PMKID(PMKSA) list in firmware.
9146
+ * input @pmksa: host given single pmksa info.
9147
+ * if it's NULL, assume whole list manipulated. e.g) flush all PMKIDs in firmware.
9148
+ * input @set: TRUE means adding PMKSA operation. FALSE means deleting.
9149
+ * return: log internal BCME_XXX error, and convert it to -EINVAL to linux generic error code.
9150
+ */
9151
+static s32 wl_cfg80211_update_pmksa(struct wiphy *wiphy, struct net_device *dev,
9152
+ struct cfg80211_pmksa *pmksa, bool set) {
9153
+
9154
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9155
+ s32 err = 0;
9156
+ pmkid_list_v3_t *pmk_list;
9157
+ uint32 alloc_len;
9158
+
9159
+ RETURN_EIO_IF_NOT_UP(cfg);
9160
+
9161
+ if (cfg->wlc_ver.wlc_ver_major < MIN_PMKID_LIST_V3_FW_MAJOR) {
9162
+ WL_ERR(("wlc_ver_major not supported:%d\n", cfg->wlc_ver.wlc_ver_major));
9163
+ return BCME_VERSION;
9164
+ }
9165
+
9166
+ alloc_len = OFFSETOF(pmkid_list_v3_t, pmkid) + ((pmksa) ? sizeof(pmkid_v3_t) : 0);
9167
+ pmk_list = (pmkid_list_v3_t *)MALLOCZ(cfg->osh, alloc_len);
9168
+
9169
+ if (pmk_list == NULL) {
9170
+ return BCME_NOMEM;
9171
+ }
9172
+
9173
+ pmk_list->version = PMKID_LIST_VER_3;
9174
+ pmk_list->length = alloc_len;
9175
+ pmk_list->count = (pmksa) ? 1 : 0; // 1 means single entry operation, 0 means whole list.
9176
+
9177
+ /* controll set/del action by lifetime parameter accordingly.
9178
+ * if set == TRUE, it's set PMKID action with lifetime permanent.
9179
+ * if set == FALSE, it's del PMKID action with lifetime zero.
9180
+ */
9181
+ pmk_list->pmkid->time_left = (set) ? KEY_PERM_PMK : 0;
9182
+
9183
+ if (pmksa) {
9184
+ if (pmksa->bssid) {
9185
+ err = memcpy_s(&pmk_list->pmkid->bssid, sizeof(pmk_list->pmkid->bssid),
9186
+ pmksa->bssid, ETHER_ADDR_LEN);
9187
+ if (err) {
9188
+ goto exit;
9189
+ }
9190
+ }
9191
+ if (pmksa->pmkid) {
9192
+ err = memcpy_s(&pmk_list->pmkid->pmkid, sizeof(pmk_list->pmkid->pmkid),
9193
+ pmksa->pmkid, WPA2_PMKID_LEN);
9194
+ if (err) {
9195
+ goto exit;
9196
+ }
9197
+ }
9198
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
9199
+ if (pmksa->pmk) {
9200
+ err = memcpy_s(&pmk_list->pmkid->pmk, sizeof(pmk_list->pmkid->pmk),
9201
+ pmksa->pmk, pmksa->pmk_len);
9202
+ if (err) {
9203
+ goto exit;
9204
+ }
9205
+ pmk_list->pmkid->pmk_len = pmksa->pmk_len;
9206
+ }
9207
+ if (pmksa->ssid) {
9208
+ err = memcpy_s(&pmk_list->pmkid->ssid, sizeof(pmk_list->pmkid->ssid),
9209
+ pmksa->ssid, pmksa->ssid_len);
9210
+ if (err) {
9211
+ goto exit;
9212
+ }
9213
+ pmk_list->pmkid->ssid_len = pmksa->ssid_len;
9214
+ }
9215
+ if (pmksa->cache_id) {
9216
+ pmk_list->pmkid->fils_cache_id = *pmksa->cache_id;
9217
+ }
9218
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
9219
+ }
9220
+ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
9221
+ alloc_len, cfg->ioctl_buf,
9222
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
9223
+
9224
+exit:
9225
+ if (pmk_list) {
9226
+ MFREE(cfg->osh, pmk_list, alloc_len);
9227
+ }
9228
+ return err;
9229
+}
9230
+
9231
+/* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
9232
+ * entry operation.
9233
+ */
55859234 static s32
55869235 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
55879236 struct cfg80211_pmksa *pmksa)
55889237 {
55899238 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5590
-
5591
- struct _pmkid_list pmkid = {.npmkid = 0};
55929239 s32 err = 0;
55939240 int i;
5594
-
9241
+ int npmkids = cfg->pmk_list->pmkids.count;
55959242 RETURN_EIO_IF_NOT_UP(cfg);
5596
- memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
5597
- memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
55989243
5599
- WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
5600
- &pmkid.pmkid[0].BSSID));
5601
- for (i = 0; i < WPA2_PMKID_LEN; i++) {
5602
- WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i]));
9244
+ if (!pmksa) {
9245
+ WL_ERR(("pmksa is not initialized\n"));
9246
+ return BCME_ERROR;
9247
+ }
9248
+ if (!npmkids) {
9249
+ /* nmpkids = 0, nothing to delete */
9250
+ WL_DBG(("npmkids=0. Skip del\n"));
9251
+ return BCME_OK;
56039252 }
56049253
5605
- for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
5606
- if (!memcmp
5607
- (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
5608
- ETHER_ADDR_LEN))
5609
- break;
5610
-
5611
- if ((cfg->pmk_list->pmkids.npmkid > 0) &&
5612
- (i < cfg->pmk_list->pmkids.npmkid)) {
5613
- memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t));
5614
- for (; i < (cfg->pmk_list->pmkids.npmkid - 1); i++) {
5615
- memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
5616
- &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
5617
- ETHER_ADDR_LEN);
5618
- memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
5619
- &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
5620
- WPA2_PMKID_LEN);
9254
+#if (WL_DBG_LEVEL > 0)
9255
+ if (pmksa->bssid) {
9256
+ WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
9257
+ pmksa->bssid));
9258
+ }
9259
+#ifdef WL_FILS
9260
+ else if (pmksa->ssid) {
9261
+ WL_DBG(("FILS: del_pmksa for ssid: "));
9262
+ for (i = 0; i < pmksa->ssid_len; i++) {
9263
+ WL_DBG(("%c", pmksa->ssid[i]));
56219264 }
5622
- cfg->pmk_list->pmkids.npmkid--;
9265
+ WL_DBG(("\n"));
9266
+ }
9267
+#endif /* WL_FILS */
9268
+ if (pmksa->pmkid) {
9269
+ for (i = 0; i < WPA2_PMKID_LEN; i++) {
9270
+ WL_DBG(("%02x\n", pmksa->pmkid[i]));
9271
+ }
9272
+ }
9273
+#endif /* (WL_DBG_LEVEL > 0) */
9274
+
9275
+ for (i = 0; i < npmkids; i++) {
9276
+ if (pmksa->bssid) {
9277
+ if (!memcmp
9278
+ (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].bssid,
9279
+ ETHER_ADDR_LEN)) {
9280
+ break;
9281
+ }
9282
+ }
9283
+#ifdef WL_FILS
9284
+ else if (pmksa->ssid) {
9285
+ if (!memcmp
9286
+ (pmksa->ssid, &cfg->pmk_list->pmkids.pmkid[i].ssid,
9287
+ pmksa->ssid_len)) {
9288
+ break;
9289
+ }
9290
+ }
9291
+#endif /* WL_FILS */
9292
+ }
9293
+ if ((npmkids > 0) && (i < npmkids)) {
9294
+ bzero(&cfg->pmk_list->pmkids.pmkid[i], sizeof(pmkid_v3_t));
9295
+ for (; i < (npmkids - 1); i++) {
9296
+ (void)memcpy_s(&cfg->pmk_list->pmkids.pmkid[i],
9297
+ sizeof(pmkid_v3_t),
9298
+ &cfg->pmk_list->pmkids.pmkid[i + 1],
9299
+ sizeof(pmkid_v3_t));
9300
+ }
9301
+ npmkids--;
9302
+ cfg->pmk_list->pmkids.length -= sizeof(pmkid_v3_t);
9303
+ cfg->pmk_list->pmkids.count--;
9304
+
56239305 } else {
56249306 err = -EINVAL;
56259307 }
9308
+
9309
+ /* current wl_update_pmklist() doesn't delete corresponding PMKID entry.
9310
+ * inside firmware. So we need to issue delete action explicitely through
9311
+ * this function.
9312
+ */
9313
+ err = wl_cfg80211_update_pmksa(wiphy, dev, pmksa, FALSE);
9314
+ /* intentional fall through even on error.
9315
+ * it should work above MIN_PMKID_LIST_V3_FW_MAJOR, otherwise let ignore it.
9316
+ */
56269317
56279318 err = wl_update_pmklist(dev, cfg->pmk_list, err);
56289319
....@@ -5630,58 +9321,21 @@
56309321
56319322 }
56329323
9324
+/* TODO: remove temporal cfg->pmk_list list, and call wl_cfg80211_update_pmksa for single
9325
+ * entry operation.
9326
+ */
56339327 static s32
56349328 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
56359329 {
56369330 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
56379331 s32 err = 0;
56389332 RETURN_EIO_IF_NOT_UP(cfg);
5639
- memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
9333
+ bzero(cfg->pmk_list, sizeof(*cfg->pmk_list));
9334
+ cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
9335
+ cfg->pmk_list->pmkids.count = 0;
9336
+ cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
56409337 err = wl_update_pmklist(dev, cfg->pmk_list, err);
56419338 return err;
5642
-
5643
-}
5644
-
5645
-static wl_scan_params_t *
5646
-wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
5647
-{
5648
- wl_scan_params_t *params;
5649
- int params_size;
5650
- int num_chans;
5651
- int bssidx = 0;
5652
-
5653
- *out_params_size = 0;
5654
-
5655
- /* Our scan params only need space for 1 channel and 0 ssids */
5656
- params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16);
5657
- params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL);
5658
- if (params == NULL) {
5659
- WL_ERR(("mem alloc failed (%d bytes)\n", params_size));
5660
- return params;
5661
- }
5662
- memset(params, 0, params_size);
5663
- params->nprobes = nprobes;
5664
-
5665
- num_chans = (channel == 0) ? 0 : 1;
5666
-
5667
- memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
5668
- params->bss_type = DOT11_BSSTYPE_ANY;
5669
- params->scan_type = DOT11_SCANTYPE_ACTIVE;
5670
- params->nprobes = htod32(1);
5671
- params->active_time = htod32(-1);
5672
- params->passive_time = htod32(-1);
5673
- params->home_time = htod32(10);
5674
- if (channel == -1)
5675
- params->channel_list[0] = htodchanspec(channel);
5676
- else
5677
- params->channel_list[0] = wl_ch_host_to_driver(bssidx, channel);
5678
-
5679
- /* Our scan params have 1 channel and 0 ssids */
5680
- params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
5681
- (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
5682
-
5683
- *out_params_size = params_size; /* rtn size to the caller */
5684
- return params;
56859339 }
56869340
56879341 #if defined(WL_CFG80211_P2P_DEV_IF)
....@@ -5702,9 +9356,24 @@
57029356 struct ether_addr primary_mac;
57039357 struct net_device *ndev = NULL;
57049358 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9359
+ struct net_device *ndev_dpp_listen = NULL;
9360
+
9361
+ RETURN_EIO_IF_NOT_UP(cfg);
9362
+#ifdef DHD_IFDEBUG
9363
+ PRINT_WDEV_INFO(cfgdev);
9364
+#endif /* DHD_IFDEBUG */
57059365
57069366 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
57079367
9368
+ /*
9369
+ * dpp listen request will arrive on primary interface
9370
+ * If so, mark dpp listen flag on this interface
9371
+ */
9372
+ ndev_dpp_listen = cfgdev_to_ndev(cfgdev);
9373
+ if (ndev_dpp_listen)
9374
+ wl_set_dpp_listen_by_netdev(cfg, ndev_dpp_listen, 1);
9375
+
9376
+ mutex_lock(&cfg->usr_sync);
57089377 WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
57099378 ieee80211_frequency_to_channel(channel->center_freq),
57109379 duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO"));
....@@ -5715,9 +9384,17 @@
57159384 goto exit;
57169385 }
57179386
9387
+#ifdef P2P_LISTEN_OFFLOADING
9388
+ if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
9389
+ WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
9390
+ err = -EAGAIN;
9391
+ goto exit;
9392
+ }
9393
+#endif /* P2P_LISTEN_OFFLOADING */
9394
+
57189395 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
57199396 if (wl_get_drv_status_all(cfg, SCANNING)) {
5720
- wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
9397
+ wl_cfg80211_cancel_scan(cfg);
57219398 }
57229399 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
57239400
....@@ -5733,7 +9410,7 @@
57339410
57349411 #ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
57359412 if (wl_get_drv_status(cfg, SCANNING, ndev)) {
5736
- struct timer_list *_timer;
9413
+ timer_list_compat_t *_timer;
57379414 WL_DBG(("scan is running. go to fake listen state\n"));
57389415
57399416 if (duration > LONG_LISTEN_TIME) {
....@@ -5746,7 +9423,7 @@
57469423 del_timer_sync(&cfg->p2p->listen_timer);
57479424 }
57489425
5749
- _timer = (struct timer_list *) &cfg->p2p->listen_timer;
9426
+ _timer = &cfg->p2p->listen_timer;
57509427 wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
57519428
57529429 INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0);
....@@ -5757,6 +9434,10 @@
57579434 }
57589435 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
57599436
9437
+#ifdef WL_BCNRECV
9438
+ /* check fakeapscan in progress then abort */
9439
+ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_LISTENBUSY);
9440
+#endif /* WL_BCNRECV */
57609441 #ifdef WL_CFG80211_SYNC_GON
57619442 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
57629443 /* do not enter listen mode again if we are in listen mode already for next af.
....@@ -5799,6 +9480,11 @@
57999480 wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
58009481 }
58019482 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
9483
+
9484
+ if (err) {
9485
+ wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
9486
+ }
9487
+
58029488 /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant
58039489 * and expire timer will send a completion to the upper layer
58049490 */
....@@ -5807,7 +9493,7 @@
58079493
58089494 exit:
58099495 if (err == BCME_OK) {
5810
- WL_INFORM(("Success\n"));
9496
+ WL_DBG(("Success\n"));
58119497 #if defined(WL_CFG80211_P2P_DEV_IF)
58129498 cfg80211_ready_on_channel(cfgdev, *cookie, channel,
58139499 duration, GFP_KERNEL);
....@@ -5818,6 +9504,7 @@
58189504 } else {
58199505 WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie));
58209506 }
9507
+ mutex_unlock(&cfg->usr_sync);
58219508 return err;
58229509 }
58239510
....@@ -5826,13 +9513,19 @@
58269513 bcm_struct_cfgdev *cfgdev, u64 cookie)
58279514 {
58289515 s32 err = 0;
5829
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
9516
+
9517
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
58309518
58319519 #ifdef P2PLISTEN_AP_SAMECHN
58329520 struct net_device *dev;
58339521 #endif /* P2PLISTEN_AP_SAMECHN */
58349522
58359523 RETURN_EIO_IF_NOT_UP(cfg);
9524
+
9525
+#ifdef DHD_IFDEBUG
9526
+ PRINT_WDEV_INFO(cfgdev);
9527
+#endif /* DHD_IFDEBUG */
9528
+
58369529 #if defined(WL_CFG80211_P2P_DEV_IF)
58379530 if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
58389531 WL_DBG((" enter ) on P2P dedicated discover interface\n"));
....@@ -5854,8 +9547,9 @@
58549547 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
58559548 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
58569549 } else {
5857
- WL_ERR(("%s : ignore, request cookie(%llu) is not matched. (cur : %llu)\n",
5858
- __FUNCTION__, cookie, cfg->last_roc_id));
9550
+ WL_ERR(("wl_cfg80211_cancel_remain_on_channel: ignore, request cookie(%llu)"
9551
+ " is not matched. (cur : %llu)\n",
9552
+ cookie, cfg->last_roc_id));
58599553 }
58609554
58619555 return err;
....@@ -5865,23 +9559,26 @@
58659559 wl_cfg80211_afx_handler(struct work_struct *work)
58669560 {
58679561 struct afx_hdl *afx_instance;
5868
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
9562
+ struct bcm_cfg80211 *cfg;
58699563 s32 ret = BCME_OK;
58709564
58719565 BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
5872
- if (afx_instance != NULL && cfg->afx_hdl->is_active) {
5873
- if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
5874
- ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
5875
- (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
5876
- } else {
5877
- ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
5878
- cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
5879
- NULL);
5880
- }
5881
- if (unlikely(ret != BCME_OK)) {
5882
- WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
5883
- if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
5884
- complete(&cfg->act_frm_scan);
9566
+ if (afx_instance) {
9567
+ cfg = wl_get_cfg(afx_instance->dev);
9568
+ if (cfg != NULL && cfg->afx_hdl->is_active) {
9569
+ if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
9570
+ ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
9571
+ (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
9572
+ } else {
9573
+ ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
9574
+ cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
9575
+ NULL);
9576
+ }
9577
+ if (unlikely(ret != BCME_OK)) {
9578
+ WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
9579
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
9580
+ complete(&cfg->act_frm_scan);
9581
+ }
58859582 }
58869583 }
58879584 }
....@@ -5890,6 +9587,7 @@
58909587 wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
58919588 {
58929589 u32 max_retry = WL_CHANNEL_SYNC_RETRY;
9590
+ bool is_p2p_gas = false;
58939591
58949592 if (dev == NULL)
58959593 return -1;
....@@ -5898,6 +9596,13 @@
58989596
58999597 wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
59009598 cfg->afx_hdl->is_active = TRUE;
9599
+
9600
+ if (cfg->afx_hdl->pending_tx_act_frm) {
9601
+ wl_action_frame_t *action_frame;
9602
+ action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
9603
+ if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len))
9604
+ is_p2p_gas = true;
9605
+ }
59019606
59029607 /* Loop to wait until we find a peer's channel or the
59039608 * pending action frame tx is cancelled.
....@@ -5915,6 +9620,9 @@
59159620
59169621 if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
59179622 !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
9623
+ break;
9624
+
9625
+ if (is_p2p_gas)
59189626 break;
59199627
59209628 if (cfg->afx_hdl->my_listen_chan) {
....@@ -5945,15 +9653,69 @@
59459653
59469654 struct p2p_config_af_params {
59479655 s32 max_tx_retry; /* max tx retry count if tx no ack */
5948
- /* To make sure to send successfully action frame, we have to turn off mpc
5949
- * 0: off, 1: on, (-1): do nothing
5950
- */
5951
- s32 mpc_onoff;
9656
+#ifdef WL_CFG80211_GON_COLLISION
9657
+ /* drop tx go nego request if go nego collision occurs */
9658
+ bool drop_tx_req;
9659
+#endif // endif
59529660 #ifdef WL_CFG80211_SYNC_GON
59539661 bool extra_listen;
5954
-#endif
9662
+#endif // endif
59559663 bool search_channel; /* 1: search peer's channel to send af */
59569664 };
9665
+
9666
+#ifdef WL_DISABLE_HE_P2P
9667
+static s32
9668
+wl_cfg80211_he_p2p_disable(struct wiphy *wiphy, struct ether_addr peer_mac)
9669
+{
9670
+ struct cfg80211_bss *bss;
9671
+ u8 *ie = NULL;
9672
+ u32 ie_len = 0;
9673
+ struct net_device *ndev = NULL;
9674
+ s32 bssidx = 0;
9675
+ s32 err = BCME_OK;
9676
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
9677
+
9678
+ bss = CFG80211_GET_BSS(wiphy, NULL, peer_mac.octet, NULL, 0);
9679
+ if (!bss) {
9680
+ WL_ERR(("Could not find the Peer device\n"));
9681
+ return BCME_ERROR;
9682
+ } else {
9683
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
9684
+#if defined(WL_CFG80211_P2P_DEV_IF)
9685
+ ie = (u8 *)bss->ies->data;
9686
+ ie_len = bss->ies->len;
9687
+#else
9688
+ ie = bss->information_elements;
9689
+ ie_len = bss->len_information_elements;
9690
+#endif /* WL_CFG80211_P2P_DEV_IF */
9691
+ GCC_DIAGNOSTIC_POP();
9692
+ }
9693
+ if (ie) {
9694
+ if ((bcm_parse_tlvs_dot11(ie, ie_len,
9695
+ EXT_MNG_HE_CAP_ID, TRUE)) == NULL) {
9696
+ WL_DBG(("Peer does not support HE capability\n"));
9697
+ ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1);
9698
+ if (ndev && (bssidx =
9699
+ wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
9700
+ WL_ERR(("Find index failed\n"));
9701
+ err = BCME_ERROR;
9702
+ } else {
9703
+ WL_DBG(("Disabling HE for P2P\n"));
9704
+ err = wl_cfg80211_set_he_mode(ndev, cfg, bssidx,
9705
+ WL_IF_TYPE_P2P_DISC, FALSE);
9706
+ if (err < 0) {
9707
+ WL_ERR(("failed to set he features, error=%d\n", err));
9708
+ }
9709
+ }
9710
+ } else {
9711
+ WL_DBG(("Peer supports HE capability\n"));
9712
+ }
9713
+ }
9714
+ CFG80211_PUT_BSS(wiphy, bss);
9715
+
9716
+ return err;
9717
+}
9718
+#endif /* WL_DISABLE_HE_P2P */
59579719
59589720 static s32
59599721 wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
....@@ -5966,26 +9728,34 @@
59669728 (wifi_p2p_pub_act_frame_t *) (action_frame->data);
59679729
59689730 /* initialize default value */
9731
+#ifdef WL_CFG80211_GON_COLLISION
9732
+ config_af_params->drop_tx_req = false;
9733
+#endif // endif
59699734 #ifdef WL_CFG80211_SYNC_GON
59709735 config_af_params->extra_listen = true;
5971
-#endif
9736
+#endif // endif
59729737 config_af_params->search_channel = false;
59739738 config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
5974
- config_af_params->mpc_onoff = -1;
59759739 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
59769740
59779741 switch (act_frm->subtype) {
59789742 case P2P_PAF_GON_REQ: {
9743
+ /* Disable he if peer does not support before starting GONEG */
9744
+#ifdef WL_DISABLE_HE_P2P
9745
+ wl_cfg80211_he_p2p_disable(wiphy, action_frame->da);
9746
+#endif /* WL_DISABLE_HE_P2P */
59799747 WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
59809748 wl_set_p2p_status(cfg, GO_NEG_PHASE);
59819749
5982
- config_af_params->mpc_onoff = 0;
59839750 config_af_params->search_channel = true;
59849751 cfg->next_af_subtype = act_frm->subtype + 1;
59859752
59869753 /* increase dwell time to wait for RESP frame */
59879754 af_params->dwell_time = WL_MED_DWELL_TIME;
59889755
9756
+#ifdef WL_CFG80211_GON_COLLISION
9757
+ config_af_params->drop_tx_req = true;
9758
+#endif /* WL_CFG80211_GON_COLLISION */
59899759 break;
59909760 }
59919761 case P2P_PAF_GON_RSP: {
....@@ -5999,12 +9769,14 @@
59999769 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
60009770 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
60019771
6002
- /* turn on mpc again if go nego is done */
6003
- config_af_params->mpc_onoff = 1;
6004
-
60059772 /* minimize dwell time */
60069773 af_params->dwell_time = WL_MIN_DWELL_TIME;
60079774
9775
+#ifdef WL_CFG80211_GON_COLLISION
9776
+ /* if go nego formation done, clear it */
9777
+ cfg->block_gon_req_tx_count = 0;
9778
+ cfg->block_gon_req_rx_count = 0;
9779
+#endif /* WL_CFG80211_GON_COLLISION */
60089780 #ifdef WL_CFG80211_SYNC_GON
60099781 config_af_params->extra_listen = false;
60109782 #endif /* WL_CFG80211_SYNC_GON */
....@@ -6049,7 +9821,6 @@
60499821 config_af_params->search_channel = true;
60509822 }
60519823
6052
- config_af_params->mpc_onoff = 0;
60539824 cfg->next_af_subtype = act_frm->subtype + 1;
60549825 /* increase dwell time to wait for RESP frame */
60559826 af_params->dwell_time = WL_MED_DWELL_TIME;
....@@ -6057,7 +9828,7 @@
60579828 }
60589829 case P2P_PAF_PROVDIS_RSP: {
60599830 cfg->next_af_subtype = P2P_PAF_GON_REQ;
6060
- af_params->dwell_time = WL_MIN_DWELL_TIME;
9831
+ af_params->dwell_time = WL_MED_DWELL_TIME;
60619832 #ifdef WL_CFG80211_SYNC_GON
60629833 config_af_params->extra_listen = false;
60639834 #endif /* WL_CFG80211_SYNC_GON */
....@@ -6077,7 +9848,7 @@
60779848 void *frame, u16 frame_len)
60789849 {
60799850 struct wl_scan_results *bss_list;
6080
- struct wl_bss_info *bi = NULL;
9851
+ wl_bss_info_t *bi = NULL;
60819852 bool result = false;
60829853 s32 i;
60839854 chanspec_t chanspec;
....@@ -6107,7 +9878,17 @@
61079878 return result;
61089879 }
61099880 #endif /* WL11U */
6110
-
9881
+static bool
9882
+wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies)
9883
+{
9884
+ if ((requested_dwell & CUSTOM_RETRY_MASK) &&
9885
+ (jiffies_to_msecs(jiffies - dwell_jiffies) >
9886
+ (requested_dwell & ~CUSTOM_RETRY_MASK))) {
9887
+ WL_ERR(("Action frame TX retry time over dwell time!\n"));
9888
+ return true;
9889
+ }
9890
+ return false;
9891
+}
61119892
61129893 static bool
61139894 wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
....@@ -6125,9 +9906,12 @@
61259906 struct net_info *netinfo;
61269907 #ifdef VSDB
61279908 ulong off_chan_started_jiffies = 0;
6128
-#endif
9909
+#endif // endif
9910
+ ulong dwell_jiffies = 0;
9911
+ bool dwell_overflow = false;
61299912 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
61309913
9914
+ int32 requested_dwell = af_params->dwell_time;
61319915
61329916 /* Add the default dwell time
61339917 * Dwell time to stay off-channel to wait for a response action frame
....@@ -6150,11 +9934,13 @@
61509934 tx_retry = 0;
61519935 cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
61529936 config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
6153
- config_af_params.mpc_onoff = -1;
61549937 config_af_params.search_channel = false;
9938
+#ifdef WL_CFG80211_GON_COLLISION
9939
+ config_af_params.drop_tx_req = false;
9940
+#endif // endif
61559941 #ifdef WL_CFG80211_SYNC_GON
61569942 config_af_params.extra_listen = false;
6157
-#endif
9943
+#endif // endif
61589944
61599945 /* config parameters */
61609946 /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
....@@ -6167,6 +9953,16 @@
61679953 WL_DBG(("Unknown subtype.\n"));
61689954 }
61699955
9956
+#ifdef WL_CFG80211_GON_COLLISION
9957
+ if (config_af_params.drop_tx_req) {
9958
+ if (cfg->block_gon_req_tx_count) {
9959
+ /* drop gon req tx action frame */
9960
+ WL_DBG(("Drop gon req tx action frame: count %d\n",
9961
+ cfg->block_gon_req_tx_count));
9962
+ goto exit;
9963
+ }
9964
+ }
9965
+#endif /* WL_CFG80211_GON_COLLISION */
61709966 } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
61719967 /* service discovery process */
61729968 if (action == P2PSD_ACTION_ID_GAS_IREQ ||
....@@ -6179,6 +9975,15 @@
61799975 cfg->next_af_subtype = action + 1;
61809976
61819977 af_params->dwell_time = WL_MED_DWELL_TIME;
9978
+ if (requested_dwell & CUSTOM_RETRY_MASK) {
9979
+ config_af_params.max_tx_retry =
9980
+ (requested_dwell & CUSTOM_RETRY_MASK) >> 24;
9981
+ af_params->dwell_time =
9982
+ (requested_dwell & ~CUSTOM_RETRY_MASK);
9983
+ WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
9984
+ config_af_params.max_tx_retry,
9985
+ af_params->dwell_time));
9986
+ }
61829987 } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
61839988 action == P2PSD_ACTION_ID_GAS_CRESP) {
61849989 /* configure service discovery response frame */
....@@ -6201,12 +10006,7 @@
620110006 }
620210007 }
620310008
6204
- /* To make sure to send successfully action frame, we have to turn off mpc */
6205
- if (config_af_params.mpc_onoff == 0) {
6206
- wldev_iovar_setint(dev, "mpc", 0);
6207
- }
6208
-
6209
- netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
10009
+ netinfo = wl_get_netinfo_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
621010010 /* validate channel and p2p ies */
621110011 if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) &&
621210012 netinfo && netinfo->bss.ies.probe_req_ie_len) {
....@@ -6224,11 +10024,11 @@
622410024 if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
622510025 OSL_SLEEP(50);
622610026 }
6227
-#endif
10027
+#endif // endif
622810028
622910029 /* if scan is ongoing, abort current scan. */
623010030 if (wl_get_drv_status_all(cfg, SCANNING)) {
6231
- wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
10031
+ wl_cfg80211_cancel_scan(cfg);
623210032 }
623310033
623410034 /* Abort P2P listen */
....@@ -6280,7 +10080,13 @@
628010080 WL_ERR(("couldn't find peer's channel.\n"));
628110081 wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
628210082 af_params->channel);
6283
- goto exit;
10083
+ /* Even if we couldn't find peer channel, try to send the frame
10084
+ * out. P2P cert 5.1.14 testbed device (realtek) doesn't seem to
10085
+ * respond to probe request (Ideally it has to be in listen and
10086
+ * responsd to probe request). However if we send Go neg req, the
10087
+ * peer is sending GO-neg resp. So instead of giving up here, just
10088
+ * proceed and attempt sending out the action frame.
10089
+ */
628410090 }
628510091
628610092 wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
....@@ -6289,7 +10095,7 @@
628910095 * but after the check of piggyback algorithm.
629010096 * To take care of current piggback algo, lets abort the scan here itself.
629110097 */
6292
- wl_notify_escan_complete(cfg, dev, true, true);
10098
+ wl_cfg80211_cancel_scan(cfg);
629310099 /* Suspend P2P discovery's search-listen to prevent it from
629410100 * starting a scan or changing the channel.
629510101 */
....@@ -6299,7 +10105,14 @@
629910105 }
630010106
630110107 /* update channel */
6302
- af_params->channel = cfg->afx_hdl->peer_chan;
10108
+ if (cfg->afx_hdl->peer_chan != WL_INVALID) {
10109
+ af_params->channel = cfg->afx_hdl->peer_chan;
10110
+ WL_ERR(("Attempt tx on peer listen channel:%d ",
10111
+ cfg->afx_hdl->peer_chan));
10112
+ } else {
10113
+ WL_ERR(("Attempt tx with the channel provided by userspace."
10114
+ "Channel: %d\n", af_params->channel));
10115
+ }
630310116 }
630410117
630510118 #ifdef VSDB
....@@ -6310,11 +10123,14 @@
631010123
631110124 wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
631210125
10126
+ dwell_jiffies = jiffies;
631310127 /* Now send a tx action frame */
631410128 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
10129
+ dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
631510130
631610131 /* if failed, retry it. tx_retry_max value is configure by .... */
6317
- while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) {
10132
+ while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry) &&
10133
+ !dwell_overflow) {
631810134 #ifdef VSDB
631910135 if (af_params->channel) {
632010136 if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
....@@ -6327,6 +10143,7 @@
632710143 #endif /* VSDB */
632810144 ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
632910145 false : true;
10146
+ dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
633010147 }
633110148
633210149 if (ack == false) {
....@@ -6343,6 +10160,9 @@
634310160 * the dwell time, go to listen state again to get next action response frame.
634410161 */
634510162 if (ack && config_af_params.extra_listen &&
10163
+#ifdef WL_CFG80211_GON_COLLISION
10164
+ !cfg->block_gon_req_tx_count &&
10165
+#endif /* WL_CFG80211_GON_COLLISION */
634610166 wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
634710167 cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
634810168 s32 extar_listen_time;
....@@ -6366,18 +10186,25 @@
636610186 #endif /* WL_CFG80211_SYNC_GON */
636710187 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
636810188
6369
- if (cfg->afx_hdl->pending_tx_act_frm)
6370
- cfg->afx_hdl->pending_tx_act_frm = NULL;
10189
+ cfg->afx_hdl->pending_tx_act_frm = NULL;
637110190
6372
- WL_INFORM(("-- sending Action Frame is %s, listen chan: %d\n",
6373
- (ack) ? "Succeeded!!":"Failed!!", cfg->afx_hdl->my_listen_chan));
6374
-
6375
-
6376
- /* if all done, turn mpc on again */
6377
- if (config_af_params.mpc_onoff == 1) {
6378
- wldev_iovar_setint(dev, "mpc", 1);
10191
+ if (ack) {
10192
+ WL_DBG(("-- Action Frame Tx succeeded, listen chan: %d\n",
10193
+ cfg->afx_hdl->my_listen_chan));
10194
+ } else {
10195
+ WL_ERR(("-- Action Frame Tx failed, listen chan: %d\n",
10196
+ cfg->afx_hdl->my_listen_chan));
637910197 }
638010198
10199
+#ifdef WL_CFG80211_GON_COLLISION
10200
+ if (cfg->block_gon_req_tx_count) {
10201
+ cfg->block_gon_req_tx_count--;
10202
+ /* if ack is ture, supplicant will wait more time(100ms).
10203
+ * so we will return it as a success to get more time .
10204
+ */
10205
+ ack = true;
10206
+ }
10207
+#endif /* WL_CFG80211_GON_COLLISION */
638110208 return ack;
638210209 }
638310210
....@@ -6395,12 +10222,12 @@
639510222 bool channel_type_valid,
639610223 #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
639710224 unsigned int wait, const u8* buf, size_t len,
6398
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
10225
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
639910226 bool no_cck,
6400
-#endif
6401
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
10227
+#endif // endif
10228
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
640210229 bool dont_wait_for_ack,
6403
-#endif
10230
+#endif // endif
640410231 u64 *cookie)
640510232 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
640610233 {
....@@ -6411,7 +10238,7 @@
641110238 struct ieee80211_channel *channel = params->chan;
641210239 const u8 *buf = params->buf;
641310240 size_t len = params->len;
6414
-#endif
10241
+#endif // endif
641510242 const struct ieee80211_mgmt *mgmt;
641610243 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
641710244 struct net_device *dev = NULL;
....@@ -6420,25 +10247,29 @@
642010247 u32 id;
642110248 bool ack = false;
642210249 s8 eabuf[ETHER_ADDR_STR_LEN];
10250
+#ifdef WL_SAE
10251
+ struct net_info *netinfo = NULL;
10252
+ struct wl_mf_params *mf_params;
10253
+ u32 mf_params_len = 0;
10254
+ s32 timeout = 0;
10255
+ s32 chan_nr;
10256
+#endif // endif
642310257
642410258 WL_DBG(("Enter \n"));
642510259
6426
- /* The CVE-2017-0706.dff patched here manually */
642710260 if (len > ACTION_FRAME_SIZE) {
642810261 WL_ERR(("bad length:%zu\n", len));
642910262 return BCME_BADLEN;
643010263 }
10264
+#ifdef DHD_IFDEBUG
10265
+ PRINT_WDEV_INFO(cfgdev);
10266
+#endif /* DHD_IFDEBUG */
643110267
643210268 dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
643310269
643410270 if (!dev) {
643510271 WL_ERR(("dev is NULL\n"));
643610272 return -EINVAL;
6437
- }
6438
-
6439
- if (len > ACTION_FRAME_SIZE) {
6440
- WL_ERR(("bad length:%zu\n", len));
6441
- return BCME_BADLEN;
644210273 }
644310274
644410275 /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
....@@ -6486,10 +10317,10 @@
648610317 #if defined(P2P_IE_MISSING_FIX)
648710318 if (!cfg->p2p_prb_noti) {
648810319 cfg->p2p_prb_noti = true;
6489
- WL_DBG(("%s: TX 802_1X Probe Response first time.\n",
6490
- __FUNCTION__));
10320
+ WL_DBG(("wl_cfg80211_mgmt_tx: TX 802_1X Probe"
10321
+ " Response first time.\n"));
649110322 }
6492
-#endif
10323
+#endif // endif
649310324 goto exit;
649410325 } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
649510326 ieee80211_is_deauth(mgmt->frame_control)) {
....@@ -6500,8 +10331,8 @@
650010331 if (!bcmp((const uint8 *)BSSID_BROADCAST,
650110332 (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
650210333 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
6503
- err = wldev_ioctl(dev, WLC_GET_ASSOCLIST,
6504
- assoc_maclist, sizeof(mac_buf), false);
10334
+ err = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST,
10335
+ assoc_maclist, sizeof(mac_buf));
650510336 if (err < 0)
650610337 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
650710338 else
....@@ -6509,13 +10340,13 @@
650910340 }
651010341 memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
651110342 scb_val.val = mgmt->u.disassoc.reason_code;
6512
- err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
6513
- sizeof(scb_val_t), true);
10343
+ err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
10344
+ sizeof(scb_val_t));
651410345 if (err < 0)
651510346 WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
6516
- WL_ERR(("Disconnect STA : %s scb_val.val %d\n",
6517
- bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
6518
- scb_val.val));
10347
+ WL_ERR(("Disconnect STA : " MACDBG " scb_val.val %d\n",
10348
+ MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mgmt->da,
10349
+ eabuf)), scb_val.val));
651910350
652010351 if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
652110352 wl_delay(400);
....@@ -6535,16 +10366,84 @@
653510366 * And previous off-channel action frame must be ended before new af tx.
653610367 */
653710368 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
6538
- wl_notify_escan_complete(cfg, dev, true, true);
10369
+ wl_cfg80211_cancel_scan(cfg);
653910370 #endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
6540
- }
10371
+#ifdef WL_SAE
10372
+ } else if (ieee80211_is_auth(mgmt->frame_control)) {
10373
+ netinfo = wl_get_netinfo_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
10374
+ reinit_completion(&netinfo->mgmt_tx_cpl);
10375
+ clear_bit(MGMT_TX_ACK, &netinfo->mgmt_txstatus);
10376
+ clear_bit(MGMT_TX_NOACK, &netinfo->mgmt_txstatus);
10377
+ clear_bit(MGMT_TX_OFF_CHAN_COMPLETED,
10378
+ &netinfo->mgmt_txstatus);
654110379
10380
+ mf_params_len = offsetof(struct wl_mf_params, data) +
10381
+ (len - DOT11_MGMT_HDR_LEN);
10382
+ mf_params = (wl_mf_params_t *)MALLOCZ(cfg->osh, mf_params_len);
10383
+ if (!mf_params) {
10384
+ WL_ERR(("Insufficient memory to allocate auth frame\n"));
10385
+ err = -ENOMEM;
10386
+ goto exit;
10387
+ }
10388
+ mf_params->dwell_time = MGMT_AUTH_FRAME_DWELL_TIME;
10389
+ mf_params->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
10390
+ mf_params->fc = mgmt->frame_control;
10391
+
10392
+ /* update channel */
10393
+ if (!channel) {
10394
+ mf_params->channel = 0;
10395
+ } else {
10396
+ chan_nr = ieee80211_frequency_to_channel(channel->center_freq);
10397
+ mf_params->channel = cpu_to_le32(chan_nr);
10398
+ }
10399
+
10400
+ memcpy(&mf_params->da.octet, &mgmt->da[0], ETH_ALEN);
10401
+ memcpy(&mf_params->bssid.octet, &mgmt->bssid[0], ETH_ALEN);
10402
+ *cookie = (u64)mf_params->data;
10403
+ mf_params->packetId = cpu_to_le32(*cookie);
10404
+
10405
+ memcpy(mf_params->data, &buf[DOT11_MGMT_HDR_LEN],
10406
+ le16_to_cpu(mf_params->len));
10407
+
10408
+ WL_DBG(("Auth frame, cookie=%lld, fc=%x, len=%d, channel=%d\n",
10409
+ *cookie, mf_params->fc,
10410
+ le16_to_cpu(mf_params->len),
10411
+ mf_params->channel));
10412
+
10413
+ netinfo->mgmt_txid = mf_params->packetId;
10414
+ set_bit(MGMT_TX_SEND_FRAME, &netinfo->mgmt_txstatus);
10415
+
10416
+ err = wldev_iovar_setbuf_bsscfg(dev, "mgmt_frame", mf_params, mf_params_len,
10417
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
10418
+ if (err < 0) {
10419
+ WL_ERR(("Failed to send auth frame %d\n", err));
10420
+ ack = false;
10421
+ goto txstatus;
10422
+ }
10423
+
10424
+ timeout = wait_for_completion_timeout(&netinfo->mgmt_tx_cpl,
10425
+ MGMT_AUTH_FRAME_WAIT_TIME);
10426
+ if ((timeout > 0) || test_bit(MGMT_TX_ACK, &netinfo->mgmt_txstatus)) {
10427
+ WL_DBG(("TX auth frame operation is success\n"));
10428
+ ack = true;
10429
+ } else {
10430
+ ack = false;
10431
+ WL_ERR(("TX auth frame operation has failed, txstatus %ld\n",
10432
+ netinfo->mgmt_txstatus));
10433
+ }
10434
+txstatus:
10435
+ cfg80211_mgmt_tx_status(cfgdev_to_wdev(cfgdev), *cookie,
10436
+ buf, len, ack, GFP_KERNEL);
10437
+ MFREE(cfg->osh, mf_params, mf_params_len);
10438
+ goto exit;
10439
+#endif /* WL_SAE */
10440
+ }
654210441 } else {
654310442 WL_ERR(("Driver only allows MGMT packet type\n"));
654410443 goto exit;
654510444 }
654610445
6547
- af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
10446
+ af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
654810447
654910448 if (af_params == NULL)
655010449 {
....@@ -6576,7 +10475,7 @@
657610475 af_params->dwell_time = params->wait;
657710476 #else
657810477 af_params->dwell_time = wait;
6579
-#endif
10478
+#endif // endif
658010479
658110480 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
658210481
....@@ -6584,25 +10483,35 @@
658410483 action_frame, action_frame->len, bssidx);
658510484 cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
658610485
6587
- kfree(af_params);
10486
+ MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
658810487 exit:
658910488 return err;
659010489 }
659110490
10491
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0))
10492
+static void
10493
+wl_cfg80211_update_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev,
10494
+ struct mgmt_frame_regs *upd)
10495
+{
10496
+ WL_DBG(("mgmt_frame_regs: %x %x %x %x\n", upd->global_stypes,upd->interface_stypes,
10497
+ upd->global_mcast_stypes,upd->interface_mcast_stypes));
659210498
10499
+ return;
10500
+}
10501
+#else
659310502 static void
659410503 wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
6595
- u16 frame_type, bool reg)
10504
+ u16 frame, bool reg)
659610505 {
659710506
6598
- WL_DBG(("frame_type: %x, reg: %d\n", frame_type, reg));
10507
+ WL_DBG(("frame_type: %x, reg: %d\n", frame, reg));
659910508
6600
- if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
10509
+ if (frame != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
660110510 return;
660210511
660310512 return;
660410513 }
6605
-
10514
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) */
660610515
660710516 static s32
660810517 wl_cfg80211_change_bss(struct wiphy *wiphy,
....@@ -6611,18 +10520,14 @@
661110520 {
661210521 s32 err = 0;
661310522 s32 ap_isolate = 0;
6614
-#ifdef PCIE_FULL_DONGLE
661510523 s32 ifidx = DHD_BAD_IF;
6616
-#endif
6617
-#if defined(PCIE_FULL_DONGLE)
661810524 dhd_pub_t *dhd;
661910525 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
662010526 dhd = (dhd_pub_t *)(cfg->pub);
662110527 #if defined(WL_ENABLE_P2P_IF)
662210528 if (cfg->p2p_net == dev)
662310529 dev = bcmcfg_to_prmry_ndev(cfg);
6624
-#endif
6625
-#endif
10530
+#endif // endif
662610531
662710532 if (params->use_cts_prot >= 0) {
662810533 }
....@@ -6638,7 +10543,6 @@
663810543
663910544 if (params->ap_isolate >= 0) {
664010545 ap_isolate = params->ap_isolate;
6641
-#ifdef PCIE_FULL_DONGLE
664210546 ifidx = dhd_net2idx(dhd->info, dev);
664310547
664410548 if (ifidx != DHD_BAD_IF) {
....@@ -6646,122 +10550,145 @@
664610550 } else {
664710551 WL_ERR(("Failed to set ap_isolate\n"));
664810552 }
6649
-#else
6650
- err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
10553
+#ifdef BCMSDIO
10554
+ /* Onus of intra-BSS packet forwarding moved to DHD.
10555
+ * DHD will handle packet intra-bss packet forwarding.
10556
+ */
10557
+ err = wldev_iovar_setint(dev, "ap_isolate", AP_ISOLATE_SENDUP_ALL);
665110558 if (unlikely(err))
665210559 {
665310560 WL_ERR(("set ap_isolate Error (%d)\n", err));
665410561 }
6655
-#endif /* PCIE_FULL_DONGLE */
10562
+#endif /* BCMSDIO */
665610563 }
665710564
665810565 if (params->ht_opmode >= 0) {
665910566 }
666010567
6661
-
666210568 return err;
666310569 }
666410570
6665
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
6666
-static s32
6667
-wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
6668
- struct ieee80211_channel *chan,
6669
- struct cfg80211_chan_def chandef)
6670
-#else
6671
-static s32
6672
-wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
6673
- struct ieee80211_channel *chan,
6674
- enum nl80211_channel_type channel_type)
6675
-#endif
10571
+static int
10572
+wl_get_bandwidth_cap(struct net_device *ndev, uint32 band, uint32 *bandwidth)
667610573 {
6677
- s32 _chan;
6678
- chanspec_t chspec = 0;
6679
- chanspec_t fw_chspec = 0;
668010574 u32 bw = WL_CHANSPEC_BW_20;
6681
-#ifdef WL11ULB
6682
- u32 ulb_bw = wl_cfg80211_get_ulb_bw(dev->ieee80211_ptr);
6683
-#endif /* WL11ULB */
6684
-
668510575 s32 err = BCME_OK;
668610576 s32 bw_cap = 0;
668710577 struct {
668810578 u32 band;
668910579 u32 bw_cap;
669010580 } param = {0, 0};
10581
+ u8 ioctl_buf[WLC_IOCTL_SMLEN];
10582
+ u32 channel_width = 0;
10583
+ struct wireless_dev *wdev = ndev_to_wdev(ndev);
10584
+ struct wiphy *wiphy = wdev->wiphy;
669110585 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6692
-#ifdef CUSTOM_SET_CPUCORE
6693
- dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
6694
-#endif /* CUSTOM_SET_CPUCORE */
669510586
6696
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
6697
- enum nl80211_channel_type channel_type = NL80211_CHAN_HT20;
6698
-#endif
10587
+#ifdef WL_6E
10588
+ if (band == IEEE80211_BAND_5GHZ || band == IEEE80211_BAND_6GHZ) {
10589
+ if (band == IEEE80211_BAND_5GHZ)
10590
+ param.band = WLC_BAND_5G;
10591
+ else if (band == IEEE80211_BAND_6GHZ)
10592
+ param.band = WLC_BAND_6G;
10593
+#else
10594
+ if (band == IEEE80211_BAND_5GHZ) {
10595
+ param.band = WLC_BAND_5G;
10596
+#endif /* WL_6E AP */
10597
+ channel_width = wl_get_chanwidth_by_netdev(cfg, ndev);
10598
+ switch (channel_width) {
10599
+ case WL_CHANSPEC_BW_80:
10600
+ case WL_CHANSPEC_BW_40:
10601
+ case WL_CHANSPEC_BW_20:
10602
+ bw = channel_width;
10603
+ /* resetting user specified channel width */
10604
+ wl_set_chanwidth_by_netdev(cfg, ndev, 0);
10605
+ break;
10606
+ default:
10607
+ err = wldev_iovar_getbuf(ndev, "bw_cap", &param, sizeof(param),
10608
+ ioctl_buf, sizeof(ioctl_buf), NULL);
10609
+ if (err) {
10610
+ if (err != BCME_UNSUPPORTED) {
10611
+ WL_ERR(("bw_cap failed, %d\n", err));
10612
+ return err;
10613
+ } else {
10614
+ err = wldev_iovar_getint(ndev, "mimo_bw_cap",
10615
+ &bw_cap);
10616
+ if (err) {
10617
+ WL_ERR(("error get mimo_bw_cap (%d)\n",
10618
+ err));
10619
+ }
10620
+ if (bw_cap != WLC_N_BW_20ALL) {
10621
+ bw = WL_CHANSPEC_BW_40;
10622
+ }
10623
+ }
10624
+ } else {
10625
+ if (WL_BW_CAP_80MHZ(ioctl_buf[0])) {
10626
+ bw = WL_CHANSPEC_BW_80;
10627
+ } else if (WL_BW_CAP_40MHZ(ioctl_buf[0])) {
10628
+ bw = WL_CHANSPEC_BW_40;
10629
+ } else {
10630
+ bw = WL_CHANSPEC_BW_20;
10631
+ }
10632
+ }
10633
+ break;
10634
+ }
10635
+ } else if (band == IEEE80211_BAND_2GHZ) {
10636
+ bw = WL_CHANSPEC_BW_20;
10637
+ }
10638
+
10639
+ *bandwidth = bw;
10640
+
10641
+ return err;
10642
+}
10643
+
10644
+static s32
10645
+wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
10646
+ struct ieee80211_channel *chan,
10647
+ enum nl80211_channel_type channel_type)
10648
+{
10649
+ s32 _chan;
10650
+ chanspec_t chspec = 0;
10651
+ chanspec_t fw_chspec = 0;
10652
+ u32 bw = WL_CHANSPEC_BW_20;
10653
+ s32 err = BCME_OK;
10654
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
10655
+#if defined(CUSTOM_SET_CPUCORE) || defined(APSTA_RESTRICTED_CHANNEL)
10656
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10657
+#endif /* CUSTOM_SET_CPUCORE || APSTA_RESTRICTED_CHANNEL */
669910658
670010659 dev = ndev_to_wlc_ndev(dev, cfg);
670110660 _chan = ieee80211_frequency_to_channel(chan->center_freq);
670210661 WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
670310662 dev->ifindex, channel_type, _chan));
670410663
6705
-#if defined(CUSTOM_PLATFORM_NV_TEGRA)
6706
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
6707
- WL_ERR(("chan_width = %d\n", chandef.width));
6708
- switch (chandef.width) {
6709
- case NL80211_CHAN_WIDTH_40:
6710
- bw = WL_CHANSPEC_BW_40;
6711
- break;
6712
- case NL80211_CHAN_WIDTH_80:
6713
- bw = WL_CHANSPEC_BW_80;
6714
- break;
6715
- case NL80211_CHAN_WIDTH_80P80:
6716
- bw = WL_CHANSPEC_BW_8080;
6717
- break;
6718
- case NL80211_CHAN_WIDTH_160:
6719
- bw = WL_CHANSPEC_BW_160;
6720
- break;
6721
- default:
6722
- bw = WL_CHANSPEC_BW_20;
6723
- break;
6724
- }
6725
- goto set_channel;
6726
-#endif
6727
-#endif
6728
-
6729
-
6730
-#ifdef WL11ULB
6731
- if (ulb_bw) {
6732
- WL_DBG(("[ULB] setting AP/GO BW to ulb_bw 0x%x \n", ulb_bw));
6733
- bw = wl_cfg80211_ulbbw_to_ulbchspec(ulb_bw);
6734
- goto set_channel;
6735
- }
6736
-#endif /* WL11ULB */
6737
- if (chan->band == IEEE80211_BAND_5GHZ) {
6738
- param.band = WLC_BAND_5G;
6739
- err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
6740
- cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
6741
- if (err) {
6742
- if (err != BCME_UNSUPPORTED) {
6743
- WL_ERR(("bw_cap failed, %d\n", err));
6744
- return err;
6745
- } else {
6746
- err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
6747
- if (err) {
6748
- WL_ERR(("error get mimo_bw_cap (%d)\n", err));
6749
- }
6750
- if (bw_cap != WLC_N_BW_20ALL)
6751
- bw = WL_CHANSPEC_BW_40;
6752
- }
6753
- } else {
6754
- if (WL_BW_CAP_80MHZ(cfg->ioctl_buf[0]))
6755
- bw = WL_CHANSPEC_BW_80;
6756
- else if (WL_BW_CAP_40MHZ(cfg->ioctl_buf[0]))
6757
- bw = WL_CHANSPEC_BW_40;
6758
- else
10664
+#if defined(APSTA_RESTRICTED_CHANNEL)
10665
+ if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
10666
+ DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
10667
+ wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
10668
+ u32 *sta_chan = (u32 *)wl_read_prof(cfg,
10669
+ bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN);
10670
+ u32 sta_band = (*sta_chan > CH_MAX_2G_CHANNEL) ?
10671
+ IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
10672
+ if (chan->band == sta_band) {
10673
+ /* Do not try SCC in 5GHz if channel is not CH149 */
10674
+ _chan = (sta_band == IEEE80211_BAND_5GHZ &&
10675
+ *sta_chan != DEFAULT_5G_SOFTAP_CHANNEL) ?
10676
+ DEFAULT_2G_SOFTAP_CHANNEL : *sta_chan;
10677
+ WL_ERR(("target channel will be changed to %d\n", _chan));
10678
+ if (_chan <= CH_MAX_2G_CHANNEL) {
675910679 bw = WL_CHANSPEC_BW_20;
6760
-
10680
+ goto set_channel;
10681
+ }
676110682 }
10683
+ }
10684
+#endif /* APSTA_RESTRICTED_CHANNEL */
676210685
6763
- } else if (chan->band == IEEE80211_BAND_2GHZ)
6764
- bw = WL_CHANSPEC_BW_20;
10686
+ err = wl_get_bandwidth_cap(dev, chan->band, &bw);
10687
+ if (err < 0) {
10688
+ WL_ERR(("Failed to get bandwidth information, err=%d\n", err));
10689
+ return err;
10690
+ }
10691
+
676510692 set_channel:
676610693 chspec = wf_channel2chspec(_chan, bw);
676710694 if (wf_chspec_valid(chspec)) {
....@@ -6771,8 +10698,8 @@
677110698 fw_chspec)) == BCME_BADCHAN) {
677210699 if (bw == WL_CHANSPEC_BW_80)
677310700 goto change_bw;
6774
- err = wldev_ioctl(dev, WLC_SET_CHANNEL,
6775
- &_chan, sizeof(_chan), true);
10701
+ err = wldev_ioctl_set(dev, WLC_SET_CHANNEL,
10702
+ &_chan, sizeof(_chan));
677610703 if (err < 0) {
677710704 WL_ERR(("WLC_SET_CHANNEL error %d"
677810705 "chip may not be supporting this channel\n", err));
....@@ -6780,6 +10707,20 @@
678010707 } else if (err) {
678110708 WL_ERR(("failed to set chanspec error %d\n", err));
678210709 }
10710
+#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
10711
+ else {
10712
+ /* Disable Frameburst only for stand-alone 2GHz SoftAP */
10713
+ if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP &&
10714
+ DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
10715
+ (_chan <= CH_MAX_2G_CHANNEL) &&
10716
+ !wl_get_drv_status(cfg, CONNECTED,
10717
+ bcmcfg_to_prmry_ndev(cfg))) {
10718
+ WL_DBG(("Disabling frameburst on "
10719
+ "stand-alone 2GHz SoftAP\n"));
10720
+ wl_cfg80211_set_frameburst(cfg, FALSE);
10721
+ }
10722
+ }
10723
+#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
678310724 } else {
678410725 WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
678510726 err = BCME_ERROR;
....@@ -6814,6 +10755,14 @@
681410755 }
681510756 }
681610757 #endif /* CUSTOM_SET_CPUCORE */
10758
+ if (!err && (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
10759
+ /* Update AP/GO operating channel */
10760
+ cfg->ap_oper_channel = ieee80211_frequency_to_channel(chan->center_freq);
10761
+ }
10762
+ if (err) {
10763
+ wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
10764
+ FW_LOGSET_MASK_ALL);
10765
+ }
681710766 return err;
681810767 }
681910768
....@@ -6822,14 +10771,49 @@
682210771 wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
682310772 {
682410773 struct net_info *_net_info, *next;
10774
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
682510775 list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
10776
+ GCC_DIAGNOSTIC_POP();
682610777 if (_net_info->ndev &&
682710778 test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
682810779 return _net_info->ndev;
682910780 }
10781
+
683010782 return NULL;
683110783 }
683210784 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
10785
+
10786
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
10787
+#ifdef BCMWAPI_WPI
10788
+static s32
10789
+wl_validate_wapisecurity(struct net_device *dev, s32 bssidx)
10790
+{
10791
+ s32 err = BCME_OK;
10792
+
10793
+ /* set auth */
10794
+ err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
10795
+ if (err < 0) {
10796
+ WL_ERR(("WAPI auth error %d\n", err));
10797
+ return BCME_ERROR;
10798
+ }
10799
+
10800
+ /* set wsec */
10801
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", SMS4_ENABLED, bssidx);
10802
+ if (err < 0) {
10803
+ WL_ERR(("WAPI wsec error %d\n", err));
10804
+ return BCME_ERROR;
10805
+ }
10806
+
10807
+ /* set upper-layer auth */
10808
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WAPI_AUTH_PSK, bssidx);
10809
+ if (err < 0) {
10810
+ WL_ERR(("WAPI wpa_auth error %d\n", err));
10811
+ return BCME_ERROR;
10812
+ }
10813
+ return 0;
10814
+}
10815
+#endif /* BCMWAPI_WPI */
10816
+#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
683310817
683410818 static s32
683510819 wl_validate_opensecurity(struct net_device *dev, s32 bssidx, bool privacy)
....@@ -6872,8 +10856,65 @@
687210856 return 0;
687310857 }
687410858
10859
+#define MAX_FILS_IND_IE_LEN 1024u
687510860 static s32
6876
-wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
10861
+wl_validate_fils_ind_ie(struct net_device *dev, const bcm_tlv_t *filsindie, s32 bssidx)
10862
+{
10863
+ s32 err = BCME_OK;
10864
+ struct bcm_cfg80211 *cfg = NULL;
10865
+ bcm_iov_buf_t *iov_buf = NULL;
10866
+ bcm_xtlv_t* pxtlv;
10867
+ int iov_buf_size = 0;
10868
+
10869
+ if (!dev || !filsindie) {
10870
+ WL_ERR(("%s: dev/filsidie is null\n", __FUNCTION__));
10871
+ goto exit;
10872
+ }
10873
+
10874
+ cfg = wl_get_cfg(dev);
10875
+ if (!cfg) {
10876
+ WL_ERR(("%s: cfg is null\n", __FUNCTION__));
10877
+ goto exit;
10878
+ }
10879
+
10880
+ iov_buf_size = sizeof(bcm_iov_buf_t) + sizeof(bcm_xtlv_t) + filsindie->len - 1;
10881
+ iov_buf = MALLOCZ(cfg->osh, iov_buf_size);
10882
+ if (!iov_buf) {
10883
+ WL_ERR(("%s: iov_buf alloc failed! %d bytes\n", __FUNCTION__, iov_buf_size));
10884
+ err = BCME_NOMEM;
10885
+ goto exit;
10886
+ }
10887
+ iov_buf->version = WL_FILS_IOV_VERSION;
10888
+ iov_buf->id = WL_FILS_CMD_ADD_IND_IE;
10889
+ iov_buf->len = sizeof(bcm_xtlv_t) + filsindie->len - 1;
10890
+ pxtlv = (bcm_xtlv_t*)&iov_buf->data[0];
10891
+ pxtlv->id = WL_FILS_XTLV_IND_IE;
10892
+ pxtlv->len = filsindie->len;
10893
+ /* memcpy_s return check not required as buffer is allocated based on ie
10894
+ * len
10895
+ */
10896
+ (void)memcpy_s(pxtlv->data, filsindie->len, filsindie->data, filsindie->len);
10897
+
10898
+ err = wldev_iovar_setbuf(dev, "fils", iov_buf, iov_buf_size,
10899
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
10900
+ if (unlikely(err)) {
10901
+ WL_ERR(("fils indication ioctl error (%d)\n", err));
10902
+ goto exit;
10903
+ }
10904
+
10905
+exit:
10906
+ if (err < 0) {
10907
+ WL_ERR(("FILS Ind setting error %d\n", err));
10908
+ }
10909
+
10910
+ if (iov_buf) {
10911
+ MFREE(cfg->osh, iov_buf, iov_buf_size);
10912
+ }
10913
+ return err;
10914
+}
10915
+
10916
+static s32
10917
+wl_validate_wpa2ie(struct net_device *dev, const bcm_tlv_t *wpa2ie, s32 bssidx)
687710918 {
687810919 s32 len = 0;
687910920 s32 err = BCME_OK;
....@@ -6882,14 +10923,14 @@
688210923 u32 pval = 0;
688310924 u32 gval = 0;
688410925 u32 wpa_auth = 0;
6885
- wpa_suite_mcast_t *mcast;
6886
- wpa_suite_ucast_t *ucast;
6887
- wpa_suite_auth_key_mgmt_t *mgmt;
6888
- wpa_pmkid_list_t *pmkid;
10926
+ const wpa_suite_mcast_t *mcast;
10927
+ const wpa_suite_ucast_t *ucast;
10928
+ const wpa_suite_auth_key_mgmt_t *mgmt;
10929
+ const wpa_pmkid_list_t *pmkid;
688910930 int cnt = 0;
689010931 #ifdef MFP
689110932 int mfp = 0;
6892
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
10933
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
689310934 #endif /* MFP */
689410935
689510936 u16 suite_count;
....@@ -6902,7 +10943,7 @@
690210943 WL_DBG(("Enter \n"));
690310944 len = wpa2ie->len - WPA2_VERSION_LEN;
690410945 /* check the mcast cipher */
6905
- mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
10946
+ mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
690610947 switch (mcast->type) {
690710948 case WPA_CIPHER_NONE:
690810949 gval = 0;
....@@ -6917,6 +10958,14 @@
691710958 case WPA_CIPHER_AES_CCM:
691810959 gval = AES_ENABLED;
691910960 break;
10961
+#ifdef BCMWAPI_WPI
10962
+ case WAPI_CIPHER_SMS4:
10963
+ gval = SMS4_ENABLED;
10964
+ break;
10965
+#endif // endif
10966
+ case WPA_CIPHER_AES_GCM256:
10967
+ gval = AES_GCMP256;
10968
+ break;
692010969 default:
692110970 WL_ERR(("No Security Info\n"));
692210971 break;
....@@ -6925,7 +10974,7 @@
692510974 return BCME_BADLEN;
692610975
692710976 /* check the unicast cipher */
6928
- ucast = (wpa_suite_ucast_t *)&mcast[1];
10977
+ ucast = (const wpa_suite_ucast_t *)&mcast[1];
692910978 suite_count = ltoh16_ua(&ucast->count);
693010979 switch (ucast->list[0].type) {
693110980 case WPA_CIPHER_NONE:
....@@ -6941,6 +10990,14 @@
694110990 case WPA_CIPHER_AES_CCM:
694210991 pval = AES_ENABLED;
694310992 break;
10993
+#ifdef BCMWAPI_WPI
10994
+ case WAPI_CIPHER_SMS4:
10995
+ pval = SMS4_ENABLED;
10996
+ break;
10997
+#endif // endif
10998
+ case WPA_CIPHER_AES_GCM256:
10999
+ pval = AES_GCMP256;
11000
+ break;
694411001 default:
694511002 WL_ERR(("No Security Info\n"));
694611003 }
....@@ -6950,35 +11007,52 @@
695011007 /* FOR WPS , set SEC_OW_ENABLED */
695111008 wsec = (pval | gval | SES_OW_ENABLED);
695211009 /* check the AKM */
6953
- mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
11010
+ mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
695411011 suite_count = cnt = ltoh16_ua(&mgmt->count);
695511012 while (cnt--) {
11013
+ if (!bcmp(mgmt->list[cnt].oui, WPA2_OUI, WPA2_OUI_LEN)) {
695611014 switch (mgmt->list[cnt].type) {
695711015 case RSN_AKM_NONE:
6958
- wpa_auth |= WPA_AUTH_NONE;
11016
+ wpa_auth |= WPA_AUTH_NONE;
695911017 break;
696011018 case RSN_AKM_UNSPECIFIED:
6961
- wpa_auth |= WPA2_AUTH_UNSPECIFIED;
11019
+ wpa_auth |= WPA2_AUTH_UNSPECIFIED;
696211020 break;
696311021 case RSN_AKM_PSK:
6964
- wpa_auth |= WPA2_AUTH_PSK;
6965
- break;
6966
-#ifdef MFP
6967
- case RSN_AKM_MFP_PSK:
6968
- wpa_auth |= WPA2_AUTH_PSK_SHA256;
6969
- break;
6970
- case RSN_AKM_MFP_1X:
6971
- wpa_auth |= WPA2_AUTH_1X_SHA256;
11022
+ wpa_auth |= WPA2_AUTH_PSK;
697211023 break;
11024
+#ifdef MFP
11025
+ case RSN_AKM_MFP_PSK:
11026
+ wpa_auth |= WPA2_AUTH_PSK_SHA256;
11027
+ break;
11028
+ case RSN_AKM_MFP_1X:
11029
+ wpa_auth |= WPA2_AUTH_1X_SHA256;
11030
+ break;
11031
+ case RSN_AKM_FILS_SHA256:
11032
+ wpa_auth |= WPA2_AUTH_FILS_SHA256;
11033
+ break;
11034
+ case RSN_AKM_FILS_SHA384:
11035
+ wpa_auth |= WPA2_AUTH_FILS_SHA384;
11036
+ break;
11037
+#ifdef WL_SAE
11038
+ case RSN_AKM_SAE_PSK:
11039
+ wpa_auth |= WPA3_AUTH_SAE_PSK;
11040
+ break;
11041
+ case RSN_AKM_SUITEB_SHA384_1X:
11042
+ wpa_auth |= WPA3_AUTH_1X_SUITE_B_SHA384;
11043
+ break;
11044
+#endif /* WL_SAE */
697311045 #endif /* MFP */
697411046 default:
697511047 WL_ERR(("No Key Mgmt Info\n"));
697611048 }
11049
+ } else if (!bcmp(mgmt->list[cnt].oui, WFA_OUI, WFA_OUI_LEN))
11050
+ wpa_auth |= WPA2_WFA_AUTH_DPP;
697711051 }
697811052
697911053 if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
6980
- rsn_cap[0] = *(u8 *)&mgmt->list[suite_count];
6981
- rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1);
11054
+ rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
11055
+ rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
698211056
698311057 if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
698411058 wme_bss_disable = 0;
....@@ -7016,7 +11090,8 @@
701611090
701711091 len -= RSN_CAP_LEN;
701811092 if (len >= WPA2_PMKID_COUNT_LEN) {
7019
- pmkid = (wpa_pmkid_list_t *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
11093
+ pmkid = (const wpa_pmkid_list_t *)
11094
+ ((const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
702011095 cnt = ltoh16_ua(&pmkid->count);
702111096 if (cnt != 0) {
702211097 WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
....@@ -7029,16 +11104,12 @@
702911104 #ifdef MFP
703011105 len -= WPA2_PMKID_COUNT_LEN;
703111106 if (len >= WPA_SUITE_LEN) {
7032
- err = wldev_iovar_setbuf_bsscfg(dev, "bip",
7033
- (void *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN),
7034
- WPA_SUITE_LEN,
7035
- cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
7036
- if (err < 0) {
7037
- WL_ERR(("bip set error %d\n", err));
7038
- return BCME_ERROR;
7039
- }
11107
+ cfg->bip_pos =
11108
+ (const u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN;
11109
+ } else {
11110
+ cfg->bip_pos = NULL;
704011111 }
7041
-#endif
11112
+#endif // endif
704211113
704311114 /* set auth */
704411115 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
....@@ -7055,15 +11126,7 @@
705511126 }
705611127
705711128 #ifdef MFP
7058
- if (mfp) {
7059
- /* This needs to go after wsec otherwise the wsec command will
7060
- * overwrite the values set by MFP
7061
- */
7062
- if ((err = wldev_iovar_setint_bsscfg(dev, "mfp", mfp, bssidx)) < 0) {
7063
- WL_ERR(("MFP Setting failed. ret = %d \n", err));
7064
- return err;
7065
- }
7066
- }
11129
+ cfg->mfp_mode = mfp;
706711130 #endif /* MFP */
706811131
706911132 /* set upper-layer auth */
....@@ -7077,11 +11140,11 @@
707711140 }
707811141
707911142 static s32
7080
-wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
11143
+wl_validate_wpaie(struct net_device *dev, const wpa_ie_fixed_t *wpaie, s32 bssidx)
708111144 {
7082
- wpa_suite_mcast_t *mcast;
7083
- wpa_suite_ucast_t *ucast;
7084
- wpa_suite_auth_key_mgmt_t *mgmt;
11145
+ const wpa_suite_mcast_t *mcast;
11146
+ const wpa_suite_ucast_t *ucast;
11147
+ const wpa_suite_auth_key_mgmt_t *mgmt;
708511148 u16 auth = 0; /* d11 open authentication */
708611149 u16 count;
708711150 s32 err = BCME_OK;
....@@ -7100,12 +11163,12 @@
710011163 len -= WPA_IE_TAG_FIXED_LEN;
710111164 /* check for multicast cipher suite */
710211165 if (len < WPA_SUITE_LEN) {
7103
- WL_INFORM(("no multicast cipher suite\n"));
11166
+ WL_INFORM_MEM(("no multicast cipher suite\n"));
710411167 goto exit;
710511168 }
710611169
710711170 /* pick up multicast cipher */
7108
- mcast = (wpa_suite_mcast_t *)&wpaie[1];
11171
+ mcast = (const wpa_suite_mcast_t *)&wpaie[1];
710911172 len -= WPA_SUITE_LEN;
711011173 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
711111174 if (IS_WPA_CIPHER(mcast->type)) {
....@@ -7132,11 +11195,11 @@
713211195 }
713311196 /* Check for unicast suite(s) */
713411197 if (len < WPA_IE_SUITE_COUNT_LEN) {
7135
- WL_INFORM(("no unicast suite\n"));
11198
+ WL_INFORM_MEM(("no unicast suite\n"));
713611199 goto exit;
713711200 }
713811201 /* walk thru unicast cipher list and pick up what we recognize */
7139
- ucast = (wpa_suite_ucast_t *)&mcast[1];
11202
+ ucast = (const wpa_suite_ucast_t *)&mcast[1];
714011203 count = ltoh16_ua(&ucast->count);
714111204 len -= WPA_IE_SUITE_COUNT_LEN;
714211205 for (i = 0; i < count && len >= WPA_SUITE_LEN;
....@@ -7168,11 +11231,11 @@
716811231 len -= (count - i) * WPA_SUITE_LEN;
716911232 /* Check for auth key management suite(s) */
717011233 if (len < WPA_IE_SUITE_COUNT_LEN) {
7171
- WL_INFORM((" no auth key mgmt suite\n"));
11234
+ WL_INFORM_MEM((" no auth key mgmt suite\n"));
717211235 goto exit;
717311236 }
717411237 /* walk thru auth management suite list and pick up what we recognize */
7175
- mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
11238
+ mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
717611239 count = ltoh16_ua(&mgmt->count);
717711240 len -= WPA_IE_SUITE_COUNT_LEN;
717811241 for (i = 0; i < count && len >= WPA_SUITE_LEN;
....@@ -7222,6 +11285,249 @@
722211285 return 0;
722311286 }
722411287
11288
+#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11289
+static u32 wl_get_cipher_type(uint8 type)
11290
+{
11291
+ u32 ret = 0;
11292
+ switch (type) {
11293
+ case WPA_CIPHER_NONE:
11294
+ ret = 0;
11295
+ break;
11296
+ case WPA_CIPHER_WEP_40:
11297
+ case WPA_CIPHER_WEP_104:
11298
+ ret = WEP_ENABLED;
11299
+ break;
11300
+ case WPA_CIPHER_TKIP:
11301
+ ret = TKIP_ENABLED;
11302
+ break;
11303
+ case WPA_CIPHER_AES_CCM:
11304
+ ret = AES_ENABLED;
11305
+ break;
11306
+#ifdef BCMWAPI_WPI
11307
+ case WAPI_CIPHER_SMS4:
11308
+ ret = SMS4_ENABLED;
11309
+ break;
11310
+#endif // endif
11311
+ default:
11312
+ WL_ERR(("No Security Info\n"));
11313
+ }
11314
+ return ret;
11315
+}
11316
+
11317
+static u32 wl_get_suite_auth_key_mgmt_type(uint8 type, const wpa_suite_mcast_t *mcast)
11318
+{
11319
+ u32 ret = 0;
11320
+ u32 is_wpa2 = 0;
11321
+
11322
+ if (!bcmp(mcast->oui, WPA2_OUI, WPA2_OUI_LEN)) {
11323
+ is_wpa2 = 1;
11324
+ }
11325
+
11326
+ WL_INFORM_MEM(("%s, type = %d\n", is_wpa2 ? "WPA2":"WPA", type));
11327
+ switch (type) {
11328
+ case RSN_AKM_NONE:
11329
+ /* For WPA and WPA2, AUTH_NONE is common */
11330
+ ret = WPA_AUTH_NONE;
11331
+ break;
11332
+ case RSN_AKM_UNSPECIFIED:
11333
+ if (is_wpa2) {
11334
+ ret = WPA2_AUTH_UNSPECIFIED;
11335
+ } else {
11336
+ ret = WPA_AUTH_UNSPECIFIED;
11337
+ }
11338
+ break;
11339
+ case RSN_AKM_PSK:
11340
+ if (is_wpa2) {
11341
+ ret = WPA2_AUTH_PSK;
11342
+ } else {
11343
+ ret = WPA_AUTH_PSK;
11344
+ }
11345
+ break;
11346
+#ifdef WL_SAE
11347
+ case RSN_AKM_SAE_PSK:
11348
+ ret = WPA3_AUTH_SAE_PSK;
11349
+ break;
11350
+#endif /* WL_SAE */
11351
+ default:
11352
+ WL_ERR(("No Key Mgmt Info\n"));
11353
+ }
11354
+
11355
+ return ret;
11356
+}
11357
+
11358
+static s32
11359
+wl_validate_wpaie_wpa2ie(struct net_device *dev, const wpa_ie_fixed_t *wpaie,
11360
+ const bcm_tlv_t *wpa2ie, s32 bssidx)
11361
+{
11362
+ const wpa_suite_mcast_t *mcast;
11363
+ const wpa_suite_ucast_t *ucast;
11364
+ const wpa_suite_auth_key_mgmt_t *mgmt;
11365
+ u16 auth = 0; /* d11 open authentication */
11366
+ u16 count;
11367
+ s32 err = BCME_OK;
11368
+ u32 wme_bss_disable;
11369
+ u16 suite_count;
11370
+ u8 rsn_cap[2];
11371
+ s32 len = 0;
11372
+ u32 i;
11373
+ u32 wsec1, wsec2, wsec;
11374
+ u32 pval = 0;
11375
+ u32 gval = 0;
11376
+ u32 wpa_auth = 0;
11377
+ u32 wpa_auth1 = 0;
11378
+ u32 wpa_auth2 = 0;
11379
+
11380
+ if (wpaie == NULL || wpa2ie == NULL)
11381
+ goto exit;
11382
+
11383
+ WL_DBG(("Enter \n"));
11384
+ len = wpaie->length; /* value length */
11385
+ len -= WPA_IE_TAG_FIXED_LEN;
11386
+ /* check for multicast cipher suite */
11387
+ if (len < WPA_SUITE_LEN) {
11388
+ WL_INFORM_MEM(("no multicast cipher suite\n"));
11389
+ goto exit;
11390
+ }
11391
+
11392
+ /* pick up multicast cipher */
11393
+ mcast = (const wpa_suite_mcast_t *)&wpaie[1];
11394
+ len -= WPA_SUITE_LEN;
11395
+ if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
11396
+ if (IS_WPA_CIPHER(mcast->type)) {
11397
+ gval |= wl_get_cipher_type(mcast->type);
11398
+ }
11399
+ }
11400
+ WL_DBG(("\nwpa ie validate\n"));
11401
+ WL_DBG(("wpa ie mcast cipher = 0x%X\n", gval));
11402
+
11403
+ /* Check for unicast suite(s) */
11404
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
11405
+ WL_INFORM_MEM(("no unicast suite\n"));
11406
+ goto exit;
11407
+ }
11408
+
11409
+ /* walk thru unicast cipher list and pick up what we recognize */
11410
+ ucast = (const wpa_suite_ucast_t *)&mcast[1];
11411
+ count = ltoh16_ua(&ucast->count);
11412
+ len -= WPA_IE_SUITE_COUNT_LEN;
11413
+ for (i = 0; i < count && len >= WPA_SUITE_LEN;
11414
+ i++, len -= WPA_SUITE_LEN) {
11415
+ if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
11416
+ if (IS_WPA_CIPHER(ucast->list[i].type)) {
11417
+ pval |= wl_get_cipher_type(ucast->list[i].type);
11418
+ }
11419
+ }
11420
+ }
11421
+ WL_ERR(("wpa ie ucast count =%d, cipher = 0x%X\n", count, pval));
11422
+
11423
+ /* FOR WPS , set SEC_OW_ENABLED */
11424
+ wsec1 = (pval | gval | SES_OW_ENABLED);
11425
+ WL_ERR(("wpa ie wsec = 0x%X\n", wsec1));
11426
+
11427
+ len -= (count - i) * WPA_SUITE_LEN;
11428
+ /* Check for auth key management suite(s) */
11429
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
11430
+ WL_INFORM_MEM((" no auth key mgmt suite\n"));
11431
+ goto exit;
11432
+ }
11433
+ /* walk thru auth management suite list and pick up what we recognize */
11434
+ mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
11435
+ count = ltoh16_ua(&mgmt->count);
11436
+ len -= WPA_IE_SUITE_COUNT_LEN;
11437
+ for (i = 0; i < count && len >= WPA_SUITE_LEN;
11438
+ i++, len -= WPA_SUITE_LEN) {
11439
+ if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
11440
+ if (IS_WPA_AKM(mgmt->list[i].type)) {
11441
+ wpa_auth1 |=
11442
+ wl_get_suite_auth_key_mgmt_type(mgmt->list[i].type, mcast);
11443
+ }
11444
+ }
11445
+
11446
+ }
11447
+ WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth1));
11448
+ WL_ERR(("\nwpa2 ie validate\n"));
11449
+
11450
+ pval = 0;
11451
+ gval = 0;
11452
+ len = wpa2ie->len;
11453
+ /* check the mcast cipher */
11454
+ mcast = (const wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
11455
+ gval = wl_get_cipher_type(mcast->type);
11456
+
11457
+ WL_ERR(("wpa2 ie mcast cipher = 0x%X\n", gval));
11458
+ if ((len -= WPA_SUITE_LEN) <= 0)
11459
+ {
11460
+ WL_ERR(("P:wpa2 ie len[%d]", len));
11461
+ return BCME_BADLEN;
11462
+ }
11463
+
11464
+ /* check the unicast cipher */
11465
+ ucast = (const wpa_suite_ucast_t *)&mcast[1];
11466
+ suite_count = ltoh16_ua(&ucast->count);
11467
+ WL_ERR((" WPA2 ucast cipher count=%d\n", suite_count));
11468
+ pval |= wl_get_cipher_type(ucast->list[0].type);
11469
+
11470
+ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
11471
+ return BCME_BADLEN;
11472
+
11473
+ WL_ERR(("wpa2 ie ucast cipher = 0x%X\n", pval));
11474
+
11475
+ /* FOR WPS , set SEC_OW_ENABLED */
11476
+ wsec2 = (pval | gval | SES_OW_ENABLED);
11477
+ WL_ERR(("wpa2 ie wsec = 0x%X\n", wsec2));
11478
+
11479
+ /* check the AKM */
11480
+ mgmt = (const wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
11481
+ suite_count = ltoh16_ua(&mgmt->count);
11482
+ wpa_auth2 = wl_get_suite_auth_key_mgmt_type(mgmt->list[0].type, mcast);
11483
+ WL_ERR(("wpa ie wpa_suite_auth_key_mgmt count=%d, key_mgmt = 0x%X\n", count, wpa_auth2));
11484
+
11485
+ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
11486
+ rsn_cap[0] = *(const u8 *)&mgmt->list[suite_count];
11487
+ rsn_cap[1] = *((const u8 *)&mgmt->list[suite_count] + 1);
11488
+ if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
11489
+ wme_bss_disable = 0;
11490
+ } else {
11491
+ wme_bss_disable = 1;
11492
+ }
11493
+ WL_DBG(("P:rsn_cap[0]=[0x%X]:wme_bss_disabled[%d]\n", rsn_cap[0], wme_bss_disable));
11494
+
11495
+ /* set wme_bss_disable to sync RSN Capabilities */
11496
+ err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
11497
+ if (err < 0) {
11498
+ WL_ERR(("wme_bss_disable error %d\n", err));
11499
+ return BCME_ERROR;
11500
+ }
11501
+ } else {
11502
+ WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
11503
+ }
11504
+
11505
+ wsec = (wsec1 | wsec2);
11506
+ wpa_auth = (wpa_auth1 | wpa_auth2);
11507
+ WL_ERR(("wpa_wpa2 wsec=0x%X wpa_auth=0x%X\n", wsec, wpa_auth));
11508
+
11509
+ /* set auth */
11510
+ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
11511
+ if (err < 0) {
11512
+ WL_ERR(("auth error %d\n", err));
11513
+ return BCME_ERROR;
11514
+ }
11515
+ /* set wsec */
11516
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
11517
+ if (err < 0) {
11518
+ WL_ERR(("wsec error %d\n", err));
11519
+ return BCME_ERROR;
11520
+ }
11521
+ /* set upper-layer auth */
11522
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
11523
+ if (err < 0) {
11524
+ WL_ERR(("wpa_auth error %d\n", err));
11525
+ return BCME_ERROR;
11526
+ }
11527
+exit:
11528
+ return 0;
11529
+}
11530
+#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
722511531
722611532 static s32
722711533 wl_cfg80211_bcn_validate_sec(
....@@ -7231,7 +11537,7 @@
723111537 s32 bssidx,
723211538 bool privacy)
723311539 {
7234
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
11540
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
723511541 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
723611542
723711543 if (!bss) {
....@@ -7250,6 +11556,15 @@
725011556 WL_DBG(("SoftAP: validating security"));
725111557 /* If wpa2_ie or wpa_ie is present validate it */
725211558
11559
+#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11560
+ if ((ies->wpa_ie != NULL && ies->wpa2_ie != NULL)) {
11561
+ if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie, ies->wpa2_ie, bssidx) < 0) {
11562
+ bss->security_mode = false;
11563
+ return BCME_ERROR;
11564
+ }
11565
+ }
11566
+ else {
11567
+#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
725311568 if ((ies->wpa2_ie || ies->wpa_ie) &&
725411569 ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
725511570 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
....@@ -7257,39 +11572,79 @@
725711572 return BCME_ERROR;
725811573 }
725911574
11575
+ if (ies->fils_ind_ie &&
11576
+ (wl_validate_fils_ind_ie(dev, ies->fils_ind_ie, bssidx) < 0)) {
11577
+ bss->security_mode = false;
11578
+ return BCME_ERROR;
11579
+ }
11580
+
726011581 bss->security_mode = true;
726111582 if (bss->rsn_ie) {
7262
- kfree(bss->rsn_ie);
11583
+ MFREE(cfg->osh, bss->rsn_ie, bss->rsn_ie[1]
11584
+ + WPA_RSN_IE_TAG_FIXED_LEN);
726311585 bss->rsn_ie = NULL;
726411586 }
726511587 if (bss->wpa_ie) {
7266
- kfree(bss->wpa_ie);
11588
+ MFREE(cfg->osh, bss->wpa_ie, bss->wpa_ie[1]
11589
+ + WPA_RSN_IE_TAG_FIXED_LEN);
726711590 bss->wpa_ie = NULL;
726811591 }
726911592 if (bss->wps_ie) {
7270
- kfree(bss->wps_ie);
11593
+ MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
727111594 bss->wps_ie = NULL;
11595
+ }
11596
+ if (bss->fils_ind_ie) {
11597
+ MFREE(cfg->osh, bss->fils_ind_ie, bss->fils_ind_ie[1]
11598
+ + FILS_INDICATION_IE_TAG_FIXED_LEN);
727211599 }
727311600 if (ies->wpa_ie != NULL) {
727411601 /* WPAIE */
727511602 bss->rsn_ie = NULL;
7276
- bss->wpa_ie = kmemdup(ies->wpa_ie,
7277
- ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
7278
- GFP_KERNEL);
11603
+ bss->wpa_ie = MALLOCZ(cfg->osh,
11604
+ ies->wpa_ie->length
11605
+ + WPA_RSN_IE_TAG_FIXED_LEN);
11606
+ if (bss->wpa_ie) {
11607
+ memcpy(bss->wpa_ie, ies->wpa_ie,
11608
+ ies->wpa_ie->length
11609
+ + WPA_RSN_IE_TAG_FIXED_LEN);
11610
+ }
727911611 } else if (ies->wpa2_ie != NULL) {
728011612 /* RSNIE */
728111613 bss->wpa_ie = NULL;
7282
- bss->rsn_ie = kmemdup(ies->wpa2_ie,
7283
- ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
7284
- GFP_KERNEL);
11614
+ bss->rsn_ie = MALLOCZ(cfg->osh,
11615
+ ies->wpa2_ie->len
11616
+ + WPA_RSN_IE_TAG_FIXED_LEN);
11617
+ if (bss->rsn_ie) {
11618
+ memcpy(bss->rsn_ie, ies->wpa2_ie,
11619
+ ies->wpa2_ie->len
11620
+ + WPA_RSN_IE_TAG_FIXED_LEN);
11621
+ }
728511622 }
11623
+#ifdef WL_FILS
11624
+ if (ies->fils_ind_ie) {
11625
+ bss->fils_ind_ie = MALLOCZ(cfg->osh,
11626
+ ies->fils_ind_ie->len
11627
+ + FILS_INDICATION_IE_TAG_FIXED_LEN);
11628
+ if (bss->fils_ind_ie) {
11629
+ memcpy(bss->fils_ind_ie, ies->fils_ind_ie,
11630
+ ies->fils_ind_ie->len
11631
+ + FILS_INDICATION_IE_TAG_FIXED_LEN);
11632
+ }
11633
+ }
11634
+#endif /* WL_FILS */
11635
+#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
11636
+ }
11637
+#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
728611638 if (!ies->wpa2_ie && !ies->wpa_ie) {
728711639 wl_validate_opensecurity(dev, bssidx, privacy);
728811640 bss->security_mode = false;
728911641 }
729011642
729111643 if (ies->wps_ie) {
7292
- bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
11644
+ bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
11645
+ if (bss->wps_ie) {
11646
+ memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
11647
+ }
729311648 }
729411649 }
729511650
....@@ -7297,66 +11652,60 @@
729711652
729811653 }
729911654
7300
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
11655
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
730111656 static s32 wl_cfg80211_bcn_set_params(
730211657 struct cfg80211_ap_settings *info,
730311658 struct net_device *dev,
730411659 u32 dev_role, s32 bssidx)
730511660 {
7306
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
11661
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
730711662 s32 err = BCME_OK;
730811663
730911664 WL_DBG(("interval (%d) \ndtim_period (%d) \n",
731011665 info->beacon_interval, info->dtim_period));
731111666
731211667 if (info->beacon_interval) {
7313
- if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD,
7314
- &info->beacon_interval, sizeof(s32), true)) < 0) {
11668
+ if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
11669
+ &info->beacon_interval, sizeof(s32))) < 0) {
731511670 WL_ERR(("Beacon Interval Set Error, %d\n", err));
731611671 return err;
731711672 }
731811673 }
731911674
732011675 if (info->dtim_period) {
7321
- if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD,
7322
- &info->dtim_period, sizeof(s32), true)) < 0) {
11676
+ if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
11677
+ &info->dtim_period, sizeof(s32))) < 0) {
732311678 WL_ERR(("DTIM Interval Set Error, %d\n", err));
732411679 return err;
732511680 }
732611681 }
732711682
732811683 if ((info->ssid) && (info->ssid_len > 0) &&
7329
- (info->ssid_len <= 32)) {
11684
+ (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
733011685 WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
733111686 if (dev_role == NL80211_IFTYPE_AP) {
733211687 /* Store the hostapd SSID */
7333
- memset(cfg->hostapd_ssid.SSID, 0x00, 32);
11688
+ bzero(cfg->hostapd_ssid.SSID, DOT11_MAX_SSID_LEN);
733411689 memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
7335
- cfg->hostapd_ssid.SSID_len = info->ssid_len;
11690
+ cfg->hostapd_ssid.SSID_len = (uint32)info->ssid_len;
733611691 } else {
733711692 /* P2P GO */
7338
- memset(cfg->p2p->ssid.SSID, 0x00, 32);
11693
+ bzero(cfg->p2p->ssid.SSID, DOT11_MAX_SSID_LEN);
733911694 memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
7340
- cfg->p2p->ssid.SSID_len = info->ssid_len;
11695
+ cfg->p2p->ssid.SSID_len = (uint32)info->ssid_len;
734111696 }
7342
- }
7343
-
7344
- if (info->hidden_ssid) {
7345
- if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
7346
- WL_ERR(("failed to set hidden : %d\n", err));
7347
- WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
734811697 }
734911698
735011699 return err;
735111700 }
7352
-#endif
11701
+#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
735311702
735411703 static s32
7355
-wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies)
11704
+wl_cfg80211_parse_ies(const u8 *ptr, u32 len, struct parsed_ies *ies)
735611705 {
735711706 s32 err = BCME_OK;
735811707
7359
- memset(ies, 0, sizeof(struct parsed_ies));
11708
+ bzero(ies, sizeof(struct parsed_ies));
736011709
736111710 /* find the WPSIE */
736211711 if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
....@@ -7373,6 +11722,13 @@
737311722 ies->wpa2_ie_len = ies->wpa2_ie->len;
737411723 }
737511724
11725
+ /* find the FILS_IND_IE */
11726
+ if ((ies->fils_ind_ie = bcm_parse_tlvs(ptr, len,
11727
+ DOT11_MNG_FILS_IND_ID)) != NULL) {
11728
+ WL_DBG((" FILS IND IE found\n"));
11729
+ ies->fils_ind_ie_len = ies->fils_ind_ie->len;
11730
+ }
11731
+
737611732 /* find the WPA_IE */
737711733 if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
737811734 WL_DBG((" WPA found\n"));
....@@ -7382,43 +11738,152 @@
738211738 return err;
738311739
738411740 }
11741
+static s32
11742
+wl_cfg80211_set_ap_role(
11743
+ struct bcm_cfg80211 *cfg,
11744
+ struct net_device *dev)
11745
+{
11746
+ s32 err = BCME_OK;
11747
+ s32 infra = 1;
11748
+ s32 ap = 0;
11749
+ s32 pm;
11750
+ s32 bssidx;
11751
+ s32 apsta = 0;
738511752
11753
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11754
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
11755
+ return -EINVAL;
11756
+ }
11757
+
11758
+ WL_INFORM_MEM(("[%s] Bringup SoftAP on bssidx:%d \n", dev->name, bssidx));
11759
+
11760
+ if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
11761
+ WL_IF_TYPE_AP, 0, NULL)) < 0) {
11762
+ WL_ERR(("wl add_del_bss returned error:%d\n", err));
11763
+ return err;
11764
+ }
11765
+
11766
+ /*
11767
+ * For older chips, "bss" iovar does not support
11768
+ * bsscfg role change/upgradation, and still
11769
+ * return BCME_OK on attempt
11770
+ * Hence, below traditional way to handle the same
11771
+ */
11772
+
11773
+ if ((err = wldev_ioctl_get(dev,
11774
+ WLC_GET_AP, &ap, sizeof(s32))) < 0) {
11775
+ WL_ERR(("Getting AP mode failed %d \n", err));
11776
+ return err;
11777
+ }
11778
+
11779
+ if (!ap) {
11780
+ /* AP mode switch not supported. Try setting up AP explicitly */
11781
+ err = wldev_iovar_getint(dev, "apsta", (s32 *)&apsta);
11782
+ if (unlikely(err)) {
11783
+ WL_ERR(("Could not get apsta %d\n", err));
11784
+ return err;
11785
+ }
11786
+ if (apsta == 0) {
11787
+ /* If apsta is not set, set it */
11788
+
11789
+ /* Check for any connected interfaces before wl down */
11790
+ if (wl_get_drv_status_all(cfg, CONNECTED) > 0) {
11791
+ WL_ERR(("Concurrent i/f operational. can't do wl down"));
11792
+ return BCME_ERROR;
11793
+ }
11794
+ err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11795
+ if (err < 0) {
11796
+ WL_ERR(("WLC_DOWN error %d\n", err));
11797
+ return err;
11798
+ }
11799
+ err = wldev_iovar_setint(dev, "apsta", 1);
11800
+ if (err < 0) {
11801
+ WL_ERR(("wl apsta 0 error %d\n", err));
11802
+ return err;
11803
+ }
11804
+ ap = 1;
11805
+ if ((err = wldev_ioctl_set(dev,
11806
+ WLC_SET_AP, &ap, sizeof(s32))) < 0) {
11807
+ WL_ERR(("setting AP mode failed %d \n", err));
11808
+ return err;
11809
+ }
11810
+ }
11811
+ }
11812
+
11813
+ if (bssidx == 0) {
11814
+ pm = 0;
11815
+ if ((err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm))) != 0) {
11816
+ WL_ERR(("wl PM 0 returned error:%d\n", err));
11817
+ /* Ignore error, if any */
11818
+ err = BCME_OK;
11819
+ }
11820
+ err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11821
+ if (err < 0) {
11822
+ WL_ERR(("SET INFRA error %d\n", err));
11823
+ return err;
11824
+ }
11825
+ }
11826
+
11827
+ /* On success, mark AP creation in progress. */
11828
+ wl_set_drv_status(cfg, AP_CREATING, dev);
11829
+ return 0;
11830
+}
11831
+
11832
+/* In RSDB downgrade cases, the link up event can get delayed upto 7-8 secs */
11833
+#define MAX_AP_LINK_WAIT_TIME 10000
738611834 static s32
738711835 wl_cfg80211_bcn_bringup_ap(
738811836 struct net_device *dev,
738911837 struct parsed_ies *ies,
739011838 u32 dev_role, s32 bssidx)
739111839 {
7392
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
11840
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
739311841 struct wl_join_params join_params;
739411842 bool is_bssup = false;
739511843 s32 infra = 1;
739611844 s32 join_params_size = 0;
7397
- s32 ap = 1;
7398
- s32 pm;
739911845 s32 wsec;
11846
+#ifdef DISABLE_11H_SOFTAP
11847
+ s32 spect = 0;
11848
+#endif /* DISABLE_11H_SOFTAP */
11849
+#ifdef SOFTAP_UAPSD_OFF
11850
+ uint32 wme_apsd = 0;
11851
+#endif /* SOFTAP_UAPSD_OFF */
740011852 s32 err = BCME_OK;
740111853 s32 is_rsdb_supported = BCME_ERROR;
11854
+ long timeout;
11855
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11856
+#ifndef IGUANA_LEGACY_CHIPS
11857
+ s32 ap = 1;
11858
+#endif // endif
740211859
740311860 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
740411861 if (is_rsdb_supported < 0)
740511862 return (-ENODEV);
740611863
7407
- WL_DBG(("Enter dev_role:%d bssidx:%d\n", dev_role, bssidx));
11864
+ WL_DBG(("Enter dev_role:%d bssidx:%d ifname:%s\n", dev_role, bssidx, dev->name));
740811865
740911866 /* Common code for SoftAP and P2P GO */
7410
- wldev_iovar_setint(dev, "mpc", 0);
11867
+ wl_clr_drv_status(cfg, AP_CREATED, dev);
11868
+
11869
+ /* Make sure INFRA is set for AP/GO */
11870
+ err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
11871
+ if (err < 0) {
11872
+ WL_ERR(("SET INFRA error %d\n", err));
11873
+ goto exit;
11874
+ }
11875
+
11876
+ /* Do abort scan before creating GO */
11877
+ wl_cfg80211_scan_abort(cfg);
741111878
741211879 if (dev_role == NL80211_IFTYPE_P2P_GO) {
7413
- is_bssup = wl_cfgp2p_bss_isup(dev, bssidx);
11880
+ is_bssup = wl_cfg80211_bss_isup(dev, bssidx);
741411881 if (!is_bssup && (ies->wpa2_ie != NULL)) {
7415
-
7416
- err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
11882
+ err = wldev_iovar_setint_bsscfg(dev, "mpc", 0, bssidx);
741711883 if (err < 0) {
7418
- WL_ERR(("SET INFRA error %d\n", err));
11884
+ WL_ERR(("MPC setting failed, ret=%d\n", err));
741911885 goto exit;
742011886 }
7421
-
742211887 err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid,
742311888 sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
742411889 bssidx, &cfg->ioctl_buf_sync);
....@@ -7427,78 +11892,101 @@
742711892 goto exit;
742811893 }
742911894
7430
- /* Do abort scan before creating GO */
7431
- wl_cfg80211_scan_abort(cfg);
11895
+#ifdef MFP
11896
+ err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx);
11897
+ if (err < 0) {
11898
+ WL_ERR(("MFP Setting failed. ret = %d \n", err));
11899
+ /* If fw doesn't support mfp, Ignore the error */
11900
+ if (err != BCME_UNSUPPORTED) {
11901
+ goto exit;
11902
+ }
11903
+ }
11904
+#endif /* MFP */
743211905
7433
- if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) {
11906
+ if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
743411907 WL_ERR(("GO Bring up error %d\n", err));
743511908 goto exit;
743611909 }
743711910 } else
743811911 WL_DBG(("Bss is already up\n"));
7439
- } else if ((dev_role == NL80211_IFTYPE_AP) &&
7440
- (wl_get_drv_status(cfg, AP_CREATING, dev))) {
7441
- /* Device role SoftAP */
11912
+ } else if (dev_role == NL80211_IFTYPE_AP) {
744211913
7443
- WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
7444
-
7445
- if (bssidx == 0) {
7446
- /* AP on primary Interface */
7447
- if (is_rsdb_supported) {
7448
- if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
7449
- NL80211_IFTYPE_AP, 0, NULL)) < 0) {
7450
- WL_ERR(("wl add_del_bss returned error:%d\n", err));
7451
- goto exit;
7452
- }
7453
- } else if (is_rsdb_supported == 0) {
7454
- /* AP mode switch not supported. Try setting up AP explicitly */
7455
- err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true);
7456
- if (err < 0) {
7457
- WL_ERR(("WLC_DOWN error %d\n", err));
7458
- goto exit;
7459
- }
7460
- err = wldev_iovar_setint(dev, "apsta", 0);
7461
- if (err < 0) {
7462
- WL_ERR(("wl apsta 0 error %d\n", err));
7463
- goto exit;
7464
- }
7465
-
7466
- if ((err = wldev_ioctl(dev,
7467
- WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
7468
- WL_ERR(("setting AP mode failed %d \n", err));
7469
- goto exit;
7470
- }
7471
-
7472
- }
7473
-
7474
- pm = 0;
7475
- if ((err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true)) != 0) {
7476
- WL_ERR(("wl PM 0 returned error:%d\n", err));
11914
+ if (!wl_get_drv_status(cfg, AP_CREATING, dev)) {
11915
+ /* Make sure fw is in proper state */
11916
+ err = wl_cfg80211_set_ap_role(cfg, dev);
11917
+ if (unlikely(err)) {
11918
+ WL_ERR(("set ap role failed!\n"));
747711919 goto exit;
747811920 }
7479
-
7480
- err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
7481
- if (err < 0) {
7482
- WL_ERR(("SET INFRA error %d\n", err));
7483
- goto exit;
7484
- }
7485
- } else if (cfg->cfgdev_bssidx && (bssidx == cfg->cfgdev_bssidx)) {
7486
-
7487
- WL_DBG(("Bringup SoftAP on virtual Interface bssidx:%d \n", bssidx));
7488
-
7489
- if ((err = wl_cfg80211_add_del_bss(cfg, dev,
7490
- bssidx, NL80211_IFTYPE_AP, 0, NULL)) < 0) {
7491
- WL_ERR(("wl bss ap returned error:%d\n", err));
7492
- goto exit;
7493
- }
7494
-
749511921 }
749611922
7497
- err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
11923
+ /* Device role SoftAP */
11924
+ WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
11925
+ /* Clear the status bit after use */
11926
+ wl_clr_drv_status(cfg, AP_CREATING, dev);
11927
+
11928
+#ifdef DISABLE_11H_SOFTAP
11929
+ if (is_rsdb_supported == 0) {
11930
+ err = wldev_ioctl_set(dev, WLC_DOWN, &ap, sizeof(s32));
11931
+ if (err < 0) {
11932
+ WL_ERR(("WLC_DOWN error %d\n", err));
11933
+ goto exit;
11934
+ }
11935
+ }
11936
+ err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT,
11937
+ &spect, sizeof(s32));
11938
+ if (err < 0) {
11939
+ WL_ERR(("SET SPECT_MANAGMENT error %d\n", err));
11940
+ goto exit;
11941
+ }
11942
+#endif /* DISABLE_11H_SOFTAP */
11943
+
11944
+#ifdef WL_DISABLE_HE_SOFTAP
11945
+ err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, FALSE);
11946
+ if (err < 0) {
11947
+ WL_ERR(("failed to set he features, error=%d\n", err));
11948
+ }
11949
+#endif /* WL_DISABLE_HE_SOFTAP */
11950
+
11951
+#ifdef SOFTAP_UAPSD_OFF
11952
+ err = wldev_iovar_setbuf_bsscfg(dev, "wme_apsd", &wme_apsd, sizeof(wme_apsd),
11953
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11954
+ if (err < 0) {
11955
+ WL_ERR(("failed to disable uapsd, error=%d\n", err));
11956
+ }
11957
+#endif /* SOFTAP_UAPSD_OFF */
11958
+#ifndef IGUANA_LEGACY_CHIPS
11959
+ err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
749811960 if (unlikely(err)) {
749911961 WL_ERR(("WLC_UP error (%d)\n", err));
750011962 goto exit;
750111963 }
11964
+#endif // endif
11965
+#ifdef MFP
11966
+ if (cfg->bip_pos) {
11967
+ err = wldev_iovar_setbuf_bsscfg(dev, "bip",
11968
+ (const void *)(cfg->bip_pos), WPA_SUITE_LEN, cfg->ioctl_buf,
11969
+ WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
11970
+ if (err < 0) {
11971
+ WL_ERR(("bip set error %d\n", err));
11972
+#if defined(IGUANA_LEGACY_CHIPS)
11973
+ if (wl_customer6_legacy_chip_check(cfg,
11974
+ bcmcfg_to_prmry_ndev(cfg))) {
11975
+ /* Ignore bip error: Some older firmwares doesn't
11976
+ * support bip iovar/ return BCME_NOTUP while trying
11977
+ * to set bip from AP bring up context. These firmares
11978
+ * include bip in RSNIE by default. So its okay to ignore
11979
+ * the error.
11980
+ */
11981
+ err = BCME_OK;
11982
+ } else
11983
+#endif // endif
11984
+ {
11985
+ goto exit;
11986
+ }
11987
+ }
11988
+ }
11989
+#endif /* MFP */
750211990
750311991 err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec);
750411992 if (unlikely(err)) {
....@@ -7511,50 +11999,103 @@
751111999 sizeof(struct wl_wsec_key), cfg->ioctl_buf,
751212000 WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
751312001 /* clear the key after use */
7514
- memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
12002
+ bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
751512003 if (unlikely(err)) {
751612004 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
751712005 goto exit;
751812006 }
751912007 }
752012008
7521
- memset(&join_params, 0, sizeof(join_params));
7522
- /* join parameters starts with ssid */
7523
- join_params_size = sizeof(join_params.ssid);
7524
- memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
7525
- cfg->hostapd_ssid.SSID_len);
7526
- join_params.ssid.SSID_len = htod32(cfg->hostapd_ssid.SSID_len);
7527
-
7528
- /* create softap */
7529
- if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
7530
- join_params_size, true)) == 0) {
7531
- WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID));
7532
- wl_clr_drv_status(cfg, AP_CREATING, dev);
7533
- wl_set_drv_status(cfg, AP_CREATED, dev);
7534
- } else {
7535
- WL_ERR(("SoftAP/GO set ssid failed! \n"));
7536
- goto exit;
7537
- }
7538
-
7539
- if (bssidx != 0) {
7540
- /* AP on Virtual Interface */
7541
- if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) {
7542
- WL_ERR(("Virtual AP Bring up error %d\n", err));
12009
+#ifdef MFP
12010
+ /* This needs to go after wsec otherwise the wsec command will
12011
+ * overwrite the values set by MFP
12012
+ */
12013
+ err = wldev_iovar_setint_bsscfg(dev, "mfp", cfg->mfp_mode, bssidx);
12014
+ if (err < 0) {
12015
+ WL_ERR(("MFP Setting failed. ret = %d \n", err));
12016
+ /* If fw doesn't support mfp, Ignore the error */
12017
+ if (err != BCME_UNSUPPORTED) {
754312018 goto exit;
754412019 }
754512020 }
12021
+#endif /* MFP */
12022
+
12023
+ bzero(&join_params, sizeof(join_params));
12024
+ /* join parameters starts with ssid */
12025
+ join_params_size = sizeof(join_params.ssid);
12026
+ join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
12027
+ (uint32)DOT11_MAX_SSID_LEN);
12028
+ memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
12029
+ join_params.ssid.SSID_len);
12030
+ join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
12031
+
12032
+ /* create softap */
12033
+ if ((err = wldev_ioctl_set(dev, WLC_SET_SSID, &join_params,
12034
+ join_params_size)) != 0) {
12035
+ WL_ERR(("SoftAP/GO set ssid failed! \n"));
12036
+ goto exit;
12037
+ } else {
12038
+ WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
12039
+ }
12040
+
12041
+ if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 1)) < 0) {
12042
+ WL_ERR(("AP Bring up error %d\n", err));
12043
+ goto exit;
12044
+ }
12045
+
12046
+ } else {
12047
+ WL_ERR(("Wrong interface type %d\n", dev_role));
12048
+ goto exit;
754612049 }
754712050
7548
- /* Mark AP/GO iface status to connected */
7549
- wl_set_drv_status(cfg, CONNECTED, dev);
12051
+ /* Wait for Linkup event to mark successful AP/GO bring up */
12052
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
12053
+ wl_get_drv_status(cfg, AP_CREATED, dev), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
12054
+ if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) {
12055
+ WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
12056
+ if (timeout == -ERESTARTSYS) {
12057
+ WL_ERR(("waitqueue was interrupted by a signal, returns -ERESTARTSYS\n"));
12058
+ err = -ERESTARTSYS;
12059
+ goto exit;
12060
+ }
12061
+ if (dhd_query_bus_erros(dhdp)) {
12062
+ err = -ENODEV;
12063
+ goto exit;
12064
+ }
12065
+ dhdp->iface_op_failed = TRUE;
12066
+#if defined(DHD_DEBUG) && defined(DHD_FW_COREDUMP)
12067
+ if (dhdp->memdump_enabled) {
12068
+ dhdp->memdump_type = DUMP_TYPE_AP_LINKUP_FAILURE;
12069
+ dhd_bus_mem_dump(dhdp);
12070
+ }
12071
+#endif /* DHD_DEBUG && DHD_FW_COREDUMP */
12072
+ err = -ENODEV;
12073
+ goto exit;
12074
+ }
12075
+ SUPP_LOG(("AP/GO Link up\n"));
755012076
755112077 exit:
7552
- if (cfg->wep_key.len)
7553
- memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
12078
+ if (cfg->wep_key.len) {
12079
+ bzero(&cfg->wep_key, sizeof(struct wl_wsec_key));
12080
+ }
12081
+
12082
+#ifdef MFP
12083
+ if (cfg->mfp_mode) {
12084
+ cfg->mfp_mode = 0;
12085
+ }
12086
+
12087
+ if (cfg->bip_pos) {
12088
+ cfg->bip_pos = NULL;
12089
+ }
12090
+#endif /* MFP */
12091
+
12092
+ if (err) {
12093
+ SUPP_LOG(("AP/GO bring up fail. err:%d\n", err));
12094
+ }
755412095 return err;
755512096 }
755612097
7557
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
12098
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
755812099 s32
755912100 wl_cfg80211_parse_ap_ies(
756012101 struct net_device *dev,
....@@ -7562,40 +12103,38 @@
756212103 struct parsed_ies *ies)
756312104 {
756412105 struct parsed_ies prb_ies;
7565
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
12106
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
756612107 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
7567
- u8 *vndr = NULL;
12108
+ const u8 *vndr = NULL;
756812109 u32 vndr_ie_len = 0;
756912110 s32 err = BCME_OK;
757012111
757112112 /* Parse Beacon IEs */
7572
- if (wl_cfg80211_parse_ies((u8 *)info->tail,
12113
+ if (wl_cfg80211_parse_ies((const u8 *)info->tail,
757312114 info->tail_len, ies) < 0) {
757412115 WL_ERR(("Beacon get IEs failed \n"));
757512116 err = -EINVAL;
757612117 goto fail;
757712118 }
757812119
7579
- vndr = (u8 *)info->proberesp_ies;
7580
- vndr_ie_len = info->proberesp_ies_len;
12120
+ vndr = (const u8 *)info->proberesp_ies;
12121
+ vndr_ie_len = (uint32)info->proberesp_ies_len;
758112122
758212123 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
758312124 /* SoftAP mode */
7584
- struct ieee80211_mgmt *mgmt;
7585
- mgmt = (struct ieee80211_mgmt *)info->probe_resp;
12125
+ const struct ieee80211_mgmt *mgmt;
12126
+ mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
758612127 if (mgmt != NULL) {
7587
- vndr = (u8 *)&mgmt->u.probe_resp.variable;
7588
- vndr_ie_len = info->probe_resp_len -
7589
- offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
12128
+ vndr = (const u8 *)&mgmt->u.probe_resp.variable;
12129
+ vndr_ie_len = (uint32)(info->probe_resp_len -
12130
+ offsetof(const struct ieee80211_mgmt, u.probe_resp.variable));
759012131 }
759112132 }
7592
-
759312133 /* Parse Probe Response IEs */
7594
- if (wl_cfg80211_parse_ies(vndr, vndr_ie_len, &prb_ies) < 0) {
12134
+ if (wl_cfg80211_parse_ies((const u8 *)vndr, vndr_ie_len, &prb_ies) < 0) {
759512135 WL_ERR(("PROBE RESP get IEs failed \n"));
759612136 err = -EINVAL;
759712137 }
7598
-
759912138 fail:
760012139
760112140 return err;
....@@ -7607,9 +12146,9 @@
760712146 struct cfg80211_beacon_data *info,
760812147 s32 bssidx)
760912148 {
7610
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
12149
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
761112150 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
7612
- u8 *vndr = NULL;
12151
+ const u8 *vndr = NULL;
761312152 u32 vndr_ie_len = 0;
761412153 s32 err = BCME_OK;
761512154
....@@ -7622,31 +12161,42 @@
762212161 WL_DBG(("Applied Vndr IEs for Beacon \n"));
762312162 }
762412163
7625
- vndr = (u8 *)info->proberesp_ies;
7626
- vndr_ie_len = info->proberesp_ies_len;
12164
+ vndr = (const u8 *)info->proberesp_ies;
12165
+ vndr_ie_len = (uint32)info->proberesp_ies_len;
762712166
762812167 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
762912168 /* SoftAP mode */
7630
- struct ieee80211_mgmt *mgmt;
7631
- mgmt = (struct ieee80211_mgmt *)info->probe_resp;
12169
+ const struct ieee80211_mgmt *mgmt;
12170
+ mgmt = (const struct ieee80211_mgmt *)info->probe_resp;
763212171 if (mgmt != NULL) {
7633
- vndr = (u8 *)&mgmt->u.probe_resp.variable;
7634
- vndr_ie_len = info->probe_resp_len -
7635
- offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
12172
+ vndr = (const u8 *)&mgmt->u.probe_resp.variable;
12173
+ vndr_ie_len = (uint32)(info->probe_resp_len -
12174
+ offsetof(struct ieee80211_mgmt, u.probe_resp.variable));
763612175 }
763712176 }
763812177
763912178 /* Set Probe Response IEs to FW */
764012179 if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
764112180 VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
7642
- WL_ERR(("Set Probe Resp IE Failed \n"));
12181
+ WL_ERR(("Set Probe Resp Vndr IE Failed \n"));
764312182 } else {
764412183 WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
764512184 }
764612185
12186
+ /* Set Assoc Response IEs to FW */
12187
+ vndr = (const u8 *)info->assocresp_ies;
12188
+ vndr_ie_len = (uint32)info->assocresp_ies_len;
12189
+
12190
+ if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
12191
+ VNDR_IE_ASSOCRSP_FLAG, vndr, vndr_ie_len)) < 0) {
12192
+ WL_ERR(("Set Assoc Resp Vndr IE Failed \n"));
12193
+ } else {
12194
+ WL_DBG(("Applied Vndr IEs for Assoc Resp \n"));
12195
+ }
12196
+
764712197 return err;
764812198 }
7649
-#endif
12199
+#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
765012200
765112201 static s32 wl_cfg80211_hostapd_sec(
765212202 struct net_device *dev,
....@@ -7654,7 +12204,7 @@
765412204 s32 bssidx)
765512205 {
765612206 bool update_bss = 0;
7657
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
12207
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
765812208 wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
765912209
766012210 if (!bss) {
....@@ -7666,54 +12216,171 @@
766612216 if (bss->wps_ie &&
766712217 memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
766812218 WL_DBG((" WPS IE is changed\n"));
7669
- kfree(bss->wps_ie);
7670
- bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
12219
+ MFREE(cfg->osh, bss->wps_ie, bss->wps_ie[1] + 2);
12220
+ bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
12221
+ if (bss->wps_ie) {
12222
+ memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
12223
+ }
767112224 } else if (bss->wps_ie == NULL) {
767212225 WL_DBG((" WPS IE is added\n"));
7673
- bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
12226
+ bss->wps_ie = MALLOCZ(cfg->osh, ies->wps_ie_len);
12227
+ if (bss->wps_ie) {
12228
+ memcpy(bss->wps_ie, ies->wps_ie, ies->wps_ie_len);
12229
+ }
767412230 }
767512231
12232
+#if defined(SUPPORT_SOFTAP_WPAWPA2_MIXED)
12233
+ if (ies->wpa_ie != NULL && ies->wpa2_ie != NULL) {
12234
+ WL_ERR(("update bss - wpa_ie and wpa2_ie is not null\n"));
12235
+ if (!bss->security_mode) {
12236
+ /* change from open mode to security mode */
12237
+ update_bss = true;
12238
+ bss->wpa_ie = MALLOCZ(cfg->osh,
12239
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
12240
+ if (bss->wpa_ie) {
12241
+ memcpy(bss->wpa_ie, ies->wpa_ie,
12242
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
12243
+ }
12244
+ bss->rsn_ie = MALLOCZ(cfg->osh,
12245
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
12246
+ if (bss->rsn_ie) {
12247
+ memcpy(bss->rsn_ie, ies->wpa2_ie,
12248
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
12249
+ }
12250
+ } else {
12251
+ /* change from (WPA or WPA2 or WPA/WPA2) to WPA/WPA2 mixed mode */
12252
+ if (bss->wpa_ie) {
12253
+ if (memcmp(bss->wpa_ie,
12254
+ ies->wpa_ie, ies->wpa_ie->length +
12255
+ WPA_RSN_IE_TAG_FIXED_LEN)) {
12256
+ MFREE(cfg->osh, bss->wpa_ie,
12257
+ bss->wpa_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
12258
+ update_bss = true;
12259
+ bss->wpa_ie = MALLOCZ(cfg->osh,
12260
+ ies->wpa_ie->length
12261
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12262
+ if (bss->wpa_ie) {
12263
+ memcpy(bss->wpa_ie, ies->wpa_ie,
12264
+ ies->wpa_ie->length
12265
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12266
+ }
12267
+ }
12268
+ }
12269
+ else {
12270
+ update_bss = true;
12271
+ bss->wpa_ie = MALLOCZ(cfg->osh,
12272
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
12273
+ if (bss->wpa_ie) {
12274
+ memcpy(bss->wpa_ie, ies->wpa_ie,
12275
+ ies->wpa_ie->length
12276
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12277
+ }
12278
+ }
12279
+ if (bss->rsn_ie) {
12280
+ if (memcmp(bss->rsn_ie,
12281
+ ies->wpa2_ie,
12282
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
12283
+ update_bss = true;
12284
+ MFREE(cfg->osh, bss->rsn_ie,
12285
+ bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
12286
+ bss->rsn_ie = MALLOCZ(cfg->osh,
12287
+ ies->wpa2_ie->len
12288
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12289
+ if (bss->rsn_ie) {
12290
+ memcpy(bss->rsn_ie, ies->wpa2_ie,
12291
+ ies->wpa2_ie->len
12292
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12293
+ }
12294
+ }
12295
+ }
12296
+ else {
12297
+ update_bss = true;
12298
+ bss->rsn_ie = MALLOCZ(cfg->osh,
12299
+ ies->wpa2_ie->len
12300
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12301
+ if (bss->rsn_ie) {
12302
+ memcpy(bss->rsn_ie, ies->wpa2_ie,
12303
+ ies->wpa2_ie->len
12304
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12305
+ }
12306
+ }
12307
+ }
12308
+ WL_ERR(("update_bss=%d\n", update_bss));
12309
+ if (update_bss) {
12310
+ bss->security_mode = true;
12311
+ wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
12312
+ if (wl_validate_wpaie_wpa2ie(dev, ies->wpa_ie,
12313
+ ies->wpa2_ie, bssidx) < 0) {
12314
+ return BCME_ERROR;
12315
+ }
12316
+ wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
12317
+ }
12318
+
12319
+ }
12320
+ else
12321
+#endif /* SUPPORT_SOFTAP_WPAWPA2_MIXED */
767612322 if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
767712323 if (!bss->security_mode) {
767812324 /* change from open mode to security mode */
767912325 update_bss = true;
768012326 if (ies->wpa_ie != NULL) {
7681
- bss->wpa_ie = kmemdup(ies->wpa_ie,
7682
- ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
7683
- GFP_KERNEL);
12327
+ bss->wpa_ie = MALLOCZ(cfg->osh,
12328
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
12329
+ if (bss->wpa_ie) {
12330
+ memcpy(bss->wpa_ie,
12331
+ ies->wpa_ie,
12332
+ ies->wpa_ie->length
12333
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12334
+ }
768412335 } else {
7685
- bss->rsn_ie = kmemdup(ies->wpa2_ie,
7686
- ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
7687
- GFP_KERNEL);
12336
+ bss->rsn_ie = MALLOCZ(cfg->osh,
12337
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
12338
+ if (bss->rsn_ie) {
12339
+ memcpy(bss->rsn_ie,
12340
+ ies->wpa2_ie,
12341
+ ies->wpa2_ie->len
12342
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12343
+ }
768812344 }
768912345 } else if (bss->wpa_ie) {
769012346 /* change from WPA2 mode to WPA mode */
769112347 if (ies->wpa_ie != NULL) {
769212348 update_bss = true;
7693
- kfree(bss->rsn_ie);
7694
- bss->rsn_ie = NULL;
7695
- bss->wpa_ie = kmemdup(ies->wpa_ie,
7696
- ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
7697
- GFP_KERNEL);
12349
+ MFREE(cfg->osh, bss->rsn_ie,
12350
+ bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
12351
+ bss->wpa_ie = MALLOCZ(cfg->osh,
12352
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN);
12353
+ if (bss->wpa_ie) {
12354
+ memcpy(bss->wpa_ie,
12355
+ ies->wpa_ie,
12356
+ ies->wpa_ie->length
12357
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12358
+ }
769812359 } else if (memcmp(bss->rsn_ie,
769912360 ies->wpa2_ie, ies->wpa2_ie->len
770012361 + WPA_RSN_IE_TAG_FIXED_LEN)) {
770112362 update_bss = true;
7702
- kfree(bss->rsn_ie);
7703
- bss->rsn_ie = kmemdup(ies->wpa2_ie,
7704
- ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
7705
- GFP_KERNEL);
12363
+ MFREE(cfg->osh, bss->rsn_ie,
12364
+ bss->rsn_ie[1] + WPA_RSN_IE_TAG_FIXED_LEN);
12365
+ bss->rsn_ie = MALLOCZ(cfg->osh,
12366
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN);
12367
+ if (bss->rsn_ie) {
12368
+ memcpy(bss->rsn_ie,
12369
+ ies->wpa2_ie,
12370
+ ies->wpa2_ie->len
12371
+ + WPA_RSN_IE_TAG_FIXED_LEN);
12372
+ }
770612373 bss->wpa_ie = NULL;
770712374 }
770812375 }
770912376 if (update_bss) {
771012377 bss->security_mode = true;
7711
- wl_cfgp2p_bss(cfg, dev, bssidx, 0);
12378
+ wl_cfg80211_bss_up(cfg, dev, bssidx, 0);
771212379 if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
771312380 wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
771412381 return BCME_ERROR;
771512382 }
7716
- wl_cfgp2p_bss(cfg, dev, bssidx, 1);
12383
+ wl_cfg80211_bss_up(cfg, dev, bssidx, 1);
771712384 }
771812385 }
771912386 } else {
....@@ -7755,8 +12422,10 @@
775512422
775612423 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
775712424 const u8 *mac_addr = params->mac;
12425
+#ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
12426
+ u16 rc = params->reason_code;
12427
+#endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
775812428 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
7759
-
776012429 WL_DBG(("Entry\n"));
776112430 if (mac_addr == NULL) {
776212431 WL_DBG(("mac_addr is NULL ignore it\n"));
....@@ -7776,22 +12445,53 @@
777612445 }
777712446
777812447 assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
7779
- err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST,
7780
- assoc_maclist, sizeof(mac_buf), false);
12448
+ err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
12449
+ assoc_maclist, sizeof(mac_buf));
778112450 if (err < 0)
778212451 WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
778312452 else
778412453 num_associated = assoc_maclist->count;
778512454
778612455 memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
7787
- scb_val.val = DOT11_RC_DEAUTH_LEAVING;
7788
- err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
7789
- sizeof(scb_val_t), true);
7790
- if (err < 0)
7791
- WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
7792
- WL_ERR(("Disconnect STA : %s scb_val.val %d\n",
7793
- bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf),
7794
- scb_val.val));
12456
+#ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
12457
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12458
+ if (rc == DOT11_RC_8021X_AUTH_FAIL) {
12459
+ WL_ERR(("deauth will be sent at F/W\n"));
12460
+ scb_val.val = DOT11_RC_8021X_AUTH_FAIL;
12461
+ } else {
12462
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12463
+#endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
12464
+
12465
+#ifdef WL_WPS_SYNC
12466
+ if (wl_wps_session_update(ndev,
12467
+ WPS_STATE_DISCONNECT_CLIENT, mac_addr) == BCME_UNSUPPORTED) {
12468
+ /* Ignore disconnect command from upper layer */
12469
+ WL_INFORM_MEM(("[WPS] Ignore client disconnect.\n"));
12470
+ } else
12471
+#endif /* WL_WPS_SYNC */
12472
+ {
12473
+
12474
+ /* need to guarantee EAP-Failure send out before deauth */
12475
+ dhd_wait_pend8021x(dev);
12476
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12477
+ scb_val.val = cpu_to_le32(params->reason_code);
12478
+#else
12479
+ scb_val.val = DOT11_RC_DEAUTH_LEAVING;
12480
+#endif // endif
12481
+ err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
12482
+ sizeof(scb_val_t));
12483
+ if (err < 0) {
12484
+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
12485
+ }
12486
+ WL_INFORM_MEM(("Disconnect STA : " MACDBG " scb_val.val %d\n",
12487
+ MAC2STRDBG(bcm_ether_ntoa((const struct ether_addr *)mac_addr,
12488
+ eabuf)), scb_val.val));
12489
+ }
12490
+#ifdef CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE
12491
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
12492
+ }
12493
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
12494
+#endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
779512495
779612496 if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
779712497 wl_delay(400);
....@@ -7813,16 +12513,24 @@
781312513 struct net_device *dev,
781412514 u8 *mac,
781512515 struct station_parameters *params)
7816
-#endif
12516
+#endif // endif
781712517 {
7818
- int err;
7819
-#ifdef DHD_LOSSLESS_ROAMING
12518
+ int err = BCME_OK;
782012519 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7821
-#endif
12520
+#ifdef WBTEXT
12521
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
12522
+#endif /* WBTEXT */
782212523
782312524 WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x "
782412525 "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac),
782512526 params->sta_flags_mask, params->sta_flags_set, dev->name));
12527
+
12528
+ if ((wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS) &&
12529
+ !(wl_get_drv_status(cfg, CONNECTED, dev))) {
12530
+ /* Return error indicating not in connected state */
12531
+ WL_ERR(("Ignore SCB_AUTHORIZE/DEAUTHORIZE in non connected state\n"));
12532
+ return -ENOTSUPP;
12533
+ }
782612534
782712535 /* Processing only authorize/de-authorize flag for now */
782812536 if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
....@@ -7831,31 +12539,97 @@
783112539 }
783212540
783312541 if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
7834
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
7835
- err = wldev_ioctl(dev, WLC_SCB_DEAUTHORIZE, (u8 *)mac, ETH_ALEN, true);
7836
-#else
7837
- err = wldev_ioctl(dev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN, true);
7838
-#endif
7839
- if (err)
12542
+ err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN);
12543
+ if (unlikely(err)) {
784012544 WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
12545
+ } else {
12546
+ WL_INFORM_MEM(("[%s] WLC_SCB_DEAUTHORIZE " MACDBG "\n",
12547
+ dev->name, MAC2STRDBG(mac)));
12548
+ }
784112549 return err;
784212550 }
784312551
7844
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
7845
- err = wldev_ioctl(dev, WLC_SCB_AUTHORIZE, (u8 *)mac, ETH_ALEN, true);
7846
-#else
7847
- err = wldev_ioctl(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true);
7848
-#endif
7849
- if (err)
12552
+ err = wldev_ioctl_set(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN);
12553
+ if (unlikely(err)) {
785012554 WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
12555
+ } else {
12556
+ WL_INFORM_MEM(("[%s] WLC_SCB_AUTHORIZE " MACDBG "\n",
12557
+ dev->name, MAC2STRDBG(mac)));
12558
+#ifdef WL_WPS_SYNC
12559
+ wl_wps_session_update(dev, WPS_STATE_AUTHORIZE, mac);
12560
+#endif /* WL_WPS_SYNC */
12561
+ }
785112562 #ifdef DHD_LOSSLESS_ROAMING
785212563 wl_del_roam_timeout(cfg);
7853
-#endif
12564
+#endif // endif
12565
+#ifdef WBTEXT
12566
+ /* send nbr request or BTM query to update RCC
12567
+ * after 4-way handshake is completed
12568
+ */
12569
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
12570
+ dhdp->wbtext_support) {
12571
+ wl_cfg80211_wbtext_update_rcc(cfg, dev);
12572
+ }
12573
+#endif /* WBTEXT */
12574
+
785412575 return err;
785512576 }
785612577 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
785712578
7858
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
12579
+static s32
12580
+wl_cfg80211_set_scb_timings(
12581
+ struct bcm_cfg80211 *cfg,
12582
+ struct net_device *dev)
12583
+{
12584
+ int err;
12585
+ u32 ps_pretend;
12586
+ wl_scb_probe_t scb_probe;
12587
+ u32 ps_pretend_retries;
12588
+
12589
+ bzero(&scb_probe, sizeof(wl_scb_probe_t));
12590
+ scb_probe.scb_timeout = WL_SCB_TIMEOUT;
12591
+ scb_probe.scb_activity_time = WL_SCB_ACTIVITY_TIME;
12592
+ scb_probe.scb_max_probe = WL_SCB_MAX_PROBE;
12593
+ err = wldev_iovar_setbuf(dev, "scb_probe", (void *)&scb_probe,
12594
+ sizeof(wl_scb_probe_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
12595
+ &cfg->ioctl_buf_sync);
12596
+ if (unlikely(err)) {
12597
+ WL_ERR(("set 'scb_probe' failed, error = %d\n", err));
12598
+ return err;
12599
+ }
12600
+
12601
+ ps_pretend_retries = WL_PSPRETEND_RETRY_LIMIT;
12602
+ err = wldev_iovar_setint(dev, "pspretend_retry_limit", ps_pretend_retries);
12603
+ if (unlikely(err)) {
12604
+ if (err == BCME_UNSUPPORTED) {
12605
+ /* Ignore error if fw doesn't support the iovar */
12606
+ WL_DBG(("set 'pspretend_retry_limit %d' failed, error = %d\n",
12607
+ ps_pretend_retries, err));
12608
+ } else {
12609
+ WL_ERR(("set 'pspretend_retry_limit %d' failed, error = %d\n",
12610
+ ps_pretend_retries, err));
12611
+ return err;
12612
+ }
12613
+ }
12614
+
12615
+ ps_pretend = MAX(WL_SCB_MAX_PROBE / 2, WL_MIN_PSPRETEND_THRESHOLD);
12616
+ err = wldev_iovar_setint(dev, "pspretend_threshold", ps_pretend);
12617
+ if (unlikely(err)) {
12618
+ if (err == BCME_UNSUPPORTED) {
12619
+ /* Ignore error if fw doesn't support the iovar */
12620
+ WL_DBG(("wl pspretend_threshold %d set error %d\n",
12621
+ ps_pretend, err));
12622
+ } else {
12623
+ WL_ERR(("wl pspretend_threshold %d set error %d\n",
12624
+ ps_pretend, err));
12625
+ return err;
12626
+ }
12627
+ }
12628
+
12629
+ return 0;
12630
+}
12631
+
12632
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
785912633 static s32
786012634 wl_cfg80211_start_ap(
786112635 struct wiphy *wiphy,
....@@ -7868,33 +12642,51 @@
786812642 s32 bssidx = 0;
786912643 u32 dev_role = 0;
787012644 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
12645
+#ifdef WL11U
12646
+ bcm_tlv_t *interworking_ie;
12647
+ u32 iw_ie_len = 0;
12648
+ u8 iw_ie[IW_IES_MAX_BUF_LEN];
12649
+#endif // endif
12650
+#ifdef ENABLE_HOGSQS
12651
+ struct ieee80211_channel *chan_h;
12652
+#endif /* ENABLE_HOGSQS */
12653
+
787112654 WL_DBG(("Enter \n"));
7872
- if ((dev == bcmcfg_to_prmry_ndev(cfg)) ||
7873
- (dev == ((struct net_device *)cfgdev_to_ndev(cfg->bss_cfgdev)))) {
7874
- WL_DBG(("Start AP req on iface: %s \n", dev->name));
7875
- dev_role = NL80211_IFTYPE_AP;
12655
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
12656
+ /* Disable scanmac if enabled */
12657
+ if (cfg->scanmac_enabled) {
12658
+ wl_cfg80211_scan_mac_disable(dev);
787612659 }
7877
-#if defined(WL_ENABLE_P2P_IF)
7878
- else if (dev == cfg->p2p_net) {
7879
- /* Group Add request on p2p0 */
7880
- WL_DBG(("Start AP req on P2P iface: GO\n"));
7881
- dev = bcmcfg_to_prmry_ndev(cfg);
7882
- dev_role = NL80211_IFTYPE_P2P_GO;
7883
- }
7884
-#endif /* WL_ENABLE_P2P_IF */
7885
- if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
12660
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
12661
+
12662
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
788612663 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
788712664 return BCME_ERROR;
788812665 }
788912666
789012667 if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
789112668 dev_role = NL80211_IFTYPE_P2P_GO;
7892
- } else if (dev_role == NL80211_IFTYPE_AP) {
12669
+ } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12670
+ dev_role = NL80211_IFTYPE_AP;
789312671 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
12672
+ err = dhd_ndo_enable(dhd, FALSE);
12673
+ WL_DBG(("Disabling NDO on Hostapd mode %d\n", err));
12674
+ if (err) {
12675
+ WL_ERR(("Disabling NDO Failed %d\n", err));
12676
+ }
12677
+#ifdef PKT_FILTER_SUPPORT
12678
+ /* Disable packet filter */
12679
+ if (dhd->early_suspended) {
12680
+ WL_ERR(("Disable pkt_filter\n"));
12681
+ dhd_enable_packet_filter(0, dhd);
12682
+ }
12683
+#endif /* PKT_FILTER_SUPPORT */
789412684 #ifdef ARP_OFFLOAD_SUPPORT
789512685 /* IF SoftAP is enabled, disable arpoe */
7896
- dhd_arp_offload_set(dhd, 0);
7897
- dhd_arp_offload_enable(dhd, FALSE);
12686
+ if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12687
+ dhd_arp_offload_set(dhd, 0);
12688
+ dhd_arp_offload_enable(dhd, FALSE);
12689
+ }
789812690 #endif /* ARP_OFFLOAD_SUPPORT */
789912691 } else {
790012692 /* only AP or GO role need to be handled here. */
....@@ -7902,19 +12694,29 @@
790212694 goto fail;
790312695 }
790412696
7905
- if (!check_dev_role_integrity(cfg, dev_role)) {
12697
+ /* disable TDLS */
12698
+#ifdef WLTDLS
12699
+ if (bssidx == 0) {
12700
+ /* Disable TDLS for primary Iface. For virtual interface,
12701
+ * tdls disable will happen from interface create context
12702
+ */
12703
+ wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_CREATE, false);
12704
+ }
12705
+#endif /* WLTDLS */
12706
+
12707
+ if (!check_dev_role_integrity(cfg, wl_get_mode_by_netdev(cfg, dev), dev_role)) {
790612708 err = -EINVAL;
790712709 goto fail;
790812710 }
790912711
7910
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
12712
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
791112713 if ((err = wl_cfg80211_set_channel(wiphy, dev,
791212714 dev->ieee80211_ptr->preset_chandef.chan,
7913
- dev->ieee80211_ptr->preset_chandef) < 0)) {
12715
+ NL80211_CHAN_HT20) < 0)) {
791412716 WL_ERR(("Set channel failed \n"));
791512717 goto fail;
791612718 }
7917
-#endif
12719
+#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
791812720
791912721 if ((err = wl_cfg80211_bcn_set_params(info, dev,
792012722 dev_role, bssidx)) < 0) {
....@@ -7927,25 +12729,76 @@
792712729 WL_ERR(("Set IEs failed \n"));
792812730 goto fail;
792912731 }
7930
- if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies,
7931
- dev_role, bssidx, info->privacy)) < 0)
7932
- {
7933
- WL_ERR(("Beacon set security failed \n"));
7934
- goto fail;
12732
+
12733
+#ifdef BCMWAPI_WPI
12734
+ if (info->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_SMS4) {
12735
+ wl_validate_wapisecurity(dev, bssidx);
793512736 }
12737
+ else
12738
+#endif // endif
12739
+ {
12740
+ WL_ERR(("%s info->crypto.ciphers_pairwise[0] is not "
12741
+ "WLAN_CIPHER_SUITE_SMS4 \n", __FUNCTION__));
12742
+
12743
+ if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies,
12744
+ dev_role, bssidx, info->privacy)) < 0)
12745
+ {
12746
+ WL_ERR(("Beacon set security failed \n"));
12747
+ goto fail;
12748
+ }
12749
+ }
12750
+
793612751 if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies,
793712752 dev_role, bssidx)) < 0) {
793812753 WL_ERR(("Beacon bring up AP/GO failed \n"));
793912754 goto fail;
794012755 }
12756
+#ifdef BCMSDIO
12757
+ if (dev_role == NL80211_IFTYPE_AP) {
12758
+ dhd_set_role(dhd, WLC_E_IF_ROLE_AP, bssidx);
12759
+ } else if (dev_role == NL80211_IFTYPE_P2P_GO) {
12760
+ dhd_set_role(dhd, WLC_E_IF_ROLE_P2P_GO, bssidx);
12761
+ }
12762
+#endif /* BCMSDIO */
794112763
12764
+ /* Set GC/STA SCB expiry timings. */
12765
+ if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
12766
+ WL_ERR(("scb setting failed \n"));
12767
+ goto fail;
12768
+ }
12769
+
12770
+ wl_set_drv_status(cfg, CONNECTED, dev);
794212771 WL_DBG(("** AP/GO Created **\n"));
12772
+
794312773 #ifdef WL_CFG80211_ACL
794412774 /* Enfoce Admission Control. */
794512775 if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
794612776 WL_ERR(("Set ACL failed\n"));
794712777 }
794812778 #endif /* WL_CFG80211_ACL */
12779
+
12780
+#ifdef WL11U
12781
+ wl_get_iwdata_by_netdev(cfg, dev, iw_ie, &iw_ie_len);
12782
+ /* Add interworking IE from beacon data */
12783
+ if ((interworking_ie = wl_cfg80211_find_interworking_ie(
12784
+ info->beacon.beacon_ies, info->beacon.beacon_ies_len)) != NULL) {
12785
+ err = wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
12786
+ VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
12787
+ interworking_ie->data, interworking_ie->len);
12788
+ if (unlikely(err)) {
12789
+ WL_ERR(("Failed to add interworking IE"));
12790
+ }
12791
+ } else if (iw_ie_len != 0) {
12792
+ /* we have to clear IW IE and disable gratuitous APR */
12793
+ wl_cfg80211_clear_iw_ie(cfg, dev, bssidx);
12794
+
12795
+ (void)wldev_iovar_setint_bsscfg(dev, "grat_arp", 0,
12796
+ bssidx);
12797
+ wl_clear_iwdata_by_netdev(cfg, dev);
12798
+ /* we don't care about error */
12799
+ cfg->wl11u = FALSE;
12800
+ }
12801
+#endif /* WL11U */
794912802
795012803 /* Set IEs to FW */
795112804 if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
....@@ -7954,20 +12807,80 @@
795412807 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
795512808 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
795612809 bool pbc = 0;
7957
- wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
12810
+ wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
795812811 if (pbc) {
795912812 WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
796012813 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
796112814 }
796212815 }
796312816
12817
+ /* Configure hidden SSID */
12818
+ if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) {
12819
+ if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
12820
+ WL_ERR(("failed to set hidden : %d\n", err));
12821
+ WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
12822
+ }
12823
+
12824
+#ifdef SUPPORT_AP_RADIO_PWRSAVE
12825
+ if (dev_role == NL80211_IFTYPE_AP) {
12826
+ if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
12827
+ wl_cfg80211_init_ap_rps(cfg);
12828
+ } else {
12829
+ WL_ERR(("Set rpsnoa failed \n"));
12830
+ }
12831
+ }
12832
+#endif /* SUPPORT_AP_RADIO_PWRSAVE */
12833
+
12834
+#ifdef ENABLE_HOGSQS
12835
+ chan_h = dev->ieee80211_ptr->preset_chandef.chan;
12836
+ if (chan_h->band == IEEE80211_BAND_5GHZ) {
12837
+ s32 value = 0x0;
12838
+
12839
+ value = M_HOGSQS_CFG;
12840
+ err = wldev_iovar_getint_bsscfg(dev, "hogsqs", &value, bssidx);
12841
+ if (unlikely(err)) {
12842
+ WL_ERR(("hogsqs command is failed %d %\n", err));
12843
+ } else {
12844
+ value |= 0x1003; /* enable mitigation */
12845
+ value |= (M_HOGSQS_CFG << 16);
12846
+ (void)wldev_iovar_setint_bsscfg(dev, "hogsqs",
12847
+ value, bssidx);
12848
+ }
12849
+ }
12850
+#endif /* ENABLE_HOGSQS */
12851
+
796412852 fail:
796512853 if (err) {
796612854 WL_ERR(("ADD/SET beacon failed\n"));
7967
- wldev_iovar_setint(dev, "mpc", 1);
12855
+ wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
12856
+ wl_cfg80211_stop_ap(wiphy, dev);
796812857 if (dev_role == NL80211_IFTYPE_AP) {
796912858 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
12859
+#ifdef PKT_FILTER_SUPPORT
12860
+ /* Enable packet filter */
12861
+ if (dhd->early_suspended) {
12862
+ WL_ERR(("Enable pkt_filter\n"));
12863
+ dhd_enable_packet_filter(1, dhd);
12864
+ }
12865
+#endif /* PKT_FILTER_SUPPORT */
12866
+#ifdef ARP_OFFLOAD_SUPPORT
12867
+ /* IF SoftAP is disabled, enable arpoe back for STA mode. */
12868
+ if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12869
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
12870
+ dhd_arp_offload_enable(dhd, TRUE);
12871
+ }
12872
+#endif /* ARP_OFFLOAD_SUPPORT */
12873
+#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12874
+ wl_cfg80211_set_frameburst(cfg, TRUE);
12875
+#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
797012876 }
12877
+#ifdef WLTDLS
12878
+ if (bssidx == 0) {
12879
+ /* Since AP creation failed, re-enable TDLS */
12880
+ wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
12881
+ }
12882
+#endif /* WLTDLS */
12883
+
797112884 }
797212885
797312886 return err;
....@@ -7980,25 +12893,51 @@
798012893 {
798112894 int err = 0;
798212895 u32 dev_role = 0;
7983
- int infra = 0;
798412896 int ap = 0;
798512897 s32 bssidx = 0;
798612898 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7987
- struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
798812899 s32 is_rsdb_supported = BCME_ERROR;
798912900 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
799012901
799112902 WL_DBG(("Enter \n"));
799212903
12904
+ if (wl_cfg80211_get_bus_state(cfg)) {
12905
+ /* since bus is down, iovar will fail. recovery path will bringup the bus. */
12906
+ WL_ERR(("bus is not ready\n"));
12907
+ return BCME_OK;
12908
+ }
799312909 is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
799412910 if (is_rsdb_supported < 0)
799512911 return (-ENODEV);
12912
+
12913
+ wl_clr_drv_status(cfg, AP_CREATING, dev);
12914
+ wl_clr_drv_status(cfg, AP_CREATED, dev);
12915
+ cfg->ap_oper_channel = 0;
12916
+
799612917 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
799712918 dev_role = NL80211_IFTYPE_AP;
799812919 WL_DBG(("stopping AP operation\n"));
12920
+#ifdef DHD_BANDSTEER
12921
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
12922
+ /* Disable bandsteer */
12923
+ cfg->ap_bs = 1;
12924
+ cfg->p2p_bs = 1;
12925
+ dhd_bandsteer_module_deinit(
12926
+ bcmcfg_to_prmry_ndev(cfg), cfg->ap_bs, cfg->p2p_bs);
12927
+ }
12928
+#endif /* DHD_BANDSTEER */
799912929 } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
800012930 dev_role = NL80211_IFTYPE_P2P_GO;
800112931 WL_DBG(("stopping P2P GO operation\n"));
12932
+#ifdef DHD_BANDSTEER
12933
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
12934
+ /* Disable bandsteer */
12935
+ cfg->ap_bs = 1;
12936
+ cfg->p2p_bs = 1;
12937
+ dhd_bandsteer_module_deinit(
12938
+ bcmcfg_to_prmry_ndev(cfg), cfg->ap_bs, cfg->p2p_bs);
12939
+ }
12940
+#endif /* DHD_BANDSTEER */
800212941 } else {
800312942 WL_ERR(("no AP/P2P GO interface is operational.\n"));
800412943 return -EINVAL;
....@@ -8009,95 +12948,89 @@
800912948 return BCME_ERROR;
801012949 }
801112950
8012
- if (!check_dev_role_integrity(cfg, dev_role)) {
12951
+ if (!check_dev_role_integrity(cfg, wl_get_mode_by_netdev(cfg, dev), dev_role)) {
801312952 WL_ERR(("role integrity check failed \n"));
801412953 err = -EINVAL;
801512954 goto exit;
801612955 }
801712956
12957
+ /* Free up resources */
12958
+ wl_cfg80211_cleanup_if(dev);
12959
+
801812960 /* Clear AP/GO connected status */
801912961 wl_clr_drv_status(cfg, CONNECTED, dev);
8020
-
8021
- if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 0)) < 0) {
12962
+ if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
802212963 WL_ERR(("bss down error %d\n", err));
802312964 }
802412965
802512966 if (dev_role == NL80211_IFTYPE_AP) {
8026
- if (bssidx == 0) {
8027
- /*
8028
- * Bring down the AP interface by changing role to STA.
8029
- * Don't do a down or "WLC_SET_AP 0" since the shared
8030
- * interface may be still running
8031
- */
8032
- if (is_rsdb_supported) {
8033
- if ((err = wl_cfg80211_add_del_bss(cfg, dev,
8034
- bssidx, NL80211_IFTYPE_STATION, 0, NULL)) < 0) {
8035
- if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32),
8036
- true)) < 0) {
8037
- WL_ERR(("setting AP mode failed %d \n", err));
8038
- err = -ENOTSUPP;
8039
- goto exit;
8040
- }
8041
- }
8042
- } else if (is_rsdb_supported == 0) {
8043
- if (dev == primary_ndev) {
8044
- err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true);
8045
- if (err < 0) {
8046
- WL_ERR(("WLC_DOWN error (%d)\n", err));
8047
- err = -ENOTSUPP;
8048
- goto exit;
8049
- }
12967
+#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
12968
+ wl_cfg80211_set_frameburst(cfg, TRUE);
12969
+#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
12970
+#ifdef PKT_FILTER_SUPPORT
12971
+ /* Enable packet filter */
12972
+ if (dhd->early_suspended) {
12973
+ WL_ERR(("Enable pkt_filter\n"));
12974
+ dhd_enable_packet_filter(1, dhd);
12975
+ }
12976
+#endif /* PKT_FILTER_SUPPORT */
12977
+#ifdef ARP_OFFLOAD_SUPPORT
12978
+ /* IF SoftAP is disabled, enable arpoe back for STA mode. */
12979
+ if (dhd->op_mode & DHD_FLAG_STA_MODE) {
12980
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
12981
+ dhd_arp_offload_enable(dhd, TRUE);
12982
+ }
12983
+#endif /* ARP_OFFLOAD_SUPPORT */
805012984
8051
- err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true);
8052
- if (err < 0) {
8053
- WL_ERR(("SET AP error %d\n", err));
8054
- err = -ENOTSUPP;
8055
- goto exit;
8056
- }
8057
-
8058
- err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
8059
- if (err < 0) {
8060
- WL_ERR(("WLC_UP error (%d)\n", err));
8061
- err = -ENOTSUPP;
8062
- goto exit;
8063
- }
8064
- }
8065
-
8066
- err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
8067
- if (err < 0) {
8068
- WL_ERR(("SET INFRA error %d\n", err));
8069
- err = -ENOTSUPP;
8070
- goto exit;
8071
- }
8072
- err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
8073
- if (unlikely(err)) {
8074
- WL_ERR(("WLC_UP error (%d)\n", err));
8075
- err = -EINVAL;
8076
- goto exit;
8077
- }
8078
- }
8079
- } else if (cfg->cfgdev_bssidx && (bssidx == cfg->cfgdev_bssidx)) {
8080
- WL_DBG(("Stop SoftAP on virtual Interface bssidx:%d \n", bssidx));
8081
- if ((err = wl_cfg80211_add_del_bss(cfg, dev,
8082
- bssidx, NL80211_IFTYPE_STATION, 0, NULL)) < 0) {
8083
- WL_ERR(("wl add_del_bss returned error:%d\n", err));
12985
+ if (is_rsdb_supported == 0) {
12986
+ /* For non-rsdb chips, we use stand alone AP. Do wl down on stop AP */
12987
+ err = wldev_ioctl_set(dev, WLC_UP, &ap, sizeof(s32));
12988
+ if (unlikely(err)) {
12989
+ WL_ERR(("WLC_UP error (%d)\n", err));
12990
+ err = -EINVAL;
808412991 goto exit;
808512992 }
808612993 }
808712994
8088
- wl_clr_drv_status(cfg, AP_CREATED, dev);
8089
- /* Turn on the MPC */
8090
- wldev_iovar_setint(dev, "mpc", 1);
12995
+#ifdef WL_DISABLE_HE_SOFTAP
12996
+ if (wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_IF_TYPE_AP, TRUE) != BCME_OK) {
12997
+ WL_ERR(("failed to set he features\n"));
12998
+ }
12999
+#endif /* WL_DISABLE_HE_SOFTAP */
809113000
8092
- wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
13001
+ wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
13002
+#ifdef SUPPORT_AP_RADIO_PWRSAVE
13003
+ if (!wl_set_ap_rps(dev, FALSE, dev->name)) {
13004
+ wl_cfg80211_init_ap_rps(cfg);
13005
+ } else {
13006
+ WL_ERR(("Set rpsnoa failed \n"));
13007
+ }
13008
+#endif /* SUPPORT_AP_RADIO_PWRSAVE */
809313009 } else {
809413010 WL_DBG(("Stopping P2P GO \n"));
13011
+#if defined(OEM_ANDROID)
809513012 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
809613013 DHD_EVENT_TIMEOUT_MS*3);
809713014 DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub));
13015
+#endif // endif
809813016 }
809913017
13018
+ SUPP_LOG(("AP/GO Link down\n"));
810013019 exit:
13020
+#ifdef WL11U
13021
+ wl_clear_iwdata_by_netdev(cfg, dev);
13022
+#endif // endif
13023
+ if (err) {
13024
+ /* In case of failure, flush fw logs */
13025
+ wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
13026
+ SUPP_LOG(("AP/GO Link down fail. err:%d\n", err));
13027
+ }
13028
+#ifdef WLTDLS
13029
+ if (bssidx == 0) {
13030
+ /* re-enable TDLS if the number of connected interfaces is less than 2 */
13031
+ wl_cfg80211_tdls_config(cfg, TDLS_STATE_AP_DELETE, false);
13032
+ }
13033
+#endif /* WLTDLS */
810113034
810213035 if (dev_role == NL80211_IFTYPE_AP) {
810313036 /* clear the AP mode */
....@@ -8118,19 +13051,13 @@
811813051 u32 dev_role = 0;
811913052 s32 bssidx = 0;
812013053 bool pbc = 0;
13054
+#ifdef WL11U
13055
+ bcm_tlv_t *interworking_ie;
13056
+ u32 iw_ie_len = 0;
13057
+ u8 iw_ie[IW_IES_MAX_BUF_LEN];
13058
+#endif // endif
812113059
812213060 WL_DBG(("Enter \n"));
8123
-
8124
- if (dev == bcmcfg_to_prmry_ndev(cfg)) {
8125
- dev_role = NL80211_IFTYPE_AP;
8126
- }
8127
-#if defined(WL_ENABLE_P2P_IF)
8128
- else if (dev == cfg->p2p_net) {
8129
- /* Group Add request on p2p0 */
8130
- dev = bcmcfg_to_prmry_ndev(cfg);
8131
- dev_role = NL80211_IFTYPE_P2P_GO;
8132
- }
8133
-#endif /* WL_ENABLE_P2P_IF */
813413061
813513062 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
813613063 WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
....@@ -8139,9 +13066,14 @@
813913066
814013067 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
814113068 dev_role = NL80211_IFTYPE_P2P_GO;
13069
+ } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
13070
+ dev_role = NL80211_IFTYPE_AP;
13071
+ } else {
13072
+ err = -EINVAL;
13073
+ goto fail;
814213074 }
814313075
8144
- if (!check_dev_role_integrity(cfg, dev_role)) {
13076
+ if (!check_dev_role_integrity(cfg, wl_get_mode_by_netdev(cfg, dev), dev_role)) {
814513077 err = -EINVAL;
814613078 goto fail;
814713079 }
....@@ -8158,6 +13090,31 @@
815813090 goto fail;
815913091 }
816013092
13093
+#ifdef WL11U
13094
+ wl_get_iwdata_by_netdev(cfg, dev, iw_ie, &iw_ie_len);
13095
+ /* Add interworking IE from beacon data */
13096
+ if ((interworking_ie = wl_cfg80211_find_interworking_ie(
13097
+ info->beacon_ies, info->beacon_ies_len)) != NULL) {
13098
+ err = wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
13099
+ VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
13100
+ interworking_ie->data, interworking_ie->len);
13101
+ if (unlikely(err)) {
13102
+ WL_ERR(("Failed to add interworking IE"));
13103
+ }
13104
+ } else if (iw_ie_len != 0) {
13105
+ /* we have to clear IW IE and disable gratuitous APR */
13106
+ wl_cfg80211_clear_iw_ie(cfg, dev, bssidx);
13107
+
13108
+ /* we don't bother whether grat_arp gets disabled or not */
13109
+ (void)wldev_iovar_setint_bsscfg(dev, "grat_arp", 0,
13110
+ bssidx);
13111
+ wl_clear_iwdata_by_netdev(cfg, dev);
13112
+ cfg->wl11u = FALSE;
13113
+ } else {
13114
+ WL_DBG(("no update in iw ie\n"));
13115
+ }
13116
+#endif /* WL11U */
13117
+
816113118 /* Set IEs to FW */
816213119 if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
816313120 WL_ERR(("Set IEs failed \n"));
....@@ -8172,7 +13129,7 @@
817213129 }
817313130 /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
817413131 if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
8175
- wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
13132
+ wl_validate_wps_ie((const char *) ies.wps_ie, ies.wps_ie_len, &pbc);
817613133 WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
817713134 if (pbc)
817813135 wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
....@@ -8182,6 +13139,9 @@
818213139 }
818313140
818413141 fail:
13142
+ if (err) {
13143
+ wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
13144
+ }
818513145 return err;
818613146 }
818713147 #else
....@@ -8198,6 +13158,7 @@
819813158 bcm_tlv_t *ssid_ie;
819913159 bool pbc = 0;
820013160 bool privacy;
13161
+ bool is_bss_up = 0;
820113162 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
820213163
820313164 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
....@@ -8225,7 +13186,7 @@
822513186 dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
822613187 }
822713188
8228
- if (!check_dev_role_integrity(cfg, dev_role)) {
13189
+ if (!check_dev_role_integrity(cfg, wl_get_mode_by_netdev(cfg, dev), dev_role)) {
822913190 err = -ENODEV;
823013191 goto fail;
823113192 }
....@@ -8243,14 +13204,16 @@
824313204 DOT11_MNG_SSID_ID)) != NULL) {
824413205 if (dev_role == NL80211_IFTYPE_AP) {
824513206 /* Store the hostapd SSID */
8246
- memset(&cfg->hostapd_ssid.SSID[0], 0x00, 32);
8247
- memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data, ssid_ie->len);
8248
- cfg->hostapd_ssid.SSID_len = ssid_ie->len;
13207
+ bzero(&cfg->hostapd_ssid.SSID[0], DOT11_MAX_SSID_LEN);
13208
+ cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
13209
+ memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
13210
+ cfg->hostapd_ssid.SSID_len);
824913211 } else {
825013212 /* P2P GO */
8251
- memset(&cfg->p2p->ssid.SSID[0], 0x00, 32);
8252
- memcpy(cfg->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len);
8253
- cfg->p2p->ssid.SSID_len = ssid_ie->len;
13213
+ bzero(&cfg->p2p->ssid.SSID[0], DOT11_MAX_SSID_LEN);
13214
+ cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
13215
+ memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
13216
+ cfg->p2p->ssid.SSID_len);
825413217 }
825513218 }
825613219
....@@ -8279,14 +13242,16 @@
827913242 } else {
828013243 WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
828113244 }
8282
-#endif
13245
+#endif // endif
13246
+
13247
+ is_bss_up = wl_cfg80211_bss_isup(dev, bssidx);
828313248
828413249 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
828513250 privacy = info->privacy;
828613251 #else
828713252 privacy = 0;
8288
-#endif
8289
- if (!wl_cfgp2p_bss_isup(dev, bssidx) &&
13253
+#endif // endif
13254
+ if (!is_bss_up &&
829013255 (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx, privacy) < 0))
829113256 {
829213257 WL_ERR(("Beacon set security failed \n"));
....@@ -8296,22 +13261,31 @@
829613261
829713262 /* Set BI and DTIM period */
829813263 if (info->interval) {
8299
- if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD,
8300
- &info->interval, sizeof(s32), true)) < 0) {
13264
+ if ((err = wldev_ioctl_set(dev, WLC_SET_BCNPRD,
13265
+ &info->interval, sizeof(s32))) < 0) {
830113266 WL_ERR(("Beacon Interval Set Error, %d\n", err));
830213267 return err;
830313268 }
830413269 }
830513270 if (info->dtim_period) {
8306
- if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD,
8307
- &info->dtim_period, sizeof(s32), true)) < 0) {
13271
+ if ((err = wldev_ioctl_set(dev, WLC_SET_DTIMPRD,
13272
+ &info->dtim_period, sizeof(s32))) < 0) {
830813273 WL_ERR(("DTIM Interval Set Error, %d\n", err));
830913274 return err;
831013275 }
831113276 }
831213277
8313
- if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0) {
13278
+ /* If bss is already up, skip bring up */
13279
+ if (!is_bss_up &&
13280
+ (err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0)
13281
+ {
831413282 WL_ERR(("Beacon bring up AP/GO failed \n"));
13283
+ goto fail;
13284
+ }
13285
+
13286
+ /* Set GC/STA SCB expiry timings. */
13287
+ if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
13288
+ WL_ERR(("scb setting failed \n"));
831513289 goto fail;
831613290 }
831713291
....@@ -8333,11 +13307,11 @@
833313307 }
833413308
833513309 WL_DBG(("** ADD/SET beacon done **\n"));
13310
+ wl_set_drv_status(cfg, CONNECTED, dev);
833613311
833713312 fail:
833813313 if (err) {
833913314 WL_ERR(("ADD/SET beacon failed\n"));
8340
- wldev_iovar_setint(dev, "mpc", 1);
834113315 if (dev_role == NL80211_IFTYPE_AP) {
834213316 /* clear the AP mode */
834313317 dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
....@@ -8346,140 +13320,61 @@
834613320 return err;
834713321
834813322 }
8349
-#endif
835013323
8351
-#ifdef WL_SCHED_SCAN
8352
-#define PNO_TIME 30
8353
-#define PNO_REPEAT 4
8354
-#define PNO_FREQ_EXPO_MAX 2
8355
-static bool
8356
-is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count)
13324
+static s32
13325
+wl_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
835713326 {
8358
- int i;
8359
-
8360
- if (!ssid || !ssid_list)
8361
- return FALSE;
8362
-
8363
- for (i = 0; i < count; i++) {
8364
- if (ssid->ssid_len == ssid_list[i].ssid_len) {
8365
- if (strncmp(ssid->ssid, ssid_list[i].ssid, ssid->ssid_len) == 0)
8366
- return TRUE;
8367
- }
8368
- }
8369
- return FALSE;
8370
-}
8371
-
8372
-static int
8373
-wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
8374
- struct net_device *dev,
8375
- struct cfg80211_sched_scan_request *request)
8376
-{
8377
- ushort pno_time = PNO_TIME;
8378
- int pno_repeat = PNO_REPEAT;
8379
- int pno_freq_expo_max = PNO_FREQ_EXPO_MAX;
8380
- wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
13327
+ int err = 0;
13328
+ s32 bssidx = 0;
13329
+ int infra = 0;
13330
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
838113331 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8382
- struct cfg80211_ssid *ssid = NULL;
8383
- struct cfg80211_ssid *hidden_ssid_list = NULL;
8384
- int ssid_cnt = 0;
8385
- int i;
8386
- int ret = 0;
8387
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
8388
- s32 rssi_thold = 0;
8389
-#endif /* LINUX_KERNEL_VER >= 3.6 */
13332
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
839013333
8391
- if (!request) {
8392
- WL_ERR(("Sched scan request was NULL\n"));
13334
+ WL_DBG(("Enter. \n"));
13335
+
13336
+ if (!wdev) {
13337
+ WL_ERR(("wdev null \n"));
839313338 return -EINVAL;
839413339 }
839513340
8396
- WL_DBG(("Enter \n"));
8397
- WL_PNO((">>> SCHED SCAN START\n"));
8398
- WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n",
8399
- request->n_match_sets, request->n_ssids));
8400
- WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
8401
- request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
8402
-
8403
-
8404
- if (!request->n_ssids || !request->n_match_sets) {
8405
- WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids));
8406
- return -EINVAL;
13341
+ if ((wdev->iftype != NL80211_IFTYPE_P2P_GO) && (wdev->iftype != NL80211_IFTYPE_AP)) {
13342
+ WL_ERR(("Unspported iface type iftype:%d \n", wdev->iftype));
840713343 }
840813344
8409
- memset(&ssids_local, 0, sizeof(ssids_local));
13345
+ wl_clr_drv_status(cfg, AP_CREATING, dev);
13346
+ wl_clr_drv_status(cfg, AP_CREATED, dev);
841013347
8411
- if (request->n_ssids > 0) {
8412
- hidden_ssid_list = request->ssids;
13348
+ /* Clear AP/GO connected status */
13349
+ wl_clr_drv_status(cfg, CONNECTED, dev);
13350
+
13351
+ cfg->ap_oper_channel = 0;
13352
+
13353
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
13354
+ WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
13355
+ return BCME_ERROR;
841313356 }
841413357
8415
- for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) {
8416
- ssid = &request->match_sets[i].ssid;
8417
- /* No need to include null ssid */
8418
- if (ssid->ssid_len) {
8419
- memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid, ssid->ssid_len);
8420
- ssids_local[ssid_cnt].SSID_len = ssid->ssid_len;
8421
- if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) {
8422
- ssids_local[ssid_cnt].hidden = TRUE;
8423
- WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid));
8424
- } else {
8425
- ssids_local[ssid_cnt].hidden = FALSE;
8426
- WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid->ssid));
8427
- }
8428
-
8429
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
8430
- /* Per BSS rssi threshold is available from kernel >= 3.15 */
8431
- rssi_thold = request->match_sets[i].rssi_thold;
8432
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
8433
- /* Blanket rssi threshold only available from cfg80211 */
8434
- rssi_thold = request->rssi_thold;
8435
-#endif /* KERNEL_VER >= 3.15 */
8436
-
8437
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
8438
- if (rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) {
8439
- ssids_local[ssid_cnt].rssi_thresh =
8440
- (int8)rssi_thold;
8441
- }
8442
-#endif /* KERNEL_VER >= 3.6 */
8443
- ssid_cnt++;
8444
- }
13358
+ /* Do bss down */
13359
+ if ((err = wl_cfg80211_bss_up(cfg, dev, bssidx, 0)) < 0) {
13360
+ WL_ERR(("bss down error %d\n", err));
844513361 }
844613362
8447
- if (ssid_cnt) {
8448
- if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, ssid_cnt,
8449
- pno_time, pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) {
8450
- WL_ERR(("PNO setup failed!! ret=%d \n", ret));
8451
- return -EINVAL;
8452
- }
8453
- cfg->sched_scan_req = request;
8454
- } else {
8455
- return -EINVAL;
13363
+ /* fall through is intentional */
13364
+ err = wldev_ioctl_set(dev, WLC_SET_INFRA, &infra, sizeof(s32));
13365
+ if (err < 0) {
13366
+ WL_ERR(("SET INFRA error %d\n", err));
13367
+ }
13368
+ wl_cfg80211_clear_per_bss_ies(cfg, dev->ieee80211_ptr);
13369
+
13370
+ if (wdev->iftype == NL80211_IFTYPE_AP) {
13371
+ /* clear the AP mode */
13372
+ dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
845613373 }
845713374
845813375 return 0;
845913376 }
8460
-
8461
-static int
8462
-wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
8463
-{
8464
- struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8465
-
8466
- WL_DBG(("Enter \n"));
8467
- WL_PNO((">>> SCHED SCAN STOP\n"));
8468
-
8469
- if (dhd_dev_pno_stop_for_ssid(dev) < 0)
8470
- WL_ERR(("PNO Stop for SSID failed"));
8471
-
8472
- if (cfg->scan_request && cfg->sched_scan_running) {
8473
- WL_PNO((">>> Sched scan running. Aborting it..\n"));
8474
- wl_notify_escan_complete(cfg, dev, true, true);
8475
- }
8476
-
8477
- cfg->sched_scan_req = NULL;
8478
- cfg->sched_scan_running = FALSE;
8479
-
8480
- return 0;
8481
-}
8482
-#endif /* WL_SCHED_SCAN */
13377
+#endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
848313378
848413379 #ifdef WL_SUPPORT_ACS
848513380 /*
....@@ -8543,8 +13438,9 @@
854313438 cca_stats_n_flags *results;
854413439 char *buf;
854513440 int retry, err;
13441
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
854613442
8547
- buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL);
13443
+ buf = (char *)MALLOCZ(cfg->osh, sizeof(char) * WLC_IOCTL_MAXLEN);
854813444 if (unlikely(!buf)) {
854913445 WL_ERR(("%s: buf alloc failed\n", __func__));
855013446 return -ENOMEM;
....@@ -8569,11 +13465,11 @@
856913465
857013466 results = (cca_stats_n_flags *)(buf);
857113467 wl_parse_dump_obss(results->buf, survey);
8572
- kfree(buf);
13468
+ MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
857313469
857413470 return 0;
857513471 exit:
8576
- kfree(buf);
13472
+ MFREE(cfg->osh, buf, sizeof(char) * WLC_IOCTL_MAXLEN);
857713473 return err;
857813474 }
857913475
....@@ -8613,18 +13509,9 @@
861313509 }
861413510
861513511 if (!idx) {
8616
- /* Disable mpc */
8617
- val = 0;
8618
- err = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val,
8619
- sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
8620
- &cfg->ioctl_buf_sync);
8621
- if (err < 0) {
8622
- WL_ERR(("set 'mpc' failed, error = %d\n", err));
8623
- }
8624
-
862513512 /* Set interface up, explicitly. */
862613513 val = 1;
8627
- err = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true);
13514
+ err = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
862813515 if (err < 0) {
862913516 WL_ERR(("set interface up failed, error = %d\n", err));
863013517 }
....@@ -8634,8 +13521,8 @@
863413521 retry = IOCTL_RETRY_COUNT;
863513522 while (retry--) {
863613523 noise = 0;
8637
- err = wldev_ioctl(ndev, WLC_GET_PHY_NOISE, &noise,
8638
- sizeof(noise), false);
13524
+ err = wldev_ioctl_get(ndev, WLC_GET_PHY_NOISE, &noise,
13525
+ sizeof(noise));
863913526 if (err >= 0) {
864013527 break;
864113528 }
....@@ -8648,8 +13535,8 @@
864813535 noise = CHAN_NOISE_DUMMY;
864913536 }
865013537
8651
- survey = (struct wl_dump_survey *) kzalloc(sizeof(struct wl_dump_survey),
8652
- GFP_KERNEL);
13538
+ survey = (struct wl_dump_survey *)MALLOCZ(cfg->osh,
13539
+ sizeof(struct wl_dump_survey));
865313540 if (unlikely(!survey)) {
865413541 WL_ERR(("%s: alloc failed\n", __func__));
865513542 return -ENOMEM;
....@@ -8684,11 +13571,11 @@
868413571 info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
868513572 SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
868613573 SURVEY_INFO_CHANNEL_TIME_TX;
8687
- kfree(survey);
13574
+ MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
868813575
868913576 return 0;
869013577 exit:
8691
- kfree(survey);
13578
+ MFREE(cfg->osh, survey, sizeof(struct wl_dump_survey));
869213579 return err;
869313580 }
869413581 #endif /* WL_SUPPORT_ACS */
....@@ -8702,6 +13589,9 @@
870213589 .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
870313590 #endif /* WL_CFG80211_P2P_DEV_IF */
870413591 .scan = wl_cfg80211_scan,
13592
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0))
13593
+ .abort_scan = wl_cfg80211_abort_scan,
13594
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) */
870513595 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
870613596 .join_ibss = wl_cfg80211_join_ibss,
870713597 .leave_ibss = wl_cfg80211_leave_ibss,
....@@ -8724,19 +13614,24 @@
872413614 .remain_on_channel = wl_cfg80211_remain_on_channel,
872513615 .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
872613616 .mgmt_tx = wl_cfg80211_mgmt_tx,
13617
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0))
13618
+ .update_mgmt_frame_registrations = wl_cfg80211_update_mgmt_frame_register,
13619
+#else
872713620 .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
13621
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) */
872813622 .change_bss = wl_cfg80211_change_bss,
8729
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
13623
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS)
873013624 .set_channel = wl_cfg80211_set_channel,
8731
-#endif
8732
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
13625
+#endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
13626
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS)
873313627 .set_beacon = wl_cfg80211_add_set_beacon,
873413628 .add_beacon = wl_cfg80211_add_set_beacon,
13629
+ .del_beacon = wl_cfg80211_del_beacon,
873513630 #else
873613631 .change_beacon = wl_cfg80211_change_beacon,
873713632 .start_ap = wl_cfg80211_start_ap,
873813633 .stop_ap = wl_cfg80211_stop_ap,
8739
-#endif
13634
+#endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
874013635 #ifdef WL_SCHED_SCAN
874113636 .sched_scan_start = wl_cfg80211_sched_scan_start,
874213637 .sched_scan_stop = wl_cfg80211_sched_scan_stop,
....@@ -8747,10 +13642,10 @@
874713642 .change_station = wl_cfg80211_change_station,
874813643 .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
874913644 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
8750
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
13645
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
875113646 .tdls_mgmt = wl_cfg80211_tdls_mgmt,
875213647 .tdls_oper = wl_cfg80211_tdls_oper,
8753
-#endif
13648
+#endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
875413649 #ifdef WL_SUPPORT_ACS
875513650 .dump_survey = wl_cfg80211_dump_survey,
875613651 #endif /* WL_SUPPORT_ACS */
....@@ -8761,7 +13656,23 @@
876113656 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
876213657 .set_rekey_data = wl_cfg80211_set_rekey_data,
876313658 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
8764
-#endif
13659
+#endif /* GTK_OFFLOAD_SUPPORT */
13660
+#if defined(WL_FILS) || defined(WL_OWE)
13661
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
13662
+ /* This should be enabled from kernel version which supports this */
13663
+ .update_connect_params = wl_cfg80211_update_connect_params,
13664
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) */
13665
+#endif /* WL_FILS || defined(WL_OWE) */
13666
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
13667
+ .set_pmk = wl_cfg80211_set_pmk,
13668
+ .del_pmk = wl_cfg80211_del_pmk,
13669
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
13670
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
13671
+ .channel_switch = wl_cfg80211_channel_switch,
13672
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
13673
+#ifdef WL_SAE
13674
+ .external_auth = wl_cfg80211_external_auth,
13675
+#endif /* WL_SAE */
876513676 };
876613677
876713678 s32 wl_mode_to_nl80211_iftype(s32 mode)
....@@ -8782,59 +13693,32 @@
878213693 return err;
878313694 }
878413695
8785
-#ifdef CONFIG_CFG80211_INTERNAL_REGDB
8786
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
8787
-static int
8788
-#else
8789
-static void
8790
-#endif /* kernel version < 3.9.0 */
8791
-wl_cfg80211_reg_notifier(
8792
- struct wiphy *wiphy,
8793
- struct regulatory_request *request)
13696
+s32
13697
+wl_cfg80211_set_country_code(struct net_device *net, char *country_code,
13698
+ bool notify, bool user_enforced, int revinfo)
879413699 {
8795
- struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
8796
- int ret = 0;
8797
- int revinfo = -1;
8798
-
8799
- if (!request || !cfg) {
8800
- WL_ERR(("Invalid arg\n"));
8801
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
8802
- return -EINVAL;
8803
-#else
8804
- return;
8805
-#endif /* kernel version < 3.9.0 */
13700
+ s32 ret = BCME_OK;
13701
+#ifdef WL_NAN
13702
+ struct wireless_dev *wdev = ndev_to_wdev(net);
13703
+ struct wiphy *wiphy = wdev->wiphy;
13704
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
13705
+ if (cfg->nan_enable) {
13706
+ mutex_lock(&cfg->if_sync);
13707
+ ret = wl_cfgnan_disable(cfg, NAN_COUNTRY_CODE_CHANGE);
13708
+ mutex_unlock(&cfg->if_sync);
13709
+ if (ret != BCME_OK) {
13710
+ WL_ERR(("failed to disable nan, error[%d]\n", ret));
13711
+ return ret;
13712
+ }
880613713 }
8807
-
8808
- WL_DBG(("ccode: %c%c Initiator: %d\n",
8809
- request->alpha2[0], request->alpha2[1], request->initiator));
8810
-
8811
- /* We support only REGDOM_SET_BY_USER as of now */
8812
- if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
8813
- (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
8814
- WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
8815
- request->initiator));
8816
- /* in case of no supported country by regdb
8817
- lets driver setup platform default Locale
8818
- */
8819
- }
8820
-
8821
- WL_ERR(("Set country code %c%c from %s\n",
8822
- request->alpha2[0], request->alpha2[1],
8823
- ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User")));
8824
-
8825
- if ((ret = wldev_set_country(bcmcfg_to_prmry_ndev(cfg), request->alpha2,
8826
- false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false),
8827
- revinfo)) < 0) {
13714
+#endif /* WL_NAN */
13715
+ ret = wldev_set_country(net, country_code,
13716
+ notify, user_enforced, revinfo);
13717
+ if (ret < 0) {
882813718 WL_ERR(("set country Failed :%d\n", ret));
882913719 }
8830
-
8831
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
883213720 return ret;
8833
-#else
8834
- return;
8835
-#endif /* kernel version < 3.9.0 */
883613721 }
8837
-#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
883813722
883913723 #ifdef CONFIG_PM
884013724 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
....@@ -8850,6 +13734,32 @@
885013734 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
885113735 #endif /* CONFIG_PM */
885213736
13737
+int wl_features_set(u8 *array, uint8 len, u32 ftidx)
13738
+{
13739
+ u8* ft_byte;
13740
+
13741
+ if ((ftidx / 8u) >= len)
13742
+ return BCME_BADARG;
13743
+
13744
+ ft_byte = &array[ftidx / 8u];
13745
+ *ft_byte |= BIT(ftidx % 8u);
13746
+ return BCME_OK;
13747
+}
13748
+
13749
+#ifdef WL_SAE
13750
+static s32 wl_wiphy_update_sae(struct wiphy *wiphy, dhd_pub_t *dhd)
13751
+{
13752
+
13753
+ if (FW_SUPPORTED(dhd, sae_ext)) {
13754
+ WL_DBG(("%s extsae enabled\n", __FUNCTION__));
13755
+ wiphy->features |= NL80211_FEATURE_SAE;
13756
+ } else if ((FW_SUPPORTED(dhd, sae)) && (FW_SUPPORTED(dhd, idsup))) {
13757
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SAE_OFFLOAD);
13758
+ WL_DBG(("%s intsae enabled\n", __FUNCTION__));
13759
+ }
13760
+ return BCME_OK;
13761
+}
13762
+#endif /* WL_SAE */
885313763 static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context)
885413764 {
885513765 s32 err = 0;
....@@ -8859,7 +13769,7 @@
885913769 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
886013770 #endif /* CONFIG_PM */
886113771
8862
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
13772
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
886313773 dhd_pub_t *dhd = (dhd_pub_t *)context;
886413774 BCM_REFERENCE(dhd);
886513775
....@@ -8868,7 +13778,7 @@
886813778 err = -ENODEV;
886913779 return err;
887013780 }
8871
-#endif
13781
+#endif // endif
887213782
887313783 wdev->wiphy =
887413784 wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
....@@ -8886,7 +13796,11 @@
888613796 wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
888713797 wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
888813798 wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
13799
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
888913800 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
13801
+#else
13802
+ wdev->wiphy->max_sched_scan_reqs = 1;
13803
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)) */
889013804 #endif /* WL_SCHED_SCAN */
889113805 wdev->wiphy->interface_modes =
889213806 BIT(NL80211_IFTYPE_STATION)
....@@ -8925,29 +13839,28 @@
892513839 #endif /* !WL_POWERSAVE_DISABLED */
892613840 wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
892713841 WIPHY_FLAG_4ADDR_AP |
8928
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39))
13842
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS)
892913843 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
8930
-#endif
13844
+#endif // endif
893113845 WIPHY_FLAG_4ADDR_STATION;
8932
-#if ((defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && (LINUX_VERSION_CODE >= \
8933
- KERNEL_VERSION(3, 2, 0)))
13846
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
893413847 /*
8935
- * If FW ROAM flag is advertised, upper layer wouldn't provide
8936
- * the bssid & freq in the connect command. This will result a
8937
- * delay in initial connection time due to firmware doing a full
8938
- * channel scan to figure out the channel & bssid. However kernel
8939
- * ver >= 3.15, provides bssid_hint & freq_hint and hence kernel
8940
- * ver >= 3.15 won't have any issue. So if this flags need to be
8941
- * advertised for kernel < 3.15, suggest to use RCC along with it
8942
- * to avoid the initial connection delay.
13848
+ * If FW ROAM flag is advertised, upper layer doesn't provide the
13849
+ * bssid & freq in the connect command. However, kernel ver >= 3.15,
13850
+ * provides bssid_hint & freq_hint which can be used by the firmware.
13851
+ * fw_ap_select variable determines whether FW selects the AP or the
13852
+ * user space selects the target AP within the given ESS.
894313853 */
8944
- wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
8945
-#endif
894613854
8947
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
13855
+ if (!us_ap_select)
13856
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
13857
+ else
13858
+ WL_MEM(("upper layer roam is selected %s\n", __FUNCTION__));
13859
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
13860
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
894813861 wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
894913862 WIPHY_FLAG_OFFCHAN_TX;
8950
-#endif
13863
+#endif // endif
895113864 #if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
895213865 4, 0))
895313866 /* From 3.4 kernel ownards AP_SME flag can be advertised
....@@ -8958,9 +13871,9 @@
895813871 #ifdef WL_CFG80211_ACL
895913872 /* Configure ACL capabilities. */
896013873 wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
8961
-#endif
13874
+#endif // endif
896213875
8963
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
13876
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
896413877 /* Supplicant distinguish between the SoftAP mode and other
896513878 * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
896613879 * response frame from Supplicant MR1 and Kernel 3.4.0 or
....@@ -8972,12 +13885,12 @@
897213885 wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
897313886 wdev->wiphy->probe_resp_offload = 0;
897413887 }
8975
-#endif
13888
+#endif // endif
897613889 #endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
897713890
8978
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
13891
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
897913892 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
8980
-#endif
13893
+#endif // endif
898113894
898213895 #if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
898313896 /*
....@@ -8989,8 +13902,10 @@
898913902 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
899013903 wdev->wiphy->wowlan = &brcm_wowlan_support;
899113904 /* If this is not provided cfg stack will get disconnect
8992
- * during suspend.
8993
- */
13905
+ * during suspend.
13906
+ * Note: wiphy->wowlan_config is freed by cfg80211 layer.
13907
+ * so use malloc instead of MALLOC(osh) to avoid false alarm.
13908
+ */
899413909 brcm_wowlan_config = kmalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL);
899513910 if (brcm_wowlan_config) {
899613911 brcm_wowlan_config->disconnect = true;
....@@ -9002,10 +13917,10 @@
900213917 brcm_wowlan_config->tcp = NULL;
900313918 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
900413919 brcm_wowlan_config->nd_config = NULL;
9005
-#endif
13920
+#endif // endif
900613921 } else {
900713922 WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
9008
- " So wiphy->wowlan_config is set to NULL\n"));
13923
+ " So wiphy->wowlan_config is set to NULL\n"));
900913924 }
901013925 wdev->wiphy->wowlan_config = brcm_wowlan_config;
901113926 #else
....@@ -9024,26 +13939,69 @@
902413939 wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
902513940 #else
902613941 wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
9027
-#endif
13942
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0) */
902813943 wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
9029
-#if defined(WL_VENDOR_EXT_SUPPORT)
9030
- WL_ERR(("Registering Vendor80211\n"));
13944
+
13945
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
13946
+ WL_INFORM_MEM(("Registering Vendor80211\n"));
903113947 err = wl_cfgvendor_attach(wdev->wiphy, dhd);
903213948 if (unlikely(err < 0)) {
903313949 WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
903413950 }
9035
-#endif /* defined(WL_VENDOR_EXT_SUPPORT) */
13951
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
13952
+#ifdef WL_FILS
13953
+ wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
13954
+#endif /* WL_FILS */
13955
+
13956
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
13957
+ wdev->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
13958
+ wdev->wiphy->max_num_csa_counters = WL_MAX_NUM_CSA_COUNTERS;
13959
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 12, 0) */
13960
+
13961
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
13962
+ KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
13963
+ wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
13964
+#endif // endif
13965
+
13966
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && \
13967
+ defined(SUPPORT_RANDOM_MAC_SCAN)
13968
+ wdev->wiphy->features |= (NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
13969
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR);
13970
+ wdev->wiphy->max_sched_scan_plans = 1; /* multiple plans not supported */
13971
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && defined(SUPPORT_RANDOM_MAC_SCAN) */
13972
+
13973
+#ifdef WL_SAE
13974
+ wdev->wiphy->features |= NL80211_FEATURE_SAE;
13975
+#endif /* WL_SAE */
13976
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)) && defined(BCMSUP_4WAY_HANDSHAKE)
13977
+ if (FW_SUPPORTED(dhd, idsup)) {
13978
+ err = wiphy_ext_feature_set(wdev->wiphy,
13979
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
13980
+ if (err) {
13981
+ return err;
13982
+ }
13983
+ err = wiphy_ext_feature_set(wdev->wiphy,
13984
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
13985
+ if (err) {
13986
+ return err;
13987
+ }
13988
+ }
13989
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) && defined(BCMSUP_4WAY_HANDSHAKE) */
13990
+#ifdef WL_SCAN_TYPE
13991
+ /* These scan types will be mapped to default scan on non-supported chipset */
13992
+ /* Advertise scan type capability. */
13993
+ wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_SPAN_SCAN);
13994
+ wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_LOW_POWER_SCAN);
13995
+ wiphy_ext_feature_set(wdev->wiphy, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
13996
+ wdev->wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN;
13997
+#endif /* WL_SCAN_TYPE */
13998
+
903613999 /* Now we can register wiphy with cfg80211 module */
903714000 err = wiphy_register(wdev->wiphy);
903814001 if (unlikely(err < 0)) {
903914002 WL_ERR(("Couldn not register wiphy device (%d)\n", err));
904014003 wiphy_free(wdev->wiphy);
904114004 }
9042
-
9043
-#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
9044
- KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
9045
- wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
9046
-#endif
904714005
904814006 return err;
904914007 }
....@@ -9059,53 +14017,63 @@
905914017 if (wdev->wiphy) {
906014018 wiphy = wdev->wiphy;
906114019
9062
-#if defined(WL_VENDOR_EXT_SUPPORT)
14020
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
906314021 wl_cfgvendor_detach(wdev->wiphy);
9064
-#endif /* if defined(WL_VENDOR_EXT_SUPPORT) */
9065
-#ifdef CONFIG_PM
14022
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
906614023 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
9067
- /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
9068
- WL_DBG(("wl_free_wdev Clearing wowlan Config \n"));
14024
+ /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
14025
+ WL_DBG(("clear wowlan\n"));
906914026 wdev->wiphy->wowlan = NULL;
9070
- if (wdev->wiphy->wowlan_config) {
9071
- kfree(wdev->wiphy->wowlan_config);
9072
- wdev->wiphy->wowlan_config = NULL;
9073
- }
907414027 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
9075
-#endif /* CONFIG_PM */
907614028 wiphy_unregister(wdev->wiphy);
907714029 wdev->wiphy->dev.parent = NULL;
907814030 wdev->wiphy = NULL;
907914031 }
908014032
908114033 wl_delete_all_netinfo(cfg);
9082
- if (wiphy)
14034
+ if (wiphy) {
14035
+ MFREE(cfg->osh, wdev, sizeof(*wdev));
908314036 wiphy_free(wiphy);
14037
+ }
908414038
908514039 /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
908614040 * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
908714041 */
908814042 }
908914043
9090
-static s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
14044
+s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
909114045 {
909214046 struct wl_scan_results *bss_list;
9093
- struct wl_bss_info *bi = NULL; /* must be initialized */
14047
+ wl_bss_info_t *bi = NULL; /* must be initialized */
909414048 s32 err = 0;
909514049 s32 i;
909614050
909714051 bss_list = cfg->bss_list;
9098
- WL_DBG(("scanned AP count (%d)\n", bss_list->count));
14052
+ WL_MEM(("scanned AP count (%d)\n", bss_list->count));
14053
+#ifdef ESCAN_CHANNEL_CACHE
14054
+ reset_roam_cache(cfg);
14055
+#endif /* ESCAN_CHANNEL_CACHE */
14056
+ preempt_disable();
909914057 bi = next_bss(bss_list, bi);
910014058 for_each_bss(bss_list, bi, i) {
14059
+#ifdef ESCAN_CHANNEL_CACHE
14060
+ add_roam_cache(cfg, bi);
14061
+#endif /* ESCAN_CHANNEL_CACHE */
910114062 err = wl_inform_single_bss(cfg, bi, false);
9102
- if (unlikely(err))
9103
- break;
14063
+ if (unlikely(err)) {
14064
+ WL_ERR(("bss inform failed\n"));
14065
+ }
910414066 }
14067
+ preempt_enable();
14068
+ WL_MEM(("cfg80211 scan cache updated\n"));
14069
+#ifdef ROAM_CHANNEL_CACHE
14070
+ /* print_roam_cache(); */
14071
+ update_roam_cache(cfg, ioctl_version);
14072
+#endif /* ROAM_CHANNEL_CACHE */
910514073 return err;
910614074 }
910714075
9108
-static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam)
14076
+static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, wl_bss_info_t *bi, bool update_ssid)
910914077 {
911014078 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
911114079 struct ieee80211_mgmt *mgmt;
....@@ -9115,19 +14083,34 @@
911514083 struct wl_scan_req *sr = wl_to_sr(cfg);
911614084 struct beacon_proberesp *beacon_proberesp;
911714085 struct cfg80211_bss *cbss = NULL;
14086
+#if defined(WL_SUPPORT_BSS_BOOTTIME) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
14087
+ struct cfg80211_inform_bss bss_data = {0x00, };
14088
+#endif /* WL_SUPPORT_BSS_BOOTTIME */
14089
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
14090
+ log_conn_event_t *event_data = NULL;
14091
+ tlv_log *tlv_data = NULL;
14092
+ u32 alloc_len, tlv_len;
14093
+ u32 payload_len;
911814094 s32 mgmt_type;
911914095 s32 signal;
912014096 u32 freq;
912114097 s32 err = 0;
912214098 gfp_t aflags;
14099
+ u8 tmp_buf[IEEE80211_MAX_SSID_LEN + 1];
912314100
912414101 if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
912514102 WL_DBG(("Beacon is larger than buffer. Discarding\n"));
912614103 return err;
912714104 }
14105
+
14106
+ if (bi->SSID_len > IEEE80211_MAX_SSID_LEN) {
14107
+ WL_ERR(("wrong SSID len:%d\n", bi->SSID_len));
14108
+ return -EINVAL;
14109
+ }
14110
+
912814111 aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
9129
- notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt)
9130
- - sizeof(u8) + WL_BSS_INFO_MAX, aflags);
14112
+ notif_bss_info = (struct wl_cfg80211_bss_info *)MALLOCZ(cfg->osh,
14113
+ sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
913114114 if (unlikely(!notif_bss_info)) {
913214115 WL_ERR(("notif_bss_info alloc failed\n"));
913314116 return -ENOMEM;
....@@ -9136,13 +14119,19 @@
913614119 notif_bss_info->channel =
913714120 wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
913814121
14122
+#ifdef WL_6E
14123
+ if (CHSPEC_IS6G(wl_chspec_driver_to_host(bi->chanspec))) {
14124
+ band = wiphy->bands[IEEE80211_BAND_6GHZ];
14125
+ } else
14126
+#endif /* WL_6E */
913914127 if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
914014128 band = wiphy->bands[IEEE80211_BAND_2GHZ];
914114129 else
914214130 band = wiphy->bands[IEEE80211_BAND_5GHZ];
914314131 if (!band) {
914414132 WL_ERR(("No valid band"));
9145
- kfree(notif_bss_info);
14133
+ MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
14134
+ + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
914614135 return -EINVAL;
914714136 }
914814137 notif_bss_info->rssi = wl_rssi_offset(dtoh16(bi->RSSI));
....@@ -9159,71 +14148,129 @@
915914148 beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
916014149 beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
916114150 wl_rst_ie(cfg);
9162
- wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, roam);
14151
+ wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, update_ssid);
916314152 wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
916414153 wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX -
916514154 offsetof(struct wl_cfg80211_bss_info, frame_buf));
916614155 notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
916714156 u.beacon.variable) + wl_get_ielen(cfg);
9168
-#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
14157
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
916914158 freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
917014159 (void)band->band;
917114160 #else
917214161 freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
9173
-#endif
14162
+#endif // endif
917414163 if (freq == 0) {
917514164 WL_ERR(("Invalid channel, fail to chcnage channel to freq\n"));
9176
- kfree(notif_bss_info);
14165
+ MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
14166
+ + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
917714167 return -EINVAL;
917814168 }
917914169 channel = ieee80211_get_channel(wiphy, freq);
918014170 if (unlikely(!channel)) {
918114171 WL_ERR(("ieee80211_get_channel error\n"));
9182
- kfree(notif_bss_info);
14172
+ MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
14173
+ + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
918314174 return -EINVAL;
918414175 }
9185
- WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
9186
- "mgmt_type %d frame_len %d\n", bi->SSID,
9187
- notif_bss_info->rssi, notif_bss_info->channel,
14176
+ memcpy(tmp_buf, bi->SSID, bi->SSID_len);
14177
+ tmp_buf[bi->SSID_len] = '\0';
14178
+ WL_DBG(("SSID : \"%s\", rssi %d, channel %d, freq %d, capability : 0x04%x, bssid %pM"
14179
+ "mgmt_type %d frame_len %d\n", tmp_buf,
14180
+ notif_bss_info->rssi, notif_bss_info->channel, freq,
918814181 mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type,
918914182 notif_bss_info->frame_len));
919014183
919114184 signal = notif_bss_info->rssi * 100;
14185
+#if defined(WL_SUPPORT_BSS_BOOTTIME) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
14186
+ bss_data.chan = channel;
14187
+ bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
14188
+ bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime());
14189
+ bss_data.signal = signal;
14190
+#endif /* WL_SUPPORT_BSS_BOOTTIME */
919214191 if (!mgmt->u.probe_resp.timestamp) {
9193
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
9194
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
9195
- struct timespec64 ts;
9196
- ktime_get_boottime_ts64(&ts);
14192
+#if defined(WL_SUPPORT_BSS_BOOTTIME) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
14193
+ mgmt->u.probe_resp.timestamp = bss_data.boottime_ns / 1000;
919714194 #else
14195
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0))
919814196 struct timespec ts;
14197
+#else
14198
+ struct timespec64 ts;
14199
+#endif // endif
919914200 get_monotonic_boottime(&ts);
9200
-#endif
920114201 mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000)
920214202 + ts.tv_nsec / 1000;
9203
-#else
9204
- struct timeval tv;
9205
- do_gettimeofday(&tv);
9206
- mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000)
9207
- + tv.tv_usec;
9208
-#endif
14203
+#endif /* WL_SUPPORT_BSS_BOOTTIME */
920914204 }
9210
-
9211
-
14205
+#if defined(WL_SUPPORT_BSS_BOOTTIME) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
14206
+ cbss = cfg80211_inform_bss_frame_data(wiphy, &bss_data, mgmt,
14207
+ le16_to_cpu(notif_bss_info->frame_len), aflags);
14208
+#else
921214209 cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
921314210 le16_to_cpu(notif_bss_info->frame_len), signal, aflags);
14211
+#endif /* WL_SUPPORT_BSS_BOOTTIME */
921414212 if (unlikely(!cbss)) {
9215
- WL_ERR(("cfg80211_inform_bss_frame error\n"));
9216
- kfree(notif_bss_info);
9217
- return -EINVAL;
14213
+ WL_ERR(("cfg80211_inform_bss_frame error bssid " MACDBG " channel %d \n",
14214
+ MAC2STRDBG((u8*)(&bi->BSSID)), notif_bss_info->channel));
14215
+ err = -EINVAL;
14216
+ goto out_err;
921814217 }
921914218
14219
+ CFG80211_PUT_BSS(wiphy, cbss);
922014220
9221
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
9222
- cfg80211_put_bss(wiphy, cbss);
9223
-#else
9224
- cfg80211_put_bss(cbss);
9225
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
9226
- kfree(notif_bss_info);
14221
+ if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID) &&
14222
+ (cfg->sched_scan_req && !cfg->scan_request)) {
14223
+ alloc_len = sizeof(log_conn_event_t) + IEEE80211_MAX_SSID_LEN + sizeof(uint16) +
14224
+ sizeof(int16);
14225
+ event_data = (log_conn_event_t *)MALLOCZ(dhdp->osh, alloc_len);
14226
+ if (!event_data) {
14227
+ WL_ERR(("%s: failed to allocate the log_conn_event_t with "
14228
+ "length(%d)\n", __func__, alloc_len));
14229
+ goto out_err;
14230
+ }
14231
+ tlv_len = 3 * sizeof(tlv_log);
14232
+ event_data->tlvs = (tlv_log *)MALLOCZ(cfg->osh, tlv_len);
14233
+ if (!event_data->tlvs) {
14234
+ WL_ERR(("%s: failed to allocate the log_conn_event_t with "
14235
+ "length(%d)\n", __func__, tlv_len));
14236
+ goto free_evt_data;
14237
+ }
14238
+
14239
+ payload_len = sizeof(log_conn_event_t);
14240
+ event_data->event = WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND;
14241
+ tlv_data = event_data->tlvs;
14242
+
14243
+ /* ssid */
14244
+ tlv_data->tag = WIFI_TAG_SSID;
14245
+ tlv_data->len = bi->SSID_len;
14246
+ memcpy(tlv_data->value, bi->SSID, bi->SSID_len);
14247
+ payload_len += TLV_LOG_SIZE(tlv_data);
14248
+ tlv_data = TLV_LOG_NEXT(tlv_data);
14249
+
14250
+ /* channel */
14251
+ tlv_data->tag = WIFI_TAG_CHANNEL;
14252
+ tlv_data->len = sizeof(uint16);
14253
+ memcpy(tlv_data->value, &notif_bss_info->channel, sizeof(uint16));
14254
+ payload_len += TLV_LOG_SIZE(tlv_data);
14255
+ tlv_data = TLV_LOG_NEXT(tlv_data);
14256
+
14257
+ /* rssi */
14258
+ tlv_data->tag = WIFI_TAG_RSSI;
14259
+ tlv_data->len = sizeof(int16);
14260
+ memcpy(tlv_data->value, &notif_bss_info->rssi, sizeof(int16));
14261
+ payload_len += TLV_LOG_SIZE(tlv_data);
14262
+ tlv_data = TLV_LOG_NEXT(tlv_data);
14263
+
14264
+ dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID,
14265
+ event_data, payload_len);
14266
+ MFREE(dhdp->osh, event_data->tlvs, tlv_len);
14267
+free_evt_data:
14268
+ MFREE(dhdp->osh, event_data, alloc_len);
14269
+ }
14270
+
14271
+out_err:
14272
+ MFREE(cfg->osh, notif_bss_info, sizeof(*notif_bss_info)
14273
+ + sizeof(*mgmt) - sizeof(u8) + WL_BSS_INFO_MAX);
922714274 return err;
922814275 }
922914276
....@@ -9232,10 +14279,45 @@
923214279 u32 event = ntoh32(e->event_type);
923314280 u32 status = ntoh32(e->status);
923414281 u16 flags = ntoh16(e->flags);
14282
+#if defined(CUSTOM_SET_OCLOFF) || defined(CUSTOM_SET_ANTNPM)
14283
+ dhd_pub_t *dhd;
14284
+ dhd = (dhd_pub_t *)(cfg->pub);
14285
+#endif /* CUSTOM_SET_OCLOFF || CUSTOM_SET_ANTNPM */
923514286
923614287 WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
923714288 if (event == WLC_E_SET_SSID) {
923814289 if (status == WLC_E_STATUS_SUCCESS) {
14290
+#ifdef CUSTOM_SET_OCLOFF
14291
+ if (dhd->ocl_off) {
14292
+ int err = 0;
14293
+ int ocl_enable = 0;
14294
+ err = wldev_iovar_setint(ndev, "ocl_enable", ocl_enable);
14295
+ if (err != 0) {
14296
+ WL_ERR(("[WIFI_SEC] wl_is_linkup: Set ocl_enable %d"
14297
+ " failed %d\n",
14298
+ ocl_enable, err));
14299
+ } else {
14300
+ WL_ERR(("[WIFI_SEC] wl_is_linkup: Set ocl_enable %d"
14301
+ " succeeded %d\n",
14302
+ ocl_enable, err));
14303
+ }
14304
+ }
14305
+#endif /* CUSTOM_SET_OCLOFF */
14306
+#ifdef CUSTOM_SET_ANTNPM
14307
+ if (dhd->mimo_ant_set) {
14308
+ int err = 0;
14309
+
14310
+ WL_ERR(("[WIFI_SEC] mimo_ant_set = %d\n", dhd->mimo_ant_set));
14311
+ err = wldev_iovar_setint(ndev, "txchain", dhd->mimo_ant_set);
14312
+ if (err != 0) {
14313
+ WL_ERR(("[WIFI_SEC] Fail set txchain\n"));
14314
+ }
14315
+ err = wldev_iovar_setint(ndev, "rxchain", dhd->mimo_ant_set);
14316
+ if (err != 0) {
14317
+ WL_ERR(("[WIFI_SEC] Fail set rxchain\n"));
14318
+ }
14319
+ }
14320
+#endif /* CUSTOM_SET_ANTNPM */
923914321 if (!wl_is_ibssmode(cfg, ndev))
924014322 return true;
924114323 }
....@@ -9257,15 +14339,11 @@
925714339 event == WLC_E_DISASSOC_IND ||
925814340 event == WLC_E_DISASSOC ||
925914341 event == WLC_E_DEAUTH) {
9260
-#if (WL_DBG_LEVEL > 0)
9261
- WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]));
9262
-#endif /* (WL_DBG_LEVEL > 0) */
14342
+ WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
926314343 return true;
926414344 } else if (event == WLC_E_LINK) {
926514345 if (!(flags & WLC_EVENT_MSG_LINK)) {
9266
-#if (WL_DBG_LEVEL > 0)
9267
- WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]));
9268
-#endif /* (WL_DBG_LEVEL > 0) */
14346
+ WL_ERR(("Link down Reason : %s\n", bcmevent_get_name(event)));
926914347 return true;
927014348 }
927114349 }
....@@ -9282,17 +14360,144 @@
928214360 return true;
928314361 if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
928414362 return true;
14363
+ if (event == WLC_E_ASSOC_RESP_IE && status != WLC_E_STATUS_SUCCESS)
14364
+ return true;
928514365
928614366 return false;
928714367 }
928814368
9289
-/* The mainline kernel >= 3.2.0 has support for indicating new/del station
9290
- * to AP/P2P GO via events. If this change is backported to kernel for which
9291
- * this driver is being built, then define WL_CFG80211_STA_EVENT. You
9292
- * should use this new/del sta event mechanism for BRCM supplicant >= 22.
9293
- */
14369
+#ifdef WL_SAE
929414370 static s32
9295
-wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14371
+wl_cfg80211_event_sae_key(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14372
+ wl_sae_key_info_t *sae_key)
14373
+{
14374
+ struct sk_buff *skb;
14375
+ gfp_t kflags;
14376
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
14377
+ int err = BCME_OK;
14378
+
14379
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
14380
+#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
14381
+ LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
14382
+ skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), BRCM_SAE_VENDOR_EVENT_BUF_LEN,
14383
+ BRCM_VENDOR_EVENT_SAE_KEY, kflags);
14384
+#else
14385
+ skb = cfg80211_vendor_event_alloc(wiphy, BRCM_SAE_VENDOR_EVENT_BUF_LEN,
14386
+ BRCM_VENDOR_EVENT_SAE_KEY, kflags);
14387
+#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
14388
+ /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
14389
+ if (!skb) {
14390
+ WL_ERR(("skb alloc failed"));
14391
+ err = BCME_NOMEM;
14392
+ goto done;
14393
+ }
14394
+
14395
+ WL_INFORM_MEM(("Received Sae Key event for "MACDBG" key length %x %x",
14396
+ MAC2STRDBG(sae_key->peer_mac), sae_key->pmk_len, sae_key->pmkid_len));
14397
+ nla_put(skb, BRCM_SAE_KEY_ATTR_PEER_MAC, ETHER_ADDR_LEN, sae_key->peer_mac);
14398
+ nla_put(skb, BRCM_SAE_KEY_ATTR_PMK, sae_key->pmk_len, sae_key->pmk);
14399
+ nla_put(skb, BRCM_SAE_KEY_ATTR_PMKID, sae_key->pmkid_len, sae_key->pmkid);
14400
+ cfg80211_vendor_event(skb, kflags);
14401
+
14402
+done:
14403
+ return err;
14404
+}
14405
+
14406
+static s32
14407
+wl_bss_handle_sae_auth(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14408
+ const wl_event_msg_t *event, void *data)
14409
+{
14410
+ int err = BCME_OK;
14411
+ uint status = ntoh32(event->status);
14412
+ wl_auth_event_t *auth_data;
14413
+ wl_sae_key_info_t sae_key;
14414
+ uint16 tlv_buf_len;
14415
+
14416
+ if (status == WLC_E_STATUS_SUCCESS) {
14417
+ auth_data = (wl_auth_event_t *)data;
14418
+ if (auth_data->version != WL_AUTH_EVENT_DATA_V1) {
14419
+ WL_ERR(("unknown auth event data version %x\n",
14420
+ auth_data->version));
14421
+ err = BCME_VERSION;
14422
+ goto done;
14423
+ }
14424
+
14425
+ tlv_buf_len = auth_data->length - WL_AUTH_EVENT_FIXED_LEN_V1;
14426
+
14427
+ /* check if PMK info present */
14428
+ sae_key.pmk = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
14429
+ WL_AUTH_PMK_TLV_ID, &(sae_key.pmk_len), BCM_XTLV_OPTION_ALIGN32);
14430
+ if (!sae_key.pmk || !sae_key.pmk_len) {
14431
+ WL_ERR(("Mandatory PMK info not present"));
14432
+ err = BCME_NOTFOUND;
14433
+ goto done;
14434
+ }
14435
+ /* check if PMKID info present */
14436
+ sae_key.pmkid = bcm_get_data_from_xtlv_buf(auth_data->xtlvs, tlv_buf_len,
14437
+ WL_AUTH_PMKID_TLV_ID, &(sae_key.pmkid_len), BCM_XTLV_OPTION_ALIGN32);
14438
+ if (!sae_key.pmkid || !sae_key.pmkid_len) {
14439
+ WL_ERR(("Mandatory PMKID info not present\n"));
14440
+ err = BCME_NOTFOUND;
14441
+ goto done;
14442
+ }
14443
+ memcpy_s(sae_key.peer_mac, ETHER_ADDR_LEN, event->addr.octet, ETHER_ADDR_LEN);
14444
+ err = wl_cfg80211_event_sae_key(cfg, ndev, &sae_key);
14445
+ if (err) {
14446
+ WL_ERR(("Failed to event sae key info\n"));
14447
+ }
14448
+ } else {
14449
+ WL_ERR(("sae auth status failure:%d\n", status));
14450
+ }
14451
+done:
14452
+ return err;
14453
+}
14454
+#endif /* WL_SAE */
14455
+
14456
+static s32
14457
+wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14458
+ const wl_event_msg_t *e, void *data)
14459
+{
14460
+ u32 reason = ntoh32(e->reason);
14461
+ u32 event = ntoh32(e->event_type);
14462
+#ifdef WL_SAE
14463
+ uint auth_type = ntoh32(e->auth_type);
14464
+#endif /* WL_SAE */
14465
+ struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
14466
+ WL_DBG(("event type : %d, reason : %d\n", event, reason));
14467
+
14468
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
14469
+ (void)memcpy_s(&cfg->event_auth_assoc, sizeof(wl_event_msg_t),
14470
+ e, sizeof(wl_event_msg_t));
14471
+ WL_ERR(("event=%d status %d reason %d \n",
14472
+ ntoh32(cfg->event_auth_assoc.event_type),
14473
+ ntoh32(cfg->event_auth_assoc.status),
14474
+ ntoh32(cfg->event_auth_assoc.reason)));
14475
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
14476
+ if (sec) {
14477
+ switch (event) {
14478
+ case WLC_E_ASSOC:
14479
+ case WLC_E_AUTH:
14480
+ case WLC_E_AUTH_IND:
14481
+ sec->auth_assoc_res_status = reason;
14482
+#ifdef WL_SAE
14483
+ if ((event == WLC_E_AUTH || event == WLC_E_AUTH_IND) &&
14484
+ auth_type == DOT11_SAE) {
14485
+ wl_bss_handle_sae_auth(cfg, ndev, e, data);
14486
+ }
14487
+#endif /* WL_SAE */
14488
+ break;
14489
+ default:
14490
+ break;
14491
+ }
14492
+ } else {
14493
+ WL_ERR(("sec is NULL\n"));
14494
+ }
14495
+ return 0;
14496
+}
14497
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) \
14498
+ && !defined(WL_COMPAT_WIRELESS)) || defined(WL_CFG80211_AP_RX_MGMT_DISCONNECT)
14499
+static s32
14500
+wl_notify_connect_status_ap_rx_mgmt(struct bcm_cfg80211 *cfg, struct net_device *ndev,
929614501 const wl_event_msg_t *e, void *data)
929714502 {
929814503 s32 err = 0;
....@@ -9300,7 +14505,6 @@
930014505 u32 reason = ntoh32(e->reason);
930114506 u32 len = ntoh32(e->datalen);
930214507
9303
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
930414508 bool isfree = false;
930514509 u8 *mgmt_frame;
930614510 u8 bsscfgidx = e->bsscfgidx;
....@@ -9314,26 +14518,7 @@
931414518 struct ether_addr bssid;
931514519 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
931614520 channel_info_t ci;
9317
-#else
9318
- struct station_info sinfo;
9319
-#endif
932014521
9321
- WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason));
9322
- /* if link down, bsscfg is disabled. */
9323
- if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
9324
- wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
9325
- wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
9326
- WL_INFORM(("AP mode link down !! \n"));
9327
- complete(&cfg->iface_disable);
9328
- return 0;
9329
- }
9330
-
9331
- if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
9332
- WL_ERR(("event %s(%d) status %d reason %d\n",
9333
- bcmevent_get_name(event), event, ntoh32(e->status), reason));
9334
- }
9335
-
9336
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
933714522 WL_DBG(("Enter \n"));
933814523 if (!len && (event == WLC_E_DEAUTH)) {
933914524 len = 2; /* reason code field */
....@@ -9360,7 +14545,7 @@
936014545 NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
936114546 memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
936214547 memset(&bssid, 0, sizeof(bssid));
9363
- err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
14548
+ err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
936414549 switch (event) {
936514550 case WLC_E_ASSOC_IND:
936614551 fc = FC_ASSOC_REQ;
....@@ -9382,7 +14567,7 @@
938214567 goto exit;
938314568 }
938414569 memset(&ci, 0, sizeof(ci));
9385
- if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) {
14570
+ if ((err = wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) {
938614571 kfree(body);
938714572 return err;
938814573 }
....@@ -9398,52 +14583,122 @@
939814583 kfree(body);
939914584 return -EINVAL;
940014585 }
9401
-#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
14586
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
940214587 freq = ieee80211_channel_to_frequency(channel);
940314588 (void)band->band;
940414589 #else
940514590 freq = ieee80211_channel_to_frequency(channel, band->band);
9406
-#endif
9407
-
9408
- err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
14591
+#endif // endif
14592
+ err = wl_frame_get_mgmt(cfg, fc, &da, &e->addr, &bssid,
940914593 &mgmt_frame, &len, body);
941014594 if (err < 0)
941114595 goto exit;
941214596 isfree = true;
941314597
9414
- if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
9415
-#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) && (LINUX_VERSION_CODE < \
9416
- KERNEL_VERSION(3, 18, 0)))
9417
- cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
9418
-
9419
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
9420
- cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len);
9421
-#else
9422
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
9423
-#endif
14598
+ if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
14599
+ reason == DOT11_SC_SUCCESS) {
14600
+ CFG80211_RX_MGMT(ndev, freq, 0, mgmt_frame, len,
14601
+ NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
942414602 } else if (event == WLC_E_DISASSOC_IND) {
9425
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
9426
- cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
9427
-#else
9428
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
9429
-#endif
14603
+ CFG80211_RX_MGMT(ndev, freq, 0, mgmt_frame, len,
14604
+ NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
943014605 } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
9431
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
9432
- cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
9433
-#else
9434
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
9435
-#endif
14606
+ CFG80211_RX_MGMT(ndev, freq, 0, mgmt_frame, len,
14607
+ NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
943614608 }
943714609
9438
-exit:
14610
+ exit:
943914611 if (isfree)
944014612 kfree(mgmt_frame);
944114613 if (body)
944214614 kfree(body);
14615
+
14616
+ return err;
14617
+}
14618
+#endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
14619
+
14620
+/* The mainline kernel >= 3.2.0 has support for indicating new/del station
14621
+ * to AP/P2P GO via events. If this change is backported to kernel for which
14622
+ * this driver is being built, then define WL_CFG80211_STA_EVENT. You
14623
+ * should use this new/del sta event mechanism for BRCM supplicant >= 22.
14624
+ */
14625
+static s32
14626
+wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
14627
+ const wl_event_msg_t *e, void *data)
14628
+{
14629
+ s32 err = 0;
14630
+ u32 event = ntoh32(e->event_type);
14631
+ u32 reason = ntoh32(e->reason);
14632
+ u32 status = ntoh32(e->status);
14633
+#ifdef BIGDATA_SOFTAP
14634
+ dhd_pub_t *dhdp;
14635
+#endif /* BIGDATA_SOFTAP */
14636
+
14637
+ WL_INFORM_MEM(("[%s] Mode AP/GO. Event:%d status:%d reason:%d\n",
14638
+ ndev->name, event, ntoh32(e->status), reason));
14639
+
14640
+ if (event == WLC_E_AUTH_IND) {
14641
+ wl_get_auth_assoc_status(cfg, ndev, e, data);
14642
+ return 0;
14643
+ }
14644
+ /* if link down, bsscfg is disabled. */
14645
+ if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
14646
+ wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
14647
+ wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
14648
+ WL_INFORM_MEM(("AP mode link down !! \n"));
14649
+ complete(&cfg->iface_disable);
14650
+ return 0;
14651
+ }
14652
+
14653
+ if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
14654
+ (reason == WLC_E_REASON_INITIAL_ASSOC) &&
14655
+ (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
14656
+ if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
14657
+ /* AP/GO brought up successfull in firmware */
14658
+ WL_INFORM_MEM(("AP/GO Link up\n"));
14659
+ wl_set_drv_status(cfg, AP_CREATED, ndev);
14660
+ OSL_SMP_WMB();
14661
+ wake_up_interruptible(&cfg->netif_change_event);
14662
+#ifdef BIGDATA_SOFTAP
14663
+ wl_ap_stainfo_init(cfg);
14664
+#endif /* BIGDATA_SOFTAP */
14665
+#ifdef WL_BCNRECV
14666
+ /* check fakeapscan is in progress, if progress then abort */
14667
+ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_CONCURRENCY);
14668
+#endif /* WL_BCNRECV */
14669
+ return 0;
14670
+ }
14671
+ }
14672
+
14673
+ if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
14674
+ WL_DBG(("event %s(%d) status %d reason %d\n",
14675
+ bcmevent_get_name(event), event, ntoh32(e->status), reason));
14676
+ }
14677
+
14678
+#ifdef BIGDATA_SOFTAP
14679
+ if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) {
14680
+ WL_ERR(("AP link down - skip get sta data\n"));
14681
+ } else {
14682
+ dhdp = (dhd_pub_t *)(cfg->pub);
14683
+ if (dhdp && dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) {
14684
+ dhd_schedule_gather_ap_stadata(cfg, ndev, e);
14685
+ }
14686
+ }
14687
+#endif /* BIGDATA_SOFTAP */
14688
+
14689
+#if !defined(WL_CFG80211_STA_EVENT) && !defined(WL_COMPAT_WIRELESS) && \
14690
+ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
14691
+ return wl_notify_connect_status_ap_rx_mgmt(cfg, ndev, e, data);
944314692 #else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
9444
- sinfo.filled = 0;
944514693 if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
9446
- reason == DOT11_SC_SUCCESS) {
14694
+ reason == DOT11_SC_SUCCESS) {
14695
+ u32 len = ntoh32(e->datalen);
14696
+ struct station_info sinfo;
14697
+
14698
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
14699
+ memset(&sinfo, 0, sizeof(struct station_info));
14700
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) */
14701
+ sinfo.filled = 0;
944714702 /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
944814703 * STATION_INFO_ASSOC_REQ_IES flag
944914704 */
....@@ -9456,36 +14711,105 @@
945614711 }
945714712 sinfo.assoc_req_ies = data;
945814713 sinfo.assoc_req_ies_len = len;
14714
+ WL_INFORM_MEM(("[%s] new sta event for "MACDBG "\n",
14715
+ ndev->name, MAC2STRDBG(e->addr.octet)));
945914716 cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
9460
- } else if (event == WLC_E_DISASSOC_IND) {
14717
+#ifdef WL_WPS_SYNC
14718
+ wl_wps_session_update(ndev, WPS_STATE_LINKUP, e->addr.octet);
14719
+#endif /* WL_WPS_SYNC */
14720
+ } else if ((event == WLC_E_DEAUTH_IND) ||
14721
+ ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED)) ||
14722
+ (event == WLC_E_DISASSOC_IND)) {
14723
+#if defined(WL_CFG80211_AP_RX_MGMT_DISCONNECT)
14724
+ err = wl_notify_connect_status_ap_rx_mgmt(cfg, ndev, e, data);
14725
+#else
14726
+ WL_INFORM_MEM(("[%s] del sta event for "MACDBG "\n",
14727
+ ndev->name, MAC2STRDBG(e->addr.octet)));
946114728 cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
9462
- } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
9463
- cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
14729
+#endif /* WL_CFG80211_AP_RX_MGMT_DISCONNECT */
14730
+#ifdef WL_WPS_SYNC
14731
+ wl_wps_session_update(ndev, WPS_STATE_LINKDOWN, e->addr.octet);
14732
+#endif /* WL_WPS_SYNC */
946414733 }
9465
-#endif
14734
+#endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
946614735 return err;
946714736 }
946814737
9469
-static s32
9470
-wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
9471
- const wl_event_msg_t *e)
14738
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
14739
+enum {
14740
+ BIGDATA_ASSOC_REJECT_NO_ACK = 1,
14741
+ BIGDATA_ASSOC_REJECT_FAIL = 2,
14742
+ BIGDATA_ASSOC_REJECT_UNSOLICITED = 3,
14743
+ BIGDATA_ASSOC_REJECT_TIMEOUT = 4,
14744
+ BIGDATA_ASSOC_REJECT_ABORT = 5,
14745
+ BIGDATA_ASSOC_REJECT_NO_NETWWORKS = 6,
14746
+ BIGDATA_ASSOC_REJECT_MAX = 50
14747
+};
14748
+
14749
+int wl_get_connect_failed_status(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
947214750 {
9473
- u32 reason = ntoh32(e->reason);
9474
- u32 event = ntoh32(e->event_type);
9475
- struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
9476
- WL_DBG(("event type : %d, reason : %d\n", event, reason));
9477
- if (sec) {
9478
- switch (event) {
9479
- case WLC_E_ASSOC:
9480
- case WLC_E_AUTH:
9481
- sec->auth_assoc_res_status = reason;
9482
- default:
9483
- break;
14751
+ u32 status = ntoh32(e->status);
14752
+
14753
+ cfg->assoc_reject_status = 0;
14754
+
14755
+ if (status != WLC_E_STATUS_SUCCESS) {
14756
+ WL_ERR(("auth assoc status event=%d e->status %d e->reason %d \n",
14757
+ ntoh32(cfg->event_auth_assoc.event_type),
14758
+ (int)ntoh32(cfg->event_auth_assoc.status),
14759
+ (int)ntoh32(cfg->event_auth_assoc.reason)));
14760
+
14761
+ switch ((int)ntoh32(cfg->event_auth_assoc.status)) {
14762
+ case WLC_E_STATUS_NO_ACK:
14763
+ cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_NO_ACK;
14764
+ break;
14765
+ case WLC_E_STATUS_FAIL:
14766
+ cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_FAIL;
14767
+ break;
14768
+ case WLC_E_STATUS_UNSOLICITED:
14769
+ cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_UNSOLICITED;
14770
+ break;
14771
+ case WLC_E_STATUS_TIMEOUT:
14772
+ cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_TIMEOUT;
14773
+ break;
14774
+ case WLC_E_STATUS_ABORT:
14775
+ cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_ABORT;
14776
+ break;
14777
+ case WLC_E_STATUS_SUCCESS:
14778
+ if (status == WLC_E_STATUS_NO_NETWORKS) {
14779
+ cfg->assoc_reject_status =
14780
+ BIGDATA_ASSOC_REJECT_NO_NETWWORKS;
14781
+ break;
14782
+ }
14783
+ default:
14784
+ cfg->assoc_reject_status = BIGDATA_ASSOC_REJECT_MAX;
14785
+ break;
948414786 }
9485
- } else
9486
- WL_ERR(("sec is NULL\n"));
14787
+ if (cfg->assoc_reject_status) {
14788
+ if (ntoh32(cfg->event_auth_assoc.event_type) == WLC_E_ASSOC) {
14789
+ cfg->assoc_reject_status += BIGDATA_ASSOC_REJECT_MAX;
14790
+ }
14791
+ }
14792
+ }
14793
+
14794
+ WL_ERR(("assoc_reject_status %d \n", cfg->assoc_reject_status));
14795
+
948714796 return 0;
948814797 }
14798
+
14799
+s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len)
14800
+{
14801
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
14802
+ int bytes_written = 0;
14803
+
14804
+ if (cfg == NULL) {
14805
+ return -1;
14806
+ }
14807
+ bytes_written = snprintf(cmd, total_len, "assoc_reject.status %d",
14808
+ cfg->assoc_reject_status);
14809
+ WL_ERR(("cmd: %s \n", cmd));
14810
+ return bytes_written;
14811
+}
14812
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
948914813
949014814 static s32
949114815 wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
....@@ -9504,10 +14828,10 @@
950414828 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
950514829
950614830 if (event == WLC_E_JOIN) {
9507
- WL_DBG(("joined in IBSS network\n"));
14831
+ WL_INFORM_MEM(("[%s] joined in IBSS network\n", ndev->name));
950814832 }
950914833 if (event == WLC_E_START) {
9510
- WL_DBG(("started IBSS network\n"));
14834
+ WL_INFORM_MEM(("[%s] started IBSS network\n", ndev->name));
951114835 }
951214836 if (event == WLC_E_JOIN || event == WLC_E_START ||
951314837 (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
....@@ -9530,8 +14854,9 @@
953014854 MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
953114855 return err;
953214856 }
9533
- WL_INFORM(("IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
9534
- MAC2STRDBG(cur_bssid), MAC2STRDBG((const u8 *)&e->addr)));
14857
+ WL_INFORM_MEM(("[%s] IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
14858
+ ndev->name, MAC2STRDBG(cur_bssid),
14859
+ MAC2STRDBG((const u8 *)&e->addr)));
953514860 wl_get_assoc_ies(cfg, ndev);
953614861 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
953714862 wl_update_bss_info(cfg, ndev, false);
....@@ -9539,12 +14864,12 @@
953914864 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
954014865 #else
954114866 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
9542
-#endif
14867
+#endif // endif
954314868 }
954414869 else {
954514870 /* New connection */
9546
- WL_INFORM(("IBSS connected to " MACDBG "\n",
9547
- MAC2STRDBG((const u8 *)&e->addr)));
14871
+ WL_INFORM_MEM(("[%s] IBSS connected to " MACDBG "\n",
14872
+ ndev->name, MAC2STRDBG((const u8 *)&e->addr)));
954814873 wl_link_up(cfg);
954914874 wl_get_assoc_ies(cfg, ndev);
955014875 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
....@@ -9553,7 +14878,7 @@
955314878 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
955414879 #else
955514880 cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
9556
-#endif
14881
+#endif // endif
955714882 wl_set_drv_status(cfg, CONNECTED, ndev);
955814883 active = true;
955914884 wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
....@@ -9565,12 +14890,506 @@
956514890 wl_init_prof(cfg, ndev);
956614891 }
956714892 else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
9568
- WL_DBG(("no action - join fail (IBSS mode)\n"));
14893
+ WL_INFORM_MEM(("no action - join fail (IBSS mode)\n"));
956914894 }
957014895 else {
957114896 WL_DBG(("no action (IBSS mode)\n"));
957214897 }
957314898 return err;
14899
+}
14900
+
14901
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
14902
+#define WiFiALL_OUI "\x50\x6F\x9A" /* Wi-FiAll OUI */
14903
+#define WiFiALL_OUI_LEN 3
14904
+#define WiFiALL_OUI_TYPE 16
14905
+
14906
+/* 11kv feature flag for big data */
14907
+#define WL_BIGDATA_11KV_QBSSLOAD 0x00000001
14908
+#define WL_BIGDATA_11KV_PROXYARP 0x00000002
14909
+#define WL_BIGDATA_11KV_TFS 0x00000004
14910
+#define WL_BIGDATA_11KV_SLEEP 0x00000008
14911
+#define WL_BIGDATA_11KV_TIMBC 0x00000010
14912
+#define WL_BIGDATA_11KV_BSSTRANS 0x00000020
14913
+#define WL_BIGDATA_11KV_DMS 0x00000040
14914
+#define WL_BIGDATA_11KV_LINK_MEA 0x00000080
14915
+#define WL_BIGDATA_11KV_NBRREP 0x00000100
14916
+#define WL_BIGDATA_11KV_BCNPASSIVE 0x00000200
14917
+#define WL_BIGDATA_11KV_BCNACTIVE 0x00000400
14918
+#define WL_BIGDATA_11KV_BCNTABLE 0x00000800
14919
+#define WL_BIGDATA_11KV_BSSAAD 0x00001000
14920
+#define WL_BIGDATA_11KV_MAX 0x00002000
14921
+
14922
+#define WL_BIGDATA_SUPPORT_11K 0x00000001
14923
+#define WL_BIGDATA_SUPPORT_11V 0x00000002
14924
+
14925
+typedef struct {
14926
+ uint8 bitmap;
14927
+ uint8 octet_len;
14928
+ uint32 flag;
14929
+} bigdata_11kv_t;
14930
+
14931
+bigdata_11kv_t bigdata_11k_info[] = {
14932
+ {DOT11_RRM_CAP_LINK, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_LINK_MEA},
14933
+ {DOT11_RRM_CAP_NEIGHBOR_REPORT, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_NBRREP},
14934
+ {DOT11_RRM_CAP_BCN_PASSIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNPASSIVE},
14935
+ {DOT11_RRM_CAP_BCN_ACTIVE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNACTIVE},
14936
+ {DOT11_RRM_CAP_BCN_TABLE, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BCNTABLE},
14937
+ {DOT11_RRM_CAP_BSSAAD, DOT11_RRM_CAP_LEN, WL_BIGDATA_11KV_BSSAAD},
14938
+};
14939
+
14940
+bigdata_11kv_t bigdata_11v_info[] = {
14941
+ {DOT11_EXT_CAP_PROXY_ARP, DOT11_EXTCAP_LEN_PROXY_ARP, WL_BIGDATA_11KV_PROXYARP},
14942
+ {DOT11_EXT_CAP_TFS, DOT11_EXTCAP_LEN_TFS, WL_BIGDATA_11KV_TFS},
14943
+ {DOT11_EXT_CAP_WNM_SLEEP, DOT11_EXTCAP_LEN_WNM_SLEEP, WL_BIGDATA_11KV_SLEEP},
14944
+ {DOT11_EXT_CAP_TIMBC, DOT11_EXTCAP_LEN_TIMBC, WL_BIGDATA_11KV_TIMBC},
14945
+ {DOT11_EXT_CAP_BSSTRANS_MGMT, DOT11_EXTCAP_LEN_BSSTRANS, WL_BIGDATA_11KV_BSSTRANS},
14946
+ {DOT11_EXT_CAP_DMS, DOT11_EXTCAP_LEN_DMS, WL_BIGDATA_11KV_DMS}
14947
+};
14948
+
14949
+static void
14950
+wl_get_11kv_info(u8 *ie, u32 ie_len, uint8 *support_11kv, uint32 *flag_11kv)
14951
+{
14952
+ bcm_tlv_t *ie_11kv = NULL;
14953
+ uint32 flag_11k = 0, flag_11v = 0;
14954
+ int i;
14955
+
14956
+ /* parsing QBSS load ie */
14957
+ if ((bcm_parse_tlvs(ie, (u32)ie_len,
14958
+ DOT11_MNG_QBSS_LOAD_ID)) != NULL) {
14959
+ flag_11k |= WL_BIGDATA_11KV_QBSSLOAD;
14960
+ }
14961
+
14962
+ /* parsing RM IE for 11k */
14963
+ if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
14964
+ DOT11_MNG_RRM_CAP_ID)) != NULL) {
14965
+ for (i = 0; i < ARRAYSIZE(bigdata_11k_info); i++) {
14966
+ if ((ie_11kv->len >= bigdata_11k_info[i].octet_len) &&
14967
+ isset(ie_11kv->data, bigdata_11k_info[i].bitmap)) {
14968
+ flag_11k |= bigdata_11k_info[i].flag;
14969
+ }
14970
+ }
14971
+ }
14972
+
14973
+ /* parsing extended cap. IE for 11v */
14974
+ if ((ie_11kv = bcm_parse_tlvs(ie, (u32)ie_len,
14975
+ DOT11_MNG_EXT_CAP_ID)) != NULL) {
14976
+ for (i = 0; i < ARRAYSIZE(bigdata_11v_info); i++) {
14977
+ if ((ie_11kv->len >= bigdata_11v_info[i].octet_len) &&
14978
+ isset(ie_11kv->data, bigdata_11v_info[i].bitmap)) {
14979
+ flag_11v |= bigdata_11v_info[i].flag;
14980
+ }
14981
+ }
14982
+ }
14983
+
14984
+ if (flag_11k > 0) {
14985
+ *support_11kv |= WL_BIGDATA_SUPPORT_11K;
14986
+ }
14987
+
14988
+ if (flag_11v > 0) {
14989
+ *support_11kv |= WL_BIGDATA_SUPPORT_11V;
14990
+ }
14991
+
14992
+ *flag_11kv = flag_11k | flag_11v;
14993
+}
14994
+
14995
+int wl_get_bss_info(struct bcm_cfg80211 *cfg, struct net_device *dev, struct ether_addr const *mac)
14996
+{
14997
+ s32 err = 0;
14998
+ wl_bss_info_v109_1_t *bi;
14999
+ uint8 eabuf[ETHER_ADDR_LEN];
15000
+ u32 rate, channel, freq, supported_rate, nss = 0, mcs_map, mode_80211 = 0;
15001
+ char rate_str[4];
15002
+ u8 *ie = NULL;
15003
+ u32 ie_len;
15004
+ struct wiphy *wiphy;
15005
+ struct cfg80211_bss *bss;
15006
+ bcm_tlv_t *interworking_ie = NULL;
15007
+ bcm_tlv_t *tlv_ie = NULL;
15008
+ bcm_tlv_t *vht_ie = NULL;
15009
+ vndr_ie_t *vndrie;
15010
+ int16 ie_11u_rel_num = -1, ie_mu_mimo_cap = -1;
15011
+ u32 i, remained_len, count = 0;
15012
+ char roam_count_str[4], akm_str[4];
15013
+ s32 val = 0;
15014
+ uint8 support_11kv = 0;
15015
+ uint32 flag_11kv = 0; /* bit flags of 11kv big data */
15016
+
15017
+ /* get BSS information */
15018
+
15019
+ strlcpy(cfg->bss_info, "x x x x x x x x x x x x x x x", sizeof(cfg->bss_info));
15020
+
15021
+ *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
15022
+
15023
+ err = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, cfg->extra_buf, WL_EXTRA_BUF_MAX);
15024
+ if (unlikely(err)) {
15025
+ WL_ERR(("Could not get bss info %d\n", err));
15026
+ cfg->roam_count = 0;
15027
+ return -1;
15028
+ }
15029
+
15030
+ if (!mac) {
15031
+ WL_ERR(("mac is null \n"));
15032
+ cfg->roam_count = 0;
15033
+ return -1;
15034
+ }
15035
+
15036
+ memcpy(eabuf, mac, ETHER_ADDR_LEN);
15037
+
15038
+ bi = (wl_bss_info_v109_1_t *)(cfg->extra_buf + 4);
15039
+ channel = wf_chspec_ctlchan(bi->chanspec);
15040
+
15041
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
15042
+ freq = ieee80211_channel_to_frequency(channel);
15043
+#else
15044
+#ifdef WL_6E
15045
+ if (CHSPEC_IS6G(wl_chspec_driver_to_host(bi->chanspec))) {
15046
+ freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_6GHZ);
15047
+ } else
15048
+#endif /* WL_6E */
15049
+ if (channel > 14) {
15050
+ freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
15051
+ } else {
15052
+ freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
15053
+ }
15054
+#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !(WL_COMPAT_WIRELESS) */
15055
+ rate = 0;
15056
+ err = wldev_ioctl_get(dev, WLC_GET_RATE, &rate, sizeof(rate));
15057
+ if (err) {
15058
+ WL_ERR(("Could not get rate (%d)\n", err));
15059
+ snprintf(rate_str, sizeof(rate_str), "x"); /* Unknown */
15060
+
15061
+ } else {
15062
+ rate = dtoh32(rate);
15063
+ snprintf(rate_str, sizeof(rate_str), "%d", (rate/2));
15064
+ }
15065
+
15066
+ /* supported maximum rate */
15067
+ supported_rate = (bi->rateset.rates[bi->rateset.count - 1] & 0x7f) / 2;
15068
+
15069
+ if (supported_rate < 12) {
15070
+ mode_80211 = BIGDATA_DOT11_11B_MODE; /* 11b maximum rate is 11Mbps. 11b mode */
15071
+ } else {
15072
+ /* It's not HT Capable case. */
15073
+ if (channel > 14) {
15074
+ mode_80211 = BIGDATA_DOT11_11A_MODE; /* 11a mode */
15075
+ } else {
15076
+ mode_80211 = BIGDATA_DOT11_11G_MODE; /* 11g mode */
15077
+ }
15078
+ }
15079
+
15080
+ if (bi->n_cap) {
15081
+ /* check Rx MCS Map for HT */
15082
+ nss = 0;
15083
+ mode_80211 = BIGDATA_DOT11_11N_MODE;
15084
+ for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
15085
+ int8 bitmap = DOT11_HT_MCS_RATE_MASK;
15086
+ if (i == MAX_STREAMS_SUPPORTED-1) {
15087
+ bitmap = DOT11_RATE_MASK;
15088
+ }
15089
+ if (bi->basic_mcs[i] & bitmap) {
15090
+ nss++;
15091
+ }
15092
+ }
15093
+ }
15094
+
15095
+ if (bi->vht_cap) {
15096
+ nss = 0;
15097
+ mode_80211 = BIGDATA_DOT11_11AC_MODE;
15098
+ for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
15099
+ mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
15100
+ if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
15101
+ nss++;
15102
+ }
15103
+ }
15104
+ }
15105
+
15106
+#if defined(WL11AX)
15107
+ if (bi->he_cap) {
15108
+ nss = 0;
15109
+ mode_80211 = BIGDATA_DOT11_11AX_MODE;
15110
+ for (i = 1; i <= HE_MCS_MAP_NSS_MAX; i++) {
15111
+ mcs_map = HE_MCS_NSS_GET_MCS(i, dtoh32(bi->he_rxmcsmap));
15112
+ if (mcs_map != HE_MCS_CODE_NONE) {
15113
+ nss++;
15114
+ }
15115
+ }
15116
+ }
15117
+#endif /* WL11AX */
15118
+
15119
+ if (nss) {
15120
+ nss = nss - 1;
15121
+ }
15122
+
15123
+ wiphy = bcmcfg_to_wiphy(cfg);
15124
+ bss = CFG80211_GET_BSS(wiphy, NULL, eabuf, bi->SSID, bi->SSID_len);
15125
+ if (!bss) {
15126
+ WL_ERR(("Could not find the AP\n"));
15127
+ } else {
15128
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
15129
+#if defined(WL_CFG80211_P2P_DEV_IF)
15130
+ ie = (u8 *)bss->ies->data;
15131
+ ie_len = bss->ies->len;
15132
+#else
15133
+ ie = bss->information_elements;
15134
+ ie_len = bss->len_information_elements;
15135
+#endif /* WL_CFG80211_P2P_DEV_IF */
15136
+ GCC_DIAGNOSTIC_POP();
15137
+ }
15138
+
15139
+ if (ie) {
15140
+ ie_mu_mimo_cap = 0;
15141
+ ie_11u_rel_num = 0;
15142
+
15143
+ if (bi->vht_cap) {
15144
+ if ((vht_ie = bcm_parse_tlvs(ie, ie_len,
15145
+ DOT11_MNG_VHT_CAP_ID)) != NULL) {
15146
+ if (vht_ie->len >= VHT_CAP_IE_LEN) {
15147
+ ie_mu_mimo_cap = (vht_ie->data[2] & 0x08) >> 3;
15148
+ }
15149
+ }
15150
+ }
15151
+
15152
+ if ((interworking_ie = bcm_parse_tlvs(ie, ie_len,
15153
+ DOT11_MNG_INTERWORKING_ID)) != NULL) {
15154
+ if ((tlv_ie = bcm_parse_tlvs(ie, ie_len, DOT11_MNG_VS_ID)) != NULL) {
15155
+ remained_len = ie_len;
15156
+
15157
+ while (tlv_ie) {
15158
+ if (count > MAX_VNDR_IE_NUMBER)
15159
+ break;
15160
+
15161
+ if (tlv_ie->id == DOT11_MNG_VS_ID) {
15162
+ vndrie = (vndr_ie_t *) tlv_ie;
15163
+
15164
+ if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
15165
+ WL_ERR(("wl_get_bss_info: invalid vndr ie."
15166
+ "length is too small %d\n",
15167
+ vndrie->len));
15168
+ break;
15169
+ }
15170
+
15171
+ if (!bcmp(vndrie->oui,
15172
+ (u8*)WiFiALL_OUI, WiFiALL_OUI_LEN) &&
15173
+ (vndrie->data[0] == WiFiALL_OUI_TYPE))
15174
+ {
15175
+ WL_ERR(("Found Wi-FiAll OUI oui.\n"));
15176
+ ie_11u_rel_num = vndrie->data[1];
15177
+ ie_11u_rel_num = (ie_11u_rel_num & 0xf0)>>4;
15178
+ ie_11u_rel_num += 1;
15179
+
15180
+ break;
15181
+ }
15182
+ }
15183
+ count++;
15184
+ tlv_ie = bcm_next_tlv(tlv_ie, &remained_len);
15185
+ }
15186
+ }
15187
+ }
15188
+
15189
+ /* get 11kv information from ie of current bss */
15190
+ wl_get_11kv_info(ie, ie_len, &support_11kv, &flag_11kv);
15191
+ }
15192
+
15193
+ for (i = 0; i < bi->SSID_len; i++) {
15194
+ if (bi->SSID[i] == ' ') {
15195
+ bi->SSID[i] = '_';
15196
+ }
15197
+ }
15198
+
15199
+ /* 0 : None, 1 : OKC, 2 : FT, 3 : CCKM */
15200
+ err = wldev_iovar_getint(dev, "wpa_auth", &val);
15201
+ if (unlikely(err)) {
15202
+ WL_ERR(("could not get wpa_auth (%d)\n", err));
15203
+ snprintf(akm_str, sizeof(akm_str), "x"); /* Unknown */
15204
+ } else {
15205
+ WL_ERR(("wpa_auth val %d \n", val));
15206
+ if (val & WPA2_AUTH_FT) {
15207
+ snprintf(akm_str, sizeof(akm_str), "2");
15208
+ } else if (val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) {
15209
+ snprintf(akm_str, sizeof(akm_str), "1");
15210
+ } else {
15211
+ snprintf(akm_str, sizeof(akm_str), "0");
15212
+ }
15213
+ }
15214
+
15215
+ if (cfg->roam_offload) {
15216
+ snprintf(roam_count_str, sizeof(roam_count_str), "x"); /* Unknown */
15217
+ } else {
15218
+ snprintf(roam_count_str, sizeof(roam_count_str), "%d", cfg->roam_count);
15219
+ }
15220
+ cfg->roam_count = 0;
15221
+
15222
+ WL_ERR(("BSSID:" MACDBG " SSID %s \n", MAC2STRDBG(eabuf), "*****"));
15223
+ WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d,"
15224
+ "MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n"
15225
+ "akm:%s, roam:%s, 11kv:%d/%d \n",
15226
+ freq, wf_chspec_to_bw_str(bi->chanspec),
15227
+ dtoh32(bi->RSSI), (rate / 2), mode_80211, nss,
15228
+ ie_mu_mimo_cap, ie_11u_rel_num, bi->SNR, bi->phy_noise,
15229
+ akm_str, roam_count_str, support_11kv, flag_11kv));
15230
+
15231
+ if (ie) {
15232
+ snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
15233
+ MACOUI" %d %s %d %s %d %d %d %d %d %d %s %s %d %d",
15234
+ MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
15235
+ dtoh32(bi->RSSI), rate_str, mode_80211, nss, ie_mu_mimo_cap,
15236
+ ie_11u_rel_num, bi->SNR, bi->phy_noise, akm_str, roam_count_str,
15237
+ support_11kv, flag_11kv);
15238
+ } else {
15239
+ /* ie_mu_mimo_cap and ie_11u_rel_num is unknow. */
15240
+ snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
15241
+ MACOUI" %d %s %d %s %d %d x x %d %d %s %s x x",
15242
+ MACOUI2STR(eabuf), freq, wf_chspec_to_bw_str(bi->chanspec),
15243
+ dtoh32(bi->RSSI), rate_str, mode_80211, nss, bi->SNR,
15244
+ bi->phy_noise, akm_str, roam_count_str);
15245
+ }
15246
+
15247
+ CFG80211_PUT_BSS(wiphy, bss);
15248
+
15249
+ return 0;
15250
+}
15251
+
15252
+s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len)
15253
+{
15254
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
15255
+
15256
+ if (cfg == NULL) {
15257
+ return -1;
15258
+ }
15259
+
15260
+ if (total_len < GET_BSS_INFO_LEN) {
15261
+ WL_ERR(("wl_cfg80211_get_bss_info: Buffer insuffient %d\n", total_len));
15262
+ return -1;
15263
+ }
15264
+
15265
+ bzero(cmd, total_len);
15266
+ memcpy(cmd, cfg->bss_info, GET_BSS_INFO_LEN);
15267
+
15268
+ WL_ERR_KERN(("cmd: %s \n", cmd));
15269
+
15270
+ return GET_BSS_INFO_LEN;
15271
+}
15272
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
15273
+
15274
+void wl_cfg80211_disassoc(struct net_device *ndev, uint32 reason)
15275
+{
15276
+ scb_val_t scbval;
15277
+ s32 err;
15278
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
15279
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
15280
+
15281
+ BCM_REFERENCE(cfg);
15282
+ BCM_REFERENCE(dhdp);
15283
+ DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15284
+ dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
15285
+
15286
+ memset_s(&scbval, sizeof(scb_val_t), 0x0, sizeof(scb_val_t));
15287
+ scbval.val = htod32(reason);
15288
+ err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
15289
+ if (err < 0) {
15290
+ WL_ERR(("WLC_DISASSOC error %d\n", err));
15291
+ }
15292
+}
15293
+void wl_cfg80211_del_all_sta(struct net_device *ndev, uint32 reason)
15294
+{
15295
+ struct net_device *dev;
15296
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
15297
+ scb_val_t scb_val;
15298
+ int err;
15299
+ char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
15300
+ sizeof(struct ether_addr) + sizeof(uint)] = {0};
15301
+ struct maclist *assoc_maclist = (struct maclist *)mac_buf;
15302
+ int num_associated = 0;
15303
+
15304
+ dev = ndev_to_wlc_ndev(ndev, cfg);
15305
+
15306
+ if (p2p_is_on(cfg)) {
15307
+ /* Suspend P2P discovery search-listen to prevent it from changing the
15308
+ * channel.
15309
+ */
15310
+ if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
15311
+ WL_ERR(("Can not disable discovery mode\n"));
15312
+ return;
15313
+ }
15314
+ }
15315
+
15316
+ assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
15317
+ err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
15318
+ assoc_maclist, sizeof(mac_buf));
15319
+ if (err < 0)
15320
+ WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
15321
+ else
15322
+ num_associated = assoc_maclist->count;
15323
+
15324
+ memset(scb_val.ea.octet, 0xff, ETHER_ADDR_LEN);
15325
+ scb_val.val = DOT11_RC_DEAUTH_LEAVING;
15326
+ scb_val.val = htod32(reason);
15327
+ err = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
15328
+ sizeof(scb_val_t));
15329
+ if (err < 0) {
15330
+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
15331
+ }
15332
+
15333
+ if (num_associated > 0)
15334
+ wl_delay(400);
15335
+
15336
+ return;
15337
+}
15338
+/* API to handle the Deauth from the AP.
15339
+* For now we are deleting the PMKID cache in DHD/FW
15340
+* in case of current connection is using SAE authnetication
15341
+*/
15342
+static s32
15343
+wl_cfg80211_handle_deauth_ind(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15344
+ const wl_event_msg_t *e, void *data)
15345
+{
15346
+ int err = BCME_OK;
15347
+#ifdef WL_SAE
15348
+ uint8 bssid[ETHER_ADDR_LEN];
15349
+ struct cfg80211_pmksa pmksa;
15350
+ s32 val = 0;
15351
+
15352
+ err = wldev_iovar_getint(ndev, "wpa_auth", &val);
15353
+ if (unlikely(err)) {
15354
+ WL_ERR(("could not get wpa_auth (%d)\n", err));
15355
+ goto done;
15356
+ }
15357
+ if (val == WPA3_AUTH_SAE_PSK) {
15358
+ (void)memcpy_s(bssid, ETHER_ADDR_LEN,
15359
+ (const uint8*)&e->addr, ETHER_ADDR_LEN);
15360
+ memset_s(&pmksa, sizeof(pmksa), 0, sizeof(pmksa));
15361
+ pmksa.bssid = bssid;
15362
+ WL_INFORM_MEM(("Deleting the PMKSA for SAE AP "MACDBG,
15363
+ MAC2STRDBG(e->addr.octet)));
15364
+ wl_cfg80211_del_pmksa(cfg->wdev->wiphy, ndev, &pmksa);
15365
+ }
15366
+done:
15367
+#endif /* WL_SAE */
15368
+ return err;
15369
+}
15370
+
15371
+static void
15372
+wl_cache_assoc_resp_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev,
15373
+ const wl_event_msg_t *e, void *data)
15374
+{
15375
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
15376
+ u32 datalen = ntoh32(e->datalen);
15377
+ u32 event_type = ntoh32(e->event_type);
15378
+
15379
+ if (datalen > VNDR_IE_MIN_LEN &&
15380
+ datalen < VNDR_IE_MAX_LEN &&
15381
+ data) {
15382
+ conn_info->resp_ie_len = datalen;
15383
+ WL_DBG((" assoc resp IES len = %d\n", conn_info->resp_ie_len));
15384
+ bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
15385
+ (void)memcpy_s(conn_info->resp_ie, sizeof(conn_info->resp_ie),
15386
+ data, datalen);
15387
+
15388
+ WL_INFORM_MEM(("[%s] copied assoc resp ies, sent to upper layer:"
15389
+ "event %d reason=%d ie_len=%d from " MACDBG "\n",
15390
+ ndev->name, event_type, ntoh32(e->reason), datalen,
15391
+ MAC2STRDBG((const u8*)(&e->addr))));
15392
+ }
957415393 }
957515394
957615395 static s32
....@@ -9581,53 +15400,222 @@
958115400 struct net_device *ndev = NULL;
958215401 s32 err = 0;
958315402 u32 event = ntoh32(e->event_type);
15403
+ u32 datalen = ntoh32(e->datalen);
958415404 struct wiphy *wiphy = NULL;
958515405 struct cfg80211_bss *bss = NULL;
958615406 struct wlc_ssid *ssid = NULL;
958715407 u8 *bssid = 0;
15408
+ s32 bssidx = 0;
15409
+ u8 *ie_ptr = NULL;
15410
+ uint32 ie_len = 0;
15411
+#ifdef WL_ANALYTICS
15412
+ struct parsed_vndr_ies disco_vndr_ie;
15413
+ struct parsed_vndr_ie_info *vndrie_info = NULL;
15414
+ uint32 i = 0;
15415
+#endif /* WL_ANALYTICS */
15416
+
15417
+ dhd_pub_t *dhdp;
15418
+ u32 mode;
15419
+ int vndr_oui_num = 0;
15420
+ char vndr_oui[MAX_VNDR_OUI_STR_LEN] = {0, };
15421
+ bool loc_gen = false;
15422
+#ifdef DHD_LOSSLESS_ROAMING
15423
+ struct wl_security *sec;
15424
+#endif /* DHD_LOSSLESS_ROAMING */
958815425
958915426 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15427
+#ifdef DHD_LOSSLESS_ROAMING
15428
+ sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
15429
+#endif /* DHD_LOSSLESS_ROAMING */
15430
+ dhdp = (dhd_pub_t *)(cfg->pub);
15431
+ BCM_REFERENCE(dhdp);
959015432
9591
- if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
15433
+ mode = wl_get_mode_by_netdev(cfg, ndev);
15434
+ /* Push link events to upper layer log */
15435
+ SUPP_LOG(("[%s] Mode:%d event:%d status:0x%x reason:%d\n",
15436
+ ndev->name, mode, ntoh32(e->event_type),
15437
+ ntoh32(e->status), ntoh32(e->reason)));
15438
+ if (mode == WL_MODE_AP) {
959215439 err = wl_notify_connect_status_ap(cfg, ndev, e, data);
9593
- } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS) {
15440
+ } else if (mode == WL_MODE_IBSS) {
959415441 err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
9595
- } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) {
9596
- WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n",
9597
- ntoh32(e->event_type), ntoh32(e->status), ndev));
15442
+ } else if (mode == WL_MODE_BSS) {
15443
+ WL_INFORM_MEM(("[%s] Mode BSS. event:%d status:%d reason:%d\n",
15444
+ ndev->name, ntoh32(e->event_type),
15445
+ ntoh32(e->status), ntoh32(e->reason)));
15446
+
15447
+ if (!wl_get_drv_status(cfg, CFG80211_CONNECT, ndev)) {
15448
+ /* Join attempt via non-cfg80211 interface.
15449
+ * Don't send resultant events to cfg80211
15450
+ * layer
15451
+ */
15452
+ WL_INFORM_MEM(("Event received in non-cfg80211"
15453
+ " connect state. Ignore\n"));
15454
+ return BCME_OK;
15455
+ }
15456
+
959815457 if (event == WLC_E_ASSOC || event == WLC_E_AUTH) {
9599
- wl_get_auth_assoc_status(cfg, ndev, e);
15458
+ wl_get_auth_assoc_status(cfg, ndev, e, data);
960015459 return 0;
960115460 }
15461
+ if (event == WLC_E_ASSOC_RESP_IE) {
15462
+ if (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) {
15463
+ wl_cache_assoc_resp_ies(cfg, ndev, e, data);
15464
+ }
15465
+ return 0;
15466
+ }
15467
+
15468
+#if defined(OEM_ANDROID)
15469
+ DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
15470
+#endif // endif
960215471 if (wl_is_linkup(cfg, e, ndev)) {
960315472 wl_link_up(cfg);
960415473 act = true;
960515474 if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
9606
-#ifdef DHD_LOSSLESS_ROAMING
9607
- bool is_connected = wl_get_drv_status(cfg, CONNECTED, ndev);
9608
-#endif
15475
+ WL_INFORM_MEM(("[%s] link up for bssid " MACDBG "\n",
15476
+ ndev->name, MAC2STRDBG((const u8*)(&e->addr))));
15477
+ if ((event == WLC_E_LINK) &&
15478
+ (ntoh16(e->flags) & WLC_EVENT_MSG_LINK) &&
15479
+ !wl_get_drv_status(cfg, CONNECTED, ndev) &&
15480
+ !wl_get_drv_status(cfg, CONNECTING, ndev)) {
15481
+ WL_INFORM_MEM(("link up in non-connected/"
15482
+ "non-connecting state\n"));
15483
+ wl_cfg80211_disassoc(ndev, WLAN_REASON_DEAUTH_LEAVING);
15484
+ return BCME_OK;
15485
+ }
960915486
9610
- printk("wl_bss_connect_done succeeded with " MACDBG "\n",
9611
- MAC2STRDBG((const u8*)(&e->addr)));
9612
- wl_bss_connect_done(cfg, ndev, e, data, true);
9613
- WL_DBG(("joined in BSS network \"%s\"\n",
9614
- ((struct wlc_ssid *)
9615
- wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID));
15487
+#ifdef WL_WPS_SYNC
15488
+ /* Avoid invocation for Roam cases */
15489
+ if ((event == WLC_E_LINK) &&
15490
+ !wl_get_drv_status(cfg, CONNECTED, ndev)) {
15491
+ wl_wps_session_update(ndev,
15492
+ WPS_STATE_LINKUP, e->addr.octet);
15493
+ }
15494
+#endif /* WL_WPS_SYNC */
15495
+
15496
+#ifdef DHD_EVENT_LOG_FILTER
15497
+ if (event == WLC_E_LINK && ndev == bcmcfg_to_prmry_ndev(cfg)) {
15498
+ int roam = FALSE;
15499
+ uint8 eth_addr[ETHER_ADDR_LEN];
15500
+ if (TRUE &&
961615501 #ifdef DHD_LOSSLESS_ROAMING
9617
- if (event == WLC_E_LINK && is_connected &&
9618
- !cfg->roam_offload) {
9619
- wl_bss_roaming_done(cfg, ndev, e, data);
15502
+ !cfg->roam_offload &&
15503
+#endif /* DHD_LOSSLESS_ROAMING */
15504
+ wl_get_drv_status(cfg, CONNECTED, ndev)) {
15505
+ roam = TRUE;
962015506 }
15507
+ memcpy(eth_addr, &(e->addr), ETHER_ADDR_LEN);
15508
+ dhd_event_log_filter_notify_connect_done(dhdp,
15509
+ eth_addr, roam);
15510
+ }
15511
+#endif /* DHD_EVENT_LOG_FILTER */
15512
+
15513
+#ifdef DHD_LOSSLESS_ROAMING
15514
+ if (event == WLC_E_LINK &&
15515
+ !cfg->roam_offload &&
15516
+ !IS_AKM_SUITE_FT(sec) &&
15517
+ wl_get_drv_status(cfg, CONNECTED, ndev))
15518
+ wl_bss_roaming_done(cfg, ndev, e, data);
962115519 #endif /* DHD_LOSSLESS_ROAMING */
962215520
15521
+ wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
15522
+ wl_bss_connect_done(cfg, ndev, e, data, true);
15523
+ if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15524
+ vndr_oui_num = wl_vndr_ies_get_vendor_oui(cfg,
15525
+ ndev, vndr_oui, ARRAY_SIZE(vndr_oui));
15526
+ if (vndr_oui_num > 0) {
15527
+ WL_INFORM_MEM(("[%s] vendor oui: %s\n",
15528
+ ndev->name, vndr_oui));
15529
+ }
962315530 }
15531
+
15532
+ WL_DBG(("joined in BSS network \"%s\"\n",
15533
+ ((struct wlc_ssid *)wl_read_prof(cfg, ndev,
15534
+ WL_PROF_SSID))->SSID));
15535
+#ifdef WBTEXT
15536
+ if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
15537
+ dhdp->wbtext_support && event == WLC_E_SET_SSID) {
15538
+ /* set wnm_keepalives_max_idle after association */
15539
+ wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
15540
+ }
15541
+#endif /* WBTEXT */
15542
+ }
962415543 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
962515544 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
9626
-
15545
+#if defined(IGUANA_LEGACY_CHIPS)
962715546 } else if (wl_is_linkdown(cfg, e)) {
15547
+ /* Lagacy chips like 4350 sends faliure status for WLC_E_SET_SSID even in
15548
+ * case of successful connection. Since these firmware are in production,
15549
+ * firmware change is avoided.
15550
+ */
15551
+#else
15552
+ } else if (wl_is_linkdown(cfg, e) ||
15553
+ ((event == WLC_E_SET_SSID) &&
15554
+ (ntoh32(e->status) != WLC_E_STATUS_SUCCESS) &&
15555
+ (wl_get_drv_status(cfg, CONNECTED, ndev)))) {
15556
+#endif // endif
15557
+ if (wl_is_linkdown(cfg, e)) {
15558
+ /* Clear IEs for disaasoc */
15559
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg,
15560
+ ndev->ieee80211_ptr)) < 0) {
15561
+ WL_ERR(("Find index failed\n"));
15562
+ } else {
15563
+ WL_ERR(("link down--clearing disconnect IEs\n"));
15564
+ if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg,
15565
+ ndev_to_cfgdev(ndev), bssidx, VNDR_IE_DISASSOC_FLAG,
15566
+ NULL, 0)) != BCME_OK) {
15567
+ WL_ERR(("Failed to clear ies err = %d\n", err));
15568
+ }
15569
+ }
15570
+ }
15571
+
15572
+ WL_INFORM_MEM(("link down. connection state bit status: [%u:%u:%u:%u]\n",
15573
+ wl_get_drv_status(cfg, CONNECTING, ndev),
15574
+ wl_get_drv_status(cfg, CONNECTED, ndev),
15575
+ wl_get_drv_status(cfg, DISCONNECTING, ndev),
15576
+ wl_get_drv_status(cfg, NESTED_CONNECT, ndev)));
15577
+
15578
+#ifdef WL_WPS_SYNC
15579
+ {
15580
+ u8 wps_state;
15581
+ if ((event == WLC_E_SET_SSID) &&
15582
+ (ntoh32(e->status) != WLC_E_STATUS_SUCCESS)) {
15583
+ /* connect fail */
15584
+ wps_state = WPS_STATE_CONNECT_FAIL;
15585
+ } else {
15586
+ wps_state = WPS_STATE_LINKDOWN;
15587
+ }
15588
+ if (wl_wps_session_update(ndev,
15589
+ wps_state, e->addr.octet) == BCME_UNSUPPORTED) {
15590
+ /* Unexpected event. Ignore it. */
15591
+ return 0;
15592
+ }
15593
+ }
15594
+#endif /* WL_WPS_SYNC */
15595
+
15596
+ if (wl_get_drv_status(cfg, DISCONNECTING, ndev) &&
15597
+ (wl_get_drv_status(cfg, NESTED_CONNECT, ndev) ||
15598
+ wl_get_drv_status(cfg, CONNECTING, ndev))) {
15599
+ /* wl_cfg80211_connect was called before 'DISCONNECTING' was
15600
+ * cleared. Deauth/Link down event is caused by WLC_DISASSOC
15601
+ * command issued from the wl_cfg80211_connect context. Ignore
15602
+ * the event to avoid pre-empting the current connection
15603
+ */
15604
+ WL_DBG(("Nested connection case. Drop event. \n"));
15605
+ wl_clr_drv_status(cfg, NESTED_CONNECT, ndev);
15606
+ wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15607
+ /* Not in 'CONNECTED' state, clear it */
15608
+ wl_clr_drv_status(cfg, CONNECTED, ndev);
15609
+ return 0;
15610
+ }
15611
+
15612
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15613
+ wl_flush_fw_log_buffer(bcmcfg_to_prmry_ndev(cfg),
15614
+ FW_LOGSET_MASK_ALL);
15615
+ }
962815616 #ifdef DHD_LOSSLESS_ROAMING
962915617 wl_del_roam_timeout(cfg);
9630
-#endif
15618
+#endif // endif
963115619 #ifdef P2PLISTEN_AP_SAMECHN
963215620 if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
963315621 wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0);
....@@ -9637,115 +15625,362 @@
963715625 #endif /* P2PLISTEN_AP_SAMECHN */
963815626 wl_cfg80211_cancel_scan(cfg);
963915627
15628
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
15629
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
15630
+ wl_get_bss_info(cfg, ndev, &e->addr);
15631
+ }
15632
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
964015633 /* Explicitly calling unlink to remove BSS in CFG */
9641
- if (wl_cfgp2p_vif_created(cfg)) {
9642
- wiphy = bcmcfg_to_wiphy(cfg);
9643
- ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
9644
- bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
9645
- if (ssid && bssid) {
9646
- bss = cfg80211_get_bss(wiphy, NULL, bssid,
9647
- ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
9648
- WLAN_CAPABILITY_ESS);
9649
- if (bss) {
9650
- cfg80211_unlink_bss(wiphy, bss);
9651
- }
15634
+ wiphy = bcmcfg_to_wiphy(cfg);
15635
+ ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
15636
+ bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
15637
+ if (ssid && bssid) {
15638
+ bss = CFG80211_GET_BSS(wiphy, NULL, bssid,
15639
+ ssid->SSID, ssid->SSID_len);
15640
+ if (bss) {
15641
+ cfg80211_unlink_bss(wiphy, bss);
15642
+ CFG80211_PUT_BSS(wiphy, bss);
965215643 }
965315644 }
965415645
965515646 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
965615647 scb_val_t scbval;
965715648 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
9658
- s32 reason = 0;
9659
- struct ether_addr bssid_dongle;
15649
+ uint32 reason = 0;
15650
+ struct ether_addr bssid_dongle = {{0, 0, 0, 0, 0, 0}};
15651
+ struct ether_addr bssid_null = {{0, 0, 0, 0, 0, 0}};
966015652
9661
- if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND)
15653
+ if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
966215654 reason = ntoh32(e->reason);
9663
- /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */
9664
- reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason;
9665
-
9666
- printk("link down if %s may call cfg80211_disconnected. "
9667
- "event : %d, reason=%d from " MACDBG "\n",
9668
- ndev->name, event, ntoh32(e->reason),
9669
- MAC2STRDBG((const u8*)(&e->addr)));
15655
+ if (reason > WLC_E_DEAUTH_MAX_REASON) {
15656
+ WL_ERR(("Event %d original reason is %d, "
15657
+ "changed 0xFF\n", event, reason));
15658
+ reason = WLC_E_DEAUTH_MAX_REASON;
15659
+ }
15660
+ wl_cfg80211_handle_deauth_ind(cfg, ndev, e, data);
15661
+ }
15662
+#ifdef SET_SSID_FAIL_CUSTOM_RC
15663
+ if ((event == WLC_E_SET_SSID) &&
15664
+ (ntoh32(e->status) == WLC_E_STATUS_TIMEOUT)) {
15665
+ reason = SET_SSID_FAIL_CUSTOM_RC;
15666
+ }
15667
+#endif /* SET_SSID_FAIL_CUSTOM_RC */
967015668
967115669 /* roam offload does not sync BSSID always, get it from dongle */
967215670 if (cfg->roam_offload) {
9673
- memset(&bssid_dongle, 0, sizeof(bssid_dongle));
9674
- if (wldev_ioctl(ndev, WLC_GET_BSSID, &bssid_dongle,
9675
- sizeof(bssid_dongle), false) == BCME_OK) {
9676
- curbssid = (u8 *)&bssid_dongle;
15671
+ bzero(&bssid_dongle, sizeof(bssid_dongle));
15672
+ if (wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid_dongle,
15673
+ sizeof(bssid_dongle)) == BCME_OK) {
15674
+ /* if not roam case, it would return null bssid */
15675
+ if (memcmp(&bssid_dongle, &bssid_null,
15676
+ ETHER_ADDR_LEN) != 0) {
15677
+ curbssid = (u8 *)&bssid_dongle;
15678
+ }
967715679 }
967815680 }
967915681 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
9680
- WL_ERR(("BSSID of event is not the connected BSSID"
9681
- "(ignore it) cur: " MACDBG " event: " MACDBG"\n",
9682
- MAC2STRDBG(curbssid),
9683
- MAC2STRDBG((const u8*)(&e->addr))));
9684
- return 0;
15682
+ bool fw_assoc_state = TRUE;
15683
+ dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
15684
+ fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
15685
+ if (!fw_assoc_state) {
15686
+ WL_ERR(("Event sends up even different BSSID"
15687
+ " cur: " MACDBG " event: " MACDBG"\n",
15688
+ MAC2STRDBG(curbssid),
15689
+ MAC2STRDBG((const u8*)(&e->addr))));
15690
+ } else {
15691
+ WL_ERR(("BSSID of event is not the connected BSSID"
15692
+ "(ignore it) cur: " MACDBG
15693
+ " event: " MACDBG"\n",
15694
+ MAC2STRDBG(curbssid),
15695
+ MAC2STRDBG((const u8*)(&e->addr))));
15696
+ return 0;
15697
+ }
968515698 }
15699
+#ifdef DBG_PKT_MON
15700
+ /* Stop packet monitor */
15701
+ if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
15702
+ DHD_DBG_PKT_MON_STOP(dhdp);
15703
+ }
15704
+#endif /* DBG_PKT_MON */
15705
+ /* clear RSSI monitor, framework will set new cfg */
15706
+#ifdef RSSI_MONITOR_SUPPORT
15707
+ dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
15708
+ FALSE, 0, 0);
15709
+#endif /* RSSI_MONITOR_SUPPORT */
968615710 wl_clr_drv_status(cfg, CONNECTED, ndev);
9687
- if (! wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15711
+
15712
+ if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15713
+ DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15714
+ dhd_net2idx(dhdp->info, ndev),
15715
+ WLAN_REASON_DEAUTH_LEAVING);
968815716 /* To make sure disconnect, explictly send dissassoc
968915717 * for BSSID 00:00:00:00:00:00 issue
969015718 */
969115719 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
9692
-
15720
+ WL_INFORM_MEM(("clear fw state\n"));
969315721 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
969415722 scbval.val = htod32(scbval.val);
9695
- err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
9696
- sizeof(scb_val_t), true);
15723
+ err = wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
15724
+ sizeof(scb_val_t));
969715725 if (err < 0) {
969815726 WL_ERR(("WLC_DISASSOC error %d\n", err));
969915727 err = 0;
970015728 }
9701
- CFG80211_DISCONNECTED(ndev, reason, NULL, 0,
9702
- false, GFP_KERNEL);
9703
- wl_link_down(cfg);
9704
- wl_init_prof(cfg, ndev);
9705
- memset(&cfg->last_roamed_addr, 0, ETHER_ADDR_LEN);
970615729 }
15730
+ if (wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15731
+ loc_gen = true;
15732
+ }
15733
+ WL_INFORM_MEM(("[%s] Indicate disconnect event to upper layer. "
15734
+ "event: %d reason=%d from " MACDBG "\n",
15735
+ ndev->name, event, ntoh32(e->reason),
15736
+ MAC2STRDBG((const u8*)(&e->addr))));
15737
+
15738
+#ifdef WBTEXT
15739
+ /* when STA was disconnected, clear join pref and set wbtext */
15740
+ if (ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION &&
15741
+ dhdp->wbtext_policy
15742
+ == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) {
15743
+ char smbuf[WLC_IOCTL_SMLEN];
15744
+ char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03,
15745
+ 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
15746
+ if ((err = wldev_iovar_setbuf(ndev, "join_pref",
15747
+ clear, sizeof(clear), smbuf,
15748
+ sizeof(smbuf), NULL))
15749
+ == BCME_OK) {
15750
+ if ((err = wldev_iovar_setint(ndev,
15751
+ "wnm_bsstrans_resp",
15752
+ dhdp->wbtext_policy))
15753
+ == BCME_OK) {
15754
+ wl_cfg80211_wbtext_set_default(ndev);
15755
+ } else {
15756
+ WL_ERR(("wl_notify_connect_status:"
15757
+ " Failed to"
15758
+ " set wbtext = %d\n",
15759
+ err));
15760
+ }
15761
+ } else {
15762
+ WL_ERR(("wl_notify_connect_status:"
15763
+ " Failed to clear join pref = %d\n",
15764
+ err));
15765
+ }
15766
+ wl_cfg80211_wbtext_clear_bssid_list(cfg);
15767
+ }
15768
+#endif /* WBTEXT */
15769
+ DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_DONE),
15770
+ dhd_net2idx(dhdp->info, ndev), reason);
15771
+ /* Send up deauth and clear states */
15772
+
15773
+ /*
15774
+ * FW sends body and body len as a part of deauth
15775
+ * and disassoc events (WLC_E_DISASSOC_IND, WLC_E_DEAUTH_IND)
15776
+ * The VIEs sits after reason code in the body. Reason code is
15777
+ * 2 bytes long.
15778
+ */
15779
+ WL_DBG(("recv disconnect ies ie_len = %d\n", ie_len));
15780
+ if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND) {
15781
+ if ((datalen > DOT11_DISCONNECT_RC) &&
15782
+ datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
15783
+ data) {
15784
+ ie_ptr = (uchar*)data + DOT11_DISCONNECT_RC;
15785
+ ie_len = datalen - DOT11_DISCONNECT_RC;
15786
+ }
15787
+ } else if (event == WLC_E_LINK &&
15788
+ ntoh32(e->reason) == WLC_E_LINK_BCN_LOSS) {
15789
+#ifdef WL_ANALYTICS
15790
+ /*
15791
+ * In case of linkdown, FW sends prb rsp IEs. Disco VIE
15792
+ * are appended with prb rsp ies. Remove prb rsp IES and
15793
+ * send disco vie to upper layer.
15794
+ * Disco VIE has fixed len of 11 octets.
15795
+ * As per SS spec.(2 octet header + 9 octet VIE)
15796
+ */
15797
+ if (datalen < (VNDR_IE_MAX_LEN + DOT11_DISCONNECT_RC) &&
15798
+ datalen >= DOT11_DISCONNECT_RC &&
15799
+ ((err = wl_cfg80211_parse_vndr_ies(
15800
+ (const u8 *)data, datalen,
15801
+ &disco_vndr_ie)) == BCME_OK)) {
15802
+ for (i = 0; i < disco_vndr_ie.count; i++) {
15803
+ vndrie_info = &disco_vndr_ie.ie_info[i];
15804
+ if ((vndrie_info->vndrie.id ==
15805
+ 0xDD) && (!memcmp(
15806
+ vndrie_info->vndrie.oui,
15807
+ SSE_OUI, DOT11_OUI_LEN)) &&
15808
+ (vndrie_info->vndrie.data[0] ==
15809
+ VENDOR_ENTERPRISE_STA_OUI_TYPE)) {
15810
+ ie_ptr = (u8 *)vndrie_info->ie_ptr;
15811
+ ie_len = vndrie_info->ie_len;
15812
+ }
15813
+ }
15814
+ }
15815
+#endif /* WL_ANALYTICS */
15816
+ }
15817
+
15818
+ CFG80211_DISCONNECTED(ndev, reason, ie_ptr, ie_len,
15819
+ loc_gen, GFP_KERNEL);
15820
+ WL_INFORM_MEM(("[%s] Disconnect event sent to upper layer"
15821
+ "event:%d reason=%d ie_len=%d from " MACDBG "\n",
15822
+ ndev->name, event, ntoh32(e->reason), ie_len,
15823
+ MAC2STRDBG((const u8*)(&e->addr))));
15824
+
15825
+ /* Wait for status to be cleared to prevent race condition
15826
+ * issues with connect context
15827
+ * In DISCONNECTING state, There is rtnl_lock issue on cfg80211.
15828
+ */
15829
+ if (!loc_gen)
15830
+ wl_cfg80211_disconnect_state_sync(cfg, ndev);
15831
+ wl_link_down(cfg);
15832
+ wl_init_prof(cfg, ndev);
970715833 }
970815834 else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
9709
- printk("link down, during connecting\n");
15835
+ DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
15836
+ dhd_net2idx(dhdp->info, ndev), 0);
15837
+ WL_INFORM_MEM(("link down, during connecting\n"));
15838
+ /* Issue WLC_DISASSOC to prevent FW roam attempts.
15839
+ * Do not issue WLC_DISASSOC again if the linkdown is
15840
+ * generated due to local disassoc, to avoid connect-disconnect
15841
+ * loop.
15842
+ */
15843
+ if (!((event == WLC_E_LINK) &&
15844
+ (ntoh32(e->reason) == WLC_E_LINK_DISASSOC) &&
15845
+ (ntoh32(e->status) == WLC_E_STATUS_SUCCESS))) {
15846
+ err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
15847
+ if (err < 0) {
15848
+ WL_ERR(("CONNECTING state,"
15849
+ " WLC_DISASSOC error %d\n",
15850
+ err));
15851
+ err = 0;
15852
+ }
971015853 #ifdef ESCAN_RESULT_PATCH
9711
- if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) ||
9712
- (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) ||
9713
- (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0))
9714
- /* In case this event comes while associating another AP */
15854
+ if ((memcmp(connect_req_bssid, broad_bssid,
15855
+ ETHER_ADDR_LEN) == 0) ||
15856
+ (memcmp(&e->addr, broad_bssid,
15857
+ ETHER_ADDR_LEN) == 0) ||
15858
+ (memcmp(&e->addr, connect_req_bssid,
15859
+ ETHER_ADDR_LEN) == 0))
15860
+ /* In case this event comes while associating
15861
+ * another AP
15862
+ */
971515863 #endif /* ESCAN_RESULT_PATCH */
9716
- wl_bss_connect_done(cfg, ndev, e, data, false);
15864
+ wl_bss_connect_done(cfg, ndev, e, data, false);
15865
+ }
971715866 }
971815867 wl_clr_drv_status(cfg, DISCONNECTING, ndev);
971915868
972015869 /* if link down, bsscfg is diabled */
972115870 if (ndev != bcmcfg_to_prmry_ndev(cfg))
972215871 complete(&cfg->iface_disable);
9723
-
15872
+#ifdef REVERSE_AIFSN
15873
+ ((dhd_pub_t *)cfg->pub)->aifsn_reverse = FALSE;
15874
+#endif /* REVERSE_AIFSN */
15875
+#ifdef WLTDLS
15876
+ /* re-enable TDLS if the number of connected interfaces
15877
+ * is less than 2.
15878
+ */
15879
+ wl_cfg80211_tdls_config(cfg, TDLS_STATE_DISCONNECT, false);
15880
+#endif /* WLTDLS */
972415881 } else if (wl_is_nonetwork(cfg, e)) {
9725
- printk("connect failed event=%d e->status %d e->reason %d \n",
9726
- event, (int)ntoh32(e->status), (int)ntoh32(e->reason));
15882
+ WL_ERR(("connect failed event=%d e->status %d e->reason %d \n",
15883
+ event, (int)ntoh32(e->status), (int)ntoh32(e->reason)));
15884
+#ifdef WL_WPS_SYNC
15885
+ if (wl_wps_session_update(ndev,
15886
+ WPS_STATE_CONNECT_FAIL, e->addr.octet) == BCME_UNSUPPORTED) {
15887
+ /* Unexpected event. Ignore it. */
15888
+ return 0;
15889
+ }
15890
+#endif /* WL_WPS_SYNC */
15891
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
15892
+ if (event == WLC_E_SET_SSID) {
15893
+ wl_get_connect_failed_status(cfg, e);
15894
+ }
15895
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
15896
+ /* Dump FW preserve buffer content */
15897
+ wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
15898
+
972715899 /* Clean up any pending scan request */
972815900 wl_cfg80211_cancel_scan(cfg);
9729
- if (wl_get_drv_status(cfg, CONNECTING, ndev))
15901
+
15902
+ if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
15903
+ if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
15904
+ WL_INFORM_MEM(("wl dissassoc\n"));
15905
+ err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
15906
+ if (err < 0) {
15907
+ WL_ERR(("WLC_DISASSOC error %d\n", err));
15908
+ err = 0;
15909
+ }
15910
+ } else {
15911
+ WL_DBG(("connect fail. clear disconnecting bit\n"));
15912
+ wl_clr_drv_status(cfg, DISCONNECTING, ndev);
15913
+ }
973015914 wl_bss_connect_done(cfg, ndev, e, data, false);
15915
+ wl_clr_drv_status(cfg, CONNECTING, ndev);
15916
+ WL_INFORM_MEM(("connect fail reported\n"));
15917
+ }
973115918 } else {
9732
- WL_DBG(("%s nothing\n", __FUNCTION__));
15919
+ WL_DBG(("wl_notify_connect_status nothing\n"));
973315920 }
9734
- }
9735
- else {
15921
+#if defined(OEM_ANDROID)
15922
+ DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
15923
+#endif // endif
15924
+ } else {
973615925 WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev)));
973715926 }
973815927 return err;
973915928 }
974015929
9741
-void wl_cfg80211_set_rmc_pid(int pid)
15930
+#ifdef WL_RELMCAST
15931
+void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
974215932 {
9743
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
15933
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
974415934 if (pid > 0)
974515935 cfg->rmc_event_pid = pid;
974615936 WL_DBG(("set pid for rmc event : pid=%d\n", pid));
974715937 }
15938
+#endif /* WL_RELMCAST */
974815939
15940
+#ifdef WLAIBSS
15941
+void wl_cfg80211_set_txfail_pid(struct net_device *dev, int pid)
15942
+{
15943
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
15944
+ if (pid > 0)
15945
+ cfg->aibss_txfail_pid = pid;
15946
+ WL_DBG(("set pid for aibss fail event : pid=%d\n", pid));
15947
+}
15948
+
15949
+static s32
15950
+wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
15951
+ const wl_event_msg_t *e, void *data)
15952
+{
15953
+ u32 evt = ntoh32(e->event_type);
15954
+ int ret = -1;
15955
+#ifdef PCIE_FULL_DONGLE
15956
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
15957
+ u32 reason = ntoh32(e->reason);
15958
+#endif // endif
15959
+ if (cfg->aibss_txfail_pid != 0) {
15960
+#ifdef PCIE_FULL_DONGLE
15961
+ if (reason == AIBSS_PEER_FREE) {
15962
+ uint8 ifindex;
15963
+ wl_event_msg_t event;
15964
+
15965
+ bzero(&event, sizeof(wl_event_msg_t));
15966
+ memcpy(&event, e, sizeof(wl_event_msg_t));
15967
+
15968
+ ifindex = (uint8)dhd_ifname2idx(dhd->info, event.ifname);
15969
+ WL_INFORM_MEM(("Peer freed. Flow rings delete for peer.\n"));
15970
+ dhd_flow_rings_delete_for_peer(dhd, ifindex,
15971
+ (void *)&event.addr.octet[0]);
15972
+ return 0;
15973
+ }
15974
+#endif // endif
15975
+ ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL,
15976
+ cfg->aibss_txfail_seq++, &e->addr, ETHER_ADDR_LEN);
15977
+ }
15978
+
15979
+ WL_DBG(("txfail : evt=%d, pid=%d, ret=%d, mac=" MACF "\n",
15980
+ evt, cfg->aibss_txfail_pid, ret, CONST_ETHERP_TO_MACF(&e->addr)));
15981
+ return ret;
15982
+}
15983
+#endif /* WLAIBSS */
974915984 #ifdef WL_RELMCAST
975015985 static s32
975115986 wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
....@@ -9804,6 +16039,7 @@
980416039 }
980516040 #endif /* GSCAN_SUPPORT */
980616041
16042
+#ifdef RSSI_MONITOR_SUPPORT
980716043 static s32 wl_handle_rssi_monitor_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
980816044 const wl_event_msg_t *e, void *data)
980916045 {
....@@ -9812,6 +16048,7 @@
981216048 u32 datalen = be32_to_cpu(e->datalen);
981316049 struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
981416050 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
16051
+
981516052 if (datalen) {
981616053 wl_rssi_monitor_evt_t *evt_data = (wl_rssi_monitor_evt_t *)data;
981716054 if (evt_data->version == RSSI_MONITOR_VERSION) {
....@@ -9830,6 +16067,7 @@
983016067 #endif /* WL_VENDOR_EXT_SUPPORT || CONFIG_BCMDHD_VENDOR_EXT */
983116068 return BCME_OK;
983216069 }
16070
+#endif /* RSSI_MONITOR_SUPPORT */
983316071
983416072 static s32
983516073 wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
....@@ -9842,7 +16080,10 @@
984216080 u32 status = be32_to_cpu(e->status);
984316081 #ifdef DHD_LOSSLESS_ROAMING
984416082 struct wl_security *sec;
9845
-#endif
16083
+#endif // endif
16084
+#if defined(WBTEXT)
16085
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16086
+#endif /* WBTEXT */
984616087 WL_DBG(("Enter \n"));
984716088
984816089 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
....@@ -9857,81 +16098,299 @@
985716098
985816099 if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
985916100 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
9860
- if (cfg->roam_offload &&
9861
- memcmp(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN) == 0) {
9862
- WL_INFORM(("BSSID already updated\n"));
9863
- return err;
9864
- }
986516101 #ifdef DHD_LOSSLESS_ROAMING
9866
- if (cfg->roam_offload) {
16102
+ sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16103
+ /* In order to reduce roaming delay, wl_bss_roaming_done is
16104
+ * early called with WLC_E_LINK event. It is called from
16105
+ * here only if WLC_E_LINK event is blocked for specific
16106
+ * security type.
16107
+ */
16108
+ if (IS_AKM_SUITE_FT(sec)) {
986716109 wl_bss_roaming_done(cfg, ndev, e, data);
16110
+ }
16111
+ /* Roam timer is deleted mostly from wl_cfg80211_change_station
16112
+ * after roaming is finished successfully. We need to delete
16113
+ * the timer from here only for some security types that aren't
16114
+ * using wl_cfg80211_change_station to authorize SCB
16115
+ */
16116
+ if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
986816117 wl_del_roam_timeout(cfg);
986916118 }
9870
- else {
9871
- sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
9872
- /* In order to reduce roaming delay, wl_bss_roaming_done is
9873
- * early called with WLC_E_LINK event. It is called from
9874
- * here only if WLC_E_LINK event is blocked for specific
9875
- * security type.
9876
- */
9877
- if (IS_AKM_SUITE_FT(sec)) {
9878
- wl_bss_roaming_done(cfg, ndev, e, data);
9879
- }
9880
- /* Roam timer is deleted mostly from wl_cfg80211_change_station
9881
- * after roaming is finished successfully. We need to delete
9882
- * the timer from here only for some security types that aren't
9883
- * using wl_cfg80211_change_station to authorize SCB
16119
+#else
16120
+#if !defined(DHD_NONFT_ROAMING)
16121
+ wl_bss_roaming_done(cfg, ndev, e, data);
16122
+#endif /* !DHD_NONFT_ROAMING */
16123
+#endif /* DHD_LOSSLESS_ROAMING */
16124
+#ifdef WBTEXT
16125
+ if (dhdp->wbtext_support) {
16126
+ /* set wnm_keepalives_max_idle after association */
16127
+ wl_cfg80211_wbtext_set_wnm_maxidle(cfg, ndev);
16128
+
16129
+ /* Mostly nbr request of BTM query will be handled
16130
+ * from wl_cfg80211_change_station
16131
+ * after key negotiation is finished.
16132
+ * This part is only for some specific security
16133
+ * types (FT, CCKM) that don't call
16134
+ * wl_cfg80211_change_station after roaming
988416135 */
988516136 if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
9886
- wl_del_roam_timeout(cfg);
16137
+ /* send nbr request or BTM query to update RCC
16138
+ * after roaming completed
16139
+ */
16140
+ wl_cfg80211_wbtext_update_rcc(cfg, ndev);
988716141 }
988816142 }
9889
-#else
9890
- wl_bss_roaming_done(cfg, ndev, e, data);
9891
-#endif /* DHD_LOSSLESS_ROAMING */
9892
- memcpy(&cfg->last_roamed_addr, (void *)&e->addr, ETHER_ADDR_LEN);
16143
+#endif /* WBTEXT */
989316144 } else {
989416145 wl_bss_connect_done(cfg, ndev, e, data, true);
989516146 }
989616147 act = true;
989716148 wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
989816149 wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
16150
+
16151
+ if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
16152
+ wl_vndr_ies_get_vendor_oui(cfg, ndev, NULL, 0);
16153
+ }
989916154 }
990016155 #ifdef DHD_LOSSLESS_ROAMING
990116156 else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) {
990216157 wl_del_roam_timeout(cfg);
990316158 }
9904
-#endif
16159
+#endif // endif
990516160 return err;
990616161 }
16162
+
16163
+#ifdef CUSTOM_EVENT_PM_WAKE
16164
+uint32 last_dpm_upd_time = 0; /* ms */
16165
+#define DPM_UPD_LMT_TIME ((CUSTOM_EVENT_PM_WAKE + (5)) * (1000) * (4)) /* ms */
16166
+#define DPM_UPD_LMT_RSSI -85 /* dbm */
16167
+
16168
+static s32
16169
+wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16170
+ const wl_event_msg_t *e, void *data)
16171
+{
16172
+ s32 err = BCME_OK;
16173
+ struct net_device *ndev = NULL;
16174
+ u8 *pbuf = NULL;
16175
+ uint32 cur_dpm_upd_time = 0;
16176
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
16177
+ s32 rssi;
16178
+#ifdef SUPPORT_RSSI_SUM_REPORT
16179
+ wl_rssi_ant_mimo_t rssi_ant_mimo;
16180
+#endif /* SUPPORT_RSSI_SUM_REPORT */
16181
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16182
+
16183
+ pbuf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
16184
+ if (pbuf == NULL) {
16185
+ WL_ERR(("failed to allocate local pbuf\n"));
16186
+ return -ENOMEM;
16187
+ }
16188
+
16189
+ err = wldev_iovar_getbuf_bsscfg(ndev, "dump",
16190
+ "pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN,
16191
+ 0, &cfg->ioctl_buf_sync);
16192
+
16193
+ if (err) {
16194
+ WL_ERR(("dump ioctl err = %d", err));
16195
+ } else {
16196
+ WL_ERR(("PM status : %s\n", pbuf));
16197
+ }
16198
+
16199
+ if (pbuf) {
16200
+ MFREE(cfg->osh, pbuf, WLC_IOCTL_MEDLEN);
16201
+ }
16202
+
16203
+ if (dhd->early_suspended) {
16204
+ /* LCD off */
16205
+#ifdef SUPPORT_RSSI_SUM_REPORT
16206
+ /* Query RSSI sum across antennas */
16207
+ memset(&rssi_ant_mimo, 0, sizeof(rssi_ant_mimo));
16208
+ err = wl_get_rssi_per_ant(ndev, ndev->name, NULL, &rssi_ant_mimo);
16209
+ if (err) {
16210
+ WL_ERR(("Could not get rssi sum (%d)\n", err));
16211
+ }
16212
+ rssi = rssi_ant_mimo.rssi_sum;
16213
+ if (rssi == 0)
16214
+#endif /* SUPPORT_RSSI_SUM_REPORT */
16215
+ {
16216
+ scb_val_t scb_val;
16217
+ memset(&scb_val, 0, sizeof(scb_val_t));
16218
+ scb_val.val = 0;
16219
+ err = wldev_ioctl_get(ndev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
16220
+ if (err) {
16221
+ WL_ERR(("Could not get rssi (%d)\n", err));
16222
+ }
16223
+ rssi = wl_rssi_offset(dtoh32(scb_val.val));
16224
+ }
16225
+ WL_ERR(("RSSI %d dBm\n", rssi));
16226
+ if (rssi > DPM_UPD_LMT_RSSI) {
16227
+ return err;
16228
+ }
16229
+ } else {
16230
+ /* LCD on */
16231
+ return err;
16232
+ }
16233
+
16234
+ if (last_dpm_upd_time == 0) {
16235
+ last_dpm_upd_time = OSL_SYSUPTIME();
16236
+ } else {
16237
+ cur_dpm_upd_time = OSL_SYSUPTIME();
16238
+ if (cur_dpm_upd_time - last_dpm_upd_time < DPM_UPD_LMT_TIME) {
16239
+ scb_val_t scbval;
16240
+ DHD_STATLOG_CTRL(dhd, ST(DISASSOC_INT_START),
16241
+ dhd_net2idx(dhd->info, ndev), 0);
16242
+ bzero(&scbval, sizeof(scb_val_t));
16243
+
16244
+ err = wldev_ioctl_set(ndev, WLC_DISASSOC,
16245
+ &scbval, sizeof(scb_val_t));
16246
+ if (err < 0) {
16247
+ WL_ERR(("Disassoc error %d\n", err));
16248
+ return err;
16249
+ }
16250
+ WL_ERR(("Force Disassoc due to updated DPM event.\n"));
16251
+
16252
+ last_dpm_upd_time = 0;
16253
+ } else {
16254
+ last_dpm_upd_time = cur_dpm_upd_time;
16255
+ }
16256
+ }
16257
+
16258
+ return err;
16259
+}
16260
+#endif /* CUSTOM_EVENT_PM_WAKE */
990716261
990816262 #ifdef QOS_MAP_SET
990916263 /* get user priority table */
991016264 uint8 *
9911
-wl_get_up_table(void)
16265
+wl_get_up_table(dhd_pub_t * dhdp, int idx)
991216266 {
9913
- return (uint8 *)(g_bcm_cfg->up_table);
16267
+ struct net_device *ndev;
16268
+ struct bcm_cfg80211 *cfg;
16269
+
16270
+ ndev = dhd_idx2net(dhdp, idx);
16271
+ if (ndev) {
16272
+ cfg = wl_get_cfg(ndev);
16273
+ if (cfg)
16274
+ return (uint8 *)(cfg->up_table);
16275
+ }
16276
+
16277
+ return NULL;
991416278 }
991516279 #endif /* QOS_MAP_SET */
991616280
9917
-#ifdef DHD_LOSSLESS_ROAMING
16281
+#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
991816282 static s32
991916283 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
992016284 const wl_event_msg_t *e, void *data)
992116285 {
9922
- s32 err = 0;
9923
-
16286
+ struct wl_security *sec;
16287
+ struct net_device *ndev;
992416288 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16289
+ u32 status = ntoh32(e->status);
16290
+ u32 reason = ntoh32(e->reason);
16291
+
16292
+ BCM_REFERENCE(sec);
16293
+
16294
+ if (status == WLC_E_STATUS_SUCCESS && reason != WLC_E_REASON_INITIAL_ASSOC) {
16295
+ WL_ERR(("Attempting roam with reason code : %d\n", reason));
16296
+ }
16297
+
16298
+#ifdef CONFIG_SILENT_ROAM
16299
+ if (dhdp->in_suspend && reason == WLC_E_REASON_SILENT_ROAM) {
16300
+ dhdp->sroamed = TRUE;
16301
+ }
16302
+#endif /* CONFIG_SILENT_ROAM */
16303
+
16304
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16305
+
16306
+#ifdef DBG_PKT_MON
16307
+ if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
16308
+ DHD_DBG_PKT_MON_STOP(dhdp);
16309
+ DHD_DBG_PKT_MON_START(dhdp);
16310
+ }
16311
+#endif /* DBG_PKT_MON */
16312
+#ifdef DHD_LOSSLESS_ROAMING
16313
+ sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16314
+ /* Disable Lossless Roaming for specific AKM suite
16315
+ * Any other AKM suite can be added below if transition time
16316
+ * is delayed because of Lossless Roaming
16317
+ * and it causes any certication failure
16318
+ */
16319
+ if (IS_AKM_SUITE_FT(sec)) {
16320
+ return BCME_OK;
16321
+ }
992516322
992616323 dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC;
992716324 /* Restore flow control */
992816325 dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
992916326
993016327 mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
9931
-
9932
- return err;
9933
-}
993416328 #endif /* DHD_LOSSLESS_ROAMING */
16329
+
16330
+ return BCME_OK;
16331
+}
16332
+#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
16333
+
16334
+static s32
16335
+wl_notify_roam_start_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16336
+ const wl_event_msg_t *e, void *data)
16337
+{
16338
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
16339
+ struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16340
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
16341
+ int event_type;
16342
+
16343
+ event_type = WIFI_EVENT_ROAM_SCAN_STARTED;
16344
+ wl_cfgvendor_send_async_event(wiphy, ndev, GOOGLE_ROAM_EVENT_START,
16345
+ &event_type, sizeof(int));
16346
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || (WL_VENDOR_EXT_SUPPORT) */
16347
+
16348
+ return BCME_OK;
16349
+}
16350
+
16351
+#ifdef ENABLE_HOGSQS
16352
+static s32
16353
+wl_cfg80211_hogsqs_notify(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16354
+ const wl_event_msg_t *e, void *data)
16355
+{
16356
+ struct net_device *ndev = NULL;
16357
+ struct wireless_dev *wdev = NULL;
16358
+ struct ether_addr *hog_etheraddr;
16359
+ gfp_t aflags;
16360
+
16361
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16362
+ wdev = ndev_to_wdev(ndev);
16363
+ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
16364
+
16365
+ hog_etheraddr = (struct ether_addr *)data;
16366
+ WL_DBG(("RX HOGGER EVENT: " MACDBG "\n", MAC2STRDBG(hog_etheraddr->octet)));
16367
+
16368
+ mutex_lock(&cfg->usr_sync);
16369
+ if ((wdev->iftype != NL80211_IFTYPE_AP) &&
16370
+ (wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
16371
+ WL_DBG(("Ignore RX HOGGER EVENT \n"));
16372
+ mutex_unlock(&cfg->usr_sync);
16373
+ return -EINVAL;
16374
+ }
16375
+
16376
+ /* Kernel cfg80211 API. this API makes NL80211_ATTR_CQM_PKT_LOSS_EVENT
16377
+ * in wpa_supplicant
16378
+ */
16379
+ cfg80211_cqm_pktloss_notify(ndev, hog_etheraddr->octet, 10, aflags);
16380
+ mutex_unlock(&cfg->usr_sync);
16381
+
16382
+ /* disable the Event of HOGGER */
16383
+ wl_add_remove_eventextmsg(ndev, WLC_E_LDF_HOGGER, false);
16384
+
16385
+ /* after WL_HOGSQS_TIMEOUT_MS timeout, workqueue handler enable the
16386
+ * event
16387
+ */
16388
+ schedule_delayed_work(&cfg->hogsqs_eventwork,
16389
+ msecs_to_jiffies(WL_HOGSQS_TIMEOUT_MS));
16390
+ return 0;
16391
+
16392
+}
16393
+#endif /* ENABLE_HOGSQS */
993516394
993616395 static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
993716396 {
....@@ -9961,14 +16420,21 @@
996116420 conn_info->resp_ie_len = 0;
996216421 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
996316422 }
16423
+
996416424 if (assoc_info.req_len) {
996516425 err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
9966
- WL_ASSOC_INFO_MAX, NULL);
16426
+ assoc_info.req_len, NULL);
996716427 if (unlikely(err)) {
996816428 WL_ERR(("could not get assoc req (%d)\n", err));
996916429 return err;
997016430 }
9971
- conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req);
16431
+ if (assoc_info.req_len < sizeof(struct dot11_assoc_req)) {
16432
+ WL_ERR(("req_len %d lessthan %d \n", assoc_info.req_len,
16433
+ (int)sizeof(struct dot11_assoc_req)));
16434
+ return BCME_BADLEN;
16435
+ }
16436
+ conn_info->req_ie_len = (uint32)(assoc_info.req_len
16437
+ - sizeof(struct dot11_assoc_req));
997216438 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
997316439 conn_info->req_ie_len -= ETHER_ADDR_LEN;
997416440 }
....@@ -9982,14 +16448,21 @@
998216448 } else {
998316449 conn_info->req_ie_len = 0;
998416450 }
16451
+
998516452 if (assoc_info.resp_len) {
998616453 err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
9987
- WL_ASSOC_INFO_MAX, NULL);
16454
+ assoc_info.resp_len, NULL);
998816455 if (unlikely(err)) {
998916456 WL_ERR(("could not get assoc resp (%d)\n", err));
999016457 return err;
999116458 }
9992
- conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp);
16459
+ if (assoc_info.resp_len < sizeof(struct dot11_assoc_resp)) {
16460
+ WL_ERR(("resp_len %d is lessthan %d \n", assoc_info.resp_len,
16461
+ (int)sizeof(struct dot11_assoc_resp)));
16462
+ return BCME_BADLEN;
16463
+ }
16464
+ conn_info->resp_ie_len = assoc_info.resp_len -
16465
+ (uint32)sizeof(struct dot11_assoc_resp);
999316466 if (conn_info->resp_ie_len <= MAX_REQ_LINE) {
999416467 memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
999516468 } else {
....@@ -10004,12 +16477,11 @@
1000416477 DOT11_MNG_QOS_MAP_ID)) != NULL) {
1000516478 WL_DBG((" QoS map set IE found in assoc response\n"));
1000616479 if (!cfg->up_table) {
10007
- cfg->up_table = kmalloc(UP_TABLE_MAX, GFP_KERNEL);
16480
+ cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
1000816481 }
1000916482 wl_set_up_table(cfg->up_table, qos_map_ie);
1001016483 } else {
10011
- kfree(cfg->up_table);
10012
- cfg->up_table = NULL;
16484
+ MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
1001316485 }
1001416486 #endif /* QOS_MAP_SET */
1001516487 } else {
....@@ -10017,104 +16489,153 @@
1001716489 }
1001816490 WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
1001916491 conn_info->resp_ie_len));
10020
-
16492
+#ifdef REVERSE_AIFSN
16493
+ DHD_REVERSE_AIFSN(cfg->pub, ndev);
16494
+#endif /* REVERSE_AIFSN */
1002116495 return err;
1002216496 }
1002316497
1002416498 static s32 wl_ch_to_chanspec(struct net_device *dev, int ch, struct wl_join_params *join_params,
10025
- size_t *join_params_size)
16499
+ size_t *join_params_size, struct ieee80211_channel *chan)
1002616500 {
10027
- struct bcm_cfg80211 *cfg;
10028
- s32 bssidx = -1;
1002916501 chanspec_t chanspec = 0, chspec;
16502
+ struct bcm_cfg80211 *cfg =
16503
+ (struct bcm_cfg80211 *)wiphy_priv(dev->ieee80211_ptr->wiphy);
1003016504
10031
- if (ch != 0) {
10032
- cfg = (struct bcm_cfg80211 *)wiphy_priv(dev->ieee80211_ptr->wiphy);
10033
- join_params->params.chanspec_num = 1;
10034
- join_params->params.chanspec_list[0] = ch;
16505
+ if ((ch != 0) && (cfg && !cfg->rcc_enabled)) {
16506
+ join_params->params.chanspec_num = 1;
16507
+ join_params->params.chanspec_list[0] = ch;
1003516508
10036
- if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
10037
- chanspec |= WL_CHANSPEC_BAND_2G;
10038
- else
10039
- chanspec |= WL_CHANSPEC_BAND_5G;
16509
+#ifdef WL_6E
16510
+ if (chan->center_freq > FREQ_START_6G_CHANNEL) {
16511
+ chanspec |= WL_CHANSPEC_BAND_6G;
16512
+ } else
16513
+#endif /* WL_6E */
16514
+ if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
16515
+ chanspec |= WL_CHANSPEC_BAND_2G;
16516
+ else
16517
+ chanspec |= WL_CHANSPEC_BAND_5G;
1004016518
10041
- /* Get the min_bw set for the interface */
10042
- chspec = wl_cfg80211_ulb_get_min_bw_chspec(dev->ieee80211_ptr, bssidx);
10043
- if (chspec == INVCHANSPEC) {
10044
- WL_ERR(("Invalid chanspec \n"));
10045
- return -EINVAL;
10046
- }
10047
- chanspec |= chspec;
10048
- chanspec |= WL_CHANSPEC_CTL_SB_NONE;
16519
+ /* Get the min_bw set for the interface */
16520
+ chspec = WL_CHANSPEC_BW_20;
16521
+ if (chspec == INVCHANSPEC) {
16522
+ WL_ERR(("Invalid chanspec \n"));
16523
+ return -EINVAL;
16524
+ }
16525
+ chanspec |= chspec;
16526
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
1004916527
10050
- *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
10051
- join_params->params.chanspec_num * sizeof(chanspec_t);
16528
+ *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
16529
+ join_params->params.chanspec_num * sizeof(chanspec_t);
1005216530
10053
- join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
10054
- join_params->params.chanspec_list[0] |= chanspec;
10055
- join_params->params.chanspec_list[0] =
10056
- wl_chspec_host_to_driver(join_params->params.chanspec_list[0]);
16531
+ join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
16532
+ join_params->params.chanspec_list[0] |= chanspec;
16533
+ join_params->params.chanspec_list[0] =
16534
+ wl_chspec_host_to_driver(join_params->params.chanspec_list[0]);
1005716535
10058
- join_params->params.chanspec_num =
10059
- htod32(join_params->params.chanspec_num);
10060
-
10061
- WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
10062
- join_params->params.chanspec_list[0],
10063
- join_params->params.chanspec_num));
16536
+ join_params->params.chanspec_num =
16537
+ htod32(join_params->params.chanspec_num);
1006416538 }
16539
+#ifdef ESCAN_CHANNEL_CACHE
16540
+ else {
16541
+ /* If channel is not present and ESCAN_CHANNEL_CACHE is enabled,
16542
+ * use the cached channel list
16543
+ */
16544
+ int n_channels;
16545
+ n_channels = get_roam_channel_list(ch, join_params->params.chanspec_list,
16546
+ MAX_ROAM_CHANNEL, &join_params->ssid, ioctl_version, chan);
16547
+ join_params->params.chanspec_num = htod32(n_channels);
16548
+ *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
16549
+ join_params->params.chanspec_num * sizeof(chanspec_t);
16550
+ }
16551
+#endif /* ESCAN_CHANNEL_CACHE */
16552
+
16553
+ WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
16554
+ join_params->params.chanspec_list[0],
16555
+ join_params->params.chanspec_num));
1006516556 return 0;
1006616557 }
1006716558
10068
-static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam)
16559
+static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16560
+ bool update_ssid)
1006916561 {
10070
- struct wl_bss_info *bi;
16562
+ struct cfg80211_bss *bss;
16563
+ wl_bss_info_t *bi;
1007116564 struct wlc_ssid *ssid;
10072
- struct bcm_tlv *tim;
16565
+ const struct bcm_tlv *tim;
1007316566 s32 beacon_interval;
1007416567 s32 dtim_period;
1007516568 size_t ie_len;
10076
- u8 *ie;
16569
+ const u8 *ie;
1007716570 u8 *curbssid;
1007816571 s32 err = 0;
1007916572 struct wiphy *wiphy;
1008016573 u32 channel;
1008116574 char *buf;
16575
+ u32 freq, band;
1008216576
1008316577 wiphy = bcmcfg_to_wiphy(cfg);
1008416578
1008516579 ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
1008616580 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
10087
-
10088
- mutex_lock(&cfg->usr_sync);
10089
-
10090
- buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_ATOMIC);
16581
+ bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
16582
+ ssid->SSID, ssid->SSID_len);
16583
+ buf = (char *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
1009116584 if (!buf) {
1009216585 WL_ERR(("buffer alloc failed.\n"));
1009316586 return BCME_NOMEM;
1009416587 }
16588
+ mutex_lock(&cfg->usr_sync);
1009516589 *(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
10096
- err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX, false);
10097
-
16590
+ err = wldev_ioctl_get(ndev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX);
1009816591 if (unlikely(err)) {
1009916592 WL_ERR(("Could not get bss info %d\n", err));
1010016593 goto update_bss_info_out;
1010116594 }
10102
- bi = (struct wl_bss_info *)(buf + 4);
16595
+ bi = (wl_bss_info_t *)(buf + 4);
1010316596 channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
1010416597 wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN);
1010516598
10106
- if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
10107
- WL_ERR(("Bssid doesn't match\n"));
10108
- err = -EIO;
10109
- goto update_bss_info_out;
10110
- }
10111
- err = wl_inform_single_bss(cfg, bi, roam);
10112
- if (unlikely(err))
10113
- goto update_bss_info_out;
16599
+ if (!bss) {
16600
+ WL_DBG(("Could not find the AP\n"));
16601
+ if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
16602
+ WL_ERR(("Bssid doesn't match\n"));
16603
+ err = -EIO;
16604
+ goto update_bss_info_out;
16605
+ }
16606
+ err = wl_inform_single_bss(cfg, bi, update_ssid);
16607
+ if (unlikely(err))
16608
+ goto update_bss_info_out;
1011416609
10115
- ie = ((u8 *)bi) + bi->ie_offset;
10116
- ie_len = bi->ie_length;
10117
- beacon_interval = cpu_to_le16(bi->beacon_period);
16610
+ ie = ((u8 *)bi) + bi->ie_offset;
16611
+ ie_len = bi->ie_length;
16612
+ beacon_interval = cpu_to_le16(bi->beacon_period);
16613
+ } else {
16614
+ WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
16615
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
16616
+ freq = ieee80211_channel_to_frequency(channel);
16617
+#else
16618
+#ifdef WL_6E
16619
+ band = CHSPEC_IS6G(wl_chspec_driver_to_host(bi->chanspec))? IEEE80211_BAND_6GHZ :
16620
+ (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
16621
+#else
16622
+ band = (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
16623
+#endif /* WL_6E */
16624
+ freq = ieee80211_channel_to_frequency(channel, band);
16625
+#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !(WL_COMPAT_WIRELESS) */
16626
+ bss->channel = ieee80211_get_channel(wiphy, freq);
16627
+#if defined(WL_CFG80211_P2P_DEV_IF)
16628
+ ie = (const u8 *)bss->ies->data;
16629
+ ie_len = bss->ies->len;
16630
+#else
16631
+ ie = bss->information_elements;
16632
+ ie_len = bss->len_information_elements;
16633
+#endif /* WL_CFG80211_P2P_DEV_IF */
16634
+ beacon_interval = bss->beacon_interval;
16635
+
16636
+ CFG80211_PUT_BSS(wiphy, bss);
16637
+ }
16638
+
1011816639 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
1011916640 if (tim) {
1012016641 dtim_period = tim->data[1];
....@@ -10125,8 +16646,8 @@
1012516646 * so we speficially query dtim information.
1012616647 */
1012716648 dtim_period = 0;
10128
- err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
10129
- &dtim_period, sizeof(dtim_period), false);
16649
+ err = wldev_ioctl_get(ndev, WLC_GET_DTIMPRD,
16650
+ &dtim_period, sizeof(dtim_period));
1013016651 if (unlikely(err)) {
1013116652 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
1013216653 goto update_bss_info_out;
....@@ -10141,7 +16662,7 @@
1014116662 WL_ERR(("Failed with error %d\n", err));
1014216663 }
1014316664
10144
- kfree(buf);
16665
+ MFREE(cfg->osh, buf, WL_EXTRA_BUF_MAX);
1014516666 mutex_unlock(&cfg->usr_sync);
1014616667 return err;
1014716668 }
....@@ -10153,40 +16674,102 @@
1015316674 struct wl_connect_info *conn_info = wl_to_conn(cfg);
1015416675 s32 err = 0;
1015516676 u8 *curbssid;
10156
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
16677
+ u32 *channel;
16678
+ scb_val_t scbval;
16679
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
1015716680 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
1015816681 struct ieee80211_supported_band *band;
1015916682 struct ieee80211_channel *notify_channel = NULL;
10160
- u32 *channel;
1016116683 u32 freq;
10162
-#endif
10163
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
16684
+#ifdef BCM4359_CHIP
16685
+ struct channel_info ci;
16686
+ u32 cur_channel;
16687
+#endif /* BCM4359_CHIP */
16688
+#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16689
+#if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16690
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
16691
+ defined(CFG80211_ROAM_API_GE_4_12)
1016416692 struct cfg80211_roam_info roam_info;
10165
-#endif
10166
-
10167
-
16693
+#endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
16694
+#if defined(WL_FILS_ROAM_OFFLD)
16695
+ struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
16696
+ struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
16697
+#endif // endif
16698
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
16699
+#ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16700
+ dhd_if_t *ifp = NULL;
16701
+#endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
1016816702 #ifdef WLFBT
1016916703 uint32 data_len = 0;
1017016704 if (data)
1017116705 data_len = ntoh32(e->datalen);
1017216706 #endif /* WLFBT */
1017316707
10174
- wl_get_assoc_ies(cfg, ndev);
16708
+ BCM_REFERENCE(dhdp);
16709
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16710
+ channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
16711
+#ifdef BCM4359_CHIP
16712
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16713
+ /* Skip calling cfg80211_roamed If the channels are same and
16714
+ * the current bssid & the new bssid are same
16715
+ * Also clear timer roam_timeout.
16716
+ * Only used on BCM4359 devices.
16717
+ */
16718
+ bzero(&ci, sizeof(ci));
16719
+ if ((wldev_ioctl_get(ndev, WLC_GET_CHANNEL, &ci,
16720
+ sizeof(ci))) < 0) {
16721
+ WL_ERR(("Failed to get current channel !"));
16722
+ err = BCME_ERROR;
16723
+ goto fail;
16724
+ }
16725
+ cur_channel = dtoh32(ci.hw_channel);
16726
+ if ((*channel == cur_channel) && ((memcmp(curbssid, &e->addr,
16727
+ ETHER_ADDR_LEN) == 0) || (memcmp(&cfg->last_roamed_addr,
16728
+ &e->addr, ETHER_ADDR_LEN) == 0))) {
16729
+ WL_ERR(("BSS already present, Skipping roamed event to"
16730
+ " upper layer\n"));
16731
+ goto fail;
16732
+ }
16733
+#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
16734
+#endif /* BCM4359 CHIP */
16735
+
16736
+ if ((err = wl_get_assoc_ies(cfg, ndev)) != BCME_OK) {
16737
+ DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
16738
+ dhd_net2idx(dhdp->info, ndev), WLAN_REASON_DEAUTH_LEAVING);
16739
+ WL_ERR(("Fetching Assoc IEs failed, Skipping roamed event to"
16740
+ " upper layer\n"));
16741
+ /* To make sure disconnect, and fw sync, explictly send dissassoc
16742
+ * for BSSID 00:00:00:00:00:00 issue
16743
+ */
16744
+ bzero(&scbval, sizeof(scb_val_t));
16745
+ scbval.val = WLAN_REASON_DEAUTH_LEAVING;
16746
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
16747
+ scbval.val = htod32(scbval.val);
16748
+ if (wldev_ioctl_set(ndev, WLC_DISASSOC, &scbval,
16749
+ sizeof(scb_val_t)) < 0) {
16750
+ WL_ERR(("WLC_DISASSOC error\n"));
16751
+ }
16752
+ goto fail;
16753
+ }
16754
+
1017516755 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID);
1017616756 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
10177
- wl_update_bss_info(cfg, ndev, true);
16757
+ if ((err = wl_update_bss_info(cfg, ndev, true)) != BCME_OK) {
16758
+ WL_ERR(("failed to update bss info, err=%d\n", err));
16759
+ goto fail;
16760
+ }
1017816761 wl_update_pmklist(ndev, cfg->pmk_list, err);
1017916762
10180
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
10181
- /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
1018216763 channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
16764
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
16765
+ /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
1018316766 if (*channel <= CH_MAX_2G_CHANNEL)
1018416767 band = wiphy->bands[IEEE80211_BAND_2GHZ];
1018516768 else
1018616769 band = wiphy->bands[IEEE80211_BAND_5GHZ];
1018716770 freq = ieee80211_channel_to_frequency(*channel, band->band);
1018816771 notify_channel = ieee80211_get_channel(wiphy, freq);
10189
-#endif
16772
+#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
1019016773 #ifdef WLFBT
1019116774 /* back up the given FBT key for the further supplicant request,
1019216775 * currently not checking the FBT is enabled for current BSS in DHD,
....@@ -10196,47 +16779,229 @@
1019616779 memcpy(cfg->fbt_key, data, FBT_KEYLEN);
1019716780 }
1019816781 #endif /* WLFBT */
10199
- printk("wl_bss_roaming_done succeeded to " MACDBG "\n",
10200
- MAC2STRDBG((const u8*)(&e->addr)));
16782
+#ifdef CUSTOM_LONG_RETRY_LIMIT
16783
+ if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
16784
+ WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
16785
+ }
16786
+#endif /* CUSTOM_LONG_RETRY_LIMIT */
16787
+ DHD_STATLOG_CTRL(dhdp, ST(REASSOC_INFORM),
16788
+ dhd_net2idx(dhdp->info, ndev), 0);
16789
+ WL_ERR(("Report roam event to upper layer. " MACDBG " (ch:%d)\n",
16790
+ MAC2STRDBG((const u8*)(&e->addr)), *channel));
1020116791
10202
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
10203
-//added by Eason 20200528
10204
- memset(&roam_info, 0, sizeof(roam_info));
16792
+#if (defined(CONFIG_ARCH_MSM) && defined(CFG80211_ROAMED_API_UNIFIED)) || \
16793
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) || defined(WL_FILS_ROAM_OFFLD) || \
16794
+ defined(CFG80211_ROAM_API_GE_4_12)
16795
+ memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
1020516796 roam_info.channel = notify_channel;
1020616797 roam_info.bssid = curbssid;
1020716798 roam_info.req_ie = conn_info->req_ie;
1020816799 roam_info.req_ie_len = conn_info->req_ie_len;
1020916800 roam_info.resp_ie = conn_info->resp_ie;
1021016801 roam_info.resp_ie_len = conn_info->resp_ie_len;
10211
-
16802
+#if defined(WL_FILS_ROAM_OFFLD)
16803
+ if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
16804
+ roam_info.fils.kek = fils_info->fils_kek;
16805
+ roam_info.fils.kek_len = fils_info->fils_kek_len;
16806
+ roam_info.fils.update_erp_next_seq_num = true;
16807
+ roam_info.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
16808
+ roam_info.fils.pmk = fils_info->fils_pmk;
16809
+ roam_info.fils.pmk_len = fils_info->fils_kek_len;
16810
+ roam_info.fils.pmkid = fils_info->fils_pmkid;
16811
+ }
16812
+#endif // endif
1021216813 cfg80211_roamed(ndev, &roam_info, GFP_KERNEL);
1021316814 #else
1021416815 cfg80211_roamed(ndev,
10215
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
16816
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
1021616817 notify_channel,
10217
-#endif
16818
+#endif // endif
1021816819 curbssid,
1021916820 conn_info->req_ie, conn_info->req_ie_len,
1022016821 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
10221
-#endif
10222
- WL_DBG(("Report roaming result\n"));
16822
+#endif /* (CONFIG_ARCH_MSM && CFG80211_ROAMED_API_UNIFIED) || LINUX_VERSION >= 4.12.0 */
1022316823
16824
+ memcpy(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN);
1022416825 wl_set_drv_status(cfg, CONNECTED, ndev);
1022516826
16827
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
16828
+ cfg->roam_count++;
16829
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
16830
+#ifdef WL_BAM
16831
+ if (wl_adps_bad_ap_check(cfg, &e->addr)) {
16832
+ if (wl_adps_enabled(cfg, ndev)) {
16833
+ wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
16834
+ }
16835
+ }
16836
+#endif /* WL_BAM */
16837
+
16838
+#ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
16839
+ ifp = dhd_get_ifp(dhdp, e->ifidx);
16840
+ if (ifp) {
16841
+ ifp->post_roam_evt = TRUE;
16842
+ }
16843
+#endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
16844
+
16845
+ /* Arm pkt logging timer */
16846
+ dhd_dump_mod_pkt_timer(dhdp, PKT_CNT_RSN_ROAM);
16847
+
16848
+ return err;
16849
+
16850
+fail:
16851
+#ifdef DHD_LOSSLESS_ROAMING
16852
+ wl_del_roam_timeout(cfg);
16853
+#endif /* DHD_LOSSLESS_ROAMING */
1022616854 return err;
1022716855 }
1022816856
16857
+static bool
16858
+wl_cfg80211_verify_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
16859
+ struct cfg80211_bss **bss)
16860
+{
16861
+ struct wiphy *wiphy;
16862
+ struct wlc_ssid *ssid;
16863
+ uint8 *curbssid;
16864
+ int count = 0;
16865
+ int ret = false;
16866
+ u8 cur_ssid[DOT11_MAX_SSID_LEN + 1];
16867
+
16868
+ wiphy = bcmcfg_to_wiphy(cfg);
16869
+ ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
16870
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16871
+ if (!ssid) {
16872
+ WL_ERR(("No SSID found in the saved profile \n"));
16873
+ return false;
16874
+ }
16875
+
16876
+ do {
16877
+ *bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
16878
+ ssid->SSID, ssid->SSID_len);
16879
+ if (*bss || (count > 5)) {
16880
+ break;
16881
+ }
16882
+
16883
+ count++;
16884
+ msleep(100);
16885
+ } while (*bss == NULL);
16886
+
16887
+ WL_DBG(("cfg80211 bss_ptr:%p loop_cnt:%d\n", *bss, count));
16888
+ if (*bss) {
16889
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0))
16890
+ /* Update the reference count after use. In case of kernel version >= 4.7
16891
+ * the cfg802_put_bss is called in cfg80211_connect_bss context
16892
+ */
16893
+ CFG80211_PUT_BSS(wiphy, *bss);
16894
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) */
16895
+ ret = true;
16896
+ } else {
16897
+ memset(cur_ssid, 0, DOT11_MAX_SSID_LEN);
16898
+ strncpy(cur_ssid, ssid->SSID,
16899
+ MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN));
16900
+ WL_ERR(("No bss entry for ssid:%s bssid:"MACDBG"\n",
16901
+ cur_ssid, MAC2STRDBG(curbssid)));
16902
+ }
16903
+
16904
+ return ret;
16905
+}
16906
+
16907
+_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
16908
+#ifdef WL_FILS
16909
+static s32
16910
+wl_get_fils_connect_params(struct bcm_cfg80211 *cfg, struct net_device *ndev)
16911
+{
16912
+ const bcm_xtlv_t* pxtlv_out;
16913
+ struct wl_fils_info *fils_info = wl_to_fils_info(cfg);
16914
+ int err = BCME_OK;
16915
+ bcm_iov_buf_t *iov_buf_in = NULL;
16916
+ bcm_iov_buf_t iov_buf_out = {0};
16917
+ u16 len;
16918
+ u16 type;
16919
+ const u8 *data;
16920
+ iov_buf_in = MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
16921
+ if (!iov_buf_in) {
16922
+ WL_ERR(("buf memory alloc failed\n"));
16923
+ err = BCME_NOMEM;
16924
+ goto exit;
16925
+ }
16926
+ iov_buf_out.version = WL_FILS_IOV_VERSION;
16927
+ iov_buf_out.id = WL_FILS_CMD_GET_CONNECT_PARAMS;
16928
+ err = wldev_iovar_getbuf(ndev, "fils", (uint8*)&iov_buf_out, sizeof(bcm_iov_buf_t),
16929
+ iov_buf_in, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
16930
+ if (unlikely(err)) {
16931
+ WL_ERR(("Get FILS Params Error (%d)\n", err));
16932
+ goto exit;
16933
+ }
16934
+ pxtlv_out = (bcm_xtlv_t*)((bcm_iov_buf_t*)iov_buf_in)->data;
16935
+ len = iov_buf_in->len;
16936
+ do {
16937
+ if (!bcm_valid_xtlv(pxtlv_out, iov_buf_in->len, BCM_XTLV_OPTION_ALIGN32)) {
16938
+ WL_ERR(("%s: XTLV is not valid\n", __func__));
16939
+ err = BCME_BADARG;
16940
+ goto exit;
16941
+ }
16942
+ bcm_xtlv_unpack_xtlv(pxtlv_out, &type, &len, &data, BCM_XTLV_OPTION_ALIGN32);
16943
+ switch (type) {
16944
+ case WL_FILS_XTLV_ERP_NEXT_SEQ_NUM:
16945
+ fils_info->fils_erp_next_seq_num = *(const u16 *)data;
16946
+ break;
16947
+ case WL_FILS_XTLV_KEK:
16948
+ if (memcpy_s(fils_info->fils_kek,
16949
+ WL_MAX_FILS_KEY_LEN, data, len) < 0) {
16950
+ err = BCME_BADARG;
16951
+ goto exit;
16952
+ }
16953
+ fils_info->fils_kek_len = len;
16954
+ break;
16955
+ case WL_FILS_XTLV_PMK:
16956
+ if (memcpy_s(fils_info->fils_pmk,
16957
+ WL_MAX_FILS_KEY_LEN, data, len) < 0) {
16958
+ err = BCME_BADARG;
16959
+ goto exit;
16960
+ }
16961
+ fils_info->fils_pmk_len = len;
16962
+ break;
16963
+ case WL_FILS_XTLV_PMKID:
16964
+ if (memcpy_s(fils_info->fils_pmkid,
16965
+ WL_MAX_FILS_KEY_LEN, data, len) < 0) {
16966
+ err = BCME_BADARG;
16967
+ goto exit;
16968
+ }
16969
+ break;
16970
+ default:
16971
+ WL_ERR(("%s: wrong XTLV code\n", __func__));
16972
+ break;
16973
+
16974
+ }
16975
+ } while ((pxtlv_out = bcm_next_xtlv(pxtlv_out, (int *)&iov_buf_in->len,
16976
+ BCM_XTLV_OPTION_ALIGN32)) && iov_buf_in->len);
16977
+exit:
16978
+ if (iov_buf_in) {
16979
+ MFREE(cfg->osh, iov_buf_in, WLC_IOCTL_SMLEN);
16980
+ }
16981
+ return err;
16982
+}
16983
+#endif /* WL_FILS */
1022916984 static s32
1023016985 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
1023116986 const wl_event_msg_t *e, void *data, bool completed)
1023216987 {
1023316988 struct wl_connect_info *conn_info = wl_to_conn(cfg);
1023416989 struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
10235
-#if defined(CUSTOM_SET_CPUCORE)
10236
- dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
10237
-#endif
1023816990 s32 err = 0;
16991
+#ifdef WL_FILS
16992
+ struct cfg80211_connect_resp_params resp_params = {0};
16993
+ struct wl_fils_info *fils_info = NULL;
16994
+ struct wlc_ssid *ssid = NULL;
16995
+ struct wiphy *wiphy = NULL;
16996
+
16997
+#endif /* WL_FILS */
1023916998 u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
16999
+ u32 event_type = ntoh32(e->event_type);
17000
+ struct cfg80211_bss *bss = NULL;
17001
+ dhd_pub_t *dhdp;
17002
+ dhdp = (dhd_pub_t *)(cfg->pub);
17003
+ BCM_REFERENCE(dhdp);
17004
+
1024017005 if (!sec) {
1024117006 WL_ERR(("sec is NULL\n"));
1024217007 return -ENODEV;
....@@ -10245,7 +17010,8 @@
1024517010 #ifdef ESCAN_RESULT_PATCH
1024617011 if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
1024717012 if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) {
10248
- WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n",
17013
+ WL_INFORM_MEM((" Connected event of connected device "
17014
+ "e=%d s=%d, ignore it\n",
1024917015 ntoh32(e->event_type), ntoh32(e->status)));
1025017016 return err;
1025117017 }
....@@ -10255,60 +17021,138 @@
1025517021 WL_DBG(("copy bssid\n"));
1025617022 memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN);
1025717023 }
10258
-
1025917024 #else
1026017025 if (cfg->scan_request) {
10261
- wl_notify_escan_complete(cfg, ndev, true, true);
17026
+ wl_cfg80211_cancel_scan(cfg);
1026217027 }
1026317028 #endif /* ESCAN_RESULT_PATCH */
1026417029 if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
1026517030 wl_cfg80211_scan_abort(cfg);
10266
- wl_clr_drv_status(cfg, CONNECTING, ndev);
1026717031 if (completed) {
1026817032 wl_get_assoc_ies(cfg, ndev);
1026917033 wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
1027017034 WL_PROF_BSSID);
1027117035 curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
10272
- wl_update_bss_info(cfg, ndev, false);
17036
+ /*
17037
+ * CFG layer relies on cached IEs (from probe/beacon) to fetch matching bss.
17038
+ * For cases, there is no match available,
17039
+ * need to update the cache based on bss info from fw.
17040
+ */
17041
+ wl_update_bss_info(cfg, ndev, true);
1027317042 wl_update_pmklist(ndev, cfg->pmk_list, err);
1027417043 wl_set_drv_status(cfg, CONNECTED, ndev);
17044
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
17045
+ if (dhdp->roam_env_detection)
17046
+ wldev_iovar_setint(ndev, "roam_env_detection",
17047
+ AP_ENV_INDETERMINATE);
17048
+#endif /* ROAM_AP_ENV_DETECTION */
1027517049 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
1027617050 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
1027717051 init_completion(&cfg->iface_disable);
1027817052 #else
1027917053 /* reinitialize completion to clear previous count */
1028017054 INIT_COMPLETION(cfg->iface_disable);
10281
-#endif
17055
+#endif // endif
1028217056 }
1028317057 #ifdef CUSTOM_SET_CPUCORE
10284
- if (wl_get_chan_isvht80(ndev, dhd)) {
17058
+ if (wl_get_chan_isvht80(ndev, dhdp)) {
1028517059 if (ndev == bcmcfg_to_prmry_ndev(cfg))
10286
- dhd->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
17060
+ dhdp->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
1028717061 else if (is_p2p_group_iface(ndev->ieee80211_ptr))
10288
- dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
10289
- dhd_set_cpucore(dhd, TRUE);
17062
+ dhdp->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
17063
+ dhd_set_cpucore(dhdp, TRUE);
1029017064 }
1029117065 #endif /* CUSTOM_SET_CPUCORE */
10292
-
17066
+#ifdef CUSTOM_LONG_RETRY_LIMIT
17067
+ if (wl_set_retry(ndev, CUSTOM_LONG_RETRY_LIMIT, 1) < 0) {
17068
+ WL_ERR(("CUSTOM_LONG_RETRY_LIMIT set fail!\n"));
17069
+ }
17070
+#endif /* CUSTOM_LONG_RETRY_LIMIT */
17071
+ bzero(&cfg->last_roamed_addr, ETHER_ADDR_LEN);
1029317072 }
10294
- cfg80211_connect_result(ndev,
10295
- curbssid,
10296
- conn_info->req_ie,
10297
- conn_info->req_ie_len,
10298
- conn_info->resp_ie,
10299
- conn_info->resp_ie_len,
10300
- completed ? WLAN_STATUS_SUCCESS :
10301
- (sec->auth_assoc_res_status) ?
10302
- sec->auth_assoc_res_status :
10303
- WLAN_STATUS_UNSPECIFIED_FAILURE,
10304
- GFP_KERNEL);
10305
- if (completed)
10306
- WL_INFORM(("Report connect result - connection succeeded\n"));
17073
+ wl_clr_drv_status(cfg, CONNECTING, ndev);
17074
+
17075
+ if (completed && (wl_cfg80211_verify_bss(cfg, ndev, &bss) != true)) {
17076
+ /* If bss entry is not available in the cfg80211 bss cache
17077
+ * the wireless stack will complain and won't populate
17078
+ * wdev->current_bss ptr
17079
+ */
17080
+ WL_ERR(("BSS entry not found. Indicate assoc event failure\n"));
17081
+ completed = false;
17082
+ sec->auth_assoc_res_status = WLAN_STATUS_UNSPECIFIED_FAILURE;
17083
+ }
17084
+#ifdef WL_FILS
17085
+ if ((sec->auth_type == DOT11_FILS_SKEY_PFS)||(sec->auth_type == DOT11_FILS_SKEY)) {
17086
+ wl_get_fils_connect_params(cfg, ndev);
17087
+ fils_info = wl_to_fils_info(cfg);
17088
+ ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
17089
+ wiphy = bcmcfg_to_wiphy(cfg);
17090
+ resp_params.status = completed ? WLAN_STATUS_SUCCESS :
17091
+ (sec->auth_assoc_res_status) ?
17092
+ sec->auth_assoc_res_status :
17093
+ WLAN_STATUS_UNSPECIFIED_FAILURE;
17094
+ resp_params.bssid = curbssid;
17095
+ resp_params.bss = CFG80211_GET_BSS(wiphy, NULL, curbssid,
17096
+ ssid->SSID, ssid->SSID_len);
17097
+ resp_params.req_ie = conn_info->req_ie;
17098
+ resp_params.req_ie_len = conn_info->req_ie_len;
17099
+ resp_params.resp_ie = conn_info->resp_ie;
17100
+ resp_params.resp_ie_len = conn_info->resp_ie_len;
17101
+#ifdef WL_FILS_ROAM_OFFLD
17102
+ resp_params.fils.kek = fils_info->fils_kek;
17103
+ resp_params.fils.kek_len = fils_info->fils_kek_len;
17104
+ resp_params.fils.update_erp_next_seq_num = true;
17105
+ resp_params.fils.erp_next_seq_num = fils_info->fils_erp_next_seq_num;
17106
+ resp_params.fils.pmk = fils_info->fils_pmk;
17107
+ resp_params.fils.pmk_len = fils_info->fils_kek_len;
17108
+ resp_params.fils.pmkid = fils_info->fils_pmkid;
17109
+#else
17110
+ resp_params.fils_kek = fils_info->fils_kek;
17111
+ resp_params.fils_kek_len = fils_info->fils_kek_len;
17112
+ resp_params.update_erp_next_seq_num = true;
17113
+ resp_params.fils_erp_next_seq_num = fils_info->fils_erp_next_seq_num;
17114
+ resp_params.pmk = fils_info->fils_pmk;
17115
+ resp_params.pmk_len = fils_info->fils_kek_len;
17116
+ resp_params.pmkid = fils_info->fils_pmkid;
17117
+#endif /* WL_FILS_ROAM_OFFLD */
17118
+ cfg80211_connect_done(ndev, &resp_params, GFP_KERNEL);
17119
+ }
1030717120 else
10308
- WL_ERR(("Report connect result - connection failed\n"));
17121
+#endif /* WL_FILS */
17122
+ {
17123
+ CFG80211_CONNECT_RESULT(ndev,
17124
+ curbssid,
17125
+ bss,
17126
+ conn_info->req_ie,
17127
+ conn_info->req_ie_len,
17128
+ conn_info->resp_ie,
17129
+ conn_info->resp_ie_len,
17130
+ completed ? WLAN_STATUS_SUCCESS :
17131
+ (sec->auth_assoc_res_status) ?
17132
+ sec->auth_assoc_res_status :
17133
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
17134
+ GFP_KERNEL);
17135
+ }
17136
+ if (completed) {
17137
+ WL_INFORM_MEM(("[%s] Report connect result - "
17138
+ "connection succeeded\n", ndev->name));
17139
+#ifdef WL_BAM
17140
+ if (wl_adps_bad_ap_check(cfg, &e->addr)) {
17141
+ if (wl_adps_enabled(cfg, ndev)) {
17142
+ wl_adps_set_suspend(cfg, ndev, ADPS_SUSPEND);
17143
+ }
17144
+ }
17145
+#endif /* WL_BAM */
17146
+ } else
17147
+ WL_ERR(("[%s] Report connect result - connection failed\n", ndev->name));
17148
+ } else {
17149
+ WL_INFORM_MEM(("[%s] Ignore event:%d. drv status"
17150
+ " connecting:%x. connected:%d\n",
17151
+ ndev->name, event_type, wl_get_drv_status(cfg, CONNECTING, ndev),
17152
+ wl_get_drv_status(cfg, CONNECTED, ndev)));
1030917153 }
1031017154 #ifdef CONFIG_TCPACK_FASTTX
10311
- if (wl_get_chan_isvht80(ndev, dhd))
17155
+ if (wl_get_chan_isvht80(ndev, dhdp))
1031217156 wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
1031317157 else
1031417158 wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
....@@ -10327,12 +17171,15 @@
1032717171
1032817172 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
1032917173
17174
+ WL_INFORM_MEM(("[%s] mic fail event - " MACDBG " \n",
17175
+ ndev->name, MAC2STRDBG(e->addr.octet)));
1033017176 mutex_lock(&cfg->usr_sync);
1033117177 if (flags & WLC_EVENT_MSG_GROUP)
1033217178 key_type = NL80211_KEYTYPE_GROUP;
1033317179 else
1033417180 key_type = NL80211_KEYTYPE_PAIRWISE;
1033517181
17182
+ wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
1033617183 cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1,
1033717184 NULL, GFP_KERNEL);
1033817185 mutex_unlock(&cfg->usr_sync);
....@@ -10358,211 +17205,10 @@
1035817205 }
1035917206 #endif /* BT_WIFI_HANDOVER */
1036017207
10361
-#ifdef PNO_SUPPORT
1036217208 static s32
10363
-wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
10364
- const wl_event_msg_t *e, void *data)
10365
-{
10366
- struct net_device *ndev = NULL;
10367
-
10368
- WL_ERR((">>> PNO Event\n"));
10369
-
10370
- ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
10371
-
10372
-
10373
-#ifndef WL_SCHED_SCAN
10374
- mutex_lock(&cfg->usr_sync);
10375
- /* TODO: Use cfg80211_sched_scan_results(wiphy); */
10376
- CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
10377
- mutex_unlock(&cfg->usr_sync);
10378
-#else
10379
- /* If cfg80211 scheduled scan is supported, report the pno results via sched
10380
- * scan results
10381
- */
10382
- wl_notify_sched_scan_results(cfg, ndev, e, data);
10383
-#endif /* WL_SCHED_SCAN */
10384
- return 0;
10385
-}
10386
-#endif /* PNO_SUPPORT */
10387
-
10388
-#ifdef GSCAN_SUPPORT
10389
-static s32
10390
-wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
10391
- const wl_event_msg_t *e, void *data)
10392
-{
10393
- s32 err = 0;
10394
- u32 event = be32_to_cpu(e->event_type);
10395
- void *ptr;
10396
- int send_evt_bytes = 0;
10397
- int batch_event_result_dummy = 0;
10398
- struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
10399
- struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
10400
- u32 len = ntoh32(e->datalen);
10401
-
10402
- switch (event) {
10403
- case WLC_E_PFN_SWC:
10404
- ptr = dhd_dev_swc_scan_event(ndev, data, &send_evt_bytes);
10405
- if (send_evt_bytes) {
10406
- wl_cfgvendor_send_async_event(wiphy, ndev,
10407
- GOOGLE_GSCAN_SIGNIFICANT_EVENT, ptr, send_evt_bytes);
10408
- kfree(ptr);
10409
- }
10410
- break;
10411
- case WLC_E_PFN_BEST_BATCHING:
10412
- err = dhd_dev_retrieve_batch_scan(ndev);
10413
- if (err < 0) {
10414
- WL_ERR(("Batch retrieval already in progress %d\n", err));
10415
- } else {
10416
- wl_cfgvendor_send_async_event(wiphy, ndev,
10417
- GOOGLE_GSCAN_BATCH_SCAN_EVENT,
10418
- &batch_event_result_dummy, sizeof(int));
10419
- }
10420
- break;
10421
- case WLC_E_PFN_SCAN_COMPLETE:
10422
- batch_event_result_dummy = WIFI_SCAN_COMPLETE;
10423
- wl_cfgvendor_send_async_event(wiphy, ndev,
10424
- GOOGLE_SCAN_COMPLETE_EVENT,
10425
- &batch_event_result_dummy, sizeof(int));
10426
- break;
10427
- case WLC_E_PFN_BSSID_NET_FOUND:
10428
- ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes,
10429
- HOTLIST_FOUND);
10430
- if (ptr) {
10431
- wl_cfgvendor_send_hotlist_event(wiphy, ndev,
10432
- ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT);
10433
- dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_FOUND);
10434
- } else {
10435
- err = -ENOMEM;
10436
- }
10437
- break;
10438
- case WLC_E_PFN_BSSID_NET_LOST:
10439
- /* WLC_E_PFN_BSSID_NET_LOST is conflict shared with WLC_E_PFN_SCAN_ALLGONE
10440
- * We currently do not use WLC_E_PFN_SCAN_ALLGONE, so if we get it, ignore
10441
- */
10442
- if (len) {
10443
- ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes,
10444
- HOTLIST_LOST);
10445
- if (ptr) {
10446
- wl_cfgvendor_send_hotlist_event(wiphy, ndev,
10447
- ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT);
10448
- dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_LOST);
10449
- } else {
10450
- err = -ENOMEM;
10451
- }
10452
- } else {
10453
- err = -EINVAL;
10454
- }
10455
- break;
10456
- case WLC_E_PFN_GSCAN_FULL_RESULT:
10457
- ptr = dhd_dev_process_full_gscan_result(ndev, data, len, &send_evt_bytes);
10458
- if (ptr) {
10459
- wl_cfgvendor_send_async_event(wiphy, ndev,
10460
- GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes);
10461
- kfree(ptr);
10462
- } else {
10463
- err = -ENOMEM;
10464
- }
10465
- break;
10466
- case WLC_E_PFN_SSID_EXT:
10467
- ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes);
10468
- if (ptr) {
10469
- wl_cfgvendor_send_async_event(wiphy, ndev,
10470
- GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes);
10471
- kfree(ptr);
10472
- } else {
10473
- err = -ENOMEM;
10474
- }
10475
- break;
10476
- case WLC_E_PFN_NET_FOUND:
10477
- break;
10478
- default:
10479
- WL_ERR(("Unknown event %d\n", event));
10480
- break;
10481
- }
10482
- return err;
10483
-}
10484
-#endif /* GSCAN_SUPPORT */
10485
-
10486
-static s32
10487
-wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
10488
- const wl_event_msg_t *e, void *data)
10489
-{
10490
- struct channel_info channel_inform;
10491
- struct wl_scan_results *bss_list;
10492
- struct net_device *ndev = NULL;
10493
- u32 len = WL_SCAN_BUF_MAX;
10494
- s32 err = 0;
10495
- unsigned long flags;
10496
-
10497
- WL_DBG(("Enter \n"));
10498
-#ifdef STBLINUX
10499
- ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
10500
- if (!wl_get_drv_status(cfg, SCANNING, ndev)) {
10501
- /* has been handled by WLC_E_ESCAN_RESULT handler */
10502
-
10503
- WL_DBG(("scan is not ready \n"));
10504
- return err;
10505
- }
10506
-#else
10507
- if (!wl_get_drv_status(cfg, SCANNING, ndev)) {
10508
- WL_ERR(("scan is not ready \n"));
10509
- return err;
10510
- }
10511
- ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
10512
-#endif /* STBLINUX */
10513
- mutex_lock(&cfg->usr_sync);
10514
- wl_clr_drv_status(cfg, SCANNING, ndev);
10515
- memset(&channel_inform, 0, sizeof(channel_inform));
10516
- err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
10517
- sizeof(channel_inform), false);
10518
- if (unlikely(err)) {
10519
- WL_ERR(("scan busy (%d)\n", err));
10520
- goto scan_done_out;
10521
- }
10522
- channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
10523
- if (unlikely(channel_inform.scan_channel)) {
10524
-
10525
- WL_DBG(("channel_inform.scan_channel (%d)\n",
10526
- channel_inform.scan_channel));
10527
- }
10528
- cfg->bss_list = cfg->scan_results;
10529
- bss_list = cfg->bss_list;
10530
- memset(bss_list, 0, len);
10531
- bss_list->buflen = htod32(len);
10532
- err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false);
10533
- if (unlikely(err) && unlikely(!cfg->scan_suppressed)) {
10534
- WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
10535
- err = -EINVAL;
10536
- goto scan_done_out;
10537
- }
10538
- bss_list->buflen = dtoh32(bss_list->buflen);
10539
- bss_list->version = dtoh32(bss_list->version);
10540
- bss_list->count = dtoh32(bss_list->count);
10541
-
10542
- err = wl_inform_bss(cfg);
10543
-
10544
-scan_done_out:
10545
- del_timer_sync(&cfg->scan_timeout);
10546
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
10547
- if (cfg->scan_request) {
10548
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 8, 0))
10549
- struct cfg80211_scan_info info = { .aborted = false };
10550
- cfg80211_scan_done(cfg->scan_request, &info);
10551
-#else
10552
- cfg80211_scan_done(cfg->scan_request, false);
10553
-#endif
10554
- cfg->scan_request = NULL;
10555
- }
10556
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
10557
- WL_DBG(("cfg80211_scan_done\n"));
10558
- mutex_unlock(&cfg->usr_sync);
10559
- return err;
10560
-}
10561
-
10562
-static s32
10563
-wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
10564
- const struct ether_addr *sa, const struct ether_addr *bssid,
10565
- u8 **pheader, u32 *body_len, u8 *pbody)
17209
+wl_frame_get_mgmt(struct bcm_cfg80211 *cfg, u16 fc,
17210
+ const struct ether_addr *da, const struct ether_addr *sa,
17211
+ const struct ether_addr *bssid, u8 **pheader, u32 *body_len, u8 *pbody)
1056617212 {
1056717213 struct dot11_management_header *hdr;
1056817214 u32 totlen = 0;
....@@ -10583,7 +17229,7 @@
1058317229 break;
1058417230 }
1058517231 totlen += DOT11_MGMT_HDR_LEN + prebody_len;
10586
- *pheader = kzalloc(totlen, GFP_KERNEL);
17232
+ *pheader = (u8 *)MALLOCZ(cfg->osh, totlen);
1058717233 if (*pheader == NULL) {
1058817234 WL_ERR(("memory alloc failed \n"));
1058917235 return -ENOMEM;
....@@ -10602,10 +17248,62 @@
1060217248 return err;
1060317249 }
1060417250
17251
+#ifdef WL_CFG80211_GON_COLLISION
17252
+static void
17253
+wl_gon_req_collision(struct bcm_cfg80211 *cfg, wl_action_frame_t *tx_act_frm,
17254
+ wifi_p2p_pub_act_frame_t *rx_act_frm, struct net_device *ndev,
17255
+ struct ether_addr sa, struct ether_addr da)
17256
+{
17257
+ if (cfg->afx_hdl->pending_tx_act_frm == NULL)
17258
+ return;
17259
+
17260
+ if (tx_act_frm &&
17261
+ wl_cfgp2p_is_pub_action(tx_act_frm->data, tx_act_frm->len)) {
17262
+ wifi_p2p_pub_act_frame_t *pact_frm;
17263
+
17264
+ pact_frm = (wifi_p2p_pub_act_frame_t *)tx_act_frm->data;
17265
+
17266
+ if (!(pact_frm->subtype == P2P_PAF_GON_REQ &&
17267
+ rx_act_frm->subtype == P2P_PAF_GON_REQ)) {
17268
+ return;
17269
+ }
17270
+ }
17271
+
17272
+ WL_ERR((" GO NEGO Request COLLISION !!! \n"));
17273
+
17274
+ /* if sa(peer) addr is less than da(my) addr,
17275
+ * my device will process peer's gon request and block to send my gon req.
17276
+ *
17277
+ * if not (sa addr > da addr),
17278
+ * my device will process gon request and drop gon req of peer.
17279
+ */
17280
+ if (memcmp(sa.octet, da.octet, ETHER_ADDR_LEN) < 0) {
17281
+ /* block to send tx gon request */
17282
+ cfg->block_gon_req_tx_count = BLOCK_GON_REQ_MAX_NUM;
17283
+ WL_ERR((" block to send gon req tx !!!\n"));
17284
+
17285
+ /* if we are finding a common channel for sending af,
17286
+ * do not scan more to block to send current gon req
17287
+ */
17288
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17289
+ wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, ndev);
17290
+ complete(&cfg->act_frm_scan);
17291
+ }
17292
+ } else {
17293
+ /* drop gon request of peer to process gon request by my device. */
17294
+ WL_ERR((" drop to receive gon req rx !!! \n"));
17295
+ cfg->block_gon_req_rx_count = BLOCK_GON_REQ_MAX_NUM;
17296
+ }
17297
+
17298
+ return;
17299
+}
17300
+#endif /* WL_CFG80211_GON_COLLISION */
1060517301
1060617302 void
10607
-wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev)
17303
+wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 bsscfgidx)
1060817304 {
17305
+ s32 err = 0;
17306
+
1060917307 if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
1061017308 if (timer_pending(&cfg->p2p->listen_timer)) {
1061117309 del_timer_sync(&cfg->p2p->listen_timer);
....@@ -10624,12 +17322,24 @@
1062417322 wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
1062517323 wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
1062617324
10627
- WL_DBG(("*** Wake UP ** abort actframe iovar\n"));
10628
- /* if channel is not zero, "actfame" uses off channel scan.
10629
- * So abort scan for off channel completion.
17325
+ WL_DBG(("*** Wake UP ** abort actframe iovar on bsscfxidx %d\n", bsscfgidx));
17326
+ /* Scan engine is not used for sending action frames in the latest driver
17327
+ * branches. actframe_abort is used in the latest driver branches
17328
+ * instead of scan abort.
17329
+ * If actframe_abort iovar succeeds, don't execute scan abort.
17330
+ * If actframe_abort fails with unsupported error,
17331
+ * execute scan abort (for backward copmatibility).
1063017332 */
10631
- if (cfg->af_sent_channel)
10632
- wl_cfg80211_scan_abort(cfg);
17333
+ if (cfg->af_sent_channel) {
17334
+ err = wldev_iovar_setint_bsscfg(ndev, "actframe_abort", 1, bsscfgidx);
17335
+ if (err < 0) {
17336
+ if (err == BCME_UNSUPPORTED) {
17337
+ wl_cfg80211_scan_abort(cfg);
17338
+ } else {
17339
+ WL_ERR(("actframe_abort failed. ret:%d\n", err));
17340
+ }
17341
+ }
17342
+ }
1063317343 }
1063417344 #ifdef WL_CFG80211_SYNC_GON
1063517345 else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
....@@ -10640,6 +17350,70 @@
1064017350 #endif /* WL_CFG80211_SYNC_GON */
1064117351 }
1064217352
17353
+#if defined(WLTDLS)
17354
+bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len)
17355
+{
17356
+ unsigned char *data;
17357
+
17358
+ if (frame == NULL) {
17359
+ WL_ERR(("Invalid frame \n"));
17360
+ return false;
17361
+ }
17362
+
17363
+ if (frame_len < 5) {
17364
+ WL_ERR(("Invalid frame length [%d] \n", frame_len));
17365
+ return false;
17366
+ }
17367
+
17368
+ data = frame;
17369
+
17370
+ if (!memcmp(data, TDLS_TUNNELED_PRB_REQ, 5) ||
17371
+ !memcmp(data, TDLS_TUNNELED_PRB_RESP, 5)) {
17372
+ WL_DBG(("TDLS Vendor Specific Received type\n"));
17373
+ return true;
17374
+ }
17375
+
17376
+ return false;
17377
+}
17378
+#endif /* WLTDLS */
17379
+
17380
+#if defined(WES_SUPPORT)
17381
+static int wes_mode = 0;
17382
+int wl_cfg80211_set_wes_mode(int mode)
17383
+{
17384
+ wes_mode = mode;
17385
+ return 0;
17386
+}
17387
+
17388
+int wl_cfg80211_get_wes_mode(void)
17389
+{
17390
+ return wes_mode;
17391
+}
17392
+
17393
+bool wl_cfg80211_is_wes(void *frame, u32 frame_len)
17394
+{
17395
+ unsigned char *data;
17396
+
17397
+ if (frame == NULL) {
17398
+ WL_ERR(("Invalid frame \n"));
17399
+ return false;
17400
+ }
17401
+
17402
+ if (frame_len < 4) {
17403
+ WL_ERR(("Invalid frame length [%d] \n", frame_len));
17404
+ return false;
17405
+ }
17406
+
17407
+ data = frame;
17408
+
17409
+ if (memcmp(data, "\x7f\x00\x00\xf0", 4) == 0) {
17410
+ WL_DBG(("Receive WES VS Action Frame \n"));
17411
+ return true;
17412
+ }
17413
+
17414
+ return false;
17415
+}
17416
+#endif /* WES_SUPPORT */
1064317417
1064417418 int wl_cfg80211_get_ioctl_version(void)
1064517419 {
....@@ -10661,24 +17435,50 @@
1066117435 wifi_p2p_pub_act_frame_t *act_frm = NULL;
1066217436 wifi_p2p_action_frame_t *p2p_act_frm = NULL;
1066317437 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
10664
- wl_event_rx_frame_data_t *rxframe =
10665
- (wl_event_rx_frame_data_t*)data;
10666
- u32 event = ntoh32(e->event_type);
17438
+ wl_event_rx_frame_data_t *rxframe;
17439
+ u32 event;
1066717440 u8 *mgmt_frame;
10668
- u8 bsscfgidx = e->bsscfgidx;
10669
- u32 mgmt_frame_len = ntoh32(e->datalen);
10670
- u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
10671
-
10672
- if (mgmt_frame_len < sizeof(wl_event_rx_frame_data_t)) {
10673
- WL_ERR(("wrong datalen:%d\n", mgmt_frame_len));
17441
+ u8 bsscfgidx;
17442
+ u32 mgmt_frame_len;
17443
+ u16 channel;
17444
+#if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
17445
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
17446
+#endif /* BCMDONGLEHOST && TDLS_MSG_ONLY_WFD && WLTDLS */
17447
+ if (ntoh32(e->datalen) < sizeof(wl_event_rx_frame_data_t)) {
17448
+ WL_ERR(("wrong datalen:%d\n", ntoh32(e->datalen)));
1067417449 return -EINVAL;
1067517450 }
10676
- mgmt_frame_len -= sizeof(wl_event_rx_frame_data_t);
10677
-
10678
- memset(&bssid, 0, ETHER_ADDR_LEN);
10679
-
17451
+ mgmt_frame_len = ntoh32(e->datalen) - (uint32)sizeof(wl_event_rx_frame_data_t);
17452
+ event = ntoh32(e->event_type);
17453
+ bsscfgidx = e->bsscfgidx;
17454
+ rxframe = (wl_event_rx_frame_data_t *)data;
17455
+ if (!rxframe) {
17456
+ WL_ERR(("rxframe: NULL\n"));
17457
+ return -EINVAL;
17458
+ }
17459
+ channel = (ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK);
17460
+ bzero(&bssid, ETHER_ADDR_LEN);
1068017461 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
17462
+ if ((ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) &&
17463
+ (event == WLC_E_PROBREQ_MSG)) {
17464
+ struct net_info *iter, *next;
17465
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
17466
+ for_each_ndev(cfg, iter, next) {
17467
+ GCC_DIAGNOSTIC_POP();
17468
+ if (iter->ndev && iter->wdev &&
17469
+ iter->wdev->iftype == NL80211_IFTYPE_AP) {
17470
+ ndev = iter->ndev;
17471
+ cfgdev = ndev_to_cfgdev(ndev);
17472
+ break;
17473
+ }
17474
+ }
17475
+ }
1068117476
17477
+#ifdef WL_6E
17478
+ if (CHSPEC_IS6G(ntoh16(rxframe->channel))) {
17479
+ band = wiphy->bands[IEEE80211_BAND_6GHZ];
17480
+ } else
17481
+#endif /* WL_6E */
1068217482 if (channel <= CH_MAX_2G_CHANNEL)
1068317483 band = wiphy->bands[IEEE80211_BAND_2GHZ];
1068417484 else
....@@ -10687,21 +17487,27 @@
1068717487 WL_ERR(("No valid band"));
1068817488 return -EINVAL;
1068917489 }
10690
-#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
17490
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
1069117491 freq = ieee80211_channel_to_frequency(channel);
1069217492 (void)band->band;
1069317493 #else
1069417494 freq = ieee80211_channel_to_frequency(channel, band->band);
10695
-#endif
17495
+#endif // endif
1069617496 if (event == WLC_E_ACTION_FRAME_RX) {
10697
- wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
10698
- NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
17497
+ u8 ioctl_buf[WLC_IOCTL_SMLEN];
1069917498
10700
- err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
17499
+ if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
17500
+ NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx,
17501
+ NULL)) != BCME_OK) {
17502
+ WL_ERR(("WLC_GET_CUR_ETHERADDR failed, error %d\n", err));
17503
+ goto exit;
17504
+ }
17505
+
17506
+ err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
1070117507 if (err < 0)
1070217508 WL_ERR(("WLC_GET_BSSID error %d\n", err));
10703
- memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
10704
- err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
17509
+ memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
17510
+ err = wl_frame_get_mgmt(cfg, FC_ACTION, &da, &e->addr, &bssid,
1070517511 &mgmt_frame, &mgmt_frame_len,
1070617512 (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
1070717513 if (err < 0) {
....@@ -10731,25 +17537,33 @@
1073117537 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
1073217538
1073317539 /* Stop waiting for next AF. */
10734
- wl_stop_wait_next_action_frame(cfg, ndev);
17540
+ wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
1073517541 }
1073617542 }
1073717543 (void) sd_act_frm;
1073817544 #ifdef WLTDLS
10739
- } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
10740
- WL_DBG((" TDLS Action Frame Received type = %d \n",
10741
- mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
10742
-
17545
+ } else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
17546
+ (wl_cfg80211_is_tdls_tunneled_frame(
17547
+ &mgmt_frame[DOT11_MGMT_HDR_LEN],
17548
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
17549
+ if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
17550
+ WL_ERR((" TDLS Action Frame Received type = %d \n",
17551
+ mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
17552
+ }
17553
+#ifdef TDLS_MSG_ONLY_WFD
17554
+ if (!dhdp->tdls_mode) {
17555
+ WL_DBG((" TDLS Frame filtered \n"));
17556
+ goto exit;
17557
+ }
17558
+#else
1074317559 if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
1074417560 cfg->tdls_mgmt_frame = mgmt_frame;
1074517561 cfg->tdls_mgmt_frame_len = mgmt_frame_len;
1074617562 cfg->tdls_mgmt_freq = freq;
1074717563 return 0;
1074817564 }
10749
-
10750
- } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_VENDOR_SPECIFIC) {
10751
- WL_DBG((" TDLS Vendor Specific Received type \n"));
10752
-#endif
17565
+#endif /* TDLS_MSG_ONLY_WFD */
17566
+#endif /* WLTDLS */
1075317567 #ifdef QOS_MAP_SET
1075417568 } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
1075517569 /* update QoS map set table */
....@@ -10759,20 +17573,41 @@
1075917573 DOT11_MNG_QOS_MAP_ID)) != NULL) {
1076017574 WL_DBG((" QoS map set IE found in QoS action frame\n"));
1076117575 if (!cfg->up_table) {
10762
- cfg->up_table = kmalloc(UP_TABLE_MAX, GFP_KERNEL);
17576
+ cfg->up_table = (uint8 *)MALLOC(cfg->osh, UP_TABLE_MAX);
1076317577 }
1076417578 wl_set_up_table(cfg->up_table, qos_map_ie);
1076517579 } else {
10766
- kfree(cfg->up_table);
10767
- cfg->up_table = NULL;
17580
+ MFREE(cfg->osh, cfg->up_table, UP_TABLE_MAX);
1076817581 }
1076917582 #endif /* QOS_MAP_SET */
17583
+#ifdef WBTEXT
17584
+ } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_RRM) {
17585
+ /* radio measurement category */
17586
+ switch (mgmt_frame[DOT11_MGMT_HDR_LEN+1]) {
17587
+ case DOT11_RM_ACTION_NR_REP:
17588
+ if (wl_cfg80211_recv_nbr_resp(ndev,
17589
+ &mgmt_frame[DOT11_MGMT_HDR_LEN],
17590
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)
17591
+ == BCME_OK) {
17592
+ WL_DBG(("RCC updated by nbr response\n"));
17593
+ }
17594
+ break;
17595
+ default:
17596
+ break;
17597
+ }
17598
+#endif /* WBTEXT */
1077017599 } else {
1077117600 /*
1077217601 * if we got normal action frame and ndev is p2p0,
1077317602 * we have to change ndev from p2p0 to wlan0
1077417603 */
10775
-
17604
+#if defined(WES_SUPPORT)
17605
+ if (wl_cfg80211_is_wes(&mgmt_frame[DOT11_MGMT_HDR_LEN],
17606
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN) && wes_mode == 0) {
17607
+ /* Ignore WES VS Action frame */
17608
+ goto exit;
17609
+ }
17610
+#endif /* WES_SUPPORT */
1077617611
1077717612 if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
1077817613 u8 action = 0;
....@@ -10785,12 +17620,30 @@
1078517620 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
1078617621
1078717622 /* Stop waiting for next AF. */
10788
- wl_stop_wait_next_action_frame(cfg, ndev);
17623
+ wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
1078917624 }
1079017625 }
1079117626 }
1079217627
1079317628 if (act_frm) {
17629
+#ifdef WL_CFG80211_GON_COLLISION
17630
+ if (act_frm->subtype == P2P_PAF_GON_REQ) {
17631
+ wl_gon_req_collision(cfg,
17632
+ &cfg->afx_hdl->pending_tx_act_frm->action_frame,
17633
+ act_frm, ndev, e->addr, da);
17634
+
17635
+ if (cfg->block_gon_req_rx_count) {
17636
+ WL_ERR(("drop frame GON Req Rx : count (%d)\n",
17637
+ cfg->block_gon_req_rx_count));
17638
+ cfg->block_gon_req_rx_count--;
17639
+ goto exit;
17640
+ }
17641
+ } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
17642
+ /* if go formation done, clear it */
17643
+ cfg->block_gon_req_tx_count = 0;
17644
+ cfg->block_gon_req_rx_count = 0;
17645
+ }
17646
+#endif /* WL_CFG80211_GON_COLLISION */
1079417647
1079517648 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
1079617649 if (cfg->next_af_subtype == act_frm->subtype) {
....@@ -10803,20 +17656,21 @@
1080317656 }
1080417657
1080517658 /* Stop waiting for next AF. */
10806
- wl_stop_wait_next_action_frame(cfg, ndev);
17659
+ wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
17660
+ } else if ((cfg->next_af_subtype == P2P_PAF_GON_RSP) &&
17661
+ (act_frm->subtype == P2P_PAF_GON_REQ)) {
17662
+ /* If current received frame is GO NEG REQ and next
17663
+ * expected frame is GO NEG RESP, do not send it up.
17664
+ */
17665
+ WL_ERR(("GO Neg req received while waiting for RESP."
17666
+ "Discard incoming frame\n"));
17667
+ goto exit;
1080717668 }
1080817669 }
1080917670 }
1081017671
1081117672 wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
1081217673 mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel);
10813
- /*
10814
- * After complete GO Negotiation, roll back to mpc mode
10815
- */
10816
- if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) ||
10817
- (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
10818
- wldev_iovar_setint(ndev, "mpc", 1);
10819
- }
1082017674 if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
1082117675 WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
1082217676 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
....@@ -10846,13 +17700,55 @@
1084617700 return 0;
1084717701 }
1084817702 if (prbreq_ies.wps_ie != NULL) {
10849
- wl_validate_wps_ie((char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
17703
+ wl_validate_wps_ie(
17704
+ (const char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
1085017705 WL_DBG((" wps_ie exist pbc = %d\n", pbc));
1085117706 /* if pbc method, send prob_req mgmt frame to upper layer */
1085217707 if (!pbc)
1085317708 return 0;
1085417709 } else
1085517710 return 0;
17711
+#ifdef WL_SAE
17712
+ } else if (event == WLC_E_EXT_AUTH_FRAME_RX) {
17713
+ u8 ioctl_buf[WLC_IOCTL_SMLEN];
17714
+ u8 *frame;
17715
+
17716
+ WL_DBG(("EVENT: auth frame rx received\n"));
17717
+ if (e->datalen < sizeof(*rxframe)) {
17718
+ WL_ERR(("EXT_AUTH_RX: event data too small. Ignoring event\n"));
17719
+ return -EINVAL;
17720
+ }
17721
+
17722
+ bzero(&da, sizeof(da));
17723
+ if ((err = wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
17724
+ NULL, 0, ioctl_buf, sizeof(ioctl_buf), bsscfgidx,
17725
+ NULL)) != BCME_OK) {
17726
+ WL_ERR(("EXT_AUTH_RX: cur_etheraddr iovar failed, error %d\n", err));
17727
+ goto exit;
17728
+ }
17729
+ memcpy(da.octet, ioctl_buf, ETHER_ADDR_LEN);
17730
+
17731
+ err = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
17732
+ if (err < 0) {
17733
+ if (cfgdev_to_wdev(cfgdev)->iftype == NL80211_IFTYPE_STATION) {
17734
+ memcpy(bssid.octet, da.octet, ETHER_ADDR_LEN);
17735
+ } else {
17736
+ WL_ERR(("EXT_AUTH_RX: WLC_GET_BSSID failed, error %d\n", err));
17737
+ }
17738
+ }
17739
+
17740
+ frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
17741
+ frame += DOT11_MGMT_HDR_LEN;
17742
+ mgmt_frame_len -= DOT11_MGMT_HDR_LEN;
17743
+ err = wl_frame_get_mgmt(cfg, FC_AUTH, &da, &e->addr, &bssid,
17744
+ &mgmt_frame, &mgmt_frame_len, frame);
17745
+ if (err < 0) {
17746
+ WL_ERR(("EXT_AUTH_RX: mgmt frame to cfg80211, len %d channel %d freq %d\n",
17747
+ mgmt_frame_len, channel, freq));
17748
+ goto exit;
17749
+ }
17750
+ isfree = true;
17751
+#endif /* WL_SAE */
1085617752 } else {
1085717753 mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
1085817754
....@@ -10865,6 +17761,20 @@
1086517761 WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
1086617762 "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
1086717763
17764
+#ifdef WL_CFG80211_USE_PRB_REQ_FOR_AF_TX
17765
+ if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) &&
17766
+ !memcmp(cfg->afx_hdl->tx_dst_addr.octet, e->addr.octet,
17767
+ ETHER_ADDR_LEN)) {
17768
+ if (cfg->afx_hdl->pending_tx_act_frm &&
17769
+ wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
17770
+ s32 channel = CHSPEC_CHANNEL(hton16(rxframe->channel));
17771
+ WL_DBG(("PROBE REQUEST : Peer found, channel : %d\n",
17772
+ channel));
17773
+ cfg->afx_hdl->peer_chan = channel;
17774
+ complete(&cfg->act_frm_scan);
17775
+ }
17776
+ }
17777
+#endif /* WL_CFG80211_USE_PRB_REQ_FOR_AF_TX */
1086817778
1086917779 /* Filter any P2P probe reqs arriving during the
1087017780 * GO-NEG Phase
....@@ -10872,7 +17782,7 @@
1087217782 if (cfg->p2p &&
1087317783 #if defined(P2P_IE_MISSING_FIX)
1087417784 cfg->p2p_prb_noti &&
10875
-#endif
17785
+#endif // endif
1087617786 wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
1087717787 WL_DBG(("Filtering P2P probe_req while "
1087817788 "being in GO-Neg state\n"));
....@@ -10885,155 +17795,25 @@
1088517795 WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
1088617796 else
1088717797 WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
10888
-
1088917798 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
10890
- cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
10891
-#elif(LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
17799
+ cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
17800
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
1089217801 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
1089317802 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
1089417803 defined(WL_COMPAT_WIRELESS)
1089517804 cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
1089617805 #else
1089717806 cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
10898
-#endif /* LINUX_VERSION >= VERSION(3, 14, 0) */
17807
+#endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
1089917808
1090017809 WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
1090117810 mgmt_frame_len, ntoh32(e->datalen), channel, freq));
1090217811 exit:
10903
- if (isfree)
10904
- kfree(mgmt_frame);
10905
- return 0;
10906
-}
10907
-
10908
-#ifdef WL_SCHED_SCAN
10909
-/* If target scan is not reliable, set the below define to "1" to do a
10910
- * full escan
10911
- */
10912
-#define FULL_ESCAN_ON_PFN_NET_FOUND 0
10913
-static s32
10914
-wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
10915
- const wl_event_msg_t *e, void *data)
10916
-{
10917
- wl_pfn_net_info_t *netinfo, *pnetinfo;
10918
- struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
10919
- int err = 0;
10920
- struct cfg80211_scan_request *request = NULL;
10921
- struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT];
10922
- struct ieee80211_channel *channel = NULL;
10923
- int channel_req = 0;
10924
- int band = 0;
10925
- struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data;
10926
- int n_pfn_results = pfn_result->count;
10927
-
10928
- WL_DBG(("Enter\n"));
10929
-
10930
- if ((e->event_type == WLC_E_PFN_NET_LOST) || !data) {
10931
- WL_PNO(("Do Nothing %d\n", e->event_type));
10932
- return 0;
17812
+ if (isfree) {
17813
+ MFREE(cfg->osh, mgmt_frame, mgmt_frame_len);
1093317814 }
10934
- if (pfn_result->version != PFN_SCANRESULT_VERSION) {
10935
- WL_ERR(("Incorrect version %d, expected %d\n", pfn_result->version,
10936
- PFN_SCANRESULT_VERSION));
10937
- return 0;
10938
- }
10939
- WL_PNO((">>> PFN NET FOUND event. count:%d \n", n_pfn_results));
10940
- if (n_pfn_results > 0) {
10941
- int i;
10942
-
10943
- if (n_pfn_results > MAX_PFN_LIST_COUNT)
10944
- n_pfn_results = MAX_PFN_LIST_COUNT;
10945
- pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t)
10946
- - sizeof(wl_pfn_net_info_t));
10947
-
10948
- memset(&ssid, 0x00, sizeof(ssid));
10949
-
10950
- request = kzalloc(sizeof(*request)
10951
- + sizeof(*request->channels) * n_pfn_results,
10952
- GFP_KERNEL);
10953
- channel = (struct ieee80211_channel *)kzalloc(
10954
- (sizeof(struct ieee80211_channel) * n_pfn_results),
10955
- GFP_KERNEL);
10956
- if (!request || !channel) {
10957
- WL_ERR(("No memory"));
10958
- err = -ENOMEM;
10959
- goto out_err;
10960
- }
10961
-
10962
- request->wiphy = wiphy;
10963
-
10964
- for (i = 0; i < n_pfn_results; i++) {
10965
- netinfo = &pnetinfo[i];
10966
- if (!netinfo) {
10967
- WL_ERR(("Invalid netinfo ptr. index:%d", i));
10968
- err = -EINVAL;
10969
- goto out_err;
10970
- }
10971
- WL_PNO((">>> SSID:%s Channel:%d \n",
10972
- netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel));
10973
- /* PFN result doesn't have all the info which are required by the supplicant
10974
- * (For e.g IEs) Do a target Escan so that sched scan results are reported
10975
- * via wl_inform_single_bss in the required format. Escan does require the
10976
- * scan request in the form of cfg80211_scan_request. For timebeing, create
10977
- * cfg80211_scan_request one out of the received PNO event.
10978
- */
10979
- ssid[i].ssid_len = MIN(netinfo->pfnsubnet.SSID_len, DOT11_MAX_SSID_LEN);
10980
- memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, ssid[i].ssid_len);
10981
- request->n_ssids++;
10982
-
10983
- channel_req = netinfo->pfnsubnet.channel;
10984
- band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
10985
- : NL80211_BAND_5GHZ;
10986
- channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band);
10987
- channel[i].band = band;
10988
- channel[i].flags |= IEEE80211_CHAN_NO_HT40;
10989
- request->channels[i] = &channel[i];
10990
- request->n_channels++;
10991
- }
10992
-
10993
- /* assign parsed ssid array */
10994
- if (request->n_ssids)
10995
- request->ssids = &ssid[0];
10996
-
10997
- if (wl_get_drv_status_all(cfg, SCANNING)) {
10998
- /* Abort any on-going scan */
10999
- wl_notify_escan_complete(cfg, ndev, true, true);
11000
- }
11001
-
11002
- if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
11003
- WL_PNO((">>> P2P discovery was ON. Disabling it\n"));
11004
- err = wl_cfgp2p_discover_enable_search(cfg, false);
11005
- if (unlikely(err)) {
11006
- wl_clr_drv_status(cfg, SCANNING, ndev);
11007
- goto out_err;
11008
- }
11009
- p2p_scan(cfg) = false;
11010
- }
11011
-
11012
- wl_set_drv_status(cfg, SCANNING, ndev);
11013
-#if FULL_ESCAN_ON_PFN_NET_FOUND
11014
- WL_PNO((">>> Doing Full ESCAN on PNO event\n"));
11015
- err = wl_do_escan(cfg, wiphy, ndev, NULL);
11016
-#else
11017
- WL_PNO((">>> Doing targeted ESCAN on PNO event\n"));
11018
- err = wl_do_escan(cfg, wiphy, ndev, request);
11019
-#endif
11020
- if (err) {
11021
- wl_clr_drv_status(cfg, SCANNING, ndev);
11022
- goto out_err;
11023
- }
11024
- cfg->sched_scan_running = TRUE;
11025
- }
11026
- else {
11027
- WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
11028
- }
11029
-out_err:
11030
- if (request)
11031
- kfree(request);
11032
- if (channel)
11033
- kfree(channel);
1103417815 return err;
1103517816 }
11036
-#endif /* WL_SCHED_SCAN */
1103717817
1103817818 static void wl_init_conf(struct wl_conf *conf)
1103917819 {
....@@ -11050,14 +17830,19 @@
1105017830 unsigned long flags;
1105117831 struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
1105217832
11053
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
11054
- memset(profile, 0, sizeof(struct wl_profile));
11055
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
17833
+ if (!profile) {
17834
+ WL_ERR(("profile null\n"));
17835
+ return;
17836
+ }
17837
+
17838
+ WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
17839
+ bzero(profile, sizeof(struct wl_profile));
17840
+ WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
1105617841 }
1105717842
1105817843 static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
1105917844 {
11060
- memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler));
17845
+ bzero(cfg->evt_handler, sizeof(cfg->evt_handler));
1106117846
1106217847 cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
1106317848 cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
....@@ -11079,6 +17864,8 @@
1107917864 cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
1108017865 cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
1108117866 cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
17867
+ cfg->evt_handler[WLC_E_AUTH_IND] = wl_notify_connect_status;
17868
+ cfg->evt_handler[WLC_E_ASSOC_RESP_IE] = wl_notify_connect_status;
1108217869 #ifdef PNO_SUPPORT
1108317870 cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
1108417871 #endif /* PNO_SUPPORT */
....@@ -11086,48 +17873,131 @@
1108617873 cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
1108717874 cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
1108817875 cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
11089
- cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event;
1109017876 cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
1109117877 cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
1109217878 cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
1109317879 cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
1109417880 cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
1109517881 #endif /* GSCAN_SUPPORT */
17882
+#ifdef RSSI_MONITOR_SUPPORT
1109617883 cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
17884
+#endif /* RSSI_MONITOR_SUPPORT */
1109717885 #ifdef WLTDLS
1109817886 cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
1109917887 #endif /* WLTDLS */
1110017888 cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
17889
+#ifdef WLAIBSS
17890
+ cfg->evt_handler[WLC_E_AIBSS_TXFAIL] = wl_notify_aibss_txfail;
17891
+#endif /* WLAIBSS */
1110117892 #ifdef WL_RELMCAST
1110217893 cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
11103
-#endif
17894
+#endif /* WL_RELMCAST */
1110417895 #ifdef BT_WIFI_HANDOVER
1110517896 cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
11106
-#endif
17897
+#endif // endif
1110717898 #ifdef WL_NAN
11108
- cfg->evt_handler[WLC_E_NAN] = wl_cfgnan_notify_nan_status;
11109
- cfg->evt_handler[WLC_E_PROXD] = wl_cfgnan_notify_proxd_status;
17899
+ cfg->evt_handler[WLC_E_NAN_CRITICAL] = wl_cfgnan_notify_nan_status;
17900
+ cfg->evt_handler[WLC_E_NAN_NON_CRITICAL] = wl_cfgnan_notify_nan_status;
1111017901 #endif /* WL_NAN */
1111117902 cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
11112
-#ifdef DHD_LOSSLESS_ROAMING
17903
+ cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
17904
+#ifdef CUSTOM_EVENT_PM_WAKE
17905
+ cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
17906
+#endif /* CUSTOM_EVENT_PM_WAKE */
17907
+#if defined(DHD_LOSSLESS_ROAMING) || defined(DBG_PKT_MON)
1111317908 cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
11114
-#endif
17909
+#endif /* DHD_LOSSLESS_ROAMING || DBG_PKT_MON */
17910
+ cfg->evt_handler[WLC_E_ROAM_START] = wl_notify_roam_start_status;
17911
+#ifdef WL_BAM
17912
+ cfg->evt_handler[WLC_E_ADPS] = wl_adps_event_handler;
17913
+#endif /* WL_BAM */
17914
+ cfg->evt_handler[WLC_E_PSK_SUP] = wl_cfg80211_sup_event_handler;
17915
+#ifdef WL_BCNRECV
17916
+ cfg->evt_handler[WLC_E_BCNRECV_ABORTED] = wl_bcnrecv_aborted_event_handler;
17917
+#endif /* WL_BCNRECV */
17918
+#ifdef WL_MBO
17919
+ cfg->evt_handler[WLC_E_MBO] = wl_mbo_event_handler;
17920
+#endif /* WL_MBO */
17921
+#ifdef WL_CAC_TS
17922
+ cfg->evt_handler[WLC_E_ADDTS_IND] = wl_cfg80211_cac_event_handler;
17923
+ cfg->evt_handler[WLC_E_DELTS_IND] = wl_cfg80211_cac_event_handler;
17924
+#endif /* WL_CAC_TS */
17925
+#if defined(WL_MBO) || defined(WL_OCE)
17926
+ cfg->evt_handler[WLC_E_PRUNE] = wl_bssid_prune_event_handler;
17927
+#endif /* WL_MBO || WL_OCE */
17928
+#ifdef RTT_SUPPORT
17929
+ cfg->evt_handler[WLC_E_PROXD] = wl_cfg80211_rtt_event_handler;
17930
+#endif // endif
17931
+#ifdef WL_CHAN_UTIL
17932
+ cfg->evt_handler[WLC_E_BSS_LOAD] = wl_cfg80211_bssload_report_event_handler;
17933
+#endif /* WL_CHAN_UTIL */
17934
+ cfg->evt_handler[WLC_E_IND_DOS_STATUS] = wl_notify_dos_status;
17935
+#ifdef WL_SAE
17936
+ cfg->evt_handler[WLC_E_EXT_AUTH_REQ] = wl_notify_extauth_req_event;
17937
+ cfg->evt_handler[WLC_E_EXT_AUTH_FRAME_RX] = wl_notify_rx_mgmt_frame;
17938
+ cfg->evt_handler[WLC_E_MGMT_FRAME_TXSTATUS] = wl_notify_mgmt_frame_tx_complete;
17939
+ cfg->evt_handler[WLC_E_MGMT_FRAME_OFF_CHAN_COMPLETE] = wl_notify_mgmt_frame_tx_complete;
17940
+#endif /* WL_SAE */
17941
+#ifdef ENABLE_HOGSQS
17942
+ cfg->evt_handler[WLC_E_LDF_HOGGER] = wl_cfg80211_hogsqs_notify;
17943
+#endif /* ENABLE_HOGSQS */
17944
+
1111517945 }
1111617946
1111717947 #if defined(STATIC_WL_PRIV_STRUCT)
11118
-static void
17948
+static int
1111917949 wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
1112017950 {
17951
+#ifdef DUAL_ESCAN_RESULT_BUFFER
17952
+ cfg->escan_info.escan_buf[0] = DHD_OS_PREALLOC(cfg->pub,
17953
+ DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
17954
+ if (cfg->escan_info.escan_buf[0] == NULL) {
17955
+ WL_ERR(("Failed to alloc ESCAN_BUF0\n"));
17956
+ return -ENOMEM;
17957
+ }
17958
+
17959
+ cfg->escan_info.escan_buf[1] = DHD_OS_PREALLOC(cfg->pub,
17960
+ DHD_PREALLOC_WIPHY_ESCAN1, ESCAN_BUF_SIZE);
17961
+ if (cfg->escan_info.escan_buf[1] == NULL) {
17962
+ WL_ERR(("Failed to alloc ESCAN_BUF1\n"));
17963
+ return -ENOMEM;
17964
+ }
17965
+
17966
+ bzero(cfg->escan_info.escan_buf[0], ESCAN_BUF_SIZE);
17967
+ bzero(cfg->escan_info.escan_buf[1], ESCAN_BUF_SIZE);
17968
+ cfg->escan_info.escan_type[0] = 0;
17969
+ cfg->escan_info.escan_type[1] = 0;
17970
+#else
1112117971 cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
1112217972 DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
17973
+ if (cfg->escan_info.escan_buf == NULL) {
17974
+ WL_ERR(("Failed to alloc ESCAN_BUF\n"));
17975
+ return -ENOMEM;
17976
+ }
1112317977 bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
17978
+#endif /* DUAL_ESCAN_RESULT_BUFFER */
17979
+
17980
+ return 0;
1112417981 }
1112517982
1112617983 static void
1112717984 wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
1112817985 {
11129
- cfg->escan_info.escan_buf = NULL;
17986
+#ifdef DUAL_ESCAN_RESULT_BUFFER
17987
+ if (cfg->escan_info.escan_buf[0] != NULL) {
17988
+ cfg->escan_info.escan_buf[0] = NULL;
17989
+ cfg->escan_info.escan_type[0] = 0;
17990
+ }
1113017991
17992
+ if (cfg->escan_info.escan_buf[1] != NULL) {
17993
+ cfg->escan_info.escan_buf[1] = NULL;
17994
+ cfg->escan_info.escan_type[1] = 0;
17995
+ }
17996
+#else
17997
+ if (cfg->escan_info.escan_buf != NULL) {
17998
+ cfg->escan_info.escan_buf = NULL;
17999
+ }
18000
+#endif /* DUAL_ESCAN_RESULT_BUFFER */
1113118001 }
1113218002 #endif /* STATIC_WL_PRIV_STRUCT */
1113318003
....@@ -11135,58 +18005,62 @@
1113518005 {
1113618006 WL_DBG(("Enter \n"));
1113718007
11138
- cfg->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
18008
+ cfg->scan_results = (struct wl_scan_results *)MALLOCZ(cfg->osh,
18009
+ WL_SCAN_BUF_MAX);
1113918010 if (unlikely(!cfg->scan_results)) {
1114018011 WL_ERR(("Scan results alloc failed\n"));
1114118012 goto init_priv_mem_out;
1114218013 }
11143
- cfg->conf = (void *)kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
18014
+ cfg->conf = (struct wl_conf *)MALLOCZ(cfg->osh, sizeof(*cfg->conf));
1114418015 if (unlikely(!cfg->conf)) {
1114518016 WL_ERR(("wl_conf alloc failed\n"));
1114618017 goto init_priv_mem_out;
1114718018 }
11148
- cfg->scan_req_int =
11149
- (void *)kzalloc(sizeof(*cfg->scan_req_int), GFP_KERNEL);
18019
+ cfg->scan_req_int = (void *)MALLOCZ(cfg->osh,
18020
+ sizeof(*cfg->scan_req_int));
1115018021 if (unlikely(!cfg->scan_req_int)) {
1115118022 WL_ERR(("Scan req alloc failed\n"));
1115218023 goto init_priv_mem_out;
1115318024 }
11154
- cfg->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
18025
+ cfg->ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
1115518026 if (unlikely(!cfg->ioctl_buf)) {
1115618027 WL_ERR(("Ioctl buf alloc failed\n"));
1115718028 goto init_priv_mem_out;
1115818029 }
11159
- cfg->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
18030
+ cfg->escan_ioctl_buf = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
1116018031 if (unlikely(!cfg->escan_ioctl_buf)) {
1116118032 WL_ERR(("Ioctl buf alloc failed\n"));
1116218033 goto init_priv_mem_out;
1116318034 }
11164
- cfg->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
18035
+ cfg->extra_buf = (void *)MALLOCZ(cfg->osh, WL_EXTRA_BUF_MAX);
1116518036 if (unlikely(!cfg->extra_buf)) {
1116618037 WL_ERR(("Extra buf alloc failed\n"));
1116718038 goto init_priv_mem_out;
1116818039 }
11169
- cfg->pmk_list = (void *)kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
18040
+ cfg->pmk_list = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->pmk_list));
1117018041 if (unlikely(!cfg->pmk_list)) {
1117118042 WL_ERR(("pmk list alloc failed\n"));
1117218043 goto init_priv_mem_out;
1117318044 }
1117418045 #if defined(STATIC_WL_PRIV_STRUCT)
11175
- cfg->conn_info = (void *)kzalloc(sizeof(*cfg->conn_info), GFP_KERNEL);
18046
+ cfg->conn_info = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->conn_info));
1117618047 if (unlikely(!cfg->conn_info)) {
11177
- WL_ERR(("cfg->conn_info alloc failed\n"));
18048
+ WL_ERR(("cfg->conn_info alloc failed\n"));
1117818049 goto init_priv_mem_out;
1117918050 }
11180
- cfg->ie = (void *)kzalloc(sizeof(*cfg->ie), GFP_KERNEL);
18051
+ cfg->ie = (void *)MALLOC(cfg->osh, sizeof(*cfg->ie));
1118118052 if (unlikely(!cfg->ie)) {
11182
- WL_ERR(("cfg->ie alloc failed\n"));
18053
+ WL_ERR(("cfg->ie alloc failed\n"));
1118318054 goto init_priv_mem_out;
1118418055 }
11185
- wl_init_escan_result_buf(cfg);
18056
+ if (unlikely(wl_init_escan_result_buf(cfg))) {
18057
+ WL_ERR(("Failed to init escan resul buf\n"));
18058
+ goto init_priv_mem_out;
18059
+ }
1118618060 #endif /* STATIC_WL_PRIV_STRUCT */
11187
- cfg->afx_hdl = (void *)kzalloc(sizeof(*cfg->afx_hdl), GFP_KERNEL);
18061
+ cfg->afx_hdl = (void *)MALLOCZ(cfg->osh, sizeof(*cfg->afx_hdl));
1118818062 if (unlikely(!cfg->afx_hdl)) {
11189
- WL_ERR(("afx hdl alloc failed\n"));
18063
+ WL_ERR(("afx hdl alloc failed\n"));
1119018064 goto init_priv_mem_out;
1119118065 } else {
1119218066 init_completion(&cfg->act_frm_scan);
....@@ -11196,8 +18070,9 @@
1119618070 }
1119718071 #ifdef WLTDLS
1119818072 if (cfg->tdls_mgmt_frame) {
11199
- kfree(cfg->tdls_mgmt_frame);
18073
+ MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
1120018074 cfg->tdls_mgmt_frame = NULL;
18075
+ cfg->tdls_mgmt_frame_len = 0;
1120118076 }
1120218077 #endif /* WLTDLS */
1120318078 return 0;
....@@ -11210,31 +18085,21 @@
1121018085
1121118086 static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
1121218087 {
11213
- kfree(cfg->scan_results);
11214
- cfg->scan_results = NULL;
11215
- kfree(cfg->conf);
11216
- cfg->conf = NULL;
11217
- kfree(cfg->scan_req_int);
11218
- cfg->scan_req_int = NULL;
11219
- kfree(cfg->ioctl_buf);
11220
- cfg->ioctl_buf = NULL;
11221
- kfree(cfg->escan_ioctl_buf);
11222
- cfg->escan_ioctl_buf = NULL;
11223
- kfree(cfg->extra_buf);
11224
- cfg->extra_buf = NULL;
11225
- kfree(cfg->pmk_list);
11226
- cfg->pmk_list = NULL;
18088
+ MFREE(cfg->osh, cfg->scan_results, WL_SCAN_BUF_MAX);
18089
+ MFREE(cfg->osh, cfg->conf, sizeof(*cfg->conf));
18090
+ MFREE(cfg->osh, cfg->scan_req_int, sizeof(*cfg->scan_req_int));
18091
+ MFREE(cfg->osh, cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
18092
+ MFREE(cfg->osh, cfg->escan_ioctl_buf, WLC_IOCTL_MAXLEN);
18093
+ MFREE(cfg->osh, cfg->extra_buf, WL_EXTRA_BUF_MAX);
18094
+ MFREE(cfg->osh, cfg->pmk_list, sizeof(*cfg->pmk_list));
1122718095 #if defined(STATIC_WL_PRIV_STRUCT)
11228
- kfree(cfg->conn_info);
11229
- cfg->conn_info = NULL;
11230
- kfree(cfg->ie);
11231
- cfg->ie = NULL;
18096
+ MFREE(cfg->osh, cfg->conn_info, sizeof(*cfg->conn_info));
18097
+ MFREE(cfg->osh, cfg->ie, sizeof(*cfg->ie));
1123218098 wl_deinit_escan_result_buf(cfg);
1123318099 #endif /* STATIC_WL_PRIV_STRUCT */
1123418100 if (cfg->afx_hdl) {
1123518101 cancel_work_sync(&cfg->afx_hdl->work);
11236
- kfree(cfg->afx_hdl);
11237
- cfg->afx_hdl = NULL;
18102
+ MFREE(cfg->osh, cfg->afx_hdl, sizeof(*cfg->afx_hdl));
1123818103 }
1123918104
1124018105 }
....@@ -11244,96 +18109,49 @@
1124418109 int ret = 0;
1124518110 WL_DBG(("Enter \n"));
1124618111
11247
- /* Do not use DHD in cfg driver */
11248
- cfg->event_tsk.thr_pid = -1;
18112
+#ifdef OEM_ANDROID
18113
+ /* Allocate workqueue for event */
18114
+ if (!cfg->event_workq) {
18115
+ cfg->event_workq = alloc_workqueue("dhd_eventd",
18116
+ WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 1);
18117
+ }
1124918118
11250
- PROC_START(wl_event_handler, cfg, &cfg->event_tsk, 0, "wl_event_handler");
11251
- if (cfg->event_tsk.thr_pid < 0)
18119
+ if (!cfg->event_workq) {
1125218120 ret = -ENOMEM;
18121
+ } else {
18122
+ INIT_WORK(&cfg->event_work, wl_event_handler);
18123
+ }
18124
+#else
18125
+ INIT_WORK(&cfg->event_work, wl_event_handler);
18126
+ cfg->event_workq_init = true;
18127
+#endif /* OEM_ANDROID */
1125318128 return ret;
1125418129 }
1125518130
1125618131 static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
1125718132 {
11258
- if (cfg->event_tsk.thr_pid >= 0)
11259
- PROC_STOP(&cfg->event_tsk);
18133
+#ifdef OEM_ANDROID
18134
+ if (cfg && cfg->event_workq) {
18135
+ cancel_work_sync(&cfg->event_work);
18136
+ destroy_workqueue(cfg->event_workq);
18137
+ cfg->event_workq = NULL;
18138
+ }
18139
+#else
18140
+ if (cfg && cfg->event_workq_init) {
18141
+ cancel_work_sync(&cfg->event_work);
18142
+ cfg->event_workq_init = false;
18143
+ }
18144
+#endif /* OEM_ANDROID */
1126018145 }
1126118146
11262
-void wl_terminate_event_handler(void)
18147
+void wl_terminate_event_handler(struct net_device *dev)
1126318148 {
11264
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
18149
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1126518150
1126618151 if (cfg) {
1126718152 wl_destroy_event_handler(cfg);
1126818153 wl_flush_eq(cfg);
1126918154 }
11270
-}
11271
-
11272
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
11273
-static void wl_scan_timeout(struct timer_list *t)
11274
-{
11275
- struct bcm_cfg80211 *cfg = from_timer(cfg, t, scan_timeout);
11276
-#else
11277
-static void wl_scan_timeout(unsigned long data)
11278
-{
11279
- struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
11280
-#endif
11281
- wl_event_msg_t msg;
11282
- struct wireless_dev *wdev = NULL;
11283
- struct net_device *ndev = NULL;
11284
- struct wl_scan_results *bss_list;
11285
- struct wl_bss_info *bi = NULL;
11286
- s32 i;
11287
- u32 channel;
11288
-#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
11289
- dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
11290
- uint32 prev_memdump_mode = dhdp->memdump_enabled;
11291
-#endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
11292
-
11293
- if (!(cfg->scan_request)) {
11294
- WL_ERR(("timer expired but no scan request\n"));
11295
- return;
11296
- }
11297
-
11298
- bss_list = wl_escan_get_buf(cfg, FALSE);
11299
- if (!bss_list) {
11300
- WL_ERR(("bss_list is null. Didn't receive any partial scan results\n"));
11301
- } else {
11302
- WL_ERR(("scanned AP count (%d)\n", bss_list->count));
11303
-
11304
- bi = next_bss(bss_list, bi);
11305
- for_each_bss(bss_list, bi, i) {
11306
- channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
11307
- WL_ERR(("SSID :%s Channel :%d\n", bi->SSID, channel));
11308
- }
11309
- }
11310
-
11311
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
11312
- if (cfg->scan_request->dev)
11313
- wdev = cfg->scan_request->dev->ieee80211_ptr;
11314
-#else
11315
- wdev = cfg->scan_request->wdev;
11316
-#endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
11317
- if (!wdev) {
11318
- WL_ERR(("No wireless_dev present\n"));
11319
- return;
11320
- }
11321
- ndev = wdev_to_wlc_ndev(wdev, cfg);
11322
-
11323
- bzero(&msg, sizeof(wl_event_msg_t));
11324
- WL_ERR(("timer expired\n"));
11325
-#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
11326
- if (dhdp->memdump_enabled) {
11327
- dhdp->memdump_enabled = DUMP_MEMFILE;
11328
- dhdp->memdump_type = DUMP_TYPE_SCAN_TIMEOUT;
11329
- dhd_bus_mem_dump(dhdp);
11330
- dhdp->memdump_enabled = prev_memdump_mode;
11331
- }
11332
-#endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
11333
- msg.event_type = hton32(WLC_E_ESCAN_RESULT);
11334
- msg.status = hton32(WLC_E_STATUS_TIMEOUT);
11335
- msg.reason = 0xFFFFFFFF;
11336
- wl_cfg80211_event(ndev, &msg, NULL);
1133718155 }
1133818156
1133918157 #ifdef DHD_LOSSLESS_ROAMING
....@@ -11349,15 +18167,9 @@
1134918167
1135018168 }
1135118169
11352
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
11353
-static void wl_roam_timeout(struct timer_list *t)
11354
-{
11355
- struct bcm_cfg80211 *cfg = from_timer(cfg, t, wl_roam_timeout);
11356
-#else
1135718170 static void wl_roam_timeout(unsigned long data)
1135818171 {
1135918172 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
11360
-#endif
1136118173 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
1136218174
1136318175 WL_ERR(("roam timer expired\n"));
....@@ -11368,6 +18180,124 @@
1136818180
1136918181 #endif /* DHD_LOSSLESS_ROAMING */
1137018182
18183
+#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
18184
+#define CP_CHAN_INFO_RAT_MODE_LTE 3
18185
+#define CP_CHAN_INFO_RAT_MODE_NR5G 7
18186
+int g_mhs_chan_for_cpcoex = 0;
18187
+
18188
+struct __packed cam_cp_noti_info {
18189
+ u8 rat;
18190
+ u32 band;
18191
+ u32 channel;
18192
+};
18193
+
18194
+int
18195
+wl_cfg80211_send_msg_to_ril()
18196
+{
18197
+ int id, buf = 1;
18198
+
18199
+ id = IPC_SYSTEM_CP_CHANNEL_INFO;
18200
+ dev_ril_bridge_send_msg(id, sizeof(int), &buf);
18201
+ WL_ERR(("[BeyondX] send message to ril.\n"));
18202
+
18203
+ OSL_SLEEP(500);
18204
+ return 0;
18205
+}
18206
+
18207
+int
18208
+wl_cfg80211_ril_bridge_notifier_call(struct notifier_block *nb,
18209
+ unsigned long size, void *buf)
18210
+{
18211
+ struct dev_ril_bridge_msg *msg;
18212
+ struct cam_cp_noti_info *cp_noti_info;
18213
+ static int mhs_channel_for_4g, mhs_channel_for_5g;
18214
+ static int recv_msg_4g, recv_msg_5g;
18215
+
18216
+ WL_ERR(("[BeyondX] receive message from ril.\n"));
18217
+ msg = (struct dev_ril_bridge_msg *)buf;
18218
+
18219
+ if (msg->dev_id == IPC_SYSTEM_CP_CHANNEL_INFO &&
18220
+ msg->data_len <= sizeof(struct cam_cp_noti_info)) {
18221
+ u8 rat;
18222
+ u32 band;
18223
+ u32 channel;
18224
+
18225
+ cp_noti_info = (struct cam_cp_noti_info *)msg->data;
18226
+ rat = cp_noti_info->rat;
18227
+ band = cp_noti_info->band;
18228
+ channel = cp_noti_info->channel;
18229
+
18230
+ /* LTE/5G Band/Freq information => Mobile Hotspot channel mapping.
18231
+ * LTE/B40: 38650~39649 => Ch.11
18232
+ * LTE/B41: 39650~41589 => Ch.1
18233
+ * 5G/N41: 499200~537999 => Ch.1
18234
+ */
18235
+ if (rat == CP_CHAN_INFO_RAT_MODE_LTE) {
18236
+ recv_msg_4g = 1;
18237
+ if (channel >= 38650 && channel <= 39649) {
18238
+ mhs_channel_for_4g = 11;
18239
+ } else if (channel >= 39650 && channel <= 41589) {
18240
+ mhs_channel_for_4g = 1;
18241
+ }
18242
+ }
18243
+ if (rat == CP_CHAN_INFO_RAT_MODE_NR5G) {
18244
+ recv_msg_5g = 1;
18245
+ if (channel >= 499200 && channel <= 537999) {
18246
+ mhs_channel_for_5g = 1;
18247
+ }
18248
+ }
18249
+
18250
+ WL_DBG(("[BeyondX] rat: %u, band: %u, channel: %u, mhs_channel_for_4g: %u, "
18251
+ "mhs_channel_for_5g: %u\n", rat, band, channel,
18252
+ mhs_channel_for_4g, mhs_channel_for_5g));
18253
+
18254
+ if (recv_msg_4g && recv_msg_5g) {
18255
+ if (mhs_channel_for_4g && mhs_channel_for_5g) {
18256
+ /* if 4G/B40 + 5G/N41, select channel 6 for MHS */
18257
+ if (mhs_channel_for_4g == 11 && mhs_channel_for_5g == 1) {
18258
+ g_mhs_chan_for_cpcoex = 6;
18259
+ /* if 4G(except for B40) + 5G/N41, select channel 1 for MHS */
18260
+ } else {
18261
+ g_mhs_chan_for_cpcoex = 1;
18262
+ }
18263
+ } else {
18264
+ g_mhs_chan_for_cpcoex = mhs_channel_for_4g ? mhs_channel_for_4g :
18265
+ mhs_channel_for_5g ? mhs_channel_for_5g : 0;
18266
+ }
18267
+ mhs_channel_for_4g = mhs_channel_for_5g = 0;
18268
+ recv_msg_4g = recv_msg_5g = 0;
18269
+ }
18270
+ }
18271
+
18272
+ return 0;
18273
+}
18274
+
18275
+static struct notifier_block wl_cfg80211_ril_bridge_notifier = {
18276
+ .notifier_call = wl_cfg80211_ril_bridge_notifier_call,
18277
+};
18278
+
18279
+static bool wl_cfg80211_ril_bridge_notifier_registered = FALSE;
18280
+#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
18281
+
18282
+#if !defined(DISALBE_11H) && defined(DHD_NOSCAN_DURING_CSA)
18283
+static void wl_del_csa_timeout(struct bcm_cfg80211 *cfg)
18284
+{
18285
+ if (cfg) {
18286
+ if (timer_pending(&cfg->csa_timeout)) {
18287
+ del_timer_sync(&cfg->csa_timeout);
18288
+ }
18289
+ }
18290
+}
18291
+
18292
+static void wl_csa_timeout(unsigned long data)
18293
+{
18294
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
18295
+
18296
+ if (cfg->in_csa)
18297
+ cfg->in_csa = FALSE;
18298
+}
18299
+#endif /* !defined(DISALBE_11H) && defined(DHD_NOSCAN_DURING_CSA) */
18300
+
1137118301 static s32
1137218302 wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
1137318303 unsigned long state, void *ptr)
....@@ -11377,13 +18307,32 @@
1137718307 #else
1137818308 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1137918309 #endif /* LINUX_VERSION < VERSION(3, 11, 0) */
11380
- struct wireless_dev *wdev = ndev_to_wdev(dev);
11381
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
18310
+ struct wireless_dev *wdev = NULL;
18311
+ struct bcm_cfg80211 *cfg = NULL;
1138218312
11383
- WL_DBG(("Enter \n"));
11384
-
11385
- if (!wdev || !cfg || dev == bcmcfg_to_prmry_ndev(cfg))
18313
+ WL_DBG(("Enter state:%lu ndev%p \n", state, dev));
18314
+ if (!dev) {
18315
+ WL_ERR(("dev null\n"));
1138618316 return NOTIFY_DONE;
18317
+ }
18318
+
18319
+ wdev = ndev_to_wdev(dev);
18320
+ if (!wdev) {
18321
+ WL_ERR(("wdev null. Do nothing\n"));
18322
+ return NOTIFY_DONE;
18323
+ }
18324
+
18325
+ cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
18326
+ if (!cfg || (cfg != wl_cfg80211_get_bcmcfg())) {
18327
+ /* If cfg80211 priv is null or doesn't match return */
18328
+ WL_ERR(("wrong cfg ptr (%p)\n", cfg));
18329
+ return NOTIFY_DONE;
18330
+ }
18331
+
18332
+ if (dev == bcmcfg_to_prmry_ndev(cfg)) {
18333
+ /* Nothing to be done for primary I/F */
18334
+ return NOTIFY_DONE;
18335
+ }
1138718336
1138818337 switch (state) {
1138918338 case NETDEV_DOWN:
....@@ -11422,9 +18371,8 @@
1142218371 break;
1142318372 }
1142418373 case NETDEV_UNREGISTER:
18374
+ wl_cfg80211_clear_per_bss_ies(cfg, wdev);
1142518375 /* after calling list_del_rcu(&wdev->list) */
11426
- wl_cfg80211_clear_per_bss_ies(cfg,
11427
- wl_get_bssidx_by_wdev(cfg, wdev));
1142818376 wl_dealloc_netinfo_by_wdev(cfg, wdev);
1142918377 break;
1143018378 case NETDEV_GOING_DOWN:
....@@ -11435,7 +18383,7 @@
1143518383 * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
1143618384 */
1143718385 if (wl_get_drv_status(cfg, SCANNING, dev))
11438
- wl_notify_escan_complete(cfg, dev, true, true);
18386
+ wl_cfg80211_cancel_scan(cfg);
1143918387 break;
1144018388 }
1144118389 return NOTIFY_DONE;
....@@ -11451,592 +18399,55 @@
1145118399 */
1145218400 static bool wl_cfg80211_netdev_notifier_registered = FALSE;
1145318401
11454
-static void wl_cfg80211_cancel_scan(struct bcm_cfg80211 *cfg)
11455
-{
11456
- struct wireless_dev *wdev = NULL;
11457
- struct net_device *ndev = NULL;
11458
-
11459
- if (!cfg->scan_request)
11460
- return;
11461
-
11462
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
11463
- if (cfg->scan_request->dev)
11464
- wdev = cfg->scan_request->dev->ieee80211_ptr;
11465
-#else
11466
- wdev = cfg->scan_request->wdev;
11467
-#endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
11468
-
11469
- if (!wdev) {
11470
- WL_ERR(("No wireless_dev present\n"));
11471
- return;
11472
- }
11473
-
11474
- ndev = wdev_to_wlc_ndev(wdev, cfg);
11475
- wl_notify_escan_complete(cfg, ndev, true, true);
11476
- WL_ERR(("Scan aborted! \n"));
11477
-}
11478
-
11479
-static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
11480
-{
11481
- wl_scan_params_t *params = NULL;
11482
- s32 params_size = 0;
11483
- s32 err = BCME_OK;
11484
- struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
11485
- if (!in_atomic()) {
11486
- /* Our scan params only need space for 1 channel and 0 ssids */
11487
- params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
11488
- if (params == NULL) {
11489
- WL_ERR(("scan params allocation failed \n"));
11490
- err = -ENOMEM;
11491
- } else {
11492
- /* Do a scan abort to stop the driver's scan engine */
11493
- err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
11494
- if (err < 0) {
11495
- WL_ERR(("scan abort failed \n"));
11496
- }
11497
- kfree(params);
11498
- }
11499
- }
11500
-#ifdef WLTDLS
11501
- if (cfg->tdls_mgmt_frame) {
11502
- kfree(cfg->tdls_mgmt_frame);
11503
- cfg->tdls_mgmt_frame = NULL;
11504
- }
11505
-#endif /* WLTDLS */
11506
-}
11507
-
11508
-static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
11509
- struct net_device *ndev,
11510
- bool aborted, bool fw_abort)
11511
-{
11512
- s32 err = BCME_OK;
11513
- unsigned long flags;
11514
- struct net_device *dev;
11515
-
11516
- WL_DBG(("Enter \n"));
11517
-
11518
- mutex_lock(&cfg->scan_complete);
11519
-
11520
- if (!ndev) {
11521
- WL_ERR(("ndev is null\n"));
11522
- err = BCME_ERROR;
11523
- goto out;
11524
- }
11525
-
11526
- if (cfg->escan_info.ndev != ndev) {
11527
- WL_ERR(("ndev is different %p %p\n", cfg->escan_info.ndev, ndev));
11528
- err = BCME_ERROR;
11529
- goto out;
11530
- }
11531
-
11532
- if (cfg->scan_request) {
11533
- dev = bcmcfg_to_prmry_ndev(cfg);
11534
-#if defined(WL_ENABLE_P2P_IF)
11535
- if (cfg->scan_request->dev != cfg->p2p_net)
11536
- dev = cfg->scan_request->dev;
11537
-#elif defined(WL_CFG80211_P2P_DEV_IF)
11538
- if (cfg->scan_request->wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
11539
- dev = cfg->scan_request->wdev->netdev;
11540
-#endif /* WL_ENABLE_P2P_IF */
11541
- }
11542
- else {
11543
- WL_DBG(("cfg->scan_request is NULL may be internal scan."
11544
- "doing scan_abort for ndev %p primary %p",
11545
- ndev, bcmcfg_to_prmry_ndev(cfg)));
11546
- dev = ndev;
11547
- }
11548
- if (fw_abort && !in_atomic())
11549
- wl_cfg80211_scan_abort(cfg);
11550
- if (timer_pending(&cfg->scan_timeout))
11551
- del_timer_sync(&cfg->scan_timeout);
11552
-#if defined(ESCAN_RESULT_PATCH)
11553
- if (likely(cfg->scan_request)) {
11554
- cfg->bss_list = wl_escan_get_buf(cfg, aborted);
11555
- wl_inform_bss(cfg);
11556
- }
11557
-#endif /* ESCAN_RESULT_PATCH */
11558
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
11559
-#ifdef WL_SCHED_SCAN
11560
- if (cfg->sched_scan_req && !cfg->scan_request) {
11561
- WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n"));
11562
- if (!aborted)
11563
- cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy);
11564
- cfg->sched_scan_running = FALSE;
11565
- cfg->sched_scan_req = NULL;
11566
- }
11567
-#endif /* WL_SCHED_SCAN */
11568
- if (likely(cfg->scan_request)) {
11569
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 8, 0))
11570
- struct cfg80211_scan_info info;
11571
- info.aborted = aborted;
11572
- cfg80211_scan_done(cfg->scan_request, &info);
11573
-#else
11574
- cfg80211_scan_done(cfg->scan_request, aborted);
11575
-#endif
11576
- cfg->scan_request = NULL;
11577
- DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
11578
- }
11579
- if (p2p_is_on(cfg))
11580
- wl_clr_p2p_status(cfg, SCANNING);
11581
- wl_clr_drv_status(cfg, SCANNING, dev);
11582
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
11583
-
11584
-out:
11585
- mutex_unlock(&cfg->scan_complete);
11586
- return err;
11587
-}
11588
-
11589
-#ifdef ESCAN_BUF_OVERFLOW_MGMT
11590
-static void
11591
-wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate)
11592
-{
11593
- int idx;
11594
- for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) {
11595
- int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1;
11596
- if (bss->RSSI < candidate[idx].RSSI) {
11597
- if (len)
11598
- memcpy(&candidate[idx + 1], &candidate[idx],
11599
- sizeof(removal_element_t) * len);
11600
- candidate[idx].RSSI = bss->RSSI;
11601
- candidate[idx].length = bss->length;
11602
- memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN);
11603
- return;
11604
- }
11605
- }
11606
-}
11607
-
11608
-static void
11609
-wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate,
11610
- wl_bss_info_t *bi)
11611
-{
11612
- int idx1, idx2;
11613
- int total_delete_len = 0;
11614
- for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) {
11615
- int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
11616
- wl_bss_info_t *bss = NULL;
11617
- if (candidate[idx1].RSSI >= bi->RSSI)
11618
- continue;
11619
- for (idx2 = 0; idx2 < list->count; idx2++) {
11620
- bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) :
11621
- list->bss_info;
11622
- if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
11623
- candidate[idx1].RSSI == bss->RSSI &&
11624
- candidate[idx1].length == dtoh32(bss->length)) {
11625
- u32 delete_len = dtoh32(bss->length);
11626
- WL_DBG(("delete scan info of " MACDBG " to add new AP\n",
11627
- MAC2STRDBG(bss->BSSID.octet)));
11628
- if (idx2 < list->count -1) {
11629
- memmove((u8 *)bss, (u8 *)bss + delete_len,
11630
- list->buflen - cur_len - delete_len);
11631
- }
11632
- list->buflen -= delete_len;
11633
- list->count--;
11634
- total_delete_len += delete_len;
11635
- /* if delete_len is greater than or equal to result length */
11636
- if (total_delete_len >= bi->length) {
11637
- return;
11638
- }
11639
- break;
11640
- }
11641
- cur_len += dtoh32(bss->length);
11642
- }
11643
- }
11644
-}
11645
-#endif /* ESCAN_BUF_OVERFLOW_MGMT */
11646
-
11647
-static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
11648
- const wl_event_msg_t *e, void *data)
11649
-{
11650
- s32 err = BCME_OK;
11651
- s32 status = ntoh32(e->status);
11652
- wl_bss_info_t *bi;
11653
- wl_escan_result_t *escan_result;
11654
- wl_bss_info_t *bss = NULL;
11655
- wl_scan_results_t *list;
11656
- wifi_p2p_ie_t * p2p_ie;
11657
- struct net_device *ndev = NULL;
11658
- u32 bi_length;
11659
- u32 i;
11660
- u8 *p2p_dev_addr = NULL;
11661
-
11662
- WL_DBG((" enter event type : %d, status : %d \n",
11663
- ntoh32(e->event_type), ntoh32(e->status)));
11664
-
11665
- ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
11666
-
11667
- mutex_lock(&cfg->usr_sync);
11668
- /* P2P SCAN is coming from primary interface */
11669
- if (wl_get_p2p_status(cfg, SCANNING)) {
11670
- if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM))
11671
- ndev = cfg->afx_hdl->dev;
11672
- else
11673
- ndev = cfg->escan_info.ndev;
11674
-
11675
- }
11676
- if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) {
11677
- WL_ERR(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n",
11678
- ndev, wl_get_drv_status(cfg, SCANNING, ndev),
11679
- ntoh32(e->event_type), ntoh32(e->status)));
11680
- goto exit;
11681
- }
11682
- escan_result = (wl_escan_result_t *)data;
11683
-
11684
- if (status == WLC_E_STATUS_PARTIAL) {
11685
- WL_INFORM(("WLC_E_STATUS_PARTIAL \n"));
11686
- DBG_EVENT_LOG(cfg->pub, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND);
11687
- if (!escan_result) {
11688
- WL_ERR(("Invalid escan result (NULL pointer)\n"));
11689
- goto exit;
11690
- }
11691
- if ((dtoh32(escan_result->buflen) > (int)ESCAN_BUF_SIZE) ||
11692
- (dtoh32(escan_result->buflen) < sizeof(wl_escan_result_t))) {
11693
- WL_ERR(("Invalid escan buffer len:%d\n", dtoh32(escan_result->buflen)));
11694
- goto exit;
11695
- }
11696
- if (dtoh16(escan_result->bss_count) != 1) {
11697
- WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
11698
- goto exit;
11699
- }
11700
- bi = escan_result->bss_info;
11701
- if (!bi) {
11702
- WL_ERR(("Invalid escan bss info (NULL pointer)\n"));
11703
- goto exit;
11704
- }
11705
- bi_length = dtoh32(bi->length);
11706
- if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
11707
- WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
11708
- goto exit;
11709
- }
11710
- if (wl_escan_check_sync_id(status, escan_result->sync_id,
11711
- cfg->escan_info.cur_sync_id) < 0)
11712
- goto exit;
11713
-
11714
- if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
11715
- if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
11716
- WL_DBG(("Ignoring IBSS result\n"));
11717
- goto exit;
11718
- }
11719
- }
11720
-
11721
- if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
11722
- p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
11723
- if (p2p_dev_addr && !memcmp(p2p_dev_addr,
11724
- cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) {
11725
- s32 channel = wf_chspec_ctlchan(
11726
- wl_chspec_driver_to_host(bi->chanspec));
11727
-
11728
- if ((channel > MAXCHANNEL) || (channel <= 0))
11729
- channel = WL_INVALID;
11730
- else
11731
- WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found,"
11732
- " channel : %d\n",
11733
- MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet),
11734
- channel));
11735
-
11736
- wl_clr_p2p_status(cfg, SCANNING);
11737
- cfg->afx_hdl->peer_chan = channel;
11738
- complete(&cfg->act_frm_scan);
11739
- goto exit;
11740
- }
11741
-
11742
- } else {
11743
- int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
11744
-#ifdef ESCAN_BUF_OVERFLOW_MGMT
11745
- removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT];
11746
- int remove_lower_rssi = FALSE;
11747
-
11748
- bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT);
11749
-#endif /* ESCAN_BUF_OVERFLOW_MGMT */
11750
-
11751
- list = wl_escan_get_buf(cfg, FALSE);
11752
- if (scan_req_match(cfg)) {
11753
- /* p2p scan && allow only probe response */
11754
- if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) &&
11755
- (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
11756
- goto exit;
11757
- if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset,
11758
- bi->ie_length)) == NULL) {
11759
- WL_ERR(("Couldn't find P2PIE in probe"
11760
- " response/beacon\n"));
11761
- goto exit;
11762
- }
11763
- }
11764
-#ifdef ESCAN_BUF_OVERFLOW_MGMT
11765
- if (bi_length > ESCAN_BUF_SIZE - list->buflen)
11766
- remove_lower_rssi = TRUE;
11767
-#endif /* ESCAN_BUF_OVERFLOW_MGMT */
11768
-
11769
- for (i = 0; i < list->count; i++) {
11770
- bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
11771
- : list->bss_info;
11772
-#ifdef ESCAN_BUF_OVERFLOW_MGMT
11773
- WL_TRACE(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n",
11774
- bss->SSID, MAC2STRDBG(bss->BSSID.octet),
11775
- i, bss->RSSI, list->count));
11776
-
11777
- if (remove_lower_rssi)
11778
- wl_cfg80211_find_removal_candidate(bss, candidate);
11779
-#endif /* ESCAN_BUF_OVERFLOW_MGMT */
11780
-
11781
- if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
11782
- (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec))
11783
- == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) &&
11784
- bi->SSID_len == bss->SSID_len &&
11785
- !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
11786
-
11787
- /* do not allow beacon data to update
11788
- *the data recd from a probe response
11789
- */
11790
- if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) &&
11791
- (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
11792
- goto exit;
11793
-
11794
- WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d"
11795
- " flags 0x%x, new: RSSI %d flags 0x%x\n",
11796
- bss->SSID, MAC2STRDBG(bi->BSSID.octet), i,
11797
- bss->RSSI, bss->flags, bi->RSSI, bi->flags));
11798
-
11799
- if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) ==
11800
- (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) {
11801
- /* preserve max RSSI if the measurements are
11802
- * both on-channel or both off-channel
11803
- */
11804
- WL_SCAN(("%s("MACDBG"), same onchan"
11805
- ", RSSI: prev %d new %d\n",
11806
- bss->SSID, MAC2STRDBG(bi->BSSID.octet),
11807
- bss->RSSI, bi->RSSI));
11808
- bi->RSSI = MAX(bss->RSSI, bi->RSSI);
11809
- } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
11810
- (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) {
11811
- /* preserve the on-channel rssi measurement
11812
- * if the new measurement is off channel
11813
- */
11814
- WL_SCAN(("%s("MACDBG"), prev onchan"
11815
- ", RSSI: prev %d new %d\n",
11816
- bss->SSID, MAC2STRDBG(bi->BSSID.octet),
11817
- bss->RSSI, bi->RSSI));
11818
- bi->RSSI = bss->RSSI;
11819
- bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL;
11820
- }
11821
- if (dtoh32(bss->length) != bi_length) {
11822
- u32 prev_len = dtoh32(bss->length);
11823
-
11824
- WL_SCAN(("bss info replacement"
11825
- " is occured(bcast:%d->probresp%d)\n",
11826
- bss->ie_length, bi->ie_length));
11827
- WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n",
11828
- bss->SSID, MAC2STRDBG(bi->BSSID.octet),
11829
- prev_len, bi_length));
11830
-
11831
- if (list->buflen - prev_len + bi_length
11832
- > ESCAN_BUF_SIZE) {
11833
- WL_ERR(("Buffer is too small: keep the"
11834
- " previous result of this AP\n"));
11835
- /* Only update RSSI */
11836
- bss->RSSI = bi->RSSI;
11837
- bss->flags |= (bi->flags
11838
- & WL_BSS_FLAGS_RSSI_ONCHANNEL);
11839
- goto exit;
11840
- }
11841
-
11842
- if (i < list->count - 1) {
11843
- /* memory copy required by this case only */
11844
- memmove((u8 *)bss + bi_length,
11845
- (u8 *)bss + prev_len,
11846
- list->buflen - cur_len - prev_len);
11847
- }
11848
- list->buflen -= prev_len;
11849
- list->buflen += bi_length;
11850
- }
11851
- list->version = dtoh32(bi->version);
11852
- memcpy((u8 *)bss, (u8 *)bi, bi_length);
11853
- goto exit;
11854
- }
11855
- cur_len += dtoh32(bss->length);
11856
- }
11857
- if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
11858
-#ifdef ESCAN_BUF_OVERFLOW_MGMT
11859
- wl_cfg80211_remove_lowRSSI_info(list, candidate, bi);
11860
- if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
11861
- WL_DBG(("RSSI(" MACDBG ") is too low(%d) to add Buffer\n",
11862
- MAC2STRDBG(bi->BSSID.octet), bi->RSSI));
11863
- goto exit;
11864
- }
11865
-#else
11866
- WL_ERR(("Buffer is too small: ignoring\n"));
11867
- goto exit;
11868
-#endif /* ESCAN_BUF_OVERFLOW_MGMT */
11869
- }
11870
-
11871
- memcpy(&(((char *)list)[list->buflen]), bi, bi_length);
11872
- list->version = dtoh32(bi->version);
11873
- list->buflen += bi_length;
11874
- list->count++;
11875
-
11876
- /*
11877
- * !Broadcast && number of ssid = 1 && number of channels =1
11878
- * means specific scan to association
11879
- */
11880
- if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) {
11881
- WL_ERR(("P2P assoc scan fast aborted.\n"));
11882
- wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false, true);
11883
- goto exit;
11884
- }
11885
- }
11886
- }
11887
- else if (status == WLC_E_STATUS_SUCCESS) {
11888
- cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
11889
- wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id,
11890
- escan_result->sync_id);
11891
-
11892
- if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
11893
- WL_INFORM(("ACTION FRAME SCAN DONE\n"));
11894
- wl_clr_p2p_status(cfg, SCANNING);
11895
- wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
11896
- if (cfg->afx_hdl->peer_chan == WL_INVALID)
11897
- complete(&cfg->act_frm_scan);
11898
- } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
11899
- WL_INFORM(("ESCAN COMPLETED\n"));
11900
- DBG_EVENT_LOG(cfg->pub, WIFI_EVENT_DRIVER_SCAN_COMPLETE);
11901
- cfg->bss_list = wl_escan_get_buf(cfg, FALSE);
11902
- if (!scan_req_match(cfg)) {
11903
- WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n",
11904
- cfg->bss_list->count));
11905
- }
11906
- wl_inform_bss(cfg);
11907
- wl_notify_escan_complete(cfg, ndev, false, false);
11908
- }
11909
- wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT);
11910
- } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) ||
11911
- (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) ||
11912
- (status == WLC_E_STATUS_NEWASSOC)) {
11913
- /* Handle all cases of scan abort */
11914
- cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
11915
- wl_escan_print_sync_id(status, escan_result->sync_id,
11916
- cfg->escan_info.cur_sync_id);
11917
- WL_DBG(("ESCAN ABORT reason: %d\n", status));
11918
- if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
11919
- WL_INFORM(("ACTION FRAME SCAN DONE\n"));
11920
- wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
11921
- wl_clr_p2p_status(cfg, SCANNING);
11922
- if (cfg->afx_hdl->peer_chan == WL_INVALID)
11923
- complete(&cfg->act_frm_scan);
11924
- } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
11925
- WL_INFORM(("ESCAN ABORTED\n"));
11926
- cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
11927
- if (!scan_req_match(cfg)) {
11928
- WL_TRACE_HW4(("scan_req_match=0: scanned AP count=%d\n",
11929
- cfg->bss_list->count));
11930
- }
11931
-
11932
- wl_inform_bss(cfg);
11933
- wl_notify_escan_complete(cfg, ndev, true, false);
11934
- } else {
11935
- /* If there is no pending host initiated scan, do nothing */
11936
- WL_DBG(("ESCAN ABORT: No pending scans. Ignoring event.\n"));
11937
- }
11938
- wl_escan_increment_sync_id(cfg, SCAN_BUF_CNT);
11939
- } else if (status == WLC_E_STATUS_TIMEOUT) {
11940
- WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request));
11941
- WL_ERR(("reason[0x%x]\n", e->reason));
11942
- if (e->reason == 0xFFFFFFFF) {
11943
- wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
11944
- }
11945
- } else {
11946
- WL_ERR(("unexpected Escan Event %d : abort\n", status));
11947
- cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
11948
- wl_escan_print_sync_id(status, escan_result->sync_id,
11949
- cfg->escan_info.cur_sync_id);
11950
- if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
11951
- WL_INFORM(("ACTION FRAME SCAN DONE\n"));
11952
- wl_clr_p2p_status(cfg, SCANNING);
11953
- wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
11954
- if (cfg->afx_hdl->peer_chan == WL_INVALID)
11955
- complete(&cfg->act_frm_scan);
11956
- } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
11957
- cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
11958
- if (!scan_req_match(cfg)) {
11959
- WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): "
11960
- "scanned AP count=%d\n",
11961
- cfg->bss_list->count));
11962
- }
11963
- wl_inform_bss(cfg);
11964
- wl_notify_escan_complete(cfg, ndev, true, false);
11965
- }
11966
- wl_escan_increment_sync_id(cfg, 2);
11967
- }
11968
-exit:
11969
- mutex_unlock(&cfg->usr_sync);
11970
- return err;
11971
-}
11972
-
1197318402 static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
1197418403 {
1197518404 u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
1197618405 bool p2p_connected = wl_cfgp2p_vif_created(cfg);
1197718406 struct net_info *iter, *next;
11978
- int err;
1197918407
1198018408 if (!(cfg->roam_flags & WL_ROAM_OFF_ON_CONCURRENT))
1198118409 return;
1198218410
1198318411 WL_DBG(("roam off:%d p2p_connected:%d connected_cnt:%d \n",
1198418412 enable, p2p_connected, connected_cnt));
11985
-
1198618413 /* Disable FW roam when we have a concurrent P2P connection */
1198718414 if (enable && p2p_connected && connected_cnt > 1) {
18415
+
1198818416 /* Mark it as to be reverted */
11989
- cfg->roam_flags |= WL_ROAM_OFF_REVERT;
11990
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
11991
- 4 && __GNUC_MINOR__ >= 6))
11992
-_Pragma("GCC diagnostic push")
11993
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
11994
-#endif
18417
+ cfg->roam_flags |= WL_ROAM_REVERT_STATUS;
18418
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1199518419 for_each_ndev(cfg, iter, next) {
11996
- if (iter->ndev) {
11997
- /* Save the current roam setting */
11998
- if ((err = wldev_iovar_getint(iter->ndev, "roam_off",
11999
- (s32 *)&iter->roam_off)) != BCME_OK) {
12000
- WL_ERR(("%s:Failed to get current roam setting err %d\n",
12001
- iter->ndev->name, err));
12002
- continue;
18420
+ GCC_DIAGNOSTIC_POP();
18421
+ if (iter->ndev && iter->wdev &&
18422
+ iter->wdev->iftype == NL80211_IFTYPE_STATION) {
18423
+ if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE)
18424
+ == BCME_OK) {
18425
+ iter->roam_off = TRUE;
1200318426 }
12004
- if ((err = wldev_iovar_setint(iter->ndev,
12005
- "roam_off", 1)) != BCME_OK) {
12006
- WL_ERR((" %s:failed to set roam_off : %d\n",
12007
- iter->ndev->name, err));
18427
+ else {
18428
+ WL_ERR(("error to enable roam_off\n"));
1200818429 }
1200918430 }
1201018431 }
12011
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12012
- 4 && __GNUC_MINOR__ >= 6))
12013
-_Pragma("GCC diagnostic pop")
12014
-#endif
1201518432 }
12016
- else if (!enable && (cfg->roam_flags & WL_ROAM_OFF_REVERT)) {
12017
- cfg->roam_flags &= ~WL_ROAM_OFF_REVERT;
12018
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12019
- 4 && __GNUC_MINOR__ >= 6))
12020
-_Pragma("GCC diagnostic push")
12021
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
12022
-#endif
18433
+ else if (!enable && (cfg->roam_flags & WL_ROAM_REVERT_STATUS)) {
18434
+ cfg->roam_flags &= ~WL_ROAM_REVERT_STATUS;
18435
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1202318436 for_each_ndev(cfg, iter, next) {
12024
- if (iter->ndev) {
18437
+ GCC_DIAGNOSTIC_POP();
18438
+ if (iter->ndev && iter->wdev &&
18439
+ iter->wdev->iftype == NL80211_IFTYPE_STATION) {
1202518440 if (iter->roam_off != WL_INVALID) {
12026
- if ((err = wldev_iovar_setint(iter->ndev, "roam_off",
12027
- iter->roam_off)) == BCME_OK)
12028
- iter->roam_off = WL_INVALID;
18441
+ if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE)
18442
+ == BCME_OK) {
18443
+ iter->roam_off = FALSE;
18444
+ }
1202918445 else {
12030
- WL_ERR((" %s:failed to set roam_off : %d\n",
12031
- iter->ndev->name, err));
18446
+ WL_ERR(("error to disable roam_off\n"));
1203218447 }
1203318448 }
1203418449 }
1203518450 }
12036
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12037
- 4 && __GNUC_MINOR__ >= 6))
12038
-_Pragma("GCC diagnostic pop")
12039
-#endif
1204018451 }
1204118452
1204218453 return;
....@@ -12054,12 +18465,9 @@
1205418465 if (connected_cnt <= 1) {
1205518466 return;
1205618467 }
12057
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12058
- 4 && __GNUC_MINOR__ >= 6))
12059
-_Pragma("GCC diagnostic push")
12060
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
12061
-#endif
18468
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1206218469 for_each_ndev(cfg, iter, next) {
18470
+ GCC_DIAGNOSTIC_POP();
1206318471 /* p2p discovery iface ndev could be null */
1206418472 if (iter->ndev) {
1206518473 chanspec = 0;
....@@ -12082,14 +18490,52 @@
1208218490 }
1208318491 }
1208418492 }
12085
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12086
- 4 && __GNUC_MINOR__ >= 6))
12087
-_Pragma("GCC diagnostic pop")
12088
-#endif
1208918493 WL_ERR(("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel"));
1209018494 return;
1209118495 }
1209218496
18497
+int
18498
+wl_cfg80211_determine_p2p_rsdb_mode(struct bcm_cfg80211 *cfg)
18499
+{
18500
+ struct net_info *iter, *next;
18501
+ u32 chanspec = 0;
18502
+ u32 band = 0;
18503
+ u32 pre_band = 0;
18504
+ bool is_rsdb_supported = FALSE;
18505
+ bool rsdb_mode = FALSE;
18506
+
18507
+ is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
18508
+
18509
+ if (!is_rsdb_supported) {
18510
+ return 0;
18511
+ }
18512
+
18513
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
18514
+ for_each_ndev(cfg, iter, next) {
18515
+ GCC_DIAGNOSTIC_POP();
18516
+ /* p2p discovery iface ndev could be null */
18517
+ if (iter->ndev) {
18518
+ chanspec = 0;
18519
+ band = 0;
18520
+ if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
18521
+ if (wldev_iovar_getint(iter->ndev, "chanspec",
18522
+ (s32 *)&chanspec) == BCME_OK) {
18523
+ chanspec = wl_chspec_driver_to_host(chanspec);
18524
+ band = CHSPEC_BAND(chanspec);
18525
+ }
18526
+
18527
+ if (!pre_band && band) {
18528
+ pre_band = band;
18529
+ } else if (pre_band && (pre_band != band)) {
18530
+ rsdb_mode = TRUE;
18531
+ }
18532
+ }
18533
+ }
18534
+ }
18535
+ WL_DBG(("RSDB mode is %s\n", rsdb_mode ? "enabled" : "disabled"));
18536
+
18537
+ return rsdb_mode;
18538
+}
1209318539
1209418540 static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
1209518541 enum wl_status state, bool set)
....@@ -12098,11 +18544,13 @@
1209818544 s32 err = BCME_OK;
1209918545 u32 mode;
1210018546 u32 chan = 0;
12101
- struct net_info *iter, *next;
1210218547 struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
12103
- dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
18548
+ dhd_pub_t *dhd = cfg->pub;
18549
+#ifdef RTT_SUPPORT
18550
+ rtt_status_info_t *rtt_status;
18551
+#endif /* RTT_SUPPORT */
1210418552 if (dhd->busstate == DHD_BUS_DOWN) {
12105
- WL_ERR(("%s : busstate is DHD_BUS_DOWN!\n", __FUNCTION__));
18553
+ WL_ERR(("busstate is DHD_BUS_DOWN!\n"));
1210618554 return 0;
1210718555 }
1210818556 WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
....@@ -12113,208 +18561,89 @@
1211318561 mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
1211418562 if (set) {
1211518563 wl_cfg80211_concurrent_roam(cfg, 1);
12116
-
18564
+ wl_cfg80211_determine_vsdb_mode(cfg);
1211718565 if (mode == WL_MODE_AP) {
12118
-
1211918566 if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
1212018567 WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
1212118568 }
12122
- wl_cfg80211_determine_vsdb_mode(cfg);
12123
- if (cfg->vsdb_mode || _net_info->pm_block) {
12124
- /* Delete pm_enable_work */
12125
- wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_MAINTAIN);
12126
- /* save PM_FAST in _net_info to restore this
12127
- * if _net_info->pm_block is false
12128
- */
12129
- if (!_net_info->pm_block && (mode == WL_MODE_BSS)) {
12130
- _net_info->pm = PM_FAST;
12131
- _net_info->pm_restore = true;
12132
- }
12133
- pm = PM_OFF;
12134
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12135
- 4 && __GNUC_MINOR__ >= 6))
12136
-_Pragma("GCC diagnostic push")
12137
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
12138
-#endif
12139
- for_each_ndev(cfg, iter, next) {
12140
- if (iter->pm_restore || (iter->ndev == NULL))
12141
- continue;
12142
- /* Save the current power mode */
12143
- err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm,
12144
- sizeof(iter->pm), false);
12145
- WL_DBG(("%s:power save %s\n", iter->ndev->name,
12146
- iter->pm ? "enabled" : "disabled"));
12147
- if (!err && iter->pm) {
12148
- iter->pm_restore = true;
12149
- }
12150
- }
12151
- for_each_ndev(cfg, iter, next) {
12152
- if (iter->ndev) {
12153
- if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
12154
- continue;
12155
- if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
12156
- sizeof(pm), true)) != 0) {
12157
- if (err == -ENODEV)
12158
- WL_DBG(("%s:netdev not ready\n",
12159
- iter->ndev->name));
12160
- else
12161
- WL_ERR(("%s:error (%d)\n",
12162
- iter->ndev->name, err));
12163
- wl_cfg80211_update_power_mode(iter->ndev);
12164
- }
12165
- }
12166
- }
12167
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12168
- 4 && __GNUC_MINOR__ >= 6))
12169
-_Pragma("GCC diagnostic pop")
12170
-#endif
12171
- } else {
12172
- /* add PM Enable timer to go to power save mode
12173
- * if supplicant control pm mode, it will be cleared or
12174
- * updated by wl_cfg80211_set_power_mgmt() if not - for static IP & HW4 P2P,
12175
- * PM will be configured when timer expired
12176
- */
18569
+ pm = PM_OFF;
18570
+ if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
18571
+ sizeof(pm))) != 0) {
18572
+ if (err == -ENODEV)
18573
+ WL_DBG(("%s:netdev not ready\n",
18574
+ _net_info->ndev->name));
18575
+ else
18576
+ WL_ERR(("%s:error (%d)\n",
18577
+ _net_info->ndev->name, err));
1217718578
12178
- /*
12179
- * before calling pm_enable_timer, we need to set PM -1 for all ndev
12180
- */
12181
- pm = PM_OFF;
12182
- if (!_net_info->pm_block) {
12183
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12184
- 4 && __GNUC_MINOR__ >= 6))
12185
-_Pragma("GCC diagnostic push")
12186
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
12187
-#endif
12188
- for_each_ndev(cfg, iter, next) {
12189
- if (iter->pm_restore || (iter->ndev == NULL))
12190
- continue;
12191
- /* Save the current power mode */
12192
- err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm,
12193
- sizeof(iter->pm), false);
12194
- WL_DBG(("%s:power save %s\n", iter->ndev->name,
12195
- iter->pm ? "enabled" : "disabled"));
12196
- if (!err && iter->pm) {
12197
- iter->pm_restore = true;
12198
- }
12199
- }
12200
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12201
- 4 && __GNUC_MINOR__ >= 6))
12202
-_Pragma("GCC diagnostic pop")
12203
-#endif
12204
- }
12205
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12206
- 4 && __GNUC_MINOR__ >= 6))
12207
-_Pragma("GCC diagnostic push")
12208
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
12209
-#endif
12210
- for_each_ndev(cfg, iter, next) {
12211
- /* p2p discovery iface ndev ptr could be null */
12212
- if (iter->ndev) {
12213
- if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
12214
- continue;
12215
- if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
12216
- sizeof(pm), true)) != 0) {
12217
- if (err == -ENODEV)
12218
- WL_DBG(("%s:netdev not ready\n",
12219
- iter->ndev->name));
12220
- else
12221
- WL_ERR(("%s:error (%d)\n",
12222
- iter->ndev->name, err));
12223
- }
12224
- }
12225
- }
12226
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12227
- 4 && __GNUC_MINOR__ >= 6))
12228
-_Pragma("GCC diagnostic pop")
12229
-#endif
12230
- if (cfg->pm_enable_work_on) {
12231
- wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
12232
- }
12233
-
12234
- cfg->pm_enable_work_on = true;
12235
-#ifdef BCMSDIO
12236
- /* Temporary WAR: disable PM work till PM is fixed in 43012 */
12237
- if (dhd_get_chipid(dhd) != BCM43012_CHIP_ID)
12238
-#endif
12239
- wl_add_remove_pm_enable_work(cfg, TRUE, WL_HANDLER_NOTUSE);
12240
-
18579
+ wl_cfg80211_update_power_mode(_net_info->ndev);
1224118580 }
18581
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
1224218582 #if defined(WLTDLS)
12243
-#if defined(DISABLE_TDLS_IN_P2P)
12244
- if (cfg->vsdb_mode || p2p_is_on(cfg))
12245
-#else
12246
- if (cfg->vsdb_mode)
12247
-#endif /* defined(DISABLE_TDLS_IN_P2P) */
12248
- {
12249
-
18583
+ if (wl_cfg80211_is_concurrent_mode(primary_dev)) {
1225018584 err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
1225118585 }
1225218586 #endif /* defined(WLTDLS) */
1225318587
12254
- }
12255
- else { /* clear */
18588
+#ifdef DISABLE_FRAMEBURST_VSDB
18589
+ if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE) &&
18590
+ wl_cfg80211_is_concurrent_mode(primary_dev) &&
18591
+ !wl_cfg80211_determine_p2p_rsdb_mode(cfg)) {
18592
+ wl_cfg80211_set_frameburst(cfg, FALSE);
18593
+ }
18594
+#endif /* DISABLE_FRAMEBURST_VSDB */
18595
+#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18596
+ if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
18597
+ wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
18598
+ /* Enable frameburst for
18599
+ * STA/SoftAP concurrent mode
18600
+ */
18601
+ wl_cfg80211_set_frameburst(cfg, TRUE);
18602
+ }
18603
+#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
18604
+ } else { /* clear */
1225618605 chan = 0;
1225718606 /* clear chan information when the net device is disconnected */
1225818607 wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
1225918608 wl_cfg80211_determine_vsdb_mode(cfg);
12260
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12261
- 4 && __GNUC_MINOR__ >= 6))
12262
-_Pragma("GCC diagnostic push")
12263
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
12264
-#endif
12265
- for_each_ndev(cfg, iter, next) {
12266
- /* P2P discovery interface ndev ptr could be NULL */
12267
- if (iter->ndev) {
12268
- if (iter->pm_restore && iter->pm) {
12269
- WL_DBG(("%s:restoring power save %s\n", iter->ndev->name,
12270
- (iter->pm ? "enabled" : "disabled")));
12271
- err = wldev_ioctl(iter->ndev,
12272
- WLC_SET_PM, &iter->pm, sizeof(iter->pm), true);
12273
- if (unlikely(err)) {
12274
- if (err == -ENODEV)
12275
- WL_DBG(("%s:netdev not ready\n",
12276
- iter->ndev->name));
12277
- else
12278
- WL_ERR(("%s:error(%d)\n",
12279
- iter->ndev->name, err));
12280
- break;
12281
- }
12282
- iter->pm_restore = 0;
12283
- wl_cfg80211_update_power_mode(iter->ndev);
18609
+ if (primary_dev == _net_info->ndev) {
18610
+ pm = PM_FAST;
18611
+#ifdef RTT_SUPPORT
18612
+ rtt_status = GET_RTTSTATE(dhd);
18613
+ if (rtt_status->status != RTT_ENABLED)
18614
+#endif /* RTT_SUPPORT */
18615
+ if ((err = wldev_ioctl_set(_net_info->ndev, WLC_SET_PM, &pm,
18616
+ sizeof(pm))) != 0) {
18617
+ if (err == -ENODEV)
18618
+ WL_DBG(("%s:netdev not ready\n",
18619
+ _net_info->ndev->name));
18620
+ else
18621
+ WL_ERR(("%s:error (%d)\n",
18622
+ _net_info->ndev->name, err));
18623
+
18624
+ wl_cfg80211_update_power_mode(_net_info->ndev);
1228418625 }
12285
- }
1228618626 }
12287
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
12288
- 4 && __GNUC_MINOR__ >= 6))
12289
-_Pragma("GCC diagnostic pop")
12290
-#endif
1229118627 wl_cfg80211_concurrent_roam(cfg, 0);
1229218628 #if defined(WLTDLS)
12293
- if (!cfg->vsdb_mode) {
18629
+ if (!wl_cfg80211_is_concurrent_mode(primary_dev)) {
1229418630 err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
1229518631 }
1229618632 #endif /* defined(WLTDLS) */
1229718633
18634
+#if defined(DISABLE_FRAMEBURST_VSDB)
18635
+ if (!DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_HOSTAP_MODE)) {
18636
+ wl_cfg80211_set_frameburst(cfg, TRUE);
18637
+ }
18638
+#endif /* DISABLE_FRAMEBURST_VSDB */
18639
+#ifdef DISABLE_WL_FRAMEBURST_SOFTAP
18640
+ if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhd) &&
18641
+ (cfg->ap_oper_channel <= CH_MAX_2G_CHANNEL)) {
18642
+ /* Disable frameburst for stand-alone 2GHz SoftAP */
18643
+ wl_cfg80211_set_frameburst(cfg, FALSE);
18644
+ }
18645
+#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */
1229818646 }
12299
- return err;
12300
-}
12301
-static s32 wl_init_scan(struct bcm_cfg80211 *cfg)
12302
-{
12303
- int err = 0;
12304
-
12305
- cfg->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler;
12306
- cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
12307
- wl_escan_init_sync_id(cfg);
12308
-
12309
- /* Init scan_timeout timer */
12310
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
12311
- timer_setup(&cfg->scan_timeout, wl_scan_timeout, 0);
12312
-#else
12313
- init_timer(&cfg->scan_timeout);
12314
- cfg->scan_timeout.data = (unsigned long) cfg;
12315
- cfg->scan_timeout.function = wl_scan_timeout;
12316
-#endif
12317
-
1231818647 return err;
1231918648 }
1232018649
....@@ -12324,17 +18653,20 @@
1232418653 int err = 0;
1232518654
1232618655 /* Init roam timer */
12327
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
12328
- timer_setup(&cfg->roam_timeout, wl_roam_timeout, 0);
12329
-#else
12330
- init_timer(&cfg->roam_timeout);
12331
- cfg->roam_timeout.data = (unsigned long) cfg;
12332
- cfg->roam_timeout.function = wl_roam_timeout;
12333
-#endif
18656
+ init_timer_compat(&cfg->roam_timeout, wl_roam_timeout, cfg);
1233418657
1233518658 return err;
1233618659 }
1233718660 #endif /* DHD_LOSSLESS_ROAMING */
18661
+
18662
+#if !defined(DISABLE_11H) && defined(DHD_NOSCAN_DURING_CSA)
18663
+static s32 wl_init_csa_timeout(struct bcm_cfg80211 *cfg)
18664
+{
18665
+ /* Init csa timer */
18666
+ init_timer_compat(&cfg->csa_timeout, wl_csa_timeout, cfg);
18667
+ return 0;
18668
+}
18669
+#endif /* !defined(DISABLE_11H) && defined(DHD_NOSCAN_DURING_CSA) */
1233818670
1233918671 static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
1234018672 {
....@@ -12344,16 +18676,19 @@
1234418676
1234518677 cfg->scan_request = NULL;
1234618678 cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
18679
+#ifdef DISABLE_BUILTIN_ROAM
1234718680 cfg->roam_on = false;
18681
+#else
18682
+ cfg->roam_on = true;
18683
+#endif /* DISABLE_BUILTIN_ROAM */
1234818684 cfg->active_scan = true;
1234918685 cfg->rf_blocked = false;
1235018686 cfg->vsdb_mode = false;
12351
-#if defined(BCMSDIO) || defined(BCMDBUS)
18687
+#if defined(BCMSDIO)
1235218688 cfg->wlfc_on = false;
12353
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
18689
+#endif /* defined(BCMSDIO) */
1235418690 cfg->roam_flags |= WL_ROAM_OFF_ON_CONCURRENT;
1235518691 cfg->disable_roam_event = false;
12356
- cfg->cfgdev_bssidx = -1;
1235718692 /* register interested state */
1235818693 set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
1235918694 spin_lock_init(&cfg->cfgdrv_lock);
....@@ -12370,7 +18705,17 @@
1237018705 wl_init_event_handler(cfg);
1237118706 mutex_init(&cfg->usr_sync);
1237218707 mutex_init(&cfg->event_sync);
12373
- mutex_init(&cfg->scan_complete);
18708
+ mutex_init(&cfg->if_sync);
18709
+ mutex_init(&cfg->scan_sync);
18710
+#ifdef WLTDLS
18711
+ mutex_init(&cfg->tdls_sync);
18712
+#endif /* WLTDLS */
18713
+#ifdef WL_BCNRECV
18714
+ mutex_init(&cfg->bcn_sync);
18715
+#endif /* WL_BCNRECV */
18716
+#ifdef WL_WPS_SYNC
18717
+ wl_init_wps_reauth_sm(cfg);
18718
+#endif /* WL_WPS_SYNC */
1237418719 err = wl_init_scan(cfg);
1237518720 if (err)
1237618721 return err;
....@@ -12380,11 +18725,23 @@
1238018725 return err;
1238118726 }
1238218727 #endif /* DHD_LOSSLESS_ROAMING */
18728
+#if !defined(DISABLE_11H) && defined(DHD_NOSCAN_DURING_CSA)
18729
+ err = wl_init_csa_timeout(cfg);
18730
+ if (err) {
18731
+ return err;
18732
+ }
18733
+#endif // endif
1238318734 wl_init_conf(cfg->conf);
1238418735 wl_init_prof(cfg, ndev);
1238518736 wl_link_down(cfg);
1238618737 DNGL_FUNC(dhd_cfg80211_init, (cfg));
12387
-
18738
+#ifdef WL_NAN
18739
+ cfg->nan_dp_state = NAN_DP_STATE_DISABLED;
18740
+ init_waitqueue_head(&cfg->ndp_if_change_event);
18741
+#endif /* WL_NAN */
18742
+ cfg->pmk_list->pmkids.length = OFFSETOF(pmkid_list_v3_t, pmkid);
18743
+ cfg->pmk_list->pmkids.count = 0;
18744
+ cfg->pmk_list->pmkids.version = PMKID_LIST_VER_3;
1238818745 return err;
1238918746 }
1239018747
....@@ -12397,7 +18754,10 @@
1239718754 del_timer_sync(&cfg->scan_timeout);
1239818755 #ifdef DHD_LOSSLESS_ROAMING
1239918756 del_timer_sync(&cfg->roam_timeout);
12400
-#endif
18757
+#endif // endif
18758
+#if !defined(DISABLE_11H) && defined(DHD_NOSCAN_DURING_CSA)
18759
+ del_timer_sync(&cfg->csa_timeout);
18760
+#endif // endif
1240118761 wl_deinit_priv_mem(cfg);
1240218762 if (wl_cfg80211_netdev_notifier_registered) {
1240318763 wl_cfg80211_netdev_notifier_registered = FALSE;
....@@ -12405,11 +18765,9 @@
1240518765 }
1240618766 }
1240718767
12408
-#if defined(WL_ENABLE_P2P_IF)
12409
-static s32 wl_cfg80211_attach_p2p(void)
18768
+#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18769
+static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
1241018770 {
12411
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
12412
-
1241318771 WL_TRACE(("Enter \n"));
1241418772
1241518773 if (wl_cfgp2p_register_ndev(cfg) < 0) {
....@@ -12420,37 +18778,43 @@
1242018778 return 0;
1242118779 }
1242218780
12423
-static s32 wl_cfg80211_detach_p2p(void)
18781
+static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
1242418782 {
12425
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
18783
+#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
1242618784 struct wireless_dev *wdev;
18785
+#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
1242718786
1242818787 WL_DBG(("Enter \n"));
1242918788 if (!cfg) {
1243018789 WL_ERR(("Invalid Ptr\n"));
1243118790 return -EINVAL;
12432
- } else
12433
- wdev = cfg->p2p_wdev;
12434
-
12435
- if (!wdev) {
12436
- WL_ERR(("Invalid Ptr\n"));
12437
- return -EINVAL;
1243818791 }
18792
+#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
18793
+ else {
18794
+ wdev = cfg->p2p_wdev;
18795
+ if (!wdev) {
18796
+ WL_ERR(("Invalid Ptr\n"));
18797
+ return -EINVAL;
18798
+ }
18799
+ }
18800
+#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
1243918801
1244018802 wl_cfgp2p_unregister_ndev(cfg);
1244118803
1244218804 cfg->p2p_wdev = NULL;
1244318805 cfg->p2p_net = NULL;
18806
+#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
1244418807 WL_DBG(("Freeing 0x%p \n", wdev));
12445
- kfree(wdev);
18808
+ MFREE(cfg->osh, wdev, sizeof(*wdev));
18809
+#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
1244618810
1244718811 return 0;
1244818812 }
12449
-#endif
18813
+#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
1245018814
12451
-s32 wl_cfg80211_attach_post(struct net_device *ndev)
18815
+static s32 wl_cfg80211_attach_post(struct net_device *ndev)
1245218816 {
12453
- struct bcm_cfg80211 * cfg = NULL;
18817
+ struct bcm_cfg80211 * cfg;
1245418818 s32 err = 0;
1245518819 s32 ret = 0;
1245618820 WL_TRACE(("In\n"));
....@@ -12458,7 +18822,7 @@
1245818822 WL_ERR(("ndev is invaild\n"));
1245918823 return -ENODEV;
1246018824 }
12461
- cfg = g_bcm_cfg;
18825
+ cfg = wl_get_cfg(ndev);
1246218826 if (unlikely(!cfg)) {
1246318827 WL_ERR(("cfg is invaild\n"));
1246418828 return -EINVAL;
....@@ -12505,12 +18869,52 @@
1250518869 return err;
1250618870 }
1250718871
18872
+struct bcm_cfg80211 *wl_get_cfg(struct net_device *ndev)
18873
+{
18874
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
18875
+
18876
+ if (!wdev)
18877
+ return NULL;
18878
+
18879
+ return wiphy_priv(wdev->wiphy);
18880
+}
18881
+
18882
+s32
18883
+wl_cfg80211_net_attach(struct net_device *primary_ndev)
18884
+{
18885
+ struct bcm_cfg80211 *cfg = wl_get_cfg(primary_ndev);
18886
+
18887
+#ifdef WL_STATIC_IF
18888
+ char iname[STATIC_INAME_STRING_LEN];
18889
+ int i = 0;
18890
+#endif /* WL_STATIC_IF */
18891
+ if (!cfg) {
18892
+ WL_ERR(("cfg null\n"));
18893
+ return BCME_ERROR;
18894
+ }
18895
+#ifdef WL_STATIC_IF
18896
+ /* Register dummy n/w iface. FW init will happen only from dev_open */
18897
+ for (i = 0; i < DHD_NUM_STATIC_IFACES; i++) {
18898
+ snprintf(iname, sizeof(iname), WL_STATIC_IFNAME_PREFIX, i+1);
18899
+ if (wl_cfg80211_register_static_if(cfg, NL80211_IFTYPE_STATION,
18900
+ iname, (DHD_MAX_IFS + i)) == NULL) {
18901
+ WL_ERR(("static i/f registration failed!\n"));
18902
+ return BCME_ERROR;
18903
+ }
18904
+ }
18905
+#endif /* WL_STATIC_IF */
18906
+ return BCME_OK;
18907
+}
18908
+
1250818909 s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
1250918910 {
1251018911 struct wireless_dev *wdev;
1251118912 struct bcm_cfg80211 *cfg;
1251218913 s32 err = 0;
1251318914 struct device *dev;
18915
+ u16 bssidx = 0;
18916
+ u16 ifidx = 0;
18917
+ dhd_pub_t *dhd = (struct dhd_pub *)(context);
1251418918
1251518919 WL_TRACE(("In\n"));
1251618920 if (!ndev) {
....@@ -12520,27 +18924,33 @@
1252018924 WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
1252118925 dev = wl_cfg80211_get_parent_dev();
1252218926
12523
- wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
18927
+ wdev = (struct wireless_dev *)MALLOCZ(dhd->osh, sizeof(*wdev));
1252418928 if (unlikely(!wdev)) {
1252518929 WL_ERR(("Could not allocate wireless device\n"));
1252618930 return -ENOMEM;
1252718931 }
1252818932 err = wl_setup_wiphy(wdev, dev, context);
1252918933 if (unlikely(err)) {
12530
- kfree(wdev);
18934
+ MFREE(dhd->osh, wdev, sizeof(*wdev));
1253118935 return -ENOMEM;
1253218936 }
1253318937 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
12534
- cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
18938
+ cfg = wiphy_priv(wdev->wiphy);
1253518939 cfg->wdev = wdev;
1253618940 cfg->pub = context;
18941
+ cfg->osh = dhd->osh;
1253718942 INIT_LIST_HEAD(&cfg->net_list);
18943
+#ifdef WBTEXT
18944
+ INIT_LIST_HEAD(&cfg->wbtext_bssid_list);
18945
+#endif /* WBTEXT */
18946
+ INIT_LIST_HEAD(&cfg->vndr_oui_list);
18947
+ spin_lock_init(&cfg->vndr_oui_sync);
1253818948 spin_lock_init(&cfg->net_list_sync);
1253918949 ndev->ieee80211_ptr = wdev;
1254018950 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
1254118951 wdev->netdev = ndev;
1254218952 cfg->state_notifier = wl_notifier_change_state;
12543
- err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE, 0);
18953
+ err = wl_alloc_netinfo(cfg, ndev, wdev, WL_IF_TYPE_STA, PM_ENABLE, bssidx, ifidx);
1254418954 if (err) {
1254518955 WL_ERR(("Failed to alloc net_info (%d)\n", err));
1254618956 goto cfg80211_attach_out;
....@@ -12562,7 +18972,7 @@
1256218972 WL_ERR(("Failed to setup debugfs %d\n", err));
1256318973 goto cfg80211_attach_out;
1256418974 }
12565
-#endif
18975
+#endif // endif
1256618976 if (!wl_cfg80211_netdev_notifier_registered) {
1256718977 wl_cfg80211_netdev_notifier_registered = TRUE;
1256818978 err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
....@@ -12572,23 +18982,38 @@
1257218982 goto cfg80211_attach_out;
1257318983 }
1257418984 }
12575
-#if defined(COEX_DHCP)
18985
+#if defined(OEM_ANDROID) && defined(COEX_DHCP)
1257618986 cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
1257718987 if (!cfg->btcoex_info)
1257818988 goto cfg80211_attach_out;
12579
-#endif
18989
+#endif /* defined(OEM_ANDROID) && defined(COEX_DHCP) */
18990
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
18991
+ cfg->random_mac_enabled = FALSE;
18992
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
1258018993
12581
- g_bcm_cfg = cfg;
12582
-
12583
-#ifdef CONFIG_CFG80211_INTERNAL_REGDB
12584
- wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
12585
-#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
12586
-
12587
-#if defined(WL_ENABLE_P2P_IF)
12588
- err = wl_cfg80211_attach_p2p();
18994
+#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
18995
+ err = wl_cfg80211_attach_p2p(cfg);
1258918996 if (err)
1259018997 goto cfg80211_attach_out;
12591
-#endif
18998
+#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
18999
+
19000
+ INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
19001
+ mutex_init(&cfg->pm_sync);
19002
+#ifdef WL_NAN
19003
+ mutex_init(&cfg->nancfg.nan_sync);
19004
+ init_waitqueue_head(&cfg->nancfg.nan_event_wait);
19005
+#endif /* WL_NAN */
19006
+ cfg->rssi_sum_report = FALSE;
19007
+#ifdef WL_BAM
19008
+ wl_bad_ap_mngr_init(cfg);
19009
+#endif /* WL_BAM */
19010
+#ifdef BIGDATA_SOFTAP
19011
+ wl_attach_ap_stainfo(cfg);
19012
+#endif /* BIGDATA_SOFTAP */
19013
+#ifdef ENABLE_HOGSQS
19014
+ INIT_DELAYED_WORK(&cfg->hogsqs_eventwork,
19015
+ wl_cfg80211_hogsqs_event_handler);
19016
+#endif // endif
1259219017
1259319018 return err;
1259419019
....@@ -12598,31 +19023,36 @@
1259819023 return err;
1259919024 }
1260019025
12601
-void wl_cfg80211_detach(void *para)
19026
+void wl_cfg80211_detach(struct bcm_cfg80211 *cfg)
1260219027 {
12603
- struct bcm_cfg80211 *cfg;
19028
+ WL_DBG(("Enter\n"));
19029
+ if (!cfg) {
19030
+ return;
19031
+ }
19032
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
1260419033
12605
- (void)para;
12606
- cfg = g_bcm_cfg;
19034
+#ifdef ENABLE_HOGSQS
19035
+ cancel_delayed_work_sync(&cfg->hogsqs_eventwork);
19036
+#endif // endif
1260719037
12608
- WL_TRACE(("In\n"));
12609
-
12610
- wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
12611
-
12612
-#if defined(COEX_DHCP)
19038
+#if defined(OEM_ANDROID) && defined(COEX_DHCP)
1261319039 wl_cfg80211_btcoex_deinit();
1261419040 cfg->btcoex_info = NULL;
12615
-#endif
19041
+#endif /* defined(OEM_ANDROID) && defined(COEX_DHCP) */
1261619042
1261719043 wl_setup_rfkill(cfg, FALSE);
1261819044 #ifdef DEBUGFS_CFG80211
1261919045 wl_free_debugfs(cfg);
12620
-#endif
19046
+#endif // endif
1262119047 if (cfg->p2p_supported) {
1262219048 if (timer_pending(&cfg->p2p->listen_timer))
1262319049 del_timer_sync(&cfg->p2p->listen_timer);
1262419050 wl_cfgp2p_deinit_priv(cfg);
1262519051 }
19052
+
19053
+#ifdef WL_WPS_SYNC
19054
+ wl_deinit_wps_reauth_sm(cfg);
19055
+#endif /* WL_WPS_SYNC */
1262619056
1262719057 if (timer_pending(&cfg->scan_timeout))
1262819058 del_timer_sync(&cfg->scan_timeout);
....@@ -12632,122 +19062,244 @@
1263219062 }
1263319063 #endif /* DHD_LOSSLESS_ROAMING */
1263419064
19065
+#ifdef WL_STATIC_IF
19066
+ wl_cfg80211_unregister_static_if(cfg);
19067
+#endif /* WL_STATIC_IF */
19068
+#if !defined(DISABLE_11H) && defined(DHD_NOSCAN_DURING_CSA)
19069
+ if (timer_pending(&cfg->csa_timeout)) {
19070
+ del_timer_sync(&cfg->csa_timeout);
19071
+ }
19072
+#endif // endif
1263519073 #if defined(WL_CFG80211_P2P_DEV_IF)
1263619074 if (cfg->p2p_wdev)
1263719075 wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
1263819076 #endif /* WL_CFG80211_P2P_DEV_IF */
12639
-#if defined(WL_ENABLE_P2P_IF)
12640
- wl_cfg80211_detach_p2p();
12641
-#endif
12642
-
19077
+#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
19078
+ wl_cfg80211_detach_p2p(cfg);
19079
+#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
19080
+#ifdef WL_BAM
19081
+ wl_bad_ap_mngr_deinit(cfg);
19082
+#endif /* WL_BAM */
19083
+#ifdef BIGDATA_SOFTAP
19084
+ wl_detach_ap_stainfo(cfg);
19085
+#endif /* BIGDATA_SOFTAP */
1264319086 wl_cfg80211_ibss_vsie_free(cfg);
12644
- wl_cfg80211_clear_mgmt_vndr_ies(cfg);
19087
+ wl_dealloc_netinfo_by_wdev(cfg, cfg->wdev);
19088
+ wl_cfg80211_set_bcmcfg(NULL);
1264519089 wl_deinit_priv(cfg);
12646
- g_bcm_cfg = NULL;
1264719090 wl_cfg80211_clear_parent_dev();
1264819091 wl_free_wdev(cfg);
1264919092 /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
1265019093 * structure "cfg", which is the private part of wiphy, has been freed in
1265119094 * wl_free_wdev !!!!!!!!!!!
1265219095 */
19096
+ WL_DBG(("Exit\n"));
1265319097 }
1265419098
12655
-static void wl_wakeup_event(struct bcm_cfg80211 *cfg)
19099
+#if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
19100
+void wl_cfg80211_register_dev_ril_bridge_event_notifier()
1265619101 {
12657
- if (cfg->event_tsk.thr_pid >= 0) {
12658
- DHD_EVENT_WAKE_LOCK(cfg->pub);
12659
- up(&cfg->event_tsk.sema);
19102
+ WL_DBG(("Enter\n"));
19103
+ if (!wl_cfg80211_ril_bridge_notifier_registered) {
19104
+ s32 err = 0;
19105
+ wl_cfg80211_ril_bridge_notifier_registered = TRUE;
19106
+ err = register_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
19107
+ if (err) {
19108
+ wl_cfg80211_ril_bridge_notifier_registered = FALSE;
19109
+ WL_ERR(("Failed to register ril_notifier! %d\n", err));
19110
+ }
1266019111 }
1266119112 }
1266219113
12663
-static s32 wl_event_handler(void *data)
19114
+void wl_cfg80211_unregister_dev_ril_bridge_event_notifier()
19115
+{
19116
+ WL_DBG(("Enter\n"));
19117
+ if (wl_cfg80211_ril_bridge_notifier_registered) {
19118
+ wl_cfg80211_ril_bridge_notifier_registered = FALSE;
19119
+ unregister_dev_ril_bridge_event_notifier(&wl_cfg80211_ril_bridge_notifier);
19120
+ }
19121
+}
19122
+#endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
19123
+
19124
+static void wl_print_event_data(struct bcm_cfg80211 *cfg,
19125
+ uint32 event_type, const wl_event_msg_t *e)
19126
+{
19127
+ s32 status = ntoh32(e->status);
19128
+ s32 reason = ntoh32(e->reason);
19129
+ s32 ifidx = ntoh32(e->ifidx);
19130
+ s32 bssidx = ntoh32(e->bsscfgidx);
19131
+
19132
+ switch (event_type) {
19133
+ case WLC_E_ESCAN_RESULT:
19134
+ if ((status == WLC_E_STATUS_SUCCESS) ||
19135
+ (status == WLC_E_STATUS_ABORT)) {
19136
+ WL_INFORM_MEM(("event_type (%d), ifidx: %d"
19137
+ " bssidx: %d scan_type:%d\n",
19138
+ event_type, ifidx, bssidx, status));
19139
+ }
19140
+ break;
19141
+ case WLC_E_LINK:
19142
+ case WLC_E_DISASSOC:
19143
+ case WLC_E_DISASSOC_IND:
19144
+ case WLC_E_DEAUTH:
19145
+ case WLC_E_DEAUTH_IND:
19146
+ WL_INFORM_MEM(("event_type (%d), ifidx: %d bssidx: %d"
19147
+ " status:%d reason:%d\n",
19148
+ event_type, ifidx, bssidx, status, reason));
19149
+ break;
19150
+
19151
+ default:
19152
+ /* Print only when DBG verbose is enabled */
19153
+ WL_DBG(("event_type (%d), ifidx: %d bssidx: %d status:%d reason: %d\n",
19154
+ event_type, ifidx, bssidx, status, reason));
19155
+ }
19156
+}
19157
+
19158
+static void wl_event_handler(struct work_struct *work_data)
1266419159 {
1266519160 struct bcm_cfg80211 *cfg = NULL;
1266619161 struct wl_event_q *e;
12667
- tsk_ctl_t *tsk = (tsk_ctl_t *)data;
1266819162 struct wireless_dev *wdev = NULL;
1266919163
12670
- cfg = (struct bcm_cfg80211 *)tsk->parent;
19164
+ WL_DBG(("Enter \n"));
19165
+ BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
19166
+ cfg->wl_evt_hdlr_entry_time = OSL_LOCALTIME_NS();
19167
+ DHD_EVENT_WAKE_LOCK(cfg->pub);
19168
+ while ((e = wl_deq_event(cfg))) {
19169
+ s32 status = ntoh32(e->emsg.status);
19170
+ u32 event_type = ntoh32(e->emsg.event_type);
19171
+ bool scan_cmplt_evt = (event_type == WLC_E_ESCAN_RESULT) &&
19172
+ ((status == WLC_E_STATUS_SUCCESS) || (status == WLC_E_STATUS_ABORT));
1267119173
12672
- WL_ERR(("tsk Enter, tsk = 0x%p\n", tsk));
19174
+ cfg->wl_evt_deq_time = OSL_LOCALTIME_NS();
19175
+ if (scan_cmplt_evt) {
19176
+ cfg->scan_deq_time = OSL_LOCALTIME_NS();
19177
+ }
19178
+ /* Print only critical events to avoid too many prints */
19179
+ wl_print_event_data(cfg, e->etype, &e->emsg);
1267319180
12674
- while (down_interruptible (&tsk->sema) == 0) {
12675
- SMP_RD_BARRIER_DEPENDS();
12676
- if (tsk->terminated) {
12677
- DHD_EVENT_WAKE_UNLOCK(cfg->pub);
19181
+ if (e->emsg.ifidx > WL_MAX_IFS) {
19182
+ WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
19183
+ goto fail;
19184
+ }
19185
+
19186
+ /* Make sure iface operations, don't creat race conditions */
19187
+ mutex_lock(&cfg->if_sync);
19188
+ if (!(wdev = wl_get_wdev_by_fw_idx(cfg,
19189
+ e->emsg.bsscfgidx, e->emsg.ifidx))) {
19190
+ /* For WLC_E_IF would be handled by wl_host_event */
19191
+ if (e->etype != WLC_E_IF)
19192
+ WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
19193
+ " Ignoring event.\n", e->emsg.bsscfgidx));
19194
+ } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
19195
+ dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
19196
+ if (dhd->busstate == DHD_BUS_DOWN) {
19197
+ WL_ERR((": BUS is DOWN.\n"));
19198
+ } else
19199
+ {
19200
+ WL_DBG(("event_type %d event_sub %d\n",
19201
+ ntoh32(e->emsg.event_type),
19202
+ ntoh32(e->emsg.reason)));
19203
+ cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
19204
+ &e->emsg, e->edata);
19205
+ if (scan_cmplt_evt) {
19206
+ cfg->scan_hdlr_cmplt_time = OSL_LOCALTIME_NS();
19207
+ }
19208
+ }
19209
+ } else {
19210
+ WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
19211
+ }
19212
+ mutex_unlock(&cfg->if_sync);
19213
+fail:
19214
+ wl_put_event(cfg, e);
19215
+ if (scan_cmplt_evt) {
19216
+ cfg->scan_cmplt_time = OSL_LOCALTIME_NS();
19217
+ }
19218
+ cfg->wl_evt_hdlr_exit_time = OSL_LOCALTIME_NS();
19219
+ }
19220
+ DHD_EVENT_WAKE_UNLOCK(cfg->pub);
19221
+}
19222
+
19223
+/*
19224
+* Generic API to handle critical events which doesnt need
19225
+* cfg enquening and sleepable API calls.
19226
+*/
19227
+s32
19228
+wl_cfg80211_handle_critical_events(struct bcm_cfg80211 *cfg,
19229
+ const wl_event_msg_t * e)
19230
+{
19231
+ s32 ret = BCME_ERROR;
19232
+ u32 event_type = ntoh32(e->event_type);
19233
+
19234
+ if (event_type >= WLC_E_LAST) {
19235
+ return BCME_ERROR;
19236
+ }
19237
+
19238
+ switch (event_type) {
19239
+ case WLC_E_NAN_CRITICAL: {
19240
+#ifdef WL_NAN
19241
+ if (ntoh32(e->reason) == WL_NAN_EVENT_STOP) {
19242
+ /* Wakeup nan stop event waiting thread */
19243
+ WL_INFORM_MEM((">> Critical Nan Stop Event Received\n"));
19244
+ OSL_SMP_WMB();
19245
+ cfg->nancfg.nan_event_recvd = true;
19246
+ OSL_SMP_WMB();
19247
+ wake_up(&cfg->nancfg.nan_event_wait);
19248
+ ret = BCME_OK;
19249
+ }
19250
+#endif /* WL_NAN */
1267819251 break;
1267919252 }
12680
- while ((e = wl_deq_event(cfg))) {
12681
- WL_DBG(("event type (%d), ifidx: %d bssidx: %d \n",
12682
- e->etype, e->emsg.ifidx, e->emsg.bsscfgidx));
12683
-
12684
- if (e->emsg.ifidx > WL_MAX_IFS) {
12685
- WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
12686
- goto fail;
12687
- }
12688
- if (e->etype == WLC_E_TDLS_PEER_EVENT)
12689
- wdev = wl_get_wdev_by_bssidx(cfg, e->emsg.ifidx);
12690
- else
12691
- wdev = wl_get_wdev_by_bssidx(cfg, e->emsg.bsscfgidx);
12692
-
12693
- if (!wdev) {
12694
- /* For WLC_E_IF would be handled by wl_host_event */
12695
- if (e->etype != WLC_E_IF)
12696
- WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
12697
- " Ignoring event.\n", e->emsg.bsscfgidx));
12698
- } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
12699
- dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
12700
- if (dhd->busstate == DHD_BUS_DOWN) {
12701
- WL_ERR((": BUS is DOWN.\n"));
12702
- } else
12703
- cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
12704
- &e->emsg, e->edata);
12705
- } else {
12706
- WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
12707
- }
12708
-fail:
12709
- wl_put_event(e);
12710
- }
12711
- DHD_EVENT_WAKE_UNLOCK(cfg->pub);
19253
+ default:
19254
+ ret = BCME_ERROR;
1271219255 }
12713
- WL_ERR(("was terminated\n"));
12714
- complete_and_exit(&tsk->completed, 0);
12715
- return 0;
19256
+ return ret;
1271619257 }
1271719258
1271819259 void
1271919260 wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
1272019261 {
19262
+ s32 status = ntoh32(e->status);
1272119263 u32 event_type = ntoh32(e->event_type);
12722
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
19264
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1272319265 struct net_info *netinfo;
1272419266
12725
-#if (WL_DBG_LEVEL > 0)
12726
- s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ?
12727
- wl_dbg_estr[event_type] : (s8 *) "Unknown";
12728
- WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
12729
-#endif /* (WL_DBG_LEVEL > 0) */
12730
-
19267
+ WL_TRACE(("event_type (%d): reason (%d): %s\n", event_type, ntoh32(e->reason),
19268
+ bcmevent_get_name(event_type)));
1273119269 if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
1273219270 WL_ERR(("Stale event ignored\n"));
1273319271 return;
1273419272 }
12735
- if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) {
12736
- WL_ERR(("during IF change, ignore event %d\n", event_type));
19273
+
19274
+#ifdef OEM_ANDROID
19275
+ if (cfg->event_workq == NULL) {
19276
+ WL_ERR(("Event handler is not created\n"));
19277
+ return;
19278
+ }
19279
+#else
19280
+ if (!cfg->event_workq_init) {
19281
+ WL_ERR(("Event handler is not created\n"));
19282
+ return;
19283
+ }
19284
+#endif /* OEM_ANDROID */
19285
+
19286
+ if (event_type == WLC_E_IF) {
19287
+ /* Don't process WLC_E_IF events in wl_cfg80211 layer */
1273719288 return;
1273819289 }
1273919290
12740
- if (event_type == WLC_E_TDLS_PEER_EVENT)
12741
- netinfo = wl_get_netinfo_by_netdev(cfg, ndev);
12742
- else
12743
- netinfo = wl_get_netinfo_by_bssidx(cfg, e->bsscfgidx);
12744
-
19291
+ netinfo = wl_get_netinfo_by_fw_idx(cfg, e->bsscfgidx, e->ifidx);
1274519292 if (!netinfo) {
1274619293 /* Since the netinfo entry is not there, the netdev entry is not
1274719294 * created via cfg80211 interface. so the event is not of interest
1274819295 * to the cfg80211 layer.
1274919296 */
12750
- WL_ERR(("ignore event %d, not interested\n", event_type));
19297
+ WL_TRACE(("ignore event %d, not interested\n", event_type));
19298
+ return;
19299
+ }
19300
+
19301
+ /* Handle wl_cfg80211_critical_events */
19302
+ if (wl_cfg80211_handle_critical_events(cfg, e) == BCME_OK) {
1275119303 return;
1275219304 }
1275319305
....@@ -12758,8 +19310,21 @@
1275819310 WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
1275919311 }
1276019312
12761
- if (likely(!wl_enq_event(cfg, ndev, event_type, e, data)))
12762
- wl_wakeup_event(cfg);
19313
+ if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
19314
+#ifdef OEM_ANDROID
19315
+ queue_work(cfg->event_workq, &cfg->event_work);
19316
+#else
19317
+ schedule_work(&cfg->event_work);
19318
+#endif /* OEM_ANDROID */
19319
+ }
19320
+ /* Mark timeout value for thread sched */
19321
+ if ((event_type == WLC_E_ESCAN_RESULT) &&
19322
+ ((status == WLC_E_STATUS_SUCCESS) ||
19323
+ (status == WLC_E_STATUS_ABORT))) {
19324
+ cfg->scan_enq_time = OSL_LOCALTIME_NS();
19325
+ WL_INFORM_MEM(("Enqueing escan completion (%d). WQ state:0x%x \n",
19326
+ status, work_busy(&cfg->event_work)));
19327
+ }
1276319328 }
1276419329
1276519330 static void wl_init_eq(struct bcm_cfg80211 *cfg)
....@@ -12777,7 +19342,7 @@
1277719342 while (!list_empty_careful(&cfg->eq_list)) {
1277819343 BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
1277919344 list_del(&e->eq_list);
12780
- kfree(e);
19345
+ MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
1278119346 }
1278219347 wl_unlock_eq(cfg, flags);
1278319348 }
....@@ -12814,14 +19379,12 @@
1281419379 uint32 evtq_size;
1281519380 uint32 data_len;
1281619381 unsigned long flags;
12817
- gfp_t aflags;
1281819382
1281919383 data_len = 0;
1282019384 if (data)
1282119385 data_len = ntoh32(msg->datalen);
12822
- evtq_size = sizeof(struct wl_event_q) + data_len;
12823
- aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
12824
- e = kzalloc(evtq_size, aflags);
19386
+ evtq_size = (uint32)(sizeof(struct wl_event_q) + data_len);
19387
+ e = (struct wl_event_q *)MALLOCZ(cfg->osh, evtq_size);
1282519388 if (unlikely(!e)) {
1282619389 WL_ERR(("event alloc failed\n"));
1282719390 return -ENOMEM;
....@@ -12830,6 +19393,7 @@
1283019393 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
1283119394 if (data)
1283219395 memcpy(e->edata, data, data_len);
19396
+ e->datalen = data_len;
1283319397 flags = wl_lock_eq(cfg);
1283419398 list_add_tail(&e->eq_list, &cfg->eq_list);
1283519399 wl_unlock_eq(cfg, flags);
....@@ -12837,50 +19401,47 @@
1283719401 return err;
1283819402 }
1283919403
12840
-static void wl_put_event(struct wl_event_q *e)
19404
+static void wl_put_event(struct bcm_cfg80211 *cfg, struct wl_event_q *e)
1284119405 {
12842
- kfree(e);
19406
+ MFREE(cfg->osh, e, e->datalen + sizeof(struct wl_event_q));
1284319407 }
1284419408
12845
-static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype)
19409
+static s32 wl_config_infra(struct bcm_cfg80211 *cfg, struct net_device *ndev, u16 iftype)
1284619410 {
1284719411 s32 infra = 0;
1284819412 s32 err = 0;
12849
- s32 mode = 0;
19413
+ bool skip_infra = false;
19414
+
1285019415 switch (iftype) {
12851
- case NL80211_IFTYPE_MONITOR:
12852
- case NL80211_IFTYPE_WDS:
12853
- WL_ERR(("type (%d) : currently we do not support this mode\n",
12854
- iftype));
12855
- err = -EINVAL;
12856
- return err;
12857
- case NL80211_IFTYPE_ADHOC:
12858
- mode = WL_MODE_IBSS;
12859
- break;
12860
- case NL80211_IFTYPE_STATION:
12861
- case NL80211_IFTYPE_P2P_CLIENT:
12862
- mode = WL_MODE_BSS;
12863
- infra = 1;
12864
- break;
12865
- case NL80211_IFTYPE_AP:
12866
- case NL80211_IFTYPE_P2P_GO:
12867
- mode = WL_MODE_AP;
12868
- infra = 1;
12869
- break;
12870
- default:
12871
- err = -EINVAL;
12872
- WL_ERR(("invalid type (%d)\n", iftype));
12873
- return err;
12874
- }
12875
- infra = htod32(infra);
12876
- err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);
12877
- if (unlikely(err)) {
12878
- WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
12879
- return err;
19416
+ case WL_IF_TYPE_IBSS:
19417
+ case WL_IF_TYPE_AIBSS:
19418
+ infra = 0;
19419
+ break;
19420
+ case WL_IF_TYPE_AP:
19421
+ case WL_IF_TYPE_STA:
19422
+ case WL_IF_TYPE_P2P_GO:
19423
+ case WL_IF_TYPE_P2P_GC:
19424
+ /* Intentional fall through */
19425
+ infra = 1;
19426
+ break;
19427
+ case WL_IF_TYPE_MONITOR:
19428
+ case WL_IF_TYPE_AWDL:
19429
+ case WL_IF_TYPE_NAN:
19430
+ /* Intentionall fall through */
19431
+ default:
19432
+ skip_infra = true;
19433
+ WL_ERR(("Skipping infra setting for type:%d\n", iftype));
19434
+ break;
1288019435 }
1288119436
12882
- wl_set_mode_by_netdev(cfg, ndev, mode);
12883
-
19437
+ if (!skip_infra) {
19438
+ infra = htod32(infra);
19439
+ err = wldev_ioctl_set(ndev, WLC_SET_INFRA, &infra, sizeof(infra));
19440
+ if (unlikely(err)) {
19441
+ WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
19442
+ return err;
19443
+ }
19444
+ }
1288419445 return 0;
1288519446 }
1288619447
....@@ -12932,7 +19493,7 @@
1293219493
1293319494 /* Write updated Event mask */
1293419495 ret = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, sizeof(eventmask), iovbuf,
12935
- sizeof(iovbuf), NULL);
19496
+ sizeof(iovbuf), NULL);
1293619497 if (unlikely(ret)) {
1293719498 WL_ERR(("Set event_msgs error (%d)\n", ret));
1293819499 }
....@@ -12947,9 +19508,13 @@
1294719508 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
1294819509 s8 eventmask[WL_EVENTING_MASK_LEN];
1294919510 s32 err = 0;
12950
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
19511
+ struct bcm_cfg80211 *cfg;
1295119512
12952
- if (!ndev || !cfg)
19513
+ if (!ndev)
19514
+ return -ENODEV;
19515
+
19516
+ cfg = wl_get_cfg(ndev);
19517
+ if (!cfg)
1295319518 return -ENODEV;
1295419519
1295519520 mutex_lock(&cfg->event_sync);
....@@ -12967,7 +19532,7 @@
1296719532 clrbit(eventmask, event);
1296819533 }
1296919534 err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
12970
- sizeof(iovbuf), NULL);
19535
+ sizeof(iovbuf), NULL);
1297119536 if (unlikely(err)) {
1297219537 WL_ERR(("Set event_msgs error (%d)\n", err));
1297319538 goto eventmsg_out;
....@@ -12978,12 +19543,292 @@
1297819543 return err;
1297919544 }
1298019545
12981
-static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
19546
+static void wl_get_bwcap(struct bcm_cfg80211 *cfg, u32 bw_cap[])
19547
+{
19548
+ u32 band, mimo_bwcap;
19549
+ int err;
19550
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
19551
+
19552
+ band = WLC_BAND_2G;
19553
+ err = wldev_iovar_getint(dev, "bw_cap", &band);
19554
+ if (likely(!err)) {
19555
+ bw_cap[NL80211_BAND_2GHZ] = band;
19556
+
19557
+ band = WLC_BAND_5G;
19558
+ err = wldev_iovar_getint(dev, "bw_cap", &band);
19559
+ if (likely(!err)) {
19560
+ bw_cap[NL80211_BAND_5GHZ] = band;
19561
+
19562
+#ifdef WL_6E
19563
+ band = WLC_BAND_6G;
19564
+ err = wldev_iovar_getint(dev, "bw_cap", &band);
19565
+ if (likely(!err)) {
19566
+ bw_cap[NL80211_BAND_6GHZ] = band;
19567
+ return;
19568
+ }
19569
+ WARN_ON(1);
19570
+#else
19571
+ return;
19572
+#endif /* WL_6E */
19573
+ }
19574
+ WARN_ON(1);
19575
+ return;
19576
+ }
19577
+ WARN_ON(1);
19578
+
19579
+ WL_ERR(("fallback to mimo_bw_cap info\n"));
19580
+ mimo_bwcap = 0;
19581
+ err = wldev_iovar_getint(dev, "mimo_bw_cap", &mimo_bwcap);
19582
+ if (unlikely(err))
19583
+ /* assume 20MHz if firmware does not give a clue */
19584
+ mimo_bwcap = WLC_N_BW_20ALL;
19585
+
19586
+ switch (mimo_bwcap) {
19587
+ case WLC_N_BW_40ALL:
19588
+ bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
19589
+ /* fall-thru */
19590
+ case WLC_N_BW_20IN2G_40IN5G:
19591
+ bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
19592
+ /* fall-thru */
19593
+ case WLC_N_BW_20ALL:
19594
+ bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
19595
+ bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
19596
+ break;
19597
+ default:
19598
+ WL_ERR(("invalid mimo_bw_cap value\n"));
19599
+ bw_cap[NL80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
19600
+ bw_cap[NL80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
19601
+ }
19602
+}
19603
+
19604
+static void wl_update_ht_cap(struct ieee80211_supported_band *band,
19605
+ u32 bwcap, u32 nchain)
19606
+{
19607
+ band->ht_cap.ht_supported = TRUE;
19608
+ if (bwcap & WLC_BW_40MHZ_BIT) {
19609
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
19610
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
19611
+ }
19612
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
19613
+ band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
19614
+ band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
19615
+ band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
19616
+ band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
19617
+
19618
+ /* An HT shall support all EQM rates for one spatial stream */
19619
+ memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
19620
+}
19621
+
19622
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
19623
+static void wl_update_vht_cap(struct bcm_cfg80211 *cfg, struct ieee80211_supported_band *band,
19624
+ u32 bwcap)
19625
+{
19626
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
19627
+ s32 err = 0;
19628
+ u32 j = 0;
19629
+ s32 txstreams = 0;
19630
+ s32 rxstreams = 0;
19631
+ s32 ldpc_cap = 0;
19632
+ s32 stbc_rx = 0;
19633
+ s32 stbc_tx = 0;
19634
+ s32 txbf_bfe_cap = 0;
19635
+ s32 txbf_bfr_cap = 0;
19636
+
19637
+ /* not allowed in 2.4G band */
19638
+ if (band->band == IEEE80211_BAND_2GHZ)
19639
+ return;
19640
+
19641
+ if (bwcap == WLC_N_BW_40ALL || bwcap == WLC_N_BW_20IN2G_40IN5G)
19642
+ band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
19643
+
19644
+ band->vht_cap.vht_supported = true;
19645
+
19646
+ err = wldev_iovar_getint(dev, "txstreams", &txstreams);
19647
+ if (unlikely(err)) {
19648
+ WL_ERR(("error reading txstreams (%d)\n", err));
19649
+ }
19650
+
19651
+ err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
19652
+ if (unlikely(err)) {
19653
+ WL_ERR(("error reading rxstreams (%d)\n", err));
19654
+ }
19655
+
19656
+ err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
19657
+ if (unlikely(err)) {
19658
+ WL_ERR(("error reading ldpc_cap (%d)\n", err));
19659
+ }
19660
+
19661
+ err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
19662
+ if (unlikely(err)) {
19663
+ WL_ERR(("error reading stbc_rx (%d)\n", err));
19664
+ }
19665
+
19666
+ err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
19667
+ if (unlikely(err)) {
19668
+ WL_ERR(("error reading stbc_tx (%d)\n", err));
19669
+ }
19670
+
19671
+ err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
19672
+ if (unlikely(err)) {
19673
+ WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
19674
+ }
19675
+
19676
+ err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
19677
+ if (unlikely(err)) {
19678
+ WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
19679
+ }
19680
+
19681
+ /* Supported */
19682
+ band->vht_cap.vht_supported = TRUE;
19683
+
19684
+ for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
19685
+ /* TX stream rates. */
19686
+ if (j <= txstreams) {
19687
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
19688
+ band->vht_cap.vht_mcs.tx_mcs_map);
19689
+ } else {
19690
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
19691
+ band->vht_cap.vht_mcs.tx_mcs_map);
19692
+ }
19693
+
19694
+ /* RX stream rates. */
19695
+ if (j <= rxstreams) {
19696
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
19697
+ band->vht_cap.vht_mcs.rx_mcs_map);
19698
+ } else {
19699
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
19700
+ band->vht_cap.vht_mcs.rx_mcs_map);
19701
+ }
19702
+ }
19703
+
19704
+ /* Capabilities */
19705
+ /* 80 MHz is mandatory */
19706
+ band->vht_cap.cap |=
19707
+ IEEE80211_VHT_CAP_SHORT_GI_80;
19708
+
19709
+ if (WL_BW_CAP_160MHZ(bwcap)) {
19710
+ band->vht_cap.cap |=
19711
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
19712
+ band->vht_cap.cap |=
19713
+ IEEE80211_VHT_CAP_SHORT_GI_160;
19714
+ }
19715
+ band->vht_cap.cap |=
19716
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
19717
+
19718
+ if (ldpc_cap)
19719
+ band->vht_cap.cap |=
19720
+ IEEE80211_VHT_CAP_RXLDPC;
19721
+
19722
+ if (stbc_tx)
19723
+ band->vht_cap.cap |=
19724
+ IEEE80211_VHT_CAP_TXSTBC;
19725
+
19726
+ if (stbc_rx)
19727
+ band->vht_cap.cap |=
19728
+ (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
19729
+
19730
+ if (txbf_bfe_cap)
19731
+ band->vht_cap.cap |=
19732
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
19733
+
19734
+ if (txbf_bfr_cap) {
19735
+ band->vht_cap.cap |=
19736
+ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
19737
+ }
19738
+
19739
+ if (txbf_bfe_cap || txbf_bfr_cap) {
19740
+ band->vht_cap.cap |=
19741
+ (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
19742
+ band->vht_cap.cap |=
19743
+ ((txstreams - 1) <<
19744
+ VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
19745
+ band->vht_cap.cap |=
19746
+ IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
19747
+ }
19748
+
19749
+ /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
19750
+ band->vht_cap.cap |=
19751
+ (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
19752
+
19753
+ WL_DBG(("%s 5GHz band vht_enab=%d vht_cap=%08x "
19754
+ "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
19755
+ __FUNCTION__,
19756
+ band->vht_cap.vht_supported,
19757
+ band->vht_cap.cap,
19758
+ band->vht_cap.vht_mcs.rx_mcs_map,
19759
+ band->vht_cap.vht_mcs.tx_mcs_map));
19760
+}
19761
+#endif // endif
19762
+
19763
+/* make up event mask ext message iovar for event larger than 128 */
19764
+s32 wl_add_remove_eventextmsg(struct net_device *ndev, u16 event, bool add)
19765
+{
19766
+ uint8 msglen;
19767
+ eventmsgs_ext_t *eventmask_msg = NULL;
19768
+ char* iov_buf = NULL;
19769
+ s32 err = 0;
19770
+ struct bcm_cfg80211 *cfg = NULL;
19771
+
19772
+ if (!ndev)
19773
+ return -ENODEV;
19774
+
19775
+ cfg = wl_get_cfg(ndev);
19776
+ if (!cfg)
19777
+ return -ENODEV;
19778
+
19779
+ iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
19780
+ if (iov_buf == NULL) {
19781
+ WL_ERR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN));
19782
+ return BCME_NOMEM;
19783
+ }
19784
+
19785
+ msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE;
19786
+ eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL);
19787
+ if (eventmask_msg == NULL) {
19788
+ WL_ERR(("failed to allocate %d bytes for event_msg_ext\n", msglen));
19789
+ return BCME_NOMEM;
19790
+ }
19791
+ bzero(eventmask_msg, msglen);
19792
+ eventmask_msg->ver = EVENTMSGS_VER;
19793
+ eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
19794
+
19795
+ /* Setup event_msgs */
19796
+ err = wldev_iovar_getbuf(ndev, "event_msgs_ext", (void *)eventmask_msg,
19797
+ msglen, iov_buf, WLC_IOCTL_SMLEN, NULL);
19798
+ if (err == 0) {
19799
+ bcopy(iov_buf, eventmask_msg, msglen);
19800
+
19801
+ if (add) {
19802
+ setbit(eventmask_msg->mask, event);
19803
+ } else {
19804
+ clrbit(eventmask_msg->mask, event);
19805
+ }
19806
+
19807
+ /* Write updated Event mask */
19808
+ eventmask_msg->ver = EVENTMSGS_VER;
19809
+ eventmask_msg->command = EVENTMSGS_SET_MASK;
19810
+ eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
19811
+
19812
+ err = wldev_iovar_setbuf(ndev, "event_msgs_ext", (void *)eventmask_msg,
19813
+ msglen, iov_buf, WLC_IOCTL_SMLEN, NULL);
19814
+
19815
+ if (err)
19816
+ WL_ERR(("Get event_msgs error (%d)\n", err));
19817
+ }
19818
+
19819
+ if (eventmask_msg)
19820
+ kfree(eventmask_msg);
19821
+ if (iov_buf)
19822
+ kfree(iov_buf);
19823
+ return err;
19824
+}
19825
+
19826
+static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, u32 bw_cap[])
1298219827 {
1298319828 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
1298419829 struct ieee80211_channel *band_chan_arr = NULL;
1298519830 wl_uint32_list_t *list;
12986
- u32 i, j, index, n_2g, n_5g, band, channel, array_size;
19831
+ u32 i, j, index, n_2g, n_5g, n_6g, band, channel, array_size;
1298719832 u32 *n_cnt = NULL;
1298819833 chanspec_t c = 0;
1298919834 s32 err = BCME_OK;
....@@ -12992,9 +19837,8 @@
1299219837 u8 *pbuf = NULL;
1299319838 bool dfs_radar_disabled = FALSE;
1299419839
12995
-#define LOCAL_BUF_LEN 1024
12996
- pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL);
12997
-
19840
+#define LOCAL_BUF_LEN 2048
19841
+ pbuf = (u8 *)MALLOCZ(cfg->osh, LOCAL_BUF_LEN);
1299819842 if (pbuf == NULL) {
1299919843 WL_ERR(("failed to allocate local buf\n"));
1300019844 return -ENOMEM;
....@@ -13004,13 +19848,12 @@
1300419848 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
1300519849 if (err != 0) {
1300619850 WL_ERR(("get chanspecs failed with %d\n", err));
13007
- kfree(pbuf);
19851
+ MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
1300819852 return err;
1300919853 }
13010
-#undef LOCAL_BUF_LEN
1301119854
1301219855 list = (wl_uint32_list_t *)(void *)pbuf;
13013
- band = array_size = n_2g = n_5g = 0;
19856
+ band = array_size = n_2g = n_5g = n_6g = 0;
1301419857 for (i = 0; i < dtoh32(list->count); i++) {
1301519858 index = 0;
1301619859 update = false;
....@@ -13029,15 +19872,24 @@
1302919872 array_size = ARRAYSIZE(__wl_2ghz_channels);
1303019873 n_cnt = &n_2g;
1303119874 band = IEEE80211_BAND_2GHZ;
13032
- ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false;
19875
+ ht40_allowed = (bw_cap[band] == WLC_N_BW_40ALL)? true : false;
1303319876 } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
1303419877 band_chan_arr = __wl_5ghz_a_channels;
1303519878 array_size = ARRAYSIZE(__wl_5ghz_a_channels);
1303619879 n_cnt = &n_5g;
1303719880 band = IEEE80211_BAND_5GHZ;
13038
- ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true;
19881
+ ht40_allowed = (bw_cap[band] == WLC_N_BW_20ALL)? false : true;
19882
+#ifdef WL_6E
19883
+ } else if (CHSPEC_IS6G(c) && channel >= CH_MIN_6G_CHANNEL &&
19884
+ (channel <= CH_MAX_6G_CHANNEL)) {
19885
+ band_chan_arr = __wl_6ghz_a_channels;
19886
+ array_size = ARRAYSIZE(__wl_6ghz_a_channels);
19887
+ n_cnt = &n_6g;
19888
+ band = IEEE80211_BAND_6GHZ;
19889
+ ht40_allowed = (bw_cap[band] == WLC_N_BW_20ALL)? false : true;
19890
+#endif /* WL_6E */
1303919891 } else {
13040
- WL_ERR(("Invalid channel Sepc. 0x%x.\n", c));
19892
+ WL_ERR(("Invalid channel Spec. 0x%x.\n", c));
1304119893 continue;
1304219894 }
1304319895 if (!ht40_allowed && CHSPEC_IS40(c))
....@@ -13053,13 +19905,13 @@
1305319905 else
1305419906 index = *n_cnt;
1305519907 if (index < array_size) {
13056
-#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
19908
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
1305719909 band_chan_arr[index].center_freq =
1305819910 ieee80211_channel_to_frequency(channel);
1305919911 #else
1306019912 band_chan_arr[index].center_freq =
1306119913 ieee80211_channel_to_frequency(channel, band);
13062
-#endif
19914
+#endif // endif
1306319915 band_chan_arr[index].hw_value = channel;
1306419916 band_chan_arr[index].beacon_found = false;
1306519917
....@@ -13087,8 +19939,13 @@
1308719939 if (!dfs_radar_disabled) {
1308819940 if (band == IEEE80211_BAND_2GHZ)
1308919941 channel |= WL_CHANSPEC_BAND_2G;
13090
- else
19942
+ else if (band == IEEE80211_BAND_5GHZ)
1309119943 channel |= WL_CHANSPEC_BAND_5G;
19944
+#ifdef WL_6E
19945
+ else if (band == IEEE80211_BAND_6GHZ)
19946
+ channel |= WL_CHANSPEC_BAND_6G;
19947
+#endif /* WL_6E */
19948
+
1309219949 channel |= WL_CHANSPEC_BW_20;
1309319950 channel = wl_chspec_host_to_driver(channel);
1309419951 err = wldev_iovar_getint(dev, "per_chan_info", &channel);
....@@ -13101,7 +19958,7 @@
1310119958 #else
1310219959 band_chan_arr[index].flags |=
1310319960 IEEE80211_CHAN_RADAR;
13104
-#endif
19961
+#endif // endif
1310519962 }
1310619963
1310719964 if (channel & WL_CHAN_PASSIVE)
....@@ -13111,7 +19968,7 @@
1311119968 #else
1311219969 band_chan_arr[index].flags |=
1311319970 IEEE80211_CHAN_NO_IR;
13114
-#endif
19971
+#endif // endif
1311519972 } else if (err == BCME_UNSUPPORTED) {
1311619973 dfs_radar_disabled = TRUE;
1311719974 WL_ERR(("does not support per_chan_info\n"));
....@@ -13125,59 +19982,56 @@
1312519982 }
1312619983 __wl_band_2ghz.n_channels = n_2g;
1312719984 __wl_band_5ghz_a.n_channels = n_5g;
13128
- kfree(pbuf);
19985
+#ifdef WL_6E
19986
+ __wl_band_6ghz.n_channels = n_6g;
19987
+#endif /* WL_6E */
19988
+ MFREE(cfg->osh, pbuf, LOCAL_BUF_LEN);
19989
+#undef LOCAL_BUF_LEN
19990
+
1312919991 return err;
1313019992 }
1313119993
13132
-s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
19994
+static s32 __wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
1313319995 {
1313419996 struct wiphy *wiphy;
13135
- struct net_device *dev;
19997
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
19998
+#ifdef WL_6E
19999
+ u32 bandlist[4];
20000
+#else
1313620001 u32 bandlist[3];
20002
+#endif /* WL_6E */
1313720003 u32 nband = 0;
1313820004 u32 i = 0;
1313920005 s32 err = 0;
1314020006 s32 index = 0;
1314120007 s32 nmode = 0;
20008
+ u32 rxchain;
20009
+ u32 nchain;
1314220010 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
13143
- u32 j = 0;
1314420011 s32 vhtmode = 0;
13145
- s32 txstreams = 0;
13146
- s32 rxstreams = 0;
13147
- s32 ldpc_cap = 0;
13148
- s32 stbc_rx = 0;
13149
- s32 stbc_tx = 0;
13150
- s32 txbf_bfe_cap = 0;
13151
- s32 txbf_bfr_cap = 0;
13152
-#endif
13153
- bool rollback_lock = false;
13154
- s32 bw_cap = 0;
20012
+#endif // endif
20013
+#ifdef WL_SAE
20014
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20015
+#endif /* WL_SAE */
20016
+ u32 bw_cap[4] = { WLC_BW_20MHZ_BIT, /* 2GHz */
20017
+ WLC_BW_20MHZ_BIT, /* 5GHz */
20018
+ 0, /* 60GHz */
20019
+ WLC_BW_20MHZ_BIT }; /* 6GHz */
1315520020 s32 cur_band = -1;
13156
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
13157
- struct ieee80211_supported_band *bands[NUM_NL80211_BANDS] = {NULL, };
13158
-#else
1315920021 struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, };
13160
-#endif
1316120022
13162
- if (cfg == NULL) {
13163
- cfg = g_bcm_cfg;
13164
- mutex_lock(&cfg->usr_sync);
13165
- rollback_lock = true;
13166
- }
13167
- dev = bcmcfg_to_prmry_ndev(cfg);
13168
-
13169
- memset(bandlist, 0, sizeof(bandlist));
13170
- err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist,
13171
- sizeof(bandlist), false);
20023
+ bzero(bandlist, sizeof(bandlist));
20024
+ err = wldev_ioctl_get(dev, WLC_GET_BANDLIST, bandlist,
20025
+ sizeof(bandlist));
1317220026 if (unlikely(err)) {
1317320027 WL_ERR(("error read bandlist (%d)\n", err));
13174
- goto end_bands;
20028
+ return err;
1317520029 }
13176
- err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band,
13177
- sizeof(s32), false);
20030
+ err = wldev_ioctl_get(dev, WLC_GET_BAND, &cur_band,
20031
+ sizeof(s32));
1317820032 if (unlikely(err)) {
1317920033 WL_ERR(("error (%d)\n", err));
13180
- goto end_bands;
20034
+ return err;
1318120035 }
1318220036
1318320037 err = wldev_iovar_getint(dev, "nmode", &nmode);
....@@ -13190,184 +20044,101 @@
1319020044 if (unlikely(err)) {
1319120045 WL_ERR(("error reading vhtmode (%d)\n", err));
1319220046 }
13193
-
13194
- if (vhtmode) {
13195
- err = wldev_iovar_getint(dev, "txstreams", &txstreams);
13196
- if (unlikely(err)) {
13197
- WL_ERR(("error reading txstreams (%d)\n", err));
13198
- }
13199
-
13200
- err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
13201
- if (unlikely(err)) {
13202
- WL_ERR(("error reading rxstreams (%d)\n", err));
13203
- }
13204
-
13205
- err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
13206
- if (unlikely(err)) {
13207
- WL_ERR(("error reading ldpc_cap (%d)\n", err));
13208
- }
13209
-
13210
- err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
13211
- if (unlikely(err)) {
13212
- WL_ERR(("error reading stbc_rx (%d)\n", err));
13213
- }
13214
-
13215
- err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
13216
- if (unlikely(err)) {
13217
- WL_ERR(("error reading stbc_tx (%d)\n", err));
13218
- }
13219
-
13220
- err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
13221
- if (unlikely(err)) {
13222
- WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
13223
- }
13224
-
13225
- err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
13226
- if (unlikely(err)) {
13227
- WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
13228
- }
13229
- }
13230
-#endif
20047
+#endif // endif
1323120048
1323220049 /* For nmode and vhtmode check bw cap */
1323320050 if (nmode ||
1323420051 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
13235
- vhtmode ||
13236
-#endif
13237
- 0) {
13238
- err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
13239
- if (unlikely(err)) {
13240
- WL_ERR(("error get mimo_bw_cap (%d)\n", err));
13241
- }
20052
+ vhtmode ||
20053
+#endif // endif
20054
+ 0) {
20055
+ wl_get_bwcap(cfg, bw_cap);
1324220056 }
20057
+
20058
+ err = wldev_iovar_getint(dev, "rxchain", &rxchain);
20059
+ if (err) {
20060
+ WL_ERR(("rxchain error (%d)\n", err));
20061
+ nchain = 1;
20062
+ } else {
20063
+ for (nchain = 0; rxchain; nchain++)
20064
+ rxchain = rxchain & (rxchain - 1);
20065
+ }
20066
+ WL_DBG(("nchain=%d\n", nchain));
1324320067
1324420068 err = wl_construct_reginfo(cfg, bw_cap);
1324520069 if (err) {
1324620070 WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
1324720071 if (err != BCME_UNSUPPORTED)
13248
- goto end_bands;
13249
- err = 0;
20072
+ return err;
1325020073 }
20074
+#ifdef WL11AX
20075
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 21))
20076
+ err = wldev_iovar_getint(dev, "he", &he);
20077
+ if (unlikely(err)) {
20078
+ WL_ERR(("error reading he (%d)\n", err));
20079
+ }
20080
+#endif // endif
20081
+#endif // endif
20082
+
1325120083 wiphy = bcmcfg_to_wiphy(cfg);
1325220084 nband = bandlist[0];
1325320085
1325420086 for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
1325520087 index = -1;
1325620088 if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
13257
- bands[IEEE80211_BAND_5GHZ] =
13258
- &__wl_band_5ghz_a;
1325920089 index = IEEE80211_BAND_5GHZ;
13260
- if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
13261
- bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
13262
-
20090
+ bands[index] = &__wl_band_5ghz_a;
1326320091 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
13264
- /* VHT capabilities. */
1326520092 if (vhtmode) {
13266
- /* Supported */
13267
- bands[index]->vht_cap.vht_supported = TRUE;
13268
-
13269
- for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
13270
- /* TX stream rates. */
13271
- if (j <= txstreams) {
13272
- VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
13273
- bands[index]->vht_cap.vht_mcs.tx_mcs_map);
13274
- } else {
13275
- VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
13276
- bands[index]->vht_cap.vht_mcs.tx_mcs_map);
13277
- }
13278
-
13279
- /* RX stream rates. */
13280
- if (j <= rxstreams) {
13281
- VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
13282
- bands[index]->vht_cap.vht_mcs.rx_mcs_map);
13283
- } else {
13284
- VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
13285
- bands[index]->vht_cap.vht_mcs.rx_mcs_map);
13286
- }
13287
- }
13288
-
13289
-
13290
- /* Capabilities */
13291
- /* 80 MHz is mandatory */
13292
- bands[index]->vht_cap.cap |=
13293
- IEEE80211_VHT_CAP_SHORT_GI_80;
13294
-
13295
- if (WL_BW_CAP_160MHZ(bw_cap)) {
13296
- bands[index]->vht_cap.cap |=
13297
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
13298
- bands[index]->vht_cap.cap |=
13299
- IEEE80211_VHT_CAP_SHORT_GI_160;
13300
- }
13301
-
13302
- bands[index]->vht_cap.cap |=
13303
- IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
13304
-
13305
- if (ldpc_cap)
13306
- bands[index]->vht_cap.cap |=
13307
- IEEE80211_VHT_CAP_RXLDPC;
13308
-
13309
- if (stbc_tx)
13310
- bands[index]->vht_cap.cap |=
13311
- IEEE80211_VHT_CAP_TXSTBC;
13312
-
13313
- if (stbc_rx)
13314
- bands[index]->vht_cap.cap |=
13315
- (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
13316
-
13317
- if (txbf_bfe_cap)
13318
- bands[index]->vht_cap.cap |=
13319
- IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
13320
-
13321
- if (txbf_bfr_cap) {
13322
- bands[index]->vht_cap.cap |=
13323
- IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
13324
- }
13325
-
13326
- if (txbf_bfe_cap || txbf_bfr_cap) {
13327
- bands[index]->vht_cap.cap |=
13328
- (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
13329
- bands[index]->vht_cap.cap |=
13330
- ((txstreams - 1) <<
13331
- VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
13332
- bands[index]->vht_cap.cap |=
13333
- IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
13334
- }
13335
-
13336
- /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
13337
- bands[index]->vht_cap.cap |=
13338
- (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
13339
- WL_INFORM(("%s band[%d] vht_enab=%d vht_cap=%08x "
13340
- "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
13341
- __FUNCTION__, index,
13342
- bands[index]->vht_cap.vht_supported,
13343
- bands[index]->vht_cap.cap,
13344
- bands[index]->vht_cap.vht_mcs.rx_mcs_map,
13345
- bands[index]->vht_cap.vht_mcs.tx_mcs_map));
20093
+ wl_update_vht_cap(cfg, bands[index], bw_cap[index]);
1334620094 }
13347
-#endif
20095
+#endif // endif
20096
+#ifdef WL11AX
20097
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 21))
20098
+ if(he) {
20099
+ bands[index]->n_iftype_data = wl_update_he_cap(cfg, &sdata[index], NL80211_BAND_5GHZ);
20100
+ bands[index]->iftype_data = &sdata[index];
20101
+ }
20102
+#endif // endif
20103
+#endif // endif
1334820104 }
1334920105 else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
13350
- bands[IEEE80211_BAND_2GHZ] =
13351
- &__wl_band_2ghz;
1335220106 index = IEEE80211_BAND_2GHZ;
13353
- if (bw_cap == WLC_N_BW_40ALL)
13354
- bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
20107
+ bands[index] = &__wl_band_2ghz;
20108
+#ifdef WL11AX
20109
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 21))
20110
+ if(he) {
20111
+ bands[index]->n_iftype_data = wl_update_he_cap(cfg, &sdata[index], NL80211_BAND_2GHZ);
20112
+ bands[index]->iftype_data = &sdata[index];
20113
+ }
20114
+#endif // endif
20115
+#endif // endif
1335520116 }
20117
+#ifdef WL_6E
20118
+ else if (bandlist[i] == WLC_BAND_6G && __wl_band_6ghz.n_channels > 0) {
20119
+ index = IEEE80211_BAND_6GHZ;
20120
+ bands[index] = &__wl_band_6ghz;
20121
+#ifdef WL11AX
20122
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 21))
20123
+ if(he) {
20124
+ bands[index]->n_iftype_data = wl_update_he_cap(cfg, &sdata[index], NL80211_BAND_6GHZ);
20125
+ bands[index]->iftype_data = &sdata[index];
20126
+ }
20127
+#endif // endif
20128
+#endif // endif
20129
+ }
20130
+#endif /* WL_6E */
1335620131
1335720132 if ((index >= 0) && nmode) {
13358
- bands[index]->ht_cap.cap |=
13359
- (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
13360
- bands[index]->ht_cap.ht_supported = TRUE;
13361
- bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
13362
- bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
13363
- /* An HT shall support all EQM rates for one spatial stream */
13364
- bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
20133
+ wl_update_ht_cap(bands[index], bw_cap[index], nchain);
1336520134 }
13366
-
1336720135 }
1336820136
1336920137 wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
1337020138 wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
20139
+#ifdef WL_6E
20140
+ wiphy->bands[IEEE80211_BAND_6GHZ] = bands[IEEE80211_BAND_6GHZ];
20141
+#endif /* WL_6E */
1337120142
1337220143 /* check if any bands populated otherwise makes 2Ghz as default */
1337320144 if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL &&
....@@ -13378,34 +20149,77 @@
1337820149
1337920150 if (notify)
1338020151 wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
20152
+#ifdef WL_SAE
20153
+ (void)wl_wiphy_update_sae(wiphy, dhd);
20154
+#endif /* WL_SAE */
1338120155
13382
- end_bands:
13383
- if (rollback_lock)
13384
- mutex_unlock(&cfg->usr_sync);
20156
+ return 0;
20157
+}
20158
+
20159
+s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
20160
+{
20161
+ s32 err;
20162
+
20163
+ mutex_lock(&cfg->usr_sync);
20164
+ err = __wl_update_wiphybands(cfg, notify);
20165
+ mutex_unlock(&cfg->usr_sync);
20166
+
1338520167 return err;
1338620168 }
1338720169
1338820170 static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
1338920171 {
1339020172 s32 err = 0;
20173
+#ifdef WL_HOST_BAND_MGMT
20174
+ s32 ret = 0;
20175
+#endif /* WL_HOST_BAND_MGMT */
20176
+ struct net_info *netinfo = NULL;
1339120177 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
1339220178 struct wireless_dev *wdev = ndev->ieee80211_ptr;
20179
+#ifdef WBTEXT
20180
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
20181
+#endif /* WBTEXT */
20182
+#ifdef WLTDLS
20183
+ u32 tdls;
20184
+#endif /* WLTDLS */
20185
+ u16 wl_iftype = 0;
20186
+ u16 wl_mode = 0;
20187
+ u8 ioctl_buf[WLC_IOCTL_SMLEN];
1339320188
1339420189 WL_DBG(("In\n"));
20190
+
20191
+ /* Reserve 0x8000 toggle bit for P2P GO/GC */
20192
+ cfg->vif_macaddr_mask = 0x8000;
1339520193
1339620194 err = dhd_config_dongle(cfg);
1339720195 if (unlikely(err))
1339820196 return err;
1339920197
13400
- err = wl_config_ifmode(cfg, ndev, wdev->iftype);
20198
+ /* Always bring up interface in STA mode.
20199
+ * Did observe , if previous SofAP Bringup/cleanup
20200
+ * is not done properly, iftype is stuck with AP mode.
20201
+ * So during next wlan0 up, forcing the type to STA
20202
+ */
20203
+ netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
20204
+ if (!netinfo) {
20205
+ WL_ERR(("there is no netinfo\n"));
20206
+ return -ENODEV;
20207
+ }
20208
+ ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
20209
+ netinfo->iftype = WL_IF_TYPE_STA;
20210
+
20211
+ if (cfg80211_to_wl_iftype(wdev->iftype, &wl_iftype, &wl_mode) < 0) {
20212
+ return -EINVAL;
20213
+ }
20214
+ err = wl_config_infra(cfg, ndev, wl_iftype);
1340120215 if (unlikely(err && err != -EINPROGRESS)) {
13402
- WL_ERR(("wl_config_ifmode failed\n"));
20216
+ WL_ERR(("wl_config_infra failed\n"));
1340320217 if (err == -1) {
1340420218 WL_ERR(("return error %d\n", err));
1340520219 return err;
1340620220 }
1340720221 }
13408
- err = wl_update_wiphybands(cfg, true);
20222
+ err = __wl_update_wiphybands(cfg, true);
1340920223 if (unlikely(err)) {
1341020224 WL_ERR(("wl_update_wiphybands failed\n"));
1341120225 if (err == -1) {
....@@ -13413,18 +20227,39 @@
1341320227 return err;
1341420228 }
1341520229 }
13416
-
13417
- err = wl_create_event_handler(cfg);
13418
- if (err) {
13419
- WL_ERR(("wl_create_event_handler failed\n"));
13420
- return err;
20230
+ if (!dhd_download_fw_on_driverload) {
20231
+ err = wl_create_event_handler(cfg);
20232
+ if (err) {
20233
+ WL_ERR(("wl_create_event_handler failed\n"));
20234
+ return err;
20235
+ }
20236
+ wl_init_event_handler(cfg);
1342120237 }
13422
- wl_init_event_handler(cfg);
13423
-
1342420238 err = wl_init_scan(cfg);
1342520239 if (err) {
1342620240 WL_ERR(("wl_init_scan failed\n"));
1342720241 return err;
20242
+ }
20243
+ err = wldev_iovar_getbuf(ndev, "wlc_ver", NULL, 0,
20244
+ &cfg->wlc_ver, sizeof(wl_wlc_version_t), NULL);
20245
+ if (likely(!err)) {
20246
+ WL_INFORM(("wl version. Major: %d\n",
20247
+ cfg->wlc_ver.wlc_ver_major));
20248
+ if ((cfg->wlc_ver.wlc_ver_major >= MIN_ESCAN_PARAM_V2_FW_MAJOR) &&
20249
+ (wldev_iovar_getbuf(ndev, "scan_ver", NULL, 0,
20250
+ ioctl_buf, sizeof(ioctl_buf), NULL) == BCME_OK)) {
20251
+ WL_INFORM_MEM(("scan_params v2\n"));
20252
+ /* use scan_params ver2 */
20253
+ cfg->scan_params_v2 = true;
20254
+ }
20255
+ } else {
20256
+ if (err == BCME_UNSUPPORTED) {
20257
+ /* Ignore on unsupported chips */
20258
+ err = BCME_OK;
20259
+ } else {
20260
+ WL_ERR(("wlc_ver query failed. err: %d\n", err));
20261
+ return err;
20262
+ }
1342820263 }
1342920264 #ifdef DHD_LOSSLESS_ROAMING
1343020265 if (timer_pending(&cfg->roam_timeout)) {
....@@ -13432,7 +20267,61 @@
1343220267 }
1343320268 #endif /* DHD_LOSSLESS_ROAMING */
1343420269
20270
+#ifdef DHD_MONITOR_INTERFACE
1343520271 err = dhd_monitor_init(cfg->pub);
20272
+#endif /* DHD_MONITOR_INTERFACE */
20273
+
20274
+#ifdef WL_HOST_BAND_MGMT
20275
+ /* By default the curr_band is initialized to BAND_AUTO */
20276
+ if ((ret = wl_cfg80211_set_band(ndev, WLC_BAND_AUTO)) < 0) {
20277
+ if (ret == BCME_UNSUPPORTED) {
20278
+ /* Don't fail the initialization, lets just
20279
+ * fall back to the original method
20280
+ */
20281
+ WL_ERR(("WL_HOST_BAND_MGMT defined, "
20282
+ "but roam_band iovar not supported \n"));
20283
+ } else {
20284
+ WL_ERR(("roam_band failed. ret=%d", ret));
20285
+ err = -1;
20286
+ }
20287
+ }
20288
+#endif /* WL_HOST_BAND_MGMT */
20289
+#if defined(WES_SUPPORT)
20290
+ /* Reset WES mode to 0 */
20291
+ wes_mode = 0;
20292
+#endif // endif
20293
+#ifdef WBTEXT
20294
+ /* when wifi up, set roam_prof to default value */
20295
+ if (dhd->wbtext_support) {
20296
+ if (dhd->op_mode & DHD_FLAG_STA_MODE) {
20297
+ wl_cfg80211_wbtext_set_default(ndev);
20298
+ wl_cfg80211_wbtext_clear_bssid_list(cfg);
20299
+ }
20300
+ }
20301
+#endif /* WBTEXT */
20302
+#ifdef WLTDLS
20303
+ if (wldev_iovar_getint(ndev, "tdls_enable", &tdls) == 0) {
20304
+ WL_DBG(("TDLS supported in fw\n"));
20305
+ cfg->tdls_supported = true;
20306
+ }
20307
+#endif /* WLTDLS */
20308
+#ifdef WL_IFACE_MGMT
20309
+#ifdef CUSTOM_IF_MGMT_POLICY
20310
+ cfg->iface_data.policy = CUSTOM_IF_MGMT_POLICY;
20311
+#else
20312
+ cfg->iface_data.policy = WL_IF_POLICY_DEFAULT;
20313
+#endif /* CUSTOM_IF_MGMT_POLICY */
20314
+#endif /* WL_IFACE_MGMT */
20315
+#ifdef WL_NAN
20316
+#ifdef WL_NANP2P
20317
+ if (FW_SUPPORTED(dhd, nanp2p)) {
20318
+ /* Enable NANP2P concurrent support */
20319
+ cfg->conc_disc = WL_NANP2P_CONC_SUPPORT;
20320
+ WL_INFORM_MEM(("nan + p2p conc discovery is supported\n"));
20321
+ cfg->nan_p2p_supported = true;
20322
+ }
20323
+#endif /* WL_NANP2P */
20324
+#endif /* WL_NAN */
1343620325
1343720326 INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
1343820327 wl_set_drv_status(cfg, READY, ndev);
....@@ -13442,29 +20331,36 @@
1344220331 static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
1344320332 {
1344420333 s32 err = 0;
13445
- unsigned long flags;
1344620334 struct net_info *iter, *next;
1344720335 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
13448
-#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF)
20336
+#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
20337
+ defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
1344920338 struct net_device *p2p_net = cfg->p2p_net;
13450
-#endif
13451
-#ifdef PROP_TXSTATUS_VSDB
13452
-#if defined(BCMSDIO) || defined(BCMDBUS)
20339
+#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT) && !PLATFORM_SLP */
1345320340 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
13454
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
13455
-#endif /* PROP_TXSTATUS_VSDB */
13456
- WL_DBG(("In\n"));
13457
- /* Delete pm_enable_work */
13458
- wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
20341
+ WL_INFORM_MEM(("cfg80211 down\n"));
1345920342
13460
-#ifdef WL_NAN
13461
- wl_cfgnan_stop_handler(ndev, g_bcm_cfg, NULL, 0, NULL);
13462
-#endif /* WL_NAN */
20343
+ /* Check if cfg80211 interface is already down */
20344
+ if (!wl_get_drv_status(cfg, READY, ndev)) {
20345
+ WL_DBG(("cfg80211 interface is already down\n"));
20346
+ return err; /* it is even not ready */
20347
+ }
20348
+
20349
+#ifdef SHOW_LOGTRACE
20350
+ /* Stop the event logging */
20351
+ wl_add_remove_eventmsg(ndev, WLC_E_TRACE, FALSE);
20352
+#endif /* SHOW_LOGTRACE */
20353
+
20354
+ /* clear vendor OUI list */
20355
+ wl_vndr_ies_clear_vendor_oui_list(cfg);
20356
+
20357
+ /* Delete pm_enable_work */
20358
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
1346320359
1346420360 if (cfg->p2p_supported) {
1346520361 wl_clr_p2p_status(cfg, GO_NEG_PHASE);
1346620362 #ifdef PROP_TXSTATUS_VSDB
13467
-#if defined(BCMSDIO) || defined(BCMDBUS)
20363
+#if defined(BCMSDIO)
1346820364 if (wl_cfgp2p_vif_created(cfg)) {
1346920365 bool enabled = false;
1347020366 dhd_wlfc_get_enable(dhd, &enabled);
....@@ -13474,63 +20370,88 @@
1347420370 cfg->wlfc_on = false;
1347520371 }
1347620372 }
13477
-#endif /* defined(BCMSDIO) || defined(BCMDBUS) */
20373
+#endif /* defined(BCMSDIO) */
1347820374 #endif /* PROP_TXSTATUS_VSDB */
1347920375 }
1348020376
13481
- /* Check if cfg80211 interface is already down */
13482
- if (!wl_get_drv_status(cfg, READY, ndev)) {
13483
- WL_DBG(("cfg80211 interface is already down"));
13484
- return err; /* it is even not ready */
20377
+#ifdef WL_NAN
20378
+ mutex_lock(&cfg->if_sync);
20379
+ wl_cfgnan_disable(cfg, NAN_BUS_IS_DOWN);
20380
+ mutex_unlock(&cfg->if_sync);
20381
+#endif /* WL_NAN */
20382
+
20383
+ if (!dhd_download_fw_on_driverload) {
20384
+ /* For built-in drivers/other drivers that do reset on
20385
+ * "ifconfig <primary_iface> down", cleanup any left
20386
+ * over interfaces
20387
+ */
20388
+ wl_cfg80211_cleanup_virtual_ifaces(cfg, false);
20389
+ }
20390
+ /* Clear used mac addr mask */
20391
+ cfg->vif_macaddr_mask = 0;
20392
+
20393
+ if (dhd->up)
20394
+ {
20395
+ /* If primary BSS is operational (for e.g SoftAP), bring it down */
20396
+ if (wl_cfg80211_bss_isup(ndev, 0)) {
20397
+ if (wl_cfg80211_bss_up(cfg, ndev, 0, 0) < 0)
20398
+ WL_ERR(("BSS down failed \n"));
20399
+ }
20400
+
20401
+ /* clear all the security setting on primary Interface */
20402
+ wl_cfg80211_clear_security(cfg);
1348520403 }
1348620404
13487
-
13488
- /* If primary BSS is operational (for e.g SoftAP), bring it down */
13489
- if (wl_cfgp2p_bss_isup(ndev, 0)) {
13490
- if (wl_cfgp2p_bss(cfg, ndev, 0, 0) < 0)
13491
- WL_ERR(("BSS down failed \n"));
13492
- }
13493
-
13494
- /* clear all the security setting on primary Interface */
13495
- wl_cfg80211_clear_security(cfg);
13496
-
13497
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
13498
- 4 && __GNUC_MINOR__ >= 6))
13499
-_Pragma("GCC diagnostic push")
13500
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
13501
-#endif
20405
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1350220406 for_each_ndev(cfg, iter, next) {
20407
+ GCC_DIAGNOSTIC_POP();
1350320408 if (iter->ndev) /* p2p discovery iface is null */
1350420409 wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
1350520410 }
13506
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
13507
- 4 && __GNUC_MINOR__ >= 6))
13508
-_Pragma("GCC diagnostic pop")
13509
-#endif
1351020411
13511
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
13512
- if (cfg->scan_request) {
13513
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 8, 0))
13514
- struct cfg80211_scan_info info = { .aborted = true };
13515
- cfg80211_scan_done(cfg->scan_request, &info);
13516
-#else
13517
- cfg80211_scan_done(cfg->scan_request, true);
13518
-#endif
13519
- cfg->scan_request = NULL;
13520
- }
13521
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
13522
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
13523
- 4 && __GNUC_MINOR__ >= 6))
13524
-_Pragma("GCC diagnostic push")
13525
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
13526
-#endif
20412
+#ifdef P2P_LISTEN_OFFLOADING
20413
+ wl_cfg80211_p2plo_deinit(cfg);
20414
+#endif /* P2P_LISTEN_OFFLOADING */
20415
+
20416
+ /* cancel and notify scan complete, if scan request is pending */
20417
+ wl_cfg80211_cancel_scan(cfg);
20418
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1352720419 for_each_ndev(cfg, iter, next) {
20420
+ GCC_DIAGNOSTIC_POP();
1352820421 /* p2p discovery iface ndev ptr could be null */
1352920422 if (iter->ndev == NULL)
1353020423 continue;
1353120424 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
13532
- if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
20425
+ WL_INFORM_MEM(("wl_cfg80211_down. connection state bit status: [%u:%u:%u:%u]"
20426
+ " for %s\n",
20427
+ wl_get_drv_status(cfg, CONNECTING, iter->ndev),
20428
+ wl_get_drv_status(cfg, CONNECTED, iter->ndev),
20429
+ wl_get_drv_status(cfg, DISCONNECTING, iter->ndev),
20430
+ wl_get_drv_status(cfg, NESTED_CONNECT, iter->ndev),
20431
+ iter->ndev->name));
20432
+
20433
+ if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
20434
+ iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
20435
+ wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
20436
+
1353320437 CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
20438
+ }
20439
+
20440
+ if ((iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
20441
+ wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
20442
+
20443
+ u8 *latest_bssid = wl_read_prof(cfg, ndev, WL_PROF_LATEST_BSSID);
20444
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
20445
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
20446
+ struct cfg80211_bss *bss = CFG80211_GET_BSS(wiphy, NULL, latest_bssid,
20447
+ wdev->ssid, wdev->ssid_len);
20448
+
20449
+ BCM_REFERENCE(bss);
20450
+
20451
+ CFG80211_CONNECT_RESULT(ndev,
20452
+ latest_bssid, bss, NULL, 0, NULL, 0,
20453
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
20454
+ GFP_KERNEL);
1353420455 }
1353520456 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
1353620457 wl_clr_drv_status(cfg, READY, iter->ndev);
....@@ -13541,22 +20462,27 @@
1354120462 wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
1354220463 wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
1354320464 wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
20465
+ wl_clr_drv_status(cfg, NESTED_CONNECT, iter->ndev);
20466
+ wl_clr_drv_status(cfg, CFG80211_CONNECT, iter->ndev);
1354420467 }
13545
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
13546
- 4 && __GNUC_MINOR__ >= 6))
13547
-_Pragma("GCC diagnostic pop")
13548
-#endif
1354920468 bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
1355020469 NL80211_IFTYPE_STATION;
13551
-#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF)
20470
+#if defined(WL_CFG80211) && (defined(WL_ENABLE_P2P_IF) || \
20471
+ defined(WL_NEWCFG_PRIVCMD_SUPPORT)) && !defined(PLATFORM_SLP)
20472
+#ifdef SUPPORT_DEEP_SLEEP
20473
+ if (!trigger_deep_sleep)
20474
+#endif /* SUPPORT_DEEP_SLEEP */
1355220475 if (p2p_net)
1355320476 dev_close(p2p_net);
13554
-#endif
20477
+#endif /* WL_CFG80211 && (WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT)&& !PLATFORM_SLP */
1355520478
1355620479 /* Avoid deadlock from wl_cfg80211_down */
13557
- mutex_unlock(&cfg->usr_sync);
13558
- wl_destroy_event_handler(cfg);
13559
- mutex_lock(&cfg->usr_sync);
20480
+ if (!dhd_download_fw_on_driverload) {
20481
+ mutex_unlock(&cfg->usr_sync);
20482
+ wl_destroy_event_handler(cfg);
20483
+ mutex_lock(&cfg->usr_sync);
20484
+ }
20485
+
1356020486 wl_flush_eq(cfg);
1356120487 wl_link_down(cfg);
1356220488 if (cfg->p2p_supported) {
....@@ -13569,28 +20495,34 @@
1356920495 del_timer_sync(&cfg->scan_timeout);
1357020496 }
1357120497
20498
+ wl_cfg80211_clear_mgmt_vndr_ies(cfg);
20499
+#if defined(OEM_ANDROID)
1357220500 DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
20501
+#endif // endif
1357320502
20503
+#ifdef DHD_MONITOR_INTERFACE
1357420504 dhd_monitor_uninit();
20505
+#endif /* DHD_MONITOR_INTERFACE */
20506
+
1357520507 #ifdef WLAIBSS_MCHAN
1357620508 bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
1357720509 #endif /* WLAIBSS_MCHAN */
1357820510
13579
-#if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF)
13580
- /* Clean up if not removed already */
13581
- if (cfg->bss_cfgdev)
13582
- wl_cfg80211_del_iface(cfg->wdev->wiphy, cfg->bss_cfgdev);
13583
-#endif /* defined (WL_VIRTUAL_APSTA) || defined (DUAL_STA_STATIC_IF) */
13584
-
1358520511 #ifdef WL11U
1358620512 /* Clear interworking element. */
1358720513 if (cfg->wl11u) {
20514
+ wl_clear_iwdata(cfg);
1358820515 cfg->wl11u = FALSE;
13589
- cfg->iw_ie_len = 0;
13590
- memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN);
1359120516 }
1359220517 #endif /* WL11U */
1359320518
20519
+#ifdef CUSTOMER_HW4_DEBUG
20520
+ if (wl_scan_timeout_dbg_enabled) {
20521
+ wl_scan_timeout_dbg_clear();
20522
+ }
20523
+#endif /* CUSTOMER_HW4_DEBUG */
20524
+
20525
+ cfg->disable_roam_event = false;
1359420526
1359520527 DNGL_FUNC(dhd_cfg80211_down, (cfg));
1359620528
....@@ -13602,7 +20534,64 @@
1360220534 return err;
1360320535 }
1360420536
13605
-s32 wl_cfg80211_up(void *para)
20537
+#ifdef WL_STATIC_IF
20538
+/* Gets index at which ndev is stored in static_ndev array - using name
20539
+ * Returns error in case match not found. Caller needs to check
20540
+ * validity of return value
20541
+ */
20542
+int
20543
+get_iface_num(const char *name, struct bcm_cfg80211 *cfg)
20544
+{
20545
+ int i = 0;
20546
+ for (i = 0; i < DHD_NUM_STATIC_IFACES; i++) {
20547
+ if (strcmp(name, cfg->static_ndev[i]->name) == 0) {
20548
+ return i;
20549
+ }
20550
+ }
20551
+ return BCME_ERROR;
20552
+}
20553
+
20554
+/* Checks whether interface is static or not by parsing static_ndev array */
20555
+bool
20556
+is_static_iface(struct bcm_cfg80211 *cfg, struct net_device *net)
20557
+{
20558
+ int i = 0;
20559
+ for (i = 0; i < DHD_NUM_STATIC_IFACES; i++) {
20560
+ if ((cfg && (cfg->static_ndev[i] == net))) {
20561
+ return true;
20562
+ }
20563
+ }
20564
+ return false;
20565
+}
20566
+
20567
+/* Checks whether interface is static or not in the case when ndev is not available,
20568
+* using the net dev name which is passed.
20569
+*/
20570
+bool
20571
+is_static_iface_name(const char *name, struct bcm_cfg80211 *cfg)
20572
+{
20573
+ int inum = 0;
20574
+ inum = get_iface_num(name, cfg);
20575
+ if (inum >= 0) {
20576
+ return true;
20577
+ }
20578
+ return false;
20579
+}
20580
+
20581
+/* Returns the static_ndev_state of the virtual interface */
20582
+int
20583
+static_if_ndev_get_state(struct bcm_cfg80211 *cfg, struct net_device *net)
20584
+{
20585
+ int i = 0;
20586
+ for (i = 0; i < DHD_NUM_STATIC_IFACES; i++) {
20587
+ if ((cfg && (cfg->static_ndev[i] == net))) {
20588
+ return cfg->static_ndev_state[i];
20589
+ }
20590
+ }
20591
+ return NDEV_STATE_NONE;
20592
+}
20593
+#endif /* WL_STATIC_IF */
20594
+s32 wl_cfg80211_up(struct net_device *net)
1360620595 {
1360720596 struct bcm_cfg80211 *cfg;
1360820597 s32 err = 0;
....@@ -13614,12 +20603,11 @@
1361420603 s8 iovbuf[WLC_IOCTL_SMLEN];
1361520604 #endif /* DISABLE_PM_BCNRX */
1361620605
13617
- (void)para;
1361820606 WL_DBG(("In\n"));
13619
- cfg = g_bcm_cfg;
20607
+ cfg = wl_get_cfg(net);
1362020608
13621
- if ((err = wldev_ioctl(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
13622
- sizeof(int), false) < 0)) {
20609
+ if ((err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
20610
+ sizeof(int)) < 0)) {
1362320611 WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
1362420612 return err;
1362520613 }
....@@ -13641,63 +20629,104 @@
1364120629 return err;
1364220630 }
1364320631 }
20632
+#if defined(BCMSUP_4WAY_HANDSHAKE)
20633
+ if (dhd->fw_4way_handshake) {
20634
+ /* This is a hacky method to indicate fw 4WHS support and
20635
+ * is used only for kernels (kernels < 3.14). For newer
20636
+ * kernels, we would be using vendor extn. path to advertise
20637
+ * FW based 4-way handshake feature support.
20638
+ */
20639
+ cfg->wdev->wiphy->features |= NL80211_FEATURE_FW_4WAY_HANDSHAKE;
20640
+ }
20641
+#endif /* BCMSUP_4WAY_HANDSHAKE */
1364420642 err = __wl_cfg80211_up(cfg);
1364520643 if (unlikely(err))
1364620644 WL_ERR(("__wl_cfg80211_up failed\n"));
1364720645
13648
-
20646
+#ifdef ROAM_CHANNEL_CACHE
20647
+ if (init_roam_cache(cfg, ioctl_version) == 0) {
20648
+ /* Enable support for Roam cache */
20649
+ cfg->rcc_enabled = true;
20650
+ WL_ERR(("Roam channel cache enabled\n"));
20651
+ } else {
20652
+ WL_ERR(("Failed to enable RCC.\n"));
20653
+ }
20654
+#endif /* ROAM_CHANNEL_CACHE */
1364920655
1365020656 /* IOVAR configurations with 'up' condition */
1365120657 #ifdef DISABLE_PM_BCNRX
13652
- interr = wldev_iovar_setbuf(bcmcfg_to_prmry_ndev(cfg), "pm_bcnrx",
13653
- (char *)&param, sizeof(param), iovbuf, sizeof(iovbuf), &cfg->ioctl_buf_sync);
20658
+ interr = wldev_iovar_setbuf(net, "pm_bcnrx", (char *)&param, sizeof(param), iovbuf,
20659
+ sizeof(iovbuf), &cfg->ioctl_buf_sync);
1365420660
13655
- if (unlikely(interr))
13656
- WL_ERR(("Set pm_bcnrx error (%d)\n", interr));
20661
+ if (unlikely(interr)) {
20662
+ WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
20663
+ }
1365720664 #endif /* DISABLE_PM_BCNRX */
20665
+#ifdef WL_CHAN_UTIL
20666
+ interr = wl_cfg80211_start_bssload_report(net);
20667
+ if (unlikely(interr)) {
20668
+ WL_ERR(("%s: Failed to start bssload_report eventing, err=%d\n",
20669
+ __FUNCTION__, interr));
20670
+ }
20671
+#endif /* WL_CHAN_UTIL */
1365820672
1365920673 mutex_unlock(&cfg->usr_sync);
1366020674
1366120675 #ifdef WLAIBSS_MCHAN
1366220676 bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
1366320677 #endif /* WLAIBSS_MCHAN */
13664
-
13665
-#ifdef DUAL_STA_STATIC_IF
13666
-#ifdef WL_VIRTUAL_APSTA
13667
-#error "Both DUAL STA and DUAL_STA_STATIC_IF can't be enabled together"
13668
-#endif
13669
- /* Static Interface support is currently supported only for STA only builds (without P2P) */
13670
- wl_cfg80211_create_iface(cfg->wdev->wiphy, NL80211_IFTYPE_STATION, NULL, "wlan%d");
13671
-#endif /* DUAL_STA_STATIC_IF */
13672
-
1367320678 return err;
1367420679 }
1367520680
1367620681 /* Private Event to Supplicant with indication that chip hangs */
1367720682 int wl_cfg80211_hang(struct net_device *dev, u16 reason)
1367820683 {
13679
- struct bcm_cfg80211 *cfg;
20684
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20685
+ dhd_pub_t *dhd;
1368020686 #if defined(SOFTAP_SEND_HANGEVT)
1368120687 /* specifc mac address used for hang event */
1368220688 uint8 hang_mac[ETHER_ADDR_LEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
13683
- dhd_pub_t *dhd;
1368420689 #endif /* SOFTAP_SEND_HANGEVT */
13685
- if (!g_bcm_cfg) {
20690
+ if (!cfg) {
1368620691 return BCME_ERROR;
1368720692 }
1368820693
13689
- cfg = g_bcm_cfg;
20694
+ RETURN_EIO_IF_NOT_UP(cfg);
1369020695
13691
- WL_ERR(("In : chip crash eventing\n"));
13692
- wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
13693
-#if defined(SOFTAP_SEND_HANGEVT)
1369420696 dhd = (dhd_pub_t *)(cfg->pub);
20697
+#if defined(DHD_HANG_SEND_UP_TEST)
20698
+ if (dhd->req_hang_type) {
20699
+ WL_ERR(("wl_cfg80211_hang, Clear HANG test request 0x%x\n",
20700
+ dhd->req_hang_type));
20701
+ dhd->req_hang_type = 0;
20702
+ }
20703
+#endif /* DHD_HANG_SEND_UP_TEST */
20704
+ if ((dhd->hang_reason <= HANG_REASON_MASK) || (dhd->hang_reason >= HANG_REASON_MAX)) {
20705
+ WL_ERR(("wl_cfg80211_hang, Invalid hang reason 0x%x\n",
20706
+ dhd->hang_reason));
20707
+ dhd->hang_reason = HANG_REASON_UNKNOWN;
20708
+ }
20709
+#if defined(DHD_USE_EXTENDED_HANG_REASON) || defined(WL_CFGVENDOR_SEND_HANG_EVENT)
20710
+ if (dhd->hang_reason != 0) {
20711
+ reason = dhd->hang_reason;
20712
+ }
20713
+#endif /* DHD_USE_EXTENDED_HANG_REASON */
20714
+ WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32)(dhd->hang_reason)));
20715
+
20716
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
20717
+#ifdef SOFTAP_SEND_HANGEVT
1369520718 if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
1369620719 cfg80211_del_sta(dev, hang_mac, GFP_ATOMIC);
1369720720 } else
1369820721 #endif /* SOFTAP_SEND_HANGEVT */
1369920722 {
13700
- CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
20723
+ if (dhd->up == TRUE) {
20724
+#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
20725
+ wl_cfgvendor_send_hang_event(dev, reason);
20726
+#else
20727
+ CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
20728
+#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
20729
+ }
1370120730 }
1370220731 if (cfg != NULL) {
1370320732 wl_link_down(cfg);
....@@ -13705,14 +20734,12 @@
1370520734 return 0;
1370620735 }
1370720736
13708
-s32 wl_cfg80211_down(void *para)
20737
+s32 wl_cfg80211_down(struct net_device *dev)
1370920738 {
13710
- struct bcm_cfg80211 *cfg;
13711
- s32 err = 0;
20739
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
20740
+ s32 err = BCME_ERROR;
1371220741
13713
- (void)para;
1371420742 WL_DBG(("In\n"));
13715
- cfg = g_bcm_cfg;
1371620743
1371720744 if (cfg) {
1371820745 mutex_lock(&cfg->usr_sync);
....@@ -13723,48 +20750,26 @@
1372320750 return err;
1372420751 }
1372520752
13726
-#if (defined(STBLINUX) && defined(WL_CFG80211))
13727
-int wl_cfg80211_cleanup(void)
20753
+void
20754
+wl_cfg80211_sta_ifdown(struct net_device *dev)
1372820755 {
13729
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
13730
- struct net_device *ndev;
13731
- unsigned long flags;
20756
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1373220757
13733
- if (!cfg)
13734
- return -EINVAL;
20758
+ WL_DBG(("In\n"));
1373520759
13736
- ndev = bcmcfg_to_prmry_ndev(cfg);
13737
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
13738
- if (cfg->scan_request) {
13739
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 8, 0))
13740
- struct cfg80211_scan_info info = { .aborted = true };
13741
- cfg80211_scan_done(cfg->scan_request, &info);
13742
-#else
13743
- cfg80211_scan_done(cfg->scan_request, true);
13744
-#endif
13745
- cfg->scan_request = NULL;
20760
+ if (cfg) {
20761
+ /* cancel scan if anything pending */
20762
+ wl_cfg80211_cancel_scan(cfg);
20763
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
20764
+ if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION) &&
20765
+ wl_get_drv_status(cfg, CONNECTED, dev)) {
20766
+ CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
20767
+ }
20768
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
1374620769 }
13747
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
13748
-
13749
- if (wl_get_drv_status(cfg, CONNECTED, ndev) ||
13750
- wl_get_drv_status(cfg, CONNECTING, ndev)) {
13751
- CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
13752
- }
13753
-
13754
- /* clear all flags */
13755
- wl_clr_drv_status(cfg, SCANNING, ndev);
13756
- wl_clr_drv_status(cfg, CONNECTING, ndev);
13757
- wl_clr_drv_status(cfg, CONNECTED, ndev);
13758
-
13759
- /* Let kernel thread to handle the event */
13760
- cond_resched();
13761
- mdelay(500);
13762
-
13763
- return 0;
1376420770 }
13765
-#endif /* STBLINUX && WL_CFG80211 */
1376620771
13767
-static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
20772
+void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
1376820773 {
1376920774 unsigned long flags;
1377020775 void *rptr = NULL;
....@@ -13772,7 +20777,7 @@
1377220777
1377320778 if (!profile)
1377420779 return NULL;
13775
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
20780
+ WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
1377620781 switch (item) {
1377720782 case WL_PROF_SEC:
1377820783 rptr = &profile->sec;
....@@ -13789,8 +20794,11 @@
1378920794 case WL_PROF_CHAN:
1379020795 rptr = &profile->channel;
1379120796 break;
20797
+ case WL_PROF_LATEST_BSSID:
20798
+ rptr = profile->latest_bssid;
20799
+ break;
1379220800 }
13793
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
20801
+ WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
1379420802 if (!rptr)
1379520803 WL_ERR(("invalid item (%d)\n", item));
1379620804 return rptr;
....@@ -13807,20 +20815,20 @@
1380720815
1380820816 if (!profile)
1380920817 return WL_INVALID;
13810
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
20818
+ WL_CFG_DRV_LOCK(&cfg->cfgdrv_lock, flags);
1381120819 switch (item) {
1381220820 case WL_PROF_SSID:
1381320821 ssid = (const wlc_ssid_t *) data;
13814
- memset(profile->ssid.SSID, 0,
20822
+ bzero(profile->ssid.SSID,
1381520823 sizeof(profile->ssid.SSID));
13816
- memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
13817
- profile->ssid.SSID_len = ssid->SSID_len;
20824
+ profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
20825
+ memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
1381820826 break;
1381920827 case WL_PROF_BSSID:
1382020828 if (data)
1382120829 memcpy(profile->bssid, data, ETHER_ADDR_LEN);
1382220830 else
13823
- memset(profile->bssid, 0, ETHER_ADDR_LEN);
20831
+ bzero(profile->bssid, ETHER_ADDR_LEN);
1382420832 break;
1382520833 case WL_PROF_SEC:
1382620834 memcpy(&profile->sec, data, sizeof(profile->sec));
....@@ -13837,11 +20845,20 @@
1383720845 case WL_PROF_CHAN:
1383820846 profile->channel = *(const u32*)data;
1383920847 break;
20848
+ case WL_PROF_LATEST_BSSID:
20849
+ if (data) {
20850
+ memcpy_s(profile->latest_bssid, sizeof(profile->latest_bssid),
20851
+ data, ETHER_ADDR_LEN);
20852
+ } else {
20853
+ memset_s(profile->latest_bssid, sizeof(profile->latest_bssid),
20854
+ 0, ETHER_ADDR_LEN);
20855
+ }
20856
+ break;
1384020857 default:
1384120858 err = -EOPNOTSUPP;
1384220859 break;
1384320860 }
13844
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
20861
+ WL_CFG_DRV_UNLOCK(&cfg->cfgdrv_lock, flags);
1384520862
1384620863 if (err == -EOPNOTSUPP)
1384720864 WL_ERR(("unsupported item (%d)\n", item));
....@@ -13875,6 +20892,7 @@
1387520892 struct wl_ie *ie = wl_to_ie(cfg);
1387620893
1387720894 ie->offset = 0;
20895
+ bzero(ie->buf, sizeof(ie->buf));
1387820896 }
1387920897
1388020898 static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
....@@ -13894,41 +20912,63 @@
1389420912 return err;
1389520913 }
1389620914
13897
-static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, const u8 *ie_stream, u32 *ie_size,
13898
- bool roam)
20915
+static void wl_update_hidden_ap_ie(wl_bss_info_t *bi, const u8 *ie_stream, u32 *ie_size,
20916
+ bool update_ssid)
1389920917 {
1390020918 u8 *ssidie;
20919
+ int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN);
20920
+ int32 remaining_ie_buf_len, available_buffer_len, unused_buf_len;
1390120921 /* cfg80211_find_ie defined in kernel returning const u8 */
13902
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
13903
- 4 && __GNUC_MINOR__ >= 6))
13904
-_Pragma("GCC diagnostic push")
13905
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
13906
-#endif
20922
+
20923
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1390720924 ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
13908
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
13909
- 4 && __GNUC_MINOR__ >= 6))
13910
-_Pragma("GCC diagnostic pop")
13911
-#endif
13912
- if (!ssidie)
20925
+ GCC_DIAGNOSTIC_POP();
20926
+
20927
+ /* ERROR out if
20928
+ * 1. No ssid IE is FOUND or
20929
+ * 2. New ssid length is > what was allocated for existing ssid (as
20930
+ * we do not want to overwrite the rest of the IEs) or
20931
+ * 3. If in case of erroneous buffer input where ssid length doesnt match the space
20932
+ * allocated to it.
20933
+ */
20934
+ if (!ssidie) {
1391320935 return;
13914
- if (ssidie[1] != bi->SSID_len) {
20936
+ }
20937
+ available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream);
20938
+ remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
20939
+ unused_buf_len = WL_EXTRA_BUF_MAX - (4 + bi->length + *ie_size);
20940
+ if (ssidie[1] > available_buffer_len) {
20941
+ WL_ERR_MEM(("wl_update_hidden_ap_ie: skip wl_update_hidden_ap_ie : overflow\n"));
20942
+ return;
20943
+ }
20944
+
20945
+ if (ssidie[1] != ssid_len) {
1391520946 if (ssidie[1]) {
13916
- WL_ERR(("%s: Wrong SSID len: %d != %d\n",
13917
- __FUNCTION__, ssidie[1], bi->SSID_len));
20947
+ WL_ERR_RLMT(("wl_update_hidden_ap_ie: Wrong SSID len: %d != %d\n",
20948
+ ssidie[1], bi->SSID_len));
1391820949 }
13919
- if (roam) {
13920
- WL_ERR(("Changing the SSID Info.\n"));
13921
- memmove(ssidie + bi->SSID_len + 2,
20950
+ /*
20951
+ * The bss info in firmware gets updated from beacon and probe resp.
20952
+ * In case of hidden network, the bss_info that got updated by beacon,
20953
+ * will not carry SSID and this can result in cfg80211_get_bss not finding a match.
20954
+ * so include the SSID element.
20955
+ */
20956
+ if ((update_ssid && (ssid_len > ssidie[1])) && (unused_buf_len > ssid_len)) {
20957
+ WL_INFORM_MEM(("Changing the SSID Info.\n"));
20958
+ memmove(ssidie + ssid_len + 2,
1392220959 (ssidie + 2) + ssidie[1],
13923
- *ie_size - (ssidie + 2 + ssidie[1] - ie_stream));
13924
- memcpy(ssidie + 2, bi->SSID, bi->SSID_len);
13925
- *ie_size = *ie_size + bi->SSID_len - ssidie[1];
13926
- ssidie[1] = bi->SSID_len;
20960
+ remaining_ie_buf_len);
20961
+ memcpy(ssidie + 2, bi->SSID, ssid_len);
20962
+ *ie_size = *ie_size + ssid_len - ssidie[1];
20963
+ ssidie[1] = ssid_len;
20964
+ } else if (ssid_len < ssidie[1]) {
20965
+ WL_ERR_MEM(("wl_update_hidden_ap_ie: Invalid SSID len: %d < %d\n",
20966
+ bi->SSID_len, ssidie[1]));
1392720967 }
1392820968 return;
1392920969 }
1393020970 if (*(ssidie + 2) == '\0')
13931
- memcpy(ssidie + 2, bi->SSID, bi->SSID_len);
20971
+ memcpy(ssidie + 2, bi->SSID, ssid_len);
1393220972 return;
1393320973 }
1393420974
....@@ -13987,13 +21027,13 @@
1398721027 {
1398821028 unsigned long flags;
1398921029
13990
- spin_lock_irqsave(&cfg->eq_lock, flags);
21030
+ WL_CFG_EQ_LOCK(&cfg->eq_lock, flags);
1399121031 return flags;
1399221032 }
1399321033
1399421034 static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
1399521035 {
13996
- spin_unlock_irqrestore(&cfg->eq_lock, flags);
21036
+ WL_CFG_EQ_UNLOCK(&cfg->eq_lock, flags);
1399721037 }
1399821038
1399921039 static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
....@@ -14012,13 +21052,14 @@
1401221052
1401321053 s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
1401421054 {
14015
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
21055
+ struct bcm_cfg80211 *cfg = wl_get_cfg(net);
1401621056 struct ether_addr primary_mac;
1401721057 if (!cfg->p2p)
1401821058 return -1;
1401921059 if (!p2p_is_on(cfg)) {
1402021060 get_primary_mac(cfg, &primary_mac);
1402121061 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
21062
+ memcpy((void *)&p2pdev_addr, (void *)&primary_mac, ETHER_ADDR_LEN);
1402221063 } else {
1402321064 memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
1402421065 ETHER_ADDR_LEN);
....@@ -14028,35 +21069,37 @@
1402821069 }
1402921070 s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
1403021071 {
14031
- struct bcm_cfg80211 *cfg;
14032
-
14033
- cfg = g_bcm_cfg;
21072
+ struct bcm_cfg80211 *cfg = wl_get_cfg(net);
1403421073
1403521074 return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
1403621075 }
1403721076
1403821077 s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
1403921078 {
14040
- struct bcm_cfg80211 *cfg;
14041
- cfg = g_bcm_cfg;
21079
+ struct bcm_cfg80211 *cfg = wl_get_cfg(net);
1404221080
1404321081 return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
1404421082 }
1404521083
1404621084 s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
1404721085 {
14048
- struct bcm_cfg80211 *cfg;
14049
- cfg = g_bcm_cfg;
21086
+ struct bcm_cfg80211 *cfg = wl_get_cfg(net);
1405021087
1405121088 return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
1405221089 }
1405321090
1405421091 s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
1405521092 {
14056
- struct bcm_cfg80211 *cfg;
14057
- cfg = g_bcm_cfg;
21093
+ struct bcm_cfg80211 *cfg = wl_get_cfg(net);
1405821094
1405921095 return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
21096
+}
21097
+
21098
+s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
21099
+{
21100
+ struct bcm_cfg80211 *cfg = wl_get_cfg(net);
21101
+
21102
+ return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
1406021103 }
1406121104
1406221105 #ifdef P2PLISTEN_AP_SAMECHN
....@@ -14068,7 +21111,7 @@
1406821111 /* disable PM for p2p responding on infra AP channel */
1406921112 s32 pm = PM_OFF;
1407021113
14071
- ret = wldev_ioctl(net, WLC_SET_PM, &pm, sizeof(pm), true);
21114
+ ret = wldev_ioctl_set(net, WLC_SET_PM, &pm, sizeof(pm));
1407221115 }
1407321116
1407421117 return ret;
....@@ -14079,7 +21122,7 @@
1407921122 {
1408021123 int freq = 0;
1408121124
14082
-#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
21125
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
1408321126 freq = ieee80211_channel_to_frequency(channel);
1408421127 #else
1408521128 {
....@@ -14090,13 +21133,12 @@
1409021133 band = IEEE80211_BAND_5GHZ;
1409121134 freq = ieee80211_channel_to_frequency(channel, band);
1409221135 }
14093
-#endif
21136
+#endif // endif
1409421137 return freq;
1409521138 }
1409621139
14097
-
1409821140 #ifdef WLTDLS
14099
-static s32
21141
+s32
1410021142 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1410121143 const wl_event_msg_t *e, void *data) {
1410221144
....@@ -14111,45 +21153,46 @@
1411121153 msg = " TDLS PEER DISCOVERD ";
1411221154 break;
1411321155 case WLC_E_TDLS_PEER_CONNECTED :
14114
-#ifdef PCIE_FULL_DONGLE
14115
- dhd_tdls_update_peer_info(ndev, TRUE, (uint8 *)&e->addr.octet[0]);
14116
-#endif /* PCIE_FULL_DONGLE */
1411721156 if (cfg->tdls_mgmt_frame) {
1411821157 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
1411921158 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
14120
- cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
14121
- 0);
21159
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0);
1412221160 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
1412321161 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
14124
- cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
14125
- 0, GFP_ATOMIC);
21162
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0,
21163
+ GFP_ATOMIC);
1412621164 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
14127
- defined(WL_COMPAT_WIRELESS)
21165
+ defined(WL_COMPAT_WIRELESS)
1412821166 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
14129
- cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
14130
- GFP_ATOMIC);
21167
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
21168
+ GFP_ATOMIC);
1413121169 #else
1413221170 cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
14133
- cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
14134
- GFP_ATOMIC);
14135
-#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */
21171
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, GFP_ATOMIC);
21172
+
21173
+#endif /* LINUX_VERSION >= VERSION(3, 18,0) || WL_COMPAT_WIRELESS */
1413621174 }
1413721175 msg = " TDLS PEER CONNECTED ";
21176
+#ifdef SUPPORT_SET_CAC
21177
+ /* TDLS connect reset CAC */
21178
+ wl_cfg80211_set_cac(cfg, 0);
21179
+#endif /* SUPPORT_SET_CAC */
1413821180 break;
1413921181 case WLC_E_TDLS_PEER_DISCONNECTED :
14140
-#ifdef PCIE_FULL_DONGLE
14141
- dhd_tdls_update_peer_info(ndev, FALSE, (uint8 *)&e->addr.octet[0]);
14142
-#endif /* PCIE_FULL_DONGLE */
1414321182 if (cfg->tdls_mgmt_frame) {
14144
- kfree(cfg->tdls_mgmt_frame);
14145
- cfg->tdls_mgmt_frame = NULL;
21183
+ MFREE(cfg->osh, cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len);
21184
+ cfg->tdls_mgmt_frame_len = 0;
1414621185 cfg->tdls_mgmt_freq = 0;
1414721186 }
1414821187 msg = "TDLS PEER DISCONNECTED ";
21188
+#ifdef SUPPORT_SET_CAC
21189
+ /* TDLS disconnec, set CAC */
21190
+ wl_cfg80211_set_cac(cfg, 1);
21191
+#endif /* SUPPORT_SET_CAC */
1414921192 break;
1415021193 }
1415121194 if (msg) {
14152
- WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((u8*)(&e->addr)),
21195
+ WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((const u8*)(&e->addr)),
1415321196 (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
1415421197 }
1415521198 return 0;
....@@ -14157,79 +21200,88 @@
1415721200 }
1415821201 #endif /* WLTDLS */
1415921202
14160
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
14161
-static s32
21203
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
1416221204 #if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
1416321205 KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
21206
+static s32
1416421207 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
14165
- u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
14166
- u32 peer_capability, const u8 *data, size_t len)
21208
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
21209
+ u32 peer_capability, const u8 *buf, size_t len)
1416721210 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
1416821211 (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
14169
-wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
21212
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
1417021213 const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
14171
- u32 peer_capability, const u8 *data, size_t len)
21214
+ u32 peer_capability, const u8 *buf, size_t len)
1417221215 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
21216
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
21217
+ const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
21218
+ u32 peer_capability, bool initiator, const u8 *buf, size_t len)
21219
+#else /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
21220
+static s32
1417321221 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
14174
- const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
14175
- u32 peer_capability, bool initiator, const u8 *data, size_t len)
14176
-#else
14177
-wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
14178
- u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data,
14179
- size_t len)
14180
-#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
21222
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
21223
+ const u8 *buf, size_t len)
21224
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
1418121225 {
1418221226 s32 ret = 0;
14183
-#ifdef WLTDLS
21227
+#if defined(TDLS_MSG_ONLY_WFD) && defined(WLTDLS)
1418421228 struct bcm_cfg80211 *cfg;
1418521229 tdls_wfd_ie_iovar_t info;
14186
- memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
14187
- cfg = g_bcm_cfg;
21230
+ bzero(&info, sizeof(info));
21231
+ cfg = wl_get_cfg(dev);
1418821232
1418921233 #if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
1419021234 /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
14191
- * and that cuases build error
14192
- */
21235
+ * and that cuases build error
21236
+ */
1419321237 BCM_REFERENCE(peer_capability);
1419421238 #endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
1419521239
1419621240 switch (action_code) {
14197
- /* We need to set TDLS Wifi Display IE to firmware
14198
- * using tdls_wfd_ie iovar
14199
- */
14200
- case WLAN_TDLS_SET_PROBE_WFD_IE:
14201
- WL_ERR(("%s WLAN_TDLS_SET_PROBE_WFD_IE\n", __FUNCTION__));
14202
- info.mode = TDLS_WFD_PROBE_IE_TX;
14203
- memcpy(&info.data, data, len);
14204
- info.length = len;
14205
- break;
14206
- case WLAN_TDLS_SET_SETUP_WFD_IE:
14207
- WL_ERR(("%s WLAN_TDLS_SET_SETUP_WFD_IE\n", __FUNCTION__));
14208
- info.mode = TDLS_WFD_IE_TX;
14209
- memcpy(&info.data, data, len);
14210
- info.length = len;
14211
- break;
14212
- case WLAN_TDLS_SET_WFD_ENABLED:
14213
- WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_ENABLED\n", __FUNCTION__));
14214
- dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
14215
- goto out;
14216
- case WLAN_TDLS_SET_WFD_DISABLED:
14217
- WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_DISABLED\n", __FUNCTION__));
14218
- dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
14219
- goto out;
14220
- default:
14221
- WL_ERR(("Unsupported action code : %d\n", action_code));
14222
- goto out;
14223
- }
21241
+ /* We need to set TDLS Wifi Display IE to firmware
21242
+ * using tdls_wfd_ie iovar
21243
+ */
21244
+ case WLAN_TDLS_SET_PROBE_WFD_IE:
21245
+ WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_PROBE_WFD_IE\n"));
21246
+ info.mode = TDLS_WFD_PROBE_IE_TX;
1422421247
21248
+ if (len > sizeof(info.data)) {
21249
+ return -EINVAL;
21250
+ }
21251
+ memcpy(&info.data, buf, len);
21252
+ info.length = len;
21253
+ break;
21254
+ case WLAN_TDLS_SET_SETUP_WFD_IE:
21255
+ WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_SETUP_WFD_IE\n"));
21256
+ info.mode = TDLS_WFD_IE_TX;
21257
+
21258
+ if (len > sizeof(info.data)) {
21259
+ return -EINVAL;
21260
+ }
21261
+ memcpy(&info.data, buf, len);
21262
+ info.length = len;
21263
+ break;
21264
+ case WLAN_TDLS_SET_WFD_ENABLED:
21265
+ WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_ENABLED\n"));
21266
+ dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
21267
+ goto out;
21268
+ case WLAN_TDLS_SET_WFD_DISABLED:
21269
+ WL_ERR(("wl_cfg80211_tdls_mgmt: WLAN_TDLS_SET_MODE_WFD_DISABLED\n"));
21270
+ dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
21271
+ goto out;
21272
+ default:
21273
+ WL_ERR(("Unsupported action code : %d\n", action_code));
21274
+ goto out;
21275
+ }
1422521276 ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
14226
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
21277
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
1422721278
1422821279 if (ret) {
1422921280 WL_ERR(("tdls_wfd_ie error %d\n", ret));
1423021281 }
21282
+
1423121283 out:
14232
-#endif /* WLTDLS */
21284
+#endif /* TDLS_MSG_ONLY_WFD && WLTDLS */
1423321285 return ret;
1423421286 }
1423521287
....@@ -14241,17 +21293,16 @@
1424121293 static s32
1424221294 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
1424321295 u8 *peer, enum nl80211_tdls_operation oper)
14244
-#endif
21296
+#endif // endif
1424521297 {
1424621298 s32 ret = 0;
1424721299 #ifdef WLTDLS
14248
- struct bcm_cfg80211 *cfg;
21300
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1424921301 tdls_iovar_t info;
1425021302 dhd_pub_t *dhdp;
1425121303 bool tdls_auto_mode = false;
14252
- cfg = g_bcm_cfg;
1425321304 dhdp = (dhd_pub_t *)(cfg->pub);
14254
- memset(&info, 0, sizeof(tdls_iovar_t));
21305
+ bzero(&info, sizeof(tdls_iovar_t));
1425521306 if (peer) {
1425621307 memcpy(&info.ea, peer, ETHER_ADDR_LEN);
1425721308 } else {
....@@ -14264,7 +21315,7 @@
1426421315 */
1426521316 if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
1426621317 info.mode = TDLS_MANUAL_EP_WFD_TPQ;
14267
- WL_ERR(("%s TDLS TUNNELED PRBOBE REQUEST\n", __FUNCTION__));
21318
+ WL_ERR(("wl_cfg80211_tdls_oper: TDLS TUNNELED PRBOBE REQUEST\n"));
1426821319 } else {
1426921320 info.mode = TDLS_MANUAL_EP_DISCOVERY;
1427021321 }
....@@ -14273,7 +21324,8 @@
1427321324 if (dhdp->tdls_mode == true) {
1427421325 info.mode = TDLS_MANUAL_EP_CREATE;
1427521326 tdls_auto_mode = false;
14276
- ret = dhd_tdls_enable(dev, false, tdls_auto_mode, NULL);
21327
+ /* Do tear down and create a fresh one */
21328
+ ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_TEARDOWN, tdls_auto_mode);
1427721329 if (ret < 0) {
1427821330 return ret;
1427921331 }
....@@ -14289,10 +21341,9 @@
1428921341 goto out;
1429021342 }
1429121343 /* turn on TDLS */
14292
- ret = dhd_tdls_enable(dev, true, tdls_auto_mode, NULL);
21344
+ ret = wl_cfg80211_tdls_config(cfg, TDLS_STATE_SETUP, tdls_auto_mode);
1429321345 if (ret < 0) {
1429421346 return ret;
14295
-
1429621347 }
1429721348 if (info.mode) {
1429821349 ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
....@@ -14302,54 +21353,65 @@
1430221353 }
1430321354 }
1430421355 out:
21356
+ if (ret) {
21357
+ wl_flush_fw_log_buffer(dev, FW_LOGSET_MASK_ALL);
21358
+ return -ENOTSUPP;
21359
+ }
1430521360 #endif /* WLTDLS */
1430621361 return ret;
1430721362 }
14308
-#endif
21363
+#endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
1430921364
14310
-s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
21365
+s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
1431121366 enum wl_management_type type)
1431221367 {
1431321368 struct bcm_cfg80211 *cfg;
14314
- struct net_device *ndev = NULL;
14315
- struct ether_addr primary_mac;
1431621369 s32 ret = 0;
21370
+ struct ether_addr primary_mac;
1431721371 s32 bssidx = 0;
1431821372 s32 pktflag = 0;
14319
- cfg = g_bcm_cfg;
21373
+ cfg = wl_get_cfg(ndev);
1432021374
14321
- if (wl_get_drv_status(cfg, AP_CREATING, net)) {
21375
+ if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
1432221376 /* Vendor IEs should be set to FW
1432321377 * after SoftAP interface is brought up
1432421378 */
21379
+ WL_DBG(("Skipping set IE since AP is not up \n"));
1432521380 goto exit;
14326
- } else if (wl_get_drv_status(cfg, AP_CREATED, net)) {
14327
- ndev = net;
14328
- bssidx = 0;
14329
- } else if (cfg->p2p) {
14330
- net = ndev_to_wlc_ndev(net, cfg);
14331
- if (!cfg->p2p->on) {
14332
- get_primary_mac(cfg, &primary_mac);
14333
- wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
14334
- /* In case of p2p_listen command, supplicant send remain_on_channel
14335
- * without turning on P2P
14336
- */
14337
-
14338
- p2p_on(cfg) = true;
14339
- ret = wl_cfgp2p_enable_discovery(cfg, net, NULL, 0);
14340
-
14341
- if (unlikely(ret)) {
21381
+ } else if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
21382
+ /* Either stand alone AP case or P2P discovery */
21383
+ if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
21384
+ /* Stand alone AP case on primary interface */
21385
+ WL_DBG(("Apply IEs for Primary AP Interface \n"));
21386
+ bssidx = 0;
21387
+ } else {
21388
+ if (!cfg->p2p) {
21389
+ /* If p2p not initialized, return failure */
21390
+ WL_ERR(("P2P not initialized \n"));
1434221391 goto exit;
1434321392 }
14344
- }
14345
- if (net == bcmcfg_to_prmry_ndev(cfg)) {
21393
+ /* P2P Discovery case (p2p listen) */
21394
+ if (!cfg->p2p->on) {
21395
+ /* Turn on Discovery interface */
21396
+ get_primary_mac(cfg, &primary_mac);
21397
+ wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
21398
+ p2p_on(cfg) = true;
21399
+ ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
21400
+ if (unlikely(ret)) {
21401
+ WL_ERR(("Enable discovery failed \n"));
21402
+ goto exit;
21403
+ }
21404
+ }
21405
+ WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
1434621406 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
1434721407 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
14348
- } else {
14349
- ndev = net;
14350
- bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
14351
- }
21408
+ }
21409
+ } else {
21410
+ /* Virtual AP/ P2P Group Interface */
21411
+ WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
21412
+ bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
1435221413 }
21414
+
1435321415 if (ndev != NULL) {
1435421416 switch (type) {
1435521417 case WL_BEACON:
....@@ -14362,9 +21424,10 @@
1436221424 pktflag = VNDR_IE_ASSOCRSP_FLAG;
1436321425 break;
1436421426 }
14365
- if (pktflag)
21427
+ if (pktflag) {
1436621428 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
1436721429 ndev_to_cfgdev(ndev), bssidx, pktflag, buf, len);
21430
+ }
1436821431 }
1436921432 exit:
1437021433 return ret;
....@@ -14376,23 +21439,11 @@
1437621439 {
1437721440 u32 val = 0;
1437821441 s32 ret = BCME_ERROR;
14379
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
14380
-
14381
- /* Disable mpc, to avoid automatic interface down. */
14382
- val = 0;
14383
-
14384
- ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val,
14385
- sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
14386
- &cfg->ioctl_buf_sync);
14387
- if (ret < 0) {
14388
- WL_ERR(("set 'mpc' failed, error = %d\n", ret));
14389
- goto done;
14390
- }
14391
-
21442
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1439221443 /* Set interface up, explicitly. */
1439321444 val = 1;
1439421445
14395
- ret = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true);
21446
+ ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
1439621447 if (ret < 0) {
1439721448 WL_ERR(("set interface up failed, error = %d\n", ret));
1439821449 goto done;
....@@ -14404,36 +21455,46 @@
1440421455 ret = BCME_OK;
1440521456 goto done;
1440621457 }
14407
- ret = wl_notify_escan_complete(cfg, ndev, true, true);
14408
- if (ret < 0) {
14409
- WL_ERR(("set scan abort failed, error = %d\n", ret));
14410
- goto done;
14411
- }
21458
+
21459
+ wl_cfg80211_cancel_scan(cfg);
1441221460
1441321461 done:
1441421462 return ret;
1441521463 }
1441621464
1441721465 static bool
14418
-wl_cfg80211_valid_channel_p2p(int channel)
21466
+wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec)
1441921467 {
1442021468 bool valid = false;
21469
+ char chanbuf[CHANSPEC_STR_LEN];
1442121470
1442221471 /* channel 1 to 14 */
14423
- if ((channel >= 1) && (channel <= 14)) {
21472
+ if ((chanspec >= 0x2b01) && (chanspec <= 0x2b0e)) {
1442421473 valid = true;
1442521474 }
21475
+#ifdef IGUANA_LEGACY_CHIPS
1442621476 /* channel 36 to 48 */
14427
- else if ((channel >= 36) && (channel <= 48)) {
21477
+ else if ((chanspec >= 0xd024) && (chanspec <= 0xd030)) {
1442821478 valid = true;
1442921479 }
1443021480 /* channel 149 to 161 */
14431
- else if ((channel >= 149) && (channel <= 161)) {
21481
+ else if ((chanspec >= 0xd095) && (chanspec <= 0xd0a5)) {
1443221482 valid = true;
1443321483 }
21484
+#else
21485
+ /* channel 36 to 48 */
21486
+ else if ((chanspec >= 0x1b24) && (chanspec <= 0x1b30)) {
21487
+ valid = true;
21488
+ }
21489
+ /* channel 149 to 161 */
21490
+ else if ((chanspec >= 0x1b95) && (chanspec <= 0x1ba1)) {
21491
+ valid = true;
21492
+ }
21493
+#endif /* IGUANA_LEGACY_CHIPS */
1443421494 else {
1443521495 valid = false;
14436
- WL_INFORM(("invalid P2P chanspec, channel = %d\n", channel));
21496
+ WL_INFORM_MEM(("invalid P2P chanspec, chanspec = %s\n",
21497
+ wf_chspec_ntoa_ex(chanspec, chanbuf)));
1443721498 }
1443821499
1443921500 return valid;
....@@ -14446,7 +21507,7 @@
1444621507 struct bcm_cfg80211 *cfg = NULL;
1444721508 chanspec_t chanspec = 0;
1444821509
14449
- cfg = g_bcm_cfg;
21510
+ cfg = wl_get_cfg(ndev);
1445021511
1445121512 /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
1445221513 chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 |
....@@ -14469,11 +21530,9 @@
1446921530 s32 ret = BCME_ERROR;
1447021531 s32 i = 0;
1447121532 s32 j = 0;
14472
- struct bcm_cfg80211 *cfg = NULL;
21533
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1447321534 wl_uint32_list_t *list = NULL;
1447421535 chanspec_t chanspec = 0;
14475
-
14476
- cfg = g_bcm_cfg;
1447721536
1447821537 /* Restrict channels to 5GHz, 20MHz BW, no SB. */
1447921538 chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 |
....@@ -14500,7 +21559,7 @@
1450021559 }
1450121560
1450221561 if (CHANNEL_IS_RADAR(channel) ||
14503
- !(wl_cfg80211_valid_channel_p2p(CHSPEC_CHANNEL(chanspec)))) {
21562
+ !(wl_cfg80211_valid_chanspec_p2p(chanspec))) {
1450421563 continue;
1450521564 } else {
1450621565 list->element[j] = list->element[i];
....@@ -14524,7 +21583,7 @@
1452421583 int retry = 0;
1452521584
1452621585 /* Start auto channel selection scan. */
14527
- ret = wldev_ioctl(ndev, WLC_START_CHANNEL_SEL, buf, buflen, true);
21586
+ ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, NULL, 0);
1452821587 if (ret < 0) {
1452921588 WL_ERR(("can't start auto channel scan, error = %d\n", ret));
1453021589 *channel = 0;
....@@ -14536,16 +21595,14 @@
1453621595
1453721596 while (retry--) {
1453821597 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
14539
-
1454021598 chosen = 0;
14541
- ret = wldev_ioctl(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen),
14542
- false);
21599
+ ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
1454321600 if ((ret == 0) && (dtoh32(chosen) != 0)) {
1454421601 *channel = (u16)(chosen & 0x00FF);
14545
- WL_INFORM(("selected channel = %d\n", *channel));
21602
+ WL_INFORM_MEM(("selected channel = %d\n", *channel));
1454621603 break;
1454721604 }
14548
- WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n",
21605
+ WL_DBG(("attempt = %d, ret = %d, chosen = %d\n",
1454921606 (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
1455021607 }
1455121608
....@@ -14562,24 +21619,11 @@
1456221619 static s32
1456321620 wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev)
1456421621 {
14565
- u32 val = 0;
14566
- s32 ret = BCME_ERROR;
14567
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
14568
-
21622
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1456921623 /* Clear scan stop driver status. */
1457021624 wl_clr_drv_status(cfg, SCANNING, ndev);
1457121625
14572
- /* Enable mpc back to 1, irrespective of initial state. */
14573
- val = 1;
14574
-
14575
- ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val,
14576
- sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
14577
- &cfg->ioctl_buf_sync);
14578
- if (ret < 0) {
14579
- WL_ERR(("set 'mpc' failed, error = %d\n", ret));
14580
- }
14581
-
14582
- return ret;
21626
+ return BCME_OK;
1458321627 }
1458421628
1458521629 s32
....@@ -14592,9 +21636,10 @@
1459221636 struct bcm_cfg80211 *cfg = NULL;
1459321637 struct net_device *ndev = NULL;
1459421638
14595
- memset(cmd, 0, total_len);
21639
+ bzero(cmd, total_len);
21640
+ cfg = wl_get_cfg(dev);
1459621641
14597
- buf = kzalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL);
21642
+ buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
1459821643 if (buf == NULL) {
1459921644 WL_ERR(("failed to allocate chanspec buffer\n"));
1460021645 return -ENOMEM;
....@@ -14604,7 +21649,6 @@
1460421649 * Always use primary interface, irrespective of interface on which
1460521650 * command came.
1460621651 */
14607
- cfg = g_bcm_cfg;
1460821652 ndev = bcmcfg_to_prmry_ndev(cfg);
1460921653
1461021654 /*
....@@ -14661,14 +21705,14 @@
1466121705 channel = 0;
1466221706 }
1466321707
14664
- pos += snprintf(pos, total_len, "%04d ", channel);
21708
+ pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
1466521709
1466621710 /* Set overall best channel same as 5GHz best channel. */
14667
- pos += snprintf(pos, total_len, "%04d ", channel);
21711
+ pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
1466821712
1466921713 done:
1467021714 if (NULL != buf) {
14671
- kfree(buf);
21715
+ MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
1467221716 }
1467321717
1467421718 /* Restore FW and driver back to normal state. */
....@@ -14747,20 +21791,24 @@
1474721791 wl_debuglevel_write(struct file *file, const char __user *userbuf,
1474821792 size_t count, loff_t *ppos)
1474921793 {
14750
- char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL];
21794
+ char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)], sublog[SUBLOGLEVELZ];
1475121795 char *params, *token, *colon;
1475221796 uint i, tokens, log_on = 0;
14753
- memset(tbuf, 0, sizeof(tbuf));
14754
- memset(sublog, 0, sizeof(sublog));
14755
- if (copy_from_user(&tbuf, userbuf, min_t(size_t, (sizeof(tbuf) - 1), count)))
14756
- return -EFAULT;
21797
+ size_t minsize = min_t(size_t, (sizeof(tbuf) - 1), count);
1475721798
21799
+ bzero(tbuf, sizeof(tbuf));
21800
+ bzero(sublog, sizeof(sublog));
21801
+ if (copy_from_user(&tbuf, userbuf, minsize)) {
21802
+ return -EFAULT;
21803
+ }
21804
+
21805
+ tbuf[minsize] = '\0';
1475821806 params = &tbuf[0];
1475921807 colon = strchr(params, '\n');
1476021808 if (colon != NULL)
1476121809 *colon = '\0';
1476221810 while ((token = strsep(&params, " ")) != NULL) {
14763
- memset(sublog, 0, sizeof(sublog));
21811
+ bzero(sublog, sizeof(sublog));
1476421812 if (token == NULL || !*token)
1476521813 break;
1476621814 if (*token == '\0')
....@@ -14769,7 +21817,7 @@
1476921817 if (colon != NULL) {
1477021818 *colon = ' ';
1477121819 }
14772
- tokens = sscanf(token, "%s %u", sublog, &log_on);
21820
+ tokens = sscanf(token, "%"S(SUBLOGLEVEL)"s %u", sublog, &log_on);
1477321821 if (colon != NULL)
1477421822 *colon = ':';
1477521823
....@@ -14790,7 +21838,6 @@
1479021838 "SUBMODULE:LEVEL (%d tokens)\n",
1479121839 tbuf, token, tokens));
1479221840
14793
-
1479421841 }
1479521842 return count;
1479621843 }
....@@ -14800,9 +21847,9 @@
1480021847 size_t count, loff_t *ppos)
1480121848 {
1480221849 char *param;
14803
- char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)];
21850
+ char tbuf[SUBLOGLEVELZ * ARRAYSIZE(sublogname_map)];
1480421851 uint i;
14805
- memset(tbuf, 0, sizeof(tbuf));
21852
+ bzero(tbuf, sizeof(tbuf));
1480621853 param = &tbuf[0];
1480721854 for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
1480821855 param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
....@@ -14857,6 +21904,16 @@
1485721904 }
1485821905 #endif /* DEBUGFS_CFG80211 */
1485921906
21907
+struct bcm_cfg80211 *wl_cfg80211_get_bcmcfg(void)
21908
+{
21909
+ return g_bcmcfg;
21910
+}
21911
+
21912
+void wl_cfg80211_set_bcmcfg(struct bcm_cfg80211 *cfg)
21913
+{
21914
+ g_bcmcfg = cfg;
21915
+}
21916
+
1486021917 struct device *wl_cfg80211_get_parent_dev(void)
1486121918 {
1486221919 return cfg80211_parent_dev;
....@@ -14874,17 +21931,21 @@
1487421931
1487521932 void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
1487621933 {
14877
- wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr", NULL,
14878
- 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
14879
- memcpy(mac->octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
21934
+ u8 ioctl_buf[WLC_IOCTL_SMLEN];
21935
+
21936
+ if (wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
21937
+ "cur_etheraddr", NULL, 0, ioctl_buf, sizeof(ioctl_buf),
21938
+ 0, NULL) == BCME_OK) {
21939
+ memcpy(mac->octet, ioctl_buf, ETHER_ADDR_LEN);
21940
+ } else {
21941
+ bzero(mac->octet, ETHER_ADDR_LEN);
21942
+ }
1488021943 }
14881
-static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
21944
+static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, s32 mode, u32 dev_role)
1488221945 {
1488321946 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
14884
- if (((dev_role == NL80211_IFTYPE_AP) &&
14885
- !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
14886
- ((dev_role == NL80211_IFTYPE_P2P_GO) &&
14887
- !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
21947
+ if (((dev_role == NL80211_IFTYPE_AP) || (dev_role == NL80211_IFTYPE_P2P_GO)) &&
21948
+ (mode != WL_MODE_AP))
1488821949 {
1488921950 WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
1489021951 return false;
....@@ -14928,113 +21989,89 @@
1492821989 }
1492921990 #endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
1493021991
14931
-#ifdef WL11U
14932
-bcm_tlv_t *
14933
-wl_cfg80211_find_interworking_ie(u8 *parse, u32 len)
21992
+#ifdef WL_HOST_BAND_MGMT
21993
+s32
21994
+wl_cfg80211_set_band(struct net_device *ndev, int band)
1493421995 {
14935
- bcm_tlv_t *ie;
21996
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
21997
+ int ret = 0;
21998
+ char ioctl_buf[50];
1493621999
14937
- while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) {
14938
- return (bcm_tlv_t *)ie;
22000
+ if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
22001
+ WL_ERR(("Invalid band\n"));
22002
+ return -EINVAL;
1493922003 }
14940
- return NULL;
22004
+
22005
+ if ((ret = wldev_iovar_setbuf(ndev, "roam_band", &band,
22006
+ sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
22007
+ WL_ERR(("seting roam_band failed code=%d\n", ret));
22008
+ return ret;
22009
+ }
22010
+
22011
+ WL_DBG(("Setting band to %d\n", band));
22012
+ cfg->curr_band = band;
22013
+
22014
+ return 0;
1494122015 }
22016
+#endif /* WL_HOST_BAND_MGMT */
1494222017
14943
-
14944
-static s32
14945
-wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
14946
- uint8 ie_id, uint8 *data, uint8 data_len)
22018
+s32
22019
+wl_cfg80211_set_if_band(struct net_device *ndev, int band)
1494722020 {
14948
- s32 err = BCME_OK;
14949
- s32 buf_len;
14950
- s32 iecount;
14951
- ie_setbuf_t *ie_setbuf;
22021
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
22022
+ int ret = 0, wait_cnt;
22023
+ char ioctl_buf[32];
1495222024
14953
- if (ie_id != DOT11_MNG_INTERWORKING_ID)
14954
- return BCME_UNSUPPORTED;
14955
-
14956
- /* Validate the pktflag parameter */
14957
- if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
14958
- VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
14959
- VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG|
14960
- VNDR_IE_CUSTOM_FLAG))) {
14961
- WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag));
14962
- return -1;
22025
+ if ((band < WLC_BAND_AUTO) || (band > WLC_BAND_2G)) {
22026
+ WL_ERR(("Invalid band\n"));
22027
+ return -EINVAL;
1496322028 }
14964
-
14965
- /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */
14966
- pktflag = htod32(pktflag);
14967
-
14968
- buf_len = sizeof(ie_setbuf_t) + data_len - 1;
14969
- ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL);
14970
-
14971
- if (!ie_setbuf) {
14972
- WL_ERR(("Error allocating buffer for IE\n"));
14973
- return -ENOMEM;
22029
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
22030
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
22031
+ BCM_REFERENCE(dhdp);
22032
+ DHD_STATLOG_CTRL(dhdp, ST(DISASSOC_INT_START),
22033
+ dhd_net2idx(dhdp->info, ndev), 0);
22034
+ ret = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
22035
+ if (ret < 0) {
22036
+ WL_ERR(("WLC_DISASSOC error %d\n", ret));
22037
+ /* continue to set 'if_band' */
22038
+ }
22039
+ else {
22040
+ /* This is to ensure that 'if_band' iovar is issued only after
22041
+ * disconnection is completed
22042
+ */
22043
+ wait_cnt = WAIT_FOR_DISCONNECT_MAX;
22044
+ while (wl_get_drv_status(cfg, CONNECTED, ndev) && wait_cnt) {
22045
+ WL_DBG(("Wait until disconnected. wait_cnt: %d\n", wait_cnt));
22046
+ wait_cnt--;
22047
+ OSL_SLEEP(50);
22048
+ }
22049
+ }
1497422050 }
14975
-
14976
- if (cfg->iw_ie_len == data_len && !memcmp(cfg->iw_ie, data, data_len)) {
14977
- WL_ERR(("Previous IW IE is equals to current IE\n"));
14978
- err = BCME_OK;
14979
- goto exit;
22051
+ if ((ret = wldev_iovar_setbuf(ndev, "if_band", &band,
22052
+ sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
22053
+ WL_ERR(("seting if_band failed ret=%d\n", ret));
22054
+ /* issue 'WLC_SET_BAND' if if_band is not supported */
22055
+ if (ret == BCME_UNSUPPORTED) {
22056
+ ret = wldev_set_band(ndev, band);
22057
+ if (ret < 0) {
22058
+ WL_ERR(("seting band failed ret=%d\n", ret));
22059
+ }
22060
+ }
1498022061 }
14981
-
14982
- strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
14983
- ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
14984
-
14985
- /* Buffer contains only 1 IE */
14986
- iecount = htod32(1);
14987
- memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int));
14988
- memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32));
14989
-
14990
- /* Now, add the IE to the buffer */
14991
- ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id;
14992
-
14993
- /* if already set with previous values, delete it first */
14994
- if (cfg->iw_ie_len != 0) {
14995
- WL_DBG(("Different IW_IE was already set. clear first\n"));
14996
-
14997
- ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0;
14998
-
14999
- err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
15000
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
15001
-
15002
- if (err != BCME_OK)
15003
- goto exit;
15004
- }
15005
-
15006
- ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len;
15007
- memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len);
15008
-
15009
- err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
15010
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
15011
-
15012
- if (err == BCME_OK) {
15013
- memcpy(cfg->iw_ie, data, data_len);
15014
- cfg->iw_ie_len = data_len;
15015
- cfg->wl11u = TRUE;
15016
-
15017
- err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx);
15018
- }
15019
-
15020
-exit:
15021
- if (ie_setbuf)
15022
- kfree(ie_setbuf);
15023
- return err;
22062
+ return ret;
1502422063 }
15025
-#endif /* WL11U */
1502622064
1502722065 s32
1502822066 wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int total_len)
1502922067 {
15030
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
15031
- char ioctl_buf[50];
22068
+ char ioctl_buf[WLC_IOCTL_SMLEN];
1503222069 int err = 0;
1503322070 uint32 val = 0;
1503422071 chanspec_t chanspec = 0;
1503522072 int abort;
1503622073 int bytes_written = 0;
15037
- wl_dfs_ap_move_status_t *status;
22074
+ struct wl_dfs_ap_move_status_v2 *status;
1503822075 char chanbuf[CHANSPEC_STR_LEN];
1503922076 const char *dfs_state_str[DFS_SCAN_S_MAX] = {
1504022077 "Radar Free On Channel",
....@@ -15044,16 +22081,16 @@
1504422081 "RSDB Mode switch in Progress For Scan"
1504522082 };
1504622083 if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
15047
- bytes_written = snprintf(command, total_len, "AP is not UP\n");
22084
+ bytes_written = snprintf(command, total_len, "AP is not up\n");
1504822085 return bytes_written;
1504922086 }
1505022087 if (!*data) {
1505122088 if ((err = wldev_iovar_getbuf(ndev, "dfs_ap_move", NULL, 0,
15052
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
22089
+ ioctl_buf, sizeof(ioctl_buf), NULL))) {
1505322090 WL_ERR(("setting dfs_ap_move failed with err=%d \n", err));
1505422091 return err;
1505522092 }
15056
- status = (wl_dfs_ap_move_status_t *)cfg->ioctl_buf;
22093
+ status = (struct wl_dfs_ap_move_status_v2 *)ioctl_buf;
1505722094
1505822095 if (status->version != WL_DFS_AP_MOVE_VERSION) {
1505922096 err = BCME_UNSUPPORTED;
....@@ -15068,14 +22105,14 @@
1506822105 bytes_written = snprintf(command, total_len,
1506922106 "AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
1507022107 }
15071
- bytes_written += snprintf(command + bytes_written, total_len,
15072
- "%s\n", dfs_state_str[status->move_status]);
22108
+ bytes_written += snprintf(command + bytes_written,
22109
+ total_len - bytes_written,
22110
+ "%s\n", dfs_state_str[status->move_status]);
1507322111 return bytes_written;
1507422112 } else {
1507522113 bytes_written = snprintf(command, total_len, "dfs AP move in IDLE state\n");
1507622114 return bytes_written;
1507722115 }
15078
-
1507922116 }
1508022117
1508122118 abort = bcm_atoi(data);
....@@ -15104,478 +22141,48 @@
1510422141 return err;
1510522142 }
1510622143
15107
-s32
15108
-wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
22144
+bool wl_cfg80211_is_concurrent_mode(struct net_device *dev)
1510922145 {
15110
- uint i = 0;
15111
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
15112
- wl_roam_prof_band_t *rp;
15113
- int err = -EINVAL, bytes_written = 0;
15114
- size_t len = strlen(data);
15115
- data[len] = '\0';
15116
-
15117
- rp = (wl_roam_prof_band_t *) kzalloc(sizeof(*rp)
15118
- * WL_MAX_ROAM_PROF_BRACKETS, GFP_KERNEL);
15119
- if (unlikely(!rp)) {
15120
- WL_ERR(("%s: failed to allocate memory\n", __func__));
15121
- err = -ENOMEM;
15122
- goto exit;
15123
- }
15124
-
15125
- rp->ver = WL_MAX_ROAM_PROF_VER;
15126
- if (*data && (!strncmp(data, "b", 1))) {
15127
- rp->band = WLC_BAND_2G;
15128
- } else if (*data && (!strncmp(data, "a", 1))) {
15129
- rp->band = WLC_BAND_5G;
22146
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22147
+ if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
22148
+ return true;
1513022149 } else {
15131
- err = snprintf(command, total_len, "Missing band\n");
15132
- goto exit;
22150
+ return false;
1513322151 }
15134
- rp->len = 0;
15135
- data++;
15136
- if (!*data) {
15137
- /* Getting roam profile from fw */
15138
- if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
15139
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
15140
- WL_ERR(("Getting roam_profile failed with err=%d \n", err));
15141
- goto exit;
15142
- }
15143
- memcpy(rp, cfg->ioctl_buf, sizeof(*rp) * WL_MAX_ROAM_PROF_BRACKETS);
15144
- /* roam_prof version get */
15145
- if (rp->ver != WL_MAX_ROAM_PROF_VER) {
15146
- WL_ERR(("bad version (=%d) in return data\n", rp->ver));
15147
- err = -EINVAL;
15148
- goto exit;
15149
- }
15150
- if ((rp->len % sizeof(wl_roam_prof_t)) != 0) {
15151
- WL_ERR(("bad length (=%d) in return data\n", rp->len));
15152
- err = -EINVAL;
15153
- goto exit;
15154
- }
15155
- for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
15156
- /* printing contents of roam profile data from fw and exits
15157
- * if code hits any of one of the below condtion.
15158
- */
15159
- if (((i * sizeof(wl_roam_prof_t)) > rp->len) ||
15160
- (rp->roam_prof[i].fullscan_period == 0)) {
15161
- break;
15162
- }
15163
-
15164
- bytes_written += snprintf(command+bytes_written,
15165
- total_len, "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)\n",
15166
- rp->roam_prof[i].roam_trigger, rp->roam_prof[i].rssi_lower,
15167
- rp->roam_prof[i].channel_usage,
15168
- rp->roam_prof[i].cu_avg_calc_dur);
15169
- }
15170
- err = bytes_written;
15171
- goto exit;
15172
- } else {
15173
- /* setting roam profile to fw */
15174
- data++;
15175
- memset(rp->roam_prof, 0, sizeof(wl_roam_prof_t) * WL_MAX_ROAM_PROF_BRACKETS);
15176
- for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
15177
- rp->roam_prof[i].roam_trigger = simple_strtol(data, &data, 10);
15178
- data++;
15179
- rp->roam_prof[i].rssi_lower = simple_strtol(data, &data, 10);
15180
- data++;
15181
- rp->roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
15182
- data++;
15183
- rp->roam_prof[i].cu_avg_calc_dur = simple_strtol(data, &data, 10);
15184
- /* filling rows */
15185
- rp->roam_prof[i].roam_flags = WL_ROAM_PROF_DEFAULT;
15186
- rp->roam_prof[i].rssi_boost_thresh = WL_JOIN_PREF_RSSI_BOOST_MIN;
15187
- rp->roam_prof[i].rssi_boost_delta = 0;
15188
- rp->roam_prof[i].nfscan = WL_ROAM_FULLSCAN_NTIMES;
15189
- rp->roam_prof[i].fullscan_period = WL_FULLROAM_PERIOD;
15190
- rp->roam_prof[i].init_scan_period = WL_ROAM_SCAN_PERIOD;
15191
- rp->roam_prof[i].backoff_multiplier = 1;
15192
- rp->roam_prof[i].max_scan_period = WL_ROAM_SCAN_PERIOD;
15193
- if (rp->band == WLC_BAND_2G)
15194
- rp->roam_prof[i].roam_delta = WL_ROAM_DELTA_2G;
15195
- else
15196
- rp->roam_prof[i].roam_delta = WL_ROAM_DELTA_5G;
15197
-
15198
- /* update roam_delta to default score for cu enabled roam profile entry */
15199
- if (rp->roam_prof[i].channel_usage != 0) {
15200
- rp->roam_prof[i].roam_delta = WL_SCORE_DELTA_DEFAULT;
15201
- }
15202
-
15203
- rp->len += sizeof(wl_roam_prof_t);
15204
-
15205
- if (*data == '\0') {
15206
- break;
15207
- }
15208
- data++;
15209
- }
15210
- if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
15211
- 8 + rp->len, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL)) < 0) {
15212
- WL_ERR(("seting roam_profile failed with err %d\n", err));
15213
- }
15214
- }
15215
-exit:
15216
- if (rp) {
15217
- kfree(rp);
15218
- }
15219
- return err;
1522022152 }
1522122153
15222
-int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
15223
- char *command, int total_len)
22154
+void* wl_cfg80211_get_dhdp(struct net_device *dev)
1522422155 {
15225
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
15226
- int bytes_written = 0, err = -EINVAL, argc = 0;
15227
- char rssi[5], band[5], weight[5];
15228
- char *endptr = NULL;
15229
- wnm_bss_select_weight_cfg_t *bwcfg;
15230
-
15231
- bwcfg = kzalloc(sizeof(*bwcfg), GFP_KERNEL);
15232
- if (unlikely(!bwcfg)) {
15233
- WL_ERR(("%s: failed to allocate memory\n", __func__));
15234
- err = -ENOMEM;
15235
- goto exit;
15236
- }
15237
- bwcfg->version = WNM_BSSLOAD_MONITOR_VERSION;
15238
- bwcfg->type = 0;
15239
- bwcfg->weight = 0;
15240
-
15241
- argc = sscanf(data, "%s %s %s", rssi, band, weight);
15242
-
15243
- if (!strcasecmp(rssi, "rssi"))
15244
- bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
15245
- else if (!strcasecmp(rssi, "cu"))
15246
- bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
15247
- else {
15248
- /* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu> <band> <weight> */
15249
- WL_ERR(("%s: Command usage error\n", __func__));
15250
- goto exit;
15251
- }
15252
-
15253
- if (!strcasecmp(band, "a"))
15254
- bwcfg->band = WLC_BAND_5G;
15255
- else if (!strcasecmp(band, "b"))
15256
- bwcfg->band = WLC_BAND_2G;
15257
- else if (!strcasecmp(band, "all"))
15258
- bwcfg->band = WLC_BAND_ALL;
15259
- else {
15260
- WL_ERR(("%s: Command usage error\n", __func__));
15261
- goto exit;
15262
- }
15263
-
15264
- if (argc == 2) {
15265
- /* If there is no data after band, getting wnm_bss_select_weight from fw */
15266
- if (bwcfg->band == WLC_BAND_ALL) {
15267
- WL_ERR(("band option \"all\" is for set only, not get\n"));
15268
- goto exit;
15269
- }
15270
- if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
15271
- sizeof(*bwcfg),
15272
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
15273
- WL_ERR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
15274
- goto exit;
15275
- }
15276
- memcpy(bwcfg, cfg->ioctl_buf, sizeof(*bwcfg));
15277
- bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
15278
- (bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU",
15279
- (bwcfg->band == WLC_BAND_2G) ? "2G" : "5G", bwcfg->weight);
15280
- err = bytes_written;
15281
- goto exit;
15282
- } else {
15283
- /* if weight is non integer returns command usage error */
15284
- bwcfg->weight = simple_strtol(weight, &endptr, 0);
15285
- if (*endptr != '\0') {
15286
- WL_ERR(("%s: Command usage error", __func__));
15287
- goto exit;
15288
- }
15289
- /* setting weight for iovar wnm_bss_select_weight to fw */
15290
- if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
15291
- sizeof(*bwcfg),
15292
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
15293
- WL_ERR(("Getting wnm_bss_select_weight failed with err=%d\n", err));
15294
- }
15295
- }
15296
-exit:
15297
- if (bwcfg) {
15298
- kfree(bwcfg);
15299
- }
15300
- return err;
15301
-}
15302
-
15303
-/* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
15304
-#define WBTEXT_TUPLE_MIN_LEN_CHECK 5
15305
-
15306
-int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
15307
- char *command, int total_len)
15308
-{
15309
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
15310
- int bytes_written = 0, err = -EINVAL;
15311
- char rssi[5], band[5];
15312
- int btcfg_len = 0, i = 0, parsed_len = 0;
15313
- wnm_bss_select_factor_cfg_t *btcfg;
15314
- size_t slen = strlen(data);
15315
- char *start_addr = NULL;
15316
- data[slen] = '\0';
15317
-
15318
- btcfg = kzalloc((sizeof(*btcfg) + sizeof(*btcfg) *
15319
- WL_FACTOR_TABLE_MAX_LIMIT), GFP_KERNEL);
15320
- if (unlikely(!btcfg)) {
15321
- WL_ERR(("%s: failed to allocate memory\n", __func__));
15322
- err = -ENOMEM;
15323
- goto exit;
15324
- }
15325
-
15326
- btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
15327
- btcfg->band = WLC_BAND_AUTO;
15328
- btcfg->type = 0;
15329
- btcfg->count = 0;
15330
-
15331
- sscanf(data, "%s %s", rssi, band);
15332
-
15333
- if (!strcasecmp(rssi, "rssi")) {
15334
- btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
15335
- }
15336
- else if (!strcasecmp(rssi, "cu")) {
15337
- btcfg->type = WNM_BSS_SELECT_TYPE_CU;
15338
- }
15339
- else {
15340
- WL_ERR(("%s: Command usage error\n", __func__));
15341
- goto exit;
15342
- }
15343
-
15344
- if (!strcasecmp(band, "a")) {
15345
- btcfg->band = WLC_BAND_5G;
15346
- }
15347
- else if (!strcasecmp(band, "b")) {
15348
- btcfg->band = WLC_BAND_2G;
15349
- }
15350
- else if (!strcasecmp(band, "all")) {
15351
- btcfg->band = WLC_BAND_ALL;
15352
- }
15353
- else {
15354
- WL_ERR(("%s: Command usage, Wrong band\n", __func__));
15355
- goto exit;
15356
- }
15357
-
15358
- if ((slen - 1) == (strlen(rssi) + strlen(band))) {
15359
- /* Getting factor table using iovar 'wnm_bss_select_table' from fw */
15360
- if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
15361
- sizeof(*btcfg),
15362
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
15363
- WL_ERR(("Getting wnm_bss_select_table failed with err=%d \n", err));
15364
- goto exit;
15365
- }
15366
- memcpy(btcfg, cfg->ioctl_buf, sizeof(*btcfg));
15367
- memcpy(btcfg, cfg->ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
15368
-
15369
- bytes_written += snprintf(command + bytes_written, total_len,
15370
- "No of entries in table: %d\n", btcfg->count);
15371
- bytes_written += snprintf(command + bytes_written, total_len, "%s factor table\n",
15372
- (btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
15373
- bytes_written += snprintf(command + bytes_written, total_len,
15374
- "low\thigh\tfactor\n");
15375
- for (i = 0; i <= btcfg->count-1; i++) {
15376
- bytes_written += snprintf(command + bytes_written, total_len,
15377
- "%d\t%d\t%d\n", btcfg->params[i].low, btcfg->params[i].high,
15378
- btcfg->params[i].factor);
15379
- }
15380
- err = bytes_written;
15381
- goto exit;
15382
- } else {
15383
- memset(btcfg->params, 0, sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT);
15384
- data += (strlen(rssi) + strlen(band) + 2);
15385
- start_addr = data;
15386
- slen = slen - (strlen(rssi) + strlen(band) + 2);
15387
- for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
15388
- if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
15389
- btcfg->params[i].low = simple_strtol(data, &data, 10);
15390
- data++;
15391
- btcfg->params[i].high = simple_strtol(data, &data, 10);
15392
- data++;
15393
- btcfg->params[i].factor = simple_strtol(data, &data, 10);
15394
- btcfg->count++;
15395
- if (*data == '\0') {
15396
- break;
15397
- }
15398
- data++;
15399
- parsed_len = data - start_addr;
15400
- } else {
15401
- WL_ERR(("%s:Command usage:less no of args\n", __func__));
15402
- goto exit;
15403
- }
15404
- }
15405
- btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
15406
- if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
15407
- cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL)) < 0) {
15408
- WL_ERR(("seting wnm_bss_select_table failed with err %d\n", err));
15409
- goto exit;
15410
- }
15411
- }
15412
-exit:
15413
- if (btcfg) {
15414
- kfree(btcfg);
15415
- }
15416
- return err;
15417
-}
15418
-
15419
-s32
15420
-wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
15421
-{
15422
- uint i = 0;
15423
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
15424
- int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
15425
- char delta[5], band[5], *endptr = NULL;
15426
- wl_roam_prof_band_t *rp;
15427
-
15428
- rp = (wl_roam_prof_band_t *) kzalloc(sizeof(*rp)
15429
- * WL_MAX_ROAM_PROF_BRACKETS, GFP_KERNEL);
15430
- if (unlikely(!rp)) {
15431
- WL_ERR(("%s: failed to allocate memory\n", __func__));
15432
- err = -ENOMEM;
15433
- goto exit;
15434
- }
15435
-
15436
- argc = sscanf(data, "%s %s", band, delta);
15437
- if (argc == 2) {
15438
- if (!strcasecmp(band, "a"))
15439
- rp->band = WLC_BAND_5G;
15440
- else if (!strcasecmp(band, "b"))
15441
- rp->band = WLC_BAND_2G;
15442
- else {
15443
- WL_ERR(("%s: Missing band\n", __func__));
15444
- goto exit;
15445
- }
15446
- /* if delta is non integer returns command usage error */
15447
- val = simple_strtol(delta, &endptr, 0);
15448
- if (*endptr != '\0') {
15449
- WL_ERR(("%s: Command usage error", __func__));
15450
- goto exit;
15451
- }
15452
- /* Getting roam profile from fw */
15453
- if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
15454
- cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
15455
- WL_ERR(("Getting roam_profile failed with err=%d \n", err));
15456
- goto exit;
15457
- }
15458
- memcpy(rp, cfg->ioctl_buf, sizeof(wl_roam_prof_band_t));
15459
- if (rp->ver != WL_MAX_ROAM_PROF_VER) {
15460
- WL_ERR(("bad version (=%d) in return data\n", rp->ver));
15461
- err = -EINVAL;
15462
- goto exit;
15463
- }
15464
- if ((rp->len % sizeof(wl_roam_prof_t)) != 0) {
15465
- WL_ERR(("bad length (=%d) in return data\n", rp->len));
15466
- err = -EINVAL;
15467
- goto exit;
15468
- }
15469
- for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
15470
- /* printing contents of roam profile data from fw and exits
15471
- * if code hits below condtion.
15472
- */
15473
- if (((i * sizeof(wl_roam_prof_t)) > rp->len) ||
15474
- (rp->roam_prof[i].fullscan_period == 0)) {
15475
- break;
15476
- }
15477
- if (rp->roam_prof[i].channel_usage != 0) {
15478
- rp->roam_prof[i].roam_delta = val;
15479
- }
15480
- len += sizeof(wl_roam_prof_t);
15481
- }
15482
- }
15483
- else {
15484
- bytes_written = snprintf(command, total_len, "Usage error, less args\n");
15485
- err = bytes_written;
15486
- goto exit;
15487
- }
15488
- rp->len = len;
15489
- if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
15490
- sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL)) < 0) {
15491
- WL_ERR(("seting roam_profile failed with err %d\n", err));
15492
- }
15493
-exit :
15494
- if (rp) {
15495
- kfree(rp);
15496
- }
15497
- return err;
15498
-}
15499
-
15500
-
15501
-int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev)
15502
-{
15503
- struct bcm_cfg80211 *cfg = NULL;
15504
- struct net_device *ndev = NULL;
15505
- unsigned long flags;
15506
- int clear_flag = 0;
15507
- int ret = 0;
15508
-
15509
- WL_TRACE(("Enter\n"));
15510
-
15511
- cfg = g_bcm_cfg;
15512
- if (!cfg)
15513
- return -EINVAL;
15514
-
15515
- ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
15516
-
15517
- spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
15518
-#ifdef WL_CFG80211_P2P_DEV_IF
15519
- if (cfg->scan_request && cfg->scan_request->wdev == cfgdev) {
15520
-#else
15521
- if (cfg->scan_request && cfg->scan_request->dev == cfgdev) {
15522
-#endif
15523
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 8, 0))
15524
- struct cfg80211_scan_info info = { .aborted = true };
15525
- cfg80211_scan_done(cfg->scan_request, &info);
15526
-#else
15527
- cfg80211_scan_done(cfg->scan_request, true);
15528
-#endif
15529
- cfg->scan_request = NULL;
15530
- clear_flag = 1;
15531
- }
15532
- spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
15533
-
15534
- if (clear_flag)
15535
- wl_clr_drv_status(cfg, SCANNING, ndev);
15536
-
15537
- return ret;
15538
-}
15539
-
15540
-bool wl_cfg80211_is_vsdb_mode(void)
15541
-{
15542
- return (g_bcm_cfg && g_bcm_cfg->vsdb_mode);
15543
-}
15544
-
15545
-void* wl_cfg80211_get_dhdp()
15546
-{
15547
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
22156
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1554822157
1554922158 return cfg->pub;
1555022159 }
1555122160
15552
-bool wl_cfg80211_is_p2p_active(void)
22161
+bool wl_cfg80211_is_p2p_active(struct net_device *dev)
1555322162 {
15554
- return (g_bcm_cfg && g_bcm_cfg->p2p);
22163
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22164
+ return (cfg && cfg->p2p);
1555522165 }
1555622166
15557
-bool wl_cfg80211_is_roam_offload(void)
22167
+bool wl_cfg80211_is_roam_offload(struct net_device * dev)
1555822168 {
15559
- return (g_bcm_cfg && g_bcm_cfg->roam_offload);
22169
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
22170
+ return (cfg && cfg->roam_offload);
1556022171 }
1556122172
15562
-bool wl_cfg80211_is_event_from_connected_bssid(const wl_event_msg_t *e, int ifidx)
22173
+bool wl_cfg80211_is_event_from_connected_bssid(struct net_device * dev, const wl_event_msg_t *e,
22174
+ int ifidx)
1556322175 {
15564
- dhd_pub_t *dhd = NULL;
15565
- struct net_device *ndev = NULL;
1556622176 u8 *curbssid = NULL;
22177
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1556722178
15568
- dhd = (dhd_pub_t *)(g_bcm_cfg->pub);
15569
-
15570
- if (dhd) {
15571
- ndev = dhd_idx2net(dhd, ifidx);
22179
+ if (!cfg) {
22180
+ /* When interface is created using wl
22181
+ * ndev->ieee80211_ptr will be NULL.
22182
+ */
22183
+ return NULL;
1557222184 }
15573
-
15574
- if (!dhd || !ndev) {
15575
- return false;
15576
- }
15577
-
15578
- curbssid = wl_read_prof(g_bcm_cfg, ndev, WL_PROF_BSSID);
22185
+ curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
1557922186
1558022187 if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
1558122188 return true;
....@@ -15591,40 +22198,46 @@
1559122198 s32 pm = PM_FAST;
1559222199 BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
1559322200 WL_DBG(("Enter \n"));
15594
- if (cfg->pm_enable_work_on) {
15595
- cfg->pm_enable_work_on = false;
15596
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15597
- 4 && __GNUC_MINOR__ >= 6))
15598
-_Pragma("GCC diagnostic push")
15599
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
15600
-#endif
15601
- for_each_ndev(cfg, iter, next) {
15602
- /* p2p discovery iface ndev could be null */
22201
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22202
+ for_each_ndev(cfg, iter, next) {
22203
+ GCC_DIAGNOSTIC_POP();
22204
+ /* p2p discovery iface ndev could be null */
22205
+ if (iter->ndev) {
22206
+ if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
22207
+ (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
22208
+ wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
22209
+ continue;
1560322210 if (iter->ndev) {
15604
- if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
15605
- (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
15606
- wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
15607
- continue;
15608
- if (iter->ndev) {
15609
- if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM,
15610
- &pm, sizeof(pm), true)) != 0) {
15611
- if (err == -ENODEV)
15612
- WL_DBG(("%s:netdev not ready\n",
15613
- iter->ndev->name));
15614
- else
15615
- WL_ERR(("%s:error (%d)\n",
15616
- iter->ndev->name, err));
15617
- } else
15618
- wl_cfg80211_update_power_mode(iter->ndev);
15619
- }
22211
+ if ((err = wldev_ioctl_set(iter->ndev, WLC_SET_PM,
22212
+ &pm, sizeof(pm))) != 0) {
22213
+ if (err == -ENODEV)
22214
+ WL_DBG(("%s:netdev not ready\n",
22215
+ iter->ndev->name));
22216
+ else
22217
+ WL_ERR(("%s:error (%d)\n",
22218
+ iter->ndev->name, err));
22219
+ } else
22220
+ wl_cfg80211_update_power_mode(iter->ndev);
1562022221 }
1562122222 }
15622
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15623
- 4 && __GNUC_MINOR__ >= 6))
15624
-_Pragma("GCC diagnostic pop")
15625
-#endif
1562622223 }
22224
+#if defined(OEM_ANDROID)
22225
+ DHD_PM_WAKE_UNLOCK(cfg->pub);
22226
+#endif /* BCMDONGLEHOST && OEM_ANDROID */
1562722227 }
22228
+
22229
+#ifdef ENABLE_HOGSQS
22230
+static void wl_cfg80211_hogsqs_event_handler(struct work_struct *work)
22231
+{
22232
+ struct bcm_cfg80211 *cfg = NULL;
22233
+ struct net_device *ndev = NULL;
22234
+ BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211,
22235
+ hogsqs_eventwork.work);
22236
+
22237
+ ndev = bcmcfg_to_prmry_ndev(cfg);
22238
+ wl_add_remove_eventextmsg(ndev, WLC_E_LDF_HOGGER, true);
22239
+}
22240
+#endif // endif
1562822241
1562922242 u8
1563022243 wl_get_action_category(void *frame, u32 frame_len)
....@@ -15636,7 +22249,7 @@
1563622249 if (frame_len < DOT11_ACTION_HDR_LEN)
1563722250 return DOT11_ACTION_CAT_ERR_MASK;
1563822251 category = ptr[DOT11_ACTION_CAT_OFF];
15639
- WL_INFORM(("Action Category: %d\n", category));
22252
+ WL_DBG(("Action Category: %d\n", category));
1564022253 return category;
1564122254 }
1564222255
....@@ -15651,15 +22264,31 @@
1565122264 if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
1565222265 return BCME_ERROR;
1565322266 *ret_action = ptr[DOT11_ACTION_ACT_OFF];
15654
- WL_INFORM(("Public Action : %d\n", *ret_action));
22267
+ WL_DBG(("Public Action : %d\n", *ret_action));
1565522268 return BCME_OK;
1565622269 }
1565722270
1565822271 #ifdef WLFBT
15659
-void
15660
-wl_cfg80211_get_fbt_key(uint8 *key)
22272
+int
22273
+wl_cfg80211_get_fbt_key(struct net_device *dev, uint8 *key, int total_len)
1566122274 {
15662
- memcpy(key, g_bcm_cfg->fbt_key, FBT_KEYLEN);
22275
+ struct bcm_cfg80211 * cfg = wl_get_cfg(dev);
22276
+ int bytes_written = -1;
22277
+
22278
+ if (total_len < FBT_KEYLEN) {
22279
+ WL_ERR(("wl_cfg80211_get_fbt_key: Insufficient buffer \n"));
22280
+ goto end;
22281
+ }
22282
+ if (cfg) {
22283
+ memcpy(key, cfg->fbt_key, FBT_KEYLEN);
22284
+ bytes_written = FBT_KEYLEN;
22285
+ } else {
22286
+ bzero(key, FBT_KEYLEN);
22287
+ WL_ERR(("wl_cfg80211_get_fbt_key: Failed to copy KCK and KEK \n"));
22288
+ }
22289
+ prhex("KCK, KEK", (uchar *)key, FBT_KEYLEN);
22290
+end:
22291
+ return bytes_written;
1566322292 }
1566422293 #endif /* WLFBT */
1566522294
....@@ -15671,63 +22300,91 @@
1567122300 wl_event_msg_t e;
1567222301
1567322302 bzero(&e, sizeof(e));
15674
- e.event_type = cpu_to_be32(WLC_E_BSSID);
22303
+ e.event_type = cpu_to_be32(WLC_E_ROAM);
1567522304 memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
1567622305 /* trigger the roam event handler */
15677
- WL_INFORM(("Delayed roam to " MACDBG "\n", MAC2STRDBG((u8*)(bssid))));
1567822306 err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
1567922307
1568022308 return err;
1568122309 }
1568222310
1568322311 static s32
15684
-wl_cfg80211_parse_vndr_ies(u8 *parse, u32 len,
22312
+wl_cfg80211_parse_vndr_ies(const u8 *parse, u32 len,
1568522313 struct parsed_vndr_ies *vndr_ies)
1568622314 {
1568722315 s32 err = BCME_OK;
15688
- vndr_ie_t *vndrie;
15689
- bcm_tlv_t *ie;
22316
+ const vndr_ie_t *vndrie;
22317
+ const bcm_tlv_t *ie;
1569022318 struct parsed_vndr_ie_info *parsed_info;
1569122319 u32 count = 0;
15692
- s32 remained_len;
22320
+ u32 remained_len;
1569322321
15694
- remained_len = (s32)len;
15695
- memset(vndr_ies, 0, sizeof(*vndr_ies));
22322
+ remained_len = len;
22323
+ bzero(vndr_ies, sizeof(*vndr_ies));
1569622324
15697
- WL_INFORM(("---> len %d\n", len));
15698
- ie = (bcm_tlv_t *) parse;
22325
+ WL_DBG(("---> len %d\n", len));
22326
+ ie = (const bcm_tlv_t *) parse;
1569922327 if (!bcm_valid_tlv(ie, remained_len))
1570022328 ie = NULL;
1570122329 while (ie) {
1570222330 if (count >= MAX_VNDR_IE_NUMBER)
1570322331 break;
15704
- if (ie->id == DOT11_MNG_VS_ID) {
15705
- vndrie = (vndr_ie_t *) ie;
15706
- /* len should be bigger than OUI length + one data length at least */
15707
- if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
15708
- WL_ERR(("%s: invalid vndr ie. length is too small %d\n",
15709
- __FUNCTION__, vndrie->len));
15710
- goto end;
15711
- }
15712
- /* if wpa or wme ie, do not add ie */
15713
- if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
15714
- ((vndrie->data[0] == WPA_OUI_TYPE) ||
15715
- (vndrie->data[0] == WME_OUI_TYPE))) {
15716
- CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
15717
- goto end;
22332
+ if (ie->id == DOT11_MNG_VS_ID || (ie->id == DOT11_MNG_ID_EXT_ID)) {
22333
+ vndrie = (const vndr_ie_t *) ie;
22334
+ if (ie->id == DOT11_MNG_ID_EXT_ID) {
22335
+ /* len should be bigger than sizeof ID extn field at least */
22336
+ if (vndrie->len < MIN_VENDOR_EXTN_IE_LEN) {
22337
+ WL_ERR(("%s: invalid vndr extn ie."
22338
+ " length %d\n",
22339
+ __FUNCTION__, vndrie->len));
22340
+ goto end;
22341
+ }
22342
+
22343
+ /*
22344
+ * skip parsing the HE capab & oper IE from upper layer
22345
+ * to avoid sending it to the FW, as these IEs will be
22346
+ * added by the FW based on the MAC & PHY capab if HE
22347
+ * is enabled.
22348
+ */
22349
+ if ((ie->data[0] == EXT_MNG_HE_CAP_ID) ||
22350
+ (ie->data[0] == EXT_MNG_HE_OP_ID)) {
22351
+ goto end;
22352
+ }
22353
+ } else {
22354
+ /* len should be bigger than OUI length +
22355
+ * one data length at least
22356
+ */
22357
+ if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
22358
+ WL_ERR(("wl_cfg80211_parse_vndr_ies:"
22359
+ " invalid vndr ie. length is too small %d\n",
22360
+ vndrie->len));
22361
+ goto end;
22362
+ }
22363
+
22364
+ /* if wpa or wme ie, do not add ie */
22365
+ if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
22366
+ ((vndrie->data[0] == WPA_OUI_TYPE) ||
22367
+ (vndrie->data[0] == WME_OUI_TYPE))) {
22368
+ CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
22369
+ goto end;
22370
+ }
1571822371 }
1571922372
1572022373 parsed_info = &vndr_ies->ie_info[count++];
1572122374
1572222375 /* save vndr ie information */
15723
- parsed_info->ie_ptr = (char *)vndrie;
22376
+ parsed_info->ie_ptr = (const char *)vndrie;
1572422377 parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
1572522378 memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
1572622379 vndr_ies->count = count;
15727
-
15728
- WL_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x \n",
15729
- parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1],
15730
- parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0]));
22380
+ if (ie->id == DOT11_MNG_ID_EXT_ID) {
22381
+ WL_DBG(("\t ** Vendor Extension ie id: 0x%02x, len:%d\n",
22382
+ ie->id, parsed_info->ie_len));
22383
+ } else {
22384
+ WL_DBG(("\t ** OUI "MACOUIDBG", type 0x%02x len:%d\n",
22385
+ MACOUI2STRDBG(parsed_info->vndrie.oui),
22386
+ parsed_info->vndrie.data[0], parsed_info->ie_len));
22387
+ }
1573122388 }
1573222389 end:
1573322390 ie = bcm_next_tlv(ie, &remained_len);
....@@ -15735,26 +22392,204 @@
1573522392 return err;
1573622393 }
1573722394
22395
+static bool
22396
+wl_vndr_ies_exclude_vndr_oui(struct parsed_vndr_ie_info *vndr_info)
22397
+{
22398
+ int i = 0;
22399
+
22400
+ while (exclude_vndr_oui_list[i]) {
22401
+ if (!memcmp(vndr_info->vndrie.oui,
22402
+ exclude_vndr_oui_list[i],
22403
+ DOT11_OUI_LEN)) {
22404
+ return TRUE;
22405
+ }
22406
+ i++;
22407
+ }
22408
+
22409
+ return FALSE;
22410
+}
22411
+
22412
+static bool
22413
+wl_vndr_ies_check_duplicate_vndr_oui(struct bcm_cfg80211 *cfg,
22414
+ struct parsed_vndr_ie_info *vndr_info)
22415
+{
22416
+ wl_vndr_oui_entry_t *oui_entry = NULL;
22417
+ unsigned long flags;
22418
+
22419
+ WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
22420
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22421
+ list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
22422
+ GCC_DIAGNOSTIC_POP();
22423
+ if (!memcmp(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN)) {
22424
+ WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22425
+ return TRUE;
22426
+ }
22427
+ }
22428
+ WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22429
+ return FALSE;
22430
+}
22431
+
22432
+static bool
22433
+wl_vndr_ies_add_vendor_oui_list(struct bcm_cfg80211 *cfg,
22434
+ struct parsed_vndr_ie_info *vndr_info)
22435
+{
22436
+ wl_vndr_oui_entry_t *oui_entry = NULL;
22437
+ unsigned long flags;
22438
+
22439
+ oui_entry = kmalloc(sizeof(*oui_entry), GFP_KERNEL);
22440
+ if (oui_entry == NULL) {
22441
+ WL_ERR(("alloc failed\n"));
22442
+ return FALSE;
22443
+ }
22444
+
22445
+ memcpy(oui_entry->oui, vndr_info->vndrie.oui, DOT11_OUI_LEN);
22446
+
22447
+ INIT_LIST_HEAD(&oui_entry->list);
22448
+ WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
22449
+ list_add_tail(&oui_entry->list, &cfg->vndr_oui_list);
22450
+ WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22451
+
22452
+ return TRUE;
22453
+}
22454
+
22455
+static void
22456
+wl_vndr_ies_clear_vendor_oui_list(struct bcm_cfg80211 *cfg)
22457
+{
22458
+ wl_vndr_oui_entry_t *oui_entry = NULL;
22459
+ unsigned long flags;
22460
+
22461
+ WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
22462
+ while (!list_empty(&cfg->vndr_oui_list)) {
22463
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22464
+ oui_entry = list_entry(cfg->vndr_oui_list.next, wl_vndr_oui_entry_t, list);
22465
+ GCC_DIAGNOSTIC_POP();
22466
+ if (oui_entry) {
22467
+ list_del(&oui_entry->list);
22468
+ kfree(oui_entry);
22469
+ }
22470
+ }
22471
+ WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22472
+}
22473
+
22474
+static int
22475
+wl_vndr_ies_get_vendor_oui(struct bcm_cfg80211 *cfg, struct net_device *ndev,
22476
+ char *vndr_oui, u32 vndr_oui_len)
22477
+{
22478
+ int i;
22479
+ int vndr_oui_num = 0;
22480
+
22481
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
22482
+ wl_vndr_oui_entry_t *oui_entry = NULL;
22483
+ struct parsed_vndr_ie_info *vndr_info;
22484
+ struct parsed_vndr_ies vndr_ies;
22485
+
22486
+ char *pos = vndr_oui;
22487
+ u32 remained_buf_len = vndr_oui_len;
22488
+ unsigned long flags;
22489
+
22490
+ if (!conn_info->resp_ie_len) {
22491
+ return BCME_ERROR;
22492
+ }
22493
+
22494
+ wl_vndr_ies_clear_vendor_oui_list(cfg);
22495
+
22496
+ if ((wl_cfg80211_parse_vndr_ies((u8 *)conn_info->resp_ie,
22497
+ conn_info->resp_ie_len, &vndr_ies)) == BCME_OK) {
22498
+ for (i = 0; i < vndr_ies.count; i++) {
22499
+ vndr_info = &vndr_ies.ie_info[i];
22500
+ if (wl_vndr_ies_exclude_vndr_oui(vndr_info)) {
22501
+ continue;
22502
+ }
22503
+
22504
+ if (wl_vndr_ies_check_duplicate_vndr_oui(cfg, vndr_info)) {
22505
+ continue;
22506
+ }
22507
+
22508
+ wl_vndr_ies_add_vendor_oui_list(cfg, vndr_info);
22509
+ vndr_oui_num++;
22510
+ }
22511
+ }
22512
+
22513
+ if (vndr_oui) {
22514
+ WL_CFG_VNDR_OUI_SYNC_LOCK(&cfg->vndr_oui_sync, flags);
22515
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
22516
+ list_for_each_entry(oui_entry, &cfg->vndr_oui_list, list) {
22517
+ GCC_DIAGNOSTIC_POP();
22518
+ if (remained_buf_len < VNDR_OUI_STR_LEN) {
22519
+ WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22520
+ return BCME_ERROR;
22521
+ }
22522
+ pos += snprintf(pos, VNDR_OUI_STR_LEN, "%02X-%02X-%02X ",
22523
+ oui_entry->oui[0], oui_entry->oui[1], oui_entry->oui[2]);
22524
+ remained_buf_len -= VNDR_OUI_STR_LEN;
22525
+ }
22526
+ WL_CFG_VNDR_OUI_SYNC_UNLOCK(&cfg->vndr_oui_sync, flags);
22527
+ }
22528
+
22529
+ return vndr_oui_num;
22530
+}
22531
+
22532
+void
22533
+wl_cfg80211_clear_p2p_disc_ies(struct bcm_cfg80211 *cfg)
22534
+{
22535
+ /* Legacy P2P used to store it in primary dev cache */
22536
+ s32 index;
22537
+ struct net_device *ndev;
22538
+ s32 bssidx;
22539
+ s32 ret;
22540
+ s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
22541
+ VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
22542
+
22543
+ WL_DBG(("Clear IEs for P2P Discovery Iface \n"));
22544
+ /* certain vendors uses p2p0 interface in addition to
22545
+ * the dedicated p2p interface supported by the linux
22546
+ * kernel.
22547
+ */
22548
+ ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
22549
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
22550
+ if (bssidx == WL_INVALID) {
22551
+ WL_DBG(("No discovery I/F available. Do nothing.\n"));
22552
+ return;
22553
+ }
22554
+
22555
+ for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
22556
+ if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
22557
+ bssidx, vndrie_flag[index], NULL, 0)) < 0) {
22558
+ if (ret != BCME_NOTFOUND) {
22559
+ WL_ERR(("vndr_ies clear failed (%d). Ignoring.. \n", ret));
22560
+ }
22561
+ }
22562
+ }
22563
+
22564
+ if (cfg->p2p_wdev && (ndev->ieee80211_ptr != cfg->p2p_wdev)) {
22565
+ /* clear IEs for dedicated p2p interface */
22566
+ wl_cfg80211_clear_per_bss_ies(cfg, cfg->p2p_wdev);
22567
+ }
22568
+}
22569
+
1573822570 s32
15739
-wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, s32 bssidx)
22571
+wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
1574022572 {
1574122573 s32 index;
22574
+ s32 ret;
1574222575 struct net_info *netinfo;
1574322576 s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
1574422577 VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
1574522578
15746
- netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
22579
+ netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
1574722580 if (!netinfo || !netinfo->wdev) {
1574822581 WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
1574922582 return -1;
1575022583 }
1575122584
15752
- WL_DBG(("clear management vendor IEs for bssidx:%d \n", bssidx));
22585
+ WL_DBG(("clear management vendor IEs for bssidx:%d \n", netinfo->bssidx));
1575322586 /* Clear the IEs set in the firmware so that host is in sync with firmware */
1575422587 for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
15755
- if (wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
15756
- bssidx, vndrie_flag[index], NULL, 0) < 0)
15757
- WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
22588
+ if ((ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
22589
+ netinfo->bssidx, vndrie_flag[index], NULL, 0)) < 0)
22590
+ if (ret != BCME_NOTFOUND) {
22591
+ WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
22592
+ }
1575822593 }
1575922594
1576022595 return 0;
....@@ -15766,18 +22601,11 @@
1576622601 struct net_info *iter, *next;
1576722602
1576822603 WL_DBG(("clear management vendor IEs \n"));
15769
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15770
- 4 && __GNUC_MINOR__ >= 6))
15771
-_Pragma("GCC diagnostic push")
15772
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
15773
-#endif
22604
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1577422605 for_each_ndev(cfg, iter, next) {
15775
- wl_cfg80211_clear_per_bss_ies(cfg, iter->bssidx);
22606
+ GCC_DIAGNOSTIC_POP();
22607
+ wl_cfg80211_clear_per_bss_ies(cfg, iter->wdev);
1577622608 }
15777
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15778
- 4 && __GNUC_MINOR__ >= 6))
15779
-_Pragma("GCC diagnostic pop")
15780
-#endif
1578122609 return 0;
1578222610 }
1578322611
....@@ -15803,27 +22631,29 @@
1580322631 s32 remained_buf_len;
1580422632 wl_bss_vndr_ies_t *ies = NULL;
1580522633 struct net_info *netinfo;
15806
-
15807
- WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d \n",
15808
- pktflag, bssidx, vndr_ie_len));
22634
+ struct wireless_dev *wdev;
1580922635
1581022636 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
22637
+ wdev = cfgdev_to_wdev(cfgdev);
1581122638
1581222639 if (bssidx > WL_MAX_IFS) {
1581322640 WL_ERR(("bssidx > supported concurrent Ifaces \n"));
1581422641 return -EINVAL;
1581522642 }
1581622643
15817
- netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
22644
+ netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
1581822645 if (!netinfo) {
1581922646 WL_ERR(("net_info ptr is NULL \n"));
1582022647 return -EINVAL;
1582122648 }
1582222649
1582322650 /* Clear the global buffer */
15824
- memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf));
22651
+ bzero(g_mgmt_ie_buf, sizeof(g_mgmt_ie_buf));
1582522652 curr_ie_buf = g_mgmt_ie_buf;
1582622653 ies = &netinfo->bss.ies;
22654
+
22655
+ WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d wdev:%p\n",
22656
+ pktflag, bssidx, vndr_ie_len, wdev));
1582722657
1582822658 switch (pktflag) {
1582922659 case VNDR_IE_PRBRSP_FLAG :
....@@ -15851,6 +22681,11 @@
1585122681 mgmt_ie_len = &ies->assoc_req_ie_len;
1585222682 mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
1585322683 break;
22684
+ case VNDR_IE_DISASSOC_FLAG :
22685
+ mgmt_ie_buf = ies->disassoc_ie;
22686
+ mgmt_ie_len = &ies->disassoc_ie_len;
22687
+ mgmt_ie_buf_len = sizeof(ies->disassoc_ie);
22688
+ break;
1585422689 default:
1585522690 mgmt_ie_buf = NULL;
1585622691 mgmt_ie_len = NULL;
....@@ -15865,23 +22700,13 @@
1586522700 /* parse and save new vndr_ie in curr_ie_buff before comparing it */
1586622701 if (vndr_ie && vndr_ie_len && curr_ie_buf) {
1586722702 ptr = curr_ie_buf;
15868
-/* must discard vndr_ie constness, attempt to change vndr_ie arg to non-const
15869
- * causes cascade of errors in other places, fix involves const casts there
15870
- */
15871
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15872
- 4 && __GNUC_MINOR__ >= 6))
15873
-_Pragma("GCC diagnostic push")
15874
-_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
15875
-#endif
15876
- if ((ret = wl_cfg80211_parse_vndr_ies((u8 *)vndr_ie,
15877
- vndr_ie_len, &new_vndr_ies)) < 0) {
22703
+
22704
+ if ((ret = wl_cfg80211_parse_vndr_ies((const u8 *)vndr_ie,
22705
+ vndr_ie_len, &new_vndr_ies)) < 0) {
1587822706 WL_ERR(("parse vndr ie failed \n"));
1587922707 goto exit;
1588022708 }
15881
-#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
15882
- 4 && __GNUC_MINOR__ >= 6))
15883
-_Pragma("GCC diagnostic pop")
15884
-#endif
22709
+
1588522710 for (i = 0; i < new_vndr_ies.count; i++) {
1588622711 struct parsed_vndr_ie_info *vndrie_info =
1588722712 &new_vndr_ies.ie_info[i];
....@@ -15902,7 +22727,7 @@
1590222727 if (mgmt_ie_buf != NULL) {
1590322728 if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
1590422729 (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
15905
- WL_INFORM(("Previous mgmt IE is equals to current IE"));
22730
+ WL_DBG(("Previous mgmt IE is equals to current IE"));
1590622731 goto exit;
1590722732 }
1590822733
....@@ -15916,11 +22741,31 @@
1591622741 for (i = 0; i < old_vndr_ies.count; i++) {
1591722742 struct parsed_vndr_ie_info *vndrie_info =
1591822743 &old_vndr_ies.ie_info[i];
22744
+#if defined(WL_MBO) || defined(WL_OCE)
22745
+ {
22746
+ if ((vndrie_info->vndrie.id == 0xDD) &&
22747
+ (!memcmp(vndrie_info->vndrie.oui, WFA_OUI, WFA_OUI_LEN)) &&
22748
+ (vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
22749
+ WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
22750
+ ", type: %0x\n",
22751
+ vndrie_info->vndrie.id,
22752
+ vndrie_info->vndrie.len,
22753
+ MACOUI2STRDBG(vndrie_info->vndrie.oui),
22754
+ vndrie_info->vndrie.data[0]));
22755
+ continue;
22756
+ }
22757
+ }
22758
+#endif /* WL_MBO || WL_OCE */
1591922759
15920
- WL_INFORM(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
15921
- vndrie_info->vndrie.id, vndrie_info->vndrie.len,
15922
- vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
15923
- vndrie_info->vndrie.oui[2]));
22760
+ if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
22761
+ WL_DBG(("DELETED VENDOR EXTN ID : %d, TYPE: %d Len: %d\n",
22762
+ vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
22763
+ vndrie_info->vndrie.len));
22764
+ } else {
22765
+ WL_DBG(("DELETED ID : %d, Len: %d , OUI:"MACOUIDBG"\n",
22766
+ vndrie_info->vndrie.id, vndrie_info->vndrie.len,
22767
+ MACOUI2STRDBG(vndrie_info->vndrie.oui)));
22768
+ }
1592422769
1592522770 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
1592622771 pktflag, vndrie_info->vndrie.oui,
....@@ -15945,12 +22790,31 @@
1594522790 for (i = 0; i < new_vndr_ies.count; i++) {
1594622791 struct parsed_vndr_ie_info *vndrie_info =
1594722792 &new_vndr_ies.ie_info[i];
15948
-
15949
- WL_INFORM(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n",
15950
- vndrie_info->vndrie.id, vndrie_info->vndrie.len,
15951
- vndrie_info->ie_len - 2,
15952
- vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
15953
- vndrie_info->vndrie.oui[2]));
22793
+#if defined(WL_MBO) || defined(WL_OCE)
22794
+ {
22795
+ if ((vndrie_info->vndrie.id == 0xDD) &&
22796
+ (!memcmp(vndrie_info->vndrie.oui, WFA_OUI, WFA_OUI_LEN)) &&
22797
+ (vndrie_info->vndrie.data[0] == WFA_OUI_TYPE_MBO_OCE)) {
22798
+ WL_DBG(("skipping ID : %d, Len: %d, OUI:"MACOUIDBG
22799
+ ",type :%0x\n",
22800
+ vndrie_info->vndrie.id,
22801
+ vndrie_info->vndrie.len,
22802
+ MACOUI2STRDBG(vndrie_info->vndrie.oui),
22803
+ vndrie_info->vndrie.data[0]));
22804
+ continue;
22805
+ }
22806
+ }
22807
+#endif /* WL_MBO || WL_OCE */
22808
+ if (vndrie_info->vndrie.id == DOT11_MNG_ID_EXT_ID) {
22809
+ WL_DBG(("ADDED VENDOR EXTN ID : %d, TYPE = %d, Len: %d\n",
22810
+ vndrie_info->vndrie.id, vndrie_info->vndrie.oui[0],
22811
+ vndrie_info->vndrie.len));
22812
+ } else {
22813
+ WL_DBG(("ADDED ID : %d, Len: %d(%d), OUI:"MACOUIDBG"\n",
22814
+ vndrie_info->vndrie.id, vndrie_info->vndrie.len,
22815
+ vndrie_info->ie_len - 2,
22816
+ MACOUI2STRDBG(vndrie_info->vndrie.oui)));
22817
+ }
1595422818
1595522819 del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
1595622820 pktflag, vndrie_info->vndrie.oui,
....@@ -16003,6 +22867,7 @@
1600322867 int macnum = 0;
1600422868 int macmode = MACLIST_MODE_DISABLED;
1600522869 struct maclist *list;
22870
+ struct bcm_cfg80211 *cfg = wl_get_cfg(cfgdev);
1600622871
1600722872 /* get the MAC filter mode */
1600822873 if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
....@@ -16015,23 +22880,24 @@
1601522880 /* if acl == NULL, macmode is still disabled.. */
1601622881 if (macmode == MACLIST_MODE_DISABLED) {
1601722882 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0)
16018
- WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
22883
+ WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list"
22884
+ " failed error=%d\n", ret));
1601922885
1602022886 return ret;
1602122887 }
1602222888
1602322889 macnum = acl->n_acl_entries;
1602422890 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
16025
- WL_ERR(("%s : invalid number of MAC address entries %d\n",
16026
- __FUNCTION__, macnum));
22891
+ WL_ERR(("wl_cfg80211_set_mac_acl: invalid number of MAC address entries %d\n",
22892
+ macnum));
1602722893 return -1;
1602822894 }
1602922895
1603022896 /* allocate memory for the MAC list */
16031
- list = (struct maclist*)kmalloc(sizeof(int) +
16032
- sizeof(struct ether_addr) * macnum, GFP_KERNEL);
22897
+ list = (struct maclist *)MALLOC(cfg->osh, sizeof(int) +
22898
+ sizeof(struct ether_addr) * macnum);
1603322899 if (!list) {
16034
- WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__));
22900
+ WL_ERR(("wl_cfg80211_set_mac_acl: failed to allocate memory\n"));
1603522901 return -1;
1603622902 }
1603722903
....@@ -16042,9 +22908,10 @@
1604222908 }
1604322909 /* set the list */
1604422910 if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0)
16045
- WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
22911
+ WL_ERR(("wl_cfg80211_set_mac_acl: Setting MAC list failed error=%d\n", ret));
1604622912
16047
- kfree(list);
22913
+ MFREE(cfg->osh, list, sizeof(int) +
22914
+ sizeof(struct ether_addr) * macnum);
1604822915
1604922916 return ret;
1605022917 }
....@@ -16055,17 +22922,15 @@
1605522922 struct cfg80211_chan_def *chandef,
1605622923 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
1605722924 \
16058
- \
16059
- \
1606022925 0)))
1606122926 struct chan_info *chaninfo,
1606222927 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
16063
-struct wiphy *wiphy)
16064
-
22928
+ struct wiphy *wiphy)
1606522929 {
1606622930 uint16 freq = 0;
1606722931 int chan_type = 0;
1606822932 int channel = 0;
22933
+ struct ieee80211_channel *chan;
1606922934
1607022935 if (!chandef) {
1607122936 return -1;
....@@ -16080,11 +22945,12 @@
1608022945 {
1608122946 if (CHSPEC_SB_UPPER(chanspec)) {
1608222947 channel += CH_10MHZ_APART;
22948
+ chan_type = NL80211_CHAN_HT40MINUS;
1608322949 } else {
1608422950 channel -= CH_10MHZ_APART;
22951
+ chan_type = NL80211_CHAN_HT40PLUS;
1608522952 }
1608622953 }
16087
- chan_type = NL80211_CHAN_HT40PLUS;
1608822954 break;
1608922955
1609022956 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
....@@ -16104,9 +22970,9 @@
1610422970 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
1610522971 }
1610622972
16107
- if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_LU)
22973
+ if (sb == WL_CHANSPEC_CTL_SB_LU || sb == WL_CHANSPEC_CTL_SB_UU)
1610822974 chan_type = NL80211_CHAN_HT40MINUS;
16109
- else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU)
22975
+ else if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_UL)
1611022976 chan_type = NL80211_CHAN_HT40PLUS;
1611122977 }
1611222978 break;
....@@ -16122,11 +22988,20 @@
1612222988 else
1612322989 freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
1612422990
22991
+ chan = ieee80211_get_channel(wiphy, freq);
22992
+ WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
22993
+ channel, freq, chan_type, chan));
22994
+
22995
+ if (unlikely(!chan)) {
22996
+ /* fw and cfg80211 channel lists are not in sync */
22997
+ WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
22998
+ ASSERT(0);
22999
+ return -EINVAL;
23000
+ }
23001
+
1612523002 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
16126
- cfg80211_chandef_create(chandef, ieee80211_get_channel(wiphy, freq), chan_type);
23003
+ cfg80211_chandef_create(chandef, chan, chan_type);
1612723004 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
16128
- \
16129
- \
1613023005 \
1613123006 0)))
1613223007 chaninfo->freq = freq;
....@@ -16143,27 +23018,36 @@
1614323018 struct cfg80211_chan_def chandef;
1614423019 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
1614523020 \
16146
- \
16147
- \
1614823021 0)))
1614923022 struct chan_info chaninfo;
1615023023 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
23024
+#if !defined(DISALBE_11H) && defined(DHD_NOSCAN_DURING_CSA)
23025
+ struct bcm_cfg80211 *cfg = NULL;
23026
+#endif // endif
1615123027
1615223028 if (!wiphy) {
1615323029 WL_ERR(("wiphy is null\n"));
1615423030 return;
1615523031 }
23032
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0))
1615623033 /* Channel switch support is only for AP/GO/ADHOC/MESH */
1615723034 if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
1615823035 dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
1615923036 WL_ERR(("No channel switch notify support for STA/GC\n"));
1616023037 return;
1616123038 }
23039
+#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION (3, 18, 0)) */
23040
+
23041
+#if !defined(DISALBE_11H) && defined(DHD_NOSCAN_DURING_CSA)
23042
+ cfg = wl_get_cfg(dev);
23043
+ if (cfg->in_csa) {
23044
+ cfg->in_csa = FALSE;
23045
+ wl_del_csa_timeout(cfg);
23046
+ }
23047
+#endif // endif
1616223048 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
1616323049 if (wl_chspec_chandef(chanspec, &chandef, wiphy)) {
1616423050 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
16165
- \
16166
- \
1616723051 \
1616823052 0)))
1616923053 if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) {
....@@ -16177,8 +23061,6 @@
1617723061 cfg80211_ch_switch_notify(dev, &chandef);
1617823062 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
1617923063 \
16180
- \
16181
- \
1618223064 0)))
1618323065 freq = chan_info.freq;
1618423066 cfg80211_ch_switch_notify(dev, freq, chan_info.chan_type);
....@@ -16189,208 +23071,67 @@
1618923071 }
1619023072 #endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
1619123073
16192
-#ifdef WL11ULB
16193
-s32
16194
-wl_cfg80211_set_ulb_mode(struct net_device *dev, int mode)
23074
+static void
23075
+wl_ap_channel_ind(struct bcm_cfg80211 *cfg,
23076
+ struct net_device *ndev,
23077
+ chanspec_t chanspec)
1619523078 {
16196
- int ret;
16197
- int cur_mode;
23079
+ u32 channel = LCHSPEC_CHANNEL(chanspec);
1619823080
16199
- ret = wldev_iovar_getint(dev, "ulb_mode", &cur_mode);
16200
- if (unlikely(ret)) {
16201
- WL_ERR(("[ULB] ulb_mode get failed. ret:%d \n", ret));
16202
- return ret;
16203
- }
16204
-
16205
- if (cur_mode == mode) {
16206
- /* If request mode is same as that of the current mode, then
16207
- * do nothing (Avoid unnecessary wl down and up).
23081
+ WL_INFORM_MEM(("(%s) AP channel:%d chspec:0x%x \n",
23082
+ ndev->name, channel, chanspec));
23083
+ if (cfg->ap_oper_channel && (cfg->ap_oper_channel != channel)) {
23084
+ /*
23085
+ * If cached channel is different from the channel indicated
23086
+ * by the event, notify user space about the channel switch.
1620823087 */
16209
- WL_INFORM(("[ULB] No change in ulb_mode. Do nothing.\n"));
16210
- return 0;
16211
- }
16212
-
16213
- /* setting of ulb_mode requires wl to be down */
16214
- ret = wldev_ioctl(dev, WLC_DOWN, NULL, 0, true);
16215
- if (unlikely(ret)) {
16216
- WL_ERR(("[ULB] WLC_DOWN command failed:[%d]\n", ret));
16217
- return ret;
16218
- }
16219
-
16220
- if (mode >= MAX_SUPP_ULB_MODES) {
16221
- WL_ERR(("[ULB] unsupported ulb_mode :[%d]\n", mode));
16222
- return -EINVAL;
16223
- }
16224
-
16225
- ret = wldev_iovar_setint(dev, "ulb_mode", mode);
16226
- if (unlikely(ret)) {
16227
- WL_ERR(("[ULB] ulb_mode set failed. ret:%d \n", ret));
16228
- return ret;
16229
- }
16230
-
16231
- ret = wldev_ioctl(dev, WLC_UP, NULL, 0, true);
16232
- if (unlikely(ret)) {
16233
- WL_ERR(("[ULB] WLC_DOWN command failed:[%d]\n", ret));
16234
- return ret;
16235
- }
16236
-
16237
- WL_DBG(("[ULB] ulb_mode set to %d successfully \n", mode));
16238
-
16239
- return ret;
16240
-}
16241
-
16242
-static s32
16243
-wl_cfg80211_ulbbw_to_ulbchspec(u32 bw)
16244
-{
16245
- if (bw == ULB_BW_DISABLED) {
16246
- return WL_CHANSPEC_BW_20;
16247
- } else if (bw == ULB_BW_10MHZ) {
16248
- return WL_CHANSPEC_BW_10;
16249
- } else if (bw == ULB_BW_5MHZ) {
16250
- return WL_CHANSPEC_BW_5;
16251
- } else if (bw == ULB_BW_2P5MHZ) {
16252
- return WL_CHANSPEC_BW_2P5;
16253
- } else {
16254
- WL_ERR(("[ULB] unsupported value for ulb_bw \n"));
16255
- return -EINVAL;
16256
- }
16257
-}
16258
-
16259
-static chanspec_t
16260
-wl_cfg80211_ulb_get_min_bw_chspec(struct wireless_dev *wdev, s32 bssidx)
16261
-{
16262
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
16263
- struct net_info *_netinfo;
16264
-
16265
- /*
16266
- * Return the chspec value corresponding to the
16267
- * BW setting for a particular interface
16268
- */
16269
- if (wdev) {
16270
- /* if wdev is provided, use it */
16271
- _netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
16272
- } else if (bssidx >= 0) {
16273
- /* if wdev is not provided, use it */
16274
- _netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
16275
- } else {
16276
- WL_ERR(("[ULB] wdev/bssidx not provided\n"));
16277
- return INVCHANSPEC;
16278
- }
16279
-
16280
- if (unlikely(!_netinfo)) {
16281
- WL_ERR(("[ULB] net_info is null \n"));
16282
- return INVCHANSPEC;
16283
- }
16284
-
16285
- if (_netinfo->ulb_bw) {
16286
- WL_DBG(("[ULB] wdev_ptr:%p ulb_bw:0x%x \n", _netinfo->wdev, _netinfo->ulb_bw));
16287
- return wl_cfg80211_ulbbw_to_ulbchspec(_netinfo->ulb_bw);
16288
- } else {
16289
- return WL_CHANSPEC_BW_20;
23088
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
23089
+ wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
23090
+#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
23091
+ cfg->ap_oper_channel = channel;
1629023092 }
1629123093 }
1629223094
1629323095 static s32
16294
-wl_cfg80211_get_ulb_bw(struct wireless_dev *wdev)
23096
+wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
23097
+const wl_event_msg_t *e, void *data)
1629523098 {
16296
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
16297
- struct net_info *_netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
23099
+ struct net_device *ndev = NULL;
23100
+ chanspec_t chanspec;
1629823101
16299
- /*
16300
- * Return the ulb_bw setting for a
16301
- * particular interface
16302
- */
16303
- if (unlikely(!_netinfo)) {
16304
- WL_ERR(("[ULB] net_info is null \n"));
23102
+ WL_DBG(("Enter\n"));
23103
+ if (unlikely(e->status)) {
23104
+ WL_ERR(("status:0x%x \n", e->status));
1630523105 return -1;
1630623106 }
1630723107
16308
- return _netinfo->ulb_bw;
23108
+ if (!data) {
23109
+ return -EINVAL;
23110
+ }
23111
+
23112
+ if (likely(cfgdev)) {
23113
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
23114
+ chanspec = *((chanspec_t *)data);
23115
+
23116
+#ifndef NO_CHANIND_FOR_AP_START
23117
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
23118
+ /* For AP/GO role */
23119
+ wl_ap_channel_ind(cfg, ndev, chanspec);
23120
+ }
23121
+#endif /* NO_CHANIND_FOR_AP_START */
23122
+ }
23123
+
23124
+ return 0;
1630923125 }
1631023126
16311
-s32
16312
-wl_cfg80211_set_ulb_bw(struct net_device *dev,
16313
- u32 ulb_bw, char *ifname)
16314
-{
16315
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
16316
- int ret;
16317
- int mode;
16318
- struct net_info *_netinfo = NULL, *iter, *next;
16319
- u32 bssidx;
16320
- enum nl80211_iftype iftype;
16321
-
16322
- if (!ifname)
16323
- return -EINVAL;
16324
-
16325
- WL_DBG(("[ULB] Enter. bw_type:%d \n", ulb_bw));
16326
-
16327
- ret = wldev_iovar_getint(dev, "ulb_mode", &mode);
16328
- if (unlikely(ret)) {
16329
- WL_ERR(("[ULB] ulb_mode not supported \n"));
16330
- return ret;
16331
- }
16332
-
16333
- if (mode != ULB_MODE_STD_ALONE_MODE) {
16334
- WL_ERR(("[ULB] ulb bw modification allowed only in stand-alone mode\n"));
16335
- return -EINVAL;
16336
- }
16337
-
16338
- if (ulb_bw >= MAX_SUPP_ULB_BW) {
16339
- WL_ERR(("[ULB] unsupported value (%d) for ulb_bw \n", ulb_bw));
16340
- return -EINVAL;
16341
- }
16342
-
16343
-#ifdef WL_CFG80211_P2P_DEV_IF
16344
- if (strcmp(ifname, "p2p-dev-wlan0") == 0) {
16345
- iftype = NL80211_IFTYPE_P2P_DEVICE;
16346
- /* Use wdev corresponding to the dedicated p2p discovery interface */
16347
- if (likely(cfg->p2p_wdev)) {
16348
- _netinfo = wl_get_netinfo_by_wdev(cfg, cfg->p2p_wdev);
16349
- } else {
16350
- return -ENODEV;
16351
- }
16352
- }
16353
-#endif /* WL_CFG80211_P2P_DEV_IF */
16354
- if (!_netinfo) {
16355
- for_each_ndev(cfg, iter, next) {
16356
- if (iter->ndev) {
16357
- if (strncmp(iter->ndev->name, ifname, strlen(ifname)) == 0) {
16358
- _netinfo = wl_get_netinfo_by_netdev(cfg, iter->ndev);
16359
- iftype = NL80211_IFTYPE_STATION;
16360
- }
16361
- }
16362
- }
16363
- }
16364
-
16365
- if (!_netinfo)
16366
- return -ENODEV;
16367
- bssidx = _netinfo->bssidx;
16368
- _netinfo->ulb_bw = ulb_bw;
16369
-
16370
-
16371
- WL_DBG(("[ULB] Applying ulb_bw:%d for bssidx:%d \n", ulb_bw, bssidx));
16372
- ret = wldev_iovar_setbuf_bsscfg(dev, "ulb_bw", (void *)&ulb_bw, 4,
16373
- cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx,
16374
- &cfg->ioctl_buf_sync);
16375
- if (unlikely(ret)) {
16376
- WL_ERR(("[ULB] ulb_bw set failed. ret:%d \n", ret));
16377
- return ret;
16378
- }
16379
-
16380
- return ret;
16381
-}
16382
-#endif /* WL11ULB */
16383
-
16384
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
1638523127 static s32
1638623128 wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1638723129 const wl_event_msg_t *e, void *data)
1638823130 {
1638923131 int error = 0;
16390
- int chsp = 0;
23132
+ u32 chanspec = 0;
1639123133 struct net_device *ndev = NULL;
16392
- struct wiphy *wiphy = NULL;
16393
- chanspec_t chanspec;
23134
+ struct ether_addr bssid;
1639423135
1639523136 WL_DBG(("Enter\n"));
1639623137 if (unlikely(e->status)) {
....@@ -16400,39 +23141,41 @@
1640023141
1640123142 if (likely(cfgdev)) {
1640223143 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
16403
- wiphy = bcmcfg_to_wiphy(cfg);
16404
- error = wldev_iovar_getint(ndev, "chanspec", &chsp);
23144
+ /* Get association state if not AP and then query chanspec */
23145
+ if (!((wl_get_mode_by_netdev(cfg, ndev)) == WL_MODE_AP)) {
23146
+ error = wldev_ioctl_get(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
23147
+ if (error) {
23148
+ WL_ERR(("CSA on %s. Not associated. error=%d\n",
23149
+ ndev->name, error));
23150
+ return BCME_ERROR;
23151
+ }
23152
+ }
23153
+
23154
+ error = wldev_iovar_getint(ndev, "chanspec", &chanspec);
1640523155 if (unlikely(error)) {
1640623156 WL_ERR(("Get chanspec error: %d \n", error));
1640723157 return -1;
1640823158 }
16409
- chanspec = wl_chspec_driver_to_host(chsp);
16410
- wl_cfg80211_ch_switch_notify(ndev, chanspec, wiphy);
16411
- } else {
16412
- WL_ERR(("cfgdev is null\n"));
16413
- return -1;
23159
+
23160
+ WL_INFORM_MEM(("[%s] CSA ind. ch:0x%x\n", ndev->name, chanspec));
23161
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
23162
+ /* For AP/GO role */
23163
+ wl_ap_channel_ind(cfg, ndev, chanspec);
23164
+ } else {
23165
+ /* STA/GC roles */
23166
+ if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
23167
+ WL_ERR(("CSA on %s. Not associated.\n", ndev->name));
23168
+ return BCME_ERROR;
23169
+ }
23170
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
23171
+ wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
23172
+#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
23173
+ }
23174
+
1641423175 }
1641523176
1641623177 return 0;
1641723178 }
16418
-#else
16419
-static s32
16420
-wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
16421
-const wl_event_msg_t *e, void *data)
16422
-{
16423
- WL_ERR(("%s:Not sup for kernel < 3.5\n", __FUNCTION__));
16424
- return 0;
16425
-}
16426
-#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
16427
-
16428
-
16429
-#ifdef WL_NAN
16430
-int
16431
-wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd, int cmd_len)
16432
-{
16433
- return wl_cfgnan_cmd_handler(ndev, g_bcm_cfg, cmd, cmd_len);
16434
-}
16435
-#endif /* WL_NAN */
1643623179
1643723180 void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
1643823181 {
....@@ -16455,9 +23198,9 @@
1645523198 }
1645623199
1645723200 #ifdef WL_CFG80211_P2P_DEV_IF
16458
-void wl_cfg80211_del_p2p_wdev(void)
23201
+void wl_cfg80211_del_p2p_wdev(struct net_device *dev)
1645923202 {
16460
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
23203
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1646123204 struct wireless_dev *wdev = NULL;
1646223205
1646323206 WL_DBG(("Enter \n"));
....@@ -16475,47 +23218,6 @@
1647523218 }
1647623219 #endif /* WL_CFG80211_P2P_DEV_IF */
1647723220
16478
-#if defined(WL_SUPPORT_AUTO_CHANNEL)
16479
-int
16480
-wl_cfg80211_set_spect(struct net_device *dev, int spect)
16481
-{
16482
- struct bcm_cfg80211 *cfg = g_bcm_cfg;
16483
- int down = 1;
16484
- int up = 1;
16485
- int err = BCME_OK;
16486
-
16487
- if (!wl_get_drv_status_all(cfg, CONNECTED)) {
16488
- err = wldev_ioctl(dev, WLC_DOWN, &down, sizeof(down), true);
16489
- if (err) {
16490
- WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
16491
- return err;
16492
- }
16493
-
16494
- err = wldev_ioctl(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect), true);
16495
- if (err) {
16496
- WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
16497
- return err;
16498
- }
16499
-
16500
- err = wldev_ioctl(dev, WLC_UP, &up, sizeof(up), true);
16501
- if (err) {
16502
- WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
16503
- return err;
16504
- }
16505
- }
16506
- return err;
16507
-}
16508
-
16509
-int
16510
-wl_cfg80211_get_sta_channel(struct net_device *dev)
16511
-{
16512
- if (wl_get_drv_status(g_bcm_cfg, CONNECTED, dev)) {
16513
- return g_bcm_cfg->channel;
16514
- }
16515
- return BCME_OK;
16516
-}
16517
-#endif /* WL_SUPPORT_AUTO_CHANNEL */
16518
-
1651923221 #ifdef GTK_OFFLOAD_SUPPORT
1652023222 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
1652123223 static s32
....@@ -16531,15 +23233,10 @@
1653123233 WL_ERR(("data is NULL or wrong net device\n"));
1653223234 return -EINVAL;
1653323235 }
16534
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
16535
- prhex("kck", (uchar *) (data->kck), RSN_KCK_LENGTH);
16536
- prhex("kek", (uchar *) (data->kek), RSN_KEK_LENGTH);
16537
- prhex("replay_ctr", (uchar *) (data->replay_ctr), RSN_REPLAY_LEN);
16538
-#else
16539
- prhex("kck", data->kck, RSN_KCK_LENGTH);
16540
- prhex("kek", data->kek, RSN_KEK_LENGTH);
16541
- prhex("replay_ctr", data->replay_ctr, RSN_REPLAY_LEN);
16542
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) */
23236
+
23237
+ prhex("kck", (const u8 *) (data->kck), RSN_KCK_LENGTH);
23238
+ prhex("kek", (const u8 *) (data->kek), RSN_KEK_LENGTH);
23239
+ prhex("replay_ctr", (const u8 *) (data->replay_ctr), RSN_REPLAY_LEN);
1654323240 bcopy(data->kck, keyinfo.KCK, RSN_KCK_LENGTH);
1654423241 bcopy(data->kek, keyinfo.KEK, RSN_KEK_LENGTH);
1654523242 bcopy(data->replay_ctr, keyinfo.ReplayCounter, RSN_REPLAY_LEN);
....@@ -16553,4 +23250,2763 @@
1655323250 return err;
1655423251 }
1655523252 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) */
16556
-#endif
23253
+#endif /* GTK_OFFLOAD_SUPPORT */
23254
+
23255
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0))
23256
+static int wl_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
23257
+ const struct cfg80211_pmk_conf *conf)
23258
+{
23259
+ int ret = 0;
23260
+ wsec_pmk_t pmk;
23261
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
23262
+ struct wl_security *sec;
23263
+ s32 bssidx;
23264
+
23265
+ pmk.key_len = conf->pmk_len;
23266
+ if (pmk.key_len > sizeof(pmk.key)) {
23267
+ ret = -EINVAL;
23268
+ return ret;
23269
+ }
23270
+ pmk.flags = 0;
23271
+ ret = memcpy_s(&pmk.key, sizeof(pmk.key), conf->pmk, conf->pmk_len);
23272
+ if (ret) {
23273
+ ret = -EINVAL;
23274
+ return ret;
23275
+ }
23276
+
23277
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
23278
+ WL_ERR(("Find index failed\n"));
23279
+ ret = -EINVAL;
23280
+ return ret;
23281
+ }
23282
+
23283
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
23284
+ if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
23285
+ (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
23286
+ ret = wldev_iovar_setbuf_bsscfg(dev, "okc_info_pmk", pmk.key, pmk.key_len,
23287
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
23288
+ if (ret) {
23289
+ /* could fail in case that 'okc' is not supported */
23290
+ WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
23291
+ }
23292
+ }
23293
+
23294
+ ret = wldev_ioctl_set(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
23295
+ if (ret) {
23296
+ WL_ERR(("wl_cfg80211_set_pmk error:%d", ret));
23297
+ ret = -EINVAL;
23298
+ return ret;
23299
+ }
23300
+ return 0;
23301
+}
23302
+
23303
+static int wl_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
23304
+ const u8 *aa)
23305
+{
23306
+ int err = BCME_OK;
23307
+ struct cfg80211_pmksa pmksa;
23308
+
23309
+ /* build up cfg80211_pmksa structure to use existing wl_cfg80211_update_pmksa API */
23310
+ bzero(&pmksa, sizeof(pmksa));
23311
+ pmksa.bssid = aa;
23312
+
23313
+ err = wl_cfg80211_update_pmksa(wiphy, dev, &pmksa, FALSE);
23314
+
23315
+ if (err) {
23316
+ WL_ERR(("wl_cfg80211_update_pmksa err:%d\n", err));
23317
+ err = -EINVAL;
23318
+ }
23319
+
23320
+ return err;
23321
+}
23322
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) */
23323
+
23324
+#if defined(WL_SUPPORT_AUTO_CHANNEL)
23325
+int
23326
+wl_cfg80211_set_spect(struct net_device *dev, int spect)
23327
+{
23328
+ int wlc_down = 1;
23329
+ int wlc_up = 1;
23330
+ int err = BCME_OK;
23331
+
23332
+ err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
23333
+ if (err) {
23334
+ WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
23335
+ return err;
23336
+ }
23337
+
23338
+ err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
23339
+ if (err) {
23340
+ WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
23341
+ return err;
23342
+ }
23343
+
23344
+ err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
23345
+ if (err) {
23346
+ WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
23347
+ return err;
23348
+ }
23349
+ return err;
23350
+}
23351
+
23352
+int
23353
+wl_cfg80211_get_sta_channel(struct bcm_cfg80211 *cfg)
23354
+{
23355
+ int channel = 0;
23356
+
23357
+ if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
23358
+ channel = cfg->channel;
23359
+ }
23360
+ return channel;
23361
+}
23362
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
23363
+
23364
+u64
23365
+wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
23366
+{
23367
+ u64 id = 0;
23368
+ id = ++cfg->last_roc_id;
23369
+#ifdef P2P_LISTEN_OFFLOADING
23370
+ if (id == P2PO_COOKIE) {
23371
+ id = ++cfg->last_roc_id;
23372
+ }
23373
+#endif /* P2P_LISTEN_OFFLOADING */
23374
+ if (id == 0)
23375
+ id = ++cfg->last_roc_id;
23376
+ return id;
23377
+}
23378
+
23379
+#ifdef WLTDLS
23380
+s32
23381
+wl_cfg80211_tdls_config(struct bcm_cfg80211 *cfg, enum wl_tdls_config state, bool auto_mode)
23382
+{
23383
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
23384
+ int err = 0;
23385
+ struct net_info *iter, *next;
23386
+ int update_reqd = 0;
23387
+ int enable = 0;
23388
+ dhd_pub_t *dhdp;
23389
+ dhdp = (dhd_pub_t *)(cfg->pub);
23390
+
23391
+ /*
23392
+ * TDLS need to be enabled only if we have a single STA/GC
23393
+ * connection.
23394
+ */
23395
+
23396
+ WL_DBG(("Enter state:%d\n", state));
23397
+ if (!cfg->tdls_supported) {
23398
+ /* FW doesn't support tdls. Do nothing */
23399
+ return -ENODEV;
23400
+ }
23401
+
23402
+ /* Protect tdls config session */
23403
+ mutex_lock(&cfg->tdls_sync);
23404
+
23405
+ if (state == TDLS_STATE_TEARDOWN) {
23406
+ /* Host initiated TDLS tear down */
23407
+ err = dhd_tdls_enable(ndev, false, auto_mode, NULL);
23408
+ goto exit;
23409
+ } else if ((state == TDLS_STATE_AP_CREATE) ||
23410
+ (state == TDLS_STATE_NMI_CREATE)) {
23411
+ /* We don't support tdls while AP/GO/NAN is operational */
23412
+ update_reqd = true;
23413
+ enable = false;
23414
+ } else if ((state == TDLS_STATE_CONNECT) || (state == TDLS_STATE_IF_CREATE)) {
23415
+ if (wl_get_drv_status_all(cfg,
23416
+ CONNECTED) >= TDLS_MAX_IFACE_FOR_ENABLE) {
23417
+ /* For STA/GC connect command request, disable
23418
+ * tdls if we have any concurrent interfaces
23419
+ * operational.
23420
+ */
23421
+ WL_DBG(("Interface limit restriction. disable tdls.\n"));
23422
+ update_reqd = true;
23423
+ enable = false;
23424
+ }
23425
+ } else if ((state == TDLS_STATE_DISCONNECT) ||
23426
+ (state == TDLS_STATE_AP_DELETE) ||
23427
+ (state == TDLS_STATE_SETUP) ||
23428
+ (state == TDLS_STATE_IF_DELETE)) {
23429
+ /* Enable back the tdls connection only if we have less than
23430
+ * or equal to a single STA/GC connection.
23431
+ */
23432
+ if (wl_get_drv_status_all(cfg,
23433
+ CONNECTED) == 0) {
23434
+ /* If there are no interfaces connected, enable tdls */
23435
+ update_reqd = true;
23436
+ enable = true;
23437
+ } else if (wl_get_drv_status_all(cfg,
23438
+ CONNECTED) == TDLS_MAX_IFACE_FOR_ENABLE) {
23439
+ /* We have one interface in CONNECTED state.
23440
+ * Verify whether its a STA interface before
23441
+ * we enable back tdls.
23442
+ */
23443
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23444
+ for_each_ndev(cfg, iter, next) {
23445
+ GCC_DIAGNOSTIC_POP();
23446
+ if ((iter->ndev) && (wl_get_drv_status(cfg, CONNECTED, ndev)) &&
23447
+ (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)) {
23448
+ WL_DBG(("Non STA iface operational. cfg_iftype:%d"
23449
+ " Can't enable tdls.\n",
23450
+ ndev->ieee80211_ptr->iftype));
23451
+ err = -ENOTSUPP;
23452
+ goto exit;
23453
+ }
23454
+ }
23455
+ /* No AP/GO found. Enable back tdls */
23456
+ update_reqd = true;
23457
+ enable = true;
23458
+ } else {
23459
+ WL_DBG(("Concurrent connection mode. Can't enable tdls. \n"));
23460
+ err = -ENOTSUPP;
23461
+ goto exit;
23462
+ }
23463
+ } else {
23464
+ WL_ERR(("Unknown tdls state:%d \n", state));
23465
+ err = -EINVAL;
23466
+ goto exit;
23467
+ }
23468
+
23469
+ if (update_reqd == true) {
23470
+ if (dhdp->tdls_enable == enable) {
23471
+ WL_DBG(("No change in tdls state. Do nothing."
23472
+ " tdls_enable:%d\n", enable));
23473
+ goto exit;
23474
+ }
23475
+ err = wldev_iovar_setint(ndev, "tdls_enable", enable);
23476
+ if (unlikely(err)) {
23477
+ WL_ERR(("tdls_enable setting failed. err:%d\n", err));
23478
+ goto exit;
23479
+ } else {
23480
+ WL_INFORM_MEM(("tdls_enable %d state:%d\n", enable, state));
23481
+ /* Update the dhd state variable to be in sync */
23482
+ dhdp->tdls_enable = enable;
23483
+ if (state == TDLS_STATE_SETUP) {
23484
+ /* For host initiated setup, apply TDLS params
23485
+ * Don't propagate errors up for param config
23486
+ * failures
23487
+ */
23488
+ dhd_tdls_enable(ndev, true, auto_mode, NULL);
23489
+
23490
+ }
23491
+ }
23492
+ } else {
23493
+ WL_DBG(("Skip tdls config. state:%d update_reqd:%d "
23494
+ "current_status:%d \n",
23495
+ state, update_reqd, dhdp->tdls_enable));
23496
+ }
23497
+
23498
+exit:
23499
+ if (err) {
23500
+ wl_flush_fw_log_buffer(ndev, FW_LOGSET_MASK_ALL);
23501
+ }
23502
+ mutex_unlock(&cfg->tdls_sync);
23503
+ return err;
23504
+}
23505
+#endif /* WLTDLS */
23506
+
23507
+struct net_device* wl_get_ap_netdev(struct bcm_cfg80211 *cfg, char *ifname)
23508
+{
23509
+ struct net_info *iter, *next;
23510
+ struct net_device *ndev = NULL;
23511
+
23512
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23513
+ for_each_ndev(cfg, iter, next) {
23514
+ GCC_DIAGNOSTIC_POP();
23515
+ if (iter->ndev) {
23516
+ if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
23517
+ if (iter->ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
23518
+ ndev = iter->ndev;
23519
+ break;
23520
+ }
23521
+ }
23522
+ }
23523
+ }
23524
+
23525
+ return ndev;
23526
+}
23527
+
23528
+struct net_device*
23529
+wl_get_netdev_by_name(struct bcm_cfg80211 *cfg, char *ifname)
23530
+{
23531
+ struct net_info *iter, *next;
23532
+ struct net_device *ndev = NULL;
23533
+
23534
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23535
+ for_each_ndev(cfg, iter, next) {
23536
+ GCC_DIAGNOSTIC_POP();
23537
+ if (iter->ndev) {
23538
+ if (strncmp(iter->ndev->name, ifname, IFNAMSIZ) == 0) {
23539
+ ndev = iter->ndev;
23540
+ break;
23541
+ }
23542
+ }
23543
+ }
23544
+
23545
+ return ndev;
23546
+}
23547
+
23548
+#ifdef SUPPORT_AP_HIGHER_BEACONRATE
23549
+#define WLC_RATE_FLAG 0x80
23550
+#define RATE_MASK 0x7f
23551
+
23552
+int wl_set_ap_beacon_rate(struct net_device *dev, int val, char *ifname)
23553
+{
23554
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23555
+ dhd_pub_t *dhdp;
23556
+ wl_rateset_args_t rs;
23557
+ int error = BCME_ERROR, i;
23558
+ struct net_device *ndev = NULL;
23559
+
23560
+ dhdp = (dhd_pub_t *)(cfg->pub);
23561
+
23562
+ if (dhdp && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23563
+ WL_ERR(("Not Hostapd mode\n"));
23564
+ return BCME_NOTAP;
23565
+ }
23566
+
23567
+ ndev = wl_get_ap_netdev(cfg, ifname);
23568
+
23569
+ if (ndev == NULL) {
23570
+ WL_ERR(("No softAP interface named %s\n", ifname));
23571
+ return BCME_NOTAP;
23572
+ }
23573
+
23574
+ bzero(&rs, sizeof(wl_rateset_args_t));
23575
+ error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
23576
+ &rs, sizeof(wl_rateset_args_t), NULL);
23577
+ if (error < 0) {
23578
+ WL_ERR(("get rateset failed = %d\n", error));
23579
+ return error;
23580
+ }
23581
+
23582
+ if (rs.count < 1) {
23583
+ WL_ERR(("Failed to get rate count\n"));
23584
+ return BCME_ERROR;
23585
+ }
23586
+
23587
+ /* Host delivers target rate in the unit of 500kbps */
23588
+ /* To make it to 1mbps unit, atof should be implemented for 5.5mbps basic rate */
23589
+ for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
23590
+ if (rs.rates[i] & WLC_RATE_FLAG)
23591
+ if ((rs.rates[i] & RATE_MASK) == val)
23592
+ break;
23593
+
23594
+ /* Valid rate has been delivered as an argument */
23595
+ if (i < rs.count && i < WL_NUMRATES) {
23596
+ error = wldev_iovar_setint(ndev, "force_bcn_rspec", val);
23597
+ if (error < 0) {
23598
+ WL_ERR(("set beacon rate failed = %d\n", error));
23599
+ return BCME_ERROR;
23600
+ }
23601
+ } else {
23602
+ WL_ERR(("Rate is invalid"));
23603
+ return BCME_BADARG;
23604
+ }
23605
+
23606
+ return BCME_OK;
23607
+}
23608
+
23609
+int
23610
+wl_get_ap_basic_rate(struct net_device *dev, char* command, char *ifname, int total_len)
23611
+{
23612
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23613
+ dhd_pub_t *dhdp;
23614
+ wl_rateset_args_t rs;
23615
+ int error = BCME_ERROR;
23616
+ int i, bytes_written = 0;
23617
+ struct net_device *ndev = NULL;
23618
+
23619
+ dhdp = (dhd_pub_t *)(cfg->pub);
23620
+
23621
+ if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23622
+ WL_ERR(("Not Hostapd mode\n"));
23623
+ return BCME_NOTAP;
23624
+ }
23625
+
23626
+ ndev = wl_get_ap_netdev(cfg, ifname);
23627
+
23628
+ if (ndev == NULL) {
23629
+ WL_ERR(("No softAP interface named %s\n", ifname));
23630
+ return BCME_NOTAP;
23631
+ }
23632
+
23633
+ bzero(&rs, sizeof(wl_rateset_args_t));
23634
+ error = wldev_iovar_getbuf(ndev, "rateset", NULL, 0,
23635
+ &rs, sizeof(wl_rateset_args_t), NULL);
23636
+ if (error < 0) {
23637
+ WL_ERR(("get rateset failed = %d\n", error));
23638
+ return error;
23639
+ }
23640
+
23641
+ if (rs.count < 1) {
23642
+ WL_ERR(("Failed to get rate count\n"));
23643
+ return BCME_ERROR;
23644
+ }
23645
+
23646
+ /* Delivers basic rate in the unit of 500kbps to host */
23647
+ for (i = 0; i < rs.count && i < WL_NUMRATES; i++)
23648
+ if (rs.rates[i] & WLC_RATE_FLAG)
23649
+ bytes_written += snprintf(command + bytes_written, total_len,
23650
+ "%d ", rs.rates[i] & RATE_MASK);
23651
+
23652
+ /* Remove last space in the command buffer */
23653
+ if (bytes_written && (bytes_written < total_len)) {
23654
+ command[bytes_written - 1] = '\0';
23655
+ bytes_written--;
23656
+ }
23657
+
23658
+ return bytes_written;
23659
+
23660
+}
23661
+#endif /* SUPPORT_AP_HIGHER_BEACONRATE */
23662
+
23663
+#ifdef SUPPORT_AP_RADIO_PWRSAVE
23664
+#define MSEC_PER_MIN (60000L)
23665
+
23666
+static int
23667
+_wl_update_ap_rps_params(struct net_device *dev)
23668
+{
23669
+ struct bcm_cfg80211 *cfg = NULL;
23670
+ rpsnoa_iovar_params_t iovar;
23671
+ u8 smbuf[WLC_IOCTL_SMLEN];
23672
+
23673
+ if (!dev)
23674
+ return BCME_BADARG;
23675
+
23676
+ cfg = wl_get_cfg(dev);
23677
+
23678
+ bzero(&iovar, sizeof(iovar));
23679
+ bzero(smbuf, sizeof(smbuf));
23680
+
23681
+ iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
23682
+ iovar.hdr.subcmd = WL_RPSNOA_CMD_PARAMS;
23683
+ iovar.hdr.len = sizeof(iovar);
23684
+ iovar.param->band = WLC_BAND_ALL;
23685
+ iovar.param->level = cfg->ap_rps_info.level;
23686
+ iovar.param->stas_assoc_check = cfg->ap_rps_info.sta_assoc_check;
23687
+ iovar.param->pps = cfg->ap_rps_info.pps;
23688
+ iovar.param->quiet_time = cfg->ap_rps_info.quiet_time;
23689
+
23690
+ if (wldev_iovar_setbuf(dev, "rpsnoa", &iovar, sizeof(iovar),
23691
+ smbuf, sizeof(smbuf), NULL)) {
23692
+ WL_ERR(("Failed to set rpsnoa params"));
23693
+ return BCME_ERROR;
23694
+ }
23695
+
23696
+ return BCME_OK;
23697
+}
23698
+
23699
+int
23700
+wl_get_ap_rps(struct net_device *dev, char* command, char *ifname, int total_len)
23701
+{
23702
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23703
+ dhd_pub_t *dhdp;
23704
+ int error = BCME_ERROR;
23705
+ int bytes_written = 0;
23706
+ struct net_device *ndev = NULL;
23707
+ rpsnoa_iovar_status_t iovar;
23708
+ u8 smbuf[WLC_IOCTL_SMLEN];
23709
+ u32 chanspec = 0;
23710
+ u8 idx = 0;
23711
+ u16 state;
23712
+ u32 sleep;
23713
+ u32 time_since_enable;
23714
+
23715
+ dhdp = (dhd_pub_t *)(cfg->pub);
23716
+
23717
+ if (!dhdp) {
23718
+ error = BCME_NOTUP;
23719
+ goto fail;
23720
+ }
23721
+
23722
+ if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23723
+ WL_ERR(("Not Hostapd mode\n"));
23724
+ error = BCME_NOTAP;
23725
+ goto fail;
23726
+ }
23727
+
23728
+ ndev = wl_get_ap_netdev(cfg, ifname);
23729
+
23730
+ if (ndev == NULL) {
23731
+ WL_ERR(("No softAP interface named %s\n", ifname));
23732
+ error = BCME_NOTAP;
23733
+ goto fail;
23734
+ }
23735
+
23736
+ bzero(&iovar, sizeof(iovar));
23737
+ bzero(smbuf, sizeof(smbuf));
23738
+
23739
+ iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
23740
+ iovar.hdr.subcmd = WL_RPSNOA_CMD_STATUS;
23741
+ iovar.hdr.len = sizeof(iovar);
23742
+ iovar.stats->band = WLC_BAND_ALL;
23743
+
23744
+ error = wldev_iovar_getbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
23745
+ smbuf, sizeof(smbuf), NULL);
23746
+ if (error < 0) {
23747
+ WL_ERR(("get ap radio pwrsave failed = %d\n", error));
23748
+ goto fail;
23749
+ }
23750
+
23751
+ /* RSDB event doesn't seem to be handled correctly.
23752
+ * So check chanspec of AP directly from the firmware
23753
+ */
23754
+ error = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
23755
+ if (error < 0) {
23756
+ WL_ERR(("get chanspec from AP failed = %d\n", error));
23757
+ goto fail;
23758
+ }
23759
+
23760
+ chanspec = wl_chspec_driver_to_host(chanspec);
23761
+ if (CHSPEC_IS2G(chanspec))
23762
+ idx = 0;
23763
+ else if (CHSPEC_IS5G(chanspec))
23764
+ idx = 1;
23765
+ else {
23766
+ error = BCME_BADCHAN;
23767
+ goto fail;
23768
+ }
23769
+
23770
+ state = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].state;
23771
+ sleep = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_dur;
23772
+ time_since_enable = ((rpsnoa_iovar_status_t *)smbuf)->stats[idx].sleep_avail_dur;
23773
+
23774
+ /* Conver ms to minute, round down only */
23775
+ sleep = DIV_U64_BY_U32(sleep, MSEC_PER_MIN);
23776
+ time_since_enable = DIV_U64_BY_U32(time_since_enable, MSEC_PER_MIN);
23777
+
23778
+ bytes_written += snprintf(command + bytes_written, total_len,
23779
+ "state=%d sleep=%d time_since_enable=%d", state, sleep, time_since_enable);
23780
+ error = bytes_written;
23781
+
23782
+fail:
23783
+ return error;
23784
+}
23785
+
23786
+int
23787
+wl_set_ap_rps(struct net_device *dev, bool enable, char *ifname)
23788
+{
23789
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23790
+ dhd_pub_t *dhdp;
23791
+ struct net_device *ndev = NULL;
23792
+ rpsnoa_iovar_t iovar;
23793
+ u8 smbuf[WLC_IOCTL_SMLEN];
23794
+ int ret = BCME_OK;
23795
+
23796
+ dhdp = (dhd_pub_t *)(cfg->pub);
23797
+
23798
+ if (!dhdp) {
23799
+ ret = BCME_NOTUP;
23800
+ goto exit;
23801
+ }
23802
+
23803
+ if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23804
+ WL_ERR(("Not Hostapd mode\n"));
23805
+ ret = BCME_NOTAP;
23806
+ goto exit;
23807
+ }
23808
+
23809
+ ndev = wl_get_ap_netdev(cfg, ifname);
23810
+
23811
+ if (ndev == NULL) {
23812
+ WL_ERR(("No softAP interface named %s\n", ifname));
23813
+ ret = BCME_NOTAP;
23814
+ goto exit;
23815
+ }
23816
+
23817
+ if (cfg->ap_rps_info.enable != enable) {
23818
+ cfg->ap_rps_info.enable = enable;
23819
+ if (enable) {
23820
+ ret = _wl_update_ap_rps_params(ndev);
23821
+ if (ret) {
23822
+ WL_ERR(("Filed to update rpsnoa params\n"));
23823
+ goto exit;
23824
+ }
23825
+ }
23826
+ bzero(&iovar, sizeof(iovar));
23827
+ bzero(smbuf, sizeof(smbuf));
23828
+
23829
+ iovar.hdr.ver = RADIO_PWRSAVE_VERSION;
23830
+ iovar.hdr.subcmd = WL_RPSNOA_CMD_ENABLE;
23831
+ iovar.hdr.len = sizeof(iovar);
23832
+ iovar.data->band = WLC_BAND_ALL;
23833
+ iovar.data->value = (int16)enable;
23834
+
23835
+ ret = wldev_iovar_setbuf(ndev, "rpsnoa", &iovar, sizeof(iovar),
23836
+ smbuf, sizeof(smbuf), NULL);
23837
+ if (ret) {
23838
+ WL_ERR(("Failed to enable AP radio power save"));
23839
+ goto exit;
23840
+ }
23841
+ cfg->ap_rps_info.enable = enable;
23842
+ }
23843
+exit:
23844
+ return ret;
23845
+}
23846
+
23847
+int
23848
+wl_update_ap_rps_params(struct net_device *dev, ap_rps_info_t* rps, char *ifname)
23849
+{
23850
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23851
+ dhd_pub_t *dhdp;
23852
+ struct net_device *ndev = NULL;
23853
+
23854
+ dhdp = (dhd_pub_t *)(cfg->pub);
23855
+
23856
+ if (!dhdp)
23857
+ return BCME_NOTUP;
23858
+
23859
+ if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
23860
+ WL_ERR(("Not Hostapd mode\n"));
23861
+ return BCME_NOTAP;
23862
+ }
23863
+
23864
+ ndev = wl_get_ap_netdev(cfg, ifname);
23865
+
23866
+ if (ndev == NULL) {
23867
+ WL_ERR(("No softAP interface named %s\n", ifname));
23868
+ return BCME_NOTAP;
23869
+ }
23870
+
23871
+ if (!rps)
23872
+ return BCME_BADARG;
23873
+
23874
+ if (rps->pps < RADIO_PWRSAVE_PPS_MIN)
23875
+ return BCME_BADARG;
23876
+
23877
+ if (rps->level < RADIO_PWRSAVE_LEVEL_MIN ||
23878
+ rps->level > RADIO_PWRSAVE_LEVEL_MAX)
23879
+ return BCME_BADARG;
23880
+
23881
+ if (rps->quiet_time < RADIO_PWRSAVE_QUIETTIME_MIN)
23882
+ return BCME_BADARG;
23883
+
23884
+ if (rps->sta_assoc_check > RADIO_PWRSAVE_ASSOCCHECK_MAX ||
23885
+ rps->sta_assoc_check < RADIO_PWRSAVE_ASSOCCHECK_MIN)
23886
+ return BCME_BADARG;
23887
+
23888
+ cfg->ap_rps_info.pps = rps->pps;
23889
+ cfg->ap_rps_info.level = rps->level;
23890
+ cfg->ap_rps_info.quiet_time = rps->quiet_time;
23891
+ cfg->ap_rps_info.sta_assoc_check = rps->sta_assoc_check;
23892
+
23893
+ if (cfg->ap_rps_info.enable) {
23894
+ if (_wl_update_ap_rps_params(ndev)) {
23895
+ WL_ERR(("Failed to update rpsnoa params"));
23896
+ return BCME_ERROR;
23897
+ }
23898
+ }
23899
+
23900
+ return BCME_OK;
23901
+}
23902
+
23903
+void
23904
+wl_cfg80211_init_ap_rps(struct bcm_cfg80211 *cfg)
23905
+{
23906
+ cfg->ap_rps_info.enable = FALSE;
23907
+ cfg->ap_rps_info.sta_assoc_check = RADIO_PWRSAVE_STAS_ASSOC_CHECK;
23908
+ cfg->ap_rps_info.pps = RADIO_PWRSAVE_PPS;
23909
+ cfg->ap_rps_info.quiet_time = RADIO_PWRSAVE_QUIET_TIME;
23910
+ cfg->ap_rps_info.level = RADIO_PWRSAVE_LEVEL;
23911
+}
23912
+#endif /* SUPPORT_AP_RADIO_PWRSAVE */
23913
+
23914
+int
23915
+wl_cfg80211_iface_count(struct net_device *dev)
23916
+{
23917
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
23918
+ struct net_info *iter, *next;
23919
+ int iface_count = 0;
23920
+
23921
+ /* Return the count of network interfaces (skip netless p2p discovery
23922
+ * interface)
23923
+ */
23924
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23925
+ for_each_ndev(cfg, iter, next) {
23926
+ GCC_DIAGNOSTIC_POP();
23927
+ if (iter->ndev) {
23928
+ iface_count++;
23929
+ }
23930
+ }
23931
+ return iface_count;
23932
+}
23933
+
23934
+#ifdef WBTEXT
23935
+static bool wl_cfg80211_wbtext_check_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
23936
+{
23937
+ wl_wbtext_bssid_t *bssid = NULL;
23938
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23939
+ /* check duplicate */
23940
+ list_for_each_entry(bssid, &cfg->wbtext_bssid_list, list) {
23941
+ GCC_DIAGNOSTIC_POP();
23942
+ if (!memcmp(bssid->ea.octet, ea, ETHER_ADDR_LEN)) {
23943
+ return FALSE;
23944
+ }
23945
+ }
23946
+
23947
+ return TRUE;
23948
+}
23949
+
23950
+static bool wl_cfg80211_wbtext_add_bssid_list(struct bcm_cfg80211 *cfg, struct ether_addr *ea)
23951
+{
23952
+ wl_wbtext_bssid_t *bssid = NULL;
23953
+ char eabuf[ETHER_ADDR_STR_LEN];
23954
+
23955
+ bssid = (wl_wbtext_bssid_t *)MALLOC(cfg->osh, sizeof(wl_wbtext_bssid_t));
23956
+ if (bssid == NULL) {
23957
+ WL_ERR(("alloc failed\n"));
23958
+ return FALSE;
23959
+ }
23960
+
23961
+ memcpy(bssid->ea.octet, ea, ETHER_ADDR_LEN);
23962
+
23963
+ INIT_LIST_HEAD(&bssid->list);
23964
+ list_add_tail(&bssid->list, &cfg->wbtext_bssid_list);
23965
+
23966
+ WL_DBG(("add wbtext bssid : %s\n", bcm_ether_ntoa(ea, eabuf)));
23967
+
23968
+ return TRUE;
23969
+}
23970
+
23971
+static void wl_cfg80211_wbtext_clear_bssid_list(struct bcm_cfg80211 *cfg)
23972
+{
23973
+ wl_wbtext_bssid_t *bssid = NULL;
23974
+ char eabuf[ETHER_ADDR_STR_LEN];
23975
+
23976
+ while (!list_empty(&cfg->wbtext_bssid_list)) {
23977
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
23978
+ bssid = list_entry(cfg->wbtext_bssid_list.next, wl_wbtext_bssid_t, list);
23979
+ GCC_DIAGNOSTIC_POP();
23980
+ if (bssid) {
23981
+ WL_DBG(("clear wbtext bssid : %s\n", bcm_ether_ntoa(&bssid->ea, eabuf)));
23982
+ list_del(&bssid->list);
23983
+ MFREE(cfg->osh, bssid, sizeof(wl_wbtext_bssid_t));
23984
+ }
23985
+ }
23986
+}
23987
+
23988
+static void wl_cfg80211_wbtext_update_rcc(struct bcm_cfg80211 *cfg, struct net_device *dev)
23989
+{
23990
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
23991
+ bcm_tlv_t * cap_ie = NULL;
23992
+ bool req_sent = FALSE;
23993
+ struct wl_profile *profile;
23994
+
23995
+ WL_DBG(("Enter\n"));
23996
+
23997
+ profile = wl_get_profile_by_netdev(cfg, dev);
23998
+ if (!profile) {
23999
+ WL_ERR(("no profile exists\n"));
24000
+ return;
24001
+ }
24002
+
24003
+ if (wl_cfg80211_wbtext_check_bssid_list(cfg,
24004
+ (struct ether_addr *)&profile->bssid) == FALSE) {
24005
+ WL_DBG(("already updated\n"));
24006
+ return;
24007
+ }
24008
+
24009
+ /* first, check NBR bit in RRM IE */
24010
+ if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24011
+ DOT11_MNG_RRM_CAP_ID)) != NULL) {
24012
+ if (isset(cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
24013
+ WL_DBG(("sending neighbor report\n"));
24014
+ req_sent = wl_cfg80211_wbtext_send_nbr_req(cfg, dev, profile);
24015
+ }
24016
+ }
24017
+
24018
+ /* if RRM nbr was not supported, check BTM bit in extend cap. IE */
24019
+ if (!req_sent) {
24020
+ if ((cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24021
+ DOT11_MNG_EXT_CAP_ID)) != NULL) {
24022
+ if (cap_ie->len >= DOT11_EXTCAP_LEN_BSSTRANS &&
24023
+ isset(cap_ie->data, DOT11_EXT_CAP_BSSTRANS_MGMT)) {
24024
+ WL_DBG(("sending btm query\n"));
24025
+ wl_cfg80211_wbtext_send_btm_query(cfg, dev, profile);
24026
+ }
24027
+ }
24028
+ }
24029
+}
24030
+
24031
+static bool wl_cfg80211_wbtext_send_nbr_req(struct bcm_cfg80211 *cfg, struct net_device *dev,
24032
+ struct wl_profile *profile)
24033
+{
24034
+ int error = -1;
24035
+ char *smbuf = NULL;
24036
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
24037
+ bcm_tlv_t * rrm_cap_ie = NULL;
24038
+ wlc_ssid_t *ssid = NULL;
24039
+ bool ret = FALSE;
24040
+
24041
+ WL_DBG(("Enter\n"));
24042
+
24043
+ /* check RRM nbr bit in extend cap. IE of assoc response */
24044
+ if ((rrm_cap_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24045
+ DOT11_MNG_RRM_CAP_ID)) != NULL) {
24046
+ if (!isset(rrm_cap_ie->data, DOT11_RRM_CAP_NEIGHBOR_REPORT)) {
24047
+ WL_DBG(("AP doesn't support neighbor report\n"));
24048
+ return FALSE;
24049
+ }
24050
+ }
24051
+
24052
+ smbuf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
24053
+ if (smbuf == NULL) {
24054
+ WL_ERR(("failed to allocated memory\n"));
24055
+ goto nbr_req_out;
24056
+ }
24057
+
24058
+ ssid = (wlc_ssid_t *)MALLOCZ(cfg->osh, sizeof(wlc_ssid_t));
24059
+ if (ssid == NULL) {
24060
+ WL_ERR(("failed to allocated memory\n"));
24061
+ goto nbr_req_out;
24062
+ }
24063
+
24064
+ ssid->SSID_len = MIN(profile->ssid.SSID_len, DOT11_MAX_SSID_LEN);
24065
+ memcpy(ssid->SSID, profile->ssid.SSID, ssid->SSID_len);
24066
+
24067
+ error = wldev_iovar_setbuf(dev, "rrm_nbr_req", ssid,
24068
+ sizeof(wlc_ssid_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
24069
+ if (error == BCME_OK) {
24070
+ ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
24071
+ (struct ether_addr *)&profile->bssid);
24072
+ } else {
24073
+ WL_ERR(("failed to send neighbor report request, error=%d\n", error));
24074
+ }
24075
+
24076
+nbr_req_out:
24077
+ if (ssid) {
24078
+ MFREE(cfg->osh, ssid, sizeof(wlc_ssid_t));
24079
+ }
24080
+
24081
+ if (smbuf) {
24082
+ MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
24083
+ }
24084
+ return ret;
24085
+}
24086
+
24087
+static bool wl_cfg80211_wbtext_send_btm_query(struct bcm_cfg80211 *cfg, struct net_device *dev,
24088
+ struct wl_profile *profile)
24089
+
24090
+{
24091
+ int error = -1;
24092
+ bool ret = FALSE;
24093
+ wl_bsstrans_query_t btq;
24094
+
24095
+ WL_DBG(("Enter\n"));
24096
+
24097
+ bzero(&btq, sizeof(wl_bsstrans_query_t));
24098
+
24099
+ btq.version = WL_BSSTRANS_QUERY_VERSION_1;
24100
+ error = wldev_iovar_setbuf(dev, "wnm_bsstrans_query", &btq,
24101
+ sizeof(btq), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
24102
+ if (error == BCME_OK) {
24103
+ ret = wl_cfg80211_wbtext_add_bssid_list(cfg,
24104
+ (struct ether_addr *)&profile->bssid);
24105
+ } else {
24106
+ WL_ERR(("wl_cfg80211_wbtext_send_btm_query: failed to set BTM query,"
24107
+ " error=%d\n", error));
24108
+ }
24109
+ return ret;
24110
+}
24111
+
24112
+static void wl_cfg80211_wbtext_set_wnm_maxidle(struct bcm_cfg80211 *cfg, struct net_device *dev)
24113
+{
24114
+ keepalives_max_idle_t keepalive = {0, 0, 0, 0};
24115
+ s32 bssidx, error;
24116
+ int wnm_maxidle = 0;
24117
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
24118
+
24119
+ /* AP supports wnm max idle ? */
24120
+ if (bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
24121
+ DOT11_MNG_BSS_MAX_IDLE_PERIOD_ID) != NULL) {
24122
+ error = wldev_iovar_getint(dev, "wnm_maxidle", &wnm_maxidle);
24123
+ if (error < 0) {
24124
+ WL_ERR(("failed to get wnm max idle period : %d\n", error));
24125
+ }
24126
+ }
24127
+
24128
+ WL_DBG(("wnm max idle period : %d\n", wnm_maxidle));
24129
+
24130
+ /* if wnm maxidle has valid period, set it as keep alive */
24131
+ if (wnm_maxidle > 0) {
24132
+ keepalive.keepalive_count = 1;
24133
+ }
24134
+
24135
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) >= 0) {
24136
+ error = wldev_iovar_setbuf_bsscfg(dev, "wnm_keepalives_max_idle", &keepalive,
24137
+ sizeof(keepalives_max_idle_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
24138
+ bssidx, &cfg->ioctl_buf_sync);
24139
+ if (error < 0) {
24140
+ WL_ERR(("set wnm_keepalives_max_idle failed : %d\n", error));
24141
+ }
24142
+ }
24143
+}
24144
+
24145
+static int
24146
+wl_cfg80211_recv_nbr_resp(struct net_device *dev, uint8 *body, uint body_len)
24147
+{
24148
+ dot11_rm_action_t *rm_rep;
24149
+ bcm_tlv_t *tlvs;
24150
+ uint tlv_len;
24151
+ int i, error;
24152
+ dot11_neighbor_rep_ie_t *nbr_rep_ie;
24153
+ chanspec_t ch;
24154
+ wl_roam_channel_list_t channel_list;
24155
+ char iobuf[WLC_IOCTL_SMLEN];
24156
+
24157
+ if (body_len < DOT11_RM_ACTION_LEN) {
24158
+ WL_ERR(("Received Neighbor Report frame with incorrect length %d\n",
24159
+ body_len));
24160
+ return BCME_ERROR;
24161
+ }
24162
+
24163
+ rm_rep = (dot11_rm_action_t *)body;
24164
+ WL_DBG(("received neighbor report (token = %d)\n", rm_rep->token));
24165
+
24166
+ tlvs = (bcm_tlv_t *)&rm_rep->data[0];
24167
+
24168
+ tlv_len = body_len - DOT11_RM_ACTION_LEN;
24169
+
24170
+ while (tlvs && tlvs->id == DOT11_MNG_NEIGHBOR_REP_ID) {
24171
+ nbr_rep_ie = (dot11_neighbor_rep_ie_t *)tlvs;
24172
+
24173
+ if (nbr_rep_ie->len < DOT11_NEIGHBOR_REP_IE_FIXED_LEN) {
24174
+ WL_ERR(("malformed Neighbor Report element with length %d\n",
24175
+ nbr_rep_ie->len));
24176
+ tlvs = bcm_next_tlv(tlvs, &tlv_len);
24177
+ continue;
24178
+ }
24179
+
24180
+ ch = CH20MHZ_CHSPEC(nbr_rep_ie->channel);
24181
+ WL_DBG(("ch:%d, bssid:"MACDBG"\n",
24182
+ ch, MAC2STRDBG(nbr_rep_ie->bssid.octet)));
24183
+
24184
+ /* get RCC list */
24185
+ error = wldev_iovar_getbuf(dev, "roamscan_channels", 0, 0,
24186
+ (void *)&channel_list, sizeof(channel_list), NULL);
24187
+ if (error) {
24188
+ WL_ERR(("Failed to get roamscan channels, error = %d\n", error));
24189
+ return BCME_ERROR;
24190
+ }
24191
+
24192
+ /* update RCC */
24193
+ if (channel_list.n < MAX_ROAM_CHANNEL) {
24194
+ for (i = 0; i < channel_list.n; i++) {
24195
+ if (channel_list.channels[i] == ch) {
24196
+ break;
24197
+ }
24198
+ }
24199
+ if (i == channel_list.n) {
24200
+ channel_list.channels[channel_list.n] = ch;
24201
+ channel_list.n++;
24202
+ }
24203
+ }
24204
+
24205
+ /* set RCC list */
24206
+ error = wldev_iovar_setbuf(dev, "roamscan_channels", &channel_list,
24207
+ sizeof(channel_list), iobuf, sizeof(iobuf), NULL);
24208
+ if (error) {
24209
+ WL_DBG(("Failed to set roamscan channels, error = %d\n", error));
24210
+ }
24211
+
24212
+ tlvs = bcm_next_tlv(tlvs, &tlv_len);
24213
+ }
24214
+
24215
+ return BCME_OK;
24216
+}
24217
+#endif /* WBTEXT */
24218
+#ifdef SUPPORT_SET_CAC
24219
+static void
24220
+wl_cfg80211_set_cac(struct bcm_cfg80211 *cfg, int enable)
24221
+{
24222
+ int ret = 0;
24223
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
24224
+
24225
+ WL_DBG(("cac enable %d\n", enable));
24226
+ if (!dhd) {
24227
+ WL_ERR(("dhd is NULL\n"));
24228
+ return;
24229
+ }
24230
+ if ((ret = dhd_wl_ioctl_set_intiovar(dhd, "cac", enable,
24231
+ WLC_SET_VAR, TRUE, 0)) < 0) {
24232
+ WL_ERR(("Failed set CAC, ret=%d\n", ret));
24233
+ } else {
24234
+ WL_DBG(("CAC set successfully\n"));
24235
+ }
24236
+ return;
24237
+}
24238
+#endif /* SUPPORT_SET_CAC */
24239
+
24240
+#ifdef SUPPORT_RSSI_SUM_REPORT
24241
+int
24242
+wl_get_rssi_per_ant(struct net_device *dev, char *ifname, char *peer_mac, void *param)
24243
+{
24244
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24245
+ wl_rssi_ant_mimo_t *get_param = (wl_rssi_ant_mimo_t *)param;
24246
+ rssi_ant_param_t *set_param = NULL;
24247
+ struct net_device *ifdev = NULL;
24248
+ char iobuf[WLC_IOCTL_SMLEN];
24249
+ int err = BCME_OK;
24250
+ int iftype = 0;
24251
+
24252
+ bzero(iobuf, WLC_IOCTL_SMLEN);
24253
+
24254
+ /* Check the interface type */
24255
+ ifdev = wl_get_netdev_by_name(cfg, ifname);
24256
+ if (ifdev == NULL) {
24257
+ WL_ERR(("Could not find net_device for ifname:%s\n", ifname));
24258
+ err = BCME_BADARG;
24259
+ goto fail;
24260
+ }
24261
+
24262
+ iftype = ifdev->ieee80211_ptr->iftype;
24263
+ if (iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO) {
24264
+ if (peer_mac) {
24265
+ set_param = (rssi_ant_param_t *)MALLOCZ(cfg->osh, sizeof(rssi_ant_param_t));
24266
+ err = wl_cfg80211_ether_atoe(peer_mac, &set_param->ea);
24267
+ if (!err) {
24268
+ WL_ERR(("Invalid Peer MAC format\n"));
24269
+ err = BCME_BADARG;
24270
+ goto fail;
24271
+ }
24272
+ } else {
24273
+ WL_ERR(("Peer MAC is not provided for iftype %d\n", iftype));
24274
+ err = BCME_BADARG;
24275
+ goto fail;
24276
+ }
24277
+ }
24278
+
24279
+ err = wldev_iovar_getbuf(ifdev, "phy_rssi_ant", peer_mac ?
24280
+ (void *)&(set_param->ea) : NULL, peer_mac ? ETHER_ADDR_LEN : 0,
24281
+ (void *)iobuf, sizeof(iobuf), NULL);
24282
+ if (unlikely(err)) {
24283
+ WL_ERR(("Failed to get rssi info, err=%d\n", err));
24284
+ } else {
24285
+ memcpy(get_param, iobuf, sizeof(wl_rssi_ant_mimo_t));
24286
+ if (get_param->count == 0) {
24287
+ WL_ERR(("Not supported on this chip\n"));
24288
+ err = BCME_UNSUPPORTED;
24289
+ }
24290
+ }
24291
+
24292
+fail:
24293
+ if (set_param) {
24294
+ MFREE(cfg->osh, set_param, sizeof(rssi_ant_param_t));
24295
+ }
24296
+
24297
+ return err;
24298
+}
24299
+
24300
+int
24301
+wl_get_rssi_logging(struct net_device *dev, void *param)
24302
+{
24303
+ rssilog_get_param_t *get_param = (rssilog_get_param_t *)param;
24304
+ char iobuf[WLC_IOCTL_SMLEN];
24305
+ int err = BCME_OK;
24306
+
24307
+ bzero(iobuf, WLC_IOCTL_SMLEN);
24308
+ bzero(get_param, sizeof(*get_param));
24309
+ err = wldev_iovar_getbuf(dev, "rssilog", NULL, 0, (void *)iobuf,
24310
+ sizeof(iobuf), NULL);
24311
+ if (err) {
24312
+ WL_ERR(("Failed to get rssi logging info, err=%d\n", err));
24313
+ } else {
24314
+ memcpy(get_param, iobuf, sizeof(*get_param));
24315
+ }
24316
+
24317
+ return err;
24318
+}
24319
+
24320
+int
24321
+wl_set_rssi_logging(struct net_device *dev, void *param)
24322
+{
24323
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24324
+ rssilog_set_param_t *set_param = (rssilog_set_param_t *)param;
24325
+ int err;
24326
+
24327
+ err = wldev_iovar_setbuf(dev, "rssilog", set_param,
24328
+ sizeof(*set_param), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
24329
+ &cfg->ioctl_buf_sync);
24330
+ if (err) {
24331
+ WL_ERR(("Failed to set rssi logging param, err=%d\n", err));
24332
+ }
24333
+
24334
+ return err;
24335
+}
24336
+#endif /* SUPPORT_RSSI_SUM_REPORT */
24337
+/* Function to flush the FW preserve buffer content
24338
+* The buffer content is sent to host in form of events.
24339
+*/
24340
+void
24341
+wl_flush_fw_log_buffer(struct net_device *dev, uint32 logset_mask)
24342
+{
24343
+ struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
24344
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
24345
+ int i;
24346
+ int err = 0;
24347
+ u8 buf[WLC_IOCTL_SMLEN] = {0};
24348
+ wl_el_set_params_t set_param;
24349
+
24350
+ /* Set the size of data to retrieve */
24351
+ memset(&set_param, 0, sizeof(set_param));
24352
+ set_param.size = WLC_IOCTL_SMLEN;
24353
+
24354
+ for (i = 0; i < dhd->event_log_max_sets; i++)
24355
+ {
24356
+ if ((0x01u << i) & logset_mask) {
24357
+ set_param.set = i;
24358
+ err = wldev_iovar_setbuf(dev, "event_log_get", &set_param,
24359
+ sizeof(struct wl_el_set_params_s), buf, WLC_IOCTL_SMLEN,
24360
+ NULL);
24361
+ if (err) {
24362
+ WL_DBG(("Failed to get fw preserve logs, err=%d\n", err));
24363
+ }
24364
+ }
24365
+ }
24366
+}
24367
+#ifdef USE_WFA_CERT_CONF
24368
+extern int g_frameburst;
24369
+#endif /* USE_WFA_CERT_CONF */
24370
+
24371
+int
24372
+wl_cfg80211_set_frameburst(struct bcm_cfg80211 *cfg, bool enable)
24373
+{
24374
+ int ret = BCME_OK;
24375
+ int val = enable ? 1 : 0;
24376
+
24377
+#ifdef USE_WFA_CERT_CONF
24378
+ if (!g_frameburst) {
24379
+ WL_DBG(("Skip setting frameburst\n"));
24380
+ return 0;
24381
+ }
24382
+#endif /* USE_WFA_CERT_CONF */
24383
+
24384
+ WL_DBG(("Set frameburst %d\n", val));
24385
+ ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg), WLC_SET_FAKEFRAG, &val, sizeof(val));
24386
+ if (ret < 0) {
24387
+ WL_ERR(("Failed set frameburst, ret=%d\n", ret));
24388
+ } else {
24389
+ WL_INFORM_MEM(("frameburst is %s\n", enable ? "enabled" : "disabled"));
24390
+ }
24391
+
24392
+ return ret;
24393
+}
24394
+
24395
+s32
24396
+wl_cfg80211_set_transition_mode(struct net_device *ndev, u32 transition_disabled)
24397
+{
24398
+ int ret = BCME_OK;
24399
+ int val = transition_disabled ? 0 : 1;
24400
+
24401
+ WL_DBG(("Set SAE transition mode %d\n", val));
24402
+ ret = wldev_iovar_setint(ndev, "extsae_transition_mode", val);
24403
+ if (ret < 0) {
24404
+ WL_ERR(("Failed set SAE transition mode, ret=%d\n", ret));
24405
+ } else {
24406
+ WL_INFORM(("SAE transition mode is %s\n",
24407
+ transition_disabled ? "disabled" : "enabled"));
24408
+ }
24409
+
24410
+ return ret;
24411
+}
24412
+
24413
+s32
24414
+wl_cfg80211_set_sae_pwe(struct net_device *ndev, u8 sae_pwe)
24415
+{
24416
+ int ret = BCME_UNSUPPORTED;
24417
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24418
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
24419
+
24420
+ /* sae_pwe 0: HnP, 1: H2E, 2: Both HnP and H2E */
24421
+ WL_DBG(("Set SAE PWE derivation machanisme %d\n", sae_pwe));
24422
+
24423
+ if (FW_SUPPORTED(dhd, sae_ext))
24424
+ ret = wldev_iovar_setint(ndev, "extsae_pwe", sae_pwe);
24425
+
24426
+ if (ret < 0)
24427
+ WL_ERR(("Failed set SAE PWE, ret=%d\n", ret));
24428
+
24429
+ return ret;
24430
+}
24431
+
24432
+s32
24433
+wl_cfg80211_set_dbg_verbose(struct net_device *ndev, u32 level)
24434
+{
24435
+ /* configure verbose level for debugging */
24436
+ if (level) {
24437
+ /* Enable increased verbose */
24438
+ wl_dbg_level |= WL_DBG_DBG;
24439
+ } else {
24440
+ /* Disable */
24441
+ wl_dbg_level &= ~WL_DBG_DBG;
24442
+ }
24443
+ WL_INFORM(("debug verbose set to %d\n", level));
24444
+
24445
+ return BCME_OK;
24446
+}
24447
+
24448
+const u8 *
24449
+wl_find_attribute(const u8 *buf, u16 len, u16 element_id)
24450
+{
24451
+ const u8 *attrib;
24452
+ u16 attrib_id;
24453
+ u16 attrib_len;
24454
+
24455
+ if (!buf) {
24456
+ WL_ERR(("buf null\n"));
24457
+ return NULL;
24458
+ }
24459
+
24460
+ attrib = buf;
24461
+ while (len >= 4) {
24462
+ /* attribute id */
24463
+ attrib_id = *attrib++ << 8;
24464
+ attrib_id |= *attrib++;
24465
+ len -= 2;
24466
+
24467
+ /* 2-byte little endian */
24468
+ attrib_len = *attrib++ << 8;
24469
+ attrib_len |= *attrib++;
24470
+
24471
+ len -= 2;
24472
+ if (attrib_id == element_id) {
24473
+ /* This will point to start of subelement attrib after
24474
+ * attribute id & len
24475
+ */
24476
+ return attrib;
24477
+ }
24478
+ if (len > attrib_len) {
24479
+ len -= attrib_len; /* for the remaining subelt fields */
24480
+ WL_DBG(("Attribue:%4x attrib_len:%d rem_len:%d\n",
24481
+ attrib_id, attrib_len, len));
24482
+
24483
+ /* Go to next subelement */
24484
+ attrib += attrib_len;
24485
+ } else {
24486
+ WL_ERR(("Incorrect Attribue:%4x attrib_len:%d\n",
24487
+ attrib_id, attrib_len));
24488
+ return NULL;
24489
+ }
24490
+ }
24491
+ return NULL;
24492
+}
24493
+
24494
+uint8 wl_cfg80211_get_bus_state(struct bcm_cfg80211 *cfg)
24495
+{
24496
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
24497
+ WL_INFORM(("dhd->hang_was_sent = %d and busstate = %d\n",
24498
+ dhd->hang_was_sent, dhd->busstate));
24499
+ return ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent);
24500
+}
24501
+
24502
+#ifdef WL_WPS_SYNC
24503
+static void wl_wps_reauth_timeout(unsigned long data)
24504
+{
24505
+ struct net_device *ndev = (struct net_device *)data;
24506
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24507
+ s32 inst;
24508
+ unsigned long flags;
24509
+
24510
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24511
+ inst = wl_get_wps_inst_match(cfg, ndev);
24512
+ if (inst >= 0) {
24513
+ WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d! state:%d\n",
24514
+ ndev->name, inst, cfg->wps_session[inst].state));
24515
+ if (cfg->wps_session[inst].state == WPS_STATE_REAUTH_WAIT) {
24516
+ /* Session should get deleted from success (linkup) or
24517
+ * deauth case. Just in case, link reassoc failed, clear
24518
+ * state here.
24519
+ */
24520
+ WL_ERR(("[%s][WPS] Reauth Timeout Inst:%d!\n",
24521
+ ndev->name, inst));
24522
+ cfg->wps_session[inst].state = WPS_STATE_IDLE;
24523
+ cfg->wps_session[inst].in_use = false;
24524
+ }
24525
+ }
24526
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24527
+}
24528
+
24529
+static void wl_init_wps_reauth_sm(struct bcm_cfg80211 *cfg)
24530
+{
24531
+ /* Only two instances are supported as of now. one for
24532
+ * infra STA and other for infra STA/GC.
24533
+ */
24534
+ int i = 0;
24535
+ struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
24536
+
24537
+ spin_lock_init(&cfg->wps_sync);
24538
+ for (i = 0; i < WPS_MAX_SESSIONS; i++) {
24539
+ /* Init scan_timeout timer */
24540
+ init_timer_compat(&cfg->wps_session[i].timer, wl_wps_reauth_timeout, pdev);
24541
+ cfg->wps_session[i].in_use = false;
24542
+ cfg->wps_session[i].state = WPS_STATE_IDLE;
24543
+ }
24544
+}
24545
+
24546
+static void wl_deinit_wps_reauth_sm(struct bcm_cfg80211 *cfg)
24547
+{
24548
+ int i = 0;
24549
+
24550
+ for (i = 0; i < WPS_MAX_SESSIONS; i++) {
24551
+ cfg->wps_session[i].in_use = false;
24552
+ cfg->wps_session[i].state = WPS_STATE_IDLE;
24553
+ if (timer_pending(&cfg->wps_session[i].timer)) {
24554
+ del_timer_sync(&cfg->wps_session[i].timer);
24555
+ }
24556
+ }
24557
+
24558
+}
24559
+
24560
+static s32
24561
+wl_get_free_wps_inst(struct bcm_cfg80211 *cfg)
24562
+{
24563
+ int i;
24564
+
24565
+ for (i = 0; i < WPS_MAX_SESSIONS; i++) {
24566
+ if (!cfg->wps_session[i].in_use) {
24567
+ return i;
24568
+ }
24569
+ }
24570
+ return BCME_ERROR;
24571
+}
24572
+
24573
+static s32
24574
+wl_get_wps_inst_match(struct bcm_cfg80211 *cfg, struct net_device *ndev)
24575
+{
24576
+ int i;
24577
+
24578
+ for (i = 0; i < WPS_MAX_SESSIONS; i++) {
24579
+ if ((cfg->wps_session[i].in_use) &&
24580
+ (ndev == cfg->wps_session[i].ndev)) {
24581
+ return i;
24582
+ }
24583
+ }
24584
+
24585
+ return BCME_ERROR;
24586
+}
24587
+
24588
+static s32
24589
+wl_wps_session_add(struct net_device *ndev, u16 mode, u8 *mac_addr)
24590
+{
24591
+ s32 inst;
24592
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24593
+ unsigned long flags;
24594
+
24595
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24596
+ /* Fetch and initialize a wps instance */
24597
+ inst = wl_get_free_wps_inst(cfg);
24598
+ if (inst == BCME_ERROR) {
24599
+ WL_ERR(("[WPS] No free insance\n"));
24600
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24601
+ return BCME_ERROR;
24602
+ }
24603
+ cfg->wps_session[inst].in_use = true;
24604
+ cfg->wps_session[inst].state = WPS_STATE_STARTED;
24605
+ cfg->wps_session[inst].ndev = ndev;
24606
+ cfg->wps_session[inst].mode = mode;
24607
+ /* return check not required since both buffer lens are same */
24608
+ (void)memcpy_s(cfg->wps_session[inst].peer_mac, ETH_ALEN, mac_addr, ETH_ALEN);
24609
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24610
+
24611
+ WL_INFORM_MEM(("[%s][WPS] session created. Peer: " MACDBG "\n",
24612
+ ndev->name, MAC2STRDBG(mac_addr)));
24613
+ return BCME_OK;
24614
+}
24615
+
24616
+static void
24617
+wl_wps_session_del(struct net_device *ndev)
24618
+{
24619
+ s32 inst;
24620
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24621
+ unsigned long flags;
24622
+ u16 cur_state;
24623
+
24624
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24625
+
24626
+ /* Get current instance for the given ndev */
24627
+ inst = wl_get_wps_inst_match(cfg, ndev);
24628
+ if (inst == BCME_ERROR) {
24629
+ WL_DBG(("[WPS] instance match NOT found\n"));
24630
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24631
+ return;
24632
+ }
24633
+
24634
+ cur_state = cfg->wps_session[inst].state;
24635
+ if (cur_state != WPS_STATE_DONE) {
24636
+ WL_DBG(("[WPS] wrong state:%d\n", cur_state));
24637
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24638
+ return;
24639
+ }
24640
+
24641
+ /* Mark this as unused */
24642
+ cfg->wps_session[inst].in_use = false;
24643
+ cfg->wps_session[inst].state = WPS_STATE_IDLE;
24644
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24645
+
24646
+ /* Ensure this API is called from sleepable context. */
24647
+ if (timer_pending(&cfg->wps_session[inst].timer)) {
24648
+ del_timer_sync(&cfg->wps_session[inst].timer);
24649
+ }
24650
+
24651
+ WL_INFORM_MEM(("[%s][WPS] session deleted\n", ndev->name));
24652
+}
24653
+
24654
+static void
24655
+wl_wps_handle_ifdel(struct net_device *ndev)
24656
+{
24657
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24658
+ unsigned long flags;
24659
+ u16 cur_state;
24660
+ s32 inst;
24661
+
24662
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24663
+ inst = wl_get_wps_inst_match(cfg, ndev);
24664
+ if (inst == BCME_ERROR) {
24665
+ WL_DBG(("[WPS] instance match NOT found\n"));
24666
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24667
+ return;
24668
+ }
24669
+ cur_state = cfg->wps_session[inst].state;
24670
+ cfg->wps_session[inst].state = WPS_STATE_DONE;
24671
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24672
+
24673
+ WL_INFORM_MEM(("[%s][WPS] state:%x\n", ndev->name, cur_state));
24674
+ if (cur_state > WPS_STATE_IDLE) {
24675
+ wl_wps_session_del(ndev);
24676
+ }
24677
+}
24678
+
24679
+static s32
24680
+wl_wps_handle_sta_linkdown(struct net_device *ndev, u16 inst)
24681
+{
24682
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24683
+ unsigned long flags;
24684
+ u16 cur_state;
24685
+ bool wps_done = false;
24686
+
24687
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24688
+ cur_state = cfg->wps_session[inst].state;
24689
+ if (cur_state == WPS_STATE_REAUTH_WAIT) {
24690
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24691
+ wl_clr_drv_status(cfg, CONNECTED, ndev);
24692
+ wl_clr_drv_status(cfg, DISCONNECTING, ndev);
24693
+ WL_INFORM_MEM(("[%s][WPS] REAUTH link down\n", ndev->name));
24694
+ /* Drop the link down event while we are waiting for reauth */
24695
+ return BCME_UNSUPPORTED;
24696
+ } else if (cur_state == WPS_STATE_STARTED) {
24697
+ /* Link down before reaching EAP-FAIL. End WPS session */
24698
+ cfg->wps_session[inst].state = WPS_STATE_DONE;
24699
+ wps_done = true;
24700
+ WL_INFORM_MEM(("[%s][WPS] link down after wps start\n", ndev->name));
24701
+ } else {
24702
+ WL_DBG(("[%s][WPS] link down in state:%d\n",
24703
+ ndev->name, cur_state));
24704
+ }
24705
+
24706
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24707
+
24708
+ if (wps_done) {
24709
+ wl_wps_session_del(ndev);
24710
+ }
24711
+ return BCME_OK;
24712
+}
24713
+
24714
+static s32
24715
+wl_wps_handle_peersta_linkdown(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24716
+{
24717
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24718
+ unsigned long flags;
24719
+ u16 cur_state;
24720
+ s32 ret = BCME_OK;
24721
+ bool wps_done = false;
24722
+
24723
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24724
+ cur_state = cfg->wps_session[inst].state;
24725
+
24726
+ if (!peer_mac) {
24727
+ WL_ERR(("Invalid arg\n"));
24728
+ ret = BCME_ERROR;
24729
+ goto exit;
24730
+ }
24731
+
24732
+ /* AP/GO can have multiple clients. so validate peer_mac addr
24733
+ * and ensure states are updated only for right peer.
24734
+ */
24735
+ if (memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
24736
+ /* Mac addr not matching. Ignore. */
24737
+ WL_DBG(("[%s][WPS] No active WPS session"
24738
+ "for the peer:" MACDBG "\n", ndev->name, MAC2STRDBG(peer_mac)));
24739
+ ret = BCME_OK;
24740
+ goto exit;
24741
+ }
24742
+ if (cur_state == WPS_STATE_REAUTH_WAIT) {
24743
+ WL_INFORM_MEM(("[%s][WPS] REAUTH link down."
24744
+ " Peer: " MACDBG "\n",
24745
+ ndev->name, MAC2STRDBG(peer_mac)));
24746
+ } else if (cur_state == WPS_STATE_STARTED) {
24747
+ /* Link down before reaching REAUTH_WAIT state. WPS
24748
+ * session ended.
24749
+ */
24750
+ cfg->wps_session[inst].state = WPS_STATE_DONE;
24751
+ WL_INFORM_MEM(("[%s][WPS] link down after wps start"
24752
+ " client:" MACDBG "\n",
24753
+ ndev->name, MAC2STRDBG(peer_mac)));
24754
+ wps_done = true;
24755
+ /* since we have freed lock above, return from here */
24756
+ ret = BCME_OK;
24757
+ } else {
24758
+ WL_ERR(("[%s][WPS] Unsupported state:%d",
24759
+ ndev->name, cur_state));
24760
+ ret = BCME_ERROR;
24761
+ }
24762
+exit:
24763
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24764
+ if (wps_done) {
24765
+ wl_wps_session_del(ndev);
24766
+ }
24767
+ return ret;
24768
+}
24769
+
24770
+static s32
24771
+wl_wps_handle_sta_linkup(struct net_device *ndev, u16 inst)
24772
+{
24773
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24774
+ unsigned long flags;
24775
+ u16 cur_state;
24776
+ s32 ret = BCME_OK;
24777
+ bool wps_done = false;
24778
+
24779
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24780
+ cur_state = cfg->wps_session[inst].state;
24781
+ if (cur_state == WPS_STATE_REAUTH_WAIT) {
24782
+ /* WPS session succeeded. del session. */
24783
+ cfg->wps_session[inst].state = WPS_STATE_DONE;
24784
+ wps_done = true;
24785
+ WL_INFORM_MEM(("[%s][WPS] WPS_REAUTH link up (WPS DONE)\n", ndev->name));
24786
+ ret = BCME_OK;
24787
+ } else {
24788
+ WL_ERR(("[%s][WPS] unexpected link up in state:%d \n",
24789
+ ndev->name, cur_state));
24790
+ ret = BCME_ERROR;
24791
+ }
24792
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24793
+ if (wps_done) {
24794
+ wl_wps_session_del(ndev);
24795
+ }
24796
+ return ret;
24797
+}
24798
+
24799
+static s32
24800
+wl_wps_handle_peersta_linkup(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24801
+{
24802
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24803
+ unsigned long flags;
24804
+ u16 cur_state;
24805
+ s32 ret = BCME_OK;
24806
+
24807
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24808
+ cur_state = cfg->wps_session[inst].state;
24809
+
24810
+ /* For AP case, check whether call came for right peer */
24811
+ if (!peer_mac ||
24812
+ memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
24813
+ WL_ERR(("[WPS] macaddr mismatch\n"));
24814
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24815
+ /* Mac addr not matching. Ignore. */
24816
+ return BCME_ERROR;
24817
+ }
24818
+
24819
+ if (cur_state == WPS_STATE_REAUTH_WAIT) {
24820
+ WL_INFORM_MEM(("[%s][WPS] REAUTH link up\n", ndev->name));
24821
+ ret = BCME_OK;
24822
+ } else {
24823
+ WL_INFORM_MEM(("[%s][WPS] unexpected link up in state:%d \n",
24824
+ ndev->name, cur_state));
24825
+ ret = BCME_ERROR;
24826
+ }
24827
+
24828
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24829
+
24830
+ return ret;
24831
+}
24832
+
24833
+static s32
24834
+wl_wps_handle_authorize(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24835
+{
24836
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24837
+ unsigned long flags;
24838
+ u16 cur_state;
24839
+ bool wps_done = false;
24840
+ s32 ret = BCME_OK;
24841
+
24842
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24843
+ cur_state = cfg->wps_session[inst].state;
24844
+
24845
+ /* For AP case, check whether call came for right peer */
24846
+ if (!peer_mac ||
24847
+ memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
24848
+ WL_ERR(("[WPS] macaddr mismatch\n"));
24849
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24850
+ /* Mac addr not matching. Ignore. */
24851
+ return BCME_ERROR;
24852
+ }
24853
+
24854
+ if (cur_state == WPS_STATE_REAUTH_WAIT) {
24855
+ /* WPS session succeeded. del session. */
24856
+ cfg->wps_session[inst].state = WPS_STATE_DONE;
24857
+ wps_done = true;
24858
+ WL_INFORM_MEM(("[%s][WPS] Authorize done (WPS DONE)\n", ndev->name));
24859
+ ret = BCME_OK;
24860
+ } else {
24861
+ WL_INFORM_MEM(("[%s][WPS] unexpected Authorize in state:%d \n",
24862
+ ndev->name, cur_state));
24863
+ ret = BCME_ERROR;
24864
+ }
24865
+
24866
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24867
+ if (wps_done) {
24868
+ wl_wps_session_del(ndev);
24869
+ }
24870
+ return ret;
24871
+}
24872
+
24873
+static s32
24874
+wl_wps_handle_reauth(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24875
+{
24876
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24877
+ unsigned long flags;
24878
+ u16 cur_state;
24879
+ u16 mode;
24880
+ s32 ret = BCME_OK;
24881
+
24882
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24883
+ cur_state = cfg->wps_session[inst].state;
24884
+ mode = cfg->wps_session[inst].mode;
24885
+
24886
+ if (((mode == WL_MODE_BSS) && (cur_state == WPS_STATE_STARTED)) ||
24887
+ ((mode == WL_MODE_AP) && (cur_state == WPS_STATE_M8_SENT))) {
24888
+ /* Move to reauth wait */
24889
+ cfg->wps_session[inst].state = WPS_STATE_REAUTH_WAIT;
24890
+ /* Use ndev to find the wps instance which fired the timer */
24891
+ timer_set_private(&cfg->wps_session[inst].timer, ndev);
24892
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24893
+ mod_timer(&cfg->wps_session[inst].timer,
24894
+ jiffies + msecs_to_jiffies(WL_WPS_REAUTH_TIMEOUT));
24895
+ WL_INFORM_MEM(("[%s][WPS] STATE_REAUTH_WAIT mode:%d Peer: " MACDBG "\n",
24896
+ ndev->name, mode, MAC2STRDBG(peer_mac)));
24897
+ return BCME_OK;
24898
+ } else {
24899
+ /* 802.1x cases */
24900
+ WL_DBG(("[%s][WPS] EAP-FAIL\n", ndev->name));
24901
+ }
24902
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24903
+ return ret;
24904
+}
24905
+
24906
+static s32
24907
+wl_wps_handle_disconnect(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24908
+{
24909
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24910
+ unsigned long flags;
24911
+ u16 cur_state;
24912
+ s32 ret = BCME_OK;
24913
+
24914
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24915
+ cur_state = cfg->wps_session[inst].state;
24916
+ /* If Disconnect command comes from user space for STA/GC,
24917
+ * respond with event without waiting for event from fw as
24918
+ * it would be dropped by the WPS_SYNC code.
24919
+ */
24920
+ if (cur_state == WPS_STATE_REAUTH_WAIT) {
24921
+ if (ETHER_ISBCAST(peer_mac)) {
24922
+ WL_DBG(("[WPS] Bcast peer. Do nothing.\n"));
24923
+ } else {
24924
+ /* Notify link down */
24925
+ CFG80211_DISCONNECTED(ndev,
24926
+ WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
24927
+ true, GFP_ATOMIC);
24928
+ }
24929
+ } else {
24930
+ WL_DBG(("[%s][WPS] Not valid state to report disconnected:%d",
24931
+ ndev->name, cur_state));
24932
+ ret = BCME_UNSUPPORTED;
24933
+ }
24934
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24935
+ return ret;
24936
+}
24937
+
24938
+static s32
24939
+wl_wps_handle_disconnect_client(struct net_device *ndev, u16 inst, const u8 *peer_mac)
24940
+{
24941
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24942
+ unsigned long flags;
24943
+ u16 cur_state;
24944
+ s32 ret = BCME_OK;
24945
+ bool wps_done = false;
24946
+
24947
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24948
+ cur_state = cfg->wps_session[inst].state;
24949
+ /* For GO/AP, ignore disconnect client during reauth state */
24950
+ if (cur_state == WPS_STATE_REAUTH_WAIT) {
24951
+ if (ETHER_ISBCAST(peer_mac)) {
24952
+ /* If there is broadcast deauth, then mark wps session as ended */
24953
+ cfg->wps_session[inst].state = WPS_STATE_DONE;
24954
+ wps_done = true;
24955
+ WL_INFORM_MEM(("[%s][WPS] BCAST deauth. WPS stopped.\n", ndev->name));
24956
+ ret = BCME_OK;
24957
+ goto exit;
24958
+ } else if (!(memcmp(cfg->wps_session[inst].peer_mac,
24959
+ peer_mac, ETH_ALEN))) {
24960
+ WL_ERR(("[%s][WPS] Drop disconnect client\n", ndev->name));
24961
+ ret = BCME_UNSUPPORTED;
24962
+ }
24963
+ }
24964
+
24965
+exit:
24966
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24967
+ if (wps_done) {
24968
+ wl_wps_session_del(ndev);
24969
+ }
24970
+ return ret;
24971
+}
24972
+
24973
+static s32
24974
+wl_wps_handle_connect_fail(struct net_device *ndev, u16 inst)
24975
+{
24976
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
24977
+ unsigned long flags;
24978
+ u16 cur_state;
24979
+ bool wps_done = false;
24980
+
24981
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
24982
+ cur_state = cfg->wps_session[inst].state;
24983
+ if (cur_state == WPS_STATE_REAUTH_WAIT) {
24984
+ cfg->wps_session[inst].state = WPS_STATE_DONE;
24985
+ wl_clr_drv_status(cfg, CONNECTED, ndev);
24986
+ wps_done = true;
24987
+ WL_INFORM_MEM(("[%s][WPS] Connect fail. WPS stopped.\n",
24988
+ ndev->name));
24989
+ } else {
24990
+ WL_ERR(("[%s][WPS] Connect fail. state:%d\n",
24991
+ ndev->name, cur_state));
24992
+ }
24993
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
24994
+ if (wps_done) {
24995
+ wl_wps_session_del(ndev);
24996
+ }
24997
+ return BCME_OK;
24998
+}
24999
+
25000
+static s32
25001
+wl_wps_handle_m8_sent(struct net_device *ndev, u16 inst, const u8 *peer_mac)
25002
+{
25003
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25004
+ unsigned long flags;
25005
+ u16 cur_state;
25006
+ s32 ret = BCME_OK;
25007
+
25008
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
25009
+ cur_state = cfg->wps_session[inst].state;
25010
+
25011
+ if (cur_state == WPS_STATE_STARTED) {
25012
+ /* Move to M8 sent state */
25013
+ cfg->wps_session[inst].state = WPS_STATE_M8_SENT;
25014
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
25015
+ return BCME_OK;
25016
+ } else {
25017
+ /* 802.1x cases */
25018
+ WL_DBG(("[%s][WPS] Not valid state to send M8\n", ndev->name));
25019
+ }
25020
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
25021
+ return ret;
25022
+}
25023
+
25024
+static s32
25025
+wl_wps_session_update(struct net_device *ndev, u16 state, const u8 *peer_mac)
25026
+{
25027
+ s32 inst;
25028
+ u16 mode;
25029
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25030
+ s32 ret = BCME_ERROR;
25031
+ unsigned long flags;
25032
+
25033
+ WL_CFG_WPS_SYNC_LOCK(&cfg->wps_sync, flags);
25034
+ /* Get current instance for the given ndev */
25035
+ inst = wl_get_wps_inst_match(cfg, ndev);
25036
+ if (inst == BCME_ERROR) {
25037
+ /* No active WPS session. Do Nothing. */
25038
+ WL_DBG(("[%s][WPS] No matching instance.\n", ndev->name));
25039
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
25040
+ return BCME_NOTFOUND;
25041
+ }
25042
+ mode = cfg->wps_session[inst].mode;
25043
+ WL_CFG_WPS_SYNC_UNLOCK(&cfg->wps_sync, flags);
25044
+
25045
+ WL_DBG(("[%s][WPS] state:%d mode:%d Peer: " MACDBG "\n",
25046
+ ndev->name, state, mode, MAC2STRDBG(peer_mac)));
25047
+
25048
+ switch (state) {
25049
+ case WPS_STATE_M8_RECVD:
25050
+ {
25051
+ /* Occasionally, due to race condition between ctrl
25052
+ * and data path, deauth ind is recvd before EAP-FAIL.
25053
+ * Ignore deauth ind before EAP-FAIL
25054
+ * So move to REAUTH WAIT on receiving M8 on GC and
25055
+ * ignore deauth ind before EAP-FAIL till 'x' timeout.
25056
+ * Kickoff a timer to monitor reauth status.
25057
+ */
25058
+ if (mode == WL_MODE_BSS) {
25059
+ ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
25060
+ } else {
25061
+ /* Nothing to be done for AP/GO mode */
25062
+ ret = BCME_OK;
25063
+ }
25064
+ break;
25065
+ }
25066
+ case WPS_STATE_M8_SENT:
25067
+ {
25068
+ /* Mantain the M8 sent state to verify
25069
+ * EAP-FAIL sent is valid
25070
+ */
25071
+ if (mode == WL_MODE_AP) {
25072
+ ret = wl_wps_handle_m8_sent(ndev, inst, peer_mac);
25073
+ } else {
25074
+ /* Nothing to be done for STA/GC mode */
25075
+ ret = BCME_OK;
25076
+ }
25077
+ break;
25078
+ }
25079
+ case WPS_STATE_EAP_FAIL:
25080
+ {
25081
+ /* Move to REAUTH WAIT following EAP-FAIL TX on GO/AP.
25082
+ * Kickoff a timer to monitor reauth status
25083
+ */
25084
+ if (mode == WL_MODE_AP) {
25085
+ ret = wl_wps_handle_reauth(ndev, inst, peer_mac);
25086
+ } else {
25087
+ /* Nothing to be done for STA/GC mode */
25088
+ ret = BCME_OK;
25089
+ }
25090
+ break;
25091
+ }
25092
+ case WPS_STATE_LINKDOWN:
25093
+ {
25094
+ if (mode == WL_MODE_BSS) {
25095
+ ret = wl_wps_handle_sta_linkdown(ndev, inst);
25096
+ } else if (mode == WL_MODE_AP) {
25097
+ /* Take action only for matching peer mac */
25098
+ if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25099
+ ret = wl_wps_handle_peersta_linkdown(ndev, inst, peer_mac);
25100
+ }
25101
+ }
25102
+ break;
25103
+ }
25104
+ case WPS_STATE_LINKUP:
25105
+ {
25106
+ if (mode == WL_MODE_BSS) {
25107
+ wl_wps_handle_sta_linkup(ndev, inst);
25108
+ } else if (mode == WL_MODE_AP) {
25109
+ /* Take action only for matching peer mac */
25110
+ if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25111
+ wl_wps_handle_peersta_linkup(ndev, inst, peer_mac);
25112
+ }
25113
+ }
25114
+ break;
25115
+ }
25116
+ case WPS_STATE_DISCONNECT_CLIENT:
25117
+ {
25118
+ /* Disconnect STA/GC command from user space */
25119
+ if (mode == WL_MODE_AP) {
25120
+ ret = wl_wps_handle_disconnect_client(ndev, inst, peer_mac);
25121
+ } else {
25122
+ WL_ERR(("[WPS] Unsupported mode %d\n", mode));
25123
+ }
25124
+ break;
25125
+ }
25126
+ case WPS_STATE_DISCONNECT:
25127
+ {
25128
+ /* Disconnect command on STA/GC interface */
25129
+ if (mode == WL_MODE_BSS) {
25130
+ ret = wl_wps_handle_disconnect(ndev, inst, peer_mac);
25131
+ }
25132
+ break;
25133
+ }
25134
+ case WPS_STATE_CONNECT_FAIL:
25135
+ {
25136
+ if (mode == WL_MODE_BSS) {
25137
+ ret = wl_wps_handle_connect_fail(ndev, inst);
25138
+ } else {
25139
+ WL_ERR(("[WPS] Unsupported mode %d\n", mode));
25140
+ }
25141
+ break;
25142
+ }
25143
+ case WPS_STATE_AUTHORIZE:
25144
+ {
25145
+ if (mode == WL_MODE_AP) {
25146
+ /* Take action only for matching peer mac */
25147
+ if (!memcmp(cfg->wps_session[inst].peer_mac, peer_mac, ETH_ALEN)) {
25148
+ wl_wps_handle_authorize(ndev, inst, peer_mac);
25149
+ } else {
25150
+ WL_INFORM_MEM(("[WPS] Authorize Request for wrong peer\n"));
25151
+ }
25152
+ }
25153
+ break;
25154
+ }
25155
+
25156
+ default:
25157
+ WL_ERR(("[WPS] Unsupported state:%d mode:%d\n", state, mode));
25158
+ ret = BCME_ERROR;
25159
+ }
25160
+
25161
+ return ret;
25162
+}
25163
+
25164
+#define EAP_EXP_ATTRIB_DATA_OFFSET 14
25165
+void
25166
+wl_handle_wps_states(struct net_device *ndev, u8 *pkt, u16 len, bool direction)
25167
+{
25168
+ eapol_header_t *eapol_hdr;
25169
+ bool tx_packet = direction;
25170
+ u16 eapol_type;
25171
+ u16 mode;
25172
+ u8 *peer_mac;
25173
+
25174
+ if (!ndev || !pkt) {
25175
+ WL_ERR(("[WPS] Invalid arg\n"));
25176
+ return;
25177
+ }
25178
+
25179
+ if (len < (ETHER_HDR_LEN + EAPOL_HDR_LEN)) {
25180
+ WL_ERR(("[WPS] Invalid len\n"));
25181
+ return;
25182
+ }
25183
+
25184
+ eapol_hdr = (eapol_header_t *)pkt;
25185
+ eapol_type = eapol_hdr->type;
25186
+
25187
+ peer_mac = tx_packet ? eapol_hdr->eth.ether_dhost :
25188
+ eapol_hdr->eth.ether_shost;
25189
+ /*
25190
+ * The implementation assumes only one WPS session would be active
25191
+ * per interface at a time. Even for hostap, the wps_pin session
25192
+ * is limited to one enrollee/client at a time. A session is marked
25193
+ * started on WSC_START and gets cleared from below contexts
25194
+ * a) Deauth/link down before reaching EAP-FAIL state. (Fail case)
25195
+ * b) Link up following EAP-FAIL. (success case)
25196
+ * c) Link up timeout after EAP-FAIL. (Fail case)
25197
+ */
25198
+
25199
+ if (eapol_type == EAP_PACKET) {
25200
+ wl_eap_header_t *eap;
25201
+
25202
+ if (len > sizeof(*eap)) {
25203
+ eap = (wl_eap_header_t *)(pkt + ETHER_HDR_LEN + EAPOL_HDR_LEN);
25204
+ if (eap->type == EAP_EXPANDED_TYPE) {
25205
+ wl_eap_exp_t *exp = (wl_eap_exp_t *)eap->data;
25206
+ if (eap->length > EAP_EXP_HDR_MIN_LENGTH) {
25207
+ /* opcode is at fixed offset */
25208
+ u8 opcode = exp->opcode;
25209
+ u16 eap_len = ntoh16(eap->length);
25210
+
25211
+ WL_DBG(("[%s][WPS] EAP EXPANDED packet. opcode:%x len:%d\n",
25212
+ ndev->name, opcode, eap_len));
25213
+ if (opcode == EAP_WSC_MSG) {
25214
+ const u8 *msg;
25215
+ const u8* parse_buf = exp->data;
25216
+ /* Check if recvd pkt is fragmented */
25217
+ if ((!tx_packet) &&
25218
+ (exp->flags &
25219
+ EAP_EXP_FLAGS_FRAGMENTED_DATA)) {
25220
+ if ((eap_len - EAP_EXP_ATTRIB_DATA_OFFSET)
25221
+ > 2) {
25222
+ parse_buf +=
25223
+ EAP_EXP_FRAGMENT_LEN_OFFSET;
25224
+ eap_len -=
25225
+ EAP_EXP_FRAGMENT_LEN_OFFSET;
25226
+ WL_DBG(("Rcvd EAP"
25227
+ " fragmented pkt\n"));
25228
+ } else {
25229
+ /* If recvd pkt is fragmented
25230
+ * and does not have
25231
+ * length field drop the packet.
25232
+ */
25233
+ return;
25234
+ }
25235
+ }
25236
+
25237
+ msg = wl_find_attribute(parse_buf,
25238
+ (eap_len - EAP_EXP_ATTRIB_DATA_OFFSET),
25239
+ EAP_ATTRIB_MSGTYPE);
25240
+ if (unlikely(!msg)) {
25241
+ WL_ERR(("[WPS] ATTRIB MSG not found!\n"));
25242
+ } else if ((*msg == EAP_WSC_MSG_M8) &&
25243
+ !tx_packet) {
25244
+ WL_INFORM_MEM(("[%s][WPS] M8\n",
25245
+ ndev->name));
25246
+ wl_wps_session_update(ndev,
25247
+ WPS_STATE_M8_RECVD, peer_mac);
25248
+ } else if ((*msg == EAP_WSC_MSG_M8) &&
25249
+ tx_packet) {
25250
+ WL_INFORM_MEM(("[%s][WPS] M8 Sent\n",
25251
+ ndev->name));
25252
+ wl_wps_session_update(ndev,
25253
+ WPS_STATE_M8_SENT, peer_mac);
25254
+ } else {
25255
+ WL_DBG(("[%s][WPS] EAP WSC MSG: 0x%X\n",
25256
+ ndev->name, *msg));
25257
+ }
25258
+ } else if (opcode == EAP_WSC_START) {
25259
+ /* WSC session started. WSC_START - Tx from GO/AP.
25260
+ * Session will be deleted on successful link up or
25261
+ * on failure (deauth context)
25262
+ */
25263
+ mode = tx_packet ? WL_MODE_AP : WL_MODE_BSS;
25264
+ wl_wps_session_add(ndev, mode, peer_mac);
25265
+ WL_INFORM_MEM(("[%s][WPS] WSC_START Mode:%d\n",
25266
+ ndev->name, mode));
25267
+ } else if (opcode == EAP_WSC_DONE) {
25268
+ /* WSC session done. TX on STA/GC. RX on GO/AP
25269
+ * On devices where config file save fails, it may
25270
+ * return WPS_NAK with config_error:0. But the
25271
+ * connection would still proceed. Hence don't let
25272
+ * state machine depend on WSC DONE.
25273
+ */
25274
+ WL_INFORM_MEM(("[%s][WPS] WSC_DONE\n", ndev->name));
25275
+ }
25276
+ }
25277
+ }
25278
+
25279
+ if (eap->code == EAP_CODE_FAILURE) {
25280
+ /* EAP_FAIL */
25281
+ WL_INFORM_MEM(("[%s][WPS] EAP_FAIL\n", ndev->name));
25282
+ wl_wps_session_update(ndev,
25283
+ WPS_STATE_EAP_FAIL, peer_mac);
25284
+ }
25285
+ }
25286
+ }
25287
+}
25288
+#endif /* WL_WPS_SYNC */
25289
+
25290
+s32
25291
+wl_cfg80211_sup_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25292
+ const wl_event_msg_t *event, void *data)
25293
+{
25294
+ int err = BCME_OK;
25295
+ u32 status = ntoh32(event->status);
25296
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
25297
+ u32 reason = ntoh32(event->reason);
25298
+
25299
+ if ((status == WLC_SUP_KEYED || status == WLC_SUP_KEYXCHANGE_WAIT_G1) &&
25300
+ reason == WLC_E_SUP_OTHER) {
25301
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
25302
+ /* NL80211_CMD_PORT_AUTHORIZED supported above >= 4.15 */
25303
+ cfg80211_port_authorized(ndev, (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID),
25304
+ GFP_KERNEL);
25305
+ WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
25306
+#elif ((LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || \
25307
+ defined(WL_VENDOR_EXT_SUPPORT))
25308
+ err = wl_cfgvendor_send_async_event(bcmcfg_to_wiphy(cfg), ndev,
25309
+ BRCM_VENDOR_EVENT_PORT_AUTHORIZED, NULL, 0);
25310
+ WL_INFORM_MEM(("4way HS finished. port authorized event sent\n"));
25311
+#else
25312
+ /* not supported in kernel <= 3,14,0 */
25313
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) */
25314
+ } else if (status < WLC_SUP_KEYXCHANGE_WAIT_G1 && reason != WLC_E_SUP_OTHER) {
25315
+ /* if any failure seen while 4way HS, should send NL80211_CMD_DISCONNECT */
25316
+ WL_ERR(("4way HS error. status:%d, reason:%d\n", status, reason));
25317
+ CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
25318
+ }
25319
+
25320
+ return err;
25321
+}
25322
+
25323
+#ifdef WL_BCNRECV
25324
+static s32
25325
+wl_bcnrecv_aborted_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25326
+ const wl_event_msg_t *e, void *data)
25327
+{
25328
+ s32 status = ntoh32(e->status);
25329
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
25330
+ /* Abort fakeapscan, when Roam is in progress */
25331
+ if (status == WLC_E_STATUS_RXBCN_ABORT) {
25332
+ wl_android_bcnrecv_stop(ndev, WL_BCNRECV_ROAMABORT);
25333
+ } else {
25334
+ WL_ERR(("UNKNOWN STATUS. status:%d\n", status));
25335
+ }
25336
+ return BCME_OK;
25337
+}
25338
+#endif /* WL_BCNRECV */
25339
+
25340
+#ifdef WL_MBO
25341
+static s32
25342
+wl_mbo_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25343
+ const wl_event_msg_t *e, void *data)
25344
+{
25345
+ s32 err = 0;
25346
+ wl_event_mbo_t *mbo_evt = (wl_event_mbo_t *)data;
25347
+ wl_event_mbo_cell_nw_switch_t *cell_sw_evt = NULL;
25348
+ wl_btm_event_type_data_t *evt_data = NULL;
25349
+
25350
+ WL_INFORM(("MBO: Evt %u\n", mbo_evt->type));
25351
+
25352
+ if (mbo_evt->type == WL_MBO_E_CELLULAR_NW_SWITCH) {
25353
+ cell_sw_evt = (wl_event_mbo_cell_nw_switch_t *)mbo_evt->data;
25354
+ BCM_REFERENCE(cell_sw_evt);
25355
+ SUPP_EVENT(("CTRL-EVENT-CELLULAR-SWITCH", "reason %d cur_assoc_time_left %u "
25356
+ "reassoc_delay %u\n", cell_sw_evt->reason,
25357
+ cell_sw_evt->assoc_time_remain, cell_sw_evt->reassoc_delay));
25358
+ } else if (mbo_evt->type == WL_MBO_E_BTM_RCVD) {
25359
+ evt_data = (wl_btm_event_type_data_t *)mbo_evt->data;
25360
+ if (evt_data->version != WL_BTM_EVENT_DATA_VER_1) {
25361
+ WL_ERR(("version mismatch. rcvd %u expected %u\n",
25362
+ evt_data->version, WL_BTM_EVENT_DATA_VER_1));
25363
+ return -1;
25364
+ }
25365
+ SUPP_EVENT(("CTRL-EVENT-BRCM-BTM-REQ-RCVD", "reason=%u\n",
25366
+ evt_data->transition_reason));
25367
+ } else {
25368
+ WL_INFORM(("UNKNOWN EVENT. type:%u\n", mbo_evt->type));
25369
+ }
25370
+ return err;
25371
+}
25372
+#endif /* WL_MBO */
25373
+
25374
+#ifdef WL_CAC_TS
25375
+static s32
25376
+wl_cfg80211_cac_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25377
+ const wl_event_msg_t *e, void *data)
25378
+{
25379
+ u32 event = ntoh32(e->event_type);
25380
+ s32 status = ntoh32(e->status);
25381
+ s32 reason = ntoh32(e->reason);
25382
+
25383
+ BCM_REFERENCE(reason);
25384
+
25385
+ if (event == WLC_E_ADDTS_IND) {
25386
+ /* The supp log format of adding ts_delay in success case needs to be maintained */
25387
+ if (status == WLC_E_STATUS_SUCCESS) {
25388
+ uint *ts_delay = (uint *)data;
25389
+ BCM_REFERENCE(ts_delay);
25390
+ SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d ts_delay=%u\n",
25391
+ status, reason, *ts_delay));
25392
+ } else {
25393
+ SUPP_EVENT(("CTRL-EVENT-CAC-ADDTS", "status=%d reason=%d\n",
25394
+ status, reason));
25395
+ }
25396
+ } else if (event == WLC_E_DELTS_IND) {
25397
+ SUPP_EVENT(("CTRL-EVENT-CAC-DELTS", "status=%d reason=%d\n", status, reason));
25398
+ }
25399
+
25400
+ return BCME_OK;
25401
+}
25402
+#endif /* WL_CAC_TS */
25403
+
25404
+#if defined(WL_MBO) || defined(WL_OCE)
25405
+static s32
25406
+wl_bssid_prune_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25407
+ const wl_event_msg_t *e, void *data)
25408
+{
25409
+ s32 err = 0;
25410
+ uint reason = 0;
25411
+ wl_bssid_pruned_evt_info_t *evt_info = (wl_bssid_pruned_evt_info_t *)data;
25412
+
25413
+ if (evt_info->version == WL_BSSID_PRUNE_EVT_VER_1) {
25414
+ if (evt_info->reason == WLC_E_PRUNE_ASSOC_RETRY_DELAY) {
25415
+ /* MBO assoc retry delay */
25416
+ reason = WIFI_PRUNE_ASSOC_RETRY_DELAY;
25417
+ SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
25418
+ " reason=%u timeout_val=%u(ms)\n", evt_info->SSID,
25419
+ ETHER_TO_MACF(evt_info->BSSID), reason, evt_info->time_remaining));
25420
+ } else if (evt_info->reason == WLC_E_PRUNE_RSSI_ASSOC_REJ) {
25421
+ /* OCE RSSI-based assoc rejection */
25422
+ reason = WIFI_PRUNE_RSSI_ASSOC_REJ;
25423
+ SUPP_EVENT(("CTRL-EVENT-BRCM-BSSID-PRUNED", "ssid=%s bssid=" MACF
25424
+ " reason=%u timeout_val=%u(ms) rssi_threshold=%d(dBm)\n",
25425
+ evt_info->SSID, ETHER_TO_MACF(evt_info->BSSID),
25426
+ reason, evt_info->time_remaining, evt_info->rssi_threshold));
25427
+ } else {
25428
+ /* Invalid other than the assoc retry delay/RSSI assoc rejection
25429
+ * in the current handler
25430
+ */
25431
+ BCM_REFERENCE(reason);
25432
+ WL_INFORM(("INVALID. reason:%u\n", evt_info->reason));
25433
+ }
25434
+ } else {
25435
+ WL_INFORM(("version mismatch. rcvd %u expected %u\n", evt_info->version,
25436
+ WL_BSSID_PRUNE_EVT_VER_1));
25437
+ }
25438
+ return err;
25439
+}
25440
+#endif /* WL_MBO || WL_OCE */
25441
+#ifdef RTT_SUPPORT
25442
+static s32
25443
+wl_cfg80211_rtt_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25444
+ const wl_event_msg_t *e, void *data)
25445
+{
25446
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
25447
+ wl_event_msg_t event;
25448
+
25449
+ (void)memcpy_s(&event, sizeof(wl_event_msg_t),
25450
+ e, sizeof(wl_event_msg_t));
25451
+ return dhd_rtt_event_handler(dhdp, &event, data);
25452
+}
25453
+#endif /* RTT_SUPPORT */
25454
+
25455
+static s32
25456
+wl_notify_dos_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25457
+ const wl_event_msg_t *e, void *data)
25458
+{
25459
+ u32 event = ntoh32(e->event_type);
25460
+ s32 status = ntoh32(e->status);
25461
+
25462
+ if (event == WLC_E_IND_DOS_STATUS)
25463
+ {
25464
+ WL_INFORM(("DOS_STATUS_IND_EVENT_DETECTED\n"));
25465
+ if ((status) == 1) {
25466
+ WL_INFORM(("NORMAL\n"));
25467
+ }
25468
+ else if ((status) == 2) {
25469
+ WL_INFORM(("ALERT\n"));
25470
+ }
25471
+ else if ((status) == 3) {
25472
+ WL_INFORM(("PROTECTED\n"));
25473
+ }
25474
+ else if ((status) == 4) {
25475
+ WL_INFORM(("MONITOR\n"));
25476
+ }
25477
+ else {
25478
+ WL_INFORM(("STATE_UNKNOWN\n"));
25479
+ }
25480
+
25481
+ }
25482
+ else
25483
+ WL_INFORM(("unknown_event\n"));
25484
+ return 0;
25485
+}
25486
+void
25487
+wl_print_verinfo(struct bcm_cfg80211 *cfg)
25488
+{
25489
+ char *ver_ptr;
25490
+ uint32 alloc_len = MOD_PARAM_INFOLEN;
25491
+
25492
+ if (!cfg) {
25493
+ WL_ERR(("cfg is NULL\n"));
25494
+ return;
25495
+ }
25496
+
25497
+ ver_ptr = (char *)MALLOCZ(cfg->osh, alloc_len);
25498
+ if (!ver_ptr) {
25499
+ WL_ERR(("Failed to alloc ver_ptr\n"));
25500
+ return;
25501
+ }
25502
+
25503
+ if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
25504
+ TRUE, &ver_ptr, alloc_len)) {
25505
+ WL_ERR(("DHD Version: %s\n", ver_ptr));
25506
+ }
25507
+
25508
+ if (!dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg),
25509
+ FALSE, &ver_ptr, alloc_len)) {
25510
+ WL_ERR(("F/W Version: %s\n", ver_ptr));
25511
+ }
25512
+
25513
+ MFREE(cfg->osh, ver_ptr, alloc_len);
25514
+}
25515
+#if defined(WL_DISABLE_HE_SOFTAP) || defined(WL_DISABLE_HE_P2P)
25516
+typedef struct {
25517
+ uint16 id;
25518
+ uint16 len;
25519
+ uint32 val;
25520
+} he_xtlv_v32;
25521
+
25522
+ static bool
25523
+wl_he_get_uint_cb(void *ctx, uint16 *id, uint16 *len)
25524
+{
25525
+ he_xtlv_v32 *v32 = ctx;
25526
+
25527
+ *id = v32->id;
25528
+ *len = v32->len;
25529
+
25530
+ return FALSE;
25531
+}
25532
+
25533
+ static void
25534
+wl_he_pack_uint_cb(void *ctx, uint16 id, uint16 len, uint8 *buf)
25535
+{
25536
+ he_xtlv_v32 *v32 = ctx;
25537
+
25538
+ BCM_REFERENCE(id);
25539
+ BCM_REFERENCE(len);
25540
+
25541
+ v32->val = htod32(v32->val);
25542
+
25543
+ switch (v32->len) {
25544
+ case sizeof(uint8):
25545
+ *buf = (uint8)v32->val;
25546
+ break;
25547
+ case sizeof(uint16):
25548
+ store16_ua(buf, (uint16)v32->val);
25549
+ break;
25550
+ case sizeof(uint32):
25551
+ store32_ua(buf, v32->val);
25552
+ break;
25553
+ default:
25554
+ /* ASSERT(0); */
25555
+ break;
25556
+ }
25557
+}
25558
+
25559
+int wl_cfg80211_set_he_mode(struct net_device *dev, struct bcm_cfg80211 *cfg,
25560
+ s32 bssidx, u32 interface_type, bool set)
25561
+{
25562
+ bcm_xtlv_t read_he_xtlv;
25563
+ uint8 se_he_xtlv[32];
25564
+ int se_he_xtlv_len = sizeof(se_he_xtlv);
25565
+ he_xtlv_v32 v32;
25566
+ u32 he_feature = 0;
25567
+ s32 err = 0;
25568
+ u32 he_interface = 0;
25569
+
25570
+ read_he_xtlv.id = WL_HE_CMD_FEATURES;
25571
+ read_he_xtlv.len = 0;
25572
+ err = wldev_iovar_getbuf_bsscfg(dev, "he", &read_he_xtlv, sizeof(read_he_xtlv),
25573
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, NULL);
25574
+ if (err < 0) {
25575
+ if (err == BCME_UNSUPPORTED) {
25576
+ /* HE not supported. Do nothing. */
25577
+ return BCME_OK;
25578
+ }
25579
+ WL_ERR(("HE get failed. error=%d\n", err));
25580
+ } else {
25581
+ he_feature = *(int*)cfg->ioctl_buf;
25582
+ he_feature = dtoh32(he_feature);
25583
+ }
25584
+
25585
+ v32.id = WL_HE_CMD_FEATURES;
25586
+ v32.len = sizeof(s32);
25587
+ if (interface_type == WL_IF_TYPE_P2P_DISC) {
25588
+ he_interface = WL_HE_FEATURES_HE_P2P;
25589
+ } else if (interface_type == WL_IF_TYPE_AP) {
25590
+ he_interface = WL_HE_FEATURES_HE_AP;
25591
+ } else {
25592
+ WL_ERR(("HE request for Invalid interface type"));
25593
+ err = BCME_BADARG;
25594
+ return err;
25595
+ }
25596
+
25597
+ if (set) {
25598
+ v32.val = (he_feature | he_interface);
25599
+ } else {
25600
+ v32.val = (he_feature & ~he_interface);
25601
+ }
25602
+
25603
+ err = bcm_pack_xtlv_buf((void *)&v32, se_he_xtlv, sizeof(se_he_xtlv),
25604
+ BCM_XTLV_OPTION_ALIGN32, wl_he_get_uint_cb, wl_he_pack_uint_cb,
25605
+ &se_he_xtlv_len);
25606
+ if (err != BCME_OK) {
25607
+ WL_ERR(("failed to pack he settvl=%d\n", err));
25608
+ }
25609
+
25610
+ err = wldev_iovar_setbuf_bsscfg(dev, "he", &se_he_xtlv, sizeof(se_he_xtlv),
25611
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
25612
+ if (err < 0) {
25613
+ WL_ERR(("failed to set he features, error=%d\n", err));
25614
+ }
25615
+ WL_INFORM(("Set HE[%d] done\n", set));
25616
+
25617
+ return err;
25618
+}
25619
+#endif /* WL_DISABLE_HE_SOFTAP || WL_DISABLE_HE_P2P */
25620
+
25621
+/* Get the concurrency mode */
25622
+int wl_cfg80211_get_concurrency_mode(struct bcm_cfg80211 *cfg)
25623
+{
25624
+ struct net_info *iter, *next;
25625
+ uint cmode = CONCURRENCY_MODE_NONE;
25626
+ u32 connected_cnt = 0;
25627
+ u32 pre_channel = 0, channel = 0;
25628
+ u32 pre_band = 0;
25629
+ u32 chanspec = 0;
25630
+ u32 band = 0;
25631
+
25632
+ connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
25633
+ if (connected_cnt <= 1) {
25634
+ return cmode;
25635
+ }
25636
+ GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
25637
+ for_each_ndev(cfg, iter, next) {
25638
+ if (iter->ndev) {
25639
+ if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
25640
+ if (wldev_iovar_getint(iter->ndev, "chanspec",
25641
+ (s32 *)&chanspec) == BCME_OK) {
25642
+ channel = wf_chspec_ctlchan(
25643
+ wl_chspec_driver_to_host(chanspec));
25644
+ band = (channel <= CH_MAX_2G_CHANNEL) ?
25645
+ IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
25646
+ }
25647
+ if ((!pre_channel && channel)) {
25648
+ pre_band = band;
25649
+ pre_channel = channel;
25650
+ } else if (pre_channel) {
25651
+ if ((pre_band == band) && (pre_channel == channel)) {
25652
+ cmode = CONCURRENCY_SCC_MODE;
25653
+ goto exit;
25654
+ } else if ((pre_band == band) && (pre_channel != channel)) {
25655
+ cmode = CONCURRENCY_VSDB_MODE;
25656
+ goto exit;
25657
+ } else if (pre_band != band) {
25658
+ cmode = CONCURRENCY_RSDB_MODE;
25659
+ goto exit;
25660
+ }
25661
+ }
25662
+ }
25663
+ }
25664
+ }
25665
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
25666
+ 4 && __GNUC_MINOR__ >= 6))
25667
+_Pragma("GCC diagnostic pop")
25668
+#endif // endif
25669
+exit:
25670
+ return cmode;
25671
+}
25672
+#ifdef WL_CHAN_UTIL
25673
+static s32
25674
+wl_cfg80211_bssload_report_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
25675
+ const wl_event_msg_t *e, void *data)
25676
+{
25677
+ s32 err = BCME_OK;
25678
+ struct sk_buff *skb = NULL;
25679
+ s32 status = ntoh32(e->status);
25680
+ u8 chan_use_percentage = 0;
25681
+#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
25682
+ LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
25683
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
25684
+#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
25685
+ /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
25686
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25687
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
25688
+ uint len;
25689
+ gfp_t kflags;
25690
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25691
+
25692
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25693
+ len = CU_ATTR_HDR_LEN + sizeof(u8);
25694
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
25695
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25696
+
25697
+#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
25698
+ LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
25699
+ skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), len,
25700
+ BRCM_VENDOR_EVENT_CU, kflags);
25701
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25702
+ skb = cfg80211_vendor_event_alloc(wiphy, len, BRCM_VENDOR_EVENT_CU, kflags);
25703
+#else
25704
+ /* No support exist */
25705
+#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
25706
+ /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
25707
+ if (!skb) {
25708
+ WL_ERR(("skb alloc failed"));
25709
+ return -ENOMEM;
25710
+ }
25711
+
25712
+ if ((status == WLC_E_STATUS_SUCCESS) && data) {
25713
+ wl_bssload_t *bssload_report = (wl_bssload_t *)data;
25714
+ chan_use_percentage = (bssload_report->chan_util * 100) / 255;
25715
+ WL_DBG(("ChannelUtilization=%hhu\n", chan_use_percentage));
25716
+ err = nla_put_u8(skb, CU_ATTR_PERCENTAGE, chan_use_percentage);
25717
+ if (err < 0) {
25718
+ WL_ERR(("Failed to put CU_ATTR_PERCENTAGE, err:%d\n", err));
25719
+ }
25720
+ }
25721
+
25722
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25723
+ cfg80211_vendor_event(skb, kflags);
25724
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25725
+
25726
+ return err;
25727
+}
25728
+
25729
+#define WL_CHAN_UTIL_DEFAULT_INTERVAL 3000
25730
+#define WL_CHAN_UTIL_THRESH_MIN 15
25731
+#define WL_CHAN_UTIL_THRESH_INTERVAL 10
25732
+#ifndef CUSTOM_CU_INTERVAL
25733
+#define CUSTOM_CU_INTERVAL WL_CHAN_UTIL_DEFAULT_INTERVAL
25734
+#endif /* CUSTOM_CU_INTERVAL */
25735
+
25736
+static s32
25737
+wl_cfg80211_start_bssload_report(struct net_device *ndev)
25738
+{
25739
+ s32 err = BCME_OK;
25740
+ wl_bssload_cfg_t blcfg;
25741
+ u8 i;
25742
+ struct bcm_cfg80211 *cfg;
25743
+
25744
+ if (!ndev) {
25745
+ return -ENODEV;
25746
+ }
25747
+
25748
+ cfg = wl_get_cfg(ndev);
25749
+ if (!cfg) {
25750
+ return -ENODEV;
25751
+ }
25752
+
25753
+ /* Typecasting to void as the buffer size is same as the memset size */
25754
+ (void)memset_s(&blcfg, sizeof(wl_bssload_cfg_t), 0, sizeof(wl_bssload_cfg_t));
25755
+ /* Set default report interval 3 sec and 8 threshhold levels between 15 to 85% */
25756
+ blcfg.rate_limit_msec = CUSTOM_CU_INTERVAL;
25757
+ blcfg.num_util_levels = MAX_BSSLOAD_LEVELS;
25758
+ for (i = 0; i < MAX_BSSLOAD_LEVELS; i++) {
25759
+ blcfg.util_levels[i] = (((WL_CHAN_UTIL_THRESH_MIN +
25760
+ (i * WL_CHAN_UTIL_THRESH_INTERVAL)) * 255) / 100);
25761
+ }
25762
+
25763
+ err = wldev_iovar_setbuf(ndev, "bssload_report_event", &blcfg,
25764
+ sizeof(wl_bssload_cfg_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
25765
+ if (unlikely(err)) {
25766
+ WL_ERR(("Set event_msgs error (%d)\n", err));
25767
+ }
25768
+
25769
+ return err;
25770
+}
25771
+#endif /* WL_CHAN_UTIL */
25772
+
25773
+s32
25774
+wl_cfg80211_config_suspend_events(struct net_device *ndev, bool enable)
25775
+{
25776
+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
25777
+ s8 eventmask[WL_EVENTING_MASK_LEN];
25778
+ s32 err = 0;
25779
+ struct bcm_cfg80211 *cfg;
25780
+
25781
+ if (!ndev) {
25782
+ return -ENODEV;
25783
+ }
25784
+
25785
+ cfg = wl_get_cfg(ndev);
25786
+ if (!cfg) {
25787
+ return -ENODEV;
25788
+ }
25789
+
25790
+ mutex_lock(&cfg->event_sync);
25791
+ err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
25792
+ if (unlikely(err)) {
25793
+ WL_ERR(("Get event_msgs error (%d)\n", err));
25794
+ goto eventmsg_out;
25795
+ }
25796
+
25797
+ (void)memcpy_s(eventmask, WL_EVENTING_MASK_LEN, iovbuf, WL_EVENTING_MASK_LEN);
25798
+ /* Add set/clear of event mask under feature specific flags */
25799
+ if (enable) {
25800
+ WL_DBG(("%s: Enabling events on resume\n", __FUNCTION__));
25801
+#ifdef WL_CHAN_UTIL
25802
+ setbit(eventmask, WLC_E_BSS_LOAD);
25803
+#endif /* WL_CHAN_UTIL */
25804
+ } else {
25805
+ WL_DBG(("%s: Disabling events before suspend\n", __FUNCTION__));
25806
+#ifdef WL_CHAN_UTIL
25807
+ clrbit(eventmask, WLC_E_BSS_LOAD);
25808
+#endif /* WL_CHAN_UTIL */
25809
+ }
25810
+
25811
+ err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
25812
+ sizeof(iovbuf), NULL);
25813
+ if (unlikely(err)) {
25814
+ WL_ERR(("Set event_msgs error (%d)\n", err));
25815
+ goto eventmsg_out;
25816
+ }
25817
+
25818
+eventmsg_out:
25819
+ mutex_unlock(&cfg->event_sync);
25820
+ return err;
25821
+}
25822
+
25823
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
25824
+int
25825
+wl_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
25826
+ struct cfg80211_csa_settings *params)
25827
+{
25828
+ s32 err = BCME_OK;
25829
+ s32 chan = 0;
25830
+ u32 band = 0;
25831
+ u32 bw = WL_CHANSPEC_BW_20;
25832
+ chanspec_t chspec = 0;
25833
+ wl_chan_switch_t csa_arg;
25834
+ struct cfg80211_chan_def *chandef = &params->chandef;
25835
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
25836
+
25837
+ dev = ndev_to_wlc_ndev(dev, cfg);
25838
+ chan = ieee80211_frequency_to_channel(chandef->chan->center_freq);
25839
+ band = chandef->chan->band;
25840
+
25841
+ WL_ERR(("netdev_ifidx(%d), target channel(%d) target bandwidth(%d),"
25842
+ " mode(%d), count(%d)\n", dev->ifindex, chan, chandef->width,
25843
+ params->block_tx, params->count));
25844
+
25845
+ if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP) {
25846
+ WL_ERR(("Channel Switch doesn't support on "
25847
+ "the non-SoftAP mode\n"));
25848
+ return -EINVAL;
25849
+ }
25850
+
25851
+ if (chan == cfg->ap_oper_channel) {
25852
+ WL_ERR(("Channel %d is same as current operating channel,"
25853
+ " so skip\n", chan));
25854
+ return BCME_OK;
25855
+ }
25856
+
25857
+ if (band == IEEE80211_BAND_5GHZ) {
25858
+#ifdef APSTA_RESTRICTED_CHANNEL
25859
+ if (chan != DEFAULT_5G_SOFTAP_CHANNEL) {
25860
+ WL_ERR(("Invalid 5G Channel, chan=%d\n", chan));
25861
+ return -EINVAL;
25862
+ }
25863
+#endif /* APSTA_RESTRICTED_CHANNEL */
25864
+ err = wl_get_bandwidth_cap(bcmcfg_to_prmry_ndev(cfg),
25865
+ band, &bw);
25866
+ if (err < 0) {
25867
+ WL_ERR(("Failed to get bandwidth information,"
25868
+ " err=%d\n", err));
25869
+ return err;
25870
+ }
25871
+ } else if (band == IEEE80211_BAND_2GHZ) {
25872
+#ifdef APSTA_RESTRICTED_CHANNEL
25873
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
25874
+ u32 *sta_chan = (u32 *)wl_read_prof(cfg,
25875
+ bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN);
25876
+
25877
+ /* In 2GHz STA/SoftAP concurrent mode, the operating channel
25878
+ * of STA and SoftAP should be confgiured to the same 2GHz
25879
+ * channel. Otherwise, it is an invalid configuration.
25880
+ */
25881
+ if (DHD_OPMODE_STA_SOFTAP_CONCURR(dhdp) &&
25882
+ wl_get_drv_status(cfg, CONNECTED,
25883
+ bcmcfg_to_prmry_ndev(cfg)) && sta_chan &&
25884
+ (*sta_chan != chan)) {
25885
+ WL_ERR(("Invalid 2G Channel in case of STA/SoftAP"
25886
+ " concurrent mode, sta_chan=%d, chan=%d\n",
25887
+ *sta_chan, chan));
25888
+ return -EINVAL;
25889
+ }
25890
+#endif /* APSTA_RESTRICTED_CHANNEL */
25891
+ bw = WL_CHANSPEC_BW_20;
25892
+ } else {
25893
+ WL_ERR(("invalid band (%d)\n", band));
25894
+ return -EINVAL;
25895
+ }
25896
+
25897
+ chspec = wf_channel2chspec(chan, bw);
25898
+ if (!wf_chspec_valid(chspec)) {
25899
+ WL_ERR(("Invalid chanspec 0x%x\n", chspec));
25900
+ return -EINVAL;
25901
+ }
25902
+
25903
+ /* Send CSA to associated STAs */
25904
+ memset(&csa_arg, 0, sizeof(wl_chan_switch_t));
25905
+ csa_arg.mode = params->block_tx;
25906
+ csa_arg.count = params->count;
25907
+ csa_arg.chspec = chspec;
25908
+ csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME;
25909
+ csa_arg.reg = 0;
25910
+
25911
+ err = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(wl_chan_switch_t),
25912
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
25913
+ if (err < 0) {
25914
+ WL_ERR(("Failed to switch channel, err=%d\n", err));
25915
+ }
25916
+
25917
+ return err;
25918
+}
25919
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) */
25920
+
25921
+#ifdef WL_WIPSEVT
25922
+int
25923
+wl_cfg80211_wips_event(uint16 misdeauth, char* bssid)
25924
+{
25925
+ s32 err = BCME_OK;
25926
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
25927
+ struct sk_buff *skb;
25928
+ gfp_t kflags;
25929
+ struct bcm_cfg80211 *cfg;
25930
+ struct net_device *ndev;
25931
+ struct wiphy *wiphy;
25932
+
25933
+ cfg = wl_cfg80211_get_bcmcfg();
25934
+ if (!cfg || !cfg->wdev) {
25935
+ WL_ERR(("WIPS evt invalid arg\n"));
25936
+ return err;
25937
+ }
25938
+
25939
+ ndev = bcmcfg_to_prmry_ndev(cfg);
25940
+ wiphy = bcmcfg_to_wiphy(cfg);
25941
+
25942
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
25943
+ skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
25944
+ BRCM_VENDOR_WIPS_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_WIPS, kflags);
25945
+
25946
+ if (!skb) {
25947
+ WL_ERR(("skb alloc failed"));
25948
+ return BCME_NOMEM;
25949
+ }
25950
+
25951
+ err = nla_put_u16(skb, WIPS_ATTR_DEAUTH_CNT, misdeauth);
25952
+ if (unlikely(err)) {
25953
+ WL_ERR(("nla_put_u16 WIPS_ATTR_DEAUTH_CNT failed\n"));
25954
+ goto fail;
25955
+ }
25956
+ err = nla_put(skb, WPPS_ATTR_DEAUTH_BSSID, ETHER_ADDR_LEN, bssid);
25957
+ if (unlikely(err)) {
25958
+ WL_ERR(("nla_put WPPS_ATTR_DEAUTH_BSSID failed\n"));
25959
+ goto fail;
25960
+ }
25961
+ cfg80211_vendor_event(skb, kflags);
25962
+
25963
+ return err;
25964
+
25965
+fail:
25966
+ if (skb) {
25967
+ nlmsg_free(skb);
25968
+ }
25969
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
25970
+ return err;
25971
+}
25972
+#endif /* WL_WIPSEVT */
25973
+
25974
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 11, 1))
25975
+void
25976
+wl_cfg80211_overtemp_event(struct net_device *ndev)
25977
+{
25978
+ return;
25979
+}
25980
+#else
25981
+void
25982
+wl_cfg80211_overtemp_event(struct net_device *ndev)
25983
+{
25984
+ struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
25985
+ struct wiphy *wiphy;
25986
+ struct sk_buff *skb;
25987
+ gfp_t kflags;
25988
+
25989
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
25990
+
25991
+ if (!cfg || !cfg->wdev) {
25992
+ WL_ERR(("cfg=%p wdev=%p\n", cfg, (cfg ? cfg->wdev : NULL)));
25993
+ return;
25994
+ }
25995
+
25996
+ wiphy = cfg->wdev->wiphy;
25997
+ if (!wiphy) {
25998
+ WL_ERR(("wiphy is NULL\n"));
25999
+ return;
26000
+ }
26001
+
26002
+#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
26003
+ LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
26004
+ skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(ndev), 0,
26005
+ BRCM_VENDOR_EVENT_OVERTEMP, kflags);
26006
+#else
26007
+ skb = cfg80211_vendor_event_alloc(wiphy, 0, BRCM_VENDOR_EVENT_OVERTEMP,
26008
+ kflags);
26009
+#endif // endif
26010
+ cfg80211_vendor_event(skb, kflags);
26011
+}
26012
+#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 11, 1) */